天堂W游戏内核驱动保护简单分析(三)

调试器检测

  1. DebugPort清零 在没有被调试之前

     +0x0bc DebugPort        : (null) 
     ​
     +0x248 Flags            : 0xd0800
        +0x248 CreateReported   : 0y0
        +0x248 NoDebugInherit   : 0y0

    被调试之后:

     +0x0bc DebugPort        : 0x89367b38 Void
     ​
     +0x248 Flags            : 0xd0801
        +0x248 CreateReported   : 0y1
        +0x248 NoDebugInherit   : 0y0

  2. 调试信息查询

     NtQuerySystemInformation(ProcessBasicInformation 和 ProcessDebugPort) 
         检测当前系统是否处于调试状态, 比如双机调试 
         SystemKernelDebuggerInformation->DebuggerEnabled = FALSE; (双机调试 )
         SystemKernelDebuggerInformation->DebuggerNotPresent = FALSE; (双机调试 )
         检测kdcom.dll内核模块是否加载                             (双机调试 )
         dt _KUSER_SHARED_DATA结构成员s
             检测 KdDebuggerEnabled 值是否为1, 这个值还会控制桌面是否显示测试模式                           (双机调试 )
             检测 KdEnteredDebugger 值是否为1                          (双机调试 )
             检测 KdDebuggerNotPresent 值是否为0,正常应该为1
         KiDebugRoutine = KdpStub 则不可调试, 可调试的是kdpTrap    (双机调试 )
         检测内核调试的其他变:
             已开启内核调试:0  未开启内核调试:1dd KdpTimeSlipPending l1
             已开启内核调试:1  未开启内核调试:0db KdpBootedNodebug  l1
             已开启内核调试:0  未开启内核调试:1dd KdDebuggerLockMaxWaitTime  l1
             已开启内核调试:有值  未开启内核调试:0dd KdDebuggerEnteredCount  l1
             已开启内核调试:有值  未开启内核调试:0db KdpContextSent   l1
             已开启内核调试:1   未开启内核调试:0db KdpBreakpointTable l4
             下内核断点:有值  未下内核断点:0dq KdTimerStop     l1
             已开启内核调试:有值  未开启内核调试:0db KdpPathBuffer   l4
             已开启内核调试:有值  未开启内核调试:0dq KdTimerDifference l1
             已开启内核调试:有值  未开启内核调试:0db KdpControlCPressed l1
             挂起:1  恢复:0dd KdUmBreakMarker l1
             已开启内核调试:有值  未开启内核调试:0dd KdEnteredDebugger l1
             挂起:1  恢复:0dq KdDebugDevice   l1
             已开启内核调试:有值  未开启内核调试:0db KdPageDebuggerSection l1
             已开启内核调试:0  未开启内核调试:1db KdpDebuggerStructuresInitialized l1
             已开启内核调试:1  未开启内核调试:0dq KdTimerStart    l1
             已开启内核调试:有值  未开启内核调试:0db KdLogBuffer     l4
             已开启内核调试:有值  未开启内核调试:0db KdDebuggerEnabled l1
             已开启内核调试:1   未开启内核调试:0dq KdDebuggerNotPresent l1
             已开启内核调试:0  未开启内核调试:1db KdpContext l4
             已开启内核调试:有值  未开启内核调试:0db KdBreakAfterSymbolLoad l1
             已开启内核调试:1  未开启内核调试:0db KdpDataBlockEncoded l1
             已开启内核调试:0  未开启内核调试:1dd KdpDebugRoutineSelect l1
             已开启内核调试:1  未开启内核调试:0dq KdpTimeSlipTimer l1
             已开启内核调试:有值  未开启内核调试:0db KdPortLocked    l1
             已开启内核调试:1  未开启内核调试:0db KdpMessageBuffer l4
             已开启内核调试:有值  未开启内核调试:0dq KdDebuggerLock  l1
             
     NtQueryInformationProcess(ProcessBasicInformation 和 ProcessDebugPort)
         ProcessDebugPort
         ProcessDebugObjectHandle
         ProcessDebugFlags
     检测父进程,进程被调试时父进程为调试进程

  1. OnNtQueryObject()查询调试对象名

     typedef enum _OBJECT_INFORMATION_CLASS{
         ObjectBasicInformation,
         ObjectNameInformation,
         ObjectTypeInformation,
         ObjectAllInformation,
         ObjectDataInformation
     }OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;

    这是一个对象的结构,我们只关心调试对象: ObjectAllInformation

    第四个成员ObjectAllInformation,查询的是调试对象名:DebugObject,每当一个应用程序被调试的时候,将会为调试对话在内核中创建一个DebugObject类型的对象。程序可以检查DebugObject类型内核对象的数量来确定是否有调试器的存在。

  2. NtSetInformationThread()修改线程标志,让其不可被调试, 某些加壳也会使用这个方式。 CrossThreadFlags标志位不能被修改,hook后让其可以被修改

  3. hook NtDebugActiveProces附加到游戏进程

  4. DebugPort偏移修改,hook DbgkpSetProcessDebugObject这个函数,将读取DebugPort偏移的值改掉

     NTSTATUS DbgkpSetProcessDebugObject(
         IN PROCESS Process, // 这里其实就指进入的游戏进程对象
         IN PDEBUG_OBJECT DebugObject,
         IN NTSTATUS MsgStatus,
         IN PETHREAD LastThread
     )

    思路1: Hook这个函数将第一个参数设置为explorer.exe, 函数就会把游戏进程的DebugObject对象转移到Explorer->Process->DebugPort, 就算游戏保护对游戏进程的DebugPort清零,也不会影响我们调试 思路2: 处理NTCreateDebugObject, 采用Hook ObCreateObject函数判断上层调用者是否是NTCreateDebugObject, 如果是,则将参数里的DebugObject备份保存 思路3: 需要修改偏移的函数

         KiDispatchException
         PspExitThread
         PspTerminateAllThreads
         PspProcessDelete
         PsIsProcessBeingDebugged
         PsGetProcessDebugPort
         NtQueryInformationProcess
         DbgkpSetProcessDebugObject
         DbgkClearProcessDebugObject
         DbgkpQueueMessage
         DbgkOpenProcessDebugPort
         DbgkCopyProcessDebugPort
         DbgkpCloseObjec
         DbgkpMarkProcessPeb
         DbgkForwardException
         DbgkCreateThread
         DbgkMapViewOfSection
         DbgkUnMapViewOfSection
         DbgkExitProcess();
         DbgkExitThread(); 

  5. ValidAccessMask清零 ValidAccessMask是在DebugObjectType的OBJECT_TYPE_INITIALIZER成员里

     0: kd> dt _object_type 89a32298
     nt!_OBJECT_TYPE
        +0x000 Mutex            : _ERESOURCE
        +0x038 TypeList         : _LIST_ENTRY [ 0x89a322d0 - 0x89a322d0 ]
        +0x040 Name             : _UNICODE_STRING "DebugObject"
        +0x048 DefaultObject    : (null) 
        +0x04c Index            : 8
        +0x050 TotalNumberOfObjects : 0
        +0x054 TotalNumberOfHandles : 0
        +0x058 HighWaterNumberOfObjects : 0
        +0x05c HighWaterNumberOfHandles : 0
        +0x060 TypeInfo         : _OBJECT_TYPE_INITIALIZER
        +0x0ac Key              : 0x75626544
        +0x0b0 ObjectLocks      : [4] _ERESOURCE
     ​
     0: kd> dt _OBJECT_TYPE_INITIALIZER 89a32298+0x60
     nt!_OBJECT_TYPE_INITIALIZER
        +0x000 Length           : 0x4c
        +0x002 UseDefaultObject : 0 ''
        +0x003 CaseInsensitive  : 0 ''
        +0x004 InvalidAttributes : 0
        +0x008 GenericMapping   : _GENERIC_MAPPING
        +0x018 ValidAccessMask  : 0x1f000f
        +0x01c SecurityRequired : 0x1 ''
        +0x01d MaintainHandleCount : 0 ''
        +0x01e MaintainTypeList : 0 ''
        +0x020 PoolType         : 0 ( NonPagedPool )
        +0x024 DefaultPagedPoolCharge : 0
        +0x028 DefaultNonPagedPoolCharge : 0x30
        +0x02c DumpProcedure    : (null) 
        +0x030 OpenProcedure    : (null) 
        +0x034 CloseProcedure   : 0x80643b68     void  nt!DbgkpCloseObject+0
        +0x038 DeleteProcedure  : 0x8060d98e     void  nt!FsRtlInitializeOplock+0
        +0x03c ParseProcedure   : (null) 
        +0x040 SecurityProcedure : 0x805f9144     long  nt!SeDefaultObjectMethod+0
        +0x044 QueryNameProcedure : (null) 
        +0x048 OkayToCloseProcedure : (null) 

    可以通过Hook ObReferenceObjectByHandle代替DebugObjectType, 让我们的调试器使用

  6. 检测 这里手动在windbg修改KUSER_SHARED_DATA 全局变量 的KdDebuggerEnabled dt _KUSER_SHARED_DATA 0xFFFFF78000000000 修改的命令是eb 0xFFFFF78000000000+0x2d4 0

  7.  hook kdcom!KdSendPacket 和 kdcom!KdReceivePacket

  8. 静态反调试可参考 静态反调试技术(2)_ntquerysysteminformation 反调试-CSDN博客

  9. 反硬件断点和自定义异常处理,在自定义函数中获取硬件断点信息来检测测试器: https://www.cnblogs.com/Sna1lGo/p/15358626.html

     SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); // SEH, VCH, UEH
     AddVectoredExceptionHandler(); // VEH
     AddVectoredContinueHandler(); // VCH
     GetThreadContext(); // 检测硬件断点
     SetThreadContext(); // 硬件断点清零

  10. ObRegisterCallbacks监控进程和线程的创建和退出、暂停、恢复等操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值