def fields(self, reload=False): if reload or not self._fields: self._fields = {} m = 0 while True: if m >= idc.GetStrucSize(self.id): break n = idc.GetMemberName(self.id, m) if n == idc.BADADDR: break sz = idc.GetMemberSize(self.id, m) mid = idc.GetMemberId(self.id, m) tp = idc.GetType(mid) fld = { 'offset': m, 'id': mid, 'name': n, 'size': sz, 'type': [tp, None] } if n != '': fld['type'][1] = idc.GetMemberFlag(self.id, m) self._fields[m] = fld m = idc.GetStrucNextOff(self.id, m) if m == idc.BADADDR: break return self._fields
def get_object_id_of_union_member_id(hash_provider, member_id): try: return union_member_object_ids[member_id] except KeyError: idx = idc.GetFirstStrucIdx() while idx != idc.BADADDR: struc_id = idc.GetStrucId(idx) if idc.IsUnion(struc_id): offset = idc.GetFirstMember(struc_id) while offset != idc.BADADDR: smember_id = idc.GetMemberId(struc_id, offset) if smember_id == member_id: name = idc.GetMemberName(struc_id, offset) if name is not None: struc_name = idc.GetStrucName(struc_id) logger.debug("found member id 0x%016X in union %s/%s" % (member_id, struc_name, name)) return hash_provider.get_struc_member_id_for_name(struc_name, offset) # next member offset = idc.GetStrucNextOff(struc_id, offset) idx = idc.GetNextStrucIdx(idx) logger.error("Could not find member id 0x%016X in unions" % member_id) return None
def get_args(f): local_variables = [] arguments = [] current = local_variables frame = idc.GetFrame(f) arg_string = "" if frame == None: return None start = idc.GetFirstMember(frame) end = idc.GetLastMember(frame) count = 0 max_count = 10000 args_str = "" while start <= end and count <= max_count: size = idc.GetMemberSize(frame, start) count = count + 1 if size == None: start = start + 1 continue name = idc.GetMemberName(frame, start) start += size if name in [" r", " s"]: # Skip return address and base pointer current = arguments continue arg_string += " " + name current.append(name) if len(arguments) == 0: arguments.append("void") return arguments
def walk_members(ea): global num_stackframes, num_default_stackframe_members frame = idaapi.get_frame(ea) if not frame: return num_stackframes += 1 sid = frame.id s = idaapi.get_struc(sid) if s is None or s == idaapi.BADADDR: return known = set() base = idc.GetFrameLvarSize(ea) for idx in xrange(0, s.memqty): ea = yatools.get_struc_member_by_idx(s, idx) if ea in known: continue m = idaapi.get_member(frame, ea) if not m or idaapi.is_special_member(m.id): continue is_data = m.flag == idaapi.FF_DATA is_default_name = idc.GetMemberName( sid, ea) == get_default_struc_member_name(False, ea, base) size = idaapi.get_member_size(m) no_comment = is_nil(idaapi.get_member_cmt(m.id, 0)) no_repeated = is_nil(idaapi.get_member_cmt(m.id, 1)) if not s.is_union( ) and is_data and size == 1 and is_default_name and no_comment and no_repeated: num_default_stackframe_members += 1 continue if m and not idaapi.is_special_member(m.id): known.add(ea) yield m
def get_struc_offset(ea, opn): path = idaapi.tid_array(1) delta = idaapi.sval_pointer() idaapi.get_stroff_path(ea, opn, path.cast(), delta.cast()) struct = path[0] if idaapi.decode_insn(ea) == 0: print 'error in {0}'.format(GetDisasm(ea)) else: op = idaapi.cmd.Operands[opn] offset = op.value result = [] idaapi.get_stroff_path(ea, opn, path.cast(), delta.cast()) struct = path[0] while offset: member_id = idc.GetMemberId(struct, offset) member_name = idc.GetMemberName(member_id) field_struct_id = idc.GetMemberStrId(struct, offset) if field_struct_id != idc.BADADDR: result.append( [field_struct_id, idc.GetStrucName(field_struct_id)]) else: result.append([member_name, idc.GetMemberFlag(struct, offset)]) return result offset -= idc.GetMemberOffset(member_name)
def getFunctionArgumentCount(ea): ''' Bit of a hack, since IDA doesn't seem to have a good way to get this information. Gets the frame for a given function, and counts named members following the 'r' member. Note: IDA won't create a frame member for an unreferenced function arg... so you've been warned. ''' rFound = False argCount = 0 sid = idc.GetFrame(ea) midx = idc.GetFirstMember(sid) while midx != idc.BADADDR: name = idc.GetMemberName(sid, midx) if rFound and name is not None: argCount += 1 #print 'Found arg at 0x%x: "%s"' % (midx, name) elif name == ' r': #print 'Found r at 0x%x:' % midx rFound = True else: #print 'Found nonarg at 0x%x: "%s"' % (midx, name) pass midx = idc.GetStrucNextOff(sid, midx) return argCount
def yacheck_reference_loop(self): for k in range(0, 2): sid = idc.GetStrucIdByName('refloop' + str(k)) self.assertNotEqual(sid, idaapi.BADADDR) self.assertEqual(idc.GetMemberName(sid, 0), 'refloop_field' + str(k)) mid = idc.GetMemberId(sid, 0) self.assertNotEqual(mid, -1) self.assertEqual(idc.GetType(mid), 'refloop' + str(1 - k) + ' *')
def yacheck_create_struct_in_stack_vars_with_renaming(self): sida = yaunit.load("create_struct_in_stack_vars_with_renaming") offset = yaunit.load("create_struct_in_stack_vars_with_renaming_offset") self.assertEqual("var1", idc.GetMemberName(sida, offset)) stype = fix_ptr_type(idc.GetType(idc.GetMemberId(sida, offset))) self.assertEqual("create_struct_in_stack_vars_with_renaming*", stype)
def build_stack_args(f): stackArgs = dict() name = idc.Name(f) end = idc.GetFunctionAttr(f, idc.FUNCATTR_END) _locals = idc.GetFunctionAttr(f, idc.FUNCATTR_FRSIZE) _uses_bp = 0 != (idc.GetFunctionFlags(f) & idc.FUNC_FRAME) frame = idc.GetFrame(f) if frame is None: return stackArgs func_type = idc.GetType(f) if (func_type is not None) and ("(" in func_type): args = func_type[ func_type.index('(')+1: func_type.rindex(')') ] args_list = [ x.strip() for x in args.split(',')] if "..." in args_list: return stackArgs if name in RECOVER_DEBUG_FL: return stackArgs #grab the offset of the stored frame pointer, so that #we can correlate offsets correctly in referent code # e.g., EBP+(-0x4) will match up to the -0x4 offset delta = idc.GetMemberOffset(frame, " s") if -1 == delta: #indicates that it wasn't found. Unsure exactly what to do # in that case, punting for now delta = 0 offset = idc.GetFirstMember(frame) while -1 != _signed_from_unsigned(offset): memberName = idc.GetMemberName(frame, offset) if memberName is None: # gaps in stack usage are fine, but generate trash output # gaps also could indicate a buffer that IDA doesn't recognize offset = idc.GetStrucNextOff(frame, offset) continue if (memberName == " r" or memberName == " s"): #the return pointer and start pointer, who cares offset = idc.GetStrucNextOff(frame, offset) continue memberSize = idc.GetMemberSize(frame, offset) if offset >= delta: offset = idc.GetStrucNextOff(frame, offset) continue memberFlag = idc.GetMemberFlag(frame, offset) #TODO: handle the case where a struct is encountered (FF_STRU flag) flag_str = _get_flags_from_bits(memberFlag) stackArgs[offset-delta] = {"name":memberName, "size":memberSize, "flags":flag_str, "writes":list(), "referent":list(), "reads":list(), "safe": False} offset = idc.GetStrucNextOff(frame, offset) return stackArgs
def build_stack_variable(func_ea): stack_vars = dict() frame = idc.GetFrame(func_ea) if not frame: return stack_vars f_name = get_symbol_name(func_ea) #grab the offset of the stored frame pointer, so that #we can correlate offsets correctly in referent code # e.g., EBP+(-0x4) will match up to the -0x4 offset delta = idc.GetMemberOffset(frame, " s") if delta == -1: delta = 0 if f_name not in _FUNC_UNSAFE_LIST: offset = idc.GetFirstMember(frame) while -1 != _signed_from_unsigned(offset): member_name = idc.GetMemberName(frame, offset) if member_name is None: offset = idc.GetStrucNextOff(frame, offset) continue if (member_name == " r" or member_name == " s"): offset = idc.GetStrucNextOff(frame, offset) continue member_size = idc.GetMemberSize(frame, offset) if offset >= delta: offset = idc.GetStrucNextOff(frame, offset) continue member_flag = idc.GetMemberFlag(frame, offset) flag_str = _get_flags_from_bits(member_flag) member_offset = offset-delta stack_vars[member_offset] = {"name": member_name, "size": member_size, "flags": flag_str, "writes": list(), "referent": list(), "reads": list(), "safe": False } offset = idc.GetStrucNextOff(frame, offset) else: offset = idc.GetFirstMember(frame) frame_size = idc.GetFunctionAttr(func_ea, idc.FUNCATTR_FRSIZE) flag_str = "" member_offset = _signed_from_unsigned(offset) - delta stack_vars[member_offset] = {"name": f_name, "size": frame_size, "flags": flag_str, "writes": list(), "referent": list(), "reads": list(), "safe": False } return stack_vars
def yacheck_function_local_vars(self): addr = yaunit.load('function_with_local_vars') frame = idaapi.get_frame(addr) frame_size = idaapi.get_struc_size(frame.id) offset = 0 last_name = None while offset < frame_size and last_name is None: last_name = idc.GetMemberName(frame.id, offset) offset += 1 self.assertEqual(last_name, 'local_var')
def add_member_descr(structure, sid): """ Insert comments descripting every member of a structure whose id is sid Arguments: structure -- structure object holding data sid -- structure id """ if len(structure.members) == 0 or \ idc.GetMemberQty(sid) == 0: return members_map = {} for member in structure.members: members_map[member.name] = member m_offset = -1 for i in xrange(0, idc.GetMemberQty(sid)): # for each member of imported structure if i == 0: m_offset = idc.GetFirstMember(sid) else: m_offset = idc.GetStrucNextOff(sid, m_offset) if m_offset == -1 or m_offset == idaapi.BADADDR: break m_name = idc.GetMemberName(sid, m_offset) # None if not m_name: continue if m_name not in members_map: # A same member may have different name between msdn databases # and ida import structure table, ida may add some prefixes. if m_name[1:] in members_map: # start with '_' m_name = m_name[1:] elif re.match(r'^tag(.)*', m_name) and \ m_name[3:] in members_map: # start with 'tag' m_name = m_name[3:] elif re.match(r'^_tag(.)*', m_name) and \ m_name[4:] in members_map: # start with '_tag' m_name = m_name[4:] else: continue idc.SetMemberComment(sid, m_offset, format_comment(members_map[m_name].description), False)
def get_struc_name(self): x = self.target.operands['x'] m = self.target.operands['m'] xtype = x.type xtype.remove_ptr_or_array() typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, xtype, '', '') sid = idc.GetStrucIdByName(typename) member = idc.GetMemberName(sid, m) return '%s::%s' % (typename, member)
def check_field(self, sid, ftype, strid, offset, size, name): if ftype is None: for i in range(offset, offset + size): self.assertIsNone(idc.GetMemberName(sid, i)) self.assertEqual(idc.GetMemberFlag(sid, i), -1) return try: self.assertNotEqual(idc.GetMemberName(sid, offset - 1), name) except: pass for k in range(offset, offset + size): self.assertEqual(idc.GetMemberName(sid, k), name) self.assertEqual(idc.GetMemberSize(sid, k), size) self.assertEqual(idc.GetMemberFlag(sid, k) & idaapi.DT_TYPE, ftype & 0xFFFFFFFF) if strid != -1: st = idaapi.get_struc(sid) mb = idaapi.get_member(st, offset) op = idaapi.opinfo_t() idaapi.retrieve_member_info(op, mb) self.assertEqual(op.tid, strid) self.assertNotEqual(idc.GetMemberName(sid, offset + size), name)
def get_struc_name(self): x = self.target.operands['x'] m = self.target.operands['m'] xtype = typestring(x.type.u_str()) xtype.remove_ptr_or_array() typename = str(xtype) sid = idc.GetStrucIdByName(typename) member = idc.GetMemberName(sid, m) return '%s::%s' % (typename, member)
def setStrucPntr(self, sid, ofs, name, tp=None): vnm = idc.GetMemberName(sid, ofs) if not vnm or vnm in (idc.BADADDR, -1): idc.AddStrucMember(sid, name, ofs, idc.FF_QWRD, -1, 8) vnm = name if vnm != name: idc.SetMemberName(sid, ofs, name) sz = idc.GetMemberSize(sid, ofs) if sz != 8: idc.SetMemberType(sid, ofs, idc.FF_QWRD, -1, 1) mid = idc.GetMemberId(sid, ofs) t = idc.GetType(mid) or '' if tp and t.replace(' ', '') != tp.replace(' ', ''): idc.SetType(mid, tp + ';')
def loadMembers(struc, sid): '''Returns list of tuples of (offset, memberName, member)''' #mixing idc & idaapi, kinda annoying but need low-level idaapi for a # type access, but cant dig into structs... members = [] off = g_dll.get_struc_first_offset(struc) while off >= 0: member = g_dll.get_member(struc, ctypes.c_int(off)) if (member == 0) or (member is None): pass #not really an error, i guess else: members.append((off, idc.GetMemberName(sid, off), member)) off = g_dll.get_struc_next_offset(struc, ctypes.c_int(off)) members.sort(key=lambda mem: mem[0]) return members
def struc_member_list(struc_id, is_union): current_idx = 0 struc = idaapi.get_struc(struc_id) if struc is None or struc == idc.BADADDR: return [] offsets = dict() for current_idx in xrange(0, struc.memqty): offset = _yatools_ida.get_struc_member_by_idx(struc, current_idx) if offset not in offsets: name = idc.GetMemberName(struc_id, offset) if name is not None: offsets[offset] = name return sorted(offsets.items())
def getStackVars(ea, base=-1): # type: (int, int) -> list[(str, int)] """ Gets the stack variables associted with the function at ea If no base is specified, the offsets don't include the base calculation in them :param ea: the address of the function :param base: the stack base, must obtain to compute the offsets relative to it :return: a list of tuples, the stack variable name and its offset """ stackVars = [] id = idc.GetFrame(ea) firstMember = idc.GetFirstMember(id) # if the function has stack variables if firstMember != idaapi.BADADDR and firstMember != -1: # build up disasm based on stack vars lastMember = idc.GetLastMember(id) i = firstMember # Stack can be offset, first member might not be found at index 0, and all offsets must be adjusted by this foundFirstElement = False stackOffset = 0 while i <= lastMember: name = idc.GetMemberName(id, i) off = idc.GetMemberOffset( id, name ) # this is the offset in the struct... which isn't always consistent! size = idc.GetMemberSize(id, i) # append if varname is found (sometimes, None is returned because the variables are not in the next index) if name: # first variable found! this is the stack of the stack variables! if not foundFirstElement: stackOffset = i foundFirstElement = True if base == -1: # absolute offsets appended stackVars.append((name, off - stackOffset)) else: # base-relative offsets appended stackVars.append((name, base - off - stackOffset)) # sometimes, for some reason, the offset for stack variables does not follow linearly if size: i += size else: # reach next var, which might not be one size unit after the last... while not idc.GetMemberSize(id, i) and i <= lastMember: i += 1 return stackVars
def struc_member_renamed(self, struct, membr): sid = struct.id mid = membr.id moff = membr.soff idx = idc.GetStrucIdx(sid) sname = idc.GetStrucName(sid) mname = idc.GetMemberName(sid, moff) self.ctrl._handle_action({ 'action': 'struct_member_renamed', 'struct': idx, 'member': mid, 'sname': sname, 'mname': mname, 'off': moff }) return 0
def StructMembers(sid): """ Get a list of structure members information. @param sid: ID of the structure. @return: List of tuples (offset, name, size) @note: If 'sid' does not refer to a valid structure, an exception will be raised. """ off = idc.GetFirstMember(sid) if off == idaapi.BADNODE: raise Exception("No structure with ID: 0x%x" % sid) members = idc.GetMemberQty(sid) for idx in range(0, members): yield (off, idc.GetMemberName(sid, off), idc.GetMemberSize(sid, off)) off = idc.GetStrucNextOff(sid, off)
def struc_member_created(self, struct, membr): sid = struct.id mid = membr.id moff = membr.soff flag = membr.flag size = idc.GetMemberSize(sid, moff) sname = idc.GetStrucName(sid) mname = idc.GetMemberName(sid, moff) idx = idc.GetStrucIdx(sid) self.ctrl._handle_action({ 'action': 'struct_member_created', 'struct': idx, 'member': mid, 'sname': sname, 'mname': mname, 'off': moff, 'flag': flag, 'size': size }) return 0
def StructMembers(sid): """ Get a list of structure members information (or stack vars if given a frame). @param sid: ID of the structure. @return: List of tuples (offset, name, size) @note: If 'sid' does not refer to a valid structure, an exception will be raised. @note: This will not return 'holes' in structures/stack frames; it only returns defined structure members. """ m = idc.GetFirstMember(sid) if m == -1: raise Exception("No structure with ID: 0x%x" % sid) while (m != idaapi.BADADDR): name = idc.GetMemberName(sid, m) if name: yield (m, name, idc.GetMemberSize(sid, m)) m = idc.GetStrucNextOff(sid, m)
def __init__(self, sid, offs): self.offs = offs #sid = struc name = None substruct = -1 size = 0 if not warnBad(sid): #struc = idaapi.get_struc(sid) #member = idaapi.get_member(struc, offs) name = idc.GetMemberName(sid, offs) substruct = idc.GetMemberStrId(sid, offs) size = idc.GetMemberSize(sid, offs) #name = idaapi.get_member_name(member.id) #substruct = idaapi.get_sptr(member) #size = idaapi.get_member_size(member) self.name = name self.struc = substruct self.size = size
def get_member_name(sid, cur_offset): if idaapi.IDA_SDK_VERSION <= 699: mn = idc.GetMemberName(sid, cur_offset) else: mn = idc.get_member_name(sid, cur_offset) return mn
def clear_struc_fields(self, struc_id, struc_size, xref_keys, is_union=False, member_type=ya.OBJECT_TYPE_STRUCT_MEMBER, name_offset=0): idc.BeginTypeUpdating(idc.UTP_STRUCT) last_offset = idc.GetLastMember(struc_id) # get existing member offsets field_offsets = set() for (xref_offset, xref_operand) in xref_keys: field_offsets.add(xref_offset) new_offsets = set() struc = idaapi.get_struc(struc_id) # create missing members first (prevent from deleting all members) for offset in field_offsets: member = idaapi.get_member(struc, offset) if member is not None and member.soff < offset: # we have a member above this member that is too big and contain this member # clear it! if DEBUG_EXPORTER: logger.debug( "reduce field : set_member_type(0x%08X, 0x%08X), overlapping 0x%08X", struc_id, member.soff, offset) idaapi.set_member_type(struc, member.soff, idc.FF_BYTE, None, 1) member = idaapi.get_member(struc, offset) if member is None or idaapi.get_member_name(member.id) is None: new_offsets.add(offset) member_name = YaToolIDATools.get_default_struc_member_name( member_type, offset, name_offset) if offset == last_offset and offset == struc_size: field_size = 0 else: field_size = 1 if DEBUG_EXPORTER: logger.debug( "AddStrucMember(0x%08X, '%s', 0x%08X, idc.FF_BYTE, -1, 0x%08X), name_offset=%d", struc_id, member_name, offset, field_size, name_offset) retval = idc.AddStrucMember(struc_id, member_name, offset, idc.FF_BYTE, -1, field_size) if retval != 0: logger.error( "Error %d with idc.AddStrucMember(0x%08X, '%s', 0x%08X," "idc.FF_BYTE, -1, 0x%08X), name_offset=%d", retval, struc_id, member_name, offset, field_size, name_offset) elif DEBUG_EXPORTER: logger.debug("Member exists : (0x%08X, '%s', 0x%08X, 0x%08X)", struc_id, idc.GetMemberName(struc_id, offset), offset, idc.GetMemberSize(struc_id, offset)) kept_offsets = field_offsets - new_offsets # clear kept members # split the loop since we will modify the structure while iterating offsets = set() for (offset, member_name) in YaToolIDATools.struc_member_list( struc_id, is_union): offsets.add(offset) for offset in offsets: if offset in kept_offsets: # This member already existed and is kept if offset == last_offset and offset == struc_size: # this is the last field, and it is a variable sized structure field_size = 0 else: field_size = 1 if member_type == ya.OBJECT_TYPE_STRUCT_MEMBER: strucmember_id = self.hash_provider.get_struc_member_id( struc_id, offset) elif member_type == ya.OBJECT_TYPE_STACKFRAME_MEMBER: strucmember_id = self.hash_provider.get_stackframe_member_object_id( struc_id, offset) else: logger.error("Bad member_type : %d" % member_type) if strucmember_id not in self.strucmember_ids: # It is not necessary to clear the member if it is presnet in the resolved_objects if DEBUG_EXPORTER: logger.debug( "SetStrucmember(0x%08X, None, 0x%08X, idc.FF_BYTE, -1, 0x%08X, name_offset=%s)", struc_id, offset, field_size, name_offset) YaToolIDATools.SetStrucmember(struc_id, None, offset, idc.FF_BYTE, -1, field_size, member_type=member_type, name_offset=name_offset) idc.SetMemberComment(struc_id, offset, "", 0) idc.SetMemberComment(struc_id, offset, "", 1) elif offset not in new_offsets: if (member_type != ya.OBJECT_TYPE_STACKFRAME_MEMBER or not idaapi.is_special_member( idc.GetMemberId(struc_id, offset))): if DEBUG_EXPORTER: logger.debug( "DelStrucMember(0x%08X, 0x%08X) (=%s:%s)", struc_id, offset, idc.GetStrucName(struc_id), idc.GetMemberName(struc_id, offset)) idc.DelStrucMember(struc_id, offset) else: # in new_offsets : just created pass idc.EndTypeUpdating(idc.UTP_STRUCT)
def argCount(self): end = idc.GetFunctionAttr(self.addr, idc.FUNCATTR_END) start = idc.GetFunctionAttr(self.addr, idc.FUNCATTR_START) frame = idc.GetFrame(start) localv = idc.GetFunctionAttr(self.addr, idc.FUNCATTR_FRSIZE) frameSize = idc.GetFrameSize(start) #idc.GetStrucSize(frame) reg_off = 0 local_count = 0 arg_count = 0 sid = idc.GetFrame(self.addr) if sid: firstM = idc.GetFirstMember(sid) lastM = idc.GetLastMember(sid) arg_count = 0 if lastM - firstM > 0x1000: return for i in xrange(firstM, lastM): mName = idc.GetMemberName(sid, i) mSize = idc.GetMemberSize(sid, i) mFlag = idc.GetMemberFlag(sid, i) off = idc.GetMemberOffset(sid, mName) #print "%s: %d, %x, off=%x" % (mName, mSize, mFlag, off) if mName == " r": reg_off = off # XXX: just store the data, dont loop twice. for i in xrange(firstM, lastM): mName = idc.GetMemberName(sid, i) mSize = idc.GetMemberSize(sid, i) mFlag = idc.GetMemberFlag(sid, i) off = idc.GetMemberOffset(sid, mName) if off <= reg_off: local_count += 1 elif off > reg_off and reg_off != 0: arg_count += 1 if arg_count > 0: return arg_count / 4 elif arg_count == 0: return 0 # offset to return try: ret = idc.GetMemberOffset(frame, " r") except: if frameSize > localv: return (frameSize - localv) / 4 # error getting function frame (or none exists) return -1 if (ret < 0): if frameSize > localv: return (frameSize - localv) / 4 return -1 firstArg = ret + 4 args = frameSize - firstArg numArgs = args / 4 return numArgs
def get_name(self): return idc.GetMemberName(*self.mid) or "{no_name}"
# func_frames maps from function address to a record of the function's stack # frame size and local variables. func_frames = {} func_addrs = [] for seg in idautils.Segments(): # Skip extern segment; as used by IDA for external functions. if idc.get_segm_attr(seg, SEGATTR_TYPE) == idc.SEG_XTRN: #print("skipping segment ", idc.get_segm_name(seg)) continue for fn in idautils.Functions(seg, idc.get_segm_end(seg)): func_addr = fn frame = ida_frame.get_frame(func_addr) frame_size = ida_frame.get_frame_size(func_addr) var_names = [] for i in range(frame_size): var_name = idc.GetMemberName(frame, i) # TODO: check if ' r' and ' s' (return address and saved registers) may have # duplicates. if var_name is None: continue var_names.append(var_name) print(var_names) func_frame = {"func_name": func_name, "func_type": func_type} func_frames[func_addr] = func_frame func_addrs.append(func_addr) # TODO: check diff between ESP at function entry and each instruction. # fn = idaapi.get_func(0) # ida_frame.get_effective_spd(fn, inst_ea) # # TODO: check whether to use get_effective_spd or get_spd.