diff options
| author | Glenn Smith <glenn@vector35.com> | 2021-08-23 19:05:09 -0400 |
|---|---|---|
| committer | Glenn Smith <glenn@vector35.com> | 2021-11-18 21:37:52 -0500 |
| commit | 994a42659dc500f602e83f91501ec4a959481fa5 (patch) | |
| tree | ca783900c9a6d41dbdd98a1cd66a083d3e886578 | |
| parent | 60f2ecd9d1961f7cd700e01f802bcf640c9d50e0 (diff) | |
Enterprise apis and support
Also secrets provider + openUrl
| -rw-r--r-- | binaryninjaapi.h | 77 | ||||
| -rw-r--r-- | binaryninjacore.h | 42 | ||||
| -rw-r--r-- | downloadprovider.cpp | 20 | ||||
| -rw-r--r-- | http.cpp | 59 | ||||
| -rw-r--r-- | http.h | 125 | ||||
| -rw-r--r-- | interaction.cpp | 14 | ||||
| -rw-r--r-- | python/CMakeLists.txt | 19 | ||||
| -rw-r--r-- | python/__init__.py | 11 | ||||
| -rw-r--r-- | python/enterprise.py | 189 | ||||
| -rw-r--r-- | python/generator.cpp | 5 | ||||
| -rw-r--r-- | python/interaction.py | 24 | ||||
| -rw-r--r-- | secretsprovider.cpp | 141 | ||||
| -rw-r--r-- | ui/uitypes.h | 1 |
13 files changed, 637 insertions, 90 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index dd443c80..629b8b31 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -37,6 +37,7 @@ #include <cstdint> #include <type_traits> #include <variant> +#include <optional> #include "binaryninjacore.h" #include "json/json.h" @@ -730,6 +731,8 @@ __attribute__ ((format (printf, 1, 2))) BNMessageBoxButtonResult ShowMessageBox(const std::string& title, const std::string& text, BNMessageBoxButtonSet buttons = OKButtonSet, BNMessageBoxIcon icon = InformationIcon); + bool OpenUrl(const std::string& url); + /*! Split a single progress function into equally sized subparts. This function takes the original progress function and returns a new function whose signature @@ -5722,6 +5725,7 @@ __attribute__ ((format (printf, 1, 2))) virtual BNMessageBoxButtonResult ShowMessageBox(const std::string& title, const std::string& text, BNMessageBoxButtonSet buttons = OKButtonSet, BNMessageBoxIcon icon = InformationIcon) = 0; + virtual bool OpenUrl(const std::string& url) = 0; }; typedef BNPluginOrigin PluginOrigin; @@ -6218,5 +6222,78 @@ __attribute__ ((format (printf, 1, 2))) virtual bool IsValid(Ref<BinaryView>) = 0; virtual void ParseInfo(Ref<DebugInfo>, Ref<BinaryView>) = 0; }; + + /*! + Class for storing secrets (e.g. tokens) in a system-specific manner + */ + class SecretsProvider: public StaticCoreRefCountObject<BNSecretsProvider> + { + std::string m_nameForRegister; + + protected: + SecretsProvider(const std::string& name); + SecretsProvider(BNSecretsProvider* provider); + + static bool HasDataCallback(void* ctxt, const char* key); + static char* GetDataCallback(void* ctxt, const char* key); + static bool StoreDataCallback(void* ctxt, const char* key, const char* data); + static bool DeleteDataCallback(void* ctxt, const char* key); + + public: + /*! + Check if data for a specific key exists, but do not retrieve it + \param key Key for data + \return True if data exists + */ + virtual bool HasData(const std::string& key) = 0; + /*! + Retrieve data for the given key, if it exists + \param key Key for data + \return Optional with data, if it exists, or empty optional if it does not exist + or otherwise could not be retrieved. + */ + virtual std::optional<std::string> GetData(const std::string& key) = 0; + /*! + Store data with the given key + \param key Key for data + \param data Data to store + \return True if the data was stored + */ + virtual bool StoreData(const std::string& key, const std::string& data) = 0; + /*! + Delete stored data with the given key + \param key Key for data + \return True if it was deleted + */ + virtual bool DeleteData(const std::string& key) = 0; + + /*! + Retrieve the list of providers + \return A list of registered providers + */ + static std::vector<Ref<SecretsProvider>> GetList(); + /*! + Retrieve a provider by name + \param name Name of provider + \return Provider object, if one with the given name is regestered, or nullptr if not + */ + static Ref<SecretsProvider> GetByName(const std::string& name); + /*! + Register a new provider + \param provider New provider to register + */ + static void Register(SecretsProvider* provider); + }; + + class CoreSecretsProvider: public SecretsProvider + { + public: + CoreSecretsProvider(BNSecretsProvider* provider); + + virtual bool HasData(const std::string& key) override; + virtual std::optional<std::string> GetData(const std::string& key) override; + virtual bool StoreData(const std::string& key, const std::string& data) override; + virtual bool DeleteData(const std::string& key) override; + }; } diff --git a/binaryninjacore.h b/binaryninjacore.h index 6b95c459..1e424ccb 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -222,6 +222,7 @@ extern "C" struct BNLinearViewCursor; struct BNDebugInfo; struct BNDebugInfoParser; + struct BNSecretsProvider; //! Console log levels @@ -2439,6 +2440,7 @@ extern "C" bool (*getFormInput)(void* ctxt, BNFormInputField* fields, size_t count, const char* title); BNMessageBoxButtonResult (*showMessageBox)(void* ctxt, const char* title, const char* text, BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon); + bool (*openUrl)(void* ctxt, const char* url); }; struct BNObjectDestructionCallbacks @@ -2651,6 +2653,15 @@ extern "C" BNPlatform* platform; }; + struct BNSecretsProviderCallbacks + { + void* context; + bool (*hasData)(void* ctxt, const char* key); + char* (*getData)(void* ctxt, const char* key); + bool (*storeData)(void* ctxt, const char* key, const char* data); + bool (*deleteData)(void* ctxt, const char* key); + }; + BINARYNINJACOREAPI char* BNAllocString(const char* contents); BINARYNINJACOREAPI void BNFreeString(char* str); BINARYNINJACOREAPI char** BNAllocStringList(const char** contents, size_t size); @@ -2674,6 +2685,23 @@ extern "C" BINARYNINJACOREAPI bool BNIsUIEnabled(void); BINARYNINJACOREAPI void BNSetLicense(const char* licenseData); + BINARYNINJACOREAPI bool BNAuthenticateEnterpriseServerWithCredentials(const char* username, const char* password); + BINARYNINJACOREAPI bool BNAuthenticateEnterpriseServerWithMethod(const char* method); + BINARYNINJACOREAPI size_t BNGetEnterpriseServerAuthenticationMethods(char*** methods, char*** names); + BINARYNINJACOREAPI bool BNDeauthenticateEnterpriseServer(void); + BINARYNINJACOREAPI void BNCancelEnterpriseServerAuthentication(void); + BINARYNINJACOREAPI bool BNConnectEnterpriseServer(void); + BINARYNINJACOREAPI bool BNAcquireEnterpriseServerLicense(uint64_t timeout, bool cached); + BINARYNINJACOREAPI bool BNReleaseEnterpriseServerLicense(void); + BINARYNINJACOREAPI bool BNIsEnterpriseServerConnected(void); + BINARYNINJACOREAPI bool BNIsEnterpriseServerAuthenticated(void); + BINARYNINJACOREAPI char* BNGetEnterpriseServerUsername(void); + BINARYNINJACOREAPI uint64_t BNGetEnterpriseServerLicenseExpirationTime(void); + BINARYNINJACOREAPI uint64_t BNGetEnterpriseServerLicenseDuration(void); + BINARYNINJACOREAPI uint64_t BNGetEnterpriseServerReservationTimeLimit(void); + BINARYNINJACOREAPI bool BNIsEnterpriseServerLicenseStillActivated(void); + BINARYNINJACOREAPI char* BNGetEnterpriseServerLastError(void); + BINARYNINJACOREAPI void BNRegisterObjectDestructionCallbacks(BNObjectDestructionCallbacks* callbacks); BINARYNINJACOREAPI void BNUnregisterObjectDestructionCallbacks(BNObjectDestructionCallbacks* callbacks); @@ -5245,6 +5273,7 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI void BNFreeFormInputResults(BNFormInputField* fields, size_t count); BINARYNINJACOREAPI BNMessageBoxButtonResult BNShowMessageBox(const char* title, const char* text, BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon); + BINARYNINJACOREAPI bool BNOpenUrl(const char* url); BINARYNINJACOREAPI BNReportCollection* BNCreateReportCollection(void); BINARYNINJACOREAPI BNReportCollection* BNNewReportCollectionReference(BNReportCollection* reports); @@ -5573,6 +5602,19 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI bool BNAddDebugDataVariable(BNDebugInfo* const debugInfo, uint64_t address, const BNType* const type, const char* name); BINARYNINJACOREAPI BNDataVariableAndName* BNGetDebugDataVariables(BNDebugInfo* const debugInfo, const char* const name, size_t* count); + // Secrets providers + BINARYNINJACOREAPI BNSecretsProvider* BNRegisterSecretsProvider(const char* name, BNSecretsProviderCallbacks* callbacks); + BINARYNINJACOREAPI BNSecretsProvider** BNGetSecretsProviderList(size_t* count); + BINARYNINJACOREAPI void BNFreeSecretsProviderList(BNSecretsProvider** providers); + BINARYNINJACOREAPI BNSecretsProvider* BNGetSecretsProviderByName(const char* name); + + BINARYNINJACOREAPI char* BNGetSecretsProviderName(BNSecretsProvider* provider); + + BINARYNINJACOREAPI bool BNSecretsProviderHasData(BNSecretsProvider* provider, const char* key); + BINARYNINJACOREAPI char* BNGetSecretsProviderData(BNSecretsProvider* provider, const char* key); + BINARYNINJACOREAPI bool BNStoreSecretsProviderData(BNSecretsProvider* provider, const char* key, const char* data); + BINARYNINJACOREAPI bool BNDeleteSecretsProviderData(BNSecretsProvider* provider, const char* key); + #ifdef __cplusplus } #endif diff --git a/downloadprovider.cpp b/downloadprovider.cpp index d54a85e3..99c6c7c2 100644 --- a/downloadprovider.cpp +++ b/downloadprovider.cpp @@ -1,3 +1,23 @@ +// Copyright (c) 2015-2021 Vector 35 Inc +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + #include "binaryninjaapi.h" using namespace BinaryNinja; @@ -24,10 +24,22 @@ #include <math.h> #include "http.h" +#ifdef BINARYNINJACORE_LIBRARY +#include "log.h" +#endif + +#ifdef BINARYNINJACORE_LIBRARY +using namespace BinaryNinjaCore; +#else using namespace BinaryNinja; using namespace std; +#endif +#ifdef BINARYNINJACORE_LIBRARY +namespace BinaryNinjaCore::Http +#else namespace BinaryNinja::Http +#endif { #define HTTP_MAX_RETRIES 3 #define HTTP_BACKOFF_FACTOR 1 @@ -167,7 +179,7 @@ namespace BinaryNinja::Http vector<uint8_t> MultipartEncode(const vector<MultipartField>& fields, string& boundary) { - boundary = string(4, '-') + "MultipartFormBoundary" + GetUniqueIdentifierString(); + boundary = string(4, '-') + "MultipartFormBoundary" + (string)BNGetUniqueIdentifierString(); vector<uint8_t> boundaryVec; boundaryVec.reserve(boundary.size()); @@ -223,8 +235,8 @@ namespace BinaryNinja::Http Request::Request(string method, string url, unordered_map<string, string> headers, vector<pair<string, string>> params, - function<bool(size_t, size_t)> downloadProgress, - function<bool(size_t, size_t)> uploadProgress): + std::function<bool(size_t, size_t)> downloadProgress, + std::function<bool(size_t, size_t)> uploadProgress): m_method(method), m_url(url), m_headers(headers), m_downloadProgress(downloadProgress), m_uploadProgress(uploadProgress) { @@ -249,8 +261,8 @@ namespace BinaryNinja::Http unordered_map<string, string> headers, vector<pair<string, string>> params, vector<uint8_t> body, - function<bool(size_t, size_t)> downloadProgress, - function<bool(size_t, size_t)> uploadProgress): + std::function<bool(size_t, size_t)> downloadProgress, + std::function<bool(size_t, size_t)> uploadProgress): m_method(method), m_url(url), m_headers(headers), m_body(body), m_downloadProgress(downloadProgress), m_uploadProgress(uploadProgress) { @@ -275,8 +287,8 @@ namespace BinaryNinja::Http unordered_map<string, string> headers, vector<pair<string, string>> params, vector<pair<string, string>> formFields, - function<bool(size_t, size_t)> downloadProgress, - function<bool(size_t, size_t)> uploadProgress): + std::function<bool(size_t, size_t)> downloadProgress, + std::function<bool(size_t, size_t)> uploadProgress): m_method(method), m_url(url), m_headers(headers), m_downloadProgress(downloadProgress), m_uploadProgress(uploadProgress) { @@ -305,8 +317,8 @@ namespace BinaryNinja::Http unordered_map<string, string> headers, vector<pair<string, string>> params, vector<MultipartField> formFields, - function<bool(size_t, size_t)> downloadProgress, - function<bool(size_t, size_t)> uploadProgress): + std::function<bool(size_t, size_t)> downloadProgress, + std::function<bool(size_t, size_t)> uploadProgress): m_method(method), m_url(url), m_headers(headers), m_downloadProgress(downloadProgress), m_uploadProgress(uploadProgress) { @@ -335,8 +347,8 @@ namespace BinaryNinja::Http Request Request::Get(string url, unordered_map<string, string> headers, vector<pair<string, string>> params, - function<bool(size_t, size_t)> downloadProgress, - function<bool(size_t, size_t)> uploadProgress) + std::function<bool(size_t, size_t)> downloadProgress, + std::function<bool(size_t, size_t)> uploadProgress) { return Request("GET", url, headers, params, downloadProgress, uploadProgress); } @@ -346,8 +358,8 @@ namespace BinaryNinja::Http unordered_map<string, string> headers, vector<pair<string, string>> params, vector<uint8_t> body, - function<bool(size_t, size_t)> downloadProgress, - function<bool(size_t, size_t)> uploadProgress) + std::function<bool(size_t, size_t)> downloadProgress, + std::function<bool(size_t, size_t)> uploadProgress) { return Request("POST", url, headers, params, body, downloadProgress, uploadProgress); } @@ -357,8 +369,8 @@ namespace BinaryNinja::Http unordered_map<string, string> headers, vector<pair<string, string>> params, vector<pair<string, string>> formFields, - function<bool(size_t, size_t)> downloadProgress, - function<bool(size_t, size_t)> uploadProgress) + std::function<bool(size_t, size_t)> downloadProgress, + std::function<bool(size_t, size_t)> uploadProgress) { return Request("POST", url, headers, params, formFields, downloadProgress, uploadProgress); } @@ -368,8 +380,8 @@ namespace BinaryNinja::Http unordered_map<string, string> headers, vector<pair<string, string>> params, vector<MultipartField> formFields, - function<bool(size_t, size_t)> downloadProgress, - function<bool(size_t, size_t)> uploadProgress) + std::function<bool(size_t, size_t)> downloadProgress, + std::function<bool(size_t, size_t)> uploadProgress) { return Request("POST", url, headers, params, formFields, downloadProgress, uploadProgress); } @@ -381,6 +393,11 @@ namespace BinaryNinja::Http int retry = 0; while (true) { + response.response.statusCode = 0; + response.response.headers.clear(); + response.body.clear(); + response.error.clear(); + RequestContext context{request, response}; BNDownloadInstanceInputOutputCallbacks callbacks{}; memset(&callbacks, 0, sizeof(BNDownloadInstanceInputOutputCallbacks)); @@ -399,7 +416,7 @@ namespace BinaryNinja::Http size_t backoff = 1000 * HTTP_BACKOFF_FACTOR * (2 * pow(2, retry - 1)); retry += 1; LogWarn("Attempt %d to %s %s failed, trying again in %zums\n", retry, request.m_method.data(), request.m_url.data(), backoff); - this_thread::sleep_for(chrono::milliseconds(backoff)); + std::this_thread::sleep_for(std::chrono::milliseconds(backoff)); } return result; } @@ -422,12 +439,12 @@ namespace BinaryNinja::Http { string str = GetString(); - unique_ptr<Json::CharReader> reader(Json::CharReaderBuilder().newCharReader()); + std::unique_ptr<Json::CharReader> reader(Json::CharReaderBuilder().newCharReader()); string errors; Json::Value value; if (!reader->parse(str.data(), str.data() + str.size(), &value, &errors)) { - throw runtime_error(std::string("Could not parse JSON: ") + errors); + throw std::runtime_error(std::string("Could not parse JSON: ") + errors.c_str()); } return value; } @@ -437,7 +454,7 @@ namespace BinaryNinja::Http { string str = GetString(); - unique_ptr<Json::CharReader> reader(Json::CharReaderBuilder().newCharReader()); + std::unique_ptr<Json::CharReader> reader(Json::CharReaderBuilder().newCharReader()); string errors; return reader->parse(str.data(), str.data() + str.size(), &value, &errors); } @@ -27,12 +27,32 @@ #include <functional> #include <utility> #include <stdint.h> + +#ifdef BINARYNINJACORE_LIBRARY +#include "downloadprovider.h" +#include "json/json.h" +#else #include "binaryninjaapi.h" +#endif +#ifdef BINARYNINJACORE_LIBRARY +namespace BinaryNinjaCore::Http +#else namespace BinaryNinja::Http +#endif { +#ifdef BINARYNINJACORE_LIBRARY +#define _STD_STRING string +#define _STD_VECTOR vector +#define _STD_UNORDERED_MAP unordered_map +#else +#define _STD_STRING std::string +#define _STD_VECTOR std::vector +#define _STD_UNORDERED_MAP std::unordered_map +#endif + enum ResponseCode { Continue = 100, @@ -84,20 +104,20 @@ namespace BinaryNinja::Http */ struct Response { - BinaryNinja::DownloadInstance::Response response; - std::vector<uint8_t> body; - std::string error; + DownloadInstance::Response response; + _STD_VECTOR<uint8_t> body; + _STD_STRING error; /*! Get response body as uint8_t vector \return Response body bytes */ - std::vector<uint8_t> GetRaw() const noexcept; + _STD_VECTOR<uint8_t> GetRaw() const noexcept; /*! Get response body as text string \return Response body string */ - std::string GetString() const noexcept; + _STD_STRING GetString() const noexcept; /*! Get response body as a json value \return Response body json @@ -118,16 +138,16 @@ namespace BinaryNinja::Http */ struct MultipartField { - std::string name; - std::vector<uint8_t> content; - std::optional<std::string> filename; + _STD_STRING name; + _STD_VECTOR<uint8_t> content; + std::optional<_STD_STRING> filename; /*! Construct a Multipart Field structure with a UTF-8 string encoded body \param name Name of the field to be sent in a POST request \param content Contents of the field */ - MultipartField(std::string name, const std::string& content): + MultipartField(_STD_STRING name, const _STD_STRING& content): name(std::move(name)), content({}), filename({}) { std::copy(content.begin(), content.end(), std::back_inserter(this->content)); @@ -139,7 +159,7 @@ namespace BinaryNinja::Http \param content Contents of the field \param filename Filename associated with the contents */ - MultipartField(std::string name, const std::string& content, std::string filename): + MultipartField(_STD_STRING name, const _STD_STRING& content, _STD_STRING filename): name(std::move(name)), content({}), filename(std::move(filename)) { std::copy(content.begin(), content.end(), std::back_inserter(this->content)); @@ -150,7 +170,7 @@ namespace BinaryNinja::Http \param name Name of the field to be sent in a POST request \param content Contents of the field */ - MultipartField(std::string name, std::vector<uint8_t> content): + MultipartField(_STD_STRING name, _STD_VECTOR<uint8_t> content): name(std::move(name)), content(std::move(content)), filename({}) { @@ -162,7 +182,7 @@ namespace BinaryNinja::Http \param content Contents of the field \param filename Filename associated with the contents */ - MultipartField(std::string name, std::vector<uint8_t> content, std::string filename): + MultipartField(_STD_STRING name, _STD_VECTOR<uint8_t> content, _STD_STRING filename): name(std::move(name)), content(std::move(content)), filename(std::move(filename)) { @@ -175,10 +195,10 @@ namespace BinaryNinja::Http */ struct Request { - std::string m_method; - std::string m_url; - std::unordered_map<std::string, std::string> m_headers; - std::vector<uint8_t> m_body; + _STD_STRING m_method; + _STD_STRING m_url; + _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> m_headers; + _STD_VECTOR<uint8_t> m_body; std::function<bool(size_t, size_t)> m_downloadProgress; std::function<bool(size_t, size_t)> m_uploadProgress; @@ -192,9 +212,9 @@ namespace BinaryNinja::Http \param downloadProgress Function to call for download progress updates \param uploadProgress Function to call for upload progress updates */ - Request(std::string method, std::string url, - std::unordered_map<std::string, std::string> headers = {}, - std::vector<std::pair<std::string, std::string>> params = {}, + Request(_STD_STRING method, _STD_STRING url, + _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers = {}, + _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params = {}, std::function<bool(size_t, size_t)> downloadProgress = {}, std::function<bool(size_t, size_t)> uploadProgress = {}); @@ -209,10 +229,10 @@ namespace BinaryNinja::Http \param downloadProgress Function to call for download progress updates \param uploadProgress Function to call for upload progress updates */ - Request(std::string method, std::string url, - std::unordered_map<std::string, std::string> headers, - std::vector<std::pair<std::string, std::string>> params, - std::vector<uint8_t> body, + Request(_STD_STRING method, _STD_STRING url, + _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers, + _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params, + _STD_VECTOR<uint8_t> body, std::function<bool(size_t, size_t)> downloadProgress = {}, std::function<bool(size_t, size_t)> uploadProgress = {}); @@ -227,10 +247,10 @@ namespace BinaryNinja::Http \param downloadProgress Function to call for download progress updates \param uploadProgress Function to call for upload progress updates */ - Request(std::string method, std::string url, - std::unordered_map<std::string, std::string> headers, - std::vector<std::pair<std::string, std::string>> params, - std::vector<std::pair<std::string, std::string>> formFields, + Request(_STD_STRING method, _STD_STRING url, + _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers, + _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params, + _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> formFields, std::function<bool(size_t, size_t)> downloadProgress = {}, std::function<bool(size_t, size_t)> uploadProgress = {}); @@ -245,10 +265,10 @@ namespace BinaryNinja::Http \param downloadProgress Function to call for download progress updates \param uploadProgress Function to call for upload progress updates */ - Request(std::string method, std::string url, - std::unordered_map<std::string, std::string> headers, - std::vector<std::pair<std::string, std::string>> params, - std::vector<MultipartField> formFields, + Request(_STD_STRING method, _STD_STRING url, + _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers, + _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params, + _STD_VECTOR<MultipartField> formFields, std::function<bool(size_t, size_t)> downloadProgress = {}, std::function<bool(size_t, size_t)> uploadProgress = {}); @@ -262,9 +282,9 @@ namespace BinaryNinja::Http \param uploadProgress Function to call for upload progress updates \return Request structure with specified fields */ - static Request Get(std::string url, - std::unordered_map<std::string, std::string> headers = {}, - std::vector<std::pair<std::string, std::string>> params = {}, + static Request Get(_STD_STRING url, + _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers = {}, + _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params = {}, std::function<bool(size_t, size_t)> downloadProgress = {}, std::function<bool(size_t, size_t)> uploadProgress = {}); @@ -279,10 +299,10 @@ namespace BinaryNinja::Http \param uploadProgress Function to call for upload progress updates \return Request structure with specified fields */ - static Request Post(std::string url, - std::unordered_map<std::string, std::string> headers = {}, - std::vector<std::pair<std::string, std::string>> params = {}, - std::vector<uint8_t> body = {}, + static Request Post(_STD_STRING url, + _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers = {}, + _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params = {}, + _STD_VECTOR<uint8_t> body = {}, std::function<bool(size_t, size_t)> downloadProgress = {}, std::function<bool(size_t, size_t)> uploadProgress = {}); @@ -297,10 +317,10 @@ namespace BinaryNinja::Http \param uploadProgress Function to call for upload progress updates \return Request structure with specified fields */ - static Request Post(std::string url, - std::unordered_map<std::string, std::string> headers, - std::vector<std::pair<std::string, std::string>> params, - std::vector<std::pair<std::string, std::string>> formFields, + static Request Post(_STD_STRING url, + _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers, + _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params, + _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> formFields, std::function<bool(size_t, size_t)> downloadProgress = {}, std::function<bool(size_t, size_t)> uploadProgress = {}); @@ -315,10 +335,10 @@ namespace BinaryNinja::Http \param uploadProgress Function to call for upload progress updates \return Request structure with specified fields */ - static Request Post(std::string url, - std::unordered_map<std::string, std::string> headers, - std::vector<std::pair<std::string, std::string>> params, - std::vector<MultipartField> formFields, + static Request Post(_STD_STRING url, + _STD_UNORDERED_MAP<_STD_STRING, _STD_STRING> headers, + _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>> params, + _STD_VECTOR<MultipartField> formFields, std::function<bool(size_t, size_t)> downloadProgress = {}, std::function<bool(size_t, size_t)> uploadProgress = {}); }; @@ -329,7 +349,7 @@ namespace BinaryNinja::Http \param str Input string \return URLEncoded string */ - std::string UrlEncode(const std::string& str); + _STD_STRING UrlEncode(const _STD_STRING& str); /*! @@ -337,7 +357,7 @@ namespace BinaryNinja::Http \param fields Input key/value pairs \return URLEncoded form body */ - std::string UrlEncode(const std::vector<std::pair<std::string, std::string>>& fields); + _STD_STRING UrlEncode(const _STD_VECTOR<std::pair<_STD_STRING, _STD_STRING>>& fields); /*! @@ -347,7 +367,7 @@ namespace BinaryNinja::Http \param boundary Output boundary between fields in the body (for Content-Type header) \return Multipart encoded form body */ - std::vector<uint8_t> MultipartEncode(const std::vector<MultipartField>& fields, std::string& boundary); + _STD_VECTOR<uint8_t> MultipartEncode(const _STD_VECTOR<MultipartField>& fields, _STD_STRING& boundary); /*! @@ -357,5 +377,10 @@ namespace BinaryNinja::Http \param response Output Response structure with body \return Zero or greater on success */ - int Perform(const BinaryNinja::Ref<BinaryNinja::DownloadInstance>& instance, const Request& request, Response& response); + int Perform(const Ref<DownloadInstance>& instance, const Request& request, Response& response); + +#undef _STD_VECTOR +#undef _STD_SET +#undef _STD_UNORDERED_MAP +#undef _STD_MAP }
\ No newline at end of file diff --git a/interaction.cpp b/interaction.cpp index 05420f17..2f808067 100644 --- a/interaction.cpp +++ b/interaction.cpp @@ -415,6 +415,13 @@ static BNMessageBoxButtonResult ShowMessageBoxCallback(void* ctxt, const char* t } +static bool OpenUrlCallback(void* ctxt, const char* url) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + return handler->OpenUrl(url); +} + + void BinaryNinja::RegisterInteractionHandler(InteractionHandler* handler) { BNInteractionHandlerCallbacks cb; @@ -433,6 +440,7 @@ void BinaryNinja::RegisterInteractionHandler(InteractionHandler* handler) cb.getDirectoryNameInput = GetDirectoryNameInputCallback; cb.getFormInput = GetFormInputCallback; cb.showMessageBox = ShowMessageBoxCallback; + cb.openUrl = OpenUrlCallback; BNRegisterInteractionHandler(&cb); } @@ -660,6 +668,12 @@ BNMessageBoxButtonResult BinaryNinja::ShowMessageBox(const string& title, const } +bool BinaryNinja::OpenUrl(const std::string& url) +{ + return BNOpenUrl(url.c_str()); +} + + ReportCollection::ReportCollection() { m_object = BNCreateReportCollection(); diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 483cbad3..9fd8c6b2 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -6,6 +6,10 @@ file(GLOB PYTHON_SOURCES ${PROJECT_SOURCE_DIR}/*.py) list(REMOVE_ITEM PYTHON_SOURCES ${PROJECT_SOURCE_DIR}/_binaryninjacore.py) list(REMOVE_ITEM PYTHON_SOURCES ${PROJECT_SOURCE_DIR}/enums.py) +if(NOT ENTERPRISE) + list(REMOVE_ITEM PYTHON_SOURCES ${PROJECT_SOURCE_DIR}/enterprise.py) +endif() + add_executable(generator ${PROJECT_SOURCE_DIR}/generator.cpp) target_link_libraries(generator binaryninjaapi) @@ -22,25 +26,12 @@ if(BN_INTERNAL_BUILD) COMMAND ${CMAKE_COMMAND} -E copy ${BN_CORE_OUTPUT_DIR}/binaryninjacore.dll ${PROJECT_BINARY_DIR}/) endif() - option(LICENSE_FILE "Path to license file, for compiling") - set(LICENSE "") - if(LICENSE_FILE) - file(READ ${LICENSE_FILE} LICENSE_CONTS) - message(STATUS "Using licence for build: ${LICENSE_FILE}") - # Encode for passing through the command-line - string(REPLACE "\n" "" LICENSE_CONTS "${LICENSE_CONTS}") - string(REPLACE "\"" "\\\"" LICENSE_CONTS "${LICENSE_CONTS}") - string(REPLACE "{" "\\{" LICENSE_CONTS "${LICENSE_CONTS}") - string(REPLACE "}" "\\}" LICENSE_CONTS "${LICENSE_CONTS}") - set(LICENSE "BN_LICENSE=${LICENSE_CONTS}") - endif() - add_custom_target(generator_copy ALL BYPRODUCTS ${PROJECT_SOURCE_DIR}/_binaryninjacore.py ${PROJECT_SOURCE_DIR}/enums.py DEPENDS ${PYTHON_SOURCES} ${PROJECT_SOURCE_DIR}/../binaryninjacore.h $<TARGET_FILE:generator> COMMAND ${CMAKE_COMMAND} -E echo "Copying Python Sources" COMMAND ${CMAKE_COMMAND} -E make_directory ${BN_RESOURCE_DIR}/python/binaryninja/ - COMMAND ${CMAKE_COMMAND} -E env ASAN_OPTIONS=detect_leaks=0 ${LICENSE} $<TARGET_FILE:generator> ${PROJECT_SOURCE_DIR}/../binaryninjacore.h ${PROJECT_SOURCE_DIR}/_binaryninjacore.py ${PROJECT_SOURCE_DIR}/enums.py + COMMAND ${CMAKE_COMMAND} -E env ASAN_OPTIONS=detect_leaks=0 $<TARGET_FILE:generator> ${PROJECT_SOURCE_DIR}/../binaryninjacore.h ${PROJECT_SOURCE_DIR}/_binaryninjacore.py ${PROJECT_SOURCE_DIR}/enums.py COMMAND ${CMAKE_COMMAND} -E copy ${PYTHON_SOURCES} ${BN_RESOURCE_DIR}/python/binaryninja/ COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/_binaryninjacore.py ${BN_RESOURCE_DIR}/python/binaryninja/ COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/enums.py ${BN_RESOURCE_DIR}/python/binaryninja/ diff --git a/python/__init__.py b/python/__init__.py index 711ed550..1cf00773 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -72,6 +72,9 @@ from .log import (redirect_output_to_log, is_output_redirected_to_log, log_debug, log_info, log_warn, log_error, log_alert, log_to_stdout, log_to_stderr, log_to_file, close_logs) from .log import log as log_at_level +# Only load Enterprise Client support on Enterprise builds +if core.BNGetProduct() == "Binary Ninja Enterprise Client": + from .enterprise import * def shutdown(): @@ -123,6 +126,14 @@ _plugin_init = False def _init_plugins(): global _enable_default_log global _plugin_init + + if not core_ui_enabled() and core.BNGetProduct() == "Binary Ninja Enterprise Client": + # Enterprise client needs to checkout a license reservation or else BNInitPlugins will fail + if not core.BNAuthenticateEnterpriseServerWithMethod("Keychain") and (not core.BNIsLicenseValidated() or not enterprise.is_license_still_activated()): + raise RuntimeError( + "To use Binary Ninja Enterprise from a headless python script, you must check out a license first.\n" + "You can either check out a license for an extended time with the UI, or use the binaryninja.enterprise module.") + if not _plugin_init: # The first call to BNInitCorePlugins returns True for successful initialization and True in this context indicates headless operation. # The result is pulled from BNInitPlugins as that now wraps BNInitCorePlugins. diff --git a/python/enterprise.py b/python/enterprise.py new file mode 100644 index 00000000..8eadb06c --- /dev/null +++ b/python/enterprise.py @@ -0,0 +1,189 @@ +import ctypes +from typing import Tuple, List, Optional + +import binaryninja._binaryninjacore as core +import binaryninja + +if core.BNGetProduct() != "Binary Ninja Enterprise Client": + # None of these functions exist on other builds, so just raise here to notify anyone who tries to use this + raise RuntimeError("Cannot use Binary Ninja Enterprise client functionality with a non-Enterprise client.") + + +def connect(): + """ + Connect to the Enterprise Server. + """ + if not core.BNConnectEnterpriseServer(): + raise RuntimeError(last_error()) + +def is_connected() -> bool: + """ + Determine if the Enterprise Server is currently connected. + :return: True if connected + """ + return core.BNIsEnterpriseServerConnected() + +def authenticate_with_credentials(username: str, password: str): + """ + Authenticate to the Enterprise Server with username/password credentials. + :param str username: Username to use. + :param str password: Password to use. + """ + if not core.BNAuthenticateEnterpriseServerWithCredentials(username, password): + raise RuntimeError(last_error()) + +def authenticate_with_method(method: str): + """ + Authenticate to the Enterprise Server with a non-password method. Note that many of these will + open a URL for a browser-based login prompt, which may not be usable on headless installations. + See :func:`authentication_methods` for a list of accepted methods. + :param str method: Name of method to use. + """ + if not core.BNAuthenticateEnterpriseServerWithMethod(method): + raise RuntimeError(last_error()) + +def authentication_methods() -> List[Tuple[str, str]]: + """ + Get a list of authentication methods accepted by the Enterprise Server. + :return: List of (<method name>, <method display name>) tuples + """ + methods = ctypes.POINTER(ctypes.c_char_p)() + names = ctypes.POINTER(ctypes.c_char_p)() + count = core.BNGetEnterpriseServerAuthenticationMethods(methods, names) + results = [] + for i in range(count): + results.append((core.pyNativeStr(methods[i]), core.pyNativeStr(names[i]))) + core.BNFreeStringList(methods, count) + core.BNFreeStringList(names, count) + return results + +def deauthenticate(): + """ + Deauthenticate from the Enterprise server, clearing any cached credentials. + """ + if not core.BNDeauthenticateEnterpriseServer(): + raise RuntimeError(last_error()) + +def cancel_authentication(): + """ + Cancel a call to :func:`authenticate_with_credentials` or :func:`authenticate_with_method`. + Note those functions are blocking, so this must be called on a separate thread. + """ + core.BNCancelEnterpriseServerAuthentication() + +def is_authenticated() -> bool: + """ + Determine if you have authenticated to the Enterprise Server. + :return: True if you are authenticated + """ + return core.BNIsEnterpriseServerAuthenticated() + +def username() -> Optional[None]: + """ + Get the username of the currently authenticated user to the Enterprise Server. + :return: Username, if authenticated. None, otherwise. + """ + return core.BNGetEnterpriseServerUsername() + +def reservation_time_limit() -> int: + """ + Get the maximum checkout duration allowed by the Enterprise Server. + .. note:: You must authenticate with the Enterprise Server before calling this. + + :return: Duration, in seconds, of the maximum time you are allowed to checkout a license. + """ + return core.BNGetEnterpriseServerReservationTimeLimit() + +def acquire_license(duration, cache=False): + """ + Check out and activate a license from the Enterprise Server. + If ``cache`` is True, the checkout will be saved to a local secrets storage. This is platform-dependent: + - macOS: Saved to the user's keychain + - Windows: Saved to the credential store + - Linux: Saved with dbus's Secret Service API + + .. note:: You must authenticate with the Enterprise Server before calling this. + + .. warning:: If ``cache`` is False, you must remember to call :func:`release_license` before the process + exits to release the uncached license back to the server. If you forget to do so, you will + have to either wait for the checkout to expire or have an administrator revoke the checkout. + + :param int duration: Desired length of license checkout, in seconds. + :param bool cache: If true, the license will be saved to a local secrets storage. + """ + if not core.BNAcquireEnterpriseServerLicense(duration, cache): + raise RuntimeError(last_error()) + +def release_license(): + """ + Release the currently checked out license back to the Enterprise Server. + + .. note:: You must authenticate with the Enterprise Server before calling this. + + .. note:: This will deactivate the Binary Ninja Enterprise client. You must call :func:`acquire_license` + again to continue using Binary Ninja Enterprise in the current process. + """ + if not core.BNReleaseEnterpriseServerLicense(): + raise RuntimeError(last_error()) + +def license_expiration_time() -> int: + """ + Get the expiry time of the current license checkout. + :return: Expiry time as a Unix epoch, or 0 if no license is checked out. + """ + return core.BNGetEnterpriseServerLicenseExpirationTime() + +def license_duration() -> int: + """ + Get the duration of the current license checkout. + :return: Duration, in seconds, of the total time of the current checkout. + """ + return core.BNGetEnterpriseServerLicenseDuration() + +def is_license_still_activated() -> bool: + """ + Determine if your current license checkout is still valid. + :return: True if your current checkout is still valid. + """ + return core.BNIsEnterpriseServerLicenseStillActivated() + +def last_error() -> str: + """ + Get a text representation the last error encountered by the Enterprise Client + :return: Last error message, or empty string if there is none. + """ + return core.BNGetEnterpriseServerLastError() + +class LicenseCheckout: + """ + Helper class for scripts to make use of a license checkout in a scope. + + :Example: + enterprise.connect() + enterprise.authenticate_with_credentials("username", "password") + with enterprise.LicenseCheckout(): + # Do some operation + bv = open_view("/bin/ls") # e.g + # License is released at end of scope + + """ + + def __init__(self, duration=900, cache=False): + self.desired_duration = duration + self.desired_cache = cache + + def __enter__(self): + # UI builds have their own license manager + if binaryninja.core_ui_enabled(): + return + if not is_connected(): + connect() + if not is_authenticated(): + raise RuntimeError("Could not checkout a license: Not authenticated. Please use binaryninja.enterprise.authenticate_with_credentials or authenticate_with_method first!") + acquire_license(self.desired_duration, self.desired_cache) + + def __exit__(self, exc_type, exc_val, exc_tb): + # UI builds have their own license manager + if binaryninja.core_ui_enabled(): + return + release_license() diff --git a/python/generator.cpp b/python/generator.cpp index e0695b66..2e42fa6f 100644 --- a/python/generator.cpp +++ b/python/generator.cpp @@ -160,11 +160,6 @@ int main(int argc, char* argv[]) return 1; } - if (getenv("BN_LICENSE")) - { - BNSetLicense(getenv("BN_LICENSE")); - } - Architecture::Register(new GeneratorArchitecture()); // Parse API header to get type and function information diff --git a/python/interaction.py b/python/interaction.py index 3bbf5fa6..581a87f6 100644 --- a/python/interaction.py +++ b/python/interaction.py @@ -20,6 +20,7 @@ import ctypes import traceback +import webbrowser from typing import Optional # Binary Ninja components @@ -491,6 +492,7 @@ class InteractionHandler: self._cb.getDirectoryNameInput = self._cb.getDirectoryNameInput.__class__(self._get_directory_name_input) self._cb.getFormInput = self._cb.getFormInput.__class__(self._get_form_input) self._cb.showMessageBox = self._cb.showMessageBox.__class__(self._show_message_box) + self._cb.openUrl = self._cb.openUrl.__class__(self._open_url) def register(self): self.__class__._interaction_handler = self @@ -665,6 +667,13 @@ class InteractionHandler: except: log_error(traceback.format_exc()) + def _open_url(self, ctxt, url): + try: + return self.open_url(url) + except: + log_error(traceback.format_exc()) + return False + def show_plain_text_report(self, view, title, contents): pass @@ -715,6 +724,10 @@ class InteractionHandler: def show_message_box(self, title, text, buttons, icon): return MessageBoxButtonResult.CancelButton + def open_url(self, url): + webbrowser.open(url) + return True + class PlainTextReport: def __init__(self, title, contents, view = None): @@ -1302,3 +1315,14 @@ def show_message_box(title, text, buttons=MessageBoxButtonSet.OKButtonSet, icon= :rtype: MessageBoxButtonResult """ return core.BNShowMessageBox(title, text, buttons, icon) + + +def open_url(url): + """ + ``open_url`` Opens a given url in the user's web browser, if available. + + :param str url: Url to open + :return: True if successful + :rtype: bool + """ + return core.BNOpenUrl(url) diff --git a/secretsprovider.cpp b/secretsprovider.cpp new file mode 100644 index 00000000..62a51fff --- /dev/null +++ b/secretsprovider.cpp @@ -0,0 +1,141 @@ +// Copyright (c) 2015-2021 Vector 35 Inc +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "binaryninjaapi.h" +#include <string.h> + +using namespace BinaryNinja; + +SecretsProvider::SecretsProvider(const std::string& name): m_nameForRegister(name) +{ + +} + + +SecretsProvider::SecretsProvider(BNSecretsProvider* provider) +{ + m_object = provider; +} + + +bool SecretsProvider::HasDataCallback(void* ctxt, const char* key) +{ + SecretsProvider* provider = (SecretsProvider*)ctxt; + return provider->HasData(key); +} + + +char* SecretsProvider::GetDataCallback(void* ctxt, const char* key) +{ + SecretsProvider* provider = (SecretsProvider*)ctxt; + std::optional<std::string> data = provider->GetData(key); + if (!data.has_value()) + return nullptr; + char* value = BNAllocString(data->c_str()); + memset(data->data(), 0, data->size()); + return value; +} + + +bool SecretsProvider::StoreDataCallback(void* ctxt, const char* key, const char* data) +{ + SecretsProvider* provider = (SecretsProvider*)ctxt; + std::string value = data; + bool result = provider->StoreData(key, value); + memset(value.data(), 0, value.size()); + return result; +} + + +bool SecretsProvider::DeleteDataCallback(void* ctxt, const char* key) +{ + SecretsProvider* provider = (SecretsProvider*)ctxt; + return provider->DeleteData(key); +} + + +std::vector<Ref<SecretsProvider>> SecretsProvider::GetList() +{ + size_t count; + BNSecretsProvider** list = BNGetSecretsProviderList(&count); + std::vector<Ref<SecretsProvider>> result; + for (size_t i = 0; i < count; i++) + result.push_back(new CoreSecretsProvider(list[i])); + BNFreeSecretsProviderList(list); + return result; +} + + +Ref<SecretsProvider> SecretsProvider::GetByName(const std::string& name) +{ + BNSecretsProvider* result = BNGetSecretsProviderByName(name.c_str()); + if (!result) + return nullptr; + return new CoreSecretsProvider(result); +} + + +void SecretsProvider::Register(SecretsProvider* provider) +{ + BNSecretsProviderCallbacks cb; + cb.context = provider; + cb.hasData = HasDataCallback; + cb.getData = GetDataCallback; + cb.storeData = StoreDataCallback; + cb.deleteData = DeleteDataCallback; + provider->m_object = BNRegisterSecretsProvider(provider->m_nameForRegister.c_str(), &cb); +} + + +CoreSecretsProvider::CoreSecretsProvider(BNSecretsProvider* provider): SecretsProvider(provider) +{ + +} + + +bool CoreSecretsProvider::HasData(const std::string& key) +{ + return BNSecretsProviderHasData(m_object, key.c_str()); +} + + +std::optional<std::string> CoreSecretsProvider::GetData(const std::string& key) +{ + char* data = BNGetSecretsProviderData(m_object, key.c_str()); + if (data == nullptr) + return std::optional<std::string>(); + + std::string value = data; + memset(data, 0, strlen(data)); + BNFreeString(data); + return value; +} + + +bool CoreSecretsProvider::StoreData(const std::string& key, const std::string& data) +{ + return BNStoreSecretsProviderData(m_object, key.c_str(), data.c_str()); +} + + +bool CoreSecretsProvider::DeleteData(const std::string& key) +{ + return BNDeleteSecretsProviderData(m_object, key.c_str()); +} diff --git a/ui/uitypes.h b/ui/uitypes.h index 7bcaa560..3ed27da8 100644 --- a/ui/uitypes.h +++ b/ui/uitypes.h @@ -85,6 +85,7 @@ typedef BinaryNinja::Ref<BinaryNinja::ReportCollection> ReportCollectionRef; typedef BinaryNinja::Ref<BinaryNinja::SaveSettings> SaveSettingsRef; typedef BinaryNinja::Ref<BinaryNinja::ScriptingInstance> ScriptingInstanceRef; typedef BinaryNinja::Ref<BinaryNinja::ScriptingProvider> ScriptingProviderRef; +typedef BinaryNinja::Ref<BinaryNinja::SecretsProvider> SecretsProviderRef; typedef BinaryNinja::Ref<BinaryNinja::Section> SectionRef; typedef BinaryNinja::Ref<BinaryNinja::Segment> SegmentRef; typedef BinaryNinja::Ref<BinaryNinja::Settings> SettingsRef; |
