4.软件断点
調試的本質:
一般調試器都會有軟件斷點,內存斷點,硬件斷點… 其實這些無非就是想讓被調試程序觸發異常再讓調試器來接管。
在OD中隨便一個地址按下F2后程序執行到那就會被斷下來,這時調試器將會擁有被調試程序的控制權,這個過程我們稱為“中斷到調試器”。
當我們在OD中按下F2其實就是將那個地址的第一個機器碼修改為0xCC對應的匯編就是 int 3 。
被調試進程:
調試器進程
int 3流程圖
IDT中進入3號中斷
我們現在只關注3環。
如果有內核調試器你3環的調試器是沒有辦法調試了,我們現在是沒有內核調試器的
DbgkpSendApillessage (x, x)
一旦產生異常會先將被調試進程掛起,然后向調試對象的鏈表插入調試事件,后面就是調試器的事了…
代碼
typedef HANDLE(__stdcall *pMyOpenThread)(DWORD dwDesiredAccess, // access rightBOOL bInheritHandle, // handle inheritance optionDWORD dwThreadId // thread identifier);//被調試進程ID,進程句柄,OEP DWORD dwDebuggeePID = 0; HANDLE hDebuggeeProcess = NULL; //被調試線程句柄 HANDLE hDebuggeeThread;//系統斷點 BOOL bIsSystemInt3 = TRUE;//被INT 3覆蓋的數據 char OriginalCode = 0;//線程上下文 CONTEXT Context = { 0 };BOOL WaitForUserCommand() {BOOL bRet = FALSE;char cContext;printf("COMMAND> ");cContext = getchar();switch (cContext){case 't':bRet = TRUE;break;case 'p':bRet = TRUE;break;case 'g':bRet = TRUE;break;}return bRet; }BOOL Int3ExceptionProc(EXCEPTION_DEBUG_INFO* excp) {BOOL bRet = FALSE;//1將INT 3修復為原來的數據(如果是系統斷點不用修復)if (bIsSystemInt3){bIsSystemInt3 = FALSE;return TRUE;}else{//還原WriteProcessMemory(hDebuggeeProcess, excp->ExceptionRecord.ExceptionAddress, &OriginalCode, 1, NULL);}//2.顯示斷點位置printf("int3 斷點 0x%p\n", excp->ExceptionRecord.ExceptionAddress);//3.獲取線程上下文Context.ContextFlags = CONTEXT_FULL || CONTEXT_DEBUG_REGISTERS;bool a = GetThreadContext(hDebuggeeThread, &Context);//4.修正EIP(0xcc斷下已經走了一個字節,Eip要-1)Context.Eip --;SetThreadContext(hDebuggeeThread, &Context);//5.顯示反匯編代碼//省略..//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;//得到線程句柄 后面要用pMyOpenThread MyOpenThread = (pMyOpenThread)GetProcAddress(LoadLibrary(L"Kernel32.dll"),"OpenThread");hDebuggeeThread = MyOpenThread(THREAD_ALL_ACCESS,FALSE,pDebugEvent->dwThreadId);if (pExceptionInfo->ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT){bRet = Int3ExceptionProc(pExceptionInfo);}return bRet; }void SetInt3BreakPoint(LPVOID addr) {ReadProcessMemory(hDebuggeeProcess, addr, &OriginalCode, 1, NULL);BYTE int3[1] = { 0xcc };WriteProcessMemory(hDebuggeeProcess, addr, int3, 1, NULL); }#define ProcessName L"C:\\Users\\Administrator\\Desktop\\控制臺測試\\Debug\\Dbgview.exe" VOID CALL() {BOOL nIsConinue = TRUE;DEBUG_EVENT debugEvent = { 0 };DWORD dwContext = DBG_CONTINUE;//1.創建調試進程STARTUPINFO startupInfo = { 0 };PROCESS_INFORMATION pInfo = { 0 };GetStartupInfo(&startupInfo);WCHAR* _ProcessName = { L"C:\\Users\\Administrator\\Desktop\\控制臺測試\\Debug\\Dbgview.exe" };BOOL bRet = CreateProcess(_ProcessName, NULL, NULL, NULL, TRUE, DEBUG_PROCESS || DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &startupInfo, &pInfo);if (bRet == FALSE){printf("CreateProcess error:%d\n", GetLastError());return ;}hDebuggeeProcess = pInfo.hProcess;//調試循環while (nIsConinue){BOOL bRet = WaitForDebugEvent(&debugEvent, INFINITE);//取DEBUG_EVENTif (!bRet){printf("WaitForDebugEvent error:%d\n", GetLastError());return;}switch (debugEvent.dwDebugEventCode){case EXCEPTION_DEBUG_EVENT:bRet = ExceptionHandler(&debugEvent);if (!bRet)dwContext = DBG_EXCEPTION_NOT_HANDLED;break;case CREATE_THREAD_DEBUG_EVENT:break;case CREATE_PROCESS_DEBUG_EVENT://進程創建的時候 在DEP處設置斷點就是將OEP處的一個字節改為0xCC(INT 3)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;}bRet = ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);} }總結