Skip to content

Commit

Permalink
Workflows early preview.
Browse files Browse the repository at this point in the history
  • Loading branch information
bpotchik committed Aug 13, 2021
1 parent ac70b36 commit 801b413
Show file tree
Hide file tree
Showing 19 changed files with 1,529 additions and 3 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ This repository contains documentation and source code for the [Binary Ninja](ht

## Branches

Please note that the [dev](/Vector35/binaryninja-api/tree/dev/) branch tracks changes on the `dev` build of binary ninja and is generally the place where all pull requests should be submitted to. However, the [master](/Vector35/binaryninja-api/tree/master/) branch tracks the `stable` build of Binary Ninja which is the default version run after installation. Online [documentation](https://api.binary.ninja/) tracks the stable branch.
Please note that the [dev](/Vector35/binaryninja-api/tree/dev/) branch tracks changes on the `dev` build of binary ninja and is generally the place where all pull requests should be submitted to. However, the [master](/Vector35/binaryninja-api/tree/master/) branch tracks the `stable` build of Binary Ninja which is the default version run after installation. Online [documentation](https://api.binary.ninja/) tracks the stable branch.

## Contributing

Public contributions are welcome to this repository. All the API and documentation in this repository is licensed under an MIT license, however, the API interfaces with a closed-source commercial application, [Binary Ninja](https://binary.ninja).

If you're interested in contributing when you submit your first PR, you'll receive a notice from [CLA Assistant](https://cla-assistant.io/) that allows you to sign our [Contribution License Agreement](https://binary.ninja/cla.pdf) online.
If you're interested in contributing when you submit your first PR, you'll receive a notice from [CLA Assistant](https://cla-assistant.io/) that allows you to sign our [Contribution License Agreement](https://binary.ninja/cla.pdf) online.

## Issues

Expand Down Expand Up @@ -64,6 +64,7 @@ There are many examples available. The [Python examples folder ](https://github.
* [mlil-parser](https://github.com/Vector35/binaryninja-api/tree/dev/examples/mlil_parser) parses Medium-Level IL, demonstrating how to match types and use a visitor class (only usable with licenses that support headless API access)
* [print_syscalls](https://github.com/Vector35/binaryninja-api/tree/dev/examples/print_syscalls) is a standalone executable that prints the syscalls used in a given binary (only usable with licenses that support headless API access)
* [triage](https://github.com/Vector35/binaryninja-api/tree/dev/examples/triage) is a fully featured plugin that is shipped and enabled by default, demonstrating how to do a wide variety of tasks including extending the UI through QT
* [workflows](https://github.com/Vector35/binaryninja-api/tree/dev/examples/workflows) is a collection of plugins that demonstrate using Workflows to extend the analysis pipeline
* [x86 extension](https://github.com/Vector35/binaryninja-api/tree/dev/examples/x86_extension) creates an architecture extension which shows how to modify the behavior of the build-in architectures without creating a complete replacement

## Licensing
Expand Down
41 changes: 41 additions & 0 deletions activity.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "binaryninjaapi.h"
#include <string>

using namespace BinaryNinja;
using namespace std;


Activity::Activity(const string& name, const std::function<void(Ref<AnalysisContext> analysisContext)>& action): m_action(action)
{
//LogError("API-Side Activity Constructed!");
m_object = BNCreateActivity(name.c_str(), this, Run);
}


Activity::Activity(BNActivity* activity)
{
m_object = BNNewActivityReference(activity);
}


Activity::~Activity()
{
//LogError("API-Side Activity Destructed!");
}


void Activity::Run(void* ctxt, BNAnalysisContext* analysisContext)
{
Activity* activity = (Activity*)ctxt;
Ref<AnalysisContext> ac = new AnalysisContext(BNNewAnalysisContextReference(analysisContext));
activity->m_action(ac);
}


string Activity::GetName() const
{
char* name = BNActivityGetName(m_object);
string result = name;
BNFreeString(name);
return result;
}
102 changes: 102 additions & 0 deletions binaryninjaapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include <atomic>
#include <memory>
#include <cstdint>
#include <type_traits>
#include <variant>
#include "binaryninjacore.h"
#include "json/json.h"

Expand Down Expand Up @@ -540,6 +542,7 @@ namespace BinaryNinja
class BackgroundTask;
class Platform;
class Settings;
class Workflow;
class Type;
class DataBuffer;
class MainThreadAction;
Expand Down Expand Up @@ -1945,6 +1948,8 @@ __attribute__ ((format (printf, 1, 2)))

void Reanalyze();

Ref<Workflow> GetWorkflow() const;

void ShowPlainTextReport(const std::string& title, const std::string& contents);
void ShowMarkdownReport(const std::string& title, const std::string& contents, const std::string& plainText);
void ShowHTMLReport(const std::string& title, const std::string& contents, const std::string& plainText);
Expand Down Expand Up @@ -3087,6 +3092,101 @@ __attribute__ ((format (printf, 1, 2)))
EnumerationBuilder& ReplaceMember(size_t idx, const std::string& name, uint64_t value);
};

#if ((__cplusplus >= 201403L) || (_MSVC_LANG >= 201703L))
template <class... Ts> struct overload : Ts... { using Ts::operator()...; };
template <class... Ts> overload(Ts...) -> overload<Ts...>;
#endif

class AnalysisContext: public CoreRefCountObject<BNAnalysisContext, BNNewAnalysisContextReference, BNFreeAnalysisContext>
{
std::unique_ptr<Json::CharReader> m_reader;
Json::StreamWriterBuilder m_builder;

public:
AnalysisContext(BNAnalysisContext* analysisContext);
virtual ~AnalysisContext();

Ref<Function> GetFunction();
Ref<LowLevelILFunction> GetLowLevelILFunction();
Ref<MediumLevelILFunction> GetMediumLevelILFunction();

void SetLowLevelILFunction(Ref<LowLevelILFunction> lowLevelIL);

bool Inform(const std::string& request);

#if ((__cplusplus >= 201403L) || (_MSVC_LANG >= 201703L))
template <typename... Args>
bool Inform(Args... args)
{
//using T = std::variant<Args...>; // FIXME: remove type duplicates
using T = std::variant<std::string, const char*, uint64_t, Ref<Architecture>>;
std::vector<T> unpackedArgs {args...};
Json::Value request(Json::arrayValue);
for (auto& arg : unpackedArgs)
std::visit(overload {
[&](Ref<Architecture> arch) { request.append(Json::Value(arch->GetName())); },
[&](uint64_t val) { request.append(Json::Value(val)); },
[&](auto& val) { request.append(Json::Value(std::forward<decltype(val)>(val))); }
}, arg);

return Inform(Json::writeString(m_builder, request));
}
#endif
};

class Activity: public CoreRefCountObject<BNActivity, BNNewActivityReference, BNFreeActivity>
{
protected:
std::function<void(Ref<AnalysisContext> analysisContext)> m_action;

static void Run(void* ctxt, BNAnalysisContext* analysisContext);

public:
Activity(const std::string& name, const std::function<void(Ref<AnalysisContext>)>& action);
Activity(BNActivity* activity);
virtual ~Activity();

std::string GetName() const;
};

class Workflow: public CoreRefCountObject<BNWorkflow, BNNewWorkflowReference, BNFreeWorkflow>
{
public:
Workflow(const std::string& name = "");
Workflow(BNWorkflow* workflow);
virtual ~Workflow() { }

static std::vector<Ref<Workflow>> GetList();
static Ref<Workflow> Instance(const std::string& name = "");
static bool RegisterWorkflow(Ref<Workflow> workflow, const std::string& description = "");

Ref<Workflow> Clone(const std::string& name, const std::string& activity = "");
bool RegisterActivity(Ref<Activity> activity, const std::string& description = "");
bool RegisterActivity(Ref<Activity> activity, std::initializer_list<const char*> initializer) { return RegisterActivity(activity, std::vector<std::string>(initializer.begin(), initializer.end())); }
bool RegisterActivity(Ref<Activity> activity, const std::vector<std::string>& subactivities, const std::string& description = "");

bool Contains(const std::string& activity);
std::string GetConfiguration(const std::string& activity = "");
std::string GetName() const;
bool IsRegistered() const;
size_t Size() const;

Ref<Activity> GetActivity(const std::string& activity);
std::vector<std::string> GetActivityRoots(const std::string& activity = "");
std::vector<std::string> GetSubactivities(const std::string& activity = "", bool immediate = true);
bool AssignSubactivities(const std::string& activity, const std::vector<std::string>& subactivities = {});
bool Clear();
bool Insert(const std::string& activity, const std::string& newActivity);
bool Insert(const std::string& activity, const std::vector<std::string>& activities);
bool Remove(const std::string& activity);
bool Replace(const std::string& activity, const std::string& newActivity);

Ref<FlowGraph> GetGraph(const std::string& activity = "", bool sequential = false);
void ShowReport(const std::string& name);

//bool Run(const std::string& activity, Ref<AnalysisContext> analysisContext);
};

class DisassemblySettings: public CoreRefCountObject<BNDisassemblySettings,
BNNewDisassemblySettingsReference, BNFreeDisassemblySettings>
{
Expand Down Expand Up @@ -3501,6 +3601,8 @@ __attribute__ ((format (printf, 1, 2)))

void Reanalyze();

Ref<Workflow> GetWorkflow() const;

void RequestAdvancedAnalysisData();
void ReleaseAdvancedAnalysisData();
void ReleaseAdvancedAnalysisData(size_t count);
Expand Down
66 changes: 66 additions & 0 deletions binaryninjacore.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ extern "C"
struct BNEnumerationBuilder;
struct BNCallingConvention;
struct BNPlatform;
struct BNActivity;
struct BNAnalysisContext;
struct BNWorkflow;
struct BNAnalysisCompletionEvent;
struct BNDisassemblySettings;
struct BNSaveSettings;
Expand Down Expand Up @@ -2130,6 +2133,16 @@ extern "C"
BNPossibleValueSet value;
};

enum BNWorkflowState
{
WorkflowInitial,
WorkflowIdle,
WorkflowRun,
WorkflowHalt,
WorkflowHold,
WorkflowInvalid
};

enum BNAnalysisState
{
InitialState,
Expand Down Expand Up @@ -3818,6 +3831,9 @@ __attribute__ ((format (printf, 1, 2)))
BINARYNINJACOREAPI void BNReanalyzeAllFunctions(BNBinaryView* view);
BINARYNINJACOREAPI void BNReanalyzeFunction(BNFunction* func);

BINARYNINJACOREAPI BNWorkflow* BNGetWorkflowForBinaryView(BNBinaryView* view);
BINARYNINJACOREAPI BNWorkflow* BNGetWorkflowForFunction(BNFunction* func);

BINARYNINJACOREAPI BNHighlightColor BNGetInstructionHighlight(BNFunction* func, BNArchitecture* arch, uint64_t addr);
BINARYNINJACOREAPI void BNSetAutoInstructionHighlight(BNFunction* func, BNArchitecture* arch, uint64_t addr,
BNHighlightColor color);
Expand Down Expand Up @@ -3961,6 +3977,56 @@ __attribute__ ((format (printf, 1, 2)))
BINARYNINJACOREAPI void BNFreeVariableList(BNVariable* vars);
BINARYNINJACOREAPI void BNFreeVariableReferenceSourceList(BNVariableReferenceSource* vars, size_t count);

// Analysis Context
BINARYNINJACOREAPI BNAnalysisContext* BNCreateAnalysisContext(void);
BINARYNINJACOREAPI BNAnalysisContext* BNNewAnalysisContextReference(BNAnalysisContext* analysisContext);
BINARYNINJACOREAPI void BNFreeAnalysisContext(BNAnalysisContext* analysisContext);
BINARYNINJACOREAPI BNFunction* BNAnalysisContextGetFunction(BNAnalysisContext* analysisContext);
BINARYNINJACOREAPI BNLowLevelILFunction* BNAnalysisContextGetLowLevelILFunction(BNAnalysisContext* analysisContext);
BINARYNINJACOREAPI BNMediumLevelILFunction* BNAnalysisContextGetMediumLevelILFunction(BNAnalysisContext* analysisContext);
BINARYNINJACOREAPI void BNSetLowLevelILFunction(BNAnalysisContext* analysisContext, BNLowLevelILFunction* lowLevelIL);
BINARYNINJACOREAPI bool BNAnalysisContextInform(BNAnalysisContext* analysisContext, const char* request);

// Activity
BINARYNINJACOREAPI BNActivity* BNCreateActivity(const char* name, void* ctxt, void (*action)(void*, BNAnalysisContext*));
BINARYNINJACOREAPI BNActivity* BNNewActivityReference(BNActivity* activity);
BINARYNINJACOREAPI void BNFreeActivity(BNActivity* activity);

BINARYNINJACOREAPI char* BNActivityGetName(BNActivity* activity);

// Workflow
BINARYNINJACOREAPI BNWorkflow* BNCreateWorkflow(const char* name);
BINARYNINJACOREAPI BNWorkflow* BNNewWorkflowReference(BNWorkflow* workflow);
BINARYNINJACOREAPI void BNFreeWorkflow(BNWorkflow* workflow);

BINARYNINJACOREAPI BNWorkflow** BNGetWorkflowList(size_t* count);
BINARYNINJACOREAPI void BNFreeWorkflowList(BNWorkflow** workflows, size_t count);
BINARYNINJACOREAPI BNWorkflow* BNWorkflowInstance(const char* name);
BINARYNINJACOREAPI bool BNRegisterWorkflow(BNWorkflow* workflow, const char* description);

BINARYNINJACOREAPI BNWorkflow* BNWorkflowClone(BNWorkflow* workflow, const char* name, const char* activity);
BINARYNINJACOREAPI bool BNWorkflowRegisterActivity(BNWorkflow* workflow, BNActivity* activity, const char** subactivities, size_t size, const char* description);

BINARYNINJACOREAPI bool BNWorkflowContains(BNWorkflow* workflow, const char* activity);
BINARYNINJACOREAPI char* BNWorkflowGetConfiguration(BNWorkflow* workflow, const char* activity);
BINARYNINJACOREAPI char* BNGetWorkflowName(BNWorkflow* workflow);
BINARYNINJACOREAPI bool BNWorkflowIsRegistered(BNWorkflow* workflow);
BINARYNINJACOREAPI size_t BNWorkflowSize(BNWorkflow* workflow);

BINARYNINJACOREAPI BNActivity* BNWorkflowGetActivity(BNWorkflow* workflow, const char* activity);
BINARYNINJACOREAPI const char** BNWorkflowGetActivityRoots(BNWorkflow* workflow, const char* activity, size_t* inoutSize);
BINARYNINJACOREAPI const char** BNWorkflowGetSubactivities(BNWorkflow* workflow, const char* activity, bool immediate, size_t* inoutSize);
BINARYNINJACOREAPI bool BNWorkflowAssignSubactivities(BNWorkflow* workflow, const char* activity, const char** activities, size_t size);
BINARYNINJACOREAPI bool BNWorkflowClear(BNWorkflow* workflow);
BINARYNINJACOREAPI bool BNWorkflowInsert(BNWorkflow* workflow, const char* activity, const char** activities, size_t size);
BINARYNINJACOREAPI bool BNWorkflowRemove(BNWorkflow* workflow, const char* activity);
BINARYNINJACOREAPI bool BNWorkflowReplace(BNWorkflow* workflow, const char* activity, const char* newActivity);

BINARYNINJACOREAPI BNFlowGraph* BNWorkflowGetGraph(BNWorkflow* workflow, const char* activity, bool sequential);
BINARYNINJACOREAPI void BNWorkflowShowReport(BNWorkflow* workflow, const char* name);

//BINARYNINJACOREAPI bool BNWorkflowRun(const char* activity, BNAnalysisContext* analysisContext);

// Disassembly settings
BINARYNINJACOREAPI BNDisassemblySettings* BNCreateDisassemblySettings(void);
BINARYNINJACOREAPI BNDisassemblySettings* BNNewDisassemblySettingsReference(BNDisassemblySettings* settings);
Expand Down
9 changes: 9 additions & 0 deletions binaryview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3327,6 +3327,15 @@ void BinaryView::Reanalyze()
}


Ref<Workflow> BinaryView::GetWorkflow() const
{
BNWorkflow* workflow = BNGetWorkflowForBinaryView(m_object);
if (!workflow)
return nullptr;
return new Workflow(workflow);
}


void BinaryView::ShowPlainTextReport(const string& title, const string& contents)
{
BNShowPlainTextReport(m_object, title.c_str(), contents.c_str());
Expand Down
5 changes: 5 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,9 @@ add_subdirectory(print_syscalls)
if(NOT HEADLESS)
add_subdirectory(uinotification)
endif()
if(NOT DEMO AND NOT PERSONAL)
add_subdirectory(workflows/inliner)
add_subdirectory(workflows/objectivec)
add_subdirectory(workflows/tailcall)
endif()
add_subdirectory(x86_extension)
39 changes: 39 additions & 0 deletions examples/workflows/inliner/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)

project(workflow_inliner)

if((NOT BN_API_PATH) AND (NOT BN_INTERNAL_BUILD))
set(BN_API_PATH $ENV{BN_API_PATH})
if(NOT BN_API_PATH)
message(FATAL_ERROR "Provide path to Binary Ninja API source in BN_API_PATH")
endif()
endif()
if(NOT BN_INTERNAL_BUILD)
add_subdirectory(${BN_API_PATH} ${PROJECT_BINARY_DIR}/api)
endif()

file(GLOB SOURCES
*.cpp
*.c
*.h)

add_library(workflow_inliner SHARED ${SOURCES})

target_link_libraries(workflow_inliner binaryninjaapi)

set_target_properties(workflow_inliner PROPERTIES
CXX_STANDARD 17
CXX_VISIBILITY_PRESET hidden
CXX_STANDARD_REQUIRED ON
C_STANDARD 99
C_STANDARD_REQUIRED ON
C_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN ON
POSITION_INDEPENDENT_CODE ON)

if(BN_INTERNAL_BUILD)
plugin_rpath(workflow_inliner)
set_target_properties(workflow_inliner PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR}
RUNTIME_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR})
endif()
Loading

0 comments on commit 801b413

Please sign in to comment.