Lesson 30: Win32 debugging API Part III
In this chapter, we will continue to explore the Win32 debug API. In particular, we will learn how to track the debugged procedure.
theory:
If you have used the debugger before, you should be more familiar with tracking. When a program is "Tracking", the program will stop after each execution of a command, which allows you to check the values in register / memory. The official definition of this single-step operation is trace. The characteristics of single-step operation are provided by the CPU itself. The 8th bit of the logo register is called the trap flag Trap Flag. If this bit is set, the CPU runs in a single step mode. The CPU will produce a Debug exception after each instruction. When Debug is abnormal, the trap flag is automatically cleared. With the Win32 debug API, we can also run the debugged program. Methods as below:
Call GetThreadContext, specifying the contextFlags to obtain the value of the logo register to set the trap flag in the Context Structure Members Register Regflag calls setthreadContext Waizard the event. The debugging program will be executed in single step mode. After each execution, we will get debug events, u.exception.pexceptionRecord.exceptioncode values are exception_single_step If you want to track the next instruction, you need to set the trap flag again.
example:
.386.model flat, stdcall option casemap: none include /masm32/include/windows.inc include /masm32/include/kernel32.inc include /masm32/include/comdlg32.inc include /masm32/include/user32.inc includelib / masm32 /lib/kernel32.lib includelib /masm32/lib/comdlg32.lib includelib /masm32/lib/user32.lib .data AppName db "Win32 Debug Example no.4", 0 ofn OPENFILENAME <> FilterString db "Executable Files", 0 , "*. EXE", 0 DB "All Files", 0, "*. *", 0, 0 EXITPROC DB "THE Debuggee EXITS", 0DH, 0AH DB "Total Instructions Executed:% Lu", 0 Totalinstruction DD 0 ? (?) .data buffer db 512 dup startinfo STARTUPINFO <> pi PROCESS_INFORMATION <> DBEvent DEBUG_EVENT <> context cONTEXT <> .code start: mov ofn.lStructSize, SIZEOF ofn mov ofn.lpstrFilter, OFFSET FilterString mov ofn.lpstrFile, OFFSET buffer mov ofn.nMaxFile, 512 mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY invoke GetOpenFileName, ADDR ofn .if eax == TRUE invoke GetStartupInfo, addr startinfo invoke CreateProcess, addr buffer, NULL, NULL, NULL, FALSE, DEBUG_PROCESS DEBUG_ONLY_THIS_PROCESS, NULL, NULL, addr startinfo, addr pi .while TRUE invoke WaitForDebugEvent, addr DBEvent, INFINITE .if DBEvent.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT invoke wsprintf, addr buffer, addr ExitProc, TotalInstruction invoke MessageBox, 0, addr buffer, addr AppName, MB_OK MB_ICONINFORMATION .break .elseif DBEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT .if DBEvent.u.Exception.pExceptionRecord.ExceptionCode ==
EXCEPTION_BREAKPOINT mov context.ContextFlags, CONTEXT_CONTROL invoke GetThreadContext, pi.hThread, addr context or context.regFlag, 100h invoke SetThreadContext, pi.hThread, addr context invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE .continue .elseif DBEvent.u .Exception.pExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP inc TotalInstruction invoke GetThreadContext, pi.hThread, addr context or context.regFlag, 100h invoke SetThreadContext, pi.hThread, addr context invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE .continue. endif .endif invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED .endw .endif invoke CloseHandle, pi.hProcess invoke CloseHandle, pi.hThread invoke ExitProcess, 0 end start analysis:
The program first displays an open file dialog that the user selects an executable file, and it performs a single step and records the number of executed instructions until the debugger exits the run.
.ELSEIF DBEVENT.DWDEBUGEVENTCODE == Exception_debug_event .IF dbevent.u.exception.pexceptionRecord.exceptioncode == Exception_breakpoint
Use this opportunity to set the debugged program for single-step operation mode. Remember, Windows will send an Exception_breakPoint message before performing the first instruction of the debugger.
Mov Context.contextFlags, Context_Control Invoke GetThreadContext, Pi.hthread, Addr Context
Call GetThreadContext to populate the CONTEXT structure specifically to the current register content of the debugger, we need the current value of the flag register.
OR Context.Regflag, 100H
Set the trap bit of the flag register image (8th)
Invoke setthreadContext, Pi.hthread, Addr Context Invoke ContinueDebugevent, Dbevent.dwprocessid, DBEvent.dwthreadId, DBG_Continue .Continue
Then call SetThreadContext to override the value of Context. Recovery the debugger run again in dbg_continue to recover the operation of the debugger. .ELSEIF DBEVENT.U.Exception.pexceptionRecord.exceptioncode == Exception_Single_Step Inc Totalinstruction
When one instruction in the debugger is executed, we will receive the debug event of Exception_Debug_event, you must check the value of U.Exception.pexceptionRecord.exceptioncode. If the value is exception_single_step, then the debug event is caused by single step operation mode. In this case, TotalinstructionTRuction plus one, because we exactly knowing that the debugger is executed at this time.
invoke GetThreadContext, pi.hThread, addr context or context.regFlag, 100h invoke SetThreadContext, pi.hThread, addr context invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE .continue
Since the trap logo is automatically cleared after the DEBUG is abnormal, if we need to continue the single-step operation mode, you must set the trap marker. WARNING: Do not use this example in this tutorial to debug a big program: tracking is very slow. You may have to wait more than 10 minutes to close the debugged program.