class ConstDefaultTest(DataclassMixin): const_bytes: bytes = csfield(cs.Const(b"BMP")) const_int: int = csfield(cs.Const(5, cs.Int8ub)) default_int: int = csfield(cs.Default(cs.Int8ub, 28)) default_lambda: bytes = csfield( cs.Default(cs.Bytes(cs.this.const_int), lambda ctx: bytes(ctx.const_int)))
class JBSQ(ct.TContainerMixin): magic: Optional[bytes] = ct.sfield( c.Select(c.Const(b"IJBQ"), c.Const(b"IJSQ"), c.Const(b"JBSQ"))) num_events: int = ct.sfield(c.Int32ul) combo: int = ct.sfield(c.Int32ul) end_time: int = ct.sfield(c.Int32ul) _1: None = ct.sfield(c.Padding(2)) starting_buttons: int = ct.sfield(c.Int16ul) start_time: int = ct.sfield(c.Int32ul) _2: None = ct.sfield(c.Padding(12)) density_graph: List[int] = ct.sfield(c.Byte[60]) events: List[Event] = ct.sfield( c.Array(c.this.num_events, ct.TStruct(Event)))
def __init__(self, const): self.const = const super().__init__( c.IfThenElse( c.this._building, c.Select(c.Bytes(len(self.const)), c.Pass), Optional(c.Const(const)), ) )
def LifeScanPacket(include_link_control: bool, ) -> construct.Struct: # pylint: disable=invalid-name if include_link_control: link_control_construct = _LINK_CONTROL else: link_control_construct = construct.Const(b"\x00") return construct.Struct( "data" / construct.RawCopy( construct.Struct( construct.Const(b"\x02"), # stx "length" / construct.Rebuild( construct.Byte, lambda this: len(this.message) + 6), "link_control" / link_control_construct, "message" / construct.Bytes(lambda this: this.length - 6), construct.Const(b"\x03"), # etx ), ), "checksum" / construct.Checksum(construct.Int16ul, lifescan.crc_ccitt, construct.this.data.data), )
def LifeScanPacket(include_link_control): # pylint: disable=invalid-name # type: (bool) -> construct.Struct if include_link_control: link_control_construct = _LINK_CONTROL else: link_control_construct = construct.Const(b'\x00') return construct.Struct( 'data' / construct.RawCopy( construct.Struct( construct.Const(b'\x02'), # stx 'length' / construct.Rebuild( construct.Byte, lambda this: len(this.message) + 6), 'link_control' / link_control_construct, 'message' / construct.Bytes(lambda this: this.length - 6), construct.Const(b'\x03'), # etx ), ), 'checksum' / construct.Checksum(construct.Int16ul, lifescan.crc_ccitt, construct.this.data.data), )
def LifeScanPacket(command_prefix, include_link_control): if include_link_control: link_control_construct = _LINK_CONTROL else: link_control_construct = construct.Const(b'\x00') command_prefix_construct = construct.Const(command_prefix, construct.Byte) return construct.Struct( 'data' / construct.RawCopy( construct.Struct( construct.Const(b'\x02'), # stx 'length' / construct.Rebuild( construct.Byte, lambda this: len(this.message) + 7), 'link_control' / link_control_construct, 'command_prefix' / command_prefix_construct, 'message' / construct.Bytes(lambda this: this.length - 7), construct.Const(b'\x03'), # etx ), ), 'checksum' / construct.Checksum(construct.Int16ul, lifescan.crc_ccitt, construct.this.data.data), )
class GetDeviceQualifierDescriptorRequest(GetDescriptorRequest): DESCRIPTOR_NAME = "device qualifier" BINARY_FORMAT = DescriptorFormat( "bLength" / DescriptorField("Length"), "bDescriptorType" / DescriptorNumber(6), "bcdUSB" / DescriptorField("USB Version"), "bDeviceClass" / DescriptorField("Class"), "bDeviceSubclass" / DescriptorField("Subclass"), "bDeviceProtocol" / DescriptorField("Protocol"), "bMaxPacketSize0" / DescriptorField("EP0 Max Pkt Size"), "bNumConfigurations" / DescriptorField("Configuration Count"), "_bReserevd" / construct.Optional(construct.Const(b"\0")))
def _bitmap_header_bytes(): return construct.Struct( "Type" / construct.Const(b'\x42\x4D'), "BF_Size" / construct. Int32ul, # File Header (14) + DIB Header (40) + Pixel Array "Reserved_1" / construct.Const(b'\x00\x00'), "Reserved_2" / construct.Const(b'\x00\x00'), "Pixel_Array_Offset" / construct.Const(b'\x36\x00\x00\x00'), "Header_Size" / construct.Const(b'\x28\x00\x00\x00'), # DIB Header "Bitmap_Width" / construct.Int32ul, "Bitmap_Height" / construct.Int32ul, "Colour_Plane_Count" / construct.Const(b'\x01\x00'), "Bits_Per_Pixel" / construct.Int16ul, "Compression_Method" / construct.Const(b'\x00\x00\x00\x00'), "Bitmap_Size_In_Bytes" / construct.Int32ul, # Pixel Array "Horizontal_Resolution_In_Pixels_Per_Meter" / construct.Int32ul, "Vertical_Resolution_In_Pixels_Per_Meter" / construct.Int32ul, "Color_Used" / construct.Const(b'\x00\x00\x00\x00'), "Important_Color" / construct.Const(b'\x00\x00\x00\x00'))
import binascii import datetime import logging import construct from glucometerutils import common from glucometerutils.support import construct_extras from glucometerutils.support import lifescan from glucometerutils.support import lifescan_binary_protocol from glucometerutils.support import serial _PACKET = lifescan_binary_protocol.LifeScanPacket(False) _COMMAND_SUCCESS = construct.Const(b'\x03\x06') _VERSION_REQUEST = construct.Const(b'\x03\x0d\x01') _VERSION_RESPONSE = construct.Struct( _COMMAND_SUCCESS, 'version' / construct.PascalString(construct.Byte, encoding='ascii'), # NULL-termination is not included in string length. construct.Const(b'\x00'), ) _SERIAL_NUMBER_REQUEST = construct.Const(b'\x03\x0b\x01\x02') _SERIAL_NUMBER_RESPONSE = construct.Struct( _COMMAND_SUCCESS, 'serial_number' / construct.CString(encoding='ascii'),
"height" / construct.Int16ul, "data" / construct.GreedyBytes) # cseg01:0002F528 66 81 7A 0E 57 52 cmp word ptr [edx+0Eh], 5257h # cseg01:0002F52E 0F 85 A3 01 00 00 jnz loc_2F6D7 # cseg01:0002F534 66 C7 05 0C 9F 08 00 0D+ mov error_num, 0Dh # cseg01:0002F53D 66 83 7A 02 70 cmp word ptr [edx+2], 70h ; 'p raw_file_2 = construct.Struct( "unk_word_00" / construct.Int16ul, # + 0x00 "version" / construct.Int16ul, # + 0x02 "ns_offset_00" / construct.Int16ul, # + 0x04 "ns_offset_01" / construct.Int16ul, # + 0x06 "ns_offset_02" / construct.Int16ul, # + 0x08 "field_A" / construct.Int16ul, "field_C" / construct.Int16ul, "signature" / construct.Const("\x57\x52"), "field_10" / construct.Int16ul, "field_12" / construct.Int16ul, "field_14" / construct.Int16ul, # // length "field_16" / construct.Int16ul, "field_18" / construct.Int16ul, "field_1A" / construct.Int16ul) obj_00 = construct.Struct( "unk_field_00" / construct.Int16ul, # + 0x00 "unk_field_02" / construct.Int16ul, # + 0x02 "unk_field_04" / construct.Int16ul, # + 0x04 "index_texture_up" / construct.Int16ul, # + 0x06 "index_texture_down" / construct.Int16ul, # + 0x08 "unk_field_0A" / construct.Int16ul, # + 0x0A "unk_field_0C" / construct.Int8ul, # + 0x0C
MAT = (1 << 22) DTS_IV = (1 << 23) MPEG_4_HE_AAC = (1 << 24) MPEG_4_HE_AAC_V2 = (1 << 25) MPEG_4_AAC_LC = (1 << 26) DRA = (1 << 27) MPEG_4_HE_AAC_SURROUND = (1 << 28) MPEG_4_AAC_LC_SURROUND = (1 << 29) MPEG_H_3D_AUDIO = (1 << 30) AC4 = (1 << 31) MPEG_4_AAC_ELD = (1 << 32) # As defined in [Audio30], Table 4-47 AudioControlInterruptEndpointDescriptor = DescriptorFormat( "bLength" / construct.Const(7, construct.Int8ul), "bDescriptorType" / DescriptorNumber(AudioClassSpecificStandardDescriptorNumbers.CS_ENDPOINT), "bEndpointAddress" / DescriptorField( description= "The address of the endpoint, use USBDirection.*.from_endpoint_address()" ), "bmAttributes" / DescriptorField( description="D1..0: Transfer type (0b11 = Interrupt)", default=0b11), "wMaxPacketSize" / DescriptorField( description= "Maximum packet size this endpoint is capable of. Used here to pass 6-byte interrupt information.", default=6), "bInterval" / DescriptorField(description="Interval for polling the Interrupt endpoint")) # As defined in [Audio30], Table 4-51 AudioStreamingIsochronousEndpointDescriptor = DescriptorFormat( "bLength" / construct.Const(7, construct.Int8ul),
class SystemdJournalParser(interface.FileObjectParser): """Parses Systemd Journal files.""" NAME = 'systemd_journal' DESCRIPTION = 'Parser for Systemd Journal files.' _OBJECT_COMPRESSED_FLAG = 0x00000001 # Unfortunately this doesn't help us knowing about the "dirtiness" or # "corrupted" file state. # A file can be in any of these states and still be corrupted, for example, by # an unexpected shut down. Once journald detects one of these, it will # "rotate" the corrupted journal file, an store it away, and change the status # to STATE_OFFLINE. # STATE_ONLINE means the file wasn't closed, but the journal can still be in a # clean state. _JOURNAL_STATE = construct.Enum( construct.ULInt8('state'), STATE_OFFLINE=0, STATE_ONLINE=1, STATE_ARCHIVED=2 ) _OBJECT_HEADER_TYPE = construct.Enum( construct.ULInt8('type'), UNUSED=0, DATA=1, FIELD=2, ENTRY=3, DATA_HASH_TABLE=4, FIELD_HASH_TABLE=5, ENTRY_ARRAY=6, TAG=7 ) _ULInt64 = construct.ULInt64('int') _OBJECT_HEADER = construct.Struct( 'object_header', _OBJECT_HEADER_TYPE, construct.ULInt8('flags'), construct.Bytes('reserved', 6), construct.ULInt64('size') ) _OBJECT_HEADER_SIZE = _OBJECT_HEADER.sizeof() _DATA_OBJECT = construct.Struct( 'data_object', construct.ULInt64('hash'), construct.ULInt64('next_hash_offset'), construct.ULInt64('next_field_offset'), construct.ULInt64('entry_offset'), construct.ULInt64('entry_array_offset'), construct.ULInt64('n_entries') ) _DATA_OBJECT_SIZE = _DATA_OBJECT.sizeof() _ENTRY_ITEM = construct.Struct( 'entry_item', construct.ULInt64('object_offset'), construct.ULInt64('hash') ) _ENTRY_OBJECT = construct.Struct( 'entry_object', construct.ULInt64('seqnum'), construct.ULInt64('realtime'), construct.ULInt64('monotonic'), construct.Struct( 'boot_id', construct.Bytes('bytes', 16), construct.ULInt64('qword1'), construct.ULInt64('qword2')), construct.ULInt64('xor_hash'), construct.Rename('object_items', construct.GreedyRange(_ENTRY_ITEM)) ) _JOURNAL_HEADER = construct.Struct( 'journal_header', construct.Const(construct.String('signature', 8), b'LPKSHHRH'), construct.ULInt32('compatible_flags'), construct.ULInt32('incompatible_flags'), _JOURNAL_STATE, construct.Bytes('reserved', 7), construct.Bytes('file_id', 16), construct.Bytes('machine_id', 16), construct.Bytes('boot_id', 16), construct.Bytes('seqnum_id', 16), construct.ULInt64('header_size'), construct.ULInt64('arena_size'), construct.ULInt64('data_hash_table_offset'), construct.ULInt64('data_hash_table_size'), construct.ULInt64('field_hash_table_offset'), construct.ULInt64('field_hash_table_size'), construct.ULInt64('tail_object_offset'), construct.ULInt64('n_objects'), construct.ULInt64('n_entries'), construct.ULInt64('tail_entry_seqnum'), construct.ULInt64('head_entry_seqnum'), construct.ULInt64('entry_array_offset'), construct.ULInt64('head_entry_realtime'), construct.ULInt64('tail_entry_realtime'), construct.ULInt64('tail_entry_monotonic'), # Added in format version 187 construct.ULInt64('n_data'), construct.ULInt64('n_fields'), # Added in format version 189 construct.ULInt64('n_tags'), construct.ULInt64('n_entry_arrays') ) def __init__(self): """Initializes a parser object.""" super(SystemdJournalParser, self).__init__() self._max_journal_file_offset = 0 def _ParseObjectHeader(self, file_object, offset): """Parses a Systemd journal object header structure. Args: file_object (dfvfs.FileIO): a file-like object. offset (int): offset to the object header. Returns: tuple[construct.Struct, int]: parsed object header and size of the object payload (data) that follows. """ file_object.seek(offset, os.SEEK_SET) object_header_data = file_object.read(self._OBJECT_HEADER_SIZE) object_header = self._OBJECT_HEADER.parse(object_header_data) payload_size = object_header.size - self._OBJECT_HEADER_SIZE return (object_header, payload_size) def _ParseItem(self, file_object, offset): """Parses a Systemd journal DATA object. This method will read, and decompress if needed, the content of a DATA object. Args: file_object (dfvfs.FileIO): a file-like object. offset (int): offset to the DATA object. Returns: tuple[str, str]: key and value of this item. Raises: ParseError: When an unexpected object type is parsed. """ object_header, payload_size = self._ParseObjectHeader(file_object, offset) file_object.read(self._DATA_OBJECT_SIZE) if object_header.type != 'DATA': raise errors.ParseError( 'Expected an object of type DATA, but got {0:s}'.format( object_header.type)) event_data = file_object.read(payload_size - self._DATA_OBJECT_SIZE) if object_header.flags & self._OBJECT_COMPRESSED_FLAG: event_data = lzma.decompress(event_data) event_string = event_data.decode('utf-8') event_key, event_value = event_string.split('=', 1) return (event_key, event_value) def _ParseJournalEntry(self, parser_mediator, file_object, offset): """Parses a Systemd journal ENTRY object. This method will generate an event per ENTRY object. Args: parser_mediator (ParserMediator): parser mediator. file_object (dfvfs.FileIO): a file-like object. offset (int): offset of the ENTRY object. Raises: ParseError: When an unexpected object type is parsed. """ object_header, payload_size = self._ParseObjectHeader(file_object, offset) entry_object_data = file_object.read(payload_size) entry_object = self._ENTRY_OBJECT.parse(entry_object_data) if object_header.type != 'ENTRY': raise errors.ParseError( 'Expected an object of type ENTRY, but got {0:s}'.format( object_header.type)) fields = {} for item in entry_object.object_items: if item.object_offset < self._max_journal_file_offset: raise errors.ParseError( 'object offset should be after hash tables ({0:d} < {1:d})'.format( offset, self._max_journal_file_offset)) key, value = self._ParseItem(file_object, item.object_offset) fields[key] = value reporter = fields.get('SYSLOG_IDENTIFIER', None) if reporter and reporter != 'kernel': pid = fields.get('_PID', fields.get('SYSLOG_PID', None)) else: pid = None event_data = SystemdJournalEventData() event_data.body = fields['MESSAGE'] event_data.hostname = fields['_HOSTNAME'] event_data.pid = pid event_data.reporter = reporter date_time = dfdatetime_posix_time.PosixTimeInMicroseconds( timestamp=entry_object.realtime) event = time_events.DateTimeValuesEvent( date_time, definitions.TIME_DESCRIPTION_WRITTEN) parser_mediator.ProduceEventWithEventData(event, event_data) def _ParseEntries(self, file_object, offset): """Parses Systemd journal ENTRY_ARRAY objects. Args: file_object (dfvfs.FileIO): a file-like object. offset (int): offset of the ENTRY_ARRAY object. Returns: list[dict]: every ENTRY objects offsets. Raises: ParseError: When an unexpected object type is parsed. """ entry_offsets = [] object_header, payload_size = self._ParseObjectHeader(file_object, offset) if object_header.type != 'ENTRY_ARRAY': raise errors.ParseError( 'Expected an object of type ENTRY_ARRAY, but got {0:s}'.format( object_header.type)) next_array_offset = self._ULInt64.parse_stream(file_object) entry_offests_numbers, _ = divmod((payload_size - 8), 8) for entry_offset in range(entry_offests_numbers): entry_offset = self._ULInt64.parse_stream(file_object) if entry_offset != 0: entry_offsets.append(entry_offset) if next_array_offset != 0: next_entry_offsets = self._ParseEntries(file_object, next_array_offset) entry_offsets.extend(next_entry_offsets) return entry_offsets def ParseFileObject(self, parser_mediator, file_object, **kwargs): """Parses a Systemd journal file-like object. Args: parser_mediator (ParserMediator): parser mediator. file_object (dfvfs.FileIO): a file-like object. Raises: UnableToParseFile: when the header cannot be parsed. """ try: journal_header = self._JOURNAL_HEADER.parse_stream(file_object) except construct.ConstructError as exception: raise errors.UnableToParseFile( 'Unable to parse journal header with error: {0!s}'.format(exception)) max_data_hash_table_offset = ( journal_header.data_hash_table_offset + journal_header.data_hash_table_size) max_field_hash_table_offset = ( journal_header.field_hash_table_offset + journal_header.field_hash_table_size) self._max_journal_file_offset = max( max_data_hash_table_offset, max_field_hash_table_offset) entries_offsets = self._ParseEntries( file_object, journal_header.entry_array_offset) for entry_offset in entries_offsets: try: self._ParseJournalEntry(parser_mediator, file_object, entry_offset) except errors.ParseError as exception: parser_mediator.ProduceExtractionError(( 'Unable to complete parsing journal file: {0:s} at offset ' '0x{1:08x}').format(exception, entry_offset)) return except construct.ConstructError as exception: raise errors.UnableToParseFile(( 'Unable to parse journal header at offset: 0x{0:08x} with ' 'error: {1:s}').format(entry_offset, exception))
return (message[0] == message_type and (content is None or content == message[1])) return _matcher _is_init_reply = _create_matcher(_INIT_RESPONSE, b'\x01') _is_keepalive_response = _create_matcher(_KEEPALIVE_RESPONSE, b'\x05') _is_uknown_message_error = _create_matcher(_UNKNOWN_MESSAGE_RESPONSE, b'\x85') _is_encryption_missing_error = _create_matcher(_ENCRYPTION_SETUP_RESPONSE, b'\x15') _is_encryption_setup_error = _create_matcher(_ENCRYPTION_SETUP_RESPONSE, b'\x14') _FREESTYLE_MESSAGE = construct.Struct( 'hid_report' / construct.Const(0, construct.Byte), 'message_type' / construct.Byte, 'command' / construct.Padded( 63, # command can only be up to 62 bytes, but one is used for length. construct.Prefixed(construct.Byte, construct.GreedyBytes)), ) _FREESTYLE_ENCRYPTED_MESSAGE = construct.Struct( 'hid_report' / construct.Const(0, construct.Byte), 'message_type' / construct.Byte, 'command' / construct.Padded( 63, # command can only be up to 62 bytes, but one is used for length. construct.GreedyBytes), ) _TEXT_COMPLETION_RE = re.compile(b'CMD (?:OK|Fail!)')
from glucometerutils.support import serial class Direction(enum.Enum): In = 0xa5 Out = 0xa3 def byte_checksum(data): return functools.reduce(operator.add, data) & 0xFF _PACKET = construct.Struct( 'data' / construct.RawCopy( construct.Struct( construct.Const(b'\x51'), 'command' / construct.Byte, 'message' / construct.Bytes(4), 'direction' / construct.Mapping(construct.Byte, {e: e.value for e in Direction}), ), ), 'checksum' / construct.Checksum(construct.Byte, byte_checksum, construct.this.data.data), ) _EMPTY_MESSAGE = 0 _CONNECT_REQUEST = 0x22 _VALID_CONNECT_RESPONSE = {0x22, 0x24, 0x54}
"type" / CompactUint, "data" / Optional(c.GreedyBytes), )), "value" / c.Prefixed(CompactUint, c.GreedyBytes), ) PsbtProprietaryKey = c.Struct( "prefix" / c.CString("utf-8"), "subtype" / CompactUint, "data" / Optional(c.GreedyBytes), ) PsbtSequence = c.FocusedSeq( "content", "content" / c.GreedyRange(PsbtKeyValue), c.Const(b"\0"), ) PsbtEnvelope = c.FocusedSeq( "sequences", "magic" / c.Const(b"psbt\xff"), "sequences" / c.GreedyRange(PsbtSequence), c.Terminated, ) Bip32Field = c.Struct( "fingerprint" / c.Bytes(4), "address_n" / c.GreedyRange(c.Int32ul), ) # fmt: on
ETHERNET_NETWORKING_FUNCTIONAL = 0x0f ATM_NETWORKING_FUNCTIONAL = 0x10 WIRELESS_HANDSET_CONTROL_MODEL_FUNCTIONAL = 0x11 MOBILE_DIRECT_LINE_MODEL_FUNCTIONAL = 0x12 MDLM_DETAIL_FUNCTIONAL = 0x13 DEVICE_MANAGEMENT_MODEL_FUNCTIONAL = 0x14 OBEX_FUNCTIONAL = 0x15 COMMAND_SET_FUCNTIONAL = 0x16 COMMAND_SET_DETAIL_FUNCTIONAL = 0x17 TELEPHONE_CONTROL_MODEL_FUNCTIONAL = 0x18 OBEX_SERVICE_IDENTIFIER_FUNCTIONAL = 0x19 NCM_FUNCTIONAL = 0x1A HeaderDescriptor = DescriptorFormat( "bLength" / construct.Const(5, construct.Int8ul), "bDescriptorType" / DescriptorNumber(CDCDescriptorNumbers.CS_INTERFACE), "bDescriptorSubtype" / DescriptorNumber(CDCDescriptorSubtypes.HEADER), "bcdCDC" / DescriptorField(description="CDC Version", default=1.1)) ACMFunctionalDescriptor = DescriptorFormat( "bLength" / construct.Const(4, construct.Int8ul), "bDescriptorType" / DescriptorNumber(CDCDescriptorNumbers.CS_INTERFACE), "bDescriptorSubtype" / DescriptorNumber( CDCDescriptorSubtypes.ABSTRACT_CONTROL_MANAGEMENT_FUNCTIONAL), "bmCapabilities" / DescriptorField(description="ACM Capabilities", default=0b0010)) UnionFunctionalDescriptor = DescriptorFormat( "bLength" / construct.Const(5, construct.Int8ul), "bDescriptorType" / DescriptorNumber(CDCDescriptorNumbers.CS_INTERFACE),
import construct as cst import time import sys con = cst.Container # alias HEADER = cst.Struct('pc_header', cst.Magic('\x00'), cst.Const(cst.UBInt8('lines'), 1), cst.UBInt8('address'), cst.Magic('\x03')) SER_STATUS = cst.BitStruct('serst', cst.Magic('\x01\x01\x00'), cst.Flag('schedule_enabled'), cst.Flag('ack_enabled'), cst.Flag('further_pages'), cst.Flag('interrupt_mode'), cst.Magic('\x00')) PAGE_IDX = cst.Bytes('page_num', 3) TEMPO = cst.BitStruct( 'tempo', cst.Magic('\x01\x01'), cst.Enum(cst.BitField('display_ctrl', 2), TIMED=0, FIXED_ON=1, FIXED_OFF=2), cst.Enum(cst.BitField('persist_time', 4), S2=1, S5=2, S10=3, S20=4, S30=5, S45=6, S60=7, S90=8, S120=9))
""" Handle packet data """ import attr import construct as cs from helper import Vector3 from constants import OpCode packet = cs.Struct( "head" / cs.Const(b"\x99\xAA"), "len" / cs.Int32sl, "opcode" / cs.Int32sl, # subsctract the 4 byte (opcode) + len 4 byte + len 4 id "rest_data" / cs.Bytes(cs.this.len - 8), "end" / cs.Const(b"\xAA\x99"), ) vector_packet = cs.Struct("X" / cs.Float32l, "Y" / cs.Float32l, "Z" / cs.Float32l) authentication_packet = cs.Struct( # "id" / cs.Int32sl, "username" / cs.PascalString(cs.Int32sl, "utf8"), ) """ TODO: find a way to re user packet parts """ send_vector_packet = cs.Struct( "head" / cs.Const(b"\x99\xAA"), "len" / cs.Int32sl, "opcode" / cs.Int32sl, # 4 "id" / cs.Int32sl, # 4
else: op = operator.add for b in data: yield op(b, rotation) % 256 rotation = (rotation + per_byte_adjustment) % 256 def create_rotator(inverse: bool): return lambda obj, ctx: bytes( rotate_bytes(obj, ctx.header.bytes_rotation, ctx.header.bytes_rotation, inverse)) PermalinkBinary = construct.FocusedSeq( "fields", schema_version=construct.Const(_CURRENT_SCHEMA_VERSION, construct.Byte), fields=construct.RawCopy( construct.Aligned( 3, construct.Struct( header=construct.BitStruct( has_seed_hash=construct.Rebuild( construct.Flag, construct.this._.seed_hash != None), bytes_rotation=construct.Rebuild( construct.BitsInteger(7), lambda ctx: single_byte_hash(ctx._.generator_params) >> 1, )), seed_hash=construct.If(construct.this.header.has_seed_hash, construct.Bytes(5)), randovania_version=construct.Bytes(4), # short git hash
import os import repoze.lru import signal import struct import sys import traceback import traffic_control # Control message for our protocol; first few bits are special as we have to # maintain compatibility with LTPv3 in the kernel (first bit must be 1); also # the packet must be at least 12 bytes in length, otherwise some firewalls # may filter it when used over port 53 ControlMessage = cs.Struct( "control", # Ensure that the first bit is 1 (L2TP control packet) cs.Const(cs.UBInt8("magic1"), 0x80), # Reduce conflict matching to other protocols as we run on port 53 cs.Const(cs.UBInt16("magic2"), 0x73A7), # Protocol version to allow future upgrades cs.UBInt8("version"), # Message type cs.UBInt8("type"), # Message data (with length prefix) cs.PascalString("data"), # Pad the message so it is at least 12 bytes long cs.Padding(lambda ctx: max(0, 6 - len(ctx["data"]))), ) # Unreliable messages (0x00 - 0x7F) CONTROL_TYPE_COOKIE = 0x01 CONTROL_TYPE_PREPARE = 0x02
PKT_READCFG=0x37, PKT_PARITYMODE=0x3F, PKT_WRITE_I2C=0x44, PKT_CLFCODECRESET=0x46, PKT_SETCODECRESET=0x47, PKT_DISCARDCODEC=0x48, PKT_DELAYNUS=0x49, PKT_DELAYNNS=0x4A, PKT_RTSTHRESH=0x4E, PKT_GAIN=0x4B) ControlPacketField = c.Enum(c.Byte, **ControlPacketFields) ############################################################################### # Generic Constructs GeneralPacket = c.Struct("START_BYTE" / c.Const(b'\x61'), "LENGTH" / c.Int16ub, "TYPE" / PacketType, "FIELDS" / c.Byte[c.this.LENGTH]) # Table 12 AMBE-3000R Version 2.2 ECMODE_IN = c.FlagsEnum( c.Int16ub, NS_ENABLE=(0x1 << 6), CP_SELECT=(0x1 << 7), CP_ENABLE=(0x1 << 8), ES_ENABLE=(0x1 << 9), DTX_ENABLE=(0x1 << 11), TD_ENABLE=(0x1 << 12), EC_ENABLE=(0x1 << 13), TS_ENABLE=(0x1 << 14), )
def __init__(self, const): self.const = const super().__init__(c.Optional(c.Const(const)))
"data" / c.GreedyBytes, )), "value" / c.Prefixed(CompactUint, c.GreedyBytes), "ofs" / c.Tell, ) Sequence = c.FocusedSeq("content", "content" / c.GreedyRange( c.FocusedSeq( "keyvalue", "terminator" / c.Peek(c.Byte), c.StopIf(c.this.terminator == 0), "keyvalue" / KeyValue, ) ), c.Const(b'\0'), ) PSBT = c.Struct( "magic" / c.Const(b'psbt'), "sep" / c.Const(b'\xff'), "general" / Sequence, "transaction" / c.RestreamData(c.this.general[0].value, Transaction), "inputs" / c.Array(c.len_(c.this.transaction.inputs), Sequence), "outputs" / c.Array(c.len_(c.this.transaction.outputs), Sequence), c.Terminated, ) # key-less format: ValueOnly = c.Prefixed(CompactUint, c.Struct(
class MasterBootRecord(BootRecord): _MBR_STRUCT = construct.Struct( "mbr", construct.HexDumpAdapter(construct.Bytes("bootloader_code", 440)), construct.Field('disk_signature', 4), construct.Padding(2), construct.Array( 4, construct.Struct( "partitions", construct.SLInt8("state"), construct.BitStruct( "beginning", construct.Octet("head"), construct.Bits("sect", 6), construct.Bits("cyl", 10), ), construct.Enum( construct.UBInt8("type"), Nothing=0x00, FAT12=0x01, XENIX_ROOT=0x02, XENIX_USR=0x03, FAT16_old=0x04, Extended_DOS=0x05, FAT16=0x06, FAT32=0x0b, FAT32_LBA=0x0c, NTFS=0x07, LINUX_SWAP=0x82, LINUX_NATIVE=0x83, PROTECTIVE_MBR=0xee, _default_=construct.Pass, ), construct.BitStruct( "ending", construct.Octet("head"), construct.Bits("sect", 6), construct.Bits("cyl", 10), ), construct.ULInt32( "sector_offset"), # offset from MBR in sectors construct.ULInt32("size"), # in sectors )), construct.Const(construct.Bytes("signature", 2), '55aa'.decode('hex')), ) def __init__(self, filePath, size, offset=None, whitelist=()): self._type = 'MBR' super(MasterBootRecord, self).__init__(filePath, size, offset, whitelist) def _parse(self): """ Main method in charge of parsing the MBR. It will try to parse the boot record according to documented known structure and extract the partition table disk signature and code section. It will then try to narrow down invariant code, hash it and match the hash against a whitelist. If no match was found, it will try some simple heuristics to detect malicious behaviours. Returns: nothing """ try: mbr = self._MBR_STRUCT.parse(self._raw) except construct.core.ConstructError as e: raise InvalidMBRError('Invalid MBR structure: {0}\n{1}'.format( e, hexdump(self._raw))) self._parsePartTable(mbr.partitions) # Windows stores the disk signature at 0x1B8, other MBRs seem to leave this area alone self._diskSignature = mbr.disk_signature # If code section is null, check for protective MBR signature (detected in partition table parsing). If found, # then the machine is likely using UEFI instead of BIOS to boot. If not, it could mean that the sample being # analyzed has been tampered by a bootkit if mbr.bootloader_code.encode('hex') == 440 * '00': if 'Protective MBR' in self._signature: self._signature.append('UEFI (no legacy boot code)') else: self._suspiciousBehaviour.append('Code section is null') else: expectedLoader, invariantCode = self._getInvariantCode( mbr.bootloader_code) codeHash = hashlib.sha256(invariantCode) self._matchHash(codeHash, expectedLoader) if len(self._signature) == 0: # No whitelisted signature matched, try some simple heuristics to flag this MBR as malicious # Note that the self._checkCode method is only given the "invariant" code section to help with the # disassembling. This will obviously leads to broken offsets, but it doesn't matter since the heuristics # don't use them. self._checkCode(invariantCode) def _parsePartTable(self, partitions): """ Private method that parses the partition table of the MBR. Updates self._partTable list. Args: partitions: Construct.Container object of the partition table Returns: nothing """ partNum = 0 for part in partitions: partNum += 1 # Assume a partition entry without size (in LBA) or type is invalid, and do not include it in the listing. if part.size != 0 and part.type != 'Nothing': self._partTable.append((partNum, part.state < 0, part.type, part.sector_offset, part.size)) else: self._logger.debug('Ignoring invalid partition: %s', part) # Early detection of protective MBR so that we don't try to make sense of the MBR partition table if part.type == 'PROTECTIVE_MBR' and partNum == 1: self._logger.debug( 'Protective MBR detected, MBR partition table should not be taken into account. ' 'GPT partition table parser not implemented yet') self._signature.append('Protective MBR') def _getInvariantCode(self, rawCode): """ Helper method that tries to narrow down "invariant code" which can be hashed and compared to well known signatures. Most MBRs have localized error strings which must be excluded from the hash computation because they may vary from a country to another. First, this method tries to detect what kind of MBR it is dealing with. Most of the time, it is enough to to look for some known hardcoded strings that identify "well known" MBR (such as Truecrypt, GRUB2, etc...). Then, this method finds where the strings are and "removes" them (as in "does not include them"). Finding these strings can be achieved by quickly studying the assembly code and looking for how these strings are echoed on screen at boot time (using interrupt 0x10). This research only needs to be done once for each type of MBR but requires an analyst to do it by static analysis. This script cannot take care of this. This method merely implements the results of such work. Currently supported MBR are: - Truecrypt - McAfee Endpoint Encryption (Safeboot) - GRUB2 - Windows (XP to 10) Args: rawCode: str of the code section Returns: 2-tuple (unicode string of expected loader, concatenated strings of invariant sections of code) """ # By default, assume all the MBR code section will be hashed. It is obviously wrong in most cases, but it allows # for a "default case" which will automatically matches no known hash in case something goes wrong with the # detection. codeStart = 0 codeEnd = len(rawCode) expectedLoader = None invariantCode = str() # TrueCrypt (detected with the hardcoded string following the first jump: " TrueCrypt Boot Loader") if rawCode[0x5:0x1b].encode('hex').upper( ) == '2054727565437279707420426F6F74204C6F61646572': # TrueCrypt uses hardcoded and not-localized error strings. Therefore every TrueCrypt MBR should have the # same code from start to end expectedLoader = 'TrueCrypt MBR' # MacAfee SafeBoot (detected with the hardcoded string following the first jump: "Safeboot ") elif rawCode[0x3:0xc].encode('hex').upper() == '53616665426F6F7420': # Two versions have been seen but both start with a jump to the same offset (0x26). # There are some strings at the of the code section but localization is unlikely so it will be assumed # to be hardcoded (until a localized version is found...). # Therefore, Safeboot code can be hashed from 0x26 to the end of code section invariantCode += rawCode[:0x3] # Hash the first JMP codeStart = 0x26 expectedLoader = 'Safeboot MBR' # GRUB (detected with the hardcoded string "GRUB " located at 0x188) elif rawCode[0x188:0x18d].encode('hex').upper() == '4752554220': # GRUB has some error strings but they are hardcoded and not localized so they can be included in the hash # computation. However GRUB can be installed on a disk (MBR) as well as on a partition (in a kind of VBR). # But in both cases the code used is the same. Since a BPB is needed for the latter case it is also present # in the MBR (but not needed). It therefore has to be excluded from the hash computation. # GRUB is jumping over the BIOS Parameter Block located between 0x3 and 0x5a. # It should be followed by the kernel address (word), kernel sector (dword), kernel sector high (dword) and # boot drive (byte). Therefore the code really starts at 0x65. # These values are hardcoded in boot.img and have little chance to change anytime soon. codeStart = 0x65 invariantCode += rawCode[:0x3] # Hash the first JMP expectedLoader = 'GRUB2 MBR' # Windows MBR cannot be detected with hardcoded strings, so they fall in the default case and further checks # are then made based on the hypothesis that this is indeed a Windows MBR. else: # Starting with NT5.0, the MBR contains localized strings which must be excluded from the hash computation. # These strings are located after the code, at 3 different offsets which can be calculated by adding 0x100 # to the values respectively stored in bytes 0x1b5, 0x1b6 and 0x1b7 (last bytes of the code section). # Eg: The first localized string is at : 0x100 + the value saved at offset 0x1B5 # Even though localized strings can be of different lengths, the offset of the first one does not vary # given one Windows version. This can therefore be used to tell Windows versions apart. firstStrOffset = construct.UBInt8('FirstStringOffset').parse( rawCode[0x1b5]) # Windows NT5 if firstStrOffset == 0x2c: expectedLoader = 'NT5.1/NT5.2 MBR' codeEnd = 0x100 + firstStrOffset # Windows NT6.0 elif firstStrOffset == 0x62: expectedLoader = 'NT6.0 MBR' codeEnd = 0x100 + firstStrOffset # Windows NT6.1+ elif firstStrOffset == 0x63: expectedLoader = 'NT6.1+ MBR' codeEnd = 0x100 + firstStrOffset else: self._suspiciousBehaviour.append( 'Invalid string offset: {0:#x}'.format(firstStrOffset)) self._logger.debug( 'First localized string offset is wrong for a windows MBR.' 'It should be 0x2c, 0x62 or 0x63) : {0:#x}'.format( firstStrOffset)) self._logger.debug( 'Expecting {0}. Code starts at {1:#x} and ends at {2:#x}'.format( expectedLoader, codeStart, codeEnd)) invariantCode += rawCode[codeStart:codeEnd] return expectedLoader, invariantCode def _checkCode(self, rawCode): md = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_16) md.detail = True checkJmp = True for i in md.disasm(rawCode, 0): # Check for JUMPs and CALLs before the first PUSH/RET. if checkJmp and len(i.groups) > 0: # Group check if available if hasattr(capstone.x86, 'X86_GRP_CALL') and hasattr( capstone.x86, 'X86_GRP_RET'): if capstone.x86.X86_GRP_CALL in i.groups or capstone.x86.X86_GRP_JUMP in i.groups: self._suspiciousBehaviour.append( 'JMP or CALL before relocation') checkJmp = False elif capstone.x86.X86_GRP_RET in i.groups: # Stop search after the first PUSH/RET checkJmp = False # Manual check in case capstone version doesn't support CALL and RET groups else: if i.mnemonic[0] == 'j' or i.mnemonic == 'call': self._suspiciousBehaviour.append( 'JMP or CALL before relocation') checkJmp = False elif i.mnemonic[:3] == 'ret': # Stop search after the first PUSH/RET checkJmp = False # Check for unknown interrupt if i.mnemonic == 'int' and i.bytes[1] not in (0x10, 0x13, 0x18, 0x1a): self._suspiciousBehaviour.append( 'Unknown Interrupt : {0:#x}'.format(i.bytes[1]))
command_prefix_construct = construct.Const(command_prefix, construct.Byte) return construct.Struct( 'data' / construct.RawCopy( construct.Struct( construct.Const(b'\x02'), # stx 'length' / construct.Rebuild( construct.Byte, lambda this: len(this.message) + 7), 'link_control' / link_control_construct, 'command_prefix' / command_prefix_construct, 'message' / construct.Bytes(lambda this: this.length - 7), construct.Const(b'\x03'), # etx ), ), 'checksum' / construct.Checksum(construct.Int16ul, lifescan.crc_ccitt, construct.this.data.data), ) COMMAND_SUCCESS = construct.Const(b'\x06') VERIO_TIMESTAMP = construct_extras.Timestamp( construct.Int32ul, epoch=946684800) # 2000-01-01 (not 2010) _GLUCOSE_UNIT_MAPPING_TABLE = { common.Unit.MG_DL: 0x00, common.Unit.MMOL_L: 0x01, } GLUCOSE_UNIT = construct.Mapping(construct.Byte, _GLUCOSE_UNIT_MAPPING_TABLE)
class VolumeBootRecord(BootRecord): _NTFS_VBR_STRUCT = construct.Struct( 'NTFS-VBR', construct.Field('JumpOverBPB', 3), construct.String("OemId", 8), construct.Struct( 'BiosParameterBlock', construct.ULInt16('SectorSize'), construct.ULInt8('SectorsPerCluster'), construct.Field('Reserved1', 2), construct.Field('MustBeZero1', 3), construct.Field('MustBeZero2', 2), construct.ULInt8('MediaDescriptor'), construct.Field('MustBeZero3', 2), construct.ULInt16('SectorsPerTrack'), construct.ULInt16('NumberOfHeads'), construct.ULInt32('HiddenSectors'), construct.Field('NotUsed1', 4), construct.Const(construct.Field('DriveNumber', 1), '80'.decode('hex')), construct.Field('Reserved2', 3), construct.ULInt64('TotalSectors'), construct.ULInt64('MFTCluster'), construct.ULInt64('MFTMirrCluster'), construct.SLInt8('ClustersPerMFTRecord'), construct.Field('NotUsed2', 3), construct.SLInt8('ClustersPerIdxBuffer'), construct.Field('NotUsed3', 3), construct.ULInt64('VolumneSN'), construct.Field('NotUsed4', 4), ), construct.HexDumpAdapter(construct.Bytes("Code", 426)), construct.Const(construct.Bytes("signature", 2), '55aa'.decode('hex')), ) _BITLOCKER_VBR_STRUCT = construct.Struct( 'FVE-VBR', construct.Field('JumpOverBPB', 3), construct.Const(construct.String("OemId", 8), '-FVE-FS-'.encode('utf8')), construct.Struct( 'BiosParameterBlock', construct.ULInt16('SectorSize'), construct.ULInt8('SectorsPerCluster'), construct.Field('Reserved1', 2), construct.Field('MustBeZero1', 3), construct.Field('MustBeZero2', 2), construct.ULInt8('MediaDescriptor'), construct.Field('MustBeZero3', 2), construct.ULInt16('SectorsPerTrack'), construct.ULInt16('NumberOfHeads'), construct.ULInt32('HiddenSectors'), construct.ULInt32('TotalSectors'), construct.ULInt32('SectorsPerFAT'), construct.ULInt16('FATFlags'), construct.ULInt16('Version'), construct.ULInt32('RootDirCluster'), construct.ULInt16('FSInfoSector'), construct.ULInt16('BackupSector'), construct.Field('Reserved2', 12), construct.Const(construct.Field('DriveNumber', 1), '80'.decode('hex')), construct.Field('Reserved3', 1), construct.Field('ExtendedBootSignature', 1), construct.ULInt32('VolumneSN'), construct.Const(construct.String("VolumeLabel", 11), 'NO NAME '.encode('utf8')), construct.Const(construct.String("SystemId", 8), 'FAT32 '.encode('utf8')), ), construct.HexDumpAdapter(construct.Bytes("Code1", 70)), construct.Field('BitlockerGUID', 16), construct.ULInt64('FVEMetadataBlockOffset1'), construct.ULInt64('FVEMetadataBlockOffset2'), construct.ULInt64('FVEMetadataBlockOffset3'), construct.HexDumpAdapter(construct.Bytes("Code2", 307)), construct.ULInt8('FirstStrOffset'), construct.ULInt8('SecondStrOffset'), construct.ULInt8('ThirdStrOffset'), construct.Const(construct.Bytes("signature", 2), '55aa'.decode('hex')), ) def __init__(self, filePath, size, offset=None, whitelist=()): self._type = 'VBR' super(VolumeBootRecord, self).__init__(filePath, size, offset, whitelist) def _parse(self): """ Main method in charge of parsing the VBR. It will try to parse the boot record according to known structures (NTFS and Bitlocker supported). It will then try to narrow down invariant code, hash it and match the hash against a whitelist. If no match was found, it will try some simple heuristics to detect malicious behaviours. Finally it will compare the HiddenSectors value in BPB to that of the record's dump offset. Returns: nothing """ try: # This will parse both NTFS and Vista bitlocker volumes since they only differ by their OEM ID vbr = self._NTFS_VBR_STRUCT.parse(self._raw) expectedLoader, invariantCode = self._getInvariantCode('NTFS', vbr) except construct.core.ConstructError as e1: # Retry with Bitlocker (Win7+) volume header structure try: vbr = self._BITLOCKER_VBR_STRUCT.parse(self._raw) expectedLoader, invariantCode = self._getInvariantCode( 'bitlocker', vbr) except construct.core.ConstructError as e2: raise InvalidVBRError( 'Invalid VBR structure: e1={0}, e2={1}\n{2}'.format( e1, e2, hexdump(self._raw))) self._oemId = vbr.OemId self._bpb = vbr.BiosParameterBlock codeHash = hashlib.sha256(invariantCode) self._matchHash(codeHash, expectedLoader) # If no whitelisted signature matched, try some simple heuristics to flag this VBR as malicious # Note that the self._checkCode method is only given the "invariant" code section to help with the # disassembling. This will obviously leads to broken offsets, but it doesn't matter since the heuristics don't # use them. if len(self._signature) == 0: self._checkCode(invariantCode) # At last, compare the offset at which this VBR was found with the value of the BPB HiddenSectors if self._offset is not None \ and (vbr.BiosParameterBlock.HiddenSectors * vbr.BiosParameterBlock.SectorSize) != self._offset: self._suspiciousBehaviour.append( 'Suspicious HiddenSectors value: {0} ({1} bytes)'.format( vbr.BiosParameterBlock.HiddenSectors, vbr.BiosParameterBlock.HiddenSectors * vbr.BiosParameterBlock.SectorSize)) def _getInvariantCode(self, vbrType, vbrStruct): """ Helper method that finds all the sections of the boot code that can be hashed and compared to a whitelist. This means that localized strings and other variable parameters (BPB, etc...) are excluded. Currently, this method only supports NTFS and Bitlocker VBR. Args: vbrType: unicode string corresponding to the VBR type ('NTFS' or 'bitlocker') vbrStruct: construct.container of the VBR Returns: 2-tuple (unicode string of expected loader, concatenated strings of invariant sections of code) """ codeStart = 0 codeEnd = None invariantCode = str() expectedLoader = None if vbrType == 'NTFS': # The first three bytes are a jump over the NTFS BPB to where the code really starts (0x54) and a NOP invariantCode += vbrStruct.JumpOverBPB codeStart = 0x54 # NTFS VBR contains localized strings which must be excluded from the hash computation. # Before Windows 8, these strings are located at 4 different offsets which can be calculated by adding # 0x100 to the values respectively stored in bytes 0x1f8, 0x1f9, 0x1fa and 0x1fb. # Starting from Windows 8, these strings are located at 3 different offsets which are directly stored in # little endian words respectively at 0x1f6, 0x1f8 and 0x1fa # Since there is no easy way to tell which version of Windows we are dealing with beforehand, we first # assume it is a Windows < 8 by testing 0x1f8 against all the known first offset. If all tests fail, assume # it is Windows >= 8 and check 0x1f6 against the only known first offset (to date) firstStrOffset = construct.UBInt8('FirstStringOffset').parse( self._raw[0x1f8]) # Windows NT5 if firstStrOffset == 0x83: expectedLoader = 'NT5.1/NT5.2 VBR' codeEnd = 0x100 + firstStrOffset # Windows NT6.0 elif firstStrOffset == 0x80: expectedLoader = 'NT6.0 VBR' codeEnd = 0x100 + firstStrOffset # Windows NT6.1 elif firstStrOffset == 0x8c: expectedLoader = 'NT6.1 VBR' codeEnd = 0x100 + firstStrOffset # Windows NT6.2+ else: firstStrOffset = construct.ULInt16('FirstStringOffset').parse( self._raw[0x1f6:0x1f8]) if firstStrOffset == 0x18a: expectedLoader = 'NT6.2+ VBR' codeEnd = firstStrOffset if codeEnd is None: self._suspiciousBehaviour.append( 'Invalid string offset: {0:#x}'.format(firstStrOffset)) self._logger.debug( 'First localized string offset is wrong for a NTFS VBR: {0:#x}. ' 'It should be 0x83, 0x80, 0x8c or 0x18a.'.format( firstStrOffset)) codeEnd = 0 elif vbrType == 'bitlocker': expectedLoader = 'NT6.1+ Bitlocker VBR' # The first three bytes are a jump over the NTFS BPB to where the code really starts (0x5A) and a NOP invariantCode += vbrStruct.JumpOverBPB # First section of code (_BITLOCKER_VBR_STRUCT.Code1) invariantCode += vbrStruct.Code1 # In the second section of code, there are localized strings which must be excluded from hash computation. # Their offsets are stored in the last 3 bytes before the VBR signature (0x55aa). # For Windows 8, 8.1 and 10, the first string offset seems to always be 0x100 (ie. FirstStrOffset = 0x00) if vbrStruct.FirstStrOffset != 0: self._suspiciousBehaviour.append( 'Invalid string offset: {0:#x}'.format( vbrStruct.FirstStrOffset)) self._logger.debug( 'First localized string offset is wrong for a Bitlocker VBR. ' 'It should be 0x00) : {0:#x}'.format( vbrStruct.FirstStrOffset)) codeStart = 0xc8 # Offset of Code2 codeEnd = 0x100 + vbrStruct.FirstStrOffset else: raise NotImplementedError( 'VBR type "{0}" is not implemented yet'.format(vbrType)) self._logger.debug( 'Expecting {0}. Code starts at {1:#x} and ends at {2:#x}'.format( expectedLoader, codeStart, codeEnd)) invariantCode += self._raw[codeStart:codeEnd] return expectedLoader, invariantCode def _checkCode(self, code): md = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_16) md.detail = True for i in md.disasm(code, 0): # Check for unknown interrupt if i.mnemonic == 'int' and i.bytes[1] not in (0x10, 0x13, 0x18, 0x1a): self._suspiciousBehaviour.append( 'Unknown Interrupt : {0:#x}'.format(i.bytes[1]))
construct.Struct( '', GUID('unknown1'), GUID('unknown2'), construct.Rename('blob_store', DPAPI_BLOB_STORE)))))) VAULT_POL = construct.Struct('VAULT_POL', construct.ULInt32('version'), GUID('guid'), construct.Rename('description', UNICODE_STRING), construct.ULInt32('unknown1'), construct.ULInt32('unknown2'), construct.ULInt32('unknown3'), construct.Rename('vpol_store', VAULT_POL_STORE)) # Key Data Blob Magic (KDBM). BCRYPT_KEY_DATA_BLOB_HEADER = construct.Struct( 'BCRYPT_KEY_DATA_BLOB_HEADER', construct.Const(construct.ULInt32('dwMagic'), 0x4d42444b), construct.ULInt32('dwVersion'), construct.ULInt32('cbKeyData')) BCRYPT_KEY_DATA_BLOB = construct.Struct( 'BCRYPT_KEY_DATA_BLOB', construct.Embed(BCRYPT_KEY_DATA_BLOB_HEADER), construct.Bytes('key', lambda ctx: ctx.cbKeyData)) BCRYPT_KEY_STORE = construct.Struct( 'BCRYPT_KEY_STORE', construct.ULInt32('size'), construct.Embed( construct.Union( '', construct.Bytes('raw', lambda ctx: ctx.size), construct.Embed( construct.Struct( '', construct.ULInt32('unknown1'), construct.ULInt32('unknown2'),
), construct.If( lambda ctx: ctx.image_descriptor.lct_flag, construct.Array( lambda ctx: pow(2, ctx.image_descriptor.lct_size + 1), construct.Array(3, construct.ULInt8('lct')), ), ), construct.ULInt8('lzw_min'), _get_data_subblocks('compressed_indices'), ) _application_extension = construct.Struct( 'application_extension', construct.Value('block_type', lambda ctx: 'application'), construct.Const(construct.ULInt8('block_size'), 11), construct.String('app_id', 8), construct.Bytes('app_auth_code', 3), _get_data_subblocks('app_data'), ) _comment_extension = construct.Struct( 'comment_extension', construct.Value('block_type', lambda ctx: 'comment'), _get_data_subblocks('comment'), ) _gce_extension = construct.Struct( 'gce_extension', construct.Value('block_type', lambda ctx: 'gce'), construct.Const(construct.ULInt8('block_size'), 4),
def _transform_vendor_trust(data: bytes) -> bytes: """Byte-swap and bit-invert the VendorTrust field. Vendor trust is interpreted as a bitmask in a 16-bit little-endian integer, with the added twist that 0 means set and 1 means unset. We feed it to a `BitStruct` that expects a big-endian sequence where bits have the traditional meaning. We must therefore do a bitwise negation of each byte, and return them in reverse order. This is the same transformation both ways, fortunately, so we don't need two separate functions. """ return bytes(~b & 0xFF for b in data)[::-1] # fmt: off Toif = c.Struct( "magic" / c.Const(b"TOI"), "format" / c.Enum(c.Byte, full_color=b"f", grayscale=b"g"), "width" / c.Int16ul, "height" / c.Int16ul, "data" / c.Prefixed(c.Int32ul, c.GreedyBytes), ) VendorTrust = c.Transformed( c.BitStruct( "reserved" / c.Default(c.BitsInteger(9), 0), "show_vendor_string" / c.Flag, "require_user_click" / c.Flag, "red_background" / c.Flag, "delay" / c.BitsInteger(4), ), _transform_vendor_trust, 2, _transform_vendor_trust, 2)
from pyscsi.pyscsi.scsi import SCSI from pyscsi.pyscsi.scsi_device import SCSIDevice from glucometerutils import common from glucometerutils import exceptions from glucometerutils.support import lifescan from glucometerutils.support import lifescan_binary_protocol # This device uses SCSI blocks as registers. _REGISTER_SIZE = 512 _PACKET = construct.Padded( _REGISTER_SIZE, lifescan_binary_protocol.LifeScanPacket(0x03, False)) _QUERY_REQUEST = construct.Struct( construct.Const(b'\xe6\x02'), 'selector' / construct.Enum(construct.Byte, serial=0x00, model=0x01, software=0x02), ) _QUERY_RESPONSE = construct.Struct( lifescan_binary_protocol.COMMAND_SUCCESS, 'value' / construct.CString(encoding='utf-16-le'), ) _READ_PARAMETER_REQUEST = construct.Struct( 'selector' / construct.Enum(construct.Byte, unit=0x04), ) _READ_UNIT_RESPONSE = construct.Struct( lifescan_binary_protocol.COMMAND_SUCCESS, 'unit' / lifescan_binary_protocol.GLUCOSE_UNIT,