![基于OD插件的內(nèi)核調(diào)試器的設計與實現(xiàn)_第1頁](http://file4.renrendoc.com/view/e141fb8396bcdad91aa91dab860fd6ca/e141fb8396bcdad91aa91dab860fd6ca1.gif)
![基于OD插件的內(nèi)核調(diào)試器的設計與實現(xiàn)_第2頁](http://file4.renrendoc.com/view/e141fb8396bcdad91aa91dab860fd6ca/e141fb8396bcdad91aa91dab860fd6ca2.gif)
![基于OD插件的內(nèi)核調(diào)試器的設計與實現(xiàn)_第3頁](http://file4.renrendoc.com/view/e141fb8396bcdad91aa91dab860fd6ca/e141fb8396bcdad91aa91dab860fd6ca3.gif)
![基于OD插件的內(nèi)核調(diào)試器的設計與實現(xiàn)_第4頁](http://file4.renrendoc.com/view/e141fb8396bcdad91aa91dab860fd6ca/e141fb8396bcdad91aa91dab860fd6ca4.gif)
![基于OD插件的內(nèi)核調(diào)試器的設計與實現(xiàn)_第5頁](http://file4.renrendoc.com/view/e141fb8396bcdad91aa91dab860fd6ca/e141fb8396bcdad91aa91dab860fd6ca5.gif)
版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
1、目 錄 TOC o 1-3 u 1緒論 PAGEREF _Toc262138811 h 2研究背景 PAGEREF _Toc262138812 h 2本文的主要研究內(nèi)容 PAGEREF _Toc262138813 h 32 Windows系統(tǒng)基礎 PAGEREF _Toc262138814 h 42.1 OD插件知識 PAGEREF _Toc262138815 h 42.1.1 OD插件簡介 PAGEREF _Toc262138816 h 42.1.2 如何編寫OD插件 PAGEREF _Toc262138817 h 5Windows系統(tǒng)理論知識 PAGEREF _Toc262138818 h
2、 52.2.1 Windows進程虛擬地址空間 PAGEREF _Toc262138819 h 5Windows系統(tǒng)調(diào)用 PAGEREF _Toc262138820 h 6Windows 句柄理解 PAGEREF _Toc262138821 h 7Windows 切換進程空間 PAGEREF _Toc262138822 h 8Windows調(diào)試系統(tǒng)原理 PAGEREF _Toc262138823 h 8Windows調(diào)試系統(tǒng)用戶模塊 PAGEREF _Toc262138824 h 8Windows調(diào)試系統(tǒng)內(nèi)核模塊 PAGEREF _Toc262138825 h 93系統(tǒng)需求分析 PAGEREF
3、 _Toc262138826 h 9存在的主要問題 PAGEREF _Toc262138827 h 9解決方案 PAGEREF _Toc262138828 h 10系統(tǒng)需求分析 PAGEREF _Toc262138829 h 10系統(tǒng)流程圖 PAGEREF _Toc262138830 h 124系統(tǒng)概要設計 PAGEREF _Toc262138831 h 13應用程序模塊 PAGEREF _Toc262138832 h 13內(nèi)核驅(qū)動模塊 PAGEREF _Toc262138833 h 145系統(tǒng)詳細設計 PAGEREF _Toc262138834 h 15的KiFastSystemCall()
4、函數(shù) PAGEREF _Toc262138835 h 15實現(xiàn)HOOK的HxKiFastSystemCall(),改變系統(tǒng)調(diào)用的流程 PAGEREF _Toc262138836 h 16解析微軟提供的PDB文件得到未導出的內(nèi)核函數(shù)地址 PAGEREF _Toc262138837 h 18向Windows系統(tǒng)內(nèi)核中加入我們自己的系統(tǒng)服務表 PAGEREF _Toc262138838 h 24實現(xiàn)我們自己的系統(tǒng)調(diào)用函數(shù) PAGEREF _Toc262138839 h 27移除EPROCESS-DebugPort端口 PAGEREF _Toc262138840 h 31HOOK Windows 內(nèi)核
5、下會發(fā)送調(diào)試事件的內(nèi)核函數(shù) PAGEREF _Toc262138841 h 32HOOK Windows內(nèi)核異常處理函數(shù) PAGEREF _Toc262138842 h 35系統(tǒng)開發(fā)小結(jié) PAGEREF _Toc262138843 h 36參考文獻 PAGEREF _Toc262138844 h 36致 謝 PAGEREF _Toc262138845 h 37基于OD插件的內(nèi)核調(diào)試器的設計與實現(xiàn)摘要:隨著計算機互聯(lián)網(wǎng)技術的飛速發(fā)展,網(wǎng)絡游戲得到了很好的發(fā)展,它的保護也是日趨完善,幾種常見的保護有nProtect GameGuard(NP), hackshield(HS),讓OllyDbg調(diào)試器
6、(OD)不能調(diào)試,Cheat Engine(CE)不能搜索游戲內(nèi)存,讓人們沒法開始逆向它們,本文即在這種背景下為了滿足人們的工作需求而設計的。系統(tǒng)以VC 應用程序編譯器和WIN DDK 驅(qū)動編譯器作為開發(fā)工具,以OD調(diào)試器提供的靜態(tài)庫,Window Research Kernel(WRK)的源碼為基礎,HOOK KiFastSystemCall()函數(shù),通過我們自己在Windows內(nèi)核下加的系統(tǒng)服務表,使其當OD調(diào)試器調(diào)用我們感興趣的系統(tǒng)調(diào)用時,跳到我們自己的系統(tǒng)調(diào)用,這樣使其成功調(diào)用,突破游戲的一般保護,本文以C語言為編程語言,本系統(tǒng)是一個具有實際應用意義的典型系統(tǒng)。關鍵詞:OD插件;NP;
7、HS;游戲保護;OD plug-in based on the kernel debugger Design and ImplementationAbstract: With the rapid development of Internet technology, computer, online games have been well developed, and its protection is also maturing, several common protect nProtect GameGuard (NP), hackshield (HS), let OllyDbg deb
8、ugger (OD) can notdebugging, Cheat Engine (CE) can not search for games of memory, so that people can not start reverse them, this is in this context in order to meet the needs of people work designed.() function, through our own in the Windows kernel plus the system service table, so that the debug
9、ger is called when the OD system call when we are interested, skip to our own system calls, so call it success, breaking the game in generalprotection of this paper, C language programming language, the system is a typical system, the practical application of significance.Key words: OD Plugins;NP;HS
10、;Game Protect TOC o 1-3 u 1緒論1.1研究背景進入二十一世紀以來,隨著社會的不斷進步和互聯(lián)網(wǎng)產(chǎn)業(yè)技術的飛速發(fā)展,網(wǎng)絡游戲得到了空前的流行,研究它的人也越來越大眾化。因此,因為種種原因,一些游戲和商業(yè)程序就會防止OD調(diào)試器和CE數(shù)據(jù)搜索器搜索游戲的數(shù)據(jù)防止逆向工作人員逆向這們,一些防調(diào)試方法如下:1, 比如檢測系統(tǒng)當前系統(tǒng)運行的進程看有沒有Od和Ce,查找窗口看有沒有它們,還有就是搜索Od和Ce的特征碼看有沒有它們,有就退出。2, 調(diào)用IsDebugPresent()函數(shù),檢測這個游戲進程是不是被調(diào)試。3, Hook DbgUiRemoteBreakIn()函數(shù)防止運行
11、int 3斷點中止游戲的程序運行,這樣能防止OD調(diào)試器附加游戲進程。4, 游戲故意產(chǎn)生異常,然后自己去處理它,如果有調(diào)試的話,異常一般會先給調(diào)試器,由調(diào)試器處理了,所以游戲就不會進入它自己的異常處理,這樣它就檢測出了調(diào)試器。5, 還有就是nProtect GameGuard(NP), hackshield(HS),PerfectProtect.sys等等的保護,一般它們都是差不多的,比如系統(tǒng)服務表(SSDT表)HOOK,內(nèi)核下Inline HOOK,一般HOOK NtOpenProcess()防止打開游戲進程得到句柄,HOOK NtReadVirtualMemory(),NtWriteVirt
12、ualMemory()防止讀寫游戲進程空間的內(nèi)存,還有就是HOOK NtDebugActiveProcess(),NtCreateDebugObject(),NtWaitForDebugEvent()等等一系列與調(diào)試有關的系統(tǒng)調(diào)用防止調(diào)試游戲,還有就是HOOK 每個CPU的中斷描述符表(IDT)表中的INT 1和INT 3斷點,防止對游戲進程下斷產(chǎn)生單步調(diào)試事件和異常調(diào)試事件,還有一種就是內(nèi)核下建立一個內(nèi)核線程一直對游戲的進程控制塊(EPROCESS)結(jié)構(gòu)體的(調(diào)試端口)DebugPort一直清0,防止游戲被Od調(diào)試收到調(diào)試信息。綜上所述,第5種保護方法一般是現(xiàn)在最流行的保護,有很多的人們在研
13、究它們的保護,他們一般采用的方法是跳過這些函數(shù)的調(diào)用,比如對于SSDT HOOK,它們可以在KiFastCallEntry()函數(shù)里進行處理,對于Inline HOOK,我們可以先HOOK SSDT進入我們自己的系統(tǒng)調(diào)用,然后才調(diào)用真正的函數(shù),對于調(diào)試端口端口的內(nèi)核函數(shù),改變這些偏移,使其操作EPROCESS結(jié)構(gòu)中的其它沒有多大用的結(jié)構(gòu)成員,比如EPROCESS.time。這種方法針對一般的保護有效,但是對于特定的保護,我們可以特別的處理,比如Tessafe.sys你可以把自己加入白名單等等處理方法,還有對于HS我們可以調(diào)用一個14號功能函數(shù)通知HS保護驅(qū)動退出等等許多的方法。本文的主要研究內(nèi)
14、容基于OD插件的內(nèi)核調(diào)試器系統(tǒng)主要是在OD調(diào)試器的基礎上編寫OD插件,HOOK OD進程空間的的KiFastSystemCall()函數(shù),改變OD進程調(diào)用一些關鍵系統(tǒng)函數(shù)的調(diào)用流程,使其進入我們自己在內(nèi)核中的實現(xiàn)的系統(tǒng)調(diào)用,這樣能夠繞過一般的保護驅(qū)動的鉤子。本系統(tǒng)是主要分為四個主要的功能來實現(xiàn):1, 編寫OD應用程序插件,利用OD調(diào)試器提供給我們的靜態(tài)庫和頭文件來編寫OD插件,在OD調(diào)試器上加個菜單選項用于控制OD調(diào)試器是不是啟動我們的這種程序機制。比如當我們點BeginHook菜單時,我們的程序就開始工作,HOOK KiFastSystemCall()函數(shù),Windows提供給程序員的一般的
15、打開進程OpenProcess(),讀進程內(nèi)存ReadVirtualmemory(),寫進程內(nèi)存WriteVirtualMemory()等等API函數(shù),最終的系統(tǒng)調(diào)用都會調(diào)用這個函數(shù),這時eax是系統(tǒng)調(diào)用ID,堆棧里有調(diào)用這個系統(tǒng)調(diào)用時的各個參數(shù),這樣,我們可以改變這些系統(tǒng)調(diào)用ID,使其調(diào)用我們自己在Windows系統(tǒng)內(nèi)核添加的系統(tǒng)調(diào)用。當我們點CancelHook時,我們的程序就停止工作。2, 由于我們內(nèi)核驅(qū)動要調(diào)用的很多內(nèi)核函數(shù)是ntkrnelpa.exe內(nèi)核文件未導出的,所以我們要自己獲取內(nèi)核函數(shù)在當前系統(tǒng)的地址,很多同學采用的是暴力搜索內(nèi)存然后匹配方法處理的,這種方法效率欠缺,并且由于
16、好多硬編碼,移值性很差。我是這么做的,在內(nèi)核驅(qū)動下,把這些未導出的函數(shù)申明為函數(shù)變量指針,然后用戶層程序(OD插件)調(diào)用DeviceIoControlFile()函數(shù)和驅(qū)動通信取得這些未導出的函數(shù)的名字,然后我們自己解析微軟提供給我們的符號文件(PDB文件),得到這個版本系統(tǒng)的未導出的函數(shù)在這個系統(tǒng)版本的內(nèi)核加載地址。然后再次調(diào)用DeviceIoControlFile()函數(shù)傳給內(nèi)核驅(qū)動。3,把微軟提供的Windows Reasarch Kernel(WRK)里的dbgk目錄下的dbgkobj.c,dbgkport.c,dbgkproc.c,dbgkp.h文件移值到我們的內(nèi)核驅(qū)動工程里來,這幾
17、個.c文件是Windows系統(tǒng)調(diào)試系統(tǒng)機制的實現(xiàn),只要我們集成進我們的驅(qū)動里來了,以后游戲保護對這些調(diào)試機制的一切HOOK與檢測,我們可以不用去管它了,相當于OD插件它們用的是我們自己集成的調(diào)試系統(tǒng)機制。還有內(nèi)核線程對EPROCESS結(jié)構(gòu)體的DebugPort清0,我們也可以跳過它。還有就是增加游戲常HOOK的幾個關鍵函數(shù),比如NtOpenProcess(),NtReadVirtualMemory(),NtWriteVirtualMemory()等等,我們自己在Windows內(nèi)核中實現(xiàn)它,下次OD調(diào)試器調(diào)用這些函數(shù)對游戲進程操作時,都會進入我們自己的這些系統(tǒng)調(diào)用,到時想實現(xiàn)什么功能就實現(xiàn)什么功
18、能。4, Windows系統(tǒng)內(nèi)核下有兩種系統(tǒng)服務表KeServiceDescriptorTable和KeServiceDescriptorTableShadow,對于圖形界面(GUI)線程,它引用的是KeServiceDescriptorTableShadow這個系統(tǒng)服務表,非GUI線程引用的是KeServiceDescriptorTable系統(tǒng)服務表。對于微軟提供的大多數(shù)API,內(nèi)核下都有專門對應的系統(tǒng)調(diào)用,比如當我們調(diào)用OpenProcess() API函數(shù)時,最終會調(diào)用系統(tǒng)調(diào)用NtOpenProcess()。每一個系統(tǒng)調(diào)用ID,在Windows內(nèi)核下都會對應一個系統(tǒng)調(diào)用函數(shù),比如NtOp
19、enProcess的系統(tǒng)調(diào)用ID,在Windows Xp 3的系統(tǒng)下ID為122。Windows Xp3 系統(tǒng)大概提供了283個系統(tǒng)調(diào)用。因此我們自己可以在這兩種系統(tǒng)服務表的后面加上我們自己的系統(tǒng)調(diào)用函數(shù),對應相應的系統(tǒng)調(diào)用ID,這樣當OD調(diào)試器調(diào)用我們感興趣的系統(tǒng)調(diào)用時,我們可以改變系統(tǒng)調(diào)用ID,這樣就可以進入我們自己實現(xiàn)的系統(tǒng)調(diào)用函數(shù)。2 Windows系統(tǒng)基礎 OD插件知識 OD插件簡介 OllyDbg 簡稱(OD) 是一款優(yōu)秀的用戶態(tài)調(diào)試工具。它不僅擁有強大的反匯編能力和動態(tài)分析力,還具有良好的擴展結(jié)構(gòu),允許用戶自行開發(fā)插件完成特定的工作。OD插件也可以有自己的窗口邏輯和功能函數(shù)。事實
20、上,我們可以將它看成這樣一個Windows 程序,它擁有自己的消息循環(huán)和窗口過程,但它的啟動是由OllyDbg 發(fā)起的,具體功能的實現(xiàn)也通過調(diào)用OllyDbg 提供的函數(shù)來實現(xiàn)的。它的啟動過程如下:在OllyDbg 的啟動過程中,有一步是檢查插件路徑下是否存在DLL 文件。如果存在,逐一進行如下掃描:1, 加載該DLL 文件,找到其入口點。2, 通過回調(diào)函數(shù),獲取插件名稱、版本等信息。3, 通過回調(diào)函數(shù),對插件進行初始化,包括申請資源、恢復全局參數(shù)等。如果某個DLL 文件無法順利執(zhí)行這三步,OllyDbg 的啟動將失敗、報錯并退出。OllyDbg 啟動以后,會一直維護插件的隊列,在特定時間向該
21、隊列發(fā)送消息,或者直接調(diào)用插件中定義的函數(shù),用戶通過插件菜單或快捷鍵主動執(zhí)行插件某功能。最后,當OllyDbg 被關閉時,還會調(diào)用插件中的回調(diào)函數(shù),釋放插件申請到的資源,并將需要保存的參數(shù)、配置和附加信息分別予以保存。.2 如何編寫OD插件 新建立一個VC 6.0的工程,把頭文件和靜態(tài)庫文件加進工程里面來,還有在工程里加入/J選項,使使char 默認為unsigned類型,這是OllyDbg 中的約定。然后定義兩個回調(diào)函數(shù),這是OD插件必需的兩個回調(diào)函數(shù),ODBG_Plugindata()和ODBG_Plugininit()函數(shù),之所以說是回調(diào)函數(shù),是因為這是由OD調(diào)試器調(diào)用它們的。比如我們在
22、ODBG_Plugindata()回調(diào)函數(shù)中傳遞我們插件的名字進去;在ODBG_Plugininit()中把OD窗口句柄保存起來;我們還實現(xiàn)了幾個回調(diào)函數(shù),ODBG_Pluginmenu(),ODBG_Pluginaction(),ODBG_Plugindestroy()函數(shù)。這些函數(shù)用于在OD插件菜單中加入菜單選項和我們的響應函數(shù)。我們可以在OD插件里面調(diào)用OD提供很多的API函數(shù),比如有Breakpoint functions,Memory functions,Thread functions,Module functions等等許多的函數(shù)庫。之后編譯成功后把它們放在OD調(diào)試器目錄下的Pl
23、ugin文件夾下就行了。 Windows系統(tǒng)理論知識 Windows進程虛擬地址空間如上圖4-1-1,在Windows系統(tǒng)中,每一個進程都有4GB的虛擬地址空間。02GB是Windows進程的用戶空間,2GB到4GB是Windows的內(nèi)核空間。物理地址擴展(PAE)除外,這時,每個進程的用戶空間為03GB。每個進程有4GB的虛擬地址空間,并不是指它真正有4GB的物理內(nèi)存,而是指每個進程都有其頁目錄表和頁表,通過它會把每個進程映射成4GB虛擬內(nèi)存空間。進程用戶空間0-2GB的映射,頁表一般會把進程的這段虛擬內(nèi)存空間映射到不同的物理內(nèi)存中。但是有例外,就是Windows常見的DLL和可執(zhí)行映象文件
24、,比如kernel32.dll,ntdll.dll和.exe文件運行時的情況。它們有寫入時復制(Copy On Write)機制,在沒有改寫這些代碼前,它們在物理內(nèi)存中只有一份內(nèi)存,所有的進程都會根據(jù)頁目錄和頁表映射到這份物理內(nèi)存。但是當有一個進程改變這些DLL的內(nèi)容時,寫入時復制就發(fā)生了。Windows這時會把這些內(nèi)容在物理內(nèi)存中拷貝一份,改變這個進程的頁目錄和頁表,使之指向這份拷貝的物理內(nèi)存,對其它的進程沒有任何影響,所以這就是用戶層HOOK 系統(tǒng)DLL時,只對本進程有效,對其它進程無效的原因。所以當我們HOOK 一個進程的ntdll.dll的KiFastSystemCall()時,它只會
25、對我們HOOK的這個進程的KiFastSystemCall()函數(shù)起作用。對別的進程沒有影響。 進程內(nèi)核空間24GB空間的映射,通常系統(tǒng)中每個進程的這段虛擬內(nèi)存空間會根據(jù)頁目錄表和頁表映射到相同的物理內(nèi)存中。比如當我們改寫一處內(nèi)存,此時對每個進程都會有效的,對整個系統(tǒng)也都是有效的。 Windows系統(tǒng)調(diào)用下面以Windows XP3系統(tǒng)分析Windows用戶層API是怎么調(diào)用系統(tǒng)調(diào)用的全過程。圖4-1-2是Windows系統(tǒng)進行系統(tǒng)調(diào)用的全過程描述:比如當我們用戶層進程調(diào)用常見的API比如Win32 API 比如OpenProcess(),ReadVirtualMemory(),WriteVi
26、rtualMemory(),CreateFile()等等函數(shù),它們接著會依次調(diào)用ntdll.dll的Zw*函數(shù),Zw*函數(shù)會傳遞系統(tǒng)調(diào)用ID,然后調(diào)用sysenter指令進入ring0,在Windows內(nèi)核下首先執(zhí)行的是KiFastCallEntry()函數(shù),它會根據(jù)系統(tǒng)調(diào)用ID分別從KeServiceDescriptorTable或者KeServiceDescriptorTableShadow這兩種系統(tǒng)調(diào)用表中取得相應的系統(tǒng)調(diào)用函數(shù)地址,然后調(diào)用之。對于GUI線程是從KeServiceDescriptorTableShadow表中取,非GUI線程是從KeServiceDescriptorTa
27、ble表中取的。所以我們可以HOOK KiFastCallEntry()這個函數(shù),我們就可以攔截一切的系統(tǒng)調(diào)用。360安全衛(wèi)士就是使用這種方法攔截系統(tǒng)調(diào)用的。當這個系統(tǒng)調(diào)用成功返回后,KiFastCallEntry()函數(shù)會調(diào)用sysexit指令退出本次的系統(tǒng)調(diào)用,然后返回到用戶進程空間,依次返回到調(diào)用用戶API的地方。 Windows 句柄理解句柄是Windows系統(tǒng)的特性。你可以簡單理解為通過它你就可以訪問相應的內(nèi)核對象。其實Windows是這么設計的,每個進程的EPROCESS結(jié)構(gòu)體中都有個ObjectTable 成員指向進程句柄表(HANDLE_TABLE),里面每一項都是HANDLE
28、_TABLE_ENTRY句柄表項。里面放著相應對象的地址,句柄只是這些表項的索引。還有一點值的注意的是句柄是進程相關的。你在本進程打開的進程句柄,在別的進程當中不能引用它的。它們的結(jié)構(gòu)體定義如下:lkd dt _HANDLE_TABLEnt!_HANDLE_TABLE +0 x000 TableCode : Uint4B /指向_HANDLE_TABLE_ENTRY數(shù)組 +0 x004 QuotaProcess : Ptr32 _EPROCESS /這個句柄表屬于哪個進程 +0 x008 UniqueProcessId : Ptr32 Void +0 x00c HandleTableLock
29、: 4 _EX_PUSH_LOCK +0 x01c HandleTableList : _LIST_ENTRY +0 x024 HandleContentionEvent : _EX_PUSH_LOCK +0 x028 DebugInfo : Ptr32 _HANDLE_TRACE_DEBUG_INFO +0 x02c ExtraInfoPages : Int4B +0 x030 FirstFree : Uint4B +0 x034 LastFree : Uint4B +0 x038 NextHandleNeedingPool : Uint4B +0 x03c HandleCount : In
30、t4B /句柄表的數(shù)量 +0 x040 Flags : Uint4B +0 x040 StrictFIFO : Pos 0, 1 Bitlkd dt _HANDLE_TABLE_ENTRYnt!_HANDLE_TABLE_ENTRY +0 x000 Object : Ptr32 Void /指向內(nèi)核對象的地址 +0 x004 GrantedAccess : Uint4B比如當我們在用戶進程調(diào)用OpenProcess() 打開進程時,它先會調(diào)ntdll.dll的ZwOpenProcess(),接著會傳遞NtOpenProcess()的系統(tǒng)調(diào)用ID,調(diào)用KiFastSystemCall()函數(shù),這
31、函數(shù)里面會調(diào)用sysenter指令進入Ring0,然后由KiFastCallEntry()根據(jù)系統(tǒng)調(diào)用ID從KeServiceDescriptorTable或者KeServiceDescriptorTableShadow這兩種系統(tǒng)調(diào)用表中找到NtOpenProcess()調(diào)用之。NtOpenProcess()里面會根據(jù)要打開的進程ID還是進程名字調(diào)用PsLookupProcessByProcessId()這個函數(shù)得到這個進程對象EPROCESS的地址,最后調(diào)用ObOpenObjectByPointer()返回進程句柄。ObOpenObjectByPointer()函數(shù)大致工作如下:首先會增加這
32、個EPROCESS對象的引用計數(shù),然后構(gòu)造一個_HANDLE_TABLE_ENTRY結(jié)構(gòu),填入對象的地址,然后把它加進這個用戶進程的句柄表(HANDLE_TBALE)中,最后返回句柄(索引)。 Windows 切換進程空間一般而言,如果線程T屬于進程P,那么當這個線程在內(nèi)核中運行時的用戶空間應該就是進程P的用戶空間。它也沒有必要訪問到別的用戶進程空間去,可是Windows允許一些跨進程的操作,特別是跨用戶進程空間的操作。所以有時候就需要把當時的用戶空間切換到別的進程空間中去。Windows提供的函數(shù)是KeStackAttachProcess()和KiAttachProcess()。它的原理其實
33、就是改變CPU的CR3寄存器使之指向要切換進程的頁目錄表。因為CPU訪問進程用戶層空間地址都是通過CR3找頁目錄表,然后通過Windows內(nèi)存管理器把虛擬地址映射成物理地址才去訪問的,所以只要我們改變CR3寄存器就行了。Windows有很多這種跨進程的操作,例如調(diào)試DbgkpPostFakeProcessCreateMessages()函數(shù)會調(diào)用KeStackAttachProcess()這個函數(shù)切換進被調(diào)試進程的用戶層空間中,因為DbgkpPostFakeModuleMessages()這個函數(shù)會訪問被調(diào)試進程的進程環(huán)境塊(PEB),然后遍歷它的用戶層模塊鏈表。最后會調(diào)用KeUnstackD
34、etachProcess()這個函數(shù)回到OD調(diào)試器的進程空間來。 Windows調(diào)試系統(tǒng)原理Windows調(diào)試系統(tǒng)用戶模塊 Windows系統(tǒng)在用戶層提供了很多的調(diào)試API供用戶程序調(diào)用,它們分別在kernel32.dll和ntdll.dll里面。常見的API有DebugActiveProcess(),DebugActiveProcessStop(),DebugSetProcessKillOnExit(),WaitForDebugEvent(),ContinueDebugEvent()。n調(diào)試函數(shù)有DbgUiDebugActiveProcess(),DbgUiIssueRemoteBreakI
35、n(),DbgUiContinue()等等API函數(shù)。 OD調(diào)試器一般會枚舉當系統(tǒng)系統(tǒng)中的所有進程,如果我們要要調(diào)試哪個進程,它就會調(diào)用DebugActiveProcess()DbgUiConnectToDbg(),這個函數(shù)里面最終會調(diào)用ntdll.dll的ZwCreateDebugObject()建立一個調(diào)試對象用來接受調(diào)試事件信息,最終依次會進入NtCreateDebugObject()系統(tǒng)調(diào)用函數(shù)。接著它會調(diào)用ProcessIdToHandle(PID)打開進程,它里面會調(diào)用ZwOpenProcess()函數(shù)打開進程,如果打開進程成功,則返回進程句柄。DbgUiDebugActivePr
36、ocess()函數(shù)進行真正的附加調(diào)試。DbgUiDebugActiveProcess()函數(shù)首先會調(diào)用ZwDebugActiveProcess()函數(shù),這個函數(shù)會把這個被調(diào)試進程的線程事件和模塊事件信息插入在先前建立的調(diào)試對象中。然后會調(diào)用DbgUiIssueRemoteBreakin()函數(shù)在被調(diào)試的進程空間中建立一個遠程線程用于執(zhí)行int 3指令斷點,目的是為了中斷到調(diào)試器。之后OD調(diào)試器就會循環(huán)調(diào)用WaitForDebugEvent()和ContinueDebugEvent()等待調(diào)試事件,然后處理調(diào)試事件信息。Windows調(diào)試系統(tǒng)內(nèi)核模塊Windows系統(tǒng)在內(nèi)核層也有很多的系統(tǒng)函數(shù)用
37、來支持調(diào)試機制,比如有NtCreateDebugObject(),DbgkpPostFakeProcessCreateMessages(),DbgkpSetProcessDebugObject(),NtWaitForDebugEvent(),NtDebugContinue(),DbgkInitialize(),DbgkpSendApiMessage(),DbgkCreateThread(),DbgkMapViewOfSection()NtDebugActiveProcess()等等函數(shù)。DbgkInitialize()函數(shù)里面會調(diào)用ObCreateObjectType()函數(shù)建立一個調(diào)試對象類
38、型。NtCreateDebugObject()函數(shù)里面會調(diào)用ObCreateObject()建立一個調(diào)試對象,然后再調(diào)用ObInsertObject()函數(shù)把這個對象插進OD進程的句柄表中。NtDebugActiveProcess()函數(shù)里面首先會調(diào)用DbgkpPostFakeProcessCreateMessages()函數(shù),這個函數(shù)里面會依次調(diào)用DbgkpPostFakeThreadMessages()和DbgkpPostFakeModuleMessages()函數(shù)向調(diào)試對象發(fā)送線程和模塊事件信息。最后會調(diào)用DbgkpSetProcessDebugObject()這個函數(shù)把被調(diào)試進程的EP
39、ROCESS的DebugPort設置成NtCreateDebugObject()函數(shù)建立的調(diào)試對象。當建立線程時,Windows系統(tǒng)會調(diào)用DbgkCreateThread()這個函數(shù)向這個調(diào)試對象發(fā)送建立線程的調(diào)試事件;當加載DLL時,Windows系統(tǒng)會調(diào)用DbgkMapViewOfSection()這個函數(shù)向這個調(diào)試對象發(fā)送加載模塊的調(diào)試事件;當被調(diào)試進程執(zhí)行用戶層int 3指令時,Windows系統(tǒng)會調(diào)用DbgkForwardException()這個函數(shù)向這個調(diào)試對象發(fā)送異常調(diào)試事件。3系統(tǒng)需求分析存在的主要問題一般防調(diào)試的程序會對NtOpenProcess(),NtReadVirtu
40、alMemory(),NtWriteVirtualMemory(),NtDebugActiveProcess(),NtCreateDebugObject(),NtWaitForDebugEvent()這些函數(shù)進行HOOK的,不是SSDT HOOK這些函數(shù),就是Inline HOOK這些函數(shù)。當我們用OD調(diào)試器還是CE搜索器,要打開它的進程并對其進行讀寫內(nèi)存時,它都會禁止操作那進程,從而導致我們操作失敗。比如程序?qū)tOpenProcess()函數(shù)HOOK后,防止打開進程,OD調(diào)試器就看不到那進程,對NtDebugActiveProcess()函數(shù)HOOK后,OD調(diào)試器雖然能看到進程,但是不能調(diào)
41、試成功的。他們有可能會在內(nèi)核下建立系統(tǒng)內(nèi)核線程不停的檢測它們HOOK代碼的地方會不會被恢復。還有可能會檢測他們HOOK的代碼到底有沒有被調(diào)用。如果沒有被調(diào)用,則認為是我們在它前面跳過去了,這樣它們肯定就檢測出了異常,他們還有可能會在內(nèi)核下建立內(nèi)核線程不時的對其保護的進程的EPROCESS的DebugPort清0,讓我們的OD調(diào)試器收不到任何調(diào)試事件信息。解決方案基于以上問題,我是這么設計的,我們的應用層OD插件HOOK OD進程空間動態(tài)庫的KiFastSystemCall()函數(shù),使其跳到我們自己的HxKiFastSystemCall(),然后對OD進程調(diào)用的相應的API函數(shù)進行過濾處理,也就
42、是改變系統(tǒng)調(diào)用ID。然后在Windows系統(tǒng)內(nèi)核下加入我們自己的系統(tǒng)調(diào)用函數(shù)和調(diào)試驅(qū)動。當OD調(diào)用比較關鍵的函數(shù),就會進入我們自己的系統(tǒng)調(diào)用。所以對于別的驅(qū)動保護HOOK的關鍵函數(shù)就不起用了,對于一直清除EPROCESS的DebugPort的線程的檢測,我們自己在內(nèi)核下可以不操作要調(diào)試進程EPROCESS的Debugport。我們移到另一個結(jié)構(gòu)體中。這樣也就可以防止它一直對DebugPort調(diào)試端口清0。系統(tǒng)需求分析根據(jù)以上的分析,為了克服現(xiàn)行OD調(diào)試器存在的不足,得到新系統(tǒng)的功能如下:我們利用OD調(diào)試器插件庫,HOOK OD進程空間的ntdll.dll的KiFastSystemCall(),
43、它是一切用戶層API要進行系統(tǒng)調(diào)用的最后入口,然后當OD進程調(diào)用API函數(shù)時,只要這個API函數(shù)里會調(diào)用系統(tǒng)函數(shù)調(diào)用,它都會跳到我們自己的HxKiFastSystemCall()函數(shù)。在我們自己實現(xiàn)的HxKiFastSystemCall()函數(shù)中,對OD進程調(diào)用的API函數(shù)進行過濾處理,比如如果是調(diào)用OpenProcess()打開進程,ReadVirtualMemory()讀進程內(nèi)存,WriteVirtualMemory()寫進程內(nèi)存,DebugActiveProcess()附加進程,WaitForDebugEvent()等待調(diào)試事件等等關鍵函數(shù),我們會在這里改變它們的系統(tǒng)調(diào)用ID,然后自己調(diào)
44、用sysenter指令進入Ring0,sysenter指令是intel CPU公司專門設計的快速系統(tǒng)調(diào)用,它會改變EIP寄存器,使其指向KiFastCallEntry()函數(shù),因此在當前系統(tǒng)中,只要發(fā)生過系統(tǒng)調(diào)用,不管是哪個進程在要求調(diào)用系統(tǒng)調(diào)用,在Ring0中首先被執(zhí)行的是KiFastCallEntry()函數(shù),然后它會根據(jù)我們傳來的系統(tǒng)調(diào)用Id從KeServiceDescriptorTable或者KeServiceDescriptorTableShadow表中去取得相應的系統(tǒng)調(diào)用函數(shù)運行。由于我們內(nèi)核驅(qū)動里面用到的很多內(nèi)核函數(shù)很底層,MS提供的DDK中并沒有導出這些函數(shù)。比如這些函數(shù)有Nt
45、ReadVirtualMemory(),NtWriteVirtualMemory(),它們都要調(diào)用的MmCopyVirtualMemory()函數(shù),這個函數(shù)微軟提供的靜態(tài)庫文件就沒有導出,還有很多比如MiProtectVirtualMemory(),PsGetNextProcess(),ObDuplicateObject(),等等沒有導出。我們不能在內(nèi)核驅(qū)動中直接調(diào)用,我們可以采用暴力搜索內(nèi)存找特征碼然后得到當前系統(tǒng)這些函數(shù)的加載地址,然后加以調(diào)用。這種方法很費時而且通用性不好。我采用另一種方法,我們應用程序自己解析微軟提供給我們的PDB符號文件搜索得到這些未導出函數(shù)的地址,然后傳進內(nèi)核驅(qū)動這
46、些內(nèi)核函數(shù)的地址,我們內(nèi)核驅(qū)動才可以加以調(diào)用這些未導出的函數(shù)。我們要在Windows內(nèi)核下加入我們自己的系統(tǒng)調(diào)用表,Windows內(nèi)核下有兩種系統(tǒng)調(diào)用表,KeServiceDescriptorTable和KeServiceDescriptorTableShadow表。我們自己在非分頁內(nèi)存中分配一個服務表, 先拷貝KeServiceDescriptorTable和KeServiceDescriptorTableShadow兩個表,然后把我們要加上的系統(tǒng)調(diào)用函數(shù)地址加進去,然后寫進KeServiceDescriptorTable和KeServiceDescriptorTableShadow表中,下
47、次如果OD進程調(diào)用我們感興趣的系統(tǒng)調(diào)用的話,KiFastCallEntry()函數(shù)就會根據(jù)服務Id從這兩個表中找到我們的系統(tǒng)調(diào)用,然后調(diào)用之。我們自己的系統(tǒng)調(diào)用很多地方可以參考WRK。WRK是Windows Server 2003系統(tǒng)的內(nèi)核。跟XP還是有點區(qū)別的。對于很重要的內(nèi)核函數(shù)KeStackAttachProcess()和KiAttachProcess (),這兩個是Windows系統(tǒng)內(nèi)核切換到別的進程空間中的關鍵函數(shù)。由于有的游戲也有HOOK,我們要自己實現(xiàn)之用來跳過HOOK,功能基本已實現(xiàn)。有的保護驅(qū)動會在內(nèi)核下建立內(nèi)核線程一直對它要保護的進程的EPROCESS的DebugPort端
48、口一直清0,這樣會導致OD調(diào)試器收不到任何調(diào)試事件信息。我是這么做的,因為我們OD調(diào)試器調(diào)用的API與調(diào)試有關的系統(tǒng)內(nèi)核函數(shù)幾乎都是我們自己在內(nèi)核驅(qū)動中實現(xiàn)的函數(shù),所以打算把操作EPROCESS的DebugPort的代碼地方都改下。改成操作另一個結(jié)構(gòu)體,里面專門對應要調(diào)試的進程的EPROCESS進程環(huán)境塊和調(diào)試對象(DebugObject)。比如NtDebugActiveProcess-DbgkpSetProcessDebugObject()里面會對要調(diào)試進程的EPROCESS的DebugPort設置成NtCreateDebugObject()的調(diào)試對象。這里不們不把被調(diào)試進程的EPROCES
49、S的DebugPort設置成指向那調(diào)試對象,而是移到上面說的結(jié)構(gòu)中去。我們此時還要HOOK 一些常見的Windows內(nèi)核函數(shù),比如建立線程時,結(jié)束線程時,加載DLL時,怎么會把調(diào)試事件信息通知到我們建立的這種對應的結(jié)構(gòu)體中。我們要Hook 這些常見的函數(shù)像建立線程時的PspUserThreadStartup(),它里面會調(diào)用DbgkCreateThread()向被調(diào)試進程EPROCESS的DebugPort發(fā)消息,我們在這里要處理,還有就是PspExitThread(),NtMapViewOfSection()等等很多函數(shù)都要處理的。我們還要Hook Windows的內(nèi)核異常處理機制,比如我們
50、用OD調(diào)試器經(jīng)常F2下的斷點,都是int 3斷點,我們要這CPU 執(zhí)行Int 3這個指令時向相應的EPROCESS的DebugPort發(fā)送調(diào)試事件信息,我們就要HOOK Windows的異常處理函數(shù)。系統(tǒng)流程圖如下圖 3-3為整個系統(tǒng)整體流程圖:4系統(tǒng)概要設計 應用程序模塊當我們把我們寫的OD插件放入OD調(diào)試器目錄下的Plugin文件夾中后,OD調(diào)試器啟動時就會調(diào)用ODBG_Plugindata()這個回調(diào)函數(shù),我們在這里調(diào)用HxLoadKrnl()函數(shù)負責加載我們的內(nèi)核驅(qū)動,我們的插件在OD調(diào)試器插件菜單中加入了以下兩個菜單選項,BeginHook和CacelHook,當用戶點擊BeginH
51、ook后,會調(diào)用HxKrnl_Init()這個函數(shù),這個函數(shù)里面主要是調(diào)用DeviceIoControl()這個函數(shù)向我們的內(nèi)核驅(qū)動依次發(fā)送相關命令。先是發(fā)送HXIOCTL_INIT這個命令,要求我們的內(nèi)核驅(qū)動從Windows內(nèi)核下得到ntkrnlpa.exe,hal.dll內(nèi)核模塊的加載地址,然后返回給我們的OD應用層插件;接著發(fā)送HXIOCTL_GET_FNNUMBERLIST命令,會取得內(nèi)核國未導出函數(shù)的個數(shù),然后發(fā)送HXIOCTL_GET_FNLIST命令,會取得這些內(nèi)核未導出函數(shù)的名字,之后我們OD插件解析內(nèi)核PDB文件得到這些未導出函數(shù)的地址,然后再次向我們的驅(qū)動發(fā)送HXIOCTL
52、_SET_DRIVER命令,通知驅(qū)動開啟把這些函數(shù)地址設置到函數(shù)指針變量中。接著OD插件會發(fā)送HXIOCTL_BEGIN_ADDSERVICE命令,要求驅(qū)動在Windows系統(tǒng)內(nèi)核下加入我們自己的系統(tǒng)調(diào)用表。最后OD插件會調(diào)用Hook()函數(shù)HOOK OD進程空間ntdll.dll的KiFastSystemCall()函數(shù),之后當OD進程再次調(diào)用API時就會進入我們的函數(shù),我們HxKiFastSystemCall()函數(shù)里面會對其系統(tǒng)調(diào)用ID進行判斷,如果是我們感興趣的系統(tǒng)調(diào)用ID,我們在這里把它改變成我們在內(nèi)核添加的對應的系統(tǒng)調(diào)用ID,然后調(diào)用sysenter指令一樣的進入Ring0,Rin
53、g0的響應函數(shù)KiFastCallEntry()會根據(jù)我們傳進來的系統(tǒng)調(diào)用ID找到我們對應的系統(tǒng)調(diào)用然后調(diào)用之。 內(nèi)核驅(qū)動模塊 內(nèi)核驅(qū)動模塊有一部分是專門和我們的OD應用層插件通訊用的,當我們的OD插件調(diào)用DeviceIoControl()函數(shù)向我們驅(qū)動發(fā)送相關命令時,我們會在HxCtrl()這個函數(shù)中做相關處理,對于HXIOCTL_INIT命令,我們會調(diào)用HxGetKenelNameAndLoadAddr()這個函數(shù)遍歷系統(tǒng)當前所有加載的內(nèi)核列表中找到ntkrnlpa.exe和hal.dll,然后返回當前的加載地址,返回給我們的應用層OD插件,對于HXIOCTL_GET_FNNUMBERLI
54、ST命令,我們返回內(nèi)核未導出函數(shù)的個數(shù),對于HXIOCTL_GET_FNLIST命令,我們返回這些未導出函數(shù)的名字,對于HXIOCTL_SET_DRIVER命令,我們把OD插件得到的內(nèi)核未導出的函數(shù)地址設置到函數(shù)指針變量中來,對于HXIOCTL_BEGIN_ADDSERVICE命令,我們在Windows內(nèi)核下加入我們自己的系統(tǒng)調(diào)用表,對于HXIOCTL_FREE這個命令,我們做好一些卸載善后操作,因為OD插件通知我們的內(nèi)核驅(qū)動要退出了。內(nèi)核驅(qū)動還有一部分就是實現(xiàn)的這些系統(tǒng)調(diào)用函數(shù)和調(diào)試模塊。5系統(tǒng)詳細設計KiFastSystemCall()函數(shù)下面這是用Windbg看的KiFastSystem
55、Call函數(shù),如下,它只有四個字節(jié),一般的HOOK至少要5個字節(jié)以上。所以我們要采用另一種方式HOOK,在ntdll.dll里找到一片沒有用的內(nèi)存,正好KiFastSystemCall上面10個字節(jié)就沒有用到。所以我們可以在這10個字節(jié)里填入我們最終要跳轉(zhuǎn)到的地址,然后從KiFastSystemCall函數(shù)開頭處改寫代碼使其跳到KiFastSystemCall-10字節(jié)處就行了,具體的HOOK代碼和UnHook代碼如下:0:001 u KiFastSystemCallntdll!KiFastSystemCall:7c92e4f0 8bd4 mov edx,esp7c92e4f2 0f34 sy
56、senter BOOL HOOK()PCHAR fun;UCHAR HookCode5=0;UCHAR Hook2=0;fun = (PCHAR)GetProcAddress(GetModuleHandle(ntdll.dll),KiFastSystemCall);/得到KiFastSystemCall函數(shù)映射的地址if (fun!= NULL)DWORD lOldProtect;DWORD oldprotect;fun-=10;if(VirtualProtect(PVOID)(DWORD)fun),14,PAGE_EXECUTE_READWRITE,&lOldProtect)/改寫代碼段內(nèi)存
57、為可讀寫和執(zhí)行的權限,方便我們能改寫代碼段fun0=0 xE9;*(DWORD*)(fun+1)=(DWORD)HxKiFastSystemCall - (DWORD)fun-5);fun+=10;fun0=0 xEB;fun1=0 xF4;VirtualProtect(PVOID)(DWORD)fun-10),14,lOldProtect,&oldprotect);hookFunctionAddr=fun;return TRUE;return FALSE; BOOL UNHOOK()if (hookFunctionAddr!= NULL)DWORD lOldProtect;PCHAR fun
58、 = hookFunctionAddr;if(VirtualProtect(PVOID)(DWORD)fun),4,PAGE_EXECUTE_READWRITE,&lOldProtect)fun0=0 x8b;fun1=0 xd4;VirtualProtect(PVOID)(DWORD)fun),4,lOldProtect,NULL);return TRUE;實現(xiàn)HOOK的HxKiFastSystemCall(),改變系統(tǒng)調(diào)用的流程當OD調(diào)試器調(diào)用一般的API時比如OpenProcess(),ReadVirtualMemory(),WriteVirtualMemory()函數(shù)時,最終會進入Ki
59、FastSystemCall()這個函數(shù),從而進入我們自己實現(xiàn)的HxKiFastSystemCall()函數(shù),在進入HxKiFastSystemCall函數(shù)的環(huán)境下,eax指向調(diào)用此API對應的系統(tǒng)調(diào)用ID,esp指向堆棧,里面放著用戶層傳來的參數(shù)。在這里我們把此函數(shù)定義成_declspec( naked ),這么定義是為了防止編譯器額外的加上優(yōu)化和自動保護堆棧代碼。在此之前我們先要把esp壓棧,保存上下文。然后傳進系統(tǒng)調(diào)用ID,然后調(diào)用FilterServiceFun()函數(shù)對我們感興趣的服務ID進行過濾改變,然后eax返回的是我們改寫過的系統(tǒng)調(diào)用ID,之后再次調(diào)用sysenter真正的進行
60、系統(tǒng)調(diào)用,實現(xiàn)Ring3進入Ring0層,這里沒用sysenter指令,因為編譯器不識別它,我用的是二進制代碼,具體實現(xiàn)代碼如下:_declspec( naked ) HxKiFastSystemCall() _asm push esp; /保存堆棧 push eax; /服務Id call FilterServiceFun; pop esp; mov edx,esp _asm _emit 0 x0F /sysenter指令進入ring0 _asm _emit 0 x34extern DWORD MyServiceStartID;int WINAPI FilterServiceFun(DWOR
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 國際海運合同環(huán)境保護要求
- 戶外運動中心裝修合同
- 快速響應運輸合同模板設計
- 展覽館裝修大包合同樣本
- 文化中心裝修班組合作協(xié)議
- 滑雪場土石方合同樣本
- 旅游導游人才獵頭協(xié)議
- 冷藏乳制品分銷協(xié)議
- 會展中心別墅裝修合同樣本
- 影視制作公司裝修合同
- 生姜高產(chǎn)種植技術專題培訓課件
- 《社會主義市場經(jīng)濟理論(第三版)》第八章社會主義市場經(jīng)濟調(diào)控論
- 交流伺服系統(tǒng)常見故障及處理分解課件
- 水土保持單元工程質(zhì)量評定表
- 圣三國蜀漢傳攻略
- 2021屆高考英語887核心詞(打印、詞頻、出處、例句、背誦)
- 天津市鄉(xiāng)鎮(zhèn)衛(wèi)生院街道社區(qū)衛(wèi)生服務中心地址醫(yī)療機構(gòu)名單
- 公司機關管理類責任矩陣
- 山東省青島市各縣區(qū)鄉(xiāng)鎮(zhèn)行政村村莊村名居民村民委員會明細及行政區(qū)劃代碼
- 《鉆井液用磺甲基酚醛樹脂技術要求》
- 數(shù)學-九宮數(shù)獨100題(附答案)
評論
0/150
提交評論