Exemplo n.º 1
0
 /**
  * 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);
 }
Exemplo n.º 2
0
  public SymbolEntry(BinaryInputBuffer inBuf, Map<Integer, String> stringTable) throws IOException {
    // Parse name
    byte[] nameArray = new byte[8];
    inBuf.read(nameArray);
    // If first 4 bytes are 0, the next 4 are an offset into the string table
    if ((nameArray[0] == 0) && (nameArray[1] == 0) && (nameArray[2] == 0) && (nameArray[3] == 0)) {
      int stringOffset =
          ((nameArray[7] & 0xFF) << 24)
              | ((nameArray[6] & 0xFF) << 16)
              | ((nameArray[5] & 0xFF) << 8)
              | (nameArray[4] & 0xFF);
      String nameString = stringTable.get(stringOffset);
      if (nameString != null) {
        Name = nameString;
      } else {
        logger.warn("No name in string table for symbol at specified offset " + stringOffset);
        Name = "Anonymous(" + stringOffset + ")";
      }
    } else {
      StringBuilder nBuilder = new StringBuilder();
      for (int i = 0; i < 8; i++) {
        if ((nameArray[i] & 0xFF) > 32 && (nameArray[i] & 0xFF) < 128)
          nBuilder.append((char) (nameArray[i] & 0xFF));
      }
      Name = nBuilder.toString();
    }

    Value = inBuf.readDWORD();
    int section = inBuf.readWORD();
    if (section >= 32768) SectionNumber = section - 65536;
    else SectionNumber = section;
    Type = inBuf.readWORD();
    StorageClass = inBuf.readBYTE();
    NumberOfAuxSymbols = inBuf.readBYTE();
  }
Exemplo n.º 3
0
 /**
  * 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);
 }
Exemplo n.º 4
0
 public AbsoluteAddress getAddressForSymbol(String symbol) {
   for (ExecutableImage module : modules) {
     AbsoluteAddress a = module.getSymbolFinder().getAddressFor(symbol);
     if (a != null) return a;
   }
   logger.error("Could not find address for symbol \"" + symbol + "\"");
   return null;
 }
Exemplo n.º 5
0
  /** 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();
      }
    }
  }
Exemplo n.º 6
0
  /**
   * 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;
    }
  }
public class ReverseCFATransformerFactory implements StateTransformerFactory {

  @SuppressWarnings("unused")
  private static final Logger logger = Logger.getLogger(ReverseCFATransformerFactory.class);

  private SetMultimap<Location, CFAEdge> reverseCFA;
  private Location sink;

  public ReverseCFATransformerFactory(Set<CFAEdge> cfa) {
    reverseCFA = HashMultimap.create();
    Set<Location> nonSinks = new HashSet<Location>();
    for (CFAEdge e : cfa) {
      reverseCFA.put(e.getTarget(), e);
      nonSinks.add(e.getSource());
    }

    FastSet<Location> sinks = new FastSet<Location>();
    for (Location l : reverseCFA.keySet()) {
      if (!nonSinks.contains(l)) {
        sinks.add(l);
      }
    }

    if (sinks.size() == 1) {
      sink = sinks.pick();
    } else if (sinks.size() == 0) {
      throw new RuntimeException("CFA has no sink!");
    } else {
      // Generate artificial exit node
      sink = new Location(new AbsoluteAddress(0xFFFFFF01L));
      for (Location l : sinks) {
        reverseCFA.put(sink, new CFAEdge(l, sink, new RTLSkip()));
      }
    }
  }

  @Override
  public Set<CFAEdge> getTransformers(AbstractState a) {
    return reverseCFA.get(a.getLocation());
  }

  @Override
  public Location getInitialLocation() {
    return sink;
  }
}
Exemplo n.º 8
0
  /** For all unresolved symbols, install simple stubs. */
  public void installStubs() {
    if (mainModule instanceof AbstractCOFFModule) {
      stubLibrary = new Win32StubLibrary(arch);
    } else if (mainModule instanceof ELFModule) {
      stubLibrary = new LinuxStubLibrary(arch);
    }

    Iterator<UnresolvedSymbol> sIter = unresolvedSymbols.iterator();
    while (sIter.hasNext()) {
      UnresolvedSymbol unresolvedSymbol = sIter.next();
      AbsoluteAddress address =
          stubLibrary.resolveSymbol(unresolvedSymbol.getFromLibrary(), unresolvedSymbol.getName());
      if (address != null) {
        // logger.debug("Installing stack height stub for " + unresolvedSymbol.getName());
        unresolvedSymbol.resolve(address);
        sIter.remove();
      }
    }

    if (!unresolvedSymbols.isEmpty())
      logger.warn("Unresolved symbols remaining: " + unresolvedSymbols);
  }
 @Override
 public RTLNumber readMemoryLocation(RTLMemoryLocation m) throws IOException {
   if (!(m.getAddress() instanceof RTLNumber)) return null;
   AbsoluteAddress va = new AbsoluteAddress((RTLNumber) m.getAddress());
   long fp = getFilePointer(va);
   if (getSectionNumber(fp) >= 0) {
     assert m.getBitWidth() % 8 == 0 : "Non-byte-aligned memory reference!";
     long val = 0;
     int bytes = m.getBitWidth() / 8;
     // OR together the least significant bytes
     inBuf.seek(fp);
     for (int i = 0; i < bytes - 1; i++) {
       val = val | ((long) inBuf.readBYTE()) << (i * 8);
     }
     // do not mask the MSB with 0xFF, so we get sign extension for free
     val = val | (((long) inBuf.readINT8()) << (bytes - 1) * 8);
     // logger.debug("Read constant value " + val + " from address " + m + " (file offset: " +
     // Long.toHexString(fp) + ") in image.");
     return ExpressionFactory.createNumber(val, m.getBitWidth());
   }
   logger.debug("No value can be read from image for address " + m);
   return null;
 }
Exemplo n.º 10
0
  @Override
  public void run() {
    Runtime runtime = Runtime.getRuntime();
    // Jakstab Algorithm
    System.out.println("Starting CPA algorithm.");
    AbstractState start = cpa.initStartState(transformerFactory.getInitialLocation());
    worklist.add(start);
    reached.add(start);
    if (art != null) art.setRoot(start);

    // Set up precisions
    Precision precision = cpa.initPrecision(transformerFactory.getInitialLocation(), null);
    Map<Location, Precision> precisionMap = new HashMap<Location, Precision>();
    precisionMap.put(start.getLocation(), precision);

    int steps = 0;
    statesVisited = 0;
    final int stepThreshold = 1000;
    long startTime = System.currentTimeMillis();
    long lastSteps = 0;
    long lastTime = 0;
    while (!worklist.isEmpty() && !stop && (!failFast || isSound())) {

      statesVisited++;
      if (++steps == stepThreshold) {

        // Helps limit memory usage
        long now = System.currentTimeMillis();
        System.gc();
        long gcTime = System.currentTimeMillis() - now;
        logger.debug("Time for GC: " + gcTime + "ms");

        now = System.currentTimeMillis();
        long duration = Math.max(1, now - lastTime);
        long speed = (1000L * (statesVisited - lastSteps) / duration);
        // speed = Math.min(speed, 1000);

        logger.warn(
            "*** Reached "
                + reached.size()
                + " states, processed "
                + statesVisited
                + " states after "
                + (now - startTime)
                + "ms, at "
                + speed
                + " states/second"
                + (transformerFactory instanceof ResolvingTransformerFactory
                    ? ", " + program.getInstructionCount() + " instructions."
                    : "."));

        logger.info(
            String.format(
                "    Allocated heap memory: %.2f MByte",
                (runtime.totalMemory() - runtime.freeMemory()) / (1024.0 * 1024.0)));

        steps = 0;

        // StatsPlotter.plot((now - startTime) + "\t" + statesVisited
        // +"\t" + program.getInstructionCount() + "\t" + gcTime + "\t"
        // + speed);

        lastSteps = statesVisited;
        lastTime = now;

        if (Options.timeout.getValue() > 0
            && (System.currentTimeMillis() - startTime > Options.timeout.getValue() * 1000)) {
          logger.error("Timeout after " + Options.timeout.getValue() + "s!");
          stop = true;
        }
      }

      // We need the state before precision refinement for building the
      // ART
      AbstractState unadjustedState = worklist.pick();

      /*
       * if (unadjustedState.getLocation().getAddress().toString().equals(
       * "0x00401189") //||
       * unadjustedState.getLocation().getAddress().toString
       * ().equals("0x0040119b") ||
       * unadjustedState.getLocation().getAddress
       * ().toString().equals("0x00401078") ||
       * unadjustedState.getLocation(
       * ).getAddress().toString().equals("0x0040100a") )
       * System.out.println("Debug " +
       * unadjustedState.getLocation().getAddress().toString());
       */

      precision = precisionMap.get(unadjustedState.getLocation());

      Pair<AbstractState, Precision> pair = cpa.prec(unadjustedState, precision, reached);

      // Warning: The refined a is not stored in "reached", only used for
      // successor calculation
      AbstractState a = pair.getLeft();

      /*
       * CompositeState a1 = (CompositeState) a; BasedNumberValuation a2 =
       * (BasedNumberValuation)a1.getComponent(1); if
       * (a2.getStore().isTop()) System.out.println("Debug TOP Value");
       */

      precision = pair.getRight();
      precisionMap.put(a.getLocation(), precision);

      // logger.debug("Picked from worklist: " + a.getIdentifier());

      // getTransformers() and post() might throw exceptions
      try {
        // For each outgoing edge
        // if (a.isTop())
        // System.out.println("Debug TOP");

        /*
         * if
         * (a.getLocation().getAddress().toString().equals("0x004106cd")
         * ||
         * (a.getLocation().getAddress().toString().equals("0x00410498")
         * && a.getLocation().getIndex() >= 0))
         * System.out.println("Debug Transformer Factory:" +
         * a.getLocation().getAddress().toString());
         */

        // Set<CFAEdge> s = transformerFactory.getTransformers(a);
        // System.out.println("Debug Transformer Factory:" +
        // a.getLocation().getAddress().toString());
        for (CFAEdge cfaEdge : transformerFactory.getTransformers(a)) {

          Precision targetPrecision = precisionMap.get(cfaEdge.getTarget());
          if (targetPrecision == null) {
            targetPrecision = cpa.initPrecision(cfaEdge.getTarget(), cfaEdge.getTransformer());
            precisionMap.put(cfaEdge.getTarget(), targetPrecision);
          }

          // Prefix everything by current location for easier
          // debugging
          // Logger.setGlobalPrefix(cfaEdge.getSource().toString());
          // if
          // (cfaEdge.getSource().getAddress().toString().equals("0x00401027")
          // &&
          // cfaEdge.getTarget().getAddress().toString().equals("0x0040102e"))
          // System.out.println("Debug Edge");
          // Calculate the set of abstract successors
          Set<AbstractState> successors = cpa.post(a, cfaEdge, targetPrecision);

          if (successors.isEmpty()) {
            logger.debug("No successors along edge " + cfaEdge + ", reached halt?");
            continue;
          }

          // logger.debug("via edge " + cfaEdge.toString() + " " +
          // successors.size() + " successors.");

          // Process every successor
          for (AbstractState succ : successors) {
            // logger.debug("Processing new post state: " +
            // succ.getIdentifier());

            // Try to merge the new state with an existing one
            Set<AbstractState> statesToRemove = new FastSet<AbstractState>();
            Set<AbstractState> statesToAdd = new FastSet<AbstractState>();

            for (AbstractState r : reached.where(0, ((CompositeState) succ).getComponent(0))) {
              AbstractState merged = cpa.merge(succ, r, targetPrecision);
              if (!merged.equals(r)) {
                // logger.debug("Merge of " +
                // succ.getIdentifier() + " and " +
                // r.getIdentifier() + " produced new state " +
                // merged.getIdentifier());
                statesToRemove.add(r);
                statesToAdd.add(merged);
              }
            }

            // replace the old state in worklist and reached with
            // the merged version
            for (AbstractState r : statesToRemove) {
              reached.remove(r);
              worklist.remove(r);
              // art.remove(r);
            }

            for (AbstractState r : statesToAdd) {
              // Only add r to the worklist if it hasn't been
              // reached yet
              if (reached.add(r)) {
                worklist.add(r);
                if (art != null) art.addChild(unadjustedState, r);
              }
            }

            // if not stopped add to worklist
            if (!cpa.stop(succ, reached, targetPrecision)
                || this.program.checkSMPos(((CompositeState) succ).getLocation().getAddress())) {
              worklist.add(succ);
              reached.add(succ);
              if (art != null) art.addChild(unadjustedState, succ);
            }
          }
          // end for each outgoing edge
        }
      } catch (StateException e) {
        if (e.getState() == null) {
          e.setState(a);
        }
        if (art != null && !unadjustedState.equals(e.getState()))
          art.addChild(unadjustedState, e.getState());
        throw e;
      }
    }
    long endTime = System.currentTimeMillis();
    if (endTime - startTime > 0) {
      logger.info(
          "Processed "
              + statesVisited
              + " states at "
              + (1000L * statesVisited / (endTime - startTime))
              + " states/second");
      logger.info(
          String.format(
              "Allocated heap memory: %.2f MByte",
              (runtime.totalMemory() - runtime.freeMemory()) / (1024.0 * 1024.0)));
    }

    completed = worklist.isEmpty();
  }
Exemplo n.º 11
0
/** @author Johannes Kinder */
@SuppressWarnings("unused")
class SymbolEntry {

  private static final Logger logger = Logger.getLogger(SymbolEntry.class);

  // Storage classes used by MS compilers
  private static final int IMAGE_SYM_CLASS_EXTERNAL = 2;
  private static final int IMAGE_SYM_CLASS_STATIC = 3;
  private static final int IMAGE_SYM_CLASS_LABEL = 6;
  private static final int IMAGE_SYM_CLASS_FUNCTION = 101;
  private static final int IMAGE_SYM_CLASS_FILE = 103;

  private final String Name;
  private final long Value;
  private final int SectionNumber;
  private final int Type;
  private final int StorageClass;
  private final int NumberOfAuxSymbols;

  public SymbolEntry(BinaryInputBuffer inBuf, Map<Integer, String> stringTable) throws IOException {
    // Parse name
    byte[] nameArray = new byte[8];
    inBuf.read(nameArray);
    // If first 4 bytes are 0, the next 4 are an offset into the string table
    if ((nameArray[0] == 0) && (nameArray[1] == 0) && (nameArray[2] == 0) && (nameArray[3] == 0)) {
      int stringOffset =
          ((nameArray[7] & 0xFF) << 24)
              | ((nameArray[6] & 0xFF) << 16)
              | ((nameArray[5] & 0xFF) << 8)
              | (nameArray[4] & 0xFF);
      String nameString = stringTable.get(stringOffset);
      if (nameString != null) {
        Name = nameString;
      } else {
        logger.warn("No name in string table for symbol at specified offset " + stringOffset);
        Name = "Anonymous(" + stringOffset + ")";
      }
    } else {
      StringBuilder nBuilder = new StringBuilder();
      for (int i = 0; i < 8; i++) {
        if ((nameArray[i] & 0xFF) > 32 && (nameArray[i] & 0xFF) < 128)
          nBuilder.append((char) (nameArray[i] & 0xFF));
      }
      Name = nBuilder.toString();
    }

    Value = inBuf.readDWORD();
    int section = inBuf.readWORD();
    if (section >= 32768) SectionNumber = section - 65536;
    else SectionNumber = section;
    Type = inBuf.readWORD();
    StorageClass = inBuf.readBYTE();
    NumberOfAuxSymbols = inBuf.readBYTE();
  }

  public String getName() {
    return Name;
  }

  public long getValue() {
    return Value;
  }

  public int getNumberOfAuxSymbols() {
    return NumberOfAuxSymbols;
  }

  public int getStorageClass() {
    return StorageClass;
  }

  /**
   * Does the symbol refer to a global variable or external function?
   *
   * @return true if the symbol is a global variable or external function, false otherwise.
   */
  public boolean isExternal() {
    return StorageClass == IMAGE_SYM_CLASS_EXTERNAL;
  }

  /**
   * Does the symbol refer to a static value, i.e. a string literal or a jump table?
   *
   * @return true, if the value field refers to the offset of the value relative to it's section
   *     start, false if it is something else.
   */
  public boolean isStatic() {
    return StorageClass == IMAGE_SYM_CLASS_STATIC;
  }

  /**
   * Does the symbol refer to a jump label? If true, the value field contains the offset of the jump
   * target relative to the section.
   *
   * @return true if the symbol points to a jump label, false otherwise.
   */
  public boolean isLabel() {
    return StorageClass == IMAGE_SYM_CLASS_LABEL;
  }

  public int getSectionNumber() {
    return SectionNumber;
  }

  @Override
  public String toString() {
    return "Name: "
        + Name
        + " Storage class: "
        + StorageClass
        + " Section number: "
        + SectionNumber
        + " Value: "
        + Long.toHexString(Value);
  }
}
Exemplo n.º 12
0
/**
 * There is one singleton Program object for all modules currently under analysis. It stores all
 * non-analysis information about the analyzed programs, including statements, the current control
 * flow graph, and symbols.
 *
 * @author Johannes Kinder
 */
public final class Program {

  private static final Logger logger = Logger.getLogger(Program.class);
  private static Program programInstance;

  /**
   * Get the singleton Program object.
   *
   * @return the singleton instance of the Program class
   */
  public static Program getProgram() {
    return programInstance;
  }

  /**
   * Initially creates the Program object.
   *
   * @param arch An Architecture object with architecture specific information
   * @return the new singleton instance of the Program class
   */
  public static Program createProgram(Architecture arch) {
    // assert programInstance == null;
    programInstance = new Program(arch);
    return programInstance;
  }

  private final Architecture arch;
  private RTLLabel start;
  private Map<RTLLabel, RTLStatement> statementMap;
  private Map<AbsoluteAddress, Instruction> assemblyMap;
  private ExecutableImage mainModule;
  private List<ExecutableImage> modules;
  private ControlFlowGraph cfg;
  private final Map<String, ExportedSymbol> exportedSymbols;
  private final Set<UnresolvedSymbol> unresolvedSymbols;
  private Set<RTLLabel> unresolvedBranches;
  private StubProvider stubLibrary;
  private Harness harness;

  public enum TargetOS {
    WINDOWS,
    LINUX,
    UNKNOWN
  };

  private TargetOS targetOS;

  private Program(Architecture arch) {
    this.arch = arch;
    this.targetOS = TargetOS.UNKNOWN;

    modules = new LinkedList<ExecutableImage>();
    assemblyMap = new TreeMap<AbsoluteAddress, Instruction>();
    statementMap = new HashMap<RTLLabel, RTLStatement>(2000);
    exportedSymbols = new HashMap<String, ExportedSymbol>();
    unresolvedSymbols = new FastSet<UnresolvedSymbol>();

    unresolvedBranches = new FastSet<RTLLabel>();
  }

  /**
   * Loads the module containing the main function. This function should be called last for correct
   * symbol resolution.
   *
   * @param moduleFile the file to load
   * @return the ExecutableImage class for the loaded module
   * @throws IOException
   * @throws BinaryParseException
   */
  public ExecutableImage loadMainModule(File moduleFile) throws IOException, BinaryParseException {
    ExecutableImage module = loadModule(moduleFile);
    mainModule = module;
    setEntryAddress(module.getEntryPoint());
    installStubs();
    return module;
  }

  /**
   * 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;
  }

  private String removeDecoration(String s) {
    if (s.charAt(0) == '@' || s.charAt(0) == '_') s = s.substring(1);
    int i = s.indexOf('@');
    if (i >= 0) s = s.substring(0, i);
    return s;
  }

  /** 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();
      }
    }
  }

  /**
   * 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);
    }
  }

  public boolean isStub(AbsoluteAddress a) {
    return a.getValue() >= StubProvider.STUB_BASE;
  }

  public boolean isImport(AbsoluteAddress a) {
    if (isStub(a)) return true;
    ExecutableImage m = getModule(a);
    if (m == null) return false;
    return m.isImportArea(a);
  }

  /** For all unresolved symbols, install simple stubs. */
  public void installStubs() {
    if (mainModule instanceof AbstractCOFFModule) {
      stubLibrary = new Win32StubLibrary(arch);
    } else if (mainModule instanceof ELFModule) {
      stubLibrary = new LinuxStubLibrary(arch);
    }

    Iterator<UnresolvedSymbol> sIter = unresolvedSymbols.iterator();
    while (sIter.hasNext()) {
      UnresolvedSymbol unresolvedSymbol = sIter.next();
      AbsoluteAddress address =
          stubLibrary.resolveSymbol(unresolvedSymbol.getFromLibrary(), unresolvedSymbol.getName());
      if (address != null) {
        // logger.debug("Installing stack height stub for " + unresolvedSymbol.getName());
        unresolvedSymbol.resolve(address);
        sIter.remove();
      }
    }

    if (!unresolvedSymbols.isEmpty())
      logger.warn("Unresolved symbols remaining: " + unresolvedSymbols);
  }

  /**
   * Install a harness that sets up the symbolic environment before calling main and provides a
   * return point with a termination statement.
   *
   * @param harness the harness object to install
   */
  public void installHarness(Harness harness) {
    this.harness = harness;
    harness.install(this);
  }

  /**
   * Set the program entry point to the given label.
   *
   * @param label the new entry point
   */
  public void setStart(RTLLabel label) {
    this.start = label;
  }

  /**
   * Set the program entry point to the given address.
   *
   * @param entryAddress the new entry address
   */
  public void setEntryAddress(AbsoluteAddress entryAddress) {
    setStart(new RTLLabel(entryAddress));
  }

  /**
   * Get the main module.
   *
   * @return the main module
   */
  public ExecutableImage getMainModule() {
    return mainModule;
  }

  /**
   * Get the module that contains the specified virtual address at runtime.
   *
   * @param a a virtual address
   * @return the module to which the given virtual address belongs.
   */
  public ExecutableImage getModule(AbsoluteAddress a) {
    for (ExecutableImage module : modules) {
      if (module.getFilePointer(a) >= 0) return module;
    }
    return null;
  }

  public Iterator<AbsoluteAddress> codeAddressIterator() {
    return getMainModule().codeBytesIterator();
  }

  /**
   * 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 boolean containsLabel(RTLLabel label) {
    return statementMap.containsKey(label);
  }

  public final int getStatementCount() {
    return statementMap.size();
  }

  public final int getInstructionCount() {
    return assemblyMap.size();
  }

  public Harness getHarness() {
    return harness;
  }

  /**
   * 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;
    }
  }

  /**
   * 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;
  }

  /**
   * Get the string representation of the assembly instruction at the given address.
   *
   * @param addr a virtual address
   * @return a string representation of the assembly code at the given address
   */
  public String getInstructionString(AbsoluteAddress addr) {
    Instruction instr = getInstruction(addr);
    if (instr == null) return "NON_EXISTENT";
    return instr.toString(addr.getValue(), symbolFinder(addr));
  }

  /**
   * Get the string representation of the specified assembly instruction assuming it is located at
   * the given address.
   *
   * @param addr a virtual address
   * @param instr an assembly instruction
   * @return a string representation of the assembly code at the given address
   */
  public String getInstructionString(AbsoluteAddress addr, Instruction instr) {
    if (instr == null) return "NON_EXISTENT";
    return instr.toString(addr.getValue(), symbolFinder(addr));
  }

  public String getSymbolFor(RTLLabel label) {
    SymbolFinder symFinder = symbolFinder(label.getAddress());
    if (symFinder.hasSymbolFor(label.getAddress())) {
      return symFinder.getSymbolFor(label.getAddress());
    } else {
      return label.toString();
    }
  }

  public String getSymbolFor(AbsoluteAddress addr) {
    return symbolFinder(addr).getSymbolFor(addr);
  }

  public AbsoluteAddress getAddressForSymbol(String symbol) {
    for (ExecutableImage module : modules) {
      AbsoluteAddress a = module.getSymbolFinder().getAddressFor(symbol);
      if (a != null) return a;
    }
    logger.error("Could not find address for symbol \"" + symbol + "\"");
    return null;
  }

  private SymbolFinder symbolFinder(AbsoluteAddress addr) {
    if (isStub(addr)) return stubLibrary.getSymbolFinder();

    ExecutableImage module = getModule(addr);
    return (module == null) ? DummySymbolFinder.getInstance() : module.getSymbolFinder();
  }

  public Set<RTLLabel> getUnresolvedBranches() {
    return unresolvedBranches;
  }

  public void setUnresolvedBranches(Set<RTLLabel> unresolvedBranches) {
    this.unresolvedBranches = unresolvedBranches;
  }

  /** @return the assemblyMap */
  public final Map<AbsoluteAddress, Instruction> getAssemblyMap() {
    return assemblyMap;
  }

  public TargetOS getTargetOS() {
    return targetOS;
  }

  /**
   * Returns all variables used in the program. At the current state of the implementation, this
   * includes only registers and flags.
   *
   * @return A set containing all variables used in this program.
   */
  public SetOfVariables getUsedVariables() {
    SetOfVariables result = new SetOfVariables();
    for (CFAEdge edge : cfg.getEdges())
      result.addAll(((RTLStatement) edge.getTransformer()).getUsedVariables());
    return result;
  }

  public Architecture getArchitecture() {
    return arch;
  }

  public Collection<ExportedSymbol> getSymbols() {
    return exportedSymbols.values();
  }

  public ControlFlowGraph getCFG() {
    return cfg;
  }

  public void setCFA(Set<CFAEdge> cfa) {
    cfg = new FineGrainedCFG(cfa);
  }

  public RTLLabel getStart() {
    return start;
  }

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

  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;
  }
}
Exemplo n.º 13
0
 public void stop() {
   logger.fatal(Characters.starredBox("Interrupt! Stopping CPA Algorithm!"));
   stop = true;
 }
Exemplo n.º 14
0
/**
 * A reduced interval congruence analysis with regioned memory. Inspired by Codesurfer's VSA domain.
 *
 * @author Johannes Kinder
 */
public class IntervalAnalysis implements ConfigurableProgramAnalysis {

  public static void register(AnalysisProperties p) {
    p.setShortHand('i');
    p.setName("Interval analysis");
    p.setDescription("Compute strided intervals with region information.");
    p.setExplicit(true);
  }

  private static final Logger logger = Logger.getLogger(IntervalAnalysis.class);
  private AbstractValueFactory<IntervalElement> valueFactory;

  public IntervalAnalysis() {
    valueFactory = new IntervalElementFactory();
  }

  @Override
  public Precision initPrecision(Location location, StateTransformer transformer) {
    return new IntervalPrecision();
  }

  /*
   * @see org.jakstab.analysis.ConfigurableProgramAnalysis#initStartState(org.jakstab.cfa.Location)
   */
  @Override
  public AbstractState initStartState(Location location) {
    // IntervalState init = new IntervalState();
    /*init.setValue(Program.getProgram().getArchitecture().stackPointer(),
    new IntervalElement(MemoryRegion.STACK, 0, 0, 0, 32));*/
    // return init;
    return new ValuationState(valueFactory);
  }

  /*
   * @see org.jakstab.analysis.ConfigurableProgramAnalysis#merge(org.jakstab.analysis.AbstractState, org.jakstab.analysis.AbstractState)
   */
  @Override
  public AbstractState merge(AbstractState s1, AbstractState s2, Precision precision) {

    // Widen s2 towards s1.
    // return ((IntervalState)s2).widen((IntervalState)s1);

    if (s2.isTop() || s1.isBot()) return s2;
    if (s1.isTop()) return s1;

    ValuationState current = (ValuationState) s2;
    ValuationState towards = (ValuationState) s1;

    ValuationState widenedState = new ValuationState(valueFactory);
    // Widen variable valuations
    for (Iterator<Map.Entry<RTLVariable, AbstractDomainElement>> entryIt =
            current.variableIterator();
        entryIt.hasNext(); ) {
      Map.Entry<RTLVariable, AbstractDomainElement> entry = entryIt.next();
      RTLVariable var = entry.getKey();
      IntervalElement v = (IntervalElement) entry.getValue();
      widenedState.setVariableValue(var, v.widen((IntervalElement) towards.getVariableValue(var)));
    }

    // Widen memory
    for (EntryIterator<MemoryRegion, Long, AbstractDomainElement> entryIt = current.storeIterator();
        entryIt.hasEntry();
        entryIt.next()) {
      MemoryRegion region = entryIt.getLeftKey();
      Long offset = entryIt.getRightKey();
      IntervalElement v = (IntervalElement) entryIt.getValue();
      int bitWidth = v.getBitWidth();
      widenedState.setMemoryValue(
          region,
          offset,
          bitWidth,
          v.widen((IntervalElement) towards.getMemoryValue(region, offset, bitWidth)));
    }

    return widenedState;
  }

  /*
   * @see org.jakstab.analysis.ConfigurableProgramAnalysis#post(org.jakstab.analysis.AbstractState, org.jakstab.analysis.StateTransformer, org.jakstab.analysis.Precision)
   */
  @Override
  public Set<AbstractState> post(final AbstractState state, CFAEdge cfaEdge, Precision precision) {

    final RTLStatement statement = (RTLStatement) cfaEdge.getTransformer();
    final ValuationState iState = (ValuationState) state;

    return Collections.singleton(
        statement.accept(
            new DefaultStatementVisitor<AbstractState>() {

              @Override
              protected AbstractState visitDefault(RTLStatement stmt) {
                return state;
              }

              @Override
              public AbstractState visit(RTLVariableAssignment stmt) {
                ValuationState post = new ValuationState(iState);
                Writable lhs = stmt.getLeftHandSide();
                RTLExpression rhs = stmt.getRightHandSide();
                AbstractDomainElement evaledRhs = iState.abstractEval(rhs);

                // Check for stackpointer alignment assignments (workaround for gcc compiled files)
                RTLVariable sp = Program.getProgram().getArchitecture().stackPointer();
                if (lhs.equals(sp) && rhs instanceof RTLOperation) {
                  RTLOperation op = (RTLOperation) rhs;
                  if (op.getOperator().equals(Operator.AND)
                      && op.getOperands()[0].equals(sp)
                      && op.getOperands()[1] instanceof RTLNumber) {
                    evaledRhs = iState.getVariableValue(sp);
                    logger.warn("Ignoring stackpointer alignment at " + stmt.getAddress());
                  }
                }

                post.setVariableValue((RTLVariable) lhs, evaledRhs);

                return post;
              }

              @Override
              public AbstractState visit(RTLMemoryAssignment stmt) {
                ValuationState post = new ValuationState(iState);
                RTLMemoryLocation m = stmt.getLeftHandSide();
                RTLExpression rhs = stmt.getRightHandSide();
                AbstractDomainElement evaledRhs = iState.abstractEval(rhs);
                AbstractDomainElement evaledAddress = iState.abstractEval(m.getAddress());
                post.setMemoryValue(evaledAddress, m.getBitWidth(), evaledRhs);
                return post;
              }

              @Override
              public AbstractState visit(RTLAssume stmt) {

                ValuationState post = new ValuationState(iState);

                RTLExpression assumption = stmt.getAssumption();

                // TODO: implement assume

                if (assumption instanceof RTLOperation) {
                  RTLOperation op = (RTLOperation) assumption;
                  switch (op.getOperator()) {
                    case UNSIGNED_LESS_OR_EQUAL:
                      RTLExpression lhs = op.getOperands()[0];
                      RTLExpression rhs = op.getOperands()[1];
                      IntervalElement evaledLhs = (IntervalElement) iState.abstractEval(lhs);
                      IntervalElement evaledRhs = (IntervalElement) iState.abstractEval(rhs);

                      if (evaledRhs.getLeft() >= 0) {
                        IntervalElement uLessInt =
                            new IntervalElement(
                                evaledRhs.getRegion(),
                                0,
                                evaledRhs.getRight(),
                                1,
                                evaledLhs.getBitWidth());
                        // TODO: Implement meet for interval elements for optimal result
                        // uLessInt = uLessInt.meet(evaledLhs);
                        // if uLessInt.isBot() return Collections.emptySet();
                        // cheap but sound solution for now: only use new interval if it has less
                        // elements
                        if (uLessInt.size() < evaledLhs.size()) {
                          if (lhs instanceof RTLVariable) {
                            post.setVariableValue((RTLVariable) lhs, uLessInt);
                          } else if (lhs instanceof RTLMemoryLocation) {
                            RTLMemoryLocation m = (RTLMemoryLocation) lhs;
                            AbstractDomainElement evaledAddress =
                                iState.abstractEval(m.getAddress());
                            post.setMemoryValue(evaledAddress, m.getBitWidth(), uLessInt);
                          }
                        }
                      }
                      break;
                    default: // nothing
                  }
                }

                return post;
              }

              @Override
              public AbstractState visit(RTLAlloc stmt) {
                ValuationState post = new ValuationState(iState);
                Writable lhs = stmt.getPointer();

                MemoryRegion newRegion;
                if (stmt.getAllocationName() != null) {
                  newRegion = MemoryRegion.create(stmt.getAllocationName());
                } else {
                  // TODO: Detect whether this allocation is unique to allow strong updates
                  newRegion = MemoryRegion.createAsSummary("alloc" + stmt.getLabel());
                }

                IntervalElement basePointer =
                    new IntervalElement(newRegion, ExpressionFactory.createNumber(0, 32));

                if (lhs instanceof RTLVariable) {
                  post.setVariableValue((RTLVariable) lhs, basePointer);
                } else {
                  RTLMemoryLocation m = (RTLMemoryLocation) lhs;
                  AbstractDomainElement evaledAddress = iState.abstractEval(m.getAddress());
                  post.setMemoryValue(evaledAddress, m.getBitWidth(), basePointer);
                }

                return post;
              }

              @Override
              public AbstractState visit(RTLHavoc stmt) {
                ValuationState post = new ValuationState(iState);

                // Only create a single state with the havoc range, since this analysis
                // is not path sensitive
                post.setVariableValue(
                    stmt.getVariable(),
                    // new IntervalElement(ExpressionFactory.getInstance().createNumber(0,
                    // stmt.getVariable().getBitWidth()),
                    // (RTLNumber)stmt.getMaximum()));
                    new IntervalElement(
                        MemoryRegion.GLOBAL,
                        0,
                        ((RTLNumber) stmt.getMaximum()).longValue(),
                        1,
                        stmt.getVariable().getBitWidth()));

                return post;
              }

              @Override
              public AbstractState visit(RTLUnknownProcedureCall stmt) {
                ValuationState post = new ValuationState(iState);
                for (RTLVariable var : stmt.getDefinedVariables()) {
                  post.setVariableValue(var, IntervalElement.getTop(var.getBitWidth()));
                }
                post.setMemoryValue(
                    IntervalElement.getTop(
                        Program.getProgram().getArchitecture().getAddressBitWidth()),
                    32,
                    IntervalElement.getTop(32));
                return post;
              }
            }));
  }

  @Override
  public AbstractState strengthen(
      AbstractState s, Iterable<AbstractState> otherStates, CFAEdge cfaEdge, Precision precision) {

    ValuationState state = (ValuationState) s;
    ValuationState strengthenedState = null;

    for (AbstractState t : otherStates) {
      // TODO: Does not work correctly if BoundedAddressTracking returns more than
      // 		 one successor state.
      if (t instanceof BasedNumberValuation) {
        BasedNumberValuation exState = (BasedNumberValuation) t;
        for (Map.Entry<RTLVariable, BasedNumberElement> entry : exState.getVariableValuation()) {
          RTLVariable var = entry.getKey();
          BasedNumberElement exVal = entry.getValue();
          if (exVal.isTop() || exVal.isNumberTop()) continue;
          if (state.getVariableValue(var).isTop()) {
            if (strengthenedState == null) {
              strengthenedState = new ValuationState(state);
            }
            strengthenedState.setVariableValue(
                var, new IntervalElement(exVal.getRegion(), exVal.getNumber()));
            // logger.debug("Strengthened state " + state.getIdentifier() +
            //		" by setting " + var + " to " + state.getValue(var));
          }
        }
      }
    }

    return strengthenedState == null ? state : strengthenedState;
  }

  @Override
  public Pair<AbstractState, Precision> prec(
      AbstractState s, Precision precision, ReachedSet reached) {
    return Pair.create(s, precision);
  }

  @Override
  public boolean stop(AbstractState s, ReachedSet reached, Precision precision) {
    return CPAOperators.stopJoin(s, reached, precision);
  }

  private RTLExpression addClause(RTLExpression formula, RTLExpression clause) {
    if (formula != null) {
      return ExpressionFactory.createAnd(formula, clause);
    } else {
      return clause;
    }
  }

  public RTLExpression getStateFormula(ValuationState state) {
    RTLExpression result = null;

    for (Iterator<Map.Entry<RTLVariable, AbstractDomainElement>> entryIt = state.variableIterator();
        entryIt.hasNext(); ) {
      Map.Entry<RTLVariable, AbstractDomainElement> entry = entryIt.next();
      RTLVariable var = entry.getKey();
      IntervalElement interval = (IntervalElement) entry.getValue();

      if (interval.size() == 1) {
        result =
            addClause(
                result,
                ExpressionFactory.createEqual(
                    var, ExpressionFactory.createNumber(interval.getLeft(), var.getBitWidth())));
      } else {
        if (!interval.leftOpen()) {
          result =
              addClause(
                  result,
                  ExpressionFactory.createLessOrEqual(
                      ExpressionFactory.createNumber(interval.getLeft(), var.getBitWidth()), var));
        }

        if (!interval.rightOpen()) {
          result =
              addClause(
                  result,
                  ExpressionFactory.createLessOrEqual(
                      var, ExpressionFactory.createNumber(interval.getRight(), var.getBitWidth())));
        }
      }
    }

    if (result == null) {
      result = ExpressionFactory.TRUE;
    }

    return result;
  }
}
/**
 * An abstract class that encapsulates the common features of MS COFF and PE files.
 *
 * @author Johannes Kinder
 */
public abstract class AbstractCOFFModule implements ExecutableImage {

  @SuppressWarnings("unused")
  private static final Logger logger = Logger.getLogger(AbstractCOFFModule.class);

  protected BinaryFileInputBuffer inBuf;
  protected COFF_Header coff_header;
  protected SectionHeader[] section_headers;
  protected Disassembler disassembler;

  @Override
  public final long getFilePointer(AbsoluteAddress va) {
    long fp = getFilePointerFromRVA(va.getValue() - getBaseAddress());
    if (fp >= 0) return fp;
    else return -1;
  }

  @Override
  public final boolean isCodeArea(AbsoluteAddress va) {
    int section = getSectionNumber(va);
    if (section < 0) return false;
    else return isCodeSection(section);
  }

  /** Returns the file pointer equivalent of the given RVA. */
  protected final long getFilePointerFromRVA(long rva) {
    int sct = getSectionNumberByRVA(rva);
    if (sct < 0) return -1;
    if (rva - getSectionHeader(sct).VirtualAddress > getSectionHeader(sct).SizeOfRawData) return -1;
    return (rva - getSectionHeader(sct).VirtualAddress) + getSectionHeader(sct).PointerToRawData;
  }

  /** Returns the RVA for a given file pointer. */
  protected final long getRVAFromFilePointer(long filePointer) {
    int sct = getSectionNumber(filePointer);
    if (sct < 0) return -1;
    return ((filePointer - getSectionHeader(sct).PointerToRawData)
        + getSectionHeader(sct).VirtualAddress);
  }

  /**
   * Returns the number of the section the given virtual address is in.
   *
   * @param va the virtual address
   * @return the section number
   */
  protected final int getSectionNumber(AbsoluteAddress va) {
    return getSectionNumberByRVA(va.getValue() - getBaseAddress());
  }

  /**
   * Returns the number of the section a given file pointer lies in.
   *
   * @param fp the file pointer
   * @return the section number
   */
  protected final int getSectionNumber(long fp) {
    for (int i = 0; i < getNumberOfSections(); i++)
      if (getSectionHeader(i).PointerToRawData <= fp
          && (getSectionHeader(i).PointerToRawData + getSectionHeader(i).SizeOfRawData) > fp)
        return i;
    return -1;
  }

  /**
   * Returns the number of the section a given RVA lies in.
   *
   * @param rva the Relative Virtual Address
   * @return the section number
   */
  protected abstract int getSectionNumberByRVA(long rva);

  /**
   * Returns the virtual address that corresponds to a given file pointer
   *
   * @param fp the file pointer
   * @return the virtual address
   */
  public final AbsoluteAddress getVirtualAddress(long fp) {
    long rva = getRVAFromFilePointer(fp);
    if (rva >= 0) return new AbsoluteAddress(rva + getBaseAddress());
    else return null;
  }

  protected final int getNumberOfSections() {
    return section_headers.length;
  }

  public AbsoluteAddress getMaxAddress() {
    long highAddress = Long.MIN_VALUE;
    for (int i = 0; i < getNumberOfSections(); i++) {
      highAddress =
          Math.max(
              getSectionHeader(i).VirtualAddress + getSectionHeader(i).SizeOfRawData, highAddress);
    }
    highAddress += getBaseAddress();
    return new AbsoluteAddress(highAddress);
  }

  public AbsoluteAddress getMinAddress() {
    long lowAddress = Long.MAX_VALUE;
    for (int i = 0; i < getNumberOfSections(); i++) {
      lowAddress = Math.min(getSectionHeader(i).VirtualAddress, lowAddress);
    }
    lowAddress += getBaseAddress();
    return new AbsoluteAddress(lowAddress);
  }

  protected final SectionHeader getSectionHeader(int index) {
    return section_headers[index];
  }

  protected final boolean isCodeSection(int section) {
    return getSectionHeader(section).isCodeSection();
  }

  protected abstract long getBaseAddress();

  @Override
  public RTLNumber readMemoryLocation(RTLMemoryLocation m) throws IOException {
    if (!(m.getAddress() instanceof RTLNumber)) return null;
    AbsoluteAddress va = new AbsoluteAddress((RTLNumber) m.getAddress());
    long fp = getFilePointer(va);
    if (getSectionNumber(fp) >= 0) {
      assert m.getBitWidth() % 8 == 0 : "Non-byte-aligned memory reference!";
      long val = 0;
      int bytes = m.getBitWidth() / 8;
      // OR together the least significant bytes
      inBuf.seek(fp);
      for (int i = 0; i < bytes - 1; i++) {
        val = val | ((long) inBuf.readBYTE()) << (i * 8);
      }
      // do not mask the MSB with 0xFF, so we get sign extension for free
      val = val | (((long) inBuf.readINT8()) << (bytes - 1) * 8);
      // logger.debug("Read constant value " + val + " from address " + m + " (file offset: " +
      // Long.toHexString(fp) + ") in image.");
      return ExpressionFactory.createNumber(val, m.getBitWidth());
    }
    logger.debug("No value can be read from image for address " + m);
    return null;
  }

  public byte[] getByteArray() {
    return inBuf.getByteArray();
  }

  @Override
  public Iterator<AbsoluteAddress> codeBytesIterator() {
    return new Iterator<AbsoluteAddress>() {

      long fp = 0;
      int sec = -1;

      {
        moveToNextCodeSection();
      }

      private void moveToNextCodeSection() {
        sec++;
        while (sec < getNumberOfSections() && !isCodeSection(sec)) {
          sec++;
        }
        if (sec >= getNumberOfSections()) {
          fp = -1;
          sec = -1;
        } else {
          fp = getSectionHeader(sec).PointerToRawData;
        }
      }

      private void moveToNextCodeByte() {

        fp++;

        if (fp >= getSectionHeader(sec).PointerToRawData + getSectionHeader(sec).SizeOfRawData) {
          moveToNextCodeSection();
          if (sec < 0) {
            return;
          }
        }
      }

      @Override
      public boolean hasNext() {
        return (fp >= 0);
      }

      @Override
      public AbsoluteAddress next() {
        if (!hasNext()) throw new IndexOutOfBoundsException();
        AbsoluteAddress res = getVirtualAddress(fp);
        moveToNextCodeByte();
        return res;
      }

      @Override
      public void remove() {
        throw new UnsupportedOperationException();
      }
    };
  }

  @Override
  public Disassembler getDisassembler() {
    if (disassembler == null) {
      disassembler = new X86Disassembler(inBuf);
    }
    return disassembler;
  }
}
/**
 * States corresponding to a line number within a pre-recorded trace. Each state stores a reference
 * to the trace to allow direct access to recorded PC values.
 */
public class TraceReplayState implements UnderApproximateState {

  @SuppressWarnings("unused")
  private static final Logger logger = Logger.getLogger(TraceReplayState.class);

  public static TraceReplayState BOT = new TraceReplayState();

  private final AbsoluteAddress cur;
  private final SetMultimap<AbsoluteAddress, AbsoluteAddress> succ;

  private TraceReplayState() {
    super();
    cur = new AbsoluteAddress(0xF0000B07L);
    succ = null;
  }

  public TraceReplayState(SetMultimap<AbsoluteAddress, AbsoluteAddress> succ, AbsoluteAddress cur) {
    this.succ = succ;
    this.cur = cur;
  }

  @Override
  public String getIdentifier() {
    return cur.toString();
  }

  @Override
  public Location getLocation() {
    throw new UnsupportedOperationException();
  }

  /**
   * Get the value of the program counter at the current state.
   *
   * @return an AbsoluteAddress corresponding to the PC value for the analyzed module.
   */
  public AbsoluteAddress getCurrentPC() {
    return cur;
  }

  /**
   * Get the value of the program counter at the current state's successor state.
   *
   * @return an AbsoluteAddress corresponding to the next PC value for the analyzed module.
   */
  public Set<AbsoluteAddress> getNextPC() {
    return succ.get(cur);
  }

  @Override
  public AbstractState join(LatticeElement l) {
    throw new UnsupportedOperationException();
  }

  @Override
  public Set<Tuple<RTLNumber>> projectionFromConcretization(RTLExpression... expressions) {

    // Only concretize expression requests from transformerFactory
    // Warning: If this method is invoked with 2 parameters for other reasons, it will
    //          likely fail!
    if (expressions.length != 2) return null;

    // If not on trace, don't concretize
    if (isBot()) return null;

    RTLExpression condition = expressions[0];
    RTLExpression target = expressions[1];
    RTLNumber cCondition;
    RTLNumber cTarget;

    Set<Tuple<RTLNumber>> res = new FastSet<Tuple<RTLNumber>>();

    for (AbsoluteAddress successor : getNextPC()) {
      RTLNumber nextPC = successor.toNumericConstant();

      if (target instanceof RTLNumber) {
        // If target is a number, this is a direct jump, and maybe conditional

        cTarget = (RTLNumber) target;

        if (condition instanceof RTLNumber) {
          // Direct, unconditional jump
          cCondition = (RTLNumber) condition;
        } else if (target.equals(nextPC)) {
          // Conditional jump that is taken according to the trace
          cCondition = ExpressionFactory.TRUE;
        } else {
          // Conditional jump that is not taken
          cCondition = ExpressionFactory.FALSE;
        }

      } else {
        // Target is not a number, so this is an indirect jump

        assert (condition instanceof RTLNumber)
            : "There should be no conditional indirect jumps in x86!";
        cCondition = (RTLNumber) condition;
        cTarget = nextPC;
      }
      res.add(Tuple.create(cCondition, cTarget));
    }

    return res;
  }

  @Override
  public boolean isBot() {
    return this == BOT;
  }

  @Override
  public boolean isTop() {
    return false;
  }

  @Override
  public int hashCode() {
    return cur.hashCode();
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null) return false;

    return cur.equals(((TraceReplayState) obj).cur);
  }

  @Override
  public boolean lessOrEqual(LatticeElement l) {
    TraceReplayState other = (TraceReplayState) l;
    if (other.isTop() || this.isBot()) return true;
    return this.equals(l);
  }

  public String toString() {
    if (isBot()) return "Trace@BOT";
    return "Trace@" + getCurrentPC() + ": Next: " + getNextPC();
  }
}
Exemplo n.º 17
0
/**
 * The main CPA worklist algorithm.
 *
 * @author Johannes Kinder
 */
public class CPAAlgorithm implements Algorithm {

  private static final Logger logger = Logger.getLogger(CPAAlgorithm.class);

  private final Program program;
  private final StateTransformerFactory transformerFactory;
  private final ConfigurableProgramAnalysis cpa;
  private final ReachedSet reached;
  private final AbstractReachabilityTree art;
  private final Worklist<AbstractState> worklist;

  private final boolean failFast;

  private long statesVisited;
  private boolean completed = false;
  private volatile boolean stop = false;

  /**
   * Instantiates a new CPA algorithm with a forward location analysis, a default forward
   * transformer factory and worklist suitable for an analysis of a complete and already
   * reconstructed control flow automaton.
   *
   * @param program The program object
   * @param cpas The list of analyses to be performed
   */
  public static CPAAlgorithm createForwardAlgorithm(
      Program program, ConfigurableProgramAnalysis... cpas) {
    ConfigurableProgramAnalysis cpa = new CompositeProgramAnalysis(new LocationAnalysis(), cpas);
    return new CPAAlgorithm(
        program, cpa, new CFATransformerFactory(program.getCFA()), new FastSet<AbstractState>());
  }

  /**
   * Instantiates a new CPA algorithm with a backward location analysis, a default backward
   * transformer factory and worklist suitable for an analysis of a complete and already
   * reconstructed control flow automaton.
   *
   * @param program The program object
   * @param cpas The list of backward analyses to be performed
   */
  public static CPAAlgorithm createBackwardAlgorithm(
      Program program, ConfigurableProgramAnalysis... cpas) {
    ConfigurableProgramAnalysis cpa =
        new CompositeProgramAnalysis(new BackwardLocationAnalysis(), cpas);
    return new CPAAlgorithm(
        program,
        cpa,
        new ReverseCFATransformerFactory(program.getCFA()),
        new FastSet<AbstractState>());
  }

  public CPAAlgorithm(
      Program program,
      ConfigurableProgramAnalysis cpa,
      StateTransformerFactory transformerFactory,
      Worklist<AbstractState> worklist) {
    this(program, cpa, transformerFactory, worklist, false);
  }

  public CPAAlgorithm(
      Program program,
      ConfigurableProgramAnalysis cpa,
      StateTransformerFactory transformerFactory,
      Worklist<AbstractState> worklist,
      boolean failFast) {
    super();
    this.program = program;
    this.cpa = cpa;
    this.transformerFactory = transformerFactory;
    this.worklist = worklist;
    this.failFast = failFast;

    if (Options.errorTrace.getValue() || Options.asmTrace.getValue())
      art = new AbstractReachabilityTree();
    else art = null;
    reached = new ReachedSet();
    this.program.setReachedSet(reached);
  }

  /**
   * After a run of the algorithm, returns the set of reached states.
   *
   * @return the set of reached (and kept) states.
   */
  public ReachedSet getReachedStates() {
    return reached;
  }

  public AbstractReachabilityTree getART() {
    return art;
  }

  public long getNumberOfStatesVisited() {
    return statesVisited;
  }

  /** Returns whether the algorithm terminated normally. */
  public boolean isCompleted() {
    return completed;
  }

  /**
   * Returns whether the algorithm had to make unsound assumptions. Always true for analyses on
   * complete CFAs.
   *
   * @return true if the analysis required unsound assumptions.
   */
  public boolean isSound() {
    if (transformerFactory instanceof ResolvingTransformerFactory) {
      return ((ResolvingTransformerFactory) transformerFactory).isSound();
    } else {
      return true;
    }
  }

  @Override
  public void run() {
    Runtime runtime = Runtime.getRuntime();
    // Jakstab Algorithm
    System.out.println("Starting CPA algorithm.");
    AbstractState start = cpa.initStartState(transformerFactory.getInitialLocation());
    worklist.add(start);
    reached.add(start);
    if (art != null) art.setRoot(start);

    // Set up precisions
    Precision precision = cpa.initPrecision(transformerFactory.getInitialLocation(), null);
    Map<Location, Precision> precisionMap = new HashMap<Location, Precision>();
    precisionMap.put(start.getLocation(), precision);

    int steps = 0;
    statesVisited = 0;
    final int stepThreshold = 1000;
    long startTime = System.currentTimeMillis();
    long lastSteps = 0;
    long lastTime = 0;
    while (!worklist.isEmpty() && !stop && (!failFast || isSound())) {

      statesVisited++;
      if (++steps == stepThreshold) {

        // Helps limit memory usage
        long now = System.currentTimeMillis();
        System.gc();
        long gcTime = System.currentTimeMillis() - now;
        logger.debug("Time for GC: " + gcTime + "ms");

        now = System.currentTimeMillis();
        long duration = Math.max(1, now - lastTime);
        long speed = (1000L * (statesVisited - lastSteps) / duration);
        // speed = Math.min(speed, 1000);

        logger.warn(
            "*** Reached "
                + reached.size()
                + " states, processed "
                + statesVisited
                + " states after "
                + (now - startTime)
                + "ms, at "
                + speed
                + " states/second"
                + (transformerFactory instanceof ResolvingTransformerFactory
                    ? ", " + program.getInstructionCount() + " instructions."
                    : "."));

        logger.info(
            String.format(
                "    Allocated heap memory: %.2f MByte",
                (runtime.totalMemory() - runtime.freeMemory()) / (1024.0 * 1024.0)));

        steps = 0;

        // StatsPlotter.plot((now - startTime) + "\t" + statesVisited
        // +"\t" + program.getInstructionCount() + "\t" + gcTime + "\t"
        // + speed);

        lastSteps = statesVisited;
        lastTime = now;

        if (Options.timeout.getValue() > 0
            && (System.currentTimeMillis() - startTime > Options.timeout.getValue() * 1000)) {
          logger.error("Timeout after " + Options.timeout.getValue() + "s!");
          stop = true;
        }
      }

      // We need the state before precision refinement for building the
      // ART
      AbstractState unadjustedState = worklist.pick();

      /*
       * if (unadjustedState.getLocation().getAddress().toString().equals(
       * "0x00401189") //||
       * unadjustedState.getLocation().getAddress().toString
       * ().equals("0x0040119b") ||
       * unadjustedState.getLocation().getAddress
       * ().toString().equals("0x00401078") ||
       * unadjustedState.getLocation(
       * ).getAddress().toString().equals("0x0040100a") )
       * System.out.println("Debug " +
       * unadjustedState.getLocation().getAddress().toString());
       */

      precision = precisionMap.get(unadjustedState.getLocation());

      Pair<AbstractState, Precision> pair = cpa.prec(unadjustedState, precision, reached);

      // Warning: The refined a is not stored in "reached", only used for
      // successor calculation
      AbstractState a = pair.getLeft();

      /*
       * CompositeState a1 = (CompositeState) a; BasedNumberValuation a2 =
       * (BasedNumberValuation)a1.getComponent(1); if
       * (a2.getStore().isTop()) System.out.println("Debug TOP Value");
       */

      precision = pair.getRight();
      precisionMap.put(a.getLocation(), precision);

      // logger.debug("Picked from worklist: " + a.getIdentifier());

      // getTransformers() and post() might throw exceptions
      try {
        // For each outgoing edge
        // if (a.isTop())
        // System.out.println("Debug TOP");

        /*
         * if
         * (a.getLocation().getAddress().toString().equals("0x004106cd")
         * ||
         * (a.getLocation().getAddress().toString().equals("0x00410498")
         * && a.getLocation().getIndex() >= 0))
         * System.out.println("Debug Transformer Factory:" +
         * a.getLocation().getAddress().toString());
         */

        // Set<CFAEdge> s = transformerFactory.getTransformers(a);
        // System.out.println("Debug Transformer Factory:" +
        // a.getLocation().getAddress().toString());
        for (CFAEdge cfaEdge : transformerFactory.getTransformers(a)) {

          Precision targetPrecision = precisionMap.get(cfaEdge.getTarget());
          if (targetPrecision == null) {
            targetPrecision = cpa.initPrecision(cfaEdge.getTarget(), cfaEdge.getTransformer());
            precisionMap.put(cfaEdge.getTarget(), targetPrecision);
          }

          // Prefix everything by current location for easier
          // debugging
          // Logger.setGlobalPrefix(cfaEdge.getSource().toString());
          // if
          // (cfaEdge.getSource().getAddress().toString().equals("0x00401027")
          // &&
          // cfaEdge.getTarget().getAddress().toString().equals("0x0040102e"))
          // System.out.println("Debug Edge");
          // Calculate the set of abstract successors
          Set<AbstractState> successors = cpa.post(a, cfaEdge, targetPrecision);

          if (successors.isEmpty()) {
            logger.debug("No successors along edge " + cfaEdge + ", reached halt?");
            continue;
          }

          // logger.debug("via edge " + cfaEdge.toString() + " " +
          // successors.size() + " successors.");

          // Process every successor
          for (AbstractState succ : successors) {
            // logger.debug("Processing new post state: " +
            // succ.getIdentifier());

            // Try to merge the new state with an existing one
            Set<AbstractState> statesToRemove = new FastSet<AbstractState>();
            Set<AbstractState> statesToAdd = new FastSet<AbstractState>();

            for (AbstractState r : reached.where(0, ((CompositeState) succ).getComponent(0))) {
              AbstractState merged = cpa.merge(succ, r, targetPrecision);
              if (!merged.equals(r)) {
                // logger.debug("Merge of " +
                // succ.getIdentifier() + " and " +
                // r.getIdentifier() + " produced new state " +
                // merged.getIdentifier());
                statesToRemove.add(r);
                statesToAdd.add(merged);
              }
            }

            // replace the old state in worklist and reached with
            // the merged version
            for (AbstractState r : statesToRemove) {
              reached.remove(r);
              worklist.remove(r);
              // art.remove(r);
            }

            for (AbstractState r : statesToAdd) {
              // Only add r to the worklist if it hasn't been
              // reached yet
              if (reached.add(r)) {
                worklist.add(r);
                if (art != null) art.addChild(unadjustedState, r);
              }
            }

            // if not stopped add to worklist
            if (!cpa.stop(succ, reached, targetPrecision)
                || this.program.checkSMPos(((CompositeState) succ).getLocation().getAddress())) {
              worklist.add(succ);
              reached.add(succ);
              if (art != null) art.addChild(unadjustedState, succ);
            }
          }
          // end for each outgoing edge
        }
      } catch (StateException e) {
        if (e.getState() == null) {
          e.setState(a);
        }
        if (art != null && !unadjustedState.equals(e.getState()))
          art.addChild(unadjustedState, e.getState());
        throw e;
      }
    }
    long endTime = System.currentTimeMillis();
    if (endTime - startTime > 0) {
      logger.info(
          "Processed "
              + statesVisited
              + " states at "
              + (1000L * statesVisited / (endTime - startTime))
              + " states/second");
      logger.info(
          String.format(
              "Allocated heap memory: %.2f MByte",
              (runtime.totalMemory() - runtime.freeMemory()) / (1024.0 * 1024.0)));
    }

    completed = worklist.isEmpty();
  }

  public void stop() {
    logger.fatal(Characters.starredBox("Interrupt! Stopping CPA Algorithm!"));
    stop = true;
  }
}
Exemplo n.º 18
0
/** @author Johannes Kinder */
public class SubstitutionElement implements AbstractValue {

  public static SubstitutionElement TOP = new SubstitutionElement(null);
  public static SubstitutionElement BOT = new SubstitutionElement(null);

  @SuppressWarnings("unused")
  private static final Logger logger = Logger.getLogger(SubstitutionElement.class);

  private final RTLExpression expression;

  public SubstitutionElement(RTLExpression e) {
    expression = e;
  }

  public RTLExpression getExpression() {
    return expression;
  }

  /*
   * @see org.jakstab.analysis.AbstractValue#concretize()
   */
  @Override
  public Set<RTLNumber> concretize() {
    if (expression instanceof RTLNumber) {
      return Collections.singleton((RTLNumber) expression);
    } else {
      // the "full" set
      return RTLNumber.ALL_NUMBERS;
    }
  }

  /*
   * @see
   * org.jakstab.analysis.AbstractValue#join(org.jakstab.analysis.LatticeElement
   * )
   */
  @Override
  public SubstitutionElement join(LatticeElement l) {
    if (l.isBot()) return this;
    SubstitutionElement other = (SubstitutionElement) l;
    if (this.isBot()) return other;
    if (expression.equals(other.getExpression())) return this;
    return TOP;
  }

  /*
   * @see org.jakstab.analysis.LatticeElement#isBot()
   */
  @Override
  public boolean isBot() {
    return this == BOT;
  }

  /*
   * @see org.jakstab.analysis.LatticeElement#isTop()
   */
  @Override
  public boolean isTop() {
    return this == TOP;
  }

  /*
   * @see
   * org.jakstab.analysis.LatticeElement#lessOrEqual(org.jakstab.analysis.
   * LatticeElement)
   */
  @Override
  public boolean lessOrEqual(LatticeElement l) {
    if (l.isTop() || this.isBot()) return true;
    if (isTop() || l.isBot()) return false;
    SubstitutionElement other = (SubstitutionElement) l;
    if (expression.equals(other.getExpression())) return true;
    return false;
  }

  @Override
  public String toString() {
    return expression.toString();
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((expression == null) ? 0 : expression.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null) return false;
    if (getClass() != obj.getClass()) return false;
    SubstitutionElement other = (SubstitutionElement) obj;
    if (expression == null) {
      if (other.expression != null) return false;
    } else if (!expression.equals(other.expression)) return false;
    return true;
  }

  @Override
  public boolean hasUniqueConcretization() {
    return (expression instanceof RTLNumber);
  }
}
Exemplo n.º 19
0
 public RawModule(File file, Architecture architecture) throws IOException {
   logger.info("Loading image as raw binary...");
   InputStream inStream = new FileInputStream(file);
   inBuf = new BinaryFileInputBuffer(inStream);
   baseAddress = new AbsoluteAddress(0x0);
 }
Exemplo n.º 20
0
/** @author Johannes Kinder */
public class RawModule implements ExecutableImage {

  @SuppressWarnings("unused")
  private static final Logger logger = Logger.getLogger(RawModule.class);

  private final BinaryFileInputBuffer inBuf;
  private final AbsoluteAddress baseAddress;
  private Disassembler disassembler;

  public RawModule(File file, Architecture architecture) throws IOException {
    logger.info("Loading image as raw binary...");
    InputStream inStream = new FileInputStream(file);
    inBuf = new BinaryFileInputBuffer(inStream);
    baseAddress = new AbsoluteAddress(0x0);
  }

  @Override
  public Disassembler getDisassembler() {
    if (disassembler == null) {
      disassembler = new X86Disassembler(inBuf);
    }
    return disassembler;
  }

  @Override
  public AbsoluteAddress getEntryPoint() {
    return baseAddress;
  }

  @Override
  public Set<ExportedSymbol> getExportedSymbols() {
    return Collections.emptySet();
  }

  @Override
  public long getFilePointer(AbsoluteAddress va) {
    return va.getValue() - baseAddress.getValue();
  }

  @Override
  public AbsoluteAddress getMaxAddress() {
    return new AbsoluteAddress(baseAddress.getValue() + inBuf.getSize());
  }

  @Override
  public AbsoluteAddress getMinAddress() {
    return baseAddress;
  }

  @Override
  public SymbolFinder getSymbolFinder() {
    return new DummySymbolFinder();
  }

  @Override
  public Set<UnresolvedSymbol> getUnresolvedSymbols() {
    return Collections.emptySet();
  }

  @Override
  public AbsoluteAddress getVirtualAddress(long fp) {
    return new AbsoluteAddress(baseAddress.getValue() + fp);
  }

  @Override
  public boolean isCodeArea(AbsoluteAddress va) {
    return true;
  }

  @Override
  public boolean isReadOnly(AbsoluteAddress a) {
    return false;
  }

  @Override
  public RTLNumber readMemoryLocation(RTLMemoryLocation m) {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public Iterator<AbsoluteAddress> codeBytesIterator() {
    throw new UnsupportedOperationException(
        "Code iteration not yet implemented for " + this.getClass().getSimpleName() + "!");
  }

  @Override
  public byte[] getByteArray() {
    return inBuf.getByteArray();
  }
}