我們知道,應(yīng)用程序總是離不開系統(tǒng)內(nèi)核所提供的服務(wù),,比如它要使用內(nèi)存的時候,,只要跟操作系統(tǒng)申請就行了,,而不用自己操心哪里有空閑的內(nèi)存空間等問題,實(shí)際上,,這些問題是由操作系統(tǒng)的內(nèi)核來代勞的,。站在黑客的角度講,如果能夠控制內(nèi)核,,實(shí)際上就是控制了內(nèi)核之上的各種應(yīng)用程序,。本文將向您介紹如何建立內(nèi)核級鉤子來控制操作系統(tǒng)向上提供的各種低級功能。有了內(nèi)核級鉤子,,我們不但能夠控制,、監(jiān)視其他程序并過濾有關(guān)數(shù)據(jù),還能用其實(shí)現(xiàn)Rootkit本身及其它程序的隱形,。 本文首先回顧系統(tǒng)調(diào)用表和內(nèi)存保護(hù)方面的知識,,然后講解如何實(shí)現(xiàn)內(nèi)核鉤子,最后對一些重要的內(nèi)核函數(shù)進(jìn)行了簡要的說明,。 一,、系統(tǒng)調(diào)用表 系統(tǒng)調(diào)用表又稱系統(tǒng)服務(wù)表或者服務(wù)描述符表,是Windows 內(nèi)核在進(jìn)行各種系統(tǒng)操作時所需的一個函數(shù)指針表,。也就是說,,這個表中存放的是提供系統(tǒng)服務(wù)的各種函數(shù)的地址。當(dāng)然,,該表所指向的都是系統(tǒng)自身的一些函數(shù),,但是,如果我們對它做了手腳后,,就可以讓它指向我們自己的函數(shù),。這正是本文要講解的重點(diǎn)。 讀者一定要注意,,修改系統(tǒng)調(diào)用表及替換內(nèi)核函數(shù)時,,會對系統(tǒng)全局產(chǎn)生影響,稍有不慎就會導(dǎo)致系統(tǒng)崩潰,。所以,,下手之前,最好對表中的各個函數(shù)要有足夠的認(rèn)識,,然后才好用我們自己的函數(shù)替換這些內(nèi)核函數(shù)的方法,。你對它們了解得越多越深,在實(shí)現(xiàn)內(nèi)核鉤子的時候就越順手,。但話又說回來,,這個系統(tǒng)調(diào)用表中的表項實(shí)在是太多了,有的指向字符串操作,,有的指向客戶機(jī)/服務(wù)器操作,,等等。所以要在短時間內(nèi)了解所有表項是不可能的,,所以下文中對它們只做有選擇的,、概括的介紹。 二,、內(nèi)存保護(hù) 現(xiàn)代的Windows操作系統(tǒng)通常將系統(tǒng)調(diào)用表所在內(nèi)存頁設(shè)為只讀來提供保護(hù),。如果不能克服這個問題,實(shí)施內(nèi)核鉤子技術(shù)就是癡人說夢,。因?yàn)樵噲D向只讀內(nèi)存寫入數(shù)據(jù)也即修改只讀內(nèi)存區(qū)時,,立刻就會藍(lán)屏。為此,,先讓我們來了解一下內(nèi)存保護(hù)方面的有關(guān)知識,。 內(nèi)存描述符表是內(nèi)存保護(hù)的一大關(guān)鍵,具體定義詳見微軟DDK中的ntddk.h頭文件,,我們這里僅做簡要介紹:
內(nèi)存描述符表(MDL)的作用是將虛擬內(nèi)存映射成物理頁,。如果將系統(tǒng)調(diào)用表所在內(nèi)存頁的MDL的MDLFlags成員設(shè)為MDL_MAPPED_TO_SYSTEM_VA 并且該頁面被鎖定的話,那么就可以使用內(nèi)核鉤子技術(shù)了,。以下代碼將可以達(dá)此目的:
好了,,我們現(xiàn)在可以通過NewSystemCallTable來新建系統(tǒng)調(diào)用表了。 進(jìn)行掛鉤時,,可以使用以下宏:
使這些宏后,,鉤子技術(shù)會變得更簡單,也更安全,。因?yàn)镮nterlockedExchange 是原子函數(shù),,不會要求中止中斷,所以交換指針的方式是安全的;另外,,它也不需要用一個宏掛鉤之后用另一個宏卸載鉤子,,所以也更方便。下圖向我們展示了攔截系統(tǒng)調(diào)用表的過程,。 系統(tǒng)調(diào)用表數(shù)據(jù)結(jié)構(gòu)KeServiceDescriptorTable不僅含有ntdll.dll 的全部函數(shù)指針,,還存有系統(tǒng)調(diào)用表的基地址和表的大小,當(dāng)建立我們自己的內(nèi)存描述符表的時候,,這些信息是不可或缺的,。利用MDL_MAPPED_TO_SYSTEM_VA 標(biāo)志,我們可以建立一個不可頁出(即不會被換到內(nèi)存之外)的MDL ,,這樣我們就可以將其鎖定,,并把返回的地址用于我們自己的系統(tǒng)調(diào)用表,重要的是,,這個系統(tǒng)調(diào)用表是可寫的,。 三,、定義鉤子函數(shù) 內(nèi)核鉤子主要有三部分組成:要鉤取的函數(shù)(在下文中稱為目標(biāo)函數(shù))、替代要鉤取的函數(shù)的函數(shù)(在下文中成為鉤子函數(shù))和系統(tǒng)調(diào)用表,。前面部分介紹了系統(tǒng)調(diào)用表的問題,,下面開始介紹鉤子函數(shù)。一般說來,,當(dāng)定義自己的鉤子函數(shù)時,,可以先到DDK 的頭文件中找到所想要的函數(shù)的原型,然后,,稍加修改就能把目標(biāo)函數(shù)變成鉤子函數(shù)了,。 例如,ZwMapViewOfSection 是一個內(nèi)核函數(shù),,允許應(yīng)用程序把從動態(tài)鏈接庫導(dǎo)出的函數(shù)映射至內(nèi)存,。如果我們想要鉤住這個內(nèi)核函數(shù),那么可以到ntddk.h頭文件中查看其函數(shù)原型,,如下所示:
有了函數(shù)原型,,我們就可以確定指向目標(biāo)函數(shù)的指針了,如下所示:
鉤子函數(shù)如下所示:
好了,,鉤子技術(shù)的三大件已經(jīng)準(zhǔn)備好了。現(xiàn)在,,我們就可以像下面這樣使用它們: HOOK( ZwMapViewOfSection, NewZwMapViewOfSection, OldZwMapViewOfSection ); 如果你打算使用DriverUnload ()的話,,可千萬不要忘了卸載鉤子。 四,、內(nèi)核函數(shù)系列 經(jīng)過上面的介紹,,我們已經(jīng)了解了系統(tǒng)調(diào)用表有關(guān)知識,也已知道如何攔截系統(tǒng)調(diào)用表中的函數(shù),,下面,,我們再來了解一下我們要鉤取的函數(shù):目標(biāo)函數(shù)。這方面,,如果我們不僅了解系統(tǒng)調(diào)用表中有哪些函數(shù),,還知道這些函數(shù)的工作機(jī)制就最好了。但實(shí)際上,,ntdll.dll 中的導(dǎo)出函數(shù)有好幾百個,,別說一個一個的探究,就是把它們都列出來,,看著看著頭都大了,。幸運(yùn)的是,,我們不必了解每個函數(shù),只要了解其所在的系列就行了,。為什么這么說?因?yàn)槲④浺呀?jīng)按照函數(shù)的功能對Ntdll.dll的導(dǎo)出函數(shù)進(jìn)行了分組,,并冠以意義明確的前綴,所以根據(jù)函數(shù)系列的前綴就能明白它們的大體功能了,。下面對這些函數(shù)系列進(jìn)行簡單的介紹: 1.KiEtw系列:本系列內(nèi)核函數(shù)用于系統(tǒng)內(nèi)核,這些函數(shù)只能從內(nèi)核的內(nèi)部進(jìn)行調(diào)用,,常用的有:KiUserCallbackDispatcher,、KiRaiseUserExceptionDispatcher、KiUserApcDispatcher,、KiUserExceptionDispatcher等,。 2.Csr系列:此系列函數(shù)用于客戶機(jī)和服務(wù)器運(yùn)行時,如果您想攔截客戶機(jī)/服務(wù)器方面的操作,,那么就需要對Csr系列內(nèi)核函數(shù)做進(jìn)一步的了解,。常見的有:CsrClientCallServer、CsrCaptureMessageBuffer,、CsrConnectClientToServer和CrsNewThread等,。 3.Ldr系列:本系列內(nèi)核函數(shù)用于加載程序管理器,如果你打算攔截加載程序的話,,那么請進(jìn)一步考察這組以Ldr為前綴的函數(shù),,常用的有:LdrInitializeThunk、LdrLockLoaderLock,、LdrUnlockLoaderLock,、LdrGetDllHandle、LdrGetProcedureAddress等,。 4.Dbg系列:本系列內(nèi)核函數(shù)用于調(diào)試管理,,如果打算攔截調(diào)試操作的話,那么請進(jìn)一步考察這組以Dbg為前綴的函數(shù),,常用的函數(shù)包括:,、DbgBreakPoint、DbgUserBreakPoint,、DbgPrint和DbgUiConnectToDbg等,。 5.Etw系列:本系列內(nèi)核函數(shù)用于追蹤窗口事件,如果你打算攔截追蹤之類的操作的話,那么請進(jìn)一步考察這組以Etw為前綴的函數(shù),。常用的函數(shù)包括:EtwTraceEvent,、EtwEnableTrace、EtwGetTraceEnableLevel和EtwGetTraceEnableFlags等,。 6.Rtl系列:本系列內(nèi)核函數(shù)用于運(yùn)行時庫,,以Rtl為前綴的函數(shù)可以完成多種操作,,例如字符串、線程,、資源,、臨界區(qū)、安全對象的初始化和使用,,內(nèi)存,、進(jìn)程異常和數(shù)據(jù)類型的處理,還用于完成定時器,、堆,、IPv4和IPv6方面的操作,以及壓縮和解壓縮等,。 7.Pfx系列:本系列內(nèi)核函數(shù)用于ANSI字符串操作,,如果你打算攔截ASNI串表方面的操作的話,就需要進(jìn)一步了解這些函數(shù),。常用的包括:PfxInitialize,、PfxRemovePrefix、PfxInsertPrefix,、PfxFindPrefix等,。 8.Zw系列:本系列內(nèi)核函數(shù)用于文件和注冊表方面的操作,比如文件操作,、注冊表操作,、訪問進(jìn)程、事件操作,、令牌操作,、進(jìn)程操作和端口操作等。 這里介紹的只是內(nèi)核函數(shù)中的一部分,,限于篇幅其他部分在此不作介紹,。 六、結(jié)束語 本文深入介紹了系統(tǒng)調(diào)用表和內(nèi)存保護(hù)方面的知識,,并介紹了實(shí)現(xiàn)鉤子函數(shù)的方法,,最后對一些重要的內(nèi)核函數(shù)進(jìn)行了簡要的說明。有了內(nèi)核級鉤子,,我們不但能夠控制,、監(jiān)視其他程序并過濾有關(guān)數(shù)據(jù),還能達(dá)到隱藏Rootkit本身及其它程序的目的,。需要說明的是,,盡管可以通過內(nèi)核鉤子技術(shù)來實(shí)現(xiàn)rootkit所需的一些功能,但是,現(xiàn)實(shí)中的rootkit通常組合使用多種其它技術(shù),,如進(jìn)程注射,、分層驅(qū)動過濾等。更多的技術(shù),,將在后文中分別加以介紹,。 |
|