From 353d233fdaac06a86a1f0f67dc2c7c3662eb5e35 Mon Sep 17 00:00:00 2001 From: Kevin Phoenix Date: Fri, 26 Jul 2024 13:44:31 -0700 Subject: [PATCH] Minor improvements to main_window --- angrmanagement/ui/main_window.py | 96 ++++++++------------- angrmanagement/ui/menus/analyze_menu.py | 8 +- angrmanagement/ui/menus/view_menu.py | 2 +- angrmanagement/ui/views/disassembly_view.py | 2 +- angrmanagement/ui/widgets/qccode_edit.py | 4 +- angrmanagement/ui/workspace.py | 10 ++- 6 files changed, 52 insertions(+), 70 deletions(-) diff --git a/angrmanagement/ui/main_window.py b/angrmanagement/ui/main_window.py index 13e31157a..c83296282 100644 --- a/angrmanagement/ui/main_window.py +++ b/angrmanagement/ui/main_window.py @@ -30,14 +30,12 @@ from angrmanagement.config import IMG_LOCATION, Conf, save_config from angrmanagement.daemon import daemon_conn, daemon_exists, run_daemon_process from angrmanagement.daemon.client import ClientService -from angrmanagement.data.jobs import DependencyAnalysisJob from angrmanagement.data.jobs.loading import LoadAngrDBJob, LoadBinaryJob, LoadTargetJob from angrmanagement.data.library_docs import LibraryDocs from angrmanagement.errors import InvalidURLError, UnexpectedStatusCodeError from angrmanagement.logic import GlobalInfo from angrmanagement.logic.commands import BasicCommand from angrmanagement.logic.threads import ExecuteCodeEvent -from angrmanagement.ui.views import DisassemblyView from angrmanagement.utils.env import app_root, is_pyinstaller from angrmanagement.utils.io import download_url, isurl @@ -141,6 +139,30 @@ class MainWindow(QMainWindow): The main window of angr management. """ + initialized: bool + app: QApplication | None + workspace: Workspace + dock_manager: QtAds.CDockManager + toolbar_manager: ToolbarManager + + # Status and Progress + _progress_stopwatch_start_time: float + _progress_message: str + _progress_percentage: float + _progress_update_timer: QTimer + _status_label: QLabel + _stopwatch_label: QIconLabel + _interrupt_job_button: QIconLabel + _progress_label: QLabel + _progress_bar: QProgressBar + _progress_dialog: QProgressDialog + + _file_menu: FileMenu + _analyze_menu: AnalyzeMenu + _view_menu: ViewMenu + _help_menu: HelpMenu + _plugin_menu: PluginMenu + def __init__( self, app: QApplication | None = None, parent=None, show: bool = True, use_daemon: bool = False ) -> None: @@ -157,41 +179,31 @@ def __init__( # initialization self.setMinimumSize(QSize(400, 400)) - self.app: QApplication | None = app - self.workspace: Workspace = None - self.dock_manager: QtAds.CDockManager + self.app = app self._dock_shortcut_event_filter = DockShortcutEventFilter(self) self._shift_shift_event_filter = ShiftShiftEventFilter(self) - if app: + if self.app is not None: self.app.installEventFilter(self._shift_shift_event_filter) - self.toolbar_manager: ToolbarManager = ToolbarManager(self) + self.toolbar_manager = ToolbarManager(self) - self._progress_stopwatch_start_time: float = 0.0 - self._progress_message: str = "" - self._progress_percentage: float = 0 - self._progress_update_timer: QTimer = QTimer() + self._progress_stopwatch_start_time = 0.0 + self._progress_message = "" + self._progress_percentage = 0 + self._progress_update_timer = QTimer() self._progress_update_timer.setSingleShot(False) self._progress_update_timer.setInterval(1000) self._progress_update_timer.timeout.connect(self._on_progress_update_timer_timeout) self.defaultWindowFlags = None - # menus - self._file_menu = None # FileMenu - self._analyze_menu = None - self._view_menu = None - self._help_menu = None - self._plugin_menu = None - - self._init_statusbar() self._init_workspace() + self._init_statusbar() self._init_toolbars() self._init_menus() - self._init_plugins() + self.workspace.plugins.discover_and_initialize_plugins() self._init_library_docs() - # self._init_url_scheme_handler() self._register_commands() @@ -423,13 +435,6 @@ def init_shortcuts_on_dock(self, dock_widget) -> None: """ dock_widget.installEventFilter(self._dock_shortcut_event_filter) - # - # Plugins - # - - def _init_plugins(self) -> None: - self.workspace.plugins.discover_and_initialize_plugins() - # # FLIRT Signatures # @@ -544,9 +549,9 @@ def _register_commands(self) -> None: [ BasicCommand(action.__name__, caption, action) for caption, action in [ - ("Analyze: Decompile", self.decompile_current_function), - ("Analyze: Interact", self.interact), - ("Analyze: Run Analysis...", self.run_analysis), + ("Analyze: Decompile", self.workspace.decompile_current_function), + ("Analyze: Interact", self.workspace.interact_program), + ("Analyze: Run Analysis...", self.workspace.run_analysis), ("File: Exit", self.quit), ("File: Load a new binary...", self.open_file_button), ("File: Load a new docker target...", self.open_docker_button), @@ -848,35 +853,6 @@ def preferences(self) -> None: def quit(self) -> None: self.close() - def run_variable_recovery(self) -> None: - self.workspace._get_or_create_view("disassembly", DisassemblyView).variable_recovery_flavor = "accurate" - - def run_induction_variable_analysis(self) -> None: - self.workspace._get_or_create_view("disassembly", DisassemblyView).run_induction_variable_analysis() - - def run_dependency_analysis(self, func_addr: int | None = None, func_arg_idx: int | None = None) -> None: - if self.workspace is None or self.workspace.main_instance is None: - return - dep_analysis_job = DependencyAnalysisJob( - self.workspace.main_instance, func_addr=func_addr, func_arg_idx=func_arg_idx - ) - self.workspace.job_manager.add_job(dep_analysis_job) - - def run_analysis(self) -> None: - if self.workspace: - self.workspace.run_analysis() - - def decompile_current_function(self) -> None: - if self.workspace is not None: - self.workspace.decompile_current_function() - - def view_proximity_for_current_function(self) -> None: - if self.workspace is not None: - self.workspace.view_proximity_for_current_function() - - def interact(self) -> None: - self.workspace.interact_program(self.workspace.main_instance.img_name) - def show_command_palette(self, parent=None) -> None: dlg = CommandPaletteDialog(self.workspace, parent=(parent or self)) dlg.setModal(True) diff --git a/angrmanagement/ui/menus/analyze_menu.py b/angrmanagement/ui/menus/analyze_menu.py index dd8d67de2..561b23e5f 100644 --- a/angrmanagement/ui/menus/analyze_menu.py +++ b/angrmanagement/ui/menus/analyze_menu.py @@ -20,22 +20,22 @@ def __init__(self, main_window: MainWindow) -> None: [ MenuEntry( "&Run Analysis...", - main_window.run_analysis, + main_window.workspace.run_analysis, shortcut=QKeySequence(Qt.Key.Key_F4), icon=icon("run-analysis"), ), MenuSeparator(), MenuEntry( "&Decompile", - main_window.decompile_current_function, + main_window.workspace.decompile_current_function, shortcut=QKeySequence(Qt.Key.Key_F5), icon=icon("pseudocode-view"), ), MenuEntry( "View in Proximity &Browser", - main_window.view_proximity_for_current_function, + main_window.workspace.view_proximity_for_current_function, shortcut=QKeySequence("Ctrl+B"), ), - MenuEntry("&Interact", main_window.interact, shortcut=QKeySequence(Qt.Key.Key_F6)), + MenuEntry("&Interact", main_window.workspace.interact_program, shortcut=QKeySequence(Qt.Key.Key_F6)), ], ) diff --git a/angrmanagement/ui/menus/view_menu.py b/angrmanagement/ui/menus/view_menu.py index 3b5b19e96..6a1093844 100644 --- a/angrmanagement/ui/menus/view_menu.py +++ b/angrmanagement/ui/menus/view_menu.py @@ -122,7 +122,7 @@ def __init__(self, main_window: MainWindow) -> None: ), MenuSeparator(), MenuEntry("&Hex", main_window.workspace.show_hex_view, icon=icon("hex-view")), - MenuEntry("Pro&ximity", main_window.view_proximity_for_current_function), + MenuEntry("Pro&ximity", main_window.workspace.view_proximity_for_current_function), MenuEntry("Pseudo&code", main_window.workspace.show_pseudocode_view, icon=icon("pseudocode-view")), MenuEntry("&Strings", main_window.workspace.show_strings_view, icon=icon("strings-view")), MenuEntry("&Patches", main_window.workspace.show_patches_view, icon=icon("patches-view")), diff --git a/angrmanagement/ui/views/disassembly_view.py b/angrmanagement/ui/views/disassembly_view.py index 3949c032d..a83ae05cd 100644 --- a/angrmanagement/ui/views/disassembly_view.py +++ b/angrmanagement/ui/views/disassembly_view.py @@ -542,7 +542,7 @@ def popup_dependson_dialog(self, addr: int | None = None, use_operand: bool = Fa if dependson.location is not None and dependson.arg is not None: # track function argument - self.workspace._main_window.run_dependency_analysis( + self.workspace.run_dependency_analysis( func_addr=addr, func_arg_idx=dependson.arg, ) diff --git a/angrmanagement/ui/widgets/qccode_edit.py b/angrmanagement/ui/widgets/qccode_edit.py index caf1e152e..099498653 100644 --- a/angrmanagement/ui/widgets/qccode_edit.py +++ b/angrmanagement/ui/widgets/qccode_edit.py @@ -30,7 +30,6 @@ from angrmanagement.ui.dialogs.xref import XRefDialog from angrmanagement.ui.documents.qcodedocument import QCodeDocument from angrmanagement.ui.menus.menu import Menu -from angrmanagement.ui.views.disassembly_view import DisassemblyView from angrmanagement.ui.widgets.qccode_highlighter import FORMATS, QCCodeHighlighter if TYPE_CHECKING: @@ -309,7 +308,6 @@ def xref_node(self, *args, node=None) -> None: # pylint: disable=unused-argumen if not isinstance(n, CVariable | CFunction | CFunctionCall): return - disasm_view = self._code_view.workspace._get_or_create_view("disassembly", DisassemblyView) if isinstance(n, CFunction | CFunctionCall): addr = n.addr if isinstance(n, CFunction) else n.callee_func.addr dialog = XRefDialog( @@ -324,7 +322,7 @@ def xref_node(self, *args, node=None) -> None: # pylint: disable=unused-argumen addr = self.get_closest_insaddr(n) dialog = XRefDialog( addr=addr, - variable_manager=disasm_view.variable_manager, + variable_manager=self.instance.project.kb.variables, variable=n.variable, instance=self.instance, disassembly_view=self._code_view, diff --git a/angrmanagement/ui/workspace.py b/angrmanagement/ui/workspace.py index 22ab54bed..579188e45 100644 --- a/angrmanagement/ui/workspace.py +++ b/angrmanagement/ui/workspace.py @@ -33,6 +33,7 @@ PrototypeFindingJob, VariableRecoveryJob, ) +from angrmanagement.data.jobs.dependency_analysis import DependencyAnalysisJob from angrmanagement.data.jobs.loading import LoadBinaryJob from angrmanagement.data.trace import BintraceTrace, Trace from angrmanagement.logic.commands import CommandManager @@ -607,6 +608,11 @@ def run_analysis(self, prompt_for_configuration: bool = True) -> None: self.generate_cfg(cfg_options) + def run_dependency_analysis(self, func_addr: int | None = None, func_arg_idx: int | None = None) -> None: + self.job_manager.add_job( + DependencyAnalysisJob(self.main_instance, func_addr=func_addr, func_arg_idx=func_arg_idx) + ) + def decompile_current_function(self) -> None: current = self.view_manager.current_tab if isinstance(current, CodeView): @@ -741,7 +747,9 @@ def create_project_from_trace(self, trace: Trace, on_complete: Callable) -> None job = LoadBinaryJob(self.main_instance, thing, load_options=load_options, on_finish=on_complete) self.job_manager.add_job(job) - def interact_program(self, img_name: str, view=None) -> None: + def interact_program(self, img_name: str | None = None, view=None) -> None: + if img_name is None: + img_name = self.main_instance.img_name if view is None or view.category != "interaction": view = self._get_or_create_view("interaction", InteractionView) view.initialize(img_name)