軟件調試(6) - 深入探討調試體系啟動及附加調試

用戶 <=== UI線程 <=== 調試器 ===> 調試工作線程 ===> 被調試進程
(獲取調試對象) (設置調試對象)


調試器
-----------------------------------------------------------------
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

Popular posts from this blog

Android Kernel Development - Kernel compilation and Hello World

How does Nested-Virtualization works?

Understanding ACPI and Device Tree