0%

使用NDIS5.1实现数据包过滤(3)

前言

在XP中可以使用 NDIS5 做网络过滤,在《WINDOWS内核安全与驱动开发》一书中,
NDIS5 做了非常详尽的解释,这里就不再做原理性的探讨,只处理具体的应用方法。
整体框架采用WDK源码中 src -> network -> ndis -> passthru 工程作为基础。

修改passthru.c文件

如下 宏定义 为与应用层通讯的 控制设备 的名称,这里修改为其他需要的名称

1
2
#define LINKNAME_STRING     L"\\DosDevices\\Passthru"
#define NTDEVICE_STRING L"\\Device\\Passthru"

DriverEntry 函数中,如下为 协议名称 的定义,这里也要修改为其他需要的名称

1
2
NdisInitUnicodeString(&Name, L"Passthru");    // 协议名称
PChars.Name = Name;

PtDispatch 函数中,如下为 控制码 的处理,这里可以添加自定义的控制码处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
switch (irpStack->MajorFunction)
{
case IRP_MJ_CREATE:
break;
case IRP_MJ_CLEANUP:
break;
case IRP_MJ_CLOSE:
break;
case IRP_MJ_DEVICE_CONTROL:
// 这里添加自定义的控制码处理
break;
default:
break;
}

修改miniport.c文件

MPSend 函数开始的位置,判断完设备状态后,调用我们的数据包解析函数

1
2
3
4
5
6
7
8
9
10
if (pAdapt->MPDeviceState > NdisDeviceStateD0)
{
return NDIS_STATUS_FAILURE;
}
// 组合数据包并进行分析
fStatus = AnalysisPacket(Packet, FALSE);
if (fStatus == STATUS_DROP)
{
return NDIS_STATUS_FAILURE; // 丢弃包
}

MPSendPackets 函数开始的for循环体中,判断完设备状态后,调用我们的数据包解析函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if (pAdapt->MPDeviceState > NdisDeviceStateD0)
{
NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
Packet,
NDIS_STATUS_FAILURE);
continue;
}
// 组合数据包并进行分析
fStatus = AnalysisPacket(Packet, FALSE);
if (fStatus == STATUS_DROP)
{
NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
Packet,
NDIS_STATUS_FAILURE);
continue; // 丢弃包
}

MPTransferData 函数中,调用 NdisTransferData 成功后,调用我们的数据包解析函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
NdisTransferData(&Status,
pAdapt->BindingHandle,
MiniportReceiveContext,
ByteOffset,
BytesToTransfer,
Packet,
BytesTransferred);
if (Status == NDIS_STATUS_SUCCESS)
{
// 组合数据包并进行分析
fStatus = AnalysisPacket(Packet, TRUE);
if (fStatus == STATUS_DROP)
{
Status = NDIS_STATUS_FAILURE; // 丢弃包
}
}

修改protocol.c文件

PtTransferDataComplete 函数的开始,定义变量以后,首先调用我们的数据包解析函数

1
2
3
4
5
6
7
8
PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
PKGFLT_STATUS fStatus;
// 组合数据包并进行分析
fStatus = AnalysisPacket(Packet, TRUE);
if (fStatus == STATUS_DROP)
{
Status = NDIS_STATUS_FAILURE; // 丢弃包
}

PtReceive 函数的开始,调用 NdisGetReceivedPacket 成功后,调用我们的数据包解析函数

1
2
3
4
5
6
7
8
9
10
Packet = NdisGetReceivedPacket(pAdapt->BindingHandle, MacReceiveContext);
if (Packet != NULL)
{
// 组合数据包并进行分析
fStatus = AnalysisPacket(Packet, TRUE);
if (fStatus == STATUS_DROP)
{
Status = NDIS_STATUS_FAILURE; // 丢弃包
break;
}

PtReceivePacket 函数的开始,判断完设备状态后,调用我们的数据包解析函数

1
2
3
4
5
6
7
8
9
10
if ((!pAdapt->MiniportHandle) || (pAdapt->MPDeviceState > NdisDeviceStateD0))
{
return 0;
}
// 组合数据包并进行分析
fStatus = AnalysisPacket(Packet, TRUE);
if (fStatus == STATUS_DROP)
{
return 0; // 丢弃包
}

数据包解析函数

数据包解析函数返回值的定义:

1
2
3
4
typedef enum {
STATUS_PASS = 0,
STATUS_DROP = 1
} PKGFLT_STATUS;

如下为数据包解析函数,拿到以太网数据包后,可以根据相关规定进行格式解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
PKGFLT_STATUS AnalysisPacket(PNDIS_PACKET Packet, BOOLEAN bRecv)
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PNDIS_BUFFER NdisBuffer = NULL;
UINT32 TotalLength = 0;
UINT32 PhysicalCount = 0;
UINT32 BufferCount = 0;
PUCHAR PacketContent = NULL;
PUCHAR tempbuf = NULL;
UINT32 copysize = 0;
UINT32 DataOffset = 0;
// 检查参数
if (Packet == NULL) return STATUS_PASS;
// 查询第一个NDIS_BUFFER(MDL)
NdisQueryPacket(Packet, // NDIS_PACKET
&PhysicalCount, // 内存中的物理块数
&BufferCount, // NDIS_BUFFER(MDL)个数
&NdisBuffer, // 首个NDIS_BUFFER(MDL)
&TotalLength); // 总共的数据长度
// 申请组合包的内存
Status = NdisAllocateMemoryWithTag(&PacketContent, TotalLength, 'MEM');
if (Status != NDIS_STATUS_SUCCESS)
return STATUS_PASS;
NdisZeroMemory(PacketContent, TotalLength);
// 循环组合包
while (NdisBuffer != NULL)
{
// 取得NDIS_BUFFER(MDL)的缓存区地址
NdisQueryBufferSafe(NdisBuffer,
&tempbuf, // 缓冲区地址
&copysize, // 缓冲区大小
NormalPagePriority);
// 如果tempbuf为NULL,说明系统资源不足
if (tempbuf == NULL)
{
NdisFreeMemory(PacketContent, 0, 0);
return STATUS_PASS;
}
// 组合包信息
NdisMoveMemory(PacketContent + DataOffset, tempbuf, copysize);
DataOffset += copysize;
// 获得下一个NDIS_BUFFER
NdisGetNextBuffer(NdisBuffer, &NdisBuffer);
}
// 到此PacketContent即为以太网数据包
// 我们可以对数据包进行解析和处理
NdisFreeMemory(PacketContent, 0, 0);
return STATUS_PASS;
}

修改INF文件

netsf_m.inf 文件中,修改如下项

1
2
3
4
5
6
7
8
9
10
11
;修改ms_passthrump小端口设备名称
[ControlFlags]
ExcludeFromSelect = ms_passthrump
[MSFT]
%PassthruMP_Desc% = PassthruMP.ndi, ms_passthrump
[MSFT.NTx86]
%PassthruMP_Desc% = PassthruMP.ndi, ms_passthrump
[MSFT.NTia64]
%PassthruMP_Desc% = PassthruMP.ndi, ms_passthrump
[MSFT.NTamd64]
%PassthruMP_Desc% = PassthruMP.ndi, ms_passthrump
1
2
3
4
5
;修改PassthruMP服务名称
[PassthruMP.ndi.AddReg]
HKR, Ndi, Service, 0, PassthruMP
[PassthruMP.ndi.Services]
AddService = PassthruMP, 0x2, PassthruMP.AddService
1
2
3
4
5
6
7
;修改passthru.sys驱动文件名
[PassthruMP.AddService]
ServiceType = 1 ;SERVICE_KERNEL_DRIVER
StartType = 3 ;SERVICE_DEMAND_START
ErrorControl = 1 ;SERVICE_ERROR_NORMAL
ServiceBinary = %12%\passthru.sys
AddReg = PassthruMP.AddService.AddReg

netsf.inf 文件中,修改如下项

1
2
3
4
5
6
7
8
9
;修改ms_passthru协议设备名称
[MSFT]
%Passthru_Desc% = Passthru.ndi, ms_passthru
[MSFT.NTx86]
%Passthru_Desc% = Passthru.ndi, ms_passthru
[MSFT.NTia64]
%Passthru_Desc% = Passthru.ndi, ms_passthru
[MSFT.NTamd64]
%Passthru_Desc% = Passthru.ndi, ms_passthru
1
2
3
;修改Passthru服务名称
[Passthru.ndi.Services]
AddService = Passthru, , Passthru.AddService
1
2
3
4
5
6
7
8
9
10
;修改passthru.sys驱动文件名
[Passthru.AddService]
DisplayName = %PassthruService_Desc%
ServiceType = 1 ;SERVICE_KERNEL_DRIVER
StartType = 3 ;SERVICE_DEMAND_START
ErrorControl = 1 ;SERVICE_ERROR_NORMAL
ServiceBinary = %12%\passthru.sys
AddReg = Passthru.AddService.AddReg
[Passthru.Files.Sys]
passthru.sys, , , 2
1
2
3
4
5
6
7
8
9
;修改ms_passthrump小端口设备名称,修改Passthru服务名称
[Passthru.ndi.AddReg]
HKR, Ndi, HelpText, , %Passthru_HELP%
HKR, Ndi, FilterClass, , failover
HKR, Ndi, FilterDeviceInfId, , ms_passthrump
HKR, Ndi, Service, , Passthru
HKR, Ndi\Interfaces, UpperRange, , noupper
HKR, Ndi\Interfaces, LowerRange, , nolower
HKR, Ndi\Interfaces, FilterMediaTypes, , "ethernet, tokenring, fddi, wan"