1.样本概况

1.1 样本信息

病毒名称:熊猫烧香
所属家族:感染型蠕虫病毒
MD5: 512301C535C88255C9A252FDF70B7A03
SHA1: CA3A1070CFF311C0BA40AB60A8FE3266CFEFE870
CRC32: E334747C

1.2 测试环境及工具

测试环境:虚拟机Windows 7 32位 测试工具:火绒剑、PCHunter、PEiD、OllyDbg、IDA

1.3 分析目标

分析病毒具体行为,找到病毒行为的具体实现代码,了解病毒实现原理,评估病毒的威胁程度。

1.4 主要行为概述

病毒行为:
①自我复制样本到C:\Windows\driver\spo0lsv.exe目录下,运行spo0lsv.exe(样本)
②在每个目录下创建了Desktop_.ini,内容为当前日期
③在C盘根目录下创建autorun.inf文件,该文件指定了自动启动的文件为根目录下的setup.exe(即样本)
④对程序目录下的exe进行了感染,图标变为熊猫烧香,打开exe时自动打开病毒
⑤设置注册表启动项为C:\Windows\driver\spo0lsv.exe
⑥删除杀毒软件注册表启动项,关闭服务
⑦访问网站,下载恶意代码

2.具体行为分析

2.1 主要行为

第一部分:自我复制:
熊猫烧香病毒分析报告 - 图2
第二部分:感染文件
熊猫烧香病毒分析报告 - 图3
第三部分:自我保护
熊猫烧香病毒分析报告 - 图4
通过火绒剑和PCHunter监视病毒,发现病毒具有以下行为:

①自我复制样本到C:\Windows\System32\drivers\spo0lsv.exe目录下,运行spo0lsv.exe(样本)

熊猫烧香病毒分析报告 - 图5

②在每个目录下创建了Desktop_.ini,内容为当前日期 熊猫烧香病毒分析报告 - 图6

③在C盘根目录下创建autorun.inf文件,该文件指定了自动启动的文件为根目录下的setup.exe(即样本)

熊猫烧香病毒分析报告 - 图7

④通过火绒剑对程序目录下的文件进行了感染,图标变为熊猫烧香,通过PEID工具感染后exe文件和病毒文件信息相同,运行exe时会自动打开病毒文件。

熊猫烧香病毒分析报告 - 图8
熊猫烧香病毒分析报告 - 图9

⑤设置注册表启动项为C:\Windows\System32\drivers\spo0lsv.exe

熊猫烧香病毒分析报告 - 图10

⑥删除杀毒软件注册表启动项

熊猫烧香病毒分析报告 - 图11

2.2 恶意代码分析

2.2.1 加固后的恶意代码树结构图

该病毒的壳是FSG v2.0,原程序和脱壳后程序对比: 熊猫烧香病毒分析报告 - 图12

2.2.2 恶意程序的代码分析片段

恶意程序的主要功能框架:
熊猫烧香病毒分析报告 - 图13

①自我复制行为

熊猫烧香病毒分析报告 - 图14

②遍历文件,感染特定类型的文件,包括可执行文件,网页文件以及备份文件。

熊猫烧香病毒分析报告 - 图15
熊猫烧香病毒分析报告 - 图16
修改文件图标,修改PE文件内容,起始部分是病毒文件,中间插入了部分代码,末尾添加感染标识:“whboy”+原文件名+”.exe”+原文件大小,修改原文件图标为熊猫烧香图标。 熊猫烧香病毒分析报告 - 图17
PE文件感染后
熊猫烧香病毒分析报告 - 图18

③设置第一个定时器 判断C盘的根目录下是否存在autorun.inf和setup.exe文件,若不存在则创建文件,并向autorun.inf文件写入内容,指定setup.exe为自启动文件,并且隐藏文件。

熊猫烧香病毒分析报告 - 图19

④第三个关键函数内有六个定时器

熊猫烧香病毒分析报告 - 图20
(1)修改病毒的注册表启动项,设置隐藏
熊猫烧香病毒分析报告 - 图21
2)检测杀毒软件,关闭杀软进程,删除杀毒软件注册表自启动项 病毒会检测系统的安全服务和当时流行的杀毒软件,如防火墙、金山毒霸、卡巴斯基、江民等杀毒软件。
熊猫烧香病毒分析报告 - 图22 熊猫烧香病毒分析报告 - 图23
通过遍历进程,查找窗口等方式定时检测杀毒软件,检测到杀毒软件结束杀毒软件进程。
熊猫烧香病毒分析报告 - 图24
熊猫烧香病毒分析报告 - 图25
大部分使用结束进程API,发WM_QUIT消息结束杀软进程,针对某些杀毒软件使用虚拟按键的方式关闭进程,例如Pjf(ustc)冰刃。

熊猫烧香病毒分析报告 - 图26

(3)通过cmd命令删除共享

熊猫烧香病毒分析报告 - 图27
(4)网络异常,下载恶意代码
熊猫烧香病毒分析报告 - 图28
下载恶意代码行为
熊猫烧香病毒分析报告 - 图29

3.解决方案

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

①病毒特征:字符串 xboy 、whboy、武汉男生感染下载者**
②Yara规则

  1. rule vir_3601
  2. {
  3. strings:
  4. $text_1="xboy "
  5. $text_2="whboy"
  6. $text_3="***武*汉*男*生*感*染*下*载*者***"
  7. condition:
  8. $text_1 or $text_2 or $text_3
  9. }

③利用ClamAv查杀
熊猫烧香病毒分析报告 - 图30

3.2 手工查杀步骤

(1)利用PCHunter工具结束进程,并删除spo0lsv.exe文件
(2)清除启动项,关闭svcshare启动项
(3)删除autorun.inf和setup.exe
(4)清除每个盘符下的Desktop_.ini文件
(5)打开注册表,HKLM\Microsoft\Windows\CurrentVersion\Explore Advanced\Folder\Hidden\SHOWALL\CheckValue,将CheckValue的值设为1。

3.3 熊猫专杀工具

熊猫烧香病毒感染文件只是做了一定的修改,并没有对文件进行加密,所以可以编写专杀工具清除病毒,恢复感染文件。其实就是将手工查杀步骤利用程序自动化完成。 专杀工具源码如下:

  1. #include "pch.h"
  2. #include <iostream>
  3. #include <TlHelp32.h>
  4. #include <tchar.h>
  5. #include <strsafe.h>
  6. #include <Shlwapi.h>
  7. #define VIRSIZE 0x7531 //熊猫病毒大小
  8. //************************************
  9. // 功能: 查找熊猫病毒进程
  10. //************************************
  11. BOOL FindVirProcess(CString nProcessName,LPDWORD lpPid)
  12. {
  13. PROCESSENTRY32 pe32;
  14. pe32.dwSize = sizeof(pe32);
  15. HANDLE nSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  16. BOOL nRet = Process32First(nSnapShot, &pe32);
  17. while (nRet)
  18. {
  19. if (nProcessName == CString(pe32.szExeFile))
  20. {
  21. *lpPid = pe32.th32ProcessID;
  22. return TRUE;
  23. }
  24. nRet = Process32Next(nSnapShot, &pe32);
  25. }
  26. return FALSE;
  27. }
  28. //************************************
  29. // 功能: 删除病毒文件
  30. //************************************
  31. VOID DeleteVirFile(CString szPath)
  32. {
  33. SetFileAttributes(szPath, FILE_ATTRIBUTE_NORMAL);
  34. DeleteFile(szPath);
  35. }
  36. //************************************
  37. // 功能: 获取PC盘符列表
  38. //************************************
  39. VOID GetDriverList(vector<CString> &DiverList)
  40. {
  41. TCHAR szDrive[MAX_PATH];
  42. TCHAR szRootPath[MAX_PATH] = {};
  43. GetLogicalDriveStrings(MAX_PATH - 1, szDrive);
  44. TCHAR* lpPath = szDrive;
  45. while (*lpPath != 0) {
  46. _tcscpy_s(szRootPath, lpPath);
  47. szRootPath[2] = _T('\0');
  48. //szRootPath[-2] = L'\0';
  49. DiverList.push_back(szRootPath); //取出第一个盘符路径
  50. lpPath += _tcslen(lpPath) + 1;
  51. }
  52. }
  53. //************************************
  54. // 功能: 扫描文件
  55. //************************************
  56. VOID ScanFile(CString lpPath)
  57. {
  58. //删除文件Desktop_.ini
  59. DeleteConfig(lpPath);
  60. //1. 构造路径
  61. CString szFilePath = lpPath;
  62. szFilePath += _T("\\*");
  63. //WCHAR szFilePath[MAX_PATH];
  64. //StringCbCopy(szFilePath, MAX_PATH, lpPath);
  65. //StringCbCat(szFilePath, MAX_PATH, L"\\*");
  66. //2. 第一次遍历
  67. WIN32_FIND_DATA wfd = { 0 };
  68. HANDLE hFile = FindFirstFile(szFilePath, &wfd);
  69. if (hFile != INVALID_HANDLE_VALUE)
  70. {
  71. do
  72. {
  73. CString szFullPath = lpPath;
  74. //3.1 判断是否是本级目录或上级目录
  75. if (!lstrcmp(wfd.cFileName, L".") || !lstrcmp(wfd.cFileName, L".."))continue;
  76. szFullPath += _T("\\");
  77. szFullPath += wfd.cFileName;
  78. //3.4 如果不是目录,获取详细信息
  79. if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  80. {
  81. ScanFile(szFullPath);
  82. }
  83. else
  84. {
  85. //恢复文件
  86. RecoveryFile(szFullPath, wfd.cFileName);
  87. }
  88. } while (FindNextFile(hFile, &wfd));
  89. }
  90. }
  91. //************************************
  92. // 功能: 恢复感染文件
  93. //************************************
  94. void RecoveryFile(CString nFilePath, CString nFileName)
  95. {
  96. int nVirType = 0;
  97. CString nLastName;
  98. nLastName = PathFindExtension(nFileName);
  99. nLastName.MakeUpper();
  100. if (nLastName == ".EXE" || nLastName == ".SCR" || nLastName == ".PIF" || nLastName == ".COM")
  101. nVirType = 1;
  102. else if (nLastName == ".HTML" || nLastName == ".HTM" || nLastName == ".ASP" || nLastName == ".ASPX" || nLastName == ".JSP" || nLastName == ".PHP")
  103. nVirType = 2;
  104. else return;
  105. //exe,scr,pif,com,htm,html,asp,php,jsp,aspx
  106. // 1.读取文件到内存
  107. HANDLE hFile = CreateFile(nFilePath,
  108. GENERIC_READ, FALSE, NULL, OPEN_EXISTING,
  109. FILE_ATTRIBUTE_NORMAL, NULL);
  110. if (hFile == INVALID_HANDLE_VALUE)
  111. {
  112. printf("打开文件 %s 失败--%s\n", (CStringA)nFileName.GetBuffer(),
  113. (CStringA)nFilePath.GetBuffer());
  114. printf("错误代码--%d\n", GetLastError());
  115. return;
  116. }
  117. // 获取文件大小
  118. DWORD dwSize = GetFileSize(hFile, NULL);
  119. CHAR* pFile = new CHAR[dwSize]{};
  120. // 读取文件内容
  121. DWORD dwRead;
  122. SetFilePointer(hFile, 0, NULL, FILE_BEGIN); //设置文件指针
  123. ReadFile(hFile, pFile, dwSize, &dwRead, NULL); //读取文件
  124. // 关闭文件句柄
  125. CloseHandle(hFile);
  126. //恢复文件 病毒感染标识:whboy+原文件名+0x2E+(exe/PIF等)+0x02+原文件大小+0x01
  127. int i = 0;
  128. if (nVirType == 1) //可执行文件恢复
  129. {
  130. //获取原文件大小
  131. for (i = 0; i < 13; i++)
  132. {
  133. if (*(pFile + dwSize - 13 + i) == (char)0x02)break; //0x02是分隔符
  134. }
  135. if (i == 13 || * (pFile + dwSize - 1) != (char)0x01) //0x01是结束符
  136. {
  137. //printf("未感染文件!%s\n", (CStringA)nFilePath.GetBuffer());
  138. delete[]pFile;
  139. return;
  140. }
  141. char nTemp[13]{};
  142. DWORD nExeSize = 0;
  143. size_t nCopySzie = 13 - i - 2;
  144. memcpy_s(nTemp, 13, (pFile + dwSize - 13 + i + 1), nCopySzie);
  145. sscanf_s(nTemp, "%d", &nExeSize);
  146. if (nExeSize <= 0)
  147. {
  148. delete[]pFile;
  149. return;
  150. }
  151. printf("感染文件类型:%s,尺寸:%d\n", (CStringA)nLastName.GetBuffer(), nExeSize);
  152. char *NewFile = new char[nExeSize] {};
  153. memcpy_s(NewFile, nExeSize, (pFile + VIRSIZE), nExeSize);
  154. if (!DeleteFile(nFilePath))
  155. {
  156. printf("修复%s失败!%s\n", (CStringA)nLastName.GetBuffer(),
  157. (CStringA)nFilePath.GetBuffer());
  158. delete[]NewFile;
  159. delete[]pFile;
  160. return;
  161. }
  162. // 1.写入文件
  163. HANDLE hFile = CreateFile(nFilePath,
  164. GENERIC_WRITE, FALSE, NULL, CREATE_NEW,
  165. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
  166. if (hFile == INVALID_HANDLE_VALUE)
  167. {
  168. printf("写入文件失败\n");
  169. return;
  170. }
  171. DWORD dwWrite;
  172. WriteFile(hFile, NewFile, nExeSize, &dwWrite, NULL); //读取文件
  173. CloseHandle(hFile);
  174. if (dwWrite == nExeSize)
  175. {
  176. delete[]NewFile;
  177. printf("修复%s成功!%s\n", (CStringA)nLastName.GetBuffer(),
  178. (CStringA)nFilePath.GetBuffer());
  179. }
  180. }
  181. else //网页文件恢复
  182. {
  183. CStringA nFileCode(pFile);
  184. if (nFileCode.Find("www.ac86.cn/66/index.htm") != -1)
  185. {
  186. int nHtmlSize = dwSize - 76;
  187. char *NewFile = new char[nHtmlSize] {};
  188. memcpy_s(NewFile, nHtmlSize, pFile, nHtmlSize);
  189. if (!DeleteFile(nFilePath))
  190. {
  191. printf("修复%s失败!%s\n", (CStringA)nLastName.GetBuffer(),
  192. (CStringA)nFilePath.GetBuffer());
  193. delete[]NewFile;
  194. delete[]pFile;
  195. return;
  196. }
  197. HANDLE hFile = CreateFile(nFilePath,
  198. GENERIC_WRITE, FALSE, NULL, CREATE_NEW,
  199. FILE_ATTRIBUTE_NORMAL, NULL);
  200. if (hFile == INVALID_HANDLE_VALUE)
  201. {
  202. printf("创建网页文件失败--%s\n", (CStringA)nFilePath.GetBuffer());
  203. return;
  204. }
  205. DWORD dwWrite;
  206. WriteFile(hFile, NewFile, nHtmlSize, &dwWrite, NULL); //写入文件
  207. CloseHandle(hFile);
  208. if (dwWrite == nHtmlSize)
  209. {
  210. delete[] NewFile;
  211. printf("修复%s成功!%s\n", (CStringA)nLastName.GetBuffer(),
  212. (CStringA)nFilePath.GetBuffer());
  213. }
  214. }
  215. }
  216. delete[] pFile;
  217. pFile = nullptr;
  218. }
  219. //************************************
  220. // 功能: 删除配置文件
  221. //************************************
  222. void DeleteConfig(CString szPath)
  223. {
  224. // 1.构造路径
  225. CString szFilePath = szPath;
  226. szFilePath += _T("\\Desktop_.ini");
  227. // 2.删除文件
  228. WIN32_FIND_DATA wfd = { 0 };
  229. HANDLE hFile = FindFirstFile(szFilePath, &wfd);
  230. if (hFile == INVALID_HANDLE_VALUE)
  231. {
  232. return; //文件不存在
  233. }
  234. FindClose(hFile);
  235. DeleteVirFile(szFilePath);
  236. printf("删除Desktop_.ini成功--%ls\n", szFilePath.GetBuffer());
  237. }
  238. int main()
  239. {
  240. // 1.结束病毒进程,删除文件
  241. DWORD dwPid = 0;
  242. FindVirProcess("spo0lsv.exe", &dwPid);
  243. HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
  244. TerminateProcess(hProcess, 0);
  245. DeleteVirFile("C:\\Windows\\System32\\drivers\\spo0lsv.exe");
  246. printf("完成----结束病毒进程\n");
  247. // 2.删除病毒自启动项
  248. //HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run\svcshare
  249. HKEY hKey = NULL;
  250. int nError = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Run\\", &hKey);
  251. if (nError != ERROR_SUCCESS) MessageBoxA(NULL, "打开注册表失败1", "提示", MB_ICONWARNING);
  252. RegDeleteValueA(hKey, "svcshare");
  253. RegCloseKey(hKey);
  254. printf("完成----删除病毒自启动项\n");
  255. // 3.恢复注册表CheckValue值
  256. //HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Folder\Hidden\SHOWALL\\CheckedValue
  257. nError = RegOpenKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced\\Folder\\Hidden\\SHOWALL\\", &hKey);
  258. if (nError != ERROR_SUCCESS) MessageBoxA(NULL, "打开注册表失败2", "提示", MB_ICONWARNING);
  259. DWORD nVal = 1;
  260. RegSetValueExA(hKey, "CheckedValue", 0, REG_DWORD, (CONST BYTE*)&nVal, sizeof(DWORD));
  261. RegCloseKey(hKey);
  262. printf("完成----恢复注册表CheckValue值\n");
  263. // 4.删除autorun.inf和setup.exe
  264. DeleteVirFile("C:\\autorun.inf");
  265. DeleteVirFile("C:\\setup.exe");
  266. printf("完成----删除autorun.inf和setup.exe\n");
  267. // 5.遍历文件夹,清除Desktop_.ini,恢复感染文件
  268. vector<CString> DiverList;
  269. GetDriverList(DiverList);
  270. for (UINT i=0;i<DiverList.size();i++)
  271. {
  272. TCHAR* szRoot = DiverList[i].GetBuffer();
  273. ScanFile(szRoot);
  274. }
  275. /*TCHAR* szRoot = L"C:\\Virus";
  276. ScanFile(szRoot);*/
  277. printf("完成----清除Desktop_.ini,恢复感染文件\n");
  278. system("pause");
  279. }