2017-10-29 30 views
1

私はconstruct 2.8を使用して、いくつかのロスト・ロスト・パスカル・プログラムによって作成されたいくつかのファイルのヘッダーをリバース・エンジニアリングしています。可変長の可変長レコードを解析するPythonの構造

ヘッダーはいくつかの異なるレコードで構成されていますが、そのうちのいくつかはオプションで、順序が固定かどうかはわかりません。例えば

、レコードの2は次のようになります。

header_record_filetype = cs.Struct(
    'record_type'/cs.Int8ub, 
    'file_type'/cs.PascalString(cs.Int16ub), 
    'unknown'/cs.Int8ub 
) 

header_record_user = cs.Struct(
    'record_type'/cs.Int8ub, 
    'user'/cs.PascalString(cs.Int16ub) 
) 

そして、私は半ダース以上を特定しました。

タイプ0のレコードを見つけるまで(またはファイルの最後に達するまで)、パーサーが不明なレコード数のrecord_typeメンバーに基づいて正しいレコードタイプを選択する方法を教えてください。

答えて

0

興味深い課題を選択しました。私はおそらくまた、ヘッダとボディタイプを定義しhttps://github.com/construct/construct/blob/master/construct/examples/formats/executable/elf32.py

、例えば:

header_body_record_filetype = cs.Struct(
    'file_type'/cs.PascalString(cs.Int16ub), 
    'unknown'/cs.Int8ub 
) 

header_body_record_user = cs.Struct(
    'user'/cs.PascalString(cs.Int16ub) 
) 

header_record = cs.Struct(
    'record_type'/cs.Int8ub, 
    'body'/Embedded(IfThenElse(this.record_type == "user", 
     header_body_record_user, 
     header_body_record_filetype, 
    )) 
) 
+0

ええ、私はこれらの行に沿って何かをやりました。私が持っていた問題の1つは、可変長文字列のために各レコードタイプの長さを決定することでした。しかし、Tellを使用する方法を考え出しました。まあ、教えてください:) – MerseyViking

0

また、私はこの1つの情報のように、例を見つけるhttp://construct.readthedocs.io/en/latest/misc.html#conditional

:様々な条件の定義をサポートしていない構築表示されます私はこのようにそれを解決してきました:

header = cs.Struct(
    'record_type'/cs.Int8ub, 
    'record'/cs.Switch(cs.this.record_type, {header_record_type_0x01: header_record_0x01, 
               header_record_type_filename: header_record_filename, 
               header_record_type_filetype: header_record_filetype, 
               header_record_type_user: header_record_user, 
               header_record_type_end: header_record_end, 
               header_record_type_image_metadata: header_record_image_metadata}, 
         default=header_record_end 
         ), 
    'offset'/cs.Tell 
) 

with open(sys.argv[1], 'rb') as f: 
    h = f.read(2048) 
    index = 0 
    record_type = h[index] 

    while record_type != 0: 
     record = header.parse(h[index:]) 
     print(record) 
     index += record.offset 
     record_type = record.record_type 

しかし、それはそれを行うための*最良の方法である場合、私は知りません。

*「最高」の値です。


編集は私がRepeatUntil()ヘルプページの一番下に隠れて構築しました。だから今、私はこれを持っている:

を構築の宣言自然と調和し多くの、よりクリーンで感じ
header = cs.Struct(
    'type'/cs.Enum(cs.Int8ub, 
        file_metadata=0x01, 
        filename=0x02, 
        file_type=0x03, 
        user=0x0A, 
        image_metadata=0x10, 
        end=0xFF), 

    'record'/cs.Switch(cs.this.type, {'file_metadata': header_record_file_metadata, 
             'filename': header_record_filename, 
             'file_type': header_record_filetype, 
             'user': header_record_user, 
             'end': header_record_end, 
             'image_metadata': header_record_image_metadata}), 
    'size'/cs.Tell 
) 

with open(sys.argv[1], 'rb') as f: 
    h = f.read(2048) 
    records = cs.RepeatUntil(lambda obj, lst, ctx: obj.type == 'end', header).parse(h) 
    print(records) 

関連する問題