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
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