1. 程式人生 > 實用技巧 >《逆向工程核心原理》——API HOOK

《逆向工程核心原理》——API HOOK

編寫dll處理hook邏輯,注入到目標程序,實現api hook。

Windows10 notepad,通過hookkernel32.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效果: