首发于奇安信攻防社区:https://forum.butian.net/share/1478
前言
在windows里面调试跟异常息息相关,如果想要对调试得心应手,异常处理的知识是必不可少的,本文主要介绍的是软件调试方面的有关知识,讲解调试程序和被调试程序之间如何建立联系
调试对象
调试器和被调试程序
调试器与被调试程序之间建立起联系的两种方式
-
CreateProcess
-
DebugActiveProcess
与调试器建立连接
首先看一下DebugActiveProcess
调用ntdll.dll
的DbgUiConnectToDbg
再调用ZwCreateDebugObject
通过调用号进入0环
进入0环创建DEBUG_OBJECT
结构体
typedef struct _DEBUG_OBJECT {
KEVENT EventsPresent;
FAST_MUTEX Mutex;
LIST_ENTRY EventList;
ULONG Flags;
} DEBUG_OBJECT, *PDEBUG_OBJECT;
然后到ntoskrnl
里面看一下NtCreateDebugObject
然后调用了ObInsertObject
创建DebugObject
结构返回句柄
再回到ntdll.dll
,当前线程回0环创建了一个DebugObject
结构,返回句柄到3环存放在了TEB的0xF24
偏移处
也就是说,遍历TEB的0xF24
偏移的地方,如果有值则一定是调试器
与被调试程序建立连接
还是回到kernel32.dll
的DebugActiveProcess
,获取句柄之后调用了DbgUiDebugActiveProcess
调用ntdll.dll
的DbgUiDebugActiveProcess
跟到ntdll.dll
里面的DbgUiDebugActiveProcess
,传入两个参数,分别为调试器的句柄和被调试进程的句柄
通过调用号进0环
来到0环的NtDebugActiveProcess
, 第一个参数为被调试对象的句柄,第二个参数为调试器的句柄
执行ObReferenceObjectByHandle
,把被调试进程的句柄放到第五个参数里面,这里eax本来存储的是调试器的EPROCESS
,执行完之后eax存储的就是被调试进程的EPROCE