Windows驱动 WFP之四WFP代码基本流程的剖析

Windows驱动 WFP之四WFP代码基本流程的剖析

首页模拟经营Idle Port更新时间:2024-06-28

总说程序员是孤独的,因为,大部分的时间都在和机器打交道。大部分的时间都在自言自语。我的内心需要足够的强大。这种强大时建立的自信的基础上的。而自信又是建立在实力基础上的。实力又是建立在积累的基础上。积累又是建立在时间的基础上。所以归根结底,就是,需要花费更多的时间。第二,需要有足够的兴趣爱好。这两点对于现在的我来说,都有。既然,自己选择了这条路,就应该义无反顾的走下去,坚持的走下去。孤独,我不怕,困难,我也不怕,永远向上的动力,爱好,对知识的渴望,支持者我。相信自己,相信明天。

今天实际看一下,WFP的Callout驱动的代码。先从DriverEntry开始:

1,在DriverEntry需要创建驱动对象和设备对象,

1.1 由于不是PNP设备,需要设置创建驱动对象的标志为config.DriverInitFlags |= WdfDriverInitNonPnpDriver.

1.2 调用WdfDriverCreate创建驱动对象。

1.3 调用WdfControlDeviceInitAllocate通过驱动对象创建 WDFDEVICE_INIT结构体。

1.4 调用WdfDeviceInitSetDeviceType设置设备类型为FILE_DEVICE_NETWORK.

1.5 调用WdfDeviceInitSetCharacteristics设置设备的特性为FILE_DEVICE_SECURE_OPEN和FILE_AUTOGENERATED_DEVICE_NAME.

1.6 调用WdfDeviceCreate创建设备对象。

1.7 调用WdfControlFinishInitializing设置设备的初始化状态为完成。

1.8 调用FwpsInjectionHandleCreate创建一个检测的句柄。并设置在哪里完成检查。通过在转发层,网络层,流层,传输层。

1.9 调用WdfDeviceWdmGetDeviceObject将框架设备对象转换为设备对象的指针。

1.10 调用FwpmEngineOpen打开一个和过滤引擎的会话,这个函数会返回一个过滤引擎的句柄。

1.11 调用FwpmTransactionBegin在当前的会话下,开始一个明确的传输。

1.12 调用FwpmSubLayerAdd函数玩系统中增加一个子层。

DWORD WINAPI FwpmSubLayerAdd0(

_In_ HANDLE engineHandle,

_In_ const FWPM_SUBLAYER0 *subLayer,

_In_opt_ PSECURITY_DESCRIPTOR sd

);

这里我们主要来看第二个参数,FWPM_SUBLAYER0这个结构体。

typedef struct FWPM_SUBLAYER0_ {

GUID subLayerKey;

FWPM_DISPLAY_DATA0 displayData;

UINT16 flags;

GUID *providerKey;

FWP_BYTE_BLOB providerData;

UINT16 weight;

} FWPM_SUBLAYER0;

这里,我们主要看第一个GUID,后面的需要在例子后分析。这个可以定义的GUID.

DEFINE_GUID(

DD_PROXY_SUBLAYER,

0x0104fd7e,

0xc825,

0x414e,

0x94, 0xc9, 0xf0, 0xd5, 0x25, 0xbb, 0xc1, 0x69

);

DDProxySubLayer.subLayerKey = DD_PROXY_SUBLAYER;

DDProxySubLayer.displayData.name = L"Datagram-Data Proxy Sub-Layer";

DDProxySubLayer.displayData.description =

L"Sub-Layer for use by Datagram-Data Proxy callouts";

DDProxySubLayer.flags = 0;

DDProxySubLayer.weight = FWP_EMPTY; // auto-weight.;

1.13 调用FwpsCalloutRegister注册一个callout:

NTSTATUS NTAPI FwpsCalloutRegister0(

_Inout_ void *deviceObject,

_In_ const FWPS_CALLOUT0 *callout,

_Out_opt_ UINT32 *calloutId

);

这里主要是第二个参数的设置:

typedef struct FWPS_CALLOUT0_ {

GUID calloutKey;

UINT32 flags;

FWPS_CALLOUT_CLASSIFY_FN0 classifyFn;

FWPS_CALLOUT_NOTIFY_FN0 notifyFn;

FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN0 flowDeleteFn;

} FWPS_CALLOUT0;

这里的calloutKey是一个GUID值,我们可以定义。classifyFn为驱动分类的函数入口。notifyFn为通知消息的函数入口。flowDeleteFn为流程删除的函数入口。

1.14 调用FwpmCalloutAdd,向过滤引擎增加一个callout.

NTSTATUS NTAPI FwpmCalloutAdd0(

_In_ HANDLE engineHandle,

_In_ const FWPM_CALLOUT0 *callout,

_In_opt_ PSECURITY_DESCRIPTOR sd,

_Out_opt_ UINT32 *id

);

这里还是看第二个参数,FWPM_CALLOUT0.

typedef struct FWPM_CALLOUT0_ {

GUID calloutKey;

FWPM_DISPLAY_DATA0 displayData;

UINT32 flags;

GUID *providerKey;

FWP_BYTE_BLOB providerData;

GUID applicableLayer;

UINT32 calloutId;

} FWPM_CALLOUT0;

所以我们看到,这里我们有两个CALLOUT了,一个是FWPS_CALLOUT0,一个是FWPM_CALLOUT0,FWPS_CALLOUT0是给驱动用的,所以这里将其CALLOUT跟设备对象进行关联,但是后面还有个FWPM_CALLOUT0,这个就是跟过滤引擎进行交互的。再看其实这两个CALLOUT的GUID值是一样的,所以这样就进行了关联。两个CALLOUT相互关联,又相互独立,FWPM_CALLOUT0,负责和过滤引擎相关的操作。FWPS_CALLOUT0负责和驱动相关本身的操作。

这样,从驱动本身的驱动对象,设备对象和过滤引擎中的过滤层和CALLOUT进行联系上了。

1.15 调用FwpmFilterAdd增加一个过滤对象到系统中。

DWORD WINAPI FwpmFilterAdd0(

_In_ HANDLE engineHandle,

_In_ const FWPM_FILTER0 *filter,

_In_opt_ SECURITY_DESCRIPTOR sd,

_Out_opt_ UINT64 *id

);

这里还是第二个参数,const FWPM_FILTER0 *filter,非常复杂的结构,这个是精髓,必须好好看。

typedef struct FWPM_FILTER0_ {

GUID filterKey;

FWPM_DISPLAY_DATA0 displayData;

UINT32 flags;

GUID *providerKey;

FWP_BYTE_BLOB providerData;

GUID layerKey;

GUID subLayerKey;

FWP_VALUE0 weight;

UINT32 numFilterConditions;

FWPM_FILTER_CONDITION0 *filterCondition;

FWPM_ACTION0 action;

union {

UINT64 rawContext;

GUID providerContextKey;

};

GUID *reserved;

UINT64 filterId;

FWP_VALUE0 effectiveWeight;

} FWPM_FILTER0;

我们先把,结构体中包含的结构,进行展开。

typedef struct FWPM_DISPLAY_DATA0_ {

wchar_t *name;

wchar_t *description;

} FWPM_DISPLAY_DATA0;

typedef struct FWP_BYTE_BLOB_ {

UINT32 size;

UINT8 *data;

} FWP_BYTE_BLOB;

关于providerKey代表的是WFP内部定义的一些GUID.

typedef struct FWP_VALUE0_ {

FWP_DATA_TYPE type;

union {

; // case(FWP_EMPTY)

UINT8 uint8;

UINT16 uint16;

UINT32 uint32;

UINT64 *uint64;

INT8 int8;

INT16 int16;

INT32 int32;

INT64 *int64;

float float32;

double *double64;

FWP_BYTE_ARRAY16 *byteArray16;

FWP_BYTE_BLOB *byteBlob;

SID *sid;

FWP_BYTE_BLOB *sd;

FWP_TOKEN_INFORMATION *tokenInformation;

FWP_BYTE_BLOB *tokenAccessInformation;

LPWSTR unicodeString;

FWP_BYTE_ARRAY6 *byteArray6;

};

} FWP_VALUE0;

这里,我的理解是,这个值代表代表一个过滤的一个比重,这个跟你在哪一层过滤都有关系。

下面看一下,最最重要的一个结构体,过滤的条件。当这所有的条件的满足的情况下,定义的过滤动作才开始。

typedef struct FWPM_FILTER_CONDITION0_ {

GUID fieldKey;

FWP_MATCH_TYPE matchType;

FWP_CONDITION_VALUE conditionValue;

} FWPM_FILTER_CONDITION0;

通常这个fieldKey域,微软有明确的定义。在每一个过滤层次上,都有不一样的过滤条件。可以看http://msdn.microsoft.com/en-us/library/windows/hardware/ff549944(v=vs.85).aspx

typedef enum FWP_MATCH_TYPE_ {

FWP_MATCH_EQUAL,

FWP_MATCH_GREATER,

FWP_MATCH_LESS,

FWP_MATCH_GREATER_OR_EQUAL,

FWP_MATCH_LESS_OR_EQUAL,

FWP_MATCH_RANGE,

FWP_MATCH_FLAGS_ALL_SET,

FWP_MATCH_FLAGS_ANY_SET,

FWP_MATCH_FLAGS_NONE_SET,

FWP_MATCH_EQUAL_CASE_INSENSITIVE,

FWP_MATCH_NOT_EQUAL,

FWP_MATCH_TYPE_MAX

} FWP_MATCH_TYPE;

typedef struct FWP_CONDITION_VALUE0_ {

FWP_DATA_TYPE type;

union {

UINT8 uint8;

UINT16 uint16;

UINT32 uint32;

UINT64 *uint64;

INT8 int8;

INT16 int16;

INT32 int32;

INT64 *int64;

float float32;

double *double64;

FWP_BYTE_ARRAY16 *byteArray16;

FWP_BYTE_BLOB *byteBlob;

SID *sid;

FWP_BYTE_BLOB *sd;

FWP_TOKEN_INFORMATION *tokenInformation;

FWP_BYTE_BLOB *tokenAccessInformation;

LPWSTR unicodeString;

FWP_BYTE_ARRAY6 *byteArray6;

FWP_V4_ADDR_AND_MASK *v4AddrMask;

FWP_V6_ADDR_AND_MASK *v6AddrMask;

FWP_RANGE0 *rangeValue;

};

} FWP_CONDITION_VALUE0;

这个可能要多看下MSDN中的设置,因为跟微软玩,必须都符合它的要求。

下面再看下,过滤动作的这个结构体。

typedef struct FWPM_ACTION0_ {

FWP_ACTION_TYPE type;

union {

GUID filterType;

GUID calloutKey;

};

} FWPM_ACTION0;

这里要提一下的就是这个calloutKey,这个值正好跟之前calloutKey相吻合,主要我们向设备对象注册的callout,向过滤引擎注册的callout,以及和过滤的callout都指向同一个GUID值。

下面就是我们来看具体的CALLOUT函数的执行了,当满足这些条件后,CALLOUT被过滤引擎调用。

我们具体来看一下这个具体的CALLOUT函数:

void NTAPI classifyFn0(

_In_ const FWPS_INCOMING_VALUES0 *inFixedValues,

_In_ const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,

_Inout_ void *layerData,

_In_ const FWPS_FILTER0 *filter,

_In_ UINT64 flowContext,

_Out_ FWPS_CLASSIFY_OUT0 *classifyOut

)

typedef struct FWPS_INCOMING_VALUES0_ {

UINT16 layerId;

UINT32 valueCount;

FWPS_INCOMING_VALUE0 *incomingValue;

} FWPS_INCOMING_VALUES0;

这个layerId就是指的是过滤层的实时标识ID.可以参考微软的http://msdn.microsoft.com/en-us/library/windows/hardware/ff570731(v=vs.85).aspx

具体的数据域。

typedef struct FWPS_INCOMING_VALUE0_ {

FWP_VALUE0 value;

} FWPS_INCOMING_VALUE0;

这个值一看就知道,就是代表那些固定的值。比如一些IP地址,PORT等等。

再看:

typedef struct FWPS_INCOMING_METADATA_VALUES0_ {

UINT32 currentMetadataValues;

UINT32 flags;

UINT64 reserved;

FWPS_DISCARD_METADATA0 discardMetadata;

UINT64 flowHandle;

UINT32 ipHeaderSize;

UINT32 transportHeaderSize;

FWP_BYTE_BLOB *processPath;

UINT64 token;

UINT64 processId;

UINT32 sourceInterfaceIndex;

UINT32 destinationInterfaceIndex;

ULONG compartmentId;

FWPS_INBOUND_FRAGMENT_METADATA0 fragmentMetadata;

ULONG pathMtu;

HANDLE completionHandle;

UINT64 transportEndpointHandle;

SCOPE_ID remoteScopeId;

WSACMSGHDR *controlData;

ULONG controlDataLength;

FWP_DIRECTION packetDirection;

#if (NTDDI_VERSION >= NTDDI_WIN6SP1)

PVOID headerIncludeHeader;

ULONG headerIncludeHeaderLength;

#if (NTDDI_VERSION >= NTDDI_WIN7)

IP_ADDRESS_PREFIX destinationPrefix;

UINT16 frameLength;

UINT64 parentEndpointHandle;

UINT32 icmpIdAndSequence;

DWORD localRedirectTargetPID;

SOCKADDR *originalDestination;

#if (NTDDI_VERSION >= NTDDI_WIN8)

HANDLE redirectRecords;

UINT32 currentL2MetadataValues;

UINT32 l2Flags;

UINT32 ethernetMacHeaderSize;

UINT32 wiFiOperationMode;

#if (NDIS_SUPPORT_NDIS630)

NDIS_SWITCH_PORT_ID vSwitchSourcePortId;

NDIS_SWITCH_NIC_INDEX vSwitchSourceNicIndex;

NDIS_SWITCH_PORT_ID vSwitchDestinationPortId;

#else

UINT32 padding0;

USHORT padding1;

UINT32 padding2;

#endif

HANDLE vSwitchPacketContext;

UINT32 l2ConnectionProfileIndex;

#endif

#endif

#endif

#if (NTDDI_VERSION >= NTDDI_WIN8)

PVOID subProcessTag;

UINT64 Reserved1;

#endif

} FWPS_INCOMING_METADATA_VALUES0;

这个数据就是包含需要过滤的一些元数据的值。

我们再来看void *layerData,这个值,可能为NULL,取决于过滤条件和过滤层。

在Stream层,这个参数指向 FWPS_STREAM_CALLOUT_IO_PACKET0 结构,对于其他的层,这个参数指向NET_BUFFER_LIST,或者为NULL.

FWPS_FILTER0 *filter

这个结构体,我们之前有看过:

typedef struct FWPS_FILTER0_ {

UINT64 filterId;

FWP_VALUE0 weight;

UINT16 subLayerWeight;

UINT16 flags;

UINT32 numFilterConditions;

FWPS_FILTER_CONDITION0 *filterCondition;

FWPS_ACTION0 action;

UINT64 context;

FWPM_PROVIDER_CONTEXT0 *providerContext;

} FWPS_FILTER0;

UINT64 flowContext,这个参数是和过滤数据相关联的上下文结构。

再来看,FWPS_CLASSIFY_OUT0 *classifyOut,这个结构体比较重要:

这个是返回给调用者的结构体。

struct FWPS_CLASSIFY_OUT0 {

FWP_ACTION_TYPE actionType;

UINT64 outContext;

UINT64 filterId;

UINT32 rights;

UINT32 flags;

UINT32 reserved;

};

可以参考http://msdn.microsoft.com/en-us/library/windows/hardware/ff551229(v=vs.85).aspx

我们再从前面看,在DriverEntry最后面,我们有起一个线程来进行对包的数据的检查,看是否需要修改,以及重新注入后发送。这个也必须根据其过滤条件有关。

我们看一个复杂的callout的ClassifyFn函数的具体实现。

void

DDProxyClassify(

_In_ const FWPS_INCOMING_VALUES* inFixedValues,

_In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,

_Inout_opt_ void* layerData,

_In_ const FWPS_FILTER* filter,

_In_ UINT64 flowContext,

_Inout_ FWPS_CLASSIFY_OUT* classifyOut

)

#endif /// (NTDDI_VERSION >= NTDDI_WIN7)

/*

This is the classifyFn function of the datagram-data callout. It

allocates a packet structure to store the classify and meta data and

it references the net buffer list for out-of-band modification and

re-injection. The packet structure will be queued to the global packet

queue. The worker thread will then be signaled, if idle, to process

the queue.

-- */

{

DD_PROXY_PENDED_PACKET* packet = NULL;

DD_PROXY_FLOW_CONTEXT* flowContextLocal = (DD_PROXY_FLOW_CONTEXT*)(DWORD_PTR)flowContext;

FWPS_PACKET_INJECTION_STATE packetState;

KLOCK_QUEUE_HANDLE packetQueueLockHandle;

BOOLEAN signalWorkerThread;

#if(NTDDI_VERSION >= NTDDI_WIN7)

UNREFERENCED_PARAMETER(classifyContext);

#endif

UNREFERENCED_PARAMETER(filter);

_Analysis_assume_(layerData != NULL);

//

// We don't have the necessary right to alter the packet.

// 首先检查,我们是否有权利去修改这个包。

if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)

{

goto Exit;

}

//

// We don't re-inspect packets that we've inspected earlier.

//

packetState = FwpsQueryPacketInjectionState(

gInjectionHandle,

layerData,

NULL

);

//如果这个包注入的状态是,之前已经被这个注入句柄注入过,就不用再处理了。

if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||

(packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))

{

classifyOut->actionType = FWP_ACTION_PERMIT;

if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)

{

classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;

}

goto Exit;

}

//分配一个和过滤条件相匹配的空间。

packet = ExAllocatePoolWithTag(

NonPagedPool,

sizeof(DD_PROXY_PENDED_PACKET),

DD_PROXY_PENDED_PACKET_POOL_TAG

);

//分配失败,直接退出,等待下一次处理。

if (packet == NULL)

{

classifyOut->actionType = FWP_ACTION_BLOCK;

classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;

goto Exit;

}

RtlZeroMemory(packet, sizeof(DD_PROXY_PENDED_PACKET));

NT_ASSERT(flowContextLocal != NULL);

packet->belongingFlow = flowContextLocal;

DDProxyReferenceFlowContext(packet->belongingFlow);

//AF_INET代表的是TCP或UDP,通过固定数据中的数据与来传输方向。

if (flowContextLocal->addressFamily == AF_INET)

{

NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4);

packet->direction =

inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].\

value.uint32;

}

else

{

NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6);

packet->direction =

inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_DIRECTION].\

value.uint32;

}

//将NET_BUFFER_LIST结构体的指针赋给packer->netBufferList.

packet->netBufferList = layerData;

//

// Reference the net buffer list to make it accessible outside of

// classifyFn.

//

//引用NET_BUFFER_LIST.

FwpsReferenceNetBufferList(packet->netBufferList, TRUE);

NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,

FWPS_METADATA_FIELD_COMPARTMENT_ID));

packet->compartmentId = inMetaValues->compartmentId;

if (packet->direction == FWP_DIRECTION_OUTBOUND)

{

NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(

inMetaValues,

FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE));

packet->endpointHandle = inMetaValues->transportEndpointHandle;

if (flowContextLocal->addressFamily == AF_INET)

{

// See PREfast comments above. Opaque pointer tricks PREfast.

#pragma prefast ( suppress: 28193, "We are NOT ignoring this return value" )

packet->ipv4RemoteAddr =

RtlUlongByteSwap( /* host-order -> network-order conversion */

inFixedValues->incomingValue\

[FWPS_FIELD_DATAGRAM_DATA_V4_IP_REMOTE_ADDRESS].value.uint32);

}

else

{

RtlCopyMemory(

(UINT8*)&packet->remoteAddr,

inFixedValues->incomingValue\

[FWPS_FIELD_DATAGRAM_DATA_V6_IP_REMOTE_ADDRESS].value.byteArray16,

sizeof(FWP_BYTE_ARRAY16)

);

}

packet->remoteScopeId = inMetaValues->remoteScopeId;

if (FWPS_IS_METADATA_FIELD_PRESENT(

inMetaValues,

FWPS_METADATA_FIELD_TRANSPORT_CONTROL_DATA))

{

NT_ASSERT(inMetaValues->controlDataLength > 0);

packet->controlData = ExAllocatePoolWithTag(

NonPagedPool,

inMetaValues->controlDataLength,

DD_PROXY_CONTROL_DATA_POOL_TAG

);

if (packet->controlData == NULL)

{

classifyOut->actionType = FWP_ACTION_BLOCK;

classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;

goto Exit;

}

RtlCopyMemory(

packet->controlData,

inMetaValues->controlData,

inMetaValues->controlDataLength

);

packet->controlDataLength = inMetaValues->controlDataLength;

}

}

else

{

NT_ASSERT(packet->direction == FWP_DIRECTION_INBOUND);

if (flowContextLocal->addressFamily == AF_INET)

{

NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4);

packet->interfaceIndex =

inFixedValues->incomingValue\

[FWPS_FIELD_DATAGRAM_DATA_V4_INTERFACE_INDEX].value.uint32;

packet->subInterfaceIndex =

inFixedValues->incomingValue\

[FWPS_FIELD_DATAGRAM_DATA_V4_SUB_INTERFACE_INDEX].value.uint32;

}

else

{

NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6);

packet->interfaceIndex =

inFixedValues->incomingValue\

[FWPS_FIELD_DATAGRAM_DATA_V6_INTERFACE_INDEX].value.uint32;

packet->subInterfaceIndex =

inFixedValues->incomingValue\

[FWPS_FIELD_DATAGRAM_DATA_V6_SUB_INTERFACE_INDEX].value.uint32;

}

NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(

inMetaValues,

FWPS_METADATA_FIELD_IP_HEADER_SIZE));

NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(

inMetaValues,

FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE));

packet->ipHeaderSize = inMetaValues->ipHeaderSize;

packet->transportHeaderSize = inMetaValues->transportHeaderSize;

packet->nblOffset =

NET_BUFFER_DATA_OFFSET(NET_BUFFER_LIST_FIRST_NB(packet->netBufferList));

}

KeAcquireInStackQueuedSpinLock(

&gPacketQueueLock,

&packetQueueLockHandle

);

if (!gDriverUnloading)

{

signalWorkerThread = IsListEmpty(&gPacketQueue);

InsertTailList(&gPacketQueue, &packet->listEntry);

packet = NULL; // ownership transferred

classifyOut->actionType = FWP_ACTION_BLOCK;

classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;

classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;

}

else

{

//

// Driver is being unloaded, permit any incoming packets.

//

signalWorkerThread = FALSE;

classifyOut->actionType = FWP_ACTION_PERMIT;

if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)

{

classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;

}

}

if (signalWorkerThread)

{

KeSetEvent(

&gPacketQueueEvent,

0,

FALSE

);

}

KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);

Exit:

if (packet != NULL)

{

DDProxyFreePendedPacket(packet, packet->controlData);

}

return;

}

这里是放在函数外注入修改,这里是通过线程来处理的,我们先看重新注入函数。

NTSTATUS

DDProxyCloneModifyReinjectInbound(

_In_ DD_PROXY_PENDED_PACKET* packet

)

/*

This function clones the inbound net buffer list and, if needed,

modifies the source port and/or source address and receive-injects

the clone back to the tcpip stack.

-- */

{

NTSTATUS status = STATUS_SUCCESS;

NET_BUFFER_LIST* clonedNetBufferList = NULL;

NET_BUFFER* netBuffer;

UDP_HEADER* udpHeader;

ULONG nblOffset;

NDIS_STATUS ndisStatus;

//

// For inbound net buffer list, we can assume it contains only one

// net buffer.

//

netBuffer = NET_BUFFER_LIST_FIRST_NB(packet->netBufferList);

nblOffset = NET_BUFFER_DATA_OFFSET(netBuffer);

//

// The TCP/IP stack could have retreated the net buffer list by the

// transportHeaderSize amount; detect the condition here to avoid

// retreating twice.

//

if (nblOffset != packet->nblOffset)

{

NT_ASSERT(packet->nblOffset - nblOffset == packet->transportHeaderSize);

packet->transportHeaderSize = 0;

}

//

// Adjust the net buffer list offset to the start of the IP header.

//

ndisStatus = NdisRetreatNetBufferDataStart(

netBuffer,

packet->ipHeaderSize packet->transportHeaderSize,

0,

NULL

);

_Analysis_assume_(ndisStatus == NDIS_STATUS_SUCCESS);

//

// Note that the clone will inherit the original net buffer list's offset.

//

status = FwpsAllocateCloneNetBufferList(

packet->netBufferList,

NULL,

NULL,

0,

&clonedNetBufferList

);

//

// Undo the adjustment on the original net buffer list.

//

NdisAdvanceNetBufferDataStart(

netBuffer,

packet->ipHeaderSize packet->transportHeaderSize,

FALSE,

NULL

);

if (!NT_SUCCESS(status))

{

goto Exit;

}

//

// Check to see if port modification is required.

//

if ((packet->belongingFlow->protocol == IPPROTO_UDP) &&

(packet->belongingFlow->toRemotePort != 0))

{

netBuffer = NET_BUFFER_LIST_FIRST_NB(clonedNetBufferList);

//

// Advance to the beginning of the transport header (i.e. UDP header).

//

NdisAdvanceNetBufferDataStart(

netBuffer,

packet->ipHeaderSize,

FALSE,

NULL

);

udpHeader = NdisGetDataBuffer(

netBuffer,

sizeof(UDP_HEADER),

NULL,

sizeof(UINT16),

0

);

NT_ASSERT(udpHeader != NULL); // We can assume UDP header in a net buffer

// is contiguous and 2-byte aligned.

_Analysis_assume_(udpHeader != NULL);

udpHeader->destPort =

packet->belongingFlow->toRemotePort;

// This is our new source port -- or

// the destination port of the original

// outbound traffic.

udpHeader->checksum = 0;

//

// Undo the advance. Net buffer list needs to be positioned at the

// beginning of IP header for address modification and/or receive-

// injection.

//

ndisStatus = NdisRetreatNetBufferDataStart(

netBuffer,

packet->ipHeaderSize,

0,

NULL

);

_Analysis_assume_(ndisStatus == NDIS_STATUS_SUCCESS);

}

if (packet->belongingFlow->toRemoteAddr != NULL)

{

status = FwpsConstructIpHeaderForTransportPacket(

clonedNetBufferList,

packet->ipHeaderSize,

packet->belongingFlow->addressFamily,

packet->belongingFlow->toRemoteAddr,

// This is our new source address --

// or the destination address of the

// original outbound traffic.

(UINT8*)&packet->belongingFlow->localAddr,

// This is the destination address of

// the clone -- or the source of the

// original outbound traffic.

packet->belongingFlow->protocol,

0,

NULL,

0,

0,

NULL,

0,

0

);

if (!NT_SUCCESS(status))

{

goto Exit;

}

}

status = FwpsInjectTransportReceiveAsync(

gInjectionHandle,

NULL,

NULL,

0,

packet->belongingFlow->addressFamily,

packet->compartmentId,

packet->interfaceIndex,

packet->subInterfaceIndex,

clonedNetBufferList,

DDProxyInjectComplete,

packet

);

if (!NT_SUCCESS(status))

{

goto Exit;

}

clonedNetBufferList = NULL; // ownership transferred to the

// completion function.

Exit:

if (clonedNetBufferList != NULL)

{

FwpsFreeCloneNetBufferList(clonedNetBufferList, 0);

}

return status;

}

写在最后,关于WFP,自己只是懂了点皮毛,这个需要非常好的网络相关的知识,而且需要对

微软的NDIS非常熟悉,虽然自己差不多将NDIS看了许多,但是还不够熟练。

而且,关于WFP中,微软定义了非常多了不好理解的数据结构和一些过滤层,

这应该是一个大工程,需要自己经常,反复揣摩。

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved