use of com.google.security.zynamics.binnavi.API.disassembly.FunctionBlock in project binnavi by google.
the class PathFinder method connectFunctions.
/**
* Connects the functions in the view using inlining edges.
*
* @param view The view where the edges are created.
* @param startNode The start node of the path.
* @param targetNode The target node of the path.
* @param passedFunctions All functions that lie on the path.
* @param entryNodes Keeps track of the entry nodes of all functions.
* @param exitNodes Keeps track of the exit nodes of all functions.
* @param functionMap Keeps track to what function a node belongs to.
*
* @return Node pair that contains the updated start node and target node.
*/
private static NodePair connectFunctions(final View view, final ViewNode startNode, final ViewNode targetNode, final Collection<FunctionBlock> passedFunctions, final Map<Function, ViewNode> entryNodes, final ArrayListMultimap<Function, ViewNode> exitNodes, final Map<ViewNode, Function> functionMap) {
ViewNode realStartNode = startNode;
ViewNode realTargetNode = targetNode;
final Set<ViewNode> handled = new HashSet<ViewNode>();
while (true) {
boolean splitNode = false;
start: for (final ViewNode node : view.getGraph().getNodes()) {
if (handled.contains(node)) {
continue;
}
if (!(node instanceof CodeNode)) {
continue;
}
final CodeNode cnode = (CodeNode) node;
for (final Instruction instruction : cnode.getInstructions()) {
for (final FunctionBlock functionBlock : passedFunctions) {
final Function function = functionBlock.getFunction();
if (callsFunction(instruction, function)) {
// A function call to a function on the path was found.
// At this point we have to split the code node after
// the function call.
final NodePair result = splitBlock(view, functionMap.get(cnode), cnode, instruction);
if (realStartNode == cnode) {
// Of course it is possible that the start node was split,
// therefore we have to update the start node to the upper
// part of the new node.
realStartNode = result.getFirst();
}
if (realTargetNode == cnode) {
// Of course it is possible that the target node was split,
// therefore we have to update the target node to the upper
// part of the new node.
realTargetNode = result.getFirst();
}
// too.
for (final FunctionBlock functionBlock2 : passedFunctions) {
final Function function2 = functionBlock2.getFunction();
if (entryNodes.get(function2) == cnode) {
// Update the entry nodes
entryNodes.put(function2, result.getFirst());
}
if (exitNodes.get(function2).contains(cnode)) {
// Update the exit nodes
if (result.getSecond() != null) {
exitNodes.remove(function2, cnode);
exitNodes.put(function2, result.getSecond());
}
}
}
if (functionMap.containsKey(cnode)) {
final Function f = functionMap.get(cnode);
functionMap.remove(cnode);
functionMap.put(result.getFirst(), f);
}
handled.add(result.getFirst());
if (result.getSecond() == null) {
for (final ViewEdge edge : node.getOutgoingEdges()) {
for (final ViewNode currentExitNode : exitNodes.get(function)) {
final ViewEdge leaveEdge = view.createEdge(currentExitNode, edge.getTarget(), EdgeType.LeaveInlinedFunction);
leaveEdge.setColor(DEFAULT_INLINING_EDGE_COLOR);
}
view.deleteEdge(edge);
}
final ViewEdge enterEdge = view.createEdge(result.getFirst(), entryNodes.get(function), EdgeType.EnterInlinedFunction);
enterEdge.setColor(DEFAULT_INLINING_EDGE_COLOR);
handled.add(cnode);
} else {
// The node was split. We simply have to connect both split parts to the
// called function.
final ViewEdge enterEdge = view.createEdge(result.getFirst(), entryNodes.get(function), EdgeType.EnterInlinedFunction);
enterEdge.setColor(DEFAULT_INLINING_EDGE_COLOR);
for (final ViewNode currentExitNode : exitNodes.get(function)) {
final ViewEdge leaveEdge = view.createEdge(currentExitNode, result.getSecond(), EdgeType.LeaveInlinedFunction);
leaveEdge.setColor(DEFAULT_INLINING_EDGE_COLOR);
}
}
splitNode = true;
break start;
}
}
}
handled.add(cnode);
}
if (!splitNode) {
break;
}
}
return new NodePair(realStartNode, realTargetNode);
}
use of com.google.security.zynamics.binnavi.API.disassembly.FunctionBlock in project binnavi by google.
the class PathFinder method createInitialEdges.
/**
* Creates view edges for all edges in the passed functions.
*
* @param view The view where the edges are created.
* @param passedFunctions All functions that lie on the path.
* @param nodeMap Maps between the basic blocks of the functions and their corresponding code
* nodes.
*/
private static void createInitialEdges(final View view, final Collection<FunctionBlock> passedFunctions, final Map<BasicBlock, ViewNode> nodeMap) {
for (final FunctionBlock functionBlock : passedFunctions) {
final Function function = functionBlock.getFunction();
for (final BlockEdge edge : function.getGraph().getEdges()) {
final ViewEdge newEdge = view.createEdge(nodeMap.get(edge.getSource()), nodeMap.get(edge.getTarget()), edge.getType());
newEdge.setColor(getEdgeColor(edge));
}
}
}
use of com.google.security.zynamics.binnavi.API.disassembly.FunctionBlock in project binnavi by google.
the class PathFinder method createPath.
/**
* Creates a view that shows all possible paths between two blocks of a module.
*
* @param module The module for which the view is created.
* @param startBlock The basic block where the path begins (must be null if startFunction is not
* null).
* @param targetBlock The basic block where the path ends (must be null if targetFunction is not
* null).
* @param startFunction The function where the path starts (must be null if startBlock is not
* null).
* @param targetFunction The function where the path ends (must be null if targetBlock is not
* null).
*
* @return The view that contains all possible paths between the start block and the target block.
*
* @throws CouldntLoadDataException
* @throws PartialLoadException
* @throws IllegalArgumentException
*/
public static View createPath(final Module module, final BasicBlock startBlock, final BasicBlock targetBlock, final Function startFunction, final Function targetFunction) throws CouldntLoadDataException, PartialLoadException {
Preconditions.checkNotNull(module, "Error: Module argument can't be null");
Preconditions.checkArgument(module.isLoaded(), "Error: Module is not loaded");
if ((startBlock == null) && (startFunction == null)) {
throw new IllegalArgumentException("Error: No valid start given");
}
if ((targetBlock == null) && (targetFunction == null)) {
throw new IllegalArgumentException("Error: No valid target given");
}
if ((startFunction != null) && !startFunction.isLoaded()) {
throw new IllegalArgumentException("Error: Start function is not loaded");
}
if ((targetFunction != null) && !targetFunction.isLoaded()) {
throw new IllegalArgumentException("Error: Target function is not loaded");
}
// The algorithm works like this:
//
// 1. Find all functions that lie between the start function and the target function.
// 2. Insert all of these functions into the new view.
// 3. Connect the individual functions at function calls and split code nodes if necessary.
// 4. Determine what nodes are actually on the path by taking the successors of the start
// node and set-unioning those with the predecessors of the target node.
// 5. Delete all the nodes which are not on the path.
// At first we determine the function where the path starts and the function where the path
// ends.
final Function realStartFunction = startFunction != null ? startFunction : startBlock.getParentFunction();
final Function realTargetFunction = targetFunction != null ? targetFunction : targetBlock.getParentFunction();
if (realStartFunction.getGraph().nodeCount() == 0) {
throw new IllegalArgumentException("Error: Functions with zero nodes can not be used for pathfinding");
}
// Determine the real start and end blocks of the path with the help of the function flow graphs
final BasicBlock realStartBlock = startBlock != null ? startBlock : findEntryNode(realStartFunction);
final BasicBlock realTargetBlock = targetBlock != null ? targetBlock : findEntryNode(realTargetFunction);
// Find out what functions are called on the way between the first block and the second block.
final LinkedHashSet<FunctionBlock> passedFunctions = findPassedFunctions(module.getCallgraph(), realStartFunction, realTargetFunction);
// Create the view that represents the calculated path
final String endAddress = realTargetBlock != null ? realTargetBlock.getAddress().toHexString() : realTargetFunction.getAddress().toHexString();
final View view = module.createView("New Pathfinder View", String.format("%s -> %s", realStartBlock.getAddress().toHexString(), endAddress));
view.load();
// Maps basic blocks of functions to their corresponding node in the new view.
final Map<BasicBlock, ViewNode> nodeMap = new HashMap<BasicBlock, ViewNode>();
// Keeps track of the entry nodes for each function,
final Map<Function, ViewNode> entryNodes = new HashMap<Function, ViewNode>();
// Keeps track of the exit nodes for each function,
final ArrayListMultimap<Function, ViewNode> exitNodes = ArrayListMultimap.create();
// Keeps track of the function a view node belongs to.
// TODO (timkornau): This should actually be accessible from the plug in API.
final Map<ViewNode, Function> functionMap = new HashMap<ViewNode, Function>();
// Create a code node for all basic blocks of the passed functions.
createInitialBlocks(view, passedFunctions, nodeMap, functionMap);
// Create view edges for all edges in the passed functions.
createInitialEdges(view, passedFunctions, nodeMap);
// Find the entry and exit nodes for all passed functions.
findEntryExitNodes(passedFunctions, nodeMap, functionMap, entryNodes, exitNodes);
ViewNode startNode = nodeMap.get(realStartBlock);
ViewNode targetNode = realTargetBlock == null ? entryNodes.get(realTargetFunction) : nodeMap.get(realTargetBlock);
startNode.setColor(Color.GREEN);
targetNode.setColor(Color.YELLOW);
// Connect the nodes of the different functions on function calls.
final NodePair splitResult = connectFunctions(view, startNode, targetNode, passedFunctions, entryNodes, exitNodes, functionMap);
startNode = splitResult.getFirst();
targetNode = splitResult.getSecond();
// all paths end here.
for (final ViewEdge edge : targetNode.getOutgoingEdges()) {
view.deleteEdge(edge);
}
// Delete all nodes that are not on the path.
deleteNodesNotOnPath(view, startNode, targetNode);
if (startNode.getOutgoingEdges().isEmpty()) {
// no path exists between the two nodes
return null;
}
try {
view.save();
} catch (final CouldntSaveDataException exception) {
CUtilityFunctions.logException(exception);
}
return view;
}
use of com.google.security.zynamics.binnavi.API.disassembly.FunctionBlock in project binnavi by google.
the class PathFinder method findEntryExitNodes.
/**
* Finds the entry nodes and exit nodes of all functions that lie on the path. This is necessary
* for function inlining.
*
* @param passedFunctions All functions that lie on the path.
* @param nodeMap Maps between the basic blocks of the functions and their corresponding code
* nodes.
* @param functionMap Keeps track to what function a view node belongs to.
* @param entryNodes Keeps track of the entry nodes of all functions.
* @param exitNodes Keeps track of the exit nodes of all functions.
*/
private static void findEntryExitNodes(final Collection<FunctionBlock> passedFunctions, final Map<BasicBlock, ViewNode> nodeMap, final Map<ViewNode, Function> functionMap, final Map<Function, ViewNode> entryNodes, final ArrayListMultimap<Function, ViewNode> exitNodes) {
// actually do have basic blocks.
for (final FunctionBlock functionBlock : passedFunctions) {
final Function function = functionBlock.getFunction();
if (function.getType() != FunctionType.Import) {
entryNodes.put(function, nodeMap.get(findEntryNode(function)));
for (final BasicBlock block : findExitNode(function.getGraph())) {
exitNodes.put(function, nodeMap.get(block));
}
}
}
// Afterwards we find the entry and exit nodes of the imported functions.
for (final Map.Entry<ViewNode, Function> p : functionMap.entrySet()) {
final Function function = p.getValue();
if (function.getType() == FunctionType.Import) {
final ViewNode node = p.getKey();
entryNodes.put(function, node);
exitNodes.put(function, node);
}
}
}
use of com.google.security.zynamics.binnavi.API.disassembly.FunctionBlock in project binnavi by google.
the class PathFinder method createInitialBlocks.
/**
* Creates the initial nodes for all basic blocks in the passed functions.
*
* @param view The view where the nodes are created.
*
* @param passedFunctions All functions that lie on the path.
* @param nodeMap Maps basic blocks of the functions on the path to their corresponding view
* nodes.
* @param functionMap Keeps track to what function a node belongs to.
*
* @throws CouldntLoadDataException Thrown if a function could not be loaded.
*/
private static void createInitialBlocks(final View view, final Collection<FunctionBlock> passedFunctions, final Map<BasicBlock, ViewNode> nodeMap, final Map<ViewNode, Function> functionMap) throws CouldntLoadDataException {
for (final FunctionBlock functionBlock : passedFunctions) {
final Function function = functionBlock.getFunction();
if (function.getType() == FunctionType.Import) {
// Imported functions to not have any basic blocks, for those functions
// we simply create a function node.
final FunctionNode newNode = view.createFunctionNode(function);
functionMap.put(newNode, function);
// TODO (timkornau): Assign a proper color to the node.
// TODO (timkornau): Properly treat forwarded functions.
} else {
function.load();
for (final BasicBlock block : function.getGraph().getNodes()) {
final CodeNode newNode = view.createCodeNode(function, block.getInstructions());
newNode.setColor(DEFAULT_BLOCK_COLOR);
nodeMap.put(block, newNode);
functionMap.put(newNode, function);
}
}
}
}
Aggregations