网站被挂黑链怎么删除,帮别人备案网站,工业品一站式采购平台,工业产品设计包括哪些转载请标明是引用于 http://blog.csdn.net/chenyujing1234
欢迎大家拍砖! 一、编译过程
弄了半天终于编译通过了#xff0c;看来驱动的开发确实没有应用来得简单啊。
由于DDK提供的ndis.h有4个#xff0c;什么时候要调用哪个我确实不清楚#xff1a; #xff08;1…转载请标明是引用于 http://blog.csdn.net/chenyujing1234
欢迎大家拍砖! 一、编译过程
弄了半天终于编译通过了看来驱动的开发确实没有应用来得简单啊。
由于DDK提供的ndis.h有4个什么时候要调用哪个我确实不清楚 1我先用#include d:\winddk\7600.16385.1\inc\ddk\ndis.h
结果报错了 [plain] view plain copy 11errors in directory e:\g2\fft\usbdri~1\ndismo~1\ndismo~4\driver3 11e:\g2\fft\usbdriver\ndismonitor\ndismonitor_v1-00_kernel_vs\driver3\ndishook.c(380) : error C2037: left of ProtocolNextOpen specifies undefined struct/union _NDIS_OPEN_BLOCK 11e:\g2\fft\usbdriver\ndismonitor\ndismonitor_v1-00_kernel_vs\driver3\ndishook.c(393) : error C2037: left of AdapterHandle specifies undefined struct/union _NDIS_OPEN_BLOCK 11e:\g2\fft\usbdriver\ndismonitor\ndismonitor_v1-00_kernel_vs\driver3\ndishook.c(734) : error C2037: left of ReceiveHandler specifies undefined struct/union _NDIS_OPEN_BLOCK 定位代码是在 [cpp] view plain copy NDIS_OPEN_BLOCK* GetNextOpen( IN NDIS_OPEN_BLOCK* pnobOpenBlock ) { // Return the information required. return pnobOpenBlock-ProtocolNextOpen; } 我想是因为找不到结构体NDIS_OPEN_BLOCK的定义的原因。关于此结构体请参考文章NDIS的NDIS_PROTOCOL_BLOCK和NDIS_OPEN_BLOCK的介绍。
于是在DDK包中执行ProtocolNextOpen这个变量总共出现在三个地方 怪不得会编译出错原来在
d:\winddk\7600.16385.1\inc\ddk\ndis.h中根据就没有此成员变量。
看一看以上三个含有ProtocolNextOpen的地方的定义吧
1、1D:\WINDDK\3790.1830\inc\ddk\w2k\ndis.h 1、2 D:\WINDDK\3790.1830\inc\ddk\wnet\ndis.h 1、3D:\WINDDK\3790.1830\inc\ddk\wxp\ndis.h 综上看来我们有两种可选
D:\WINDDK\3790.1830\inc\ddk\w2k\ndis.h
D:\WINDDK\3790.1830\inc\ddk\wxp\ndis.h
2试看看D:\WINDDK\3790.1830\inc\ddk\wxp\ndis.h吧
报以下错误 [plain] view plain copy 11d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(7156) : error C2011: _MAP_REGISTER_ENTRY : struct type redefinition 11d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(10163) : error C2061: syntax error : identifier W_SEND_HANDLER 11d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(10164) : error C2061: syntax error : identifier WTransferDataHandler 11d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(10164) : error C2059: syntax error : ; 11d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(10169) : error C2061: syntax error : identifier WSendPacketsHandler 11d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(10169) : error C2059: syntax error : ; 11d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(10171) : error C2061: syntax error : identifier CancelSendPacketsHandler 11d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(10171) : error C2059: syntax error : ; 11d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(10182) : error C2061: syntax error : identifier QC 这么多错误我想放弃引方案。
3试看看D:\WINDDK\3790.1830\inc\ddk\w2k\ndis.h
只有两个报错 [plain] view plain copy 11d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: _MAP_REGISTER_ENTRY : struct type redefinition 11d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: _MAP_REGISTER_ENTRY : struct type redefinition 11d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: _MAP_REGISTER_ENTRY : struct type redefinition 11d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: _MAP_REGISTER_ENTRY : struct type redefinition 11d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: _MAP_REGISTER_ENTRY : struct type redefinition 11d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: _MAP_REGISTER_ENTRY : struct type redefinition 11d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: _MAP_REGISTER_ENTRY : struct type redefinition 11d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: _MAP_REGISTER_ENTRY : struct type redefinition 3、1既然是重定义那么我把它的定义屏蔽掉吧 3、2再试看看这个错误消除了现在还剩下一个错 [plain] view plain copy 11d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(9297) : error C1083: Cannot open include file: afilter.h: No such file or directory 1Compiling - ndishook.c 11d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(9297) : error C1083: Cannot open include file: afilter.h: No such file or directory 1Compiling - vpcknt.c 11d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(9297) : error C1083: Cannot open include file: afilter.h: No such file or directory 1Compiling - ndishook.c 11d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(9297) : error C1083: Cannot open include file: afilter.h: No such file or directory 这个好解决给它指定绝对路径嘛 改进经网友xkjcf要求把绝对路径去掉
3、2、1在sources文件中添加INCLUDES路径 路径总线
A、我测试发现“工具-选项-项目解决方案-C目录-包含里设置的INCLUDE路径”与sources路径下的INCLUDE路径有优先级
其中sources中的路径有更高的优先级。
B、在sources文件中若是有多个路径且都含有同一个.h文件那么此时包哪一个是没有顺序关系的。
eg
在此sources下有 两个路径下都有usbdlib.h 文件可是我在引用它时 却引用到了后者的路径以致报错 3、2、2 再试看看哈哈^-^ 另人兴奋的.sys文件产生了。 二、源码分析 1、DriverEntry
与我数的Windows驱动的入口开发一样这里的DriverEntry没有什么特别的地方
1、1 创建设备和设备SymbolicLink名字。 [cpp] view plain copy ntStatus IoCreateDevice( DriverObject, sizeof( DEVICE_EXTENSION ), uszDriverString, FILE_DEVICE_UNKNOWN, 0, FALSE, pDeviceObject ); [cpp] view plain copy // Point uszDeviceString at the device name. RtlInitUnicodeString( uszDeviceString, L\\DosDevices\\ SYSDRIVER_NAME_WIDE ); // Create symbolic link to the user-visible name. ntStatus IoCreateSymbolicLink( uszDeviceString, uszDriverString ); 创建SymbolicLink时名字为\\DosDevices\\VPCKnt。
这里说明驱动中的SymbolicLink命名的一个特点DosDevices的符号链接名就是??, 所以\\DosDevices\\XXXX其实就是\\??\\XXXX [cpp] view plain copy TEXT(a\\\\.\VPCKnt/a), 1、2 分配派遣函数 [cpp] view plain copy DriverObject-DriverUnload VPCKernelNtDriverUnload; DriverObject-MajorFunction[ IRP_MJ_CREATE ] VPCKernelNtDispatchCreate; DriverObject-MajorFunction[ IRP_MJ_CLOSE ] VPCKernelNtDispatchClose; DriverObject-MajorFunction[ IRP_MJ_DEVICE_CONTROL ] VPCKernelNtDispatchIoctl; 以上函数是包含完成NDIS抓包的所有逻辑我们重点分析。
1、3 PDEVICE_EXTENSION扩展附加及初始化
PDEVICE_EXTENSION为我们息定义的结构体把它附加到设备象中这样以后在派遣函数中我们就可以从扩展数据中获得我们自定义的数据 [cpp] view plain copy typedef struct _DEVICE_EXTENSION { // Boolean表明是否用户态的service/application已经创建文件对象 ULONG WasCreated; FAST_MUTEX WasCreatedFastMutex; // InterceptNDIS表明是否我们不得不去中断NDIS活动 ULONG InterceptNDIS; // 关于NDIS Hook的状态信息 PNT_PROTOCOL_LIST NdisProtocolList; PNDISHOOK_HANDLER_STUB NdisStubsList; DWORD NdisStubsNum; // 客户端想要表现的Open Adapter的列表 OALIST_ITEM* OaList; DWORD OaListItems; NDIS_SPIN_LOCK OaListSpinLock; // 等待被接收的包列表 NEXT_PACKET* PacketsBuff; DWORD PacketsBuffMaxItems; DWORD PacketsBuffStart /* first allocated; -1 empty */, PacketsBuffEnd /* first free */; DWORD PacketsLost; PKEVENT PacketsReadyEvent; NDIS_SPIN_LOCK PacketsBuffSpinLock; // Loopback trick stuff. DWORD dwLtLoopbackAdapterIpAddress; // tipically: 0xA9FE1981; zero if lt is disabled. DWORD dwLtTrickNatIpAddress; // tipically: 0xA9FE1980; zero if lt is disabled. // Other. NDIS_SPIN_LOCK ReceiveWorkItemSpinLock; DWORD ReceiveWorkItemIdCounter; NDIS_SPIN_LOCK PacketSerialCounterSpinLock; DWORD PacketSerialCounter; } DEVICE_EXTENSION, *PDEVICE_EXTENSION; [cpp] view plain copy extension pDeviceObject-DeviceExtension; 初始化同步操作互斥体及其他逻辑变量 [cpp] view plain copy // Initialize WasCreated and its mutex. extension-WasCreated 0; ExInitializeFastMutex( extension-WasCreatedFastMutex ); // Initialize InterceptNDIS. extension-InterceptNDIS 0; // 初始化NDIS状态变量 extension-NdisProtocolList NULL; extension-NdisStubsList NULL; extension-NdisStubsNum 0; // 初始化OaList事件 extension-OaList NULL; extension-OaListItems 0; NdisAllocateSpinLock( extension-OaListSpinLock ); // 初始化包Buffer extension-PacketsBuff NULL; extension-PacketsBuffMaxItems 0; extension-PacketsBuffStart -1; extension-PacketsBuffEnd 0; extension-PacketsLost 0; extension-PacketsReadyEvent NULL; NdisAllocateSpinLock( extension-PacketsBuffSpinLock ); // 初始化其他res.... NdisAllocateSpinLock( extension-ReceiveWorkItemSpinLock ); extension-ReceiveWorkItemIdCounter 0; NdisAllocateSpinLock( extension-PacketSerialCounterSpinLock ); extension-PacketSerialCounter 0; // Initialize the lt stuff. extension-dwLtLoopbackAdapterIpAddress 0; extension-dwLtTrickNatIpAddress 0; 2、IRP_MJ_CREATE派遣函数VPCKernelNtDispatchCreate
此函数相对简单只是根据DeviceExtension中自定义的数据来做“仅允许一个文件对象的创建”的处理而已。
3、 IRP_MJ_CLOSE派遣函数VPCKernelNtDispatchClose
标识客户端关闭了后去做清理工作
1擦除已经分配的打开的adapters [cpp] view plain copy ReleaseOaList (); 2停止中断 [cpp] view plain copy extension-InterceptNDIS 0; 3Unhook NDIS Handler functions
Unhook NDIS其实就是重新装载原始的句柄指针在Unhook NDIS 的前后都调用KeDelayExecutionThread让CPU停下来半秒。
关于KeDelayExecutionThread请参考我的文章 DDK下的Sleep函数KeDelayExecutionThread [cpp] view plain copy KeDelayExecutionThread( UserMode, FALSE, liWaitElapse ); // Unhook NDIS Handler functions. if ( extension-NdisProtocolList ) UnhookInstalledProtocols( (PNT_PROTOCOL) ( (BYTE*) extension-NdisProtocolList sizeof( NT_PROTOCOL_LIST ) ), extension-NdisProtocolList-dwProtocolsNum, (PNT_OPEN_ADAPTER) ( (BYTE*) extension-NdisProtocolList sizeof( NT_PROTOCOL_LIST ) extension-NdisProtocolList-dwProtocolsNum * sizeof( NT_PROTOCOL ) ), extension-NdisProtocolList-dwOpenAdaptersNum ); KeDelayExecutionThread( UserMode, FALSE, liWaitElapse ); 以上UnhookIntalledProtocols函数的参数大家看得有点晕了其实这是作者对extension-NdisProtocoList的一个数据结构定义罢了 [cpp] view plain copy typedef struct _NT_PROTOCOL_LIST { // ...Info... DWORD dwProtocolsNum; DWORD dwOpenAdaptersNum; // ...Data... // // x List of NT_PROTOCOL(s) follows. // x List of NT_OPEN_ADAPTER(s) follows. // } NT_PROTOCOL_LIST, *PNT_PROTOCOL_LIST; 它的最前面是存着协议和Adapter数据的个数信息后面分别是存着协议数组和Adapter数据。 [cpp] view plain copy NTSTATUS UnhookInstalledProtocols( PNT_PROTOCOL pntpProtocols, DWORD dwProtocolsSize, PNT_OPEN_ADAPTER pntoaAdapters, DWORD dwAdaptersSize ) { DWORD i; PNT_OPEN_ADAPTER pntoaThisAdapter; // 重载原始的句柄指针. for ( i0; idwAdaptersSize; i ) { pntoaThisAdapter pntoaAdapters[ i ]; // Restore the Original Pointers. if ( pntoaThisAdapter-Original_SendHandler ) RestoreHandlerPointerSecure( pntoaThisAdapter-pobBlockPtr-SendHandler, pntoaThisAdapter-Original_SendHandler, pntoaThisAdapter-Stub_SendHandler ); if ( pntoaThisAdapter-Original_ReceiveHandler ) RestoreHandlerPointerSecure( pntoaThisAdapter-pobBlockPtr-ReceiveHandler, pntoaThisAdapter-Original_ReceiveHandler, pntoaThisAdapter-Stub_ReceiveHandler ); if ( pntoaThisAdapter-Original_PostNt31ReceiveHandler ) RestoreHandlerPointerSecure( pntoaThisAdapter-pobBlockPtr-PostNt31ReceiveHandler, pntoaThisAdapter-Original_PostNt31ReceiveHandler, pntoaThisAdapter-Stub_PostNt31ReceiveHandler ); if ( pntoaThisAdapter-Original_SendPacketsHandler ) RestoreHandlerPointerSecure( pntoaThisAdapter-pobBlockPtr-SendPacketsHandler, pntoaThisAdapter-Original_SendPacketsHandler, pntoaThisAdapter-Stub_SendPacketsHandler ); if ( pntoaThisAdapter-Original_TransferDataHandler ) RestoreHandlerPointerSecure( pntoaThisAdapter-pobBlockPtr-TransferDataHandler, pntoaThisAdapter-Original_TransferDataHandler, pntoaThisAdapter-Stub_TransferDataHandler ); if ( pntoaThisAdapter-Original_ReceivePacketHandler ) RestoreHandlerPointerSecure( pntoaThisAdapter-pobBlockPtr-ReceivePacketHandler, pntoaThisAdapter-Original_ReceivePacketHandler, pntoaThisAdapter-Stub_ReceivePacketHandler ); if ( pntoaThisAdapter-Original_TDCompleteHandler pntoaThisAdapter-pmbMiniportPtr ) RestoreHandlerPointerSecure( pntoaThisAdapter-pmbMiniportPtr-TDCompleteHandler, pntoaThisAdapter-Original_TDCompleteHandler, pntoaThisAdapter-Stub_TDCompleteHandler ); } // Return to the caller. return STATUS_SUCCESS; } 4释放内存
4、1释放协议数组中每个成员中的pbWorkItemHeader [cpp] view plain copy static VOID ReleaseReceiveWorkItems () { PDEVICE_EXTENSION extension g_pDeviceObject-DeviceExtension; int i, c; NT_PROTOCOL* pBase NULL; NT_PROTOCOL* pThis NULL; if ( extension-NdisProtocolList NULL || extension-NdisProtocolList-dwProtocolsNum 0 ) { return; } pBase (NT_PROTOCOL*) ( (BYTE*) extension-NdisProtocolList sizeof( NT_PROTOCOL_LIST ) ); NdisAcquireSpinLock( extension-ReceiveWorkItemSpinLock ); c extension-NdisProtocolList-dwProtocolsNum; for ( i0; ic; i ) { pThis pBase[ i ]; if ( pThis-pbWorkItemHeader ) { // free... ExFreePool( pThis-pbWorkItemHeader ); pThis-pbWorkItemHeader NULL; pThis-uiWorkItemHeaderSize 0; } } NdisReleaseSpinLock( extension-ReceiveWorkItemSpinLock ); } 4、2释放包Buffer [cpp] view plain copy static VOID ReleasePackets () 5、IRP_MJ_DEVICE_CONTROL派遣函数VPCKernelNtDispatchIoctl
此函数主要主是一个switch ..... case 语句case了应用程序对函数的的四种IOCTROL码。
5、1IOCTL_VPCKNT_GET_VERSION
因为Irp-AssociatedIrp.SystemBuffer指向的Buffer就是应用层得到的Out Buffer所以把版本号写到这块内存就对了。
5、2IOCTL_VPCKNT_INITIALIZE_HOOK
5、2、1分配包Buffer
分配的包的最大个数由上层决定默认是32。 [cpp] view plain copy extension-PacketsBuff (NEXT_PACKET*) ExAllocatePool( NonPagedPool, ihiHookInput.dwPacketsBuffMaxItems * sizeof( NEXT_PACKET ) ); if ( extension-PacketsBuff ) { extension-PacketsBuffMaxItems ihiHookInput.dwPacketsBuffMaxItems; memset( extension-PacketsBuff, 0, ihiHookInput.dwPacketsBuffMaxItems * sizeof( NEXT_PACKET ) ); } 5、2、2获得包准备好事件
调用ObReferenceObjectByHandle由应用层的hNotificationEvent得到对应的PKEVENT。原理参考Window XP驱动开发(二十二) 驱动程序的同步处理 [cpp] view plain copy if ( ihiHookInput.hNotificationEvent ) { NTSTATUS ntEvRes ObReferenceObjectByHandle( ihiHookInput.hNotificationEvent, 0, (POBJECT_TYPE) NULL, UserMode, (PVOID) extension-PacketsReadyEvent, (POBJECT_HANDLE_INFORMATION) NULL); if ( ntEvRes ! STATUS_SUCCESS ) extension-PacketsReadyEvent NULL; } 5、2、3注册协议并安装协议 关于这部分的内容特别重要我们将在“6、核心源码”中分析。 [cpp] view plain copy __try { nsRegRes RegisterFakeProtocol( hFakeProtocolHandle, SYSDRIVER_NAME_ANSI ); if ( nsRegRes STATUS_SUCCESS ) { nsHookRes HookInstalledProtocols( pplProtocolList, pnhhsStubsList, dwStubsNum, hFakeProtocolHandle ); } } __except ( EXCEPTION_EXECUTE_HANDLER ) { } 安装后得到Ndis Hook的结果即下图的数据结构 5、2、4把Ndis Hook的结果返回到应用程序的Out Buffer中 [cpp] view plain copy pbOutputBufferPayload (BYTE*) Irp-AssociatedIrp.SystemBuffer sizeof( ihoHookOutput ); // Inform about the Ndis Hook results. if ( nsHookRes STATUS_SUCCESS ) // NDIS Hook Ok. { // Info. ihoHookOutput.bNdisHookSucceeded 1; ihoHookOutput.dwProtocolListBufferSize sizeof( NT_PROTOCOL_LIST ) pplProtocolList-dwProtocolsNum * sizeof( NT_PROTOCOL ) pplProtocolList-dwOpenAdaptersNum * sizeof( NT_OPEN_ADAPTER ); // Data. memcpy( pbOutputBufferPayload, pplProtocolList, ihoHookOutput.dwProtocolListBufferSize ); pbOutputBufferPayload ihoHookOutput.dwProtocolListBufferSize; } else // NDIS Hook Failed. { // Info. ihoHookOutput.bNdisHookSucceeded 0; ihoHookOutput.dwProtocolListBufferSize 0; } // Copy the Header structure. * (INITIALIZE_HOOK_OUTPUT*) Irp-AssociatedIrp.SystemBuffer ihoHookOutput; 5、3IOCTL_VPCKNT_SUBMIT_OALIST
5、4IOCTL_VPCKNT_GET_NEXT_PACKET 6、核心源码分析
6、1 注册协议
注册的PROTOCOL_CHARACTERISTICS为NDIS 4.0版本的。 [cpp] view plain copy NDIS40_PROTOCOL_CHARACTERISTICS ndis40pcFakeProtCharacts; 在初始化ndis40pcFakeProtCharacts结构体时给它预留了15个自定义的函数根据实现需要可完成这15个函数的定义。 [cpp] view plain copy ndis40pcFakeProtCharacts.OpenAdapterCompleteHandler FakeProtocol_OpenAdapterComplete; ndis40pcFakeProtCharacts.CloseAdapterCompleteHandler FakeProtocol_CloseAdapterComplete; ndis40pcFakeProtCharacts.SendCompleteHandler FakeProtocol_SendComplete; ndis40pcFakeProtCharacts.TransferDataCompleteHandler FakeProtocol_TransferDataComplete; ndis40pcFakeProtCharacts.ResetCompleteHandler FakeProtocol_ResetComplete; ndis40pcFakeProtCharacts.RequestCompleteHandler FakeProtocol_RequestComplete; ndis40pcFakeProtCharacts.ReceiveHandler FakeProtocol_Receive; ndis40pcFakeProtCharacts.ReceiveCompleteHandler FakeProtocol_ReceiveComplete; ndis40pcFakeProtCharacts.StatusHandler FakeProtocol_Status; ndis40pcFakeProtCharacts.StatusCompleteHandler FakeProtocol_StatusComplete; NdisInitializeString( ndis40pcFakeProtCharacts.Name, pszProtocolName ); ndis40pcFakeProtCharacts.ReceivePacketHandler FakeProtocol_ReceivePacket; ndis40pcFakeProtCharacts.BindAdapterHandler FakeProtocol_BindAdapter; ndis40pcFakeProtCharacts.UnbindAdapterHandler FakeProtocol_UnbindAdapter; ndis40pcFakeProtCharacts.PnPEventHandler FakeProtocol_PnpEvent; ndis40pcFakeProtCharacts.UnloadHandler FakeProtocol_UnloadProtocol; 然后调用NdisRegisterProtocol注册。 6、2安装协议
6、2、1分配要求的内存
包括PNT_PROTOCOL1M作为协议数组、PNT_OPEN_ADAPTER1M作为协议Adpater 的数组、PNDISHOOK_HANDLER_STUB128K用于Hook句柄的存根 6、2、2循环访问列表协议获得已安装的列表协议句柄
循环获得协议的方法是调用GetNextProtocol函数此函数根据NDIS50_PROTOCOL_BLOCK结构体中的NextProtocol 来访问下一个协议能这样做的原因是因为协议之间是一条单链表。
这里把NDIS_HANDLE 强转为NDIS50_PROTOCOL_BLOCK类型再次说明了两者其实是同一结构的。 [cpp] view plain copy NDIS_HANDLE GetNextProtocol( IN NDIS_HANDLE hProtocolHandle ) { DWORD dwNdisVersion; NDIS50_PROTOCOL_BLOCK* pn50pbProtBlockPtr; // Return the Next Protocol in the Linked List. dwNdisVersion GetNdisVersion (); if ( dwNdisVersion 0xFFFFFFFF ) return NULL; switch( dwNdisVersion ) { case 0x00050000: case 0x00050001: // Windows 2000 / Windows XP NDIS Version. pn50pbProtBlockPtr (NDIS50_PROTOCOL_BLOCK*) hProtocolHandle; return (NDIS_HANDLE) pn50pbProtBlockPtr-NextProtocol; default: // Unrecognized NDIS Version. Exit. return NULL; } } 6、2、3根据列表协议句柄获得对应的Characteristics数据结构。 [cpp] view plain copy NDIS50_PROTOCOL_CHARACTERISTICS* GetProtocolCharacteristics( IN NDIS_HANDLE hProtocolHandle ) { DWORD dwNdisVersion; NDIS50_PROTOCOL_BLOCK* pn50pbProtBlockPtr; // Return the Protocol Characteristics information for this protocol. dwNdisVersion GetNdisVersion (); if ( dwNdisVersion 0xFFFFFFFF ) return NULL; switch( dwNdisVersion ) { case 0x00050000: case 0x00050001: // Windows 2000 / Windows XP NDIS Version. pn50pbProtBlockPtr (NDIS50_PROTOCOL_BLOCK*) hProtocolHandle; return pn50pbProtBlockPtr-ProtocolCharacteristics; default: // Unrecognized NDIS Version. Exit. return NULL; } } 从以上两步的结果中提取信息进行编号保存在协议数组中。
6、2、4从协议句柄中获得协议中打开的Adapter。
从结果中提取信息进行编号保存在协议Adapter数组中。
综合6、2、36、2、4我们得到了协议、Characteristics及协议Adapter的关系图。 6、2、5Hook处理各种Handle
6、2、5、1Hook 发送句柄
首先判断原有的SendHandler是否可以Hook
其实原理很简单因为Hook的句柄我们会存在一个区域内通过判断是否在这个区域内能判断是不是Hook过。 [cpp] view plain copy static BOOLEAN CanHook( IN PVOID fnptr ) { if ( fnptr NULL || g_pbCanHookRefMemStart NULL || g_pbCanHookRefMemEnd NULL ) // # pointer problem... return FALSE; else if ( ((BYTE*)fnptr) g_pbCanHookRefMemStart ((BYTE*)fnptr) g_pbCanHookRefMemEnd ) // # already hooked... return FALSE; else // # ok, can hook... return TRUE; } 然后填充存根代码
bPushImm32Opcode、dwOperationID、bJmpRel32Opcode分别填充固定的码值这没什么可讲
但dwJmpDisplacement值的得到有点费解若有知道的网友可否告诉我一下 [cpp] view plain copy static void FillStubCode( PNDISHOOK_HANDLER_STUB pnhhsThisStub, DWORD dwThisAdapterOrd, DWORD dwAddInfo ) { // Fill the Stub structure. pnhhsThisStub-bPushImm32Opcode 0x68; pnhhsThisStub-dwOperationID ( dwThisAdapterOrd 0x10 ) | dwAddInfo; pnhhsThisStub-bJmpRel32Opcode 0xE9; pnhhsThisStub-dwJmpDisplacement (DWORD) HandlerGeneralDispatcher - ( (DWORD) pnhhsThisStub FIELD_OFFSET( NDISHOOK_HANDLER_STUB, bJmpRel32Opcode ) ) - 5; } !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!重点中的重点改日讲解 [cpp] view plain copy static PVOID g_vpvHandlersVector[] { New_SendHandler, // SENDHANDLER_FNID New_ReceiveHandler, // RECEIVEHANDLER_FNID New_PostNt31ReceiveHandler, // POSTNT31RECEIVEHANDLER_FNID New_SendPacketsHandler, // SENDPACKETSHANDLER_FNID New_TransferDataHandler, // TRANSFERDATAHANDLER_FNID New_ReceivePacketHandler, // RECEIVEPACKETHANDLER_FNID New_TDCompleteHandler // TDCOMPLETEHANDLER_FNID }; [cpp] view plain copy static void __declspec(naked) HandlerGeneralDispatcher ( void ) { __asm { // ### Load in EAX and ECX the Code found in the Stack. ### mov eax, dword ptr[ esp ] // eax Code: 0xYYYYZZZZ. (y Adapter Ordinal, z Handler Ordinal.) mov ecx, eax // ecx Code: 0xYYYYZZZZ. shr eax, 0x10 // eax 0x0000YYYY and ecx, 0xFFFF // ecx 0x0000ZZZZ mov dword ptr[ esp ], eax // Updates Code in Stack: 0x0000YYYY // ### Call the appropriate Handler based on the Handler Ordinal. ### lea eax, [ offset g_vpvHandlersVector ecx * 4 ]; call dword ptr[ eax ] // ### Pop in ECX the HookPrivateStorage parameter. ### pop ecx // ### Check whether we have to call the Original Handler or we have to return control to the Caller. ### cmp ecx, 0x1000 ja callOriginalHandler // ### Return the Control to the Caller. ### pop edx add esp, ecx jmp edx callOriginalHandler: // ### Call the Original Handler. ### jmp ecx } } 最后将记录原有的发送句柄后目的是在UnhookInstalledProtocols时能重载原始句柄指指将自己的发送Handle附加到原有的发送句柄上。 [cpp] view plain copy pntoaThisAdapter-Original_SendHandler pobAdapter-SendHandler; pntoaThisAdapter-Stub_SendHandler pnhhsThisStub; pobAdapter-SendHandler (SEND_HANDLER) pnhhsThisStub; 这样pobAdapter-SendHandler 就会调用我们自定义的New_SendHandler函数了。关于它的处理我们在“7、 自定义处理函数讲解”中进行讲解。 6、2、5、2Hook 接收句柄
与Hook 发送句柄类似。
6、2、5、3Hook postnt31接收句柄
与Hook 发送句柄类似。
6、2、5、4Hook 发送包句柄
与Hook 发送句柄类似。
6、2、5、5Hook 传送数据句柄
与Hook 发送句柄类似。
6、2、5、6Hook 接收包句柄
与Hook 发送句柄类似。
6、2、5、6Hook 传送数据完成句柄
与Hook 发送句柄类似。 7、自定义处理函数的讲解
7、1New_SendHandler 以入参HookPrivateStorage来标识哪一协议哪一Adapter
如果判断如果需要中断NDIS请求那么就调用Intercept_SendHandler将此数据包进行截获
截获完成后根据返回结果判断是否要将原始的处句柄返回回去默认是需要将原始句柄返回这样我们截获了包后此包能再次发送出去。 [cpp] view plain copy NDIS_STATUS __cdecl New_SendHandler( IN OUT DWORD HookPrivateStorage, IN OUT DWORD CallingFnRetAddress, IN OUT NDIS_HANDLE MacBindingHandle, IN OUT PNDIS_PACKET Packet ) { NDIS_STATUS nsRetStatus NDIS_STATUS_SUCCESS; SEND_HANDLER pfnOriginal NULL; DWORD OpenAdapterId HookPrivateStorage; PDEVICE_EXTENSION pdeExtension g_pDeviceObject-DeviceExtension; BOOLEAN bExecuteOriginalHandler TRUE; // Get a pointer to the Original Handler. pfnOriginal g_pntoaAdapters[ OpenAdapterId ].Original_SendHandler; // Check if we have to intercept the NDIS Request. if ( pdeExtension-InterceptNDIS ) bExecuteOriginalHandler Intercept_SendHandler( g_pntpProtocols[ g_pntoaAdapters[ OpenAdapterId ].dwProtocolOrd ], g_pntoaAdapters[ OpenAdapterId ], nsRetStatus, MacBindingHandle, Packet ); // Make call the Original Handler and return. if ( bExecuteOriginalHandler ) HookPrivateStorage (DWORD) pfnOriginal; // Original Handler. else HookPrivateStorage 2 * 0x4; // Passed Parameters Size. return nsRetStatus; } 7、1、1在Intercept_SendHandler里先判断此Adapter是不是要被处理 [cpp] view plain copy // process. if ( HaveToProcess( pnoaAdapter ) ) { 判断原理是判断它是不是在OaList列表中。
7、1、2如果判断此Adapter是需要处理的那么就调用NdisPacket2MemoryRegion为此包分配分内存。
首先调用系统API NdisQueryPacket查询此PNDIS_PACKET包的PNDIS_BUFFER和总共的内存大小。 [cpp] view plain copy NdisQueryPacket( Packet, NULL, NULL, pnbCurrent, uiTotalSize ); 然后根据PNDIS_PACKET包的内存大小及我们要添加的头的大小算出自定义包所需要的内存大小 [cpp] view plain copy ulMemSize ulHeaderBufferSize uiTotalSize; if ( ulMemSize 0 ) return NULL; pbMem (BYTE*) ExAllocatePool( NonPagedPool, ulMemSize ); if ( pbMem NULL ) return NULL; 最后把输入的包的BUFFER复制到我们自定义的内存中。 [cpp] view plain copy while( pnbCurrent ) { NdisQueryBuffer( pnbCurrent, pvPtr, uiPtrDim ); if ( pvPtr NULL || uiCount uiPtrDim uiTotalSize ) { ExFreePool( pbMem ); return NULL; } else { memcpy( pbMem uiCount, pvPtr, uiPtrDim ); uiCount uiPtrDim; } NdisGetNextBuffer( pnbCurrent, pnbCurrent ); } 7、1、3把从7、1、2中得到的自定义数据内存保存到extern的包队列中并通过事件告知应用程序可以取包了。 [cpp] view plain copy VOID QueuePacket( IN PNT_OPEN_ADAPTER pnoaAdapter, IN BYTE* pbData, IN DWORD dwDataSize, BYTE bDirection, DWORD dwSerial ) { PDEVICE_EXTENSION extension g_pDeviceObject-DeviceExtension; // add. NdisAcquireSpinLock( extension-PacketsBuffSpinLock ); if ( extension-PacketsBuff extension-PacketsBuffMaxItems ) { NEXT_PACKET* pThis extension-PacketsBuff[ extension-PacketsBuffEnd ]; // // manage the circular buffer. // // compare end and start. if ( extension-PacketsBuffEnd extension-PacketsBuffStart ) { // ### free ### if ( pThis-pbData ) ExFreePool( pThis-pbData ); // ### inc counter ### extension-PacketsLost ; // ### inc start pos ### extension-PacketsBuffStart ; if ( extension-PacketsBuffStart extension-PacketsBuffMaxItems ) extension-PacketsBuffStart 0; } // inc end pos. extension-PacketsBuffEnd ; if ( extension-PacketsBuffEnd extension-PacketsBuffMaxItems ) extension-PacketsBuffEnd 0; if ( extension-PacketsBuffStart -1 ) extension-PacketsBuffStart 0; // // fill this one. // pThis-dwOpenAdapterOrdinal pnoaAdapter-dwOrdinal; pThis-dwPacketSerial dwSerial; pThis-pbData pbData; pThis-dwDataLength dwDataSize; pThis-bDirection bDirection; // // set the user event. // if ( extension-PacketsReadyEvent ) KeSetEvent( extension-PacketsReadyEvent, 0, FALSE ); } NdisReleaseSpinLock( extension-PacketsBuffSpinLock ); // return. return; } 7、1、4如果是ARP或IP协议那么发送包回到协议 [cpp] view plain copy VOID SendPacketHook( IN PNT_PROTOCOL pnpProtocol, IN PNT_OPEN_ADAPTER pnoaAdapter, IN BYTE* pbData, IN DWORD dwDataSize )