首先调用ObRegisterCallbacks,查看所形成的结构是怎么样的。
OB_CALLBACK_REGISTRATION ObCallBack = { 0 };
OB_OPERATION_REGISTRATION ObOperation = { 0 };
ObCallBack.Version = ObGetFilterVersion();
ObCallBack.OperationRegistrationCount = 1;
ObCallBack.RegistrationContext = NULL;
ObCallBack.OperationRegistration = &ObOperation;
RtlInitUnicodeString(&ObCallBack.Altitude, L"22222");
ObOperation.ObjectType = PsProcessType;
ObOperation.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;//OB_OPERATION_HANDLE_CREATE = 1 OB_OPERATION_HANDLE_DUPLICATE = 2
ObOperation.PreOperation = ObProcess; //ObProcess在本次实验中地址为0xfffff880`03df2480
ObOperation.PostOperation = NULL;
NTSTATUS Status;
Status = ObRegisterCallbacks(&ObCallBack, &Handle);
然后查看PsProcessType中所形成的链表结构
kd> dt _OBJECT_TYPE 0Xfffffa80`0ccb9d10
nt!_OBJECT_TYPE
+0x000 TypeList : _LIST_ENTRY [ 0xfffffa80`0ccb9d10 - 0xfffffa80`0ccb9d10 ]
+0x010 Name : _UNICODE_STRING "Process"
+0x020 DefaultObject : (null)
+0x028 Index : 0x7 ''
+0x02c TotalNumberOfObjects : 0x2b
+0x030 TotalNumberOfHandles : 0x10e
+0x034 HighWaterNumberOfObjects : 0x34
+0x038 HighWaterNumberOfHandles : 0x127
+0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER
+0x0b0 TypeLock : _EX_PUSH_LOCK
+0x0b8 Key : 0x636f7250
+0x0c0 CallbackList : _LIST_ENTRY [ 0xfffff8a0`02385560 - 0xfffff8a0`02385560 ]
然后查看CallbackList
kd> dq 0xfffff8a0`02385560
fffff8a0`02385560 fffffa80`0ccb9dd0 fffffa80`0ccb9dd0
fffff8a0`02385570 00000001`00000003 fffff8a0`02385540
fffff8a0`02385580 fffffa80`0ccb9d10 fffff880`03df2480
fffff8a0`02385590 00000000`00000000 00000000`00000000
fffff8a0`023855a0 00320032`00320032 ffff0000`00000032
可以较为清晰的看出几个值,偏移0处为LIST_ENTRY 与类型对象中的链表相连,偏移0x20处为类型对象的地址即PsProcessType,偏移0x28处为ObProcess
接下来分析 ObRegisterCallbacks得到具体的结构对应项
如上述可知ObRegisterCallbacks有两个调用参数
rcx = ObCallBack;
rdx = Handle;
PAGE:00000001404B6D60 arg_0 = qword ptr 8
PAGE:00000001404B6D60 arg_8 = qword ptr 10h
PAGE:00000001404B6D60 arg_10 = qword ptr 18h
PAGE:00000001404B6D60 arg_18 = qword ptr 20h
PAGE:00000001404B6D60
PAGE:00000001404B6D60 mov rax, rsp
PAGE:00000001404B6D63 mov [rax+8], rbx
PAGE:00000001404B6D67 mov [rax+18h], rbp
PAGE:00000001404B6D6B mov [rax+20h], rsi
PAGE:00000001404B6D6F mov [rax+10h], rdx
PAGE:00000001404B6D73 push rdi
PAGE:00000001404B6D74 push r12
PAGE:00000001404B6D76 push r13
PAGE:00000001404B6D78 push r14
PAGE:00000001404B6D7A push r15
PAGE:00000001404B6D7C sub rsp, 20h
PAGE:00000001404B6D80 movzx eax, [rcx+OB_CALLBACK_REGISTRATION.Version] ; 获得填充结构中的Version
PAGE:00000001404B6D83 xor ebx, ebx ; ebx = 0
PAGE:00000001404B6D85 mov r12, rcx ; r12 = ObCallBack
PAGE:00000001404B6D88 mov ecx, 0FF00h ; ecx = 0xFF00
PAGE:00000001404B6D8D mov r14d, 100h ; r14d = 0x100
PAGE:00000001404B6D93 mov r15, rdx ; r15 = Handle
PAGE:00000001404B6D96 and ax, cx ; ax = Version & 0xFF00
PAGE:00000001404B6D99 mov esi, ebx ; esi = 0
PAGE:00000001404B6D9B cmp ax, r14w ; 将(Version & 0xFF00)和0x100进行比较
PAGE:00000001404B6D9F jz short loc_1404B6DAB
PAGE:00000001404B6DA1 loc_1404B6DA1: ; CODE XREF: ObRegisterCallbacks+51↓j
PAGE:00000001404B6DA1 mov eax, 0C000000Dh ; 如果(Version & 0xFF00)不为0x100或设置的Count为0 返回0xC000000D错误
PAGE:00000001404B6DA6 jmp loc_1404B7009
PAGE:00000001404B6DAB ; ---------------------------------------------------------------------------
PAGE:00000001404B6DAB
PAGE:00000001404B6DAB loc_1404B6DAB: ; CODE XREF: ObRegisterCallbacks+3F↑j
PAGE:00000001404B6DAB cmp [r12+OB_CALLBACK_REGISTRATION.OperationRegistrationCount], bx
PAGE:00000001404B6DB1 jz short loc_1404B6DA1 ; 如果(Version & 0xFF00)不为0x100或设置的Count为0 返回0xC000000D错误
PAGE:00000001404B6DB3 movzx ecx, [r12+OB_CALLBACK_REGISTRATION.OperationRegistrationCount]
PAGE:00000001404B6DB9 movzx eax, [r12+OB_CALLBACK_REGISTRATION.Altitude.Length]
PAGE:00000001404B6DBF mov r8d, 6C46624Fh ; Tag
PAGE:00000001404B6DC5 shl ecx, 6
PAGE:00000001404B6DC8 lea ebp, [rcx+rax+20h]
PAGE:00000001404B6DCC mov ecx, 1 ; PoolType
PAGE:00000001404B6DD1 mov edx, ebp ; NumberOfBytes
PAGE:00000001404B6DD3 mov r13d, ebp
PAGE:00000001404B6DD6 call ExAllocatePoolWithTag ; 申请 0x40 * Count + 0x20 + Altitude.Length的长度
PAGE:00000001404B6DDB mov rdi, rax
PAGE:00000001404B6DDE cmp rax, rbx
PAGE:00000001404B6DE1 jnz short loc_1404B6DED
PAGE:00000001404B6DE3 mov eax, 0C000009Ah ; 如果申请内存失败 则返回0xC000009A错误
PAGE:00000001404B6DE8 jmp loc_1404B7009
PAGE:00000001404B6DED ; ---------------------------------------------------------------------------
PAGE:00000001404B6DED
PAGE:00000001404B6DED loc_1404B6DED: ; CODE XREF: ObRegisterCallbacks+81↑j
PAGE:00000001404B6DED mov r8, r13 ; Size
PAGE:00000001404B6DF0 xor edx, edx ; Val
PAGE:00000001404B6DF2 mov rcx, rax ; Dst
PAGE:00000001404B6DF5 call memset ; 将申请的内存置零
PAGE:00000001404B6DF5 ; 接下来就开始进行结构的填充
PAGE:00000001404B6DF5 ; 我们暂且将这个结构命名为CallBackStr
PAGE:00000001404B6DFA mov [rdi+CallBackStr.VersionCmp], r14w ; 根据上面可知r14w = 0x100 将r14w填入结构偏移0处
PAGE:00000001404B6DFE mov rax, [r12+OB_CALLBACK_REGISTRATION.RegistrationContext]
PAGE:00000001404B6E03 mov [rdi+CallBackStr.RegistrationContext], rax ; 将提供的RegistrationContext填入结构0x8偏移处
PAGE:00000001404B6E03 ; 该对象在调用到回调函数时为函数的第一个参数
PAGE:00000001404B6E07 movzx edx, [r12+OB_CALLBACK_REGISTRATION.Altitude.Length]
PAGE:00000001404B6E0D sub ebp, edx ; ebp = 0x40* Count + 0x20
PAGE:00000001404B6E0F mov [rdi+CallBackStr.length2], dx ; 将所给Altitude字符的长度 填入偏移0x10和0x12处
PAGE:00000001404B6E13 mov [rdi+CallBackStr.length1], dx
PAGE:00000001404B6E17 mov r8, rdx ; Size
PAGE:00000001404B6E1A mov ecx, ebp ; ecx = 0x40 * count + 0x20
PAGE:00000001404B6E1C add rcx, rdi ; rcx = 申请的内存地址 + 0x40 * count + 0x20
PAGE:00000001404B6E1F mov [rdi+18h], rcx
PAGE:00000001404B6E23 mov rdx, [r12+OB_CALLBACK_REGISTRATION.Altitude.Buffer]
PAGE:00000001404B6E28 call memmove ; 从这个拷贝复制可以看出在结构的最后一个部分存放着提供的Altitude中的字符串
PAGE:00000001404B6E2D mov r14d, ebx ; r14d = 0
PAGE:00000001404B6E30 cmp bx, [r12+OB_CALLBACK_REGISTRATION.OperationRegistrationCount]
PAGE:00000001404B6E36 jnb loc_1404B6FDD ; 判断所给的count是否为非正数,如果成立则跳转 我们这里不考虑负数的情况
PAGE:00000001404B6E3C mov rbp, rbx ; rbp = 0
PAGE:00000001404B6E3F lea r13, [rdi+58h] ; r13 = 申请内存地址 + 0x58处
PAGE:00000001404B6E43
PAGE:00000001404B6E43 loc_1404B6E43: ; CODE XREF: ObRegisterCallbacks+199↓j
PAGE:00000001404B6E43 mov rsi, [r12+OB_CALLBACK_REGISTRATION.OperationRegistration]
PAGE:00000001404B6E48 cmp [rsi+rbp+OB_OPERATION_REGISTRATION.Operations], ebx ;
PAGE:00000001404B6E48 ; 判断所提供的参数中是否已经定义了对于何种情况需要进入回调函数
PAGE:00000001404B6E48 ; 在前面提供的例子中 可以看到这里我们设置为
PAGE:00000001404B6E48 ; OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE
PAGE:00000001404B6E48 ; 即在打开句柄或者复制句柄的时候会进入回调函数
PAGE:00000001404B6E4C jz loc_1404B6F08
PAGE:00000001404B6E52 mov rax, [rsi+rbp+OB_OPERATION_REGISTRATION.ObjectType]
PAGE:00000001404B6E56 mov rcx, [rax]
PAGE:00000001404B6E59 test [rcx+_OBJECT_TYPE.TypeInfo.___u1.ObjectTypeFlags], 40h
PAGE:00000001404B6E5D jz loc_1404B6F08 ;
PAGE:00000001404B6E5D ; 判断类型对象中的ObjectTyoeFlags第7位是否为1
PAGE:00000001404B6E5D ; 该值在调用回调函数的时候也会进行判断
PAGE:00000001404B6E5D ; 如果将该值设置为0 则会禁止回调
PAGE:00000001404B6E63 mov rcx, [rsi+rbp+OB_OPERATION_REGISTRATION.PreOperation]
PAGE:00000001404B6E68 cmp rcx, rbx ; 接下来判断是否给了访问前的回调函数和访问后的回调函数
PAGE:00000001404B6E68 ; 如果给了则会调用MmVerifyCallbackFunction判断回调函数是否合法
PAGE:00000001404B6E6B jnz short loc_1404B6E7D
PAGE:00000001404B6E6D cmp [rsi+rbp+OB_OPERATION_REGISTRATION.PostOperation], rbx
PAGE:00000001404B6E72 jz loc_1404B6F08
PAGE:00000001404B6E78 cmp rcx, rbx
PAGE:00000001404B6E7B jz short loc_1404B6E86
PAGE:00000001404B6E7D
PAGE:00000001404B6E7D loc_1404B6E7D: ; CODE XREF: ObRegisterCallbacks+10B↑j
PAGE:00000001404B6E7D call MmVerifyCallbackFunction
PAGE:00000001404B6E82 cmp eax, ebx
PAGE:00000001404B6E84 jz short loc_1404B6F01
PAGE:00000001404B6E86
PAGE:00000001404B6E86 loc_1404B6E86: ; CODE XREF: ObRegisterCallbacks+11B↑j
PAGE:00000001404B6E86 mov rcx, [rsi+rbp+OB_OPERATION_REGISTRATION.PostOperation]
PAGE:00000001404B6E8B cmp rcx, rbx
PAGE:00000001404B6E8E jz short loc_1404B6E99 ; r13 = 申请内存地址 + 0x58处 所以相当于在结构0x58偏移处填充0
PAGE:00000001404B6E90 call MmVerifyCallbackFunction
PAGE:00000001404B6E95 cmp eax, ebx
PAGE:00000001404B6E97 jz short loc_1404B6F01
PAGE:00000001404B6E99
PAGE:00000001404B6E99 loc_1404B6E99: ; CODE XREF: ObRegisterCallbacks+12E↑j
PAGE:00000001404B6E99 mov [r13+0], rbx ; r13 = 申请内存地址 + 0x58处 所以相当于在结构0x58偏移处填充0
PAGE:00000001404B6E9D lea rdx, [r13-38h] ; 在结构偏移0x20处 初始化一个链表
PAGE:00000001404B6EA1 mov [rdx], rdx
PAGE:00000001404B6EA4 mov [r13-30h], rdx
PAGE:00000001404B6EA8 mov eax, [rsi+rbp+OB_OPERATION_REGISTRATION.Operations]
PAGE:00000001404B6EAC mov [r13-28h], eax ; 将操作码 填充到结构的0x30
PAGE:00000001404B6EB0 mov [r13-20h], rdi ; 将结构的首地址 填充到偏移0x38处
PAGE:00000001404B6EB4 mov rax, [rsi+rbp+OB_OPERATION_REGISTRATION.ObjectType]
PAGE:00000001404B6EB8 mov rcx, [rax] ; 取出类型对象地址赋给rcx 即PsProcessType
PAGE:00000001404B6EBB mov [r13-18h], rcx ; 将类型对象地址 填充到结构0x40处
PAGE:00000001404B6EBF mov rax, [rsi+rbp+OB_OPERATION_REGISTRATION.PreOperation]
PAGE:00000001404B6EC4 mov [r13-10h], rax ; 将访问前函数地址填充到结构0x48处
PAGE:00000001404B6EC8 mov rax, [rsi+rbp+OB_OPERATION_REGISTRATION.PostOperation]
PAGE:00000001404B6ECD mov [r13-8], rax ; 将访问后函数地址填充到结构0x50偏移处
PAGE:00000001404B6ED1 call ObpInsertCallbackByAltitude ; 将结构中的链表插入到类型对象的CallbackList链表中
到这里我们先总结下所得到的结构
typedef struct _CallBackStr
{
USHORT VersionCmp;//0
UCHAR uFill1[6];//2 填充结构
PVOID RegistrationContext;//8
USHORT length1;//0x10
USHORT lenth2;//0x12
UCHAR uFill2[0xC];//0x14 填充结构
LIST_ENTRY List; //0x20
ULONG Operations;//0x30
ULONG uFill3;//0x34
PVOID pExAlloc;//0x38
PVOID pObjectType;//0x40
PVOID PreOperation;//0x48
PVOID PostOperation;//0x50
ULONG64 uEnd;//0x58
UCHAR uNameBuffer[lenth];//0x60
}CallBackStr,*PCallBackStr;
再次取出CallbackList
kd> dq 0xfffff8a0`02385560
fffff8a0`02385560 fffffa80`0ccb9dd0 fffffa80`0ccb9dd0
fffff8a0`02385570 00000001`00000003 fffff8a0`02385540
fffff8a0`02385580 fffffa80`0ccb9d10 fffff880`03df2480
fffff8a0`02385590 00000000`00000000 00000000`00000000
fffff8a0`023855a0 00320032`00320032 ffff0000`00000032
可以看出0xfffff8a0`02385560为结构的0x20偏移处,取出结构首地址
kd> dq 0xfffff8a0`02385540
fffff8a0`02385540 00000000`00010100 00000000`00000000
fffff8a0`02385550 00000000`000a000a fffff8a0`023855a0
fffff8a0`02385560 fffffa80`0ccb9dd0 fffffa80`0ccb9dd0
fffff8a0`02385570 00000001`00000003 fffff8a0`02385540
fffff8a0`02385580 fffffa80`0ccb9d10 fffff880`03df2480
fffff8a0`02385590 00000000`00000000 00000000`00000000
fffff8a0`023855a0 00320032`00320032 ffff0000`00000032
可以看到除了个别地方 (偏移0x34和偏移0x2处) 其余都和代码所对应 继续分析接下来的代码
PAGE:00000001404B6ED6 cmp eax, ebx
PAGE:00000001404B6ED8 mov esi, eax
PAGE:00000001404B6EDA jl short loc_1404B6F15
PAGE:00000001404B6EDC mov eax, 1
PAGE:00000001404B6EE1 add rbp, 20h
PAGE:00000001404B6EE5 add r13, 40h
PAGE:00000001404B6EE9 add [rdi+CallBackStr.flag], ax ; 将结构的偏移2处 置为1
PAGE:00000001404B6EED movzx ecx, [r12+OB_CALLBACK_REGISTRATION.OperationRegistrationCount]
PAGE:00000001404B6EF3 add r14d, eax
PAGE:00000001404B6EF6 cmp r14d, ecx
PAGE:00000001404B6EF9 jb loc_1404B6E43 ; 如果Count>1将会进入循环再次进入填充插入环节
PAGE:00000001404B6EFF jmp short loc_1404B6F0D
PAGE:00000001404B6F0D loc_1404B6F0D: ; CODE XREF: ObRegisterCallbacks+19F↑j
PAGE:00000001404B6F0D cmp esi, ebx
PAGE:00000001404B6F0F jge loc_1404B6FDD ; 判断插入链表的返回值 如果大于等于0 跳转
PAGE:00000001404B6FDD loc_1404B6FDD: ; CODE XREF: ObRegisterCallbacks+D6↑j
PAGE:00000001404B6FDD ; ObRegisterCallbacks+1AF↑j
PAGE:00000001404B6FDD cmp bx, [rdi+CallBackStr.flag] ; 如果偏移2处 为负数跳转
PAGE:00000001404B6FE1 jnb short loc_1404B7004
PAGE:00000001404B6FE3 lea rcx, [rdi+34h] ; 取出偏移0x34处地址
PAGE:00000001404B6FE7 mov r15d, 1
PAGE:00000001404B6FED
PAGE:00000001404B6FED loc_1404B6FED: ; CODE XREF: ObRegisterCallbacks+29D↓j
PAGE:00000001404B6FED or [rcx], r15d ; 此处便为设置偏移0x34处
PAGE:00000001404B6FF0 movzx eax, [rdi+CallBackStr.flag]
PAGE:00000001404B6FF4 add ebx, r15d
PAGE:00000001404B6FF7 add rcx, 40h
PAGE:00000001404B6FFB cmp ebx, eax
PAGE:00000001404B6FFD jb short loc_1404B6FED ; 此处便为设置偏移0x34处
PAGE:00000001404B6FFF mov r15, [rsp+48h+arg_8]
PAGE:00000001404B7004
PAGE:00000001404B7004 loc_1404B7004: ; CODE XREF: ObRegisterCallbacks+281↑j
PAGE:00000001404B7004 mov [r15], rdi
PAGE:00000001404B7007 loc_1404B7007: ; CODE XREF: ObRegisterCallbacks+27B↑j
PAGE:00000001404B7007 mov eax, esi
PAGE:00000001404B7009
PAGE:00000001404B7009 loc_1404B7009: ; CODE XREF: ObRegisterCallbacks+46↑j
PAGE:00000001404B7009 ; ObRegisterCallbacks+88↑j
PAGE:00000001404B7009 mov rbx, [rsp+48h+arg_0]
PAGE:00000001404B700E mov rbp, [rsp+48h+arg_10]
PAGE:00000001404B7013 mov rsi, [rsp+48h+arg_18]
PAGE:00000001404B7018 add rsp, 20h
PAGE:00000001404B701C pop r15
PAGE:00000001404B701E pop r14
PAGE:00000001404B7020 pop r13
PAGE:00000001404B7022 pop r12
PAGE:00000001404B7024 pop rdi
PAGE:00000001404B7025 retn
以上便为对于ObRegisterCallbacks 如果存在错误 希望能予以指出。