当前位置: 首页 > news >正文

10.0 探索API调试事件原理

本章笔者将通过Windows平台下自带的调试API接口实现对特定进程的动态转存功能,首先简单介绍一下关于调试事件的相关信息,调试事件的建立需要依赖于DEBUG_EVENT这个特有的数据结构,该结构用于向调试器报告调试事件。当一个程序发生异常事件或者被调试器附加时,就会产生对应的DEBUG_EVENT调试事件,通常DEBUG_EVENT包含了多种调试类型,包括异常事件、进程创建事件、线程创建事件、进程退出事件和线程退出事件等等,我们只需要动态捕捉这些调试事件并作相应的处理即可实现更多有用的功能。

调试事件通常可以分为如下几种类型;

  • 异常事件 (Exception Event) - 发生了异常,例如访问非法的内存、除以零或调用了无效的函数。
  • 进程创建事件 (Process Creation Event) - 当一个新进程被创建时发送此事件。
  • 进程退出事件 (Process Exit Event) - 当一个进程退出时发送此事件。
  • 线程创建事件 (Thread Creation Event) - 当一个新线程被创建时发送此事件。
  • 线程退出事件 (Thread Exit Event) - 当一个线程退出时发送此事件。
  • 调试字符串事件 (Debug String Event) - 当一个进程向其调试器发送字符串消息时发送此事件。
  • 输出字符串事件 (Output String Event) - 当输出调试字符串时发送此事件。
  • 动态链接库加载事件(LOAD_DLL_DEBUG_EVENT) - 当进程装载 DLL 时发送此事件。

当我们需要调试一个程序时有两种方式可以实现,第一种方式是通过CreateProcess()函数创建一个进程,并在调用函数时指定DEBUG_PROCESS || DEBUG_ONLY_THIS_PROCESS则当程序被运行起来后自动进入到调试状态,另一种方式则是通过DebugActiveProcess()函数,该函数接受一个正在运行的进程PID号,可动态附加到一个已运行程序上而对其进行调试。

一旦调试器通过CreateProcess()附加并运行,下一步则是通过WaitForDebugEvent()用于等待一个调试事件,当有调试事件到达后系统会将调试类型存储到debugEvent.dwDebugEventCode这个变量内,此时我们可以通过判断该变量内的参数来对特定的事件做出自定义处理操作,接着会通过ContinueDebugEvent()继续等待下一个调试事件的到来,我们以打开一个进程并创建调试为例,看一下如下代码片段;

#include <iostream>
#include <windows.h>int main(int argc, char* argv[])
{DEBUG_EVENT debugEvent = { 0 };BOOL bRet = TRUE;// 创建调试进程STARTUPINFO startupInfo = { 0 };PROCESS_INFORMATION pInfo = { 0 };GetStartupInfo(&startupInfo);// 创建调试进程并设置 DEBUG_PROCESS || DEBUG_ONLY_THIS_PROCESS 调试事件bRet = CreateProcess("d://lyshark.exe", NULL, NULL, NULL, TRUE, DEBUG_PROCESS || DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &startupInfo, &pInfo);if (!bRet){return 0;}// 附加调试进程// DebugActiveProcess(13940)// 无限循环等待调试事件while (WaitForDebugEvent(&debugEvent, INFINITE)){// 根据调试事件判断switch (debugEvent.dwDebugEventCode){// 异常调试事件case EXCEPTION_DEBUG_EVENT:printf("异常处理事件 \n");break;// 线程创建调试事件case CREATE_THREAD_DEBUG_EVENT:printf("线程创建调试事件 \n");break;// 进程创建调试事件case CREATE_PROCESS_DEBUG_EVENT:printf("进程创建调试事件 \n");break;// 线程退出调试事件case EXIT_THREAD_DEBUG_EVENT:printf("线程退出调试事件 \n");break;// 进程退出调试事件case EXIT_PROCESS_DEBUG_EVENT:printf("进程退出调试事件 \n");break;// 装载DLL调试事件case LOAD_DLL_DEBUG_EVENT:printf("装载DLL调试事件 \n");break;// 卸载DLL调试事件case UNLOAD_DLL_DEBUG_EVENT:printf("卸载DLL调试事件 \n");break;// 输出调试信息事件case OUTPUT_DEBUG_STRING_EVENT:printf("输出调试信息事件 \n");break;}// 使调试器能够继续以前报告调试事件的线程bRet = ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);}system("pause");return 0;
}

当编译并运行上述程序后,读者应该能看到如下图所示的输出效果,其中包括了各类调试事件被触发时的提示信息,由于在调试事件内没有做任何操作,程序在加载后就被自动运行起来了;

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/b8eecce4.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

http://www.lryc.cn/news/181368.html

相关文章:

  • 文心一言 VS 讯飞星火 VS chatgpt (104)-- 算法导论10.1 2题
  • 检测防火墙是否开启、判断程序是否加入防火墙白名单(附源码)
  • vtk 动画入门 1 代码
  • 【VR】【unity】如何在VR中实现远程投屏功能?
  • OpenGl材质
  • 背包问题
  • JavaSE | 初始Java(十一) | 抽象类和抽象接口
  • 产品经理如何科学的进行需求调研?
  • AI智能问答系统源码/AI绘画商业系统/支持GPT联网提问/支持Midjourney绘画
  • 玩具玩偶配送经营商城小程序的作用是什么?
  • latex表格内容换行
  • 2023 牛客国庆day4 【10.2训练补题】
  • android的USB开发时 mUsbManager.getDeviceList()获取都为空
  • SpringCloud Alibaba - Seata 部署 TC 服务,并集成微服务
  • Java基础面试,接口和抽象类的区别?
  • 《视觉 SLAM 十四讲》V2 第 4 讲 李群与李代数 【什么样的相机位姿 最符合 当前观测数据】
  • 【深蓝学院】手写VIO第4章--基于滑动窗口算法的 VIO 系统:可观性和 一致性--笔记
  • mfc 动态加载dll库,Mat转CImage,读ini配置文件,鼠标操作,在edit控件上画框,调试信息打印
  • 索尼 toio™应用创意开发征文|检测工业平台震动
  • 【已解决】 Expected linebreaks to be ‘LF‘ but found ‘CRLF‘.
  • Java8 Lambda.stream.sorted() 方法使用浅析分享
  • Neural Networks for Fingerprint Recognition
  • ChatGPT推出全新功能,引发人工智能合成声音担忧|百能云芯
  • Java 实现遍历一个文件夹,文件夹有100万数据,获取到修改时间在2天之内的数据
  • 持续集成部署-k8s-命令行工具:基础命令的使用
  • 使用python脚本的时间盲注完整步骤
  • C++项目:仿mudou库one thread one loop式并发服务器实现
  • 【算法训练-贪心算法 一】买卖股票的最佳时机II
  • 单阶段目标检测与双阶段目标检测的联系与区别
  • Mysql技术文档--设计表规范式-一次性扫盲