因此,首先,我尝试从在x86(32位)上剥离二进制文件。
现在,我的计划是这样的: br />
push %ebp
表示一个函数的起始地址。
我也可以扫描整个问题,将所有
functions
指令标识为目标,请将这些函数调用的目的地视为所有函数的开始地址问题是:
二进制可能永远也不会被调用。
call
的某些部分已被编译器优化为call
(考虑尾递归调用)对于结束地址,事情变得更加棘手,因为多个
jump
存在于一个函数中... 所以我想我可以保守地考虑将任何最接近的函数起始地址之间的范围视为一个函数。 ?有什么更好的解决方法吗?。
#1 楼
反转二进制的调用图或控制流图并不是为了使人胆怯,而是仍然是研究人员的热门话题。但是,不幸的是,您会遇到很多障碍。如果静态分析二进制文件,遵循
call
指令很可能会产生很好的结果。唯一的问题是,有时您会遇到间接调用/跳转。意思是,操作数将是一个包含目标地址的寄存器。例如,如果目标二进制文件原始源代码是用C++
(虚拟函数)编写的,则这种情况经常发生。在这种情况下,获取目标地址的一种方法是模拟或运行计算目标地址的代码块。另一个方法是通过启发式评估其价值(启发式方法很糟糕)。 其次,您可以运行具有多个输入数据集的二进制文件并动态提取调用图(这可以通过检测执行)。然后,您可以交叉引用所有获得的调用图...
三,我建议以基本块为中心的方法,而不是功能性的方法。主要是因为函数本身是一个基本块,并且与尝试匹配可能会从一个编译器更改为另一个编译器或从一个编译器版本更改为另一个版本的模式时相比,通过这种方式查找功能会更幸运。
以下出版物非常有趣:[1],[2],[3],如果您想了解更多有关该主题的知识,我也鼓励您检查
DynInst
和callgrind
。 评论
我在跟踪调用和对寄存器跳转进行(最小!)仿真方面取得了一些成功。在此处查看示例输出代码段。推荐的在线阅读:Decompiler Design-esp。基本块方法。
–杂件
2014年7月11日在10:20
#2 楼
通常,此问题的解决方案可以分类为:模式匹配试探法。就像您要提出的一样。例如,在二进制文件中搜索push
es可以提供一个(近似)函数开始的近似值。但是,如果要定位函数结尾,事情会变得更加困难。机器学习。模式匹配可以使用机器学习自动进行。文献中有一些建议,例如[1],[2]和[3]。所有这些尝试学习函数的字节级功能的起点和终点。但是,现代的编译器优化使这种方法难以推广到训练集之外的二进制文件。
基于CFG的技术。这是基于[4](同时是第一作者)和[5]的最有前途的方法。基本上,它将继续进行(1)直接调用目标分析,(2)遍历CFG以定位函数结束和(3)尾部调用目标分析。
调用帧信息(CFI)记录。在执行任何操作之前,请先检查
.eh_frame
部分中的CFI记录。很可能已经在其中定义了功能。为了转储CFI记录,您可以使用readelf --debug-dump=frames /bin/ls
之类的方法。评论
凉。感谢您以很好的方式总结问题。现在是2020年,独自发表有关“确定功能边界”的研究论文可能不像我五年前发布这个问题时那样有希望。但是,是的,很高兴看到二进制黑客组织不断探索和发表该领域的论文。
– lllllllllllll
5月27日8:36
评论
最简单的方法可能是获得IDA 5.0(免费版本)并让它完成工作。您也可以考虑使用radare2。看到问题:用Radare2进行递归遍历是什么?