def split_funcs(startEA, endEA): ''' Description: Attempt to split the function we created into a bunch of smaller functions based on aligns we find in the middle of the func. If we do successfully split, recurse on the remainder of the original function. Input: startEA - The beginning of the function endEA - The end of the function Output: The IDB is updated with the resulting functions ''' ea = startEA while ea < endEA: # We found an align so delete the function and try to make 2 new ones in its place. if idaapi.isAlign(idc.GetFlags(ea)) and idc.DelFunction(startEA): # Make the first function. if idc.MakeFunction(startEA, _un_nop(ea, idc.NextHead)): # We found an align, now get past them. while idaapi.isAlign(idc.GetFlags(ea)): ea += idc.ItemSize(ea) # Make the second function and recurse to ensure it doesn't need split too. if idc.MakeFunction(_un_nop(ea, idc.PrevHead), endEA): append_debug('Split 0x%X - 0x%X at 0x%X.' % (startEA, endEA, ea)) split_funcs(ea, endEA) return else: # We failed to make the second function, so delete the first. idc.DelFunction(startEA) # Splitting failed - rebuild the original function. idc.MakeFunction(startEA, endEA) append_debug('Almost split 0x%X - 0x%X at 0x%X.' % (startEA, endEA, ea)) ea += idc.ItemSize(ea)
def is_internal_code(ea): if is_invalid_ea(ea): return False if is_external_segment(ea): return False if is_code(ea): return True # find stray 0x90 (NOP) bytes in .text that IDA # thinks are data items. flags = idc.GetFlags(ea) if idaapi.isAlign(flags): if not try_mark_as_code(ea): return False return True return False
def is_internal_code(ea): if is_invalid_ea(ea): return False if is_external_segment(ea): return False if is_code(ea): return True # find stray 0x90 (NOP) bytes in .text that IDA # thinks are data items. flags = idc.GetFlags(ea) if idaapi.isAlign(flags): if not try_mark_as_code(ea): return False return True return False
def instructionHandler(M, F, B, inst, new_eas): insn_t = idautils.DecodeInstruction(inst) if not insn_t: # handle jumps after noreturn functions if idc.Byte(inst) == 0xCC: I = addInst(B, inst, [0xCC]) return I, True else: raise Exception("Cannot read instruction at: {0:x}".format(inst)) # check for align instruction pf = idc.GetFlags(inst) if idaapi.isAlign(pf): return None, True # skip HLTs -- they are privileged, and are used in ELFs after a noreturn call if isHlt(inst): return None, False DEBUG("\t\tinst: {0}\n".format(idc.GetDisasm(inst))) inst_bytes = readInstructionBytes(inst) DEBUG("\t\tBytes: {0}\n".format(inst_bytes)) I = addInst(B, inst, inst_bytes) if isJmpTable(inst): handleJmpTable(I, F, inst, new_eas) return I, False if isIndirectCall(inst): global FUNCTIONS_NEED_TRAMPOLINE FUNCTIONS_NEED_TRAMPOLINE = True #check for code refs from here crefs = [] for cref in idautils.CodeRefsFrom(inst, 0): crefs.append(cref) fn = getFunctionName(cref) if isCall(inst): elfy, fn_replace = isElfThunk(cref) if elfy: fn = fn_replace if isExternalReference(cref) or elfy: fn = handleExternalRef(fn) I.ext_call_name = fn DEBUG("EXTERNAL CALL: {0}\n".format(fn)) if doesNotReturn(fn): return I, True else: I.call_target = cref if cref not in RECOVERED_EAS: new_eas.add(cref) DEBUG("INTERNAL CALL: {0}\n".format(fn)) elif isUnconditionalJump(inst): if isExternalReference(cref): fn = handleExternalRef(fn) I.ext_call_name = fn DEBUG("EXTERNAL JMP: {0}\n".format(fn)) if doesNotReturn(fn): DEBUG("Nonreturn JMP\n") return I, True else: DEBUG("INTERNAL JMP: {0:x}\n".format(cref)) I.true_target = cref #true: jump to where we have a code-ref #false: continue as we were print hex(inst), crefs if isConditionalJump(inst): I.true_target = crefs[0] I.false_target = inst+len(inst_bytes) return I, False relo_off = findRelocOffset(inst, len(inst_bytes)) if relo_off != -1: I.reloc_offset = relo_off for dref in idautils.DataRefsFrom(inst): if dref in crefs: continue if inValidSegment(dref): if isExternalReference(dref): fn = getFunctionName(dref) fn = handleExternalRef(fn) if isExternalData(fn): I.ext_data_name = fn sys.stdout.write("EXTERNAL DATA REF FROM {0:x} to {1}\n".format(inst, fn)) else: I.ext_call_name = fn sys.stdout.write("EXTERNAL CODE REF FROM {0:x} to {1}\n".format(inst, fn)) elif isInternalCode(dref): DEBUG("\t\tCode Ref from {0:x} to {1:x}\n".format(inst, dref)) I.call_target = dref if dref not in RECOVERED_EAS: new_eas.add(dref) else: dref_size = idc.ItemSize(dref) I.data_offset = handleDataRelocation(M, dref, new_eas) DEBUG("\t\tData Ref: {0:x}, size: {1}, offset : {2:x}\n".format( dref, dref_size, I.data_offset)) else: DEBUG("Data not in valid segment {0:x}\n".format(dref)) # if we have a mov sth, imm with imm that it's likely a fn pointer, # we add that pointer to the list of ones to disassemble # TODO: use also some other info to assume this if insn_t[1].type == idaapi.o_imm and insn_t.itype == idaapi.NN_mov and inValidSegment(insn_t[1].value): ref = insn_t[1].value if isInternalCode(ref) and ref not in RECOVERED_EAS: new_eas.add(ref) if isCall(inst): coderefs = [i for i in idautils.CodeRefsFrom(inst, 0)] coderefs_normal = [i for i in idautils.CodeRefsFrom(inst, 1)] if len(coderefs) == 0 and len(coderefs_normal) == 1 and insn_t[0].type == idaapi.o_near: for cref in coderefs_normal: I.call_target = cref if cref not in RECOVERED_EAS: new_eas.add(cref) return I, False
def isAlign(ea): return idaapi.isAlign(idaapi.getFlags(ea))
def isAlign(ea=None): ea = ui.current.address() if ea is None else ea return idaapi.isAlign(idaapi.getFlags(ea))
def isAlign(ea): return idaapi.isAlign(idaapi.getFlags(ea))