深入浅出angr(六)
字数 793 2025-08-05 19:10:02
深入浅出angr(六)教学文档
前言
angr是一款强大的二进制分析框架,特别适合解决混淆的逆向工程题目。当面对以下情况时,angr能发挥巨大优势:
- 程序混淆严重,手动去混淆困难
- 动态调试耗时耗力
- 需要快速找到程序执行路径
快速寻找find和avoid地址的技巧
方法概述
在解决混淆题目时,确定正确的执行路径(find)和需要避免的路径(avoid)是关键。对于大量混淆的程序,手动分析每个分支效率低下,可以通过以下方法高效获取avoid地址:
- 二进制模式匹配:通过搜索特定指令的机器码来识别分支点
- 地址计算:将文件偏移转换为内存地址
实战示例:hackcon2016_angry-reverser
e = open('./yolomolo', 'rb').read()
avoids = []
index = 0
while True:
index = e.find(b'\xB9\x00\x00\x00\x00', index+1) # 搜索mov ecx, 0指令
if index == -1:
break
addr = 0x400000 + index # 计算内存地址
avoids.append(addr)
完整angr解决方案
import angr
import claripy
def main():
flag = claripy.BVS('flag', 20*8, explicit_name=True)
buf = 0x606000
crazy = 0x400646
find = 0x405a6e
# 获取avoid地址列表
e = open('./yolomolo', 'rb').read()
avoids = []
index = 0
while True:
index = e.find(b'\xB9\x00\x00\x00\x00', index+1)
if index == -1: break
avoids.append(0x400000 + index)
# 设置angr项目
proj = angr.Project('./yolomolo')
state = proj.factory.blank_state(addr=crazy, add_options={angr.options.LAZY_SOLVES})
# 设置输入约束
state.memory.store(buf, flag, endness='Iend_BE')
state.regs.rdi = buf
for i in range(19):
state.solver.add(flag.get_byte(i) >= 0x30)
state.solver.add(flag.get_byte(i) <= 0x7f)
# 执行符号执行
simgr = proj.factory.simulation_manager(state)
simgr.explore(find=find, avoid=avoids)
# 输出结果
found = simgr.found[0]
return found.solver.eval(flag, cast_to=bytes)
线性程序解决方案
angr特别适合解决线性结构的程序,如ekopartyctf2016_rev250。
关键步骤
-
环境设置:处理动态库依赖
LD_LIBRARY_PATH=./ ./FUck_binary -
识别关键地址:
- find地址:0x403a40
- avoid地址:0x403ABA, 0x403A7E等
-
自动获取avoid地址:
avoids = []
def get_avoids():
file_bytes = open('./FUck_binary','rb').read()
index = 0
while True:
index = file_bytes.find(b'\x66\x90', index+1) # 搜索nop指令
if index == -1: break
if index < 0x3a7e: continue # 过滤无效地址
avoids.append(0x400000 + index)
完整解决方案
import angr
import claripy
BUF_LEN = 100
def main():
# 获取avoid地址
get_avoids()
# 设置angr项目
p = angr.Project('FUck_binary')
flag = claripy.BVS('flag', BUF_LEN*8)
state = p.factory.entry_state(stdin=flag)
# 设置输入约束(可打印字符)
for c in flag.chop(8):
state.solver.add(state.solver.And(c <= '~', c >= ' '))
# 执行符号执行
ex = p.factory.simulation_manager(state)
ex.explore(find=0x403a40, avoid=avoids)
# 输出结果
found = ex.found[0]
print(found.posix.dumps(0))
关键技巧总结
-
输入约束设置:
- 限制为可打印字符:
state.solver.And(c <= '~', c >= ' ') - 限制ASCII范围:
flag.get_byte(i) >= 0x30和flag.get_byte(i) <= 0x7f
- 限制为可打印字符:
-
调试技巧:
import logging logging.getLogger('angr.sim_manager').setLevel(logging.DEBUG) -
地址转换:
- 文件偏移到内存地址:
0x400000 + index
- 文件偏移到内存地址:
-
指令模式识别:
mov ecx, 0→\xB9\x00\x00\x00\x00- nop指令 →
\x66\x90
适用场景
angr最适合以下类型的逆向题目:
- 线性结构的程序
- 混淆严重的程序
- 分支众多的程序
- 需要快速求解的程序
通过合理使用angr的符号执行能力,可以大幅提高逆向工程效率,避免手动分析的繁琐过程。