コンテンツにスキップ

Structure — バイナリ DSL

技術目次へ戻る

ほぼすべての Windows プロトコル PDU は impacket.structure.Structure の サブクラスです。SMB、NTLM、DPAPI、PAC の一部、TDS、レジストリ hive など、 ASN.1 / NDR 以外の固定レイアウトはここに集約されています。

struct.pack / unpack を、順序付きフィールド宣言へ持ち上げたものです。 フィールド順が wire 順です。辞書では宣言できません。

サブクラスは次の 2 つのクラス属性を持ちます。

属性意味
commonHdr親と共有する先頭フィールド。継承で使う
structure本体フィールド。サブクラスが再定義すると 親の structure は置き換わる

各フィールドは (name, format) または (name, format, third) です。 third は : フィールドのネストクラス、または _ フィールドの unpack 用 eval 文字列です。

class Example(Structure):
structure = (
('Magic', '"SMB'),
('Count', '<H-Data'),
('Data', ':'),
)
  • getData() が commonHdr + structure を順に pack し、alignment があれば 各フィールド後にパディングします。
  • fromString(data) は同じ順で unpack し、pack サイズ + alignment だけ バッファを進めます。
  • __setitem__ はキャッシュ self.data を無効化します。次の getData() で 再計算されます。

既定エンコーディングは ENCODING = 'latin-1' です。

指定意味
struct のコード (<H, !L, 16s など)1 フィールド 1 値。'Hl' のように複数値をまとめてはいけない
:生バイト、ネスト Structure、または getData() を持つオブジェクト。長さ指定が無いと残り全部
zASCIIZ
uUTF-16LE。偶数境界の \x00\x00 で終端
wNDR 文字列マクロ (MaxCount, Offset, ActualCount, data)
'xxxx / "xxxxリテラル。unpack 時も一致必須
?-field名前付きフィールドの長さ。例: '<H-Data'
?1*?2配列。個数は ?1(定数可)。?1 が空なら残り全部
_pack しない。第 3 引数があれば unpack 時に eval
?=pythonpack 時にフィールド文脈で eval した結果を pack
?&fieldnameオプションポインタ。0 なら対象フィールドを skip
%...printf 風。pack のみ。unpack できない

'-field' による長さ指定は、可変長 : を安全に切るための標準パターンです。 SMB2 の SMB2SessionSetup は _ と SecurityBufferLength で同じことをします。

フィールドをマージするヘルパーはありません。親のレイアウトを残すなら 共有部分を commonHdr に置き、子は structure だけを足します。 ネストは ('inner', ':', InnerClass) です。

SMB1 では AsciiOrUnicodeStructure (smb.py) が FLAGS2_UNICODE に応じて UnicodeStructure / AsciiStructure を選びます。

  • フィールド順 = wire 順。途中挿入は後方互換を壊します。
  • : は長さフィールドが無いと残り全部を飲みます。
  • u の終端は偶数オフセットに置く必要があります。
  • '<L=0' のような既定値は pack 時 eval であり、コンストラクタ初期値ではありません。
  • alignment はフィールドごとに効きます。NDR の alignment 規則とは別物です。

プロトコル固有の配列・ポインタ・conformant 構造は NDR 側を使います。Structure を NDR CALL の代わりに 使わないでください。