?? lion-tutorial28.htm
字號:
structure.<br>
dwContinueStatus specifies how to continue the thread that reported the
debug event. There are two possible values:<b> DBG_CONTINUE</b> and <b>DBG_EXCEPTION_NOT_HANDLED</b>.
For all other debug events, those two values do the same thing: resume the
thread. The exception is the <b>EXCEPTION_DEBUG_EVENT</b>. If the thread
reports an exception debug event, it means an exception occurred in the
debuggee thread. If you specify <b>DBG_CONTINUE</b>, the thread will ignore
its own exception handling and continue with the execution. In this scenario,
your program must examine and resolve the exception itself before resuming
the thread with <b>DBG_CONTINUE</b> else the exception will occur again
and again and again.... If you specify <b>DBG_EXCEPTION_NOT_HANDLED</b>,
your program is telling Windows that it didn't handle the exception: Windows
should use the default exception handler of the debuggee to handle the exception.
<br>
In conclusion, if the debug event refers to an exception in the debuggee
process, you should call <b>ContinueDebugEvent</b> with <b>DBG_CONTINUE</b>
flag if your program already removed the cause of exception. Otherwise,
your program must call <b>ContinueDebugEvent</b> with <b>DBG_EXCEPTION_NOT_HANDLED</b>
flag. Except in one case which you must always use <b>DBG_CONTINUE</b> flag:
the first <b>EXCEPTION_DEBUG_EVENT</b> which has the value <b>EXCEPTION_BREAKPOINT</b>
in the ExceptionCode member. When the debuggee is going to execute its very
first instruction, your program will receive the exception debug event.
It's actually a debug break (int 3h). If you respond by calling <b>ContinueDebugEvent
</b>with <b>DBG_EXCEPTION_NOT_HANDLED</b> flag, Windows NT will refuse to
run the debuggee (because no one cares for it). You must always use <b>DBG_CONTINUE</b>
flag in this case to tell Windows that you want the thread to go on.</p>
</li>
<li><b>Continue this cycle in an infinite loop until the debuggee process exits</b>.
Your program must be in an infinite loop much like a message loop until the
debuggee exits. The loop looks like this:
<p><b>.while TRUE<br>
invoke WaitForDebugEvent, addr DebugEvent, INFINITE<br>
.break .if DebugEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT<br>
<Handle the debug events><br>
invoke ContinueDebugEvent, DebugEvent.dwProcessId, DebugEvent.dwThreadId,
DBG_EXCEPTION_NOT_HANDLED <br>
.endw </b><br>
</p>
<p>Here's the catch: Once you start debugging a program, you just can't detach
from the debuggee until it exits.</p>
</li>
</ol>
<p>Let's summarize the steps again:</p>
<ol>
<li><b>Create a process or attach your program to a running process</b>.</li>
<li><b>Wait for debugging events</b></li>
<li><b>Do whatever your program want to do in response to the debug event</b>.</li>
<li><b>Let the debuggee continues execution</b>.</li>
<li><b>Continue this cycle in an infinite loop until the debuggee process exits</b></li>
</ol>
<h3>Example:</h3>
<p>This example debugs a win32 program and shows important information such as
the process handle, process Id, image base and so on.</p>
<p>.386 <br>
.model flat,stdcall <br>
option casemap:none <br>
include \masm32\include\windows.inc <br>
include \masm32\include\kernel32.inc <br>
include \masm32\include\comdlg32.inc <br>
include \masm32\include\user32.inc <br>
includelib \masm32\lib\kernel32.lib <br>
includelib \masm32\lib\comdlg32.lib <br>
includelib \masm32\lib\user32.lib <br>
.data <br>
AppName db "Win32 Debug Example no.1",0 <br>
ofn OPENFILENAME <> <br>
FilterString db "Executable Files",0,"*.exe",0 <br>
db
"All Files",0,"*.*",0,0 <br>
ExitProc db "The debuggee exits",0 <br>
NewThread db "A new thread is created",0 <br>
EndThread db "A thread is destroyed",0 <br>
ProcessInfo db "File Handle: %lx ",0dh,0Ah <br>
db "Process
Handle: %lx",0Dh,0Ah <br>
db "Thread
Handle: %lx",0Dh,0Ah <br>
db "Image
Base: %lx",0Dh,0Ah <br>
db "Start
Address: %lx",0 <br>
.data? <br>
buffer db 512 dup(?) <br>
startinfo STARTUPINFO <> <br>
pi PROCESS_INFORMATION <> <br>
DBEvent DEBUG_EVENT <> <br>
.code <br>
start: <br>
mov ofn.lStructSize,sizeof ofn <br>
mov ofn.lpstrFilter, offset FilterString <br>
mov ofn.lpstrFile, offset buffer <br>
mov ofn.nMaxFile,512 <br>
mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_EXPLORER
or OFN_HIDEREADONLY <br>
invoke GetOpenFileName, ADDR ofn <br>
.if eax==TRUE <br>
invoke GetStartupInfo,addr startinfo <br>
invoke CreateProcess, addr buffer, NULL, NULL, NULL, FALSE, DEBUG_PROCESS+ DEBUG_ONLY_THIS_PROCESS,
NULL, NULL, addr startinfo, addr pi <br>
.while TRUE <br>
invoke WaitForDebugEvent, addr DBEvent, INFINITE <br>
.if DBEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT <br>
invoke MessageBox, 0, addr ExitProc, addr
AppName, MB_OK+MB_ICONINFORMATION <br>
.break <br>
.elseif DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT <br>
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
<br>
invoke MessageBox,0, addr buffer, addr
AppName, MB_OK+MB_ICONINFORMATION <br>
.elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT <br>
.if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT
<br>
invoke ContinueDebugEvent,
DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE <br>
.continue <br>
.endif <br>
.elseif DBEvent.dwDebugEventCode==CREATE_THREAD_DEBUG_EVENT <br>
invoke MessageBox,0, addr NewThread, addr
AppName, MB_OK+MB_ICONINFORMATION <br>
.elseif DBEvent.dwDebugEventCode==EXIT_THREAD_DEBUG_EVENT <br>
invoke MessageBox,0, addr EndThread, addr
AppName, MB_OK+MB_ICONINFORMATION <br>
.endif <br>
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId,
DBG_EXCEPTION_NOT_HANDLED <br>
.endw <br>
invoke CloseHandle,pi.hProcess <br>
invoke CloseHandle,pi.hThread <br>
.endif <br>
invoke ExitProcess, 0 <br>
end start </p>
<h3>Analysis:</h3>
<p>The program fills the OPENFILENAME structure and then calls GetOpenFileName
to let the user choose a program to be debugged.</p>
<p>invoke GetStartupInfo,addr startinfo <br>
invoke CreateProcess, addr buffer, NULL, NULL, NULL, FALSE, DEBUG_PROCESS+ DEBUG_ONLY_THIS_PROCESS,
NULL, NULL, addr startinfo, addr pi </p>
<p>When the user chose one, it calls <b>CreateProcess</b> to load the program.
It calls <b>GetStartupInfo</b> to fill the <b>STARTUPINFO</b> structure with
its default values. Note that we use <b>DEBUG_PROCESS</b> combined with <b>DEBUG_ONLY_THIS_PROCESS</b>
flags in order to debug only this program, not including its child processes.</p>
<p>.while TRUE <br>
invoke WaitForDebugEvent, addr DBEvent, INFINITE <br>
</p>
<p>When the debuggee is loaded, we enter the infinite debug loop, calling <b>WaitForDebugEvent.</b>
<b>WaitForDebugEvent</b> will not return until a debug event occurs in the debuggee
because we specify <b>INFINITE</b> as its second parameter. When a debug event
occurred, <b>WaitForDebugEvent </b>returns and DBEvent is filled with information
about the debug event.</p>
<p> .if DBEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT <br>
invoke MessageBox, 0, addr ExitProc, addr
AppName, MB_OK+MB_ICONINFORMATION <br>
.break </p>
<p>We first check the value in <b>dwDebugEventCode</b>. If it's<b> EXIT_PROCESS_DEBUG_EVENT,</b>
we display a message box saying "The debuggee exits" and then get
out of the debug loop.</p>
<p> .elseif DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT
<br>
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
<br>
invoke MessageBox,0, addr buffer, addr
AppName, MB_OK+MB_ICONINFORMATION </p>
<p>If the value in <b>dwDebugEventCode</b> is <b>CREATE_PROCESS_DEBUG_EVENT</b>,
then we display several interesting information about the debuggee in a message
box. We obtain those information from <b>u.CreateProcessInfo</b>. CreateProcessInfo
is a structure of type <b>CREATE_PROCESS_DEBUG_INFO</b>. You can get more info
about this structure from Win32 API reference. </p>
<p> .elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT <br>
.if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT
<br>
invoke ContinueDebugEvent,
DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE <br>
.continue <br>
.endif </p>
<p>If the value in <b>dwDebugEventCode</b> is <b>EXCEPTION_DEBUG_EVENT</b>, we
must check further for the exact type of exception. It's a long line of nested
structure reference but you can obtain the kind of exception from <b>ExceptionCode</b>
member. If the value in <b>ExceptionCode</b> is <b>EXCEPTION_BREAKPOINT</b>
and it occurs for the first time (or if we are sure that the debuggee has no
embedded int 3h), we can safely assume that this exception occured when the
debuggee was going to execute its very first instruction. When we are done with
the processing, we must call <b>ContinueDebugEvent</b> with <b>DBG_CONTINUE</b>
flag to let the debuggee run. Then we go back to wait for the next debug event.</p>
<p> .elseif DBEvent.dwDebugEventCode==CREATE_THREAD_DEBUG_EVENT <br>
invoke MessageBox,0, addr NewThread, addr
AppName, MB_OK+MB_ICONINFORMATION <br>
.elseif DBEvent.dwDebugEventCode==EXIT_THREAD_DEBUG_EVENT <br>
invoke MessageBox,0, addr EndThread, addr
AppName, MB_OK+MB_ICONINFORMATION <br>
.endif </p>
<p>If the value in <b>dwDebugEventCode</b> is <b>CREATE_THREAD_DEBUG_EVENT</b>
or <b>EXIT_THREAD_DEBUG_EVENT</b>, we display a message box saying so.</p>
<p> invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId,
DBG_EXCEPTION_NOT_HANDLED <br>
.endw </p>
<p>Except for the<b> EXCEPTION_DEBUG_EVENT</b> case above, we call <b>ContinueDebugEvent</b>
with <b>DBG_EXCEPTION_NOT_HANDLED</b> flag to resume the debuggee.</p>
<p>invoke CloseHandle,pi.hProcess <br>
invoke CloseHandle,pi.hThread </p>
<p>When the debuggee exits, we are out of the debug loop and must close both process
and thread handles of the debuggee. Closing the handles doesn't mean we are
killing the process/thread. It just means we don't want to use those handles
to refer to the process/thread anymore. <strong> </strong></p>
<hr size="1">
<div align="center"> This article come from Iczelion's asm page, Welcom to <a href="http://asm.yeah.net">http://asm.yeah.net</a></div>
</body>
</html>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -