Пример #1
0
def run_query(qf, ea_list, qs):
    subtitle = qs.help
    title = subtitle if len(subtitle) < 80 else "%s..." % subtitle[:77]
    ch = hxtb.ic_t(title="Shell [%s]" % title)
    mode = qs.ast_type == 1

    idaapi.show_wait_box("Processing")
    try:
        nfuncs = len(ea_list)
        for j, ea in enumerate(ea_list):
            if idaapi.user_cancelled():
                break
            idaapi.replace_wait_box("Processing function %d/%d" %
                                    (j + 1, nfuncs))
            r = list()
            try:
                r = hxtb.exec_query(qf, [ea],
                                    mode,
                                    parents=True,
                                    flags=idaapi.DECOMP_NO_WAIT)
                for x in r:
                    ch.append(x)
            except Exception as e:
                print("%s: %s" % (SCRIPT_NAME, e))
    finally:
        idaapi.hide_wait_box()
    return ch
Пример #2
0
 def __call__(self):
     if idaapi.user_cancelled():
         bc_log.info("Analysis cancelled by user, terminating process")
         self.qprocess.terminate()
         return -1
     else:
         return self.interval
Пример #3
0
    def retrieve_selected_functions(self, funcs):
        if not self.check_before_use():
            return

        funcset_ids = [self.funcset] if not self.cfg['usepublic'] else None
        i, succ, skip, fail = 0, 0, 0, 0
        _funcs = [ea for ea in funcs]
        funcs_len = len(_funcs)
        idaapi.show_wait_box("Matching... (0/{})".format(funcs_len))
        for ea in _funcs:
            i += 1
            idaapi.replace_wait_box("Matching... ({}/{})".format(i, funcs_len))
            if idaapi.user_cancelled():
                idaapi.hide_wait_box()
                print(
                    "[{}] {} functions successfully matched, {} functions failed, {} functions skipped"
                    .format(self.name, succ, fail, skip))
                return
            code = self.retrieve_function_with_check(ea, 1, funcset_ids)
            if code == 0:
                succ += 1
            elif code == 1:
                skip += 1
            else:
                fail += 1

        idaapi.hide_wait_box()
        print(
            "[{}] {} functions successfully matched, {} functions failed, {} functions skipped"
            .format(self.name, succ, fail, skip))
Пример #4
0
    def match_funcs(self, funcs):
        if not self.check_before_use():
            return

        i, fail, skip, succ = 0, 0, 0, 0

        def stop():
            idaapi.hide_wait_box()
            BinaryAILog.summary(succ, skip, fail, "matched")

        funcs_len = len(funcs)
        idaapi.show_wait_box("Matching... (0/{})".format(funcs_len))
        for ea in funcs:
            # refresh process status
            i += 1
            idaapi.replace_wait_box("Matching... ({}/{})".format(i, funcs_len))
            # check cancelled or not
            if idaapi.user_cancelled():
                stop()
                return
            status = None
            try:
                status = self._match_with_check(ea)
            finally:
                if status == 1:
                    succ += 1
                elif status == 0:
                    skip += 1
                else:
                    fail += 1
        stop()
Пример #5
0
def ghidraaas_checkin(bin_file_path, filename, ghidra_server_url):
    """
    Upload the .bytes files in ghidraaas.
    One time only (until IDA is restarted...)
    """
    idaapi.show_wait_box("Connecting to Ghidraaas. Sending bytes file...")
    try:
        md5_hash = idautils.GetInputFileMD5()
        queue = Queue.Queue()

        my_args = (bin_file_path, filename, ghidra_server_url, md5_hash, queue)
        t1 = threading.Thread(target=ghidraaas_checkin_thread,
                              args=my_args)
        t1.start()

        counter = 0
        stop = False

        while not stop:
            time.sleep(SLEEP_LENGTH)
            counter += 1

            # User terminated action
            if idaapi.user_cancelled():
                stop = True
                print("GhIDA:: [!] Check-in interrupted.")
                continue

            # Reached TIIMEOUT
            if counter > COUNTER_MAX:
                stop = True
                print("GhIDA:: [!] Timeout reached.")
                continue

            # Thread terminated
            if not t1.isAlive():
                stop = True
                print("GhIDA:: [DEBUG] Thread terminated.")
                continue

        print("GhIDA:: [DEBUG] Joining check-in thread.")
        t1.join(0)
        q_result = queue.get_nowait()
        print("GhIDA:: [DEBUG] Thread joined. Got queue result.")
        idaapi.hide_wait_box()
        return q_result

    except Exception:
        idaapi.hide_wait_box()
        print("GhIDA:: [!] Check-in error.")
        idaapi.warning("GhIDA check-in error")
        return False
Пример #6
0
def ghidraaas_checkout(ghidra_server_url):
    """
    That's all. Remove .bytes file from Ghidraaas server.
    """
    if not GLOBAL_CHECKIN:
        return

    idaapi.show_wait_box(
        "Connecting to Ghidraaas. Removing temporary files...")
    try:
        md5_hash = idautils.GetInputFileMD5()
        aargs = (md5_hash, ghidra_server_url)

        t1 = threading.Thread(target=ghidraaas_checkout_thread,
                              args=aargs)
        t1.start()

        counter = 0
        stop = False

        while not stop:
            time.sleep(SLEEP_LENGTH)
            counter += 1

            if idaapi.user_cancelled():
                print("GhIDA:: [!] Check-out interrupted.")
                stop = True
                continue

            if counter > COUNTER_MAX:
                print("GhIDA:: [!] Timeout reached.")
                stop = True
                continue

            if not t1.isAlive():
                stop = True
                print("GhIDA:: [DEBUG] Thread terminated.")
                continue

        print("GhIDA:: [DEBUG] Joining check-out thread.")
        t1.join(0)
        print("GhIDA:: [DEBUG] Thread joined")
        idaapi.hide_wait_box()
        return

    except Exception:
        idaapi.hide_wait_box()
        print("GhIDA:: [!] Check-out error")
        idaapi.warning("GhIDA check-out error")
        return
Пример #7
0
    def upload_funcs(self, funcs):
        if not self.check_before_use(check_funcset=True):
            return

        i, succ, skip, fail = 0, 0, 0, 0

        def stop():
            idaapi.hide_wait_box()
            BinaryAILog.summary(succ, skip, fail, "uploaded")

        funcs_len = len(funcs)
        idaapi.show_wait_box("Uploading... (0/{})".format(funcs_len))
        for ea in funcs:
            i += 1
            idaapi.replace_wait_box("Uploading... ({}/{})".format(
                i, funcs_len))

            if idaapi.user_cancelled():
                stop()
                return
            # < minsize
            pfn = idaapi.get_func(ea)
            if idaapi.FlowChart(pfn).size < bai_config['minsize']:
                skip += 1
                continue
            # try upload
            func_id = None
            try:
                func_id = self.mgr.upload(ea, self.mgr.funcset)
            except DecompilationFailure as e:
                BinaryAILog.fail(idaapi.get_func_name(ea), str(e))
                fail += 1
                continue
            except BinaryAIException as e:
                stop()
                BinaryAILog.fatal(e)
            # fail
            if not func_id:
                fail += 1
                continue
            succ += 1
        stop()
Пример #8
0
 def upload_selected_functions(self, funcs):
     if not self.check_before_use(check_funcset=True):
         return
     i, succ, skip, fail = 0, 0, 0, 0
     _funcs = [ea for ea in funcs]
     funcs_len = len(_funcs)
     idaapi.show_wait_box("Uploading... (0/{})".format(funcs_len))
     for ea in _funcs:
         i += 1
         idaapi.replace_wait_box("Uploading... ({}/{})".format(
             i, funcs_len))
         if idaapi.user_cancelled():
             idaapi.hide_wait_box()
             print(
                 "[{}] {} functions successfully uploaded, {} functions failed, {} functions skipped"
                 .format(self.name, succ, fail, skip))
             return
         pfn = idaapi.get_func(ea)
         if idaapi.FlowChart(pfn).size < self.cfg['minsize']:
             skip += 1
             continue
         func_id = None
         try:
             func_id = self.upload_function(ea, self.funcset)
         except DecompilationFailure:
             pass
         except BinaryAIException as e:
             idaapi.hide_wait_box()
             assert False, "[BinaryAI] {}".format(e._msg)
         func_name = idaapi.get_func_name(ea)
         if not func_id:
             print("[{}] {} failed because upload error".format(
                 self.name, func_name))
             fail += 1
             continue
         succ += 1
     idaapi.hide_wait_box()
     print(
         "[{}] {} functions successfully uploaded, {} functions failed, {} functions skipped"
         .format(self.name, succ, fail, skip))
Пример #9
0
    def revert_funcs(self, funcs):
        i, succ, skip = 0, 0, 0

        def stop():
            idaapi.hide_wait_box()
            BinaryAILog.summary(succ, skip, 0, "reverted")

        funcs_len = len(funcs)
        idaapi.show_wait_box("Reverting... (0/{})".format(funcs_len))
        for ea in funcs:
            i += 1
            idaapi.replace_wait_box("Reverting... ({}/{})".format(i, funcs_len))

            if idaapi.user_cancelled():
                stop()
                return

            if bai_mark.revert_bai_func(ea):
                succ += 1
            else:
                skip += 1
        stop()
Пример #10
0
            idaapi.replace_wait_box("Total progress: %s\n\nScanning: %s\n\n" %
                                    (progress, funcname))

            try:
                cfunc = idaapi.decompile(ea, flags=idaapi.DECOMP_NO_WAIT)
            except idaapi.DecompilationFailure:
                print "Error decompiling function @ 0x%x" % ea
                cfunc = None

            if cfunc:
                fp = func_parser_t(cfunc)
                fp.apply_to(cfunc.body, None)
                choser.feed(fp.data)

            if idaapi.user_cancelled():
                aborted = True
                break

            i += 1
        idaapi.hide_wait_box()
        if aborted:
            idaapi.warning("Aborted.")

    # IDA <= 7.2
    else:
        for ea in func_list:
            try:
                cfunc = idaapi.decompile(ea)
            except idaapi.DecompilationFailure:
                print "Error decompiling function @ 0x%x" % ea
Пример #11
0
    def analysis_finish_cb(self, outfname, logfname, cfaoutfname, ea=None):
        idaapi.show_wait_box("HIDECANCEL\nParsing BinCAT analysis results")
        bc_log.debug("Parsing analyzer result file")
        # Here we can't check for user_cancelled because the UI is
        # unresponsive when parsing.
        try:
            cfa = cfa_module.CFA.parse(outfname, logs=logfname)
        except (pybincat.PyBinCATException, NoSectionError):
            idaapi.hide_wait_box()
            bc_log.error("Could not parse result file")
            return None
        self.clear_background()
        self.cfa = cfa
        if cfa:
            # XXX add user preference for saving to idb? in that case, store
            # reference to marshalled cfa elsewhere
            bc_log.info("Storing analysis results to idb...")
            with open(outfname, 'rb') as f:
                self.netnode["out.ini"] = f.read()
            with open(logfname, 'rb') as f:
                self.netnode["analyzer.log"] = f.read()
            if self.remapped_bin_path:
                self.netnode["remapped_bin_path"] = self.remapped_bin_path
            self.netnode["remap_binary"] = self.remap_binary
            if cfaoutfname is not None and os.path.isfile(cfaoutfname):
                with open(cfaoutfname, 'rb') as f:
                    self.last_cfaout_marshal = f.read()
            bc_log.info("Analysis results have been stored idb.")
        else:
            bc_log.info("Empty or unparseable result file.")
        bc_log.debug("----------------------------")
        idaapi.replace_wait_box("Updating IDB with BinCAT results")
        # Update current RVA to start address (nodeid = 0)
        # by default, use current ea - e.g, in case there is no results (cfa is
        # None) or no node 0 (happens in backward mode)
        current_ea = self.current_ea
        if ea is not None:
            current_ea = ea
        else:
            try:
                node0 = cfa['0']
                if node0:
                    current_ea = node0.address.value
            except (KeyError, TypeError):
                # no cfa is None, or no node0
                pass
        try:
            self.set_current_ea(current_ea, force=True)
        except TypeError as e:
            bc_log.warn("Could not load results from IDB")
            bc_log.warn("------ BEGIN EXCEPTION -----")
            bc_log.exception(e)
            bc_log.warn("------ END EXCEPTION -----")
            idaapi.hide_wait_box()
            return None
        self.netnode["current_ea"] = current_ea
        if not cfa:
            return
        for addr, nodeids in cfa.addr_nodes.items():
            if hasattr(idaapi,
                       "user_cancelled") and idaapi.user_cancelled() > 0:
                bc_log.info("User cancelled!")
                idaapi.hide_wait_box()
                return None
            ea = addr.value
            tainted = False
            taint_id = 1
            for n_id in nodeids:
                # is it tainted?
                # find child nodes
                node = cfa[n_id]
                if node.tainted:
                    tainted = True
                    if node.taintsrc:
                        # Take the first one
                        taint_id = int(node.taintsrc[0].split("-")[1])
                    break

            if tainted:
                idaapi.set_item_color(ea, taint_color(taint_id))
            else:
                idaapi.set_item_color(ea, 0xF0F0F0)
        idaapi.hide_wait_box()
        self.gui.focus_registers()
Пример #12
0
def ghidraaas_decompile(address,
                        xml_file_path,
                        bin_file_path,
                        ghidra_server_url):
    """
    Send the xml file to ghidraaas
    and ask to decompile a function
    """
    global GLOBAL_CHECKIN

    # Filename without the .xml extension
    filename = GLOBAL_FILENAME

    if not GLOBAL_CHECKIN:
        if ghidraaas_checkin(bin_file_path, filename, ghidra_server_url):
            GLOBAL_CHECKIN = True
        else:
            raise Exception("[!] Ghidraaas Check-in error")

    idaapi.show_wait_box(
        "Connecting to Ghidraaas. Decompiling function %s" % address)

    try:
        md5_hash = idautils.GetInputFileMD5()
        queue = Queue.Queue()

        aargs = (address, xml_file_path, bin_file_path,
                 ghidra_server_url, filename, md5_hash, queue)
        t1 = threading.Thread(target=ghidraaas_decompile_thread,
                              args=aargs)
        t1.start()

        counter = 0
        stop = False

        while not stop:
            time.sleep(SLEEP_LENGTH)
            counter += 1

            if idaapi.user_cancelled():
                print("GhIDA:: [!] decompilation interrupted.")
                stop = True
                continue

            if counter > COUNTER_MAX:
                print("GhIDA:: [!] Timeout reached.")
                stop = True
                continue

            if not t1.isAlive():
                stop = True
                print("GhIDA:: [DEBUG] Thread terminated.")
                continue

        print("GhIDA:: [DEBUG] Joining decompilation thread.")
        t1.join(0)
        q_result = queue.get_nowait()
        print("GhIDA:: [DEBUG] Thread joined. Got queue result.")
        idaapi.hide_wait_box()
        return q_result

    except Exception:
        idaapi.hide_wait_box()
        print("GhIDA:: [!] Unexpected decompilation error")
        idaapi.warning("GhIDA decompilation error")
        return None
Пример #13
0
def ghidra_headless(address,
                    xml_file_path,
                    bin_file_path,
                    ghidra_headless_path,
                    ghidra_plugins_path):
    """
    Call Ghidra in headless mode and run the plugin
    FunctionDecompile.py to decompile the code of the function.
    """
    try:
        if not os.path.isfile(ghidra_headless_path):
            print("GhIDA:: [!] ghidra analyzeHeadless not found.")
            raise Exception("analyzeHeadless not found")

        decompiled_code = None
        idaapi.show_wait_box("Ghida decompilation started")

        prefix = "%s_" % address
        output_temp = tempfile.NamedTemporaryFile(prefix=prefix, delete=False)
        output_path = output_temp.name
        # print("GhIDA:: [DEBUG] output_path: %s" % output_path)
        output_temp.close()

        cmd = [ghidra_headless_path,
               ".",
               "Temp",
               "-import",
               xml_file_path,
               '-readOnly',
               '-scriptPath',
               ghidra_plugins_path,
               '-postScript',
               'FunctionDecompile.py',
               address,
               output_path,
               "-noanalysis",
               "-deleteProject"]

        # Options to 'safely' terminate the process
        if os.name == 'posix':
            kwargs = {
                'preexec_fn': os.setsid
            }
        else:
            kwargs = {
                'creationflags': subprocess.CREATE_NEW_PROCESS_GROUP,
                'shell': True
            }

        p = subprocess.Popen(cmd,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT,
                             **kwargs)

        stop = False
        counter = 0
        print("GhIDA:: [INFO] Ghidra headless (timeout: %ds)" % TIMEOUT)
        print("GhIDA:: [INFO] Waiting Ghidra headless analysis to finish...")

        while not stop:
            time.sleep(SLEEP_LENGTH)
            counter += 1
            subprocess.Popen.poll(p)

            # Process terminated
            if p.returncode is not None:
                stop = True
                print("GhIDA:: [INFO] Ghidra analysis completed!")
                continue

            # User terminated action
            if idaapi.user_cancelled():
                # Termiante the process!
                terminate_process(p.pid)
                stop = True
                print("GhIDA:: [!] Ghidra analysis interrupted.")
                continue

            # Process timeout
            if counter > COUNTER_MAX:
                terminate_process(p.pid)
                stop = True
                print("GhIDA:: [!] Decompilation error - timeout reached")
                continue

        # Check if JSON response is available
        if os.path.isfile(output_path):
            with open(output_path) as f_in:
                j = json.load(f_in)
                if j['status'] == "completed":
                    decompiled_code = j['decompiled']
                else:
                    print("GhIDA:: [!] Decompilation error -",
                          " JSON response is malformed")

            # Remove the temporary JSON response file
            os.remove(output_path)
        else:
            print("GhIDA:: [!] Decompilation error - JSON response not found")
            idaapi.warning("Ghidra headless decompilation error")

    except Exception as e:
        print("GhIDA:: [!] %s" % e)
        print("GhIDA:: [!] Ghidra headless analysis failed")
        idaapi.warning("Ghidra headless analysis failed")
        decompiled_code = None

    finally:
        idaapi.hide_wait_box()
        return decompiled_code