QQ盜號(hào)木馬之逆向分析
QQ盜號(hào)木馬之逆向分析
電腦已經(jīng)走進(jìn)我們的生活,與我們的生活息息相關(guān),感覺(jué)已經(jīng)離不開(kāi)電腦與網(wǎng)絡(luò),對(duì)于電腦安全防范,今天小編在這里給大家推薦一些電腦病毒與木馬相關(guān)文章,歡迎大家圍觀參考,想了解更多,請(qǐng)繼續(xù)關(guān)注學(xué)習(xí)啦。
一般來(lái)說(shuō),病毒分析不會(huì)涉及到算法問(wèn)題,如果是要分析算法(如我之前對(duì)于CM4注冊(cè)機(jī)制的分析),那么我們更多地是需要關(guān)注程序的流程與邏輯,一般不深究CALL的具體內(nèi)容。而病毒分析則往往需要搞清楚各個(gè)不同的CALL的意義,才能夠弄清楚病毒的行為。所以本文的第一部分著重講述對(duì)這些CALL的剖析。而第二部分則簡(jiǎn)單討論一下進(jìn)程守護(hù)技術(shù)的實(shí)現(xiàn)。
逆向分析
這里我們跳過(guò)程序的初始化部分,來(lái)到第一個(gè)API函數(shù)的位置:
我們能夠直接看到的第一個(gè)API函數(shù)是GetModuleFileName,這個(gè)函數(shù)用于獲取當(dāng)前進(jìn)程已加載模塊的文件的完整路徑,該模塊必須由當(dāng)前進(jìn)程加載。而該函數(shù)的返回值則是文件路徑長(zhǎng)度,該返回值保存在了EAX中,為2B,也就是說(shuō)路徑長(zhǎng)度為2B個(gè)字符??梢钥匆幌滤祷氐穆窂绞鞘裁?。路徑保存在“PathBuffer”中,跟蹤該地址查看:
可見(jiàn)程序已正確獲取了當(dāng)前文件的地址。然后繼續(xù)分析下一個(gè)API函數(shù):
這里出現(xiàn)了ShellExecute這個(gè)函數(shù),它的功能是運(yùn)行一個(gè)外部程序(或者是打開(kāi)一個(gè)已注冊(cè)的文件、打開(kāi)一個(gè)目錄、打印一個(gè)文件等等),并對(duì)外部程序有一定的控制。具體到本程序,ShellExecute會(huì)運(yùn)行Explorer.exe程序來(lái)打開(kāi)“d:\”,其實(shí)也就是使用程序管理器打開(kāi)D盤(pán)根目錄。但是執(zhí)行這個(gè)API函數(shù)是有條件的,它需要根據(jù)第二行CALL語(yǔ)句的結(jié)果進(jìn)行判定,那么有必要進(jìn)入這個(gè)CALL,看看需要滿(mǎn)足什么條件才能夠執(zhí)行ShellExecute。
進(jìn)入oso.00403C48這個(gè)函數(shù)
程序會(huì)對(duì)EAX和EDX中的內(nèi)容進(jìn)行比對(duì),其中EAX保存的字符串就是我們之前使用GetModuleFileName所獲取的當(dāng)前文件的路徑,只不過(guò)被轉(zhuǎn)化成了大寫(xiě)字符。而EDX保存的是D盤(pán)根目錄下的OSO.EXE這個(gè)文件路徑。二者在這里很明顯是不同的。所以黃色高亮顯示的條件跳轉(zhuǎn)語(yǔ)句也就不成立,程序會(huì)繼續(xù)順序執(zhí)行:
這里需要說(shuō)明的是,由于本病毒是由Delphi編寫(xiě)的,那么字符串首地址減去4后,取出的4字節(jié)內(nèi)容便是此字符串的長(zhǎng)度。因此的前兩句代碼意思就是獲取兩個(gè)路徑的字符數(shù),然后通過(guò)相減進(jìn)行比較。這里很明顯當(dāng)前路徑的字符數(shù)量是要大的,因此黃色高亮顯示的條件跳轉(zhuǎn)成立,來(lái)到oso.00403C6B的位置:
這里依舊是字符的比較,由于二者不相等,所以最后一句的條件跳轉(zhuǎn)成立,來(lái)到oso.00403CD1的位置:
這里比較的是盤(pán)符,也是不相等的,所以條件跳轉(zhuǎn)成立,本函數(shù)也就執(zhí)行完畢了。綜合上述分析,這段函數(shù)的功用是判斷當(dāng)前所執(zhí)行的文件是不是位于D盤(pán)的根目錄下,如果是,則執(zhí)行中的ShellExecute這個(gè)函數(shù),反之則跳過(guò)這個(gè)函數(shù)執(zhí)行。由于我們的這個(gè)程序是位于桌面上的,因此不執(zhí)行ShellExecute函數(shù)。
接下來(lái)程序還會(huì)繼續(xù)判斷當(dāng)前程序是否位于E、F、G、H、I盤(pán)根目錄下,如果不是,那么也就不執(zhí)行相應(yīng)的ShellExecute函數(shù)。
之后程序會(huì)調(diào)用名為oso.004050F0的函數(shù),進(jìn)入其內(nèi)部分析:
可見(jiàn)病毒程序調(diào)用了GetSystemDirectory函數(shù)用于獲取系統(tǒng)目錄。一般來(lái)說(shuō),惡意程序使用這個(gè)函數(shù)的目的就是要將自身復(fù)制到系統(tǒng)目錄中,以迷惑用戶(hù)(詳見(jiàn)《反病毒攻防研究第001篇:自我復(fù)制與自刪除》)。之后病毒程序會(huì)將字符“severe.exe”與上面獲得的系統(tǒng)目錄字符串進(jìn)行組合,新的路徑也就是病毒程序需要隱藏的位置:
之后可以看到CreateFile函數(shù):
但是這個(gè)CreateFile函數(shù)的執(zhí)行是有條件的,它取決于第一行代碼中的CALL的返回值。進(jìn)入這個(gè)CALL進(jìn)行分析,可以找到:
程序調(diào)用了FindFirstFile函數(shù)來(lái)查找系統(tǒng)目錄中有沒(méi)有severe.exe這個(gè)文件,如果沒(méi)有(返回值為-1)則不執(zhí)行的CreateFile函數(shù)。由此可見(jiàn),CreateFile函數(shù)在這里的作用不是創(chuàng)建文件,而是打開(kāi)文件。接下來(lái)就是文件的復(fù)制操作:
之后又是一系列的文件復(fù)制,病毒會(huì)將自身改名為tfidma.exe,并復(fù)制到系統(tǒng)目錄中。還會(huì)將自身改名為conime.exe,復(fù)制到系統(tǒng)目錄的drivers文件夾中。類(lèi)似的操作不再贅述。之后程序就會(huì)再次調(diào)用ShellExecute函數(shù),以執(zhí)行所創(chuàng)建出來(lái)的這些程序。因此在“資源管理器”中就會(huì)出現(xiàn)severe.exe、conime.exe與tfidma.exe等進(jìn)程??梢哉f(shuō)在這個(gè)時(shí)候,我們的計(jì)算機(jī)就已經(jīng)中病毒了。接下來(lái)我們會(huì)遇到線(xiàn)程的創(chuàng)建函數(shù):
CreateThread函數(shù)往往與Sleep或者WaitForSingleObject函數(shù)相配合使用。因?yàn)槊總€(gè)線(xiàn)程都有自己的CPU時(shí)間片,當(dāng)主線(xiàn)程創(chuàng)建了新線(xiàn)程后,它的CPU時(shí)間片有時(shí)并沒(méi)有完,它還可以繼續(xù)執(zhí)行。有時(shí)候如果主線(xiàn)程的代碼非常少,那么在CPU指定的CPU時(shí)間片中主線(xiàn)程執(zhí)行完后就退出了。主線(xiàn)程結(jié)束,那么意味著程序也就結(jié)束了,所以在這種情況下,我們自己創(chuàng)建的線(xiàn)程根本就沒(méi)有被執(zhí)行到。所以我們需要讓主線(xiàn)程等待我們創(chuàng)建的線(xiàn)程,就需要使用Sleep或者WaitForSingleObject函數(shù)。本程序所采用的就是Sleep函數(shù)(等待1.3秒)。
根據(jù)OD對(duì)CreateThread函數(shù)的解析可以知道,該線(xiàn)程所調(diào)用的是oso.00404958這個(gè)函數(shù)。分析這個(gè)函數(shù)可以知道,它主要是創(chuàng)建了名為“hx1.bat”的批處理文件并執(zhí)行,而該批處理的內(nèi)容為:
其主要作用就是修改系統(tǒng)時(shí)間,測(cè)試本地網(wǎng)絡(luò)系統(tǒng)并刪除自身。病毒的常規(guī)分析部分就是這些。
三、進(jìn)程守護(hù)技術(shù)原理
進(jìn)程的守護(hù)技術(shù)最早應(yīng)該是源于“中國(guó)黑客病毒(worm.runouce)”,它開(kāi)創(chuàng)性地采用了“三線(xiàn)程”結(jié)構(gòu)。創(chuàng)建三線(xiàn)程就是為了更好地保護(hù)程序自身不被關(guān)閉和刪除。我們可以將想要執(zhí)行的代碼放在主線(xiàn)程里,然后再生成兩個(gè)輔助線(xiàn)程,它們的功能就是實(shí)現(xiàn)對(duì)程序的保護(hù),防止程序被用戶(hù)關(guān)閉或刪除。在此,稱(chēng)我們的可執(zhí)行文件的進(jìn)程為主進(jìn)程。兩個(gè)輔助線(xiàn)程相互實(shí)時(shí)監(jiān)視,如果監(jiān)視對(duì)象被關(guān)閉了,就重新創(chuàng)建線(xiàn)程或進(jìn)程。比如病毒程序可以選擇Explorer.exe和Taskmgr.exe作為遠(yuǎn)程進(jìn)程駐體。如果用戶(hù)知道了遠(yuǎn)程線(xiàn)程的駐體為資源管理器后,就會(huì)打開(kāi)任務(wù)管理器來(lái)結(jié)束Explorer,這時(shí)我們?cè)侔堰h(yuǎn)程線(xiàn)程駐入到任務(wù)管理器中。也就是說(shuō),只要Explorer或Taskmgr有一個(gè)存在,就不可能結(jié)束主進(jìn)程。如果有其它結(jié)束進(jìn)程的工具,你就可以將其關(guān)閉掉,只要資源管理器和任務(wù)管理器均不存在時(shí),就沒(méi)有駐體來(lái)維持遠(yuǎn)程進(jìn)程。不過(guò),如果我們選擇的遠(yuǎn)程進(jìn)程為隨機(jī)的,或者就是病毒自創(chuàng)的,這就不容易發(fā)現(xiàn)了。
這種三線(xiàn)程結(jié)構(gòu)的程序框架大致如下(代碼來(lái)自《淺析三線(xiàn)程程序開(kāi)發(fā)思路與實(shí)現(xiàn)》):
// 1.主線(xiàn)程:main // 獲得操作系統(tǒng)的系統(tǒng)目錄
GetSystemDirectory(syspath,MAX_PATH); // 查詢(xún)系統(tǒng)目錄下病毒是否存在
FindFirstFile(virusname,&fdata); // 如果系統(tǒng)目錄下沒(méi)有,在將正在運(yùn)行的程序復(fù)制到系統(tǒng)目錄下
CopyFile(curname,tname,TRUE); // 在查詢(xún)完畢后,關(guān)閉相關(guān)句柄
FindClose(ffhandle); // 打開(kāi)系統(tǒng)目錄下的文件
CreateFile(kname,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); // 修改時(shí)間
SetFileTime(fchandle,&ftime,NULL,&ftime); // 設(shè)置屬性
SetFileAttributes(kname,FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM ); // 創(chuàng)建駐留在主進(jìn)程內(nèi)的輔助監(jiān)視線(xiàn)程
CreateThread(NULL,0,watch,(LPVOID)rthread,0,NULL);
// 2.本地輔助監(jiān)視線(xiàn)程:watch // 以查詢(xún)方式打開(kāi)注冊(cè)表的HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run
RegOpenKeyEx(HKEY_LOCAL_MACHINE,rgspath,0,KEY_QUERY_VALUE,&hkey); // 查詢(xún)是否存在virusname的鍵值
RegQueryValueEx(hkey,_T("virusname"),NULL,NULL,(LPBYTE)lpdata,&dwbuflen); // 如果沒(méi)有相關(guān)鍵值,就以寫(xiě)方式再次打開(kāi)注冊(cè)表
RegOpenKeyEx(HKEY_LOCAL_MACHINE,rgspath,0,KEY_WRITE,&hkey); // 寫(xiě)入我們想要的東西,系統(tǒng)每次啟動(dòng)都會(huì)運(yùn)行我們的可執(zhí)行文件;
RegSetValueEx(hkey,_T("virusname"),NULL,type,(const byte *)wtname,dwbuflen); // 獲得遠(yuǎn)程線(xiàn)程的運(yùn)行情況,看是否為STILL_ACTIVE,如果不是則創(chuàng)建遠(yuǎn)程線(xiàn)程
GetExitCodeThread(wethread,&exitcode);
// 3.遠(yuǎn)程線(xiàn)程:remote // 以所有可能的訪問(wèn)方式打開(kāi)主進(jìn)程,以便監(jiān)視主進(jìn)程的運(yùn)行情況
tOpenProcess(PROCESS_ALL_ACCESS,FALSE,erp->rpmousepid); // 等待直到主進(jìn)程結(jié)束
tWaitForSingleObject(erp->rpprocesshandle,INFINITE); // 重新啟動(dòng)我們的可執(zhí)行文件
tWinExec(erp->rpwinexecname, 0);
// 4.獲得進(jìn)程ID:processtopid // 列舉所有的進(jìn)程
EnumProcesses(lpidprocesses,sizeof(lpidprocesses),&cbneeded); // 以查詢(xún)信息和讀取的方式打開(kāi)進(jìn)程
OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE,lpidprocesses[i]); //獲得進(jìn)程模塊的句柄
EnumProcessModules(hprocess,&hmodule,sizeof(hmodule),&cbneeded); // 獲得特定模塊的名字,以備比較
GetModuleBaseName(hprocess,hmodule,normalname,sizeof(normalname));
// 5.創(chuàng)建遠(yuǎn)程線(xiàn)程:createremote // PROCESS_CREATE_THREAD for CreateRemoteThread
// PROCESS_VM_OPERATION for VirtualAllocEx // PROCESS_VM_WRITE for WriteProcessMemory
OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE,FALSE,remotepid); // 在遠(yuǎn)程進(jìn)程中分配空間,以備將線(xiàn)程代碼置入其中
VirtualAllocEx(rphandle,NULL,cb,MEM_COMMIT,PAGE_EXECUTE_READWRITE); // 將遠(yuǎn)程線(xiàn)程remote的代碼寫(xiě)入到遠(yuǎn)程進(jìn)程的地址空間中
WriteProcessMemory(rphandle,remotethr,(LPVOID)remote,cb,NULL); // 將遠(yuǎn)程線(xiàn)程所需的參數(shù)也寫(xiě)入到遠(yuǎn)程進(jìn)程的地址空間中
WriteProcessMemory(rphandle,remotepar,(LPVOID)&rp,cb,NULL); // 創(chuàng)建遠(yuǎn)程監(jiān)視線(xiàn)程
CreateRemoteThread(rphandle,NULL,0,(LPTHREAD_START_ROUTINE)remotethr,(LPVOID)remotepar,0,NULL);
畢竟本系列不是教大家編寫(xiě)病毒,而是剖析病毒的大概思路,所以上述程序大家有個(gè)大概的印象即可,這樣在以后的實(shí)際分析中,就能有大概的應(yīng)對(duì)思路。
四、小結(jié)
至此,QQ盜號(hào)木馬(oso.exe)病毒程序的分析就到這里。希望大家喜歡.