zoukankan      html  css  js  c++  java
  • Win64 驱动内核编程-16.WFP网络监控驱动(防火墙)

    WFP驱动监控网络

        WFP 是微软推出来替代 TDI HOOKNDIS 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!
    ");
    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
    ",
             (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,看上面图片输出。

     

  • 相关阅读:
    20155313 杨瀚 《网络对抗技术》实验九 Web安全基础
    20155313 杨瀚 《网络对抗技术》实验八 Web基础
    20155313 杨瀚 《网络对抗技术》实验七 网络欺诈防范
    20155313 杨瀚 《网络对抗技术》实验六 信息搜集与漏洞扫描
    20155313 杨瀚 《网络对抗技术》实验五 MSF基础应用
    20155313 杨瀚 《网络对抗技术》实验四 恶意代码分析
    20155313 杨瀚 《网络对抗技术》实验三 免杀原理与实践
    20155313 杨瀚 《网络对抗技术》实验二 后门原理与实践
    20155313 杨瀚 《网络对抗技术》实验一 PC平台逆向破解(5)M
    20155313 2017-2018-1 《信息安全系统设计基础》课程总结
  • 原文地址:https://www.cnblogs.com/csnd/p/12062015.html
Copyright © 2011-2022 走看看