如果基本块末尾的指令是跳转/分支指令(如B或JNZ),我想知道使用 IDAPython并确定它是否有条件。我需要它以一种与 CPU 无关的方式,而不依赖于助记符。
我无法通过在 $IDA_DIR/python 目录中进行 grepping 来找到如何执行此操作。
如果基本块末尾的指令是跳转/分支指令(如B或JNZ),我想知道使用 IDAPython并确定它是否有条件。我需要它以一种与 CPU 无关的方式,而不依赖于助记符。
我无法通过在 $IDA_DIR/python 目录中进行 grepping 来找到如何执行此操作。
你可以试试我写的这个函数,它在我做的一些快速测试中工作得很好。您可能需要实现更多代码来处理边缘情况,但通常它应该可以工作。
该函数是用以下通用假设编写的(并非总是如此):
这是我认为有帮助的注释代码:
from idaapi import *
from idc import *
def check_conditional(func_ea, addr):
# Get: function's base address, suspicious branch/jmp address
# Returns: a strings which says whether the address is a Conditional Branch, Unconditional Branch or neither
f_start = get_func(func_ea).startEA
f_end = FindFuncEnd(f_start)
# Get local function's references made from the instruction
refs = CodeRefsFrom(addr, 0)
refs = set(filter(lambda x: x>=f_start and x<=f_end, refs))
if refs:
# Add a reference to the next instruction if the flow continues to it
next_head = NextHead(addr, f_end)
if isFlow(GetFlags(next_head)):
# refs holds the referenced address so you can use them later
refs.add(next_head)
return "Conditional Branch"
else:
return "Unconditional Branch"
else:
return "Not JMP/Branch at all"
这个解决方案不是 100% 架构不可知的,但它更简单一点,添加对具有延迟槽的架构的支持应该不会太困难。如果您只对流程是否有条件感兴趣,那么您可以忽略该Rfirst0部分。
def conditional_branches_for(ea):
func = idaapi.get_func(ea)
for basicblock in idaapi.FlowChart(func):
# Insert logic here for getting branch for archs with delay slots
last_ea = PrevHead(basicblock.endEA)
# Get any Xrefs that are not part of the regular flow
if Rfirst0(last_ea) == idaapi.BADADDR:
print('Skipping {:#x} because it is not a branch'.format(last_ea))
continue
successors = len(tuple(basicblock.succs()))
if successors == 0:
branch_type = 'does not branch'
elif successors == 1:
branch_type = 'has an unconditional branch'
else:
branch_type = 'has a conditional branch'
print('BasicBlock at {:#x} {}'.format(last_ea, branch_type))