简单的活着

angr.analyses.CFG

Posted on By Mista Cai

angr.analyses.CFG

angr包括分析以恢复二进制程序的控制流图。

基本思想

二进制文件的一个基本分析就是控制流图。控制流图以基本块为节点,jumps/calls/rets/etc为边。

angr可以生成两种CFG:静态CFGFast,动态CFGEmulated。

  • CFGFast使用静态分析来生成CFG。 它更快,但理论上受到一些控制流转换只能在执行时解决的限制。 这与其他流行的逆向工程工具执行的CFG分析相同,其结果与其输出相当。
  • CFGEmulated使用符号执行来捕获CFG。 虽然它在理论上更准确,但速度要慢得多。 由于仿真的准确性(系统调用,缺少硬件功能等)的问题,它通常也不太完整。

建立控制流图

>>> import angr
# load your project
>>> p = angr.Project('/bin/true', load_options={'auto_load_libs': False})

# Generate a static CFG
>>> cfg = p.analyses.CFGFast()

# generate a dynamic CFG
>>> cfg = p.analyses.CFGEmulated(keep_state=True)

使用CFG

CFG的核心是NetworkX di-graph.这意味着所有正常的NetworkX API都可用:

>>> print("This is the graph:", cfg.graph)
>>> print("It has %d nodes and %d edges" % (len(cfg.graph.nodes()), len(cfg.graph.edges())))

CFG图的节点是CFGNode类的实例。 由于上下文敏感性,给定的基本块可以在图中具有多个节点(对于多个上下文)

# this grabs *any* node at a given location:
>>> entry_node = cfg.get_any_node(p.entry)

# on the other hand, this grabs all of the nodes
>>> print("There were %d contexts for the entry block" % len(cfg.get_all_nodes(p.entry)))

# we can also look up predecessors and successors
>>> print("Predecessors of the entry point:", entry_node.predecessors)
>>> print("Successors of the entry point:", entry_node.successors)
>>> print("Successors (and type of jump) of the entry point:", [ jumpkind + " to " + str(node.addr) for node,jumpkind in cfg.get_successors_and_jumpkind(entry_node) ])

CFG可视化

控制流图形渲染是一个难题。 angr没有提供任何用于渲染CFG分析输出的内置机制,并且尝试使用传统的图形渲染库(如matplotlib)将导致图像无法使用。

在axt的angr-utils库中可以找到一种查看angr CFG的解决方案。

angr-utils,主要提供CFG可视化,标准输出PP和工具函数。

安装

cd angr-dev
git clone https://github.com/axt/bingraphvis
pip install -e ./bingraphvis
git clone https://github.com/axt/angr-utils
pip install -e ./angr-utils

应用

案例

import angr
from angrutils import *
proj = angr.Project("<...>/ais3_crackme", load_options={'auto_load_libs':False})
main = proj.loader.main_object.get_symbol("main")
start_state = proj.factory.blank_state(addr=main.rebased_addr)
cfg = proj.analyses.CFGEmulated(fail_fast=True, starts=[main.rebased_addr], initial_state=start_state)
plot_cfg(cfg, "ais3_cfg", asminst=True, remove_imports=True, remove_path_terminator=True)  

共享库

CFG分析不区分不同二进制对象的代码。 这意味着默认情况下,它将尝试通过加载的共享库分析控制流。 这几乎不是预期的行为,因为这可能会将分析时间延长到几天。 要加载没有共享库的二进制文件,请将以下关键字参数添加到Project构造函数中:load_options = {'auto_load_libs':False}