首页 > 系统相关 >windows 驱动实例分析系列: NDIS 6.0的Filter 驱动改造(二)

windows 驱动实例分析系列: NDIS 6.0的Filter 驱动改造(二)

时间:2024-11-01 19:48:15浏览次数:3  
标签:pFilter windows LIST FILTER Filter BUFFER 驱动 NET NDIS

缓冲区池

Filter驱动要发送数据,除了实现这两个回调之外,还需要分配一个NET_BUFFER_LIST池,用于从池中分配NET_BUFFER_LIST结构,注意内核代码必须仅从Pool中分配NET_BUFFER_LIST以及NET_BUFFER等缓冲区结构。

分配

 一般会使用下面的代码来分配缓冲区池:

NDIS_HANDLE AllocateListPool(NDIS_HANDLE NdisHandle)
{
	NET_BUFFER_LIST_POOL_PARAMETERS PoolParameters;

	NdisZeroMemory(&PoolParameters, sizeof(NET_BUFFER_LIST_POOL_PARAMETERS));

	PoolParameters.Header.Type        = NDIS_OBJECT_TYPE_DEFAULT;
	PoolParameters.Header.Revision    = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
	PoolParameters.Header.Size        = sizeof(PoolParameters);
	PoolParameters.ProtocolId         = NDIS_PROTOCOL_ID_DEFAULT ;
	PoolParameters.ContextSize        = sizeof(FILTER_SEND_NETBUFLIST_RSVD);
	PoolParameters.fAllocateNetBuffer = TRUE;
	PoolParameters.PoolTag            = FILTER_ALLOC_TAG;

    return NdisAllocateNetBufferListPool(NdisHandle, &PoolParameters);
}

后续可以用这个句柄分配一个NET_BUFFER_LIST结构,并且包含一个NET_BUFFER,这样的话就避免了调用NdisAllocateNetBufferPool分配NET_BUFFER的麻烦,但是NET_BUFFER_LIST可以挂接多个NET_BUFFER,这也是NdisAllocateNetBufferPool存在的意义。

释放

可以调用下面的代码释放分配的Pool:

// 释放NET_BUFFER_LIST池
void ReleasePool(NDIS_HANDLE  pNdisPoolHandle)
{
	if(NULL != pNdisPoolHandle)
	{
		NdisFreeNetBufferListPool(pNdisPoolHandle);
		pNdisPoolHandle = NULL;
	}
}

在释放 NET_BUFFER_LIST 结构池之前,必须释放池中的所有NET_BUFFER_LIST结构,注意:释放结构池不等于释放池中的所有结构。 

数据包的接收

相比起发送,接收要简单很多,有两个例程和接受相关,分别是FilterReceiveNetBufferLists以及FilterReturnNetBufferLists函数,前者用于接受数据包,后者则是将数据包返回基础驱动程序。

如果 NDIS 传递给FilterReturnNetBufferLists中的 ReceiveFlags 中NDIS_RECEIVE_FLAGS_RESOURCES标志 指示的FilterReceiveNetBufferLists 函数未设置,Filter 驱动程序必须调用 NdisFReturnNetBufferLists 函数以返回 NET_BUFFER_LIST 结构和关联的数据。 在 Filter 驱动程序调用 NdisFReturnNetBufferLists 后,NDIS 将数据返回到基础驱动程序。:

VOID
FilterReceiveNetBufferLists(
    NDIS_HANDLE         FilterModuleContext,
    PNET_BUFFER_LIST    NetBufferLists,
    NDIS_PORT_NUMBER    PortNumber,
    ULONG               NumberOfNetBufferLists,
    ULONG               ReceiveFlags
    )
/*++

Routine Description:

FilerEReceiveNetBufferLists是Filter驱动程序的可选函数。

如果提供,此功能处理接收底层发出的指示NIC或更低级别的Filter驱动程序。此函数也可以处理环回的结果。

如果此处理程序为NULL,NDIS将跳过调用此处理程序在处理接收指示时的处理,并将调用在堆栈中下一个更高的指示驱动。

一个不提供FilterReceiveNetBufferLists处理程序无法提供FilterReturnNetBufferLists处理程序,无法启动原始接收指示本身。

Arguments:

    FilterModuleContext      - 上下文.
    NetBufferLists           - 数据包
    PortNumber               - 接收端口
    ReceiveFlags             -

N.B.: 检查 NDIS_TEST_RECEIVE_CANNOT_PEND 中的 ReceiveFlags 非常重要。这控制接收指示是同步还是异步函数调用。

--*/
{

    PMS_FILTER          pFilter = (PMS_FILTER)FilterModuleContext;
    BOOLEAN             DispatchLevel;
    ULONG               Ref;
    BOOLEAN             bFalse = FALSE;
#if DBG
    ULONG               ReturnFlags;
#endif

    DEBUGP(DL_TRACE, "===>ReceiveNetBufferList: NetBufferLists = %p.\n", NetBufferLists);
    do
    {

        DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags);
#if DBG
        FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);

        if (pFilter->State != FilterRunning)
        {
            FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);

            if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags))
            {
                ReturnFlags = 0;
                if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags))
                {
                    NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
                }

                NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);
            }
            break;
        }
        FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
#endif

        ASSERT(NumberOfNetBufferLists >= 1);

        //
        // 如果您想丢弃接收到的数据包,则必须小心地
        // 修改 NBL 链,如下所示:
        //
        // if NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags):
        // 对于每个未丢弃的 NBL,暂时将其从
        // 链接列表中断开,并使用
        // NdisFIndicateReceiveNetBufferLists 和
        // NDIS_RECEIVE_FLAGS_RESOURCES 标志集单独指示它。
        // 然后立即
        // 将 NBL 重新链接到链中。当所有 NBL 都已
        // 指示时,您可以从此函数返回。
        // 
        // 否则(NDIS_TEST_RECEIVE_CANNOT_PEND 为 FALSE):
        // 将 NBL 的链接列表分为两个链:
        // 一个链包含要丢弃的数据包,另一个链中包含其他所有内容。
        // 使用 NdisFReturnNetBufferLists 返回第一个链,并使用 NdisFIndicateReceiveNetBufferLists 指示其余链。
        //
        // 注意:在以太网数据包的接收路径上,一个 NBL 将只有一个 NB。因此(假设您正在以太网上接收,或者连接到 Native WiFi 上方)您不必担心丢弃一个 NB,而是尝试指示同一 NBL 上的其余 NB。
        // 换句话说,如果第一个 NB 应该被丢弃,则丢弃整个 NBL。

        // 如果您想修改数据包,并且可以快速完成,您可以在此处进行修改。但是,请确保您保存了足够的信息以撤消 FilterReturnNetBufferLists 处理程序中的修改。

        // 如有必要,将 NetBufferLists 排队在本地结构中以供稍后处理。但是,不要将它们排队“太久”,否则系统的性能可能会下降。如果您需要无限期地保留 NBL,则分配内存,执行深度复制,然后返回原始 NBL。

        if (pFilter->TrackReceives)
        {
            FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
            pFilter->OutstandingRcvs += NumberOfNetBufferLists;
            Ref = pFilter->OutstandingRcvs;

            FILTER_LOG_RCV_REF(1, pFilter, NetBufferLists, Ref);
            FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
        }
#ifdef FILTER_TEST
        CopyNetBufferList(pFilter, NetBufferLists);
#endif
        NdisFIndicateReceiveNetBufferLists(
                   pFilter->FilterHandle,
                   NetBufferLists,
                   PortNumber,
                   NumberOfNetBufferLists,
                   ReceiveFlags);


        if (NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags) &&
            pFilter->TrackReceives)
        {
            FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
            pFilter->OutstandingRcvs -= NumberOfNetBufferLists;
            Ref = pFilter->OutstandingRcvs;
            FILTER_LOG_RCV_REF(2, pFilter, NetBufferLists, Ref);
            FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
        }

    } while (bFalse);

    DEBUGP(DL_TRACE, "<===ReceiveNetBufferList: Flags = %8x.\n", ReceiveFlags);

}
数据包的访问

下面的代码用于将数据取出来,代码中并未处理缓冲区不足的情况,这只是一个案例演示:

NDIS_STATUS 
CopyNetBufferList(
IN PMS_FILTER pFilter, 
IN PNET_BUFFER_LIST NetBufferLists
)
{
    PUCHAR				pData = NULL;
    PNET_BUFFER_LIST	pCurrNbl = NetBufferLists;
    PNET_BUFFER			pCurrBuff = NULL;
    PNET_BUFFER         pNextBuff = NULL;
    PMDL				pMdl = NULL;

    ULONG				ulOffset = 0;
    int					nDataLen = 0;
    BOOLEAN             bFlags = !(KeGetCurrentIrql() == PASSIVE_LEVEL);

    // 1. 循环处理NET_BUFFER_LIST
    while (pCurrNbl)
    {
        // 2. 获取一个NET_BUFFER
        pCurrBuff = NET_BUFFER_LIST_FIRST_NB(pCurrNbl);

        while (pCurrBuff)
        {
            // 2.1 获取偏移量
            ulOffset = NET_BUFFER_DATA_OFFSET(pCurrBuff);
            // 2.2. 获取NML
            pMdl = NET_BUFFER_FIRST_MDL(pCurrBuff);
            // 2.3. 获取长度
            nDataLen = NET_BUFFER_DATA_LENGTH(pCurrBuff);

            if (pMdl == NULL || nDataLen == 0) continue;

            // 从MDL中获取虚拟地址
            pData = (UCHAR*)MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
            pNextBuff = NET_BUFFER_NEXT_NB(pCurrBuff);
            if (NULL == pNextBuff)
            {
                // 获取真正的数据地址 pData
                pData = pData + ulOffset;
                nDataLen = nDataLen - ulOffset;

                // 避免越界
                nDataLen = nDataLen > _DATA_SIZE ? _DATA_SIZE : nDataLen;

                // 由于上层随时可以读取数据,故需要增加自旋锁
                FILTER_ACQUIRE_LOCK(&pFilter->DataLock, bFlags);

                NdisZeroMemory(pFilter->Data, _DATA_SIZE);
                NdisMoveMemory(pFilter->Data, pData, nDataLen);

                FILTER_RELEASE_LOCK(&pFilter->DataLock, bFlags);
            }
            pCurrBuff = pNextBuff;
        }
        pCurrNbl = NET_BUFFER_LIST_NEXT_NBL(pCurrNbl);
    }
    return 0;
}

接收之后就是原始的数据缓冲区了。 

标签:pFilter,windows,LIST,FILTER,Filter,BUFFER,驱动,NET,NDIS
From: https://blog.csdn.net/m0_72813396/article/details/143351767

相关文章

  • windows 驱动实例分析系列: NDIS 6.0的Filter 驱动改造(一)
    NDIS生成的Filter例程已经非常完善,但根据需要还是要对它进行改造,以适应实际的需求,在这一类的改造中,主要涉及的三个方面:处理OID、发送数据包、接收数据包。需求和定义一般来说,Filter驱动要么需要对某些数据包进行处理、要么是需要对某些网络适配器的行为进行修改,所以需求最......
  • Windows部署rabbitmq
    本次安装环境:系统:Windows11软件建议版本:erlangOPT26.0.2rabbitmq3.12.4一、下载1.1下载erlang官网下载地址:1.2下载rabbitmq官网下载地址:建议使用解压版,安装版可能会在安装软件时出现查不到erlang环境的报错,导致安装失败。二、部署2.1部署erlang2.1.1安装http复制代码右键管......
  • 内置RC振荡器/抗干扰能力强VK1668 SOP24数码管驱动控制器/LED驱动器原厂技术支持
    产品品牌:永嘉微电/VINKA产品型号:VK1668封装形式:SOP24概述VK1668是一种带键盘扫描接口的数码管或点阵LED驱动控制专用芯片,内部集成有3线串行接口、数据锁存器、LED驱动、键盘扫描等电路。SEG脚接LED阳极,GRID脚接LED阴极,可支持13SEGx4GRID、12SEGx5GRID、11SEGx6GRID、10S......
  • 利用Msfvenom对Windows进行远程控制
    一、准备工作先在kali安装Apache2,下载代码如下sudoaptinstallapache2 启动Apache2服务serviceapache2start 在kali浏览器中输入你的kaliIP,得到该页面说明启动成功二、开始1.msf远控生成(1)在kali运行msf生成exemsfvenom-pwindows/meterpreter/reverse_t......
  • Nothing Phone(2)的灯带驱动研究笔记
    最近整了部NothingPhone(2),bl秒解的设定是真的舒服,所以买来第一时间就透了一遍(指root了)。然后半夜睡不着,就打算研究一下这个灯带是怎么调用的。然后就开始了,一段孤独的旅程充满烦恼~内核源码:很不幸,除了知道了灯带型号是aw20036之外没啥收获,原因无他,单纯看不懂代码,注释都不怎......
  • 渗透测试常用windows命令
    渗透测试是一种评估计算机系统、网络或Web应用安全性的实践,它通过模拟恶意黑客的攻击手段来识别潜在的安全漏洞。在渗透测试过程中,使用Windows命令行工具可以帮助测试者进行信息收集、系统分析等操作。以下是一些渗透测试中常用的Windows命令:1.**系统信息收集**  -`syst......
  • 机器人技术革新:人工智能的强力驱动
    内容概要在当今世界,机器人技术与人工智能的结合正如星星与大海,彼此辉映。随着科技的不断进步,人工智能不仅仅是为机器人赋予了“聪明的大脑”,更是推动了整个行业的快速发展。回顾机器人技术的发展历程,我们会发现,从简单的机械臂到如今高效的自主机器人,这一过程充满了创新与挑战......
  • Windows内核驱动-进程回调
    一、核心代码一共三部分:定义回调函数注册回调移除回调#include<ntddk.h>//定义回调函数,在后续实现VOIDProcessNotifyRoutine( _Inout_PEPROCESSProcess,//进程对象,这是个不透明结构,不建议强行使用其中的字段 _In_HANDLEProcessId,//进程ID _In_......
  • Mac和Windows最全快捷键 - Photoshop2024
    在数字化图像处理的世界里,Photoshop一直是专业设计师和摄影师的首选工具。无论是在图像编辑、图层处理还是各种效果应用上,Photoshop的功能都令人称赞。然而,Photoshop功能繁多,如果一一通过菜单查找,不仅耗时而且不够高效。熟练掌握快捷键可以极大地提高工作效率,让操作更加流畅。......
  • 利用 AWS 的事件驱动数据网格架构应对现代数据挑战
    背景   在当今数据驱动的世界中,企业必须适应数据管理、分析和利用方式的快速变化。传统的集中式系统和单片式架构虽然在历史上已经足够,但已无法满足企业日益增长的需求,因为企业需要更快地实时获取数据见解。事件驱动数据网格架构是这一领域的革命性框架,与AWS服务结合后,它将......