天天看點

bouml 逆向分析c++_簡單病毒樣本分析

bouml 逆向分析c++_簡單病毒樣本分析

病毒樣本分析分類

        病毒樣本分析大緻分為兩種,一種是行為分析,一種是逆向分析。

        行為分析主要是通過系統監控軟體,監控系統中各資源或環境的變化,比如監控系統資料庫、監控檔案、監控程序,以及監控網絡等。當然了,還可以通過 HIPS 軟體來監控病毒的行為。各類系統監控工具或者是 HIPS 軟體都是在系統的不同層面上進行了不同方式的 HOOK。比如說在核心層進行 HOOK,在應用層進行 HOOK。HOOK 的方式也是多樣化的,比如直接 HOOK API 函數,或者 HOOK SSDT 表中的核心函數。

        逆向分析主要是通過靜态分析或者動态調試來檢視病毒的反彙編代碼,通過斷點或者單步來觀察病毒的記憶體資料、寄存器資料等相關内容。

        行為分析可以快速的确定病毒的行為進而寫出專殺工具,但是對于感染型的病毒是無法通過行為分析進行分析的,或者病毒需要某些觸發條件才能執行相應的動作,這樣因為系統環境的因素,也無法通過行為分析得到病毒的行為特征。逆向分析通過檢視病毒的各個分支流程可以完整的、全面的檢視病毒的各個流程,包括病毒需要在某些條件下才被觸發的流程,都可以通過檢視反彙編代碼進行檢視。但是,對于病毒的逆向分析需要有 Windows 的開發能力,需要有閱讀彙編的代碼。相對于行為分析來講,要求的技術含量更高一些。

bouml 逆向分析c++_簡單病毒樣本分析

執行個體示範

        我們通過一個真實的病毒樣本,進行一次逆向分析,希望可以對病毒分析的入門者有一定的幫助。

        下載下傳到樣本後,放置到虛拟機中,虛拟機最好也處于斷網情況,因為我們不确定病毒到底有哪些行為。由于我們是逆向分析,即使一些需要連網後才有的病毒行為,我們也能通過反彙編代碼一覽無餘。放置在虛拟機中後,我們例行用 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 語言、彙編語言等知識。如果有對反病毒有興趣的朋友,可以到一些反病毒網站參考一下他們關于病毒分析的招聘要求,就可以有方向性的進行學習了。希望這篇文章能給你帶來幫助。

        注:文章時很早以前寫的,病毒樣本已經找不到了,而且提供病毒樣本也違法。

bouml 逆向分析c++_簡單病毒樣本分析