def makeInterface(self, offset): idc.SetType(offset, "interfaceType") ifaceid = idc.GetStrucIdByName("interfaceType") meth_offs = idc.GetMemberOffset(ifaceid, "methods") slice_id = idc.GetStrucIdByName("slice") size_off = idc.GetMemberOffset(slice_id, "len") size = self.stepper.ptr(offset + meth_offs + size_off) if size != 0: addr = self.getPtr(slice_id, offset + meth_offs, "data") idc.SetType(addr, "imethod") sz = idc.GetStrucSize(idc.GetStrucIdByName("imethod")) self.make_arr(addr, size, sz, "imethod") names = self.processIMethods(addr, size) # For now only for go1.7 if names is None: return name = self.getName(offset) while name[0] == "*": name = name[1:] name = Utils.relaxName(name) name = "user_interface_" + name # TODO: this is for go1.7 need additional check for other versions fields = [("inter", "void *"), ("type", "void *"), ("link", "void *"), ("bad", "__int32"), ("unused", "__int32")] for i in names: fields.append((i, "void *")) itype = [(name, fields)] self.settings.structCreator.createTypes(itype)
def parseFuncType(self, offset): return sid = idc.GetStrucIdByName("funcType") in_size = idc.Word(offset + idc.GetMemberOffset(sid, "incount")) out_size = idc.Word(offset + idc.GetMemberOffset(sid, "outcount")) sz = idc.GetStrucSize(sid) for i in xrange(in_size + out_size): idc.SetType(offset + sz + i * self.stepper.size, "type *")
def createUserTypeStruct(self, addr, name, size, self_size): fields = [] sid = idc.GetStrucIdByName("structField") sz = idc.GetStrucSize(sid) sid_type = idc.GetStrucIdByName("type") fields = [] curr_offset = 0 idc.MakeComm(addr, name) for i in xrange(size): fieldname = self.nameFromOffset( self.getPtr(sid, addr + i * sz, "Name")) type_addr = self.getPtr(sid, addr + i * sz, "typ") typename = self.getType(type_addr) size = self.getPtr(sid_type, type_addr, "size") if fieldname == "" or fieldname is None: fieldname = "unused_" + Utils.id_generator() offset = self.getStructFieldOffset(sid, addr + i * sz) if offset != curr_offset: print "Offset missmatch.Got %d expected %d. Adding padding..." % ( curr_offset, offset) if offset < curr_offset: raise ("Too many bytes already") while offset != curr_offset: fields.append(("padding", "char")) curr_offset += 1 curr_offset += size if size != 0: offset_kind = idc.GetMemberOffset(sid_type, "kind") kind_of_type = self.getKindEnumName(type_addr) print kind_of_type if kind_of_type == "STRUCT_": #Disabled for now name_type = self.getName(type_addr) while name_type[0] == "*": name_type = name_type[1:] name_type = Utils.relaxName(name_type) name_type = "ut_" + name_type #print "setting type %s" % name_type fields.append((fieldname, name_type)) elif kind_of_type == "STRING": fields.append((fieldname, "string")) elif kind_of_type == "SLICE": fields.append((fieldname, "slice")) elif kind_of_type == "INTERFACE": fields.append((fieldname, "__iface")) else: fields.append((fieldname, "char [%d]" % size)) if curr_offset != self_size: print "%x: Structure size mismatch: %x" % (addr, curr_offset) if self_size < curr_offset: raise ("Too many bytes already") while self_size != curr_offset: fields.append(("padding", "char")) curr_offset += 1 new_type = [(name, fields)] self.settings.structCreator.createTypes(new_type) new_type_sid = idc.GetStrucIdByName(name) sz = idc.GetStrucSize(new_type_sid) if sz != self_size: print "%x" % addr raise ("Error at creating structure")
def fillStruct(self, sid, data): for i in data: new_type = None #(i1, i2, i3) = self.stepper.parseField(i[1]) name = i[1] if name[0] == "*": name = name[1:] if i[1] != "uintptr": i1, i2, i3 = (idc.FF_BYTE | idc.FF_DATA, -1, 1) else: i1, i2, i3 = self.uintptr if name == i[1]: new_type = i[1] else: new_type = name + " *" res = idc.AddStrucMember(sid, i[0], -1, i1, i2, i3) use_name = i[0] if res == -1: #Bad name #print "Bad name %s for struct member" % i[0] use_name = i[0] + "_autogen_" + id_generator() idc.AddStrucMember(sid, use_name, -1, i1, i2, i3) if new_type is not None: offset = idc.GetMemberOffset(sid, use_name) #print "Setting %s as %s" % (i[0], new_type) idc.SetType(idc.GetMemberId(sid, offset), new_type)
def _populate_wrapper_struct__slices(sid, classinfo): """Fill in the members of the wrapper struct.""" # First add the vtable pointer. offset = 0 vtable_ptr_type = '{}::vtable *'.format(classinfo.classname) ret = idau.struct_add_ptr(sid, 'vtable', offset, type=vtable_ptr_type) if ret not in (0, idc.STRUC_ERROR_MEMBER_OFFSET): _log(0, 'Could not create {}.vtable: {}', classinfo.classname, ret) return False # Now add all the ::fields structs. offset += idau.WORD_SIZE for ci in classinfo.ancestors(inclusive=True): # Get the sid of the ::fields struct. fields_sid = idau.struct_open(ci.classname + '::fields') if fields_sid is None: _log(0, 'Could not find {}::fields', ci.classname) return False # If this is a 0-length struct (no fields), skip it. size = idc.GetStrucSize(fields_sid) if size == 0: continue # If this is already in the wrapper struct, skip it. This avoids weird # STRUC_ERROR_MEMBER_VARLAST errors. if idc.GetMemberOffset(sid, ci.classname) != -1: continue # Add the ::fields struct to the wrapper. ret = idau.struct_add_struct(sid, ci.classname, offset, fields_sid) if ret != 0: _log(0, 'Could not create {}.{}: {}', classinfo.classname, ci.classname, ret) return False offset += size return True
def getName(self, offset): sid = idc.GetStrucIdByName("type") string_addr = offset + idc.GetMemberOffset(sid, "string") ptr = self.stepper.ptr(string_addr) idc.SetType(ptr, "string") name = self.stepper.ptr(ptr) return idc.GetString(name)
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 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 makeStructType(self, offset): idc.SetType(offset, "structType") sid = idc.GetStrucIdByName("structType") slice_id = idc.GetStrucIdByName("slice") offset_elem = idc.GetMemberOffset(sid, "fields") inner_offset = idc.GetMemberOffset(slice_id, "data") addr = self.stepper.ptr(offset_elem + offset + inner_offset) inner_offset = idc.GetMemberOffset(slice_id, "len") size = self.stepper.ptr(offset + offset_elem + inner_offset) if size == 0: return idc.SetType(addr, "structField") sz = idc.GetStrucSize(idc.GetStrucIdByName("structField")) self.make_arr(addr, size, sz, "structField") sid_type = idc.GetStrucIdByName("type") size_new_struct = self.getPtr(sid_type, offset, "size") for i in xrange(size): self.processStructField(addr, i * sz)
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
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 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 getPtrToThis(self, sid, offset): memb_offs = idc.GetMemberOffset(sid, "ptrtothis") return idc.Dword(offset + memb_offs)
def getKindEnumName(self, addr): struc_id = idc.GetStrucIdByName("type") offset_kind = idc.GetMemberOffset(struc_id, "kind") kind = idc.Byte(addr + offset_kind) & 0x1f return self.settings.typer.standardEnums[0][1][kind]
def getPtr(self, sid, addr, name): name_off = idc.GetMemberOffset(sid, name) return self.stepper.ptr(addr + name_off)
def getDword(self, sid, addr, name): name_off = idc.GetMemberOffset(sid, name) return idc.Dword(addr + name_off)