1. Elie Bursztein
  2. OWADE

Source

OWADE / src / ui / owade / fileExtraction / getFiles.py


#############################################################################
##                                                                         ##
## This file is part of Owade : www.owade.org                              ##
## Offline Windows Analyzer and Data Extractor                             ##
##                                                                         ##
##  Authors:                                                               ##
##  Elie Bursztein <owade@elie.im>                                         ##
##  Ivan Fontarensky <ivan.fontarensky@cassidian.com>                      ##
##  Matthieu Martin <matthieu.mar+owade@gmail.com>                         ##
##  Jean-Michel Picod <jean-michel.picod@cassidian.com>                    ##
##                                                                         ##
## This program is distributed under GPLv3 licence (see LICENCE.txt)       ##
##                                                                         ##
#############################################################################
import os.path
__author__="ashe"
__date__ ="$Jun 13, 2011 3:08:21 PM$"

import os
import shutil
from subprocess import call
from stat import ST_SIZE

from ui.owade.constants import *
from ui.owade.process import Process
from ui.owade.fileExtraction.foremost import Foremost
from ui.owade.fileExtraction.mmls import Mmls
from ui.owade.fileExtraction.hash import Hash
from ui.owade.fileExtraction.mount import Mount
from ui.owade.fileExtraction.umount import Umount
from ui.owade.models import HardDrive, Partition, File, FileInfo

## Copy all the files from the hard drive image and stock them into the database
class GetFiles(Process):
    def __init__(self, internLog, terminalLog, hardDrive, overWrite):
        Process.__init__(self, internLog, terminalLog)
        self.hardDrive_ = hardDrive
        self.overWrite_ = overWrite


    def run(self):
        #is DD exist and get dump
        self.internLog_.addLog("Check hard drive", 1)
        path = self.hardDrive_.image_path()
        if not os.path.exists(path):
            self.internLog_.addLog("Hard drive's dump has been deleted (%s)" % (path), 2)
            return

        #is Partition already exist, yes and overwrite : dump them
        self.internLog_.addLog("Check paritions on database", 1)
        partitions = Partition.objects.filter(harddrive=self.hardDrive_)
        if partitions.count() != 0:
            if not self.overWrite_:
                self.internLog_.addLog("Partitions already exist in the database, jump this step", 2)
                return
            self.internLog_.addLog("Dump old partitions", 1)
            try:
                partitions.delete()
            except Exception as exp:
                self.internLog_.addLog("Delete partitions from database failed: %s" % (exp), 2)
                return

        if self.interupt_:
            return

        #is parition exists ? mmls
        self.internLog_.addLog("Check paritions on image", 1)
        mmls = Mmls(self.internLog_, self.terminalLog_, self.hardDrive_.image_path())

        #no -> try to recreate them
        if not self.launch(mmls):
            self.restore()
            mmls = Mmls(self.internLog_, self.terminalLog_, self.hardDrive_.image_path())
            self.launch(mmls)

        #yes -> parc and create files
        if mmls.success_:
            self.softRecovery(mmls.partitions_)

        #no -> hard recovery
        else:
            self.hardRecovery()


    def softRecovery(self, partitions):
        self.internLog_.addLog("Soft recovery", 1)
        mountpoint = "%s/%s" % (IMAGE_DIR, "recoverymount")
        if os.path.exists(mountpoint):
            os.rmdir(mountpoint)
        os.mkdir(mountpoint)

        rv = True
        for part in partitions:
            #Add partition in db
            self.internLog_.addLog("Partition: %s" % (str(part)), 1)
            partition = Partition(slot=part['slot'], offset=part['offset'],
                size=part['size'], type=part['type'], harddrive=self.hardDrive_)
            if not self.updateDb(partition):
                rv = False
                continue
                #return False

            #Mount partition
            mount = Mount(self.internLog_, self.terminalLog_, 'ntfs', int(partition.offset) * 512,
                self.hardDrive_.image_path(), mountpoint)
            if not self.launch(mount):
                self.internLog_.addLog("Mount fail", 2)
                rv = False
                continue
                #return False

            #Parc partition
            curDir = os.getcwd()
            os.chdir(mountpoint)
            self.parc(partition, "/")
            os.chdir(curDir)

            #Umount partition
            umount = Umount(self.internLog_, self.terminalLog_, mountpoint)
            if not self.launch(umount):
                self.internLog_.addLog("Umount fail", 2)
                rv = False
                continue
                #return False

        os.rmdir(mountpoint)
        if self.interupt_:
            return False
        return rv


    def parc(self, partition, pathWindowsDir):
        pathLocalDir = os.getcwd()
        contents = os.listdir(pathLocalDir)

        #Parc files on current directory
        for nameFile in contents:
            pathLocalFile = os.path.join(pathLocalDir, nameFile)
            #If is file : add it on db
            if os.path.isfile(pathLocalFile):
                self.addFile(partition, pathLocalDir, nameFile, pathWindowsDir)
            #If is directory : recursive parc
            elif os.path.isdir(pathLocalFile):
                os.chdir(pathLocalFile)
                self.parc(partition, "%s%s/" % (pathWindowsDir, nameFile))
                os.chdir(pathLocalDir)
            else:
                self.internLog_.addLog("Not a directory nor a file: %s" % (pathLocalFile), 1)
            if self.interupt_:
                return False
        return True


    def addFile(self, partition, pathLocalDir, nameFile, pathWindowsDir):
        path = os.path.join(pathLocalDir, nameFile)

        #Get hash of the file
        hash = Hash(self.internLog_, self.terminalLog_, path)
        if not self.launch(hash):
            return False
        checksum = hash.hash_

        #Check using the hash if the file already exist
        file = None
        files = File.objects.filter(checksum=checksum)
        for f in files:
            if call(["cmp", f.file_path(), path]) == 0:
                file = f
                break

        #if it doesn't exist, create it in the db
        if file == None:
            pos = nameFile.rfind('.')
            extension = ""
            if pos != -1:
                extension = nameFile[pos + 1:].lower()
            size = os.stat(path)[ST_SIZE]
            file = File(checksum=checksum, extension=extension, size=size)
            if not self.updateDb(file):
                return false
            shutil.copy(path, file.file_path())

        #Create the link between parition and file in the db
        fileInfo = FileInfo(name=nameFile, dir_path=pathWindowsDir, partition=partition, file=file)
        if not self.updateDb(fileInfo):
            return False
        return True


    def hardRecovery(self):
        self.internLog_.addLog("Hard recovery", 1)
        dumpDir = "%s/%s" % (IMAGE_DIR, "recoveryforemost")
        if os.path.exists(dumpDir):
            os.rmdir(dumpDir)
        os.mkdir(dumpDir)

        #Create a fake partition in the database
        partition = Partition(slot=1, offset=0,
            size=self.hardDrive_.size, type="Hard Recovery", harddrive=self.hardDrive_)
        if not self.updateDb(partition):
            return False

        #Use foremost to do the hard recovery
        foremost = Foremost(self.internLog_, self.terminalLog_, self.hardDrive_.image_path(), dumpDir)
        if not self.launch(foremost):
            self.internLog_.addLog("Foremost failed to recover", 1)
            return False

        #Parc foremost dump to save files
        dirs = os.listdir(dumpDir)
        for nameDir in dirs:
            pathLocalDir = os.path.join(dumpDir, nameDir)
            #If it's one of foremost dir : parc
            if os.path.isdir(pathLocalDir):
                files = os.listdir(pathLocalDir)
                for nameFile in files:
                    pathLocalFile = os.path.join(pathLocalDir, nameFile)
                    if os.path.isfile(pathLocalFile):
                        addFile(partition, pathLocalDir, nameFile, "")
            if self.interupt_:
                return False

        os.rmdir(dumpDir)
        return True


    def restore(self):
        #Hard to automate, as they all ask for user confirmation or partition selection
        #self.internLog_.addLog("Trying to restore partitions", 1)
        self.internLog_.addLog("Restoration isn't automated in Owade, you shound give a try before continuing", 2)
        self.internLog_.addLog("Cancel this process then launch testdisk on %s" % self.hardDrive_.image_path(), 2)



    hardDrive_ = None
    overWrite_ = None