细节解密NDIS协议驱动为什么能捕获到发送包
NDIS Loopback Discussion
http://www.ndis.com/ndis-ndis5/loopback/loopback.htm
Looping Back NDIS Packets
http://msdn.microsoft.com/en-us/library/ff557071.aspx
============================================================
XP2环境下的具体流程:
tcpip调用ndissend的时候
//////////////////////////////////////////
ndissend(miniport,mypacket)
{
)//这个标志貌似是协议驱动设置混杂模式就会设置上的,上面标志说明中提到,如果一个miniport有多个protocol绑定,只要有有其中一个就会设置上
if(miniport->flag&check_for_loopback)
{
ndisMLoopbackPacketX( miniport, mypacket)
}
}
////////////////////////////
ndisMLoopbackPacketX( miniport, mypacket)
{
if ((mypacket->Private.NdisPacketFlags & 0x20)//20= fPACKET_ALREADY_LOOPEDBACK
{ return ;}
ndis_packet * new_packet=NULL;
//ndisMIsLoopbackPacket会申请一个新的new_packet
is_LOOPBACK_ONLY = ndisMIsLoopbackPacket((_NDIS_MINIPORT_BLOCK *)miniport_block, (_NDIS_PACKET *)mypacket, &new_packet);
if (new_packet)
{
if ( pMini_block->MediaType != 7 ) // 7=NdisMediumArcnet878_2
{
确定要loopback上去了,加上20=fPACKET_ALREADY_LOOPEDBACK标志,说明已 经处理过了
mypacket->Private.NdisPacketFlags |= 0x20u;
ethFilterDprIndicateReceivePacket(miniport_block, new_packet);
}
returnis_LOOPBACK_ONLY ;
}
////////////////////=================================================================
char __fastcall ndisMIsLoopbackPacket(_NDIS_MINIPORT_BLOCK *pMini_block, _NDIS_PACKET *ori_packet, _NDIS_PACKET **pNewPacket)
{
//里面会有目标地址是否为自身的判断,略过!
v7 = pMini_block2->MediaType;
if ( !v7 ) // mediatype =0 means NdisMedium802_3
{
判断
if ( !(BYTE2(pMini_block2->Flags) & 0x80) ) // 80,其实就是flags的800000标志,对应着SEND_LOOPBACK_DIRECTED
{}
else{
//一般情况下都是这个分支,说明miniport一般都设置了SEND_LOOPBACK_DIRECTED这个标志位
判断下包里面的MAC地址是不是本机的MAC地址,我们需要的情况是MAC地址不同
申请一个新包pNewPacket,把ori_packet数据copy到pNewPacket
if ( pNewPacket )
{
*pNewPacket = pNewPacket_allocated;//pNewPacket_allocated在前面已经copy好数据
pNewPacket_allocated->Private.NdisPacketFlags |= 2u;// 会多了fPACKET_IS_LOOPBACK, fPACKET_CLEAR_ITEMS这2个属性
pNewPacket_allocated->Private.Flags = v27->Private.Flags & 0x80 | 0x100;
} // 80就是DONT_LOOPBACK,但这里是与操作,如果原来没的话,也不会加上
// 100=IS_LOOPBACK_PACKET标明是loopback包
return 0;
}
}
}
PS:如果你想你发送的包不给捕获,很简单,只要把你的包加上DONT_LOOPBACK标志即可,默认是无这个标志的
////////////////////////////////
ethFilterDprIndicateReceivePacket(miniport_block, new_packet)
{
miniport_filter_header = mini_block->EthDB //_X_FILTER类型,这个_X_FILTER结构有NumOpens字段,标志有多少个协议绑定了它
//pBindInfo是_X_BINDING_INFO类型,
for ( pBindInfo = miniport_filter_header->OpenList; pBindInfo; pBindInfo = v89 )
{
v89 = pBindInfo->NextOpen; //取对应的_NDIS_OPEN_BLOCK
if ( !(pkt1->Private.Flags & 0x80) // // 80好像是DONT_LOOPBACK
{
v65 = pBindInfo->PacketFilters;
v66 = (unsigned __int8)(v65 & 0xA0) == 0;// a0就是NDIS_PACKET_TYPE_ALL_LOCAL和NDIS_PACKET_TYPE_PROMISCUOUS的组合
// 这里取值的来源是bindinfo链表,里面每个对应一个绑定信息,说明是针对指定设定的协议驱动,例如A驱动的设置成NDIS_PACKET_TYPE_PROMISCUOUS
// 但如果B协议驱动不设置NDIS_PACKET_TYPE_PROMISCUOUS的话,B协议驱动不能接收到。
v92 = v65 & 0xA0;
if ( v66 ) // 一些其它的协议会跳走。。例如TCP/IP,所以不会重复接收到发送出去的包
//
// 测试改了tcpip的这个标志位为0x8b后,tcpip!arprecv回调也能接收到发送出去的包,修改之前是不能的
{ //
// 在我把wireshark协议驱动的这个_X_BINDING_INFO->PacketFilters改为0xb后。
// 由于0xb&a0==0,所以改了之后,就收不到发送出去的包了。但还是能收到外部发来的包,
// 因为发送和接收的包indicate的路径不一样,前者是直接在send的时候判断是否要loopback就直接indicate了
JUMPOUT(v96, 8u, *(unsigned int *)loc_22FB1);//不符合就循环跳过。。例子中就是tcpip协议驱动不会接收到(出现JUMPOUT,是因为IDA识别函数的范围不准确)
}
//条件满足0xA0,调用协议驱动的接收例程,像wireshark为什么能截获发送包就是因为这里的调用了wireshark的协议驱动的ReceiveHandler
openblock = pBindInfo->NdisBindingHandle
openblock->ReceiveHandler( )
}
}
XP环境,粗略F5,粗略动态跟踪,不保证无错