Hook API这个方法,可以在自己的程序中,改变甚至重写Windows的API,或者在其他DLL中的函数。
实际并没有改写,只是修改调用为自己的函数而已。
这个技术用处多多,比如写游戏作弊器和间谍程序,检测程序对API的调用参数等等。
参考了这两个例子,第一个包含演示程序:
XXXXXXXXXXXXXXXXXXXt/friendan/article/details/12222651XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/blog/static/181485234201241310454415/实际上就是修改了函数入口的汇编代码,跳转到自己的函数里,自己的函数可以做些坏事然后再跳到原来的函数里去23333
首先找到要修改的函数的入口地址,然后保存下入口处的二进制代码(长度根据系统架构和程序而定)
开hook的时候需要修改函数的入口内容,32位和64位的方法不太一样:
32位用的是jmp指令,以当前地址为参考,跳转到指定的地址,就是自己函数的地址-原来函数的地址-5(5是指令长度,0xe9是jmp,后面4字节是相对地址)
不过在64位下,这个就不适用了,jmp能跳转的地址范围有限,在64位情况下很可能跳不到,于是就需要改成这样
mov rax,XX XX XX XX XX XX XX XX
PUSH RAX
RET
那堆xx就是64位的函数地址,这里写自己函数的地址。对应的十六进制码为48 B8 XX XX XX XX XX XX XX XX 50 C3,一共12字节
不知道为啥,网上涉及Hook API的程序都喜欢内嵌汇编,但是我觉得这样很困惑,降低可读性,于是我用memset等代替了那些汇编
还有64位环境下C内嵌汇编不方便,需要asm文件
关闭hook的时候把保存的原来函数的入口处的代码写回去就好了
有一点需要注意,在自己函数中需要调用原来的被修改的函数时,需要先关闭hook,不然就变成递归了,死循环,程序就炸了
下面是完整代码,支持32位和64位,自动切换
<code class="lang-cpp">typedef struct APIHOOK *LPAPIHOOK;
LPAPIHOOK APIHook_CreateHook(HANDLE hProc, FARPROC oldFunc, void* newFunc);
void APIHook_DestoryHook(LPAPIHOOK hook);
void APIHook_TurnOnHook(LPAPIHOOK hook);
void APIHook_TurnOffHook(LPAPIHOOK hook);
typedef struct APIHOOK {
#ifdef _AMD64_
BYTE OldCode[12];
BYTE NewCode[12];
#else
BYTE OldCode[5];
BYTE NewCode[5];
#endif
FARPROC oldProc;
HANDLE hP;
bool status;
}APIHOOK;
void APIHook_TurnOnHook(LPAPIHOOK hook) {
if (hook == NULL)
return;
DWORD dwTemp = 0;
DWORD dwOldProtect;
#ifdef _AMD64_
VirtualProtectEx(hook->hP, hook->oldProc, 12, PAGE_READWRITE, &dwOldProtect);
WriteProcessMemory(hook->hP, hook->oldProc, hook->NewCode, 12, 0);
VirtualProtectEx(hook->hP, hook->oldProc, 12, dwOldProtect, &dwTemp);
#else
VirtualProtectEx(hook->hP, hook->oldProc, 5, PAGE_READWRITE, &dwOldProtect);
WriteProcessMemory(hook->hP, hook->oldProc, hook->NewCode, 5, 0);
VirtualProtectEx(hook->hP, hook->oldProc, 5, dwOldProtect, &dwTemp);
#endif
hook->status = true;
}
void APIHook_TurnOffHook(LPAPIHOOK hook) {
if (hook == NULL)
return;
DWORD dwTemp = 0;
DWORD dwOldProtect;
#ifdef _AMD64_
VirtualProtectEx(hook->hP, hook->oldProc, 12, PAGE_READWRITE, &dwOldProtect);
WriteProcessMemory(hook->hP, hook->oldProc, hook->OldCode, 12, 0);
VirtualProtectEx(hook->hP, hook->oldProc, 12, dwOldProtect, &dwTemp);
#else
VirtualProtectEx(hook->hP, hook->oldProc, 5, PAGE_READWRITE, &dwOldProtect);
WriteProcessMemory(hook->hP, hook->oldProc, hook->OldCode, 5, 0);
VirtualProtectEx(hook->hP, hook->oldProc, 5, dwOldProtect, &dwTemp);
#endif
hook->status = false;
}
LPAPIHOOK APIHook_CreateHook(HANDLE hProc, FARPROC oldFunc, void* newFunc) {
LPAPIHOOK ret = (LPAPIHOOK)malloc(sizeof(APIHOOK));
ret->hP = hProc;
ret->oldProc = oldFunc;
if (ret->oldProc == NULL)
{
return NULL;
}
#ifdef _AMD64_
memcpy_s(ret->OldCode, 12, (BYTE*)(ret->oldProc), 12);
ret->NewCode[0] = 0x48;
ret->NewCode[1] = 0xB8;
ULONG64 addr = (ULONG64)newFunc;
memcpy_s(ret->NewCode + 2, 8, &addr, 8);
ret->NewCode[10] = 0x50;
ret->NewCode[11] = 0xC3;
#else
memcpy_s(ret->OldCode, 5, (BYTE*)(ret->oldProc), 5);
ret->NewCode[0] = 0xe9; //jmp
ULONG32 aNew = (ULONG32)newFunc - (ULONG32)(void*)(ret->oldProc) - 5;
memcpy_s(ret->NewCode + 1, 4, &aNew, 4);
#endif
ret->status = false;
return ret;
}
void APIHook_DestoryHook(LPAPIHOOK hook) {
if (hook == NULL)
return;
if (hook->status)
APIHook_TurnOffHook(hook);
free(hook);
}</code>
APIHook_CreateHook用来创造一个Hook, hProc是要被Hook的进程的句柄,这里是当前进程的句柄, oldFunc是要被修改的函数的地址,newFunc是新函数的指针
newFunc的声明要和原来函数一样,这点需要特别注意,
比如下面替换TrackPopupMenuEx的例子:
<code class="lang-cpp">BOOL WINAPI MyTrackPopupMenuEx(HMENU hMenu, UINT uFlags, int x, int y, HWND hwnd, LPTPMPARAMS lptpm)
{
APIHook_TurnOffHook(apiHook_TPM);
//Do something here
BOOL ret = TrackPopupMenuEx(hMenu, uFlags, x, y, hwnd, lptpm);
//Do something here
APIHook_TurnOnHook(apiHook_TPM);
return ret;
}
LPAPIHOOK apiHook_TPM;
//Create a api hook
HMODULE hmod = LoadLibrary(TEXT("User32.dll"));
apiHook_TPM = APIHook_CreateHook(OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId()),
GetProcAddress(hmod, "TrackPopupMenuEx"),
MyTrackPopupMenuEx);
APIHook_TurnOnHook(apiHook_TPM);
//Dont forget APIHook_DestoryHook(apiHook_TPM);</code>
APIHook_TurnOffHook关闭Hook
APIHook_TurnOnHook开启Hook
APIHook_DestoryHook关闭并释放Hook所占的资源
这个例子中的代码只能修改自己程序也就是当前进程中的API调用,跨进程则无效,如果需要修改其他程序的API调用,需要先进行线程注入,之后我会贴代码
200字以内,仅用于支线交流,主线讨论请采用回复功能。