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 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 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 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.get_func_attr(func_ea, idc.FUNCATTR_FRAME) 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.get_first_member(frame) while -1 != _signed_from_unsigned(offset): member_name = idc.get_member_name(frame, offset) if member_name is None: offset = idc.get_next_offset(frame, offset) continue if (member_name == " r" or member_name == " s"): offset = idc.get_next_offset(frame, offset) continue member_size = idc.GetMemberSize(frame, offset) if offset >= delta: offset = idc.get_next_offset(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.get_next_offset(frame, offset) else: offset = idc.get_first_member(frame) frame_size = idc.get_func_attr(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 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 set_struct_offsets(offsets, sid): for offset in offsets: try: add_struct_member(sid, offset_name(offset), offset.offset, offset.size) except exceptions.SarkErrorStructMemberName: # Get the offset of the member with the same name existing_offset = idc.GetMemberOffset(sid, offset_name(offset)) if offset.offset == existing_offset: pass else: raise except exceptions.SarkErrorStructMemberOffset: # Get the size of the member at the same offset if offset.size == idc.GetMemberSize(sid, offset.offset): # If they are the same, all is well. pass
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 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 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 size(self): "size of the member" return idc.GetMemberSize(self.parent.sid, self.struct_offset)