一尘不染

如何反汇编,修改然后重新组装Linux可执行文件?

linux

无论如何,这可以做到吗?我使用过objdump,但是不会产生我所知道的任何汇编程序都会接受的汇编输出。我希望能够在可执行文件中更改指令,然后再对其进行测试。


阅读 757

收藏
2020-06-02

共1个答案

一尘不染

我认为没有任何可靠的方法可以做到这一点。机器代码格式非常复杂,比汇编文件更复杂。实际上不可能采用已编译的二进制文件(例如ELF格式)并生成可汇编为相同(或相似程度)二进制文件的源汇编程序。为了了解它们之间的差异,请将直接编译到汇编器(gcc -S)的GCC编译输出与可执行文件(objdump -D)上的objdump输出进行比较。

我可以想到两个主要的并发症。首先,由于指针偏移之类的原因,机器代码本身与汇编代码不是一一对应的。

例如,考虑到Hello world的C代码:

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现在只是内存中某个随机偏移量-很难在正确的位置创建一个包含此常量的程序集源文件,因为汇编器和链接器可以自由选择这些常量的位置。

其次,我对此不是很确定(这取决于位置无关代码之类的东西),但是我相信对printf的引用实际上并没有在该代码中的指针地址处进行编码,但是ELF头包含一个查找表,该表在运行时动态替换其地址。因此,反汇编代码与源汇编代码并不完全对应。

总而言之,源程序集带有 符号, 而编译后的机器代码具有难以逆转的 地址

第二个主要的麻烦是,程序集源文件不能包含原始ELF文件头中存在的所有信息,例如要动态链接的库以及原始编译器放置在其中的其他元数据。很难重建它。

就像我说的那样,有可能一种特殊的工具可以操纵所有这些信息,但是不太可能会简单地产生可以重新组装回可执行文件的汇编代码。

如果您只想修改可执行文件的一小部分,我建议您使用一种比重新编译整个应用程序更微妙的方法。使用objdump来获取您感兴趣的函数的汇编代码。将其手动转换为“源汇编语法”(在这里,我希望有一个工具能够以与输入相同的语法实际产生反汇编)
,然后根据需要对其进行修改。完成后,仅重新编译这些函数,然后使用objdump找出修改后的程序的机器代码。然后,使用十六进制编辑器将新的机器代码手动粘贴到原始程序的相应部分的顶部,请注意新代码与旧代码的字节数完全相同(否则所有偏移量都是错误的)。如果新代码较短,您可以按照NOP指令进行填充。如果更长,则可能会遇到麻烦,可能必须创建新函数并改为调用它们。

2020-06-02