示例#1
0
def find_main(rad: RAD, instructions: List[CsInsn]) -> Union[None, int]:
    '''Try to find main by interpreting the given basic block as starting the
    C runtime.'''

    # Bail if there aren't at least two instructions.
    if len(instructions) < 2:
        note("Entry point too short to be C stub.")
        return None

    # Check that the last thing is a call.
    last = instructions[-1]
    if last.mnemonic == 'hlt':
        last = instructions[-2]
    if last.mnemonic != 'call':
        # Last thing in the block must be a call.
        note("Last effective instruction in block is not a call.")
        return None

    # Found a call.  It should be RIP relative and out of scope.
    address = OperandTests.is_rip_relative(last.operands[0])
    if address is not None and rad.in_range(address):
        # The C runtime would be out of range.
        note("Last effective instruction in block is call in range.")
        return None

    # Run through this and find a setting for RDI.
    main_addr = None
    for insn in instructions:
        # See if this is a mov.
        if insn.mnemonic != 'mov' and insn.mnemonic != 'lea':
            continue

        # See if the first operand is the RDI register.
        dest = insn.operands[0]
        sour = insn.operands[1]
        if not OperandTests.is_reg(dest) or insn.reg_name(dest.reg) != 'rdi':
            continue

        # Find out what value is being set for RDI.
        if insn.mnemonic == 'mov' and OperandTests.is_imm(sour):
            main_addr = sour.value.imm
        elif insn.mnemonic == 'lea':
            main_addr = OperandTests.is_rip_relative(sour)
            main_addr += insn.address + insn.size

    # Either we found main or we didn't.
    if main_addr is not None:
        note("Possible main function at " + hex(main_addr))
    return main_addr
示例#2
0
def do_pass_two(bbs: Set[int], rad: RAD) -> Dict[int, Node]:
    '''Run pass two of basic block discovery.
    
    This builds the basic blocks, creates function and predicate nodes from them,
    and stores these in a dictionary by their first address.'''

    note("Starting pass two")

    # Dictionary to hold nodes.
    nodes: Dict[int, Node] = {}

    # Now generate the nodes.
    count = 0
    for address in bbs:
        debug(f"Possible basic block at {hex(address)}")
        if not rad.in_range(address):
            continue

        # Create a basic block starting at this location.
        bb = BasicBlock()
        node: Node
        count += 1
        run = True
        while run:
            # Disassemble the instruction.
            try:
                i = rad.at(address)
            except AddressException:
                # Ignore and let the basic block be terminated.
                run = False
                continue
            except NotExecutableException:
                # Ignore and let the basic block be terminated.
                run = False
                continue

            # Add the instruction to the basic block.
            nextaddr = i.address + i.size
            bb.add(i)

            # Determine if there is a next address for us to disassemble in this
            # basic block.
            run = False
            if InstructionTests.is_call(i):
                if DebugOpts.CALL_ENDS_BB:
                    # The call ends the basic block.
                    node = FunctionNode(bb, nextaddr)
                    nodes[bb.get_address()] = node
                    continue
                else:
                    # Assume the call returns and disassemble the next address as part
                    # of this basic block.
                    address = nextaddr
                    run = True

            elif InstructionTests.is_branch(i) or InstructionTests.is_jump(i):
                # A branch or jump ends the basic block.
                if i.mnemonic.endswith('jmp'):
                    if OperandTests.is_imm(i.operands[0]):
                        node = FunctionNode(bb, int(i.op_str, 0))
                        nodes[bb.get_address()] = node
                    elif OperandTests.is_mem(i.operands[0]):
                        disp = OperandTests.is_rip_relative(i.operands[0])
                        if disp is not None:
                            node = FunctionNode(bb, nextaddr + disp)
                            nodes[bb.get_address()] = node
                        else:
                            node = FunctionNode(bb, 0)
                            nodes[bb.get_address()] = node
                    else:
                        node = FunctionNode(bb, 0)
                        nodes[bb.get_address()] = node
                else:
                    node = PredicateNode(bb, int(i.op_str, 0), nextaddr)
                    nodes[bb.get_address()] = node
                continue

            elif InstructionTests.is_interrupt(i):
                if DebugOpts.SYSCALL_ENDS_BB:
                    # The system call ends the basic block.
                    node = FunctionNode(bb, nextaddr)
                    nodes[bb.get_address()] = node
                    continue
                else:
                    # Assume the system call returns and disassemble the next address
                    # as part of this basic block.
                    address = nextaddr
                    run = True

            elif (i.mnemonic == 'hlt' or InstructionTests.is_ret(i)
                  or InstructionTests.is_interrupt_return(i)):
                # A halt or return ends the basic block.
                node = FunctionNode(bb, 0)
                nodes[bb.get_address()] = node
                continue

            else:
                # The basic block continues.
                address = nextaddr
                run = True

            # If the address is in the set of basic block starts, terminate
            # this basic block.
            if address in bbs:
                node = FunctionNode(bb, address)
                nodes[bb.get_address()] = node
                run = False

    note("Finished pass two")
    note(f"Wrote {count} basic blocks")
    note(f"Generated {len(nodes)} nodes")

    return nodes