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 插件中运行的,通过运行该代码片段可以获取到引用给当前函数的所有地址,并将其以十六进制的形式打印出来。
