首页
论坛
课程
招聘
[原创]x64逆向热身练习: nt!ObRegisterCallbacks回调的检测与摘除
2020-11-17 20:59 4424

[原创]x64逆向热身练习: nt!ObRegisterCallbacks回调的检测与摘除

2020-11-17 20:59
4424

     以前自学了<<C++反汇编与逆向分析揭秘>>,书中讲得很不错,不过:里面全是x86的讲解。x64上,寄存器位数进行了扩充,C/C++函数传参也与x86有所不同, 但其中的分析思路基本上还是一致的。目前毕竟用64位操作系统的机器太多了,所以有必要从32位逆向过渡到64位。目前,我就以逆向内核API:nt! ObRegisterCallbacks分析其中的数据结构和实现逻辑,然后实现对 nt!ObRegisterCallbacks回调的检测与摘除, 对x64逆向进行一次热身练习。

一. 目标操作系统: Win7 X64 内核版本号:7600 (其它系统分析方法大同小异,这里仅仅是练习)

二. 对nt!ObRegisterCallbacks的逆向分析过程:

  1. msdn中已给出函数原型:

NTSTATUS ObRegisterCallbacks(
  _In_  POB_CALLBACK_REGISTRATION CallBackRegistration,
  _Out_ PVOID                     *RegistrationHandle
);

其中个OB_CALLBACK_REGISTRATION相关结构定义如下:
typedef struct _OB_OPERATION_REGISTRATION {
  POBJECT_TYPE                *ObjectType;
  OB_OPERATION                Operations;
  POB_PRE_OPERATION_CALLBACK  PreOperation;
  POB_POST_OPERATION_CALLBACK PostOperation;
} OB_OPERATION_REGISTRATION, *POB_OPERATION_REGISTRATION;

typedef struct _OB_CALLBACK_REGISTRATION {
  USHORT                    Version;
  USHORT                    OperationRegistrationCount;
  UNICODE_STRING            Altitude;
  PVOID                     RegistrationContext;
  OB_OPERATION_REGISTRATION *OperationRegistration;
} OB_CALLBACK_REGISTRATION, *POB_CALLBACK_REGISTRATION;

2. 逆向分析过程,为了不断提高对汇编代码的阅读能力,我这里不用F5,而是IDA Pro静态反汇编分析,如果遇到疑问再动态调试。

(1)调试中相关的数据结构:

0: kd> dt -b nt!_OBJECT_TYPE
   +0x000 TypeList         : _LIST_ENTRY
      +0x000 Flink            : Ptr64 
      +0x008 Blink            : Ptr64 
   +0x010 Name             : _UNICODE_STRING
      +0x000 Length           : Uint2B
      +0x002 MaximumLength    : Uint2B
      +0x008 Buffer           : Ptr64 
   +0x020 DefaultObject    : Ptr64 
   +0x028 Index            : UChar
   +0x02c TotalNumberOfObjects : Uint4B
   +0x030 TotalNumberOfHandles : Uint4B
   +0x034 HighWaterNumberOfObjects : Uint4B
   +0x038 HighWaterNumberOfHandles : Uint4B
   +0x040 TypeInfo         : _OBJECT_TYPE_INITIALIZER
      +0x000 Length           : Uint2B
      +0x002 ObjectTypeFlags  : UChar
      +0x002 CaseInsensitive  : Pos 0, 1 Bit
      +0x002 UnnamedObjectsOnly : Pos 1, 1 Bit
      +0x002 UseDefaultObject : Pos 2, 1 Bit
      +0x002 SecurityRequired : Pos 3, 1 Bit
      +0x002 MaintainHandleCount : Pos 4, 1 Bit
      +0x002 MaintainTypeList : Pos 5, 1 Bit
      +0x002 SupportsObjectCallbacks : Pos 6, 1 Bit
      +0x004 ObjectTypeCode   : Uint4B
      +0x008 InvalidAttributes : Uint4B
      +0x00c GenericMapping   : _GENERIC_MAPPING
         +0x000 GenericRead      : Uint4B
         +0x004 GenericWrite     : Uint4B
         +0x008 GenericExecute   : Uint4B
         +0x00c GenericAll       : Uint4B
      +0x01c ValidAccessMask  : Uint4B
      +0x020 RetainAccess     : Uint4B
      +0x024 PoolType         : 
         NonPagedPool = 0n0
         PagedPool = 0n1
         NonPagedPoolMustSucceed = 0n2
         DontUseThisType = 0n3
         NonPagedPoolCacheAligned = 0n4
         PagedPoolCacheAligned = 0n5
         NonPagedPoolCacheAlignedMustS = 0n6
         MaxPoolType = 0n7
         NonPagedPoolSession = 0n32
         PagedPoolSession = 0n33
         NonPagedPoolMustSucceedSession = 0n34
         DontUseThisTypeSession = 0n35
         NonPagedPoolCacheAlignedSession = 0n36
         PagedPoolCacheAlignedSession = 0n37
         NonPagedPoolCacheAlignedMustSSession = 0n38
      +0x028 DefaultPagedPoolCharge : Uint4B
      +0x02c DefaultNonPagedPoolCharge : Uint4B
      +0x030 DumpProcedure    : Ptr64 
      +0x038 OpenProcedure    : Ptr64 
      +0x040 CloseProcedure   : Ptr64 
      +0x048 DeleteProcedure  : Ptr64 
      +0x050 ParseProcedure   : Ptr64 
      +0x058 SecurityProcedure : Ptr64 
      +0x060 QueryNameProcedure : Ptr64 
      +0x068 OkayToCloseProcedure : Ptr64 
   +0x0b0 TypeLock         : _EX_PUSH_LOCK
      +0x000 Locked           : Pos 0, 1 Bit
      +0x000 Waiting          : Pos 1, 1 Bit
      +0x000 Waking           : Pos 2, 1 Bit
      +0x000 MultipleShared   : Pos 3, 1 Bit
      +0x000 Shared           : Pos 4, 60 Bits
      +0x000 Value            : Uint8B
      +0x000 Ptr              : Ptr64 
   +0x0b8 Key              : Uint4B
   +0x0c0 CallbackList     : _LIST_ENTRY
      +0x000 Flink            : Ptr64 
      +0x008 Blink            : Ptr64 

0: kd> dt nt!_EX_PUSH_LOCK
   +0x000 Locked           : Pos 0, 1 Bit
   +0x000 Waiting          : Pos 1, 1 Bit
   +0x000 Waking           : Pos 2, 1 Bit
   +0x000 MultipleShared   : Pos 3, 1 Bit
   +0x000 Shared           : Pos 4, 60 Bits
   +0x000 Value            : Uint8B
   +0x000 Ptr              : Ptr64 Void

kd> dt nt!_KAPC_STATE
   +0x000 ApcListHead      : [2] _LIST_ENTRY
   +0x020 Process          : Ptr64 _KPROCESS
   +0x028 KernelApcInProgress : UChar
   +0x029 KernelApcPending : UChar
   +0x02a UserApcPending   : UChar

(2)对ObRegisterCallbacks的内部实现的静态分析过程

PAGE:00000001404AA640                 public ObRegisterCallbacks
PAGE:00000001404AA640 ObRegisterCallbacks proc near
PAGE:00000001404AA640
PAGE:00000001404AA640 arg_0           = qword ptr  8
PAGE:00000001404AA640 arg_8           = qword ptr  10h
PAGE:00000001404AA640 arg_10          = qword ptr  18h
PAGE:00000001404AA640 arg_18          = qword ptr  20h
PAGE:00000001404AA640
PAGE:00000001404AA640                 mov     rax, rsp
PAGE:00000001404AA643                 mov     [rax+8], rbx
PAGE:00000001404AA647                 mov     [rax+18h], rbp
PAGE:00000001404AA64B                 mov     [rax+20h], rsi
PAGE:00000001404AA64F                 mov     [rax+10h], rdx
PAGE:00000001404AA653                 push    rdi
PAGE:00000001404AA654                 push    r12
PAGE:00000001404AA656                 push    r13
PAGE:00000001404AA658                 push    r14
PAGE:00000001404AA65A                 push    r15
PAGE:00000001404AA65C                 sub     rsp, 20h
PAGE:00000001404AA660                 movzx   eax, word ptr [rcx]
PAGE:00000001404AA663                 xor     ebx, ebx
PAGE:00000001404AA665                 mov     r12, rcx        ; CallBackRegistration
PAGE:00000001404AA668                 mov     ecx, 0FF00h
PAGE:00000001404AA66D                 mov     r14d, 100h      ; OB_FLT_REGISTRATION_VERSION
PAGE:00000001404AA673                 mov     r15, rdx        ; RegistrationHandle
PAGE:00000001404AA676                 and     ax, cx          ; 取CallBackRegistration->Version的低8位
PAGE:00000001404AA679                 mov     esi, ebx
PAGE:00000001404AA67B                 cmp     ax, r14w        ; CallBackRegistration->Version&0xFF验证,即:CallBackRegistration->Version的低8位必须为: 0x100(OB_FLT_REGISTRATION_VERSION)
PAGE:00000001404AA67F                 jz      short loc_1404AA68B ; 如果验证通不过,最终返回STATUS_INVALID_PARAMETER
PAGE:00000001404AA681
PAGE:00000001404AA681 loc_1404AA681:                          ; CODE XREF: ObRegisterCallbacks+51j
PAGE:00000001404AA681                 mov     eax, 0C000000Dh ; STATUS_INVALID_PARAMETER
PAGE:00000001404AA686                 jmp     loc_1404AA8E9
PAGE:00000001404AA68B ; ---------------------------------------------------------------------------
PAGE:00000001404AA68B
PAGE:00000001404AA68B loc_1404AA68B:                          ; CODE XREF: ObRegisterCallbacks+3Fj
PAGE:00000001404AA68B                 cmp     [r12+2], bx     ; CallBackRegistration->OperationRegistrationCount验证
PAGE:00000001404AA691                 jz      short loc_1404AA681 ; 如果验证通不过,最终返回STATUS_INVALID_PARAMETER
PAGE:00000001404AA693                 movzx   ecx, word ptr [r12+2] ; CallBackRegistration->OperationRegistrationCount
PAGE:00000001404AA699                 movzx   eax, word ptr [r12+8] ; CallBackRegistration->Altitude->Length
PAGE:00000001404AA69F                 mov     r8d, 6C46624Fh  ; Tag
PAGE:00000001404AA6A5                 shl     ecx, 6
PAGE:00000001404AA6A8                 lea     ebp, [rcx+rax+20h] ; 分配空间长度: CallBackRegistration->OperationRegistrationCount*64+CallbackRegistration->Altitude->Length+32
PAGE:00000001404AA6AC                 mov     ecx, 1          ; PoolType
PAGE:00000001404AA6B1                 mov     edx, ebp        ; NumberOfBytes
PAGE:00000001404AA6B3                 mov     r13d, ebp
PAGE:00000001404AA6B6                 call    ExAllocatePoolWithTag ; 分配PagedPool缓冲区
PAGE:00000001404AA6BB                 mov     rdi, rax
PAGE:00000001404AA6BE                 cmp     rax, rbx
PAGE:00000001404AA6C1                 jnz     short loc_1404AA6CD
PAGE:00000001404AA6C3                 mov     eax, 0C000009Ah ; STATUS_INSUFFICIENT_RESOURCES
PAGE:00000001404AA6C8                 jmp     loc_1404AA8E9
PAGE:00000001404AA6CD ; ---------------------------------------------------------------------------
PAGE:00000001404AA6CD
PAGE:00000001404AA6CD loc_1404AA6CD:                          ; CODE XREF: ObRegisterCallbacks+81j
PAGE:00000001404AA6CD                 mov     r8, r13         ; Size
PAGE:00000001404AA6D0                 xor     edx, edx        ; Val
PAGE:00000001404AA6D2                 mov     rcx, rax        ; Dst
PAGE:00000001404AA6D5                 call    memset          ; 相当于RtlZeroMemory初始化缓冲区
PAGE:00000001404AA6DA                 mov     [rdi], r14w     ; 缓冲区0偏移处处保存: OB_FLT_REGISTRATION_VERSION
PAGE:00000001404AA6DE                 mov     rax, [r12+18h]  ; CallBackRegistration->RegistrationContext
PAGE:00000001404AA6E3                 mov     [rdi+8], rax    ; 缓冲区8字节偏移处保存CallBackRegistration->RegistrationContext
PAGE:00000001404AA6E7                 movzx   edx, word ptr [r12+8] ; CallBackRegistration->Altitude->Length
PAGE:00000001404AA6ED                 sub     ebp, edx
PAGE:00000001404AA6EF                 mov     [rdi+12h], dx   ; 缓冲区0x12处保存: CallBackRegistration->Altitude->Length
PAGE:00000001404AA6F3                 mov     [rdi+10h], dx   ; 缓冲区0x10处保存: CallBackRegistration->Altitude->Length
PAGE:00000001404AA6F7                 mov     r8, rdx         ; Size
PAGE:00000001404AA6FA                 mov     ecx, ebp
PAGE:00000001404AA6FC                 add     rcx, rdi        ; Dst
PAGE:00000001404AA6FF                 mov     [rdi+18h], rcx  ; 缓冲区0x18处保存一个指向WSTR缓冲区的指针
PAGE:00000001404AA703                 mov     rdx, [r12+10h]  ; Src
PAGE:00000001404AA708                 call    memmove         ; 相当于: RtlCopyUnicodeString(rdi+0x10,&CallBackRegistration->Altitude),于是缓冲区0x10偏移处数据类型为UNICODE_STRING,保存Altitude
PAGE:00000001404AA70D                 mov     r14d, ebx       ; 循环计数器n初始化为0
PAGE:00000001404AA710                 cmp     bx, [r12+2]     ; 验证: CallBackRegistration->OperationRegistrationCount
PAGE:00000001404AA716                 jnb     loc_1404AA8BD   ; 前面已经验证过: CallBackRegistration->OperationRegistrationCount!=0了,对于无符号数:  CallBackRegistration->OperationRegistrationCount>0,不可能跳转到loc_1404AA8BD处
PAGE:00000001404AA71C                 mov     rbp, rbx        ; 说明: 0 < CallllBackRegistration->OperationRegistrationCount,其中rbp指向CallbackRegistration->OperationRegistration中的某个元素, 索引号index初始为0
PAGE:00000001404AA71F                 lea     r13, [rdi+58h]  ; rdi+58h保存到r13 <=> r13初始化为: rdi+n*40h+58h, 其中n为0
PAGE:00000001404AA723
PAGE:00000001404AA723 loc_1404AA723:                          ; CODE XREF: ObRegisterCallbacks+199j
PAGE:00000001404AA723                 mov     rsi, [r12+20h]  ; CallbackRegistration->OperationRegistration
PAGE:00000001404AA728                 cmp     [rsi+rbp+8], ebx ; 验证: CallbackRegistaion->OperationRegistration[index].Operations
PAGE:00000001404AA72C                 jz      loc_1404AA7E8   ; 如果验证通不过,最终会返回: STATUS_INVALID_PARAMETER
PAGE:00000001404AA732                 mov     rax, [rsi+rbp]  ; CallbackRegistaion->OperationRegistration[index].OjbectType
PAGE:00000001404AA736                 mov     rcx, [rax]      ; CallbackRegistaion->OperationRegistration[index].ObjectType->TypeList.Flink实际上就是: CallbackRegistaion->OperationRegistration[index].ObjectType
PAGE:00000001404AA739                 test    byte ptr [rcx+42h], 40h ; 验证ObjectType->TypeInfo.ObjectTypeFlags
PAGE:00000001404AA73D                 jz      loc_1404AA7E8   ; 如果验证通不过,最终会返回: STATUS_INVALID_PARAMETER
PAGE:00000001404AA743                 mov     rcx, [rsi+rbp+10h] ; CallbackRegistaion->OperationRegistration[index].PreOperation
PAGE:00000001404AA748                 cmp     rcx, rbx        ; 检查CallbackRegistaion->OperationRegistration[index].PreOperation是否为空
PAGE:00000001404AA74B                 jnz     short loc_1404AA75D ; CallbackRegistaion->OperationRegistration[index].PreOperation!=NULL则跳
PAGE:00000001404AA74D                 cmp     [rsi+rbp+18h], rbx ; 检查CallbackRegistaion->OperationRegistration[index].PostOperation是否为空
PAGE:00000001404AA752                 jz      loc_1404AA7E8   ; 如果PreOperation,PostOperation都为空了,最终返回STATUS_INVALID_PARAMETER
PAGE:00000001404AA758                 cmp     rcx, rbx        ; 检查CallbackRegistaion->OperationRegistration[index].PreOperation是否为空
PAGE:00000001404AA75B                 jz      short loc_1404AA766 ; CallbackRegistaion->OperationRegistration[index].PreOperation==NULL则跳
PAGE:00000001404AA75D
PAGE:00000001404AA75D loc_1404AA75D:                          ; CODE XREF: ObRegisterCallbacks+10Bj
PAGE:00000001404AA75D                 call    sub_1404647F0   ; if(CallbackRegistaion->OperationRegistration[index].PreOperation!=NULL) call nt!MmVerifyCallbackFunction
PAGE:00000001404AA762                 cmp     eax, ebx
PAGE:00000001404AA764                 jz      short loc_1404AA7E1 ; STATUS_ACCESS_DENIED, 预操作回调校验失败
PAGE:00000001404AA766
PAGE:00000001404AA766 loc_1404AA766:                          ; CODE XREF: ObRegisterCallbacks+11Bj
PAGE:00000001404AA766                 mov     rcx, [rsi+rbp+18h] ; CallbackRegistaion->OperationRegistration[index].PostOperation
PAGE:00000001404AA76B                 cmp     rcx, rbx
PAGE:00000001404AA76E                 jz      short loc_1404AA779 ; CallbackRegistaion->OperationRegistration[index].PostOperation为空则跳
PAGE:00000001404AA770                 call    sub_1404647F0   ; if(CallbackRegistaion->OperationRegistration[index].PostOperation!=NULL) call nt!MmVerifyCallbackFunction
PAGE:00000001404AA775                 cmp     eax, ebx
PAGE:00000001404AA777                 jz      short loc_1404AA7E1 ; STATUS_ACCESS_DENIED, 后操作回调校验失败
PAGE:00000001404AA779
PAGE:00000001404AA779 loc_1404AA779:                          ; CODE XREF: ObRegisterCallbacks+12Ej
PAGE:00000001404AA779                 mov     [r13+0], rbx    ; 缓冲区n*0x40+0x58处(rdi+n*40h+58h)保存0
PAGE:00000001404AA77D                 lea     rdx, [r13-38h]  ; 缓冲区n*0x40+0x20处地址(rdi+n*40h+58h-38h==rdi+n*40h+20h)
PAGE:00000001404AA781                 mov     [rdx], rdx      ; 缓冲区n*0x40+0x20处指向自身
PAGE:00000001404AA784                 mov     [r13-30h], rdx  ; 缓冲区n*0x40+0x28处指向自生,说明: 缓冲区n*0x40+0x20处是LIST_ENTRY类型,相当于执行的是InitializeListHead([rdi+n*40h+20h])
PAGE:00000001404AA788                 mov     eax, [rsi+rbp+8] ; CallbackRegistaion->OperationRegistration[index].Operations
PAGE:00000001404AA78C                 mov     [r13-28h], eax  ; 缓冲区n*0x40+0x30处(rdi+n*40h+58h-28h==rdi+n*40h+30h)保存: CallbackRegistaion->OperationRegistration[index].Operations
PAGE:00000001404AA790                 mov     [r13-20h], rdi  ; 缓冲区n*0x40+0x38处(rdi+n*40h+58h-20h==rdi+n*40h+38h)指向缓冲区本身(rdi)
PAGE:00000001404AA794                 mov     rax, [rsi+rbp]  ; CallbackRegistation->OperationRegistration[index].OjbectType
PAGE:00000001404AA798                 mov     rcx, [rax]      ; CallbackRegistation->OperationRegistration[index].OjbectType->TypeList.Flink
PAGE:00000001404AA79B                 mov     [r13-18h], rcx  ; 缓冲区n*0x40+0x40处(rdi+n*40h+58h-18h==rdi+n*40h+40h)保存:CallbackRegistation->OperationRegistration[index].OjbectType->TypeList.Flink
PAGE:00000001404AA79F                 mov     rax, [rsi+rbp+10h] ; CallbackRegistaion->OperationRegistration[index].PreOperation
PAGE:00000001404AA7A4                 mov     [r13-10h], rax  ; 缓冲区n*0x40+0x48偏移处(rdi+n*40h+58h-10h==rdi+n*40h+48h)保存: CallbackRegistaion->OperationRegistration[index].PreOperation
PAGE:00000001404AA7A8                 mov     rax, [rsi+rbp+18h] ; CallbackRegistaion->OperationRegistration[index].PostOperation
PAGE:00000001404AA7AD                 mov     [r13-8], rax    ; 缓冲区n*0x40+0x50处(rdi+n*40h+58h-8==rdi+n*40h+50h)保存: CallbackRegistaion->OperationRegistration[index].PostOperation
PAGE:00000001404AA7B1                 call    sub_140400A60   ; call nt!ObpInsertCallbackByAltitude 插入回调
PAGE:00000001404AA7B6                 cmp     eax, ebx        ; 插入是否成功判断
PAGE:00000001404AA7B8                 mov     esi, eax
PAGE:00000001404AA7BA                 jl      short loc_1404AA7F5 ; 如果有一项插入失败了则跳
PAGE:00000001404AA7BC                 mov     eax, 1
PAGE:00000001404AA7C1                 add     rbp, 20h        ; 指向CallbackRegistaion->OperationRegistration的下1个元素,index++
PAGE:00000001404AA7C5                 add     r13, 40h        ; 指向数组(每个元素为0x40字节)中的下1个元素
PAGE:00000001404AA7C9                 add     [rdi+2], ax     ; 当成功插入回调后,缓冲区+2偏移处加1,计为inserted
PAGE:00000001404AA7CD                 movzx   ecx, word ptr [r12+2] ; CallBackRegistration->OperationRegistrationCount
PAGE:00000001404AA7D3                 add     r14d, eax       ; 循环计数器加1: n++
PAGE:00000001404AA7D6                 cmp     r14d, ecx       ; 循环条件: 循环计数器n<CallBackRegistration->OperationRegistrationCount
PAGE:00000001404AA7D9                 jb      loc_1404AA723   ; n==CallbackRegistration->OperationRegistrationCount则退出循环
PAGE:00000001404AA7DF                 jmp     short loc_1404AA7ED
PAGE:00000001404AA7E1 ; ---------------------------------------------------------------------------
PAGE:00000001404AA7E1
PAGE:00000001404AA7E1 loc_1404AA7E1:                          ; CODE XREF: ObRegisterCallbacks+124j
PAGE:00000001404AA7E1                                         ; ObRegisterCallbacks+137j
PAGE:00000001404AA7E1                 mov     esi, 0C0000022h ; STATUS_ACCESS_DENIED
PAGE:00000001404AA7E6                 jmp     short loc_1404AA7F5 ; 失败了
PAGE:00000001404AA7E8 ; ---------------------------------------------------------------------------
PAGE:00000001404AA7E8
PAGE:00000001404AA7E8 loc_1404AA7E8:                          ; CODE XREF: ObRegisterCallbacks+ECj
PAGE:00000001404AA7E8                                         ; ObRegisterCallbacks+FDj ...
PAGE:00000001404AA7E8                 mov     esi, 0C000000Dh ; STATUS_INVALID_PARAMETER
PAGE:00000001404AA7ED
PAGE:00000001404AA7ED loc_1404AA7ED:                          ; CODE XREF: ObRegisterCallbacks+19Fj
PAGE:00000001404AA7ED                 cmp     esi, ebx
PAGE:00000001404AA7EF                 jge     loc_1404AA8BD   ; 成功则跳
PAGE:00000001404AA7F5
PAGE:00000001404AA7F5 loc_1404AA7F5:                          ; CODE XREF: ObRegisterCallbacks+17Aj
PAGE:00000001404AA7F5                                         ; ObRegisterCallbacks+1A6j
PAGE:00000001404AA7F5                 mov     r12d, ebx       ; index初始值为: 0
PAGE:00000001404AA7F8                 cmp     bx, [rdi+2]     ; 循环次数为: inserted
PAGE:00000001404AA7FC                 jnb     loc_1404AA8AE   ; 已插入数为0则跳
PAGE:00000001404AA802                 lea     rbp, [rdi+40h]  ; rdi+0x40计为: rdi+0x20+0*0x40+0x20
PAGE:00000001404AA806                 mov     r14d, 0B0h
PAGE:00000001404AA80C                 mov     r13d, 1
PAGE:00000001404AA812
PAGE:00000001404AA812 loc_1404AA812:                          ; CODE XREF: ObRegisterCallbacks+268j
PAGE:00000001404AA812                 mov     rax, gs:188h    ; kThread
PAGE:00000001404AA81B                 dec     word ptr [rax+1C6h] ; kThread->SpecialApcDisable--
PAGE:00000001404AA822                 mov     rcx, [rbp+0]    ; ObjectType
PAGE:00000001404AA826                 add     rcx, r14        ; ObjectType->TypeLock
PAGE:00000001404AA829                 lock bts qword ptr [rcx], 0 ; ObjectType->TypeLock的bit0送CF,然后将ObjectType->TypeLock的bit0置1
PAGE:00000001404AA82F                 jnb     short loc_1404AA836 ; CF==0则跳
PAGE:00000001404AA831                 call    ExfAcquirePushLockExclusive ; CF==1时会执行
PAGE:00000001404AA836
PAGE:00000001404AA836 loc_1404AA836:                          ; CODE XREF: ObRegisterCallbacks+1EFj
PAGE:00000001404AA836                 mov     rax, [rbp-18h]  ; CallbackLinks.Blink
PAGE:00000001404AA83A                 mov     rcx, [rbp-20h]  ; CallbackLinks.Flink
PAGE:00000001404AA83E                 mov     [rax], rcx      ; CallbackLinks.Blink->Flink=Callbacks.Flink
PAGE:00000001404AA841                 mov     [rcx+8], rax    ; CallbackLinks.Flink->Blink=CallbackLinks.Blink  所以以上4条指令相当于RemoveEntryList(&CallbackLinks)
PAGE:00000001404AA845                 mov     rdx, [rbp+0]    ; ObjectType->TypeList.Flink实际上就是指向的ObjectType本身
PAGE:00000001404AA849                 add     rdx, r14        ; ObjectType->TypeLock
PAGE:00000001404AA84C                 prefetchw byte ptr [rdx]
PAGE:00000001404AA84F                 mov     rax, [rdx]      ; ObjectType->TypeLock.Ptr
PAGE:00000001404AA852                 mov     rcx, rax
PAGE:00000001404AA855                 and     rcx, 0FFFFFFFFFFFFFFF0h ; (ULONG_PTR)ObjectType->TypeLock.Ptr&0xFFFFFFFFFFFFFFF0
PAGE:00000001404AA859                 cmp     rcx, 10h
PAGE:00000001404AA85D                 lea     rcx, [rax-10h]  ; (ULONG_PTR)ObjectType->TypeLock.Ptr-0x10
PAGE:00000001404AA861                 ja      short loc_1404AA866 ; (ULONG_PTR)ObjectType->TypeLock.Ptr&0xFFFFFFFFFFFFFFF0 > 0x10则跳
PAGE:00000001404AA863                 mov     rcx, rbx
PAGE:00000001404AA866
PAGE:00000001404AA866 loc_1404AA866:                          ; CODE XREF: ObRegisterCallbacks+221j
PAGE:00000001404AA866                 test    al, 2           ; ((BYTE)ObjectType->TypeLock.Ptr)&2
PAGE:00000001404AA868                 jnz     short loc_1404AA871
PAGE:00000001404AA86A                 lock cmpxchg [rdx], rcx ; 如果[rdx]==rax,ZF置1,rcx送[rdx], 否则:ZF置0, [rdx]送rax
PAGE:00000001404AA86F                 jz      short loc_1404AA879 ; ZF==1则跳
PAGE:00000001404AA871
PAGE:00000001404AA871 loc_1404AA871:                          ; CODE XREF: ObRegisterCallbacks+228j
PAGE:00000001404AA871                 mov     rcx, rdx
PAGE:00000001404AA874                 call    ExfReleasePushLock ; ((BYTE)ObjectType->TypeLock.Ptr)&2!=0或者ZF==0时执行
PAGE:00000001404AA879
PAGE:00000001404AA879 loc_1404AA879:                          ; CODE XREF: ObRegisterCallbacks+22Fj
PAGE:00000001404AA879                 mov     rax, gs:188h    ; kThread
PAGE:00000001404AA882                 add     [rax+1C6h], r13w ; ++kThread->SpecialApcDisable
PAGE:00000001404AA88A                 jnz     short loc_1404AA89A ; kThread->SpecialApcDisable!=0则跳
PAGE:00000001404AA88C                 add     rax, 50h        ; kThread->ApcState
PAGE:00000001404AA890                 cmp     [rax], rax      ; kThread->ApcState.ApcListHead[0].Flink==&kThread->ApcState.ApcListHead[0] or not <=> IsListEmtpy(&kThread->ApcState.ApcListHead[0]) or not
PAGE:00000001404AA893                 jz      short loc_1404AA89A ; 不需要递送内核模式APC则跳
PAGE:00000001404AA895                 call    KiCheckForKernelApcDelivery ; kThread->SpecialApcDisable==0且!IsListEmpty(&kThread->ApcState.ApcListHead[0]),需要检查并递送内核模式APC
PAGE:00000001404AA89A
PAGE:00000001404AA89A loc_1404AA89A:                          ; CODE XREF: ObRegisterCallbacks+24Aj
PAGE:00000001404AA89A                                         ; ObRegisterCallbacks+253j
PAGE:00000001404AA89A                 movzx   eax, word ptr [rdi+2] ; 已插入的个数
PAGE:00000001404AA89E                 add     r12d, r13d      ; index++
PAGE:00000001404AA8A1                 add     rbp, 40h        ; 指向下一个位置
PAGE:00000001404AA8A5                 cmp     r12d, eax
PAGE:00000001404AA8A8                 jb      loc_1404AA812   ; 对已插入项回滚完毕则退出循环
PAGE:00000001404AA8AE
PAGE:00000001404AA8AE loc_1404AA8AE:                          ; CODE XREF: ObRegisterCallbacks+1BCj
PAGE:00000001404AA8AE                 mov     edx, 6C46624Fh  ; Tag
PAGE:00000001404AA8B3                 mov     rcx, rdi        ; P
PAGE:00000001404AA8B6                 call    ExFreePoolWithTag ; 释放空间
PAGE:00000001404AA8BB                 jmp     short loc_1404AA8E7
PAGE:00000001404AA8BD ; ---------------------------------------------------------------------------
PAGE:00000001404AA8BD
PAGE:00000001404AA8BD loc_1404AA8BD:                          ; CODE XREF: ObRegisterCallbacks+D6j
PAGE:00000001404AA8BD                                         ; ObRegisterCallbacks+1AFj
PAGE:00000001404AA8BD                 cmp     bx, [rdi+2]     ; index初始为0, 循环次数为插入数: inserted
PAGE:00000001404AA8C1                 jnb     short loc_1404AA8E4 ; 无符号inserted==0则跳
PAGE:00000001404AA8C3                 lea     rcx, [rdi+34h]  ; 缓冲区0x34偏移处,计为: 0x20+0*64+0x14
PAGE:00000001404AA8C7                 mov     r15d, 1
PAGE:00000001404AA8CD
PAGE:00000001404AA8CD loc_1404AA8CD:                          ; CODE XREF: ObRegisterCallbacks+29Dj
PAGE:00000001404AA8CD                 or      [rcx], r15d     ; 缓冲区0x20+index*64+0x14处设置InsertFlag标志
PAGE:00000001404AA8D0                 movzx   eax, word ptr [rdi+2]
PAGE:00000001404AA8D4                 add     ebx, r15d       ; index++
PAGE:00000001404AA8D7                 add     rcx, 40h        ; 0x20+index*64+0x14
PAGE:00000001404AA8DB                 cmp     ebx, eax
PAGE:00000001404AA8DD                 jb      short loc_1404AA8CD ; 对所有项: InsertFlag标志置1完成则退出循环
PAGE:00000001404AA8DF                 mov     r15, [rsp+48h+arg_8]
PAGE:00000001404AA8E4
PAGE:00000001404AA8E4 loc_1404AA8E4:                          ; CODE XREF: ObRegisterCallbacks+281j
PAGE:00000001404AA8E4                 mov     [r15], rdi      ; 成功了, RegistrationHandle句柄值为缓冲区地址
PAGE:00000001404AA8E7
PAGE:00000001404AA8E7 loc_1404AA8E7:                          ; CODE XREF: ObRegisterCallbacks+27Bj
PAGE:00000001404AA8E7                 mov     eax, esi
PAGE:00000001404AA8E9
PAGE:00000001404AA8E9 loc_1404AA8E9:                          ; CODE XREF: ObRegisterCallbacks+46j
PAGE:00000001404AA8E9                                         ; ObRegisterCallbacks+88j
PAGE:00000001404AA8E9                 mov     rbx, [rsp+48h+arg_0]
PAGE:00000001404AA8EE                 mov     rbp, [rsp+48h+arg_10]
PAGE:00000001404AA8F3                 mov     rsi, [rsp+48h+arg_18]
PAGE:00000001404AA8F8                 add     rsp, 20h
PAGE:00000001404AA8FC                 pop     r15
PAGE:00000001404AA8FE                 pop     r14
PAGE:00000001404AA900                 pop     r13
PAGE:00000001404AA902                 pop     r12
PAGE:00000001404AA904                 pop     rdi
PAGE:00000001404AA905                 retn

(3)通过细细阅读,可以逆推出RegistratioHandle所指向的缓冲区数据结构:

//Obp回调信息,RegistratioHandle所指向的缓冲区结构
typedef struct _OBP_CALLBACK_INFO{
    USHORT Version;                   //offset: 0x0  版本:OB_FLT_REGISTRATION_VERSION
    USHORT Inserted;                  //offset: 0x2  插入的回调项个数,即:数组ObpCallbackEntries元素个数
    PVOID RegistrationContext ;  //offset: 0x8      RegistrationContext
    UNICODE_STRING Altitude;   //offset: 0x10   Altitude
    OBP_CALLBACK_ENTRY  ObpCallbackEntries[ANY_SIZE];  //offset: 0x20, OBP_CALLBACK_ENTRY数组,元素个数为:  CallbackRegistration->OperationRegistrationCount
 }OBP_CALLBACK_INFO,*POBP_CALLBACK_INFO,*LPOBP_CALLBACK_INFO;


其中OBP_CALLBACK_ENTRY为回调项信息,数据结构如下:

//Obp回调项(0x40==64字节),index表示在OBP_CALLBACK_INFO的ObpCallbackEntries数组元素索引号
typedef struct _OBP_CALLBACK_ENTRY{
    LIST_ENTRY CallbackLinks;     //offset from OBP_CALLBACK_INFO: 0x20+index*64  //链节点
    OB_OPERATION  Operations; //offset from OBP_CALLBACK_INFO: 0x30+index*64 //操作
    ULONG InsertFlag;    //offset from OBP_CALLBACK_INFO: 0x34+index*64  //插入标志,插入后会置1
    PVOID pSelf;     //offset from OBP_CALLBACK_INFO: 0x38+index*64    //指向: OBP_CALLBACK_INFO,即保存的是: RegistratioHandle
    PLIST_ENTRY pListObjectTypeEntry; //offset from OBP_CALLBACK_INFO: 0x40+index*64 //指向: CallbackRegistation->OperationRegistration[index].OjbectType->TypeList.Flink,通过后续的调试分析实际上就等于: &CallbackRegistation->OperationRegistration[index].OjbectType->TypeList,指向的就是OBJECT_TYPE本身
    POB_PRE_OPERATION_CALLBACK  PreOperation; //offset from OBP_CALLBACK_INFO: 0x48+index*64  //预操作回调
    POB_POST_OPERATION_CALLBACK  PostOperation; //offset from OBP_CALLBACK_INFO: 0x50+index*64 //后操作回调用
    UCHAR Fill[8];  //offset from OBP_CALLBACK_INFOt: 0x58+index*64, 填满64字节
}OBP_CALLBACK_ENTRY,*POBP_CALLBACK_ENTRY,*LPOBP_CALLBACK_ENTRY;

整个RegistratioHandle所指向的缓冲区尾部的最后CallbackRegistration->Altitude->Length字节保存: pObpCallbackInfo->Altitude->Buffer所指向的UNICODE串缓冲区


(4)ObRegisterCallbacks等价的C实现:

#define TAG 'ObFl'

//ObRegisterCallbacks内部实现还原:
//实际上是将回调项信息(POBP_CALLBACK_ENTRY)插入了*PsProcessType或*PsThreadType这些ObjectType的CallackList中
//所有后续在检查回调时,通过pObpCallbackEntry->pSelf就可得到POBP_CALLBACK_INFO,即:RegistratioHandle
NTSTATUS ObRegisterCallbacks(
    IN POB_CALLBACK_REGISTRATION  CallBackRegistration,
    OUT PVOID  *RegistrationHandle
)
{
    POBP_CALLBACK_INFO pObpCallbackInfo;
    PKTHREAD pkThread;
    POBJECT_TYPE pObjectType;
    ULONG_PTR RCX,RAX,RDX;
    NTSTATUS ntStatus;
    ULONG i,ulNumberOfBytes,ulAttitudeStrOffset;
    BOOLEAN bVerified;
    LONG CF,ZF;
    
    
    //回调版本信息,个数校验
    if(CallBackRegistration->Version&0xFF00==0x100&&CallBackRegistration->OperationRegistrationCount>0){
        //分配缓冲区
        ulNumberOfBytes=CallbackRegistration->OperationRegistrationCount*sizeof(OBP_CALLBACK_ENTRY)+0x20+CallbackRegistration->Altitude->Length; //缓冲区长度
        pObpCallbackInfo=(POBP_CALLBACK_INFO)ExAllocatePoolWithTag(PagedPool,
            (SIZE_T)ulNumberOfBytes,
            TAG); 
        if(pObpCallbackInfo==NULL) return STATUS_INSUFFICIENT_RESOURCES;  
        
        //缓冲区初始化为0
        RtlZeroMemory(pObpCallbackInfo,
            sizeof(OBP_CALLBACK_INFO));
        
        //向缓冲区填写信息
        pObpCallbackInfo->Version=0x100;
        pObpCallbackInfo->RegistrationContext=CallBackRegistration->RegistrationContext;
        ulAttitudeStrOffset=ulNumberOfBytes-CallBackRegistration->Altitude->Length;
        RtlInitEmptyUnicodeString(&pObpCallbackInfo->Altitude,
            (PUCHAR)pObpCallbackInfo+ulAttitudeStrOffset,
            CallBackRegistration->Altitude->Length);
        RtlCopyUnicodeString(&pObpCallbackInfo->Altitude,&CallBackRegistration->Altitude);
        
        //回调项逐个填写并插入ObjectType->CallbackList中,可能有多个,取决于CallBackRegistration->OperationRegistrationCount
        for(i=0;i<CallBackRegistration->OperationRegistrationCount;i++){
             //对CallbackRegistaion->OperationRegistration[i]的相关域进行检查
            if(CallbackRegistaion->OperationRegistration[i].Operations!=0
                &&(CallbackRegistaion->OperationRegistration[i].ObjectType->TypeInfo.ObjectTypeFlags&0x40)!=0
                &&(CallbackRegistaion->OperationRegistration[i].PreOperation!=NULL||CallbackRegistaion->OperationRegistration[i].PostOperation!=NULL)){ 
                
                //对回调函数作校验
                bVerified=FALSE;
                if(CallbackRegistaion->OperationRegistration[i].PreOperation!=NULL){
                   //预操作回调需要校验
                   bVerified=MmVerifyCallbackFunction(CallbackRegistaion->OperationRegistration[i].PreOperation);
                   if(CallbackRegistaion->OperationRegistration[i].PostOperation!=NULL){
                       //后操作回调都需要作校验
                       bVerified=MmVerifyCallbackFunction(CallbackRegistaion->OperationRegistration[i].PostOperation);
                   }
                }else{
                    if(CallbackRegistaion->OperationRegistration[i].PostOperation!=NULL){
                        //后操作回调需要校验
                        bVerified=MmVerifyCallbackFunction(CallbackRegistaion->OperationRegistration[i].PostOperation);
                    }
                }
                if(bVerified){
                    //填写回调项
                    *(PULONG)&pObpCallbackInfo->ObpCallbackEntries[i].Fill[0]=0;
                    pObpCallbackInfo->ObpCallbackEntries[i].CallbackLinks.Flink=pObpCallbackInfo->ObpCallbackEntries[i].CallbackLinks.Blink=&pObpCallbackInfo->ObpCallbackEntries[i].CallbackLinks;
                    pObpCallbackInfo->ObpCallbackEntries[i].Operations=CallbackRegistaion->OperationRegistration[i].Operations;
                    pObpCallbackInfo->ObpCallbackEntries[i].pSelf=(PVOID)pObpCallbackInfo;
                    //通过调试观察: CallbackRegistaion->OperationRegistration[i].OjbectType->TypeList.Flink==&CallbackRegistaion->OperationRegistration[i].OjbectType->TypeList
                    //实际上就是指向的CallbackRegistaion->OperationRegistration[i].OjbectType自身
                    pObpCallbackInfo->ObpCallbackEntries[i].pListObjectTypeEntry=CallbackRegistaion->OperationRegistration[i].OjbectType->TypeList.Flink;
                    pObpCallbackInfo->ObpCallbackEntries[i].PreOperation=Registaion->OperationRegistration[i].PreOperation;
                    pObpCallbackInfo->ObpCallbackEntries[i].PostOperation=Registaion->OperationRegistration[i].PostOperation;

                    //插入回调用项
                    ntStatus=ObpInsertCallbackByAltitude(&CallbackRegistaion->OperationRegistration[i].OjbectType,
                        &pObpCallbackInfo->ObpCallbackEntries[i]);
                }else{
                    ntStatus=STATUS_ACCESS_DENIED;
                }
            }else{
                ntStatus=STATUS_INVALID_PARAMETER;
            }

            if(NT_SUCCESS(ntStatus)){
                //回调项插入成功,插入数递增
                pObpCallbackInfo->Inserted++;
            }else{
                //有回调项插入失败了,对于前面已插入的,需要作回滚处理,并且退出
                for(i=0;i<pObpCallbackInfo->Inserted;i++){
                     pkThread=(PKTHREAD)PsGetCurrentThread();
                     pkThread->SpecialApcDisable--;
                     pObjectType=(POBJECT_TYPE)CONTAINING_RECORD(pObpCallbackInfo->ObpCallbackEntries[i].pListObjectTypeEntry,
                         OBJECT_TYPE,
                         TypeList);
                     
                     //模拟: lock bts qword ptr [rcx], 0 ; ObjectType->TypeLock的bit0送CF,然后将ObjectType->TypeLock的bit0置1
                     CF=1;
                     pObjectType->TypeLock.Locked=InterlockedExchange(&CF,
                        (LONG)(pObjectType->TypeLock.Locked&0x1));   
                     if(CF){
                         ExfAcquirePushLockExclusive(&pObjectType->TypeLock);
                     }
                     
                     RemovEntryList(&pObpCallbackInfo->ObpCallbackEntries[i].CallbackLinks);  //从回调链中移除
                     
                     RAX=(ULONG_PTR)pObjectType->TypeLock.Ptr;  //mov     rax, [rdx]
                     RCX= RAX;
                     RCX&=0xFFFFFFFFFFFFFFF0;
                     RCX=RCX>0x10?RAX-0x10:0;

                     if(!(((BYTE)RAX)&2)){
                         //模拟: lock cmpxchg [rdx], rcx: 如果[rdx]==rax,ZF置1,rcx送[rdx], 否则:ZF置0, [rdx]送rax
                         if((ULONG_TR)InterlockedCompareExchangePointer(&pObjectType->TypeLock.Ptr,
                             (PVOID)RCX,
                             (PVOID)RAX)==RAX){
                             ZF=1;
                         }else{
                             ZF=0;
                             RAX=(ULONG_PTR)pObjectType->TypeLock.Ptr;
                         }
                         if(!ZF){
                             ExfReleasePushLock(&pObjectType->TypeLock);
                         }
                     }else{
                         ExfReleasePushLock(&pObjectType->TypeLock);
                     }
                     if(++pkThread->SpecialApcDisable==0&&!IsListEmpty(&kThread->ApcState.ApcListHead[0])){
                         KiCheckForKernelApcDelivery();  //检查并递送内核模式APC
                     }
                }//end for
                
                //释放缓冲区并退出
                ExFreePoolWithTag(pObpCallbackInfo,
                    TAG);
                break;
            }
        }//end for
    }else{
        ntStatus=STATUS_INVALID_PARAMETER;
    }
    if(NT_SUCCESS(ntStatus)){
        //所有的都成功了,把每个回调项InsertFlag bit0置1
        for(i=0;i<pObpCallbackInfo->Inserted;i++){
             pObpCallbackInfo->ObpCallbackEntries[i].InsertFlag|=1;
        }
        *RegistrationHandle=(PVOID)pObpCallbackInfo; //RegistrationHandle句柄值就是缓冲区地址
    }

    return ntStatus;
}

这里:我产生了一个小小的疑问:

为什么是: pObpCallbackInfo->ObpCallbackEntries[i].pListObjectTypeEntry=CallbackRegistaion->OperationRegistration[i].OjbectType->TypeList.Flink?而不是:  pObpCallbackInfo->ObpCallbackEntries[i].pListObjectTypeEntry=&CallbackRegistaion->OperationRegistration[i].OjbectType->TypeList?难道Flink还指向得有其它对象,或者就是指向ObjectType自身?通过对nt!ObRegisterCallbacks调试观察,找到了答案:


果然是第2种猜测: pObpCallbackInfo->ObpCallbackEntries[i].pListObjectTypeEntry=&CallbackRegistaion->OperationRegistration[i].OjbectType->TypeList,而TypeList是OBJECT_TYPE的第1个成员,所以: 实际上就是pObpCallbackInfo->ObpCallbackEntries[i].pListObjectTypeEntry就是指向OBJECT_TYPE自身


(5)要弄清楚回调项 pObpCallbackInfo->ObpCallbackEntries[i]是如何插入OBJECT_TYPE中的,需要对函数nt!ObpInsertCallbackByAltitude进行逆向分析:

PAGE:0000000140400A60 sub_140400A60   proc near               ; CODE XREF: ObRegisterCallbacks+171p
PAGE:0000000140400A60
PAGE:0000000140400A60 arg_0           = qword ptr  8
PAGE:0000000140400A60 arg_8           = qword ptr  10h
PAGE:0000000140400A60 arg_10          = qword ptr  18h
PAGE:0000000140400A60 arg_18          = qword ptr  20h
PAGE:0000000140400A60
PAGE:0000000140400A60                 mov     rax, rsp
PAGE:0000000140400A63                 mov     [rax+8], rbx
PAGE:0000000140400A67                 mov     [rax+10h], rbp
PAGE:0000000140400A6B                 mov     [rax+18h], rsi
PAGE:0000000140400A6F                 mov     [rax+20h], rdi
PAGE:0000000140400A73                 push    r12
PAGE:0000000140400A75                 push    r13
PAGE:0000000140400A77                 push    r14
PAGE:0000000140400A79                 sub     rsp, 20h
PAGE:0000000140400A7D                 mov     rax, gs:188h    ; kThread
PAGE:0000000140400A86                 xor     ebx, ebx
PAGE:0000000140400A88                 mov     rbp, rdx
PAGE:0000000140400A8B                 dec     word ptr [rax+1C6h] ; kThread->SpecialApcDisable--
PAGE:0000000140400A92                 mov     r12, rcx
PAGE:0000000140400A95                 mov     r13d, ebx       ; 返回值初始化为: STATUS_SUCCESS
PAGE:0000000140400A98                 lea     rdi, [rcx+0B0h] ; ObjectType->TypeLock
PAGE:0000000140400A9F                 lock bts qword ptr [rdi], 0 ; 将ObjectType->TypeLock中的bit0送CF,然后该位置1
PAGE:0000000140400AA5                 jnb     short loc_140400AAF ; CF==0则跳
PAGE:0000000140400AA7                 mov     rcx, rdi
PAGE:0000000140400AAA                 call    ExfAcquirePushLockExclusive ; CF==1会调用
PAGE:0000000140400AAF
PAGE:0000000140400AAF loc_140400AAF:                          ; CODE XREF: sub_140400A60+45j
PAGE:0000000140400AAF                 add     r12, 0C0h       ; 保存: &ObjectType->CallbackList到r12
PAGE:0000000140400AB6                 mov     rsi, [r12]      ; pListEntry=ObjectType->CallbackList.Flink
PAGE:0000000140400ABA                 cmp     rsi, r12        ; if(pListEntry!=&ObjectType->CallbackList)
PAGE:0000000140400ABD                 jz      short loc_140400AEC ; pListEntry==&ObjectType->CallbackList则跳
PAGE:0000000140400ABF                 mov     r14, [rbp+18h]  ; ObpCallbackInfo=(POBP_CALLBACK_INFO)ObpCallbackEntry->pSelf
PAGE:0000000140400AC3
PAGE:0000000140400AC3 loc_140400AC3:                          ; CODE XREF: sub_140400A60+7Ej
PAGE:0000000140400AC3                 mov     rcx, [rsi+18h]
PAGE:0000000140400AC7                 lea     rdx, [r14+10h]  ; ObpCallbackInfo->Altitude(待插入项的Altitude)
PAGE:0000000140400ACB                 add     rcx, 10h        ; 已插入项的Altitude
PAGE:0000000140400ACF                 call    RtlCompareAltitudes
PAGE:0000000140400AD4                 cmp     eax, ebx
PAGE:0000000140400AD6                 jle     short loc_140400AE2 ; 已插入项的Altitude<=待插入项的Altitude就退出循环,说明ObjectType->CallbackList是按Altitude降序排列的有序回调链
PAGE:0000000140400AD8                 mov     rsi, [rsi]      ; pListEntry=pListEntry->Flink
PAGE:0000000140400ADB                 cmp     rsi, r12        ; while(pListEntry!=&ObjectType->CallbackList)
PAGE:0000000140400ADE                 jnz     short loc_140400AC3 ; pListEntry==&ObjectType->CallbackList则结束循环
PAGE:0000000140400AE0                 cmp     eax, ebx
PAGE:0000000140400AE2
PAGE:0000000140400AE2 loc_140400AE2:                          ; CODE XREF: sub_140400A60+76j
PAGE:0000000140400AE2                 jnz     short loc_140400AEC ; 如果Altitude没有重复,就实现插入
PAGE:0000000140400AE4                 mov     r13d, 0C01C0011h ; STATUS_FLT_INSTANCE_NAME_COLLISION
PAGE:0000000140400AEA                 jmp     short loc_140400B02 ; 发现了重复的Altitude
PAGE:0000000140400AEC ; ---------------------------------------------------------------------------
PAGE:0000000140400AEC
PAGE:0000000140400AEC loc_140400AEC:                          ; CODE XREF: sub_140400A60+5Dj
PAGE:0000000140400AEC                                         ; sub_140400A60:loc_140400AE2j
PAGE:0000000140400AEC                 mov     rcx, [rsi+8]    ; pListEntry->Blink到rcx
PAGE:0000000140400AF0                 mov     rax, [rcx]      ; pListEntry->Blink->Flink到rax <=> pListEntry到rax
PAGE:0000000140400AF3                 mov     [rbp+8], rcx    ; ObpCallbackEntry->CallbackLinks.Blink=pListEntry->Blink
PAGE:0000000140400AF7                 mov     [rbp+0], rax    ; ObpCallbackEntry->CallbackLinks.Flink=pListEntry
PAGE:0000000140400AFB                 mov     [rax+8], rbp    ; pListEntry->Blink->Flink->Blink=&ObpCallbackEntry->CallbackLinks
PAGE:0000000140400AFF                 mov     [rcx], rbp      ; pListEntry->Blink->Flink=&ObpCallbackInfo->ObpCallbackEntry->CallbackLinks
PAGE:0000000140400B02
PAGE:0000000140400B02 loc_140400B02:                          ; CODE XREF: sub_140400A60+8Aj
PAGE:0000000140400B02                 prefetchw byte ptr [rdi]
PAGE:0000000140400B05                 mov     rax, [rdi]      ; ObjectType->TypeLock.Ptr
PAGE:0000000140400B08                 mov     rcx, rax
PAGE:0000000140400B0B                 and     rcx, 0FFFFFFFFFFFFFFF0h ; ((ULONG_PTR)ObjectType->TypeLock.Ptr)&0FFFFFFFFFFFFFFF0h
PAGE:0000000140400B0F                 cmp     rcx, 10h
PAGE:0000000140400B13                 jbe     short loc_140400B19 ; ((ULONG_PTR)ObjectType->TypeLock.Ptr)&0FFFFFFFFFFFFFFF0h <= 0x10则跳
PAGE:0000000140400B15                 lea     rbx, [rax-10h]  ; (ULONG_PTR)ObjectType->TypeLock.Ptr-0x10
PAGE:0000000140400B19
PAGE:0000000140400B19 loc_140400B19:                          ; CODE XREF: sub_140400A60+B3j
PAGE:0000000140400B19                 test    al, 2           ; ((BYTE)ObjectType->TypeLock.Ptr) & 2
PAGE:0000000140400B1B                 jnz     short loc_140400B24 ; ((BYTE)ObjectType->TypeLock.Ptr) & 2不为0则跳
PAGE:0000000140400B1D                 lock cmpxchg [rdi], rbx ; 如果[rdi]==rax,则ZF置1,rbx送[rdi],否则: ZF置0,[rdi]送rax
PAGE:0000000140400B22                 jz      short loc_140400B2C ; ZF==1则跳
PAGE:0000000140400B24
PAGE:0000000140400B24 loc_140400B24:                          ; CODE XREF: sub_140400A60+BBj
PAGE:0000000140400B24                 mov     rcx, rdi
PAGE:0000000140400B27                 call    ExfReleasePushLock ; (((BYTE)ObjectType->TypeLock.Ptr) & 2)!=0或者ZF==0调用
PAGE:0000000140400B2C
PAGE:0000000140400B2C loc_140400B2C:                          ; CODE XREF: sub_140400A60+C2j
PAGE:0000000140400B2C                 mov     rcx, gs:188h    ; kThread
PAGE:0000000140400B35                 add     word ptr [rcx+1C6h], 1 ; kThread->SpecialApcDisable++
PAGE:0000000140400B3D                 jnz     short loc_140400B4D ; 检查: kThread->SpecialApcDisable是否开启
PAGE:0000000140400B3F                 add     rcx, 50h        ; kThread->ApcState
PAGE:0000000140400B43                 cmp     [rcx], rcx      ; 检查: kThread->ApcState.ApcListHead[0]是否为空
PAGE:0000000140400B46                 jz      short loc_140400B4D ; 不需要递送内核模式APC则跳
PAGE:0000000140400B48                 call    KiCheckForKernelApcDelivery ; 当kThread->SpecialApcDisable==0并且!IsListEmpty(&kThread->ApcState.ApcListHead[0])时,需要检查并递送内核模式APC
PAGE:0000000140400B4D
PAGE:0000000140400B4D loc_140400B4D:                          ; CODE XREF: sub_140400A60+DDj
PAGE:0000000140400B4D                                         ; sub_140400A60+E6j
PAGE:0000000140400B4D                 mov     rbx, [rsp+38h+arg_0]
PAGE:0000000140400B52                 mov     rbp, [rsp+38h+arg_8]
PAGE:0000000140400B57                 mov     rsi, [rsp+38h+arg_10]
PAGE:0000000140400B5C                 mov     rdi, [rsp+38h+arg_18]
PAGE:0000000140400B61                 mov     eax, r13d       ; NT_STATUS
PAGE:0000000140400B64                 add     rsp, 20h
PAGE:0000000140400B68                 pop     r14
PAGE:0000000140400B6A                 pop     r13
PAGE:0000000140400B6C                 pop     r12
PAGE:0000000140400B6E                 retn
PAGE:0000000140400B6E ; ---------------------------------------------------------------------------
PAGE:0000000140400B6F                 align 20h
PAGE:0000000140400B6F sub_140400A60   endp

可以看出: 内部会遍历ObjectType->CallbackList按Altitude降序排列的 链,比较Altitude,如果Altitude不重复:就把pObpCallbackEntry插入ObjectType->CallbackLis链,并且始终保持ObjectType->CallbackList链相关的回调的Altitude按降序排列,最终返回STATUS_SUCCESS,如果重复了,最终会返回: STATUS_FLT_INSTANCE_NAME_COLLISION. 整个原子操作过程是由:ObjectType->TypeLock锁来控制的,返回前会检查锁的状态,在必要时会释放锁,

然后,检查是否需要递送内核模式APC,在必要时会递送,最后返回。

(6)nt!ObpInsertCallbackByAltitude对应的C实现:

//ObpInsertCallbackByAltitude内部实现还原:
//功能: 搜索pObjectType->CallbackList回调链,如果Altitude不重复,则将pObpCallbackEntry->CallbackLinks插入pObjectType->CallbackList中
//pObjectType->CallbackList中相关的回调始终保持按Altitude降序
NTSTATUS ObpInsertCallbackByAltitude(
    IN POBJECT_TYPE pObjectType,
    IN POBP_CALLBACK_ENTRY pObpCallbackEntry)
{
    POBP_CALLBACK_ENTRY  pCurCallbackEntry;
    POBP_CALLBACK_INFO   pObpCallbackInfo,pObjCurCallbackInfo;
    PLIST_ENTRY pListEntry;
    PKTHREAD pkThread;
    ULONG_PTR RCX,RAX,RBX,RDX;
    NTSTATUS ntStatus=STATUS_SUCCESS;
    LONG CF,ZF;
    LONG r;

    pkThread=(PKTHREAD)PsGetCurrentThread;    
    kThread->SpecialApcDisable--;
    
    
    //模拟: lock bts qword ptr [rdi], 0 ; 将ObjectType->TypeLock中的bit0送CF,然后将ObjectType->TypeLock的bit0置1
    CF=1;
    pObjectType->TypeLock.Locked=InterlockedExchange(&CF,
        (LONG)(pObjectType->TypeLock.Locked&0x1)); 
    if(CF){
        ExfAcquirePushLockExclusive(&pObjectType->TypeLock);
    }
    
    //在按Altitude降序的回调链中,检查有无重复的Altitude
    pObpCallbackInfo=(POBP_CALLBACK_INFO)pObpCallbackEntry->pSelf;
    for(pListEntry=pObjectType->CallbackList.Flink; pListEntry!=&pObjectType->CallbackList;pListEntry=pListEntry->Flink){
         pCurCallbackEntry=(POBP_CALLBACK_ENTRY)CONTAINIG_RECORD(pListEntry,
             POBP_CALLBACK_ENTRY,
             CallbackLinks);
         pObjCurCallbackInfo=(POBP_CALLBACK_INFO)pCurCallbackEntry->pSelf;
         if((r=RtlCompareAltitudes(&pObjCurCallbackInfo->Altitude,
             &pObpCallbackInfo->Altitude))<=0){
             break;
         }
    }
    if(r==0){
        //Altitude重复了
        ntStatus=STATUS_FLT_INSTANCE_NAME_COLLISION;
    }else{
        //Altitude没有重复,在pListEntry之前插入
        pObpCallbackEntry->CallbackLinks.Blink=pListEntry->Blink;
        pObpCallbackEntry->CallbackLinks.Flink=pListEntry;
        pListEntry->Blink->Flink->Blink=&pObpCallbackEntry->CallbackLinks;
        pListEntry->Blink->Flink=&pObpCallbackInfo->ObpCallbackEntry->CallbackLinks;
    }
    RAX=(ULONG_PTR)ObjectType->TypeLock.Ptr;  //mov     rax, [rdi]
    RCX= RAX;
    RCX&=0xFFFFFFFFFFFFFFF0;
    RBX=RCX>0x10?RAX-0x10:0;
    if(!(((BYTE)RAX)&2)){
           //模拟: lock cmpxchg [rdi], rbx, 如果[rdi]==rax,则ZF置1,rbx送[rdi],否则: ZF置0,[rdi]送rax
           if(InterlockedCompareExchangePointer(&ObjectType->TypeLock.Ptr,
               (PVOID)RBX,
               (PVOID)RAX)==RAX){
               ZF=1;
           }else{
               ZF=0;
               RAX=ObjectType->TypeLock.Ptr;
           }
           if(!ZF){
               ExfReleasePushLock(&ObjectType->TypeLock);
           }
    }else{
        ExfReleasePushLock(&ObjectType->TypeLock);
    }
    pkThread=(PKTHREAD)PsGetCurrentThread();
    if(++pkThread->SpecialApcDisable==0&&!IsListEmpty(&kThread->ApcState.ApcListHead[0])){
        KiCheckForKernelApcDelivery(); //检查并递送内核模式Apc
    }
    
    return ntStatus;
}

三. ObRegisterCallbacks回调的检测及摘除:

通过前面逆向分析,已经弄清楚了WIN7 X64 7600上ObRegisterCallbacks的ObjectType->CallbackList回调项数据结构及插入过程,现在来实现两个功能:

通过遍历*PsProcessType,*PsThreadType对象类型的CallbackList链,检测系统中ObRegisterCallbacks已注册的回调

通过pObpCallbackEntry->pMySefl得到的RegistrationHandle,摘除指定的回调

1.这里先实现一个简单的ObRegisterCallbacks注册回调的驱动,InstallObjCallback.sys,便于后续的验证测试:

/*InstallObjCallback.c*/
#include <Ntifs.h>
#include <ntddk.h>
#include <Ntstrsafe.h>

#define DEBUG_LEVEL DPFLTR_ERROR_LEVEL

#ifndef PROCESS_TERMINATE
#define PROCESS_TERMINATE 0x0001
#endif

#ifndef THREAD_TERMINATE
#define THREAD_TERMINATE 0x0001
#endif

//未公开的内核API,直接声明下就可以用了
NTKERNELAPI
HANDLE  PsGetThreadId(
	_In_ PETHREAD Thread
);

//进程预处理回调用
OB_PREOP_CALLBACK_STATUS ObjectPsProcessPreCallback(
	_In_ PVOID                         RegistrationContext,
	_In_ POB_PRE_OPERATION_INFORMATION OperationInformation
);

//线程预处理回调
OB_PREOP_CALLBACK_STATUS ObjectPsThreadPreCallback(
	_In_ PVOID                         RegistrationContext,
	_In_ POB_PRE_OPERATION_INFORMATION OperationInformation
);

//进程后处理回调
VOID ObjectPsProcessPostCallback(
	_In_  PVOID RegistrationContext,
	_In_  POB_POST_OPERATION_INFORMATION OperationInformation
);

//线程后处理回调
VOID ObjectPsThreadPostCallback(
	_In_  PVOID RegistrationContext,
	_In_  POB_POST_OPERATION_INFORMATION OperationInformation
);

//内核模块卸载函数
VOID DriverUnload(
	IN PDRIVER_OBJECT pDriverObject
);

//回掉项数组
OB_OPERATION_REGISTRATION g_obOperationRegistrations[] = {
	{
		NULL,
		OB_OPERATION_HANDLE_CREATE| OB_OPERATION_HANDLE_DUPLICATE,
		ObjectPsProcessPreCallback,
		ObjectPsProcessPostCallback
	},
    {
		NULL,
		OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
		ObjectPsThreadPreCallback,
		ObjectPsThreadPostCallback
    }
};

//回调句柄
PVOID g_RegistrationHandle = NULL;

//驱动对象
PDRIVER_OBJECT g_pDriverObject = NULL;

//内核模块入口函数
NTSTATUS DriverEntry(
	IN PDRIVER_OBJECT pDriverObject,
	IN PUNICODE_STRING punsRegistryPath
)
{
	NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
	ULONG ulAltitude;
	LARGE_INTEGER liTime;
	static OB_CALLBACK_REGISTRATION obCallbackRegistration;
	static WCHAR wAltitude[10] = { L'\0' };

    g_pDriverObject = pDriverObject;  //驱动对象

	//填写注册信息
	RtlZeroMemory(&obCallbackRegistration,
		sizeof(OB_CALLBACK_REGISTRATION));
	obCallbackRegistration.Version = OB_FLT_REGISTRATION_VERSION;
	obCallbackRegistration.OperationRegistrationCount = sizeof(g_obOperationRegistrations) / sizeof(OB_OPERATION_REGISTRATION);
	KeQuerySystemTime(&liTime);
	//产生320000-329999之间的一个随机数
	ulAltitude = 320000 + RtlRandomEx(&liTime.LowPart) % 10000;
	RtlStringCbPrintfW(wAltitude,
		sizeof(wAltitude),
		L"%u",
		ulAltitude);
	RtlInitUnicodeString(
		&obCallbackRegistration.Altitude,
		wAltitude);
	obCallbackRegistration.RegistrationContext = (PVOID)pDriverObject;
	g_obOperationRegistrations[0].ObjectType = *PsProcessType;
	g_obOperationRegistrations[1].ObjectType = *PsThreadType;
	obCallbackRegistration.OperationRegistration = &g_obOperationRegistrations[0];

	//注册回调
	ntStatus = ObRegisterCallbacks(&obCallbackRegistration,
		&g_RegistrationHandle);

	if (NT_SUCCESS(ntStatus)) {
		KdPrintEx((
			DPFLTR_IHVDRIVER_ID,
			DEBUG_LEVEL,
			"Succeeded to ObRegisterCallbacks[DriverEntry]!\n"
			));
	}else {
		KdPrintEx((
			DPFLTR_IHVDRIVER_ID,
			DEBUG_LEVEL,
			"Failed to ObRegisterCallbacks[DriverEntry]!Status: 0x%08X\n",
			ntStatus
			));
	}

#if DBG
	pDriverObject->DriverUnload = DriverUnload;
#endif

	return ntStatus;
}

//内核模块卸载函数
VOID DriverUnload(
	IN PDRIVER_OBJECT pDriverObject
)
{
	LARGE_INTEGER  liDelay;
	ASSERT(g_pDriverObject == pDriverObject);

	if (g_RegistrationHandle != NULL) {
		ObUnRegisterCallbacks(g_RegistrationHandle);
		g_RegistrationHandle = NULL;

		liDelay.QuadPart = ((LONGLONG)(-10)) * 1000 * 1000 * 5;
		KeDelayExecutionThread(KernelMode,
			FALSE,
			&liDelay);
	}

	return;
}

//进程预处理回调用
OB_PREOP_CALLBACK_STATUS ObjectPsProcessPreCallback(
	_In_ PVOID                         RegistrationContext,
	_In_ POB_PRE_OPERATION_INFORMATION OperationInformation
)
{
	ULONG TargetProcessId = (ULONG)PsGetProcessId((PEPROCESS)OperationInformation->Object),CurrentProcessId = (ULONG)PsGetCurrentProcessId();
	ULONG ulDesiredAccess, ulOrgDesiredAccess;
	
	if (CurrentProcessId != TargetProcessId) {
		switch (OperationInformation->Operation) {
		case OB_OPERATION_HANDLE_CREATE:
			ulDesiredAccess = OperationInformation->Parameters->CreateHandleInformation.DesiredAccess;
			ulOrgDesiredAccess = OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess;
			break;
		case OB_OPERATION_HANDLE_DUPLICATE:
			ulDesiredAccess = OperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess;
			ulOrgDesiredAccess = OperationInformation->Parameters->DuplicateHandleInformation.OriginalDesiredAccess;
			break;
		}
		if (ulDesiredAccess&PROCESS_TERMINATE) {
			KdPrintEx((
				DPFLTR_IHVDRIVER_ID,
				DEBUG_LEVEL,
				"Process(pid: %u) will open the process(pid: %u) for terminate[ObjectPsProcessPreCallback]!\n",
				CurrentProcessId,TargetProcessId
				));
		}
	}
	return OB_PREOP_SUCCESS;
}

//线程预处理回调
OB_PREOP_CALLBACK_STATUS ObjectPsThreadPreCallback(
	_In_ PVOID                         RegistrationContext,
	_In_ POB_PRE_OPERATION_INFORMATION OperationInformation
)
{
	PEPROCESS peTargetProcess = IoThreadToProcess((PETHREAD)OperationInformation->Object);
	ULONG TargetThreadId = (ULONG)PsGetThreadId((PETHREAD)OperationInformation->Object),
		   TargetProcessId = (ULONG)PsGetProcessId(peTargetProcess),
		   CurrentProcessId = (ULONG)PsGetCurrentProcessId();
	ULONG ulDesiredAccess, ulOrgDesiredAccess;
	if (CurrentProcessId != TargetProcessId) {
		switch (OperationInformation->Operation) {
		case OB_OPERATION_HANDLE_CREATE:
			ulDesiredAccess = OperationInformation->Parameters->CreateHandleInformation.DesiredAccess;
			ulOrgDesiredAccess = OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess;
			break;
		case OB_OPERATION_HANDLE_DUPLICATE:
			ulDesiredAccess = OperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess;
			ulOrgDesiredAccess = OperationInformation->Parameters->DuplicateHandleInformation.OriginalDesiredAccess;
			break;
		}
		if (ulDesiredAccess&THREAD_TERMINATE) {
			KdPrintEx((
				DPFLTR_IHVDRIVER_ID,
				DEBUG_LEVEL,
				"Process(pid: %u) will open the thread(pid: %u, tid: %u) for terminate[ObjectPsThreadPreCallback]!\n",
				CurrentProcessId, TargetProcessId,TargetThreadId
				));
		}
	}
	
	return OB_PREOP_SUCCESS;
}

//进程后处理回调
VOID ObjectPsProcessPostCallback(
	_In_  PVOID RegistrationContext,
	_In_  POB_POST_OPERATION_INFORMATION OperationInformation
)
{
	ULONG TargetProcessId = (ULONG)PsGetProcessId((PEPROCESS)OperationInformation->Object), CurrentProcessId = (ULONG)PsGetCurrentProcessId();
	ULONG ulGranteddAccess;

	if (CurrentProcessId != TargetProcessId) {
		switch (OperationInformation->Operation) {
		case OB_OPERATION_HANDLE_CREATE:
			ulGranteddAccess = OperationInformation->Parameters->CreateHandleInformation.GrantedAccess;
		case OB_OPERATION_HANDLE_DUPLICATE:
			ulGranteddAccess = OperationInformation->Parameters->DuplicateHandleInformation.GrantedAccess;
			break;
		}
		if (ulGranteddAccess&PROCESS_TERMINATE) {
			KdPrintEx((
				DPFLTR_IHVDRIVER_ID,
				DEBUG_LEVEL,
				"Process(pid: %u) opened the process(pid: %u) for terminate[ObjectPsProcessPostCallback]!\n",
				CurrentProcessId, TargetProcessId
				));
		}
	}
	return;
}

//线程后处理回调
VOID ObjectPsThreadPostCallback(
	_In_  PVOID RegistrationContext,
	_In_  POB_POST_OPERATION_INFORMATION OperationInformation
)
{
	PEPROCESS peTargetProcess = IoThreadToProcess((PETHREAD)OperationInformation->Object);
	ULONG TargetThreadId = (ULONG)PsGetThreadId((PETHREAD)OperationInformation->Object),
		TargetProcessId = (ULONG)PsGetProcessId(peTargetProcess),
		CurrentProcessId = (ULONG)PsGetCurrentProcessId();
	ULONG ulGrantedAccess;

	if (CurrentProcessId != TargetProcessId) {
		switch (OperationInformation->Operation) {
		case OB_OPERATION_HANDLE_CREATE:
			ulGrantedAccess = OperationInformation->Parameters->CreateHandleInformation.GrantedAccess;
			
			break;
		case OB_OPERATION_HANDLE_DUPLICATE:
			ulGrantedAccess = OperationInformation->Parameters->DuplicateHandleInformation.GrantedAccess;
		    break;
		}
		if (ulGrantedAccess&THREAD_TERMINATE) {
			KdPrintEx((
				DPFLTR_IHVDRIVER_ID,
				DEBUG_LEVEL,
				"Process(pid: %u) opened the thread(pid: %u, tid: %u) for terminate[ObjectPsThreadPostCallback]!",
				CurrentProcessId, TargetProcessId, TargetThreadId
				));
		}
	}

	return;
}


2.再实现一个驱动CheckObjCallback.sys来实现ObRegisterCallbacks的检查及摘除:

/*CheckObjCallback.h*/
#pragma once

//宏定义
#define DEVICE_NAME L"\\Device\\CheckObjCallback"
#define SYMLNK_NAME L"\\DosDevices\\CheckObjCallback"

#define TAG 'COTG'

#define ANY_SIZE 1

#ifndef MAX_PATH
#define MAX_PATH 260
#endif

//
//设备控制请求
//
#define IOCTL_QUERY_OBJCALLBACKS CTL_CODE(FILE_DEVICE_UNKNOWN,0x101,METHOD_OUT_DIRECT,FILE_READ_DATA | FILE_WRITE_DATA)
#define IOCTL_REMOVE_OBJCALLBACK CTL_CODE(FILE_DEVICE_UNKNOWN,0x102,METHOD_BUFFERED,FILE_READ_DATA | FILE_WRITE_DATA)

//结构定义
//缓冲区总长度为: CallbackRegistration->OperationRegistrationCount*64+32+CallbackRegistration->Altitude->Length
//缓冲区指向: OBP_CALLBACK_INFO随CallbackRegistration->OperationRegistrationCount而不同的变长结构
//尾部的最后CallbackRegistration->Altitude->Length字节保存: Altitude->Buffer所指向的UNICODE串
//Obp回调项(0x40==64字节),index表示在OBP_CALLBACK_INFO的ObpCallbackEntries数组元素索引号
typedef struct _OBP_CALLBACK_ENTRY {
	LIST_ENTRY CallbackLinks;     //offset from OBP_CALLBACK_INFO: 0x20+index*64
	OB_OPERATION  Operations; //offset from OBP_CALLBACK_INFO: 0x30+index*64
	ULONG InsertFlag;    //offset from OBP_CALLBACK_INFO: 0x34+index*64
	PVOID pSelf;     //offset from OBP_CALLBACK_INFO: 0x38+index*64 
	PLIST_ENTRY pListObjectTypeEntry; //offset from OBP_CALLBACK_INFO: 0x40+index*64
	POB_PRE_OPERATION_CALLBACK  PreOperation; //offset from OBP_CALLBACK_INFO: 0x48+index*64
	POB_POST_OPERATION_CALLBACK  PostOperation; //offset from OBP_CALLBACK_INFO: 0x50+index*64
	UCHAR Fill[8];  //offset from OBP_CALLBACK_INFOt: 0x58+index*64, 填满64字节
}OBP_CALLBACK_ENTRY, *POBP_CALLBACK_ENTRY, *LPOBP_CALLBACK_ENTRY;

//Obp回调信息
typedef struct _OBP_CALLBACK_INFO {
	USHORT Version;                   //offset: 0x0
	USHORT Inserted;                  //offset: 0x2
	PVOID RegistrationContext;  //offset: 0x8
	UNICODE_STRING Altitude;   //offset: 0x10
	OBP_CALLBACK_ENTRY  ObpCallbackEntries[ANY_SIZE];  //offset: 0x20, OBP_CALLBACK_ENTRY数组,元素个数为:  CallbackRegistration->OperationRegistrationCount
}OBP_CALLBACK_INFO, *POBP_CALLBACK_INFO, *LPOBP_CALLBACK_INFO;

//LDR_DATATABLE_ENTRY最小数据结构定义
typedef struct _LDR_DATA_TABLE_ENTRY {
	LIST_ENTRY InLoadOrderLinks;
	LIST_ENTRY InMemoryOrderLinks;
	LIST_ENTRY InInitializationOrderLinks;
	PVOID DllBase;
	PVOID EntryPoint;
	ULONG SizeOfImage;
	UNICODE_STRING FullDllName;
	UNICODE_STRING BaseDllName;
	ULONG Flags;
	USHORT LoadCount;
	USHORT TlsIndex;
	union {
		LIST_ENTRY HashLinks;
		struct {
			PVOID SectionPointer;
			ULONG CheckSum;
		};
	};
	union {
		ULONG TimeDateStamp;
		PVOID LoadedImports;
	};
	PVOID EntryPointActivationContext;
	PVOID PatchInformation;
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

//对象回调用信息
//回调项信息(与应用层交互)
typedef struct _OBJ_CALLBACK_ENTRY {
	PVOID pOperation;  //操作回调
	ULONG ulOperationType; //操作回调类型: 0: 表示预操作回调, 1: 表示后操作回调用
	ULONG ulObjectType;   //对象类型: 0: 进程, 1: 表示线程
	WCHAR wKernelModulePath[MAX_PATH]; //操作回调所在的内核模块
}OBJ_CALLBACK_ENTRY,*POBJ_CALLBACK_ENTRY,*LPOBJ_CALLBACK_ENTRY;

//回调信息(与应用层交互)
#define MAX_OBJ_CALLBACK_ENTRY 32
typedef struct _OBJ_CALLBACK_INFO {
	WCHAR wAltitude[MAX_PATH]; //Altitude
	PVOID RegistrationHandle; //回掉句柄
	ULONG ulCount; //不超过MAX_OBJ_CALLBACK_ENTRY
	OBJ_CALLBACK_ENTRY objCallbackEntries[MAX_OBJ_CALLBACK_ENTRY];
}OBJ_CALLBACK_INFO,*POBJ_CALLBACK_INFO,*LPOBJ_CALLBACK_INFO;


//全局变量结构体
typedef struct _USER_GLOBAL_INFO {
	PDRIVER_OBJECT g_pDriverObject;
	PDEVICE_OBJECT g_pCDO;
	LONG g_lUsers;
	LONG g_lCallbackListOffsetInObj;  //CallbackList在OBJECT_TYPE中的偏移量
	RTL_OSVERSIONINFOEXW oviEx; //系统版本信息
}USER_GLOBAL_INFO, *PUSER_GLOBAL_INFO, *LPUSER_GLOBAL_INFO;

//
//框架函数
//
//内核模块入口函数
NTSTATUS DriverEntry(
	IN PDRIVER_OBJECT pDriverObject,
	IN PUNICODE_STRING pUnsRegPath
);

//内核模块卸载函数
VOID DriverUnload(
	IN PDRIVER_OBJECT pDriverObject
);

//分发函数(IRP_MJ_CREATE,IRP_MJ_CLEANUP,IRP_MJ_CLOSE)
NTSTATUS DispatchGeneral(
	IN PDEVICE_OBJECT pDeviceObject,
	IN PIRP pIrp
);

//分发函数(IRP_MJ_DEVICE_CONTROL)
NTSTATUS DispatchDeviceControl(
	IN PDEVICE_OBJECT pDeviceObject,
	IN PIRP pIrp
);

//
//功能函数
//
//
//搜索指定地址所在的内核模块
NTSTATUS GetKernelModuleFullNameByAddr(
	IN PDRIVER_OBJECT pMyDriverObject,
	IN PVOID pAddr,
	IN OUT PUNICODE_STRING punsKernelModuleFullName
);

//获取系统中的ObRegisterCallbacks注册的对象回调函数信息
NTSTATUS QueryCallbackInfosForObRegisterCallbacks(
	OUT POBJ_CALLBACK_INFO pObjCallbackInfos,
	IN ULONG ulMaxAltitudeCount,
	OUT PULONG pulRetAltitudeCount
);
/*CheckObjCallback.c*/
#include <ntddk.h>
#include "CheckObjCallback.h"

#define DEBUG_LEVEL DPFLTR_ERROR_LEVEL

//指定函数所在的节
#pragma alloc_text(INIT,DriverEntry)
#pragma alloc_text(PAGE,DriverUnload)
#pragma alloc_text(PAGE,DispatchGeneral)
#pragma alloc_text(PAGE,DispatchDeviceControl)
#pragma alloc_text(PAGE,GetKernelModuleFullNameByAddr)

//
// 全局变量
//
USER_GLOBAL_INFO g_userGlobalInfo;

//
//框架函数
//
//内核模块入口函数
NTSTATUS DriverEntry(
	IN PDRIVER_OBJECT pDriverObject,
	IN PUNICODE_STRING pUnsRegPath
)
{
	NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
	UNICODE_STRING unsDeviceName, unsSymLnkName;

	do {
		RtlZeroMemory(&g_userGlobalInfo,
			sizeof(USER_GLOBAL_INFO));
		g_userGlobalInfo.g_pDriverObject = pDriverObject; //保存驱动对象指针

		//获取系统版本信息
		g_userGlobalInfo.oviEx.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
		ntStatus = RtlGetVersion((PRTL_OSVERSIONINFOW)&g_userGlobalInfo.oviEx);
		ASSERT(NT_SUCCESS(ntStatus));

		g_userGlobalInfo.g_lCallbackListOffsetInObj = -1; //初始化CallbackList偏移量为一个无效值
#ifdef _WIN64		
		switch (g_userGlobalInfo.oviEx.dwMajorVersion) {
		case 6:
			switch (g_userGlobalInfo.oviEx.dwMinorVersion) {
			case 1:
				if (g_userGlobalInfo.oviEx.wServicePackMajor == 0) {
					//WIN7 x64 7600
					g_userGlobalInfo.g_lCallbackListOffsetInObj = 0xC0; //CallbackList偏移量
				}
				break;
			}
			break;
		}
#endif

		//创建控制设备
		RtlInitUnicodeString(&unsDeviceName,
			DEVICE_NAME);
		ntStatus = IoCreateDevice(pDriverObject,
			0,
			&unsDeviceName,
			FILE_DEVICE_UNKNOWN,
			FILE_DEVICE_SECURE_OPEN,
			FALSE,
			&g_userGlobalInfo.g_pCDO);
		if (!NT_SUCCESS(ntStatus)) {
			KdPrintEx((
				DPFLTR_IHVDRIVER_ID,
				DEBUG_LEVEL,
				"Failed to IoCreateDevice[DriverEntry]!Status: 0x%08X\n",
				ntStatus
				));
			break;
		}

		//创建控制设备符号链接
		RtlInitUnicodeString(&unsSymLnkName, 
			SYMLNK_NAME);
		IoDeleteSymbolicLink(&unsSymLnkName);
		ntStatus = IoCreateSymbolicLink(&unsSymLnkName,
			&unsDeviceName);
		if (!NT_SUCCESS(ntStatus)) {
			KdPrintEx((
				DPFLTR_IHVDRIVER_ID,
				DEBUG_LEVEL,
				"Failed to IoCreateSymbolicLink[DriverEntry]!Status: 0x%08X\n",
				ntStatus
				));
			break;
		}

		//指定分发函数
		pDriverObject->MajorFunction[IRP_MJ_CREATE] = \
		pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = \
		pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchGeneral;
		pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControl;

#if DBG
		pDriverObject->DriverUnload = DriverUnload;
#endif

	} while (FALSE);

	if (!NT_SUCCESS(ntStatus)) {
		//失败时的处理
		DriverUnload(pDriverObject);
	}

	return ntStatus;
}

//内核模块卸载函数
VOID DriverUnload(
	IN PDRIVER_OBJECT pDriverObject
)
{
	UNICODE_STRING unsSymLnkName;

	PAGED_CODE();
	ASSERT(g_userGlobalInfo.g_pDriverObject == pDriverObject);

	//检查并删除控制设备
	if (g_userGlobalInfo.g_pCDO != NULL) {
		RtlInitUnicodeString(&unsSymLnkName, SYMLNK_NAME);
		IoDeleteSymbolicLink(&unsSymLnkName);
		IoDeleteDevice(g_userGlobalInfo.g_pCDO);
		g_userGlobalInfo.g_pCDO = NULL;
	}

	return;
}

//分发函数(IRP_MJ_CREATE,IRP_MJ_CLEANUP,IRP_MJ_CLOSE)
NTSTATUS DispatchGeneral(
	IN PDEVICE_OBJECT pDeviceObject,
	IN PIRP pIrp
)
{
	PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
	ULONG_PTR ulptrInformation = 0;
	NTSTATUS ntStatus = STATUS_NOT_IMPLEMENTED;

	PAGED_CODE();

	switch (pIrpSp->MajorFunction) {
	case IRP_MJ_CREATE:
		ntStatus = STATUS_SUCCESS;
		InterlockedIncrement(&g_userGlobalInfo.g_lUsers);
		break;
	case IRP_MJ_CLEANUP:
		ntStatus = STATUS_SUCCESS;
		break;
	case IRP_MJ_CLOSE:
		ntStatus = STATUS_SUCCESS;
		InterlockedDecrement(&g_userGlobalInfo.g_lUsers);
		break;
	}

	pIrp->IoStatus.Status = ntStatus;
	pIrp->IoStatus.Information = ulptrInformation;
	IoCompleteRequest(pIrp,
		IO_NO_INCREMENT);

	return ntStatus;
}

//分发函数(IRP_MJ_DEVICE_CONTROL)
NTSTATUS DispatchDeviceControl(
	IN PDEVICE_OBJECT pDeviceObject,
	IN PIRP pIrp
)
{
	PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
	PVOID pInputBuffer, pOutputBuffer;
	ULONG_PTR ulptrInformation = 0;
	ULONG ulInputBufLen, ulOutputBufLen, ulCount;
	NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
	
    PAGED_CODE();
	ASSERT(pIrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);

	switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode) {
	case IOCTL_QUERY_OBJCALLBACKS:  //查询系统中通过ObRegisterCallbacks注册的回调
	{
		ASSERT((pIrpSp->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_OUT_DIRECT);
		do {
			//检查输出缓冲区合法性
			if (pIrp->MdlAddress == NULL) {
				ntStatus = STATUS_INVALID_PARAMETER;
				break;
			}
			pOutputBuffer = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,
				NormalPagePriority);
			if (pOutputBuffer == NULL) {
				ntStatus = STATUS_INSUFFICIENT_RESOURCES;
				break;
			}
			ulOutputBufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
			if (ulOutputBufLen < sizeof(OBJ_CALLBACK_INFO)) {
				ntStatus = STATUS_BUFFER_TOO_SMALL;
				break;
			}
			if (MmGetMdlByteCount(pIrp->MdlAddress) < ulOutputBufLen) {
				ntStatus = STATUS_BUFFER_OVERFLOW;
				break;
			}

			//获取通过ObRegisterCallbacks注册的回调
			ntStatus = QueryCallbackInfosForObRegisterCallbacks(
				(POBJ_CALLBACK_INFO)pOutputBuffer,
				ulOutputBufLen / sizeof(OBJ_CALLBACK_INFO),
				&ulCount);
			if (!NT_SUCCESS(ntStatus)) {
				break;
			}

			//成功了,保存实际输出的字节数
			ulptrInformation = ulCount * sizeof(OBJ_CALLBACK_INFO);
		} while (FALSE);
	}
		break;
	case IOCTL_REMOVE_OBJCALLBACK: //摘除ObRegisterCallbacks注册的回调
	{
		ASSERT((pIrpSp->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED);
		do {
			//检查输入缓冲区合法性
			pInputBuffer = pIrp->AssociatedIrp.SystemBuffer;
			if (pInputBuffer == NULL) {
				ntStatus = STATUS_INVALID_PARAMETER;
				break;
			}
			ulInputBufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
			if (ulInputBufLen < sizeof(PVOID)) {
				ntStatus = STATUS_BUFFER_TOO_SMALL;
				break;
			}

			//摘除回调
			ObUnRegisterCallbacks(*(PVOID*)pInputBuffer);
			ntStatus = STATUS_SUCCESS;
		} while (FALSE);
	}
		break;
	}

	pIrp->IoStatus.Status = ntStatus;
	pIrp->IoStatus.Information = ulptrInformation;
	IoCompleteRequest(pIrp,
		IO_NO_INCREMENT);

	return ntStatus;
}

//
//功能函数
//
//
//搜索指定地址所在的内核模块
NTSTATUS GetKernelModuleFullNameByAddr(
	IN PDRIVER_OBJECT pMyDriverObject,
	IN PVOID pAddr,
	IN OUT PUNICODE_STRING punsKernelModuleFullName
)
{
	PLDR_DATA_TABLE_ENTRY pMyLDRDTEntry, pLDRDTEntry;
	PLIST_ENTRY pListHead = NULL, pListEntry;
	NTSTATUS ntStatus = STATUS_PROCEDURE_NOT_FOUND;
	UNICODE_STRING unsNtModuleName1 = RTL_CONSTANT_STRING(L"ntoskrnl.exe"), unsNtModuleName2 = RTL_CONSTANT_STRING(L"ntkrnlpa.exe");
	KIRQL kSavedIrql;
	
	PAGED_CODE();
	ASSERT(pMyDriverObject == g_userGlobalInfo.g_pDriverObject);

	pMyLDRDTEntry = (PLDR_DATA_TABLE_ENTRY)pMyDriverObject->DriverSection;
	if (pMyLDRDTEntry != NULL) {
		KeRaiseIrql(APC_LEVEL, &kSavedIrql);
		
		//找内核模块加载顺序链表头(ntoskrnl.exe/ntkrnlpa.exe模块的前面1个)
		for (pListEntry = pMyLDRDTEntry->InLoadOrderLinks.Blink; pListEntry != &pMyLDRDTEntry->InLoadOrderLinks; pListEntry = pListEntry->Blink) {
			pLDRDTEntry = (PLDR_DATA_TABLE_ENTRY)CONTAINING_RECORD(pListEntry,
				LDR_DATA_TABLE_ENTRY,
				InLoadOrderLinks);
			if (pLDRDTEntry->BaseDllName.Buffer != NULL && pLDRDTEntry->FullDllName.Buffer != NULL) {
				if (RtlCompareUnicodeString(&pLDRDTEntry->BaseDllName, &unsNtModuleName1, TRUE) == 0
					|| RtlCompareUnicodeString(&pLDRDTEntry->BaseDllName, &unsNtModuleName2, TRUE) == 0) {
					pListHead = pListEntry->Blink;
					break;
				}
			}
		}

		if (pListHead != NULL) {
			//根据地址从内核模块加载顺序链中搜索内核模块
			for (pListEntry = pListHead->Flink; pListEntry != pListHead; pListEntry = pListEntry->Flink) {
				pLDRDTEntry = (PLDR_DATA_TABLE_ENTRY)CONTAINING_RECORD(pListEntry,
					LDR_DATA_TABLE_ENTRY,
					InLoadOrderLinks);
				if (pLDRDTEntry->FullDllName.Buffer != NULL) {
					if ((ULONG_PTR)pAddr >= (ULONG_PTR)pLDRDTEntry->DllBase && (ULONG_PTR)pAddr < (ULONG_PTR)pLDRDTEntry->DllBase + pLDRDTEntry->SizeOfImage) {
						//找到内核模块
						if (punsKernelModuleFullName->Length > 0) punsKernelModuleFullName->Length = 0;
						ntStatus = RtlAppendUnicodeStringToString(punsKernelModuleFullName,
							&pLDRDTEntry->FullDllName);
						break;
					}
				}
			}
		}
		
		KeLowerIrql(kSavedIrql);
	}


	return ntStatus;
}

//获取系统中的ObRegisterCallbacks注册的对象回调函数信息
NTSTATUS QueryCallbackInfosForObRegisterCallbacks(
	OUT POBJ_CALLBACK_INFO pObjCallbackInfos,
	IN ULONG ulMaxAltitudeCount,
	OUT PULONG pulRetAltitudeCount
)
{
	POBP_CALLBACK_ENTRY pObpCallbackEntry;
	POBP_CALLBACK_INFO pObpCallbackInfo;
	POBJECT_TYPE pObjType;
	PLIST_ENTRY pCallbackListHead,pCallbackListEntry;
	ULONG i,j,ulAltitudeCount = 0;
	NTSTATUS ntStatus = STATUS_NOT_SUPPORTED;
	UNICODE_STRING unsAltitude, unsKernelModulePath;
	KIRQL kSavedIrql;
	
	if (g_userGlobalInfo.g_lCallbackListOffsetInObj > -1) {
		ntStatus = STATUS_PROCEDURE_NOT_FOUND;

		//遍历*PsProcessType的CallbackList链
		pObjType = *PsProcessType;
		pCallbackListHead = (PLIST_ENTRY)((PUCHAR)pObjType + g_userGlobalInfo.g_lCallbackListOffsetInObj); //比如: WIN7 X64 7600 CallbackList在OBJECT_TYPE中的偏移量为: 0x0c0 
		KeRaiseIrql(APC_LEVEL, &kSavedIrql);
		for (pCallbackListEntry = pCallbackListHead->Flink; pCallbackListEntry != pCallbackListHead; pCallbackListEntry = pCallbackListEntry->Flink) {
			if (ulAltitudeCount >= ulMaxAltitudeCount) {
				break;
			}
			pObpCallbackEntry = (POBP_CALLBACK_ENTRY)CONTAINING_RECORD(pCallbackListEntry,
				OBP_CALLBACK_ENTRY,
				CallbackLinks); //得到ObpCallback项

			//检查插入标志
			if (pObpCallbackEntry->InsertFlag & 0x1) {
				//得到ObpCallbackInfo
				//注意:pObpCallbackInfo->objCallbackEntries中的各回调项包括了进程,线程对象类型,回调项个数为: pObpCallbackInfo->Inserted
				pObpCallbackInfo = (POBP_CALLBACK_INFO)pObpCallbackEntry->pSelf; 
				ASSERT(pObpCallbackInfo != NULL);

				//根据Altitude检查是否已保存过了
				for (i = 0; i < ulAltitudeCount; i++) {
					RtlInitUnicodeString(&unsAltitude,
						pObjCallbackInfos[i].wAltitude);
					if (RtlCompareUnicodeString(
					   &unsAltitude,
						&pObpCallbackInfo->Altitude,
						FALSE) == 0) {
						//已保存过了
						break;
					}
				}

				if (i == ulAltitudeCount) {
					//需要保存
					RtlZeroMemory(&pObjCallbackInfos[i], sizeof(OBJ_CALLBACK_INFO));
					
					//保存Altitude
					RtlInitEmptyUnicodeString(&unsAltitude,
						pObjCallbackInfos[i].wAltitude,
						sizeof(pObjCallbackInfos[i].wAltitude));
					RtlCopyUnicodeString(&unsAltitude,
						&pObpCallbackInfo->Altitude);
					pObjCallbackInfos[i].wAltitude[sizeof(pObjCallbackInfos[i].wAltitude) / sizeof(WCHAR) - 1] = L'\0';
				
					pObjCallbackInfos[i].RegistrationHandle = (PVOID)pObpCallbackInfo; //回调句柄
					pObjCallbackInfos[i].ulCount = 0; //回调个数初始化

					//保存各回调项(注意:这里的回调项包括了:进程和线程对象类型)
					for (j = 0; j < (ULONG)pObpCallbackInfo->Inserted; j++) {
						//检查插入标志
						if (pObpCallbackInfo->ObpCallbackEntries[j].InsertFlag & 0x1) {
							pObjType = (POBJECT_TYPE)pObpCallbackInfo->ObpCallbackEntries[j].pListObjectTypeEntry; //对象类型

							//保存预操作回调
							pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].pOperation = pObpCallbackInfo->ObpCallbackEntries[j].PreOperation; //预操作回调
							pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].ulOperationType = 0; //操作回调类型: 0: 表示预操作回调, 1: 表示后操作回调用
							//对象类型: 0: 进程, 1: 表示线程
							if (pObjType == *PsProcessType) {
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].ulObjectType = 0;
							}
							else {
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].ulObjectType = 1;
							}
							//预操作回调所在内核模块
							RtlInitEmptyUnicodeString(&unsKernelModulePath,
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath,
								sizeof(pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath));
							GetKernelModuleFullNameByAddr(g_userGlobalInfo.g_pDriverObject,
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].pOperation,
								&unsKernelModulePath);
							pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath[sizeof(pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath) / sizeof(WCHAR) - 1] = L'\0';
							if (++pObjCallbackInfos[i].ulCount >= MAX_OBJ_CALLBACK_ENTRY) {
								break;
							}

							//保存后操作回调
							pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].pOperation = pObpCallbackInfo->ObpCallbackEntries[j].PostOperation; //后操作回调
							pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].ulOperationType = 1; //操作回调类型: 0: 表示预操作回调, 1: 表示后操作回调
							//对象类型: 0: 进程, 1: 表示线程
							if (pObjType == *PsProcessType) {
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].ulObjectType = 0;
							}
							else {
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].ulObjectType = 1;
							}
							//后操作回调所在内核模块
							RtlInitEmptyUnicodeString(&unsKernelModulePath,
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath,
								sizeof(pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath));
							GetKernelModuleFullNameByAddr(g_userGlobalInfo.g_pDriverObject,
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].pOperation,
								&unsKernelModulePath);
							pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath[sizeof(pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath) / sizeof(WCHAR) - 1] = L'\0';
							if (++pObjCallbackInfos[i].ulCount >= MAX_OBJ_CALLBACK_ENTRY) {
								break;
							}
						}
					}//end for

					//Altitude数递增
					ulAltitudeCount++;
				}
			}
		}//end for
		KeLowerIrql(kSavedIrql);

		//遍历*PsThreadType的CallbackList链
		pObjType = *PsThreadType;
		pCallbackListHead = (PLIST_ENTRY)((PUCHAR)pObjType + g_userGlobalInfo.g_lCallbackListOffsetInObj); //比如: WIN7 X64 7600 CallbackList在OBJECT_TYPE中的偏移量为: 0x0c0 
		KeRaiseIrql(APC_LEVEL, &kSavedIrql);
		for (pCallbackListEntry = pCallbackListHead->Flink; pCallbackListEntry != pCallbackListHead; pCallbackListEntry = pCallbackListEntry->Flink) {
			if (ulAltitudeCount >= ulMaxAltitudeCount) {
				break;
			}
			pObpCallbackEntry = (POBP_CALLBACK_ENTRY)CONTAINING_RECORD(pCallbackListEntry,
				OBP_CALLBACK_ENTRY,
				CallbackLinks); //得到ObpCallback项

			//检查插入标志
			if (pObpCallbackEntry->InsertFlag & 0x1) {
				//得到ObpCallbackInfo
				//注意:pObpCallbackInfo->objCallbackEntries中的各回调项包括了进程,线程对象类型,回调项个数为: pObpCallbackInfo->Inserted
				pObpCallbackInfo = (POBP_CALLBACK_INFO)pObpCallbackEntry->pSelf;
				ASSERT(pObpCallbackInfo != NULL);

				//根据Altitude检查是否已保存过了
				for (i = 0; i < ulAltitudeCount; i++) {
					RtlInitUnicodeString(&unsAltitude,
						pObjCallbackInfos[i].wAltitude);
					if (RtlCompareUnicodeString(
						&unsAltitude,
						&pObpCallbackInfo->Altitude,
						FALSE) == 0) {
						//已保存过了
						break;
					}
				}

				if (i == ulAltitudeCount) {
					//需要保存
					RtlZeroMemory(&pObjCallbackInfos[i], sizeof(OBJ_CALLBACK_INFO));

					//保存Altitude
					RtlInitEmptyUnicodeString(&unsAltitude,
						pObjCallbackInfos[i].wAltitude,
						sizeof(pObjCallbackInfos[i].wAltitude));
					RtlCopyUnicodeString(&unsAltitude,
						&pObpCallbackInfo->Altitude);
					pObjCallbackInfos[i].wAltitude[sizeof(pObjCallbackInfos[i].wAltitude) / sizeof(WCHAR) - 1] = L'\0';

					pObjCallbackInfos[i].RegistrationHandle = (PVOID)pObpCallbackInfo; //回调句柄
					pObjCallbackInfos[i].ulCount = 0; //回调个数初始化

					//保存各回调项(注意:这里的回调项包括了:进程和线程对象类型)
					for (j = 0; j < (ULONG)pObpCallbackInfo->Inserted; j++) {
						//检查插入标志
						if (pObpCallbackInfo->ObpCallbackEntries[j].InsertFlag & 0x1) {
							pObjType = (POBJECT_TYPE)pObpCallbackInfo->ObpCallbackEntries[j].pListObjectTypeEntry; //对象类型

							//保存预操作回调
							pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].pOperation = pObpCallbackInfo->ObpCallbackEntries[j].PreOperation; //预操作回调
							pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].ulOperationType = 0; //操作回调类型: 0: 表示预操作回调, 1: 表示后操作回调用
							//对象类型: 0: 进程, 1: 表示线程
							if (pObjType == *PsProcessType) {
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].ulObjectType = 0;
							}
							else {
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].ulObjectType = 1;
							}
							//预操作回调所在内核模块
							RtlInitEmptyUnicodeString(&unsKernelModulePath,
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath,
								sizeof(pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath));
							GetKernelModuleFullNameByAddr(g_userGlobalInfo.g_pDriverObject,
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].pOperation,
								&unsKernelModulePath);
							pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath[sizeof(pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath) / sizeof(WCHAR) - 1] = L'\0';
							if (++pObjCallbackInfos[i].ulCount >= MAX_OBJ_CALLBACK_ENTRY) {
								break;
							}

							//保存后操作回调
							pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].pOperation = pObpCallbackInfo->ObpCallbackEntries[j].PostOperation; //后操作回调
							pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].ulOperationType = 1; //操作回调类型: 0: 表示预操作回调, 1: 表示后操作回调
							//对象类型: 0: 进程, 1: 表示线程
							if (pObjType == *PsProcessType) {
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].ulObjectType = 0;
							}
							else {
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].ulObjectType = 1;
							}
							//后操作回调所在内核模块
							RtlInitEmptyUnicodeString(&unsKernelModulePath,
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath,
								sizeof(pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath));
							GetKernelModuleFullNameByAddr(g_userGlobalInfo.g_pDriverObject,
								pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].pOperation,
								&unsKernelModulePath);
							pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath[sizeof(pObjCallbackInfos[i].objCallbackEntries[pObjCallbackInfos[i].ulCount].wKernelModulePath) / sizeof(WCHAR) - 1] = L'\0';
							if (++pObjCallbackInfos[i].ulCount >= MAX_OBJ_CALLBACK_ENTRY) {
								break;
							}
						}
					}//end for

					//Altitude数递增
					ulAltitudeCount++;
				}
			}
		}//end for
		KeLowerIrql(kSavedIrql);
		
        if (ulAltitudeCount > 0) {
			//成功
			*pulRetAltitudeCount = ulAltitudeCount;
			ntStatus = STATUS_SUCCESS;
		}
	}
	
	return ntStatus;
}


 3.用户层Deamon:

// Deamon.cpp
//
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#pragma warning(disable : 4996)

#include <iostream>
using namespace std;

//控制设备符号链接
#define DEVICE_NAME TEXT("\\\\.\\CheckObjCallback")

//
//设备控制请求
//
#define IOCTL_QUERY_OBJCALLBACKS CTL_CODE(FILE_DEVICE_UNKNOWN,0x101,METHOD_OUT_DIRECT,FILE_READ_DATA | FILE_WRITE_DATA)
#define IOCTL_REMOVE_OBJCALLBACK CTL_CODE(FILE_DEVICE_UNKNOWN,0x102,METHOD_BUFFERED,FILE_READ_DATA | FILE_WRITE_DATA)

//对象回调用信息
//回调项信息
typedef struct _OBJ_CALLBACK_ENTRY {
	PVOID pOperation;  //操作回调
	ULONG ulOperationType; //操作回调类型: 0: 表示预操作回调, 1: 表示后操作回调用
	ULONG ulObjectType;   //对象类型: 0: 进程, 1: 表示线程
	WCHAR wKernelModulePath[MAX_PATH]; //操作回调所在的内核模块
}OBJ_CALLBACK_ENTRY, *POBJ_CALLBACK_ENTRY, *LPOBJ_CALLBACK_ENTRY;

//回调信息
#define MAX_OBJ_CALLBACK_ENTRY 32
typedef struct _OBJ_CALLBACK_INFO {
	WCHAR wAltitude[MAX_PATH]; //Altitude
	PVOID RegistrationHandle; //回掉句柄
	ULONG ulCount; //不超过MAX_OBJ_CALLBACK_ENTRY
	OBJ_CALLBACK_ENTRY objCallbackEntries[MAX_OBJ_CALLBACK_ENTRY];
}OBJ_CALLBACK_INFO, *POBJ_CALLBACK_INFO, *LPOBJ_CALLBACK_INFO;


//显示命令行
VOID ShowUsage(LPCSTR argv0);

//检查参数
INT CheckArgv(INT argc, CHAR *argv[]);

//命令开关
CONST CHAR* g_switches[] = {
	"queryobcallbacks","removeobcallback",NULL
};

//查询ObRegisterCallbacks注册的回调
ULONG QueryObCallbacks(IN HANDLE hDevice,OUT LPOBJ_CALLBACK_INFO lpObjCallbackInfos,IN ULONG ulMaxAltitudeCount);

//摘除ObRegisterCallbacks注册的回调
BOOL RemoveObCallback(IN HANDLE hDevice, IN PVOID RegistrationHandle);

int main(int argc, char *argv[])
{
	HANDLE hDevice;
	INT n = CheckArgv(argc, argv);
	ULONG i,j,ulCount;
	CHAR szName[MAX_PATH];

	if (n < 0) {
		ShowUsage((LPCSTR)argv[0]);
		::exit(1);
	}

	//打开控制设备
	hDevice = ::CreateFile(DEVICE_NAME,
		GENERIC_READ|GENERIC_WRITE,
		FILE_SHARE_READ|FILE_SHARE_WRITE,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL);

	if (hDevice != INVALID_HANDLE_VALUE) {
		switch (n) {
		case 0: //queryobcallbacks
		{
			LPOBJ_CALLBACK_INFO lpObjCallbackInfos;
			lpObjCallbackInfos = new OBJ_CALLBACK_INFO[1024];
			if (lpObjCallbackInfos != NULL) {
				if ((ulCount = QueryObCallbacks(hDevice, lpObjCallbackInfos, 1024)) > 0) {
					for (i = 0; i < ulCount; i++) {
						::ZeroMemory(szName, MAX_PATH);
						::WideCharToMultiByte(CP_ACP,
							0,
							lpObjCallbackInfos[i].wAltitude,
							-1,
							szName,
							sizeof(szName),
							NULL,
							NULL);
						cout << "Altitude: " << szName << endl;
						printf("回调句柄: 0x%p\n", lpObjCallbackInfos[i].RegistrationHandle);
						for (j = 0; j < lpObjCallbackInfos[i].ulCount;j++){
							::ZeroMemory(szName, MAX_PATH);
							::WideCharToMultiByte(CP_ACP,
								0,
								lpObjCallbackInfos[i].objCallbackEntries[j].wKernelModulePath,
								-1,
								szName,
								sizeof(szName),
								NULL,
								NULL);
							printf("对象类型: %s, 回调类型: %s, 回调函数: 0x%p, 内核模块: %s\n",
								(lpObjCallbackInfos[i].objCallbackEntries[j].ulObjectType == 0 ? "*PsProcessType" : "*PsThreadType"),
								(lpObjCallbackInfos[i].objCallbackEntries[j].ulOperationType == 0 ? "PreOperation" : "PostOperation"),
								lpObjCallbackInfos[i].objCallbackEntries[j].pOperation,
								szName);
						}
						cout << endl;
					}
					cout << "对象回调的Altitude个数: " << ulCount << endl;
				}else {
					cout << "没有查询到对象回调信息!错误码: " << ::GetLastError() << endl;
				}
				delete[] lpObjCallbackInfos;
			}
		}
		break;
		case 1: //removeobcallback
		{
			PVOID RegistrationHandle;
			::sscanf((const char*)argv[2], "0x%p", &RegistrationHandle);
			if (RemoveObCallback(hDevice, RegistrationHandle)) {
				printf("对象回调(句柄: 0x%p)已成功摘除\n", RegistrationHandle);
			}else {
				printf("对象回调(句柄: 0x%p)摘除失败!错误码: %u\n", RegistrationHandle,::GetLastError());
			}
		}
		break;
		}

		//关闭控制设备
		::CloseHandle(hDevice);
	}else {
		cout << "打开控制设备失败!错误码: " << ::GetLastError() << endl;
	}

	return 0;
}

//显示命令行
VOID ShowUsage(LPCSTR argv0)
{
	CONST CHAR *p;
	if ((p = ::strrchr(argv0, '\\')) != NULL) {
		p++;
	}
	else {
		p = argv0;
	}
	printf("命令行:\n");
	printf("%s /queryobcallbacks: 查询ObRegisterCallbacks注册的回调\n", p);
	printf("%s /removeobcallback <handle>: 摘除ObRegisterCallbacks注册的回调\n", p);

	return;
}

//检查参数
INT CheckArgv(INT argc, CHAR *argv[])
{
	INT i, n = -1;
	if (argc < 2) return -1;

	if (argv[1][0] != '/'&&argv[1][0] != '-') return -1;

	for (i = 0; g_switches[i] != NULL; i++) {
		if (::strcmp((LPCSTR)&argv[1][1], g_switches[i]) == 0) {
			break;
		}
	}

	if (g_switches[i] == NULL) return -1;

	switch (i) {
	case 0: //queryobcallbacks
		if (argc == 2) n = i;
		break;
	case 1: //removeobcallback
		if (argc == 3) n = i;
		break;
	}

	return n;
}

//查询ObRegisterCallbacks注册的回调
ULONG QueryObCallbacks(IN HANDLE hDevice, OUT LPOBJ_CALLBACK_INFO lpObjCallbackInfos, IN ULONG ulMaxAltitudeCount)
{
	DWORD dwBytesRet;
	ULONG ulRetCount = 0;

	if (::DeviceIoControl(hDevice,
		IOCTL_QUERY_OBJCALLBACKS,
		NULL,
		0,
		(LPVOID)lpObjCallbackInfos,
		ulMaxAltitudeCount * sizeof(OBJ_CALLBACK_INFO),
		&dwBytesRet,
		NULL)) {
		ulRetCount = dwBytesRet / sizeof(OBJ_CALLBACK_INFO);
	}

	return ulRetCount;
}

//摘除ObRegisterCallbacks注册的回调
BOOL RemoveObCallback(IN HANDLE hDevice, IN PVOID RegistrationHandle)
{
	DWORD dwBytesRet;
	BOOL bSuc;

	bSuc = ::DeviceIoControl(hDevice,
		IOCTL_REMOVE_OBJCALLBACK,
		(LPVOID)&RegistrationHandle,
		sizeof(PVOID),
		NULL,
		0,
		&dwBytesRet,
		NULL);

	return bSuc;
}

3. 在WIN7 X64 7600上的运行效果(注意: 不能保证兼容其它系统,因为其它操作系统未公开的数据结构可能不一样,但分析和实现方法应该是一致的,这里仅仅是1次逆向练习),这里把InstallObjCallback.sys分别命名为:InstallObjCallback1.sys,InstallObjCallback2.sys,InstallObjCallback3.sys,随机产生3个不同的Altitude并注册回调,便于观察效果

可以看出: ObjectType->CallbackList链相关的回调的Altitude确实降序排列的,句柄为:0xFFFFF8A001F29850的回调也确实被摘除了。



恭喜ID[飞翔的猫咪]获看雪安卓应用安全能力认证高级安全工程师!!

最后于 2020-11-28 11:25 被低调putchar编辑 ,原因:
收藏
点赞2
打赏
分享
最新回复 (11)
雪    币: 7781
活跃值: 活跃值 (2403)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
hhkqqs 活跃值 1 2020-11-18 13:34
2
0
写的不错,其实枚举回调链表还能写的更简单一点,因为通过正规ObRegisterCallback注册的回调数组的ObjectType需要一致性,也就是说PsProcessType里的链表只能是PsProcessType类型的回调,PsThreadType的同理。个人感觉 if (pObjType == *PsProcessType) 这句判断完全可以剔除
雪    币: 2673
活跃值: 活跃值 (2189)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-11-18 14:18
3
0
hhkqqs 写的不错,其实枚举回调链表还能写的更简单一点,因为通过正规ObRegisterCallback注册的回调数组的ObjectType需要一致性,也就是说PsProcessType里的链表只能是PsPro ...
嗯!我主要考率到: nt!ObpInsertCallbackByAltitude内部是把 &pObpCallbackInfo->>ObpCallbackEntries[j].CallbackLinks这个PLIST_ENTRY插入了(*PsProcessType)->CallbackList或者(*PsThreadType)->CallbackList,所以通过ObjectType->CallbackList的CONTAINING_RECORD:得到的仅仅是: &pObpCallbackInfo->>ObpCallbackEntries[j],其中的对象类型毫无疑问:与*PsProcessTypeh或*PsThread是一致的。

不过pObpCallbackInfo->ObpCallbackEntries[j].pSelf指向的就是:pObpCallbackInfo了,即:RegistrationHandle, pObpCallbackInfo->Inserted是数组ObpCallbackEntries[]个数, 如果为2的话,
索引不同的ObpCallbackEntries[]元素就会有不同的对象类型:*PsProcessType,*PsThreadType了(它们具有相同的RegistrationHandle和Altitude名,分别监控进程和线程)。所以用了嵌套循环:代码就显得复杂了。

其实要用单循环也可以做到,只是与用户层交互的数据结构就要调整下!这样可以把内核层的算法时间复杂度从o(n^2)降低到o(n),另外也便于理解。
练习嘛!我循序渐进,逐步提高!
雪    币: 7781
活跃值: 活跃值 (2403)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
hhkqqs 活跃值 1 2020-11-18 14:39
4
0
低调putchar 嗯!我主要考率到: nt!ObpInsertCallbackByAltitude内部是把 &pObpCallbackInfo->>ObpCallbackEntries[j].Cal ...

~

最后于 2020-11-18 16:05 被hhkqqs编辑 ,原因:
雪    币: 2673
活跃值: 活跃值 (2189)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-11-18 15:02
5
0
hhkqqs 你误解了我的意思,我是指ObpCallbackEntries不可能同时存在PsProcessType和PsThreadType,因为ObRegisterCallback中OB_OPERATION_RE ...

明白你的意思了.OK! 我再跟一下!

最后于 2020-11-20 15:49 被低调putchar编辑 ,原因:
雪    币: 7781
活跃值: 活跃值 (2403)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
hhkqqs 活跃值 1 2020-11-18 15:16
6
0
低调putchar 明白你的意思了,也就说:OB_OPERATION_REGISTRATION数组中每个元素的:ObjectType成员必须一致才符合规范。OK! 我再跟一下![em_69]

~

最后于 2020-11-18 15:58 被hhkqqs编辑 ,原因:
雪    币: 2673
活跃值: 活跃值 (2189)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-11-18 16:00
7
0
hhkqqs 低调putchar 明白你的意思了,也就说:OB_OPERATION_REGISTRATION数组中每个元素的:ObjectType成员必须一致才符合规范。OK! ...

在虚拟机里调试过了!WIN7 X64 7600上没有这个现象。

数组中分别指定了: *PsProcessType, *PsThreadType

1. 进程过滤


2.线程过滤:



应该是系统不同的原因,毕竟WIN10系统后面做得很烂,坑太多了, 而且这些坑文档中根本就查不到。

前段时间忙项目又装了Center OS虚拟机, 我这台笔记本硬盘空间快不够了,所以我只有把太占空间的

WIN10系统虚拟机移其它机器上了。以后,我准备用另一台笔记本再调试WIN10。


雪    币: 2673
活跃值: 活跃值 (2189)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-11-18 16:04
8
0
系统版本太多!有坑也正常。
雪    币: 7781
活跃值: 活跃值 (2403)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
hhkqqs 活跃值 1 2020-11-18 16:04
9
0
低调putchar 明白你的意思了,也就说:OB_OPERATION_REGISTRATION数组中每个元素的:ObjectType成员必须一致才符合规范。OK! 我再跟一下![em_69]
我好像知道你的枚举应该怎么简化了,我看到你是尝试把所有的handle枚举出来,我刚看了下巨硬的示例代码是允许handle的回调数组存在不同ObjectType的,所以你这个思路本身没问题,但是如果有很多handle都注册了不同ObjectType的数组,你依次遍历Process和Thread的Callback链表就会存在不少重复枚举的判断,影响效率。我觉得可以不考虑使用handle的信息,直接遍历Process和Thread的CallbackList就够了,在用户层按handle值排序就能看出每个handle分别注册了什么样的回调
雪    币: 2673
活跃值: 活跃值 (2189)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-11-18 16:07
10
0
hhkqqs 我好像知道你的枚举应该怎么简化了,我看到你是尝试把所有的handle枚举出来,我刚看了下巨硬的示例代码是允许handle的回调数组存在不同ObjectType的,所以你这个思路本身没问题,但是如果有很 ...
对!这样内核层运行效率更高!练习嘛!我逐步提高!
雪    币: 7781
活跃值: 活跃值 (2403)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
hhkqqs 活跃值 1 2020-11-18 18:02
11
0
低调putchar 对!这样内核层运行效率更高!练习嘛!我逐步提高![em_65]
我又在win10下试了一次,好像是某杀软注册的线程回调和我的有冲突,win10下ObRegisterCallbacks的实现几乎和win7一模一样不可能有bug的
雪    币: 2673
活跃值: 活跃值 (2189)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-11-18 20:13
12
0
hhkqqs 我又在win10下试了一次,好像是某杀软注册的线程回调和我的有冲突,win10下ObRegisterCallbacks的实现几乎和win7一模一样不可能有bug的[em_10]
不同内核版本的系统未公开的数据结构不能保证完全相同,所以,很多的Rookit恶意代码一般都要对系统及内核版本进行判断的,在支持的系统上就开干。不过,我这里纯粹是感兴趣,以技术学习为目的,不干坏事的。再说,要加驱的话现在的HIPS都要拦截报警的!
游客
登录 | 注册 方可回帖
返回