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
|
0069997D 68 6969728E push 8E726969
00699982 FFB5 DD1C1B07 push dword ptr [ebp+71B1CDD]
00699988 8D85 F2361B07 lea eax, dword ptr [ebp+71B36F2]
0069998E FFD0 call eax ; 获取一系列的需要的函数地址.. 外壳使用的
00699990 8985 7D291B07 mov dword ptr [ebp+71B297D], eax ; kernel32.ExitProcess
00699996 C685 392E1B07 4>mov byte ptr [ebp+71B2E39], 43
0069999D 68 5E6B679C push 9C676B5E
006999A2 FFB5 DD1C1B07 push dword ptr [ebp+71B1CDD]
006999A8 8D85 F2361B07 lea eax, dword ptr [ebp+71B36F2]
006999AE FFD0 call eax
006999B0 8985 A6D32C07 mov dword ptr [ebp+72CD3A6], eax ; kernel32.CreateThread
006999B6 C685 392E1B07 5>mov byte ptr [ebp+71B2E39], 54
006999BD 68 296862EE push EE626829
006999C2 FFB5 DD1C1B07 push dword ptr [ebp+71B1CDD]
006999C8 8D85 F2361B07 lea eax, dword ptr [ebp+71B36F2]
006999CE FFD0 call eax
006999D0 8985 AAD32C07 mov dword ptr [ebp+72CD3AA], eax ; kernel32.TerminateThread
这里是获取外壳所需函数阶段, 大部分都是获取的真实的函数地址. 当然也有一些获取的是重定位内核里面的函数地址, 比如VirtualFree.函数的种类也很丰富, 有打开文件一类的, 查找文件, 复制文件, 还有内存操作的函数.. 函数获取完了就是下面的动作了.
0069A11C 8985 56D42C07 mov dword ptr [ebp+72CD456], eax ; 处理IAT开始了感觉好像是加密
0069A122 6A 04 push 4
0069A124 68 00100000 push 1000
0069A129 68 00100000 push 1000
0069A12E 6A 00 push 0
0069A130 FF95 111C1B07 call dword ptr [ebp+71B1C11] ; VirtualAlloc
0069A136 8985 49041B07 mov dword ptr [ebp+71B0449], eax
0069A13C 8D85 CE9C2C07 lea eax, dword ptr [ebp+72C9CCE]
0069A142 FFD0 call eax
0069A144 6A 04 push 4
0069A146 68 00100000 push 1000
0069A14B 68 00200000 push 2000
0069A150 6A 00 push 0
0069A152 FF95 111C1B07 call dword ptr [ebp+71B1C11] ; VirtualAlloc
0069A158 8985 C90D1B07 mov dword ptr [ebp+71B0DC9], eax
0069A15E 8985 F1151B07 mov dword ptr [ebp+71B15F1], eax
0069A164 6A 40 push 40
0069A166 68 00100000 push 1000
0069A16B 68 00000100 push 10000
0069A170 6A 00 push 0
0069A172 FF95 111C1B07 call dword ptr [ebp+71B1C11] ; VirtualAlloc
0069A178 8985 41201B07 mov dword ptr [ebp+71B2041], eax
这里申请了3块内存, 这3块内存的作用下面有讲到
0069A17E 8BB5 952A1B07 mov esi, dword ptr [ebp+71B2A95] ; 这句代码非常重要esi-->IAT加密表地址
0069A184 8B9D 411D1B07 mov ebx, dword ptr [ebp+71B1D41]
0069A18A 89B5 95211B07 mov dword ptr [ebp+71B2195], esi
0069A190 899D ED0F1B07 mov dword ptr [ebp+71B0FED], ebx ; 这里指向所有DLL的模块基址
0069A196 8B9D 411D1B07 mov ebx, dword ptr [ebp+71B1D41] ; 这里是获取IAT加密表的地址.. 准备开始
处理IAT了
0069A19C 8B0B mov ecx, dword ptr [ebx] ; 取某个DLL 模块基址
0069A19E 83F9 00 cmp ecx, 0
0069A1A1 0F84 690A0000 je delphi7_.0069AC10 ; 输入表处理完成等于0后跳
这里有几个关键的地方. esi-->指向的就是上面加密出来的IAT加密表. ebx-->里面是所有DLL的模块基址. 然后mov ecx, [ebx] 我们可以获取到某个DLL的模块基址, 接着一个一个处理, 直到为0. 处理完毕.
0069A1A9 60 pushad
0069A1AA 33C0 xor eax, eax
0069A1AC 8985 D9091B07 mov dword ptr [ebp+71B09D9], eax
0069A1B2 BE 3C000000 mov esi, 3C
0069A1B7 037424 20 add esi, dword ptr [esp+20]
0069A1BB 66:AD lods word ptr [esi] ; PE头到了
0069A1BD 034424 20 add eax, dword ptr [esp+20]
0069A1C1 8B70 78 mov esi, dword ptr [eax+78] ; 定位到PE的导出表RVA
0069A1C4 037424 20 add esi, dword ptr [esp+20] ; 导出表RVA+模块基址
0069A1C8 8B7E 18 mov edi, dword ptr [esi+18] ; NumberOfFunctions导出函数个数
0069A1CB 89BD 691F1B07 mov dword ptr [ebp+71B1F69], edi ; edi == 导出函数数量
0069A1D1 85FF test edi, edi
这段代码是定位到某个DLL的导出表上面.
0069A1EF 6A 04 push 4
0069A1F1 68 00100000 push 1000
0069A1F6 52 push edx
0069A1F7 6A 00 push 0
0069A1F9 FF95 111C1B07 call dword ptr [ebp+71B1C11] ; 重定位的VirtualAlloc函数
0069A1FF 8985 511A1B07 mov dword ptr [ebp+71B1A51], eax ; 分配到内存
0069A205 8BD0 mov edx, eax
0069A207 59 pop ecx
0069A208 E8 10100000 call delphi7_.0069B21D ; 获取到导出表中的名称函数序号偏移
0069A20D 56 push esi
0069A20E AD lods dword ptr [esi] ; 这是函数的字符串名称
0069A20F 034424 24 add eax, dword ptr [esp+24] ; 到这里就已经得到了函数的真实地址
0069A213 97 xchg eax, edi
0069A214 8BDF mov ebx, edi
0069A216 57 push edi
0069A217 32C0 xor al, al
0069A219 AE scas byte ptr es:[edi] ; 求函数字符串的长度
0069A21A ^ 0F85 F9FFFFFF jnz delphi7_.0069A219
0069A220 5E pop esi
0069A221 2BFB sub edi, ebx
0069A223 52 push edx
0069A224 8BD7 mov edx, edi
0069A226 8BBD 49041B07 mov edi, dword ptr [ebp+71B0449] ; edi = 前面申请的内存,存放解码用的数据表
0069A22C 83C9 FF or ecx, FFFFFFFF
0069A22F 33C0 xor eax, eax
0069A231 8A06 mov al, byte ptr [esi]
0069A233 32C1 xor al, cl
0069A235 46 inc esi ; 查表, 得到解码Key
0069A236 8B0487 mov eax, dword ptr [edi+eax\*4] ; 求字符串的Hash码
0069A239 C1E9 08 shr ecx, 8
0069A23C 33C8 xor ecx, eax
0069A23E 4A dec edx
0069A23F ^ 0F85 EAFFFFFF jnz delphi7_.0069A22F
0069A245 8BC1 mov eax, ecx
0069A247 F7D0 not eax
0069A249 5A pop edx
0069A24A 8902 mov dword ptr [edx], eax ; 上面求出来的的 HASH保存起来
0069A24C 83C2 04 add edx, 4
0069A24F 52 push edx
0069A250 FF85 D9091B07 inc dword ptr [ebp+71B09D9] ; 已Hash的函数个数
0069A256 8B95 D9091B07 mov edx, dword ptr [ebp+71B09D9]
0069A25C 3995 691F1B07 cmp dword ptr [ebp+71B1F69], edx
0069A262 0F84 0A000000 je delphi7_.0069A272
0069A268 5A pop edx
0069A269 5E pop esi
0069A26A 83C6 04 add esi, 4
0069A26D ^ E9 9BFFFFFF jmp delphi7_.0069A20D
0069A272 5A pop edx ; 到这里一个DLL就处理完成了
0069A273 5E pop esi ; 感觉上面是加密IAT组建自己的加密IAT表..
上面这段代码是将函数名称的Hash码都保存起来. 反正就是瞎倒腾, 也不知道倒腾出什么东西来.. 下面我们要修改代码, 但是不是这一段.
0069A2BD 60 pushad
0069A2BE 8DB5 82D42C07 lea esi, dword ptr [ebp+72CD482]
0069A2C4 8DBD 9AEF2C07 lea edi, dword ptr [ebp+72CEF9A]
0069A2CA 2BFE sub edi, esi
0069A2CC 8BD7 mov edx, edi
0069A2CE 8BBD 49041B07 mov edi, dword ptr [ebp+71B0449]
0069A2D4 83C9 FF or ecx, FFFFFFFF
0069A2D7 33C0 xor eax, eax
0069A2D9 8A06 mov al, byte ptr [esi]
0069A2DB 32C1 xor al, cl
0069A2DD 46 inc esi
0069A2DE 8B0487 mov eax, dword ptr [edi+eax\*4]
0069A2E1 C1E9 08 shr ecx, 8
0069A2E4 33C8 xor ecx, eax
0069A2E6 4A dec edx ; 难道这里是求CRC的代码?
0069A2E7 ^ 0F85 EAFFFFFF jnz delphi7_.0069A2D7
0069A2ED 8BC1 mov eax, ecx
0069A2EF F7D0 not eax
0069A2F1 3985 49061B07 cmp dword ptr [ebp+71B0649], eax
0069A2F7 0F84 17000000 je delphi7_.0069A314
0069A2FD 83BD 85011B07 0>cmp dword ptr [ebp+71B0185], 0
0069A304 0F85 0A000000 jnz delphi7_.0069A314 ; 自校验path位置1.. 改成jmp
0069A30A C785 31291B07 0>mov dword ptr [ebp+71B2931], 1
这一段是关于自效验的判断. 我们当然可以随便就跳过了.. 所以这个是要path的位置1.. 其实看到这个代码我有种说不出的亲切. 这个肯定是用assembly写出来的, 而且是手工的. 看着非常的舒服. 我们可以很轻易的就定位到一小段代码的开始位置, 结束位置. 久违的汇编啊.... 完了之后给其他模块调用的, 我也写过..
0069A315 B9 B6282501 mov ecx, 12528B6 ; 硬编码的解码Key1
0069A31A BA F9628A76 mov edx, 768A62F9 ; 硬编码的解码Key2
0069A31F AD lods dword ptr [esi] ; 这里是加载IAT加密表的第一个字段
0069A320 89B5 95211B07 mov dword ptr [ebp+71B2195], esi
0069A326 C746 FC 0000000>mov dword ptr [esi-4], 0 ; 取出来就清0, 好猥琐
0069A32D 3D EEEEEEEE cmp eax, EEEEEEEE ; 结束符标记判断
0069A332 0F85 20000000 jnz delphi7_.0069A358
0069A338 813E DDDDDDDD cmp dword ptr [esi], DDDDDDDD ; 结束标记判断
0069A33E 0F85 14000000 jnz delphi7_.0069A358
0069A344 C706 00000000 mov dword ptr [esi], 0 ; 清零
0069A34A 83C6 04 add esi, 4
0069A358 8BD8 mov ebx, eax
0069A35A 3385 31291B07 xor eax, dword ptr [ebp+71B2931]
0069A360 C1C8 03 ror eax, 3
0069A363 2BC2 sub eax, edx
0069A365 C1C0 10 rol eax, 10
0069A368 33C1 xor eax, ecx
0069A36A 899D 31291B07 mov dword ptr [ebp+71B2931], ebx ; 解密出第一个字段值
0069A370 3D 00000100 cmp eax, 10000
0069A375 0F83 45000000 jnb delphi7_.0069A3C0
0069A37B 813E BBBBBBBB cmp dword ptr [esi], BBBBBBBB ; 结束标记判断
0069A381 0F85 39000000 jnz delphi7_.0069A3C0
0069A387 C706 00000000 mov dword ptr [esi], 0 ; 清零
0069A38D 83C6 04 add esi, 4
到这里开始就是正式的解码阶段了. 这里首先取出来IAT加密结构的第一个字段. 解密出来.. 现在我们手头上已经有了某个API函数的Hash值. 现在我们需要做的就是在加密表中根据HASH进行查找..
0069A3C0 51 push ecx
0069A3C1 52 push edx
0069A3C2 33C9 xor ecx, ecx
0069A3C4 8B95 511A1B07 mov edx, dword ptr [ebp+71B1A51]
0069A3CA 3B02 cmp eax, dword ptr [edx] ; 比较Hash值
0069A3CC 0F84 38000000 je delphi7_.0069A40A
0069A3D2 83C2 04 add edx, 4
0069A3D5 41 inc ecx
0069A3D6 3B8D 691F1B07 cmp ecx, dword ptr [ebp+71B1F69]
0069A3DC ^ 0F85 E8FFFFFF jnz delphi7_.0069A3CA ; 这里是根据Hash值进行查找, 我们可以使用下
0069A3E2 8DB5 7BD32C07 lea esi, dword ptr [ebp+72CD37B]
0069A3E8 8DBD 8D221B07 lea edi, dword ptr [ebp+71B228D]
0069A3EE AC lods byte ptr [esi]
0069A3EF 84C0 test al, al
0069A3F1 0F84 06000000 je delphi7_.0069A3FD
0069A3F7 AA stos byte ptr es:[edi]
0069A3F8 ^ E9 F1FFFFFF jmp delphi7_.0069A3EE
0069A3FD B8 07000000 mov eax, 7
0069A402 8D8D D04E1B07 lea ecx, dword ptr [ebp+71B4ED0]
0069A408 FFE1 jmp ecx
0069A40A 898D D9091B07 mov dword ptr [ebp+71B09D9], ecx ; 这是IAT加密表中的下标
0069A410 5A pop edx
0069A411 59 pop ecx
这一段就是查找代码.. 查到到以后我们就在IAT加密表中定位到了函数的Hash值. mov [ebp+71B09D9], ecx里面保存的就是下标了.
0069A412 56 push esi
0069A413 8B9D 411D1B07 mov ebx, dword ptr [ebp+71B1D41] ; DLL模块表
0069A419 8B0B mov ecx, dword ptr [ebx] ; 取得模块基址
0069A41B 8B85 D9091B07 mov eax, dword ptr [ebp+71B09D9]
0069A421 D1E0 shl eax, 1 ; IAT加密表下标
0069A423 0385 2D201B07 add eax, dword ptr [ebp+71B202D]
0069A429 33F6 xor esi, esi
0069A42B 96 xchg eax, esi
0069A42C 66:AD lods word ptr [esi] ; 在原始的DLL我们也是可以很容易定位到函数的真实地址.
0069A42E C1E0 02 shl eax, 2
0069A431 0385 452A1B07 add eax, dword ptr [ebp+71B2A45]
0069A437 96 xchg eax, esi
0069A438 AD lods dword ptr [esi]
0069A439 03C1 add eax, ecx ; 到这里就根据第一个dword解密出API函数的地址了
0069A43B 5E pop esi
刚才我们不是加密了么? 又解密出来了, 并且获得了真实的API函数地址.
0069A43C 83BD F91A1B07 0>cmp dword ptr [ebp+71B1AF9], 1
0069A443 0F84 39000000 je delphi7_.0069A482 ; 判断是否是特殊DLL的特殊函数,是则加密.这里改jmp
0069A449 3B8D DD1C1B07 cmp ecx, dword ptr [ebp+71B1CDD] ; 判断到底是哪个DLL, 一看就知道了. 有3个DLL
0069A44F 0F84 2D000000 je delphi7_.0069A482
0069A455 3B8D 491C1B07 cmp ecx, dword ptr [ebp+71B1C49]
0069A45B 0F84 21000000 je delphi7_.0069A482
0069A461 3B8D 89291B07 cmp ecx, dword ptr [ebp+71B2989]
0069A467 0F84 15000000 je delphi7_.0069A482
0069A46D 8D9D CBE72C07 lea ebx, dword ptr [ebp+72CE7CB]
0069A473 FFD3 call ebx ; 这就是传说中的加密函数了
0069A475 8BF8 mov edi, eax
0069A477 8985 DD261B07 mov dword ptr [ebp+71B26DD], eax
0069A47D E9 3E060000 jmp delphi7_.0069AAC0
0069A482 8D9D CBE72C07 lea ebx, dword ptr [ebp+72CE7CB]
0069A488 FFD3 call ebx ; 这是干嘛的??
这里是判断是否是kernel32.dll user32.dll 或者advapi32.dll中的一个.我们当然要跳过. 这样就可以不加密了. 呵呵. 现在我们要跳过的是两个地方..
0069AAC6 AD lods dword ptr [esi] ; 这里取第IAT加密表的第2个dword
0069AAC7 C746 FC 0000000>mov dword ptr [esi-4], 0 ; 清零, 猥琐
0069AACE C1C0 05 rol eax, 5 ; 第2个dword是解码出API写入IAT表地址
0069AAD1 05 B6282501 add eax, 12528B6 ; 解码算法
0069AAD6 0385 F5031B07 add eax, dword ptr [ebp+71B03F5]
0069AADC 8B8D DD261B07 mov ecx, dword ptr [ebp+71B26DD] ; eax == 要写入IAT表的地址.
0069AAE2 8908 mov dword ptr [eax], ecx ; Code断点的第2个阶段. 断在这里
0069AAE4 AD lods dword ptr [esi] ; 这里取IAT表的第3个dword
0069AAE5 C746 FC 0000000>mov dword ptr [esi-4], 0 ; 清零
0069AAEC 89B5 95211B07 mov dword ptr [ebp+71B2195], esi ; 第3个dword解码出调用这个API的地址
0069AAF2 83F8 FF cmp eax, -1
0069AAF5 0F85 20000000 jnz delphi7_.0069AB1B
0069AAFB 813E DDDDDDDD cmp dword ptr [esi], DDDDDDDD ; 是否是结束标记
0069AB01 0F85 14000000 jnz delphi7_.0069AB1B
0069AB07 C706 00000000 mov dword ptr [esi], 0
0069AB0D 83C6 04 add esi, 4
0069AB10 89B5 95211B07 mov dword ptr [ebp+71B2195], esi
0069AB16 ^ E9 5CF7FFFF jmp delphi7_.0069A277
0069AB1B C1C0 03 rol eax, 3
0069AB1E 0385 F5031B07 add eax, dword ptr [ebp+71B03F5] ; 定位到调用API的地址
0069AB24 83BD 59251B07 0>cmp dword ptr [ebp+71B2559], 1
0069AB2B 0F84 9D000000 je delphi7_.0069ABCE
0069AB31 813E AAAAAAAA cmp dword ptr [esi], AAAAAAAA ; 判断是否是结束标记
0069AB37 0F85 12000000 jnz delphi7_.0069AB4F
0069AB3D 83C6 04 add esi, 4
0069AB40 C746 FC 0000000>mov dword ptr [esi-4], 0 ; 清零
0069AB47 97 xchg eax, edi
0069AB48 B0 E9 mov al, 0E9
这里取出IAT表的第2个字段, 这个字段的作用是定位到调用API的地址..
0069AB94 B0 90 mov al, 90
0069AB96 AA stos byte ptr es:[edi] ; 调用的地址首字节写90
0069AB97 58 pop eax
0069AB98 AA stos byte ptr es:[edi] ; 写入E9
0069AB99 E9 24000000 jmp delphi7_.0069ABC2
0069AB9E 58 pop eax
0069AB9F AA stos byte ptr es:[edi]
0069ABA0 807F FF E9 cmp byte ptr [edi-1], 0E9
0069ABA4 0F85 18000000 jnz delphi7_.0069ABC2
0069ABAA 83BD BED32C07 0>cmp dword ptr [ebp+72CD3BE], 0
0069ABB1 0F84 08000000 je delphi7_.0069ABBF
0069ABB7 8D9D 7E1B2C07 lea ebx, dword ptr [ebp+72C1B7E]
0069ABBD FFD3 call ebx
0069ABBF 8847 04 mov byte ptr [edi+4], al
0069ABC2 8B85 DD261B07 mov eax, dword ptr [ebp+71B26DD]
0069ABC8 2BC7 sub eax, edi
0069ABCA 83E8 04 sub eax, 4
0069ABCD AB stos dword ptr es:[edi] ; 写入要跳转到的地址
0069ABCE AD lods dword ptr [esi] ; 又加载一个字节
0069ABCF C746 FC 0000000>mov dword ptr [esi-4], 0 ; 清零.. 太猥琐了
|