Skip to content

Commit

Permalink
Add background task example plugin
Browse files Browse the repository at this point in the history
Clarify BackgroundTask functionality (skip-note, skip-ci)

Providing clear documentation so it is understood that background tasks do not manage the execution of said the task.

Add background_task plugin to examples section
  • Loading branch information
emesare committed May 23, 2024
1 parent 331d226 commit dff192e
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ In addition to the default build setup, you may want to:

There are many examples available. The [Python examples folder](https://github.com/Vector35/binaryninja-api/tree/dev/python/examples) demonstrates many different applications of the Python API, while C++ examples include:

- [background_task](https://github.com/Vector35/binaryninja-api/tree/dev/examples/background_task) is a plugin that demonstrates managing a background task.\*
- [bin-info](https://github.com/Vector35/binaryninja-api/tree/dev/examples/bin-info) is a standalone executable that prints some information about a given binary to the terminal.\*
- [breakpoint](https://github.com/Vector35/binaryninja-api/tree/dev/examples/breakpoint) is a plugin that allows you to select a region within an x86 binary and use the context menu to fill it with breakpoint bytes.
- [command-line disassm](https://github.com/Vector35/binaryninja-api/tree/dev/examples/cmdline_disasm) demonstrates how to dump disassembly to the command line.\*
Expand Down
16 changes: 14 additions & 2 deletions binaryninjaapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -15513,8 +15513,20 @@ namespace BinaryNinja {
public CoreRefCountObject<BNBackgroundTask, BNNewBackgroundTaskReference, BNFreeBackgroundTask>
{
public:
BackgroundTask(BNBackgroundTask* task);
BackgroundTask(const std::string& initialText, bool canCancel);
BackgroundTask(BNBackgroundTask *task);

/*!
Provides a mechanism for reporting progress of
an optionally cancelable task to the user via the status bar in the UI.
If canCancel is is `True`, then the task can be cancelled either
programmatically or by the user via the UI.

\note This API does not provide a means to execute a task. The caller is responsible to execute (and possibly cancel) the task.

\param initialText Text description of the progress of the background task (displayed in status bar of the UI)
\param canCancel Whether the task can be cancelled
*/
BackgroundTask(const std::string &initialText, bool canCancel);

bool CanCancel() const;
bool IsCancelled() const;
Expand Down
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
add_subdirectory(background_task)
add_subdirectory(bin-info)
add_subdirectory(breakpoint)
add_subdirectory(cmdline_disasm)
Expand Down
36 changes: 36 additions & 0 deletions examples/background_task/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
cmake_minimum_required(VERSION 3.13 FATAL_ERROR)

project(background_task CXX C)

file(GLOB SOURCES
src/*.cpp
src/*.h)

add_library(background_task SHARED ${SOURCES})

if(NOT BN_API_BUILD_EXAMPLES AND NOT BN_INTERNAL_BUILD)
# Out-of-tree build
find_path(
BN_API_PATH
NAMES binaryninjaapi.h
HINTS ../.. binaryninjaapi $ENV{BN_API_PATH}
REQUIRED
)
add_subdirectory(${BN_API_PATH} api)
endif()

target_link_libraries(background_task binaryninjaui)

set_target_properties(background_task PROPERTIES
CXX_STANDARD 17
CXX_VISIBILITY_PRESET hidden
CXX_STANDARD_REQUIRED ON
VISIBILITY_INLINES_HIDDEN ON
POSITION_INDEPENDENT_CODE ON
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out/bin)

if(BN_INTERNAL_BUILD)
ui_plugin_rpath(background_task)
endif()

bn_install_plugin(${PROJECT_NAME})
80 changes: 80 additions & 0 deletions examples/background_task/src/backgroundtask.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include <thread>
#include <random>

#include "binaryninjaapi.h"

using namespace BinaryNinja;

static Ref<BackgroundTask> inspireBackgroundTask = nullptr;

uint64_t InspireWriteCallback(uint8_t *data, uint64_t len, void *ctxt)
{
try
{
Json::Value json;
std::unique_ptr<Json::CharReader> reader(Json::CharReaderBuilder().newCharReader());
std::string errors;
if (!reader->parse((char *) data, (char *) data + len, &json, &errors))
{
LogError("Failed to parse! %s", errors.c_str());
}
else
{
std::random_device rd;
std::map<int, int> hist;
std::uniform_int_distribution<Json::ArrayIndex> dist(0, json.size());
auto randQuoteObj = json.get(dist(rd), 0);
if (randQuoteObj.isObject() && randQuoteObj.size() == 2)
{
std::string quote = randQuoteObj.get("text", Json::Value("INVALID")).asString();
LogInfo("%s", quote.c_str());
// Display quote in progress text for 3 seconds.
inspireBackgroundTask->SetProgressText(quote);
std::this_thread::sleep_for(std::chrono::seconds(3));
}
}
} catch (Json::Exception e)
{
LogError("JSON exception! %s", e.m_message.c_str());
inspireBackgroundTask->Cancel();
}
return len;
}

bool InspireProgressCallback(void *ctxt, uint64_t progress, uint64_t total)
{
// Close connection on cancellation
return !inspireBackgroundTask->IsCancelled();
}

void Inspire(BinaryView *bv)
{
inspireBackgroundTask = new BackgroundTask("Getting inspired!", true);
std::thread inspireThread([]() {
LogInfo("Getting inspired!");
BNDownloadInstanceOutputCallbacks outputCallbacks;
memset(&outputCallbacks, 0, sizeof(outputCallbacks));
outputCallbacks.writeCallback = InspireWriteCallback;
outputCallbacks.progressCallback = InspireProgressCallback;

auto downloadProvider = DownloadProvider::GetByName("CoreDownloadProvider");
auto downloadInstance = downloadProvider->CreateNewInstance();
inspireBackgroundTask->SetProgressText("Waiting for inspiration...");
if (downloadInstance->PerformRequest("https://type.fit/api/quotes", &outputCallbacks))
LogError("Inspiration failed!");

inspireBackgroundTask->Finish();
});
inspireThread.detach();
}

extern "C" {
BN_DECLARE_CORE_ABI_VERSION

BINARYNINJAPLUGIN bool CorePluginInit()
{
PluginCommand::Register("Inspire me!", "Print an inspirational quote to the log", Inspire);

return true;
}
}

0 comments on commit dff192e

Please sign in to comment.