来源:远方网络 | 2005-4-10 17:23:15 | (有2029人读过)
sevencat: 网卡的混杂模式好像要通过NDIS设置。 下面是转贴的。 哪位UP一下,我来贴完。 一、驱动开发网 作者:gjpland 看到很多仁兄提供的数据包的拦截技术,其中最多的是编写IM DRIVER在NDIS中间层 对MINIPORT(网卡驱动程序)和协议驱动程序之间的数据包进行拦截。这是微软提供的一种技术
但编写该过滤程序拦截程序非常的复杂,安装也很麻烦。
本人简单的介绍一种更有效的基于NDIS包拦截技术。
大家都知道,NDIS协议驱动程序是通过填写一张NDIS_PROTOCOL_CHARACTERISTICS的表
,并调用NDIS API 函数NdisRegisterProtocol进行注册。现在我们来关注一下NDIS_PROTOCOL_CHARACTERI
STICS这张表, 这张表中存有所有协议驱动程序与底层的派发函数的入口。如SendHandler,ReceiveHandler,Bi
ndAdapterHandler等, 当网卡有数据包进入时,会通过表中ReceiveHandle 或ReceivePacketHandler通知协议驱动程
序有一个该协议 的数据包进入,反之协议驱动程序是通过SendHandler或SendPacketsHandler函数向网卡驱动
发送数据包到网络 上去的,有人会奇怪程序中明明不是调用NdisSend或NdisSendPackets函数发送的吗?没错,
是这样的, 但是你可以看一下NDIS.H的头文件里对这两个函数的定义就知道了,他们都是一个 宏定义,实际还是通过这表中SendHandler或SendPacketsHandler发送的。
现在我们所要做的事情应该很清楚了,只要我们能够将每一个协议程序所填写的NDIS_PROTOCO
L_CHARACTERISTICS 表里的派发函数指向自己的函数,我们就能成功的对数据包进行拦截。那么每个协议驱动程序的这张
表到底存放在 那里呢?太简单了,看一下下面的我对NdisRegisterProtocol重新给出的原型就很明白了。
struct _NDIS_PROTOCOL_BLOCK { PNDIS_OPEN_BLOCK OpenQueue; // queue of opens for this protocol REFERENCE Ref; // contains spinlock for OpenQueue UINT Length; // of this NDIS_PROTOCOL_BLOCK struct NDIS50_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics;// handler
addresses
struct _NDIS_PROTOCOL_BLOCK * NextProtocol; // Link to next ULONG MaxPatternSize; #if defined(NDIS_WRAPPER) // // Protocol filters // struct _NDIS_PROTOCOL_FILTER * ProtocolFilter[NdisMediumMax+1]; WORK_QUEUE_ITEM WorkItem; // Used during NdisRegisterProtocol to // notify protocols of existing drivers. KMUTEX Mutex; // For serialization of Bind/Unbind requests PKEVENT DeregEvent; // Used by NdisDeregisterProtocol #endif }; typedef struct _NDIS_PROTOCOL_BLOCK NDIS_PROTOCOL_BLOCK,
*PNDIS_PROTOCOL_BLOCK;
EXPORT VOID NdisRegisterProtocol( OUT PNDIS_STATUS Status, OUT PNDIS_PROTOCOL_BLOCK NdisProtocolHandle, /*注意NDIS_HANDLE所指向的
就是PNDIS_PROTOCOL_BLOCK的结构,不要有什么怀疑。*/ IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics, IN UINT CharacteristicsLength );
NDIS_PROTOCOL_BLOCK(协议表)
是NDIS维护所有系统中已注册协义的单向链接表。字段NextProtocol指向下一个协议表。 庆幸的是,当我们注册一新的协议时,NDIS总是会把新注册的协义放在链表的头并返回这张表,
所以只要我们注册一个新的协议 通过新协议注册返回的链表头就可以轻而易举的遍历系统中所有协议表.现在我们所希望得到的每个
协议的 NDIS_PROTOCOL_CHARACTERISTICS表就放在我们面前了,如何勾挂表中的派发函数,我
想不必多说了吧。顺便说一句 NDISREGISTERPROTOCOL为NDIS_PROTOCOL_BLOCK所分配的内存是NonPagedPool
类型的。对于核心DRIVER来说,核心区内存 是一个线性的内存区,所有核心DRIVER是可以随便访问核心内存区的任意地址。所要注意的是不
同IRQL级别下对分页 和非分页内存。
有人会问这样就行了吗?真的拦截下来了吗?如果有那位仁兄心急现在就写程序的话, 准会失望的,因为他会发现结果什么东西都没拦截到或偶而会拦截到一些数据包。为什么? 因为NDIS网卡驱动和协议驱动在发送和接收到数居时并不是调用PNDIS_OPEN_BLOCK->Proto
colCharacteristics 里的派发函数。怎么办? 有必要先介绍一下NDIS网卡驱动和协议驱动之间是如何BINDING 的吧, NdisRegisterProtocol在注册完一个协议后,不久NDIS会通过调用表中 BindAdapterHandler派发函数,通知协议对每一个网卡进行BINDING。或者当系统通PNP找到
一块新的网卡时 也会调用BindAdapterHandler对协议进行BINDING。协议在BINDING 调用里,会根据自己的
需要使用NdisOpenAdapter 将自身绑定到适合的网卡。并返回NdisBindingHandle.NdisBindingHandle是什么?NdisBin
dingHandl其实是 指向NDIS_OPEN_BLOCK表的一根指针,那么NDIS_OPEN_BLOCK表有什么用呢?当协议顺
利的绑定后,每个绑定的网卡 和每一个协议之间建立了数据传输的通道,而NDIS_OPEN_BLOCK就是用来维护这一数据通道的
表。 struct _NDIS_OPEN_BLOCK { PNDIS_MAC_BLOCK MacHandle; // pointer to our MAC NDIS_HANDLE MacBindingHandle; // context when calling MacXX funcs PNDIS_ADAPTER_BLOCK AdapterHandle; // pointer to our adapter PNDIS_PROTOCOL_BLOCK ProtocolHandle; // pointer to our protocol NDIS_HANDLE ProtocolBindingContext;// context when calling ProtXX funcs PNDIS_OPEN_BLOCK AdapterNextOpen; // used by adapter's OpenQueue PNDIS_OPEN_BLOCK ProtocolNextOpen; // used by protocol's OpenQueue PFILE_OBJECT FileObject; // created by operating system BOOLEAN Closing; // TRUE when removing this struct BOOLEAN Unloading; // TRUE when processing unload BOOLEAN NoProtRsvdOnRcvPkt; // Reflect the protocol_options NDIS_HANDLE CloseRequestHandle; // 0 indicates an internal close KSPIN_LOCK SpinLock; // guards Closing PNDIS_OPEN_BLOCK NextGlobalOpen;
// // These are optimizations for getting to MAC routines. They are not // necessary, but are here to save a dereference through the MAC block. // SEND_HANDLER SendHandler; TRANSFER_DATA_HANDLER TransferDataHandler;
// // These are optimizations for getting to PROTOCOL routines. They are not // necessary, but are here to save a dereference through the PROTOCOL block. // SEND_COMPLETE_HANDLER SendCompleteHandler; TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler; RECEIVE_HANDLER ReceiveHandler; RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler;
// // Extentions to the OPEN_BLOCK since Product 1. // RECEIVE_HANDLER PostNt31ReceiveHandler; RECEIVE_COMPLETE_HANDLER PostNt31ReceiveCompleteHandler;
// // NDIS 4.0 extensions // RECEIVE_PACKET_HANDLER ReceivePacketHandler; SEND_PACKETS_HANDLER SendPacketsHandler;
// // More NDIS 3.0 Cached Handlers // RESET_HANDLER ResetHandler; REQUEST_HANDLER RequestHandler;
// // Needed for PnP // UNICODE_STRING AdapterName; // Upcased name of the adapter we are bound to };
上面的表结构可以很清楚的看到这张表是一个单向链接表,并且存放了和PNDIS_OPEN_BLOCK-
>ProtocolCharacteristics 一样的数据收发派发函数,当第N块网卡发送数据包到第N个协议时,就会调用第N个协议与第N个
网卡之间建立的 NDIS_OPEN_BLOCK表里的SendHandler或SendPacketHandler。所以我们还需要对这张表
里的派发函数进行处理(勾挂)。 那么又如何勾挂协议与网卡之间的NDIS_OPEN_BLOCK表呢。我们再回到NDIS_PROTOCOL_
BLOCK这张表中,在 NDIS_PROTOCOL_BLOCK表中字段PNDIS_OPEN_BLOCK OpenQueue;就是所有该协议所
有NDIS_OPEN_BLOCK的表头。 通过AdapterNextOpen遍历一下,再勾挂一把。就可以顺利拦截了。
值得注意的是。 1。 NDIS_OPEN_BLOCK NDIS_PROTOCOL_BLOCK 这些结构不同NDIS版本是不同的, 解决方法是在windows 98和windows95下(ndis 3.1)使用windows98ddk 带的NDIS.H 里的
定义 在windows me下(ndis 5.0或4。0)请使用WINDOWS 98ddk里NDIS.H里的定义 nt(ndis4.0)用NTDDK里的定议,以此类推,2000(ndis5.0) 2。不要重复勾挂同一个函数。
有问题可以通过 QQ:3955727 mail:gjpland@netease.com
// //Protocol Wrapper Version 1.05 //Author: gjp //email: gjpland@netease.com //
#include "NdisHook.h" #include "HookRule.h"
#pragma pack(push) #pragma pack(1) typedef struct _HOOK_CONTEXT_STRUCT { //runtime code ubyte code1_0x58; //0x58 | pop eax | pop caller IP from stack to
eax ubyte code2_0x68; //0x68 | push IMM | push our hook context
address struct _HOOK_CONTEXT_STRUCT *m_pHookContext;//point this ubyte code3_0x50; //0x50 | push eax | push caller
IP from eax to stack ubyte code4_0xE9; //0xE9 | jmp HookProc | jump our hook proc udword m_pHookProcOffset;
//our context data
PVOID m_pOriginalProc; PVOID m_pHookProc; PVOID m_pBindAdaptHandle; PVOID m_pProtocolContent; PVOID *m_ppOriginPtr;
struct _HOOK_CONTEXT_STRUCT *m_pHookNext;
}HOOK_CONTEXT_STRUCT; #pragma pack(pop)
HOOK_CONTEXT_STRUCT *m_pOurAllOfHookContext = NULL;
dword m_IsFilterEnabled = FALSE; NDIS_HANDLE m_ourPacketPoolHandle = NULL; NDIS_HANDLE m_ourBufferPoolHandle = NULL; PNDIS_PACKET m_ourPacketHandle = NULL; PNDIS_BUFFER m_ourBufferHandle = NULL; PVOID m_ourBuffer = NULL;
void ReadPacket(PNDIS_PACKET Packet,PVOID pBuffer,udword dwBufSize); uword wswap(uword value);
void HookUnload(void) { ReleaseHookFunc();
if( m_ourBufferHandle ) { NdisFreeBuffer(m_ourBufferHandle); m_ourBufferHandle = NULL; } if( m_ourBuffer ) { NdisFreeMemory(m_ourBuffer,MAX_PACKET_SIZE,0); m_ourBuffer = NULL; } if( m_ourPacketHandle ) { NdisFreePacket(m_ourPacketHandle); m_ourPacketHandle = NULL; } if( m_ourBufferPoolHandle ) { NdisFreeBufferPool(m_ourBufferPoolHandle); m_ourBufferPoolHandle = NULL; } if( m_ourPacketPoolHandle ) { NdisFreePacketPool(m_ourPacketPoolHandle); m_ourPacketPoolHandle = NULL; } return; } dword HookInit(void) { NTSTATUS status;
m_ourPacketPoolHandle = NULL; NdisAllocatePacketPool(&status,&m_ourPacketPoolHandle,0xFFF,0x10); if( status != NDIS_STATUS_SUCCESS ) return FALSE;
m_ourBufferPoolHandle = NULL; NdisAllocateBufferPool(&status,&m_ourBufferPoolHandle,0x10); if( status != NDIS_STATUS_SUCCESS ) return FALSE;
m_ourBuffer = NULL; status =
NdisAllocateMemoryWithTag(&m_ourBuffer,MAX_PACKET_SIZE,'NAMW'); if( status != NDIS_STATUS_SUCCESS ) return FALSE;
m_ourBufferHandle = NULL;
NdisAllocateBuffer(&status,&m_ourBufferHandle,m_ourBufferPoolHandle,m_ourBuff
er,MAX_PACKET_SIZE); if( status != NDIS_STATUS_SUCCESS ) return FALSE;
m_ourPacketHandle = NULL;
NdisAllocatePacket(&status,&m_ourPacketHandle,m_ourPacketPoolHandle); if( status != NDIS_STATUS_SUCCESS ) return FALSE;
NdisChainBufferAtFront(m_ourPacketHandle,m_ourBufferHandle); return TRUE; }
typedef struct _NDIS41_PROTOCOL_CHARACTERISTICS { #ifdef __cplusplus NDIS40_PROTOCOL_CHARACTERISTICS Ndis40Chars; #else NDIS40_PROTOCOL_CHARACTERISTICS; #endif
// // Start of NDIS 4.1 extensions. //
CO_SEND_COMPLETE_HANDLER
CoSendCompleteHandler; CO_STATUS_HANDLER
CoStatusHandler; CO_RECEIVE_PACKET_HANDLER
CoReceivePacketHandler; CO_REQUEST_HANDLER
CoRequestHandler; CO_REQUEST_COMPLETE_HANDLER
CoRequestCompleteHandler;
} NDIS41_PROTOCOL_CHARACTERISTICS;
dword HookProtocol(void) { //Default ndis version is 5.0 NDIS_PROTOCOL_CHARACTERISTICS ourNPC; NDIS_STRING protoName = NDIS_STRING_CONST("HdFw_Slot"); NDIS_STATUS Status; NDIS_HANDLE ourProtocolHandle = NULL; byte *ProtocolChain; dword offset; dword len;
// NDIS_PROTOCOL_BLOCK *pNdisBlock = NULL;
// pNdisBlock = pNdisBlock->NextProtocol; // pNdisBlock->NextProtocol = NULL;
memset(&ourNPC,0,sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
if( m_dwMajorVersion == 0x03 ) { len = sizeof(NDIS30_PROTOCOL_CHARACTERISTICS); //We must need at least ndis version 3.10 ourNPC.MajorNdisVersion = 0x03; ourNPC.MinorNdisVersion = 0x0A; } else if( m_dwMajorVersion == 0x04 ) { len = sizeof(NDIS40_PROTOCOL_CHARACTERISTICS);
ourNPC.MajorNdisVersion = 0x04; ourNPC.MinorNdisVersion = 0x00; } else { //treat as version 5.0 len = sizeof(NDIS50_PROTOCOL_CHARACTERISTICS); ourNPC.MajorNdisVersion = 0x05; ourNPC.MinorNdisVersion = 0x00; }
ourNPC.Name = protoName; ourNPC.OpenAdapterCompleteHandler = PtOpenAdapterComplete; ourNPC.CloseAdapterCompleteHandler = PtCloseAdapterComplete; ourNPC.SendCompleteHandler = PtSendComplete; ourNPC.TransferDataCompleteHandler = PtTransferDataComplete; ourNPC.ResetCompleteHandler = PtResetComplete; ourNPC.RequestCompleteHandler = PtRequestComplete; ourNPC.ReceiveHandler = PtReceive; ourNPC.ReceiveCompleteHandler = PtReceiveComplete; ourNPC.StatusHandler = PtStatus; ourNPC.StatusCompleteHandler = PtStatusComplete; ourNPC.BindAdapterHandler = PtBindAdapter; ourNPC.UnbindAdapterHandler = PtUnbindAdapter; ourNPC.UnloadHandler = PtUnload; ourNPC.ReceivePacketHandler = PtReceivePacket; ourNPC.PnPEventHandler = PtPNPHandler;
NdisRegisterProtocol(&Status,&ourProtocolHandle,&ourNPC,len); if( !NT_SUCCESS(Status) || ourProtocolHandle == NULL ) return FALSE;
//NdisRegisterProtocol return hand reference of
NDIS_PROTOCOL_BLOCK; ProtocolChain = (byte *)ourProtocolHandle; while(1) { DebugInfoCount++;
//Obtain pointer to next protocol link. if( m_dwMajorVersion == 0x03 ) offset = 4; else if( m_dwMajorVersion == 0x04 ) { if( m_dwMinorVersion == 0x01 ) offset = 0x8C; else offset = 0x60; } else if( m_dwMajorVersion == 0x05 ) //NDIS_PROTOCOL_BLOCK->NextProtocol offset = 0x10; else //Error break;
ProtocolChain = ((byte **)(ProtocolChain + offset))[0]; if( ProtocolChain == NULL ) break;
HookFuncBlock(ProtocolChain); } if( m_dwMajorVersion != 4 ) NdisDeregisterProtocol(&Status,ourProtocolHandle); else { // ((byte *)ourProtocolHandle)[0x0C] = 0x01; // NdisDeregisterProtocol(&Status,ourProtocolHandle); } return TRUE; } // ProtocolContent // Version NextChain offset NDIS_PROTOCOL_CHARACTERISTICS offset
BindingAdaptHandle offset // NDIS 3.XX 0x04
0x14
0x08 // NDIS 4.XX 0x60
0x14
0x00 // NDIS 4.01 0x8C
0x14
0x00 // NDIS 5.XX 0x10
0x14
0x00
|