📄 lion-tutorial28.htm
字号:
<html>
<head>
<link rel="stylesheet" href="../../asm.css">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Iczelion's win32 asm tutorial</title>
</head>
<body bgcolor="#FFFFFF" background="../../images/back01.jpg">
<p align="center">Tutorial 28: Win32 Debug API Part 1</p>
<hr size="1">
In this tutorial, you'll learn what Win32 offers to developers regarding debugging
primitives. You'll know how to debug a process when you're finished with this
tutorial. <br>
Download <b><a href="files/tut28.zip" style="text-decoration:none">the example</a></b>.
<h3>Theory:</h3>
<p>Win32 has several APIs that allow programmers to use some of the powers of
a debugger. They are called Win32 Debug APIs or primitives. With them, you can:</p>
<ul>
<li>Load a program or attach to a running program for debugging</li>
<li>Obtain low-level information about the program you're debugging, such as
process ID, address of entrypoint, image base and so on.</li>
<li>Be notified of debugging-related events such as when a process/thread starts/exits,
DLLs are loaded/unloaded etc.</li>
<li>Modify the process/thread being debugged</li>
</ul>
<p>In short, you can code a simple debugger with those APIs. Since this subject
is vast, I divide it into several managable parts: this tutorial being the first
part. I'll explain the basic concepts and general framework for using Win32
Debug APIs in this tutorial.<br>
The steps in using Win32 Debug APIs are:</p>
<ol>
<li><b>Create a process or attach your program to a running process</b>. This
is the first step in using Win32 Debug APIs. Since your program will act as
a debugger, you need a program to debug. The program being debugged is called
a debuggee. You can acquire a debuggee in two ways:
<ul>
<li>You can create the debuggee process yourself with <b>CreateProcess</b>.
In order to create a process for debugging, you must specify the <b>DEBUG_PROCESS</b>
flag. This flag tells Windows that we want to debug the process. Windows
will send notifications of important debugging-related events (debug events)
that occur in the debuggee to your program. The debuggee process will
be immediately suspended until your program is ready. If the debuggee
also creates child processes, Windows will also send debug events that
occur in all those child processes to your program as well. This behavior
is usually undesirable. You can disable this behavior by specifying <b>DEBUG_ONLY_THIS_PROCESS</b>
flag in combination of <b>DEBUG_PROCESS</b> flag. </li>
<li>You can attach your program to a running process with <b>DebugActiveProcess.</b></li>
</ul>
</li>
<li><b>Wait for debugging events</b>. After your program acquired a debuggee,
the debuggee's primary thread is suspended and will continue to be suspended
until your program calls <b>WaitForDebugEvent</b>. This function works like
other WaitForXXX functions, ie. it blocks the calling thread until the waited-for
event occurs. In this case, it waits for debug events to be sent by Windows.
Let's see its definition:
<p><b>WaitForDebugEvent proto lpDebugEvent:DWORD, dwMilliseconds:DWORD</b></p>
<p><b>lpDebugEvent</b> is the address of a <b>DEBUG_EVENT</b> structure that
will be filled with information about the debug event that occurs within
the debuggee.</p>
<p><b>dwMilliseconds</b> is the length of time in milliseconds this function
will wait for the debug event to occur. If this period elapses and no debug
event occurs,<b> WaitForDebugEvent</b> returns to the caller. On the other
hand, if you specify<b> INFINITE </b>constant in this argument, the function
will not return until a debug event occurs.</p>
<p>Now let's examine the DEBUG_EVENT structure in more detail.</p>
<p><b>DEBUG_EVENT STRUCT <br>
dwDebugEventCode dd ? <br>
dwProcessId dd ? <br>
dwThreadId dd ? <br>
u DEBUGSTRUCT <> <br>
DEBUG_EVENT ENDS </b></p>
<p><b>dwDebugEventCode</b> contains the value that specifies what type of
debug event occurs. In short, there can be many types of events, your program
needs to check the value in this field so it knows what type of event occurs
and responds appropriately. The possible values are:</p>
</li>
<table border="1" cellspacing="2" cellpadding="2" align="center">
<tr bgcolor="#009999">
<th><b>Value</b></th>
<th>Meanings</th>
</tr>
<tr>
<td><b>CREATE_PROCESS_DEBUG_EVENT</b></td>
<td>A process is created. This event will be sent when the debuggee process
is just created (and not yet running) or when your program just attaches
itself to a running process with <b>DebugActiveProcess</b>. This is the
first event your program will receive.</td>
</tr>
<tr>
<td><b>EXIT_PROCESS_DEBUG_EVENT</b></td>
<td>A process exits.</td>
</tr>
<tr>
<td><b>CREATE_THEAD_DEBUG_EVENT</b></td>
<td>A new thread is created in the debuggee process or when your program
first attaches itself to a running process. Note that you'll not receive
this notification when the primary thread of the debuggee is created.
</td>
</tr>
<tr>
<td height="131"><b>EXIT_THREAD_DEBUG_EVENT</b></td>
<td height="131">A thread in the debuggee process exits. Your program will
not receive this event for the primary thread. In short, you can think
of the primary thread of the debuggee as the equivalent of the debuggee
process itself. Thus, when your program sees <b>CREATE_PROCESS_DEBUG_EVENT</b>,
it's actually the <b>CREATE_THREAD_DEBUG_EVENT</b> for the primary thread.</td>
</tr>
<tr>
<td><b>LOAD_DLL_DEBUG_EVENT</b></td>
<td>The debuggee loads a DLL. You'll receive this event when the PE loader
first resolves the links to DLLs (you call <b>CreateProcess</b> to load
the debuggee) and when the debuggee calls LoadLibrary.</td>
</tr>
<tr>
<td><b>UNLOAD_DLL_DEBUG_EVENT</b></td>
<td>A DLL is unloaded from the debuggee process. </td>
</tr>
<tr>
<td><b>EXCEPTION_DEBUG_EVENT</b></td>
<td>An exception occurs in the debuggee process. <b>Important:</b> This
event will occur once just before the debuggee starts executing its first
instruction. The exception is actually a debug break (int 3h). When you
want to resume the debuggee, call <b>ContinueDebugEvent </b>with<b> DBG_CONTINUE
</b>flag. Don't use <b>DBG_EXCEPTION_NOT_HANDLED</b> flag else the debuggee
will refuse to run under NT (on Win98, it works fine).</td>
</tr>
<tr>
<td><b>OUTPUT_DEBUG_STRING_EVENT</b></td>
<td>This event is generated when the debuggee calls <b>DebugOutputString</b>
function to send a message string to your program. </td>
</tr>
<tr>
<td><b>RIP_EVENT</b></td>
<td>System debugging error occurs</td>
</tr>
</table>
<p><b>dwProcessId</b> and <b>dwThreadId</b> are the process and thread Ids of
the process that the debug event occurs. You can use these values as identifiers
of the process/thread you're interested in. Remember that if you use <b>CreateProcess</b>
to load the debuggee, you also get the process and thread IDs of the debuggee
in the <b>PROCESS_INFO</b> structure. You can use these values to differentiate
between the debug events occurring in the debuggee and its child processes
(in case you didn't specify <b>DEBUG_ONLY_THIS_PROCESS </b>flag).</p>
<p> <b>u</b> is a union that contains more information about the debug event.
It can be one of the following structures depending on the value of <b>dwDebugEventCode</b>
above. </p>
<table border="1" cellspacing="2" cellpadding="2" align="center">
<tr bgcolor="#009900">
<th><b>value in dwDebugEventCode</b></th>
<th>Interpretation of u</th>
</tr>
<tr>
<td><b>CREATE_PROCESS_DEBUG_EVENT</b></td>
<td> A <b>CREATE_PROCESS_DEBUG_INFO</b> structure named <b>CreateProcessInfo</b></td>
</tr>
<tr>
<td><b>EXIT_PROCESS_DEBUG_EVENT</b></td>
<td>An <b>EXIT_PROCESS_DEBUG_INFO structure named</b> ExitProcess</td>
</tr>
<tr>
<td><b>CREATE_THREAD_DEBUG_EVENT</b></td>
<td>A <b>CREATE_THREAD_DEBUG_INFO</b> structure named <b>CreateThread</b></td>
</tr>
<tr>
<td><b>EXIT_THREAD_DEBUG_EVENT</b></td>
<td>An <b>EXIT_THREAD_DEBUG_EVENT </b>structure named <b>ExitThread</b></td>
</tr>
<tr>
<td><b>LOAD_DLL_DEBUG_EVENT</b></td>
<td>A <b>LOAD_DLL_DEBUG_INFO</b> structure named<b> LoadDll</b></td>
</tr>
<tr>
<td><b>UNLOAD_DLL_DEBUG_EVENT</b></td>
<td>An <b>UNLOAD_DLL_DEBUG_INFO</b> structure named <b>UnloadDll</b></td>
</tr>
<tr>
<td><b>EXCEPTION_DEBUG_EVENT</b></td>
<td>An <b>EXCEPTION_DEBUG_INFO</b> structure named <b>Exception</b></td>
</tr>
<tr>
<td><b>OUTPUT_DEBUG_STRING_EVENT</b></td>
<td>An <b>OUTPUT_DEBUG_STRING_INFO </b>structure named <b>DebugString</b></td>
</tr>
<tr>
<td><b>RIP_EVENT</b></td>
<td>A <b>RIP_INFO</b> structure named <b>RipInfo</b></td>
</tr>
</table>
<p>I won't go into detail about all those structures in this tutorial, only
the <b>CREATE_PROCESS_DEBUG_INFO </b>structure will be covered here. <br>
Assuming that our program calls <b>WaitForDebugEvent</b> and it returns. The
first thing we should do is to examine the value in <b>dwDebugEventCode</b>
to see which type of debug event occured in the debuggee process. For example,
if the value in <b>dwDebugEventCode</b> is <b>CREATE_PROCESS_DEBUG_EVENT</b>,
you can interpret the member in <b>u</b> as <b>CreateProcessInfo</b> and access
it with <b>u.CreateProcessInfo</b>. </p>
<li><b>Do whatever your program want to do in response to the debug event</b>.
When <b>WaitForDebugEvent </b>returns, it means a debug event just occurred
in the debuggee process or a timeout occurs. Your program needs to examine
the value in <b>dwDebugEventCode</b> in order to react to the event appropriately.
In this regard, it's like processing Windows messages: you choose to handle
some and ignore some. </li>
<li><b>Let the debuggee continues execution</b>. When a debug event occurs,
Windows suspends the debuggee. When you're finished with the event handling,
you need to kick the debuggee into moving again. You do this by calling <b>ContinueDebugEvent</b>
function.
<p><b>ContinueDebugEvent proto dwProcessId:DWORD, dwThreadId:DWORD, dwContinueStatus:DWORD</b></p>
<p>This function resumes the thread that was previously suspended because
a debug event occurred.<br>
<b>dwProcessId</b> and <b>dwThreadId</b> are the process and thread IDs
of the thread that will be resumed. You usually take these two values from
the <b>dwProcessId</b> and <b>dwThreadId</b> members of the <b>DEBUG_EVENT</b>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -