예제 #1
0
class TestArray(unittest.TestCase):

    def setUp(self):
        self.c = Array(4, UBInt8("foo"))

    def test_trivial(self):
        pass

    def test_parse(self):
        self.assertEqual(self.c.parse(six.b("\x01\x02\x03\x04")), [1, 2, 3, 4])
        self.assertEqual(self.c.parse(six.b("\x01\x02\x03\x04\x05\x06")),
            [1, 2, 3, 4])

    def test_build(self):
        self.assertEqual(self.c.build([5, 6, 7, 8]), six.b("\x05\x06\x07\x08"))

    def test_build_oversized(self):
        self.assertRaises(ArrayError, self.c.build, [5, 6, 7, 8, 9])

    def test_build_undersized(self):
        self.assertRaises(ArrayError, self.c.build, [5, 6, 7])
예제 #2
0
파일: pe32.py 프로젝트: catlee/construct
        MEMBER_OF_UNION=11,
        UNION_TAG=12,
        TYPE_DEFINITION=13,
        UNDEFINED_STATIC=14,
        ENUM_TAG=15,
        MEMBER_OF_ENUM=16,
        REGISTER_PARAM=17,
        BIT_FIELD=18,
        BLOCK=100,
        FUNCTION=101,
        END_OF_STRUCT=102,
        FILE=103,
        SECTION=104,
        WEAK_EXTERNAL=105,
    ), "number_of_aux_symbols" / Int8ul,
    "aux_symbols" / Array(this.number_of_aux_symbols, Bytes(18)))

coff_header = "coff_header" / Struct(
    Const(b"PE\x00\x00"),
    "machine_type" / Enum(Int16ul,
                          UNKNOWN=0x0,
                          AM33=0x1d3,
                          AMD64=0x8664,
                          ARM=0x1c0,
                          EBC=0xebc,
                          I386=0x14c,
                          IA64=0x200,
                          M32R=0x9041,
                          MIPS16=0x266,
                          MIPSFPU=0x366,
                          MIPSFPU16=0x466,
예제 #3
0
'''
Siemens/Bruker Diffrac-AT Raw Format
 * https://github.com/wojdyr/xylib/blob/master/xylib/brucker_raw.cpp
'''
from __future__ import absolute_import
import numpy as np
from construct import (Padding, Struct, Switch, String, Array, Const, OnDemand,
                       Embedded, Computed, Int32ul, Int16ul, Float64l,
                       Float32l, this, Check)
from .construct_utils import FixedSizeCString

Block_v2 = Struct('header_len' / Int16ul, 'num_steps' / Int16ul, Padding(4),
                  'time_per_step' / Float32l, 'x_step' / Float64l,
                  'x_start' / Float64l, Padding(26), 'temperature' / Int16ul,
                  Padding(this.header_len - 48),
                  'y' / OnDemand(Array(this.num_steps, Float32l)))

RAW_v2 = Struct('num_steps' / Int32ul, Padding(162),
                'date_time_measure' / FixedSizeCString(20),
                'anode_material' / FixedSizeCString(2), 'lambda1' / Float32l,
                'lambda2' / Float32l, 'intensity_ratio' / Float32l, Padding(8),
                'sample_runtime' / Float32l, Padding(42),
                'blocks' / Array(this.num_steps, Block_v2))

Block_v101 = Struct(
    'header_len' / Int32ul, Check(this.header_len == 304),
    'num_steps' / Int32ul, 'start_theta' / Float64l, 'start_2theta' / Float64l,
    Padding(76), 'high_voltage' / Float32l,
    'amplifier_gain' / Float32l, 'discriminator_1_lower_level' / Float32l,
    Padding(64), 'step_size' / Float64l,
    Padding(8), 'time_per_step' / Float32l, Padding(12), 'rpm' / Float32l,
예제 #4
0
#!/usr/bin/python3

from construct import Array, Const, Default, Enum, GreedyRange, Int8ub, Int16ub, Int32ub, Padding, PrefixedArray, String, Struct, Switch, this

# file format from https://reverseengineering.stackexchange.com/questions/4311/help-reversing-a-edb-database-file-for-pioneers-rekordbox-software

AnlzTagPath = Struct(
    "payload_size" / Int32ub,  # is 0 for some tag types
    "path" / String(this.payload_size - 2, encoding="utf-16-be"),
    Padding(2))

AnlzTagVbr = Struct(Padding(4), "idx" / Array(400, Int32ub),
                    "unknown" / Int32ub)

AnlzQuantizeTick = Struct(
    "beat" / Int16ub,
    "bpm_100" / Int16ub,
    "time" / Int32ub  # in ms from start
)

AnlzTagQuantize = Struct(Padding(4), "unknown" / Const(Int32ub, 0x80000),
                         "entries" / PrefixedArray(Int32ub, AnlzQuantizeTick))

AnlzTagQuantize2 = Struct(Padding(4), "u1" / Const(Int32ub, 0x01000002),
                          "entries" / PrefixedArray(Int32ub, AnlzQuantizeTick),
                          "u2" / Int32ub, "u3" / Int32ub, "u4" / Int32ub,
                          "u5" / Int32ub, "u6" / Int32ub, Padding(8))

AnlzTagWaveform = Struct(
    "payload_size" / Int32ub,  # is 0 for some tag types
    "unknown" / Const(Int32ub, 0x10000),
예제 #5
0
Random = Struct(
    "random",
    UBInt32("gmt_unix_time"),
    Bytes("random_bytes", 28),
)

SessionID = Struct(
    "session_id",
    UBInt8("length"),
    Bytes("session_id", lambda ctx: ctx.length),
)

CipherSuites = Struct(
    "cipher_suites",
    UBInt16("length"),  # TODO: Reject packets of length 0
    Array(lambda ctx: ctx.length // 2, UBInt16("cipher_suites")),
)

CompressionMethods = Struct(
    "compression_methods",
    UBInt8("length"),  # TODO: Reject packets of length 0
    Array(lambda ctx: ctx.length, UBInt8("compression_methods")),
)

ServerName = Struct(
    "",
    UBInt8("type"),
    PascalString("name", length_field=UBInt16("length")),
)

SNIExtension = Struct(
예제 #6
0
파일: ai.py 프로젝트: nymanjens/aoc-mgz
"""AI."""

from mgz import Version
from mgz.util import Find
from construct import (Array, Byte, If, Int16ul, Int32sl, Int32ul, Padding,
                       PascalString, Struct, this, IfThenElse)

# pylint: disable=invalid-name

script = "script" / Struct(
    Padding(4), "seq" / Int32sl, "max_rules" / Int16ul, "num_rules" / Int16ul,
    Padding(4),
    Array(
        this.num_rules, "rules" / Struct(
            Padding(12), "num_facts" / Byte, "num_facts_actions" / Byte,
            Padding(2),
            Array(
                16, "data" / Struct("type" / Int32ul, "id" / Int16ul, Padding(
                    2), Array(4, "params" / Int32ul))))))

ai = "ai" / Struct(
    "has_ai" / Int32ul,  # if true, parse AI
    "yep" / If(
        this.has_ai == 1,
        IfThenElse(
            lambda ctx: ctx._.version == Version.DE,
            Find(
                b'\00' * 4096, None
            ),  # The ai structure in DE seems to have changed, for now we simply skip it
            "ais" / Struct(
                "max_strings" / Int16ul,
예제 #7
0
    # 'start'/Tell,
    # OneOf(Computed(this.start == this.data_start), [True]),
    'data_size' / Computed(this.data_end - this.data_start),
    'data' / If(
        this.data_end > this.data_start,
        Switch(
            this.type,
            dict(
                WIP_TAG_LIST=RepeatUntil(
                    lambda obj, ctx: obj.data_end >= ctx.data_end,
                    LazyBound(lambda: WIPTag)),
                WIP_TAG_EXTENDED=Bytes(10),
                WIP_TAG_DOUBLE=Float64l,
                WIP_TAG_FLOAT=Float32l,
                WIP_TAG_INT64=Int64sl,
                WIP_TAG_INT32=Array(this.data_size // 4, Int32sl),
                WIP_TAG_UINT32=Array(this.data_size // 4, Int32ul),
                WIP_TAG_CHAR=Array(this.data_size, Int8ul),
                WIP_TAG_BOOL=Int8ul,
                WIP_TAG_STRING=WIPString,
            ))),
    'end' / Tell,
    # pad to get to data_end
    Padding(this.data_end - this.end),
)

WIPFile = Struct(
    Const(b'WIT_PR06'),  # alternately, "WIT_PRCT"
    'root' / WIPTag,
    # Validate the root name
    OneOf(Computed(this.root.name), ['WITec Project']))
예제 #8
0
    TimeSecAdapter("imperial_time" / Int32sl), "explored_percent" / Byte,
    "research_count" / Byte, "research_percent" / Byte)

society = "society" / Struct(
    "score" / Int16ul,
    "total_wonders" / Byte,
    "total_castles" / Byte,
    "relics_captured" / Byte,
    Padding(1),
    "villager_high" / Int16ul,
)

achievements = "achievements" / Struct(
    "player_name" / Bytes(16),
    "total_score" / Int16ul,
    Array(8, "total_scores" / Int16ul),
    "victory" / Flag,
    "civilization" / Byte,
    "color_id" / Byte,
    "team" / Byte,
    "ally_count" / Byte,
    "random_civ" / Flag,  # never actually set
    "mvp" / Flag,
    Padding(3),
    "result" / Int32ul,
    military,
    Padding(32),
    economy,
    Padding(16),
    technology,
    Padding(1),
예제 #9
0
    Embedded(
        If(lambda ctx: ctx.type != 0,
           Struct("order" / Byte, "flag" / Byte, "count" / Byte))))

static = "static" / Struct(
    "object_type" / Int16ul, "sprite" / Int16ul, "garrisoned_in_id" / Int32sl,
    "hitpoints" / Float32l, "object_state" / Byte, "sleep" / Flag,
    "doppleganger" / Flag, "go_to_sleep" / Flag, "object_id" / Int32ul,
    "facet" / Byte, "x" / Float32l, "y" / Float32l, "z" / Float32l,
    "screen_offset_x" / Int16ul, "screen_offset_y" / Int16ul,
    "shadow_offset_x" / Int16ul, "shadow_offset_y" / Int16ul,
    "selected_group" / If(lambda ctx: find_version(ctx) == Version.AOK, Byte),
    ResourceEnum("resource_type" / Int16sl), "amount" / Float32l,
    "worker_count" / Byte, "current_damage" / Byte, "damaged_lately_timer" /
    Byte, "under_attack" / Byte, "pathing_group_len" / Int32ul, "pathing_group"
    / Array(lambda ctx: ctx.pathing_group_len, "object_id" / Int32ul),
    "group_id" / Int32sl, "roo_already_called" / Byte, "de_static_unk1" /
    If(lambda ctx: find_version(ctx) == Version.DE, Bytes(19)),
    "has_sprite_list" / Byte, "sprite_list" /
    If(lambda ctx: ctx.has_sprite_list != 0,
       RepeatUntil(lambda x, lst, ctx: lst[-1].type == 0, sprite_list)),
    "de_effect_block" / If(
        lambda ctx: find_version(ctx) == Version.DE,
        Struct(
            Padding(4), "has_effect" / Byte, "effect" / If(
                lambda ctx: ctx.has_effect == 1,
                Struct(Padding(3), "length" / Int16ul,
                       "name" / Bytes(lambda ctx: ctx.length),
                       If(lambda ctx: ctx.length > 0, Padding(33)))),
            If(
                lambda ctx: ctx.effect is None or
예제 #10
0
from .genre import Genre
from .key import Key
from .label import Label

# a strange page exists for every (?) page type, header.u9 is 1004 and page is filled with 0xf8ffff1f
StrangePage = Struct(
    "strange_header" / Struct(
        "index" / Int32ul,  # page index (same as header?)
        "next_index" /
        Int32ul,  # index of next page containing real data or 0x3ffffff if next page empty
        Const(0x3fffffff, Int32ul),
        Padding(4),
        "entry_count" / Int16ul,  # number of 4-byte values
        "u2" / Int16ul,  # always 8191?
    ),
    Array(1004, Int32ul),
    Padding(20))

ReverseIndexedEntry = FocusedSeq(
    "entry",
    "entry_offset" / Int16ul,
    "entry" / Pointer(
        this._._.entries_start + this.entry_offset,
        Switch(
            lambda ctx: "strange"
            if ctx._._.is_strange_page else ctx._._.page_type,
            {
                "block_tracks": Track,
                "block_artists": Artist,
                "block_albums": Album,
                "block_playlists": Playlist,
예제 #11
0
    def __setup_constructors(self):
        '''Set endianness and create transport-specific constructors.'''
        # Set endianness of constructors before using them.
        self._set_endian('little')

        self.__Length = Int32ul
        self.__Type = Enum(
                Int16ul,
                default=Pass,
                Undefined=0x0000,
                Command=0x0001,
                Data=0x0002,
                Response=0x0003,
                Event=0x0004,
                )
        # This is just a convenience constructor to get the size of a header.
        self.__Code = Int16ul
        self.__Header = Struct(
                'Length' / self.__Length,
                'Type' / self.__Type,
                'Code' / self.__Code,
                'TransactionID' / self._TransactionID,
                )
        # These are the actual constructors for parsing and building.
        self.__CommandHeader = Struct(
                'Length' / self.__Length,
                'Type' / self.__Type,
                'OperationCode' / self._OperationCode,
                'TransactionID' / self._TransactionID,
                )
        self.__ResponseHeader = Struct(
                'Length' / self.__Length,
                'Type' / self.__Type,
                'ResponseCode' / self._ResponseCode,
                'TransactionID' / self._TransactionID,
                )
        self.__EventHeader = Struct(
                'Length' / self.__Length,
                'Type' / self.__Type,
                'EventCode' / self._EventCode,
                'TransactionID' / self._TransactionID,
                )
        # Apparently nobody uses the SessionID field. Even though it is
        # specified in ISO15740:2013(E), no device respects it and the session
        # number is implicit over USB.
        self.__Param = Range(0, 5, self._Parameter)
        self.__FullParam = Struct(Array(5, self._Parameter))
        self.__FullEventParam = Struct(Array(3, self._Parameter))
        self.__CommandTransactionBase = Struct(
                Embedded(self.__CommandHeader),
                'Payload' / Bytes(
                    lambda ctx, h=self.__Header: ctx.Length - h.sizeof()
                )
        )
        self.__CommandTransaction = ExprAdapter(
                self.__CommandTransactionBase,
                encoder=lambda obj, ctx, h=self.__Header: Container(
                    Length=len(obj.Payload) + h.sizeof(),
                    **obj
                    ),
                decoder=lambda obj, ctx: obj,
                )
        self.__ResponseTransactionBase = Struct(
                Embedded(self.__ResponseHeader),
                'Payload' / Bytes(
                    lambda ctx, h=self.__Header: ctx.Length - h.sizeof())
                )
        self.__ResponseTransaction = ExprAdapter(
                self.__ResponseTransactionBase,
                encoder=lambda obj, ctx, h=self.__Header: Container(
                    Length=len(obj.Payload) + h.sizeof(),
                    **obj
                    ),
                decoder=lambda obj, ctx: obj,
                )
        self.__EventTransactionBase = Struct(
                Embedded(self.__EventHeader),
                'Payload' / Bytes(
                      lambda ctx, h=self.__Header: ctx.Length - h.sizeof()),
                )
        self.__EventTransaction = ExprAdapter(
                self.__EventTransactionBase,
                encoder=lambda obj, ctx, h=self.__Header: Container(
                    Length=len(obj.Payload) + h.sizeof(),
                    **obj
                    ),
                decoder=lambda obj, ctx: obj,
                )
예제 #12
0
"""All low level structures used for parsing eddystone packets."""
from construct import Struct, Byte, Switch, Const, OneOf, Int8sl, Array, \
                      Int16ul, Int16ub, Int32ub, GreedyString

from ..const import EDDYSTONE_UUID, EDDYSTONE_URL_SCHEMES, EDDYSTONE_TLM_UNENCRYPTED, \
                    EDDYSTONE_TLM_ENCRYPTED, EDDYSTONE_UID_FRAME, EDDYSTONE_URL_FRAME, \
                    EDDYSTONE_TLM_FRAME, EDDYSTONE_EID_FRAME, FLAGS_DATA_TYPE, \
                    SERVICE_DATA_TYPE, SERVICE_UUIDS_DATA_TYPE

# pylint: disable=invalid-name

EddystoneUIDFrame = Struct("tx_power" / Int8sl, "namespace" / Array(10, Byte),
                           "instance" / Array(6, Byte),
                           "rfu" / Const(b"\x00\x00"))

EddystoneURLFrame = Struct(
    "tx_power" / Int8sl,
    "url_scheme" / OneOf(Byte, list(EDDYSTONE_URL_SCHEMES)),
    "url" / GreedyString(encoding="ascii"))

UnencryptedTLMFrame = Struct(
    "voltage" / Int16ub,
    "temperature" / Int16ul,
    "advertising_count" / Int32ub,
    "seconds_since_boot" / Int32ub,
)

EncryptedTLMFrame = Struct("encrypted_data" / Array(12, Byte),
                           "salt" / Int16ul, "mic" / Int16ul)

EddystoneTLMFrame = Struct(
예제 #13
0
    "hwinit.cfg"  # 25 Hardware init config
]

# offset and size need to be multiplied by LOG_BLOCK_SZ
FlashFileEntry = Struct("offset" / Int32ul, "size" / Int32ul,
                        "unknown" / Int64ul)

FlashHeader = Struct(
    "magic" / Bytes(4),  # HEADER_MAGIC
    "format_version" / Int8ul,
    "sequence_version" / Int8ul,
    "layout_version" / Int16ul,
    "unknown_1" / Int64ul,
    "unknown_2" / Int64ul,
    "unknown_3" / Int64ul,
    "files" / Array(FLASH_FILES_COUNT, FlashFileEntry),
    Padding(544),
    "guid" / UUIDAdapter(),
    "hash" / Bytes(HEADER_HASH_SIZE)  # SHA256 checksum
)


class DurangoNand(object):
    def __init__(self, filename):
        # offset : sequence_version
        self.header_offsets = dict()
        self.xbfs_tables = list()
        self.is_valid = True
        self.dump_type = None
        self.filename = filename
        self.filesize = os.stat(self.filename).st_size
예제 #14
0
"""Lobby."""

from construct import Array, Byte, Bytes, Flag, Int32ul, Padding, Peek, Struct, If, Computed, Embedded

from mgz.enums import GameTypeEnum, RevealMapEnum
from mgz.util import Version

# pylint: disable=invalid-name, bad-continuation


# Player inputs in the lobby, and several host settings.
lobby = "lobby"/Struct(
    Array(8, "teams"/Byte), # team number selected by each player
    If(lambda ctx: ctx._.version != Version.DE,
        Padding(1),
    ),
    Peek("reveal_map_id"/Int32ul),
    RevealMapEnum("reveal_map"/Int32ul),
    Padding(4),
    "map_size"/Int32ul,
    "population_limit_encoded"/Int32ul,
    "population_limit"/Computed(lambda ctx: ctx.population_limit_encoded * (25 if ctx._.version in [Version.USERPATCH14, Version.USERPATCH15] else 1)),
    Embedded(If(lambda ctx: ctx._.version != Version.AOK,
        Struct(
            Peek("game_type_id"/Byte),
            GameTypeEnum("game_type"/Byte),
            "lock_teams"/Flag
        )
    )),
    If(lambda ctx: ctx._.version == Version.DE,
        Padding(5)
예제 #15
0
 def setUp(self):
     self.c = Array(4, UBInt8("foo"))
예제 #16
0
파일: mst.py 프로젝트: scieloorg/ioisis
    def create_record_struct(self, control_record):
        # Pre-computed lengths and flags
        ffi = self.format == "ffi"
        slacked = not self.packed
        leader_len = 18 + 4 * ffi + 2 * slacked
        dir_entry_len = 6 + 4 * ffi + 2 * (ffi & slacked)
        min_mod = max(self.min_modulus, 1 << self.default_shift)
        inf = float("inf")

        # Data types for integer values (strings are always big endian)
        Int16s, Int16u, Int32s, Int32u = {
            "big": (Int16sb, Int16ub, Int32sb, Int32ub),
            "little": (Int16sl, Int16ul, Int32sl, Int32ul),
        }[self.endianness]

        # For the leader and directory structure of the records,
        # some sizes are configured based on the ffi and lockable flags
        # (MRFL is the record length)
        if self.lockable:
            mfrl_fields = [
                "mfrl" / Rebuild(
                    Int32s if ffi else Int16s,
                    lambda this: -this._build_total_len
                    if this.get("rlock", False) else this._build_total_len),
                "total_len" / Computed(lambda this: abs(this.mfrl)),
                "rlock" / Computed(lambda this: this.mfrl < 0),
            ]
        else:
            mfrl_fields = [
                "mfrl" / Rebuild(Int32u if ffi else Int16u,
                                 lambda this: this._build_total_len),
                "total_len" / Computed(lambda this: this.mfrl),
            ]

        return Struct(
            # Block alignment ("never splits" the leader unless BASE fits)
            "_before_start" / Tell,
            Padding(
                lambda this: never_split_pad_size(this._before_start,
                                                  leader_len),
                self.block_filler,
            ),
            "_start" / Tell,

            # Build time pre-computed information
            "_build_len_list" /
            Computed(lambda this: None if "fields" not in this else
                     [len(field) for field in this.fields]),
            "_build_pos_list" /
            Computed(lambda this: None if "fields" not in this else list(
                accumulate([0] + this._build_len_list))),
            "_build_total_len_padless" /
            Computed(lambda this: None if "fields" not in this else leader_len
                     + dir_entry_len * len(this.fields) + this._build_pos_list[
                         -1]  # Fields length
                     ),
            "_build_total_len" /
            Computed(lambda this: None
                     if "fields" not in this else this._build_total_len_padless
                     + pad_size(control_record.get("modulus", min_mod), this.
                                _build_total_len_padless)),

            # Record leader/header
            "mfn" / Int32s,  # Master file number
            Check(lambda this: this.mfn != 0),  # Not a control record
            Check(lambda this: control_record.get("next_mfn", inf) > this.mfn),
            *mfrl_fields,
            Check(lambda this: this.total_len % control_record.get(
                "modulus", min_mod) == 0),
            *([Const(self.slack_filler * 2)] if slacked and not ffi else []),
            "old_block" / Default(Int32s, 0),  # MFBWB backward pointer block
            "old_offset" / Default(Int16u, 0),  # MFBWP backward pointer offset
            *([Const(self.slack_filler * 2)] if slacked and ffi else []),
            "base_addr" / Rebuild(
                Int32u if ffi else Int16u,
                lambda this: leader_len + dir_entry_len * len(this.fields),
            ),
            "num_fields" / Rebuild(
                Int16u,  # NVF
                lambda this: len(this.fields)),
            "status" / Default(Int16u, 0),  # Active is 0, deleted is 1

            # Directory
            "dir" / Struct(
                "tag" / Int16u,
                *([Const(self.slack_filler * 2)] if slacked and ffi else []),
                "pos" / Rebuild(
                    Int32u if ffi else Int16u,
                    lambda this: this._._build_pos_list[this._index],
                ),
                "len" / Rebuild(
                    Int32u if ffi else Int16u,
                    lambda this: this._._build_len_list[this._index],
                ),
            )[lambda this: this.num_fields],
            "_before_fields" / Tell,
            Check(lambda this: this.base_addr == this._before_fields - this.
                  _start),

            # Field data
            "fields" / Array(
                lambda this: this.num_fields,
                "value" / Bytes(lambda this: this.dir[this._index].len),
            ),

            # Record alignment (implicitly checks the length stored in MFRL)
            "_after_fields" / Tell,
            Padding(
                lambda this: this.total_len -
                (this._after_fields - this._start),
                self.record_filler,
            ),
        )
예제 #17
0
PT_WIFI_STATS_REQUEST = 0x37
PT_WIFI_STATS_RESPONSE = 0x38

ENTRY_TYPE = Sequence("entries", UBInt8("type"), UBInt32("timestamp"),
                      UBInt32("sample"))

WIFI_STATS_REQUEST = Struct("wifi_stats_request", UBInt8("version"),
                            UBInt8("type"), UBInt32("length"), UBInt32("seq"),
                            UBInt32("module_id"), Bytes("hwaddr", 6),
                            UBInt8("channel"), UBInt8("band"))

WIFI_STATS_RESPONSE = Struct("wifi_stats_response", UBInt8("version"),
                             UBInt8("type"), UBInt32("length"), UBInt32("seq"),
                             UBInt32("module_id"), Bytes("wtp", 6),
                             UBInt16("nb_entries"),
                             Array(lambda ctx: ctx.nb_entries, ENTRY_TYPE))


class WiFiStats(ModulePeriodic):
    """ A maps poller. """

    MODULE_NAME = "wifistats"
    REQUIRED = ['module_type', 'worker', 'tenant_id', 'block']

    def __init__(self):

        super().__init__()

        # parameters
        self._block = None
예제 #18
0
                     UBInt32("count"))

WTP_STATS_REQUEST = Struct("stats_request", UBInt8("version"), UBInt8("type"),
                           UBInt32("length"), UBInt32("seq"),
                           UBInt32("module_id"))

WTP_STATS_RESPONSE = \
    Struct("stats_response", UBInt8("version"),
           UBInt8("type"),
           UBInt32("length"),
           UBInt32("seq"),
           UBInt32("module_id"),
           Bytes("wtp", 6),
           UBInt16("nb_tx"),
           UBInt16("nb_rx"),
           Array(lambda ctx: ctx.nb_tx + ctx.nb_rx, WTP_STATS))


class WTPBinCounter(ModulePeriodic):
    """ WTPBinCounter object.

    This primitive tracks the packets/bytes sent and received by a LVAP (which
    is the virtual AP running in the WTP). Traffic is classified in the
    specifed bins.

    For example:

        wtp_bin_counter(bins=[512, 1514, 8192],
                        wtp="11:22:33:44:55:66",
                        2000,
                        callback=counters_callback)
예제 #19
0
    "device" / Bytes(6),
    "iface_id" / Int32ub,
)
WCS_REQUEST.name = "wcs_request"

WCS_ENTRY = Struct(
    "type" / Int8ub,
    "timestamp" / Int64ub,
    "sample" / Int32ub,
)
WCS_ENTRY.name = "wcs_entry"

WCS_RESPONSE = Struct("version" / Int8ub, "type" / Int8ub, "length" / Int32ub,
                      "seq" / Int32ub, "xid" / Int32ub, "device" / Bytes(6),
                      "iface_id" / Int32ub, "nb_entries" / Int16ub,
                      "entries" / Array(lambda ctx: ctx.nb_entries, WCS_ENTRY))
WCS_RESPONSE.name = "wcs_response"


class ChannelStats(EWorker):
    """WiFi Channel Statistics Worker

    Parameters:
        service_id: the service id as an UUID (mandatory)
        every: the polling period in ms (optional, default: 2000)
    """
    def __init__(self, service_id, project_id, every):

        super().__init__(service_id=service_id,
                         project_id=project_id,
                         every=every)
예제 #20
0
    "size" / Int16ub,
    "count" / Int32ub,
)
COUNTERS_ENTRY.name = "counters_entry"

BIN_COUNTERS_RESPONSE = Struct(
    "version" / Int8ub,
    "type" / Int8ub,
    "length" / Int32ub,
    "seq" / Int32ub,
    "xid" / Int32ub,
    "device" / Bytes(6),
    "sta" / Bytes(6),
    "nb_tx" / Int16ub,
    "nb_rx" / Int16ub,
    "stats" / Array(lambda ctx: ctx.nb_tx + ctx.nb_rx, COUNTERS_ENTRY),
)
BIN_COUNTERS_RESPONSE.name = "bin_counters_response"


class LVAPBinCounter(EWiFiApp):
    """LVAP Bin Counter Primitive.

    This primitive collects the packet counters from the specified LVAP.

    Parameters:
        sta: the LVAP to track as an EtherAddress (mandatory)
        bins: the bins for the measurements (optional, default: [8192])
        every: the loop period in ms (optional, default 2000ms)

    Example:
예제 #21
0
    "tx_packets" / Int32ub,
    "tx_bytes" / Int32ub,
)
SLICE_STATS_ENTRY.name = "slice_stats_entry"

WIFI_SLICE_STATS_RESPONSE = Struct(
    "version" / Int8ub,
    "type" / Int8ub,
    "length" / Int32ub,
    "seq" / Int32ub,
    "xid" / Int32ub,
    "device" / Bytes(6),
    "ssid" / Bytes(WIFI_NWID_MAXSIZE + 1),
    "slice_id" / Int8ub,
    "nb_entries" / Int16ub,
    "stats" / Array(lambda ctx: ctx.nb_entries, SLICE_STATS_ENTRY),
)
WIFI_SLICE_STATS_RESPONSE.name = "wifi_slice_stats_response"


class SliceStats(EWiFiApp):
    """WiFi Slice Statistics Primitive.

    This primitive collects the slice statistics.

    Parameters:
        slice_id: the slice to track (optinal, default 0)
        every: the loop period in ms (optional, default 2000ms)

    Example:
        POST /api/v1/projects/52313ecb-9d00-4b7d-b873-b55d3d9ada26/apps
예제 #22
0
                        RED=1,
                        YELLOW=2,
                        BLACK=3,
                        WHITE=4,
                        GREEN=5,
                        ORANGE=6,
                        PURPLE=7,
                        BROWN=8,
                        GRAY=9),
    "score" / Byte,
    "penalty_shot" / Byte,  # penalty shot counter
    "single_shots" / Short,  # bits represent penalty shot success
    "coach_sequence" / Byte,
    "coach_message" / Bytes(253),
    Renamed("coach", RobotInfo),
    "players" / Array(11, RobotInfo))

GameState = "gamedata" / Struct(
    "header" / Const(Bytes(4), b'RGme'),
    "version" / Const(Byte, 12),
    "packet_number" / Short,
    "players_per_team" / Byte,
    "game_type" / Byte,
    "game_state" / Enum(
        Byte,
        STATE_INITIAL=0,
        # auf startposition gehen
        STATE_READY=1,
        # bereithalten
        STATE_SET=2,
        # spielen
예제 #23
0
                        RED=1,
                        YELLOW=2,
                        BLACK=3,
                        WHITE=4,
                        GREEN=5,
                        ORANGE=6,
                        PURPLE=7,
                        BROWN=8,
                        GRAY=9),
    "score" / Byte,
    "penalty_shot" / Byte,  # penalty shot counter
    "single_shots" / Short,  # bits represent penalty shot success
    "coach_sequence" / Byte,
    "coach_message" / PaddedString(253, 'utf8'),
    "coach" / RobotInfo,
    "players" / Array(11, RobotInfo))

GameState = "gamedata" / Struct(
    "header" / Const(b'RGme'),
    "version" / Const(12, Short),
    "packet_number" / Byte,
    "players_per_team" / Byte,
    "game_type" / Byte,
    "game_state" / Enum(
        Byte,
        STATE_INITIAL=0,
        # auf startposition gehen
        STATE_READY=1,
        # bereithalten
        STATE_SET=2,
        # spielen
예제 #24
0
        return self.send("get_indicatorLamp")


class ProntoPulseAdapter(Adapter):
    def _decode(self, obj, context, path):
        return int(obj * context._.modulation_period)

    def _encode(self, obj, context, path):
        raise RuntimeError("Not implemented")


ChuangmiIrSignal = Struct(
    Const(0xA567, Int16ul),
    "edge_count" / Rebuild(Int16ul,
                           len_(this.edge_pairs) * 2 - 1),
    "times_index" / Array(16, Int32ul),
    "edge_pairs" / Array(
        (this.edge_count + 1) // 2,
        BitStruct("gap" / BitsInteger(4), "pulse" / BitsInteger(4)),
    ),
)

ProntoBurstPair = Struct("pulse" / ProntoPulseAdapter(Int16ub),
                         "gap" / ProntoPulseAdapter(Int16ub))

Pronto = Struct(
    Const(0, Int16ub),
    "_ticks" / Int16ub,
    "modulation_period" / Computed(this._ticks * 0.241246),
    "frequency" / Computed(1000000 / this.modulation_period),
    "intro_len" / Int16ub,
예제 #25
0
                  "cur_tp" / Int32ub, "last_attempts" / Int32ub,
                  "last_successes" / Int32ub, "hist_attempts" / Int32ub,
                  "hist_successes" / Int32ub)
RC_ENTRY.name = "rc_entry"

WIFI_RC_STATS_RESPONSE = Struct(
    "version" / Int8ub,
    "type" / Int8ub,
    "length" / Int32ub,
    "seq" / Int32ub,
    "xid" / Int32ub,
    "device" / Bytes(6),
    "iface_id" / Int32ub,
    "sta" / Bytes(6),
    "nb_entries" / Int16ub,
    "stats" / Array(lambda ctx: ctx.nb_entries, RC_ENTRY),
)
WIFI_RC_STATS_RESPONSE.name = "wifi_rc_stats_response"


class RCStats(EWiFiApp):
    """WiFi Rate Control Statistics Primitive.

    This primitive collects the RC statistics from the specified LVAP.

    Parameters:
        sta: the LVAP to track as an EtherAddress (mandatory)
        every: the loop period in ms (optional, default 2000ms)

    Example:
        POST /api/v1/projects/52313ecb-9d00-4b7d-b873-b55d3d9ada26/apps
예제 #26
0
        return play_method(command, *command_args)


class ProntoPulseAdapter(Adapter):
    def _decode(self, obj, context, path):
        return int(obj * context._.modulation_period)

    def _encode(self, obj, context, path):
        raise RuntimeError('Not implemented')


ChuangmiIrSignal = Struct(
    Const(0xa567,
          Int16ul), 'edge_count' / Rebuild(Int16ul,
                                           len_(this.edge_pairs) * 2 - 1),
    'times_index' / Array(16, Int32ul), 'edge_pairs' / Array(
        (this.edge_count + 1) // 2,
        BitStruct(
            'gap' / BitsInteger(4),
            'pulse' / BitsInteger(4),
        )))

ProntoBurstPair = Struct(
    'pulse' / ProntoPulseAdapter(Int16ub),
    'gap' / ProntoPulseAdapter(Int16ub),
)

Pronto = Struct(
    Const(0, Int16ub),
    '_ticks' / Int16ub,
    'modulation_period' / Computed(this._ticks * 0.241246),
예제 #27
0
from mgz.enums import VictoryEnum, ResourceLevelEnum, AgeEnum, PlayerTypeEnum, DifficultyEnum

# pylint: disable=invalid-name, bad-continuation

de_string = Struct(Const(b"\x60\x0A"), "length" / Int16ul,
                   "value" / Bytes(lambda ctx: ctx.length))

separator = Const(b"\xa3_\x02\x00")

de = "de" / Struct(
    "options" / Int32sl,
    Int32ul,
    Int32ul,
    "dlc_count" / Int32ul,
    "dlc_ids" / Array(lambda ctx: ctx.dlc_count, Int32ul),
    Bytes(4),
    "difficulty" / DifficultyEnum(Int32ul),
    "map_size" / Int32ul,
    "map_id" / Int32ul,
    "reveal_map" / Int32ul,
    Peek("victory_type_id" / Int32ul),
    VictoryEnum("victory_type" / Int32ul),
    Peek("starting_resources_id" / Int32ul),
    ResourceLevelEnum("starting_resources" / Int32ul),
    Peek("starting_age_id" / Int32ul),
    AgeEnum("starting_age" / Int32ul),
    Peek("ending_age_id" / Int32ul),
    AgeEnum("ending_age" / Int32ul),
    "game_type" / Int32ul,
    separator,
예제 #28
0
                        Bytes("addrs", 6),
                        Bytes("hwaddr", 6),
                        UBInt8("channel"),
                        UBInt8("band"))

POLLER_RESP_MSG = Struct("poller_response", UBInt8("version"),
                         UBInt8("type"),
                         UBInt16("length"),
                         UBInt32("seq"),
                         UBInt32("poller_id"),
                         Bytes("wtp", 6),
                         Bytes("hwaddr", 6),
                         UBInt8("channel"),
                         UBInt8("band"),
                         UBInt16("nb_entries"),
                         Array(lambda ctx: ctx.nb_entries, POLLER_ENTRY_TYPE))


class Maps(Module):
    """ A maps poller. """

    REQUIRED = ['module_type', 'worker', 'tenant_id', 'block']

    _addrs = EtherAddress('FF:FF:FF:FF:FF:FF')
    _block = None

    def __eq__(self, other):

        return super().__eq__(other) and \
            self.addrs == other.addrs and \
            self.block == other.block
예제 #29
0
from construct import Struct, Const, Int32ul, Array, Padding, Tell
from .pagetype import PageTypeEnum

FileHeaderEntry = Struct(
    "page_type" / PageTypeEnum,
    "empty_candidate" / Int32ul,
    "first_page" /
    Int32ul,  # always points to a strange page, which then links to a real data page
    "last_page" / Int32ul)

FileHeader = Struct(
    Padding(4),  # always 0
    "page_size" / Const(Int32ul, 4096),
    "page_entries" / Int32ul,  # FileHeaderEntry follow, usually 20
    "next_unused_page" /
    Int32ul,  # even unreferenced -> not used as any "empty_candidate", points "out of file"
    "unknown1" / Int32ul,  # (5,4,4,1,1,1...)
    "sequence" /
    Int32ul,  # sequence number, always incremented by 1 (sometimes 2/3)
    Padding(4),  # always 0
    "entries" / Array(lambda ctx: ctx.page_entries, FileHeaderEntry),
    "length" / Tell,  # usually 348 when page_entries=20
    Padding(lambda ctx: ctx.page_size - ctx.length))
예제 #30
0
            command_line=obj.command_line,
            company=obj.company,
            version=obj.version,
            description=obj.description,
            start_time=obj.start_time,
            end_time=obj.end_time,
            modules=obj.modules)


ProcessStruct = ProcessStructAdapter(RawProcessStruct)
ProcessTable = """
The table of all the processes that the events in the logs come from.
""" * Struct(
    "table_offset" / Tell,
    "count" / Int32ul,
    "process_indexes" / Array(lambda this: this.count, Int32ul),
    "processes" / Array(
        lambda this: this.count,
        Struct(
            "is_64bit" / Computed(lambda ctx: ctx._._.is_64bit
                                  ),  # keep this in order to use PVoid
            "strings_table" /
            Computed(lambda ctx: ctx._._.strings_table
                     ),  # keep the reference to the string table
            "offset" / Int32ul,
            "process" / Pointer(lambda this: this._.table_offset + this.offset,
                                ProcessStruct)),
    ),
    CheckCustom(
        lambda this: all(i == p.process[0]
                         for i, p in zip(this.process_indexes, this.processes)
예제 #31
0
def EventsOffsetArray(number_of_events):
    return Array(number_of_events, Struct("offset" / Int32ul, "flags" / Byte))
예제 #32
0
파일: ssexy.py 프로젝트: Bletchley13/ssexy
def ssexy_linux(fname, *eips):
    import elf32
    from construct import Struct, ULInt32, ULInt16, ULInt8, Array, CString
    from construct import OptionalGreedyRange

    # assume low-endian binary
    elf32_rel = Struct('elf32_rel', ULInt32('r_offset'), ULInt32('r_info'))
    ELF32_R_SYM = lambda x: x.r_info >> 8
    ELF32_R_TYPE = lambda x: x.r_info & 0xff
    R_386_PC32 = 2

    elf32_sym = Struct('elf32_sym', ULInt32('st_name'), ULInt32('st_value'),
        ULInt32('st_size'), ULInt8('st_info'), ULInt8('st_other'),
        ULInt16('st_shndx'))

    elf = elf32.elf32_file.parse_stream(file(fname, 'rb'))

    # retrieve section by name
    elf32_section = lambda elf, name: [x for x in elf.sections
        if x.name == name][0]

    # for now we assume that all code is in the .text section
    code_section = [x for x in elf.sections if x.name == '.text']
    if not len(code_section):
        raise Exception('your binary doesn\'t have a .text section..')

    relocs = [x.data.value for x in elf.sections if x.name == '.rel.dyn']
    if not len(relocs):
        raise Exception('no relocs available, compile with -pie')

    # read all relocations
    relocs = Array(len(relocs[0]) / elf32_rel.sizeof(),
        elf32_rel).parse(relocs[0])
    # now get the offsets of the relocations
    relocs = set([x.r_offset for x in relocs])

    imports = {}

    # a list of addresses that were used.
    addresses = []

    # a list of all m128 values we use
    m128s = []

    # a list of all dword values we use
    m32s = []

    instructions = pyasm2.block()

    # get string at offset
    dynstr = lambda x: CString(None).parse(
        elf32_section(elf, '.dynstr').data.value[x:])

    # read the symbol table
    imports = OptionalGreedyRange(elf32_sym).parse(elf32_section(elf,
        '.dynsym').data.value)

    # resolve relocations
    section = elf32_section(elf, '.rel.dyn')
    relocates = {}
    for x in xrange(0, section.size, elf32_rel.sizeof()):
        x = elf32_rel.parse(section.data.value[x:x+elf32_rel.sizeof()])
        # relocation to fixup addresses to imports
        if ELF32_R_TYPE(x) == R_386_PC32:
            relocates[x.r_offset] = dynstr(imports[ELF32_R_SYM(x)].st_name)

    # walk each section, find those that are executable and disassemble those
    section = elf32_section(elf, '.text')
    g = distorm3.DecomposeGenerator(section.addr, section.data.value,
            distorm3.Decode32Bits)
    for instr in g:
        # useless instruction?
        if str(instr) in ('NOP', 'ADD [EAX], AL', 'LEA ESI, [ESI]',
                    'INT 3') or str(instr)[:2] == 'DB':
            continue

        # a jump to one of the imports?
        #if instr.mnemonic == 'JMP' and instr.operands[0].type == \
        #        distorm3.OPERAND_ABSOLUTE_ADDRESS and \
        #        instr.operands[0].disp in imports:
        #    iat_label[instr.address] = imports[instr.operands[0].disp]
        #    continue

        # quite hackery, but when the jumps with thunk address have been
        # processed, we can be fairly sure that there will be no (legit)
        # code anymore.
        #if len(iat_label):
        #    break

        #print str(instr)

        #print str(instr)

        # convert the instruction from distorm3 format to pyasm2 format.
        instr = distorm3_to_pyasm2(instr)

        # we create the block already here, otherwise our `labelnr' is
        # not defined.
        #block = pyasm2.block(pyasm2.Label('%08x' % instr.address), instr)
        offset_flat = None
        addr = instr.address

        # now we check if this instruction has a relocation inside it
        # not a very efficient way, but oke.
        reloc = instr.length > 4 and relocs.intersection(range(
            instr.address, instr.address + instr.length - 3))
        if reloc:
            # make an immediate with `addr' set to True
            enable_addr = lambda x: Immediate(int(x), addr=True)

            # TODO support for two relocations in one instruction
            # (displacement *and* immediate)
            reloc = reloc.pop()
            if not hasattr(instr, 'op1'):
                instr.op1, instr.op2 = None, None
            # there is only one operand, that's easy
            if not instr.op2:
                #sys.stderr.write('reloc in op1 %s??\n' % instr.op1)
                if isinstance(instr.op1, pyasm2.MemoryAddress):
                    # special occassion, this memory addres is an import
                    if instr.op1.reg1 is None and \
                            instr.op1.reg2 is None and \
                            int(instr.op1.disp) in imports:
                        instr.op1 = imports[int(instr.op1.disp)]
                    else:
                        addresses.append(int(instr.op1.disp))
                        # change the displacement to a label
                        #instr.op1 = str(instr.op1).replace('0x',
                        #    '__lbl_00')
                        instr.op1 = enable_addr(instr.op1)
                elif isinstance(instr.op1, pyasm2.Immediate):
                    addresses.append(int(instr.op1))
                    offset_flat = int(instr.op1)
                    #instr.op1 = str(instr.op1).replace('0x',
                    #    'offset flat:__lbl_00')
            # if the second operand is an immediate and the relocation is
            # in the last four bytes of the instruction, then this
            # immediate is the reloc. Otherwise, if the second operand is
            # a memory address, then it's the displacement.
            elif isinstance(instr.op2, pyasm2.Immediate) and reloc == \
                    instr.address + instr.length - 4:
                # keep this address
                addresses.append(int(instr.op2))
                # make a label from this address
                # TODO: fix this horrible hack
                offset_flat = int(instr.op2)
                #instr.op2 = pyasm2.Label('offset flat:__lbl_%08x' %
                #    int(instr.op2), prepend=False)
            elif isinstance(instr.op2, pyasm2.MemoryAddress) and \
                    reloc == instr.address + instr.length - 4:
                addresses.append(int(instr.op2.disp))
                # change the displacement to a label
                instr.op2 = enable_addr(instr.op2)
                #instr.op2 = str(instr.op2).replace('0x', '__lbl_00')
                #sys.stderr.write('reloc in op2 memaddr %s\n' %
                #    str(instr.op2))
            # the relocation is not inside the second operand, it must be
            # inside the first operand after all.
            elif isinstance(instr.op1, pyasm2.MemoryAddress):
                addresses.append(int(instr.op1.disp))
                instr.op1 = enable_addr(instr.op1)
                #instr.op1 = str(instr.op1).replace('0x', '__lbl_00')
                #sys.stderr.write('reloc in op1 memaddr %s\n' %
                #    str(instr.op1))
            elif isinstance(instr.op1, pyasm2.Immediate):
                addresses.append(int(instr.op1))
                instr.op1 = enable_addr(instr.op1)
                #instr.op1 = '__lbl_%08x' % int(instr.op1)
                #sys.stderr.write('reloc in op1 imm %s\n' % instr.op1)
            else:
                sys.stderr.write('Invalid Relocation!\n')

        #print instr
        m32len = len(m32s)
        instr = translate.Translater(instr, m128s, m32s).translate()
        if offset_flat:
            encode_offset_flat = lambda x: str(x).replace('0x',
                'offset flat:__lbl_') if isinstance(x, (int, long,
                pyasm2.imm)) and int(x) == offset_flat or isinstance(x,
                pyasm2.mem) and x.disp == offset_flat else x

            if isinstance(instr, pyasm2.block):
                for x in instr.instructions:
                    x.op1 = encode_offset_flat(x.op1)
                    x.op2 = encode_offset_flat(x.op2)
            else:
                x.op1 = encode_offset_flat(x.op1)
                x.op2 = encode_offset_flat(x.op2)

            # update stuff
            m32s = m32s[:m32len] + [x.replace('0x%08x' % offset_flat,
                'offset flat:__lbl_%08x' % offset_flat)
                for x in m32s[m32len:]]

        instructions += pyasm2.block(pyasm2.Label('%08x' % addr), instr)

    # remove any addresses that are from within the current section
    newlist = addresses[:]
    for i in xrange(len(addresses)):
        if addresses[i] >= code_section[0].addr and addresses[i] < \
                code_section[0].addr + code_section[0].size:
            newlist[i] = None
    addresses = filter(lambda x: x is not None, newlist)

    # walk over each instruction, if it has references, we update them
    for instr in instructions.instructions:
        # we can skip labels
        if isinstance(instr, pyasm2.Label):
            continue

        # check for references to imports
        if isinstance(instr, pyasm2.RelativeJump):
            # not very good, but for now (instead of checking relocs) we check
            # if the index is in the iat tabel..
            #if int(instr.lbl.index, 16) in iat_label:
                #instr.lbl.index = iat_label[int(instr.lbl.index, 16)]
                #instr.lbl.prepend = False
            continue

    program = ['.file "ssexy.c"', '.intel_syntax noprefix']

    # we walk over each section, if a reference to this section has been found
    # then we will dump the entire section as bytecode.. with matching labels
    for section in elf.sections:
        base = section.addr
        data = section.data.value
        addr = set(range(base, base + section.size)).intersection(addresses)
        if addr:
            # create a header for this section
            program.append('.section %s' % section.name)

            # for now we do it the easy way.. one line and label per byte, lol
            for addr in xrange(section.size):
                program.append('__lbl_%08x: .byte 0x%02x' % (base + addr,
                    ord(data[addr])))

            # empty line..
            program.append('')

    # now we define all xmm's etc we gathered
    program.append('.align 4')
    program += m32s
    program.append('.align 16')
    program += m128s

    # time to define 'main'
    program.append('.text')
    program.append('.globl Main')
    program.append('.type Main, @function')

    OEP = elf.entry

    # f****d up shit
    relocates = dict(('jmp __lbl_%08x' % k, 'jmp ' + v)
        for k, v in relocates.items())

    eips = ['__lbl_%08x' % x for x in eips]

    # append each instruction
    for instr in instructions.instructions:
        # if this is an label, we want a colon as postfix
        if isinstance(instr, pyasm2.Label):
            program.append(str(instr) + ':')

            # if OEP is at this address, we will also add the `_main' label
            if str(instr) == '__lbl_%08x' % OEP:
                program.append('Main:')

                # we have to initialize the stack register, so..
                # for now we assume esp gpr is stored as first gpr in xmm7
                program.append('movd xmm7, esp')

            # if the label is in the list of addresses to which we have to add
            # an "movd xmm7, esp" instruction, then add it (e.g. callback
            # function for pthread_create)
            if str(instr) in eips:
                program.append('movd xmm7, esp')
        else:
            # TODO: fix this terrible hack as well
            program.append(str(instr).replace('byte', 'byte ptr').replace(
                'word', 'word ptr').replace('retn', 'ret').replace(
                '__lbl_00400000', '0x400000').replace('oword ptr', ''))
            if program[-1] in relocates:
                program[-1] = relocates[program[-1]]

    print '\n'.join(program)
ContainerBlob = Struct("unknown" / Int32ul, "unknown2" / Int32ul,
                       "magic" / Bytes(8), "data" / Bytes(0x88),
                       "file_guid" / UUIDAdapter())
"""
Substruct of ContainerIndex, holds file entries
"""
ContainerIdxEntry = Struct(
    "filename" / PascalStringUtf16(Int32ul, encoding="utf16"),
    "filename_alt" / PascalStringUtf16(Int32ul, encoding="utf16"),
    "text" / PascalStringUtf16(Int32ul, encoding="utf16"),
    "blob_number" / Int8ul,
    "save_type" / Int32ul,  # sync state?
    "folder_guid" / UUIDAdapter(),
    "filetime" / FILETIMEAdapter(),
    "unknown" / Int64ul,  # always 0?
    "filesize" / Int32ul,
    "unknown2" / Int32ul  # always 0?
)
"""
Structure of containers.index file
"""
ContainerIndex = Struct(
    "type" / Int32ul,
    "file_count" / Int32ul,
    "name" / PascalStringUtf16(Int32ul, encoding="utf16"),
    "aum_id" / PascalStringUtf16(Int32ul, encoding="utf16"),
    "filetime" / FILETIMEAdapter(),
    "unknown" / Int32ul,  # seen values 0, 1, 3 so far
    "id" / PascalStringUtf16(Int32ul, encoding="utf16"),
    "files" / Array(this.file_count, ContainerIdxEntry))