def parseApplePartitionMap(bytesData): # Based on description at: # https://en.wikipedia.org/wiki/Apple_Partition_Map#Layout # and code at: # https://opensource.apple.com/source/IOStorageFamily/IOStorageFamily-116/IOApplePartitionScheme.h # Variable naming mostly follows Apple's code. # Set up elemement object to store extracted properties properties = ET.Element("applePartitionMap") addProperty(properties, "signature", bc.bytesToText(bytesData[0:2])) addProperty(properties, "numberOfPartitionEntries", bc.bytesToUInt(bytesData[4:8])) addProperty(properties, "partitionBlockStart", bc.bytesToUInt(bytesData[8:12])) addProperty(properties, "partitionBlockCount", bc.bytesToUInt(bytesData[12:16])) addProperty(properties, "partitionName", bc.bytesToText(bytesData[16:48])) addProperty(properties, "partitionType", bc.bytesToText(bytesData[48:80])) addProperty(properties, "partitionLogicalBlockStart", bc.bytesToUInt(bytesData[80:84])) addProperty(properties, "partitionLogicalBlockCount", bc.bytesToUInt(bytesData[84:88])) addProperty(properties, "partitionFlags", bc.bytesToUInt(bytesData[88:92])) addProperty(properties, "bootCodeBlockStart", bc.bytesToUInt(bytesData[92:96])) addProperty(properties, "bootCodeSizeInBytes", bc.bytesToUInt(bytesData[96:100])) addProperty(properties, "bootCodeLoadAddress", bc.bytesToUInt(bytesData[100:104])) addProperty(properties, "bootCodeJumpAddress", bc.bytesToUInt(bytesData[108:112])) addProperty(properties, "bootCodeChecksum", bc.bytesToUInt(bytesData[116:120])) addProperty(properties, "processorType", bc.bytesToText(bytesData[120:136])) return(properties)
def parsePrimaryVolumeDescriptor(bytesData): # Set up elemement object to store extracted properties properties = ET.Element("primaryVolumeDescriptor") addProperty(properties, "typeCode", bc.bytesToUnsignedChar(bytesData[0:1])) addProperty(properties, "standardIdentifier", bc.bytesToText(bytesData[1:6])) addProperty(properties, "version", bc.bytesToUnsignedChar(bytesData[6:7])) addProperty(properties, "systemIdentifier", bc.bytesToText(bytesData[8:40])) addProperty(properties, "volumeIdentifier", bc.bytesToText(bytesData[40:72])) # Fields below are stored as both little-endian and big-endian; only # big-endian values read here! # Number of Logical Blocks in which the volume is recorded addProperty(properties, "volumeSpaceSize", bc.bytesToUInt(bytesData[84:88])) # The size of the set in this logical volume (number of disks) addProperty(properties, "volumeSetSize", bc.bytesToUShortInt(bytesData[122:124])) # The number of this disk in the Volume Set addProperty(properties, "volumeSequenceNumber", bc.bytesToUShortInt(bytesData[126:128])) # The size in bytes of a logical block addProperty(properties, "logicalBlockSize", bc.bytesToUShortInt(bytesData[130:132])) # The size in bytes of the path table addProperty(properties, "pathTableSize", bc.bytesToUInt(bytesData[136:140])) # Location of Type-L Path Table (note this is stored as little-endian only, hence # byte swap!) addProperty(properties, "typeLPathTableLocation", bc.swap32(bc.bytesToUInt(bytesData[140:144]))) # Location of Optional Type-L Path Table addProperty(properties, "optionalTypeLPathTableLocation", bc.swap32(bc.bytesToUInt(bytesData[144:148]))) # Location of Type-M Path Table addProperty(properties, "typeMPathTableLocation", bc.bytesToUInt(bytesData[148:152])) # Location of Optional Type-M Path Table addProperty(properties, "optionalTypeMPathTableLocation", bc.bytesToUInt(bytesData[152:156])) # Following fields are all text strings addProperty(properties, "volumeSetIdentifier", bc.bytesToText(bytesData[190:318])) addProperty(properties, "publisherIdentifier", bc.bytesToText(bytesData[318:446])) addProperty(properties, "dataPreparerIdentifier", bc.bytesToText(bytesData[446:574])) addProperty(properties, "applicationIdentifier", bc.bytesToText(bytesData[574:702])) addProperty(properties, "copyrightFileIdentifier", bc.bytesToText(bytesData[702:740])) addProperty(properties, "abstractFileIdentifier", bc.bytesToText(bytesData[740:776])) addProperty(properties, "bibliographicFileIdentifier", bc.bytesToText(bytesData[776:813])) # Following fields are all date-time values addProperty(properties, "volumeCreationDateAndTime", decDateTimeToDate(bytesData[813:830])) addProperty(properties, "volumeModificationDateAndTime", decDateTimeToDate(bytesData[830:847])) addProperty(properties, "volumeExpirationDateAndTime", decDateTimeToDate(bytesData[847:864])) addProperty(properties, "volumeEffectiveDateAndTime", decDateTimeToDate(bytesData[864:881])) addProperty(properties, "fileStructureVersion", bc.bytesToUnsignedChar(bytesData[881:882])) return(properties)
def makeHumanReadable(self, remapTable={}): # Takes element object, and returns a modified version in which all # non-printable 'text' fields (which may contain numeric data or binary strings) # are replaced by printable strings # # Property values in original tree may be mapped to alternative (more user-friendly) # reportable values using a remapTable, which is a nested dictionary. for elt in self.iter(): # Text field of this element textIn = elt.text # Tag name tag = elt.tag # Step 1: replace property values by values defined in enumerationsMap, # if applicable try: # If tag is in enumerationsMap, replace property values parameterMap = remapTable[tag] try: # Map original property values to values in dictionary remappedValue = parameterMap[textIn] except KeyError: # If value doesn't match any key: use original value # instead remappedValue = textIn except KeyError: # If tag doesn't match any key in enumerationsMap, use original # value remappedValue = textIn # Step 2: convert all values to text strings. # First set up list of all numeric data types, # which is dependent on the Python version used if config.PYTHON_VERSION.startswith(config.PYTHON_2): # Python 2.x numericTypes = [int, long, float, bool] # Long type is deprecated in Python 3.x! else: numericTypes = [int, float, bool] # Convert if remappedValue != None: # Data type textType = type(remappedValue) # Convert text field, depending on type if textType == bytes: textOut = bytesToText(remappedValue) elif textType in numericTypes: textOut = str(remappedValue) else: textOut = removeControlCharacters(remappedValue) # Update output tree elt.text = textOut
def parseMasterDirectoryBlock(bytesData): # Based on description at: # https://developer.apple.com/legacy/library/documentation/mac/Files/Files-102.html # Set up elemement object to store extracted properties properties = ET.Element("masterDirectoryBlock") addProperty(properties, "signature", bc.bytesToText(bytesData[0:2])) addProperty(properties, "blockSize", bc.bytesToUShortInt(bytesData[18:20])) addProperty(properties, "blockCount", bc.bytesToUInt(bytesData[20:24])) return (properties)
def parseApplePartitionMap(bytesData): # Based on description at: # https://en.wikipedia.org/wiki/Apple_Partition_Map#Layout # and code at: # https://opensource.apple.com/source/IOStorageFamily/IOStorageFamily-116/IOApplePartitionScheme.h # Variable naming mostly follows Apple's code. # Set up elemement object to store extracted properties properties = ET.Element("applePartitionMap") addProperty(properties, "signature", bc.bytesToText(bytesData[0:2])) addProperty(properties, "numberOfPartitionEntries", bc.bytesToUInt(bytesData[4:8])) addProperty(properties, "partitionBlockStart", bc.bytesToUInt(bytesData[8:12])) addProperty(properties, "partitionBlockCount", bc.bytesToUInt(bytesData[12:16])) addProperty(properties, "partitionName", bc.bytesToText(bytesData[16:48])) addProperty(properties, "partitionType", bc.bytesToText(bytesData[48:80])) addProperty(properties, "partitionLogicalBlockStart", bc.bytesToUInt(bytesData[80:84])) addProperty(properties, "partitionLogicalBlockCount", bc.bytesToUInt(bytesData[84:88])) addProperty(properties, "partitionFlags", bc.bytesToUInt(bytesData[88:92])) addProperty(properties, "bootCodeBlockStart", bc.bytesToUInt(bytesData[92:96])) addProperty(properties, "bootCodeSizeInBytes", bc.bytesToUInt(bytesData[96:100])) addProperty(properties, "bootCodeLoadAddress", bc.bytesToUInt(bytesData[100:104])) addProperty(properties, "bootCodeJumpAddress", bc.bytesToUInt(bytesData[108:112])) addProperty(properties, "bootCodeChecksum", bc.bytesToUInt(bytesData[116:120])) addProperty(properties, "processorType", bc.bytesToText(bytesData[120:136])) return (properties)
def makeHumanReadable(self, remapTable = {}): # Takes element object, and returns a modified version in which all # non-printable 'text' fields (which may contain numeric data or binary strings) # are replaced by printable strings # # Property values in original tree may be mapped to alternative (more user-friendly) # reportable values using a remapTable, which is a nested dictionary. for elt in self.iter(): # Text field of this element textIn = elt.text # Tag name tag = elt.tag # Step 1: replace property values by values defined in enumerationsMap, # if applicable try: # If tag is in enumerationsMap, replace property values parameterMap = remapTable[tag] try: # Map original property values to values in dictionary remappedValue = parameterMap[textIn] except KeyError: # If value doesn't match any key: use original value instead remappedValue = textIn except KeyError: # If tag doesn't match any key in enumerationsMap, use original value remappedValue = textIn # Step 2: convert all values to text strings if remappedValue != None: # Data type textType = type(remappedValue) # Convert text field, depending on type if textType == bytes: textOut = bytesToText(remappedValue) elif textType in[int,float,bool]: textOut=str(remappedValue) else: textOut=remappedValue # Update output tree elt.text = textOut
def parseAppleZeroBlock(bytesData): # Based on code at: # https://opensource.apple.com/source/IOStorageFamily/IOStorageFamily-116/IOApplePartitionScheme.h # Set up elemement object to store extracted properties properties = ET.Element("appleZeroBlock") addProperty(properties, "signature", bc.bytesToText(bytesData[0:2])) addProperty(properties, "blockSize", bc.bytesToUShortInt(bytesData[2:4])) addProperty(properties, "blockCount", bc.bytesToUInt(bytesData[4:8])) addProperty(properties, "deviceType", bc.bytesToUShortInt(bytesData[8:10])) addProperty(properties, "deviceID", bc.bytesToUShortInt(bytesData[10:12])) addProperty(properties, "driverData", bc.bytesToUInt(bytesData[12:16])) addProperty(properties, "driverDescriptorCount", bc.bytesToUShortInt(bytesData[80:82])) addProperty(properties, "driverDescriptorBlockStart", bc.bytesToUInt(bytesData[82:86])) addProperty(properties, "driverDescriptorBlockCount", bc.bytesToUShortInt(bytesData[86:88])) addProperty(properties, "driverDescriptorSystemType", bc.bytesToUShortInt(bytesData[88:90])) return(properties)
def decDateTimeToDate(datetime): # Convert 17 bit dec-datetime field to formatted date-time string # TODO: incorporate time zone offset into result try: year = int(bc.bytesToText(datetime[0:4])) month = int(bc.bytesToText(datetime[4:6])) day = int(bc.bytesToText(datetime[6:8])) hour = int(bc.bytesToText(datetime[8:10])) minute = int(bc.bytesToText(datetime[10:12])) second = int(bc.bytesToText(datetime[12:14])) hundrethSecond = int(bc.bytesToText(datetime[14:16])) timeZoneOffset = bc.bytesToUnsignedChar(datetime[16:17]) dateString = "%d/%02d/%02d" % (year, month, day) timeString = "%02d:%02d:%02d" % (hour, minute, second) dateTimeString = "%s, %s" % (dateString, timeString) except ValueError: dateTimeString = "" return (dateTimeString)
def decDateTimeToDate(datetime): # Convert 17 bit dec-datetime field to formatted date-time string # TODO: incorporate time zone offset into result try: year = int(bc.bytesToText(datetime[0:4])) month = int(bc.bytesToText(datetime[4:6])) day = int(bc.bytesToText(datetime[6:8])) hour = int(bc.bytesToText(datetime[8:10])) minute = int(bc.bytesToText(datetime[10:12])) second = int(bc.bytesToText(datetime[12:14])) hundrethSecond = int(bc.bytesToText(datetime[14:16])) timeZoneOffset = bc.bytesToUnsignedChar(datetime[16:17]) dateString = "%d/%02d/%02d" % (year, month, day) timeString = "%02d:%02d:%02d" % (hour, minute, second) dateTimeString = "%s, %s" % (dateString, timeString) except ValueError: dateTimeString="" return(dateTimeString)
def parseAppleZeroBlock(bytesData): # Based on code at: # https://opensource.apple.com/source/IOStorageFamily/IOStorageFamily-116/IOApplePartitionScheme.h # Set up elemement object to store extracted properties properties = ET.Element("appleZeroBlock") addProperty(properties, "signature", bc.bytesToText(bytesData[0:2])) addProperty(properties, "blockSize", bc.bytesToUShortInt(bytesData[2:4])) addProperty(properties, "blockCount", bc.bytesToUInt(bytesData[4:8])) addProperty(properties, "deviceType", bc.bytesToUShortInt(bytesData[8:10])) addProperty(properties, "deviceID", bc.bytesToUShortInt(bytesData[10:12])) addProperty(properties, "driverData", bc.bytesToUInt(bytesData[12:16])) addProperty(properties, "driverDescriptorCount", bc.bytesToUShortInt(bytesData[80:82])) addProperty(properties, "driverDescriptorBlockStart", bc.bytesToUInt(bytesData[82:86])) addProperty(properties, "driverDescriptorBlockCount", bc.bytesToUShortInt(bytesData[86:88])) addProperty(properties, "driverDescriptorSystemType", bc.bytesToUShortInt(bytesData[88:90])) return (properties)
def parsePrimaryVolumeDescriptor(bytesData): # Set up elemement object to store extracted properties properties = ET.Element("primaryVolumeDescriptor") addProperty(properties, "typeCode", bc.bytesToUnsignedChar(bytesData[0:1])) addProperty(properties, "standardIdentifier", bc.bytesToText(bytesData[1:6])) addProperty(properties, "version", bc.bytesToUnsignedChar(bytesData[6:7])) addProperty(properties, "systemIdentifier", bc.bytesToText(bytesData[8:40])) addProperty(properties, "volumeIdentifier", bc.bytesToText(bytesData[40:72])) # Fields below are stored as both little-endian and big-endian; only # big-endian values read here! # Number of Logical Blocks in which the volume is recorded addProperty(properties, "volumeSpaceSize", bc.bytesToUInt(bytesData[84:88])) # The size of the set in this logical volume (number of disks) addProperty(properties, "volumeSetSize", bc.bytesToUShortInt(bytesData[122:124])) # The number of this disk in the Volume Set addProperty(properties, "volumeSequenceNumber", bc.bytesToUShortInt(bytesData[126:128])) # The size in bytes of a logical block addProperty(properties, "logicalBlockSize", bc.bytesToUShortInt(bytesData[130:132])) # The size in bytes of the path table addProperty(properties, "pathTableSize", bc.bytesToUInt(bytesData[136:140])) # Location of Type-L Path Table (note this is stored as little-endian only, hence # byte swap!) addProperty(properties, "typeLPathTableLocation", bc.swap32(bc.bytesToUInt(bytesData[140:144]))) # Location of Optional Type-L Path Table addProperty(properties, "optionalTypeLPathTableLocation", bc.swap32(bc.bytesToUInt(bytesData[144:148]))) # Location of Type-M Path Table addProperty(properties, "typeMPathTableLocation", bc.bytesToUInt(bytesData[148:152])) # Location of Optional Type-M Path Table addProperty(properties, "optionalTypeMPathTableLocation", bc.bytesToUInt(bytesData[152:156])) # Following fields are all text strings addProperty(properties, "volumeSetIdentifier", bc.bytesToText(bytesData[190:318])) addProperty(properties, "publisherIdentifier", bc.bytesToText(bytesData[318:446])) addProperty(properties, "dataPreparerIdentifier", bc.bytesToText(bytesData[446:574])) addProperty(properties, "applicationIdentifier", bc.bytesToText(bytesData[574:702])) addProperty(properties, "copyrightFileIdentifier", bc.bytesToText(bytesData[702:740])) addProperty(properties, "abstractFileIdentifier", bc.bytesToText(bytesData[740:776])) addProperty(properties, "bibliographicFileIdentifier", bc.bytesToText(bytesData[776:813])) # Following fields are all date-time values addProperty(properties, "volumeCreationDateAndTime", decDateTimeToDate(bytesData[813:830])) addProperty(properties, "volumeModificationDateAndTime", decDateTimeToDate(bytesData[830:847])) addProperty(properties, "volumeExpirationDateAndTime", decDateTimeToDate(bytesData[847:864])) addProperty(properties, "volumeEffectiveDateAndTime", decDateTimeToDate(bytesData[864:881])) addProperty(properties, "fileStructureVersion", bc.bytesToUnsignedChar(bytesData[881:882])) return (properties)