中間層驅(qū)動(dòng)下面連接ndis miniport驅(qū)動(dòng),,上面連接ndis protocol驅(qū)動(dòng)
,,可以監(jiān)控所有本機(jī)收到的和發(fā)出去的網(wǎng)絡(luò)包,。自己寫一個(gè)NDIS Intermediate Driver (中間層驅(qū)動(dòng))
可以過濾網(wǎng)絡(luò)包實(shí)現(xiàn)類似防火墻的功能(我不知道那些防火墻是不是這樣做的,,好像都是去寫NDIS Hook
Drivers,,而不是這個(gè)),,也可以修改網(wǎng)絡(luò)包,,可以用來做VPN等功能(實(shí)際VPN客戶端可能不一定是這樣做的,,不過確實(shí)有人寫了類似的實(shí)例),。
有上圖可以知道中間層是包括protocol和虛擬miniport兩部分的,因?yàn)槲易约鹤隽艘粋€(gè)arp防欺騙工具,,所以像寫一個(gè)這樣的驅(qū)動(dòng)來截取本機(jī)收到的ARP包,。因?yàn)榍懊娌捎胣dis
protocol驅(qū)動(dòng)來獲取arp包也是可以的,但同時(shí)在發(fā)送ARP包的時(shí)候,可能是handle有沖突,,我自己弄不好同步問題,,索性再寫個(gè)中間層驅(qū)動(dòng)算了。參考WinDDK自帶的
Passthru例子,,稍加修改就可以達(dá)到目的,。我想捕獲本機(jī)收到的ARP包,所以只要修改protocol.c
中的PtReceivePacket()函數(shù)就可以了,,本機(jī)收到網(wǎng)絡(luò)包的時(shí)候系統(tǒng)是會(huì)自動(dòng)回調(diào)這個(gè)函數(shù)的,,我只要在這里過濾ARP包然后轉(zhuǎn)發(fā)給自己的應(yīng)用程序就行了。不過好像說是底層有的miniport不支持直接提交packet上來,,所以也有可能是通過PtReceive()這個(gè)函數(shù)提交數(shù)據(jù),。所以也要改一下這個(gè)函數(shù)才行。我實(shí)際測(cè)試的時(shí)候也是有時(shí)是在PtReceivePacket()中得到數(shù)據(jù),,有時(shí)是在PtReceive()得到數(shù)據(jù)的,。所以最后兩個(gè)都改一下吧。如果像過濾本機(jī)發(fā)出去的網(wǎng)絡(luò)包,,那么看miniport那部分就行了,。不過我沒有做了,我只是想得到本機(jī)收到的ARP包而已了,。
改后的PtReceivePacket()函數(shù)如下,,其他的修改如PtReceive,還有就是和用戶態(tài)應(yīng)用程序交互IO控制相應(yīng)那些,,ARP包結(jié)構(gòu)等就不細(xì)說了,。
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);
//通知應(yīng)用程序收到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是一個(gè)從別人的代碼里面抄過來的,,從packet結(jié)構(gòu)讀取包緩存的函數(shù)。一并轉(zhuǎn)貼出來吧,,如下:
/**************************************************************************************************/
/*
*/
/* 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 包的關(guān)鍵代碼了,。如果像過濾 TCP/IP包其實(shí)也是要修改一點(diǎn)點(diǎn)就行了。
要什么其他的功能自己動(dòng)手吧,,我也是看了一下MSDN的參考而已,,不甚明白。
自己動(dòng)手豐衣足食,!