我如何强制 IDA 递归地重新分析一个函数(意味着包括它内部的每个函数等等)并识别所有函数内部的所有函数?因为现在当映射 PE 时,IDA 无法识别其中的任何函数,这与我分析 PE 文件时不同,我必须单击每个函数 (unk_xxx) 并在其开头按 P 以便它可以识别功能..
单击选项中的重新分析也不起作用。
此处建议的 Alt + P 也不起作用:
在反编译器视图中,alt+P 根本不做任何事情,在反编译中它只是编辑函数。
使用 IDA 7.5。
我如何强制 IDA 递归地重新分析一个函数(意味着包括它内部的每个函数等等)并识别所有函数内部的所有函数?因为现在当映射 PE 时,IDA 无法识别其中的任何函数,这与我分析 PE 文件时不同,我必须单击每个函数 (unk_xxx) 并在其开头按 P 以便它可以识别功能..
单击选项中的重新分析也不起作用。
此处建议的 Alt + P 也不起作用:
在反编译器视图中,alt+P 根本不做任何事情,在反编译中它只是编辑函数。
使用 IDA 7.5。
在调试期间,IDA 会进行有限数量的自动分析以加快调试体验而不干扰进程。您可以做的是将要分析的模块复制到数据库中,然后停止调试器,让IDA完成对保存数据的自动分析。这可以通过模块列表中的“分析模块”命令来完成。
请注意,如果模块在下次运行时加载到另一个地址(例如由于ASLR),您将在数据库中发生冲突,因此如果您需要经常重新运行该进程,则不建议这样做,但更多适用于这种情况的“调试大部分完成,现在我需要静态分析它”。
如果有人觉得需要在非调试设置中以编程方式执行此操作,这就是我将使用的代码。
注意#1:有一些我自己的快捷功能GetFuncStart
没有包括在内,我相信你可以解决它们。Commenter
只需要删除对类的引用。
注意#2:所采取的看似极端的措施ZeroFunction
是我发现确保函数真正重建的唯一方法。ida_auto 函数似乎没有什么作用。如果适合您,您可以选择不那么极端的东西。
注意#3:被调用函数的顺序被颠倒以尝试从底向上重建,希望允许 IDA 对参数等进行更有根据的猜测。
注意 #4:许多多余的变量、列表等来自更大的原始函数,它(除其他外)产生 .dot 可视化图形。我已经把它们留在了,以免有人找到它们的用途。
def RebuildFuncAndSubs(ea):
subs = RecurseCalled(ea)['calledLocs']
subs.reverse()
for addr in subs:
ZeroFunction(addr)
idc.auto_wait()
ZeroFunction(ea)
idc.auto_wait()
def RecurseCalled(ea=None, width=512):
def all_xrefs_from(funcea, iteratee=None):
if iteratee is None:
iteratee = lambda x: x
xrefs = []
for (startea, endea) in Chunks(funcea):
for head in Heads(startea, endea):
xrefs.extend([GetFuncStart(x.to) for x in idautils.XrefsFrom(head) \
if x.type in (ida_xref.fl_CF, ida_xref.fl_CN, ida_xref.fl_JF, ida_xref.fl_JN) \
and not ida_funcs.is_same_func(funcea, x.to) \
and IsFunc_(x.to)])
xrefs = list(set(xrefs))
return xrefs
if ea is None:
ea = idc.get_screen_ea()
calledNames = list()
calledLocs = list()
visited = set([])
if isinstance(ea, list):
pending = set(ea)
initial = set([GetFuncStart(x) for x in ea])
else:
pending = set([ea])
initial = set([GetFuncStart(ea)])
depth = 0
count = 0
added = [1]
functionCalls = collections.defaultdict(set)
namedFunctionCalls = collections.defaultdict(set)
fwd = dict()
rev = dict()
while pending and len(pending) < width:
target = pending.pop()
count += 1
added[0] -= 1
if added[0] < 1:
depth += 1
added.pop()
visited.add(target)
fnName = idc.get_func_name(target) or idc.get_name(target) or "0x%x" % ref
fnStart = GetFuncStart(target)
if fnStart < idc.BADADDR:
target = fnStart
visited.add(target)
if not fnStart in initial:
calledNames.append(fnName)
calledLocs.append(fnStart)
refs = all_xrefs_from(fnStart)
refs = set(refs)
refs -= visited
size1 = len(pending)
pending |= refs
size2 = len(pending) - size1
added.append(size2)
return {'calledName': calledNames,
'calledLocs': calledLocs,
}
def ZeroFunction(ea, total=False):
print("0x%x: ZeroFunction" % ea)
start = 0
end = 0
# Don't hold the func_t object open
func = clone_items(ida_funcs.get_func(ea))
if not func:
return BADADDR
# Keep existing comments
with Commenter(ea, 'func') as commenter:
fnLoc = func.start_ea
fnName = ida_funcs.get_func_name(fnLoc)
flags = func.flags # idc.get_func_attr(ea, FUNCATTR_FLAGS)
# remove library flag
idc.set_func_attr(fnLoc, FUNCATTR_FLAGS, flags & ~4)
ida_name.del_local_name(fnLoc)
ida_name.del_global_name(fnLoc)
# RemoveAllChunks(ea)
for start, end in idautils.Chunks(ea):
idc.remove_fchunk(start, end)
ida_funcs.del_func(func.start_ea)
idc.set_color(fnLoc, CIC_FUNC, 0xffffffff)
if not total:
func = ida_funcs.func_t(fnLoc)
res = ida_funcs.find_func_bounds(func, ida_funcs.FIND_FUNC_DEFINE | ida_funcs.FIND_FUNC_IGNOREFN)
if res == ida_funcs.FIND_FUNC_UNDEF:
print("0x%x ZeroFunction: func passed flow to unexplored bytes" % fnLoc)
elif res == ida_funcs.FIND_FUNC_OK:
ida_funcs.add_func_ex(func)
idc.auto_wait()
# remove library flag (again)
idc.set_func_flags(fnLoc, idc.get_func_flags(fnLoc) & ~4)
# return original function name
idc.set_name(fnLoc, fnName, idc.SN_NOWARN)