def _mount_pytsk3_volumes(self): """Generator that mounts every partition of this image and yields the mountpoint.""" # Loop over all volumes in image. for p in self._find_pytsk3_volumes(): import pytsk3 volume = Volume(disk=self, **self.args) self.volumes.append(volume) # Fill volume with more information volume.offset = p.start * BLOCK_SIZE volume.fsdescription = p.desc if self.index is not None: volume.index = '{0}.{1}'.format(self.index, p.addr) else: volume.index = p.addr volume.size = p.len * BLOCK_SIZE if p.flags == pytsk3.TSK_VS_PART_FLAG_ALLOC: volume.flag = 'alloc' elif p.flags == pytsk3.TSK_VS_PART_FLAG_UNALLOC: volume.flag = 'unalloc' self._debug(" Unallocated space: block offset: {0}, length: {1} ".format(p.start, p.len)) elif p.flags == pytsk3.TSK_VS_PART_FLAG_META: volume.flag = 'meta' # unalloc / meta partitions do not have stats and can not be mounted if volume.flag != 'alloc': yield volume continue for v in volume.init(): yield v
def _mount_mmls_volumes(self): """Finds and mounts all volumes based on mmls.""" try: cmd = ['mmls'] if self.vstype != 'detect': cmd.extend(['-t', self.vstype]) cmd.append(self.get_raw_path()) output = util.check_output_(cmd, self.parser) self.volume_source = 'multi' except Exception as e: self._debug("[-] Failed executing mmls command") self._debug(e) return output = output.split("Description", 1)[-1] for line in output.splitlines(): if not line: continue try: index, slot, start, end, length, description = line.split(None, 5) volume = Volume(disk=self, **self.args) self.volumes.append(volume) volume.offset = int(start) * BLOCK_SIZE volume.fsdescription = description if self.index is not None: volume.index = '{0}.{1}'.format(self.index, int(index[:-1])) else: volume.index = int(index[:-1]) volume.size = int(length) * BLOCK_SIZE except Exception as e: self._debug("[-] Error while parsing mmls output") self._debug(e) continue if slot.lower() == 'meta': volume.flag = 'meta' elif slot.lower() == '-----': volume.flag = 'unalloc' else: volume.flag = 'alloc' # unalloc / meta partitions do not have stats and can not be mounted if volume.flag != 'alloc': yield volume continue for v in volume.init(): yield v
def mount_single_volume(self): """Mounts a volume assuming that the mounted image does not contain a full disk image, but only a single volume. A new :class:`Volume` object is created based on the disk file and :func:`init` is called on this object. This function will typically yield one volume, although if the volume contains other volumes, multiple volumes may be returned. """ volume = Volume(disk=self, **self.args) volume.offset = 0 if self.index is None: volume.index = 0 else: volume.index = '{0}.0'.format(self.index) description = util.check_output_(['file', '-sL', self.get_fs_path()]).strip() if description: # description is the part after the :, until the first comma volume.fsdescription = description.split(': ', 1)[1].split(',', 1)[0].strip() if 'size' in description: volume.size = re.findall(r'size: (\d+)', description)[0] else: volume.size = os.path.getsize(self.get_fs_path()) volume.flag = 'alloc' self.volumes = [volume] self.volume_source = 'single' for v in volume.init(no_stats=True): # stats can't be retrieved from single volumes yield v
def mount_directory(self): """Method that 'mounts' a directory. It actually just symlinks it. It is useful for AVFS mounts, that are not otherwise detected. This is a last resort method. """ if not self.mount_directories: return volume = Volume(disk=self, **self.args) volume.offset = 0 if self.index is None: volume.index = 0 else: volume.index = '{0}.0'.format(self.index) filesize = _util.check_output_(['du', '-scDb', self.get_fs_path()]).strip() if filesize: volume.size = int(filesize.splitlines()[-1].split()[0]) volume.flag = 'alloc' volume.fsdescription = 'Directory' self.volumes = [volume] self.volume_source = 'directory' for v in volume.init(no_stats=True): # stats can't be retrieved from directory yield v
def _mount_pytsk3_volumes(self): """Generator that mounts every partition of this image and yields the mountpoint.""" # Loop over all volumes in image. for p in self._find_pytsk3_volumes(): import pytsk3 volume = Volume(disk=self, **self.args) self.volumes.append(volume) # Fill volume with more information volume.offset = p.start * self.block_size volume.fsdescription = p.desc.strip() if self.index is not None: volume.index = '{0}.{1}'.format(self.index, p.addr) else: volume.index = p.addr volume.size = p.len * self.block_size if p.flags == pytsk3.TSK_VS_PART_FLAG_ALLOC: volume.flag = 'alloc' volume.slot = _util.determine_slot(p.table_num, p.slot_num) self._assign_disktype_data(volume) logger.info("Found allocated {2}: block offset: {0}, length: {1} ".format(p.start, p.len, volume.fsdescription)) elif p.flags == pytsk3.TSK_VS_PART_FLAG_UNALLOC: volume.flag = 'unalloc' logger.info("Found unallocated space: block offset: {0}, length: {1} ".format(p.start, p.len)) elif p.flags == pytsk3.TSK_VS_PART_FLAG_META: volume.flag = 'meta' logger.info("Found meta volume: block offset: {0}, length: {1} ".format(p.start, p.len)) # unalloc / meta partitions do not have stats and can not be mounted if volume.flag != 'alloc': yield volume continue for v in volume.init(): yield v
def _mount_parted_volumes(self): """Finds and mounts all volumes based on parted.""" # for some reason, parted does not properly return extended volume types in its machine # output, so we need to execute it twice. meta_volumes = [] try: output = _util.check_output_(['parted', self.get_raw_path(), 'print']) for line in output.splitlines(): if 'extended' in line: meta_volumes.append(int(line.split()[0])) except Exception: logger.exception("Failed executing parted command.") # skip detection of meta volumes try: # parted does not support passing in the vstype. It either works, or it doesn't. cmd = ['parted', self.get_raw_path(), '-sm', 'unit s', 'print free'] output = _util.check_output_(cmd) self.volume_source = 'multi' except Exception as e: logger.exception("Failed executing parted command") return num = 0 for line in output.splitlines(): if line.startswith("Warning") or not line or ':' not in line or line.startswith(self.get_raw_path()): continue line = line[:-1] # remove last ; try: slot, start, end, length, description = line.split(':', 4) if ':' in description: description, label, flags = description.split(':', 2) else: description, label, flags = description, '', '' volume = Volume(disk=self, **self.args) self.volumes.append(volume) volume.offset = int(start[:-1]) * self.block_size # remove last s volume.size = int(length[:-1]) * self.block_size volume.fsdescription = description if self.index is not None: volume.index = '{0}.{1}'.format(self.index, num) else: volume.index = num # TODO: detection of meta volumes if description == 'free': volume.flag = 'unalloc' logger.info("Found unallocated space: block offset: {0}, length: {1}".format(start[:-1], length[:-1])) elif int(slot) in meta_volumes: volume.flag = 'meta' volume.slot = int(slot) logger.info("Found meta volume: block offset: {0}, length: {1}".format(start[:-1], length[:-1])) else: volume.flag = 'alloc' volume.slot = int(slot) self._assign_disktype_data(volume) logger.info("Found allocated {2}: block offset: {0}, length: {1} ".format(start[:-1], length[:-1], volume.fsdescription)) except AttributeError as e: logger.exception("Error while parsing parted output") continue num += 1 # unalloc / meta partitions do not have stats and can not be mounted if volume.flag != 'alloc': yield volume continue for v in volume.init(): yield v
def _mount_mmls_volumes(self): """Finds and mounts all volumes based on mmls.""" try: cmd = ['mmls'] if self.vstype != 'detect': cmd.extend(['-t', self.vstype]) cmd.append(self.get_raw_path()) output = _util.check_output_(cmd, stderr=subprocess.STDOUT) self.volume_source = 'multi' except Exception as e: # some bug in sleuthkit makes detection sometimes difficult, so we hack around it: if hasattr(e, 'output') and "(GPT or DOS at 0)" in e.output.decode() and self.vstype != 'gpt': self.vstype = 'gpt' try: logger.warning("Error in retrieving volume info: mmls couldn't decide between GPT and DOS, " "choosing GPT for you. Use --vstype=dos to force DOS.", exc_info=True) cmd = ['mmls', '-t', self.vstype, self.get_raw_path()] output = _util.check_output_(cmd, stderr=subprocess.STDOUT) self.volume_source = 'multi' except Exception as e: logger.exception("Failed executing mmls command") return else: logger.exception("Failed executing mmls command") return output = output.split("Description", 1)[-1] for line in output.splitlines(): if not line: continue try: values = line.split(None, 5) # sometimes there are only 5 elements available description = '' index, slot, start, end, length = values[0:5] if len(values) > 5: description = values[5] volume = Volume(disk=self, **self.args) self.volumes.append(volume) volume.offset = int(start) * self.block_size volume.fsdescription = description if self.index is not None: volume.index = '{0}.{1}'.format(self.index, int(index[:-1])) else: volume.index = int(index[:-1]) volume.size = int(length) * self.block_size except Exception as e: logger.exception("Error while parsing mmls output") continue if slot.lower() == 'meta': volume.flag = 'meta' logger.info("Found meta volume: block offset: {0}, length: {1}".format(start, length)) elif slot.lower() == '-----': volume.flag = 'unalloc' logger.info("Found unallocated space: block offset: {0}, length: {1}".format(start, length)) else: volume.flag = 'alloc' if ":" in slot: volume.slot = _util.determine_slot(*slot.split(':')) else: volume.slot = _util.determine_slot(-1, slot) self._assign_disktype_data(volume) logger.info("Found allocated {2}: block offset: {0}, length: {1} ".format(start, length, volume.fsdescription)) # unalloc / meta partitions do not have stats and can not be mounted if volume.flag != 'alloc': yield volume continue for v in volume.init(): yield v