遍历wfp(防火墙)的callouts过滤处理函数

admin 2024年4月23日05:40:52评论2 views字数 5730阅读19分6秒阅读模式

本周天终端安全开发直播,带你走进智能终端安全!

遍历wfp(防火墙)的callouts过滤处理函数

WFP的callouts是由内核模块的wfp过滤框架向网络堆栈(netio.sys)注册的函数,也就是说callouts是最终防火墙或者网络过滤干活的处理函数对象。

这个主要干活的是通过FwpsCalloutRegister注册的三个回调函数,注册成功后会返回一个callout_id用于标识被注册的wfp callout对象。

callout对象结构

typedef struct FWPS_CALLOUT1_{   // Uniquely identifies the callout. This must be the same GUID supplied to   // FwpmCalloutAdd0.   GUID calloutKey;   // Flags   UINT32 flags;   // Pointer to the classification function.   FWPS_CALLOUT_CLASSIFY_FN1 classifyFn;   // Pointer to the notification function.   FWPS_CALLOUT_NOTIFY_FN1 notifyFn;   // Pointer to the flow delete function.   FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN0 flowDeleteFn;} FWPS_CALLOUT1;

classifyFn:主要干活的回调,可以获得网络包全部信息(与注册类型相关),可以实现网络包数据拦截、编辑等。

notifyFn:当过滤器被添加到过滤引擎时被调用。

flowDeleteFn:当一个网络数据被终止时调用,这个函数中可以对classifyfn中的操作进行清理。

那如何枚举出这三个函数呢,如何实现类似Pchunter中枚举系统回调的功能呢,关联出时哪一个驱动注册的wfp网络过滤函数?

 这里基于windows10 22h2版本做试验

遍历wfp(防火墙)的callouts过滤处理函数

第一步用windbg挂载上内核加载符号(如果没有驱动开发基础可以到最后联系作者学习)。

遍历wfp(防火墙)的callouts过滤处理函数

第二步通过逆向分析(详细逆向分析视频教程到最后联系作者学习)确定netio.sys有个全局变量gWfpGlobal保存所有callouts相关信息,直接查看。

```

dp netio!gWfpGlobal L1

Unloaded modules:

fffff804`332e0000 fffff804`332f0000   dump_storport.sys

fffff804`33310000 fffff804`33330000   dump_lsi_sas.sys

fffff804`33350000 fffff804`3336e000   dump_dumpfve.sys

fffff804`34f10000 fffff804`34f2c000   dam.sys

fffff804`31430000 fffff804`31441000   WdBoot.sys

fffff804`32990000 fffff804`329a1000   hwpolicy.sys

0: kd> dp netio!gWfpGlobal L1

fffff804`3226c560  ffffdd8b`5aae9050

```

第三步反汇编FeInitCalloutTable函数。

```u netio!FeInitCalloutTable L20ffff804`32213935 c3              ret0: kd> u netio!FeInitCalloutTable L20NETIO!FeInitCalloutTable:fffff804`32213804 4053            push    rbxfffff804`32213806 4883ec20        sub     rsp,20hfffff804`3221380a 488b054f8d0500  mov     rax,qword ptr [NETIO!gWfpGlobal (fffff804`3226c560)]fffff804`32213811 0f57c0          xorps   xmm0,xmm0fffff804`32213814 ba57667043      mov     edx,43706657hfffff804`32213819 b900400100      mov     ecx,14000hfffff804`3221381e 0f118090010000  movups  xmmword ptr [rax+190h],xmm0fffff804`32213825 4c8b05348d0500  mov     r8,qword ptr [NETIO!gWfpGlobal (fffff804`3226c560)]fffff804`3221382c 4981c098010000  add     r8,198hfffff804`32213833 e8c805feff      call    NETIO!WfpPoolAllocNonPaged (fffff804`321f3e00)fffff804`32213838 488bd8          mov     rbx,raxfffff804`3221383b 4885c0          test    rax,raxfffff804`3221383e 0f85b8480100    jne     NETIO!FeInitCalloutTable+0x148f8 (fffff804`322280fc)fffff804`32213844 488b0d158d0500  mov     rcx,qword ptr [NETIO!gWfpGlobal (fffff804`3226c560)]fffff804`3221384b 33d2            xor     edx,edxfffff804`3221384d 41b800400100    mov     r8d,14000hfffff804`32213853 488b8998010000  mov     rcx,qword ptr [rcx+198h]fffff804`3221385a e8217b0000      call    NETIO!memset (fffff804`3221b380)fffff804`3221385f 488b05fa8c0500  mov     rax,qword ptr [NETIO!gWfpGlobal (fffff804`3226c560)]fffff804`32213866 c7809001000000040000 mov dword ptr [rax+190h],400hfffff804`32213870 e81f000000      call    NETIO!InitDefaultCallout (fffff804`32213894)fffff804`32213875 488bd8          mov     rbx,raxfffff804`32213878 4885c0          test    rax,raxfffff804`3221387b 0f857b480100    jne     NETIO!FeInitCalloutTable+0x148f8 (fffff804`322280fc)fffff804`32213881 488bc3          mov     rax,rbxfffff804`32213884 4883c420        add     rsp,20hfffff804`32213888 5b              pop     rbxfffff804`32213889 c3              ret```
```fffff804`3221380a 488b054f8d0500  mov     rax,qword ptr [NETIO!gWfpGlobal (fffff804`3226c560)] 这行是我们上面的gWfpGlobal全局变量地址fffff804`32213866 c7809001000000040000 mov dword ptr [rax+190h],400h 这行gWfpGlobal+190h 保存的是整个数组(callout)个数fffff804`32213853 488b8998010000  mov     rcx,qword ptr [rcx+198h] 这行gWfpGlobal+198h 保存的是数组(callout)起始地址```

到这里我们确定了callout信息保存的地址跟他具体实际的地址与数组个数,我们还有一个问题就是得知道这个数组里面的每一个成员的大小,其实就是一个结构体数组。

第四步反汇编InitDefaultCallout函数。

```u NETIO!InitDefaultCalloutffff804`3221388b cc              int     3fffff804`3221388c cc              int     3fffff804`3221388d cc              int     30: kd> dp ffffdd8b`5aae9050+198 L1ffffdd8b`5aae91e8  ffffdd8b`586dc0000: kd> u NETIO!InitDefaultCallout L20NETIO!InitDefaultCallout:fffff804`32213894 4053            push    rbxfffff804`32213896 4883ec20        sub     rsp,20hfffff804`3221389a 4c8d057f960500  lea     r8,[NETIO!gFeCallout (fffff804`3226cf20)]fffff804`322138a1 ba57667043      mov     edx,43706657hfffff804`322138a6 b950000000      mov     ecx,50hfffff804`322138ab e85005feff      call    NETIO!WfpPoolAllocNonPaged (fffff804`321f3e00)fffff804`322138b0 488bd8          mov     rbx,raxfffff804`322138b3 4885c0          test    rax,raxfffff804`322138b6 0f8556480100    jne     NETIO!InitDefaultCallout+0x1487e (fffff804`32228112)fffff804`322138bc 488b0d5d960500  mov     rcx,qword ptr [NETIO!gFeCallout (fffff804`3226cf20)]fffff804`322138c3 448d4050        lea     r8d,[rax+50h]fffff804`322138c7 33d2            xor     edx,edxfffff804`322138c9 e8b27a0000      call    NETIO!memset (fffff804`3221b380)fffff804`322138ce 488b0d4b960500  mov     rcx,qword ptr [NETIO!gFeCallout (fffff804`3226cf20)]fffff804`322138d5 488d0594ca0200  lea     rax,[NETIO!FeDefaultClassifyCallback (fffff804`32240370)]fffff804`322138dc c70104000000    mov     dword ptr [rcx],4fffff804`322138e2 488b0d37960500  mov     rcx,qword ptr [NETIO!gFeCallout (fffff804`3226cf20)]fffff804`322138e9 c7410401000000  mov     dword ptr [rcx+4],1fffff804`322138f0 488b0d29960500  mov     rcx,qword ptr [NETIO!gFeCallout (fffff804`3226cf20)]fffff804`322138f7 48894110        mov     qword ptr [rcx+10h],raxfffff804`322138fb 488d0daeca0200  lea     rcx,[NETIO!FeDefaultClassifyCallbackFast (fffff804`322403b0)]fffff804`32213902 488b0517960500  mov     rax,qword ptr [NETIO!gFeCallout (fffff804`3226cf20)]fffff804`32213909 48894828        mov     qword ptr [rax+28h],rcxfffff804`3221390d 488d0d4c8fffff  lea     rcx,[NETIO!FeDefaultNotifyCallback (fffff804`3220c860)]fffff804`32213914 488b0505960500  mov     rax,qword ptr [NETIO!gFeCallout (fffff804`3226cf20)]fffff804`3221391b 48894818        mov     qword ptr [rax+18h],rcxfffff804`3221391f 488b05fa950500  mov     rax,qword ptr [NETIO!gFeCallout (fffff804`3226cf20)]fffff804`32213926 81483040030000  or      dword ptr [rax+30h],340hfffff804`3221392d 488bc3          mov     rax,rbxfffff804`32213930 4883c420        add     rsp,20h```
```fffff804`322138a6 b950000000      mov     ecx,50h 这一行我们能确实下来成员类型大小```

现在我们获取了我们想要的全部信息,直接用windbg命令来遍历注册的所有callout函数。(实际这个数组是动态变化的,也就是说你注册callout的时候他会动态增大内存来保存你的函数,默认大小是0x50*0x400=0x14000)。

直接遍历命令

```r $t0=poi(poi(netio!gWfpGlobal)+198);.for ( r $t1=0; @$t1 < 400; r $t1=@$t1+1 ) {r $t1;dps @$t0+2*@$ptrsize L3; r $t0=@$t0+50;}```

遍历wfp(防火墙)的callouts过滤处理函数

相关视频教程

遍历wfp(防火墙)的callouts过滤处理函数

更多详细内容添加作者微信

遍历wfp(防火墙)的callouts过滤处理函数

本周天终端安全开发直播,带你走进智能终端安全!扫码进群。

遍历wfp(防火墙)的callouts过滤处理函数

直播内容 本周天终端安全开发直播,带你走进智能终端安全!

遍历wfp(防火墙)的callouts过滤处理函数

原文始发于微信公众号(安全狗的自我修养):遍历wfp(防火墙)的callouts过滤处理函数

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年4月23日05:40:52
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   遍历wfp(防火墙)的callouts过滤处理函数https://cn-sec.com/archives/2088368.html

发表评论

匿名网友 填写信息