切换方法调用可执行文件

问题描述 投票:1回答:1

我想知道如何将调用切换为可执行文件中的另一个函数(在我的情况下为.exe)

这是我尝试使用的代码

#include <stdio.h>

void hello()
{
    printf("Hello world!");
}

void investigate()
{
    printf("Investigate all the things!");
}

main()
{
    hello();
}

一旦我编译了上面的代码(使用gcc)并从中获得了一个可执行文件(.exe),我想用“调查”切换“你好”调用。

- 编辑 -

我的环境:Windows 10(64位),mingw与gcc / g ++ 4.8.1

- 编辑2--

我对Linux的答案(任何Ubuntu或任何OpenSuse和任何架构)都很好,对我而言,拥有一个概念验证非常重要。

c assembly disassembly
1个回答
2
投票

假设编译器没有完全省略死函数,它没有内联函数并且调用不会通过PLT,一旦编译了可执行文件,就可以简单地编辑调用指令。

请注意,这两个函数必须是“兼容的”,其中兼容性的概念是模糊的,这意味着“新的必须至少满足编译器在调用旧函数时所做的相同假设”。 ABI当然是一个这样的假设,但它可能不是唯一的假设。

如果编译器省略了死函数,则无法切换函数(缺少一个)。

如果您的编译器内联了该调用,则无法切换该函数(没有调用)。您可以对抗编译器并在调用站点(在C源代码中)重写代码,这称为修补。

如果编译器使用PLT,则需要更改PLT存根使用的GOT条目。您可能需要记录一下自己,但更改链接过程实际上是PLT机制的一个特征。

如果您的编译器没有做任何事情,那么当没有启用优化时,这应该是这样一个简单源的情况,您可以使用objdump -d <file>查找调用站点和新函数的地址:

000000000040051d <hello>:
  40051d:   55                      push   %rbp
  40051e:   48 89 e5                mov    %rsp,%rbp
  400521:   bf f0 05 40 00          mov    $0x4005f0,%edi
  400526:   b8 00 00 00 00          mov    $0x0,%eax
  40052b:   e8 d0 fe ff ff          callq  400400 <printf@plt>
  400530:   5d                      pop    %rbp
  400531:   c3                      retq   

0000000000400532 <investigate>:
  400532:   55                      push   %rbp
  400533:   48 89 e5                mov    %rsp,%rbp
  400536:   bf fd 05 40 00          mov    $0x4005fd,%edi
  40053b:   b8 00 00 00 00          mov    $0x0,%eax
  400540:   e8 bb fe ff ff          callq  400400 <printf@plt>
  400545:   5d                      pop    %rbp
  400546:   c3                      retq   

0000000000400547 <main>:
  400547:   55                      push   %rbp
  400548:   48 89 e5                mov    %rsp,%rbp
  40054b:   b8 00 00 00 00          mov    $0x0,%eax
  400550:   e8 c8 ff ff ff          callq  40051d <hello>
  400555:   b8 00 00 00 00          mov    $0x0,%eax
  40055a:   5d                      pop    %rbp
  40055b:   c3                      retq   
  40055c:   0f 1f 40 00             nopl   0x0(%rax)

然后使用call指令结束后目标地址和地址之间的差异来更改call指令的立即值(只要两个地址的原点相同,则无关紧要)。

Target = 400532 
After the end of call = 400555
Difference = 400532 - 400555 = -23 = 0xFFFFFFDD

Change from:
400550: e8 c8 ff ff ff
to:
400550: e8 dd ff ff ff

请注意,immediates是小端。 您可以使用hexeditor编辑代码,在文件中查找偏移量,您可以使用精灵阅读器并对自己进行一些数学运算,或者只需搜索调用指令的字节(另请查看周围的字节数)呼吁确定)。

编辑后,二进制文件已修补:

 0000000000400532 <investigate>:
  400532:   55                      push   %rbp
  400533:   48 89 e5                mov    %rsp,%rbp
  400536:   bf fd 05 40 00          mov    $0x4005fd,%edi
  40053b:   b8 00 00 00 00          mov    $0x0,%eax
  400540:   e8 bb fe ff ff          callq  400400 <printf@plt>
  400545:   5d                      pop    %rbp
  400546:   c3                      retq   

0000000000400547 <main>:
  400547:   55                      push   %rbp
  400548:   48 89 e5                mov    %rsp,%rbp
  40054b:   b8 00 00 00 00          mov    $0x0,%eax
  400550:   e8 dd ff ff ff          callq  400532 <investigate>
  400555:   b8 00 00 00 00          mov    $0x0,%eax
  40055a:   5d                      pop    %rbp
  40055b:   c3                      retq   
© www.soinside.com 2019 - 2024. All rights reserved.