我不认为有任何可靠的方法来做到这一点。机器代码格式非常复杂,比汇编文件更复杂。它不是真的可能采取编译的二进制(例如,在ELF格式),并产生一个源汇编程序,将编译为相同(或相似足够)的二进制。为了理解差异,比较GCC编译直接到汇编程序(gcc -S)的输出和objdump在可执行文件(objdump -D)的输出。
有两个主要的复杂性,我可以想到。首先,机器代码本身不是与汇编代码的1对1对应,因为像指针偏移的东西。
例如,考虑C语言的Hello world:
int main()
{
printf("Hello, world!\n");
return 0;
}
这将编译为x86汇编代码:
.LC0:
.string "hello"
.text
movl $.LC0, %eax
movl %eax, (%esp)
call printf
其中.LCO是命名常量,printf是共享库符号表中的符号。与objdump的输出进行比较:
80483cd: b8 b0 84 04 08 mov $0x80484b0,%eax
80483d2: 89 04 24 mov %eax,(%esp)
80483d5: e8 1a ff ff ff call 80482f4
首先,常量.LC0现在只是内存中某些随机偏移 – 很难创建一个在正确位置包含此常量的汇编源文件,因为汇编器和链接器可以自由选择这些常量的位置。
其次,我不完全确定这一点(它取决于诸如位置无关代码之类的事情),但我相信printf的引用实际上并没有编码在那个代码的指针地址,但ELF头包含一个查找表,其在运行时动态地替换其地址。因此,反汇编代码不完全对应于源汇编代码。
总而言之,源程序集具有符号,而编译的机器代码具有难以逆转的地址。
第二个主要复杂性是汇编源文件不能包含原始ELF文件头中存在的所有信息,例如要动态链接的库以及原始编译器放置的其他元数据。这将是很难重建这。
像我说的,有可能一个特殊的工具可以操纵所有这些信息,但是不可能简单地生成可以重新组装回可执行文件的汇编代码。
如果你有兴趣修改可执行文件的一小部分,我建议一个更微妙的方法,而不是重新编译整个应用程序。使用objdump获取您感兴趣的函数的汇编代码。手动将它转换为“源汇编语法”(这里,我希望有一个工具,实际上生成反汇编在与输入相同的语法) ,并根据需要修改它。当你完成后,重新编译那些函数,并使用objdump找出修改后的程序的机器代码。然后,使用十六进制编辑器将新机器代码手动粘贴到原始程序的相应部分的顶部,注意新代码与旧代码的字节数完全相同(或者所有偏移都是错误的)。如果新代码较短,可以使用NOP指令将其填充。如果它更长,你可能会有麻烦,并可能需要创建新的功能,并调用它们。