我对二进制代码级别的软件的形式验证感兴趣。显然,第一步是从二进制文件中恢复实际的汇编指令。

IDAPro可以很好地反汇编x86,但是,仍有可能将某些数据解释为代码。 。因此,基于它的分析仍然是不正确的。 />和ARM指令的可变性小于x86(2或4个字节的长度)。

反汇编ARM二进制文件可以吗?换句话说,反汇编程序能否准确地恢复实际代码?

#1 楼

经过一些研究,我认为我可以从理论角度进行一些解释。请注意,我的讨论仅限于剥离(无调试信息)可执行文件。我们知道,几种数据可以与可执行文件中的代码混合,包括填充字节和开关跳转地址计算。

为了将日期与代码分开,我们需要精确地提取属于该代码的字节,并据此假定其余字节属于数据。从众所周知的入口点开始精确地提取代码的主要挑战是间接跳转,即控制流重定向到运行时计算的内存地址。 DarthZirka提到了一些示例,其中包括C ++中的切换表,函数指针和vtable。不可思议。该结果自70年代末期在学术界开始普及拆卸以来就已确立,我可以参考以下早期论文以获取更多详细信息。 Horspool和N. Marovac。解决计算机程序反翻译问题的方法。计算机,1979年,23(3):223-229。因此,任何反汇编方法都应基于启发式算法,例如识别常见的编译器惯用法和/或近似(间接)超出间接跳转可到达的地址集。后者通常通过基于抽象解释框架的静态分析来完成。与ARM相比,X86中的可变大小指令会使事情变得更难(过度近似),但是仍然存在本质问题。

#2 楼

覆盖率/完整性问题与拆卸引擎的“准确性”或指令长度的变化无关。如果并且当未从植根于目标二进制文件入口点的调用树中静态引用代码时,就会出现问题。

其中包括:


其他外部入口点(DLL导出,TLS回调等)
切换表
vtables
非静态函数指针/表(例如C风格的对象)
与异常处理等有关的功能/重击。
CRT初始化/退出表

准确性在交换表方面发挥作用,在IDA中由各个处理器模块负责。其他事情由加载程序,内核,编译器特定的插件(RTTI,异常funclet)以及最终的人工操作员负责。

x64 COFF中的SEH信息涵盖了所有非叶函数,与32位COFF相比,覆盖率大大提高。如果您可以控制构建过程,则可以通过调试信息(PDB,TDS等)获得几乎完美的覆盖范围。让链接器生成详细的MAP文件也可能会有所帮助。在这种情况下,反汇编程序可能难以确定给定的立即数是偏移量还是数字。基于指针的指针也会发生相同的问题,包括IDA希望发生RVA的地方之外的RVA。

#3 楼

您将面临与任何反汇编程序一样的问题:您不知道事物的含义。

我上周遇到的现实示例:当我看到0x00408800值传递给函数时,我确定这一定是个面具。经过大量跟踪,发现值存储在某个地方,在其他地方复制,在类构造函数中使用,并在子类的方法中访问,我发现这实际上是一个内存位置,恰好是一个更大的数组,所以它甚至没有一个符号。从数据到代码的那个地址。可能会从中计算出每个使用的值,您将无法自动找到这样的歧义。但是,这只是歧义的一个例子,我想能够区分存储位置和位图对于任何类型的代码验证都是非常重要的。

因此,除非您进行还有更多的假设(代码是由特定的编译器生成的,该编译器仅发出以特定方式组合的有限数量的基本块),不,我认为这是不可能的。

评论


再举一个例子:有时程序会推送一个类似0x40001000的参数,它可能是例如图片库或位掩码。 IDA通常认为它是一个函数指针而不是位掩码,甚至为该地址创建一个外部参照和一个函数。因此,最终,除非您模拟所有可能的情况(不可能),否则无法以编程方式知道该数字的含义。

–rev
15年2月24日在15:15

仅在以下情况下这是一个问题:(1)收件人的签名未知(当前二进制文件的一部分或TIL / PDB中都不知道),并且(2)收件人执行该指针。即比较少见。 IOW,这个问题通常是无法解决的,但对于大型类的实际二进制文件则可以完美解决。

– DarthGizka
15年2月24日在16:28

如果您可以访问所有这些信息,我会怀疑OPs语句“显然,第一步将是从二进制文件中恢复实际的汇编指令”成立。

–贡特拉姆·布洛姆(Guntram Blohm)
15年2月24日在16:31