-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathimport_unicorn.py
executable file
·75 lines (54 loc) · 2.29 KB
/
import_unicorn.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#!/usr/bin/env python3
# Emulate an arm system using uincorn with a binary produced by ghidra
# Given a pickle file as arg from Ghidra produced with `export_unicorn.py`,
# Usage: python3 import_unicorn.py pickle_file_path
# If you get an invalid memory write error:
# - Did you set START and END to sane values?
# - Turn on debug, and identify the bad instruction. Maybe you need to map additional memory that we failed to export from Ghidra?
(START,END) = (0x0, 0xFFFFFF)
DEBUG = False
import os
import sys
import pickle
from unicorn import *
from unicorn.arm_const import *
from capstone import *
assert(len(sys.argv) > 1), f"USAGE: {sys.argv[0]} pickle_path"
in_path = sys.argv[1]
assert(os.path.isfile(sys.argv[1])), f"File {sys.argv[1]} not found"
with open(in_path, "rb") as f:
data = pickle.load(f, encoding='utf8')
BAD_ADDRS = [] # Put addresses in here that you want to skip emulation of
def hook_code(emu, address, size, user_data):
global last_ib
global idx
if DEBUG:
print('>>> Tracing instruction at 0x%x, instruction size = 0x%x' %(address, size))
code = emu.mem_read(address, size)
for i in disasm.disasm(code, size):
print("\t0x{:x}\t{}\t{}".format(i.address, i.mnemonic, i.op_str))
if address in BAD_ADDRS:
emu.reg_write(UC_ARM_REG_PC, (address+size)|1)
# Initialize decompiler
disasm = Cs(CS_ARCH_ARM, CS_MODE_THUMB)
disasm.detail = True
# Initialize emulator and add hook callback
emu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
emu.hook_add(UC_HOOK_CODE, hook_code)
# Map memory (TODO: differentiate RWX permissions?)
for (start,sz) in data["mem_regions"]:
#print(f"Mapping from 0x{start:x} to 0x{start+sz:x}")
emu.mem_map(start, sz)
# Set up data
for offset, raw_data in data["data"].items():
#print(f"Filling in {len(raw_data)} bytes at 0x{offset:x}")
emu.mem_write(offset, bytes(raw_data))
# Set up stack higher than all the functions we've mapped in already
stack_start = (max(e for (_, e) in data["mem_regions"])+0x10000) & ~0x1000
stack_size = 0x1000
emu.mem_map(stack_start, stack_size)
# Add a single argument to the stack and set up stack pointer
emu.mem_write(stack_start+0x100, bytes([0x12, 0x34, 0x56, 0x78]))
emu.reg_write(UC_ARM_REG_SP, stack_start+0x100)
# Run emulator in thumb mode
emu.emu_start(START | 1, END)