Question

Okay so, i am building a utility to monitor filesystem, registry and network activity (process wise; only activity by selected processes). I have accomplished the filesystem and registry activity part by developing a minifilter driver. However, i am uncertain as to how should i do it for the network. What i want to do is much like what sysinternal's TCPView does, however i only want to monitor ESTABLISHED connections by the selected processes. Here is what i want to get in real time for each connection:

-protocol (TCP or UDP)

-source port

-remote IP and port

-[optional] amount of bytes transferred on a particular connection from the time that the monitoring started

What should i use? i heard about LSPs, but reading into it a bit further i realized that it is VERY difficult to write proper functioning LSPs, not to mention that there is hardly any material available for them to learn from scratch. Also that they are becoming obsolete. Problem is that i only have about 2-3 weeks of time to learn+write this module. Due to the time limit i certainly don't want to go for something like WFP, unless there is a very good tutorial for it out there, and i am not talking about the MSDN documentation. I don't know if this could be 'easily' done using NDIS etc.

Anyhow, so what should i do, where should i focus my efforts. Should i take the risk with learning about the LSPs, or would NDIS accomplish the task, or something else. I am kind of clueless right now. Help me out here!

Was it helpful?

Solution

Look at GetExtendedTcpTable and GetExtendedUdpTable. These APIs will get you most of what you need. But just to keep things interesting, the demo code I wrote uses GetTcp6Table2 instead.

#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE

#include <windows.h>
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <iphlpapi.h>
#include <Tcpestats.h>
#include <Tcpmib.h>
#include <Mstcpip.h>
#include <stdlib.h>
#include <stdio.h>

#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")

PCWSTR
StringFromState(MIB_TCP_STATE State)
{
    switch (State)
    {
        case MIB_TCP_STATE_CLOSED:
            return L"CLOSED";
        case MIB_TCP_STATE_LISTEN:
            return L"LISTEN";
        case MIB_TCP_STATE_SYN_SENT:
            return L"SYN_SENT";
        case MIB_TCP_STATE_SYN_RCVD:
            return L"SYN_RCVD";
        case MIB_TCP_STATE_ESTAB:
            return L"ESTAB";
        case MIB_TCP_STATE_FIN_WAIT1:
            return L"FIN_WAIT1";
        case MIB_TCP_STATE_FIN_WAIT2:
            return L"FIN_WAIT2";
        case MIB_TCP_STATE_CLOSE_WAIT:
            return L"CLOSE_WAIT";
        case MIB_TCP_STATE_CLOSING:
            return L"CLOSING";
        case MIB_TCP_STATE_LAST_ACK:
            return L"LAST_ACK";
        case MIB_TCP_STATE_TIME_WAIT:
            return L"TIME_WAIT";
        case MIB_TCP_STATE_DELETE_TCB:
            return L"DELETE_TCB";
        default:
            return L"[Unknown]";
    }
}

LPWSTR (NTAPI *pRtlIpv6AddressToStringW)(const IN6_ADDR *, LPWSTR);

int __cdecl main()
{
    ULONG r;

    // We need to load this dynamically, because ntdll.lib doesn't export it
    HMODULE ntdll = LoadLibrary(L"ntdll");
    pRtlIpv6AddressToStringW = (decltype(pRtlIpv6AddressToStringW))GetProcAddress(ntdll, "RtlIpv6AddressToStringW");

    // Initial guess for the table size
    ULONG cbTable = 100;
    MIB_TCP6TABLE2 *table = nullptr;
    while (true)
    {
        table = (MIB_TCP6TABLE2*)malloc(cbTable);
        if (!table)
            return 1;
        r = GetTcp6Table2(table, &cbTable, FALSE);
        if (ERROR_INSUFFICIENT_BUFFER == r)
        {
            // Try again with bigger buffer
            free(table);
            continue;
        }
        else if (ERROR_SUCCESS == r)
        {
            break;
        }
        else
        {
            free(table);
            wprintf(L"GetTcp6Table2 = %u\n", r);
            return 1;
        }
    }

    // Print table heading
    wprintf(L"%56s %56s %10s %6s\n", L"Local endpoint", L"Remote endpoint", L"State", L"PID");
    for (ULONG i = 0; i < table->dwNumEntries; i++)
    {
        MIB_TCP6ROW2 const &entry = table->table[i];

        WCHAR localAddr[46];
        WCHAR remoteAddr[46];
        pRtlIpv6AddressToStringW(&entry.LocalAddr, localAddr);
        pRtlIpv6AddressToStringW(&entry.RemoteAddr, remoteAddr);

        WCHAR localEndpoint[56];
        WCHAR remoteEndpoint[56];
        swprintf_s(localEndpoint,  L"[%s]:%-5u", localAddr,  ntohs(entry.dwLocalPort));
        swprintf_s(remoteEndpoint, L"[%s]:%-5u", remoteAddr, ntohs(entry.dwRemotePort));

        wprintf(L"%56s %56s %10s %6u\n",
                localEndpoint, remoteEndpoint,
                StringFromState(entry.State),
                entry.dwOwningPid);
    }

    free(table);
    return 0;
}

Example output (actual addresses anonymized):

C:\>test.exe
                              Local endpoint                              Remote endpoint     State  PID
                                  [::]:80                                      [::]:0        LISTEN    4
                                  [::]:135                                     [::]:0        LISTEN  980
                                  [::]:445                                     [::]:0        LISTEN    4
                                  [::]:1025                                    [::]:0        LISTEN  692
[2001:xxxx:x:xxx:x:xxxx:xxx.xx.xxx.xx]:6044                 [xxxx:xxx:xxxx:xxxx::x]:443       ESTAB 3248
[2001:xxxx:x:xxx:x:xxxx:xxx.xx.xxx.xx]:6045                 [xxxx:xxx:xxxx:xxxx::x]:443       ESTAB 3248
  [2001:xxxx:xx:x:xxxx:xxxx:xxxx:xxxx]:53759 [2001:xxxx:xx:xxxx:xxx:xxxx:xxxx:xxxx]:135   TIME_WAIT    0

OTHER TIPS

Sounds to me like you want something like winpcap which is what wireshark uses.

http://www.winpcap.org/

Also the netstat code from ReactOS might be interesting

http://doxygen.reactos.org/dd/d3f/netstat_8c_source.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top