天天看點

分享一個之前寫的mbr的分析過程

一、概述(前言)

修改MBR,挂鈎13号中斷,繼續挂鈎BlLoaderBlock結構得到核心基址,完成對IoInitSystem挂鈎執行樣本的驅動檔案,為防止MBR被修複又挂鈎了磁盤的IRP讀寫。

流程圖

分享一個之前寫的mbr的分析過程

圖一

二、技術細節詳細分析

脫殼

首先查殼,顯示為ASPack(2.12-2.42),方法就是直接esp定律。od會幫你斷,之後一個大跳到達oep,脫殼結束,如下圖二所示。

分享一個之前寫的mbr的分析過程

圖二

脫殼之後的樣本

脫殼結束之後看看樣本做了些什麼事情,f5之後可以發現一個被标紅的位址(0x7FFE0500),在32位和64位Windows中,共享資料的隻讀使用者模式位址均為0x7FFE0000,也就是_KUSER_SHARED_DATA結構的位址。

當然三環是沒有權限修改的,在核心也有一份一模一樣的資料0xffdf0000(0x32)。之後使用windbg列印了該結構發現根本沒有偏移0x500的結構,列印該位址也沒有什麼特殊意義的值。那麼該值可能是它作為零環和三環标志位的一個位址,畢竟是MBR病毒(隻是猜測),如圖三所示。

分享一個之前寫的mbr的分析過程
分享一個之前寫的mbr的分析過程

圖三

日志檔案

樣本接着會建立c:\windows\temp\00000218.tmp檔案,該檔案記錄着目前程式運作之後的狀态,會将目前的資訊記錄到檔案中,如圖四所示。

分享一個之前寫的mbr的分析過程

圖四

擷取資訊

通過IOCTL_VOLUME_LOGICAL_TO_PHYSICAL擷取檔案的扇區偏移量,樣本查詢的是\\\\.\\C:,就是得到在實體磁盤的偏移,簡單來說就是找到實體磁盤下c盤的位置,如圖五所示。

分享一個之前寫的mbr的分析過程

圖五

樣本會檢查0x7FFE0500位址下的值是否為0xEE00A121(也許該标志位是用來判斷目前系統是否已經被感染)。如果不是就建立名為// Global\\7BC8413E-DEF5-4BF6-9530-9EAD7F45338B的互斥體,接着會獲得\\\\.\\PhysicalDrive0的資訊也就是MBR(位于整個硬碟的0磁道0柱面1扇區),主要用來引導系統的啟動,如圖六所示。

分享一個之前寫的mbr的分析過程

圖六

獲得原始的mbr的資訊,并判斷讀取出來的内容是否是正确的,如圖七所示。

分享一個之前寫的mbr的分析過程

圖七

修改MBR

樣本會将目前獲得的分區資訊記錄到日志檔案中,之後将自己的驅動檔案寫入到0xfff00000位置,接着将自己的其他shellcode代碼寫入到7800-7a00的位置7c00保留原始的mbr引導,在将原始的mbr給覆寫掉,到此寫入就完成了。這裡有個疑問就是怎麼知道寫入的扇區的位置,具體的計算方式如下(7800/200=3c,7a00/200=3d,7c00/200=3f)。在分析引導檔案的時候會得到寫入磁盤的位置,我們隻需要觀察扇區的位置是否一緻就行了,如圖八所示。

分享一個之前寫的mbr的分析過程

圖八

接着樣本使用MoveFileExA重新開機之後删除自身,拷貝自己到目前目錄下,這裡改了一個位元組,并修改字尾為.dll,如圖九所示。

分享一個之前寫的mbr的分析過程

圖九

注冊目前dll,啟動目前檔案夾下的dll檔案,睡眠1800000之後重新開機系統,如圖十所示,到目前為止樣本第一次啟動之後執行的事情基本差不多就是這樣了。

分享一個之前寫的mbr的分析過程
分享一個之前寫的mbr的分析過程

圖十

分析修改之後的MBR和挂鈎流程

挂鈎13号中斷

開啟了漫長的挂鈎之旅,通過分析知道樣本會申請2kb的記憶體空間(主要目的是長期駐留記憶體,保證在挂鈎函數正常的執行),之後将自身的代碼拷貝到申請的記憶體中,接着在0磁道的3d扇區取兩個扇區的内容追加寫入到申請的記憶體空間(這也解決了我們上面的疑問在圖八中提出的,就是到底把代碼寫到哪裡去了,從這裡我們可以看出寫入的位置和計算的位置是符合的),如圖十一所示。

分享一個之前寫的mbr的分析過程

圖十一

接着對13号中斷挂鈎,這裡有很多小細節需要注意。雖然代碼一直在目前記憶體和申請的記憶體來回執行,但是偏移是一樣的,之後通過修改13号中斷的偏移位址和段位址,完成對13号中斷的hook。

(原始的13号中斷的位址記錄在es:73h下面),之後将原始的mbr引導代碼寫回到00:7c00處,在将執行權限交還給mbr,到這裡13号中斷挂鈎也結束了,如圖十二所示。

分享一個之前寫的mbr的分析過程

圖十二

挂鈎實模式下的Ntldr

系統在啟動的時候會啟動Ntldr,如果讀入磁盤的内容到記憶體中就會執行int 13,那麼就會進入到樣本hook的流程中,之後完成對Ntldr的BlLoadBootDrivers下一行挂鈎。首先樣本會判斷目前ah的值,其中42為拓展讀,2為非拓展讀,如果滿足兩個中的一個就會進入下面的流程,執行原來的13号中斷傳回,如圖十三所示。

分享一個之前寫的mbr的分析過程

圖十三

接下來儲存現場之後執行原始流程,由于int13将代碼讀入到記憶體中,那麼樣本就可以對讀入的代碼進行特診掃描,在int 13下不同的ah對應不同的效果。

分享一個之前寫的mbr的分析過程

圖十四

這裡檢查的特診碼的為8B F0 85 F6 74 21/22 80 3D,如圖十五所示。

分享一個之前寫的mbr的分析過程

圖十五

如果找到對應的位置BlLoadBootDrivers的下一行代碼,改變指定位置的代碼為ff15,也就是間接call,call後面的位址存放的是要跳轉的位址。

這裡存的值是下一個扇區的首位址,如圖十六。

分享一個之前寫的mbr的分析過程

圖十六

接着樣本會進行查找特征碼為83 C4 02 E9 00 00 E9 FD FF的位置,找到之後nop掉,提升棧指針,在将之後的一個位元組的代碼清零,如圖十七所示。

分享一個之前寫的mbr的分析過程

圖十七

挂鈎32位保護模式IoInitSystem.

這個樣本在win7 32位下挂鈎Ntldr的BlLoadBootDrivers是挂不上去的,是以調試不了,但是不影響,就算能調也不一定知道它在幹嘛,一樣的需要科普一下其他的知識點(到處都是知識盲區)。當樣本再次獲得執行權限的時候已經通過Startup.com切換到保護模式下(之後遇到一些問題還是把xp裝上了,在xp下es變成了9f00)。首先是在esp+24的地方拿到osloder的基位址,之後搜尋特診碼,獲得BlLoaderBlock結構的位址,這個結構和_LDR_DATA_ TABLE_ENTRY前幾項一樣,如圖十八所示。

分享一個之前寫的mbr的分析過程

圖十八

可以通過周遊連結清單的方式得到ntosknl的基位址,之後在定位到Ntoskrnl! IoInitSystem的位址,如圖十九所示。

分享一個之前寫的mbr的分析過程

圖十九

最後将得到的核心基位址和IoInitSystem函數位址放在9f40c和9f404中,如圖二十所示。

分享一個之前寫的mbr的分析過程

圖二十

之後完成對IoInitSystem函數的hook,由于我們已經知道了IoInitSystem函數的位移,那麼隻需要把這個相對位址替換成樣本的相對位址就行了。最後樣本把9f400記憶體的資料放到ntosknl最後的200h中,如圖二十一所示。

分享一個之前寫的mbr的分析過程

圖二十一

加載驅動檔案

直接看代碼當然還楞了一下,怎麼把12345678h壓入堆棧,這有什麼用啊。但是當真實運作之後的值是被改變了的,其實在圖二十的時候就已經被改變了,修改之後的值為IoInitSystemhe函數位址和核心基位址,如圖二十二所示。

分享一個之前寫的mbr的分析過程

圖二十二

之後由于看ida(沒有符号連結,也不知道該位址代表的意義)太難了,這個時候核心都加載起來了可以使用Windbg了,那就使用Windbg來調試。之後通過ExAllocatepool的crc32得到函數位址,申請1a8h的記憶體空間從偏移55的地方将代碼拷貝到申請的記憶體空間,如圖二十三所示。

分享一個之前寫的mbr的分析過程

圖二十三

之後進入申請的記憶體空間中繼續執行,首先是執行IoInitSytem的流程(執行的時間有點長),之後通過ntopenfile的crc32找到對應的函數位址(構造參數的位址不是三環的位址,當時寫的時候沒注意),如圖二十四所示。

分享一個之前寫的mbr的分析過程
分享一個之前寫的mbr的分析過程

圖二十四

之後調用NtOpenFile打開\??\PhysicalDrive0,目的是找它寫入的驅動檔案,這裡如果不調試的話很難知道它在幹什麼,一開始我也有疑問就是打開檔案的字元串放在哪裡,後來找了找才知道它已經被拷貝搭配申請的記憶體空間了,如圖二十五所示。

分享一個之前寫的mbr的分析過程

圖二十五

之後又調用ExAllocatepool申請了0x3bc00位元組大小的記憶體空間用來存儲讀取到了驅動檔案。使用NtReadFile讀取指定偏移的驅動檔案,如圖二十六所示。

分享一個之前寫的mbr的分析過程

圖二十六

之後根據檔案的SizeOfImage,重新申請一塊記憶體空間,将目前的驅動檔案拉伸之後存放到新申請的記憶體空間中,如圖二十七所示。

分享一個之前寫的mbr的分析過程

圖二十七

接着樣本會找到驅動的入口位址,然後直接調用(什麼都沒有修複,可能是在驅動中執行其他操作),之後判斷成功與否,失敗會釋放資源,成功清零目前的代碼,之後回到正常的流程中進行執行,如圖二十八所示。

分享一個之前寫的mbr的分析過程

圖二十八

驅動檔案

修複自身

到目前為止整個引導的過程就結束了,現在分析一下它的驅動檔案。樣本進來做的第一件事是修複重定位表,從之前的分析流程中,也可以知道樣本跳到這個驅動檔案之前是沒有做任何修複的,隻是簡單的拉伸了一下pe檔案。樣本的修複重定位如圖二十九所示。

分享一個之前寫的mbr的分析過程

圖二十九

最後完成導出表的修複,整個pe基本就修複完成了,如圖三十所示。

分享一個之前寫的mbr的分析過程

圖三十

建立系統線程

樣本接着建立一個系統線程,在這之前又指派了一串代碼,這個代碼會在新線程中使用(看的交叉引用),如圖三十一所示。

分享一個之前寫的mbr的分析過程

圖三十一

進入線程函數之後可以發現,它首先解密了一段代碼,這個是pe檔案,在解密之後又進行了重定向,之後判斷目前系統版本,主要目的是根據系統版本選擇獲得PsLoadedModuleList位址的方式,之後将控制權交給新的解密出來的pe檔案,如圖三十二所示。

分享一個之前寫的mbr的分析過程

圖三十二

解密後的驅動檔案

之後又到了一個入口函數,一開始還比較疑惑它把PsLoadedModuleList傳進來幹什麼,子產品隐藏?不應該啊它壓根就不是按照正常的方式加載驅動的,連結清單也不會有啊.之後才發現它IAT還沒有修(可以通過PsLoadedModuleList找到各個子產品的導出函數,重定位在進來之前就修複了),這裡的第一個函數就是修改它的IAT,如圖三十三所示。

分享一個之前寫的mbr的分析過程

圖三十三

接着擷取了之前那個驅動的第二個區段的RVA(.rdata)放在全局變量中,之後擦除PE頭的資訊(也是之前的那個驅動),如圖三十四。

分享一個之前寫的mbr的分析過程
分享一個之前寫的mbr的分析過程

圖三十四

接着函數格式化了它的字元串,但這個函數是真的複雜,如圖三十五所示,ida還不能反編譯。

分享一個之前寫的mbr的分析過程

三十五

話是這樣說,但是我也沒有真的去看,因為之後它調用了一個核心中初始化字元串的RtlInitUnicodeString(核心中字元不能和三環一樣亂來,需要按照要求初始化為UNICODESTRING的格式),如圖三十六所示。

分享一個之前寫的mbr的分析過程

三十六

之後它獲得了\Device\HardDisk0對象之後在OBJECT_DIRECTORY中周遊驅動對象(完成對磁盤的hook,這裡的資料結果不太熟悉,看着像是在hook)如圖三十七所示。

分享一個之前寫的mbr的分析過程

三十七

接下來建立一個過濾裝置,綁定函數,如果之前的代碼執行失敗就會執行之後的代碼,這個代碼就是對磁盤的hook(前提需要之前的代碼執行失敗,是以之前的那個猜測是另外一種方式的hook),如圖三十八所示。

分享一個之前寫的mbr的分析過程
分享一個之前寫的mbr的分析過程
分享一個之前寫的mbr的分析過程

三十八

繼續建立新的系統線程

之後做了很多irp和事件的操作,由于水準有限(自己寫驅動的時候就沒怎麼用這些東西),不知道在幹嘛(但是好像是在做一些檢查,這裡就直接跳過了),來到新的線程中進行假裝分析一下,之後樣本擷取了目前計算機的配置資訊,如圖三十九所示。

分享一個之前寫的mbr的分析過程

圖三十九

接着使用NtDeviceIoControlFile函數繼續擷取目前計算機的配置資訊,主要擷取的資訊包括系統盤符(c盤)、符号連結為scsi2的SCSIDISK資訊、擷取驅動器版本,傳回GETVERSIONINPARAMS結構指針、使用IOCTL_STORAGE_QUERY_PROPERTY擷取序列号,如圖四十所示。

分享一個之前寫的mbr的分析過程

圖四十

完成準備工作之後驅動又新啟動了三個線程繼續工作,線程啟動後把0xFFDF0500的值改為0xEE00A121,這裡也填了一個坑,當驅動正常加載之後能夠将0xFFDF0500标志位的值進行修改(對應使用者層是0x7ffe0500,同一份實體記憶體,做了虛拟位址的映射,但是對3環和0環來說權限不同)。但由于對核心結構的生疏很多東西分析起來也很困難,是以這裡就到此為止了,如圖四十一所示。

分享一個之前寫的mbr的分析過程
分享一個之前寫的mbr的分析過程

圖四十一