软件调试学习笔记(三)—— 调试事件的处理
軟件調試學習筆記(三)—— 調試事件的處理
- 要點回顧
- 調試事件的處理
- 實驗一:實現簡單調試器(創建進程)
- 實驗二:分析異常來源
- 實驗三:實現簡單調試器(附加進程)
- 實驗四:分析NtDebugActiveProcess
- 總結
要點回顧
調試事件的處理
調試器調試目標進程步驟:
實驗一:實現簡單調試器(創建進程)
1)將Dbgview.exe拷貝到C盤根目錄下。
2)編譯并運行以下代碼:
// MyDebugger.cpp : Defines the entry point for the console application. //#include "stdafx.h" #include <windows.h> #define DEBUGGEE "C:\\Dbgview.exe"int main(int argc, char* argv[]) {BOOL nIsContinue = TRUE;DEBUG_EVENT debugEvent = {0};BOOL bRet = TRUE;//1.創建調試進程STARTUPINFO startupInfo = {0};PROCESS_INFORMATION pInfo = {0};GetStartupInfo(&startupInfo);bRet = CreateProcess(DEBUGGEE, NULL, NULL, NULL, TRUE, DEBUG_PROCESS || DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &startupInfo, &pInfo);if(!bRet){printf("CreateProcess error: %d \n", GetLastError());return 0;}//2.調試循環while(nIsContinue){bRet = WaitForDebugEvent(&debugEvent, INFINITE);if(!bRet){printf("WaitForDebugEvent error: %d \n", GetLastError());return 0;}switch(debugEvent.dwDebugEventCode){//1.異常case EXCEPTION_DEBUG_EVENT:printf("EXCEPTION_DEBUG_EVENT %x %x %x \n",debugEvent.u.Exception.ExceptionRecord.ExceptionAddress,debugEvent.u.Exception.ExceptionRecord.ExceptionCode,debugEvent.u.Exception.ExceptionRecord.ExceptionFlags);//printf("EXCEPTION_DEBUG_EVENT\n");break;//2.case CREATE_THREAD_DEBUG_EVENT:printf("CREATE_THREAD_DEBUG_EVENT\n");break;//3.case CREATE_PROCESS_DEBUG_EVENT:printf("CREATE_PROCESS_DEBUG_EVENT\n");break;//4.case EXIT_THREAD_DEBUG_EVENT:printf("EXIT_THREAD_DEBUG_EVENT\n");break;//5.case EXIT_PROCESS_DEBUG_EVENT:printf("EXIT_PROCESS_DEBUG_EVENT\n");break;//6.case LOAD_DLL_DEBUG_EVENT:printf("LOAD_DLL_DEBUG_EVENT\n");break;//7.case UNLOAD_DLL_DEBUG_EVENT:printf("UNLOAD_DLL_DEBUG_EVENT\n");break;//8.case OUTPUT_DEBUG_STRING_EVENT:printf("OUTPUT_DEBUG_STRING_EVENT\n");break;}bRet = ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);}return 0; }運行結果:
進程被正常創建,但是在程序創建過程中產生了一條異常事件。
思考:為什么在進程創建過程中會產生一條異常事件?
答案:需要了解進程的創建過程。
進程的創建過程:
實驗二:分析異常來源
1)初步定位異常事件來源
1.1 將調試器設置為第一次暫停于系統斷點
1.2 加載Dbgview.exe
不難看出,是由于程序加載時調用了INT 3指令導致異常事件的產生。
右下角堆棧窗口顯示當前指令位于ntdll.DbgBreakPoint函數。
2)在IDA中定位DbgBreakPoint
3)查看DbgBreakPoint的交叉引用列表
在列表中發現LdrpInitializeProcess,這是進程初始化過程的相關函數。
4)分析LdrpInitializeProcess
4.1 從函數頭向下分析
4.2 分析調用DbgBreakPoint之處
說明在程序創建過程中,一定有API修改了BeingDebugged這個標志位。
5)查看LdrpInitializeProcess函數的交叉引用
6)查看LdrpInitialize函數的交叉引用
最終定位到了LdrInitializeThunk函數,在進程創建過程中會調用此函數。
這么做是因為系統在進程創建過程中給了調試器一個機會讓程序中斷下來。
實驗三:實現簡單調試器(附加進程)
1)啟動“驅動管理.exe“
2)編譯并運行以下代碼
#include "stdafx.h" #include <windows.h> #include <tlhelp32.h> #define DEBUGGEE "驅動管理.exe"int GetProcessId(char *processName) {HANDLE hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);if (hProcSnap == INVALID_HANDLE_VALUE){ExitProcess(-1);}PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) };if(Process32First(hProcSnap, &pe32)){do{ if(pe32.th32ProcessID != 0){if(strcmp(pe32.szExeFile, processName) == 0){return pe32.th32ProcessID;}}}while(Process32Next(hProcSnap, &pe32));}CloseHandle(hProcSnap);return 0; }int main(int argc, char* argv[]) {BOOL nIsContinue = TRUE;DEBUG_EVENT debugEvent = {0};BOOL bRet = TRUE;//1.附加調試進程if(!DebugActiveProcess(GetProcessId(DEBUGGEE))){return 0;}//2.調試循環while(nIsContinue){bRet = WaitForDebugEvent(&debugEvent, INFINITE);if(!bRet){printf("WaitForDebugEvent error: %d \n", GetLastError());return 0;}switch(debugEvent.dwDebugEventCode){//1.異常case EXCEPTION_DEBUG_EVENT:printf("EXCEPTION_DEBUG_EVENT %x %x %x \n",debugEvent.u.Exception.ExceptionRecord.ExceptionAddress,debugEvent.u.Exception.ExceptionRecord.ExceptionCode,debugEvent.u.Exception.ExceptionRecord.ExceptionFlags);//printf("EXCEPTION_DEBUG_EVENT\n");break;//2.case CREATE_THREAD_DEBUG_EVENT:printf("CREATE_THREAD_DEBUG_EVENT\n");break;//3.case CREATE_PROCESS_DEBUG_EVENT:printf("CREATE_PROCESS_DEBUG_EVENT\n");break;//4.case EXIT_THREAD_DEBUG_EVENT:printf("EXIT_THREAD_DEBUG_EVENT\n");break;//5.case EXIT_PROCESS_DEBUG_EVENT:printf("EXIT_PROCESS_DEBUG_EVENT\n");break;//6.case LOAD_DLL_DEBUG_EVENT:printf("LOAD_DLL_DEBUG_EVENT\n");break;//7.case UNLOAD_DLL_DEBUG_EVENT:printf("UNLOAD_DLL_DEBUG_EVENT\n");break;//8.case OUTPUT_DEBUG_STRING_EVENT:printf("OUTPUT_DEBUG_STRING_EVENT\n");break;}bRet = ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);}return 0; }運行結果:
思考:為什么在附加進程時,會收到與進程創建相同的信息。
答案:這些信息被稱為“杜撰的調試信息”。
DebugActiveProcess最終會進入ntoskrnl!NtDebugActiveProcess。
實驗四:分析NtDebugActiveProcess
跟入DbgkpPostFakeProcessCreateMessages。
提供這些虛假消息的目的是給提供調試器一些必要的信息,但可靠性較低(例如模塊信息是通過遍歷PEB的Ldr鏈表模擬出來的,但是部分模塊可能已經被程序卸載或隱藏了)。
總結
總結
以上是生活随笔為你收集整理的软件调试学习笔记(三)—— 调试事件的处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 软件调试学习笔记(二)—— 调试事件的采
- 下一篇: 软件调试学习笔记(四)—— 异常的处理流