軟件調試(6) - 深入探討調試體系啟動及附加調試
用戶 <=== UI線程 <=== 調試器 ===> 調試工作線程 ===> 被調試進程
(獲取調試對象) (設置調試對象)
調試器
-----------------------------------------------------------------
DbgSsReserved[0] => 被調試線程鏈表頭
DbgSsReserved[1] => 調試對象的句柄 //判斷是否句柄 !handle xxxxx
鏈表頭結構:
WaitForDebugEvent , ContinueDebugEvent 會維護DbgSsReserved[0]鏈表
WinXP=> Ntdll!DbgUiGetThreadDebugObject 和Ntdll!DbgUiSetThreadDebugObject
實際上就是讀寫鏈表
WaitForDebugEvent => 從teb獲取調試對象
DbgSsReserved[1] 由kernel32的調試API所設置, 如果Windbg不是調用他來調試
*而CreateProcess時R3層會把他設置為非0 但在CreateProcess後Windbg會調用DbgUiSetThreadDebugObject設置為0
被調試進程 和原本進程的差異
------------------------------------------------------------------
1. EPROCESS Debugport字段不為0, 內核空間判斷一個進程是否正在被調試的主要特征
2. PEB的BeingDebugged字段不為0, 用戶態判斷是否正在被調試的主要方法
3. 可能會存在一條線程RemoteBreakin, 作用就是將被調試進程中斷到調試器
4. F12
Debugport
-------------------------------------------------------------------
winXP前: 指向LPC
winXP後: 指向調試對象
作用: 用於傳送調試信息
BeingDebugged
-------------------------------------------------------------------
kernel32!IsDebuggerPresent就是檢測PEB->BeingDebugged判斷是否被調試
判斷是否內核對象 !object xxxxx
CreateProcess調試之設置為DEBUG_PROCESS主要三個動作:
--------------------------------------------------------------------
1: NtCreateProcess前調用DbgUiConnectToDbg()使調用線程與調試子系統連接(才可以訪問對象xxxx)=>內部調用ZwCreateDebugObject以建立調試對象=>返回後保存到DbgSsReserved[1](為了防止重覆動作會先檢查是否為空)
2: NtCreateProcess時調用PspCreateProcess會檢測句柄是否為空,不為空則換成對象指針=>最後放到EPROCESS的DebugPort
3: PspCreateProcess調用MmCreaTePeb時會根據EPROCESS->DebugPort設置IsBeingDebugged
第一批調試事件
-------------------------------------------------------------------
- 一個新創建進程的初始線程的回調函數是內核中的KiThreadStartup, 將線程下降IRQL至APC後便執行PspUserThreadStartUp發送調試信息到調試器
- 調試器處理後 一直會收到一堆加載DLL或打印log的調試事件
初始斷點
-------------------------------------------------------------------
當新進程初始化在自己的上下文中初始化時=>作為進程初始化的步驟=>NTDLL!LdrpInitializeProcess函數會檢測正在初始化的進程是否處於調試狀態(BeingDebugged),如果是執觸發一個斷點異常,目的是中斷到調試器(掛起線程除調用線程外)
附加到已啟動的進程
--------------------------------
DebugActiveProcess會做3件事建立調試關係:
1: 通過DbgUiConnectToDbg()使調用進程與子系統建立關係,建立調試對象
2: 調用ProcessIdToHandle函數,獲得指定進程ID的進程句柄=>調用OpenProcess=>NtOpenProcess(必要提升權限,最好是SE_DEBUG_NAME)
3: 調用ntdll!DbgUiDebugActiveProcess=>調用nt!NtDebugActiveProcess(將被調試進程的句柄和調試對象的句作為參數)=>他會進行3個動作
3.1 根據參數指定句取得被調試進程的EPROCESS 和 調試對象的指針
3.2 向調試對象發送杜擇的調試事件
3.3 調用DbgkpSetProcessDebugObject(設置被調試進程的EPROCESS->DebugPort) 及 DbgkpMarkProcessPeb(設置被調試進程的Peb->BeingDebugged)
(獲取調試對象) (設置調試對象)
調試器
-----------------------------------------------------------------
DbgSsReserved[0] => 被調試線程鏈表頭
DbgSsReserved[1] => 調試對象的句柄 //判斷是否句柄 !handle xxxxx
鏈表頭結構:
typedef struct _DBGSS_THREAD_DATA { struct _DBGSS_THREAD_DATA *Next; HANDLE ThreadHandle; HANDLE ProcessHandle; DWORD ProcessID; DWORD ThreadID; BOOLEAN HandleMarked; //退出標志 }DBGSS_THREAD_DATA,*PDBGSS_THREAD_DATA;
WaitForDebugEvent , ContinueDebugEvent 會維護DbgSsReserved[0]鏈表
WinXP=> Ntdll!DbgUiGetThreadDebugObject 和Ntdll!DbgUiSetThreadDebugObject
實際上就是讀寫鏈表
WaitForDebugEvent => 從teb獲取調試對象
DbgSsReserved[1] 由kernel32的調試API所設置, 如果Windbg不是調用他來調試
*而CreateProcess時R3層會把他設置為非0 但在CreateProcess後Windbg會調用DbgUiSetThreadDebugObject設置為0
被調試進程 和原本進程的差異
------------------------------------------------------------------
1. EPROCESS Debugport字段不為0, 內核空間判斷一個進程是否正在被調試的主要特征
2. PEB的BeingDebugged字段不為0, 用戶態判斷是否正在被調試的主要方法
3. 可能會存在一條線程RemoteBreakin, 作用就是將被調試進程中斷到調試器
4. F12
Debugport
-------------------------------------------------------------------
winXP前: 指向LPC
winXP後: 指向調試對象
作用: 用於傳送調試信息
BeingDebugged
-------------------------------------------------------------------
kernel32!IsDebuggerPresent就是檢測PEB->BeingDebugged判斷是否被調試
判斷是否內核對象 !object xxxxx
CreateProcess調試之設置為DEBUG_PROCESS主要三個動作:
--------------------------------------------------------------------
1: NtCreateProcess前調用DbgUiConnectToDbg()使調用線程與調試子系統連接(才可以訪問對象xxxx)=>內部調用ZwCreateDebugObject以建立調試對象=>返回後保存到DbgSsReserved[1](為了防止重覆動作會先檢查是否為空)
2: NtCreateProcess時調用PspCreateProcess會檢測句柄是否為空,不為空則換成對象指針=>最後放到EPROCESS的DebugPort
3: PspCreateProcess調用MmCreaTePeb時會根據EPROCESS->DebugPort設置IsBeingDebugged
第一批調試事件
-------------------------------------------------------------------
- 一個新創建進程的初始線程的回調函數是內核中的KiThreadStartup, 將線程下降IRQL至APC後便執行PspUserThreadStartUp發送調試信息到調試器
- 調試器處理後 一直會收到一堆加載DLL或打印log的調試事件
初始斷點
-------------------------------------------------------------------
當新進程初始化在自己的上下文中初始化時=>作為進程初始化的步驟=>NTDLL!LdrpInitializeProcess函數會檢測正在初始化的進程是否處於調試狀態(BeingDebugged),如果是執觸發一個斷點異常,目的是中斷到調試器(掛起線程除調用線程外)
附加到已啟動的進程
--------------------------------
BOOL DebugActiveProcess(DWORD dwProcessId)
DebugActiveProcess會做3件事建立調試關係:
1: 通過DbgUiConnectToDbg()使調用進程與子系統建立關係,建立調試對象
2: 調用ProcessIdToHandle函數,獲得指定進程ID的進程句柄=>調用OpenProcess=>NtOpenProcess(必要提升權限,最好是SE_DEBUG_NAME)
3: 調用ntdll!DbgUiDebugActiveProcess=>調用nt!NtDebugActiveProcess(將被調試進程的句柄和調試對象的句作為參數)=>他會進行3個動作
3.1 根據參數指定句取得被調試進程的EPROCESS 和 調試對象的指針
3.2 向調試對象發送杜擇的調試事件
3.3 調用DbgkpSetProcessDebugObject(設置被調試進程的EPROCESS->DebugPort) 及 DbgkpMarkProcessPeb(設置被調試進程的Peb->BeingDebugged)
Comments
Post a Comment