10

我正在尝试编写一个 exe 打包程序/保护程序,以此来了解更多关于汇编程序、c++ 以及 PE 文件如何工作的信息。我目前已经让它工作了,所以包含 EP 的部分与一个密钥进行异或,并创建了一个包含我的解密代码的新部分。一切都很好,除非我在解密后尝试 JMP 到原始 EP。

基本上我这样做:

DWORD originalEntryPoint = optionalHeader->AddressOfEntryPoint;
// -- snip -- //
    crypted.put(0xE9);
 crypted.write((char*)&orginalEntryPoint, sizeof(DWORD)); 

但 ollydbg 并没有跳转到入口点,而是显示这段代码反汇编为:

00404030   .-E9 00100000    JMP 00405035 ; should be 00401000 =[

当我尝试在 olly 中手动更改它时,新的操作码显示为

00404030    -E9 CBCFFFFF    JMP crypted.00401000

0xCBCFFFFF 是从哪里来的?我将如何从 C++ 端生成它?

4

3 回答 3

19

你可以使用:

push DESTINATION_VA
ret

或者

mov eax,DESTINATION_VA
jmp eax

像这样使用相对 E9 jmp 编码:

CURRENT_RVA: jmp (DESTINATION_RVA - CURRENT_RVA - 5 [sizeof(E9 xx xx xx xx)])

如果您有 VA 地址并且图像未重新定位,则 push + ret 是最佳解决方案

于 2010-01-12T14:28:30.467 回答
7

我认为这E9是相对跳转的操作码:它的操作数指定要跳转的相对距离,从下一条指令的开始加减。

如果您希望操作数指定绝对地址,则需要不同的操作码。

于 2009-10-09T21:47:54.687 回答
6

绝对间接跳转的操作码是 FF + 4 字节地址。这最常用于存储在数据中的地址的跳转表。

绝对地址在未加载到预期地址时确实需要重定位,因此通常首选相对地址。相对跳转的代码也小了 2 个字节。

英特尔优化手册指出,cpu 期望 call 和 ret 成对使用,因此答案 2 中建议的没有调用的 ret 会导致他们所谓的“性能损失”。

此外,如果代码没有加载到编译器假定的相同地址,则 ret 可能会使程序崩溃。计算相对地址会更安全。

于 2011-04-10T02:39:31.557 回答