def __init__(self, vivisect_workspace): viv_utils.LoggingObject.__init__(self) self.vivisect_workspace = vivisect_workspace self.emu = makeEmulator(vivisect_workspace) self.driver = viv_utils.emulator_drivers.FunctionRunnerEmulatorDriver( self.emu) self.index = viv_utils.InstructionFunctionIndex(vivisect_workspace)
def decode_strings(vw, decoding_functions_candidates, min_length, no_filter=False): """ FLOSS string decoding algorithm :param vw: vivisect workspace :param decoding_functions_candidates: identification manager :param min_length: minimum string length :param no_filter: do not filter decoded strings :return: list of decoded strings ([DecodedString]) """ decoded_strings = [] function_index = viv_utils.InstructionFunctionIndex(vw) # TODO pass function list instead of identification manager for fva, _ in decoding_functions_candidates.get_top_candidate_functions( 10): for ctx in string_decoder.extract_decoding_contexts(vw, fva): for delta in string_decoder.emulate_decoding_routine( vw, function_index, fva, ctx): for delta_bytes in string_decoder.extract_delta_bytes( delta, ctx.decoded_at_va, fva): for decoded_string in string_decoder.extract_strings( delta_bytes, min_length, no_filter): decoded_strings.append(decoded_string) return decoded_strings
def main(): # default to INFO, unless otherwise changed logging.basicConfig(level=logging.WARNING) parser = make_parser() options, args = parser.parse_args() set_logging_level(options.debug, options.verbose) if options.list_plugins: print_plugin_list() sys.exit(0) sample_file_path = parse_sample_file_path(parser, args) min_length = parse_min_length_option(options.min_length) if options.all_strings: floss_logger.info("Extracting static strings...") print_all_strings(sample_file_path, min_length=min_length, quiet=options.quiet) with open(sample_file_path, "rb") as f: magic = f.read(2) if magic != "MZ": floss_logger.error("FLOSS currently supports the following formats: PE") return floss_logger.info("Generating vivisect workspace") vw = viv_utils.getWorkspace(sample_file_path) selected_functions = select_functions(vw, options.functions) floss_logger.debug("Selected the following functions: %s", ", ".join(map(hex, selected_functions))) selected_plugin_names = select_plugins(options.plugins) floss_logger.debug("Selected the following plugins: %s", ", ".join(map(str, selected_plugin_names))) selected_plugins = filter(lambda p: str(p) in selected_plugin_names, get_all_plugins()) time0 = time() floss_logger.info("Identifying decoding functions...") decoding_functions_candidates = im.identify_decoding_functions(vw, selected_plugins, selected_functions) if not options.quiet: print_identification_results(sample_file_path, decoding_functions_candidates) floss_logger.info("Decoding strings...") function_index = viv_utils.InstructionFunctionIndex(vw) decoded_strings = decode_strings(vw, function_index, decoding_functions_candidates) print_decoding_results(decoded_strings, min_length, options.group_functions, quiet=options.quiet) floss_logger.info("Extracting stackstrings...") print_stack_strings(stackstrings.extract_stackstrings(vw, selected_functions), min_length, quiet=options.quiet) if options.ida_python_file: floss_logger.info("Creating IDA script...") create_script(sample_file_path, options.ida_python_file, decoded_strings) time1 = time() if not options.quiet: print("Finished execution after %f seconds" % (time1 - time0))
def __init__(self, sample_file_path): viv_utils.LoggingObject.__init__(self) self.vivisect_workspace = viv_utils.getWorkspace(sample_file_path) self.function_index = viv_utils.InstructionFunctionIndex( self.vivisect_workspace) # TODO do we need a set for the decoded strings? self.decoded_strings = set([])
def extract_strings(sample_path): """ Deobfuscate strings from sample_path """ vw = viv_utils.getWorkspace(sample_path) function_index = viv_utils.InstructionFunctionIndex(vw) decoding_functions_candidates = identify_decoding_functions(vw) decoded_strings = floss_main.decode_strings(vw, function_index, decoding_functions_candidates) selected_functions = floss_main.select_functions(vw, None) decoded_stackstrings = stackstrings.extract_stackstrings(vw, selected_functions) decoded_strings.extend(decoded_stackstrings) return [ds.s for ds in decoded_strings]
def search(): """ Attempts to find potential device names in the currently opened binary, it starts by searching for unicode device names, if this fails then it utilises FLOSS to search for stack based and obsfucated strings. """ if not find_unicode_device_name(): print "Unicode device name not found, attempting to find obsfucated and stack based strings." try: import floss import floss.identification_manager import floss.main import floss.stackstrings import viv_utils except: print "Please install FLOSS to continue, see: https://github.com/fireeye/flare-floss/" sample_file_path = idc.GetInputFile() try: vw = viv_utils.getWorkspace(sample_file_path, should_save=False) except Exception, e: print("Vivisect failed to load the input file: {0}".format( e.message)) return functions = set(vw.getFunctions()) plugins = floss.main.get_all_plugins() device_names = set() stack_strings = floss.stackstrings.extract_stackstrings(vw, functions) for i in stack_strings: device_names.add(i) dec_func_candidates = floss.identification_manager.identify_decoding_functions( vw, plugins, functions) func_index = viv_utils.InstructionFunctionIndex(vw) decoded_strings = floss.main.decode_strings(vw, func_index, dec_func_candidates) if len(decoded_strings) > 0: for i in decoded_strings: device_names.add(str(i.s)) print "Potential device names from obsfucated or stack strings:" for i in device_names: print i else: print "No obsfucated or stack strings found :("
def _main(bin_path, ofva): fva = int(ofva, 0x10) logging.basicConfig(level=logging.DEBUG) vw = viv_utils.getWorkspace(bin_path) index = viv_utils.InstructionFunctionIndex(vw) # optimization: avoid re-processing the same function repeatedly called_fvas = set([]) for callerva in vw.getCallers(fva): callerfva = index[ callerva] # the address of the function that contains this instruction if callerfva in called_fvas: continue emulate_function(vw, index[callerva], fva) called_fvas.add(callerfva) return
def floss_decode_strings(self, vw, decoders, min_length=4, no_filter=False, max_insn=2000, max_hits=1): decoded_strings = [] function_index = viv_utils.InstructionFunctionIndex(vw) for fva in decoders: for ctx in floss.string_decoder.extract_decoding_contexts( vw, fva, max_hits): for delta in floss.string_decoder.emulate_decoding_routine( vw, function_index, fva, ctx, max_insn): for delta_bytes in floss.string_decoder.extract_delta_bytes( delta, ctx.decoded_at_va, fva): for decoded_string in floss.string_decoder.extract_strings( delta_bytes, min_length, no_filter): decoded_strings.append(decoded_string) return decoded_strings
", ".join(map(str, selected_plugin_names))) selected_plugins = filter(lambda p: str(p) in selected_plugin_names, get_all_plugins()) time0 = time() if not options.no_decoded_strings: floss_logger.info("Identifying decoding functions...") decoding_functions_candidates = im.identify_decoding_functions( vw, selected_plugins, selected_functions) if options.expert: print_identification_results(sample_file_path, decoding_functions_candidates) floss_logger.info("Decoding strings...") function_index = viv_utils.InstructionFunctionIndex(vw) decoded_strings = decode_strings(vw, function_index, decoding_functions_candidates) if not options.expert: decoded_strings = filter_unique_decoded(decoded_strings) print_decoding_results(decoded_strings, min_length, options.group_functions, quiet=options.quiet, expert=options.expert) else: decoded_strings = [] if not options.no_stack_strings: floss_logger.info("Extracting stackstrings...") stack_strings = stackstrings.extract_stackstrings(
def decode_strings( vw: VivWorkspace, functions: List[int], min_length: int, max_insn_count: int = DS_MAX_INSN_COUNT, max_hits: int = DS_MAX_ADDRESS_REVISITS_CTX_EXTRACTION, verbosity: int = floss.render.default.Verbosity.DEFAULT, disable_progress: bool = False, ) -> List[DecodedString]: """ FLOSS string decoding algorithm arguments: vw: the workspace functions: addresses of the candidate decoding routines min_length: minimum string length max_insn_count: max number of instructions to emulate per function max_hits: max number of emulations per instruction verbosity: verbosity level disable_progress: no progress bar """ logger.info("decoding strings") decoded_strings = list() function_index = viv_utils.InstructionFunctionIndex(vw) pb = floss.utils.get_progress_bar(functions, disable_progress, desc="decoding strings", unit=" functions") with tqdm.contrib.logging.logging_redirect_tqdm( ), floss.utils.redirecting_print_to_tqdm(): for fva in pb: seen: Set[str] = set() ctxs = extract_decoding_contexts(vw, fva, function_index) n_calls = len(ctxs) for n, ctx in enumerate(ctxs, 1): if isinstance(pb, tqdm.tqdm): pb.set_description( f"emulating function 0x{fva:x} (call {n}/{n_calls})") if should_shortcut(fva, n, n_calls, len(seen)): break for delta in emulate_decoding_routine(vw, function_index, fva, ctx, max_insn_count): for delta_bytes in extract_delta_bytes( delta, ctx.decoded_at_va, fva): for s in floss.utils.extract_strings( delta_bytes.bytes, min_length, seen): ds = DecodedString( delta_bytes.address + s.offset, delta_bytes.address_type, s.string, s.encoding, delta_bytes.decoded_at, delta_bytes.decoding_routine, ) floss.results.log_result(ds, verbosity) seen.add(ds.string) decoded_strings.append(ds) return decoded_strings
def main(argv=None): """ :param argv: optional command line arguments, like sys.argv[1:] :return: 0 on success, non-zero on failure """ logging.basicConfig(level=logging.WARNING) parser = make_parser() if argv is not None: options, args = parser.parse_args(argv[1:]) else: options, args = parser.parse_args() set_logging_level(options.debug, options.verbose) if options.list_plugins: print_plugin_list() return 0 sample_file_path = parse_sample_file_path(parser, args) min_length = parse_min_length_option(options.min_length) # expert profile settings if options.expert: options.save_workspace = True options.group_functions = True options.quiet = False if not is_workspace_file(sample_file_path): if not options.no_static_strings and not options.functions: floss_logger.info("Extracting static strings...") print_static_strings(sample_file_path, min_length=min_length, quiet=options.quiet) if options.no_decoded_strings and options.no_stack_strings and not options.should_show_metainfo: # we are done return 0 if os.path.getsize(sample_file_path) > MAX_FILE_SIZE: floss_logger.error("FLOSS cannot extract obfuscated strings or stackstrings from files larger than" " %d bytes" % MAX_FILE_SIZE) return 1 try: vw = load_vw(sample_file_path, options.save_workspace, options.verbose, options.is_shellcode, options.shellcode_entry_point, options.shellcode_base) except WorkspaceLoadError: return 1 try: selected_functions = select_functions(vw, options.functions) except Exception as e: floss_logger.error(str(e)) return 1 floss_logger.debug("Selected the following functions: %s", get_str_from_func_list(selected_functions)) selected_plugin_names = select_plugins(options.plugins) floss_logger.debug("Selected the following plugins: %s", ", ".join(map(str, selected_plugin_names))) selected_plugins = filter(lambda p: str(p) in selected_plugin_names, get_all_plugins()) if options.should_show_metainfo: meta_functions = None if options.functions: meta_functions = selected_functions print_file_meta_info(vw, meta_functions) time0 = time() if not options.no_decoded_strings: floss_logger.info("Identifying decoding functions...") decoding_functions_candidates = im.identify_decoding_functions(vw, selected_plugins, selected_functions) if options.expert: print_identification_results(sample_file_path, decoding_functions_candidates) floss_logger.info("Decoding strings...") function_index = viv_utils.InstructionFunctionIndex(vw) decoded_strings = decode_strings(vw, function_index, decoding_functions_candidates) if not options.expert: decoded_strings = filter_unique_decoded(decoded_strings) print_decoding_results(decoded_strings, min_length, options.group_functions, quiet=options.quiet, expert=options.expert) else: decoded_strings = [] if not options.no_stack_strings: floss_logger.info("Extracting stackstrings...") stack_strings = stackstrings.extract_stackstrings(vw, selected_functions) if not options.expert: stack_strings = list(set(stack_strings)) print_stack_strings(stack_strings, min_length, quiet=options.quiet, expert=options.expert) else: stack_strings = [] if options.x64dbg_database_file: imagebase = vw.filemeta.values()[0]['imagebase'] floss_logger.info("Creating x64dbg database...") create_x64dbg_database(sample_file_path, options.x64dbg_database_file, imagebase, decoded_strings) if options.ida_python_file: floss_logger.info("Creating IDA script...") create_ida_script(sample_file_path, options.ida_python_file, decoded_strings, stack_strings) if options.radare2_script_file: floss_logger.info("Creating r2script...") create_r2_script(sample_file_path, options.radare2_script_file, decoded_strings, stack_strings) time1 = time() if not options.quiet: print("\nFinished execution after %f seconds" % (time1 - time0)) return 0