import Unicorn2

This commit is contained in:
Nguyen Anh Quynh
2021-10-03 22:14:44 +08:00
parent 772558119a
commit aaaea14214
837 changed files with 368717 additions and 200912 deletions

View File

@ -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

View 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

View 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

View File

@ -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 = ""

View File

@ -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

View File

@ -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