Windows內核分析索引目錄:https://www.cnblogs.com/onetrainee/p/11675224.html
內存斷點與硬件斷點
一、內存斷點
內存斷點的本質是修改頁屬性,觸發頁異常,走0E號中斷。
1. 設置內存斷點:
頁屬性如下:
#define PAGE_NOACCESS 0x01
#define PAGE_READONLY 0x02
#define PAGE_READWRITE 0x04
#define PAGE_WRITECOPY 0x08
#define PAGE_EXECUTE 0x10
#define PAGE_EXECUTE_READ 0x20
#define PAGE_EXECUTE_READWRITE 0x40
#define PAGE_EXECUTE_WRITECOPY 0x80
我們調用 VirutalProtectEx 函數來修改頁屬性。
比如,當我們設置內存訪問斷點,我們將相應的地址所在的頁設置為 PAGE_NOACCESS。
VirtualProtectEx(handle, (PVOID)debugAddress, 1, PAGE_NOACCESS, &oldProtote)
之后,程序訪問該地址會觸發 ACCESS_VIOLATION(c0000005)錯誤,會走0E號中斷,然后包裝加入到 DEBUG_OBJECT.EventLink,通知調試器有事件需要處理。
2. 設置內存斷點案例:
1 DWORD debugAddress = _ttoi(debugStrAddress); 2 3 if (VirtualProtectEx(handle, (PVOID)debugAddress, 1, PAGE_NOACCESS, &oldProtote)) 4 { 5 setText(this->m_edlog, L"內存訪問斷點\r\n"); 6 }
3. 內存斷點恢復案例
1 DWORD memoryHandler(CdebugToolsDlg *pdlg, DEBUG_EVENT dbgEvent) 2 { 3 4 //恢復內存斷點 5 HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, TRUE, dbgEvent.dwProcessId); 6 if (handle == NULL) 7 { 8 return -1; 9 } 10 11 auto er = dbgEvent.u.Exception.ExceptionRecord; 12 if (er.ExceptionInformation[0] == 0) 13 { 14 CString str; 15 str.Format(L"讀斷點被觸發%X,er.ExceptionAddress = %X", er.ExceptionInformation[1], er.ExceptionAddress); 16 setText(pdlg->m_edlog, str); 17 } 18 19 DWORD dwProtect =0; 20 BOOLEAN isCommand = 0; 21 22 isCommand = VirtualProtectEx(handle, (PVOID)er.ExceptionInformation[1], 1, oldProtote, &dwProtect); 23 24 handleInt3 = TRUE; 25 while (isCommand && handleInt3) 26 { 27 Sleep(1); 28 } 29 30 handleInt3 = FALSE; 31 return 0; 32 }
4. 注意事項
1)我們是對一個地址(字節,字或雙字)下斷點,但實際上操作的是一個頁。因此,如果我們要詳細處理,將觸發頁異常時,我們必須判斷是否是我們的目標地址,如果不是,則從調試器角度自然放行,不通知使用者。
2)在修復好頁異常之后,我們在重新設置頁異常,以便於下一次斷下。
二、硬件斷點
硬件斷點是基於寄存器 Dr0~Dr7 實現的。
Dr寄存器在三環沒有讀取和修改權限(mov eax,dr3),只能通過CONTEXT來讀取,或填寫CONTEXT然后傳遞到零環來修改。
關於硬件斷點,詳情可以查看 在Intel手冊 Volume3 Chapter 17.2 Debug Registers
1. DR寄存器的基本布局
如下圖:Dr0~3寄存器存儲四個硬件斷點的地址,Dr4~5為保留寄存器,Dr6 狀態寄存器,Dr7 控制寄存器。
我們如果使用DR1作為硬件斷點,必須在Dr7設置好相應的標志,否則無法使用。
1)DR6寄存器介紹
2)DR7寄存器介紹
2. 硬件斷點的設置
1 DWORD debugAddress = _ttoi(debugStrAddress); 2 3 4 HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, TRUE, hThreadId); 5 if (hThread == NULL) 6 { 7 return; 8 } 9 10 SuspendThread(hThread); 11 12 CONTEXT context = {0}; 13 context.ContextFlags = CONTEXT_ALL; 14 GetThreadContext(hThread, &context); 15 16 context.Dr0 = debugAddress; 17 context.Dr7 |= 0x3fff1; 18 SetThreadContext(hThread, &context); 19 20 ResumeThread(hThread); 21 22 setText(this->m_edlog, L"硬件訪問斷點\r\n");
3. 硬件斷點的恢復
1 BOOLEAN isHard = context.Dr6 & 0xf; 2 if (isHard) 3 { 4 //下次在斷下 5 context.Dr7 |= 1; 6 CString str; 7 str.Format(L"硬件中斷被觸發%X,er.ExceptionAddress = %X", er.ExceptionInformation[1], er.ExceptionAddress); 8 setText(pdlg->m_edlog, str); 9 }