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())
flags = idc.GetFlags(ea)is just wrong, there is noeavariable in this script. Meaning this code never actually worked. Theidc.GetSpd(func_item)call is again wrong:GetSpdtakes past-the-end address, not the address of the current instruction. – KulaGGin Jan 26 '22 at 08:46GetSpd, the formulaop.addr + idc.GetSpd(func_item) + stack_baseis still wrong. TheGetSpdgets the difference between the initial and current values of ESP and doesn't help to determine which stack variable is referenced and on what offset. For example, I have instructionmov [rbp+0F0h+var_18], raxat address0x14001242A.var_18is at offset 0x18 respectively. The past-the-end address is0x140012431, so I do idc.GetSpd(0x140012431), and get-0x118. – KulaGGin Jan 26 '22 at 08:54op.addr + idc.GetSpd(func_item) + stack_baseturns into:0x14001242A + (-0x118) + 0x118, which equals to0x14001242A, which is the instruction address, not the stack offset. Which makes this answer completely wrong. If you want a working solution, check out the accepted answer by @mayahustle. – KulaGGin Jan 26 '22 at 08:54