熊猫烧香病毒分析

文章目录

  • 样本概况
    • 样本信息
    • 测试环境及工具
    • 分析目标
  • 具体行为分析
    • 初步分析病毒文件
    • 查看病毒主要行为
    • 详细分析病毒文件
  • 解决方案
    • 提取病毒特征
    • 手工查杀病毒
    • 编写查杀工具
  • 总结
  • PS

样本概况

样本信息

  • 病毒名称:spo0lsv.exe
  • 样本大小:98816 bytes
  • 所属家族:感染性病毒 (Virus)、蠕虫病毒 (Worm)
  • MD5 值:3CE8412544B47D544357C5BE42FBE704
  • SHA1 值:23FC53530BAACCFC4E83E3A74ADB219958B8E665
  • CRC32:AFA1B975
  • 病毒行为:修改 PE 文件,设置文件夹属性,杀掉杀毒软件进程,关闭系统和杀毒软件服务,设置文件属性,在根目录创建自运行文件,修改注册表,修改启动项等

测试环境及工具

  • 测试环境:Windows 7 32 位
  • 工具:PEiD、x64dbg、Process Explorer、PCHunter、火绒剑、Ollydbg、IDA、IDR、010Editor

分析目标

  • 初步分析病毒文件
  • 查看病毒主要行为
  • 详细分析病毒文件
  • 手工查杀病毒
  • 编写查杀工具

具体行为分析

初步分析病毒文件

  • 通常,我们拿到病毒文件的第一件事是查看其文件信息,主要是看它是否加壳。有许多软件能查到壳的信息,这里我选择的是 PEiD v0.95。从下图可以看出,该文件已加壳。壳的信息是 FSG 2.0,这是一个压缩壳。

    熊猫烧香病毒分析_第1张图片

  • 脱壳。这里我们选择“手工”脱壳,使用的是 x64dbg。先用 x64dbg 打开病毒文件(说明:因为当前是 Windows 7 32 位系统,所以安装的是 32 位的 x64dbg,即 x32dbg),然后按 F9,来到壳的入口点。

    熊猫烧香病毒分析_第2张图片

  • 单步几次,先不进入第一个 call,往下翻,找到注释(反汇编窗口的右边)有“LoadLibraryA”和“GetProcAddress”的地方。具体分析见下图。

    熊猫烧香病毒分析_第3张图片

  • 在上图中标注“跳转到真正的入口点”的 jmp 处按 F4,然后单步,即可到达真正的入口点。

    熊猫烧香病毒分析_第4张图片

  • 找到真正的入口点后即可脱壳。这里使用 x64dbg 的插件 Scylla,当然,也可用别的工具。

    熊猫烧香病毒分析_第5张图片

  • 在弹出的 Scylla 对话框中,如图所示的步骤操作即可。(第一步:自动获取 IAT;第二步:获取导入表;第三步:Dump;第四步:修复 IAT)

    熊猫烧香病毒分析_第6张图片

  • 脱壳成功。

    熊猫烧香病毒分析_第7张图片

    熊猫烧香病毒分析_第8张图片

  • 使用 PEiD、Exeinfo PE 等工具查看脱壳后的病毒文件信息。

    熊猫烧香病毒分析_第9张图片

    熊猫烧香病毒分析_第10张图片

  • 使用 LordPE 查看脱壳后的病毒文件信息。

    熊猫烧香病毒分析_第11张图片

    熊猫烧香病毒分析_第12张图片

    熊猫烧香病毒分析_第13张图片

    熊猫烧香病毒分析_第14张图片

  • 因为这是一个 Delphi 程序,所以还可使用IDR获取敏感字符串信息,导出 map 文件(说明:IDA 加载签名文件后也可导出 map 文件),在之后的详细分析中,可用 Ollydbg 导入这个 map 文件,这样 Ollydbg 也可识别 Delphi 的字符串。

    熊猫烧香病毒分析_第15张图片

  • 总结:上述步骤是在获取病毒样本之后对其的初步分析,关键在于查壳和脱壳,由于本次分析的病毒文件使用的壳较为简单,故并未使用专业的脱壳软件。还有就是,我们知道了这是一个 Delphi 程序,也就知道了它的调用约定等信息,便能更好地助益我们后面的详细分析。

查看病毒主要行为

  • 这里使用火绒剑这款工具查看病毒的行为。请注意,下述操作须在虚拟机等环境中进行,千万不要在物理机中操作,以免造成不必要的损失。在虚拟机中操作前,务必先保存快照,一来虚拟机以后可能还会用到,此举可避免无谓的重装,二来后面的分析也要回到无毒的环境进行。保存快照后,把病毒文件拖入火绒剑,点击“确定”。这时病毒程序开始运行。

    熊猫烧香病毒分析_第16张图片

  • 由下图可看出,病毒的行为不少。此时可先过滤一部分动作,每次只选择同一类型的行为,避免杂乱无章和手忙脚乱。接下来,便正式开始分析。

    熊猫烧香病毒分析_第17张图片

  • 先分析第一个大项 —— “执行监控”。子项有“模块加载”“进程退出”“进程启动”,都是很重要的,所以全选。点击“确定”。

    熊猫烧香病毒分析_第18张图片

  • 由下图可看出,病毒的这一类型的行为不算太多,我们可逐一查看、分析。

    熊猫烧香病毒分析_第19张图片

  • 通过上一步,我们可总结出病毒的两种主要行为:一、退出自身进程,创建“spo0lsv.exe”进程;二、取消网络共享。

  • 分析第二个大项 —— “文件监控”。由于子项太多,且大多不需要详细分析,故只选择如下几项。点击“确定”。

    熊猫烧香病毒分析_第20张图片

  • 由下图可看出,虽然只选择了“文件监控”的几个子项,但病毒的行为依然不少,可见,这个病毒集中的“火力”之一便是文件操作。我们可一一点开这些行为,具体分析。

    熊猫烧香病毒分析_第21张图片

  • 经过上一步的细致分析,可将熊猫烧香病毒在文件操作方面的行为总结出来:在“C:\Windows\System32\drivers”目录创建“spo0lsv.exe”,设置属性,修改文件;在每个目录创建“Desktop_.ini”,设置隐藏等属性,修改文件;设置每个可执行文件的属性,并修改文件;在 C 盘根目录创建“setup.exe”,设置隐藏等属性,修改文件;在 C 盘根目录创建“autorun.inf”(用于双击磁盘后自动运行指定文件,这里是“setup.exe”),设置隐藏等属性,修改文件。

  • 分析第三个大项 —— “注册表监控”。同样的,我们只需选择“删除注册表项值” “设置注册表项值”“创建注册表键”这三个子项逐一分析即可。点击“确定”。

    熊猫烧香病毒分析_第22张图片

  • 由下图可看出,熊猫烧香病毒删除了当时各大杀毒软件的开机启动项,这样,病毒就可以肆无忌惮了。往下翻,可看出又重复了上述行为,再看“时间”,可推测使用了定时器,每隔一段时间即重复删除。

    熊猫烧香病毒分析_第23张图片

  • 由下图可看出,熊猫烧香病毒创建了自身的注册表键。

    熊猫烧香病毒分析_第24张图片

  • 由下图可看出,熊猫烧香病毒在“HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run”中创建了“svcshare”,即设置了位于“C:\Windows\system32\drivers”的“spo0lsv.exe”的开机启动项。往下翻,可看出又重复了上述行为,再看“时间”,可推测使用了定时器,每隔一段时间即重复设置。

    熊猫烧香病毒分析_第25张图片

  • 由下图可看出,熊猫烧香病毒设置了位于“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Folder\Hidden\SHOWALL”的“CheckedValue”为 0,实现了隐藏文件的目的,因而我们即使在“文件夹和搜索选项”中设置“显示隐藏的文件、文件夹和驱动器”也不会看到隐藏文件,这就达到了病毒隐藏自身的目的。同样的,往下翻,可看出又重复了上述行为,再看“时间”,可推测使用了定时器,每隔一段时间即重复设置。

    熊猫烧香病毒分析_第26张图片

  • 经过如上详细分析,可将熊猫烧香病毒在注册表方面的主要行为总结出来:删除各大杀毒软件的开机启动项;创建自身开机启动项;使隐藏文件无法通过普通设置显示,也就隐藏了自身。

  • 分析第四大项 —— “进程监控”。由于每一个操作都可能是重要的行为,为了避免遗漏,这里我们选择全部的子项进行分析。点击“确定”。

    熊猫烧香病毒分析_第27张图片

  • 经过逐项查看,至此,我们可以将熊猫烧香病毒在进程方面的操作归纳如下:一、枚举进程;二、打开进程;三、创建进程;四、跨进程写内存;五、跨进程恢复线程;六、打开设备;七、查找窗口;八、发送窗口消息。同样的,往下翻,并且看右边的“时间”,可推测使用了定时器,每隔一段时间即重复上述行为。虽然归纳出了这些行为,但仅凭这些仍难分析出更多信息,具体的行为分析留待后面的详细分析。

    熊猫烧香病毒分析_第28张图片

    熊猫烧香病毒分析_第29张图片

  • 分析第五大项 —— “网络监控”。同样的,由于每一个操作都可能是重要的行为,为了避免遗漏,这里我们选择全部的子项进行分析。点击“确定”。

    熊猫烧香病毒分析_第30张图片

  • 通过逐项查看,我们可以知道熊猫烧香病毒在网络方面的操作:一、网络连接,访问139、80、443、445 等端口;二、发送数据包;三、HTTP 请求,访问当时的一些门户网站。上述第一、二个行为的目的是连接局域网里的计算机,向外发送数据包;第三个行为的目的可能是一种试探,推测其思路为:如果能访问这些网站(意味着连接了互联网),即可进行诸如下载木马等恶意行为。

    熊猫烧香病毒分析_第31张图片

    熊猫烧香病毒分析_第32张图片

  • 我们还可通过抓包工具“WSExplorer”查看是否发送、接收数据包。由下图可看出,熊猫烧香病毒的确做出了这一行为。也可看出,主要是接收数据包。

    熊猫烧香病毒分析_第33张图片

    熊猫烧香病毒分析_第34张图片

  • 分析第六大项 —— “行为监控”。这个项目可以说是对病毒全部行为的汇总,因而我们全选,这也能为我们之前的分析起到查漏补缺的作用。点击“确定”。

    熊猫烧香病毒分析_第35张图片

  • 由下图可看出(往下翻仍是这些行为,只是路径和文件不同,可见,熊猫烧香病毒感染了所有的文件),该病毒主要的行为在文件操作,包括感染 PE 文件、自我复制、覆写PE 文件等。

    熊猫烧香病毒分析_第36张图片

  • 经过上面的分析,我们已经大致了解病毒的主要行为,现总结如下:

    • 退出自身进程,创建“spo0lsv.exe”进程。
    • 取消网络共享。
    • 在“C:\Windows\System32\drivers”目录创建“spo0lsv.exe”并启动。
    • 在每个目录创建“Desktop_.ini”,并设置隐藏等属性。
    • 设置每个可执行文件的属性,并修改文件(病毒的自我复制等)。
    • 在C盘根目录创建“setup.exe”和“autorun.inf”,设置隐藏等属性,并启动。
    • 删除各大杀毒软件的开机启动项。
    • 创建自身的开机启动项。
    • 设置注册表,使隐藏文件无法通过普通设置显示。
    • 连接局域网,向外发送数据包;访问门户网站。

详细分析病毒文件

  • 现在开始详细分析,即借助 IDA 和 Ollydbg 两款工具,动静结合地分析熊猫烧香这个病毒。当然,主要用到的是 IDA,只有到了静态分析无法确定时才用到 Ollydbg。

  • 用 IDA 打开病毒文件,先将不重要的部分折叠,结果如下:

    熊猫烧香病毒分析_第37张图片

  • 一开始是大段的字符串复制,其实是病毒作者与他人的对话,不是重点,故不一一分析。

  • 对话结束之后,会遇到两个解码函数,其后是比较字符串,类似于校验,如果没通过,则退出进程。如下:

    熊猫烧香病毒分析_第38张图片

  • 接下来是三个 call,经过上下文分析,推测这些可能是关键函数,需要一一详细分析。下面是分析之后得出的结论:

    熊猫烧香病毒分析_第39张图片

  • 第一个 call 做的事如上所述,现将代码出示,其中的注释即是详细的分析过程:

    熊猫烧香病毒分析_第40张图片

    熊猫烧香病毒分析_第41张图片

    熊猫烧香病毒分析_第42张图片

    熊猫烧香病毒分析_第43张图片

    熊猫烧香病毒分析_第44张图片

    • PS:如果在 Ollydbg 中分析,至此就会退出进程,解决方法有两种,一是单步至上面图四的 jz 跳转处时修改 zf 标志位为 1,二是用 Ollydbg 再次打开位于 C:\Windows\System32\drivers 目录的 spo0lsv.exe 文件,此即病毒文件

    熊猫烧香病毒分析_第45张图片

  • 关于第一个 call 的总结:

    • 复制自身至系统目录并设置隐藏属性,然后运行;
    • 退出自身进程。
  • 接下来分析第二个 call。其先调用三个函数,如下:

    熊猫烧香病毒分析_第46张图片

  • 先分析第一个函数,其内部调用创建线程的 CreateThread 函数,故我们只需分析其线程回调函数即可。如下:

    熊猫烧香病毒分析_第47张图片

  • 线程回调函数又调用了一个重要的函数,即遍历驱动器的函数,也有必要分析,如下:

    熊猫烧香病毒分析_第48张图片

    熊猫烧香病毒分析_第49张图片

    熊猫烧香病毒分析_第50张图片

    熊猫烧香病毒分析_第51张图片

    熊猫烧香病毒分析_第52张图片

    熊猫烧香病毒分析_第53张图片

    熊猫烧香病毒分析_第54张图片

    熊猫烧香病毒分析_第55张图片

    熊猫烧香病毒分析_第56张图片

    熊猫烧香病毒分析_第57张图片

    熊猫烧香病毒分析_第58张图片

    熊猫烧香病毒分析_第59张图片

    熊猫烧香病毒分析_第60张图片

    熊猫烧香病毒分析_第61张图片

  • 再分析第二个函数,其内部调用 SetTimer 函数,即设置一个定时器,对于这个函数,我们也只需分析其回调函数即可。如下:

    熊猫烧香病毒分析_第62张图片

    熊猫烧香病毒分析_第63张图片

    熊猫烧香病毒分析_第64张图片

    熊猫烧香病毒分析_第65张图片

    熊猫烧香病毒分析_第66张图片

  • 最后分析第三个函数。其内部调用 BeginThread 函数,同样的,也只需要分析其回调函数。如下:

    熊猫烧香病毒分析_第67张图片

    熊猫烧香病毒分析_第68张图片

  • 至此,外部的第二个 call 分析完毕,现总结如下:

    • 遍历驱动器,感染 EXE、SCR、PIF、COM 等文件;
    • 遍历驱动器,在每个目录写入 Desktop_.ini 文件,写入感染时间,设置隐藏等属性;
    • 遍历驱动器,感染 HTM、HTML、ASP、PHP、JSP、ASPX 等文件;
    • 在驱动器根目录写入 setup.exe 病毒文件和 autorun.inf 自运行文件,并设置隐藏等属性;
    • 创建套接字,感染 139、445 端口。
  • 最后,分析外部的第三个 call。其内部调用六个 SetTimer 函数,即设置六个定时器,同样的,只需要分析其回调函数或创建线程的回调函数即可。

  • 第一个定时器的回调函数如下:

    熊猫烧香病毒分析_第69张图片

  • 可以看出,其操作了注册表,效果如下:

    • 添加自身的开机启动项

      熊猫烧香病毒分析_第70张图片

    • 设置关于隐藏文件的值项

      熊猫烧香病毒分析_第71张图片

  • 其中,回调函数内部创建了一个线程,故有必要分析其线程回调函数。如下:

    熊猫烧香病毒分析_第72张图片

    熊猫烧香病毒分析_第73张图片

    熊猫烧香病毒分析_第74张图片

    熊猫烧香病毒分析_第75张图片

  • 第二个定时器创建了一个线程,同样的,只需要分析其线程回调函数。如下:

    熊猫烧香病毒分析_第76张图片

    熊猫烧香病毒分析_第77张图片

  • 第三个定时器创建了两个线程,而第一个线程的回调函数和第二个定时器的线程回调函数一样,不再赘述。现只分析第二个线程的回调函数。如下:

    熊猫烧香病毒分析_第78张图片

  • 第四个定时器创建了一个线程,同样的,只分析其回调函数。如下:

    熊猫烧香病毒分析_第79张图片

  • 上述关闭系统服务后的效果之一如下:

    熊猫烧香病毒分析_第80张图片

  • 第五个定时器没有创建线程,其回调函数如下:

    熊猫烧香病毒分析_第81张图片

  • 第六个定时器也没有创建线程,其回调函数如下:

    熊猫烧香病毒分析_第82张图片

    熊猫烧香病毒分析_第83张图片

  • 综上,第三个外部 call 也已分析完毕,现将其总结如下:

    • 设置六个定时器。
      • 第一个定时器:
        • 操作注册表,添加自身开机启动项,设置不可轻易修改为显示隐藏文件的值项;
        • 关闭杀毒软件的窗口和进程。
      • 第二个定时器:
        • 从指定链接下载病毒文件并运行。
      • 第三个定时器:
        • 从指定链接下载病毒文件并运行;
        • 取消网络共享。
      • 第四个定时器:
        • 关闭系统、杀毒软件服务;
        • 删除杀毒软件开机启动注册表值项。
      • 第五个定时器:
        • 解码指定链接,获取 Html 源代码。
      • 第六个定时器:
        • 从指定链接下载病毒文件并运行。

解决方案

提取病毒特征

  • 字符串:***武*汉*男*生*感*染*下*载*者***WhBoy

手工查杀病毒

  • 结束 spo0lsv.exe 进程,可通过 cmd 输入 tasklisttaskkill 命令;

  • 在“运行”中输入 msconfig,打开启动项管理,把 svcshare 这个启动项关闭

  • 在运行中输入regedit,打开注册表编辑器,找到如下键(或子键):HKLM\Microsoft\Windows\CurrentVersion\Explore/Advanced/Folder\Hidden\SHOWALL,将其中的值项 CheckValue 设为 1;

  • 在资源管理器中设置显示隐藏文件,把驱动器根目录下的 setup.exeautorun.inf 文件删除;

  • 删除 C:\Windows\system32\drivers 目录下的 spo0lsv.exe 文件;

  • 删除各个目录下的 Desktop_.ini 文件。

编写查杀工具

  • main 函数:

    int main()
    {
        DWORD dwPid = 0;
     
        // 提权
        if (!EnableDebugPrivilege(SE_DEBUG_NAME))
        {
            printf("提权失败!!!\n");
        }
        // 杀死病毒进程
        if (!FindTargetProcess(L"spo0lsv.exe", &dwPid))
        {
            printf("获取进程PID失败!!!\n");
        }
        else
        {
            HANDLE hproc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
            if (!TerminateProcess(hproc, 0))
            {
                printf("无法结束病毒进程!!!\n");
            }
            CloseHandle(hproc);
        }
     
        // 删除系统目录下的病毒文件 spo0lsv.exe
        printf("正在删除病毒文件...\n");
     
        DeleteSysVirus();
     
        // 删除每个盘符下的 setup.exe和autorun.inf 文件 和每个文件夹下的  Desktop_.ini 文件
        DeleteFiles();
     
        // 检查注册表
        printf("正在检查注册表...\n");
        CheckRegedit();
        system("pause");
    }
    

  • 获取权限函数:

    BOOL EnableDebugPrivilege(LPCTSTR pszPrivilege)
    {
        HANDLE hToken = INVALID_HANDLE_VALUE;
        LUID luid;
        TOKEN_PRIVILEGES tp;
        BOOL bRet = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
        if (bRet == FALSE)
        {
            return bRet;
        }
        bRet = LookupPrivilegeValue(NULL, pszPrivilege, &luid);
        if (bRet == FALSE)
        {
            return bRet;
        }
        tp.PrivilegeCount = 1;
        tp.Privileges[0].Luid = luid;
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
        return bRet;
    }
    

  • 遍历进程函数:

    BOOL FindTargetProcess(LPCTSTR pszProcessName, DWORD *dwPid)
    {
        BOOL bFind = FALSE;
        HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (hProcessSnap == INVALID_HANDLE_VALUE)
        {
            return bFind;
        }
        PROCESSENTRY32 pe = { 0 };
        pe.dwSize = sizeof(pe);
        BOOL bRet = Process32First(hProcessSnap, &pe);
        while (bRet)
        {
            if (lstrcmp(pe.szExeFile, pszProcessName) == 0)
            {
                *dwPid = pe.th32ProcessID;
                bFind = TRUE;
                break;
            }
            bRet = Process32Next(hProcessSnap, &pe);
        }
        CloseHandle(hProcessSnap);
        return bFind;
    }
    

  • 删除系统目录中 spo0lsv.exe 文件函数:

    VOID DeleteSysVirus()
    {
        TCHAR szSysPath[MAX_PATH] = { 0 };
        BOOL bRet;
        GetSystemDirectory(szSysPath, MAX_PATH);
        lstrcat(szSysPath, L"\\drivers\\spo0lsv.exe");
        printf("检查硬盘中是否存在spoclsv.exe文件...\n");
        if (GetFileAttributes(szSysPath) == 0xFFFFFFFF)
        {
            printf("spo0lsv.exe病毒文件不存在\n");
        }
        else
        {
            printf("spo0lsv.exe病毒文件存在,正在计算md5值\n");
            std::string dwMd5 = getFileMD5(TCHAR2STRING(szSysPath));
            // 9A76CBBEC498FDDC87F30E74A91AE7B3 是病毒的 md5 值
            if (dwMd5 == "9A76CBBEC498FDDC87F30E74A91AE7B3")
            {
                printf("校验和验证失败\n");
            }
            else
            {
                printf("校验和验证成功,正在删除...\n");
                // 去除文件的隐藏、系统以及只读属性
                DWORD dwFileAttributes = GetFileAttributes(szSysPath);
                dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
                dwFileAttributes &= ~FILE_ATTRIBUTE_SYSTEM;
                dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;
                SetFileAttributes(szSysPath, dwFileAttributes);
                // 删除 spoclsv.exe
                bRet = DeleteFile(szSysPath);
                if (bRet)
                {
                    printf("spo0lsv.exe病毒被删除!\n");
                }
                else
                {
                    printf("spo0lsv.exe病毒无法删除\n");
                }
            }
        }
    }
    

  • 删除各个驱动器根目录中 setup.exeautorun.inf 和各个目录中 Desktop_ini 文件函数:

    VOID DeleteFiles()
    {
        TCHAR szDriverString[MAXBYTE] = { 0 };
        TCHAR *pTmp = NULL;
        BOOL bRet;
        //获取字符串类型的驱动器列表
        GetLogicalDriveStrings(MAXBYTE, szDriverString);
        pTmp = szDriverString;
        TCHAR szAutorunPath[MAX_PATH] = { 0 };
        TCHAR szSetupPath[MAX_PATH] = { 0 };
        lstrcat(szAutorunPath, pTmp);
        lstrcat(szAutorunPath, L"autorun.inf");
        lstrcat(szSetupPath, pTmp);
        lstrcat(szSetupPath, L"setup.exe");
        if (GetFileAttributes(szSetupPath) == 0xFFFFFFFF)
        {
            printf("setup.exe病毒文件不存在\n");
        }
        else
        {
            std::string dwMd5 = getFileMD5(TCHAR2STRING(szSetupPath));
            if ((dwMd5 == "9A76CBBEC498FDDC87F30E74A91AE7B3"))
            {
                printf("%s校验和验证失败\n", szSetupPath);
            }
            else
            {
                printf("校验和验证成功,正在删除...\n");
                // 去除文件的隐藏、系统以及只读属性
                DWORD dwFileAttributes = GetFileAttributes(szSetupPath);
                dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
                dwFileAttributes &= ~FILE_ATTRIBUTE_SYSTEM;
                dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;
                SetFileAttributes(szSetupPath, dwFileAttributes);
                // 删除setup.exe
                bRet = DeleteFile(szSetupPath);
                if (bRet)
                {
                    printf("%s病毒被删除!\n", szSetupPath);
                }
                else
                {
                    printf("%s病毒无法删除!\n", szSetupPath);
                }
            }
        }
     
        // 去除文件的隐藏、系统以及只读属性
        DWORD dwFileAttributes = GetFileAttributes(szAutorunPath);
        dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
        dwFileAttributes &= ~FILE_ATTRIBUTE_SYSTEM;
        dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;
        SetFileAttributes(szAutorunPath, dwFileAttributes);
        // 删除autorun.inf
        bRet = DeleteFile(szAutorunPath);
        if (bRet)
        {
            printf("%s被删除!\n", szAutorunPath);
        }
        else
        {
            printf("%s不存在或无法删除!\n", szAutorunPath);
        }
        // 删除Desktop_.ini
        EnumFile(pTmp);
        // 检查下一个盘符
        pTmp += 4;
    }
    

  • 修复与检查注册表函数:

    VOID CheckRegedit()
    {
        // 首先检查启动项
        TCHAR RegRun[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
        HKEY hKeyHKCU = NULL;
        LONG lSize = MAXBYTE;
        TCHAR cData[MAXBYTE] = { 0 };
        long lRet = RegOpenKey(HKEY_CURRENT_USER, RegRun, &hKeyHKCU);
        if (lRet == ERROR_SUCCESS)
        {
            lRet = RegQueryValueEx(hKeyHKCU, L"svcshare", NULL, NULL, (unsigned char*)cData, (unsigned long*)&lSize);
            if (lRet == ERROR_SUCCESS)
            {
                lRet = RegDeleteValue(hKeyHKCU, L"svcshare");
                if (lRet == ERROR_SUCCESS)
                {
                    printf("注册表启动项中的病毒信息已删除!\n");
                }
                else
                {
                    printf("注册表启动项中的病毒信息无法删除\n");
                }
            }
            else
            {
                printf("注册表启动项中不存在病毒信息\n");
            }
            RegCloseKey(hKeyHKCU);
        }
        else
        {
            printf("注册表启动项信息读取失败\n");
        }
        // 接下来修复文件的隐藏显示,需要将 CheckedValue 的值设置为 1
        TCHAR RegHide[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced\\Folder\\Hidden\\SHOWALL";
        HKEY hKeyHKLM = NULL;
        DWORD dwFlag = 1;
        long lRetHide = RegOpenKey(HKEY_LOCAL_MACHINE, RegHide, &hKeyHKLM);
        if (lRetHide == ERROR_SUCCESS)
        {
            printf("检测注册表的文件隐藏选项...\n");
            if (ERROR_SUCCESS == RegSetValueEx(hKeyHKLM, L"CheckedValue", 0, REG_DWORD, (CONST BYTE*) & dwFlag, 4))
            {
                printf("注册表文件隐藏修复完毕!\n");
            }
            else
            {
                printf("无法恢复注册表的文件隐藏选项\n");
            }
        }
    }
    

  • 遍历文件函数:

    VOID EnumFile(PTCHAR szPath)
    {
        TCHAR szBuffPath[MAX_PATH] = {};
        TCHAR szFilePath[MAX_PATH] = {};
        _stprintf_s(szBuffPath, _T("%s\\*.*"), szPath);
        WIN32_FIND_DATA wfd = {};
        HANDLE hFindFile = FindFirstFile(szBuffPath, &wfd);
        if (hFindFile != INVALID_HANDLE_VALUE)
        {
            do {
                TCHAR szPahtAll[MAX_PATH] = {};
                _stprintf_s(szPahtAll, _T("%s\\%s"), szPath, wfd.cFileName);
                //过滤特殊目录 . ..
                if (lstrcmp(_T("."), wfd.cFileName) == 0 || lstrcmp(_T(".."), wfd.cFileName) == 0)
                {
                    continue;
                }
                //判断是文件还是目录
                if (wfd.dwFileAttributes& FILE_ATTRIBUTE_DIRECTORY)
                {
                    //printf("目录:%S\n", wfd.cFileName);
                    //递归调用自己
                    EnumFile(szPahtAll);
                }
                else {
                    if (!lstrcmp(wfd.cFileName, L"Desktop_.ini"))
                    {
                        // 去除文件的隐藏、系统以及只读属性
                        DWORD dwFileAttributes = GetFileAttributes(szPahtAll);
                        dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
                        dwFileAttributes &= ~FILE_ATTRIBUTE_SYSTEM;
                        dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;
                        SetFileAttributes(szPahtAll, dwFileAttributes);
                        // 删除Desktop_.ini
                        if (DeleteFile(szPahtAll))
                        {
                            printf("%S已被删除\n", szPahtAll);
                            continue;
                        }
                    }
                    PTSTR Suffix = PathFindExtensionW(wfd.cFileName);
                    if (!lstrcmp(Suffix, L".exe"))
                    {
                        FixFile(szPahtAll);
                    }
                }
            } while (FindNextFile(hFindFile, &wfd));
        }
    }
    

  • 修复 PE 文件函数:

    VOID FixFile(PTCHAR szPath)
    {
        HANDLE hFile = CreateFileW(
            szPath,
            GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_READ,
            NULL,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL,
            NULL);
        if (hFile == INVALID_HANDLE_VALUE)
        {
            return;
        }
        DWORD dwSize = GetFileSize(hFile, NULL);
        BYTE* pFile = new BYTE[dwSize];
        if (pFile == NULL)
        {
            return;
        }
        DWORD dwCount = 0;
        ReadFile(hFile, pFile, dwSize, &dwCount, NULL);
        BYTE* p = pFile;
        DWORD dwNum = 0;
        DWORD dwSourceSize = 0;
        if (pFile[dwCount-1] == 0x01)
        {
            p = pFile + dwCount - 1;
            while (*p-- != 0x00)
                dwNum++;
            p += 2;
            if (strncmp((char*)p, "WhBoy", 5))
            {
                return;
            }
            pFile[dwCount-1] = 0x00;
            while (*p++ != 0x02);
            dwSourceSize = atoi((char*)p);
            // 偏移等于 = 感染文件总大小 - 原文件大小 - 感染标识字符串长度 - 1
            DWORD dwOffset = dwSize - dwSourceSize - dwNum - 1;
            pFile += dwOffset;
            //SetFilePointer(hFile, NULL, NULL, FILE_BEGIN);
            //WriteFile(hFile, pFile, dwSourceSize, &dwNum, NULL);
            CloseHandle(hFile);
            HANDLE hFile = CreateFileW(
                szPath,
                GENERIC_READ | GENERIC_WRITE,
                FILE_SHARE_READ,
                NULL,
                CREATE_ALWAYS,
                FILE_ATTRIBUTE_NORMAL,
                NULL);
            SetFilePointer(hFile, NULL, NULL, FILE_BEGIN);
            WriteFile(hFile, pFile, dwSourceSize, &dwNum, NULL);
        }
        CloseHandle(hFile);
    }
    

总结

  • 病毒分析工作枯燥而漫长,需要沉心、耐心;
  • 分析过程中很多时候需要动用想象力,大胆假设,细心求证;
  • 进入细节前,要先对所分析的样本有一个概要的了解;
  • 不可钻牛角,一时无法分析出的,可暂时搁置,一来调整心态,二来或许能在后面的分析过程中找到思路;
  • 活用各种工具,不要只局限于 IDA 或 Ollydbg。

PS

  • 因为直接从 word 复制过来,导致图片太小看不清,可辅助 pdf 查看:提取码:jrdu

你可能感兴趣的:(病毒分析,windows,c语言,安全,经验分享)