首页 > 系统相关 >调试进程与被调试进程之间的桥梁

调试进程与被调试进程之间的桥梁

时间:2023-02-17 16:46:17浏览次数:37  
标签:句柄 桥梁 DEBUG 进程 DbgSsReserved 调试 调试器

当调试器进程通过CreateProcessW(A)创建进程时,传入的dwCreationFlags为DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS时,表明调试当前创建的进程且不调试这个进程创建的子进程。

而CreateProcessW进程检测到此标志时会创建一个调试对象,具体调用堆栈如下:

KERNELBASE!CreateProcessW
  KERNELBASE!CreateProcessInternalW
    ntdll!DbgUiConnectToDbg会去读数组中的数据[1]
      如果句柄为空调用ntdll!NtCreateDebugObject 作为ntdll!DbgUiConnectToDbg的返回函数,在ntdll!NtCreateDebugObject 函数返回前在内核中 就对teb.DbgSsReserved[1]中写入了句柄值,类型为DebugObject

我们自己写一个进程,这个进程会以调试方式启动一个进程,在创建进程前手动加入断点,运行程序时如果有JIT调试器那么会自动中断下来,然后使用!teb命令获取TEB地址

 

 

再查看DbgSsReserved的值

 

 

 并对DbgSsReserved[1] 即对DbgSsReserved指针+4得到一个地址下一个硬件写入断点,断下来后调用堆栈如下:

 

 

 可知在call edx的时候就写入完成了,查看句柄值:

 

 

如果使用内核调试的话 ,还可以查看此句柄对应的内核调试对象DebugObject的内存地址。

 

接下来调试器调用WaitForDebugEvent即可获取调试事件,此函数界面原型如下:

WINBASEAPI BOOL APIENTRY WaitForDebugEvent(_Out_ LPDEBUG_EVENT lpDebugEvent,_In_ DWORD dwMilliseconds);

第一个参数为一个指向DEBUG_EVENT数据结构的指针

typedef struct _DEBUG_EVENT {
    DWORD dwDebugEventCode;
    DWORD dwProcessId;
    DWORD dwThreadId;
    union {
        EXCEPTION_DEBUG_INFO Exception;
        CREATE_THREAD_DEBUG_INFO CreateThread;
        CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
        EXIT_THREAD_DEBUG_INFO ExitThread;
        EXIT_PROCESS_DEBUG_INFO ExitProcess;
        LOAD_DLL_DEBUG_INFO LoadDll;
        UNLOAD_DLL_DEBUG_INFO UnloadDll;
        OUTPUT_DEBUG_STRING_INFO DebugString;
        RIP_INFO RipInfo;
    } u;
} DEBUG_EVENT, *LPDEBUG_EVENT;

其中包含一个联合数据类型,当dwDebugEventCode取不同值时,u代表不同的数据结构。

这个函数的调用栈如下:

KERNEL32!WaitForDebugEventStub
  KERNELBASE!WaitForDebugEvent
    KERNELBASE!WaitForDebugEventWorker
      KERNELBASE!BaseFormatTimeOut
      DbgUiWaitStateChange 返回c0000008
        ntdll!NtWaitForDebugEvent(传入多个参数 包括teb.DbgSsReserved[1]数组共两个数据)

如果当前进程不是调试器进程(即teb.DbgSsReserved[1]为空时),那么DbgUiWaitStateChange 返回0xc0000008,代表STATUS_INVALID_HANDLE句柄错误。

调试器进程的teb.DbgSsReserved[1]应该为一个句柄,才可以获取调试消息。

 

每个进程在内核中都有一个EPROCESS结构体,而EPRCESS结构体中有一个变量为DebugPort。如下:

 

 

 

对于被调试进程来说,EPROCESS结构体中DebugPort是不为空的,而之前的调试进程的teb.DbgSsReserved[1]存储的是句柄值,句柄在内核中对应的就是这个DebugPort对应的地址。

所以调试进程中有一个句柄指向了DebugObject,被调试进程的DebugPort也指向了同一个DebugObject。

当被调试进程产生了异常事件、进程启动退出事件、线程启动退出事件、模块加载卸载事件、输出调试消息、RIP_INFO报告 RIP 调试事件 (系统调试错误)这些异常消息时,都会将这些消息存储到DebugObject结构体对应的链表中。

当调试器使用WaitForDebugEvent时,内部ntdll的函数会使用teb.DbgSsReserved[1]的句柄寻找到DebugObject,进而获取到调试消息队列获取函数,返回给调试器,调试器处理完成后,再通过continueDebugEvent函数通知系统调试器处理结果:

1、DBG_CONTINUE告诉系统,已经处理了异常,让被调试进程继续运行。

2、DBG_EXCEPTION_NOT_HANDLED告诉系统,调试器不处理该异常,交给程序自己的异常处理机制处理。

3、DBG_REPLY_LATER这个没有使用过,按照MSDN解释为:Windows 10版本 1507 或更高版本中受支持,此标志会导致 dwThreadId 在目标继续后重播现有的中断事件。 通过针对 dwThreadId 调用 SuspendThread API,调试器可以在进程中恢复其他线程,稍后返回到中断状态。下次进行测试。

 

总结一下:调试器进程中某一个线程调用了CreateProcess时使用调试标志,那么此线程的teb.DbgSsReserved[1]会存储一个指向DebugObject的句柄,注意是线程的DbgSsReserved[1],也就是说在同一进程的其他线程中调用WaitForDebugEvent就会出现问题。

 

标签:句柄,桥梁,DEBUG,进程,DbgSsReserved,调试,调试器
From: https://www.cnblogs.com/ps12345678/p/17130687.html

相关文章

  • Linux上调试程序
    安装pudb安装命令pipinstallpudb-ihttps://pypi.doubanio.com/simple运行程序使用:pudbtest.py参考资料:如何使用pudb在终端调试python代码PUDB调试python程序......
  • Linux如何查看系统和进程的运行状态?
    对于运维人员来讲,监控服务器的运行状态是他们的必要工作,而Linux系统提供了很多关于服务器运行状态的命令,那么Linux如何查看系统和进程的运行状态?可以使用top命令,接下来......
  • 多进程
    高效编程一、多任务原理概念现代操作系统比如MacOSX,UNIX,Linux,Windows等,都是支持“多任务”的操作系统什么叫多任务?就是操作系统可以同时运行多个任务单核CPU......
  • Chrome 打开一个页面需要启动多少进程?分别有哪些进程?
    打开1个页面至少需要1个网络进程、1个浏览器进程、1个GPU进程以及1个渲染进程,共4个;最新的Chrome浏览器包括:1个浏览器(Browser)主进程、1个GPU进程、1个网......
  • GUI程序中使用Write语句调试
    LazarusGUI程序中使用Write语句调试比如像VB下的Debug.print可直接在立即窗口中打印出调试内容其实可以使用WriteLn('XXXX',XXX);Write('XXXXXX');但是在......
  • 使用alert卡住electron界面,打开调试控制台
    思路主要的思路是在electron的app.asar解包后,在主页面的html中加入js脚本alert,再重新打包,打开程序卡住界面,在按enter键的同时,按ctrl+shift+i,打开控制台案例说明观......
  • 嵌入式驱动开发之spi---spi串口通信调试
    一.概念SPI是SerialPeripheralInterface(串型外部接口)的缩写。SPI接口有4根PIN脚,分别是:        *SPICLK  :用于传输数据的同步时钟        ......
  • 读Java实战(第二版)笔记12_重构、测试和调试
    1. 设计模式1.1. 对设计经验的归纳总结1.2. 一种可重用的蓝图1.3. Java5引入了for-each循环1.3.1. 替代了很多显式使用迭代器的情形1.4. Java7推出的菱形操......
  • GDB调试Core文件出现问号?的原因
    函数的调用其实是函数的入栈出栈操作,但当程序栈因程序的错误导致破坏了栈,这时候就会导致gdb解析core文件时解析不出来的情况,即是问号(?)那还能做点什么呢?可以通过打印\(......
  • 调度器44—进程退出流程
    基于Linux-5.10一、do_exit()简要流程1.执行路径各驱动和内核机制中直接调用SYSCALL_DEFINE1(exit,int,error_code)//exit.c将(error_code&0xff)<<8传给参数c......