Ejemplo n.º 1
0
def MakeStackVarName(ea,off):
    """Given an routine address, fetch the name of the stack variable
    at the specified offset from the return address, and format it for
    display.

    >>> MakeStackVarName(ScreenEA(), 0x140)
    var_13C
    >>> MakeStackVarName(ScreenEA(), -4)
    (pushed arg)

    Returns:
        String name of the stack variable.
    """
    (Member,MemberOffset) = GetStackMemberContaining(ea,off)

    StackVarName = "???+" + name.Offset(off)
    if Member:
        StackVarName = ida.get_member_name(Member.id)

        if MemberOffset != 0:
            StackVarName += name.Offset(MemberOffset)
    elif MemberOffset < 0:
        # Currently, I have no way of enumerating stack-based argument
        # names, so we just return a generic name.
        StackVarName = "(pushed arg)"

    return StackVarName
Ejemplo n.º 2
0
def GetStackMemberContaining(ea,off):
    """
    @return Tuple containing (Nearest Stack Variable, Offset)

    Retrieve the name of a stack variable from the routine which
    contains address EA, where the stack variable is at offset 'off'
    from the initial stack pointer upon routine entry.

    For more information, see the source to IdaPython, as there are
    no documented APIs to do this.  Relevant source is for 'MakeLocal',
    at: https://code.google.com/p/idapython/source/browse/trunk/python/idc.py?r=333#855

    Consider the following frame, where we want to get the name for the
    stack variable that is 0x30 bytes from the return addr.

    -00000030 Zach            dd ?                    ; offset
    -0000002C FreeWilly       dd ?                    ; offset
    -00000028 b               dd ?                    ; offset
    -00000024 LooksLikeMemory dd ?
    -00000020 a               dd ?                    ; offset
    -0000001C xzibit          YoDawg ?
    -00000018 ms_exc          CPPEH_RECORD ?
    +00000000  s              db 4 dup(?)
    +00000004  r              db 4 dup(?)
    +00000008 argc            dd ?
    +0000000C argv            dd ?                    ; offset
    +00000010 envp            dd ?                    ; offset

    The variable we want is 'FreeWilly'.  Although IDA claims it is
    at offset 2C, this is based from the stack frame pointer, not the
    return addr.  Our offset is from RA.
    """

    # Helper for error message
    ErrLoc = "%s (%s)" % (addr.Clickable(ea), name.From(ea))

    # Returns a func_t*
    Func = ida.get_func(ea)

    # Returns a struc_t*
    Frame = ida.get_frame(Func)

    #
    # Find out how tall the frame is
    #
    # This is roughly the total size between $ra and the highest
    # stack variable.
    #
    FrameSize = ida.GetFrameSize(ea)

    #
    # Find the frame member whose EOFF is the same value
    # This will be the return address
    #
    ReturnAddr = None
    MemberCount = Frame.memqty

    for i in xrange(MemberCount):
        Member = Frame.get_member(i)
        Name   = ida.get_member_name(Member.id)
        # print repr(Name)
        # EOFF   = Member.eoff
        # if EOFF == FrameSize:
        if Name == " r":
            ReturnAddr = Member

    if not ReturnAddr:
        print "!!! Could not find return address in %s" % ErrLoc
        return (None, off)

    #
    # Calculate the offset from the return address,
    # and find the member with a matching EOFF
    #
    # IDA Stack frames look like this interanlly:
    #
    # ----------------- --.
    # local 1             |
    # -----------------   | Frame size
    # local 0             |
    # -----------------   |
    # frame pointer       |
    # -----------------   |
    # return address      |
    # ----------------- --'
    # arg0
    # -----------------
    # arg1
    #
    #
    # N.B. There may not be a matching value.  For example,
    #      a routine may 'lea ecx, [esp+xxx]' for a __thiscall,
    #      but never touch anything inside the large span of
    #      memory available for the structure.
    # Members   = [Frame.get_member(i) for i in xrange(MemberCount)]
    # StackOffs = [(m.soff, m.eoff)    for m in Members]

    DesiredOff = ReturnAddr.soff - off

    # print "ErrLoc    %s"    % ErrLoc
    # print "FrameSize %x"    % FrameSize
    # print "$ra       %x-%x" % (ReturnAddr.soff, ReturnAddr.eoff)
    # print "off       %x"    % off
    # print "size      %x"    % size
    # print "Desired   %x"    % DesiredOff

    rv = (None, off)
    if DesiredOff >= 0:
        Members = [Frame.get_member(i) for i in xrange(MemberCount)]
        SOFFs   = [M.soff for M in Members]
        EOFFs   = [M.eoff for M in Members]


        for i in range(MemberCount):
            Member = Members[i]
            Name   = ida.get_member_name(Member.id)
            sThis  = SOFFs[i]
            sNext  = EOFFs[i]

            try:    sNext = SOFFs[i+1]
            except: pass

            # print "%20s %x..%x" % (Name,sThis,sNext)

            if sThis <= DesiredOff and DesiredOff < sNext:
                # print "%x <= %x < %x" % (sThis, DesiredOff, sNext)
                rv = (Member, DesiredOff-sThis)

    else:
        rv = (None, DesiredOff)
    return rv