一、目标
前一篇文章中,我们学习了如何用Unicorn来运行一段代码,但是它的执行过程我们看不见,出了bug也没法调试,所以我们需要一个调试器来分析代码。
这个调试器需要有如下功能:
- 下断点
- 读写寄存器
- 反汇编
- dump内存
- 单步调试(步入/步过)
- 快速接入各种不同的Unicorn项目
二、分析
Unicorn 提供了强大的指令级Hook(UC_HOOK_CODE), 使得每一条指令执行前,我们都有机会处理。 UC_HOOK_CODE 的callback原型定义如下
typedef void (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size, void *user_data);
- address: 当前执行的指令地址
- size: 当前指令的长度,如果长度未知,则为0
- user_data: hook_add 设置的user_data参数 调用hook_add 函数可以为指定的代码范围添加hook的callback。 python包中的hook_add函数原型如下
def hook_add(self, htype, callback, user_data=None, begin=1, end=0, arg1=0):
pass
UC_HOOK_CODE 的功能是每条指令执行前调用callback。
callback中,我们可以通过参数得知指令执行地址、指令执行长度、虚拟机指针。 有了虚拟机指针,我们可以很方便的访问各种寄存器、内存等资源。在UC_HOOK_CODE的callback中,也可以直接修改PC寄存器来改变流程。
本文将编写一个UnicornDebugger 类,调试器的各种功能均在该类中实现, 调用该类的构造函数即可附加到一个Uc虚拟机对象上。 类的定义
附加调试器
def test_arm():
print("Emulate ARM code")
try:
# Initialize emulator in ARM mode
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
mu.hook_add(UC_HOOK_CODE, hook_code, begin=ADDRESS, end=ADDRESS)
#debugger attach
udbg = UnicornDebugger(mu)
udbg.add_bpt(ADDRESS)
except UcError as e:
print("ERROR: %s" % e)
if __name__ == '__main__':
test_arm()
反汇编
Unicorn 并没有反汇编功能,虽然它的内部一定有与反汇编相关的代码。我们只能自己想办法反汇编。Unicorn 有一个兄弟,它叫Capstone。Capstone是一款支持多种处理器和开发语言的反汇编框架。 Capstone 官方地址 我将使用Capstone 作为调试模块的反汇编器。
安装 Capstone
Capstone 对python的支持特别好,我们的开发语言是python3,所以直接使用pip 安装capstone 即可。
pip install capstone
快速入门 Capstone
Capstone 很强大,也可以很简单, 下面一段代码就是Capstone的入门例子。
from capstone import *
from capstone.arm import *
CODE = b"\xf1\x02\x03\x0e\x00\x00\xa0\xe3\x02\x30\xc1\xe7\x00\x00\x53\xe3"
md = Cs(CS_ARCH_ARM, CS_MODE_ARM)
for i in md.disasm(CODE, 0x1000):
print("%x:\t%s\t%s" %(i.address, i.mnemonic, i.op_str))
上面这段代码的输出如下
1000: mcreq p2, #0, r0, c3, c1, #7
1004: mov r0, #0
1008: strb r3, [r1, r2]
100c: cmp r3, #0
三、代码
完整的代码在这里 UnicornDebugger.py
参考
https://bbs.pediy.com/thread-253868.htm Unicorn 在 Android 的应用
关注微信公众号,最新技术干货实时推送