费尔个人防火墙采用两种封包过滤技术
費爾個人防火墻采用兩種封包過濾技術(shù) [轉(zhuǎn)原作者:FLASHSKY?
EMAIL:flashsky@xfocus.org
?
????? 由于互聯(lián)網(wǎng)發(fā)展的歷史原因, TCP/IP 協(xié)議及 HTTP 、 FTP 等基于 TCP/IP 協(xié)議的各種應(yīng)用層協(xié)議,在協(xié)議設(shè)計之初均未考慮安全傳輸問題。隨著互聯(lián)網(wǎng)的發(fā)展,國際標準組織雖陸續(xù)推出了 SSL 、 HTTP1.1 等具有安全傳輸能力的應(yīng)用層協(xié)議,但作為應(yīng)用層承載協(xié)議的 TCP/IP 協(xié)議仍存在著固有的安全缺陷,造成至今未能有徹底的、低成本的、不需硬件支持的互聯(lián)網(wǎng)安全傳輸解決方案。正是由于網(wǎng)絡(luò)傳輸安全問題的現(xiàn)實存在,推動著黑客攻擊技術(shù)、防火墻技術(shù)的不斷發(fā)展。
????無論是黑客攻擊技術(shù)還是防火墻技術(shù),其實現(xiàn)均必須具備網(wǎng)絡(luò)封包截獲技術(shù)。黑客利用網(wǎng)絡(luò)封包截獲技術(shù),偵聽獲取網(wǎng)絡(luò)傳輸數(shù)據(jù),并發(fā)起仿冒攻擊、篡改攻擊等;防火墻利用網(wǎng)絡(luò)封包截獲技術(shù),截斷式地或偵聽式地獲取通過本機的網(wǎng)絡(luò)封包,進行安全策略撿擇后,或放行、或攔截丟棄網(wǎng)絡(luò)封包,以達到反攻擊的目的。
一、概述
????網(wǎng)絡(luò)封包截獲,涉及驅(qū)動編程技術(shù)、核心態(tài)編程技術(shù)、系統(tǒng)動態(tài)鏈接庫編程技術(shù)、協(xié)議生成與解析編程技術(shù)等,集中體現(xiàn)了網(wǎng)絡(luò)應(yīng)用的核心技術(shù),是防火墻等高級網(wǎng)絡(luò)應(yīng)用開發(fā)的基礎(chǔ)。基于 Windows 2000 和 Windows XP 的網(wǎng)絡(luò)封包截獲技術(shù)主要分為三種: WinSock2 動態(tài)鏈接庫重載、傳輸層過濾驅(qū)動、中間層驅(qū)動。
??????WinSock2 動態(tài)鏈接庫重載 :?系統(tǒng)的 WinScok2 動態(tài)鏈接庫( ..\system32\winsock.dll ),隨系統(tǒng)啟動而載入內(nèi)存,提供 29 個用于網(wǎng)絡(luò)傳輸?shù)墓δ芎瘮?shù)。 IE 等普通上層應(yīng)用程序,調(diào)用 WinScok2 動態(tài)鏈接庫中的 WSPSend 、 WSPRecv 等函數(shù),實現(xiàn)網(wǎng)絡(luò)收、發(fā)功能。修改注冊表中 HKEY_LOCAL_MACHINE\SYSTM\CURRENTCONTROLSET\SERVICES\WinSock2 項,建立新的自定義 WSPStartup 入口函數(shù),可以重載 winsock.dll 。通過重載 winsock.dll 中的有關(guān)網(wǎng)絡(luò)收、發(fā)函數(shù),增加網(wǎng)絡(luò)封包收、發(fā)前、后的自定義處理功能,實現(xiàn)網(wǎng)絡(luò)封包截獲。公開源代碼的費爾防火墻,使用了 WinSock2 動態(tài)鏈接庫重載,實現(xiàn)網(wǎng)絡(luò)封包的截獲與安全解析。
??????傳輸層過濾驅(qū)動:?使用 NDIS ( Network Driver Interface Specification 網(wǎng)絡(luò)驅(qū)動接口規(guī)范)技術(shù),又稱為 TDI 編程( Transport Driver Interface 傳輸層驅(qū)動接口編程 )。 Windows 2000 和 Windows XP 操作系統(tǒng)中, TCP/IP 協(xié)議作為系統(tǒng)驅(qū)動程序( ..\system32\TcpIp.sys ),在系統(tǒng)啟動時加載入系統(tǒng)內(nèi)存,以 TCP/IP 設(shè)備對象( DeviceObject )的形式供應(yīng)用程序或其它系統(tǒng)程序調(diào)用。傳輸層過濾驅(qū)動程序創(chuàng)建一個或多個設(shè)備對象,直接掛接到 TCP/IP 設(shè)備對象之上。掛接成功后,當其它程序使用網(wǎng)絡(luò)傳輸功能,調(diào)用 TCP/IP 設(shè)備對象時,操作系統(tǒng)首先將該調(diào)用映射到 TCP/IP 設(shè)備對象之上所掛接的傳輸層過濾驅(qū)動程序。通過傳輸層過濾驅(qū)動程序,再調(diào)用下層的 TCP/IP 設(shè)備對象,從而完成網(wǎng)絡(luò)訪問功能。同樣,從 TCP/IP 層上傳至應(yīng)用程序的網(wǎng)絡(luò)封包,也要經(jīng)傳輸層過濾驅(qū)動程序后,再轉(zhuǎn)發(fā)至目標應(yīng)用程序端口。基于此工作原理,可以在傳輸層過濾驅(qū)動程序中實現(xiàn)網(wǎng)絡(luò)封包截獲,完成網(wǎng)絡(luò)封包的過濾及加解密處理。公開原代碼的 TcpIpDog.sys 及微軟官方 2000 DDK 的 Packet.c 例程,使用傳輸層過濾驅(qū)動技術(shù),實現(xiàn)了網(wǎng)絡(luò)封包截獲。
??????中間層驅(qū)動:?與傳輸層過濾驅(qū)動實現(xiàn)基本原理一致,也是使用 NDIS 技術(shù)。主要差別在于,中間層驅(qū)動程序,掛接在協(xié)議設(shè)備對象(包括 TCP/IP 設(shè)備對象)和網(wǎng)卡設(shè)備對象之間。任何進出網(wǎng)卡的網(wǎng)絡(luò)封包,均必須首先經(jīng)過中間層驅(qū)動程序的處理。從某種意義上分析,中間層驅(qū)動程序更象一個虛擬網(wǎng)卡。該虛擬卡封裝了物理網(wǎng)卡,對物理網(wǎng)卡的一切網(wǎng)絡(luò)訪問操作,均必須先經(jīng)虛擬卡處理。公開原代碼的微軟官方 2000 DDK 的 Passthru.c 例程,使用中間層驅(qū)動技術(shù),實現(xiàn)了網(wǎng)絡(luò)封包截獲。
????以上三種網(wǎng)絡(luò)封包截獲技術(shù)中, WinSock2 動態(tài)鏈接庫重載、傳輸層過濾驅(qū)動截獲網(wǎng)絡(luò)封包不夠徹底,均存在被繞開的技術(shù)可能,而 中間層驅(qū)動作用于協(xié)議層之下、物理網(wǎng)卡驅(qū)動層之上,與協(xié)議無關(guān),對網(wǎng)絡(luò)封包的截獲最為徹底,基本不存在被繞開的技術(shù)可能,但也最具有技術(shù)難度。中間層驅(qū)動程序的技術(shù)難點主要體現(xiàn)為:
??????缺少公開的技術(shù)資料,基本無中文講解資料、教材書籍。即使是 微軟官方 2000 DDK 的 Passthru.c 例程,也僅公開了偵聽式數(shù)據(jù)報頭的截獲方法與數(shù)據(jù)結(jié)構(gòu),而對 IRP ( I/O Request Packet 系統(tǒng) I/O 請求包)結(jié)構(gòu)未作進一步的公開。
???? ??與硬件相關(guān)性大。某種意義上,中間層驅(qū)動程序更象虛擬網(wǎng)卡,而網(wǎng)卡硬件性能的不一致,在中間層驅(qū)動程序中也必須有所體現(xiàn)。如,總線型網(wǎng)卡與非總線型網(wǎng)卡接收數(shù)據(jù)包的原理并不相同,就要求中間層驅(qū)動程序也必須同時考慮兩種網(wǎng)卡的不同要求。
????? 作用于協(xié)議層之下,必須手動解析各種傳輸協(xié)議,造成在中間層解析協(xié)議的技術(shù)難度較大。
????? 編程與調(diào)試困難。驅(qū)動程序的編制與調(diào)試本身就極為困難,加之中間層驅(qū)動程序作用于網(wǎng)卡驅(qū)動程序之上,而基本不可能擁有網(wǎng)卡驅(qū)動的原程序,無法使用 So ftICE.exe 等調(diào)試工具加載網(wǎng)卡驅(qū)動的調(diào)試符號,加之網(wǎng)卡工作原理復(fù)雜,使得中間層驅(qū)動程序的調(diào)試較 USB 接口等一般硬件驅(qū)動程序調(diào)試更為困難。
由于以上原因,基于中間層驅(qū)動技術(shù)的網(wǎng)絡(luò)通信產(chǎn)品,基本止于試驗室內(nèi),止于項目定制式的產(chǎn)品,少有成熟的通用產(chǎn)品問世。而也正是由于中間層驅(qū)動程序的協(xié)議無關(guān)性、不可繞開性及存在的技術(shù)挑戰(zhàn)性,吸引著包括黑客在內(nèi)的大量精英程序員。
二、 NDIS 簡介
????NDIS 是 Network Driver Interface Specification (網(wǎng)絡(luò)驅(qū)動程序接口規(guī)范)的縮寫,為傳輸層提供了標準的網(wǎng)絡(luò)接口。在 Windows 操作系統(tǒng)中,所有的應(yīng)用程序都最終通過調(diào)用 NDIS 接口,實現(xiàn)網(wǎng)絡(luò)訪問。 NDIS 在操作系統(tǒng)中的結(jié)構(gòu)如圖一所示。
圖一: NDIS 結(jié)構(gòu)圖
如圖一所示, NDIS 支持 3 種類型的驅(qū)動程序:
??????傳輸層驅(qū)動程序 ( Protocol Drivers ): 對上層應(yīng)用程序開放 TDI 接口,對下層驅(qū)動程序開放 Protocol 接口,與下層 Miniport 接口對接,實現(xiàn)協(xié)議驅(qū)動功能。嚴格意義上講,傳輸層驅(qū)動與協(xié)議驅(qū)動尚有區(qū)別,但本文僅涉及 TCP/IP 協(xié)議,并不涉及本地介質(zhì)認可的其它協(xié)議,為便于理解,而將傳輸層驅(qū)動、協(xié)議驅(qū)動簡化為傳輸層驅(qū)動。
????? 中間層驅(qū)動程序( Intermediate Drivers ): 位于物理網(wǎng)卡驅(qū)動程序(即微軟官方所稱的微型端口驅(qū)動程序)之上, 同時具備 Miniport 接口和 Protocol 接口,可與上、下層驅(qū)動程序?qū)?#xff0c;提供轉(zhuǎn)發(fā)驅(qū)動功能。利用其位于物理網(wǎng)卡之上的轉(zhuǎn)發(fā)功能,可以實現(xiàn)不可繞開的網(wǎng)絡(luò)封包截獲。
????? 微型端口驅(qū)動程序( Miniport Drivers ): 對上層的中間層驅(qū)動程序開放 Miniport 接口,再通過 NDIS 接口完成對物理網(wǎng)卡的操作,實現(xiàn)對物理網(wǎng)卡的驅(qū)動功能。
三、開發(fā)工具簡介
????由于缺少教材性的中文資料,客觀上造成理解、建立驅(qū)動程序開發(fā)環(huán)境有一定困難。許多對驅(qū)動開發(fā)感興趣的程序員,往往是因為不能夠正確理解和建立驅(qū)動程序開發(fā)環(huán)境,要么放棄了驅(qū)動程序研究,要么人為復(fù)雜化了驅(qū)動程序開發(fā)過程。筆者結(jié)合實際工作經(jīng)驗,在有關(guān)幫助文檔之外,主要強調(diào)各種開發(fā)包的本質(zhì)功能及相互關(guān)系。具體開發(fā)環(huán)境的建立步驟,特別是各種開發(fā)包的安裝順序,請參見有關(guān)開發(fā)包的幫助文檔。
????與 USB 接口驅(qū)動等其它驅(qū)動程序開發(fā)一樣,中間層驅(qū)動程序開發(fā)也主要是利用微軟提供的 Windows 2000 DDk 開發(fā)包,其中 DDK 是 Drivers Develop Kit 的簡稱。 DDK 提供了大量符合 Windows 操作系統(tǒng) NDIS 接口規(guī)范的 C 語言函數(shù),為驅(qū)動開發(fā)程序員提供了良好的開發(fā)接口。
????鑒于 DDK 開發(fā)包理解和使用較為困難,許多第三方公司對 DDK 進行了不嚴格的面向?qū)ο蟮姆庋b,為程序員在 VC++6.0 環(huán)境中使用面向?qū)ο蟮恼Z言開發(fā)驅(qū)動程序,提供了更為友好的平臺接口。其中影響較大,應(yīng)用較為成功的是 Compware 公司的 DriverStudio 3.1 。特別是 DriverStudio 3.1 提供了封裝類庫的原代碼(含注示),和常見的驅(qū)動例程,程序員不但可以參考其提供的驅(qū)動例程,而且可以通過修改現(xiàn)有的封裝類庫簡化開發(fā)功能的實現(xiàn),甚至能夠生成自定義驅(qū)動類。同時, DriverStudio 3.1 還提供了開發(fā)向?qū)Чδ?#xff0c;可以象使用 MFC 開發(fā)向?qū)б粯?#xff0c;通過向?qū)Чδ茏詣由纱罅侩y以編寫的驅(qū)動公共模塊,極大地減少了開發(fā)工作量,降低了開發(fā)難度。
VC++6.0 、 DriverStudio 3.1 、 Windows 2000 DDk 三種主要開發(fā)工具的關(guān)系可簡述如下:
??????Windows 2000 DDk 是微軟官方提供的 Windows 2000/XP NDIS 接口的具體 C 語言編程實現(xiàn),是包括中間層驅(qū)動在內(nèi)的各種驅(qū)動程序的核心開發(fā)包。
????? DriverStudio 3.1 是 Compware 公司提供的基于 Windows 2000 DDk 的開發(fā)包,其主要是對 Windows 2000 DDk 進行了不嚴格的面向?qū)ο蟮姆庋b,并能夠在安裝過程中自動設(shè)置 VC++6.0 開發(fā)環(huán)境、自動設(shè)置系統(tǒng)環(huán)境變量,使程序員可以象調(diào)用 MFC 類庫一樣調(diào)用 DriverStudio 3.1 類庫,可以使用面向?qū)ο蟮恼Z言進行驅(qū)動程序開發(fā),以降低開發(fā)難度。同時, DriverStudio 3.1 還提供了 Compware 公司的 SoftICE.exe 調(diào)試工具,以提高驅(qū)動程序調(diào)試效率。
???? ? 通過 DriverStudio 3.1 的 DDK Build Setting 菜單功能調(diào)用 VC++6.0 ,能夠自動設(shè)置環(huán)境參數(shù),使 VC++6.0 能夠編譯鏈接至 DriverStudio 3.1 的類庫文件,從而編譯鏈接至 DDK 庫文件,使 VC++6.0 成為驅(qū)動程序的最終開發(fā)平臺。
四、中間層驅(qū)動程序模型分析
????上文已簡單地提到過中間層驅(qū)動程序位于 Miniport 和 Protocol 驅(qū)動程序之間,同時具有 Miniport 和 Protocol 兩種驅(qū)動程序接口。具體來講,中間層驅(qū)動程序在自己的上下兩端分別開放出一個 Miniport 接口(對上)和 Protocol 接口(對下)。其中,位于中間驅(qū)動程序上面的 Miniport 接口,與上層驅(qū)動程序的 Protocol 接口對接;位于下面的 Protocol 接口,與下層驅(qū)動程序的 Miniport 接口對接。通過兩種接口的使用,使得中間層驅(qū)動程序能夠插入 Miniport 和 Protocol 驅(qū)動程序之間。
?
圖二: NDIS 中間層驅(qū)動程序安裝前后的對比結(jié)構(gòu)示意
如圖二所示,中間層驅(qū)動程序安裝前,物理網(wǎng)卡驅(qū)動程序與傳輸層驅(qū)動程序進行直接通信,兩者間通過 NDIS 接口完成網(wǎng)絡(luò)封包傳遞;中間驅(qū)動程序安裝后,網(wǎng)絡(luò)封包經(jīng)中間層驅(qū)動程序在物理網(wǎng)卡驅(qū)動程序、傳輸層驅(qū)動程序之間進行轉(zhuǎn)發(fā),從而使得中間層驅(qū)動程序具備了網(wǎng)絡(luò)封包截獲功能。
????利用 NDIS 中間驅(qū)動程序,可以在網(wǎng)卡驅(qū)動程序和傳輸層驅(qū)動程序之間插入一層自定義處理,從而可以用來截獲網(wǎng)絡(luò)封包,并重新進行封包、加密、網(wǎng)絡(luò)地址轉(zhuǎn)換及過濾等操作。且由于中間層驅(qū)動程序位于網(wǎng)卡驅(qū)動程序和傳輸層驅(qū)動程序之間,可以截獲較為底層的與協(xié)議無關(guān)的網(wǎng)絡(luò)封包,可以完成更為底層的操作,編寫網(wǎng)絡(luò)安全軟件的安全強度更有保證。
????考慮到篇幅和水平所限,且考慮到 DriverStudio 3.1 開發(fā)向?qū)軌蜃詣由纱罅恐虚g層驅(qū)動的基礎(chǔ)代碼,本文不再對中間層驅(qū)動程序內(nèi)部的 UML 模型展開深入分析,有興趣的讀者可參見 DriverStudio 3.1 幫助文檔中的 DriverNetworks Help/Programing Guide/NDIS Drivers Framework/NDIS Intermediate Drivers Framework 的詳細分析說明,且可參見 DriverStudio 3.1 目錄 SOURCE 下的 DNW.dsw 中的 KndisLib Classes 進行原代碼級的理解分析。在此,筆者特別強調(diào),對 KndisLib Classes 進行原代碼級的理解分析是打牢驅(qū)動程序開發(fā)技術(shù)基礎(chǔ)、提高驅(qū)動程序開發(fā)能力的有效方法。
五、網(wǎng)絡(luò)封包截獲核心原代碼分析
????網(wǎng)絡(luò)封包無外乎分為收、發(fā)兩種封包,因此截獲網(wǎng)絡(luò)封包的理想位置應(yīng)是發(fā)送封包之前,和接收封包之后。具體來講,接收封包的截獲位置,應(yīng)位于物理網(wǎng)卡接收封包之后;發(fā)送封包的截獲位置,應(yīng)位于通過物理網(wǎng)卡發(fā)送封包之前。
????DriverStudio 3.1 開發(fā)包提供了 OnReceive 和 OnSend 兩個十分方便的虛函數(shù)。其中,物理網(wǎng)卡接收封包之后, NDIS 將調(diào)用 OnReceive 虛函數(shù);通過物理網(wǎng)卡發(fā)送封包之前, NDIS 將調(diào)用 OnSend 虛函數(shù)。因此,只需在自開發(fā)的中間層驅(qū)動程序中實現(xiàn)這兩個虛函數(shù),加入自定義的封包處理方法,就能夠很方便地實現(xiàn)網(wǎng)絡(luò)封包截獲處理功能。 DriverStudio 3.1 開發(fā)向?qū)軌蜃詣由纱罅炕A(chǔ)代碼,甚至自動生成了空處理的 OnReceive 和 OnSend 兩虛函數(shù),程序員只要加以改寫,就能夠?qū)崿F(xiàn)自定義的封包處理功能,極大地簡化了開發(fā)過程。
????但我們應(yīng)注意到,中間層驅(qū)動程序位于傳輸層驅(qū)動程序或協(xié)議層驅(qū)動程序之下,因此就要求我們必須自編程實現(xiàn)協(xié)議的解析功能。之所以在此再次強調(diào)協(xié)議的解析,是因為 DriverStudio 3.1 開發(fā)包所提供的例程中,對 TCP/IP 協(xié)議的數(shù)據(jù)結(jié)構(gòu)定義有誤( TCP 包頭長度的計算方法不正確),雖不影響該例程的正常編譯和運行,但若在該例程基礎(chǔ)上修改設(shè)計更完善的 TCP/IP 封包的截獲程序,將會造成難以測試發(fā)現(xiàn)的漏包現(xiàn)象。
(一) TCP/IP 協(xié)議數(shù)據(jù)結(jié)構(gòu)的定義
????定義正確的協(xié)議數(shù)據(jù)結(jié)構(gòu),是實現(xiàn)協(xié)議解析,進而實現(xiàn)封包截獲的基礎(chǔ)。所謂協(xié)議數(shù)據(jù)結(jié)構(gòu),其實質(zhì)是協(xié)議的包頭數(shù)據(jù)結(jié)構(gòu),包體內(nèi)是 HTTP 等應(yīng)用層協(xié)議數(shù)據(jù),無關(guān)于本文涉及的網(wǎng)絡(luò)封包截獲。任何有效的 TCP/IP 數(shù)據(jù)包均由包頭數(shù)據(jù)和包體數(shù)據(jù)組成,其中包頭包括以太幀數(shù)據(jù)頭、 IP 數(shù)據(jù)頭、 TCP 數(shù)據(jù)頭;包體內(nèi)包含應(yīng)用層協(xié)議數(shù)據(jù)。
// Ethernet Packet Header
typedef struct _ETHERNET_HEADER {
UCHAR eth_dest[6]; // Destination address
UCHAR eth_src[6]; // Source address
union {
USHORT eth_len; // 802.3 length field.
USHORT eth_type; // Ethernet type field.
};
} ETHERNET_HEADER, *PETHERNET_HEADER;
// Internet Protocol (IP) Packet Header
typedef struct IP_HEADER
{
UCHAR iph_verlen; // Version and length
UCHAR iph_tos; // Type of service
USHORT iph_length; // Total datagram length
USHORT iph_id; // Identification
USHORT iph_offset; // Flags, fragment offset
UCHAR iph_ttl; // Time to live
UCHAR iph_protocol; // Protocol
USHORT iph_xsum; // Header checksum
ULONG iph_src; // Source address
ULONG iph_dest; // Destination address
} IP_HEADER, *PIP_HEADER;
// TCP Packet Header
typedef struct TCP_HEADER
{
USHORT tcph_src; // Source Port Number
USHORT tcph_dest; // Destination Port Number
ULONG tcph_seq; // Sequence Number
ULONG tcph_ack_seq; // Acknowlegdement Number
USHORT tcph_flags; // Flags
USHORT tcph_window; // Window
USHORT tcph_check; // Checksum
USHORT tcph_urgent; // Urgent pointer
UCHAR GetDataOffset() {
USHORT nLen=(tcph_flags & 0x 00f 0);// 例程中無此處理,造成標志字段高 4 位為全零(如 //tcph_flags=0x0270 )時, TCP 包頭長度計算出錯。 // 雖標志字段高 4 位為全零在正常收發(fā)封包過程中不 // 會出現(xiàn),但在通過“三次握手”建立 TCP 連接和結(jié) // 束 TCP 連接過程中,必然出現(xiàn)高 4 位為全零情況, // 進而造成在此過程中 TCP 包頭長度計算錯。一但 //TCP 包頭長度計算錯,可能引發(fā)進一步的異常。
return (nLen >> 4)*4;
}
} TCP_HEADER, *PTCP_HEADER;
(二) TCP/IP 協(xié)議解析函數(shù)的實現(xiàn)
????在 TCP/IP 協(xié)議數(shù)據(jù)結(jié)構(gòu)的定義的基礎(chǔ)上,可根據(jù)項目開發(fā)需要實現(xiàn)協(xié)議解析功能函數(shù)。下文原代碼中,主要實現(xiàn)了源 IP 地址、目的 IP 地址、源 TCP 端口號、目的 TCP 端口號、包頭總長度的解析功能。現(xiàn)有的 DriverStudio 3.1 開發(fā)包例程和 Windows 2000 DDk 例程中,未能提供協(xié)議解析代碼。因此,初學(xué)者應(yīng)特別注意下文原代碼中的移位計算。部分初學(xué)者就是因為對 VC 指針與協(xié)議中數(shù)據(jù)類型的對應(yīng)關(guān)系理解不正確,或未進行移位處理,或移位處理不正確,均造成協(xié)議解析不正確,進而造成封包無法正確截獲。
//Parse address in KNdistPacket
bool SecurityVirtualCardAdapter::GetAddr_OnRec(const KNdisPacket& Original, //Data packet
//Out parameters
ULONG *pIpScrAddr,ULONG *pIpDesctAddr,
USHORT *pTcpScrAddr,USHORT *pTcpDesctAddr,
ULONG *pPckHdLen)
{
//Return buffers count in the packet
UINT nBufCnt=Original.QueryBufferCount();
//Return the first buffer in the packet
KNdisBuffer Buf=Original.QueryFirstBuffer();
//Tests if the buffer is initialed correctly
if(!Buf.IsValid())
return false;
//Return the first buffer length
//KNdisBuffer::Length
// UINT Length( ) ;
// Gets the length.
//Length of the underlying buffer in bytes.
ULONG nBufLen = Buf.Length();
//Return TCP packet header length
ULONG nHdrLen=sizeof(ETHERNET_HEADER)
+sizeof(TCP_HEADER)
+sizeof(IP_HEADER);
if(nHdrLen>nBufLen)
return false;
//KNdisBuffer::Address
// PVOID Address( ) ;
// Gets the virtual address.
//Virtual address of the first byte of the buffer, or NULL if an error has occurred.
PETHERNET_HEADER pEthHdr = (PETHERNET_HEADER) Buf.Address();
//Return false if ethernet packet is not IP protocol
if(pEthHdr->eth_type!=ETH_TYPE_IP)
return false;
//Return false if not TCP protocol
PIP_HEADER pIpHdr=(PIP_HEADER)((PCHAR)pEthHdr+sizeof(ETHERNET_HEADER));
if(pIpHdr->iph_protocol!=IP_PROTOCOL_TCP)
return false;
//Get IP address
ULONG srcIp=pIpHdr->iph_src;
*pIpScrAddr=((srcIp&0xff)<<24)+
((srcIp&0xff00)<<8)+
((srcIp&0xff0000)>>8)+
((srcIp&0xff000000)>>24);
ULONG destIp=pIpHdr->iph_dest;
*pIpDesctAddr=((destIp&0xff)<<24)+
((destIp&0xff00)<<8)+
((destIp&0xff0000)>>8)+
((destIp&0xff000000)>>24);
//Get TCP port number and TCP packet header length
PTCP_HEADER pTcpHdr=(PTCP_HEADER)((PCHAR)pIpHdr+sizeof(IP_HEADER));
UCHAR nTcpPckHdLen=pTcpHdr->GetDataOffset();
USHORT scrPort=pTcpHdr->tcph_src;
*pTcpScrAddr=((scrPort&0xff00)>>8)+((scrPort&0x00ff)<<8);
//TRACE("GW Rec Source TCP port=%d\n",*pTcpScrAddr);
USHORT desctPort=pTcpHdr->tcph_dest;
*pTcpDesctAddr=((desctPort&0xff00)>>8)+((desctPort&0x00ff)<<8);
//TRACE("GW Rec Desct TCP port=%d\n",*pTcpDesctAddr);
//Return packet header length
*pPckHdLen=sizeof(ETHERNET_HEADER)+sizeof(IP_HEADER)+nTcpPckHdLen;
return true;
}
(三) OnReceive 虛函數(shù)的實現(xiàn)
????根據(jù)物理網(wǎng)卡工作方式的不同,接收封包方式主要有全包接收方式和部分接收方式。其中,全包接收方式對應(yīng)于總線型網(wǎng)卡,網(wǎng)卡收到封包后, NDIS 將一次性把完整的封包提交至 OnReceive 虛函數(shù);部分接收方式對應(yīng)于非總線型網(wǎng)卡,網(wǎng)卡收到封包后, NDIS 將先把封包的一部分提交至 OnReceive 虛函數(shù),上層程序根據(jù)封包的一部分判斷是否同意接收,若同意接收網(wǎng)卡將再次提交封包的其它部分,若不同意接收網(wǎng)卡則丟棄該封包。相對應(yīng)于以上兩種接收方式, DriverStudio 3.1 開發(fā)包也提供了 OnReceive 虛函數(shù)的兩種形式:
??????NDIS_STATUS SecurityVirtualCardAdapter::OnReceive
(const KNdisPacket& Original, KNdisPacket& Repackaged)// 對應(yīng)于全包接收方式
??????NDIS_STATUS SecurityVirtualCardAdapter::OnReceive
(IN OUT KNdisPartialPacket& PacketToAccept,
IN PVOID HeaderBuffer, IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer, IN UINT LookaheadBufferSize,
IN UINT PacketSize)// 對應(yīng)于部分接收方式
????全包接收方式下的 OnReceive 虛函數(shù)的實現(xiàn)較為簡單,且與 OnSend 虛函數(shù)的實現(xiàn)原理完全一致,開發(fā)包例程中有詳細參考,本文“ OnSend 虛函數(shù)的實現(xiàn)”也將有原代碼展示,因此下文原代碼將僅涉及部分接收方式下的 OnReceive 虛函數(shù)的實現(xiàn)。
????部分接收方式下,若在中間層程序程序中對全包進行處理,按照 DriverStudio 3.1 的幫助說明,將需要進行私有包池的建立和管理,編程復(fù)雜、調(diào)試難度大。筆者研究測試發(fā)現(xiàn),在 Windows 2000/XP/2003 下,由于操作系統(tǒng)對網(wǎng)卡緩存管理有相當好的連續(xù)性,完全可以經(jīng)計算后,通過部分接收包的指針獲得全包指針。簡而言之,在 Windows 2000/XP/2003 下,可以通過指針位置計算后,采用全包接收處理方式對部分接收進行全包處理,從而極大地降低了部分接收方式的中間層驅(qū)動程序開發(fā)難度。指針位置計算的關(guān)鍵,是在部分包緩存區(qū)中忽略以太幀頭。
????具體原代碼如下(為補充上文的協(xié)議解析功能,其中涉及了包頭中其它字段的解析):
NDIS_STATUS SecurityVirtualCardAdapter::OnReceive
(IN OUT KNdisPartialPacket& PacketToAccept,
IN PVOID HeaderBuffer, IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer, IN UINT LookaheadBufferSize,
IN UINT PacketSize)
{
PETHERNET_HEADER pEthHd=(PETHERNET_HEADER)HeaderBuffer;
PIP_HEADER pIpHd=(PIP_HEADER)((PUCHAR)HeaderBuffer+sizeof(ETHERNET_HEADER));
PTCP_HEADER pTcpHd=(PTCP_HEADER)((PUCHAR)HeaderBuffer+
sizeof(ETHERNET_HEADER)+
sizeof(IP_HEADER));
USHORT nEthType=pEthHd->eth_type;
UCHAR nProtocol=pIpHd->iph_protocol;
if(nEthType!=ETH_TYPE_IP||nProtocol!=IP_PROTOCOL_TCP)
{
//TRACE("Not TCP/IP");
UNREFERENCED_PARAMETER(PacketToAccept);
return NDIS_STATUS_SUCCESS;
}
ULONG nScrIpAddr=pIpHd->iph_src;
ULONG nDestIpAddr=pIpHd->iph_dest;
USHORT nScrPort=pTcpHd->tcph_src;
USHORT nDestPort=pTcpHd->tcph_dest;
USHORT nTcpHdLen=pTcpHd->GetDataOffset();
nScrIpAddr=((nScrIpAddr&0xff000000)>>24)+
((nScrIpAddr&0x00ff0000)>>8)+
((nScrIpAddr&0x0000ff00)<<8)+
((nScrIpAddr&0x000000ff)<<24);
nScrPort=((nScrPort&0xff00)>>8)+((nScrPort&0x00ff)<<8);
nDestIpAddr=((nDestIpAddr&0xff000000)>>24)+
((nDestIpAddr&0x00ff0000)>>8)+
((nDestIpAddr&0x0000ff00)<<8)+
((nDestIpAddr&0x000000ff)<<24);
nDestPort=((nDestPort&0xff00)>>8)+((nDestPort&0x00ff)<<8);
if(!IsEncrypt(nScrIpAddr,nDestIpAddr,nScrPort,nDestPort))
{
//TRACE("Submit not encrypt packet");
UNREFERENCED_PARAMETER(PacketToAccept);
return NDIS_STATUS_SUCCESS;
}
TRACE("******** Receive partial *************");
TRACE("HeaderBufferSize=%d",HeaderBufferSize);
TRACE("PacketSize=%d",PacketSize);
TRACE("LookaheadBufferSize=%d",LookaheadBufferSize);
TRACE("pHeaderBuffer=0x%0x",HeaderBuffer);
TRACE("pLookAheadBuffer=0x%0x",LookAheadBuffer);
TRACE("Source=%d.%d.%d.%d:%d",(nScrIpAddr&0xff000000)>>24,
(nScrIpAddr&0x00ff0000)>>16,
(nScrIpAddr&0x0000ff00)>>8,
(nScrIpAddr&0x000000ff),
nScrPort);
TRACE("Dest=%d.%d.%d.%d:%d",(nDestIpAddr&0xff000000)>>24,
(nDestIpAddr&0x00ff0000)>>16,
(nDestIpAddr&0x0000ff00)>>8,
(nDestIpAddr&0x000000ff),
nDestPort);
TRACE("// TCP Pakcet Header ///");
ULONG nSeq=pTcpHd->tcph_seq;
nSeq=((nSeq&0xff000000)>>24)+
((nSeq&0x00ff0000)>>8)+
((nSeq&0x0000ff00)<<8)+
((nSeq&0x000000ff)<<24);
ULONG nAck=pTcpHd->tcph_ack_seq;
nAck=((nAck&0xff000000)>>24)+
((nAck&0x00ff0000)>>8)+
((nAck&0x0000ff00)<<8)+
((nAck&0x000000ff)<<24);
USHORT nFlags=pTcpHd->tcph_flags;
USHORT nWin=pTcpHd->tcph_window;
TRACE("Seq=0x%0x",nSeq);
TRACE("Ack=0x%0x",nAck);
TRACE("Flags=0x%0x",nFlags);
TRACE("Win=0x%0x",nWin);
TRACE("///");
?
PUCHAR pLook=(PUCHAR)LookAheadBuffer;
USHORT nIpandTcpHdLen=sizeof(IP_HEADER)+nTcpHdLen;
if(PacketSize<(UINT)(nIpandTcpHdLen+7))
{
TRACE("Submit no Encrypt packet");
UNREFERENCED_PARAMETER(PacketToAccept);
return NDIS_STATUS_SUCCESS;
}
//LookaheadBufferSize
for(USHORT i=0;i<PacketSize;i++)
{
if(i>nIpandTcpHdLen-1)
{
UCHAR test=pLook[i];
TRACE("Look[%d]=(0x%0x,%c)->(0x%0x,%c",i,test,test,pLook[i],pLook[i]);
}
}
UNREFERENCED_PARAMETER(PacketToAccept);
return NDIS_STATUS_SUCCESS;
}
(四) OnSend 虛函數(shù)的實現(xiàn)
????OnReceive 虛函數(shù)的實現(xiàn)相對較為簡單, DriverStudio 3.1 提供了詳細例程及說明,本文不再詳細分析,僅列出自編寫的原代碼。
NDIS_STATUS SecurityVirtualCardAdapter::OnSend
(const KNdisPacket& Original, KNdisPacket& Repackaged)
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
ULONG IpScrAddr=0,IpDesctAddr=0;
USHORT TcpScrAddr=0,TcpDesctAddr=0;
ULONG PckHdLen=0;
ULONG *pIpScrAddr,*pIpDesctAddr;
USHORT *pTcpScrAddr, *pTcpDesctAddr;
ULONG *pPckHdLen;
pIpScrAddr=&IpScrAddr;
pIpDesctAddr=&IpDesctAddr;
pPckHdLen=&PckHdLen;
pTcpScrAddr=&TcpScrAddr;
pTcpDesctAddr=&TcpDesctAddr;
if(GetAddr_OnSend(Original,
pIpScrAddr,pIpDesctAddr,
pTcpScrAddr,pTcpDesctAddr,
pPckHdLen))// 判斷是否是須加密處理的封包
{
TRACE("----- Send Encrypt -----");
Repackaged.CloneDown(Original);// 開發(fā)包提供的向下復(fù)制封包方法
EncryptPacket_OnSend(Repackaged,*pPckHdLen);// 自定義的加密處理函數(shù)
TRACE("----- Send Encrypt End -----");
return Status;
}
else
{
Repackaged.CloneDown(Original);
return Status;
}
}
【參考文獻】
?????《 Windows 防火墻與網(wǎng)絡(luò)封包截獲技術(shù)》 朱雁輝 電子工業(yè)出版社 2002
????? Windows 2000 DDk 幫助文檔 Microsoft 公司 2003
????? DriverStudio 3.1 幫助文檔 Compware 公司 2004
費爾個人防火墻采用兩種封包過濾技術(shù):
1. 應(yīng)用層封包過濾,采用 Winsock 2 SPI。
2. 核心層封包過濾,采用 NDIS-HOOK。
Winsock 2 SPI 的技術(shù)特點:
Winsock 2 SPI 工作在 API 之下 Driver 之上,屬于應(yīng)用層的范疇。利用這項技術(shù)可以截獲所有的基于 Socket 的網(wǎng)絡(luò)通信。比如:IE、OUTLOOK 等常見的應(yīng)用程序都是使用 Socket 進行通信。它的技術(shù)特點主要有:
優(yōu)點:
1. 工作在應(yīng)用層,以 DLL 的形式存在,編程、調(diào)試方便。
2. 跨 Windows 平臺,可以直接在 Windows 98/ME/NT/2000/XP上通用,Windows 95 只需安裝上 Winsock 2 for 95,也可以正常運行。
3. 效率高,由于工作在應(yīng)用層,CPU 占用率低。
4. 封包還沒有按照低層協(xié)議進行切片,所以比較完整,很容易做內(nèi)容過濾。
5. 做防色情之類的軟件,不用根據(jù)具體的瀏覽器進行分別編程,既簡單又安全。
缺點:
1. 不用 Socket 的網(wǎng)絡(luò)通信無法攔截,比如:使用NetBios的網(wǎng)上鄰居,和使用ICMP協(xié)議的Ping。
2. 微軟對SPI設(shè)計的問題,導(dǎo)致如果安裝順序出錯很容易造成網(wǎng)絡(luò)癱瘓。這意味著如果同時安裝幾個使用SPI技術(shù)的軟件,而且有使用非標準安裝方式的軟件,很容易有的被繞過或者不能正常網(wǎng)絡(luò)通信。所以建議編寫SPI程序一定要用標準的安裝方式。
SPI 在 操作系統(tǒng)種的結(jié)構(gòu)如下圖:我們需要處理的是傳輸服務(wù)提供者。
層次結(jié)構(gòu)圖:費爾個人防火墻的XFILTER.DLL處的就是基礎(chǔ)服務(wù)提供者的位置。
NDIS-HOOK 的技術(shù)特點:
NDIS 是網(wǎng)絡(luò)接口規(guī)范,Windows 使用 NDIS 函數(shù)庫實現(xiàn) NDIS 接口。所有的網(wǎng)絡(luò)通信最終必須通過 NDIS 完成。NDIS 橫跨 傳輸層、網(wǎng)絡(luò)層和數(shù)據(jù)鏈路層,NDIS 的結(jié)構(gòu)如下圖:
微軟提供了以下幾種標準接口編程方式:
1. TDI 傳輸層過濾驅(qū)動程序(TDI Filter,比如常見的 Tcp Filter Driver)
2. 協(xié)議驅(qū)動程序 (Protocol Driver)
3. 中間驅(qū)動程序 (IM Driver)
4. 小端口驅(qū)動程序 (Miniport Driver)
其中 TDI Filter Driver 和 IM Driver 通常用做封包過濾。也是防火墻和VPN軟件常用的技術(shù)。但是它們都有一些缺陷:
TDI Filter Driver 屬于 Upper Driver,位于 TcpIp.sys 之上,這就意味著由 TcpIp.sys 接收并直接處理的數(shù)據(jù)包就不會傳送到上面,從而無法過濾某些接收的數(shù)據(jù)包,典型的就是ICMP,ICMP的應(yīng)答包直接由TcpIp.sys生成并回應(yīng),上面的過濾驅(qū)動程序全然不知。
IM Driver 功能比較強大,但編程接口復(fù)雜。最麻煩的是安裝,自動化安裝太困難。
NDIS-HOOK 克服了上面的缺陷。NDIS-HOOK 的工作原理是直接替換 NDIS 的函數(shù)庫中的函數(shù)地址,這樣只要向 NDIS 的請求就會先經(jīng)過我們自己函數(shù)的處理,這樣就非常簡單,處理完轉(zhuǎn)發(fā)給系統(tǒng)函數(shù)就完成了。NDIS-HOOK技術(shù)有以下特點:
1. 編程方便、接口簡單、思路明確、性能穩(wěn)定。
2. 更靈活,可以僅僅截獲自己需求的,不需要冗余的代碼。
3. 功能強大,可以截獲所有 NDIS 和 TDI 函數(shù)完成的功能。當然比標準方式功能強大許多。還可以用這項技術(shù)延伸到 HOOK 所有系統(tǒng)函數(shù)。
4. 安全性高,這樣截獲封包較為底層,不容易被穿透。
5. 安裝簡單。
NDIS-HOOK 安裝前的結(jié)構(gòu)示意圖:
NDIS-HOOK 安裝后的結(jié)構(gòu)示意圖:
總結(jié)
以上是生活随笔為你收集整理的费尔个人防火墙采用两种封包过滤技术的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 综述:用于自动驾驶的全景鱼眼相机的理论模
- 下一篇: Jenkins-Pipline