Last active
October 10, 2019 21:34
-
-
Save jcalabres/0645e325b3e5e3a59448975d706cc2b3 to your computer and use it in GitHub Desktop.
Unicorn emulation example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
from __future__ import print_function | |
from unicorn import * | |
from unicorn.x86_const import * | |
from capstone import * | |
import sys | |
#******* Architectures (from unicorn.h) ****************************************************************** | |
# typedef enum uc_arch { | |
# UC_ARCH_ARM = 1, // ARM architecture (including Thumb, Thumb-2) | |
# UC_ARCH_ARM64, // ARM-64, also called AArch64 | |
# UC_ARCH_MIPS, // Mips architecture | |
# UC_ARCH_X86, // X86 architecture (including x86 & x86-64) | |
# UC_ARCH_PPC, // PowerPC architecture | |
# UC_ARCH_SPARC, // Sparc architecture | |
# UC_ARCH_M68K, // M68K architecture | |
# UC_ARCH_MAX, | |
# } uc_arch; | |
#********************************************************************************************************* | |
#******* Modes (from unicorn.h) ************************************************************************** | |
# typedef enum uc_mode { | |
# UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode) | |
# UC_MODE_ARM = 0, // 32-bit ARM | |
# UC_MODE_16 = 1 << 1, // 16-bit mode (X86) | |
# UC_MODE_32 = 1 << 2, // 32-bit mode (X86) | |
# UC_MODE_64 = 1 << 3, // 64-bit mode (X86, PPC) | |
# UC_MODE_THUMB = 1 << 4, // ARM's Thumb mode, including Thumb-2 | |
# UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series | |
# UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM | |
# UC_MODE_MICRO = 1 << 4, // MicroMips mode (MIPS) | |
# UC_MODE_MIPS3 = 1 << 5, // Mips III ISA | |
# UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA | |
# UC_MODE_V9 = 1 << 4, // SparcV9 mode (Sparc) | |
# UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (PPC) | |
# UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode | |
# UC_MODE_MIPS32 = UC_MODE_32, // Mips32 ISA (Mips) | |
# UC_MODE_MIPS64 = UC_MODE_64, // Mips64 ISA (Mips) | |
# } uc_mode; | |
#********************************************************************************************************* | |
#******* Hook types (from unicorn.h) ********************************************************************* | |
#// All type of hooks for uc_hook_add() API. | |
#typedef enum uc_hook_type { | |
# UC_HOOK_INTR = 1 << 0, // Hook all interrupt/syscall events | |
# UC_HOOK_INSN = 1 << 1, // Hook a particular instruction | |
# UC_HOOK_CODE = 1 << 2, // Hook a range of code | |
# UC_HOOK_BLOCK = 1 << 3, // Hook basic blocks | |
# UC_HOOK_MEM_READ_UNMAPPED = 1 << 4, // Hook for memory read on unmapped memory | |
# UC_HOOK_MEM_WRITE_UNMAPPED = 1 << 5, // Hook for invalid memory write events | |
# UC_HOOK_MEM_FETCH_UNMAPPED = 1 << 6, // Hook for invalid memory fetch for execution events | |
# UC_HOOK_MEM_READ_PROT = 1 << 7, // Hook for memory read on read-protected memory | |
# UC_HOOK_MEM_WRITE_PROT = 1 << 8, // Hook for memory write on write-protected memory | |
# UC_HOOK_MEM_FETCH_PROT = 1 << 9, // Hook for memory fetch on non-executable memory | |
# UC_HOOK_MEM_READ = 1 << 10, // Hook memory read events. | |
# UC_HOOK_MEM_WRITE = 1 << 11, // Hook memory write events. | |
# UC_HOOK_MEM_FETCH = 1 << 12, // Hook memory fetch for execution events | |
#} uc_hook_type; | |
#********************************************************************************************************* | |
#You can install hooks to special events (list of events can be found above) | |
#Here are two examples, that you can use... | |
#Example 1 - hook function def for basic hooks (UC_HOOK_CODE, UC_HOOK_BLOCK, etc) | |
def hook_code(uc, address, size, user_data): | |
print('>>> Tracing instruction at 0x%x, instruction size = 0x%x' %(address, size)) | |
tmp = CODE[address-ADDRESS:address-ADDRESS+size] | |
print('>>> Instruction code at [0x%x] =' %(address), end='') | |
for i in md.disasm(tmp, address): | |
print('0x%x:\t%s\t%s' %(i.address, i.mnemonic, i.op_str)) | |
return True | |
#Example 2 - hook function def for memory access (UC_HOOK_MEM_READ, etc) | |
def hook_invalid(mu, access, address, size, value, user_data): | |
mu.mem_map(address, 4096) | |
return True | |
#Other function prototypes can be found in unicorn/unicorn.py... | |
#Memory address where emulation starts | |
ADDRESS = 0x1000000 | |
try: | |
#Init... | |
print("[Init]") | |
mu = Uc(UC_ARCH_X86, UC_MODE_64) | |
md = Cs(CS_ARCH_X86, CS_MODE_64) | |
mu.mem_map(ADDRESS, 4096) | |
#Init register for the stack | |
ESP_ADDR = 0x00010000 | |
mu.reg_write(UC_X86_REG_ESP, ESP_ADDR) | |
mu.mem_map(ESP_ADDR, 4096) | |
#Open code from file here | |
file = open('xxx64.sc','rb') | |
CODE = file.read() | |
#Capstone disasm | |
print("[Disasm]") | |
for i in md.disasm(CODE, 0): | |
print('0x%x:\t%s\t%s' %(i.address, i.mnemonic, i.op_str)) | |
#Write machine code to previously mapped memory | |
mu.mem_write(ADDRESS, CODE) | |
#Emulation start! | |
print("[Emulation]") | |
#Add hooks here! | |
#One must use the mu.hook_add function, which takes two arguments> | |
# - a hook code, type of uc_hook_type (see type definition above!) | |
# - a hook function (for example "hook_code") | |
#An example for hook_code: "mu.hook_add(UC_HOOK_SOMETHING, hook_something)" | |
mu.hook_add(UC_HOOK_CODE,hook_code) | |
mu.hook_add(UC_HOOK_MEM_WRITE_UNMAPPED,hook_invalid) | |
mu.emu_start(ADDRESS, ADDRESS + len(CODE)) | |
#Done! | |
print("[Done]") | |
except UcError as e: | |
print("ERROR: %s" % e) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment