从二进制文件中获取源代码

Obtaining source code from the binary

不是应该可以从它的二进制文件中获取源代码吗? 既然编译就是将高级语言(源代码)转化为低级语言(机器码)的过程,难道我们就不能反过来得到源代码吗?如果不是,为什么?

假设我给你数字3,并告诉你我是通过将两个数字相加得到的。你能告诉我 3 是两个数的和吗?这是不可能的,因为 sum 是一个单向函数——不可能从它的输出中恢复它的参数。我本可以从 -5558 获得它,即使 for you 12 仍然得出相同的答案.

编译类似。有无数的 C++ 程序可以生成任何特定的机器代码输出(或多或少)。

您当然可以反转编译过程并生成 C 或 C++ 代码,这些代码至少会产生具有相同语义(含义)但可能字节对字节不同的机器代码。此类工具在不同程度上存在。

所以是的,这是可能的,但是因为来自源代码的很多信息必然会丢失,代码您将不会对原始源代码的设计有太多了解。对于任何大型项目,您得到的将是执行相同操作但对人类来说几乎不可读的代码。这将是一些非常非常混乱的 C/C++。

为什么信息丢失了?因为高级语言的全部重要之处在于 它们应该对人类有效处理。源代码越高级、越易于人类理解,它与编译器完成后生成的机器代码的差异就越大。作为软件设计师,您的主要 objective 是 利用 编译器和其他代码生成工具将高级思想和概念转换为机器代码。两者差距越大,高层设计的信息丢失的越多。

请记住,编译器唯一必须保留的是代码的 语义(含义)。只要 显示 代码正在按照您的意思执行,一切都很好。例如,现代编译器可以预先执行部分代码,并且只存储操作的结果,当它根据某些指标 "sense" 这样做时。假设您的整个程序如下所示:

#include <iostream>
#include <cmath>
int main() {
  std::cout << sin(1)+cos(2) << std::endl;
  return 0;
}

假设是一个 Unix 系统,编译器完全有权生成执行 两个 系统调用的机器代码:写入 stdout,使用常量缓冲区,然后退出。反编译这样的代码,你可以得到:

#include <unistd.h>
#include <cstdlib>
int main() {
  write(0, "0.425324\n", 9);
  exit(0);
}