![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5iZjRmN0AjNkJWZ0ImM5ATN1QmMwMmN5UGM1QGO5QDZl9CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
病毒樣本分析分類
病毒樣本分析大緻分為兩種,一種是行為分析,一種是逆向分析。
行為分析主要是通過系統監控軟體,監控系統中各資源或環境的變化,比如監控系統資料庫、監控檔案、監控程序,以及監控網絡等。當然了,還可以通過 HIPS 軟體來監控病毒的行為。各類系統監控工具或者是 HIPS 軟體都是在系統的不同層面上進行了不同方式的 HOOK。比如說在核心層進行 HOOK,在應用層進行 HOOK。HOOK 的方式也是多樣化的,比如直接 HOOK API 函數,或者 HOOK SSDT 表中的核心函數。
逆向分析主要是通過靜态分析或者動态調試來檢視病毒的反彙編代碼,通過斷點或者單步來觀察病毒的記憶體資料、寄存器資料等相關内容。
行為分析可以快速的确定病毒的行為進而寫出專殺工具,但是對于感染型的病毒是無法通過行為分析進行分析的,或者病毒需要某些觸發條件才能執行相應的動作,這樣因為系統環境的因素,也無法通過行為分析得到病毒的行為特征。逆向分析通過檢視病毒的各個分支流程可以完整的、全面的檢視病毒的各個流程,包括病毒需要在某些條件下才被觸發的流程,都可以通過檢視反彙編代碼進行檢視。但是,對于病毒的逆向分析需要有 Windows 的開發能力,需要有閱讀彙編的代碼。相對于行為分析來講,要求的技術含量更高一些。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5iZjRmN0AjNkJWZ0ImM5ATN1QmMwMmN5UGM1QGO5QDZl9CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
執行個體示範
我們通過一個真實的病毒樣本,進行一次逆向分析,希望可以對病毒分析的入門者有一定的幫助。
下載下傳到樣本後,放置到虛拟機中,虛拟機最好也處于斷網情況,因為我們不确定病毒到底有哪些行為。由于我們是逆向分析,即使一些需要連網後才有的病毒行為,我們也能通過反彙編代碼一覽無餘。放置在虛拟機中後,我們例行用 PEID 查殼之。幸運的是這個病毒沒有,而且是用VC編寫的。
由于無殼,省去了脫殼的步驟。我們用 OD 載入病毒,由于是 VC 編寫的直接跳過 VC 的啟動函數,來到真正的病毒代碼處,有點分析經驗的人都能一眼看出哪些部分是 VC 的啟動代碼,關于如何跳過病毒的啟動代碼就不介紹了。我們直接來到病毒的代碼處,病毒的代碼如下所示(為了保證代碼的美觀,我去掉了 OD 中機器碼的那一列,把注釋列放到了對應代碼的上一行):
00401457 PUSH EBP00401458 MOV EBP,ESP0040145A SUB ESP,41800401460 PUSH EBX00401461 PUSH ESI00401462 PUSH EDI00401463 CALL 00401160
00401457 位址處是病毒代碼的開始位置,也就是我們在用 VC 寫代碼是的 main() 函數處。在 00401463 位址處的代碼 CALL 00401160 是調用了一個函數,我們檢視被調用函數的代碼,代碼如下:
00401160 PUSH EBP00401161 MOV EBP,ESP00401163 SUB ESP,1C00401166 LEA EAX,DWORD PTR SS:[EBP-4]00401169 PUSH EAX0040116A PUSH 28 ; kernel32.GetCurrentProcess0040116C CALL DWORD PTR DS:[]00401172 PUSH EAX ; ADVAPI32.OpenProcessToken00401173 CALL DWORD PTR DS:[]00401179 TEST EAX,EAX0040117B JE SHORT 004011CC0040117D LEA EAX,DWORD PTR SS:[EBP-C]00401180 PUSH EAX ; ASCII "SeDebugPrivilege"00401181 PUSH 0040314800401186 PUSH 0 ; ADVAPI32.LookupPrivilegeValueA00401188 CALL DWORD PTR DS:[]0040118E TEST EAX,EAX00401190 JNZ SHORT 0040119D00401192 PUSH DWORD PTR SS:[EBP-4] ; kernel32.CloseHandle00401195 CALL DWORD PTR DS:[]0040119B LEAVE0040119C RETN
從代碼中我們可以看出,00401160 位址處的函數依次調用了如下的 API 函數,分别是:GetCurrentProcess()->OpenProcessToken()->LookupPrivilegeValueA()->CloseHandle()。從前三個 API 函數我們可以看出,這個函數的作用是調整目前程序的權限,我們配合 00401181 位址處入棧的字元串 “SeDebugPrivilege” 可以看出,這個函數将目前程序的權限調整為具有調試的權限。
回到前面繼續看我們病毒的主流程,接着上面的代碼如下:
00401468 MOV ESI,103 ; [ebp - 418]儲存系統目錄0040146D LEA EAX,DWORD PTR SS:[EBP-418]00401473 PUSH ESI00401474 PUSH EAX ; kernel32.GetSystemDirectoryA00401475 CALL DWORD PTR DS:[] ; [ebp - 314]儲存Windows目錄0040147B LEA EAX,DWORD PTR SS:[EBP-314] 00401481 PUSH ESI00401482 PUSH EAX ; kernel32.GetWindowsDirectoryA00401483 CALL DWORD PTR DS:[] ; [ebp - 10c]儲存目前病毒檔案的路徑(包含病毒檔案名)00401489 LEA EAX,DWORD PTR SS:[EBP-10C]0040148F PUSH ESI00401490 XOR EBX,EBX00401492 PUSH EAX00401493 PUSH EBX ; kernel32.GetModuleFileNameA00401494 CALL DWORD PTR DS:[] ; MSVCRT.strrchr0040149A MOV EDI,DWORD PTR DS:[]004014A0 LEA EAX,DWORD PTR SS:[EBP-10C]004014A6 PUSH 5C004014A8 PUSH EAX ; 從右找出第一個"\"的位置004014A9 CALL EDI004014AB POP ECX004014AC CMP EAX,EBX004014AE POP ECX004014AF JE SHORT 004014B3 ; 得到病毒的目前路徑004014B1 MOV BYTE PTR DS:[EAX],BL004014B3 PUSH 1 ; 此處是對麥克風裝置進行設定,這裡沒有詳細看004014B5 CALL 004016AC004014BA POP ECX004014BB PUSH EBX004014BC PUSH EBX004014BD PUSH EBX004014BE PUSH 00401349004014C3 PUSH 400004014C8 PUSH EBX ; kernel32.CreateThread004014C9 CALL DWORD PTR DS:[]
看到該處反彙編代碼處,我們可以看出,病毒獲得了系統目錄及 Windows 目錄的路徑,還有病毒的目前路徑,以及病毒的檔案名。在 004014c9 位址處,調用了 CreateThread() 函數,該函數用來建立一個線程。CreateThread() 函數的函數原型如下:
HANDLE CreateThread( LPSECURITY_ATTRIBUTESlpThreadAttributes, // SD DWORD dwStackSize, // initial stack size LPTHREAD_START_ROUTINElpStartAddress, // thread function LPVOID lpParameter, // thread argument DWORD dwCreationFlags, // creation option LPDWORD lpThreadId // thread identifier);
CreateThread() 函數的第三個參數是線程函數的位址,由于 WIN32 API 的調用方式是 stdcall 方式,是以函數的入棧方式是從右至左,那麼線程的函數位址是在 004014be 的指令給出,該處的指令為 push 00401349。既然知道了線程函數的位址是 401349,那麼我們就看一下這個線程函數的代碼完成了什麼樣的功能,代碼如下:
00401349 PUSH EBP0040134A MOV EBP,ESP0040134C PUSH ECX0040134D PUSH ECX0040134E PUSH EBX0040134F PUSH ESI00401350 PUSH EDI00401351 NOP ; USER32.SendMessageA00401352 MOV ESI,DWORD PTR DS:[]……00401367 PUSH EDI ; ASCII "AVP.AlertDialog"00401368 PUSH 00403134 ; USER32.FindWindowA0040136D CALL DWORD PTR DS:[]……00401384 PUSH EDI00401385 PUSH EAX ; USER32.FindWindowExA00401386 CALL DWORD PTR DS:[]……004013AA PUSH EDI004013AB PUSH EDI004013AC PUSH DWORD PTR SS:[EBP-8] ; USER32.FindWindowExA004013AF CALL DWORD PTR DS:[]…… ; USER32.FindWindowExA004013D8 CALL DWORD PTRDS:[]……004013FD PUSH EDI004013FE PUSH DWORD PTR SS:[EBP-8] ; USER32.FindWindowExA00401401 CALL DWORD PTR DS:[]……00401420 PUSH EDI ; ASCII "AVP.Product_Notification"00401421 PUSH 004030DC ; USER32.FindWindowA00401426 CALL DWORD PTR DS:[]……0040143C PUSH EDI ; USER32.FindWindowA0040143D CALL DWORD PTR DS:[]……0040144F PUSH EAX00401450 CALL ESI00401452 JMP 0040135F
從該反彙編代碼處我們能看出,整個線程函數處于一個死循環中,因為函數的最後一句代碼 00401452 jmp 0040135f 是一個向上的跳轉指令。在循環中基本上隻完成了一個任務,也就是不斷的查找(查找視窗調用的是 FindWindowEx() 函數)某個視窗,隻要找到那個視窗就調用 SendMessage 函數向它發送消息。通過它查找的視窗是 “AVP.AlertDialog” 和 “AVP.Product_Notification”,說明這段代碼是通過發送消息來躲過特定防毒軟體的主動防禦。我們接着看病毒的主要流程,代碼如下:
004014CF LEA EAX,DWORD PTR SS:[EBP-314] ; windows目錄004014D5 PUSH EAX004014D6 LEA EAX,DWORD PTR SS:[EBP-10C] ; 病毒目前目錄004014DC PUSH EAX ; MSVCRT._stricmp004014DD CALL DWORD PTR DS:[]004014E3 POP ECX004014E4 TEST EAX,EAX004014E6 POP ECX ; 這個分支很重要,它判斷病毒的所在位置004014E7 JNZ 00401612
這段代碼是判斷病毒的目前位置,病毒的目前位置決定了病毒的流程走向。這是在病毒中一個很重要的分支。由于目前病毒不處于 C:\windows 目錄下,那麼流程必然會跳走,我們先來看跳走的流程,傳回來在繼續檢視未跳走的流程。
; MSVCRT.sprintf00401612 MOV EDI,DWORD PTRDS:[]00401618 LEA EAX,DWORD PTRSS:[EBP-314] ; ASCII "mppds.exe"0040161E PUSH 00403020 00401623 PUSH EAX00401624 LEA EAX,DWORD PTRSS:[EBP-210] ; ASCII"%s\%s"0040162A PUSH 0040307C0040162F PUSH EAX00401630 CALL EDI00401632 ADD ESP,10 ; 儲存病毒路徑00401635 LEA EAX,DWORD PTRSS:[EBP-10C]0040163B PUSH ESI0040163C PUSH EAX0040163D PUSH EBX ; kernel32.GetModuleFileNameA0040163E CALL DWORD PTRDS:[]00401644 LEA EAX,DWORD PTRSS:[EBP-210]0040164A PUSH EBX0040164B PUSH EAX0040164C LEA EAX,DWORD PTRSS:[EBP-10C]00401652 PUSH EAX ;kernel32.CopyFileA00401653 CALL DWORD PTRDS:[] ; kernel32.GetCurrentProcessId00401659 CALL DWORD PTRDS:[]0040165F PUSH EAX00401660 LEA EAX,DWORD PTRSS:[EBP-10C]00401666 PUSH 4000401668 PUSH EAX00401669 LEA EAX,DWORD PTRSS:[EBP-210]0040166F PUSH 4000401671 PUSH EAX00401672 8D85 ECFCFFFF LEA EAX,DWORD PTR SS:[EBP-314] ; ASCII "%s %c%s%c%d"00401678 PUSH 004030B40040167D PUSH EAX0040167E CALL EDI00401680 ADD ESP,1C00401683 LEA EAX,DWORD PTRSS:[EBP-314]00401689 PUSH EBX ; 以帶參數的方式啟動拷貝到C槽的mppds.exe檔案0040168A PUSH EAX ; kernel32.WinExec0040168B CALL DWORD PTRDS:[]
上面的反彙編代碼調用了 CopyFile() 函數将自身拷貝到 Windows 目錄下,并且調用 WinExec() 函數啟動拷貝到 Windows 目錄下的 mppds.exe,在啟動的時候為 mppds.exe 帶了參數,對 WinExec() 的調用棧如下所示:
0012FAF8 0012FC10 |CmdLine ="C:\WINDOWS\mppds.exe @C:\Documents and Settings\Administrator\桌面\[email protected]"0012FAFC 00000000 \ShowState = SW_HIDE
我們關閉目前 OD,不要讓病毒以該參數啟動,我們啟動另外一個 OD 來調試 Windows 目錄下的 mppds.exe ,并且調試時帶上如上的參數。我們直接運作到那個關鍵的跳轉處,繼續往下執行,反彙編代碼如下:
; kernel32.GetCommandLineA004014ED CALL DWORD PTRDS:[]…… ; 省略了中間的代碼是得到參數中病毒原來的位置00401542 ADD ESP,1800401545 MOV BYTE PTR SS:[EBP+EDI-10D],BL0040154C PUSH DWORD PTR SS:[EBP-4]0040154F PUSH EBX00401550 PUSH 1F0FFF ; kernel32.OpenProcess00401555 CALL DWORD PTRDS:[]……00401561 PUSH EBX00401562 PUSH EDI ; kernel32.TerminateProcess00401563 CALL DWORD PTRDS:[]00401569 PUSH -10040156B PUSH EDI; kernel32.WaitForSingleObject0040156C CALL DWORD PTRDS:[]00401572 LEA EAX,DWORD PTR SS:[EBP-10C]00401578 PUSH EAX ; kernel32.DeleteFileA00401579 CALL DWORD PTRDS:[]0040157F TEST EAX,EAX00401581 JNZ SHORT 0040158D00401583 PUSH 1 ; kernel32.Sleep00401585 CALL DWORD PTRDS:[]0040158B JMP SHORT 00401572
上面的代碼是 GetCommandLine() 函數得到病毒的原來的位置,然後通過 OpenProcess() 和 TerminateProcess() 兩個函數結束掉原來病毒的程序,然後調用 DeleteFile() 函數删除原來的病毒。
; ASCII "explorer.exe"0040158D PUSH 004030C4 ; 該函數用來查找explorer.exe程序的PID00401592 CALL 00401000…… ; 釋放mppds.dll檔案004015CD CALL 0040109C…… ; 注入mppds.dll到explorer.exe程序004015E6 CALL 004011F9…… ; 将mppds.exe寫入系統資料庫的啟動項00401609 CALL 004017A5…… ; 病毒的另一個關鍵分支執行完畢00401610 JMP SHORT 00401691
00401592 位址處的 CALL 是調用了一個函數,其函數的作用是獲得 explorer.exe 程序的 PID,在其反彙編代碼中依次調用了幾個函數:
CreateToolhelp32Snapshot()->Process32First()->Process32Next()->CloseHandle(),這個是個典型的周遊系統程序的代碼,而在周遊的過程中始終在拿程序名與 “explorer.exe” 進行比較,如果相等的會則結束周遊過程,并傳回 explorer.exe 程序的 PID。
004015cd 處的 CALL 調用的函數是釋放一個 DLL 檔案到系統路徑,其反彙編代碼中依次調用了如下幾個函數:
FindResource()->SizeofResource()->LoadResource()->SetHandleCount()->fopen()->fwrite()->fclose()。這也是一個典型的通過資源釋放檔案的過程,該過程從 mppds.exe 檔案的資源中釋放出 mppds.dll 檔案到系統目錄下。
004015e6 位址處的 CALL 調用的函數是将釋放出來的 mppds.dll 檔案注入到 explorer.exe 程序中,也就是說位址 401592 的 CALL 和位址 15cd 的 CALL,是為目前位址的注入做準備的。在分析代碼時我們可以看一些主要的代碼,整個功能也就明白了,004015e6 位址處 CALL 的函數中調用了 CreateRomoteThread() 函數,通過這一個函數我們就能确定該函數的目的是用來進行注入的。
00401609 位址處的 CALL 是将病毒的加入到系統資料庫的啟動項中,因為在這個 CALL 中調用了系統資料庫操作相關的函數,另外配合幾個字元串常量,我們就很容易的發現了該函數的作用了。
到這裡,整個病毒的功能我們就分析完成了,至于釋放出來的 mppds.dll 的功能這裡就不再繼續分析了。我們這裡完整的分析了一個病毒,從我們分析的過程中可以看出,熟悉 Win32 API 和一些程式設計知識對于我們分析病毒是非常有幫助的。在反病毒廠商招聘病毒分析師時其中就要求熟悉 Win32 API、C 語言、彙編語言等知識。如果有對反病毒有興趣的朋友,可以到一些反病毒網站參考一下他們關于病毒分析的招聘要求,就可以有方向性的進行學習了。希望這篇文章能給你帶來幫助。
注:文章時很早以前寫的,病毒樣本已經找不到了,而且提供病毒樣本也違法。