徐國天 中國刑事警察學(xué)院
當(dāng)前,木馬類惡意程序常用的電子數(shù)據(jù)取證方法有動態(tài)分析法和靜態(tài)取證法。動態(tài)分析法是將惡意程序在一部測試用智能終端設(shè)備上真實地運行起來,同時觀察惡意程序執(zhí)行后所表現(xiàn)出的一些外在行為特征,如加密磁盤文件、關(guān)閉防火墻、退出殺毒軟件、彈出勒索信息等[1]。通過捕獲惡意程序收發(fā)的網(wǎng)絡(luò)通信數(shù)據(jù)可以獲得黑客預(yù)留的郵箱賬戶、控制服務(wù)器IP地址等涉案信息。動態(tài)取證方法操作簡單,便于實現(xiàn)。但是一些隱藏的惡意行為通過動態(tài)取證方法很難發(fā)現(xiàn),例如惡意程序的鍵盤記錄行為、注冊表操作行為、惡意代碼植入行為等。借助靜態(tài)取證可對這些隱藏的惡意行為進(jìn)行完整取證。靜態(tài)取證方法是將惡意程序逆向反編譯為匯編代碼,再從程序主入口開始逐行閱讀源代碼,提取出惡意程序的主要功能和相關(guān)配置信息,完成取證分析工作。靜態(tài)取證方法的優(yōu)點是可以對惡意程序的所有功能進(jìn)行取證分析,只要代碼分析足夠仔細(xì),就不會漏掉一項取證結(jié)論。但是這種方法的缺點也十分明顯,就是取證人員需要閱讀的匯編代碼量非常大,取證周期漫長、效率低下,不能滿足公安工作實際需要。
針對靜態(tài)取證方法存在的不足,本文提出一種基于函數(shù)映射的惡意程序逆向分析取證方法。這種方法不需要完整閱讀惡意程序匯編代碼,在惡意程序主要系統(tǒng)函數(shù)和核心惡意功能之間建立一種映射關(guān)系,通過閱讀系統(tǒng)函數(shù)所在位置的局部匯編代碼來完成取證分析工作,在提高取證效率、縮短取證周期的同時,最大限度地保證了取證結(jié)論的全面和完整。
通過對多種類型的木馬程序進(jìn)行取證分析,我們發(fā)現(xiàn)每類惡意程序都會實現(xiàn)一些特定功能,例如盜號木馬實現(xiàn)的主要功能有特定窗口監(jiān)視、鍵盤輸入監(jiān)控、賬戶信息竊取、惡意進(jìn)程隱藏、開機自動運行、防火墻穿透等。每類惡意功能的實現(xiàn)都會使用特定的系統(tǒng)函數(shù),例如發(fā)送郵件會用到WSAStartup、connect、send函數(shù)[2],鍵盤輸入監(jiān)控涉及到GetWindowText和GetAsynKeyState函數(shù),注冊表操作涉及到RegOpenKey函數(shù)。反過來說,當(dāng)惡意程序匯編代碼中出現(xiàn)特定系統(tǒng)函數(shù)時,可在系統(tǒng)函數(shù)和主要功能之間建立一種映射關(guān)系,即初步判斷程序所具有的惡意功能,再通過系統(tǒng)函數(shù)斷點設(shè)置可以獲得關(guān)鍵配置信息,進(jìn)而完成取證分析工作。例如從connect和send參數(shù)中可以獲得黑客郵箱賬戶信息和發(fā)送的郵件正文數(shù)據(jù),從createfile函數(shù)參數(shù)可以獲得惡意程序創(chuàng)建的文件名和存儲位置,從RegOpenKey函數(shù)可以獲得惡意程序操作的注冊表鍵值。
基于函數(shù)映射的惡意程序逆向取證方法如圖1所示,首先將送檢的惡意程序使用Ollydbg反編譯為匯編代碼,提取出全部系統(tǒng)函數(shù),之后對函數(shù)進(jìn)行分類,在函數(shù)和系統(tǒng)功能之間建立一個初步的映射關(guān)系。在關(guān)鍵函數(shù)上設(shè)置斷點,觀察程序中斷時函數(shù)的相關(guān)參數(shù)值,進(jìn)而確定惡意功能是否存在,提取出相應(yīng)的配置信息。本文以一款惡意程序為例,對這種取證方法進(jìn)行實例研究。
使用Loadpe工具查看送檢惡意程序,在USER32.dll鏈接庫下使用了5個系統(tǒng)函數(shù),如圖2所示,通過這些函數(shù)可以對木馬程序的惡意功能進(jìn)行初步判斷。GetKeyState和GetAsynKeyState函數(shù)用于獲得用戶的按鍵信息,初步判斷木馬具有鍵盤記錄功能。GetForeGroundWindow函數(shù)用于獲得系統(tǒng)最前端窗口句柄,GetWindowTextA函數(shù)用于獲得指定窗口的標(biāo)題,初步判斷木馬使用這兩個函數(shù)獲取系統(tǒng)最前端窗口標(biāo)題,根據(jù)標(biāo)題內(nèi)容確定是否啟動鍵盤記錄功能。
我們首先在GetKeyState函數(shù)上設(shè)置斷點,發(fā)現(xiàn)Ollydbg沒有停留在斷點位置,推測在特定標(biāo)題的被監(jiān)控窗口沒有出現(xiàn)時,木馬不啟動鍵盤記錄功能。為了驗證木馬是否具有鍵盤記錄功能,同時獲得被監(jiān)控的窗口標(biāo)題信息,我們需要對GetForeGroundWindow和GetWindowTextA函數(shù)進(jìn)行分析。
GetForeGroundWindow函數(shù)沒有參數(shù),函數(shù)返回值是一個指向前臺窗口的句柄。GetWindowTextA函數(shù)可以獲得一個指定窗口的標(biāo)題值,函數(shù)的第一個參數(shù)hWnd是指向窗口的句柄,第二個參數(shù)lpString是獲取到的窗口標(biāo)題值。這兩個函數(shù)配合使用可以獲得系統(tǒng)最前端窗口的標(biāo)題值。
使 用 Ollydbg對 GetForeGroundWindow和GetWindowTextA函數(shù)設(shè)置斷點,分析參數(shù)調(diào)用關(guān)系,結(jié)果如圖4所示。GetForeGroundWindow函數(shù)執(zhí)行結(jié)束后,木馬獲得系統(tǒng)最前端窗口的句柄,當(dāng)前系統(tǒng)最前端窗口是Ollydbg軟件窗口,句柄值為0X001D0764。GetWindowTextA函數(shù)的第一個參數(shù)值為打開窗口的句柄,本例值為0X001D0764,說明函數(shù)要獲取的是Ollydbg的窗口標(biāo)題。第二個參數(shù)是一個字符數(shù)組緩沖區(qū),存儲的是讀出的窗口標(biāo)題,內(nèi)存起始地址為0X1000818C,定位到這個位置可以看到是Ollydbg的窗口標(biāo)題。
按照正常的軟件設(shè)計思維,在獲取到系統(tǒng)前臺窗口標(biāo)題后,木馬應(yīng)該將這個標(biāo)題和預(yù)先設(shè)置好的監(jiān)控標(biāo)題進(jìn)行比較,如果相同,則記錄在該窗口內(nèi)輸入的按鍵信息。在進(jìn)行字符串比較操作時就可以獲得被監(jiān)控的窗口標(biāo)題。
圖5顯示的是獲取前臺窗口標(biāo)題的局部匯編代碼,可以看到在GetWindowTextA函數(shù)獲得前臺窗口標(biāo)題后,在地址0X10001578位置出現(xiàn)一次函數(shù)調(diào)用call_Unpacke.10002360,這個函數(shù)的匯編代碼如圖6所示。這段代碼量不是很大,仔細(xì)閱讀之后,可以判斷出函數(shù)功能是進(jìn)行字符串比較,但是閱讀起來仍然比較繁瑣。這里為了簡化取證分析難度,快速獲得函數(shù)功能,我們提出了一種基于參數(shù)變換的函數(shù)功能快速測試法。這種方法采用Ollydbg動態(tài)調(diào)試被測函數(shù),動態(tài)調(diào)整函數(shù)的輸入?yún)?shù)值,同時記錄函數(shù)的每組輸出結(jié)果,通過對多組測試數(shù)據(jù)的比較分析得出函數(shù)的核心功能。下面應(yīng)用這種方法來測試_Unpacke.10002360函數(shù)的主要功能。
分別采用三組參數(shù)測試_Unpacke.10002360函數(shù)功能,圖7為函數(shù)測試結(jié)果。在內(nèi)存地址0X10001578處設(shè)置斷點,程序中斷在這里。此時,第一個參數(shù)值為“網(wǎng)易”,懷疑木馬程序監(jiān)控的是標(biāo)題為“網(wǎng)易”的登錄窗口;第二個參數(shù)值為前臺窗口,即Ollydbg窗口的標(biāo)題值。在地址0X10001580位置設(shè)置斷點,程序運行到這里,此時EAX寄存器中保存函數(shù)執(zhí)行結(jié)果,本次測試值為0。
接下來運行程序,程序再次中斷在0X10001578地址,此時在內(nèi)存窗口定位到0X1000818C,即參數(shù)2的起始地址。將開始四個字節(jié)修改為漢字“網(wǎng)易”的十六進(jìn)制數(shù)值。在地址0X10001580位置設(shè)置斷點,程序運行到這里,此時EAX寄存器中保存函數(shù)執(zhí)行結(jié)果,本次測試值為0X1000818C,即參數(shù)2的起始地址。
接下來第三次運行程序,程序還是中斷在0X10001578地址,此時在內(nèi)存窗口定位到參數(shù)2的起始地址。將第三個字節(jié)開始的四個字節(jié)修改為漢字“網(wǎng)易”的十六進(jìn)制數(shù)值。在地址0X10001580位置設(shè)置斷點,程序運行到這里,此時EAX寄存器中保存函數(shù)執(zhí)行結(jié)果,本次測試值為0X1000818E,即漢字“網(wǎng)易”在參數(shù)2中的起始位置。
經(jīng)過前面測試,不難發(fā)現(xiàn)_Unpacke.10002360函數(shù)是一個字符串定位函數(shù),參數(shù)1是主串,參數(shù)2是子串,函數(shù)返回值是子串在主串中的起始地址,如果子串不在主串之中,則函數(shù)返回值為NULL。經(jīng)過這步分析,我們還獲得了木馬程序監(jiān)控的是標(biāo)題為“網(wǎng)易”的登錄窗口。
獲取木馬記錄的按鍵信息是證明木馬存在的直接證據(jù),本文提出一種二次斷點法來截獲按鍵信息。首先,在窗口比較函數(shù)上設(shè)置第一次程序執(zhí)行斷點,運行到斷點位置,從傳遞的參數(shù)中可以提取出木馬的監(jiān)控窗口標(biāo)題。之后,木馬會調(diào)用GetAsynKeyState函數(shù)逐個字節(jié)記錄按鍵信息,按照通常的程序設(shè)計思路,記錄的按鍵信息會統(tǒng)一存放在一塊內(nèi)存區(qū)域內(nèi),之后可以采取加密或壓縮措施進(jìn)行保護(hù)。定位到這塊內(nèi)存區(qū)域,在其上設(shè)置內(nèi)存寫入斷點,當(dāng)木馬向該區(qū)域?qū)懭霐?shù)據(jù)時會觸發(fā)中斷,從內(nèi)存中可以提取到按鍵信息,圖8描述了這種取證方法。
在本例中,鍵盤記錄功能被寫在一個單獨的函數(shù)內(nèi)實現(xiàn)。圖9上部匯編代碼為GetAsynKeyState函數(shù)后面局部代碼,出現(xiàn)一個內(nèi)存寫入地址0X10008584,在Ollydbg的內(nèi)存窗口定位到這個地址,查看這個位置存儲的數(shù)據(jù)是另一個內(nèi)存地址0X7FF80000,定位到第二個內(nèi)存地址,查看到被監(jiān)控的窗口名為“網(wǎng)易.txt - 記事本”,監(jiān)控到的按鍵信息為兩個F8按鍵和一個小寫字母“j”。
本文提出一種基于函數(shù)映射的惡意程序逆向分析取證方法。這種方法不需要完整閱讀惡意程序匯編代碼,在惡意程序主要系統(tǒng)函數(shù)和核心惡意功能之間建立一種映射關(guān)系,通過閱讀系統(tǒng)函數(shù)所在位置的局部匯編代碼來完成取證分析工作,在提高取證效率、縮短取證周期的同時,最大限度保證了取證結(jié)論的全面和完整。