def _ReadFileHeader(self): """Reads the file header. Raises: IOError: if the file header cannot be read. """ if self._debug: print(u'Seeking file header offset: 0x{0:08x}'.format(0)) self._file_object.seek(0, os.SEEK_SET) file_header_data = self._file_object.read(self._FILE_HEADER.sizeof()) if self._debug: print(u'File header data:') print(hexdump.Hexdump(file_header_data)) try: file_header_struct = self._FILE_HEADER.parse(file_header_data) except construct.FieldError as exception: raise IOError( u'Unable to parse file header with error: {0:s}'.format( exception)) if self._debug: print(u'Signature\t\t\t\t\t\t\t: {0!s}'.format( file_header_struct.signature)) print(u'Number of pages\t\t\t\t\t\t\t: {0:d}'.format( file_header_struct.number_of_pages)) print(u'') page_sizes_data_size = file_header_struct.number_of_pages * 4 page_sizes_data = self._file_object.read(page_sizes_data_size) if self._debug: print(u'Page sizes data:') print(hexdump.Hexdump(page_sizes_data)) try: page_sizes_array = construct.Array( file_header_struct.number_of_pages, construct.UBInt32(u'page_sizes')).parse(page_sizes_data) except construct.FieldError as exception: raise IOError( u'Unable to parse page sizes array with error: {0:s}'.format( exception)) self._page_sizes = [] for page_index in range(file_header_struct.number_of_pages): self._page_sizes.append(page_sizes_array[page_index]) if self._debug: print(u'Page: {0:d} size\t\t\t\t\t\t\t: {1:d}'.format( page_index, page_sizes_array[page_index])) if self._debug: print(u'')
def WriteShellItem(self, shell_item_data): """Writes a shell item. Args: shell_item_data: a binary string containing the shell item data. """ print(hexdump.Hexdump(shell_item_data))
def WriteShellItem(self, shell_item_data): """Writes a shell item. Args: shell_item_data (bytes): shell item data. """ print(hexdump.Hexdump(shell_item_data))
def _ReadFileFooter(self): """Reads the file footer. Raises: IOError: if the file footer cannot be read. """ file_footer_data = self._file_object.read(self._FILE_FOOTER.sizeof()) if self._debug: print(u'File footer data:') print(hexdump.Hexdump(file_footer_data))
def _ReadDestListHeader(self, olecf_item): """Reads the DestList stream header. Args: olecf_item: the OLECF item (instance of pyolecf.item). Raises: IOError: if the DestList stream header cannot be read. """ olecf_item.seek(0, os.SEEK_SET) if self._debug: print(u'Reading header at offset: 0x{0:08x}'.format(0)) header_data = olecf_item.read(self._DEST_LIST_STREAM_HEADER.sizeof()) if self._debug: print(u'Header data:') print(hexdump.Hexdump(header_data)) try: dest_list_header_struct = self._DEST_LIST_STREAM_HEADER.parse(header_data) except construct.FieldError as exception: raise IOError(( u'Unable to parse header with error: {0:s}').format(exception)) if self._debug: print(u'Format version\t\t\t\t\t\t\t\t: {0:d}'.format( dest_list_header_struct.format_version)) print(u'Number of entries\t\t\t\t\t\t\t: {0:d}'.format( dest_list_header_struct.number_of_entries)) print(u'Number of pinned entries\t\t\t\t\t\t: {0:d}'.format( dest_list_header_struct.number_of_pinned_entries)) print(u'Unknown1\t\t\t\t\t\t\t\t: {0:f}'.format( dest_list_header_struct.unknown1)) print(u'Last entry number\t\t\t\t\t\t\t: {0:d}'.format( dest_list_header_struct.last_entry_number)) print(u'Unknown2\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( dest_list_header_struct.unknown2)) print(u'Last revision number\t\t\t\t\t\t\t: {0:d}'.format( dest_list_header_struct.last_revision_number)) print(u'Unknown3\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( dest_list_header_struct.unknown3)) print(u'') if dest_list_header_struct.format_version not in (1, 3, 4): raise IOError( u'Unsupported format version: {0:d}'.format( dest_list_header_struct.format_version)) self._format_version = dest_list_header_struct.format_version
def _ReadFileHeader(self): """Reads a file header. Raises: IOError: if the file header cannot be read. """ if self._debug: print(u'Seeking file header offset: 0x{0:08x}'.format(0)) self._file_object.seek(0, os.SEEK_SET) file_header_data = self._file_object.read( self._EMF_FILE_HEADER.sizeof()) if self._debug: print(u'File header data:') print(hexdump.Hexdump(file_header_data)) try: emf_file_header_struct = self._EMF_FILE_HEADER.parse( file_header_data) except construct.FieldError as exception: raise IOError((u'Unable to parse file header with error: {0:s}' ).format(exception)) if self._debug: record_type_string = self._EMF_RECORD_TYPES.get( emf_file_header_struct.record_type, u'UNKNOWN') print(u'Record type\t\t\t\t\t\t\t: 0x{0:04x} ({1:s})'.format( emf_file_header_struct.record_type, record_type_string)) print(u'Record size\t\t\t\t\t\t\t: {0:d}'.format( emf_file_header_struct.record_size)) print(u'Signature\t\t\t\t\t\t\t: 0x{0:04x}'.format( emf_file_header_struct.signature)) print(u'Signature\t\t\t\t\t\t\t: 0x{0:04x}'.format( emf_file_header_struct.format_version)) print(u'File size\t\t\t\t\t\t\t: {0:d}'.format( emf_file_header_struct.file_size)) print(u'Number of records\t\t\t\t\t\t: {0:d}'.format( emf_file_header_struct.number_of_records)) print(u'Number of handles\t\t\t\t\t\t: {0:d}'.format( emf_file_header_struct.number_of_handles)) print(u'Unknown (reserved)\t\t\t\t\t\t: 0x{0:04x}'.format( emf_file_header_struct.unknown1)) print(u'Description string size\t\t\t\t\t\t: {0:d}'.format( emf_file_header_struct.description_string_size)) print(u'Description string offset\t\t\t\t\t: 0x{0:04x}'.format( emf_file_header_struct.description_string_offset)) print(u'')
def _ReadFileHeader(self): """Reads a file header. Raises: IOError: if the file header cannot be read. """ if self._debug: print(u'Seeking file header offset: 0x{0:08x}'.format(0)) self._file_object.seek(0, os.SEEK_SET) file_header_data = self._file_object.read( self._WMF_FILE_HEADER.sizeof()) if self._debug: print(u'File header data:') print(hexdump.Hexdump(file_header_data)) try: wmf_file_header_struct = self._WMF_FILE_HEADER.parse( file_header_data) except construct.FieldError as exception: raise IOError((u'Unable to parse file header with error: {0:s}' ).format(exception)) if self._debug: print(u'File type\t\t\t\t\t\t\t: 0x{0:04x}'.format( wmf_file_header_struct.file_type)) print(u'Record size\t\t\t\t\t\t\t: {0:d}'.format( wmf_file_header_struct.record_size)) print(u'Format version\t\t\t\t\t\t\t: {0:d}'.format( wmf_file_header_struct.format_version)) print(u'File size\t\t\t\t\t\t\t: {0:d}'.format( wmf_file_header_struct.file_size)) print(u'Maximum number of object\t\t\t\t\t: {0:d}'.format( wmf_file_header_struct.maximum_number_of_objects)) print(u'Largest record size\t\t\t\t\t\t: {0:d}'.format( wmf_file_header_struct.largest_record_size)) print(u'Number of records\t\t\t\t\t\t: {0:d}'.format( wmf_file_header_struct.number_of_records)) print(u'') if wmf_file_header_struct.file_type not in (1, 2): raise IOError(u'Unsupported file type: {0:d}'.format( wmf_file_header_struct.file_type)) if wmf_file_header_struct.record_size != 9: raise IOError(u'Unsupported record size: {0:d}'.format( wmf_file_header_struct.record_size))
def _ReadRecord(self, file_offset): """Reads a record. Args: file_offset: an integer containing the file offset of the record. Raises: IOError: if the record cannot be read. """ if self._debug: print(u'Seeking record offset: 0x{0:08x}'.format(file_offset)) self._file_object.seek(file_offset, os.SEEK_SET) record_header_data_size = self._WMF_RECORD_HEADER.sizeof() record_header_data = self._file_object.read(record_header_data_size) if self._debug: print(u'Record header data:') print(hexdump.Hexdump(record_header_data)) try: wmf_record_header_struct = self._WMF_RECORD_HEADER.parse( record_header_data) except construct.FieldError as exception: raise IOError((u'Unable to parse record header with error: {0:s}' ).format(exception)) record_size = wmf_record_header_struct.record_size * 2 if self._debug: print(u'Record size\t\t\t\t\t\t\t: {0:d} ({1:d})'.format( wmf_record_header_struct.record_size, record_size)) record_type_string = self._WMF_RECORD_TYPES.get( wmf_record_header_struct.record_type, u'UNKNOWN') print(u'Record type\t\t\t\t\t\t\t: 0x{0:04x} ({1:s})'.format( wmf_record_header_struct.record_type, record_type_string)) print(u'') data_offset = file_offset + record_header_data_size data_size = record_size - record_header_data_size if self._debug: self._ReadRecordData(wmf_record_header_struct.record_type, data_size) return Record(wmf_record_header_struct.record_type, record_size, data_offset, data_size)
def _ReadLruData(self): """Reads the LRU data.""" lru_data = self._file_object.read(self._LRU_DATA.sizeof()) if self._debug: print(u'Index file LRU data:') print(hexdump.Hexdump(lru_data)) try: index_file_lru = self._LRU_DATA.parse(lru_data) except construct.FieldError as exception: raise IOError(u'Unable to parse LRU data with error: {0:s}'.format( exception)) if self._debug: print(u'Filled flag\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( index_file_lru.get(u'filled_flag'))) for value in index_file_lru.get(u'sizes'): print(u'Size\t\t\t\t\t\t\t\t\t: {0:d}'.format(value)) cache_address_index = 0 for value in index_file_lru.get(u'head_addresses'): cache_address = CacheAddress(value) print(u'Head address: {0:d}\t\t\t\t\t\t\t\t: {1:s}'.format( cache_address_index, cache_address.GetDebugString())) cache_address_index += 1 cache_address_index = 0 for value in index_file_lru.get(u'tail_addresses'): cache_address = CacheAddress(value) print(u'Tail address: {0:d}\t\t\t\t\t\t\t\t: {1:s}'.format( cache_address_index, cache_address.GetDebugString())) cache_address_index += 1 cache_address = CacheAddress(index_file_lru.get(u'transaction_address')) print(u'Transaction address\t\t\t\t\t\t\t: {0:s}'.format( cache_address.GetDebugString())) print(u'Operation\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( index_file_lru.get(u'operation'))) print(u'Operation list\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( index_file_lru.get(u'operation_list'))) print(u'')
def _ReadRecordData(self, record_type, data_size): """Reads a record. Args: record_type (int): record type. data_size (int): size of the record data. Raises: IOError: if the record cannot be read. """ record_data = self._file_object.read(data_size) if self._debug and data_size > 0: print(u'Record data:') print(hexdump.Hexdump(record_data)) # TODO: use lookup dict with callback. struct_type = self._EMF_RECORD_DATA_STRUCT_TYPES.get(record_type, None) if not struct_type: return try: record_data_struct = struct_type.parse(record_data) except construct.FieldError as exception: raise IOError((u'Unable to parse record data with error: {0:s}' ).format(exception)) if self._debug: if record_type == 0x0018: print(u'Color\t\t\t\t\t\t\t\t: 0x{0:04x}'.format( record_data_struct.color)) elif record_type == 0x0025: stock_object_string = self._EMF_STOCK_OBJECTS.get( record_data_struct.object_identifier, None) if stock_object_string: print(u'Object identifier\t\t\t\t\t\t: 0x{0:08x} ({1:s})'. format(record_data_struct.object_identifier, stock_object_string)) else: print(u'Object identifier\t\t\t\t\t\t: 0x{0:08x}'.format( record_data_struct.object_identifier)) print(u'')
def _ReadVolumePath(self, volume_path_record_data): """Reads the volume path. Args: volume_path_record_data: the volume path record data. Raises: IOError: if the volume path cannot be read. """ try: volume_path_struct = self._VOLUME_PATH.parse( volume_path_record_data) except construct.FieldError as exception: raise IOError( u'Unable to parse volume path with error: {0:s}'.format( exception)) record_size = volume_path_struct.get(u'record_size') record_type = volume_path_struct.get(u'record_type') if record_type != 2: raise IOError( u'Unsupported record type: {0:d}'.format(record_type)) if self._debug: print(u'Volume path record data:') print(hexdump.Hexdump(volume_path_record_data)) try: # The struct includes the end-of-string character that we need # to strip off. self.volume_path = volume_path_struct.get(u'volume_path') self.volume_path = b''.join(self.volume_path).decode(u'utf16')[:-1] except UnicodeDecodeError as exception: self.volume_path = u'' if self._debug: print(u'Record size\t\t\t\t\t\t\t\t: {0:d}'.format(record_size)) print(u'Record type\t\t\t\t\t\t\t\t: {0:d} ({1:s})'.format( record_type, self._RECORD_TYPES.get(record_type, u'Unknown'))) print(u'Volume path\t\t\t\t\t\t\t\t: {0:s}'.format( self.volume_path)) print(u'')
def _ReadPage(self, page_size): """Reads the page. Args: page_size (int): page size. """ page_data = self._file_object.read(page_size) try: page_header_struct = self._PAGE_HEADER.parse(page_data) except construct.FieldError as exception: raise IOError( u'Unable to parse file header with error: {0:s}'.format( exception)) page_header_data_size = 8 + (4 * page_header_struct.number_of_records) if self._debug: print(u'Page header data:') print(hexdump.Hexdump(page_data[:page_header_data_size])) if self._debug: print(u'Signature\t\t\t\t\t\t\t: 0x{0:08x}'.format( page_header_struct.signature)) print(u'Number of records\t\t\t\t\t\t: {0:d}'.format( page_header_struct.number_of_records)) record_offsets = [] for record_index in range(page_header_struct.number_of_records): record_offsets.append(page_header_struct.offsets[record_index]) if self._debug: print(u'Record: {0:d} offset\t\t\t\t\t\t: {1:d}'.format( record_index, page_header_struct.offsets[record_index])) if self._debug: print(u'') for record_offset in iter(record_offsets): self._ParseRecord(page_data, record_offset)
def _ParseRecord(self, page_data, record_offset): """Reads a record from the page data. Args: page_data (bytes): page data. record_offset (int): record offset. """ try: record_header_struct = self._RECORD_HEADER.parse( page_data[record_offset:]) except construct.FieldError as exception: raise IOError( u'Unable to parse record header with error: {0:s}'.format( exception)) record_data_size = record_offset + record_header_struct.size if self._debug: print(u'Record data:') print(hexdump.Hexdump(page_data[record_offset:record_data_size])) if self._debug: print(u'Size\t\t\t\t\t\t\t\t: {0:d}'.format( record_header_struct.size)) print(u'Unknown1\t\t\t\t\t\t\t: 0x{0:08x}'.format( record_header_struct.unknown1)) print(u'Flags\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( record_header_struct.flags)) print(u'Unknown2\t\t\t\t\t\t\t: 0x{0:08x}'.format( record_header_struct.unknown2)) print(u'URL offset\t\t\t\t\t\t\t: {0:d}'.format( record_header_struct.url_offset)) print(u'name offset\t\t\t\t\t\t\t: {0:d}'.format( record_header_struct.name_offset)) print(u'path offset\t\t\t\t\t\t\t: {0:d}'.format( record_header_struct.path_offset)) print(u'value offset\t\t\t\t\t\t\t: {0:d}'.format( record_header_struct.value_offset)) print(u'Unknown3\t\t\t\t\t\t\t: 0x{0:08x}'.format( record_header_struct.unknown3)) date_time = (datetime.datetime(2001, 1, 1) + datetime.timedelta( seconds=int(record_header_struct.expiration_time))) print(u'expiration time\t\t\t\t\t\t\t: {0!s} ({1:f})'.format( date_time, record_header_struct.expiration_time)) date_time = (datetime.datetime(2001, 1, 1) + datetime.timedelta( seconds=int(record_header_struct.creation_time))) print(u'creation time\t\t\t\t\t\t\t: {0!s} ({1:f})'.format( date_time, record_header_struct.creation_time)) print(u'') if record_header_struct.url_offset: data_offset = record_offset + record_header_struct.url_offset string = construct.CString(u'string').parse( page_data[data_offset:record_data_size]) else: sting = u'' print(u'URL\t\t\t\t\t\t\t\t: {0:s}'.format(string)) if record_header_struct.name_offset: data_offset = record_offset + record_header_struct.name_offset string = construct.CString(u'string').parse( page_data[data_offset:record_data_size]) else: sting = u'' print(u'Name\t\t\t\t\t\t\t\t: {0:s}'.format(string)) if record_header_struct.path_offset: data_offset = record_offset + record_header_struct.path_offset string = construct.CString(u'string').parse( page_data[data_offset:record_data_size]) else: sting = u'' print(u'Path\t\t\t\t\t\t\t\t: {0:s}'.format(string)) if record_header_struct.value_offset: data_offset = record_offset + record_header_struct.value_offset string = construct.CString(u'string').parse( page_data[data_offset:record_data_size]) else: sting = u'' print(u'Value\t\t\t\t\t\t\t\t: {0:s}'.format(string)) print(u'')
def _ReadEntry(self, file_offset): """Reads an entry. Args: file_offset (int): entry offset relative to the start of the file. Returns: int: size of the entry. Raises: IOError: if the entry cannot be read. """ if self._debug: print(u'Seeking entry at offset: 0x{0:08x}'.format(file_offset)) self._file_object.seek(file_offset, os.SEEK_SET) entry_struct_size = self._UTMP_ENTRY.sizeof() entry_data = self._file_object.read(entry_struct_size) file_offset += entry_struct_size if self._debug: print(u'Entry data:') print(hexdump.Hexdump(entry_data)) try: entry_struct = self._UTMP_ENTRY.parse(entry_data) except construct.FieldError as exception: raise IOError(( u'Unable to parse entry data section with error: ' u'{0:s}').file_format(exception)) if self._debug: print(u'Type\t\t\t\t\t\t\t\t: 0x{0:08x}'.format(entry_struct.type)) print(u'PID\t\t\t\t\t\t\t\t: {0:d}'.format(entry_struct.pid)) terminal = entry_struct.terminal.replace(u'\0', '') print(u'Terminal\t\t\t\t\t\t\t: {0:s}'.format(terminal)) print(u'Terminal ID\t\t\t\t\t\t\t: {0:d}'.format(entry_struct.terminal_id)) username = entry_struct.username.replace(u'\0', '') print(u'Username\t\t\t\t\t\t\t: {0:s}'.format(username)) hostname = entry_struct.hostname.replace(u'\0', '') print(u'Hostname\t\t\t\t\t\t\t: {0:s}'.format(hostname)) print(u'Termination\t\t\t\t\t\t\t: 0x{0:04x}'.format(entry_struct.termination)) print(u'Exit\t\t\t\t\t\t\t\t: 0x{0:04x}'.format(entry_struct.exit)) print(u'Session\t\t\t\t\t\t\t\t: {0:d}'.format(entry_struct.session)) date_time = (datetime.datetime(1970, 1, 1) + datetime.timedelta( seconds=int(entry_struct.timestamp))) print(u'Timestamp\t\t\t\t\t\t\t: {0!s} ({1:d})'.format( date_time, entry_struct.timestamp)) print(u'Micro seconds\t\t\t\t\t\t\t: {0:d}'.format(entry_struct.micro_seconds)) print(u'Address A\t\t\t\t\t\t\t: 0x{0:08x}'.format(entry_struct.address_a)) print(u'Address B\t\t\t\t\t\t\t: 0x{0:08x}'.format(entry_struct.address_b)) print(u'Address C\t\t\t\t\t\t\t: 0x{0:08x}'.format(entry_struct.address_c)) print(u'Address D\t\t\t\t\t\t\t: 0x{0:08x}'.format(entry_struct.address_d)) print(u'') return entry_struct_size
def _ReadFixedSizeDataSection(self): """Reads the fixed size data section. Raises: IOError: if the fixed size data section cannot be read. """ if self._debug: print( u'Seeking fixed size data section offset: 0x{0:08x}'.format(0)) self._file_object.seek(0, os.SEEK_SET) fixed_size_data = self._file_object.read( self._JOB_FIXED_SIZE_DATA_STRUCT.sizeof()) if self._debug: print(u'Fixed size data:') print(hexdump.Hexdump(fixed_size_data)) try: job_fixed_size_data_struct = self._JOB_FIXED_SIZE_DATA_STRUCT.parse( fixed_size_data) except construct.FieldError as exception: raise IOError( (u'Unable to parse fixed size data section with error: ' u'{0:s}').format(exception)) if self._debug: print(u'Product version\t\t\t\t\t\t\t: 0x{0:04x}'.format( job_fixed_size_data_struct.product_version)) print(u'Format version\t\t\t\t\t\t\t: 0x{0:04x}'.format( job_fixed_size_data_struct.format_version)) uuid_object = uuid.UUID( bytes_le=job_fixed_size_data_struct.job_identifier) print(u'Job identifier\t\t\t\t\t\t\t: {0!s}'.format(uuid_object)) print(u'Application name size offset\t\t\t\t\t: 0x{0:04x}'.format( job_fixed_size_data_struct.application_name_size_offset)) print(u'Trigger offset\t\t\t\t\t\t\t: 0x{0:04x}'.format( job_fixed_size_data_struct.trigger_offset)) print(u'Error retry count\t\t\t\t\t\t: {0:d}'.format( job_fixed_size_data_struct.error_retry_count)) print(u'Error retry interval\t\t\t\t\t\t: {0:d} minutes'.format( job_fixed_size_data_struct.error_retry_interval)) print(u'Idle deadline\t\t\t\t\t\t\t: {0:d} minutes'.format( job_fixed_size_data_struct.idle_deadline)) print(u'Idle wait\t\t\t\t\t\t\t: {0:d} minutes'.format( job_fixed_size_data_struct.idle_wait)) print(u'Priority\t\t\t\t\t\t\t: 0x{0:08x}'.format( job_fixed_size_data_struct.priority)) print(u'Maximum run time\t\t\t\t\t\t: {0:d} milliseconds'.format( job_fixed_size_data_struct.maximum_run_time)) print(u'Exit code\t\t\t\t\t\t\t: 0x{0:08x}'.format( job_fixed_size_data_struct.exit_code)) print(u'Status\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( job_fixed_size_data_struct.status)) print(u'Flags\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( job_fixed_size_data_struct.flags)) print(u'Year\t\t\t\t\t\t\t\t: {0:d}'.format( job_fixed_size_data_struct.year)) print(u'Month\t\t\t\t\t\t\t\t: {0:d}'.format( job_fixed_size_data_struct.month)) print(u'Weekday\t\t\t\t\t\t\t\t: {0:d}'.format( job_fixed_size_data_struct.weekday)) print(u'Day\t\t\t\t\t\t\t\t: {0:d}'.format( job_fixed_size_data_struct.day)) print(u'Hours\t\t\t\t\t\t\t\t: {0:d}'.format( job_fixed_size_data_struct.hours)) print(u'Minutes\t\t\t\t\t\t\t\t: {0:d}'.format( job_fixed_size_data_struct.minutes)) print(u'Seconds\t\t\t\t\t\t\t\t: {0:d}'.format( job_fixed_size_data_struct.seconds)) print(u'Milliseconds\t\t\t\t\t\t\t: {0:d}'.format( job_fixed_size_data_struct.milliseconds)) print(u'')
def _ReadDestListEntry(self, olecf_item, stream_offset): """Reads a DestList stream entry. Args: olecf_item: the OLECF item (instance of pyolecf.item). stream_offset: an integer containing the stream offset of the entry. Returns: An integer containing the entry data size. Raises: IOError: if the DestList stream entry cannot be read. """ if self._format_version == 1: dest_list_entry = self._DEST_LIST_STREAM_ENTRY_V1 elif self._format_version >= 3: dest_list_entry = self._DEST_LIST_STREAM_ENTRY_V3 if self._debug: print(u'Reading entry at offset: 0x{0:08x}'.format(stream_offset)) entry_data = olecf_item.read(dest_list_entry.sizeof()) if self._debug: print(u'Entry data:') print(hexdump.Hexdump(entry_data)) try: dest_list_entry_struct = dest_list_entry.parse(entry_data) except construct.FieldError as exception: raise IOError(( u'Unable to parse entry with error: {0:s}').format(exception)) entry_path_size = dest_list_entry_struct.path_size * 2 if self._debug: print(u'Unknown1\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( dest_list_entry_struct.unknown1)) try: uuid_object = uuid.UUID( bytes_le=dest_list_entry_struct.droid_volume_identifier) print(u'Droid volume identifier\t\t\t\t\t\t\t: {0:s}'.format( uuid_object)) except (TypeError, ValueError): pass try: uuid_object = uuid.UUID( bytes_le=dest_list_entry_struct.droid_file_identifier) print(u'Droid file identifier\t\t\t\t\t\t\t: {0:s}'.format( uuid_object)) except (TypeError, ValueError): pass try: uuid_object = uuid.UUID( bytes_le=dest_list_entry_struct.birth_droid_volume_identifier) print(u'Birth droid volume identifier\t\t\t\t\t\t: {0:s}'.format( uuid_object)) except (TypeError, ValueError): pass try: uuid_object = uuid.UUID( bytes_le=dest_list_entry_struct.birth_droid_file_identifier) print(u'Birth droid file identifier\t\t\t\t\t\t: {0:s}'.format( uuid_object)) except (TypeError, ValueError): pass hostname = dest_list_entry_struct.hostname hostname, _, _ = hostname.partition(u'\x00') print(u'Hostname\t\t\t\t\t\t\t\t: {0:s}'.format(hostname)) print(u'Entry number\t\t\t\t\t\t\t\t: {0:d}'.format( dest_list_entry_struct.entry_number)) print(u'Unknown2\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( dest_list_entry_struct.unknown2)) print(u'Unknown3\t\t\t\t\t\t\t\t: {0:f}'.format( dest_list_entry_struct.unknown3)) print(u'Last modification time\t\t\t\t\t\t\t: {0!s}'.format( FromFiletime(dest_list_entry_struct.last_modification_time))) # TODO: debug print pin status. print(u'Pin status\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( dest_list_entry_struct.pin_status)) if self._format_version >= 3: print(u'Unknown4\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( dest_list_entry_struct.unknown4)) print(u'Unknown5\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( dest_list_entry_struct.unknown5)) print(u'Unknown6\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( dest_list_entry_struct.unknown6)) print(u'Path size\t\t\t\t\t\t\t\t: {0:d} ({1:d})'.format( dest_list_entry_struct.path_size, entry_path_size)) print(u'') entry_path_data = olecf_item.read(entry_path_size) if self._debug: print(u'Entry path data:') print(hexdump.Hexdump(entry_path_data)) try: path_string = entry_path_data.decode(u'utf16') except UnicodeDecodeError as exception: path_string = u'' if self._debug: print(u'Path string\t\t\t\t\t\t\t\t: {0:s}'.format(path_string)) print(u'') entry_footer_data = b'' if self._format_version >= 3: entry_footer_data = olecf_item.read(4) if self._debug: print(u'Entry footer data:') print(hexdump.Hexdump(entry_footer_data)) return len(entry_data) + len(entry_path_data) + len(entry_footer_data)
def _ReadRecordData(self, record_type, data_size): """Reads a record. Args: record_type (int): record type. data_size (int): size of the record data. Raises: IOError: if the record cannot be read. """ record_data = self._file_object.read(data_size) if self._debug and data_size > 0: print(u'Record data:') print(hexdump.Hexdump(record_data)) # TODO: use lookup dict with callback. struct_type = self._WMF_RECORD_DATA_STRUCT_TYPES.get(record_type, None) if not struct_type: return try: record_data_struct = struct_type.parse(record_data) except construct.FieldError as exception: raise IOError((u'Unable to parse record data with error: {0:s}' ).format(exception)) if self._debug: if record_type == 0x0103: map_mode_string = self._WMF_MAP_MODES.get( record_data_struct.map_mode, u'UNKNOWN') print(u'Map mode\t\t\t\t\t\t\t: 0x{0:04x} ({1:s})'.format( record_data_struct.map_mode, map_mode_string)) elif record_type == 0x0107: stretch_mode_string = self._WMF_STRETCH_MODES.get( record_data_struct.stretch_mode, u'UNKNOWN') print(u'Stretch mode\t\t\t\t\t\t\t: 0x{0:04x} ({1:s})'.format( record_data_struct.stretch_mode, stretch_mode_string)) elif record_type == 0x0127: print( u'Number of saved device context\t\t\t\t\t: {0:d}'.format( record_data_struct.number_of_saved_device_context)) elif record_type in (0x020b, 0x020c): print(u'X coordinate\t\t\t\t\t\t\t: {0:d}'.format( record_data_struct.x_coordinate)) print(u'Y coordinate\t\t\t\t\t\t\t: {0:d}'.format( record_data_struct.y_coordinate)) elif record_type == 0x0b41: raster_operation_string = self._WMF_RASTER_OPERATIONS.get( record_data_struct.raster_operation, u'UNKNOWN') print( u'Raster operation\t\t\t\t\t\t: 0x{0:08x} ({1:s})'.format( record_data_struct.raster_operation, raster_operation_string)) print(u'Source height\t\t\t\t\t\t\t: {0:d}'.format( record_data_struct.source_height)) print(u'Source width\t\t\t\t\t\t\t: {0:d}'.format( record_data_struct.source_width)) print(u'Source X coordinate\t\t\t\t\t\t: {0:d}'.format( record_data_struct.source_x_coordinate)) print(u'Source Y coordinate\t\t\t\t\t\t: {0:d}'.format( record_data_struct.source_y_coordinate)) print(u'Destination height\t\t\t\t\t\t: {0:d}'.format( record_data_struct.destination_height)) print(u'Destination width\t\t\t\t\t\t: {0:d}'.format( record_data_struct.destination_width)) print(u'Destination X coordinate\t\t\t\t\t: {0:d}'.format( record_data_struct.destination_x_coordinate)) print(u'Destination Y coordinate\t\t\t\t\t: {0:d}'.format( record_data_struct.destination_y_coordinate)) print(u'')
def _ReadChangeLogEntry(self): """Reads a change log entry. Returns: A change log entry (instance of ChangeLogEntry). Raises: IOError: if the change log entry cannot be read. """ file_offset = self._file_object.tell() try: change_log_entry_struct = self._CHANGE_LOG_ENTRY.parse_stream( self._file_object) except construct.FieldError as exception: raise IOError( u'Unable to parse change log entry with error: {0:s}'.format( exception)) record_size = change_log_entry_struct.get(u'record_size') record_type = change_log_entry_struct.get(u'record_type') if record_type != 1: raise IOError( u'Unsupported record type: {0:d}'.format(record_type)) signature = change_log_entry_struct.get(u'signature') if signature != self.SIGNATURE: raise IOError(u'Unsupported change.log file signature') change_log_entry = ChangeLogEntry() change_log_entry.entry_type = change_log_entry_struct.get( u'entry_type') change_log_entry.entry_flags = change_log_entry_struct.get( u'entry_flags') change_log_entry.file_attribute_flags = change_log_entry_struct.get( u'file_attribute_flags') change_log_entry.sequence_number = change_log_entry_struct.get( u'sequence_number') try: # The struct includes the end-of-string character that we need # to strip off. process_name = change_log_entry_struct.get(u'process_name') process_name = b''.join(process_name).decode(u'utf16')[:-1] except UnicodeDecodeError as exception: process_name = u'' change_log_entry.process_name = process_name self._file_object.seek(file_offset, os.SEEK_SET) change_log_entry_record_data = self._file_object.read(record_size) if self._debug: print(u'Change log entry record data:') print(hexdump.Hexdump(change_log_entry_record_data)) if self._debug: print(u'Record size\t\t\t\t\t\t\t\t: {0:d}'.format(record_size)) print(u'Record type\t\t\t\t\t\t\t\t: {0:d} ({1:s})'.format( record_type, self._RECORD_TYPES.get(record_type, u'Unknown'))) print(u'Signature\t\t\t\t\t\t\t\t: 0x{0:08x}'.format(signature)) print(u'Entry type\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( change_log_entry.entry_type)) for flag, description in self.LOG_ENTRY_TYPES.items(): if change_log_entry.entry_type & flag: print(u'\t{0:s}'.format(description)) print(u'') print(u'Entry flags\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( change_log_entry.entry_flags)) for flag, description in self.LOG_ENTRY_FLAGS.items(): if change_log_entry.entry_flags & flag: print(u'\t{0:s}'.format(description)) print(u'') print(u'File attribute flags\t\t\t\t\t\t\t: 0x{0:08x}'.format( change_log_entry.file_attribute_flags)) # TODO: print flags. print(u'Sequence number\t\t\t\t\t\t\t\t: {0:d}'.format( change_log_entry.sequence_number)) print(u'Process name data size\t\t\t\t\t\t\t: 0x{0:08x}'.format( change_log_entry_struct.get(u'process_name_data_size'))) print(u'Unknown1\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( change_log_entry_struct.get(u'unknown1'))) print(u'Process name\t\t\t\t\t\t\t\t: {0:s}'.format( change_log_entry.process_name)) sub_record_data_offset = (change_log_entry_struct.sub_record_data - file_offset) sub_record_data_size = record_size - 4 if self._debug: print(u'Sub record data offset\t\t\t\t\t\t\t: {0:d}'.format( sub_record_data_offset)) print(u'Sub record data size\t\t\t\t\t\t\t: {0:d}'.format( sub_record_data_size - sub_record_data_offset)) if sub_record_data_offset < sub_record_data_size: print(u'') while sub_record_data_offset < sub_record_data_size: read_size = self._ReadRecord(change_log_entry_record_data, sub_record_data_offset) if read_size == 0: break sub_record_data_offset += read_size copy_of_record_size = construct.ULInt32(u'record_size').parse( change_log_entry_record_data[-4:]) if record_size != copy_of_record_size: raise IOError(u'Record size mismatch ({0:d} != {1:d})'.format( record_size, copy_of_record_size)) if self._debug: print(u'Copy of record size\t\t\t\t\t\t\t: {0:d}'.format( copy_of_record_size)) print(u'') return change_log_entry
def _ReadFileHeader(self): """Reads the file header. Raises: IOError: if the file header cannot be read. """ if self._debug: print(u'Seeking file header offset: 0x{0:08x}'.format(0)) self._file_object.seek(0, os.SEEK_SET) try: file_header_struct = self._FILE_HEADER.parse_stream( self._file_object) except construct.FieldError as exception: raise IOError( u'Unable to parse file header with error: {0:s}'.format( exception)) signature = file_header_struct.get(u'signature') if signature != self.SIGNATURE: raise IOError(u'Unsupported change.log file signature') record_size = file_header_struct.get(u'record_size') record_type = file_header_struct.get(u'record_type') if record_type != 0: raise IOError( u'Unsupported record type: {0:d}'.format(record_type)) format_version = file_header_struct.get(u'format_version') if format_version != 2: raise IOError( u'Unsupported change.log format version: {0:d}'.format( format_version)) self._file_object.seek(0, os.SEEK_SET) file_header_data = self._file_object.read(record_size) if self._debug: print(u'File header data:') print(hexdump.Hexdump(file_header_data)) if self._debug: print(u'Record size\t\t\t\t\t\t\t\t: {0:d}'.format(record_size)) print(u'Record type\t\t\t\t\t\t\t\t: {0:d} ({1:s})'.format( record_type, self._RECORD_TYPES.get(record_type, u'Unknown'))) print(u'Signature\t\t\t\t\t\t\t\t: 0x{0:08x}'.format(signature)) print(u'Format version\t\t\t\t\t\t\t\t: {0:d}'.format( format_version)) self._ReadVolumePath(file_header_data[16:-4]) copy_of_record_size = construct.ULInt32(u'record_size').parse( file_header_data[-4:]) if record_size != copy_of_record_size: raise IOError(u'Record size mismatch ({0:d} != {1:d})'.format( record_size, copy_of_record_size)) if self._debug: print(u'Copy of record size\t\t\t\t\t\t\t: {0:d}'.format( copy_of_record_size)) print(u'')
def _ReadFileHeader(self): """Reads the file header. Raises: IOError: if the file header cannot be read. """ if self._debug: print(u'Seeking file header offset: 0x{0:08x}'.format(0)) self._file_object.seek(0, os.SEEK_SET) file_header_data = self._file_object.read(self._FILE_HEADER.sizeof()) if self._debug: print(u'Index file header data:') print(hexdump.Hexdump(file_header_data)) try: file_header = self._FILE_HEADER.parse(file_header_data) except construct.FieldError as exception: raise IOError(u'Unable to parse file header with error: {0:s}'.format( exception)) signature = file_header.get(u'signature') if signature != self.SIGNATURE: raise IOError(u'Unsupported index file signature') self.version = u'{0:d}.{1:d}'.format( file_header.get(u'major_version'), file_header.get(u'minor_version')) if self.version not in [u'2.0', u'2.1']: raise IOError(u'Unsupported index file version: {0:s}'.format( self.version)) self.creation_time = file_header.get(u'creation_time') if self._debug: print(u'Signature\t\t\t\t\t\t\t\t: 0x{0:08x}'.format(signature)) print(u'Version\t\t\t\t\t\t\t\t\t: {0:s}'.format(self.version)) print(u'Number of entries\t\t\t\t\t\t\t: {0:d}'.format( file_header.get(u'number_of_entries'))) print(u'Stored data size\t\t\t\t\t\t\t: {0:d}'.format( file_header.get(u'stored_data_size'))) print(u'Last created file number\t\t\t\t\t\t: f_{0:06x}'.format( file_header.get(u'last_created_file_number'))) print(u'Unknown1\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( file_header.get(u'unknown1'))) print(u'Unknown2\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( file_header.get(u'unknown2'))) print(u'Table size\t\t\t\t\t\t\t\t: {0:d}'.format( file_header.get(u'table_size'))) print(u'Unknown3\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( file_header.get(u'unknown3'))) print(u'Unknown4\t\t\t\t\t\t\t\t: 0x{0:08x}'.format( file_header.get(u'unknown4'))) date_string = ( datetime.datetime(1601, 1, 1) + datetime.timedelta(microseconds=self.creation_time)) print(u'Creation time\t\t\t\t\t\t\t\t: {0!s} (0x{1:08x})'.format( date_string, self.creation_time)) print(u'')
def _ReadRecord(self, record_data, record_data_offset): """Reads a record. Args: record_data: the record data. record_data_offset: the record data offset. Returns: The record size. Raises: IOError: if the record cannot be read. """ try: record_header_struct = self._RECORD_HEADER.parse( record_data[record_data_offset:]) except construct.FieldError as exception: raise IOError( u'Unable to parse record header with error: {0:s}'.format( exception)) record_size = record_header_struct.get(u'record_size') record_type = record_header_struct.get(u'record_type') if self._debug: print(u'Record data:') print( hexdump.Hexdump( record_data[record_data_offset:record_data_offset + record_size])) if self._debug: print(u'Record size\t\t\t\t\t\t\t\t: {0:d}'.format(record_size)) print(u'Record type\t\t\t\t\t\t\t\t: {0:d} ({1:s})'.format( record_type, self._RECORD_TYPES.get(record_type, u'Unknown'))) record_data_offset += self._RECORD_HEADER.sizeof() if record_type in [4, 5, 9]: try: utf16_stream = self._UTF16_STREAM.parse( record_data[record_data_offset:]) except construct.FieldError as exception: raise IOError( u'Unable to parse UTF-16 stream with error: {0:s}'.format( exception)) try: # The UTF-16 stream includes the end-of-string character that we need # to strip off. value_string = b''.join(utf16_stream).decode(u'utf16')[:-1] except UnicodeDecodeError as exception: value_string = u'' # TODO: add support for other record types. # TODO: store record values in runtime objects. if self._debug: if record_type == 4: print(u'Secondary path\t\t\t\t\t\t\t\t: {0:s}'.format( value_string)) elif record_type == 5: print(u'Backup filename\t\t\t\t\t\t\t\t: {0:s}'.format( value_string)) elif record_type == 9: print(u'Short filename\t\t\t\t\t\t\t\t: {0:s}'.format( value_string)) print(u'') return record_size
def _ReadFileHeader(self): """Reads the file header. Raises: IOError: if the file header cannot be read. """ if self._debug: print(u'Seeking file header offset: 0x{0:08x}'.format(0)) self._file_object.seek(0, os.SEEK_SET) file_header_data = self._file_object.read(self._FILE_HEADER.sizeof()) if self._debug: print(u'Data block file header data:') print(hexdump.Hexdump(file_header_data)) try: file_header = self._FILE_HEADER.parse(file_header_data) except construct.FieldError as exception: raise IOError(u'Unable to parse file header with error: {0:s}'.format( exception)) signature = file_header.get(u'signature') if signature != self.SIGNATURE: raise IOError(u'Unsupported data block file signature') self.version = u'{0:d}.{1:d}'.format( file_header.get(u'major_version'), file_header.get(u'minor_version')) if self.version not in [u'2.0', u'2.1']: raise IOError(u'Unsupported data block file version: {0:s}'.format( self.version)) self.version = u'{0:d}.{1:d}'.format( file_header.get(u'major_version'), file_header.get(u'minor_version')) self.block_size = file_header.get(u'block_size') self.number_of_entries = file_header.get(u'number_of_entries') if self._debug: print(u'Signature\t\t\t\t\t\t\t\t: 0x{0:08x}'.format(signature)) print(u'Version\t\t\t\t\t\t\t\t\t: {0:s}'.format(self.version)) print(u'File number\t\t\t\t\t\t\t\t: {0:d}'.format( file_header.get(u'file_number'))) print(u'Next file number\t\t\t\t\t\t\t: {0:d}'.format( file_header.get(u'next_file_number'))) print(u'Block size\t\t\t\t\t\t\t\t: {0:d}'.format(self.block_size)) print(u'Number of entries\t\t\t\t\t\t\t: {0:d}'.format( self.number_of_entries)) print(u'Maximum number of entries\t\t\t\t\t\t: {0:d}'.format( file_header.get(u'maximum_number_of_entries'))) # TODO: print emtpy, hints, updating and user. block_number = 0 block_range_start = 0 block_range_end = 0 in_block_range = False for value_32bit in file_header.get(u'allocation_bitmap'): for unused_bit in range(0, 32): if value_32bit & 0x00000001: if not in_block_range: block_range_start = block_number block_range_end = block_number in_block_range = True block_range_end += 1 elif in_block_range: in_block_range = False if self._debug: print(u'Block range\t: {0:d} - {1:d} ({2:d})'.format( block_range_start, block_range_end, block_range_end - block_range_start)) value_32bit >>= 1 block_number += 1 print(u'')
def _ReadFileEntry(self, file_offset): """Reads a file entry. Args: file_offset (int): current file offset. Raises: IOError: if the file entry cannot be read. """ if self._debug: print(u'Seeking file entry at offset: 0x{0:08x}'.format(file_offset)) self._file_object.seek(file_offset, os.SEEK_SET) if self.file_format == u'bin-big-endian': file_entry_struct = self._CPIO_BINARY_BIG_ENDIAN_FILE_ENTRY_STRUCT elif self.file_format == u'bin-little-endian': file_entry_struct = self._CPIO_BINARY_LITTLE_ENDIAN_FILE_ENTRY_STRUCT elif self.file_format == u'odc': file_entry_struct = self._CPIO_PORTABLE_ASCII_FILE_ENTRY_STRUCT elif self.file_format in (u'crc', u'newc'): file_entry_struct = self._CPIO_NEW_ASCII_FILE_ENTRY_STRUCT file_entry_struct_size = file_entry_struct.sizeof() file_entry_data = self._file_object.read(file_entry_struct_size) file_offset += file_entry_struct_size if self._debug: print(u'File entry data:') print(hexdump.Hexdump(file_entry_data)) try: file_entry_struct = file_entry_struct.parse(file_entry_data) except construct.FieldError as exception: raise IOError(( u'Unable to parse file entry data section with error: ' u'{0:s}').file_format(exception)) if self.file_format in (u'bin-big-endian', u'bin-little-endian'): inode_number = file_entry_struct.inode_number mode = file_entry_struct.mode user_identifier = file_entry_struct.user_identifier group_identifier = file_entry_struct.group_identifier modification_time = ( (file_entry_struct.modification_time_upper << 16) | file_entry_struct.modification_time_lower) path_string_size = file_entry_struct.path_string_size file_size = ( (file_entry_struct.file_size_upper << 16) | file_entry_struct.file_size_lower) elif self.file_format == u'odc': inode_number = int(file_entry_struct.inode_number, 8) mode = int(file_entry_struct.mode, 8) user_identifier = int(file_entry_struct.user_identifier, 8) group_identifier = int(file_entry_struct.group_identifier, 8) modification_time = int(file_entry_struct.modification_time, 8) path_string_size = int(file_entry_struct.path_string_size, 8) file_size = int(file_entry_struct.file_size, 8) elif self.file_format in (u'crc', u'newc'): inode_number = int(file_entry_struct.inode_number, 16) mode = int(file_entry_struct.mode, 16) user_identifier = int(file_entry_struct.user_identifier, 16) group_identifier = int(file_entry_struct.group_identifier, 16) modification_time = int(file_entry_struct.modification_time, 16) path_string_size = int(file_entry_struct.path_string_size, 16) file_size = int(file_entry_struct.file_size, 16) if self._debug: if self.file_format in (u'bin-big-endian', u'bin-little-endian'): print(u'Signature\t\t\t\t\t\t\t\t: 0x{0:04x}'.format( file_entry_struct.signature)) else: print(u'Signature\t\t\t\t\t\t\t\t: {0!s}'.format( file_entry_struct.signature)) if self.file_format not in (u'crc', u'newc'): if self.file_format in (u'bin-big-endian', u'bin-little-endian'): device_number = file_entry_struct.device_number elif self.file_format == u'odc': device_number = int(file_entry_struct.device_number, 8) print(u'Device number\t\t\t\t\t\t\t\t: {0:d}'.format(device_number)) print(u'Inode number\t\t\t\t\t\t\t\t: {0:d}'.format(inode_number)) print(u'Mode\t\t\t\t\t\t\t\t\t: {0:o}'.format(mode)) print(u'User identifier (UID)\t\t\t\t\t\t\t: {0:d}'.format( user_identifier)) print(u'Group identifier (GID)\t\t\t\t\t\t\t: {0:d}'.format( group_identifier)) if self.file_format in (u'bin-big-endian', u'bin-little-endian'): number_of_links = file_entry_struct.number_of_links elif self.file_format == u'odc': number_of_links = int(file_entry_struct.number_of_links, 8) elif self.file_format in (u'crc', u'newc'): number_of_links = int(file_entry_struct.number_of_links, 16) print(u'Number of links\t\t\t\t\t\t\t\t: {0:d}'.format(number_of_links)) if self.file_format not in (u'crc', u'newc'): if self.file_format in (u'bin-big-endian', u'bin-little-endian'): special_device_number = file_entry_struct.special_device_number elif self.file_format == u'odc': special_device_number = int( file_entry_struct.special_device_number, 8) print(u'Special device number\t\t\t\t\t\t\t\t: {0:d}'.format( special_device_number)) print(u'Modification time\t\t\t\t\t\t\t: {0:d}'.format(modification_time)) if self.file_format not in (u'crc', u'newc'): print(u'Path string size\t\t\t\t\t\t\t: {0:d}'.format(path_string_size)) print(u'File size\t\t\t\t\t\t\t\t: {0:d}'.format(file_size)) if self.file_format in (u'crc', u'newc'): device_major_number = int(file_entry_struct.device_major_number, 16) print(u'Device major number\t\t\t\t\t\t\t: {0:d}'.format( device_major_number)) device_minor_number = int(file_entry_struct.device_minor_number, 16) print(u'Device minor number\t\t\t\t\t\t\t: {0:d}'.format( device_minor_number)) special_device_major_number = int( file_entry_struct.special_device_major_number, 16) print(u'Special device major number\t\t\t\t\t\t: {0:d}'.format( special_device_major_number)) special_device_minor_number = int( file_entry_struct.special_device_minor_number, 16) print(u'Special device minor number\t\t\t\t\t\t: {0:d}'.format( special_device_minor_number)) print(u'Path string size\t\t\t\t\t\t\t: {0:d}'.format(path_string_size)) checksum = int(file_entry_struct.checksum, 16) print(u'Checksum\t\t\t\t\t\t\t\t: 0x{0:08x}'.format(checksum)) path_string_data = self._file_object.read(path_string_size) file_offset += path_string_size # TODO: should this be ASCII? path_string = path_string_data.decode(u'ascii') path_string, _, _ = path_string.partition(u'\x00') if self._debug: print(u'Path string\t\t\t\t\t\t\t\t: {0:s}'.format(path_string)) if self.file_format in (u'bin-big-endian', u'bin-little-endian'): padding_size = file_offset % 2 if padding_size > 0: padding_size = 2 - padding_size elif self.file_format == u'odc': padding_size = 0 elif self.file_format in (u'crc', u'newc'): padding_size = file_offset % 4 if padding_size > 0: padding_size = 4 - padding_size if self._debug: padding_data = self._file_object.read(padding_size) print(u'Path string alignment padding:') print(hexdump.Hexdump(padding_data)) file_offset += padding_size file_entry = CPIOArchiveFileEntry(self._file_object) file_entry.data_offset = file_offset file_entry.data_size = file_size file_entry.group_identifier = group_identifier file_entry.inode_number = inode_number file_entry.modification_time = modification_time file_entry.path = path_string file_entry.mode = mode file_entry.size = ( file_entry_struct_size + path_string_size + padding_size + file_size) file_entry.user_identifier = user_identifier if self.file_format in (u'crc', u'newc'): file_offset += file_size padding_size = file_offset % 4 if padding_size > 0: padding_size = 4 - padding_size if self._debug: self._file_object.seek(file_offset, os.SEEK_SET) padding_data = self._file_object.read(padding_size) print(u'File data alignment padding:') print(hexdump.Hexdump(padding_data)) file_entry.size += padding_size if self._debug: print(u'') return file_entry