Initial refactoring stage

This commit is contained in:
elicn
2022-06-01 18:04:27 +03:00
parent 0ebac3b455
commit 4f13e14227
6 changed files with 1419 additions and 898 deletions

View File

View 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)

View 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)

View 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))

View 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