idapython - 获取外部参照到堆栈变量
有一个函数可以执行此操作:build_stkvar_xrefs
,在 C++ 中定义,但通过 Python SWIG 绑定公开。当您需要时,IDA 会动态构建堆栈外部参照。为了使用该功能,需要进行一些设置。
你需要使用一些函数来获得你需要的东西:
get_func(ea)
: 检索func_t
函数的结构ea
get_frame(func_t foo)
: 返回由struct_t
指定的函数框架的结构foo
DecodeInstruction(ea)
: 返回inst_t
代表指令在ea
get_stkvar(op_t op, sval_t v)
:op
是对指令的引用,v
是操作数中的立即数。通常你只是使用op.addr
. 它返回一个元组,(member_t, val)
。member_t
是一个指向堆栈变量的指针,这正是我们所需要的。与堆栈val
变量中的soff
字段值相同member_t
。稍后会详细介绍。xreflist_t()
: 创建一个新xreflist
的xreflist_entry_t
build_stkvar_xrefs(xreflist_t xrefs, func_t func, member_t member)
: 用xreflist_entry_t
表示member
in给出的堆栈 var 外部参照的's填充外部参照func
。struct_t.get_member(x)
:您可以使用此方法迭代帧中的所有堆栈变量以检索所有member_t
的。如果要为所有堆栈变量构建外部参照,这通常更容易。
这是所有这些如何联系在一起的示例:
# 0x4012d0 is the function address
# 0x4012dc is an instruction address referencing
# a stack variable. It looks like:
# mov [ebp - 4], ecx
pFunc = get_func(0x4012d0)
pFrame = get_frame(pFunc)
inst = DecodeInstruction(0x4012dc)
op = inst[0] #first operand references stack var
pMember, val = get_stkvar(op, op.addr)
xrefs = xreflist_t()
build_stkvar_xrefs(xrefs, pFunc, pMember)
for xref in xrefs:
print hex(xref.ea) #print xref address
# Contrived member dictionary example.
dictMem = dict()
x = 0
while(x < pFrame.memqty):
dictMem[GetMemberName(pFrame.id, pFrame.get_member(x).soff)] = pFrame.get_member(x)
x = x+1
# given var name you can now use the
# dictionary to grab the member_t to pass
# to build_stkvar_xrefs
pMem = dictMem["var_4"]
xrefs = xreflist_t()
build_stkvar_xrefs(xrefs, pFunc, pMem)
for xref in xrefs:
print hex(xref.ea) #print xrefs to var_4
soff
不是堆栈偏移量。我认为它的意思是“结构偏移”,它是帧结构的偏移,因此您可以检索其他位信息。您将需要此字段来使用其他与堆栈变量相关的函数,例如:SetMemberType、SetMemberName、GetMemberName、DelStrucMember 等。
因此,对于外部参照查找的简单动态变量名称,您可以执行以下操作:
def get_stack_xrefs(func_ea, var_name):
pFunc = get_func(func_ea)
pFrame = get_frame(pFunc)
pMember = None
result = []
while(x < pFrame.memqty):
if GetMemberName(pFrame.id, pFrame.get_member(x).soff) == var_name:
pMember = pFrame.get_member(x)
break;
x = x+1
if pMember:
xrefs = xreflist_t()
build_stkvar_xrefs(xrefs, pFunc, pMember)
for each in xrefs:
result.append(each.ea)
return result
如果您想了解有关这些功能的更多信息,我建议您查看 IDA SDK 文档中的以下模块(无特定顺序):
- 功能文件
- 框架.hpp
- 结构体
参考:https : //www.hex-rays.com/products/ida/support/sdkdoc/files.html
TL;DR:没有简单的 API 来实现这一点,代码在答案的末尾或这里。
据我所知,没有简单的方法来获取对堆栈结构的引用。似乎调用帧 ididautils.XrefsTo(sid)
在哪里sid
(使用 检索idc.GetFrame
)应该可以工作,但是我无法在尝试中产生任何结果。
但是,您可以遍历函数的指令并在遇到堆栈引用操作数时手动计算堆栈中的偏移量。
我创建了一个要点片段来展示这一点,虽然我认为它很容易解释,但我会在这里简要介绍一下。
首先,我们需要堆栈偏移量到参数的映射,这由find_stack_members
函数处理,它使用idc.GetFrame
上面提到的API 函数来获取特定函数堆栈的结构 ID。然后,它使用idautils.StructMembers
API 迭代堆栈变量。
find_stack_members
函数中一个有趣的逻辑是它使用<space>r
成员名称作为堆栈的基础(一旦进入函数,堆栈就在这里),稍后用于find_stack_xrefs
根据当前计算变量的堆栈偏移量堆栈增量和操作数立即值。
该find_stack_xrefs
函数迭代给定函数中的指令,并跳过任何指令,但那些定义为引用堆栈的操作数的指令(请注意,引用堆栈但未由 IDA 的自动分析或手动定义的参数将不会被处理,因此不会算作交叉引用)。
如果指令中存在堆栈偏移操作数,该find_stack_xrefs
函数将继续使用堆栈的基偏移(之前由 检索find_stack_members
)、当前堆栈增量(由 IDA 计算并使用 API 可用idc.GetSpd
)和从操作数中获取的立即数来计算它的偏移结构体。
为方便起见,我还在此处包含了代码:
import idc, idaapi, idautils, ida_xref
def find_stack_members(func_ea):
members = {}
base = None
frame = idc.GetFrame(func_ea)
for frame_member in idautils.StructMembers(frame):
member_offset, member_name, _ = frame_member
members[member_offset] = member_name
if member_name == ' r':
base = member_offset
if not base:
raise ValueError("Failed identifying the stack's base address using the return address hidden stack member")
return members, base
def find_stack_xrefs(func_offset):
func_ea = ida_funcs.get_func(func_offset).startEA
members, stack_base = find_stack_members(func_ea)
for func_item in FuncItems(func_ea):
flags = idc.GetFlags(ea)
stkvar = 0 if idc.isStkvar0(flags) else 1 if idc.isStkvar1(flags) else None
if not stkvar:
continue
ida_ua.decode_insn(func_item)
op = ida_ua.cmd.Operands[stkvar]
stack_offset = op.addr + idc.GetSpd(func_item) + stack_base
member = members[stack_offset]
print("At offset {:x} stack member {} is referenced by operand number {}".format(func_item, member, stkvar))
if __name__ == "__main__":
find_stack_xrefs(idc.ScreenEA())