this will give you a basic how-to instantantiate your plugin, which will receive the qt main application as object. this object allows you to alter, create ui elements and to access dwarf core (for speak with frida).
Your best environment to create and debug a plugin will be an IDE with Dwarf project opened (so you have api references and completition). You will then create the plugins folder in dwarf path (if not existing), and creare a directory with the plugin name
dwarf_path/plugins/my_plugin/
create a file called plugin.py (this is mandatory)
dwarf_path/plugins/my_plugin/plugin.py
then you have to instantiate the main class for your plugin, which must be named "Plugin".
you than have to define the __get_plugin_info__
method and declare 2 special methods
class Plugin:
def __get_plugin_info__(self):
return {
'name': 'my plugin',
'description': 'my plugin description',
'version': '1.0.0',
'author': 'my name',
'homepage': 'https://github.com/repo',
'license': 'https://www.gnu.org/licenses/gpl-3.0',
}
def __get_top_menu_actions__(self):
pass
def __get_agent__(self):
pass
def __init__(self, app):
self.app = app
that's it.
for reference, I'm posting r2dwarf code as an example, you can checkout the full impl here
class Plugin:
def __get_plugin_info__(self):
return {
'name': 'r2dwarf',
'description': 'r2frida in Dwarf',
'version': '1.0.0',
'author': 'iGio90',
'homepage': 'https://github.com/iGio90/Dwarf',
'license': 'https://www.gnu.org/licenses/gpl-3.0',
}
def __get_top_menu_actions__(self):
if len(self.menu_items) > 0:
return self.menu_items
options = QAction('Options')
options.triggered.connect(lambda: OptionsDialog.show_dialog(self._prefs))
self.menu_items.append(options)
return self.menu_items
def __get_agent__(self):
self.app.dwarf.onReceiveCmd.connect(self._on_receive_cmd)
# we create the first pipe here to be safe that the r2 agent is loaded before the first breakpoint
# i.e if we start dwarf targetting a package from args and a script breaking at first open
# dwarf will hang because r2frida try to load it's agent and frida turn to use some api uth which are
# not usable before the breakpoint quit
# __get_agent__ is request just after our agent load and it solved all the things
# still not the best solution as if the pipe got broken for some reason and we re-attempt to create it
# while we are in a bkp we will face the same shit
self._create_pipe()
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'agent.js'), 'r') as f:
return f.read()
def __init__(self, app):
self.app = app
# block the creation of pipe on fatal errors
self.pipe_locker = False
self._prefs = Prefs()
self.pipe = None
self.current_seek = ''
self.with_r2dec = False
self._working = False
self.r2_widget = None
self.menu_items = []
self.app.session_manager.sessionCreated.connect(self._on_session_created)
self.app.session_manager.sessionStopped.connect(self._on_session_stopped)
self.app.onUIElementCreated.connect(self._on_ui_element_created)