生活随笔
收集整理的這篇文章主要介紹了
逆向工程核心原理读书笔记-API钩取之记事本小写转大写
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
我們通過一個示例來練習鉤取Notepad.exe的WriteFile,保存文件時將小寫字母全部轉(zhuǎn)換為大寫字母。下面我們先測試一下代碼。
運行notepad.exe并查看PID。
在命令行窗口中輸入命令與參數(shù)。
輸入一串小寫字母之后選擇保存。
再次打開文件,之前的小寫字母全部變成了大寫字母。
我們來分析一下源代碼,看看是怎么實現(xiàn)的。
首先看一下main函數(shù)。main函數(shù)通過DebugActiveProcess將調(diào)試器附加到該運行的進程上,然后進入DebugLoop處理來自被調(diào)試者的調(diào)試事件。
[cpp]?view plaincopy
int?main(int?argc,?char*?argv[])?? {?? ????DWORD?dwPID;?? ?? ????if(?argc?!=?2?)?? ????{?? ????????printf("\nUSAGE?:?hookdbg.exe?<pid>\n");?? ????????return?1;?? ????}?? ?? ?????? ????dwPID?=?atoi(argv[1]);?? ????if(?!DebugActiveProcess(dwPID)?)?? ????{?? ????????printf("DebugActiveProcess(%d)?failed!!!\n"?? ???????????????"Error?Code?=?%d\n",?dwPID,?GetLastError());?? ????????return?1;?? ????}?? ?? ?????? ????DebugLoop();?? ?? ????return?0;?? }??
接下來是DebugLoop。它從被調(diào)試者處接收事件并處理,然后使被調(diào)試者繼續(xù)運行。ContinueDebugEvent是一個使被調(diào)試者繼續(xù)運行的函數(shù)。
[cpp]?view plaincopy
void?DebugLoop()?? {?? ????DEBUG_EVENT?de;?? ????DWORD?dwContinueStatus;?? ?? ?????? ????while(?WaitForDebugEvent(&de,?INFINITE)?)?? ????{?? ????????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);?? ????}?? }??
DebugLoop處理3種調(diào)試事件,分別是EXIT_PROCESS_DEBUG_EVENT、CREATE_PROCESS_DEBUG_EVENT、EXCEPTION_DEBUG_EVENT。
1.被調(diào)試進程終止時會觸發(fā)EXIT_PROCESS_DEBUG_EVENT。這里在發(fā)生該事件時,調(diào)試器與被調(diào)試者將一起終止。
2.OnCreateProcessDebugEvent是CREATE_PROCESS_DEBUG_EVENT事件句柄,被調(diào)試進程啟動(或者附加)時即調(diào)用執(zhí)行該函數(shù)。下面看一下它的核心部分。
[cpp]?view plaincopy
BOOL?OnCreateProcessDebugEvent(LPDEBUG_EVENT?pde)?? {?? ?????? ????g_pfWriteFile?=?GetProcAddress(GetModuleHandleA("kernel32.dll"),?"WriteFile");?? ?? ?????? ?????? ????memcpy(&g_cpdi,?&pde->u.CreateProcessInfo,?sizeof(CREATE_PROCESS_DEBUG_INFO));?? ????ReadProcessMemory(g_cpdi.hProcess,?g_pfWriteFile,??? ??????????????????????&g_chOrgByte,?sizeof(BYTE),?NULL);?? ????WriteProcessMemory(g_cpdi.hProcess,?g_pfWriteFile,??? ???????????????????????&g_chINT3,?sizeof(BYTE),?NULL);?? ?? ????return?TRUE;?? }??
首先獲取WriteFile的起始地址,它獲取的不是被調(diào)試進程的內(nèi)存地址,而是調(diào)試進行的內(nèi)存地址。對于Windows XP的DLL而言,它們在所有進程中都會加載到相同的地址(虛擬內(nèi)存)。由于調(diào)試器擁有被調(diào)試進程的句柄(帶有調(diào)試權限),所以可以使用ReadProcessMemory和WriteProcessMemory對被調(diào)試進程的內(nèi)存空間自由進行讀寫操作。
3.OnExceptionDebugEvent是EXCEPTION_DEBUG_EVENT事件句柄,它處理被調(diào)試者的INT3指令。下面看一下它的核心部分。
[cpp]?view plaincopy
BOOL?OnExceptionDebugEvent(LPDEBUG_EVENT?pde)?? {?? ????CONTEXT?ctx;?? ????PBYTE?lpBuffer?=?NULL;?? ????DWORD?dwNumOfBytesToWrite,?dwAddrOfBuffer,?i;?? ????PEXCEPTION_RECORD?per?=?&pde->u.Exception.ExceptionRecord;?? ?? ?????? ????if(?EXCEPTION_BREAKPOINT?==?per->ExceptionCode?)?? ????{?? ?????????? ????????if(?g_pfWriteFile?==?per->ExceptionAddress?)?? ????????{?? ?????????????? ?????????????? ????????????WriteProcessMemory(g_cpdi.hProcess,?g_pfWriteFile,??? ???????????????????????????????&g_chOrgByte,?sizeof(BYTE),?NULL);?? ?????????????? ????????????ctx.ContextFlags?=?CONTEXT_CONTROL;?? ????????????GetThreadContext(g_cpdi.hThread,?&ctx);?? ?????????????? ?????????????? ?????????????? ????????????ReadProcessMemory(g_cpdi.hProcess,?(LPVOID)(ctx.Esp?+?0x8),??? ??????????????????????????????&dwAddrOfBuffer,?sizeof(DWORD),?NULL);?? ????????????ReadProcessMemory(g_cpdi.hProcess,?(LPVOID)(ctx.Esp?+?0xC),??? ??????????????????????????????&dwNumOfBytesToWrite,?sizeof(DWORD),?NULL);?? ?????????????? ????????????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);?? ?????????????? ?????????????? ????????????free(lpBuffer);?? ?? ?????????????? ????????????ctx.Eip?=?(DWORD)g_pfWriteFile;?? ????????????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;?? }??
首先脫鉤,因為在將小寫字母轉(zhuǎn)換為大寫字母之后需要正常調(diào)用WriteFile。接著獲取線程的上下文,獲取WriteFile的第二個參數(shù)和第三個參數(shù)的值。調(diào)用WriteFile時,我們要在傳遞過來的參數(shù)中知道param2(緩沖區(qū)地址)和param3(緩沖區(qū)大小)這兩個參數(shù)。函數(shù)參數(shù)存儲在棧中,通過CONTEXT.Esp成員可以獲得它們的值。然后把小寫字母轉(zhuǎn)換為大寫字母之后覆寫WriteFile緩沖區(qū),把線程上下文的EIP修改為WriteFile起始地址。因為在WriteFile的起始地址處設置了斷點,被調(diào)試者內(nèi)部調(diào)用WriteFile時,會在起始地址處遇到INT3指令。執(zhí)行該指令時,EIP的值會增加一個字節(jié),所以EIP的當前地址為WriteFile+1。修改好CONTEXT.Eip成員后,調(diào)用SetThreadContext。現(xiàn)在運行調(diào)試進程。如果沒有Sleep(0)語句,Notepad.exe在調(diào)用WriteFile的過程中我們的程序會嘗試將WriteFile的首字節(jié)修改為0xCC,這可能導致內(nèi)存訪問異常。最后設置鉤子,方便下次鉤取操作。
完整的代碼如下。
[cpp]?view plaincopy
#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");?? ?? ?????? ?????? ????memcpy(&g_cpdi,?&pde->u.CreateProcessInfo,?sizeof(CREATE_PROCESS_DEBUG_INFO));?? ????ReadProcessMemory(g_cpdi.hProcess,?g_pfWriteFile,??? ??????????????????????&g_chOrgByte,?sizeof(BYTE),?NULL);?? ????WriteProcessMemory(g_cpdi.hProcess,?g_pfWriteFile,??? ???????????????????????&g_chINT3,?sizeof(BYTE),?NULL);?? ?? ????return?TRUE;?? }?? ?? BOOL?OnExceptionDebugEvent(LPDEBUG_EVENT?pde)?? {?? ????CONTEXT?ctx;?? ????PBYTE?lpBuffer?=?NULL;?? ????DWORD?dwNumOfBytesToWrite,?dwAddrOfBuffer,?i;?? ????PEXCEPTION_RECORD?per?=?&pde->u.Exception.ExceptionRecord;?? ?? ?????? ????if(?EXCEPTION_BREAKPOINT?==?per->ExceptionCode?)?? ????{?? ?????????? ????????if(?g_pfWriteFile?==?per->ExceptionAddress?)?? ????????{?? ?????????????? ?????????????? ????????????WriteProcessMemory(g_cpdi.hProcess,?g_pfWriteFile,??? ???????????????????????????????&g_chOrgByte,?sizeof(BYTE),?NULL);?? ?????????????? ????????????ctx.ContextFlags?=?CONTEXT_CONTROL;?? ????????????GetThreadContext(g_cpdi.hThread,?&ctx);?? ?????????????? ?????????????? ?????????????? ????????????ReadProcessMemory(g_cpdi.hProcess,?(LPVOID)(ctx.Esp?+?0x8),??? ??????????????????????????????&dwAddrOfBuffer,?sizeof(DWORD),?NULL);?? ????????????ReadProcessMemory(g_cpdi.hProcess,?(LPVOID)(ctx.Esp?+?0xC),??? ??????????????????????????????&dwNumOfBytesToWrite,?sizeof(DWORD),?NULL);?? ?????????????? ????????????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);?? ?????????????? ?????????????? ????????????free(lpBuffer);?? ?? ?????????????? ????????????ctx.Eip?=?(DWORD)g_pfWriteFile;?? ????????????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)?)?? ????{?? ????????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;?? ????}?? ?? ?????? ????dwPID?=?atoi(argv[1]);?? ????if(?!DebugActiveProcess(dwPID)?)?? ????{?? ????????printf("DebugActiveProcess(%d)?failed!!!\n"?? ???????????????"Error?Code?=?%d\n",?dwPID,?GetLastError());?? ????????return?1;?? ????}?? ?? ?????? ????DebugLoop();?? ?? ????return?0;?? }??
總結(jié)
以上是生活随笔為你收集整理的逆向工程核心原理读书笔记-API钩取之记事本小写转大写的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。