« たぶんの検索ができるよ、たぶん | トップページ | どこでも検索 »

パケット採取ツールでも載せておこうか

まだ頭が冷え切らないうちに、変信(変な返信のことであり、回答になってない)が来たので、検証の続きはもうしばらくあとにする。とりあえず、ダダ漏れ検証に使ったパケット解析ツールでも載せておこうかと思うのだが、ファイルアップロードするためだけに管理ページに入るのは嫌なので、VC++用のコードを直接コピーしておく。

ただし、きれいなコードとは言えないし、コメントもないし、バグがあるかも知れないからそのあたりは個人で楽しむ範囲で。
あと、悪用しちゃ、「だめ、絶対」。

コードを読むにはC++と、ソケットとスレッドの基礎知識があると良いと思われる。

はじめに、SapporoWorksの中の人に敬意を表しておきたい。
たいへん参考になりました。

じゃ、一気に載せちゃうぞ。

// Special Thanks : SapporoWorks http://homepage2.nifty.com/spw/tips/PacketDump.html
#include "stdafx.h" // プリコンパイルヘッダを使わない場合不要
#include <stdio.h>
#include <tchar.h>
#include <conio.h>
#include <process.h>
#include "winsock2.h"
#pragma comment(lib, "ws2_32.lib")
#ifdef _DEBUG
#define dprintf_s printf_s
#else
#define dprintf_s
#endif
char *Protocol[]={
    "Reserved",     //  0
    "ICMP",         //  1
    "IGMP",         //  2
    "GGP",          //  3
    "IP",           //  4
    "ST",           //  5
    "TCP",          //  6
    "UCL",          //  7
    "EGP",          //  8
    "IGP",          //  9
    "BBN-RCC-MON",  // 10
    "NVP-II",       // 11
    "PUP",          // 12
    "ARGUS",        // 13
    "EMCON",        // 14
    "XNET",         // 15
    "CHAOS",        // 16
    "UDP",          // 17
    "MUX",          // 18
    "DCN-MEAS",     // 19
    "HMP",          // 20
    "PRM",          // 21
    "XNS-IDP",      // 22
    "TRUNK-1",      // 23
    "TRUNK-2",      // 24
    "LEAF-1",       // 25
    "LEAF-2",       // 26
    "RDP",          // 27
    "IRTP",         // 28
    "ISO-TP4",      // 29
    "NETBLT",       // 30
    "MFE-NSP",      // 31
    "MERIT-INP",    // 32
    "SEP",          // 33
    "3PC",          // 34
    "IDPR",         // 35
    "XTP",          // 36
    "DDP",          // 37
    "IDPR-CMTP",    // 38
    "TP++",         // 39
    "IL",           // 40
    "SIP",          // 41
    "SDRP",         // 42
    "SIP-SR",       // 43
    "SIP-FRAG",     // 44
    "IDRP",         // 45
    "RSVP",         // 46
    "GRE",          // 47
    "MHRP",         // 48
    "BNA",          // 49
    "SIPP-ESP",     // 50
    "SIPP-AH",      // 51
    "I-NLSP",       // 52
    "SWIPE",        // 53
    "NHRP",         // 54
    "unknown",      // 55
    "unknown",      // 56
    "unknown",      // 57
    "unknown",      // 58
    "unknown",      // 59
    "unknown",      // 60
    "unknown",      // 61
    "CFTP",         // 62
    "unknown",      // 63
    "SAT-EXPAK",    // 64
    "KRYPTOLAN",    // 65
    "RVD",          // 66
    "IPPC",         // 67
    "unknown",      // 68
    "SAT-MON",      // 69
    "VISA",         // 70
    "IPCV",         // 71
    "CPNX",         // 72
    "CPHB",         // 73
    "WSN",          // 74
    "PVP",          // 75
    "BR-SAT-MON",   // 76
    "SUN-ND",       // 77
    "WB-MON",       // 78
    "WB-EXPAK",     // 79
    "ISO-IP",       // 80
    "VMTP",         // 81
    "SECURE-VMTP",  // 82
    "VINES",        // 83
    "TTP",          // 84
    "NSFNET-IGP",   // 85
    "DGP",          // 86
    "TCF",          // 87
    "IGRP",         // 88
    "OSPFIGP",      // 89
    "Sprite-RPC",   // 90
    "LARP",         // 91
    "MTP",          // 92
    "AX.25",        // 93
    "IPIP",         // 94
    "MICP",         // 95
    "SCC-SP",       // 96
    "ETHERIP",      // 97
    "ENCAP",        // 98
    "unknown",      // 98
    "GMTP"          // 99
    };
#define SIO_RCVALL  0x98000001
#define MAX_IP_SIZE 1024 * 128
class CWPCap32Base
{
private:
    WSADATA wsd;
    CWPCap32Base()
    {
        dprintf_s("%s\n", __FUNCTION__);
        //Ver2.2 でWinSockを初期化する
        WSAStartup(MAKEWORD(2, 2), &wsd);
        socket_address_list = NULL;
        socket_address_list_count = 0;
        in_addr = NULL;
        // アドレスリストを初期化
        InitSocketAddressList();
    }
    ~CWPCap32Base()
    {
        dprintf_s("%s\n", __FUNCTION__);
        //WinSockの終了処理
        WSACleanup();
        if (socket_address_list != NULL)
        {
            delete[] socket_address_list;
            delete[] in_addr;
            socket_address_list_count = 0;
        }
    }
public:
    static CWPCap32Base& GetInstance()
    {
        static CWPCap32Base instance;
        return instance;
    }
public:
    typedef char char1024[1024];
private:
    char1024 *socket_address_list;
    int socket_address_list_count;
    IN_ADDR *in_addr;
public:
    SOCKET CreateSocket(int no)
    {
        if (no < 0 || no >= socket_address_list_count)
        {
            return INVALID_SOCKET;
        }
        SOCKET sock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
        if (sock == INVALID_SOCKET)
        {
            return INVALID_SOCKET;
        }
        SOCKADDR_IN s_in;
        s_in.sin_addr.s_addr = in_addr[no].s_addr;
        s_in.sin_family = AF_INET;
        s_in.sin_port = htons(0);
        //bind
        if (bind(sock, (SOCKADDR *)&s_in, sizeof(s_in)) == SOCKET_ERROR)
        {
            closesocket(sock);
            return INVALID_SOCKET;
        }
        unsigned int optval = 1;
        DWORD d;
        if (WSAIoctl(sock, SIO_RCVALL, &optval, sizeof(optval), NULL, 0, &d, NULL, NULL) == SOCKET_ERROR)
        {
            closesocket(sock);
            return INVALID_SOCKET;
        }
        return sock;
    }
    char1024* GetSocketAddressList()
    {
        return socket_address_list;
    }
    int GetSocketAddressCount()
    {
        return socket_address_list_count;
    }
    char* GetSocketAddress(int no)
    {
        return (no < 0 || no >= socket_address_list_count) ? NULL : socket_address_list[no];
    }
private:
    void InitSocketAddressList()
    {
        // 消滅時には自動破棄
        class tag_my_socket
        {
        public:
            SOCKET sock;
            tag_my_socket()
            {
                sock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
            }
            ~tag_my_socket()
            {
                if(INVALID_SOCKET != sock)
                {
                    closesocket(sock);
                }
            }
        } my_socket;
        SOCKET sock = my_socket.sock;
        if (INVALID_SOCKET != sock)
        {
            DWORD d;
            char buf[4096];
            if (SOCKET_ERROR != WSAIoctl(sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, buf, 4096, &d, NULL, NULL))
            {
                SOCKET_ADDRESS_LIST *slist = (SOCKET_ADDRESS_LIST *)buf;
                int count = slist->iAddressCount;
                if (count > 0)
                {
                    if (socket_address_list != NULL)
                    {
                        delete[] socket_address_list;
                        delete[] in_addr;
                    }
                    socket_address_list = new char1024[count];
                    in_addr = new IN_ADDR[count];
                    socket_address_list_count = count;
                    for(int i = 0; i < count; i++)
                    {
                        in_addr[i] = ((SOCKADDR_IN *)slist->Address[i].lpSockaddr)->sin_addr;
                        sprintf_s(socket_address_list[i], "%s", inet_ntoa(in_addr[i]));
                    }
                }
            }
        }
    }
};
class CWPCap32
{
private:
    SOCKET sock;
    HANDLE hThread;
    FILE *file;
    unsigned char *buf;
    bool bStop;
    int sno;
public:
    CWPCap32()
    {
        dprintf_s("%s\n", __FUNCTION__);
        bStop = false;
        file = NULL;
        sock = INVALID_SOCKET;
        buf = NULL;
        hThread = NULL;
        sno = -1;
    }
    void Run(int no)
    {
        dprintf_s("%s\n", __FUNCTION__);
        sno = no;
        sock = CWPCap32Base::GetInstance().CreateSocket(no);
        fopen_s(&file, CWPCap32Base::GetInstance().GetSocketAddress(no), "a+t");
        buf = new unsigned char[MAX_IP_SIZE];
        hThread = (HANDLE)_beginthread(CaptureThread, 0, this);
    }
    void Stop()
    {
        dprintf_s("%s\n", __FUNCTION__);
        bStop = true;
        if(hThread != NULL)
        {
            //キャプチャスレッドの破棄
            if(WAIT_TIMEOUT == WaitForSingleObject(hThread, 1000))
            {
                TerminateThread(hThread, 1);
            }
            hThread = NULL;
        }
    }
    ~CWPCap32()
    {
        dprintf_s("%s\n", __FUNCTION__);
        if(hThread != NULL)
        {
            //キャプチャスレッドの破棄
            TerminateThread(hThread, 1);
        }
        if(sock != INVALID_SOCKET)
        {
            closesocket(sock);
        }
        if(file != NULL)
        {
            fclose(file);
        }
        if(buf != NULL)
        {
            delete[] buf;
        }
    }
    static void CaptureThread(void *arg)
    {
        dprintf_s("%s\n", __FUNCTION__);
        WSABUF wsb;
        unsigned long len;
        DWORD Flags;
        CWPCap32 *p = (CWPCap32 *)arg;
        while(!(p->bStop))
        {
            Sleep(1);
            wsb.buf = (char*) (p->buf);
            wsb.len = MAX_IP_SIZE;
            memset(wsb.buf, 0x0, MAX_IP_SIZE);
            Flags = 0;
            //パケット取得
            if(SOCKET_ERROR == WSARecv(p->sock, &wsb, 1, &len, &Flags, NULL, NULL))
            {
                sprintf_s((char *)(p->buf), MAX_IP_SIZE, "WSARecv failed. Code %d", WSAGetLastError());
                p->file_writeline((char *)(p->buf));
                continue;
            }
            //パケット表示
            p->packet_print(p->buf, len);
        }
        dprintf_s("%s exit\n", __FUNCTION__);
        p->hThread = NULL;
        _endthread();
    }
    void packet_print(unsigned char *data, unsigned long len)
    {
        char Buf[10], TmpBuf[1024];
        unsigned char *p;
        int d;
        //unsigned int i,y;
        SYSTEMTIME t;
        GetLocalTime(&t);
        file_writeline("-----------------------------------------------------------");
        sprintf_s(TmpBuf, "%02d/%02d/%02d %02d:%02d:%02d Protocol: %s ", t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond, Protocol[data[9]]);
        file_writeline(TmpBuf);
        sprintf_s(TmpBuf, "Source Address: %d.%d.%d.%d ", data[12], data[13], data[14], data[15]);
        file_writeline(TmpBuf);
        sprintf_s(TmpBuf, "Destination Address: %d.%d.%d.%d", data[16], data[17], data[18], data[19]);
        file_writeline(TmpBuf);
        sprintf_s(TmpBuf, "Source Port: %d  Destination Port: %d", data[20]*256+data[21], data[22]*256+data[23]);
        file_writeline(TmpBuf);
        for(int i = 0; ((__int64)len - (__int64)i * (__int64)16) > (__int64)0; i++)
        {
            p = data + i*16;
            d = len - i*16;
            if (d > 16)
            {
                d = 16;
            }
            sprintf_s(TmpBuf, "%08lx : ", i );
            for (int j=0; j<d; j++)
            {
                sprintf_s(Buf, "%02x ", *(BYTE *)p++ );
                strcat_s(TmpBuf, Buf);
            }
            for (int j=d; j<16; j++)
            {
                strcat_s(TmpBuf,"   ");
            }
            p = data + i*16;
            for (int j = 0; j < d; j++, p++)
            {
                sprintf_s(Buf, "%c", isprint( *p ) ? *p : '.' );
                strcat_s(TmpBuf, Buf);
            }
            file_writeline(TmpBuf);
        }
        sprintf_s(TmpBuf, "%s.%02d.%02d.%02d.%02d.%02d.%02d.%03d",
            CWPCap32Base::GetInstance().GetSocketAddress(sno),
            t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond, t.wMilliseconds);
        file_writeline(TmpBuf);
        FILE *binfile = NULL;
        if(fopen_s(&binfile, TmpBuf, "a+b") == 0)
        {
            fwrite((void *)data, sizeof(unsigned char), len, binfile);
            fclose(binfile);
        }
    }
    void file_writeline(char *line)
    {
        if(file != NULL)
        {
            dprintf_s("%s\n", __FUNCTION__);
            fprintf_s(file, "%s\n", line);
        }
        dprintf_s("tid:%08x %s\n", GetCurrentThreadId(), line);
    }
};
int _tmain(int argc, _TCHAR* argv[])
{
    int count = CWPCap32Base::GetInstance().GetSocketAddressCount();
    CWPCap32 *pc32 = new CWPCap32[count];
    if (pc32 == NULL)
    {
        return -1;
    }
    for(int i = 0; i < count; i++)
    {
        pc32[i].Run(i);
    }
    printf_s("hit any key to stop...\n");
    while(!_kbhit())
    {
        Sleep(1);
    }
    printf_s("stopping...\n");
    for(int i = 0; i < count; i++)
    {
        pc32[i].Stop();
    }
    delete[] pc32;
    return 0;
}

これだけ。

Win32コンソールアプリケーションプロジェクトを用意したら、_tmain関数が含まれるcppファイルの中身を丸ごと置き換えてコンパイルビルドすれば実行ファイルができるはず。

実行するとカレントディレクトリにファイルを吐くので、できればコマンドプロンプト(cmd.exe)で吐いてもいいディレクトリに移動して実行した方がいい。
ファイル名がIPアドレスのものにテキスト化ダンプが書き込まれる。
IPアドレス.時間のファイルは各パケットの生バイナリだけど、msecまで一致している場合には追記になるのでご注意。
#ディレクトリ指定や生バイナリの完全個別ファイル化、ファイル多過ぎ&でか過ぎへの対策など、改良の余地は十分にあり。

止めるには何かキーを押せばいいんだけど、パケット取得スレッドが動いていないと待ちが発生する。
コマンドプロンプトを閉じちゃってもいいと思うけど・・・
#このあたりは、ソケットが受信状態かどうかと終了シグナルハンドルをWaitForMultipleするようにスレッド内の処理を変えれば、ブロック状態を回避して、スマートに解決する方法があるはずだが、忘却。

あと、これはXP以降のOSでしか使えないので、ご注意。
でも、追加ドライバ一切不要ってのは良いと思う。

実行中にどこぞのWEBサイトにでもアクセスすれば、パケットダンプがドバドバ出ること請け合い。
たとえ、SSLでも証明書だけは暗号化されていないので、それっぽいものが確認できて実に興味深い。
メール送受信(POP/SMTP)しても、メール内容丸見えだったり、かなり面白い。
#日本語対応してないので、見ただけで分かるのはメールアドレスくらいだろうけど、それでもPOP時のパスワードなんかは場合によっては丸見えかも知れないよ~

スイッチング機能非搭載の古いハブ使ってたり、VirtualPCのNATとかWindowsマシンでルータ組んでたりする場合は、別マシンの通信とか、通過するパケットを見たりもできる。
要はNICに到達したIPパケットを、ポートバインドしてるかどうかに関わらず採れちゃうわけ。
#別マシン同士の通信パケット見る場合はWindowsファイアウォールを切っておいた方がいいと思われるけど、それだと自分も危険なので、それなりの覚悟を持って。

いろいろ試すと、たとえば敵(誰か)が通信経路上に何か(パケット採取するツールとか)仕掛けていたらって想像すると、中身の暗号化って結構重要だって気づくはず。
こんなに簡単に見えちゃうんだから、それほど非現実的な想像ではないはず。
そして、その想像が想像に過ぎないことを確認する方法ってのは存在しない・・・。

さて、ビルド環境が無いけどって人がいると思う。
VC++はExpress Editionとして無償ダウンロードできるものが使えると思うけど、未確認(すまん、やってみて)。

パケット解析方法はまた今度にする。
#とはいえIPに詳しいわけじゃなくてチョーテキトーな方法だから期待は不要。

|

« たぶんの検索ができるよ、たぶん | トップページ | どこでも検索 »

パソコン・インターネット」カテゴリの記事

趣味」カテゴリの記事

コメント

この記事へのコメントは終了しました。