对于ollvm的恢复基本基于angr和miasm,但对于arm的恢复,支持并不理想;所以便看到了另外的一框架unicorn。
LLVM将混淆之后的程序分为以下几个模块:
1.函数的开始地址为序言的地址
2.序言的后继为主分发器
3.后继为主分发器的块为预处理器
4.后继为预处理器的块为真实块
5.无后继的块为retn块
6.剩下的为无用块
所以我们去混淆的大概思路就是按照几个模块找到函数地址,将真实块留下,retn块留下,之后那些无用块全部置为nop;关键就是对真实块和虚拟块的识别,之后再对真实块中两种 分支 和 顺序 关系的识别,使用符号执行模拟两者之间的关系。
unicorn的优点
- 支持多种架构: Arm, Arm64 (Armv8), M68K, Mips, Sparc, & X86 (include X86_64).
- 对Windows和*nix系统(已确认包含Mac OSX, Linux, *BSD & Solaris)的原生支持
- 具有平台独立且简洁易于使用的API
- 使用JIT编译技术, 性能表现优异
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple unicorn
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple capstone //使用capstone进行反汇编
这篇 只 先对unicorn熟悉了解下
官方文档给的例子
#coding:utf-8
from unicorn import *
from unicorn.arm_const import *
ARM_CODE = b"\x37\x00\xa0\xe3\x03\x10\x42\xe0"
# mov r0, #0x37;
# sub r1, r2, r3
# Test ARM
# callback for tracing instructions
def hook_code(uc, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
def test_arm():
print("Emulate ARM code")
try:
# Initialize emulator in ARM mode
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB) #创建UC对象
# map 2MB memory for this emulation 创建2MB的内存空间
ADDRESS = 0x10000
mu.mem_map(ADDRESS, 2 * 0x10000)
mu.mem_write(ADDRESS, ARM_CODE) #将前面定义的ARM_CODE传入内存空间内,只支持byte
#未开机前寄存器赋值
mu.reg_write(UC_ARM_REG_R0, 0x1234)
mu.reg_write(UC_ARM_REG_R2, 0x6789)
mu.reg_write(UC_ARM_REG_R3, 0x3333)
#添加指令集Hook
# 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))
print("已开机")
#获取计算器结果
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)
test_arm()
***************************************
结果如下:
Emulate ARM code
已开机
>>> R0 = 0x37
>>> R1 = 0x3456
通过上述脚本来了解各个函数的作用
R0 寄存器为 0x37,R1 为 0x3456
之后使用capstone 来对操作的代码进行反汇编,查看进行了什么操作
from capstone import *
from capstone.arm import *
CODE = b"\x37\x00\xa0\xe3\x03\x10\x42\xe0"
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: mov r0, #0x37
1004: sub r1, r2, r3