繁体   English   中英

装配级功能指纹

[英]Assembly-level function fingerprint

我想确定两个可执行文件中的两个函数是否从相同的(C)源代码编译而成,并且即使它们是由不同的编译器版本或具有不同的编译选项进行编译的,我也想这样做。 当前,我正在考虑实现某种汇编程序级功能指纹识别。 函数的指纹应具有以下特性:

  1. 在不同情况下从同一来源编译的两个函数可能具有相同的指纹(或相似的指纹),
  2. 从不同的C语言源编译的两个函数可能具有不同的指纹,
  3. (奖励)如果两个源函数相似,则指纹也相似(对于合理的相似定义)。

我现在正在寻找的是一组已编译函数的属性,这些函数分别满足(1.)并且希望也可以合在一起(2.)。

假设条件

当然,这通常是不可能的,但是在大多数情况下可能会存在某些可行的方法。 以下是一些可能使其变得更容易的假设:

  • linux ELF二进制文件(尽管没有可用的调试信息),
  • 不会以任何方式混淆
  • 由gcc编译,
  • 在x86 linux上(可以在其他体系结构上实现的方法很好)。

主意

不幸的是,我几乎没有组装经验。 以下是上述属性的一些想法:

  • 函数中包含的指令类型(即浮点指令,存储屏障)
  • 该函数的内存访问(它是从堆中读取/写入吗?堆栈?)
  • 库函数被调用(它们的名称应在ELF中可用;而且其顺序通常不应更改)
  • 控制流程图的形状(我想这将高度依赖于编译器)

现有工作

我只能找到切线相关的工作:


您对功能属性有什么建议吗? 还是可以实现我目标的其他想法? 还是已经实施了类似的方法,但我完全错过了?

FLIRT使用字节级模式匹配,因此它会因指令编码的任何更改而崩溃(例如,不同的寄存器分配/重新排序的指令)。

有关图匹配,请参见BinDiff。 Halvar虽未公开,但已在其博客中描述了一些方法。 他们甚至以BinCrowd plugin的形式开源了一些用于生成指纹的算法

以我的观点,做这种事情的最简单方法是将函数汇编分解回某种更高层次的形式,其中存在结构(例如forwhile ,function调用等),然后匹配这些更高层次的结构。

这样可以防止指令重新排序,循环提升,循环展开以及任何其他使比较混乱的优化,您甚至可以在两端将这个较高级别的结构最大化(最大化),以确保它们在同一点,因此未优化之间的比较调试代码和-O3不会因缺少临时性/缺少寄存器溢出等而失效。

您可以使用诸如回旋镖之类的东西作为反编译的基础(除非您不会吐出C代码)。

我建议您从编写代码的语言以及代码对编译器优化施加的约束的角度来解决此问题。

我不是很熟悉C标准,但是C ++具有“可观察”行为的概念。 该标准对此进行了仔细的定义,并且只要结果具有相同的可观察到的行为,编译器就具有很大的自由度。 对于尝试确定两个函数是否相同的建议是,尝试确定它们的可观察行为(它们执行的I / O以及与其他内存区域的交互方式以及交互顺序)。

如果问题集可以简化为由n个不同的编译器编译的一小套已知的CC++源代码函数,每个编译器具有m [n]个不同的编译器选项集,那么直接的解决方案(如果很乏味)将是编译该代码以及编译器和选项的每种组合,并在数据库中对生成的指令字节或更有效地将其哈希签名进行分类。

所使用的可能的编译器选项集可能很大,但是在实际实践中,工程师通常使用相当标准的选项集,但选项集很少,通常仅针对调试进行了最小优化,而针对发布进行了全面优化。 对许多项目配置进行的研究可能会发现,在任何一种工程文化中,与编译器的工作方式的偏见或迷信有关,无论准确性与否,都只有两个或三个以上。

我怀疑这种方法最接近您的实际需求:一种调查可疑的盗用源代码的方法。 所有建议的重建编译器分析树的技术都可能取得成果,但是对于被忽视的对称解或模棱两可的无法解决的情况具有很大的潜力。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM