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 }
来源:oschina
链接:https://my.oschina.net/u/4349637/blog/3335286