#NEWLINE# def main( ) : #NEWLINE# #INDENT# class MyParser ( argparse . ArgumentParser ) : #NEWLINE# #INDENT# def error( self , message ) : #NEWLINE# #INDENT# sys . stderr . write ( 'error: {0}\n' . format ( message ) ) #NEWLINE# self . print_help ( ) #NEWLINE# sys . exit ( 2 ) #NEWLINE# #UNINDENT# #UNINDENT# class AppendDictAction ( argparse . Action ) : #NEWLINE# #INDENT# def __call__( self , parser , namespace , values , option_string = None ) : #NEWLINE# #INDENT# items = getattr ( namespace , self . dest , { #NEWLINE# #INDENT# #NEWLINE# #UNINDENT# } ) #NEWLINE# try : #NEWLINE# #INDENT# vals = values . split ( ',' ) #NEWLINE# for t in vals : #NEWLINE# #INDENT# ( k , v ) = t . split ( '=' , 1 ) #NEWLINE# items [ k ] = v #NEWLINE# #UNINDENT# #UNINDENT# except ValueError : #NEWLINE# #INDENT# parser . error ( 'invalid argument {}' . format ( self . dest ) ) #NEWLINE# #UNINDENT# setattr ( namespace , self . dest , items ) #NEWLINE# #UNINDENT# #UNINDENT# class CheckAction ( argparse . Action ) : #NEWLINE# #INDENT# def _check_command( self , command , package = '' , why = '' ) : #NEWLINE# #INDENT# if _util . command_exists ( command ) : #NEWLINE# #INDENT# print ( ' INSTALLED {}' . format ( command ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( why and package ) : #NEWLINE# #INDENT# print ( ' MISSING   {:<20}needed for {}, part of the {} package' . format ( command , why , package ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if why : #NEWLINE# #INDENT# print ( ' MISSING   {:<20}needed for {}' . format ( command , why ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if package : #NEWLINE# #INDENT# print ( ' MISSING   {:<20}part of the {} package' . format ( command , package ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# print ( ' MISSING   {}' . format ( command ) ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# #UNINDENT# #UNINDENT# def _check_module( self , module , pip_name = '' , why = '' ) : #NEWLINE# #INDENT# if ( not pip_name ) : #NEWLINE# #INDENT# pip_name = module #NEWLINE# #UNINDENT# if ( ( module == 'magic' ) and _util . module_exists ( module ) ) : #NEWLINE# #INDENT# import magic #NEWLINE# if hasattr ( magic , 'from_file' ) : #NEWLINE# #INDENT# print ( ' INSTALLED {:<20}(Python package)' . format ( pip_name ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if hasattr ( magic , 'open' ) : #NEWLINE# #INDENT# print ( ' INSTALLED {:<20}(system package)' . format ( pip_name ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# print ( ' ERROR     {:<20}expecting {}, found other module named magic' . format ( pip_name , pip_name ) ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# else : #NEWLINE# #INDENT# if ( ( module != 'magic' ) and _util . module_exists ( module ) ) : #NEWLINE# #INDENT# print ( ' INSTALLED {}' . format ( pip_name ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if why : #NEWLINE# #INDENT# print ( ' MISSING   {:<20}needed for {}, install using pip' . format ( pip_name , why ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# print ( ' MISSING   {:<20}install using pip' . format ( pip_name , why ) ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# #UNINDENT# def __call__( self , parser , namespace , values , option_string = None ) : #NEWLINE# #INDENT# print ( 'The following commands are used by imagemounter internally. Without most commands, imagemounter works perfectly fine, but may lack some detection or mounting capabilities.' ) #NEWLINE# print ( '-- Mounting base disk images (at least one required, first three recommended) --' ) #NEWLINE# self . _check_command ( 'xmount' , 'xmount' , 'several types of disk images' ) #NEWLINE# self . _check_command ( 'ewfmount' , 'ewf-tools' , 'EWF images (partially covered by xmount)' ) #NEWLINE# self . _check_command ( 'affuse' , 'afflib-tools' , 'AFF images (partially covered by xmount)' ) #NEWLINE# self . _check_command ( 'vmware-mount' , why = 'VMWare disks' ) #NEWLINE# print ( '-- Detecting volumes and volume types (at least one required) --' ) #NEWLINE# self . _check_command ( 'mmls' , 'sleuthkit' ) #NEWLINE# self . _check_module ( 'pytsk3' ) #NEWLINE# self . _check_command ( 'parted' , 'parted' ) #NEWLINE# print ( '-- Detecting volume types (all recommended, first two highly recommended) --' ) #NEWLINE# self . _check_command ( 'fsstat' , 'sleuthkit' ) #NEWLINE# self . _check_command ( 'file' , 'libmagic1' ) #NEWLINE# self . _check_module ( 'magic' , 'python-magic' ) #NEWLINE# self . _check_command ( 'disktype' , 'disktype' ) #NEWLINE# print ( '-- Enhanced mounting and detecting disks (install when needed) --' ) #NEWLINE# self . _check_command ( 'mdadm' , 'mdadm' , 'RAID disks' ) #NEWLINE# self . _check_command ( 'cryptsetup' , 'cryptsetup' , 'LUKS containers' ) #NEWLINE# self . _check_command ( 'mountavfs' , 'avfs' , 'compressed disk images' ) #NEWLINE# print ( '-- Mounting volumes (install when needed) --' ) #NEWLINE# self . _check_command ( 'mount.xfs' , 'xfsprogs' , 'XFS volumes' ) #NEWLINE# self . _check_command ( 'mount.ntfs' , 'ntfs-3g' , 'NTFS volumes' ) #NEWLINE# self . _check_command ( 'lvm' , 'lvm2' , 'LVM volumes' ) #NEWLINE# self . _check_command ( 'vmfs-fuse' , 'vmfs-tools' , 'VMFS volumes' ) #NEWLINE# self . _check_command ( 'mount.jffs2' , 'mtd-tools' , 'JFFS2 volumes' ) #NEWLINE# self . _check_command ( 'mount.squashfs' , 'squashfs-tools' , 'SquashFS volumes' ) #NEWLINE# self . _check_command ( 'bdemount' , 'libbde-utils' , 'Bitlocker Drive Encryption volumes' ) #NEWLINE# parser . exit ( ) #NEWLINE# #UNINDENT# #UNINDENT# parser = MyParser ( description = 'Utility to mount volumes in Encase and dd images locally.' ) #NEWLINE# parser . add_argument ( 'images' , nargs = '*' , help = 'path(s) to the image(s) that you want to mount; generally just the first file (e.g. the .E01 or .001 file) or the folder containing the files is enough in the case of split files' ) #NEWLINE# parser . add_argument ( '--version' , action = 'version' , version = __version__ , help = 'display version and exit' ) #NEWLINE# parser . add_argument ( '--check' , action = CheckAction , nargs = 0 , help = 'do a system check and list which tools are installed' ) #NEWLINE# parser . add_argument ( '-u' , '--unmount' , action = 'store_true' , default = False , help = 'try to unmount left-overs of previous imount runs; may occasionally not be able to detect all mountpoints or detect too much mountpoints; use --casename to limit the unmount options' ) #NEWLINE# parser . add_argument ( '-w' , '--wait' , action = 'store_true' , default = False , help = 'pause on some additional warnings' ) #NEWLINE# parser . add_argument ( '-k' , '--keep' , action = 'store_true' , default = False , help = 'keep volumes mounted after program exits' ) #NEWLINE# parser . add_argument ( '--no-interaction' , action = 'store_true' , default = False , help = 'do not ask for any user input, implies --keep' ) #NEWLINE# parser . add_argument ( '-o' , '--only-mount' , default = None , help = 'specify which volume(s) you want to mount, comma-separated' ) #NEWLINE# parser . add_argument ( '-v' , '--verbose' , action = 'count' , default = False , help = 'enable verbose output' ) #NEWLINE# parser . add_argument ( '-c' , '--color' , action = 'store_true' , default = False , help = 'force colorizing the output' ) #NEWLINE# parser . add_argument ( '--no-color' , action = 'store_true' , default = False , help = 'prevent colorizing the output' ) #NEWLINE# parser . add_argument ( '-r' , '--reconstruct' , action = 'store_true' , default = False , help = 'attempt to reconstruct the full filesystem tree; implies -s and mounts all partitions at once' ) #NEWLINE# parser . add_argument ( '--carve' , action = 'store_true' , default = False , help = 'automatically carve the free space of a mounted volume for deleted files' ) #NEWLINE# parser . add_argument ( '-md' , '--mountdir' , default = None , help = 'specify other directory for volume mountpoints' ) #NEWLINE# parser . add_argument ( '-p' , '--pretty' , action = 'store_true' , default = False , help = 'use pretty names for mount points; useful in combination with --mountdir' ) #NEWLINE# parser . add_argument ( '-cn' , '--casename' , default = None , help = 'name to add to the --mountdir, often used in conjunction with --pretty' ) #NEWLINE# parser . add_argument ( '-rw' , '--read-write' , action = 'store_true' , default = False , help = 'mount image read-write by creating a local write-cache file in a temp directory; implies --method=xmount' ) #NEWLINE# parser . add_argument ( '-m' , '--method' , choices = [ 'xmount' , 'affuse' , 'ewfmount' , 'vmware-mount' , 'avfs' , 'auto' , 'dummy' ] , default = 'auto' , help = "use other tool to mount the initial images; results may vary between methods and if something doesn't work, try another method; dummy can be used when base should not be mounted (default: auto)" ) #NEWLINE# parser . add_argument ( '-d' , '--detection' , choices = [ 'pytsk3' , 'mmls' , 'parted' , 'auto' ] , default = 'auto' , help = 'use other volume detection method; pytsk3 and mmls should provide identical results, though pytsk3 is using the direct C API of mmls, but requires pytsk3 to be installed; auto distinguishes between pytsk3 and mmls only (default: auto)' ) #NEWLINE# parser . add_argument ( '--vstype' , choices = VOLUME_SYSTEM_TYPES , default = 'detect' , help = 'specify type of volume system (partition table); if you don\'t know, use "detect" to try to detect (default: detect)' ) #NEWLINE# parser . add_argument ( '--fstypes' , action = AppendDictAction , default = { #NEWLINE# #INDENT# '?' : 'unknown' , #NEWLINE# #UNINDENT# } , help = ( 'allows the specification of the file system type per volume number; format: 0.1=lvm,...; use volume number ? for all undetected file system types and * for all file systems; accepted file systems types are {}' . format ( ', ' . join ( FILE_SYSTEM_TYPES ) ) + ', and none only for the ? volume (defaults to unknown)' ) ) #NEWLINE# parser . add_argument ( '--keys' , action = AppendDictAction , default = { #NEWLINE# #INDENT# #NEWLINE# #UNINDENT# } , help = 'allows the specification of key material per volume number; format: 0.1=p:pass,...; exact format depends on volume type' ) #NEWLINE# toggroup = parser . add_argument_group ( 'toggles' ) #NEWLINE# toggroup . add_argument ( '--stats' , action = 'store_true' , default = False , help = 'show limited information from fsstat, which will slow down mounting and may cause random issues such as partitions being unreadable (default)' ) #NEWLINE# toggroup . add_argument ( '--no-stats' , action = 'store_true' , default = False , help = 'do not show limited information from fsstat' ) #NEWLINE# toggroup . add_argument ( '--disktype' , action = 'store_true' , default = False , help = 'use the disktype command to get even more information about the volumes (default)' ) #NEWLINE# toggroup . add_argument ( '--no-disktype' , action = 'store_true' , default = False , help = 'do not use disktype to get more information' ) #NEWLINE# toggroup . add_argument ( '--raid' , action = 'store_true' , default = False , help = 'try to detect whether the volume is part of a RAID array (default)' ) #NEWLINE# toggroup . add_argument ( '--no-raid' , action = 'store_true' , default = False , help = 'prevent trying to mount the volume in a RAID array' ) #NEWLINE# toggroup . add_argument ( '--single' , action = 'store_true' , default = False , help = 'do not try to find a volume system, but assume the image contains a single volume' ) #NEWLINE# toggroup . add_argument ( '--no-single' , action = 'store_true' , default = False , help = 'prevent trying to mount the image as a single volume if no volume system was found' ) #NEWLINE# args = parser . parse_args ( ) #NEWLINE# if ( ( not args . color ) and args . no_color ) : #NEWLINE# #INDENT# args . color = False #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if args . color : #NEWLINE# #INDENT# args . color = True #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# args . color = _util . terminal_supports_color ( ) #NEWLINE# #UNINDENT# #UNINDENT# if ( not args . color ) : #NEWLINE# #INDENT# def col( s , * args , **kwargs ) : #NEWLINE# #INDENT# return s #NEWLINE# #UNINDENT# #UNINDENT# else : #NEWLINE# #INDENT# from termcolor import colored #NEWLINE# col = colored #NEWLINE# #UNINDENT# class ImageMounterFormatter ( logging . Formatter ) : #NEWLINE# #INDENT# def format( self , record ) : #NEWLINE# #INDENT# msg = record . getMessage ( ) #NEWLINE# if ( ( args . verbose >= 4 ) and record . exc_info ) : #NEWLINE# #INDENT# if ( not record . exc_text ) : #NEWLINE# #INDENT# record . exc_text = self . formatException ( record . exc_info ) #NEWLINE# #UNINDENT# if ( msg [ ( - 1 ) : ] != '\n' ) : #NEWLINE# #INDENT# msg += '\n' #NEWLINE# #UNINDENT# msg += record . exc_text #NEWLINE# #UNINDENT# if ( record . levelno >= logging . WARNING ) : #NEWLINE# #INDENT# return col ( ( '[-] ' + msg ) , 'cyan' ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( record . levelno == logging . INFO ) : #NEWLINE# #INDENT# return col ( ( '[+] ' + msg ) , 'cyan' ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if msg . startswith ( '$' ) : #NEWLINE# #INDENT# return col ( ( '  ' + msg ) , 'cyan' ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# return col ( ( '    ' + msg ) , 'cyan' ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# #UNINDENT# #UNINDENT# handler = logging . StreamHandler ( ) #NEWLINE# handler . setFormatter ( ImageMounterFormatter ( ) ) #NEWLINE# logger = logging . getLogger ( 'imagemounter' ) #NEWLINE# logger . setLevel ( { #NEWLINE# #INDENT# 0 : logging . CRITICAL , #NEWLINE# 1 : logging . WARNING , #NEWLINE# 2 : logging . INFO , #NEWLINE# #UNINDENT# } . get ( args . verbose , logging . DEBUG ) ) #NEWLINE# logger . addHandler ( handler ) #NEWLINE# if os . geteuid ( ) : #NEWLINE# #INDENT# print ( col ( '[!] Not running as root!' , 'yellow' ) ) #NEWLINE# #UNINDENT# if ( ( 'a' in __version__ ) or ( 'b' in __version__ ) ) : #NEWLINE# #INDENT# print ( col ( 'Development release v{0}. Please report any bugs you encounter.' . format ( __version__ ) , attrs = [ 'dark' ] ) ) #NEWLINE# print ( col ( 'Bug reports: use -vvvv to get maximum verbosity and include  imount --check  output in your report' , attrs = [ 'dark' ] ) ) #NEWLINE# print ( col ( 'Critical bug? Use git tag to list all versions and use git checkout <version>' , attrs = [ 'dark' ] ) ) #NEWLINE# #UNINDENT# if ( ( not args . stats ) and args . no_stats ) : #NEWLINE# #INDENT# args . stats = False #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# args . stats = True #NEWLINE# #UNINDENT# explicit_disktype = False #NEWLINE# if ( ( not args . disktype ) and args . no_disktype ) : #NEWLINE# #INDENT# args . disktype = False #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if args . disktype : #NEWLINE# #INDENT# explicit_disktype = True #NEWLINE# #UNINDENT# args . disktype = True #NEWLINE# #UNINDENT# explicit_raid = False #NEWLINE# if ( ( not args . raid ) and args . no_raid ) : #NEWLINE# #INDENT# args . raid = False #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if args . raid : #NEWLINE# #INDENT# explicit_raid = True #NEWLINE# #UNINDENT# args . raid = True #NEWLINE# #UNINDENT# if ( args . single == args . no_single ) : #NEWLINE# #INDENT# args . single = None #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if args . single : #NEWLINE# #INDENT# args . single = True #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if args . no_single : #NEWLINE# #INDENT# args . single = False #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# if args . no_interaction : #NEWLINE# #INDENT# args . keep = True #NEWLINE# if args . wait : #NEWLINE# #INDENT# print ( col ( "[!] --no-interaction can't be used in conjunction with --wait" , 'yellow' ) ) #NEWLINE# args . wait = False #NEWLINE# #UNINDENT# #UNINDENT# if ( ( args . method not in ( 'xmount' , 'auto' ) ) and args . read_write ) : #NEWLINE# #INDENT# print ( col ( '[!] {0} does not support mounting read-write! Will mount read-only.' . format ( args . method ) , 'yellow' ) ) #NEWLINE# args . read_write = False #NEWLINE# #UNINDENT# mount_command = ( 'avfsd' if ( args . method == 'avfs' ) else args . method ) #NEWLINE# if ( ( args . method not in ( 'auto' , 'dummy' ) ) and ( not _util . command_exists ( mount_command ) ) ) : #NEWLINE# #INDENT# print ( col ( '[-] {0} is not installed!' . format ( args . method ) , 'red' ) ) #NEWLINE# sys . exit ( 1 ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( ( args . method == 'auto' ) and ( not any ( map ( _util . command_exists , ( 'xmount' , 'affuse' , 'ewfmount' , 'vmware-mount' , 'avfsd' ) ) ) ) ) : #NEWLINE# #INDENT# print ( col ( '[-] No tools installed to mount the image base! Please install xmount, affuse (afflib-tools), ewfmount (ewf-tools), vmware-mount or avfs first.' , 'red' ) ) #NEWLINE# sys . exit ( 1 ) #NEWLINE# #UNINDENT# #UNINDENT# if ( ( args . detection == 'pytsk3' ) and ( not _util . module_exists ( 'pytsk3' ) ) ) : #NEWLINE# #INDENT# print ( col ( '[-] pytsk3 module does not exist!' , 'red' ) ) #NEWLINE# sys . exit ( 1 ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( ( args . detection in ( 'mmls' , 'parted' ) ) and ( not _util . command_exists ( args . detection ) ) ) : #NEWLINE# #INDENT# print ( col ( '[-] {0} is not installed!' . format ( args . detection ) , 'red' ) ) #NEWLINE# sys . exit ( 1 ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( ( args . detection == 'auto' ) and ( not any ( ( _util . module_exists ( 'pytsk3' ) , _util . command_exists ( 'mmls' ) , _util . command_exists ( 'parted' ) ) ) ) ) : #NEWLINE# #INDENT# print ( col ( '[-] No tools installed to detect volumes! Please install mmls (sleuthkit), pytsk3 or parted first.' , 'red' ) ) #NEWLINE# sys . exit ( 1 ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# if ( args . raid and ( not _util . command_exists ( 'mdadm' ) ) ) : #NEWLINE# #INDENT# if explicit_raid : #NEWLINE# #INDENT# print ( col ( '[!] RAID mount requires the mdadm command.' , 'yellow' ) ) #NEWLINE# #UNINDENT# args . raid = False #NEWLINE# #UNINDENT# if ( args . reconstruct and ( not args . stats ) ) : #NEWLINE# #INDENT# print ( '[!] You explicitly disabled stats, but --reconstruct implies the use of stats. Stats are re-enabled.' ) #NEWLINE# args . stats = True #NEWLINE# #UNINDENT# if ( args . disktype and ( not _util . command_exists ( 'disktype' ) ) ) : #NEWLINE# #INDENT# if explicit_disktype : #NEWLINE# #INDENT# print ( col ( '[-] The disktype command can not be used in this session, as it is not installed.' , 'yellow' ) ) #NEWLINE# #UNINDENT# args . disktype = False #NEWLINE# #UNINDENT# if ( args . stats and ( not _util . command_exists ( 'fsstat' ) ) ) : #NEWLINE# #INDENT# print ( col ( '[-] The fsstat command (part of sleuthkit package) is required to obtain stats, but is not installed. Stats can not be obtained during this session.' , 'yellow' ) ) #NEWLINE# args . stats = False #NEWLINE# if args . reconstruct : #NEWLINE# #INDENT# print ( col ( '[-] Reconstruction requires stats to be obtained, but stats can not be enabled.' , 'red' ) ) #NEWLINE# sys . exit ( 1 ) #NEWLINE# #UNINDENT# #UNINDENT# if args . fstypes : #NEWLINE# #INDENT# for ( k , v ) in args . fstypes . items ( ) : #NEWLINE# #INDENT# if ( ( v . strip ( ) not in FILE_SYSTEM_TYPES ) and ( not ( ( k == '?' ) and ( v . strip ( ) . lower ( ) == 'none' ) ) ) ) : #NEWLINE# #INDENT# print ( '[!] Error while parsing --fstypes: {} is invalid' . format ( v ) ) #NEWLINE# sys . exit ( 1 ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# if ( '*' in args . fstypes ) : #NEWLINE# #INDENT# print ( '[!] You are forcing the file system type to {0}. This may cause unexpected results.' . format ( args . fstypes [ '*' ] ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( ( '?' in args . fstypes ) and ( args . fstypes [ '?' ] not in ( 'unknown' , 'none' ) ) ) : #NEWLINE# #INDENT# print ( '[!] You are using the file system type {0} as fallback. This may cause unexpected results.' . format ( args . fstypes [ '?' ] ) ) #NEWLINE# #UNINDENT# #UNINDENT# if args . only_mount : #NEWLINE# #INDENT# args . only_mount = args . only_mount . split ( ',' ) #NEWLINE# #UNINDENT# if ( ( args . vstype != 'detect' ) and args . single ) : #NEWLINE# #INDENT# print ( "[!] There's no point in using --single in combination with --vstype." ) #NEWLINE# #UNINDENT# if ( args . carve and ( not _util . command_exists ( 'photorec' ) ) ) : #NEWLINE# #INDENT# print ( col ( '[-] The photorec command (part of testdisk package) is required to carve, but is not installed. Carving will be disabled.' , 'yellow' ) ) #NEWLINE# args . carve = False #NEWLINE# #UNINDENT# if ( ( not args . images ) and ( not args . unmount ) ) : #NEWLINE# #INDENT# print ( col ( '[-] You must specify at least one path to a disk image' , 'red' ) ) #NEWLINE# sys . exit ( 1 ) #NEWLINE# #UNINDENT# if args . unmount : #NEWLINE# #INDENT# unmounter = Unmounter ( ** vars ( args ) ) #NEWLINE# commands = unmounter . preview_unmount ( ) #NEWLINE# if ( not commands ) : #NEWLINE# #INDENT# print ( '[+] Nothing to do' ) #NEWLINE# parser . exit ( ) #NEWLINE# #UNINDENT# print ( '[!] --unmount will rigorously clean anything that looks like a mount or volume group originating from this utility. You may regret using this if you have other mounts or volume groups that are similarly named. The following commands will be executed:' ) #NEWLINE# for c in commands : #NEWLINE# #INDENT# print ( '    {0}' . format ( c ) ) #NEWLINE# #UNINDENT# try : #NEWLINE# #INDENT# input ( '>>> Press [enter] to continue or ^C to cancel... ' ) #NEWLINE# unmounter . unmount ( ) #NEWLINE# #UNINDENT# except KeyboardInterrupt : #NEWLINE# #INDENT# print ( '\n[-] Aborted.' ) #NEWLINE# #UNINDENT# sys . exit ( 0 ) #NEWLINE# #UNINDENT# images = [ ] #NEWLINE# for ( num , image ) in enumerate ( args . images ) : #NEWLINE# #INDENT# if os . path . isdir ( image ) : #NEWLINE# #INDENT# for f in glob . glob ( os . path . join ( image , '*.[E0]01' ) ) : #NEWLINE# #INDENT# images . append ( f ) #NEWLINE# break #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# print ( col ( '[-] {0} is a directory not containing a .001 or .E01 file, aborting!' . format ( image ) , 'red' ) ) #NEWLINE# break #NEWLINE# #UNINDENT# continue #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( not os . path . exists ( image ) ) : #NEWLINE# #INDENT# print ( col ( '[-] Image {0} does not exist, aborting!' . format ( image ) , 'red' ) ) #NEWLINE# break #NEWLINE# #UNINDENT# #UNINDENT# images . append ( image ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# p = None #NEWLINE# try : #NEWLINE# #INDENT# p = ImageParser ( images , ** vars ( args ) ) #NEWLINE# num = 0 #NEWLINE# found_raid = False #NEWLINE# for disk in p . disks : #NEWLINE# #INDENT# num += 1 #NEWLINE# print ( '[+] Mounting image {0} using {1}...' . format ( p . paths [ 0 ] , disk . method ) ) #NEWLINE# if ( not disk . mount ( ) ) : #NEWLINE# #INDENT# print ( col ( '[-] Failed mounting base image. Perhaps try another mount method than {0}?' . format ( disk . method ) , 'red' ) ) #NEWLINE# return #NEWLINE# #UNINDENT# if args . raid : #NEWLINE# #INDENT# if disk . add_to_raid ( ) : #NEWLINE# #INDENT# found_raid = True #NEWLINE# #UNINDENT# #UNINDENT# if args . read_write : #NEWLINE# #INDENT# print ( '[+] Created read-write cache at {0}' . format ( disk . rwpath ) ) #NEWLINE# #UNINDENT# if args . disktype : #NEWLINE# #INDENT# disk . volumes . load_disktype_data ( ) #NEWLINE# #UNINDENT# print ( '[+] Mounted raw image [{num}/{total}]' . format ( num = num , total = len ( args . images ) ) ) #NEWLINE# #UNINDENT# sys . stdout . write ( '[+] Mounting volume...\r' ) #NEWLINE# sys . stdout . flush ( ) #NEWLINE# has_left_mounted = False #NEWLINE# for volume in p . mount_volumes ( args . single , args . only_mount ) : #NEWLINE# #INDENT# try : #NEWLINE# #INDENT# if ( ( not volume . mountpoint ) and ( not volume . loopback ) ) : #NEWLINE# #INDENT# if ( volume . exception and ( volume . size is not None ) and ( volume . size <= 1048576 ) ) : #NEWLINE# #INDENT# print ( col ( '[-] Exception while mounting small volume {0}' . format ( volume . get_description ( ) ) , 'yellow' ) ) #NEWLINE# if args . wait : #NEWLINE# #INDENT# input ( col ( '>>> Press [enter] to continue... ' , attrs = [ 'dark' ] ) ) #NEWLINE# #UNINDENT# #UNINDENT# else : #NEWLINE# #INDENT# if volume . exception : #NEWLINE# #INDENT# print ( col ( '[-] Exception while mounting {0}' . format ( volume . get_description ( ) ) , 'red' ) ) #NEWLINE# if ( not args . no_interaction ) : #NEWLINE# #INDENT# input ( col ( '>>> Press [enter] to continue... ' , attrs = [ 'dark' ] ) ) #NEWLINE# #UNINDENT# #UNINDENT# else : #NEWLINE# #INDENT# if ( volume . flag != 'alloc' ) : #NEWLINE# #INDENT# if ( args . wait or args . verbose ) : #NEWLINE# #INDENT# print ( col ( '[-] Skipped {0} {1} volume' . format ( volume . get_description ( ) , volume . flag ) , 'yellow' ) ) #NEWLINE# #UNINDENT# if args . wait : #NEWLINE# #INDENT# input ( col ( '>>> Press [enter] to continue... ' , attrs = [ 'dark' ] ) ) #NEWLINE# #UNINDENT# #UNINDENT# else : #NEWLINE# #INDENT# if ( not volume . _should_mount ( args . only_mount ) ) : #NEWLINE# #INDENT# print ( col ( '[-] Skipped {0}' . format ( volume . get_description ( ) ) , 'yellow' ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# print ( col ( '[-] Could not mount volume {0}' . format ( volume . get_description ( ) ) , 'yellow' ) ) #NEWLINE# if args . wait : #NEWLINE# #INDENT# input ( col ( '>>> Press [enter] to continue... ' , attrs = [ 'dark' ] ) ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# #UNINDENT# #UNINDENT# if ( args . carve and ( volume . flag in ( 'alloc' , 'unalloc' ) ) ) : #NEWLINE# #INDENT# sys . stdout . write ( '[+] Carving volume...\r' ) #NEWLINE# sys . stdout . flush ( ) #NEWLINE# if volume . carve ( freespace = False ) : #NEWLINE# #INDENT# print ( '[+] Carved data is available at {0}.' . format ( col ( volume . carvepoint , 'green' , attrs = [ 'bold' ] ) ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# print ( col ( '[-] Carving failed.' , 'red' ) ) #NEWLINE# #UNINDENT# #UNINDENT# else : #NEWLINE# #INDENT# continue #NEWLINE# #UNINDENT# #UNINDENT# else : #NEWLINE# #INDENT# if volume . mountpoint : #NEWLINE# #INDENT# print ( '[+] Mounted volume {0} on {1}.' . format ( col ( volume . get_description ( ) , attrs = [ 'bold' ] ) , col ( volume . mountpoint , 'green' , attrs = [ 'bold' ] ) ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if volume . loopback : #NEWLINE# #INDENT# print ( '[+] Mounted volume {0} as loopback on {1}.' . format ( col ( volume . get_description ( ) , attrs = [ 'bold' ] ) , col ( volume . loopback , 'green' , attrs = [ 'bold' ] ) ) ) #NEWLINE# print ( col ( '[-] Could not detect further volumes in the loopback device.' , 'red' ) ) #NEWLINE# #UNINDENT# #UNINDENT# if args . carve : #NEWLINE# #INDENT# sys . stdout . write ( '[+] Carving volume...\r' ) #NEWLINE# sys . stdout . flush ( ) #NEWLINE# if volume . carve ( ) : #NEWLINE# #INDENT# print ( '[+] Carved data is available at {0}.' . format ( col ( volume . carvepoint , 'green' , attrs = [ 'bold' ] ) ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# print ( col ( '[-] Carving failed.' , 'red' ) ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# if ( args . reconstruct or args . keep ) : #NEWLINE# #INDENT# has_left_mounted = True #NEWLINE# continue #NEWLINE# #UNINDENT# input ( col ( '>>> Press [enter] to unmount the volume, or ^C to keep mounted... ' , attrs = [ 'dark' ] ) ) #NEWLINE# while True : #NEWLINE# #INDENT# if volume . unmount ( ) : #NEWLINE# #INDENT# break #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# try : #NEWLINE# #INDENT# print ( col ( '[-] Error unmounting volume. Perhaps files are still open?' , 'red' ) ) #NEWLINE# input ( col ( '>>> Press [enter] to retry unmounting, or ^C to skip... ' , attrs = [ 'dark' ] ) ) #NEWLINE# #UNINDENT# except KeyboardInterrupt : #NEWLINE# #INDENT# has_left_mounted = True #NEWLINE# print ( '' ) #NEWLINE# break #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# #UNINDENT# except KeyboardInterrupt : #NEWLINE# #INDENT# has_left_mounted = True #NEWLINE# print ( '' ) #NEWLINE# #UNINDENT# sys . stdout . write ( '[+] Mounting volume...\r' ) #NEWLINE# sys . stdout . flush ( ) #NEWLINE# #UNINDENT# for disk in p . disks : #NEWLINE# #INDENT# if ( [ x for x in disk . volumes if x . was_mounted ] == 0 ) : #NEWLINE# #INDENT# if ( args . vstype != 'detect' ) : #NEWLINE# #INDENT# print ( col ( '[?] Could not determine volume information of {0}. Image may be empty, or volume system type {0} was incorrect.' . format ( args . vstype . upper ( ) ) , 'yellow' ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if found_raid : #NEWLINE# #INDENT# print ( col ( '[?] Could not determine volume information. Image may be empty, or volume system type could not be detected. Try explicitly providing the volume system type with --vstype, or providing more volumes to complete the RAID array.' , 'yellow' ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( ( not args . raid ) or ( args . single is False ) ) : #NEWLINE# #INDENT# print ( col ( '[?] Could not determine volume information. Image may be empty, or volume system type could not be detected. Try explicitly providing the volume system type with --vstype, mounting as RAID with --raid and/or mounting as a single volume with --single' , 'yellow' ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# print ( col ( '[?] Could not determine volume information. Image may be empty, or volume system type could not be detected. Try explicitly providing the volume system type with --vstype.' , 'yellow' ) ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# if args . wait : #NEWLINE# #INDENT# input ( col ( '>>> Press [enter] to continue... ' , attrs = [ 'dark' ] ) ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# print ( '[+] Parsed all volumes!' ) #NEWLINE# if args . reconstruct : #NEWLINE# #INDENT# print ( '[+] Performing reconstruct... ' ) #NEWLINE# root = p . reconstruct ( ) #NEWLINE# if ( not root ) : #NEWLINE# #INDENT# print ( col ( '[-] Failed reconstructing filesystem: could not find root directory.' , 'red' ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# failed = [ ] #NEWLINE# for disk in p . disks : #NEWLINE# #INDENT# failed . extend ( [ x for x in disk . volumes if ( ( not x . bindmountpoint ) and x . mountpoint and ( x != root ) ) ] ) #NEWLINE# #UNINDENT# if failed : #NEWLINE# #INDENT# print ( '[+] Parts of the filesystem are reconstructed in {0}.' . format ( col ( root . mountpoint , 'green' , attrs = [ 'bold' ] ) ) ) #NEWLINE# for m in failed : #NEWLINE# #INDENT# print ( '    {0} was not reconstructed' . format ( m . mountpoint ) ) #NEWLINE# #UNINDENT# #UNINDENT# else : #NEWLINE# #INDENT# print ( '[+] The entire filesystem is reconstructed in {0}.' . format ( col ( root . mountpoint , 'green' , attrs = [ 'bold' ] ) ) ) #NEWLINE# #UNINDENT# #UNINDENT# if ( not args . keep ) : #NEWLINE# #INDENT# input ( col ( '>>> Press [enter] to unmount all volumes... ' , attrs = [ 'dark' ] ) ) #NEWLINE# #UNINDENT# #UNINDENT# else : #NEWLINE# #INDENT# if ( has_left_mounted and ( not args . keep ) ) : #NEWLINE# #INDENT# input ( col ( '>>> Some volumes were left mounted. Press [enter] to unmount all... ' , attrs = [ 'dark' ] ) ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# except KeyboardInterrupt : #NEWLINE# #INDENT# print ( '\n[+] User pressed ^C, aborting...' ) #NEWLINE# return #NEWLINE# #UNINDENT# except Exception as e : #NEWLINE# #INDENT# import traceback #NEWLINE# traceback . print_exc ( ) #NEWLINE# print ( col ( '[-] {0}' . format ( e ) , 'red' ) ) #NEWLINE# if ( not args . no_interaction ) : #NEWLINE# #INDENT# input ( col ( '>>> Press [enter] to continue.' , attrs = [ 'dark' ] ) ) #NEWLINE# #UNINDENT# #UNINDENT# finally : #NEWLINE# #INDENT# if args . keep : #NEWLINE# #INDENT# print ( '[+] Analysis complete.' ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( not p ) : #NEWLINE# #INDENT# print ( '[-] Crashed before creating parser' ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# print ( '[+] Analysis complete, unmounting...' ) #NEWLINE# try : #NEWLINE# #INDENT# remove_rw = ( p . rw_active ( ) and ( 'y' in input ( '>>> Delete the rw cache file? [y/N] ' ) . lower ( ) ) ) #NEWLINE# #UNINDENT# except KeyboardInterrupt : #NEWLINE# #INDENT# remove_rw = False #NEWLINE# #UNINDENT# while True : #NEWLINE# #INDENT# if p . clean ( remove_rw ) : #NEWLINE# #INDENT# break #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# try : #NEWLINE# #INDENT# print ( col ( '[-] Error unmounting base image. Perhaps volumes are still open?' , 'red' ) ) #NEWLINE# input ( col ( '>>> Press [enter] to retry unmounting, or ^C to cancel... ' , attrs = [ 'dark' ] ) ) #NEWLINE# #UNINDENT# except KeyboardInterrupt : #NEWLINE# #INDENT# print ( '' ) #NEWLINE# break #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# print ( '[+] All cleaned up' )