//////////////////////////////////////////////////////////////////////////////////////////////////
/*
因WFP的资料极度匮乏,特公示。
注释:这是初级的,入门的,更深的等待你挖掘。
这里有两个例子:
1.一个是纯内核驱动的。
2.一个是R0和R3紧密配合使用的。
made by correy
made at 2016.08.17
homepage:http://correy.webs.com
*/
//////////////////////////////////////////////////////////////////////////////////////////////////
//驱动代码如下:
#pragma once
#include <ntifs.h>
#include <Fwpsk.h>
#include <windef.h>
#include <initguid.h> //静态定义UUID用的,否则:error LNK2001。
#include <Fwpmk.h>
#include <Ntstrsafe.h>
#include <ndis.h>
#include <Wsk.h>
#include <ipmib.h>
#include <netpnp.h>
#include <ntintsafe.h>
#include <intrin.h>
#pragma warning(disable:4047)
#pragma warning(disable:4028)
#define TAG 'test' //test
PDEVICE_OBJECT deviceObject;
DEFINE_GUID(CALLOUTKEY, 0x99999999, 0x9999, 0x9999, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99);
VOID NTAPI ClassifyFn(
IN const FWPS_INCOMING_VALUES0 *inFixedValues,
IN const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
IN OUT VOID *layerData,
IN const FWPS_FILTER0 *filter,
IN UINT64 flowContext,
OUT FWPS_CLASSIFY_OUT0 *classifyOut
)
{
KdPrint(("ClassifyFn.\r\n"));
}
NTSTATUS NTAPI NotifyFn(IN FWPS_CALLOUT_NOTIFY_TYPE notifyType, IN const GUID *filterKey, IN const FWPS_FILTER0 *filter)
{
return STATUS_SUCCESS;
}
VOID Unload(IN PDRIVER_OBJECT DriverObject)
{
NTSTATUS status;
UNICODE_STRING uniWin32NameString;
status = FwpsCalloutUnregisterByKey(&CALLOUTKEY); ASSERT(NT_SUCCESS(status));
//RtlInitUnicodeString( &uniWin32NameString, L"\\DosDevices\\hpm" );
//IoDeleteSymbolicLink( &uniWin32NameString );
IoDeleteDevice(deviceObject);// Delete the device object
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
NTSTATUS NtStatus = STATUS_SUCCESS;
UNICODE_STRING ntUnicodeString;
UNICODE_STRING ntWin32NameString;
FWPS_CALLOUT0 sCallout ={0};
UINT32 CalloutId;// Variable for the run-time callout identifier
KdBreakPoint();
__debugbreak();
DriverObject->DriverUnload = Unload;
RtlInitUnicodeString( &ntUnicodeString, L"\\Device\\hpm");
NtStatus = IoCreateDevice(DriverObject, 0, &ntUnicodeString, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &deviceObject);
ASSERT (NT_SUCCESS( NtStatus ));
//RtlInitUnicodeString( &ntWin32NameString, L"\\DosDevices\\hpm" );
//NtStatus = IoCreateSymbolicLink(&ntWin32NameString, &ntUnicodeString );
//ASSERT (NT_SUCCESS( NtStatus ));
sCallout.calloutKey = CALLOUTKEY;
sCallout.classifyFn = ClassifyFn;
sCallout.notifyFn = NotifyFn;
NtStatus = FwpsCalloutRegister0(deviceObject, &sCallout, &CalloutId);
ASSERT (NT_SUCCESS( NtStatus ));
return NtStatus;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
//应用层的代码如下:
#include <windows.h>
#include <fwpmu.h>
#include <stdio.h>
#include <assert.h>
#include <intrin.h>
#include <conio.h>
#include <initguid.h> //静态定义UUID用的,否则:error LNK2001。
#pragma comment(lib, "fwpuclnt.lib")
const GUID PROVIDER_KEY = {0x5fb216a8, 0xe2e8, 0x4024, { 0xb8, 0x53, 0x39, 0x1a, 0x41, 0x68, 0x64, 0x1e }};
DEFINE_GUID(CALLOUTKEY, 0x99999999, 0x9999, 0x9999, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99);
DWORD Install()
/*
功能:开启内核的WFP的Callout。
参考:
1.https://msdn.microsoft.com/en-us/library/windows/desktop/bb427376(v=vs.85).aspx
2.Windows-driver-samples-master\network\trans\msnmntr
*/
{
HANDLE engine = NULL;
FWPM_SESSION0 session;
memset(&session, 0, sizeof(session));
session.displayData.name = L"SDK Examples";// The session name isn't required but may be useful for diagnostics.
session.txnWaitTimeoutInMSec = INFINITE;// Set an infinite wait timeout, so we don't have to handle FWP_E_TIMEOUT errors while waiting to acquire the transaction lock.
session.flags = FWPM_SESSION_FLAG_DYNAMIC;// Let the Base Filtering Engine cleanup after us.
DWORD result = FwpmEngineOpen0(NULL, RPC_C_AUTHN_DEFAULT, NULL, &session, &engine);// The authentication service should always be RPC_C_AUTHN_DEFAULT.
assert(ERROR_SUCCESS == result);
result = FwpmTransactionBegin0(engine, 0);// We add the provider and sublayer from within a single transaction to make it easy to clean up partial results in error paths.
assert(ERROR_SUCCESS == result);
/*
此处不是必要的调用:
1.FwpmProviderAdd0
2.FwpmSubLayerAdd0
3.如果加上更好。
*/
//不添加过滤条件,WFP的内核Callout汗函数也不会调用。
FWPM_FILTER filter;
RtlZeroMemory(&filter, sizeof(FWPM_FILTER));
filter.layerKey = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
filter.displayData.name = L"name";
filter.displayData.description = L"description";
filter.action.type = FWP_ACTION_CALLOUT_INSPECTION; // We're only doing inspection.
filter.action.calloutKey = CALLOUTKEY;
filter.weight.type = FWP_EMPTY; // auto-weight.
filter.numFilterConditions = 0;
result = FwpmFilterAdd(engine, &filter, NULL, NULL);
assert(ERROR_SUCCESS == result);
// Once all the adds have succeeded, we commit the transaction to persist the new objects.
result = FwpmTransactionCommit0(engine);
assert(ERROR_SUCCESS == result);
_getch();//一调用FwpmEngineClose0效果就没有了,就是内核的ClassifyFn就不运行了。
// FwpmEngineClose0 accepts null engine handles, so we needn't precheck for null.
// Also, when closing an engine handle, any transactions still in progress are automatically aborted, so we needn't explicitly abort the transaction in error paths.
FwpmEngineClose0(engine);
return result;
}
int _tmain(int argc, _TCHAR* argv[])
{
DebugBreak();
__debugbreak();
//运行/测试前确保驱动加载。
DWORD D = Install();
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
//如果需要SOURCES文件,SOURCES文件内容如下:
TARGETNAME=wfp
TARGETTYPE=DRIVER
LINKER_FLAGS = $(LINKER_FLAGS)/INTEGRITYCHECK
INCLUDES=\
$(DDK_INC_PATH);
TARGETLIBS=\
$(DDK_LIB_PATH)\ntoskrnl.lib \
$(DDK_LIB_PATH)\ndis.lib \
$(DDK_LIB_PATH)\fwpkclnt.lib \
$(SDK_LIB_PATH)\uuid.lib
TARGETLIBS=$(TARGETLIBS) $(DDK_LIB_PATH)\Ntstrsafe.lib
C_DEFINES=$(C_DEFINES) -DBINARY_COMPATIBLE=0 -DNT -DUNICODE -D_UNICODE -DNDIS60 -DNDIS_SUPPORT_NDIS6
SOURCES= wfp.c
//////////////////////////////////////////////////////////////////////////////////////////////////
/*
纯驱动版的。
注释:可以没有用FwpmSubLayerAdd添加自己的SubLayer,而是用FWPM_SUBLAYER_UNIVERSAL设置subLayerKey
*/
#pragma once
#include <ntifs.h>
#include <Fwpsk.h>
#include <windef.h>
#include <initguid.h> //静态定义UUID用的,否则:error LNK2001。
#include <Fwpmk.h>
// Context structure to be associated with the filters
typedef struct FILTER_CONTEXT_ {
//.
//. // Driver-specific content
//.
int test;
} FILTER_CONTEXT, *PFILTER_CONTEXT;
#define FILTER_CONTEXT_POOL_TAG 'fcpt'// Memory pool tag for filter context structures
// Context structure to be associated with data flows
typedef struct FLOW_CONTEXT_ {
//...
int test;
} FLOW_CONTEXT, *PFLOW_CONTEXT;
#define FLOW_CONTEXT_POOL_TAG 'fcpt'
PDEVICE_OBJECT deviceObject;
UINT32 CalloutId;// Variable for the run-time callout identifier
FWPS_CALLOUT0 Callout ={0};
HANDLE injectionHandle;// Injection handle
HANDLE gEngineHandle;
DEFINE_GUID(WFP_TEST_GUID, 0x99999999, 0x9999, 0x9999, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99);
DEFINE_GUID(WFP_TEST_LAYER, 0x88888888, 0x8888, 0x8888, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88);
// Prototypes for the callout's callout functions
VOID NTAPI ClassifyFn(
IN const FWPS_INCOMING_VALUES0 *inFixedValues,
IN const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
IN OUT VOID *layerData,
IN const FWPS_FILTER0 *filter,
IN UINT64 flowContext,
OUT FWPS_CLASSIFY_OUT0 *classifyOut
)
{
}
NTSTATUS NTAPI NotifyFn(
IN FWPS_CALLOUT_NOTIFY_TYPE notifyType,
IN const GUID *filterKey,
IN const FWPS_FILTER0 *filter
)
{
NTSTATUS NtStatus = STATUS_SUCCESS;
PFILTER_CONTEXT context;
ASSERT(filter != NULL);
switch(notifyType)// Switch on the type of notification
{
case FWPS_CALLOUT_NOTIFY_ADD_FILTER:// A filter is being added to the filter engine
//context = (PFILTER_CONTEXT)ExAllocatePoolWithTag(NonPagedPool, sizeof(FILTER_CONTEXT), FILTER_CONTEXT_POOL_TAG);// Allocate the filter context structure
//if (context == NULL) {// Check the result of the memory allocation
// return STATUS_INSUFFICIENT_RESOURCES;// Return error
//}
// Initialize the filter context structure
//...
//filter->context = (UINT64)context;// Associate the filter context structure with the filter
break;
case FWPS_CALLOUT_NOTIFY_DELETE_FILTER:// A filter is being removed from the filter engine
context = (PFILTER_CONTEXT)filter->context;// Get the filter context structure from the filter
if (context) {// Check whether the filter has a context
// Cleanup the filter context structure
//...
//ExFreePoolWithTag(context, FILTER_CONTEXT_POOL_TAG);// Free the memory for the filter context structure
}
break;
case FWPS_CALLOUT_NOTIFY_ADD_FILTER_POST_COMMIT:
break;
default:// Unknown notification
// Do nothing
break;
}
return STATUS_SUCCESS;
return NtStatus;
}
VOID NTAPI FlowDeleteFn(
IN UINT16 layerId,
IN UINT32 calloutId,
IN UINT64 flowContext
)
{
PFLOW_CONTEXT context;
context = (PFLOW_CONTEXT)flowContext;// Get the flow context structure
// Cleanup the flow context structure
//...
//ExFreePoolWithTag(context, FLOW_CONTEXT_POOL_TAG);// Free the memory for the flow context structure
}
VOID Unload(IN PDRIVER_OBJECT DriverObject)
{
NTSTATUS status;
FwpmEngineClose0(gEngineHandle);
status = FwpsCalloutUnregisterById0(CalloutId);// Unregister the callout
if (status == STATUS_DEVICE_BUSY)// Check result
{
// For each data flow that is being processed by the callout that has an associated context,
// clean up the context and then call FwpsFlowRemoveContext0 to remove the context from the data flow.
//...
status = FwpsCalloutUnregisterById0(CalloutId);// Finish unregistering the callout
}
if (status != STATUS_SUCCESS)// Check status
{
// Handle error
//...
}
IoDeleteDevice(deviceObject);// Delete the device object
status = FwpsInjectionHandleDestroy0(injectionHandle);// Destroy the injection handle
if (status != STATUS_SUCCESS)// Check status
{
// Handle error
//...
}
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
NTSTATUS NtStatus = STATUS_SUCCESS;
FWPM_SUBLAYER0 SubLayer;
FWPM_SESSION0 session = {0};
FWPM_FILTER0 filter = {0};
FWPM_FILTER_CONDITION0 filterConditions[3] = {0};
FWPM_CALLOUT0 mCallout = {0};
FWPM_DISPLAY_DATA0 displayData = {0};
KdBreakPoint();
DriverObject->DriverUnload = Unload;// Specify the callout driver's Unload function
NtStatus = IoCreateDevice(DriverObject, 0, NULL, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &deviceObject);// Create a device object
if (!NT_SUCCESS( NtStatus )) {
return NtStatus;
}
//WDK文档的Registering Callouts with the Filter Engine章节没有这个函数,可是卸载里有用这个变量。DDPROXY有。
NtStatus = FwpsInjectionHandleCreate0(AF_INET, FWPS_INJECTION_TYPE_TRANSPORT, &injectionHandle);
if (!NT_SUCCESS(NtStatus)) {
IoDeleteDevice(deviceObject);
return NtStatus;
}
session.flags = FWPM_SESSION_FLAG_DYNAMIC;
NtStatus = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &gEngineHandle);
if (!NT_SUCCESS(NtStatus)) {
FwpsInjectionHandleDestroy0(injectionHandle);
IoDeleteDevice(deviceObject);
return NtStatus;
}
NtStatus = FwpmTransactionBegin0(gEngineHandle, 0);
if (!NT_SUCCESS(NtStatus)) {
FwpmEngineClose0(gEngineHandle);
FwpsInjectionHandleDestroy0(injectionHandle);
IoDeleteDevice(deviceObject);
return NtStatus;
}
RtlZeroMemory(&SubLayer, sizeof(FWPM_SUBLAYER0));
SubLayer.subLayerKey = WFP_TEST_LAYER;
SubLayer.displayData.name = L"WFP TEST NAME";
SubLayer.displayData.description = L"WFP TEST DESCRIPTION";
SubLayer.flags = 0;
SubLayer.weight = FWP_EMPTY; // auto-weight.;
NtStatus = FwpmSubLayerAdd0(gEngineHandle, &SubLayer, NULL);
if (!NT_SUCCESS(NtStatus)) {
FwpmEngineClose0(gEngineHandle);
FwpsInjectionHandleDestroy0(injectionHandle);
IoDeleteDevice(deviceObject);
return NtStatus;
}
Callout.calloutKey = WFP_TEST_GUID;
Callout.flags = 0;
Callout.classifyFn = ClassifyFn;
Callout.notifyFn = NotifyFn;
Callout.flowDeleteFn = FlowDeleteFn;
NtStatus = FwpsCalloutRegister0(deviceObject, &Callout, &CalloutId);
if (!NT_SUCCESS( NtStatus )) {
FwpmEngineClose0(gEngineHandle);
FwpsInjectionHandleDestroy0(injectionHandle);
IoDeleteDevice(deviceObject);
return NtStatus;
}
displayData.name = L"XXX name";
displayData.description = L"XXX description";
mCallout.calloutKey = WFP_TEST_GUID;
mCallout.displayData = displayData;
mCallout.applicableLayer = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
NtStatus = FwpmCalloutAdd0(gEngineHandle, &mCallout, NULL, NULL);
if (!NT_SUCCESS(NtStatus)) {
FwpsCalloutUnregisterById0(CalloutId);
FwpmEngineClose0(gEngineHandle);
FwpsInjectionHandleDestroy0(injectionHandle);
IoDeleteDevice(deviceObject);
return NtStatus;
}
filterConditions[0].fieldKey = FWPM_CONDITION_DIRECTION;
filterConditions[0].matchType = FWP_MATCH_EQUAL;
filterConditions[0].conditionValue.type = FWP_UINT32;
filterConditions[0].conditionValue.uint32 = FWP_DIRECTION_OUTBOUND;
filter.layerKey = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
filter.displayData.name = L"WFP TEST NAME";
filter.displayData.description = L"WFP TEST DESCRIPTION";
filter.action.type = FWP_ACTION_CALLOUT_TERMINATING;
filter.action.calloutKey = WFP_TEST_GUID;
filter.filterCondition = filterConditions;
filter.subLayerKey = WFP_TEST_LAYER;
filter.weight.type = FWP_EMPTY; // auto-weight.
filter.rawContext = 0;
filter.numFilterConditions = 1;
NtStatus = FwpmFilterAdd0(gEngineHandle, &filter, NULL, NULL);
if (!NT_SUCCESS(NtStatus)) {
FwpsCalloutUnregisterById0(CalloutId);
FwpmEngineClose0(gEngineHandle);
FwpsInjectionHandleDestroy0(injectionHandle);
IoDeleteDevice(deviceObject);
return NtStatus;
}
NtStatus = FwpmTransactionCommit0(gEngineHandle);
if (!NT_SUCCESS(NtStatus)) {
FwpsCalloutUnregisterById0(CalloutId);
FwpmEngineClose0(gEngineHandle);
FwpsInjectionHandleDestroy0(injectionHandle);
IoDeleteDevice(deviceObject);
return NtStatus;
}
return NtStatus;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
没有评论:
发表评论