def find_imported_subroutines(): """Find the address of all imported functions.""" # Collect addresses of imported code. imported_eas = set() num_imports = idaapi.get_import_module_qty() for i in xrange(num_imports): idaapi.enum_import_names(i, lambda ea, name, ord: imported_eas.add(ea)) # Mark IDA-identified stuff imported stuff as imported. for ea in imported_eas: if not program.has_subroutine(ea): log.error( "No subroutine associated with import {:08x}.".format(ea)) continue sub = program.get_subroutine(ea) sub.visibility = program.Subroutine.VISIBILITY_IMPORTED # Mark functions in code sections marked as external as being imported. for sub in program.subroutines(): if program.Subroutine.VISIBILITY_INTERNAL != sub.visibility: continue if has_segment_type(sub.ea, idc.SEG_XTRN): log.debug("Subroutine {:08x} is imported".format(sub.ea)) sub.visibility = program.Subroutine.VISIBILITY_IMPORTED if sub.name: log.info("Found imported subroutine {} at {:08x}".format( sub.name, sub.ea))
def find_imported_subroutines(): """Find the address of all imported functions.""" # Collect addresses of imported code. imported_eas = set() num_imports = idaapi.get_import_module_qty() for i in xrange(num_imports): idaapi.enum_import_names(i, lambda ea, name, ord: imported_eas.add(ea)) # Mark IDA-identified stuff imported stuff as imported. for ea in imported_eas: if not program.has_subroutine(ea): log.error("No subroutine associated with import {:08x}.".format(ea)) continue sub = program.get_subroutine(ea) sub.visibility = program.Subroutine.VISIBILITY_IMPORTED # Mark functions in code sections marked as external as being imported. for sub in program.subroutines(): if program.Subroutine.VISIBILITY_INTERNAL != sub.visibility: continue if has_segment_type(sub.ea, idc.SEG_XTRN): log.debug("Subroutine {:08x} is imported".format(sub.ea)) sub.visibility = program.Subroutine.VISIBILITY_IMPORTED if sub.name: log.info("Found imported subroutine {} at {:08x}".format( sub.name, sub.ea))
def find_exported_subroutines(): """Find the functions that are exported to other binaries.""" exported_eas = find_exported_eas() for ea in exported_eas: if not program.has_subroutine(ea): continue sub = program.get_subroutine(ea) if program.Subroutine.VISIBILITY_INTERNAL != sub.visibility: continue sub.visibility = program.Subroutine.VISIBILITY_EXPORTED if sub.name: log.info("Found exported subroutine {} at {:08x}".format( sub.name, sub.ea)) mark_entry_block_address_taken(sub)
def analyse_subroutine(sub): """Goes through the basic blocks of an identified function.""" if len(sub.blocks): return # We've already processed this subroutine. log.info("Analysing subroutine {} at {:08x}".format(sub.name, sub.ea)) block_head_eas = set() block_head_eas.add(sub.ea) # Try to get IDA to give us function information. f = idaapi.get_func(sub.ea) if f: for b in idaapi.FlowChart(f): block_head_eas.add(b.startEA) for chunk_start_ea, chunk_end_ea in idautils.Chunks(sub.ea): block_head_eas.add(chunk_start_ea) else: log.warning("IDA does not recognise subroutine at {:08x}".format( sub.ea)) # Iteratively scan for block heads. This will do linear sweeps looking for # block terminators. These linear sweeps do not consider flows incoming # flows from existing blocks that logically split a block into two. found_block_eas = set() while len(block_head_eas): block_head_ea = block_head_eas.pop() if block_head_ea in found_block_eas: continue found_block_eas.add(block_head_ea) # Try to make sure that analysis will terminate if we accidentally # walk through a noreturn call. if block_head_ea != sub.ea and program.has_subroutine(block_head_ea): continue log.debug("Found block head at {:08x}".format(block_head_ea)) if program.has_basic_block(block_head_ea): existing_block = program.get_basic_block(block_head_ea) term_inst = existing_block.terminator assert term_inst is not None else: term_inst = find_linear_terminator(block_head_ea) log.debug("Linear terminator of {:08x} is {:08x}".format( block_head_ea, term_inst.ea)) succ_eas = tuple(get_static_successors(term_inst)) if succ_eas: log.debug("Static successors of {:08x} are {}".format( term_inst.ea, ", ".join("{:08x}".format(sea) for sea in succ_eas))) block_head_eas.update(succ_eas) # Create blocks associated with this subroutine for each block # head that the prior analysis discovered. blocks = [] for block_head_ea in found_block_eas: if block_head_ea != sub.ea and program.has_subroutine(block_head_ea): continue block = sub.get_basic_block(block_head_ea) blocks.append(block) log.debug("Subroutine {:08x} has {} blocks".format(sub.ea, len(blocks))) # Analyse the blocks blocks.sort(key=lambda b: b.ea) for block in blocks: analyse_block(sub, block) log.debug("Block at {:08x} has {} instructions".format( block.ea, len(block.instructions)))
def analyse_subroutine(sub): """Goes through the basic blocks of an identified function.""" if len(sub.blocks): return # We've already processed this subroutine. log.info("Analysing subroutine {} at {:08x}".format(sub.name, sub.ea)) block_head_eas = set() block_head_eas.add(sub.ea) # Try to get IDA to give us function information. f = idaapi.get_func(sub.ea) if f: for b in idaapi.FlowChart(f): block_head_eas.add(b.startEA) for chunk_start_ea, chunk_end_ea in idautils.Chunks(sub.ea): block_head_eas.add(chunk_start_ea) else: log.warning("IDA does not recognise subroutine at {:08x}".format(sub.ea)) # Iteratively scan for block heads. This will do linear sweeps looking for # block terminators. These linear sweeps do not consider flows incoming # flows from existing blocks that logically split a block into two. found_block_eas = set() while len(block_head_eas): block_head_ea = block_head_eas.pop() if block_head_ea in found_block_eas: continue if not is_code(block_head_ea): log.error("Block head at {:08x} is not code.".format(block_head_ea)) continue found_block_eas.add(block_head_ea) # Try to make sure that analysis will terminate if we accidentally # walk through a noreturn call. if block_head_ea != sub.ea and program.has_subroutine(block_head_ea): continue log.debug("Found block head at {:08x}".format(block_head_ea)) if program.has_basic_block(block_head_ea): existing_block = program.get_basic_block(block_head_ea) term_inst = existing_block.terminator assert term_inst is not None else: term_inst = find_linear_terminator(block_head_ea) if not term_inst: log.error("Block at {:08x} has no terminator!".format(block_head_ea)) found_block_eas.remove(block_head_ea) continue log.debug("Linear terminator of {:08x} is {:08x}".format( block_head_ea, term_inst.ea)) succ_eas = tuple(get_static_successors(term_inst)) if succ_eas: log.debug("Static successors of {:08x} are {}".format( term_inst.ea, ", ".join("{:08x}".format(sea) for sea in succ_eas))) block_head_eas.update(succ_eas) # Create blocks associated with this subroutine for each block # head that the prior analysis discovered. blocks = [] for block_head_ea in found_block_eas: if block_head_ea != sub.ea and program.has_subroutine(block_head_ea): continue block = sub.get_basic_block(block_head_ea) blocks.append(block) log.debug("Subroutine {:08x} has {} blocks".format(sub.ea, len(blocks))) # Analyse the blocks blocks.sort(key=lambda b: b.ea) for block in blocks: analyse_block(sub, block) log.debug("Block at {:08x} has {} instructions".format( block.ea, len(block.instructions)))