NDIS生成的Filter例程已经非常完善,但根据需要还是要对它进行改造,以适应实际的需求,在这一类的改造中,主要涉及的三个方面: 处理OID、发送数据包、接收数据包。
需求和定义
一般来说,Filter 驱动要么需要对某些数据包进行处理、要么是需要对某些网络适配器的行为进行修改,所以需求最终是处理OID请求、发送和接收数据包。
为了便于演示,将会提供下面3个最基本的功能:
- 发起OID请求;
- 发送ICMP数据包;
- 接收的数据包;
案例将会创建4个IOCTL来演示:
#define _NDIS_CONTROL_CODE(request,method) \
CTL_CODE(FILE_DEVICE_PHYSICAL_NETCARD, request, method, FILE_ANY_ACCESS)
// 获取当前存在的网卡个数
// 输出缓冲区是一个ULONG的值,这个值指出当前系统上有 N 个网络适配器
#define IOCTL_FILTER_GET_NUMBER _NDIS_CONTROL_CODE(14, METHOD_BUFFERED)
// 获取所有网卡的地址
// 输出缓冲区是一个 N*6 大小的缓冲区,根据加载顺序记录 Mac 地址
#define IOCTL_FILTER_GET_ALL_ADDRESS _NDIS_CONTROL_CODE(15, METHOD_BUFFERED)
// 发送一个UDP广播包
// IOCTL_FILTER_SEND_DATA 输入/输出缓冲区
typedef struct _tagPACKET_INFO
{
UCHAR SrcMac[_MAC_LENGTH];// Mac地址
UCHAR DesMac[_MAC_LENGTH];// Mac地址
ULONG SrcIPv4; // 源IP地址,源地址
ULONG DesIPv4; // 目的IP地址,源地址
// USHORT SrcPort; // 源端口 注意ICMP数据包没有使用这两个值
// USHORT DesPort; // 目的端口 注意ICMP数据包没有使用这两个值
USHORT Length; // 数据长度
CHAR Data[_DATA_SIZE]; // 数据内容
}PACKET_INFO, * PPACKET_INFO;
#define IOCTL_FILTER_SEND_DATA _NDIS_CONTROL_CODE(16, METHOD_BUFFERED)
// 接收最近的数据包
// 输入/输出缓冲区
#define IOCTL_FILTER_RECEIVE_DATA _NDIS_CONTROL_CODE(17, METHOD_BUFFERED)
这里的宏定义比较普通,只是NDIS自行封装了_NDIS_CONTROL_CODE(request,method) 。
设备对象和网络适配器
Filter层抽象了网络架构,无论是什么类型的网络适配器,它们对于Filter都是一样的接口,这也是为什么Filter驱动被用于网络数据包过滤的原因之一:
无论 以太网、Wifi、1394、蓝牙这些网络适配器都会在同一时间挂载Filter驱动,Filter驱动将作为所有的网络适配器过滤驱动来实现和设计的。
这里有一个概念上的区别,当Filter驱动被加载到内核中时,它作为一个模块,可能会实例化为多个Filter对象,每个Filter对象依附在一个网络适配器之上,这带来了两面性:
Filter驱动的通讯是针对Filter而不是每个网络适配器;
每个网络适配器都会有自己的上下文;
这两个点带来的直观影响是NDISFilterDeviceIoControl函数和具体的网络适配器不直接相关。
发送OID
NDIS 定义对象标识符 (OID) 值来标识适配器参数,其中包括操作参数,例如设备特征、可配置的设置和统计信息。这里使用获取网卡Mac地址来演示;
Mac地址涉及的OID包括:
1. OID_802_3_CURRENT_ADDRESS:
NIC 当前使用的地址。网络管理软件无法使用 NDIS 接口库设置当前工作站地址。 它必须将此地址设置为配置参数。
2. OID_802_3_PERMANENT_ADDRESS:
硬件中编码的 NIC 的地址。
代码看起来如下:
NDIS_STATUS FilterGetMacAddress(_In_ NDIS_HANDLE FilterModuleContext)
{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
UCHAR Mac[_MAC_LENGTH];
ULONG BytesProcessed = 0;
NDIS_STATUS Status = 0;
NdisZeroMemory(&Mac[0], _MAC_LENGTH);
Status = filterDoInternalRequest(
pFilter,
NdisRequestQueryInformation,
OID_802_3_PERMANENT_ADDRESS,
(PVOID)&Mac[0],
_MAC_LENGTH,
0,
0,
&BytesProcessed);
if (Status == NDIS_STATUS_SUCCESS)
{
RtlCopyMemory(&pFilter->Mac[0], &Mac[0], _MAC_LENGTH);
}
return Status;
}
NDIS_STATUS
filterDoInternalRequest(
_In_ PMS_FILTER FilterModuleContext,
_In_ NDIS_REQUEST_TYPE RequestType,
_In_ NDIS_OID Oid,
_Inout_updates_bytes_to_(InformationBufferLength, *pBytesProcessed)
PVOID InformationBuffer,
_In_ ULONG InformationBufferLength,
_In_opt_ ULONG OutputBufferLength,
_In_ ULONG MethodId,
_Out_ PULONG pBytesProcessed
)
{
FILTER_REQUEST FilterRequest;
PNDIS_OID_REQUEST NdisRequest = &FilterRequest.Request;
NDIS_STATUS Status;
ASSERT(pBytesProcessed != NULL);
*pBytesProcessed = 0;
NdisZeroMemory(NdisRequest, sizeof(NDIS_OID_REQUEST));
NdisInitializeEvent(&FilterRequest.ReqEvent);
NdisRequest->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
NdisRequest->Header.Revision = NDIS_OID_REQUEST_REVISION_1;
NdisRequest->Header.Size = sizeof(NDIS_OID_REQUEST);
NdisRequest->RequestType = RequestType;
switch (RequestType)
{
case NdisRequestQueryInformation:
NdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer =
InformationBuffer;
NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength =
InformationBufferLength;
break;
case NdisRequestSetInformation:
NdisRequest->DATA.SET_INFORMATION.Oid = Oid;
NdisRequest->DATA.SET_INFORMATION.InformationBuffer =
InformationBuffer;
NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
InformationBufferLength;
break;
case NdisRequestMethod:
NdisRequest->DATA.METHOD_INFORMATION.Oid = Oid;
NdisRequest->DATA.METHOD_INFORMATION.MethodId = MethodId;
NdisRequest->DATA.METHOD_INFORMATION.InformationBuffer =
InformationBuffer;
NdisRequest->DATA.METHOD_INFORMATION.InputBufferLength =
InformationBufferLength;
NdisRequest->DATA.METHOD_INFORMATION.OutputBufferLength = OutputBufferLength;
break;
default:
ASSERTMSG("Invalid request type in filterDoInternalRequest",
FALSE);
break;
}
NdisRequest->RequestId = (PVOID)FILTER_REQUEST_ID;
Status = NdisFOidRequest(FilterModuleContext->FilterHandle,
NdisRequest);
if (Status == NDIS_STATUS_PENDING)
{
NdisWaitEvent(&FilterRequest.ReqEvent, 0);
Status = FilterRequest.Status;
}
if (Status == NDIS_STATUS_SUCCESS)
{
if (RequestType == NdisRequestSetInformation)
{
*pBytesProcessed = NdisRequest->DATA.SET_INFORMATION.BytesRead;
}
if (RequestType == NdisRequestQueryInformation)
{
*pBytesProcessed = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
}
if (RequestType == NdisRequestMethod)
{
*pBytesProcessed = NdisRequest->DATA.METHOD_INFORMATION.BytesWritten;
}
//
// The driver below should set the correct value to BytesWritten
// or BytesRead. But now, we just truncate the value to InformationBufferLength
//
if (RequestType == NdisRequestMethod)
{
if (*pBytesProcessed > OutputBufferLength)
{
*pBytesProcessed = OutputBufferLength;
}
}
else
{
if (*pBytesProcessed > InformationBufferLength)
{
*pBytesProcessed = InformationBufferLength;
}
}
}
return Status;
}
标签:INFORMATION,windows,NdisRequest,OID,Filter,驱动,DATA,NDIS
From: https://blog.csdn.net/m0_72813396/article/details/142833163