-
Notifications
You must be signed in to change notification settings - Fork 150
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
928 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
|
||
=============== | ||
Binary Analysis | ||
=============== | ||
|
||
.. code-block:: cpp | ||
#include "BPatch.h" | ||
#include "BPatch_addressSpace.h" | ||
#include "BPatch_binaryEdit.h" | ||
#include "BPatch_flowGraph.h" | ||
#include "BPatch_function.h" | ||
#include "BPatch_process.h" | ||
#include <stdio.h> | ||
using namespace std; | ||
using namespace Dyninst; | ||
// Create an instance of class BPatch | ||
BPatch bpatch; | ||
// Different ways to perform instrumentation | ||
typedef enum { create, attach, open } accessType_t; | ||
BPatch_addressSpace *startInstrumenting(accessType_t accessType, | ||
const char *name, int pid, | ||
const char *argv[]) { | ||
BPatch_addressSpace *handle = NULL; | ||
switch (accessType) { | ||
case create: | ||
handle = bpatch.processCreate(name, argv); | ||
if (!handle) { | ||
fprintf(stderr, "processCreate failed\n"); | ||
} | ||
break; | ||
case attach: | ||
handle = bpatch.processAttach(name, pid); | ||
if (!handle) { | ||
fprintf(stderr, "processAttach failed\n"); | ||
} | ||
break; | ||
case open: | ||
// Open the binary file and all dependencies | ||
handle = bpatch.openBinary(name, true); | ||
if (!handle) { | ||
fprintf(stderr, "openBinary failed\n"); | ||
} | ||
break; | ||
} | ||
return handle; | ||
} | ||
int binaryAnalysis(BPatch_addressSpace *app) { | ||
BPatch_image *appImage = app->getImage(); | ||
int insns_access_memory = 0; | ||
std::vector<BPatch_function *> functions; | ||
appImage->findFunction("InterestingProcedure", functions); | ||
if (functions.size() == 0) { | ||
fprintf(stderr, "No function InterestingProcedure\n"); | ||
return insns_access_memory; | ||
} else if (functions.size() > 1) { | ||
fprintf(stderr, "More than one InterestingProcedure; using the first one\n"); | ||
} | ||
BPatch_flowGraph *fg = functions[0]->getCFG(); | ||
std::set<BPatch_basicBlock *> blocks; | ||
fg->getAllBasicBlocks(blocks); | ||
for (auto block_iter = blocks.begin(); block_iter != blocks.end(); ++block_iter) { | ||
BPatch_basicBlock *block = *block_iter; | ||
std::vector<InstructionAPI::Instruction::Ptr> insns; | ||
block->getInstructions(insns); | ||
for (auto insn_iter = insns.begin(); insn_iter != insns.end(); ++insn_iter) { | ||
InstructionAPI::Instruction::Ptr insn = *insn_iter; | ||
if (insn->readsMemory() }} insn->writesMemory()) { | ||
insns_access_memory++; | ||
} | ||
} | ||
} | ||
return insns_access_memory; | ||
} | ||
int main() { | ||
// Set up information about the program to be instrumented | ||
const char *progName = "InterestingProgram"; | ||
int progPID = 42; | ||
const char *progArgv[] = {"InterestingProgram", "-h", NULL}; | ||
accessType_t mode = create; | ||
// Create/attach/open a binary | ||
BPatch_addressSpace *app = startInstrumenting(mode, progName, progPID, progArgv); | ||
if (!app) { | ||
fprintf(stderr, "startInstrumenting failed\n"); | ||
exit(1); | ||
} | ||
int memAccesses = binaryAnalysis(app); | ||
fprintf(stderr, "Found %d memory accesses\n", memAccesses); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
============================ | ||
Control flow graph traversal | ||
============================ | ||
|
||
The following complete example uses the ParseAPI to parse a binary and | ||
dump its control flow graph in the Graphviz file format. As an example, | ||
it can be built with G++ as follows: | ||
``g++ -std=c++0x -o example example.cc -L<library install path> -I<headers install path> -lparseAPI -linstructionAPI -lsymtabAPI -lsymLite -ldynDwarf -ldynElf -lcommon -L<libelf path> -lelf -L<libdwarf path> -ldwarf``. | ||
Note: this example must be compiled with C++11x support; for G++ this is | ||
enabled with ``-std=c++0x``, and it is on by default for Visual Studio. | ||
|
||
.. code-block:: cpp | ||
// Example ParseAPI program; produces a graph (in DOT format) of the | ||
// control flow graph of the provided binary. | ||
// | ||
// Improvements by E. Robbins (er209 at kent dot ac dot uk) | ||
// | ||
#include <stdio.h> | ||
#include <map> | ||
#include <vector> | ||
#include <unordered_map> | ||
#include <sstream> | ||
#include "CodeObject.h" | ||
#include "CFG.h" | ||
using namespace std; | ||
using namespace Dyninst; | ||
using namespace ParseAPI; | ||
int main(int argc, char * argv[]) | ||
{ | ||
map<Address, bool> seen; | ||
vector<Function *> funcs; | ||
SymtabCodeSource *sts; | ||
CodeObject *co; | ||
// Create a new binary code object from the filename argument | ||
sts = new SymtabCodeSource( argv[1] ); | ||
co = new CodeObject( sts ); | ||
// Parse the binary | ||
co->parse(); | ||
cout << "digraph G {" << endl; | ||
// Print the control flow graph | ||
const CodeObject::funclist& all = co->funcs(); | ||
auto fit = all.begin(); | ||
for(int i = 0; fit != all.end(); ++fit, i++) { // i is index for clusters | ||
Function *f = *fit; | ||
// Make a cluster for nodes of this function | ||
cout << "\t subgraph cluster_" << i | ||
<< " { \n\t\t label=\"" | ||
<< f->name() | ||
<< "\"; \n\t\t color=blue;" << endl; | ||
cout << "\t\t\"" << hex << f->addr() << dec | ||
<< "\" [shape=box"; | ||
if (f->retstatus() == NORETURN) | ||
cout << ",color=red"; | ||
cout << "]" << endl; | ||
// Label functions by name | ||
cout << "\t\t\"" << hex << f->addr() << dec | ||
<< "\" [label = \"" | ||
<< f->name() << "\\n" << hex << f->addr() << dec | ||
<< "\"];" << endl; | ||
stringstream edgeoutput; | ||
auto bit = f->blocks().begin(); | ||
for( ; bit != f->blocks().end(); ++bit) { | ||
Block *b = *bit; | ||
// Don't revisit blocks in shared code | ||
if(seen.find(b->start()) != seen.end()) | ||
continue; | ||
seen[b->start()] = true; | ||
cout << "\t\t\"" << hex << b->start() << dec << | ||
"\";" << endl; | ||
auto it = b->targets().begin(); | ||
for( ; it != b->targets().end(); ++it) { | ||
if(!*it) continue; | ||
std::string s = ""; | ||
if((*it)->type() == CALL) | ||
s = " [color=blue]"; | ||
else if((*it)->type() == RET) | ||
s = " [color=green]"; | ||
// Store the edges somewhere to be printed outside of the cluster | ||
edgeoutput << "\t\"" | ||
<< hex << (*it)->src()->start() | ||
<< "\" -> \"" | ||
<< (*it)->trg()->start() | ||
<< "\"" << s << endl; | ||
} | ||
} | ||
// End cluster | ||
cout << "\t}" << endl; | ||
// Print edges | ||
cout << edgeoutput.str() << endl; | ||
} | ||
cout << "}" << endl; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
|
||
==================== | ||
Function Disassembly | ||
==================== | ||
|
||
The following example uses ParseAPI and InstructionAPI to disassemble | ||
the basic blocks in a function. As an example, it can be built with G++ | ||
as follows: | ||
``g++ -std=c++0x -o code_sample code_sample.cc -L<library install path> -I<headers install path> -lparseAPI -linstructionAPI -lsymtabAPI -lsymLite -ldynDwarf -ldynElf -lcommon -L<libelf path> -lelf -L<libdwarf path> -ldwarf``. | ||
Note: this example must be compiled with C++11x support; for G++ this is | ||
enabled with ``-std=c++0x``, and it is on by default for Visual Studio. | ||
|
||
.. code-block:: cpp | ||
/* | ||
Copyright (C) 2015 Alin Mindroc | ||
(mindroc dot alin at gmail dot com) | ||
This is a sample program that shows how to use InstructionAPI in order to | ||
6 print the assembly code and functions in a provided binary. | ||
This program is free software; you can redistribute it and/or | ||
modify it under the terms of the GNU Lesser General Public | ||
11 License as published by the Free Software Foundation; either | ||
version 2.1 of the License, or (at your option) any later version. | ||
*/ | ||
#include <iostream> | ||
#include "CodeObject.h" | ||
#include "InstructionDecoder.h" | ||
using namespace std; | ||
using namespace Dyninst; | ||
using namespace ParseAPI; | ||
using namespace InstructionAPI; | ||
int main(int argc, char **argv){ | ||
if(argc != 2){ | ||
printf("Usage: %s <binary path>\n", argv[0]); | ||
return -1; | ||
} | ||
char *binaryPath = argv[1]; | ||
SymtabCodeSource *sts; | ||
CodeObject *co; | ||
Instruction::Ptr instr; | ||
SymtabAPI::Symtab *symTab; | ||
std::string binaryPathStr(binaryPath); | ||
bool isParsable = SymtabAPI::Symtab::openFile(symTab, binaryPathStr); | ||
if(isParsable == false){ | ||
const char *error = "error: file can not be parsed"; | ||
cout << error; | ||
return - 1; | ||
} | ||
sts = new SymtabCodeSource(binaryPath); | ||
co = new CodeObject(sts); | ||
//parse the binary given as a command line arg | ||
co->parse(); | ||
//get list of all functions in the binary | ||
const CodeObject::funclist &all = co->funcs(); | ||
if(all.size() == 0){ | ||
const char *error = "error: no functions in file"; | ||
cout << error; | ||
return - 1; | ||
} | ||
auto fit = all.begin(); | ||
Function *f = *fit; | ||
//create an Instruction decoder which will convert the binary opcodes to strings | ||
InstructionDecoder decoder(f->isrc()->getPtrToInstruction(f->addr()), | ||
InstructionDecoder::maxInstructionLength, | ||
f->region()->getArch()); | ||
for(;fit != all.end(); ++fit){ | ||
Function *f = *fit; | ||
//get address of entry point for current function | ||
Address crtAddr = f->addr(); | ||
int instr_count = 0; | ||
instr = decoder.decode((unsigned char *)f->isrc()->getPtrToInstruction(crtAddr)); | ||
auto fbl = f->blocks().end(); | ||
fbl--; | ||
Block *b = *fbl; | ||
Address lastAddr = b->last(); | ||
//if current function has zero instructions, don’t output it | ||
if(crtAddr == lastAddr) | ||
continue; | ||
cout << "\n\n\"" << f->name() << "\" :"; | ||
while(crtAddr < lastAddr){ | ||
//decode current instruction | ||
instr = decoder.decode((unsigned char *)f->isrc()->getPtrToInstruction(crtAddr)); | ||
cout << "\n" << hex << crtAddr; | ||
cout << ": \"" << instr->format() << "\""; | ||
//go to the address of the next instruction | ||
crtAddr += instr->size(); | ||
instr_count++; | ||
} | ||
} | ||
return 0; | ||
} |
Oops, something went wrong.