Example #1
0
def analyse_function_returns():
  """Find all function call instructions, and mark the blocks associated
  with their return addresses as having their addresses taken."""
  log.info("Analysing targets of function call return instructions")
  for block in program.basic_blocks():
    term_inst = block.terminator
    if not term_inst or not term_inst.is_function_call():
      continue
    return_target_block = program.get_basic_block(term_inst.next_ea)
    return_target_block.address_is_taken = True
Example #2
0
def analyse_function_returns():
    """Find all function call instructions, and mark the blocks associated
  with their return addresses as having their addresses taken."""
    log.info("Analysing targets of function call return instructions")
    for block in program.basic_blocks():
        term_inst = block.terminator
        if not term_inst or not term_inst.is_function_call():
            continue
        return_target_block = program.get_basic_block(term_inst.next_ea)
        return_target_block.address_is_taken = True
Example #3
0
def analyse_indirect_jump(block, jump_inst, blocks):
  """Analyse an indirect jump and try to determine its targets."""
  log.info("Analysing indirect jump at {:08x}".format(jump_inst.ea))
  si = idaapi.get_switch_info_ex(jump_inst.ea)
  target_eas = set()
  if si:
    num_targets = si.get_jtable_size()
    log.info("IDA identified a jump table at {:08x} with {} targets".format(
        jump_inst.ea, num_targets))
    target_eas.update(idautils.CodeRefsFrom(jump_inst.ea, True))

  for target_ea in target_eas:
    block = program.get_basic_block(target_ea)
    block.address_is_taken = True
Example #4
0
def analyse_indirect_jump(block, jump_inst, blocks):
    """Analyse an indirect jump and try to determine its targets."""
    log.info("Analysing indirect jump at {:08x}".format(jump_inst.ea))
    si = idaapi.get_switch_info_ex(jump_inst.ea)
    target_eas = set()
    if si:
        num_targets = si.get_jtable_size()
        log.info(
            "IDA identified a jump table at {:08x} with {} targets".format(
                jump_inst.ea, num_targets))
        target_eas.update(idautils.CodeRefsFrom(jump_inst.ea, True))

    for target_ea in target_eas:
        block = program.get_basic_block(target_ea)
        block.address_is_taken = True
Example #5
0
def analyse_callbacks():
    """Analyse functions that are used as callbacks."""
    global POSSIBLE_CODE_REFS
    log.info("Analysing callbacks")
    for ea in POSSIBLE_CODE_REFS:
        if program.has_basic_block(ea):
            block = program.get_basic_block(ea)
            if not block.address_is_taken:
                block.address_is_taken = True
                log.info("Block {:08x} is a callback".format(ea))

    for block in program.basic_blocks():
        if not block.address_is_taken:
            if len(tuple(idautils.DataRefsTo(block.ea))):
                block.address_is_taken = True
                log.info("Block {:08x} is a callback".format(block.ea))
Example #6
0
def analyse_callbacks():
  """Analyse functions that are used as callbacks."""
  global POSSIBLE_CODE_REFS
  log.info("Analysing callbacks")
  for ea in POSSIBLE_CODE_REFS:
    if program.has_basic_block(ea):
      block = program.get_basic_block(ea)
      if not block.address_is_taken:
        block.address_is_taken = True
        log.info("Block {:08x} is a callback (1)".format(ea))

  for block in program.basic_blocks():
    if not block.address_is_taken:
      if len(tuple(idautils.DataRefsTo(block.ea))):
        block.address_is_taken = True
        log.info("Block {:08x} is a callback (2)".format(block.ea))
Example #7
0
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)))
Example #8
0
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)))