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