挂钩函数时,为什么覆盖前5个字节无关紧要?

时间:2016-08-06 21:40:36

标签: assembly x86 hook machine-code

当挂钩函数需要覆盖原始函数的5个字节时,堆栈帧的初始设置无关紧要,因为签名和调用约定与替换函数的原始函数相同,但是我没有得到的是你要覆盖原始函数的前几个字节。 55(推ebp)8B EC(mov ebp,esp),你还需要2个?为什么覆盖那些对函数至关重要的提取2字节无关紧要?

00440112                         ; int __cdecl function(int, FILE *)
.text:00440112                         var_410         = byte ptr -410h
.text:00440112                         var_310         = byte ptr -310h
.text:00440112                         var_210         = byte ptr -210h
.text:00440112                         var_110         = byte ptr -110h
.text:00440112                         var_10          = byte ptr -10h
.text:00440112                         var_4           = dword ptr -4
.text:00440112                         arg_0           = dword ptr  8
.text:00440112                         arg_4           = dword ptr  0Ch
.text:00440112
.text:00440112 55                                      push    ebp
.text:00440113 8B EC                                   mov     ebp, esp
.text:00440115 81 EC 10 04 00 00                       sub     esp, 410h
.text:0044011B 53                                      push    ebx
.text:0044011C 56                                      push    esi
.text:0044011D 8B 75 0C                                mov     esi, [ebp+arg_4]
.text:00440120 80 7E 04 00                             cmp     byte ptr [esi+4], 0
.text:00440124 57                                      push    edi
.text:00440125 C7 86 10 01 00 00 63 00+                mov     dword ptr [esi+110h], 63h
.text:0044012F 74 0F                                   jz      short loc_440140
.text:00440131 83 3D 7A 4E 4B 00 00                    cmp     dword_4B4E7A, 0
.text:00440138 7F 06                                   jg      short loc_440140
.text:0044013A 83 65 FC 00                             and     [ebp+var_4], 0
.text:0044013E EB 07                                   jmp     short loc_440147

参加上面的组装。 'E9 ?? ?? ?? ??”将取代'55 8B EC 81 EC'(?? ?? ?? ?? ??跳转到的函数的地址),所以我看到它的方式是在堆栈上为本地变量分配0x410不会发生当被调用的新函数跳回到0x44011B处的原始函数时;为什么这不重要?我不明白我错过了什么。

如果要重现允许使用此方法挂钩函数的功能代码,请参阅MyUsername112358的答案HERE

1 个答案:

答案 0 :(得分:2)

正如您所注意到的,如果您打算能够执行原始代码,则无法在5字节边界处切断。您将不得不反汇编并复制涵盖前5个字节的指令。

您可以查看我的ia32hook,该OllyDbg使用disassembler' s The relevant snippet来查找切断位置。 Microsoft Detours

#include "ollydisasm/disasm.h"

static inline unsigned long CleanBiteOff(const unsigned char *ptr, size_t amount)
{
    static t_disasm disasm;
    unsigned long size = 0;
    do {size += Disasm(ptr+size, 16, ptr+size, &disasm, DISASM_SIZE);} while(size < amount);
    return size;
}

返回的size是您需要复制的字节数。在蹦床的末尾,你复制这些字节会跳回(char*)func+size,一切都很好。

您链接的答案,也没有刷新指令缓存,如果指令指针恰好指向您即将修补的字节,则会出现严重问题。您应该暂停线程,并声明eip没有指向您要修补的字节。

如果这不是出于学习目的,请考虑使用Remote Debugging之类的解决方案。