news 2026/4/16 8:45:19

汇编语言全接触-29.Win32调试API二

作者头像

张小明

前端开发工程师

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

我们继续Win32调试API的话题。在本章中,我们将要学习如何修改被调试程序。

下载 the example

理论:

在前面一章中,我们学会了如何装载被调试的进程以及如何处理进程中发生的事件。为了有实际用途,我们的程序应具有修改被调试程序的能力。有好几个API函数用于这一目的。

ReadProcessMemory该函数允许你去读指定的进程的内存。函数原型如下:

ReadProcessMemory proto hProcess:DWORD, lpBaseAddress:DWORD, lpBuffer:DWORD, nSize:DWORD, lpNumberOfBytesRead:DWORD

hProcess 待读进程的句柄.

lpBaseAddress 目标进程中待读内存起始地址。例如,如果你想要读目标 进程中从地址401000h开始的4个字节,该参数值应置为401000h。

lpBuffer 接收缓冲区地址

nSize 想要读的字节数。

lpNumberOfBytesRead 记录实际读取的字节数的变量地址。如果对这个值 不关心,填入NULL即可。

WriteProcessMemory 是对应于ReadProcessMemory的函数,通过它 可以写目标进程的内存。其参数和ReadProcessMemory 相同。

理解接下去的两个函数需要一些进程上下文的有关背景知识。在象Windows这样的 多任务操作系统中,同一时间里可能运行着几个程序。Windows分配给每个线程一个 时间片,当时间片结束后,Windows将冻结当前线程并切换到下一具有最高优先级的 线程。在切换之前,Windows将保存当前进程的寄存器的 内容,这样当在该线程再 次恢复运行时,Windows可以恢复最近一次线程运行的*环境*。保存的寄存器内容总 称为进程上下文。

现在回到我们的主题。当一个调试事件发生时,Windows暂停被调试进程,并保存其 进程上下文。由于进程被暂停运行,我们可以确信其进程上下文内容将保持不变。 可以用GetThreadContext来获取进程上下文内容,并且也可以用GetThreadContext 来修改进程上下文内容。

这两个函数威力非凡。有了他们,对被调试进程你就具有象VxD的能力: 如改变其寄 存器内容,而在被调试程序恢复运行前,这些值将会写回寄存器中。在进程上下文中 所做的任何改动,将都会反映到被调试程序中。想象一下: 甚至可以改变eip寄存器 的内容,这样你可以让程序运行到你想要的任何地方! 在正常情况下是不可能做到这 一点的。

GetThreadContext proto hThread:DWORD, lpContext:DWORD

hThread 你想要获得上下文的线程句柄

lpContext 函数成功返回时用来保存上下文内容的结构指针。

SetThreadContext 参数相同。让我们来看看上下文的结构:

CONTEXT STRUCT

ContextFlags dd ?

;----------------------------------------------------------------------------------------------------------

;当ContextFlags包含CONTEXT_DEBUG_REGISTERS,返回本部分

;-----------------------------------------------------------------------------------------------------------

iDr0 dd ?

iDr1 dd ?

iDr2 dd ?

iDr3 dd ?

iDr6 dd ?

iDr7 dd ?

;----------------------------------------------------------------------------------------------------------

;当ContextFlags包含CONTEXT_FLOATING_POINT,返回本部分

;-----------------------------------------------------------------------------------------------------------

FloatSave FLOATING_SAVE_AREA <>

;----------------------------------------------------------------------------------------------------------

;当ContextFlags包含CONTEXT_SEGMENTS,返回本部分

;-----------------------------------------------------------------------------------------------------------

regGs dd ?

regFs dd ?

regEs dd ?

regDs dd ?

;----------------------------------------------------------------------------------------------------------

;当ContextFlags包含CONTEXT_INTEGER,返回本部分

;-----------------------------------------------------------------------------------------------------------

regEdi dd ?

regEsi dd ?

regEbx dd ?

regEdx dd ?

regEcx dd ?

regEax dd ?

;----------------------------------------------------------------------------------------------------------

;当ContextFlags包含CONTEXT_CONTROL,返回本部分

;-----------------------------------------------------------------------------------------------------------

regEbp dd ?

regEip dd ?

regCs dd ?

regFlag dd ?

regEsp dd ?

regSs dd ?

;----------------------------------------------------------------------------------------------------------

;当ContextFlags包含CONTEXT_EXTENDED_REGISTERS,返回本部分

;-----------------------------------------------------------------------------------------------------------

ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?) CONTEXT ENDS

可以看出,该结构中的成员是对实际处理器的寄存器的模仿。在使用该结构之前 要在ContextFlags 中指定哪些寄存器组用来读写。如要访问所有的寄存器, 你可以置ContextFlags 为CONTEXT_FULL 。或者只访问regEbp, regEip, regCs, regFlag, regEsp 或 regSs, 应置ContextFlags 为 CONTEXT_CONTROL 。

在使用结构CONTEXT 时还应记住: 它必须是双字对齐的,否则在NT下将得 到奇怪的结果。可以在定义前加上"align dword"。例如:

align dword

MyContext CONTEXT <>

例:

第一个例子演示DebugActiveProcess的使用。首先,需要在Windows显示在屏幕上以前运行一个待调试程序win.exe,该程序将处于无限循环运行状态中。然后你运行例子程序,它将把自己与win.exe连接起来,并且修改win.exe的代码,这样win.exe将退出无限循环状态而显示自己的窗口。

.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.2",0

ClassName db "SimpleWinClass",0

SearchFail db "Cannot find the target process",0

TargetPatched db "Target patched!",0

buffer dw 9090h

.data?

DBEvent DEBUG_EVENT <>

ProcessId dd ?

ThreadId dd ?

align dword

context CONTEXT <>

.code

start:

invoke FindWindow, addr ClassName, NULL

.if eax!=NULL

invoke GetWindowThreadProcessId, eax, addr ProcessId

mov ThreadId, eax

invoke DebugActiveProcess, ProcessId

.while TRUE

invoke WaitForDebugEvent, addr DBEvent, INFINITE

.break .if DBEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT

.if DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT

mov context.ContextFlags, CONTEXT_CONTROL

invoke GetThreadContext,DBEvent.u.CreateProcessInfo.hThread, addr context

invoke WriteProcessMemory, DBEvent.u.CreateProcessInfo.hProcess, context.regEip ,addr buffer, 2, NULL

invoke MessageBox, 0, addr TargetPatched, addr AppName, MB_OK+MB_ICONINFORMATION

.elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT

.if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT

invoke ContinueDebugEvent, DBEvent.dwProcessId,DBEvent.dwThreadId, DBG_CONTINUE

.continue

.endif

.endif

invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED

.endw

.else

invoke MessageBox, 0, addr SearchFail, addr AppName,MB_OK+MB_ICONERROR .endif

invoke ExitProcess, 0

end start

;--------------------------------------------------------------------

; The partial source code of win.asm, our debuggee. It's actually

; the simple window example in tutorial 2 with an infinite loop inserted

; just before it enters the message loop.

;----------------------------------------------------------------------

......

mov wc.hIconSm,eax

invoke LoadCursor,NULL,IDC_ARROW

mov wc.hCursor,eax

invoke RegisterClassEx, addr wc

INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\ WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\ CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\ hInst,NULL

mov hwnd,eax

jmp $ <---- Here's our infinite loop. It assembles to EB FE

invoke ShowWindow, hwnd,SW_SHOWNORMAL

invoke UpdateWindow, hwnd

.while TRUE

invoke GetMessage, ADDR msg,NULL,0,0

.break .if (!eax)

invoke TranslateMessage, ADDR msg

invoke DispatchMessage, ADDR msg

.endw

mov eax,msg.wParam

ret

WinMain endp

分析:

invoke FindWindow, addr ClassName, NULL

我们的程序需要用DebugActiveProcess将自己绑定到被调试程序,这需要知道被调试程序的进程Id。用GetWindowThreadProcessId 可以得到该Id,该函数需要窗口句柄作为参数,因此首先需要知道窗口句柄。

用FindWindow, 我们先指定窗口类的名称,返回的是该类创建的窗口句柄。如 果返回NULL,则表明当前没有该类的窗口。

.if eax!=NULL

invoke GetWindowThreadProcessId, eax, addr ProcessId

mov ThreadId, eax

invoke DebugActiveProcess, ProcessId

得到进程Id后,我们调用DebugActiveProcess。这样就进入等待调试事件的循环中。

.if DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT

mov context.ContextFlags, CO

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

大模型进阶之路:RAG与DeepSeek技术融合与最佳实践(建议收藏)

简介 本文分析了RAG与DeepSeek的结合效果&#xff0c;通过法律领域实验发现&#xff1a;DeepSeek在推理生成阶段表现优异&#xff0c;但不适合检索任务&#xff0c;应与专业嵌入模型(如Qwen2)分工协作。这种组合在需要强推理和高可追溯性的场景(如法律咨询)有潜力&#xff0c;关…

作者头像 李华
网站建设 2026/4/16 8:43:44

【Flink】Flink架构深度剖析:JobManager与TaskManager

Flink架构深度剖析&#xff1a;JobManager与TaskManager 前言 上一篇我们成功跑起了第一个 Flink 程序&#xff0c;但你有没有想过&#xff1a;当你点击"运行"后&#xff0c;代码是怎么被执行的&#xff1f;数据是怎么在多个节点之间流动的&#xff1f; 这篇文章我…

作者头像 李华
网站建设 2026/4/16 10:14:18

(21)手写Spring框架

Spring IoC容器的实现原理&#xff1a;工厂模式 解析XML 反射机制。 我们给自己的框架起名为&#xff1a;myspring&#xff08;我的春天&#xff09; 第一步&#xff1a;创建模块myspring 采用Maven方式新建Module&#xff1a;myspring打包方式采用jar&#xff0c;并且引入do…

作者头像 李华
网站建设 2026/4/16 10:17:52

MATLAB中两种常用的纹理特征提取方法:灰度共生矩阵和灰度差分统计

1. 灰度共生矩阵 灰度共生矩阵是迄今为止最经典、最常用的纹理分析方法。它通过计算图像中特定方向和距离的像素对出现的频率来描述纹理。 原理简介 GLCM是一个方阵&#xff0c;其大小由图像的最大灰度级决定。矩阵中的元素 P(i, j | d, θ) 表示在给定空间距离 d 和方向 θ 时…

作者头像 李华
网站建设 2026/4/16 13:41:51

2025年12月9日,OpenAI发布ChatGPT-5.2:未来已经到来,AI改变生活

2025年12月9日&#xff0c;OpenAI迎来了一个重磅发布——ChatGPT-5.2。作为继ChatGPT-5.0之后的又一重要版本更新&#xff0c;5.2不仅带来了更强的技术功能&#xff0c;还让人工智能在各个领域的应用变得更加深入人心。通过强大的多模态能力、超高的情感理解、无缝的跨行业适配…

作者头像 李华
网站建设 2026/4/16 7:03:57

.NET 10 网络堆栈深度架构解析:HTTP/3、性能优化与后量子加密的融合演进

T 10 的发布&#xff0c;微软不仅是在更新一个开发框架&#xff0c;更是在重新定义云原生时代的网络通信标准。本次更新的核心理念紧扣“更现代、更高效、更开发者友好”的三大支柱&#xff0c;标志着.NET 网络堆栈从传统的 TCP/IP 依赖向以 UDP 为基础的 QUIC 协议、后量子加密…

作者头像 李华