0%

使用NDIS6.0实现数据包过滤(4)

前言

在WIN7中可以使用 NDIS6 做网络过滤,在 NDIS6 中提供了一种 LightWeight Filter 的框架,
我们这里使用WDK源码中 src -> network -> ndis -> filter 工程作为基础。

修改device.c文件

这个文件主要是处理与应用层通讯的功能,我们可以在 FilterDeviceIoControl 函数中处理
自定义的控制码功能,使用时需要把原有的控制码处理程序删除。

修改filter.h文件

在文件的开头我们可以找到如下一系列宏定义,我们使用的是 NDISLWF 框架(source中定义),
所以只需要修改 NDISLWF 定义的内容,设备名称、服务名称、唯一标识都需要修改

1
2
3
4
5
6
7
#if NDISLWF
#define FILTER_FRIENDLY_NAME L"NDIS Sample LightWeight Filter"
#define FILTER_UNIQUE_NAME L"{5cbf81bd-5055-47cd-9055-a76b2b4e3697}" //<-修改
#define FILTER_SERVICE_NAME L"NDISLWF" //<-修改
#define LINKNAME_STRING L"\\DosDevices\\NDISLWF" //<-修改
#define NTDEVICE_STRING L"\\Device\\NDISLWF" //<-修改
#endif

修改filter.c文件

FilterSendNetBufferLists 函数中,处理发送数据包的功能。原函数的代码主要处理
调试和跟踪发送的数据包信息,如果我们不处理这些功能,就可以把相关代码全部删除

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
VOID FilterSendNetBufferLists(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN NDIS_PORT_NUMBER PortNumber,
IN ULONG SendFlags)
{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
PNET_BUFFER_LIST CurrNbl = NULL;
BOOLEAN DispatchLevel = FALSE;
BOOLEAN bFalse = FALSE;
PKGFLT_STATUS fStatus = STATUS_PASS;
DEBUGP(DL_TRACE, ("===>SendNetBufferList: NBL = %p.\n", NetBufferLists));
do
{
DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags);
// 调试的相关处理,如果不需要可以删除
#if DBG
// we should never get packets to send if we are not in running state
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
// If the filter is not in running state, fail the send
if (pFilter->State != FilterRunning)
{
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
CurrNbl = NetBufferLists;
while (CurrNbl)
{
NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_PAUSED;
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
}
NdisFSendNetBufferListsComplete(pFilter->FilterHandle,
NetBufferLists,
DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
break;
}
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
#endif
//////////////////////////////////////////////////////////////////////////
// 循环检测所有的包,决定是否拦截
CurrNbl = NetBufferLists;
while (CurrNbl != NULL)
{
fStatus = AnalysisPacket(pFilter, CurrNbl, FALSE);
if (fStatus == STATUS_DROP) break;
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
}
if (fStatus == STATUS_DROP)
{
CurrNbl = NetBufferLists;
while (CurrNbl != NULL)
{
NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_FAILURE;
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
}
NdisFSendNetBufferListsComplete(pFilter->FilterHandle,
NetBufferLists,
DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
break;
}
//////////////////////////////////////////////////////////////////////////
// 跟踪的相关处理,如果不需要可以删除
if (pFilter->TrackSends)
{
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
CurrNbl = NetBufferLists;
while (CurrNbl)
{
pFilter->OutstandingSends++;
FILTER_LOG_SEND_REF(1, pFilter, CurrNbl, pFilter->OutstandingSends);
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
}
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
}
// 数据包发送的正常调度函数
// If necessary, queue the NetBufferList in a local structure for later processing
NdisFSendNetBufferLists(pFilter->FilterHandle, NetBufferLists, PortNumber, SendFlags);
} while (bFalse);
DEBUGP(DL_TRACE, ("<===SendNetBufferList. \n"));
}

FilterReceiveNetBufferLists 函数中,处理接收数据包的功能。与发送原函数的类似,
代码主要处理调试和跟踪接收的数据包信息,同样也可以把相关代码全部删除

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
VOID FilterReceiveNetBufferLists(
IN NDIS_HANDLE FilterModuleContext,
IN PNET_BUFFER_LIST NetBufferLists,
IN NDIS_PORT_NUMBER PortNumber,
IN ULONG NumberOfNetBufferLists,
IN ULONG ReceiveFlags)
{

PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
BOOLEAN DispatchLevel;
ULONG Ref = 0;
BOOLEAN bFalse = FALSE;
PKGFLT_STATUS fStatus = STATUS_PASS;
PNET_BUFFER_LIST CurrNbl = NULL;
#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
//////////////////////////////////////////////////////////////////////////
// 循环检测所有的包
CurrNbl = NetBufferLists;
while (CurrNbl != NULL)
{
fStatus = AnalysisPacket(pFilter, CurrNbl, TRUE);
if (fStatus == STATUS_DROP) break;
CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl);
}
if (fStatus == STATUS_DROP)
{
if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags))
{
NdisFReturnNetBufferLists(pFilter->FilterHandle,
NetBufferLists,
DispatchLevel ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0);
}
break;
}
//////////////////////////////////////////////////////////////////////////
// 跟踪的相关处理,如果不需要可以删除
ASSERT(NumberOfNetBufferLists >= 1);
// If necessary, queue the NetBufferList in a local structure for later processing.
// We may need to travel the list, some of them may not need post processing
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);
}
// 数据包接收的正常调度函数
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));
}

数据包解析函数

与在 NDIS5 中定义的函数相似,但是数据包存储的格式有所变化

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
PKGFLT_STATUS AnalysisPacket(PMS_FILTER pFilter, PNET_BUFFER_LIST CurNbl, BOOLEAN bRecv)
{
ULONG TotalLength = 0;
PUCHAR PacketContent = NULL;
PETH_HEADER EthHeader = NULL;
PONE_PACKET OnePacket = NULL;
NTSTATUS NtStatus = STATUS_SUCCESS;
PKGFLT_STATUS fStatus = STATUS_PASS;
// 检查参数
if (pFilter == NULL) return STATUS_PASS;
if (CurNbl == NULL) return STATUS_PASS;
// 查询数据包的长度
TotalLength = GetOneNblLen(CurNbl);
if (TotalLength == 0) return STATUS_PASS;
// 申请数据包的空间
PacketContent = (PUCHAR)NdisAllocateMemoryWithTagPriority(
pFilter->FilterHandle, TotalLength, 'MEM', NormalPoolPriority);
if (PacketContent == NULL) return STATUS_PASS;
NdisZeroMemory(PacketContent, TotalLength);
// 获取数据包的内容
NtStatus = GetOneNblData(CurNbl, PacketContent, TotalLength);
if (!NT_SUCCESS(NtStatus))
{
NdisFreeMemory(PacketContent, 0, 0);
return STATUS_PASS;
}
// 到此PacketContent即为以太网数据包
// 我们可以对数据包进行解析和处理
NdisFreeMemory(PacketContent, 0, 0);
return STATUS_PASS;
}

获取数据包长度的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
ULONG GetOneNblLen(IN PNET_BUFFER_LIST CurNbl)
{
ULONG Length = 0;
PNET_BUFFER NetBuffer = NULL;
if (CurNbl == NULL) return 0;
NetBuffer = NET_BUFFER_LIST_FIRST_NB(CurNbl);
while (NetBuffer != NULL)
{
Length += NET_BUFFER_DATA_LENGTH(NetBuffer);
NetBuffer = NET_BUFFER_NEXT_NB(NetBuffer);
}
return Length;
}

获取数据包内容的函数

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
NTSTATUS GetOneNblData(IN PNET_BUFFER_LIST CurNbl, OUT PUCHAR Buffer, IN ULONG BufLen)
{
PNET_BUFFER CurNb = NULL;
PMDL CurMdl = NULL;
ULONG MdlOffset = 0;
PVOID MdlData = NULL;
ULONG MdlBufLen = 0;
ULONG CopyLen = 0;
ULONG BufOffset = 0;
// 检查参数的有效性
if (CurNbl == NULL) return STATUS_UNSUCCESSFUL;
if (Buffer == NULL) return STATUS_UNSUCCESSFUL;
if (BufLen == 0) return STATUS_UNSUCCESSFUL;
// 循环复制数据
CurNb = NET_BUFFER_LIST_FIRST_NB(CurNbl);
while (CurNb != NULL)
{
if (BufOffset >= BufLen) break;
CurMdl = NET_BUFFER_CURRENT_MDL(CurNb);
MdlOffset = NET_BUFFER_CURRENT_MDL_OFFSET(CurNb);
while (CurMdl != NULL)
{
if (BufOffset >= BufLen) break;
NdisQueryMdl(CurMdl, &MdlData, &MdlBufLen, NormalPagePriority);
// NBL->DataLength <= MDL1->ByteCount + ... + MDLx->ByteCount - NBL->CurrentMDLOffset
// 这里 Data length 不等于 Buffer Length
CopyLen = MdlBufLen - MdlOffset;
if (CopyLen > BufLen) CopyLen = BufLen;
// 复制数据到总缓冲区内
if ((MdlData != NULL) && (BufLen > 0))
{
NdisMoveMemory((Buffer + BufOffset), (PUCHAR)MdlData + MdlOffset, CopyLen);
BufOffset += CopyLen;
BufLen -= CopyLen; // 剩余空间大小
}
// 一般来说,只有第一个MDL的buffer才有偏移,其余的都没有。
// 如果offset大于了buflen,那么第一个MDL就没有存在的意义了。
MdlOffset = 0;
NdisGetNextMdl(CurMdl, &CurMdl);
}
CurNb = NET_BUFFER_NEXT_NB(CurNb);
}
return STATUS_SUCCESS;
}

修改INF文件

ndislwf.inf 中,修改如下项

1
2
3
4
5
6
7
;修改MS_NdisLwf设备名称
[MSFT.NTx86]
%NdisLwf_Desc%=Install, MS_NdisLwf
[MSFT.NTia64]
%NdisLwf_Desc%=Install, MS_NdisLwf
[MSFT.NTamd64]
%NdisLwf_Desc%=Install, MS_NdisLwf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
;修改ndislwf.sys驱动文件名
[SourceDisksFiles]
ndislwf.sys = 1
[ndislwf.copyfiles.sys]
ndislwf.sys, , , 2
[NdisLwf_Service_Inst]
DisplayName = %NdisLwf_Desc%
ServiceType = 1 ;SERVICE_KERNEL_DRIVER
StartType = 1 ;SERVICE_SYSTEM_START
ErrorControl = 1 ;SERVICE_ERROR_NORMAL
ServiceBinary = %12%\ndislwf.sys
LoadOrderGroup = NDIS
Description = %NdisLwf_Desc%
AddReg = Common.Params.reg
1
2
3
4
5
6
7
8
9
10
11
12
13
;修改NdisLwf服务名称
[Inst_Ndi]
HKR, Ndi, Service, , "NdisLwf"
HKR, Ndi, CoServices, 0x00010000, "NdisLwf"
HKR, Ndi, HelpText, , %NdisLwf_HelpText%
HKR, Ndi, FilterClass, , compression
HKR, Ndi, FilterType, 0x00010001, 0x00000002
HKR, Ndi\Interfaces, UpperRange, , "noupper"
HKR, Ndi\Interfaces, LowerRange, , "nolower"
HKR, Ndi\Interfaces, FilterMediaTypes, , "ethernet"
HKR, Ndi,FilterRunType, 0x00010001, 1
[Install.Remove.Services]
DelService = NdisLwf, 0x200