news 2026/4/22 16:01:09

汇编语言全接触-30.Win32调试API三

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
汇编语言全接触-30.Win32调试API三

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

下载 例子.

理论:

如果你以前使用过调试器,那么你应对跟踪比较熟悉。当"跟踪"一个程序时,程序在每执行一条指令后将会停止,这使你有机会去检查寄存器/内存中的值。这种单步运行的官方定义为跟踪(tracing)。

单步运行的特色是由CPU本身提供的。标志寄存器的第8位称为陷阱标志trap flag。如果该位设置,则CPU运行于单步模式。CPU将在每条指令后产生一个debug异常。当debug 异常产生后,陷阱标志自动清除。利用win32调试api,我们也可以单步运行被调试程序。方法如下:

调用GetThreadContext, 指定 ContextFlags为CONTEXT_CONTROL, 来获得标志寄存器的值

设置CONTEXT结构成员标志寄存器regFlag中的陷阱标志位

调用 SetThreadContext

等待调式事件。被调试程序将按单步模式执行,在每执行一条指令后,我们将得到调试 事件,u.Exception.pExceptionRecord.ExceptionCode值为EXCEPTION_SINGLE_STEP

如果要跟踪下一条指令,需要再次设置陷阱标志位。

例:

.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 多分钟才能关闭被调试程序。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/20 1:07:30

C语言中以坐标的方式图解“字母金字塔”的绘制

目录题目题目解析题目理解空格图-坐标解析字母递增图-坐标解析字母递减图-坐标解析代码汇总验证代码汇总终端运行验证坐标图解法的好处建议好处题目 实现字母金字塔&#xff0c;通过键盘输入字符来控制层数&#xff0c;如输入D&#xff0c;则打印下面图形 AABAABCBAABCDCBA题目…

作者头像 李华
网站建设 2026/4/21 5:16:53

Q CLI 助力合合信息实现 Aurora 的升级运营

1. 升级背景 合合信息是一家中国领先的人工智能(AI)产品公司&#xff0c;一直致力于通过AI技术赋能创新&#xff0c;为全球数亿用户和多元化行业提供产品服务。凭借超过18年的AI研究和应用专业知识&#xff0c;合合信息已成为全球多模态大模型文本智能技术的领先者&#xff0c…

作者头像 李华
网站建设 2026/4/18 13:06:32

PDF对比终极指南:三步快速定位文档差异

PDF对比终极指南&#xff1a;三步快速定位文档差异 【免费下载链接】diff-pdf A simple tool for visually comparing two PDF files 项目地址: https://gitcode.com/gh_mirrors/di/diff-pdf 在文档处理工作中&#xff0c;PDF对比是每个职场人士都会遇到的常见需求。无论…

作者头像 李华
网站建设 2026/4/19 15:16:00

OBS Studio直播画质提升实战指南:7个立竿见影的设置技巧

OBS Studio直播画质提升实战指南&#xff1a;7个立竿见影的设置技巧 【免费下载链接】obs-studio 项目地址: https://gitcode.com/gh_mirrors/obs/obs-studio 想要实现专业级的直播画质&#xff0c;OBS Studio直播优化和推流质量提升是每个主播必须掌握的技能。无论是直…

作者头像 李华
网站建设 2026/4/20 22:20:02

PostgreSQL vs MySQL:工程视角下的数据库选型终极指南

PostgreSQL vs MySQL 数据库选型终极指南(生产级实战版) 数据库选型不是功能清单的比拼,而是对业务复杂度、团队能力与未来不确定性的判断。 在实际项目中,“到底选 PostgreSQL 还是 MySQL”几乎是每个技术团队都会遇到的经典问题。它表面看是数据库对比,实质上是工程哲学…

作者头像 李华
网站建设 2026/4/20 12:15:45

构建AI知识库助手:LobeChat与RAG技术集成方案

构建AI知识库助手&#xff1a;LobeChat与RAG技术集成方案 在企业数字化转型加速的今天&#xff0c;员工每天面对海量文档、政策手册和内部知识库&#xff0c;却常常“知道信息存在&#xff0c;但找不到答案”。传统搜索引擎返回的是链接列表&#xff0c;而通用大模型如ChatGPT虽…

作者头像 李华