-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
356 lines (286 loc) · 18.9 KB
/
index.html
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
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>易语言逆向分析 by l0g1n</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/normalize.css" media="screen">
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
<link rel="stylesheet" type="text/css" href="stylesheets/github-light.css" media="screen">
</head>
<body>
<section class="page-header">
<h1 class="project-name">易语言逆向分析</h1>
<h2 class="project-tagline"></h2>
<a href="https://github.com/l0g1n/E_language_reverse" class="btn">View on GitHub</a>
<a href="https://github.com/l0g1n/E_language_reverse/zipball/master" class="btn">Download .zip</a>
<a href="https://github.com/l0g1n/E_language_reverse/tarball/master" class="btn">Download .tar.gz</a>
</section>
<section class="main-content">
<h2>
<a id="易语言介绍" class="anchor" href="#%E6%98%93%E8%AF%AD%E8%A8%80%E4%BB%8B%E7%BB%8D" aria-hidden="true"><span class="octicon octicon-link"></span></a>易语言介绍</h2>
<p>易语言功能强大,具有多个支持库,可以很快的进行产品开发。与其它语言相比,学习难度也低一些,目前很多的外挂程序,核心功能编写为动态链接库,界面开发的工作会使用易语言来进行。</p>
<p>易语言编写的程序,最终的功能实现,还是需要调用系统的动态链接库。我对易语言的理解是对系统动态库中常用的功能进行了一次封装,使其使用起来更加方便简单。</p>
<p>由于易语言本身带有多个支持库,使用我们的逆向分析变得困难重重。我们无法分辨哪些是初始化操作,哪些是关键代码,我们不能很容易的找到程序所使用到的系统函数等等。带着这些问题,我对易语言的程序进行了一些逆向分析,分享给大家,希望对你有帮助。</p>
<p>本文以下面的样本为例子:</p>
<pre><code>样本名称:1.exe
样本MD5:ab58a0167e3f318226e1937e983be3d0
样本SHA1:f28d8d6a4074ba296209e69e4a59e278cadb95e7
样本来源:http://www.52pojie.cn/thread-430260-1-1.html
</code></pre>
<h2>
<a id="支持库加载过程" class="anchor" href="#%E6%94%AF%E6%8C%81%E5%BA%93%E5%8A%A0%E8%BD%BD%E8%BF%87%E7%A8%8B" aria-hidden="true"><span class="octicon octicon-link"></span></a>支持库加载过程</h2>
<p>易语言生成的程序,运行后,首先进行的操作是在Temp目录下创建新的文件夹,并将自身所需要的支持库释放到该目录下,文件后缀为.fnr、.fne等等,如下图</p>
<p><img src="http://i.imgur.com/oASfph3.png" alt=""></p>
<p>接着会使用函数<code>LoadLibraryA</code>将支持库<code>krnln.fnr</code>加载到内存中,使用<code>GetProcAddress</code>获取其导出函数<code>GetNewSock</code>的地址,并通过<code>call eax</code>调用进行初始化的相关操作。</p>
<p><img src="http://i.imgur.com/c4bFsit.png" alt=""></p>
<p>初始化前后,第二个data段的对比</p>
<p><img src="http://i.imgur.com/uYkxso6.png" alt=""></p>
<p>可以看到,当程序执行到<code>0x46DD99</code>时,<code>0x46DDD0-0x46DE12</code>处的函数地址已经填充完毕,程序通过这些函数来执行操作。</p>
<p>而其它支持库(如:<code>eAPI.fne</code>、<code>EThread.fne</code>)的调用过程是通过<code>krnln.fnr</code>来完成的,同样也会使用<code>LoadLibraryA</code>来加载支持库,<code>GetProcAddress</code>获取函数<code>GetNewInf</code>地址,并进行调用,同样,该函数的功能也是进行相关初始化操作。</p>
<p>易语言实现各种功能,最终还是需要调用系统函数,但是如何进行调用的,我们如何扒开这些外壳,来找到系统函数的调用地址。</p>
<h2>
<a id="函数调用" class="anchor" href="#%E5%87%BD%E6%95%B0%E8%B0%83%E7%94%A8" aria-hidden="true"><span class="octicon octicon-link"></span></a>函数调用</h2>
<p>程序所实现的功能,需要依赖于系统动态链接库中的各种函数。通过分析发现,易语言的程序有两种函数调用,一是直接调用系统动态链接库函数,二是调用其它支持库函数。但两种函数的调用,都是经过支持库krnln.fnr发起。</p>
<ul>
<li>
<code>krnln.fnr</code> --> 系统动态链接库函数</li>
<li>
<code>krnln.fnr</code> --> 其它支持库(如:<code>eAPI.fne</code>、<code>EThread.fne</code>) --> 系统动态链接库函数</li>
</ul>
<p>下面对两种调用进行分析,围绕如何调用和参数传递来介绍</p>
<h3>
<a id="直接调用系统函数" class="anchor" href="#%E7%9B%B4%E6%8E%A5%E8%B0%83%E7%94%A8%E7%B3%BB%E7%BB%9F%E5%87%BD%E6%95%B0" aria-hidden="true"><span class="octicon octicon-link"></span></a>直接调用系统函数</h3>
<p>以<code>Process32Next</code>为例,说明一下调用过程:</p>
<pre><code>0046D05D B8 06000000 mov eax,0x6 ; ID号,用来指明调用哪个函数
0046D062 E8 A50D0000 call 1.0046DE0C ; 获取并调用该函数
0046D067 3965 EC cmp dword ptr ss:[ebp-0x14],esp
</code></pre>
<p>当执行到<code>0x46D062</code>时,此时栈中的数据,就是所调用函数的参数</p>
<pre><code>0012FA48 00000108
0012FA4C 00242820
</code></pre>
<p><code>F7</code>进入该函数</p>
<pre><code>0046DE0C - FF25 01C44600 jmp dword ptr ds:[0x46C401] ; krnln.1002CC84
</code></pre>
<p>再次<code>F7</code>进入到函数内部,在分析时,可以把此部分当作特征,定位调用系统函数的位置</p>
<pre><code>1002CC84 50 push eax ; 传入ID号
1002CC85 E8 E7FFFFFF call <krnln.GetProcAddress_ByID> ; 获取函数地址
1002CC8A 83C4 04 add esp,0x4
1002CC8D FFE0 jmp eax ; 调用该函数
</code></pre>
<p>执行到<code>0x1002CC8D</code>,<code>F7</code>进入,看栈中数据</p>
<pre><code>0012FA44 0046D067 /CALL 到 Process32Next 来自 1.0046D062
0012FA48 00000108 |hSnapshot = 00000108 (window)
0012FA4C 00242820 \lppe
</code></pre>
<p>这样就完成了一次调用过程。</p>
<p>还有一个问题没有解决,如何通过ID号,来判断要获取的是哪个函数的地址呢?猜测在程序中应该有一个表,跟到<code>GetProcAddress_ByID</code>函数中,来看一下如何从ID号获取的函数名称。在该函数内部,我们找到下面的代码</p>
<pre><code>1005AF78 8B87 D0010000 mov eax,dword ptr ds:[edi+0x1D0] ; edi=0x10118678,计算之后,eax=0x15E5e8
1005AF7E 8B0498 mov eax,dword ptr ds:[eax+ebx*4]
1005AF81 894424 10 mov dword ptr ss:[esp+0x10],eax ; 1.0040948E
</code></pre>
<p>得到函数名称列表</p>
<pre><code>0015E538 0040947A ASCII "UnhookWindowsHookEx"
0015E53C 0040948E ASCII "OpenProcess"
0015E540 0040949A ASCII "ZwResumeProcess"
0015E544 004094AA ASCII "CloseHandle"
0015E548 004094B6 ASCII "CreateToolhelp32Snapshot"
0015E54C 004094CF ASCII "Process32First"
0015E550 004094DE ASCII "Process32Next"
0015E554 004094EC ASCII "GetModuleHandleA"
0015E558 004094FD ASCII "SetWindowsHookExA"
0015E55C 0040950F ASCII "RtlAdjustPrivilege"
0015E560 00409522 ASCII "ZwSuspendProcess"
0015E564 00409533 ASCII "ClipCursor"
0015E568 0040953E ASCII "CallNextHookEx"
</code></pre>
<p>有了这个函数列表,也知道了参数是如何进行传递的,这就可以当函数执行到<code>0x46D062</code>时,我们就知道本次调用的函数是哪个,也知道传入的参数有哪些,无需再进行<code>krnln</code>模块中进行分析。同时,我们还可以使用指令搜索,来获取哪个函数会在什么地址处被调用。</p>
<p>例如:我们想知道函数<code>CreateToolhelp32Snapshot</code>在哪些被调用,查找函数名称表,可以知道该函数的ID号为4。我们就可以查找命令序列</p>
<pre><code>mov eax,0x4
call 0046DE0C
</code></pre>
<p>来定位调用该函数的地址。</p>
<h3>
<a id="调用易语言模块的函数" class="anchor" href="#%E8%B0%83%E7%94%A8%E6%98%93%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9D%97%E7%9A%84%E5%87%BD%E6%95%B0" aria-hidden="true"><span class="octicon octicon-link"></span></a>调用易语言模块的函数</h3>
<p>以调用<code>EThread</code>支持库中某函数为例</p>
<pre><code>0046D645 BB 00000000 mov ebx,0x0
0046D64A B8 04000000 mov eax,0x4
0046D64F E8 9A070000 call 1.0046DDEE
</code></pre>
<p>通过<code>eax</code>、<code>ebx</code>来计算需要调用的模块及函数地址,而函数调用的参数则通过栈来传递</p>
<p><code>F7</code>进入该函数</p>
<pre><code>0046DDEE - FF25 05C44600 jmp dword ptr ds:[0x46C405] ; krnln.1002CC8F
</code></pre>
<p>再次<code>F7</code>,进入到函数内部,该部分代码片段可以用来定位调用支持库函数的地址</p>
<pre><code>1002CC8F 8B15 70861110 mov edx,dword ptr ds:[0x10118670]
1002CC95 8B1482 mov edx,dword ptr ds:[edx+eax*4] ; 读取函数地址
1002CC98 85D2 test edx,edx
1002CC9A 75 0D jnz Xkrnln.1002CCA9 ; 若不为0,则跳过函数0x1005BA00
1002CC9C 51 push ecx
1002CC9D 53 push ebx
1002CC9E 50 push eax
1002CC9F E8 5CED0200 call krnln.1005BA00 ; 计算获取地址
1002CCA4 8BD0 mov edx,eax
1002CCA6 58 pop eax
1002CCA7 5B pop ebx
1002CCA8 59 pop ecx
1002CCA9 03DA add ebx,edx
1002CCAB 8D5424 08 lea edx,dword ptr ss:[esp+0x8]
1002CCAF 83EC 0C sub esp,0xC
1002CCB2 52 push edx
1002CCB3 FF7424 14 push dword ptr ss:[esp+0x14]
1002CCB7 C74424 08 00000>mov dword ptr ss:[esp+0x8],0x0
1002CCBF C74424 0C 00000>mov dword ptr ss:[esp+0xC],0x0
1002CCC7 C74424 10 00000>mov dword ptr ss:[esp+0x10],0x0
1002CCCF 8D5424 08 lea edx,dword ptr ss:[esp+0x8]
1002CCD3 52 push edx
1002CCD4 FF13 call dword ptr ds:[ebx] ; 调用函数
1002CCD6 8B4424 0C mov eax,dword ptr ss:[esp+0xC]
1002CCDA 8B5424 10 mov edx,dword ptr ss:[esp+0x10]
1002CCDE 8B4C24 14 mov ecx,dword ptr ss:[esp+0x14]
1002CCE2 83C4 18 add esp,0x18
1002CCE5 C3 retn
</code></pre>
<p>当程序执行到<code>0x1002CCD4</code>时,栈中的数据如下:</p>
<pre><code>0012FA54 0012FA60
0012FA58 00000003
0012FA5C 0012FA74 a3
0012FA60 00000000
0012FA64 00000000
0012FA68 00000000
0012FA6C 0046D654 返回到 1.0046D654 来自 1.0046DDEE
0012FA70 00000003
0012FA74 0046DA79 1.0046DA79
</code></pre>
<p><code>ebx</code>的值为<code>0x155C97C</code>,而<code>ds:[0155C97C]=015510D0 (EThread.015510D0)</code>,由于<code>EThread</code>模块未进行加密,我们可以通过IDA来加载<code>EThread</code>模块进行分析,加载时,请注意选择<code>Manual load</code>,根据OD中该模块所在的基地址进行设置,这样方法定位函数位置。</p>
<p>在IDA中,定位到函数<code>0x15510D0</code></p>
<pre><code>void *__cdecl sub_15510D0(int a1, signed int ThreadId, int a3)
{
int v3; // esi@1
signed int v4; // edi@1
void *v5; // eax@3
void *result; // eax@5
v3 = a3;
v4 = ThreadId;
if ( ThreadId > 1 && *(_DWORD *)(a3 + 20) )
v5 = *(void **)(a3 + 12);
else
v5 = 0;
result = CreateThread(0, 0, *(LPTHREAD_START_ROUTINE *)a3, v5, 0, (LPDWORD)&ThreadId);
*(_DWORD *)a1 = result != 0;
if ( v4 >= 3 && *(_DWORD *)(v3 + 32) )
**(_DWORD **)(v3 + 24) = result;
else
result = (void *)CloseHandle(result);
return result;
}
</code></pre>
<p>可以很清楚的看出该函数的功能是创建线程执行函数,而关键的参数则是<code>a3</code>,通过栈中的数据,得到<code>a3 = 0x0012FA74</code>,而该地址所指向的函数为:<code>0046DA79</code>,当函数<code>0x15510D0</code>执行完成后,会返回到地址<code>0x1002CCD6</code>,再通过<code>0x1002CCE5</code>返回到程序空间,完成一次支持库的调用。如果模块被加密,无法静态分析,可以在模块加载的时候进行分析,找出加密算法,编写IDA脚本进行解密,或是直接进入动态跟踪进行分析。</p>
<h2>
<a id="分析方法" class="anchor" href="#%E5%88%86%E6%9E%90%E6%96%B9%E6%B3%95" aria-hidden="true"><span class="octicon octicon-link"></span></a>分析方法</h2>
<p>下面来介绍一下我的分析方法,以及如何快速定位核心代码,希望对你有帮助</p>
<ol>
<li>
<p><code>OD</code>载入样本,<code>CTRL+F</code>查找指令<code>call eax</code>,<code>CTRL+L</code>查找下一条,找到下面的位置</p>
<pre><code>0040150E |. FFD0 call eax
00401510 |. EB 11 jmp X1.00401523
00401512 |> 6A 10 push 0x10 ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
00401514 |. 68 30704000 push 1.00407030 ; |Title = "Error"
00401519 |. FF75 FC push [local.1] ; |Text
0040151C |. 53 push ebx ; |hOwner
0040151D |. FF15 AC604000 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
00401523 |> 5F pop edi
00401524 |. 5E pop esi
00401525 |. 33C0 xor eax,eax
00401527 |. 5B pop ebx
00401528 |. C9 leave
00401529 \. C2 1000 retn 0x10
</code></pre>
</li>
<li>
<p><code>F4</code>运行到<code>0x40150E</code>,在此之前的代码可以忽略掉,它们的功能是释放所需要的各种支持库,并加载<code>krnln.fnr</code>,<code>F7</code>进入。</p>
<pre><code>1002D69A 55 push ebp
1002D69B 8BEC mov ebp,esp
1002D69D 6A 00 push 0x0
1002D69F 6A 00 push 0x0
1002D6A1 8B45 08 mov eax,dword ptr ss:[ebp+0x8]
1002D6A4 50 push eax
1002D6A5 B9 78861110 mov ecx,krnln.10118678
1002D6AA E8 B0F4FFFF call krnln.1002CB5F
1002D6AF 5D pop ebp
1002D6B0 C2 0400 retn 0x4
</code></pre>
</li>
<li>
<p><code>F4</code>运行到<code>0x1002D6AA</code>,<code>F7</code>进入。</p>
<pre><code>1002CB5F 55 push ebp
1002CB60 8BEC mov ebp,esp
1002CB62 83EC 08 sub esp,0x8
1002CB65 53 push ebx
1002CB66 56 push esi
1002CB67 57 push edi
1002CB68 894D F8 mov dword ptr ss:[ebp-0x8],ecx
1002CB6B FF15 E4630E10 call dword ptr ds:[<&KERNEL32.GetProcess>; kernel32.GetProcessHeap
1002CB71 8B4D F8 mov ecx,dword ptr ss:[ebp-0x8]
1002CB74 8981 A8040000 mov dword ptr ds:[ecx+0x4A8],eax
1002CB7A 8B55 F8 mov edx,dword ptr ss:[ebp-0x8]
1002CB7D 8B82 C4000000 mov eax,dword ptr ds:[edx+0xC4]
1002CB83 83C0 01 add eax,0x1
1002CB86 8B4D F8 mov ecx,dword ptr ss:[ebp-0x8]
1002CB89 8981 C4000000 mov dword ptr ds:[ecx+0xC4],eax
1002CB8F 8B55 10 mov edx,dword ptr ss:[ebp+0x10]
1002CB92 52 push edx
1002CB93 8B45 0C mov eax,dword ptr ss:[ebp+0xC]
1002CB96 50 push eax
1002CB97 8B4D 08 mov ecx,dword ptr ss:[ebp+0x8]
1002CB9A 51 push ecx
1002CB9B 8B4D F8 mov ecx,dword ptr ss:[ebp-0x8]
1002CB9E E8 FD1F0300 call krnln.1005EBA0
1002CBA3 FFD0 call eax
</code></pre>
</li>
<li>
<p><code>F4</code>运行到<code>0x1002CBA3</code>,<code>F7</code>进入,至此,已经回到了用户空间,从现在开始才到了程序实现功能的位置,从这里开始进行分析。进入每一个<code>jmp</code>的地址,找出直接调用系统的地址和调用自带支持库的地址,对两个地址下断点,就可以直接<code>F9</code>运行,直接后续的分析操作了。</p>
<pre><code>0046DD99 FC cld
0046DD9A DBE3 finit
0046DD9C E8 F7FFFFFF call 1.0046DD98
0046DDA1 68 84DD4600 push 1.0046DD84
0046DDA6 B8 03000000 mov eax,0x3
0046DDAB E8 32000000 call 1.0046DDE2
0046DDB0 83C4 04 add esp,0x4
0046DDB3 68 01000152 push 0x52010001
0046DDB8 E8 1F000000 call 1.0046DDDC
0046DDBD 83C4 04 add esp,0x4
0046DDC0 E8 11000000 call 1.0046DDD6
0046DDC5 6A 00 push 0x0
0046DDC7 E8 04000000 call 1.0046DDD0
0046DDCC 83C4 04 add esp,0x4
0046DDCF C3 retn
0046DDD0 - FF25 21C44600 jmp dword ptr ds:[0x46C421] ; krnln.1002D56F
0046DDD6 - FF25 25C44600 jmp dword ptr ds:[0x46C425] ; krnln.1002D4D2
0046DDDC - FF25 29C44600 jmp dword ptr ds:[0x46C429] ; krnln.1002D505
0046DDE2 - FF25 2DC44600 jmp dword ptr ds:[0x46C42D] ; krnln.1002CC6A
0046DDE8 >- FF25 1DC44600 jmp dword ptr ds:[0x46C41D] ; krnln.1002D66A
0046DDEE - FF25 05C44600 jmp dword ptr ds:[0x46C405] ; krnln.1002CC8F
0046DDF4 - FF25 11C44600 jmp dword ptr ds:[0x46C411] ; krnln.1002D4AB
0046DDFA - FF25 09C44600 jmp dword ptr ds:[0x46C409] ; krnln.1002CCE6
0046DE00 >- FF25 15C44600 jmp dword ptr ds:[0x46C415] ; krnln.1002D58C
0046DE06 - FF25 FDC34600 jmp dword ptr ds:[0x46C3FD] ; krnln.1002D46E
0046DE0C - FF25 01C44600 jmp dword ptr ds:[0x46C401] ; krnln.1002CC84
0046DE12 - FF25 0DC44600 jmp dword ptr ds:[0x46C40D] ; krnln.1002D48C
</code></pre>
</li>
</ol>
<h2>
<a id="总结" class="anchor" href="#%E6%80%BB%E7%BB%93" aria-hidden="true"><span class="octicon octicon-link"></span></a>总结</h2>
<p>通过这一个样本的分析,我们知道了一些易语言分析的规律,支持库的加载过程、函数的调用过程。分辨出支持库的加载过程可以让我们跳过不必要的分析,直接进入功能代码分析;而函数的调用过程更像是把握住了程序的两个入口,这对于逆向分析,判断样本的功能具有极大的作用。</p>
<div align="right">(如有问题,请联系:[email protected],2015.11.20,by l0g1n)</div>
<footer class="site-footer">
<span class="site-footer-owner"><a href="https://github.com/l0g1n/E_language_reverse">易语言逆向分析</a> is maintained by <a href="https://github.com/l0g1n">l0g1n</a>.</span>
<span class="site-footer-credits">This page was generated by <a href="https://pages.github.com">GitHub Pages</a> using the <a href="https://github.com/jasonlong/cayman-theme">Cayman theme</a> by <a href="https://twitter.com/jasonlong">Jason Long</a>.</span>
</footer>
</section>
</body>
</html>