如何反汇编,修改,然后重新组装一个Linux可执行文件?
反正有这个可以做的吗? 我已经使用objdump,但是不会产生汇编输出,我知道任何汇编程序都会接受这个汇编输出。 我希望能够更改可执行文件中的指令,然后再进行testing。
我不认为有任何可靠的方法来做到这一点。 机器码格式非常复杂,比assembly文件更复杂。 编译的二进制文件(比如ELF格式文件)并不是真的有可能产生一个源代码汇编程序,它将编译成相同的(或类似的)二进制文件。 为了理解差异,将GCC编译直接输出到汇编器( gcc -S
)的输出与objdump在可执行文件( objdump -D
)上的输出进行比较。
我可以想到两个主要的并发症。 首先,由于指针偏移等原因,机器码本身并不是与汇编代码一一对应的。
例如,考虑C代码到Hello世界:
int main() { printf("Hello, world!\n"); return 0; }
这编译为x86汇编代码:
.LC0: .string "hello" .text <snip> 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 <printf@plt>
首先,常量.LC0现在只是内存中的某个随机偏移量 – 在正确的位置创build一个包含这个常量的汇编源文件是很困难的,因为汇编器和链接器可以自由select这些常量的位置。
其次,我不完全确定(这取决于位置独立的代码),但我相信对printf的引用实际上并没有在那里的代码中的指针地址编码,但ELF头包含一个查找表,它在运行时dynamic地replace它的地址。 因此,反汇编代码并不完全对应源代码汇编代码。
总之,源程序集具有符号,而编译的机器代码具有难以反转的地址 。
第二个主要的复杂情况是程序集源文件不能包含原始ELF文件头中的所有信息,比如要dynamic链接哪些库以及原始编译器放在那里的其他元数据。 这将很难重build。
就像我所说的那样,一个特殊的工具可能会操纵所有这些信息,但是不太可能只是简单地生成汇编代码,而这些汇编代码可以被重新组装回可执行文件。
如果您只想修改可执行文件的一小部分,我build议比重新编译整个应用程序更微妙的方法。 使用objdump来获取你感兴趣的函数的汇编代码。手工将它转换为“源代码汇编语法”(在这里,我希望有一个工具实际上产生与input相同语法的反汇编) ,并根据需要进行修改。 完成后,重新编译这些函数并使用objdump来找出修改过的程序的机器码。 然后,使用hex编辑器手动将新的机器代码粘贴到原始程序相应部分的顶部,注意新代码的字节数与旧代码的字节数完全相同(否则所有偏移量都会错误)。 如果新代码较短,则可以使用NOP指令进行填充。 如果时间较长,则可能会遇到麻烦,可能需要创build新的function并调用它们。
为了改变二进制程序集内部的代码,通常有三种方法可以做到这一点。
- 如果它只是一个常量这样简单的事情,那么你只需用hex编辑器来改变位置。 假设你可以find它开始。
- 如果您需要更改代码,则使用LD_PRELOAD覆盖程序中的某些function。 如果函数不在函数表中,那不起作用。
- 在你想要修复的函数中join代码,直接跳转到你通过LD_PRELOAD加载的函数,然后跳回到相同的位置(这是上述两者的组合)
当然只有第二个人会工作,如果大会做任何一种自我完整性检查。
编辑:如果它不是很明显,那么玩二进制程序集是非常高级的开发人员的东西,你会很难在这里问它,除非它是真正具体的事情你问。
从技术angular度来看,@ mgiuca正确地解决了这个问题。 事实上,将可执行程序拆分为易于重新编译的汇编源代码并不是一件容易的事情。
为了增加一些讨论的内容,有一些技术/工具可能有趣的探索,尽pipe它们在技术上是复杂的。
- 静态/dynamic仪器 。 这种技术需要分析可执行格式,为特定目的插入/删除/replace特定的汇编指令,修复对可执行文件中variables/函数的所有引用,并发出新的修改后的可执行文件。 我所知道的一些工具是: PIN , 劫机者 , PEBIL , DynamoRIO 。 考虑到将这些工具configuration为与其devise目的不同的目的可能会非常棘手,并且需要了解可执行格式和指令集。
- 完全可执行的反编译 。 这种技术试图从可执行文件重build一个完整的汇编源代码。 你可能想看看在线反汇编 ,试图做的工作。 你失去了有关不同来源模块和可能的函数/variables名称的信息。
- 可重新编程的反编译 。 这种技术试图从可执行文件中提取更多信息,查看编译器指纹 (即由已知编译器生成的代码模式)和其他确定性的东西。 主要目标是从可执行文件重build更高级别的源代码,如C源代码。 这有时能够重新获得有关函数/variables名称的信息。 考虑用
-g
编译源代码通常会提供更好的结果。 你可能想试试Retargetable Decompiler 。
其中大部分来自脆弱性评估和执行分析研究领域。 他们是复杂的技术,通常这些工具不能立即使用。 尽pipe如此,它们在尝试对某些软件进行反向工程时提供了非常宝贵的帮助
另一件你可能有兴趣做的事情是:
- 二进制仪器 – 改变现有的代码
如果有兴趣的话,可以看看:Pin,Valgrind(或者这样做的项目:NaCl– Google的Native Client,也许是QEmu。)
你可以在ptrace(换句话说,像gdb这样的debugging器)的监督下运行这个可执行文件,这样就可以随时控制执行,而不需要修改实际的文件。 当然,需要通常的编辑技巧,比如find你想影响的特定指令在可执行文件中。