def parse_mft(file):

    # The analyzeMFT library is only somewhat written to support being modular and used in another program/script.
    # As such, to access some functionality it is necessary to trick the library into believing it is being
    # called from command line. To do so, I have implemented OptionParser to pass arguguments in a way the
    # library understands. The below arguments, stored in the variable options, tell analyzeMFT to use the local
    # timezone, perform anomaly detection while processing the $MFT and that the arguments "inmemory",
    # "debug" and "useGUI" are unset and therefore False.
    input_file = open(file, 'rb')
    args = ["--localtz", "True", "--anomaly", "True"]
    parser = OptionParser()
    parser.add_option("--inmemory", dest="inmemory")
    parser.add_option("--debug", dest="debug")
    parser.add_option("--localtz", dest="localtz")
    parser.add_option("--UseGUI", dest="UseGUI")
    parser.add_option("--anomaly", dest="anomaly")
    (options, args) = parser.parse_args(args)
    date_settings = date_options()

    # Read the first 1024 bytes of the $MFT. Each record is 1024 bytes so a single record is being read.
    # Also, open a handle to the CSV we will write all of the parsed $MFT data to.
    raw_record = input_file.read(1024)
    parsed_mft = csv.writer(open(os.getcwd() + "/parsed_mft.csv", 'wb'),
                            dialect=csv.excel,
                            quoting=1)

    # If the raw MFT record is not blank, pass the raw record to analyzeMFT's parser along with the
    # necessary options set previously. If the parsed record is an actual file it will have $FILE_NAME
    # attributes. Some NTFS inodes are reserved or not used and therefore will not have a $FILE_NAME
    # record. If this is the case, do not attempt to read its name and mark it as haviing no FN record.
    #  When done, read the next 1024 bytes of the $MFT. The first iteration passes the argument 'True'
    # to the mft_to_csv function telling it to print the column headers. In doing so, we are skipping
    # reading in any attributes of $MFT since we are not concerned with an attacker timestomping it.
    # The result is a CSV containing a parse $MFT.
    if raw_record != "":

        mft_record = {}
        mft_record = mft.parse_record(raw_record, options)

        parsed_mft.writerow(mft.mft_to_csv(mft_record, True, date_settings))
        raw_record = input_file.read(1024)

    while raw_record != "":

        mft_record = {}
        mft_record = mft.parse_record(raw_record, options)

        if mft_record['fncnt'] != 0:
            mft_record['filename'] = mft_record[('fn', 0)]["name"]
        else:
            mft_record['filename'] = "NoFNRecord"

        parsed_mft.writerow(mft.mft_to_csv(mft_record, False, date_settings))
        raw_record = input_file.read(1024)
Exemplo n.º 2
0
    def process_mft_file(self):

        self.sizecheck()

        self.build_filepaths()

        # reset the file reading
        self.num_records = 0
        self.file_mft.seek(0)
        raw_record = self.file_mft.read(1024)

        if self.options.output is not None:
            self.file_csv.writerow(mft.mft_to_csv(None, True, self.options))

        while raw_record != "":
            record = mft.parse_record(raw_record, self.options)
            if self.options.debug:
                print(record)

            record['filename'] = self.mft[self.num_records]['filename']

            self.do_output(record)

            self.num_records += 1

            if record['ads'] > 0:
                for i in range(0, record['ads']):
                    #                         print "ADS: %s" % (record['data_name', i])
                    record_ads = record.copy()
                    record_ads['filename'] = record['filename'] + ':' + record[
                        'data_name', i]
                    self.do_output(record_ads)

            raw_record = self.file_mft.read(1024)
Exemplo n.º 3
0
    def process_mft_file(self):
        self.sizecheck()
        self.build_filepaths()

        # reset the file reading
        self.num_records = 0
        self.file_mft.seek(0)
        raw_record = self.file_mft.read(1024)
        if self.options.output is not None:
            header_values = mft.mft_to_csv(None, True, self.options)
            self.file_csv.writerow(header_values)

        while raw_record:
            record = mft.parse_record(raw_record, self.options)
            record['filename'] = self.mft[self.num_records]['filename']
            self.do_output(record)
            self.num_records += 1

            if record['ads'] > 0:
                for i in range(0, record['ads']):
                    record_ads = record.copy()
                    record_ads['filename'] = record['filename'] + ':' + record[
                        'data_name', i].decode("utf-8")
                    self.do_output(record_ads)

            raw_record = self.file_mft.read(1024)
Exemplo n.º 4
0
    def build_file_paths(self):
        """
        reading record-by-record from the MFT table, parsing it and building the file paths
        """
        # reset the file reading
        self.analyzeMFT_session.file_mft.seek(0)
        self.analyzeMFT_session.num_records = 0

        # 1024 = 1KB is the size of a record in the MFT table
        raw_record = self.analyzeMFT_session.file_mft.read(1024)
        while raw_record != "":
            minirec = {}
            # parsing the records with an analyzeMFT function
            record = mft.parse_record(raw_record,
                                      self.analyzeMFT_session.options)
            minirec['filename'] = record['filename']
            minirec['fncnt'] = record['fncnt']
            if record['fncnt'] == 1:
                minirec['par_ref'] = record['fn', 0]['par_ref']
                minirec['name'] = record['fn', 0]['name']
            if record['fncnt'] > 1:
                minirec['par_ref'] = record['fn', 0]['par_ref']
                for i in (0, record['fncnt'] - 1):
                    if record['fn', i]['nspace'] == 0x1 or record[
                            'fn', i]['nspace'] == 0x3:
                        minirec['name'] = record['fn', i]['name']
                if minirec.get('name') is None:
                    minirec['name'] = record['fn', record['fncnt'] - 1]['name']

            self.analyzeMFT_session.mft[
                self.analyzeMFT_session.num_records] = minirec
            self.analyzeMFT_session.num_records += 1

            # reading the next record
            raw_record = self.analyzeMFT_session.file_mft.read(1024)
Exemplo n.º 5
0
 def get_filelist(self):
 
     num_records = 0
     record = {}
     
     self.rd.seek(self.part['mftstart'], 0)
     raw_record = self.rd.read(1024)
 
     record = mft.parse_record(raw_record, self.options)
 
     length = record['data',0]['dataruns'][0][0] * 4096
     offset = record['data',0]['dataruns'][0][1] * \
                 self.part['spc'] * self.part['bps'] * self.part['start']        
 
     self.rd.seek(self.part['mftstart'], 0)
 
     for i in range(0, length, 1024):    
         raw_record = self.rd.read(1024)
 
         record = {}
         minirec = {}
         record = mft.parse_record(raw_record, self.options)
         if self.options.debug: print record
                
         minirec['filename'] = record['filename']
         minirec['fncnt'] = record['fncnt']
         if record['fncnt'] == 1:
             minirec['par_ref'] = record['fn',0]['par_ref']
             minirec['name'] = record['fn',0]['name']
         if record['fncnt'] > 1:
             minirec['par_ref'] = record['fn',0]['par_ref']
             minirec['name'] = record['fn', record['fncnt']-1]['name']		
         
         # Corrupt records don't have data elements. Fix in analyzeMFT
         try:
             minirec['data'] = record['data', 0]                #code
             minirec['datacnt'] = record['datacnt']               
         except Exception:
             minirec['data'] = ''
             minirec['datacnd'] = 0
 
         self.filelist[num_records] = minirec
 
         num_records = num_records + 1
 
     self.gen_filepaths()
Exemplo n.º 6
0
 def collect_mft(self):
 
     self.rd.seek(self.part['mftstart'])
     data = self.rd.read(1024)
 
     record = mft.parse_record(data, options)
     
     collect_file(record['data',0], filename)
Exemplo n.º 7
0
    def plaso_process_mft_file(self):

        # TODO - Add ADS support ....

        self.build_filepaths()

        # reset the file reading
        self.num_records = 0
        self.file_mft.seek(0)
        raw_record = self.file_mft.read(1024)

        while raw_record:
            record = mft.parse_record(raw_record, self.options)

            record['filename'] = self.mft[self.num_records]['filename']
            self.fullmft[self.num_records] = record
            self.num_records += 1
            raw_record = self.file_mft.read(1024)
Exemplo n.º 8
0
    def build_filepaths(self):
        # reset the file reading
        self.file_mft.seek(0)

        self.num_records = 0

        # 1024 is valid for current version of Windows but should really get this value from somewhere
        raw_record = self.file_mft.read(1024)
        while raw_record != "":
            minirec = {}
            record = mft.parse_record(raw_record, self.options)
            if self.options.debug:
                print(record)

            minirec['filename'] = record['filename']
            minirec['fncnt'] = record['fncnt']
            if record['fncnt'] == 1:
                minirec['par_ref'] = record['fn', 0]['par_ref']
                minirec['name'] = record['fn', 0]['name']
            if record['fncnt'] > 1:
                minirec['par_ref'] = record['fn', 0]['par_ref']
                for i in (0, record['fncnt'] - 1):
                    # print record['fn',i]
                    if record['fn', i]['nspace'] == 0x1 or record[
                            'fn', i]['nspace'] == 0x3:
                        minirec['name'] = record['fn', i]['name']
                if minirec.get('name') is None:
                    minirec['name'] = record['fn', record['fncnt'] - 1]['name']

            self.mft[self.num_records] = minirec

            if self.options.progress:
                if self.num_records % (self.mftsize /
                                       5) == 0 and self.num_records > 0:
                    print(
                        'Building Filepaths: {0:.0f}'.format(
                            100.0 * self.num_records / self.mftsize) + '%')

            self.num_records += 1

            raw_record = self.file_mft.read(1024)

        self.gen_filepaths()
Exemplo n.º 9
0
    def update_record(self, record_no, raw_record = None):
        """
            Update record when it changes (or to initialize)
        """

        # if new data is provided, use the new data as the raw record,
        # otherwise, reparse it from the internal self.MFT_RAW file 
        if raw_record:
            assert len(raw_record) == 1024
            self.MFT_RAW = self.MFT_RAW[:record_no*1024] + raw_record + self.MFT_RAW[(record_no+1)*1024:]

        raw_record = self.MFT_RAW[record_no*1024:(record_no+1)*1024]            

  
        record = mft.parse_record(raw_record, mft.set_default_options())

        # Update the filepaths?
        if record['fncnt'] == 1:
            record['par_ref'] = record['fn',0]['par_ref']
            record['name'] = record['fn',0]['name']
        if record['fncnt'] > 1:
            record['par_ref'] = record['fn',0]['par_ref']
            for j in (0, record['fncnt']-1):
                #print record['fn',i]
                if (record['fn', j]['nspace'] == 0x1 or record['fn', j]['nspace'] == 0x3):
                    record['name'] = record['fn', j]['name']
            if (record.get('name') == None):
                record['name'] = record['fn', record['fncnt']-1]['name']
    
    
        # add the record to the MFT
        self.mft[record_no] = record
    
        # process children records, if any
        # children records are stored in other records or on disk (non-resident)
        self._process_children(record_no)
    


        # Need to call gen_filepaths()
        self.gen_filepaths()
Exemplo n.º 10
0
    def _process_children(self, record_no):
        """
            Process all the children records for the parent MFT record at record_no
            
            Children records are all attributes stored separately, e.g. in another MFT
            record or (if non-resident) in the filesystem
        """

                    
        # check if this MFT record has an attribute list
        record = self.mft[record_no]

                
        if 'attribute_list' in record:
            
            # check if resident elsewhere in MFT or non-resident (in the filesystem somewhere)
            if record['attribute_list']['res'] != 0: # non-resident
                # TODO pull from filesystem - remember to use volume offsets
                pass
                
            # go through each attribute list entry and pluck from other MFT entries
            for attr_list_record in record['attribute_list']['records']:
                    
                # skip if it's in the current record                        
                if attr_list_record['mft_record_no'] != record_no:
                        
                    # find the other record and look for the attribute we need
                    raw_other_record = self.MFT_RAW[attr_list_record['mft_record_no']*1024:(attr_list_record['mft_record_no']+1)*1024]
                    other_record = mft.parse_record(raw_other_record, mft.set_default_options())
                    
                    self.mft[attr_list_record['mft_record_no']] = other_record
                                       
                    for attribute in other_record['attributes']:
                        if attribute['type'] == attr_list_record['type'] and \
                        attribute['name'] == attr_list_record['name']:
                        
                            record['attributes'].append(attribute)