本周天终端安全开发直播,带你走进智能终端安全!
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版本做试验
第一步用windbg挂载上内核加载符号(如果没有驱动开发基础可以到最后联系作者学习)。
第二步通过逆向分析(详细逆向分析视频教程到最后联系作者学习)确定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 L20
ffff804`32213935 c3 ret
0: kd> u netio!FeInitCalloutTable L20
NETIO!FeInitCalloutTable:
fffff804`32213804 4053 push rbx
fffff804`32213806 4883ec20 sub rsp,20h
fffff804`3221380a 488b054f8d0500 mov rax,qword ptr [NETIO!gWfpGlobal (fffff804`3226c560)]
fffff804`32213811 0f57c0 xorps xmm0,xmm0
fffff804`32213814 ba57667043 mov edx,43706657h
fffff804`32213819 b900400100 mov ecx,14000h
fffff804`3221381e 0f118090010000 movups xmmword ptr [rax+190h],xmm0
fffff804`32213825 4c8b05348d0500 mov r8,qword ptr [NETIO!gWfpGlobal (fffff804`3226c560)]
fffff804`3221382c 4981c098010000 add r8,198h
fffff804`32213833 e8c805feff call NETIO!WfpPoolAllocNonPaged (fffff804`321f3e00)
fffff804`32213838 488bd8 mov rbx,rax
fffff804`3221383b 4885c0 test rax,rax
fffff804`3221383e 0f85b8480100 jne NETIO!FeInitCalloutTable+0x148f8 (fffff804`322280fc)
fffff804`32213844 488b0d158d0500 mov rcx,qword ptr [NETIO!gWfpGlobal (fffff804`3226c560)]
fffff804`3221384b 33d2 xor edx,edx
fffff804`3221384d 41b800400100 mov r8d,14000h
fffff804`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],400h
fffff804`32213870 e81f000000 call NETIO!InitDefaultCallout (fffff804`32213894)
fffff804`32213875 488bd8 mov rbx,rax
fffff804`32213878 4885c0 test rax,rax
fffff804`3221387b 0f857b480100 jne NETIO!FeInitCalloutTable+0x148f8 (fffff804`322280fc)
fffff804`32213881 488bc3 mov rax,rbx
fffff804`32213884 4883c420 add rsp,20h
fffff804`32213888 5b pop rbx
fffff804`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!InitDefaultCallout
ffff804`3221388b cc int 3
fffff804`3221388c cc int 3
fffff804`3221388d cc int 3
0: kd> dp ffffdd8b`5aae9050+198 L1
ffffdd8b`5aae91e8 ffffdd8b`586dc000
0: kd> u NETIO!InitDefaultCallout L20
NETIO!InitDefaultCallout:
fffff804`32213894 4053 push rbx
fffff804`32213896 4883ec20 sub rsp,20h
fffff804`3221389a 4c8d057f960500 lea r8,[NETIO!gFeCallout (fffff804`3226cf20)]
fffff804`322138a1 ba57667043 mov edx,43706657h
fffff804`322138a6 b950000000 mov ecx,50h
fffff804`322138ab e85005feff call NETIO!WfpPoolAllocNonPaged (fffff804`321f3e00)
fffff804`322138b0 488bd8 mov rbx,rax
fffff804`322138b3 4885c0 test rax,rax
fffff804`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,edx
fffff804`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],4
fffff804`322138e2 488b0d37960500 mov rcx,qword ptr [NETIO!gFeCallout (fffff804`3226cf20)]
fffff804`322138e9 c7410401000000 mov dword ptr [rcx+4],1
fffff804`322138f0 488b0d29960500 mov rcx,qword ptr [NETIO!gFeCallout (fffff804`3226cf20)]
fffff804`322138f7 48894110 mov qword ptr [rcx+10h],rax
fffff804`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],rcx
fffff804`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],rcx
fffff804`3221391f 488b05fa950500 mov rax,qword ptr [NETIO!gFeCallout (fffff804`3226cf20)]
fffff804`32213926 81483040030000 or dword ptr [rax+30h],340h
fffff804`3221392d 488bc3 mov rax,rbx
fffff804`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过滤处理函数
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论