用调试信息反编译C代码
Decompile C code with debug info?
与C/c++编译器生成的编译后的机器码相比,Java和Python字节码相对容易反编译。
我无法找到一个令人信服的答案,为什么从-g选项的信息是不够的反编译,但足以调试?Python/Java字节码中包含的额外内容是什么,使反编译变得容易?
以下是一些原因:
- Java和Python的字节码相对简单和高级,而一些cpu(比如x86)的指令集是极其复杂的。
- 字节码紧密地模仿了它们所设计的语言结构。
- 在生成字节码时,Java和Python通过优化的方式做得很少。这导致字节码与原始源代码的结构紧密对应。一个好的优化C或c++编译器能够生成远离原始源代码的汇编。
- Java和Python编译器很少,C和c++编译器很多。如果您的目标是一个已知的编译器(或一组已知的编译器),则更容易生成高质量的反编译器。 与c++相比,Python和Java是相对简单的语言(这一点不适用于C)。
- c++模板对质量反编译提出了许多挑战(这一点也不适用于C)。
- C/c++预处理器。
- 在Python中,源文件和字节码文件之间存在一对一的关系。在Java中,这种关系是一个源到一个或多个字节码文件。在C和c++中,这种关系是多对多的,在源代码前端有很多重叠(想想头文件)。
我无法找到一个令人信服的答案,为什么从-g选项的信息是不够的反编译,但足以调试?
debugging信息基本上只包含生成代码中的地址与源文件行号之间的映射关系。调试器不需要反编译代码——它只显示原始源代码。如果源文件丢失,调试器不会神奇地显示它们。
也就是说,调试信息的存在确实使反编译更容易。如果调试信息包括使用的类型和函数原型的布局,反编译器可以使用它并提供更精确的反编译。然而,在许多情况下,它仍然可能与原始来源不同。
例如,下面是一个用Hex-Rays反编译器反编译的函数,而不使用调试信息:
int __stdcall sub_4050A0(int a1)
{
int result; // eax@1
result = a1;
if ( *(_BYTE *)(a1 + 12) )
{
result = sub_404600(*(_DWORD *)a1);
*(_BYTE *)(a1 + 12) = 0;
}
return result;
}
由于它不知道a1
的类型,因此对其字段的访问表示为添加和强制类型转换。
void __thiscall mytree::write_page(mytree *this, PAGE *src)
{
if ( src->isChanged )
{
cache::set_changed(this->cache, src->baseAddr);
src->isChanged = 0;
}
}
你可以看到它已经改进了很多。
至于为什么反编译字节码通常更容易,除了NPE的答案检查还有这个。
一些处理器,如x86处理器,具有可变长度的指令。如果控制被传递到指令的中间(=第一个字节之后的任何地方),那也可以是一个有效的指令(或几个指令)。这使得明确地反汇编机器码变得困难。C/c++代码可以利用这个特性。
在一些处理器和操作系统上,可以像执行代码一样执行数据,也可以像使用数据一样使用代码。这使得很难明确地将两者分开。而且,这也是C/c++程序通常可以轻松做到的。
在一些处理器和操作系统上,很容易生成代码并执行它,并且可以在运行时修改现有代码。这也会在反编译代码时造成歧义。C/c++程序通常也可以这样做。
EDIT:另外,一些cpu对同一条指令有多种不同的编码。例如,x86 cpu有2条指令mov reg, reg/mem
和mov reg/mem, reg
。这些允许您在寄存器和内存位置之间移动数据(在任何方向上)以及在两个寄存器之间移动数据。这两个指令都可以用来在两个寄存器之间传输数据,但是它们有不同的编码。如果程序以某种方式依赖于特定的编码(例如,为了通过校验和验证其完整性的目的),那么从mov eax, ebx
这样的反汇编中,您将无法告诉它最初是两个mov
指令中的哪一个,因此,如果您试图重新组装反汇编,您可能会破坏程序。
您可以使用调试器来调试带有或不带有调试/符号信息的程序。这些信息只会使人们更容易导航代码和数据,因为许多(但不一定是全部)例程和变量可以使用它们的名称和类型来标识和显示,而不仅仅是原始地址和原始无类型数据。
我猜各种字节码在它们能做的事情上不那么模棱两可,也更受限制,这使得反编译它们更容易。
- 如何修复sfml c++代码编译错误
- 尝试用java代码编译和运行c++代码
- 此代码编译良好,但文件未创建?请指出错误
- 为什么我的 BaseClass:Method 代码编译(带有单冒号)?
- 代码编译没有任何输出,入门程序
- 通过Python Distutils(用于Python C扩展)使用可重定位的设备代码编译CUDA代码
- 代码编译但不起作用!cmd窗口只是理想和理想,但什么也没发生
- 无法使用 g++ 使用C++代码编译 C 库
- 如何在Ubuntu中使用Visual Studio代码编译C++代码
- 推力+提升代码编译错误
- C++代码编译,但在 Zorin OS 上运行时显示错误
- 如何在使用模板时将 CPP 代码编译到库文件中
- 是否可以将Visual Studio 2017将C 代码编译到EXE以外的文件类型中
- 使用 Visual Studio for C++ 代码编译错误
- 使用 Android Studio 使用本机代码编译 apk 时,如何在链接处删除 libgnustl_static.
- 使用 Emscripten 将 OpenCV 代码编译C++ Javascript
- 将C 代码编译到独立应用程序.App
- 为什么此代码编译 (C++11) 而没有类型不匹配错误
- 重用编译器前端的结果,以加快多个配置/平台的C++代码编译
- 如何将C++11代码编译为网络汇编