def ChunkMovePart(inner_start, inner_end_ex, function_address): # maybe the given range covers multiple chunks result = [] fn_print("MACRO move 0x%x-0x%x to 0x%x" % (inner_start, inner_end_ex, function_address)) DisableAutoAnalysis() current_inner_start = inner_start while current_inner_start < inner_end_ex: chunk_start = idc.GetFchunkAttr(current_inner_start, idc.FUNCATTR_START) chunk_end_ex = idc.GetFchunkAttr(current_inner_start, idc.FUNCATTR_END) new_inner_end_ex = inner_end_ex if chunk_end_ex < inner_end_ex: new_inner_end_ex = chunk_end_ex result.extend( _ChunkMovePart(current_inner_start, new_inner_end_ex, function_address)) current_inner_start = idc.GetFchunkAttr(current_inner_start, idc.FUNCATTR_END) while not InsIsCode(current_inner_start): current_inner_start = idc.NextHead(current_inner_start) assert current_inner_start != BADADDR #endwhile #endwhile EnableAutoAnalysis() return result
def guessrange(ea): '''Try really hard to get boundaries of the block at specified address''' start, end = function.getRange(ea) if function.contains(start, ea) and not (ea >= start and ea < end): return (idc.GetFchunkAttr(ea, idc.FUNCATTR_START), idc.GetFchunkAttr(ea, idc.FUNCATTR_END)) return start, end
def __chunks(cls, ea): '''enumerates all chunks in a function ''' res = idc.FirstFuncFchunk(ea) while res != idc.BADADDR: (start, end) = idc.GetFchunkAttr(res, idc.FUNCATTR_START), idc.GetFchunkAttr(res, idc.FUNCATTR_END) yield start,end res = idc.NextFuncFchunk(ea, res) return
def iterFuncChunks(self, ea): start = self.funcStart(ea) end = self.funcEnd(ea) if not start or not end: return [] current = idc.FirstFuncFchunk(start) chunks = [current] while True: next = idc.NextFuncFchunk(start, current) if next != idc.BADADDR: current = next chunks.append(next) else: break res = [] for chunk in chunks: chunk_end = idc.GetFchunkAttr(chunk, idc.FUNCATTR_END) res.extend(list(self.iterInstructions(chunk, chunk_end))) return res
def FunctionChunks(addr): result = [] entry = idc.GetFunctionAttr(addr, idc.FUNCATTR_START) chunk = idc.FirstFuncFchunk(entry) if chunk == BADADDR: return result # list the function chunks result.append([chunk, idc.GetFchunkAttr(chunk, idc.FUNCATTR_END)]) while chunk != BADADDR: chunk = idc.NextFuncFchunk(entry, chunk) if chunk != BADADDR: result.append([chunk, idc.GetFchunkAttr(chunk, idc.FUNCATTR_END)]) return result
def enumerate_function_chunks(f_start): """ The function gets a list of chunks for the function. @f_start - first address of the function @return - list of chunks """ # Enumerate all chunks in the function chunks = list() first_chunk = idc.FirstFuncFchunk(f_start) chunks.append((first_chunk, idc.GetFchunkAttr(first_chunk, idc.FUNCATTR_END))) next_chunk = first_chunk while next_chunk != 0xffffffffL: next_chunk = idc.NextFuncFchunk(f_start, next_chunk) if next_chunk != 0xffffffffL: chunks.append( (next_chunk, idc.GetFchunkAttr(next_chunk, idc.FUNCATTR_END))) return chunks
def init(tests): # workaround ida 6.95 function chunks which should really be functions for ea in [0x6718f260, 0x671a5250]: numrefs = idc.GetFchunkAttr(ea, idc.FUNCATTR_REFQTY) if numrefs <= 1: continue for idx in range(numrefs, 0, -1): idc.RemoveFchunk(idc.GetFchunkReferer(ea, idx - 1), ea) idc.MakeFunction(ea) idc.Wait() YaCo.start_tests()
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