angr源码分析——数据依赖图 DDG

这篇博客详细剖析了angr框架中数据依赖图(DDG)的构建过程,通过实例解析DDG的构造函数和关键函数track(),探讨了handle_tmp_read函数如何判断数据依赖,为理解angr的DDG提供深入理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于官方文档中关于数据依赖图(DDG)的说明少之又少,所以这是一篇对angr构造数据依赖图由浅入深的分析博客。下面就开始吧。
DDG的使用案例:

#先加载一个二进制文件,选择符号分析模式
proj = angr.Project(binary_path,load_options={'auto_load_libs': False},default_analysis_mode='symbolic')
#利用CFGAccurate构造一个cfg,记得将选项keep_state设置为True,state添加选项sim_options.refs
cfg = proj.analyses.CFGAccurate(context_sensitivity_level=2, keep_state=True,state_add_options=angr.sim_options.refs)
#传入刚刚构造好的cfg,构造数据依赖图
ddg = proj.analyses.DDG(cfg, start=cfg.functions['main'].addr)
#打印出构造好的DDG的节点数目
print len(ddg.graph)

下面我们从DDG的构造函数开始,梳理DDG的构造过程。

在DDG的构造函数前,有这样一段声明:
这是一个快速的数据依赖图,直接由我们的CFG分析结果生成。合理性或准确性是零保证的。仅用于跟踪简单的数据依赖。
可以看出angr DDG的构造是真的很不靠谱哦。但是为了能改进它,也要先了解它的原理。
构造函数的参数很少,所以可定制的地方也不多:
        :param cfg:         控制流图,保证每个node都有state,这也是需要打开keep_state选项的原因。
        :param start:       一个地址, 指定从哪里开始生成数据依赖图.
        :param call_depth:  整数或空. 一个非负整数,代表跟进调用图的深度,空代表无深度限制.
        :param iterable or None block_addrs: 一个块地址集合,表示DDG分析的范围.

构造函数的前面都是变量的初始化,然后直接调用了self._construct()函数开始构造。函数执行流程以及在下述代码的注释中,如果真的想了解其中的原理,是一定要结合代码来看的。
    def _construct(self):
        """
        Construct the data dependence graph.
        主要跟踪如下类型的依赖:
        - (Intra-IRSB) IRSB内部的临时变量依赖
        - 寄存器依赖
        - 内存依赖, 尽管它是有限制的
        跟踪如下类型的内存访问:
        - (函数内) 栈的读写.
            跟踪函数内栈的改变, 和栈指针的依赖.
        - (函数间) 栈的读写.
        - (全局) 静态内存位置.
            将所有可访问内存位置映射到它们每个函数的原语句。在那之后,我们遍历CFG并将每一对读取/写入以控制流的顺序链接在一起.
        不跟踪如下类型的内存访问
        - 符号内存的访问
            好吧,它们不能在fastpath模式下被追踪(这是我们生成CTF的模式).
        """

        worklist = []
        worklist_set = set()

        # Initialize the worklist
        if self._start is None: #如何没有给出分析的起始点
            # 初始化在CFG中入度为0的点
            for n in self._cfg.graph.nodes():
                if self._cfg.graph.in_degree(n) == 0:
                    # Put it into the worklist
                    job = DDGJob(n, 0) #创建job
                    self._worklist_append(job, worklist, worklist_set)
        else: #否则将跟据start获得node,并创建job,加入到worklist中
            for n in self._cfg.get_all_nodes(self._start):
                job = DDGJob(n, 0)
                self._worklist_append(job, worklist, worklist_set)

        # A dict storing defs set
        # DDGJob -> LiveDefinition
        live_defs_per_node = {}

        while worklist:
            # 从worklist中取出一个节点
            ddg_job = worklist[0]
            l.debug("Processing %s.", ddg_job)
            node, call_depth = ddg_job.cfg_node, ddg_job.call_depth
            worklist = worklist[ 1 : ]
            worklist_set.remove(node)

            # 获取一个节点node所有的final states. 通常超过一个 (一个successors
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值