Files
d810/d810/manager.py
Boris Batteux 33f8d22f28 Initial commit
2020-10-29 11:09:07 +01:00

197 lines
7.7 KiB
Python

from __future__ import annotations
import os
import json
import logging
import idaapi
from typing import TYPE_CHECKING, List
if TYPE_CHECKING:
from d810.conf import D810Configuration, ProjectConfiguration
# Note that imports are performed directly in the functions so that they are reloaded each time the plugin is restarted
# This allow to load change code/drop new rules without having to reboot IDA
d810_state = None
D810_LOG_DIR_NAME = "d810_logs"
MANAGER_INFO_FILENAME = "manager_info.json"
logger = logging.getLogger('D810')
def reload_all_modules():
manager_info_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), MANAGER_INFO_FILENAME)
with open(manager_info_path, "r") as f:
manager_info = json.load(f)
for module_name in manager_info["module_list"]:
idaapi.require(module_name)
class D810Manager(object):
def __init__(self, log_dir):
self.instruction_optimizer_rules = []
self.instruction_optimizer_config = {}
self.block_optimizer_rules = []
self.block_optimizer_config = {}
self.instruction_optimizer = None
self.block_optimizer = None
self.hx_decompiler_hook = None
self.log_dir = log_dir
self.config = {}
def configure(self, **kwargs):
self.config = kwargs
def reload(self):
self.stop()
logger.debug("Reloading manager...")
from d810.hexrays_hooks import InstructionOptimizerManager, BlockOptimizerManager, HexraysDecompilationHook
self.instruction_optimizer = InstructionOptimizerManager(self)
self.instruction_optimizer.configure(**self.instruction_optimizer_config)
self.block_optimizer = BlockOptimizerManager(self)
self.block_optimizer.configure(**self.block_optimizer_config)
for rule in self.instruction_optimizer_rules:
rule.log_dir = self.log_dir
self.instruction_optimizer.add_rule(rule)
for cfg_rule in self.block_optimizer_rules:
cfg_rule.log_dir = self.log_dir
self.block_optimizer.add_rule(cfg_rule)
self.instruction_optimizer.install()
self.block_optimizer.install()
self.hx_decompiler_hook = HexraysDecompilationHook(self)
self.hx_decompiler_hook.hook()
def configure_instruction_optimizer(self, rules, **kwargs):
self.instruction_optimizer_rules = [rule for rule in rules]
self.instruction_optimizer_config = kwargs
def configure_block_optimizer(self, rules, **kwargs):
self.block_optimizer_rules = [rule for rule in rules]
self.block_optimizer_config = kwargs
def stop(self):
if self.instruction_optimizer is not None:
logger.debug("Removing InstructionOptimizer...")
self.instruction_optimizer.remove()
self.instruction_optimizer = None
if self.block_optimizer is not None:
logger.debug("Removing ControlFlowFixer...")
self.block_optimizer.remove()
self.block_optimizer = None
if self.hx_decompiler_hook is not None:
logger.debug("Removing HexraysDecompilationHook...")
self.hx_decompiler_hook.unhook()
self.hx_decompiler_hook = None
class D810State(object):
def __init__(self, d810_config: D810Configuration):
# For debugging purposes, to interact with this object from the console
# Type in IDA Python shell 'from d810.manager import d810_state' to access it
global d810_state
d810_state = self
reload_all_modules()
self.d810_config = d810_config
self.log_dir = os.path.join(self.d810_config.get("log_dir"), D810_LOG_DIR_NAME)
self.manager = D810Manager(self.log_dir)
from d810.optimizers.instructions import KNOWN_INS_RULES
from d810.optimizers.flow import KNOWN_BLK_RULES
self.known_ins_rules = [x for x in KNOWN_INS_RULES]
self.known_blk_rules = [x for x in KNOWN_BLK_RULES]
self.gui = None
self.current_project = None
self.projects: List[ProjectConfiguration] = []
self.current_project_index = self.d810_config.get("last_project_index")
self.current_ins_rules = []
self.current_blk_rules = []
self.register_default_projects()
self.load_project(self.current_project_index)
def register_default_projects(self):
from d810.conf import ProjectConfiguration
self.projects = []
for project_configuration_path in self.d810_config.get("configurations"):
project_configuration = ProjectConfiguration(project_configuration_path,
conf_dir=self.d810_config.config_dir)
project_configuration.load()
self.projects.append(project_configuration)
logger.debug("Rule configurations loaded: {0}".format(self.projects))
def add_project(self, config: ProjectConfiguration):
self.projects.append(config)
self.d810_config.get("configurations").append(config.path)
self.d810_config.save()
def update_project(self, old_config: ProjectConfiguration, new_config: ProjectConfiguration):
old_config_index = self.projects.index(old_config)
self.projects[old_config_index] = new_config
def del_project(self, config: ProjectConfiguration):
self.projects.remove(config)
self.d810_config.get("configurations").remove(config.path)
self.d810_config.save()
os.remove(config.path)
def load_project(self, project_index: int):
self.current_project_index = project_index
self.current_project = self.projects[project_index]
self.current_ins_rules = []
self.current_blk_rules = []
for rule in self.known_ins_rules:
for rule_conf in self.current_project.ins_rules:
if rule.name == rule_conf.name:
rule.configure(rule_conf.config)
rule.set_log_dir(self.log_dir)
self.current_ins_rules.append(rule)
logger.debug("Instruction rules configured")
for blk_rule in self.known_blk_rules:
for rule_conf in self.current_project.blk_rules:
if blk_rule.name == rule_conf.name:
blk_rule.configure(rule_conf.config)
blk_rule.set_log_dir(self.log_dir)
self.current_blk_rules.append(blk_rule)
logger.debug("Block rules configured")
self.manager.configure(**self.current_project.additional_configuration)
logger.debug("Project loaded.")
def start_d810(self):
print("D-810 ready to deobfuscate...")
self.manager.configure_instruction_optimizer([rule for rule in self.current_ins_rules],
generate_z3_code=self.d810_config.get("generate_z3_code"),
dump_intermediate_microcode=self.d810_config.get(
"dump_intermediate_microcode"),
**self.current_project.additional_configuration)
self.manager.configure_block_optimizer([rule for rule in self.current_blk_rules],
**self.current_project.additional_configuration)
self.manager.reload()
self.d810_config.set("last_project_index", self.current_project_index)
self.d810_config.save()
def stop_d810(self):
print("Stopping D-810...")
self.manager.stop()
def start_plugin(self):
from d810.ida_ui import D810GUI
self.gui = D810GUI(self)
self.gui.show_windows()
def stop_plugin(self):
self.manager.stop()
if self.gui:
self.gui.term()
self.gui = None