Пример #1
0
    def load(self):
        plugin_menu = self.main.getMenuByType(cutter.MainWindow.MenuType.Plugins)

        action = QtWidgets.QAction("x64dbg - Import database", self.main)
        action.triggered.connect(self.import_db)
        plugin_menu.addAction(action)

        action = QtWidgets.QAction("x64dbg - Export database", self.main)
        action.triggered.connect(self.export_db)
        plugin_menu.addAction(action)

        cutter.message("[w64dbg-cutter] Initialized")
Пример #2
0
    def export_db(self):
        filename = self.file_dialog("Open new file for export", True)
        if not filename:
            return

        cutter.message("[x64dbg-cutter]: Exporting database to %s" % filename)
        
        db = {}
        
        base_addr = cutter.cmdj("elJ bin.baddr")[0]["value"]
        cutter.message("[x64dbg-cutter]: baddr is %d" % base_addr)
        
        # We can only export items from the main binary currently
        module = os.path.basename(cutter.cmdj("ij")["core"]["file"]).lower()
        
        # ref: {"addr":5368778842,"size":1,"prot":"--x","hw":false,"trace":false,"enabled":true,"data":"","cond":""}
        db["breakpoints"] = [{
            "address": hex(bp["addr"] - base_addr), # Comment address relative to the base of the module
            "enabled": bp["enabled"], # Whether the breakpoint is enabled
            "type": BPHARDWARE if bp["hw"] else BPNORMAL, # see https://github.com/x64dbg/x64dbg/blob/development/src/dbg/breakpoint.h#L13
            "module": module, # The module that the comment is in
        } for bp in cutter.cmdj("dbj")]
        cutter.message("[x64dbg-cutter]: %d breakpoint(s) exported" % len(db["breakpoints"]))
        
        # ref: {"offset":5368713216,"type":"CCu","name":"[00] -rwx section size 65536 named .textbss"}
        db["comments"] = [{
            "module": module, # The module that the comment is in
            "address": hex(c["offset"] - base_addr), # Comment address relative to the base of the module
            "manual": True, # Whether the comment was created by the user - set to True to show it in the comments window
            "text": c["name"], # Comment text
        } for c in cutter.cmdj("CCj")]
        cutter.message("[x64dbg-cutter]: %d comment(s) exported" % len(db["comments"]))

        # Set flagspace to all before iterating over fj to show all of the flags
        cutter.cmd("fs *")

        # ref: {"name":"fcn.1400113de","size":5,"offset":5368779742}
        db["labels"] = [{
            "module": module, # The module that the label is in
            "address": hex(label["offset"] - base_addr), # Label address relative to the base of the module
            "manual": False, # Whether the label was created by the user
            "text": label["name"], # Label text
        } for label in cutter.cmdj("fj") if (label["offset"] - base_addr) >= 0]
        cutter.message("[x64dbg-cutter]: %d labels(s) exported" % len(db["labels"]))

        with open(filename, "w") as outfile:
            json.dump(db, outfile, indent=1)
Пример #3
0
    def load_architecture(self, name):
        # fix name
        name = name.lower()
        if name.startswith("x86"):
            name = "x86-64"
        if name.startswith("arm"):
            name = "arm"

        self.arch = name

        path = self.base_path
        dbpath = os.path.join(path, "archs", name + ".sql")

        if (not os.path.isfile(dbpath)):
            cutter.message("Manual not found for architecture: %s" % name)
            return False

        con = sq.connect(":memory:")
        con.text_factory = str
        con.executescript(open(dbpath).read())

        cur = con.cursor()
        cur.execute("SELECT mnem, description FROM instructions")
        con.commit()

        rows = cur.fetchall()
        for row in rows:
            inst = row[0]
            lines = row[1].replace("\r\n", "\n").split("\n")

            self.inst_map[inst] = lines

        con.close()

        for (inst, data) in self.inst_map.items():
            data = data[0]

            if (data[0:3] == "-R:"):
                ref = data[3:]

                if (ref in self.inst_map):
                    self.inst_map[inst] = self.inst_map[ref]

        cutter.message("Manual loaded for architecture: %s" % name)
        return True
    def file_dialog(self, title, new=False):
        file_dialog = QtWidgets.QFileDialog(self.main, title,
                                            self._last_directory,
                                            'Databases (*.dd64)')

        if new:
            filename = file_dialog.getSaveFileName()[0]
        else:
            file_dialog.setFileMode(QtWidgets.QFileDialog.ExistingFile)
            filename = file_dialog.getOpenFileName()[0]

        # Remember the last directory we were in (parsed from a selected file)
        # for the next time the user comes to load coverage files
        if filename:
            self._last_directory = os.path.dirname(filename) + os.sep

        cutter.message("[w64dbg-cutter] Received filename from file dialog:")
        cutter.message(" - %s" % filename)

        return filename
Пример #5
0
    def file_dialog(self, title, new=False):
        if new:
            filename = QtWidgets.QFileDialog.getSaveFileName(
                self.main, title, self._last_directory, X64DBG_FILE_FILTERS)[0]
            # Append x64dbg's file prefix to the saved file
            # NOTE: This solution isn't ideal but preferred filename isn't available in
            # PySide's QtFileDialog constructor
            if not re.findall(".dd(64|32)", filename):
                bitness = cutter.cmdj("elJ asm.bits")[0]["value"]
                filename += f".dd{bitness}"
        else:
            filename = QtWidgets.QFileDialog.getOpenFileName(
                self.main, title, self._last_directory, X64DBG_FILE_FILTERS)[0]


        # Remember the last directory we were in (parsed from a selected file)
        # for the next time the user comes to load coverage files
        if filename:
            self._last_directory = os.path.dirname(filename) + os.sep

        cutter.message("[w64dbg-cutter] Received filename from file dialog:")
        cutter.message(" - %s" % filename)

        return filename
Пример #6
0
 def handle_disassembler_action(self):
     # for actions in plugin menu Cutter sets data to address for current dissasembly line
     cutter.message("Dissasembly menu action callback 0x{:x}".format(
         self.disas_action.data()))
Пример #7
0
 def handle_addressable_item_action(self):
     # for actions in plugin menu Cutter sets data to current item address
     submenu_action = self.addr_submenu.menuAction()
     cutter.message("Context menu action callback 0x{:x}".format(
         submenu_action.data()))
Пример #8
0
    def log(self, msg):
        """log to cutter console

        @param msg: message to log
        """
        cutter.message(f"[CAPAExplorer]: {msg}")
Пример #9
0
def log(msg):
    """log to cutter console

    @param msg: message to log
    """
    cutter.message(f"[capa explorer]: {msg}")
Пример #10
0
def create_cutter_plugin():
    try:
        return CAPAExplorerPlugin()
    except Exception as e:
        cutter.message(str(e))
    def import_db(self):
        filename = self.file_dialog("Open x64dbg (Uncompressed) JSON database")
        if not filename:
            return

        cutter.message("[x64dbg-cutter]: Importing database %s" % filename)

        with open(filename) as dbdata:
            db = json.load(dbdata)

        # We can only import symbols for the main binary currently
        module = os.path.basename(cutter.cmdj("ij")["core"]["file"]).lower()
        base_addr = cutter.cmdj("evj bin.baddr")[0]["value"]

        count = 0
        breakpoints = db.get("breakpoints", [])
        for bp in breakpoints:
            try:
                if bp["module"] != module:
                    continue
                address = int(bp["address"], 16) + base_addr
                cutter.cmd("dbs " + str(address))
                # Breakpoints created by dbs are enabled by default
                if not bp["enabled"]:
                    cutter.cmd("dbd " + str(address))
                count += 1
            except:
                cutter.message("[x64dbg-cutter]: " + traceback.format_exc())
        cutter.message("[x64dbg-cutter]: %d/%d breakpoints(s) imported" %
                       (count, len(breakpoints)))

        count = 0
        comments = db.get("comments", [])
        for comment in comments:
            try:
                if comment["module"] != module:
                    continue
                address = int(comment["address"], 16) + base_addr
                text = base64.b64encode(
                    comment["text"].encode("utf-8")).decode()
                cutter.cmd("CCu base64:" + text + " @ " + str(address))
                count += 1
            except:
                cutter.message("[x64dbg-cutter]: " + traceback.format_exc())
        cutter.message("[x64dbg-cutter]: %d/%d comment(s) imported" %
                       (count, len(comments)))

        # Create a new flagspace for x64dbg labels and bookmarks to allow easy removal
        cutter.cmd("fs x64dbgcutter.labels")
        count = 0
        labels = db.get("labels", [])
        for label in labels:
            try:
                if label["module"] != module:
                    continue
                address = int(label["address"], 16) + base_addr
                # Spaces don't show up in flags, use underscore instead
                text = label["text"].replace(" ", "_")
                cutter.cmd("f " + text + " @ " + str(address))
                count += 1
            except:
                cutter.message("[x64dbg-cutter]: " + traceback.format_exc())
        cutter.message("[x64dbg-cutter]: %d/%d label(s) imported" %
                       (count, len(labels)))

        cutter.cmd("fs x64dbgcutter.bookmarks")
        count = 0
        bookmarks = db.get("bookmarks", [])
        for bookmark in bookmarks:
            try:
                if bookmark["module"] != module:
                    continue
                address = int(bookmark["address"], 16) + base_addr
                cutter.cmd("f " + "bookmark_" + str(address) + " @ " +
                           str(address))
                count += 1
            except:
                cutter.message("[x64dbg-cutter]: " + traceback.format_exc())
        cutter.message("[x64dbg-cutter]: %d/%d bookmark(s) imported" %
                       (count, len(bookmarks)))

        cutter.message("[x64dbg-cutter]: Done!")