首页
论坛
课程
招聘
Windows驱动编程之NetFilter SDK
2021-7-19 17:15 4485

Windows驱动编程之NetFilter SDK

2021-7-19 17:15
4485

一、引言

  Nfsdk源码网友口碑一直不错,梳理笔记分享。NetFilter SDK团队维护了多平台源码,本篇只介绍Windows平台。
官网:https://netfiltersdk.com
官网帮助:https://netfiltersdk.com/help/nfsdk2/
如果对Windows网络驱动没有概念,请先看:https://bbs.pediy.com/thread-268468.htm

二、源码分析

Netfilter sdk 2.0f主要分析三个模块,驱动,Dll和应用层:
编译环境:Wdk 2008/ wdk7600,win7/win10 x32x64
源码:泄露版v1.5.5.6(文章不提供,网上一堆)的socketRedirect示例。

R3/Nfapi:

1) SocksRedirector.cpp.main入口分析:
For循环部分参数解析,eh则是EventHandler类负责规则和数据处理,Add_rule()函数负责添加规则。
图片描述

 

2) Eh.Init函数负责Proxy的初始化:
图片描述

 

3) Nf_init驱动初始化,数据初始化包括hash_tab链表和启动Work线程:
图片描述

 

4) Work线程负责Event事件处理,并且阻塞在Read I/O数据,等待驱动返回数据,如下所示:

1
2
3
4
5
if (!ReadFile(g_hDevice, &rr, sizeof(rr), NULL, &ol))
{
    if (GetLastError() != ERROR_IO_PENDING)
        goto finish;
}

图片描述

 

5) HandleEvent负责处理来自内核捕获的传输层,网络层数据流,TCP/UDP-IP规则处理都可以在该类中,然后通过Nfapi.cpp接口将修改后的数据Write_IRP到驱动(注入):
图片描述

 

6) 规则添加部分,这部分请具体参考官方说明,下面是bypass本地和UDP/TCP重定向规则添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    memset(&rule, 0, sizeof(rule));
    rule.filteringFlag = NF_ALLOW;
    rule.ip_family = AF_INET;
    *((unsigned long*)rule.remoteIpAddress) = inet_addr("127.0.0.1");
    *((unsigned long*)rule.remoteIpAddressMask) = inet_addr("255.0.0.0");
    nf_addRule(&rule, FALSE);
 
    // Filter UDP packets
    memset(&rule, 0, sizeof(rule));
    rule.ip_family = AF_INET;        //
    rule.protocol = IPPROTO_UDP;    // UDP协议
    rule.filteringFlag = NF_FILTER;
    nf_addRule(&rule, FALSE);
 
    // Filter TCP connect requests
    memset(&rule, 0, sizeof(rule));
//    rule.ip_family = AF_INET;
    rule.protocol = IPPROTO_TCP;   // TCP协议
    rule.direction = NF_D_OUT;
//    rule.remotePort = htons(443);
    rule.filteringFlag = NF_INDICATE_CONNECT_REQUESTS;
    nf_addRule(&rule, FALSE);

7) 规则中的Direction字段,NF_FILTER模式EventHandler类将负责处理过滤的数据包,NF_INDICATE_CONNECT_REQUESTS只会触发EventHandler类中的tcpConnectRequest函数(因为该事件只会调用一次虚函数)。
图片描述

 

8) Add_rule通过Nfapi发送NF_REQ_ADD_HEAD_RULE /NF_REQ_ADD_TAIL_RULE来实现规则添加:
图片描述

 

9) 可以看到通过nf_postData和驱动进行数据传输,通过Write I/O将数据传入到驱动:
图片描述
  除了EventHandler类具体的操作,应用层主要初始化r3所需List_Buffer和Work事件处理线程,和驱动交互通过NfApi来Write_Irp控制驱动。

Driver:

1) DriverEntry首先初始化数据链表,dirver_init初始化devctrl_ioThread和devctrl_injectThread两个线程。
  devctrl_ioThread主要用来处理驱动内部的事件处理,如数据包拷贝返回应用层等工作,devctrl_injectThread主要负责不同层数据包重新注入,r3修改完成数据包重新发送Send则会进入到该线程注入:
图片描述

 

Devctrl_serviceReads函数中devctrl_fillBuffer如下:
图片描述

 

如果是NF_TCP_REINJECT类型会调用devctrl_pushTcpInject,激活devctrl_injectThread事件处理。

2) 框架注册Callout层梳理如下,注册了那么多子层为了满足传输层-网络层不通需求的数据拦截,通过应用层规则和标志位来使用驱动层数据即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
recvSubLayer:    
FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4    IPPROTO_TCP
FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6    IPPROTO_TCP    
FWPM_LAYER_STREAM_V4   
FWPM_LAYER_STREAM_V6    
FWPM_LAYER_OUTBOUND_TRANSPORT_V4   
FWPM_LAYER_INBOUND_TRANSPORT_V6    
FWPM_LAYER_ALE_ENDPOINT_CLOSURE_V4    IPPROTO_TCP     FWPM_LAYER_ALE_ENDPOINT_CLOSURE_V6    IPPROTO_TCP
pConnectRedirectSubLayer:    
FWPM_LAYER_ALE_CONNECT_REDIRECT_V4    IPPROTO_TCP     FWPM_LAYER_ALE_CONNECT_REDIRECT_V6    IPPROTO_TCP  
recvPortSubLayer:    
FWPM_LAYER_STREAM_V4    
FWPM_LAYER_STREAM_V6 
subLayer:    
FWPM_LAYER_STREAM_V4    
FWPM_LAYER_STREAM_V6    
FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4    IPPROTO_UDP     FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6    IPPROTO_UDP     FWPM_LAYER_OUTBOUND_TRANSPORT_V4     FWPM_LAYER_INBOUND_TRANSPORT_V6     FWPM_LAYER_ALE_ENDPOINT_CLOSURE_V4      IPPROTO_UDP     FWPM_LAYER_ALE_ENDPOINT_CLOSURE_V6    IPPROTO_UDP     FWPM_LAYER_OUTBOUND_IPPACKET_V4     FWPM_LAYER_INBOUND_IPPACKET_V4     FWPM_LAYER_OUTBOUND_IPPACKET_V6     FWPM_LAYER_INBOUND_IPPACKET_V6 
pUdpSubLayer:    
FWPM_LAYER_DATAGRAM_DATA_V4        IPPROTO_UDP        FWPM_LAYER_DATAGRAM_DATA_V6        IPPROTO_UDP  pUdpConnectRedirectSubLayer:     FWPM_LAYER_ALE_CONNECT_REDIRECT_V4    IPPROTO_UDP     FWPM_LAYER_ALE_CONNECT_REDIRECT_V6    IPPROTO_UDP

其他更多层注册请参考MSDN;
https://docs.microsoft.com/zh-cn/windows-hardware/drivers/network/management-filtering-layer-identifiers

 

3) 通过NfApi发送Write_Irp处理devctrl_dispatch派遣函数,控制码IRP_MJ_WRITE调用devctrl_write.devctrl_processRequest函数处理请求数据:
图片描述

 

4) 应用层Add_rule驱动中将规则解析加入全局g_lRules链表中,如下所示:
图片描述

三、重定向:

TCP重定向方法和TCP数据修改,客户端连接Server必要的几个步骤:

  1. Create socket
  2. Connect server
  3. Send & Recv

  WFP每个阶段都提供了对应的筛选器对应GUID,这个过程有很多重定向办法,比如Connect连接直接将目标IP进行重定向,也可以在stearm或者garmdata层(udp)做拦截block,重新注入层(改包)。

 

1) 应用层Main添加了TCP重定向规则才会生效:

1
2
3
4
5
6
7
8
// Filter TCP connect requests
    memset(&rule, 0, sizeof(rule));
//  rule.ip_family = AF_INET;
    rule.protocol = IPPROTO_TCP;
    rule.direction = NF_D_OUT;
//    rule.remotePort = htons(443);
    rule.filteringFlag = NF_INDICATE_CONNECT_REQUESTS;
    nf_addRule(&rule, FALSE);

2) 驱动初始化的时候,会注册callout和过滤器(Driver中的第二步),相关代码如下:

1
2
3
4
5
6
7
8
9
10
Dirver.callout.c:
        status = callouts_addFlowEstablishedFilter(
            &g_calloutGuids[CG_ALE_CONNECT_REDIRECT_V4],
            &FWPM_LAYER_ALE_CONNECT_REDIRECT_V4,
            pConnectRedirectSubLayer);
        if (!NT_SUCCESS(status))
        {
            break;
        }
CG_ALE_CONNECT_REDIRECT_V4关联的回调函数

Callouts_connectRedirectCallout,如何处理连接操作如下:

  • 首先参数检测,调用callouts_createFlowContext将句柄和五要素等数据,包括判断当前规则状态:
    图片描述

  • 如果NF_INDICATE_CONNECT规则,push:NF_TCP_CONNECT_REQUEST标志:
    图片描述

    1
    status = devctrl_pushTcpData(pTcpCtx->id, NF_TCP_CONNECT_REQUEST, pTcpCtx, NULL);
  • devctrl_pushTcpData函数负责将保存的数据插入链表,激活g_ioThreadEvent事件如下:
    图片描述

  • Devctrl_ioThread()负责处理g_ioThreadEvent激活事件,如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    void devctrl_ioThread(IN PVOID StartContext)
    {
      UNREFERENCED_PARAMETER(StartContext);
     
      KdPrint((DPREFIX"devctrl_ioThread\n"));
     
      for(;;)
      {
          KeWaitForSingleObject(
              &g_ioThreadEvent,
               Executive,
               KernelMode,
               FALSE,
               NULL
           );
     
          if (devctrl_isShutdown())
          {
              break;
          }
     
          devctrl_serviceReads();
      }
     
      PsTerminateSystemThread(STATUS_SUCCESS);
    }
  • IRP_pakcet完成返回:

    1
    2
    3
    4
    pResult->length = devctrl_fillBuffer();
    irp->IoStatus.Status = STATUS_SUCCESS;
    irp->IoStatus.Information = sizeof(NF_READ_RESULT);
    IoCompleteRequest(irp, IO_NO_INCREMENT);
  • 应用层接收到驱动传递来的数据以后,其实激活了处理的事件:
      通过事件调用EventHandler类的tcpCpnnectRequest函数,然后在应用层函数修改数据,通过nf_postData将数据包发送至驱动:
    图片描述

  IRP_MJ_WRITE就会被触发,执行devctrl_processRequest来分发进程的IRP,根据NF标志调用devctrl_processTcpConnect,如下:
图片描述

 

  基于Connect_Redirect这种方式重定位无法拦截具体的包数据,驱动需要注册Stearm&Established层出入栈条件,将包数据回传到应用层,在Send和Recv时候对数据Buffer进行操作。
  Nfsdk框架初始化时候已经注册完成,提供了过滤标志,tcpSend其他的函数生效只需要在tcpConnectRequest函数修改重定向数据后,标志位pConnInfo->filteringFlag标志开启NF_FILTER即可,如下所示:
图片描述

总结:

  驱动负责网络数据捕获,将数据抛到应用层,应用层根据规则过滤、改包。应用层通过接口将修改Packet发送至驱动,注入到对应的层从而闭环,应用层处理数据也会减少了一些风险,健壮性会好一些。
  NetFilter SDK2.0源码对应用层开发友好,接口文档和示例就可以基于TDI/WFP开发网络防火墙和代理,驱动是透明的。邮件反馈回复及时,有问题他们会给予帮助。这套代码思路也可以应用到其他方向如MiniFilter,也会有比较好的效果。觉着如果事件这种触发方式换成ALPC通信,r0~r3数据传输会更高效一些。


[培训] 优秀毕业生寄语:恭喜id:一颗金柚子获得阿里offer《安卓高级研修班》火热招生!!!

最后于 2021-7-19 20:19 被一半人生编辑 ,原因:
收藏
点赞1
打赏
分享
最新回复 (24)
雪    币: 9956
活跃值: 活跃值 (4321)
能力值: ( LV12,RANK:302 )
在线值:
发帖
回帖
粉丝
一半人生 活跃值 5 2021-7-19 19:29
2
0

本地代理也是一个重要模块,这里不做具体的带过,他是为了解决WFP设计缺陷所产生的,命中的规则IP重定向本地代理。

本地代理获取真实的IP创建连接,数据做双向通道(Socket5代理),为什么会这样做?

打个比方,WFP在完成重定向之后(回调结束),立刻想要发送一个Send数据给重定向节点,WFP设计问题回调不结束导致connect没办法完成,回调结束的你无法捕获,导致没办法像Hook那样,本地代理就是为了解决这类问题,Nfsdk团队明确了这一点:

Yes,  the  connections are redirected to a local proxy. Then the local
proxy  establishes a connection with remote server. It allows to avoid
the  issues  on  WFP  layer  with  injecting  proxy  handshake packets
immediately  after  establishing  a connection with remote server. The
local  proxy  uses  generic  sockets, so it allows to send and receive
packets without limitations.

-- 
Best regards,
 Vitaly                            mailto:support@netfiltersdk.com


最后于 2021-7-20 08:17 被一半人生编辑 ,原因:
雪    币: 1047
活跃值: 活跃值 (181)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
天涯一鸿 活跃值 2021-7-20 22:27
3
0

。。。没有一个关键字可以搜到有价值的东西,不知道网上一大堆是指的啥,不过先收藏吧,以后如果遇到了就demo加IDA对着调吧

最后于 2021-7-20 22:27 被天涯一鸿编辑 ,原因:
雪    币: 0
活跃值: 活跃值 (152)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
粘粘搭搭 活跃值 2021-7-21 14:05
4
0
我想看什么老哥就发什么,真是太棒了
雪    币: 61
活跃值: 活跃值 (773)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
fengyunabc 活跃值 1 2021-7-22 11:49
5
0
感谢分享!
雪    币: 62
活跃值: 活跃值 (209)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
值得怀疑 活跃值 2021-7-22 19:04
6
0
天涯一鸿 。。。没有一个关键字可以搜到有价值的东西,不知道网上一大堆是指的啥,不过先收藏吧,以后如果遇到了就demo加IDA对着调吧
一样··搜不到这源码要搜啥关键字啊。。。。。。。。。。。。。
雪    币: 1907
活跃值: 活跃值 (882)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caolinkai 活跃值 2021-7-23 17:13
7
0
网上一大堆,结果 毛都 没搜到。。。。。。。。。
雪    币: 1907
活跃值: 活跃值 (882)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caolinkai 活跃值 2021-7-23 17:13
8
0
一半人生 本地代理也是一个重要模块,这里不做具体的带过,他是为了解决WFP设计缺陷所产生的,命中的规则IP重定向本地代理。本地代理获取真实的IP创建连接,数据做双向通道(Socket5代理),为什么会这样做?打 ...
网上一大堆,结果 毛都 没搜到。。。。。。。。。
雪    币: 182
活跃值: 活跃值 (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
dfangboy 活跃值 3天前
9
0
我也没搜到。然后问楼主,要1500。买不起
雪    币: 9956
活跃值: 活跃值 (4321)
能力值: ( LV12,RANK:302 )
在线值:
发帖
回帖
粉丝
10
0
dfangboy 我也没搜到。然后问楼主,要1500。买不起

建议大家花钱支持作者,搞这一行的不易。

雪    币: 9956
活跃值: 活跃值 (4321)
能力值: ( LV12,RANK:302 )
在线值:
发帖
回帖
粉丝
11
0

不要私了,至于看待便宜或贵,取决于对自己的价值。

微软开源了基于WFP防火墙模板,github免费下载:

Windows-driver-samples/network/trans/WFPSampler at master · microsoft/Windows-driver-samples (github.com)

最后于 3天前 被一半人生编辑 ,原因:
雪    币: 3
活跃值: 活跃值 (175)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bestbird 活跃值 3天前
12
0

nfsdk-src-1.5.9.0-pf-src-1.2.4.1.z01


最后于 3天前 被bestbird编辑 ,原因: aa
上传的附件:
雪    币: 3
活跃值: 活跃值 (175)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bestbird 活跃值 3天前
13
0

nfsdk-src-1.5.9.0-pf-src-1.2.4.1.z02

上传的附件:
雪    币: 3
活跃值: 活跃值 (175)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bestbird 活跃值 3天前
14
0

nfsdk-src-1.5.9.0-pf-src-1.2.4.1.zip


上传的附件:
雪    币: 3
活跃值: 活跃值 (175)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bestbird 活跃值 3天前
15
1
还有一个古老的版本必须单线程下载:
ftp://uploads@uploads.2ccc.com/NetFilter%20SDK%201.4.0.0%20+%20ProtocolFilters%201.0.8.1%20-%20Full%20Sources.7z
雪    币: 3
活跃值: 活跃值 (175)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bestbird 活跃值 3天前
16
0
另外有
BoxedApp SDK Full Source
BoxedApp Packer Full Source
就是太大不好上传
https://www.boxedapp.com/
雪    币: 182
活跃值: 活跃值 (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
dfangboy 活跃值 3天前
17
0
太感谢楼上的兄弟了。
雪    币: 71
活跃值: 活跃值 (50)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
dumingqiao 活跃值 2天前
18
0
泄漏那个 v1.5.5.6 有Bug,ProtocolFilters里面的SSL 重定向隔十几分钟就会无缘无故失效。
雪    币: 9956
活跃值: 活跃值 (4321)
能力值: ( LV12,RANK:302 )
在线值:
发帖
回帖
粉丝
19
0
dumingqiao 泄漏那个 v1.5.5.6 有Bug,ProtocolFilters里面的SSL 重定向隔十几分钟就会无缘无故失效。
这个是他类里面的的问题
雪    币: 62
活跃值: 活跃值 (209)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
值得怀疑 活跃值 2天前
20
0
bestbird 另外有 BoxedApp SDK Full Source BoxedApp Packer Full Source 就是太大不好上传 https://www.boxedapp.com/
感谢大兄弟, BoxedApp 有网盘链接下载码
雪    币: 0
活跃值: 活跃值 (152)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
粘粘搭搭 活跃值 2天前
21
0

1

最后于 2天前 被粘粘搭搭编辑 ,原因:
雪    币: 0
活跃值: 活跃值 (152)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
粘粘搭搭 活跃值 2天前
22
0
微软的wfp是不是多个wfp回调支持不太好,我经常遇到有些时候wfp的回调不来。必须height调高,别人设置一个已修改就不来了,这种类似的问题有没有研究过的?
雪    币: 3
活跃值: 活跃值 (175)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bestbird 活跃值 2天前
23
0
个人更加喜欢俄罗斯NTKernel卖的那个而不是NetFilter SDK。
雪    币: 9956
活跃值: 活跃值 (4321)
能力值: ( LV12,RANK:302 )
在线值:
发帖
回帖
粉丝
24
0
bestbird 个人更加喜欢俄罗斯NTKernel卖的那个而不是NetFilter SDK。
这个相比于netfilter sdk是不是更完善一些
雪    币: 3
活跃值: 活跃值 (175)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bestbird 活跃值 3小时前
25
0
一半人生 这个相比于netfilter sdk是不是更完善一些

https://www.ntkernel.com/windows-packet-filter/
不只是完善。有人用它写过后门,传说服务器5年没重启都没事。

也是更新了很多年:https://www.ntkernel.com/winpkfilter-release-history/

最后于 3小时前 被bestbird编辑 ,原因:
游客
登录 | 注册 方可回帖
返回