TL;DR: There's no simple API to achieve this, code is at the end of the answer or here.
As far as I know, there is no easy way to get the references to stack structure. It seems like calling idautils.XrefsTo(sid)
where sid
is the frame id (retrieved using idc.GetFrame
) should work, however I couldn't get it to yield any result in my attempts.
Instead, however, you could walk over the function's instructions and calculate the offsets into the stack manually whenever a stack reference operand is encountered.
I created a gist snippet to show just that, and although I think it's quite self-explanatory I'll go over it briefly here.
First, we'll need a mapping of stack offsets to arguments, this is taken care of by the find_stack_members
function, which uses the idc.GetFrame
API function mentioned above to get the structure ID for the stack of a specific function. Then, it uses idautils.StructMembers
API to iterate over the stack variables.
One interesting piece of logic in the find_stack_members
function is that it uses the <space>r
member name as the base of the stack (where the stack is once the function is entered), this is used later in find_stack_xrefs
to calculate the stack offset of a variable based on the current stack delta and the operand immediate value.
The find_stack_xrefs
function iterates over the instructions in the given function, and skips any instruction but those with a operand defined to reference the stack (note that arguments that reference the stack but aren't defined as such by either IDA's auto-analysis or manually will not be treated and hence will not count as a cross-reference).
If a stack offset operand exists in the instrcution, the find_stack_xrefs
function will proceed to calculate it's offset using the stack's base offset (previously retrieved by find_stack_members
), the current stack delta (calculated by IDA and available using the API idc.GetSpd
) and the immediate taken from the Operand structure.
For convenience, I'm also including the code here:
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())