Skip to content

Instantly share code, notes, and snippets.

@nirizr
Last active September 1, 2022 20:11
Show Gist options
  • Save nirizr/fe0ce9948b3db05555da42bbfe0e5a1e to your computer and use it in GitHub Desktop.
Save nirizr/fe0ce9948b3db05555da42bbfe0e5a1e to your computer and use it in GitHub Desktop.
IDAPYTHON: List all references to all stack variables of a function
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())
@nirizr
Copy link
Author

nirizr commented Aug 14, 2017

I wrote this to answer the following RE.SO question:
https://reverseengineering.stackexchange.com/q/16055/2147

@KulaGGin
Copy link

KulaGGin commented Jan 26, 2022

This code doesn't work: it's outdated, it has multiple bugs and the algorithm is simply wrong. Don't anyone use it, and if you try, you won't be able to, anyway. I'll give you just a few examples: flags = idc.GetFlags(ea) is just wrong, there is no ea variable in this script. Meaning this code never actually worked. The idc.GetSpd(func_item) call is again wrong: GetSpd takes past-the-end address, not the address of the current instruction.

And even after you supply a proper argument for GetSpd, the formula op.addr + idc.GetSpd(func_item) + stack_base is still wrong. The GetSpd gets 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 instruction mov [rbp+0F0h+var_18], rax at address 0x14001242A. var_18 is at offset 0x18 respectively. The past-the-end address is 0x140012431, so I do idc.GetSpd(0x140012431), and get -0x118.

Then formula: op.addr + idc.GetSpd(func_item) + stack_base turns into: 0x14001242A + (-0x118) + 0x118, which equals to 0x14001242A, 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 in the question: https://reverseengineering.stackexchange.com/a/16095/33592

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment