在手写汇编上执行时,反编译是否明显受到更多限制?

逆向工程 部件 反编译
2021-06-27 16:26:12

我了解 C 语言反编译器旨在反编译由 C 编译器生成的代码,并且此类反编译器有很多限制,有时实际上是错误的(从某种意义上说,它们生成的 C 代码在功能上与它们的汇编代码不同虽然我不明白为什么它们会生成功能上不等效的代码)。

如果您从手写汇编开始,反编译真的不起作用吗?我不是在谈论高度优化或混淆的程序集;我可以理解那些可能会以某种方式破坏反编译。

2个回答

这更像是一个扩展评论,而不是一个经验研究的答案。

观点 1:反编译器设计假设违规

抽象地说,我们可以考虑的一种方式是工具设计。一个工具在应用于其设计者开发的工具来解决的问题时往往表现最佳。请记住,反编译器执行与编译相反的操作,因此可以提出一个论点,即使用反编译器分析从手写汇编生成的机器代码是将其应用于它不打算解决的问题的一个例子,因为该机器代码不是编译产生的。

换句话说,如果反编译器做出的假设是被分析的机器代码是由编译器生成的,那么从手写汇编生成的机器代码就违反了这个假设。当 HLL 源代码一开始就不存在时,尝试反编译从手写汇编生成的机器代码相当于尝试为机器代码近似高级语言 (HLL) 源代码。

mumblehard-ghidra-反编译

在上面的屏幕截图中,我们看到 Ghidra 的反编译器在mumblehard变体的解包存根中为机器代码生成的输出解包存根是用汇编编写的(观察直接在位置0x08048064处进行的系统调用0x08048095)。

观点 2:不存在的 Source-to-Assembly 关系

由于 HLL 源代码(例如 C++)和从该源代码生成的汇编代码之间的关系,反编译是可能的 - 由编译器完成的翻译。对于手写汇编,从来没有这种关系存在,也没有发生过这种翻译。因此,在处理由手写汇编生成的机器代码时,假设应该由反编译器在该机器代码和 HLL 之间导出有意义的映射是错误的。手工组装不需要与通过编译从 HLL 代码生成的组装有任何关系。如果手工组装的程序集由于某种原因而采用某种形式——仅仅因为程序员可以完全控制低级操作——则无法通过编译 HLL 源代码生成,

我不明白为什么他们实际上是错的

编译器将人类可读形式(如C)的高级代码转换为低级代码(以便机器可以理解它)。在编译期间,由于语言转换、多重优化等,大部分语义和句法信息丢失。调试符号可能会保留一些信息(因为它们用于调试目的,对代码的实际功能没有贡献),但是它们通常在 COTS 二进制文件中被剥离。因此,有时很难(np-hard?)恢复所有信息。考虑以下程序:

int main() {
  int a[10];
  a[4] = 4;
}

main:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-32], 4
        mov     eax, 0
        pop     rbp
        ret

程序编译没有优化,可以看到相关信息永久丢失(虽然可以尝试根据栈大小来预测数组,但无法断定它确实是数组)。

如果您从手写汇编开始,反编译真的不起作用吗?

它可能会也可能不会。如果二进制文件是使用 gcc 或 llvm 等标准编译器编译的,那么此类编译器将使用特定格式(调用约定、优化或代码表示风格等)。但是在手写汇编中,您基本上可以做任何事情(使用自定义格式、不同的调用约定等)。因此,很难预测程序员的意图。

在这篇最近发表的论文中阅读有关反编译正确性的更多信息:

刘志博和王帅。2020. 我们走了多远:测试C反编译器的反编译正确性。在第 29 届 ACM SIGSOFT 软件测试和分析国际研讨会 (ISSTA 2020) 的会议记录中。计算机协会,纽约,纽约,美国,475–487。DOI:https : //doi.org/10.1145/3395363.3397370