生活随笔
收集整理的這篇文章主要介紹了
软件调试学习笔记(六)—— 硬件断点
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
軟件調試學習筆記(六)—— 硬件斷點
- 硬件斷點
- 設置硬件斷點
- 觸發硬件斷點
- 處理硬件斷點
- 實驗:硬件斷點的設置與處理
硬件斷點
描述:
與軟件斷點與內存斷點不同,硬件斷點不依賴被調試程序,而是依賴于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"
DWORD dwDebuggeePID
= 0;
HANDLE hDebuggeeThread
= NULL;
HANDLE hDebuggeeProcess
= NULL;
BOOL bIsSystemInt3
= TRUE
;
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
)
{Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;GetThreadContext(hDebuggeeThread
, &Context
);Context
.Dr0
= (DWORD
)pAddress
;Context
.Dr7
|= 1;Context
.Dr7
&= 0xfff0ffff; SetThreadContext(hDebuggeeThread
, &Context
);
}BOOL
Int3ExceptionProc(EXCEPTION_DEBUG_INFO
*pExceptionInfo
)
{BOOL bRet
= FALSE
;if(bIsSystemInt3
){bIsSystemInt3
= FALSE
;return TRUE
;}else{WriteProcessMemory(hDebuggeeProcess
, pExceptionInfo
->ExceptionRecord
.ExceptionAddress
, &OriginalCode
, 1, NULL);}printf("Int 3斷點:0x%p \r\n", pExceptionInfo
->ExceptionRecord
.ExceptionAddress
);Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;GetThreadContext(hDebuggeeThread
, &Context
);Context
.Eip
--;SetThreadContext(hDebuggeeThread
, &Context
);SetHardBreakPoint((PVOID
)((DWORD
)pExceptionInfo
->ExceptionRecord
.ExceptionAddress
+1));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
;Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;GetThreadContext(hDebuggeeThread
, &Context
);if(Context
.Dr6
& 0xF) {printf("硬件斷點:%x 0x%p \n", Context
.Dr7
&0x00030000, Context
.Dr0
);Context
.Dr0
= 0;Context
.Dr7
&= 0xfffffffe;}else {printf("單步:0x%p \n", Context
.Eip
);Context
.Dr7
&= 0xfffffeff;}SetThreadContext(hDebuggeeThread
, &Context
);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
){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;ReadProcessMemory(hDebuggeeProcess
, addr
, &OriginalCode
, 1, NULL);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
;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
;while(nIsContinue
){bRet
= WaitForDebugEvent(&debugEvent
, INFINITE
);if(!bRet
){printf("WaitForDebugEvent error: %d \n", GetLastError());return 0;}switch(debugEvent
.dwDebugEventCode
){case EXCEPTION_DEBUG_EVENT
:bRet
= ExceptionHandler(&debugEvent
);if(!bRet
)dwContinue
= DBG_EXCEPTION_NOT_HANDLED
;break;case CREATE_THREAD_DEBUG_EVENT
:break;case CREATE_PROCESS_DEBUG_EVENT
:SetInt3BreakPoint((PCHAR
)debugEvent
.u
.CreateProcessInfo
.lpStartAddress
);break;case EXIT_THREAD_DEBUG_EVENT
:break;case EXIT_PROCESS_DEBUG_EVENT
:break;case LOAD_DLL_DEBUG_EVENT
:break;case UNLOAD_DLL_DEBUG_EVENT
:break;case OUTPUT_DEBUG_STRING_EVENT
:break;}bRet
= ContinueDebugEvent(debugEvent
.dwProcessId
, debugEvent
.dwThreadId
, DBG_CONTINUE
);}return 0;
}
運行結果:
2)輸入g并回車,觸發硬件斷點
3)再次輸入g并回車,使程序繼續運行
總結
以上是生活随笔為你收集整理的软件调试学习笔记(六)—— 硬件断点的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。