def getSize(self, withPool=False):
        """
        Computes the size of the function the first time this is called, and caches that computation for later
        Parsed Comment commands:
            <endpool> specifies the last element in the pool. That element's size is included in the pool.
                      to specify a function has no pool at all, put the comment command at its last instruction.
        :param withPool: (bool) somewhat of a heuristic. Computes the pool size as simply the amount of bytes since
                         the function's code portion finished (endEA) until a new code head is detected
        :return:  Returns the size of the Function in bytes: EndEA - StartEA (if no pool selected, otherwise + pool)
        """
        if not withPool: return self.func.end_ea - self.func.start_ea
        head = self.func.end_ea

        # check if the function is set to have no pool
        instSize = self.isThumb() and 2 or 4
        endCmt = idc.Comment(self.func.end_ea - instSize)
        if endCmt and '<endpool>' in endCmt:
            return self.func.end_ea - self.func.start_ea

        while not idc.isCode(idc.GetFlags(head)):
            # manual pool computation, trust and assume that this is the last element in the pool!
            if idc.Comment(head) and '<endpool>' in idc.Comment(head):
                head += idc.get_item_size(head)
                break
            # advance to next data element
            head += idc.get_item_size(head)

        return head - self.func.start_ea
Пример #2
0
def walk_stack(ea, func_args):
	found_args = []
	while len(found_args) < func_args:
		ea = previous_ea(ea)
		if idc.Comment(ea):
			found_args.append((ea, idc.Comment(ea)))

	return found_args
Пример #3
0
    def get_patch_byte(self, ea, fpos, org_val, patch_val):

        # Aggregate contiguous bytes (base ea + length)
        # NOTE: Looking at the last item [-1] is sufficient
        #       since we are dealing with sorted data.
        if len(self.items_data) and (ea - self.items_data[-1][0] == self.items_data[-1][2]):

            # Increment length
            self.items_data[-1][2] += 1
            self.items[-1][2] = str(self.items_data[-1][2])

            # Append patched bytes
            self.items_data[-1][3].append(patch_val)
            self.items[-1][3] = " ".join(["%02X" % x for x in self.items_data[-1][3]])

            # Append original bytes
            self.items_data[-1][4].append(org_val)
            self.items[-1][4] =  " ".join(["%02X" % x for x in self.items_data[-1][4]])


        # Add new patch byte to the list
        else:

            name = idc.SegName(ea)

            if idc.GetFunctionName(ea) or idc.Name(ea):
                name += ": %s" % idc.GetFunctionName(ea) or idc.Name(ea)


            comment = idc.Comment(ea) or idc.RptCmt(ea) or ""
            # DATA STORAGE FORMAT:      address, function / fpos, len,    patched byte(s), original byte(s), comments
            self.items.append(     ["%08X" % ea,            name, "1", "%02X" % patch_val, "%02X" % org_val, comment])
            self.items_data.append([         ea,            fpos,   1,        [patch_val],        [org_val], None]   )

        return 0
Пример #4
0
def get_single_comment(ea, is_func=False):
    """IDA has repeatable and regular comments. BN only has regular comments.
    This function constructs a single comment from both repeatable and regular
    comments
    """
    regular_comment = ""
    repeatable_comment = ""

    if is_func:
        regular_comment = idc.GetFunctionCmt(ea, 0)
        repeatable_comment = idc.GetFunctionCmt(ea, 1)
    else:
        regular_comment = idc.Comment(ea)
        repeatable_comment = idc.RptCmt(ea)

    if regular_comment is None:
        return repeatable_comment
    elif repeatable_comment is None:
        return regular_comment
    elif repeatable_comment is None and regular_comment is None:
        return None
    else:
        if len(regular_comment) == 0:
            return repeatable_comment

        if len(repeatable_comment) == 0:
            return repeatable_comment

        return regular_comment + "\n" + repeatable_comment

    return None
Пример #5
0
    def get_patch_byte(self, ea, fpos, org_val, patched_val):
        org_byte = "%02x" % org_val
        patched_byte = "%02x" % patched_val

        if self.prev_addr is None or ea != (self.prev_addr + 1):
            name = idc.SegName(ea)
            if idc.GetFunctionName(ea) or idc.Name(ea):
                name += ": %s" % idc.GetFunctionName(ea) or idc.Name(ea)

            comment = idc.Comment(ea) or idc.RptCmt(ea) or ""

            self.patched_bytes.append({
                'name': name,
                'begin_addr': ea,
                'original': org_byte,
                'patched': patched_byte,
                'comment': comment
            })

        else:
            self.patched_bytes[-1]['original'] += org_byte
            self.patched_bytes[-1]['patched'] += patched_byte

        self.prev_addr = ea

        return 0
Пример #6
0
def append_comment(ea, s, repeatable=False):
    """
    add the given string as a (possibly repeating) comment to the given address.
    does not add the comment if it already exists.
    adds the comment on its own line.

    Args:
      ea (int): the address at which to add the comment.
      s (str): the comment text.
      repeatable (bool): if True, set a repeatable comment.

    Raises:
      UnicodeEncodeError: if the given string is not ascii.
    """
    # see: http://blogs.norman.com/2011/security-research/improving-ida-analysis-of-x64-exception-handling

    s = s.encode("ascii")

    if repeatable:
        string = idc.RptCmt(ea)
    else:
        string = idc.Comment(ea)

    if not string:
        string = s  # no existing comment
    else:
        if s in string:  # ignore duplicates
            return
        string = string + "\\n" + s

    if repeatable:
        idc.MakeRptCmt(ea, string)
    else:
        idc.MakeComm(ea, string)
Пример #7
0
    def OnDeleteLine(self, n):
        ans = idaapi.askyn_c(
            1,
            "HIDECANCEL\nAre you sure you want to delete function [%s] @ [%s]?"
            % (self.items[n][3], self.items[n][4]))
        if ans == 1:
            asms = Assembler.LoadSavedAssemblers()
            item = int(self.items[n][2], 16)
            if asms != None and len(asms.keys()) > 0:
                for asm in asms.itervalues():
                    if asm.functions.has_key(item):
                        print "Removed [%08x]!" % item
                        del asm.functions[item]
                        asm.SaveState()

            opty_ea = int(self.items[n][4], 16)
            print "set_name[%08x]" % opty_ea
            idc.MakeComm(opty_ea, "")
            idaapi.set_name(opty_ea, "")
            idc.DelFunction(opty_ea)

            comment = idc.Comment(item)
            comment = re.sub(r"(?i)OPTY@\[[\d+abcdef]+\];\s*", "", comment)
            idc.MakeComm(item, comment)

        self.populate_items()
        return n
 def visit_line(self, line):
     comm = {}
     for address in line.extract_addresses():
         idacomm = idc.Comment(address)
         newcomm = idacomm and bap_comment.parse(idacomm) or {}
         union(comm, newcomm)
     if comm:
         line.widget.line += COLOR_START
         line.widget.line += bap_comment.dumps(comm)
         line.widget.line += COLOR_END
 def activate(self, ctx):
     pos = idc.ScreenEA()
     # Get current comment for this instruction and remove the C define from it, if present
     comment = idc.Comment(pos)
     code = get_operand_value(pos)
     define = ioctl_decoder.get_define(code)
     comment = comment.replace(define, "")
     idc.MakeComm(pos, comment)
     # Remove the ioctl from the valid list and add it to the invalid list to avoid 'find_all_ioctls' accidently re-indexing it.
     ioctl_tracker.remove_ioctl(pos)
def make_comment(pos, string):
    """
    Creates a comment with contents `string` at address `pos`.
    If the address is already commented append the new comment to the existing comment
    """
    
    current_comment = idc.Comment(pos)
    if not current_comment:
        idc.MakeComm(pos, string)
    elif string not in current_comment:
        idc.MakeComm(pos, current_comment + " " + string)
Пример #11
0
 def cmt_changed(self, *args):
     """
         A comment changed somewhere
     """
     addr, rpt = args
     if rpt:
         cmt = idc.RptCmt(addr)
     else:
         cmt = idc.Comment(addr)
     if not SkelUtils.filter_coms_blacklist(cmt):
         self.skel_conn.push_comment(addr, cmt)
     return idaapi.IDB_Hooks.cmt_changed(self, *args)
Пример #12
0
        def postprocess(self):
            try:
                if "MakeComment" in self.cmdname:
                    if idc.Comment(self.addr) is not None:
                        self.skel_conn.push_comment(self.addr,
                                                    idc.Comment(self.addr))
                    if idc.GetFunctionCmt(self.addr, 0) != "":
                        self.skel_conn.push_comment(
                            self.addr, idc.GetFunctionCmt((self.addr), 0))
                elif "MakeRptCmt" in self.cmdname:
                    if idc.GetCommentEx(self.addr, 1) != "":
                        self.skel_conn.push_comment(
                            self.addr, idc.GetCommentEx(self.addr, 1))
                    if idc.GetFunctionCmt(self.addr, 1) != "":
                        self.skel_conn.push_comment(
                            self.addr, idc.GetFunctionCmt(self.addr, 1))

                elif self.cmdname == "MakeFunction":
                    if idc.GetFunctionAttr(self.addr, 0) is not None:
                        pass
                        #push_change("idc.MakeFunction", shex(idc.GetFunctionAttr(
                        #    self.addr, 0)), shex(idc.GetFunctionAttr(self.addr, 4)))
                elif self.cmdname == "DeclareStructVar":
                    print "Fixme : declare Struct variable"
                elif self.cmdname == "SetType":
                    newtype = idc.GetType(self.addr)
                    if newtype is None:
                        newtype = ""
                    else:
                        newtype = SkelUtils.prepare_parse_type(
                            newtype, self.addr)
                        self.skel_conn.push_type(int(self.addr), newtype)
                    # XXX IMPLEMENT
                elif self.cmdname == "OpStructOffset":
                    print "Fixme, used when typing a struct member/stack var/data pointer to a struct offset "
            except KeyError:
                pass
            return 0
Пример #13
0
def AppendComment(ea, s, repeatable=False):
    # see williutils and http://blogs.norman.com/2011/security-research/improving-ida-analysis-of-x64-exception-handling
    if repeatable:
        string = idc.RptCmt(ea)
    else:
        string = idc.Comment(ea)
    if not string:
        string = s  # no existing comment
    else:
        if s in string:  # ignore duplicates
            return
        string = string + "\n" + s
    if repeatable:
        idc.MakeRptCmt(ea, string)
    else:
        idc.MakeComm(ea, string)
Пример #14
0
    def execute_comment(comment):
        """
            Thread safe comment wrapper
        """
        def make_rpt():
            idc.MakeRptCmt(comment["address"],
                           comment["data"].encode('ascii', 'replace'))

        cmt = idc.Comment(comment["address"])
        if cmt != comment["data"] and idc.RptCmt(
                comment["address"]) != comment["data"]:
            g_logger.debug("[x] Adding comment %s @ 0x%x ", comment["data"],
                           comment["address"])
            return idaapi.execute_sync(make_rpt, idaapi.MFF_WRITE)
        else:
            pass
Пример #15
0
 def activate(self, ctx):
     # get item and remove
     ind = ctx.chooser_selection.at(0)
     ioctl = self.items[ind - 1]
     pos = int(ioctl[0], 16)
     define = ioctl[5]
     global ioctl_tracker
     for (addr, val) in ioctl_tracker.ioctls:
         if addr == pos:
             code = val
             break
     # Get current comment for this instruction and remove the C define from it, if present
     comment = idc.Comment(pos)
     comment = comment.replace(define, "")
     idc.MakeComm(pos, comment)
     # Remove the ioctl from the valid list and add it to the invalid list to avoid 'find_all_ioctls' accidently re-indexing it.
     ioctl_tracker.remove_ioctl(pos, code)
Пример #16
0
 def get_comments(self, _start, _end):
     comments = ''
     # parse all the instructions
     for instr in idautils.Heads(_start, _end):
         if idc.GetFlags(instr) & idc.FF_COMM:
             # is it a repeatable comment?
             tmp_comment = idc.Comment(instr)
             if tmp_comment is not None:
                 # add the current regular comment
                 comments += struct.pack(
                     '>I', len(tmp_comment)) + struct.pack(
                         ">I", instr - _start) + tmp_comment
             else:
                 # add the current repeatable comment
                 comments += struct.pack('>I', len(
                     idc.RptCmt(instr))) + struct.pack(
                         ">I", instr - _start) + idc.RptCmt(instr)
     return comments
Пример #17
0
def get_comments(ea):
    comments = []
    text = idc.RptCmt(ea)
    if text and len(text) > 0:
        comments.append({
            'type':
            'repeatable',
            'comment':
            text,
            'offset':
            str(hex(ea)).rstrip("L").upper().replace("0X", "0x")
        })
    text = idc.Comment(ea)
    if text and len(text) > 0:
        comments.append({
            'type':
            'regular',
            'comment':
            text,
            'offset':
            str(hex(ea)).rstrip("L").upper().replace("0X", "0x")
        })
    text = _iter_extra_comments(ea, idaapi.E_PREV)
    if text and len(text) > 0:
        comments.append({
            'type':
            'anterior',
            'comment':
            text,
            'offset':
            str(hex(ea)).rstrip("L").upper().replace("0X", "0x")
        })
    text = _iter_extra_comments(ea, idaapi.E_NEXT)
    if text and len(text) > 0:
        comments.append({
            'type':
            'posterior',
            'comment':
            text,
            'offset':
            str(hex(ea)).rstrip("L").upper().replace("0X", "0x")
        })
    return comments
Пример #18
0
def import_comments(comments):
    """Import BN comments
    """
    for addr, comment in comments.items():
        addr = int(addr)
        comment = comment.encode("utf-8")
        current_comment = idc.Comment(addr)

        # make a new comment
        if not current_comment:
            idc.MakeComm(addr, comment)
            continue

        # ensure comments hasn't already been imported
        if comment in current_comment:
            continue

        # append to comment
        idc.MakeComm(addr, current_comment + " " + comment)
Пример #19
0
	def imp_cb(ea, name, ord):
		if name in funcs:
			for xref in idautils.XrefsTo(ea):
				call_addr = xref.frm
				caller_name = idc.GetFunctionName(call_addr)
				prev = idc.PrevHead(call_addr)
				for _ in range(10):
					if idc.Comment(prev) == 'Tag' and idc.GetOpType(prev, 1) == 5:
						tag_raw = idc.GetOperandValue(prev, 1)
						tag = ''
						for i in range(3, -1, -1):
							tag += chr((tag_raw >> 8 * i) & 0xFF)
						if tag in tags.keys():
							tags[tag].add(caller_name)
						else:
							tags[tag] = set([caller_name])
						break
					prev = idc.PrevHead(prev)
		return True
Пример #20
0
def linearize_comment(ea, function_comment=False):
    regular_comment = ""
    repeatable_comment = ""

    if function_comment:
        regular_comment = idc.GetFunctionCmt(ea, 0)
        repeatable_comment = idc.GetFunctionCmt(ea, 1)
    else:
        regular_comment = idc.Comment(ea)
        repeatable_comment = idc.RptCmt(ea)

    if regular_comment is None and repeatable_comment is None:
        return None
    elif regular_comment is not None and repeatable_comment is None:
        return regular_comment
    elif repeatable_comment is not None and regular_comment is None:
        return repeatable_comment
    else:
        if len(regular_comment) == 0:
            return repeatable_comment
        if len(repeatable_comment) == 0:
            return repeatable_comment
        return regular_comment + "\n" + repeatable_comment
    return None
Пример #21
0
    def Assemble(self, function, nasm=True):
        '''
            Main Assemble Function
        '''

        if self.functions.has_key(function.start_ea):
            ans = idaapi.askyn_c(
                1,
                "HIDECANCEL\nFunction @ [%08x] was already optimized, are you sure you want to overwrite old one?"
            )
            if ans == 0:
                return

        idc.Batch(1)

        self.jmp_table = ""
        self.jmp_table_refs = []
        self.jmp_deps = {}
        self.ref_instr = {}
        self.bb_head_ea = {}

        function_ea = self.free_ea
        function_end = None

        if debug:
            print ">Assemble(%08x) - Starting" % function.start_ea

        if nasm:
            if self.opty_dir == None:
                self.opty_dir = idc.GetIdbPath()
                self.opty_dir = self.opty_dir[:self.opty_dir.rfind(
                    os.sep)] + os.sep + "optimice_%s" % idc.GetInputFile()
                if not os.path.isdir(self.opty_dir):
                    os.mkdir(self.opty_dir)

            self.nasm = True
            self.nasmfw = open(
                self.opty_dir + os.sep + 'f_%08x.asm' % function.start_ea,
                "w+")
            self.NasmWriteToFile("[BITS 32]\n")
            self.NasmWriteToFile("\torg %09xh\n" % function_ea)
        else:
            self.nasm = False

        for bb_ea in function.DFSFalseTraverseBlocks():
            if self.nasm:
                self.NasmWriteToFile("\nL%08x:\n" % bb_ea)
                self.bb_head_ea[bb_ea] = True
            else:
                self.bb_head_ea[bb_ea] = self.free_ea

            for instr in function.GetBBInstructions(bb_ea):
                if instr == None:
                    continue

                mnem = self.BuildAsmString(instr, function)

                if debug:
                    print ">Assemble - Assembling @ %08x [%s]" % (
                        instr.GetOriginEA(), mnem)

                if not self.nasm:
                    self.AsmAndWrite(mnem, instr, function=function)

            if not instr.IsCFI():
                ref_from = list(function.GetRefsFrom(
                    instr.GetOriginEA()))[0][0]

                if self.bb_head_ea.has_key(ref_from):
                    if self.nasm:
                        self.NasmWriteToFile("\tjmp L%08x ; \n" % ref_from)
                    else:
                        self.AsmAndWrite("jmp %09xh" %
                                         self.bb_head_ea[ref_from])

            elif instr.GetMnem() == "call":
                for ref, path in function.GetRefsFrom(instr.GetOriginEA()):
                    if path == False:
                        if self.bb_head_ea.has_key(ref):
                            if self.nasm:
                                self.NasmWriteToFile(
                                    "\tjmp L%08x ; ###FAKE 2 JMP###\n" % ref)
                            else:
                                self.AsmAndWrite("jmp %09xh" %
                                                 self.bb_head_ea[ref])

            elif instr.IsJcc():
                ref_from = list(function.GetRefsFrom(instr.GetOriginEA()))
                for ref, path in ref_from:
                    if path == False:
                        break

                if path == True:
                    raise MiscError

                elif self.bb_head_ea.has_key(ref):
                    print "Check this out @ [%08x] ref:[%08x]" % (
                        instr.GetOriginEA(), ref)
                    if self.nasm:
                        self.NasmWriteToFile(
                            "\tjmp L%08x ; ###FAKE 2 JMP###\n" % ref)
                    else:
                        self.AsmAndWrite("jmp %09xh" % self.bb_head_ea[ref])

        ret = None
        if self.nasm:
            self.NasmWriteToFile(self.jmp_table)

            self.nasmfw.close()
            self.nasmfw = None

            ret = self.NasmAssemble(function.start_ea, self.free_ea)
            if ret != None:
                self.free_ea = ret
        else:
            ret = self.AsmAndWriteBranches(function)
            self.free_ea = ret

        self.ref_instr = {}
        idc.Batch(0)

        if ret != None:
            idc.MakeFunction(function_ea)

            comment = idc.Comment(function_ea)
            if comment != None:
                comment = 'Origin@[%08x]; %s' % (function.start_ea, comment)
            else:
                comment = 'Origin@[%08x];' % function.start_ea

            idc.MakeComm(function_ea, comment)

            comment = idc.Comment(function.start_ea)
            if comment != None:
                comment = 'OPTY@[%08x]; %s' % (function_ea, comment)
            else:
                comment = 'OPTY@[%08x];' % function_ea

            idc.MakeComm(function.start_ea, comment)

            idaapi.set_name(function_ea, "om_%s" % idc.Name(function.start_ea))

        function_end = self.free_ea
        self.functions[function.start_ea] = (function_ea, function_end)

        idaapi.refresh_idaview_anyway()
Пример #22
0
 def regular(self):
     """Regular Comment"""
     return idc.Comment(self._ea)