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
Esempio n. 2
0
 def get_function_sid(self, in_stack, local_size=1):
     if not in_stack:
         return 'create_struct_complex', idc.AddStrucEx(0, 'create_struct_complex', 0)
     ea = yaunit.get_next_function(lambda ea : yaunit.has_locals(ea, local_size))
     frame = idaapi.get_frame(ea)
     self.assertNotEqual(frame, None)
     offset = idc.GetFirstMember(frame.id)
     while offset != idaapi.BADADDR:
         idc.DelStrucMember(frame.id, offset)
         offset = idc.GetFirstMember(frame.id)
     return ea, frame.id
Esempio n. 3
0
 def yatest_create_struct_in_stack_vars_with_renaming(self):
     """
     test creation of struct from stack vars
     used to find a bug (structure is correctly applied on var if renamed)
     """
     # create structure
     ident, sida = self.get_function_sid_without_del(
         True, local_size=complex_struc3_size, count_from_first_var=True)
     self.assertNotEqual(sida, -1)
     sidb = idc.AddStrucEx(0, 'create_struct_in_stack_vars_with_renaming',
                           0)
     self.assertNotEqual(sidb, -1)
     size = self.create_complex2(sidb, complex_struc3)
     self.assertEqual(complex_struc3_size, size)
     # set first var prototype
     offset = idc.GetFirstMember(sida)
     member_id = idc.GetMemberId(sida, offset)
     self.assertNotEqual(member_id, -1)
     self.assertTrue(
         idc.SetType(member_id,
                     "create_struct_in_stack_vars_with_renaming* x;"))
     self.assertEqual("create_struct_in_stack_vars_with_renaming *",
                      idc.GetType(idc.GetMemberId(sida, offset)))
     idc.SetMemberName(sida, offset, "var1")
     yaunit.save("create_struct_in_stack_vars_with_renaming", sida)
     yaunit.save("create_struct_in_stack_vars_with_renaming_offset", offset)
Esempio n. 4
0
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
Esempio n. 5
0
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
Esempio n. 6
0
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
Esempio n. 7
0
 def get_function_sid_without_del(self, in_stack, local_size=1, count_from_first_var=False):
     if not in_stack:
         return 'create_struct_complex', idc.AddStrucEx(0, 'create_struct_complex', 0)
     ea = yaunit.get_next_function(lambda ea : yaunit.has_locals(ea, local_size, count_from_first_var))
     frame = idaapi.get_frame(ea)
     self.assertNotEqual(frame, None)
     offset = idc.GetFirstMember(frame.id)
     return ea, frame.id
def hasStackVars(ea):
    """
    :param ea: address of the function
    :return: whether the function has stack variables or not
    """
    id = idc.GetFrame(ea)
    firstMember = idc.GetFirstMember(id)
    return firstMember != idaapi.BADADDR and firstMember != -1
Esempio n. 9
0
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 getStackVarDisasm(self):
        """
        if the function uses stack variables with SP, their symbols should be defined
        :return:
        """
        disasm = ''
        id = idc.GetFrame(self.func_ea)
        firstMember = idc.GetFirstMember(id)
        if hasStackVars(self.func_ea):
            # first, obtain the base by finding an instruction that uses one of the stack variables
            stackVars = getStackVars(self.func_ea)
            ea = self.func_ea
            base = -1

            # TODO: maybe use get_min_spd_ea(func_ea) to get the base pointer? this stands for stack pointer delta!

            # search function instructions to find base (TODO: hacky, but i dunno how else to find base yet)
            while ea < self.func_ea + self.getSize():
                d = Data.Data(ea)
                origDisasm = d.getOrigDisasm()
                # case where the stack frame is referenced
                for var, offset in stackVars:
                    if var in origDisasm and '#' in origDisasm:
                        # cases like LDR SP, [base+var_xx]
                        if '[' in origDisasm:
                            # grab the base
                            if '+' in origDisasm:
                                base = int(
                                    origDisasm[origDisasm.index('#') +
                                               1:origDisasm.index('+')], 16)
                            else:
                                base = 0
                            # obtained base! no need to continue looping
                            break
                        # some cases like ADD SP, base+var_xx don't have '['
                        elif '+' in origDisasm:
                            base = int(
                                origDisasm[origDisasm.index('#') +
                                           1:origDisasm.index('+')], 16)
                            # obtained base! no need to continue looping
                            break
                if base != -1:
                    break
                ea += d.getSize()
            # if base couldn't be found still, it's likely no SP access is done with variables
            if base == -1:
                base = 0

            # build up disasm based on stack vars using base-relative offsets
            for name, off in stackVars:
                relOff = base - off
                if relOff > 0:
                    disasm += ".equ %s, -0x%X\n" % (name, abs(relOff))
                else:
                    disasm += ".equ %s, 0x%X\n" % (name, abs(relOff))

        return disasm
Esempio n. 11
0
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)
Esempio n. 12
0
def has_locals(ea, lvar_size=1, count_from_first_var=False):
    frame = idaapi.get_frame(ea)

    if frame is None or frame.memqty <= 1:
        return False
    
    if count_from_first_var:
        sida = frame.id
        offset = idc.GetFirstMember(sida)
        return idc.GetFrameLvarSize(ea) > lvar_size+offset
    else:
        return idc.GetFrameLvarSize(ea) > lvar_size
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
Esempio n. 14
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)
Esempio n. 15
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)
Esempio n. 16
0
 def yatest_create_struct_in_stack_vars(self):
     """
     test creation of struct from stack vars
     used to find a bug when creating struct for stack vars and naming vars
     """
     # create structure
     ident, sida = self.get_function_sid_without_del(True, local_size=complex_struc3_size, count_from_first_var=True)
     self.assertNotEqual(sida, -1)
     sidb = idc.AddStrucEx(0, 'create_struct_in_stack_vars', 0)
     self.assertNotEqual(sidb, -1)
     size = self.create_complex2(sidb, complex_struc3)
     self.assertEqual(complex_struc3_size, size)
     # set first var prototype
     offset = idc.GetFirstMember(sida)
     member_id = idc.GetMemberId(sida, offset)
     self.assertNotEqual(member_id, -1)
     self.assertTrue(idc.SetType(member_id, "create_struct_in_stack_vars* x;"))
     self.assertEqual("create_struct_in_stack_vars *",
                      idc.GetType(idc.GetMemberId(sida, offset)))
     yaunit.save("create_struct_in_stack_vars", sida)
     yaunit.save("create_struct_in_stack_vars_offset", offset)
Esempio n. 17
0
def get_struc_id_from_member_if(member_id):
    try:
        return member_struc_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:
                        member_struc_ids[member_id] = struc_id
                        return struc_id
                    offset = idc.GetStrucNextOff(struc_id, offset)
            idx = idc.GetNextStrucIdx(idx)
        logger.error("Could not find struc id from member id 0x%08X (name=%s)" %
                     (member_id, idaapi.get_struc_name(member_id)))
        return None
Esempio n. 18
0
    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
Esempio n. 19
0
 def _get_members_offset(self):
     off = idc.GetFirstMember(self.sid)
     for i in range(self.nb_member):
         yield off
         off = idc.GetStrucNextOff(self.sid, off)
Esempio n. 20
0
 def _get_members_offset(self):
     off = idc.GetFirstMember(self.sid)
     while off != idc.BADADDR:
         yield off
         off = idc.GetStrucNextOff(self.sid, off)