Merge remote-tracking branch 'eli/uc-py-next' into staged
This commit is contained in:
commit
ffd34cbb8c
@ -1,15 +1,29 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
./sample_x86.py
|
python3 ./sample_arm.py
|
||||||
echo "=========================="
|
echo "=========================="
|
||||||
./shellcode.py
|
python3 ./sample_armeb.py
|
||||||
echo "=========================="
|
echo "=========================="
|
||||||
./sample_arm.py
|
python3 ./sample_arm64.py
|
||||||
echo "=========================="
|
echo "=========================="
|
||||||
./sample_arm64.py
|
python3 ./sample_arm64eb.py
|
||||||
echo "=========================="
|
echo "=========================="
|
||||||
./sample_mips.py
|
python3 ./sample_m68k.py
|
||||||
echo "=========================="
|
echo "=========================="
|
||||||
./sample_sparc.py
|
python3 ./sample_mips.py
|
||||||
echo "=========================="
|
echo "=========================="
|
||||||
./sample_m68k.py
|
python3 ./sample_ppc.py
|
||||||
|
echo "=========================="
|
||||||
|
python3 ./sample_riscv.py
|
||||||
|
echo "=========================="
|
||||||
|
python3 ./sample_s390x.py
|
||||||
|
echo "=========================="
|
||||||
|
python3 ./sample_sparc.py
|
||||||
|
echo "=========================="
|
||||||
|
python3 ./sample_tricore.py
|
||||||
|
echo "=========================="
|
||||||
|
python3 ./sample_x86.py
|
||||||
|
echo "=========================="
|
||||||
|
python3 ./shellcode.py
|
||||||
|
echo "=========================="
|
||||||
|
python3 ./sample_ctl.py
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
# By Lazymio(@wtdcode), 2021
|
# By Lazymio(@wtdcode), 2021
|
||||||
|
|
||||||
from unicorn import *
|
from unicorn import *
|
||||||
from unicorn.unicorn import UC_HOOK_EDGE_GEN_CB
|
|
||||||
from unicorn.x86_const import *
|
from unicorn.x86_const import *
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
@ -58,7 +57,7 @@ def test_uc_ctl_tb_cache():
|
|||||||
# Now we clear cache for all TBs.
|
# Now we clear cache for all TBs.
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
uc.ctl_remove_cache(addr + i * 512, addr + i * 512 + 1)
|
uc.ctl_remove_cache(addr + i * 512, addr + i * 512 + 1)
|
||||||
|
|
||||||
evicted = time_emulation(uc, addr, addr + len(code))
|
evicted = time_emulation(uc, addr, addr + len(code))
|
||||||
|
|
||||||
print(f">>> Run time: First time {standard}, Cached: {cached}, Cached evicted: {evicted}")
|
print(f">>> Run time: First time {standard}, Cached: {cached}, Cached evicted: {evicted}")
|
||||||
@ -93,7 +92,7 @@ def test_uc_ctl_exits():
|
|||||||
uc.hook_add(UC_HOOK_EDGE_GENERATED, trace_new_edge)
|
uc.hook_add(UC_HOOK_EDGE_GENERATED, trace_new_edge)
|
||||||
|
|
||||||
# Trace cmp instruction.
|
# Trace cmp instruction.
|
||||||
uc.hook_add(UC_HOOK_TCG_OPCODE, trace_tcg_sub, UC_TCG_OP_SUB, UC_TCG_OP_FLAG_CMP)
|
uc.hook_add(UC_HOOK_TCG_OPCODE, trace_tcg_sub, aux1=UC_TCG_OP_SUB, aux2=UC_TCG_OP_FLAG_CMP)
|
||||||
|
|
||||||
uc.ctl_exits_enabled(True)
|
uc.ctl_exits_enabled(True)
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
# Unicorn Python bindings, by Nguyen Anh Quynnh <aquynh@gmail.com>
|
# New and improved Unicorn Python bindings by elicn
|
||||||
|
# based on Nguyen Anh Quynnh's work
|
||||||
|
|
||||||
from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const, riscv_const, s390x_const, tricore_const
|
from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const, riscv_const, s390x_const, tricore_const
|
||||||
from .unicorn_const import *
|
from .unicorn_const import *
|
||||||
from .unicorn import Uc, uc_version, uc_arch_supported, version_bind, debug, UcError, __version__
|
from .unicorn import Uc, ucsubclass, uc_version, uc_arch_supported, version_bind, debug, UcError, __version__
|
||||||
|
0
bindings/python/unicorn/arch/__init__.py
Normal file
0
bindings/python/unicorn/arch/__init__.py
Normal file
81
bindings/python/unicorn/arch/arm.py
Normal file
81
bindings/python/unicorn/arch/arm.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
# AArch32 classes and structures.
|
||||||
|
#
|
||||||
|
# @author elicn
|
||||||
|
|
||||||
|
from typing import Any, Tuple
|
||||||
|
|
||||||
|
import ctypes
|
||||||
|
|
||||||
|
from .. import Uc
|
||||||
|
from .. import arm_const as const
|
||||||
|
|
||||||
|
from .types import UcTupledReg, UcReg128
|
||||||
|
|
||||||
|
ARMCPReg = Tuple[int, int, int, int, int, int, int, int]
|
||||||
|
|
||||||
|
|
||||||
|
class UcRegCP(UcTupledReg[ARMCPReg]):
|
||||||
|
"""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
|
||||||
|
|
||||||
|
|
||||||
|
class UcAArch32(Uc):
|
||||||
|
"""Unicorn subclass for ARM architecture.
|
||||||
|
"""
|
||||||
|
|
||||||
|
REG_RANGE_Q = range(const.UC_ARM_REG_Q0, const.UC_ARM_REG_Q15 + 1)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __select_reg_class(reg_id: int):
|
||||||
|
"""Select class for special architectural registers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
reg_class = (
|
||||||
|
(UcAArch32.REG_RANGE_Q, 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 = UcAArch32.__select_reg_class(reg_id)
|
||||||
|
|
||||||
|
if reg_cls is None:
|
||||||
|
if reg_id == const.UC_ARM_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 = UcAArch32.__select_reg_class(reg_id)
|
||||||
|
|
||||||
|
if reg_cls is None:
|
||||||
|
if reg_id == const.UC_ARM_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)
|
126
bindings/python/unicorn/arch/arm64.py
Normal file
126
bindings/python/unicorn/arch/arm64.py
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
# 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 uccallback
|
||||||
|
from ..unicorn_const import UC_ERR_ARG, UC_HOOK_INSN
|
||||||
|
from .types import uc_engine, UcTupledReg, UcReg128
|
||||||
|
|
||||||
|
ARM64CPReg = 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(UcTupledReg[ARM64CPReg]):
|
||||||
|
"""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
|
||||||
|
|
||||||
|
|
||||||
|
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():
|
||||||
|
@uccallback(HOOK_INSN_SYS_CFUNC)
|
||||||
|
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 __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)
|
178
bindings/python/unicorn/arch/intel.py
Normal file
178
bindings/python/unicorn/arch/intel.py
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
# 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 uccallback
|
||||||
|
from ..unicorn_const import UC_ERR_ARG, UC_HOOK_INSN
|
||||||
|
from .types import uc_engine, UcTupledReg, UcReg128, UcReg256, UcReg512
|
||||||
|
|
||||||
|
X86MMRReg = Tuple[int, int, int, int]
|
||||||
|
X86MSRReg = 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_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(UcTupledReg[X86MMRReg]):
|
||||||
|
"""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
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class UcRegMSR(UcTupledReg[X86MSRReg]):
|
||||||
|
_fields_ = (
|
||||||
|
('rid', ctypes.c_uint32),
|
||||||
|
('val', ctypes.c_uint64)
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def value(self) -> int:
|
||||||
|
return self.val
|
||||||
|
|
||||||
|
|
||||||
|
class UcRegFPR(UcTupledReg[X86FPReg]):
|
||||||
|
_fields_ = (
|
||||||
|
('mantissa', ctypes.c_uint64),
|
||||||
|
('exponent', ctypes.c_uint16)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
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():
|
||||||
|
@uccallback(HOOK_INSN_IN_CFUNC)
|
||||||
|
def __hook_insn_in_cb(handle: int, port: int, size: int, key: int) -> int:
|
||||||
|
return callback(self, port, size, user_data)
|
||||||
|
|
||||||
|
return __hook_insn_in_cb
|
||||||
|
|
||||||
|
def __hook_insn_out():
|
||||||
|
@uccallback(HOOK_INSN_OUT_CFUNC)
|
||||||
|
def __hook_insn_out_cb(handle: int, port: int, size: int, value: int, key: int):
|
||||||
|
callback(self, port, size, value, user_data)
|
||||||
|
|
||||||
|
return __hook_insn_out_cb
|
||||||
|
|
||||||
|
def __hook_insn_syscall():
|
||||||
|
@uccallback(HOOK_INSN_SYSCALL_CFUNC)
|
||||||
|
def __hook_insn_syscall_cb(handle: int, key: int):
|
||||||
|
callback(self, user_data)
|
||||||
|
|
||||||
|
return __hook_insn_syscall_cb
|
||||||
|
|
||||||
|
def __hook_insn_cpuid():
|
||||||
|
@uccallback(HOOK_INSN_CPUID_CFUNC)
|
||||||
|
def __hook_insn_cpuid_cb(handle: int, key: int) -> int:
|
||||||
|
return callback(self, user_data)
|
||||||
|
|
||||||
|
return __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))
|
92
bindings/python/unicorn/arch/types.py
Normal file
92
bindings/python/unicorn/arch/types.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# Common types and structures.
|
||||||
|
#
|
||||||
|
# @author elicn
|
||||||
|
|
||||||
|
from abc import abstractmethod
|
||||||
|
from typing import Generic, Tuple, TypeVar
|
||||||
|
|
||||||
|
import ctypes
|
||||||
|
|
||||||
|
uc_err = ctypes.c_int
|
||||||
|
uc_engine = ctypes.c_void_p
|
||||||
|
uc_context = ctypes.c_void_p
|
||||||
|
uc_hook_h = ctypes.c_size_t
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
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_value(cls, value: int):
|
||||||
|
assert type(value) is int
|
||||||
|
|
||||||
|
mask = (1 << 64) - 1
|
||||||
|
size = cls._fields_[0][1]._length_
|
||||||
|
|
||||||
|
return cls(tuple((value >> (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
Loading…
Reference in New Issue
Block a user