本章笔者将通过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. 一招带你吃透MySQL高级

    MySQL8高级之架构和优化 让 第01章 Linux下MySQL的安装与使用 1.安装 1.1.docker安装 docker run -d \ -p 3309:3306 \ -v /atguigu ...

  2. Java使用joml计算机图形学库,将3D坐标旋转正交投影转为2D坐标

    最近遇到了一个困扰我许久的难题,现将解决方案分享出来 由于我们的项目侧重点在前端绘图,导致了前后端工作量不协调,我后端接口很快就能写完,而前端一个图要画好久,领导见状将前端的任务分到后端一部分用Jav ...

  3. 强化学习实践:Policy Gradient-Cart pole游戏展示

    摘要:智能体 agent 在环境 environment 中学习,根据环境的状态 state(或观测到的 observation),执行动作 action,并根据环境的反馈 reward(奖励)来指导 ...

  4. LSP协议被劫持,导致无法上网

    QQ无法登录,网页打不开 用火绒的断网修复 说已经修复了 结果屁用没有 然后找的百度经验 管理员打开命令行窗口 输入 netsh winsock reset catalog 重启即生效

  5. 分布式多协议接入网关FluxMQ-2.0功能说明

    FluxMQ-2.0版本更新内容 前言 FLuxMQ是一款基于java开发,支持无限设备连接的云原生分布式物联网接入平台.FluxMQ基于Netty开发,底层采用Reactor3反应堆模型,具备低延迟 ...

  6. 即构携手智能对讲机品牌Runbo,打造可视化对讲通信系统

    现代通信技术的发展,让信息的传递变得前所未有的便捷.作为双向移动通信工具,对讲机不需要网络支持就可以进行通话,且没有话费产生,尤其适合酒店.物业等使用区域固定.通话频繁的场景. 随着技术的不断迭代,对 ...

  7. [GIT]解决:failed to push some refs to ...(过程重现)

    本问题有很多种情况,解决方法也很多,本文只针对笔者本人的自身诉求和情况,选择了一种适合我的解决方法.仅供参考. 1 问题描述 johnnyzen@XXDSSS MINGW64 /e/source_co ...

  8. Python 潮流周刊第 11 期(2023-07-15)

    查看全文:Python潮流周刊#11:如何使用 Golang 运行 Python 代码? 文章&教程 1.使用 Golang 和 Docker 运行 Python 代码 2.答案在代码中:&q ...

  9. kbuild系统中最简单的目标 -- help(三)

    当你学完help目标后你会发现它与我们的代码基本没有什么直接的关系,仅仅是用来生成kbuild的简短使用说明,但是用它来作为学习掌握kbuild编译系统的开篇,不管是从难度还是学习感受上真的是再适合不 ...

  10. grafana Variables 变量的使用

    概念澄清 A variable is a placeholder for a value. # 变量是值的占位符. # 参考文档:https://grafana.com/docs/grafana/la ...