欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

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

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

     本文是对从3环调试器工作流程的实现看反调试 的一个补充和扩展, 主要从异常分发的流程的实现来看怎么反调试。
     后面还有一篇[原创]从异常分发流程的实现看反双机调试【有码】
     后面顺变会附带上写满注释的wrk代码,方便大家对照着看。
     由于本人水平有限,错误之处难免,请大神们不吝指正哈!

目录

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

    栈的变化:... 1

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

        填充TrapFrame结构:... 1

    异常结构相关:... 1

        异常结构体... 1

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

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

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

异常分发全流程:... 1

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

    先来个流程图:... 1

核心代码的分析:... 1

    KiDispatchException的分析:... 1

    DbgkForwardException的分析:... 1

    DbgkpSendApiMessage的分析:... 1

    DbgkpQueueMessage 的分析:... 1

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



//////////////////////////////////////////////////正文/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

一个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,让机器重启


谢谢大家观看!



上传的附件 dbgk.rar

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功