Monday, September 27, 2010

The first part of the Win32 debugging API


In this tutorial we will learn Win32 available to developers for debugging in the original language. At the end of tutorial we will learn how to debug a process.
Download example program.

Theory:
Win32 for programmers to use some API, which provides the equivalent function of the debugger. They were called the Win32 debugging API (or original language). Use the API, we can:

Load a program or bundled into a running program for debugging on
Obtained by low-level debugging of the program information, such as process ID, enter the address, the image base address and so on.
When the incident occurred and when debugging the notice, such as process / thread start / end, DLL loading / discharge, etc..
Modify the debugging process or thread
In short, we can use the API to write a simple debugger. As some of this subject is too large, I divide it into several parts, but this tutorial is the first part of it. In this tutorial, I will explain some of basic concepts and the general framework of the Win32 debugging API.
Use the Win32 debugging API, the following steps:

Create a process or tied to a running processes. This is the first step in using the Win32 debugging API. As our program to play the role of the debugger, we find a program for debugging. A program being debugged is called To debuggee. can be obtained in two ways debuggee:
Created by CreateProcess debuggee process. In order to create a process being debugged, you must specify DEBUG_PROCESS flag. This flag tells Windows that we want to debug the process. Debuggee occur when important events related with the debug (debug event), Windows will give us The program sends notification. debuggee immediately suspended to wait for our program ready. If debuggee also created a child process, Windows will for each child in the process of debugging events to send notification to our programs. This feature is usually not necessary. we can specify a combination of signs DEBUG_PROCESS DEBUG_ONLY_THIS_PROCESS and to ban it.
We can also use the DebugActiveProcess flag tied to a running processes.
Waiting for debug events. Debuggee process in obtaining a post, debuggee the main thread is suspended, the situation will continue to call WaitForDebugEvent up our procedures. WaitForXXX this function and other similar functions, for example, it blocks the calling thread until waiting for events. For this function, it wait for Windows to send debug events from the. Here is its definition:
WaitForDebugEvent proto lpDebugEvent: DWORD, dwMilliseconds: DWORD

lpDebugEvent is the address of a DEBUG_EVENT this structure will be filled on the debuggee debug events that occur in the information.

dwMilliseconds the function to wait for debugging events of the time, in milliseconds. If there is no time to debug the incident, WaitForDebugEvent return to the caller. On the other hand, if the parameter is designated as INFIN99vE constant, the function will have to wait until the debug events .

Now we look at DEBUG_EVENT structure.

DEBUG_EVENT STRUCT
dwDebugEventCode dd?
dwProcessId dd?
dwThreadId dd?
u DEBUGSTRUCT <>
DEBUG_EVENT ENDS

dwDebugEventCode The value specifies the wait events occurred in the type of debugging. because there are many types of events occur, our procedure to check the value, know the type of events and respond. The value of the possible values are as follows:

Value meaning
CREATE_PROCESS_DEBUG_EVENT process is created. When debuggee process has just been created (not running) or our program just to DebugActiveProcess tied to a process running when the event occurs. This is our procedure should be the first event.
EX99v_PROCESS_DEBUG_EVENT process exit.
CREATE_THEAD_DEBUG_EVENT When a new thread is created in deuggee process or our program to run in the first binding event occurs during the process. It should be noted that when debugge the main thread is created will not receive the notice.
EX99v_THREAD_DEBUG_EVENT debuggee the thread exit event. Debugee exit the main thread does not receive the notice. We believe that the main thread and debugge debuggee process is synonymous. So when we see CREATE_PROCESS_DEBUG_EVENT signs the procedure, the main thread it is CREATE_THREAD_DEBUG_EVENT logo.
LOAD_DLL_DEBUG_EVENT debuggee into a DLL. When the PE loader DLL first decomposition point to a link, we will receive the event. (When you call CreateProcess into debuggee time) and when debuggee also occurs when calling LoadLibrary.
UNLOAD_DLL_DEBUG_EVENT a DLL is unloaded from debuggee events.
EXCEPTION_DEBUG_EVENT in debuggee abnormal events occur. Note: This event is only the beginning in debuggee took place before the first instruction of its time. Exception is actually a debug interrupt (int 3h). If you want to restore debuggee things to DBG_CONTINUE signs calling ContinueDebugEvent function. Do not use the logo or debuggee DBG_EXCEPTION_NOT_HANDLED refuse to run in the NT (Win98 to run well).
OUTPUT_DEBUG_STRING_EVENT when debuggee DebugOutputString function call to send a message to our string when the event occurs.
RIP_EVENT system debugging error

dwProcessId and dwThreadId debug the course of events took place and thread Id. We can use these values as we are interested in the process or thread identifier. Remember, if we use CreateProcess to load debuggee, we can get debuggee in PROCESS_INFO the process of structural and thread. We can use these values to different debug event occurred in debuggee in the process or its children (if not specified DEBUG_ONLY_THIS_PROCESS signs).

u is a joint, including the commissioning event for more information. dwDebugEventCode different according to the above, it can be the following structure:

dwDebugEventCode u explained
CREATE_PROCESS_DEBUG_EVENT structure called CreateProcessInfo the CREATE_PROCESS_DEBUG_INFO
EX99v_PROCESS_DEBUG_EVENT structure called ExitProcess the EX99v_PROCESS_DEBUG_INFO
CREATE_THREAD_DEBUG_EVENT structure called CreateThread the CREATE_THREAD_DEBUG_INFO
EX99v_THREAD_DEBUG_EVENT structure called ExitThread the EX99v_THREAD_DEBUG_EVENT
LOAD_DLL_DEBUG_EVENT structure called LoadDll the LOAD_DLL_DEBUG_INFO
UNLOAD_DLL_DEBUG_EVENT structure called UnloadDll the UNLOAD_DLL_DEBUG_INFO
EXCEPTION_DEBUG_EVENT structure called the Exception of EXCEPTION_DEBUG_INFO
OUTPUT_DEBUG_STRING_EVENT structure called DebugString the OUTPUT_DEBUG_STRING_INFO
RIP_EVENT structure called RipInfo of RIP_INFO

In this tutorial I will not say all of these structures in detail, here only to talk about CREATE_PROCESS_DEBUG_INFO structure in detail.
Suppose our program calls the WaitForDebugEvent function and returns, the first thing we need to do is to check the value in terms debuggee dwDebugEventCode process occurred in the type of debug event. For example, if dwDebugEventCode value CREATE_PROCESS_DEBUG_EVENT, on u can be considered a member of the CreateProcessInfo with u.CreateProcessInfo to visit.

In our program, do the debugging event response. When WaitForDebugEvent return, which means that the process took place in the debuggee debug event or timeout occurred. So our procedure to check dwDebugEventCode to make an appropriate response. Here are some like handling Windows messages: the user to select and ignore messages.
Continue to run debuggee. When the debug event occurs, Windows hangs a debuggee, so when we finished with debugging event, but also to debuggee continue. ContinueDebugEvent function call to complete the process.
ContinueDebugEvent proto dwProcessId: DWORD, dwThreadId: DWORD, dwContinueStatus: DWORD

The function recovery as thread debugging events pending.
dwProcessId and dwThreadId is to restore the thread's process ID and thread ID, usually the two values from DEBUG_EVENT structure dwProcessId and dwThreadId members are.
dwContinueStatus report shows how to debug the event thread. There are two possible values: DBG_CONTINUE and DBG_EXCEPTION_NOT_HANDLED. For most debugging events, the two values are the same: to restore the thread. The only exception is EXCEPTION_DEBUG_EVENT, if the thread is reported in an exception debug event, which means that the thread in the debuggee an exception occurs. If you specify DBG_CONTINUE, the thread will ignore its own exception handling section and continue. In this case, our process must be to DBG_CONTINUE restoration of prior thread and handle the exception, or exceptions will be endless if we continue to occur .... DBG_EXCEPTION_NOT_HANDLED specified value, is to tell Windows that our procedure does not handle the exception: Windows will use the default exception handler debuggee to deal with exception.
In short, if our program does not consider the exceptions, and debugging process of the event has a point debuggee exception, it should call the function with DBG_CONTINUE logo ContinueDebugEvent. Otherwise, our program will have to DBG_EXCEPTION_NOT_HANDLED call ContinueDebugEvent. But in following this circumstances must DBG_CONTINUE signs: the first members of the value in ExceptionCode EXCEPTION_BREAKPOINT of EXCEPTION_DEBUG_EVENT event. When debuggee started its first instruction, our function will receive exception debug event. It is in fact a debug interrupt (int 3h). If we are to respond to DBG_EXCEPTION_NOT_HANDLED call ContinueDebugEvent debug events, Windows NT will refuse debuggee (because it is no exception handling). So in this case, the use DBG_CONTINUE flag tells Windows that we want the thread to continue execution.

Continue the above steps until the debuggee process cycle exit. Our program must be a message loop like the infinite loop until the end debuggee. The cycle of roughly as follows:
. While TRUE
invoke WaitForDebugEvent, addr DebugEvent, INFIN99vE
. Break. If DebugEvent.dwDebugEventCode == EX99v_PROCESS_DEBUG_EVENT

invoke ContinueDebugEvent, DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED
. Endw


That is, when starting the debugger, we can not debuggee separate program until it ended.

Let us summarize these steps:

Create a process or a bundle of our program to run the processes.
Wait for the debug events
Response debug event.
Continue debuggee.
To continue this endless loop until the end of the process debuggee
Examples:
This example shows debug a win32 program and handle, such as process, process Id, image base address and so on.

.386
. Model flat, stdcall
option casemap: none
include masm32includewindows.inc
include masm32includekernel32.inc
include masm32includecomdlg32.inc
include masm32includeuser32.inc
includelib masm32libkernel32.lib
includelib masm32libcomdlg32.lib
includelib masm32libuser32.lib
. Data
AppName db "Win32 Debug Example no.1", 0
ofn OPENFILENAME <>
FilterString db "Executable Files", 0, "*. exe", 0
db "All Files", 0 ,"*.*", 0,0
ExitProc db "The debuggee exits", 0
NewThread db "A new thread is created", 0
EndThread db "A thread is destroyed", 0
ProcessInfo db "File Handle:% lx", 0dh, 0Ah
db "Process Handle:% lx", 0Dh, 0Ah
db "Thread Handle:% lx", 0Dh, 0Ah
db "Image Base:% lx", 0Dh, 0Ah
db "Start Address:% lx", 0
. Data?
buffer db 512 dup (?)
startinfo STARTUPINFO <>
pi PROCESS_INFORMATION <>
DBEvent DEBUG_EVENT <>
. 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, INFIN99vE
. If DBEvent.dwDebugEventCode == EX99v_PROCESS_DEBUG_EVENT
invoke MessageBox, 0, addr ExitProc, addr AppName, MB_OK + MB_ICONINFORMATION
. Break
. Elseif DBEvent.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT
invoke wsprintf, addr buffer, addr ProcessInfo, DBEvent.u.CreateProcessInfo.hFile, DBEvent.u.CreateProcessInfo.hProcess, DBEvent.u.CreateProcessInfo.hThread, DBEvent.u.CreateProcessInfo.lpBaseOfImage, DBEvent.u.CreateProcessInfo.lpStartAddress
invoke MessageBox, 0, addr buffer, addr AppName, MB_OK + MB_ICONINFORMATION
. Elseif DBEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
. If DBEvent.u.Exception.pExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE
. Continue
. Endif
. Elseif DBEvent.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT
invoke MessageBox, 0, addr NewThread, addr AppName, MB_OK + MB_ICONINFORMATION
. Elseif DBEvent.dwDebugEventCode == EX99v_THREAD_DEBUG_EVENT
invoke MessageBox, 0, addr EndThread, addr AppName, MB_OK + MB_ICONINFORMATION
. Endif
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED
. Endw
invoke CloseHandle, pi.hProcess
invoke CloseHandle, pi.hThread
. Endif
invoke ExitProcess, 0
end start

Analysis:
Program first fill OPENFILENAME structure, called GetOpenFileName allows users to choose to debug procedures.

invoke GetStartupInfo, addr startinfo
invoke CreateProcess, addr buffer, NULL, NULL, NULL, FALSE, DEBUG_PROCESS + DEBUG_ONLY_THIS_PROCESS, NULL, NULL, addr startinfo, addr pi

When receiving the user selection, call the CreateProcess loader. And call the default value of fill GetStartupInfo STARTUPINFO structure. NOTE We will DEBUG_PROCESS mark and logo combination DEBUG_ONLY_THIS_PROCESS only debug the program, not including the child process.

. While TRUE
invoke WaitForDebugEvent, addr DBEvent, INFIN99vE


Is loaded in the debuggee, we call WaitForDebugEvent into endless loop debugging, WaitForDebugEvent debug event occurs in the debuggee returns, because we specified INFIN99vE as the second argument. When debug event occurs, WaitForDebugEvent back and fill DBEvent structure.

. If DBEvent.dwDebugEventCode == EX99v_PROCESS_DEBUG_EVENT
invoke MessageBox, 0, addr ExitProc, addr AppName, MB_OK + MB_ICONINFORMATION
. Break

We first check dwDebugEventCode of value if it is EX99v_PROCESS_DEBUG_EVENT, with a message box displays "The debuggee exits" and exit the debugging cycle.

. Elseif DBEvent.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT
invoke wsprintf, addr buffer, addr ProcessInfo, DBEvent.u.CreateProcessInfo.hFile, DBEvent.u.CreateProcessInfo.hProcess, DBEvent.u.CreateProcessInfo.hThread, DBEvent.u.CreateProcessInfo.lpBaseOfImage, DBEvent.u.CreateProcessInfo.lpStartAddress
invoke MessageBox, 0, addr buffer, addr AppName, MB_OK + MB_ICONINFORMATION

If dwDebugEventCode value CREATE_PROCESS_DEBUG_EVENT, we show some interest in the message box the bottom of the information. The information obtained from the u.CreateProcessInfo. CreateProcessInfo a CREATE_PROCESS_DEBUG_INFO type of structure. You can access Win32 API access to it for more information e .

. Elseif DBEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
. If DBEvent.u.Exception.pExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE
. Continue
. Endif

If dwDebugEventCode value EXCEPTION_DEBUG_EVENT, we will further check the exception type. It is a lot of nested structure, but we can get from the exception type ExceptionCode members. If ExceptionCode value EXCEPTION_BREAKPOINT and was the first place (or we No known deuggee int 3h instructions), we can safely assume that the first instruction to be executed in debuggee this exception occurs when. in our completion of these processing, you can call ContinueDebugEvent with DBG_CONTINUE to continue debuggee. Then we continue to wait next debug events.

. Elseif DBEvent.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT
invoke MessageBox, 0, addr NewThread, addr AppName, MB_OK + MB_ICONINFORMATION
. Elseif DBEvent.dwDebugEventCode == EX99v_THREAD_DEBUG_EVENT
invoke MessageBox, 0, addr EndThread, addr AppName, MB_OK + MB_ICONINFORMATION
. Endif

If dwDebugEventCode value CREATE_THREAD_DEBUG_EVENT or EX99v_THREAD_DEBUG_EVENT, our program displays a message box.

invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED
. Endw

In addition to the above discussed EXCEPTION_DEBUG_EVENT, with signs calling ContinueDebugEvent function DBG_EXCEPTION_NOT_HANDLED resume debuggee implementation.

invoke CloseHandle, pi.hProcess
invoke CloseHandle, pi.hThread

When debuggee the end, we jumped out of the debugging cycle, this time to close the thread and process handles debuggee. To close the handle does not mean to shut down these processes and threads. Just not use these handles Bale.







Recommended links:



Visual Studio 2010 Will Be Formally Included F #



Common operation of FreeBSD 5.2



Training of new employees approach HR



MPEG to 3GPP



Listed company s three key financial indicators



Golden Abacus eAM State Assets Bureau Haizhu District, Guangzhou presence



Gateway Bank of CHINA has become the odds



Easy to use Games Simulation



Communication states united states into dell 39 s



AMD executives just compensation was 1.25 billion up wages Ma



OGM Converter



ASF To MPG



Report TIMERS And Time Synch



My favorite PASSWORD Managers



No comments:

Post a Comment