diff options
| -rw-r--r-- | backgroundtask.cpp | 6 | ||||
| -rw-r--r-- | binaryninjaapi.h | 381 | ||||
| -rw-r--r-- | binaryninjacore.h | 165 | ||||
| -rw-r--r-- | binaryview.cpp | 151 | ||||
| -rw-r--r-- | database.cpp | 6 | ||||
| -rw-r--r-- | externallibrary.cpp | 144 | ||||
| -rw-r--r-- | filemetadata.cpp | 42 | ||||
| -rw-r--r-- | project.cpp | 683 | ||||
| -rw-r--r-- | python/__init__.py | 1 | ||||
| -rw-r--r-- | python/binaryview.py | 79 | ||||
| -rw-r--r-- | python/exceptions.py | 4 | ||||
| -rw-r--r-- | python/externallibrary.py | 125 | ||||
| -rw-r--r-- | python/filemetadata.py | 23 | ||||
| -rw-r--r-- | python/project.py | 411 | ||||
| -rw-r--r-- | python/scriptingprovider.py | 16 | ||||
| -rw-r--r-- | python/settings.py | 2 | ||||
| -rw-r--r-- | rust/src/filemetadata.rs | 17 | ||||
| -rwxr-xr-x | scripts/linux-setup.sh | 1 | ||||
| -rw-r--r-- | ui/externallocationdialog.h | 29 | ||||
| -rw-r--r-- | ui/linearview.h | 5 | ||||
| -rw-r--r-- | ui/options.h | 1 | ||||
| -rw-r--r-- | ui/settingsview.h | 6 | ||||
| -rw-r--r-- | ui/uicontext.h | 46 | ||||
| -rw-r--r-- | ui/uitypes.h | 5 | ||||
| -rw-r--r-- | ui/util.h | 2 |
25 files changed, 2285 insertions, 66 deletions
diff --git a/backgroundtask.cpp b/backgroundtask.cpp index b2d4a738..5aeadaf8 100644 --- a/backgroundtask.cpp +++ b/backgroundtask.cpp @@ -43,6 +43,12 @@ string BackgroundTask::GetProgressText() const } +uint64_t BackgroundTask::GetRuntimeSeconds() const +{ + return BNGetBackgroundTaskRuntimeSeconds(m_object); +} + + void BackgroundTask::Cancel() { BNCancelBackgroundTask(m_object); diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 872b862b..4dc1ac07 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -2384,11 +2384,314 @@ namespace BinaryNinja { void WriteGlobalData(const std::string& key, const DataBuffer& val); Ref<FileMetadata> GetFile(); + void ReloadConnection(); Ref<KeyValueStore> ReadAnalysisCache() const; void WriteAnalysisCache(Ref<KeyValueStore> val); }; + + /*! + + \ingroup project + */ + struct ProjectException : std::runtime_error + { + ProjectException(const std::string& desc) : std::runtime_error(desc.c_str()) {} + }; + + class ExternalLibrary; + class Symbol; + class Project; + class ProjectFile; + class ProjectFolder; + + /*! + + \ingroup project + */ + + class ExternalLocation : public CoreRefCountObject<BNExternalLocation, BNNewExternalLocationReference, BNFreeExternalLocation> + { + public: + ExternalLocation(BNExternalLocation* loc); + + Ref<Symbol> GetInternalSymbol(); + std::optional<uint64_t> GetAddress(); + std::optional<std::string> GetSymbol(); + Ref<ExternalLibrary> GetExternalLibrary(); + + bool HasAddress(); + bool HasSymbol(); + + void SetAddress(std::optional<uint64_t> address); + void SetSymbol(std::optional<std::string> symbol); + void SetExternalLibrary(Ref<ExternalLibrary> library); + }; + + /*! + + \ingroup project + */ + + class ExternalLibrary : public CoreRefCountObject<BNExternalLibrary, BNNewExternalLibraryReference, BNFreeExternalLibrary> + { + public: + ExternalLibrary(BNExternalLibrary* lib); + + std::string GetName() const; + Ref<ProjectFile> GetBackingFile() const; + + void SetBackingFile(Ref<ProjectFile> file); + }; + + + /*! + \ingroup project + */ + class ProjectNotification + { + private: + BNProjectNotification m_callbacks; + + static bool BeforeOpenProjectCallback(void* ctxt, BNProject* project); + static void AfterOpenProjectCallback(void* ctxt, BNProject* project); + static bool BeforeCloseProjectCallback(void* ctxt, BNProject* project); + static void AfterCloseProjectCallback(void* ctxt, BNProject* project); + static bool BeforeProjectMetadataWrittenCallback(void* ctxt, BNProject* project, char* key, BNMetadata* value); + static void AfterProjectMetadataWrittenCallback(void* ctxt, BNProject* project, char* key, BNMetadata* value); + static bool BeforeProjectFileCreatedCallback(void* ctxt, BNProject* project, BNProjectFile* projectFile); + static void AfterProjectFileCreatedCallback(void* ctxt, BNProject* project, BNProjectFile* projectFile); + static bool BeforeProjectFileUpdatedCallback(void* ctxt, BNProject* project, BNProjectFile* projectFile); + static void AfterProjectFileUpdatedCallback(void* ctxt, BNProject* project, BNProjectFile* projectFile); + static bool BeforeProjectFileDeletedCallback(void* ctxt, BNProject* project, BNProjectFile* projectFile); + static void AfterProjectFileDeletedCallback(void* ctxt, BNProject* project, BNProjectFile* projectFile); + static bool BeforeProjectFolderCreatedCallback(void* ctxt, BNProject* project, BNProjectFolder* projectFolder); + static void AfterProjectFolderCreatedCallback(void* ctxt, BNProject* project, BNProjectFolder* projectFolder); + static bool BeforeProjectFolderUpdatedCallback(void* ctxt, BNProject* project, BNProjectFolder* projectFolder); + static void AfterProjectFolderUpdatedCallback(void* ctxt, BNProject* project, BNProjectFolder* projectFolder); + static bool BeforeProjectFolderDeletedCallback(void* ctxt, BNProject* project, BNProjectFolder* projectFolder); + static void AfterProjectFolderDeletedCallback(void* ctxt, BNProject* project, BNProjectFolder* projectFolder); + + public: + ProjectNotification(); + virtual ~ProjectNotification() {} + + BNProjectNotification* GetCallbacks() { return &m_callbacks; } + + virtual bool OnBeforeOpenProject(Project* project) + { + (void)project; + return true; + } + + virtual void OnAfterOpenProject(Project* project) + { + (void)project; + } + + virtual bool OnBeforeCloseProject(Project* project) + { + (void)project; + return true; + } + + virtual void OnAfterCloseProject(Project* project) + { + (void)project; + } + + virtual bool OnBeforeProjectMetadataWritten(Project* project, std::string& key, Metadata* value) + { + (void)project; + (void)key; + (void)value; + return true; + } + + virtual void OnAfterProjectMetadataWritten(Project* project, std::string& key, Metadata* value) + { + (void)project; + (void)key; + (void)value; + } + + virtual bool OnBeforeProjectFileCreated(Project* project, ProjectFile* projectFile) + { + (void)project; + (void)projectFile; + return true; + } + + virtual void OnAfterProjectFileCreated(Project* project, ProjectFile* projectFile) + { + (void)project; + (void)projectFile; + } + + virtual bool OnBeforeProjectFileUpdated(Project* project, ProjectFile* projectFile) + { + (void)project; + (void)projectFile; + return true; + } + + virtual void OnAfterProjectFileUpdated(Project* project, ProjectFile* projectFile) + { + (void)project; + (void)projectFile; + } + + virtual bool OnBeforeProjectFileDeleted(Project* project, ProjectFile* projectFile) + { + (void)project; + (void)projectFile; + return true; + } + + virtual void OnAfterProjectFileDeleted(Project* project, ProjectFile* projectFile) + { + (void)project; + (void)projectFile; + } + + virtual bool OnBeforeProjectFolderCreated(Project* project, ProjectFolder* projectFolder) + { + (void)project; + (void)projectFolder; + return true; + } + + virtual void OnAfterProjectFolderCreated(Project* project, ProjectFolder* projectFolder) + { + (void)project; + (void)projectFolder; + } + + virtual bool OnBeforeProjectFolderUpdated(Project* project, ProjectFolder* projectFolder) + { + (void)project; + (void)projectFolder; + return true; + } + + virtual void OnAfterProjectFolderUpdated(Project* project, ProjectFolder* projectFolder) + { + (void)project; + (void)projectFolder; + } + + virtual bool OnBeforeProjectFolderDeleted(Project* project, ProjectFolder* projectFolder) + { + (void)project; + (void)projectFolder; + return true; + } + + virtual void OnAfterProjectFolderDeleted(Project* project, ProjectFolder* projectFolder) + { + (void)project; + (void)projectFolder; + } + }; + + /*! + + \ingroup project + */ + class ProjectFolder : public CoreRefCountObject<BNProjectFolder, BNNewProjectFolderReference, BNFreeProjectFolder> + { + public: + ProjectFolder(BNProjectFolder* folder); + + Ref<Project> GetProject() const; + std::string GetId() const; + std::string GetName() const; + std::string GetDescription() const; + void SetName(const std::string& name); + void SetDescription(const std::string& description); + Ref<ProjectFolder> GetParent() const; + void SetParent(Ref<ProjectFolder> parent); + bool Export(const std::string& destination, const std::function<bool(size_t progress, size_t total)>& progressCallback = {}) const; + }; + + /*! + + \ingroup project + */ + class ProjectFile : public CoreRefCountObject<BNProjectFile, BNNewProjectFileReference, BNFreeProjectFile> + { + public: + ProjectFile(BNProjectFile* file); + + Ref<Project> GetProject() const; + std::string GetPathOnDisk() const; + bool ExistsOnDisk() const; + std::string GetName() const; + std::string GetDescription() const; + void SetName(const std::string& name); + void SetDescription(const std::string& description); + std::string GetId() const; + Ref<ProjectFolder> GetFolder() const; + void SetFolder(Ref<ProjectFolder> folder); + bool Export(const std::string& destination) const; + }; + + + /*! + + \ingroup project + */ + class Project : public CoreRefCountObject<BNProject, BNNewProjectReference, BNFreeProject> + { + public: + Project(BNProject* project); + + static Ref<Project> CreateProject(const std::string& path, const std::string& name); + static Ref<Project> OpenProject(const std::string& path); + static std::vector<Ref<Project>> GetOpenProjects(); + + bool Open(); + bool Close(); + std::string GetId() const; + bool IsOpen() const; + std::string GetPath() const; + std::string GetName() const; + void SetName(const std::string& name); + std::string GetDescription() const; + void SetDescription(const std::string& description); + + Ref<Metadata> QueryMetadata(const std::string& key); + bool StoreMetadata(const std::string& key, Ref<Metadata> value); + void RemoveMetadata(const std::string& key); + + Ref<ProjectFolder> CreateFolderFromPath(const std::string& path, Ref<ProjectFolder> parent, const std::string& description, + const std::function<bool(size_t progress, size_t total)>& progressCallback = {}); + Ref<ProjectFolder> CreateFolder(Ref<ProjectFolder> parent, const std::string& name, const std::string& description); + Ref<ProjectFolder> CreateFolderUnsafe(Ref<ProjectFolder> parent, const std::string& name, const std::string& description, const std::string& id); + std::vector<Ref<ProjectFolder>> GetFolders() const; + Ref<ProjectFolder> GetFolderById(const std::string& id) const; + void PushFolder(Ref<ProjectFolder> folder); + void DeleteFolder(Ref<ProjectFolder> folder, const std::function<bool(size_t progress, size_t total)>& progressCallback = {}); + + Ref<ProjectFile> CreateFileFromPath(const std::string& path, Ref<ProjectFolder> folder, const std::string& name, const std::string& description, const std::function<bool(size_t progress, size_t total)>& progressCallback = {}); + Ref<ProjectFile> CreateFileFromPathUnsafe(const std::string& path, Ref<ProjectFolder> folder, const std::string& name, const std::string& description, const std::string& id, const std::function<bool(size_t progress, size_t total)>& progressCallback = {}); + Ref<ProjectFile> CreateFile(const std::vector<uint8_t>& contents, Ref<ProjectFolder> folder, const std::string& name, const std::string& description, const std::function<bool(size_t progress, size_t total)>& progressCallback = {}); + Ref<ProjectFile> CreateFileUnsafe(const std::vector<uint8_t>& contents, Ref<ProjectFolder> folder, const std::string& name, const std::string& description, const std::string& id, const std::function<bool(size_t progress, size_t total)>& progressCallback = {}); + std::vector<Ref<ProjectFile>> GetFiles() const; + Ref<ProjectFile> GetFileById(const std::string& id) const; + Ref<ProjectFile> GetFileByPathOnDisk(const std::string& path); + void PushFile(Ref<ProjectFile> file); + void DeleteFile_(Ref<ProjectFile> file); + + void RegisterNotification(ProjectNotification* notify); + void UnregisterNotification(ProjectNotification* notify); + + void BeginBulkOperation(); + void EndBulkOperation(); + }; + + /*! \ingroup undo @@ -2439,6 +2742,7 @@ namespace BinaryNinja { public: FileMetadata(); FileMetadata(const std::string& filename); + FileMetadata(Ref<ProjectFile> projectFile); FileMetadata(BNFileMetadata* file); /*! Close the underlying file handle @@ -2646,10 +2950,6 @@ namespace BinaryNinja { std::optional<std::string> GetLastRedoEntryTitle(); void ClearUndoEntries(); - bool OpenProject(); - void CloseProject(); - bool IsProjectOpen(); - /*! Get the current View name, e.g. ``Linear:ELF``, ``Graph:PE`` \return The current view name @@ -2706,11 +3006,13 @@ namespace BinaryNinja { \param data the binary view to unregister */ void UnregisterViewOfType(const std::string& type, BinaryNinja::Ref<BinaryNinja::BinaryView> data); + + Ref<ProjectFile> GetProjectFile() const; + void SetProjectFile(Ref<ProjectFile> projectFile); }; class Function; struct DataVariable; - class Symbol; class Tag; class TagType; struct TagReference; @@ -2770,6 +3072,12 @@ namespace BinaryNinja { static void ComponentFunctionRemovedCallback(void* ctxt, BNBinaryView* data, BNComponent* component, BNFunction* function); static void ComponentDataVariableAddedCallback(void* ctxt, BNBinaryView* data, BNComponent* component, BNDataVariable* var); static void ComponentDataVariableRemovedCallback(void* ctxt, BNBinaryView* data, BNComponent* component, BNDataVariable* var); + static void ExternalLibraryAddedCallback(void* ctxt, BNBinaryView* data, BNExternalLibrary* library); + static void ExternalLibraryUpdatedCallback(void* ctxt, BNBinaryView* data, BNExternalLibrary* library); + static void ExternalLibraryRemovedCallback(void* ctxt, BNBinaryView* data, BNExternalLibrary* library); + static void ExternalLocationAddedCallback(void* ctxt, BNBinaryView* data, BNExternalLocation* location); + static void ExternalLocationUpdatedCallback(void* ctxt, BNBinaryView* data, BNExternalLocation* location); + static void ExternalLocationRemovedCallback(void* ctxt, BNBinaryView* data, BNExternalLocation* location); public: @@ -2814,6 +3122,12 @@ namespace BinaryNinja { ComponentFunctionRemoved = 1ULL << 36, ComponentDataVariableAdded = 1ULL << 37, ComponentDataVariableRemoved = 1ULL << 38, + ExternalLibraryAdded = 1ULL << 39, + ExternalLibraryUpdated = 1ULL << 40, + ExternalLibraryRemoved = 1ULL << 41, + ExternalLocationAdded = 1ULL << 42, + ExternalLocationUpdated = 1ULL << 43, + ExternalLocationRemoved = 1ULL << 44, BinaryDataUpdates = DataWritten | DataInserted | DataRemoved, FunctionLifetime = FunctionAdded | FunctionRemoved, @@ -3120,6 +3434,42 @@ namespace BinaryNinja { (void)component; (void)var; } + + virtual void OnExternalLibraryAdded(BinaryView* data, ExternalLibrary* library) + { + (void)data; + (void)library; + } + + virtual void OnExternalLibraryUpdated(BinaryView* data, ExternalLibrary* library) + { + (void)data; + (void)library; + } + + virtual void OnExternalLibraryRemoved(BinaryView* data, ExternalLibrary* library) + { + (void)data; + (void)library; + } + + virtual void OnExternalLocationAdded(BinaryView* data, ExternalLocation* location) + { + (void)data; + (void)location; + } + + virtual void OnExternalLocationUpdated(BinaryView* data, ExternalLocation* location) + { + (void)data; + (void)location; + } + + virtual void OnExternalLocationRemoved(BinaryView* data, ExternalLocation* location) + { + (void)data; + (void)location; + } }; /*! @@ -3233,9 +3583,9 @@ namespace BinaryNinja { */ class QualifiedName : public NameList { - public: - using NameList::operator=; using NameList::operator+; + using NameList::operator=; + public: QualifiedName(); QualifiedName(const BNQualifiedName* name); @@ -3260,9 +3610,9 @@ namespace BinaryNinja { */ class NameSpace : public NameList { - public: - using NameList::operator=; using NameList::operator+; + using NameList::operator=; + public: NameSpace(); NameSpace(const std::string& name); @@ -6008,6 +6358,16 @@ namespace BinaryNinja { \return Whether the magic value exists */ bool GetExpressionParserMagicValue(const std::string& name, uint64_t* value); + + Ref<ExternalLibrary> AddExternalLibrary(const std::string& name, Ref<ProjectFile> backingFile, bool isAuto = false); + void RemoveExternalLibrary(const std::string& name); + Ref<ExternalLibrary> GetExternalLibrary(const std::string& name); + std::vector<Ref<ExternalLibrary>> GetExternalLibraries(); + + Ref<ExternalLocation> AddExternalLocation(Ref<Symbol> internalSymbol, Ref<ExternalLibrary> library, std::optional<std::string> externalSymbol, std::optional<uint64_t> externalAddress, bool isAuto = false); + void RemoveExternalLocation(Ref<Symbol> internalSymbol); + Ref<ExternalLocation> GetExternalLocation(Ref<Symbol> internalSymbol); + std::vector<Ref<ExternalLocation>> GetExternalLocations(); }; @@ -14815,6 +15175,7 @@ namespace BinaryNinja { bool IsCancelled() const; bool IsFinished() const; std::string GetProgressText() const; + uint64_t GetRuntimeSeconds() const; void Cancel(); void Finish(); @@ -15037,7 +15398,7 @@ namespace BinaryNinja { ================= ========================== ============== ============================================== Default SettingsDefaultScope Lowest Settings Schema User SettingsUserScope - <User Directory>/settings.json - Project SettingsProjectScope - <Project Directory>/.binaryninja/settings.json + Project SettingsProjectScope - <Project Directory>/settings.json Resource SettingsResourceScope Highest Raw BinaryView (Storage in BNDB) ================= ========================== ============== ============================================== diff --git a/binaryninjacore.h b/binaryninjacore.h index 3bea2623..db945810 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -132,6 +132,8 @@ #define DEFAULT_INTERNAL_NAMESPACE "BNINTERNALNAMESPACE" #define DEFAULT_EXTERNAL_NAMESPACE "BNEXTERNALNAMESPACE" +#define BNDB_SUFFIX "bndb" +#define BNDB_EXT ("." BNDB_SUFFIX) // The BN_DECLARE_CORE_ABI_VERSION must be included in native plugin modules. If // the ABI version is not declared, the core will not load the plugin. @@ -265,6 +267,11 @@ extern "C" typedef struct BNLogger BNLogger; typedef struct BNSymbolQueue BNSymbolQueue; typedef struct BNTypeContainer BNTypeContainer; + typedef struct BNProject BNProject; + typedef struct BNProjectFile BNProjectFile; + typedef struct BNExternalLibrary BNExternalLibrary; + typedef struct BNExternalLocation BNExternalLocation; + typedef struct BNProjectFolder BNProjectFolder; //! Console log levels typedef enum BNLogLevel @@ -1495,8 +1502,37 @@ extern "C" void (*componentFunctionRemoved)(void*ctxt, BNBinaryView* view, BNComponent* component, BNFunction* function); void (*componentDataVariableAdded)(void*ctxt, BNBinaryView* view, BNComponent* component, BNDataVariable* var); void (*componentDataVariableRemoved)(void*ctxt, BNBinaryView* view, BNComponent* component, BNDataVariable* var); + void (*externalLibraryAdded)(void* ctxt, BNBinaryView* data, BNExternalLibrary* library); + void (*externalLibraryUpdated)(void* ctxt, BNBinaryView* data, BNExternalLibrary* library); + void (*externalLibraryRemoved)(void* ctxt, BNBinaryView* data, BNExternalLibrary* library); + void (*externalLocationAdded)(void* ctxt, BNBinaryView* data, BNExternalLocation* location); + void (*externalLocationUpdated)(void* ctxt, BNBinaryView* data, BNExternalLocation* location); + void (*externalLocationRemoved)(void* ctxt, BNBinaryView* data, BNExternalLocation* location); } BNBinaryDataNotification; + typedef struct BNProjectNotification + { + void* context; + bool (*beforeOpenProject)(void* ctxt, BNProject* project); + void (*afterOpenProject)(void* ctxt, BNProject* project); + bool (*beforeCloseProject)(void* ctxt, BNProject* project); + void (*afterCloseProject)(void* ctxt, BNProject* project); + bool (*beforeProjectMetadataWritten)(void* ctxt, BNProject* project, char* key, BNMetadata* value); + void (*afterProjectMetadataWritten)(void* ctxt, BNProject* project, char* key, BNMetadata* value); + bool (*beforeProjectFileCreated)(void* ctxt, BNProject* project, BNProjectFile* projectFile); + void (*afterProjectFileCreated)(void* ctxt, BNProject* project, BNProjectFile* projectFile); + bool (*beforeProjectFileUpdated)(void* ctxt, BNProject* project, BNProjectFile* projectFile); + void (*afterProjectFileUpdated)(void* ctxt, BNProject* project, BNProjectFile* projectFile); + bool (*beforeProjectFileDeleted)(void* ctxt, BNProject* project, BNProjectFile* projectFile); + void (*afterProjectFileDeleted)(void* ctxt, BNProject* project, BNProjectFile* projectFile); + bool (*beforeProjectFolderCreated)(void* ctxt, BNProject* project, BNProjectFolder* projectFolder); + void (*afterProjectFolderCreated)(void* ctxt, BNProject* project, BNProjectFolder* projectFolder); + bool (*beforeProjectFolderUpdated)(void* ctxt, BNProject* project, BNProjectFolder* projectFolder); + void (*afterProjectFolderUpdated)(void* ctxt, BNProject* project, BNProjectFolder* projectFolder); + bool (*beforeProjectFolderDeleted)(void* ctxt, BNProject* project, BNProjectFolder* projectFolder); + void (*afterProjectFolderDeleted)(void* ctxt, BNProject* project, BNProjectFolder* projectFolder); + } BNProjectNotification; + typedef struct BNFileAccessor { void* context; @@ -3058,6 +3094,8 @@ extern "C" BINARYNINJACOREAPI bool BNIsUIEnabled(void); BINARYNINJACOREAPI void BNSetLicense(const char* licenseData); + BINARYNINJACOREAPI bool BNIsDatabase(const char* filename); + BINARYNINJACOREAPI bool BNAuthenticateEnterpriseServerWithCredentials( const char* username, const char* password, bool remember); BINARYNINJACOREAPI bool BNAuthenticateEnterpriseServerWithMethod(const char* method, bool remember); @@ -3214,7 +3252,7 @@ extern "C" BINARYNINJACOREAPI void BNSetSaveSettingsName(BNSaveSettings* settings, const char* name); // File metadata object - BINARYNINJACOREAPI BNFileMetadata* BNCreateFileMetadata(void); + BINARYNINJACOREAPI BNFileMetadata* BNCreateFileMetadata(); BINARYNINJACOREAPI BNFileMetadata* BNNewFileReference(BNFileMetadata* file); BINARYNINJACOREAPI void BNFreeFileMetadata(BNFileMetadata* file); BINARYNINJACOREAPI void BNCloseFile(BNFileMetadata* file); @@ -3266,6 +3304,108 @@ extern "C" BINARYNINJACOREAPI size_t BNGetKeyValueStoreValueStorageSize(BNKeyValueStore* store); BINARYNINJACOREAPI size_t BNGetKeyValueStoreNamespaceSize(BNKeyValueStore* store); + // Project object + BINARYNINJACOREAPI BNProject* BNNewProjectReference(BNProject* project); + BINARYNINJACOREAPI void BNFreeProject(BNProject* project); + BINARYNINJACOREAPI void BNFreeProjectList(BNProject** projects, size_t count); + BINARYNINJACOREAPI BNProject** BNGetOpenProjects(size_t* count); + BINARYNINJACOREAPI BNProject* BNCreateProject(const char* path, const char* name); + BINARYNINJACOREAPI BNProject* BNOpenProject(const char* path); + BINARYNINJACOREAPI bool BNProjectOpen(BNProject* project); + BINARYNINJACOREAPI bool BNProjectClose(BNProject* project); + BINARYNINJACOREAPI char* BNProjectGetId(BNProject* project); + BINARYNINJACOREAPI bool BNProjectIsOpen(BNProject* project); + BINARYNINJACOREAPI char* BNProjectGetPath(BNProject* project); + BINARYNINJACOREAPI char* BNProjectGetName(BNProject* project); + BINARYNINJACOREAPI void BNProjectSetName(BNProject* project, const char* name); + BINARYNINJACOREAPI char* BNProjectGetDescription(BNProject* project); + BINARYNINJACOREAPI void BNProjectSetDescription(BNProject* project, const char* description); + + BINARYNINJACOREAPI BNMetadata* BNProjectQueryMetadata(BNProject* project, const char* key); + BINARYNINJACOREAPI bool BNProjectStoreMetadata(BNProject* project, const char* key, BNMetadata* value); + BINARYNINJACOREAPI void BNProjectRemoveMetadata(BNProject* project, const char* key); + + BINARYNINJACOREAPI BNProjectFile* BNProjectCreateFileFromPath(BNProject* project, const char* path, BNProjectFolder* folder, const char* name, const char* description, void* ctxt, + bool (*progress)(void* ctxt, size_t progress, size_t total)); + BINARYNINJACOREAPI BNProjectFile* BNProjectCreateFileFromPathUnsafe(BNProject* project, const char* path, BNProjectFolder* folder, const char* name, const char* description, const char* id, void* ctxt, + bool (*progress)(void* ctxt, size_t progress, size_t total)); + BINARYNINJACOREAPI BNProjectFile* BNProjectCreateFile(BNProject* project, const uint8_t* contents, size_t contentsSize, BNProjectFolder* folder, const char* name, const char* description, void* ctxt, + bool (*progress)(void* ctxt, size_t progress, size_t total)); + BINARYNINJACOREAPI BNProjectFile* BNProjectCreateFileUnsafe(BNProject* project, const uint8_t* contents, size_t contentsSize, BNProjectFolder* folder, const char* name, const char* description, const char* id, void* ctxt, + bool (*progress)(void* ctxt, size_t progress, size_t total)); + BINARYNINJACOREAPI BNProjectFile** BNProjectGetFiles(BNProject* project, size_t* count); + BINARYNINJACOREAPI BNProjectFile* BNProjectGetFileById(BNProject* project, const char* id); + BINARYNINJACOREAPI BNProjectFile* BNProjectGetFileByPathOnDisk(BNProject* project, const char* path); + + BINARYNINJACOREAPI void BNProjectPushFile(BNProject* project, BNProjectFile* file); + BINARYNINJACOREAPI void BNProjectDeleteFile(BNProject* project, BNProjectFile* file); + + BINARYNINJACOREAPI BNProjectFolder* BNProjectCreateFolderFromPath(BNProject* project, const char* path, BNProjectFolder* parent, const char* description, void* ctxt, + bool (*progress)(void* ctxt, size_t progress, size_t total)); + BINARYNINJACOREAPI BNProjectFolder* BNProjectCreateFolder(BNProject* project, BNProjectFolder* parent, const char* name, const char* description); + BINARYNINJACOREAPI BNProjectFolder* BNProjectCreateFolderUnsafe(BNProject* project, BNProjectFolder* parent, const char* name, const char* description, const char* id); + BINARYNINJACOREAPI BNProjectFolder** BNProjectGetFolders(BNProject* project, size_t* count); + BINARYNINJACOREAPI BNProjectFolder* BNProjectGetFolderById(BNProject* project, const char* id); + BINARYNINJACOREAPI void BNProjectPushFolder(BNProject* project, BNProjectFolder* folder); + BINARYNINJACOREAPI void BNProjectDeleteFolder(BNProject* project, BNProjectFolder* folder, void* ctxt, + bool (*progress)(void* ctxt, size_t progress, size_t total)); + + BINARYNINJACOREAPI void BNProjectBeginBulkOperation(BNProject* project); + BINARYNINJACOREAPI void BNProjectEndBulkOperation(BNProject* project); + + // ProjectFile object + BINARYNINJACOREAPI BNProjectFile* BNNewProjectFileReference(BNProjectFile* file); + BINARYNINJACOREAPI void BNFreeProjectFile(BNProjectFile* file); + BINARYNINJACOREAPI void BNFreeProjectFileList(BNProjectFile** files, size_t count); + BINARYNINJACOREAPI char* BNProjectFileGetPathOnDisk(BNProjectFile* file); + BINARYNINJACOREAPI bool BNProjectFileExistsOnDisk(BNProjectFile* file); + BINARYNINJACOREAPI char* BNProjectFileGetName(BNProjectFile* file); + BINARYNINJACOREAPI void BNProjectFileSetName(BNProjectFile* file, const char* name); + BINARYNINJACOREAPI char* BNProjectFileGetDescription(BNProjectFile* file); + BINARYNINJACOREAPI void BNProjectFileSetDescription(BNProjectFile* file, const char* description); + BINARYNINJACOREAPI char* BNProjectFileGetId(BNProjectFile* file); + BINARYNINJACOREAPI BNProjectFolder* BNProjectFileGetFolder(BNProjectFile* file); + BINARYNINJACOREAPI void BNProjectFileSetFolder(BNProjectFile* file, BNProjectFolder* folder); + BINARYNINJACOREAPI BNProject* BNProjectFileGetProject(BNProjectFile* file); + BINARYNINJACOREAPI bool BNProjectFileExport(BNProjectFile* file, const char* destination); + + // ProjectFolder object + BINARYNINJACOREAPI BNProjectFolder* BNNewProjectFolderReference(BNProjectFolder* folder); + BINARYNINJACOREAPI void BNFreeProjectFolder(BNProjectFolder* folder); + BINARYNINJACOREAPI void BNFreeProjectFolderList(BNProjectFolder** folders, size_t count); + BINARYNINJACOREAPI char* BNProjectFolderGetId(BNProjectFolder* folder); + BINARYNINJACOREAPI char* BNProjectFolderGetName(BNProjectFolder* folder); + BINARYNINJACOREAPI void BNProjectFolderSetName(BNProjectFolder* folder, const char* name); + BINARYNINJACOREAPI char* BNProjectFolderGetDescription(BNProjectFolder* folder); + BINARYNINJACOREAPI void BNProjectFolderSetDescription(BNProjectFolder* folder, const char* description); + BINARYNINJACOREAPI BNProjectFolder* BNProjectFolderGetParent(BNProjectFolder* folder); + BINARYNINJACOREAPI void BNProjectFolderSetParent(BNProjectFolder* folder, BNProjectFolder* parent); + BINARYNINJACOREAPI BNProject* BNProjectFolderGetProject(BNProjectFolder* folder); + BINARYNINJACOREAPI bool BNProjectFolderExport(BNProjectFolder* folder, const char* destination, void* ctxt, + bool (*progress)(void* ctxt, size_t progress, size_t total)); + + // ExternalLibrary object + BINARYNINJACOREAPI BNExternalLibrary* BNNewExternalLibraryReference(BNExternalLibrary* lib); + BINARYNINJACOREAPI void BNFreeExternalLibrary(BNExternalLibrary* lib); + BINARYNINJACOREAPI void BNFreeExternalLibraryList(BNExternalLibrary** libs, size_t count); + BINARYNINJACOREAPI char* BNExternalLibraryGetName(BNExternalLibrary* lib); + BINARYNINJACOREAPI void BNExternalLibrarySetBackingFile(BNExternalLibrary* lib, BNProjectFile* file); + BINARYNINJACOREAPI BNProjectFile* BNExternalLibraryGetBackingFile(BNExternalLibrary* lib); + + // ExternalLocation object + BINARYNINJACOREAPI BNExternalLocation* BNNewExternalLocationReference(BNExternalLocation*loc); + BINARYNINJACOREAPI void BNFreeExternalLocation(BNExternalLocation*loc); + BINARYNINJACOREAPI void BNFreeExternalLocationList(BNExternalLocation**locs, size_t count); + BINARYNINJACOREAPI BNSymbol* BNExternalLocationGetInternalSymbol(BNExternalLocation* loc); + BINARYNINJACOREAPI uint64_t BNExternalLocationGetAddress(BNExternalLocation* loc); + BINARYNINJACOREAPI char* BNExternalLocationGetSymbol(BNExternalLocation* loc); + BINARYNINJACOREAPI BNExternalLibrary* BNExternalLocationGetExternalLibrary(BNExternalLocation* loc); + BINARYNINJACOREAPI bool BNExternalLocationHasAddress(BNExternalLocation* loc); + BINARYNINJACOREAPI bool BNExternalLocationHasSymbol(BNExternalLocation* loc); + BINARYNINJACOREAPI void BNExternalLocationSetAddress(BNExternalLocation* loc, uint64_t* address); + BINARYNINJACOREAPI void BNExternalLocationSetSymbol(BNExternalLocation* loc, const char* symbol); + BINARYNINJACOREAPI void BNExternalLocationSetExternalLibrary(BNExternalLocation* loc, BNExternalLibrary* library); + // Database object BINARYNINJACOREAPI BNDatabase* BNNewDatabaseReference(BNDatabase* database); BINARYNINJACOREAPI void BNFreeDatabase(BNDatabase* database); @@ -3285,6 +3425,7 @@ extern "C" BINARYNINJACOREAPI BNDataBuffer* BNReadDatabaseGlobalData(BNDatabase* database, const char* key); BINARYNINJACOREAPI bool BNWriteDatabaseGlobalData(BNDatabase* database, const char* key, BNDataBuffer* val); BINARYNINJACOREAPI BNFileMetadata* BNGetDatabaseFile(BNDatabase* database); + BINARYNINJACOREAPI void BNDatabaseReloadConnection(BNDatabase* database); BINARYNINJACOREAPI BNKeyValueStore* BNReadDatabaseAnalysisCache(BNDatabase* database); BINARYNINJACOREAPI bool BNWriteDatabaseAnalysisCache(BNDatabase* database, BNKeyValueStore* val); BINARYNINJACOREAPI bool BNSnapshotHasData(BNDatabase* db, int64_t id); @@ -3330,6 +3471,9 @@ extern "C" BINARYNINJACOREAPI char* BNGetFilename(BNFileMetadata* file); BINARYNINJACOREAPI void BNSetFilename(BNFileMetadata* file, const char* name); + BINARYNINJACOREAPI BNProjectFile* BNGetProjectFile(BNFileMetadata* file); + BINARYNINJACOREAPI void BNSetProjectFile(BNFileMetadata* file, BNProjectFile* pfile); + BINARYNINJACOREAPI char* BNBeginUndoActions(BNFileMetadata* file, bool anonymousAllowed); BINARYNINJACOREAPI void BNCommitUndoActions(BNFileMetadata* file, const char* id); BINARYNINJACOREAPI void BNRevertUndoActions(BNFileMetadata* file, const char* id); @@ -3357,10 +3501,6 @@ extern "C" BINARYNINJACOREAPI char* BNGetUserEmail(BNUser* user); BINARYNINJACOREAPI char* BNGetUserId(BNUser* user); - BINARYNINJACOREAPI bool BNOpenProject(BNFileMetadata* file); - BINARYNINJACOREAPI void BNCloseProject(BNFileMetadata* file); - BINARYNINJACOREAPI bool BNIsProjectOpen(BNFileMetadata* file); - BINARYNINJACOREAPI char* BNGetCurrentView(BNFileMetadata* file); BINARYNINJACOREAPI uint64_t BNGetCurrentOffset(BNFileMetadata* file); BINARYNINJACOREAPI bool BNNavigate(BNFileMetadata* file, const char* view, uint64_t offset); @@ -3444,6 +3584,9 @@ extern "C" BINARYNINJACOREAPI void BNRegisterDataNotification(BNBinaryView* view, BNBinaryDataNotification* notify); BINARYNINJACOREAPI void BNUnregisterDataNotification(BNBinaryView* view, BNBinaryDataNotification* notify); + BINARYNINJACOREAPI void BNRegisterProjectNotification(BNProject* project, BNProjectNotification* notify); + BINARYNINJACOREAPI void BNUnregisterProjectNotification(BNProject* project, BNProjectNotification* notify); + BINARYNINJACOREAPI bool BNCanAssemble(BNBinaryView* view, BNArchitecture* arch); BINARYNINJACOREAPI bool BNIsNeverBranchPatchAvailable(BNBinaryView* view, BNArchitecture* arch, uint64_t addr); @@ -5709,9 +5852,20 @@ extern "C" BINARYNINJACOREAPI BNBinaryView* BNLoadFilename(const char* const filename, const bool updateAnalysis, bool (*progress)(size_t, size_t), const BNMetadata* const options); + BINARYNINJACOREAPI BNBinaryView* BNLoadProjectFile(BNProjectFile* projectFile, const bool updateAnalysis, + bool (*progress)(size_t, size_t), const BNMetadata* const options); BINARYNINJACOREAPI BNBinaryView* BNLoadBinaryView(BNBinaryView* view, const bool updateAnalysis, bool (*progress)(size_t, size_t), const BNMetadata* const options, const bool isDatabase); + BINARYNINJACOREAPI BNExternalLibrary* BNBinaryViewAddExternalLibrary(BNBinaryView* view, const char* name, BNProjectFile* backingFile, bool isAuto); + BINARYNINJACOREAPI void BNBinaryViewRemoveExternalLibrary(BNBinaryView* view, const char* name); + BINARYNINJACOREAPI BNExternalLibrary* BNBinaryViewGetExternalLibrary(BNBinaryView* view, const char* name); + BINARYNINJACOREAPI BNExternalLibrary** BNBinaryViewGetExternalLibraries(BNBinaryView* view, size_t* count); + BINARYNINJACOREAPI BNExternalLocation* BNBinaryViewAddExternalLocation(BNBinaryView* view, BNSymbol* internalSymbol, BNExternalLibrary* library, const char* externalSymbol, uint64_t* externalAddress, bool isAuto); + BINARYNINJACOREAPI void BNBinaryViewRemoveExternalLocation(BNBinaryView* view, BNSymbol* internalSymbol); + BINARYNINJACOREAPI BNExternalLocation* BNBinaryViewGetExternalLocation(BNBinaryView* view, BNSymbol* internalSymbol); + BINARYNINJACOREAPI BNExternalLocation** BNBinaryViewGetExternalLocations(BNBinaryView* view, size_t* count); + // Source code processing BINARYNINJACOREAPI bool BNPreprocessSource(const char* source, const char* fileName, char** output, char** errors, const char** includeDirs, size_t includeDirCount); @@ -6145,6 +6299,7 @@ extern "C" BINARYNINJACOREAPI void BNFreeBackgroundTask(BNBackgroundTask* task); BINARYNINJACOREAPI void BNFreeBackgroundTaskList(BNBackgroundTask** tasks, size_t count); BINARYNINJACOREAPI char* BNGetBackgroundTaskProgressText(BNBackgroundTask* task); + BINARYNINJACOREAPI uint64_t BNGetBackgroundTaskRuntimeSeconds(BNBackgroundTask* task); BINARYNINJACOREAPI bool BNCanCancelBackgroundTask(BNBackgroundTask* task); BINARYNINJACOREAPI void BNCancelBackgroundTask(BNBackgroundTask* task); BINARYNINJACOREAPI bool BNIsBackgroundTaskFinished(BNBackgroundTask* task); diff --git a/binaryview.cpp b/binaryview.cpp index 7d79a839..600b46ac 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -408,6 +408,60 @@ void BinaryDataNotification::ComponentDataVariableRemovedCallback(void* ctxt, BN } +void BinaryDataNotification::ExternalLibraryAddedCallback(void* ctxt, BNBinaryView* data, BNExternalLibrary* library) +{ + BinaryDataNotification* notify = (BinaryDataNotification*)ctxt; + Ref<BinaryView> view = new BinaryView(BNNewViewReference(data)); + Ref<ExternalLibrary> libraryObj = new ExternalLibrary(BNNewExternalLibraryReference(library)); + notify->OnExternalLibraryAdded(view, libraryObj); +} + + +void BinaryDataNotification::ExternalLibraryUpdatedCallback(void* ctxt, BNBinaryView* data, BNExternalLibrary* library) +{ + BinaryDataNotification* notify = (BinaryDataNotification*)ctxt; + Ref<BinaryView> view = new BinaryView(BNNewViewReference(data)); + Ref<ExternalLibrary> libraryObj = new ExternalLibrary(BNNewExternalLibraryReference(library)); + notify->OnExternalLibraryUpdated(view, libraryObj); +} + + +void BinaryDataNotification::ExternalLibraryRemovedCallback(void* ctxt, BNBinaryView* data, BNExternalLibrary* library) +{ + BinaryDataNotification* notify = (BinaryDataNotification*)ctxt; + Ref<BinaryView> view = new BinaryView(BNNewViewReference(data)); + Ref<ExternalLibrary> libraryObj = new ExternalLibrary(BNNewExternalLibraryReference(library)); + notify->OnExternalLibraryRemoved(view, libraryObj); +} + + +void BinaryDataNotification::ExternalLocationAddedCallback(void* ctxt, BNBinaryView* data, BNExternalLocation* location) +{ + BinaryDataNotification* notify = (BinaryDataNotification*)ctxt; + Ref<BinaryView> view = new BinaryView(BNNewViewReference(data)); + Ref<ExternalLocation> locationObj = new ExternalLocation(BNNewExternalLocationReference(location)); + notify->OnExternalLocationAdded(view, locationObj); +} + + +void BinaryDataNotification::ExternalLocationUpdatedCallback(void* ctxt, BNBinaryView* data, BNExternalLocation* location) +{ + BinaryDataNotification* notify = (BinaryDataNotification*)ctxt; + Ref<BinaryView> view = new BinaryView(BNNewViewReference(data)); + Ref<ExternalLocation> locationObj = new ExternalLocation(BNNewExternalLocationReference(location)); + notify->OnExternalLocationUpdated(view, locationObj); +} + + +void BinaryDataNotification::ExternalLocationRemovedCallback(void* ctxt, BNBinaryView* data, BNExternalLocation* location) +{ + BinaryDataNotification* notify = (BinaryDataNotification*)ctxt; + Ref<BinaryView> view = new BinaryView(BNNewViewReference(data)); + Ref<ExternalLocation> locationObj = new ExternalLocation(BNNewExternalLocationReference(location)); + notify->OnExternalLocationRemoved(view, locationObj); +} + + BinaryDataNotification::BinaryDataNotification() { m_callbacks.context = this; @@ -450,6 +504,12 @@ BinaryDataNotification::BinaryDataNotification() m_callbacks.componentFunctionRemoved = ComponentFunctionRemovedCallback; m_callbacks.componentDataVariableAdded = ComponentDataVariableAddedCallback; m_callbacks.componentDataVariableRemoved = ComponentDataVariableRemovedCallback; + m_callbacks.externalLibraryAdded = ExternalLibraryAddedCallback; + m_callbacks.externalLibraryUpdated = ExternalLibraryUpdatedCallback; + m_callbacks.externalLibraryRemoved = ExternalLibraryRemovedCallback; + m_callbacks.externalLocationAdded = ExternalLocationAddedCallback; + m_callbacks.externalLocationUpdated = ExternalLocationUpdatedCallback; + m_callbacks.externalLocationRemoved = ExternalLocationRemovedCallback; } @@ -495,6 +555,12 @@ BinaryDataNotification::BinaryDataNotification(NotificationTypes notifications) m_callbacks.componentFunctionRemoved = (notifications & NotificationType::ComponentFunctionRemoved) ? ComponentFunctionRemovedCallback : nullptr; m_callbacks.componentDataVariableAdded = (notifications & NotificationType::ComponentDataVariableAdded) ? ComponentDataVariableAddedCallback : nullptr; m_callbacks.componentDataVariableRemoved = (notifications & NotificationType::ComponentDataVariableRemoved) ? ComponentDataVariableRemovedCallback : nullptr; + m_callbacks.externalLibraryAdded = (notifications & NotificationType::ExternalLibraryAdded) ? ExternalLibraryAddedCallback : nullptr; + m_callbacks.externalLibraryUpdated = (notifications & NotificationType::ExternalLibraryUpdated) ? ExternalLibraryUpdatedCallback : nullptr; + m_callbacks.externalLibraryRemoved = (notifications & NotificationType::ExternalLibraryRemoved) ? ExternalLibraryRemovedCallback : nullptr; + m_callbacks.externalLocationAdded = (notifications & NotificationType::ExternalLocationAdded) ? ExternalLocationAddedCallback : nullptr; + m_callbacks.externalLocationUpdated = (notifications & NotificationType::ExternalLocationUpdated) ? ExternalLocationUpdatedCallback : nullptr; + m_callbacks.externalLocationRemoved = (notifications & NotificationType::ExternalLocationRemoved) ? ExternalLocationRemovedCallback : nullptr; } @@ -4773,6 +4839,91 @@ void BinaryView::RemoveExpressionParserMagicValues(const vector<string>& names) } +Ref<ExternalLibrary> BinaryView::AddExternalLibrary(const std::string& name, Ref<ProjectFile> backingFile, bool isAuto) +{ + BNExternalLibrary* lib = BNBinaryViewAddExternalLibrary(m_object, name.c_str(), backingFile ? backingFile->m_object : nullptr, isAuto); + if (!lib) + return nullptr; + return new ExternalLibrary(BNNewExternalLibraryReference(lib)); +} + + +void BinaryView::RemoveExternalLibrary(const std::string& name) +{ + BNBinaryViewRemoveExternalLibrary(m_object, name.c_str()); +} + + +Ref<ExternalLibrary> BinaryView::GetExternalLibrary(const std::string& name) +{ + BNExternalLibrary* lib = BNBinaryViewGetExternalLibrary(m_object, name.c_str()); + if (!lib) + return nullptr; + return new ExternalLibrary(BNNewExternalLibraryReference(lib)); +} + + +std::vector<Ref<ExternalLibrary>> BinaryView::GetExternalLibraries() +{ + size_t count; + BNExternalLibrary** libs = BNBinaryViewGetExternalLibraries(m_object, &count); + + vector<Ref<ExternalLibrary>> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.push_back(new ExternalLibrary(BNNewExternalLibraryReference(libs[i]))); + + BNFreeExternalLibraryList(libs, count); + return result; +} + + +Ref<ExternalLocation> BinaryView::AddExternalLocation(Ref<Symbol> internalSymbol, Ref<ExternalLibrary> library, std::optional<std::string> externalSymbol, std::optional<uint64_t> externalAddress, bool isAuto) +{ + BNExternalLocation* loc = BNBinaryViewAddExternalLocation(m_object, + internalSymbol->GetObject(), + library ? library->m_object : nullptr, + externalSymbol.has_value() ? externalSymbol.value().c_str() : nullptr, + externalAddress.has_value() ? &externalAddress.value() : nullptr, + isAuto + ); + + if (!loc) + return nullptr; + return new ExternalLocation(BNNewExternalLocationReference(loc)); +} + + +void BinaryView::RemoveExternalLocation(Ref<Symbol> internalSymbol) +{ + BNBinaryViewRemoveExternalLocation(m_object, internalSymbol->GetObject()); +} + + +Ref<ExternalLocation> BinaryView::GetExternalLocation(Ref<Symbol> internalSymbol) +{ + BNExternalLocation* loc = BNBinaryViewGetExternalLocation(m_object, internalSymbol->GetObject()); + if (!loc) + return nullptr; + return new ExternalLocation(BNNewExternalLocationReference(loc)); +} + + +std::vector<Ref<ExternalLocation>> BinaryView::GetExternalLocations() +{ + size_t count; + BNExternalLocation** locs = BNBinaryViewGetExternalLocations(m_object, &count); + + vector<Ref<ExternalLocation>> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.push_back(new ExternalLocation(BNNewExternalLocationReference(locs[i]))); + + BNFreeExternalLocationList(locs, count); + return result; +} + + Relocation::Relocation(BNRelocation* reloc) { m_object = reloc; diff --git a/database.cpp b/database.cpp index 8f9912e8..26802f29 100644 --- a/database.cpp +++ b/database.cpp @@ -541,6 +541,12 @@ Ref<FileMetadata> Database::GetFile() } +void Database::ReloadConnection() +{ + BNDatabaseReloadConnection(m_object); +} + + Ref<KeyValueStore> Database::ReadAnalysisCache() const { BNKeyValueStore* store = BNReadDatabaseAnalysisCache(m_object); diff --git a/externallibrary.cpp b/externallibrary.cpp new file mode 100644 index 00000000..77b9cabc --- /dev/null +++ b/externallibrary.cpp @@ -0,0 +1,144 @@ +// Copyright (c) 2015-2023 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 <optional> +#include "binaryninjaapi.h" +#include "binaryninjacore.h" + +using namespace BinaryNinja; + + +ExternalLibrary::ExternalLibrary(BNExternalLibrary* lib) +{ + m_object = lib; +} + + +std::string ExternalLibrary::GetName() const +{ + char* name = BNExternalLibraryGetName(m_object); + std::string result = name; + BNFreeString(name); + return result; +} + + +Ref<ProjectFile> ExternalLibrary::GetBackingFile() const +{ + BNProjectFile* file = BNExternalLibraryGetBackingFile(m_object); + if (!file) + return nullptr; + return new ProjectFile(BNNewProjectFileReference(file)); +} + + +void ExternalLibrary::SetBackingFile(Ref<ProjectFile> file) +{ + BNExternalLibrarySetBackingFile(m_object, file ? file->m_object : nullptr); +} + + +ExternalLocation::ExternalLocation(BNExternalLocation* loc) +{ + m_object = loc; +} + + +Ref<Symbol> ExternalLocation::GetInternalSymbol() +{ + BNSymbol* sym = BNExternalLocationGetInternalSymbol(m_object); + return new Symbol(sym); +} + + +std::optional<uint64_t> ExternalLocation::GetAddress() +{ + if (BNExternalLocationHasAddress(m_object)) + { + return BNExternalLocationGetAddress(m_object); + } + return {}; +} + + +std::optional<std::string> ExternalLocation::GetSymbol() +{ + if (BNExternalLocationHasSymbol(m_object)) + { + return BNExternalLocationGetSymbol(m_object); + } + return {}; +} + + +Ref<ExternalLibrary> ExternalLocation::GetExternalLibrary() +{ + BNExternalLibrary* lib = BNExternalLocationGetExternalLibrary(m_object); + if (!lib) + return nullptr; + return new ExternalLibrary(BNNewExternalLibraryReference(lib)); +} + + +bool ExternalLocation::HasAddress() +{ + return BNExternalLocationHasAddress(m_object); +} + + +bool ExternalLocation::HasSymbol() +{ + return BNExternalLocationHasSymbol(m_object); +} + + +void ExternalLocation::SetAddress(std::optional<uint64_t> address) +{ + if (address.has_value()) + { + uint64_t addr = address.value(); + BNExternalLocationSetAddress(m_object, &addr); + } + else + { + BNExternalLocationSetAddress(m_object, nullptr); + } +} + + +void ExternalLocation::SetSymbol(std::optional<std::string> symbol) +{ + if (symbol.has_value()) + { + std::string sym = symbol.value(); + BNExternalLocationSetSymbol(m_object, sym.c_str()); + } + else + { + BNExternalLocationSetSymbol(m_object, nullptr); + } +} + + +void ExternalLocation::SetExternalLibrary(Ref<ExternalLibrary> library) +{ + BNExternalLocationSetExternalLibrary(m_object, library ? library->m_object : nullptr); +} + + diff --git a/filemetadata.cpp b/filemetadata.cpp index 89e759af..656fbce7 100644 --- a/filemetadata.cpp +++ b/filemetadata.cpp @@ -19,6 +19,7 @@ // IN THE SOFTWARE. #include <cstring> #include "binaryninjaapi.h" +#include "binaryninjacore.h" using namespace BinaryNinja; using namespace Json; @@ -69,6 +70,14 @@ FileMetadata::FileMetadata(const string& filename) } +FileMetadata::FileMetadata(Ref<ProjectFile> projectFile) +{ + m_object = BNCreateFileMetadata(); + BNSetProjectFile(m_object, projectFile->m_object); + BNSetFilename(m_object, projectFile->GetPathOnDisk().c_str()); +} + + FileMetadata::FileMetadata(BNFileMetadata* file) { m_object = file; @@ -489,24 +498,6 @@ void FileMetadata::ClearUndoEntries() } -bool FileMetadata::OpenProject() -{ - return BNOpenProject(m_object); -} - - -void FileMetadata::CloseProject() -{ - BNCloseProject(m_object); -} - - -bool FileMetadata::IsProjectOpen() -{ - return BNIsProjectOpen(m_object); -} - - string FileMetadata::GetCurrentView() { char* view = BNGetCurrentView(m_object); @@ -569,6 +560,21 @@ void FileMetadata::UnregisterViewOfType(const std::string& type, BinaryNinja::Re } +void FileMetadata::SetProjectFile(Ref<ProjectFile> projectFile) +{ + BNSetProjectFile(m_object, projectFile ? projectFile->m_object : nullptr); +} + + +Ref<ProjectFile> FileMetadata::GetProjectFile() const +{ + BNProjectFile* bin = BNGetProjectFile(m_object); + if (!bin) + return nullptr; + return new ProjectFile(bin); +} + + SaveSettings::SaveSettings() { m_object = BNCreateSaveSettings(); diff --git a/project.cpp b/project.cpp new file mode 100644 index 00000000..b456d66c --- /dev/null +++ b/project.cpp @@ -0,0 +1,683 @@ +// Copyright (c) 2015-2023 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 <cstring> +#include "binaryninjaapi.h" +#include "binaryninjacore.h" + +using namespace BinaryNinja; + + +bool ProjectNotification::BeforeOpenProjectCallback(void* ctxt, BNProject* object) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + return notify->OnBeforeOpenProject(project); +} + + +void ProjectNotification::AfterOpenProjectCallback(void* ctxt, BNProject* object) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + notify->OnAfterOpenProject(project); +} + + +bool ProjectNotification::BeforeCloseProjectCallback(void* ctxt, BNProject* object) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + return notify->OnBeforeCloseProject(project); +} + + +void ProjectNotification::AfterCloseProjectCallback(void* ctxt, BNProject* object) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + notify->OnAfterCloseProject(project); +} + + +bool ProjectNotification::BeforeProjectMetadataWrittenCallback(void* ctxt, BNProject* object, char* key, BNMetadata* value) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + std::string keyStr = key; + BNFreeString(key); + Ref<Metadata> metaVal = new Metadata(BNNewMetadataReference(value)); + return notify->OnBeforeProjectMetadataWritten(project, keyStr, metaVal); +} + + +void ProjectNotification::AfterProjectMetadataWrittenCallback(void* ctxt, BNProject* object, char* key, BNMetadata* value) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + std::string keyStr = key; + BNFreeString(key); + Ref<Metadata> metaVal = new Metadata(BNNewMetadataReference(value)); + notify->OnAfterProjectMetadataWritten(project, keyStr, metaVal); +} + + +bool ProjectNotification::BeforeProjectFileCreatedCallback(void* ctxt, BNProject* object, BNProjectFile* bnProjectFile) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + Ref<ProjectFile> projectFile = new ProjectFile(BNNewProjectFileReference(bnProjectFile)); + return notify->OnBeforeProjectFileCreated(project, projectFile); +} + + +void ProjectNotification::AfterProjectFileCreatedCallback(void* ctxt, BNProject* object, BNProjectFile* bnProjectFile) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + Ref<ProjectFile> projectFile = new ProjectFile(BNNewProjectFileReference(bnProjectFile)); + notify->OnAfterProjectFileCreated(project, projectFile); +} + + +bool ProjectNotification::BeforeProjectFileUpdatedCallback(void* ctxt, BNProject* object, BNProjectFile* bnProjectFile) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + Ref<ProjectFile> projectFile = new ProjectFile(BNNewProjectFileReference(bnProjectFile)); + return notify->OnBeforeProjectFileUpdated(project, projectFile); +} + + +void ProjectNotification::AfterProjectFileUpdatedCallback(void* ctxt, BNProject* object, BNProjectFile* bnProjectFile) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + Ref<ProjectFile> projectFile = new ProjectFile(BNNewProjectFileReference(bnProjectFile)); + notify->OnAfterProjectFileUpdated(project, projectFile); +} + + +bool ProjectNotification::BeforeProjectFileDeletedCallback(void* ctxt, BNProject* object, BNProjectFile* bnProjectFile) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + Ref<ProjectFile> projectFile = new ProjectFile(BNNewProjectFileReference(bnProjectFile)); + return notify->OnBeforeProjectFileDeleted(project, projectFile); +} + + +void ProjectNotification::AfterProjectFileDeletedCallback(void* ctxt, BNProject* object, BNProjectFile* bnProjectFile) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + Ref<ProjectFile> projectFile = new ProjectFile(BNNewProjectFileReference(bnProjectFile)); + notify->OnAfterProjectFileDeleted(project, projectFile); +} + + +bool ProjectNotification::BeforeProjectFolderCreatedCallback(void* ctxt, BNProject* object, BNProjectFolder* bnProjectFolder) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + Ref<ProjectFolder> projectFolder = new ProjectFolder(BNNewProjectFolderReference(bnProjectFolder)); + return notify->OnBeforeProjectFolderCreated(project, projectFolder); +} + + +void ProjectNotification::AfterProjectFolderCreatedCallback(void* ctxt, BNProject* object, BNProjectFolder* bnProjectFolder) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + Ref<ProjectFolder> projectFolder = new ProjectFolder(BNNewProjectFolderReference(bnProjectFolder)); + notify->OnAfterProjectFolderCreated(project, projectFolder); +} + + +bool ProjectNotification::BeforeProjectFolderUpdatedCallback(void* ctxt, BNProject* object, BNProjectFolder* bnProjectFolder) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + Ref<ProjectFolder> projectFolder = new ProjectFolder(BNNewProjectFolderReference(bnProjectFolder)); + return notify->OnBeforeProjectFolderUpdated(project, projectFolder); +} + + +void ProjectNotification::AfterProjectFolderUpdatedCallback(void* ctxt, BNProject* object, BNProjectFolder* bnProjectFolder) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + Ref<ProjectFolder> projectFolder = new ProjectFolder(BNNewProjectFolderReference(bnProjectFolder)); + notify->OnAfterProjectFolderUpdated(project, projectFolder); +} + + +bool ProjectNotification::BeforeProjectFolderDeletedCallback(void* ctxt, BNProject* object, BNProjectFolder* bnProjectFolder) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + Ref<ProjectFolder> projectFolder = new ProjectFolder(BNNewProjectFolderReference(bnProjectFolder)); + return notify->OnBeforeProjectFolderDeleted(project, projectFolder); +} + + +void ProjectNotification::AfterProjectFolderDeletedCallback(void* ctxt, BNProject* object, BNProjectFolder* bnProjectFolder) +{ + ProjectNotification* notify = (ProjectNotification*)ctxt; + Ref<Project> project = new Project(BNNewProjectReference(object)); + Ref<ProjectFolder> projectFolder = new ProjectFolder(BNNewProjectFolderReference(bnProjectFolder)); + notify->OnAfterProjectFolderDeleted(project, projectFolder); +} + + +ProjectNotification::ProjectNotification() +{ + m_callbacks.context = this; + m_callbacks.beforeOpenProject = BeforeOpenProjectCallback; + m_callbacks.afterOpenProject = AfterOpenProjectCallback; + m_callbacks.beforeCloseProject = BeforeCloseProjectCallback; + m_callbacks.afterCloseProject = AfterCloseProjectCallback; + m_callbacks.beforeProjectMetadataWritten = BeforeProjectMetadataWrittenCallback; + m_callbacks.afterProjectMetadataWritten = AfterProjectMetadataWrittenCallback; + m_callbacks.beforeProjectFileCreated = BeforeProjectFileCreatedCallback; + m_callbacks.afterProjectFileCreated = AfterProjectFileCreatedCallback; + m_callbacks.beforeProjectFileUpdated = BeforeProjectFileUpdatedCallback; + m_callbacks.afterProjectFileUpdated = AfterProjectFileUpdatedCallback; + m_callbacks.beforeProjectFileDeleted = BeforeProjectFileDeletedCallback; + m_callbacks.afterProjectFileDeleted = AfterProjectFileDeletedCallback; + m_callbacks.beforeProjectFolderCreated = BeforeProjectFolderCreatedCallback; + m_callbacks.afterProjectFolderCreated = AfterProjectFolderCreatedCallback; + m_callbacks.beforeProjectFolderUpdated = BeforeProjectFolderUpdatedCallback; + m_callbacks.afterProjectFolderUpdated = AfterProjectFolderUpdatedCallback; + m_callbacks.beforeProjectFolderDeleted = BeforeProjectFolderDeletedCallback; + m_callbacks.afterProjectFolderDeleted = AfterProjectFolderDeletedCallback; +} + + +Project::Project(BNProject* project) +{ + m_object = project; +} + + +Ref<Project> Project::CreateProject(const std::string& path, const std::string& name) +{ + BNProject* bnproj = BNCreateProject(path.c_str(), name.c_str()); + if (!bnproj) + return nullptr; + return new Project(bnproj); +} + + +Ref<Project> Project::OpenProject(const std::string& path) +{ + BNProject* bnproj = BNOpenProject(path.c_str()); + if (!bnproj) + return nullptr; + return new Project(bnproj); +} + + +std::vector<Ref<Project>> Project::GetOpenProjects() +{ + size_t count = 0; + BNProject** bnprojs = BNGetOpenProjects(&count); + + std::vector<Ref<Project>> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + result.push_back(new Project(BNNewProjectReference(bnprojs[i]))); + } + BNFreeProjectList(bnprojs, count); + return result; +} + + +bool Project::Open() +{ + return BNProjectOpen(m_object); +} + + +bool Project::Close() +{ + return BNProjectClose(m_object); +} + + +std::string Project::GetId() const +{ + char* id = BNProjectGetId(m_object); + std::string result = id; + BNFreeString(id); + return result; +} + + +bool Project::IsOpen() const +{ + return BNProjectIsOpen(m_object); +} + + +std::string Project::GetPath() const +{ + char* path = BNProjectGetPath(m_object); + std::string result = path; + BNFreeString(path); + return result; +} + + +std::string Project::GetName() const +{ + char* name = BNProjectGetName(m_object); + std::string result = name; + BNFreeString(name); + return result; +} + + +void Project::SetName(const std::string& name) +{ + BNProjectSetName(m_object, name.c_str()); +} + + +std::string Project::GetDescription() const +{ + char* description = BNProjectGetDescription(m_object); + std::string result = description; + BNFreeString(description); + return result; +} + + +void Project::SetDescription(const std::string& description) +{ + BNProjectSetDescription(m_object, description.c_str()); +} + + +Ref<Metadata> Project::QueryMetadata(const std::string& key) +{ + BNMetadata* value = BNProjectQueryMetadata(m_object, key.c_str()); + if (value == nullptr) + return nullptr; + return new Metadata(value); +} + + +bool Project::StoreMetadata(const std::string& key, Ref<Metadata> value) +{ + return BNProjectStoreMetadata(m_object, key.c_str(), value->m_object); +} + + +void Project::RemoveMetadata(const std::string& key) +{ + BNProjectRemoveMetadata(m_object, key.c_str()); +} + + +Ref<ProjectFolder> Project::CreateFolderFromPath(const std::string& path, Ref<ProjectFolder> parent, const std::string& description, + const std::function<bool(size_t progress, size_t total)>& progressCallback) +{ + ProgressContext cb; + cb.callback = progressCallback; + BNProjectFolder* folder = BNProjectCreateFolderFromPath(m_object, path.c_str(), parent ? parent->m_object : nullptr, description.c_str(), &cb, ProgressCallback); + if (folder == nullptr) + return nullptr; + return new ProjectFolder(folder); +} + + +Ref<ProjectFolder> Project::CreateFolder(Ref<ProjectFolder> parent, const std::string& name, const std::string& description) +{ + BNProjectFolder* folder = BNProjectCreateFolder(m_object, parent ? parent->m_object : nullptr, name.c_str(), description.c_str()); + if (folder == nullptr) + return nullptr; + return new ProjectFolder(folder); +} + + +Ref<ProjectFolder> Project::CreateFolderUnsafe(Ref<ProjectFolder> parent, const std::string& name, const std::string& description, const std::string& id) +{ + BNProjectFolder* folder = BNProjectCreateFolderUnsafe(m_object, parent ? parent->m_object : nullptr, name.c_str(), description.c_str(), id.c_str()); + if (folder == nullptr) + return nullptr; + return new ProjectFolder(folder); +} + + +std::vector<Ref<ProjectFolder>> Project::GetFolders() const +{ + size_t count; + + BNProjectFolder** folders = BNProjectGetFolders(m_object, &count); + std::vector<Ref<ProjectFolder>> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + result.push_back(new ProjectFolder(BNNewProjectFolderReference(folders[i]))); + } + + BNFreeProjectFolderList(folders, count); + return result; +} + + +Ref<ProjectFolder> Project::GetFolderById(const std::string& id) const +{ + BNProjectFolder* folder = BNProjectGetFolderById(m_object, id.c_str()); + if (folder == nullptr) + return nullptr; + return new ProjectFolder(folder); +} + + +void Project::PushFolder(Ref<ProjectFolder> folder) +{ + BNProjectPushFolder(m_object, folder->m_object); +} + + +void Project::DeleteFolder(Ref<ProjectFolder> folder, const std::function<bool(size_t progress, size_t total)>& progressCallback) +{ + ProgressContext cb; + cb.callback = progressCallback; + BNProjectDeleteFolder(m_object, folder->m_object, &cb, ProgressCallback); +} + + +Ref<ProjectFile> Project::CreateFileFromPath(const std::string& path, Ref<ProjectFolder> folder, const std::string& name, const std::string& description, const std::function<bool(size_t progress, size_t total)>& progressCallback) +{ + ProgressContext cb; + cb.callback = progressCallback; + BNProjectFile* file = BNProjectCreateFileFromPath(m_object, path.c_str(), folder ? folder->m_object : nullptr, name.c_str(), description.c_str(), &cb, ProgressCallback); + if (file == nullptr) + return nullptr; + return new ProjectFile(file); +} + + +Ref<ProjectFile> Project::CreateFileFromPathUnsafe(const std::string& path, Ref<ProjectFolder> folder, const std::string& name, const std::string& description,const std::string& id, const std::function<bool(size_t progress, size_t total)>& progressCallback) +{ + ProgressContext cb; + cb.callback = progressCallback; + BNProjectFile* file = BNProjectCreateFileFromPathUnsafe(m_object, path.c_str(), folder ? folder->m_object : nullptr, name.c_str(), description.c_str(), id.c_str(), &cb, ProgressCallback); + if (file == nullptr) + return nullptr; + return new ProjectFile(file); +} + + +Ref<ProjectFile> Project::CreateFile(const std::vector<uint8_t>& contents, Ref<ProjectFolder> folder, const std::string& name, const std::string& description, const std::function<bool(size_t progress, size_t total)>& progressCallback) +{ + ProgressContext cb; + cb.callback = progressCallback; + BNProjectFile* file = BNProjectCreateFile(m_object, contents.data(), contents.size(), folder ? folder->m_object : nullptr, name.c_str(), description.c_str(), &cb, ProgressCallback); + if (file == nullptr) + return nullptr; + return new ProjectFile(file); +} + + +Ref<ProjectFile> Project::CreateFileUnsafe(const std::vector<uint8_t>& contents, Ref<ProjectFolder> folder, const std::string& name, const std::string& description,const std::string& id, const std::function<bool(size_t progress, size_t total)>& progressCallback) +{ + ProgressContext cb; + cb.callback = progressCallback; + BNProjectFile* file = BNProjectCreateFileUnsafe(m_object, contents.data(), contents.size(), folder ? folder->m_object : nullptr, name.c_str(), description.c_str(), id.c_str(), &cb, ProgressCallback); + if (file == nullptr) + return nullptr; + return new ProjectFile(file); +} + + +std::vector<Ref<ProjectFile>> Project::GetFiles() const +{ + size_t count; + BNProjectFile** files = BNProjectGetFiles(m_object, &count); + + std::vector<Ref<ProjectFile>> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + result.push_back(new ProjectFile(BNNewProjectFileReference(files[i]))); + } + + BNFreeProjectFileList(files, count); + return result; +} + + +Ref<ProjectFile> Project::GetFileById(const std::string& id) const +{ + BNProjectFile* file = BNProjectGetFileById(m_object, id.c_str()); + if (file == nullptr) + return nullptr; + return new ProjectFile(file); +} + + +Ref<ProjectFile> Project::GetFileByPathOnDisk(const std::string& path) +{ + BNProjectFile* file = BNProjectGetFileByPathOnDisk(m_object, path.c_str()); + if (file == nullptr) + return nullptr; + return new ProjectFile(file); +} + + +void Project::PushFile(Ref<ProjectFile> file) +{ + BNProjectPushFile(m_object, file->m_object); +} + + +void Project::DeleteFile_(Ref<ProjectFile> file) +{ + BNProjectDeleteFile(m_object, file->m_object); +} + + +void Project::RegisterNotification(ProjectNotification* notify) +{ + BNRegisterProjectNotification(m_object, notify->GetCallbacks()); +} + + +void Project::UnregisterNotification(ProjectNotification* notify) +{ + BNUnregisterProjectNotification(m_object, notify->GetCallbacks()); +} + + +void Project::BeginBulkOperation() +{ + BNProjectBeginBulkOperation(m_object); +} + + +void Project::EndBulkOperation() +{ + BNProjectEndBulkOperation(m_object); +} + + +ProjectFile::ProjectFile(BNProjectFile* file) +{ + m_object = file; +} + + +Ref<Project> ProjectFile::GetProject() const +{ + return new Project(BNProjectFileGetProject(m_object)); +} + + +std::string ProjectFile::GetPathOnDisk() const +{ + char* path = BNProjectFileGetPathOnDisk(m_object); + std::string result = path; + BNFreeString(path); + return result; +} + + +bool ProjectFile::ExistsOnDisk() const +{ + return BNProjectFileExistsOnDisk(m_object); +} + + +std::string ProjectFile::GetName() const +{ + char* name = BNProjectFileGetName(m_object); + std::string result = name; + BNFreeString(name); + return result; +} + + +std::string ProjectFile::GetDescription() const +{ + char* description = BNProjectFileGetDescription(m_object); + std::string result = description; + BNFreeString(description); + return result; +} + + +void ProjectFile::SetName(const std::string& name) +{ + BNProjectFileSetName(m_object, name.c_str()); +} + + +void ProjectFile::SetDescription(const std::string& description) +{ + BNProjectFileSetDescription(m_object, description.c_str()); +} + + +std::string ProjectFile::GetId() const +{ + char* id = BNProjectFileGetId(m_object); + std::string result = id; + BNFreeString(id); + return result; +} + + +Ref<ProjectFolder> ProjectFile::GetFolder() const +{ + BNProjectFolder* folder = BNProjectFileGetFolder(m_object); + if (!folder) + return nullptr; + return new ProjectFolder(folder); +} + + +void ProjectFile::SetFolder(Ref<ProjectFolder> folder) +{ + BNProjectFileSetFolder(m_object, folder ? folder->m_object : nullptr); +} + + +bool ProjectFile::Export(const std::string& destination) const +{ + return BNProjectFileExport(m_object, destination.c_str()); +} + + +ProjectFolder::ProjectFolder(BNProjectFolder* folder) +{ + m_object = folder; +} + + +Ref<Project> ProjectFolder::GetProject() const +{ + return new Project(BNProjectFolderGetProject(m_object)); +} + + +std::string ProjectFolder::GetId() const +{ + char* id = BNProjectFolderGetId(m_object); + std::string result = id; + BNFreeString(id); + return result; +} + + +std::string ProjectFolder::GetName() const +{ + char* name = BNProjectFolderGetName(m_object); + std::string result = name; + BNFreeString(name); + return result; +} + + +std::string ProjectFolder::GetDescription() const +{ + char* desc = BNProjectFolderGetDescription(m_object); + std::string result = desc; + BNFreeString(desc); + return result; +} + + +void ProjectFolder::SetName(const std::string& name) +{ + BNProjectFolderSetName(m_object, name.c_str()); +} + + +void ProjectFolder::SetDescription(const std::string& description) +{ + BNProjectFolderSetDescription(m_object, description.c_str()); +} + + +Ref<ProjectFolder> ProjectFolder::GetParent() const +{ + BNProjectFolder* parent = BNProjectFolderGetParent(m_object); + if (!parent) + return nullptr; + return new ProjectFolder(parent); +} + + +void ProjectFolder::SetParent(Ref<ProjectFolder> parent) +{ + BNProjectFolderSetParent(m_object, parent ? parent->m_object : nullptr); +} + + +bool ProjectFolder::Export(const std::string& destination, const std::function<bool(size_t progress, size_t total)>& progressCallback) const +{ + ProgressContext cb; + cb.callback = progressCallback; + return BNProjectFolderExport(m_object, destination.c_str(), &cb, ProgressCallback); +} diff --git a/python/__init__.py b/python/__init__.py index f06b0681..2b12d827 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -71,6 +71,7 @@ from .typeprinter import * from .component import * from .typecontainer import * from .exceptions import * +from .project import * # We import each of these by name to prevent conflicts between # log.py and the function 'log' which we don't import below from .log import ( diff --git a/python/binaryview.py b/python/binaryview.py index 0c475445..5b78fca9 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -68,6 +68,7 @@ from . import mediumlevelil from . import highlevelil from . import debuginfo from . import flowgraph +from . import project # The following are imported as such to allow the type checker disambiguate the module name # from properties and methods of the same name from . import workflow as _workflow @@ -76,6 +77,9 @@ from . import types as _types from . import platform as _platform from . import deprecation from . import typecontainer +from . import externallibrary +from . import project + PathType = Union[str, os.PathLike] InstructionsType = Generator[Tuple[List['_function.InstructionTextToken'], int], None, None] @@ -2322,7 +2326,7 @@ class BinaryView: return BinaryView(file_metadata=file_metadata, handle=view) @staticmethod - def load(source: Union[str, bytes, bytearray, 'databuffer.DataBuffer', 'os.PathLike', 'BinaryView'], update_analysis: Optional[bool] = True, + def load(source: Union[str, bytes, bytearray, 'databuffer.DataBuffer', 'os.PathLike', 'BinaryView', 'project.ProjectFile'], update_analysis: Optional[bool] = True, progress_func: Optional[ProgressFuncType] = None, options: Mapping[str, Any] = {}) -> Optional['BinaryView']: """ ``load`` opens, generates default load options (which are overridable), and returns the first available \ @@ -2371,6 +2375,8 @@ class BinaryView: source = str(source) if isinstance(source, BinaryView): handle = core.BNLoadBinaryView(source.handle, update_analysis, progress_cfunc, metadata.Metadata(options).handle, source.file.has_database) + elif isinstance(source, project.ProjectFile): + handle = core.BNLoadProjectFile(source._handle, update_analysis, progress_cfunc, metadata.Metadata(options).handle) elif isinstance(source, str): handle = core.BNLoadFilename(source, update_analysis, progress_cfunc, metadata.Metadata(options).handle) elif isinstance(source, bytes) or isinstance(source, bytearray) or isinstance(source, databuffer.DataBuffer): @@ -2951,6 +2957,14 @@ class BinaryView: def new_auto_function_analysis_suppressed(self, suppress: bool) -> None: core.BNSetNewAutoFunctionAnalysisSuppressed(self.handle, suppress) + @property + def project(self) -> Optional['project.Project']: + return self.file.project + + @property + def project_file(self) -> Optional['project.ProjectFile']: + return self.file.project_file + def _init(self, ctxt): try: return self.init() @@ -8647,6 +8661,69 @@ class BinaryView: def create_logger(self, logger_name:str) -> Logger: return Logger(self.file.session_id, logger_name) + def add_external_library(self, name: str, backing_file: Optional['project.ProjectFile'] = None, auto: bool = False) -> externallibrary.ExternalLibrary: + file_handle = None + if backing_file is not None: + file_handle = backing_file._handle + handle = core.BNBinaryViewAddExternalLibrary(self.handle, name, file_handle, auto) + assert handle is not None, "core.BNBinaryViewAddExternalLibrary returned None" + return externallibrary.ExternalLibrary(handle) + + def remove_external_library(self, name: str): + core.BNBinaryViewRemoveExternalLibrary(self.handle, name) + + def get_external_library(self, name: str) -> Optional[externallibrary.ExternalLibrary]: + handle = core.BNBinaryViewGetExternalLibrary(self.handle, name) + if handle is None: + return None + return externallibrary.ExternalLibrary(handle) + + def get_external_libraries(self) -> List[externallibrary.ExternalLibrary]: + count = ctypes.c_ulonglong(0) + handles = core.BNBinaryViewGetExternalLibraries(self.handle, count) + assert handles is not None, "core.BNBinaryViewGetExternalLibraries returned None" + result = [] + try: + for i in range(count.value): + new_handle = core.BNNewExternalLibraryReference(handles[i]) + assert new_handle is not None, "core.BNNewExternalLibraryReference returned None" + result.append(externallibrary.ExternalLibrary(new_handle)) + return result + finally: + core.BNFreeExternalLibraryList(handles, count.value) + + def add_external_location(self, symbol: '_types.CoreSymbol', library: Optional[externallibrary.ExternalLibrary], external_symbol: Optional[str], external_address: Optional[int], auto: bool = False) -> externallibrary.ExternalLocation: + c_addr = None + if external_address is not None: + c_addr = ctypes.c_ulonglong(external_address) + + handle = core.BNBinaryViewAddExternalLocation(self.handle, symbol.handle, library._handle if library else None, external_symbol, c_addr, auto) + assert handle is not None, "core.BNBinaryViewAddExternalLocation returned None" + return externallibrary.ExternalLocation(handle) + + def remove_external_location(self, symbol: '_types.CoreSymbol'): + core.BNBinaryViewRemoveExternalLocation(self.handle, symbol._handle) + + def get_external_location(self, symbol: '_types.CoreSymbol') -> Optional[externallibrary.ExternalLocation]: + handle = core.BNBinaryViewGetExternalLocation(self.handle, symbol.handle) + if handle is None: + return None + return externallibrary.ExternalLocation(handle) + + def get_external_locations(self) -> List[externallibrary.ExternalLocation]: + count = ctypes.c_ulonglong(0) + handles = core.BNBinaryViewGetExternalLocations(self.handle, count) + assert handles is not None, "core.BNBinaryViewGetExternalLocations returned None" + result = [] + try: + for i in range(count.value): + new_handle = core.BNNewExternalLocationReference(handles[i]) + assert new_handle is not None, "core.BNNewExternalLocationReference returned None" + result.append(externallibrary.ExternalLocation(handles[i])) + return result + finally: + core.BNFreeExternalLocationList(handles, count.value) + class BinaryReader: """ diff --git a/python/exceptions.py b/python/exceptions.py index cb285253..a2ba197a 100644 --- a/python/exceptions.py +++ b/python/exceptions.py @@ -5,3 +5,7 @@ class RelocationWriteException(Exception): class ILException(Exception): """ Exception raised when IL operations fail """ pass + +class ProjectException(Exception): + """ Exception raised when project operations fail """ + pass diff --git a/python/externallibrary.py b/python/externallibrary.py new file mode 100644 index 00000000..6ae7b806 --- /dev/null +++ b/python/externallibrary.py @@ -0,0 +1,125 @@ +# coding=utf-8 +# Copyright (c) 2015-2023 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. + +import ctypes + +from typing import Optional + +from . import _binaryninjacore as core +from . import project +from . import types + + +class ExternalLibrary: + def __init__(self, handle: core.BNExternalLibrary): + self._handle = handle + + def __del__(self): + if core is not None: + core.BNFreeExternalLibrary(self._handle) + + def __repr__(self) -> str: + return f'<ExternalLibrary: {self.name}>' + + def __str__(self) -> str: + return f'<ExternalLibrary: {self.name}>' + + @property + def name(self) -> str: + return core.BNExternalLibraryGetName(self._handle) # type: ignore + + @property + def backing_file(self) -> Optional[project.ProjectFile]: + handle = core.BNExternalLibraryGetBackingFile(self._handle) + if handle is None: + return None + return project.ProjectFile(handle) + + @backing_file.setter + def backing_file(self, new_file: Optional[project.ProjectFile]): + new_file_handle = None + if new_file is not None: + new_file_handle = new_file._handle + core.BNExternalLibrarySetBackingFile(self._handle, new_file_handle) + + +class ExternalLocation: + def __init__(self, handle: core.BNExternalLocation): + self._handle = handle + + def __del__(self): + if core is not None: + core.BNFreeExternalLocation(self._handle) + + def __repr__(self) -> str: + return f'<ExternalLocation: {self.internal_symbol}>' + + def __str__(self) -> str: + return f'<ExternalLocation: {self.internal_symbol}>' + + @property + def internal_symbol(self) -> 'types.CoreSymbol': + sym = core.BNExternalLocationGetInternalSymbol(self._handle) + assert sym is not None, "core.BNExternalLocationGetInternalSymbol returned None" + return types.CoreSymbol(sym) + + @property + def has_address(self) -> bool: + return core.BNExternalLocationHasAddress(self._handle) + + @property + def has_symbol(self) -> bool: + return core.BNExternalLocationHasSymbol(self._handle) + + @property + def address(self) -> Optional[int]: + if not self.has_address: + return None + return core.BNExternalLocationGetAddress(self._handle) + + @address.setter + def address(self, new_address: Optional[int]): + c_addr = None + if new_address is not None: + c_addr = ctypes.c_ulonglong(new_address) + return core.BNExternalLocationSetAddress(self._handle, c_addr) + + @property + def symbol(self) -> Optional[str]: + if not self.has_symbol: + return None + return core.BNExternalLocationGetSymbol(self._handle) + + @symbol.setter + def symbol(self, new_symbol: Optional[str]): + return core.BNExternalLocationSetSymbol(self._handle, new_symbol) + + @property + def library(self) -> Optional[ExternalLibrary]: + handle = core.BNExternalLocationGetExternalLibrary(self._handle) + if handle is None: + return None + return ExternalLibrary(handle) + + @library.setter + def library(self, new_library: Optional[ExternalLibrary]): + lib_handle = new_library._handle if new_library is not None else None + return core.BNExternalLocationSetExternalLibrary(self._handle, lib_handle) diff --git a/python/filemetadata.py b/python/filemetadata.py index ec0e16bb..e51436b1 100644 --- a/python/filemetadata.py +++ b/python/filemetadata.py @@ -31,6 +31,7 @@ from .log import log_error from . import binaryview from . import database from . import deprecation +from . import project ProgressFuncType = Callable[[int, int], bool] ViewName = str @@ -298,6 +299,20 @@ class FileMetadata: def snapshot_data_applied_without_error(self) -> bool: return core.BNIsSnapshotDataAppliedWithoutError(self.handle) + @property + def project(self) -> Optional['project.Project']: + project_file = self.project_file + if project_file is None: + return None + return project_file.project + + @property + def project_file(self) -> Optional['project.ProjectFile']: + handle = core.BNGetProjectFile(self.handle) + if handle is None: + return None + return project.ProjectFile(handle) + def close(self) -> None: """ Closes the underlying file handle. It is recommended that this is done in a @@ -606,14 +621,6 @@ class FileMetadata: return None return binaryview.BinaryView(file_metadata=self, handle=view) - def open_project(self) -> bool: - return core.BNOpenProject(self.handle) - - def close_project(self) -> None: - core.BNCloseProject(self.handle) - - def is_project_open(self) -> bool: - return core.BNIsProjectOpen(self.handle) @property def existing_views(self) -> List[ViewName]: diff --git a/python/project.py b/python/project.py new file mode 100644 index 00000000..e1f7171d --- /dev/null +++ b/python/project.py @@ -0,0 +1,411 @@ +# Copyright (c) 2015-2023 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. + +import ctypes + +from contextlib import contextmanager +from os import PathLike +from typing import Callable, List, Optional, Union + +from . import _binaryninjacore as core +from .exceptions import ProjectException +from .metadata import Metadata, MetadataValueType + + +ProgressFuncType = Callable[[int, int], bool] +AsPath = Union[PathLike, str] + +#TODO: notifications + +def nop(*args, **kwargs): + """ + Function that just returns True, used as default for callbacks + + :return: True + """ + return True + + +def wrap_progress(progress_func: ProgressFuncType): + """ + Wraps a progress function in a ctypes function for passing to the FFI + + :param progress_func: Python progress function + :return: Wrapped ctypes function + """ + return ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)( + lambda ctxt, cur, total: progress_func(cur, total)) + + +class ProjectFile: + def __init__(self, handle: core.BNProjectFileHandle): + self._handle = handle + + def __del__(self): + if core is not None: + core.BNFreeProjectFile(self._handle) + + def __repr__(self) -> str: + path = self.name + parent = self.folder + while parent is not None: + path = parent.name + '/' + path + parent = parent.parent + return f'<ProjectFile: {self.project.name}/{path}>' + + def __str__(self) -> str: + path = self.name + parent = self.folder + while parent is not None: + path = parent.name + '/' + path + parent = parent.parent + return f'<ProjectFile: {self.project.name}/{path}>' + + @property + def project(self): + proj_handle = core.BNProjectFileGetProject(self._handle) + + if proj_handle is None: + raise ProjectException("Failed to get project for file") + + return Project(handle=proj_handle) + + @property + def path_on_disk(self) -> str: + return core.BNProjectFileGetPathOnDisk(self._handle) # type: ignore + + @property + def exists_on_disk(self) -> bool: + return core.BNProjectFileExistsOnDisk(self._handle) + + @property + def id(self) -> str: + return core.BNProjectFileGetId(self._handle) # type: ignore + + @property + def name(self) -> str: + return core.BNProjectFileGetName(self._handle) # type: ignore + + @name.setter + def name(self, new_name: str): + return core.BNProjectFileSetName(self._handle, new_name) + + @property + def description(self) -> str: + return core.BNProjectFileGetDescription(self._handle) # type: ignore + + @description.setter + def description(self, new_description: str): + return core.BNProjectFileSetDescription(self._handle, new_description) + + @property + def folder(self) -> Optional['ProjectFolder']: + folder_handle = core.BNProjectFileGetFolder(self._handle) + if folder_handle is None: + return None + return ProjectFolder(handle=folder_handle) + + @folder.setter + def folder(self, new_folder: Optional['ProjectFolder']): + folder_handle = None if new_folder is None else new_folder._handle + core.BNProjectFileSetFolder(self._handle, folder_handle) + + def export(self, dest: AsPath) -> bool: + return core.BNProjectFileExport(self._handle, str(dest)) + + +class ProjectFolder: + def __init__(self, handle: core.BNProjectFolderHandle): + self._handle = handle + + def __del__(self): + if core is not None: + core.BNFreeProjectFolder(self._handle) + + def __repr__(self) -> str: + path = self.name + parent = self.parent + while parent is not None: + path = parent.name + '/' + path + parent = parent.parent + return f'<ProjectFolder: {self.project.name}/{path}>' + + def __str__(self) -> str: + path = self.name + parent = self.parent + while parent is not None: + path = parent.name + '/' + path + parent = parent.parent + return f'<ProjectFolder: {self.project.name}/{path}>' + + @property + def project(self): + proj_handle = core.BNProjectFolderGetProject(self._handle) + + if proj_handle is None: + raise ProjectException("Failed to get project for folder") + + return Project(handle=proj_handle) + + @property + def id(self) -> str: + return core.BNProjectFolderGetId(self._handle) # type: ignore + + @property + def name(self) -> str: + return core.BNProjectFolderGetName(self._handle) # type: ignore + + @name.setter + def name(self, new_name: str): + return core.BNProjectFolderSetName(self._handle, new_name) + + @property + def description(self) -> str: + return core.BNProjectFolderGetDescription(self._handle) # type: ignore + + @description.setter + def description(self, new_description: str): + return core.BNProjectFolderSetDescription(self._handle, new_description) + + @property + def parent(self) -> Optional['ProjectFolder']: + folder_handle = core.BNProjectFolderGetParent(self._handle) + if folder_handle is None: + return None + return ProjectFolder(handle=folder_handle) + + @parent.setter + def parent(self, new_parent: Optional['ProjectFolder']): + parent_handle = None if new_parent is None else new_parent._handle + core.BNProjectFolderSetParent(self._handle, parent_handle) + + def export(self, dest: AsPath, progress_func: ProgressFuncType = nop) -> bool: + return core.BNProjectFolderExport(self._handle, str(dest), None, wrap_progress(progress_func)) + + +class Project: + def __init__(self, handle: core.BNProjectHandle): + self._handle = handle + + def __del__(self): + if core is not None: + core.BNFreeProject(self._handle) + + def __repr__(self) -> str: + return f'<Project: {self.name}>' + + def __str__(self) -> str: + return f'<Project: {self.name}>' + + @staticmethod + def open_project(path: AsPath) -> 'Project': + project_handle = core.BNOpenProject(str(path)) + if project_handle is None: + raise ProjectException("Failed to open project") + return Project(handle=project_handle) + + @staticmethod + def create_project(path: AsPath, name: str) -> 'Project': + project_handle = core.BNCreateProject(str(path), name) + if project_handle is None: + raise ProjectException("Failed to create project") + return Project(handle=project_handle) + + def open(self) -> bool: + return core.BNProjectOpen(self._handle) + + def close(self) -> bool: + return core.BNProjectClose(self._handle) + + @property + def id(self) -> str: + return core.BNProjectGetId(self._handle) # type: ignore + + @property + def is_open(self) -> bool: + return core.BNProjectIsOpen(self._handle) + + @property + def path(self) -> str: + return core.BNProjectGetPath(self._handle) # type: ignore + + @property + def name(self) -> str: + return core.BNProjectGetName(self._handle) # type: ignore + + @name.setter + def name(self, new_name: str): + core.BNProjectSetName(self._handle, new_name) + + @property + def description(self) -> str: + return core.BNProjectGetDescription(self._handle) # type: ignore + + @description.setter + def description(self, new_description: str): + core.BNProjectSetDescription(self._handle, new_description) + + def query_metadata(self, key: str) -> MetadataValueType: + md_handle = core.BNProjectQueryMetadata(self._handle, key) + if md_handle is None: + raise KeyError(key) + return Metadata(handle=md_handle).value + + def store_metadata(self, key: str, value: MetadataValueType): + _val = value + if not isinstance(_val, Metadata): + _val = Metadata(_val) + core.BNProjectStoreMetadata(self._handle, key, _val.handle) + + def remove_metadata(self, key: str): + core.BNProjectRemoveMetadata(self._handle, key) + + def create_folder_from_path(self, path: Union[PathLike, str], parent: Optional[ProjectFolder] = None, description: str = "", progress_func: ProgressFuncType = nop) -> ProjectFolder: + parent_handle = parent._handle if parent is not None else None + folder_handle = core.BNProjectCreateFolderFromPath( + project=self._handle, + path=str(path), + parent=parent_handle, + description=description, + ctxt=None, + progress=wrap_progress(progress_func) + ) + + if folder_handle is None: + raise ProjectException("Failed to create folder") + + return ProjectFolder(handle=folder_handle) + + def create_folder(self, parent: Optional[ProjectFolder], name: str, description: str = "") -> ProjectFolder: + parent_handle = parent._handle if parent is not None else None + folder_handle = core.BNProjectCreateFolder( + project=self._handle, + parent=parent_handle, + name=name, + description=description, + ) + + if folder_handle is None: + raise ProjectException("Failed to create folder") + + return ProjectFolder(handle=folder_handle) + + @property + def folders(self) -> List[ProjectFolder]: + count = ctypes.c_size_t() + value = core.BNProjectGetFolders(self._handle, count) + if value is None: + raise ProjectException("Failed to get list of project folders") + result = [] + try: + for i in range(count.value): + folder_handle = core.BNNewProjectFolderReference(value[i]) + if folder_handle is None: + raise ProjectException("core.BNNewProjectFolderReference returned None") + result.append(ProjectFolder(folder_handle)) + return result + finally: + core.BNFreeProjectFolderList(value, count.value) + + def get_folder_by_id(self, id: str) -> Optional[ProjectFolder]: + handle = core.BNProjectGetFolderById(self._handle, id) + if handle is None: + return None + folder = ProjectFolder(handle) + return folder + + def push_folder(self, folder: ProjectFolder): + core.BNProjectPushFolder(self._handle, folder._handle) + + def delete_folder(self, folder: ProjectFolder, progress_func: ProgressFuncType = nop): + core.BNProjectDeleteFolder(self._handle, folder._handle, None, wrap_progress(progress_func)) + + def create_file_from_path(self, path: AsPath, folder: Optional[ProjectFile], name: str, description: str = "", progress_func: ProgressFuncType = nop) -> ProjectFile: + folder_handle = folder._handle if folder is not None else None + file_handle = core.BNProjectCreateFileFromPath( + project=self._handle, + path=str(path), + folder=folder_handle, + name=name, + description=description, + ctxt=None, + progress=wrap_progress(progress_func) + ) + + if file_handle is None: + raise ProjectException("Failed to create file") + + return ProjectFile(handle=file_handle) + + def create_file(self, contents: bytes, folder: Optional[ProjectFile], name: str, description: str = "", progress_func: ProgressFuncType = nop) -> ProjectFile: + folder_handle = folder._handle if folder is not None else None + buf = (ctypes.c_ubyte * len(contents))() + ctypes.memmove(buf, contents, len(contents)) + file_handle = core.BNProjectCreateFile( + project=self._handle, + contents=buf, + contentsSize=len(contents), + folder=folder_handle, + name=name, + description=description, + ctxt=None, + progress=wrap_progress(progress_func) + ) + + if file_handle is None: + raise ProjectException("Failed to create file") + + return ProjectFile(handle=file_handle) + + @property + def files(self) -> List[ProjectFile]: + count = ctypes.c_size_t() + value = core.BNProjectGetFiles(self._handle, count) + if value is None: + raise ProjectException("Failed to get list of project files") + result = [] + try: + for i in range(count.value): + file_handle = core.BNNewProjectFileReference(value[i]) + if file_handle is None: + raise ProjectException("core.BNNewProjectFileReference returned None") + result.append(ProjectFile(file_handle)) + return result + finally: + core.BNFreeProjectFileList(value, count.value) + + def get_file_by_id(self, id: str) -> Optional[ProjectFile]: + handle = core.BNProjectGetFileById(self._handle, id) + if handle is None: + return None + file = ProjectFile(handle) + return file + + def push_file(self, file: ProjectFile): + core.BNProjectPushFile(self._handle, file._handle) + + def delete_file(self, file: ProjectFile): + core.BNProjectDeleteFile(self._handle, file._handle) + + @contextmanager + def bulk_operation(self): + core.BNProjectBeginBulkOperation(self._handle) + yield + core.BNProjectEndBulkOperation(self._handle) diff --git a/python/scriptingprovider.py b/python/scriptingprovider.py index 7042b988..d7d5b5dc 100644 --- a/python/scriptingprovider.py +++ b/python/scriptingprovider.py @@ -660,6 +660,7 @@ class PythonScriptingInstance(ScriptingInstance): blacklisted_vars = { "current_thread", "current_view", + "current_project", "bv", "current_function", "current_basic_block", @@ -705,6 +706,7 @@ class PythonScriptingInstance(ScriptingInstance): self.current_selection_begin = 0 self.current_selection_end = 0 self.current_dbg = None + self.current_project = None # Selections that were current as of last issued command self.active_view = None @@ -821,6 +823,7 @@ from binaryninja import * self.active_selection_begin = self.current_selection_begin self.active_selection_end = self.current_selection_end self.active_dbg = self.current_dbg + self.active_project = self.current_project if self.active_view is not None: self.active_file_offset = self.active_view.get_data_offset_for_address(self.active_addr) else: @@ -829,6 +832,7 @@ from binaryninja import * self.locals.blacklist_enabled = False self.locals["current_thread"] = self.interpreter self.locals["current_view"] = self.active_view + self.locals["current_project"] = self.active_project self.locals["bv"] = self.active_view self.locals["current_function"] = self.active_func self.locals["current_basic_block"] = self.active_block @@ -895,10 +899,12 @@ from binaryninja import * action_handler = None view_frame = None view = None + project = None if context is not None: action_handler = context.getCurrentActionHandler() view_frame = context.getCurrentViewFrame() view = context.getCurrentView() + project = context.getProject() view_location = view_frame.getViewLocation() if view_frame is not None else None action_context = None @@ -970,6 +976,7 @@ from binaryninja import * self.active_il_function = None self.locals["current_ui_context"] = context + self.locals["current_project"] = project self.locals["current_ui_view_frame"] = view_frame self.locals["current_ui_view"] = view self.locals["current_ui_action_handler"] = action_handler @@ -983,6 +990,7 @@ from binaryninja import * if not ui_locals_valid: self.locals["current_ui_context"] = None + self.locals["current_project"] = None self.locals["current_ui_view_frame"] = None self.locals["current_ui_view"] = None self.locals["current_ui_action_handler"] = None @@ -1193,10 +1201,14 @@ from binaryninja import * @abc.abstractmethod def perform_set_current_binary_view(self, view): self.interpreter.current_view = view - if view is not None and self.debugger_imported: - self.interpreter.current_dbg = self.DebuggerController(view) + if view is not None: + if self.debugger_imported: + self.interpreter.current_dbg = self.DebuggerController(view) + self.interpreter.current_project = view.project + else: self.interpreter.current_dbg = None + self.interpreter.current_project = None # This is a workaround that allows BN to properly free up resources when the last tab of a binary view is closed. # Without this update, the interpreter local variables will NOT be updated until the user interacts with the diff --git a/python/settings.py b/python/settings.py index 8ddfc945..486d3d2f 100644 --- a/python/settings.py +++ b/python/settings.py @@ -50,7 +50,7 @@ class Settings: ================= ========================== ============== ============================================== Default SettingsDefaultScope Lowest Settings Schema User SettingsUserScope - <User Directory>/settings.json - Project SettingsProjectScope - <Project Directory>/.binaryninja/settings.json + Project SettingsProjectScope - <Project Directory>/settings.json Resource SettingsResourceScope Highest Raw BinaryView (Storage in BNDB) ================= ========================== ============== ============================================== diff --git a/rust/src/filemetadata.rs b/rust/src/filemetadata.rs index 43c6f05d..6f335c24 100644 --- a/rust/src/filemetadata.rs +++ b/rust/src/filemetadata.rs @@ -15,7 +15,6 @@ use binaryninjacore_sys::{ BNBeginUndoActions, BNCloseFile, - BNCloseProject, BNCommitUndoActions, BNCreateDatabase, BNCreateFileMetadata, @@ -29,14 +28,12 @@ use binaryninjacore_sys::{ BNIsBackedByDatabase, //BNSetFileMetadataNavigationHandler, BNIsFileModified, - BNIsProjectOpen, BNMarkFileModified, BNMarkFileSaved, BNNavigate, BNNewFileReference, BNOpenDatabaseForConfiguration, BNOpenExistingDatabase, - BNOpenProject, BNRedo, BNRevertUndoActions, BNSaveAutoSnapshot, @@ -265,20 +262,6 @@ impl FileMetadata { Ok(unsafe { BinaryView::from_raw(view) }) } } - - pub fn open_project(&self) -> bool { - unsafe { BNOpenProject(self.handle) } - } - - pub fn close_project(&self) { - unsafe { - BNCloseProject(self.handle); - } - } - - pub fn is_project_open(&self) -> bool { - unsafe { BNIsProjectOpen(self.handle) } - } } impl ToOwned for FileMetadata { diff --git a/scripts/linux-setup.sh b/scripts/linux-setup.sh index 59f436d9..e8d1a55c 100755 --- a/scripts/linux-setup.sh +++ b/scripts/linux-setup.sh @@ -138,6 +138,7 @@ createmime() <icon name=\"application-x-${APP}\"/> <magic-deleteall/> <glob pattern=\"*.${EXT}\"/> + <glob pattern=\"*.bnpm\"/> <sub-class-of type=\"application/x-sqlite3\" /> </mime-type> </mime-info>"| $SUDO tee ${MIMEFILE} >/dev/null diff --git a/ui/externallocationdialog.h b/ui/externallocationdialog.h new file mode 100644 index 00000000..c86eea70 --- /dev/null +++ b/ui/externallocationdialog.h @@ -0,0 +1,29 @@ +#pragma once + +#include <QtWidgets/QComboBox> +#include <QtWidgets/QDialog> +#include <QtWidgets/QLineEdit> +#include <QtWidgets/QPushButton> +#include "uitypes.h" + + +class BINARYNINJAUIAPI ExternalLocationDialog : public QDialog +{ + QPushButton* m_acceptButton; + QPushButton* m_cancelButton; + + QLineEdit* m_internalSymbolField; + QComboBox* m_libraryField; + QLineEdit* m_externalSymbolField; + QLineEdit* m_addressField; + + BinaryViewRef m_data; + ExternalLocationRef m_location; + + void Submit(); + + void updateForm(); + +public: + ExternalLocationDialog(QWidget* parent, BinaryViewRef data, ExternalLocationRef loc = nullptr, ExternalLibraryRef lib = nullptr, std::optional<std::string> rawSym = {}); +}; diff --git a/ui/linearview.h b/ui/linearview.h index 7f590ce0..936ceb59 100644 --- a/ui/linearview.h +++ b/ui/linearview.h @@ -251,6 +251,7 @@ class BINARYNINJAUIAPI LinearView : public QAbstractScrollArea, public View, pub bool navigateToLine( FunctionRef func, uint64_t offset, size_t instrIndex, bool center, bool updateHighlight, bool navByRef = false); bool navigateToGotoLabel(uint64_t label); + bool navigateToExternalLink(uint64_t linkSourceAddr); void viewData(); void scrollLines(int count); @@ -335,6 +336,10 @@ private Q_SLOTS: void tagAddressAccepted(TagTypeRef tt); void manageAddressTags(); + void createExternalLink(); + void editExternalLink(); + void removeExternalLink(); + void convertToNop(); void alwaysBranch(); void invertBranch(); diff --git a/ui/options.h b/ui/options.h index 0bfba08c..4c7153c7 100644 --- a/ui/options.h +++ b/ui/options.h @@ -43,6 +43,7 @@ class BINARYNINJAUIAPI OptionsDialog : public QDialog FileContext* m_file = nullptr; FileMetadataRef m_fileMetadata = nullptr; BinaryViewRef m_rawData = nullptr; + ProjectRef m_project = nullptr; std::vector<std::tuple<std::string, size_t, std::string, uint64_t, uint64_t, std::string>> m_objects; const std::string m_oldFlag = "old:"; diff --git a/ui/settingsview.h b/ui/settingsview.h index 8ec548b7..812eed3c 100644 --- a/ui/settingsview.h +++ b/ui/settingsview.h @@ -371,9 +371,9 @@ class BINARYNINJAUIAPI SettingsScopeBar : public QWidget Q_OBJECT QPushButton* m_userLabel; - BinaryViewScopeLabel* m_projectLabel; + QPushButton* m_projectLabel; BinaryViewScopeLabel* m_resourceLabel; - ClickableLabel* m_openProjectLabel; + //ClickableLabel* m_openProjectLabel; QLabel* m_desc; unsigned long m_highlightIdx; @@ -384,6 +384,7 @@ class BINARYNINJAUIAPI SettingsScopeBar : public QWidget void refresh(); void setResource(BinaryViewRef view); + void setScope(BNSettingsScope scope); void updateTheme(); Q_SIGNALS: @@ -453,6 +454,7 @@ class BINARYNINJAUIAPI SettingsView : public QWidget void refreshAllSettings(); void refreshCurrentScope(); void setData(BinaryViewRef view, const QString& name = ""); + void setScope(BNSettingsScope scope); void setDefaultGroupSelection(const QString& group, const QString& subgroup = ""); void focusSearch(); void setSearchFilter(const QString& filter) { if (m_search) m_search->setText(filter); }; diff --git a/ui/uicontext.h b/ui/uicontext.h index 99abb84e..df4ff0a2 100644 --- a/ui/uicontext.h +++ b/ui/uicontext.h @@ -7,6 +7,7 @@ #include "binaryninjaapi.h" #include "action.h" #include "preview.h" +#include "uitypes.h" #define PREVIEW_HOVER_TIME 500 @@ -79,6 +80,41 @@ class BINARYNINJAUIAPI UIContextNotification return true; } /*! + Callback after a project is opened + \param context Context which opened the project + \param project Project that was opened + \param frame ViewFrame constructed to display the project + */ + virtual void OnAfterOpenProject(UIContext* context, ProjectRef project) + { + (void)context; + (void)project; + } + /*! + Callback before a project file is opened + \param context Context opening the project file + \param projectFile Project file that is being opened + \return True if the project file should be opened + */ + virtual bool OnBeforeOpenProjectFile(UIContext* context, ProjectFileRef projectFile) + { + (void)context; + (void)projectFile; + return true; + } + /*! + Callback after a project file is opened + \param context Context which opened the project file + \param projectFile Project file that was opened + \param frame ViewFrame constructed to display the project file + */ + virtual void OnAfterOpenProjectFile(UIContext* context, ProjectFileRef projectFile, ViewFrame* frame) + { + (void)context; + (void)projectFile; + (void)frame; + } + /*! Callback before a file (raw or database) is opened (after OnAfterOpenDatabase if opening a database) \param context Context opening the file \param file Context with the file and ui views @@ -264,6 +300,9 @@ class BINARYNINJAUIAPI UIContext bool NotifyOnBeforeOpenDatabase(FileMetadataRef metadata); bool NotifyOnAfterOpenDatabase(FileMetadataRef metadata, BinaryViewRef data); + void NotifyOnAfterOpenProject(ProjectRef project); + bool NotifyOnBeforeOpenProjectFile(ProjectFileRef projectFile); + void NotifyOnAfterOpenProjectFile(ProjectFileRef projectFile, ViewFrame* frame); bool NotifyOnBeforeOpenFile(FileContext* file); void NotifyOnAfterOpenFile(FileContext* file, ViewFrame* frame); bool NotifyOnBeforeSaveFile(FileContext* file, ViewFrame* frame); @@ -326,8 +365,9 @@ public: Open a tab containing the given widget with the given name \param name Name for tab \param widget Widget to display in the tab (optionally a ViewFrame) + \return Index of created tab */ - virtual void createTabForWidget(const QString& name, QWidget* widget) = 0; + virtual int createTabForWidget(const QString& name, QWidget* widget) = 0; /*! * Open a new window with the same file context and Navigate to a given location @@ -409,8 +449,12 @@ public: */ virtual std::vector<ViewFrame*> getAllViewFramesForTab(QWidget* tab) const = 0; + virtual ProjectRef getProject(); + virtual bool openFilename(const QString& path, bool openOptions = false); + virtual ProjectRef openProject(const QString& path); virtual ViewFrame* openFileContext(FileContext* file, const QString& forcedView = "", bool addTab = true); + virtual bool openProjectFile(ProjectFileRef file, ExternalLocationRef loc = nullptr, bool openWithOptions = false); virtual void recreateViewFrames(FileContext* file) = 0; UIActionHandler* globalActions() { return &m_globalActions; } diff --git a/ui/uitypes.h b/ui/uitypes.h index 083c4ac5..49ef0480 100644 --- a/ui/uitypes.h +++ b/ui/uitypes.h @@ -75,6 +75,8 @@ typedef BinaryNinja::Ref<BinaryNinja::DisassemblySettings> DisassemblySettingsRe typedef BinaryNinja::Ref<BinaryNinja::DownloadInstance> DownloadInstanceRef; typedef BinaryNinja::Ref<BinaryNinja::DownloadProvider> DownloadProviderRef; typedef BinaryNinja::Ref<BinaryNinja::Enumeration> EnumerationRef; +typedef BinaryNinja::Ref<BinaryNinja::ExternalLibrary> ExternalLibraryRef; +typedef BinaryNinja::Ref<BinaryNinja::ExternalLocation> ExternalLocationRef; typedef BinaryNinja::Ref<BinaryNinja::FileMetadata> FileMetadataRef; typedef BinaryNinja::Ref<BinaryNinja::FlowGraph> FlowGraphRef; typedef BinaryNinja::Ref<BinaryNinja::FlowGraphLayoutRequest> FlowGraphLayoutRequestRef; @@ -86,6 +88,9 @@ typedef BinaryNinja::Ref<BinaryNinja::MainThreadAction> MainThreadActionRef; typedef BinaryNinja::Ref<BinaryNinja::MediumLevelILFunction> MediumLevelILFunctionRef; typedef BinaryNinja::Ref<BinaryNinja::HighLevelILFunction> HighLevelILFunctionRef; typedef BinaryNinja::Ref<BinaryNinja::Platform> PlatformRef; +typedef BinaryNinja::Ref<BinaryNinja::Project> ProjectRef; +typedef BinaryNinja::Ref<BinaryNinja::ProjectFile> ProjectFileRef; +typedef BinaryNinja::Ref<BinaryNinja::ProjectFolder> ProjectFolderRef; typedef BinaryNinja::Ref<BinaryNinja::ReportCollection> ReportCollectionRef; typedef BinaryNinja::Ref<BinaryNinja::SaveSettings> SaveSettingsRef; typedef BinaryNinja::Ref<BinaryNinja::ScriptingInstance> ScriptingInstanceRef; @@ -29,7 +29,7 @@ bool BINARYNINJAUIAPI showDisassemblyPreview(QWidget* parent, ViewFrame* frame, const ViewLocation& location); void BINARYNINJAUIAPI showTextTooltip(QWidget* parent, const QPoint& previewPos, const QString& text); -bool BINARYNINJAUIAPI isBinaryNinjaDataBase(QFileInfo& info, QFileAccessor& accessor); +bool BINARYNINJAUIAPI isBinaryNinjaDatabase(QFileInfo& info, QFileAccessor& accessor); PlatformRef BINARYNINJAUIAPI getOrAskForPlatform(QWidget* parent, BinaryViewRef data); PlatformRef BINARYNINJAUIAPI getOrAskForPlatform(QWidget* parent, PlatformRef defaultValue); |
