1. 程式人生 > 實用技巧 >《逆向工程核心原理》——通過除錯方式hook Api

《逆向工程核心原理》——通過除錯方式hook Api

1、附加目標程序,

2、CREATE_PROCESS_DEBUG_EVENT附加事件中將目標api處設定為0xcc(INT 3斷點)

3、EXCEPTION_DEBUG_EVENT異常事件中,首先判斷是否為EXCEPTION_BREAKPOINT 斷點異常,然後GetThreadContext、SetThreadContext 進行相關修改操作

#include <iostream>
#include "windows.h"
#include "stdio.h"

LPVOID g_pfWriteFile = NULL;
CREATE_PROCESS_DEBUG_INFO g_cpdi;
BYTE g_chINT3 
= 0xCC, g_chOrgByte = 0; BOOL OnCreateProcessDebugEvent(LPDEBUG_EVENT pde) { g_pfWriteFile = GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile");//或取WriteFile的API地址(其實獲取的是除錯者的地址,但是沒有影響) printf("g_pfWriteFile(0x%08X)\n ", g_pfWriteFile);//g_pfWriteFile(1990541344) 76a54020 memcpy(&g_cpdi, &pde->u.CreateProcessInfo, sizeof
(CREATE_PROCESS_DEBUG_INFO)); ReadProcessMemory(g_cpdi.hProcess, g_pfWriteFile, &g_chOrgByte, sizeof(BYTE), NULL);//g_cpdi.hProcess是被除錯程序的控制代碼,g_pfWriteFile是WriteFile API的地址 ,此函式讀取api第一個位元組,儲存到g_chOrgByte中 WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile, &g_chINT3, sizeof
(BYTE), NULL); //以上兩個函式對除錯程序進行讀寫, return TRUE; } BOOL OnExceptionDebugEvent(LPDEBUG_EVENT pde) { CONTEXT ctx; PBYTE lpBuffer = NULL; DWORD64 dwNumOfBytesToWrite, dwAddrOfBuffer;//x64指標8位元組 DWORD i; PEXCEPTION_RECORD per = &pde->u.Exception.ExceptionRecord; if (EXCEPTION_BREAKPOINT == per->ExceptionCode) { //是斷點異常時 if (g_pfWriteFile == per->ExceptionAddress) { //斷點地址為writefile 的api地址時候 WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile, &g_chOrgByte, sizeof(BYTE), NULL);//恢復api第一個位元組(unhook) //ctx.ContextFlags = CONTEXT_CONTROL; //或取執行緒上下文 ctx.ContextFlags = CONTEXT_ALL; //獲取執行緒上下文,CONTEXT_CONTROL缺少一些暫存器的值,這裡使用CONTEXT_ALL GetThreadContext(g_cpdi.hThread, &ctx); //printf("0x%08X\n", GetLastError()); //x64下系統api使用fastcall呼叫約定 //ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.Esp + 0x8), // &dwAddrOfBuffer, sizeof(DWORD), NULL);//獲取api的第二個引數值 //ReadProcessMemory(g_cpdi.hProcess, (LPVOID)(ctx.Esp + 0xC), // &dwNumOfBytesToWrite, sizeof(DWORD), NULL);//獲取取api的第三個引數值 dwAddrOfBuffer = ctx.Rdx;//WriteFile第2個引數 緩衝區:lpBuffer dwNumOfBytesToWrite = ctx.R8;//WriteFile第3個引數 緩衝區大小:nNumberOfBytesToWrite lpBuffer = (PBYTE)malloc(dwNumOfBytesToWrite + 1);//分配臨時緩衝區 memset(lpBuffer, 0, dwNumOfBytesToWrite + 1); ReadProcessMemory(g_cpdi.hProcess, (LPVOID)dwAddrOfBuffer, lpBuffer, dwNumOfBytesToWrite, NULL);//將第三個引數值複製到臨時緩衝區 printf("\n### original string ###\n%s\n", lpBuffer); for (i = 0; i < dwNumOfBytesToWrite; i++) { //將小寫字母轉換為大寫字母 if (0x61 <= lpBuffer[i] && lpBuffer[i] <= 0x7A) lpBuffer[i] -= 0x20; } printf("\n### converted string ###\n%s\n", lpBuffer); WriteProcessMemory(g_cpdi.hProcess, (LPVOID)dwAddrOfBuffer, lpBuffer, dwNumOfBytesToWrite, NULL);//將變換後的緩衝區複製到writefile緩衝區 free(lpBuffer);//釋放臨時緩衝區 //將執行緒上下文的EIP更改為writefile首地址(當前為writefile()+1位置,int3命令之後) ctx.Rip = (DWORD64)g_pfWriteFile;//x64指標8位元組 SetThreadContext(g_cpdi.hThread, &ctx); // 執行被除錯程序 ContinueDebugEvent(pde->dwProcessId, pde->dwThreadId, DBG_CONTINUE);//執行被除錯程序 Sleep(0); WriteProcessMemory(g_cpdi.hProcess, g_pfWriteFile, &g_chINT3, sizeof(BYTE), NULL); return TRUE; } } return FALSE; } void DebugLoop() { DEBUG_EVENT de; DWORD dwContinueStatus; while (WaitForDebugEvent(&de, INFINITE))//while迴圈等待被除錯者發生事件,並根據不同的事件型別做出不同的反映 { dwContinueStatus = DBG_CONTINUE; if (CREATE_PROCESS_DEBUG_EVENT == de.dwDebugEventCode)// 被除錯程序生成事件或者附加事件 { OnCreateProcessDebugEvent(&de); } else if (EXCEPTION_DEBUG_EVENT == de.dwDebugEventCode)// 異常事件 { if (OnExceptionDebugEvent(&de)) continue; } else if (EXIT_PROCESS_DEBUG_EVENT == de.dwDebugEventCode)// 被除錯程序終止事件 { break;//偵錯程式終止 } ContinueDebugEvent(de.dwProcessId, de.dwThreadId, dwContinueStatus);// 再次執行被除錯者 } } int main(int argc, char* argv[]) { DWORD dwPID; //if (argc != 2) //驗證引數 //{ // printf("\nUSAGE : hookdbg.exe <pid>\n"); // return 1; //} printf("input pid\n"); scanf("%d", &dwPID); //dwPID = atoi(argv[1]); //pid if (!DebugActiveProcess(dwPID)) //將偵錯程式(本執行檔案)附加到執行的程序上,開始除錯 { printf("DebugActiveProcess(%d) failed!!!\n" "Error Code = %d\n", dwPID, GetLastError()); return 1; } DebugLoop();// 除錯迴圈,處理來自被除錯者的除錯事件 return 0; }

x64下要注意api的呼叫約定以及指標大小為8位元組;