Windows平台调试器原理与编写01.调试框架

news/2025/2/22 13:40:55/文章来源:https://www.cnblogs.com/weiyuanzhang/p/18730813

调试器原理与编写01.调试框架-C/C++基础-断点社区-专业的老牌游戏安全技术交流社区 - BpSend.net

调试框架

调试器最基本功能: 断点,单步

断点分为三类

  1. 软件断点
  2. 硬件断点
  3. 内存断点

window提供了一套机制,帮助用户来实现一套3环的调试器

事件驱动 : 窗口的各种操作(外在的想要对窗口做一下改动,例如点击菜单,点击按钮,按下键盘等)

消息响应 : 这些事件会被封装成结构体,叫做消息

调试器也是类似,调试器有各种跟调试相关的事情发生,这些事情会被封装成一个个结构体传给我们,我们只需要一直处理这样一个个的结构体的信息,这些结构体就是调试事件,调试事件 90% 都是处理异常,调试器本身就是依托于系统的异常机制实现的

步骤

建立调试会话

当调试器开始调试另一个进程的时候称为调试会话的建立,当调试器没有调试进程时,就叫没有调试会话

调试器建立会话的2种方式

启动 CreateProcess

img

调试标志主要2种

img

附加 DebugActiveProcess

img

脱离 DebugActiveProcessStop
结束调试,但是被调试的进程仍然运行,一般用于测试调试时修改的有没有效果,大部分时候用不到

img

循环接受调试事件
WaitForDebugEvent

img

超时时间 : INFINITE 一直等待,只能使用控制台程序 ,不能用于窗口程序

img

img

处理调试事件
提交处理结果

结果提交给系统

当调试器调试进程时, 被调试进程处于挂起状态,当调试事件处理完之后,被调试进程是处于运行还是挂起要看我们的操作,返回结果就是告诉系统 被调试进程 是 继续挂起还是运行

ContinueDebugEvent

img

第3个参数: 继续状态

DBG_CONTINUE 继续运行(如果异常应该状态表示异常已处理,进程继续运行)

DBG_EXCEPTION_NOT_HANDLED 只对异常事件有用

代码实现

新建工程

img

完成代码
.386
.model flat, stdcall
option casemap:noneinclude windows.inc
include user32.inc
include kernel32.inc
include msvcrt.incincludelib user32.lib
includelib kernel32.lib
includelib msvcrt.lib.datag_szExe db "winmine.exe",0  ;被调试的进程g_szEXCEPTION_DEBUG_EVENT           db "EXCEPTION_DEBUG_EVENT",0dh,0ah, 0g_szCREATE_THREAD_DEBUG_EVENT       db "CREATE_THREAD_DEBUG_EVENT",0dh,0ah,0g_szCREATE_PROCESS_DEBUG_EVENT      db "CREATE_PROCESS_DEBUG_EVENT",0dh,0ah, 0g_szEXIT_THREAD_DEBUG_EVENT         db "EXIT_THREAD_DEBUG_EVENT",0dh,0ah, 0g_szEXIT_PROCESS_DEBUG_EVENT        db "EXIT_PROCESS_DEBUG_EVENT",0dh,0ah, 0g_szLOAD_DLL_DEBUG_EVENT            db "LOAD_DLL_DEBUG_EVENT" , 0dh,0ah, 0g_szUNLOAD_DLL_DEBUG_EVENT          db "UNLOAD_DLL_DEBUG_EVENT" , 0dh,0ah, 0g_szOUTPUT_DEBUG_STRING_EVENT       db "OUTPUT_DEBUG_STRING_EVENT" , 0dh,0ah, 0.codemain procLOCAL  @si:STARTUPINFOLOCAL  @pi:PROCESS_INFORMATION LOCAL  @de:DEBUG_EVENT  ;这个结构体使用后需要清0;初始化变量invoke  RtlZeroMemory,addr @si, size @siinvoke  RtlZeroMemory,addr @pi, size @piinvoke  RtlZeroMemory,addr @de, size @de  ;建立调试会话invoke CreateProcess,NULL,offset g_szExe,NULL,NULL,NULL,\DEBUG_ONLY_THIS_PROCESS,NULL,NULL,addr @si,addr @pi.if !eaxret  ;建立调试会话失败直接退出.endif ;循环接受调试事件.while  TRUEinvoke WaitForDebugEvent,addr @de,INFINITE;处理调试事件.if @de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT           ;异常 90%都是在处理这个invoke crt_printf, offset g_szEXCEPTION_DEBUG_EVENT.elseif @de.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT   ;创建线程invoke crt_printf, offset g_szCREATE_THREAD_DEBUG_EVENT.elseif @de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT  ;创建进程invoke crt_printf, offset g_szCREATE_PROCESS_DEBUG_EVENT.elseif @de.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT     ;线程退出invoke crt_printf, offset g_szEXIT_THREAD_DEBUG_EVENT .elseif @de.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT    ;进程退出invoke crt_printf, offset g_szEXIT_PROCESS_DEBUG_EVENT           .elseif @de.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT        ;dll被加载invoke crt_printf, offset g_szLOAD_DLL_DEBUG_EVENT  .elseif @de.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT      ;dll被卸载invoke crt_printf, offset g_szUNLOAD_DLL_DEBUG_EVENT            .elseif @de.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT      ;输出信息invoke crt_printf, offset g_szOUTPUT_DEBUG_STRING_EVENT .endif;提交事件处理结果invoke ContinueDebugEvent,@de.dwProcessId,@de.dwThreadId,DBG_CONTINUE;DEBUG_EVENT结构体使用后清0invoke  RtlZeroMemory,addr @de, size @de  .endwretmain endpstart:invoke mainend start
处理 LOAD_DLL_DEBUG_EVENT 事件

img

img

img

img

img

img

用winhex 打开 该id 进程,查看内存数据 发现还是搜不到

img

img

img

发现是系统dll,再看一下后面的

img

img

img

在F9执行几次,发现地址是固定的,但是指针指向的dll 会发生变化

img

所以 lpImageName 存储的是一个二级指针, 拿到 dll 地址就必须跨进程读写内存,但是第一个dll (ntdll.dll)例外,没办法拿到数据

.386
.model flat, stdcall
option casemap:noneinclude windows.inc
include user32.inc
include kernel32.inc
include msvcrt.incincludelib user32.lib
includelib kernel32.lib
includelib msvcrt.lib.datag_szExe db "winmine.exe",0  ;被调试的进程g_hExe dd  0               ;进程句柄g_szEXCEPTION_DEBUG_EVENT           db "EXCEPTION_DEBUG_EVENT",0dh,0ah, 0g_szCREATE_THREAD_DEBUG_EVENT       db "CREATE_THREAD_DEBUG_EVENT",0dh,0ah,0g_szCREATE_PROCESS_DEBUG_EVENT      db "CREATE_PROCESS_DEBUG_EVENT",0dh,0ah, 0g_szEXIT_THREAD_DEBUG_EVENT         db "EXIT_THREAD_DEBUG_EVENT",0dh,0ah, 0g_szEXIT_PROCESS_DEBUG_EVENT        db "EXIT_PROCESS_DEBUG_EVENT",0dh,0ah, 0g_szLOAD_DLL_DEBUG_EVENT            db "LOAD_DLL_DEBUG_EVENT" , 0dh,0ah, 0g_szUNLOAD_DLL_DEBUG_EVENT          db "UNLOAD_DLL_DEBUG_EVENT" , 0dh,0ah, 0g_szOUTPUT_DEBUG_STRING_EVENT       db "OUTPUT_DEBUG_STRING_EVENT" , 0dh,0ah, 0g_szLoadDllFmt   db "%08X  %s", 0dh,0ah, 0g_szwLoadDllFmt  dw '%','0','8','X',' ', '%','s', 0dh,0ah, 0.codeOnLoadDll proc uses esi pDE:ptr DEBUG_EVENTLOCAL  @dwAddr:DWORDLOCAL  @dwByteReaded:DWORDLOCAL  @szwPath[512]:WORDinvoke crt_printf, offset g_szLOAD_DLL_DEBUG_EVENT  invoke  RtlZeroMemory,addr @szwPath, size @szwPathmov esi,pDEassume esi: ptr DEBUG_EVENTinvoke ReadProcessMemory,g_hExe,[esi].u.LoadDll.lpImageName,addr @dwAddr, size @dwAddr,addr  @dwByteReaded.if !eaxret  .endif invoke ReadProcessMemory,g_hExe, @dwAddr ,addr @szwPath, sizeof  @szwPath,addr  @dwByteReaded.if !eaxret  .endif .if [esi].u.LoadDll.fUnicode   ;如果是 unicodeinvoke crt_wprintf, offset g_szwLoadDllFmt,[esi].u.LoadDll.lpBaseOfDll,addr @szwPath.elseifinvoke crt_printf, offset g_szwLoadDllFmt,[esi].u.LoadDll.lpBaseOfDll,addr @szwPath.endifassume esi:nothingretOnLoadDll endpmain procLOCAL  @si:STARTUPINFOLOCAL  @pi:PROCESS_INFORMATION LOCAL  @de:DEBUG_EVENT  ;这个结构体使用后需要清0;初始化变量invoke  RtlZeroMemory,addr @si, size @siinvoke  RtlZeroMemory,addr @pi, size @piinvoke  RtlZeroMemory,addr @de, size @de  ;建立调试会话invoke CreateProcess,NULL,offset g_szExe,NULL,NULL,NULL,\DEBUG_ONLY_THIS_PROCESS,NULL,NULL,addr @si,addr @pi.if !eaxret  ;建立调试会话失败直接退出.endif mov eax,@pi.hProcessmov g_hExe,eax;循环接受调试事件.while  TRUEinvoke WaitForDebugEvent,addr @de,INFINITE;处理调试事件.if @de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT           ;异常 90%都是在处理这个invoke crt_printf, offset g_szEXCEPTION_DEBUG_EVENT.elseif @de.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT   ;创建线程invoke crt_printf, offset g_szCREATE_THREAD_DEBUG_EVENT.elseif @de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT  ;创建进程invoke crt_printf, offset g_szCREATE_PROCESS_DEBUG_EVENT.elseif @de.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT     ;线程退出invoke crt_printf, offset g_szEXIT_THREAD_DEBUG_EVENT .elseif @de.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT    ;进程退出invoke crt_printf, offset g_szEXIT_PROCESS_DEBUG_EVENT           .elseif @de.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT        ;dll被加载;invoke crt_printf, offset g_szLOAD_DLL_DEBUG_EVENT  invoke OnLoadDll,addr @de.elseif @de.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT      ;dll被卸载invoke crt_printf, offset g_szUNLOAD_DLL_DEBUG_EVENT            .elseif @de.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT      ;输出信息invoke crt_printf, offset g_szOUTPUT_DEBUG_STRING_EVENT .endif;提交事件处理结果invoke ContinueDebugEvent,@de.dwProcessId,@de.dwThreadId,DBG_CONTINUE;DEBUG_EVENT结构体使用后清0invoke  RtlZeroMemory,addr @de, size @de  .endwretmain endpstart:invoke mainend start

NtQueryProcessInfomation 获取进程信息

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/887986.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

本地部署DeepSeek-R1-AWQ

一、部署环境准备 系统信息:主机名为 10-200-3-23 IP 地址为 10.200.3.23 操作系统为 ubuntu 22.04 配备 8 卡 A100。二、驱动与桥接器安装安装 gcc执行命令 apt-get update -y apt install build-essential -y安装驱动下载驱动 wget https://us.download.nvidia.com/tesla/…

k8s部署nfs+sc

1.下载软件包nfs-subdir-external-provisioner-4.0.18.tgz 该软件包内文件截图 修改values.yaml 在目录内执行 helm install nfs-provisioner -f values.yaml . #老重要了2.查看执行是否成功 3.测试是否成功 编写yaml apiVersion: v1kind: PersistentVolumeClaimmetadata…

P2661 [NOIP 2015 提高组] 信息传递——染色做法

原题 本来想当水题刷的,结果被水题刷了。。。70到80到90到100,必须写个题解记录一下(doge) 题目分析一句话:求一个无权有向图中的最短环路(确保有环) tip:每一个点出度为一,那么必然有环,以样例为例如下。思路没必要每轮模拟全部的传送,只看某一个人的传送过程: 就…

有哪些好用的AI工具?(你想要的AI工具都在这)

1. 常见应用场景 1.1. 国内通用大模型模型名称 简介 官网地址DeepSeek 深度求索公司研发的高性能开源模型,以低成本、高推理能力著称,支持数学、代码等复杂任务。 https://chat.deepseek.com/豆包 字节跳动开发的智能语言模型,基于深度学习技术,支持多种自然语言处理任务。…

Kubernetes 集群上部署 Open WebUI

在前一篇博文中记录了 k8s 集群上部署 ollama + deepseek-r1:7b,这篇博文记录一下 Open WebUI 的部署。还是用 helm 部署,添加 open-webui 的 helm repo,准备 helm 清单文件,通过 helm 命令在 ai 命名空间下进行部署在前一篇博文中记录了 k8s 集群上部署 ollama + deepseek…

2025.2.22

Hehe_0 模拟赛内容随笔 [NOIP2015]金币1 2 3 4 。。。1 2-3 4-6 7-10 。。。观察数据范围1e4,暴力就行,然后可以去思考优化版本 由于已经把规律给出来了,所以可以提前离线处理出来,如果数据过大,可以预处理每一次金币变化的天数,然后根据提问二分找区间然后求和。这种数…

充电桩功能扩展,解决桩企内存不足的问题

OCPP(开放充电点协议)1.6是电动汽车充电基础设施中广泛使用的通信标准。尽管OCPP 1.6为充电桩与中央管理系统(CSMS)之间的交互提供了基本功能,但由于OCPP主板的内存资源有限,其能够实现的功能也受到了一定的限制。为了解决这一问题,OCPP协议网关作为OCPP主板的扩展,能够…

Spring复习-AOP

AOP的概念 AOP,Aspect Oriented Programming,面向切面编程,是对面向对象编程OOP的升华。OOP是纵向对一个事物的抽象,一个对象包括静态的属性信息,包括动态的方法信息等。而AOP是横向的对不同事物的抽象,属性与属性、方法与方法、对象与对象都可以组成一个切面,而用这种思…

Univer sheet加载上下文菜单卡死崩溃问题定位

背景: 我的应用技术栈是Vue3,Univer是基于react的,所以定位问题花了很久,在此记录一下查问题的方式。 使用Chrome DevTools的Performance进行录制,复现卡死操作后,在Performance Monitr中可以看到CPU Usage持续100%,且页面重计算次数持续飙高。由于页面卡死,Performanc…

乐园杂音

沟槽的杉井光为什么还不填坑! 其实兔子最早看的一批轻小说就有乐杂,但是那时候没有写读后感的习惯,现在重刷一遍乐杂,就顺便写一下读后感。兔子每次给别人看这张图都会让他们猜女主是谁。 其实吧,虽然普遍认为《离别的钢琴奏鸣曲》比《乐园杂音》写的要好,但是兔子更喜欢…

一张图搞懂支付账务

会计与程序语言虽不同,却能从相同维度描绘业务场景。如何利用这一原理,拆解支付账务的科目设置、对账与核算流程,建立起清晰的账务处理逻辑?让我们一起一探究竟。学习账务的时候你是否经常有这些疑问“待结算和待清算是什么?为什么要有已清算?待结算和待清算是一回事吗?…

Diffusion-DPO:一种基于直接偏好优化的扩散模型对齐新方法

本文介绍了一种名为 Diffusion-DPO 的方法,该方法改编自最近提出的直接偏好优化 (DPO)。DPO 作为 RLHF 的简化替代方案,通过分类目标直接优化策略,以更好地满足人类偏好。诸如 GPT-4 和 Llama 2 等高性能大型语言模型 (LLM) 的训练通常分为两个阶段:https://avoid.overfit.…