软件调试学习笔记(六)—— 硬件断点

  • 硬件断点
  • 设置硬件断点
  • 触发硬件断点
  • 处理硬件断点
  • 实验:硬件断点的设置与处理

硬件断点

描述

  1. 与软件断点与内存断点不同,硬件断点不依赖被调试程序,而是依赖于CPU中的调试寄存器
  2. 调试寄存器有7个,分别为Dr0~Dr7
  3. 用户最多能够设置4个硬件断点,这是由于只有Dr0~Dr3用于存储线性地址。
  4. 其中,Dr4和Dr5是保留的。


思考:假如在Dr0寄存器中写入线性地址,是否所有线程都会受影响?
答案:不对,每个线程都拥有一份独立的寄存器,切换线程时,寄存器的值也会被切换。

设置硬件断点

1)Dr0~Dr3用于设置硬件断点,由于只有4个断点寄存器,所以最多只能设置4个硬件调试断点。
2)Dr7是最重要的寄存器:

  1. L0/G0 ~ L3/G3:控制Dr0~Dr3是否有效,局部还是全局;每次异常后,Lx都被清零,Gx不清零。
  2. 断点长度(LENx):00(1字节)、01(2字节)、11(4字节)
  3. 断点类型(R/Wx):00(执行断点)、01(写入断点)、11(访问断点)

触发硬件断点

被调试进程:
1)CPU执行时检测当前线性地址与调试寄存器(Dr0~Dr3)中的线性地址相等。
2)查IDT表找到对应的中断处理函数(nt!_KiTrap01)
3)CommonDispatchException
4)KiDispatchException
5)DbgkForwardException收集并发送调试事件

最终调用DbgkpSendApiMessage(x, x)
第一个参数:消息类型
第二个参数:是否挂起其它线程

调试器进程:
1)循环判断
2)取出调试事件
3)列出信息:寄存器、内存
4)用户处理

处理硬件断点

1)硬件调试断点产生的异常是 STATUS_SINGLE_STEP(单步异常)
2)检测Dr6寄存器的B0~B3:哪个寄存器触发的异常

实验:硬件断点的设置与处理

实验附件:https://pan.baidu.com/s/16p7PDlSsBJeTnIttBGaXlQ 密码: 9lro
1)编译并运行以下代码:

#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>#define DEBUGGEE "C:\\helloworld.exe"//被调试进程ID,进程句柄,OEP
DWORD dwDebuggeePID = 0;//被调试线程句柄
HANDLE hDebuggeeThread = NULL;
HANDLE hDebuggeeProcess = NULL;//系统断点
BOOL bIsSystemInt3 = TRUE;//被INT 3覆盖的数据
CHAR OriginalCode = 0;//线程上下文
CONTEXT Context;typedef HANDLE (__stdcall *FnOpenThread) (DWORD, BOOL, DWORD);VOID InitDebuggeeInfo(DWORD dwPID, HANDLE hProcess)
{dwDebuggeePID = dwPID;hDebuggeeProcess = hProcess;
}DWORD GetProcessId(LPTSTR lpProcessName)
{HANDLE hProcessSnap = NULL;PROCESSENTRY32 pe32 = {0};hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);if(hProcessSnap == (HANDLE)-1){return 0;}pe32.dwSize = sizeof(PROCESSENTRY32);if(Process32First(hProcessSnap, &pe32)){do {if(!strcmp(lpProcessName, pe32.szExeFile))return (int)pe32.th32ProcessID;} while (Process32Next(hProcessSnap, &pe32));}else{CloseHandle(hProcessSnap);}return 0;
}BOOL WaitForUserCommand()
{BOOL bRet = FALSE;CHAR command;printf("COMMAND>");command = getchar();switch(command){case 't':bRet = TRUE;break;case 'p':bRet = TRUE;break;case 'g':bRet = TRUE;break;}getchar();return bRet;
}VOID SetHardBreakPoint(PVOID pAddress)
{//1. 获取线程上下文Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;GetThreadContext(hDebuggeeThread, &Context);//2. 设置断点位置Context.Dr0 = (DWORD)pAddress;Context.Dr7 |= 1;//3. 设置断点长度和类型Context.Dr7 &= 0xfff0ffff;   //执行断点(16、17位 置0) 1字节(18、19位 置0)//5. 设置线程上下文SetThreadContext(hDebuggeeThread, &Context);
}BOOL Int3ExceptionProc(EXCEPTION_DEBUG_INFO *pExceptionInfo)
{BOOL bRet = FALSE;//1. 将INT 3修复为原来的数据(如果是系统断点,不用修复)if(bIsSystemInt3){bIsSystemInt3 = FALSE;return TRUE;}else{WriteProcessMemory(hDebuggeeProcess, pExceptionInfo->ExceptionRecord.ExceptionAddress, &OriginalCode, 1, NULL);}//2. 显示断点位置printf("Int 3断点:0x%p \r\n", pExceptionInfo->ExceptionRecord.ExceptionAddress);//3. 获取线程上下文Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;GetThreadContext(hDebuggeeThread, &Context);//4. 修正EIPContext.Eip--;SetThreadContext(hDebuggeeThread, &Context);//5. 显示反汇编代码、寄存器等/*硬件断点需要设置在被调试进程的的线程上下文中。因此当被调试程序触发调试器设置的INT 3断点时,此时设置硬件断点较为合理。*/SetHardBreakPoint((PVOID)((DWORD)pExceptionInfo->ExceptionRecord.ExceptionAddress+1));//6. 等待用户命令while(bRet == FALSE){bRet = WaitForUserCommand();}return bRet;
}BOOL AccessExceptionProc(EXCEPTION_DEBUG_INFO *pExceptionInfo)
{BOOL bRet = TRUE;return bRet;
}BOOL SingleStepExceptionProc(EXCEPTION_DEBUG_INFO *pExceptionInfo)
{BOOL bRet = FALSE;//1. 获取线程上下文Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;GetThreadContext(hDebuggeeThread, &Context);//2. 判断是否是硬件断点导致的异常if(Context.Dr6 & 0xF) //B0~B3不为空 硬件断点{//2.1 显示断点信息printf("硬件断点:%x 0x%p \n", Context.Dr7&0x00030000, Context.Dr0);//2.2 将断点去除Context.Dr0 = 0;Context.Dr7 &= 0xfffffffe;}else    //单步异常{//2.1 显示断点信息printf("单步:0x%p \n", Context.Eip);//2.2 将断点去除Context.Dr7 &= 0xfffffeff;}SetThreadContext(hDebuggeeThread, &Context);//6. 等待用户命令while(bRet == FALSE){bRet = WaitForUserCommand();}return bRet;
}BOOL ExceptionHandler(DEBUG_EVENT *pDebugEvent)
{ BOOL bRet = TRUE;EXCEPTION_DEBUG_INFO *pExceptionInfo = NULL;pExceptionInfo = &pDebugEvent->u.Exception;//得到线程句柄,后面要用FnOpenThread MyOpenThread = (FnOpenThread)GetProcAddress(LoadLibrary("kernel32.dll"), "OpenThread");hDebuggeeThread = MyOpenThread(THREAD_ALL_ACCESS, FALSE, pDebugEvent->dwThreadId);switch(pExceptionInfo->ExceptionRecord.ExceptionCode){//INT 3异常case EXCEPTION_BREAKPOINT:bRet = Int3ExceptionProc(pExceptionInfo);break;//访问异常case EXCEPTION_ACCESS_VIOLATION:bRet = AccessExceptionProc(pExceptionInfo);break;//单步执行case EXCEPTION_SINGLE_STEP:bRet = SingleStepExceptionProc(pExceptionInfo);break;}return bRet;
}VOID SetInt3BreakPoint(LPVOID addr)
{CHAR int3 = 0xCC;//1. 备份ReadProcessMemory(hDebuggeeProcess, addr, &OriginalCode, 1, NULL);//2. 修改WriteProcessMemory(hDebuggeeProcess, addr, &int3, 1, NULL);
}int main(int argc, char* argv[])
{BOOL nIsContinue = TRUE;DEBUG_EVENT debugEvent = {0};BOOL bRet = TRUE;DWORD dwContinue = DBG_CONTINUE;//1.创建调试进程STARTUPINFO startupInfo = {0};PROCESS_INFORMATION pInfo = {0};GetStartupInfo(&startupInfo);bRet = CreateProcess(DEBUGGEE, NULL, NULL, NULL, TRUE, DEBUG_PROCESS || DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &startupInfo, &pInfo);if(!bRet){printf("CreateProcess error: %d \n", GetLastError());return 0;}hDebuggeeProcess = pInfo.hProcess;//2.调试循环while(nIsContinue){bRet = WaitForDebugEvent(&debugEvent, INFINITE);if(!bRet){printf("WaitForDebugEvent error: %d \n", GetLastError());return 0;}switch(debugEvent.dwDebugEventCode){//1.异常case EXCEPTION_DEBUG_EVENT:bRet = ExceptionHandler(&debugEvent);if(!bRet)dwContinue = DBG_EXCEPTION_NOT_HANDLED;break;//2.case CREATE_THREAD_DEBUG_EVENT:break;//3.创建进程case CREATE_PROCESS_DEBUG_EVENT://设置INT 3断点SetInt3BreakPoint((PCHAR)debugEvent.u.CreateProcessInfo.lpStartAddress);break;//4.case EXIT_THREAD_DEBUG_EVENT:break;//5.case EXIT_PROCESS_DEBUG_EVENT:break;//6.case LOAD_DLL_DEBUG_EVENT:break;//7.case UNLOAD_DLL_DEBUG_EVENT:break;//8.case OUTPUT_DEBUG_STRING_EVENT:break;}bRet = ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);}return 0;
}

运行结果:

2)输入g并回车,触发硬件断点

3)再次输入g并回车,使程序继续运行

软件调试学习笔记(六)—— 硬件断点相关推荐

  1. 软件调试学习笔记(五)—— 软件断点内存断点

    软件调试学习笔记(五)-- 软件断点&内存断点 调试的本质 软件断点 软件断点的执行流程 分析INT 3执行流程 实验:处理软件断点 内存断点 内存断点的执行流程 实验:处理内存断点 调试的本 ...

  2. 软件调试学习笔记(七)—— 单步步入单步步过

    软件调试学习笔记(七)-- 单步步入&单步步过 单步步入 设置单步异常 处理单步异常 实验1:单步异常的设置与处理 单步步过 实现思路 实验2:实现单步步过 单步步入 描述: 单步步入的实现依 ...

  3. 软件调试学习笔记(四)—— 异常的处理流程

    软件调试学习笔记(四)-- 异常的处理流程 要点回顾 异常的处理流程 实验1:理解调试器与异常的关系 未处理异常:最后一道防线 实验2:理解UnhandledExceptionFilter执行流程 实 ...

  4. 软件调试学习笔记(三)—— 调试事件的处理

    软件调试学习笔记(三)-- 调试事件的处理 要点回顾 调试事件的处理 实验一:实现简单调试器(创建进程) 实验二:分析异常来源 实验三:实现简单调试器(附加进程) 实验四:分析NtDebugActiv ...

  5. 软件调试学习笔记(二)—— 调试事件的采集

    软件调试学习笔记(二)-- 调试事件的采集 要点回顾 调试事件的种类 调试事件采集函数 例:分析PspUserThreadStartup 例:分析PspExitThread 总结 要点回顾 调试器与被 ...

  6. 软件调试学习笔记(一)—— 调试对象

    软件调试学习笔记(一)-- 调试对象 准备工作 调试器与被调试程序 DebugActiveProcess 连接调试器 分析kernel32!DebugActiveProcess 分析ntdll!Dbg ...

  7. Windows软件调试学习笔记(1)

    --WINDBG中的表达式 WINDBG接受两种表达式,C++表达式和MASM表达式. 1. MASM表达式中的数值: MASM表达式中的数值可以基于16,10,8,2四种进制.用n命令可以设置WIN ...

  8. 【软考中级】软件设计师学习笔记

    软件设计师学习笔记 计算机系统知识 程序语言设计 数据结构 操作系统 软件工程基础知识 结构化开发方法 创建型设计模式 行为型设计模式 结构型设计模式: 算法设计与分析 数据库技术基础 网络与信息安全 ...

  9. AndroidCamera学习笔记一 硬件

    AndroidCamera学习笔记一 硬件 题记 硬件部分 镜头 传感器 ISP.DSP 闪光灯.滤光片等其他部件 摄像头重要参数 分辨率.像素 光圈数 景深 焦距 硬件成像流程![成像流程](htt ...

最新文章

  1. 牛客小白月赛5-F题: 圆(circle)
  2. java中各种vo举例_了解JAVA中的POJO,Entity,PO,VO,DTO,DM包括代码举例展示
  3. 放置奇兵 算法 月度活动 破碎时空记录 1-3关
  4. 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
  5. 回顾经典,Netflix的推荐系统架构
  6. hdu 2191悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包)
  7. java班长竞选投票_竞选班长采取投票式,引家长不满,班主任:您说该怎么选?...
  8. linux停止tomcat为什么要kill其掉进程 而不是直接shutdown.sh
  9. 2 spss 统计绘图与线性回归
  10. javascript DOM 操作基础知识小结
  11. 阿里小二最想销毁的照片都在这里了,时间真的是把杀猪刀?
  12. 实现中文唇语识别的多种途径
  13. 华科计算机学院新生家长群是多少,关于开通2020级本科和研究生新生群及新生家长群的公告...
  14. .Net6 图片转文字PictureToTxt
  15. FAST迅捷FW150US无线网卡安装说明
  16. 阿里旺铺运营怎样做到低价引流
  17. OTM区块链应用离我们的生活有多近?
  18. 电容传感器FDC2214单通道应用寄存器计算
  19. Zookeeper-3.4.5安装步骤及异常处理
  20. socks代理服务器协议的说明

热门文章

  1. 成功解决pyinstaller生成exe缺少各种包的问题
  2. Python语言学习之pandas:DataFrame二维表的简介、常用函数、常用案例之详细攻略
  3. TF之VGG系列:利用预先编制好的脚本data_convert .py文件将图片格式转换为tfrecord 格式
  4. AI:《A Simple Tool to Start Making Decisions with the Help of AI—借助人工智能开始决策的简单工具》翻译与解读
  5. Py之GUI:Python下各种GUI(图形用户界面)简介、使用优缺点对比
  6. 梯度下降与delta法则
  7. 关于SCI的那些事儿
  8. [jstips]向数组中插入一个元素
  9. unity UV 动画
  10. 不错的linux下通用的java程序启动脚本(转载)