版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、目 錄 TOC o 1-3 u 1緒論 PAGEREF _Toc262138811 h 2研究背景 PAGEREF _Toc262138812 h 2本文的主要研究內(nèi)容 PAGEREF _Toc262138813 h 32 Windows系統(tǒng)基礎(chǔ) 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進(jìn)程虛擬地址空間 PAGEREF _Toc262138819 h 5Windows系統(tǒng)調(diào)用 PAGEREF _Toc262138820 h 6Windows 句柄理解 PAGEREF _Toc262138821 h 7Windows 切換進(jìn)程空間 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)概要設(shè)計 PAGEREF _Toc262138831 h 13應(yīng)用程序模塊 PAGEREF _Toc262138832 h 13內(nèi)核驅(qū)動模塊 PAGEREF _Toc262138833 h 145系統(tǒng)詳細(xì)設(shè)計 PAGEREF _Toc262138834 h 15的KiFastSystemCall()
4、函數(shù) PAGEREF _Toc262138835 h 15實(shí)現(xiàn)HOOK的HxKiFastSystemCall(),改變系統(tǒng)調(diào)用的流程 PAGEREF _Toc262138836 h 16解析微軟提供的PDB文件得到未導(dǎo)出的內(nèi)核函數(shù)地址 PAGEREF _Toc262138837 h 18向Windows系統(tǒng)內(nèi)核中加入我們自己的系統(tǒng)服務(wù)表 PAGEREF _Toc262138838 h 24實(shí)現(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參考文獻(xiàn) PAGEREF _Toc262138844 h 36致 謝 PAGEREF _Toc262138845 h 37基于OD插件的內(nèi)核調(diào)試器的設(shè)計與實(shí)現(xiàn)摘要:隨著計算機(jī)互聯(lián)網(wǎng)技術(shù)的飛速發(fā)展,網(wǎng)絡(luò)游戲得到了很好的發(fā)展,它的保護(hù)也是日趨完善,幾種常見的保護(hù)有nProtect GameGuard(NP), hackshield(HS),讓OllyDbg調(diào)試器
6、(OD)不能調(diào)試,Cheat Engine(CE)不能搜索游戲內(nèi)存,讓人們沒法開始逆向它們,本文即在這種背景下為了滿足人們的工作需求而設(shè)計的。系統(tǒng)以VC 應(yīng)用程序編譯器和WIN DDK 驅(qū)動編譯器作為開發(fā)工具,以O(shè)D調(diào)試器提供的靜態(tài)庫,Window Research Kernel(WRK)的源碼為基礎(chǔ),HOOK KiFastSystemCall()函數(shù),通過我們自己在Windows內(nèi)核下加的系統(tǒng)服務(wù)表,使其當(dāng)OD調(diào)試器調(diào)用我們感興趣的系統(tǒng)調(diào)用時,跳到我們自己的系統(tǒng)調(diào)用,這樣使其成功調(diào)用,突破游戲的一般保護(hù),本文以C語言為編程語言,本系統(tǒng)是一個具有實(shí)際應(yīng)用意義的典型系統(tǒng)。關(guān)鍵詞:OD插件;NP;
7、HS;游戲保護(hù);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研究背景進(jìn)入二十一世紀(jì)以來,隨著社會的不斷進(jìn)步和互聯(lián)網(wǎng)產(chǎn)業(yè)技術(shù)的飛速發(fā)展,網(wǎng)絡(luò)游戲得到了空前的流行,研究它的人也越來越大眾化。因此,因為種種原因,一些游戲和商業(yè)程序就會防止OD調(diào)試器和CE數(shù)據(jù)搜索器搜索游戲的數(shù)據(jù)防止逆向工作人員逆向這們,一些防調(diào)試方法如下:1, 比如檢測系統(tǒng)當(dāng)前系統(tǒng)運(yùn)行的進(jìn)程看有沒有Od和Ce,查找窗口看有沒有它們,還有就是搜索Od和Ce的特征碼看有沒有它們,有就退出。2, 調(diào)用IsDebugPresent()函數(shù),檢測這個游戲進(jìn)程是不是被調(diào)試。3, Hook DbgUiRemoteBreakIn()函數(shù)防止運(yùn)行
11、int 3斷點(diǎn)中止游戲的程序運(yùn)行,這樣能防止OD調(diào)試器附加游戲進(jìn)程。4, 游戲故意產(chǎn)生異常,然后自己去處理它,如果有調(diào)試的話,異常一般會先給調(diào)試器,由調(diào)試器處理了,所以游戲就不會進(jìn)入它自己的異常處理,這樣它就檢測出了調(diào)試器。5, 還有就是nProtect GameGuard(NP), hackshield(HS),PerfectProtect.sys等等的保護(hù),一般它們都是差不多的,比如系統(tǒng)服務(wù)表(SSDT表)HOOK,內(nèi)核下Inline HOOK,一般HOOK NtOpenProcess()防止打開游戲進(jìn)程得到句柄,HOOK NtReadVirtualMemory(),NtWriteVirt
12、ualMemory()防止讀寫游戲進(jìn)程空間的內(nèi)存,還有就是HOOK NtDebugActiveProcess(),NtCreateDebugObject(),NtWaitForDebugEvent()等等一系列與調(diào)試有關(guān)的系統(tǒng)調(diào)用防止調(diào)試游戲,還有就是HOOK 每個CPU的中斷描述符表(IDT)表中的INT 1和INT 3斷點(diǎn),防止對游戲進(jìn)程下斷產(chǎn)生單步調(diào)試事件和異常調(diào)試事件,還有一種就是內(nèi)核下建立一個內(nèi)核線程一直對游戲的進(jìn)程控制塊(EPROCESS)結(jié)構(gòu)體的(調(diào)試端口)DebugPort一直清0,防止游戲被Od調(diào)試收到調(diào)試信息。綜上所述,第5種保護(hù)方法一般是現(xiàn)在最流行的保護(hù),有很多的人們在研
13、究它們的保護(hù),他們一般采用的方法是跳過這些函數(shù)的調(diào)用,比如對于SSDT HOOK,它們可以在KiFastCallEntry()函數(shù)里進(jìn)行處理,對于Inline HOOK,我們可以先HOOK SSDT進(jìn)入我們自己的系統(tǒng)調(diào)用,然后才調(diào)用真正的函數(shù),對于調(diào)試端口端口的內(nèi)核函數(shù),改變這些偏移,使其操作EPROCESS結(jié)構(gòu)中的其它沒有多大用的結(jié)構(gòu)成員,比如EPROCESS.time。這種方法針對一般的保護(hù)有效,但是對于特定的保護(hù),我們可以特別的處理,比如Tessafe.sys你可以把自己加入白名單等等處理方法,還有對于HS我們可以調(diào)用一個14號功能函數(shù)通知HS保護(hù)驅(qū)動退出等等許多的方法。本文的主要研究內(nèi)
14、容基于OD插件的內(nèi)核調(diào)試器系統(tǒng)主要是在OD調(diào)試器的基礎(chǔ)上編寫OD插件,HOOK OD進(jìn)程空間的的KiFastSystemCall()函數(shù),改變OD進(jìn)程調(diào)用一些關(guān)鍵系統(tǒng)函數(shù)的調(diào)用流程,使其進(jìn)入我們自己在內(nèi)核中的實(shí)現(xiàn)的系統(tǒng)調(diào)用,這樣能夠繞過一般的保護(hù)驅(qū)動的鉤子。本系統(tǒng)是主要分為四個主要的功能來實(shí)現(xiàn):1, 編寫OD應(yīng)用程序插件,利用OD調(diào)試器提供給我們的靜態(tài)庫和頭文件來編寫OD插件,在OD調(diào)試器上加個菜單選項用于控制OD調(diào)試器是不是啟動我們的這種程序機(jī)制。比如當(dāng)我們點(diǎn)BeginHook菜單時,我們的程序就開始工作,HOOK KiFastSystemCall()函數(shù),Windows提供給程序員的一般的
15、打開進(jìn)程OpenProcess(),讀進(jìn)程內(nèi)存ReadVirtualmemory(),寫進(jìn)程內(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)用。當(dāng)我們點(diǎn)CancelHook時,我們的程序就停止工作。2, 由于我們內(nèi)核驅(qū)動要調(diào)用的很多內(nèi)核函數(shù)是ntkrnelpa.exe內(nèi)核文件未導(dǎo)出的,所以我們要自己獲取內(nèi)核函數(shù)在當(dāng)前系統(tǒng)的地址,很多同學(xué)采用的是暴力搜索內(nèi)存然后匹配方法處理的,這種方法效率欠缺,并且由于
16、好多硬編碼,移值性很差。我是這么做的,在內(nèi)核驅(qū)動下,把這些未導(dǎo)出的函數(shù)申明為函數(shù)變量指針,然后用戶層程序(OD插件)調(diào)用DeviceIoControlFile()函數(shù)和驅(qū)動通信取得這些未導(dǎo)出的函數(shù)的名字,然后我們自己解析微軟提供給我們的符號文件(PDB文件),得到這個版本系統(tǒng)的未導(dǎo)出的函數(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)機(jī)制的實(shí)現(xiàn),只要我們集成進(jìn)我們的驅(qū)動里來了,以后游戲保護(hù)對這些調(diào)試機(jī)制的一切HOOK與檢測,我們可以不用去管它了,相當(dāng)于OD插件它們用的是我們自己集成的調(diào)試系統(tǒng)機(jī)制。還有內(nèi)核線程對EPROCESS結(jié)構(gòu)體的DebugPort清0,我們也可以跳過它。還有就是增加游戲常HOOK的幾個關(guān)鍵函數(shù),比如NtOpenProcess(),NtReadVirtualMemory(),NtWriteVirtualMemory()等等,我們自己在Windows內(nèi)核中實(shí)現(xiàn)它,下次OD調(diào)試器調(diào)用這些函數(shù)對游戲進(jìn)程操作時,都會進(jìn)入我們自己的這些系統(tǒng)調(diào)用,到時想實(shí)現(xiàn)什么功能就實(shí)現(xiàn)什么功
18、能。4, Windows系統(tǒng)內(nèi)核下有兩種系統(tǒng)服務(wù)表KeServiceDescriptorTable和KeServiceDescriptorTableShadow,對于圖形界面(GUI)線程,它引用的是KeServiceDescriptorTableShadow這個系統(tǒng)服務(wù)表,非GUI線程引用的是KeServiceDescriptorTable系統(tǒng)服務(wù)表。對于微軟提供的大多數(shù)API,內(nèi)核下都有專門對應(yīng)的系統(tǒng)調(diào)用,比如當(dāng)我們調(diào)用OpenProcess() API函數(shù)時,最終會調(diào)用系統(tǒng)調(diào)用NtOpenProcess()。每一個系統(tǒng)調(diào)用ID,在Windows內(nèi)核下都會對應(yīng)一個系統(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)服務(wù)表的后面加上我們自己的系統(tǒng)調(diào)用函數(shù),對應(yīng)相應(yīng)的系統(tǒng)調(diào)用ID,這樣當(dāng)OD調(diào)試器調(diào)用我們感興趣的系統(tǒng)調(diào)用時,我們可以改變系統(tǒng)調(diào)用ID,這樣就可以進(jìn)入我們自己實(shí)現(xiàn)的系統(tǒng)調(diào)用函數(shù)。2 Windows系統(tǒng)基礎(chǔ) OD插件知識 OD插件簡介 OllyDbg 簡稱(OD) 是一款優(yōu)秀的用戶態(tài)調(diào)試工具。它不僅擁有強(qiáng)大的反匯編能力和動態(tài)分析力,還具有良好的擴(kuò)展結(jié)構(gòu),允許用戶自行開發(fā)插件完成特定的工作。OD插件也可以有自己的窗口邏輯和功能函數(shù)。事實(shí)
20、上,我們可以將它看成這樣一個Windows 程序,它擁有自己的消息循環(huán)和窗口過程,但它的啟動是由OllyDbg 發(fā)起的,具體功能的實(shí)現(xiàn)也通過調(diào)用OllyDbg 提供的函數(shù)來實(shí)現(xiàn)的。它的啟動過程如下:在OllyDbg 的啟動過程中,有一步是檢查插件路徑下是否存在DLL 文件。如果存在,逐一進(jìn)行如下掃描:1, 加載該DLL 文件,找到其入口點(diǎn)。2, 通過回調(diào)函數(shù),獲取插件名稱、版本等信息。3, 通過回調(diào)函數(shù),對插件進(jìn)行初始化,包括申請資源、恢復(fù)全局參數(shù)等。如果某個DLL 文件無法順利執(zhí)行這三步,OllyDbg 的啟動將失敗、報錯并退出。OllyDbg 啟動以后,會一直維護(hù)插件的隊列,在特定時間向該
21、隊列發(fā)送消息,或者直接調(diào)用插件中定義的函數(shù),用戶通過插件菜單或快捷鍵主動執(zhí)行插件某功能。最后,當(dāng)OllyDbg 被關(guān)閉時,還會調(diào)用插件中的回調(diào)函數(shù),釋放插件申請到的資源,并將需要保存的參數(shù)、配置和附加信息分別予以保存。.2 如何編寫OD插件 新建立一個VC 6.0的工程,把頭文件和靜態(tài)庫文件加進(jìn)工程里面來,還有在工程里加入/J選項,使使char 默認(rèn)為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ù)中傳遞我們插件的名字進(jìn)去;在ODBG_Plugininit()中把OD窗口句柄保存起來;我們還實(shí)現(xiàn)了幾個回調(diào)函數(shù),ODBG_Pluginmenu(),ODBG_Pluginaction(),ODBG_Plugindestroy()函數(shù)。這些函數(shù)用于在OD插件菜單中加入菜單選項和我們的響應(yīng)函數(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進(jìn)程虛擬地址空間如上圖4-1-1,在Windows系統(tǒng)中,每一個進(jìn)程都有4GB的虛擬地址空間。02GB是Windows進(jìn)程的用戶空間,2GB到4GB是Windows的內(nèi)核空間。物理地址擴(kuò)展(PAE)除外,這時,每個進(jìn)程的用戶空間為03GB。每個進(jìn)程有4GB的虛擬地址空間,并不是指它真正有4GB的物理內(nèi)存,而是指每個進(jìn)程都有其頁目錄表和頁表,通過它會把每個進(jìn)程映射成4GB虛擬內(nèi)存空間。進(jìn)程用戶空間0-2GB的映射,頁表一般會把進(jìn)程的這段虛擬內(nèi)存空間映射到不同的物理內(nèi)存中。但是有例外,就是Windows常見的DLL和可執(zhí)行映象文件
24、,比如kernel32.dll,ntdll.dll和.exe文件運(yùn)行時的情況。它們有寫入時復(fù)制(Copy On Write)機(jī)制,在沒有改寫這些代碼前,它們在物理內(nèi)存中只有一份內(nèi)存,所有的進(jìn)程都會根據(jù)頁目錄和頁表映射到這份物理內(nèi)存。但是當(dāng)有一個進(jìn)程改變這些DLL的內(nèi)容時,寫入時復(fù)制就發(fā)生了。Windows這時會把這些內(nèi)容在物理內(nèi)存中拷貝一份,改變這個進(jìn)程的頁目錄和頁表,使之指向這份拷貝的物理內(nèi)存,對其它的進(jìn)程沒有任何影響,所以這就是用戶層HOOK 系統(tǒng)DLL時,只對本進(jìn)程有效,對其它進(jìn)程無效的原因。所以當(dāng)我們HOOK 一個進(jìn)程的ntdll.dll的KiFastSystemCall()時,它只會
25、對我們HOOK的這個進(jìn)程的KiFastSystemCall()函數(shù)起作用。對別的進(jìn)程沒有影響。 進(jìn)程內(nèi)核空間24GB空間的映射,通常系統(tǒng)中每個進(jìn)程的這段虛擬內(nèi)存空間會根據(jù)頁目錄表和頁表映射到相同的物理內(nèi)存中。比如當(dāng)我們改寫一處內(nèi)存,此時對每個進(jìn)程都會有效的,對整個系統(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)進(jìn)行系統(tǒng)調(diào)用的全過程描述:比如當(dāng)我們用戶層進(jìn)程調(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指令進(jìn)入ring0,在Windows內(nèi)核下首先執(zhí)行的是KiFastCallEntry()函數(shù),它會根據(jù)系統(tǒng)調(diào)用ID分別從KeServiceDescriptorTable或者KeServiceDescriptorTableShadow這兩種系統(tǒng)調(diào)用表中取得相應(yīng)的系統(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)用的。當(dāng)這個系統(tǒng)調(diào)用成功返回后,KiFastCallEntry()函數(shù)會調(diào)用sysexit指令退出本次的系統(tǒng)調(diào)用,然后返回到用戶進(jìn)程空間,依次返回到調(diào)用用戶API的地方。 Windows 句柄理解句柄是Windows系統(tǒng)的特性。你可以簡單理解為通過它你就可以訪問相應(yīng)的內(nèi)核對象。其實(shí)Windows是這么設(shè)計的,每個進(jìn)程的EPROCESS結(jié)構(gòu)體中都有個ObjectTable 成員指向進(jìn)程句柄表(HANDLE_TABLE),里面每一項都是HANDLE
28、_TABLE_ENTRY句柄表項。里面放著相應(yīng)對象的地址,句柄只是這些表項的索引。還有一點(diǎn)值的注意的是句柄是進(jìn)程相關(guān)的。你在本進(jìn)程打開的進(jìn)程句柄,在別的進(jìn)程當(dāng)中不能引用它的。它們的結(jié)構(gòu)體定義如下:lkd dt _HANDLE_TABLEnt!_HANDLE_TABLE +0 x000 TableCode : Uint4B /指向_HANDLE_TABLE_ENTRY數(shù)組 +0 x004 QuotaProcess : Ptr32 _EPROCESS /這個句柄表屬于哪個進(jìn)程 +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比如當(dāng)我們在用戶進(jìn)程調(diào)用OpenProcess() 打開進(jìn)程時,它先會調(diào)ntdll.dll的ZwOpenProcess(),接著會傳遞NtOpenProcess()的系統(tǒng)調(diào)用ID,調(diào)用KiFastSystemCall()函數(shù),這
31、函數(shù)里面會調(diào)用sysenter指令進(jìn)入Ring0,然后由KiFastCallEntry()根據(jù)系統(tǒng)調(diào)用ID從KeServiceDescriptorTable或者KeServiceDescriptorTableShadow這兩種系統(tǒng)調(diào)用表中找到NtOpenProcess()調(diào)用之。NtOpenProcess()里面會根據(jù)要打開的進(jìn)程ID還是進(jìn)程名字調(diào)用PsLookupProcessByProcessId()這個函數(shù)得到這個進(jìn)程對象EPROCESS的地址,最后調(diào)用ObOpenObjectByPointer()返回進(jìn)程句柄。ObOpenObjectByPointer()函數(shù)大致工作如下:首先會增加這
32、個EPROCESS對象的引用計數(shù),然后構(gòu)造一個_HANDLE_TABLE_ENTRY結(jié)構(gòu),填入對象的地址,然后把它加進(jìn)這個用戶進(jìn)程的句柄表(HANDLE_TBALE)中,最后返回句柄(索引)。 Windows 切換進(jìn)程空間一般而言,如果線程T屬于進(jìn)程P,那么當(dāng)這個線程在內(nèi)核中運(yùn)行時的用戶空間應(yīng)該就是進(jìn)程P的用戶空間。它也沒有必要訪問到別的用戶進(jìn)程空間去,可是Windows允許一些跨進(jìn)程的操作,特別是跨用戶進(jìn)程空間的操作。所以有時候就需要把當(dāng)時的用戶空間切換到別的進(jìn)程空間中去。Windows提供的函數(shù)是KeStackAttachProcess()和KiAttachProcess()。它的原理其實(shí)
33、就是改變CPU的CR3寄存器使之指向要切換進(jìn)程的頁目錄表。因為CPU訪問進(jìn)程用戶層空間地址都是通過CR3找頁目錄表,然后通過Windows內(nèi)存管理器把虛擬地址映射成物理地址才去訪問的,所以只要我們改變CR3寄存器就行了。Windows有很多這種跨進(jìn)程的操作,例如調(diào)試DbgkpPostFakeProcessCreateMessages()函數(shù)會調(diào)用KeStackAttachProcess()這個函數(shù)切換進(jìn)被調(diào)試進(jìn)程的用戶層空間中,因為DbgkpPostFakeModuleMessages()這個函數(shù)會訪問被調(diào)試進(jìn)程的進(jìn)程環(huán)境塊(PEB),然后遍歷它的用戶層模塊鏈表。最后會調(diào)用KeUnstackD
34、etachProcess()這個函數(shù)回到OD調(diào)試器的進(jìn)程空間來。 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)試器一般會枚舉當(dāng)系統(tǒng)系統(tǒng)中的所有進(jìn)程,如果我們要要調(diào)試哪個進(jìn)程,它就會調(diào)用DebugActiveProcess()DbgUiConnectToDbg(),這個函數(shù)里面最終會調(diào)用ntdll.dll的ZwCreateDebugObject()建立一個調(diào)試對象用來接受調(diào)試事件信息,最終依次會進(jìn)入NtCreateDebugObject()系統(tǒng)調(diào)用函數(shù)。接著它會調(diào)用ProcessIdToHandle(PID)打開進(jìn)程,它里面會調(diào)用ZwOpenProcess()函數(shù)打開進(jìn)程,如果打開進(jìn)程成功,則返回進(jìn)程句柄。DbgUiDebugActivePr
36、ocess()函數(shù)進(jìn)行真正的附加調(diào)試。DbgUiDebugActiveProcess()函數(shù)首先會調(diào)用ZwDebugActiveProcess()函數(shù),這個函數(shù)會把這個被調(diào)試進(jìn)程的線程事件和模塊事件信息插入在先前建立的調(diào)試對象中。然后會調(diào)用DbgUiIssueRemoteBreakin()函數(shù)在被調(diào)試的進(jìn)程空間中建立一個遠(yuǎn)程線程用于執(zhí)行int 3指令斷點(diǎn),目的是為了中斷到調(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)試機(jī)制,比如有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ù)把這個對象插進(jìn)OD進(jìn)程的句柄表中。NtDebugActiveProcess()函數(shù)里面首先會調(diào)用DbgkpPostFakeProcessCreateMessages()函數(shù),這個函數(shù)里面會依次調(diào)用DbgkpPostFakeThreadMessages()和DbgkpPostFakeModuleMessages()函數(shù)向調(diào)試對象發(fā)送線程和模塊事件信息。最后會調(diào)用DbgkpSetProcessDebugObject()這個函數(shù)把被調(diào)試進(jìn)程的EP
39、ROCESS的DebugPort設(shè)置成NtCreateDebugObject()函數(shù)建立的調(diào)試對象。當(dāng)建立線程時,Windows系統(tǒng)會調(diào)用DbgkCreateThread()這個函數(shù)向這個調(diào)試對象發(fā)送建立線程的調(diào)試事件;當(dāng)加載DLL時,Windows系統(tǒng)會調(diào)用DbgkMapViewOfSection()這個函數(shù)向這個調(diào)試對象發(fā)送加載模塊的調(diào)試事件;當(dāng)被調(diào)試進(jìn)程執(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ù)進(jìn)行HOOK的,不是SSDT HOOK這些函數(shù),就是Inline HOOK這些函數(shù)。當(dāng)我們用OD調(diào)試器還是CE搜索器,要打開它的進(jìn)程并對其進(jìn)行讀寫內(nèi)存時,它都會禁止操作那進(jìn)程,從而導(dǎo)致我們操作失敗。比如程序?qū)tOpenProcess()函數(shù)HOOK后,防止打開進(jìn)程,OD調(diào)試器就看不到那進(jìn)程,對NtDebugActiveProcess()函數(shù)HOOK后,OD調(diào)試器雖然能看到進(jìn)程,但是不能調(diào)
41、試成功的。他們有可能會在內(nèi)核下建立系統(tǒng)內(nèi)核線程不停的檢測它們HOOK代碼的地方會不會被恢復(fù)。還有可能會檢測他們HOOK的代碼到底有沒有被調(diào)用。如果沒有被調(diào)用,則認(rèn)為是我們在它前面跳過去了,這樣它們肯定就檢測出了異常,他們還有可能會在內(nèi)核下建立內(nèi)核線程不時的對其保護(hù)的進(jìn)程的EPROCESS的DebugPort清0,讓我們的OD調(diào)試器收不到任何調(diào)試事件信息。解決方案基于以上問題,我是這么設(shè)計的,我們的應(yīng)用層OD插件HOOK OD進(jìn)程空間動態(tài)庫的KiFastSystemCall()函數(shù),使其跳到我們自己的HxKiFastSystemCall(),然后對OD進(jìn)程調(diào)用的相應(yīng)的API函數(shù)進(jìn)行過濾處理,也就
42、是改變系統(tǒng)調(diào)用ID。然后在Windows系統(tǒng)內(nèi)核下加入我們自己的系統(tǒng)調(diào)用函數(shù)和調(diào)試驅(qū)動。當(dāng)OD調(diào)用比較關(guān)鍵的函數(shù),就會進(jìn)入我們自己的系統(tǒng)調(diào)用。所以對于別的驅(qū)動保護(hù)HOOK的關(guān)鍵函數(shù)就不起用了,對于一直清除EPROCESS的DebugPort的線程的檢測,我們自己在內(nèi)核下可以不操作要調(diào)試進(jìn)程EPROCESS的Debugport。我們移到另一個結(jié)構(gòu)體中。這樣也就可以防止它一直對DebugPort調(diào)試端口清0。系統(tǒng)需求分析根據(jù)以上的分析,為了克服現(xiàn)行OD調(diào)試器存在的不足,得到新系統(tǒng)的功能如下:我們利用OD調(diào)試器插件庫,HOOK OD進(jìn)程空間的ntdll.dll的KiFastSystemCall(),
43、它是一切用戶層API要進(jìn)行系統(tǒng)調(diào)用的最后入口,然后當(dāng)OD進(jìn)程調(diào)用API函數(shù)時,只要這個API函數(shù)里會調(diào)用系統(tǒng)函數(shù)調(diào)用,它都會跳到我們自己的HxKiFastSystemCall()函數(shù)。在我們自己實(shí)現(xiàn)的HxKiFastSystemCall()函數(shù)中,對OD進(jìn)程調(diào)用的API函數(shù)進(jìn)行過濾處理,比如如果是調(diào)用OpenProcess()打開進(jìn)程,ReadVirtualMemory()讀進(jìn)程內(nèi)存,WriteVirtualMemory()寫進(jìn)程內(nèi)存,DebugActiveProcess()附加進(jìn)程,WaitForDebugEvent()等待調(diào)試事件等等關(guān)鍵函數(shù),我們會在這里改變它們的系統(tǒng)調(diào)用ID,然后自己調(diào)
44、用sysenter指令進(jìn)入Ring0,sysenter指令是intel CPU公司專門設(shè)計的快速系統(tǒng)調(diào)用,它會改變EIP寄存器,使其指向KiFastCallEntry()函數(shù),因此在當(dāng)前系統(tǒng)中,只要發(fā)生過系統(tǒng)調(diào)用,不管是哪個進(jìn)程在要求調(diào)用系統(tǒng)調(diào)用,在Ring0中首先被執(zhí)行的是KiFastCallEntry()函數(shù),然后它會根據(jù)我們傳來的系統(tǒng)調(diào)用Id從KeServiceDescriptorTable或者KeServiceDescriptorTableShadow表中去取得相應(yīng)的系統(tǒng)調(diào)用函數(shù)運(yùn)行。由于我們內(nèi)核驅(qū)動里面用到的很多內(nèi)核函數(shù)很底層,MS提供的DDK中并沒有導(dǎo)出這些函數(shù)。比如這些函數(shù)有Nt
45、ReadVirtualMemory(),NtWriteVirtualMemory(),它們都要調(diào)用的MmCopyVirtualMemory()函數(shù),這個函數(shù)微軟提供的靜態(tài)庫文件就沒有導(dǎo)出,還有很多比如MiProtectVirtualMemory(),PsGetNextProcess(),ObDuplicateObject(),等等沒有導(dǎo)出。我們不能在內(nèi)核驅(qū)動中直接調(diào)用,我們可以采用暴力搜索內(nèi)存找特征碼然后得到當(dāng)前系統(tǒng)這些函數(shù)的加載地址,然后加以調(diào)用。這種方法很費(fèi)時而且通用性不好。我采用另一種方法,我們應(yīng)用程序自己解析微軟提供給我們的PDB符號文件搜索得到這些未導(dǎo)出函數(shù)的地址,然后傳進(jìn)內(nèi)核驅(qū)動這
46、些內(nèi)核函數(shù)的地址,我們內(nèi)核驅(qū)動才可以加以調(diào)用這些未導(dǎo)出的函數(shù)。我們要在Windows內(nèi)核下加入我們自己的系統(tǒng)調(diào)用表,Windows內(nèi)核下有兩種系統(tǒng)調(diào)用表,KeServiceDescriptorTable和KeServiceDescriptorTableShadow表。我們自己在非分頁內(nèi)存中分配一個服務(wù)表, 先拷貝KeServiceDescriptorTable和KeServiceDescriptorTableShadow兩個表,然后把我們要加上的系統(tǒng)調(diào)用函數(shù)地址加進(jìn)去,然后寫進(jìn)KeServiceDescriptorTable和KeServiceDescriptorTableShadow表中,下
47、次如果OD進(jìn)程調(diào)用我們感興趣的系統(tǒng)調(diào)用的話,KiFastCallEntry()函數(shù)就會根據(jù)服務(wù)Id從這兩個表中找到我們的系統(tǒng)調(diào)用,然后調(diào)用之。我們自己的系統(tǒng)調(diào)用很多地方可以參考WRK。WRK是Windows Server 2003系統(tǒng)的內(nèi)核。跟XP還是有點(diǎn)區(qū)別的。對于很重要的內(nèi)核函數(shù)KeStackAttachProcess()和KiAttachProcess (),這兩個是Windows系統(tǒng)內(nèi)核切換到別的進(jìn)程空間中的關(guān)鍵函數(shù)。由于有的游戲也有HOOK,我們要自己實(shí)現(xiàn)之用來跳過HOOK,功能基本已實(shí)現(xiàn)。有的保護(hù)驅(qū)動會在內(nèi)核下建立內(nèi)核線程一直對它要保護(hù)的進(jìn)程的EPROCESS的DebugPort端
48、口一直清0,這樣會導(dǎo)致OD調(diào)試器收不到任何調(diào)試事件信息。我是這么做的,因為我們OD調(diào)試器調(diào)用的API與調(diào)試有關(guān)的系統(tǒng)內(nèi)核函數(shù)幾乎都是我們自己在內(nèi)核驅(qū)動中實(shí)現(xiàn)的函數(shù),所以打算把操作EPROCESS的DebugPort的代碼地方都改下。改成操作另一個結(jié)構(gòu)體,里面專門對應(yīng)要調(diào)試的進(jìn)程的EPROCESS進(jìn)程環(huán)境塊和調(diào)試對象(DebugObject)。比如NtDebugActiveProcess-DbgkpSetProcessDebugObject()里面會對要調(diào)試進(jìn)程的EPROCESS的DebugPort設(shè)置成NtCreateDebugObject()的調(diào)試對象。這里不們不把被調(diào)試進(jìn)程的EPROCES
49、S的DebugPort設(shè)置成指向那調(diào)試對象,而是移到上面說的結(jié)構(gòu)中去。我們此時還要HOOK 一些常見的Windows內(nèi)核函數(shù),比如建立線程時,結(jié)束線程時,加載DLL時,怎么會把調(diào)試事件信息通知到我們建立的這種對應(yīng)的結(jié)構(gòu)體中。我們要Hook 這些常見的函數(shù)像建立線程時的PspUserThreadStartup(),它里面會調(diào)用DbgkCreateThread()向被調(diào)試進(jìn)程EPROCESS的DebugPort發(fā)消息,我們在這里要處理,還有就是PspExitThread(),NtMapViewOfSection()等等很多函數(shù)都要處理的。我們還要Hook Windows的內(nèi)核異常處理機(jī)制,比如我們
50、用OD調(diào)試器經(jīng)常F2下的斷點(diǎn),都是int 3斷點(diǎn),我們要這CPU 執(zhí)行Int 3這個指令時向相應(yīng)的EPROCESS的DebugPort發(fā)送調(diào)試事件信息,我們就要HOOK Windows的異常處理函數(shù)。系統(tǒng)流程圖如下圖 3-3為整個系統(tǒng)整體流程圖:4系統(tǒng)概要設(shè)計 應(yīng)用程序模塊當(dāng)我們把我們寫的OD插件放入OD調(diào)試器目錄下的Plugin文件夾中后,OD調(diào)試器啟動時就會調(diào)用ODBG_Plugindata()這個回調(diào)函數(shù),我們在這里調(diào)用HxLoadKrnl()函數(shù)負(fù)責(zé)加載我們的內(nèi)核驅(qū)動,我們的插件在OD調(diào)試器插件菜單中加入了以下兩個菜單選項,BeginHook和CacelHook,當(dāng)用戶點(diǎn)擊BeginH
51、ook后,會調(diào)用HxKrnl_Init()這個函數(shù),這個函數(shù)里面主要是調(diào)用DeviceIoControl()這個函數(shù)向我們的內(nèi)核驅(qū)動依次發(fā)送相關(guān)命令。先是發(fā)送HXIOCTL_INIT這個命令,要求我們的內(nèi)核驅(qū)動從Windows內(nèi)核下得到ntkrnlpa.exe,hal.dll內(nèi)核模塊的加載地址,然后返回給我們的OD應(yīng)用層插件;接著發(fā)送HXIOCTL_GET_FNNUMBERLIST命令,會取得內(nèi)核國未導(dǎo)出函數(shù)的個數(shù),然后發(fā)送HXIOCTL_GET_FNLIST命令,會取得這些內(nèi)核未導(dǎo)出函數(shù)的名字,之后我們OD插件解析內(nèi)核PDB文件得到這些未導(dǎo)出函數(shù)的地址,然后再次向我們的驅(qū)動發(fā)送HXIOCTL
52、_SET_DRIVER命令,通知驅(qū)動開啟把這些函數(shù)地址設(shè)置到函數(shù)指針變量中。接著OD插件會發(fā)送HXIOCTL_BEGIN_ADDSERVICE命令,要求驅(qū)動在Windows系統(tǒng)內(nèi)核下加入我們自己的系統(tǒng)調(diào)用表。最后OD插件會調(diào)用Hook()函數(shù)HOOK OD進(jìn)程空間ntdll.dll的KiFastSystemCall()函數(shù),之后當(dāng)OD進(jìn)程再次調(diào)用API時就會進(jìn)入我們的函數(shù),我們HxKiFastSystemCall()函數(shù)里面會對其系統(tǒng)調(diào)用ID進(jìn)行判斷,如果是我們感興趣的系統(tǒng)調(diào)用ID,我們在這里把它改變成我們在內(nèi)核添加的對應(yīng)的系統(tǒng)調(diào)用ID,然后調(diào)用sysenter指令一樣的進(jìn)入Ring0,Rin
53、g0的響應(yīng)函數(shù)KiFastCallEntry()會根據(jù)我們傳進(jìn)來的系統(tǒng)調(diào)用ID找到我們對應(yīng)的系統(tǒng)調(diào)用然后調(diào)用之。 內(nèi)核驅(qū)動模塊 內(nèi)核驅(qū)動模塊有一部分是專門和我們的OD應(yīng)用層插件通訊用的,當(dāng)我們的OD插件調(diào)用DeviceIoControl()函數(shù)向我們驅(qū)動發(fā)送相關(guān)命令時,我們會在HxCtrl()這個函數(shù)中做相關(guān)處理,對于HXIOCTL_INIT命令,我們會調(diào)用HxGetKenelNameAndLoadAddr()這個函數(shù)遍歷系統(tǒng)當(dāng)前所有加載的內(nèi)核列表中找到ntkrnlpa.exe和hal.dll,然后返回當(dāng)前的加載地址,返回給我們的應(yīng)用層OD插件,對于HXIOCTL_GET_FNNUMBERLI
54、ST命令,我們返回內(nèi)核未導(dǎo)出函數(shù)的個數(shù),對于HXIOCTL_GET_FNLIST命令,我們返回這些未導(dǎo)出函數(shù)的名字,對于HXIOCTL_SET_DRIVER命令,我們把OD插件得到的內(nèi)核未導(dǎo)出的函數(shù)地址設(shè)置到函數(shù)指針變量中來,對于HXIOCTL_BEGIN_ADDSERVICE命令,我們在Windows內(nèi)核下加入我們自己的系統(tǒng)調(diào)用表,對于HXIOCTL_FREE這個命令,我們做好一些卸載善后操作,因為OD插件通知我們的內(nèi)核驅(qū)動要退出了。內(nèi)核驅(qū)動還有一部分就是實(shí)現(xiàn)的這些系統(tǒng)調(diào)用函數(shù)和調(diào)試模塊。5系統(tǒng)詳細(xì)設(shè)計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í)行的權(quán)限,方便我們能改寫代碼段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;實(shí)現(xiàn)HOOK的HxKiFastSystemCall(),改變系統(tǒng)調(diào)用的流程當(dāng)OD調(diào)試器調(diào)用一般的API時比如OpenProcess(),ReadVirtualMemory(),WriteVirtualMemory()函數(shù)時,最終會進(jìn)入Ki
59、FastSystemCall()這個函數(shù),從而進(jìn)入我們自己實(shí)現(xiàn)的HxKiFastSystemCall()函數(shù),在進(jìn)入HxKiFastSystemCall函數(shù)的環(huán)境下,eax指向調(diào)用此API對應(yīng)的系統(tǒng)調(diào)用ID,esp指向堆棧,里面放著用戶層傳來的參數(shù)。在這里我們把此函數(shù)定義成_declspec( naked ),這么定義是為了防止編譯器額外的加上優(yōu)化和自動保護(hù)堆棧代碼。在此之前我們先要把esp壓棧,保存上下文。然后傳進(jìn)系統(tǒng)調(diào)用ID,然后調(diào)用FilterServiceFun()函數(shù)對我們感興趣的服務(wù)ID進(jìn)行過濾改變,然后eax返回的是我們改寫過的系統(tǒng)調(diào)用ID,之后再次調(diào)用sysenter真正的進(jìn)行
60、系統(tǒng)調(diào)用,實(shí)現(xiàn)Ring3進(jìn)入Ring0層,這里沒用sysenter指令,因為編譯器不識別它,我用的是二進(jìn)制代碼,具體實(shí)現(xiàn)代碼如下:_declspec( naked ) HxKiFastSystemCall() _asm push esp; /保存堆棧 push eax; /服務(wù)Id call FilterServiceFun; pop esp; mov edx,esp _asm _emit 0 x0F /sysenter指令進(jìn)入ring0 _asm _emit 0 x34extern DWORD MyServiceStartID;int WINAPI FilterServiceFun(DWOR
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度金融創(chuàng)新企業(yè)股權(quán)轉(zhuǎn)讓中介協(xié)議3篇
- 二零二五年特種動物養(yǎng)殖合作開發(fā)協(xié)議書3篇
- 《隱函數(shù)存在定理》課件
- 二零二五年度藝術(shù)品投資合作框架協(xié)議3篇
- 2025新版汽車租賃合同范本下載
- 協(xié)議存款合同書范本
- 2025深圳大山地木工合同
- 借款擔(dān)保協(xié)議范本
- 年度飲料加工機(jī)械競爭策略分析報告
- 二零二五年度留守兒童社會實(shí)踐參與合同3篇
- 英語名著閱讀老人與海教學(xué)課件(the-old-man-and-the-sea-)
- 學(xué)校食品安全知識培訓(xùn)課件
- 全國醫(yī)學(xué)博士英語統(tǒng)一考試詞匯表(10000詞全) - 打印版
- 最新《會計職業(yè)道德》課件
- DB64∕T 1776-2021 水土保持生態(tài)監(jiān)測站點(diǎn)建設(shè)與監(jiān)測技術(shù)規(guī)范
- ?中醫(yī)院醫(yī)院等級復(fù)評實(shí)施方案
- 數(shù)學(xué)-九宮數(shù)獨(dú)100題(附答案)
- 理正深基坑之鋼板樁受力計算
- 學(xué)校年級組管理經(jīng)驗
- 10KV高壓環(huán)網(wǎng)柜(交接)試驗
- 未來水電工程建設(shè)抽水蓄能電站BIM項目解決方案
評論
0/150
提交評論