WIN32汇编: 30.Win32调试API第三部分

原创 2001年06月17日 20:32:00

第30课: Win32调试API 第三部分


在本章中,我们将继续探讨win32调试api。特别地,我们将学习如何去跟踪被调试程序.
下载 例子.

理论:

如果你以前使用过调试器,那么你应对跟踪比较熟悉。当"跟踪"一个程序时,程序在每执行一条指令后将会停止,这使你有机会去检查寄存器/内存中的值。这种单步运行的官方定义为跟踪(tracing)。
单步运行的特色是由CPU本身提供的。标志寄存器的第8位称为陷阱标志trap flag。如果该位设置,则CPU运行于单步模式。CPU将在每条指令后产生一个debug异常。当debug 异常产生后,陷阱标志自动清除。利用win32调试api,我们也可以单步运行被调试程序。方法如下:

  1. 调用GetThreadContext, 指定 ContextFlagsCONTEXT_CONTROL, 来获得标志寄存器的值
  2. 设置CONTEXT结构成员标志寄存器regFlag中的陷阱标志位
  3. 调用 SetThreadContext
  4. 等待调式事件。被调试程序将按单步模式执行,在每执行一条指令后,我们将得到调试 事件,u.Exception.pExceptionRecord.ExceptionCode值为EXCEPTION_SINGLE_STEP
  5. 如果要跟踪下一条指令,需要再次设置陷阱标志位。

例:

.386
.model flat,stdcall
option casemap:none
include /masm32/include/windows.inc
include /masm32/include/kernel32.inc
include /masm32/include/comdlg32.inc
include /masm32/include/user32.inc
includelib /masm32/lib/kernel32.lib
includelib /masm32/lib/comdlg32.lib
includelib /masm32/lib/user32.lib

.data
AppName db "Win32 Debug Example no.4",0
ofn OPENFILENAME <>
FilterString db "Executable Files",0,"*.exe",0
             db "All Files",0,"*.*",0,0
ExitProc db "The debuggee exits",0Dh,0Ah
         db "Total Instructions executed : %lu",0
TotalInstruction dd 0

.data?
buffer db 512 dup(?)
startinfo STARTUPINFO <>
pi PROCESS_INFORMATION <>
DBEvent DEBUG_EVENT <>
context CONTEXT <>

.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, INFINITE
       .if DBEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT
          invoke wsprintf, addr buffer, addr ExitProc, TotalInstruction
          invoke MessageBox, 0, addr buffer, addr AppName, MB_OK+MB_ICONINFORMATION
          .break
       .elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT           .if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT
             mov context.ContextFlags, CONTEXT_CONTROL
             invoke GetThreadContext, pi.hThread, addr context
             or context.regFlag,100h
             invoke SetThreadContext,pi.hThread, addr context
             invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE
             .continue
          .elseif DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_SINGLE_STEP
             inc TotalInstruction
             invoke GetThreadContext,pi.hThread,addr context or context.regFlag,100h
             invoke SetThreadContext,pi.hThread, addr context
             invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId,DBG_CONTINUE
             .continue
          .endif
       .endif
       invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED
    .endw
.endif
invoke CloseHandle,pi.hProcess
invoke CloseHandle,pi.hThread
invoke ExitProcess, 0
end start

分析:

该程序先显示一个打开文件对话框,当用户选择了一个可执行文件,它将单步执行该程序,并记录执行的指令数,直到被调试程序退出运行。

       .elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT           .if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT

利用该机会来设置被调试程序为单步运行模式。记住,在执行被调试程序的第一条指令前 windows将发送一个EXCEPTION_BREAKPOINT消息。

             mov context.ContextFlags, CONTEXT_CONTROL
             invoke GetThreadContext, pi.hThread, addr context

调用GetThreadContext,以被调试程序的当前寄存器内容来填充CONTEXT 结构 特别地,我们需要标志寄存器的当前值。

             or context.regFlag,100h

设置标志寄存器映象的陷阱位(第8位)

             invoke SetThreadContext,pi.hThread, addr context
             invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE
             .continue

然后调用SetThreadContext去覆盖CONTEXT的值。再以DBG_CONTINUE调用 ContinueDebugEvent 来恢复被调试程序的运行。

          .elseif DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_SINGLE_STEP
             inc TotalInstruction

当调试程序中一条指令执行后,我们将接收到EXCEPTION_DEBUG_EVENT的调试事件, 必须要检查u.Exception.pExceptionRecord.ExceptionCode的值。如果该值为 EXCEPTION_SINGLE_STEP,那么,该调试事件是单步运行模式造成的。在这种情况 下,TotalInstruction加一,因为我们确切地知道此时被调试程序执行了一条指令。

             invoke GetThreadContext,pi.hThread,addr context or context.regFlag,100h
             invoke SetThreadContext,pi.hThread, addr context
             invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId,DBG_CONTINUE
             .continue

由于陷阱标志在debug异常后自动清除了,如果我们需要继续保持单步运行模式,则必须设置陷阱标志位。
警告: 不要用本教程中的此例子来调试大程序: 跟踪是很慢的。你或许需要等待10 多分钟才能关闭被调试程序。

WIN32汇编: 28.Win32调试API第一部分

第二十八课: Win32调试API 第一部分 在本教程中,我们将学习Win32提供给开发者的用于调试的原语. 在教程的结尾,我们将学习如何调试一个进程. 下载 例子程序.理论:Win32有一些供程序员...
  • GodDragon
  • GodDragon
  • 2001年06月17日 20:30
  • 1978

WIN32汇编: 29.Win32调试API第二部分

第29课: Win32调试API 第二部分我们继续Win32调试API的话题。在本章中,我们将要学习如何修改被调试程序。下载 the example 理论:在前面一章中,我们学会了如何装载被调试的进程...
  • GodDragon
  • GodDragon
  • 2001年06月17日 20:31
  • 1985

Win32汇编 API的调用

Win32汇编 API的调用
  • cay22
  • cay22
  • 2011年04月16日 11:04
  • 3805

现在该不该学习Win 32 API和汇编?

现在该不该学习Win 32 API和汇编?——《.NET 2.0面向对象编程揭秘》勘误兼回答读者问题本书出版以来,陆续收到了一些读者的邮件,或者探讨技术,或者指出疏漏。感谢热心而且细心的读者,你们对技...
  • bitfan
  • bitfan
  • 2008年04月14日 09:38
  • 8994

Win32汇编语言学习笔记>>第二课:编写第一个Win32汇编程序

本节课主要是编译连接一段写好的代码: 程序运行如下: 代码: .386 .model flat,stdcall option casemap:none include C:\mas...
  • eldn__
  • eldn__
  • 2013年01月01日 12:33
  • 1336

Win32调试API学习心得(一)

    最近学习了一下WIN32的调试API,并做了一个简单的调试器,略有心得,特写出来希望对需要的朋友有所帮助.参考资料:lczlion:>               彭春华:>概述:   Win...
  • pankun
  • pankun
  • 2003年08月24日 15:33
  • 1603

使用WIN32汇编语言实现一个基本windows窗口的过程分析

一个常规的windows窗口一般都是一些一样的构造,你如果想要更改一些个性化的设置,你可以在这个一般的模板伤添砖加瓦,构造自己比较喜欢的类型,下边就分析一下一般的windows窗口的一般模板。 一...
  • qq_22642239
  • qq_22642239
  • 2016年03月07日 20:55
  • 2468

Win32汇编控制台下的几种输入输出方式

以下文章转自别人的帖子:在熟悉指令、伪指令和汇编语法的过程中, 首先需要的是输入、输出的手段.下面是之前尝试出的控制台输入、输出的几种办法:1、使用 MASM 提供的 StdIn、StdOut 函数;...
  • jiangtongcn
  • jiangtongcn
  • 2011年02月24日 15:33
  • 2963

Win32学习笔记 - WNDCLASSEX结构体

typedef struct _WNDCLASSEX { UINT cbSize; //结构体的大小 ...
  • u011471873
  • u011471873
  • 2016年03月07日 20:54
  • 568

win32汇编-使用子程序以及堆栈平衡原理

子程序名 proc [距离][语言类型][可视区域][USES寄存器列表][,参数:类型]...[VARARG] local 局部变量列表 指令 子程序名 endp 距离:可以使ne...
  • u012997311
  • u012997311
  • 2017年07月14日 16:41
  • 193
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:WIN32汇编: 30.Win32调试API第三部分
举报原因:
原因补充:

(最多只允许输入30个字)