首页
论坛
课程
招聘
[原创]逆向分析ObRegisterCallbacks学习回调结构
2020-11-30 17:09 1312

[原创]逆向分析ObRegisterCallbacks学习回调结构

2020-11-30 17:09
1312

首先调用ObRegisterCallbacks,查看所形成的结构是怎么样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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中所形成的链表结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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得到具体的结构对应项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
如上述可知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:                       
PAGE:00000001404B6DA1                 mov     eax, 0C000000Dh ; 如果(Version & 0xFF00)不为0x100或设置的Count为0 返回0xC000000D错误
PAGE:00000001404B6DA6                 jmp     loc_1404B7009
PAGE:00000001404B6DAB ; ---------------------------------------------------------------------------
PAGE:00000001404B6DAB
PAGE:00000001404B6DAB loc_1404B6DAB:                         
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:                         
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字符的长度 填入偏移0x100x12
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:                        
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:                        
PAGE:00000001404B6E7D                 call    MmVerifyCallbackFunction
PAGE:00000001404B6E82                 cmp     eax, ebx
PAGE:00000001404B6E84                 jz      short loc_1404B6F01
PAGE:00000001404B6E86
PAGE:00000001404B6E86 loc_1404B6E86:                        
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:                        
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链表中

到这里我们先总结下所得到的结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

1
2
3
4
5
6
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偏移处,取出结构首地址

1
2
3
4
5
6
7
8
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处) 其余都和代码所对应 继续分析接下来的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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:                         
PAGE:00000001404B6F0D                 cmp     esi, ebx
PAGE:00000001404B6F0F                 jge     loc_1404B6FDD   ; 判断插入链表的返回值 如果大于等于0 跳转
 
PAGE:00000001404B6FDD loc_1404B6FDD:                         
PAGE:00000001404B6FDD                                        
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:                         
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:                        
PAGE:00000001404B7004                 mov     [r15], rdi
PAGE:00000001404B7007 loc_1404B7007:                        
PAGE:00000001404B7007                 mov     eax, esi
PAGE:00000001404B7009
PAGE:00000001404B7009 loc_1404B7009:                      
PAGE:00000001404B7009                                       
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 如果存在错误 希望能予以指出。


看雪侠者千人榜,看看你上榜了吗?

最后于 2020-11-30 17:14 被JustOn1y编辑 ,原因:
收藏
点赞0
打赏
分享
最新回复 (2)
雪    币: 1859
活跃值: 活跃值 (1596)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
低调putchar 活跃值 1 2020-11-30 23:23
2
0

其实: UCHAR uFill1[6]; //2 填充成员 ULONG uFill3; //0x34  填充成员只是为了阅读的方便
如果没有指定对齐方式,默认按8字节对齐,如果把字节对齐考虑进来,这2个成员可以简化掉。

期待楼主更精彩的帖子!

最后于 2020-11-30 23:28 被低调putchar编辑 ,原因:
雪    币: 258
活跃值: 活跃值 (71)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
JustOn1y 活跃值 2020-12-1 09:27
3
0
低调putchar 其实: UCHAR uFill1[6]; //2 填充成员 ULONG uFill3; // ...
感谢你的提醒
游客
登录 | 注册 方可回帖
返回