import Unicorn2
This commit is contained in:
@ -120,7 +120,28 @@ UC_ARM_REG_IPSR = 114
|
||||
UC_ARM_REG_MSP = 115
|
||||
UC_ARM_REG_PSP = 116
|
||||
UC_ARM_REG_CONTROL = 117
|
||||
UC_ARM_REG_ENDING = 118
|
||||
UC_ARM_REG_IAPSR = 118
|
||||
UC_ARM_REG_EAPSR = 119
|
||||
UC_ARM_REG_XPSR = 120
|
||||
UC_ARM_REG_EPSR = 121
|
||||
UC_ARM_REG_IEPSR = 122
|
||||
UC_ARM_REG_PRIMASK = 123
|
||||
UC_ARM_REG_BASEPRI = 124
|
||||
UC_ARM_REG_BASEPRI_MAX = 125
|
||||
UC_ARM_REG_FAULTMASK = 126
|
||||
UC_ARM_REG_APSR_NZCVQ = 127
|
||||
UC_ARM_REG_APSR_G = 128
|
||||
UC_ARM_REG_APSR_NZCVQG = 129
|
||||
UC_ARM_REG_IAPSR_NZCVQ = 130
|
||||
UC_ARM_REG_IAPSR_G = 131
|
||||
UC_ARM_REG_IAPSR_NZCVQG = 132
|
||||
UC_ARM_REG_EAPSR_NZCVQ = 133
|
||||
UC_ARM_REG_EAPSR_G = 134
|
||||
UC_ARM_REG_EAPSR_NZCVQG = 135
|
||||
UC_ARM_REG_XPSR_NZCVQ = 136
|
||||
UC_ARM_REG_XPSR_G = 137
|
||||
UC_ARM_REG_XPSR_NZCVQG = 138
|
||||
UC_ARM_REG_ENDING = 139
|
||||
|
||||
# alias registers
|
||||
UC_ARM_REG_R13 = 12
|
||||
|
40
bindings/python/unicorn/ppc_const.py
Normal file
40
bindings/python/unicorn/ppc_const.py
Normal file
@ -0,0 +1,40 @@
|
||||
# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [ppc_const.py]
|
||||
|
||||
# PPC registers
|
||||
|
||||
UC_PPC_REG_INVALID = 0
|
||||
|
||||
# General purpose registers
|
||||
UC_PPC_REG_PC = 1
|
||||
UC_PPC_REG_0 = 2
|
||||
UC_PPC_REG_1 = 3
|
||||
UC_PPC_REG_2 = 4
|
||||
UC_PPC_REG_3 = 5
|
||||
UC_PPC_REG_4 = 6
|
||||
UC_PPC_REG_5 = 7
|
||||
UC_PPC_REG_6 = 8
|
||||
UC_PPC_REG_7 = 9
|
||||
UC_PPC_REG_8 = 10
|
||||
UC_PPC_REG_9 = 11
|
||||
UC_PPC_REG_10 = 12
|
||||
UC_PPC_REG_11 = 13
|
||||
UC_PPC_REG_12 = 14
|
||||
UC_PPC_REG_13 = 15
|
||||
UC_PPC_REG_14 = 16
|
||||
UC_PPC_REG_15 = 17
|
||||
UC_PPC_REG_16 = 18
|
||||
UC_PPC_REG_17 = 19
|
||||
UC_PPC_REG_18 = 20
|
||||
UC_PPC_REG_19 = 21
|
||||
UC_PPC_REG_20 = 22
|
||||
UC_PPC_REG_21 = 23
|
||||
UC_PPC_REG_22 = 24
|
||||
UC_PPC_REG_23 = 25
|
||||
UC_PPC_REG_24 = 26
|
||||
UC_PPC_REG_25 = 27
|
||||
UC_PPC_REG_26 = 28
|
||||
UC_PPC_REG_27 = 29
|
||||
UC_PPC_REG_28 = 30
|
||||
UC_PPC_REG_29 = 31
|
||||
UC_PPC_REG_30 = 32
|
||||
UC_PPC_REG_31 = 33
|
142
bindings/python/unicorn/riscv_const.py
Normal file
142
bindings/python/unicorn/riscv_const.py
Normal file
@ -0,0 +1,142 @@
|
||||
# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [riscv_const.py]
|
||||
|
||||
# RISCV registers
|
||||
|
||||
UC_RISCV_REG_INVALID = 0
|
||||
|
||||
# General purpose registers
|
||||
UC_RISCV_REG_X0 = 1
|
||||
UC_RISCV_REG_X1 = 2
|
||||
UC_RISCV_REG_X2 = 3
|
||||
UC_RISCV_REG_X3 = 4
|
||||
UC_RISCV_REG_X4 = 5
|
||||
UC_RISCV_REG_X5 = 6
|
||||
UC_RISCV_REG_X6 = 7
|
||||
UC_RISCV_REG_X7 = 8
|
||||
UC_RISCV_REG_X8 = 9
|
||||
UC_RISCV_REG_X9 = 10
|
||||
UC_RISCV_REG_X10 = 11
|
||||
UC_RISCV_REG_X11 = 12
|
||||
UC_RISCV_REG_X12 = 13
|
||||
UC_RISCV_REG_X13 = 14
|
||||
UC_RISCV_REG_X14 = 15
|
||||
UC_RISCV_REG_X15 = 16
|
||||
UC_RISCV_REG_X16 = 17
|
||||
UC_RISCV_REG_X17 = 18
|
||||
UC_RISCV_REG_X18 = 19
|
||||
UC_RISCV_REG_X19 = 20
|
||||
UC_RISCV_REG_X20 = 21
|
||||
UC_RISCV_REG_X21 = 22
|
||||
UC_RISCV_REG_X22 = 23
|
||||
UC_RISCV_REG_X23 = 24
|
||||
UC_RISCV_REG_X24 = 25
|
||||
UC_RISCV_REG_X25 = 26
|
||||
UC_RISCV_REG_X26 = 27
|
||||
UC_RISCV_REG_X27 = 28
|
||||
UC_RISCV_REG_X28 = 29
|
||||
UC_RISCV_REG_X29 = 30
|
||||
UC_RISCV_REG_X30 = 31
|
||||
UC_RISCV_REG_X31 = 32
|
||||
|
||||
# Floating-point registers
|
||||
UC_RISCV_REG_F0 = 33
|
||||
UC_RISCV_REG_F1 = 34
|
||||
UC_RISCV_REG_F2 = 35
|
||||
UC_RISCV_REG_F3 = 36
|
||||
UC_RISCV_REG_F4 = 37
|
||||
UC_RISCV_REG_F5 = 38
|
||||
UC_RISCV_REG_F6 = 39
|
||||
UC_RISCV_REG_F7 = 40
|
||||
UC_RISCV_REG_F8 = 41
|
||||
UC_RISCV_REG_F9 = 42
|
||||
UC_RISCV_REG_F10 = 43
|
||||
UC_RISCV_REG_F11 = 44
|
||||
UC_RISCV_REG_F12 = 45
|
||||
UC_RISCV_REG_F13 = 46
|
||||
UC_RISCV_REG_F14 = 47
|
||||
UC_RISCV_REG_F15 = 48
|
||||
UC_RISCV_REG_F16 = 49
|
||||
UC_RISCV_REG_F17 = 50
|
||||
UC_RISCV_REG_F18 = 51
|
||||
UC_RISCV_REG_F19 = 52
|
||||
UC_RISCV_REG_F20 = 53
|
||||
UC_RISCV_REG_F21 = 54
|
||||
UC_RISCV_REG_F22 = 55
|
||||
UC_RISCV_REG_F23 = 56
|
||||
UC_RISCV_REG_F24 = 57
|
||||
UC_RISCV_REG_F25 = 58
|
||||
UC_RISCV_REG_F26 = 59
|
||||
UC_RISCV_REG_F27 = 60
|
||||
UC_RISCV_REG_F28 = 61
|
||||
UC_RISCV_REG_F29 = 62
|
||||
UC_RISCV_REG_F30 = 63
|
||||
UC_RISCV_REG_F31 = 64
|
||||
UC_RISCV_REG_PC = 65
|
||||
UC_RISCV_REG_ENDING = 66
|
||||
|
||||
# Alias registers
|
||||
UC_RISCV_REG_ZERO = 1
|
||||
UC_RISCV_REG_RA = 2
|
||||
UC_RISCV_REG_SP = 3
|
||||
UC_RISCV_REG_GP = 4
|
||||
UC_RISCV_REG_TP = 5
|
||||
UC_RISCV_REG_T0 = 6
|
||||
UC_RISCV_REG_T1 = 7
|
||||
UC_RISCV_REG_T2 = 8
|
||||
UC_RISCV_REG_S0 = 9
|
||||
UC_RISCV_REG_FP = 9
|
||||
UC_RISCV_REG_S1 = 10
|
||||
UC_RISCV_REG_A0 = 11
|
||||
UC_RISCV_REG_A1 = 12
|
||||
UC_RISCV_REG_A2 = 13
|
||||
UC_RISCV_REG_A3 = 14
|
||||
UC_RISCV_REG_A4 = 15
|
||||
UC_RISCV_REG_A5 = 16
|
||||
UC_RISCV_REG_A6 = 17
|
||||
UC_RISCV_REG_A7 = 18
|
||||
UC_RISCV_REG_S2 = 19
|
||||
UC_RISCV_REG_S3 = 20
|
||||
UC_RISCV_REG_S4 = 21
|
||||
UC_RISCV_REG_S5 = 22
|
||||
UC_RISCV_REG_S6 = 23
|
||||
UC_RISCV_REG_S7 = 24
|
||||
UC_RISCV_REG_S8 = 25
|
||||
UC_RISCV_REG_S9 = 26
|
||||
UC_RISCV_REG_S10 = 27
|
||||
UC_RISCV_REG_S11 = 28
|
||||
UC_RISCV_REG_T3 = 29
|
||||
UC_RISCV_REG_T4 = 30
|
||||
UC_RISCV_REG_T5 = 31
|
||||
UC_RISCV_REG_T6 = 32
|
||||
UC_RISCV_REG_FT0 = 33
|
||||
UC_RISCV_REG_FT1 = 34
|
||||
UC_RISCV_REG_FT2 = 35
|
||||
UC_RISCV_REG_FT3 = 36
|
||||
UC_RISCV_REG_FT4 = 37
|
||||
UC_RISCV_REG_FT5 = 38
|
||||
UC_RISCV_REG_FT6 = 39
|
||||
UC_RISCV_REG_FT7 = 40
|
||||
UC_RISCV_REG_FS0 = 41
|
||||
UC_RISCV_REG_FS1 = 42
|
||||
UC_RISCV_REG_FA0 = 43
|
||||
UC_RISCV_REG_FA1 = 44
|
||||
UC_RISCV_REG_FA2 = 45
|
||||
UC_RISCV_REG_FA3 = 46
|
||||
UC_RISCV_REG_FA4 = 47
|
||||
UC_RISCV_REG_FA5 = 48
|
||||
UC_RISCV_REG_FA6 = 49
|
||||
UC_RISCV_REG_FA7 = 50
|
||||
UC_RISCV_REG_FS2 = 51
|
||||
UC_RISCV_REG_FS3 = 52
|
||||
UC_RISCV_REG_FS4 = 53
|
||||
UC_RISCV_REG_FS5 = 54
|
||||
UC_RISCV_REG_FS6 = 55
|
||||
UC_RISCV_REG_FS7 = 56
|
||||
UC_RISCV_REG_FS8 = 57
|
||||
UC_RISCV_REG_FS9 = 58
|
||||
UC_RISCV_REG_FS10 = 59
|
||||
UC_RISCV_REG_FS11 = 60
|
||||
UC_RISCV_REG_FT8 = 61
|
||||
UC_RISCV_REG_FT9 = 62
|
||||
UC_RISCV_REG_FT10 = 63
|
||||
UC_RISCV_REG_FT11 = 64
|
@ -3,12 +3,12 @@
|
||||
import ctypes
|
||||
import ctypes.util
|
||||
import distutils.sysconfig
|
||||
from functools import wraps
|
||||
import pkg_resources
|
||||
import inspect
|
||||
import os.path
|
||||
import sys
|
||||
import weakref
|
||||
import functools
|
||||
|
||||
from . import x86_const, arm64_const, unicorn_const as uc
|
||||
|
||||
@ -105,6 +105,8 @@ def _setup_prototype(lib, fname, restype, *argtypes):
|
||||
getattr(lib, fname).argtypes = argtypes
|
||||
|
||||
ucerr = 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
|
||||
@ -130,6 +132,7 @@ _setup_prototype(_uc, "uc_mem_write", ucerr, uc_engine, ctypes.c_uint64, ctypes.
|
||||
_setup_prototype(_uc, "uc_emu_start", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_size_t)
|
||||
_setup_prototype(_uc, "uc_emu_stop", ucerr, uc_engine)
|
||||
_setup_prototype(_uc, "uc_hook_del", ucerr, uc_engine, uc_hook_h)
|
||||
_setup_prototype(_uc, "uc_mmio_map", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p)
|
||||
_setup_prototype(_uc, "uc_mem_map", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_uint32)
|
||||
_setup_prototype(_uc, "uc_mem_map_ptr", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_uint32, ctypes.c_void_p)
|
||||
_setup_prototype(_uc, "uc_mem_unmap", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t)
|
||||
@ -140,12 +143,12 @@ _setup_prototype(_uc, "uc_free", ucerr, ctypes.c_void_p)
|
||||
_setup_prototype(_uc, "uc_context_save", ucerr, uc_engine, uc_context)
|
||||
_setup_prototype(_uc, "uc_context_restore", ucerr, uc_engine, uc_context)
|
||||
_setup_prototype(_uc, "uc_context_size", ctypes.c_size_t, uc_engine)
|
||||
_setup_prototype(_uc, "uc_context_reg_read", ucerr, uc_context, ctypes.c_int, ctypes.c_void_p)
|
||||
_setup_prototype(_uc, "uc_context_reg_write", ucerr, uc_context, ctypes.c_int, ctypes.c_void_p)
|
||||
_setup_prototype(_uc, "uc_context_free", ucerr, uc_context)
|
||||
_setup_prototype(_uc, "uc_mem_regions", ucerr, uc_engine, ctypes.POINTER(ctypes.POINTER(_uc_mem_region)), ctypes.POINTER(ctypes.c_uint32))
|
||||
|
||||
# uc_hook_add is special due to variable number of arguments
|
||||
_uc.uc_hook_add = _uc.uc_hook_add
|
||||
_uc.uc_hook_add.restype = ucerr
|
||||
# https://bugs.python.org/issue42880
|
||||
_setup_prototype(_uc, "uc_hook_add", ucerr, uc_engine, ctypes.POINTER(uc_hook_h), ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint64, ctypes.c_uint64)
|
||||
|
||||
UC_HOOK_CODE_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p)
|
||||
UC_HOOK_INSN_INVALID_CB = ctypes.CFUNCTYPE(ctypes.c_bool, uc_engine, ctypes.c_void_p)
|
||||
@ -168,7 +171,12 @@ UC_HOOK_INSN_OUT_CB = ctypes.CFUNCTYPE(
|
||||
ctypes.c_int, ctypes.c_uint32, ctypes.c_void_p
|
||||
)
|
||||
UC_HOOK_INSN_SYSCALL_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_void_p)
|
||||
|
||||
UC_MMIO_READ_CB = ctypes.CFUNCTYPE(
|
||||
ctypes.c_uint64, uc_engine, ctypes.c_uint64, ctypes.c_int, ctypes.c_void_p
|
||||
)
|
||||
UC_MMIO_WRITE_CB = ctypes.CFUNCTYPE(
|
||||
None, uc_engine, ctypes.c_uint64, ctypes.c_int, ctypes.c_uint64, ctypes.c_void_p
|
||||
)
|
||||
|
||||
# access to error code via @errno of UcError
|
||||
class UcError(Exception):
|
||||
@ -199,27 +207,103 @@ def version_bind():
|
||||
def uc_arch_supported(query):
|
||||
return _uc.uc_arch_supported(query)
|
||||
|
||||
# uc_reg_read/write and uc_context_reg_read/write.
|
||||
def reg_read(reg_read_func, arch, reg_id, opt=None):
|
||||
if arch == uc.UC_ARCH_X86:
|
||||
if reg_id in [x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]:
|
||||
reg = uc_x86_mmr()
|
||||
status = reg_read_func(reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg.selector, reg.base, reg.limit, reg.flags
|
||||
if reg_id in range(x86_const.UC_X86_REG_FP0, x86_const.UC_X86_REG_FP0+8):
|
||||
reg = uc_x86_float80()
|
||||
status = reg_read_func(reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg.mantissa, reg.exponent
|
||||
if reg_id in range(x86_const.UC_X86_REG_XMM0, x86_const.UC_X86_REG_XMM0+8):
|
||||
reg = uc_x86_xmm()
|
||||
status = reg_read_func(reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg.low_qword | (reg.high_qword << 64)
|
||||
if reg_id in range(x86_const.UC_X86_REG_YMM0, x86_const.UC_X86_REG_YMM0+16):
|
||||
reg = uc_x86_ymm()
|
||||
status = reg_read_func(reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg.first_qword | (reg.second_qword << 64) | (reg.third_qword << 128) | (reg.fourth_qword << 192)
|
||||
if reg_id is x86_const.UC_X86_REG_MSR:
|
||||
if opt is None:
|
||||
raise UcError(uc.UC_ERR_ARG)
|
||||
reg = uc_x86_msr()
|
||||
reg.rid = opt
|
||||
status = reg_read_func(reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg.value
|
||||
|
||||
def _catch_hook_exception(func):
|
||||
@wraps(func)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
"""Catches exceptions raised in hook functions.
|
||||
if arch == uc.UC_ARCH_ARM64:
|
||||
if reg_id in range(arm64_const.UC_ARM64_REG_Q0, arm64_const.UC_ARM64_REG_Q31+1) or range(arm64_const.UC_ARM64_REG_V0, arm64_const.UC_ARM64_REG_V31+1):
|
||||
reg = uc_arm64_neon128()
|
||||
status = reg_read_func(reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg.low_qword | (reg.high_qword << 64)
|
||||
|
||||
If an exception is raised, it is saved to the Uc object and a call to stop
|
||||
emulation is issued.
|
||||
"""
|
||||
try:
|
||||
return func(self, *args, **kwargs)
|
||||
except Exception as e:
|
||||
# If multiple hooks raise exceptions, just use the first one
|
||||
if self._hook_exception is None:
|
||||
self._hook_exception = e
|
||||
# read to 64bit number to be safe
|
||||
reg = ctypes.c_uint64(0)
|
||||
status = reg_read_func(reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg.value
|
||||
|
||||
self.emu_stop()
|
||||
def reg_write(reg_write_func, arch, reg_id, value):
|
||||
reg = None
|
||||
|
||||
return wrapper
|
||||
if arch == uc.UC_ARCH_X86:
|
||||
if reg_id in [x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]:
|
||||
assert isinstance(value, tuple) and len(value) == 4
|
||||
reg = uc_x86_mmr()
|
||||
reg.selector = value[0]
|
||||
reg.base = value[1]
|
||||
reg.limit = value[2]
|
||||
reg.flags = value[3]
|
||||
if reg_id in range(x86_const.UC_X86_REG_FP0, x86_const.UC_X86_REG_FP0+8):
|
||||
reg = uc_x86_float80()
|
||||
reg.mantissa = value[0]
|
||||
reg.exponent = value[1]
|
||||
if reg_id in range(x86_const.UC_X86_REG_XMM0, x86_const.UC_X86_REG_XMM0+8):
|
||||
reg = uc_x86_xmm()
|
||||
reg.low_qword = value & 0xffffffffffffffff
|
||||
reg.high_qword = value >> 64
|
||||
if reg_id in range(x86_const.UC_X86_REG_YMM0, x86_const.UC_X86_REG_YMM0+16):
|
||||
reg = uc_x86_ymm()
|
||||
reg.first_qword = value & 0xffffffffffffffff
|
||||
reg.second_qword = (value >> 64) & 0xffffffffffffffff
|
||||
reg.third_qword = (value >> 128) & 0xffffffffffffffff
|
||||
reg.fourth_qword = value >> 192
|
||||
if reg_id is x86_const.UC_X86_REG_MSR:
|
||||
reg = uc_x86_msr()
|
||||
reg.rid = value[0]
|
||||
reg.value = value[1]
|
||||
|
||||
if arch == uc.UC_ARCH_ARM64:
|
||||
if reg_id in range(arm64_const.UC_ARM64_REG_Q0, arm64_const.UC_ARM64_REG_Q31+1) or range(arm64_const.UC_ARM64_REG_V0, arm64_const.UC_ARM64_REG_V31+1):
|
||||
reg = uc_arm64_neon128()
|
||||
reg.low_qword = value & 0xffffffffffffffff
|
||||
reg.high_qword = value >> 64
|
||||
|
||||
if reg is None:
|
||||
# convert to 64bit number to be safe
|
||||
reg = ctypes.c_uint64(value)
|
||||
|
||||
status = reg_write_func(reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
|
||||
return
|
||||
|
||||
class uc_x86_mmr(ctypes.Structure):
|
||||
"""Memory-Management Register for instructions IDTR, GDTR, LDTR, TR."""
|
||||
@ -306,6 +390,8 @@ class Uc(object):
|
||||
def __init__(self, arch, mode):
|
||||
# verify version compatibility with the core before doing anything
|
||||
(major, minor, _combined) = uc_version()
|
||||
# print("core version =", uc_version())
|
||||
# print("binding version =", uc.UC_API_MAJOR, uc.UC_API_MINOR)
|
||||
if major != uc.UC_API_MAJOR or minor != uc.UC_API_MINOR:
|
||||
self._uch = None
|
||||
# our binding version is different from the core's API version
|
||||
@ -319,10 +405,9 @@ class Uc(object):
|
||||
raise UcError(status)
|
||||
# internal mapping table to save callback & userdata
|
||||
self._callbacks = {}
|
||||
self._ctype_cbs = {}
|
||||
self._ctype_cbs = []
|
||||
self._callback_count = 0
|
||||
self._cleanup.register(self)
|
||||
self._hook_exception = None # The exception raised in a hook
|
||||
|
||||
@staticmethod
|
||||
def release_handle(uch):
|
||||
@ -340,9 +425,6 @@ class Uc(object):
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
|
||||
if self._hook_exception is not None:
|
||||
raise self._hook_exception
|
||||
|
||||
# stop emulation
|
||||
def emu_stop(self):
|
||||
status = _uc.uc_emu_stop(self._uch)
|
||||
@ -351,100 +433,11 @@ class Uc(object):
|
||||
|
||||
# return the value of a register
|
||||
def reg_read(self, reg_id, opt=None):
|
||||
if self._arch == uc.UC_ARCH_X86:
|
||||
if reg_id in [x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]:
|
||||
reg = uc_x86_mmr()
|
||||
status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg.selector, reg.base, reg.limit, reg.flags
|
||||
if reg_id in range(x86_const.UC_X86_REG_FP0, x86_const.UC_X86_REG_FP0+8):
|
||||
reg = uc_x86_float80()
|
||||
status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg.mantissa, reg.exponent
|
||||
if reg_id in range(x86_const.UC_X86_REG_XMM0, x86_const.UC_X86_REG_XMM0+8):
|
||||
reg = uc_x86_xmm()
|
||||
status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg.low_qword | (reg.high_qword << 64)
|
||||
if reg_id in range(x86_const.UC_X86_REG_YMM0, x86_const.UC_X86_REG_YMM0+16):
|
||||
reg = uc_x86_ymm()
|
||||
status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg.first_qword | (reg.second_qword << 64) | (reg.third_qword << 128) | (reg.fourth_qword << 192)
|
||||
if reg_id is x86_const.UC_X86_REG_MSR:
|
||||
if opt is None:
|
||||
raise UcError(uc.UC_ERR_ARG)
|
||||
reg = uc_x86_msr()
|
||||
reg.rid = opt
|
||||
status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg.value
|
||||
|
||||
if self._arch == uc.UC_ARCH_ARM64:
|
||||
if reg_id in range(arm64_const.UC_ARM64_REG_Q0, arm64_const.UC_ARM64_REG_Q31+1) or range(arm64_const.UC_ARM64_REG_V0, arm64_const.UC_ARM64_REG_V31+1):
|
||||
reg = uc_arm64_neon128()
|
||||
status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg.low_qword | (reg.high_qword << 64)
|
||||
|
||||
# read to 64bit number to be safe
|
||||
reg = ctypes.c_uint64(0)
|
||||
status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg.value
|
||||
return reg_read(functools.partial(_uc.uc_reg_read, self._uch), self._arch, reg_id, opt)
|
||||
|
||||
# write to a register
|
||||
def reg_write(self, reg_id, value):
|
||||
reg = None
|
||||
|
||||
if self._arch == uc.UC_ARCH_X86:
|
||||
if reg_id in [x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]:
|
||||
assert isinstance(value, tuple) and len(value) == 4
|
||||
reg = uc_x86_mmr()
|
||||
reg.selector = value[0]
|
||||
reg.base = value[1]
|
||||
reg.limit = value[2]
|
||||
reg.flags = value[3]
|
||||
if reg_id in range(x86_const.UC_X86_REG_FP0, x86_const.UC_X86_REG_FP0+8):
|
||||
reg = uc_x86_float80()
|
||||
reg.mantissa = value[0]
|
||||
reg.exponent = value[1]
|
||||
if reg_id in range(x86_const.UC_X86_REG_XMM0, x86_const.UC_X86_REG_XMM0+8):
|
||||
reg = uc_x86_xmm()
|
||||
reg.low_qword = value & 0xffffffffffffffff
|
||||
reg.high_qword = value >> 64
|
||||
if reg_id in range(x86_const.UC_X86_REG_YMM0, x86_const.UC_X86_REG_YMM0+16):
|
||||
reg = uc_x86_ymm()
|
||||
reg.first_qword = value & 0xffffffffffffffff
|
||||
reg.second_qword = (value >> 64) & 0xffffffffffffffff
|
||||
reg.third_qword = (value >> 128) & 0xffffffffffffffff
|
||||
reg.fourth_qword = value >> 192
|
||||
if reg_id is x86_const.UC_X86_REG_MSR:
|
||||
reg = uc_x86_msr()
|
||||
reg.rid = value[0]
|
||||
reg.value = value[1]
|
||||
|
||||
if self._arch == uc.UC_ARCH_ARM64:
|
||||
if reg_id in range(arm64_const.UC_ARM64_REG_Q0, arm64_const.UC_ARM64_REG_Q31+1) or range(arm64_const.UC_ARM64_REG_V0, arm64_const.UC_ARM64_REG_V31+1):
|
||||
reg = uc_arm64_neon128()
|
||||
reg.low_qword = value & 0xffffffffffffffff
|
||||
reg.high_qword = value >> 64
|
||||
|
||||
if reg is None:
|
||||
# convert to 64bit number to be safe
|
||||
reg = ctypes.c_uint64(value)
|
||||
|
||||
status = _uc.uc_reg_write(self._uch, reg_id, ctypes.byref(reg))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg_write(functools.partial(_uc.uc_reg_write, self._uch), self._arch, reg_id, value)
|
||||
|
||||
# read from MSR - X86 only
|
||||
def msr_read(self, msr_id):
|
||||
@ -468,6 +461,33 @@ class Uc(object):
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
|
||||
def _mmio_map_read_cb(self, handle, offset, size, user_data):
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
return cb(self, offset, size, data)
|
||||
|
||||
def _mmio_map_write_cb(self, handle, offset, size, value, user_data):
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
cb(self, offset, size, value, data)
|
||||
|
||||
def mmio_map(self, address, size, read_cb, user_data_read, write_cb, user_data_write):
|
||||
internal_read_cb = ctypes.cast(UC_MMIO_READ_CB(self._mmio_map_read_cb), UC_MMIO_READ_CB)
|
||||
internal_write_cb = ctypes.cast(UC_MMIO_WRITE_CB(self._mmio_map_write_cb), UC_MMIO_WRITE_CB)
|
||||
|
||||
self._callback_count += 1
|
||||
self._callbacks[self._callback_count] = (read_cb, user_data_read)
|
||||
read_count = self._callback_count
|
||||
self._callback_count += 1
|
||||
self._callbacks[self._callback_count] = (write_cb, user_data_write)
|
||||
write_count = self._callback_count
|
||||
|
||||
status = _uc.uc_mmio_map(self._uch, address, size, internal_read_cb, read_count, internal_write_cb, write_count)
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
|
||||
# https://docs.python.org/3/library/ctypes.html#callback-functions
|
||||
self._ctype_cbs.append(internal_read_cb)
|
||||
self._ctype_cbs.append(internal_write_cb)
|
||||
|
||||
# map a range of memory
|
||||
def mem_map(self, address, size, perms=uc.UC_PROT_ALL):
|
||||
status = _uc.uc_mem_map(self._uch, address, size, perms)
|
||||
@ -500,49 +520,41 @@ class Uc(object):
|
||||
raise UcError(status)
|
||||
return result.value
|
||||
|
||||
@_catch_hook_exception
|
||||
def _hookcode_cb(self, handle, address, size, user_data):
|
||||
# call user's callback with self object
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
cb(self, address, size, data)
|
||||
|
||||
@_catch_hook_exception
|
||||
def _hook_mem_invalid_cb(self, handle, access, address, size, value, user_data):
|
||||
# call user's callback with self object
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
return cb(self, access, address, size, value, data)
|
||||
|
||||
@_catch_hook_exception
|
||||
def _hook_mem_access_cb(self, handle, access, address, size, value, user_data):
|
||||
# call user's callback with self object
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
cb(self, access, address, size, value, data)
|
||||
|
||||
@_catch_hook_exception
|
||||
def _hook_intr_cb(self, handle, intno, user_data):
|
||||
# call user's callback with self object
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
cb(self, intno, data)
|
||||
|
||||
@_catch_hook_exception
|
||||
def _hook_insn_invalid_cb(self, handle, user_data):
|
||||
# call user's callback with self object
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
return cb(self, data)
|
||||
|
||||
@_catch_hook_exception
|
||||
def _hook_insn_in_cb(self, handle, port, size, user_data):
|
||||
# call user's callback with self object
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
return cb(self, port, size, data)
|
||||
|
||||
@_catch_hook_exception
|
||||
def _hook_insn_out_cb(self, handle, port, size, value, user_data):
|
||||
# call user's callback with self object
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
cb(self, port, size, value, data)
|
||||
|
||||
@_catch_hook_exception
|
||||
def _hook_insn_syscall_cb(self, handle, user_data):
|
||||
# call user's callback with self object
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
@ -615,7 +627,7 @@ class Uc(object):
|
||||
)
|
||||
|
||||
# save the ctype function so gc will leave it alone.
|
||||
self._ctype_cbs[self._callback_count] = cb
|
||||
self._ctype_cbs.append(cb)
|
||||
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
@ -631,7 +643,7 @@ class Uc(object):
|
||||
h = 0
|
||||
|
||||
def context_save(self):
|
||||
context = UcContext(self._uch)
|
||||
context = UcContext(self._uch, self._arch, self._mode)
|
||||
status = _uc.uc_context_save(self._uch, context.context)
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
@ -664,14 +676,16 @@ class Uc(object):
|
||||
|
||||
|
||||
class UcContext:
|
||||
def __init__(self, h):
|
||||
def __init__(self, h, arch, mode):
|
||||
self._context = uc_context()
|
||||
self._size = _uc.uc_context_size(h)
|
||||
self._to_free = True
|
||||
status = _uc.uc_context_alloc(h, ctypes.byref(self._context))
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
|
||||
self._arch = arch
|
||||
self._mode = mode
|
||||
|
||||
@property
|
||||
def context(self):
|
||||
return self._context
|
||||
@ -680,16 +694,34 @@ class UcContext:
|
||||
def size(self):
|
||||
return self._size
|
||||
|
||||
@property
|
||||
def arch(self):
|
||||
return self._arch
|
||||
|
||||
@property
|
||||
def mode(self):
|
||||
return self._mode
|
||||
|
||||
# return the value of a register
|
||||
def reg_read(self, reg_id, opt=None):
|
||||
return reg_read(functools.partial(_uc.uc_context_reg_read, self._context), self.arch, reg_id, opt)
|
||||
|
||||
# write to a register
|
||||
def reg_write(self, reg_id, value):
|
||||
return reg_write(functools.partial(_uc.uc_context_reg_write, self._context), self.arch, reg_id, value)
|
||||
|
||||
# Make UcContext picklable
|
||||
def __getstate__(self):
|
||||
return (bytes(self), self.size)
|
||||
|
||||
return (bytes(self), self.size, self.arch, self.mode)
|
||||
|
||||
def __setstate__(self, state):
|
||||
self._size = state[1]
|
||||
self._context = ctypes.cast(ctypes.create_string_buffer(state[0], self._size), uc_context)
|
||||
# __init__ won'e be invoked, so we are safe to set it here.
|
||||
self._to_free = False
|
||||
|
||||
self._arch = state[2]
|
||||
self._mode = state[3]
|
||||
|
||||
def __bytes__(self):
|
||||
return ctypes.string_at(self.context, self.size)
|
||||
|
||||
@ -708,6 +740,8 @@ def debug():
|
||||
"sparc": uc.UC_ARCH_SPARC,
|
||||
"m68k": uc.UC_ARCH_M68K,
|
||||
"x86": uc.UC_ARCH_X86,
|
||||
"riscv": uc.UC_ARCH_RISCV,
|
||||
"ppc": uc.UC_ARCH_PPC,
|
||||
}
|
||||
|
||||
all_archs = ""
|
||||
|
@ -1,11 +1,12 @@
|
||||
# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [unicorn_const.py]
|
||||
UC_API_MAJOR = 1
|
||||
UC_API_MAJOR = 2
|
||||
|
||||
UC_API_MINOR = 0
|
||||
UC_VERSION_MAJOR = 1
|
||||
UC_VERSION_MAJOR = 2
|
||||
|
||||
UC_VERSION_MINOR = 0
|
||||
UC_VERSION_EXTRA = 3
|
||||
|
||||
UC_VERSION_EXTRA = 0
|
||||
UC_SECOND_SCALE = 1000000
|
||||
UC_MILISECOND_SCALE = 1000
|
||||
UC_ARCH_ARM = 1
|
||||
@ -15,7 +16,8 @@ UC_ARCH_X86 = 4
|
||||
UC_ARCH_PPC = 5
|
||||
UC_ARCH_SPARC = 6
|
||||
UC_ARCH_M68K = 7
|
||||
UC_ARCH_MAX = 8
|
||||
UC_ARCH_RISCV = 8
|
||||
UC_ARCH_MAX = 9
|
||||
|
||||
UC_MODE_LITTLE_ENDIAN = 0
|
||||
UC_MODE_BIG_ENDIAN = 1073741824
|
||||
@ -27,7 +29,6 @@ UC_MODE_V8 = 64
|
||||
UC_MODE_ARM926 = 128
|
||||
UC_MODE_ARM946 = 256
|
||||
UC_MODE_ARM1176 = 512
|
||||
UC_MODE_ARMBE8 = 1024
|
||||
UC_MODE_MICRO = 16
|
||||
UC_MODE_MIPS3 = 32
|
||||
UC_MODE_MIPS32R6 = 64
|
||||
@ -42,6 +43,8 @@ UC_MODE_QPX = 16
|
||||
UC_MODE_SPARC32 = 4
|
||||
UC_MODE_SPARC64 = 8
|
||||
UC_MODE_V9 = 16
|
||||
UC_MODE_RISCV32 = 4
|
||||
UC_MODE_RISCV64 = 8
|
||||
|
||||
UC_ERR_OK = 0
|
||||
UC_ERR_NOMEM = 1
|
||||
|
@ -254,7 +254,9 @@ UC_X86_REG_MSR = 248
|
||||
UC_X86_REG_MXCSR = 249
|
||||
UC_X86_REG_FS_BASE = 250
|
||||
UC_X86_REG_GS_BASE = 251
|
||||
UC_X86_REG_ENDING = 252
|
||||
UC_X86_REG_FLAGS = 252
|
||||
UC_X86_REG_RFLAGS = 253
|
||||
UC_X86_REG_ENDING = 254
|
||||
|
||||
# X86 instructions
|
||||
|
||||
|
Reference in New Issue
Block a user