Esempio n. 1
0
    def unload(self):
        """
        Unload the plugin, and remove any UI integrations.
        """

        # if the core was never fully loaded, there's nothing else to do
        if not self.loaded:
            return

        pmsg("Unloading %s..." % self.PLUGIN_NAME)

        # mark the core as 'unloaded' and teardown its components
        self.loaded = False

        # remove UI integrations
        self._uninstall_ui()

        # spin down any active contexts (stop threads, cleanup qt state, etc)
        for pctx in self.contexts.values():
            pctx.terminate()
        self.contexts = {}

        # all done
        logger.info("-" * 75)
        logger.info("Plugin terminated")
Esempio n. 2
0
    def interactive_final_execution(self):
        """
        Handle UI actions for seeking to the final execution of the selected address.
        """
        address = disassembler[self].get_current_address()
        result = self.reader.seek_to_final(address, BreakpointType.EXEC)

        # TODO: blink screen? make failure more visible...
        if not result:
            pmsg(f"Go to 0x{address:08x} failed, no executions of address")
Esempio n. 3
0
    def _load_theme(self, filepath):
        """
        Load and apply the plugin theme at the given filepath.
        """

        # attempt to read json theme from disk
        try:
            theme = self._read_theme(filepath)

        # reading file from dsik failed
        except OSError:
            pmsg("Could not open theme file at '%s'" % filepath)
            return False

        # JSON decoding failed
        except JSONDecodeError as e:
            pmsg("Failed to decode theme '%s' to json" % filepath)
            pmsg(" - " + str(e))
            return False

        # do some basic sanity checking on the given theme file
        if not self._validate_theme(theme):
            return False

        # try applying the loaded theme to the plugin
        try:
            self._apply_theme(theme)
        except Exception as e:
            pmsg("Failed to load the plugin user theme\n%s" % e)
            return False

        # return success
        self._notify_theme_changed()
        return True
Esempio n. 4
0
    def warmup(self):
        """
        Warms up the theming system prior to initial use.
        """
        if self._initialized:
            return

        logger.debug("Warming up theme subsystem...")

        #
        # attempt to load the user's preferred (or hinted) theme. if we are
        # successful, then there's nothing else to do!
        #

        self._refresh_theme_hints()
        if self._load_preferred_theme():
            self._initialized = True
            logger.debug(" - warmup complete, using preferred theme!")
            return

        #
        # failed to load the preferred theme... so delete the 'active'
        # file (if there is one) and warn the user before falling back
        #

        try:
            os.remove(os.path.join(self.get_user_theme_dir(), ".active_theme"))
        except:
            pass

        disassembler.warning(
            "Failed to load plugin user theme!\n\n"
            "Please check the console for more information..."
        )

        #
        # if no theme is loaded, we will attempt to detect & load the in-box
        # themes based on the user's disassembler theme
        #

        loaded = self._load_preferred_theme(fallback=True)
        if not loaded:
            pmsg("Could not load plugin fallback theme!") # this is a bad place to be...
            return

        logger.debug(" - warmup complete, using hint-recommended theme!")
        self._initialized = True
Esempio n. 5
0
    def _validate_theme(self, theme):
        """
        Pefrom rudimentary theme validation.
        """
        logger.debug(" - Validating theme fields for '%s'..." % theme["name"])
        user_fields = theme.get("fields", None)
        if not user_fields:
            pmsg("Could not find theme 'fields' definition")
            return False

        # check that all the 'required' fields exist in the given theme
        for field in self._required_fields:
            if field not in user_fields:
                pmsg("Could not find required theme field '%s'" % field)
                return False

        # theme looks good enough for now...
        return True
Esempio n. 6
0
    def load_trace(self, filepath):
        """
        Load a trace from the given filepath.

        If there is a trace already loaded / in-use prior to calling this
        function, it will simply be replaced by the new trace.
        """

        #
        # create the trace reader. this will load the given trace file from
        # disk and wrap it with a number of useful APIs for navigating the
        # trace and querying information (memory, registers) from it at
        # chosen states of execution
        #

        self.reader = TraceReader(filepath, self.arch, disassembler[self])
        pmsg(f"Loaded trace of {self.reader.trace.length:,} instructions...")

        #
        # we only hook directly into the disassembler / UI / subsytems once
        # a trace is loaded. this ensures that our python handlers don't
        # introduce overhead on misc disassembler callbacks when the plugin
        # isn't even being used in the reversing session.
        #

        self.core.hook()

        #
        # attach the trace engine to the various plugin UI controllers, giving
        # them the necessary access to drive the underlying trace reader
        #

        self.breakpoints.reset()
        self.trace.attach_reader(self.reader)
        self.stack.attach_reader(self.reader)
        self.memory.attach_reader(self.reader)
        self.registers.attach_reader(self.reader)

        #
        # connect any high level signals from the new trace reader
        #

        self.reader.idx_changed(self._idx_changed)
Esempio n. 7
0
    def interactive_load_trace(self, reloading=False):
        """
        Handle UI actions for loading a trace file.
        """

        # prompt the user with a file dialog to select a trace of interest
        filenames = self._select_trace_file()
        if not filenames:
            return

        # TODO: ehh, only support loading one trace at a time right now
        assert len(filenames) == 1, "Please select only one trace file to load"
        disassembler.show_wait_box("Loading trace from disk...")
        filepath = filenames[0]

        # attempt to load the user selected trace
        try:
            self.load_trace(filepath)
        except:
            pmsg("Failed to load trace...")
            pmsg(traceback.format_exc())
            disassembler.hide_wait_box()
            return
        disassembler.hide_wait_box()

        #
        # if we are 're-loading', we are loading over an existing trace, so
        # there should already be plugin UI elements visible and active.
        #
        # do not attempt to show / re-position the UI elements as they may
        # have been moved by the user from their default positions into
        # locations that they prefer
        #

        if reloading:
            return

        # show the plugin UI elements, and dock its windows as appropriate
        self.show_ui()
Esempio n. 8
0
    def load(self):
        """
        Load the plugin, and register universal UI actions with the disassembler.
        """
        self.contexts = {}
        self._update_checked = False

        # print plugin banner
        pmsg(
            f"Loading {self.PLUGIN_NAME} v{self.PLUGIN_VERSION} - (c) {self.PLUGIN_AUTHORS} - {self.PLUGIN_DATE}"
        )

        # the plugin color palette
        self.palette = PluginPalette()
        self.palette.theme_changed(self.refresh_theme)

        # integrate plugin UI to disassembler
        self._install_ui()

        # all done, mark the core as loaded
        logger.info("Successfully loaded plugin")
        self.loaded = True