import Unicorn2
This commit is contained in:
@ -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 .
|
@ -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
65
bindings/python/sample_ppc.py
Executable 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
71
bindings/python/sample_riscv.py
Executable 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()
|
||||
|
@ -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()
|
||||
|
@ -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/*']
|
||||
}
|
||||
|
@ -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