angr项目中的Hook与SimProcedure技术详解
什么是Hook和SimProcedure
在angr符号执行引擎中,Hook和SimProcedure是两项强大的功能,它们允许开发者修改程序的执行行为。简单来说:
- Hook:可以理解为在特定代码位置插入的"钩子",当执行流到达该位置时,会触发我们自定义的处理逻辑
- SimProcedure:是angr提供的一种高级Hook机制,专门用于模拟或替换函数的行为
快速入门示例
让我们从一个简单例子开始,了解如何使用SimProcedure:
from angr import Project, SimProcedure
# 加载目标程序
project = Project('examples/fauxware/fauxware')
# 定义一个SimProcedure子类
class CustomMain(SimProcedure):
def run(self, argc, argv):
print(f'程序运行参数: argc={argc}, argv={argv}')
return 0 # 返回0表示成功
# 将自定义过程挂钩到main函数
project.hook_symbol('main', CustomMain())
# 执行符号执行
simgr = project.factory.simulation_manager()
simgr.run() # 执行直到没有活跃状态
这个例子中,我们创建了一个CustomMain类继承自SimProcedure,重写了run方法。当程序执行到main函数时,会执行我们的自定义逻辑而不是原始代码。
SimProcedure的工作原理
参数传递机制
SimProcedure最强大的特性之一是自动参数提取。当定义run方法时:
- 方法参数(argc, argv等)会自动从程序状态中提取
- 提取过程遵循当前架构的调用约定
- 返回值也会按照调用约定写回程序状态
实现上下文
在angr内部,SimProcedure通过以下方式管理:
project._sim_procedures字典维护地址到SimProcedure实例的映射- 当执行流到达挂钩地址时,会调用对应SimProcedure的execute方法
- 每次执行都会创建新的SimProcedure实例以保证线程安全
高级特性
控制流操作
SimProcedure提供了多种控制流操作方法:
self.ret(value):从函数返回self.jump(addr):跳转到指定地址self.exit(code):终止程序self.call(addr, args, continue_at):调用函数并指定返回后继续执行的方法self.inline_call(procedure, *args):内联调用其他SimProcedure
条件分支
要实现条件分支,可以直接操作SimSuccessors对象:
# 创建状态副本
new_state = state.copy()
# 添加后继状态
self.successors.add_successor(
new_state, # 新状态
target_addr, # 目标地址
condition, # 条件表达式
jumpkind # 跳转类型
)
过程延续(Continuation)
SimProcedure延续允许在调用函数后恢复执行:
class ExampleProc(SimProcedure):
IS_FUNCTION = True
local_vars = ('counter',)
def run(self):
self.counter = 0
self.call(target_func, (arg1, arg2), 'after_call')
def after_call(self, result):
self.counter += 1
if self.counter < 10:
self.call(target_func, (arg1, arg2), 'after_call')
关键点:
- 设置
IS_FUNCTION = True - 定义
local_vars元组指定需要持久化的变量 - 使用
self.call()指定返回后继续执行的方法
数据类型处理
在SimProcedure中处理数据时需要注意:
- 参数会被包装为
SimActionObject类型,这是对普通位向量的轻量级封装 - 可以直接返回Python原生类型(如整数),它们会自动转换为适当大小的位向量
- 处理浮点数时需要显式指定调用约定
静态分析支持
通过设置类变量可以帮助静态分析:
NO_RET:表示函数不会返回ADDS_EXITS:表示函数会产生额外退出路径IS_SYSCALL:标记为系统调用
如果设置了ADDS_EXITS,还需要实现static_exits()方法。
用户Hook简化接口
对于不需要完整SimProcedure功能的场景,可以使用更简单的用户Hook:
@project.hook(0x1234, length=5)
def simple_hook(state):
state.regs.rax = 1 # 设置rax寄存器值
# 自动跳过5字节继续执行
特点:
- 不需要处理参数提取
- 通过length参数控制执行流
- 可以返回多个后继状态实现复杂控制流
符号挂钩实战
最常见的应用场景是替换库函数:
class DeterministicRand(SimProcedure):
def run(self, sequence=None):
idx = self.state.globals.get('rand_idx', 0) % len(sequence)
result = sequence[idx]
self.state.globals['rand_idx'] = idx + 1
return result
# 挂钩rand函数,使其返回固定序列
project.hook_symbol('rand', DeterministicRand(sequence=[1,2,3,4,5]))
这个例子将rand()函数替换为返回预定义序列的版本,对于需要确定性执行的分析非常有用。
总结
angr的Hook和SimProcedure机制提供了强大的程序行为修改能力。通过本文介绍的技术,开发者可以:
- 轻松替换任意函数实现
- 精确控制程序执行流
- 构建复杂的分析逻辑
- 实现库函数模拟
无论是进行程序分析、程序验证还是符号执行,这些技术都是angr工具箱中不可或缺的部分。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



