10.0 探索API调试事件原理

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

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

相关文章
|
6月前
|
消息中间件 分布式计算 Java
探究Kafka原理-3.生产者消费者API原理解析(上)
探究Kafka原理-3.生产者消费者API原理解析
66 0
|
3月前
|
API Docker 容器
jumpserver API调试
jumpserver API调试
|
3月前
|
API 开发者 Python
API接口:原理、实现及应用
本文详细介绍了API接口在现代软件开发中的重要性及其工作原理。API接口作为应用程序间通信的桥梁,通过预定义的方法和协议实现数据和服务的共享。文章首先解释了API接口的概念,接着通过Python Flask框架示例展示了API的设计与实现过程,并强调了安全性的重要性。最后,本文还讨论了API接口在Web服务和移动应用程序等领域的广泛应用场景。
|
3月前
|
移动开发 开发框架 小程序
开发H5程序或者小程序的时候,后端Web API项目在IISExpress调试中使用IP地址,便于开发调试
开发H5程序或者小程序的时候,后端Web API项目在IISExpress调试中使用IP地址,便于开发调试
|
3月前
|
存储 API
【Azure API 管理】为调用APIM的请求启用Trace -- 调试APIM Policy的利器
【Azure API 管理】为调用APIM的请求启用Trace -- 调试APIM Policy的利器
|
3月前
|
Kubernetes 负载均衡 API
在K8S中,api-service 和 kube-schedule 高可用原理是什么?
在K8S中,api-service 和 kube-schedule 高可用原理是什么?
|
6月前
|
XML 搜索推荐 API
通义千问API:让大模型使用各种工具
本章我们将通过一个简单的例子,揭示基于LangChain的Agent开发的秘密,从而了解如何扩展大模型的能力。
通义千问API:让大模型使用各种工具
|
5月前
|
存储 缓存 Java
JavaSE 字符串String及相关API StringBuilder StringJoiner 底层原理 详解
JavaSE 字符串String及相关API StringBuilder StringJoiner 底层原理 详解
45 2
|
4月前
|
Web App开发 JavaScript 前端开发
js 调试—— 【控制台】debugger语句 、 命令行API
js 调试—— 【控制台】debugger语句 、 命令行API
251 0
|
6月前
|
安全 算法 Java
Java Stream API:原理、应用与深入解析
Java Stream API:原理、应用与深入解析
296 2