C 挂钩-热插接
我正在尝试钩住Windows API函数FindWindowA()。我成功地用下面的代码完成了它,而没有“热补丁”:我已经覆盖了函数开头的字节。调用myHook(),调用FindWindowA()时会显示一个消息框 user32.dll已启用热修补,我希望在实际函数之前覆盖NOPs,而不是覆盖函数本身。但是,当我将hotpatching设置为TRUE时,下面的代码将不起作用。当FindWindowA()被执行时,它什么也不做C 挂钩-热插接,c,windows,assembly,hook,hotpatching,C,Windows,Assembly,Hook,Hotpatching,我正在尝试钩住Windows API函数FindWindowA()。我成功地用下面的代码完成了它,而没有“热补丁”:我已经覆盖了函数开头的字节。调用myHook(),调用FindWindowA()时会显示一个消息框 user32.dll已启用热修补,我希望在实际函数之前覆盖NOPs,而不是覆盖函数本身。但是,当我将hotpatching设置为TRUE时,下面的代码将不起作用。当FindWindowA()被执行时,它什么也不做 #include <stdio.h> #include &
#include <stdio.h>
#include <windows.h>
void myHook()
{
MessageBoxA(NULL, "Hooked", "Hook", MB_ICONINFORMATION);
}
int main(int argc, char *argv[])
{
BOOLEAN hotpatching = FALSE;
LPVOID fwAddress = GetProcAddress(GetModuleHandleA("user32.dll"), "FindWindowA");
LPVOID fwHotpatchingAddress = (LPVOID)((DWORD)fwAddress - 5);
LPVOID myHookAddress = &myHook;
DWORD jmpOffset = (DWORD)&myHook - (DWORD)(!hotpatching ? fwAddress : fwHotpatchingAddress) - 5; // -5 because "JMP offset" = 5 bytes (1 + 4)
printf("fwAddress: %X\n", fwAddress);
printf("fwHotpatchingAddress: %X\n", fwHotpatchingAddress);
printf("myHookAddress: %X\n", myHookAddress);
printf("jmpOffset: %X\n", jmpOffset);
printf("Ready?\n\n");
getchar();
char JMP[1] = {0xE9};
char RETN[1] = {0xC3};
LPVOID offset0 = NULL;
LPVOID offset1 = NULL;
LPVOID offset2 = NULL;
if (!hotpatching)
offset0 = fwAddress;
else
offset0 = fwHotpatchingAddress;
offset1 = (LPVOID)((DWORD)offset0 + 1);
offset2 = (LPVOID)((DWORD)offset1 + 4);
DWORD oldProtect = 0;
VirtualProtect(offset0, 6, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(fwAddress, JMP, 1);
memcpy(offset1, &jmpOffset, 4);
memcpy(offset2, RETN, 1);
VirtualProtect(offset0, 6, oldProtect, &oldProtect);
printf("FindWindowA() Patched");
getchar();
FindWindowA(NULL, "Test");
getchar();
return 0;
}
#包括
#包括
void myHook()
{
MessageBoxA(空,“钩住”,“钩住”,MB_图标信息);
}
int main(int argc,char*argv[])
{
布尔热修补=假;
LPVOID fwAddress=GetProcAddress(GetModuleHandleA(“user32.dll”),“FindWindowA”);
LPVOID-fwHotpatchingAddress=(LPVOID)((DWORD)fwAddress-5);
LPVOID myHookAddress=&myHook;
DWORD jmpOffset=(DWORD)和myHook-(DWORD)(!hotpatching?fwAddress:fwatpatchingaddress)-5;//-5,因为“JMP偏移量”=5字节(1+4)
printf(“fwAddress:%X\n”,fwAddress);
printf(“fwHotpatchingAddress:%X\n”,fwHotpatchingAddress);
printf(“myHookAddress:%X\n”,myHookAddress);
printf(“jmpOffset:%X\n”,jmpOffset);
printf(“准备好了吗?\n\n”);
getchar();
char JMP[1]={0xE9};
char-RETN[1]={0xC3};
LPVOID offset0=NULL;
LPVOID offset1=NULL;
LPVOID offset2=NULL;
如果(!热补丁)
offset0=地址;
其他的
偏移量0=fwHotpatchingAddress;
偏移量1=(LPVOID)((DWORD)偏移量0+1);
偏移量2=(LPVOID)((DWORD)偏移量1+4);
DWORD-oldProtect=0;
虚拟保护(偏移量0、6、页面执行、读写和旧保护);
memcpy(fwAddress,JMP,1);
memcpy(抵销1和jmpOffset,4);
memcpy(抵销2,RETN,1);
虚拟保护(偏移量0、6、oldProtect和oldProtect);
printf(“FindWindowA()补丁”);
getchar();
FindWindowA(空,“测试”);
getchar();
返回0;
}
你能告诉我怎么了吗
谢谢。启用热修补的可执行映像由编译器和链接器准备,以允许在使用时替换映像。将应用以下两个更改(x86):
mov edi,edi
()(2) 768C8D66 90 nop
768C8D67 90 nop
768C8D68 90 nop
768C8D69 90 nop
768C8D6A 90 nop
(1) 768C8D6B 8B FF mov edi,edi
(3) 768C8D6D 55 push ebp
768C8D6E 8B EC mov ebp,esp
(1)
用2字节no-op指定函数入口点。(2)
是链接器提供的填充,而(3)
是非平凡函数实现的开始
要钩住一个函数,您必须通过跳转到钩子函数jmp myHook
来覆盖(2)
,并通过用相对跳转jmp$-5
替换(1)
来访问此代码
钩子函数必须使堆栈保持一致状态。它应该声明为防止编译器生成函数prolog和epilog代码。最后一条指令必须按照钩子函数的调用约定执行堆栈清理,或者跳回由
(3)
指定的地址处的钩子函数。如果未对函数进行热修补,则无法对函数进行热修补。未执行函数入口点之前的5个NOP。它们只是为动态创建的JMP指令留出空间。要获得此代码,您必须在函数入口点用相对跳转覆盖2字节NOP(mov edi,edi
)。好的,我知道了!我覆盖NOP,但它们从未执行,因为它们在实际函数开始之前(mov edi,edi
)。我必须将mov-edi,edi
替换为向后跳转5个字节的JMP指令(或者7个字节,因为mov-edi,edi
有2个字节长)。非常感谢。