標 題: 【原創(chuàng)】使用TDI與WinSock進行客戶端服務(wù)器編程 作 者: Cryin 時 間: 2010-12-24,18:47:37 鏈 接: http://bbs./showthread.php?t=127069 題目:使用TDI與WinSock進行客戶端服務(wù)器編程 日期:2010年12月24日 作者:Cryin' (http://hi.baidu.com/justear) 簡介: 在本文中,,您將了解到使用傳輸驅(qū)動程序接口TDI與應(yīng)用層套接字WinSock客戶端服務(wù)器應(yīng)用程序內(nèi)核級編程實現(xiàn)細節(jié)。介紹常用的TDI函數(shù)并提供編寫TDI與WinSock(TCP)應(yīng)用程序的詳細說明,。最后還提供了源代碼以演示編寫程序的步驟,。 開始之前: 在開始學(xué)習本文內(nèi)容之前,假設(shè)讀者以具備以下基礎(chǔ): Windows 內(nèi)核級編程的知識和經(jīng)驗 網(wǎng)絡(luò)編程概念及應(yīng)用層Socket編程經(jīng)驗 了解并安裝有Microsoft DDK WinSock(服務(wù)器): 應(yīng)用層套接字編程流程比較簡單,,這里簡單介紹: 加載套接字庫并創(chuàng)建Socket(socket()) 綁定套接字到指定端口和IP(bind()) 設(shè)置套接字進行監(jiān)聽以等待連接請求(listen()) 接受連接請求(accept()) 發(fā)送或接收信息(send()/recv()) 關(guān)閉套接字(closesocket()) TDI(客戶端): TDI 定義在傳輸協(xié)議棧中較高級別公開的內(nèi)核模式網(wǎng)絡(luò)接口,,如下圖: 圖:傳輸協(xié)議棧 TDI應(yīng)用程序可以分為兩種類型,與基于Socket的應(yīng)用程序類似: 面向連接(使用TCP協(xié)議,,通信可靠) 面向誤連接(使用UDP協(xié)議,,通信不可靠) 常用TDI函數(shù): 這里討論一些比較常用的TDI,以便實現(xiàn)基于傳輸驅(qū)動程序接口TDI與WinSock客戶端服務(wù)器編程。 打開TDI設(shè)備: VOID InitializeObjectAttributes( OUT POBJECT_ATTRIBUTES InitializedAttributes, IN PUNICODE_STRING ObjectName, IN ULONG Attributes, IN HANDLE RootDirectory, IN PSECURITY_DESCRIPTOR SecurityDescriptor ); 所附帶的參數(shù): InitializedAttributes 要初始化的OBJECT_ATTRIBUTES結(jié)構(gòu)的指針 ObjectName Unicode 設(shè)備名稱,,對于無連接的情況為 device\UDP,,對于本文是面向連接的通信,則為 device\TCP,。此 ObjectName必須為 Unicode 字符串,。該 Unicode 字符串可以使用 RtlInitUnicodeString 庫調(diào)用進行初始化。 Attributes 只需填寫為OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE即可 RootDirectory 此處為NULL SecurityDescriptor 設(shè)置安全描述符,。由于筆者總是打開內(nèi)核句柄,,所以很少設(shè)置這個參數(shù) 接下來需要打開本地傳輸?shù)刂返奈募ο螅蛻舳藨?yīng)用程序必須調(diào)用ZwCreateFile函數(shù)并在擴展屬性中傳遞此地址。當ZwCreateFile成功調(diào)用時,,將返回傳輸文件(表示連接端點)的句柄,。客戶端必須調(diào)用ObReferenceObjectByHandle函數(shù),,該函數(shù)將返回相應(yīng)的傳輸文件對象,。該傳輸文件對象將用于向遠程服務(wù)端發(fā)送數(shù)據(jù)或接收數(shù)據(jù)。此外客戶端必須事件處理例程以接收各種網(wǎng)絡(luò)事件,,如接收數(shù)據(jù)、斷開連接,、錯誤等,。 NTSTATUS ObReferenceObjectByHandle( IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType OPTIONAL, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL ); 所附帶的參數(shù): Handle 為對象指定一個打開句柄。此句柄由 ZwCreateFile 返回,。 DesiredAccess 指定所請求的對象訪問權(quán)限類型,。此字段的解釋取決于對象類型。 ObjectType 指向?qū)ο箢愋偷闹羔???梢詾?nbsp;*IoFileObjectType 或 *ExEventObjectType。如果 AccessMode 為 KernelMode,,此參數(shù)可以為 NULL,。 AccessMode 指定要為訪問檢查使用的訪問模式。必須為 UserMode 或 KernelMode,。對于底層驅(qū)動 程序,,應(yīng)指定 KernelMode。 Object 指向接收對象指針的變量,。 HandleInformation 驅(qū)動程序會將此參數(shù)設(shè)置為 NULL,。 VOID KeInitializeEvent( IN PRKEVENT Event, IN EVENT_TYPE Type, IN BOOLEAN State ); 所附帶的參數(shù): Event 指向事件對象地址的指針 Type 事件類型,NotificationEvent 或者SynchronizationEvent State 事件初始化信號狀態(tài) IoSetCompletionRoutine函數(shù)將向基礎(chǔ)驅(qū)動程序注冊回調(diào)函數(shù),,以在鏈中底層驅(qū)動程序完成了對 IRP 的請求時進行調(diào)用,。將在 IRP 完成(成功或失敗)和取消 IRP 請求時調(diào)用回調(diào)例程,。 VOID IoSetCompletionRoutine( IN PIRP Irp, IN PIO_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context, IN BOOLEAN InvokeOnSuccess, IN BOOLEAN InvokeOnError, IN BOOLEAN InvokeOnCancel ); 所附帶的參數(shù): Irp 指向驅(qū)動程序希望跟蹤的 IRP 的指針 CompletionRoutine 指定驅(qū)動程序提供的 IoCompletion 例程(更低層的驅(qū)動程序完成數(shù)據(jù)包時調(diào)用)的入 口點 Context 指向驅(qū)動程序確定的上下文的指針,,以將該上下文傳遞給 IoCompletion 例程 InvokeOnSuccess 指定如果 IRP 完成,且 IRP 的 IO_STATUS_BLOCK 結(jié)構(gòu)中包含成功狀態(tài)值,,是否 基于 NT_SUCCESS 宏(在 ntdef.h 中定義)的結(jié)果調(diào)用完成例程 InvokeOnError 指定如果 IRP 完成,,且 IRP 的 IO_STATUS_BLOCK 結(jié)構(gòu)中非成功狀態(tài)值,是否調(diào) 用完成例程 InvokeOnCancel 指定如果驅(qū)動程序或內(nèi)核調(diào)用 IoCancelIrp 來取消 IRP,,是否調(diào)用完成例程 IoAllocateMdl 函數(shù)用于分配 MDL 結(jié)構(gòu),,該結(jié)構(gòu)足夠?qū)μ峁┑木彌_區(qū)進行映射。驅(qū)動程序間傳輸?shù)臄?shù)據(jù)均采用 MDL 結(jié)構(gòu)的形式。驅(qū)動程序應(yīng)使用此函數(shù)分配的 MDL 調(diào)用 MmBuildMdlForNonPagedPool 以從非分頁池建立 MDL,。此外,,還可以選擇將此函數(shù)與具有 IRP 的 MDL 關(guān)聯(lián)(如果傳遞了此 IRP)。 PMDL IoAllocateMdl( IN PVOID VirtualAddress, IN ULONG Length, IN BOOLEAN SecondaryBuffer, IN BOOLEAN ChargeQuota, IN OUT PIRP Irp OPTIONAL ); 所附帶的參數(shù): VirtualAddress 指向 MDL 要描述的緩沖區(qū)的虛擬基地址的指針 Length 指定 MDL 要描述的緩沖區(qū)的長度(以字節(jié)為單位),。此值必須小于以下公式的計算值: PAGE_SIZE * (65535 - sizeof (MDL)) / sizeof(ULONG_PTR) SecondaryBuffer 指示緩沖區(qū)是主緩沖區(qū)還是次緩沖區(qū),。確定 MDL 如何鏈接到 IRP。IRP 中除 MDL 描 述的第一個緩沖區(qū)外的所有緩沖區(qū)均被視為次緩沖區(qū),。如果沒有與 MDL 關(guān)聯(lián)的 IRP,, 此字段必須為 FALSE ChargeQuota 應(yīng)由中間驅(qū)動程序設(shè)置為 FALSE。只有特定的高層驅(qū)動程序才能將此值設(shè)置為 TRUE,,應(yīng)在發(fā)出 I/O 請求以分配另一個 IRP 線程的上下文中調(diào)用此類驅(qū)動程序,。 Irp 指向與 MDL 關(guān)聯(lián)的 IRP 的指針。如果 Irp 指針非空,,所分配的 MDL 將根據(jù) SecondaryBuffer 的值與指定的 IRP 的 MDL 列表關(guān)聯(lián) IoCallDriver 會在進行調(diào)用時將經(jīng)過格式化的 IRP 請求傳遞給基礎(chǔ)驅(qū)動程序(按照在設(shè)備對象指定的方式),。在調(diào)用此函數(shù)前,調(diào)用驅(qū)動程序必須為目標驅(qū)動程序設(shè)置 I/O 堆棧位置,。(有關(guān)更多信息,,請參閱 DDK 幫助中關(guān)于將 IRP 傳遞到驅(qū)動程序棧的內(nèi)容。)調(diào)用方必須檢查返回值,,以確保已由較低層的驅(qū)動程序完成了 IRP 請求,。如果返回值不是 SUCCESS,則調(diào)用方在繼續(xù)下一個任務(wù)之前,,必須等待相應(yīng)的事件,。 NTSTATUS IoCallDriver( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ); 所附帶的參數(shù): DeviceObject 指向設(shè)備對象的指針,該對象表示所請求的 I/O 操作的目標設(shè)備 Irp 指向 IRP 的指針 返回值 IoCallDriver 返回較低層驅(qū)動程序在給定請求的 IO 狀態(tài)塊中設(shè)置的 NTSTATUS 值,; 或者,,如果請求在排隊進行進一步處理,則返回 STATUS_PENDING PIRP TdiBuildInternalDeviceControlIrp( IN CCHAR IrpSubFunction, IN PDEVICE_OBJECT DeviceObject, IN PFILE_OBJECT FileObject, IN PKEVENT Event, IN PIO_STATUS_BLOCK IoStatusBlock ); 所附帶的參數(shù): IrpSubFunction 返回與制定參數(shù)對應(yīng)的后面要處理的IRP,,參數(shù)可以為以下值: TDI_ASSOCIATE_ADDRESS The caller will pass the returned IRP to TdiBuildAssociateAddress. TDI_DISASSOCIATE_ADDRESS The caller will pass the returned IRP to TdiBuildDisassociateAddress. TDI_CONNECT The caller will pass the returned IRP to TdiBuildConnect. TDI_LISTEN The caller will pass the returned IRP to TdiBuildListen. TDI_ACCEPT The caller will pass the returned IRP to TdiBuildAccept. TDI_DISCONNECT The caller will pass the returned IRP to TdiBuildDisconnect. TDI_SEND The caller will pass the returned IRP to TdiBuildSend. TDI_RECEIVE The caller will pass the returned IRP to TdiBuildReceive. TDI_SEND_DATAGRAM The caller will pass the returned IRP to TdiBuildSendDatagram. TDI_RECEIVE_DATAGRAM The caller will pass the returned IRP to TdiBuildReceiveDatagram. TDI_SET_EVENT_HANDLER The caller will pass the returned IRP to TdiBuildSetEventHandler. TDI_QUERY_INFORMATION The caller will pass the returned IRP to TdiBuildQueryInformation. TDI_SET_INFORMATION The caller will pass the returned IRP to TdiBuildSetInformation. TDI_ACTION The caller will pass the returned IRP to TdiBuildAction. DeviceObject 設(shè)備對象 FileObject 由ObReferenceObjectByHandle指定的FileObject Event 事件指針 IoStatusBlock 指向IO_STATUS_BLOCK對象的指針 編寫TDI客戶端的還需要用到的函數(shù)有: 建立連接TdiBuildConnect 發(fā)送信息TdiBuildSend 接收信息TdiBuildReceive 關(guān)閉連接TdiBuildDisconnect 有關(guān)更多TDI的函數(shù),,請參考MSDN。實例截圖: 圖:使用TDI與WinSock進行客戶端服務(wù)器編程效果圖 實例代碼: Winsock服務(wù)端編譯環(huán)境:Microsoft Visual C++ 6.0 TDI客戶端編譯環(huán)境:WDK 7600.16385.0 測試環(huán)境:Windows XP SP3 源代碼下載:http://code.google.com/p/tdiwinsockcommunication/ 參考文獻: http://www.ibm.com/developerworks/cn...resources.html Professional.Rootkits |
|
來自: 夢醉千秋 > 《驅(qū)動內(nèi)核》