예제 #1
0
def extract_strings(vw):
    """
    Deobfuscate strings from vivisect workspace
    """
    decoding_functions_candidates = identify_decoding_functions(vw)
    decoded_strings = floss_main.decode_strings(vw, decoding_functions_candidates, 4)
    selected_functions = floss_main.select_functions(vw, None)
    decoded_stackstrings = stackstrings.extract_stackstrings(vw, selected_functions, 4)
    decoded_strings.extend(decoded_stackstrings)
    return [ds.s for ds in decoded_strings]
예제 #2
0
def extract_strings(vw):
    """
    Deobfuscate strings from vivisect workspace
    """
    decoding_functions_candidates = identify_decoding_functions(vw)
    decoded_strings = floss_main.decode_strings(vw, decoding_functions_candidates, 4)
    selected_functions = floss_main.select_functions(vw, None)
    decoded_stackstrings = stackstrings.extract_stackstrings(vw, selected_functions, 4)
    decoded_strings.extend(decoded_stackstrings)
    return [ds.s for ds in decoded_strings]
예제 #3
0
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)
    decoded_stackstrings = stackstrings.extract_stackstrings(vw)
    decoded_strings.extend(decoded_stackstrings)
    return [ds.s for ds in decoded_strings]
예제 #4
0
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]
예제 #5
0
    def each(self, target):
        self.results = {
            'warnings': [],
            'static_strings': [],
            'decoded_strings': [],
            'stack_strings': []
        }

        try:
            data = open(target, "r").read(MAX_FILESIZE)
        except (IOError, OSError) as e:
            self.log('error', 'Cannot open file {}'.format(target))
            self.results = None
            return False

        # Load list of IOC's
        try:
            with open(self.interesting_strings_file) as f:
                self.interesting_strings = f.read().splitlines()
            self.log(
                'info', 'Loaded interesting strings from {}'.format(
                    self.interesting_strings_file))
        except:
            # No IOC file, create an empty list
            self.log('info', 'No file with interesting strings defined')
            self.interesting_strings = []

        # Load list of ignored strings
        try:
            with open(self.ignored_strings_file) as f:
                self.ignored_strings = f.read().splitlines()
            self.log(
                'info', 'Loaded ignored strings from {}'.format(
                    self.ignored_strings_file))
        except:
            # No IOC file, create an empty list
            self.log('info', 'No file with ignored strings defined')
            self.ignored_strings = []

        # Extract static strings
        static_strings = re.findall(
            "[\x1f-\x7e]{" + str(self.minimum_string_len) + ",}", data)
        for s in re.findall(
                "(?:[\x1f-\x7e][\x00]){" + str(self.minimum_string_len) + ",}",
                data):
            static_strings.append(s.decode("utf-16le"))

        if self.maximum_string_len != 0:
            for i, s in enumerate(static_strings):
                static_strings[i] = s[:self.maximum_string_len]

        if self.maximum_strings != 0 and len(
                static_strings) > self.maximum_strings:
            self.log(
                'warning', 'Maximum number of strings reached ({})'.format(
                    str(self.maximum_strings)))
            static_strings = static_strings[:self.maximum_strings]
            static_strings.append("[snip]")

        try:
            # Prepare Floss for extracting hidden & encoded strings
            vw = vivisect.VivWorkspace()
            vw.loadFromFile(target)
            vw.analyze()

            selected_functions = main.select_functions(vw, None)
            decoding_functions_candidates = id_man.identify_decoding_functions(
                vw, main.get_all_plugins(), selected_functions)
        except Exception as e:
            self.log('error', 'Cannot analyze file {}'.format(target))
            self.results = None
            return False

        # Decode & extract hidden & encoded strings
        try:
            decoded_strings = main.decode_strings(
                vw, decoding_functions_candidates, self.minimum_string_len)
            decoded_strs = main.filter_unique_decoded(decoded_strings)

            stack_strings = stackstrings.extract_stackstrings(
                vw, selected_functions, self.minimum_string_len)
            stack_strings = list(stack_strings)

            decoded_strings = [
                x for x in decoded_strs if not x in static_strings
            ]
        except Exception as e:
            self.log('error', 'Cannot extract strings from {}'.format(target))
            self.results = None
            return False

        # Populate results[] with found strings
        if len(decoded_strings) or len(stack_strings):
            self.log('info', 'Found stack or decoded strings')
            for k, s in enumerate(decoded_strings):
                buffer = main.sanitize_string_for_printing(s.s)
                skip = False
                for ignore in self.ignored_strings:
                    if str(buffer).find(ignore) >= 0:
                        skip = True
                        break
                if not skip:
                    self.results['decoded_strings'].append(buffer)
            self.search_ioc(self.results['decoded_strings'])

            for k, s in enumerate(stack_strings):
                skip = False
                for ignore in self.ignored_strings:
                    if str(s.s).find(ignore) >= 0:
                        skip = True
                        break
                if not skip:
                    self.results['stack_strings'].append(s.s)
            self.search_ioc(self.results['stack_strings'])

        # Populate results[] with static strings
        self.log('info', 'Found static strings')
        for s in static_strings:
            skip = False
            for ignore in self.ignored_strings:
                if str(s).find(ignore) >= 0:
                    skip = True
                    break
            if not skip:
                self.results['static_strings'].append(s)
        self.search_ioc(self.results['static_strings'])

        # Deduplicate warnings
        self.results['warnings'] = list(dict.fromkeys(
            self.results['warnings']))

        return True
예제 #6
0
    def run(self):
        """Run FLOSS to extract strings from sample.
        @return: dictionary of floss strings.
        """

        if not HAVE_FLOSS or processing_cfg.floss.on_demand and not self.on_demand:
            return

        results = {}

        if not os.path.exists(self.file_path):
            log.error("Sample file doesn't exist: %s", self.file_path)

        try:
            if not fm.is_supported_file_type(self.file_path):
                if self.package == "Shellcode":
                    fileformat = "sc32"
                elif self.package == "Shellcode_x64":
                    fileformat = "sc64"
                else:
                    return results
            else:
                fileformat = "pe"

            min_length = processing_cfg.floss.min_length
            fm.set_log_config(fm.DebugLevel.NONE, True)
            tmpres = {}
            results = {}

            if processing_cfg.floss.static_strings:
                with open(self.file_path, "rb") as f:
                    with contextlib.closing(
                            mmap.mmap(f.fileno(), 0,
                                      access=mmap.ACCESS_READ)) as buf:
                        tmpres["static_strings"] = list(
                            fm.extract_ascii_unicode_strings(buf, min_length))

            sigspath = fm.get_signatures(
                os.path.join(CUCKOO_ROOT, processing_cfg.floss.sigs_path))
            vw = fm.load_vw(self.file_path, fileformat, sigspath, False)

            try:
                selected_functions = fm.select_functions(vw, None)
            except ValueError as e:
                # failed to find functions in workspace
                print(e.args[0])
                return

            decoding_function_features, library_functions = fm.find_decoding_function_features(
                vw,
                selected_functions,
                True,
            )

            if processing_cfg.floss.stack_strings:
                selected_functions = fm.get_functions_without_tightloops(
                    decoding_function_features)
                tmpres["stack_strings"] = fm.extract_stackstrings(
                    vw,
                    selected_functions,
                    min_length,
                    verbosity=False,
                    disable_progress=True,
                )

            if processing_cfg.floss.tight_strings:
                tightloop_functions = fm.get_functions_with_tightloops(
                    decoding_function_features)
                tmpres["tight_strings"] = fm.extract_tightstrings(
                    vw,
                    tightloop_functions,
                    min_length=min_length,
                    verbosity=False,
                    disable_progress=True,
                )

            if processing_cfg.floss.decoded_strings:
                top_functions = fm.get_top_functions(
                    decoding_function_features, 20)
                fvas_to_emulate = fm.get_function_fvas(top_functions)
                fvas_tight_functions = fm.get_tight_function_fvas(
                    decoding_function_features)
                fvas_to_emulate = fm.append_unique(fvas_to_emulate,
                                                   fvas_tight_functions)

                tmpres["decoded_strings"] = fm.decode_strings(
                    vw,
                    fvas_to_emulate,
                    min_length,
                    verbosity=False,
                    disable_progress=True,
                )

            for stype in tmpres.keys():
                if tmpres[stype]:
                    results[stype] = []
                for sval in tmpres[stype]:
                    results[stype].append(sval.string)

        except Exception as e:
            log.error(e, exc_info=True)

        fm.set_log_config(fm.DebugLevel.DEFAULT, False)

        return results
예제 #7
0
    def run(self):
        """Run Floss on analyzed file.
        @return: Floss results dict.
        """
        self.key = "strings"
        self.floss = self.options.get("floss")
        self.MIN_STRINGLEN = int(self.options.get("min_str_len"))
        self.MAX_STRINGLEN = self.options.get("max_str_len")
        self.MAX_STRINGCNT = self.options.get("max_str_cnt")
        self.MAX_FILESIZE = 16*1024*1024
        
        STRING_TYPES = [
            "decoded",
            "stack",
            "static"
        ]
        
        strings = {}

        if self.task["category"] == "file":
            if not os.path.exists(self.file_path):
                raise CuckooProcessingError(
                    "Sample file doesn't exist: \"%s\"" % self.file_path
                )

            try:
                f = File(self.file_path)
                filename = os.path.basename(self.task["target"])
                base_name = os.path.splitext(filename)[0]
                ext = filename.split(os.path.extsep)[-1].lower()
                data = open(self.file_path, "r").read(self.MAX_FILESIZE)
            except (IOError, OSError) as e:
                raise CuckooProcessingError("Error opening file %s" % e)
            
            # Extract static strings
            static_strings = re.findall("[\x1f-\x7e]{" + str(self.MIN_STRINGLEN) + ",}", data)
            for s in re.findall("(?:[\x1f-\x7e][\x00]){" + str(self.MIN_STRINGLEN) + ",}", data):
                static_strings.append(s.decode("utf-16le"))

            if self.MAX_STRINGLEN != 0:
                for i, s in enumerate(static_strings):
                    static_strings[i] = s[:self.MAX_STRINGLEN]

            if self.MAX_STRINGCNT != 0 and len(static_strings) > self.MAX_STRINGCNT:
                static_strings = static_strings[:self.MAX_STRINGCNT]
                static_strings.append("[snip]")

            package = self.task.get("package")

            if self.floss and (package == "exe" or ext == "exe" or "PE32" in f.get_type()):
                # Disable floss verbose logging
                main.set_logging_levels()
                
                try:
                    # Prepare Floss for extracting hidden & encoded strings
                    vw = vivisect.VivWorkspace()
                    vw.loadFromFile(self.file_path)
                    vw.analyze()

                    selected_functions = main.select_functions(vw, None)
                    decoding_functions_candidates = id_man.identify_decoding_functions(
                        vw, main.get_all_plugins(), selected_functions
                    )
                except Exception as e:
                    raise CuckooProcessingError("Error analyzing file with vivisect: %s" % e)

                try:
                    # Decode & extract hidden & encoded strings
                    decoded_strings = main.decode_strings(
                        vw, decoding_functions_candidates, self.MIN_STRINGLEN
                    )
                    decoded_strs = main.filter_unique_decoded(decoded_strings)

                    stack_strings = stackstrings.extract_stackstrings(
                        vw, selected_functions, self.MIN_STRINGLEN
                    )
                    stack_strings = list(stack_strings)

                    decoded_strings = [x for x in decoded_strs if not x in static_strings]
                except Exception as e:
                    raise CuckooProcessingError("Error extracting strings with floss: %s" % e)

                if len(decoded_strings) or len(stack_strings):
                    # Create annotated scripts
                    if self.options.get("idapro_str_sct"):
                        idapro_sct_name = base_name + ".idb"
                        strings["idapro_sct_name"] = idapro_sct_name

                        main.create_ida_script(
                            self.file_path, os.path.join(self.str_script_path, idapro_sct_name), 
                            decoded_strings, stack_strings
                        )

                    if self.options.get("radare_str_sct"):
                        radare_sct_name = base_name + ".r2"
                        strings["radare_sct_name"] = radare_sct_name

                        main.create_r2_script(
                            self.file_path, os.path.join(self.str_script_path, radare_sct_name), 
                            decoded_strings, stack_strings
                        )

                    if self.options.get("x64dbg_str_sct"):
                        x64dbg_sct_name = base_name + ".json"
                        strings["x64dbg_sct_name"] = x64dbg_sct_name

                        imagebase = vw.filemeta.values()[0]['imagebase']
                        main.create_x64dbg_database(
                            self.file_path, os.path.join(self.str_script_path, base_name + ".json"), 
                            imagebase, decoded_strings
                        )

                # convert Floss strings into regular, readable strings
                for idx, s in enumerate(decoded_strings):
                    decoded_strings[idx] = main.sanitize_string_for_printing(s.s)

                for idx, s in enumerate(stack_strings):
                    stack_strings[idx] = s.s

                results = [decoded_strings, stack_strings, static_strings]

                for idx, str_type in enumerate(STRING_TYPES):
                    strings[str_type] = results[idx]

            else:
                strings["static"] = static_strings

        return strings