sdasgup3
3/30/2017 - 6:27 AM

recover stack resident "scalar variables" and "structures"

recover stack resident "scalar variables" and "structures"

import idaapi
import idc 
import idautils


def _get_flags_from_bits(flag):
    if -1 == flag:
        return ""
    cls = {
      'MASK':1536,
      1536:'FF_CODE',
      1024:'FF_DATA',
      512:'FF_TAIL',
      0:'FF_UNK',
    }

    comm = {
      'MASK':1046528,
      2048:'FF_COMM',
      4096:'FF_REF',
      8192:'FF_LINE',
      16384:'FF_NAME',
      32768:'FF_LABL',
      65536:'FF_FLOW',
      524288:'FF_VAR',
      49152:'FF_ANYNAME',
    }

    _0type = {
      'MASK':15728640,
      1048576:'FF_0NUMH',
      2097152:'FF_0NUMD',
      3145728:'FF_0CHAR',
      4194304:'FF_0SEG',
      5242880:'FF_0OFF',
      6291456:'FF_0NUMB',
      7340032:'FF_0NUMO',
      8388608:'FF_0ENUM',
      9437184:'FF_0FOP',
      10485760:'FF_0STRO',
      11534336:'FF_0STK',
    }
    _1type = {
      'MASK':251658240,
      16777216:'FF_1NUMH',
      33554432:'FF_1NUMD',
      50331648:'FF_1CHAR',
      67108864:'FF_1SEG',
      83886080:'FF_1OFF',
      100663296:'FF_1NUMB',
      117440512:'FF_1NUMO',
      134217728:'FF_1ENUM',
      150994944:'FF_1FOP',
      167772160:'FF_1STRO',
      184549376:'FF_1STK',
    }
    datatype = {
      'MASK':4026531840,
      0:'FF_BYTE',
      268435456:'FF_WORD',
      536870912:'FF_DWRD',
      805306368:'FF_QWRD',
      1073741824:'FF_TBYT',
      1342177280:'FF_ASCI',
      1610612736:'FF_STRU',
      1879048192:'FF_OWRD',
      2147483648:'FF_FLOAT',
      2415919104:'FF_DOUBLE',
      2684354560:'FF_PACKREAL',
      2952790016:'FF_ALIGN',
    }

    flags = set()
    flags.add(cls[cls['MASK']&flag])

    for category in [comm, _0type, _1type, datatype]:
        val = category.get(category['MASK']&flag, None)
        if val:
            flags.add(val)
    return flags


def _signed_from_unsigned64(val):
    if val & 0x8000000000000000:
        return -0x10000000000000000 + val
    return val
  
def  _explore_struct(idx):
  if ( idx == -1 ): 
    print("Internal IDA error, GetStrucId returned -1!")
  
  name = GetStrucName(idx)
  size = GetStrucSize(idx)
  members = GetMemberQty(idx)

  print "\tName {0} Size {1} Qnty {2}\n".format(name, size, members)
  member_off = 0
  while member_off != size :
    mname = GetMemberName(idx,member_off);
    if mname == "": 
      print "  Hole ( {0} bytes)\n".format(GetStrucNextOff(idx,member_off)-member_off)
    else :
      msize = GetMemberSize(idx,member_off);
      mtype = GetMemberFlag(idx,member_off) & DT_TYPE;
      if  mtype == FF_BYTE          : mtype = "Byte"
      elif  mtype == FF_WORD     : mtype = "Word"
      elif  mtype == FF_DWRD     : mtype = "Double word"
      elif  mtype == FF_QWRD     : mtype = "Quadro word"
      elif  mtype == FF_TBYT     : mtype = "Ten bytes"
      elif  mtype == FF_ASCI     : mtype = "ASCII string"
      elif  mtype == FF_STRU     : mtype = "Structure {0}".format(GetStrucName(GetMemberStrId(idx,member_off))) 
      #elif  mtype == FF_XTRN     : mtype = "Unknown external?!"
      elif  mtype == FF_FLOAT    : mtype = "Float"
      elif  mtype == FF_DOUBLE   : mtype = "Double"	
      elif  mtype == FF_PACKREAL : mtype = "Packed Real"
      else                          : mtype = "Unknown Type {0:x}".format(mtype)

      print "MName {0} Size {1} Type {2}".format(mname, msize, mtype)
      mtype = GetMemberFlag(idx,member_off);
      if isOff0(mtype):   print(" Offset")
      elif  isChar0(mtype) :print(" Character")
      elif  isSeg0(mtype)  :  print(" Segment")
      elif  isDec0(mtype)  : print(" Decimal")
      elif  isHex0(mtype)  : print(" Hex")
      elif  isOct0(mtype)  : print(" Octal")
      elif  isBin0(mtype)  : print(" Binary")
    member_off = GetStrucNextOff(idx,member_off)

def recover_stack_arg(base='ebp'):

    funcs = idautils.Functions()
    for f in funcs:
      print "\nRecover stack args of {0}".format(idc.Name(f));
      # find the stack frame
      frame = idc.GetFrame(f)
      if frame is None:
        print "None."
        return

      _uses_bp = 0 != (idc.GetFunctionFlags(f) & idc.FUNC_FRAME)
      size  = idc.GetStrucSize(frame)
      delta = idc.GetMemberOffset(frame, " s")
      if -1 == delta:
        return "base pointer cannot be located."  
      else: 
        print "base pointer offset {0:x}".format(delta) 

      # figure out all of the variable names
      offset = idc.GetFirstMember(frame)
      while -1 != _signed_from_unsigned64(offset):
        memberName = idc.GetMemberName(frame, offset)
        if memberName is None:
            memberName = "gap"
            offset = idc.GetStrucNextOff(frame, offset)
            continue
        memberSize = idc.GetMemberSize(frame, offset)
        memberFlag = idc.GetMemberFlag(frame, offset)
        flag_str = _get_flags_from_bits(memberFlag)
        print "Offset {0:x} Name {1} Size {2} Flags {3}".format(offset - delta, memberName, memberSize, flag_str)
        if 'FF_STRU' in flag_str:
          idx  = GetStrucIdByName('biff')
          _explore_struct(idx)

        offset = idc.GetStrucNextOff(frame, offset)


if __name__ == "__main__":
  #idaapi.autoWait()
  recover_stack_arg()
  #idc.Exit(0)