diff options
| author | Rusty Wagner <rusty@vector35.com> | 2017-08-31 21:41:25 -0400 |
|---|---|---|
| committer | Rusty Wagner <rusty@vector35.com> | 2017-08-31 21:41:25 -0400 |
| commit | 7cbb40a71ffb2583862191b7999e436807f9a0e8 (patch) | |
| tree | 25846f8d0e811b16b28291aeaf6359bee51e28c4 /examples | |
| parent | 980e2f090fb47f7f71a46b03e8c636819f3214ec (diff) | |
| parent | 0b30396eb319e89e4f69d9cbac12fc3d4b453f53 (diff) | |
Merge branch 'dev'
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/llil_parser/CMakeLists.txt | 50 | ||||
| -rw-r--r-- | examples/llil_parser/Makefile | 51 | ||||
| -rw-r--r-- | examples/llil_parser/Makefile.win | 9 | ||||
| -rw-r--r-- | examples/llil_parser/src/llil_parser.cpp | 409 | ||||
| -rw-r--r-- | examples/mlil_parser/CMakeLists.txt | 50 | ||||
| -rw-r--r-- | examples/mlil_parser/Makefile | 51 | ||||
| -rw-r--r-- | examples/mlil_parser/Makefile.win | 9 | ||||
| -rw-r--r-- | examples/mlil_parser/src/mlil_parser.cpp | 356 | ||||
| -rw-r--r-- | examples/x86_extension/Makefile | 59 | ||||
| m--------- | examples/x86_extension/src/asmx86 | 0 | ||||
| -rw-r--r-- | examples/x86_extension/src/x86_extension.cpp | 502 |
11 files changed, 1546 insertions, 0 deletions
diff --git a/examples/llil_parser/CMakeLists.txt b/examples/llil_parser/CMakeLists.txt new file mode 100644 index 00000000..6d782109 --- /dev/null +++ b/examples/llil_parser/CMakeLists.txt @@ -0,0 +1,50 @@ +# 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(${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) + diff --git a/examples/llil_parser/Makefile b/examples/llil_parser/Makefile new file mode 100644 index 00000000..13c01e62 --- /dev/null +++ b/examples/llil_parser/Makefile @@ -0,0 +1,51 @@ +# Path to prebuilt libbinaryninjaapi.a +BINJA_API_A := ../../bin/libbinaryninjaapi.a + +# Path to binaryninjaapi.h and json +INC := -I../../ + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + # Path to binaryninja install + BINJAPATH := $(HOME)/binaryninja/ + CC := g++ +else + BINJAPATH := /Applications/Binary\ Ninja.app/Contents/MacOS + CC := clang++ +endif + +SRCDIR := src +BUILDDIR := build +TARGETDIR := bin + +TARGETNAME := llil_parser +TARGET := $(TARGETDIR)/$(TARGETNAME) + +SRCEXT := cpp +SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT)) +OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o)) + +LIBS := -L $(BINJAPATH) -lbinaryninjacore +CFLAGS := -c -std=gnu++11 -O2 -Wall -W -fPIC -pipe + +all: $(TARGET) + +ifeq ($(UNAME_S),Linux) +$(TARGET): $(OBJECTS) + @mkdir -p $(TARGETDIR) + $(CC) $^ $(BINJA_API_A) $(LIBS) -Wl,-rpath=$(BINJAPATH) -ldl -o $@ +else +$(TARGET): $(OBJECTS) + @mkdir -p $(TARGETDIR) + $(CC) $^ $(BINJA_API_A) $(LIBS) -o $@ + install_name_tool -change @rpath/libbinaryninjacore.dylib $(BINJAPATH)/libbinaryninjacore.dylib $@ +endif + +$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT) + @mkdir -p $(BUILDDIR) + $(CC) $(CFLAGS) $(INC) -c -o $@ $< + +clean: + $(RM) -r $(BUILDDIR) $(TARGETDIR) + +.PHONY: clean diff --git a/examples/llil_parser/Makefile.win b/examples/llil_parser/Makefile.win new file mode 100644 index 00000000..fb714c0b --- /dev/null +++ b/examples/llil_parser/Makefile.win @@ -0,0 +1,9 @@ +BINJA_API_INC_PATH = ..\..\ +BINJA_API_LIB = ..\..\bin\libbinaryninjaapi.lib +BINJA_CORE_LIB = "c:\Program Files\Vector35\BinaryNinja\binaryninjacore.lib" + +FLAGS = /DWIN32 /D__WIN32__ /EHsc /I$(BINJA_API_INC_PATH) /link $(BINJA_API_LIB) $(BINJA_CORE_LIB) + +bininfo: ./src/llil_parser.cpp + if not exist bin mkdir bin + cl ./src/llil_parser.cpp $(FLAGS) /Fe:.\bin\bininfo diff --git a/examples/llil_parser/src/llil_parser.cpp b/examples/llil_parser/src/llil_parser.cpp new file mode 100644 index 00000000..72ac71bd --- /dev/null +++ b/examples/llil_parser/src/llil_parser.cpp @@ -0,0 +1,409 @@ +#include <stdio.h> +#include <inttypes.h> +#include "binaryninjacore.h" +#include "binaryninjaapi.h" +#include "lowlevelilinstruction.h" + +using namespace BinaryNinja; +using namespace std; + + +#ifndef __WIN32__ +#include <libgen.h> +#include <dlfcn.h> +static string GetPluginsDirectory() +{ + Dl_info info; + if (!dladdr((void *)BNGetBundledPluginDirectory, &info)) + return NULL; + + stringstream ss; + ss << dirname((char *)info.dli_fname) << "/plugins/"; + return ss.str(); +} +#else +static string GetPluginsDirectory() +{ + return "C:\\Program Files\\Vector35\\Binary Ninja\\plugins\\"; +} +#endif + + +static void PrintIndent(size_t indent) +{ + for (size_t i = 0; i < indent; i++) + printf(" "); +} + + +static void PrintOperation(BNLowLevelILOperation operation) +{ +#define ENUM_PRINTER(op) \ + case op: \ + printf(#op); \ + break; + + switch (operation) + { + ENUM_PRINTER(LLIL_NOP) + ENUM_PRINTER(LLIL_SET_REG) + ENUM_PRINTER(LLIL_SET_REG_SPLIT) + ENUM_PRINTER(LLIL_SET_FLAG) + ENUM_PRINTER(LLIL_LOAD) + ENUM_PRINTER(LLIL_STORE) + ENUM_PRINTER(LLIL_PUSH) + ENUM_PRINTER(LLIL_POP) + ENUM_PRINTER(LLIL_REG) + ENUM_PRINTER(LLIL_CONST) + ENUM_PRINTER(LLIL_CONST_PTR) + ENUM_PRINTER(LLIL_FLAG) + ENUM_PRINTER(LLIL_FLAG_BIT) + ENUM_PRINTER(LLIL_ADD) + ENUM_PRINTER(LLIL_ADC) + ENUM_PRINTER(LLIL_SUB) + ENUM_PRINTER(LLIL_SBB) + ENUM_PRINTER(LLIL_AND) + ENUM_PRINTER(LLIL_OR) + ENUM_PRINTER(LLIL_XOR) + ENUM_PRINTER(LLIL_LSL) + ENUM_PRINTER(LLIL_LSR) + ENUM_PRINTER(LLIL_ASR) + ENUM_PRINTER(LLIL_ROL) + ENUM_PRINTER(LLIL_RLC) + ENUM_PRINTER(LLIL_ROR) + ENUM_PRINTER(LLIL_RRC) + ENUM_PRINTER(LLIL_MUL) + ENUM_PRINTER(LLIL_MULU_DP) + ENUM_PRINTER(LLIL_MULS_DP) + ENUM_PRINTER(LLIL_DIVU) + ENUM_PRINTER(LLIL_DIVU_DP) + ENUM_PRINTER(LLIL_DIVS) + ENUM_PRINTER(LLIL_DIVS_DP) + ENUM_PRINTER(LLIL_MODU) + ENUM_PRINTER(LLIL_MODU_DP) + ENUM_PRINTER(LLIL_MODS) + ENUM_PRINTER(LLIL_MODS_DP) + ENUM_PRINTER(LLIL_NEG) + ENUM_PRINTER(LLIL_NOT) + ENUM_PRINTER(LLIL_SX) + ENUM_PRINTER(LLIL_ZX) + ENUM_PRINTER(LLIL_LOW_PART) + ENUM_PRINTER(LLIL_JUMP) + ENUM_PRINTER(LLIL_JUMP_TO) + ENUM_PRINTER(LLIL_CALL) + ENUM_PRINTER(LLIL_RET) + ENUM_PRINTER(LLIL_NORET) + ENUM_PRINTER(LLIL_IF) + ENUM_PRINTER(LLIL_GOTO) + ENUM_PRINTER(LLIL_FLAG_COND) + ENUM_PRINTER(LLIL_CMP_E) + ENUM_PRINTER(LLIL_CMP_NE) + ENUM_PRINTER(LLIL_CMP_SLT) + ENUM_PRINTER(LLIL_CMP_ULT) + ENUM_PRINTER(LLIL_CMP_SLE) + ENUM_PRINTER(LLIL_CMP_ULE) + ENUM_PRINTER(LLIL_CMP_SGE) + ENUM_PRINTER(LLIL_CMP_UGE) + ENUM_PRINTER(LLIL_CMP_SGT) + ENUM_PRINTER(LLIL_CMP_UGT) + ENUM_PRINTER(LLIL_TEST_BIT) + ENUM_PRINTER(LLIL_BOOL_TO_INT) + ENUM_PRINTER(LLIL_ADD_OVERFLOW) + ENUM_PRINTER(LLIL_SYSCALL) + ENUM_PRINTER(LLIL_BP) + ENUM_PRINTER(LLIL_TRAP) + ENUM_PRINTER(LLIL_UNDEF) + ENUM_PRINTER(LLIL_UNIMPL) + ENUM_PRINTER(LLIL_UNIMPL_MEM) + ENUM_PRINTER(LLIL_SET_REG_SSA) + ENUM_PRINTER(LLIL_SET_REG_SSA_PARTIAL) + ENUM_PRINTER(LLIL_SET_REG_SPLIT_SSA) + ENUM_PRINTER(LLIL_REG_SPLIT_DEST_SSA) + ENUM_PRINTER(LLIL_REG_SSA) + ENUM_PRINTER(LLIL_REG_SSA_PARTIAL) + ENUM_PRINTER(LLIL_SET_FLAG_SSA) + ENUM_PRINTER(LLIL_FLAG_SSA) + ENUM_PRINTER(LLIL_FLAG_BIT_SSA) + ENUM_PRINTER(LLIL_CALL_SSA) + ENUM_PRINTER(LLIL_SYSCALL_SSA) + ENUM_PRINTER(LLIL_CALL_PARAM_SSA) + ENUM_PRINTER(LLIL_CALL_STACK_SSA) + ENUM_PRINTER(LLIL_CALL_OUTPUT_SSA) + ENUM_PRINTER(LLIL_LOAD_SSA) + ENUM_PRINTER(LLIL_STORE_SSA) + ENUM_PRINTER(LLIL_REG_PHI) + ENUM_PRINTER(LLIL_FLAG_PHI) + ENUM_PRINTER(LLIL_MEM_PHI) + default: + printf("<invalid operation %" PRId32 ">", operation); + break; + } +} + + +static void PrintFlagCondition(BNLowLevelILFlagCondition cond) +{ + switch (cond) + { + ENUM_PRINTER(LLFC_E) + ENUM_PRINTER(LLFC_NE) + ENUM_PRINTER(LLFC_SLT) + ENUM_PRINTER(LLFC_ULT) + ENUM_PRINTER(LLFC_SLE) + ENUM_PRINTER(LLFC_ULE) + ENUM_PRINTER(LLFC_SGE) + ENUM_PRINTER(LLFC_UGE) + ENUM_PRINTER(LLFC_SGT) + ENUM_PRINTER(LLFC_UGT) + ENUM_PRINTER(LLFC_NEG) + ENUM_PRINTER(LLFC_POS) + ENUM_PRINTER(LLFC_O) + ENUM_PRINTER(LLFC_NO) + default: + printf("<invalid condition>"); + break; + } +} + + +static void PrintRegister(LowLevelILFunction* func, uint32_t reg) +{ + if (LLIL_REG_IS_TEMP(reg)) + printf("temp%d", LLIL_GET_TEMP_REG_INDEX(reg)); + else + { + string name = func->GetArchitecture()->GetRegisterName(reg); + if (name.size() == 0) + printf("<no name>"); + else + printf("%s", name.c_str()); + } +} + + +static void PrintFlag(LowLevelILFunction* func, uint32_t flag) +{ + if (LLIL_REG_IS_TEMP(flag)) + printf("cond:%d", LLIL_GET_TEMP_REG_INDEX(flag)); + else + { + string name = func->GetArchitecture()->GetFlagName(flag); + if (name.size() == 0) + printf("<no name>"); + else + printf("%s", name.c_str()); + } +} + + +static void PrintILExpr(const LowLevelILInstruction& instr, size_t indent) +{ + PrintIndent(indent); + PrintOperation(instr.operation); + printf("\n"); + + indent++; + + for (auto& operand : instr.GetOperands()) + { + switch (operand.GetType()) + { + case IntegerLowLevelOperand: + PrintIndent(indent); + printf("int 0x%" PRIx64 "\n", operand.GetInteger()); + break; + + case IndexLowLevelOperand: + PrintIndent(indent); + printf("index %" PRIdPTR "\n", operand.GetIndex()); + break; + + case ExprLowLevelOperand: + PrintILExpr(operand.GetExpr(), indent); + break; + + case RegisterLowLevelOperand: + PrintIndent(indent); + printf("reg "); + PrintRegister(instr.function, operand.GetRegister()); + printf("\n"); + break; + + case FlagLowLevelOperand: + PrintIndent(indent); + printf("flag "); + PrintFlag(instr.function, operand.GetFlag()); + printf("\n"); + break; + + case FlagConditionLowLevelOperand: + PrintIndent(indent); + printf("flag condition "); + PrintFlagCondition(operand.GetFlagCondition()); + printf("\n"); + break; + + case SSARegisterLowLevelOperand: + PrintIndent(indent); + printf("ssa reg "); + PrintRegister(instr.function, operand.GetSSARegister().reg); + printf("#%" PRIdPTR "\n", operand.GetSSARegister().version); + break; + + case SSAFlagLowLevelOperand: + PrintIndent(indent); + printf("ssa flag "); + PrintFlag(instr.function, operand.GetSSAFlag().flag); + printf("#%" PRIdPTR "\n", operand.GetSSAFlag().version); + break; + + case IndexListLowLevelOperand: + PrintIndent(indent); + printf("index list "); + for (auto i : operand.GetIndexList()) + printf("%" PRIdPTR " ", i); + printf("\n"); + break; + + case SSARegisterListLowLevelOperand: + PrintIndent(indent); + printf("ssa reg list "); + for (auto& i : operand.GetSSARegisterList()) + { + PrintRegister(instr.function, i.reg); + printf("#%" PRIdPTR " ", i.version); + } + printf("\n"); + break; + + case SSAFlagListLowLevelOperand: + PrintIndent(indent); + printf("ssa reg list "); + for (auto& i : operand.GetSSAFlagList()) + { + PrintFlag(instr.function, i.flag); + printf("#%" PRIdPTR " ", i.version); + } + printf("\n"); + break; + + default: + PrintIndent(indent); + printf("<invalid operand>\n"); + break; + } + } +} + + +int main(int argc, char *argv[]) +{ + if (argc != 2) + { + fprintf(stderr, "Expected input filename\n"); + return 1; + } + + // In order to initiate the bundled plugins properly, the location + // of where bundled plugins directory is must be set. Since + // libbinaryninjacore is in the path get the path to it and use it to + // determine the plugins directory + SetBundledPluginDirectory(GetPluginsDirectory()); + InitCorePlugins(); + InitUserPlugins(); + + Ref<BinaryData> bd = new BinaryData(new FileMetadata(), argv[1]); + Ref<BinaryView> bv; + for (auto type : BinaryViewType::GetViewTypes()) + { + if (type->IsTypeValidForData(bd) && type->GetName() != "Raw") + { + bv = type->Create(bd); + break; + } + } + + if (!bv || bv->GetTypeName() == "Raw") + { + fprintf(stderr, "Input file does not appear to be an exectuable\n"); + return -1; + } + + bv->UpdateAnalysisAndWait(); + + // Go through all functions in the binary + for (auto& func : bv->GetAnalysisFunctionList()) + { + // Get the name of the function and display it + Ref<Symbol> sym = func->GetSymbol(); + if (sym) + printf("Function %s:\n", sym->GetFullName().c_str()); + else + printf("Function at 0x%" PRIx64 ":\n", func->GetStart()); + + // Fetch the low level IL for the function + Ref<LowLevelILFunction> il = func->GetLowLevelIL(); + if (!il) + { + printf(" Does not have LLIL\n\n"); + continue; + } + + // Loop through all blocks in the function + for (auto& block : il->GetBasicBlocks()) + { + // Loop though each instruction in the block + for (size_t instrIndex = block->GetStart(); instrIndex < block->GetEnd(); instrIndex++) + { + // Fetch IL instruction + LowLevelILInstruction instr = (*il)[instrIndex]; + + // Display core's intrepretation of the IL instruction + vector<InstructionTextToken> tokens; + il->GetInstructionText(func, func->GetArchitecture(), instrIndex, tokens); + printf(" %" PRIdPTR " @ 0x%" PRIx64 " ", instrIndex, instr.address); + for (auto& token: tokens) + printf("%s", token.text.c_str()); + printf("\n"); + + // Generically parse the IL tree and display the parts + PrintILExpr(instr, 2); + + // Example of using visitors to find all constants in the instruction + instr.VisitExprs([&](const LowLevelILInstruction& expr) { + switch (expr.operation) + { + case LLIL_CONST: + case LLIL_CONST_PTR: + printf(" Found constant 0x%" PRIx64 "\n", expr.GetConstant()); + return false; // Done parsing this + default: + break; + } + return true; // Parse any subexpressions + }); + + // Example of using the templated accessors for efficiently parsing load instructions + instr.VisitExprs([&](const LowLevelILInstruction& expr) { + switch (expr.operation) + { + case LLIL_LOAD: + if (expr.GetSourceExpr<LLIL_LOAD>().operation == LLIL_CONST_PTR) + { + printf(" Loading from address 0x%" PRIx64 "\n", + expr.GetSourceExpr<LLIL_LOAD>().GetConstant<LLIL_CONST_PTR>()); + return false; // Done parsing this + } + break; + default: + break; + } + return true; // Parse any subexpressions + }); + } + } + + printf("\n"); + } + return 0; +} diff --git a/examples/mlil_parser/CMakeLists.txt b/examples/mlil_parser/CMakeLists.txt new file mode 100644 index 00000000..1bf6e3a7 --- /dev/null +++ b/examples/mlil_parser/CMakeLists.txt @@ -0,0 +1,50 @@ +# Mostly copied from https://github.com/Vector35/binaryninja-api/blob/dev/examples/breakpoint/CMakeLists.txt + +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +project(MLIL_Parser) + +#----------------------------------------------------------------------------- +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) + diff --git a/examples/mlil_parser/Makefile b/examples/mlil_parser/Makefile new file mode 100644 index 00000000..44b7b77f --- /dev/null +++ b/examples/mlil_parser/Makefile @@ -0,0 +1,51 @@ +# Path to prebuilt libbinaryninjaapi.a +BINJA_API_A := ../../bin/libbinaryninjaapi.a + +# Path to binaryninjaapi.h and json +INC := -I../../ + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + # Path to binaryninja install + BINJAPATH := $(HOME)/binaryninja/ + CC := g++ +else + BINJAPATH := /Applications/Binary\ Ninja.app/Contents/MacOS + CC := clang++ +endif + +SRCDIR := src +BUILDDIR := build +TARGETDIR := bin + +TARGETNAME := mlil_parser +TARGET := $(TARGETDIR)/$(TARGETNAME) + +SRCEXT := cpp +SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT)) +OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o)) + +LIBS := -L $(BINJAPATH) -lbinaryninjacore +CFLAGS := -c -std=gnu++11 -O2 -Wall -W -fPIC -pipe + +all: $(TARGET) + +ifeq ($(UNAME_S),Linux) +$(TARGET): $(OBJECTS) + @mkdir -p $(TARGETDIR) + $(CC) $^ $(BINJA_API_A) $(LIBS) -Wl,-rpath=$(BINJAPATH) -ldl -o $@ +else +$(TARGET): $(OBJECTS) + @mkdir -p $(TARGETDIR) + $(CC) $^ $(BINJA_API_A) $(LIBS) -o $@ + install_name_tool -change @rpath/libbinaryninjacore.dylib $(BINJAPATH)/libbinaryninjacore.dylib $@ +endif + +$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT) + @mkdir -p $(BUILDDIR) + $(CC) $(CFLAGS) $(INC) -c -o $@ $< + +clean: + $(RM) -r $(BUILDDIR) $(TARGETDIR) + +.PHONY: clean diff --git a/examples/mlil_parser/Makefile.win b/examples/mlil_parser/Makefile.win new file mode 100644 index 00000000..92718ac0 --- /dev/null +++ b/examples/mlil_parser/Makefile.win @@ -0,0 +1,9 @@ +BINJA_API_INC_PATH = ..\..\ +BINJA_API_LIB = ..\..\bin\libbinaryninjaapi.lib +BINJA_CORE_LIB = "c:\Program Files\Vector35\BinaryNinja\binaryninjacore.lib" + +FLAGS = /DWIN32 /D__WIN32__ /EHsc /I$(BINJA_API_INC_PATH) /link $(BINJA_API_LIB) $(BINJA_CORE_LIB) + +bininfo: ./src/mlil_parser.cpp + if not exist bin mkdir bin + cl ./src/mlil_parser.cpp $(FLAGS) /Fe:.\bin\bininfo diff --git a/examples/mlil_parser/src/mlil_parser.cpp b/examples/mlil_parser/src/mlil_parser.cpp new file mode 100644 index 00000000..8fb762eb --- /dev/null +++ b/examples/mlil_parser/src/mlil_parser.cpp @@ -0,0 +1,356 @@ +#include <stdio.h> +#include <inttypes.h> +#include "binaryninjacore.h" +#include "binaryninjaapi.h" +#include "mediumlevelilinstruction.h" + +using namespace BinaryNinja; +using namespace std; + + +#ifndef __WIN32__ +#include <libgen.h> +#include <dlfcn.h> +static string GetPluginsDirectory() +{ + Dl_info info; + if (!dladdr((void *)BNGetBundledPluginDirectory, &info)) + return NULL; + + stringstream ss; + ss << dirname((char *)info.dli_fname) << "/plugins/"; + return ss.str(); +} +#else +static string GetPluginsDirectory() +{ + return "C:\\Program Files\\Vector35\\Binary Ninja\\plugins\\"; +} +#endif + + +static void PrintIndent(size_t indent) +{ + for (size_t i = 0; i < indent; i++) + printf(" "); +} + + +static void PrintOperation(BNMediumLevelILOperation operation) +{ +#define ENUM_PRINTER(op) \ + case op: \ + printf(#op); \ + break; + + switch (operation) + { + ENUM_PRINTER(MLIL_NOP) + ENUM_PRINTER(MLIL_SET_VAR) + ENUM_PRINTER(MLIL_SET_VAR_FIELD) + ENUM_PRINTER(MLIL_SET_VAR_SPLIT) + ENUM_PRINTER(MLIL_LOAD) + ENUM_PRINTER(MLIL_LOAD_STRUCT) + ENUM_PRINTER(MLIL_STORE) + ENUM_PRINTER(MLIL_STORE_STRUCT) + ENUM_PRINTER(MLIL_VAR) + ENUM_PRINTER(MLIL_VAR_FIELD) + ENUM_PRINTER(MLIL_ADDRESS_OF) + ENUM_PRINTER(MLIL_ADDRESS_OF_FIELD) + ENUM_PRINTER(MLIL_CONST) + ENUM_PRINTER(MLIL_CONST_PTR) + ENUM_PRINTER(MLIL_ADD) + ENUM_PRINTER(MLIL_ADC) + ENUM_PRINTER(MLIL_SUB) + ENUM_PRINTER(MLIL_SBB) + ENUM_PRINTER(MLIL_AND) + ENUM_PRINTER(MLIL_OR) + ENUM_PRINTER(MLIL_XOR) + ENUM_PRINTER(MLIL_LSL) + ENUM_PRINTER(MLIL_LSR) + ENUM_PRINTER(MLIL_ASR) + ENUM_PRINTER(MLIL_ROL) + ENUM_PRINTER(MLIL_RLC) + ENUM_PRINTER(MLIL_ROR) + ENUM_PRINTER(MLIL_RRC) + ENUM_PRINTER(MLIL_MUL) + ENUM_PRINTER(MLIL_MULU_DP) + ENUM_PRINTER(MLIL_MULS_DP) + ENUM_PRINTER(MLIL_DIVU) + ENUM_PRINTER(MLIL_DIVU_DP) + ENUM_PRINTER(MLIL_DIVS) + ENUM_PRINTER(MLIL_DIVS_DP) + ENUM_PRINTER(MLIL_MODU) + ENUM_PRINTER(MLIL_MODU_DP) + ENUM_PRINTER(MLIL_MODS) + ENUM_PRINTER(MLIL_MODS_DP) + ENUM_PRINTER(MLIL_NEG) + ENUM_PRINTER(MLIL_NOT) + ENUM_PRINTER(MLIL_SX) + ENUM_PRINTER(MLIL_ZX) + ENUM_PRINTER(MLIL_LOW_PART) + ENUM_PRINTER(MLIL_JUMP) + ENUM_PRINTER(MLIL_JUMP_TO) + ENUM_PRINTER(MLIL_CALL) + ENUM_PRINTER(MLIL_CALL_UNTYPED) + ENUM_PRINTER(MLIL_CALL_OUTPUT) + ENUM_PRINTER(MLIL_CALL_PARAM) + ENUM_PRINTER(MLIL_RET) + ENUM_PRINTER(MLIL_NORET) + ENUM_PRINTER(MLIL_IF) + ENUM_PRINTER(MLIL_GOTO) + ENUM_PRINTER(MLIL_CMP_E) + ENUM_PRINTER(MLIL_CMP_NE) + ENUM_PRINTER(MLIL_CMP_SLT) + ENUM_PRINTER(MLIL_CMP_ULT) + ENUM_PRINTER(MLIL_CMP_SLE) + ENUM_PRINTER(MLIL_CMP_ULE) + ENUM_PRINTER(MLIL_CMP_SGE) + ENUM_PRINTER(MLIL_CMP_UGE) + ENUM_PRINTER(MLIL_CMP_SGT) + ENUM_PRINTER(MLIL_CMP_UGT) + ENUM_PRINTER(MLIL_TEST_BIT) + ENUM_PRINTER(MLIL_BOOL_TO_INT) + ENUM_PRINTER(MLIL_ADD_OVERFLOW) + ENUM_PRINTER(MLIL_SYSCALL) + ENUM_PRINTER(MLIL_SYSCALL_UNTYPED) + ENUM_PRINTER(MLIL_BP) + ENUM_PRINTER(MLIL_TRAP) + ENUM_PRINTER(MLIL_UNDEF) + ENUM_PRINTER(MLIL_UNIMPL) + ENUM_PRINTER(MLIL_UNIMPL_MEM) + ENUM_PRINTER(MLIL_SET_VAR_SSA) + ENUM_PRINTER(MLIL_SET_VAR_SSA_FIELD) + ENUM_PRINTER(MLIL_SET_VAR_SPLIT_SSA) + ENUM_PRINTER(MLIL_SET_VAR_ALIASED) + ENUM_PRINTER(MLIL_SET_VAR_ALIASED_FIELD) + ENUM_PRINTER(MLIL_VAR_SSA) + ENUM_PRINTER(MLIL_VAR_SSA_FIELD) + ENUM_PRINTER(MLIL_VAR_ALIASED) + ENUM_PRINTER(MLIL_VAR_ALIASED_FIELD) + ENUM_PRINTER(MLIL_CALL_SSA) + ENUM_PRINTER(MLIL_CALL_UNTYPED_SSA) + ENUM_PRINTER(MLIL_SYSCALL_SSA) + ENUM_PRINTER(MLIL_SYSCALL_UNTYPED_SSA) + ENUM_PRINTER(MLIL_CALL_PARAM_SSA) + ENUM_PRINTER(MLIL_CALL_OUTPUT_SSA) + ENUM_PRINTER(MLIL_LOAD_SSA) + ENUM_PRINTER(MLIL_LOAD_STRUCT_SSA) + ENUM_PRINTER(MLIL_STORE_SSA) + ENUM_PRINTER(MLIL_STORE_STRUCT_SSA) + ENUM_PRINTER(MLIL_VAR_PHI) + ENUM_PRINTER(MLIL_MEM_PHI) + default: + printf("<invalid operation %" PRId32 ">", operation); + break; + } +} + + +static void PrintVariable(MediumLevelILFunction* func, const Variable& var) +{ + string name = func->GetFunction()->GetVariableName(var); + if (name.size() == 0) + printf("<no name>"); + else + printf("%s", name.c_str()); +} + + +static void PrintILExpr(const MediumLevelILInstruction& instr, size_t indent) +{ + PrintIndent(indent); + PrintOperation(instr.operation); + printf("\n"); + + indent++; + + for (auto& operand : instr.GetOperands()) + { + switch (operand.GetType()) + { + case IntegerMediumLevelOperand: + PrintIndent(indent); + printf("int 0x%" PRIx64 "\n", operand.GetInteger()); + break; + + case IndexMediumLevelOperand: + PrintIndent(indent); + printf("index %" PRIdPTR "\n", operand.GetIndex()); + break; + + case ExprMediumLevelOperand: + PrintILExpr(operand.GetExpr(), indent); + break; + + case VariableMediumLevelOperand: + PrintIndent(indent); + printf("var "); + PrintVariable(instr.function, operand.GetVariable()); + printf("\n"); + break; + + case SSAVariableMediumLevelOperand: + PrintIndent(indent); + printf("ssa var "); + PrintVariable(instr.function, operand.GetSSAVariable().var); + printf("#%" PRIdPTR "\n", operand.GetSSAVariable().version); + break; + + case IndexListMediumLevelOperand: + PrintIndent(indent); + printf("index list "); + for (auto i : operand.GetIndexList()) + printf("%" PRIdPTR " ", i); + printf("\n"); + break; + + case VariableListMediumLevelOperand: + PrintIndent(indent); + printf("var list "); + for (auto& i : operand.GetVariableList()) + { + PrintVariable(instr.function, i); + printf(" "); + } + printf("\n"); + break; + + case SSAVariableListMediumLevelOperand: + PrintIndent(indent); + printf("ssa var list "); + for (auto& i : operand.GetSSAVariableList()) + { + PrintVariable(instr.function, i.var); + printf("#%" PRIdPTR " ", i.version); + } + printf("\n"); + break; + + case ExprListMediumLevelOperand: + PrintIndent(indent); + printf("expr list\n"); + for (auto& i : operand.GetExprList()) + PrintILExpr(i, indent + 1); + break; + + default: + PrintIndent(indent); + printf("<invalid operand>\n"); + break; + } + } +} + + +int main(int argc, char *argv[]) +{ + if (argc != 2) + { + fprintf(stderr, "Expected input filename\n"); + return 1; + } + + // In order to initiate the bundled plugins properly, the location + // of where bundled plugins directory is must be set. Since + // libbinaryninjacore is in the path get the path to it and use it to + // determine the plugins directory + SetBundledPluginDirectory(GetPluginsDirectory()); + InitCorePlugins(); + InitUserPlugins(); + + Ref<BinaryData> bd = new BinaryData(new FileMetadata(), argv[1]); + Ref<BinaryView> bv; + for (auto type : BinaryViewType::GetViewTypes()) + { + if (type->IsTypeValidForData(bd) && type->GetName() != "Raw") + { + bv = type->Create(bd); + break; + } + } + + if (!bv || bv->GetTypeName() == "Raw") + { + fprintf(stderr, "Input file does not appear to be an exectuable\n"); + return -1; + } + + bv->UpdateAnalysisAndWait(); + + // Go through all functions in the binary + for (auto& func : bv->GetAnalysisFunctionList()) + { + // Get the name of the function and display it + Ref<Symbol> sym = func->GetSymbol(); + if (sym) + printf("Function %s:\n", sym->GetFullName().c_str()); + else + printf("Function at 0x%" PRIx64 ":\n", func->GetStart()); + + // Fetch the medium level IL for the function + Ref<MediumLevelILFunction> il = func->GetMediumLevelIL(); + if (!il) + { + printf(" Does not have MLIL\n\n"); + continue; + } + + // Loop through all blocks in the function + for (auto& block : il->GetBasicBlocks()) + { + // Loop though each instruction in the block + for (size_t instrIndex = block->GetStart(); instrIndex < block->GetEnd(); instrIndex++) + { + // Fetch IL instruction + MediumLevelILInstruction instr = (*il)[instrIndex]; + + // Display core's intrepretation of the IL instruction + vector<InstructionTextToken> tokens; + il->GetInstructionText(func, func->GetArchitecture(), instrIndex, tokens); + printf(" %" PRIdPTR " @ 0x%" PRIx64 " ", instrIndex, instr.address); + for (auto& token: tokens) + printf("%s", token.text.c_str()); + printf("\n"); + + // Generically parse the IL tree and display the parts + PrintILExpr(instr, 2); + + // Example of using visitors to find all constants in the instruction + instr.VisitExprs([&](const MediumLevelILInstruction& expr) { + switch (expr.operation) + { + case MLIL_CONST: + case MLIL_CONST_PTR: + printf(" Found constant 0x%" PRIx64 "\n", expr.GetConstant()); + return false; // Done parsing this + default: + break; + } + return true; // Parse any subexpressions + }); + + // Example of using the templated accessors for efficiently parsing load instructions + instr.VisitExprs([&](const MediumLevelILInstruction& expr) { + switch (expr.operation) + { + case MLIL_LOAD: + if (expr.GetSourceExpr<MLIL_LOAD>().operation == MLIL_CONST_PTR) + { + printf(" Loading from address 0x%" PRIx64 "\n", + expr.GetSourceExpr<MLIL_LOAD>().GetConstant<MLIL_CONST_PTR>()); + return false; // Done parsing this + } + break; + default: + break; + } + return true; // Parse any subexpressions + }); + } + } + + printf("\n"); + } + return 0; +} diff --git a/examples/x86_extension/Makefile b/examples/x86_extension/Makefile new file mode 100644 index 00000000..1ee60891 --- /dev/null +++ b/examples/x86_extension/Makefile @@ -0,0 +1,59 @@ +# Path to prebuilt libbinaryninjaapi.a +BINJA_API_A := ../../bin/libbinaryninjaapi.a + +# Path to binaryninjaapi.h and json +INC := -I../../ + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + # Path to binaryninja install + BINJAPATH := $(shell cat ~/.binaryninja/lastrun) + PLUGIN_DIR := ~/.binaryninja/plugins/ + CC := g++ +else + BINJAPATH := /Applications/Binary\ Ninja.app/Contents/MacOS + PLUGIN_DIR := ~/Library/Application\ Support/Binary\ Ninja/plugins/ + CC := clang++ +endif + +SRCDIR := src +BUILDDIR := build +TARGETDIR := bin + +TARGETNAME := x86_extension +TARGET := $(TARGETDIR)/$(TARGETNAME) + +SRCEXT := cpp +SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT)) +OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o)) src/asmx86/libasmx86.a + +LIBS := -L$(BINJAPATH) -lbinaryninjacore +CFLAGS := -c -std=gnu++11 -O2 -Wall -W -fPIC -pipe -Wno-unused-function + +all: $(TARGET) + +ifeq ($(UNAME_S),Linux) +$(TARGET): $(OBJECTS) + @mkdir -p $(TARGETDIR) + $(CC) $^ $(BINJA_API_A) $(LIBS) -shared -Wl,-rpath=$(BINJAPATH) -ldl -o bin/lib$(TARGETNAME).so +else +$(TARGET): $(OBJECTS) + @mkdir -p $(TARGETDIR) + $(CC) $^ $(BINJA_API_A) $(LIBS) -single_module -dynamiclib -o bin/lib$(TARGETNAME).dylib + install_name_tool -add_rpath $(BINJAPATH)/libbinaryninjacore.dylib bin/lib$(TARGETNAME).dylib +endif + +$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT) + @mkdir -p $(BUILDDIR) + $(CC) $(CFLAGS) $(INC) -c -o $@ $< + +src/asmx86/libasmx86.a: + $(MAKE) -C src/asmx86 + +install: + cp bin/lib$(TARGETNAME).dylib $(PLUGIN_DIR) + +clean: + $(RM) -r $(BUILDDIR) $(TARGETDIR) + +.PHONY: clean diff --git a/examples/x86_extension/src/asmx86 b/examples/x86_extension/src/asmx86 new file mode 160000 +Subproject f78096d79ccfcc5169b6e2ae0fa89e3eed5b85c diff --git a/examples/x86_extension/src/x86_extension.cpp b/examples/x86_extension/src/x86_extension.cpp new file mode 100644 index 00000000..9efcc119 --- /dev/null +++ b/examples/x86_extension/src/x86_extension.cpp @@ -0,0 +1,502 @@ +#define _CRT_SECURE_NO_WARNINGS +#include <inttypes.h> +#include <stdio.h> +#include <string.h> +#include "binaryninjaapi.h" +#include "asmx86/asmx86.h" + +using namespace BinaryNinja; +using namespace std; +using namespace asmx86; + + +#define IL_FLAG_C 0 +#define IL_FLAG_P 2 +#define IL_FLAG_A 4 +#define IL_FLAG_Z 6 +#define IL_FLAG_S 7 +#define IL_FLAG_D 10 +#define IL_FLAG_O 11 + +#define IL_FLAGWRITE_ALL 1 +#define IL_FLAGWRITE_NOCARRY 2 +#define IL_FLAGWRITE_CO 3 + +#define REG_FSBASE 0x100 +#define REG_GSBASE 0x101 + +#define TRAP_DIV 0 +#define TRAP_ICEBP 1 +#define TRAP_NMI 2 +#define TRAP_BP 3 +#define TRAP_OVERFLOW 4 +#define TRAP_BOUND 5 +#define TRAP_ILL 6 +#define TRAP_NOT_AVAIL 7 +#define TRAP_DOUBLE 8 +#define TRAP_TSS 10 +#define TRAP_NO_SEG 11 +#define TRAP_STACK 12 +#define TRAP_GPF 13 +#define TRAP_PAGE 14 +#define TRAP_FPU 16 +#define TRAP_ALIGN 17 +#define TRAP_MCE 18 +#define TRAP_SIMD 19 + +static uint8_t GetShiftCountForScale(uint8_t scale) +{ + switch (scale) + { + case 2: + return 1; + case 4: + return 2; + case 8: + return 3; + default: + return 0; + } +} + + +static uint32_t GetStackPointer(size_t addrSize) +{ + switch (addrSize) + { + case 2: + return REG_SP; + case 4: + return REG_ESP; + default: + return REG_RSP; + } +} + + +static uint32_t GetFramePointer(size_t addrSize) +{ + switch (addrSize) + { + case 2: + return REG_BP; + case 4: + return REG_EBP; + default: + return REG_RBP; + } +} + + +static uint32_t GetCountRegister(size_t addrSize) +{ + switch (addrSize) + { + case 2: + return REG_CX; + case 4: + return REG_ECX; + default: + return REG_RCX; + } +} + + +static size_t GetILOperandMemoryAddress(LowLevelILFunction& il, InstructionOperand& operand, size_t i, size_t addrSize) +{ + size_t offset; + if (operand.operand != MEM) + offset = il.Operand(i, il.Undefined()); + else if ((operand.components[0] == NONE) && (operand.components[1] == NONE) && operand.relative) + offset = il.Operand(i, il.ConstPointer(addrSize, operand.immediate)); + else if ((operand.components[0] == NONE) && (operand.components[1] == NONE)) + offset = il.Operand(i, il.Const(addrSize, operand.immediate)); + else if ((operand.components[1] == NONE) && (operand.immediate == 0)) + offset = il.Operand(i, il.Register(addrSize, operand.components[0])); + else if (operand.components[1] == NONE) + { + offset = il.Operand(i, il.Add(addrSize, il.Register(addrSize, operand.components[0]), + il.Const(addrSize, operand.immediate))); + } + else if ((operand.components[0] == NONE) && (operand.scale == 1) && (operand.immediate == 0)) + offset = il.Operand(i, il.Register(addrSize, operand.components[1])); + else if ((operand.components[0] == NONE) && (operand.scale == 1)) + { + offset = il.Operand(i, il.Add(addrSize, il.Register(addrSize, operand.components[1]), + il.Const(addrSize, operand.immediate))); + } + else if ((operand.components[0] == NONE) && (operand.immediate == 0)) + { + offset = il.Operand(i, il.ShiftLeft(addrSize, il.Register(addrSize, operand.components[1]), + il.Const(1, GetShiftCountForScale(operand.scale)))); + } + else if (operand.components[0] == NONE) + { + offset = il.Operand(i, il.Add(addrSize, il.ShiftLeft(addrSize, il.Register(addrSize, operand.components[1]), + il.Const(1, GetShiftCountForScale(operand.scale))), il.Const(addrSize, operand.immediate))); + } + else if ((operand.scale == 1) && (operand.immediate == 0)) + { + offset = il.Operand(i, il.Add(addrSize, il.Register(addrSize, operand.components[0]), + il.Register(addrSize, operand.components[1]))); + } + else if (operand.scale == 1) + { + offset = il.Operand(i, il.Add(addrSize, il.Add(addrSize, il.Register(addrSize, operand.components[0]), + il.Register(addrSize, operand.components[1])), il.Const(addrSize, operand.immediate))); + } + else if (operand.immediate == 0) + { + offset = il.Operand(i, il.Add(addrSize, il.Register(addrSize, operand.components[0]), + il.ShiftLeft(addrSize, il.Register(addrSize, operand.components[1]), + il.Const(1, GetShiftCountForScale(operand.scale))))); + } + else + { + offset = il.Operand(i, il.Add(addrSize, il.Add(addrSize, il.Register(addrSize, operand.components[0]), + il.ShiftLeft(addrSize, il.Register(addrSize, operand.components[1]), + il.Const(1, GetShiftCountForScale(operand.scale)))), il.Const(addrSize, operand.immediate))); + } + + if (operand.segment == SEG_FS) + return il.Operand(i, il.Add(addrSize, il.Register(addrSize, REG_FSBASE), offset)); + if (operand.segment == SEG_GS) + return il.Operand(i, il.Add(addrSize, il.Register(addrSize, REG_GSBASE), offset)); + return offset; +} + + +static size_t ReadILOperand(LowLevelILFunction& il, Instruction& instr, size_t i, size_t addrSize, bool isAddress = false) +{ + InstructionOperand& operand = instr.operands[i]; + switch (operand.operand) + { + case NONE: + return il.Undefined(); + case IMM: + if (isAddress) + return il.Operand(i, il.ConstPointer(operand.size, operand.immediate)); + else + return il.Operand(i, il.Const(operand.size, operand.immediate)); + case MEM: + return il.Operand(i, il.Load(operand.size, GetILOperandMemoryAddress(il, operand, i, addrSize))); + default: + return il.Operand(i, il.Register(operand.size, operand.operand)); + } +} + + +static size_t WriteILOperand(LowLevelILFunction& il, Instruction& instr, size_t i, size_t addrSize, size_t value) +{ + InstructionOperand& operand = instr.operands[i]; + switch (operand.operand) + { + case NONE: + case IMM: + return il.Undefined(); + case MEM: + return il.Operand(i, il.Store(operand.size, GetILOperandMemoryAddress(il, operand, i, addrSize), value)); + default: + return il.Operand(i, il.SetRegister(operand.size, operand.operand, value)); + } +} + + +static size_t DirectJump(Architecture* arch, LowLevelILFunction& il, uint64_t target, size_t addrSize) +{ + BNLowLevelILLabel* label = il.GetLabelForAddress(arch, target); + if (label) + return il.Goto(*label); + else + return il.Jump(il.ConstPointer(addrSize, target)); +} + + +static void ConditionalJump(Architecture* arch, LowLevelILFunction& il, size_t cond, size_t addrSize, uint64_t t, uint64_t f) +{ + BNLowLevelILLabel* trueLabel = il.GetLabelForAddress(arch, t); + BNLowLevelILLabel* falseLabel = il.GetLabelForAddress(arch, f); + + if (trueLabel && falseLabel) + { + il.AddInstruction(il.If(cond, *trueLabel, *falseLabel)); + return; + } + + LowLevelILLabel trueCode, falseCode; + + if (trueLabel) + { + il.AddInstruction(il.If(cond, *trueLabel, falseCode)); + il.MarkLabel(falseCode); + il.AddInstruction(il.Jump(il.ConstPointer(addrSize, f))); + return; + } + + if (falseLabel) + { + il.AddInstruction(il.If(cond, trueCode, *falseLabel)); + il.MarkLabel(trueCode); + il.AddInstruction(il.Jump(il.ConstPointer(addrSize, t))); + return; + } + + il.AddInstruction(il.If(cond, trueCode, falseCode)); + il.MarkLabel(trueCode); + il.AddInstruction(il.Jump(il.ConstPointer(addrSize, t))); + il.MarkLabel(falseCode); + il.AddInstruction(il.Jump(il.ConstPointer(addrSize, f))); +} + + +static void DirFlagIf(size_t addrSize, + LowLevelILFunction& il, + std::function<void (size_t addrSize, LowLevelILFunction& il)> addPreTestIl, + std::function<void (size_t addrSize, LowLevelILFunction& il)> addDirFlagSetIl, + std::function<void (size_t addrSize, LowLevelILFunction& il)> addDirFlagClearIl) +{ + LowLevelILLabel dirFlagSet, dirFlagClear, dirFlagDone; + + addPreTestIl(addrSize, il); + + il.AddInstruction(il.If(il.Flag(IL_FLAG_D), dirFlagSet, dirFlagClear)); + il.MarkLabel(dirFlagSet); + + addDirFlagSetIl(addrSize, il); + + il.AddInstruction(il.Goto(dirFlagDone)); + il.MarkLabel(dirFlagClear); + + addDirFlagClearIl(addrSize, il); + + il.AddInstruction(il.Goto(dirFlagDone)); + il.MarkLabel(dirFlagDone); +} + + +static void Repeat(size_t addrSize, + Instruction& instr, + LowLevelILFunction& il, + std::function<void (size_t addrSize, LowLevelILFunction& il)> addil) +{ + LowLevelILLabel trueLabel, falseLabel, doneLabel; + if (instr.flags & X86_FLAG_ANY_REP) + { + il.AddInstruction(il.Goto(trueLabel)); + il.MarkLabel(trueLabel); + il.AddInstruction(il.If(il.CompareEqual(addrSize, il.Register(addrSize, GetCountRegister(addrSize)), + il.Const(addrSize, 0)), doneLabel, falseLabel)); + il.MarkLabel(falseLabel); + } + + addil(addrSize, il); + + if (instr.flags & X86_FLAG_ANY_REP) + { + il.AddInstruction(il.SetRegister(addrSize, GetCountRegister(addrSize), + il.Sub(addrSize, il.Register(addrSize, GetCountRegister(addrSize)), + il.Const(addrSize, 1)))); + if (instr.flags & X86_FLAG_REPE) + il.AddInstruction(il.If(il.FlagCondition(LLFC_E), trueLabel, doneLabel)); + else if (instr.flags & X86_FLAG_REPNE) + il.AddInstruction(il.If(il.FlagCondition(LLFC_NE), trueLabel, doneLabel)); + else + il.AddInstruction(il.Goto(trueLabel)); + il.MarkLabel(doneLabel); + } +} + +// This is a wrapper for the x86 architecture. Its useful for extending and improving +// the existing core x86 architecture. +class x86ArchitectureExtension: public Architecture +{ + Architecture* m_arch; +public: + x86ArchitectureExtension() : Architecture("x86_extension") + { + m_arch = new CoreArchitecture(BNGetArchitectureByName("x86")); + } + + virtual size_t GetAddressSize() const override + { + return 4; + } + + virtual BNEndianness GetEndianness() const override + { + return LittleEndian; + } + + virtual bool GetInstructionInfo(const uint8_t* data, uint64_t addr, size_t maxLen, InstructionInfo& result) override + { + return m_arch->GetInstructionInfo(data, addr, maxLen, result); + } + + virtual bool GetInstructionText(const uint8_t* data, uint64_t addr, size_t& len, vector<InstructionTextToken>& result) override + { + return m_arch->GetInstructionText(data, addr, len, result); + } + + virtual bool GetInstructionLowLevelIL(const uint8_t* data, uint64_t addr, size_t& len, LowLevelILFunction& il) override + { + Instruction instr; + if (!asmx86::Disassemble32(data, addr, len, &instr)) + { + il.AddInstruction(il.Undefined()); + return false; + } + if (instr.operation == CPUID) + { + // The default implementation of CPUID doesn't set registers to constant values + // Here we'll emulate a Intel(R) Core(TM) i5-6267U CPU @ 2.90GHz with _eax set to 1 + il.AddInstruction(il.Register(4, REG_EAX)); // Reference the register so we know it is read + il.AddInstruction(il.SetRegister(4, REG_EAX, il.Const(4, 0x000406e3))); + il.AddInstruction(il.SetRegister(4, REG_EBX, il.Const(4, 0x03100800))); + il.AddInstruction(il.SetRegister(4, REG_ECX, il.Const(4, 0x7ffafbbf))); + il.AddInstruction(il.SetRegister(4, REG_EDX, il.Const(4, 0xbfebfbff))); + len = instr.length; + return true; + } + return m_arch->GetInstructionLowLevelIL(data, addr, len, il); + } + + virtual size_t GetFlagWriteLowLevelIL(BNLowLevelILOperation op, size_t size, uint32_t flagWriteType, + uint32_t flag, BNRegisterOrConstant* operands, size_t operandCount, LowLevelILFunction& il) override + { + return m_arch->GetFlagWriteLowLevelIL(op,size, flagWriteType, flag, operands, operandCount, il); + } + + virtual string GetRegisterName(uint32_t reg) override + { + return m_arch->GetRegisterName(reg); + } + + virtual string GetFlagName(uint32_t flag) override + { + return m_arch->GetFlagName(flag); + } + + virtual vector<uint32_t> GetAllFlags() override + { + return m_arch->GetAllFlags(); + } + + virtual string GetFlagWriteTypeName(uint32_t flags) override + { + return m_arch->GetFlagWriteTypeName(flags); + } + + virtual vector<uint32_t> GetAllFlagWriteTypes() override + { + return m_arch->GetAllFlagWriteTypes(); + } + + virtual BNFlagRole GetFlagRole(uint32_t flag) override + { + return m_arch->GetFlagRole(flag); + } + + virtual vector<uint32_t> GetFlagsRequiredForFlagCondition(BNLowLevelILFlagCondition cond) override + { + return m_arch->GetFlagsRequiredForFlagCondition(cond); + } + + virtual vector<uint32_t> GetFlagsWrittenByFlagWriteType(uint32_t writeType) override + { + return m_arch->GetFlagsWrittenByFlagWriteType(writeType); + } + + virtual bool IsNeverBranchPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override + { + return m_arch->IsNeverBranchPatchAvailable(data, addr, len); + } + + virtual bool IsAlwaysBranchPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override + { + return m_arch->IsAlwaysBranchPatchAvailable(data, addr, len); + } + + virtual bool IsInvertBranchPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override + { + return m_arch->IsInvertBranchPatchAvailable(data, addr, len); + } + + virtual bool IsSkipAndReturnZeroPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override + { + return m_arch->IsSkipAndReturnZeroPatchAvailable(data, addr, len); + } + + virtual bool IsSkipAndReturnValuePatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override + { + return m_arch->IsSkipAndReturnValuePatchAvailable(data, addr, len); + } + + virtual bool ConvertToNop(uint8_t* data, uint64_t addr, size_t len) override + { + return m_arch->ConvertToNop(data, addr, len); + } + + virtual bool AlwaysBranch(uint8_t* data, uint64_t addr, size_t len) override + { + return m_arch->AlwaysBranch(data, addr, len); + } + + virtual bool InvertBranch(uint8_t* data, uint64_t addr, size_t len) override + { + return m_arch->InvertBranch(data, addr, len); + } + + virtual bool SkipAndReturnValue(uint8_t* data, uint64_t addr, size_t len, uint64_t value) override + { + return m_arch->SkipAndReturnValue(data, addr, len, value); + } + + virtual vector<uint32_t> GetFullWidthRegisters() override + { + return m_arch->GetFullWidthRegisters(); + } + + virtual vector<uint32_t> GetGlobalRegisters() override + { + return m_arch->GetGlobalRegisters(); + } + + virtual vector<uint32_t> GetAllRegisters() override + { + return m_arch->GetAllRegisters(); + } + + virtual BNRegisterInfo GetRegisterInfo(uint32_t reg) override + { + return m_arch->GetRegisterInfo(reg); + } + + virtual uint32_t GetStackPointerRegister() override + { + return m_arch->GetStackPointerRegister(); + } + + virtual bool Assemble(const string& code, uint64_t addr, DataBuffer& result, string& errors) override + { + return m_arch->Assemble(code, addr, result, errors); + } +}; + + +extern "C" +{ + BINARYNINJAPLUGIN bool CorePluginInit() + { + Architecture* x86ext = new x86ArchitectureExtension(); + Architecture::Register(x86ext); + + // Register the architectures with the binary format parsers so that they know when to use + // these architectures for disassembling an executable file + BinaryViewType::RegisterArchitecture("ELF", 3, LittleEndian, x86ext); + BinaryViewType::RegisterArchitecture("PE", 0x14c, LittleEndian, x86ext); + BinaryViewType::RegisterArchitecture("Mach-O", 0x00000007, LittleEndian, x86ext); + x86ext->SetBinaryViewTypeConstant("ELF", "R_COPY", 5); + x86ext->SetBinaryViewTypeConstant("ELF", "R_JUMP_SLOT", 7); + return true; + } +} |
