相对于由C/C++编译器生成的机器码,Java和Python字节码相对容易反编译。
我找不到令人信服的答案,为什么-g选项中的信息对于反编译来说是不足够的,但对于调试却足够了呢? Python/Java字节码中包含的额外信息是什么,使得反编译变得容易?
相对于由C/C++编译器生成的机器码,Java和Python字节码相对容易反编译。
我找不到令人信服的答案,为什么-g选项中的信息对于反编译来说是不足够的,但对于调试却足够了呢? Python/Java字节码中包含的额外信息是什么,使得反编译变得容易?
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++程序也经常可以做到这一点。
编辑:此外,一些CPU对于同一条指令可能有多种不同的编码方式。例如,x86 CPU有两个指令mov reg, reg/mem
和mov reg/mem, reg
。这些指令允许您在寄存器和内存位置之间(双向)以及在两个寄存器之间传输数据。这两个指令都可以用于在两个寄存器之间传输数据,但它们具有不同的编码方式。如果程序某种程度上依赖于特定的编码方式(例如,为了通过校验和验证其完整性),那么从反汇编中像mov eax, ebx
这样的代码中,您将无法确定最初是哪一个mov
指令,因此,如果您尝试重新组装反汇编代码,则可能会破坏程序。
您可以使用调试器来调试带有或不带有调试/符号信息的程序。这些信息只是使人类更容易浏览代码和数据,因为许多(但不一定全部)例程和变量可以使用它们的名称和类型进行识别和显示,而不仅仅是原始地址和原始类型数据。
我猜各种字节码更少歧义且更受限制,这就使得反编译更容易。