样本名称:彩虹猫
MD5:19DBEC50735B5F2A72D4199C4E184960
SHA1:6FED7732F7CB6F59743795B2AB154A3676F4C822
实验平台:Windows10
分析工具:PEiD v0.95、StudyPE x64 v1.11、IDA x32 v7.0、VMWare WorkStation v16.2
一、运行观察以及信息收集
双击病毒样本后接连弹出两个警告弹窗(告知用户危险)。点击确定后,桌面会慢慢出现一些诡异的现象,比如:
自动弹出多个浏览器搜索窗口
鼠标晃动异常
窗口颜色怪异
反复出现系统提示音
出现六个病毒进程
尝试关闭任意一个,或者手动关闭计算机,都会遭至大量弹窗随后蓝屏,接着Windows无法正常启动,只会循环播放一只彩虹猫附带欢快的背景音乐,无论重启多少次都是如此。运行观察结束,用基本的可执行文件信息查看工具分析。
1.PEiD
监测到该样本可能使用了ASProtect v1.32进行加壳或加密
2.StudyPE+
查看样本导入表,可以看到很多对样本分析有用的函数,我们将函数与之前观察到的样本运行行为相关联。
自动弹出多个浏览器搜索窗口———————-ShellExecute
鼠标异常晃动————————————–SetCursorPos、GetCursorPos
桌面出现奇怪图标———————————DrawIcon
窗口颜色怪异————————————–BitBlt、StretchBlt
反复出现系统提示音——————————-PlaySoundA
出现6个病毒进程——————————–ShellExecute
其他函数:
OpenProcessToken、AdjustTokenPrivilege、LookUpPrivilegeValue 给进程提权
GetMessage、TranslateMessage、DispatchMessage 建立消息循环
CreateToolhelp32Snapshot、Process32First、Process32Next 遍历进程
SetWindowHookEx、UnhookWindowHookEx、CallNextHookEx 给窗口下钩子
LoadLibrary、GetProcAddress 加载库并导入函数
二、入口部分
使用IDA载入样本,定位到入口函数Start并按下F5获得伪代码,但是这些伪代码只是IDA根据现有信息猜测出来的,并不能保证100%准确,有的时候甚至会对分析工作产生误导,一会就能看到。
在start函数的起始部分调用GetCommandLineW、CommandLineToArgvW获取进程参数,之后整个Start函数就根据进程参数分成了几大块,整理后其结构大致可分为如下
我们第一次双击样本的时候是不带参数的,所以先看无参数也就是else部分
三、无参数部分
此处先是用MessagexBox依次弹出两个警告信息提示框,正是我们运行病毒时所看到的警告。若两个弹窗都被用户确认,使用GetModuleFileNameW获取当前进程的路径并保存,当然所保存的空间由LocalAlloc提前申请。接着用do while执行5次循环,每次循环都调用一次ShellExecuteW,参数正是刚才得到的样本进程路径,以及字符串**”/watchdog”,即以“/watchdog”**为参数,生成5个病毒exe进程。
在最后调用了ShellExecuteExW以“/main”为参数生成了一个MEMZ.exe进程,一般带Ex后缀是加强版函数,表示在普通版函数基础上进行了功能的扩展,这里特意用了一个功能更强的函数一定有特别的目的。该函数接收一个SHELLEXECUTEINFOA结构体,结构体中设定了进程路径和执行参数,关键之处在于紧接着调用了SetPriorityClass,当中对hProcess成员复制为0x80,查看MSDN得知该值意味着的进程将拥有最高的响应优先级,最后调用ExitProcess使当前进程结束。
现在知道在观察阶段看到的6个exe进程是怎么来的了:最开始双击生成了一个原始进程,原始进程生成了5个watchdog进程和1个/main进程,然后原始进程迅速结束了自己,等打开任务管理器查看时,还存在6个exe进程。
四、“watchdog”部分
1.主体部分
首先是CreateThread创建一个线程,IDA给自动命名为sub_40114A。以watchdog为参数运行的MEMZ.exe进程是有5个的,也就是说这里看到的创建一个线程是“某个进程“的行为,5个进程一共应该创建了5个线程。进入sub_40114A看看这个线程干了些什么事。
2.子函数sub_40114A
前三个函数用来获取当前进程路径(这种多个函数配合起来做事的情况有很多,常常是最后一个函数完成关键功能,前面几个都是为它提供必要的参数),比如LocalAlloc申请空间用来存路径字符串,GetCurrentProcess获取当前进程句柄,这都是第三个函数要用到的。
接着一个大的while循环把后面的代码都包了进去,该while循环的条件永远为真,说明是个死循环。在循环内部使用CreateToolhelp32Snapshot给进程拍快照,再用Process32FirstW和Process32NextW进行遍历,我们在观察阶段查看导入表时也发现了这三个函数,这里就用上了。
每当遍历到一个进程时都要获取它的路径,并和之前获取的路径对比,如果相同就让计数器加1,很明显这就是在看当前有多少个exe的进程。当遍历完所有进程后,就统计出了exe的进程个数。然后由于Sleep函数的存在,死循环每隔一段时间就能统计出当前exe进程的个数并存放在v4变量中,然后先判断v4和v7的大小,再让v7保存v4的值。
如此就形成了一个监测机制,v7永远只保存v4最大的值,一旦v4的值小于了v7就会被if语句监测到,并进入sub_401021子函数。这正好和我们观察阶段的发现一致。只要exe进程数量减少,系统就会蓝屏重启,这就是它的监测原理。反过来我们可以推测sub_401021就是完成系统蓝屏重启功能的。
3.子函数sub_401021
在这个子函数的开头是一个do while循环,循环次数为20次,用CreateThread创建线程,这没什么特别的,像往常一样我们双击StartAddress准备去看这个线程做了什么事,但是双击过后却没有任何反应,这其实是IDA的代码识别出现错误。(后续补充
在这里为了不影响我们的分析主线,直接键盘按G输入地址4010FE就可以跳到StartAddress的代码。该处的MessageBoxA用于弹出消息,有26条消息保存在lpText所指向的地址中。使用sub_401A55获取随机数保存在v3,v3对0x1A取余以实现在26条消息中随机选取一条并显示。
而SetWindowsHookEx和UnhookWindowsHookEx用于给窗口下钩子,干了什么事要到回调函数fn里去看。code==3表明目标窗口即将被创建,此时lParam表示该窗口的基本信息(坐标、大小等),修改这些信息可以在窗口真正创建之前生效,下方正是在随机修改窗口的位置。
sub_401021的后半部分是两种关机的方式:先主动诱发蓝屏关机,如果不成功则主动退出Windows。
前一种方式使用LoadLibrary加载ntdll库,再连续两次调用GetProcAddress获取两个函数地址,这两个函数是未公开的Windows API,只能用这种方式来隐式调用。随后依次调用这两个函数,主动引发蓝屏。很多恶意程序在隐式调用时会对函数名字符串先加密,要用的时候再解密,或者干脆不使用函数名而用函数编号,显然我们分析的样本没有做这种“隐蔽处理”。
后一种方式先用一系列函数给当前进程提权,然后调用ExitWindowsEx主动关闭Windows。
总结一下,我们确认了之前的猜想,sub_401021确实是一个强制关机的函数,先创建线程用于弹出大量位置和内容都随机的窗口,再使用蓝屏或退出Windows的方式强制关闭计算机.
4.注册并创建窗口
我们依次分析了函数开头->sub_40114A->sub_401021,是时候回到watchdog的主体部分。这张图之前出现过。在创建sub_40114A后,调用RegisterClassExA注册了一个名为“hax”的用户自定义窗口类型,并用CreateWindowExA将其创建。此处有个小问题,传递给RegisterClassExA函数的结构体变量pExecInfo定义为了SHELLEXECUTEINFOW类型,而不是该函数所需要的WNDCLASSEXA类型,这是IDA的识别出现了错误。
5.回调函数sub_401000
创建的窗口有一个回调函数sub_401000。经查询MSDN,常量值16和22分别对应窗口消息WM_CLOSE和WM_ENDSESSION,那么整体含义就很明了了:该窗口回调函数会对窗口消息进行过滤,若消息为WM_CLOSE或者WM_ENDSESSION,则调用sub_401021强制关机(这个函数前面刚分析过)。而WM_CLOSE或WM_ENDSESSION消息是在系统关机时,由操作系统发送给各个窗口。
若是其他消息,则并不做任何处理,丢给系统默认处理函数DefWindowProcW。
如此一来,sub_401021这个强制关机函数在两处被调用。第一个是监测watchdog进程数量,如有减少就调用。第二个是监测用户是否主动关机,如有也调用。这和我们观察阶段看到的完全一致。
6.消息循环
紧接着的代码GetMessage、TranslateMessage、DispatchMessage被包进一个大的while循环,这是常见的操作,叫做“消息循环”。由于在前面创建了窗口,并且还对发送给窗口的消息进行了过滤,意味着我们必须自己写消息循环完成收取消息和派发消息的工作,否则创建的窗口是收不到消息的。Windows并不会自动帮我们完成消息循环。
五、“/main”部分
1.主体
由于开头部分代码和MBR有极强的联系,索性把它划到MBR章节了,到时候再一块说。这里有一个do while 循环,/main部分的分析就从这儿开始。
此处的do while循环以v8为计数器,内部用CreateThread创建线程,循环跑10次(v8 < 0xA),一共创建10个线程。这不由地让人好奇,创建这么多线程是要做什么?先别慌跳进去看,它还附带一个参数v9,并被赋予初始值off_405130,每次循环自增2。以off开头表明是某个静态地址,我们双击过去看看。
off_405130地址所指向的是一块数据区,并且这里的数据还有非常强的规律性。每组都由1个dd类型的数据加4个db类型的数据组成,一共有10组。
db: data byte 1字节数据
dw: data word 2字节数据
dd: data dword 4字节数据
dq: data qword 8字节数据
再回过头来看看前面的do while,v9被赋值为off_405130并作为参数传入。Sleep函数里也用到了v9,它将v9看作了数组首地址,并每次取数组的第1项(数组项数从0开始)。每次循环v9都会自增2,由于v9的数据类型是DWORD ,每次自增2就是自增两个DWORD的大小,即8个字节。
v9的值指向的都是不同的静态地址,如果挨个双击跳过去看,会发现它们其实都是函数地址。而v9[1]是Sleep函数的参数,所指向的肯定是时间量(毫秒)。v9是4个字节的DWORD * 类型,那它指向的当然就是4字节的DWORD类型,所以这些时间量都是4字节的DWORD类型。我们在IDA中右键单击地址就可以选择其解析长度,我们用4字节来解析它。
看到这样的结构,很容易让人想到病毒作者写代码时应该用了结构体数组,结构体的构成如下:
1 | struct tagFuncWithDelay |
10个这样的结构体在一个数组中,现在我们明白了,创建了10个进程,并且每次创建都会有延迟时间,这个延迟时间和进程的函数地址是放在一起的,一共有10组,都在一个大数组off_405130里。
2.子函数sub_401A2B
这个子函数的代码很短:用大数组中的函数地址依次创建线程。由于是函数指针,要用它调用函数当然得声明其参数、返回值、调用方式之类的。
这10个函数做的事很简单,我以sub_40156D为例。它调用GetCursorPos获取鼠标指针坐标,然后用各种方式修改这个坐标的值,比如这里调用sub_401A55生成随机数并返回,用这些随机数与鼠标指针坐标做运算,最后调用SetCursorPos来设置鼠标指针坐标,用户就会发现鼠标指针随机晃动了。所有这10个函数都干的类似的事,这里不再依次分析。
这里还有一个小细节,10个函数每个的返回值部分都有不同,有的是返回一个随机值,有的是返回一个固定值。返回值被保存在v1,每次循环都会在if语句中判断!v1–是否为真,也即v1自减1后是否为0,控制v1的值就能决定循环的次数,再配合后面的Sleep函数就能决定这10个函数的激活时间。这10个函数中,有的需要一个固定的激活时间,有的需要一个随机的激活时间,只需要控制返回值即v1就可以了。
六、MBR部分
1.主体
MBR全称主引导记录(Master Boot Record),整个硬盘最开头的512字节就是它。计算机启动后会先运行MBR里的代码进行各种状态的检查和初始化的工作,然后再把控制权转交给操作系统(简单地讲就是一个JMP指令跳到操作系统的起始代码),Windows就加载启动了。
这个病毒干了一件很可恶的事,它直接把整个MBR覆盖掉了,变成了它自己的代码,那么它想干什么都行了,只要它不主动交出代码执行流程,Windows绝没有启动的机会。
MBR里既有代码也有数据,开头的0-446字节是代码,紧接着就是数据,数据部分记录着硬盘的分区信息,结尾以固定的0x55 0xAA作为结束符(PE文件结构)。
对MBR有个初步了解后,回头来看代码。现在先回到/main未分析的部分,我们前面提到过,它和MBR有紧密关联。
首先使用CreateFileA以文件形式打开了主硬盘,也即PhysicalDrive0,这样方便后续的覆盖操作。紧接着用LocalAlloc分配一段以0为初始值的内存空间,并拷贝两段神秘数据到分配的内存空间。这两段数据中第一段byte_402118大小304字节,第二段byte_402248大小1952字节,拷贝时中间跳过了206字节。最后将内存空间的数据覆盖到主硬盘(PhysicalDrive0)的开头部位,原始MBR遭到破坏。
第一段正好就覆盖了MBR的代码区域,所以几乎可以肯定这304字节是代码。第二段数据已经不属于MBR的范围,而且高达1952字节,很可能是用于显示动画的图像数据和音频数据。
一旦将MBR覆盖,侵入也即宣告成功,病毒作者赶紧写了一堆话想要好好炫耀一番,这段话被写入note.txt文件中,并用Windows自带的记事本打开。
遗留问题:IDA伪代码的问题以及MBR调试的问题(MBR运行在16位环境直接和硬件打交道,此阶段Windows根本没加载,OllyDbg或者WinDebug这种常用的调试器当然用不了。这时该用–Bochs(发音同“box”))
参考链接:看雪论坛彩虹猫样本分析