def remFuncChunks(): """ deletes all functions that have function chunks in them and appends "function_chunks_" to their names """ foundProblem = False for seg in idautils.Segments(): for ea in idautils.Functions(start=idc.SegStart(seg), end=idc.SegEnd(seg)): f = idaapi.get_func(ea) # chunk f if f.tailqty > 0: foundProblem = True print("Removing chunk function @ %07X" % f.startEA) idaapi.del_func(f.startEA) name = idc.Name(f.startEA) if "function_chunks_" not in name: newName = 'function_chunks_%s' % name print("Renaming %s -> %s" % ((name, newName))) idc.MakeName(f.startEA, newName) if foundProblem: print("Removed all function chunks!") else: print("No function chunks detected!")
def remove(fn): if type(fn) is idaapi.func_t: return idaapi.del_func(fn.startEA) return remove(by(fn))
##SCRIPT TO REBUILD ANATOVA FUNCTIONS functions = [] bucket = [] for f in idautils.Functions(): name = idc.get_func_name(f) if name[:2] == "j_": continue addr = f func = idaapi.get_func(f) size = func.endEA - func.startEA print "{} {} - {}".format(addr, name, size) tmp = {"addr": addr, "name": name, "size": size} if size == 11: if len(bucket) > 0: functions.append(bucket) bucket = [] bucket.append(tmp) functions.append(bucket) for bucket in functions: init = bucket[0]['addr'] tmp = bucket[-1] end = init for f in bucket: fin += f['size'] idaapi.del_func(f['addr']) idaapi.add_func(init, end)
def do_hanging(S, E): if not process_hanging: return Verbose("STATUS put all hanging instructions in functions") partitioning.Init() # fixed parameters partitioning.subcfg_forward = False partitioning.subcfg_backward = True partitioning.subcfg_backforth = False # PHASE 1a: mark hanging blocks # Here we have a problem, as basic blocks and control flow edges are not known for hanging instructions. # We solve this by letting IDA define a function at the hanging instruction address. hanging_functions = set() marked_block_count = 0 change = True while change: change = False for i in idapython.iter_hanging(S, E): if not MakeFunction(i): # could not create function Verbose( "could not create function for hanging instruction at 0x%x" % i) continue # print("hanging 0x%x" % i) change = True f_start = GetFunctionAttr(i, FUNCATTR_START) hanging_functions.add(f_start) # print("START 0x%x" % f_start) for block in idapython.iter_blocks_in_function(f_start): # print("marking block 0x%x-0x%x" % (block.startEA, PrevHead(block.endEA))) partitioning.MarkBlock(block.startEA, PrevHead(block.endEA)) marked_block_count += 1 #endfor blocks #endfor iter_hanging #endwhile change # PHASE 1b: mark ignored edges #TODO ins_to_functions(S, E) # PHASE 2: iteratively associate hanging blocks with function D.collect_links(same_function) if not repartition_hanging: return idapython.DumpDatabase(DumpDatabaseName('before-hanging-repart')) Verbose("STATUS repartition hanging instructions") # collect possible start points: # blocks that have one or more non-hanging incoming/outgoing blocks start_points = set() for block in partitioning.MarkedBlockIterator(): added = False for x in idapython.BblIncomingInsns(block): start = block_start_address(x) if (start is not None) and (not partitioning.IsBlockMarked(start)): start_points.add(block) added = True break #endfor incoming # early continue if possible if added: continue for x in idapython.BblOutgoingInsns(block_end_address(block)): if not partitioning.IsBlockMarked(x): start_points.add(block) break #endfor outgoing #endfor marked Verbose("STATUS start with %d/%d" % (len(start_points), marked_block_count)) total_iterations = 0 total_moved_blocks = 0 configurations = [[False, False, False, False, False], [False, False, False, True, False], [False, False, False, False, True], [False, False, True, False, False], [True, True, False, False, False], [True, True, False, True, False], [True, True, False, False, True], [True, True, True, False, False]] for conf in configurations: start_points, nr_iterations, nr_moved_blocks = partitioning.repartition( start_points, [], conf[0], conf[1], conf[2], conf[3], conf[4], True, False) total_iterations += nr_iterations total_moved_blocks += nr_moved_blocks # final pass: iterate remaining hanging blocks for block in partitioning.MarkedBlockIterator(): start_points.add(block) # hardcoded flags here start_points, nr_iterations, nr_moved_blocks = partitioning.repartition( start_points, [], True, True, True, False, False, True, False) total_iterations += nr_iterations total_moved_blocks += nr_moved_blocks Verbose("STATUS moved %d/%d blocks in %d iterations" % (total_moved_blocks, marked_block_count, total_iterations)) if repartition_hanging_rehang: nr_rehang = 0 for block in partitioning.MarkedBlockIterator(): Verbose("deleting block 0x%x" % block) idaapi.del_func(block) nr_rehang += 1 Verbose("STATUS rehung %d blocks" % nr_rehang)
def delete_multichunk_funcs(): for func_t in iter_multichunk_funcs(): idaapi.del_func(func_t.startEA)
def _ChunkMovePart(inner_start, inner_end_ex, function_address): moved_blocks = [] fn_print("MICRO move 0x%x-0x%x to 0x%x" % (inner_start, inner_end_ex, function_address)) outer_function = idc.GetFunctionAttr(inner_start, idc.FUNCATTR_START) outer_start = idc.GetFchunkAttr(inner_start, idc.FUNCATTR_START) outer_end_ex = idc.GetFchunkAttr(inner_start, idc.FUNCATTR_END) function_address2 = idc.GetFunctionAttr(function_address, idc.FUNCATTR_START) if outer_start == 0xffffffff: fn_print("outer start not defined") outer_start = inner_start if outer_end_ex == 0xffffffff: fn_print("outer end not defined") outer_end_ex = inner_end_ex if function_address2 == outer_function: fn_print("don't move, already in function") return moved_blocks # remove chunk from function remove_chunk_ok = True if outer_function == BADADDR: fn_print("already hanging 0x%x-0x%x" % (outer_start, outer_end_ex)) else: fn_print("remove 0x%x-0x%x from 0x%x" % (outer_start, outer_end_ex, outer_function)) remove_chunk_ok = FunctionRemoveChunk(outer_start) moved_blocks.append([outer_start, outer_end_ex]) if not remove_chunk_ok: fn_print(" could not remove chunk") chunks = FunctionChunks(outer_start) if len(chunks) == 1: fn_print(" deleting function, moving entire chunk") if (inner_start != outer_start) or (inner_end_ex != outer_end_ex): fn_print(" changed function bounds!") remove_chunk_ok = idaapi.del_func(outer_start) assert remove_chunk_ok inner_start = outer_start inner_end_ex = outer_end_ex else: fn_print(" function contains chunks %s" % [['0x%x-0x%x' % (i, j)] for i, j in chunks]) # to disable function chunk isolation # return moved_blocks if (chunks[0][0] <= inner_start) and (inner_start < chunks[0][1]): fn_print( "have to move first chunk, need to work around this..." ) fn_print("removing all but first chunk") for i in range(1, len(chunks)): remove_chunk_ok_2 = FunctionRemoveChunk(chunks[i][0]) assert remove_chunk_ok_2 current_address = chunks[i][0] while current_address < chunks[i][1]: assert InsIsData(current_address) or InsIsHanging( current_address ), "0x%x does not hang nor is data" % current_address current_address = idc.NextHead(current_address) #endwhile #endfor fn_print( "create new function starting at second chunk (0x%x-0x%x)" % (chunks[1][0], chunks[1][1])) create_function_ok = FunctionCreateAt( chunks[1][0], chunks[1][1]) moved_blocks.append([chunks[1][0], chunks[1][1]]) assert create_function_ok if len(chunks) > 2: for i in range(2, len(chunks)): moved_blocks_sub = _ChunkMovePart( chunks[i][0], chunks[i][1], chunks[1][0]) moved_blocks.extend(moved_blocks_sub) assert len(moved_blocks_sub) > 0 #endfor #endif fn_print( "finally removing entire function for first chunk") remove_chunk_ok = idaapi.del_func(chunks[0][0]) moved_blocks.append([chunks[0][0], chunks[0][1]]) assert remove_chunk_ok for i in range(1, len(chunks)): ii = chunks[i][0] while ii < chunks[i][1]: assert not InsIsHanging(ii), "0x%x hangs" % ii ii = idc.NextHead(ii) #endif #endfor inner_start = outer_start inner_end_ex = outer_end_ex else: assert False #endif #endif #endif #endif assert remove_chunk_ok move_block_ok = False # regular move # append the desired part to the correct function restored_whole_chunk = False fn_print("moving 0x%x-0x%x" % (inner_start, inner_end_ex)) move_block_ok = FunctionAppendChunk(function_address, inner_start, inner_end_ex) fn_print(" move-block %d" % move_block_ok) if not move_block_ok: if outer_start == outer_function: fn_print( "error-restore: start of function 0x%x-(0x%x-0x%x)-0x%x to 0x%x" % (outer_start, inner_start, inner_end_ex, outer_end_ex, outer_function)) assert outer_end_ex == inner_end_ex restored_whole_chunk = FunctionCreateAt(outer_start, outer_end_ex) moved_blocks.append([outer_start, outer_end_ex]) assert restored_whole_chunk else: fn_print("restoring 0x%x-0x%x to 0x%x" % (outer_start, outer_end_ex, outer_function)) restored_whole_chunk = FunctionAppendChunk(outer_function, outer_start, outer_end_ex) moved_blocks.append([outer_start, outer_end_ex]) if not restored_whole_chunk: real_function = idc.GetFunctionAttr(outer_start, idc.FUNCATTR_START) should_be_function = outer_function if real_function == should_be_function: restored_whole_chunk = True else: fn_print("0x%x/0x%x" % (real_function, should_be_function)) #endif assert restored_whole_chunk else: moved_blocks.append([inner_start, inner_end_ex]) if not restored_whole_chunk: # add PRE-part to original function, if needed if outer_start < inner_start: fn_print(" prefix...") if InsIsHanging(outer_start): prefixmove = FunctionAppendChunk(outer_function, outer_start, inner_start) moved_blocks.append([outer_start, inner_start]) if not prefixmove: fn_print( "could not restore prefix 0x%x-0x%x, instead adding it to the new function too" % (outer_start, inner_start)) prefixmove = FunctionAppendChunk(function_address, outer_start, inner_start) assert prefixmove moved_blocks.append( [outer_start, inner_start, function_address]) else: fn_print("restored prefix 0x%x-0x%x" % (outer_start, inner_start)) #endif #endif #endif # add POST-part to original function, if needed if inner_end_ex < outer_end_ex: fn_print(" postfix...") post_start = inner_end_ex while post_start < outer_end_ex: if InsIsData(post_start): # skip data post_start = idc.NextHead(post_start) else: # found start of a block of code subpost_start = post_start fn_print("found subpost start 0x%x" % subpost_start) subpost_end = idc.NextHead(subpost_start) while subpost_end < outer_end_ex: if not InsIsHanging(subpost_end): break subpost_end = idc.NextHead(subpost_end) #endwhile subpost_start # don't go past the end of the section E = section_end(subpost_start) if subpost_end > E: subpost_end = E fn_print("found subpost 0x%x-0x%x" % (subpost_start, subpost_end)) postfixmove = FunctionAppendChunk(outer_function, subpost_start, subpost_end) moved_blocks.append([subpost_start, subpost_end]) if not postfixmove: fn_print( "could not restore postfix 0x%x-0x%x, instead adding it to the new function too" % (subpost_start, subpost_end)) postfixmove = FunctionAppendChunk( function_address, subpost_start, subpost_end) if not postfixmove: DumpDatabase('assertion.idb') assert postfixmove moved_blocks.append([subpost_start, subpost_end]) else: fn_print("restored postfix 0x%x-0x%x" % (subpost_start, subpost_end)) #endif post_start = subpost_end #endif #endwhile post_start #endif #endif ii = outer_start while ii < outer_end_ex: assert not InsIsHanging(ii), "0x%x hangs" % ii ii = idc.NextHead(ii) #endif return moved_blocks