MEMZ 源码级分析

MEMZ 这个上古毒物我两三年前就下载了它的样本,然后把它扔到硬盘的某个角落。今天重新给它翻出来,看看它的源代码到底是怎么样的。

首先 ,样本: MEMZ_virus.zip (密码:MEMZ!virus

工具:IDA Pro v7.0 IDA7.0.zip

 

 

(Index不想写w


 

 

 

解压,发现目录里有两个文件,一个.bat,另一个.exe

很明显.exe就是病毒样本,那么.bat什么用的?

打开

 

可以看到,为了逃避检测,它还特地把执行内容写到js

很明显这个bat是用来生成exe病毒文件的。

就一个base64加密竟然直接绕过了360????

 

 

 


 

 

 

直接用IDA打开MEMZ.exe,分析源代码

程序出口点为start函数,跟进

然后直接一个 F5 下去

 

观察一下函数的流程。

 

首先获取了程序的启动参数,类似于int main(int argc,char**argv),只不过用Windows API GetCommandLine()的方式获取。

然后再判断参数是否存在,存在的话再判断是不是为/watchdog,是的话创建一个新线程执行sub_40114A()

创建完新线程后,调用了RegisterClassEx注册窗口和CreateWindowEx新建窗口。

但是这里的参数有点奇怪

RegisterClassEx的定义
ATOM WINAPI RegisterClassEx(
_In_ const WNDCLASSEX *lpwcx
);

参数应该为WNDCLASSEX*而不是SHELLEXECUTEINFO*

有可能是IDA反编译出错,也有可能是作者的混淆(可能性更大

总之,到MSDN上找这两的定义

注意程序中的调用为RegisterClassExA((const WNDCLASSEXA *)&pExecInfo.lpVerb);

所以SHELLEXECUTEINFO.lpVerb及以下与WNDCLASSEX.cbSize及以下的参数一一对应。(项数也刚好相同,大小也相等sizeof(*void)=sizeof(int)=sizeof(DWORD)=4

分析一下参数就可以发现,它创建了一个类名为hax的窗口,且此窗口的回调函数为sub_4010000,其余什么也没有。

跟进此函数

winuser.h里面可以看到关于Message系列常数定义的值

WM_CLOSE对应窗口关闭请求,WM_ENDSESSION对应关机时关闭窗口请求

且如果传给当前窗口的消息不为其中任一时,窗口信息转为DefWindowProc处理。

否则调用函数sub_401021

跟进此函数

函数一开始就创建了 20 个线程执行同样这个函数,这样会变成无限创建线程,如果没有后续处理系统会卡死。

上面这个是我一开始的想法。其实它是错的。

这20个线程执行的不是这个函数的开头,而是一段IDA没能F5出来的代码,在这里

(意义不明,下图看得出堆栈也是平衡的,不知道为什么IDA错误

没有办法,我们直接对着汇编分析。

首先push esi,意义不明。

然后调用GetCurrentThreadId获取当前线程ID,保存在eax中。

接着SetWindowHookEx(idHook=5,lpfn=offset_fn,hmod=0,dwId);

查阅MSDN

即所有的窗口事件将会被传送到fn所指向的函数处理,跟进

再次查询MSDNcode=3即创建窗口事件

跟进函数sub_401A55

发现这是个生成随机数的函数。

观察原函数,生成的随机数都返回给了v4 (LPARAM),所以这段代码实现了随机设置此句柄上的窗口位置。

之后调用了MessageBox(hWnd=0,lpText,Caption="MEMZ",0x1010=MB_OK|MB_ICONERROR|MB_SYSTEMMODAL)来显示对话框。

最后使用UnhookWindowHookEx卸载之前的钩子。

MessageBox中的内容lpText则是随机以下内容

 

回到原函数,创建对话框后

首先获取(LoadLibrary)ntdll.dll中的RtlAdjustPrivilegeNtRaiseHardError函数,如果这两个函数都能成功获取的话,就先调用v4(RtlAdjustPrivilege),再调用v6(NtRaiseHardError)

但是如果有一获取不成功,就是用原始的方法提升至SeShutdownPrivilege权限,最后调用ExitWindowsEx强制关机。

RtlAdjustPrivilege是一个MSDN未公开的函数,因为它可以做到一行提权,完美替代以前使用传统的OpenProcessToken -> LookupPrivilegeValue -> AdjustTokenPrivileges麻烦方法。

此函数定义NTSTATUS RtlAdjustPrivilege
(
ULONG Privilege, //Privilege [In] Privilege index to change.
BOOLEAN Enable, //Enable [In] If TRUE, then enable the privilege otherwise disable.
BOOLEAN CurrentThread, //CurrentThread [In] If TRUE, then enable in calling thread, otherwise process.
PBOOLEAN Enabled //
Enabled [Out] Whether privilege was previously enabled or disabled.
)

19 = 0x13 = SE_SHUTDOWN_PRIVILEGE即关机权限

同样,NtRaiseHardError也为ntdll.dllMSDN未公开的函数,它的功能是引发一次蓝屏(与普通蓝屏不同,这个蓝屏一般由硬件错误引起,区别如图

)。

函数定义NTSYSAPI NTSTATUS NTAPI NtRaiseHardError
(
IN NTSTATUS ErrorStatus,
IN ULONG NumberOfParameters,
IN PUNICODE_STRING UnicodeStringParameterMask OPTIONAL,
IN PVOID *Parameters,
IN HARDERROR_RESPONSE_OPTION ResponseOption,
OUT PHARDERROR_RESPONSE Response
);

使用例子:

(也可以参考:https://blog.csdn.net/AcceZn/article/details/54670776

即可引起一次0xC000021A蓝屏。(注:代码中NtRaiseHardError的第一个参数为负数是因为signed int的溢出)

 

别忘了,在创建窗口前还创建了一个线程执行函数sub_40114A()

继续跟进

这个函数流程是一目了然。

首先用GetProcessImageFileName获取当前运行文件名,然后利用tlhelp32.h里的CreateToolhelp32Snapshot结合Process32FirstProcess32Next遍历所有进程,也获取这些进程的文件名,并寻找与当前进程名相等的数量。如果数量v4比之前的数量v7还少(说明有进程被杀死),直接调用函数sub_401021,即之前的蓝屏/关机函数。

 

总结一下目前为止的流程:从程序启动开始,如果参数带有/watchdog,则创建一个线程判断是否有当前病毒程序被杀死,有的话直接蓝屏/关机。之后创建一个窗口,如果检测到窗口被关闭或系统将要关闭,手动创建多个线程蓝屏/关机。

 

 

 


 

 

 

回到主程序,继续往下看流程。(注:此时还在有参数存在的条件内,即有参数但不为/watchdog,因为在之前创建窗口后使用while死循环获取并处理窗口消息。

连续调用CreateFileWriteFile尝试向\\.\PhysicalDrive0即0号磁盘设备写入扇区内容。中间那一大段就是获取写入内容,这一段就是覆盖系统MBR的过程。

首先打开当前磁盘目录下的note.txt,写入以下内容,完成后调用notepad将其打开,即显示了这段信息。

之后循环创建线程执行函数sub_401A2B

然后进入while() Sleep永久阻塞状态

 

中间这一段有点难分析,我们先看接下来的程序。(注:此时为无参数内

一堆警告信息。

都确认之后

首先通过ShellExecuteEx创建5个带/watchdog参数的程序(作用如上分析),再执行一个带/main参数的程序,还SetPriorityClass (0x80u=HIGH_PRIORITY_CLASS)设置最高优先级后本进程退出。

 

 

 


 

 

 

现在整个程序的流程都大概清楚了:先是用户点击,此时无参数,显示两个警告,都确认后创建5个/watch进程和一个/main进程并退出。/watchdog进程只是检测是否有自己的进程被杀死或者要关机了,那个时候直接蓝屏/关机。/main进程才是执行主要功能的进程,先是覆盖磁盘MBR,然后开始搞事搞事(好像确实是真的搞事)。

回到刚刚参数/main(现在已经知道是它了)执行的地方,现在来详细分析这段调用(循环创建线程执行函数sub_401A2B)的功能。

跟进sub_401A2B()

发现这个函数只是简单地调用了以参数lpThreadParameter传进来的函数,并且只要函数调用成功的话这个函数的两个参数都自加,10sec后又重新执行一遍。

所以问题的所在不是这个函数,而是参数v9

回到原函数,分析一下流程:首先v8=0; v9=(DWORD *)&off_405130

然后Sleep() v9指向的空间的第二个DWORD字节的数据大小。

接着CreateThread() v9指向的空间第一个DWORD指向的函数。

最后v9越过两个DWORD字节,并且阻塞10msec后继续。

看得出来,最重要的就是在off_405130处的数据了。

函数都直接硬编码了在里面,我们一个一个分析。

 

来到sub_4014FC(函数只有一个参数,我也不知道为什么

先是sub_401A55()随机数到v2,然后ShellExecute (&lpFile)[v2 % 0x2E],即随机打开以下文件

 

来到sub_40156D

先是GetCursorPos获取指针位置,然后疯狂在一定范围内随机,最后SetCursorPos,实现了鼠标不断抖动跟喝了脉动一样的效果。

 

来到sub_4017A5

也很明显,先是随机了一定范围内的数作为SendInput的参数(1=INPUT_KEYBOARD),且这个随机数作为可视ASCII被模拟发送至键盘。('0'=48 '0'+42=90='Z'

 

来到sub_4016A0

随机了一个数作为PlaySound的参数(&pszSound)[v1 % 3],即随机播放下列声音

 

来到sub_4015D4

先用GetDesktopWindow()获取了顶层桌面的句柄,再用GetWindowDC()获取了桌面的窗口设备上下文(DC),接着用GetWindowRect获取桌面的大小,最后使用BitBlt()绘制图形并ReleaseDC()关闭写入。

BitBlt()参数中的0x330008=NOTSRCCOPY
Copies the inverted source rectangle to the destination.”(MSDN),就是实现了将整个桌面进行反色显示的功能。(一个F5刷新即可复原)

 

来到sub_40162A

发现创建了一个新线程执行sub_401994,跟进

功能与之前分析的类似。

 

来到sub_401866

首先使用GetSystemMetrics()获取ICO支持大小,如下

然后同样的获取桌面DC,鼠标位置。之后用LoadIcon()读取ICO图片,在鼠标位置上调用DrawIcon绘制ICO图片后,再随机生成位置绘制ICO图片。(同样F5刷新可去除)

注:0x7F01=32513=IDI_ERROR 0x7F03=32515=IDI_EXCLAMATION

 

来到sub_401688

使用了EnumChildWindows()获取桌面上所有子窗口,并且用EnumFunc()函数回调,跟进。

使用GlobalAlloc()分配堆空间,作为SendMessageTimeout()的一参数,同时设置Msg,超时时间为0x64=100msec

Msg=0xD,开始先获取窗口中所有文本,存到v2,然后将v2代入sub_401AA0,最后Msg=0xC重新设置窗口的文本为处理后的v2。跟进此函数。

对不起根本不想看,自己去试过之后知道这个函数作用是颠倒字符串,同STLreverse()一样。

这个函数功能就是颠倒桌面子窗口中所有文本框里的字符串。

(注:这里的桌面不仅仅是explorer.exe,还有其子进程,就是所有通过双击打开的程序。

 

来到sub_4017E9

StretchBlt()BitBlt()的区别就是前者会根据Dst放缩图像,后者只是单纯拷贝。

StretchBlt()中参数0xCC0020=SRCCOPY,即将整个桌面缩小50,50,100,100

实现了无限循环缩小屏幕的效果。(同样,F5刷新可复原)

 

来到sub_4016CD

生成一堆随机数,然后再一定范围内随机复制图像,造成混乱的效果(同样F5可去除)

 

 

 


 

 

 

至此所有的功能都分析完了。

总结: 双击打开病毒文件时,首先弹出俩警告框,点取消直接退出,点确定则创建五个参数/watchdog和一个参数/main的进程。/watchdog进程检测是否有病毒进程被关闭或者将要关机,有的话弹出20个提示框,然后蓝屏/关机。/main进程首先修改磁盘MBR,然后用记事本弹出信息,最后循环执行打开程序/播放声音/反色屏幕/放图片/不断缩放屏幕/随意复制屏幕内容等操作并堵塞。

感觉除了改MBR其它好像都不会怎么样

所以帮它把改MBR去掉就安全了

源代码,要去掉CreateFile并且不触发ExitProcess

首先把底下的jnz改成jmp

然后。。。。。。。。。。。

再来到这里

同样把jnz换成jmp

再然后。。。。。。。。。。。。

然后很完美

前面删的太爽一不小心把这个给删了

弄回去就好了

还有这个也要弄回去(手打就成这样了,不过不影响

然后写入

一份无毒无害安全的MEMZ.exe就弄好了

。。。。。。虽然运行不正常

别了别了别这样换,重新替换一次,这次只修改jmp以及call以及push调用

然后就成功的去掉了写MBR的功能。

因为它实在是太安全了,以至于360都报毒了

 

修改版(去除写MBR,安全无害,可以在真机上运行):memz_edit.zip(密码:memz!funny

(PS:从上面的源代码分析看得出来,其实只要taskkill /f /im MEMZ.exe就好了,什么都不会发生

(可以直接写一个检测按键的程序,xx键按下while(1)if(GetAsyncKeyState(...))直接全部关闭MEMZ.exe,是完美安全的做法。

 

 

 


 

 

 

总感觉把写MBR去了这程序乐趣就少了一半

所以我特地把MBRNC代码提出来:dump.bin(如果只有mbr.bin是不够的

直接用WinHex等工具覆盖写到虚拟机的磁盘偏移量0就可以了。

为了方便写入,我还特地写了个小工具 WriteMBR.exe(源代码:WriteMBR.zip

直接把.bin文件拖进去就可以了。

 

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。本来弄到这里很开心很快乐

直到我看到了这个 https://github.com/Leurak/MEMZ

MMP*******************************************************************************************************************************

MD有源代码我还分析个**

。。。。。。。等等,其实这波不亏啊。

因为在Windows上配置编译环境比TM直接改汇编还难

 

 

 


 

 

 

好了,源代码有是有,但是我也不会改

只好自己琢磨这也弄个骚东西出来。

推荐下载地址: av_full.rar (无打包,多文件

(注:Win7以上可能无法运行! av_packed_full.rar (打包版本,单文件

(注:无压缩 av_packed_full.exe

(注:精简警告:可能运行不正常!!! av_packed.exe av_packed.rar

注:安全无毒警告! http://r.virscan.org/language/zh-cn/report/58c20ab6372e192bf370238cb13bbbdb

至于360sd………………………….大家都知道的。(QVM和KVM存在意义不明????)

声明:本程序并不会篡改任何系统文件(重启后就跟没运行过一样),可以放心的在真机上食用。

源代码: av_source.zipbuild with VC6 on win7x64

特别鸣谢:6332812(虽然是自己拿来用的w

顺带BUG:XP上自行关掉静音,谢谢合作

还有我在Win7上写的,界面是这样的:

如果拿到XP上运行界面变成这样知道一下意思一下就行哈

《MEMZ 源码级分析》上有9条评论

    1. 上次丢数据的时候给弄没了,只存了 av_source.zip 的备份。如果想玩的话,可以自己编译一份 MEMZ,或者闲着无聊也可以拿 IDA 啥的改一改ww

        1. 用 VC++ 之类的编译源代码,剩下的资源文件根据说明生成打包就可以了。不过实际上可能会有点麻烦,自己弄编译环境的话可能不会比 IDA 里 NOP 几下快(

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注