挖矿木马分析报告
基本信息
| 样本名称 | d48ab2e921f5c725672fce16135d1f09.vir | 
|---|---|
| 样本类型 | 挖矿木马 | 
| 样本大小 | 457 KB (468,480 字节) | 
| MD5 | d48ab2e921f5c725672fce16135d1f09 | 
简介
该挖矿木马感染受害主机后,会将自身复制到
%AppData%目录下,并以svchostx64.exe来命名,从而伪装自身。然后通过创建计划任务来维持该样本运行。样本文件的.plato节表中包含了一个开源的矿机XMRig.exe,该恶意样本再执行时通过创建自身傀儡进程,将开源矿机XMRig.exe注入其中,从而实现利用受害主机资源来进行挖矿。该样本不仅会判断受害主机当前是否处于空闲,还会监控进程。当不空闲时(也就是用户正在执行操作时)或是监控到任务管理器进程时,便结束傀儡进程,终止挖矿,来隐藏自身不被发现。
流程图

简单行为分析
复制自身
运行样本后,复制自身文件到指定目录C:\Users\<UserName>\AppData\Roaming\下,并重命名为svchostx64.exe。如图1:

创建计划任务
该样本通过调用schtasks.exe,执行如下命令:
1  | "C:\Windows\System32\schtasks.exe" /SC MINUTE /MO 1 /F /Create /TN Adasdsadas3id /tr "\"C:\Users\john\AppData\Roaming\svchostx64.exe\""  | 
创建名为==Adasdsadas3id==的计划任务,每一分钟运行一次释放出来的svchostx64.exe,如图2:

每一分钟运行一次计划任务,并迅速结束了自身程序,如图3:

进行网络连接
可以从上图中看出,再创建完计划任务后,再次==运行自身程序==,并执行了如下参数:
1  | -o monerohash.com:3333 -u 4BrL51JCc9NGQ71kWhnYoDRffsDZy7m1HUU7MRU4nUMXAHNFBEJhkTZV9HdaL4gfuNBxLPc3BeMkLGaPbF5vWtANQni58KYZqH43YSDeqY -p x -k --donate-level=1 -t 3  | 
其中含有可疑URL: monerohash.com:3333,如图4:

并与IP:107.191.99.95:3333和107.191.99.221:3333,进行TCP链接,如图5:

样本详细分析
获取dump.exe
首先通过工具查壳,显示该恶意样本没有壳,如图:

异常区段
然后查看样本的节表,发现其中.data区段很可疑。其中.data区段的virtualsize远远大于Raw Size,基本可以推测该样本是一个经过特殊处理的,如图:

混淆代码
然后将样本拖入IDA中,发现其中有大量窗体程序的API,而样本的执行行为中并没有发现有关窗体的行为。
经过分析,这些窗体程序的API全部都==存在问题==,都无法正常执行,(推断这些API是用来==迷惑分析==的)。但在这些==迷惑分析==的API中,夹杂着真正执行的程序代码。如下图,红色框标识的便是真正执行的程序代码。除红色框标识外的指令,大多都是垃圾指令,都无法正常执行。
==真正执行的程序代码:==
- 调用函数
LocalAlloc,开辟大小为0X4FCF3的堆空间 - 将地址
0x40D1C+0x7958C中的==经过加密==的汇编指令,写入开辟的堆空间中 - 执行函数
Decode_409320,==解密==堆空间中的汇编指令 - 执行开辟的堆空间中的汇编指令
 

获取dump.exe
由于在执行堆空间中的指令之前都没有执行任何功能代码,便==推测==在堆空间中,很可能会开辟虚拟空间来存储==PE文件==,然后将其展开再执行。
这里用OD跟到开辟的堆空间中,给函数VirtualAlloc下断点,然后F9运行,发现果不其然命中断点,然后再在开辟的虚拟空间中下==硬件写入断点==,果真写入了一个PE文件,==应征了推测==。这里便可将其dump下来,并起名为dump.exe,该文件便是真正要执行的程序。如图:

然后继续用OD跟,便会发现在虚拟空间中,将这个==PE文件进行展开==,然后最终跳回该PE文件的OEP处执行。
分析dump.exe
上一步将样本进行了脱壳,获取到dump.exe,该文件便是该恶意样本的主要行为程序。
其主要执行了:
- 创建互斥体
 - 复制自身到
%AppData%\svchostx64.exe - 创建计划任务,每分钟执行一次
svhostx64.exe - 创建线程,防止系统进入休眠状态
 - 获取区段
.plator中的开源矿机程序XMRig.exe - 创建==傀儡进程==,将矿机程序
XMRig.exe注入创建的傀儡进程,并监视进程,当检测到进程==任务管理器时==,便终止==傀儡进程== 
主要行为函数代码段如图:

隐式加载调用函数
该恶意样本使用大量的隐式加载调用系统API,如下图获取函数OpenMutexW,就是通过隐式加载调用的。
首先通过硬编码的方式,将要获取的函数,以及相应的模块字符串,获取到。
然后将要动态加载的DLL模块名,以及要调用的函数名作为参数,传给函数
GetProcAddress_402536,来获取要调用的API

函数:GetProcAddress_402536获取函数地址
- 该函数通过遍历
PEB->PEB_LDR_DATA->inMemoryOrderModuleList-> LDR_MODULE()-> LDR_MODULE(ntdll)->LDR_MODULE(kernel32).BaseAddress,先获取到模块kernel32的基址。 - 再执行函数
traverse_Export_402483遍历模块kernel32的导出表,来获取函数GetModuleHandleA - 再执行函数
traverse_Export_402483遍历模块kernel32的导出表,来获取函数LoadLibraryA - 然后再用获取到的
GetModuleHandleA去获取要获取DLL模块句柄,再用获取到的LoadLibraryA去加载该DLL模块句柄,就能根据传进来参数,来加载不同的DLL模块 - 然后再从加载的DLL模块中,获取想要获取函数的地址
 

- 函数:
traverse_Export_402483遍历DLL模块的导出表获取函数地址- 先遍历模块的PE头,获取到导出表结构,然后遍历导出表。
 - 遍历导出表中的名称表
AddressOfNames中的函数名去进行比较,找到想要获取的函数名。记下索引 - 在通过索引,去名称序号表
AddressOfNameOrdinals中获取索引相对应的NameOrdinal名称序号 - 再根据
NameOrdinal名称序号,去函数地址表AddressOfFunction中获取要获取的函数地址 
 

创建互斥体
创建互斥体NIHILMsINERaassdaa
- 首先通过隐式加载调用函数
OpenMutexW,来判断互斥体NIHILMsINERaassdaa是否存在,若存在便直接退出 - 当互斥体
NIHILMsINERaassdaa不存在时,便调用函数CreateMutexW来创建互斥体 

复制自身并创建计划任务
复制自身文件到%AppData%\svchostx64.exe,并添加计划任务每一分钟执行一次复制后的程序svchostx64,应征了简单行为分析==图1,图2==抓到的行为。
主要行为:
- 获取路径
%AppData%,并将其拼接为:%AppData%\svchostx64.exe - 获取当前进程的绝对路径,并与拼接出的路径进行判断,判断当前正在执行进程是否为
svchostx64.exe - 若两路径不一样时,再通过函数
CreateFileW检测svhostx64文件是否已经存在 - 若
svhostx64文件不存在,便执行函数CopyFileW,将当前执行的自身文件拷贝至%AppData%\svchostx64.exe - 当复制成功后,执行函数
Create_Schtask_4026CC,调用schtasks创建计划任务每分钟执行一次复制后的程序svchostx64 
代码如图:

函数:Create_Schtask_4026CC创建计划任务
通过执行函数ShellExecuteW,调用schtasks来执行下面指令,来创建名为==Adasdsadas3id==的计划任务,每分钟执行一次svchostx64.exe
1  | /SC MINUTE /MO 1 /F /Create /TN Adasdsadas3id /tr "\"C:\Users\john\AppData\Roaming\svchostx64.exe\  | 

创建线程,防止进入休眠
创建线程,创建死循环,每一秒执行一次函数SetThreadExecutionState,来通知系统当前进程正在使用,从而防止应用程序运行时进入休眠状态或关闭显示器
主要行为:
- 通知系统所设置的状态应保持有效
 - 启用离开模式
 - 通过重置系统空闲计时器来强制系统进入工作状态。
 
代码如图:

获取区段中的PE文件
该文件的.plato区段中存储着一个开源的矿机程序XMRig.exe,要想运行改程序首先要先获取到该矿机的PE文件
主要行为:
- 读取当前进程,遍历节表寻找区段
.plato,并获取相应区段的.plato.Virtual Adress和.plato.Virtual Size - 开辟大小为
.plato.Virtual Size的虚拟空间,并将.plato.Virtual Adress中的PE文件数据保存至开辟的虚拟空间中 
代码如图:

既然是从内存中读取了区段.plato中的PE文件数据,并且并没有将其展开,可以直接dump下来,或是直接去文件中找到该区段,直接将数据拷贝下来,然后发现拷贝下来的文件是一个名为XMRig.exe的开源的矿机,如图:

该矿机可在==GitHub==直接找到其源码,链接为:https://github.com/xmrig/xmrig

创建傀儡进程并监控进程
创建自身进程,并将上一步获取到的开源的矿机程序XMRig.exe注入该进程中并执行,其中还会监控进程,当检测到进程==任务管理器==时,便会终止傀儡进程
主要行为:
- 避免用户察觉,执行函数
JudgeSystemFree_4019E1,检测操作系统当前是否处于空闲状态。当系统处于忙碌状态,将==终止傀儡进程==,也就是只在系统空闲时实施挖矿行为,来防止用户在使用时发现。 - 解密硬编码指令
CommandLine,并转换为unicode,放入开辟好的虚拟空间中。 - 创建和当前进程一样的傀儡==子进程==,并将解密出来
CommandLine作为参数传给创建的子进程来执行。 - 将上一步获取到的开源矿机程序
XMRig.exe展开,==注入到创建的子进程中==。 - 避免用户察觉,监视当前所有进程,当检测到进程==任务管理器==时,便==终止傀儡进程==,来隐藏自身防止被发现。
 
代码如图:

- 避免用户察觉,函数
JudgeSystemFree_4019E1,检测操作系统当前是否处于空闲状态 
通过调用函数GetLastInputInfo和函数CallNtPowerInformation来检索系统空闲状态信息,从而来判断操作系统当前是否处于空闲状态,当操作系统属于空闲状态返回1,否则返回0,如图:

然后死循环,根据函数JudgeSystemFree_4019E1的==两次返回值==来进行判断,当系统处于==忙碌==时,便==终止傀儡进程,来避免被用户察觉==,其两次执行结果如下:
第一次执行函数JudgeSystemFree_4019E1

第二次执行函数JudgeSystemFree_4019E1

- 解密硬编码指令
CommandLine,并转换为unicode,放入开辟好的虚拟空间中 
然后根据第一次执行函数JudgeSystemFree_4019E1的返回的结果,执行不同操作,但所执行的代码实则却是一样的,都是解密一样的CommandLine,然后最终再将解密出来的CommandLine转换为Unicode存起来,如图:

解密出来的指令,如图:

- 创建和当前进程一样的傀儡==子进程==,并将解密出来
CommandLine作为参数传给创建的子进程来执行 
以没有控制台窗口并挂起的方式,来创建当前进程的子进程,并执行解密出来的CommandLine作为参数来执行,应征了简单行为分析==图4==抓到的行为,代码如下图:

- 将上一步获取到的开源矿机程序
XMRig.exe展开,==注入到创建的子进程中==- 先通过函数
GetThreadContext,读取线程上下文 - 再通过函数
ReadProcessMemory,读取context->Ebx+0x8的AddressOfImageBase字段,获取创建的傀儡子进程的==加载基址(随机基址)== - 再将获取到的==加载基址(随机基址)==与前面获取到的矿机程序
XMRig.exe的ImageBase进行比较。当一样时,便通过函数NtUnmapViewOfSection强制卸载==加载基址(随机基址)==处的模块,反之不做操作。 - 然后通过函数
VirtualAllocEx,远程开辟大小为XMRig.exe的sizeofImage,基址为其ImageBase的==虚拟空间== - 然后往远程开辟的==虚拟空间==中,写入文件
XMRig.exe的DOS头,并将各个区段==展开== - 再修复傀儡进程的==加载基址(随机基址)==,并通过函数
SetThreadContext,设置线程上下文,修改傀儡进程的入口点地址为XMRig.exe的AddressOfEntryPoint - 最后通过函数
NtAlertResumeThread,恢复进程,结束挂起 
 - 先通过函数
 

- 避免用户察觉,监视当前所有进程,当检测到进程==任务管理器==时,便终止傀儡进程
 
创建了两个死循环,来==避免用户察觉==。
其中第一个死循环,前面分析
JudgeSystemFree_4019E1中提到过,来判断系统是否处于忙碌,当处于==忙碌时==,便终止傀儡进程,来避免用户察觉。不过这里还有一个检测函数traverse_Proc_4014EF,遍历进程,当检测到进程名为Taskmgr便返回1,退出循环,终止傀儡进程。第二个死循环,不断执行检测函数
traverse_Proc_4014EF监控进程。当检测到进程Taskmgr,便一直睡眠,直到检测不到进程Taskmgr时,便从新执行当前函数inject_4010C5,创建傀儡进程,注入矿机。

- 函数
traverse_Proc_4014EF 
- 函数
 
快照系统中的所有进程,然后遍历所有进程,比较进程名,当遇到Taskmgr,便返回1,如图:

分析矿机程序
前面分析也有提到,dump.exe的最后一个区段.plato中包含一个矿机程序XMRig.exe,并且该矿机程序XMRig.exe是开源的,可以直接在网上找到,并下载,如图:

其中我们比较关注的就是傀儡进程,执行的指令对应的是什么意思,这里我们可以在GitHub上查看该矿机的帮助手册README,链接: https://github.com/xmrig/xmrig ,通过帮助手册中的Options,查看该框架的指令,如下:
1  | -a, --algo=ALGO specify the algorithm to use  | 
然而该样本执行的参数为:
1  | -o monerohash.com:3333 -u 4BrL51JCc9NGQ71kWhnYoDRffsDZy7m1HUU7MRU4nUMXAHNFBEJhkTZV9HdaL4gfuNBxLPc3BeMkLGaPbF5vWtANQni58KYZqH43YSDeqY -p x -k --donate-level=1 -t 3  | 
其各项参数解析如下表:
| Options | Meaning | Value | 
|---|---|---|
| - o | URL of mining server(矿池) | monerohash.com:3333 | 
| - u | username for mining server(用户名) | 4BrL51JCc9NGQ71kW…. | 
| - p | password for mining server(密码) | x | 
| - k | send keepalived packet for prevent timeout (防止超时) | NULL | 
| -donate-level | Default donation 5% (5 minutes in 100 minutes) can be reduced to 1%(捐赠比例) | 1 | 
| - t | number of miner threads(线程数量) | 3 | 
其中矿池:monerohash.com:3333,为门罗币的矿池。
也就说明该样本通过创建傀儡进程,注入这个开源的矿机程序XMRig.exe,连接到(门罗币)的矿池,用病毒作者自己的用户名密码登陆上,来进行挖矿来获利的。
样本溯源
文件信息
| FileName | FileSize | MD5 | 
|---|---|---|
| d48ab2e921f5c725672fce16135d1f09.vir | 468480 bytes | D48AB2E921F5C725672FCE16135D1F09 | 
| svchostx64.exe | 468480 bytes | D48AB2E921F5C725672FCE16135D1F09 | 
| XMRig.exe | 283136 bytes | C131DE679C5B230CDD3415A47F53ED10 | 
网络信息
矿池URL为:monerohash.com:3333
| 矿池的 IP | 服务器所在地 | 
|---|---|
| 107.191.99.221 | 美国 纽约 | 
| 107.191.99.95 | 美国 纽约 | 
IOCs
| 互斥体 | NIHILMsINERaassdaa | 
|---|---|
| 释放文件名 | svchostx64.exe | 
| 计划任务名 | Adasdsadas3id | 
| 特定区段名 | .plato | 
| 矿池 | monerohash.com:3333 | 
查杀方案
- 1.删除计划任务
 
由于该样本只在复制自身之后才会创建计划任务,因此我们可以直接删除该计划任务。
打开
CMD,执行指令schtasks /delete /TN Adasdsadas3id /F,删除计划任务。
- 2.将文件MD5加入杀软黑名单
 
由于该样本是复制自身到%AppData%目录下的svhostx64.exe,两文件的MD5值是一样的,并且该恶意样本是通过创建傀儡进程将自身文件中的矿机程序注入其中,因此只需要删除该文文件,便能实现查杀。
重启电脑,将恶意样本的
MD5值**D48AB2E921F5C725672FCE16135D1F09**,加入杀软的应用黑名单中,进行一次全盘查杀
总结
该挖矿木马通过创建傀儡进程,将自身最后一个区段存储的开源矿机程序注入到傀儡进程中,从而进行挖矿,使攻击者利用受害者的主机赚取加密数字货币来获利。并且该挖矿木马还会检测当前系统是否空闲,是否启用进程管理器等操作来隐蔽自身,避免用户察觉。长期被感染的主机会大大降低系统硬件的寿命。因此大家应不要从不正规的网址下载文件,或是从不确定来源的地方接收文件,安装杀软,定期杀毒,做好防范工作。




