WFP驱动监控网络

WFP 是微软推出来替代 TDI HOOK、NDIS HOOK 等拦截网络通信的方案,WFP 的框架非常庞大,在 RING3 和 RING0 各有一套类似的函数,令人兴奋的是,即使在 R3 使用 WFP,也可以做到全局拦截访问网络。由于 WFP 的范围太广,实在难以一言概括,感兴趣的朋友可以自行到 MSDN 上查看微软对它的官方概述。本文的目的,是给大家理顺 WFP 的框架,并利用 WFP 拦截指定进程访问网络,或拦截对指定 IP 地址/端口的访问。

一个标准的 WFP 程序大体是这样子的: 首先使用 FwpmEngineOpen  开启 WFP  引擎 (获得个 一个 WFP  的 使用 句柄) )用 ,然后用 FwpmTransactionBegin  设置 对网络通信 内容 的 过滤 权限(是只读) 还是允许修改) , 然后用 FwpsCalloutRegister 、FwpmCalloutAdd 、FwpmFilterAdd  选择你 要过滤的内容, 并 添加 过滤器对象 和 回调函数, 最后用 用 FwpmTransactionCommit  确认刚才的内容, 让 刚才添加的 回调函数 开始生效 。 当用 你不用 WFP  的 时候, 就要用FwpmFilterDeleteById 、FwpmCalloutDeleteById 、FwpsCalloutUnregisterById  把你刚才添加的过滤器对象和回调函数删除掉,然后用 用 FwpmEngineClose  关闭 WFP 擎 引擎 ( 类似于 关闭句柄) )。

一个概述已经是这样子了,实现起来就更加麻烦了。为了方便大家学习,作者(胡文亮)已经把微软的 WFP 实例进行了最大简化,并把核心的注册回调功能封装成了一个函数。下面一步一步进行分析。在具体分析之前,有一些重要的内容需要先说明,否则后面的内容肯定会让大家一头雾水。一、WFP  一次性 要 注册的回调函数 不是 1  个 ,而是 3  个 。 但只有 1  个 是 “ 事前 ”回调, 另外 2  个 都是 “ 事后 ” 回调 (一般 只 使用“ 事前 ” 回调 ,不使用“ 事后 ”回调) )。二、WFP  能过滤 的内容很多,你必须选择一个 感兴趣的内容。 这个“ 感 兴趣 的 内容” 用官话来说叫做 “过滤 条件标志 ”, 这货 其实 是一个 常量 , 由于我们是 要过滤进程联网, 而且 一般都是用 IPV4  协议,所以 “过滤 条件标志 ”为 为 FWPM_LAYER_ALE_AUTH_CONNECT_V4 ( 在 这个

页面 可以的 查到所有的 “过滤 条件标志” ”) )。三、 你个 必须为这个 “过滤 条件标志 ”指定一个 GUID ,当然 GUID  的 值 随便设置 就行 ,只要 在 系统范围内不重复。 。 代码中的 GUID  就是 随意设定的,它的名称为:GUID_ALE_AUTH_CONNECT_CALLOUT_V4。

我用的VS2015+wdk10开发的,VS15里面需要设置这些东西:

添加库:ntoskrnl.lib ndis.lib fwpkclnt.lib uuid.lib

添加宏定义:NDIS_SUPPORT_NDIS6

注册的代码:

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,
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.calloutKey = *calloutKey;
sCallout.classifyFn = classifyFn;
sCallout.flowDeleteFn = flowDeleteNotifyFn;
sCallout.notifyFn = notifyFn;
//要使用哪个设备对象注册
status = FwpsCalloutRegister( gDevObj,&sCallout,calloutId );
if( !NT_SUCCESS(status))
goto exit;
bCalloutRegistered = TRUE;
mDispData.name = L"WFP TEST";
mDispData.description = L"TESLA.ANGELA's WFP TEST";
//你感兴趣的内容
mCallout.applicableLayer = *layerKey;
//你感兴趣的内容的GUID
mCallout.calloutKey = *calloutKey;
mCallout.displayData = mDispData;
//添加回调函数
status = FwpmCalloutAdd( gEngineHandle,&mCallout,NULL,NULL);
if( !NT_SUCCESS(status))
goto exit;
mFilter.action.calloutKey = *calloutKey;
//在callout里决定
mFilter.action.type = FWP_ACTION_CALLOUT_TERMINATING;
mFilter.displayData.name = L"WFP TEST";
mFilter.displayData.description = L"TESLA.ANGELA's WFP TEST";
mFilter.layerKey = *layerKey;
mFilter.numFilterConditions = 0;
mFilter.filterCondition = mFilter_condition;
mFilter.subLayerKey = FWPM_SUBLAYER_UNIVERSAL;
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,
&GUID_ALE_AUTH_CONNECT_CALLOUT_V4,
WallALEConnectClassify,
WallNotifyFn,
WallFlowDeleteFn,
&gAleConnectCalloutId,
&gAleConnectFilterId);
if( !NT_SUCCESS(status))
{
DbgPrint("RegisterCalloutForLayer-FWPM_LAYER_ALE_AUTH_CONNECT_V4 failed!\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;
}

三个回调函数以及其他:

#include <ntddk.h>
#pragma warning(push)
#pragma warning(disable:4201) // unnamed struct/union
#pragma warning(disable:4995)
#include <ndis.h>
#include <fwpsk.h>
#pragma warning(pop)
#include <fwpmk.h>
#include <limits.h>
#include <ws2ipdef.h>
#include <in6addr.h>
#include <ip2string.h>
#include <strsafe.h>
#include <wdm.h> #define INITGUID
#include <guiddef.h>
#define bool BOOLEAN
#define true TRUE
#define false FALSE
#define DEVICE_NAME L"\\Device\\MyDriver"
#define DEVICE_DOSNAME L"\\DosDevices\\MyDriver"
#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
)
{
return STATUS_SUCCESS;
} VOID NTAPI WallFlowDeleteFn
(
IN UINT16 layerId,
IN UINT32 calloutId,
IN UINT64 flowContext
)
{
return;
} //协议代码转为名称
char* ProtocolIdToName(UINT16 id)
{
char *ProtocolName=kmalloc(16);
switch(id) //http://www.ietf.org/rfc/rfc1700.txt
{
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;
} //最重要的过滤函数
//http://msdn.microsoft.com/en-us/library/windows/hardware/ff551238(v=vs.85).aspx
void NTAPI WallALEConnectClassify
(
IN const FWPS_INCOMING_VALUES0* inFixedValues,
IN const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,
IN OUT void* layerData,
IN const void* classifyContext,
IN const FWPS_FILTER* filter,
IN UINT64 flowContext,
OUT FWPS_CLASSIFY_OUT* classifyOut
)
{
char *ProtocolName=NULL;
DWORD LocalIp,RemoteIP;
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("[WFP]IRQL=%d;PID=%ld;Path=%S;Local=%u.%u.%u.%u:%d;Remote=%u.%u.%u.%u:%d;Protocol=%s\n",
(USHORT)KeGetCurrentIrql(),
(DWORD)(inMetaValues->processId),
(PWCHAR)inMetaValues->processPath->data, //NULL,//
(LocalIp>>24)&0xFF,(LocalIp>>16)&0xFF,(LocalIp>>8)&0xFF,LocalIp&0xFF,
inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT].value.uint16,
(RemoteIP>>24)&0xFF,(RemoteIP>>16)&0xFF,(RemoteIP>>8)&0xFF,RemoteIP&0xFF,
inFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT].value.uint16,
ProtocolName);
kfree(ProtocolName);
classifyOut->actionType = FWP_ACTION_PERMIT;//允许连接 //禁止IE联网(设置“行动类型”为FWP_ACTION_BLOCK)
// if(wcsstr((PWCHAR)inMetaValues->processPath->data,L"iexplore.exe"))
// {
// classifyOut->actionType = FWP_ACTION_BLOCK;
// classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
// classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
// }
return;
}

执行结果,进行网络监控,并且禁止ie访问网络:

刚刚看有一个哥们写的也不错,留在这方便以后用的时候一起查看:

http://blog.csdn.net/rodney443220/article/details/37653793

还有一点要注意。回调函数执行的时候IRQL不一定是0,还可能是2,看上面图片输出。

Win64 驱动内核编程-16.WFP网络监控驱动(防火墙)的更多相关文章

  1. Win64 驱动内核编程-3.内核里使用内存

    内核里使用内存 内存使用,无非就是申请.复制.设置.释放.在 C 语言里,它们对应的函数是:malloc.memcpy.memset.free:在内核编程里,他们分别对应 ExAllocatePool ...

  2. Win64 驱动内核编程-8.内核里的其他常用

    内核里的其他常用 1.遍历链表.内核里有很多数据结构,但它们并不是孤立的,内核使用双向链表把它们像糖 葫芦一样给串了起来.所以遍历双向链表能获得很多重要的内核数据.举个简单的例子,驱 动对象 Driv ...

  3. Win64 驱动内核编程-7.内核里操作进程

    在内核里操作进程 在内核里操作进程,相信是很多对 WINDOWS 内核编程感兴趣的朋友第一个学习的知识点.但在这里,我要让大家失望了,在内核里操作进程没什么特别的,就标准方法而言,还是调用那几个和进程 ...

  4. Win64 驱动内核编程-18.SSDT

    SSDT 学习资料:http://blog.csdn.net/zfdyq0/article/details/26515019 学习资料:WIN64内核编程基础 胡文亮 SSDT(系统服务描述表),刚开 ...

  5. Win64 驱动内核编程-13.回调监控模块加载

    回调监控模块加载 模块加载包括用户层模块(.DLL)和内核模块(.SYS)的加载.传统方法要监控这两者加在必须 HOOK 好几个函数,比如 NtCreateSection 和 NtLoadDriver ...

  6. Win64 驱动内核编程-11.回调监控进线程句柄操作

    无HOOK监控进线程句柄操作 在 NT5 平台下,要监控进线程句柄的操作. 通常要挂钩三个API:NtOpenProcess.NtOpenThread.NtDuplicateObject.但是在 VI ...

  7. Win64 驱动内核编程-14.回调监控文件

    回调监控文件 使用 ObRegisterCallbacks 实现保护进程,其实稍微 PATCH 下内核,这个函数还能实现文件操作监视.但可惜只能在 WIN7X64 上用.因为在 WIN7X64 上 P ...

  8. Win64 驱动内核编程-15.回调监控注册表

    回调监控注册表 在 WIN32 平台上,监控注册表的手段通常是 SSDT HOOK.不过用 SSDT HOOK 的方式监控注册表实在是太麻烦了,要 HOOK 一大堆函数,还要处理一些 NT6 系统有而 ...

  9. Win64 驱动内核编程-12.回调监控进线程创建和退出

    回调监控进线程创建和退出 两个注册回调的函数:PsSetCreateProcessNotifyRoutine   进程回调PsSetCreateThreadNotifyRoutine    线程回调分 ...

随机推荐

  1. PTA甲级—常用技巧与算法

    散列 1078 Hashing (25 分) Quadratic probing (with positive increments only) is used to solve the collis ...

  2. 初窥MyBatis-普通的CRUD操作

    编写接口 编写对应的Mapper.xml中的sql语句 测试(增删改需要提交事务) <mapper namespace="com.perwrj.dao.UserMapper" ...

  3. MarkFormat,一个在Word中使用Mark进行格式化的插件

    MarkFormat(标记格式化),是一款在Word中基于标记进行格式化的工具. 让我们看下具体效果. 首先是有标记的文本 点击格式化之后 点击去除标记之后(去除标记也会进行格式化) 如果想要恢复标记 ...

  4. Sass/Scss 基础篇

    Sass/Scss 基础篇 总结Sass学习到的内容 应用Sass/Scss前,环境配置 首先下载Ruby (http://rubyinstaller.org/downloads) 通过命令下载sas ...

  5. 痞子衡嵌入式:盘点国内Cortex-M内核MCU厂商高性能产品

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是国内Cortex-M内核MCU厂商高性能产品. 在8/16位中低端MCU领域,国内厂商的本土化产品设计以及超低价特点,使得其与国外大厂竞 ...

  6. CVE-2020-1938 -Tomcat-AJP任意文件读取/包含

    为什么这个漏洞被称作 Ghostcat(幽灵猫)? 这个漏洞影响全版本默认配置下的 Tomcat(在我们发现此漏洞的时候,确认其影响 Tomcat 9/8/7/6 全版本,而年代过于久远的更早的版本未 ...

  7. FreeBSD Fcitx 输入法框架设置

    #FreeBSD# 在.cshrc和/etc/csh.cshrc中进行如下配置,此配置可以解决部分窗口fcitx无效的问题. setenv QT4_IM_MODULE fcitx setenv GTK ...

  8. WDN302国产化网络存储控制模块

    WDN302是一款网络存储控制模块,实现对NAS和IP-SAN的混合支持,通过以太网对海量存储的访问,实现数据的存储.共享.恢复和防丢失. 飞腾 FT1500A/16处理器,主频 1.5GHz: 支持 ...

  9. P2766 最长不下降子序列问题 题解(网络流)

    题目链接 最长不下降子序列问题 解题思路 分成三小问解决. 第一小问,求\(LIS\),因为\(n<=500\),直接\(O(N^2)\)暴力求解即可. 第二三小问,建立模型用网络流求解. 对于 ...

  10. All I know about A/B Test (1) : 均值型指标与比值(率)型指标的计算区别

    因为最近在找实习,所以打算把自己之前学过的关数据分析的知识总结(复习)一下.在总结A/B test时,我发现中文互联网中关于A/B test的总结已经很多了,但是对于均值型指标和比值(率)型指标在设计 ...