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

@ -1,14 +0,0 @@
#!/bin/bash
set -e -x
cd bindings/python
# Compile wheels
if [ -f /opt/python/cp36-cp36m/bin/python ];then
/opt/python/cp36-cp36m/bin/python setup.py bdist_wheel
else
python3 setup.py bdist_wheel
fi
cd dist
auditwheel repair *.whl
mv -f wheelhouse/*.whl .

View File

@ -45,7 +45,7 @@ def test_arm64():
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, hook_block)
# tracing one instruction at ADDRESS with customized callback
# tracing one instruction with customized callback
mu.hook_add(UC_HOOK_CODE, hook_code, begin=ADDRESS, end=ADDRESS)
# emulate machine code in infinite time

65
bindings/python/sample_ppc.py Executable file
View File

@ -0,0 +1,65 @@
#!/usr/bin/env python
# Sample code for PPC of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
#
from __future__ import print_function
from unicorn import *
from unicorn.ppc_const import *
# code to be emulated
PPC_CODE = b"\x7F\x46\x1A\x14" # add r26, r6, r3
# memory address where emulation starts
ADDRESS = 0x10000
# callback for tracing basic blocks
def hook_block(uc, address, size, user_data):
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
# callback for tracing instructions
def hook_code(uc, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
# Test PPC
def test_ppc():
print("Emulate PPC code")
try:
# Initialize emulator in PPC EB mode
mu = Uc(UC_ARCH_PPC, UC_MODE_PPC32 | UC_MODE_BIG_ENDIAN)
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, PPC_CODE)
# initialize machine registers
mu.reg_write(UC_PPC_REG_3, 0x1234)
mu.reg_write(UC_PPC_REG_6, 0x6789)
mu.reg_write(UC_PPC_REG_26, 0x5555)
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, hook_block)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, hook_code)
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + len(PPC_CODE))
# now print out some registers
print(">>> Emulation done. Below is the CPU context")
r26 = mu.reg_read(UC_PPC_REG_26)
print(">>> r26 = 0x%x" % r26)
except UcError as e:
print("ERROR: %s" % e)
if __name__ == '__main__':
test_ppc()

71
bindings/python/sample_riscv.py Executable file
View File

@ -0,0 +1,71 @@
#!/usr/bin/env python
# Sample code for RISCV of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
#
from __future__ import print_function
from unicorn import *
from unicorn.riscv_const import *
'''
$ cstool riscv64 1305100093850502
0 13 05 10 00 addi a0, zero, 1
4 93 85 05 02 addi a1, a1, 0x20
'''
RISCV_CODE = b"\x13\x05\x10\x00\x93\x85\x05\x02"
# memory address where emulation starts
ADDRESS = 0x10000
# callback for tracing basic blocks
def hook_block(uc, address, size, user_data):
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
# callback for tracing instructions
def hook_code(uc, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
# Test RISCV
def test_riscv():
print("Emulate RISCV code")
try:
# Initialize emulator in RISCV32 mode
mu = Uc(UC_ARCH_RISCV, UC_MODE_RISCV32)
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, RISCV_CODE)
# initialize machine registers
mu.reg_write(UC_RISCV_REG_A0, 0x1234)
mu.reg_write(UC_RISCV_REG_A1, 0x7890)
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, hook_block)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, hook_code)
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + len(RISCV_CODE))
# now print out some registers
print(">>> Emulation done. Below is the CPU context")
a0 = mu.reg_read(UC_RISCV_REG_A0)
a1 = mu.reg_read(UC_RISCV_REG_A1)
print(">>> A0 = 0x%x" %a0)
print(">>> A1 = 0x%x" %a1)
except UcError as e:
print("ERROR: %s" % e)
if __name__ == '__main__':
test_riscv()

View File

@ -16,6 +16,7 @@ X86_CODE64 = b"\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\
X86_CODE32_INOUT = b"\x41\xE4\x3F\x4a\xE6\x46\x43" # INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46, AL; INC ebx
X86_CODE64_SYSCALL = b'\x0f\x05' # SYSCALL
X86_CODE16 = b'\x00\x00' # add byte ptr [bx + si], al
X86_MMIO_CODE = b"\x89\x0d\x04\x00\x02\x00\x8b\x0d\x04\x00\x02\x00" # mov [0x20004], ecx; mov ecx, [0x20004]
# memory address where emulation starts
ADDRESS = 0x1000000
@ -386,7 +387,6 @@ def test_i386_loop():
except UcError as e:
print("ERROR: %s" % e)
# Test X86 32 bit with IN/OUT instruction
def test_i386_inout():
print("Emulate i386 code with IN/OUT instructions")
@ -464,6 +464,9 @@ def test_i386_context_save():
print(">>> Unpickling CPU context")
saved_context = pickle.loads(pickled_saved_context)
print(">>> Modifying some register.")
saved_context.reg_write(UC_X86_REG_EAX, 0xc8c8)
print(">>> CPU context restored. Below is the CPU context")
mu.context_restore(saved_context)
print(">>> EAX = 0x%x" %(mu.reg_read(UC_X86_REG_EAX)))
@ -628,6 +631,38 @@ def test_x86_16():
except UcError as e:
print("ERROR: %s" % e)
def mmio_read_cb(uc, offset, size, data):
print(f">>> Read IO memory at offset {hex(offset)} with {hex(size)} bytes and return 0x19260817")
return 0x19260817
def mmio_write_cb(uc, offset, size, value, data):
print(f">>> Write value {hex(value)} to IO memory at offset {hex(offset)} with {hex(size)} bytes")
def test_i386_mmio():
print("Test i386 IO memory")
try:
# Initialize emulator in X86-32bit mode
mu = Uc(UC_ARCH_X86, UC_MODE_32)
# map 8KB memory for this emulation and write the code
mu.mem_map(0x10000, 0x8000)
mu.mem_write(0x10000, X86_MMIO_CODE)
# map the IO memory
mu.mmio_map(0x20000, 0x4000, mmio_read_cb, None, mmio_write_cb, None)
# prepare registers.
mu.reg_write(UC_X86_REG_ECX, 0xdeadbeef)
# emulate machine code in infinite time
mu.emu_start(0x10000, 0x10000 + len(X86_MMIO_CODE))
# now print out some registers
print(f">>> Emulation done. ECX={hex(mu.reg_read(UC_X86_REG_ECX))}")
except UcError as e:
print("ERROR: %s" % e)
if __name__ == '__main__':
test_x86_16()
@ -651,3 +686,5 @@ if __name__ == '__main__':
test_x86_64()
print("=" * 35)
test_x86_64_syscall()
print("=" * 35)
test_i386_mmio()

View File

@ -15,7 +15,6 @@ from distutils.util import get_platform
from distutils.command.build import build
from distutils.command.sdist import sdist
from setuptools.command.bdist_egg import bdist_egg
from setuptools.command.develop import develop
SYSTEM = sys.platform
@ -23,36 +22,18 @@ SYSTEM = sys.platform
IS_64BITS = platform.architecture()[0] == '64bit'
# are we building from the repository or from a source distribution?
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
ROOT_DIR = os.path.dirname(os.path.realpath(__file__))
LIBS_DIR = os.path.join(ROOT_DIR, 'unicorn', 'lib')
HEADERS_DIR = os.path.join(ROOT_DIR, 'unicorn', 'include')
SRC_DIR = os.path.join(ROOT_DIR, 'src')
BUILD_DIR = SRC_DIR if os.path.exists(SRC_DIR) else os.path.join(ROOT_DIR, '../..')
UC_DIR = os.path.join(ROOT_DIR, '../..')
BUILD_DIR = os.path.join(UC_DIR, 'build')
# Parse version from pkgconfig.mk
VERSION_DATA = {}
with open(os.path.join(BUILD_DIR, 'pkgconfig.mk')) as fp:
lines = fp.readlines()
for line in lines:
line = line.strip()
if len(line) == 0:
continue
if line.startswith('#'):
continue
if '=' not in line:
continue
k, v = line.split('=', 1)
k = k.strip()
v = v.strip()
if len(k) == 0 or len(v) == 0:
continue
VERSION_DATA[k] = v
if 'PKG_MAJOR' not in VERSION_DATA or \
'PKG_MINOR' not in VERSION_DATA or \
'PKG_EXTRA' not in VERSION_DATA:
raise Exception("Malformed pkgconfig.mk")
VERSION_DATA['PKG_MAJOR'] = "2"
VERSION_DATA['PKG_MINOR'] = "0"
VERSION_DATA['PKG_EXTRA'] = "0"
# VERSION_DATA['PKG_TAG'] = "0"
if 'PKG_TAG' in VERSION_DATA:
VERSION = '{PKG_MAJOR}.{PKG_MINOR}.{PKG_EXTRA}.{PKG_TAG}'.format(**VERSION_DATA)
@ -63,12 +44,9 @@ if SYSTEM == 'darwin':
LIBRARY_FILE = "libunicorn.dylib"
MAC_LIBRARY_FILE = "libunicorn*.dylib"
STATIC_LIBRARY_FILE = None
elif SYSTEM == 'win32':
elif SYSTEM in ('win32', 'cygwin'):
LIBRARY_FILE = "unicorn.dll"
STATIC_LIBRARY_FILE = "unicorn.lib"
elif SYSTEM == 'cygwin':
LIBRARY_FILE = "cygunicorn.dll"
STATIC_LIBRARY_FILE = None
else:
LIBRARY_FILE = "libunicorn.so"
STATIC_LIBRARY_FILE = None
@ -84,7 +62,6 @@ def copy_sources():
"""
src = []
os.system('make -C %s clean' % os.path.join(ROOT_DIR, '../..'))
shutil.rmtree(SRC_DIR, ignore_errors=True)
os.mkdir(SRC_DIR)
@ -108,9 +85,8 @@ def copy_sources():
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../README.md")))
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../*.TXT")))
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../RELEASE_NOTES")))
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../make.sh")))
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../cmake.sh")))
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../CMakeLists.txt")))
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../pkgconfig.mk")))
for filename in src:
outpath = os.path.join(SRC_DIR, os.path.basename(filename))
@ -130,7 +106,7 @@ def build_libraries():
os.mkdir(LIBS_DIR)
# copy public headers
shutil.copytree(os.path.join(BUILD_DIR, 'include', 'unicorn'), os.path.join(HEADERS_DIR, 'unicorn'))
shutil.copytree(os.path.join(UC_DIR, 'include', 'unicorn'), os.path.join(HEADERS_DIR, 'unicorn'))
# check if a prebuilt library exists
# if so, use it instead of building
@ -141,35 +117,37 @@ def build_libraries():
return
# otherwise, build!!
os.chdir(BUILD_DIR)
os.chdir(UC_DIR)
try:
subprocess.check_call(['msbuild', '-ver'])
subprocess.check_call(['msbuild', '/help'])
except:
has_msbuild = False
else:
has_msbuild = True
if has_msbuild and SYSTEM == 'win32':
if platform.architecture()[0] == '32bit':
plat = 'Win32'
elif 'win32' in sys.argv:
plat = 'Win32'
else:
plat = 'x64'
plat = 'Win32' if platform.architecture()[0] == '32bit' else 'x64'
conf = 'Debug' if os.getenv('DEBUG', '') else 'Release'
subprocess.call(['msbuild', 'unicorn.sln', '-m', '-p:Platform=' + plat, '-p:Configuration=' + conf], cwd=os.path.join(BUILD_DIR, 'msvc'))
subprocess.call(['msbuild', '-m', '-p:Platform=' + plat, '-p:Configuration=' + conf], cwd=os.path.join(UC_DIR, 'msvc'))
obj_dir = os.path.join(BUILD_DIR, 'msvc', plat, conf)
obj_dir = os.path.join(UC_DIR, 'msvc', plat, conf)
shutil.copy(os.path.join(obj_dir, LIBRARY_FILE), LIBS_DIR)
shutil.copy(os.path.join(obj_dir, STATIC_LIBRARY_FILE), LIBS_DIR)
else:
# platform description refs at https://docs.python.org/2/library/sys.html#sys.platform
new_env = dict(os.environ)
new_env['UNICORN_BUILD_CORE_ONLY'] = 'yes'
cmd = ['sh', './make.sh']
if SYSTEM == "win32":
if not os.path.exists(BUILD_DIR):
os.mkdir(BUILD_DIR)
os.chdir(BUILD_DIR)
cmd = ['sh', '../cmake.sh']
if SYSTEM == "cygwin":
if IS_64BITS:
cmd.append('cygwin-mingw64')
else:
cmd.append('cygwin-mingw32')
elif SYSTEM == "win32":
if IS_64BITS:
cmd.append('cross-win64')
else:
@ -196,6 +174,7 @@ def build_libraries():
sys.exit(1)
os.chdir(cwd)
class custom_sdist(sdist):
def run(self):
clean_bins()
@ -211,12 +190,6 @@ class custom_build(build):
build_libraries()
return build.run(self)
class custom_develop(develop):
def run(self):
log.info("Building C extensions")
build_libraries()
return develop.run(self)
class custom_bdist_egg(bdist_egg):
def run(self):
self.run_command('build')
@ -225,6 +198,10 @@ class custom_bdist_egg(bdist_egg):
def dummy_src():
return []
cmdclass = {}
cmdclass['build'] = custom_build
cmdclass['sdist'] = custom_sdist
cmdclass['bdist_egg'] = custom_bdist_egg
if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv:
idx = sys.argv.index('bdist_wheel') + 1
@ -245,14 +222,28 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv:
# https://www.python.org/dev/peps/pep-0425/
sys.argv.insert(idx + 1, name.replace('.', '_').replace('-', '_'))
try:
from setuptools.command.develop import develop
class custom_develop(develop):
def run(self):
log.info("Building C extensions")
build_libraries()
return develop.run(self)
cmdclass['develop'] = custom_develop
except ImportError:
print("Proper 'develop' support unavailable.")
def join_all(src, files):
return tuple(os.path.join(src, f) for f in files)
long_desc = '''
Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator framework
based on [QEMU](https://qemu.org).
based on [QEMU](http://qemu.org).
Unicorn offers some unparalleled features:
- Multi-architecture: ARM, ARM64 (ARMv8), M68K, MIPS, SPARC, and X86 (16, 32, 64-bit)
- Multi-architecture: ARM, ARM64 (ARMv8), M68K, MIPS, PowerPC, SPARC and X86 (16, 32, 64-bit)
- Clean/simple/lightweight/intuitive architecture-neutral API
- Implemented in pure C language, with bindings for Crystal, Clojure, Visual Basic, Perl, Rust, Ruby, Python, Java, .NET, Go, Delphi/Free Pascal, Haskell, Pharo, and Lua.
- Native support for Windows & *nix (with Mac OSX, Linux, *BSD & Solaris confirmed)
@ -261,7 +252,7 @@ Unicorn offers some unparalleled features:
- Thread-safety by design
- Distributed under free software license GPLv2
Further information is available at https://www.unicorn-engine.org
Further information is available at http://www.unicorn-engine.org
'''
setup(
@ -273,18 +264,18 @@ setup(
author_email='aquynh@gmail.com',
description='Unicorn CPU emulator engine',
long_description=long_desc,
long_description_content_type="text/markdown",
url='https://www.unicorn-engine.org',
#long_description_content_type="text/markdown",
url='http://www.unicorn-engine.org',
classifiers=[
'License :: OSI Approved :: BSD License',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3',
],
requires=['ctypes'],
cmdclass={'build': custom_build, 'develop': custom_develop, 'sdist': custom_sdist, 'bdist_egg': custom_bdist_egg},
zip_safe=False,
cmdclass=cmdclass,
zip_safe=True,
include_package_data=True,
is_pure=False,
is_pure=True,
package_data={
'unicorn': ['lib/*', 'include/unicorn/*']
}

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