Last active
September 1, 2022 20:11
-
-
Save nirizr/fe0ce9948b3db05555da42bbfe0e5a1e to your computer and use it in GitHub Desktop.
IDAPYTHON: List all references to all stack variables of a function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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