Initial refactoring stage
This commit is contained in:
0
bindings/python/unicorn/arch/__init__.py
Normal file
0
bindings/python/unicorn/arch/__init__.py
Normal file
59
bindings/python/unicorn/arch/arm.py
Normal file
59
bindings/python/unicorn/arch/arm.py
Normal file
@@ -0,0 +1,59 @@
|
||||
# AArch32 classes and structures.
|
||||
#
|
||||
# @author elicn
|
||||
|
||||
from typing import Any, Tuple
|
||||
|
||||
import ctypes
|
||||
|
||||
from .. import Uc, UcError
|
||||
from .. import arm_const as const
|
||||
from ..unicorn_const import UC_ERR_ARG
|
||||
|
||||
ARMCPReg = Tuple[int, int, int, int, int, int, int]
|
||||
ARMCPRegValue = Tuple[int, int, int, int, int, int, int, int]
|
||||
|
||||
class UcRegCP(ctypes.Structure):
|
||||
"""ARM coprocessors registers for instructions MRC, MCR, MRRC, MCRR
|
||||
"""
|
||||
|
||||
_fields_ = (
|
||||
('cp', ctypes.c_uint32),
|
||||
('is64', ctypes.c_uint32),
|
||||
('sec', ctypes.c_uint32),
|
||||
('crn', ctypes.c_uint32),
|
||||
('crm', ctypes.c_uint32),
|
||||
('opc1', ctypes.c_uint32),
|
||||
('opc2', ctypes.c_uint32),
|
||||
('val', ctypes.c_uint64)
|
||||
)
|
||||
|
||||
@property
|
||||
def value(self) -> int:
|
||||
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):
|
||||
"""Unicorn subclass for ARM architecture.
|
||||
"""
|
||||
|
||||
def reg_read(self, reg_id: int, aux: Any = None):
|
||||
if reg_id == const.UC_ARM_REG_CP_REG:
|
||||
return self._reg_read(reg_id, UcRegCP, *aux)
|
||||
|
||||
# fallback to default reading method
|
||||
return super().reg_read(reg_id, aux)
|
||||
|
||||
def reg_write(self, reg_id: int, value) -> None:
|
||||
if reg_id == const.UC_ARM_REG_CP_REG:
|
||||
self._reg_write(reg_id, UcRegCP, value)
|
||||
return
|
||||
|
||||
# fallback to default writing method
|
||||
super().reg_write(reg_id, value)
|
||||
135
bindings/python/unicorn/arch/arm64.py
Normal file
135
bindings/python/unicorn/arch/arm64.py
Normal file
@@ -0,0 +1,135 @@
|
||||
# AArch64 classes and structures.
|
||||
#
|
||||
# @author elicn
|
||||
|
||||
from typing import Any, Callable, NamedTuple, Tuple
|
||||
|
||||
import ctypes
|
||||
|
||||
from .. import Uc, UcError
|
||||
from .. import arm64_const as const
|
||||
|
||||
from ..unicorn import _catch_hook_exception, _cast_func
|
||||
from ..unicorn_const import UC_ERR_ARG, UC_HOOK_INSN
|
||||
from .types import uc_engine, UcReg128
|
||||
|
||||
ARM64CPReg = Tuple[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)
|
||||
|
||||
|
||||
class UcRegCP(ctypes.Structure):
|
||||
"""ARM64 coprocessors registers for instructions MRS, MSR
|
||||
"""
|
||||
|
||||
_fields_ = (
|
||||
('crn', ctypes.c_uint32),
|
||||
('crm', ctypes.c_uint32),
|
||||
('op0', ctypes.c_uint32),
|
||||
('op1', ctypes.c_uint32),
|
||||
('op2', ctypes.c_uint32),
|
||||
('val', ctypes.c_uint64)
|
||||
)
|
||||
|
||||
@property
|
||||
def value(self) -> int:
|
||||
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):
|
||||
"""Unicorn subclass for ARM64 architecture.
|
||||
"""
|
||||
|
||||
REG_RANGE_Q = range(const.UC_ARM64_REG_Q0, const.UC_ARM64_REG_Q31 + 1)
|
||||
REG_RANGE_V = range(const.UC_ARM64_REG_V0, const.UC_ARM64_REG_V31 + 1)
|
||||
|
||||
def hook_add(self, htype: int, callback: Callable, user_data: Any = None, begin: int = 1, end: int = 0, aux1: int = 0, aux2: int = 0) -> int:
|
||||
if htype != UC_HOOK_INSN:
|
||||
return super().hook_add(htype, callback, user_data, begin, end, aux1, aux2)
|
||||
|
||||
insn = ctypes.c_int(aux1)
|
||||
|
||||
def __hook_insn_sys():
|
||||
@_catch_hook_exception
|
||||
def __hook_insn_sys_cb(handle: int, reg: int, pcp_reg: Any, key: int) -> int:
|
||||
cp_reg = ctypes.cast(pcp_reg, ctypes.POINTER(UcRegCP)).contents
|
||||
|
||||
class CpReg(NamedTuple):
|
||||
crn: int
|
||||
crm: int
|
||||
op0: int
|
||||
op1: int
|
||||
op2: int
|
||||
val: int
|
||||
|
||||
cp_reg = CpReg(cp_reg.crn, cp_reg.crm, cp_reg.op0, cp_reg.op1, cp_reg.op2, cp_reg.val)
|
||||
|
||||
return callback(self, reg, cp_reg, user_data)
|
||||
|
||||
return _cast_func(HOOK_INSN_SYS_CFUNC, __hook_insn_sys_cb)
|
||||
|
||||
handlers = {
|
||||
const.UC_ARM64_INS_MRS : __hook_insn_sys,
|
||||
const.UC_ARM64_INS_MSR : __hook_insn_sys,
|
||||
const.UC_ARM64_INS_SYS : __hook_insn_sys,
|
||||
const.UC_ARM64_INS_SYSL : __hook_insn_sys
|
||||
}
|
||||
|
||||
handler = handlers.get(insn.value)
|
||||
|
||||
if handler is None:
|
||||
raise UcError(UC_ERR_ARG)
|
||||
|
||||
fptr = handler()
|
||||
|
||||
return getattr(self, '_Uc__do_hook_add')(htype, fptr, begin, end, insn)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def __select_reg_class(reg_id: int):
|
||||
"""Select class for special architectural registers.
|
||||
"""
|
||||
|
||||
reg_class = (
|
||||
(UcAArch64.REG_RANGE_Q, UcReg128),
|
||||
(UcAArch64.REG_RANGE_V, UcReg128)
|
||||
)
|
||||
|
||||
return next((cls for rng, cls in reg_class if reg_id in rng), None)
|
||||
|
||||
|
||||
def reg_read(self, reg_id: int, aux: Any = None):
|
||||
# select register class for special cases
|
||||
reg_cls = UcAArch64.__select_reg_class(reg_id)
|
||||
|
||||
if reg_cls is None:
|
||||
if reg_id == const.UC_ARM64_REG_CP_REG:
|
||||
return self._reg_read(reg_id, UcRegCP, *aux)
|
||||
|
||||
else:
|
||||
# fallback to default reading method
|
||||
return super().reg_read(reg_id, aux)
|
||||
|
||||
return self._reg_read(reg_id, reg_cls)
|
||||
|
||||
def reg_write(self, reg_id: int, value) -> None:
|
||||
# select register class for special cases
|
||||
reg_cls = UcAArch64.__select_reg_class(reg_id)
|
||||
|
||||
if reg_cls is None:
|
||||
if reg_id == const.UC_ARM64_REG_CP_REG:
|
||||
self._reg_write(reg_id, UcRegCP, value)
|
||||
|
||||
else:
|
||||
# fallback to default writing method
|
||||
super().reg_write(reg_id, value)
|
||||
|
||||
else:
|
||||
self._reg_write(reg_id, reg_cls, value)
|
||||
207
bindings/python/unicorn/arch/intel.py
Normal file
207
bindings/python/unicorn/arch/intel.py
Normal file
@@ -0,0 +1,207 @@
|
||||
# Intel architecture classes and structures.
|
||||
#
|
||||
# @author elicn
|
||||
|
||||
from typing import Any, Callable, Tuple
|
||||
|
||||
import ctypes
|
||||
|
||||
from .. import Uc, UcError
|
||||
from .. import x86_const as const
|
||||
|
||||
from ..unicorn import _catch_hook_exception, _cast_func
|
||||
from ..unicorn_const import UC_ERR_ARG, UC_HOOK_INSN
|
||||
from .types import uc_engine, UcReg128, UcReg256, UcReg512
|
||||
|
||||
X86MMRReg = Tuple[int, int, 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_OUT_CFUNC = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint32, ctypes.c_int, ctypes.c_uint32, ctypes.c_void_p)
|
||||
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)
|
||||
|
||||
|
||||
class UcRegMMR(ctypes.Structure):
|
||||
"""Memory-Management Register for instructions IDTR, GDTR, LDTR, TR.
|
||||
"""
|
||||
|
||||
_fields_ = (
|
||||
('selector', ctypes.c_uint16), # not used by GDTR and IDTR
|
||||
('base', ctypes.c_uint64), # handle 32 or 64 bit CPUs
|
||||
('limit', ctypes.c_uint32),
|
||||
('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
|
||||
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_ = (
|
||||
('rid', ctypes.c_uint32),
|
||||
('val', ctypes.c_uint64)
|
||||
)
|
||||
|
||||
@property
|
||||
def value(self) -> int:
|
||||
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(ctypes.Structure):
|
||||
_fields_ = (
|
||||
('mantissa', ctypes.c_uint64),
|
||||
('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):
|
||||
"""Unicorn subclass for Intel architecture.
|
||||
"""
|
||||
|
||||
REG_RANGE_MMR = (
|
||||
const.UC_X86_REG_IDTR,
|
||||
const.UC_X86_REG_GDTR,
|
||||
const.UC_X86_REG_LDTR,
|
||||
const.UC_X86_REG_TR
|
||||
)
|
||||
|
||||
REG_RANGE_FP = range(const.UC_X86_REG_FP0, const.UC_X86_REG_FP7 + 1)
|
||||
REG_RANGE_XMM = range(const.UC_X86_REG_XMM0, const.UC_X86_REG_XMM31 + 1)
|
||||
REG_RANGE_YMM = range(const.UC_X86_REG_YMM0, const.UC_X86_REG_YMM31 + 1)
|
||||
REG_RANGE_ZMM = range(const.UC_X86_REG_ZMM0, const.UC_X86_REG_ZMM31 + 1)
|
||||
|
||||
def hook_add(self, htype: int, callback: Callable, user_data: Any = None, begin: int = 1, end: int = 0, aux1: int = 0, aux2: int = 0) -> int:
|
||||
if htype != UC_HOOK_INSN:
|
||||
return super().hook_add(htype, callback, user_data, begin, end, aux1, aux2)
|
||||
|
||||
insn = ctypes.c_int(aux1)
|
||||
|
||||
def __hook_insn_in():
|
||||
@_catch_hook_exception
|
||||
def __hook_insn_in_cb(handle: int, port: int, size: int, key: int) -> int:
|
||||
return callback(self, port, size, user_data)
|
||||
|
||||
return _cast_func(HOOK_INSN_IN_CFUNC, __hook_insn_in_cb)
|
||||
|
||||
def __hook_insn_out():
|
||||
@_catch_hook_exception
|
||||
def __hook_insn_out_cb(handle: int, port: int, size: int, value: int, key: int):
|
||||
callback(self, port, size, value, user_data)
|
||||
|
||||
return _cast_func(HOOK_INSN_OUT_CFUNC, __hook_insn_out_cb)
|
||||
|
||||
def __hook_insn_syscall():
|
||||
@_catch_hook_exception
|
||||
def __hook_insn_syscall_cb(handle: int, key: int):
|
||||
callback(self, user_data)
|
||||
|
||||
return _cast_func(HOOK_INSN_SYSCALL_CFUNC, __hook_insn_syscall_cb)
|
||||
|
||||
def __hook_insn_cpuid():
|
||||
@_catch_hook_exception
|
||||
def __hook_insn_cpuid_cb(handle: int, key: int) -> int:
|
||||
return callback(self, user_data)
|
||||
|
||||
return _cast_func(HOOK_INSN_CPUID_CFUNC, __hook_insn_cpuid_cb)
|
||||
|
||||
handlers = {
|
||||
const.UC_X86_INS_IN : __hook_insn_in,
|
||||
const.UC_X86_INS_OUT : __hook_insn_out,
|
||||
const.UC_X86_INS_SYSCALL : __hook_insn_syscall,
|
||||
const.UC_X86_INS_SYSENTER : __hook_insn_syscall,
|
||||
const.UC_X86_INS_CPUID : __hook_insn_cpuid
|
||||
}
|
||||
|
||||
handler = handlers.get(insn.value)
|
||||
|
||||
if handler is None:
|
||||
raise UcError(UC_ERR_ARG)
|
||||
|
||||
fptr = handler()
|
||||
|
||||
return getattr(self, '_Uc__do_hook_add')(htype, fptr, begin, end, insn)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def __select_reg_class(reg_id: int):
|
||||
"""Select class for special architectural registers.
|
||||
"""
|
||||
|
||||
reg_class = (
|
||||
(UcIntel.REG_RANGE_MMR, UcRegMMR),
|
||||
(UcIntel.REG_RANGE_FP, UcRegFPR),
|
||||
(UcIntel.REG_RANGE_XMM, UcReg128),
|
||||
(UcIntel.REG_RANGE_YMM, UcReg256),
|
||||
(UcIntel.REG_RANGE_ZMM, UcReg512)
|
||||
)
|
||||
|
||||
return next((cls for rng, cls in reg_class if reg_id in rng), None)
|
||||
|
||||
|
||||
def reg_read(self, reg_id: int, aux: Any = None):
|
||||
# select register class for special cases
|
||||
reg_cls = UcIntel.__select_reg_class(reg_id)
|
||||
|
||||
if reg_cls is None:
|
||||
# backward compatibility: msr read through reg_read
|
||||
if reg_id == const.UC_X86_REG_MSR:
|
||||
if type(aux) is not int:
|
||||
raise UcError(UC_ERR_ARG)
|
||||
|
||||
value = self.msr_read(aux)
|
||||
|
||||
else:
|
||||
value = super().reg_read(reg_id, aux)
|
||||
else:
|
||||
value = self._reg_read(reg_id, reg_cls)
|
||||
|
||||
return value
|
||||
|
||||
def reg_write(self, reg_id: int, value) -> None:
|
||||
# select register class for special cases
|
||||
reg_cls = UcIntel.__select_reg_class(reg_id)
|
||||
|
||||
if reg_cls is None:
|
||||
# backward compatibility: msr write through reg_write
|
||||
if reg_id == const.UC_X86_REG_MSR:
|
||||
if type(value) is not tuple or len(value) != 2:
|
||||
raise UcError(UC_ERR_ARG)
|
||||
|
||||
self.msr_write(*value)
|
||||
return
|
||||
|
||||
super().reg_write(reg_id, value)
|
||||
else:
|
||||
self._reg_write(reg_id, reg_cls, value)
|
||||
|
||||
|
||||
def msr_read(self, msr_id: int) -> int:
|
||||
return self._reg_read(const.UC_X86_REG_MSR, UcRegMSR, msr_id)
|
||||
|
||||
|
||||
def msr_write(self, msr_id: int, value: int) -> None:
|
||||
self._reg_write(const.UC_X86_REG_MSR, UcRegMSR, (msr_id, value))
|
||||
48
bindings/python/unicorn/arch/types.py
Normal file
48
bindings/python/unicorn/arch/types.py
Normal file
@@ -0,0 +1,48 @@
|
||||
# Common types and structures.
|
||||
#
|
||||
# @author elicn
|
||||
|
||||
import ctypes
|
||||
|
||||
|
||||
uc_err = ctypes.c_int
|
||||
uc_mode = ctypes.c_int
|
||||
uc_arch = ctypes.c_int
|
||||
uc_engine = ctypes.c_void_p
|
||||
uc_context = ctypes.c_void_p
|
||||
uc_hook_h = ctypes.c_size_t
|
||||
|
||||
|
||||
class UcLargeReg(ctypes.Structure):
|
||||
"""A base class for large registers that are internally represented as
|
||||
an array of multiple qwords.
|
||||
|
||||
This class is meant to be inherited, not instantiated directly.
|
||||
"""
|
||||
|
||||
qwords: ctypes.Array
|
||||
|
||||
@property
|
||||
def value(self) -> int:
|
||||
return sum(qword << (64 * i) for i, qword in enumerate(self.qwords))
|
||||
|
||||
@classmethod
|
||||
def from_param(cls, param: int):
|
||||
assert type(param) is int
|
||||
|
||||
mask = (1 << 64) - 1
|
||||
size = cls._fields_[0][1]._length_
|
||||
|
||||
return cls(tuple((param >> (64 * i)) & mask for i in range(size)))
|
||||
|
||||
|
||||
class UcReg128(UcLargeReg):
|
||||
_fields_ = [('qwords', ctypes.c_uint64 * 2)]
|
||||
|
||||
|
||||
class UcReg256(UcLargeReg):
|
||||
_fields_ = [('qwords', ctypes.c_uint64 * 4)]
|
||||
|
||||
|
||||
class UcReg512(UcLargeReg):
|
||||
_fields_ = [('qwords', ctypes.c_uint64 * 8)]
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user