Skip to content
This repository has been archived by the owner on Feb 19, 2021. It is now read-only.

Commit

Permalink
Merge branch 'master' into auto-analysis
Browse files Browse the repository at this point in the history
  • Loading branch information
NeatMonster committed Oct 8, 2018
2 parents 73d0e85 + a9f07a2 commit d3dd6f3
Show file tree
Hide file tree
Showing 10 changed files with 310 additions and 459 deletions.
136 changes: 77 additions & 59 deletions idarling/core/core.py
Expand Up @@ -22,9 +22,17 @@

from PyQt5.QtCore import QCoreApplication, QFileInfo # noqa: I202

from .hooks import HexRaysHooks, Hooks, IDBHooks, IDPHooks, UIHooks, ViewHooks
from .hooks import HexRaysHooks, IDBHooks, IDPHooks
from ..module import Module
from ..shared.commands import JoinSession, LeaveSession, ListDatabases
from ..shared.commands import (
JoinSession,
LeaveSession,
ListDatabases,
UpdateLocation,
)

if sys.version_info > (3,):
long = int


class Core(Module):
Expand Down Expand Up @@ -57,16 +65,16 @@ def __init__(self, plugin):
self._project = None
self._database = None
self._tick = 0
self._users = {}

self._idb_hooks = None
self._idp_hooks = None
self._hxe_hooks = None
self._view_hooks = None
self._ui_hooks = None

self._ui_hooks_core = None
self._idb_hooks_core = None
self._idp_hooks_core = None
self._ui_hooks_core = None
self._view_hooks_core = None
self._hooked = False

@property
Expand Down Expand Up @@ -96,53 +104,35 @@ def tick(self, tick):
self._tick = tick
self.save_netnode()

def add_user(self, name, user):
self._users[name] = user
self._plugin.interface.painter.refresh()
self._plugin.interface.widget.refresh()

def remove_user(self, name):
user = self._users.pop(name)
self._plugin.interface.painter.refresh()
self._plugin.interface.widget.refresh()
return user

def get_user(self, name):
return self._users[name]

def get_users(self):
return self._users

def _install(self):
# Instantiate the hooks
self._idb_hooks = IDBHooks(self._plugin)
self._idp_hooks = IDPHooks(self._plugin)
self._hxe_hooks = HexRaysHooks(self._plugin)
self._view_hooks = ViewHooks(self._plugin)
self._ui_hooks = UIHooks(self._plugin)

core = self
self._plugin.logger.debug("Installing core hooks")

class UIHooksCore(Hooks, ida_kernwin.UI_Hooks):
"""
The UI core hook is used to determine when IDA is fully loaded,
meaning that we can starting hooking to receive our user events.
"""

def __init__(self, plugin):
ida_kernwin.UI_Hooks.__init__(self)
Hooks.__init__(self, plugin)

def ready_to_run(self, *_):
self._plugin.logger.debug("Ready to run hook")
core.load_netnode()
core.join_session()
self._plugin.interface.painter.set_custom_nav_colorizer()

def database_inited(self, *_):
self._plugin.logger.debug("Database inited hook")
self._plugin.interface.painter.install()

self._ui_hooks_core = UIHooksCore(self._plugin)
self._ui_hooks_core.hook()

class IDBHooksCore(Hooks, ida_idp.IDB_Hooks):
"""
The IDB core hook is used to know when the database is being
closed. We then need to unhook our user events.
"""

def __init__(self, plugin):
ida_idp.IDB_Hooks.__init__(self)
Hooks.__init__(self, plugin)

class IDBHooksCore(ida_idp.IDB_Hooks):
def closebase(self):
self._plugin.logger.debug("Closebase hook")
self._plugin.interface.painter.uninstall()
core._plugin.logger.trace("Closebase hook")
core.leave_session()
core.save_netnode()

Expand All @@ -151,35 +141,65 @@ def closebase(self):
core.ticks = 0
return 0

self._idb_hooks_core = IDBHooksCore(self._plugin)
self._idb_hooks_core = IDBHooksCore()
self._idb_hooks_core.hook()

class IDPHooksCore(Hooks, ida_idp.IDP_Hooks):
"""
The IDP core hook is sued to know when the auto-analysis has
finished so that we can call the queued events.
"""

def __init__(self, plugin):
ida_idp.IDP_Hooks.__init__(self)
Hooks.__init__(self, plugin)
class IDPHooksCore(ida_idp.IDP_Hooks):
def ev_get_bg_color(self, color, ea):
core._plugin.logger.trace("Get bg color hook")
value = core._plugin.interface.painter.get_bg_color(ea)
if value is not None:
ctypes.c_uint.from_address(long(color)).value = value
return 1
return 0

def auto_queue_empty(self, _):
self._plugin.logger.debug("Auto queue empty hook")
core._plugin.logger.debug("Auto queue empty hook")
if ida_auto.get_auto_state() == ida_auto.AU_NONE:
client = self._plugin.network.client
client = core._plugin.network.client
if client:
client.call_events()

self._idp_hooks_core = IDPHooksCore(self._plugin)
self._idp_hooks_core = IDPHooksCore()
self._idp_hooks_core.hook()

class UIHooksCore(ida_kernwin.UI_Hooks):
def ready_to_run(self):
core._plugin.logger.trace("Ready to run hook")
core.load_netnode()
core.join_session()
core._plugin.interface.painter.ready_to_run()

def get_ea_hint(self, ea):
core._plugin.logger.trace("Get ea hint hook")
return core._plugin.interface.painter.get_ea_hint(ea)

def widget_visible(self, widget):
core._plugin.logger.trace("Widget visible")
core._plugin.interface.painter.widget_visible(widget)

self._ui_hooks_core = UIHooksCore()
self._ui_hooks_core.hook()

class ViewHooksCore(ida_kernwin.View_Hooks):
def view_loc_changed(self, view, now, was):
core._plugin.logger.trace("View loc changed hook")
if now.plce.toea() != was.plce.toea():
name = core._plugin.config["user"]["name"]
color = core._plugin.config["user"]["color"]
core._plugin.network.send_packet(
UpdateLocation(name, now.plce.toea(), color)
)

self._view_hooks_core = ViewHooksCore()
self._view_hooks_core.hook()
return True

def _uninstall(self):
self._plugin.logger.debug("Uninstalling core hooks")
self._idb_hooks_core.unhook()
self._ui_hooks_core.unhook()
self._view_hooks_core.unhook()
self.unhook_all()
return True

Expand All @@ -192,8 +212,6 @@ def hook_all(self):
self._idb_hooks.hook()
self._idp_hooks.hook()
self._hxe_hooks.hook()
self._view_hooks.hook()
self._ui_hooks.hook()
self._hooked = True

def unhook_all(self):
Expand All @@ -205,8 +223,6 @@ def unhook_all(self):
self._idb_hooks.unhook()
self._idp_hooks.unhook()
self._hxe_hooks.unhook()
self._view_hooks.unhook()
self._ui_hooks.unhook()
self._hooked = False

def load_netnode(self):
Expand Down Expand Up @@ -268,6 +284,7 @@ def databases_listed(reply):
)
)
self.hook_all()
self._users.clear()

d = self._plugin.network.send_packet(
ListDatabases.Query(self._project)
Expand All @@ -282,4 +299,5 @@ def leave_session(self):
if self._project and self._database:
name = self._plugin.config["user"]["name"]
self._plugin.network.send_packet(LeaveSession(name))
self._users.clear()
self.unhook_all()
48 changes: 0 additions & 48 deletions idarling/core/hooks.py
Expand Up @@ -28,7 +28,6 @@

import events as evt # noqa: I100,I202
from .events import Event # noqa: I201
from ..shared.commands import UpdateLocation


class Hooks(object):
Expand Down Expand Up @@ -718,50 +717,3 @@ def _send_user_numforms(self, ea):
if numforms != self._numforms:
self._send_packet(evt.UserNumformsEvent(ea, numforms))
self._numforms = numforms


class ViewHooks(Hooks, ida_kernwin.View_Hooks): # FIXME: Move to core hooks?
def __init__(self, plugin):
ida_kernwin.View_Hooks.__init__(self)
Hooks.__init__(self, plugin)

def view_loc_changed(self, view, now, was):
self._plugin.logger.debug("View loc changed hook")
if now.plce.toea() != was.plce.toea():
name = self._plugin.config["user"]["name"]
color = self._plugin.config["user"]["color"]
self._plugin.network.send_packet(
UpdateLocation(name, now.plce.toea(), color)
)


class UIHooks(Hooks, ida_kernwin.UI_Hooks): # FIXME: Move to core hooks?
def __init__(self, plugin):
ida_kernwin.UI_Hooks.__init__(self)
Hooks.__init__(self, plugin)
self._state = {}

def get_ea_hint(self, ea):
self._plugin.logger.debug("Get ea hint hook")
if self._plugin.network.connected:
painter = self._plugin.interface.painter
nbytes = painter.nbytes
for name, infos in painter.users_positions.items():
address = infos["address"]
if address - nbytes * 4 <= ea <= address + nbytes * 4:
return str(name)

def saving(self):
self._plugin.logger.debug("Saving hook")
painter = self._plugin.interface.painter
users_positions = painter.users_positions
for user_position in users_positions.values():
address = user_position["address"]
color = painter.clear_database(address)
self._state[color] = address

def saved(self):
self._plugin.logger.debug("Saved hook")
painter = self._plugin.interface.painter
for color, address in self._state.items():
painter.repaint_database(color, address)
72 changes: 63 additions & 9 deletions idarling/interface/dialogs.py
Expand Up @@ -447,11 +447,48 @@ def color_button_activated(_):
self._name_line_edit.setText(name)
user_layout.addWidget(self._name_line_edit)

text = "Show other users in the navigation bar"
self._navbar_colorizer_checkbox = QCheckBox(text)
layout.addRow(self._navbar_colorizer_checkbox)
checked = self._plugin.config["user"]["navbar_colorizer"]
self._navbar_colorizer_checkbox.setChecked(checked)
text = "Disable all user cursors"
self._disable_all_cursors_checkbox = QCheckBox(text)
layout.addRow(self._disable_all_cursors_checkbox)
navbar_checked = not self._plugin.config["cursors"]["navbar"]
funcs_checked = not self._plugin.config["cursors"]["funcs"]
disasm_checked = not self._plugin.config["cursors"]["disasm"]
all_checked = navbar_checked and funcs_checked and disasm_checked
self._disable_all_cursors_checkbox.setChecked(all_checked)

def state_changed(state):
enabled = state == Qt.Unchecked
self._disable_navbar_cursors_checkbox.setChecked(not enabled)
self._disable_navbar_cursors_checkbox.setEnabled(enabled)
self._disable_funcs_cursors_checkbox.setChecked(not enabled)
self._disable_funcs_cursors_checkbox.setEnabled(enabled)
self._disable_disasm_cursors_checkbox.setChecked(not enabled)
self._disable_disasm_cursors_checkbox.setEnabled(enabled)

self._disable_all_cursors_checkbox.stateChanged.connect(state_changed)

style_sheet = """QCheckBox{ margin-left: 20px; }"""

text = "Disable navigation bar user cursors"
self._disable_navbar_cursors_checkbox = QCheckBox(text)
layout.addRow(self._disable_navbar_cursors_checkbox)
self._disable_navbar_cursors_checkbox.setChecked(navbar_checked)
self._disable_navbar_cursors_checkbox.setEnabled(not all_checked)
self._disable_navbar_cursors_checkbox.setStyleSheet(style_sheet)

text = "Disable functions window user cursors"
self._disable_funcs_cursors_checkbox = QCheckBox(text)
layout.addRow(self._disable_funcs_cursors_checkbox)
self._disable_funcs_cursors_checkbox.setChecked(funcs_checked)
self._disable_funcs_cursors_checkbox.setEnabled(not all_checked)
self._disable_funcs_cursors_checkbox.setStyleSheet(style_sheet)

text = "Disable disassembly view user cursors"
self._disable_disasm_cursors_checkbox = QCheckBox(text)
layout.addRow(self._disable_disasm_cursors_checkbox)
self._disable_disasm_cursors_checkbox.setChecked(disasm_checked)
self._disable_disasm_cursors_checkbox.setEnabled(not all_checked)
self._disable_disasm_cursors_checkbox.setStyleSheet(style_sheet)

text = "Allow other users to send notifications"
self._notifications_checkbox = QCheckBox(text)
Expand Down Expand Up @@ -702,8 +739,19 @@ def _reset(self, _):
self._name_line_edit.setText(config["user"]["name"])
self._set_color(ida_color=config["user"]["color"])

checked = config["user"]["navbar_colorizer"]
self._navbar_colorizer_checkbox.setChecked(checked)
navbar_checked = not config["cursors"]["navbar"]
funcs_checked = not config["cursor"]["funcs"]
disasm_checked = not config["cursor"]["disasm"]
all_checked = navbar_checked and funcs_checked and disasm_checked
self._disable_all_cursors_checkbox.setChecked(all_checked)

self._disable_navbar_cursors_checkbox.setChecked(navbar_checked)
self._disable_navbar_cursors_checkbox.setEnabled(not all_checked)
self._disable_funcs_cursors_checkbox.setChecked(funcs_checked)
self._disable_funcs_cursors_checkbox.setEnabled(not all_checked)
self._disable_disasm_cursors_checkbox.setChecked(disasm_checked)
self._disable_disasm_cursors_checkbox.setEnabled(not all_checked)

checked = config["user"]["notifications"]
self._notifications_checkbox.setChecked(checked)

Expand Down Expand Up @@ -732,8 +780,14 @@ def _commit(self):
self._plugin.config["user"]["color"] = self._color
self._plugin.interface.widget.refresh()

checked = self._navbar_colorizer_checkbox.isChecked()
self._plugin.config["user"]["navbar_colorizer"] = checked
all_ = self._disable_all_cursors_checkbox.isChecked()
checked = self._disable_navbar_cursors_checkbox.isChecked()
self._plugin.config["cursors"]["navbar"] = not all_ and not checked
checked = self._disable_funcs_cursors_checkbox.isChecked()
self._plugin.config["cursors"]["funcs"] = not all_ and not checked
checked = self._disable_disasm_cursors_checkbox.isChecked()
self._plugin.config["cursors"]["disasm"] = not all_ and not checked

checked = self._notifications_checkbox.isChecked()
self._plugin.config["user"]["notifications"] = checked

Expand Down

0 comments on commit d3dd6f3

Please sign in to comment.