Post

프로세스 보호 (PspProcessOpen)

STATUS_UNSUCCESSFUL (0xC0000001)

OpenProcess를 호출하면 0xC0000001를 반환하며 실패하는 해킹툴이 발견되었습니다.

다음과 같이 NtOpenProcess 시스콜 이후에 실패하고 있으며, 이를 봤을 때 커널 레벨에서 조작된 것을 추측할 수 있습니다.

해당 값은 MS-ERREF 문서에 나와있는데 요청이 실패한 경우 반환되는 값입니다. 특정한 경우가 아닌, 범용적으로 사용되는 코드라 해당 내용만 가지고는 어떤 부분이 조작되었는지 짐작하기 어렵습니다.

Return value/codeDescription
0xC0000001

STATUS_UNSUCCESSFUL
{Operation Failed} The requested operation was unsuccessful.

ntkrnlmp 내에 존재하는 OpenProcess와 관련된 반환 부분을 전부 확인하였지만 조작으로 의심되는 부분이 확인되지 않았습니다.

Kernel Debugging

덤프만으로는 변조된 위치를 찾기 어렵기 때문에, 가상 환경에서 커널 디버깅을 통해 분석을 진행하였습니다. 다음과 같이 보호가 걸린 프로세스를 대상으로 OpenProcess를 시도하고 동적 분석을 진행합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <Windows.h>
#include <stdio.h>

int main()
{
    MessageBoxA(0, "Wait", "debug", 0);

    // dwm.exe
    HANDLE dwm = 0;
    do
    {
        dwm = OpenProcess(PROCESS_ALL_ACCESS, false, 9360);

        printf("handle : %08X\n", dwm);
    } while (!dwm);

    system("pause");
}

분석은 Windbg Preview를 통해 진행하였으며, 커널 디버그 모드에서는 다음과 같이 대상 프로세스를 찾고 bp를 설정합니다.

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
2: kd> !process 0 0 test.exe
PROCESS ffffce05ef58a080
    SessionId: 1  Cid: 2aa8    Peb: abecbd3000  ParentCid: 1578
    DirBase: 12809a000  ObjectTable: ffffe086d45b5b40  HandleCount: 138.
    Image: test.exe

2: kd> .process /i /r /p ffffce05ef58a080
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
2: kd> g
Break instruction exception - code 80000003 (first chance)
nt!DbgBreakPointWithStatus:
fffff805`25407150 cc              int     3
14: kd> .reload /user
Loading User Symbols
...............................

14: kd> u test!main
test!main [C:\Users\JH\Downloads\ConsoleApplication5\ConsoleApplication5.cpp @ 5]:
00007ff6`fd631070 4883ec28        sub     rsp,28h
00007ff6`fd631074 4533c9          xor     r9d,r9d
00007ff6`fd631077 4c8d0522e40100  lea     r8,[test!`string' (00007ff6`fd64f4a0)]
00007ff6`fd63107e 488d1523e40100  lea     rdx,[test!`string' (00007ff6`fd64f4a8)]
00007ff6`fd631085 33c9            xor     ecx,ecx
00007ff6`fd631087 ff15f3610100    call    qword ptr [test!_imp_MessageBoxA (00007ff6`fd647280)]
00007ff6`fd63108d 33d2            xor     edx,edx
00007ff6`fd63108f 41b890240000    mov     r8d,2490h
00007ff6`fd631095 b9ffff1f00      mov     ecx,1FFFFFh
00007ff6`fd63109a ff15605f0100    call    qword ptr [test!_imp_OpenProcess (00007ff6`fd647000)]
00007ff6`fd6310a0 488bd0          mov     rdx,rax

0: kd> bp /p @$proc 00007ff6`fd63109a

이후에 메세지 박스를 확인하여 OpenProcess가 실행되면 중단점이 실행됩니다.

동적 디버깅을 통해 함수 내부로 진입해 다음과 같은 코드 위치에서 0xC0000001가 반환되는 것을 확인하였습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
14: kd> u rip-5
nt!ObpIncrementHandleCountEx+0x343:
fffff805`2564be23 e828c0dbff      call    nt!guard_dispatch_icall (fffff805`25407e50)
fffff805`2564be28 8be8            mov     ebp,eax
fffff805`2564be2a 4584ed          test    r13b,r13b
fffff805`2564be2d 0f8515010000    jne     nt!ObpIncrementHandleCountEx+0x468 (fffff805`2564bf48)
fffff805`2564be33 65488b042588010000 mov   rax,qword ptr gs:[188h]
fffff805`2564be3c 66ff88e4010000  dec     word ptr [rax+1E4h]
fffff805`2564be43 33d2            xor     edx,edx
fffff805`2564be45 498bce          mov     rcx,r14

14: kd> r
rax=00000000c0000001 rbx=ffffce05e64b0400 rcx=0000000000000001
rdx=0000000000000001 rsi=0000000000000001 rdi=ffffce05eb26f050
rip=fffff8052564be28 rsp=fffff40851bff160 rbp=ffffce05ec1bd080
 r8=ffffce05ec1bd080  r9=ffffce05eb26f080 r10=0000000000002a68
r11=ffffce05e5f030b0 r12=0000000000000001 r13=0000000000000000
r14=ffffce05eb26f060 r15=0000000000000000
iopl=0         nv up ei pl zr na po nc
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00040246
nt!ObpIncrementHandleCountEx+0x348:
fffff805`2564be28 8be8            mov     ebp,eax

해당 위치를 다시 확인해보면 다음과 같이 심볼 정보가 존재하지 않은 특정 함수로 진입합니다. 함수 내부에서는 0xC0000001를 반환하고 있으며, 해킹툴에 의하여 호출되는 함수로 추측할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
ffffce05`e5f19000 49bbb030f0e505ceffff mov     r11, 0FFFFCE05E5F030B0h
ffffce05`e5f1900a 4d3bc1               cmp     r8, r9
ffffce05`e5f1900d 741a                 je      FFFFCE05E5F19029
ffffce05`e5f1900f 85c9                 test    ecx, ecx
ffffce05`e5f19011 7416                 je      FFFFCE05E5F19029
ffffce05`e5f19013 498b03               mov     rax, qword ptr [r11]
ffffce05`e5f19016 4c8b5008             mov     r10, qword ptr [rax+8]
ffffce05`e5f1901a 4d399140040000       cmp     qword ptr [r9+440h], r10
ffffce05`e5f19021 7506                 jne     FFFFCE05E5F19029
ffffce05`e5f19023 b8010000c0           mov     eax, 0C0000001h
ffffce05`e5f19028 c3                   ret     

해당 함수의 호출 스택은 다음과 같습니다.

RingCall Stacks
00xffffce05e5f19000
0nt!ObpIncrementHandleCountEx
0nt!ObpCreateHandle
0nt!ObOpenObjectByPointer
0nt!PsOpenProcess
0nt!NtOpenProcess
0nt!KiSystemServiceCopyEnd
3ntdll!NtOpenProcess
3KERNELBASE!OpenProcess
3test!main

ObpIncrementHandleCountEx에서는 다음과 같이 함수 포인터를 구해오며 _guard_dispatch_icall를 통해 rax에 존재하는 해킹툴 함수를 호출합니다.

1
2
3
4
5
6
7
8
9
10
fffff805`2564bdfa 8b4c245c           mov     ecx, dword ptr [rsp+5Ch]
fffff805`2564bdfe 4c8bc5             mov     r8, rbp
*fffff805`2564be01 488b4378           mov     rax, qword ptr [rbx+78h]
fffff805`2564be05 4c8b4c2470         mov     r9, qword ptr [rsp+70h]
fffff805`2564be0a 0fb6942420010000   movzx   edx, byte ptr [rsp+120h]
fffff805`2564be12 894c2428           mov     dword ptr [rsp+28h], ecx
fffff805`2564be16 488b4c2468         mov     rcx, qword ptr [rsp+68h]
fffff805`2564be1b 48894c2420         mov     qword ptr [rsp+20h], rcx
fffff805`2564be20 418bcc             mov     ecx, r12d
fffff805`2564be23 e828c0dbff         call    ntkrnlmp!_guard_dispatch_icall (fffff80525407e50)

참조되는 함수 포인터의 메모리를 확인해보면 다음과 같습니다. PspProcessClose, PspProcessDelete 함수와 함께 해킹툴 코드가 위치하고 있으며, 이를 통해 특정 함수 테이블이 후킹되었음을 추측할 수 있습니다.

1
2
3
4
4: kd> dqs rbx+78
ffffce05`e64b0478  ffffce05`e5f19000
ffffce05`e64b0480  fffff805`256fb510 nt!PspProcessClose
ffffce05`e64b0488  fffff805`255f4c50 nt!PspProcessDelete

후킹된 함수는 nt!PspProcessOpen이며, 해킹툴이 적용되지 않은 클린 환경에서 동일한 테스트를 통해 확인하였습니다.

Kernel Memory Dump

디버깅을 통해 확인된 정보를 실제 해킹툴이 적용된 덤프 파일에서 다시 확인해봤습니다. 후킹된 nt!PspProcessOpen 함수는 PsProcessType를 통해 다음과 같이 확인할 수 있습니다.

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
3: kd> dqs PsProcessType
fffff800`6dafc410  ffff8488`aa562b00

3: kd> dt_object_type ffff8488`aa562b00
ntdll!_OBJECT_TYPE
   +0x000 TypeList         : _LIST_ENTRY [ 0xffff8488`aa562b00 - 0xffff8488`aa562b00 ]
   +0x010 Name             : _UNICODE_STRING "Process"
   +0x020 DefaultObject    : (null) 
   +0x028 Index            : 0x7 ''
   +0x02c TotalNumberOfObjects : 0xa1
   +0x030 TotalNumberOfHandles : 0x524
   +0x034 HighWaterNumberOfObjects : 0xa4
   +0x038 HighWaterNumberOfHandles : 0x548
   +0x040 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x0b8 TypeLock         : _EX_PUSH_LOCK
   +0x0c0 Key              : 0x636f7250
   +0x0c8 CallbackList     : _LIST_ENTRY [ 0xffff9606`6a412b00 - 0xffff9606`6a429780 ]

3: kd> dt_OBJECT_TYPE_INITIALIZER ffff8488`aa562b00+40
ntdll!_OBJECT_TYPE_INITIALIZER
   +0x000 Length           : 0x78
   +0x002 ObjectTypeFlags  : 0xca
   +0x002 CaseInsensitive  : 0y0
   +0x002 UnnamedObjectsOnly : 0y1
   +0x002 UseDefaultObject : 0y0
   +0x002 SecurityRequired : 0y1
   +0x002 MaintainHandleCount : 0y0
   +0x002 MaintainTypeList : 0y0
   +0x002 SupportsObjectCallbacks : 0y1
   +0x002 CacheAligned     : 0y1
   +0x003 UseExtendedParameters : 0y0
   +0x003 Reserved         : 0y0000000 (0)
   +0x004 ObjectTypeCode   : 0x20
   +0x008 InvalidAttributes : 0xb0
   +0x00c GenericMapping   : _GENERIC_MAPPING
   +0x01c ValidAccessMask  : 0x1fffff
   +0x020 RetainAccess     : 0x101000
   +0x024 PoolType         : 200 ( NonPagedPoolNx )
   +0x028 DefaultPagedPoolCharge : 0x1000
   +0x02c DefaultNonPagedPoolCharge : 0xa98
   +0x030 DumpProcedure    : (null) 
   +0x038 OpenProcedure    : 0xffff8488`aa5624e0     long  +ffff8488aa5624e0
   +0x040 CloseProcedure   : 0xfffff800`6d46e6e0     void  nt!PspProcessClose+0
   +0x048 DeleteProcedure  : 0xfffff800`6d4039e0     void  nt!PspProcessDelete+0
   +0x050 ParseProcedure   : (null) 
   +0x050 ParseProcedureEx : (null) 
   +0x058 SecurityProcedure : 0xfffff800`6d4d8eb0     long  nt!SeDefaultObjectMethod+0
   +0x060 QueryNameProcedure : (null) 
   +0x068 OkayToCloseProcedure : (null) 
   +0x070 WaitObjectFlagMask : 0
   +0x074 WaitObjectFlagOffset : 0
   +0x076 WaitObjectPointerOffset : 0

이전에 확인된 내용과 동일하게 OpenProcedure(PspProcessOpen) 함수가 함수 테이블을 통해 후킹되어 있습니다.

1
2
3
4
5
3: kd> dt_OBJECT_TYPE_INITIALIZER ffff8488`aa562b00+40
ntdll!_OBJECT_TYPE_INITIALIZER
   +0x038 OpenProcedure    : 0xffff8488`aa5624e0     long  +ffff8488aa5624e0
   +0x040 CloseProcedure   : 0xfffff800`6d46e6e0     void  nt!PspProcessClose+0
   +0x048 DeleteProcedure  : 0xfffff800`6d4039e0     void  nt!PspProcessDelete+0

해킹툴이 적용되지 않은 정상 환경에서는 다음과 같이 OpenProcess가 nt!PspProcessOpen을 나타냅니다.

1
2
3
4
5
3: kd> dt_OBJECT_TYPE_INITIALIZER ffff8488`aa562b00+40
ntdll!_OBJECT_TYPE_INITIALIZER
   +0x038 OpenProcedure    : 0xfffff800`6d3fd930     long  nt!PspProcessOpen+0
   +0x040 CloseProcedure   : 0xfffff800`6d46e6e0     void  nt!PspProcessClose+0
   +0x048 DeleteProcedure  : 0xfffff800`6d4039e0     void  nt!PspProcessDelete+0

Hookcode

해킹툴에서 사용하는 후킹 코드는 다음과 같으며 다양한 기능을 수행하고 있습니다. 간략하게 핵심적인 부분만 분석 진행하였습니다.

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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
3: kd> $$>< C:\git\Windbg Scripts\CheckOpenProcedure
hooked openprocedure.
ffff8488`aa562b78  ffff8488`aa5624e0
ffff8488`aa562b80  fffff800`6d46e6e0 nt!PspProcessClose
ffff8488`aa562b88  fffff800`6d4039e0 nt!PspProcessDelete

ffff8488`aa5624e0 89542410        mov     dword ptr [rsp+10h],edx
ffff8488`aa5624e4 894c2408        mov     dword ptr [rsp+8],ecx
ffff8488`aa5624e8 55              push    rbp
ffff8488`aa5624e9 53              push    rbx
ffff8488`aa5624ea 56              push    rsi
ffff8488`aa5624eb 57              push    rdi
ffff8488`aa5624ec 4154            push    r12
ffff8488`aa5624ee 4155            push    r13
ffff8488`aa5624f0 4156            push    r14
ffff8488`aa5624f2 4157            push    r15
ffff8488`aa5624f4 488d6c24e9      lea     rbp,[rsp-17h]
ffff8488`aa5624f9 4881ece8000000  sub     rsp,0E8h
ffff8488`aa562500 48bb302456aa8884ffff mov rbx,0FFFF8488AA562430h
ffff8488`aa56250a 33ff            xor     edi,edi
ffff8488`aa56250c 4d8bf9          mov     r15,r9
ffff8488`aa56250f 498bf0          mov     rsi,r8
ffff8488`aa562512 448bf1          mov     r14d,ecx
ffff8488`aa562515 488b1b          mov     rbx,qword ptr [rbx]
ffff8488`aa562518 48897d6f        mov     qword ptr [rbp+6Fh],rdi
ffff8488`aa56251c ff5348          call    qword ptr [rbx+48h]
ffff8488`aa56251f 4c8b657f        mov     r12,qword ptr [rbp+7Fh]
ffff8488`aa562523 4c8be8          mov     r13,rax
ffff8488`aa562526 493bf7          cmp     rsi,r15
ffff8488`aa562529 0f854e040000    jne     ffff8488`aa56297d  Branch

ffff8488`aa56252f 4d85e4          test    r12,r12
ffff8488`aa562532 0f8445040000    je      ffff8488`aa56297d  Branch

ffff8488`aa562538 41813c2401010000 cmp     dword ptr [r12],101h
ffff8488`aa562540 0f8537040000    jne     ffff8488`aa56297d  Branch

ffff8488`aa562546 488b4b10        mov     rcx,qword ptr [rbx+10h]
ffff8488`aa56254a 4885c9          test    rcx,rcx
ffff8488`aa56254d 0f85cb000000    jne     ffff8488`aa56261e  Branch

ffff8488`aa562553 488bce          mov     rcx,rsi
ffff8488`aa562556 ff5358          call    qword ptr [rbx+58h]
ffff8488`aa562559 4885c0          test    rax,rax
ffff8488`aa56255c 0f841b040000    je      ffff8488`aa56297d  Branch

ffff8488`aa562562 4805000f0000    add     rax,0F00h
ffff8488`aa562568 488d4d6f        lea     rcx,[rbp+6Fh]
ffff8488`aa56256c 48894c2430      mov     qword ptr [rsp+30h],rcx
ffff8488`aa562571 4c8d4d97        lea     r9,[rbp-69h]
ffff8488`aa562575 0f57c0          xorps   xmm0,xmm0
ffff8488`aa562578 40887c2428      mov     byte ptr [rsp+28h],dil
ffff8488`aa56257d 488bce          mov     rcx,rsi
ffff8488`aa562580 48c744242010000000 mov   qword ptr [rsp+20h],10h
ffff8488`aa562589 4d8bc5          mov     r8,r13
ffff8488`aa56258c 48894577        mov     qword ptr [rbp+77h],rax
ffff8488`aa562590 488bd0          mov     rdx,rax
ffff8488`aa562593 0f114597        movups  xmmword ptr [rbp-69h],xmm0
ffff8488`aa562597 ff5370          call    qword ptr [rbx+70h]
ffff8488`aa56259a 85c0            test    eax,eax
ffff8488`aa56259c 0f88db030000    js      ffff8488`aa56297d  Branch

ffff8488`aa5625a2 48b800b9dcfeefcdab60 mov rax,60ABCDEFFEDCB900h
ffff8488`aa5625ac 48394597        cmp     qword ptr [rbp-69h],rax
ffff8488`aa5625b0 0f85c7030000    jne     ffff8488`aa56297d  Branch

ffff8488`aa5625b6 488b4d9f        mov     rcx,qword ptr [rbp-61h]
ffff8488`aa5625ba 49be0000fdffff7f0000 mov r14,7FFFFFFD0000h
ffff8488`aa5625c4 488d810000ffff  lea     rax,[rcx-10000h]
ffff8488`aa5625cb 493bc6          cmp     rax,r14
ffff8488`aa5625ce 0f87a5030000    ja      ffff8488`aa562979  Branch

ffff8488`aa5625d4 48894b18        mov     qword ptr [rbx+18h],rcx
ffff8488`aa5625d8 488bce          mov     rcx,rsi
ffff8488`aa5625db 48897310        mov     qword ptr [rbx+10h],rsi
ffff8488`aa5625df ff9380000000    call    qword ptr [rbx+80h]
ffff8488`aa5625e5 4c8b4d77        mov     r9,qword ptr [rbp+77h]
ffff8488`aa5625e9 488d456f        lea     rax,[rbp+6Fh]
ffff8488`aa5625ed 4889442430      mov     qword ptr [rsp+30h],rax
ffff8488`aa5625f2 488d5597        lea     rdx,[rbp-69h]
ffff8488`aa5625f6 0f57c0          xorps   xmm0,xmm0
ffff8488`aa5625f9 40887c2428      mov     byte ptr [rsp+28h],dil
ffff8488`aa5625fe 4c8bc6          mov     r8,rsi
ffff8488`aa562601 48c744242010000000 mov   qword ptr [rsp+20h],10h
ffff8488`aa56260a 498bcd          mov     rcx,r13
ffff8488`aa56260d 0f114597        movups  xmmword ptr [rbp-69h],xmm0
ffff8488`aa562611 ff5370          call    qword ptr [rbx+70h]

ffff8488`aa562614 b8010000c0      mov     eax,0C0000001h
ffff8488`aa562619 e9c1030000      jmp     ffff8488`aa5629df  Branch

ffff8488`aa56261e 483bf1          cmp     rsi,rcx
ffff8488`aa562621 0f8556030000    jne     ffff8488`aa56297d  Branch

ffff8488`aa562627 488b5318        mov     rdx,qword ptr [rbx+18h]
ffff8488`aa56262b 488d456f        lea     rax,[rbp+6Fh]
ffff8488`aa56262f 4889442430      mov     qword ptr [rsp+30h],rax
ffff8488`aa562634 4c8d4c2448      lea     r9,[rsp+48h]
ffff8488`aa562639 0f57c0          xorps   xmm0,xmm0
ffff8488`aa56263c 40887c2428      mov     byte ptr [rsp+28h],dil
ffff8488`aa562641 41bf20000000    mov     r15d,20h
ffff8488`aa562647 4d8bc5          mov     r8,r13
ffff8488`aa56264a 4c897c2420      mov     qword ptr [rsp+20h],r15
ffff8488`aa56264f 0f11442448      movups  xmmword ptr [rsp+48h],xmm0
ffff8488`aa562654 0f114587        movups  xmmword ptr [rbp-79h],xmm0
ffff8488`aa562658 ff5370          call    qword ptr [rbx+70h]
ffff8488`aa56265b 85c0            test    eax,eax
ffff8488`aa56265d 78b5            js      ffff8488`aa562614  Branch

ffff8488`aa56265f 8b442448        mov     eax,dword ptr [rsp+48h]
ffff8488`aa562663 2500ffffff      and     eax,0FFFFFF00h
ffff8488`aa562668 3d00b9dcfe      cmp     eax,0FEDCB900h
ffff8488`aa56266d 75a5            jne     ffff8488`aa562614  Branch

ffff8488`aa56266f 397c244c        cmp     dword ptr [rsp+4Ch],edi
ffff8488`aa562673 749f            je      ffff8488`aa562614  Branch

ffff8488`aa562675 397d8f          cmp     dword ptr [rbp-71h],edi
ffff8488`aa562678 749a            je      ffff8488`aa562614  Branch

ffff8488`aa56267a 488b4587        mov     rax,qword ptr [rbp-79h]
ffff8488`aa56267e 49be0000fdffff7f0000 mov r14,7FFFFFFD0000h
ffff8488`aa562688 48050000ffff    add     rax,0FFFFFFFFFFFF0000h
ffff8488`aa56268e 493bc6          cmp     rax,r14
ffff8488`aa562691 7781            ja      ffff8488`aa562614  Branch

ffff8488`aa562693 8b4c244c        mov     ecx,dword ptr [rsp+4Ch]
ffff8488`aa562697 488d5577        lea     rdx,[rbp+77h]
ffff8488`aa56269b 48897d77        mov     qword ptr [rbp+77h],rdi
ffff8488`aa56269f ff5378          call    qword ptr [rbx+78h]
ffff8488`aa5626a2 85c0            test    eax,eax
ffff8488`aa5626a4 0f886affffff    js      ffff8488`aa562614  Branch

ffff8488`aa5626aa 8b442448        mov     eax,dword ptr [rsp+48h]
ffff8488`aa5626ae 3d01b9dcfe      cmp     eax,0FEDCB901h
ffff8488`aa5626b3 0f843f020000    je      ffff8488`aa5628f8  Branch

ffff8488`aa5626b9 3d02b9dcfe      cmp     eax,0FEDCB902h
ffff8488`aa5626be 0f84fd010000    je      ffff8488`aa5628c1  Branch

ffff8488`aa5626c4 3d03b9dcfe      cmp     eax,0FEDCB903h
ffff8488`aa5626c9 0f84b3010000    je      ffff8488`aa562882  Branch

ffff8488`aa5626cf 3d04b9dcfe      cmp     eax,0FEDCB904h
ffff8488`aa5626d4 0f842b010000    je      ffff8488`aa562805  Branch

ffff8488`aa5626da 3d05b9dcfe      cmp     eax,0FEDCB905h
ffff8488`aa5626df 0f84d2000000    je      ffff8488`aa5627b7  Branch

ffff8488`aa5626e5 3d06b9dcfe      cmp     eax,0FEDCB906h
ffff8488`aa5626ea 0f8492000000    je      ffff8488`aa562782  Branch

ffff8488`aa5626f0 3d07b9dcfe      cmp     eax,0FEDCB907h
ffff8488`aa5626f5 0f8539020000    jne     ffff8488`aa562934  Branch

ffff8488`aa5626fb 488b4d77        mov     rcx,qword ptr [rbp+77h]
ffff8488`aa5626ff 488d55d7        lea     rdx,[rbp-29h]
ffff8488`aa562703 0f57c0          xorps   xmm0,xmm0
ffff8488`aa562706 0f1145d7        movups  xmmword ptr [rbp-29h],xmm0
ffff8488`aa56270a 0f1145e7        movups  xmmword ptr [rbp-19h],xmm0
ffff8488`aa56270e 0f1145f7        movups  xmmword ptr [rbp-9],xmm0
ffff8488`aa562712 ff5338          call    qword ptr [rbx+38h]
ffff8488`aa562715 488b542450      mov     rdx,qword ptr [rsp+50h]
ffff8488`aa56271a 488d442440      lea     rax,[rsp+40h]
ffff8488`aa56271f 0f57c0          xorps   xmm0,xmm0
ffff8488`aa562722 4889442428      mov     qword ptr [rsp+28h],rax
ffff8488`aa562727 458d7710        lea     r14d,[r15+10h]
ffff8488`aa56272b 48897c2440      mov     qword ptr [rsp+40h],rdi
ffff8488`aa562730 4c8d4da7        lea     r9,[rbp-59h]
ffff8488`aa562734 4c89742420      mov     qword ptr [rsp+20h],r14
ffff8488`aa562739 4533c0          xor     r8d,r8d
ffff8488`aa56273c 4883c9ff        or      rcx,0FFFFFFFFFFFFFFFFh
ffff8488`aa562740 0f1145a7        movups  xmmword ptr [rbp-59h],xmm0
ffff8488`aa562744 0f1145b7        movups  xmmword ptr [rbp-49h],xmm0
ffff8488`aa562748 0f1145c7        movups  xmmword ptr [rbp-39h],xmm0
ffff8488`aa56274c ff93a0000000    call    qword ptr [rbx+0A0h]
ffff8488`aa562752 488d4dd7        lea     rcx,[rbp-29h]
ffff8488`aa562756 8bf0            mov     esi,eax
ffff8488`aa562758 ff5340          call    qword ptr [rbx+40h]
ffff8488`aa56275b 85f6            test    esi,esi
ffff8488`aa56275d 0f88dd010000    js      ffff8488`aa562940  Branch

ffff8488`aa562763 488d456f        lea     rax,[rbp+6Fh]
ffff8488`aa562767 4889442430      mov     qword ptr [rsp+30h],rax
ffff8488`aa56276c 488d55a7        lea     rdx,[rbp-59h]
ffff8488`aa562770 40887c2428      mov     byte ptr [rsp+28h],dil
ffff8488`aa562775 4c89742420      mov     qword ptr [rsp+20h],r14

ffff8488`aa56277a 498bcd          mov     rcx,r13
ffff8488`aa56277d e9a1010000      jmp     ffff8488`aa562923  Branch

ffff8488`aa562782 837d8f18        cmp     dword ptr [rbp-71h],18h
ffff8488`aa562786 0f8565010000    jne     ffff8488`aa5628f1  Branch

ffff8488`aa56278c 488d456f        lea     rax,[rbp+6Fh]
ffff8488`aa562790 4d8bc5          mov     r8,r13
ffff8488`aa562793 4889442430      mov     qword ptr [rsp+30h],rax
ffff8488`aa562798 4c8d4b20        lea     r9,[rbx+20h]
ffff8488`aa56279c 40887c2428      mov     byte ptr [rsp+28h],dil
ffff8488`aa5627a1 48c744242018000000 mov   qword ptr [rsp+20h],18h

ffff8488`aa5627aa 488b5587        mov     rdx,qword ptr [rbp-79h]
ffff8488`aa5627ae 488b4b10        mov     rcx,qword ptr [rbx+10h]
ffff8488`aa5627b2 e974010000      jmp     ffff8488`aa56292b  Branch

ffff8488`aa5627b7 488b4d77        mov     rcx,qword ptr [rbp+77h]
ffff8488`aa5627bb 488d55a7        lea     rdx,[rbp-59h]
ffff8488`aa5627bf 0f57c0          xorps   xmm0,xmm0
ffff8488`aa5627c2 0f1145a7        movups  xmmword ptr [rbp-59h],xmm0
ffff8488`aa5627c6 0f1145b7        movups  xmmword ptr [rbp-49h],xmm0
ffff8488`aa5627ca 0f1145c7        movups  xmmword ptr [rbp-39h],xmm0
ffff8488`aa5627ce ff5338          call    qword ptr [rbx+38h]
ffff8488`aa5627d1 488b4587        mov     rax,qword ptr [rbp-79h]
ffff8488`aa5627d5 4c8d442440      lea     r8,[rsp+40h]
ffff8488`aa5627da 41b900800000    mov     r9d,8000h
ffff8488`aa5627e0 48894597        mov     qword ptr [rbp-69h],rax
ffff8488`aa5627e4 488d5597        lea     rdx,[rbp-69h]
ffff8488`aa5627e8 48897c2440      mov     qword ptr [rsp+40h],rdi
ffff8488`aa5627ed 4883c9ff        or      rcx,0FFFFFFFFFFFFFFFFh
ffff8488`aa5627f1 ff9398000000    call    qword ptr [rbx+98h]
ffff8488`aa5627f7 488d4da7        lea     rcx,[rbp-59h]
ffff8488`aa5627fb 8bf0            mov     esi,eax
ffff8488`aa5627fd ff5340          call    qword ptr [rbx+40h]
ffff8488`aa562800 e92b010000      jmp     ffff8488`aa562930  Branch

ffff8488`aa562805 488b4d77        mov     rcx,qword ptr [rbp+77h]
ffff8488`aa562809 488d55a7        lea     rdx,[rbp-59h]
ffff8488`aa56280d 0f57c0          xorps   xmm0,xmm0
ffff8488`aa562810 0f1145a7        movups  xmmword ptr [rbp-59h],xmm0
ffff8488`aa562814 0f1145b7        movups  xmmword ptr [rbp-49h],xmm0
ffff8488`aa562818 0f1145c7        movups  xmmword ptr [rbp-39h],xmm0
ffff8488`aa56281c ff5338          call    qword ptr [rbx+38h]
ffff8488`aa56281f 8b458f          mov     eax,dword ptr [rbp-71h]
ffff8488`aa562822 4c8d4d97        lea     r9,[rbp-69h]
ffff8488`aa562826 48894597        mov     qword ptr [rbp-69h],rax
ffff8488`aa56282a 488d542440      lea     rdx,[rsp+40h]
ffff8488`aa56282f 8b4593          mov     eax,dword ptr [rbp-6Dh]
ffff8488`aa562832 4533c0          xor     r8d,r8d
ffff8488`aa562835 89442428        mov     dword ptr [rsp+28h],eax
ffff8488`aa562839 4883c9ff        or      rcx,0FFFFFFFFFFFFFFFFh
ffff8488`aa56283d c744242000301000 mov     dword ptr [rsp+20h],103000h
ffff8488`aa562845 48897c2440      mov     qword ptr [rsp+40h],rdi
ffff8488`aa56284a ff9390000000    call    qword ptr [rbx+90h]
ffff8488`aa562850 488d4da7        lea     rcx,[rbp-59h]
ffff8488`aa562854 8bf0            mov     esi,eax
ffff8488`aa562856 ff5340          call    qword ptr [rbx+40h]
ffff8488`aa562859 85f6            test    esi,esi
ffff8488`aa56285b 0f88df000000    js      ffff8488`aa562940  Branch

ffff8488`aa562861 488d456f        lea     rax,[rbp+6Fh]
ffff8488`aa562865 4889442430      mov     qword ptr [rsp+30h],rax
ffff8488`aa56286a 488d542440      lea     rdx,[rsp+40h]
ffff8488`aa56286f 40887c2428      mov     byte ptr [rsp+28h],dil
ffff8488`aa562874 48c744242008000000 mov   qword ptr [rsp+20h],8
ffff8488`aa56287d e9f8feffff      jmp     ffff8488`aa56277a  Branch

ffff8488`aa562882 837d8f08        cmp     dword ptr [rbp-71h],8
ffff8488`aa562886 488b4d77        mov     rcx,qword ptr [rbp+77h]
ffff8488`aa56288a 7505            jne     ffff8488`aa562891  Branch

ffff8488`aa56288c ff5358          call    qword ptr [rbx+58h]
ffff8488`aa56288f eb03            jmp     ffff8488`aa562894  Branch

ffff8488`aa562891 ff5360          call    qword ptr [rbx+60h]

ffff8488`aa562894 48894597        mov     qword ptr [rbp-69h],rax
ffff8488`aa562898 4885c0          test    rax,rax
ffff8488`aa56289b 0f8493000000    je      ffff8488`aa562934  Branch

ffff8488`aa5628a1 488d456f        lea     rax,[rbp+6Fh]
ffff8488`aa5628a5 4889442430      mov     qword ptr [rsp+30h],rax
ffff8488`aa5628aa 488d5597        lea     rdx,[rbp-69h]
ffff8488`aa5628ae 40887c2428      mov     byte ptr [rsp+28h],dil
ffff8488`aa5628b3 48c744242008000000 mov   qword ptr [rsp+20h],8
ffff8488`aa5628bc e9b9feffff      jmp     ffff8488`aa56277a  Branch

ffff8488`aa5628c1 4c8b4c2450      mov     r9,qword ptr [rsp+50h]
ffff8488`aa5628c6 498d810000ffff  lea     rax,[r9-10000h]
ffff8488`aa5628cd 493bc6          cmp     rax,r14
ffff8488`aa5628d0 771f            ja      ffff8488`aa5628f1  Branch

ffff8488`aa5628d2 8b458f          mov     eax,dword ptr [rbp-71h]
ffff8488`aa5628d5 488d4d6f        lea     rcx,[rbp+6Fh]
ffff8488`aa5628d9 4c8b4577        mov     r8,qword ptr [rbp+77h]
ffff8488`aa5628dd 48894c2430      mov     qword ptr [rsp+30h],rcx
ffff8488`aa5628e2 c644242801      mov     byte ptr [rsp+28h],1
ffff8488`aa5628e7 4889442420      mov     qword ptr [rsp+20h],rax
ffff8488`aa5628ec e9b9feffff      jmp     ffff8488`aa5627aa  Branch

ffff8488`aa5628f1 be010000c0      mov     esi,0C0000001h
ffff8488`aa5628f6 eb38            jmp     ffff8488`aa562930  Branch

ffff8488`aa5628f8 488b542450      mov     rdx,qword ptr [rsp+50h]
ffff8488`aa5628fd 488d820000ffff  lea     rax,[rdx-10000h]
ffff8488`aa562904 493bc6          cmp     rax,r14
ffff8488`aa562907 7732            ja      ffff8488`aa56293b  Branch

ffff8488`aa562909 8b458f          mov     eax,dword ptr [rbp-71h]
ffff8488`aa56290c 488d4d6f        lea     rcx,[rbp+6Fh]
ffff8488`aa562910 48894c2430      mov     qword ptr [rsp+30h],rcx
ffff8488`aa562915 488b4d77        mov     rcx,qword ptr [rbp+77h]
ffff8488`aa562919 c644242801      mov     byte ptr [rsp+28h],1
ffff8488`aa56291e 4889442420      mov     qword ptr [rsp+20h],rax

ffff8488`aa562923 4c8b4d87        mov     r9,qword ptr [rbp-79h]
ffff8488`aa562927 4c8b4310        mov     r8,qword ptr [rbx+10h]

ffff8488`aa56292b ff5370          call    qword ptr [rbx+70h]
ffff8488`aa56292e 8bf0            mov     esi,eax

ffff8488`aa562930 85f6            test    esi,esi
ffff8488`aa562932 780c            js      ffff8488`aa562940  Branch

ffff8488`aa562934 be01000000      mov     esi,1
ffff8488`aa562939 eb05            jmp     ffff8488`aa562940  Branch

ffff8488`aa56293b be010000c0      mov     esi,0C0000001h

ffff8488`aa562940 4c8b4b18        mov     r9,qword ptr [rbx+18h]
ffff8488`aa562944 488d456f        lea     rax,[rbp+6Fh]
ffff8488`aa562948 4c8b4310        mov     r8,qword ptr [rbx+10h]
ffff8488`aa56294c 488d542448      lea     rdx,[rsp+48h]
ffff8488`aa562951 4889442430      mov     qword ptr [rsp+30h],rax
ffff8488`aa562956 498bcd          mov     rcx,r13
ffff8488`aa562959 40887c2428      mov     byte ptr [rsp+28h],dil
ffff8488`aa56295e 4c897c2420      mov     qword ptr [rsp+20h],r15
ffff8488`aa562963 89742448        mov     dword ptr [rsp+48h],esi
ffff8488`aa562967 ff5370          call    qword ptr [rbx+70h]
ffff8488`aa56296a 488b4d77        mov     rcx,qword ptr [rbp+77h]
ffff8488`aa56296e ff9388000000    call    qword ptr [rbx+88h]
ffff8488`aa562974 e99bfcffff      jmp     ffff8488`aa562614  Branch

ffff8488`aa562979 448b755f        mov     r14d,dword ptr [rbp+5Fh]

ffff8488`aa56297d 488b4b10        mov     rcx,qword ptr [rbx+10h]
ffff8488`aa562981 4885c9          test    rcx,rcx
ffff8488`aa562984 7418            je      ffff8488`aa56299e  Branch

ffff8488`aa562986 ff5368          call    qword ptr [rbx+68h]
ffff8488`aa562989 3d03010000      cmp     eax,103h
ffff8488`aa56298e 740e            je      ffff8488`aa56299e  Branch

ffff8488`aa562990 488b4b10        mov     rcx,qword ptr [rbx+10h]
ffff8488`aa562994 ff9388000000    call    qword ptr [rbx+88h]
ffff8488`aa56299a 48897b10        mov     qword ptr [rbx+10h],rdi

ffff8488`aa56299e 493bf7          cmp     rsi,r15
ffff8488`aa5629a1 7428            je      ffff8488`aa5629cb  Branch

ffff8488`aa5629a3 4585f6          test    r14d,r14d
ffff8488`aa5629a6 7423            je      ffff8488`aa5629cb  Branch

ffff8488`aa5629a8 498bcf          mov     rcx,r15
ffff8488`aa5629ab ff5350          call    qword ptr [rbx+50h]
ffff8488`aa5629ae 4885c0          test    rax,rax
ffff8488`aa5629b1 7418            je      ffff8488`aa5629cb  Branch

ffff8488`aa5629b3 488d4b20        lea     rcx,[rbx+20h]

ffff8488`aa5629b7 483901          cmp     qword ptr [rcx],rax
ffff8488`aa5629ba 0f8454fcffff    je      ffff8488`aa562614  Branch

ffff8488`aa5629c0 ffc7            inc     edi
ffff8488`aa5629c2 4883c108        add     rcx,8
ffff8488`aa5629c6 83ff03          cmp     edi,3
ffff8488`aa5629c9 72ec            jb      ffff8488`aa5629b7  Branch

ffff8488`aa5629cb 8b5567          mov     edx,dword ptr [rbp+67h]
ffff8488`aa5629ce 4d8bcf          mov     r9,r15
ffff8488`aa5629d1 4c8bc6          mov     r8,rsi
ffff8488`aa5629d4 4c89642420      mov     qword ptr [rsp+20h],r12
ffff8488`aa5629d9 418bce          mov     ecx,r14d
ffff8488`aa5629dc ff5308          call    qword ptr [rbx+8]

ffff8488`aa5629df 4881c4e8000000  add     rsp,0E8h
ffff8488`aa5629e6 415f            pop     r15
ffff8488`aa5629e8 415e            pop     r14
ffff8488`aa5629ea 415d            pop     r13
ffff8488`aa5629ec 415c            pop     r12
ffff8488`aa5629ee 5f              pop     rdi
ffff8488`aa5629ef 5e              pop     rsi
ffff8488`aa5629f0 5b              pop     rbx
ffff8488`aa5629f1 5d              pop     rbp
ffff8488`aa5629f2 c3              ret

DataTable

다음과 같은 데이터 테이블을 NonPagedPool 영역에 할당하여 사용합니다. 보호 대상 목록, 서브 프로세스, 원본 함수 등 다양한 정보들이 포함되어 있습니다.

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
typedef struct _MUXUE_hookTable
{
    PVOID           hookTableAddr;                     // 현재 테이블의 주소
    PVOID           fpPspProcessOpen;                  // PspProcessOpen 원본 주소
    PEPROCESS       subProcess;                        // 서브 프로세스 (통신 프로세스)
    PVOID           virtualAddr;                       // 통신 버퍼 (가상 메모리 주소)
    HANDLE          processId[PROTECTION_COUNT];       // 보호 대상 프로세스 ID

    // 후킹 코드에서 사용하는 함수는 전부 아래의 테이블을 통해 호출함.
    struct _MUXUE_FUNCTION_TABLE
    {
        PVOID fpKeStackAttachProcess;             // KeStackAttachProcess    
        PVOID fpKeUnstackDetachProcess;           // KeUnstackDetachProcess;
        PVOID fpPsGetCurrentProcess;              // PsGetCurrentProcess
        PVOID fpPsGetProcessId;                   // PsGetProcessId
        PVOID fpPsGetProcessPeb;                  // PsGetProcessPeb
        PVOID fpPsGetProcessWow64Process;         // PsGetProcessWow64Process
        PVOID fpPsGetProcessExitStatus;           // PsGetProcessExitStatus
        PVOID fpMmCopyVirtualMemory;              // MmCopyVirtualMemory
        PVOID fpPsLookupProcessByProcessId;       // PsLookupProcessByProcessId
        PVOID fpObfReferenceObject;               // ObfReferenceObject
        PVOID fpHalPutDmaAdapter;                 // HalPutDmaAdapter
        PVOID fpZwAllocateVirtualMemory;          // ZwAllocateVirtualMemory
        PVOID fpZwFreeVirtualMemory;              // ZwFreeVirtualMemory
        PVOID fpZwQueryVirtualMemory;             // ZwQueryVirtualMemory
    }ntCall;

}MUXUE_hookTable, *PMUXUE_hookTable;

Protocol

후킹된 함수를 통해 유저 레벨 애플리케이션과 통신합니다. PEB 영역을 입출력 버퍼로 사용합니다.

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
typedef enum _MUXUE_IO_COMMAND : DWORD32
{
    MUXUE_IO_COMMAND_NULL     = 0xFEDCB900,
    MUXUE_IO_COMMAND_1        = 0xFEDCB901,
    MUXUE_IO_COMMAND_2        = 0xFEDCB902,
    MUXUE_IO_COMMAND_3        = 0xFEDCB903,
    MUXUE_IO_COMMAND_4        = 0xFEDCB904,
    MUXUE_IO_COMMAND_5        = 0xFEDCB905,
    MUXUE_IO_COMMAND_6        = 0xFEDCB906,
    MUXUE_IO_COMMAND_7        = 0xFEDCB907,
    MUXUE_IO_COMMAND_8        = 0xFEDCB908,
}MUXUE_IO_COMMAND;

// Device I/O
if (hookTable->ntCall.fpMmCopyVirtualMemory(hookTable->subProcess, hookTable->virtualAddr, current_process, &io_buffer, 0x20, 0, &return_size) < 0)
    return STATUS_UNSUCCESSFUL;

switch ((_DWORD)io_buffer)
{
    case MUXUE_IO_COMMAND_3: ...
    case MUXUE_IO_COMMAND_4: ...
    case MUXUE_IO_COMMAND_5: ...
    case MUXUE_IO_COMMAND_6: ...
....
}

SubProcess

특정 프로세스를 서브 프로세스로 전환합니다. 전환되면 보호 대상 목록에 추가되며, PEB 영역을 통해 커널 영역과 통신합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    // 서브 프로세스 지정
    PPEB peb = hookTable->ntCall.fpPsGetProcessPeb(process);
    if (peb)
    {
        dwm_process = peb + 0xF00;
        dwm_peb_ = 0;
        if (hookTable->ntCall.fpMmCopyVirtualMemory(process, peb + 0xF00, current_process, &dwm_peb_, 16, 0, &return_size) >= 0 &&
            (_QWORD)dwm_peb_ == 0x60ABCDEFFEDCB900)
        {
            if ((unsigned __int64)(*((_QWORD*)&dwm_peb_ + 1) - 0x10000) <= 0x7FFFFFFD0000)
            {
                hookTable->virtualAddr    = *((_QWORD*)&dwm_peb_ + 1);
                hookTable->subProcess    = process;
                hookTable->ntCall.fpObfReferenceObject(process);
                LOBYTE(v28) = 0;
                dwm_peb_ = 0;

                // 입력 버퍼 정리
                hookTable->ntCall.MmCopyVirtualMemory(current_process, &dwm_peb_, process, dwm_process, 16, v28, &return_size);
                return STATUS_UNSUCCESSFUL;
            }
        }
    }

OpenProcedure

PspProcessOpen을 후킹하여 실행되는 코드입니다. 다른 프로세스에서 보호 프로세스에 접근하면 STATUS_UNSUCCESSFUL을 반환하고, 아닌 경우에 원본 함수를 호출합니다. 해킹툴 프로세스를 OpenProcess 시도했을 때 실패한 이유입니다.

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
NTSTATUS PspProcessOpen_Hook(OB_OPEN_REASON OpenReason, BYTE AccessMode, PEPROCESS process, PVOID Object, ACCESS_MASK* GrantedAccess, ULONG HandleCount)
{
...
    if (process != Object)
    {
        if (OpenReason != ObCreateHandle)
        {
            HANDLE processId = hookTable->ntCall.fpPsGetProcessId(Object);

            if (processId)
            {
                //
                // 접근하려는 프로세스가 보호 대상이면 실패를 반환함.
                // OpenProcess가 실패하는 이유..
                // 
                // [보호 프로세스 목록]
                // 1. 서브 프로세스
                // 2. DWM
                // 

                for (int i = 0; i < PROTECTION_COUNT; ++i)
                {
                    if (hookTable->processId[i] == processId)
                    {
                        return STATUS_UNSUCCESSFUL;
                    }
                }

                return hookTable->ntCall.fpPspProcessOpen(OpenReason, AccessMode, process, Object, GrantedAccess, HandleCount);
            }
        }
    }

    return hookTable->ntCall.fpPspProcessOpen(OpenReason, AccessMode, process, Object, GrantedAccess, HandleCount);
}

Windbg Script

덤프 분석 시 활용할 수 있는 스크립트를 개발하였습니다. Export 변수인 PsProcessType를 참조하여 OpenProcedure(PspProcessOpen)이 후킹되어있는지 검사합니다. 해당 코드는 GitHub에도 업로드되어 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$$ OpenProcedure 후킹 체크
$$ 작성 버전 : Windows 10 Kernel Version 19041 MP (4 procs) Free x64 
$$ 사용 방법 : CheckOpenProcedure
$$ 작성일 : 2022-03-16
$$ 작성자 : wlsgjd

r $t0 = poi(nt!PsProcessType)

$$ object_type->TypeInfo->OpenProcedure
r $t1 = poi(@$t0 + 0x78)

.if (@$t1 != nt!PspProcessOpen)
{
	.printf "hooked openprocedure.\n"
    dqs (@$t0 + 0x78) L? 3
	.printf "\n"
	u @$t1
}
.else
{
	.printf "clean openprocedure.\n"
}

사용 방법은 다음과 같습니다. 후킹된 경우에는 변조된 위치와 호출되는 함수 코드를 출력합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
5: kd> $$>< C:\git\Windbg Scripts\CheckOpenProcedure
hooked openprocedure.
ffffd808`35165b48  fffff803`4f9e3f68
ffffd808`35165b50  fffff803`324c4e00 nt!PspProcessClose
ffffd808`35165b58  fffff803`3245f840 nt!PspProcessDelete

fffff803`4f9e3f68 e9e1001500      jmp     fffff803`4fb3404e
fffff803`4f9e3f6d cc              int     3
fffff803`4f9e3f6e cc              int     3
fffff803`4f9e3f6f cc              int     3
fffff803`4f9e3f70 cc              int     3
fffff803`4f9e3f71 cc              int     3
fffff803`4f9e3f72 cc              int     3
fffff803`4f9e3f73 cc              int     3

후킹되지 않은 경우엔 다음과 같이 클린 메세지를 출력합니다.

1
2
2: kd> $$>< C:\git\Windbg Scripts\CheckOpenProcedure
clean openprocedure.

POC Code

분석한 내용을 바탕으로 해킹툴과 동일하게 동작하는 코드를 개발하였습니다. 전체 소스코드는 GitHub에 업로드 하였습니다.

후킹 코드는 드라이버가 언로드 되어도 동작해야 하기 때문에 다음과 같이 NonPagedPool 영역에 복사하였습니다.

1
2
OB_OPEN_METHOD fpMyPspProcessOpen = ExAllocatePool(NonPagedPool, HOOK_FUNC_SIZE);
RtlCopyMemory(fpMyPspProcessOpen, MyPspProcessOpen, HOOK_FUNC_SIZE);

또한, 원본 함수 및 보호 대상을 포함하고 있는 데이터 테이블을 NonPagedPool 영역에 생성하였습니다. 해당 메모리 구조는 해킹툴과 동일하게 제작하였습니다.

1
2
3
4
5
6
7
typedef struct _MY_HOOK_TABLE MY_HOOK_TABLE, * PMY_HOOK_TABLE;
typedef struct _MY_HOOK_TABLE
{
	MY_HOOK_TABLE*	this_ptr;
	HANDLE			dwm_pid;
	OB_OPEN_METHOD	old_OpenProcedure;
} MY_HOOK_TABLE, * PMY_HOOK_TABLE;
1
2
3
4
PMY_HOOK_TABLE hook_table = ExAllocatePool(NonPagedPool, sizeof(MY_HOOK_TABLE));
hook_table->this_ptr = hook_table;
hook_table->old_OpenProcedure = processType->TypeInfo.OpenProcedure;
hook_table->dwm_pid = GetProcessId(eprocess);

그리고, 시그니처 형태의 정적 주소를 NonPagedPool 영역에 할당한 메모리 주소로 교체합니다. 이렇게 되면 드라이버가 언로드 되어도 새로 할당된 NonPagedPool 메모리 영역을 참조하여 실행하게 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#define HOOK_TABLE_SIG		(ULONG64)0x123456789
#define THIS_PTR(p)			p->this_ptr

#define GET_PROCESS_ID(p)	(*(ULONG64*)((BYTE*)p + 0x440))				// EPROCESS->UniqueProcessId

static NTSTATUS MyPspProcessOpen(OB_OPEN_REASON OpenReason, BYTE AccessMode, PEPROCESS Process, PVOID Object, ACCESS_MASK GrantedAccess, ULONG HandleCount)
{
	PMY_HOOK_TABLE hook_table = HOOK_TABLE_SIG;

	if (Process != Object)
	{
		if (OpenReason != ObCreateHandle)
		{
			if (GET_PROCESS_ID(Object) == THIS_PTR(hook_table)->dwm_pid)
			{
				return STATUS_UNSUCCESSFUL;
			}
		}
	}

	// Disabled cfg(Control Flow Guard)
	return THIS_PTR(hook_table)->old_OpenProcedure(OpenReason, AccessMode, Process, Object, GrantedAccess, HandleCount);
};
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
PVOID SearchHookSignature64(PVOID addr, ULONG64 sig, SIZE_T size)
{
	SIZE_T max_size = size - sizeof(ULONG64);

	for (int i = 0; i <= max_size; ++i)
	{
		ULONG64* addr64 = (BYTE*)addr + i;
		if (*addr64 == sig)
			return addr64;
	}

	return 0;
};

int PatchHookTableAddress64(PVOID HookFunc, ULONG64 sig, PMY_HOOK_TABLE HookTable, SIZE_T Size)
{
	int result = 0;

	while (1)
	{
		PULONG64 my_sig = SearchHookSignature64(HookFunc, HOOK_TABLE_SIG, Size);

		if (my_sig)
		{
			*my_sig = HookTable;
			result++;
		}
		else
		{
			break;
		}

	}
	return result;
};
1
2
3
4
5
6
7
8
9
10
OB_OPEN_METHOD fpMyPspProcessOpen = ExAllocatePool(NonPagedPool, HOOK_FUNC_SIZE);
RtlCopyMemory(fpMyPspProcessOpen, MyPspProcessOpen, HOOK_FUNC_SIZE);
if (PatchHookTableAddress64(fpMyPspProcessOpen, HOOK_TABLE_SIG, hook_table, HOOK_FUNC_SIZE) > 0)
{
	processType->TypeInfo.OpenProcedure = fpMyPspProcessOpen;

	DbgPrint("ProcessOpenProcedure : 0x%p => 0x%p\n",
		hook_table->old_OpenProcedure,
		processType->TypeInfo.OpenProcedure);
}

실행 시 다음과 같이 프로세스가 보호되어 OpenProcess가 실패합니다.

CFG (Control Flow Guard)

버퍼 오버플로우와 같은 메모리 취약점을 방지하기 위해 만들어진 보안 기능이며 빌드 옵션 중 하나입니다.

1
2
3
4
5
6
What is Control Flow Guard?
Control Flow Guard (CFG) is a highly-optimized platform security feature that was created to combat memory corruption vulnerabilities. By placing tight restrictions on where an application can execute code from, it makes it much harder for exploits to execute arbitrary code through vulnerabilities such as buffer overflows. CFG extends previous exploit mitigation technologies such as /GS, DEP, and ASLR.

Prevent memory corruption and ransomware attacks.
Restrict the capabilities of the server to whatever is needed at a particular point in time to reduce attack surface.
Make it harder to exploit arbitrary code through vulnerabilities such as buffer overflows.

자세한 내용은 Control Flow Guard for platform security 페이지에서 확인할 수 있습니다.

해당 프로젝트를 빌드하게 되면 원본 프로시저(old_OpenProcedure) 호출 부분에서 포인터 호출이 아닌, gaurd_dispatch_icall_fptr 형태의 함수가 호출되고 있습니다.

이 상태에서 코드를 실행해 보면 BSOD가 발생합니다. 해당 오류는 언로드 된 드라이버 영역을 참조했을 때 발생하는 오류입니다.

자세한 내용은 DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS 페이지에서 확인할 수 있습니다.

덤프를 확인해보면 다음과 같이 정적 메모리 영역이 호출되고 있습니다.

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
6: kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS (ce)
A driver unloaded without cancelling timers, DPCs, worker threads, etc.
The broken driver's name is displayed on the screen and saved in
KiBugCheckDriver.
Arguments:
Arg1: fffff8048d141910, memory referenced
Arg2: 0000000000000010, value 0 = read operation, 1 = write operation
Arg3: fffff8048d141910, If non-zero, the instruction address which referenced the bad memory
	address.
Arg4: 0000000000000000, Mm internal code.

FILE_IN_CAB:  MEMORY.dmp
WRITE_ADDRESS:  fffff8048d141910 
IMAGE_NAME:  HookProcessOpen.sys
MODULE_NAME: HookProcessOpen
PROCESS_NAME:  explorer.exe

TRAP_FRAME:  ffff870919a16eb0 -- (.trap 0xffff870919a16eb0)
NOTE: The trap frame does not contain all registers.
Some register values may be zeroed or incorrect.
rax=fffff80472cb6290 rbx=0000000000000000 rcx=0000000000000001
rdx=0000000000000001 rsi=0000000000000000 rdi=0000000000000000
rip=fffff8048d141910 rsp=ffff870919a17048 rbp=ffff9d01732f2080
 r8=ffff9d01732f2080  r9=ffff9d0173a430c0 r10=0000000000002484
r11=0000000000000001 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0         nv up ei ng nz na po cy
<Unloaded_HookProcessOpen.sys>+0x1910:
fffff804`8d141910 ??              ???
Resetting default scope

IP_MODULE_UNLOADED: 
HookProcessOpen.sys+1910
fffff804`8d141910 ??              ???

STACK_TEXT:  
ffff8709`19a16c08 fffff804`72a4a91f     : 00000000`00000050 fffff804`8d141910 00000000`00000010 ffff8709`19a16eb0 : nt!KeBugCheckEx
ffff8709`19a16c10 fffff804`7289f540     : ffff8709`19a178d8 00000000`00000010 ffff8709`19a16f30 00000000`00000000 : nt!MiSystemFault+0x18d3bf
ffff8709`19a16d10 fffff804`72a0555e     : ffff9d01`7368b080 fffff804`7289cc86 00000000`00000000 00000000`00000000 : nt!MmAccessFault+0x400
ffff8709`19a16eb0 fffff804`8d141910     : ffff9d01`69ff0052 ffff9d01`7368b6d0 fffff804`72807bae ffff9d01`7368b080 : nt!KiPageFault+0x35e
ffff8709`19a17048 ffff9d01`69ff0052     : ffff9d01`7368b6d0 fffff804`72807bae ffff9d01`7368b080 ffff9d01`73a430a0 : <Unloaded_HookProcessOpen.sys>+0x1910
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
// MyPspProcessOpen
6: kd> uf ffff9d01`69ff0000
ffff9d01`69ff0000 4883ec48        sub     rsp,48h
ffff9d01`69ff0004 448bd9          mov     r11d,ecx
ffff9d01`69ff0007 48b9703ffd69019dffff mov rcx,0FFFF9D0169FD3F70h
ffff9d01`69ff0011 4d3bc1          cmp     r8,r9
ffff9d01`69ff0014 741c            je      ffff9d01`69ff0032  Branch

ffff9d01`69ff0016 4585db          test    r11d,r11d
ffff9d01`69ff0019 7417            je      ffff9d01`69ff0032  Branch

ffff9d01`69ff001b 488b01          mov     rax,qword ptr [rcx]
ffff9d01`69ff001e 4c8b5008        mov     r10,qword ptr [rax+8]
ffff9d01`69ff0022 4d399140040000  cmp     qword ptr [r9+440h],r10
ffff9d01`69ff0029 7507            jne     ffff9d01`69ff0032  Branch

ffff9d01`69ff002b b8010000c0      mov     eax,0C0000001h
ffff9d01`69ff0030 eb20            jmp     ffff9d01`69ff0052  Branch

ffff9d01`69ff0032 488b01          mov     rax,qword ptr [rcx]
ffff9d01`69ff0035 8b4c2478        mov     ecx,dword ptr [rsp+78h]
ffff9d01`69ff0039 894c2428        mov     dword ptr [rsp+28h],ecx
ffff9d01`69ff003d 8b4c2470        mov     ecx,dword ptr [rsp+70h]
ffff9d01`69ff0041 488b4010        mov     rax,qword ptr [rax+10h]
ffff9d01`69ff0045 894c2420        mov     dword ptr [rsp+20h],ecx
ffff9d01`69ff0049 418bcb          mov     ecx,r11d
ffff9d01`69ff004c ff15260f0000    call    qword ptr [ffff9d01`69ff0f78] // old_OpenProcedure

ffff9d01`69ff0052 4883c448        add     rsp,48h
ffff9d01`69ff0056 c3              ret

6: kd> dqs ffff9d01`69ff0f78
ffff9d01`69ff0f78  fffff804`8d141910 <Unloaded_HookProcessOpen.sys>+0x1910
ffff9d01`69ff0f80  fffff804`8d141280 <Unloaded_HookProcessOpen.sys>+0x1280
ffff9d01`69ff0f88  fffff804`8d141930 <Unloaded_HookProcessOpen.sys>+0x1930
ffff9d01`69ff0f90  fffff804`8d141930 <Unloaded_HookProcessOpen.sys>+0x1930

해당 문제는 CFG 옵션을 비활성화하면 간단하게 해결됩니다. 해당 기능은 [프로젝트 설정 - C/C++ - 코드 생성] 페이지에서 ‘행 가드 제어’ 옵션을 통해 설정이 가능합니다.

프로젝트 설정 후, Re-Build 하게 되면 다음과 같이 포인터 함수가 의도한대로 호출됩니다.

THIS_PTR

아래에 코드는 눈으로 봤을 때 아무런 문제가 없습니다. 하나의 지역 변수에 정적 메모리 주소를 한번 참조하고, 이를 통해 동작하는 그런 코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static NTSTATUS MyPspProcessOpen(OB_OPEN_REASON OpenReason, BYTE AccessMode, PEPROCESS Process, PVOID Object, ACCESS_MASK GrantedAccess, ULONG HandleCount)
{
	PMY_HOOK_TABLE hook_table = HOOK_TABLE_SIG;

	if (Process != Object)
	{
		if (OpenReason != ObCreateHandle)
		{
			if (GET_PROCESS_ID(Object) == hook_table->dwm_pid)
			{
				return STATUS_UNSUCCESSFUL;
			}
		}
	}

	// Disabled cfg(Control Flow Guard)
	return hook_table->old_OpenProcedure(OpenReason, AccessMode, Process, Object, GrantedAccess, HandleCount);
};

그러나 빌드하여 바이너리를 확인 시, 코드 최적화에 의해 다음과 같이 정적 포인터를 최초 1번이 아닌, 참조 될 때마다(해당 코드에서는 총 2번 실행) 참조하는 것을 확인할 수 있습니다. 이 경우, 시그니처가 전부 패치되지 않아 BSOD가 발생합니다.

그리하여 다음과 같이 내부에서 this_ptr을 참조하도록 코드를 구성하여 최초 1회만 정적 포인터를 참조하고, 이후에는 내부 지역 변수(r11)를 통해 추가로 참조되도록 설계하였습니다.

This post is licensed under CC BY 4.0 by the author.