summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2024-05-22 20:06:24 -0400
committerMason Reed <mason@vector35.com>2024-05-22 20:22:44 -0400
commitdff192e3bd6d5737633a740988c31e4ecba92998 (patch)
tree39dfd844e8c35c0af37e917f97abeabf568c8d72
parent331d226464fb043a12eada4f4c752d8ef20c5efb (diff)
Add background task example plugin
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
-rw-r--r--README.md1
-rw-r--r--binaryninjaapi.h16
-rw-r--r--examples/CMakeLists.txt1
-rw-r--r--examples/background_task/CMakeLists.txt36
-rw-r--r--examples/background_task/src/backgroundtask.cpp80
5 files changed, 132 insertions, 2 deletions
diff --git a/README.md b/README.md
index 2d35380a..b0c0caa1 100644
--- a/README.md
+++ b/README.md
@@ -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.\*
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index 364eb564..d2cf74d2 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -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;
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 8a831b46..790815c3 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,3 +1,4 @@
+add_subdirectory(background_task)
add_subdirectory(bin-info)
add_subdirectory(breakpoint)
add_subdirectory(cmdline_disasm)
diff --git a/examples/background_task/CMakeLists.txt b/examples/background_task/CMakeLists.txt
new file mode 100644
index 00000000..36e012b0
--- /dev/null
+++ b/examples/background_task/CMakeLists.txt
@@ -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})
diff --git a/examples/background_task/src/backgroundtask.cpp b/examples/background_task/src/backgroundtask.cpp
new file mode 100644
index 00000000..8a307080
--- /dev/null
+++ b/examples/background_task/src/backgroundtask.cpp
@@ -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;
+ }
+}