From 5d74602b5654262bcbba486b45a815a046e2365e Mon Sep 17 00:00:00 2001 From: Ivan Gotovchits Date: Tue, 27 Feb 2018 16:09:31 -0500 Subject: [PATCH] updates to BAP 1.4 release In this update we are relying on the new Primus Taint Analysis Framework to provide us data-flow information via the `primus-propagate-taint` compatibility layer. We allow a user to select the taint propagation engine, as well as its parameters. This commit also moves the bap_taint module to the utilities package, as otherwise it is loaded multiple times by each plugin separatly that may lead to unexpected results (don't ask me what are they) There is also a small fix that prevents the racing condition between askXXX dialogs and IDA Python breakability facility. The merge of this PR is blocked until https://github.com/BinaryAnalysisPlatform/bap/pull/784 is merged --- plugins/bap/plugins/__init__.py | 2 +- plugins/bap/plugins/bap_bir_attr.py | 5 ++- plugins/bap/plugins/bap_taint_ptr.py | 2 +- plugins/bap/plugins/bap_taint_reg.py | 2 +- plugins/bap/plugins/pseudocode_bap_taint.py | 2 +- plugins/bap/utils/__init__.py | 2 +- plugins/bap/{plugins => utils}/bap_taint.py | 50 ++++++++++++++------- plugins/plugin_loader_bap.py | 17 ++++--- 8 files changed, 52 insertions(+), 30 deletions(-) rename plugins/bap/{plugins => utils}/bap_taint.py (72%) diff --git a/plugins/bap/plugins/__init__.py b/plugins/bap/plugins/__init__.py index f827183..78b4514 100644 --- a/plugins/bap/plugins/__init__.py +++ b/plugins/bap/plugins/__init__.py @@ -1,4 +1,4 @@ """This module contains all the plugins that will be loaded by BAP-Loader.""" -__all__ = ('bap_bir_attr', 'bap_taint', 'bap_view', 'pseudocode_bap_comment', +__all__ = ('bap_bir_attr', 'bap_taint_ptr', 'bap_taint_reg' 'bap_view', 'pseudocode_bap_comment', 'pseudocode_bap_taint') diff --git a/plugins/bap/plugins/bap_bir_attr.py b/plugins/bap/plugins/bap_bir_attr.py index bef2bc7..5aa1112 100644 --- a/plugins/bap/plugins/bap_bir_attr.py +++ b/plugins/bap/plugins/bap_bir_attr.py @@ -73,7 +73,10 @@ def run(self, arg): """ args_msg = "Arguments that will be passed to `bap'" - + # If a user is not fast enough in providing the answer + # IDA Python will popup a modal window that will block + # a user from providing the answer. + idaapi.disable_script_timeout() args = idaapi.askstr(ARGS_HISTORY, '--passes=', args_msg) if args is None: return diff --git a/plugins/bap/plugins/bap_taint_ptr.py b/plugins/bap/plugins/bap_taint_ptr.py index 02b852e..0edb3fd 100644 --- a/plugins/bap/plugins/bap_taint_ptr.py +++ b/plugins/bap/plugins/bap_taint_ptr.py @@ -1,4 +1,4 @@ -from bap.plugins.bap_taint import BapTaint +from bap.utils.bap_taint import BapTaint class BapTaintPtr(BapTaint): wanted_hotkey = "Ctrl-Shift-A" diff --git a/plugins/bap/plugins/bap_taint_reg.py b/plugins/bap/plugins/bap_taint_reg.py index 85d796f..557693c 100644 --- a/plugins/bap/plugins/bap_taint_reg.py +++ b/plugins/bap/plugins/bap_taint_reg.py @@ -1,4 +1,4 @@ -from bap.plugins.bap_taint import BapTaint +from bap.utils.bap_taint import BapTaint class BapTaintReg(BapTaint): wanted_hotkey = "Shift-A" diff --git a/plugins/bap/plugins/pseudocode_bap_taint.py b/plugins/bap/plugins/pseudocode_bap_taint.py index 8cc63c3..b6b6b42 100644 --- a/plugins/bap/plugins/pseudocode_bap_taint.py +++ b/plugins/bap/plugins/pseudocode_bap_taint.py @@ -8,7 +8,7 @@ import idaapi from bap.utils import hexrays -from bap.plugins.bap_taint import BapTaint +from bap.utils.bap_taint import BapTaint colors = { 'black': 0x000000, diff --git a/plugins/bap/utils/__init__.py b/plugins/bap/utils/__init__.py index 42ba074..87da377 100644 --- a/plugins/bap/utils/__init__.py +++ b/plugins/bap/utils/__init__.py @@ -1,4 +1,4 @@ """Commonly used utilities.""" __all__ = ('sexpr', 'bap_comment', 'run', 'ida', 'abstract_ida_plugins', - 'config') + 'config', 'bap_taint') diff --git a/plugins/bap/plugins/bap_taint.py b/plugins/bap/utils/bap_taint.py similarity index 72% rename from plugins/bap/plugins/bap_taint.py rename to plugins/bap/utils/bap_taint.py index a2be4b0..0187422 100644 --- a/plugins/bap/plugins/bap_taint.py +++ b/plugins/bap/utils/bap_taint.py @@ -18,7 +18,6 @@ import idaapi import idc from bap.utils.run import BapIda -from bap.utils.abstract_ida_plugins import DoNothing patterns = [ ('true', 'gray'), @@ -27,23 +26,45 @@ ('taints', 'yellow') ] +ENGINE_HISTORY=117342 + +ask_engine='What engine would you like, primus or legacy?' +ask_depth='For how many RTL instructions to propagate?' + class PropagateTaint(BapIda): ENGINE='primus' + DEPTH=4096 + LOOP_DEPTH=64 "Propagate taint information using BAP" def __init__(self, addr, kind): super(PropagateTaint,self).__init__() + # If a user is not fast enough in providing the answer + # IDA Python will popup a modal window that will block + # a user from providing the answer. + idaapi.disable_script_timeout() + + engine = idaapi.askstr(ENGINE_HISTORY, self.ENGINE, ask_engine) \ + or self.ENGINE + depth = idaapi.asklong(self.DEPTH, ask_depth) \ + or self.DEPTH + + # don't ask for the loop depth as a user is already annoyed. + loop_depth = self.LOOP_DEPTH - self.action = 'taint propagating from {:s}0x{:X}'.format( + self.action = 'propagating taint from {:s}0x{:X}'.format( '*' if kind == 'ptr' else '', addr) - propagate = 'run' if self.ENGINE == 'primus' else 'propagate-taint' + propagate = 'run' if engine == 'primus' else 'propagate-taint' self.passes = ['taint', propagate, 'map-terms','emit-ida-script'] self.script = self.tmpfile('py') scheme = self.tmpfile('scm') + stdin=self.tmpfile('stdin') + stdout=self.tmpfile('stdout') for (pat,color) in patterns: scheme.write('(({0}) (color {1}))\n'.format(pat,color)) scheme.close() + name = idc.GetFunctionName(addr) self.args += [ '--taint-'+kind, '0x{:X}'.format(addr), @@ -53,16 +74,22 @@ def __init__(self, addr, kind): '--emit-ida-script-file', self.script.name ] - if self.ENGINE == 'primus': + if engine == 'primus': self.args += [ - '--run-entry-points=all-subroutines', - '--primus-limit-max-length=100', - '--primus-propagate-taint-run', + '--run-entry-points={}'.format(name), + '--primus-limit-max-length={}'.format(depth), + '--primus-limit-max-visited={}'.format(loop_depth), '--primus-promiscuous-mode', - '--primus-greedy-scheduler' + '--primus-greedy-scheduler', + '--primus-propagate-taint-from-attributes', + '--primus-propagate-taint-to-attributes', + '--primus-lisp-channel-redirect=:{0},:{1}'.format( + stdin.name, + stdout.name) ] + class BapTaint(idaapi.plugin_t): flags = 0 comment = "BAP Taint Plugin" @@ -139,10 +166,3 @@ def install_callback(cls, callback_fn, ptr_or_reg=None): else: idc.Fatal("Invalid ptr_or_reg value passed {}". format(repr(ptr_or_reg))) - -class BapTaintStub(DoNothing): - pass - - -def PLUGIN_ENTRY(): - return BapTaintStub() diff --git a/plugins/plugin_loader_bap.py b/plugins/plugin_loader_bap.py index 33b1397..da94ed6 100644 --- a/plugins/plugin_loader_bap.py +++ b/plugins/plugin_loader_bap.py @@ -1,6 +1,7 @@ """Loads all possible BAP IDA Python plugins.""" - - +import os +import bap.plugins +import bap.utils.run import idaapi @@ -15,24 +16,22 @@ class bap_loader(idaapi.plugin_t): def init(self): """Read directory and load as many plugins as possible.""" - import os - import bap.plugins - import bap.utils.run - import idaapi + self.plugins = [] idaapi.msg("BAP Loader activated\n") bap.utils.run.check_and_configure_bap() plugin_path = os.path.dirname(bap.plugins.__file__) - idaapi.msg("Loading plugins from {}\n".format(plugin_path)) + idaapi.msg("BAP> Loading plugins from {}\n".format(plugin_path)) for plugin in sorted(os.listdir(plugin_path)): path = os.path.join(plugin_path, plugin) if not plugin.endswith('.py') or plugin.startswith('__'): continue # Skip non-plugins - idaapi.load_plugin(path) - return idaapi.PLUGIN_SKIP # The loader will be called whenever needed + idc.Message('BAP> Loading {}\n'.format(plugin)) + self.plugins.append(idaapi.load_plugin(path)) + return idaapi.PLUGIN_KEEP def term(self): """Ignored."""