Skip to content

Commit

Permalink
A LLIL C++ API Parser example with in depth build notes (#721)
Browse files Browse the repository at this point in the history
* make cmake file more generic and fix missing sources

* add llil cpp example

* added image

* fix string stream under linux

* fix path under linux

* Update build notes for linux

* analysis sync | mac os path | lill* usage change

* added path note and removed comment about mac path

* use UpdateAnalysisAndWait()
  • Loading branch information
robert-yates authored and plafosse committed Jul 16, 2017
1 parent c7e1874 commit cc3755b
Show file tree
Hide file tree
Showing 5 changed files with 730 additions and 35 deletions.
38 changes: 3 additions & 35 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,9 @@ cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)

project(binaryninja-api)

add_library(binaryninjaapi STATIC
architecture.cpp
backgroundtask.cpp
basicblock.cpp
binaryninjaapi.cpp
binaryreader.cpp
binaryview.cpp
binaryviewtype.cpp
binarywriter.cpp
callingconvention.cpp
databuffer.cpp
demangle.cpp
fileaccessor.cpp
filemetadata.cpp
function.cpp
functiongraph.cpp
functiongraphblock.cpp
functionrecognizer.cpp
interaction.cpp
json/jsoncpp.cpp
log.cpp
lowlevelil.cpp
mainthread.cpp
mediumlevelil.cpp
metadata.cpp
platform.cpp
plugin.cpp
pluginmanager.cpp
scriptingprovider.cpp
settings.cpp
tempfile.cpp
transform.cpp
type.cpp
update.cpp
)
file( GLOB SRCS *.cpp json/json.h json/jsoncpp.cpp json/json-forwards.h)

add_library(binaryninjaapi STATIC ${SRCS})

set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin)

Expand Down
51 changes: 51 additions & 0 deletions examples/llil_parser/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Mostly copied from https://github.com/Vector35/binaryninja-api/blob/dev/examples/breakpoint/CMakeLists.txt

CMAKE_MINIMUM_REQUIRED(VERSION 2.6)

project(LLIL_Parser)

#-----------------------------------------------------------------------------
include_directories("inc/")
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../..)
#-----------------------------------------------------------------------------
file( GLOB_RECURSE SRCS *.cpp *.h)
#-----------------------------------------------------------------------------
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
#-----------------------------------------------------------------------------
if(WIN32)
set(BINJA_DIR "C:\\Program Files\\Vector35\\BinaryNinja"
CACHE PATH "Binary Ninja installation directory")
set(BINJA_BIN_DIR "${BINJA_DIR}")
set(BINJA_PLUGINS_DIR "$ENV{APPDATA}/Binary Ninja/plugins"
CACHE PATH "Binary Ninja user plugins directory")
elseif(APPLE)
set(BINJA_DIR "/Applications/Binary Ninja.app"
CACHE PATH "Binary Ninja installation directory")
set(BINJA_BIN_DIR "${BINJA_DIR}/Contents/MacOS")
set(BINJA_PLUGINS_DIR "$ENV{HOME}/Library/Application Support/Binary Ninja/plugins"
CACHE PATH "Binary Ninja user plugins directory")
else()
set(BINJA_DIR "$ENV{HOME}/binaryninja"
CACHE PATH "Binary Ninja installation directory")
set(BINJA_BIN_DIR "${BINJA_DIR}")
set(BINJA_PLUGINS_DIR "$ENV{HOME}/.binaryninja/plugins"
CACHE PATH "Binary Ninja user plugins directory")
endif()
#-----------------------------------------------------------------------------
add_executable (${PROJECT_NAME} ${SRCS} )
#-----------------------------------------------------------------------------
find_library(BINJA_API_LIBRARY binaryninjaapi
HINTS ${CMAKE_CURRENT_SOURCE_DIR}/../../bin ${CMAKE_CURRENT_SOURCE_DIR}/../../bin/Release ${CMAKE_CURRENT_SOURCE_DIR}/../../bin/Debug)
find_library(BINJA_CORE_LIBRARY binaryninjacore
HINTS ${BINJA_BIN_DIR})
#-----------------------------------------------------------------------------
target_link_libraries(${PROJECT_NAME}
${BINJA_API_LIBRARY}
${BINJA_CORE_LIBRARY}
)
#-----------------------------------------------------------------------------
install (TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION bin
LIBRARY DESTINATION Lib
ARCHIVE DESTINATION Lib)

63 changes: 63 additions & 0 deletions examples/llil_parser/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
LLIL Parser - Binary Ninja C++ API Sample
===

> Robert Yates | 22nd June 2017
LLIL Parser is a simple example for demonstrating how to use the BinaryNinja C++ API

![ScreenShot](https://user-images.githubusercontent.com/1876966/27665067-58d34dd0-5c6b-11e7-9361-6efd01cfa0af.JPG)

Example of building under windows from scratch
===

* https://cmake.org/ Required for this example
* We will be using Visual Studio 2017 however if want to use a different version simply run the `cmake -G` command to find the alternative name to use in the cmake commands below, be sure to use the Win64 version.

Note: if you havent installed binary ninja into a default location then you will need to edit the cmake file and also the `std::string get_plugins_directory()` function in the `.cpp` file

# Building the BinaryNinja API
```
git clone https://github.com/Vector35/binaryninja-api.git
cd binaryninja
mkdir _build
cd _build
cmake .. -G "Visual Studio 15 2017 Win64"
cmake --build . --config Release
```

The objective here is to build the `binaryninjaapi.lib` This will be placed in the `bin` folder

# Building the C++ Example

```
cd ../examples
mkdir _build
cd _build
cmake ../llil_parser -G "Visual Studio 15 2017 Win64"
cmake --build . --config Release
cd Release
copy "c:\Program Files\Vector35\BinaryNinja\binaryninjacore.dll" .
```

If you get an error about `BINJA_API_LIBRARY` check the API has built properly and `binaryninjaapi.lib` is located in the `bin` folder in the root folder of the API

If you get an error about `BINJA_CORE_LIBRARY` then the file C:\Program Files\Vector35\BinaryNinja\binaryninjacore.lib is missing see [Create .lib file from .dll](https://adrianhenke.wordpress.com/2008/12/05/create-lib-file-from-dll/) on details about how to create this lib file from the dll file located in that directory

> Building under the linux is almost exactly the same however you need not use the `-G` parameter and you build with the `make` command instead of `cmake --build` another important note is that i had to execute `cp ~/binaryninja/libbinaryninjacore.so.1 ~/binaryninja/libbinaryninjacore.so` before linking would work
Note i do not have access to a MAC so i havent tested this.

Using the example
===

Simply run the compiled executable with a target binary as a parameter and it will parse the LLIL from the first detected function in the target binary.

The `void LlilParser::analysisInstruction(const BNLowLevelILInstruction& insn)` function is probably the most
function of interest for learning.

This example is only intended for learning from the source code however if you wish to turn it into something more useful then you could add callbacks in the analysis function to keep track of when certain regs, values occur etc.

# Disclaimer

This was mostly figured out by myself and may not be the best way to achieve the intended desire, however i hope it serves as a starting point

171 changes: 171 additions & 0 deletions examples/llil_parser/inc/LowLevel_IL_Parser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#ifndef __LOWLEVEL_IL_PARSER_H_
#define __LOWLEVEL_IL_PARSER_H_

#include "binaryninjacore.h"
#include "binaryninjaapi.h"
#include <map>

std::string get_plugins_directory();
void ShowBanner();

using namespace BinaryNinja;

enum OperandPurpose
{
kDest,
kSrc,
kConstant,
kLeft,
kRight,
kHi,
kLow,
kTargets,
kCondition,
kVector,
kOutput,
kStack,
kParam,
kDestMemory,
kSrcMemory,
kTrue,
kFalse,
kBit,
kCarry,
kFullReg,
};

enum OperandType
{
kReg,
kExpr,
kFlag,
kIntList,
kInt,
kRegSsa,
kRegSsaList,
kFlagSsa,
kCond,
kFlagSsaList,
};

struct BNLowLevelILOperationSyntax
{
OperandPurpose purpose;
OperandType type;
};


static std::map<BNLowLevelILOperation, std::vector<BNLowLevelILOperationSyntax>> g_llilSyntaxMap = { \
{ LLIL_NOP,{} }, \
{ LLIL_SET_REG,{ { kDest, kReg },{ kSrc,kExpr } } }, \
{ LLIL_SET_REG_SPLIT,{ { kHi, kReg },{ kLow,kReg },{ kSrc,kExpr } } } , \
{ LLIL_SET_FLAG,{ { kDest, kFlag },{ kSrc,kExpr } } }, \
{ LLIL_LOAD,{ { kSrc, kExpr } } }, \
{ LLIL_STORE,{ { kDest, kExpr },{ kSrc,kExpr } } }, \
{ LLIL_PUSH,{ { kSrc, kExpr } } }, \
{ LLIL_POP,{} }, \
{ LLIL_REG,{ { kSrc, kReg } } }, \
{ LLIL_CONST,{ { kConstant, kInt } } }, \
{ LLIL_CONST_PTR,{ { kConstant, kInt } } }, \
{ LLIL_FLAG,{ { kSrc, kFlag } } }, \
{ LLIL_FLAG_BIT,{ { kSrc, kFlag },{ kBit,kInt } } }, \
{ LLIL_ADD,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_ADC,{ { kLeft, kExpr },{ kRight,kExpr },{ kCarry,kExpr } } }, \
{ LLIL_SUB,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_SBB,{ { kLeft, kExpr },{ kRight,kExpr },{ kCarry,kExpr } } }, \
{ LLIL_AND,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_OR,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_XOR,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_LSL,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_LSR,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_ASR,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_ROL,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_RLC,{ { kLeft, kExpr },{ kRight,kExpr },{ kCarry,kExpr } } }, \
{ LLIL_ROR,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_RRC,{ { kLeft, kExpr },{ kRight,kExpr },{ kCarry,kExpr } } }, \
{ LLIL_MUL,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_MULU_DP,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_MULS_DP,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_DIVU,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_DIVU_DP,{ { kHi, kExpr },{ kLow,kExpr },{ kRight,kExpr } } }, \
{ LLIL_DIVS,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_DIVS_DP,{ { kHi, kExpr },{ kLow,kExpr },{ kRight,kExpr } } }, \
{ LLIL_MODU,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_MODU_DP,{ { kHi, kExpr },{ kLow,kExpr },{ kRight,kExpr } } }, \
{ LLIL_MODS,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_MODS_DP,{ { kHi, kExpr },{ kLow,kExpr },{ kRight,kExpr } } }, \
{ LLIL_NEG,{ { kSrc, kExpr } } }, \
{ LLIL_NOT,{ { kSrc, kExpr } } }, \
{ LLIL_SX,{ { kSrc, kExpr } } }, \
{ LLIL_ZX,{ { kSrc, kExpr } } }, \
{ LLIL_LOW_PART,{ { kSrc, kExpr } } }, \
{ LLIL_JUMP,{ { kDest, kExpr } } }, \
{ LLIL_JUMP_TO,{ { kDest, kExpr },{ kTargets,kIntList } } }, \
{ LLIL_CALL,{ { kDest, kExpr } } }, \
{ LLIL_RET,{ { kDest, kExpr } } }, \
{ LLIL_NORET,{} }, \
{ LLIL_IF,{ { kCondition, kExpr },{ kTrue,kInt },{ kFalse,kInt } } }, \
{ LLIL_GOTO,{ { kDest, kInt } } }, \
{ LLIL_FLAG_COND,{ { kCondition, kCond } } }, \
{ LLIL_CMP_E,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_CMP_NE,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_CMP_SLT,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_CMP_ULT,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_CMP_SLE,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_CMP_ULE,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_CMP_SGE,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_CMP_UGE,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_CMP_SGT,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_CMP_UGT,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_TEST_BIT,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_BOOL_TO_INT,{ { kSrc, kExpr } } }, \
{ LLIL_ADD_OVERFLOW,{ { kLeft, kExpr },{ kRight,kExpr } } }, \
{ LLIL_SYSCALL,{} }, \
{ LLIL_BP,{} }, \
{ LLIL_TRAP,{ { kVector, kInt } } }, \
{ LLIL_UNDEF,{} }, \
{ LLIL_UNIMPL,{} }, \
{ LLIL_UNIMPL_MEM,{ { kSrc, kExpr } } }, \
{ LLIL_SET_REG_SSA,{ { kDest, kRegSsa },{ kSrc,kExpr } } }, \
{ LLIL_IF,{ { kFullReg, kRegSsa },{ kDest,kReg },{ kSrc,kExpr } } }, \
{ LLIL_SET_REG_SPLIT_SSA,{ { kHi, kExpr },{ kLow,kExpr },{ kSrc,kExpr } } }, \
{ LLIL_REG_SPLIT_DEST_SSA,{ { kDest, kRegSsa } } }, \
{ LLIL_REG_SSA,{ { kSrc, kRegSsa } } }, \
{ LLIL_REG_SSA_PARTIAL,{ { kFullReg, kRegSsa },{ kSrc,kReg } } }, \
{ LLIL_SET_FLAG_SSA,{ { kDest, kFlagSsa },{ kSrc,kExpr } } }, \
{ LLIL_FLAG_SSA,{ { kSrc, kFlagSsa } } }, \
{ LLIL_FLAG_BIT_SSA,{ { kSrc, kFlagSsa },{ kBit, kInt } } }, \
{ LLIL_CALL_SSA,{ { kOutput, kExpr },{ kDest,kExpr },{ kStack,kExpr },{ kParam,kExpr } } }, \
{ LLIL_SYSCALL_SSA,{ { kOutput, kExpr },{ kStack,kExpr },{ kParam,kExpr } } }, \
{ LLIL_CALL_OUTPUT_SSA,{ { kDestMemory, kInt },{ kDest, kRegSsaList } } }, \
{ LLIL_CALL_STACK_SSA,{ { kSrc, kRegSsa },{ kSrcMemory, kInt } } }, \
{ LLIL_CALL_PARAM_SSA,{ { kSrc, kRegSsaList } } }, \
{ LLIL_LOAD_SSA,{ { kSrc, kExpr },{ kSrcMemory, kInt } } }, \
{ LLIL_STORE_SSA,{ { kDest, kExpr },{ kDestMemory,kInt },{ kSrcMemory,kInt },{ kSrc,kExpr } } }, \
{ LLIL_REG_PHI,{ { kDest, kRegSsa },{ kSrc, kRegSsaList } } }, \
{ LLIL_FLAG_PHI,{ { kDest, kFlagSsa },{ kSrc, kFlagSsaList } } }, \
{ LLIL_MEM_PHI,{ { kDestMemory, kInt },{ kSrcMemory, kIntList } } }, \
};


class LlilParser
{

public:
LlilParser(BinaryView *bv);
const std::string getLowLevelILOperationName(const BNLowLevelILOperation id) const;
void decodeIndexInFunction(uint64_t functionAddress, int indexIl);
void decodeWholeFunction(uint64_t functionAddress);
void decodeWholeFunction(BinaryNinja::Function *function);
private:
void showIndent() const;
void analysisInstruction(const BNLowLevelILInstruction& insn);

BinaryView *m_bv;
std::vector<BinaryNinja::Ref<BinaryNinja::Function>> m_currentFunction;
int m_tabs;
size_t m_currentInstructionId;
};


#endif /* __LOWLEVEL_IL_PARSER_H_ */
Loading

0 comments on commit cc3755b

Please sign in to comment.