如何在 Windows 上使用 LWF driver 将数据包注入接收 (Rx) 路径?

How to inject packets into Receive (Rx) path using LWF driver on Windows?

我正在开发一个基于 WinPcap 的 NDIS 6 Light-weight 过滤器 (LWF) driver。我们可以想象网络适配器有两条路径:TxRx.

Tx为发送方式

Rx为接收方式

我们知道 WinPcap 能够向网络发送数据包(所以这是 Tx 方式)。我想知道是否可以将数据包发送到 Rx,所以这意味着 将数据包注入适配器并假装该数据包是来自网络的到达数据包 .

首先我不知道这是否可行?如果是,那么继续阅读:

我已经编写了代码,使用NdisFIndicateReceiveNetBufferLists 调用将我制作的数据包指示给上层,然后在FilterReturnNetBufferLists 处理程序中释放数据包。所以包括Windows OS在内的上层模块会知道有一个新的数据包从网络传来(实际上不是事实)。

但是,我的方法行不通。我使用 Nping(来自 Nmap)来 ping 我的网关,nping window 冻结,甚至任务管理器也无法终止它。所以它一定是driver停止。

我注意到这种方式应该可行 基于:

  1. Jeffery 对 post 的回答:Is FilterSendNetBufferLists handler a must for an NDIS filter to use NdisFSendNetBufferLists?

  2. 来自微软的解释:https://msdn.microsoft.com/en-us/library/windows/hardware/ff570452(v=vs.85).aspx

  3. OSR提供的例子:https://www.osronline.com/showthread.cfm?link=242847

然后我分析了driver打印的日志。似乎我的 NdisFIndicateReceiveNetBufferLists 调用(用于发送到 Rx)只调用了一次,然后 driver 用于其他工作,而环 3 nping 已死。我重用了来自 NPF_SendCompleteEx 的现有 well-running 代码中的大部分代码(这是将完成发送到正常 Tx 的处理程序)。所以我觉得这部分不会有bug吧?

整个代码库托管在 GitHub 上:https://github.com/nmap/npcap

它不包含此 post 中的错误代码,因为我尚未提交它,但如果您需要,它会提供一些背景知识:)

我的注入代码:

NTSTATUS
NPF_Write(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
{
    POPEN_INSTANCE      Open;
    POPEN_INSTANCE      GroupOpen;
    POPEN_INSTANCE      TempOpen;
    PIO_STACK_LOCATION  IrpSp;
    ULONG               SendFlags = 0;
    PNET_BUFFER_LIST    pNetBufferList;
    NDIS_STATUS         Status;
    ULONG               NumSends;
    ULONG               numSentPackets;

    TRACE_ENTER();

    IrpSp = IoGetCurrentIrpStackLocation(Irp);

    Open = IrpSp->FileObject->FsContext;

    if (NPF_StartUsingOpenInstance(Open) == FALSE)
    {
        // 
        // an IRP_MJ_CLEANUP was received, just fail the request
        //
        Irp->IoStatus.Information = 0;
        Irp->IoStatus.Status = STATUS_CANCELLED;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        TRACE_EXIT();
        return STATUS_CANCELLED;
    }

    NumSends = Open->Nwrites;

    //
    // validate the send parameters set by the IOCTL
    //
    if (NumSends == 0)
    {
        NPF_StopUsingOpenInstance(Open);
        Irp->IoStatus.Information = 0;
        Irp->IoStatus.Status = STATUS_SUCCESS;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);

        TRACE_EXIT();
        return STATUS_SUCCESS;
    }

    //
    // Validate input parameters: 
    // 1. The packet size should be greater than 0,
    // 2. less-equal than max frame size for the link layer and
    // 3. the maximum frame size of the link layer should not be zero.
    //
    if (IrpSp->Parameters.Write.Length == 0 ||  // Check that the buffer provided by the user is not empty
        Open->MaxFrameSize == 0 ||  // Check that the MaxFrameSize is correctly initialized
        Irp->MdlAddress == NULL ||
        IrpSp->Parameters.Write.Length > Open->MaxFrameSize) // Check that the fame size is smaller that the MTU
    {
        TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Frame size out of range, or maxFrameSize = 0. Send aborted");

        NPF_StopUsingOpenInstance(Open);

        Irp->IoStatus.Information = 0;
        Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);

        TRACE_EXIT();
        return STATUS_UNSUCCESSFUL;
    }

    // 
    // Increment the ref counter of the binding handle, if possible
    //
    if (NPF_StartUsingBinding(Open) == FALSE)
    {
        TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Adapter is probably unbinding, cannot send packets");

        NPF_StopUsingOpenInstance(Open);

        Irp->IoStatus.Information = 0;
        Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);

        TRACE_EXIT();
        return STATUS_INVALID_DEVICE_REQUEST;
    } 

    NdisAcquireSpinLock(&Open->WriteLock);
    if (Open->WriteInProgress)
    {
        // Another write operation is currently in progress
        NdisReleaseSpinLock(&Open->WriteLock);

        NPF_StopUsingBinding(Open);

        TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Another Send operation is in progress, aborting.");

        NPF_StopUsingOpenInstance(Open);

        Irp->IoStatus.Information = 0;
        Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);

        TRACE_EXIT();

        return STATUS_UNSUCCESSFUL;
    }
    else
    {
        Open->WriteInProgress = TRUE;
        NdisResetEvent(&Open->NdisWriteCompleteEvent);
    }

    NdisReleaseSpinLock(&Open->WriteLock);

    TRACE_MESSAGE2(PACKET_DEBUG_LOUD,
        "Max frame size = %u, packet size = %u",
        Open->MaxFrameSize,
        IrpSp->Parameters.Write.Length);

    //
    // reset the number of packets pending the SendComplete
    //
    Open->TransmitPendingPackets = 0;

    NdisResetEvent(&Open->WriteEvent);

    numSentPackets = 0;

    while (numSentPackets < NumSends)
    {
        pNetBufferList = NdisAllocateNetBufferAndNetBufferList(Open->PacketPool,
            0,
            0,
            Irp->MdlAddress,
            0,
            Irp->MdlAddress->ByteCount);

        if (pNetBufferList != NULL)
        {
            //
            // packet is available, prepare it and send it with NdisSend.
            //

            //
            // If asked, set the flags for this packet.
            // Currently, the only situation in which we set the flags is to disable the reception of loopback
            // packets, i.e. of the packets sent by us.
            //
            //if (Open->SkipSentPackets)
            //{
            //  NPFSetNBLFlags(pNetBufferList, g_SendPacketFlags);
            //}


            // The packet hasn't a buffer that needs not to be freed after every single write
            RESERVED(pNetBufferList)->FreeBufAfterWrite = FALSE;

            // Save the IRP associated with the packet
            // RESERVED(pPacket)->Irp=Irp;

            // Attach the writes buffer to the packet

            InterlockedIncrement(&Open->TransmitPendingPackets);

            NdisResetEvent(&Open->NdisWriteCompleteEvent);

            //receive the packets before sending them
            ASSERT(Open->GroupHead != NULL);
            if (Open->GroupHead != NULL)
            {
                GroupOpen = Open->GroupHead->GroupNext;
            }
            else
            {
                //this is impossible
                GroupOpen = Open->GroupNext;
            }

#ifdef HAVE_WFP_LOOPBACK_SUPPORT
            // Do not capture the send traffic we send, if this is our loopback adapter.
            if (Open->Loopback == FALSE)
            {
#endif
                while (GroupOpen != NULL)
                {
                    TempOpen = GroupOpen;
                    if (TempOpen->AdapterBindingStatus == ADAPTER_BOUND && TempOpen->SkipSentPackets == FALSE)
                    {
                        NPF_TapExForEachOpen(TempOpen, pNetBufferList);
                    }

                    GroupOpen = TempOpen->GroupNext;
                }
#ifdef HAVE_WFP_LOOPBACK_SUPPORT
            }
#endif

            pNetBufferList->SourceHandle = Open->AdapterHandle;
            NPFSetNBLChildOpen(pNetBufferList, Open); //save the child open object in the packets
            //SendFlags |= NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK;

            // Recognize IEEE802.1Q tagged packet, as no many adapters support VLAN tag packet sending, no much use for end users,
            // and this code examines the data which lacks efficiency, so I left it commented, the sending part is also unfinished.
            // This code refers to Win10Pcap at https://github.com/SoftEtherVPN/Win10Pcap.
//          if (Open->Loopback == FALSE)
//          {
//              PUCHAR pHeaderBuffer;
//              UINT iFres;
//
//              BOOLEAN withVlanTag = FALSE;
//              UINT VlanID = 0;
//              UINT VlanUserPriority = 0;
//              UINT VlanCanFormatID = 0;
//
//              NdisQueryMdl(
//                  Irp->MdlAddress,
//                  &pHeaderBuffer,
//                  &iFres,
//                  NormalPagePriority);
//
//              // Determine if the packet is IEEE802.1Q tagged packet.
//              if (iFres >= 18)
//              {
//                  if (pHeaderBuffer[12] == 0x81 && pHeaderBuffer[13] == 0x00)
//                  {
//                      USHORT pTmpVlanTag = 0;
//
//                      ((UCHAR *)(&pTmpVlanTag))[0] = pHeaderBuffer[15];
//                      ((UCHAR *)(&pTmpVlanTag))[1] = pHeaderBuffer[14];
//
//                      VlanID = pTmpVlanTag & 0x0FFF;
//                      VlanUserPriority = (pTmpVlanTag >> 13) & 0x07;
//                      VlanCanFormatID = (pTmpVlanTag >> 12) & 0x01;
//
//                      if (VlanID != 0)
//                      {
//                          withVlanTag = TRUE;
//                      }
//                  }
//              }
//          }

            //
            //  Call the MAC
            //
#ifdef HAVE_WFP_LOOPBACK_SUPPORT
            if (Open->Loopback == TRUE)
            {
                NPF_LoopbackSendNetBufferLists(Open->GroupHead,
                    pNetBufferList);
            }
            else
#endif
#ifdef HAVE_SEND_TO_RECEIVE_PATH_SUPPORT
                if (Open->SendToRxPath == TRUE)
                {
                    IF_LOUD(DbgPrint("hahahahahahahahahahahaha:: SendToRxPath, Open->AdapterHandle=%p, pNetBufferList=%u\n", Open->AdapterHandle, pNetBufferList);)
                    // pretend to receive these packets from network and indicate them to upper layers
                    NdisFIndicateReceiveNetBufferLists(
                        Open->AdapterHandle,
                        pNetBufferList,
                        NDIS_DEFAULT_PORT_NUMBER,
                        1,
                        0);
                }
                else
#endif
                {
                    NdisFSendNetBufferLists(Open->AdapterHandle,
                        pNetBufferList,
                        NDIS_DEFAULT_PORT_NUMBER,
                        SendFlags);
                }

            numSentPackets ++;
        }
        else
        {
            //
            // no packets are available in the Transmit pool, wait some time. The 
            // event gets signalled when at least half of the TX packet pool packets
            // are available
            //
            NdisWaitEvent(&Open->WriteEvent, 1);
        }
    }

    //
    // when we reach this point, all the packets have been enqueued to NdisSend,
    // we just need to wait for all the packets to be completed by the SendComplete
    // (if any of the NdisSend requests returned STATUS_PENDING)
    //
    NdisWaitEvent(&Open->NdisWriteCompleteEvent, 0);

    //
    // all the packets have been transmitted, release the use of the adapter binding
    //
    NPF_StopUsingBinding(Open);

    //
    // no more writes are in progress
    //
    NdisAcquireSpinLock(&Open->WriteLock);
    Open->WriteInProgress = FALSE;
    NdisReleaseSpinLock(&Open->WriteLock);

    NPF_StopUsingOpenInstance(Open);

    //
    // Complete the Irp and return success
    //
    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = IrpSp->Parameters.Write.Length;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    TRACE_EXIT();

    return STATUS_SUCCESS;
}

我的 FilterReturnNetBufferLists 处理程序:

_Use_decl_annotations_
VOID
NPF_ReturnEx(
    NDIS_HANDLE         FilterModuleContext,
    PNET_BUFFER_LIST    NetBufferLists,
    ULONG               ReturnFlags
    )
/*++

Routine Description:

    FilterReturnNetBufferLists handler.
    FilterReturnNetBufferLists is an optional function. If provided, NDIS calls
    FilterReturnNetBufferLists to return the ownership of one or more NetBufferLists
    and their embedded NetBuffers to the filter driver. If this handler is NULL, NDIS
    will skip calling this filter when returning NetBufferLists to the underlying
    miniport and will call the next lower driver in the stack. A filter that doesn't
    provide a FilterReturnNetBufferLists handler cannot originate a receive indication
    on its own.

Arguments:

    FilterInstanceContext       - our filter context area
    NetBufferLists              - a linked list of NetBufferLists that this 
                                  filter driver indicated in a previous call to 
                                  NdisFIndicateReceiveNetBufferLists
    ReturnFlags                 - flags specifying if the caller is at DISPATCH_LEVEL

--*/
{
    POPEN_INSTANCE      ChildOpen;
    POPEN_INSTANCE      GroupOpen;
    POPEN_INSTANCE      TempOpen;
    BOOLEAN             FreeBufAfterWrite;
    PNET_BUFFER_LIST    pNetBufList;
    PNET_BUFFER_LIST    pNextNetBufList;
    PNET_BUFFER         Currbuff;
    PMDL                pMdl;
    POPEN_INSTANCE      Open = (POPEN_INSTANCE) FilterModuleContext;

    TRACE_ENTER();

#ifdef HAVE_SEND_TO_RECEIVE_PATH_SUPPORT
    pNetBufList = NetBufferLists;

    while (pNetBufList != NULL)
    {
        pNextNetBufList = NET_BUFFER_LIST_NEXT_NBL(pNetBufList);
        NET_BUFFER_LIST_NEXT_NBL(pNetBufList) = NULL;

        if (pNetBufList->SourceHandle == Open->AdapterHandle) //this is our self-sent packets
        {
            TRACE_MESSAGE(PACKET_DEBUG_LOUD, "hahahaha This is my own send to Rx packets");
            ChildOpen = NPFGetNBLChildOpen(pNetBufList); //get the child open object that sends these packets
            FreeBufAfterWrite = RESERVED(pNetBufList)->FreeBufAfterWrite;

            if (FreeBufAfterWrite)
            {
                //
                // Packet sent by NPF_BufferedWrite()
                //

                //Free the NBL allocate by myself
                Currbuff = NET_BUFFER_LIST_FIRST_NB(pNetBufList);
                while (Currbuff)
                {
                    pMdl = NET_BUFFER_FIRST_MDL(Currbuff);
                    NdisFreeMdl(pMdl); //Free MDL
                    Currbuff = NET_BUFFER_NEXT_NB(Currbuff);
                }
                NdisFreeNetBufferList(pNetBufList); //Free NBL
            }
            else
            {
                //
                // Packet sent by NPF_Write()
                //

                //Free the NBL allocate by myself
                NdisFreeNetBufferList(pNetBufList); //Free NBL
            }

            // this if should always be false, as Open is always the GroupHead itself, only GroupHead is known by NDIS and get invoked in NPF_SendCompleteEx() function.
            if (Open->GroupHead != NULL)
            {
                GroupOpen = Open->GroupHead->GroupNext;
            }
            else
            {
                GroupOpen = Open->GroupNext;
            }

            //GroupOpen = Open->GroupNext;

            while (GroupOpen != NULL)
            {
                TempOpen = GroupOpen;
                if (ChildOpen == TempOpen) //only indicate the specific child open object
                {
                    NPF_SendCompleteExForEachOpen(TempOpen, FreeBufAfterWrite);
                    break;
                }

                GroupOpen = TempOpen->GroupNext;
            }
        }
        else
        {
            TRACE_MESSAGE(PACKET_DEBUG_LOUD, "hahahaha This is NOT my own send to Rx packets");
            // Return the received NBLs.  If you removed any NBLs from the chain, make
            // sure the chain isn't empty (i.e., NetBufferLists!=NULL).
            NdisFReturnNetBufferLists(Open->AdapterHandle, pNetBufList, ReturnFlags);
        }

        pNetBufList = pNextNetBufList;
    }
#else
    // Return the received NBLs.  If you removed any NBLs from the chain, make
    // sure the chain isn't empty (i.e., NetBufferLists!=NULL).
    NdisFReturnNetBufferLists(Open->AdapterHandle, NetBufferLists, ReturnFlags);
#endif

    TRACE_EXIT();
}

我的日志:

00010269    58.36443710 MDL 42  
00010270    58.36444092 hahahahahahahahahahahaha:: SendToRxPath, Open->AdapterHandle=FFFFFA8003C24010, pNetBufferList=68928096  
00010271    58.36450577 --> NPF_ReturnEx    
00010272    58.36450577     NPF_ReturnEx: hahahaha This is my own send to Rx packets    
00010273    58.36451340 <-- NPF_ReturnEx    
00010274    59.04499054 --> NPF_NetworkClassify 
00010275    59.04499817 --> NPF_IsPacketSelfSent    
00010276    59.04499817 <-- NPF_IsPacketSelfSent    
00010277    59.04499817     NPF_NetworkClassify: NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: 0] 
00010278    59.04500961 <-- NPF_NetworkClassify 
00010279    59.04502869 --> NPF_SendEx  
00010280    59.04503632 --> NPF_SendCompleteEx  
00010281    59.04504395 <-- NPF_SendCompleteEx  
00010282    59.04504395 <-- NPF_SendEx  
00010283    59.04520798 --> NPF_NetworkClassify 
00010284    59.04520798 --> NPF_IsPacketSelfSent    
00010285    59.04521561 <-- NPF_IsPacketSelfSent    
00010286    59.04521561     NPF_NetworkClassify: NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: 0] 
00010287    59.04522324 <-- NPF_NetworkClassify 
00010288    59.04529953 --> NPF_SendEx  
00010289    59.04529953 --> NPF_SendCompleteEx  
00010290    59.04530716 <-- NPF_SendCompleteEx  
00010291    59.04530716 <-- NPF_SendEx  
00010292    59.04531097 --> NPF_NetworkClassify 
00010293    59.04531097 --> NPF_IsPacketSelfSent    
00010294    59.04531097 <-- NPF_IsPacketSelfSent    
00010295    59.04531860     NPF_NetworkClassify: NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: 0] 
00010296    59.04531860 <-- NPF_NetworkClassify 
00010297    59.04541397 --> NPF_NetworkClassify 
00010298    59.04541397 --> NPF_IsPacketSelfSent    
00010299    59.04541397 <-- NPF_IsPacketSelfSent    
00010300    59.04542160     NPF_NetworkClassify: NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: 0] 
00010301    59.04542160 <-- NPF_NetworkClassify 
00010302    59.04543304 --> NPF_SendEx  
00010303    59.04543304 Received on CPU 0  3    
00010304    59.04544067 Received on CPU 0  2    
00010305    59.04544067 MDL 62  
00010306    59.04544067 next MDL 24 and added   
00010307    59.04544830 --> NPF_SendCompleteEx  
00010308    59.04547882 <-- NPF_SendCompleteEx  
00010309    59.04548645 <-- NPF_SendEx  
00010310    59.04558563 --> NPF_NetworkClassify 
00010311    59.04558563 --> NPF_IsPacketSelfSent    
00010312    59.04558563 <-- NPF_IsPacketSelfSent    
00010313    59.04559326     NPF_NetworkClassify: NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: 0] 
00010314    59.04560089 <-- NPF_NetworkClassify 
00010315    59.04560471 --> NPF_SendEx  
00010316    59.04561234 Received on CPU 0  4    
00010317    59.04561234 Received on CPU 0  3    
00010318    59.04561234 MDL 42  
00010319    59.04561996 next MDL 24 and added   
00010320    59.04561996 --> NPF_SendCompleteEx  
00010321    59.04562378 <-- NPF_SendCompleteEx  
00010322    59.04562378 <-- NPF_SendEx  
00010323    59.15098953 --> NPF_NetworkClassify 
00010324    59.15098953 --> NPF_IsPacketSelfSent    
00010325    59.15099335 <-- NPF_IsPacketSelfSent    
00010326    59.15099335     NPF_NetworkClassify: NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: 0] 
00010327    59.15103912 <-- NPF_NetworkClassify 
00010328    59.15105820 --> NPF_SendEx  
00010329    59.15106583 --> NPF_SendCompleteEx  
00010330    59.15106583 <-- NPF_SendCompleteEx  
00010331    59.15106583 <-- NPF_SendEx  
00010332    59.15113449 --> NPF_NetworkClassify 
00010333    59.15113449 --> NPF_IsPacketSelfSent    
00010334    59.15114212 <-- NPF_IsPacketSelfSent    
00010335    59.15114212     NPF_NetworkClassify: NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: 0] 
00010336    59.15114975 <-- NPF_NetworkClassify 
00010337    59.15118027 --> NPF_SendEx  
00010338    59.15118027 --> NPF_SendCompleteEx  
00010339    59.15118790 <-- NPF_SendCompleteEx  
00010340    59.15118790 <-- NPF_SendEx  
00010341    59.15118790 --> NPF_NetworkClassify 
00010342    59.15119171 --> NPF_IsPacketSelfSent    
00010343    59.15119171 <-- NPF_IsPacketSelfSent    
00010344    59.15119171     NPF_NetworkClassify: NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: 0] 
00010345    59.15119934 <-- NPF_NetworkClassify 
00010346    59.15123367 --> NPF_NetworkClassify 
00010347    59.15123749 --> NPF_IsPacketSelfSent    
00010348    59.15123749 <-- NPF_IsPacketSelfSent    
00010349    59.15123749     NPF_NetworkClassify: NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: 0] 
00010350    59.15124512 <-- NPF_NetworkClassify 
00010351    59.15125275 --> NPF_SendEx  
00010352    59.15125275 Received on CPU 1  1    
00010353    59.15125656 Received on CPU 1  1    
00010354    59.15132904 MDL 62  
00010355    59.15133286 next MDL 24 and added   
00010356    59.15134048 --> NPF_SendCompleteEx  
00010357    59.15134811 <-- NPF_SendCompleteEx  
00010358    59.15134811 <-- NPF_SendEx  
00010359    59.15138626 --> NPF_NetworkClassify 
00010360    59.15138626 --> NPF_IsPacketSelfSent    
00010361    59.15138626 <-- NPF_IsPacketSelfSent    
00010362    59.15139389     NPF_NetworkClassify: NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: 0] 
00010363    59.15139771 <-- NPF_NetworkClassify 
00010364    59.15140533 --> NPF_SendEx  
00010365    59.15140533 Received on CPU 1  2    
00010366    59.15140533 Received on CPU 1  2    
00010367    59.15141296 MDL 42  
00010368    59.15141296 next MDL 24 and added   
00010369    59.15141296 --> NPF_SendCompleteEx  
00010370    59.15141678 <-- NPF_SendCompleteEx  
00010371    59.15141678 <-- NPF_SendEx  
00010372    59.19804001 --> NPF_SendEx  
00010373    59.19805527 --> NPF_SendCompleteEx  
00010374    59.19805527 <-- NPF_SendCompleteEx  
00010375    59.19805527 <-- NPF_SendEx  
00010376    59.35518646 --> NPF_NetworkClassify 
00010377    59.35519409 --> NPF_IsPacketSelfSent    
00010378    59.35519409 <-- NPF_IsPacketSelfSent    
00010379    59.35519409     NPF_NetworkClassify: NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: 0] 
00010380    59.35520554 <-- NPF_NetworkClassify 
00010381    59.35526276 --> NPF_SendEx  
00010382    59.35527039 --> NPF_SendCompleteEx  
00010383    59.35527802 <-- NPF_SendCompleteEx  
00010384    59.35527802 <-- NPF_SendEx  
00010385    59.35528183 --> NPF_NetworkClassify 
00010386    59.35528183 --> NPF_IsPacketSelfSent    
00010387    59.35528183 <-- NPF_IsPacketSelfSent    
00010388    59.35528946     NPF_NetworkClassify: NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: 0] 
00010389    59.35528946 <-- NPF_NetworkClassify 
00010390    59.35543823 --> NPF_NetworkClassify 
00010391    59.35543823 --> NPF_IsPacketSelfSent    
00010392    59.35543823 <-- NPF_IsPacketSelfSent    
00010393    59.35544205     NPF_NetworkClassify: NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: 0] 
00010394    59.35544968 <-- NPF_NetworkClassify 
00010395    59.35546112 --> NPF_SendEx  
00010396    59.35546875 Received on CPU 0  5    
00010397    59.35546875 Received on CPU 0  4    
00010398    59.35547638 MDL 42  
00010399    59.35547638 next MDL 50 and added   
00010400    59.35548019 --> NPF_SendCompleteEx  
00010401    59.35548019 <-- NPF_SendCompleteEx  
00010402    59.35548782 <-- NPF_SendEx  
00010403    59.47556305 --> NPF_TapEx   
00010404    59.47557068 --> NPF_ReturnEx    
00010405    59.47557068     NPF_ReturnEx: hahahaha This is NOT my own send to Rx packets    
00010406    59.47557068 <-- NPF_ReturnEx    
00010407    59.47557831 <-- NPF_TapEx   
00010408    59.58328247 --> NPF_TapEx   
00010409    59.58329773 --> NPF_ReturnEx    
00010410    59.58329773     NPF_ReturnEx: hahahaha This is NOT my own send to Rx packets    
00010411    59.58329773 <-- NPF_ReturnEx    
00010412    59.58329773 <-- NPF_TapEx   
00010413    59.58549881 --> NPF_TapEx   
00010414    59.58550262 --> NPF_ReturnEx    
00010415    59.58551025     NPF_ReturnEx: hahahaha This is NOT my own send to Rx packets    
00010416    59.58551025 <-- NPF_ReturnEx    
00010417    59.58551025 <-- NPF_TapEx   
00010418    60.11791992 --> NPF_NetworkClassify 
00010419    60.11791992 --> NPF_IsPacketSelfSent    
00010420    60.11792755 <-- NPF_IsPacketSelfSent    
00010421    60.11792755     NPF_NetworkClassify: NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: 0] 
00010422    60.11793900 <-- NPF_NetworkClassify 
00010423    60.11795807 --> NPF_SendEx  
00010424    60.11796570 Received on CPU 0  6    
00010425    60.11796570 Received on CPU 0  5    
00010426    60.11796951 MDL 42  
00010427    60.11796951 next MDL 50 and added   

正确的做法是根据 MSDN 使用 NdisFIndicateReceiveNetBufferListshttps://msdn.microsoft.com/en-us/library/windows/hardware/ff570448(v=vs.85).aspx