1

I want to detect all the variables live at any instruction/address in a binary. By variable, I refer to both global as well as function local variables. In other words, given a Linux ELF and a virtual address, is there any means to know programmatically what all are the variables (in terms of memory locations) live at that point?

IDA Pro seems to detect the memory locations of probable variables in a procedure. Does IDA expose any API to collect such information?

I plan to use DynamoRIO to dynamically monitor the program at run-time. A call-ret pair should mark the beginning and ending of a function. Once I encounter a call, I monitor all the read-write accesses on stack locations referenced either by %ebp or %esp. The problem is tail-calls where compiler optimizes a call substituting by jmp, thereby detection of function virtually impossible.

2
  • What do you mean by all the variables ? Are globals and caller function locals included ? What about other threads ?
    – w s
    Nov 3, 2015 at 9:24
  • I have updated the original question. Kindly have a look at it.
    – sherlock
    Nov 3, 2015 at 9:40

1 Answer 1

4

I don't think that it is possible.

Let's assume the following C code:

int f1(int p1, int p2)
{
    int l1, l2, l3;
    /* some code */
    l1 = l1 + l2; // here is our virtual address
    return l1;
}

int f2(int p3, int p4)
{
    int l4, l5, l6;
    return f1(p3, p4);
}

int f3(int p5, p6)
{
    int l7, l8;
    return f2(p5, p6) + f1(p6, p5);
}

Obviously the set of local variables in whole the stack of this thread will be different when calling f3, f2 and f1.

For example when f3 calls f2 f2's locals are on stack. after call to f2 when f3 calls f1 obviously the whole threads stack is different and f2 locals are not alive and it is impossible to restore the full stack layout of callers without knowing the full execution sequence and stack trace.

Determining global variables, however, is simpler - they always alive and can be retrieved by iteration on all data and bss like elf segments with, for example, following simple code:

import idautils
import idc
seg_list = [".bss", ".data"] #insert your segment names here
seg_addrs = []
for seg in Segments():
    if idc.SegName(seg) in seg_list:
        seg_addrs.append(seg)

for seg in seg_addrs:  
    start = SegStart(seg)
    end = SegEnd(seg)
    for ea in idautils.Heads(start, end):
        gen_xrefs = XrefsTo(ea, 0)
        for xx in gen_xrefs:
            print hex(ea), hex(xx.frm)

Everything which Ida recognizes as referenced will be printed out. The accuracy of these results, however, is questionable and depends on accuracy of IDA analysis.

Function local variables and stack layout can be retrieved by getting the stack frame structure, with usage of the following APIs:

GetFrame(ea)         #Get ID of function frame structure
GetFrameLvarSize(ea) #Get size of local variables in function frame
GetFrameRegsSize(ea) #Get size of saved registers in function frame
GetFrameArgsSize(ea) #Get size of arguments in function frame which are purged upon return
GetFrameSize(ea)     #Get full size of function frame

The frame structure may be observed with the following IDAPython APIs from idc module:

GetMemberId(sid, member_offset)
GetStrucPrevOff(sid, offset)
GetStrucNextOff(sid, offset)
GetFirstMember(sid)
GetLastMember(sid)
GetMemberOffset(sid, member_name)
GetMemberName(sid, member_offset)
GetMemberComment(sid, member_offset, repeatable)
GetMemberSize(sid, member_offset)
GetMemberFlag(sid, member_offset)
GetMemberStrId(sid, member_offset)
IsUnion(sid)

Hope it helps.

3
  • 1
    What if a function is recursive? What if it calls alloca ? What if a signal handler (linux), or exception handler (windows) calls a function? There's just too many ways for local variables to get generated anywhere on the stack to reliably determine every possible location for a particular variable. There's only 2 things you can do - stop the program at a specific point and check the current stack frame, or analyze the call tree and local stacks to get a "what happens if we omit all special cases" list. Nov 3, 2015 at 13:36
  • Kindly check the OP once again. I have updated the last paragraph to explain my approach. The problem now lies in detecting a tail-call where compiler optimizes a CALL substituting by JMP.
    – sherlock
    Nov 12, 2015 at 6:37
  • I'd suggest to ask this question separately to make the question more visible. I never used DinamoRio, so may be somebody else will help you,
    – w s
    Nov 12, 2015 at 7:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.