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

调试框架

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

断点分为三类

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

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

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

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

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

步骤

建立调试会话

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

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

启动 CreateProcess

调试标志主要2种

附加 DebugActiveProcess

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

循环接受调试事件
WaitForDebugEvent

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

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

结果提交给系统

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

ContinueDebugEvent

第3个参数: 继续状态

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

DBG_EXCEPTION_NOT_HANDLED 只对异常事件有用

代码实现

新建工程

完成代码
.386
.model flat, stdcall
option casemap:none include windows.inc
include user32.inc
include kernel32.inc
include msvcrt.inc includelib user32.lib
includelib kernel32.lib
includelib msvcrt.lib .data
g_szExe db "winmine.exe",0 ;被调试的进程 g_szEXCEPTION_DEBUG_EVENT db "EXCEPTION_DEBUG_EVENT",0dh,0ah, 0 g_szCREATE_THREAD_DEBUG_EVENT db "CREATE_THREAD_DEBUG_EVENT",0dh,0ah,0 g_szCREATE_PROCESS_DEBUG_EVENT db "CREATE_PROCESS_DEBUG_EVENT",0dh,0ah, 0 g_szEXIT_THREAD_DEBUG_EVENT db "EXIT_THREAD_DEBUG_EVENT",0dh,0ah, 0 g_szEXIT_PROCESS_DEBUG_EVENT db "EXIT_PROCESS_DEBUG_EVENT",0dh,0ah, 0 g_szLOAD_DLL_DEBUG_EVENT db "LOAD_DLL_DEBUG_EVENT" , 0dh,0ah, 0 g_szUNLOAD_DLL_DEBUG_EVENT db "UNLOAD_DLL_DEBUG_EVENT" , 0dh,0ah, 0 g_szOUTPUT_DEBUG_STRING_EVENT db "OUTPUT_DEBUG_STRING_EVENT" , 0dh,0ah, 0 .code main proc
LOCAL @si:STARTUPINFO
LOCAL @pi:PROCESS_INFORMATION
LOCAL @de:DEBUG_EVENT ;这个结构体使用后需要清0 ;初始化变量
invoke RtlZeroMemory,addr @si, size @si
invoke RtlZeroMemory,addr @pi, size @pi
invoke 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 !eax
ret ;建立调试会话失败直接退出
.endif ;循环接受调试事件
.while TRUE invoke 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结构体使用后清0
invoke RtlZeroMemory,addr @de, size @de .endw ret main endp start: invoke main end start
处理 LOAD_DLL_DEBUG_EVENT 事件

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

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

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

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

.386
.model flat, stdcall
option casemap:none include windows.inc
include user32.inc
include kernel32.inc
include msvcrt.inc includelib user32.lib
includelib kernel32.lib
includelib msvcrt.lib .data
g_szExe db "winmine.exe",0 ;被调试的进程
g_hExe dd 0 ;进程句柄 g_szEXCEPTION_DEBUG_EVENT db "EXCEPTION_DEBUG_EVENT",0dh,0ah, 0 g_szCREATE_THREAD_DEBUG_EVENT db "CREATE_THREAD_DEBUG_EVENT",0dh,0ah,0 g_szCREATE_PROCESS_DEBUG_EVENT db "CREATE_PROCESS_DEBUG_EVENT",0dh,0ah, 0 g_szEXIT_THREAD_DEBUG_EVENT db "EXIT_THREAD_DEBUG_EVENT",0dh,0ah, 0 g_szEXIT_PROCESS_DEBUG_EVENT db "EXIT_PROCESS_DEBUG_EVENT",0dh,0ah, 0 g_szLOAD_DLL_DEBUG_EVENT db "LOAD_DLL_DEBUG_EVENT" , 0dh,0ah, 0 g_szUNLOAD_DLL_DEBUG_EVENT db "UNLOAD_DLL_DEBUG_EVENT" , 0dh,0ah, 0 g_szOUTPUT_DEBUG_STRING_EVENT db "OUTPUT_DEBUG_STRING_EVENT" , 0dh,0ah, 0 g_szLoadDllFmt db "%08X %s", 0dh,0ah, 0 g_szwLoadDllFmt dw '%','0','8','X',' ', '%','s', 0dh,0ah, 0 .code OnLoadDll proc uses esi pDE:ptr DEBUG_EVENT
LOCAL @dwAddr:DWORD
LOCAL @dwByteReaded:DWORD
LOCAL @szwPath[512]:WORD invoke crt_printf, offset g_szLOAD_DLL_DEBUG_EVENT
invoke RtlZeroMemory,addr @szwPath, size @szwPath mov esi,pDE
assume esi: ptr DEBUG_EVENT invoke ReadProcessMemory,g_hExe,[esi].u.LoadDll.lpImageName,addr @dwAddr, size @dwAddr,addr @dwByteReaded
.if !eax
ret
.endif invoke ReadProcessMemory,g_hExe, @dwAddr ,addr @szwPath, sizeof @szwPath,addr @dwByteReaded
.if !eax
ret
.endif .if [esi].u.LoadDll.fUnicode ;如果是 unicode invoke crt_wprintf, offset g_szwLoadDllFmt,[esi].u.LoadDll.lpBaseOfDll,addr @szwPath
.elseif invoke crt_printf, offset g_szwLoadDllFmt,[esi].u.LoadDll.lpBaseOfDll,addr @szwPath .endif assume esi:nothing
ret OnLoadDll endp main proc
LOCAL @si:STARTUPINFO
LOCAL @pi:PROCESS_INFORMATION
LOCAL @de:DEBUG_EVENT ;这个结构体使用后需要清0 ;初始化变量
invoke RtlZeroMemory,addr @si, size @si
invoke RtlZeroMemory,addr @pi, size @pi
invoke 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 !eax
ret ;建立调试会话失败直接退出
.endif mov eax,@pi.hProcess
mov g_hExe,eax
;循环接受调试事件
.while TRUE invoke 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结构体使用后清0
invoke RtlZeroMemory,addr @de, size @de .endw ret main endp start: invoke main end start

NtQueryProcessInfomation 获取进程信息

Windows平台调试器原理与编写01.调试框架的更多相关文章

  1. C#比较两个对象是否为同一个对象。 Visual Studio调试器指南---多线程应用程序调试(一)

    两个对象是否为同一个对象:是看两个对象是否指向堆中的同一块内存. 1.使用object.ReferenceEquals() class Program { static void Main(strin ...

  2. 嵌入式调试器原理和各类调试器集锦(JLINK、STLINK、CCDEBUG)

    工欲善其事,必先善其器.调试器在嵌入式开发调试中的重要性不言而喻,单步.断点和监察的效率远高于串口打印.但是,调试器对于一般开发人员往往是一个黑匣子.今天我们就来谈谈调试器的原理,顺便把自己的几类调试 ...

  3. Visual Studio调试器指南---多线程应用程序调试(一)

    线程是操作系统向其授予处理器时间的指令序列. 在操作系统中运行的每个进程都包含至少一个线程. 包含多个线程的进程称为多线程.有多个处理器.多核处理器或超线程进程的计算机可以同时运行多个线程. 使用多个 ...

  4. w3wp.exe已附加有调试器,但没有该调试器配置为调试此未经处理的异常,若要调试此异常,必须分离当前的调试器。

    之前通过使用VS2010附加进程调试项目后,今天开机发现调试本机的项目报错如下图: 到网上到处查看无果,经过反复实验找到解决方法,我的项目是发布到IIS的 1.首先删除IIS上面的项目 2.在VS右击 ...

  5. 第二章排错的工具:调试器Windbg(上)

    感谢博主 http://book.51cto.com/art/200711/59731.htm <Windows用户态程序高效排错>第二章主要介绍用户态调试相关的知识和工具.本文主要讲了排 ...

  6. 用python开发调试器——起始篇

    首先,你得准备一套python开发环境,正常情况下,一般是在windows下开发的,因为win系统应用广泛,再则就是要有个IDE,这里我选择我熟悉的Eclipse.环境搭建,网上都有,比如:http: ...

  7. 第二章排错的工具:调试器Windbg(下)

    感谢博主 http://book.51cto.com/art/200711/59874.htm 2.2  读懂机器的语言:汇编,CPU执行指令的最小单元2.2.1  需要用汇编来排错的常见情况 汇编是 ...

  8. [连载]《C#通讯(串口和网络)框架的设计与实现》- 11.调试器的设计

    目       录 第十一章     调试器设计... 2 11.1         调试接口... 2 11.2         界面方式调试... 3 11.3         命令行方式调试.. ...

  9. Win32调试API原理

    在Win32中自带了一些API函数,它们提供了相当于一般调试器的大多数功能,这些函数统称为Win32调试API(Win32 Debug API).利用这些API可以做到加载一个程序或捆绑到一个正在运行 ...

  10. 【基础】CodeBlocks调试器基本使用方法

     CodeBlocks是一个开放源码的全功能的跨平台C/C++集成开发环境. 下载地址:http://www.codeblocks.org/downloads/26 其中,Windows环境下可以使用 ...

随机推荐

  1. Scala高阶函数 2(以函数作为返回值,函数柯里化,应用函数)

    package com.wyh.day01 object ScalaFun4 { def main(args: Array[String]): Unit = { /** * 以函数作为返回值 */ d ...

  2. WPF无边框的一个方案(保留默认窗口的拖动、阴影等效果)

    使用 WindowStyle="None" AllowsTransparency="True" 的方式达成无边框的效果有很多无法忽视的缺陷,比如失去了拖动效果. ...

  3. cudatooklit安装记录_windows

    Windows本地部署deepseek,使用速度不是很理想,在此尝试使用GPU加速 在cmd中使用命令查看支持的版本 nvidia-smi 注意对应的 Driver Version,根据Nvidia给 ...

  4. C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)

    前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录.追踪C#/.NET/.NET Core领域.生态的每周最新.最实用.最有价值的技术文章.社区动态.优质项目和学习资源等. ...

  5. Ansible管理密码库文件

    ansible可能需要访问密码或API密钥等敏感数据,以便能配置受管主机.通常,此信息可能以纯文本形式存储在清单变量或其他Ansible文件中.但若如此,任何有权访问Ansible文件的用户或存储,这 ...

  6. 如何在 IIS 上部署 Go API?

    问题场景 我这边原先的技术栈主要是 .NET(Core), 所以服务器基本上都是 Windows Server + IIS. 这次有个 API 服务用 Go 重写, 但是部署有点不美, 直接执行黑框框 ...

  7. 《HarmonyOS Next开发进阶:打造功能完备的Todo应用华章》

    章节 6:日期选择器与日期处理 目标 学习如何使用DatePicker组件. 理解日期格式化和日期计算. 内容 日期选择器基础 使用DatePicker组件. 处理日期选择事件. 日期格式化 格式化日 ...

  8. .net WorkFlow 流程传阅

    WikeFlow官网:www.wikesoft.com WikeFlow学习版演示地址:workflow.wikesoft.com WikeFlow学习版源代码下载:https://gitee.com ...

  9. 使用SymPy求解矩阵微分方程

    引言 在数学.物理.工程等领域,微分方程常常被用来描述系统的变化和动态过程.对于多变量系统或者多方程系统,矩阵微分方程是非常常见的,它可以用来描述如电路.控制系统.振动系统等复杂的动态行为.今天,我们 ...

  10. Asp.net mvc基础(三)View的查找

    1.指定转到的视图 View("指定的视图名称"); 优先于寻找Action方法名称可以创建的视图的文件夹,如果没有,就去View文件夹下的Shared文件夹寻找指定的视图名称. ...