Last active
February 12, 2022 09:27
-
-
Save four0four/f78566701529d758da52d73649518804 to your computer and use it in GitHub Desktop.
Unicorn Engine - based Zynq bootrom emulation harness
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 | |
import sys | |
from colors import * | |
from unicorn import * | |
from unicorn.arm_const import * | |
from capstone import Cs, CS_ARCH_ARM, CS_MODE_ARM, CsError | |
# hooks: | |
f_cov = open('coverage.txt', 'wb') | |
def hook_block(uc, address, size, user_data): | |
#print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size)) | |
global f_cov | |
f_cov.write(b"ROM_bigger.bin+0x%x\n"%address) | |
def start_tracing_blocks(u, address, size, user_data): | |
u.hook_add(UC_HOOK_BLOCK, hook_block) | |
def dump_mem(u, address, size, user_data): | |
(addr, nbytes, outf) = user_data | |
d = u.mem_read(addr, nbytes) | |
with open(outf, 'wb') as f: | |
f.write(d) | |
print("dumped %d bytes from 0x%x to %s"%(nbytes, addr, outf)) | |
def sha_hook(u, address, size, user_data): | |
src = u.reg_read(UC_ARM_REG_R0) | |
n = u.reg_read(UC_ARM_REG_R1) | |
dst = u.reg_read(UC_ARM_REG_R2) | |
print(green("sha(src: 0x%x, n: %x, dst: 0x%x)"%(src, n, dst))) | |
def sdio_read(u, address, size, user_data): | |
unk = u.reg_read(UC_ARM_REG_R0) | |
dest = u.reg_read(UC_ARM_REG_R1) | |
sdio_src = u.reg_read(UC_ARM_REG_R2) << 9 | |
n_blocks = u.reg_read(UC_ARM_REG_R3) | |
lr = u.reg_read(UC_ARM_REG_LR); | |
print(green("sdio_read(drive: 0x%x, dst: 0x%x, sdio_src: 0x%x, nblock: 0x%x), lr == 0x%x"%(unk, dest, sdio_src>>9, n_blocks, lr))) | |
# with open("sd-old.bin", 'rb') as f: | |
with open("/dev/sdd1", 'rb') as f: | |
f.seek(sdio_src) | |
d = f.read(n_blocks << 9) | |
u.mem_write(dest, d) | |
# don't need the rest of the func, for now...hopefully ok? | |
u.reg_write(UC_ARM_REG_R0, 0) | |
u.reg_write(UC_ARM_REG_PC, u.reg_read(UC_ARM_REG_LR)) | |
def fake_dma(u, address, size, user_data): | |
dst = 0x007021C | |
with open("payload_full.bin", "rb") as f: | |
b = f.read() | |
u.mem_write(dst, b) | |
print(yellow("faking %d bytes of DMA @ 0x%x"%(len(b), dst))) | |
break_temp = dict() | |
def print_retval(u, address, size, user_data): | |
global break_temp | |
def rval_cb(u, a, s, ud): | |
global break_temp | |
r0 = u.reg_read(UC_ARM_REG_R0) | |
print("%s() = 0x%x"%(ud, r0)) | |
if a in break_temp: | |
u.hook_del(break_temp[a]) | |
lr = u.reg_read(UC_ARM_REG_LR) | |
print("%s from 0x%x"%(user_data, lr)) | |
h = u.hook_add(UC_HOOK_CODE, rval_cb, begin=lr, end=lr, user_data=user_data) | |
break_temp[lr] = h | |
def boot_fn_hook(u, address, size, user_data): | |
global break_temp | |
def print_bootdat(u, address, size, user_data): | |
global break_temp | |
dat = u.mem_read(user_data[0], user_data[1]) | |
#print("read:\n"+"="*20+"\n%s\n"%dat.hex()) | |
# this segfaults, lol. | |
# if address in break_temp: | |
# u.hook_del(break_temp[address]) | |
offset = u.reg_read(UC_ARM_REG_R0) | |
dest = u.reg_read(UC_ARM_REG_R1) | |
nbytes = u.reg_read(UC_ARM_REG_R2) | |
print(green("run_boot_alg(%x, %x, %d)"%(offset, dest, nbytes))) | |
lr = u.reg_read(UC_ARM_REG_LR) | |
h = u.hook_add(UC_HOOK_CODE, print_bootdat, begin=lr, end=lr, user_data=(dest, nbytes)) | |
break_temp[lr] = h | |
def f_open_hook(u, address, size, user_data): | |
fp = u.reg_read(UC_ARM_REG_R0) | |
path = u.reg_read(UC_ARM_REG_R1) | |
mode = u.reg_read(UC_ARM_REG_R2) | |
ptr = path | |
path_str = b"" | |
while path_str[-1:] != b'\x00': | |
path_str += u.mem_read(ptr, 1) | |
ptr += 1 | |
print("f_open(%x, %s, %x)"%(fp, path_str, mode)) | |
def f_seek_hook(u, address, size, user_data): | |
fp = u.reg_read(UC_ARM_REG_R0) | |
offset = u.reg_read(UC_ARM_REG_R1) | |
print("f_seek(0x%x, 0x%x)"%(fp, offset)) | |
def f_read_hook(u, address, size, user_data): | |
fd = u.reg_read(UC_ARM_REG_R0) | |
dest = u.reg_read(UC_ARM_REG_R1) | |
nbytes = u.reg_read(UC_ARM_REG_R2) | |
nbytes_out = u.reg_read(UC_ARM_REG_R3) | |
print("f_read(fp: 0x%x, dst: 0x%x, n: %d, n_out: 0x%x)"%(fd, dest, nbytes, nbytes_out)) | |
def dmb_read_hook(u, address, size, user_data): | |
r0 = u.reg_read(UC_ARM_REG_R0) | |
lr = u.reg_read(UC_ARM_REG_LR) | |
""" | |
if r0 in DMB_READ_HOOKS: | |
r0r = DMB_READ_HOOKS[r0] | |
u.reg_write(UC_ARM_REG_R0, r0r) | |
u.reg_write(UC_ARM_REG_PC, u.reg_read(UC_ARM_REG_LR)) | |
# print("dmb_read(0x%08x) = 0x%08x\n\t[LR = 0x%08x]"%(r0, r0r, lr)) | |
return | |
""" | |
#print("dmb_read(0x%08x)\n\t[LR = 0x%08x]"%(r0, lr)) | |
def dmb_writeb_hook(u, address, size, user_data): | |
r0 = u.reg_read(UC_ARM_REG_R0) | |
r1 = u.reg_read(UC_ARM_REG_R1) | |
lr = u.reg_read(UC_ARM_REG_LR) | |
# print("dmb_writeb(dst: 0x%08x, val: 0x%02x)\n\t[LR = 0x%08x]"%(r0, r1&0xff, lr)) | |
def dmb_writew_hook(u, address, size, user_data): | |
r0 = u.reg_read(UC_ARM_REG_R0) | |
r1 = u.reg_read(UC_ARM_REG_R1) | |
lr = u.reg_read(UC_ARM_REG_LR) | |
# print("dmb_writew(dst: 0x%08x, val: 0x%08x)\n\t[LR = 0x%08x]"%(r0, r1, lr)) | |
def skip_fn(u, address, size, user_data): | |
print(yellow("skipping %s"%user_data)) | |
u.reg_write(UC_ARM_REG_PC, u.reg_read(UC_ARM_REG_LR)) | |
def skip_fn_ret0(u, address, size, user_data): | |
print(yellow("skipping (r0=0) %s"%user_data)) | |
u.reg_write(UC_ARM_REG_R0, 0) | |
u.reg_write(UC_ARM_REG_PC, u.reg_read(UC_ARM_REG_LR)) | |
def skip_fn_ret1(u, address, size, user_data): | |
print(yellow("skipping (r0=1) %s"%user_data)) | |
u.reg_write(UC_ARM_REG_R0, 1) | |
u.reg_write(UC_ARM_REG_PC, u.reg_read(UC_ARM_REG_LR)) | |
def catch_wfe_loop(u, address, size, user_data): | |
r0 = u.reg_read(UC_ARM_REG_R0) | |
lr = u.reg_read(UC_ARM_REG_LR) | |
print(red("caught panic. reason: 0x%04x, lr: 0x%08x"%(r0,lr))) | |
u.emu_stop() | |
# memory callbacks | |
def always_val(u, access, address, size, value, user_data): | |
u.mem_write(address, user_data.to_bytes(4, 'little')) | |
def dump_writes(u, access, address, size, value, user_data): | |
print("writing 0x%08x to 0x%08x"%( value, address)) | |
def setup_mem(u): | |
# load the rom | |
with open("bootrom.bin", 'rb') as f: | |
u.mem_map(0, 0x20000) | |
u.mem_write(0, f.read()) | |
# setup some OCM | |
u.mem_map(0x40000, 0x40000) | |
# I/O peripherals | |
u.mem_map(0xe0000000, 0x300000) | |
# slcr peripherals | |
u.mem_map(0xf8000000, 0xc00) | |
# "ps system" registers | |
u.mem_map(0xf8001000, 0x80f000) | |
# cpu control | |
u.mem_map(0xf8900000, 0x603000) | |
# now populate some shit | |
def disas_one(u, addr): | |
global cd | |
insn = next(cd.disasm(u.mem_read(addr, 4), 4)) | |
return insn.mnemonic + " " + insn.op_str | |
def dump_regs(u): | |
print("[R0]: 0x%08x, [R1]: 0x%08x, [R2]: 0x%08x"%( | |
u.reg_read(UC_ARM_REG_R0), | |
u.reg_read(UC_ARM_REG_R1), | |
u.reg_read(UC_ARM_REG_R2)) | |
) | |
print("[R3]: 0x%08x, [R4]: 0x%08x, [R5]: 0x%08x"%( | |
u.reg_read(UC_ARM_REG_R3), | |
u.reg_read(UC_ARM_REG_R4), | |
u.reg_read(UC_ARM_REG_R5)) | |
) | |
print("[R6]: 0x%08x, [R7]: 0x%08x, [R8]: 0x%08x"%( | |
u.reg_read(UC_ARM_REG_R6), | |
u.reg_read(UC_ARM_REG_R7), | |
u.reg_read(UC_ARM_REG_R8)) | |
) | |
print("[R9]: 0x%08x, [R10]: 0x%08x, [R11]: 0x%08x"%( | |
u.reg_read(UC_ARM_REG_R9), | |
u.reg_read(UC_ARM_REG_R10), | |
u.reg_read(UC_ARM_REG_R11)) | |
) | |
print("[R12]: 0x%08x, [SP]: 0x%08x, [PC]: 0x%08x"%( | |
u.reg_read(UC_ARM_REG_R12), | |
u.reg_read(UC_ARM_REG_SP), | |
u.reg_read(UC_ARM_REG_PC)) | |
) | |
print("[LR]: 0x%08x"%( | |
u.reg_read(UC_ARM_REG_LR)) | |
) | |
cpsr = u.reg_read(UC_ARM_REG_CPSR) | |
cpsr_str = \ | |
(green("N") if (cpsr & 1<<31) else red("N")) + \ | |
(green("Z") if (cpsr & 1<<30) else red("Z")) + \ | |
(green("C") if (cpsr & 1<<29) else red("C")) + \ | |
(green("V") if (cpsr & 1<<28) else red("V")) + \ | |
(green("Q") if (cpsr & 1<<27) else red("Q")) + \ | |
(green("J") if (cpsr & 1<<24) else red("J")) + \ | |
(green("E") if (cpsr & 1<<9) else red("E")) + \ | |
(green("A") if (cpsr & 1<<8) else red("A")) + \ | |
(green("I") if (cpsr & 1<<7) else red("I")) + \ | |
(green("F") if (cpsr & 1<<6) else red("F")) + \ | |
(green("T") if (cpsr & 1<<5) else red("T")) + \ | |
"" | |
print("[CPSR]: %s (0x%08x)"%(cpsr_str, cpsr)) | |
ROM_HOOKS = [\ | |
# (0xAFB4, "dmb_read", dmb_read_hook), | |
(0xAFE8, "dmb_writeb", dmb_writeb_hook), | |
(0xB000, "dmb_writew", dmb_writew_hook), | |
(0x00D4, "invalidate_caches", skip_fn), | |
(0x102C, "save_rst_reason", skip_fn), | |
(0x0378, "set_gpios_bias_slew", skip_fn), | |
(0x02A8, "do_crcs", skip_fn), | |
(0xAF68, "timer_wait", skip_fn_ret1), | |
(0x07a4, "wfe_loop_securemode", catch_wfe_loop), | |
(0x1E28, "wfe_loop_securemode2", catch_wfe_loop), | |
(0x0C04, "halt_with_error", catch_wfe_loop), | |
(0x9AD8, red("fatfs_disk_status_mb"), print_retval), | |
(0x9AF4, red("fatfs_disk_initialize"), skip_fn_ret0), | |
# (0x59EC, red("check_header_chksum"), skip_fn_ret0), | |
(0x009EA8, "sdio_read", sdio_read), | |
(0x59AC, "check_hdr_magic", print_retval), | |
(0x0848C , "mount_vol", print_retval), | |
(0x083D8 , "check_fs", print_retval), | |
(0x8AB8 , "follow_path", print_retval), | |
(0x595C, "run_boot_alg", boot_fn_hook), | |
(0x008F7C, "f_read", f_read_hook), | |
(0x0091E0, "f_seek", f_seek_hook), | |
(0x008E7C, "f_open", f_open_hook), | |
(0x3238, "do_sha", sha_hook), | |
#(0x1960, "fake_dma", fake_dma), | |
(0x1980, (0x070220, 0x284, "fatfs_state.bin"), dump_mem), | |
# (0xA104 , red("asdf"), skip_fn), | |
] | |
MEM_HOOKS = [\ | |
(0xE010002F, UC_HOOK_MEM_READ, always_val, 0), | |
(0xE010002C, UC_HOOK_MEM_READ, always_val, 2), | |
(0xF800702C, UC_HOOK_MEM_READ, always_val, 0), | |
(0xF800010C, UC_HOOK_MEM_READ, always_val, 0x15), # pll status | |
(0xF800025C, UC_HOOK_MEM_READ, always_val, 5), # bootmode == sdio | |
(0xE0100004, UC_HOOK_MEM_WRITE, dump_writes, 0), | |
(0xE0100008, UC_HOOK_MEM_WRITE, dump_writes, 0), | |
(0xE010000C, UC_HOOK_MEM_WRITE, dump_writes, 0), | |
# ( 0x07049C, UC_HOOK_MEM_READ, always_val, 0), | |
# (0xF800D010, UC_HOOK_MEM_READ, always_val, 0x400) # efuses - enable secureboot | |
# (0x70220, UC_HOOK_MEM_READ, always_val, 1), | |
] | |
def setup_hooks(u): | |
for (a, d, f) in ROM_HOOKS: | |
u.hook_add(UC_HOOK_CODE, f, begin=a, end=a, user_data = d) | |
for (a, t, f, v) in MEM_HOOKS: | |
u.hook_add(t, f, begin=a, end=a, user_data = v) | |
def dump_pc(u, before=3, after=3): | |
pc = u.reg_read(UC_ARM_REG_PC) | |
# print before | |
for i in range(pc-(before*4), pc, 4): | |
print("%08x %08x %s"%(i, int.from_bytes(u.mem_read(i, 4), 'big'), disas_one(u, i))) | |
print(green("===PC=== %08x %s"%(int.from_bytes(u.mem_read(pc, 4), 'big'), disas_one(u, pc)))) | |
for i in range(pc+4, pc+(after*4)+4, 4): | |
print("%08x %08x %s"%(i, int.from_bytes(u.mem_read(i, 4), 'big'), disas_one(u, i))) | |
def dump_stack(u, before=3, after=3): | |
sp = u.reg_read(UC_ARM_REG_SP) | |
for i in range(sp-(before*4), sp, 4): | |
print("%08x %08x"%(i, int.from_bytes(u.mem_read(i, 4), 'little'))) | |
print(green("===SP=== %08x"%(int.from_bytes(u.mem_read(sp, 4), 'little')))) | |
for i in range(sp+4, sp+(after*4)+4, 4): | |
print("%08x %08x"%(i, int.from_bytes(u.mem_read(i, 4), 'little'))) | |
if __name__ == '__main__': | |
cd = Cs(CS_ARCH_ARM, CS_MODE_ARM) | |
u = Uc(UC_ARCH_ARM, UC_MODE_ARM) | |
setup_mem(u) | |
setup_hooks(u) | |
# fuck it, trace it all | |
u.hook_add(UC_HOOK_BLOCK, hook_block) | |
try: | |
u.emu_start(0, 0xfffffff, timeout=1000000, count=0) | |
except UcError as e: | |
print(red("ERROR: %s\n" % e)) | |
dump_regs(u) | |
print("-"*20) | |
dump_stack(u) | |
print("-"*20) | |
dump_pc(u) | |
#print(u.mem_read(0x070490, 4).hex()) | |
#print(u.mem_read(0x0070EB8, 4).hex()) | |
f_cov.close() |
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 | |
import cmd | |
import sys | |
from colors import * | |
from unicorn import * | |
from unicorn.arm_const import * | |
from capstone import Cs, CS_ARCH_ARM, CS_MODE_ARM, CsError | |
# hooks: | |
f_cov = open('coverage.txt', 'wb') | |
def hook_block(uc, address, size, user_data): | |
#print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size)) | |
global f_cov | |
f_cov.write(b"ROM_bigger.bin+0x%x\n"%address) | |
def start_tracing_blocks(u, address, size, user_data): | |
u.hook_add(UC_HOOK_BLOCK, hook_block) | |
break_temp = dict() | |
def print_retval(u, address, size, user_data): | |
global break_temp | |
def rval_cb(u, a, s, ud): | |
global break_temp | |
r0 = u.reg_read(UC_ARM_REG_R0) | |
print("%s() = 0x%x"%(ud, r0)) | |
""" | |
if a in break_temp: | |
u.hook_del(break_temp[a]) | |
""" | |
lr = u.reg_read(UC_ARM_REG_LR) | |
h = u.hook_add(UC_HOOK_CODE, rval_cb, begin=lr, end=lr, user_data=user_data) | |
break_temp[lr] = h | |
def boot_fn_hook(u, address, size, user_data): | |
global break_temp | |
def print_bootdat(u, address, size, user_data): | |
global break_temp | |
dat = u.mem_read(user_data[0], user_data[1]) | |
#print("read:\n"+"="*20+"\n%s\n"%dat.hex()) | |
# THIS SEGFAULT?? | |
# if address in break_temp: | |
# u.hook_del(break_temp[address]) | |
offset = u.reg_read(UC_ARM_REG_R0) | |
dest = u.reg_read(UC_ARM_REG_R1) | |
nbytes = u.reg_read(UC_ARM_REG_R2) | |
print(green("run_boot_alg(%x, %x, %d)"%(offset, dest, nbytes))) | |
lr = u.reg_read(UC_ARM_REG_LR) | |
h = u.hook_add(UC_HOOK_CODE, print_bootdat, begin=lr, end=lr, user_data=(dest, nbytes)) | |
break_temp[lr] = h | |
def dmb_read_hook(u, address, size, user_data): | |
r0 = u.reg_read(UC_ARM_REG_R0) | |
lr = u.reg_read(UC_ARM_REG_LR) | |
""" | |
if r0 in DMB_READ_HOOKS: | |
r0r = DMB_READ_HOOKS[r0] | |
u.reg_write(UC_ARM_REG_R0, r0r) | |
u.reg_write(UC_ARM_REG_PC, u.reg_read(UC_ARM_REG_LR)) | |
# print("dmb_read(0x%08x) = 0x%08x\n\t[LR = 0x%08x]"%(r0, r0r, lr)) | |
return | |
""" | |
#print("dmb_read(0x%08x)\n\t[LR = 0x%08x]"%(r0, lr)) | |
win = False | |
def log_success(u, address, size, user_data): | |
global win | |
win = True | |
u.emu_stop() | |
def dmb_writeb_hook(u, address, size, user_data): | |
r0 = u.reg_read(UC_ARM_REG_R0) | |
r1 = u.reg_read(UC_ARM_REG_R1) | |
lr = u.reg_read(UC_ARM_REG_LR) | |
# print("dmb_writeb(dst: 0x%08x, val: 0x%02x)\n\t[LR = 0x%08x]"%(r0, r1&0xff, lr)) | |
def dmb_writew_hook(u, address, size, user_data): | |
r0 = u.reg_read(UC_ARM_REG_R0) | |
r1 = u.reg_read(UC_ARM_REG_R1) | |
lr = u.reg_read(UC_ARM_REG_LR) | |
# print("dmb_writew(dst: 0x%08x, val: 0x%08x)\n\t[LR = 0x%08x]"%(r0, r1, lr)) | |
def skip_fn(u, address, size, user_data): | |
print(yellow("skipping %s"%user_data)) | |
u.reg_write(UC_ARM_REG_PC, u.reg_read(UC_ARM_REG_LR)) | |
def skip_fn_ret0(u, address, size, user_data): | |
print(yellow("skipping (r0=0) %s"%user_data)) | |
u.reg_write(UC_ARM_REG_R0, 0) | |
u.reg_write(UC_ARM_REG_PC, u.reg_read(UC_ARM_REG_LR)) | |
def skip_fn_ret1(u, address, size, user_data): | |
print(yellow("skipping (r0=1) %s"%user_data)) | |
u.reg_write(UC_ARM_REG_R0, 1) | |
u.reg_write(UC_ARM_REG_PC, u.reg_read(UC_ARM_REG_LR)) | |
def catch_wfe_loop(u, address, size, user_data): | |
r0 = u.reg_read(UC_ARM_REG_R0) | |
lr = u.reg_read(UC_ARM_REG_LR) | |
#print(red("caught panic. reason: 0x%04x, lr: 0x%08x"%(r0,lr))) | |
u.emu_stop() | |
# memory callbacks | |
def always_val(u, access, address, size, value, user_data): | |
u.mem_write(address, user_data.to_bytes(4, 'little')) | |
def setup_mem(u): | |
# load the rom | |
with open("bootrom.bin", 'rb') as f: | |
u.mem_map(0, 0x20000) | |
u.mem_write(0, f.read()) | |
# setup some OCM | |
u.mem_map(0x40000, 0x40000) | |
# I/O peripherals | |
u.mem_map(0xe0000000, 0x300000) | |
# slcr peripherals | |
u.mem_map(0xf8000000, 0xc00) | |
# "ps system" registers | |
u.mem_map(0xf8001000, 0x80f000) | |
# cpu control | |
u.mem_map(0xf8900000, 0x603000) | |
# now populate some shit | |
def disas_one(u, addr): | |
global cd | |
insn = next(cd.disasm(u.mem_read(addr, 4), 4)) | |
return insn.mnemonic + " " + insn.op_str | |
def dump_regs(u): | |
print("[R0]: 0x%08x, [R1]: 0x%08x, [R2]: 0x%08x"%( | |
u.reg_read(UC_ARM_REG_R0), | |
u.reg_read(UC_ARM_REG_R1), | |
u.reg_read(UC_ARM_REG_R2)) | |
) | |
print("[R3]: 0x%08x, [R4]: 0x%08x, [R5]: 0x%08x"%( | |
u.reg_read(UC_ARM_REG_R3), | |
u.reg_read(UC_ARM_REG_R4), | |
u.reg_read(UC_ARM_REG_R5)) | |
) | |
print("[R6]: 0x%08x, [R7]: 0x%08x, [R8]: 0x%08x"%( | |
u.reg_read(UC_ARM_REG_R6), | |
u.reg_read(UC_ARM_REG_R7), | |
u.reg_read(UC_ARM_REG_R8)) | |
) | |
print("[R9]: 0x%08x, [R10]: 0x%08x, [R11]: 0x%08x"%( | |
u.reg_read(UC_ARM_REG_R9), | |
u.reg_read(UC_ARM_REG_R10), | |
u.reg_read(UC_ARM_REG_R11)) | |
) | |
print("[R12]: 0x%08x, [SP]: 0x%08x, [PC]: 0x%08x"%( | |
u.reg_read(UC_ARM_REG_R12), | |
u.reg_read(UC_ARM_REG_SP), | |
u.reg_read(UC_ARM_REG_PC)) | |
) | |
print("[LR]: 0x%08x"%( | |
u.reg_read(UC_ARM_REG_LR)) | |
) | |
cpsr = u.reg_read(UC_ARM_REG_CPSR) | |
cpsr_str = \ | |
(green("N") if (cpsr & 1<<31) else red("N")) + \ | |
(green("Z") if (cpsr & 1<<30) else red("Z")) + \ | |
(green("C") if (cpsr & 1<<29) else red("C")) + \ | |
(green("V") if (cpsr & 1<<28) else red("V")) + \ | |
(green("Q") if (cpsr & 1<<27) else red("Q")) + \ | |
(green("J") if (cpsr & 1<<24) else red("J")) + \ | |
(green("E") if (cpsr & 1<<9) else red("E")) + \ | |
(green("A") if (cpsr & 1<<8) else red("A")) + \ | |
(green("I") if (cpsr & 1<<7) else red("I")) + \ | |
(green("F") if (cpsr & 1<<6) else red("F")) + \ | |
(green("T") if (cpsr & 1<<5) else red("T")) + \ | |
"" | |
print("[CPSR]: %s (0x%08x)"%(cpsr_str, cpsr)) | |
ROM_HOOKS = [\ | |
(0x07a4, "wfe_loop_securemode", catch_wfe_loop), | |
(0x1E28, "wfe_loop_securemode2", catch_wfe_loop), | |
(0x0C04, "halt_with_error", catch_wfe_loop), | |
(0x595C, "run_boot_alg", boot_fn_hook), | |
(0x5F8C, "success", log_success), | |
] | |
MEM_HOOKS = [\ | |
(0xE010002F, UC_HOOK_MEM_READ, always_val, 0), | |
(0xE010002C, UC_HOOK_MEM_READ, always_val, 2), | |
(0xF800702C, UC_HOOK_MEM_READ, always_val, 0), | |
(0xF800010C, UC_HOOK_MEM_READ, always_val, 0x15), # pll status | |
(0xF800025C, UC_HOOK_MEM_READ, always_val, 5), # bootmode == sdio | |
(0xF800D010, UC_HOOK_MEM_READ, always_val, 0x400) # efuses - enable secureboot | |
# (0x70220, UC_HOOK_MEM_READ, always_val, 1), | |
] | |
def setup_hooks(u): | |
for (a, d, f) in ROM_HOOKS: | |
u.hook_add(UC_HOOK_CODE, f, begin=a, end=a, user_data = d) | |
for (a, t, f, v) in MEM_HOOKS: | |
u.hook_add(t, f, begin=a, end=a, user_data = v) | |
def dump_pc(u, before=3, after=3): | |
pc = u.reg_read(UC_ARM_REG_PC) | |
# print before | |
for i in range(pc-(before*4), pc, 4): | |
print("%08x %08x %s"%(i, int.from_bytes(u.mem_read(i, 4), 'big'), disas_one(u, i))) | |
print(green("===PC=== %08x %s"%(int.from_bytes(u.mem_read(pc, 4), 'big'), disas_one(u, pc)))) | |
for i in range(pc+4, pc+(after*4)+4, 4): | |
print("%08x %08x %s"%(i, int.from_bytes(u.mem_read(i, 4), 'big'), disas_one(u, i))) | |
if __name__ == '__main__': | |
cd = Cs(CS_ARCH_ARM, CS_MODE_ARM) | |
u = Uc(UC_ARCH_ARM, UC_MODE_ARM) | |
setup_mem(u) | |
setup_hooks(u) | |
# fuck it, trace it all | |
u.hook_add(UC_HOOK_BLOCK, hook_block) | |
if "--secure" in sys.argv: | |
# secure boot range: | |
u.reg_write(UC_ARM_REG_R5, 0xF8000100) | |
u.reg_write(UC_ARM_REG_R6, 0xF80001AC) | |
else: | |
# standard range: | |
u.reg_write(UC_ARM_REG_R5, 0xE0001000) | |
u.reg_write(UC_ARM_REG_R6, 0xF8006FFC) | |
u.reg_write(UC_ARM_REG_SP, 0x7D4A0) | |
u.reg_write(UC_ARM_REG_PC, 0x05C6C) | |
if sys.argv[1] == "all": | |
# for testing | |
reg_first = 0xE0001000 | |
#reg_first = 0xf8000000-0x10 | |
reg_last = 0xF8007000 | |
base = u.context_save() | |
reg_test = reg_first | |
f_ok = open("allowed.txt", 'wb+') | |
f_blocked = open("blocked.txt", 'wb+') | |
ranges = [\ | |
(0xE0001000, 0xE0010000), | |
(0xE0100000, 0xE0102000), | |
(0xF8000000, 0xF8010000), | |
# (0xF8898000, 0xF889D000), | |
# (0xF8800000, 0xF880B000), | |
# (0xf8f00000, 0xf8f08000), | |
] | |
for (reg_test, reg_last) in ranges: | |
while reg_test != reg_last: | |
u.context_restore(base) | |
u.reg_write(UC_ARM_REG_R0, reg_test) | |
try: | |
u.emu_start(0x05C6C, 0xfffffff, timeout=1000000, count=0) | |
except UcError as e: | |
print(red("ERROR: %s\n" % e)) | |
dump_regs(u) | |
print("-"*20) | |
dump_pc(u) | |
if win: | |
#print(green("OK: 0x%x"%reg_test)) | |
f_ok.write(b"0x%x\n"%reg_test) | |
else: | |
f_blocked.write(b"0x%x\n"%reg_test) | |
#print(red("No: 0x%x"%reg_test)) | |
win = False | |
reg_test += 4 | |
if reg_test & 0xfffff000 == reg_test: | |
print("0x%x"%reg_test) | |
f_cov.close() | |
f_ok.close() | |
f_blocked.close() | |
else: | |
reg_test = int(sys.argv[1], 0) | |
print("testing RIL access to 0x%x..."%reg_test) | |
u.reg_write(UC_ARM_REG_R0, reg_test) | |
try: | |
u.emu_start(0x05C6C, 0xfffffff, timeout=1000000, count=0) | |
except UcError as e: | |
print(red("ERROR: %s\n" % e)) | |
dump_regs(u) | |
print("-"*20) | |
dump_pc(u) | |
if win: | |
print(green("OK: 0x%x"%reg_test)) | |
else: | |
print(red("No: 0x%x"%reg_test)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment