2016年8月31日星期三

枚举ALE的endpoints

/*
目的:演示FwpsAleEndpointEnum的用法。
注意:编译的平台和运行的平台。
说明:Ale的Endpoint,这是什么呢?
      类似TCPView.exe不停的显示和更新,
      当然这个函数每次获取的值/数量也是不同的。

made by correy
made at 2016.08.31.
homepage:http://correy.webs.com
*/

#include <ntifs.h>
#include <windef.h>
#include <ntddk.h>
#include <ntstrsafe.h>
#include <Fwpsk.h>
#include <initguid.h> //静态定义UUID用的,否则:error LNK2001。
#include <Fwpmk.h>
#include <ndis.h>
#include <Wsk.h>
#include <ipmib.h>
#include <netpnp.h>
#include <ntintsafe.h>

#include <intrin.h> //VS2012编译。
#include <immintrin.h>//VS2012编译。
//#include <mmintrin.h> //WDK 编译。
//#include <emmintrin.h>//WDK 编译。
//#include <xmmintrin.h>//WDK 编译。

#pragma warning(disable:4100) //未引用的形参
#pragma warning(disable:4214) //整形以外的位域类型
#pragma warning(disable:4121) //封装要区分成员对齐方式

#define TAG 'test' //test

//https://msdn.microsoft.com/en-us/library/windows/desktop/ms738518%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
//其实:IPV4的只需This buffer should be large enough to hold at least 16 characters.
#define MAX_ADDRESS_STRING_LENGTH   64


wchar_t * get_protocol_name(UINT8 protocol)
{
    wchar_t * protocol_name = 0;

    switch(protocol)
    {
    case IPPROTO_TCP:
        protocol_name = L"TCP";
        break;
    case IPPROTO_UDP:
        protocol_name = L"UDP";
        break;
    case IPPROTO_IPV4:
        protocol_name = L"IPV4";
        break;
    case IPPROTO_IPV6:
        protocol_name = L"IPV6";
        break;
    case IPPROTO_ICMP:
        protocol_name = L"ICMP";
        break;
    case IPPROTO_IGMP:
        protocol_name = L"IGMP";
        break;
    case IPPROTO_ICMPV6:
        protocol_name = L"ICMPV6";
        break;
    default:
        protocol_name = L"未知";//也可打印一个数值。
        break;
    }

    return protocol_name;
}


//DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}


//DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    HANDLE gEngineHandle;
    NTSTATUS Status = STATUS_SUCCESS;
    FWPM_SESSION0 session = {0};
    FWPS_ALE_ENDPOINT_ENUM_TEMPLATE0 enumTemplate;//编译为WIN 7版本,VISTA是没有这个变量的。
    HANDLE enumHandle;
    FWPS_ALE_ENDPOINT_PROPERTIES0 **entries;
    UINT32                        numEntriesReturned;
    UINT32 calloutIndex = 0;
    UNICODE_STRING appId = {0};

    //KdBreakPoint();
    __debugbreak();

    DriverObject->DriverUnload = Unload;

    session.flags = FWPM_SESSION_FLAG_DYNAMIC;
    Status = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &gEngineHandle);
    ASSERT (NT_SUCCESS(Status));

    RtlZeroMemory(&enumTemplate, sizeof(FWPS_ALE_ENDPOINT_ENUM_TEMPLATE0));
    Status = FwpsAleEndpointCreateEnumHandle0(gEngineHandle, &enumTemplate, &enumHandle);//Available starting with Windows 7
    ASSERT (NT_SUCCESS(Status));

    Status = FwpsAleEndpointEnum0(gEngineHandle, enumHandle, 0xFFFFFFFF, &entries, &numEntriesReturned);//Available starting with Windows 7
    ASSERT (NT_SUCCESS(Status));

    KdPrint(("numEntriesReturned:0x%x.\n\n\n", numEntriesReturned));

    for( ; calloutIndex < numEntriesReturned; calloutIndex++)
    {
        KdPrint(("calloutIndex:0x%x.\n",(calloutIndex + 1)));

        if (entries[calloutIndex]->ipVersion == FWP_IP_VERSION_V4)
        {
            UINT32 l4a = RtlUlongByteSwap((ULONG)entries[calloutIndex]->localV4Address);
            UINT32 r4a = RtlUlongByteSwap((ULONG)entries[calloutIndex]->remoteV4Address);
            wchar_t localV4Address[MAX_ADDRESS_STRING_LENGTH] = {0};
            wchar_t remoteV4Address[MAX_ADDRESS_STRING_LENGTH] = {0};

            RtlIpv4AddressToString((const struct in_addr *)&l4a, localV4Address);
            RtlIpv4AddressToString((const struct in_addr *)&r4a, remoteV4Address);

            KdPrint(("ipVersion:FWP_IP_VERSION_V4.\n"));
            KdPrint(("localV4Address:%ws.\n", localV4Address));
            KdPrint(("remoteV4Address:%ws.\n", remoteV4Address));
        }
        else if (entries[calloutIndex]->ipVersion == FWP_IP_VERSION_V6)
        {
            /*
            这个IPV6的地址的字节序需要转换不?
            最大是RtlUlonglongByteSwap,64-bit,但是IPv6 is 128 bits。
            难道要用这个函数两次,两次的也不符合,自己写个函数?自己可以验证下。
            */
            wchar_t localV6Address[MAX_ADDRESS_STRING_LENGTH] = {0};
            wchar_t remoteV6Address[MAX_ADDRESS_STRING_LENGTH] = {0};

            RtlIpv6AddressToString((const struct in6_addr *)&entries[calloutIndex]->localV6Address, localV6Address);
            RtlIpv6AddressToString((const struct in6_addr *)&entries[calloutIndex]->remoteV6Address, remoteV6Address);

            KdPrint(("ipVersion:FWP_IP_VERSION_V6.\n"));
            KdPrint(("localV6Address:%ws.\n", localV6Address));
            KdPrint(("remoteV6Address:%ws.\n", remoteV6Address));
        }
        else
        {
            KdBreakPoint();
        }

        KdPrint(("ipProtocol:%ws.\n", get_protocol_name(entries[calloutIndex]->ipProtocol)));
        KdPrint(("localPort:%d.\n", entries[calloutIndex]->localPort));
        KdPrint(("remotePort:%d.\n", entries[calloutIndex]->remotePort));
        KdPrint(("localTokenModifiedId:0x%x.\n", entries[calloutIndex]->localTokenModifiedId));
        KdPrint(("mmSaId:0x%x.\n", entries[calloutIndex]->mmSaId));
        KdPrint(("qmSaId:0x%x.\n", entries[calloutIndex]->qmSaId));
        KdPrint(("ipsecStatus:0x%x.\n", entries[calloutIndex]->ipsecStatus));
        KdPrint(("flags:0x%x.\n", entries[calloutIndex]->flags));

        appId.Buffer = (PWCH)&entries[calloutIndex]->appId.data[0];
        appId.Length = (USHORT)entries[calloutIndex]->appId.size;
        appId.MaximumLength = appId.Length;
        KdPrint(("appId:%wZ.\n", &appId));//进程的完整路径(NT式的设备路径)。一个特殊是:System。

        KdPrint(("\n"));
    }

    FwpmFreeMemory((VOID**)&entries);
    Status = FwpsAleEndpointDestroyEnumHandle0(gEngineHandle, enumHandle);//Available starting with Windows 7
    ASSERT (NT_SUCCESS(Status));

    FwpmEngineClose0(gEngineHandle);

    return Status;
}

没有评论:

发表评论