日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2025/3/21 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 软件调试学习笔记(六)—— 硬件断点 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

軟件調試學習筆記(六)—— 硬件斷點

  • 硬件斷點
  • 設置硬件斷點
  • 觸發硬件斷點
  • 處理硬件斷點
  • 實驗:硬件斷點的設置與處理

硬件斷點

描述

  • 與軟件斷點與內存斷點不同,硬件斷點不依賴被調試程序,而是依賴于CPU中的調試寄存器
  • 調試寄存器有7個,分別為Dr0~Dr7
  • 用戶最多能夠設置4個硬件斷點,這是由于只有Dr0~Dr3用于存儲線性地址。
  • 其中,Dr4和Dr5是保留的。

  • 思考:假如在Dr0寄存器中寫入線性地址,是否所有線程都會受影響?
    答案:不對,每個線程都擁有一份獨立的寄存器,切換線程時,寄存器的值也會被切換。

    設置硬件斷點

    1)Dr0~Dr3用于設置硬件斷點,由于只有4個斷點寄存器,所以最多只能設置4個硬件調試斷點。
    2)Dr7是最重要的寄存器:

  • L0/G0 ~ L3/G3:控制Dr0~Dr3是否有效,局部還是全局;每次異常后,Lx都被清零,Gx不清零。
  • 斷點長度(LENx):00(1字節)、01(2字節)、11(4字節)
  • 斷點類型(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并回車,使程序繼續運行

    總結

    以上是生活随笔為你收集整理的软件调试学习笔记(六)—— 硬件断点的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。