数据包拦截:Windows下网络数据报的监听和拦截技术



Windows下网络数据报监听和拦截技术1
Windows下网络数据报监听和拦截技术是个比较古老话题应用也很广泛例如
防火墙等等这篇小文只是对该技术个整理总结没有新技术高手免看:)
要监听和拦截Windows下数据报基本可以在两个层次进行个是用户态(user-mo
de)个是核心态(kernel-mode)
在用户态下从高到低大概有 4种思路方法
1、原是套结字(Raw Socket)Winsock2以后提供了原始套结字功能可以在用户态用
Winsock接收所有流经WinsockIP包这种思路方法在MSDN里面有叙述是MS官方支持
思路方法在网上也有很多资料但是这种思路方法只能监听但是不能拦截数据报所以可以
作为网络监视器选择技术但是不能实现防火墙等更高要求功能另外最致命
点就是只能在Winsock层次上进行而对于网络协议栈中底层协议数据包例如TDI无法
进行处理对于些木马和病毒来说很容易避开这个层次监听
2、替换系统自带WINSOCK动态连接库这种思路方法可以在很多文章里面找到详细实现
细节 通过替换系统Winsock库部分导出实现数据报监听和拦截缺点同1

3、Winsock服务提供者(SPI)SPI是Winsock是Winsock2个新特性
起初Winsock是围绕着TCP/IP协议运行但是在Winsock 2中却增加了对更多传输协
支持Winsock2不仅提供了个供应用访问网络服务Windows 应用程
序编程接口(API)还包含了由传输服务提供者和名字解析服务提供者实现Winsock
服务提供者接口(SPI)和ws2_32.dll Winsock 2传输服务提供者是以动态链接库
形式(DLL)存在以下是winsock 2在传输服务提供者上WOSA(Windows开放服务结
构):
----------------------------
|Windows 2 应用|
----------------------------Windows 2 API
| WS2_32.DLL |
----------------------------Windows 2 传输SPI
| 传输服务提供者(DLL) |
----------------------------
Windows SPI提供 3种协议:分层协议基础协议和协议链分层协议是在基础
协议上层依靠底层基础协议实现更高级通信服务基础协议是能够独立安全地
和远程端点实现数据通信协议它是相对和分层协议而言协议链是将系列
础协议和分层协议按特点顺序连接在链状结构可以通过Platform SDK附带
工具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官方思路方法具体使用思路方法在
其Platform SDK里面有详细例子(LSP)在MSDN里面也有详细解释这种思路方法优点
是能够获得Winsock进程详细信息并能实现Qos和数据加密所以SPI是用户态
数据拦截较好地点缺点同1
4、Windows2000包过滤接口由于过滤规则限制太多不灵活而应用不多
5、网络监视器SDKMS官方实时监视分析网络数据思路方法但是由于封装太复?
樱?
使用起来不灵活

在核心态下数据报监视和拦截思路方法比较复杂由于大多个人防火墙都是在核心?
?
实现所以在这里比较详细叙述具体请参见nt/2kDDK文档大概有下面几
个思路方法
1、 TDI过滤驱动(TDI Filter Driver)
2、 NDIS中间层驱动(NDIS Intermediate Driver)编写IM DRIVER在NDIS中间层


对MINIPORT(网卡驱动)和协议驱动的间数据包进行拦截这是微软提供
种技术在DDK中MS提供了Passthru例子很多中间层过滤驱动都可以由的改编但编
写该过滤拦截非常复杂安装也很麻烦
3、 Win2k Filter-Hook Driver
4、 NDIS Hook Driver这种思路方法又有两种实现方式
(1)向NDIS注册假协议(fake protocol)这是在协议层上处理在Windows内核中


所有已注册协议是通过个单向协议链表来维护这个单向链表保存了所有已
注册协议NDIS_PROTOCOL_BLOCK结构地址在这个结构中保存了协议驱动所指定
派发地址如RECEIVE_HANDLER等
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;
# d(NDIS_WRAPPER)
//
// Protocol filters
//
struct _NDIS_PROTOCOL_FILTER * ProtocolFilter[NdisMediumMax+1];
WORK_QUEUE_ITEM WorkItem; // Used during NdisRegisterProtocol to
// noty protocols of existing drivers.
KMUTEX Mutex; // For serialization of Bind/Unbind requests
PKEVENT DeregEvent; // Used by NdisDeregisterProtocol
#end
};
typedef struct _NDIS_PROTOCOL_BLOCK NDIS_PROTOCOL_BLOCK, *PNDIS_PROTOCOL_BLO
CK;并且每个协议驱动还对应个NDIS_OPEN_BLOCK单向链表来维护其所绑定网卡
信息当协议驱动NdisRegisterProtocol的后
EXPORT
VOID
NdisRegisterProtocol(
OUT PNDIS_STATUS Status,
OUT PNDIS_PROTOCOL_BLOCK NdisProtocolHandle, /*注意NDIS_HANDLE所指向就是PN
DIS_PROTOCOL_BLOCK结构不要有什么怀疑*/
IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
IN UINT CharacteristicsLength
);
NDIS总是会把新注册协议放在协议链表表头并返回这张表所以只要我们注册
协议通过新协议注册返回链表头就可以轻而易举遍历系统中所有协议表但是
如果要成功地挂接派发还需要对协议所对应NDIS_OPEN_BLOCK结构里派发函
数进行挂接NDIS并不是直接协议驱动在NDIS_PROTOCOL_CHARACTERISTICS所注
派发地址而是NDIS_OPEN_BLOCK里派发
struct _NDIS_OPEN_BLOCK
{
PNDIS_MAC_BLOCK MacHandle; // poer to our MAC
NDIS_HANDLE MacBindingHandle; // context when calling MacXX funcs
PNDIS_ADAPTER_BLOCK AdapterHandle; // poer to our adapter
PNDIS_PROTOCOL_BLOCK ProtocolHandle; // poer 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 ernal 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 ReHandler;
REQUEST_HANDLER RequestHandler;
//
// Needed for PnP
//
UNICODE_STRING AdapterName; // Upd name of the adapter we are bound to
};
这张表是个单向链接表并且存放了和PNDIS_OPEN_BLOCK->ProtocolCharacteristic
s
数据收发派发当第N块网卡发送数据包到第N个协议时就会第N个协议
和第N个网卡的间建立
NDIS_OPEN_BLOCK表里SendHandler或SendPacketHandler所以我们还需要对这张表里
派发进行处理(勾挂)
值得注意在Windows9x/Me/NTDDK中NDIS_PROTOCOL_BLOCK定义是很明确
而在Windows 2000/xpDDK中并没有该结构详细定义也就是说该结构在Windows2
000/xp下是非公开因此开发人员需要利用各种调试工具来发掘该结构详细定义


也正是如此这种思路方法对平台依赖性比较大需要在中判断区别操作系统
版本而使用区别结构定义可以用NdisOpenProtocolConfiguration打开协议配置
NdisReadConfiguration查询NDIS版本
下面注册fake protocol并将PNDIS_PROTOCOL_BLOCK结构存在ProtHandle中NDIS_
HANDLE GetProtocolBlock
{
NDIS_PROTOCOL_CHARACTERISTICS PChars;
NDIS_STRING Name;
NDIS_HANDLE ProtHandle;
NDIS_STATUS Status;
NdisZeroMemory(&PChars, (NDIS_PROTOCOL_CHARACTERISTICS));
PChars.MajorNdisVersion = 5;
PChars.MinorNdisVersion = 0;
NdisInitUnicodeString(&Name, L\"WssFW\"); // Protocol name
PChars.Name = Name;
PChars.OpenAdapterCompleteHandler = NULL;
PChars.CloseAdapterCompleteHandler = NULL;
PChars.SendCompleteHandler = NULL;
PChars.TransferDataCompleteHandler = NULL;

PChars.ReCompleteHandler = 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,
(NDIS_PROTOCOL_CHARACTERIS
TICS));
ASSERT(Status NDIS_STATUS_SUCCESS);
(Status NDIS_STATUS_SUCCESS)
ProtHandle;

NULL;
}
下面挂接PNDIS_PROTOCOL_BLOCK中PNDIS_PROTOCOL_CHARACTERISTICS结构R
ec
eiveHandler和ReceivePacketHandler
PVOID
HookProtoFunc(
PNDIS_PROTOCOL_CHARACTERISTICS pCharacteristics,


DWORD dwFunctionCode,
PVOID pfuncNew,
DWORD dwNdisVersion)
{
PVOID pOldFunc = NULL;
//Check parameters
( (!pCharacteristics ) || (!pfuncNew) )
NULL;
switch(dwFunctionCode)
{
PROTO_RECEIVE_HANDLER:
//Just hook _disibledevent=> {
pOldFunc = pCharacteristics->ReceiveHandler;
( pOldFunc )
pCharacteristics->ReceiveHandler = pfuncNew;
}
;
PROTO_RECEIVE_PACKET_HANDLER:
(pCharacteristics->ReceivePacketHandler != pfuncNew)
{
// pOpenBlock is NULL or pOpenBlock->ReceivePacketHandl
er is NULL,
//just hook Characteristics;
pOldFunc = pCharacteristics->ReceivePacketHandler;
(pOldFunc)
pCharacteristics->ReceivePacketHandler = pfuncNew
;
}
;
default:
;
}
pOldFunc;
}
下面挂接PNDIS_OPEN_BLOCK结构里ReceiveHandler和ReceivePacketHandler
PVOID
HookBlockFunc(
PNDIS_OPEN_BLOCK pFirstOpenBlock,
DWORD dwFunctionCode,
PVOID pfuncNew,
DWORD dwNdisVersion)
{
RECEIVE_HANDLER * pReceiveHandler = NULL;


RECEIVE_PACKET_HANDLER * pReceivePacketHandler = NULL;
// PVOID pFuncHandler = NULL;
PVOID pOldFunc = NULL;
PNDIS_OPEN_BLOCK pOpenBlock = pFirstOpenBlock;
(!pFirstOpenBlock)
NULL;
(!pfuncNew )
NULL;
switch(dwFunctionCode)
{
PROTO_RECEIVE_HANDLER:
//travel all NDIS_OPEN_BLOCK
for(;pOpenBlock;pOpenBlock = GetNextBlock( pOpenBlock,dwNdisVersi
on ))
{
pReceiveHandler = GetReceiveHandler(pOpenBlock,dwNdisVers
ion);
//Just hook _disibledevent=> {
pOldFunc = *pReceiveHandler;
*pReceiveHandler = pfuncNew;
}
(dwNdisVersion 0x00040001)//win2k ????
{
pReceiveHandler = GetPostNt31ReceiveHandler(pOpen
Block,dwNdisVersion);
( *pReceiveHandler != pfuncNew )
{
pOldFunc = *pReceiveHandler;
*pReceiveHandler = pfuncNew;
}
}
}
;
PROTO_RECEIVE_PACKET_HANDLER:
//travel all NDIS_OPEN_BLOCK
for(;pOpenBlock;pOpenBlock = GetNextBlock( pOpenBlock,dwNdisVersi


on ))
pReceivePacketHandler = GetReceivePacketHandler( pOpenBlo
ck,dwNdisVersion
);
//Just hook _disibledevent=> {
pOldFunc = *pReceivePacketHandler;
*pReceivePacketHandler = pfuncNew;
}
}
;

default:
;
}
pOldFunc;
}


bsp; &PChars,
(NDIS_PROTOCOL_CHARACTERIS
TICS));
ASSERT(Status NDIS_STATUS_SUCCESS);
(Status NDIS_STATUS_SUCCESS)
ProtHandle;

NULL;
}
下面挂接PNDIS_PROTOCOL_BLOCK中PNDIS_PROTOCOL_CHARACTERISTICS结构R
ec
eiveHandler和ReceivePacketHandler
PVOID
HookProtoFunc(
PNDIS_PROTOCOL_CHARACTERISTICS pCharacteristics,
DWORD dwFunctionCode,
PVOID pfuncNew,
DWORD dwNdisVersion)
{
PVOID pOldFunc = NULL;
//Check parameters
( (!pCharacteristics ) || (!pfuncNew) )
NULL;
switch(dwFunctionCode)
{
PROTO_RECEIVE_HANDLER:
//Just hook _disibledevent=> {
pOldFunc = pCharacteristics->ReceiveHandler;
( pOldFunc )


pCharacteristics->ReceiveHandler = pfuncNew;
}
;
PROTO_RECEIVE_PACKET_HANDLER:
(pCharacteristics->ReceivePacketHandler != pfuncNew)
{
// pOpenBlock is NULL or pOpenBlock->ReceivePacketHandl
er is NULL,
//just hook Characteristics;
pOldFunc = pCharacteristics->ReceivePacketHandler;
(pOldFunc)
pCharacteristics->ReceivePacketHandler = pfuncNew
;
}
;
default:
;
}
pOldFunc;
}
下面挂接PNDIS_OPEN_BLOCK结构里ReceiveHandler和ReceivePacketHandler
PVOID
HookBlockFunc(
PNDIS_OPEN_BLOCK pFirstOpenBlock,
DWORD dwFunctionCode,
PVOID pfuncNew,
DWORD dwNdisVersion)
{
RECEIVE_HANDLER * pReceiveHandler = NULL;
RECEIVE_PACKET_HANDLER * pReceivePacketHandler = NULL;
// PVOID pFuncHandler = NULL;
PVOID pOldFunc = NULL;
PNDIS_OPEN_BLOCK pOpenBlock = pFirstOpenBlock;
(!pFirstOpenBlock)
NULL;
(!pfuncNew )
NULL;
switch(dwFunctionCode)
{
PROTO_RECEIVE_HANDLER:
//travel all NDIS_OPEN_BLOCK
for(;pOpenBlock;pOpenBlock = GetNextBlock( pOpenBlock,dwNdisVersi
on ))
{
pReceiveHandler = GetReceiveHandler(pOpenBlock,dwNdisVers
ion);
//Just hook _disibledevent=>


{
pOldFunc = *pReceiveHandler;
*pReceiveHandler = pfuncNew;
}
(dwNdisVersion 0x00040001)//win2k ????
{
pReceiveHandler = GetPostNt31ReceiveHandler(pOpen
Block,dwNdisVersion);
( *pReceiveHandler != pfuncNew )
{
pOldFunc = *pReceiveHandler;
*pReceiveHandler = pfuncNew;
}
}
}
;
PROTO_RECEIVE_PACKET_HANDLER:
//travel all NDIS_OPEN_BLOCK
for(;pOpenBlock;pOpenBlock = GetNextBlock( pOpenBlock,dwNdisVersi
on ))
pReceivePacketHandler = GetReceivePacketHandler( pOpenBlo
ck,dwNdisVersion
);
//Just hook _disibledevent=> {
pOldFunc = *pReceivePacketHandler;
*pReceivePacketHandler = pfuncNew;
}
}
;

default:
;
}


pOldFunc;
}


bsp; &PChars,
(NDIS_PROTOCOL_CHARACTERIS
TICS));
ASSERT(Status NDIS_STATUS_SUCCESS);
(Status NDIS_STATUS_SUCCESS)
ProtHandle;

NULL;
}
下面挂接PNDIS_PROTOCOL_BLOCK中PNDIS_PROTOCOL_CHARACTERISTICS结构R
ec
eiveHandler和ReceivePacketHandler
PVOID
HookProtoFunc(
PNDIS_PROTOCOL_CHARACTERISTICS pCharacteristics,
DWORD dwFunctionCode,
PVOID pfuncNew,
DWORD dwNdisVersion)
{
PVOID pOldFunc = NULL;
//Check parameters
( (!pCharacteristics ) || (!pfuncNew) )
NULL;
switch(dwFunctionCode)
{
PROTO_RECEIVE_HANDLER:
//Just hook _disibledevent=> {
pOldFunc = pCharacteristics->ReceiveHandler;
( pOldFunc )
pCharacteristics->ReceiveHandler = pfuncNew;
}
;
PROTO_RECEIVE_PACKET_HANDLER:
(pCharacteristics->ReceivePacketHandler != pfuncNew)
{
// pOpenBlock is NULL or pOpenBlock->ReceivePacketHandl
er is NULL,
//just hook Characteristics;
pOldFunc = pCharacteristics->ReceivePacketHandler;
(pOldFunc)
pCharacteristics->ReceivePacketHandler = pfuncNew


;
}
;
default:
;
}
pOldFunc;
}
下面挂接PNDIS_OPEN_BLOCK结构里ReceiveHandler和ReceivePacketHandler
PVOID
HookBlockFunc(
PNDIS_OPEN_BLOCK pFirstOpenBlock,
DWORD dwFunctionCode,
PVOID pfuncNew,
DWORD dwNdisVersion)
{
RECEIVE_HANDLER * pReceiveHandler = NULL;
RECEIVE_PACKET_HANDLER * pReceivePacketHandler = NULL;
// PVOID pFuncHandler = NULL;
PVOID pOldFunc = NULL;
PNDIS_OPEN_BLOCK pOpenBlock = pFirstOpenBlock;
(!pFirstOpenBlock)
NULL;
(!pfuncNew )
NULL;
switch(dwFunctionCode)
{
PROTO_RECEIVE_HANDLER:
//travel all NDIS_OPEN_BLOCK
for(;pOpenBlock;pOpenBlock = GetNextBlock( pOpenBlock,dwNdisVersi
on ))
{
pReceiveHandler = GetReceiveHandler(pOpenBlock,dwNdisVers
ion);
//Just hook _disibledevent=> {
pOldFunc = *pReceiveHandler;
*pReceiveHandler = pfuncNew;
}
, (dwNdisVersion 0x00040001)//win2k ????
{
pReceiveHandler = GetPostNt31ReceiveHandler(pOpen
Block,dwNdisVersion);
( *pReceiveHandler != pfuncNew )
{


pOldFunc = *pReceiveHandler;
*pReceiveHandler = pfuncNew;
}
}
}
;
PROTO_RECEIVE_PACKET_HANDLER:
//travel all NDIS_OPEN_BLOCK
for(;pOpenBlock;pOpenBlock = GetNextBlock( pOpenBlock,dwNdisVersi
on ))
pReceivePacketHandler = GetReceivePacketHandler( pOpenBlo
ck,dwNdisVersion
);
//Just hook _disibledevent=> {
pOldFunc = *pReceivePacketHandler;
*pReceivePacketHandler = pfuncNew;
}
}
;

default:
;
}
pOldFunc;
}


Tags:  数据包拦截工具 如何拦截数据包 数据拦截 数据包拦截

延伸阅读

最新评论

发表评论