📄 lion-tut-c28.htm
字号:
<调试事件处理><br>
invoke ContinueDebugEvent, DebugEvent.dwProcessId, DebugEvent.dwThreadId,
DBG_EXCEPTION_NOT_HANDLED <br>
.endw </b><br>
</p>
<p>就是说,当开始调试程序时,我们的程序不能和debuggee分开直到它结束.</p>
</li>
</ol>
<p>我们再来总结一下这些步骤:</p>
<ol>
<li><b>创建一个进程或捆绑我们的程序到运行中的进程上</b>.</li>
<li><b>等待调试事件</b></li>
<li><b>响应调试事件</b>.</li>
<li><b>继续执行debuggee</b>.</li>
<li><b>继续这一无尽循环直到debuggee进程结束</b></li>
</ol>
<h3>例子:</h3>
<p>这个例子调试一个win32程序并显示诸如进程句柄,进程Id,映象基址等.</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>分析:</h3>
<p>程序首先填充OPENFILENAME结构,调用GetOpenFileName让用户选择要调试的程序.</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>当接收用户选择后,调用<b>CreateProcess</b>装载程序.并调用<b>GetStartupInfo</b>以默认值填充<b>STARTUPINFO</b>结构.注意我们将<b>DEBUG_PROCESS</b>标志与<b>DEBUG_ONLY_THIS_PROCESS</b>标志组合来仅调试这个程序,不包括子进程.</p>
<p>.while TRUE <br>
invoke WaitForDebugEvent, addr DBEvent, INFINITE <br>
</p>
<p>在debuggee被装入后,我们调用<b>WaitForDebugEvent</b>进入无尽的调试循环,<b>WaitForDebugEvent</b>在debuggee中发生调试事件时返回,因为我们指定了<b>INFINITE</b>作为第二个参数.当调试事件发生时,
<b>WaitForDebugEvent </b>返回并填充DBEvent结构.</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>我们要先检查<b>dwDebugEventCode</b>的值, 如果是<b>EXIT_PROCESS_DEBUG_EVENT,</b>用一个消息框显示"The
debuggee exits" 并退出调试循环.</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>如果<b>dwDebugEventCode</b> 的值为<b>CREATE_PROCESS_DEBUG_EVENT</b>,我们就在消息框中显示一些感兴趣的底层信息.这些信息从<b>u.CreateProcessInfo</b>获得.
CreateProcessInfo是一个<b>CREATE_PROCESS_DEBUG_INFO</b>类型的结构体.你可以查阅Win32 API获得它的更多信息e.
</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>如果<b>dwDebugEventCode</b> 的值为<b>EXCEPTION_DEBUG_EVENT</b>,我们就要更进一步检查异常类型.它是一大堆的结构嵌套,但我们可以从<b>ExceptionCode</b>成员获得异常类型.如果<b>ExceptionCode</b>的值为
<b>EXCEPTION_BREAKPOINT</b>并且是第一次发生(或者我们已知道deuggee中没有int 3h指令),我们可以安全地假定在debuggee要执行第一条指令时发生这一异常.在我们完成这些处理后,就可以用
<b>DBG_CONTINUE</b>调用<b>ContinueDebugEvent</b>来继续执行debuggee.接着我们继续等待下一个调试事件的发生.</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>如果<b>dwDebugEventCode</b> 的值为<b>CREATE_THREAD_DEBUG_EVENT</b>或<b>EXIT_THREAD_DEBUG_EVENT</b>,
我们的程序显示一个消息框.</p>
<p> invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId,
DBG_EXCEPTION_NOT_HANDLED <br>
.endw </p>
<p>除了上面讨论过的<b> EXCEPTION_DEBUG_EVENT</b>,用<b>DBG_EXCEPTION_NOT_HANDLED</b>标志调用<b>ContinueDebugEvent</b>函数恢复debuggee的执行.</p>
<p>invoke CloseHandle,pi.hProcess <br>
invoke CloseHandle,pi.hThread </p>
<p>当debuggee结束时,我们就跳出了调试循环,这时要关闭 debuggee的线程和进程句柄.关闭这些句柄并不意味着要关闭这些进程和线程.只是说不再用这些句柄罢了.
</p>
<HR SIZE=1>
<DIV align=center>
<SCRIPT language=JavaScript1.1 src="../lion-tut-c13.files/textclick"></SCRIPT>
<BR>
</DIV>
<!-- 10:1 文本广告交换 -->
<DIV align=center>
<SCRIPT language=JavaScript1.1 src="../lion-tut-c13.files/c21.htm"></SCRIPT>
<!-- 10:1 文本广告交换 --></DIV>
<HR SIZE=1>
<DIV align=center>校对:LuoYunBin's Win32 ASM Page, <A
href="http://asm.yeah.net/">http://asm.yeah.net</A></DIV>
</BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -