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"内存访问断点 "); 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"硬件访问断点 ");
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 }