我正在寻找能够从二进制文件中重建控制流图,同时支持多个平台(例如x86,x64,arm)的项目。例如,考虑以下简短的汇编程序:

.global main
.intel_syntax noprefix

.extern getchar
.extern printf

.section .data
jmpTable:
    .long _stub0
    .long _stub1
    .long _stub2
fmt: .asciz "%x\n"


.section .text

main:
    call getchar
    mov dl, 4
    imul dl
    add eax, offset jmpTable
    jmp [eax]
    .long 3851
_stub0:
    mov eax, 0
    jmp end
    .long 3851
_stub1:
    mov eax, 1
    jmp end
    .long 3851
_stub2:
    mov eax, 2
    jmp end
    .long 3851
end:
    push eax
    push offset fmt
    call printf
    add esp, 8
    ret


我考虑过的项目:


IDA(到目前为止,提取很痛苦)
BARF(天真的,有限的方法)
Angr(容易破解或永远计算)
Radare2(是否有任何API可以导出cfg数据?)
JakStab(仅限于x86)

相当明显的选择仍然是,导出过程间CFG仍然很麻烦。同样,尽管它能够找到此示例的所有基本块,但它错过了所有间接边缘。

项目应提供某种API来提供cfg。我知道仅靠静态分析来解决这个问题是不可行的。我正在寻找一种尽力而为的方法。

评论

从IDA提取信息的哪一部分特别痛苦?对我来说,编写IDAPython脚本似乎很容易。然后,如果IDA的原始API对您来说很麻烦,那么您可以构建自己的接口。

IDA公开了许多内部结构,并对控制流程图有自己的了解。主要批评是对边缘的功能和处理(和标记)的关注。

McSema和CMU BAP似乎很有希望。

#1 楼

目前,实践中最有效的方法似乎遵循符号执行的原理。这项技术最初是根据给定的源代码自动构建一组测试用例而开发的,最近已在二进制分析中用于发现和(部分)恢复所分析二进制程序的CFG。

大多数时候,如果要处理几种汇编语言,则需要对程序使用中间表示。目前,有许多这样的通用模型,没有一个真的比其他模型具有至高无上的优势。然而,最受欢迎的似乎是LLVM的中间表示(许多工具都使用它),第二受欢迎的似乎是VEX,Valgrind使用的中间表示(在Angr中使用)。也可以选择使用来自QEMU的语言或RREIL语言的语言,但较不常用。但是,大多数项目都有其自己的中间表示。

然后,您需要基于符号执行来构建CFG恢复程序的模块如下:


Loader:此模块负责执行您的二进制程序(它可以是可执行文件或库)并模拟本机加载程序的工作,以构建加载过程完成后所获得内容的真实内存映像
解码器:该模块负责将在符号执行程序时找到的本机程序集转换为您自己的中间表示形式。这是一段很长(很痛苦)的代码!因此,在执行此操作时要做好准备。
符号执行引擎:符号执行引擎通常基于使用逻辑QF_AUFBV(无量词/数组/未解释函数/位向量)的SMT求解器,如果您天真地对其进行编码,则符号执行引擎实际上可能是性能瓶颈,因为CFG的恢复将使用很多。在这里,拥有一个好的公式简化(或切片)模块才是真正的关键。

除了这三个模块之外,您还可以通过添加更多高级分析并开始编写一个抽象解释框架来改进您的工具,可以添加到中间表示的顶部,只是有机会展示仅通过SMT求解器的功能无法发现的CFG的某些部分。

此外,性能确实是使工具真正可用的关键。因此,能够捕获变量的确切范围或检测二进制代码中的函数或模块/对象的能力有助于大大减少您必须立即考虑的代码的大小。

现在,我可以为您提供有关此主题的很多指示和文章,但我有一点时间。稍后我可能会回来完成一本详尽的清单,但是希望上面已经给出了总体思路。希望对您有所帮助。

评论


感谢您的解释。我希望以前以比angr中的hacky实现更可靠的方式完成此操作。您知道其他提供这种功能的项目吗?

–诺德瓦尔德
16年9月2日在7:36

前一段时间,我编写了执行符号执行(或可以用作帮助执行此操作的模块)的工具列表。也许您可以在那里找到一些提示。

–恐怖
16年9月2日在11:57

#2 楼

使用radare2在JSON中提取控制流图:

$> python
import r2pipe
r2 = r2pipe.open("/bin/ls")
r2.cmd("aaa") # See radare.today/posts/analysis-by-default/
cfg = r2.cmdj("agj")


https://github.com/radare/radare2-bindings/tree/master/r2pipe/python

评论


是否没有某种“真实”的api?

–诺德瓦尔德
16-09-30在6:22

它不仅是一个:github.com/radare/radare2-bindings。 r2pipe只是r_core_cmd()的包装,它生成或连接到r2会话并运行命令并返回输出。只要有许多命令具有json输出,您就可以使用cmdj(),它将为您使用的语言返回一个本机对象。根据我的测试,这比使用swig绑定要快得多,因为数据序列化和ffi确实很昂贵。和json解析器的速度更快。 r2pipe不需要维护,它将在您想要的大多数用例中为您提供帮助。

–麦金
16-10-1在12:49



#3 楼


Angr(容易中断或永久计算)


如果您仍然对寻找解决方案感兴趣,则可以尝试再次尝试。您应该跳入我们的松弛频道(angr.slack.com,请从http://angr.io获得邀请),以便我们可以一起解决所有CFG恢复问题。

我相信angr会给您带来帮助您已经提到的所有解决方案中的最佳灵活性,而无需进入象征性的执行地狱。

免责声明:我是angr的核心开发人员。

#4 楼

我认为Radare2的“ agj”命令仅提取函数调用图,这与CFG(其中节点代表基本块的控制流程图)不同。