def test_overwrite(self): s = Struct("s", Byte("a"), Byte("a"), allow_overwrite = True ) self.assertEqual(s.parse(b"\x01\x02").a, 2) s = Struct("s", Byte("a"), Embedded(Struct("b", Byte("a"), allow_overwrite = True )), ) self.assertEqual(s.parse(b"\x01\x02").a, 2) s = Struct("s", Embedded(Struct("b", Byte("a"), )), Byte("a"), allow_overwrite = True ) self.assertEqual(s.parse(b"\x01\x02").a, 2)
def test_overwrite(self): s = Struct("s", Byte("a"), Byte("a"), allow_overwrite = True ) self.assertEqual(s.parse(six.b("\x01\x02")).a, 2) s = Struct("s", Byte("a"), Embedded(Struct("b", Byte("a"), allow_overwrite = True )), ) self.assertEqual(s.parse(six.b("\x01\x02")).a, 2) s = Struct("s", Embedded(Struct("b", Byte("a"), )), Byte("a"), allow_overwrite = True ) self.assertEqual(s.parse(six.b("\x01\x02")).a, 2)
def parse(buffer, byteorder = "<"): """ Parameters ---------- buffer: bytes-like byteorder: char "<": Little-endian ">": Big-endian Returns ------- dict key: Vendor name values: list of attributes """ Integer = Int32ul if byteorder == "<" else Int32ub Section = Struct( "len" / Integer, "vendor" / CString(encoding = "ascii"), "_pos" / Tell, "data" / Bytes(this.len - this._pos), ) SubSectionHeader = Struct( "tag" / Byte, "len" / Integer, "_pos" / Tell, "data" / Bytes(this.len - this._pos), ) RawAttribute = Struct( "tag" / ULEB, "parameterType" / Computed(lambda ctx: ATTRIBUTES[ctx.tag].parameterType), "name" / Computed(lambda ctx: ATTRIBUTES[ctx.tag].tag), "_conv" / Computed(lambda ctx: ATTRIBUTES[ctx.tag].conv), "value" / Switch(this.parameterType, { Reader.INT32: Integer, Reader.ULEB: ULEB, Reader.CSTRING: CString(encoding = "ascii") }), "pos" / Tell, ) format_version = buffer[0] i = 1 length = len(buffer) result = {} while True: section = Section.parse(buffer[i : ]) if not section.vendor in result: result[section.vendor] = [] i += section.len res = SubSectionHeader.parse(section.data) j = 0 while j < len(res.data): attr = RawAttribute.parse(res.data[j : ]) r = Attribute(attr.tag, attr.name, attr.value) if attr._conv != Ident: r.description = attr._conv[attr.value] result[section.vendor].append(r) j += attr.pos if i >= length: break return result
def do_abbrevs(self): section = self.sections['.debug_abbrev'] image = section.image length = len(section.image) Abbrevation = Struct( "start" / Tell, "code" / ULEB, "details" / If(lambda ctx: ctx.code != 0, Struct( "tag" / ULEB, "children" / self.u8, )), "stop" / Tell, ) Attribute = Struct( "start" / Tell, "attrValue" / ULEB, "formValue" / ULEB, "stop" / Tell, "next" / Computed((this.attrValue != 0) and (this.formValue != 0)), ) offset = 0 result = OrderedDict() kOffs = offset while True: print("Offset: {}".format(offset)) abbrev = Abbrevation.parse(image[offset:]) if abbrev.code != 0: print("{} {} {}".format(abbrev.code, constants.Tag(abbrev.details.tag), abbrev.details.children == 1)) key = ( kOffs, abbrev.code, ) offset += abbrev.stop - abbrev.start if offset >= length: break if abbrev.code == 0: kOffs = offset result[key] = Abbreviation(0, False, []) continue result[key] = Abbreviation(constants.Tag(abbrev.details.tag), (abbrev.details.children == 1), []) while True: attr = Attribute.parse(image[offset:]) if attr.attrValue != 0 and attr.formValue != 0: result[key].attrs.append( (constants.AttributeEncoding(attr.attrValue), constants.AttributeForm(attr.formValue))) print(" {} {}".format( constants.AttributeEncoding(attr.attrValue), constants.AttributeForm(attr.formValue))) offset += (attr.stop - attr.start) if not attr.next: break self.abbreviations = result
def test_list_invalid(): s = Struct( 'hash' / ChecksumValue(hashlib.sha1, this.data, True), # note: True instead of default False 'data' / ChecksumSourceData(Struct( 'x' / Bytes(4) )), VerifyOrWriteChecksums ) with pytest.raises(ChecksumCalcError): s.parse(test_data)
def test_no_sourcedata(): s = Struct( 'hash' / ChecksumValue(hashlib.sha1, this.data), 'data' / Struct( 'x' / Bytes(4) ), VerifyOrWriteChecksums ) with pytest.raises(ChecksumCalcError): s.parse(test_data)
def test_main(): s = Struct('a' / Byte) # original behavior _global_struct_io_patch.unpatch() try: value = s.parse(b'\x01') assert '_io' in value finally: _global_struct_io_patch.patch() # patched value = s.parse(b'\x01') assert '_io' not in value
def __init__(self, data): frame = Struct( "Frame", Bytes("destination", 6), Bytes("source", 6), Enum(UBInt16("type"), IPv4=0x0800, ARP=0x0806, RARP=0x8035, X25=0x0805, IPX=0x8137, IPv6=0x86DD, VLAN=0x8100)) try: ethernet = frame.parse(data[:14]) except MappingError: self.frame = None log.msg("Broken ethernet header %s" % repr(data)) return data = data[14:] self.src_mac = ethernet.destination self.dst_mac = ethernet.source if ethernet.type == 'VLAN': d = ord(data[0]) self.vlan = d & 0x0fff self.vlan_priority = d >> 13 elif ethernet.type == 'IPv4': ipv4 = IPv4Header(data) self.ip = ipv4.ip self.ip_sport = ipv4.ip_sport self.ip_dport = ipv4.ip_dport else: print(ethernet.type, repr(data))
def read_messages(self): """Read messages.""" from construct import Struct, PascalString, Int16ul, Tell, this, Bytes frmt = Struct( "instructions_length" / Int16ul, "instructions" / Bytes(this.instructions_length), "hints" / PascalString(Int16ul, "utf8"), "victory" / PascalString(Int16ul, "utf8"), "defeat" / PascalString(Int16ul, "utf8"), "history" / PascalString(Int16ul, "utf8"), "scouts" / PascalString(Int16ul, "utf8"), "offset" / Tell, ) parsing = frmt.parse(self.header[self.position:]) self.position += parsing.offset parsing.instructions = parsing.instructions.rstrip(b'\x00') parsing.hints = parsing.hints.rstrip('\x00') parsing.victory = parsing.victory.rstrip('\x00') parsing.defeat = parsing.defeat.rstrip('\x00') parsing.history = parsing.history.rstrip('\x00') parsing.scouts = parsing.scouts.rstrip('\x00') return dict(parsing)
class MessageParse(object): def __init__(self): self.constructFrame = Struct( "parser", OptionalGreedyRange( Struct( "packets", UBInt8("header"), UBInt16("plen"), UBInt8("dir"), ULInt64("nodeid"), UBInt16("funcid"), Array( lambda ctx: (ctx.plen - 1 - 8 - 2) / 8, Struct( "datas", ULInt16("type"), ULInt16("unit"), LFloat32("value"), )), UBInt8("sum"), # UBInt8("simulation") ), ), OptionalGreedyRange(UBInt8("leftovers"), ), ) def construct_parse(self, bytestream): return self.constructFrame.parse(bytestream) def parse_pkgs(self, bytestream): container = self.construct_parse(bytestream) return container.packets, container.leftovers
def _extract_elf_corefile(self, exe_name=None): """ Reads the ELF formatted core dump image and parse it """ self.core_elf_file.write(self.core_src.data) # Need to be closed before read. Otherwise the result will be wrong self.core_elf_file.close() core_elf = ESPCoreDumpElfFile(self.core_elf_file.name) # Read note segments from core file which are belong to tasks (TCB or stack) for seg in core_elf.note_segments: for note_sec in seg.note_secs: # Check for version info note if note_sec.name == 'ESP_CORE_DUMP_INFO' \ and note_sec.type == ESPCoreDumpElfFile.PT_INFO \ and exe_name: exe_elf = ElfFile(exe_name) app_sha256 = binascii.hexlify(exe_elf.sha256) coredump_sha256_struct = Struct( 'ver' / Int32ul, 'sha256' / Bytes(64) # SHA256 as hex string ) coredump_sha256 = coredump_sha256_struct.parse( note_sec.desc[:coredump_sha256_struct.sizeof()]) if coredump_sha256.sha256 != app_sha256: raise ESPCoreDumpLoaderError( 'Invalid application image for coredump: coredump SHA256({}) != app SHA256({}).' .format(coredump_sha256, app_sha256)) if coredump_sha256.ver != self.version: raise ESPCoreDumpLoaderError( 'Invalid application image for coredump: coredump SHA256 version({}) != app SHA256 version({}).' .format(coredump_sha256.ver, self.version))
def decode_data(payload): from construct import Struct, Int8ub, Int16ub, Float32l pytrack = Struct( "lat" / Float32l, "lng" / Float32l, "roll" / Int8ub, "pitch" / Int8ub, "volt" / Int8ub, "wake" / Int8ub, ) s = pytrack.parse(bytearray.fromhex(payload)) p = {} if 'lat' in s.keys(): p['lat'] = s['lat'] if 'lng' in s.keys(): p['lng'] = s['lng'] if 'roll' in s.keys(): p['roll'] = (s['roll'] - 128.0) / (256.0 / 360.0) if 'pitch' in s.keys(): p['pitch'] = (s['pitch'] - 128.0) / (256.0 / 180.0) if 'volt' in s.keys(): p['volt'] = s['volt'] / 256.0 * 5.0 if 'wake' in s.keys(): p['wake'] = s['wake'] return p
def test_nested(): s = Struct( 'a' / Byte, 'b' / DeferredValue(Byte), 'c' / Byte, 'struct' / Struct('new_value' / Tell, WriteDeferredValue(this.new_value + 7, this._.b), 'x' / Byte)) # parsing assert s.parse(b'\x01\x02\x03\x04') == { 'a': 1, 'b': 2, 'c': 3, 'struct': { 'new_value': 3, 'x': 4 } } # building assert s.build({ 'a': 0xff, 'c': 0xfe, 'struct': { 'x': 0x42 } }) == b'\xff\x0a\xfe\x42'
def decode_data(data): print("Pytrack sensor data:") pytrack = Struct( "lat" / Float32l, "lng" / Float32l, "roll" / Int8ub, "pitch" / Int8ub, "volt" / Int8ub, "wake" / Int8ub, ) s = pytrack.parse(bytearray.fromhex(data)) print(s) d = {} if 'lat' in s.keys(): d['lat'] = s['lat'] if 'lng' in s.keys(): d['lng'] = s['lng'] if 'roll' in s.keys(): d['roll'] = (s['roll'] - 128.0) / (256.0 / 360.0) if 'pitch' in s.keys(): d['pitch'] = (s['pitch'] - 128.0) / (256.0 / 180.0) if 'volt' in s.keys(): d['volt'] = s['volt'] / 256.0 * 5.0 if 'wake' in s.keys(): d['wake'] = s['wake'] return d
def _parse(self, struct: Struct, encoded: HexStr_, crc=True) -> dict: """ Parses struct, and returns a serializable Python object. """ if encoded is None: return None def normalize(val): """ Recursively converts construct Container values to serializable Python objects. Private items (key starts with '_') are filtered. """ if isinstance(val, Container): return { k: normalize(v) for k, v in dict(val).items() if not k.startswith('_') } else: return val byte_val = unhexlify(encoded) if crc: if CRC8.calculate(byte_val) == b'\x00': byte_val = byte_val[:-1] else: raise exceptions.CRCFailed(f'{self} failed CRC check') return normalize(struct.parse(byte_val))
def _parse_program_headers(self): ProgramHeaders = Struct("segments" / Array( lambda ctx: self.e_phnum, "segment" / IfThenElse( lambda ctx: self.b64, Struct( "p_type" / self.Word, "p_flags" / self.Word, "p_offset" / self.Off, "p_vaddr" / self.Addr, "p_paddr" / self.Addr, "p_filesz" / self.Xword, "p_memsz" / self.Xword, "p_align" / self.Xword, ), Struct( "p_type" / self.Word, "p_offset" / self.Off, "p_vaddr" / self.Addr, "p_paddr" / self.Addr, "p_filesz" / self.Word, "p_memsz" / self.Word, "p_flags" / self.Word, "p_align" / self.Word, )), )) if hasattr(self, 'e_shnum'): #if self.e_shnum: # print("PG_size: {}".format(ProgramHeaders.sizeof() / self.e_phnum)) self._program_headers = ProgramHeaders.parse( self.fp[self.e_phoff:])
def __init__(self, filename, encoding=None, password=None, cached=True, check=False, current_tablename=None, date_fieldname=None, time_fieldname=None, decryptor_class=TpsDecryptor): self.filename = filename self.encoding = encoding self.password = password self.cached = cached self.check = check self.current_table_number = None # Name part before .tps self.name = os.path.basename(filename) self.name = text_type(os.path.splitext(self.name)[0]).lower() if date_fieldname is not None: self.date_fieldname = date_fieldname else: self.date_fieldname = [] if time_fieldname is not None: self.time_fieldname = time_fieldname else: self.time_fieldname = [] self.cache_pages = {} if not os.path.isfile(self.filename): raise FileNotFoundError(self.filename) self.file_size = os.path.getsize(self.filename) # Check file size if check: if self.file_size & 0x3F != 0: # TODO check translate warn('File size is not a multiple of 64 bytes.', RuntimeWarning) with open(self.filename, mode='r+b') as tpsfile: self.tps_file = mmap.mmap(tpsfile.fileno(), 0) self.decryptor = decryptor_class(self.tps_file, self.password) try: # TPS file header header = Struct('header', ULInt32('offset'), ULInt16('size'), ULInt32('file_size'), ULInt32('allocated_file_size'), Const(Bytes('top_speed_mark', 6), b'tOpS\x00\x00'), UBInt32('last_issued_row'), ULInt32('change_count'), ULInt32('page_root_ref'), Array(lambda ctx: (ctx['size'] - 0x20) / 2 / 4, ULInt32('block_start_ref')), Array(lambda ctx: (ctx['size'] - 0x20) / 2 / 4, ULInt32('block_end_ref')), ) self.header = header.parse(self.read(0x200)) self.pages = TpsPagesList(self, self.header.page_root_ref, check=self.check) self.tables = TpsTablesList(self, encoding=self.encoding, check=self.check) self.set_current_table(current_tablename) except adapters.ConstError: print('Bad cryptographic keys.')
def test_single(): s = Struct('a' / Byte, 'b' / DeferredValue(Byte), 'c' / Byte, 'new_value' / Tell, WriteDeferredValue(this.new_value, this.b)) # parsing assert s.parse(b'\x01\x02\x03') == {'a': 1, 'b': 2, 'c': 3, 'new_value': 3} # building assert s.build({'a': 0xff, 'c': 0xfe}) == b'\xff\x03\xfe'
def test_group_adapter(): s = Struct('groups' / commands.GroupListAdapter()) for left, right in [([], b'\x00'), ([0, 1], b'\x03'), ([i for i in range(8)], b'\xFF')]: assert s.build({'groups': left}) == right assert s.parse(right) == {'groups': left} with pytest.raises(ValueError): s.build({'groups': [8]})
def test_list(): s = Struct( ChecksumValue(hashlib.sha1, lambda this: this.data[0:2], True), 'data' / Array(3, ChecksumSourceData(Struct( 'a' / Byte ))), VerifyOrWriteChecksums ) values = b'\x01\x02\x03' # same range hashval = hashlib.sha1(values[0:2]).digest() assert s.parse(hashval + values) == {'data': [{'a': 1}, {'a': 2}, {'a': 3}]} # different range hashval = hashlib.sha1(values[0:1]).digest() with pytest.raises(ChecksumVerifyError): s.parse(hashval + values)
def _parse_note(self, data): Note = Struct("namesz" / self.Word, "descsz" / self.Word, "type" / self.Word, "name" / Bytes(this.namesz), "desc" / Bytes(this.descsz)) if not data: return None result = Note.parse(data) result.desc = binascii.b2a_hex(result.desc).decode() result.name = self.asciiCString.parse(result.name) return result
def test_enumconvert(): class TestEnum(Enum): A = 0x42 @property def prop(self): return 1337 s = Struct('e' / EnumConvert(Byte, TestEnum), 'v' / Computed(lambda this: this.e.prop)) # valid assert s.parse(b'\x42') == {'e': TestEnum.A, 'v': 1337} assert s.build({'e': TestEnum.A}) == b'\x42' # invalid with pytest.raises(MappingError): s.parse(b'\x00') with pytest.raises(MappingError): s.build({'e': 0})
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])
def _recv_hello_request(self): fmt = Struct( 'length' / Int32ul, 'type' / Int32ul, 'version' / Int32ul, 'dummy' / Bytes(8), 'seed' / Bytes(16), ) msg = self._recv_msg() data = fmt.parse(msg) return data
def test(self): pstring = Struct("pstring", UBInt8("length"), Struct("inner", UBInt8("inner_length"), Bytes("data", foo), ) ) obj = pstring.parse(six.b("\x03\x02helloXXX")) print(repr(obj)) self.assertEqual(obj, Container(length = 3, inner = Container(inner_length = 2, data = six.b("hello")))) size = pstring._sizeof(Container(inner_length = 2, _ = Container(length = 3))) self.assertEqual(size, 7)
def parse_header(data): """ split up header information (using construct) """ mavlink_header = Struct('header', Const(Byte('magic'), MAVLINK_MAGIC), Byte('plength'), Byte('sequence'), Byte('sysid'), Byte('compid'), Byte('msgid'), ) return mavlink_header.parse(data[0:6])
def _parse_note(self, data): Note = Struct( "namesz" / self.Word, "descsz" / self.Word, "type" / self.Word, "name" / Bytes(this.namesz), "desc" / Bytes(this.descsz) ) print(len(data), data.tobytes()) result = Note.parse(data) result.desc = binascii.b2a_hex(result.desc).decode() print(result.desc) print(result)
def test_parse(): rawcopy = AttributeRawCopy(Array(3, Byte)) # test default and custom name for name in [None, 'newname']: subcon = (name @ rawcopy) if name is not None else rawcopy s = Struct('num' / Byte, 'array' / subcon) value = s.parse(b'\xff\x01\x02\x03') assert value.num == 0xff assert value.array == [1, 2, 3] assert getattr(value.array, '__raw__' if name is None else name) == b'\x01\x02\x03'
class TestMetaFieldStruct(unittest.TestCase): def setUp(self): self.mf = MetaField("data", lambda context: context["length"]) self.s = Struct("foo", Byte("length"), self.mf) def test_trivial(self): pass def test_parse(self): c = self.s.parse(b"\x03ABC") self.assertEqual(c.length, 3) self.assertEqual(c.data, b"ABC") c = self.s.parse(b"\x04ABCD") self.assertEqual(c.length, 4) self.assertEqual(c.data, b"ABCD") def test_sizeof_default(self): self.assertRaises(SizeofError, self.mf.sizeof) def test_sizeof(self): context = Container(length=4) self.assertEqual(self.mf.sizeof(context), 4)
class TestMetaFieldStruct(unittest.TestCase): def setUp(self): self.mf = MetaField("data", lambda context: context["length"]) self.s = Struct("foo", Byte("length"), self.mf) def test_trivial(self): pass def test_parse(self): c = self.s.parse("\x03ABC") self.assertEqual(c.length, 3) self.assertEqual(c.data, "ABC") c = self.s.parse("\x04ABCD") self.assertEqual(c.length, 4) self.assertEqual(c.data, "ABCD") def test_sizeof_default(self): self.assertRaises(SizeofError, self.mf.sizeof) def test_sizeof(self): context = Container(length=4) self.assertEqual(self.mf.sizeof(context), 4)
def f(client: LedgerClient) -> DeviceResponse: response = client.apdu_exchange(INS, data, P1, P2) response_template = Struct( public_key=Prefixed(Int8ub, GreedyBytes), address=PascalString(Int8ub, "ascii"), chain_code=Bytes(32), ) parsed_response = response_template.parse(response) return DeviceResponse( public_key=parsed_response.public_key, address=parsed_response.address, chain_code=parsed_response.chain_code, )
def _send_request( self, request_format: construct.struct, request_obj: Optional[Dict[str, Any]], response_format: construct.Struct, ) -> construct.Container: try: request = request_format.build(request_obj) self._send_packet(request) response_pkt = self._read_packet() return response_format.parse(response_pkt.message) except construct.ConstructError as e: raise lifescan.MalformedCommand(str(e))
def _send_request( self, lba: int, request_format: construct.Struct, request_obj: Optional[Dict[str, Any]], response_format: construct.Struct, ) -> construct.Container: """Send a request to the meter, and read its response. Args: lba: the address of the block register to use, known valid addresses are 3, 4 and 5. request_format: a construct format identifier of the request to send request_obj: the object to format with the provided identifier response_format: a construct format identifier to parse the returned message with. Returns: The Container object parsed from the response received by the meter. Raises: lifescan.MalformedCommand if Construct fails to build the request or parse the response. """ try: request = request_format.build(request_obj) request_raw = _PACKET.build( {"data": { "value": { "message": request } }}) logging.debug("Request sent: %s", binascii.hexlify(request_raw)) self.scsi_.write10(lba, 1, request_raw) response_raw = self.scsi_.read10(lba, 1) logging.debug("Response received: %s", binascii.hexlify(response_raw.datain)) response_pkt = _PACKET.parse(response_raw.datain).data logging.debug("Response packet: %r", response_pkt) response = response_format.parse(response_pkt.value.message) logging.debug("Response parsed: %r", response) return response except construct.ConstructError as e: raise lifescan.MalformedCommand(str(e))
def _parse_comment(self, data): Line = Struct("line" / CString("ascii"), "pos" / Tell) if not data: return "" length = len(data) result = [] i = 0 if data.find(b"\x00") == -1: return str(data, "ascii") while i < length: #print("*** LINE", data[i : ]) line = Line.parse(data[i:]) if line.line: result.append(line.line) i += line.pos return '\n'.join(result)
class TestEmbedingBranch(TestCase): def setUp(self): self.cons = Struct('foo', Enum(Byte("a_enum"), ALFA=1, BETA=2 ), Switch('switch', lambda ctx: ctx.a_enum, { 'ALFA': Embed(Struct('struct_alfa', Byte('byte_alfa'))), 'BETA': Embed(Struct('struct_beta', Byte('byte_beta'))), }) ) def test_construct(self): contents = self.cons.parse('\x01\x03\xee\x33') self.assertIn('a_enum', contents) self.assertEqual(contents['a_enum'], 'ALFA') self.assertIn('byte_alfa', contents)
def get_data(binary_data): """Get data from binary string.""" raw_header, raw_body = binary_data[:HEADER_LENTH], binary_data[HEADER_LENTH+1:] # TODO !!! Uncomment when will take valid data !!! #header = HEADER_FORMAT.parse(raw_header) # if binascii.crc_hqx(raw_body, 0xffff) != header.checksum: # logger.exception('Checksums is not match') # raise InputError(binascii.crc_hqx(raw_body, 0xffff), 'Checksums is not match') result = {} while True: current_type = raw_body[:1] if not current_type: return result type_of_struct = "0x{}".format(binascii.hexlify(current_type)) data = STRUCT_TYPES.get(type_of_struct, None) if not data: logger.exception('Data type is not exist') raise AttributeError data_size = data[1] if not isinstance(data[1], int) else Byte[data[1]] body_format = Struct( "type" / Int8ul, "data" / data_size, ) # TODO !!! Remove that exception when will take valid data try: current = body_format.parse(raw_body[:data_size.sizeof()+1]) except : return result result[data[0]] = current.data raw_body = raw_body[body_format.sizeof():]
SERVER_INVITE_OPTION = 0x12 ), Switch("OptionData", lambda ctx: ctx["OptionID"], { "CLIENT_NICK_OPTION" : CString('Nickname'), "CLIENT_MEMBERSHIP_OPTION" : ClientMemberShipOption, "SERVER_OPTION" : Struct("ServerOption", ULInt16('Port')), "SERVER_CHANNELS_OPTION" : PrefixedArray(CString('Channels'), ULInt8("NumChannels")), "SERVER_INVITE_OPTION" : ServerInviteOption } ) ) peerPDU = Struct( 'peerPDU', CString('ClientID'), OptionalGreedyRepeater(Option) ) if __name__ == '__main__': data = peerPDU.build(Container(ClientID="Bob", Option=[ Container(OptionID="SERVER_INVITE_OPTION", OptionData=Container(ChannelID="TM2011", ClientID=["Alice", "Billy"])), Container(OptionID="CLIENT_NICK_OPTION", OptionData="Susan")] ) ) print repr(data) packet = peerPDU.parse(data) print packet
class IpAddressAdapter(Adapter): def _encode(self,obj,context): return "".join(chr(int(b)) for b in obj.split()) def _decode(self,obj,context): return ".".join(str(ord(b)) for b in obj) #IpAddressAdapter(Bytes("foo",4)).parse("\x01\x02\x03\x04") class PrintContext(Construct): def _parse(self, stream, context): print context print "hello" foo = Struct("foo", Byte("a"), Byte("b"), PrintContext("c"), Struct("bar", Byte("a"), Byte("b"), PrintContext("c"), ), PrintContext("d"), ) foo.parse("\x01\x02\x03\x04")
class RfidFrame(object): def __init__(self): # 接收数据的数据格式定义 self.rfidFrame = Struct("frame", OptionalGreedyRange( Struct("packets", UBInt16("header"), Enum(UBInt8("cmdcode"), F1=0xF1, F2=0xF2, F3=0xF3, F4=0xF4, ), Switch("datas", lambda ctx: ctx.cmdcode, { "F1": Struct("sub", UBInt8("readerID"), UBInt8("packet_len"), UBInt8("status"), Array(lambda ctx: ( ctx.packet_len - 2 - 1 - 1 - 1 - 1 - 2) / 6, Struct("blocks", # UBInt8('elec'), Array(3, UBInt8('cardID')), UBInt8('triggerID'), UBInt16('relativeTime') ) ) ), "F2": Struct("sub", UBInt8("packet_len"), UBInt8("readerID")), "F3": Struct("sub", UBInt8("packet_len"), UBInt8("result")), "F4": Struct("sub", UBInt8("packet_len"), UBInt8("rssl")), } ), UBInt16("crc"), ) ), OptionalGreedyRange( UBInt8("leftovers"), ), ) self.readerID = None self.rssl = 1 self.triggerID = None def rfidFrameParse(self, bytestream): return self.rfidFrame.parse(bytestream) def handle_data(self, pkgs): cmdcode = pkgs[0].cmdcode # datas = pkgs.packets.datas[0] # 对指令码判断工作模式 if cmdcode == "F1": # 存储温度,湿度,以及其他数据 print self.data_p(pkgs) # #rfidDb.saveID( self.cardID,self.triggerID,) #存储触发器id和卡号到数据库 # # print 'the trigger ID is :', self.triggerID # print 'the card ID is :', self.cardID elif cmdcode == "F2": # 得到阅读器id self.readerID = self.getReaderID(pkgs) print self.readerID elif cmdcode == 'F3': # 此处还不能写小写的f3,是字符串匹配,要和系统返回的一样.否则无法进入循环 # 获得设置门限值的结果 result = self.getResult(pkgs) result = hex(result) # 此处result的值是2进制数要转换成16进制数来进行门限值的设置结果判断 if result == '0xaa': print 'setted success' else: print 'setted falure' elif cmdcode == "F4": # 得到门限值 self.rssl = self.getRSSI(pkgs) print self.rssl def getReaderID(self, pkgs): return pkgs[0].datas.readerID def getCardID(self, pkgs): return pkgs[0].datas.blocks[0].cardID def getTriggerID(self, pkgs): return pkgs[0].datas.blocks[0].triggerID def getResult(self, pkgs): return pkgs[0].datas.result def getRSSI(self, pkgs): return pkgs[0].datas.rssl def data_p(self, pkgs): data = "" # 处理卡号和触发器id important_data = "" for pkg in pkgs[0].datas.blocks: cardID = pkg.cardID if cardID[0] == 1: print cardID print dec_to_hex(cardID[1]) + dec_to_hex(cardID[2]), "电量异常" data += dec_to_hex(cardID[1]) data += dec_to_hex(cardID[2]) triggerID = pkg.triggerID if triggerID != 0: important_data += hex_to_dec(data) + ":" + str(triggerID) + "," data = "" important_data = important_data[0:-1] + "\n" return important_data
class IPTransport(object): '''Implement IP transport.''' def __init__(self, device=None): '''Instantiate the first available PTP device over IP''' self.__setup_constructors() logger.debug('Init IP') self.__dev = device if device is None: raise NotImplementedError( 'IP discovery not implemented. Please provide a device.' ) self.__device = device # Signal usable implicit session self.__implicit_session_open = Event() # Signal implicit session is shutting down self.__implicit_session_shutdown = Event() self.__check_session_lock = Lock() self.__transaction_lock = Lock() self.__event_queue = Queue() atexit.register(self._shutdown) def _shutdown(self): try: self.__close_implicit_session() except Exception as e: logger.error(e) @contextmanager def __implicit_session(self): '''Manage implicit sessions with responder''' # There is now an implicit session self.__check_session_lock.acquire() if not self.__implicit_session_open.is_set(): try: self.__open_implicit_session() self.__check_session_lock.release() yield except Exception as e: logger.error(e) raise PTPError('Failed to open PTP/IP implicit session') finally: if self.__implicit_session_open.is_set(): self.__close_implicit_session() if self.__check_session_lock.locked(): self.__check_session_lock.release() else: self.__check_session_lock.release() yield def __open_implicit_session(self): '''Establish implicit session with responder''' self.__implicit_session_shutdown.clear() # Establish Command and Event connections if type(self.__device) is tuple: host, port = self.__device self.__setup_connection(host, port) else: self.__setup_connection(self.__device) self.__implicit_session_open.set() # Prepare Event and Probe threads self.__event_proc = Thread( name='EvtPolling', target=self.__poll_events ) self.__event_proc.daemon = False self.__ping_pong_proc = Thread( name='PingPong', target=self.__ping_pong ) self.__ping_pong_proc.daemon = False # Launch Event and Probe threads self.__event_proc.start() self.__ping_pong_proc.start() def __close_implicit_session(self): '''Terminate implicit session with responder''' self.__implicit_session_shutdown.set() if not self.__implicit_session_open.is_set(): return # Only join running threads. if self.__event_proc.is_alive(): self.__event_proc.join(2) if self.__ping_pong_proc.is_alive(): self.__ping_pong_proc.join(2) logger.debug('Close connections for {}'.format(repr(self.__dev))) try: self.__evtcon.shutdown(socket.SHUT_RDWR) except socket.error as e: if e.errno == 107: pass else: raise e try: self.__cmdcon.shutdown(socket.SHUT_RDWR) except socket.error as e: if e.errno == 107: pass else: raise e self.__evtcon.close() self.__cmdcon.close() self.__implicit_session_open.clear() def __setup_connection(self, host=None, port=15740): '''Establish a PTP/IP session for a given host''' logger.debug( 'Establishing PTP/IP connection with {}:{}' .format(host, port) ) socket.setdefaulttimeout(5) hdrlen = self.__Header.sizeof() # Command Connection Establishment self.__cmdcon = create_connection((host, port)) # Send InitCommand # TODO: Allow users to identify as an arbitrary initiator. init_cmd_req_payload = self.__InitCommand.build( Container( InitiatorGUID=16*[0xFF], InitiatorFriendlyName='PTPy', InitiatorProtocolVersion=Container( Major=100, Minor=000, ), )) init_cmd_req = self.__Packet.build( Container( Type='InitCommand', Payload=init_cmd_req_payload, ) ) actual_socket(self.__cmdcon).sendall(init_cmd_req) # Get ACK/NACK init_cmd_req_rsp = actual_socket(self.__cmdcon).recv(72) init_cmd_rsp_hdr = self.__Header.parse( init_cmd_req_rsp[0:hdrlen] ) if init_cmd_rsp_hdr.Type == 'InitCommandAck': cmd_ack = self.__InitCommandACK.parse(init_cmd_req_rsp[hdrlen:]) logger.debug( 'Command connection ({}) established' .format(cmd_ack.ConnectionNumber) ) elif init_cmd_rsp_hdr.Type == 'InitFail': cmd_nack = self.__InitFail.parse(init_cmd_req_rsp[hdrlen:]) msg = 'InitCommand failed, Reason: {}'.format( cmd_nack ) logger.error(msg) raise PTPError(msg) else: msg = 'Unexpected response Type to InitCommand : {}'.format( init_cmd_rsp_hdr.Type ) logger.error(msg) raise PTPError(msg) # Event Connection Establishment self.__evtcon = create_connection((host, port)) self.__evtcon.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.__evtcon.setsockopt(socket.IPPROTO_TCP, socket.SO_KEEPALIVE, 1) # Send InitEvent payload = self.__InitEvent.build(Container( ConnectionNumber=cmd_ack.ConnectionNumber, )) evt_req = self.__Packet.build( Container( Type='InitEvent', Payload=payload, ) ) actual_socket(self.__evtcon).sendall(evt_req) # Get ACK/NACK init_evt_req_rsp = actual_socket(self.__evtcon).recv( hdrlen + self.__InitFail.sizeof() ) init_evt_rsp_hdr = self.__Header.parse( init_evt_req_rsp[0:hdrlen] ) if init_evt_rsp_hdr.Type == 'InitEventAck': logger.debug( 'Event connection ({}) established' .format(cmd_ack.ConnectionNumber) ) elif init_evt_rsp_hdr.Type == 'InitFail': evt_nack = self.__InitFail.parse(init_evt_req_rsp[hdrlen:]) msg = 'InitEvent failed, Reason: {}'.format( evt_nack ) logger.error(msg) raise PTPError(msg) else: msg = 'Unexpected response Type to InitEvent : {}'.format( init_evt_rsp_hdr.Type ) logger.error(msg) raise PTPError(msg) # Helper methods. # --------------------- def __setup_constructors(self): '''Set endianness and create transport-specific constructors.''' # Set endianness of constructors before using them. self._set_endian('little') self.__Length = Int32ul self.__Type = Enum( Int32ul, Undefined=0x00000000, InitCommand=0x00000001, InitCommandAck=0x00000002, InitEvent=0x00000003, InitEventAck=0x00000004, InitFail=0x00000005, Command=0x00000006, Response=0x00000007, Event=0x00000008, StartData=0x00000009, Data=0x0000000A, Cancel=0x0000000B, EndData=0x0000000C, Ping=0x0000000D, Pong=0x0000000E, ) self.__Header = Struct( 'Length' / self.__Length, 'Type' / self.__Type, ) self.__Param = Range(0, 5, self._Parameter) self.__EventParam = Range(0, 3, self._Parameter) self.__PacketBase = Struct( Embedded(self.__Header), 'Payload' / Bytes( lambda ctx, h=self.__Header: ctx.Length - h.sizeof()), ) self.__Packet = ExprAdapter( self.__PacketBase, encoder=lambda obj, ctx, h=self.__Header: Container( Length=len(obj.Payload) + h.sizeof(), **obj ), decoder=lambda obj, ctx: obj, ) # Yet another arbitrary string type. Max-length CString utf8-encoded self.__PTPIPString = ExprAdapter( RepeatUntil( lambda obj, ctx, lst: six.unichr(obj) in '\x00' or len(lst) == 40, Int16ul ), 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], ) # PTP/IP packets # Command self.__ProtocolVersion = Struct( 'Major' / Int16ul, 'Minor' / Int16ul, ) self.__InitCommand = Embedded(Struct( 'InitiatorGUID' / Array(16, Int8ul), 'InitiatorFriendlyName' / self.__PTPIPString, 'InitiatorProtocolVersion' / self.__ProtocolVersion, )) self.__InitCommandACK = Embedded(Struct( 'ConnectionNumber' / Int32ul, 'ResponderGUID' / Array(16, Int8ul), 'ResponderFriendlyName' / self.__PTPIPString, 'ResponderProtocolVersion' / self.__ProtocolVersion, )) # Event self.__InitEvent = Embedded(Struct( 'ConnectionNumber' / Int32ul, )) # Common to Events and Command requests self.__Reason = Enum( # TODO: Verify these codes... Int32ul, Undefined=0x0000, RejectedInitiator=0x0001, Busy=0x0002, Unspecified=0x0003, ) self.__InitFail = Embedded(Struct( 'Reason' / self.__Reason, )) self.__DataphaseInfo = Enum( Int32ul, Undefined=0x00000000, In=0x00000001, Out=0x00000002, ) self.__Command = Embedded(Struct( 'DataphaseInfo' / self.__DataphaseInfo, 'OperationCode' / self._OperationCode, 'TransactionID' / self._TransactionID, 'Parameter' / self.__Param, )) self.__Response = Embedded(Struct( 'ResponseCode' / self._ResponseCode, 'TransactionID' / self._TransactionID, 'Parameter' / self.__Param, )) self.__Event = Embedded(Struct( 'EventCode' / self._EventCode, 'TransactionID' / self._TransactionID, 'Parameter' / self.__EventParam, )) self.__StartData = Embedded(Struct( 'TransactionID' / self._TransactionID, 'TotalDataLength' / Int64ul, )) # TODO: Fix packing and unpacking dataphase data self.__Data = Embedded(Struct( 'TransactionID' / self._TransactionID, 'Data' / Bytes( lambda ctx: ctx._.Length - self.__Header.sizeof() - self._TransactionID.sizeof() ), )) self.__EndData = Embedded(Struct( 'TransactionID' / self._TransactionID, 'Data' / Bytes( lambda ctx: ctx._.Length - self.__Header.sizeof() - self._TransactionID.sizeof() ), )) self.__Cancel = Embedded(Struct( 'TransactionID' / self._TransactionID, )) # Convenience construct for parsing packets self.__PacketPayload = Debugger(Struct( 'Header' / Embedded(self.__Header), 'Payload' / Embedded(Switch( lambda ctx: ctx.Type, { 'InitCommand': self.__InitCommand, 'InitCommandAck': self.__InitCommandACK, 'InitEvent': self.__InitEvent, 'InitFail': self.__InitFail, 'Command': self.__Command, 'Response': self.__Response, 'Event': self.__Event, 'StartData': self.__StartData, 'Data': self.__Data, 'EndData': self.__EndData, }, default=Pass, )) )) def __parse_response(self, ipdata): '''Helper method for parsing data.''' # Build up container with all PTP info. response = self.__PacketPayload.parse(ipdata) # Sneak in an implicit Session ID response['SessionID'] = self.session_id return response def __recv(self, event=False, wait=False, raw=False): '''Helper method for receiving packets.''' hdrlen = self.__Header.sizeof() with self.__implicit_session(): ip = ( actual_socket(self.__evtcon) if event else actual_socket(self.__cmdcon) ) data = bytes() while True: try: ipdata = ip.recv(hdrlen) except socket.timeout: if event: return None else: ipdata = ip.recv(hdrlen) if len(ipdata) == 0 and not event: raise PTPError('Command connection dropped') elif event: return None # Read a single entire header while len(ipdata) < hdrlen: ipdata += ip.recv(hdrlen - len(ipdata)) header = self.__Header.parse( ipdata[0:hdrlen] ) # Read a single entire packet while len(ipdata) < header.Length: ipdata += ip.recv(header.Length - len(ipdata)) # Run sanity checks. if header.Type not in [ 'Cancel', 'Data', 'Event', 'Response', 'StartData', 'EndData', ]: raise PTPError( 'Unexpected PTP/IP packet type {}' .format(header.Type) ) if header.Type not in ['StartData', 'Data', 'EndData']: break else: response = self.__parse_response(ipdata) if header.Type == 'StartData': expected = response.TotalDataLength current_transaction = response.TransactionID elif ( header.Type == 'Data' and response.TransactionID == current_transaction ): data += response.Data elif ( header.Type == 'EndData' and response.TransactionID == current_transaction ): data += response.Data datalen = len(data) if datalen != expected: logger.warning( '{} data than expected {}/{}' .format( 'More' if datalen > expected else 'Less', datalen, expected ) ) response['Data'] = data response['Type'] = 'Data' return response if raw: # TODO: Deal with raw Data packets?? return ipdata else: return self.__parse_response(ipdata) def __send(self, ptp_container, event=False): '''Helper method for sending packets.''' packet = self.__Packet.build(ptp_container) ip = ( actual_socket(self.__evtcon) if event else actual_socket(self.__cmdcon) ) while ip.sendall(packet) is not None: logger.debug('Failed to send {} packet'.format(ptp_container.Type)) def __send_request(self, ptp_container): '''Send PTP request without checking answer.''' # Don't modify original container to keep abstraction barrier. ptp = Container(**ptp_container) # Send unused parameters always ptp['Parameter'] += [0] * (5 - len(ptp.Parameter)) # Send request ptp['Type'] = 'Command' ptp['DataphaseInfo'] = 'In' ptp['Payload'] = self.__Command.build(ptp) self.__send(ptp) def __send_data(self, ptp_container, data): '''Send data without checking answer.''' # Don't modify original container to keep abstraction barrier. ptp = Container(**ptp_container) # Send data ptp['Type'] = 'Data' ptp['DataphaseInfo'] = 'Out' ptp['Payload'] = data self.__send(ptp) # Actual implementation # --------------------- def send(self, ptp_container, data): '''Transfer operation with dataphase from initiator to responder''' logger.debug('SEND {}{}'.format( ptp_container.OperationCode, ' ' + str(list(map(hex, ptp_container.Parameter))) if ptp_container.Parameter else '', )) with self.__implicit_session(): with self.__transaction_lock: self.__send_request(ptp_container) self.__send_data(ptp_container, data) # Get response and sneak in implicit SessionID and missing # parameters. return self.__recv() def recv(self, ptp_container): '''Transfer operation with dataphase from responder to initiator.''' logger.debug('RECV {}{}'.format( ptp_container.OperationCode, ' ' + str(list(map(hex, ptp_container.Parameter))) if ptp_container.Parameter else '', )) with self.__implicit_session(): with self.__transaction_lock: self.__send_request(ptp_container) dataphase = self.__recv() if hasattr(dataphase, 'Data'): response = self.__recv() if ( (ptp_container.TransactionID != dataphase.TransactionID) or (ptp_container.SessionID != dataphase.SessionID) or (dataphase.TransactionID != response.TransactionID) or (dataphase.SessionID != response.SessionID) ): raise PTPError( 'Dataphase does not match with requested operation' ) response['Data'] = dataphase.Data return response else: return dataphase def mesg(self, ptp_container): '''Transfer operation without dataphase.''' op = ptp_container['OperationCode'] if op == 'OpenSession': self.__open_implicit_session() with self.__implicit_session(): with self.__transaction_lock: self.__send_request(ptp_container) # Get response and sneak in implicit SessionID and missing # parameters for FullResponse. response = self.__recv() rc = response['ResponseCode'] if op == 'OpenSession': if rc != 'OK': self.__close_implicit_session() elif op == 'CloseSession': if rc == 'OK': self.__close_implicit_session() return response def event(self, wait=False): '''Check event. If `wait` this function is blocking. Otherwise it may return None. ''' evt = None ipdata = None timeout = None if wait else 0.001 if not self.__event_queue.empty(): ipdata = self.__event_queue.get(block=not wait, timeout=timeout) if ipdata is not None: evt = self.__parse_response(ipdata) return evt def __poll_events(self): '''Poll events, adding them to a queue.''' logger.debug('Start') while ( not self.__implicit_session_shutdown.is_set() and self.__implicit_session_open.is_set() and _main_thread_alive() ): try: evt = self.__recv(event=True, wait=False, raw=True) except OSError as e: if e.errno == 9 and not self.__implicit_session_open.is_set(): break else: raise e if evt is not None: logger.debug('Event queued') self.__event_queue.put(evt) sleep(5e-3) logger.debug('Stop') def __ping_pong(self): '''Poll events, adding them to a queue.''' logger.debug('Start') last = time() while ( not self.__implicit_session_shutdown.is_set() and self.__implicit_session_open.is_set() and _main_thread_alive() ): if time() - last > 10: logger.debug('PING') # TODO: implement Ping Pong last = time() sleep(0.10) logger.debug('Stop')
class USBTransport(object): '''Implement USB transport.''' def __init__(self, *args, **kwargs): device = kwargs.get('device', None) '''Instantiate the first available PTP device over USB''' logger.debug('Init USB') self.__setup_constructors() # If no device is specified, find all devices claiming to be Cameras # and get the USB endpoints for the first one that works. if device is None: logger.debug('No device provided, probing all USB devices.') if isinstance(device, six.string_types): name = device logger.debug( 'Device name provided, probing all USB devices for {}.' .format(name) ) device = None else: name = None devs = ( [device] if (device is not None) else find_usb_cameras(name=name) ) self.__claimed = False self.__acquire_camera(devs) self.__event_queue = Queue() self.__event_shutdown = Event() # Locks for different end points. self.__inep_lock = RLock() self.__intep_lock = RLock() self.__outep_lock = RLock() # Slightly redundant transaction lock to avoid catching other request's # response self.__transaction_lock = RLock() self.__event_proc = Thread( name='EvtPolling', target=self.__poll_events ) self.__event_proc.daemon = False atexit.register(self._shutdown) self.__event_proc.start() def __available_cameras(self, devs): for dev in devs: if self.__setup_device(dev): logger.debug('Found USB PTP device {}'.format(dev)) yield else: message = 'No USB PTP device found.' logger.error(message) raise PTPError(message) def __acquire_camera(self, devs): '''From the cameras given, get the first one that does not fail''' for _ in self.__available_cameras(devs): # Stop system drivers try: if self.__dev.is_kernel_driver_active( self.__intf.bInterfaceNumber): try: self.__dev.detach_kernel_driver( self.__intf.bInterfaceNumber) except usb.core.USBError: message = ( 'Could not detach kernel driver. ' 'Maybe the camera is mounted?' ) logger.error(message) except NotImplementedError as e: logger.debug('Ignoring unimplemented function: {}'.format(e)) # Claim camera try: logger.debug('Claiming {}'.format(repr(self.__dev))) usb.util.claim_interface(self.__dev, self.__intf) self.__claimed = True except Exception as e: logger.warn('Failed to claim PTP device: {}'.format(e)) continue self.__dev.reset() break else: message = ( 'Could not acquire any camera.' ) logger.error(message) raise PTPError(message) def _shutdown(self): logger.debug('Shutdown request') self.__event_shutdown.set() # Free USB resource on shutdown. # Only join a running thread. if self.__event_proc.is_alive(): self.__event_proc.join(2) try: if self.__claimed: logger.debug('Release {}'.format(repr(self.__dev))) usb.util.release_interface(self.__dev, self.__intf) except Exception as e: logger.warn(e) # Helper methods. # --------------------- def __setup_device(self, dev): '''Get endpoints for a device. True on success.''' self.__inep = None self.__outep = None self.__intep = None self.__cfg = None self.__dev = None self.__intf = None # Attempt to find the USB in, out and interrupt endpoints for a PTP # interface. for cfg in dev: for intf in cfg: if intf.bInterfaceClass == PTP_USB_CLASS: for ep in intf: ep_type = endpoint_type(ep.bmAttributes) ep_dir = endpoint_direction(ep.bEndpointAddress) if ep_type == ENDPOINT_TYPE_BULK: if ep_dir == ENDPOINT_IN: self.__inep = ep elif ep_dir == ENDPOINT_OUT: self.__outep = ep elif ((ep_type == ENDPOINT_TYPE_INTR) and (ep_dir == ENDPOINT_IN)): self.__intep = ep if not (self.__inep and self.__outep and self.__intep): self.__inep = None self.__outep = None self.__intep = None else: logger.debug('Found {}'.format(repr(self.__inep))) logger.debug('Found {}'.format(repr(self.__outep))) logger.debug('Found {}'.format(repr(self.__intep))) self.__cfg = cfg self.__dev = dev self.__intf = intf return True return False def __setup_constructors(self): '''Set endianness and create transport-specific constructors.''' # Set endianness of constructors before using them. self._set_endian('little') self.__Length = Int32ul self.__Type = Enum( Int16ul, default=Pass, Undefined=0x0000, Command=0x0001, Data=0x0002, Response=0x0003, Event=0x0004, ) # This is just a convenience constructor to get the size of a header. self.__Code = Int16ul self.__Header = Struct( 'Length' / self.__Length, 'Type' / self.__Type, 'Code' / self.__Code, 'TransactionID' / self._TransactionID, ) # These are the actual constructors for parsing and building. self.__CommandHeader = Struct( 'Length' / self.__Length, 'Type' / self.__Type, 'OperationCode' / self._OperationCode, 'TransactionID' / self._TransactionID, ) self.__ResponseHeader = Struct( 'Length' / self.__Length, 'Type' / self.__Type, 'ResponseCode' / self._ResponseCode, 'TransactionID' / self._TransactionID, ) self.__EventHeader = Struct( 'Length' / self.__Length, 'Type' / self.__Type, 'EventCode' / self._EventCode, 'TransactionID' / self._TransactionID, ) # Apparently nobody uses the SessionID field. Even though it is # specified in ISO15740:2013(E), no device respects it and the session # number is implicit over USB. self.__Param = Range(0, 5, self._Parameter) self.__CommandTransactionBase = Struct( Embedded(self.__CommandHeader), 'Payload' / Bytes( lambda ctx, h=self.__Header: ctx.Length - h.sizeof() ) ) self.__CommandTransaction = ExprAdapter( self.__CommandTransactionBase, encoder=lambda obj, ctx, h=self.__Header: Container( Length=len(obj.Payload) + h.sizeof(), **obj ), decoder=lambda obj, ctx: obj, ) self.__ResponseTransactionBase = Struct( Embedded(self.__ResponseHeader), 'Payload' / Bytes( lambda ctx, h=self.__Header: ctx.Length - h.sizeof()) ) self.__ResponseTransaction = ExprAdapter( self.__ResponseTransactionBase, encoder=lambda obj, ctx, h=self.__Header: Container( Length=len(obj.Payload) + h.sizeof(), **obj ), decoder=lambda obj, ctx: obj, ) def __parse_response(self, usbdata): '''Helper method for parsing USB data.''' # Build up container with all PTP info. logger.debug('Transaction:') usbdata = bytearray(usbdata) if logger.isEnabledFor(logging.DEBUG): for l in hexdump( six.binary_type(usbdata[:512]), result='generator' ): logger.debug(l) transaction = self.__ResponseTransaction.parse(usbdata) response = Container( SessionID=self.session_id, TransactionID=transaction.TransactionID, ) logger.debug('Interpreting {} transaction'.format(transaction.Type)) if transaction.Type == 'Response': response['ResponseCode'] = transaction.ResponseCode response['Parameter'] = self.__Param.parse(transaction.Payload) elif transaction.Type == 'Event': event = self.__EventHeader.parse( usbdata[0:self.__Header.sizeof()] ) response['EventCode'] = event.EventCode response['Parameter'] = self.__Param.parse(transaction.Payload) else: command = self.__CommandHeader.parse( usbdata[0:self.__Header.sizeof()] ) response['OperationCode'] = command.OperationCode response['Data'] = transaction.Payload return response def __recv(self, event=False, wait=False, raw=False): '''Helper method for receiving data.''' # TODO: clear stalls automatically ep = self.__intep if event else self.__inep lock = self.__intep_lock if event else self.__inep_lock usbdata = array.array('B', []) with lock: tries = 0 # Attempt to read a header while len(usbdata) < self.__Header.sizeof() and tries < 5: if tries > 0: logger.debug('Data smaller than a header') logger.debug( 'Requesting {} bytes of data' .format(ep.wMaxPacketSize) ) try: usbdata += ep.read( ep.wMaxPacketSize ) except usb.core.USBError as e: # Return None on timeout or busy for events if ( (e.errno is None and ('timeout' in e.strerror.decode() or 'busy' in e.strerror.decode())) or (e.errno == 110 or e.errno == 16 or e.errno == 5) ): if event: return None else: logger.warning('Ignored exception: {}'.format(e)) else: logger.error(e) raise e tries += 1 logger.debug('Read {} bytes of data'.format(len(usbdata))) if len(usbdata) == 0: if event: return None else: raise PTPError('Empty USB read') if ( logger.isEnabledFor(logging.DEBUG) and len(usbdata) < self.__Header.sizeof() ): logger.debug('Incomplete header') for l in hexdump( six.binary_type(bytearray(usbdata)), result='generator' ): logger.debug(l) header = self.__ResponseHeader.parse( bytearray(usbdata[0:self.__Header.sizeof()]) ) if header.Type not in ['Response', 'Data', 'Event']: raise PTPError( 'Unexpected USB transfer type. ' 'Expected Response, Event or Data but received {}' .format(header.Type) ) while len(usbdata) < header.Length: usbdata += ep.read( min( header.Length - len(usbdata), # Up to 64kB 64 * 2**10 ) ) if raw: return usbdata else: return self.__parse_response(usbdata) def __send(self, ptp_container, event=False): '''Helper method for sending data.''' ep = self.__intep if event else self.__outep lock = self.__intep_lock if event else self.__outep_lock transaction = self.__CommandTransaction.build(ptp_container) with lock: try: sent = 0 while sent < len(transaction): sent = ep.write( # Up to 64kB transaction[sent:(sent + 64*2**10)] ) except usb.core.USBError as e: # Ignore timeout or busy device once. if ( (e.errno is None and ('timeout' in e.strerror.decode() or 'busy' in e.strerror.decode())) or (e.errno == 110 or e.errno == 16 or e.errno == 5) ): logger.warning('Ignored USBError {}'.format(e.errno)) ep.write(transaction) def __send_request(self, ptp_container): '''Send PTP request without checking answer.''' # Don't modify original container to keep abstraction barrier. ptp = Container(**ptp_container) # Don't send unused parameters try: while not ptp.Parameter[-1]: ptp.Parameter.pop() if len(ptp.Parameter) == 0: break except IndexError: # The Parameter list is already empty. pass # Send request ptp['Type'] = 'Command' ptp['Payload'] = self.__Param.build(ptp.Parameter) self.__send(ptp) def __send_data(self, ptp_container, data): '''Send data without checking answer.''' # Don't modify original container to keep abstraction barrier. ptp = Container(**ptp_container) # Send data ptp['Type'] = 'Data' ptp['Payload'] = data self.__send(ptp) @property def _dev(self): return None if self.__event_shutdown.is_set() else self.__dev @_dev.setter def _dev(self, value): raise ValueError('Read-only property') # Actual implementation # --------------------- def send(self, ptp_container, data): '''Transfer operation with dataphase from initiator to responder''' datalen = len(data) logger.debug('SEND {} {} bytes{}'.format( ptp_container.OperationCode, datalen, ' ' + str(list(map(hex, ptp_container.Parameter))) if ptp_container.Parameter else '', )) with self.__transaction_lock: self.__send_request(ptp_container) self.__send_data(ptp_container, data) # Get response and sneak in implicit SessionID and missing # parameters. response = self.__recv() logger.debug('SEND {} {} bytes {}{}'.format( ptp_container.OperationCode, datalen, response.ResponseCode, ' ' + str(list(map(hex, response.Parameter))) if ptp_container.Parameter else '', )) return response def recv(self, ptp_container): '''Transfer operation with dataphase from responder to initiator.''' logger.debug('RECV {}{}'.format( ptp_container.OperationCode, ' ' + str(list(map(hex, ptp_container.Parameter))) if ptp_container.Parameter else '', )) with self.__transaction_lock: self.__send_request(ptp_container) dataphase = self.__recv() if hasattr(dataphase, 'Data'): response = self.__recv() if not (ptp_container.SessionID == dataphase.SessionID == response.SessionID): self.__dev.reset() raise PTPError( 'Dataphase session ID missmatch: {}, {}, {}.' .format( ptp_container.SessionID, dataphase.SessionID, response.SessionID ) ) if not (ptp_container.TransactionID == dataphase.TransactionID == response.TransactionID): self.__dev.reset() raise PTPError( 'Dataphase transaction ID missmatch: {}, {}, {}.' .format( ptp_container.TransactionID, dataphase.TransactionID, response.TransactionID ) ) if not (ptp_container.OperationCode == dataphase.OperationCode): self.__dev.reset() raise PTPError( 'Dataphase operation code missmatch: {}, {}.'. format( ptp_container.OperationCode, dataphase.OperationCode ) ) response['Data'] = dataphase.Data else: response = dataphase logger.debug('RECV {} {}{}{}'.format( ptp_container.OperationCode, response.ResponseCode, ' {} bytes'.format(len(response.Data)) if hasattr(response, 'Data') else '', ' ' + str(list(map(hex, response.Parameter))) if response.Parameter else '', )) return response def mesg(self, ptp_container): '''Transfer operation without dataphase.''' logger.debug('MESG {}{}'.format( ptp_container.OperationCode, ' ' + str(list(map(hex, ptp_container.Parameter))) if ptp_container.Parameter else '', )) with self.__transaction_lock: self.__send_request(ptp_container) # Get response and sneak in implicit SessionID and missing # parameters for FullResponse. response = self.__recv() logger.debug('MESG {} {}{}'.format( ptp_container.OperationCode, response.ResponseCode, ' ' + str(list(map(hex, response.Parameter))) if response.Parameter else '', )) return response def event(self, wait=False): '''Check event. If `wait` this function is blocking. Otherwise it may return None. ''' evt = None usbdata = None if wait: usbdata = self.__event_queue.get(block=True) elif not self.__event_queue.empty(): usbdata = self.__event_queue.get(block=False) if usbdata is not None: evt = self.__parse_response(usbdata) return evt def __poll_events(self): '''Poll events, adding them to a queue.''' while not self.__event_shutdown.is_set() and _main_thread_alive(): try: evt = self.__recv(event=True, wait=False, raw=True) if evt is not None: logger.debug('Event queued') self.__event_queue.put(evt) except usb.core.USBError as e: logger.error( '{} polling exception: {}'.format(repr(self.__dev), e) ) # check if disconnected if e.errno == 19: break except Exception as e: logger.error( '{} polling exception: {}'.format(repr(self.__dev), e) )
""" What : Internet Group Management Protocol, Version 2 How : http://www.ietf.org/rfc/rfc2236.txt Who : jesse @ housejunkie . ca """ from construct import Byte, Enum,Struct, UBInt16 from construct.protocols.layer3.ipv4 import IpAddress from binascii import unhexlify import six igmp_type = Enum(Byte("igmp_type"), MEMBERSHIP_QUERY = 0x11, MEMBERSHIP_REPORT_V1 = 0x12, MEMBERSHIP_REPORT_V2 = 0x16, LEAVE_GROUP = 0x17, ) igmpv2_header = Struct("igmpv2_header", igmp_type, Byte("max_resp_time"), UBInt16("checksum"), IpAddress("group_address"), ) if __name__ == '__main__': capture = unhexlify(six.b("1600FA01EFFFFFFD")) print (igmpv2_header.parse(capture))
Who : jesse @ housejunkie . ca """ from construct import ( Byte, Enum, Struct, UBInt16, UBInt32, ) from construct.protocols.layer3.ipv4 import IpAddress igmp_type = Enum(Byte("igmp_type"), MEMBERSHIP_QUERY = 0x11, MEMBERSHIP_REPORT_V1 = 0x12, MEMBERSHIP_REPORT_V2 = 0x16, LEAVE_GROUP = 0x17, ) igmpv2_header = Struct("igmpv2_header", igmp_type, Byte("max_resp_time"), UBInt16("checksum"), IpAddress("group_address"), ) if __name__ == '__main__': capture = "1600FA01EFFFFFFD".decode("hex") print igmpv2_header.parse(capture)
def ssexy_linux(fname, *eips): import elf32 from construct import Struct, ULInt32, ULInt16, ULInt8, Array, CString from construct import OptionalGreedyRange # assume low-endian binary elf32_rel = Struct('elf32_rel', ULInt32('r_offset'), ULInt32('r_info')) ELF32_R_SYM = lambda x: x.r_info >> 8 ELF32_R_TYPE = lambda x: x.r_info & 0xff R_386_PC32 = 2 elf32_sym = Struct('elf32_sym', ULInt32('st_name'), ULInt32('st_value'), ULInt32('st_size'), ULInt8('st_info'), ULInt8('st_other'), ULInt16('st_shndx')) elf = elf32.elf32_file.parse_stream(file(fname, 'rb')) # retrieve section by name elf32_section = lambda elf, name: [x for x in elf.sections if x.name == name][0] # for now we assume that all code is in the .text section code_section = [x for x in elf.sections if x.name == '.text'] if not len(code_section): raise Exception('your binary doesn\'t have a .text section..') relocs = [x.data.value for x in elf.sections if x.name == '.rel.dyn'] if not len(relocs): raise Exception('no relocs available, compile with -pie') # read all relocations relocs = Array(len(relocs[0]) / elf32_rel.sizeof(), elf32_rel).parse(relocs[0]) # now get the offsets of the relocations relocs = set([x.r_offset for x in relocs]) imports = {} # a list of addresses that were used. addresses = [] # a list of all m128 values we use m128s = [] # a list of all dword values we use m32s = [] instructions = pyasm2.block() # get string at offset dynstr = lambda x: CString(None).parse( elf32_section(elf, '.dynstr').data.value[x:]) # read the symbol table imports = OptionalGreedyRange(elf32_sym).parse(elf32_section(elf, '.dynsym').data.value) # resolve relocations section = elf32_section(elf, '.rel.dyn') relocates = {} for x in xrange(0, section.size, elf32_rel.sizeof()): x = elf32_rel.parse(section.data.value[x:x+elf32_rel.sizeof()]) # relocation to fixup addresses to imports if ELF32_R_TYPE(x) == R_386_PC32: relocates[x.r_offset] = dynstr(imports[ELF32_R_SYM(x)].st_name) # walk each section, find those that are executable and disassemble those section = elf32_section(elf, '.text') g = distorm3.DecomposeGenerator(section.addr, section.data.value, distorm3.Decode32Bits) for instr in g: # useless instruction? if str(instr) in ('NOP', 'ADD [EAX], AL', 'LEA ESI, [ESI]', 'INT 3') or str(instr)[:2] == 'DB': continue # a jump to one of the imports? #if instr.mnemonic == 'JMP' and instr.operands[0].type == \ # distorm3.OPERAND_ABSOLUTE_ADDRESS and \ # instr.operands[0].disp in imports: # iat_label[instr.address] = imports[instr.operands[0].disp] # continue # quite hackery, but when the jumps with thunk address have been # processed, we can be fairly sure that there will be no (legit) # code anymore. #if len(iat_label): # break #print str(instr) #print str(instr) # convert the instruction from distorm3 format to pyasm2 format. instr = distorm3_to_pyasm2(instr) # we create the block already here, otherwise our `labelnr' is # not defined. #block = pyasm2.block(pyasm2.Label('%08x' % instr.address), instr) offset_flat = None addr = instr.address # now we check if this instruction has a relocation inside it # not a very efficient way, but oke. reloc = instr.length > 4 and relocs.intersection(range( instr.address, instr.address + instr.length - 3)) if reloc: # make an immediate with `addr' set to True enable_addr = lambda x: Immediate(int(x), addr=True) # TODO support for two relocations in one instruction # (displacement *and* immediate) reloc = reloc.pop() if not hasattr(instr, 'op1'): instr.op1, instr.op2 = None, None # there is only one operand, that's easy if not instr.op2: #sys.stderr.write('reloc in op1 %s??\n' % instr.op1) if isinstance(instr.op1, pyasm2.MemoryAddress): # special occassion, this memory addres is an import if instr.op1.reg1 is None and \ instr.op1.reg2 is None and \ int(instr.op1.disp) in imports: instr.op1 = imports[int(instr.op1.disp)] else: addresses.append(int(instr.op1.disp)) # change the displacement to a label #instr.op1 = str(instr.op1).replace('0x', # '__lbl_00') instr.op1 = enable_addr(instr.op1) elif isinstance(instr.op1, pyasm2.Immediate): addresses.append(int(instr.op1)) offset_flat = int(instr.op1) #instr.op1 = str(instr.op1).replace('0x', # 'offset flat:__lbl_00') # if the second operand is an immediate and the relocation is # in the last four bytes of the instruction, then this # immediate is the reloc. Otherwise, if the second operand is # a memory address, then it's the displacement. elif isinstance(instr.op2, pyasm2.Immediate) and reloc == \ instr.address + instr.length - 4: # keep this address addresses.append(int(instr.op2)) # make a label from this address # TODO: fix this horrible hack offset_flat = int(instr.op2) #instr.op2 = pyasm2.Label('offset flat:__lbl_%08x' % # int(instr.op2), prepend=False) elif isinstance(instr.op2, pyasm2.MemoryAddress) and \ reloc == instr.address + instr.length - 4: addresses.append(int(instr.op2.disp)) # change the displacement to a label instr.op2 = enable_addr(instr.op2) #instr.op2 = str(instr.op2).replace('0x', '__lbl_00') #sys.stderr.write('reloc in op2 memaddr %s\n' % # str(instr.op2)) # the relocation is not inside the second operand, it must be # inside the first operand after all. elif isinstance(instr.op1, pyasm2.MemoryAddress): addresses.append(int(instr.op1.disp)) instr.op1 = enable_addr(instr.op1) #instr.op1 = str(instr.op1).replace('0x', '__lbl_00') #sys.stderr.write('reloc in op1 memaddr %s\n' % # str(instr.op1)) elif isinstance(instr.op1, pyasm2.Immediate): addresses.append(int(instr.op1)) instr.op1 = enable_addr(instr.op1) #instr.op1 = '__lbl_%08x' % int(instr.op1) #sys.stderr.write('reloc in op1 imm %s\n' % instr.op1) else: sys.stderr.write('Invalid Relocation!\n') #print instr m32len = len(m32s) instr = translate.Translater(instr, m128s, m32s).translate() if offset_flat: encode_offset_flat = lambda x: str(x).replace('0x', 'offset flat:__lbl_') if isinstance(x, (int, long, pyasm2.imm)) and int(x) == offset_flat or isinstance(x, pyasm2.mem) and x.disp == offset_flat else x if isinstance(instr, pyasm2.block): for x in instr.instructions: x.op1 = encode_offset_flat(x.op1) x.op2 = encode_offset_flat(x.op2) else: x.op1 = encode_offset_flat(x.op1) x.op2 = encode_offset_flat(x.op2) # update stuff m32s = m32s[:m32len] + [x.replace('0x%08x' % offset_flat, 'offset flat:__lbl_%08x' % offset_flat) for x in m32s[m32len:]] instructions += pyasm2.block(pyasm2.Label('%08x' % addr), instr) # remove any addresses that are from within the current section newlist = addresses[:] for i in xrange(len(addresses)): if addresses[i] >= code_section[0].addr and addresses[i] < \ code_section[0].addr + code_section[0].size: newlist[i] = None addresses = filter(lambda x: x is not None, newlist) # walk over each instruction, if it has references, we update them for instr in instructions.instructions: # we can skip labels if isinstance(instr, pyasm2.Label): continue # check for references to imports if isinstance(instr, pyasm2.RelativeJump): # not very good, but for now (instead of checking relocs) we check # if the index is in the iat tabel.. #if int(instr.lbl.index, 16) in iat_label: #instr.lbl.index = iat_label[int(instr.lbl.index, 16)] #instr.lbl.prepend = False continue program = ['.file "ssexy.c"', '.intel_syntax noprefix'] # we walk over each section, if a reference to this section has been found # then we will dump the entire section as bytecode.. with matching labels for section in elf.sections: base = section.addr data = section.data.value addr = set(range(base, base + section.size)).intersection(addresses) if addr: # create a header for this section program.append('.section %s' % section.name) # for now we do it the easy way.. one line and label per byte, lol for addr in xrange(section.size): program.append('__lbl_%08x: .byte 0x%02x' % (base + addr, ord(data[addr]))) # empty line.. program.append('') # now we define all xmm's etc we gathered program.append('.align 4') program += m32s program.append('.align 16') program += m128s # time to define 'main' program.append('.text') program.append('.globl Main') program.append('.type Main, @function') OEP = elf.entry # f****d up shit relocates = dict(('jmp __lbl_%08x' % k, 'jmp ' + v) for k, v in relocates.items()) eips = ['__lbl_%08x' % x for x in eips] # append each instruction for instr in instructions.instructions: # if this is an label, we want a colon as postfix if isinstance(instr, pyasm2.Label): program.append(str(instr) + ':') # if OEP is at this address, we will also add the `_main' label if str(instr) == '__lbl_%08x' % OEP: program.append('Main:') # we have to initialize the stack register, so.. # for now we assume esp gpr is stored as first gpr in xmm7 program.append('movd xmm7, esp') # if the label is in the list of addresses to which we have to add # an "movd xmm7, esp" instruction, then add it (e.g. callback # function for pthread_create) if str(instr) in eips: program.append('movd xmm7, esp') else: # TODO: fix this terrible hack as well program.append(str(instr).replace('byte', 'byte ptr').replace( 'word', 'word ptr').replace('retn', 'ret').replace( '__lbl_00400000', '0x400000').replace('oword ptr', '')) if program[-1] in relocates: program[-1] = relocates[program[-1]] print '\n'.join(program)
if(sysstr =="Windows"): print ("Call Windows tasks") elif(sysstr == "Linux"): print ("Call Linux tasks") else: print ("Other System tasks") # UsePlatform() from construct import Struct, OptionalGreedyRange, Embed, Enum, Switch,String from construct import UBInt8, UBInt16, UBInt32, UBInt64, Byte from construct.macros import Array rfid = Struct("frame", UBInt8("flagID"), String("f",1), Array(4, String("nodeID",1)), ) mm = rfid.parse("F1070E0100138E0000F21D65" | hexStr_to_hex) print mm print [binascii.b2a_hex(x) for x in mm.nodeID] # print binascii.b2a_hex(mm.f) # print mm.flagID # print '01' | hex_to_dec # print [binascii.b2a_hex(x) for x in mm.nodeID ] a = {'or':2} # print a[::-1] if not a.get('order'): print 12