内存断点与硬件断点

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     }
原文地址:https://www.cnblogs.com/onetrainee/p/11987083.html