本章筆者將通過`Windows`平臺下自帶的調試API介面實現對特定進程的動態轉存功能,首先簡單介紹一下關於調試事件的相關信息,調試事件的建立需要依賴於`DEBUG_EVENT`這個特有的數據結構,該結構用於向調試器報告調試事件。當一個程式發生異常事件或者被調試器附加時,就會產生對應的`DEBUG_... ...
本章筆者將通過Windows
平臺下自帶的調試API介面實現對特定進程的動態轉存功能,首先簡單介紹一下關於調試事件的相關信息,調試事件的建立需要依賴於DEBUG_EVENT
這個特有的數據結構,該結構用於向調試器報告調試事件。當一個程式發生異常事件或者被調試器附加時,就會產生對應的DEBUG_EVENT
調試事件,通常DEBUG_EVENT
包含了多種調試類型,包括異常事件、進程創建事件、線程創建事件、進程退出事件和線程退出事件等等,我們只需要動態捕捉這些調試事件並作相應的處理即可實現更多有用的功能。
調試事件通常可以分為如下幾種類型;
- 異常事件 (Exception Event) - 發生了異常,例如訪問非法的記憶體、除以零或調用了無效的函數。
- 進程創建事件 (Process Creation Event) - 當一個新進程被創建時發送此事件。
- 進程退出事件 (Process Exit Event) - 當一個進程退出時發送此事件。
- 線程創建事件 (Thread Creation Event) - 當一個新線程被創建時發送此事件。
- 線程退出事件 (Thread Exit Event) - 當一個線程退出時發送此事件。
- 調試字元串事件 (Debug String Event) - 當一個進程向其調試器發送字元串消息時發送此事件。
- 輸出字元串事件 (Output String Event) - 當輸出調試字元串時發送此事件。
- 動態鏈接庫載入事件(LOAD_DLL_DEBUG_EVENT) - 當進程裝載 DLL 時發送此事件。
當我們需要調試一個程式時有兩種方式可以實現,第一種方式是通過CreateProcess()
函數創建一個進程,併在調用函數時指定DEBUG_PROCESS || DEBUG_ONLY_THIS_PROCESS
則當程式被運行起來後自動進入到調試狀態,另一種方式則是通過DebugActiveProcess()
函數,該函數接受一個正在運行的進程PID號,可動態附加到一個已運行程式上而對其進行調試。
一旦調試器通過CreateProcess()
附加並運行,下一步則是通過WaitForDebugEvent()
用於等待一個調試事件,當有調試事件到達後系統會將調試類型存儲到debugEvent.dwDebugEventCode
這個變數內,此時我們可以通過判斷該變數內的參數來對特定的事件做出自定義處理操作,接著會通過ContinueDebugEvent()
繼續等待下一個調試事件的到來,我們以打開一個進程並創建調試為例,看一下如下代碼片段;
#include <iostream>
#include <windows.h>
int main(int argc, char* argv[])
{
DEBUG_EVENT debugEvent = { 0 };
BOOL bRet = TRUE;
// 創建調試進程
STARTUPINFO startupInfo = { 0 };
PROCESS_INFORMATION pInfo = { 0 };
GetStartupInfo(&startupInfo);
// 創建調試進程並設置 DEBUG_PROCESS || DEBUG_ONLY_THIS_PROCESS 調試事件
bRet = CreateProcess("d://lyshark.exe", NULL, NULL, NULL, TRUE, DEBUG_PROCESS || DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &startupInfo, &pInfo);
if (!bRet)
{
return 0;
}
// 附加調試進程
// DebugActiveProcess(13940)
// 無限迴圈等待調試事件
while (WaitForDebugEvent(&debugEvent, INFINITE))
{
// 根據調試事件判斷
switch (debugEvent.dwDebugEventCode)
{
// 異常調試事件
case EXCEPTION_DEBUG_EVENT:
printf("異常處理事件 \n");
break;
// 線程創建調試事件
case CREATE_THREAD_DEBUG_EVENT:
printf("線程創建調試事件 \n");
break;
// 進程創建調試事件
case CREATE_PROCESS_DEBUG_EVENT:
printf("進程創建調試事件 \n");
break;
// 線程退出調試事件
case EXIT_THREAD_DEBUG_EVENT:
printf("線程退出調試事件 \n");
break;
// 進程退出調試事件
case EXIT_PROCESS_DEBUG_EVENT:
printf("進程退出調試事件 \n");
break;
// 裝載DLL調試事件
case LOAD_DLL_DEBUG_EVENT:
printf("裝載DLL調試事件 \n");
break;
// 卸載DLL調試事件
case UNLOAD_DLL_DEBUG_EVENT:
printf("卸載DLL調試事件 \n");
break;
// 輸出調試信息事件
case OUTPUT_DEBUG_STRING_EVENT:
printf("輸出調試信息事件 \n");
break;
}
// 使調試器能夠繼續以前報告調試事件的線程
bRet = ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);
}
system("pause");
return 0;
}
當編譯並運行上述程式後,讀者應該能看到如下圖所示的輸出效果,其中包括了各類調試事件被觸發時的提示信息,由於在調試事件內沒有做任何操作,程式在載入後就被自動運行起來了;
本文作者: 王瑞
本文鏈接: https://www.lyshark.com/post/b8eecce4.html
版權聲明: 本博客所有文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!
文章出處:https://www.cnblogs.com/LyShark/p/17741475.html
本博客所有文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!