/** * Get the statement at a specific label. If there is no statement stored, attempts to disassemble * the instruction at the label's virtual address. If the address is outside of the file area, * logs an error and returns a Halt statement by default. * * @param label The label for which to get the statement * @return The statement object at label. */ public final RTLStatement getStatement(RTLLabel label) { if (!statementMap.containsKey(label)) { AbsoluteAddress address = label.getAddress(); Instruction instr = getInstruction(address); // If we did not get an instruction, add an artificial Halt for recovery if (instr == null) { RTLHalt halt = new RTLHalt(); halt.setLabel(label); putStatement(halt); logger.error("ERROR: Replacing unknown instruction with HALT."); if (Options.debug.getValue()) throw new DisassemblyException("Disassembly failed at " + address); } else { try { StatementSequence seq = arch.getRTLEquivalent(address, instr); for (RTLStatement s : seq) { putStatement(s); } } catch (Exception e) { logger.error("Error during translation of instruction to IL"); e.printStackTrace(); RTLStatement skip = new RTLSkip(); skip.setLabel(label); skip.setNextLabel(new RTLLabel(new AbsoluteAddress(address.getValue() + 1))); putStatement(skip); } assert statementMap.containsKey(label) : "Disassembly did not produce label: " + label; } } return statementMap.get(label); }
/** * Stores a statement in the program. If a statement already exists with the same label, it is * replaced. * * @param stmt The statement to be stored. Has to contain a proper label. */ public final void putStatement(RTLStatement stmt) { RTLStatement existing = statementMap.get(stmt.getLabel()); if (existing != null) { if (existing.equals(stmt)) return; logger.debug("Replacing statement at " + stmt.getLabel()); } statementMap.put(stmt.getLabel(), stmt); }
public int countIndirectBranches() { int res = 0; for (Map.Entry<AbsoluteAddress, Instruction> entry : assemblyMap.entrySet()) { Instruction instr = entry.getValue(); if (instr instanceof BranchInstruction) { BranchInstruction branch = (BranchInstruction) instr; if (branch.isIndirect()) { // if branch target is not a memory operand pointing into a static data area of the binary // (imports) if (branch.getBranchDestination() instanceof MemoryOperand) { MemoryOperand memOp = (MemoryOperand) branch.getBranchDestination(); // Import calls have only displacement if (memOp.getBase() == null && memOp.getIndex() == null) { AbsoluteAddress disp = new AbsoluteAddress(memOp.getDisplacement()); // Check whether displacement points into import table ExecutableImage module = getModule(disp); if (module instanceof PEModule && ((PEModule) module).getImportTable().containsKey(disp)) continue; } } res++; // logger.verbose(entry.getKey() + "\t" + getInstructionString(entry.getKey())); } } } return res; }
/** * Returns the address of the given procedure within the given library. Procedures present within * the analyzed modules are given precedence over stub functions. * * @param library * @param procedure * @return the virtual address of the procedure */ public AbsoluteAddress getProcAddress(String library, String procedure) { ExportedSymbol expSymbol = exportedSymbols.get(procedure); if (expSymbol != null) { return expSymbol.getAddress(); } else { return stubLibrary.resolveSymbol(library, procedure); } }
/** Resolves symbols between the loaded modules. */ private void resolveSymbols() { Iterator<UnresolvedSymbol> sIter = unresolvedSymbols.iterator(); while (sIter.hasNext()) { UnresolvedSymbol unresolvedSymbol = sIter.next(); ExportedSymbol symbol = exportedSymbols.get(removeDecoration(unresolvedSymbol.getName())); if (symbol != null) { logger.debug("Resolving symbol " + unresolvedSymbol.getName()); unresolvedSymbol.resolve(symbol.getAddress()); sIter.remove(); } } }
public LinkedList<BranchInstruction> getIndirectBranches() { LinkedList<BranchInstruction> indirectBranches = new LinkedList<BranchInstruction>(); for (Map.Entry<AbsoluteAddress, Instruction> entry : assemblyMap.entrySet()) { Instruction instr = entry.getValue(); if (instr instanceof BranchInstruction) { BranchInstruction branch = (BranchInstruction) instr; if (branch.isIndirect()) { indirectBranches.add(branch); } } } return indirectBranches; }
/** * Gets the assembly instruction at the specified virtual address. * * @param address a virtual address * @return the assembly instruction at the specified address */ public final Instruction getInstruction(AbsoluteAddress address) { Instruction instr = assemblyMap.get(address); if (instr != null) { return instr; } else { // No real instructions in prologue/epilogue if (harness.contains(address) || isStub(address)) return null; ExecutableImage module = getModule(address); long fp = -1; if (module == null) { logger.error("No module for address " + address + ". Cannot disassemble instruction!"); } else { fp = module.getFilePointer(address); // Also check whether fp is out of the int range, since the X86Disassembler actually // performs this cast in its implementation. if (fp < 0 || (int) fp < 0) { logger.error("Requested instruction outside of file area: " + address); } else { if (!module.isCodeArea(address)) { logger.error("Requested instruction outside code section: " + address); return null; } instr = module.getDisassembler().decodeInstruction(fp); if (instr == null) { logger.error("Instruction could not be disassembled at: " + address); } } } if (instr != null) putInstruction(address, instr); return instr; } }
/** * Loads a secondary (library or stub) module for analysis. Automatically determines the correct * file type. * * @param moduleFile the file to load * @return the ExecutableImage class for the loaded module * @throws IOException * @throws BinaryParseException */ public ExecutableImage loadModule(File moduleFile) throws IOException, BinaryParseException { // First try to load it as a PE file, then object file, ELF and finally raw binary code // The right thing to do would be some smart IDing of the file type, but // this exception chaining works for now... ExecutableImage module = null; try { module = new PEModule(moduleFile, getArchitecture()); targetOS = TargetOS.WINDOWS; } catch (BinaryParseException e) { try { module = new ObjectFile(moduleFile, getArchitecture()); } catch (BinaryParseException e2) { try { module = new ELFModule(moduleFile, getArchitecture()); targetOS = TargetOS.LINUX; } catch (BinaryParseException e3) { module = new RawModule(moduleFile, getArchitecture()); } } } for (ExecutableImage existingModule : modules) { if (existingModule.getMaxAddress().getValue() >= module.getMinAddress().getValue() && existingModule.getMinAddress().getValue() <= module.getMaxAddress().getValue()) { throw new RuntimeException("Virtual addresses of modules overlap!"); } } modules.add(module); unresolvedSymbols.addAll(module.getUnresolvedSymbols()); for (ExportedSymbol symbol : module.getExportedSymbols()) { exportedSymbols.put(removeDecoration(symbol.getName()), symbol); } resolveSymbols(); return module; }
public Collection<ExportedSymbol> getSymbols() { return exportedSymbols.values(); }
/** * Stores an assembly instruction at the given address, overwriting any existing instruction. * * @param addr the virtual address to save the instruction at * @param instr the assembly instruction * @return true if there was no instruction stored for that address before, false otherwise. */ public final boolean putInstruction(AbsoluteAddress addr, Instruction instr) { // logger.info(addr + " " + instr.toString(addr.getValue(), new DummySymbolFinder())); return assemblyMap.put(addr, instr) == null; }
public final int getInstructionCount() { return assemblyMap.size(); }
public final int getStatementCount() { return statementMap.size(); }
public boolean containsLabel(RTLLabel label) { return statementMap.containsKey(label); }