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])
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,
''' 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,
#!/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),
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(
"""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,
# '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']))
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),
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
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,
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, )
"""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(
"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
"""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)
def setUp(self): self.c = Array(4, UBInt8("foo"))
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, ), )
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
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)
"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)
"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:
"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
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
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
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,
"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
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),
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,
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
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))
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)
def EventsOffsetArray(number_of_events): return Array(number_of_events, Struct("offset" / Int32ul, "flags" / Byte))
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))