《逆向工程核心原理》——API HOOK
编写dll处理hook逻辑,注入到目标进程,实现api hook。
Windows10 notepad,通过hook kernel32.dll.WriteFile,实现小写字母转大写保存到文件。
hook前kernel32.dll.WriteFile入口:
kernel32.dll.WriteFile在调用时入口是条jmp指令
跳转后
hook时通过GetProcAddress得到的是jmp处的地址,在jmp指令周边有一些int 3指令,这些空间可以用来做一些跳转操作。
#include "pch.h" #include <tchar.h> #define DLLNAME "kernel32.dll" #define WRITEFILE "WriteFile" BYTE g_pOrgBytes[6] = { 0 }; FARPROC g_writefile = GetProcAddress(GetModuleHandleA(DLLNAME), WRITEFILE); //此函数用来将api前5个字节改为jmp xxxx BOOL hook_by_code(FARPROC pfnOrg, PROC pfnNew, PBYTE pOrgBytes) { DWORD dwOldProtect, dwAddress; BYTE pBuf[6] = { 0xE9,0,0,0,0, 0x90}; PBYTE pByte; pByte = (PBYTE)pfnOrg; if (pByte[0] == 0xE9)//若已被勾取,则返回False return FALSE; VirtualProtect((LPVOID)pfnOrg, 12, PAGE_EXECUTE_READWRITE, &dwOldProtect);//为了修改字节,先向内存添加“写”的属性 memcpy(pOrgBytes, pfnOrg, 6);//备份原有代码 dwAddress = (DWORD64)pfnNew - (DWORD64)pfnOrg - 5;//计算JMP地址 => XXXX = pfnNew - pfnOrg - 5 memcpy(&pBuf[1], &dwAddress, 4);//E9,剩下后面4个字节为跳转的地址 memcpy(pfnOrg, pBuf, 6);//复制指令,跳转到hook逻辑 memcpy(&pByte[6], pOrgBytes, 6);//后面的int 3指令进行修改,跳转到原api逻辑 pByte[8] -= 6;//修正跳转偏移 VirtualProtect((LPVOID)pfnOrg, 12, dwOldProtect, &dwOldProtect);//恢复内存属性 return TRUE; } BOOL unhook_by_code(FARPROC pFunc, PBYTE pOrgBytes) { DWORD dwOldProtect; PBYTE pByte; pByte = (PBYTE)pFunc; if (pByte[0] != 0xE9)//若已脱钩,则返回False return FALSE; VirtualProtect((LPVOID)pFunc, 6, PAGE_EXECUTE_READWRITE, &dwOldProtect);//向内存添加“写”的属性,为恢复原代码做准备 memcpy(pFunc, pOrgBytes, 6);//脱钩 VirtualProtect((LPVOID)pFunc, 6, dwOldProtect, &dwOldProtect);//恢复内存属性 return TRUE; } //WINBASEAPI //BOOL //WINAPI //WriteFile( // _In_ HANDLE hFile, // _In_reads_bytes_opt_(nNumberOfBytesToWrite) LPCVOID lpBuffer, // _In_ DWORD nNumberOfBytesToWrite, // _Out_opt_ LPDWORD lpNumberOfBytesWritten, // _Inout_opt_ LPOVERLAPPED lpOverlapped //); typedef BOOL(WINAPI* PFWriteFile)( _In_ HANDLE hFile, _In_reads_bytes_opt_(nNumberOfBytesToWrite) LPCVOID lpBuffer, _In_ DWORD nNumberOfBytesToWrite, _Out_opt_ LPDWORD lpNumberOfBytesWritten, _Inout_opt_ LPOVERLAPPED lpOverlapped ); BOOL WINAPI MyWriteFile( _In_ HANDLE hFile, _In_reads_bytes_opt_(nNumberOfBytesToWrite) LPCVOID lpBuffer, _In_ DWORD nNumberOfBytesToWrite, _Out_opt_ LPDWORD lpNumberOfBytesWritten, _Inout_opt_ LPOVERLAPPED lpOverlapped) { PBYTE ptr = (PBYTE)g_writefile; //unhook_by_code(g_writefile, g_pOrgBytes); BOOL ret = TRUE; char* pc = (char*)lpBuffer; while (*pc) { if (*pc >= 'a' && *pc <= 'z') { *pc -= 0x20; } pc++; } ret = ((PFWriteFile)(ptr+6))(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);//原入口偏移+6处是修正的原jmp指令 //hook_by_code(g_writefile, (PROC)MyWriteFile, g_pOrgBytes); return ret; } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: hook_by_code(g_writefile,(PROC)MyWriteFile, g_pOrgBytes); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: unhook_by_code(g_writefile,g_pOrgBytes); break; } return TRUE; }
hook效果: