コード例 #1
0
ファイル: mst.py プロジェクト: scieloorg/ioisis
 def create_xrf_struct(self, control_record):
     shift = control_record.shift
     Int32s, BitStructWrapper = {
         "big": (Int32sb, lambda x: x),
         "little": (Int32sl, ByteSwapped),
     }[self.endianness]
     return FocusedSeq(
         "data",
         "data" / DictSegSeq(
             idx_field=Int32s,
             subcon=BitStructWrapper(
                 BitStruct(
                     "block" /
                     Default(BitsInteger(21 + shift, signed=True), 0),
                     "is_new" / Default(Flag, False),
                     "is_updated" / Default(Flag, False),
                     "offset" / Default(
                         ExprAdapter(
                             BitsInteger(9 - shift),
                             lambda obj, context: obj << shift,
                             lambda obj, context: obj >> shift,
                         ), 0),
                 )),
             block_size=127,  # Not counting the index field
             empty_item={},
             check_nonempty=lambda item: any([
                 item.block,
                 item.offset,
                 item.is_new,
                 item.is_updated,
             ]),
         ),
         Terminated,
     )
コード例 #2
0
ファイル: __init__.py プロジェクト: hao507/objutils
    def _parse_symbol_section(self, section):
        sh_link = section.sh_link
        if self.b64:
            pass
        else:
            pass
        Symbol = Struct(
            "st_name" / self.Word,
            "st_value" / self.Addr,
            "st_size" / self.Word,
            "st_info" / BitStruct(
                "st_bind" / BitsInteger(4),
                "st_type" / BitsInteger(4),
            ),
            "st_other" / Int8ul,
            "symbol_name" / Computed(lambda ctx: self.get_string(sh_link, ctx.st_name)),
            "st_shndx" / self.Half,
            "section_name" / Computed(lambda ctx: defs.section_name(ctx.st_shndx)),
             "hidden" / Computed(lambda ctx: ctx.st_other in
                 (defs.SymbolVisibility.STV_HIDDEN, defs.SymbolVisibility.STV_INTERNAL)),
        )
        """
        typedef struct {
            Elf32_Word  st_name;
            Elf32_Addr  st_value;
            Elf32_Word  st_size;
            unsigned char   st_info;
            unsigned char   st_other;
            Elf32_Half  st_shndx;
        } Elf32_Sym;

        typedef struct {
            Elf64_Word  st_name;
            unsigned char   st_info;
            unsigned char   st_other;
            Elf64_Half  st_shndx;
            Elf64_Addr  st_value;
            Elf64_Xword st_size;
        } Elf64_Sym;
        """
        num_symbols = len(section.image) // Symbol.sizeof()
        for offset in range(0, len(section.image), Symbol.sizeof()):
            sym = Symbol.parse(section.image[offset : offset + Symbol.sizeof()])
            db_sym = Elf_Symbol(st_name = sym.st_name, st_value = sym.st_value, st_size = sym.st_size,
                st_bind = sym.st_info.st_bind, st_type = sym.st_info.st_type, st_other = sym.st_other,
                st_shndx = sym.st_shndx, symbol_name = sym.symbol_name, section_name = sym.section_name,
                hidden = sym.hidden)
            self.session.add(db_sym)
        #print(db_sym)
        self.session.commit()
        query = self.session.query(Elf_Symbol)
        aaa = query.filter(Elf_Symbol.section_name == "SHN_ABS").all()
        print("SECTIONS",  [a.symbol_name for a in aaa])
コード例 #3
0
class KeyIndicesAdapter(Adapter):
    _subcon = GreedyRange(BitsInteger(12))

    def _decode(self, obj, context, path):
        """
        Flatten a list dictionaries into list of items:
            [{first=1, second=2}, {last=3}] -> [1, 2, 3]
        """
        ret = []
        for item in obj:
            if "last" in item:
                ret += [item["last"]]
            else:
                ret += [item["first"], item["second"]]
        return sorted(ret)

    def _encode(self, obj, context, path):
        """
        Expand a list into list of dictionaries:
            [1, 2, 3] -> [{first=1, second=2}, {last=3}]
        """
        ret = []
        obj.sort()
        while len(obj) > 1:
            ret += [dict(first=obj.pop(0), second=obj.pop(0))]

        if obj:
            ret += [dict(last=obj.pop())]

        return ret
コード例 #4
0
 def _parse_symbol_section(self, section):
     sh_link = section.sh_link
     symbols = []
     Symbol = Struct(
         "st_name" / self.Word,
         "st_value" / self.Addr,
         "st_size" / self.Word,
         "st_info" / BitStruct(
             "st_bind" / BitsInteger(4),
             "st_type" / BitsInteger(4),
         ),
         "st_other" / Int8ul,
         "symbol_name" /
         Computed(lambda ctx: self.get_string(sh_link, ctx.st_name)),
         "st_shndx" / self.Half,
     )
     symbol_cache = {}
     num_symbols = len(section.image) // Symbol.sizeof()
     for offset in range(0, len(section.image), Symbol.sizeof()):
         sym = Symbol.parse(section.image[offset:offset + Symbol.sizeof()])
         section_header = None
         if sym.st_shndx in defs.SpecialSections:
             section_name = defs.special_section_name(sym.st_shndx)
         else:
             if not sym.st_shndx in symbol_cache:
                 section_header = self.session.query(model.Elf_Section).\
                     filter(model.Elf_Section.index == sym.st_shndx).first()
                 if section_header:
                     section_name = section_header.section_name
                 else:
                     section_name = str(sym.st_shndx)
         db_sym = model.Elf_Symbol(
             st_name=sym.st_name,
             st_value=sym.st_value,
             st_size=sym.st_size,
             st_bind=sym.st_info.st_bind,
             st_type=sym.st_info.st_type,
             st_other=sym.st_other,
             st_shndx=sym.st_shndx,
             symbol_name=sym.symbol_name,
             section_name=section_name,
             access=section_header.sh_flags if section_header else 0)
         symbols.append(db_sym)
     self.session.bulk_save_objects(symbols)
     self.session.commit()
コード例 #5
0
 def generate_register_ctrl_meas(mode_enum: Bme280SensorMode, temperature_oversampling: int, # noqa: MC0001
                                 pressure_oversampling: int) -> None:
     # Set temperature oversampling
     if temperature_oversampling == 16:
         osrs_t = 0b101
     elif temperature_oversampling == 8:
         osrs_t = 0b100
     elif temperature_oversampling == 4:
         osrs_t = 0b011
     elif temperature_oversampling == 2:
         osrs_t = 0b010
     elif temperature_oversampling == 1:
         osrs_t = 0b001
     elif temperature_oversampling == 0:
         osrs_t = 0b000
     else:
         raise ConfigurationError(f"Pressure oversampling value {temperature_oversampling} is invalid!")
     # Set pressure oversampling
     if pressure_oversampling == 16:
         osrs_p = 0b101
     elif pressure_oversampling == 8:
         osrs_p = 0b100
     elif pressure_oversampling == 4:
         osrs_p = 0b011
     elif pressure_oversampling == 2:
         osrs_p = 0b010
     elif pressure_oversampling == 1:
         osrs_p = 0b001
     elif pressure_oversampling == 0:
         osrs_p = 0b000
     else:
         raise ConfigurationError(f"Pressure oversampling value {pressure_oversampling} is invalid!")
     # Determine operation mode
     if mode_enum is Bme280SensorMode.NORMAL:
         mode = 0b11
     elif mode_enum is Bme280SensorMode.FORCED:
         mode = 0b01
     elif mode_enum is Bme280SensorMode.SLEEP:
         mode = 0b00
     else:
         raise ConfigurationError(f"Measurement mode {mode_enum.name} is undefined!")
     # Concatenate bit sequences
     ctrl_meas_struct = BitStruct("osrs_t" / BitsInteger(3), "osrs_p" / BitsInteger(3), "mode" / BitsInteger(2))
     ctrl_meas_byte = ctrl_meas_struct.build({"osrs_t": osrs_t, "osrs_p": osrs_p, "mode": mode})
     return int.from_bytes(ctrl_meas_byte, endianness)
コード例 #6
0
 def generate_register_config(standby_time: float, irr_filter_coefficient: int) -> int:
     # Set the standby time
     if standby_time == 1000:
         t_sb = 0b101
     elif standby_time == 500:
         t_sb = 0b100
     elif standby_time == 250:
         t_sb = 0b011
     elif standby_time == 125:
         t_sb = 0b010
     elif standby_time == 62.5:
         t_sb = 0b001
     elif standby_time == 20:
         t_sb = 0b111
     elif standby_time == 10:
         t_sb = 0b110
     elif standby_time == 0.5:
         t_sb = 0b000
     else:
         raise ConfigurationError(f"Standby time value {standby_time} is invalid!")
     # Set irr filter coefficient
     if irr_filter_coefficient == 16:
         irr_filter = 0b100
     elif irr_filter_coefficient == 8:
         irr_filter = 0b011
     elif irr_filter_coefficient == 4:
         irr_filter = 0b010
     elif irr_filter_coefficient == 2:
         irr_filter = 0b001
     elif irr_filter_coefficient == 0:
         irr_filter = 0b000
     else:
         raise ConfigurationError(f"IRR filter coefficient value {irr_filter_coefficient} is invalid!")
     # Disable SPI Interface
     spi3wire_enable = 0
     # Concatenate bit sequences
     config_byte_struct = BitStruct("t_sb" / BitsInteger(3),
                                    "irr_filter" / BitsInteger(3),
                                    "spi3wire_enable" / BitsInteger(2))
     config_byte = config_byte_struct.build({"t_sb": t_sb,
                                             "irr_filter": irr_filter,
                                             "spi3wire_enable": spi3wire_enable})
     return int.from_bytes(config_byte, endianness)
コード例 #7
0
ファイル: adapters.py プロジェクト: torretahacs/pai
def PGMFlags(count, start_index_from=1):
    return DictArray(
        count,
        start_index_from,
        Bitwise(
            Struct(
                "_index" / Computed(this._index + start_index_from),
                "fire_2_wires" / Default(Flag, False),
                "normally_closed" / Default(Flag, False),
                "_unknown1" / BitsInteger(1),
                "disabled" / ExprSymmetricAdapter(
                    Default(Flag, False), lambda obj, ctx: not obj
                ),  #  False when a relay is assigned
                "_unknown2" / BitsInteger(2),
                "timer_active" / Default(Flag, False),  # when timer is active
                "on" / Default(Flag, False),  # when is activated
                "time_left" /
                Bytewise(ByteSwapped(Default(Int24ub, 0))),  # byte in seconds
            ), ),
    )
コード例 #8
0
ファイル: packet.py プロジェクト: fvdpol/ViewSB
class USBTokenPacket(USBPacket):
    """ Class representing a token packet. """

    FIELDS = {'crc5', 'crc_valid'}

    DATA_FORMAT = BitsSwapped(
        BitStruct(
            "device_address" / BitsInteger(7),
            "endpoint_number" / BitsInteger(4),
            "crc5" / BitsInteger(5),
        ))

    def validate(self):
        #parsed = self.parse_data()
        # TODO: validate crc5
        pass

    def generate_summary(self):
        return "{} token".format(self.pid.summarize())

    def summarize_data(self, summary_length_bytes=8):
        # NOTE: summary_length_bytes is ignored for a token packet.
        return "address={}, endpoint=0x{:02x}, direction={}".format(
            self.device_address, self.endpoint_number, self.direction)

    def get_detail_fields(self):

        fields = {
            'Length': '{} bytes'.format(len(self.get_raw_data())),
            'PID': '{} (0x{:02x})'.format(self.pid.name, self.pid.value),
            'Device': '0x{:02x}'.format(self.device_address),
            'Endpoint': '0x{:02x}'.format(self.endpoint_number),
            'CRC5': '0x{:02x}'.format(self.crc5)
        }

        return [(self.generate_summary(), fields)]

    def get_raw_data(self):
        # device_address, endpoint, and crc5 are included in self.data.
        return b''.join([bytes([self.pid]), self.data])
コード例 #9
0
ファイル: packet.py プロジェクト: fvdpol/ViewSB
class USBStartOfFrame(USBPacket):
    """ Class representing a USB start-of-frame (pseudo) packet. """

    FIELDS = {'frame_number', 'crc5', 'crc_valid'}

    DATA_FORMAT = BitsSwapped(
        BitStruct(
            "frame_number" / BitsInteger(11),
            "crc5" / BitsInteger(5),
        ))

    def validate(self):
        #parsed = self.parse_data()
        # TODO: validate crc5
        pass

    def generate_summary(self):
        return "{}".format(self.pid.summarize())

    def summarize_data(self, summary_length_bytes=8):
        # NOTE: summary_length_bytes is ignored for a token packet.
        return "frame={}".format(self.frame_number)

    def get_detail_fields(self):

        fields = {
            'Length': '{} bytes'.format(len(self.get_raw_data())),
            'PID': '{} (0x{:02x})'.format(self.pid.name, self.pid.value),
            'Frame Number': '{:0d}'.format(self.frame_number),
            'CRC5': '0x{:02x}'.format(self.crc5)
        }

        return [(self.generate_summary(), fields)]

    def get_raw_data(self):
        # frame number, and crc5 are included in self.data.
        return b''.join([bytes([self.pid]), self.data])
コード例 #10
0
ファイル: parsers.py プロジェクト: Curtis-Davidson/pai
def get_user_definition(settings):
    if (
        settings.system_options.user_code_length_6
        or settings.system_options.user_code_length_flexible
    ):
        code = ExprAdapter(
            Bytes(3),
            lambda obj, path: binascii.hexlify(obj)
            .decode()
            .rstrip("0")
            .replace("a", "0")
            or None,
            lambda obj, path: binascii.unhexlify(obj.replace("0", "a")),
        )
    else:
        code = ExprAdapter(
            Bytes(3),
            lambda obj, path: binascii.hexlify(obj)
            .decode()
            .rstrip("0")
            .replace("a", "0")[:4]
            or None,
            lambda obj, path: binascii.unhexlify((obj + obj[:2]).replace("0", "a")),
        )

    return Struct(
        "code" / code,
        "options"
        / BitsSwapped(
            BitStruct(
                "type" / Enum(BitsInteger(2), FullMaster=0x3, Master=0x2, Regular=0x0),
                "duress" / Flag,
                "bypass" / Flag,
                "arm_only" / Flag,
                "stay_instant_arming" / Flag,
                "force_arming" / Flag,
                "all_subsystems" / Flag,
            )
        ),
        "partitions" / BitsSwapped(Bitwise(StatusFlags(8))),
        "access" / BitStruct("level" / Nibble, "schedule" / Nibble),
        "access_options" / Bytes(1),
        "card_serial_number" / Bytes(3),
    )
コード例 #11
0
def create_entry_chunk():
    a = Struct(
        DATEPACKED / BitStruct(
            "Isfut" / BitsInteger(length=1),
            "Reserved" / BitsInteger(length=5),
            "MicroSec" / BitsInteger(length=10),
            "MilliSec" / BitsInteger(length=10),
            "Second" / BitsInteger(length=6),
            "Minute" / BitsInteger(length=6),
            "Hour" / BitsInteger(length=5),
            DAY / RevBitsInteger(length=5),
            MONTH / RevBitsInteger(length=4),
            YEAR / RevBitsInteger(length=12),  # 64bit
        ),
        CLOSE / RevFormatField("<", "f"),
        OPEN / RevFormatField("<", "f"),
        HIGH / RevFormatField("<", "f"),
        LOW / RevFormatField("<", "f"),
        VOLUME / RevFormatField("<", "f"),  # 160
        "AUX1" / RevFormatField("<", "f"),
        "AUX2" / RevFormatField("<", "f"),
        "TERMINATOR" / RevFormatField("<", "f"),
    )
    return a
コード例 #12
0
 def parse_calibration_bytes(calibration_segment1: bytes, calibration_segment2: bytes) -> Bme280CalibrationData:
     # Parse bytes to container
     calibration_segment1_container = Bme280Reader.STRUCT_CALIBRATION1.parse(calibration_segment1)
     calibration_segment2_container = Bme280Reader.STRUCT_CALIBRATION2.parse(calibration_segment2)
     # Bit order from the sensor does not allow for parsing dig_H4 and dig_h5 inside of a BitStruct with BitsInteger
     # Required order is 0xE4,0xE5[right 4 Bits],0xE6,0xE5[left 4 Bits]
     reorder_struct = BitStruct("byte_0xE4" / BitsInteger(8), "bits_0xE5_right" / BitsInteger(4),
                                "byte_OxE6" / BitsInteger(8), "bits_0xE5_left" / BitsInteger(4))
     reorder_bitsegments = calibration_segment2_container.pop("misaligned_bitsegment")
     reorder_bitsegments.pop("_io")
     # Recreate bytes with correct order
     reordered_bytes = reorder_struct.build(reorder_bitsegments)
     # Parse the reordered bytes with a Bitstruct
     humidity_struct = BitStruct("dig_H4" / BitsInteger(12), "dig_H5" / BitsInteger(12))
     # Parse bytes to container
     humidity_container = humidity_struct.parse(reordered_bytes)
     # Unpack containers into dataclass
     calibration_dict = {**calibration_segment1_container, **calibration_segment2_container, **humidity_container}
     # Remove construct container _io object
     calibration_dict.pop("_io", None)
     return Bme280CalibrationData(**calibration_dict)
コード例 #13
0
 "unknown" / BitStruct(
     "unused" / Flag,  # bit 7
     Padding(6),
     "comflag" / Flag,  # bit 0
 ),
 "status" / Int8ul,
 "statusflags" / Int8ul * "unknown status flags",
 "pricnt" / Int8ul,
 "_icount" / Int16ul,
 "flags" / BitStruct(  # XXX: embedding BitStruct is not possible
     "iserror" / Flag,  # bit 7
     "disablestop" / Flag,  # bit 6
     Padding(1),
     "arith" / Flag,  # bit 4
     Padding(2),
     "_codesegment" / BitsInteger(2),  # bits 0…1
 ),
 "icount" / Computed(
     this._icount | (this.flags._codesegment << 16)
 ),  # XXX: byte-swapping 18 bit int is not possible? is codesegment low/high bits of icount?
 "module" / Int16ul,
 "pbase" / Int8ul,
 "c8k" / Int8ul,
 "lbase" / Int16ul,
 "ltop" / Int16ul,
 "lsTop" / Int16ul,
 "heap" / BitStruct(  # XXX: is this just a 16 bit pointer?
     "top" / BitsInteger(12),  # XXX: incorrect byte order
     "segment" / Nibble,  # bit 0…3
 ),
 Padding(4),
コード例 #14
0
PT_HELLO_SERVICE = 0x00
PT_CAPABILITIES_SERVICE = 0x01
PT_UE_REPORTS_SERVICE = 0x02

TLVS = Struct(
    "type" / Int16ub,
    "length" / Int16ub,
    "value" / Bytes(this.length - 4),
)

HEADER = Struct(
    "version" / Int8ub,
    "flags" / BitStruct("padding" / Padding(7), "msg_type" / Flag),
    "tsrc" / BitStruct(
        "crud_result" / BitsInteger(2),
        "action" / BitsInteger(14),
    ),
    "length" / Int32ub,
    "padding" / Bytes(2),
    "device" / Bytes(6),
    "seq" / Int32ub,
    "xid" / Int32ub,
)

PACKET = Struct(
    "version" / Int8ub,
    "flags" / BitStruct("padding" / Padding(7), "msg_type" / Flag),
    "tsrc" / BitStruct(
        "crud_result" / BitsInteger(2),
        "action" / BitsInteger(14),
コード例 #15
0
ファイル: packet.py プロジェクト: xartron/ViewSB
class USBSetupTransaction(USBTransaction):
    """
    Class describing a USB setup transaction, which is a specialized transaction that
    contains metadata for a control transfer.
    """

    FIELDS = {
        'request_direction', 'request_type', 'recipient', 'request_number',
        'value', 'index', 'request_length', 'handshake'
    }

    # Define the data format for setup packets.
    DATA_FORMAT = BitStruct(
        "request_direction" / BitsInteger(1), "request_type" / BitsInteger(2),
        "recipient" / BitsInteger(5), "request_number" / Bytewise(Byte),
        "value" / Bytewise(Int16ul), "index" / Bytewise(Int16ul),
        "request_length" / Bytewise(Int16ul))

    def validate(self):
        self.parse_data()
        self.parse_field_as_direction('request_direction')

        # Extract our stalled field from the data/handshake PIDs.
        self.stalled = (self.data_pid is USBPacketID.STALL) or (
            self.handshake is USBPacketID.STALL)

    @classmethod
    def from_setup_data(cls, setup_data, **fields):

        # Ensure our setup-data is byte compatible.
        setup_data = bytes(setup_data)

        # Break our setup data into its component pieces.
        request_type_composite, request, value, index, length = struct.unpack(
            "<BBHHH", setup_data)

        # Parse the request type bytes.
        direction = USBDirection.from_request_type(request_type_composite)
        request_type = USBRequestType.from_request_type(request_type_composite)
        recipient = USBRequestRecipient.from_request_type(
            request_type_composite)

        if 'endpoint_number' not in fields:
            fields['endpoint_number'] = 0

        if 'token' not in fields:
            fields['token'] = USBPacketID.SETUP

        if 'handshake' not in fields:
            fields['handshake'] = USBPacketID.ACK

        # Generate the setup transaction from the extracted data.
        transaction = USBSetupTransaction(direction=USBDirection.OUT,
                                          request_direction=direction,
                                          request_type=request_type,
                                          request_number=request,
                                          recipient=recipient,
                                          value=value,
                                          index=index,
                                          request_length=length,
                                          data=setup_data,
                                          **fields)
        return transaction

    def summarize(self):
        return "control request setup transaction for {} request".format(
            self.request_direction.name)

    def summarize_data(self, summary_length_bytes=8):
        return "value={:04x} index={:04x} length={:04x}".format(
            self.value, self.index, self.request_length)
コード例 #16
0
    "xid" / Int32ub,
    "device" / Bytes(6),
    "iface_id" / Int32ub,
    "sta" / Bytes(6),
    "flags" / BitStruct(
        "padding" / Padding(7),
        "ht_caps" / Flag
    ),
    "ht_caps_info" / BitStruct(
        "L_SIG_TXOP_Protection_Support" / Flag,
        "Forty_MHz_Intolerant" / Flag,
        "Reserved" / Flag,
        "DSSS_CCK_Mode_in_40_MHz" / Flag,
        "Maximum_AMSDU_Length" / Flag,
        "HT_Delayed_Block_Ack" / Flag,
        "Rx_STBC" / BitsInteger(2),
        "Tx_STBC" / Flag,
        "Short_GI_for_40_MHz" / Flag,
        "Short_GI_for_20_MHz" / Flag,
        "HT_Greenfield" / Flag,
        "SM_Power_Save" / BitsInteger(2),
        "Supported_Channel_Width_Set" / Flag,
        "LDPC_Coding_Capability" / Flag,
    ),
    "ssid" / Bytes(WIFI_NWID_MAXSIZE + 1)
)
PROBE_REQUEST.name = "probe_request"

PROBE_RESPONSE = Struct(
    "version" / Int8ub,
    "type" / Int8ub,
コード例 #17
0
# Contains definition of Space Packet, and its corresponding encoder and decoder
# CCSDS-133.0-B-1 standard

from dataclasses import dataclass
from enum import Enum
from typing import List

from construct import BitStruct, BitsInteger, Flag

MAX_APID_VAL = 2047
MAX_SEQ_NUM = 16383
MAX_BYTES_PER_PACKET = 65536
SPP_HEADER_BYTES = 6

SpacePacketHeader = BitStruct('ccsds_version' / BitsInteger(3),
                              'packet_type' / BitsInteger(1),
                              'sec_hdr_flag' / Flag, 'apid' / BitsInteger(11),
                              'seq_flags' / BitsInteger(2),
                              'packet_seq_count' / BitsInteger(14),
                              'data_length' / BitsInteger(16))


class SpacePacketType(Enum):
    TELECOMMAND = 0  # ground station to satellite
    TELEMETRY = 1  # satellite to ground station


class SpacePacketSequenceFlags(Enum):
    SEGMENT_CONTINUATION = 0
    SEGMENT_FIRST = 1
    SEGMENT_LAST = 2
コード例 #18
0
                            INCH_25=0x31,
                            INCH_25a=0x32,
                            INCH_26=0x33,
                            INCH_26a=0x34,
                            INCH_27=0x35,
                            INCH_27a=0x36,
                            SIZE_700C=0x37,
                            INCH_28=0x38,
                            INCH_28a=0x39,
                            INCH_29=0x3A,
                            INCH_29a=0x3B,
                            INCH_30=0x3C,
                            INCH_30a=0x3D),
    'Speedmeter' / BitStruct(
        'Speedmeter_Model' /
        Enum(BitsInteger(2), EXTERNAL=0b00, INTERNAL=0b01, MOTORPHASE=0b10),
        'Signals' / BitsInteger(6)), 'Checksum' / Byte)

# 53 0b 03 ff ff 64 06 14 0a 19 08 14 14 27
pedal_message = Struct(
    'pedal_message' / Const(b"\x53\x0B"),
    'pedal_type' / Enum(Byte,
                        NONE=0x00,
                        DH_SENSOR_12=0x01,
                        BB_SENSOR_32=0x02,
                        DOUBLE_SIGNAL_24=0x03),
    'designated_assist' / Enum(Byte,
                               MODE_0=0x00,
                               MODE_1=0x01,
                               MODE_2=0x02,
                               MODE_3=0x03,
コード例 #19
0
ファイル: parsers.py プロジェクト: Curtis-Davidson/pai
        Struct(
            "po"
            / BitStruct(
                "command" / Const(0x1, Nibble),
                "status"
                / Struct(
                    "reserved" / Flag,
                    "alarm_reporting_pending" / Flag,
                    "Winload_connected" / Flag,
                    "NeWare_connected" / Flag,
                ),
            ),
            "length" / PacketLength(Int8ub),
            "result"
            / BitStruct(
                "_not_used0" / BitsInteger(3),
                "neware_answer" / Flag,
                "_not_used1" / BitsInteger(4),
            ),
            "callback" / Int16ub,
        )
    ),
    "checksum" / PacketChecksum(Bytes(1)),
)

InitializeCommunication = Struct(
    "fields"
    / RawCopy(
        Struct(
            "po" / Struct("command" / Const(0x00, Int8ub)),
            "module_address" / Default(Int8ub, 0x00),  # (00= panel/module)
コード例 #20
0
    def _set_endian(self, endian):
        '''Instantiate constructors to given endianness'''
        # All constructors need to be instantiated before use by setting their
        # endianness. But only those that don't depend on endian-generic
        # constructors need to be explicitly instantiated to a given
        # endianness.
        logger.debug('Set PTP endianness')
        if endian == 'little':
            self._UInt8 = Int8ul
            self._UInt16 = Int16ul
            self._UInt32 = Int32ul
            self._UInt64 = Int64ul
            self._UInt128 = BitsInteger(128, signed=False, swapped=True)
            self._Int8 = Int8sl
            self._Int16 = Int16sl
            self._Int32 = Int32sl
            self._Int64 = Int64sl
            self._Int128 = BitsInteger(128, signed=True, swapped=True)
        elif endian == 'big':
            self._UInt8 = Int8ub
            self._UInt16 = Int16ub
            self._UInt32 = Int32ub
            self._UInt64 = Int64ub
            self._UInt128 = BitsInteger(128, signed=False, swapped=False)
            self._Int8 = Int8sb
            self._Int16 = Int16sb
            self._Int32 = Int32sb
            self._Int64 = Int64sb
            self._Int128 = BitsInteger(128, signed=True, swapped=False)
        elif endian == 'native':
            self._UInt8 = Int8un
            self._UInt16 = Int16un
            self._UInt32 = Int32un
            self._UInt64 = Int64un
            self._UInt128 = BitsInteger(128, signed=False)
            self._Int8 = Int8sn
            self._Int16 = Int16sn
            self._Int32 = Int32sn
            self._Int64 = Int64sn
            self._Int128 = BitsInteger(128, signed=True)
        else:
            raise PTPError(
                'Only little and big endian conventions are supported.')

        # Implicit instantiation. Needs to happen after the above.
        self._PTPString = self._PTPString()
        self._DateTime = self._DateTime()
        self._Parameter = self._Parameter()
        self._VendorExtensionID = self._VendorExtensionID()
        self._OperationCode = self._OperationCode()
        self._EventCode = self._EventCode()
        self._PropertyCode = self._PropertyCode()
        self._ObjectFormatCode = self._ObjectFormatCode()
        self._DeviceInfo = self._DeviceInfo()
        self._SessionID = self._SessionID()
        self._TransactionID = self._TransactionID()
        self._ObjectHandle = self._ObjectHandle()
        self._ResponseCode = self._ResponseCode()
        self._Event = self._Event()
        self._Response = self._Response()
        self._Operation = self._Operation()
        self._StorageID = self._StorageID()
        self._StorageIDs = self._StorageIDs()
        self._StorageType = self._StorageType()
        self._FilesystemType = self._FilesystemType()
        self._AccessCapability = self._AccessCapability()
        self._StorageInfo = self._StorageInfo()
        self._DataTypeCode = self._DataTypeCode()
        self._DataType = self._DataType()
        self._GetSet = self._GetSet()
        self._FormFlag = self._FormFlag()
        self._DevicePropDesc = self._DevicePropDesc()
        self._VendorExtensionMap = self._VendorExtensionMap()
        self._VendorExtensionMapArray = self._VendorExtensionMapArray()

        self._AssociationType = self._AssociationType()
        self._AssociationDesc = self._AssociationDesc()
        self._ProtectionStatus = self._ProtectionStatus()
        self._ObjectInfo = self._ObjectInfo()
コード例 #21
0
class PTP(object):
    '''Implement bare PTP device. Vendor specific devices should extend it.'''
    # Base PTP protocol transaction elements
    # --------------------------------------
    _UInt8 = Int8un
    _UInt16 = Int16un
    _UInt32 = Int32un
    _UInt64 = Int64un
    _UInt128 = BitsInteger(128)

    _Int8 = Int8sn
    _Int16 = Int16sn
    _Int32 = Int32sn
    _Int64 = Int64sn
    _Int128 = BitsInteger(128, signed=True)

    def _Parameter(self):
        '''Return desired endianness for Parameter'''
        return self._UInt32

    def _SessionID(self):
        '''Return desired endianness for SessionID'''
        return self._UInt32

    def _TransactionID(self):
        '''Return desired endianness for TransactionID'''
        return Enum(
            self._UInt32,
            default=Pass,
            NA=0xFFFFFFFF,
        )

    # TODO: Check if these Enums can be replaced with more general
    # associations. Or even with Python Enums. Otherwise there is always a risk
    # of a typo creeping in.
    def _OperationCode(self, **vendor_operations):
        '''Return desired endianness for known OperationCode'''
        return Enum(self._UInt16,
                    default=Pass,
                    Undefined=0x1000,
                    GetDeviceInfo=0x1001,
                    OpenSession=0x1002,
                    CloseSession=0x1003,
                    GetStorageIDs=0x1004,
                    GetStorageInfo=0x1005,
                    GetNumObjects=0x1006,
                    GetObjectHandles=0x1007,
                    GetObjectInfo=0x1008,
                    GetObject=0x1009,
                    GetThumb=0x100A,
                    DeleteObject=0x100B,
                    SendObjectInfo=0x100C,
                    SendObject=0x100D,
                    InitiateCapture=0x100E,
                    FormatStore=0x100F,
                    ResetDevice=0x1010,
                    SelfTest=0x1011,
                    SetObjectProtection=0x1012,
                    PowerDown=0x1013,
                    GetDevicePropDesc=0x1014,
                    GetDevicePropValue=0x1015,
                    SetDevicePropValue=0x1016,
                    ResetDevicePropValue=0x1017,
                    TerminateOpenCapture=0x1018,
                    MoveObject=0x1019,
                    CopyObject=0x101A,
                    GetPartialObject=0x101B,
                    InitiateOpenCapture=0x101C,
                    StartEnumHandles=0x101D,
                    EnumHandles=0x101E,
                    StopEnumHandles=0x101F,
                    GetVendorExtensionMapss=0x1020,
                    GetVendorDeviceInfo=0x1021,
                    GetResizedImageObject=0x1022,
                    GetFilesystemManifest=0x1023,
                    GetStreamInfo=0x1024,
                    GetStream=0x1025,
                    **vendor_operations)

    def _ResponseCode(self, **vendor_responses):
        '''Return desired endianness for known ResponseCode'''
        return Enum(self._UInt16,
                    default=Pass,
                    Undefined=0x2000,
                    OK=0x2001,
                    GeneralError=0x2002,
                    SessionNotOpen=0x2003,
                    InvalidTransactionID=0x2004,
                    OperationNotSupported=0x2005,
                    ParameterNotSupported=0x2006,
                    IncompleteTransfer=0x2007,
                    InvalidStorageId=0x2008,
                    InvalidObjectHandle=0x2009,
                    DevicePropNotSupported=0x200A,
                    InvalidObjectFormatCode=0x200B,
                    StoreFull=0x200C,
                    ObjectWriteProtected=0x200D,
                    StoreReadOnly=0x200E,
                    AccessDenied=0x200F,
                    NoThumbnailPresent=0x2010,
                    SelfTestFailed=0x2011,
                    PartialDeletion=0x2012,
                    StoreNotAvailable=0x2013,
                    SpecificationByFormatUnsupported=0x2014,
                    NoValidObjectInfo=0x2015,
                    InvalidCodeFormat=0x2016,
                    UnknownVendorCode=0x2017,
                    CaptureAlreadyTerminated=0x2018,
                    DeviceBusy=0x2019,
                    InvalidParentObject=0x201A,
                    InvalidDevicePropFormat=0x201B,
                    InvalidDevicePropValue=0x201C,
                    InvalidParameter=0x201D,
                    SessionAlreadyOpened=0x201E,
                    TransactionCanceled=0x201F,
                    SpecificationOfDestinationUnsupported=0x2020,
                    InvalidEnumHandle=0x2021,
                    NoStreamEnabled=0x2022,
                    InvalidDataset=0x2023,
                    **vendor_responses)

    def _EventCode(self, **vendor_events):
        '''Return desired endianness for known EventCode'''
        return Enum(self._UInt16,
                    default=Pass,
                    Undefined=0x4000,
                    CancelTransaction=0x4001,
                    ObjectAdded=0x4002,
                    ObjectRemoved=0x4003,
                    StoreAdded=0x4004,
                    StoreRemoved=0x4005,
                    DevicePropChanged=0x4006,
                    ObjectInfoChanged=0x4007,
                    DeviceInfoChanged=0x4008,
                    RequestObjectTransfer=0x4009,
                    StoreFull=0x400A,
                    DeviceReset=0x400B,
                    StorageInfoChanged=0x400C,
                    CaptureComplete=0x400D,
                    UnreportedStatus=0x400E,
                    **vendor_events)

    def _Event(self):
        return Struct(
            'EventCode' / self._EventCode,
            'SessionID' / self._SessionID,
            'TransactionID' / self._TransactionID,
            'Parameter' / Array(3, self._Parameter),
        )

    def _Response(self):
        return Struct(
            'ResponseCode' / self._ResponseCode,
            'SessionID' / self._SessionID,
            'TransactionID' / self._TransactionID,
            'Parameter' / Array(5, self._Parameter),
        )

    def _Operation(self):
        return Struct(
            'OperationCode' / self._OperationCode,
            'SessionID' / self._SessionID,
            'TransactionID' / self._TransactionID,
            'Parameter' / Array(5, self._Parameter),
        )

    def _PropertyCode(self, **vendor_properties):
        '''Return desired endianness for known OperationCode'''
        return Enum(self._UInt16,
                    default=Pass,
                    Undefined=0x5000,
                    BatteryLevel=0x5001,
                    FunctionalMode=0x5002,
                    ImageSize=0x5003,
                    CompressionSetting=0x5004,
                    WhiteBalance=0x5005,
                    RGBGain=0x5006,
                    FNumber=0x5007,
                    FocalLength=0x5008,
                    FocusDistance=0x5009,
                    FocusMode=0x500A,
                    ExposureMeteringMode=0x500B,
                    FlashMode=0x500C,
                    ExposureTime=0x500D,
                    ExposureProgramMode=0x500E,
                    ExposureIndex=0x500F,
                    ExposureBiasCompensation=0x5010,
                    DateTime=0x5011,
                    CaptureDelay=0x5012,
                    StillCaptureMode=0x5013,
                    Contrast=0x5014,
                    Sharpness=0x5015,
                    DigitalZoom=0x5016,
                    EffectMode=0x5017,
                    BurstNumber=0x5018,
                    BurstInterval=0x5019,
                    TimelapseNumber=0x501A,
                    TimelapseInterval=0x501B,
                    FocusMeteringMode=0x501C,
                    UploadURL=0x501D,
                    Artist=0x501E,
                    CopyrightInfo=0x501F,
                    **vendor_properties)

    # PTP Datasets for specific operations
    # ------------------------------------
    def _ObjectHandle(self):
        '''Return desired endianness for ObjectHandle'''
        return self._UInt32

    def _ObjectFormatCode(self, **vendor_object_formats):
        '''Return desired endianness for known ObjectFormatCode'''
        return Enum(
            self._UInt16,
            default=Pass,
            # Ancilliary
            UndefinedAncilliary=0x3000,
            Association=0x3001,
            Script=0x3002,
            Executable=0x3003,
            Text=0x3004,
            HTML=0x3005,
            DPOF=0x3006,
            AIFF=0x3007,
            WAV=0x3008,
            MP3=0x3009,
            AVI=0x300A,
            MPEG=0x300B,
            ASF=0x300C,
            QT=0x300D,
            # Images
            UndefinedImage=0x3800,
            EXIF_JPEG=0x3801,
            TIFF_EP=0x3802,
            FlashPix=0x3803,
            BMP=0x3804,
            CIFF=0x3805,
            GIF=0x3807,
            JFIF=0x3808,
            PCD=0x3809,
            PICT=0x380A,
            PNG=0x380B,
            TIFF=0x380D,
            TIFF_IT=0x380E,
            JP2=0x380F,
            JPX=0x3810,
            DNG=0x3811,
            **vendor_object_formats)

    def _DateTime(self):
        '''Return desired endianness for DateTime'''
        return ExprAdapter(
            self._PTPString,
            encoder=lambda obj, ctx:
            # TODO: Support timezone encoding.
            datetime.strftime(obj, '%Y%m%dT%H%M%S.%f')[:-5],
            decoder=lambda obj, ctx: iso8601(obj),
        )

    def _PTPString(self):
        '''Returns a PTP String constructor'''
        return ExprAdapter(
            PrefixedArray(self._UInt8, self._UInt16),
            encoder=lambda obj, ctx: []
            if len(obj) == 0 else [ord(c) for c in six.text_type(obj)] + [0],
            decoder=lambda obj, ctx: u''.join([six.unichr(o)
                                               for o in obj]).split('\x00')[0],
        )

    def _PTPArray(self, element):
        return PrefixedArray(self._UInt32, element)

    def _VendorExtensionID(self):
        return Enum(
            self._UInt32,
            default=Pass,
            EastmanKodak=0x00000001,
            SeikoEpson=0x00000002,
            Agilent=0x00000003,
            Polaroid=0x00000004,
            AgfaGevaert=0x00000005,
            Microsoft=0x00000006,
            Equinox=0x00000007,
            Viewquest=0x00000008,
            STMicroelectronics=0x00000009,
            Nikon=0x0000000A,
            Canon=0x0000000B,
            FotoNation=0x0000000C,
            PENTAX=0x0000000D,
            Fuji=0x0000000E,
            Sony=0x00000011,  # Self-imposed.
            Samsung=0x0000001A,
            Parrot=0x0000001B,
        )

    def _DeviceInfo(self):
        '''Return desired endianness for DeviceInfo'''
        return Struct(
            'StandardVersion' / self._UInt16,
            'VendorExtensionID' / self._VendorExtensionID,
            'VendorExtensionVersion' / self._UInt16,
            'VendorExtensionDesc' / self._PTPString,
            'FunctionalMode' / self._UInt16,
            'OperationsSupported' / self._PTPArray(self._OperationCode),
            'EventsSupported' / self._PTPArray(self._EventCode),
            'DevicePropertiesSupported' / self._PTPArray(self._PropertyCode),
            'CaptureFormats' / self._PTPArray(self._ObjectFormatCode),
            'ImageFormats' / self._PTPArray(self._ObjectFormatCode),
            'Manufacturer' / self._PTPString,
            'Model' / self._PTPString,
            'DeviceVersion' / self._PTPString,
            'SerialNumber' / self._PTPString,
        )

    def _StorageType(self):
        '''Return desired endianness for StorageType'''
        return Enum(
            self._UInt16,
            default=Pass,
            Undefined=0x0000,
            FixedROM=0x0001,
            RemovableROM=0x0002,
            FixedRAM=0x0003,
            RemovableRAM=0x0004,
        )

    def _FilesystemType(self, **vendor_filesystem_types):
        '''Return desired endianness for known FilesystemType'''
        return Enum(self._UInt16,
                    default=Pass,
                    Undefined=0x0000,
                    GenericFlat=0x0001,
                    GenericHierarchical=0x0002,
                    DCF=0x0003,
                    **vendor_filesystem_types)

    def _AccessCapability(self):
        '''Return desired endianness for AccessCapability'''
        return Enum(
            self._UInt16,
            default=Pass,
            ReadWrite=0x0000,
            ReadOnlyWithoutObjectDeletion=0x0001,
            ReadOnlyWithObjectDeletion=0x0002,
        )

    def _StorageInfo(self):
        '''Return desired endianness for StorageInfo'''
        return Struct(
            'StorageType' / self._StorageType,
            'FilesystemType' / self._FilesystemType,
            'AccessCapability' / self._AccessCapability,
            'MaxCapacity' / self._UInt64,
            'FreeSpaceInBytes' / self._UInt64,
            'FreeSpaceInImages' / self._UInt32,
            'StorageDescription' / self._PTPString,
            'VolumeLabel' / self._PTPString,
        )

    def _StorageID(self):
        '''Return desired endianness for StorageID'''
        # TODO: automatically set and parse PhysicalID and LogicalID
        return self._UInt32

    def _StorageIDs(self):
        '''Return desired endianness for StorageID'''
        # TODO: automatically set and parse PhysicalID and LogicalID
        return self._PTPArray(self._StorageID)

    def _DataTypeCode(self, **vendor_datatype_codes):
        '''Return desired endianness for DevicePropDesc'''
        return Enum(self._UInt16,
                    default=Pass,
                    Undefined=0x0000,
                    Int128=0x0009,
                    Int128Array=0x4009,
                    Int16=0x0003,
                    Int16Array=0x4003,
                    Int32=0x0005,
                    Int32Array=0x4005,
                    Int64=0x0007,
                    Int64Array=0x4007,
                    Int8=0x0001,
                    Int8Array=0x4001,
                    UInt128=0x000a,
                    UInt128Array=0x400a,
                    UInt16=0x0004,
                    UInt16Array=0x4004,
                    UInt32=0x0006,
                    UInt32Array=0x4006,
                    UInt64=0x0008,
                    UInt64Array=0x4008,
                    UInt8=0x0002,
                    UInt8Array=0x4002,
                    String=0xFFFF,
                    **vendor_datatype_codes)

    def _DataType(self, **vendor_datatypes):
        datatypes = {
            'Int128': self._Int128,
            'Int128Array': self._PTPArray(self._Int128),
            'Int16': self._Int16,
            'Int16Array': self._PTPArray(self._Int16),
            'Int32': self._Int32,
            'Int32Array': self._PTPArray(self._Int32),
            'Int64': self._Int64,
            'Int64Array': self._PTPArray(self._Int64),
            'Int8': self._Int8,
            'Int8Array': self._PTPArray(self._Int8),
            'UInt128': self._UInt128,
            'UInt128Array': self._PTPArray(self._UInt128),
            'UInt16': self._UInt16,
            'UInt16Array': self._PTPArray(self._UInt16),
            'UInt32': self._UInt32,
            'UInt32Array': self._PTPArray(self._UInt32),
            'UInt64': self._UInt64,
            'UInt64Array': self._PTPArray(self._UInt64),
            'UInt8': self._UInt8,
            'UInt8Array': self._PTPArray(self._UInt8),
            'String': self._PTPString,
        }
        datatypes.update(vendor_datatypes if vendor_datatypes else {})

        def DataTypeCode(ctx):
            # Try to get the DataTypeCode from the parent contexts up to 20
            # levels...
            for i in range(20):
                try:
                    return ctx.DataTypeCode
                except AttributeError:
                    ctx = ctx._

        return Switch(DataTypeCode, datatypes, default=Pass)

    def _GetSet(self):
        return Enum(
            self._UInt8,
            default=Pass,
            Get=0x00,
            GetSet=0x01,
        )

    def _FormFlag(self):
        return Enum(
            self._UInt8,
            default=Pass,
            NoForm=0x00,
            Range=0x01,
            Enumeration=0x02,
        )

    def _RangeForm(self, element):
        return Struct(
            'MinimumValue' / element,
            'MaximumValue' / element,
            'StepSize' / element,
        )

    def _EnumerationForm(self, element):
        return PrefixedArray(self._UInt16, element)

    def _Form(self, element):
        return Switch(
            lambda x: x.FormFlag,
            {
                'Range': 'Range' / self._RangeForm(element),
                'Enumeration': 'Enumeration' / self._EnumerationForm(element),
                'NoForm': Pass
            },
            default=Pass,
        )

    def _DevicePropDesc(self):
        '''Return desired endianness for DevicePropDesc'''
        return Struct('PropertyCode' / self._PropertyCode,
                      'DataTypeCode' / self._DataTypeCode,
                      'GetSet' / self._GetSet,
                      'FactoryDefaultValue' / self._DataType,
                      'CurrentValue' / self._DataType,
                      'FormFlag' / self._FormFlag,
                      'Form' / self._Form(self._DataType))

    def _ProtectionStatus(self):
        return Enum(
            self._UInt16,
            default=Pass,
            NoProtection=0x0000,
            ReadOnly=0x0001,
        )

    def _AssociationType(self, **vendor_associations):
        return Enum(self._UInt16,
                    default=Pass,
                    Undefined=0x0000,
                    GenericFolder=0x0001,
                    Album=0x0002,
                    TimeSequence=0x0003,
                    HorizontalPanoramic=0x0004,
                    VerticalPanoramic=0x0005,
                    Panoramic2D=0x0006,
                    AncillaryData=0x0007,
                    **vendor_associations)

    def _AssociationDesc(self, **vendor_associations):
        return Enum(self._UInt32,
                    default=Pass,
                    Undefined=0x00000000,
                    DefaultPlaybackData=0x00000003,
                    ImagesPerRow=0x00000006,
                    **vendor_associations)

    def _ObjectInfo(self):
        '''Return desired endianness for ObjectInfo'''
        return Struct(
            'StorageID' / self._StorageID,
            'ObjectFormat' / self._ObjectFormatCode,
            'ProtectionStatus' / self._ProtectionStatus,
            'ObjectCompressedSize' / self._UInt32,
            'ThumbFormat' / self._ObjectFormatCode,
            'ThumbCompressedSize' / self._UInt32,
            'ThumbPixWidth' / self._UInt32,
            'ThumbPixHeight' / self._UInt32,
            'ImagePixWidth' / self._UInt32,
            'ImagePixHeight' / self._UInt32,
            'ImageBitDepth' / self._UInt32,
            'ParentObject' / self._ObjectHandle,
            'AssociationType' / self._AssociationType,
            'AssociationDesc' / self._AssociationDesc,
            'SequenceNumber' / self._UInt32,
            'Filename' / self._PTPString,
            'CaptureDate' / self._DateTime,
            'ModificationDate' / self._DateTime,
            'Keywords' / self._PTPString,
        )

    def _VendorExtensionMap(self):
        '''Return desired endianness for VendorExtensionMap'''
        # TODO: Integrate vendor extensions and their Enums to parse Native
        # codes to their name.
        return Struct(
            'NativeCode' / self._UInt16,
            'MappedCode' / self._UInt16,
            'MappedVendorExtensionID' / self._VendorExtensionID,
        )

    def _VendorExtensionMapArray(self):
        '''Return desired endianness for VendorExtensionMapArray'''
        return PrefixedArray(
            self._UInt64,
            self._VendorExtensionMap,
        )

    # Helper to concretize generic constructors to desired endianness
    # ---------------------------------------------------------------
    def _set_endian(self, endian):
        '''Instantiate constructors to given endianness'''
        # All constructors need to be instantiated before use by setting their
        # endianness. But only those that don't depend on endian-generic
        # constructors need to be explicitly instantiated to a given
        # endianness.
        logger.debug('Set PTP endianness')
        if endian == 'little':
            self._UInt8 = Int8ul
            self._UInt16 = Int16ul
            self._UInt32 = Int32ul
            self._UInt64 = Int64ul
            self._UInt128 = BitsInteger(128, signed=False, swapped=True)
            self._Int8 = Int8sl
            self._Int16 = Int16sl
            self._Int32 = Int32sl
            self._Int64 = Int64sl
            self._Int128 = BitsInteger(128, signed=True, swapped=True)
        elif endian == 'big':
            self._UInt8 = Int8ub
            self._UInt16 = Int16ub
            self._UInt32 = Int32ub
            self._UInt64 = Int64ub
            self._UInt128 = BitsInteger(128, signed=False, swapped=False)
            self._Int8 = Int8sb
            self._Int16 = Int16sb
            self._Int32 = Int32sb
            self._Int64 = Int64sb
            self._Int128 = BitsInteger(128, signed=True, swapped=False)
        elif endian == 'native':
            self._UInt8 = Int8un
            self._UInt16 = Int16un
            self._UInt32 = Int32un
            self._UInt64 = Int64un
            self._UInt128 = BitsInteger(128, signed=False)
            self._Int8 = Int8sn
            self._Int16 = Int16sn
            self._Int32 = Int32sn
            self._Int64 = Int64sn
            self._Int128 = BitsInteger(128, signed=True)
        else:
            raise PTPError(
                'Only little and big endian conventions are supported.')

        # Implicit instantiation. Needs to happen after the above.
        self._PTPString = self._PTPString()
        self._DateTime = self._DateTime()
        self._Parameter = self._Parameter()
        self._VendorExtensionID = self._VendorExtensionID()
        self._OperationCode = self._OperationCode()
        self._EventCode = self._EventCode()
        self._PropertyCode = self._PropertyCode()
        self._ObjectFormatCode = self._ObjectFormatCode()
        self._DeviceInfo = self._DeviceInfo()
        self._SessionID = self._SessionID()
        self._TransactionID = self._TransactionID()
        self._ObjectHandle = self._ObjectHandle()
        self._ResponseCode = self._ResponseCode()
        self._Event = self._Event()
        self._Response = self._Response()
        self._Operation = self._Operation()
        self._StorageID = self._StorageID()
        self._StorageIDs = self._StorageIDs()
        self._StorageType = self._StorageType()
        self._FilesystemType = self._FilesystemType()
        self._AccessCapability = self._AccessCapability()
        self._StorageInfo = self._StorageInfo()
        self._DataTypeCode = self._DataTypeCode()
        self._DataType = self._DataType()
        self._GetSet = self._GetSet()
        self._FormFlag = self._FormFlag()
        self._DevicePropDesc = self._DevicePropDesc()
        self._VendorExtensionMap = self._VendorExtensionMap()
        self._VendorExtensionMapArray = self._VendorExtensionMapArray()

        self._AssociationType = self._AssociationType()
        self._AssociationDesc = self._AssociationDesc()
        self._ProtectionStatus = self._ProtectionStatus()
        self._ObjectInfo = self._ObjectInfo()

    def __init__(self, *args, **kwargs):
        logger.debug('Init PTP')
        # Session and transaction helpers
        # -------------------------------
        self._session = 0
        self.__session_open = False
        self.__transaction_id = 1
        self.__has_the_knowledge = False
        super(PTP, self).__init__(*args, **kwargs)

    @property
    def _transaction(self):
        '''Give magical property for the latest TransactionID'''
        current_id = 0
        if self.__session_open:
            current_id = self.__transaction_id
            self.__transaction_id += 1
            if self.__transaction_id > 0xFFFFFFFE:
                self.__transaction_id = 1
        return current_id

    @_transaction.setter
    def _transaction(self, value):
        '''Manage reset of TransactionID'''
        if value != 1:
            raise PTPError(
                'Current TransactionID should not be set. Only reset.')
        else:
            self.__transaction_id = 1

    @property
    def session_id(self):
        '''Expose internat SessionID'''
        return self._session

    @session_id.setter
    def session_id(self, value):
        '''Ignore external modifications to SessionID'''
        pass

    @contextmanager
    def session(self):
        '''
        Manage session with context manager.

        Once transport specific interfaces are defined, this allows easier,
        more nuclear sessions:

            from ptpy import PTPy
            camera = PTPy()
            with camera.session():
                camera.get_device_info()
        '''
        # TODO: Deal with devices that only support one session (where
        # SessionID must be always 1, like some older Canon cameras.)
        # TODO: Deal with devices that only support one arbitrary session where
        # the ID is communicated to the initiator after an OpenSession attempt.
        # This might also account for the above.
        logger.debug('Session requested')
        if not self.__session_open:
            logger.debug('Open session')
            try:
                self.open_session()
                yield
            finally:
                logger.debug('Close session')
                if self.__session_open:
                    self.close_session()
        else:
            logger.debug('Using outer session')
            yield

    @contextmanager
    def open_capture(self):
        '''
        Manage open capture with context manager.

        This allows easier open capture with automatic closing
        '''
        # TODO: implement!

    # Transport-specific functions
    # ----------------------------
    def send(self, ptp_container, payload):
        '''Operation with dataphase from initiator to responder'''
        try:
            return super(PTP, self).send(ptp_container, payload)
        except Exception as e:
            logger.error(e)
            raise e

    def recv(self, ptp_container):
        '''Operation with dataphase from responder to initiator'''
        try:
            return super(PTP, self).recv(ptp_container)
        except Exception as e:
            logger.error(e)
            raise e

    def mesg(self, ptp_container):
        '''Operation with no dataphase'''
        try:
            return super(PTP, self).mesg(ptp_container)
        except Exception as e:
            logger.error(e)
            raise e

    def event(self, wait=False):
        try:
            return super(PTP, self).event(wait=wait)
        except Exception as e:
            logger.error(e)
            raise e

    # Operation-specific methods and helpers
    # --------------------------------------
    def _parse_if_data(self, response, constructor):
        '''If the response contains data, parse it with constructor.'''
        return (constructor.parse(response.Data)
                if hasattr(response, 'Data') else None)

    def _build_if_not_data(self, data, constructor):
        '''If the data is not binary, build it with constructor.'''
        return (constructor.build(data)
                if isinstance(data, Container) else data)

    def _name(self, name_or_code, constructor):
        '''Helper method to get the code for an Enum constructor.'''
        name = name_or_code
        if isinstance(name_or_code, int):
            try:
                name = constructor.decoding[name_or_code]
            except Exception:
                pass

        return name

    def _code(self, name_or_code, constructor):
        '''Helper method to get the code for an Enum constructor.'''
        if isinstance(name_or_code, six.string_types):
            try:
                code = constructor.encoding[name_or_code]
            except Exception:
                raise PTPError('Unknown property name. Try with a number?')
        else:
            code = name_or_code

        return code

    def _obtain_the_knowledge(self):
        '''Initialise an internal representation of device behaviour.'''
        logger.debug('Gathering info about all device properties')
        self.__device_info = self.get_device_info()
        self.__prop_desc = {}
        with self.session():
            for p in self.__device_info.DevicePropertiesSupported:
                # TODO: Update __prop_desc with arrival of events
                # transparently.
                self.__prop_desc[p] = self.get_device_prop_desc(p)
                # TODO: Get info regarding ObjectHandles here. And update as
                # events are received. This should be transparent for the user.

        self.__has_the_knowledge = True

    def _update_the_knowledge(self, props=None):
        '''Update an internal representation of device behaviour.'''
        logger.debug('Gathering info about extra device properties')
        with self.session():
            for p in props:
                self.__prop_desc[p] = self.get_device_prop_desc()
                self.__device_info.DevicePropertiesSupported.append(p)

    def open_session(self):
        self._session += 1
        self._transaction = 1
        ptp = Container(
            OperationCode='OpenSession',
            # Only the OpenSession operation is allowed to have a 0
            # SessionID, because no session is open yet.
            SessionID=0,
            TransactionID=0,
            Parameter=[self._session])
        response = self.mesg(ptp)
        if response.ResponseCode == 'OK':
            self.__session_open = True
        return response

    def close_session(self):
        ptp = Container(OperationCode='CloseSession',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[])
        response = self.mesg(ptp)
        if response.ResponseCode == 'OK':
            self.__session_open = False
        return response

    def reset_device(self):
        ptp = Container(
            OperationCode='ResetDevice',
            SessionID=self._session,
            TransactionID=self._transaction,
            Parameter=[],
        )
        response = self.recv(ptp)
        if response.ResponseCode == 'OK':
            self.__session_open = False
        return response

    def power_down(self):
        ptp = Container(
            OperationCode='PowerDown',
            SessionID=self._session,
            TransactionID=self._transaction,
            Parameter=[],
        )
        response = self.recv(ptp)
        if response.ResponseCode == 'OK':
            self.__session_open = False
        return response

    # TODO: Add decorator to check there is an open session.
    def reset_device_prop_value(self, device_property, reset_all=False):
        '''Reset given device property to factory default.

        If `reset_all` is `True`, the device_property can be `None`.
        '''
        if isinstance(device_property, six.string_types):
            try:
                code = self._PropertyCode.encoding[device_property]
            except Exception:
                raise PTPError('Unknown property name. Try with a number?')
        else:
            code = device_property

        ptp = Container(
            OperationCode='ResetDevicePropValue',
            SessionID=self._session,
            TransactionID=self._transaction,
            Parameter=[0xffffffff if reset_all else code],
        )
        response = self.recv(ptp)
        return response

    def get_device_info(self):
        ptp = Container(
            OperationCode='GetDeviceInfo',
            SessionID=self._session,
            # GetrDeviceInfo can happen outside a session. But if there is one
            # running just use that one.
            TransactionID=(self._transaction if self.__session_open else 0),
            Parameter=[])
        response = self.recv(ptp)
        return self._parse_if_data(response, self._DeviceInfo)

    def get_storage_ids(self):
        ptp = Container(OperationCode='GetStorageIDs',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[])
        response = self.recv(ptp)
        return self._parse_if_data(response, self._StorageIDs)

    def get_storage_info(self, storage_id):
        ptp = Container(OperationCode='GetStorageInfo',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[storage_id])
        response = self.recv(ptp)
        return self._parse_if_data(response, self._StorageInfo)

    def get_num_objects(
        self,
        storage_id,
        object_format=0,
        object_handle=0,
        all_storage_ids=False,
        all_formats=False,
        in_root=False,
    ):
        '''Total number of objects present in `storage_id`'''
        if object_handle != 0 and in_root and object_handle != 0xffffffff:
            raise ValueError(
                'Cannot get both root and {}'.format(object_handle))
        code = self._code(object_format, self._ObjectFormatCode)
        ptp = Container(OperationCode='GetNumObjects',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[
                            0xffffffff if all_storage_ids else storage_id,
                            0xffffffff if all_formats else code,
                            0xffffffff if in_root else object_handle
                        ])
        response = self.recv(ptp)
        return response.Parameter[0] if response.Parameter else None

    def get_object_handles(
        self,
        storage_id,
        object_format=0,
        object_handle=0,
        all_storage_ids=False,
        all_formats=False,
        in_root=False,
    ):
        '''Return array of ObjectHandles present in `storage_id`'''
        if object_handle != 0 and in_root and object_handle != 0xffffffff:
            raise ValueError(
                'Cannot get both root and {}'.format(object_handle))
        code = self._code(object_format, self._ObjectFormatCode)
        ptp = Container(OperationCode='GetObjectHandles',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[
                            0xffffffff if all_storage_ids else storage_id,
                            0xffffffff if all_formats else code,
                            0xffffffff if in_root else object_handle
                        ])
        response = self.recv(ptp)
        return self._parse_if_data(response,
                                   self._PTPArray(self._ObjectHandle))

    def __constructor(self, device_property):
        '''Get the correct constructor using the latest GetDevicePropDesc.'''
        builder = Struct(
            'DataTypeCode' / Computed(
                lambda ctx: self.__prop_desc[device_property].DataTypeCode),
            'Value' / self._DataType)
        return builder

    def get_device_prop_desc(self, device_property):
        '''Retrieve the property description.

        Accepts a property name or a number.
        '''
        code = self._code(device_property, self._PropertyCode)

        ptp = Container(OperationCode='GetDevicePropDesc',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[code])
        response = self.recv(ptp)
        result = self._parse_if_data(response, self._DevicePropDesc)
        # Update the knowledge on response.
        if self.__has_the_knowledge and hasattr(response, 'Data'):
            device_property = self._name(device_property, self._PropertyCode)
            logger.debug('Updating knowledge of {}'.format(
                hex(device_property) if isinstance(device_property, int
                                                   ) else device_property))
            self.__prop_desc[device_property] = result
        return result

    def get_device_prop_value(self, device_property):
        code = self._code(device_property, self._PropertyCode)

        ptp = Container(
            OperationCode='GetDevicePropValue',
            SessionID=self._session,
            TransactionID=self._transaction,
            Parameter=[code],
        )
        response = self.recv(ptp)
        if self.__has_the_knowledge and hasattr(response, 'Data'):
            device_property = self._name(device_property, self._PropertyCode)
            c = self.__constructor(device_property)
            response = c.parse(response.Data).Value
        return response

    def set_device_prop_value(self, device_property, value_payload):
        code = self._code(device_property, self._PropertyCode)

        # Attempt to use current knowledge of properties
        if self.__has_the_knowledge:
            device_property = self._name(device_property, self._PropertyCode)
            c = self.__constructor(device_property)
            value_payload = c.build(
                Container(Value=value_payload,
                          DataTypeCode=(
                              self.__prop_desc[device_property].DataTypeCode)))

        ptp = Container(
            OperationCode='SetDevicePropValue',
            SessionID=self._session,
            TransactionID=self._transaction,
            Parameter=[code],
        )
        response = self.send(ptp, value_payload)
        return response

    def initiate_capture(self, storage_id=0, object_format=0):
        '''Initiate capture with current camera settings.'''
        code = self._code(object_format, self._ObjectFormatCode)
        ptp = Container(OperationCode='InitiateCapture',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[
                            storage_id,
                            code,
                        ])
        response = self.recv(ptp)
        return response

    def initiate_open_capture(self, storage_id=0, object_format=0):
        '''Initiate open capture in `storage_id` of type `object_format`.'''
        code = self._code(object_format, self._ObjectFormatCode)
        ptp = Container(OperationCode='InitiateOpenCapture',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[
                            storage_id,
                            code,
                        ])
        response = self.recv(ptp)
        return response

    def terminate_open_capture(self, transaction_id):
        '''Terminate the open capture initiated in `transaction_id`'''
        ptp = Container(OperationCode='TerminateOpenCapture',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[
                            transaction_id,
                        ])
        response = self.recv(ptp)
        return response

    def get_object_info(self, handle):
        '''Get ObjectInfo dataset for given handle.'''
        ptp = Container(OperationCode='GetObjectInfo',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[handle])
        response = self.recv(ptp)
        return self._parse_if_data(response, self._ObjectInfo)

    def send_object_info(self, objectinfo):
        '''Send ObjectInfo to responder.

        The object should correspond to the latest SendObjectInfo interaction
        between Initiator and Responder.
        '''
        objectinfo = self._build_if_not_data(objectinfo, self._ObjectInfo)

        ptp = Container(OperationCode='SendObjectInfo',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[])

        return self.send(ptp, objectinfo)

    def send_object(self, bytes_data):
        '''Send object to responder.

        The object should correspond to the latest SendObjectInfo interaction
        between Initiator and Responder.
        '''
        ptp = Container(OperationCode='SendObject',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[])
        response = self.send(ptp, bytes_data)
        if response.ResponseCode != 'OK':
            response = self.send(ptp, bytes_data)
        return response

    def get_object(self, handle):
        '''Retrieve object from responder.

        The object should correspond to a previous GetObjectInfo interaction
        between Initiator and Responder in the same session.
        '''
        ptp = Container(OperationCode='GetObject',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[handle])
        return self.recv(ptp)

    def get_partial_object(self, handle, offset, max_bytes, until_end=False):
        '''Retrieve partial object from responder.

        The object should correspond to a previous GetObjectInfo interaction
        between Initiator and Responder in the same session.
        Size fields represent maximum size as opposed to the actual size.

        The first response parameter represents the actual number of bytes sent
        by responder.
        '''
        ptp = Container(
            OperationCode='GetPartialObject',
            SessionID=self._session,
            TransactionID=self._transaction,
            Parameter=[handle, offset, 0xFFFFFFFF if until_end else max_bytes])
        return self.recv(ptp)

    def delete_object(self,
                      handle,
                      object_format=0,
                      delete_all=False,
                      delete_all_images=False):
        '''Delete object for given handle.

        Optionally delete all objects or all images.
        '''
        code = self._code(object_format, self._ObjectFormatCode)

        # Do the most destruction:
        if delete_all and delete_all_images:
            delete_all_images = False

        ptp = Container(OperationCode='DeleteObject',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[
                            0xFFFFFFFF if delete_all else handle,
                            code,
                        ])

        return self.mesg(ptp)

    def move_object(
        self,
        handle,
        storage_id=0,
        parent_handle=0,
    ):
        '''Move object to parent.

        Parent should be an Association. Default parent is the root directory
        of `storage_id`
        '''
        ptp = Container(OperationCode='MoveObject',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[
                            handle,
                            storage_id,
                            parent_handle,
                        ])

        return self.mesg(ptp)

    def copy_object(
        self,
        handle,
        storage_id=0,
        parent_handle=0,
    ):
        '''Copy object to parent.

        Parent should be an Association. Default parent is the root directory
        of `storage_id`
        '''
        ptp = Container(OperationCode='CopyObject',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[
                            handle,
                            storage_id,
                            parent_handle,
                        ])

        return self.mesg(ptp)

    def get_thumb(self, handle):
        '''Retrieve thumbnail for object from responder.
        '''
        ptp = Container(OperationCode='GetThumb',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[handle])
        return self.recv(ptp)

    def get_resized_image_object(self, handle, width, height=0):
        '''Retrieve resized image object from responder.

        The object should correspond to a previous GetObjectInfo interaction
        between Initiator and Responder in the same session.

        If width is provided then the aspect ratio may change. The device may
        not support this.
        '''
        ptp = Container(OperationCode='GetResizedImageObject',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[handle, width, height])
        return self.recv(ptp)

    def get_vendor_extension_maps(self, handle):
        '''Get VendorExtension maps when supporting more than one extension.
        '''
        ptp = Container(OperationCode='GetVendorExtensionMaps',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[])
        response = self.recv(ptp)
        return self._parse_if_data(response, self._VendorExtensionMapArray)

    def get_vendor_device_info(self, extension):
        '''Get VendorExtension maps when supporting more than one extension.
        '''
        code = self._code(extension, self._VendorExtensionID)
        ptp = Container(OperationCode='GetVendorDeviceInfo',
                        SessionID=self._session,
                        TransactionID=self._transaction,
                        Parameter=[code])
        response = self.recv(ptp)
        return self._parse_if_data(response, self._DeviceInfo)
コード例 #22
0
class MasterBootRecord(BootRecord):
    _MBR_STRUCT = Struct(
        'bootloader_code' / Bytes(440),
        'disk_signature' / Bytes(4),
        Padding(2),
        'partitions' / Array(
            4,
            Struct(
                'state' / Int8sl,
                'beginning' / BitStruct(
                    'head' / Octet,
                    'sect' / BitsInteger(6),
                    'cyl' / BitsInteger(10),
                ),
                Enum(
                    'type' / Int8ub,
                    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_=Pass,
                ),
                'ending' / BitStruct(
                    'head' / Octet,
                    'sect' / BitsInteger(6),
                    'cyl' / BitsInteger(10),
                ),
                'sector_offset' / Int32ul,  # offset from MBR in sectors
                'size' / Int32ul,  # in sectors
            )),
        Const('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 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':
                dPart = {
                    'Number': partNum,
                    'Attributes': 'Active' if part.state < 0 else 'Inactive',
                    'Type': part.type,
                    'Start sector': part.sector_offset,
                    'Size in sectors': part.size
                }
                self._partTable.append(dPart)
            else:
                self._logger.debug('Ignoring invalid partition: %s',
                                   repr(part))
            # Protective MBR is just informative, keep on parsing partition table in case there is a valid
            # active partition
            if part.type == 'PROTECTIVE_MBR' and partNum == 1:
                self._logger.debug(
                    'Protective MBR detected, MBR partition table should not be taken into account. '
                    'Look for the GPT table partition instead')
                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 = Int8ub.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]))
コード例 #23
0
#!/usr/bin/env python

from construct import BitStruct, BitsInteger, Padding, Enum, Flag

SCB_ICSR = 0xe000ed04
scb_icsr = BitStruct(
                     "NMIPENDSET" / Flag,
                     Padding(2),
                     "PENDSVSET" / Flag,
                     "PENDSVCLR" / Flag,
                     "PENDSTSET" / Flag,
                     "PENDSTCLR" / Flag,
                     Padding(1),
                     "DEBUG" / Flag,
                     "ISRPENDING" / Flag,
                     "VECTPENDING" / BitsInteger(10),
                     "RETOBASE" / Flag,
                     Padding(2),
                     "VECTACTIVE" / BitsInteger(9)
                     )

SCB_SHCSR = 0xe000ed24
scb_shcsr = BitStruct(
                     Padding(13),
                      "USGFAULTENA" / Flag,
                      "BUSFAULTENA" / Flag,
                      "MEMFAULTENA" / Flag,
                      "SVCALLPENDED"/ Flag,
                      "BUSFAULTPENDED" / Flag,
                      "MEMFAULTPENDED" / Flag,
                      "USGFAULTPENDED" / Flag,
コード例 #24
0
ConfigurationSet = Select(
    static=ConfigurationSetWithOptionalDhcpDisabled,
    dns=ConfigurationSetWithOptionalDhcpEnabledWithStaticDns,
    minimal=ConfigurationSetWithoutOptionalAutoDhcpEnabled,
)

ConfigurationStatus = Struct(
    "chip_revision_id" / Int8ul,
    Embedded(ConfigurationSetWithOptionalDhcpDisabled),
    "flags" / EnumAdapter(Int8ul, DhcpFlag),
    "status_code" / EnumAdapter(Int8ul, StatusCode),
)

ConnectionState = BitStruct(
    "conn_state" / EnumAdapter(BitsInteger(3), ConnState),
    "link_status" / EnumAdapter(BitsInteger(1), LinkStatus),
    "last_error" / EnumAdapter(BitsInteger(4), LastError))

# GATEWAY PACKETS MSG
PacketsStatus = Struct(
    "total_eth_rx_errors" / Int16ul,
    "total_eth_tx_errors" / Int16ul,
    "bandwidth" / Int16ul,
    "connection_state" / ConnectionState,
)

GatewayConfigParams = SwitchStruct(
    "subopcode" / EnumAdapter(Int8ul, GatewayConfigServerSubOpcode),
    "payload" / Switch(
        this.subopcode,
コード例 #25
0
class PartitionStatus(Subconstruct):
    first2 = BitStruct(
        'fire_alarm' / Flag,
        'audible_alarm' / Flag,
        'silent_alarm' / Flag,
        'was_in_alarm' / Flag,  # is in alarm
        'arm_no_entry' / Flag,
        'arm_stay' / Flag,  # Armed in Stay mode
        'arm_away' / Flag,  # Armed in Away mode
        'arm' / Flag,  # Armed

        'lockout' / Flag,
        'programming' / Flag,
        'zone_bypassed' / Flag,
        'alarm_in_memory' / Flag,
        'trouble' / Flag,
        'entry_delay' / Flag,
        'exit_delay' / Flag,
        'ready' / Flag
    )

    last4 = BitStruct(
        'zone_supervision_trouble' / Flag,
        'zone_fire_loop_trouble' / Flag,
        'zone_low_battery_trouble' / Flag,
        'zone_tamper_trouble' / Flag,
        'voice_arming' / Flag,
        'auto_arming_engaged' / Flag,
        'fire_delay_in_progress' / Flag,
        'intellizone_engage' / Flag,

        'time_to_refresh_zone_status' / Flag,
        'panic_alarm' / Flag,
        'police_code_delay' / Flag,  # Within police code delay
        'follow_become_delay' / Flag,  # Follow become delay when is bypassed
        'remote_arming' / Flag,
        'stay_arming_auto' / Flag,  # if no entry zone is tripped
        'partition_recently_close' / Flag,
        'cancel_alarm_reporting_on_disarming' / Flag,

        'tx_delay_finished' / Flag,  # (Time Out / instant alarm)
        'auto_arm_reach' / Flag,
        'fire_delay_end' / Flag,
        'no_movement_delay_end' / Flag,
        'alarm_duration_finished' / Flag,
        'entry_delay_finished' / Flag,
        'exit_delay_finished' / Flag,
        'intellizone_delay_finished' / Flag,

        '_free0' / BitsInteger(3),
        'all_zone_closed' / Flag,  # (Bypass or not)
        'inhibit_ready' / Flag,
        'bypass_ready' / Flag,
        'force_ready' / Flag,
        'stay_instant_ready' / Flag,
    )

    def __init__(self, subcons_or_size):
        if isinstance(subcons_or_size, Construct):
            self.size = subcons_or_size.sizeof()
            subcons = subcons_or_size
        else:
            self.size = subcons_or_size
            subcons = Bytes(subcons_or_size)
        super(PartitionStatus, self).__init__(subcons)

    def _parse(self, stream, context, path):
        obj = Container()

        if self.size == 32:
            for i in range(1, 6):
                obj[i] = self.first2._parsereport(stream, context, path)
                obj[i].update(self.last4._parsereport(stream, context, path))

            obj[6] = self.first2._parsereport(stream, context, path)
        elif self.size == 16:
            obj[6] = self.last4._parsereport(stream, context, path)
            for i in range(7, 9):
                obj[i] = self.first2._parsereport(stream, context, path)
                obj[i].update(self.last4._parsereport(stream, context, path))
        else:
            raise Exception('Not supported size. Only 32 or 16')

        return obj
コード例 #26
0
ファイル: cute_pld.py プロジェクト: kng/gr-satellites
# -*- coding: utf-8 -*-

# Copyright 2021 The Regents of the University of Colorado
#
# This file is part of gr-satellites
#
# SPDX-License-Identifier: GPL-3.0-or-later
#

from ..adapters import AffineAdapter, LinearAdapter
from construct import Adapter, BitsInteger, BitStruct, Container, Enum, Flag, \
                      Float32b, Int8ub, Int16ub, Int16sb, Int32ub, Padding, \
                      Struct

cute_pld_ccsds_header = BitStruct(
    'ccsds_version' / BitsInteger(3),
    'packet_type' / BitsInteger(1),
    'secondary_header_flag' / BitsInteger(1),
    'APID' / BitsInteger(11),
    'sequence_flags' / BitsInteger(2),
    'sequence_counter' / BitsInteger(14),
    'packet_length' / BitsInteger(16)
)

cute_pld_sw_stat = Struct(
    'ccsds_header' / cute_pld_ccsds_header,
    'shCoarse' / Int32ub,
    'shFine' / Int16ub,
    'pldSwVerMaj' / Int8ub,
    'pldSwVerMin' / Int8ub,
    'pldSwVerPatch' / Int8ub,
コード例 #27
0
ファイル: types.py プロジェクト: George117/pyxcp
    "odt" / Byte,
    "daq" / Byte,
    "data" / GreedyBytes,
)

ResourceType = BitStruct(
    Padding(2),
    "dbg" / Flag,
    "pgm" / Flag,
    "stim" / Flag,
    "daq" / Flag,
    Padding(1),
    "calpag" / Flag,
)

AddressGranularity = Enum(BitsInteger(2),
                          BYTE=0b00,
                          WORD=0b01,
                          DWORD=0b10,
                          RESERVED=0b11)

ByteOrder = Enum(BitsInteger(1), INTEL=0, MOTOROLA=1)

# byte-order dependent types
Int16u = IfThenElse(this._.byteOrder == ByteOrder.INTEL, Int16ul, Int16ub)
Int16s = IfThenElse(this._.byteOrder == ByteOrder.INTEL, Int16sl, Int16sb)
Int32u = IfThenElse(this._.byteOrder == ByteOrder.INTEL, Int32ul, Int32ub)
Int32s = IfThenElse(this._.byteOrder == ByteOrder.INTEL, Int32sl, Int32sb)

CommModeBasic = BitStruct(
    "optional" / Flag,  # The OPTIONAL flag indicates whether additional
コード例 #28
0
ファイル: panel.py プロジェクト: skeary/pai
StartCommunicationResponse = Struct(
    "fields" / RawCopy(
        Struct(
            "po" / BitStruct(
                "command" / Const(0, Nibble), "status" / Struct(
                    "reserved" / Flag, "alarm_reporting_pending" / Flag,
                    "Windload_connected" / Flag, "NeWare_connected" / Flag)),
            "_not_used0" / Bytes(3),
            "product_id" / ProductIdEnum,
            "firmware" /
            Struct("version" / Int8ub, "revision" / Int8ub, "build" / Int8ub),
            "panel_id" / Int16ub,
            "_not_used1" / Bytes(5),
            "transceiver" / Struct(
                "firmware_build" / Int8ub,
                "family" / Int8ub,
                "firmware_version" / Int8ub,
                "firmware_revision" / Int8ub,
                "noise_floor_level" / Int8ub,
                "status" / BitStruct(
                    "_not_used" / BitsInteger(6),
                    "noise_floor_high" / Flag,
                    "constant_carrier" / Flag,
                ),
                "hardware_revision" / Int8ub,
            ),
            "_not_used2" / Bytes(14),
        )), "checksum" / Checksum(
            Bytes(1), lambda data: calculate_checksum(data), this.fields.data))
コード例 #29
0
ファイル: debug.py プロジェクト: gbdlin/python-bluetooth-mesh
    )
)

ArapContentGet = Struct(
    "page" / Int8ul
)

ArapContent = Struct(
    "current_page" / Int8ul,
    "last_page" / Int8ul,
    "nodes" / DictAdapter(
        GreedyRange(
            ByteSwapped(
                BitStruct(
                    "sequence" / Bytewise(Int24ub),
                    "ivi" / BitsInteger(1),
                    "address" / BitsInteger(15),
                )
            )
        ),
        key=this.address,
        value=[this.ivi, this.sequence]
    )
)

DebugPayload = Struct(
    "subopcode" / EnumAdapter(Int8ul, DebugSubOpcode),
    "data" / Default(Switch(
        this.subopcode,
        {
            DebugSubOpcode.RSSI_THRESHOLD_SET: RssiThreshold,
コード例 #30
0
ファイル: parsers.py プロジェクト: jakezp/pai-1
    Checksum, Bytes, this, Default, Padding, Enum, Int24ub, ExprAdapter, Byte, obj_, Array, Computed, Subconstruct, \
    ValidationError, ExprSymmetricAdapter, Bitwise, BitsSwapped, Embedded, ByteSwapped

from .adapters import StatusFlags, ZoneFlags, DateAdapter, PartitionStatus, EventAdapter, \
    ZoneFlagBitStruct, DictArray, EnumerationAdapter
from ..common import CommunicationSourceIDEnum, ProductIdEnum, calculate_checksum, PacketLength, PacketChecksum

LoginConfirmationResponse = Struct(
    "fields" / RawCopy(
        Struct(
            "po" / BitStruct(
                "command" / Const(0x1, Nibble), "status" /
                Struct("reserved" / Flag, "alarm_reporting_pending" / Flag,
                       "Winload_connected" / Flag, "NeWare_connected" / Flag)),
            "length" / PacketLength(Int8ub), "result" /
            BitStruct("_not_used0" / BitsInteger(4), "partition_2" / Flag,
                      "_not_used1" / BitsInteger(3)), "callback" / Int16ub)),
    "checksum" / PacketChecksum(Bytes(1)))

InitializeCommunication = Struct(
    "fields" / RawCopy(
        Struct(
            "po" / Struct("command" / Const(0x00, Int8ub)),
            "module_address" / Default(Int8ub, 0x00),  # (00= panel/module)
            "_not_used0" / Padding(2),
            "product_id" / ProductIdEnum,
            "firmware" /
            Struct("version" / Int8ub, "revision" / Int8ub, "build" / Int8ub),
            "panel_id" / Int16ub,
            "pc_password" / Default(Bytes(2), b'0000'),
            "modem_speed" / Bytes(1),