当前位置: 首页 > article >正文

【记录】Angr|Angr 标准库函数替换怎么看哪些库函数被Angr支持?

文章目录

  • 前言
  • 分析
    • 什么是库函数替换?
      • 为什么需要库函数替换?
    • 如何查找支持的库函数
      • 官方支持列表
      • 目录结构说明
    • 常用的替换包括哪些?
      • 1. 字符串处理函数
      • 2. 内存管理函数
      • 3. 文件操作函数
    • 高级技巧
      • 1. 自定义库函数实现
      • 2. 条件替换
    • 常见问题与解决方案详解
      • 1. 找不到合适的替换函数
        • 问题表现
        • 解决方案
          • 1.1 源码分析法
          • 1.2 自定义实现示例
          • 1.3 使用近似替换
      • 2. 替换后行为异常
        • 问题表现
        • 解决方案
          • 2.1 函数签名检查
          • 2.2 约束条件调整
          • 2.3 状态空间控制
      • 3. 性能问题
        • 问题表现
        • 解决方案
          • 3.1 简化替换函数
          • 3.2 深度限制
          • 3.3 优化约束条件
      • 实用建议
      • 最佳实践总结
    • 总结

前言

我在学习 Angr,这里会记录一些琐碎的、在中文引擎里一搜没找到解法的问题。Angr 是一种符号执行工具。

我的学习内容:
博主链接:Angr 使用技巧速通笔记(二) | TokameinE - 雨声淅淅沥沥,犬吠永不止息
Github 教程链接:https://github.com/jakespringer/angr_ctf

本博客是学习到 13_angr_static_binary 时产生的疑惑。

分析

什么是库函数替换?

在符号执行过程中,为了更好地控制执行流程和状态空间,Angr 会使用自己实现的版本来替换程序中的标准库函数调用。这些替换函数通常是原始函数的简化版本,专门为符号执行优化设计。

为什么需要库函数替换?

  1. 性能优化: 原始库函数可能过于复杂,会导致状态空间爆炸
  2. 行为控制: 可以更精确地控制函数行为,便于分析
  3. 符号执行支持: 确保函数可以正确处理符号值
  4. 跨平台兼容: 提供统一的函数行为,减少平台差异

如何查找支持的库函数

首先,Angr 标准库函数替换怎么看哪些库函数被Angr支持?这个问题 Angr_ctf 题解里面写了,提供了官方支持列表。

官方支持列表

Angr 的所有支持库函数都可以在其 GitHub 仓库中找到:
https://github.com/angr/angr/tree/master/angr/procedures

目录结构说明

angr/procedures/
├── libc/           # C标准库函数
├── posix/          # POSIX系统调用
├── win32/          # Windows API
├── linux_kernel/   # Linux内核函数
└── ...

进而不由产生其他疑问:

  1. 这么多库函数怎么知道自己想要的是哪个?
  2. 常用的替换包括哪些?

常用的替换包括哪些?

常用的替换有哪些?
Angr替换库函数的种类相对广泛,常见的包括:

  • 内存相关函数:如mallocfreecalloc等。
  • 字符串操作函数:如strlenstrcpystrncpy等。
  • 文件操作函数:如openreadwriteclose等。
  • 系统调用:如execveexit等。
  • 时间和日期相关:如timegmtimelocaltime等。

这些替换的函数一般都提供了简化版或精简版的实现,方便Angr进行符号执行和模拟。

1. 字符串处理函数

# 示例: 替换 strlen 函数
import angr

def analyze_strlen():
    proj = angr.Project('./target_binary')
    
    # 手动替换 strlen
    proj.hook_symbol('strlen', angr.SIM_PROCEDURES['libc']['strlen']())
    
    # 模拟执行
    state = proj.factory.entry_state()
    simgr = proj.factory.simulation_manager(state)
    simgr.explore()

常见字符串函数替换:

  • strlen: 字符串长度计算
  • strcpy: 字符串复制
  • strncpy: 限制长度的字符串复制
  • strcat: 字符串拼接

2. 内存管理函数

# 示例: 替换 malloc 和 free
def analyze_memory():
    proj = angr.Project('./target_binary')
    
    # 替换内存分配函数
    proj.hook_symbol('malloc', angr.SIM_PROCEDURES['libc']['malloc']())
    proj.hook_symbol('free', angr.SIM_PROCEDURES['libc']['free']())

常见内存函数:

  • malloc: 动态内存分配
  • calloc: 分配并清零内存
  • realloc: 重新分配内存
  • free: 释放内存

3. 文件操作函数

# 示例: 模拟文件操作
def analyze_file_ops():
    proj = angr.Project('./target_binary')
    
    # 替换文件操作函数
    proj.hook_symbol('fopen', angr.SIM_PROCEDURES['libc']['fopen']())
    proj.hook_symbol('fread', angr.SIM_PROCEDURES['libc']['fread']())
    proj.hook_symbol('fwrite', angr.SIM_PROCEDURES['libc']['fwrite']())
    proj.hook_symbol('fclose', angr.SIM_PROCEDURES['libc']['fclose']())

高级技巧

1. 自定义库函数实现

有时候 Angr 提供的默认实现可能不满足需求,我们可以自定义实现:

class CustomStrlen(angr.SimProcedure):
    def run(self, str_addr):
        # 自定义 strlen 实现
        strlen = 0
        while True:
            curr_char = self.state.memory.load(str_addr + strlen, 1)
            curr_val = self.state.solver.eval(curr_char)
            if curr_val == 0:
                break
            strlen += 1
        return strlen

# 使用自定义实现
proj.hook_symbol('strlen', CustomStrlen())

2. 条件替换

根据不同条件使用不同的替换实现:

def conditional_hook(state):
    # 根据状态决定是否替换
    if state.solver.eval(state.regs.rax) > 0x1000:
        return angr.SIM_PROCEDURES['libc']['malloc']()
    return None

proj.hook_symbol('malloc', conditional_hook)

常见问题与解决方案详解

后面这些解决方案由AI生成

1. 找不到合适的替换函数

问题表现
  • 在 Angr 的标准库中找不到目标函数的实现
  • 现有的替换函数不能完全满足分析需求
  • 需要处理特殊的或非标准的库函数
解决方案
1.1 源码分析法

首先查看 Angr 源码中类似功能的实现:

# 示例:查找字符串比较相关的函数实现
# 路径:angr/procedures/libc/strcmp.py

class strcmp(angr.SimProcedure):
    def run(self, a_addr, b_addr):
        # 实现细节
        pass

# 如果需要实现类似的函数,可以参考这个模板
1.2 自定义实现示例
# 自定义一个复杂的字符串处理函数
class CustomStrProcess(angr.SimProcedure):
    def run(self, str_addr, len_param):
        # 1. 参数处理
        strlen = self.state.solver.eval(len_param)
        if strlen > 1000:  # 添加合理的限制
            strlen = 1000

        # 2. 内存读取
        string = self.state.memory.load(str_addr, strlen)
        
        # 3. 实现特定的处理逻辑
        processed = self.process_string(string)
        
        # 4. 处理返回值
        return processed

    def process_string(self, string):
        # 实现具体的处理逻辑
        pass

# 使用自定义函数替换
proj.hook_symbol('target_function', CustomStrProcess())
1.3 使用近似替换

如果无法完全匹配原函数功能,可以使用功能相近的替换:

# 示例:用 strncmp 替换 strcmp
proj.hook_symbol('strcmp', angr.SIM_PROCEDURES['libc']['strncmp'](length=100))

2. 替换后行为异常

问题表现
  • 程序执行路径不符合预期
  • 符号执行过程中出现异常
  • 分析结果不准确
解决方案
2.1 函数签名检查
# 正确的函数签名示例
class CorrectMemcpy(angr.SimProcedure):
    def run(self, dest_addr, src_addr, length):
        # 确保参数类型正确
        if not isinstance(length, claripy.ast.Base):
            length = self.state.solver.BVV(length, self.state.arch.bits)
        
        # 实现内存复制逻辑
        return dest_addr

# 使用方法
proj.hook_symbol('memcpy', CorrectMemcpy())
2.2 约束条件调整
def add_constraints(state):
    # 添加基本约束
    buff_addr = state.regs.rdi  # 假设缓冲区地址在 rdi 寄存器
    
    # 限制缓冲区大小
    state.add_constraints(state.mem[buff_addr].uint32_t != 0)
    state.add_constraints(state.mem[buff_addr].uint32_t < 1024)
    
    # 限制字符范围
    for i in range(32):
        curr_byte = state.memory.load(buff_addr + i, 1)
        state.add_constraints(curr_byte >= 0x20)
        state.add_constraints(curr_byte <= 0x7e)

# 在符号执行前添加约束
state = proj.factory.entry_state()
add_constraints(state)
2.3 状态空间控制
# 设置执行超时和内存限制
def explore_with_limits():
    proj = angr.Project('./target_binary')
    state = proj.factory.entry_state()
    
    # 创建模拟管理器
    simgr = proj.factory.simulation_manager(state)
    
    # 设置探索限制
    simgr.explore(
        find=lambda s: b"success" in s.posix.dumps(1),
        avoid=lambda s: b"fail" in s.posix.dumps(1),
        n_find=1,  # 只需要找到一个解
        max_active=1000,  # 限制活动状态数量
        timeout=300  # 设置超时(秒)
    )

3. 性能问题

问题表现
  • 符号执行速度过慢
  • 内存消耗过大
  • 状态爆炸
解决方案
3.1 简化替换函数
# 简化版的 strlen 实现
class FastStrlen(angr.SimProcedure):
    def run(self, str_addr):
        # 设置最大搜索长度
        MAX_LEN = 64
        
        # 快速扫描定长
        for i in range(MAX_LEN):
            curr_char = self.state.memory.load(str_addr + i, 1)
            is_null = self.state.solver.is_true(curr_char == 0)
            if is_null:
                return i
        
        return MAX_LEN

# 使用简化版本
proj.hook_symbol('strlen', FastStrlen())
3.2 深度限制
def limited_exploration():
    proj = angr.Project('./target_binary')
    state = proj.factory.entry_state()
    simgr = proj.factory.simulation_manager(state)
    
    # 设置探索策略
    simgr.use_technique(angr.exploration_techniques.LoopSeer(
        loops=[0x400c40, 0x400d30],  # 指定循环的地址
        bound=10  # 限制循环执行次数
    ))
    
    # 限制执行深度
    simgr.use_technique(angr.exploration_techniques.LengthLimiter(
        max_length=1000  # 最大执行步数
    ))
    
    return simgr.run()
3.3 优化约束条件
def optimize_constraints():
    proj = angr.Project('./target_binary')
    state = proj.factory.entry_state()
    
    # 1. 添加智能约束
    input_size = 32
    input_chars = [state.solver.BVS(f'c{i}', 8) for i in range(input_size)]
    
    # 2. 使用批量约束而不是单字符约束
    printable = state.solver.And(
        state.solver.And(c >= 0x20, c <= 0x7e) for c in input_chars
    )
    state.add_constraints(printable)
    
    # 3. 使用预设值减少求解空间
    known_prefix = b"FLAG{"
    for i, c in enumerate(known_prefix):
        state.add_constraints(input_chars[i] == c)
    
    return state

实用建议

  1. 日志与调试

很有用

# 开启详细日志
import logging
logging.getLogger('angr').setLevel(logging.DEBUG)

# 添加调试点
@proj.hook(0x400c40)
def debug_hook(state):
    print(f"执行到地址 0x400c40")
    print(f"寄存器状态: {state.regs}")
    print(f"内存内容: {state.mem[state.regs.rsp].uint64_t.concrete}")
  1. 性能监控
import time
import resource

def monitor_execution():
    start_time = time.time()
    start_memory = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
    
    # 执行分析
    result = run_analysis()
    
    end_time = time.time()
    end_memory = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
    
    print(f"执行时间: {end_time - start_time:.2f} 秒")
    print(f"内存使用: {(end_memory - start_memory) / 1024:.2f} MB")
    
    return result

最佳实践总结

  1. 渐进式调试

    • 先用简单的替换函数测试
    • 逐步添加复杂功能
    • 持续监控性能变化
  2. 模块化设计

    • 将复杂的替换函数拆分为小模块
    • 便于测试和维护
    • 提高代码复用性
  3. 错误处理

    • 添加适当的错误处理机制
    • 设置合理的超时和限制
    • 保存中间状态便于调试

这些解决方案和最佳实践可以帮助你处理 Angr 库函数替换过程中遇到的大多数问题。在实际应用中,可能需要根据具体情况组合使用多种方案。

总结

库函数替换是 Angr 符号执行中的重要机制,掌握它能够帮助我们更好地控制程序分析过程。本文详细介绍了:

  1. 库函数替换的基本概念
  2. 如何查找和使用支持的库函数
  3. 常用替换函数的详细说明
  4. 实战案例演示
  5. 高级使用技巧
  6. 常见问题的解决方案

希望这篇文章能够帮助读者更好地理解和使用 Angr 的库函数替换功能。

本账号所有文章均为原创,欢迎转载,请注明文章出处:https://shandianchengzi.blog.csdn.net/article/details/144883082。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。


http://www.kler.cn/a/466528.html

相关文章:

  • 通过爬虫方式实现视频号助手发布视频
  • VScode SSH 错误:Got bad result from install script 解決
  • linux定时执行脚本的方法
  • 【大模型】7 天 AI 大模型学习
  • Rust中的Option枚举快速入门
  • JAVA:Spring Boot 集成 Quartz 实现分布式任务的技术指南
  • Couchbase是不是MPP数据库
  • 学生管理系统springboot+论文源码调试讲解
  • 【Seed-Labs 2.0】Cross-Site Scripting (XSS) Attack Lab (Web Application: Elgg)
  • Python:爬虫基础《爬取红楼梦》
  • Redis Hash哈希
  • 使用Clion在ubuntu上进行交叉编译,并在Linux上远程编译五子棋
  • ABAQUS三维Voronoi晶体几何建模
  • 多台DHCP服务器时的问题讨论
  • Windmill 实战:快速构建自动化工作流和用户界面
  • Windows安装了pnpm后无法在Vscode中使用
  • AWS S3文件存储工具类
  • PyTorch AMP 混合精度中grad_scaler.py的scale函数解析
  • 使用函数求e的近似值(PTA)C语言
  • 【硬件测试】基于FPGA的2FSK+帧同步系统开发与硬件片内测试,包含高斯信道,误码统计,可设置SNR
  • 阻抗(Impedance)、容抗(Capacitive Reactance)、感抗(Inductive Reactance)
  • 【Docker】:Docker容器使用
  • 野火直播 5.9.5 | 频道丰富的电视直播软件,支持港澳台频道和快速换台
  • 【深度学习】Java DL4J基于 LSTM 构建新能源预测模型
  • vue学习第一阶段
  • MacBook_Xcode_Swift雨燕