HexForge.py (115 lines of code) (raw):
import idaapi
import inspect
from hexforge_modules import crypto_modules, encoding_modules, misc_modules, search_modules
from hexforge_modules.search_modules import SearchVirustotalBytes, SearchVirustotalString, SearchGitHub, SearchGoogle, SearchGrepApp
CRYPTO_MODULE_PATH = "HexForge/crypto/"
ENCODING_MODULE_PATH = "HexForge/encoding/"
MISC_MODULE_PATH = "HexForge/misc/"
SEARCH_MODULE_PATH = "HexForge/search/"
ida_version = idaapi.get_kernel_version()
is_ida_9_or_later = float(ida_version) >= 9.0
g_crypto_modules = []
g_encoding_modules = []
g_misc_modules = []
g_search_modules = []
class hexforge_plugin_t(idaapi.plugin_t):
flags = idaapi.PLUGIN_KEEP
comment = ""
help = ""
wanted_name = "HexForge"
def init(self):
global g_crypto_modules
global g_encoding_modules
global g_misc_modules
global g_search_modules
idaapi.msg("init() called!\n")
g_crypto_modules = self._init_modules(crypto_modules)
g_encoding_modules = self._init_modules(encoding_modules)
g_misc_modules = self._init_modules(misc_modules)
g_search_modules = self._init_modules(search_modules)
self._init_actions()
self._init_hooks()
return idaapi.PLUGIN_KEEP
def run(self, arg):
idaapi.msg("run() called with %d!\n" % arg)
def term(self):
self._del_action()
idaapi.msg("term() called!\n")
# --------------------------------------------------------------------------
# Initializations
# --------------------------------------------------------------------------
def _init_modules(self, modules) -> None:
initialized_modules = []
for _, cls in inspect.getmembers(modules, inspect.isclass):
try:
initialized_modules.append(cls())
except Exception as e:
idaapi.msg(f"Failed to initialize {cls.__name__}: {e}\n")
return initialized_modules
def _init_actions(self) -> None:
for module in g_crypto_modules + g_encoding_modules + g_misc_modules + g_search_modules:
module.init_action()
def _del_action(self) -> None:
for module in g_crypto_modules + g_encoding_modules + g_misc_modules + g_search_modules:
module.del_action()
# --------------------------------------------------------------------------
# Initialize Hooks
# --------------------------------------------------------------------------
def _init_hooks(self) -> None:
"""
Install plugin hooks into IDA.
"""
self._hooks = Hooks()
self._hooks.hook()
# Plugin Hooks
class Hooks(idaapi.UI_Hooks):
def finish_populating_widget_popup(self, widget, popup):
"""
A right click menu is about to be shown. (IDA 7)
"""
inject_actions(widget, popup, idaapi.get_widget_type(widget))
return 0
# Prefix Wrappers
def inject_actions(form, popup, form_type) -> int:
"""
Inject actions to popup menu(s) based on context.
"""
if is_ida_9_or_later:
valid_form_types = (idaapi.BWN_DISASM, idaapi.BWN_HEXVIEW, idaapi.BWN_PSEUDOCODE)
else:
valid_form_types = (idaapi.BWN_DISASMS, idaapi.BWN_DUMP, idaapi.BWN_PSEUDOCODE)
if form_type in valid_form_types:
for module in g_crypto_modules:
idaapi.attach_action_to_popup(
form,
popup,
module.ACTION_NAME,
CRYPTO_MODULE_PATH,
idaapi.SETMENU_APP,
)
for module in g_misc_modules:
idaapi.attach_action_to_popup(
form,
popup,
module.ACTION_NAME,
MISC_MODULE_PATH,
idaapi.SETMENU_APP,
)
for module in g_encoding_modules:
idaapi.attach_action_to_popup(
form,
popup,
module.ACTION_NAME,
ENCODING_MODULE_PATH,
idaapi.SETMENU_APP,
)
for module in g_search_modules:
# Exclude byte searches in decompiler
if form_type == idaapi.BWN_PSEUDOCODE and isinstance(module, SearchVirustotalBytes):
continue
# Exclude string searches in disassembler
if is_ida_9_or_later:
if form_type == idaapi.BWN_DISASM and isinstance(module, (SearchGoogle, SearchGrepApp,SearchGitHub,SearchVirustotalString)):
continue
idaapi.attach_action_to_popup(
form,
popup,
module.ACTION_NAME,
SEARCH_MODULE_PATH,
idaapi.SETMENU_APP,
)
else:
if form_type == idaapi.BWN_DISASMS and isinstance(module, (SearchGoogle, SearchGrepApp,SearchGitHub,SearchVirustotalString)):
continue
idaapi.attach_action_to_popup(
form,
popup,
module.ACTION_NAME,
SEARCH_MODULE_PATH,
idaapi.SETMENU_APP,
)
return 0
# Register IDA plugin
def PLUGIN_ENTRY() -> hexforge_plugin_t:
return hexforge_plugin_t()
PLUGIN_ENTRY()