[md]

0x1前言

文中的注释有的来自微软官方的解释翻译,有的来自Windows内核安全与驱动开发书中的解释,也有的来自我个人的理解。代码功能是在Windows内核安全与驱动开发第15章中Wfpsample代码的基础上完成的.

0x2环境配置

1610609082543.png (23.62 KB, 下载次数: 0)

2021-1-24 18:54 上传

代码直接编译一大堆错误,网上找了找原因是环境配置问题

在wfp开发是遇到

FwpmEngineOpen0无法解析;NET_BUFFER_LIST未定义

在链接器->输入 的附加依赖项中加入如下lib,自己项目需要什么就加什么

$(DDK_LIB_PATH)\NTOSKrnl.lib;$(DDK_LIB_PATH)\FwpKClnt.lib;$(DDK_LIB_PATH)\NetIO.lib;$(DDK_LIB_PATH)\NDIS.lib;$(DDK_LIB_PATH)\WDMSec.lib;$(SDK_LIB_PATH)\UUID.lib;

定义的NDIS和系统版本关系

// Legal values include:

//    6.0  Available starting with Windows Vista RTM

//    6.1  Available starting with Windows Vista SP1 / Windows Server 2008

//    6.20 Available starting with Windows 7 / Windows Server 2008 R2

//    6.30 Available starting with Windows 8 / Windows Server "8"

#define FILTER_MAJOR_NDIS_VERSION   6

#if defined(NDIS60)

#define FILTER_MINOR_NDIS_VERSION   0

#elseif defined(NDIS620)

#define FILTER_MINOR_NDIS_VERSION   20

#elseif defined(NDIS630)

#define FILTER_MINOR_NDIS_VERSION   30

#endif

NET_BUFFER_LIST未定义时,需要定义NDIS版本,可以参考ndis.h

在编译器的c/c++ ->预处理器中添加 NDIS61

0x3WFP框架功能介绍

以下为个人理解,有错误或不同的理解也欢迎指出

初看wfp代码,有点乱,因为它既设置了呼出接口过滤函数,也设置了Irp过滤函数,仔细看完所有代码后发现,它并不像minifiter一样,有专门的新函数用于和应用层交互,虽然他也是一个新的框架相较于tdi和ndis,它仍然是用的Irp过滤函数与应用层交互,在与应用层DeivceIoControl这个irp交互时,会传入一个结构体,这个结构体里有各种想过滤的目标的信息,把这个结构体插入链表,然后在的注册的呼出接口过滤函数里,对该链表进行读取,然后判断是否是目标,从而进行相应的过滤操作。

1设置IRP过滤函数

DriverObject->MajorFunction[IRP_MJ_CREATE] = WfpSampleIRPDispatch;

DriverObject->MajorFunction[IRP_MJ_CLOSE] =  WfpSampleIRPDispatch;

DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = WfpSampleIRPDispatch;

CREATE与CLOSE在打开和关闭驱动时过滤函数会被调用

CONTROL用于与应用层交换

switch( IrpStack->Parameters.DeviceIoControl.IoControlCode )

{

case IOCTL_WFP_SAMPLE_ADD_RULE:

{

BOOLEAN bSucc = FALSE;

bSucc = AddNetRuleInfo(        pSystemBuffer ,uInLen );

if( bSucc == FALSE )

{

nStatus = STATUS_UNSUCCESSFUL;

}

break;

}

default:

{

ulInformation = 0;

nStatus = STATUS_UNSUCCESSFUL;

}

}

}

CONTROL码为IOCTL_WFP_SAMPLE_ADD_RULE时通过AddNetRuleInfo函数将数据加入链表

其他的IRP不做处理。

2创建设备对象与初始化

UNICODE_STRING        uDeviceName = {0};

UNICODE_STRING        uSymbolName = {0};

PDEVICE_OBJECT        pDeviceObj = NULL;

NTSTATUS nStatsus = STATUS_UNSUCCESSFUL;

RtlInitUnicodeString(&uDeviceName,WFP_DEVICE_NAME);

RtlInitUnicodeString(&uSymbolName,WFP_SYM_LINK_NAME);

nStatsus = IoCreateDevice(DriverObject,0,&uDeviceName,FILE_DEVICE_UNKNOWN,0,FALSE,&pDeviceObj);

if( pDeviceObj != NULL )

{

pDeviceObj->Flags |= DO_BUFFERED_IO;

}

IoCreateSymbolicLink(&uSymbolName,&uDeviceName);

return pDeviceObj;

与普通驱动无区别,创建设备对象创建符号链接。

InitializeListHead(&g_WfpRuleList);

KeInitializeSpinLock(&g_RuleLock);

DriverObject->DriverUnload = DriverUnload;

初始化链表用于存放数据,初始化锁用于保证安全写入链表。

3WFP功能函数

//注册呼出接口

if (STATUS_SUCCESS  != WfpRegisterCallouts(g_pDeviceObj) )

{

break;

}

//添加呼出接口

if( STATUS_SUCCESS != WfpAddCallouts() )

{

break;

}

//添加子层

if( STATUS_SUCCESS != WfpAddSubLayer() )

{

break;

}

//添加过滤引擎

if( STATUS_SUCCESS != WfpAddFilters() )

{

break;

}

流程正如注释,注册呼出接口->添加呼出接口->添加子层->添加过滤引擎;

接口实际上相当于普通驱动的过滤函数,接口设置的函数用于对数据进行处理,

子层是分层的一个更小单位,一个分层中包含了多个或零个子层,而子层之间的优先级由权重来区分,权重越大,优先级越高。

过滤引擎中

Filter.action.calloutKey = WFP_SAMPLE_ESTABLISHED_CALLOUT_V4_GUID;

这个值决定这个驱动加入那个层,

那层是什么,不同的层有什么区别。

过滤引擎由很多层组成。每一层代表了网络协议栈的一个层。分层是一个容器,里面包含了0或多个过滤器,或一个或多个子层。每个分层都有一个唯一标识的UID,不同的层获取的数据不一样,这是Windows内核安全与驱动开发书中的解释

在不同的层获取的数据不一样,这个不一样指的是首部,传输层比应用层多个tcp/udp首部,但本质上这个数据的用户数据部分没有改变,只是加了个首部,数据会经过每个层,我看书的时候以为获取不一样的数据是指不同的用户数据,看书的时候一直纠结,这些都能截获什么样的用户数据,看完了都没说,后搜了一下网络协议栈,才恍然大悟,其实用户数据会经过每个层,只是经过时会加上不同的头部,所以不同。所以不同的层就是有不同的首部。

其他的细节部分建议看书。

0x4开发日志

1打印过滤到的ip并进行拦截测试

//ulRemoteIPAddress 表示远端IP

ulRemoteIPAddress =

inFixedValues->

incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_ADDRESS]

.value.uint32;

DbgPrint("remote ip is %x\n", ulRemoteIPAddress);

在过滤函数Wfp_Sample_Established_ClassifyFn_V4里对获取的ip进行打印

1611211389312.png (245.35 KB, 下载次数: 0)

2021-1-24 18:55 上传

百度ip为112.80.248.76,获取的数为0x7050f84c,转化一下刚好对应,ip获取成功。

if (ulRemoteIPAddress = 0x7050F84C)

{

classifyOut->actionType = FWP_ACTION_BLOCK;

}

先做个简单的拦截测试,classifyOut->actionType = FWP_ACTION_BLOCK;就是返回拦截的意思。

1611211683818.png (176.67 KB, 下载次数: 0)

2021-1-24 18:56 上传

百度刷新一下一直是没反应,就用cmd,ping一下baidu,拦截成功

2应用层获取网站输入并进行ip地址转化发给驱动

[Asm] 纯文本查看 复制代码CString str;

GetDlgItemText(IDC_EDIT_PORT, str);

const charcstr;

char temp[zxsq-anti-bbcode-100];

::wsprintfA(temp, "%ls", (LPCTSTR)str);

cstr = temp;

hostenthost = gethostbyname(cstr);

实现定义变量str,从文本框中获取文本放入str,再把 char* 类型的str转为char类型,再通过字符串使用函数gethostbyname获取ip。

1611389535830.png (11.52 KB, 下载次数: 0)

2021-1-24 18:56 上传

然后我本来想测试一下IP是否成功get到,就用messagebox,显示一下host。host为0,调用WSAGetLastError,看一下没有符号表,就用od调了一下,返回值为0000276D,看了一下错误信息,函数就通过字符串获取ip,我还以为那个函数可以单独使用。又加上WSAStartup相关代码。

ULONG a[10] = { 0 };

int x = 0;

for (x;; x++)

{

a[x] = inet_addr(inet_ntoa(*((in_addr *)host->h_addr_list[0])));

if (host->h_addr_list[x] + host->h_length >= host->h_name)

{

break;

}

}

HANDLE hFile = CreateFile(_T("\\\\.\\wfp_sample_device"),GENERIC_ALL,0,NULL,OPEN_EXISTING,0,NULL);

if( hFile == INVALID_HANDLE_VALUE )

{

return;

}

ST_WFP_NETINFO Info = {0};

// Info.m_uRemotePort = uPort;

for (x; x >= 0; x--)

{

Info.m_ulRemoteIPAddr = a[x];

DWORD dwNeedSize = 0;

BOOL rValue = DeviceIoControl(hFile, IOCTL_WFP_SAMPLE_ADD_RULE, (LPVOID)&Info, sizeof(Info), NULL, 0, &dwNeedSize, NULL);

}

接下来用个循环把通过函数inet_addr把字符串ip转成ULONG的值存入数组ULONG a[10],再打开驱动通过DeviceIoControl发送数据,for循环把数组每个值都发过去。

3驱动获取输入存入链表与过滤函数读取链表判断拦截

BOOLEAN AddNetRuleInfo(PVOID pBuf,ULONG uLen)

{

BOOLEAN bSucc = FALSE;

PST_WFP_NETINFO        pRuleInfo = NULL;

do

{

PST_WFP_NETINFOLIST pRuleNode = NULL;

KIRQL        OldIRQL = 0;

pRuleInfo = (PST_WFP_NETINFO)pBuf;

if( pRuleInfo == NULL )

{

break;

}

if( uLen < sizeof(ST_WFP_NETINFO) )

{

break;

}

pRuleNode = (PST_WFP_NETINFOLIST)ExAllocatePoolWithTag(NonPagedPool,sizeof(ST_WFP_NETINFOLIST),WFP_TAG);

if( pRuleNode == NULL )

{

break;

}

memset(pRuleNode,0,sizeof(ST_WFP_NETINFOLIST));

pRuleNode->m_stWfpNetInfo.m_uSrcPort = pRuleInfo->m_uSrcPort;

pRuleNode->m_stWfpNetInfo.m_uRemotePort = pRuleInfo->m_uRemotePort;

pRuleNode->m_stWfpNetInfo.m_ulSrcIPAddr = pRuleInfo->m_ulSrcIPAddr;

pRuleNode->m_stWfpNetInfo.m_ulRemoteIPAddr = pRuleInfo->m_ulRemoteIPAddr;

pRuleNode->m_stWfpNetInfo.m_ulNetWorkType = pRuleInfo->m_ulNetWorkType;

pRuleNode->m_stWfpNetInfo.m_uDirection = pRuleInfo->m_uDirection;

KeAcquireSpinLock(&g_RuleLock,&OldIRQL);

InsertHeadList(&g_WfpRuleList,&pRuleNode->m_linkPointer);

KeReleaseSpinLock(&g_RuleLock,OldIRQL);

bSucc = TRUE;

break;

}

while (FALSE);

return bSucc;

}

应用层通过DeviceIoControl发送数据,驱动通过设置DeviceIoControl的irp函数进行操作,在WfpSampleIRPDispatch函数里调用AddNetRuleInfo函数将数据存入全局变量的链表。

BOOLEAN IsHitRule(USHORT ulRemoteIPAddress)

{

BOOLEAN bIsHit = FALSE;

do

{

KIRQL        OldIRQL = 0;

PLIST_ENTRY        pEntry = NULL;

if( g_WfpRuleList.Blink == NULL ||

g_WfpRuleList.Flink == NULL )

{

break;

}

KeAcquireSpinLock(&g_RuleLock,&OldIRQL);

pEntry = g_WfpRuleList.Flink;

while( pEntry != &g_WfpRuleList )

{

PST_WFP_NETINFOLIST pInfo = CONTAINING_RECORD(pEntry,ST_WFP_NETINFOLIST,m_linkPointer);

if (ulRemoteIPAddress == pInfo->m_stWfpNetInfo.m_ulRemoteIPAddr)

{

bIsHit = TRUE;

break;

}

pEntry = pEntry->Flink;

}

KeReleaseSpinLock(&g_RuleLock,OldIRQL);

}

while (FALSE);

return bIsHit;

}

过滤函数Wfp_Sample_Established_ClassifyFn_V4里调用IsHitRule函数,传入参数ulRemoteIPAddress为当前包的ip,通过读取链表中从应用层获取的ip进行一一比对,有目标ip就把bIsHit = TRUE;,返回它,在外面判断bIsHit 的值,是true就拦截。

0x5调试日志

测试时发现没有拦截成功

应用层调试

1611471439944.png (230.7 KB, 下载次数: 0)

2021-1-24 18:57 上传

对wsprintfA下断点(其他的函数也一样),断下后返回用户代码,往下找inet_addr函数(ip转换函数)

1611471658898.png (349.03 KB, 下载次数: 0)

2021-1-24 18:58 上传

断下后第一次od里是112.80.248.75 而ping 的是112.80.248.76,我又重试了一次又是112.80.248.75 。

1611471977297.png (360.29 KB, 下载次数: 0)

2021-1-24 18:58 上传

然后我又全部重试了一次,这一次od里是112.80.248.76,而ping 的是112.80.248.75,我又ping一下又是112.80.248.76,猜测可能百度有多个ip(个人猜测,有错误欢迎大佬指出)。

应用层ip获取成功了,接下来看数据是否发送成功。

1611472704192.png (310.17 KB, 下载次数: 0)

2021-1-24 18:58 上传

for (x; x >= 0; x--)

{

ST_WFP_NETINFO Info = { 0 };

Info.m_ulRemoteIPAddr = a[x];

DWORD dwNeedSize = 0;

BOOL rValue = DeviceIoControl(hFile, IOCTL_WFP_SAMPLE_ADD_RULE, (LPVOID)&Info, sizeof(Info), NULL, 0, &dwNeedSize, NULL);

if (rValue == 0)

{

MessageBox(L"failed");

}

else

{

CString temp_value = _T("");

temp_value.Format(_T("%x"), a[x]);

MessageBox(temp_value);

}

}

a[x]是存放ip的ULONG数组,MessageBox(L"failed");是失败,MessageBox一个数值就是发送成功,数值为ip的值,4cf85070可以和ip对上,那就是没问题题,应用层的排查到此为止。

驱动层调试

while( pEntry != &g_WfpRuleList )

{

PST_WFP_NETINFOLIST pInfo = CONTAINING_RECORD(pEntry,ST_WFP_NETINFOLIST,m_linkPointer);

DbgPrint("111is --%x-\n", pInfo->m_stWfpNetInfo.m_ulRemoteIPAddr);

char *ip1 = ulRemoteIPAddress;

char *ip2 = pInfo->m_stWfpNetInfo.m_ulRemoteIPAddr;

DbgBreakPoint();

if (ulRemoteIPAddress == pInfo->m_stWfpNetInfo.m_ulRemoteIPAddr)

{

bIsHit = TRUE;

break;

}

pEntry = pEntry->Flink;

}602C9824

在判断前加个DbgBreakPoint()断点,既可以看目标ip是否拦截到,也可以看应用层发的数据是否存入链表。

1611474478838.png (82.5 KB, 下载次数: 0)

2021-1-24 18:59 上传

从windbg中可以很明显的看出来了,ulRemoteIPAddress是0x24982c60

而pInfo->m_stWfpNetInfo.m_ulRemoteIPAddr是               0x602c9824,两个数刚好是反过来的,

总结一下:应用层的数据类型变来变去的过程里内存的存放翻转了一次,导致驱动进行比对时不相同,从而未能拦截。

0x6使用展示

1611480725539.png (153.61 KB, 下载次数: 0)

2021-1-24 18:59 上传

在网站框内输入想拦截的网址即可,第一次为未输入网站ping 百度成功,第二次为输入网站后ping百度,拦截成功,网址可输入多个。

0x7文件源码及总结

vs看源码方便些,就不把源码帖出来占篇幅了,直接给源码文件

总结的话,下次买电脑一定买个硬盘好的,虚拟机用着是真难受,开机要半天,点一下卡三秒。

wfp 禁用ip_WFP网络过滤驱动——限制网站访问相关推荐

  1. WFP网络过滤驱动-限制网站访问

    文章目录 前言 WFP入门介绍 WFP基本架构 名词解释 代码基本结构 代码示例 前言 WFP Architecture - Win32 apps | Microsoft Learn是一个网络流量处理 ...

  2. wfp 禁用ip_[原创]WFP网络过滤驱动——限制网站访问

    0x1前言 文中的注释有的来自微软官方的解释翻译,有的来自Windows内核安全与驱动开发书中的解释,也有的来自我个人的理解.代码功能是在Windows内核安全与驱动开发第15章中Wfpsample代 ...

  3. NDIS LWF网络过滤驱动开发(一):LWF简介及数据结构说明

    写在之前:换工作了,做Win驱动开发,还是网络过滤驱动.之前从未接触过这些,只是做着单机的桌面应用程序,所以一切是从头开始.从驱动到网络,很多的不懂,一步步走来,现在多少有些进展了,现在就总结下这段过 ...

  4. (转)TDI FILTER 网络过滤驱动完全解析

    http://blog.csdn.net/charlesprince/article/details/5924376 TDI FILTER 过滤驱动的功能一般用来进行整个系统中的所有网络流量的分析,记 ...

  5. wfp 禁用ip_WFP 层要求和限制

    WFP 层要求和限制WFP Layer Requirements and Restrictions 01/22/2019 本文内容 以下要求和限制适用于 WFP 层.The following req ...

  6. TDI Filter 过滤驱动

    By Fanxiushu  2013, 引用和转载请注明原作者 为了让大家有兴趣阅读下去, 举个正在使用的可能大家都比较熟悉的例子: 360 的安全卫士里,有个流量防火墙的功能, 它可以监视每个进程的 ...

  7. windows7以上平台 NDISFilter 网卡过滤驱动开发

    by fanxiushu 2019-01-16 转载或引用请注明原始作者 这里讨论的都是基于WIN7以上平台,NDIS 6.0以上版本的网络驱动. 做个驱动的目的,是因为很早之前,我使用 TDI 和 ...

  8. Windows 文件系统过滤驱动开发教程 (第二版)

    Windows 文件系统过滤驱动开发教程 (第二版)       楚狂人-2007-上海 (MSN:walled_river@hotmail.com)          -1.  改版序....... ...

  9. Windows文件系统过滤驱动开发教程(0,1,2)

    0. 作者,楚狂人自述 我长期网上为各位项目经理充当"技术实现者"的角色.我感觉Windows文件系统驱动的开发能找到的资料比较少.为了让技术经验不至于遗忘和引起大家交流的兴趣我以 ...

最新文章

  1. 使用javascript模拟常见数据结构(二)
  2. 单列索引和联合索引,有什么区别?
  3. 在游戏里模拟天空的颜色,太迷人了!
  4. 单边指数信号的特点_测试技术课后题答案1信号描述
  5. 反序列化对象列表发生异常_Apache Thrift系列详解:序列化机制
  6. Spring中HibernateCallback的用法(转)
  7. Asp.Net中SqlServer数据库连接方式
  8. Android APP开发入门教程-Button
  9. 面对一直在房价洼地的长沙,我不后悔十几年前逃离长沙
  10. CryptoJS 下载地址
  11. manifest权限
  12. C#访问网页、保存网页
  13. 解读 Centralized Feature Pyramid for Object Detection
  14. EKS学习 环境搭建方法
  15. 使用 sudo nautilus 进入ubuntu 文件管理器。可以随意复制,删除,粘贴,无权限限制
  16. 在线文档编辑工具哪个更好?
  17. 利用SSH 或 Teamviewer 控制远程服务器
  18. c#调用HTTP请求
  19. RC滤波器、时域、频域分析笔记A
  20. c程序设计:输入长方形的高和宽,求该长方形的周长和面积

热门文章

  1. c语言:(指针)实现输入三个整数从小到大排序
  2. linux部署qq机器人记录
  3. 阿里云服务搭建微信小程序开发环境
  4. 如何让centos7串口数(ttyS*)大于4个
  5. 我的世界基java版刷怪机制_我的世界1.8版本刷怪机制_我的世界代码1.8版本刷怪机制_快吧单机游戏...
  6. matlab 常值函数,matlab常用数值函数大全
  7. 《 ERP高级计划》书的解读-APS算法分析之七分解技术(DT)(蔡颖)(转)
  8. 计算机网络ip地址在哪,w7的ip地址在哪?小编教你怎么查看
  9. 怎么把一个表格拆分成两个表格
  10. AI工程师的自我修养