当挂钩函数需要覆盖原始函数的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
答案 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之类的解决方案。