病毒名称:熊猫烧香
所属家族:Fujack
MD5值:512301C535C88255C9A252FDF70B7A03
SHA1值:CA3A1070CFF311C0BA40AB60A8FE3266CFEFE870
CRC32:E334747C
病毒行为概述:
- 文件操作行为:
0. 自我复制到C盘,C:\Windows\System32\driver目录下,结束自身并启动C:\Windows\system32\drivers\spo0lsv.exe
1. 在每个目录下创建Desktop_.ini文件,存放当前日期
2. 在C盘目录下创建了autorun.inf文件(双击磁盘自动运行),并指定了自动启动的文件为根目录下setup.exe(释放的样本文件)
- 系统操作行为:
0. 设置注册表自启动项为C:\Windows\system32\drivers\spo0lsv.exe
1. 修改资源管理器中文件的隐藏属性,设置隐藏文件不显示
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Folder\Hidden\SHOWALL\CheckedValue
- 进程操作行为:
0. 遍历进程,服务,窗口,及对其进行相关操作
1. 创建可执行文件
2. 对系统中的部分文件进行感染(如后缀为.exe,.com,.html,.asp,.src等),图标变为熊猫烧香
3. 执行CMD命令关闭网络共享
- 网络行为
0. 访问门户网站
1. 对局域网内的一些IP进行连接
系统环境:win7 Professional 32位(15pb实验环境)
工具:
0. 火绒剑(行为分析)
1. autorun(查看启动项,计划任务,WMI,服务等)
2. PCHunter(文件,进程等管理)
3. WSExplorer(抓包工具,分析流量)
4. OllyDbg(动态调式)
5. IDA(静态分析)
6. PEID(查壳)
7. OllyDbg(动态调试分析)
8. VirtualStdio(编写专杀工具)
分析样本需要完成的目标:
0. 分析并记录样本产生的恶意行为
1. 对样本进行详细分析,找出恶意代码及具体实现过程
2. 对病毒的整个运行过程对应相应执行的恶意代码制作流程图
3. 提取出样本特征,完成分析报告,并编写专杀工具
在虚拟机中模拟病毒运行,提取样本信息,等待病毒运行一段时间后,对计算机进行检查
1. 打开PCHunter(ARK工具)
查看进程,找到熊猫烧香的进程信息。
查看文件,发现C盘,D盘根目录都创建了两个文件setup.exe和autorun.inf创建时间与病毒运行时间相符合,使用系统文件查看器却看不到,应该是设置了隐藏和系统属性,去除属性就可以查看到,但过很短时间内却又隐藏了
猜测是设置了定时任务设置,或者进程服务等动态扫描设置
查看autorun.inf文件,执行打开setup.exe的命令
同时所有的目录下都创建了Desktop_.ini文件,同时也设置了隐藏和系统属性,但去除属性后并未将属性动态设置回去,里面只保存了当前日期
查看网络信息,在局域网内的可疑连接
将病毒文件加入在启动项中
2. 使用autorun查看启动项,计划任务,服务,WMI
3. WSExplorer抓包
不间断的对外发起外连
查看文件,计算机中的exe文件图标都换成了熊猫烧香
将样本中主机中提取出来
定位到病毒样本文件将文件后缀修改为.vir,提取出来
对主机进行手动清理
1. 结束可疑的恶意病毒进程
2. 删除添加的启动项
3. 将创建的样本文件spo0lsv.exe,及Desktop_.ini,anturun.inf,setup.exe删除
4. 恢复被修改的系统配置
5. 被修改的exe文件无法恢复,且点击运行后会再次激活病毒,需要进一步分析对被修改的exe文件的具体操作
打开火绒剑工具,将病毒样本拖拽进行行为监控,设置监控所有事件
让病毒程序运行一段时间后,查看监控事件
对监控到的事件进行过滤分类详细分析
主要查看对文件的修改,创建,删除等关键操作
大致分析为对文件进行遍历,在目录下创建Desktop_.ini并写入日期,对后缀为exe,html,asp,com等文件进行写入操作,间断性的在根目录下创建setup.exe文件,aoturun.inf文件(写入内容为执行命令启动setup.exe),同时对创建的所有文件设置隐藏属性。
查看到首先创建了spo0lsv.exe并写入,接着遍历目录创建Desktop_.ini文件
然后依次对exe文件进行写入
根目录创建autorun.inf和setup.exe文件
写入html文件
创建Tmp文件
主要查看对内存的写入,创建进程,终止进程等操作
枚举进程,创建进程,跨进程写入内存,打开设备
创建cmd.exe执行命令
枚举窗口
主要关注创建,设置,删除注册表键值的操作
创建注册表并添加键值信息
对局域网内IP的139端口发起连接,外连访问网站
较为重要的恶意行为
自启动项的修改,自我复制,释放文件等
1. 使用查壳工具DIE获取样本文件信息,壳为FSG2.0
2. 脱壳
壳入口点
单步分析跳转到OEP
Dump设置OEP
修复IAT,设置OEP,IAT地址大小,先在内存中将间隔还原为0
获取到样本文件xiongmao_dump.exe进行详细分析
PEID深度扫描
1. 将样本在IDA中打开
Shift+f5 添加delphi符号
需要注意Delphi程序使用Fastcall前两个参数使用ECX,EDX传参
初步分析,根据IDA中伪C代码,前面都是对变量字符窗的初始化操作,调用关键函数后会有一个比较参数,为非则退出进程,在OD中动态分析该函数
在OD中动态分析
在IDA中生成MAP文件,OD使用插件加载,获取符号信息便于分析
OD中动态分析
基本过程
1. 将加密的字符串与一个特殊标识 xboy传入参数,判断0x405250为解码函数
2. 解密后对比字符串相同则继续执行程序
关键循环,对加密的字符串进行解密
IDA中
基本过程:
1. 判断当前路径是否存在Desktop_.ini文件
2. 构造需要创建的文件spo0lsv.exe路径,与病毒程序本身路径进行比较,一样退出
3. 遍历进程找到spo0lsv.exe终止
4. 复制自身到系统system32\drivers目录下spo0lsv.exe文件,并创建进程退出自身
分析函数0x40819C在IDA中使用伪代码查看该函数,有多个函数未识别,具体功能不好猜测,大致为对文件,路径,目录的字符串拼接,未识别到的函数在OD中具体分析
在这里修改跳转继续分析当前病毒程序
在IDA中补全得到的信息
该函数内调用了三个函数,依次进行详细分析
在IDA中静态查看,依次分析这三个函数
步骤分析:
1. 遍历磁盘文件,在未排除目录下创建Desktop_.ini文件
2. 如果是文件则识别后缀名,处理exe,com,html等文件
Sub_40A5B0为创建线程,分析回调函数0x409348
OD中单步分析,获取当前系统的磁盘名称
进入sub_409348进行分析
排除以上出现的目录,不在这些目录下创建ini文件
如果当前遍历到的目录不在排除名单内,则创建ini文件
递归完成继续调用FindNext查找,实现整个根路径遍历
找到循环遍历结束的地址,FindFile的结束条件为获取到的文件句柄为 -1,当不为目录时跳出查找
继续分析对文件的操作
删除GHO文件
自己释放的文件跳过
EXE类型的文件,调用函数sub_407F00处理
SCR类型的文件,调用函数sub_407F00处理
及以下文件类型,调用函数sub_407F00
对htm,html,asp,php,jsp,aspx文件处理
当不为以上任意文件类型时,继续遍历,如遍历结束则退出函数
1.1 0x407F00:修改exe,src,pie,com类型的文件
步骤分析:
1. 打开目标文件读取到内存
2. 复制病毒到感染的目标文件,覆盖原有文件
3. 将原数据追加到感染的文件
4. 再追加写入标识字符串 如 文件名+后缀名+随机数?+原文件大小
进入对文件操作的函数,分析其具体操作行为
对读取内存文件的分析
继续单步分析,在内存中寻找标志字符串
拷贝自身到目标文件
拷贝成功,将文件名,后缀名,文件大小拼接为一个特殊标识字符串
完成修改写入
查看被感染文件的2进制数据,发现字符串被追加到了结尾
末尾追加的数字确实为文件大小
1.2 0x4079CC:修改html,asp,php等类型的文件
步骤分析
1. 读取文件到内存,判断标识是否已经写入
2. 打开文件,设置文件指针到结尾
3. 写入iframe标签字符串,大小为3B
OD中单步分析
写入长度为0x4C的数据
IDA中分析
步骤分析:
1. 设置计时器每隔 6s 执行
2. 回调函数执行流程
1. 获取系统所有磁盘名称
2. 判断根路径下setup.exe和aoturun.inf文件是否存在
3. 不存在则拷贝自身创建setup.exe,创建aoturun.inf写入命令
4. 设置文件属性为隐藏,只读,系统
该函数设置了一个计时器,对回调函数进行分析
点击查看push进入的回调函数地址,为0x408E7C
在OD中单步分析结合IDA的伪代码补全整个函数流程
在根路径下创建setup.exe文件
在根路径下创建autorun.inf文件
写入内容
"[AutoRun]\r\nOPEN=setup.exe\r\nshellexecute=setup.exe\r\nshell\Auto\command=setup.exe\r\n"
设置文件隐藏属性,然后判断是否继续循环
步骤分析:
1. BeginThread函数中,循环创建线程,回调函数为0x403BC8
2. 单步分析找到关键网络连接的函数0x408B64
3. 判断本地网络连接,获取本地网络IP,从1开始递增连接
4. 连接139,445端口,获取目标主机系统版本时间,遍历共享目录,拼接本地病毒文件路径,需要在目标主机创建的病毒文件路径,拷贝病毒文件
对关键网络连接函数0x40B864进行分析
在OD中调试总是跑飞,为排除分析干扰,把其他操作都nop掉,把线程数量改为1,调式
修改跳转,判断连接成功的操作,进入该函数
再次找到关键操作函数分析,获取模块基址文件名
获取目标主机系统版本
遍历目标主机共享目录
调用了rpc
函数设置了六个定时器,依次进行分析
分析技巧:因为逻辑直接没有关联,分析其中一个把其他的都nop掉,防止干扰卡顿
步骤分析:
1. 将C:\Windows\System32\Drivers\spo0lsv.exe添加到注册表系统启动项中
"Software\\Microsoft\\Windows\\CurrentVersion\\Run"
2. 设置不显示隐藏文件
SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced\\Folder\\Hidden\\SHOWALL\\CheckedValue
3. 创建线程0x4061B8
1. 遍历窗口,匹配杀软窗口名发消息关闭
2. 遍历进程,匹配杀软进程名终止进程
OD中动态分析结合IDA
分析函数0x406E2C,创建了一个线程,回调函数0x4061B8
反杀软,遍历窗口关闭杀软
再次遍历窗口
函数0x405FC4为遍历进程,匹配杀软进程名则终止进程
步骤分析:
1. 创建线程,分析回调函数0x40C9B8
2. 回调函数执行下载数据到文件并调用WinExec执行
跳转继续判断
构造文件路径,下载数据到文件
执行下载的数据
步骤分析:
1. 下载恶意代码执行的步骤与上一个一样,调用的0x40C9B8的回调函数
2. 执行CMD命令关闭网络共享
获取磁盘名称,循环执行命令关闭共享
关闭已有共享
步骤分析:
1. 创建线程,回调函数为0x406E44
对服务进行停止删除操作,删除选定的注册表项
步骤分析:
1. 解密字符串,获取网址,并访问
分析的建立网络连接函数
步骤分析:
1. 下载病毒更新文件并执行
如果判断成功则下载执行
获取退出消息时程序退出
特征包括:
1. 二进制特征 提取一段特殊的二进制数据作为查杀标志,这里提取了一个特殊的四字节数据,因为病毒文件和感染文件在0x6548处都会出现这个特殊数据,当为病毒文件时,直接清空内存,为感染文件则修复
2. 也可以使用特殊字符串xboy,whboy等作为病毒特征标识,编写yara规则查找出符合特征的文件
- // 1. 创建一个快照用于遍历进程,参数2可以留空
- HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
- // 2. 创建一个用于保存进程信息的结构体
- PROCESSENTRY32 ProcessInfo = { sizeof(PROCESSENTRY32) };
- // 3. 尝试遍历第一个进程的信息,成功就继续,失败就跳过
- if (Process32First(Snapshot, &ProcessInfo))
- {
- do {
- if (!wcscmp(ProcessInfo.szExeFile, L"spo0lsv.exe"))
- {
- HANDLE hProc = OpenProcess(PROCESS_TERMINATE, NULL, ProcessInfo.th32ProcessID);
- DWORD result = TerminateProcess(hProc, -1);
- printf("终止进程:%S, 错误码:%d, 终止结果:%d\n\n", ProcessInfo.szExeFile, GetLastError(), result);
- CloseHandle(hProc);
- }
- // 4. 尝试遍历进程快照内的下一个进程
- } while (Process32Next(Snapshot, &ProcessInfo));
- }
- return 0;
- //遍历文件
- DWORD WINAPI FindFile(CString str)
- {
- //拼接路径
- CString path;
- path = str + L"\\*";
- //文件查找
- //保存找到的文件信息
- WIN32_FIND_DATA FindData;
- HANDLE hFile = FindFirstFileW(path, &FindData);
- //如果句柄有效
- if (hFile != INVALID_HANDLE_VALUE)
- {
- do {
- CString FileName = FindData.cFileName;
- CString TempPath = str + L"\\" + FindData.cFileName;
- //判断是文件还是目录
- if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- {
- //过滤'.'和'..'目录
- if (wcscmp(FileName, L".") && wcscmp(FileName, L".."))
- FindFile(TempPath);
- }
- else
- //对文件的识别判断与操作
- } while (FindNextFileW(hFile, &FindData));
- }
- //关闭文件句柄
- FindClose(hFile);
- return 0;
- }
- //如果需要删除
- if (!wcscmp(FileName, L"Desktop_.ini") ||
- !wcscmp(FileName, L"setup.exe") ||
- !wcscmp(FileName, L"autorun.inf") ||
- !wcscmp(FileName, L"worm.txt"))
- {
- SetFileAttributes(TempPath, FILE_ATTRIBUTE_NORMAL);
- if (DeleteFile(TempPath))
- printf("病毒文件:%S 删除成功\n", TempPath);
- else
- printf("病毒文件:%S 删除失败\n", TempPath);
- }
对exe等文件的感染操作为写入病毒文件,并把原文件追加到结尾,再添加标识字符串,可以先根据病毒特征判断文件是否被感染,如果感染则从文件中删除病毒文件的数据,再从后往前读取截断标识字符串,还原文件,如果是病毒文件则清空数据,操作思路如下代码
- //如果是被感染的exe等类型文件,则恢复
- else if (!wcscmp(extension, L".exe") ||
- !wcscmp(extension, L".pie") ||
- !wcscmp(extension, L".com") ||
- !wcscmp(extension, L".src"))
- {
- //读取文件到内存并恢复
- SetFileAttributes(TempPath, FILE_ATTRIBUTE_NORMAL);
- ReadFileToMem1(TempPath);
- }
- //读取文件恢复exe类
- void ReadFileToMem1(CStringA path)
- {
- HANDLE hFile = CreateFileA(path,GENERIC_READ,NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL );//只读的方式打开文件
- PDWORD pPeSign = NULL;
- DWORD dwRealSize = 0;
- if (hFile == INVALID_HANDLE_VALUE)
- {
- if (GetLastError() == 32) return;//被系统占用
- printf("%d 打开文件 %s 失败\n", GetLastError(), path); return;
- }
- //获取文件大小 小于病毒文件则证明未感染
- DWORD dwFilezSize = GetFileSize(hFile, NULL);
- if (dwFilezSize < 0x6548) return;
- PCHAR pMem = new CHAR[dwFilezSize]{};
- BOOL b = ReadFile(hFile, pMem, dwFilezSize, &dwRealSize, 0);
- if (!b) { printf("读取文件 %s 失败\n", path); return; }
- pPeSign = PDWORD(pMem + 0x6548); CloseHandle(hFile);
- //被感染了 PE头的0x6548位置为 boyæ 0xE6796F62
- if (*pPeSign == (DWORD)0xE6796F62)
- {
- PCHAR pEnd = pMem + dwFilezSize - 1; //指向最后一个字节
- while (*pEnd != '\0')
- pEnd--;
- pMem += 0x7531; //病毒文件大小
- //修复文件覆盖感染文件
- HANDLE hFile = CreateFileA(path,GENERIC_READ | GENERIC_WRITE,NULL,NULL,CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,NULL);
- if (hFile == INVALID_HANDLE_VALUE)
- {
- printf("修复文件 %s 失败,请再次修复或手动删除\n", path);
- return;
- }
- DWORD size = pEnd - pMem; //修复大小
- WriteFile(hFile, pMem, size > 0 ? size : 0, &dwRealSize, 0);
- path2 += path + "\n";
- CloseHandle(hFile);
- return;
- }
- }
html文件判断末尾是否被追加iframe标签,对比字符串,如果被感染则删除添加的数据
- //打开文件操作 同上
- //先判断最后面有没有被追加修改
- DWORD dwFilezSize = GetFileSize(hFile, NULL);
- PCHAR pMem = new CHAR[dwFilezSize]{};
- ReadFile(hFile, pMem, dwFilezSize, &dwRealSize, 0);
- piFrame = PCHAR(pMem + dwFilezSize - 0x4C);
- *(pMem + dwFilezSize - 1) = 0;
- CloseHandle(hFile);
- //被感染了
- if (!strcmp(piFrame,
- "\r"))
- {
- //修复文件覆盖感染文件
- //创建文件 同上
- if (hFile == INVALID_HANDLE_VALUE)
- {
- printf("修复文件 %S 失败\n", path);
- return;
- }
- //修复大小
- DWORD size = piFrame - pMem;
- WriteFile(hFile, pMem, size > 0 ? size : 0, &dwRealSize, 0);
- printf("修复文件 %S 成功\n", path);
- CloseHandle(hFile);
- return;
- }
从启动项中删除添加的病毒文件路径,删除添加的注册表项
- //删除设置的注册表
- void RestoreRegValue()
- {
- //主键
- HKEY RootKey = HKEY_CURRENT_USER;
- //子健
- LPCTSTR lpSubKey = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"
- //接收将要打开的子健句柄
- HKEY hkResult = 0;
- //打开一个已经存在的注册表键值
- LONG lReturn = RegOpenKeyEx(
- RootKey, //根键句柄
- lpSubKey, //子健路径
- 0, //保留
- KEY_ALL_ACCESS,//指定打开句柄的权限
- &hkResult //子健句柄
- );
- int ret = RegSetValueExA(hkResult, "svcshare", 0, REG_SZ, (BYTE*)"", 0);
- if (ret == 0)
- printf("清空注册表键 Software\\Microsoft\\Windows\\CurrentVersion\\Run\\svcshare 成功\n\n");
- //病毒添加的项
- HKEY RootKey1 = HKEY_LOCAL_MACHINE;
- LPCTSTR lpSubKey1 = L"SOFTWARE\\Microsoft\\Tracing\\spo0lsv_RASAPI32";
- LPCTSTR lpSubKey2 = L"SOFTWARE\\Microsoft\\Tracing\\spo0lsv_RASMANCS";
- if (int ret = RegDeleteKeyEx(RootKey1, lpSubKey1, KEY_WOW64_32KEY, 0))
- printf("%d 删除 SOFTWARE\\Microsoft\\Tracing\\spo0lsv_RASAPI32 成功\n", ret);
- if (int ret = RegDeleteKeyEx(RootKey1, lpSubKey2, KEY_WOW64_32KEY, 0))
- printf("%d 删除 SOFTWARE\\Microsoft\\Tracing\\spo0lsv_RASMANCS 成功\n", ret);
- RegCloseKey(hkResult);
- }
将系统存在的被关闭的服务恢复启动,因为感染主机是否开启的这些服务未知,代码只做参考
- //恢复服务
- void RestoreServices()
- {
- //打开计算机服务管理系统
- SC_HANDLE hSCM = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
- for (DWORD i = 0; i < 22; i++)
- {
- SC_HANDLE schService;
- schService = OpenService(hSCM,
- services[i],//服务名字
- SERVICE_ALL_ACCESS);//打开服务
- //如果打开失败
- if (schService == NULL)
- {
- printf("打开 %S 服务失败\n", services[i]);
- continue;
- }
- //开始启动服务
- if (!StartService(schService, 0, NULL))
- {
- printf("启动 %S 服务失败\n", services[i]);
- CloseServiceHandle(schService);
- continue;
- }
- printf("启动 %S 服务成功\n", services[i]);
- CloseServiceHandle(schService);
- }
- }
作为第一个分析的病毒,熊猫烧香病毒还是比较全面的,对被感染主机作了大量的修改操作,在感染文件的同时,还有自我保护,持续化的功能,开启了多线程操作,加上计时器实现实时感染,并带有下载恶意代码执行,定时自更新,同时开启了十条线程作来进行局域网内的传播扩散,也表现了蠕虫病毒极强的传播性,而修复的手段只能是恢复感染文件,清理干净恶意病毒文件,删除启动项,否则一不小心就死灰复燃。
这一次的分析流程总体来说还是比较完整的,从行为到代码的实现,熊猫烧香是delphi编写的,对于库函数不太熟练,但底层调用的还是windows的API,病毒除了感染文件的操作,在维持自身,扩散的同时,会大量使用到类似注册表,服务,网络有关的系统操作API,需要多加练习查阅,熟悉参数及功能,可以使得分析更加顺利。
同时,因为是一个多线程的程序,并设置了多个计时器,在调式的过程中还是遇到了一些问题的,断不下来下来,跑飞等问题,经过多次尝试,也找到了些方法,在回调函数多下几个断点,设置线程空闲,修改源代码去除干扰等,这次就是在分析某个线程操作时,就把其他操作代码nop掉,专心分析特定操作。总的还是收获很大,逆向需要耐心。