mones2/06.5.RawSocketを試す


Top / mones2 / 06.5.RawSocketを試す

これは何か

RawSocketを試します。
使うかどうかは分かりません。

ここまでの成果

たまにはハッカーっぽく、Binary 2.0っぽい記事を書こう。

Windows 2000/XPでは、RawSocketという仕組みが用意されていて、パケットをかなり自由に受信したり・送信することができます。

RawSocketでは、いわゆる「生パケット」が扱えるのです。

悪い言い方をすると、パケットを覗きみたり、パケットを偽装することも可能ということになります。

以前までは、ドライバレベルでコーディングしないとできなかったようなのですが、WinSock 2.2以降では、これがとても簡単にできます。

今日は、これを利用して簡単なパケットモニタツールを作ってみようと思います。

ビルドは cygwin+mingwです。

大きな流れは以下のとおりです。

  1. Socketの初期化
  2. IPアドレスの取得(必須ではありません)
  3. バインド
  4. プロミスキャスモードに設定
  5. 受信

では1つずつ見ていきましょう 1.Socketの初期化

   // Socket初期化
   if (INVALID_SOCKET == (this->socket = ::socket(AF_INET, SOCK_RAW, IPPROTO_IP)))
   {
       TRACE("INVALID_SOCKET\n");
       return false;
   }

2. IPアドレスの取得

Windowsは、複数のIPアドレスを持っている可能性があるので、そのIPアドレスを列挙します。

なお今回は、1個目に見つかったアドレスを使用するようにしています。

GUIであれば、IPアドレスを選択できるようにするのもよいでしょう。

   SOCKET_ADDRESS_LIST* addressList;
   DWORD d;
   char buffer[1024];

   // アダプタの列挙
   if (WSAIoctl(this->socket, SIO_ADDRESS_LIST_QUERY, NULL, 0, buffer, 1024, &d, NULL, NULL) != 0)
   {
       TRACE("INVALID_SOCKET\n");
       return 0;
   }

   addressList = (SOCKET_ADDRESS_LIST*)buffer;

   if (addressList->iAddressCount == 0)
   {
       TRACE("address not found\n");
       return 0;
   }

   // 1番目のアドレスを使う(手抜き)
   return ((SOCKADDR_IN*)addressList->Address[0].lpSockaddr)->sin_addr.s_addr;

3.バインド

2.で取得したアドレスを元にbind()

   // bind
   SOCKADDR_IN addr_in;
   addr_in.sin_addr.s_addr = this->GetIPAddress(); // IPアドレス
   addr_in.sin_family      = AF_INET;              // IPv4
   addr_in.sin_port        = htons(0);             // 0で初期化らしい
   if (SOCKET_ERROR == bind(this->socket, (SOCKADDR*)&addr_in, sizeof(addr_in)))
   {
       TRACE("bind error\n");
       return false;
   }

4.プロミスキャスモードに設定

NIC(ネットワークインターフェースカード)は、通常自分宛でないパケットは破棄するようになっていますが、プロミスキャスモードという動作モードに設定可能で、これをすると自分宛以外のパケットも受信できるようになります。

今回はパケットモニターを作っているのでこのモードに設定します。

   // プロミスキャスモードの設定
   #define SIO_RCVALL _WSAIOW(IOC_VENDOR, 1)
   unsigned long optval=1; //PROMISC
   if (SOCKET_ERROR != WSAIoctl(this->socket, SIO_RCVALL, &optval, sizeof(optval), NULL, 0, &d, NULL, NULL))
   {
       TRACE("SIO_RCVALL\n");
       return false;
   }

5.受信

いよいよ受信です。WSARecv関数を使用して受信します。

なお今回はブロックモードで受信しています。

ブロックモードとは、パケットがくるまでスレッドがブロックされるモードのことです。

要は、パケット到着まで他の作業はできません。

   unsigned long length;
   unsigned long flags = 0;
   WSABUF wsb;
   wsb.buf = (PTCHAR)this->readBuffer;
   wsb.len = MAX_RECV_SIZE;
   ZeroMemory(wsb.buf, wsb.len);

   if (SOCKET_ERROR == WSARecv(this->socket, &wsb, 1, &length, &flags, NULL, NULL))
   {
       TRACE("RECIEVE ERROR\n");
       return false;
   }

パケットモニタ

上記手順を踏めば、ほんの100行足らずでパケットを受信することができてしまいます。

今回は、この処理を抽象化して以下のように使えるようにしてみました。

RawSocketクラスのインスタンスに対して、Open/Read/Closeするだけです。

int main(int argc, char *argv[])
{
   byte buffer[1024];
   dword length;
   RawSocket socket;

   if (!socket.Open()) {
       printf("Socket Open Error\n");
       return -1;
   }

   for (int i = 0; i < 3; i++)
   {
       printf("\nWaiting for Packet...\n");
       socket.Read(buffer, 1024, &length);

       IP::Header* header = (IP::Header*)buffer;

       printf("protocol number %x\n", header->prot);
       printf("source   address ");
       printAddress(header->srcip);

       printf("dest     address ");
       printAddress(header->dstip);

       printf("data     ");
       for (int j = 0; j < 10; j++)
       {
           printf("%02x ", header->data[j]);
       }
       printf("\n");
   }

   if (!socket.Close()) {
       printf("Socket Close Error\n");
       return -1;
   }

   return 0;
}

実際に動作させると

Waiting for Packet... protocol number 1 source address 192.168.11.2 dest address 192.168.11.2 data 00 00 61 ffffffce 6c 0e 05 00 3c ffffff86

こんな感じでパケットの中身を読むことができます。

プロトコルごとにさらに詳しく解析するといろいろと楽しいことができそうですね。

ソースとか

ソースと実行ファイルを置いておきます。

使用は自己責任でお願いします。実行ファイルは管理者権限でないと動作しないと思います。

rawsocket.zip

資料

はてなブックマーク - higeponのブックマーク

あとがき

この試みはもちろんMonaのネットワーク対応の一環です。

つい調子に乗って勢いで書いてしまいました。

次は、パケット送信にチャレンジしようと思っていますが、需要が少ないためか受信に比べて資料が少ないようです。

コメント

コメントはありません。 コメント/mones2/06.5.RawSocketを試す?

お名前:

MENU

now: 2

リンク


最新の20件
2018-05-03 2017-09-29 2017-04-25 2017-01-10 2016-12-11 2016-10-04 2016-08-14 2016-06-05 2016-05-29 2016-04-15 2015-12-28 2013-02-25 2013-02-21 2013-02-20 2013-02-12 2013-02-11 2013-02-10
最新の20件
2010-02-01 2010-01-31 2010-01-30 2010-01-29 2010-01-16

Counter: 3937, today: 1, yesterday: 0

添付ファイル: filerawsocket-20051126.zip 767件 [詳細] filerawsocket-20051125.zip 464件 [詳細] filerawsocket.zip 1049件 [詳細]

リロード   新規 編集 凍結 差分 添付 複製 改名   トップ 一覧 検索 最終更新 バックアップ   ヘルプ   最終更新のRSS

Last-modified: 2008-03-28 (金) 15:48:00 (3794d);  Modified by mona
PukiWiki 1.4.6 Copyright © 2001-2005 PukiWiki Developers Team. License is GPL.
Based on "PukiWiki" 1.3 by yu-ji
Powered by PHP 5.2.17
HTML convert time to 0.067 sec.