def extract(self, offset, description, file_name, size, name=None): ''' Extract an embedded file from the target file, if it matches an extract rule. Called automatically by Binwalk.scan(). @offset - Offset inside the target file to begin the extraction. @description - Description of the embedded file to extract, as returned by libmagic. @file_name - Path to the target file. @size - Number of bytes to extract. @name - Name to save the file as. Returns the name of the extracted file (blank string if nothing was extracted). ''' fname = '' recurse = False original_dir = os.getcwd() rules = self.match(description) file_path = os.path.realpath(file_name) # No extraction rules for this file if not rules: return (None, None, False) else: binwalk.core.common.debug("Found %d matching extraction rules" % len(rules)) # Generate the output directory name where extracted files will be stored output_directory = self.build_output_directory(file_name) # Extract to end of file if no size was specified if not size: size = file_size(file_path) - offset if os.path.isfile(file_path): os.chdir(output_directory) # Loop through each extraction rule until one succeeds for i in range(0, len(rules)): rule = rules[i] # Make sure we don't recurse into any extracted directories if instructed not to if rule['recurse'] in [True, False]: recurse = rule['recurse'] else: recurse = True # Copy out the data to disk, if we haven't already fname = self._dd(file_path, offset, size, rule['extension'], output_file_name=name) # If there was a command specified for this rule, try to execute it. # If execution fails, the next rule will be attempted. if rule['cmd']: # Note the hash of the original file; if --rm is specified and the # extraction utility modifies the original file rather than creating # a new one (AFAIK none currently do, but could happen in the future), # we don't want to remove this file. if self.remove_after_execute: fname_md5 = file_md5(fname) # Execute the specified command against the extracted file if self.run_extractors: extract_ok = self.execute(rule['cmd'], fname, rule['codes']) else: extract_ok = True # Only clean up files if remove_after_execute was specified if extract_ok == True and self.remove_after_execute: # Remove the original file that we extracted, # if it has not been modified by the extractor. try: if file_md5(fname) == fname_md5: os.unlink(fname) except KeyboardInterrupt as e: raise e except Exception as e: pass # If the command executed OK, don't try any more rules if extract_ok == True: break # Else, remove the extracted file if this isn't the last rule in the list. # If it is the last rule, leave the file on disk for the user to examine. elif i != (len(rules)-1): try: os.unlink(fname) except KeyboardInterrupt as e: raise e except Exception as e: pass # If there was no command to execute, just use the first rule else: break os.chdir(original_dir) return (output_directory, fname, recurse)
def extract(self, offset, description, file_name, size, name=None): ''' Extract an embedded file from the target file, if it matches an extract rule. Called automatically by Binwalk.scan(). @offset - Offset inside the target file to begin the extraction. @description - Description of the embedded file to extract, as returned by libmagic. @file_name - Path to the target file. @size - Number of bytes to extract. @name - Name to save the file as. Returns the name of the extracted file (blank string if nothing was extracted). ''' fname = '' recurse = False original_dir = os.getcwd() rules = self.match(description) file_path = os.path.realpath(file_name) # No extraction rules for this file if not rules: return (None, None, False) else: binwalk.core.common.debug("Found %d matching extraction rules" % len(rules)) # Generate the output directory name where extracted files will be stored output_directory = self.build_output_directory(file_name) # Extract to end of file if no size was specified if not size: size = file_size(file_path) - offset if os.path.isfile(file_path): os.chdir(output_directory) # Loop through each extraction rule until one succeeds for i in range(0, len(rules)): rule = rules[i] # Make sure we don't recurse into any extracted directories if instructed not to if rule['recurse'] in [True, False]: recurse = rule['recurse'] else: recurse = True # Copy out the data to disk, if we haven't already fname = self._dd(file_path, offset, size, rule['extension'], output_file_name=name) # If there was a command specified for this rule, try to execute it. # If execution fails, the next rule will be attempted. if rule['cmd']: # Note the hash of the original file; if --rm is specified and the # extraction utility modifies the original file rather than creating # a new one (AFAIK none currently do, but could happen in the future), # we don't want to remove this file. if self.remove_after_execute: fname_md5 = file_md5(fname) # Execute the specified command against the extracted file if self.run_extractors: extract_ok = self.execute(rule['cmd'], fname, rule['codes']) else: extract_ok = True # Only clean up files if remove_after_execute was specified if extract_ok == True and self.remove_after_execute: # Remove the original file that we extracted, # if it has not been modified by the extractor. try: if file_md5(fname) == fname_md5: os.unlink(fname) except KeyboardInterrupt as e: raise e except Exception as e: pass # If the command executed OK, don't try any more rules if extract_ok == True: break # Else, remove the extracted file if this isn't the last rule in the list. # If it is the last rule, leave the file on disk for the user to examine. elif i != (len(rules)-1): try: os.unlink(fname) except KeyboardInterrupt as e: raise e except Exception as e: pass # If there was no command to execute, just use the first rule else: break os.chdir(original_dir) return (output_directory, fname, recurse)