您的位置:首页 > 理论基础 > 计算机网络

NDIS网络数据监控程序NDISMonitor(1)-----驱动程序(编译过程与源码讲解)

2014-06-21 23:36 489 查看
转载请标明是引用于 http://blog.csdn.net/chenyujing1234 

欢迎大家拍砖!

 

一、编译过程

弄了半天终于编译通过了,看来驱动的开发确实没有应用来得简单啊。

由于DDK提供的ndis.h有4个,什么时候要调用哪个我确实不清楚:



(1)我先用#include <d:\winddk\7600.16385.1\inc\ddk\ndis.h>

结果报错了:

[plain]
view plaincopy

1>1>errors in directory e:\g2\fft\usbdri~1\ndismo~1\ndismo~4\driver3  
1>1>e:\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'  
1>1>e:\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'  
1>1>e:\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 plaincopy

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、1)D:\WINDDK\3790.1830\inc\ddk\w2k\ndis.h



(1、2) D:\WINDDK\3790.1830\inc\ddk\wnet\ndis.h



(1、3)D:\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 plaincopy

1>1>d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(7156) : error C2011: '_MAP_REGISTER_ENTRY' : 'struct' type redefinition  
1>1>d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(10163) : error C2061: syntax error : identifier 'W_SEND_HANDLER'  
1>1>d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(10164) : error C2061: syntax error : identifier 'WTransferDataHandler'  
1>1>d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(10164) : error C2059: syntax error : ';'  
1>1>d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(10169) : error C2061: syntax error : identifier 'WSendPacketsHandler'  
1>1>d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(10169) : error C2059: syntax error : ';'  
1>1>d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(10171) : error C2061: syntax error : identifier 'CancelSendPacketsHandler'  
1>1>d:\winddk\3790.1830\inc\ddk\wxp\ndis.h(10171) : error C2059: syntax error : ';'  
1>1>d:\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 plaincopy

1>1>d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: '_MAP_REGISTER_ENTRY' : 'struct' type redefinition  
1>1>d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: '_MAP_REGISTER_ENTRY' : 'struct' type redefinition  
1>1>d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: '_MAP_REGISTER_ENTRY' : 'struct' type redefinition  
1>1>d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: '_MAP_REGISTER_ENTRY' : 'struct' type redefinition  
1>1>d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: '_MAP_REGISTER_ENTRY' : 'struct' type redefinition  
1>1>d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: '_MAP_REGISTER_ENTRY' : 'struct' type redefinition  
1>1>d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: '_MAP_REGISTER_ENTRY' : 'struct' type redefinition  
1>1>d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(5567) : error C2011: '_MAP_REGISTER_ENTRY' : 'struct' type redefinition  

(3、1)既然是重定义,那么我把它的定义屏蔽掉吧:



(3、2)再试看看,这个错误消除了,现在还剩下一个错:

[plain]
view plaincopy

1>1>d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(9297) : error C1083: Cannot open include file: 'afilter.h': No such file or directory  
1>Compiling - ndishook.c  
1>1>d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(9297) : error C1083: Cannot open include file: 'afilter.h': No such file or directory  
1>Compiling - vpcknt.c  
1>1>d:\winddk\3790.1830\inc\ddk\w2k\ndis.h(9297) : error C1083: Cannot open include file: 'afilter.h': No such file or directory  
1>Compiling - ndishook.c  
1>1>d:\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 plaincopy

ntStatus = IoCreateDevice( DriverObject,  
        sizeof( DEVICE_EXTENSION ),  
        & uszDriverString,  
        FILE_DEVICE_UNKNOWN,  
        0,  
        FALSE,  
        & pDeviceObject );  

 

[cpp]
view plaincopy

// 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 plaincopy

TEXT(<a>\\\\.\VPCKnt</a>),   

1、2   分配派遣函数

[cpp]
view plaincopy

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 plaincopy

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 plaincopy

extension = pDeviceObject->DeviceExtension;  

 

初始化同步操作互斥体及其他逻辑变量:

[cpp]
view plaincopy

// 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 plaincopy

ReleaseOaList ();  

(2)停止中断;

[cpp]
view plaincopy

extension->InterceptNDIS = 0;  

(3)Unhook NDIS Handler functions;

Unhook NDIS其实就是重新装载原始的句柄指针,在Unhook NDIS 的前后都调用KeDelayExecutionThread让CPU停下来半秒。

关于KeDelayExecutionThread请参考我的文章: <<DDK下的Sleep函数KeDelayExecutionThread>>

[cpp]
view plaincopy

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 plaincopy

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 plaincopy

NTSTATUS UnhookInstalledProtocols( PNT_PROTOCOL pntpProtocols, DWORD dwProtocolsSize, PNT_OPEN_ADAPTER pntoaAdapters, DWORD dwAdaptersSize )  
{  
    DWORD               i;  
    PNT_OPEN_ADAPTER    pntoaThisAdapter;  
  
    // 重载原始的句柄指针.  
    for ( i=0; i<dwAdaptersSize; 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 plaincopy

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 ( i=0; i<c; 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 plaincopy

static VOID ReleasePackets ()  

 

5、IRP_MJ_DEVICE_CONTROL派遣函数VPCKernelNtDispatchIoctl

此函数主要主是一个switch ..... case 语句,case了应用程序对函数的的四种IOCTROL码。

(5、1)IOCTL_VPCKNT_GET_VERSION

因为Irp->AssociatedIrp.SystemBuffer指向的Buffer就是应用层得到的Out Buffer,所以把版本号写到这块内存就对了。

(5、2)IOCTL_VPCKNT_INITIALIZE_HOOK

(5、2、1)分配包Buffer

分配的包的最大个数,由上层决定,默认是32。

[cpp]
view plaincopy

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 plaincopy

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 plaincopy

__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 plaincopy

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、3)IOCTL_VPCKNT_SUBMIT_OALIST

(5、4)IOCTL_VPCKNT_GET_NEXT_PACKET

 

 6、核心源码分析

(6、1) 注册协议

注册的PROTOCOL_CHARACTERISTICS为NDIS 4.0版本的。

[cpp]
view plaincopy

NDIS40_PROTOCOL_CHARACTERISTICS     ndis40pcFakeProtCharacts;  

在初始化ndis40pcFakeProtCharacts结构体时给它预留了15个自定义的函数,根据实现需要可完成这15个函数的定义。

[cpp]
view plaincopy

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_PROTOCOL(1M,作为协议数组)、PNT_OPEN_ADAPTER(1M,作为协议Adpater 的数组)、PNDISHOOK_HANDLER_STUB(128K,用于Hook句柄的存根)

 (6、2、2)循环访问列表协议,获得已安装的列表协议句柄;

循环获得协议的方法是调用GetNextProtocol函数,此函数根据NDIS50_PROTOCOL_BLOCK结构体中的NextProtocol 来访问下一个协议,能这样做的原因是因为协议之间是一条单链表。

这里把NDIS_HANDLE 强转为NDIS50_PROTOCOL_BLOCK类型,再次说明了两者其实是同一结构的。

[cpp]
view plaincopy

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 plaincopy

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、3)(6、2、4)我们得到了协议、Characteristics及协议Adapter的关系图。



 (6、2、5)Hook处理各种Handle

(6、2、5、1)Hook 发送句柄

首先判断原有的SendHandler是否可以Hook:

其实原理很简单,因为Hook的句柄我们会存在一个区域内,通过判断是否在这个区域内能判断是不是Hook过。

[cpp]
view plaincopy

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 plaincopy

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 plaincopy

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 plaincopy

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 plaincopy

pntoaThisAdapter->Original_SendHandler = pobAdapter->SendHandler;  
                            pntoaThisAdapter->Stub_SendHandler = pnhhsThisStub;  
                            pobAdapter->SendHandler = (SEND_HANDLER) pnhhsThisStub;  

这样pobAdapter->SendHandler  就会调用我们自定义的New_SendHandler函数了。关于它的处理我们在“7、   自定义处理函数讲解”中进行讲解。

 

(6、2、5、2)Hook 接收句柄

与Hook 发送句柄类似。

(6、2、5、3)Hook postnt31接收句柄

与Hook 发送句柄类似。

(6、2、5、4)Hook 发送包句柄

与Hook 发送句柄类似。

(6、2、5、5)Hook 传送数据句柄

与Hook 发送句柄类似。

(6、2、5、6)Hook 接收包句柄

与Hook 发送句柄类似。

(6、2、5、6)Hook 传送数据完成句柄

与Hook 发送句柄类似。

 

 7、自定义处理函数的讲解

(7、1)New_SendHandler

 以入参HookPrivateStorage来标识哪一协议,哪一Adapter;

如果判断如果需要中断NDIS请求,那么就调用Intercept_SendHandler将此数据包进行截获;

截获完成后,根据返回结果判断是否要将原始的处句柄返回回去(默认是需要将原始句柄返回),这样我们截获了包后此包能再次发送出去。

[cpp]
view plaincopy

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 plaincopy

// process.  
    if ( HaveToProcess( pnoaAdapter ) )  
    {  

判断原理是判断它是不是在OaList列表中。

(7、1、2)如果判断此Adapter是需要处理的那么就调用NdisPacket2MemoryRegion为此包分配分内存。

首先调用系统API NdisQueryPacket查询此PNDIS_PACKET包的PNDIS_BUFFER和总共的内存大小。

[cpp]
view plaincopy

NdisQueryPacket( Packet,  
        NULL, NULL,  
        & pnbCurrent,  
        & uiTotalSize );  

然后根据PNDIS_PACKET包的内存大小及我们要添加的头的大小算出自定义包所需要的内存大小:

[cpp]
view plaincopy

ulMemSize = ulHeaderBufferSize + uiTotalSize;  
    if ( ulMemSize == 0 )  
        return NULL;  
  
    pbMem = (BYTE*) ExAllocatePool( NonPagedPool, ulMemSize );  
    if ( pbMem == NULL )  
        return NULL;  

最后把输入的包的BUFFER复制到我们自定义的内存中。

[cpp]
view plaincopy

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 plaincopy

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 plaincopy

VOID SendPacketHook( IN PNT_PROTOCOL pnpProtocol, IN PNT_OPEN_ADAPTER pnoaAdapter, IN BYTE* pbData, IN DWORD dwDataSize )  

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐