1. 程式人生 > >惡意程式碼分析實戰 Lab 5-1 習題筆記

惡意程式碼分析實戰 Lab 5-1 習題筆記

Lab 5-1

問題

1.DllMain的地址是什麼?

解答: 這個我們用IDA Pro開啟來查詢,因為最新的IDA Pro不支援我們執行病毒那個虛擬機器的版本(xp pro 32),所以下面的分析都是在win7上的

開啟IDA Pro之後就會提示你是否開啟一個叫proximity browser的東西,然後開啟這個東西就可以看到DllMain的位置

Main

如果沒有跳出來,這裡可以點開這個視窗

Proximity browser

然後右鍵選擇Text view就可以看到地址了

右鍵

注意標黃的地方

地址

標黃的地方都是一樣的地址,不是IDA的bug,上面那些都是一些IDA生成的一些註釋,真正在這個地址上的只有

mov eas, [esp+fdwReson]

這一行

所以DllMain的地址就是在.text節的0x100D02E

2.使用Imports視窗並瀏覽到gethostbyname,匯入函式定位到什麼地址?

解答: 我們開啟Imports視窗

然後搜尋這個

搜尋

然後雙擊這個找到的函式也行,其實Imports這裡已經標明瞭地址了

地址

於是這個問題的答案就是0x100163CC,但是我們可以用雙擊去原文中查詢的方式

地址

這裡可以看出這是在.idata節的0x100163CC

最後的答案就是gethostbyname.idata節的0x100163CC

3.有多少函式呼叫了gethostbyname?

解答: 這個按照說中說的做就行了,但是注意一點,不是在Imports視窗按Ctrl x

是在IDA View窗口裡面,也就雙擊Imports窗口裡面gethostbyname函式跳出來的那個視窗

點選

這是右擊gethostbyname之後的顯示,然後點選Jump to xref to oprand...這個選項,會跳出這個

跳出

型別r是被”讀取”的引用,CPU必須先讀取這個匯入項,再呼叫它,型別p是被呼叫的引用

這裡顯示了18行,但是並不是18個函式呼叫了這個gethostbyname,注意看,好多函式都是一樣的(+後面的是偏移地址)

標註

然後我們自己數一下就會發現,其實只有五個函式引用了gethostbyname

然後注意看就是每個r的型別,總有一個p的型別,所以被引用的次數就是18/2=9次

所以答案就是五個函式引用了九次

4.將精力集中在位於0x10001757處的對gethostname的呼叫,你能找到哪個DNS請求將被出發嗎?

解答: 我們先跳過去看看

按一下g就跳出這個視窗了

然後輸入0x10001757這個地址,就會跳了

跳

跳到

然後我們檢視這個程式碼

程式碼

call函式預設將棧頂的一個值作為函式的引數傳遞給函式,然後棧頂現在是eax push進去的

所以我們找eax的值,然後找到了mov off_10019040這個,然後檢視off_10019040

引數

然後我們可以跳到off_1001940定義的地方,看到了這個字串(藍色的是IDA標識的)

[This is RDO]pics.praticalmalwareanalys

然後這裡大家也看到了,ida顯示不全,我們繼續追查

雙擊後面的aThisIsRdoPics

無

就可以看到完整的字串了

[This is RDO]pics.praticalmalwareanalysis.com

然後我們回過頭來看當時的那段程式碼

程式碼

off_10019040中的值給了eax之後(off_10019040是字串指標)

學過C語言的同學都應該知道指標

現在這個off_10019040指標指向的是字串的第一個字元,也就是符號[

0Dh轉換成十進位制是13

字串是這個[This is RDO]pics.praticalmalwareanalysis.com

+在指標裡面的意思你可以理解成是指標向後移動,這個C語言裡面有講,然後我們講指標往後移動13

最後指標指向的是p這個字元

所以最後push進棧的值是pics.praticalmalwareanalysis.com

於是我們可以得出這個問題的答案就是會對

pics.praticalmalwareanalysis.com

進行DNS解析

5.IDA pro識別了在0x10001656處的子過程中的多少個區域性變數?

解答: 老規矩,跳先

然後會發現這些被IDA識別的變數

變數

然後簡單的一數,是24個,和書中的計算結果有點差異,然後我數了一下書裡的截圖,是24個,這裡就不糾結這個了,方法知道了就行

6.IDA pro識別了在0x10001656處的子過程中的多少個引數?

解答: 引數是呼叫這個函式的函式傳遞給被呼叫函式的值,搞清楚這個就好辦了

引數

我們可以看見這裡IDA識別的結果是傳入了一個LPVOID型別的lpThreadParameter

所以答案就是識別了一個引數

7.使用string視窗,來在反彙編中定位字串\cmd.exe /c。它位於哪?

解答: 這個我們按SHIFT F12就調出String視窗了

然後檢視這個字串,雙擊就行了

查詢

然後

雙擊

所以答案就是在xdoors_d:10095B34

8.在引用\cmd.exe /c的程式碼所在的區域發生了什麼?

解答: 我們右鍵查詢aCmd_exeC引用

引用

然後跳到這個引用的地方

跳

然後我們可以發現在這裡,字串被壓入了棧中

然後分析這個函式會發現開頭這個字串

字串

'Hi,Master [%d/%d/%d %d:%d:%d]

然後可以在這個大概位置上

大概位置

發現一些比較函式,然後點開之後會發現

有關

這些有關於系統資訊和系統操作的字串

按書中的觀點這是一個遠端shell會話函式

9.在同樣的區域,在0x100101c8處,看起來好像dword_1008E5C4是一個全域性變數,它幫助決定走哪條路徑。那惡意程式碼是如何設定dword_1008E5C4的呢?(提示:使用dword_1008E5C4的交叉引用。)

解答: 先跳到這個地方,然後郵件檢視交叉引用

交叉引用

其他兩處都是cmp函式

只有第一處是mov改變了它的值

我們跳到這個地方檢視

mov

可以看到這個dword_1008E5C4的上面,有一次sub_10003695函式的呼叫,而彙編中,函式呼叫的返回值儲存在eax

然後我們檢視sub_10003695這個函式到底返回了什麼

我們雙擊這個函式就可以跳到這個函式的定義了

函式

然後這裡注意一下,就是雙擊會跳到.text:100036C2這個位置的sub_10003694,但是其實這個位置是函式的結束,上面.text:10003695處還有一個sub_10003695(發現沒有,其實IDA命名函式是用他的位置加上sub來的)

sub_10003695    proc near               ; CODE XREF: 
VersionInformation= _OSVERSIONINFOA ptr -94h
                push    ebp
                mov     ebp, esp
                sub     esp, 94h        ; 將esp增加94h也就是148d,37個位元組
                lea     eax, [ebp+VersionInformation] ; 將ebp+VersionInformation的地址賦值給eax
                mov     [ebp+VersionInformation.dwOSVersionInfoSize], 94h ; 將這個地址的值賦值成94h
                push    eax             ; lpVersionInformation
                call    ds:GetVersionExA ; 在一個OSVERSIONINFO結構中載入與平臺和作業系統有關的版本資訊
                                         ; 上面有定義這個OSVERSIONINFO結構
                xor     eax, eax        ; 將eax置0(因為GetVersionExA的返回值在eax中)
                cmp     [ebp+VersionInformation.dwPlatformId], 2 ; 這裡將dwPlatformId和2進行比較
                                                                 ; 為什麼和2比較我們下面解釋
                setz    al              ; Set Byte if Zero (ZF=1) ; 
                leave                   ; High Level Procedure Exit
                retn                    ; Return Near from Procedure
sub_10003695    endp

我們可以來檢視一個OSVERSIONINFOA的結構

OSVERSIONINFOA

檢視dwPlatformId中的可能的值

dwPlatformId

因為在windows系統中,VER_PLATFORM_WIN32_NT代表的值是2

無

對windows核心不是很瞭解,但是從文件來看,VER_PLATFORM_WIN32_NT等於2的話,就是代表系統是

Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003, Windows XP, or Windows 2000

setz意思是當ZF標誌被設定時,AL暫存器設1

因為剛剛我們cmp了兩個數,所以如果兩個數相同,ZF=1,然後setzAL被設定為1,反之不相同的話,AL被設定為0(ALEAX的低8位,對應的AHEAX的高8位)

一般來說,會執行這個機器的都是上面那幾種windows機器,所以這裡比較一般都是會相同的,所以,AL被設定成了1,然後就是用retn返回了eax中的值

但是為什麼書上說的是返回的是1,因為我們前面執行過

xor eax, eax

eax現在是被異或都成了0eax有16位)

我們現在分析一下,01234567代表的是高8位(ah),剩下的代表的是低八位(al)

先是

xor eax, eax

這個執行完之後的eax

01234567 89ABCDEF
-------- --------
00000000 00000000

然後我們接著執行

cmp [ebp+VersionInformation.dwPlatformId], 2
setz al

之後的eax89ABCDEF代表的al被置為了1,其餘的ah儲存不變

01234567 89ABCDEF
-------- --------
00000000 00000001

然後這個值其實就是十進位制的1

所以sub_10003694的返回值是1

於是

mov dword_1008E5C4, eax

最後的dword_1008E5C4的值就被賦成了1

所以這個全域性變數在程式執行的時候一直保持的是1

10.在位於0x1000FF58處的子過程中的幾百行指令中,一系列使用memcmp來比較字串的比較。如果對robotword的字串比較是成功的(當memcmp返回0),會發生什麼?

解答: 這個函式我們剛剛看過,但是沒細入分析過

整個從0x1000FF58開始的函式,第一個使用memecp是這裡(標黃的那裡

這裡

一開始是比較了quiteax的值,因為這兩個值被壓入了棧中

然後我們找到robotwork,慢慢往右下角拖就是了

robotwork

它首先壓入了一個robotwork字串指標,然後壓入了eax,然後call memcmp,如果兩個數相同,返回0,然後

add eap, 0Ch

0Ch12d,也是4(位元組)*3(個),因為push後面跟的是立即數,所以一個數佔4位元組,然後offset也是4個位元組,所以,一開始的push 9,和後面的兩次push,加起來一共是3次,所以這裡回收了這3個一共12位元組的空間

test eax, eax

如果eax0,則ZF置為1JZ跳轉,eax0說明前面的memcmp比較的結果是相同,也就是

如果前面兩個數相同,則JZ跳轉,JNZ不跳轉

然後問題當字串比較成功,memcmp返回0會發生什麼

會發生的是,JNZ不跳轉,程式繼續按從上到下的順序執行,下面要執行的就是

無

push [ebp+s] ; 將ebp(esp是棧頂指標,ebp是棧基址)地址增加s
             ; (棧中,esp地址減小,棧空間增大,ebp增加,ebp將向棧底偏移)
             ; 將ebp向下s的指標地址壓棧
call sub_100052A2
jmp short loc_100103F6

然後就是呼叫了sub_100052A2這個函式

這個函式是這樣的

程式

其他的都可以不管,看最下的地方

這個函式查詢了

值

SOFTWARE\Microsoft\Windows\CurrentVersion

這個登錄檔的地方,用的是RegOpenKeyExA

其實這裡也只查詢了這個,沒有查詢書中說的那個WorKTime,在這個登錄檔目錄下,甚至就沒有這個項

無

然後跳轉到這裡

跳轉

書中說

將這一資訊返回給push [ebp+s]處傳給該函式的網路socket

s是這裡定義的

s

但是不知道是怎麼把這資訊返回給上面的的引數的

返回

11.PSLIST匯出函式做了什麼?

解答: 我們開啟匯出函式表

匯出函式

這個函式有兩條執行大路徑

路徑

然後執行的選擇取決於這個sub_100036C3

取決

這個函式返回的是1

返回

call    ds:GetVersionExA ; 呼叫函式檢視系統版本
cmp     [ebp+VersionInformation.dwPlatformId], 2 ; 這個我們上面說過,如果等於2,是那些windows版本
                                                 ; 包括`Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003, Windows XP, or Windows 2000`
jnz     short loc_100036FA ; 如果不想等,則跳轉結束
cmp     [ebp+VersionInformation.dwMajorVersion], 5 ; 5代表特殊版本的windows
jb      short loc_100036FA ; 無符號比較,如果[ebp+VersionInformation.dwMajorVersion]小於5跳轉
push    1
pop     eax
leave                   ; High Level Procedure Exit
retn
cmp     [ebp+VersionInformation.dwMajorVersion], 5

這裡的5代表什麼意思

5

代表的就是這麼幾個版本的windows

所以這個函式的作用就是具體判斷目標主機的系統版本,如果是過低的版本,就直接跳轉結束

如果是符合要求的版本,則返回1

無

然後就是比較跳轉,如果eax0test之後,ZF1,然後JZ跳轉
如果eax不為0ZF不為0,然後JZ不跳轉
也就是如果版本符合要求,就不跳轉(跳轉之後是直接結束)

不

不跳轉之後,push了一個字串進去,然後呼叫strlen返回字串的長度在eax中,然後test eax, eax

如果eax(字串長度)0ZF置為1JNZ不跳轉
反之如果不為0JNZ跳轉

假設eax0JNZ不跳轉,我們走一下這條線

不跳轉

那麼下一個執行完push之後,就是執行call sub_10006518

無

從彙編中可以看出,這個sub_10006518執行了這個函式CreateToolHelp32Snapshot,這個函式是

CreateToolhelp32Snapshot函式為指定的程序、程序使用的堆[HEAP]、模組[MODULE]、執行緒[THREAD])建立一個快照[snapshot]。

然後我們看跳轉那條線

跳轉

跳轉這條線上(藍色),它將字串壓入棧之後,又壓入了一個0,然後呼叫了sub_1000664C這個函式

無

這個函式依舊還是呼叫了CreateToolHelp32Snapshot這個函式,然後還有GetLastErrorsprintf這些個函式

sprintf函式的輸出是

無

所以我們不難想,GetLastError是用於判斷CreateToolHelp32Snapshot這個函式有沒有執行成功的

無

如果失敗,就執行endp(也就是圖中標註的exit_0)

如果成功,則執行retn(也就是圖中的return_0)

按照書中的說法

這兩條程式碼路徑都通過send將程序列表通過socket傳送

但是我是沒找到這個sendsocket這兩個函式

無

唯一能扯上一點關係的就是這裡有個

push [ebp+s]

但是這個s是如何看出就是代表socket或者send呢,不得而解

12.使用圖模式來繪製出對sub_10004E79的交叉引用圖。當進入這個函式時,哪個API函式可能被呼叫?僅僅基於這些API函式,你會如何重新命名這個函式?

解答:: 按照書上的做法

這裡

我們跳到指定位置之後,按照這個選單,點選

然後出來這個

出來

直接預設點確定就行了

然後就出現這個了

出現

我們關心的主要是下面這三層

可以看出這個函式sub_10004E79主要呼叫的有

GetSystemDefaultLangIDsprintfsub_100038EEstrlen

sub_100038EE主要呼叫了sendmallocfree__imp_strlen

然後GetSystemDefaultLangID是獲取系統的預設語言的函式,sendsocket傳送的函式

由此我們可以按照書上的做法,將這個函式重新命名為send_languageID

13.DllMain直接呼叫了多少個Windows API?多少個在深度為2的時候被呼叫?

解答: 搜尋DllMain找到這個函式的位置

DLL

然後用上面的方法開啟檢視

檢視

會發現檢視極其龐大。。。(因為預設Recursion depth為-1)

我們重新開啟,將這裡改為1

深度

然後就可以看到呼叫深度為1的所有函數了

深度為1

所以DllMain在深度為1直接呼叫的API也就是strncpy_strnicmpCreateThreadstrlen這麼幾個

要知道全部的 API,那就得一個一個數了。。。

深度為2

同樣的方法檢視深度為2時候的呼叫(很大的呼叫表)

14.在0x10001358處,有一個對Sleep(一個使用一個包含要睡眠的毫秒數的引數的API函式)的呼叫。順著程式碼往後看,如果這段程式碼執行,這個程式會睡眠多久?

解答: 我們跳到那個地方看看

函式

Sleep函式的引數是壓入棧的eax,而這個eax從哪裡來,是call ds:atoi的返回值,再乘以3E8h,最後就被壓入了棧中,供Sleep做入參

atoi的引數是從前面的push eax中來的,eax的根源是從off_10019020傳進來的

off_10019020的值放在這裡

無

[This is CTI]30

然後執行了這個(這個前面說過,指標的+多少相當於指標往後偏移多少

 add eax, 0Dh

0Dh相當於十進位制的13d

往後偏移13個位元組,最後指標指向3(從0開始數)

然後將指向3的指標壓入棧,其實現在指標就相當於這樣

char origin_str[] = "[This is CTI]30";
char *p_str = origin_str;
p_str = p_str + 13;

最後輸出的p_str就是30,然後呼叫這個atoi,它是把字串(char)轉換成整型(int)的函式

call ds:atoi

然後這個函式的輸出就是(int)30

imul eax, 3E8h

3E8h就是1000dimul是乘,然後301000就是30000(3w)

然後我們從MSDN確定一下單位

單位

這裡顯示是以milliseconds為單位,就是毫秒,30000ms = 30s

所以這個函式會休眠30s

15.在0x10001701處是一個對socket的呼叫。它的3個引數是什麼?

解答: 我們還是先跳到這個函式的位置

socket

這裡是將612壓入了棧中,然後我們不知道具體的配置資訊,按照書中的做法

無

然後就會跳出一大堆的東西

無

然後我們查詢一下關於socket有關的函式,這時候如果你對socket的相關函式的引數不是很清楚的話,建議還是查查MSDN

我們都知道棧是先進後出的型別,先壓入的資料,其實是最後才呼叫的

MSDN

最後壓入的是2這個數(彙編不像其他高階語言,引數的順序可以顛倒),然後2應該對應的就是af這個引數

我們就點開2的對話方塊,然後去MSDN查對應的值,一般輸入都有的頭就可以了

MSDN

這裡是AF,一般這種對應表裡面,一個函式用的到的,肯定只會出現一次,果不其然,我們搜AF之後,就會發現,這裡之後兩個AF開頭的

AF

除了第一個的AF_INET之外,還有一個AF_OP_COMM,其實這個並不是socket函式的引數

太長

太長了截不完,不信的同學可以自己上MSDN去查(手動滑稽)

然後我們就可以將這個引數重新命名一下

重新命名

大概看起來就像這樣,然後我們按這種方法來找(其實雙擊你找到的那個對話方塊裡面的引數名就可以重新命名了)

然後第二個壓入棧中的1,在socket中對應的是type

這裡都有的

這裡都有的都是帶sock

sock

然後注意就是不要和socket混淆了,這裡是sock,然後就是為什麼會出現兩個一摸一樣的SOCK_STREAM,其實一個東西

一樣

一個是MS SDK另一個是Virtual C++ 6.0,其實都是一樣的,然後我們重新命名一下

最後一個6,它是第一個壓入棧中的值,但是卻是最後呼叫的

他對應的是protocol

protocol

這裡只有搜IPPROTO就可以了

一樣的方法

一樣的

然後最後把這些符號常量重新命名之後,彙編程式碼成了這樣的

這樣

我們的函式入參就一目瞭然了,稍微解釋了一下這三個引數的意思

AF_INET 用於連線連線物件是IPv4時(對應的IPv6用的是 AF_INET6)

SOCK_STREAM 用於連線方式使用TCP時候(對應的UDP對應的是SOCK_DGRAM)

IPPROTO_TCP 用於繼續指明傳輸的方式是TCP(對應的UDP是IPPROTO_UDP)

16.使用MSDN頁面的socket和IDA pro中的命名符號常量,你能使引數更加有意義嗎?在你應用修改之後,引數是什麼?

解答: 就是上面剛剛分析的那些引數。。。感覺分析多了

17.搜尋in指令(opcode 0xED)的使用。這個指令和一個魔術字串VMXh用來進行VMware的檢測。 在這個惡意程式碼中被使用了嗎?使用對執行in指令函式的交叉引用,能發現進一步檢測VMware的證據嗎?

解答: 按照書上的做法我們試試

無

這裡搜尋要學會使用技巧,不然出一大堆沒用的東西

無

然後我們可以發現,出了一些不是運算的註釋和名稱之外,只剩下標黃這個東西可以值得點開看看,如果是在不確定,可以一個一個點開看看

無

我這一版本的IDA並沒有標註這個二進位制的意思,書上是標註出來的

右鍵

我們右鍵,會顯示出各種不同的編碼結果

可以發現有個VMXh,但是書中說經過一個比較之後,後面會發現一個Found Virtual Machine字串,但是目前暫時沒發現這個字串

18.將你的游標跳轉到0x1001D988處,你發現了什麼?

解答: 這個我們跳了看看就知道了

無

發現一些不知道什麼鬼的東西,然後按照書中說的,我們執行這個python程式碼看看

執行這個指令碼的前提是裝了python

19.如果你安裝了IDA Python外掛(包裹IDA Pro的商業版本的外掛),執行Lab05-01.py,一個本書中隨惡意程式碼提供的IDA Pro Python指令碼,(確定游標是在0x1001D988處。)在你執行這個指令碼後發生了什麼?

解答: 執行這個python指令碼之後,其實沒啥變化,如果你不仔細看的話

其實字元已經變了

租房也

然後現在這串字串已經變可讀了,反正就是在那一瞬間,哈哈哈

20.將游標放在同一位置,你如何將這個資料轉成一個單一的ASCII字串?

解答: 這個其實前面的就是ASCII碼,也就是db後面的

可以在設定裡面開自動註釋來顯示

註釋

21.使用一個文字編輯器開啟這個指令碼。它是如何工作的?

解答: 如下

指令碼解釋

本文完