このドキュメントを読んでいる間https://wiki.wireshark.org/CaptureFilters私はこの行を見つけました:
tcp[((tcp[12:1] & 0xf0) >> 2):4]
TCPヘッダーの長さを計算しますが、それが実際にどのように機能するか(詳細)はわかりません。
誰かがそれを説明できますか?
これを「HTTP GETリクエストのキャプチャ」フィルタの例からプルしたと思います。
まず、いくつかの表記法:
var[n]
は、varのn番目のバイトを意味します。var[n,c]
は、オフセットnから始まるcバイトのvarを意味します。 var[3:4]
は、varのバイト3、4、5、6を返します。&
は bitwise AND演算です。>>
は、ビット単位の右シフトを意味します。それで、私たちは何を持っていますか?
tcp[((tcp[12:1] & 0xf0) >> 2):4]
これを個別の部分に分解してみましょう。
tcp[12:1]
は、オフセット12でTCP=セグメント(つまり、ヘッダーを含むパケット)の1バイトを取得します。 構造 から、オフセット12(0xC)がデータオフセットフィールド。その定義は次のとおりです。
データオフセット(4ビット)は、TCPヘッダーのサイズを32ビットワードで指定します。最小サイズのヘッダーは5ワード、最大サイズは15ワードなので、最小サイズは20バイトで、ヘッダーで最大40バイトのオプションを許可する最大60バイト。このフィールドは、TCPセグメントの開始から実際のセグメントまでのオフセットでもあるという事実からその名前を取得しますデータ。
うんいいね。ただし、このフィールドは4ビットのみであり、tcp[12:1]
はバイト全体(8ビット)をとります。最初の4つだけが必要です。
tcp[12:1] & 0xf0
はそのデータオフセットバイトを受け取り、定数0xF0を使用してビットごとのAND演算を適用します。これは、masking演算としてよく知られています。これは、定数のビットが0に設定されると、出力でもゼロに設定されるためです。これをバイナリで考えると簡単です。 0xF0は11110000であり、x & 0
任意のビットに対して、xは常に0であり、x & 1
任意のビットxは常にxであり、0xF0のゼロビットは「スイッチオフ」またはmask指定されたビットになりますが、一人で休む。この場合、想像するとtcp[12:1]
は10110101です。最後の4ビットがゼロにマスクされるため、結果は10110000になります。ここでの考え方は、データオフセットフィールドの長さは4ビットしかないため、8ビットなので、無関係なビットをマスクして最初の4ビットだけにするというものです。
ここでの問題は、数値的に言えば、4ビットがバイトの「トップ」側にあるということです。つまり、1101(データオフセットビット)だけではなく、11010000になります。データオフセットフィールドの「生の」値を取得したいだけの場合は、4桁右シフトします。 10110000 >> 4 = 1101
、つまり「下」の4ビットを破棄し、上4ビットを右にシフトします。ただし、この場合、フィルターは4桁ではなく2桁だけシフトします。
これは、データオフセットフィールドの定義に戻って参照したい場所です。これは、ヘッダーのサイズをバイトではなく32ビットワードで指定します。 。したがって、バイト単位でヘッダーの長さを知りたい場合は、4を掛ける必要があります。結局のところ、ビット単位の左シフト1は、数値に2を掛けることと同じであり、ビット単位の左シフト2のシフトは、数値に4を掛けることと同じです。
これを、これまでに見たものと組み合わせます:>> 4
は、データオフセットの生の値を取得したい場合にフィルターで意味を成しますが、それを4で乗算します。これは、左シフトと同等です(<< 2
)、その右シフトの一部をキャンセルし、>> 2
。
そう、 (tcp[12:1] & 0xf0) >> 2
は、データオフセットフィールドを抽出し、4を掛けて、TCPヘッダーのバイト単位のサイズを取得します。
しかし、待ってください、まだまだあります! 。指定したフィルターで、さらに1つの操作を実行する必要があります。
tcp[((tcp[12:1] & 0xf0) >> 2):4]
中間変数を使用すると、これは簡単に確認できます。
$offset = ((tcp[12:1] & 0xf0) >> 2)
tcp[$offset:4]
これが行うことは、最初の4バイトを取得することです後TCPヘッダー、つまりペイロードの最初の4データバイトこれをプルしたフィルターで、このフィルターを使用してHTTP GETリクエストを探していました。
port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420
0x47455420
定数は、実際にはASCII GET
のバイト数(その最後の文字はスペース))の数値エンコーディングで、ASCII値それらの文字の0x47、0x45、0x54、0x20です。
それで、これはどのように完全に機能しますか? TCPヘッダーから4ビットのデータオフセットフィールドを抽出し、4を掛けてヘッダーのサイズをバイト単位で計算します(これもデータへのオフセットです)。次に4を抽出します。このオフセットのバイトを使用してデータの最初の4バイトを取得します。次に、これを「GET」と比較して、HTTP GETであることを確認します。