美文网首页
熊猫烧香病毒的查杀和修复

熊猫烧香病毒的查杀和修复

作者: MagicalGuy | 来源:发表于2018-10-10 00:48 被阅读0次

熊猫烧香是蠕虫病毒的变种,Delphi语言编写,本文研究的病毒版本中,它拥有自我复制,本地感染和局域网感染的能力,甚至感染网页代码。感染寄生于被感染文件,执行被感染文件时会分离出病毒程序并执行。病毒运行时存在关闭安全软件类进程,关闭并删除安全软件相关服务,启动项,删除GHO系统备份文件,更换软件图标等动作。

病毒名称:(Nimaya)熊猫烧香
所属家族:Virus.Win32.Lamer.gx(卡巴斯基)
MD5值:B8F8E75C9E77743A61BBEA9CCBCFFD5D
SHA1值:188FC8FC580C0EA4BF8A8900A3D36471823C8923
SHA256: 0c15096fb3bc30800f7af002c25953162b799391300a62b8507fe8e4f6532768
SSDeep:
3072:apAja0pSLwYqK6hVZ7N4bdq4a53YKCOTpc:a2ja0pShqK65ZOq4QYK1m
CRC32:E63D45D3

病毒执行流程:


image.png

自动查杀实现:

#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_.ini
                    BOOL 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.exe
            bRet = DeleteFile((LPCWSTR)szSysPath);
            if (bRet){
                cout << "spoclsv.exe病毒被删除!" << endl;
            }
            else{
                cout << "spoclsv.exe病毒无法删除" << endl;
            }
        }
    }

    //  删除每个盘符下的setup.exe与autorun.inf,以及Desktop_.ini

    char 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.exe
                bRet = 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.inf
        bRet = DeleteFile((LPCWSTR)szAutorunPath);

        if (bRet){
            cout << pTmp << " autorun.inf已删除!" << endl;
        }
        else{
            cout << pTmp << " autorun.inf不存在或无法删除" << endl;
        }
        // 删除Desktop_.ini
        FindFiles(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的值设置为1
    TCHAR 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;
}

实现效果:


image.png

实现功能有:提升权限查杀病毒进程,遍历盘符删除病毒文件或自动运行脚本,以及删除病毒的注册表启动项和修改回来设置的文件隐藏选项。

修复工具:

该熊猫烧香病毒感染exe等非网页文件时,只是复制了一份以被感染文件命名的病毒文件,在其后面追加被感染文件的内容,后面再加上感染标志。而网页文件只是简单的在其原文件的末尾添加了一段脚本代码。
由此我们也容易使用010Editor工具进行手工还原文件。这里我尝试编写一个恢复单个被感染exe文件的小例子。例如如下图恢复被感染程序Exam1.exe,RecoverFiles.exe是编写的修复工具。如果想实现全盘修复,需要自己遍历盘符和文件夹各文件。修复工具效果如下:


image.png

实现代码如下:

#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.exe
    if ((in = fopen("Exam1.exe", "rb")) == NULL)
    {
        printf("The file %s can not be opened.\n", "Exam1.exe");
        return;
    }

    //创建修复文件Exam2.exe
    if ((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");
                //文件错误标志和文件结束标志置为0
                clearerr(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");
}

相关文章

网友评论

      本文标题:熊猫烧香病毒的查杀和修复

      本文链接:https://www.haomeiwen.com/subject/dlquaftx.html