【驱动】一个完整的wfp驱动

概述:一个完整的 WFP 驱动程序

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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
#include <ntddk.h>
#pragma warning(push)
#pragma warning(disable:4201) // unnamed struct/union
#pragma warning(disable:4995)
#include <fwpsk.h>
#pragma warning(pop)
#include <ndis.h>
#include <fwpmk.h>
#include <limits.h>
#include <ws2ipdef.h>
#include <in6addr.h>
#include <ip2string.h>
#include <strsafe.h>
#define INITGUID
#include <guiddef.h>
#define bool BOOLEAN
#define true TRUE
#define false FALSE
#define DEVICE_NAME L"\\Device\\WFP_TEST"
#define DEVICE_DOSNAME L"\\DosDevices\\WFP_TEST"
#define kmalloc(_s) ExAllocatePoolWithTag(NonPagedPool, _s, 'SYSQ')
#define kfree(_p) ExFreePool(_p)

DEFINE_GUID // {6812FC83-7D3E-499a-A012-55E0D85F348B}
(
GUID_ALE_AUTH_CONNECT_CALLOUT_V4,
0x6812fc83,
0x7d3e,
0x499a,
0xa0, 0x12, 0x55, 0xe0, 0xd8, 0x5f, 0x34, 0x8b
);

PDEVICE_OBJECT gDevObj;

HANDLE gEngineHandle = 0;
HANDLE gInjectHandle = 0;
//CalloutId
UINT32 gAleConnectCalloutId = 0;
//FilterId
UINT64 gAleConnectFilterId = 0;

/*
以下两个回调函数没啥用
*/
NTSTATUS NTAPI WallNotifyFn
(
IN FWPS_CALLOUT_NOTIFY_TYPE notifyType,
IN const GUID *filterKey,
IN const FWPS_FILTER *filter
)
{
KdPrint(("NotifyFn\n"));
return STATUS_SUCCESS;
}

VOID NTAPI WallFlowDeleteFn
(
IN UINT16 layerId,
IN UINT32 calloutId,
IN UINT64 flowContext
)
{
KdPrint(("FlowDeleteFn\n"));
return;
}

//协议代码转为名称
char* ProtocolIdToName(UINT16 id)
{
char *ProtocolName = kmalloc(16);
RtlZeroMemory(ProtocolName,16);
switch (id)
{
case 1:
strcpy_s(ProtocolName, 4 + 1, "ICMP");
break;
case 2:
strcpy_s(ProtocolName, 4 + 1, "IGMP");
break;
case 6:
strcpy_s(ProtocolName, 3 + 1, "TCP");
break;
case 17:
strcpy_s(ProtocolName, 3 + 1, "UDP");
break;
case 27:
strcpy_s(ProtocolName, 3 + 1, "RDP");
break;
default:
strcpy_s(ProtocolName, 7 + 1, "UNKNOWN");
break;
}
return ProtocolName;
}

//最重要的过滤函数
void NTAPI WallALEConnectClassify
(
IN const FWPS_INCOMING_VALUES0* inFixedValues,//此结构包含筛选层上每个数据字段的值
//incomingValue[index] => index的值是枚举类型FWPS_FIELDS_ALE_AUTH_CONNECT_V4,
//枚举名字说明了该值的类型例如:FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS 就是本地IP

IN const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,//此结构包含筛选层上每个元数据字段的值。
IN OUT void* layerData,//指向结构的指针,该结构描述正在过滤的层上的原始数据。此参数可能为NULL,
//这取决于所筛选的层和调用classfyFn0标注函数的条件。
//对于流层,此参数指向FWPS_stream_Callout_IO_PACKET 0结构。
//对于所有其他层,如果NetBufferList结构不是NULL,则该参数指向该结构。
IN const void* classifyContext,//由过滤器引擎指向与标注驱动程序关联的上下文数据的指针 没有找出该指针类型
IN const FWPS_FILTER* filter,//指向FWPS_FILTER1结构的指针。此结构描述指定筛选器操作的标注的筛选器。
IN UINT64 flowContext,//包含与数据流关联的上下文的UINT 64类型变量。如果没有与数据流相关联的上下文,则此参数为零。
//如果在不支持数据流的过滤层将标注添加到筛选引擎中,则clamfyFn1回调函数应忽略此参数
OUT FWPS_CLASSIFY_OUT* classifyOut //指向FWPS_GARGY_OUT 0结构的指针,该结构接收clamfyFn1回调函数返回给调用方的任何数据
)
{

char *ProtocolName = NULL;
DWORD LocalIp, RemoteIP;
PWCHAR Path = NULL;


do
{
Path = ExAllocatePoolWithTag(NonPagedPool, inMetaValues->processPath->size+2, 'NET');
if (NULL==Path)
{
break;
}

RtlZeroMemory(Path, inMetaValues->processPath->size + 2);
wcscpy_s(Path, inMetaValues->processPath->size / 2, (WCHAR*)inMetaValues->processPath->data);

LocalIp = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS].value.uint32;
RemoteIP = inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS].value.uint32;
ProtocolName = ProtocolIdToName(inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint16);


DbgPrint("进程ID : %d", (DWORD)(inMetaValues->processId));
DbgPrint("Path=%S", Path);
DbgPrint("本地地址=%u.%u.%u.%u ", (LocalIp >> 24) & 0xFF, (LocalIp >> 16) & 0xFF, (LocalIp >> 8) & 0xFF, LocalIp & 0xFF);
DbgPrint("端口%d\n", inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT].value.uint16);

DbgPrint("远程地址=%u.%u.%u.%u ", (RemoteIP >> 24) & 0xFF, (RemoteIP >> 16) & 0xFF, (RemoteIP >> 8) & 0xFF, RemoteIP & 0xFF);
DbgPrint("端口%d\n", inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT].value.uint16);
DbgPrint("协议名: %s\n", ProtocolName);


kfree(ProtocolName);
} while (0);


if (NULL != Path)
{
ExFreePoolWithTag(Path, 'NET');
}
classifyOut->actionType = FWP_ACTION_PERMIT;//允许连接

return;
}

NTSTATUS RegisterCalloutForLayer
(
IN const GUID* layerKey,
IN const GUID* calloutKey,
IN FWPS_CALLOUT_CLASSIFY_FN classifyFn,
IN FWPS_CALLOUT_NOTIFY_FN notifyFn,
IN FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN flowDeleteNotifyFn,
OUT UINT32* calloutId, //注册callout时返回此ID
OUT UINT64* filterId
)
{
NTSTATUS status = STATUS_SUCCESS;
FWPS_CALLOUT sCallout = { 0 };
FWPM_FILTER mFilter = { 0 };
FWPM_FILTER_CONDITION mFilter_condition[1] = { 0 };
FWPM_CALLOUT mCallout = { 0 };
FWPM_DISPLAY_DATA mDispData = { 0 };
BOOLEAN bCalloutRegistered = FALSE;

//这里未指定sCallout.flags
sCallout.calloutKey = *calloutKey; //一个唯一的GUID值,用来标记此callout
sCallout.classifyFn = classifyFn; //每当回调处理网络数据时,过滤器引擎将调用此函数,处理网络数据在这个回调函数里面处理.
sCallout.flowDeleteFn = flowDeleteNotifyFn; //每当终止由回调处理的数据流时,筛选器引擎将调用此函数
sCallout.notifyFn = notifyFn; //卸载callout时,会调用这个回调

//要使用哪个设备对象注册
status = FwpsCalloutRegister(gDevObj, //自己创建的设备对象
&sCallout, //该结构体有用的是指定了classifyFn回调,处理连接时的数据就会用到这个回调函数.
calloutId //返回的calloutID ,取消注册callout会用到这个值
);
if (!NT_SUCCESS(status))
goto exit;

bCalloutRegistered = TRUE;


mDispData.name = L"WFP TEST"; //可选的名字
mDispData.description = L"yxp's WFP TEST"; //可选的描述
//你感兴趣的内容
mCallout.applicableLayer = *layerKey; //过滤层标识符 此过滤层允许授权对传出tcp连接的连接请求,
//以及基于发送的第一个数据包授权传出非tcp通信量

//你感兴趣的内容的GUID
mCallout.calloutKey = *calloutKey; //该GUID值必须与FwpsCalloutRegister注册时的GUID值相同.
mCallout.displayData = mDispData;

//向过滤引擎添加callout
status = FwpmCalloutAdd(gEngineHandle,
&mCallout, //flags没有设置
NULL, //安全描述符 可以为NULL
NULL); //返回一个ID 与FwpsCalloutRegister函数返回的ID是相同的.
if (!NT_SUCCESS(status))
goto exit;


//FWPM_action0结构指定在所有筛选条件都为真时所采取的操作
mFilter.action.calloutKey = *calloutKey;
//交给callout处理 由callout来决定返回阻止(block)或者允许(permit)
mFilter.action.type = FWP_ACTION_CALLOUT_TERMINATING;

//描述
mFilter.displayData.name = L"WFP TEST";
mFilter.displayData.description = L"yxp's WFP TEST";


mFilter.layerKey = *layerKey; //这个值和FwpmCalloutAdd里面使用的值一样 过滤层标识符 此过滤层允许授权对传出tcp连接的连接请求,
//以及基于发送的第一个数据包授权传出非tcp通信量

//过滤条件数
mFilter.numFilterConditions = 0;
//过滤条件
mFilter.filterCondition = mFilter_condition;

mFilter.subLayerKey = FWPM_SUBLAYER_UNIVERSAL; //此子层承载所有未分配给任何其他子层的筛选器

//BFE将根据过滤条件自动分配权重
mFilter.weight.type = FWP_EMPTY;

//添加一个新的过滤器对象到系统中
status = FwpmFilterAdd(gEngineHandle, &mFilter, NULL, filterId);
if (!NT_SUCCESS(status))
goto exit;
exit:
if (!NT_SUCCESS(status))
{
if (bCalloutRegistered)
{
FwpsCalloutUnregisterById(*calloutId);
}
}
return status;
}

NTSTATUS WallRegisterCallouts()
{
NTSTATUS status = STATUS_SUCCESS;
BOOLEAN bInTransaction = FALSE;
BOOLEAN bEngineOpened = FALSE;
FWPM_SESSION session = { 0 };

//置此标志时,会话结束时将自动删除在会话期间添加的任何对象
session.flags = FWPM_SESSION_FLAG_DYNAMIC;

//开启WFP引擎
status = FwpmEngineOpen(NULL,
RPC_C_AUTHN_WINNT,
NULL,
&session,
&gEngineHandle);
if (!NT_SUCCESS(status))
goto exit;
bEngineOpened = TRUE;
// 在当前会话中开始显式事务
status = FwpmTransactionBegin(gEngineHandle, 0);
if (!NT_SUCCESS(status))
goto exit;
bInTransaction = TRUE;
//注册回调函数
status = RegisterCalloutForLayer(
&FWPM_LAYER_ALE_AUTH_CONNECT_V4, //此过滤层允许授权对传出tcp连接的连接请求,
//以及基于发送的第一个数据包授权传出非tcp通信量
&GUID_ALE_AUTH_CONNECT_CALLOUT_V4,
WallALEConnectClassify,
WallNotifyFn,
WallFlowDeleteFn,
&gAleConnectCalloutId,
&gAleConnectFilterId);
if (!NT_SUCCESS(status))
{
DbgPrint("RegisterCalloutForLayer失败!\n");
goto exit;
}
//确认所有内容并提交,让回调函数正式发挥作用
status = FwpmTransactionCommit(gEngineHandle);
if (!NT_SUCCESS(status))
goto exit;
bInTransaction = FALSE;
exit:
if (!NT_SUCCESS(status))
{
if (bInTransaction)
{
FwpmTransactionAbort(gEngineHandle);
}
if (bEngineOpened)
{
FwpmEngineClose(gEngineHandle);
gEngineHandle = 0;
}
}
return status;
}

NTSTATUS WallUnRegisterCallouts()
{
if (gEngineHandle != 0)
{
//删除FilterId
FwpmFilterDeleteById(gEngineHandle, gAleConnectFilterId);
//删除CalloutId
FwpmCalloutDeleteById(gEngineHandle, gAleConnectCalloutId);
//清空FilterId
gAleConnectFilterId = 0;
//反注册CalloutId
FwpsCalloutUnregisterById(gAleConnectCalloutId);
//清空CalloutId
gAleConnectCalloutId = 0;
//关闭引擎
FwpmEngineClose(gEngineHandle);
gEngineHandle = 0;
}
return STATUS_SUCCESS;
}

VOID DriverUnload(PDRIVER_OBJECT driverObject)
{
NTSTATUS status;
UNICODE_STRING deviceDosName = { 0 };
status = WallUnRegisterCallouts();
if (!NT_SUCCESS(status))
{
DbgPrint("WallUnRegisterCallouts失败\n");
return;
}
RtlInitUnicodeString(&deviceDosName, DEVICE_DOSNAME);
IoDeleteSymbolicLink(&deviceDosName);
if (gDevObj)
{
IoDeleteDevice(gDevObj);
gDevObj = NULL;
}
DbgPrint("驱动卸载成功\n");
}

NTSTATUS DriverEntry(PDRIVER_OBJECT driverObject, PUNICODE_STRING registryPath)
{
UNICODE_STRING deviceName = { 0 };
UNICODE_STRING deviceDosName = { 0 };
NTSTATUS status = STATUS_SUCCESS;
driverObject->DriverUnload = DriverUnload;
RtlInitUnicodeString(&deviceName, DEVICE_NAME);
status = IoCreateDevice(driverObject,
0,
&deviceName,
FILE_DEVICE_NETWORK,
0,
FALSE,
&gDevObj);
if (!NT_SUCCESS(status))
{
DbgPrint("创建设备对象失败\n");
return STATUS_UNSUCCESSFUL;
}
RtlInitUnicodeString(&deviceDosName, DEVICE_DOSNAME);
status = IoCreateSymbolicLink(&deviceDosName, &deviceName);
if (!NT_SUCCESS(status))
{
DbgPrint("创建符号链接失败\n");
return STATUS_UNSUCCESSFUL;
}
status = WallRegisterCallouts();
if (!NT_SUCCESS(status))
{
DbgPrint("WallRegisterCallouts 失败!\n");
return STATUS_UNSUCCESSFUL;
}
DbgPrint("过滤驱动加载成功\n");
return status;
}



【驱动】一个完整的wfp驱动
https://hodlyounger.github.io/A_OS/Windows/驱动/【驱动】一个完整的wfp驱动/
作者
mingming
发布于
2023年10月27日
许可协议