Windows下网络数据报及监听和拦截技术.docx
《Windows下网络数据报及监听和拦截技术.docx》由会员分享,可在线阅读,更多相关《Windows下网络数据报及监听和拦截技术.docx(15页珍藏版)》请在冰豆网上搜索。
![Windows下网络数据报及监听和拦截技术.docx](https://file1.bdocx.com/fileroot1/2023-5/20/5a60267b-0028-413e-8fd4-f8f1bfbc8b9c/5a60267b-0028-413e-8fd4-f8f1bfbc8b9c1.gif)
Windows下网络数据报及监听和拦截技术
Windows下网络数据报及监听和拦截技术
Windows下网络数据报的监听和拦截技术1
Windows下网络数据报的监听和拦截技术是一个比较古老的话题,应用也很广泛,例如
防火墙等等。
这篇小文只是对该技术的一个总结,没有新技术,高手免看:
)
要监听和拦截Windows下的数据报,基本可以在两个层次进行,一个是用户态(user-mo
de),一个是核心态(kernel-mode)。
在用户态下,从高到低大概有四种方法。
1、原是套结字(RawSocket)。
Winsock2以后提供了原始套结字功能,可以在用户态用
Winsock函数接收所有流经Winsock的IP包。
这种方法在MSDN里面有叙述,是MS官方支持
的方法,在网上也有很多资料。
但是这种方法只能监听但是不能拦截数据报,所以可以
作为网络监视器的选择技术,但是不能实现防火墙等更高要求的功能。
另外最致命的缺
点就是只能在Winsock层次上进行,而对于网络协议栈中底层协议的数据包例如TDI无法
进行处理。
对于一些木马和病毒来说很容易避开这个层次的监听。
2、替换系统自带的WINSOCK动态连接库。
这种方法可以在很多文章里面找到详细的实现
细节。
通过替换系统Winsock库的部分导出函数,实现数据报的监听和拦截。
缺点同1。
3、Winsock服务提供者(SPI)。
SPI是Winsock的另一面,是Winsock2的一个新特性。
起初的Winsock是围绕着TCP/IP协议运行的,但是在Winsock2中却增加了对更多传输协
议的支持。
Winsock2不仅提供了一个供应用程序访问网络服务的Windowssocket应用程
序编程接口(API),还包含了由传输服务提供者和名字解析服务提供者实现的Winsock
服务提供者接口(SPI)和ws2_32.dll。
Winsock2的传输服务提供者是以动态链接库的
形式(DLL)存在的。
以下是winsock2在传输服务提供者上的WOSA(Windows开放服务结
构):
----------------------------
|Windowssocket2应用程序|
----------------------------Windowssocket2API
|WS2_32.DLL|
----------------------------Windowssocket2传输SPI
|传输服务提供者(DLL)|
----------------------------
WindowssocketSPI提供三种协议:
分层协议,基础协议和协议链。
分层协议是在基础
协议的上层,依靠底层基础协议实现更高级的通信服务。
基础协议是能够独立,安全地
和远程端点实现数据通信的协议,它是相对与分层协议而言的。
协议链是将一系列的基
础协议和分层协议按特点的顺序连接在一起的链状结构,可以通过PlatformSDK附带的
工具Sporder.exe察看系统已经安装的SPI,请参见下图:
API------------------------
|WS2_32.DLL|
SPI------------------------
|分层协议|
SPI-------------
|分层协议|
SPI------------------------
|基础协议|
------------------------
每个应用程序通过Ws2_32.dll和相应的服务提供者进行严格的数据交换。
Ws2_32.dl
l根
据应用程序在创建套接字时所提供的参数来选择特定的服务提供者,然后把应用程序的
实现过程转发由所选创建套接字的服务提供者来管理。
也就是说,Ws2_32.dll只是一个
中间过程,而应用程序只是一个接口,数据通信的实现却是由服务提供者来完成的。
所
以我们通过适当的增加自己的分层协议服务提供者,使其位于SPI的顶端,那么就能将W
s2_32.dll传给服务提供者的数据报拦截下来。
由于是MS的官方方法,具体的使用方法在
其PlatformSDK里面有详细的例子(LSP),在MSDN里面也有详细的解释。
这种方法的优点
是能够获得调用Winsock的进程的详细信息,并能实现Qos和数据加密。
所以SPI是用户态
数据拦截的较好地点。
缺点同1。
4、Windows2000包过滤接口。
由于过滤规则限制太多不灵活而应用不多。
5、网络监视器SDK。
MS官方的实时监视分析网络数据的方法。
但是由于封装的太复?
樱?
使用起来不灵活。
在核心态下,数据报的监视和拦截方法比较复杂,由于大多个人防火墙都是在核心?
?
实现的,所以在这里比较详细的叙述一下。
具体的请参见nt/2kDDK文档。
大概有下面几
个方法。
1、TDI过滤驱动程序(TDIFilterDriver)。
2、NDIS中间层驱动程序(NDISIntermediateDriver)。
编写IMDRIVER在NDIS中间层
对MINIPORT(网卡驱动程序)和协议驱动程序之间的数据包进行拦截。
这是微软提供的
一种技术。
在DDK中MS提供了Passthru例子,很多中间层过滤驱动都可以由之改编。
但编
写该过滤程序拦截程序非常的复杂,安装也很麻烦。
3、Win2kFilter-HookDriver。
4、NDISHookDriver。
这种方法又有两种实现方式。
(1)向NDIS注册假协议(fakeprotocol)。
这是在协议层上的处理。
在Windows内核中
,所有已注册的协议是通过一个单向的协议链表来维护的。
这个单向链表保存了所有已
注册协议的NDIS_PROTOCOL_BLOCK结构的地址,在这个结构中保存了协议驱动所指定的相
应的派发函数的地址如RECEIVE_HANDLER等。
struct_NDIS_PROTOCOL_BLOCK
{
PNDIS_OPEN_BLOCKOpenQueue;//queueofopensforthisprotocol
REFERENCERef;//containsspinlockforOpenQueue
UINTLength;//ofthisNDIS_PROTOCOL_BLOCKstruct
NDIS50_PROTOCOL_CHARACTERISTICSProtocolCharacteristics;//handleraddresses
struct_NDIS_PROTOCOL_BLOCK*NextProtocol;//Linktonext
ULONGMaxPatternSize;
#ifdefined(NDIS_WRAPPER)
//
//Protocolfilters
//
struct_NDIS_PROTOCOL_FILTER*ProtocolFilter[NdisMediumMax+1];
WORK_QUEUE_ITEMWorkItem;//UsedduringNdisRegisterProtocolto
//notifyprotocolsofexistingdrivers.
KMUTEXMutex;//ForserializationofBind/Unbindrequests
PKEVENTDeregEvent;//UsedbyNdisDeregisterProtocol
#endif
};
typedefstruct_NDIS_PROTOCOL_BLOCKNDIS_PROTOCOL_BLOCK,*PNDIS_PROTOCOL_BLO
CK;并且,每个协议驱动还对应一个NDIS_OPEN_BLOCK的单向链表来维护其所绑定的网卡
信息。
当协议驱动调用NdisRegisterProtocol之后,
EXPORT
VOID
NdisRegisterProtocol(
OUTPNDIS_STATUSStatus,
OUTPNDIS_PROTOCOL_BLOCKNdisProtocolHandle,/*注意NDIS_HANDLE所指向的就是PN
DIS_PROTOCOL_BLOCK的结构,不要有什么怀疑。
*/
INPNDIS_PROTOCOL_CHARACTERISTICSProtocolCharacteristics,
INUINTCharacteristicsLength
);
NDIS总是会把新注册的协议放在协议链表的表头并返回这张表,所以只要我们注册一个
新的协议通过新协议注册返回的链表头就可以轻而易举的遍历系统中所有协议表。
但是
,如果要成功地挂接派发函数,还需要对协议所对应的NDIS_OPEN_BLOCK结构里的派发函
数进行挂接,因为NDIS并不是直接调用协议驱动在NDIS_PROTOCOL_CHARACTERISTICS所注
册的派发函数地址,而是调用NDIS_OPEN_BLOCK里的派发函数。
struct_NDIS_OPEN_BLOCK
{
PNDIS_MAC_BLOCKMacHandle;//pointertoourMAC
NDIS_HANDLEMacBindingHandle;//contextwhencallingMacXXfuncs
PNDIS_ADAPTER_BLOCKAdapterHandle;//pointertoouradapter
PNDIS_PROTOCOL_BLOCKProtocolHandle;//pointertoourprotocol
NDIS_HANDLEProtocolBindingContext;//contextwhencallingProtXXfuncs
PNDIS_OPEN_BLOCKAdapterNextOpen;//usedbyadapter'sOpenQueue
PNDIS_OPEN_BLOCKProtocolNextOpen;//usedbyprotocol'sOpenQueue
PFILE_OBJECTFileObject;//createdbyoperatingsystem
BOOLEANClosing;//TRUEwhenremovingthisstruct
BOOLEANUnloading;//TRUEwhenprocessingunload
BOOLEANNoProtRsvdOnRcvPkt;//Reflecttheprotocol_options
NDIS_HANDLECloseRequestHandle;//0indicatesaninternalclose
KSPIN_LOCKSpinLock;//guardsClosing
PNDIS_OPEN_BLOCKNextGlobalOpen;
//
//TheseareoptimizationsforgettingtoMACroutines.Theyarenot
//necessary,butareheretosaveadereferencethroughtheMACblock.
//
SEND_HANDLERSendHandler;
TRANSFER_DATA_HANDLERTransferDataHandler;
//
//TheseareoptimizationsforgettingtoPROTOCOLroutines.Theyarenot
//necessary,butareheretosaveadereferencethroughthePROTOCOLblock.
//
SEND_COMPLETE_HANDLERSendCompleteHandler;
TRANSFER_DATA_COMPLETE_HANDLERTransferDataCompleteHandler;
RECEIVE_HANDLERReceiveHandler;
RECEIVE_COMPLETE_HANDLERReceiveCompleteHandler;
//
//ExtentionstotheOPEN_BLOCKsinceProduct1.
//
RECEIVE_HANDLERPostNt31ReceiveHandler;
RECEIVE_COMPLETE_HANDLERPostNt31ReceiveCompleteHandler;
//
//NDIS4.0extensions
//
RECEIVE_PACKET_HANDLERReceivePacketHandler;
SEND_PACKETS_HANDLERSendPacketsHandler;
//
//MoreNDIS3.0CachedHandlers
//
RESET_HANDLERResetHandler;
REQUEST_HANDLERRequestHandler;
//
//NeededforPnP
//
UNICODE_STRINGAdapterName;//Upcasednameoftheadapterweareboundto
};
这张表是一个单向链接表,并且存放了和PNDIS_OPEN_BLOCK->ProtocolCharacteristic
s
一样的数据收发派发函数,当第N块网卡发送数据包到第N个协议时,就会调用第N个协议
与第N个网卡之间建立的
NDIS_OPEN_BLOCK表里的SendHandler或SendPacketHandler。
所以我们还需要对这张表里
的派发函数进行处理(勾挂)。
值得注意的是,在Windows9x/Me/NT的DDK中,NDIS_PROTOCOL_BLOCK的定义是很明确的,
而在Windows2000/xp的DDK中,并没有该结构的详细定义,也就是说该结构在Windows2
000/xp下是非公开的,因此开发人员需要利用各种调试工具来发掘该结构的详细定义。
也正是因为如此,这种方法对平台的依赖性比较大,需要在程序中判断不同的操作系统
版本而使用不同的结构定义。
可以用NdisOpenProtocolConfiguration打开协议配置,用
NdisReadConfiguration查询NDIS版本。
下面的函数注册fakeprotocol并将PNDIS_PROTOCOL_BLOCK结构存在ProtHandle中NDIS_
HANDLEGetProtocolBlock()
{
NDIS_PROTOCOL_CHARACTERISTICSPChars;
NDIS_STRINGName;
NDIS_HANDLEProtHandle;
NDIS_STATUSStatus;
NdisZeroMemory(&PChars,sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
PChars.MajorNdisVersion=5;
PChars.MinorNdisVersion=0;
NdisInitUnicodeString(&Name,L"WssFW");//Protocolname
PChars.Name=Name;
PChars.OpenAdapterCompleteHandler=NULL;
PChars.CloseAdapterCompleteHandler=NULL;
PChars.SendCompleteHandler=NULL;
PChars.TransferDataCompleteHandler=NULL;
PChars.ResetCompleteHandler=NULL;
PChars.RequestCompleteHandler=NULL;
PChars.ReceiveHandler=NULL;
PChars.ReceiveCompleteHandler=NULL;
PChars.StatusHandler=NULL;
PChars.StatusCompleteHandler=NULL;
PChars.BindAdapterHandler=NULL;
PChars.UnbindAdapterHandler=NULL;
PChars.UnloadHandler=NULL;
PChars.ReceivePacketHandler=NULL;
PChars.PnPEventHandler=NULL;
NdisRegisterProtocol(&Status,
&ProtHandle,
&PChars,
sizeof(NDIS_PROTOCOL_CHARACTERIS
TICS));
ASSERT(Status==NDIS_STATUS_SUCCESS);
if(Status==NDIS_STATUS_SUCCESS)
returnProtHandle;
else
returnNULL;
}
下面的函数挂接PNDIS_PROTOCOL_BLOCK中PNDIS_PROTOCOL_CHARACTERISTICS结构的R
ec
eiveHandler和ReceivePacketHandler
PVOID
HookProtoFunc(
PNDIS_PROTOCOL_CHARACTERISTICSpCharacteristics,
DWORDdwFunctionCode,
PVOIDpfuncNew,
DWORDdwNdisVersion)
{
PVOIDpOldFunc=NULL;
//Checkparameters
if((!
pCharacteristics)||(!
pfuncNew))
returnNULL;
switch(dwFunctionCode)
{
casePROTO_RECEIVE_HANDLER:
//Justhookonce!
if(pCharacteristics->ReceiveHandler!
=pfuncNew)
{
pOldFunc=pCharacteristics->ReceiveHandler;
if(pOldFunc)
pCharacteristics->ReceiveHandler=pfuncNew;
}
break;
casePROTO_RECEIVE_PACKET_HANDLER:
if(pCharacteristics->ReceivePacketHandler!
=pfuncNew)
{
//ifpOpenBlockisNULLorpOpenBlock->ReceivePacketHandl
erisNULL,
//justhookCharacteristics;
pOldFunc=pCharacteristics->ReceivePacketHandler;
if(pOldFunc)
pCharacteristics->ReceivePacketHandler=pfuncNew
;
}
break;
default:
break;
}
returnpOldFunc;
}
下面的函数挂接PNDIS_OPEN_BLOCK结构里的ReceiveHandler和ReceivePacketHandler
PVOID
HookBlockFunc(
PNDIS_OPEN_BLOCKpFirstOpenBlock,
DWORDdwFunctionCode,
PVOIDpfuncNew,
DWORDdwNdisVersion)
{
RECEIVE_HANDLER*pReceiveHandler=NULL;
RECEIVE_PACKET_HANDLER*pReceivePacketHandler=NULL;
//PVOIDpFuncHandler=NULL;
PVOIDpOldFunc=NULL;
PNDIS_OPEN_BLOCKpOpenBlock=pFirstOpenBlock;
if(!
pFirstOpenBlock)
returnNULL;
if(!
pfuncNew)
returnNULL;
switch(dwFunctionCode)
{
casePROTO_RECEIVE_HANDLER:
//travelallNDIS_OPEN_BLOCK
for(;pOpenBlock;pOpenBlock=GetNextBlock(pOpenBlock,dwNdisVersi
on))
{
pReceiveHandler=GetReceiveHandler(pOpenBlock,dwNdisVers
ion);
//Justhookonce!
if(*pReceiveHandler!
=pfuncNew)
{
pOldFunc=*pReceiveHandler;
*pReceiveHandler=pfuncNew;
}
if(dwNdisVersion==0x00040001)//win2k?
?
?
?
{
pReceiveHandler=GetPostNt31ReceiveHandler(pOpen
Block,dwNdisVersion);
if(*pReceiveHandler!
=pfuncNew)
{
pOldFunc=*pReceiveHandler;
*pReceiveHandler=pfuncNew;
}
}
}
break;
casePROTO_RECEIVE_PACKET_HANDLER:
//travelallNDIS_OPEN_BLOCK
for(;pOpenBlock;pOpenBlock=GetNextBlock(pOpenBlock,dwNdisVersi
on))
pReceivePacketHandler=GetReceivePacketHandler(pOpenBlo
ck,dwNdisVersion
);
//Justhookonce!
if(*pReceivePacketHandler!
=pfuncNew)
{
pOldFunc=*pReceivePacketHandler;
*pReceivePacketHandler=pfuncNew;
}
}
break;
default:
break;
}
returnpOldFu