中间层驱动下面连接ndis miniport驱动,上面连接ndis protocol驱动
,可以监控所有本机收到的和发出去的网络包。自己写一个NDIS Intermediate Driver (中间层驱动)
可以过滤网络包实现类似防火墙的功能(我不知道那些防火墙是不是这样做的,好像都是去写NDIS Hook
Drivers,而不是这个),也可以修改网络包,可以用来做VPN等功能(实际VPN客户端可能不一定是这样做的,不过确实有人写了类似的实例)。
有上图可以知道中间层是包括protocol和虚拟miniport两部分的,因为我自己做了一个arp防欺骗工具,所以像写一个这样的驱动来截取本机收到的ARP包。因为前面采用ndis
protocol驱动来获取arp包也是可以的,但同时在发送ARP包的时候,可能是handle有冲突,我自己弄不好同步问题,索性再写个中间层驱动算了。参考WinDDK自带的
Passthru例子,稍加修改就可以达到目的。我想捕获本机收到的ARP包,所以只要修改protocol.c
中的PtReceivePacket()函数就可以了,本机收到网络包的时候系统是会自动回调这个函数的,我只要在这里过滤ARP包然后转发给自己的应用程序就行了。不过好像说是底层有的miniport不支持直接提交packet上来,所以也有可能是通过PtReceive()这个函数提交数据。所以也要改一下这个函数才行。我实际测试的时候也是有时是在PtReceivePacket()中得到数据,有时是在PtReceive()得到数据的。所以最后两个都改一下吧。如果像过滤本机发出去的网络包,那么看miniport那部分就行了。不过我没有做了,我只是想得到本机收到的ARP包而已了。
改后的PtReceivePacket()函数如下,其他的修改如PtReceive,还有就是和用户态应用程序交互IO控制相应那些,ARP包结构等就不细说了。
INT
PtReceivePacket(
IN NDIS_HANDLE
ProtocolBindingContext,
IN PNDIS_PACKET Packet
)
/*++
Routine Description:
ReceivePacket handler. Called by NDIS if the miniport below
supports
NDIS 4.0 style receives. Re-package the buffer chain in a new
packet
and indicate the new packet to protocols above us. Any context
for
packets indicated up must be kept in the MiniportReserved field.
NDIS 5.1 - packet stacking - if there is sufficient "stack space"
in
the packet passed to us, we can use the same packet in a
receive
indication.
Arguments:
ProtocolBindingContext - Pointer to our adapter structure.
Packet - Pointer to the packet
Return Value:
== 0 -> We are done with the packet
!= 0 -> We will keep
the packet and call NdisReturnPackets() this
many times when
done.
--*/
{
PADAPT pAdapt
=(PADAPT)ProtocolBindingContext;
NDIS_STATUS Status;
PNDIS_PACKET MyPacket;
BOOLEAN
Remaining;
//----------------------
ULONG
readPacketBufferLength;
//-----------------------
//
// Drop the packet silently if the upper miniport edge isn't
initialized or
// the miniport edge is in low power state
//
if ((!pAdapt->MiniportHandle) || (pAdapt->MPDeviceState >
NdisDeviceStateD0))
{
return 0;
}
///-----widebright增加的 过滤 ARP包的
段----------------------------------------------------------------------------
DBGPRINT(("PtReceivePacket Function \n"));
//////////////////////////////////////////////////////////
GetPktPayload(Packet, // Copy
payload
&recARPPacket, //
to area.
sizeof(recARPPacket), //
Amount of space in area.
&readPacketBufferLength // Return number of bytes in
packet.
);
if (readPacketBufferLength
!=0)
{
if (recARPPacket.ehhdr.eh_type == 1544) //
#define EPT_ARP 0x0806 1544= htons(EPT_ARP) 就是看是不是ARP包
{
DBGPRINT(("PtReceivePacket Function and ARP packet \n"));
//////////////////////////////////////////////////////////
if (pEvent)
KeSetEvent(pEvent, 0, 0);
//通知应用程序收到ARP 包了
}
}
//如果return 0 则表示丢弃 包,不传给上一层
///-----widebright增加的 过滤 ARP包的
段----------------------------------------------------------------------------
#ifdef NDIS51
//
// Check if we can reuse the same packet for
indicating up.
// See also: PtReceive().
//
(VOID)NdisIMGetCurrentPacketStack(Packet, &Remaining);
if
(Remaining)
{
//
// We can reuse "Packet".
Indicate it up and be done with it.
//
Status =
NDIS_GET_PACKET_STATUS(Packet);
NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &Packet,
1);
return((Status != NDIS_STATUS_RESOURCES) ? 1 : 0);
}
#endif // NDIS51
//
// Get a packet off the pool and indicate that up
//
NdisDprAllocatePacket(&Status,
&MyPacket,
pAdapt->RecvPacketPoolHandle);
if (Status == NDIS_STATUS_SUCCESS)
{
PRECV_RSVD RecvRsvd;
RecvRsvd = (PRECV_RSVD)(MyPacket->MiniportReserved);
RecvRsvd->OriginalPkt = Packet;
NDIS_PACKET_FIRST_NDIS_BUFFER(MyPacket) =
NDIS_PACKET_FIRST_NDIS_BUFFER(Packet);
NDIS_PACKET_LAST_NDIS_BUFFER(MyPacket) =
NDIS_PACKET_LAST_NDIS_BUFFER(Packet);
//
// Get the original packet (it could be the same
packet as the one
// received or a different one based on the number
of layered miniports
// below) and set it on the indicated packet so
the OOB data is visible
// correctly to protocols above
us.
//
NDIS_SET_ORIGINAL_PACKET(MyPacket,
NDIS_GET_ORIGINAL_PACKET(Packet));
//
// Set Packet Flags
//
NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
Status = NDIS_GET_PACKET_STATUS(Packet);
NDIS_SET_PACKET_STATUS(MyPacket, Status);
NDIS_SET_PACKET_HEADER_SIZE(MyPacket, NDIS_GET_PACKET_HEADER_SIZE(Packet));
if (pAdapt->MiniportHandle != NULL)
{
NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket,
1);
}
//
// Check if we had indicated up the packet with
NDIS_STATUS_RESOURCES
// NOTE -- do not use
NDIS_GET_PACKET_STATUS(MyPacket) for this since
// it might have
changed! Use the value saved in the local variable.
//
if (Status == NDIS_STATUS_RESOURCES)
{
//
// Our ReturnPackets handler will not be called for this
packet.
// We should reclaim it right here.
//
NdisDprFreePacket(MyPacket);
}
return((Status != NDIS_STATUS_RESOURCES) ? 1 : 0);
}
else
{
//
// We are out of packets. Silently
drop it.
//
return(0);
}
}
可以看到我增加的代码是很少的,
GetPktPayload是一个从别人的代码里面抄过来的,从packet结构读取包缓存的函数。一并转贴出来吧,如下:
/**************************************************************************************************/
/*
*/
/* Copy the payload of the specified packet into the specified
buffer.
*/
/*
*/
/* Adapted from http://www./papers/ndispacket/readonpacket.htm,
12 May 2003.
*/
/*
*/
/**************************************************************************************************/
VOID
GetPktPayload(
PNDIS_PACKET
pPacket, // Address of packet descriptor.
PUCHAR pOutBfr, // Address of output buffer, to get
copied packet payload.
ULONG
ulOutBfrAvail, // Size of output buffer.
PULONG pUlBytesCopied // Output variable for number of bytes
copied.
)
{
PNDIS_BUFFER pNdisBfr;
ULONG ulBfrCnt,
ulTotPktLen,
ulCurrBfr,
ulAmtToMove;
PUCHAR pCurrBfr;
*pUlBytesCopied = 0; // Set 0 bytes
copied.
if (0==ulOutBfrAvail) // Is output buffer 0
bytes in length?
goto Done;
NdisQueryPacket(pPacket, // Get information
from packet descriptor.
NULL,
NULL,
&pNdisBfr, // Output variable for address of first
buffer descriptor.
&ulTotPktLen // Output variable for number of bytes
in packet payload.
);
NdisQueryBuffer(pNdisBfr, // Get information
from first buffer descriptor.
&pCurrBfr, // Output variable for address of
described virtual area.
&ulCurrBfr // Output variable for size of virtual
area.
);
while (ulOutBfrAvail>0) // Space remaining
in output buffer?
{
while
(0==ulCurrBfr) // While the current buffer has zero
length.
{
NdisGetNextBuffer(pNdisBfr,
// Get next buffer descriptor.
&pNdisBfr
);
if (NULL==pNdisBfr) //
None?
goto Done;
NdisQueryBuffer(pNdisBfr, // Get information
from next buffer descriptor.
&pCurrBfr, // Output variable for address of current
buffer.
&ulCurrBfr // Output
variable for size of current buffer.
);
}
if (ulCurrBfr>ulOutBfrAvail) // Does current
buffer's usable size exceed space remaining in output buffer?
ulAmtToMove = ulOutBfrAvail; // Use only amount remaining in
output buffer.
else
ulAmtToMove =
ulCurrBfr; // Use full size of current buffer.
NdisMoveMemory(pOutBfr, // Copy packet data
to output buffer.
pCurrBfr,
ulAmtToMove
);
*pUlBytesCopied += ulAmtToMove; // Update output
variable of bytes copied.
pOutBfr +=
ulAmtToMove; // Update pointer to output
buffer.
ulOutBfrAvail -= ulAmtToMove; // Update
number of bytes available in output buffer.
ulCurrBfr = 0; // Force search for
next buffer.
} // End
'while' copy bytes to output buffer.
Done:
;
}
这就是获取ARP 包的关键代码了。如果像过滤 TCP/IP包其实也是要修改一点点就行了。
要什么其他的功能自己动手吧,我也是看了一下MSDN的参考而已,不甚明白。
自己动手丰衣足食!