本章笔者将通过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 许可协议。转载请注明出处!

10.0 探索API调试事件原理的更多相关文章

  1. IE升级到10.0,VS2010启动调试时报“未能将脚本调试器附加到计算机..”

    IE升级到10.0,VS2010启动调试时报“未能将脚本调试器附加到计算机..” 今天,在调试代码时,调试器弹出提示框,报:未能将脚本调试器附加到计算机XXX上的进程iexplore.exe . 已附 ...

  2. Java 动态调试技术原理及实践

    本文转载自Java 动态调试技术原理及实践 导语 断点调试是我们最常使用的调试手段,它可以获取到方法执行过程中的变量信息,并可以观察到方法的执行路径.但断点调试会在断点位置停顿,使得整个应用停止响应. ...

  3. Web jquery表格组件 JQGrid 的使用 - 4.JQGrid参数、ColModel API、事件及方法

    系列索引 Web jquery表格组件 JQGrid 的使用 - 从入门到精通 开篇及索引 Web jquery表格组件 JQGrid 的使用 - 4.JQGrid参数.ColModel API.事件 ...

  4. iOS 10.0 更新点(开发者视角)

    html, body {overflow-x: initial !important;}html { font-size: 14px; } body { margin: 0px; padding: 0 ...

  5. Kafka 0.10.0

    2.1 Producer API We encourage all new development to use the new Java producer. This client is produ ...

  6. 还在期待安卓9.0吗?Android 10.0要来了

    目前,美国 Google公司的 AndroidP (安卓9.0),已经正式全面推出有几个多月了.众多手机品牌厂商也都在积极的进行更新适配 Android 9.0 系统(修改UI界面也算是二次开发,嗯) ...

  7. Atitit web remote远程调试的原理attilax总结

    Atitit web remote远程调试的原理attilax总结 Jvm是vm打开一个debug port,然后ide先连接..然后执行url,就会vm会与ide沟通.. Php的xdebug po ...

  8. Dottrace 10.0.2 使用心得

    开发环境vs2015 软件:JetBrains dotTrace 10.0.2 刚开始不知道怎么下手,多看了一会还有一位仁兄的解释.算是对某个功能小有入门了. 当前会查看某个方法在抓取快照时间它的执行 ...

  9. 调试寄存器 原理与使用:DR0-DR7

    调试寄存器 原理与使用:DR0-DR7 下面介绍的知识性信息来自intel IA-32手册(可以在intel的开发手册或者官方网站查到),提示和补充来自学习调试器实现时的总结. 希望能给你带去有用的信 ...

  10. 非寻常方式学习ApacheTomcat架构及10.0.12源码编译

    概述 开启博客分享已近三个月,感谢所有花时间精力和小编一路学习和成长的伙伴们,有你们的支持,我们继续再接再厉 **本人博客网站 **IT小神 www.itxiaoshen.com 定义 Tomcat官 ...

随机推荐

  1. 文字生成图像 AI免费工具第一弹 StableDiffusion

    随着ChatGPT的爆火,text-to-image文字生成图像.以及更广义的AIGC(AI Generated Content)相关的话题最近一直热度不减.相信大家这几天经常会在各类的自媒体.甚至是 ...

  2. 从0搭建Vue3组件库(十):如何搭建一个 Cli 脚手架

    本篇文章将实现一个名为create-easyest脚手架的开发,只需一个命令npm init easyest就可以将整个组件库开发框架拉到本地. 创建 Cli 包 首先,我们在 packages 目录 ...

  3. 【python基础】函数-参数形式

    鉴于函数定义中可能包含多个形参变量,因此函数调用中也可能包含多个实参变量.向函数传递实参变量给形参变量的方式有很多,可使用位置参数,这要求实参变量的顺序与形参变量的顺序相同:也可使用关键字参数,都由变 ...

  4. tSNE算法在自然语言处理中的应用:文本降维和可视化

    目录 技术原理及概念 t-SNE(Toeplitz-Stochastic Neural Network)是一种常用的文本降维和可视化算法,它的核心思想是将高维文本数据映射到低维空间,同时保持数据的一致 ...

  5. php屏蔽非正常访问和检测用户登录检测

    <?phpnamespace Manage\Controller;use Common\Controller\DefaultController;class BaseController ext ...

  6. Apache Hudi 元数据字段揭秘

    介绍 Apache Hudi 最初由Uber于 2016 年开发,旨在实现一个交易型数据湖,该数据湖可以快速可靠地支持更新,以支持公司拼车平台的大规模增长. Apache Hudi 现在被业内许多人广 ...

  7. 如何构建高效、可观的系统「GitHub 热点速览」

    经典老项目 system-design 教你如何设计一个健壮的系统,新项目 noodle 教你如何提升教育效率,而后者甚至单日获得了 1,600 star,刚开源就获得了 6k+ 的 star. 除了 ...

  8. Swift函数调用方式浅析

    函数的调用机制   函数的调用机制是在函数调用时通过那种路径走到最终调用函数地址的机制. 在编程语言中,函数的调用机制有三种 1.静态调用:编译期就确定了函数内存地址,执行效率最高,还可以使用编译器优 ...

  9. typedef函数的使用

    typedef int INT; //相当于给int起了一个别名INT typedef struct Student { int sid; char name[100]; char sex; }ST; ...

  10. Linux 命令:btrfs filesystem resize

    btrfs filesystem resize 2:300G /path ## 为创建了btrfs文件系统,已经挂载到/path 且device ID为2的硬盘/分区进行resize # 已经做过硬盘 ...