📄 tut28.html
字号:
<html>
<head>
<title>Iczelion's Win32 Assembly Tutorial 28: Win32 Debug API Part 1</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body bgcolor="#330099" text="#FFFFFF" link="#FFFFCC" vlink="#FFCCCC" alink="#CCFFCC">
<h1 align="center"><font face="Arial, Helvetica, sans-serif" color="#FFFFCC">Tutorial
28: Win32 Debug API Part 1</font></h1>
<p><font face="MS Sans Serif" 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>.</font></p>
<h3><font face="MS Sans Serif" size="-1">Theory:</font></h3>
<p><font face="MS Sans Serif" size="-1">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:</font></p>
<ul>
<li><font face="MS Sans Serif" size="-1">Load a program or attach to a running
program for debugging</font></li>
<li><font face="MS Sans Serif" size="-1">Obtain low-level information about
the program you're debugging, such as process ID, address of entrypoint, image
base and so on.</font></li>
<li><font face="MS Sans Serif" size="-1">Be notified of debugging-related events
such as when a process/thread starts/exits, DLLs are loaded/unloaded etc.</font></li>
<li><font face="MS Sans Serif" size="-1">Modify the process/thread being debugged</font></li>
</ul>
<p><font face="MS Sans Serif" size="-1">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.</font><br>
<font face="MS Sans Serif" size="-1">The steps in using Win32 Debug APIs are:</font></p>
<ol>
<li><font color="#CCFFCC"><b><font face="MS Sans Serif" size="-1">Create a process
or attach your program to a running process</font></b></font><font face="MS Sans Serif" size="-1">.
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:</font>
<ul>
<li><font face="MS Sans Serif" size="-1">You can create the debuggee process
yourself with <font color="#FFFFCC"><b>CreateProcess</b></font>. In order
to create a process for debugging, you must specify the <font color="#FFCCCC"><b>DEBUG_PROCESS</b></font>
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 <font color="#FFCCCC"><b>DEBUG_ONLY_THIS_PROCESS</b></font>
flag in combination of <font color="#FFCCCC"><b>DEBUG_PROCESS</b></font>
flag. </font></li>
<li><font face="MS Sans Serif" size="-1">You can attach your program to
a running process with <font color="#FFFFCC"><b>DebugActiveProcess.</b></font></font></li>
</ul>
</li>
<li><font color="#CCFFCC"><b><font face="MS Sans Serif" size="-1">Wait for debugging
events</font></b></font><font face="MS Sans Serif" size="-1">. After your
program acquired a debuggee, the debuggee's primary thread is suspended and
will continue to be suspended until your program calls <font color="#FFFFCC"><b>WaitForDebugEvent</b></font>.
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:</font>
<p><font face="MS Sans Serif" size="-1"><b><font color="#CCCC99">WaitForDebugEvent
proto lpDebugEvent:DWORD, dwMilliseconds:DWORD</font></b></font></p>
<p><font face="MS Sans Serif" size="-1"><b><font color="#CC9900">lpDebugEvent</font></b>
is the address of a <font color="#33CC00"><b>DEBUG_EVENT</b></font> structure
that will be filled with information about the debug event that occurs within
the debuggee.</font></p>
<p><font face="MS Sans Serif" size="-1"><b><font color="#CC9900">dwMilliseconds</font></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,<font color="#FFFFCC"><b>
WaitForDebugEvent</b></font> returns to the caller. On the other hand, if
you specify<font color="#FFCCCC"><b> INFINITE </b></font>constant in this
argument, the function will not return until a debug event occurs.</font></p>
<p><font face="MS Sans Serif" size="-1">Now let's examine the DEBUG_EVENT
structure in more detail.</font></p>
<p><b><font face="MS Sans Serif" size="-1" color="#33CC00">DEBUG_EVENT STRUCT
<br>
dwDebugEventCode dd ? <br>
dwProcessId dd ? <br>
dwThreadId dd ? <br>
u DEBUGSTRUCT <> <br>
DEBUG_EVENT ENDS </font></b></p>
<p><font face="MS Sans Serif" size="-1"><b><font color="#CC9900">dwDebugEventCode</font></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:</font></p>
</li>
<table border="1" cellspacing="2" cellpadding="2" align="center">
<tr bgcolor="#009999">
<th><b><font face="MS Sans Serif" size="-1">Value</font></b></th>
<th><font face="MS Sans Serif" size="-1">Meanings</font></th>
</tr>
<tr>
<td><b><font face="MS Sans Serif" size="-1">CREATE_PROCESS_DEBUG_EVENT</font></b></td>
<td><font face="MS Sans Serif" size="-1">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 <font color="#FFFFCC"><b>DebugActiveProcess</b></font>.
This is the first event your program will receive.</font></td>
</tr>
<tr>
<td><b><font face="MS Sans Serif" size="-1">EXIT_PROCESS_DEBUG_EVENT</font></b></td>
<td><font face="MS Sans Serif" size="-1">A process exits.</font></td>
</tr>
<tr>
<td><b><font face="MS Sans Serif" size="-1">CREATE_THEAD_DEBUG_EVENT</font></b></td>
<td><font face="MS Sans Serif" size="-1">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. </font></td>
</tr>
<tr>
<td height="131"><b><font face="MS Sans Serif" size="-1">EXIT_THREAD_DEBUG_EVENT</font></b></td>
<td height="131"><font face="MS Sans Serif" size="-1">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 <font color="#FFCCCC"><b>CREATE_PROCESS_DEBUG_EVENT</b></font>, it's
actually the <font color="#FFCCCC"><b>CREATE_THREAD_DEBUG_EVENT</b></font>
for the primary thread.</font></td>
</tr>
<tr>
<td><b><font face="MS Sans Serif" size="-1">LOAD_DLL_DEBUG_EVENT</font></b></td>
<td><font face="MS Sans Serif" size="-1">The debuggee loads a DLL. You'll
receive this event when the PE loader first resolves the links to DLLs
(you call <font color="#FFFFCC"><b>CreateProcess</b></font> to load the
debuggee) and when the debuggee calls LoadLibrary.</font></td>
</tr>
<tr>
<td><b><font face="MS Sans Serif" size="-1">UNLOAD_DLL_DEBUG_EVENT</font></b></td>
<td><font face="MS Sans Serif" size="-1">A DLL is unloaded from the debuggee
process. </font></td>
</tr>
<tr>
<td><b><font face="MS Sans Serif" size="-1">EXCEPTION_DEBUG_EVENT</font></b></td>
<td><font face="MS Sans Serif" size="-1">An exception occurs in the debuggee
process. <font color="#FF3333"><b>Important:</b></font> <font color="#33FF33">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 <font color="#FFFFCC"><b>ContinueDebugEvent
</b></font>with<b><font color="#FFCCCC"> DBG_CONTINUE </font></b>flag.
Don't use <font color="#FFCCCC"><b>DBG_EXCEPTION_NOT_HANDLED</b></font>
flag else the debuggee will refuse to run under NT (on Win98, it works
fine).</font></font></td>
</tr>
<tr>
<td><b><font face="MS Sans Serif" size="-1">OUTPUT_DEBUG_STRING_EVENT</font></b></td>
<td><font face="MS Sans Serif" size="-1">This event is generated when the
debuggee calls <font color="#FFFFCC"><b>DebugOutputString</b></font> function
to send a message string to your program. </font></td>
</tr>
<tr>
<td><b><font face="MS Sans Serif" size="-1">RIP_EVENT</font></b></td>
<td><font face="MS Sans Serif" size="-1">System debugging error occurs</font></td>
</tr>
</table>
<p><font face="MS Sans Serif" size="-1"><b><font color="#CC9900">dwProcessId</font></b>
and <font color="#CC9900"><b>dwThreadId</b></font> 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 <font color="#FFFFCC"><b>CreateProcess</b></font> to load the debuggee,
you also get the process and thread IDs of the debuggee in the <font color="#FFCCCC"><b>PROCESS_INFO</b></font>
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -