Exemple #1
0
    def collare_export(self):
        project_path = cutter.cmd("e prj.file")
        if ".collare_projects" in project_path:
            base_addr = int(json.loads(cutter.cmd("iSj"))[0]["vaddr"])
            changes = {"function_names": {}, "comments": {}, "base": base_addr}
            functions = cutter.cmd("afij @@F")
            functions = functions.replace("]\n[", ",")
            functions = json.loads(functions)
            for function in functions:
                if hex(function["offset"])[2:] not in function["name"]:
                    # Non-default function names
                    changes["function_names"][function["offset"]] = {
                        "name": function["name"],
                        "end": function["offset"] + function["size"]
                    }

            comments = cutter.cmd("CCfj @@F")
            comments = comments.replace("[]\n", "").replace("]\n[", ",")
            comments = json.loads(comments)
            for comment in comments:
                changes["comments"][comment["offset"]] = comment["name"]
            with open(
                    os.path.join(os.path.dirname(project_path),
                                 "changes.json"), "w") as changes_file:
                json.dump(changes, changes_file)
            QMessageBox.information(self.main, "CollaRE", "Export Done!",
                                    QMessageBox.Ok)
        else:
            QMessageBox.warning(self.main, "CollaRE", "Not a CollaRE project!",
                                QMessageBox.Ok)
Exemple #2
0
 def generate_local_data_references(self):
     # aga
     function_name = self.get_output_name("data_references", function=True)
     command = "aga" + self.get_output_format_cmd(self.combo.currentIndex())
     command += " > "
     command += function_name
     cutter.cmd(command)
Exemple #3
0
 def generate_xrefs(self):
     # agx
     function_name = self.get_output_name("xrefs", function=True)
     command = "agx" + self.get_output_format_cmd(self.combo.currentIndex())
     command += " > "
     command += function_name
     cutter.cmd(command)
Exemple #4
0
 def generate_local_callgraph(self):
     # agc
     function_name = self.get_output_name("callgraph", function=True)
     command = "agc" + self.get_output_format_cmd(self.combo.currentIndex())
     command += " > "
     command += function_name
     cutter.cmd(command)
Exemple #5
0
def print_data(data, offset):
    cleaned = ""
    for c in data:
        if (ord(c) <= 0x7f and ord(c) >= 0x20):
            cleaned += c
    if len(cleaned) >= 3:
        print('%d - Hidden String: "%s"' % (offset, cleaned))
        cutter.cmd('CC Hidden String: \"%s\" @ %d' % (cleaned, offset))
Exemple #6
0
    def setAvoidAddr(self):
        offset = int(self.avoidAddrAction.data())
        if offset in self.avoidAddrs or offset in self.findAddrs or offset in self.symAddrs:
            print("[angr-cutter] Address %s was already set" % hex(offset))
            return

        self.avoidAddrs.append(offset)
        self.updateAvoidAddrLine()
        cutter.cmd("ecHi yellow @ %d" % offset)
Exemple #7
0
def radare_crawl():
    funcs = json.loads(cutter.cmd('aflj'))
    for func in funcs:
        try:
            instructions = json.loads(
                cutter.cmd('pdfj %s @ %s' % (func['size'], func['offset'])))
        except ValueError as e:
            continue
        mov_hunt(instructions)
Exemple #8
0
    def setAvoidAddr(self):
        offset = int(self.avoidAddrAction.data())
        if offset in self.avoidAddrs or offset in self.findAddrs or offset in self.symAddrs:
            printMessage("Address %s was already set" %
                         hex(offset), LogLevel.WARNING)
            return

        self.avoidAddrs.append(offset)
        self.updateAvoidAddrLine()
        cutter.cmd("ecHi yellow @ %d" % offset)
    def runSomethingInThread(self):
        ## you see print only on console if you start cutter from console
        print('send from threadd')

        ### next line freeze cutter, not everytime for the first time,
        ### sometimes it runs 2,3 times ,then freezes
        curr_pos = cutter.cmd('s')

        time.sleep(5)
        curr_pos = cutter.cmd('s')

        print('send from thread after time')
        self.resultReady.emit()
Exemple #10
0
    def unsetAddr(self):
        offset = self.unsetAddrAction.data()
        if offset in self.findAddrs:
            self.findAddrs.remove(offset)
            self.updateFindAddrLine()
        if offset in self.avoidAddrs:
            self.avoidAddrs.remove(offset)
            self.updateAvoidAddrLine()
        if offset in self.symAddrs:
            del self.symAddrs[offset]
            self.updateSymAddrLine()

        cutter.cmd("ecH- @ %d" % offset)
Exemple #11
0
    def setSymAddr(self):
        offset = int(self.symAddrAction.data())
        if offset in self.avoidAddrs or offset in self.findAddrs or offset in self.symAddrs:
            printMessage("Address %s was already set" %
                         hex(offset), LogLevel.WARNING)
            return

        dialog = SymAddrDialog()
        dialog.exec_()
        size = dialog.getSize()

        self.symAddrs[offset] = size
        self.updateSymAddrLine()
        cutter.cmd("ecHi black @ %d" % offset)
Exemple #12
0
    def update_content(self):
        current_line = cutter.cmdj("pdj 1")[0]

        # Running "ij" during DockWidget init causes a crash
        if not self.cutterref:
            info = cutter.cmdj("ij")["bin"]
            arch = info["arch"]
            self.cutterref = CutterRef(info["arch"] + "-" + str(info["bits"]))

        try:
            inst = current_line["disasm"].split()[0]
        except:
            return

        # Don't update the text box for the same instruction
        if inst != self.previous_inst:
            doc = self.cutterref.get_instruction_doc(inst)
            # Use r2's documentation if the instruction wasn't found in the loaded manual
            if not doc:
                doc = cutter.cmd("aod @ " + str(current_line["offset"]))

            self.view.setHtml(doc)
            self.previous_inst = inst

        return
Exemple #13
0
    def setSymAddr(self):
        offset = int(self.symAddrAction.data())
        if offset in self.avoidAddrs or offset in self.findAddrs or offset in self.symAddrs:
            print("[angr-cutter] Address %s was already set" % hex(offset))
            return

        text, ok = QInputDialog.getText(self, "Symbolize address",
                                        "Size(bytes):")
        if ok:
            size = int(text)
        else:
            size = 8

        self.symAddrs[offset] = size
        self.updateSymAddrLine()
        cutter.cmd("ecHi black @ %d" % offset)
Exemple #14
0
 def output_callgraph(self):
     output = 'deep_callgraph_' + cutter.cmd(
         'afi.') + self.get_output_format_extension(
             self.combo.currentIndex())
     file = open(output, "w")
     file.write(self.graph_dot)
     file.close()
Exemple #15
0
 def send_to_mixto(self):
     if self.mixto_entry_id is not None:
         arg = self.command[0:70]
         out = cutter.cmd(self.command).strip()
         url = urljoin(
             self.mixto_host,
             "/api/entry/{}/{}/commit".format(self.workspace,
                                              self.mixto_entry_id),
         )
         req = Request(
             method="POST",
             url=url,
             data=dumps({
                 "type": "tool",
                 "title": "(Cutter) - " + arg,
                 "data": out,
                 "meta": {},
             }).encode(),
             headers={
                 "x-api-key": self.mixto_api,
                 "Content-Type": "application/json",
             },
         )
         try:
             res = urlopen(req)
             status = res.getcode()
             if status > 300:
                 self.message.setText("{} error".format(status))
             else:
                 self.message.setText("OK!")
         except HTTPError as e:
             self.message.setText(getattr(e, "message", repr(e)))
     else:
         self.message.setText("Entry ID not provided")
Exemple #16
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)
Exemple #17
0
 def get_reg(self, name):
     if name == "efl":
         name = "eflags"
     reg = cutter.cmd("dr " + name)
     # Large regs(over 80bits) are returned as hex
     if "0x" in reg:
         val = int(reg, 16)
     else:
         val = int(reg)
     return val
Exemple #18
0
    def startExplore(self):
        if len(self.findAddrs) == 0:
            printMessage(
                "You have to set a find address to explore to", LogLevel.WARNING)
            return

        self.stateMgr = StateManager()
        self.simMgr = self.stateMgr.simulation_manager()

        # Configure symbolic memory addresses and registers
        for addr in self.symAddrs:
            self.stateMgr.sim(addr, self.symAddrs[addr])
        for reg in self.viewRegisters.symRegs:
            self.stateMgr.sim(
                self.stateMgr[reg], self.viewRegisters.symRegs[reg])

        # Start exploration
        printMessage("Starting exploration with find (%s) and avoid (%s)" %
                     (self.findAddrs, self.avoidAddrs,), LogLevel.INFO)
        printMessage("Symbolics are: " +
                     str(self.stateMgr.symbolics), LogLevel.INFO)
        self.simMgr.explore(find=self.findAddrs, avoid=self.avoidAddrs)

        # Attempt to print the results
        if len(self.simMgr.found):
            printMessage("Found: " + str(self.simMgr.found[0]), LogLevel.INFO)

            conc = self.stateMgr.concretize(self.simMgr.found[0])
            for addr in conc:
                printMessage("0x%x ==> %s" %
                             (addr, repr(conc[addr])), LogLevel.INFO)

            self.applySimButton.setDisabled(False)
        else:
            printMessage("Failed to find a state", LogLevel.ERROR)
            self.applySimButton.setDisabled(True)

        # Synchronize displays
        cutter.core().refreshAll.emit()
        # Return to the previous seek
        cutter.cmd("s %d" % cutter.core().getProgramCounterValue())
Exemple #19
0
def smart_rename_function(location, name):

    # Get function info
    function_info = cutter.cmdj('afij @%s' % location)

    if not len(function_info):
        # no function at location, trigger analysis
        # and refetch function info
        cutter.cmd('af @ %s' % location)
        function_info = cutter.cmdj('afij @%s' % location)

    old_fn_name = function_info[0]['name']

    # Sometimes the vivisect feature extractor identifies
    # adresses in the middle of functions as function starts
    # for some reason. We get the actual addr with r2.
    actual_offset = function_info[0]['offset']

    if old_fn_name.startswith('fcn.'):
        # Function has default name, replace all of it.
        cutter.cmd('afn {} @ {}'.format(name, actual_offset))
    else:
        # Function does not have generic name keep old name as prefix
        name = f'{old_fn_name}__{name}'
        cutter.cmd('afn {} @ {}'.format(name, actual_offset))
Exemple #20
0
 def collare_import(self):
     project_path = cutter.cmd("e prj.file")
     if ".collare_projects" in project_path:
         with open(
                 os.path.join(os.path.dirname(project_path),
                              "changes.json"), "r") as changes_file:
             changes = json.load(changes_file)
             base = changes["base"]
             if base != int(json.loads(cutter.cmd("iSj"))[0]["vaddr"]):
                 base = int(json.loads(
                     cutter.cmd("iSj"))[0]["vaddr"]) - base
             else:
                 base = 0
             for comment in changes["comments"]:
                 comment_address = int(comment, 10) + base
                 current_comment = self.get_comment_at(comment_address)
                 if current_comment:
                     if self.get_comment_at(comment_address) in changes[
                             "comments"][comment]:
                         self.set_comment_at(comment_address,
                                             changes["comments"][comment])
                     elif changes["comments"][comment] in current_comment:
                         pass
                     else:
                         self.set_comment_at(
                             comment_address, current_comment + "; " +
                             changes["comments"][comment])
                 else:
                     self.set_comment_at(comment_address,
                                         changes["comments"][comment])
             for function in changes["function_names"]:
                 self.rename_function(
                     int(function, 10) + base,
                     changes["function_names"][function]["name"])
         QMessageBox.information(self.main, "CollaRE", "Import Done!",
                                 QMessageBox.Ok)
     else:
         QMessageBox.warning(self.main, "CollaRE", "Not a CollaRE project!",
                             QMessageBox.Ok)
Exemple #21
0
 def get_output_name(self, graph_name, function=False):
     if not function:
         name = graph_name + "." + self.get_output_format_extension(
             self.combo.currentIndex())
         return self.append_to_path(name)
     else:
         function_name = cutter.cmd('afi.')
         function_name = function_name.replace("\n", "")
         function_name += "_"
         function_name += graph_name
         function_name += "."
         function_name += self.get_output_format_extension(
             self.combo.currentIndex())
         return self.append_to_path(function_name)
Exemple #22
0
 def generate_callgraph(self):
     # TODO: get user settings for the .dot graph instead of using this hardcoded settings
     self.graph_dot = """digraph code {
     rankdir=LR;
     outputorder=edgesfirst;
     graph [bgcolor=azure fontname="Courier" splines="curved"];
     node [fillcolor=white style=filled fontname="Courier New Bold" fontsize=14 shape=box];
     edge [arrowhead="normal" style=bold weight=2];"""
     self.used_nodes = []
     function_name = cutter.cmd('afi.')
     function_name = function_name.replace("\n", "")
     self.functions_list = cutter.cmdj('aflmj')
     self.get_calls(function_name)
     self.graph_dot += '\n}'
Exemple #23
0
    def decodeAll(self):
        # Start with analysis
        cutter.cmd('aa')

        # Build the decoder table
        self.buildDecoderTable()

        # Dump all the strings passed to decoder function
        for xref in cutter.cmdj("axtj %d" % self.decoder['fcn']):
            xref_addr = xref['from']
            arg_len, arg_offsets = cutter.cmdj("pdj -2 @ %d" % xref_addr)

            if not 'val' in arg_len:
                continue

            indexes = cutter.cmdj("pxj %d @ %d" % (arg_len['val'] * 2, arg_offsets['val']))
            decoded_str = self.decode(indexes)

            #print("%s @ %s" % (decoded_str, hex(xref_addr)))
            cutter.cmd("CC Decoded: %s @ %d" % (decoded_str, xref_addr))

        # Refresh interface
        cutter.refresh()
Exemple #24
0
 def resolve_name(self, name):
     try:
         modules = cutter.cmdj("dmmj")
         for m in modules[1:]:
             addr = m["address"]
             lib = os.path.basename(m["name"]).split(".")[0].split("-")[0]
             o = cutter.cmd("dmi* %s %s" % (lib, name))
             for line in o.split("\n"):
                 line = line.split()
                 if len(line) < 4:
                     continue
                 if line[1] == name or line[3] == "sym." + name:
                     return int(line[3], 16)
     except:
         pass
     return None
def decode_strings(verbose=True):

    if verbose:
        print("\n%s\n\tStarting the decode of the encrypted strings\n%s\n\n" %
              ('~'*60, '~'*60))

    # Declaration of decryption-table related variables
    decryption_table = 0x41BA3C
    decryption_table_end = 0x41BA77
    decryption_table_len = decryption_table_end - decryption_table
    decryption_function = 0x4012A0

    # Analyze the binary to better detect functions and x-refs
    cutter.cmd('aa')

    # Rename the decryption function
    cutter.cmd('afn decryption_function %d' % decryption_function)

    # Dump the decryption table to a variable
    decryption_table_content = cutter.cmdj(
        "pxj %d @ %d" % (decryption_table_len, decryption_table))

    # Iterate x-refs to the decryption function
    for xref in cutter.cmdj('axtj %d' % decryption_function):
        # Get the arguments passed to the decryption function: length and encrypted string
        length_arg, offsets_arg = cutter.cmdj('pdj -2 @ %d' % (xref['from']))

        # String variable to store the decrypted string
        decrypted_string = ""

        # Guard rail to avoid exception
        if (not 'val' in length_arg):
            continue

        # Manually decrypt the encrypted string
        for i in range(0, length_arg['val']):
            decrypted_string += chr(decryption_table_content[cutter.cmdj(
                'pxj 1 @ %d' % (offsets_arg['val'] + (i*2)))[0]])

        # Print the decrypted and the address it was referenced to the console
        if verbose:
            print(decrypted_string + " @ " + hex(xref['from']))

        # Add comments to each call of the decryption function
        cutter.cmd('CC Decrypted: %s @ %d' % (decrypted_string, xref['from']))
Exemple #26
0
    def debugStateChanged(self):
        # Calculate the diff based on the previous baddr
        baddr = int(cutter.cmd("e bin.baddr").strip('\n'), 16)
        diff = baddr - self.baddr
        self.baddr = baddr

        if cutter.core().currentlyDebugging:
            disableUi = False
        else:
            del self.stateMgr
            self.stateMgr = None
            disableUi = True
            # applySim can be enabled only after startExplore
            self.applySimButton.setDisabled(True)

        # Enable exploration action when in debug mode
        self.startButton.setDisabled(disableUi)
        self.stopButton.setDisabled(disableUi)

        # Rebase addresses
        tmp = []
        for addr in self.findAddrs:
            tmp.append(addr + diff)
        self.findAddrs = tmp

        tmp = []
        for addr in self.avoidAddrs:
            tmp.append(addr + diff)
        self.avoidAddrs = tmp

        tmp = {}
        for addr in self.symAddrs:
            tmp[addr + diff] = self.symAddrs[addr]
        self.symAddrs = tmp

        self.update()
Exemple #27
0
 def generate_imports_graph(self):
     # agi
     name = self.get_output_name("imports_refs")
     command = "agi" + self.get_output_format_cmd(self.combo.currentIndex())
     cutter.cmd(command + " > " + name)
Exemple #28
0
 def generate_global_refs(self):
     # agR
     name = self.get_output_name("global_references")
     command = "agR" + self.get_output_format_cmd(self.combo.currentIndex())
     cutter.cmd(command + " > " + name)
Exemple #29
0
 def generate_global_callgraph(self):
     # agC
     name = self.get_output_name("global_callgraph")
     command = "agC" + self.get_output_format_cmd(self.combo.currentIndex())
     cutter.cmd(command + " > " + name)
Exemple #30
0
 def generate_fortune(self):
     fortune = cutter.cmd("fo").replace("\n", "")
     res = cutter.core().cmdRaw(f"?E {fortune}")
     self.text.setText(res)