从异常分发流程的实现看反用户调试器

本文是对 从3环调试器工作流程的实现看反调试 的一个补充和扩展,主要从异常分发的流程的实现来看怎么反调试。


后面还有一篇链接:[原创]从异常分发流程的实现看反双机调试【有码】 

后面顺变会附带上写满注释的wrk代码,方便大家对照着看。


由于本人水平有限,错误之处难免,请大神们不吝指正哈!


一个INT 3被执行的时候关键数据结构变化

栈的变化:

INT 3刚被执行的时候堆栈的情况:

说明:

          1.      从tss段中取出对应权限的esp

          2.      把用户空间的ss寄存器压入HardwareSegss

          3.      把用户空间的esp寄存器压入HardwareEsp

          4.      把标志寄存器压入到EFLAGS

          5.      把用户空间的cs寄存器压入到SegCs中

          6.      把用户空间的eip压入到Eip中 

填充TrapFrame结构:

说明:

1. V8 6Gs、V86Fs、V86Ds、V86Es,这些寄存器现在仅仅作为保留,不必研究

2. HardwareSegSs、HardwareEsp、Eflags、SegCs、Eip,这些在中断的时候cpu会帮我保存

3. 其他的寄存器操作系统在中断例程保存

异常结构相关:

异常结构体

说明:

1. 在学习阶段只需要关注ExceptionCode和ExceptionAddress即可,其他的参数如果不写调试器暂时用不到

异常结构体在什么阶段被填充(以INT 3为例):

说明:

1. 从上图可以看到在CommonDispatchException中被填充

2. 但是我们也可以看到我们分析的重点会在KiDispatchException中,是的我们的分析的重点就是他,但是分析它之前我们得做一些准备工作

异常结构体具体是如何被填充的

这个问题只能贴代码了,就贴CommonDispatchException代码,这块的代码已经有很详细的注释了,等会全部的代码放到附件中提供下载 

为什么讲异常分发流程会讲下核心数据结构:

1. 后面我会把详细注释过的wrk的源代码作为附录,大家可以对照注释去看异常分发的源代码

2. 根据我的经验,阻碍看源代码就是对这些数据结构不了解,特别是TrapFrame、异常时候的堆栈、在异常中怎么返回这类问题

异常分发全流程:

1. 如果你看到这张图不想看了,你的感觉是对的,我第一次看到这张图也是一脸懵逼,感觉好复杂啊,幸好我们今天仅仅只学习其中的一块,就是图的左半部分

2. 如果你看到这里有什么第一次、第二次XX,先不用纠结这个问题,我们只讨论第一次的话题,因为男人的第一次是难以忘怀的,不对是第一次分发才和3环调试器有密切关系,第二次分发以后专门开个帖子对着源代码讲下

3. 忽略图中的内核调试器

第一次分发且有用户调试器:

先来个流程图:

说明:

1. 可以看到核心的函数是 DbgkForwardException

2. 把调试事件发送到调试对象的核心函数是DbgkSendApiMessage

核心代码的分析:

KiDispatchException 的分析:

主要调用了DbgkForwardException,这个是用户调试的主要函数

DbgkForwardException的分析:

先检查 CrossThreadFlags 的 PS_CROSS_THREAD_FLAGS_HIDEFROMDBG 标志位是否被设置,如果被设置代表不会被调试。

调用 DbgkpSendapiMessage 发送异常信息给调试器

DbgkpSendApiMessage 的分析:

说明:

1. 这个函数主要调用了 DbgkpQueueMessage 函数

DbgkpQueueMessage 的分析:

这里会获取一个全局锁,这个是一个反调试的好地方

把调试事件插入DebugObject的EventList里面去:

等待调试器处理这个调试事件

从异常分发流程中总结出来的反3环调试:

1. 直接对idt做hook,比如3号中断,这样就没法使用软件断点了

2. 对需要保护的进程的每个线程的的 Ethread 结构体的CrossThreadFlag 设置 PS_CROSS_THREAD_FLAGS_HIDEFROMDBG,有一个专门的api是:ZwSetInformationThread(hThread, ThreadHideFromDebugger, NULL, NULL)

3. DbgkpSendApiMessage 进行挂钩,直接返回STATUS_UNSUCCESSFUL

4. DbgkpQueueMessage 进行挂钩,直接返回STATUS_UNSUCCESSFUL

5. 这个就比较比较猥琐了:ExAcquireFastMutex (&DbgkpProcessDebugPortMutex),直接锁住这个全局变量,所有的调试器都会卡死,并且没有钩子

6. DbgkpSuspendProcess和DbgkpResumeProcess 挂钩,向0x64端口写入0xFE,让机器重启

谢谢大家观看!

本文由看雪论坛 又出bug了 原创

转载请注明来自看雪社区

原文链接:

[原创]从异常分发流程的实现看反用户调试器-『软件逆向』-看雪安全论坛​bbs.pediy.com

更多干货请关注看雪学院公众号 ikanxue!

你可能感兴趣的:(从异常分发流程的实现看反用户调试器)