技術 > dll木馬
目錄
No. 1
  dll 木馬揭秘
  相信經常玩木馬的朋友們都會知道一些木馬的特性,也會有自己最喜愛的木馬,不過,很多朋友依然不知道近年興起的“dll木馬”為何物。什麽是“dll木馬”呢?它與一般的木馬有什麽不同?
  一、從dll技術說起
  要瞭解dll木馬,就必須知道這個“dll”是什麽意思,所以,讓我們追溯到幾年前,dos係統大行其道的日子裏。在那時候,寫程序是一件繁瑣的事情,因為每個程序的代碼都是獨立的,有時候為了實現一個功能,就要為此寫很多代碼,後來隨着編程技術發展,程序員們把很多常用的代碼集合(通用代碼)放進一個獨立的文件裏,並把這個文件稱為“庫”(library),在寫程序的時候,把這個庫文件加入編譯器,就能使用這個庫包含的所有功能而不必自己再去寫一大堆代碼,這個技術被稱為“靜態鏈接”(static link)。靜態鏈接技術讓勞累的程序員鬆了口氣,一切似乎都很美好。可是事實證明,美好的事物不會存在太久,因為靜態鏈接就像一個粗魯的推銷員,不管你想不想要宣傳單,他都全部塞到你的手上來。寫一個程序衹想用到一個庫文件包含的某個圖形效果,就因為這個,你不得不把這個庫文件攜帶的所有的圖形效果都加入程序,留着它們當花瓶擺設,這倒沒什麽重要,可是這些花瓶卻把道路都阻塞了——靜態鏈接技術讓最終的程序成了大塊頭,因為編譯器把整個庫文件也算進去了。
  時代在發展,靜態鏈接技術由於天生的弊端,不能滿足程序員的願望,人們開始尋找一種更好的方法來解决代碼重複的難題。後來,windows係統出現了,時代的分水嶺終於出現。windows係統使用一種新的鏈接技術,這種被稱為“動態鏈接”(dynamic link)的新技術同樣也是使用庫文件,微軟稱它們為“動態鏈接庫”——dynamic link library,dll的名字就是這樣來的。動態鏈接本身和靜態鏈接沒什麽區別,也是把通用代碼寫進一些獨立文件裏,但是在編譯方面,微軟繞了個圈子,並沒有采取把庫文件加進程序的方法,而是把庫文件做成已經編譯好的程序文件,給它們開個交換數據的接口,程序員寫程序的時候,一旦要使用某個庫文件的一個功能函數,係統就把這個庫文件調入內存,連接上這個程序占有的任務進程,然後執行程序要用的功能函數,並把結果返回給程序顯示出來,在我們看來,就像是程序自己帶有的功能一樣。完成需要的功能後,這個dll停止運行,整個調用過程結束。微軟讓這些庫文件能被多個程序調用,實現了比較完美的共享,程序員無論要寫什麽程序,衹要在代碼裏加入對相關dll的調用聲明就能使用它的全部功能。最重要的是,dll絶對不會讓你多拿一個花瓶,你要什麽它就給你什麽,你不要的東西它纔不會給你。這樣,寫出來的程序就不能再攜帶一大堆垃圾了——絶對不會讓你把吃剩的東西帶回傢,否則罰款,這是自助餐。
  dll技術的誕生,使編寫程序變成一件簡單的事情,windows為我們提供了幾千個函數接口,足以滿足大多數程序員的需要。而且,windows係統自身就是由幾千個dll文件組成,這些dll相互扶持,組成了強大的windows係統。如果windows使用靜態鏈接技術,它的體積會有多大?我不敢想。
  二、應用程序接口api
  上面我們對dll技術做了個大概分析,在裏面我提到了“接口”,這又是什麽呢?因為dll不能像靜態庫文件那樣塞進程序裏,所以,如何讓程序知道實現功能的代碼和文件成了問題,微軟就為dll技術做了標準規範,讓一個dll文件像奶酪一樣開了許多小洞,每個洞口都註明裏面存放的功能的名字,程序衹要根據標準規範找到相關洞口就可以取得它要的美味了,這個洞口就是“應用程序接口”(application programming interface),每個dll帶的接口都不相同,盡最大可能的減少了代碼的重複。用steven的一句話:api就是一個工具箱,你根據需要取出蠃絲刀、扳手,用完後再把它們放回原處。在windows裏,最基本的3個dll文件是kernel32.dll、user32.dll、gdi32.dll。它們共同構成了基本的係統框架。
  三、dll與木馬
  dll是編譯好的代碼,與一般程序沒什麽大差別,衹是它不能獨立運行,需要程序調用。那麽,dll與木馬能扯上什麽關係呢?如果你學過編程並且寫過dll,就會發現,其實dll的代碼和其他程序幾乎沒什麽兩樣,僅僅是接口和啓動模式不同,衹要改動一下代碼入口,dll就變成一個獨立的程序了。當然,dll文件是沒有程序邏輯的,這裏並不是說dll=exe,不過,依然可以把dll看做缺少了main入口的exe,dll帶的各個功能函數可以看作一個程序的幾個函數模塊。dll木馬就是把一個實現了木馬功能的代碼,加上一些特殊代碼寫成dll文件,導出相關的api,在別人看來,這衹是一個普通的dll,但是這個dll卻攜帶了完整的木馬功能,這就是dll木馬的概念。也許有人會問,既然同樣的代碼就可以實現木馬功能,那麽直接做程序就可以,為什麽還要多此一舉寫成dll呢?這是為了隱藏,因為dll運行時是直接挂在調用它的程序的進程裏的,並不會另外産生進程,所以相對於傳統exe木馬來說,它很難被查到。
  四、dll的運行
  雖然dll不能自己運行,可是windows在加載dll的時候,需要一個入口函數,就如同exe的main一樣,否則係統無法引用dll。所以根據編寫規範,windows必須查找並執行dll裏的一個函數dllmain作為加載dll的依據,這個函數不作為api導出,而是內部函數。dllmain函數使dll得以保留在內存裏,有的dll裏面沒有dllmain函數,可是依然能使用,這是因為windows在找不到dllmain的時候,會從其它運行庫中找一個不做任何操作的缺省dllmain函數啓動這個dll使它能被載入,並不是說dll可以放棄dllmain函數。
  五、dll木馬技術分析
  到了這裏,您也許會想,既然dll木馬有那麽多好處,以後寫木馬都采用dll方式不就好了嗎?話雖然是這麽說沒錯,但是dll木馬並不是一些人想象的那麽容易寫的。要寫一個能用的dll木馬,你需要瞭解更多知識。
  1.木馬的主體
  千萬別把木馬模塊寫得真的像個api庫一樣,這不是開發winapi。dll木馬可以導出幾個輔助函數,但是必須有一個過程負責主要執行代碼,否則這個dll衹能是一堆零碎api函數,別提工作了。
  如果涉及一些通用代碼,可以在dll裏寫一些內部函數,供自己的代碼使用,而不是把所有代碼都開放成接口,這樣它自己本身都難調用了,更不可能發揮作用。
  dll木馬的標準執行入口為dllmain,所以必須在dllmain裏寫好dll木馬運行的代碼,或者指嚮dll木馬的執行模塊。
  2.動態嵌入技術
  windows中,每個進程都有自己的私有內存空間,別的進程是不允許對這個私人領地進行操作的,但是,實際上我們仍然可以利用種種方法進入並操作進程的私有內存,這就是動態嵌入,它是將自己的代碼嵌入正在運行的進程中的技術。動態嵌入有很多種,最常見的是鈎子、api以及遠程綫程技術,現在的大多數dll木馬都采用遠程綫程技術把自己挂在一個正常係統進程中。其實動態嵌入並不少見,羅技的mouseware驅動就挂着每一個係統進程-_-
  遠程綫程技術就是通過在另一個進程中創建遠程綫程(remotethread)的方法進入那個進程的內存地址空間。在dll木馬的範疇裏,這個技術也叫做“註入”,當載體在那個被註入的進程裏創建了遠程綫程並命令它加載dll時,木馬就挂上去執行了,沒有新進程産生,要想讓木馬停止惟有讓挂接這個木馬dll的進程退出運行。但是,很多時候我們衹能束手無策——它和explorer.exe挂在一起了,你確定要關閉windows嗎?
  3.木馬的啓動
  有人也許會迫不及待的說,直接把這個dll加入係統啓動項目不就可以了。答案是no,前面說過,dll不能獨立運行,所以無法在啓動項目裏直接啓動它。要想讓木馬跑起來,就需要一個exe使用動態嵌入技術讓dll搭上其他正常進程的車,讓被嵌入的進程調用這個dll的dllmain函數,激發木馬運行,最後啓動木馬的exe結束運行,木馬啓動完畢。
  啓動dll木馬的exe是個重要角色,它被稱為loader,如果沒有loader,dll木馬就是破爛一堆,因此,一個算得上成熟的dll木馬會想辦法保護它的loader不會那麽容易被毀滅。記得狼狽為姦的故事嗎?dll木馬就是爬在狼loader上的狽。
  loader可以是多種多樣的,windows的rundll32.exe也被一些dll木馬用來做了loader,這種木馬一般不帶動態嵌入技術,它直接挂着rundll32進程運行,用rundll32的方法(rundll32.exe [dll名],[函數] [參數])像調用api一樣去引用這個dll的啓動函數激發木馬模塊開始執行,即使你殺了rundll32,木馬本體還是在的,一個最常見的例子就是3721中文實名,雖然它不是木馬。
  註册表的appinit_dlls鍵也被一些木馬用來啓動自己,如求職信病毒。利用註册表啓動,就是讓係統執行dllmain來達到啓動木馬的目的。因為它是kernel調入的,對這個dll的穩定性有很大要求,稍有錯誤就會導致係統崩潰,所以很少看到這種木馬。
  有一些更復雜點的dll木馬通過svchost.exe啓動,這種dll木馬必須寫成nt-service,入口函數是servicemain,一般很少見,但是這種木馬的隱蔽性也不錯,而且loader有保障。
  4.其它
  到這裏大傢也應該對dll木馬有個瞭解了,是不是很想寫一個?別急,不知道大傢想過沒有,既然dll木馬這麽好,為什麽到現在能找到的dll木馬寥寥無幾?現在讓我來潑冷水,最重要的原因衹有一個:由於dll木馬挂着係統進程運行,如果它本身寫得不好,例如沒有防止運行錯誤的代碼或者沒有嚴格規範用戶的輸入,dll就會出錯崩潰。別緊張,一般的exe也是這樣完蛋的,但是dll崩潰會導致它挂着的程序跟着遭殃,別忘記它挂接的是係統進程哦,結局就是……慘不忍睹。所以寫一個能公佈的dll木馬,在排錯檢查方面做的工作要比一般的exe木馬多,寫得多了自己都煩躁……
  六、dll木馬的發現和查殺
  經常看看啓動項有沒有多出莫名其妙的項目,這是loader的所在,衹要殺了狼,狽就不能再狂了。而dll木馬本體比較難發現,需要你有一定編程知識和分析能力,在loader裏查找dll名稱,或者從進程裏看多挂接了什麽陌生的dll,可是對新手來說……總之就是比較難啊比較難,所以,最簡單的方法:殺毒軟件和防火墻(不是萬能藥,切忌長期服用)。
相關詞
動態嵌入式