Make special regs definitions generic

This commit is contained in:
elicn
2022-10-20 14:16:53 +03:00
parent 0e63841628
commit 647832b01b
5 changed files with 63 additions and 55 deletions

View File

@@ -9,13 +9,12 @@ import ctypes
from .. import Uc from .. import Uc
from .. import arm_const as const from .. import arm_const as const
from .types import UcReg128 from .types import UcTupledReg, UcReg128
ARMCPReg = Tuple[int, int, int, int, int, int, int] ARMCPReg = Tuple[int, int, int, int, int, int, int, int]
ARMCPRegValue = Tuple[int, int, int, int, int, int, int, int]
class UcRegCP(ctypes.Structure): class UcRegCP(UcTupledReg[ARMCPReg]):
"""ARM coprocessors registers for instructions MRC, MCR, MRRC, MCRR """ARM coprocessors registers for instructions MRC, MCR, MRRC, MCRR
""" """
@@ -34,12 +33,6 @@ class UcRegCP(ctypes.Structure):
def value(self) -> int: def value(self) -> int:
return self.val return self.val
@classmethod
def from_param(cls, param: ARMCPRegValue):
assert type(param) is tuple and len(param) == len(cls._fields_)
return cls(*param)
class UcAArch32(Uc): class UcAArch32(Uc):
"""Unicorn subclass for ARM architecture. """Unicorn subclass for ARM architecture.

View File

@@ -11,15 +11,14 @@ from .. import arm64_const as const
from ..unicorn import uccallback from ..unicorn import uccallback
from ..unicorn_const import UC_ERR_ARG, UC_HOOK_INSN from ..unicorn_const import UC_ERR_ARG, UC_HOOK_INSN
from .types import uc_engine, UcReg128 from .types import uc_engine, UcTupledReg, UcReg128
ARM64CPReg = Tuple[int, int, int, int, int] ARM64CPReg = Tuple[int, int, int, int, int, int]
ARM64CPRegValue = Tuple[int, int, int, int, int, int]
HOOK_INSN_SYS_CFUNC = ctypes.CFUNCTYPE(ctypes.c_uint32, uc_engine, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_void_p) HOOK_INSN_SYS_CFUNC = ctypes.CFUNCTYPE(ctypes.c_uint32, uc_engine, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_void_p)
class UcRegCP(ctypes.Structure): class UcRegCP(UcTupledReg[ARM64CPReg]):
"""ARM64 coprocessors registers for instructions MRS, MSR """ARM64 coprocessors registers for instructions MRS, MSR
""" """
@@ -36,12 +35,6 @@ class UcRegCP(ctypes.Structure):
def value(self) -> int: def value(self) -> int:
return self.val return self.val
@classmethod
def from_param(cls, param: ARM64CPRegValue):
assert type(param) is tuple and len(param) == len(cls._fields_)
return cls(*param)
class UcAArch64(Uc): class UcAArch64(Uc):
"""Unicorn subclass for ARM64 architecture. """Unicorn subclass for ARM64 architecture.

View File

@@ -11,9 +11,10 @@ from .. import x86_const as const
from ..unicorn import uccallback from ..unicorn import uccallback
from ..unicorn_const import UC_ERR_ARG, UC_HOOK_INSN from ..unicorn_const import UC_ERR_ARG, UC_HOOK_INSN
from .types import uc_engine, UcReg128, UcReg256, UcReg512 from .types import uc_engine, UcTupledReg, UcReg128, UcReg256, UcReg512
X86MMRReg = Tuple[int, int, int, int] X86MMRReg = Tuple[int, int, int, int]
X86MSRReg = Tuple[int, int]
X86FPReg = Tuple[int, int] X86FPReg = Tuple[int, int]
HOOK_INSN_IN_CFUNC = ctypes.CFUNCTYPE(ctypes.c_uint32, uc_engine, ctypes.c_uint32, ctypes.c_int, ctypes.c_void_p) HOOK_INSN_IN_CFUNC = ctypes.CFUNCTYPE(ctypes.c_uint32, uc_engine, ctypes.c_uint32, ctypes.c_int, ctypes.c_void_p)
@@ -22,7 +23,7 @@ HOOK_INSN_SYSCALL_CFUNC = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_void_p)
HOOK_INSN_CPUID_CFUNC = ctypes.CFUNCTYPE(ctypes.c_uint32, uc_engine, ctypes.c_void_p) HOOK_INSN_CPUID_CFUNC = ctypes.CFUNCTYPE(ctypes.c_uint32, uc_engine, ctypes.c_void_p)
class UcRegMMR(ctypes.Structure): class UcRegMMR(UcTupledReg[X86MMRReg]):
"""Memory-Management Register for instructions IDTR, GDTR, LDTR, TR. """Memory-Management Register for instructions IDTR, GDTR, LDTR, TR.
""" """
@@ -33,18 +34,8 @@ class UcRegMMR(ctypes.Structure):
('flags', ctypes.c_uint32) # not used by GDTR and IDTR ('flags', ctypes.c_uint32) # not used by GDTR and IDTR
) )
@property
def value(self) -> X86MMRReg:
return tuple(getattr(self, fname) for fname, _ in self._fields_)
@classmethod class UcRegMSR(UcTupledReg[X86MSRReg]):
def from_param(cls, param: X86MMRReg):
assert type(param) is tuple and len(param) == len(cls._fields_)
return cls(*param)
class UcRegMSR(ctypes.Structure):
_fields_ = ( _fields_ = (
('rid', ctypes.c_uint32), ('rid', ctypes.c_uint32),
('val', ctypes.c_uint64) ('val', ctypes.c_uint64)
@@ -54,29 +45,13 @@ class UcRegMSR(ctypes.Structure):
def value(self) -> int: def value(self) -> int:
return self.val return self.val
@classmethod
def from_param(cls, param: Tuple[int, int]):
assert type(param) is tuple and len(param) == len(cls._fields_)
return cls(*param) class UcRegFPR(UcTupledReg[X86FPReg]):
class UcRegFPR(ctypes.Structure):
_fields_ = ( _fields_ = (
('mantissa', ctypes.c_uint64), ('mantissa', ctypes.c_uint64),
('exponent', ctypes.c_uint16) ('exponent', ctypes.c_uint16)
) )
@property
def value(self) -> X86FPReg:
return tuple(getattr(self, fname) for fname, _ in self._fields_)
@classmethod
def from_param(cls, param: X86FPReg):
assert type(param) is tuple and len(param) == len(cls._fields_)
return cls(*param)
class UcIntel(Uc): class UcIntel(Uc):
"""Unicorn subclass for Intel architecture. """Unicorn subclass for Intel architecture.

View File

@@ -2,6 +2,9 @@
# #
# @author elicn # @author elicn
from abc import abstractmethod
from typing import Generic, Tuple, TypeVar
import ctypes import ctypes
uc_err = ctypes.c_int uc_err = ctypes.c_int
@@ -12,7 +15,51 @@ uc_context = ctypes.c_void_p
uc_hook_h = ctypes.c_size_t uc_hook_h = ctypes.c_size_t
class UcLargeReg(ctypes.Structure): VT = TypeVar('VT', bound=Tuple[int, ...])
class UcReg(ctypes.Structure):
"""A base class for composite registers.
This class is meant to be inherited, not instantiated directly.
"""
@property
@abstractmethod
def value(self):
"""Get register value.
"""
pass
@classmethod
@abstractmethod
def from_value(cls, value):
"""Create a register instance from a given value.
"""
pass
class UcTupledReg(UcReg, Generic[VT]):
"""A base class for registers whose values are represented as a set
of fields.
This class is meant to be inherited, not instantiated directly.
"""
@property
def value(self) -> VT:
return tuple(getattr(self, fname) for fname, *_ in self.__class__._fields_) # type: ignore
@classmethod
def from_value(cls, value: VT):
assert type(value) is tuple and len(value) == len(cls._fields_)
return cls(*value)
class UcLargeReg(UcReg):
"""A base class for large registers that are internally represented as """A base class for large registers that are internally represented as
an array of multiple qwords. an array of multiple qwords.
@@ -26,13 +73,13 @@ class UcLargeReg(ctypes.Structure):
return sum(qword << (64 * i) for i, qword in enumerate(self.qwords)) return sum(qword << (64 * i) for i, qword in enumerate(self.qwords))
@classmethod @classmethod
def from_param(cls, param: int): def from_value(cls, value: int):
assert type(param) is int assert type(value) is int
mask = (1 << 64) - 1 mask = (1 << 64) - 1
size = cls._fields_[0][1]._length_ size = cls._fields_[0][1]._length_
return cls(tuple((param >> (64 * i)) & mask for i in range(size))) return cls(tuple((value >> (64 * i)) & mask for i in range(size)))
class UcReg128(UcLargeReg): class UcReg128(UcLargeReg):

View File

@@ -338,7 +338,7 @@ class RegStateManager:
"""Register write helper method. """Register write helper method.
""" """
reg = regtype.from_param(value) if issubclass(regtype, ctypes.Structure) else regtype(value) reg = regtype.from_value(value) if issubclass(regtype, UcReg) else regtype(value)
status = self._do_reg_write(reg_id, ctypes.byref(reg)) status = self._do_reg_write(reg_id, ctypes.byref(reg))
if status != uc.UC_ERR_OK: if status != uc.UC_ERR_OK: