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)