예제 #1
0
class SimpleYaraScan(YaraScanMixin, plugin.TypedProfileCommand,
                     plugin.PhysicalASMixin, plugin.ProfileCommand):
    """A Simple plugin which only yarascans the physical Address Space.

    This plugin should not trigger profile autodetection and therefore should be
    usable on any file at all.
    """

    name = "simple_yarascan"
    __args = [
        plugin.CommandOption("start",
                             default=0,
                             type="IntParser",
                             help="Start searching from this offset."),
        plugin.CommandOption("limit",
                             default=2**64,
                             type="IntParser",
                             help="The length of data to search."),
    ]

    table_header = [
        dict(name="Rule", width=10),
        dict(name="Match", hidden=True),
        dict(name="Offset", style="address"),
        dict(name="hexdump", hex_width=16, width=67),
    ]

    PROFILE_REQUIRED = False

    def collect(self):
        """Render output."""
        count = 0
        address_space = self.session.physical_address_space
        for buffer_as in scan.BufferASGenerator(
                self.session, address_space, self.plugin_args.start,
                self.plugin_args.start + self.plugin_args.limit):
            self.session.report_progress(
                "Scanning buffer %#x->%#x (%#x)", buffer_as.base_offset,
                buffer_as.end(),
                buffer_as.end() - buffer_as.base_offset)

            for match in self.rules.match(data=buffer_as.data):
                for buffer_offset, _, _ in match.strings:
                    hit_offset = buffer_offset + buffer_as.base_offset
                    count += 1
                    if count >= self.plugin_args.hits:
                        break

                    yield dict(
                        Match=match,
                        Rule=match.rule,
                        Offset=hit_offset,
                        hexdump=utils.HexDumpedString(
                            self.session.physical_address_space.read(
                                hit_offset - self.plugin_args.pre_context,
                                self.plugin_args.context +
                                self.plugin_args.pre_context)))
예제 #2
0
class SimpleYaraScan(YaraScanMixin, plugin.TypedProfileCommand,
                     plugin.PhysicalASMixin, plugin.ProfileCommand):
    """A Simple plugin which only yarascans the physical Address Space.

    This plugin should not trigger profile autodetection and therefore should be
    usable on any file at all.
    """

    name = "simple_yarascan"
    __args = [
        plugin.CommandOption("start",
                             default=0,
                             type="IntParser",
                             help="Start searching from this offset."),
        plugin.CommandOption("limit",
                             default=2**64,
                             type="IntParser",
                             help="The length of data to search."),
    ]

    table_header = plugin.PluginHeader(
        dict(name="Rule", width=10),
        dict(name="Offset", style="address"),
        dict(name="HexDump", cname="hexdump", hex_width=16, width=67),
    )

    PROFILE_REQUIRED = False

    def collect(self):
        """Render output."""
        count = 0
        scanner = BaseYaraASScanner(
            session=self.session,
            address_space=self.session.physical_address_space,
            rules=self.rules)

        for rule, address, _, _ in scanner.scan(offset=self.plugin_args.start,
                                                maxlen=self.plugin_args.limit):
            count += 1
            if count >= self.plugin_args.hits:
                break

            yield (rule, address,
                   utils.HexDumpedString(
                       self.session.physical_address_space.read(
                           address - self.plugin_args.pre_context,
                           self.plugin_args.context +
                           self.plugin_args.pre_context)))
예제 #3
0
    def get_plugin_args(self, cls):
        """Collects the args from the plugin."""
        args = yaml_utils.OrderedYamlDict()
        for subclass in cls.__mro__:
            for definition in getattr(cls, "_%s__args" % cls.__name__, []):
                # Definitions can be just simple dicts.
                if isinstance(definition, dict):
                    definition = plugin.CommandOption(**definition)

                # We have seen this arg before.
                previous_definition = args.get(definition.name)
                if previous_definition:
                    # Since we traverse the definition in reverse MRO order,
                    # later definitions should be masked by earlier (more
                    # derived) definitions.
                    continue

                args[definition.name] = self.get_command_dict(definition)

        return args
예제 #4
0
class YaraScanMixin(object):
    """A common implementation of yara scanner.

    This should be mixed with the OS specific Scanner (e.g. WinScanner) and
    plugin.TypedProfileCommand.
    """

    name = "yarascan"

    table_header = plugin.PluginHeader(
        dict(name="Owner", width=20),
        dict(name="Rule", width=10),
        dict(name="Offset", style="address"),
        dict(name="HexDump", style="hexdump", hex_width=16),
        dict(name="Context"),
    )

    __args = [
        plugin.CommandOption("hits", default=10, type="IntParser",
                             help="Quit after finding this many hits."),

        plugin.CommandOption("string", default=None,
                             help="A verbatim string to search for."),

        plugin.CommandOption("binary_string", default=None,
                             help="A binary string (encoded as hex) to search "
                             "for. e.g. 000102[1-200]0506"),

        plugin.CommandOption("yara_file", default=None,
                             help="The yara signature file to read."),

        plugin.CommandOption("yara_expression", default=None,
                             help="If provided we scan for this yara "
                             "expression."),

        plugin.CommandOption("context", default=0x40, type="IntParser",
                             help="Context to print after the hit."),

        plugin.CommandOption("pre_context", default=0, type="IntParser",
                             help="Context to print before the hit."),

    ]

    scanner_defaults = dict(
        scan_physical=True
    )

    def __init__(self, *args, **kwargs):
        """Scan using yara signatures."""
        super(YaraScanMixin, self).__init__(*args, **kwargs)

        # Compile the yara rules in advance.
        if self.plugin_args.yara_expression:
            self.rules_source = self.plugin_args.yara_expression
            self.rules = yara.compile(source=self.rules_source)

        elif self.plugin_args.binary_string:
            self.compile_rule(
                'rule r1 {strings: $a = {%s} condition: $a}' %
                self.plugin_args.binary_string)

        elif self.plugin_args.string:
            self.compile_rule(
                'rule r1 {strings: $a = "%s" condition: $a}' %
                self.plugin_args.string)

        elif self.plugin_args.yara_file:
            self.compile_rule(open(self.plugin_args.yara_file).read())

        elif not self.ignore_required:
            raise plugin.PluginError("You must specify a yara rule file or "
                                     "string to match.")

    def compile_rule(self, rule):
        self.rules_source = rule
        try:
            self.rules = yara.compile(source=rule)
        except Exception as e:
            raise plugin.PluginError(
                "Failed to compile yara expression: %s" % e)

    def generate_hits(self, run):
        scanner = BaseYaraASScanner(
            session=self.session,
            address_space=run.address_space,
            rules=self.rules)

        for hit in scanner.scan(offset=run.start, maxlen=run.length):
            yield hit

    def collect(self):
        """Render output."""
        count = 0
        for run in self.generate_memory_ranges():
            for rule, address, _, _ in self.generate_hits(run):
                count += 1
                if count >= self.plugin_args.hits:
                    break

                # Result hit the physical memory - Get some context on this hit.
                if run.data.get("type") == "PhysicalAS":
                    rammap_plugin = self.session.plugins.rammap(
                        start=address, end=address+1)
                    symbol = rammap_plugin.summary()[0]
                else:
                    symbol = self.session.address_resolver.format_address(
                        address)

                yield (run.data.get("task") or run.data.get("type"),
                       rule, address,
                       utils.HexDumpedString(
                           run.address_space.read(
                               address - self.plugin_args.pre_context,
                               self.plugin_args.context +
                               self.plugin_args.pre_context)),
                       symbol)