隱藏是病毒的天性,在業(yè)界對病毒的定義里,“隱蔽性”就是病毒的一個最基本特征,任何病毒都希望在被感染的計算機(jī)中隱藏起來不被發(fā)現(xiàn),因為病毒都只 有在不被發(fā)現(xiàn)的情況下,才能實施其破壞行為。為了達(dá)到這個目的,許多病毒使用了各種不同的技術(shù)來躲避反病毒軟件的檢驗,這樣就產(chǎn)生了各種各樣令普通用戶頭 痛的病毒隱藏形式。由于木馬后門的行為特征已具備病毒條件,因此這里把木馬后門也統(tǒng)一歸納為病毒來描述。
開山鼻祖:隱藏窗口 & 隱藏進(jìn)程 & 隱藏文件
在計算機(jī)流行的早期,計算機(jī)病毒和木馬后門等危害程序在普通用戶范圍的普及并不是很廣泛,這個時期的用戶群對計算機(jī)和網(wǎng)絡(luò)安全的防范意識可以說 是幾乎沒有的,普通用戶的系統(tǒng)也多為脆弱的Windows 95/98系列和電話線撥號的慢速網(wǎng)絡(luò),而那一段時間正是外國木馬“bo”和國產(chǎn)木馬雛形“冰河”、“netspy”等在如今看來各方面技術(shù)都頗為簡單的 遠(yuǎn)程控制軟件大行其道的黃金時期,很多用戶根本就沒有防火墻和殺毒軟件(即使有,也是以殺cih的為主),即使遠(yuǎn)方的黑客把用戶的計算機(jī)翻了個底朝天,用 戶也不會有所察覺,這一時期接觸此類技術(shù)的人相對較少,因此并未造成如今這個病毒到處蔓延的局面。
因為這個階段國內(nèi)用戶的機(jī)器環(huán)境仍然以Windows 9x為主流,所以病毒編寫者們并不需要消耗太多的腦筋就可以做到讓病毒悄無聲息運行的效果,并讓它在alt+del+ctrl呼出的任務(wù)管理器中不可見。
我們都知道,在Windows下運行的程序界面都被定義為“窗口”,程序通過這個途徑與用戶產(chǎn)生交互,每個完整的程序都必須擁有至少一個窗口, 但是如果編寫者將這個窗口在運行期間設(shè)置為“不可見”呢?這樣一來,用戶就不會察覺到這個程序在桌面上運行了,但是如果有一定經(jīng)驗的用戶打開任務(wù)管理器, 他就會因為發(fā)現(xiàn)系統(tǒng)里多出來的進(jìn)程而產(chǎn)生懷疑,因此病毒編寫者在這個時期采取了初級形式的隱藏手段:隱藏進(jìn)程。
其實所謂隱藏進(jìn)程,是利用微軟未公開的一個api(application programming interface,應(yīng)用程序接口)函數(shù)“registerserviceprocess”將自身注冊為“服務(wù)進(jìn)程”,而恰巧Windows 9x中的任務(wù)管理器是不會顯示此類進(jìn)程的,結(jié)果就被病毒鉆了空子,讓“冰河”等木馬在國內(nèi)大部分普通用戶的機(jī)器上安家落戶。
而早期后門技術(shù)里,還有一個最基本的行為就是隱藏文件,與今天的各種隱藏手段相比,它可謂是“不入流”級別了——這里提到的“隱藏”,就是簡單 的將文件屬性設(shè)置為“隱藏”而已,除此之外,再無別的保護(hù)手段了,然而,由于系統(tǒng)設(shè)計時為了避免初學(xué)者胡亂刪除文件而默認(rèn)“不顯示系統(tǒng)和隱藏文件”的做法 (到了Windows 2000/xp時代,這個做法更升級到“隱藏受保護(hù)的系統(tǒng)文件”了),卻恰好給這些病毒提供了天然的隱身場所——大部分對電腦操作不熟悉的用戶根本不知道 “隱藏文件”的含義,更別提設(shè)置為“顯示所有文件”了,在那個安全軟件廠商剛開始探索市場的時代,用戶更是不會留意太多安全產(chǎn)品及其實際含義,因而這個時 期成了各種初期木馬技術(shù)發(fā)展的重要階段,利用這種手段制作的木馬被統(tǒng)稱為“第一代木馬”。
以現(xiàn)在的技術(shù)和眼光看來,這些早期技術(shù)作品的發(fā)現(xiàn)和清理是相對較簡單的了,因為它們采用的“進(jìn)程隱藏”技術(shù)在NT體系上的Windows2000/xp/2003等操作系統(tǒng)上已經(jīng)無效了,直接使用系統(tǒng)自帶的任務(wù)管理器便能發(fā)現(xiàn)和迅速終止進(jìn)程運行,而后在“控制面板” ——“文件夾選項”里面設(shè)置“顯示所有文件”和取消“隱藏受保護(hù)的系統(tǒng)文件”,就能發(fā)現(xiàn)那個被隱藏起來的木馬程序了。對于Windows 9x用戶,使用任意一款第三方的進(jìn)程管理工具如“Windows優(yōu)化大師”的進(jìn)程管理組件即可輕松發(fā)現(xiàn)。
繼續(xù)發(fā)展:使用線程注射技術(shù)的dll木馬
雖然現(xiàn)在使用“線程注射”的木馬病毒和流氓軟件已經(jīng)遍地開花了,但是從那個混沌時代經(jīng)歷過來的人都不會忘記首個采用“線程注射”的dll木馬“廣外幽靈”在當(dāng)時所帶來的恐懼,“線程注射”到底是種什么東西呢?下面就讓我們來詳細(xì)講解一下。
首先,用戶可能不會了解“線程”(thread)的意思,而要講解“線程”,就不能不先提到“進(jìn)程”(process)的概念。許多剛接觸計算 機(jī)的用戶無法理解“進(jìn)程”是什么東西:常常聽到高手說打開任務(wù)管理器關(guān)閉某某進(jìn)程,但是一看到任務(wù)管理器列表里的一堆東西,頭就大了。許多用戶知道使用任 務(wù)管理器關(guān)閉一些失去響應(yīng)的任務(wù),但是如果某個任務(wù)沒有在“應(yīng)用程序”列表里出現(xiàn),用戶就不知所措了。到底什么是“進(jìn)程”呢?“進(jìn)程”是指一個可執(zhí)行文件 在運行期間請求系統(tǒng)在內(nèi)存里開辟給它的數(shù)據(jù)信息塊,系統(tǒng)通過控制這個數(shù)據(jù)塊為運行中的程序提供數(shù)據(jù)交換和決定程序生存期限,任何程序都必須擁有至少一個進(jìn) 程,否則它不被系統(tǒng)承認(rèn)。
進(jìn)程從某一方面而言就是可執(zhí)行文件把自身從存儲介質(zhì)復(fù)制在內(nèi)存中的映像,它通常和某個在磁盤上的文件保持著對應(yīng)關(guān)系,一個完整的進(jìn)程信息包括很 多方面的數(shù)據(jù),我們使用進(jìn)程查看工具看到的“應(yīng)用程序”選項卡包含的是進(jìn)程的標(biāo)題,而“進(jìn)程”選項卡包含的是進(jìn)程文件名、進(jìn)程標(biāo)識符、占用內(nèi)存等,其中 “進(jìn)程文件名”和“進(jìn)程標(biāo)識符”是必須掌握的關(guān)鍵,“進(jìn)程標(biāo)識符”是系統(tǒng)分配給進(jìn)程內(nèi)存空間時指定的唯一數(shù)字,進(jìn)程從載入內(nèi)存到結(jié)束運行的期間里這個數(shù)字 都是保持不變的,而“進(jìn)程文件名”則是對應(yīng)著的介質(zhì)存儲文件名稱,根據(jù)“進(jìn)程文件名”我們就可以找到最初的可執(zhí)行文件位置。
任務(wù)管理器的“應(yīng)用程序”項里列出來的“任務(wù)”,是指進(jìn)程在桌面上顯示出來的窗口對象,例如用戶打開word 2003撰寫文檔,它的進(jìn)程“winword.exe”會創(chuàng)建一個在桌面上顯示的前臺窗口,這個窗口就是任務(wù)管理器里看得見的“任務(wù)”了,而實際上真正在 運行的是進(jìn)程“winword.exe”。并不是所有的進(jìn)程都會在任務(wù)管理器里留下“任務(wù)”的,像QQ、msn 和所有后臺程序,它們并不會在任務(wù)列表里出現(xiàn),但是你會在進(jìn)程列表里找到它們,如果要它們在任務(wù)列表里出現(xiàn)該怎么辦呢?只要讓它們產(chǎn)生一個在桌面上出現(xiàn)的 窗體就可以了,隨便打開一個好友聊天,就會發(fā)現(xiàn)任務(wù)列表里終于出現(xiàn)了qq的任務(wù)。因此,真正科學(xué)的終止程序執(zhí)行方案是針對“進(jìn)程”來結(jié)束程序的運行,而不 是在任務(wù)列表里關(guān)閉程序,因為木馬作者們是不會讓自己的木馬在任務(wù)列表里出現(xiàn)的,但是進(jìn)程列表里一般人都是逃不過的。
而“線程”,則是在一個進(jìn)程里產(chǎn)生的多個執(zhí)行進(jìn)度實例,舉個簡單例子,一個網(wǎng)絡(luò)文件傳輸程序如果只有一個線程(單線程)運作,那么它的執(zhí)行效率 會非常低下,因為它既需要從網(wǎng)絡(luò)上讀取文件數(shù)據(jù),又需要把文件保存到磁盤,同時還需要繪制當(dāng)前傳輸進(jìn)度條,由于在代碼的角度里這些操作只能一條條的順序執(zhí) 行,程序就不能很好的做到在保存數(shù)據(jù)的同時繪制傳輸進(jìn)度條,即使程序員將其勉強湊到一塊執(zhí)行,在用戶方面看來,這個程序的響應(yīng)會非常緩慢甚至直接崩潰,而 “多線程”技術(shù)則是為了解決這種問題而產(chǎn)生的,采用“多線程”技術(shù)編寫的應(yīng)用程序在運行時可以產(chǎn)生多個同時執(zhí)行的操作實例,例如一個采用“多線程”技術(shù)的 網(wǎng)絡(luò)文件傳輸程序就能同時分出三個進(jìn)度來同時執(zhí)行網(wǎng)絡(luò)數(shù)據(jù)傳輸、文件保存操作和繪制傳輸進(jìn)度條的操作,于是在用戶看來,這個程序運行非常流暢,這就是線程 的作用。在程序運行時,只能產(chǎn)生一個進(jìn)程,但是在這個進(jìn)程的內(nèi)存空間(系統(tǒng)為程序能正常執(zhí)行而開辟的獨立內(nèi)存領(lǐng)域)里,可以產(chǎn)生多個線程,其中至少有一個 默認(rèn)的線程,被稱為“主線程”,它是程序主要代碼的運行部分。
那么,“線程注射”又是什么含義呢?其實它的全稱是“遠(yuǎn)程線程注射”(remotethread injection),通常情況下,各個進(jìn)程的內(nèi)存空間是不可以相互訪問的,這也是為程序能夠穩(wěn)定運行打下基礎(chǔ),這個訪問限制讓所有進(jìn)程之間互相獨立,這 樣一來,任何一個非系統(tǒng)關(guān)鍵進(jìn)程發(fā)生崩潰時都不會影響到其他內(nèi)存空間里的進(jìn)程執(zhí)行,從而使nt架構(gòu)的穩(wěn)定性遠(yuǎn)遠(yuǎn)高于win9x架構(gòu)。但是在一些特定的場合 里,必須讓進(jìn)程之間可以互相訪問和管理,這就是“遠(yuǎn)程線程”技術(shù)的初衷,這個技術(shù)實現(xiàn)了進(jìn)程之間的跨內(nèi)存空間訪問,其核心是產(chǎn)生一個特殊的線程,這個線程 能夠?qū)⒁欢螆?zhí)行代碼連接到另一個進(jìn)程所處的內(nèi)存空間里,作為另一個進(jìn)程的其中一個非核心線程來運行,從而達(dá)到交換數(shù)據(jù)的目的,這個連接的過程被稱為“注 射”(injection)。遠(yuǎn)程線程技術(shù)好比一棵寄生在大樹上的蔓藤,一旦目標(biāo)進(jìn)程被注射,這段新生的線程就成為目標(biāo)進(jìn)程的一部分代碼了,只要目標(biāo)進(jìn)程 不被終止,原進(jìn)程無論是否還在運行都不會再影響到執(zhí)行結(jié)果了。
與“線程注射”離不開的是“hook”技術(shù),這個“hook”,又是什么呢?其官方定義如下:
鉤子(hook),是Windows消息處理機(jī)制的一個平臺,應(yīng)用程序可以在上面設(shè)置子程以監(jiān)視指定窗口的某種消息,而且所監(jiān)視的窗口可以是其他進(jìn)程所創(chuàng)建的。當(dāng)消息到達(dá)后,在目標(biāo)窗口處理函數(shù)之前處理它。鉤子機(jī)制允許應(yīng)用程序截獲處理window消息或特定事件。
鉤子實際上是一個處理消息的程序段,通過系統(tǒng)調(diào)用,把它掛入系統(tǒng)。每當(dāng)特定的消息發(fā)出,在沒有到達(dá)目的窗口前,鉤子程序就先捕獲該消息,亦即鉤 子函數(shù)先得到控制權(quán)。這時鉤子函數(shù)即可以加工處理(改變)該消息,也可以不作處理而繼續(xù)傳遞該消息,還可以強制結(jié)束消息的傳遞。
在這里,木馬編寫者首先把一個實際為木馬主體的dll文件載入內(nèi)存,然后通過“線程注射”技術(shù)將其注入其他進(jìn)程的內(nèi)存空間,最后這個dll里的 代碼就成為其他進(jìn)程的一部分來實現(xiàn)了自身的隱藏執(zhí)行,通過調(diào)用“hook”機(jī)制,這個dll木馬便實現(xiàn)了監(jiān)視用戶的輸入輸出操作,截取有用的資料等操作。 這種木馬的實際執(zhí)行體是一個dll文件,由于Windows系統(tǒng)自身就包含著大量的dll文件,誰也無法一眼看出哪個dll文件不是系統(tǒng)自帶的,所以這種 木馬的隱蔽性又提高了一級,而且它的執(zhí)行方式也更加隱蔽,這是由Windows系統(tǒng)自身特性決定的,Windows自身就是大量使用dll的系統(tǒng),許多 dll文件在啟動時便被相關(guān)的應(yīng)用程序加載進(jìn)內(nèi)存里執(zhí)行了,可是有誰在進(jìn)程里直接看到過某個dll在運行的?因為系統(tǒng)是把dll視為一種模塊性質(zhì)的執(zhí)行體 來調(diào)用的,它內(nèi)部只包含了一堆以函數(shù)形式輸出的模塊,也就是說每個dll都需要由一個用到它的某個函數(shù)的exe來加載,當(dāng)dll里的函數(shù)執(zhí)行完畢后就會返 回一個運行結(jié)果給調(diào)用它的exe,然后dll進(jìn)程退出內(nèi)存結(jié)束這次執(zhí)行過程,這就是標(biāo)準(zhǔn)的dll運行周期,而采用了“線程注射”技術(shù)的dll則不是這樣, 它們自身雖然也是導(dǎo)出函數(shù),但是它們的代碼是具備執(zhí)行邏輯的,這種模塊就像一個普通exe,只是它不能直接由自身啟動,而是需要有一個特殊作用的程序(稱 為加載者)產(chǎn)生的進(jìn)程把這個dll的主體函數(shù)載入內(nèi)存中執(zhí)行,從而讓它成為一個運行中的木馬程序。
了解Windows的用戶都知道,模塊是緊緊依賴于進(jìn)程的,調(diào)用了某個模塊的進(jìn)程一旦退出執(zhí)行,其加載的dll模塊也就被迫終止了,但是在 dll木馬里,這個情況是不會因為最早啟動的exe被終止而發(fā)生的,因為它使用了“遠(yuǎn)程線程注射”技術(shù),所以,在用戶發(fā)現(xiàn)異常時,dll木馬早就不知道被 注入哪個正常進(jìn)程里了,即使用戶發(fā)現(xiàn)了這個木馬dll,也無法把它終止,因為要關(guān)閉它就必須在那么多的系統(tǒng)進(jìn)程里找到被它注射的進(jìn)程,并將其終止,對一般 用戶來說,這是個不可能完成的任務(wù)。