# 恶意传播之——社工+白+黑
0x00 背景
=======
* * *
日前实验室捕获一个样本。远远望去,像是搜狗输入法,在测试机中点开一看,弹出一款游戏的物价表,再看PE文件属性,还带正常着数字签名,一副人畜无害的样子。经过一番认真分析后。发现远没有这么简单,这里就分析过程记录一下,希望其他安全工作者有些许帮助。
先介绍一下所谓白名单免杀。随着病毒与杀软之间的斗争,杀软的手段不断地增多、增强,由早期传统的特征码匹配算法发展到目前虚拟机技术、实时监控技术等流行的查杀算法。但始终存在一种最直接也最根本的免杀方式——白名单免杀。病毒就安安静静地躺在杀软的白名单中,谁闲的没事会去查水表呢?
当了解了白名单免杀的基本含义之后,就可以针对样本进行深入的研究,本文以下内容就是笔者拿到样本之后,逐步分析样本主要功能的完整过程,其分析环境如下:
* 分析环境:win 7 x86 VMware
* 分析工具:IDA、CFF、OD
0x01 样本概述
=========
* * *
样本包含5个文件:
| File name | size | MD5 | attribute |
| — | — | — | — |
| nvvsvc1.exe.exe | 451.50 KB (462336 bytes) | 4D9B3A508BC2402A86E10F7907022263 | hidden |
| HWSignature.dll | 48.50 KB (49664 bytes) | 85F50E1D2DE076079D98F09416E4C710 | hidden |
| HanziSort.dat | 158.75 KB (162557 bytes) | 4FB42CBC7ADD3CF2AB3F0A99B9E7CE25 | hidden |
| 图1 | Shortcut linked to cmd | cmd /c nvvsvc1.exe & exit | Shortcut |
| 01.jpg.jpg | 99.07 KB (101446 bytes) | 78501660AD39494A7248BA0C96989494 | hidden |
* nvvsvc1.exe:即为搜狗输入法的更新工具,用virusbook查看后可判定完全没有问题。此外,该文件有正常的数字签名,见下图。
![p1](http://drops.javaweb.org/uploads/images/b75a2ca4f8f27182ba7f1f7eab77ff112431539a.jpg)
* HWSignature.dll:这个DLL原本是搜狗输入法的硬件签名DLL,该样本中被劫持为恶意劫持。
* HanziSort.dat:原本为搜狗输入法与汉字相关的数据文件,该样本中被替换为其他数据文件。
* 01.jpg.jpg:一副jpg图片,内容为《怪物猎人官方最新价格表》,后文有展示。
* 图1:指向cmd的快捷方式,其参数为`cmd.exe /c nvvsvc1.exe & exit`
其中,nvvsvc1.exe为主程序,其目的是加载HWSignature.dll,而HWSignature.dll会加载并解码HanziSort.dat, 进一步的,HanziSort.dat会再次解码自身并在内存中释放svchost2.dll,此后手动加载svchost2.dll,该DLL为包含恶意程序的主要功能。
传播方式:以《怪物猎人官方最新物价表》为鱼饵进行钓鱼,下载解压后,其他文件隐藏,只能看到名称为“图1”的文件,点开后确实会展示图片,但木马也会加载。**笔者建议广大游戏玩家,下载的攻略要先看清是什么东西,再点开查看内容。**
0x02 主程序分析
==========
* * *
拿到样本之后,首先放到virusbook查了查,主程序想必没问题,而除此之外的一个DLL就被查出有问题了。很明显,这是一个通过DLL劫持加载自己的木马样本,这种通过DLL劫持的木马,可以算是白名单免杀吗?这个问题先放一放,后文(0x8 结语)会给出笔者的看法。
IDA分析主程序,绝大部分都是输入法相关的操作,中规中矩。值得注意的是,此处创建了8个线程。
![p2](http://drops.javaweb.org/uploads/images/06e1a3dc1373280f802d2d5a7ee616ec0a9ebb25.jpg)
这其中第4个线程,即执行sub_427C80的线程会进一步调用sub_42F090函数,在该函数的子函数中,会加载HWSignature.dll,但此处被样本劫持,用来执行其恶意功能。
![p3](http://drops.javaweb.org/uploads/images/70acfb1615cc2f324f0ceb23d86779d42a556601.jpg)
0x03 DLL分析
==========
* * *
跟进这个DLL,进一步分析该DLL的行为。无关行为不说,该DLL会打开HanziSort.dat文件:
![p4](http://drops.javaweb.org/uploads/images/010bab5e54687315e0c87df61bcfbe7c0b652d3f.jpg)
读取其内容,并解码:
![p5](http://drops.javaweb.org/uploads/images/f027edc01f9f306531bc009181a4419d296bb50a.jpg)
其解码方式很简单,只是把读取到的文件内容逐字节的与0x56做异或运算。解码之后,成为包含可执行指令的程序段:
![p6](http://drops.javaweb.org/uploads/images/40781b57b4e3c1808597c2ca61a8416dc3c2515e.jpg)
此后,程序会通过retn的方式跳到解码的代码段执行。
0x04 DAT分析
==========
* * *
在DAT解码的代码中,首先会寻找解码内容为0xDDCCBBAA的位置:
![p7](http://drops.javaweb.org/uploads/images/a1e6c02e3746a864f37d441ba41b2138402493f0.jpg)
通过该地址,可以辅助完成一些列的定位操作,具体内容不做介绍。进而会调用VirtualAlloc函数分配内存空间,然后通过memcpy函数将指定数据拷贝到申请的内存中:
![p8](http://drops.javaweb.org/uploads/images/1bf5aab4e558a8b0f10e9f7f70c61b2daa43c39c.jpg)
![p9](http://drops.javaweb.org/uploads/images/a1adf872cc15764f332477abd088cc34a01fd1dc.jpg)
而拷贝过去的内存段,会再一次进行解码:
![p10](http://drops.javaweb.org/uploads/images/aa1907a2d86a5d7fc5f8758005dd5a5b184b2977.jpg)
其解码方式同样比较简单,是逐字节与0xCC进行异或运算。当完整所有解码工作之后,可以发现解码之后的内存为一个完整的PE文件:
![p11](http://drops.javaweb.org/uploads/images/f71860a81fcecf5cbbc2aca3bb6241a44223dd12.jpg)
将该PE文件dump出来,用查看CFF看下,可以确认是个完整的DLL:
![p12](http://drops.javaweb.org/uploads/images/907228d1c35e73ed667909ca492b5bef2dda1089.jpg)_(忽略一些细节吧。笔者懒得打码了。)_
这个DLL叫做svchost2.dll,后面的代码可想而知,新申请一块内存
![p13](http://drops.javaweb.org/uploads/images/9a59d5c755c04dcbacb9b29246fec689e7cb713d.jpg)
然后手动完成PE的加载流程:
![p14](http://drops.javaweb.org/uploads/images/d2cedba1553bb5920123bc7e966d8792ad93ef72.jpg)
以及根据导入表和重定位表做一些修复工作,并加载所需的各种DLL,最后调用VirtualProtect更改页保护。
![p15](http://drops.javaweb.org/uploads/images/bcee8db4c03daddf1813fee7f4dbdbd2fb2098a8.jpg)
完成以上操作之后,调用DLL main函数:
![p16](http://drops.javaweb.org/uploads/images/cd64e376ded421c9beb1cd5219f239ae772c6e26.jpg)
DLL的主函数并没有什么需要深入分析的地方,这里略过。DLL main返回后,会查找DLL导出的mystart函数:
![p17](http://drops.javaweb.org/uploads/images/0cdecace1270b9c504da46f7bdbebd5cd54d7bc2.jpg)
最后调用mystart:
![p18](http://drops.javaweb.org/uploads/images/7fd53a800df93e98a244fb90b5afc48d8955f45d.jpg)
0x05 mystart分析
==============
* * *
在该函数中,首先会获得当前仅进程的名字,并判断名字中是否包含”1.exe”字符串。
![p19](http://drops.javaweb.org/uploads/images/296298915630b8f39f97227422b01a47ef2b3e8f.jpg)
获得的样本中,当然是包含该字符串的。接下来,会进行一些有意思的事。首先会调用WinExec执行”`taskkill /f /im cmd.exe`”命令,然后创建一个互斥体。
![p20](http://drops.javaweb.org/uploads/images/4cf19a3ec252867c0ac41fcc9a8c1bd83eb1639f.jpg)
进一步的,该样本会在C:\Users\zzz\AppData\Roaming创建一个文件夹,其名字随机:
![p21](http://drops.javaweb.org/uploads/images/749e8e890f8953b54930c7320bbce708f421856d.jpg)
在本次分析中为:C:\Users\zzz\AppData\Roaming\dptpbzwoztxwrh,并将样本所在的文件夹中所有文件都复制到该目录下,包括ida生成的几个文件,但排除01.jpg.jpg。对于这幅图片,该样本会调用cmd执行rundll32.exe shimgvw.dll imageview_fullscreen 01.jpg.jpg,其作用就是把样本中的01.jpg.jpg展示出来:
![p22](http://drops.javaweb.org/uploads/images/8dee67ccbb89011b26391092391eb541b5d766d8.jpg)_(01.jpg.jpg :什么仇什么怨?)_
如此一来,受害者看到了想了解的《价格表》,也不会怀疑该文件是木马了。此外,复制到Roaming的主程序会重命名为MSUpdateXXXXXXXX.exe,XXXXXXXX表示8位随机字母。注意,IDA生成的几个文件也会被复制过去并重命名。
![p23](http://drops.javaweb.org/uploads/images/417bc59d1fb19087e57de6152af35b37f1c81a5b.jpg)
拷贝完成之后,释放互斥体,并Sleep(0x2EE0)的时间。
![p24](http://drops.javaweb.org/uploads/images/eabd0202dd0296a168c53065b6c0fa8389257c44.jpg)
并注册表增加一些键值:
![p25](http://drops.javaweb.org/uploads/images/0b0996b500ed6e89a2b0e02c12757e0481ccf476.jpg)
最后,通过shellexecute执行刚刚复制到Roaming的样本文件。
![p26](http://drops.javaweb.org/uploads/images/d874797559b717ddbc22a93d14a6868589fe60a9.jpg)
0x06 第二次执行分析
============
* * *
当第二次执行时,之前的行为都是类似的,只有在mystart函数中,出现了变化。由于当前进程是复制到Roaming下的镜像文件,重命名之后不包含”1.exe”字符串(参考上文)。所以会执行到另一个分支,调用Fi函数。
![p27](http://drops.javaweb.org/uploads/images/fe28cb71d273364318a9ba1738efdae79a214b17.jpg)
该函数为svchost2.dll的另外一个导出函数。该函数会隐藏自己的进程名以及其他的信息:
![p28](http://drops.javaweb.org/uploads/images/90806a291185d64d4c0a4a107a2feb152e63a5d7.jpg)
隐藏结果使自己的进程名变为csrss.exe的,如图:
![p29](http://drops.javaweb.org/uploads/images/dc7ddf10931e428a5c614180035e4b7538c62acd.jpg)
但这种隐藏手段并不高级,随便一个工具就能识别出来。
进而,会调用Fa函数,该DLL的另一个导出函数。在该函数中出现了一些网络行为。首先,会连接139.196.184.116:34176
![p30](http://drops.javaweb.org/uploads/images/fe59fa914f146a727209bf69eec1772f76d70341.jpg)
并发送数据:
![p31](http://drops.javaweb.org/uploads/images/f76c7de59c342e2f92b9c87a3484fbb11b19032c.jpg)
该数据是怎么来的,暂时没有必要追究。有需要时,可以进一步分析,不过,可以肯定的是,对于同一台机器,每次发送的数据是一样的,应该是作为机器的ID标识。发送之后,会接收到如下内容:
![p32](http://drops.javaweb.org/uploads/images/4f77c149b91e7613bcd320efcde1efcef50fd5e7.jpg)
针对返回的内容,会判断是否含有”Set-Cookie:”字符串,如果有,则取出:
![p33](http://drops.javaweb.org/uploads/images/3c6337c227fe523534213eca714f59902cc2f854.jpg)
接下来,会用该Cookie作为机器的标识。
进而,会连接139.196.184.116:35131地址:
![p34](http://drops.javaweb.org/uploads/images/8bf166e2f6fbe7c4fbdfe52cccfddb153065f76c.jpg)
但是该端口已经挂掉了,无法连接上。所以,笔者只好重新定向到自己的IP,并模拟其通信。 连接上IP之后,会发送一些随机生成的数据:
![p35](http://drops.javaweb.org/uploads/images/e2d78e8536293c74f2703421d1c1435d26431f5c.jpg)
本机的监听结果如下:
![p36](http://drops.javaweb.org/uploads/images/e46a922d81ac7bb3dc80da90bdc03a9cc4518594.jpg)
发送3次随机生成的数据之后,会创建新线程用于接收返回数据:
![p37](http://drops.javaweb.org/uploads/images/5cebd193b6a66c5c16c86a3fe615408e90e717d1.jpg)
该线程会接收来自139.196.184.116:35131回复的数据,但是由于该端口已经挂掉了,笔者只能随意的回复点什么东西,比如说ADLab@westone.com.cn
![p38](http://drops.javaweb.org/uploads/images/eb0e371361e2199c10eb5b6b4ea8b35dc11b50bf.jpg)
接收到回复之后,会在sub_12A50F0中做解码工作。其解码工作首先会将受到的数据逐比特与0xE9异或。
![p39](http://drops.javaweb.org/uploads/images/a9e7112c12beb73d6222ef343d50e079ce8c463b.jpg)
进而会对长度进行判断,然后对几个关键位置的内容进行判断,如果出现不符合的情况就会结束该线程;如果全部满足条件,则调用zlib 1.2.8版的库函数解压接收到的数据。
![p40](http://drops.javaweb.org/uploads/images/19a5adc2aaa32a0b8d3199e100c4a77b121f7f44.jpg)
最后根据解压缩出来的内容选择初始化某个对象,并调用该对象的成员函数,实现恶意功能。
![p41](http://drops.javaweb.org/uploads/images/5d2e18fef4fff545012310384d7b8d713587886d.jpg)
执行完毕后,该线程会进入循环接收新的数据,并执行相应功能。此外,主线程创建了上述之后,会统计当前系统的各种信息:
![p42](http://drops.javaweb.org/uploads/images/cdd756b05cc496ecb4261e50ca2a8d946e4fc89c.jpg)
其中sub_100010F0实现捕获摄像头信息的相关操作。当获取了所有的信息之后,发送给目标地址,目标地址同样挂掉了。最后同样进入发送和接收的循环中。
0x07 恶意功能分析
===========
* * *
该样本的恶意功能比较多,现随机展示一个通过匿名双管道实现远程CMD的功能。该功能由编号0x31的分支实现。
![p43](http://drops.javaweb.org/uploads/images/aae3d8f8dffea7f8b98030e5aa86c0e1b7e2f438.jpg)
详情参考sub_10007DC0函数,该函数首先会调用sub_10004C00 初始化socket,进而调用sub_1000F060创建管道并启动CMD进程:
![p44](http://drops.javaweb.org/uploads/images/0ca70025c94afa13924fe1154b57bcf20bca6ef5.jpg)
![p45](http://drops.javaweb.org/uploads/images/23d5476e1ace66faa925082ed3ce49dd6ab8fd56.jpg)
0x08 结语
=======
* * *
这个样本并不复杂,但是能够实现较为全面的木马功能,另外通过游戏攻略进行传播,利用白+黑的方式过杀软。哪怕现在HWSignature.dll会被查杀。但有白名单宿主进程的话,绕过杀软并不困难(基本瞬间就能想到好几种绕过检测的方式)。因此这种模式是值得我们警惕的。
请登录后查看评论内容