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