Emotet木馬運行原理完全分析

作者:浪子_三少

預估稿費:1000RMB

(本篇文章享受雙倍稿費 活動鏈接請點擊此處)

投稿方式:發送郵件至linwei#360.cn,或登陸網頁版在線投稿

釣魚郵件

最近公司收到一些釣魚木馬郵件,內容形式如下:

感染Doc文檔

郵件里有個鏈接,當點開鏈接後會下載一個doc文檔,打開文檔會發現有宏代碼

經過一些列解密後會執行shell執行宏命令,列印出這個信息出來後發現,原來執行了powershell命令

是從網路url中下載一些文件並且 StartProcess,看來這才是真正的木馬,下載的是一個exe,名字是隨機的四個字元的exe名字。

木馬分析

下面就開始分析這個木馬,用ollydbg載入木馬,在Winmain函數入口點下斷點:

F9飛一次,停在了入口,慢慢 F8單步,木馬直接到了0300149C的地址

F7繼續進入函數:

進入函數不久木馬一直兩個代碼間循環,無法繼續往下走,

(1) 循環起止1.

(2) 循環往上跳

當我們f9的時候一直不能跳出循環,我們通過IDA查看發現他做了一個時間判斷故意為了防止被分析做了一個時間開關,這個時間有點太大了。

我們直接修改EIP到循環外的地址,跳過這個循環。

繼續往下走。

下面有Call VirtualProtect,而這個VirtualProtect把剛才分配的地址改寫成PAGE_EXECUTE_READWRITE的屬性,也就是變成一個可讀寫可執行的代碼頁。

下面就到了木馬對內置的加密代碼的解密了,可以明顯看到原始數據被加密了。

解密完後我們可以看到內存地址內容了,

到此這個函數就執行完畢,返回到入口函數位置後,下面有個cal [3011744] 實際上是前面函數內解密分配的shellcode函數 。

實際上是call 001AA618,進入函數

再次進入就進入真正的函數位置了

Shellcode

很明顯字元串 75 73 65 72 33 32用位元組碼寫出來,作者做了一些免殺處理。

在shellcode遇到第一個函數這個函數call 001AA008,函數的功能是查找木馬的導入表找到LoadLibraryA函數和GetProcAddress這兩個函數地址

接下來就是通過LoadLibrary 和GetProcAddress函數動態獲取一些API的地址,

一共要獲取幾十個函數的地址,這塊我們跳過去,F9一路飛到地址001AB4EF

這個函數直接調用函數下面的地址,繼續 F8單步到001AB50F

繼續F7進入001AB50F函數

在這裡他會判斷木馬目錄下有沒有apfHQ文件,所以我們事先需要生成一個apfHQ文件在目錄下,空文件也行,這個過程完畢後就進入了01AA408函數。

繼續往1AA408函數內部F7,會經過一些列的RegisterClassEx, CreateWinodws、GetMssage等窗口函數後就進入了1AA108函數

繼續F7進入1AA108函數,在進入函數不久,木馬會去取一個內存數據,並且判斷4550 「PE」這個標誌位

接下來調用 GetStartUpInfo,取得當前進程的啟動信息

然後接續獲得當前進程的命令行參數

然後調用CreateProcess 來把自己作為子進程創建起來,而且創建標誌位是CREATE_SUSPENDED

0x00000004

是以懸掛進程的方式創建子進程

然後繼續通過GetThreadContext函數獲得子進程的線程上下文

然後在子進程的0x400000的地址遠程分配一個大小0xC00大小的內存,內存屬性0x40,即讀寫可執行的屬性內存PAGE_EXECUTE_READWRITE 0x40

接下來木馬就會使用ZwWriteVirtualMemory函數往子進程的0x400000地址寫入大小0x400的數據,通過查看寫入的數據發現是個pe頭

下面就是pe頭數據

提取PE文件

然後木馬會解析這個內存里的pe文件的各個節.text .data .rdata 等等節段,通過ZwWriteVirtualMemory函數分別往子進程的相應內存里遠程寫入數據。

分別寫完數據後,然後改寫子進程pe載入器的子進程的執行載入的首地址為0x400000

然後使用SetThreadContext設置子進程的當前線程EIP 指向0x408FE5

最後調用ResumeThread函數恢復子進程的線程繼續執行

最後父進程退出,子進程開始干一些真正的盜取行為,到此我們可以知道木馬是通過創建子自身子進程通過GetThreadContext、ZwWriteVirtualMemory、SetThreadContext、ResumeThread,來實現hook方法達到隱藏真實pe的目的來增加分析人員的分析難度,他的真PE文件加密存貯在數據段中解密後如下:

PE文件分析

接下來我們就來講解這個從內存里扣出來的pe文件到底怎麼工作的。Emotet在入口點,通過hash對比去查找ntdll.dll,kernel32.dll的模塊句柄,而不是通過我們常用的方法GetMoudleHanlde()的方法去獲取句柄,

看看serverlog_search_moudle這個函數的實現,在函數內部使用了[[[FS:[30]+0xc]+0xc]+0x30]的方法去獲取模塊的名字,在ring3層FS寄存器指向的是線程環境塊,0x30的偏移即指向PEB(進程環境塊),PEB的0xc就是指向LDR表,後面的偏移就是從LDR表中獲取模塊的BaseName,計算相應的hash對比去從LDR表中獲取模塊的句柄。

獲取了模塊首地址後,通過解密.data節段的加密導入表來獲取相應的函數地址

下面是獲取到的ntdll的對應函數表

下面是獲取的kernel32的對應函數表

接下來就進入了init初始化的工作

首先會創建一個事件加一個互斥體

當這個mutex互斥體之前不存在時會再次把自身進程啟動一遍,如果互斥體存在就進入的工作的函數里,這樣也是為了多進程的方式。

當進入工作函數server_get_info_and_timer時,就表示木馬已經開始真正的工作了。

PE文件工作分析

工作初期木馬會再次獲取他所需的函數表,方式類似之前不再贅訴,他要獲取advapi32.dll、ole32.dll、shell32.dll、crypt32.dll、urlmon.dll、wininet.dll的所需函數,如下:

然後木馬會獲取windows目錄,然後計算系統目錄所在的磁碟的磁碟id。

接下來就是取當前電腦的電腦+磁碟id的組合,並且根據磁碟id來計算當前電腦所要生成的服務程序的名字。

服務的名字是根據之前磁碟id, 在字元串」agent,app,audio,bio,bits,cache,card,cart,cert,com,

crypt,dcom,defrag,device,dhcp,dns,event,evt,flt,gdi,group,

help,home,host,info,iso,launch,log,logon,lookup,man,math,

mgmt,msi,ncb,net,nv,nvidia,proc,prop,prov,provider,reg,rpc,

screen,search」中計算出對應的字元來填充組合成所要生成的服務名和exe的名字。

得到本木馬服務的exe名字後就計算系統目錄里的木馬exe的crc的值

接下來就是獲取電腦名,並且會將電腦中的非0-9、a-z、A-Z的字元替換成X,並且最多只獲取16個字元的名字,然後和磁碟id組合起來

接著木馬就會使用CreateTimerQueueTimer函數創建一個Timer計時器,

流程就進入了serverlog_posturl_timer函數空間

根據當前的運行狀態執行同的邏輯,case 1:時表示木馬正準備初始化,然後設置狀態為2,定時器執行到case 2:時就會將本木馬exe創建成一個windows服務,服務名就是之前計算出來的service_name, 然後設置成狀態3,進入case 3:會填充一些IP地址與埠

IP地址和埠直接寫死在.data節,可以看到內存里內置了很多IP與埠,0x1BB即433埠,1F90即8080埠

Case 3還會初始化加密上下文

使用的rsa演算法,導入了內存里的publickey,0x13即RSA_CSP_PUBLICKEYBLOB

Case 3執行完畢會設置成狀態4,下次定時器的時候就進入case 4,case 4會把枚舉當前電腦的進程信息,木馬的exe的crc,電腦名磁碟id填充到待加密的緩衝區

然後對以上進行加密,再post到伺服器的433埠

注意在發送到433之前,木馬有進行了一次rsa加密

然後使用post的方式發送到伺服器的433埠。

然後木馬通過InternetReadFile

函數獲取伺服器的返回結果,這個結果會執行各種流程,其中有一個流程是從遠程伺服器去下載exe,並且執行。

如果有更新的木馬會調用start_download_exe函數去實現自我更新

到此基本上木馬所有主要工作流程都已經分析完畢。


推薦閱讀:

360 殺毒、安全衛士和金山毒霸、金山衛士以及瑞星哪個更好?為什麼?
病毒軟體寫免殺有多難?
怎麼能讓自己寫的程序不被360提示木馬?
在咖啡館遇見陌生人借用電腦,會是騙子嗎?

TAG:木马 | 计算机病毒 | 网络安全 |