大揭秘系統(tǒng)DLL技術(shù)助力木馬靜態(tài)變動(dòng)態(tài)

字號(hào):

很多朋友依然不知道近年興起的“DLL木馬”為何物。什么是“DLL木馬”呢?它與一般的木馬有什么不同?
    一、從DLL技術(shù)說(shuō)起
    要了解DLL木馬,就必須知道這個(gè)“DLL”是什么意思,所以,讓我們追溯到幾年前,DOS系統(tǒng)大行其道的日子里。在那時(shí)候,寫程序是一件繁瑣的事情,因?yàn)槊總€(gè)程序的代碼都是獨(dú)立的,有時(shí)候?yàn)榱藢?shí)現(xiàn)一個(gè)功能,就要為此寫很多代碼,后來(lái)隨著編程技術(shù)發(fā)展,程序員們把很多常用的代碼集合(通用代碼)放進(jìn)一個(gè)獨(dú)立的文件里,并把這個(gè)文件稱為“庫(kù)”(Library),在寫程序的時(shí)候,把這個(gè)庫(kù)文件加入編譯器,就能使用這個(gè)庫(kù)包含的所有功能而不必自己再去寫一大堆代碼,這個(gè)技術(shù)被稱為“靜態(tài)鏈接”(Static Link)。靜態(tài)鏈接技術(shù)讓勞累的程序員松了口氣,一切似乎都很美好??墒鞘聦?shí)證明,美好的事物不會(huì)存在太久,因?yàn)殪o態(tài)鏈接就像一個(gè)粗魯?shù)耐其N員,不管你想不想要宣傳單,他都全部塞到你的手上來(lái)。寫一個(gè)程序只想用到一個(gè)庫(kù)文件包含的某個(gè)圖形效果,就因?yàn)檫@個(gè),你不得不把這個(gè)庫(kù)文件攜帶的所有的圖形效果都加入程序,留著它們當(dāng)花瓶擺設(shè),這倒沒(méi)什么重要,可是這些花瓶卻把道路都阻塞了――靜態(tài)鏈接技術(shù)讓最終的程序成了大塊頭,因?yàn)榫幾g器把整個(gè)庫(kù)文件也算進(jìn)去了。
    時(shí)代在發(fā)展,靜態(tài)鏈接技術(shù)由于天生的弊端,不能滿足程序員的愿望,人們開(kāi)始尋找一種更好的方法來(lái)解決代碼重復(fù)的難題。后來(lái),Windows系統(tǒng)出現(xiàn)了,時(shí)代的分水嶺終于出現(xiàn)。Windows系統(tǒng)使用一種新的鏈接技術(shù),這種被稱為“動(dòng)態(tài)鏈接”(Dynamic Link)的新技術(shù)同樣也是使用庫(kù)文件,微軟稱它們?yōu)椤皠?dòng)態(tài)鏈接庫(kù)”――Dynamic Link Library,DLL的名字就是這樣來(lái)的。動(dòng)態(tài)鏈接本身和靜態(tài)鏈接沒(méi)什么區(qū)別,也是把通用代碼寫進(jìn)一些獨(dú)立文件里,但是在編譯方面,微軟繞了個(gè)圈子,并沒(méi)有采取把庫(kù)文件加進(jìn)程序的方法,而是把庫(kù)文件做成已經(jīng)編譯好的程序文件,給它們開(kāi)個(gè)交換數(shù)據(jù)的接口,程序員寫程序的時(shí)候,一旦要使用某個(gè)庫(kù)文件的一個(gè)功能函數(shù),系統(tǒng)就把這個(gè)庫(kù)文件調(diào)入內(nèi)存,連接上這個(gè)程序占有的任務(wù)進(jìn)程,然后執(zhí)行程序要用的功能函數(shù),并把結(jié)果返回給程序顯示出來(lái),在我們看來(lái),就像是程序自己帶有的功能一樣。完成需要的功能后,這個(gè)DLL停止運(yùn)行,整個(gè)調(diào)用過(guò)程結(jié)束。微軟讓這些庫(kù)文件能被多個(gè)程序調(diào)用,實(shí)現(xiàn)了比較完美的共享,程序員無(wú)論要寫什么程序,只要在代碼里加入對(duì)相關(guān)DLL的調(diào)用聲明就能使用它的全部功能。最重要的是,DLL絕對(duì)不會(huì)讓你多拿一個(gè)花瓶,你要什么它就給你什么,你不要的東西它才不會(huì)給你。這樣,寫出來(lái)的程序就不能再攜帶一大堆垃圾了――絕對(duì)不會(huì)讓你把吃剩的東西帶回家,否則罰款,這是自助餐。
    DLL技術(shù)的誕生,使編寫程序變成一件簡(jiǎn)單的事情,Windows為我們提供了幾千個(gè)函數(shù)接口,足以滿足大多數(shù)程序員的需要。而且,Windows系統(tǒng)自身就是由幾千個(gè)DLL文件組成,這些DLL相互扶持,組成了強(qiáng)大的Windows系統(tǒng)。如果Windows使用靜態(tài)鏈接技術(shù),它的體積會(huì)有多大?我不敢想。
    二、應(yīng)用程序接口API
    上面我們對(duì)DLL技術(shù)做了個(gè)大概分析,在里面我提到了“接口”,這又是什么呢?因?yàn)镈LL不能像靜態(tài)庫(kù)文件那樣塞進(jìn)程序里,所以,如何讓程序知道實(shí)現(xiàn)功能的代碼和文件成了問(wèn)題,微軟就為DLL技術(shù)做了標(biāo)準(zhǔn)規(guī)范,讓一個(gè)DLL文件像奶酪一樣開(kāi)了許多小洞,每個(gè)洞口都注明里面存放的功能的名字,程序只要根據(jù)標(biāo)準(zhǔn)規(guī)范找到相關(guān)洞口就可以取得它要的美味了,這個(gè)洞口就是“應(yīng)用程序接口”(Application Programming Interface),每個(gè)DLL帶的接口都不相同,盡可能的減少了代碼的重復(fù)。用Steven的一句話:API就是一個(gè)工具箱,你根據(jù)需要取出螺絲刀、扳手,用完后再把它們放回原處。在Windows里,最基本的3個(gè)DLL文件是kernel32.dll、user32.dll、gdi32.dll。它們共同構(gòu)成了基本的系統(tǒng)框架。
    三、DLL與木馬
    DLL是編譯好的代碼,與一般程序沒(méi)什么大差別,只是它不能獨(dú)立運(yùn)行,需要程序調(diào)用。那么,DLL與木馬能扯上什么關(guān)系呢?如果你學(xué)過(guò)編程并且寫過(guò)DLL,就會(huì)發(fā)現(xiàn),其實(shí)DLL的代碼和其他程序幾乎沒(méi)什么兩樣,僅僅是接口和啟動(dòng)模式不同,只要改動(dòng)一下代碼入口,DLL就變成一個(gè)獨(dú)立的程序了。當(dāng)然,DLL文件是沒(méi)有程序邏輯的,這里并不是說(shuō)DLL=EXE,不過(guò),依然可以把DLL看做缺少了main入口的EXE,DLL帶的各個(gè)功能函數(shù)可以看作一個(gè)程序的幾個(gè)函數(shù)模塊。DLL木馬就是把一個(gè)實(shí)現(xiàn)了木馬功能的代碼,加上一些特殊代碼寫成DLL文件,導(dǎo)出相關(guān)的API,在別人看來(lái),這只是一個(gè)普通的DLL,但是這個(gè)DLL卻攜帶了完整的木馬功能,這就是DLL木馬的概念。也許有人會(huì)問(wèn),既然同樣的代碼就可以實(shí)現(xiàn)木馬功能,那么直接做程序就可以,為什么還要多此一舉寫成DLL呢?這是為了隱藏,因?yàn)镈LL運(yùn)行時(shí)是直接掛在調(diào)用它的程序的進(jìn)程里的,并不會(huì)另外產(chǎn)生進(jìn)程,所以相對(duì)于傳統(tǒng)EXE木馬來(lái)說(shuō),它很難被查到。
    四、DLL的運(yùn)行
    雖然DLL不能自己運(yùn)行,可是Windows在加載DLL的時(shí)候,需要一個(gè)入口函數(shù),就如同EXE的main一樣,否則系統(tǒng)無(wú)法引用DLL。所以根據(jù)編寫規(guī)范,Windows必須查找并執(zhí)行DLL里的一個(gè)函數(shù)DllMain作為加載DLL的依據(jù),這個(gè)函數(shù)不作為API導(dǎo)出,而是內(nèi)部函數(shù)。DllMain函數(shù)使DLL得以保留在內(nèi)存里,有的DLL里面沒(méi)有DllMain函數(shù),可是依然能使用,這是因?yàn)閃indows在找不到DllMain的時(shí)候,會(huì)從其它運(yùn)行庫(kù)中找一個(gè)不做任何操作的缺省DllMain函數(shù)啟動(dòng)這個(gè)DLL使它能被載入,并不是說(shuō)DLL可以放棄DllMain函數(shù)。