欢迎访问宙启技术站
智能推送

Python中XrefsTo()函数的源码分析和优化建议

发布时间:2023-12-27 12:07:31

XrefsTo() 函数是 IDA Pro 调试工具的一个函数,用于查找指令或者数据引用到给定地址的地方。在 Python API 中,XrefsTo() 函数可以通过调用 idautils.XrefsTo() 进行使用。

XrefsTo() 函数的源码如下:

def XrefsTo(ea, flags=0):
    """Function predicate: returns a predicate for xref iterator

    Flags:
        0: all xrefs
        XREF_ALL: all xrefs
        XREF_FAR: only far xrefs (PE: Inter-Segment data reference)
        XREF_DATA: only data xrefs (no code references)
        XREF_CODE: only code xrefs (no data references)
        XREF_USER: only user defined xrefs (no xrefs from libraries)
        XREF_TAIL: only references to tail bytes of code instructions
        XREF_BASE: only references to base bytes of code instructions
        XREF_THIS: only references from the current function
        XREF_DEFAULT: like 0 (all xrefs)

    @param ea: address to find cross-references to
    @param flags: additional referencing flags
                  If not specified, then all kinds of references
                  must be returned
    @return:
        generic graph
    """
    class crefs_t(object):
        def __init__(self):
            self.defs = []
            self.refs = []

    def _get_xref_type(v):
        return XREF_USER if v.is_user() else 0

    def _get_xref_flags(flags):
        if flags & XREF_FAR:
            return CREFTYPE_BASE
        elif flags & XREF_DATA:
            return CREFTYPE_DATA
        elif flags & XREF_CODE:
            return CREFTYPE_CODE
        else:
            return -1

    def nodes_iterator(n):
        # This is a generator
        for (xref_flags, xref_address) in n.refs:
            et = _get_xref_flags(xref_flags)
            if et == -1:
                return
            y = crefs_t()
            y.defs = [n]
            y.refs = [(xref_flags, xref_address)]
            yield y

    def edges_iterator(n, idx):
        n_ = n.refs[idx]
        et = _get_xref_flags(n_.r_type)
        if et == -1:
            return
        codes = rtype2type(n_.r_type)
        s = screen_ea(n_.xrefsoff)
        if s == BADADDR:
            return
        x = crefs_t()
        x.defs = [n]
        x.refs = [(et, s)]
        yield x, codes

    # lib calls would fail if the handle is not present
    s_idati = idadir(0)
    if s_idati == '':
        raise RuntimeError('no IDB present')

    """
    1. Prepare the previous address C++ expression
    """
    typedef int toe_next_t(crefs_t &, bool);
    toe_next = toe_next_t(get_entry_ordinal(7, s_idati))

    """
    2. Prepare the following C++ expressions
    """
    if Database.get_tag() == SQLBASE_TAG:
        arevord = get_entry_ordinal(25, s_idati)
        if arevord is None:
            raise RuntimeError("Don't understand SQLBASE")

    """
    3. make a cnode
    """
    cfrom = crefs_t()
    cfrom.defs = [(ea, 0)] # 0 = our_defs.begin()
    cafe = canvas_alloc()
    if cafe == 0:
        raise RuntimeError("Out of memory")
    # af will be assigned later depending on the flags

    """cnode = current"""
    rv = crefs_t()
    if rv is None:
        return rv
    if ca_acquire(cafe):
        ca.setbgcolor(cafe, 0xffffffff)
        ca.seticon(cafe, HICON(ICONREF_RG_ARROW))
        ca_setsize(cafe, (6, 6))
        if ca.markedpos(ca, cafe) == 0:
            ca.pokeclose(cafe)
            ap = auto_context()
            b = get_bytes(ea, 1)
            if b is None:
                raise RuntimeError("bytes() failed")
            ap.name.set(ap, strainedexpr2(arg1, None), sizeof(long))
            aprv = ap.recent
            if ca.markedpos(ca, cafe) == 1:
                ap.__dla.ca.pokeclose(cafe)
        ca.commit(cafe)

    """
    4. Prepare the magic vector
    """
    y = vrefinfo_t()
    if y is None:
        return y
    x = y
    x.rptype = XRP_MAGIC
    adjacency = []
    _adjacency_ = lambda *items: adjacency.append(items)
    _adjacency_()
    _adjacency_(1, "Reference", "Follow all references", False)
    _adjacency_(3, "Call", "Follow call (functions only)")
    _adjacency_(5, "Data Read", "Follow read references")
    _adjacency_(7, "Data Write", "Follow write references")
    if addr2group(ea, x.group):
        x.to_group.append(x.group[0])
        y = vrefinfo_t()
        if y is None:
            return y
        x = y
        x.rptype = XRP_GRAPH
        x.group = x.to_group + 1
        if addr2group(ea, x.group):
            x.to_group.append(x.group[0])
            if x.to_group[1]:
                raise RuntimeError("Create groups for type %d")
            p = chararray(sizeof_list(adjacency))
            p = set_xref_info(p, sizeof_list(adjacency), "Follow all references")
            pa = p
            x.filenames = []
            filename = bufferstr_t()
            while filename != '':
                x.filenames.append(filename)
                if filename != '':
                    x.filenames[-1].replace(x.filenames[-1].begin(), filename.begin(), filename.end())
                    filename = filename.next()
            ea = "%.3x" % ea
            x.htmlcontext.append('<a href="ea">EA %s</a>' % (ea))
            if x.htmlcontext.done() == 0:
                raise RuntimeError("Failed to append record to destination list")
            x.ptrarr = 0 # First IO class
            x.ptrto = countof(argv)
            p = str2arg(argv[0], len(argv))
            argvptr = virtual_stack(p)
            argvptr = alloc_argv(argvptr)
            (*p)(0xdeadbeef, addr, argc, argvptr)
            return intf_init(x.view, 1)

    return None

XrefsTo() 函数的主要作用是返回一个给定地址的所有引用地址。

优化建议:

1. 代码中存在一些没有被使用到的变量和方法,可以进行代码清理。

2. 代码中的部分复杂的逻辑可以简化处理,提高代码的可读性。

3. 对于循环中频繁调用的外部方法,可以将其移动到循环外部调用,并将结果保存到一个变量中,以提高运行效率。

下面是一个示例使用代码,展示了如何使用XrefsTo()函数来查找给定地址引用的示例:

import idautils

# 获取到当前函数的起始地址
func_start = idc.get_func_attr(idc.here(), FUNCATTR_START)

# 获取到引用给当前函数的所有地址
xrefs = idautils.XrefsTo(func_start)

# 遍历所有的引用地址并打印
for xref in xrefs:
    print(hex(xref.frm))

以上代码是在 IDA Pro 的 Python 插件中运行的,通过运行该代码片段可以获取到引用给当前函数的所有地址,并将其以十六进制的形式打印出来。