def visit_MLIL_CONST_PTR(self, expr):
        log.log_debug(f'MLIL_CONST_PTR: {expr.constant:x}')
        view = expr.function.source_function.view
        symbol = view.get_symbol_at(expr.constant)
        string = view.get_string_at(expr.constant)

        if string is not None:
            return [
                InstructionTextToken(InstructionTextTokenType.StringToken,
                                     repr(string.value), string.start)
            ]

        elif symbol is not None:
            NormalSymbols = (SymbolType.FunctionSymbol, SymbolType.DataSymbol)
            ImportSymbols = (SymbolType.ImportedFunctionSymbol,
                             SymbolType.ImportedDataSymbol)

            return [
                InstructionTextToken(
                    (InstructionTextTokenType.CodeSymbolToken if symbol.type
                     in NormalSymbols else InstructionTextTokenType.ImportToken
                     if symbol.type in ImportSymbols else
                     InstructionTextTokenType.PossibleAddressToken),
                    symbol.short_name,
                    expr.constant,
                    size=expr.size,
                    address=expr.address)
            ]
예제 #2
0
파일: ui.py 프로젝트: Vector35/debugger
    def __init__(self, state):
        self.state = state
        self.debug_view = None
        self.last_ip = 0
        self.regs = []
        self.stack = []

        registers_widget = self.widget("Debugger Registers")
        modules_widget = self.widget("Debugger Modules")
        threads_widget = self.widget("Debugger Threads")
        stack_widget = self.widget("Debugger Stack")
        bp_widget = self.widget("Debugger Breakpoints")
        #console_widget = self.widget('Debugger Console')

        if registers_widget is None or modules_widget is None or threads_widget is None or stack_widget is None or bp_widget is None:
            # One of the views failed to create, bail
            log_debug(
                "Creating Debugger UI for view with missing dock widgets!")
            return

        # Initial view data
        self.context_display()
        self.update_highlights()
        self.update_breakpoints()
        Settings().register_group("debugger", "Debugger")
        key = 'debugger.extra_annotations'
        if not Settings().contains(key):
            Settings().register_setting(
                key,
                '{"description" : "Enables automatic additional annotations to be added to the start of functions that will persist after the debugger has moved away. Must break or step across the start of a function to trigger. Currently uses comments but will be migrated to ephemeral comments when that system is finished.", "title" : "Debugger Function Start Annotations", "default" : false, "type" : "boolean"}'
            )
예제 #3
0
    def run(self):
        if self.context == None:
            log_warn("Cannot run snippets outside of the UI at this time.")
            return
        if self.snippetChanged():
            question = QMessageBox.question(
                self, self.tr("Confirm"),
                self.tr("You have unsaved changes, must save first. Save?"))
            if (question == QMessageBox.StandardButton.No):
                return
            else:
                self.save()
        actionText = actionFromSnippet(self.currentFile,
                                       self.snippetDescription.text())
        UIActionHandler.globalActions().executeAction(actionText, self.context)

        log_debug("Saving snippet %s" % self.currentFile)
        outputSnippet = codecs.open(self.currentFile, "w", "utf-8")
        outputSnippet.write("#" + self.snippetDescription.text() + "\n")
        outputSnippet.write("#" +
                            self.keySequenceEdit.keySequence().toString() +
                            "\n")
        outputSnippet.write(self.edit.toPlainText())
        outputSnippet.close()
        self.registerAllSnippets()
예제 #4
0
 def loadSnippet(self):
     self.currentFileLabel.setText(QFileInfo(self.currentFile).baseName())
     log_debug("Loading %s as a snippet." % self.currentFile)
     (snippetDescription, snippetKey, snippetCode) = loadSnippetFromFile(self.currentFile)
     self.snippetDescription.setText(snippetDescription) if snippetDescription else self.snippetDescription.setText("")
     self.keySequenceEdit.setKeySequence(snippetKey[0]) if len(snippetKey) != 0 else self.keySequenceEdit.setKeySequence(QKeySequence(""))
     self.edit.setPlainText(snippetCode) if snippetCode else self.edit.setPlainText("")
예제 #5
0
    def run(self):
        if len(self.bv.platform.type_libraries) == 0:
            log_warn(f"No type libraries loaded for: {self.bv.platform.name}")
            return

        for sym in self.bv.get_symbols_of_type(SymbolType.ImportedFunctionSymbol):
            # log_debug(f"checking sym: {sym.name}")
            for typelib in self.bv.platform.type_libraries:
                sym_type = typelib.get_named_object(sym.name)

                # log_debug(f"Checking in typelib: {typelib}")

                if sym_type == None:
                    continue

                # log_debug(f"Found type type: {sym_type}")

                func = self.bv.get_function_at(sym.address)
                if func == None:
                    continue

                func.set_user_type(sym_type)
                log_debug("Updated sym %s at 0x%02X" % (sym.name, sym.address))

        self.bv.update_analysis_and_wait()
예제 #6
0
 def deleteSnippet(self):
     selection = self.tree.selectedIndexes()[::self.columns][0] #treeview returns each selected element in the row
     snippetName = self.files.fileName(selection)
     question = QMessageBox.question(self, self.tr("Confirm"), self.tr("Confirm deletion: ") + snippetName)
     if (question == QMessageBox.StandardButton.Yes):
         log_debug("Deleting snippet %s." % snippetName)
         self.clearSelection()
         self.files.remove(selection)
예제 #7
0
 def save(self):
     log_debug("Saving snippet %s" % self.currentFile)
     outputSnippet = open(self.currentFile, "w")
     outputSnippet.write("#" + self.snippetDescription.text() + "\n")
     outputSnippet.write("#" + self.keySequenceEdit.keySequence().toString() + "\n")
     outputSnippet.write(self.edit.toPlainText())
     outputSnippet.close()
     self.registerAllSnippets()
예제 #8
0
    def rename(self):
        renamed = 0
        newprocfn = self.bv.get_symbol_by_raw_name("go.runtime.newproc")
        xrefs = self.bv.get_code_refs(newprocfn.address)
        for xref in xrefs:
            log_info("found xref at 0x{:x}".format(xref.address))
            addr = xref.address
            fn = self.get_function_around(addr)
            callinst = fn.get_low_level_il_at(addr)
            if callinst.operation != bn.LowLevelILOperation.LLIL_CALL:
                log_debug("not a call instruction {!r}".format(callinst))
                continue
            params = []
            # FIXME: this is such a dirty hack
            # get the previous two LIL instruction
            j = 1
            while len(params) < 2:
                for i in range(1, 7):
                    try:
                        j += 1
                        inst = fn.get_low_level_il_at(addr - j)
                        log_debug("instruction: -{} {!r}".format(j, inst))
                        break
                    except IndexError:
                        continue
                params.append(inst)

            # FIXME: does this work on non-x86?
            # check if 2 push instructions
            skip = True
            for inst in params:
                if inst.operation != bn.LowLevelILOperation.LLIL_PUSH:
                    skip = True
            if skip:
                continue

            # get the address of the function pointer, which should be the
            # second push instruction
            inst = params[1]
            fptr = inst.src.value.value
            log_info("found call to newproc {!r} with fptr {!r}".format(
                callinst, fptr))

            if fptr and not self.bv.get_symbol_at(fptr):
                a = self.get_pointer_at_virt(fptr)
                # target function
                tfn = self.bv.get_function_at(a)
                if tfn:
                    varname = "fptr_"
                    varname += sanitize_var_name(tfn.name)
                    t = self.bv.parse_type_string("void*")
                    self.bv.define_user_data_var(a, t[0])
                    sym = bn.types.Symbol('DataSymbol', a, varname, varname)
                    self.bv.define_user_symbol(sym)
                    renamed += 1

        log_info(
            "renamed {} function pointers, passed to newproc".format(renamed))
예제 #9
0
def bb_mlil_analysis(bv, bb, og_bb_start, metadata):
    """Check authenticity of instructions in MLIL.

    Args:
        bv (BinaryView): top-level binary view handler. Lots of
                         interesting methods can be accessed.
        bb (list): list of MLIL instructions.
        og_bb_start (long): address of where original basic block starts.
        isa_specific_data (dict): None or dictionary containing isa-specific
                                  info. Read in from
                                  "storage/non_generic_spec.json".

    Returns:
        bool: True if content of bb doesn't make sense. False if it's a legit.
    """
    bb = bb2ilbb(bb, 'mlil', bv)
    if not bb:
        return False

    # first bb's instruction; instr.address
    faulting_addr = og_bb_start

    # check if isa is supported. If not, do not run this analysis
    isa_specific_data = metadata.spec['isa'].get(bv.arch.name)

    # result
    alerted_rules = list()

    #    # rule: def_no_use_dep
    #    if def_no_use_dep(bb, bv, isa_specific_data):
    #        log_debug(
    #            ('* def_no_use_dep: ' + 'bb start( 0x{0:02X} ) ' +
    #             'instr addr( 0x{1:02X} )').format(faulting_addr,
    #                                               faulting_addr))
    #        alerted_rules.append('def_no_use_dep')

    for instr in bb:

        if instr.operation.name == 'MLIL_STORE':

            # rule: memaccess_self
            if memaccess_self(instr.ssa_form):
                log_debug(
                    ('* memaccess_self: ' + 'bb start( 0x{0:02X} ) ' +
                     'instr addr( 0x{1:02X} )').format(faulting_addr,
                                                       instr.address))
                alerted_rules.append('memaccess_self')


#        # rule: conditional_unused
#        if conditional_unused(instr):
#            log_debug(
#                ('* conditional_unused: ' + 'bb start( 0x{0:02X} ) ' +
#                 'instr addr( 0x{1:02X} )').format(faulting_addr,
#                                                   instr.address))
#            alerted_rules.append('conditional_unused')

    return alerted_rules
def type_discrepency_ptr_in_mult_div(instr):
    """
    """
    log_debug("[type_discrepency_ptr_in_mult_div]: entry " +
              hex(instr.address))
    # check if it is multiply or division operation
    if instr.operation.name != 'LLIL_SET_REG':
        return False
    if instr.src.operation.value not in range(36, 43):
        # division and multiply values
        # LLIL_MUL, LLIL_MULU_DP, LLIL_MULS_DP, LLIL_DIVU
        # LLIL_DIVU_DP, LLIL_DIVS, LLIL_DIVS_DP
        return False

    # check if reg is also used as memory pointer
    # reg_oi: register of interest
    reg_oi = instr.ssa_form.dest
    if isinstance(reg_oi, ILRegister):
        return False
    log_debug("[type_discrepency_ptr_in_mult_div]: reg_io " + repr(reg_oi) +
              " at " + hex(instr.address))
    for reg_use_il in instr.function.get_ssa_reg_uses(reg_oi):
        # dereference in destination
        mem_dest_struct = Tree(
            llil_type='LLIL_STORE',
            childs=[Tree(llil_type='LLIL_REG', childs=[Tree(llil_type='F')])])
        # dereference in source
        mem_src_struct = Tree(
            llil_type='LLIL_LOAD',
            childs=[Tree(llil_type='LLIL_REG', childs=[Tree(llil_type='F')])])

        # check for dereference in destination
        llil_tree = Tree()
        llil2tree(reg_use_il, llil_tree)
        if ((match_tree(mem_dest_struct, llil_tree)
             and mem_dest_struct.childs[0].childs[0].llil_type == str(
                 reg_oi.reg))):
            if reg_use_il.size == 1:
                # memory access size is same as counter size. So, it is okay
                return False
            return True

        # check for dereference in source
        if not hasattr(reg_use_il, 'src'):
            return False
        llil_tree = Tree()
        llil2tree(reg_use_il.src, llil_tree)
        if ((match_tree(mem_src_struct, llil_tree) and
             mem_src_struct.childs[0].childs[0].llil_type == str(reg_oi.reg))):
            load_ils = list()
            get_type(reg_use_il.src, LowLevelILInstruction, 'LLIL_LOAD',
                     load_ils, 'operation.name')
            for li in load_ils:
                if li.dest.reg == reg_oi.reg and li.size == 1:
                    return False
            return True
    return False
예제 #11
0
    def kaitaiParse(self, ksModuleName=None):
        log.log_debug('kaitaiParse() with len(bv)=%d and bv.file.filename=%s' %
                      (len(self.binaryView), self.binaryView.file.filename))

        if len(self.binaryView) == 0:
            return

        kaitaiIO = kshelpers.KaitaiBinaryViewIO(self.binaryView)
        parsed = kshelpers.parseIo(kaitaiIO, ksModuleName)
        if not parsed:
            return

        # it SEEMS as if parsing is finished at this moment, but some parsing
        # is postponed until attributes are accessed, so we must try/catch here
        tree = None
        if True:
            try:
                tree = kshelpers.buildQtree(parsed)
            except Exception as e:
                log.log_error(
                    'kaitai module %s threw exception, check file type' %
                    ksModuleName)
                tree = None
        else:
            tree = kshelpers.buildQtree(parsed)

        if not tree:
            return

        self.ioRoot = tree.ksobj._io
        self.ioCurrent = tree.ksobj._io

        self.treeWidget.clear()
        self.treeWidget.setSortingEnabled(False)  # temporarily, for efficiency
        # two options with how we create the hierarchy
        if False:
            # treat root as top level "file" container
            tree.setLabel('file')
            tree.setValue(None)
            tree.setStart(0)
            tree.setEnd(0)
            self.treeWidget.insertTopLevelItem(0, tree)
        else:
            # add root's children as top level items
            self.treeWidget.insertTopLevelItems(0, tree.takeChildren())

        # enable sorting
        self.treeWidget.setSortingEnabled(True)
        self.treeWidget.sortByColumn(2, Qt.AscendingOrder)

        # TODO: select first item, maybe expand a few things
        self.rootSelectionStart = 0
        self.rootSelectionEnd = 1

        self.treeWidget.setUniformRowHeights(True)
        self.treeWidget.queueInitialPresentation = True
예제 #12
0
 def read_cstring(self, address):
     self.br.seek(address)
     st = ""
     while "\x00" not in st and len(st) < 0x1000:
         x = self.br.read(255)
         if x:
             st += x
             self.br.seek(address + len(st))
         else:
             break
         log_debug("{!r}".format(st))
     return st
예제 #13
0
 def read_cstring(self, address):
     self.br.seek(address)
     st = b""
     while b"\x00" not in st and len(st) < 0x1000:
         x = self.br.read(255)
         if x:
             st += x
             self.br.seek(address + len(st))
         else:
             break
         log_debug("{!r}".format(st))
     return st[:st.find(b"\x00")].decode("UTF-8")
예제 #14
0
 def newFileDialog(self):
     (snippetName, ok) = QInputDialog.getText(self, self.tr("Snippet Name"), self.tr("Snippet Name: "))
     if ok and snippetName:
         if not snippetName.endswith(".py"):
             snippetName += ".py"
         index = self.tree.selectionModel().currentIndex()
         selection = self.files.filePath(index)
         if QFileInfo(selection).isDir():
             open(os.path.join(selection, snippetName), "w").close()
         else:
             open(os.path.join(snippetPath, snippetName), "w").close()
         log_debug("Snippet %s created." % snippetName)
예제 #15
0
    def is_valid_for_data(self, data):
        for view_type in _macho_types:
            macho: BinaryView = data.get_view_of_type(view_type)
            if macho is not None and '_objc_msgSend' in macho.symbols:
                try:
                    macho.query_metadata('objc_init')
                except:
                    macho.store_metadata('objc_init', True)
                    macho.add_analysis_completion_event(callback)
                    log_debug(f"Found an Objective-C binary!")

        # Return False so we are not added as a valid BinaryView
        return False
    def visit_MLIL_CALL(self, expr):
        log.log_debug(f'visit_MLIL_CALL: {expr}')
        output = [
            InstructionTextToken(InstructionTextTokenType.LocalVariableToken,
                                 v.name, v.identifier) for v in expr.output
        ]
        dest = self.visit(expr.dest)
        params = [self.visit(p) for p in expr.params]

        for p in params[:-1]:
            p.append(
                InstructionTextToken(InstructionTextTokenType.TextToken, ', '))

        log.log_debug(f'output: {output}')
        log.log_debug(f'dest: {dest}')
        log.log_debug(f'params: {list(chain(*params))}')

        return [
            *output,
            InstructionTextToken(InstructionTextTokenType.TextToken,
                                 ' = ' if output else ''), *dest,
            InstructionTextToken(InstructionTextTokenType.TextToken, '('),
            *chain(*params),
            InstructionTextToken(InstructionTextTokenType.TextToken, ')')
        ]
예제 #17
0
 def applySvd(self):
     selection = self.tree.selectedIndexes()[::self.columns][
         0]  #treeview returns each selected element in the row
     svdName = self.files.fileName(selection)
     if (svdName != ""):
         question = QMessageBox.question(
             self, self.tr("Confirm"),
             self.
             tr(f"Confirm applying {svdName} to {os.path.basename(self.context.file.filename)} : "
                ))
         if (question == QMessageBox.StandardButton.Yes):
             log_debug("SVD Browser: Applying SVD %s." % svdName)
             load_svd(self.context, self.currentFile)
             self.close()
예제 #18
0
def conditional_unused(instr):
    """Check if conditional flags are set but no usage

    Args:
        instr (MediumLevelILInstruction): mlil instruction object.

    Returns:
        bool: True if conditional flags are set but not used else False.
    """
    log_debug("enter conditional_unused: " + hex(instr.address))

    # link to macro:
    # https://api.binary.ninja/_modules/binaryninja/enums.html#MediumLevelILOperation  # noqa: E501
    if instr.operation.value == 8:  # MLIL_VAR, just a single variable and no assignment
        # ex: test instruction without usage
        # ignore if it is part of bool operation for a JCC instruction
        cur_i = instr.instr_index + 1
        while instr.function[cur_i].address == instr.address:
            # native instruction can be broken down into multiple il instructions
            # if it is broken down, they will still share same VA
            if hasattr(instr.function[cur_i], 'dest') and  \
                    hasattr(instr.function[cur_i].dest, 'type') and  \
                    str(instr.function[cur_i].dest.type) == 'bool':
                return False
            cur_i += 1
        return True

    # check if top level operation is mathematical operations. Should not be
    if instr.operation.value in range(
            18, 45) or instr.operation.value in range(83, 90):
        # ignore if it is part of bool operation for a JCC instruction
        cur_i = instr.instr_index

        try:
            while instr.function[cur_i].address == instr.address:
                # native instruction can be broken down into multiple il instructions
                # if it is broken down, they will still share same VA
                if hasattr(instr.function[cur_i], 'dest') and  \
                        hasattr(instr.function[cur_i].dest, 'type') and  \
                        str(instr.function[cur_i].dest.type) == 'bool':
                    return False
                cur_i += 1
        except:
            # make sure original instruction index has corresponding instruction
            # if not return True
            pass

        return True
    return False
예제 #19
0
 def newFileDialog(self):
     (snippetName, ok) = QInputDialog.getText(self, self.tr("Snippet Name"), self.tr("Snippet Name: "), flags=self.windowFlags())
     if ok and snippetName:
         if not snippetName.endswith(".py"):
             snippetName += ".py"
         index = self.tree.selectionModel().currentIndex()
         selection = self.files.filePath(index)
         if QFileInfo(selection).isDir():
             path = os.path.join(selection, snippetName)
         else:
             path = os.path.join(snippetPath, snippetName)
             self.readOnly(False)
         open(path, "w").close()
         self.tree.setCurrentIndex(self.files.index(path))
         log_debug("Snippet %s created." % snippetName)
예제 #20
0
    def run(self):
        if self.context == None:
            log_warn("Cannot run snippets outside of the UI at this time.")
            return
        if self.snippetChanged():
            self.save()
        actionText = actionFromSnippet(self.currentFile, self.snippetDescription.text())
        UIActionHandler.globalActions().executeAction(actionText, self.context)

        log_debug("Saving snippet %s" % self.currentFile)
        outputSnippet = codecs.open(self.currentFile, "w", "utf-8")
        outputSnippet.write("#" + self.snippetDescription.text() + "\n")
        outputSnippet.write("#" + self.keySequenceEdit.keySequence().toString() + "\n")
        outputSnippet.write(self.edit.toPlainText())
        outputSnippet.close()
        self.registerAllSnippets()
예제 #21
0
def get_address_from_inst(bv, addr):
    inst = None
    try:
        bbs = bv.get_basic_blocks_at(addr)
        if bbs:
            inst = bbs[0].function.get_low_level_il_at(addr)
    except IndexError:
        inst = None

    if inst is not None:
        log_debug("got inst: {!r}".format(inst))
        if inst.src:
            if inst.src.value:
                if inst.src.value.value:
                    return inst.src.value.value
    else:
        return None
예제 #22
0
 def on_downloadRequested(self, download):
     old_path = download.url().path()  # download.path()
     suffix = QFileInfo(old_path).suffix()
     if (suffix.lower() in ["zip", "svd", "pack", "patched"]):
         log_debug(f"SVD Browser: Downloading {str(download.url())}")
         if suffix.lower() == "svd" or suffix.lower() == "patched":
             download.setDownloadDirectory(svdPath)
             download.accept()
         else:
             with TemporaryDirectory() as tempfolder:
                 log_debug(
                     f"SVD Browser: Downloading pack/zip to {tempfolder}")
                 fname = download.url().fileName()
                 r = requests.get(download.url().toString(),
                                  allow_redirects=True)
                 dlfile = os.path.join(tempfolder, fname)
                 open(dlfile, "wb").write(r.content)
                 '''
                 # TODO: See if the original QT Downloader can be fixed since it would
                 # help with situations where the user entered credentials in the browser.
                 download.setDownloadDirectory(tempfolder)
                 download.accept()
                 while not download.finished:
                     import time
                     time.sleep(100)
                 '''
                 if fname.endswith(".zip") or fname.endswith(".pack"):
                     destFolder = os.path.join(svdPath,
                                               os.path.splitext(fname)[0])
                     log_debug(f"SVD Browser: Creating {destFolder}")
                     if not os.path.exists(destFolder):
                         os.mkdir(destFolder)
                     with ZipFile(dlfile, 'r') as zipp:
                         for ifname in zipp.namelist():
                             if ifname.endswith(".svd"):
                                 info = zipp.getinfo(ifname)
                                 info.filename = os.path.basename(
                                     info.filename)
                                 log_debug(
                                     f"SVD Browser: Extracting {info.filename} from {ifname}"
                                 )
                                 zipp.extract(info, path=destFolder)
                 else:
                     #Move file into place
                     shutil.move(dlfile, svdPath)
     else:
         show_message_box(
             "Invalid file",
             "That download does not appear to be a valid SVD/ZIP/PACK file."
         )
     download.cancel()
예제 #23
0
def crazy_mem_offset(instr, bv):
    """
    """
    log_debug("[crazy_mem_offset]: entry "+hex(instr.address))
    # check dest for constant
    if instr.operation.name == 'LLIL_STORE_SSA':
        const_ils = list()
        get_type(instr.dest, LowLevelILInstruction, 'LLIL_CONST',
                 const_ils, 'operation.name')
        log_debug("[crazy_mem_offset]: "+str(const_ils))
        for c in const_ils:
            log_debug("[crazy_mem_offset]: const value "+str(c.value.value))
            if bv.is_offset_readable(c.value.value) or bv.is_offset_writable(c.value.value):
                log_debug("[crazy_mem_offset]: offset is a valid virtual address")
                continue
            # greater than a certain value and less than a certain value
            if c.constant > 0x100000 or c.constant < -0x100000:
                return True

    # check src for constant
    if not hasattr(instr, 'src'):
        return False
    load_ils = list()
    get_type(instr.src, LowLevelILInstruction,
             'LLIL_LOAD_SSA', load_ils, 'operation.name')

    for load_il in load_ils:
        const_ils = list()
        get_type(load_il, LowLevelILInstruction,
                 'LLIL_CONST', const_ils, 'operation.name')
        if not const_ils:
            continue
        for c in const_ils:
            if bv.is_offset_readable(c.value.value) or \
                    bv.is_offset_writable(c.value.value):
                log_debug("[crazy_mem_offset]: offset is a valid virtual address")
                continue
            # greater than a certain value and less than a certain value
            if c.constant > 0x100000 or c.constant < -0x100000:
                return True
    return False
    def execute(self, state):
        """
        Execute instruction that this class was initialized with.

        :state: Current active state
        """

        operation = self.instruction.operation.name
        log.log_debug("Evaluating {}: {} @ {}".format(
            operation, self.instruction, hex(self.instruction.address)))

        try:
            if self.instruction.value.is_constant:
                size = self.instruction.size * 8
                return [BitVecVal(self.instruction.value.value, size)]
        except AttributeError:
            pass

        executor = getattr(self, "evaluate_" + operation, None)

        if executor is not None:
            result = executor(state)
        else:
            raise NotImplementedError(repr(operation))

        for i in range(len(result)):
            width = self.instruction.size * 8
            if operation.endswith("_DP"):
                # Double precision
                width = width * 2
            if width < result[i].size():
                result[i] = Extract(width - 1, 0, result[i])
            if width > result[i].size():
                result[i] = ZeroExt(width - result[i].size(), result[i])

        log.log_debug("Completed {}: {} @ {}".format(
            operation, self.instruction, hex(self.instruction.address)))

        return result
예제 #25
0
    def rename_functions(self):
        renamed = 0
        log_info("renaming functions based on .gopclntab section")

        gopclntab = self.get_section_by_name(".gopclntab")

        if gopclntab is None:
            pattern = "\xfb\xff\xff\xff\x00\x00"
            base_addr = self.bv.find_next_data(0, pattern)

            if base_addr is None:
                log_alert("Failed to find section '.gopclntab'")
                return
        else:
            base_addr = gopclntab.start

        size_addr = base_addr + 8
        size = self.get_pointer_at(size_addr)

        log_info("found .gopclntab section at 0x{:x} with {} entries".format(
            base_addr, size / (self.ptr_size * 2)))

        start_addr = size_addr + self.ptr_size
        end_addr = base_addr + (size * self.ptr_size * 2)

        for addr in range(start_addr, end_addr, (2 * self.ptr_size)):
            log_debug("analyzing at 0x{:x}".format(addr))
            func_addr = self.get_pointer_at(addr)
            entry_offset = self.get_pointer_at(addr + self.ptr_size)

            log_debug("func_addr 0x{:x}, entry offset 0x{:x}".format(
                func_addr, entry_offset))

            name_str_offset = self.get_pointer_at(
                base_addr + entry_offset + self.ptr_size, 4)
            name_addr = base_addr + name_str_offset

            name = self.read_cstring(name_addr)
            log_debug("found name '{}' for address 0x{:x}".format(
                name, func_addr))

            func = self.bv.get_function_at(func_addr)
            if not func:
                func = self.bv.create_user_function(func_addr)

            if name and len(name) > 2:
                name = GOFUNC_PREFIX + santize_gofunc_name(name)
                sym = bn.types.Symbol('FunctionSymbol', func_addr, name, name)
                self.bv.define_user_symbol(sym)
                renamed += 1
            else:
                log_warn(
                    ("not using function name {!r} for function at 0x{:x}"
                     " in .gopclntab addr 0x{:x} name addr 0x{:x}").format(
                         name, func_addr, addr, name_addr))

        log_info("renamed {} go functions".format(renamed))
예제 #26
0
def bb_analysis(bv, bb, og_bb_start, metadata):
    """Check authenticity of `bb` based on instructions used.

    Args:
        bv (BinaryView): top-level binary view handler. Lots of
                         interesting methods can be accessed.
        bb (BasicBlock): BinaryNinja.BasicBlock object.
        og_bb_start (long): address of where original basic block starts.
        isa_specific_data (dict): None or dictionary containing isa-specific
                                  info. Read in from
                                  "storage/non_generic_spec.json".

    Returns:
        bool: True if content of bb doesn't make sense. False if it's a legit.
    """
    # first bb's instruction; instr.address
    faulting_addr = og_bb_start

    # check if isa is supported. If not, do not run this analysis
    isa_specific_data = metadata.spec['isa'].get(bv.arch.name)

    # result
    alerted_rules = list()

    # rule: weird_cutoff
    if weird_cutoff(bb, bv):
        log_debug(('* weird_cutoff: ' + 'bb start( 0x{0:02X} ) ' +
                   'instr addr( 0x{1:02X} )').format(faulting_addr,
                                                     faulting_addr))
        alerted_rules.append('weird_cutoff')

    # rule: prob_of_unimpl
    if prob_of_unimpl(bb, bv, isa_specific_data):
        log_debug(('* prob_of_unimpl: ' + 'bb start( 0x{0:02X} ) ' +
                   'instr addr( 0x{1:02X} )').format(faulting_addr,
                                                     faulting_addr))
        alerted_rules.append('prob_of_unimpl')

    for instr in bb:

        # rule: priviledged_instructions
        if priviledged_instructions(instr, bv, isa_specific_data):
            log_debug(
                ('* priviledged_instructions: ' + 'bb start( 0x{0:02X} ) ' +
                 'instr addr( 0x{1:02X} )').format(faulting_addr,
                                                   faulting_addr))
            alerted_rules.append('priviledged_instructions')

    return alerted_rules
예제 #27
0
def memaccess_self(instr):
    """Check if register used as pointer but also stored its ptr address to itself.

    Args:
        instr (MediumLevelILInstruction): mlil instruction object.

    Returns:
        bool: True if register used as pointer but also stored its ptr address
              to itself, else False.
    """
    log_debug("enter memaccess_self: " + hex(instr.address))
    # get vars read at destination
    # get vars used in memory access
    dest_vars_read = [
        i.var.name for i in instr.dest.vars_read if hasattr(i, 'var')
    ]
    if not dest_vars_read:
        return False
    log_debug("[memaccess_self] dest_vars_read: " + str(dest_vars_read))

    # get vars read at src that is not part of memory load
    # vars in src operands that are not a part of memory load!
    src_vars_read = list()
    # (1) check if it is a mov instruction for a subregister
    if instr.src.operation.name in [
            'MLIL_CONST', 'MLIL_VAR_SSA', 'MLIL_VAR_SSA_FIELD'
    ]:
        if instr.src.operation.name == 'MLIL_VAR_SSA_FIELD':
            src_vars_read.append(instr.src.src)
    # (2) heuristic for all other instructions
    else:
        for operand in instr.src.operands:
            if isinstance(operand, MediumLevelILInstruction):
                if operand.operation.name == 'MLIL_LOAD_SSA':
                    # skip if vars is inside memory access
                    continue
                for i in operand.vars_read:
                    if hasattr(i, 'var'):
                        src_vars_read.append(i.var.name)
            else:  # SSAVariable object
                if hasattr(operand, 'var'):
                    src_vars_read.append(operand.var.name)

    log_debug("[memaccess_self] src_vars_read: " + str(src_vars_read))
    for src_var in src_vars_read:
        if src_var in dest_vars_read:
            return True
    return False
예제 #28
0
def bb_llil_analysis(bv, bb, og_bb_start, metadata):
    """Check authenticity of instructions in LLIL.

    Args:
        bv (BinaryView): top-level binary view handler. Lots of
                         interesting methods can be accessed.
        bb (list): list of LLIL instructions.
        og_bb_start (long): address of where original basic block starts.

    Returns:
        bool: True if content of bb doesn't make sense. False if it's a legit.
    """
    bb = bb2ilbb(bb, 'llil', bv)
    if not bb:
        return False

    isa_specific_data = metadata.spec['isa'].get(bv.arch.name)

    # first bb's instruction; instr.address
    faulting_addr = og_bb_start

    # result
    alerted_rules = list()

    for instr in bb:

        # rule: stack_pointer_oddity
        if stack_pointer_oddity(instr, bv, isa_specific_data):
            log_debug(
                ('* stack_pointer_oddity: ' + 'bb start( 0x{0:02X} ) ' +
                 'instr addr( 0x{1:02X} )').format(faulting_addr,
                                                   instr.address))
            alerted_rules.append('stack_pointer_oddity')

        # rule: crazy_mem_offset
        if crazy_mem_offset(instr.ssa_form, bv):
            log_debug(
                ('* crazy_mem_offset: ' + 'bb start( 0x{0:02X} ) ' +
                 'instr addr( 0x{1:02X} )').format(faulting_addr,
                                                   instr.address))
            alerted_rules.append('crazy_mem_offset')

        # rule: type_discrepency_ptr_in_mult_div
        if type_discrepency_ptr_in_mult_div(instr):
            log_debug(
                ('* type_discrepency_ptr_in_mult_div: ' +
                 'bb start( 0x{0:02X} ) ' + 'instr addr( 0x{1:02X} )').format(
                     faulting_addr, instr.address))
            alerted_rules.append('type_discrepency_ptr_in_mult_div')

        if instr.operation == LowLevelILOperation.LLIL_STORE:

            # rule: memaccess_nonexist
            if memaccess_nonexist(instr, bv):
                log_debug(
                    ('* memaccess_nonexist: ' + 'bb start( 0x{0:02X} ) ' +
                     'instr addr( 0x{1:02X} )').format(faulting_addr,
                                                       instr.address))
                alerted_rules.append('memaccess_nonexist')

            # rule: memaccess_src_dest_discrepancy
            if memaccess_src_dest_discrepancy(instr, bv):
                log_debug(
                    ('* memaccess_src_dest_discrepancy: ' +
                     'bb start( 0x{0:02X} ) ' +
                     'instr addr( 0x{1:02X} )').format(faulting_addr,
                                                       instr.address))
                alerted_rules.append('memaccess_src_dest_discrepancy')

        if instr.operation == LowLevelILOperation.LLIL_CALL:

            # rule: call_dest_nonexist
            if call_dest_nonexist(instr, bv):
                log_debug(
                    ('* call_dest_nonexist: ' + 'bb start( 0x{0:02X} ) ' +
                     'instr addr( 0x{1:02X} )').format(faulting_addr,
                                                       instr.address))
                alerted_rules.append('call_dest_nonexist')

        # rule: jmp_dest_nonexist
        if instr.operation == LowLevelILOperation.LLIL_JUMP:
            if jmp_dest_nonexist(instr, bv):
                log_debug(
                    ('* jmp_dest_nonexist: ' + 'bb start( 0x{0:02X} ) ' +
                     'instr addr( 0x{1:02X} )').format(faulting_addr,
                                                       instr.address))
                alerted_rules.append('jmp_dest_nonexist')
    return alerted_rules
예제 #29
0
def callback(self):
    log_debug(f"I'm in an analysis completion event! {self.view}")
예제 #30
0
def stack_pointer_oddity(instr, bv, isa_specific_data):
    """
    (1) stack pointer should not be assigned a constant
    (2) in a memory operation (LLIL_LOAD), stack pointer should only be
        in LLIL_ADD or LLIL_SUB
    (3) usage of stack pointer should be in a memory access
    """
    log_debug("[stack_pointer_oddity]: entry "+hex(instr.address))

    # ignore stack pointer usages relating to function prologue/epilogue
    if not instr.function.get_medium_level_il_instruction_index(instr.instr_index):
        return False

    # ignore stack pointer operations for restoring stack frame
    if instr.il_basic_block[-1].operation.value in [57, 58]:
        return False

    # ignore instructions that are not completely lifted
    if instr.operation.name == 'LLIL_UNIMPL_MEM':
        return False

    stack_ptrs = list()
    if not isa_specific_data:
        stack_ptrs = isa_specific_data['stack_pointers']
    else:
        stack_ptrs.append(bv.arch.stack_pointer) 
    for stack_ptr in stack_ptrs:
        if not contain_type(instr, ILRegister, stack_ptr, temp=[]):
            continue
        log_debug("[stack_pointer_oddity]: contain_type({}, {}, {}) "
            .format(str(instr), str(ILRegister), str(stack_ptr)))
        log_debug("[stack_pointer_oddity]: contains stack_ptr "+str(stack_ptr))

        # check for memory access with stack pointer
        stack_semantics_add = list()
        stack_semantics_load = list()
        stack_semantics_store = list()
        get_type(instr, LowLevelILInstruction,
                 'LLIL_ADD', stack_semantics_add, 'operation.name')
        get_type(instr, LowLevelILInstruction,
                 'LLIL_STORE', stack_semantics_store, 'operation.name')
        get_type(instr, LowLevelILInstruction,
                 'LLIL_LOAD', stack_semantics_load, 'operation.name')
        log_debug("[stack_pointer_oddity]: stack semantics "+str(stack_semantics_add))
        if contain_type(instr, LowLevelILInstruction, 'LLIL_LOAD', temp=[]) or \
                contain_type(instr, LowLevelILInstruction, 'LLIL_STORE', temp=[]):
            # stack pointer used in memory access
            if (not any([il for il in stack_semantics_add if il.left.operation.name == 'LLIL_REG' and il.left.src.name == stack_ptr])) and \
                    (not any([il for il in stack_semantics_store if il.dest.operation.name == 'LLIL_REG' and il.dest.src.name == stack_ptr])) and \
                    (not any([il for il in stack_semantics_load if il.src.operation.name == 'LLIL_REG' and il.src.src.name == stack_ptr])):
                log_debug('[stack_pointer_oddity]: found(1)')
                return True
        # copying stack pointer value is fine
        elif (hasattr(instr, 'dest') and hasattr(instr, 'src') and hasattr(instr.src, 'src') and
                isinstance(instr.dest, ILRegister) and 
                instr.operation.name == 'LLIL_SET_REG' and 
                instr.src.operation.name == 'LLIL_REG' and 
                stack_ptr == instr.src.src.name):
            pass
        else:
            # adding or substracting stack offsets
            # have to take care of 'esp = esp + 4' or 'lea, [esp+0x38]'
            if not (hasattr(instr, 'dest') and hasattr(instr, 'src') and \
                    isinstance(instr.dest, ILRegister) and \
                    instr.src.operation.value in [22, 24] and \
                    stack_ptr in [str(i) for i in instr.src.tokens]):
                # the only other acceptable form: esp = esp + <const>
                # 22, 24 == LLIL_ADD, LLIL_SUB
                log_debug('[stack_pointer_oddity]: found(2) at :'+hex(instr.address))
                return True
    return False