From c3693b77c1fa9c1b5c45483045eeab929cf7bd16 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Tue, 23 Aug 2016 22:52:32 -0400 Subject: Fix some memory leaks --- binaryninjaapi.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index d3234dcc..f79e9d75 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -857,13 +857,13 @@ namespace BinaryNinja std::vector> GetSymbolsOfType(BNSymbolType type); std::vector> GetSymbolsOfType(BNSymbolType type, uint64_t start, uint64_t len); - void DefineAutoSymbol(Symbol* sym); - void UndefineAutoSymbol(Symbol* sym); + void DefineAutoSymbol(Ref sym); + void UndefineAutoSymbol(Ref sym); - void DefineUserSymbol(Symbol* sym); - void UndefineUserSymbol(Symbol* sym); + void DefineUserSymbol(Ref sym); + void UndefineUserSymbol(Ref sym); - void DefineImportedFunction(Symbol* importAddressSym, Function* func); + void DefineImportedFunction(Ref importAddressSym, Ref func); bool IsNeverBranchPatchAvailable(Architecture* arch, uint64_t addr); bool IsAlwaysBranchPatchAvailable(Architecture* arch, uint64_t addr); @@ -904,8 +904,8 @@ namespace BinaryNinja std::map> GetTypes(); Ref GetTypeByName(const std::string& name); bool IsTypeAutoDefined(const std::string& name); - void DefineType(const std::string& name, Type* type); - void DefineUserType(const std::string& name, Type* type); + void DefineType(const std::string& name, Ref type); + void DefineUserType(const std::string& name, Ref type); void UndefineType(const std::string& name); void UndefineUserType(const std::string& name); @@ -1643,8 +1643,8 @@ namespace BinaryNinja Ref CreateFunctionGraph(); std::map GetStackLayout(); - void CreateAutoStackVariable(int64_t offset, Type* type, const std::string& name); - void CreateUserStackVariable(int64_t offset, Type* type, const std::string& name); + void CreateAutoStackVariable(int64_t offset, Ref type, const std::string& name); + void CreateUserStackVariable(int64_t offset, Ref type, const std::string& name); void DeleteAutoStackVariable(int64_t offset); void DeleteUserStackVariable(int64_t offset); bool GetStackVariableAtFrameOffset(int64_t offset, StackVariable& var); -- cgit v1.3.1 From e878199be4a74c880acd5d38c33965b47d7630d0 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Thu, 25 Aug 2016 20:42:33 -0400 Subject: Adding APIs for database save/load progress and constant references --- binaryninjaapi.h | 10 ++++++++++ binaryninjacore.h | 15 +++++++++++++++ binaryview.cpp | 13 +++++++++++++ filemetadata.cpp | 43 ++++++++++++++++++++++++++++++++++++++++++ function.cpp | 13 +++++++++++++ python/__init__.py | 55 ++++++++++++++++++++++++++++++++++++++++++++---------- 6 files changed, 139 insertions(+), 10 deletions(-) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index f79e9d75..7c951dee 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -511,8 +511,14 @@ namespace BinaryNinja bool IsBackedByDatabase() const; bool CreateDatabase(const std::string& name, BinaryView* data); + bool CreateDatabase(const std::string& name, BinaryView* data, + const std::function& progressCallback); Ref OpenExistingDatabase(const std::string& path); + Ref OpenExistingDatabase(const std::string& path, + const std::function& progressCallback); bool SaveAutoSnapshot(BinaryView* data); + bool SaveAutoSnapshot(BinaryView* data, + const std::function& progressCallback); void BeginUndoActions(); void CommitUndoActions(); @@ -766,7 +772,10 @@ namespace BinaryNinja bool IsAnalysisChanged() const; bool IsBackedByDatabase() const; bool CreateDatabase(const std::string& path); + bool CreateDatabase(const std::string& path, + const std::function& progressCallback); bool SaveAutoSnapshot(); + bool SaveAutoSnapshot(const std::function& progressCallback); void BeginUndoActions(); void AddUndoAction(UndoAction* action); @@ -1626,6 +1635,7 @@ namespace BinaryNinja std::vector GetRegistersReadByInstruction(Architecture* arch, uint64_t addr); std::vector GetRegistersWrittenByInstruction(Architecture* arch, uint64_t addr); std::vector GetStackVariablesReferencedByInstruction(Architecture* arch, uint64_t addr); + std::vector GetConstantsReferencedByInstruction(Architecture* arch, uint64_t addr); Ref GetLiftedIL() const; size_t GetLiftedILForInstruction(Architecture* arch, uint64_t addr); diff --git a/binaryninjacore.h b/binaryninjacore.h index 2ba6f7e6..4d8c31d9 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1013,6 +1013,12 @@ extern "C" void (*addAction)(void* ctxt, BNMainThreadAction* action); }; + struct BNConstantReference + { + int64_t value; + size_t size; + }; + BINARYNINJACOREAPI char* BNAllocString(const char* contents); BINARYNINJACOREAPI void BNFreeString(char* str); @@ -1105,8 +1111,14 @@ extern "C" BINARYNINJACOREAPI bool BNIsBackedByDatabase(BNFileMetadata* file); BINARYNINJACOREAPI bool BNCreateDatabase(BNBinaryView* data, const char* path); + BINARYNINJACOREAPI bool BNCreateDatabaseWithProgress(BNBinaryView* data, const char* path, + void* ctxt, void (*progress)(void* ctxt, size_t progress, size_t total)); BINARYNINJACOREAPI BNBinaryView* BNOpenExistingDatabase(BNFileMetadata* file, const char* path); + BINARYNINJACOREAPI BNBinaryView* BNOpenExistingDatabaseWithProgress(BNFileMetadata* file, const char* path, + void* ctxt, void (*progress)(void* ctxt, size_t progress, size_t total)); BINARYNINJACOREAPI bool BNSaveAutoSnapshot(BNBinaryView* data); + BINARYNINJACOREAPI bool BNSaveAutoSnapshotWithProgress(BNBinaryView* data, void* ctxt, + void (*progress)(void* ctxt, size_t progress, size_t total)); BINARYNINJACOREAPI char* BNGetFilename(BNFileMetadata* file); BINARYNINJACOREAPI void BNSetFilename(BNFileMetadata* file, const char* name); @@ -1433,6 +1445,9 @@ extern "C" BINARYNINJACOREAPI BNStackVariableReference* BNGetStackVariablesReferencedByInstruction(BNFunction* func, BNArchitecture* arch, uint64_t addr, size_t* count); BINARYNINJACOREAPI void BNFreeStackVariableReferenceList(BNStackVariableReference* refs, size_t count); + BINARYNINJACOREAPI BNConstantReference* BNGetConstantsReferencedByInstruction(BNFunction* func, + BNArchitecture* arch, uint64_t addr, size_t* count); + BINARYNINJACOREAPI void BNFreeConstantReferenceList(BNConstantReference* refs); BINARYNINJACOREAPI BNLowLevelILFunction* BNGetFunctionLiftedIL(BNFunction* func); BINARYNINJACOREAPI size_t BNGetLiftedILForInstruction(BNFunction* func, BNArchitecture* arch, uint64_t addr); diff --git a/binaryview.cpp b/binaryview.cpp index cff3ed10..14393930 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -518,12 +518,25 @@ bool BinaryView::CreateDatabase(const string& path) } +bool BinaryView::CreateDatabase(const string& path, + const function& progressCallback) +{ + return m_file->CreateDatabase(path, this, progressCallback); +} + + bool BinaryView::SaveAutoSnapshot() { return m_file->SaveAutoSnapshot(this); } +bool BinaryView::SaveAutoSnapshot(const function& progressCallback) +{ + return m_file->SaveAutoSnapshot(this, progressCallback); +} + + void BinaryView::BeginUndoActions() { m_file->BeginUndoActions(); diff --git a/filemetadata.cpp b/filemetadata.cpp index 51e152bf..b3764167 100644 --- a/filemetadata.cpp +++ b/filemetadata.cpp @@ -25,6 +25,19 @@ using namespace Json; using namespace std; +struct DatabaseProgressCallbackContext +{ + std::function func; +}; + + +static void DatabaseProgressCallback(void* ctxt, size_t progress, size_t total) +{ + DatabaseProgressCallbackContext* cb = (DatabaseProgressCallbackContext*)ctxt; + cb->func(progress, total); +} + + char* NavigationHandler::GetCurrentViewCallback(void* ctxt) { NavigationHandler* handler = (NavigationHandler*)ctxt; @@ -246,6 +259,15 @@ bool FileMetadata::CreateDatabase(const string& name, BinaryView* data) } +bool FileMetadata::CreateDatabase(const string& name, BinaryView* data, + const function& progressCallback) +{ + DatabaseProgressCallbackContext cb; + cb.func = progressCallback; + return BNCreateDatabaseWithProgress(data->GetObject(), name.c_str(), &cb, DatabaseProgressCallback); +} + + Ref FileMetadata::OpenExistingDatabase(const string& path) { BNBinaryView* data = BNOpenExistingDatabase(m_object, path.c_str()); @@ -255,12 +277,33 @@ Ref FileMetadata::OpenExistingDatabase(const string& path) } +Ref FileMetadata::OpenExistingDatabase(const string& path, + const function& progressCallback) +{ + DatabaseProgressCallbackContext cb; + cb.func = progressCallback; + BNBinaryView* data = BNOpenExistingDatabaseWithProgress(m_object, path.c_str(), &cb, DatabaseProgressCallback); + if (!data) + return nullptr; + return new BinaryView(data); +} + + bool FileMetadata::SaveAutoSnapshot(BinaryView* data) { return BNSaveAutoSnapshot(data->GetObject()); } +bool FileMetadata::SaveAutoSnapshot(BinaryView* data, + const function& progressCallback) +{ + DatabaseProgressCallbackContext cb; + cb.func = progressCallback; + return BNSaveAutoSnapshotWithProgress(data->GetObject(), &cb, DatabaseProgressCallback); +} + + void FileMetadata::BeginUndoActions() { BNBeginUndoActions(m_object); diff --git a/function.cpp b/function.cpp index c5033276..27193992 100644 --- a/function.cpp +++ b/function.cpp @@ -288,6 +288,19 @@ vector Function::GetStackVariablesReferencedByInstructio } +vector Function::GetConstantsReferencedByInstruction(Architecture* arch, uint64_t addr) +{ + size_t count; + BNConstantReference* refs = BNGetConstantsReferencedByInstruction(m_object, arch->GetObject(), addr, &count); + + vector result; + result.insert(result.end(), &refs[0], &refs[count]); + + BNFreeConstantReferenceList(refs); + return result; +} + + Ref Function::GetLiftedIL() const { return new LowLevelILFunction(BNGetFunctionLiftedIL(m_object)); diff --git a/python/__init__.py b/python/__init__.py index 027c2a1f..092e07c0 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -372,18 +372,32 @@ class FileMetadata(object): def navigate(self, view, offset): return core.BNNavigate(self.handle, str(view), offset) - def create_database(self, filename): - - return core.BNCreateDatabase(self.raw.handle, str(filename)) + def create_database(self, filename, progress_func = None): + if progress_func is None: + return core.BNCreateDatabase(self.raw.handle, str(filename)) + else: + return core.BNCreateDatabaseWithProgress(self.raw.handle, str(filename), None, + ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)( + lambda ctxt, cur, total: progress_func(cur, total))) - def open_existing_database(self, filename): - view = core.BNOpenExistingDatabase(self.handle, str(filename)) + def open_existing_database(self, filename, progress_func = None): + if progress_func is None: + view = core.BNOpenExistingDatabase(self.handle, str(filename)) + else: + view = core.BNOpenExistingDatabaseWithProgress(self.handle, str(filename), None, + ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)( + lambda ctxt, cur, total: progress_func(cur, total))) if view is None: return None return BinaryView(self, handle = view) - def save_auto_snapshot(self): - return core.BNSaveAutoSnapshot(self.raw.handle) + def save_auto_snapshot(self, progress_func = None): + if progress_func is None: + return core.BNSaveAutoSnapshot(self.raw.handle) + else: + return core.BNSaveAutoSnapshotWithProgress(self.raw.handle, None, + ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)( + lambda ctxt, cur, total: progress_func(cur, total))) def get_view_of_type(self, name): view = core.BNGetFileViewOfType(self.handle, str(name)) @@ -1683,26 +1697,28 @@ class BinaryView(object): """ return core.LittleEndian - def create_database(self, filename): + def create_database(self, filename, progress_func = None): """ ``perform_get_database`` writes the current database (.bndb) file out to the specified file. :param str filename: path and filename to write the bndb to, this string `should` have ".bndb" appended to it. + :param callable() progress_func: optional function to be called with the current progress and total count. :return: true on success, false on failure :rtype: bool """ return self.file.create_database(filename) - def save_auto_snapshot(self): + def save_auto_snapshot(self, progress_func = None): """ ``save_auto_snapshot`` saves the current database to the already created file. .. note:: :py:method:`create_database` should have been called prior to executing this method + :param callable() progress_func: optional function to be called with the current progress and total count. :return: True if it successfully saved the snapshot, False otherwise :rtype: bool """ - return self.file.save_auto_snapshot() + return self.file.save_auto_snapshot(progress_func) def get_view_of_type(self, name): """ @@ -4248,6 +4264,16 @@ class StackVariableReference: return "" % (self.source_operand, self.name, self.referenced_offset) return "" % (self.source_operand, self.name) +class ConstantReference: + def __init__(self, val, size): + self.value = val + self.size = size + + def __repr__(self): + if self.size == 0: + return "" % self.value + return "" % (self.value, self.size) + class IndirectBranchInfo: def __init__(self, source_arch, source_addr, dest_arch, dest_addr, auto_defined): self.source_arch = source_arch @@ -4531,6 +4557,15 @@ class Function(object): core.BNFreeStackVariableReferenceList(refs, count.value) return result + def get_constants_referenced_by(self, arch, addr): + count = ctypes.c_ulonglong() + refs = core.BNGetConstantsReferencedByInstruction(self.handle, arch.handle, addr, count) + result = [] + for i in xrange(0, count.value): + result.append(ConstantReference(refs[i].value, refs[i].size)) + core.BNFreeConstantReferenceList(refs) + return result + def get_lifted_il_at(self, arch, addr): return core.BNGetLiftedILForInstruction(self.handle, arch.handle, addr) -- cgit v1.3.1 From 827662fbb6caa9d0aa3089cafb20a578a68eaee7 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Tue, 30 Aug 2016 19:30:43 -0400 Subject: Add API to determine if a function still has analysis updates to complete --- binaryninjaapi.h | 1 + binaryninjacore.h | 1 + function.cpp | 6 ++++++ python/__init__.py | 5 +++++ 4 files changed, 13 insertions(+) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 7c951dee..f60ee159 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1611,6 +1611,7 @@ namespace BinaryNinja bool WasAutomaticallyDiscovered() const; bool CanReturn() const; bool HasExplicitlyDefinedType() const; + bool NeedsUpdate() const; std::vector> GetBasicBlocks() const; void MarkRecentUse(); diff --git a/binaryninjacore.h b/binaryninjacore.h index 4d8c31d9..c293f940 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1381,6 +1381,7 @@ extern "C" BINARYNINJACOREAPI void BNRemoveUserFunction(BNBinaryView* view, BNFunction* func); BINARYNINJACOREAPI void BNUpdateAnalysis(BNBinaryView* view); BINARYNINJACOREAPI void BNAbortAnalysis(BNBinaryView* view); + BINARYNINJACOREAPI bool BNIsFunctionUpdateNeeded(BNFunction* func); BINARYNINJACOREAPI BNFunction* BNNewFunctionReference(BNFunction* func); BINARYNINJACOREAPI void BNFreeFunction(BNFunction* func); diff --git a/function.cpp b/function.cpp index 27193992..78a33bda 100644 --- a/function.cpp +++ b/function.cpp @@ -72,6 +72,12 @@ bool Function::HasExplicitlyDefinedType() const } +bool Function::NeedsUpdate() const +{ + return BNIsFunctionUpdateNeeded(m_object); +} + + vector> Function::GetBasicBlocks() const { size_t count; diff --git a/python/__init__.py b/python/__init__.py index 092e07c0..e9f036ae 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -4348,6 +4348,11 @@ class Function(object): """Whether function has explicitly defined types (read-only)""" return core.BNHasExplicitlyDefinedType(self.handle) + @property + def needs_update(self): + """Whether the function has analysis that needs to be updated (read-only)""" + return core.BNIsFunctionUpdateNeeded(self.handle) + @property def basic_blocks(self): """List of basic blocks (read-only)""" -- cgit v1.3.1 From 3978e18b09ca745fd08defb8f00fbece267beaf2 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Tue, 30 Aug 2016 21:59:40 -0400 Subject: Add API to reanalyze --- binaryninjaapi.h | 4 ++++ binaryninjacore.h | 3 +++ binaryview.cpp | 6 ++++++ function.cpp | 6 ++++++ python/__init__.py | 16 ++++++++++++++++ 5 files changed, 35 insertions(+) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index f60ee159..7c417623 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -919,6 +919,8 @@ namespace BinaryNinja void UndefineUserType(const std::string& name); bool FindNextData(uint64_t start, const DataBuffer& data, uint64_t& result, BNFindFlag flags = NoFindFlags); + + void Reanalyze(); }; class BinaryData: public BinaryView @@ -1672,6 +1674,8 @@ namespace BinaryNinja size_t operand); void SetIntegerConstantDisplayType(Architecture* arch, uint64_t instrAddr, uint64_t value, size_t operand, BNIntegerDisplayType type); + + void Reanalyze(); }; struct FunctionGraphEdge diff --git a/binaryninjacore.h b/binaryninjacore.h index c293f940..3aa0a1e6 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1565,6 +1565,9 @@ extern "C" BINARYNINJACOREAPI void BNUndefineAnalysisType(BNBinaryView* view, const char* name); BINARYNINJACOREAPI void BNUndefineUserAnalysisType(BNBinaryView* view, const char* name); + BINARYNINJACOREAPI void BNReanalyzeAllFunctions(BNBinaryView* view); + BINARYNINJACOREAPI void BNReanalyzeFunction(BNFunction* func); + // Disassembly settings BINARYNINJACOREAPI BNDisassemblySettings* BNCreateDisassemblySettings(void); BINARYNINJACOREAPI BNDisassemblySettings* BNNewDisassemblySettingsReference(BNDisassemblySettings* settings); diff --git a/binaryview.cpp b/binaryview.cpp index 14393930..6631f3d6 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1440,6 +1440,12 @@ bool BinaryView::FindNextData(uint64_t start, const DataBuffer& data, uint64_t& } +void BinaryView::Reanalyze() +{ + BNReanalyzeAllFunctions(m_object); +} + + BinaryData::BinaryData(FileMetadata* file): BinaryView(BNCreateBinaryDataView(file->GetObject())) { } diff --git a/function.cpp b/function.cpp index 78a33bda..cbd9ec40 100644 --- a/function.cpp +++ b/function.cpp @@ -572,3 +572,9 @@ void Function::SetIntegerConstantDisplayType(Architecture* arch, uint64_t instrA { BNSetIntegerConstantDisplayType(m_object, arch->GetObject(), instrAddr, value, operand, type); } + + +void Function::Reanalyze() +{ + BNReanalyzeFunction(m_object); +} diff --git a/python/__init__.py b/python/__init__.py index e9f036ae..82aaba32 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -3231,6 +3231,14 @@ class BinaryView(object): return None return result.value + def reanalyze(self): + """ + ``reanalyze`` causes all functions to be reanalyzed. This function does not wait for the analysis to finish. + + :rtype: None + """ + core.BNReanalyzeAllFunctions(self.handle) + def __setattr__(self, name, value): try: object.__setattr__(self,name,value) @@ -4677,6 +4685,14 @@ class Function(object): display_type = core.BNIntegerDisplayType_by_name[display_type] core.BNSetIntegerConstantDisplayType(self.handle, arch.handle, instr_addr, value, operand, display_type) + def reanalyze(self): + """ + ``reanalyze`` causes this functions to be reanalyzed. This function does not wait for the analysis to finish. + + :rtype: None + """ + core.BNReanalyzeFunction(self.handle) + class BasicBlockEdge: def __init__(self, branch_type, target, arch): self.type = core.BNBranchType_names[branch_type] -- cgit v1.3.1 From b84ab8966522eb5063e6a213ca1e48d32e0fd090 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Wed, 31 Aug 2016 00:13:54 -0400 Subject: Add API to enqueue work on the worker thread(s) --- binaryninjaapi.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ binaryninjaapi.h | 5 +++++ binaryninjacore.h | 4 ++++ python/__init__.py | 14 +++++++++--- 4 files changed, 82 insertions(+), 3 deletions(-) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.cpp b/binaryninjaapi.cpp index f98dfef7..71a5a8f7 100644 --- a/binaryninjaapi.cpp +++ b/binaryninjaapi.cpp @@ -24,6 +24,12 @@ using namespace BinaryNinja; using namespace std; +struct WorkerThreadActionContext +{ + std::function action; +}; + + void BinaryNinja::InitCorePlugins() { BNInitCorePlugins(); @@ -138,3 +144,59 @@ void BinaryNinja::AddOptionalPluginDependency(const string& name) { BNAddOptionalPluginDependency(name.c_str()); } + + +static void WorkerActionCallback(void* ctxt) +{ + WorkerThreadActionContext* action = (WorkerThreadActionContext*)ctxt; + action->action(); + delete action; +} + + +void BinaryNinja::WorkerEnqueue(const function& action) +{ + WorkerThreadActionContext* ctxt = new WorkerThreadActionContext; + ctxt->action = action; + BNWorkerEnqueue(ctxt, WorkerActionCallback); +} + + +void BinaryNinja::WorkerEnqueue(RefCountObject* owner, const function& action) +{ + struct + { + Ref owner; + function func; + } context; + context.owner = owner; + context.func = action; + + WorkerEnqueue([=]() { + context.func(); + }); +} + + +void BinaryNinja::WorkerPriorityEnqueue(const function& action) +{ + WorkerThreadActionContext* ctxt = new WorkerThreadActionContext; + ctxt->action = action; + BNWorkerPriorityEnqueue(ctxt, WorkerActionCallback); +} + + +void BinaryNinja::WorkerPriorityEnqueue(RefCountObject* owner, const function& action) +{ + struct + { + Ref owner; + function func; + } context; + context.owner = owner; + context.func = action; + + WorkerPriorityEnqueue([=]() { + context.func(); + }); +} diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 7c417623..6902c1a3 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -371,6 +371,11 @@ namespace BinaryNinja Ref ExecuteOnMainThread(const std::function& action); void ExecuteOnMainThreadAndWait(const std::function& action); + void WorkerEnqueue(const std::function& action); + void WorkerEnqueue(RefCountObject* owner, const std::function& action); + void WorkerPriorityEnqueue(const std::function& action); + void WorkerPriorityEnqueue(RefCountObject* owner, const std::function& action); + class DataBuffer { BNDataBuffer* m_buffer; diff --git a/binaryninjacore.h b/binaryninjacore.h index 3aa0a1e6..a24ce9fa 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1959,6 +1959,10 @@ extern "C" BINARYNINJACOREAPI BNMainThreadAction* BNExecuteOnMainThread(void* ctxt, void (*func)(void* ctxt)); BINARYNINJACOREAPI void BNExecuteOnMainThreadAndWait(void* ctxt, void (*func)(void* ctxt)); + // Worker thread queue management + BINARYNINJACOREAPI void BNWorkerEnqueue(void* ctxt, void (*action)(void* ctxt)); + BINARYNINJACOREAPI void BNWorkerPriorityEnqueue(void* ctxt, void (*action)(void* ctxt)); + #ifdef __cplusplus } #endif diff --git a/python/__init__.py b/python/__init__.py index 82aaba32..fa8ff02c 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -9916,7 +9916,7 @@ def redirect_output_to_log(): global _output_to_log _output_to_log = True -class _MainThreadActionContext: +class _ThreadActionContext: _actions = [] def __init__(self, func): @@ -9939,16 +9939,24 @@ class _MainThreadActionContext: self.__class__._actions.remove(self) def execute_on_main_thread(func): - action = _MainThreadActionContext(func) + action = _ThreadActionContext(func) obj = core.BNExecuteOnMainThread(0, action.callback) if obj: return MainThreadAction(obj) return None def execute_on_main_thread_and_wait(func): - action = _MainThreadActionContext(func) + action = _ThreadActionContext(func) core.BNExecuteOnMainThreadAndWait(0, action.callback) +def worker_enqueue(func): + action = _ThreadActionContext(func) + core.BNWorkerEnqueue(0, action.callback) + +def worker_priority_enqueue(func): + action = _ThreadActionContext(func) + core.BNWorkerEnqueue(0, action.callback) + bundled_plugin_path = core.BNGetBundledPluginDirectory() user_plugin_path = core.BNGetUserPluginDirectory() -- cgit v1.3.1 From c910aa5a42fb789225bb58c990d077d39da9b4ce Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Wed, 31 Aug 2016 17:21:53 -0400 Subject: Cache lines on API side to avoid UI hangs with large basic blocks --- binaryninjaapi.h | 11 ++++++++--- functiongraph.cpp | 30 +++++++++++++++++++++++++++--- functiongraphblock.cpp | 20 ++++++++++++++++---- 3 files changed, 51 insertions(+), 10 deletions(-) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 6902c1a3..fed1bbd9 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1694,6 +1694,10 @@ namespace BinaryNinja class FunctionGraphBlock: public CoreRefCountObject { + std::vector m_cachedLines; + std::vector m_cachedEdges; + bool m_cachedLinesValid, m_cachedEdgesValid; + public: FunctionGraphBlock(BNFunctionGraphBlock* block); @@ -1705,14 +1709,15 @@ namespace BinaryNinja int GetWidth() const; int GetHeight() const; - std::vector GetLines() const; - std::vector GetOutgoingEdges() const; + const std::vector& GetLines(); + const std::vector& GetOutgoingEdges(); }; class FunctionGraph: public RefCountObject { BNFunctionGraph* m_graph; std::function m_completeFunc; + std::map> m_cachedBlocks; static void CompleteCallback(void* ctxt); @@ -1735,7 +1740,7 @@ namespace BinaryNinja void OnComplete(const std::function& func); void Abort(); - std::vector> GetBlocks() const; + std::vector> GetBlocks(); int GetWidth() const; int GetHeight() const; diff --git a/functiongraph.cpp b/functiongraph.cpp index 93f60f63..30e2e165 100644 --- a/functiongraph.cpp +++ b/functiongraph.cpp @@ -104,14 +104,26 @@ void FunctionGraph::Abort() } -vector> FunctionGraph::GetBlocks() const +vector> FunctionGraph::GetBlocks() { size_t count; BNFunctionGraphBlock** blocks = BNGetFunctionGraphBlocks(m_graph, &count); vector> result; for (size_t i = 0; i < count; i++) - result.push_back(new FunctionGraphBlock(BNNewFunctionGraphBlockReference(blocks[i]))); + { + auto block = m_cachedBlocks.find(blocks[i]); + if (block == m_cachedBlocks.end()) + { + FunctionGraphBlock* newBlock = new FunctionGraphBlock(BNNewFunctionGraphBlockReference(blocks[i])); + m_cachedBlocks[blocks[i]] = newBlock; + result.push_back(newBlock); + } + else + { + result.push_back(block->second); + } + } BNFreeFunctionGraphBlockList(blocks, count); return result; @@ -137,7 +149,19 @@ vector> FunctionGraph::GetBlocksInRegion(int left, int t vector> result; for (size_t i = 0; i < count; i++) - result.push_back(new FunctionGraphBlock(BNNewFunctionGraphBlockReference(blocks[i]))); + { + auto block = m_cachedBlocks.find(blocks[i]); + if (block == m_cachedBlocks.end()) + { + FunctionGraphBlock* newBlock = new FunctionGraphBlock(BNNewFunctionGraphBlockReference(blocks[i])); + m_cachedBlocks[blocks[i]] = newBlock; + result.push_back(newBlock); + } + else + { + result.push_back(block->second); + } + } BNFreeFunctionGraphBlockList(blocks, count); return result; diff --git a/functiongraphblock.cpp b/functiongraphblock.cpp index af330497..436339f6 100644 --- a/functiongraphblock.cpp +++ b/functiongraphblock.cpp @@ -27,6 +27,8 @@ using namespace std; FunctionGraphBlock::FunctionGraphBlock(BNFunctionGraphBlock* block) { m_object = block; + m_cachedLinesValid = false; + m_cachedEdgesValid = false; } @@ -72,8 +74,11 @@ int FunctionGraphBlock::GetHeight() const } -vector FunctionGraphBlock::GetLines() const +const vector& FunctionGraphBlock::GetLines() { + if (m_cachedLinesValid) + return m_cachedLines; + size_t count; BNDisassemblyTextLine* lines = BNGetFunctionGraphBlockLines(m_object, &count); @@ -96,12 +101,17 @@ vector FunctionGraphBlock::GetLines() const } BNFreeDisassemblyTextLines(lines, count); - return result; + m_cachedLines = result; + m_cachedLinesValid = true; + return m_cachedLines; } -vector FunctionGraphBlock::GetOutgoingEdges() const +const vector& FunctionGraphBlock::GetOutgoingEdges() { + if (m_cachedEdgesValid) + return m_cachedEdges; + size_t count; BNFunctionGraphEdge* edges = BNGetFunctionGraphBlockOutgoingEdges(m_object, &count); @@ -117,5 +127,7 @@ vector FunctionGraphBlock::GetOutgoingEdges() const } BNFreeFunctionGraphBlockOutgoingEdgeList(edges, count); - return result; + m_cachedEdges = result; + m_cachedEdgesValid = true; + return m_cachedEdges; } -- cgit v1.3.1 From 75f597bb8fcd58315537f1dcd9802bbaadcdbd36 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Wed, 31 Aug 2016 18:06:31 -0400 Subject: Add API to determine if an address is backed by the file --- binaryninjaapi.h | 3 +++ binaryninjacore.h | 2 ++ binaryview.cpp | 20 ++++++++++++++++++++ python/__init__.py | 39 ++++++++++++++++++++++++++++++++++++--- 4 files changed, 61 insertions(+), 3 deletions(-) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index fed1bbd9..342dcc48 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -730,6 +730,7 @@ namespace BinaryNinja virtual bool PerformIsOffsetReadable(uint64_t offset); virtual bool PerformIsOffsetWritable(uint64_t offset); virtual bool PerformIsOffsetExecutable(uint64_t offset); + virtual bool PerformIsOffsetBackedByFile(uint64_t offset); virtual uint64_t PerformGetNextValidOffset(uint64_t offset); virtual uint64_t PerformGetStart() const { return 0; } virtual uint64_t PerformGetLength() const { return 0; } @@ -756,6 +757,7 @@ namespace BinaryNinja static bool IsOffsetReadableCallback(void* ctxt, uint64_t offset); static bool IsOffsetWritableCallback(void* ctxt, uint64_t offset); static bool IsOffsetExecutableCallback(void* ctxt, uint64_t offset); + static bool IsOffsetBackedByFileCallback(void* ctxt, uint64_t offset); static uint64_t GetNextValidOffsetCallback(void* ctxt, uint64_t offset); static uint64_t GetStartCallback(void* ctxt); static uint64_t GetLengthCallback(void* ctxt); @@ -811,6 +813,7 @@ namespace BinaryNinja bool IsOffsetReadable(uint64_t offset) const; bool IsOffsetWritable(uint64_t offset) const; bool IsOffsetExecutable(uint64_t offset) const; + bool IsOffsetBackedByFile(uint64_t offset) const; uint64_t GetNextValidOffset(uint64_t offset) const; uint64_t GetStart() const; diff --git a/binaryninjacore.h b/binaryninjacore.h index a24ce9fa..6eff4d46 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -637,6 +637,7 @@ extern "C" bool (*isOffsetReadable)(void* ctxt, uint64_t offset); bool (*isOffsetWritable)(void* ctxt, uint64_t offset); bool (*isOffsetExecutable)(void* ctxt, uint64_t offset); + bool (*isOffsetBackedByFile)(void* ctxt, uint64_t offset); uint64_t (*getNextValidOffset)(void* ctxt, uint64_t offset); uint64_t (*getStart)(void* ctxt); uint64_t (*getLength)(void* ctxt); @@ -1164,6 +1165,7 @@ extern "C" BINARYNINJACOREAPI bool BNIsOffsetReadable(BNBinaryView* view, uint64_t offset); BINARYNINJACOREAPI bool BNIsOffsetWritable(BNBinaryView* view, uint64_t offset); BINARYNINJACOREAPI bool BNIsOffsetExecutable(BNBinaryView* view, uint64_t offset); + BINARYNINJACOREAPI bool BNIsOffsetBackedByFile(BNBinaryView* view, uint64_t offset); BINARYNINJACOREAPI uint64_t BNGetNextValidOffset(BNBinaryView* view, uint64_t offset); BINARYNINJACOREAPI uint64_t BNGetStartOffset(BNBinaryView* view); BINARYNINJACOREAPI uint64_t BNGetEndOffset(BNBinaryView* view); diff --git a/binaryview.cpp b/binaryview.cpp index 6631f3d6..1c03eca5 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -258,6 +258,7 @@ BinaryView::BinaryView(const std::string& typeName, FileMetadata* file) view.isOffsetReadable = IsOffsetReadableCallback; view.isOffsetWritable = IsOffsetWritableCallback; view.isOffsetExecutable = IsOffsetExecutableCallback; + view.isOffsetBackedByFile = IsOffsetBackedByFileCallback; view.getNextValidOffset = GetNextValidOffsetCallback; view.getStart = GetStartCallback; view.getLength = GetLengthCallback; @@ -357,6 +358,13 @@ bool BinaryView::IsOffsetExecutableCallback(void* ctxt, uint64_t offset) } +bool BinaryView::IsOffsetBackedByFileCallback(void* ctxt, uint64_t offset) +{ + BinaryView* view = (BinaryView*)ctxt; + return view->PerformIsOffsetBackedByFile(offset); +} + + uint64_t BinaryView::GetNextValidOffsetCallback(void* ctxt, uint64_t offset) { BinaryView* view = (BinaryView*)ctxt; @@ -439,6 +447,12 @@ bool BinaryView::PerformIsOffsetExecutable(uint64_t offset) } +bool BinaryView::PerformIsOffsetBackedByFile(uint64_t offset) +{ + return PerformIsValidOffset(offset); +} + + uint64_t BinaryView::PerformGetNextValidOffset(uint64_t offset) { if (offset < PerformGetStart()) @@ -696,6 +710,12 @@ bool BinaryView::IsOffsetExecutable(uint64_t offset) const } +bool BinaryView::IsOffsetBackedByFile(uint64_t offset) const +{ + return BNIsOffsetBackedByFile(m_object, offset); +} + + uint64_t BinaryView::GetNextValidOffset(uint64_t offset) const { return BNGetNextValidOffset(m_object, offset); diff --git a/python/__init__.py b/python/__init__.py index b8a87aff..d199385a 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -945,6 +945,7 @@ class BinaryView(object): self._cb.isOffsetReadable = self._cb.isOffsetReadable.__class__(self._is_offset_readable) self._cb.isOffsetWritable = self._cb.isOffsetWritable.__class__(self._is_offset_writable) self._cb.isOffsetExecutable = self._cb.isOffsetExecutable.__class__(self._is_offset_executable) + self._cb.isOffsetBackedByFile = self._cb.isOffsetExecutable.__class__(self._is_offset_backed_by_file) self._cb.getNextValidOffset = self._cb.getNextValidOffset.__class__(self._get_next_valid_offset) self._cb.getStart = self._cb.getStart.__class__(self._get_start) self._cb.getLength = self._cb.getLength.__class__(self._get_length) @@ -1389,6 +1390,13 @@ class BinaryView(object): log_error(traceback.format_exc()) return False + def _is_offset_backed_by_file(self, ctxt, offset): + try: + return self.perform_is_offset_backed_by_file(offset) + except: + log_error(traceback.format_exc()) + return False + def _get_next_valid_offset(self, ctxt, offset): try: return self.perform_get_next_valid_offset(offset) @@ -1632,6 +1640,20 @@ class BinaryView(object): """ return self.is_valid_offset(addr) + def perform_is_offset_backed_by_file(self, addr): + """ + ``perform_is_offset_backed_by_file`` implements a check if a virtual address ``addr`` is backed by the file + contents. + + .. warning:: This method **must not** be called directly. + + :param int addr: a virtual address to be checked + :return: true if the virtual address is backed by the file, false if the virtual address is initialized by \ + the loader + :rtype: int + """ + return self.is_valid_offset(addr) + def perform_get_next_valid_offset(self, addr): """ ``perform_get_next_valid_offset`` implements a query for the next valid readable, writable, or executable virtual @@ -1933,7 +1955,7 @@ class BinaryView(object): def is_offset_readable(self, addr): """ - ``is_valid_offset`` checks if an virtual address ``addr`` is valid for reading. + ``is_offset_readable`` checks if an virtual address ``addr`` is valid for reading. :param int addr: a virtual address to be checked :return: true if the virtual address is valid for reading, false if the virtual address is invalid or error @@ -1943,7 +1965,7 @@ class BinaryView(object): def is_offset_writable(self, addr): """ - ``is_valid_offset`` checks if an virtual address ``addr`` is valid for writing. + ``is_offset_writable`` checks if an virtual address ``addr`` is valid for writing. :param int addr: a virtual address to be checked :return: true if the virtual address is valid for writing, false if the virtual address is invalid or error @@ -1953,7 +1975,7 @@ class BinaryView(object): def is_offset_executable(self, addr): """ - ``is_valid_offset`` checks if an virtual address ``addr`` is valid for executing. + ``is_offset_executable`` checks if an virtual address ``addr`` is valid for executing. :param int addr: a virtual address to be checked :return: true if the virtual address is valid for executing, false if the virtual address is invalid or error @@ -1961,6 +1983,17 @@ class BinaryView(object): """ return core.BNIsOffsetExecutable(self.handle, addr) + def is_offset_backed_by_file(self, addr): + """ + ``is_offset_backed_by_file`` checks if an virtual address ``addr`` is backed by the file contents. + + :param int addr: a virtual address to be checked + :return: true if the virtual address is backed by the file, false if the virtual address is initialized by \ + the loader + :rtype: bool + """ + return core.BNIsOffsetBackedByFile(self.handle, addr) + def save(self, dest): """ ``save`` saves the original binary file to the provided destination ``dest`` along with any modifications. -- cgit v1.3.1 From 50cafb19ae59ba48fea2e7bd0c79a2e9473c2c86 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Sat, 3 Sep 2016 01:32:35 -0400 Subject: Adding APIs to ensure IL is available for upcoming caching methods --- binaryninjaapi.h | 21 ++++++++++++++++ binaryninjacore.h | 3 +++ function.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ python/__init__.py | 38 ++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 342dcc48..72e13567 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1611,8 +1611,11 @@ namespace BinaryNinja class Function: public CoreRefCountObject { + int m_advancedAnalysisRequests; + public: Function(BNFunction* func); + virtual ~Function(); Ref GetArchitecture() const; Ref GetPlatform() const; @@ -1684,6 +1687,24 @@ namespace BinaryNinja BNIntegerDisplayType type); void Reanalyze(); + + void RequestAdvancedAnalysisData(); + void ReleaseAdvancedAnalysisData(); + void ReleaseAdvancedAnalysisData(size_t count); + }; + + class AdvancedFunctionAnalysisDataRequestor + { + Ref m_func; + + public: + AdvancedFunctionAnalysisDataRequestor(Function* func = nullptr); + AdvancedFunctionAnalysisDataRequestor(const AdvancedFunctionAnalysisDataRequestor& req); + ~AdvancedFunctionAnalysisDataRequestor(); + AdvancedFunctionAnalysisDataRequestor& operator=(const AdvancedFunctionAnalysisDataRequestor& req); + + Ref GetFunction() { return m_func; } + void SetFunction(Function* func); }; struct FunctionGraphEdge diff --git a/binaryninjacore.h b/binaryninjacore.h index 6eff4d46..0c2738cb 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1384,6 +1384,9 @@ extern "C" BINARYNINJACOREAPI void BNUpdateAnalysis(BNBinaryView* view); BINARYNINJACOREAPI void BNAbortAnalysis(BNBinaryView* view); BINARYNINJACOREAPI bool BNIsFunctionUpdateNeeded(BNFunction* func); + BINARYNINJACOREAPI void BNRequestAdvancedFunctionAnalysisData(BNFunction* func); + BINARYNINJACOREAPI void BNReleaseAdvancedFunctionAnalysisData(BNFunction* func); + BINARYNINJACOREAPI void BNReleaseAdvancedFunctionAnalysisDataMultiple(BNFunction* func, size_t count); BINARYNINJACOREAPI BNFunction* BNNewFunctionReference(BNFunction* func); BINARYNINJACOREAPI void BNFreeFunction(BNFunction* func); diff --git a/function.cpp b/function.cpp index cbd9ec40..de12918f 100644 --- a/function.cpp +++ b/function.cpp @@ -27,6 +27,14 @@ using namespace std; Function::Function(BNFunction* func) { m_object = func; + m_advancedAnalysisRequests = 0; +} + + +Function::~Function() +{ + if (m_advancedAnalysisRequests > 0) + BNReleaseAdvancedFunctionAnalysisDataMultiple(m_object, (size_t)m_advancedAnalysisRequests); } @@ -578,3 +586,67 @@ void Function::Reanalyze() { BNReanalyzeFunction(m_object); } + + +void Function::RequestAdvancedAnalysisData() +{ + BNRequestAdvancedFunctionAnalysisData(m_object); +#ifdef WIN32 + InterlockedIncrement((LONG*)&m_advancedAnalysisRequests); +#else + __sync_fetch_and_add(&m_advancedAnalysisRequests, 1); +#endif +} + + +void Function::ReleaseAdvancedAnalysisData() +{ + BNReleaseAdvancedFunctionAnalysisData(m_object); +#ifdef WIN32 + InterlockedDecrement((LONG*)&m_advancedAnalysisRequests); +#else + __sync_fetch_and_add(&m_advancedAnalysisRequests, -1); +#endif +} + + +AdvancedFunctionAnalysisDataRequestor::AdvancedFunctionAnalysisDataRequestor(Function* func): m_func(func) +{ + if (m_func) + m_func->RequestAdvancedAnalysisData(); +} + + +AdvancedFunctionAnalysisDataRequestor::AdvancedFunctionAnalysisDataRequestor(const AdvancedFunctionAnalysisDataRequestor& req) +{ + m_func = req.m_func; + if (m_func) + m_func->RequestAdvancedAnalysisData(); +} + + +AdvancedFunctionAnalysisDataRequestor::~AdvancedFunctionAnalysisDataRequestor() +{ + if (m_func) + m_func->ReleaseAdvancedAnalysisData(); +} + + +AdvancedFunctionAnalysisDataRequestor& AdvancedFunctionAnalysisDataRequestor::operator=( + const AdvancedFunctionAnalysisDataRequestor& req) +{ + SetFunction(req.m_func); + return *this; +} + + +void AdvancedFunctionAnalysisDataRequestor::SetFunction(Function* func) +{ + if (m_func) + m_func->ReleaseAdvancedAnalysisData(); + + m_func = func; + + if (m_func) + m_func->RequestAdvancedAnalysisData(); +} diff --git a/python/__init__.py b/python/__init__.py index d199385a..cd559fe5 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -4330,8 +4330,11 @@ class Function(object): def __init__(self, view, handle): self._view = view self.handle = core.handle_of_type(handle, core.BNFunction) + self._advanced_analysis_requests = 0 def __del__(self): + if self._advanced_analysis_requests > 0: + core.BNReleaseAdvancedFunctionAnalysisDataMultiple(self.handle, self._advanced_analysis_requests) core.BNFreeFunction(self.handle) @property @@ -4726,6 +4729,41 @@ class Function(object): """ core.BNReanalyzeFunction(self.handle) + def request_advanced_analysis_data(self): + core.BNRequestAdvancedFunctionAnalysisData(self.handle) + self._advanced_analysis_requests += 1 + + def release_advanced_analysis_data(self): + core.BNReleaseAdvancedFunctionAnalysisData(self.handle) + self._advanced_analysis_requests -= 1 + +class AdvancedFunctionAnalysisDataRequestor(object): + def __init__(self, func = None): + self._function = func + if self._function is not None: + self._function.request_advanced_analysis_data() + + def __del__(self): + if self._function is not None: + self._function.release_advanced_analysis_data() + + @property + def function(self): + return self._function + + @function.setter + def function(self, func): + if self._function is not None: + self._function.release_advanced_analysis_data() + self._function = func + if self._function is not None: + self._function.request_advanced_analysis_data() + + def close(self): + if self._function is not None: + self._function.release_advanced_analysis_data() + self._function = None + class BasicBlockEdge: def __init__(self, branch_type, target, arch): self.type = core.BNBranchType_names[branch_type] -- cgit v1.3.1 From 2e2c0fad51051871642f10f57cc0db96dd58a2ad Mon Sep 17 00:00:00 2001 From: Andrew Lamoureux Date: Tue, 6 Sep 2016 13:08:33 -0400 Subject: ExecuteWorkerProcess new parms: out,err text,bin --- binaryninjaapi.cpp | 5 +++-- binaryninjaapi.h | 2 +- binaryninjacore.h | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.cpp b/binaryninjaapi.cpp index 71a5a8f7..1a9f5713 100644 --- a/binaryninjaapi.cpp +++ b/binaryninjaapi.cpp @@ -93,7 +93,7 @@ string BinaryNinja::GetPathRelativeToUserPluginDirectory(const string& rel) bool BinaryNinja::ExecuteWorkerProcess(const string& path, const vector& args, const DataBuffer& input, - string& output, string& errors) + string& output, string& errors, bool stdoutIsText, bool stderrIsText) { const char** argArray = new const char*[args.size() + 1]; for (size_t i = 0; i < args.size(); i++) @@ -102,7 +102,8 @@ bool BinaryNinja::ExecuteWorkerProcess(const string& path, const vector& char* outputStr; char* errorStr; - bool result = BNExecuteWorkerProcess(path.c_str(), argArray, input.GetBufferObject(), &outputStr, &errorStr); + bool result = BNExecuteWorkerProcess(path.c_str(), argArray, input.GetBufferObject(), &outputStr, &errorStr, + stdoutIsText, stderrIsText); output = outputStr; errors = errorStr; diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 72e13567..ff505527 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -346,7 +346,7 @@ namespace BinaryNinja std::string GetPathRelativeToUserPluginDirectory(const std::string& path); bool ExecuteWorkerProcess(const std::string& path, const std::vector& args, const DataBuffer& input, - std::string& output, std::string& errors); + std::string& output, std::string& errors, bool stdoutIsText=false, bool stderrIsText=true); std::string GetVersionString(); uint32_t GetBuildId(); diff --git a/binaryninjacore.h b/binaryninjacore.h index 0c2738cb..1fe0ad5a 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1041,7 +1041,8 @@ extern "C" BINARYNINJACOREAPI char* BNGetPathRelativeToUserPluginDirectory(const char* path); BINARYNINJACOREAPI bool BNExecuteWorkerProcess(const char* path, const char* args[], - BNDataBuffer* input, char** output, char** error); + BNDataBuffer* input, char** output, char** error, + bool stdoutIsText, bool stderrIsText); BINARYNINJACOREAPI void BNSetCurrentPluginLoadOrder(BNPluginLoadOrder order); BINARYNINJACOREAPI void BNAddRequiredPluginDependency(const char* name); -- cgit v1.3.1 From f5e59b13b726a0d154dbe9351010ed3bd4b2b9e6 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Tue, 6 Sep 2016 21:15:32 -0400 Subject: Add APIs for interactive work queue and worker thread count --- binaryninjaapi.cpp | 36 ++++++++++++++++++++++++++++++++++++ binaryninjaapi.h | 5 +++++ binaryninjacore.h | 4 ++++ python/__init__.py | 12 +++++++++++- 4 files changed, 56 insertions(+), 1 deletion(-) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.cpp b/binaryninjaapi.cpp index 1a9f5713..e1dab528 100644 --- a/binaryninjaapi.cpp +++ b/binaryninjaapi.cpp @@ -201,3 +201,39 @@ void BinaryNinja::WorkerPriorityEnqueue(RefCountObject* owner, const function& action) +{ + WorkerThreadActionContext* ctxt = new WorkerThreadActionContext; + ctxt->action = action; + BNWorkerInteractiveEnqueue(ctxt, WorkerActionCallback); +} + + +void BinaryNinja::WorkerInteractiveEnqueue(RefCountObject* owner, const function& action) +{ + struct + { + Ref owner; + function func; + } context; + context.owner = owner; + context.func = action; + + WorkerInteractiveEnqueue([=]() { + context.func(); + }); +} + + +size_t BinaryNinja::GetWorkerThreadCount() +{ + return BNGetWorkerThreadCount(); +} + + +void BinaryNinja::SetWorkerThreadCount(size_t count) +{ + BNSetWorkerThreadCount(count); +} diff --git a/binaryninjaapi.h b/binaryninjaapi.h index ff505527..a86f1067 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -375,6 +375,11 @@ namespace BinaryNinja void WorkerEnqueue(RefCountObject* owner, const std::function& action); void WorkerPriorityEnqueue(const std::function& action); void WorkerPriorityEnqueue(RefCountObject* owner, const std::function& action); + void WorkerInteractiveEnqueue(const std::function& action); + void WorkerInteractiveEnqueue(RefCountObject* owner, const std::function& action); + + size_t GetWorkerThreadCount(); + void SetWorkerThreadCount(size_t count); class DataBuffer { diff --git a/binaryninjacore.h b/binaryninjacore.h index 1fe0ad5a..960390fa 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1968,6 +1968,10 @@ extern "C" // Worker thread queue management BINARYNINJACOREAPI void BNWorkerEnqueue(void* ctxt, void (*action)(void* ctxt)); BINARYNINJACOREAPI void BNWorkerPriorityEnqueue(void* ctxt, void (*action)(void* ctxt)); + BINARYNINJACOREAPI void BNWorkerInteractiveEnqueue(void* ctxt, void (*action)(void* ctxt)); + + BINARYNINJACOREAPI size_t BNGetWorkerThreadCount(void); + BINARYNINJACOREAPI void BNSetWorkerThreadCount(size_t count); #ifdef __cplusplus } diff --git a/python/__init__.py b/python/__init__.py index d5eca84a..e36670cc 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -10097,7 +10097,17 @@ def worker_enqueue(func): def worker_priority_enqueue(func): action = _ThreadActionContext(func) - core.BNWorkerEnqueue(0, action.callback) + core.BNWorkerPriorityEnqueue(0, action.callback) + +def worker_interactive_enqueue(func): + action = _ThreadActionContext(func) + core.BNWorkerInteractiveEnqueue(0, action.callback) + +def get_worker_thread_count(): + return core.BNGetWorkerThreadCount() + +def set_worker_thread_count(count): + core.BNSetWorkerThreadCount(count) bundled_plugin_path = core.BNGetBundledPluginDirectory() user_plugin_path = core.BNGetUserPluginDirectory() -- cgit v1.3.1 From 6be6ee30e5973fa4d5f29cebdeafdf05c3f4251e Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Fri, 9 Sep 2016 03:29:14 -0400 Subject: Minor changes to API for creation of IL functions --- binaryninjaapi.h | 4 ++-- binaryninjacore.h | 4 ++-- lowlevelil.cpp | 8 ++++---- python/__init__.py | 15 +++++++-------- 4 files changed, 15 insertions(+), 16 deletions(-) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index a86f1067..9c7ff4f1 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1788,7 +1788,7 @@ namespace BinaryNinja BNNewLowLevelILFunctionReference, BNFreeLowLevelILFunction> { public: - LowLevelILFunction(Architecture* arch); + LowLevelILFunction(Architecture* arch, Function* func = nullptr); LowLevelILFunction(BNLowLevelILFunction* func); uint64_t GetCurrentAddress() const; @@ -1883,7 +1883,7 @@ namespace BinaryNinja void AddLabelForAddress(Architecture* arch, ExprId addr); BNLowLevelILLabel* GetLabelForAddress(Architecture* arch, ExprId addr); - void Finalize(Function* func = nullptr); + void Finalize(); bool GetExprText(Architecture* arch, ExprId expr, std::vector& tokens); bool GetInstructionText(Function* func, Architecture* arch, size_t i, diff --git a/binaryninjacore.h b/binaryninjacore.h index 960390fa..f917c2fa 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1665,7 +1665,7 @@ extern "C" BINARYNINJACOREAPI BNSymbol* BNImportedFunctionFromImportAddressSymbol(BNSymbol* sym, uint64_t addr); // Low-level IL - BINARYNINJACOREAPI BNLowLevelILFunction* BNCreateLowLevelILFunction(BNArchitecture* arch); + BINARYNINJACOREAPI BNLowLevelILFunction* BNCreateLowLevelILFunction(BNArchitecture* arch, BNFunction* func); BINARYNINJACOREAPI BNLowLevelILFunction* BNNewLowLevelILFunctionReference(BNLowLevelILFunction* func); BINARYNINJACOREAPI void BNFreeLowLevelILFunction(BNLowLevelILFunction* func); BINARYNINJACOREAPI uint64_t BNLowLevelILGetCurrentAddress(BNLowLevelILFunction* func); @@ -1681,7 +1681,7 @@ extern "C" BINARYNINJACOREAPI size_t BNLowLevelILIf(BNLowLevelILFunction* func, uint64_t op, BNLowLevelILLabel* t, BNLowLevelILLabel* f); BINARYNINJACOREAPI void BNLowLevelILInitLabel(BNLowLevelILLabel* label); BINARYNINJACOREAPI void BNLowLevelILMarkLabel(BNLowLevelILFunction* func, BNLowLevelILLabel* label); - BINARYNINJACOREAPI void BNFinalizeLowLevelILFunction(BNLowLevelILFunction* func, BNFunction* sourceFunc); + BINARYNINJACOREAPI void BNFinalizeLowLevelILFunction(BNLowLevelILFunction* func); BINARYNINJACOREAPI size_t BNLowLevelILAddLabelList(BNLowLevelILFunction* func, BNLowLevelILLabel** labels, size_t count); BINARYNINJACOREAPI size_t BNLowLevelILAddOperandList(BNLowLevelILFunction* func, uint64_t* operands, size_t count); diff --git a/lowlevelil.cpp b/lowlevelil.cpp index 550accc2..a312bbd6 100644 --- a/lowlevelil.cpp +++ b/lowlevelil.cpp @@ -30,9 +30,9 @@ LowLevelILLabel::LowLevelILLabel() } -LowLevelILFunction::LowLevelILFunction(Architecture* arch) +LowLevelILFunction::LowLevelILFunction(Architecture* arch, Function* func) { - m_object = BNCreateLowLevelILFunction(arch->GetObject()); + m_object = BNCreateLowLevelILFunction(arch->GetObject(), func ? func->GetObject() : nullptr); } @@ -559,9 +559,9 @@ BNLowLevelILLabel* LowLevelILFunction::GetLabelForAddress(Architecture* arch, Ex } -void LowLevelILFunction::Finalize(Function* func) +void LowLevelILFunction::Finalize() { - BNFinalizeLowLevelILFunction(m_object, func ? func->GetObject() : nullptr); + BNFinalizeLowLevelILFunction(m_object); } diff --git a/python/__init__.py b/python/__init__.py index e36670cc..7978fd2c 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -7201,7 +7201,10 @@ class LowLevelILFunction(object): if handle is not None: self.handle = core.handle_of_type(handle, core.BNLowLevelILFunction) else: - self.handle = core.BNCreateLowLevelILFunction(arch.handle) + func_handle = None + if self.source_function is not None: + func_handle = self.source_function.handle + self.handle = core.BNCreateLowLevelILFunction(arch.handle, func_handle) def __del__(self): core.BNFreeLowLevelILFunction(self.handle) @@ -8164,17 +8167,13 @@ class LowLevelILFunction(object): core.BNLowLevelILSetExprSourceOperand(self.handle, expr.index, n) return expr - def finalize(self, func = None): + def finalize(self): """ - ``finalize`` ends the provided LowLevelILLabel. + ``finalize`` ends the function and computes the list of basic blocks. - :param LowLevelILFunction func: optional function to end :rtype: None """ - if func is None: - core.BNFinalizeLowLevelILFunction(self.handle, None) - else: - core.BNFinalizeLowLevelILFunction(self.handle, func.handle) + core.BNFinalizeLowLevelILFunction(self.handle) def add_label_for_address(self, arch, addr): """ -- cgit v1.3.1 From 6d3fe290eb20e31a33e929933c01d2ca3eb43da1 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Sat, 10 Sep 2016 00:36:27 -0400 Subject: Add API for list of basic blocks starting at an address --- binaryninjaapi.h | 1 + binaryninjacore.h | 1 + binaryview.cpp | 14 ++++++++++++++ python/__init__.py | 16 ++++++++++++++++ 4 files changed, 32 insertions(+) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 9c7ff4f1..d4df479b 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -867,6 +867,7 @@ namespace BinaryNinja Ref GetRecentBasicBlockForAddress(uint64_t addr); std::vector> GetBasicBlocksForAddress(uint64_t addr); + std::vector> GetBasicBlocksStartingAtAddress(uint64_t addr); std::vector GetCodeReferences(uint64_t addr); std::vector GetCodeReferences(uint64_t addr, uint64_t len); diff --git a/binaryninjacore.h b/binaryninjacore.h index f917c2fa..51bf3391 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1420,6 +1420,7 @@ extern "C" BINARYNINJACOREAPI void BNFreeBasicBlockList(BNBasicBlock** blocks, size_t count); BINARYNINJACOREAPI BNBasicBlock* BNGetRecentBasicBlockForAddress(BNBinaryView* view, uint64_t addr); BINARYNINJACOREAPI BNBasicBlock** BNGetBasicBlocksForAddress(BNBinaryView* view, uint64_t addr, size_t* count); + BINARYNINJACOREAPI BNBasicBlock** BNGetBasicBlocksStartingAtAddress(BNBinaryView* view, uint64_t addr, size_t* count); BINARYNINJACOREAPI BNLowLevelILFunction* BNGetFunctionLowLevelIL(BNFunction* func); BINARYNINJACOREAPI size_t BNGetLowLevelILForInstruction(BNFunction* func, BNArchitecture* arch, uint64_t addr); diff --git a/binaryview.cpp b/binaryview.cpp index 1c03eca5..0a7f23ce 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -987,6 +987,20 @@ vector> BinaryView::GetBasicBlocksForAddress(uint64_t addr) } +vector> BinaryView::GetBasicBlocksStartingAtAddress(uint64_t addr) +{ + size_t count; + BNBasicBlock** blocks = BNGetBasicBlocksStartingAtAddress(m_object, addr, &count); + + vector> result; + for (size_t i = 0; i < count; i++) + result.push_back(new BasicBlock(BNNewBasicBlockReference(blocks[i]))); + + BNFreeBasicBlockList(blocks, count); + return result; +} + + vector BinaryView::GetCodeReferences(uint64_t addr) { size_t count; diff --git a/python/__init__.py b/python/__init__.py index 7978fd2c..33202a2c 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -2288,6 +2288,22 @@ class BinaryView(object): core.BNFreeBasicBlockList(blocks, count.value) return result + def get_basic_blocks_starting_at(self, addr): + """ + ``get_basic_blocks_at`` get a list of :py:Class:`BasicBlock` objects which start at the provided virtual address. + + :param int addr: virtual address of BasicBlock desired + :return: a list of :py:Class:`BasicBlock` objects + :rtype: list(BasicBlock) + """ + count = ctypes.c_ulonglong(0) + blocks = core.BNGetBasicBlocksStartingAtAddress(self.handle, addr, count) + result = [] + for i in xrange(0, count.value): + result.append(BasicBlock(self, core.BNNewBasicBlockReference(blocks[i]))) + core.BNFreeBasicBlockList(blocks, count.value) + return result + def get_recent_basic_block_at(self, addr): block = core.BNGetRecentBasicBlockForAddress(self.handle, addr) if block is None: -- cgit v1.3.1 From fb0d896cd5cc3197a8dd259a9ca53f2788ef5fdb Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Wed, 14 Sep 2016 00:28:27 -0400 Subject: Add APIs for instruction and block highlighting --- basicblock.cpp | 110 +++++++++++++++++++++++++++++++++++ binaryninjaapi.h | 30 ++++++++++ binaryninjacore.h | 40 +++++++++++++ function.cpp | 123 +++++++++++++++++++++++++++++++++++++++ functiongraphblock.cpp | 6 ++ python/__init__.py | 152 +++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 461 insertions(+) (limited to 'binaryninjaapi.h') diff --git a/basicblock.cpp b/basicblock.cpp index 377c5704..93a279a1 100644 --- a/basicblock.cpp +++ b/basicblock.cpp @@ -172,3 +172,113 @@ vector BasicBlock::GetDisassemblyText(DisassemblySettings* BNFreeDisassemblyTextLines(lines, count); return result; } + + +BNHighlightColor BasicBlock::GetBasicBlockHighlight() +{ + return BNGetBasicBlockHighlight(m_object); +} + + +void BasicBlock::SetAutoBasicBlockHighlight(BNHighlightColor color) +{ + BNSetAutoBasicBlockHighlight(m_object, color); +} + + +void BasicBlock::SetAutoBasicBlockHighlight(BNHighlightStandardColor color, uint8_t alpha) +{ + BNHighlightColor hc; + hc.style = StandardHighlightColor; + hc.color = color; + hc.mixColor = NoHighlightColor; + hc.mix = 0; + hc.r = 0; + hc.g = 0; + hc.b = 0; + hc.alpha = alpha; + SetAutoBasicBlockHighlight(hc); +} + + +void BasicBlock::SetAutoBasicBlockHighlight(BNHighlightStandardColor color, BNHighlightStandardColor mixColor, + uint8_t mix, uint8_t alpha) +{ + BNHighlightColor hc; + hc.style = MixedHighlightColor; + hc.color = color; + hc.mixColor = mixColor; + hc.mix = mix; + hc.r = 0; + hc.g = 0; + hc.b = 0; + hc.alpha = alpha; + SetAutoBasicBlockHighlight(hc); +} + + +void BasicBlock::SetAutoBasicBlockHighlight(uint8_t r, uint8_t g, uint8_t b, uint8_t alpha) +{ + BNHighlightColor hc; + hc.style = CustomHighlightColor; + hc.color = NoHighlightColor; + hc.mixColor = NoHighlightColor; + hc.mix = 0; + hc.r = r; + hc.g = g; + hc.b = b; + hc.alpha = alpha; + SetAutoBasicBlockHighlight(hc); +} + + +void BasicBlock::SetUserBasicBlockHighlight(BNHighlightColor color) +{ + BNSetUserBasicBlockHighlight(m_object, color); +} + + +void BasicBlock::SetUserBasicBlockHighlight(BNHighlightStandardColor color, uint8_t alpha) +{ + BNHighlightColor hc; + hc.style = StandardHighlightColor; + hc.color = color; + hc.mixColor = NoHighlightColor; + hc.mix = 0; + hc.r = 0; + hc.g = 0; + hc.b = 0; + hc.alpha = alpha; + SetUserBasicBlockHighlight(hc); +} + + +void BasicBlock::SetUserBasicBlockHighlight(BNHighlightStandardColor color, BNHighlightStandardColor mixColor, + uint8_t mix, uint8_t alpha) +{ + BNHighlightColor hc; + hc.style = MixedHighlightColor; + hc.color = color; + hc.mixColor = mixColor; + hc.mix = mix; + hc.r = 0; + hc.g = 0; + hc.b = 0; + hc.alpha = alpha; + SetUserBasicBlockHighlight(hc); +} + + +void BasicBlock::SetUserBasicBlockHighlight(uint8_t r, uint8_t g, uint8_t b, uint8_t alpha) +{ + BNHighlightColor hc; + hc.style = CustomHighlightColor; + hc.color = NoHighlightColor; + hc.mixColor = NoHighlightColor; + hc.mix = 0; + hc.r = r; + hc.g = g; + hc.b = b; + hc.alpha = alpha; + SetUserBasicBlockHighlight(hc); +} diff --git a/binaryninjaapi.h b/binaryninjaapi.h index d4df479b..30285380 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1561,6 +1561,18 @@ namespace BinaryNinja std::vector> GetAnnotations(); std::vector GetDisassemblyText(DisassemblySettings* settings); + + BNHighlightColor GetBasicBlockHighlight(); + void SetAutoBasicBlockHighlight(BNHighlightColor color); + void SetAutoBasicBlockHighlight(BNHighlightStandardColor color, uint8_t alpha = 255); + void SetAutoBasicBlockHighlight(BNHighlightStandardColor color, BNHighlightStandardColor mixColor, + uint8_t mix, uint8_t alpha = 255); + void SetAutoBasicBlockHighlight(uint8_t r, uint8_t g, uint8_t b, uint8_t alpha = 255); + void SetUserBasicBlockHighlight(BNHighlightColor color); + void SetUserBasicBlockHighlight(BNHighlightStandardColor color, uint8_t alpha = 255); + void SetUserBasicBlockHighlight(BNHighlightStandardColor color, BNHighlightStandardColor mixColor, + uint8_t mix, uint8_t alpha = 255); + void SetUserBasicBlockHighlight(uint8_t r, uint8_t g, uint8_t b, uint8_t alpha = 255); }; struct StackVariable @@ -1633,6 +1645,7 @@ namespace BinaryNinja bool NeedsUpdate() const; std::vector> GetBasicBlocks() const; + Ref GetBasicBlockAtAddress(Architecture* arch, uint64_t addr) const; void MarkRecentUse(); std::string GetCommentForAddress(uint64_t addr) const; @@ -1692,6 +1705,22 @@ namespace BinaryNinja void SetIntegerConstantDisplayType(Architecture* arch, uint64_t instrAddr, uint64_t value, size_t operand, BNIntegerDisplayType type); + BNHighlightColor GetInstructionHighlight(Architecture* arch, uint64_t addr); + void SetAutoInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightColor color); + void SetAutoInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightStandardColor color, + uint8_t alpha = 255); + void SetAutoInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightStandardColor color, + BNHighlightStandardColor mixColor, uint8_t mix, uint8_t alpha = 255); + void SetAutoInstructionHighlight(Architecture* arch, uint64_t addr, uint8_t r, uint8_t g, uint8_t b, + uint8_t alpha = 255); + void SetUserInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightColor color); + void SetUserInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightStandardColor color, + uint8_t alpha = 255); + void SetUserInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightStandardColor color, + BNHighlightStandardColor mixColor, uint8_t mix, uint8_t alpha = 255); + void SetUserInstructionHighlight(Architecture* arch, uint64_t addr, uint8_t r, uint8_t g, uint8_t b, + uint8_t alpha = 255); + void Reanalyze(); void RequestAdvancedAnalysisData(); @@ -1731,6 +1760,7 @@ namespace BinaryNinja public: FunctionGraphBlock(BNFunctionGraphBlock* block); + Ref GetBasicBlock() const; Ref GetArchitecture() const; uint64_t GetStart() const; uint64_t GetEnd() const; diff --git a/binaryninjacore.h b/binaryninjacore.h index 51bf3391..de7b77fd 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1020,6 +1020,35 @@ extern "C" size_t size; }; + enum BNHighlightColorStyle + { + StandardHighlightColor = 0, + MixedHighlightColor = 1, + CustomHighlightColor = 2 + }; + + enum BNHighlightStandardColor + { + NoHighlightColor = 0, + BlueHighlightColor = 1, + GreenHighlightColor = 2, + CyanHighlightColor = 3, + RedHighlightColor = 4, + MagentaHighlightColor = 5, + YellowHighlightColor = 6, + OrangeHighlightColor = 7, + WhiteHighlightColor = 8, + BlackHighlightColor = 9 + }; + + struct BNHighlightColor + { + BNHighlightColorStyle style; + BNHighlightStandardColor color; + BNHighlightStandardColor mixColor; + uint8_t mix, r, g, b, alpha; + }; + BINARYNINJACOREAPI char* BNAllocString(const char* contents); BINARYNINJACOREAPI void BNFreeString(char* str); @@ -1418,6 +1447,7 @@ extern "C" BINARYNINJACOREAPI void BNFreeBasicBlock(BNBasicBlock* block); BINARYNINJACOREAPI BNBasicBlock** BNGetFunctionBasicBlockList(BNFunction* func, size_t* count); BINARYNINJACOREAPI void BNFreeBasicBlockList(BNBasicBlock** blocks, size_t count); + BINARYNINJACOREAPI BNBasicBlock* BNGetFunctionBasicBlockAtAddress(BNFunction* func, BNArchitecture* arch, uint64_t addr); BINARYNINJACOREAPI BNBasicBlock* BNGetRecentBasicBlockForAddress(BNBinaryView* view, uint64_t addr); BINARYNINJACOREAPI BNBasicBlock** BNGetBasicBlocksForAddress(BNBinaryView* view, uint64_t addr, size_t* count); BINARYNINJACOREAPI BNBasicBlock** BNGetBasicBlocksStartingAtAddress(BNBinaryView* view, uint64_t addr, size_t* count); @@ -1575,6 +1605,15 @@ extern "C" BINARYNINJACOREAPI void BNReanalyzeAllFunctions(BNBinaryView* view); BINARYNINJACOREAPI void BNReanalyzeFunction(BNFunction* func); + BINARYNINJACOREAPI BNHighlightColor BNGetInstructionHighlight(BNFunction* func, BNArchitecture* arch, uint64_t addr); + BINARYNINJACOREAPI void BNSetAutoInstructionHighlight(BNFunction* func, BNArchitecture* arch, uint64_t addr, + BNHighlightColor color); + BINARYNINJACOREAPI void BNSetUserInstructionHighlight(BNFunction* func, BNArchitecture* arch, uint64_t addr, + BNHighlightColor color); + BINARYNINJACOREAPI BNHighlightColor BNGetBasicBlockHighlight(BNBasicBlock* block); + BINARYNINJACOREAPI void BNSetAutoBasicBlockHighlight(BNBasicBlock* block, BNHighlightColor color); + BINARYNINJACOREAPI void BNSetUserBasicBlockHighlight(BNBasicBlock* block, BNHighlightColor color); + // Disassembly settings BINARYNINJACOREAPI BNDisassemblySettings* BNCreateDisassemblySettings(void); BINARYNINJACOREAPI BNDisassemblySettings* BNNewDisassemblySettingsReference(BNDisassemblySettings* settings); @@ -1622,6 +1661,7 @@ extern "C" BINARYNINJACOREAPI BNFunctionGraphBlock* BNNewFunctionGraphBlockReference(BNFunctionGraphBlock* block); BINARYNINJACOREAPI void BNFreeFunctionGraphBlock(BNFunctionGraphBlock* block); + BINARYNINJACOREAPI BNBasicBlock* BNGetFunctionGraphBasicBlock(BNFunctionGraphBlock* block); BINARYNINJACOREAPI BNArchitecture* BNGetFunctionGraphBlockArchitecture(BNFunctionGraphBlock* block); BINARYNINJACOREAPI uint64_t BNGetFunctionGraphBlockStart(BNFunctionGraphBlock* block); BINARYNINJACOREAPI uint64_t BNGetFunctionGraphBlockEnd(BNFunctionGraphBlock* block); diff --git a/function.cpp b/function.cpp index de12918f..109b6f49 100644 --- a/function.cpp +++ b/function.cpp @@ -100,6 +100,15 @@ vector> Function::GetBasicBlocks() const } +Ref Function::GetBasicBlockAtAddress(Architecture* arch, uint64_t addr) const +{ + BNBasicBlock* block = BNGetFunctionBasicBlockAtAddress(m_object, arch->GetObject(), addr); + if (!block) + return nullptr; + return new BasicBlock(block); +} + + void Function::MarkRecentUse() { BNMarkFunctionAsRecentlyUsed(m_object); @@ -582,6 +591,120 @@ void Function::SetIntegerConstantDisplayType(Architecture* arch, uint64_t instrA } +BNHighlightColor Function::GetInstructionHighlight(Architecture* arch, uint64_t addr) +{ + return BNGetInstructionHighlight(m_object, arch->GetObject(), addr); +} + + +void Function::SetAutoInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightColor color) +{ + BNSetAutoInstructionHighlight(m_object, arch->GetObject(), addr, color); +} + + +void Function::SetAutoInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightStandardColor color, + uint8_t alpha) +{ + BNHighlightColor hc; + hc.style = StandardHighlightColor; + hc.color = color; + hc.mixColor = NoHighlightColor; + hc.mix = 0; + hc.r = 0; + hc.g = 0; + hc.b = 0; + hc.alpha = alpha; + SetAutoInstructionHighlight(arch, addr, hc); +} + + +void Function::SetAutoInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightStandardColor color, + BNHighlightStandardColor mixColor, uint8_t mix, uint8_t alpha) +{ + BNHighlightColor hc; + hc.style = MixedHighlightColor; + hc.color = color; + hc.mixColor = mixColor; + hc.mix = mix; + hc.r = 0; + hc.g = 0; + hc.b = 0; + hc.alpha = alpha; + SetAutoInstructionHighlight(arch, addr, hc); +} + + +void Function::SetAutoInstructionHighlight(Architecture* arch, uint64_t addr, uint8_t r, uint8_t g, uint8_t b, + uint8_t alpha) +{ + BNHighlightColor hc; + hc.style = CustomHighlightColor; + hc.color = NoHighlightColor; + hc.mixColor = NoHighlightColor; + hc.mix = 0; + hc.r = r; + hc.g = g; + hc.b = b; + hc.alpha = alpha; + SetAutoInstructionHighlight(arch, addr, hc); +} + + +void Function::SetUserInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightColor color) +{ + BNSetUserInstructionHighlight(m_object, arch->GetObject(), addr, color); +} + + +void Function::SetUserInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightStandardColor color, + uint8_t alpha) +{ + BNHighlightColor hc; + hc.style = StandardHighlightColor; + hc.color = color; + hc.mixColor = NoHighlightColor; + hc.mix = 0; + hc.r = 0; + hc.g = 0; + hc.b = 0; + hc.alpha = alpha; + SetUserInstructionHighlight(arch, addr, hc); +} + + +void Function::SetUserInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightStandardColor color, + BNHighlightStandardColor mixColor, uint8_t mix, uint8_t alpha) +{ + BNHighlightColor hc; + hc.style = MixedHighlightColor; + hc.color = color; + hc.mixColor = mixColor; + hc.mix = mix; + hc.r = 0; + hc.g = 0; + hc.b = 0; + hc.alpha = alpha; + SetUserInstructionHighlight(arch, addr, hc); +} + + +void Function::SetUserInstructionHighlight(Architecture* arch, uint64_t addr, uint8_t r, uint8_t g, uint8_t b, + uint8_t alpha) +{ + BNHighlightColor hc; + hc.style = CustomHighlightColor; + hc.color = NoHighlightColor; + hc.mixColor = NoHighlightColor; + hc.mix = 0; + hc.r = r; + hc.g = g; + hc.b = b; + hc.alpha = alpha; + SetUserInstructionHighlight(arch, addr, hc); +} + + void Function::Reanalyze() { BNReanalyzeFunction(m_object); diff --git a/functiongraphblock.cpp b/functiongraphblock.cpp index 436339f6..47261453 100644 --- a/functiongraphblock.cpp +++ b/functiongraphblock.cpp @@ -32,6 +32,12 @@ FunctionGraphBlock::FunctionGraphBlock(BNFunctionGraphBlock* block) } +Ref FunctionGraphBlock::GetBasicBlock() const +{ + return new BasicBlock(BNGetFunctionGraphBasicBlock(m_object)); +} + + Ref FunctionGraphBlock::GetArchitecture() const { return new CoreArchitecture(BNGetFunctionGraphBlockArchitecture(m_object)); diff --git a/python/__init__.py b/python/__init__.py index 33202a2c..b29c9f80 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -4381,6 +4381,93 @@ class IndirectBranchInfo: def __repr__(self): return " %s:%#x>" % (self.source_arch.name, self.source_addr, self.dest_arch.name, self.dest_addr) +class HighlightColor(object): + def __init__(self, color = None, mix_color = None, mix = None, red = None, green = None, blue = None, alpha = 255): + if (red is not None) and (green is not None) and (blue is not None): + self.style = core.CustomHighlightColor + self.red = red + self.green = green + self.blue = blue + elif (mix_color is not None) and (mix is not None): + self.style = core.MixedHighlightColor + if color is None: + self.color = core.NoHighlightColor + else: + self.color = color + self.mix_color = mix_color + self.mix = mix + else: + self.style = core.StandardHighlightColor + if color is None: + self.color = core.NoHighlightColor + else: + self.color = color + self.alpha = alpha + + def _standard_color_to_str(self, color): + if color == core.NoHighlightColor: + return "none" + if color == core.BlueHighlightColor: + return "blue" + if color == core.GreenHighlightColor: + return "green" + if color == core.CyanHighlightColor: + return "cyan" + if color == core.RedHighlightColor: + return "red" + if color == core.MagentaHighlightColor: + return "magenta" + if color == core.YellowHighlightColor: + return "yellow" + if color == core.OrangeHighlightColor: + return "orange" + if color == core.WhiteHighlightColor: + return "white" + if color == core.BlackHighlightColor: + return "black" + return "%d" % color + + def __repr__(self): + if self.style == core.StandardHighlightColor: + if self.alpha == 255: + return "" % self._standard_color_to_str(self.color) + return "" % (self._standard_color_to_str(self.color), self.alpha) + if self.style == core.MixedHighlightColor: + if self.alpha == 255: + return "" % (self._standard_color_to_str(self.color), + self._standard_color_to_str(self.mix_color), self.mix) + return "" % (self._standard_color_to_str(self.color), + self._standard_color_to_str(self.mix_color), self.mix, self.alpha) + if self.style == core.CustomHighlightColor: + if self.alpha == 255: + return "" % (self.red, self.green, self.blue) + return "" % (self.red, self.green, self.blue, self.alpha) + return "" + + def _get_core_struct(self): + result = core.BNHighlightColor() + result.style = self.style + result.color = core.NoHighlightColor + result.mix_color = core.NoHighlightColor + result.mix = 0 + result.r = 0 + result.g = 0 + result.b = 0 + result.alpha = self.alpha + + if self.style == core.StandardHighlightColor: + result.color = self.color + elif self.style == core.MixedHighlightColor: + result.color = self.color + result.mixColor = self.mix_color + result.mix = self.mix + elif self.style == core.CustomHighlightColor: + result.r = self.red + result.g = self.green + result.b = self.blue + + return result + class Function(object): def __init__(self, view, handle): self._view = view @@ -4790,6 +4877,32 @@ class Function(object): core.BNReleaseAdvancedFunctionAnalysisData(self.handle) self._advanced_analysis_requests -= 1 + def get_basic_block_at(self, arch, addr): + block = core.BNGetFunctionBasicBlockAtAddress(self.handle, arch.handle, addr) + if not block: + return None + return BasicBlock(self._view, handle = block) + + def get_instr_highlight(self, arch, addr): + color = core.BNGetInstructionHighlight(self.handle, arch.handle, addr) + if color.style == core.StandardHighlightColor: + return HighlightColor(color = color.color, alpha = color.alpha) + elif color.style == core.MixedHighlightColor: + return HighlightColor(color = color.color, mix_color = color.mixColor, mix = color.mix, alpha = color.alpha) + elif color.style == core.CustomHighlightColor: + return HighlightColor(red = color.r, green = color.g, blue = color.b, alpha = color.alpha) + return HighlightColor(color = core.NoHighlightColor) + + def set_auto_instr_highlight(self, arch, addr, color): + if not isinstance(color, HighlightColor): + color = HighlightColor(color = color) + core.BNSetAutoInstructionHighlight(self.handle, arch.handle, addr, color._get_core_struct()) + + def set_user_instr_highlight(self, arch, addr, color): + if not isinstance(color, HighlightColor): + color = HighlightColor(color = color) + core.BNSetUserInstructionHighlight(self.handle, arch.handle, addr, color._get_core_struct()) + class AdvancedFunctionAnalysisDataRequestor(object): def __init__(self, func = None): self._function = func @@ -4902,6 +5015,22 @@ class BasicBlock(object): def disassembly_text(self): return self.get_disassembly_text() + @property + def highlight(self): + """Highlight color for basic block""" + color = core.BNGetBasicBlockHighlight(self.handle) + if color.style == core.StandardHighlightColor: + return HighlightColor(color = color.color, alpha = color.alpha) + elif color.style == core.MixedHighlightColor: + return HighlightColor(color = color.color, mix_color = color.mixColor, mix = color.mix, alpha = color.alpha) + elif color.style == core.CustomHighlightColor: + return HighlightColor(red = color.r, green = color.g, blue = color.b, alpha = color.alpha) + return HighlightColor(color = core.NoHighlightColor) + + @highlight.setter + def highlight(self, value): + self.set_user_highlight(value) + def __setattr__(self, name, value): try: object.__setattr__(self,name,value) @@ -4956,6 +5085,16 @@ class BasicBlock(object): core.BNFreeDisassemblyTextLines(lines, count.value) return result + def set_auto_highlight(self, color): + if not isinstance(color, HighlightColor): + color = HighlightColor(color = color) + core.BNSetAutoBasicBlockHighlight(self.handle, color._get_core_struct()) + + def set_user_highlight(self, color): + if not isinstance(color, HighlightColor): + color = HighlightColor(color = color) + core.BNSetUserBasicBlockHighlight(self.handle, color._get_core_struct()) + class LowLevelILBasicBlock(BasicBlock): def __init__(self, view, handle, owner): super(LowLevelILBasicBlock, self).__init__(view, handle) @@ -4998,6 +5137,19 @@ class FunctionGraphBlock(object): def __del__(self): core.BNFreeFunctionGraphBlock(self.handle) + @property + def basic_block(self): + """Basic block associated with this part of the funciton graph (read-only)""" + block = core.BNGetFunctionGraphBasicBlock(self.handle) + func = core.BNGetBasicBlockFunction(block) + if func is None: + core.BNFreeBasicBlock(block) + block = None + else: + block = BasicBlock(BinaryView(None, handle = core.BNGetFunctionData(func)), block) + core.BNFreeFunction(func) + return block + @property def arch(self): """Function graph block architecture (read-only)""" -- cgit v1.3.1 From 124cf1bc4f465a915621b7ac81af94b9a69a937a Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Thu, 15 Sep 2016 01:55:28 -0400 Subject: Add APIs to display busy indicator for long running plugin tasks --- backgroundtask.cpp | 75 +++++++++++++++++++++++++++++++++++++++++ binaryninjaapi.h | 19 +++++++++++ binaryninjacore.h | 16 +++++++++ python/__init__.py | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+) create mode 100644 backgroundtask.cpp (limited to 'binaryninjaapi.h') diff --git a/backgroundtask.cpp b/backgroundtask.cpp new file mode 100644 index 00000000..aebf980c --- /dev/null +++ b/backgroundtask.cpp @@ -0,0 +1,75 @@ +#include "binaryninjaapi.h" + +using namespace std; +using namespace BinaryNinja; + + +BackgroundTask::BackgroundTask(BNBackgroundTask* task) +{ + m_object = task; +} + + +BackgroundTask::BackgroundTask(const string& initialText, bool canCancel) +{ + m_object = BNBeginBackgroundTask(initialText.c_str(), canCancel); +} + + +bool BackgroundTask::CanCancel() const +{ + return BNCanCancelBackgroundTask(m_object); +} + + +bool BackgroundTask::IsCancelled() const +{ + return BNIsBackgroundTaskCancelled(m_object); +} + + +bool BackgroundTask::IsFinished() const +{ + return BNIsBackgroundTaskFinished(m_object); +} + + +string BackgroundTask::GetProgressText() const +{ + char* text = BNGetBackgroundTaskProgressText(m_object); + string result = text; + BNFreeString(text); + return result; +} + + +void BackgroundTask::Cancel() +{ + BNCancelBackgroundTask(m_object); +} + + +void BackgroundTask::Finish() +{ + BNFinishBackgroundTask(m_object); +} + + +void BackgroundTask::SetProgressText(const string& text) +{ + BNSetBackgroundTaskProgressText(m_object, text.c_str()); +} + + +vector> BackgroundTask::GetRunningTasks() +{ + size_t count; + BNBackgroundTask** tasks = BNGetRunningBackgroundTasks(&count); + + vector> result; + for (size_t i = 0; i < count; i++) + result.push_back(new BackgroundTask(BNNewBackgroundTaskReference(tasks[i]))); + + BNFreeBackgroundTaskList(tasks, count); + return result; +} diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 30285380..3400cca7 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -2260,4 +2260,23 @@ namespace BinaryNinja public: virtual void AddMainThreadAction(MainThreadAction* action) = 0; }; + + class BackgroundTask: public CoreRefCountObject + { + public: + BackgroundTask(BNBackgroundTask* task); + BackgroundTask(const std::string& initialText, bool canCancel); + + bool CanCancel() const; + bool IsCancelled() const; + bool IsFinished() const; + std::string GetProgressText() const; + + void Cancel(); + void Finish(); + void SetProgressText(const std::string& text); + + static std::vector> GetRunningTasks(); + }; } diff --git a/binaryninjacore.h b/binaryninjacore.h index de7b77fd..89dceba1 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -102,6 +102,7 @@ extern "C" struct BNScriptingProvider; struct BNScriptingInstance; struct BNMainThreadAction; + struct BNBackgroundTask; //! Console log levels enum BNLogLevel @@ -2014,6 +2015,21 @@ extern "C" BINARYNINJACOREAPI size_t BNGetWorkerThreadCount(void); BINARYNINJACOREAPI void BNSetWorkerThreadCount(size_t count); + // Background task progress reporting + BINARYNINJACOREAPI BNBackgroundTask* BNBeginBackgroundTask(const char* initialText, bool canCancel); + BINARYNINJACOREAPI void BNFinishBackgroundTask(BNBackgroundTask* task); + BINARYNINJACOREAPI void BNSetBackgroundTaskProgressText(BNBackgroundTask* task, const char* text); + BINARYNINJACOREAPI bool BNIsBackgroundTaskCancelled(BNBackgroundTask* task); + + BINARYNINJACOREAPI BNBackgroundTask** BNGetRunningBackgroundTasks(size_t* count); + BINARYNINJACOREAPI BNBackgroundTask* BNNewBackgroundTaskReference(BNBackgroundTask* task); + BINARYNINJACOREAPI void BNFreeBackgroundTask(BNBackgroundTask* task); + BINARYNINJACOREAPI void BNFreeBackgroundTaskList(BNBackgroundTask** tasks, size_t count); + BINARYNINJACOREAPI char* BNGetBackgroundTaskProgressText(BNBackgroundTask* task); + BINARYNINJACOREAPI bool BNCanCancelBackgroundTask(BNBackgroundTask* task); + BINARYNINJACOREAPI void BNCancelBackgroundTask(BNBackgroundTask* task); + BINARYNINJACOREAPI bool BNIsBackgroundTaskFinished(BNBackgroundTask* task); + #ifdef __cplusplus } #endif diff --git a/python/__init__.py b/python/__init__.py index b29c9f80..6abbdfa6 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -9961,6 +9961,104 @@ class MainThreadActionHandler(object): def add_action(self, action): pass +class _BackgroundTaskMetaclass(type): + @property + def list(self): + """List all running background tasks (read-only)""" + count = ctypes.c_ulonglong() + tasks = core.BNGetRunningBackgroundTasks(count) + result = [] + for i in xrange(0, count.value): + result.append(BackgroundTask(core.BNNewBackgroundTaskReference(tasks[i]))) + core.BNFreeBackgroundTaskList(tasks) + return result + + def __iter__(self): + _init_plugins() + count = ctypes.c_ulonglong() + tasks = core.BNGetRunningBackgroundTasks(count) + try: + for i in xrange(0, count.value): + yield BackgroundTask(core.BNNewBackgroundTaskReference(tasks[i])) + finally: + core.BNFreeBackgroundTaskList(tasks) + +class BackgroundTask(object): + __metaclass__ = _BackgroundTaskMetaclass + + def __init__(self, initial_progress_text = "", can_cancel = False, handle = None): + if handle is None: + self.handle = core.BNBeginBackgroundTask(initial_progress_text, can_cancel) + else: + self.handle = handle + + def __del__(self): + core.BNFreeBackgroundTask(self.handle) + + @property + def progress(self): + """Text description of the progress of the background task (displayed in status bar of the UI)""" + return core.BNGetBackgroundTaskProgressText(self.handle) + + @progress.setter + def progress(self, value): + core.BNSetBackgroundTaskProgressText(self.handle, str(value)) + + @property + def can_cancel(self): + """Whether the task can be cancelled (read-only)""" + return core.BNCanCancelBackgroundTask(self.handle) + + @property + def finished(self): + """Whether the task has finished""" + return core.BNIsBackgroundTaskFinished(self.handle) + + @finished.setter + def finished(self, value): + if value: + self.finish() + + def finish(self): + core.BNFinishBackgroundTask(self.handle) + + @property + def cancelled(self): + """Whether the task has been cancelled""" + return core.BNIsBackgroundTaskCancelled(self.handle) + + @cancelled.setter + def cancelled(self, value): + if value: + self.cancel() + + def cancel(self): + core.BNCancelBackgroundTask(self.handle) + +class BackgroundTaskThread(BackgroundTask): + def __init__(self, initial_progress_text = "", can_cancel = False): + class _Thread(threading.Thread): + def __init__(self, task): + threading.Thread.__init__(self) + self.task = task + + def run(self): + self.task.run() + self.task.finish() + self.task = None + + BackgroundTask.__init__(self, initial_progress_text, can_cancel) + self.thread = _Thread(self) + + def run(self): + pass + + def start(self): + self.thread.start() + + def join(self): + self.thread.join() + def LLIL_TEMP(n): return n | 0x80000000 -- cgit v1.3.1 From 2ec606fab8754dad2135deec2e72e87d39382978 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Fri, 16 Sep 2016 19:09:01 -0400 Subject: Add APIs for user interaction from plugins --- binaryninjaapi.h | 50 ++++++++++ binaryninjacore.h | 39 ++++++++ binaryview.cpp | 33 +++++++ interaction.cpp | 286 +++++++++++++++++++++++++++++++++++++++++++++++++++++ python/__init__.py | 248 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 656 insertions(+) create mode 100644 interaction.cpp (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 3400cca7..720a8eb6 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -275,6 +275,7 @@ namespace BinaryNinja class DataBuffer; class MainThreadAction; class MainThreadActionHandler; + class InteractionHandler; /*! Logs to the error console with the given BNLogLevel. @@ -381,6 +382,26 @@ namespace BinaryNinja size_t GetWorkerThreadCount(); void SetWorkerThreadCount(size_t count); + std::string MarkdownToHTML(const std::string& contents); + + void RegisterInteractionHandler(InteractionHandler* handler); + + void ShowPlainTextReport(const std::string& title, const std::string& contents); + void ShowMarkdownReport(const std::string& title, const std::string& contents, + const std::string& plainText = ""); + void ShowHTMLReport(const std::string& title, const std::string& contents, + const std::string& plainText = ""); + + bool GetTextLineInput(std::string& result, const std::string& prompt, const std::string& title); + bool GetIntegerInput(int64_t& result, const std::string& prompt, const std::string& title); + bool GetAddressInput(uint64_t& result, const std::string& prompt, const std::string& title); + bool GetChoiceInput(size_t& idx, const std::string& prompt, const std::string& title, + const std::vector& choices); + bool GetOpenFileNameInput(std::string& result, const std::string& prompt, const std::string& ext = ""); + bool GetSaveFileNameInput(std::string& result, const std::string& prompt, const std::string& ext = "", + const std::string& defaultName = ""); + bool GetDirectoryNameInput(std::string& result, const std::string& prompt, const std::string& defaultName = ""); + class DataBuffer { BNDataBuffer* m_buffer; @@ -935,6 +956,13 @@ namespace BinaryNinja bool FindNextData(uint64_t start, const DataBuffer& data, uint64_t& result, BNFindFlag flags = NoFindFlags); void Reanalyze(); + + void ShowPlainTextReport(const std::string& title, const std::string& contents); + void ShowMarkdownReport(const std::string& title, const std::string& contents, const std::string& plainText); + void ShowHTMLReport(const std::string& title, const std::string& contents, const std::string& plainText); + bool GetAddressInput(uint64_t& result, const std::string& prompt, const std::string& title); + bool GetAddressInput(uint64_t& result, const std::string& prompt, const std::string& title, + uint64_t currentAddress); }; class BinaryData: public BinaryView @@ -2279,4 +2307,26 @@ namespace BinaryNinja static std::vector> GetRunningTasks(); }; + + class InteractionHandler + { + public: + virtual void ShowPlainTextReport(Ref view, const std::string& title, const std::string& contents) = 0; + virtual void ShowMarkdownReport(Ref view, const std::string& title, const std::string& contents, + const std::string& plainText); + virtual void ShowHTMLReport(Ref view, const std::string& title, const std::string& contents, + const std::string& plainText); + + virtual bool GetTextLineInput(std::string& result, const std::string& prompt, const std::string& title) = 0; + virtual bool GetIntegerInput(int64_t& result, const std::string& prompt, const std::string& title); + virtual bool GetAddressInput(uint64_t& result, const std::string& prompt, const std::string& title, + Ref view, uint64_t currentAddr); + virtual bool GetChoiceInput(size_t& idx, const std::string& prompt, const std::string& title, + const std::vector& choices) = 0; + virtual bool GetOpenFileNameInput(std::string& result, const std::string& prompt, const std::string& ext = ""); + virtual bool GetSaveFileNameInput(std::string& result, const std::string& prompt, + const std::string& ext = "", const std::string& defaultName = ""); + virtual bool GetDirectoryNameInput(std::string& result, const std::string& prompt, + const std::string& defaultName = ""); + }; } diff --git a/binaryninjacore.h b/binaryninjacore.h index 89dceba1..34806b6c 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1050,6 +1050,26 @@ extern "C" uint8_t mix, r, g, b, alpha; }; + struct BNInteractionHandlerCallbacks + { + void* context; + void (*showPlainTextReport)(void* ctxt, BNBinaryView* view, const char* title, const char* contents); + void (*showMarkdownReport)(void* ctxt, BNBinaryView* view, const char* title, const char* contents, + const char* plaintext); + void (*showHTMLReport)(void* ctxt, BNBinaryView* view, const char* title, const char* contents, + const char* plaintext); + bool (*getTextLineInput)(void* ctxt, char** result, const char* prompt, const char* title); + bool (*getIntegerInput)(void* ctxt, int64_t* result, const char* prompt, const char* title); + bool (*getAddressInput)(void* ctxt, uint64_t* result, const char* prompt, const char* title, + BNBinaryView* view, uint64_t currentAddr); + bool (*getChoiceInput)(void* ctxt, size_t* result, const char* prompt, const char* title, + const char** choices, size_t count); + bool (*getOpenFileNameInput)(void* ctxt, char** result, const char* prompt, const char* ext); + bool (*getSaveFileNameInput)(void* ctxt, char** result, const char* prompt, const char* ext, + const char* defaultName); + bool (*getDirectoryNameInput)(void* ctxt, char** result, const char* prompt, const char* defaultName); + }; + BINARYNINJACOREAPI char* BNAllocString(const char* contents); BINARYNINJACOREAPI void BNFreeString(char* str); @@ -2030,6 +2050,25 @@ extern "C" BINARYNINJACOREAPI void BNCancelBackgroundTask(BNBackgroundTask* task); BINARYNINJACOREAPI bool BNIsBackgroundTaskFinished(BNBackgroundTask* task); + // Interaction APIs + BINARYNINJACOREAPI void BNRegisterInteractionHandler(BNInteractionHandlerCallbacks* callbacks); + BINARYNINJACOREAPI char* BNMarkdownToHTML(const char* contents); + BINARYNINJACOREAPI void BNShowPlainTextReport(BNBinaryView* view, const char* title, const char* contents); + BINARYNINJACOREAPI void BNShowMarkdownReport(BNBinaryView* view, const char* title, const char* contents, + const char* plaintext); + BINARYNINJACOREAPI void BNShowHTMLReport(BNBinaryView* view, const char* title, const char* contents, + const char* plaintext); + BINARYNINJACOREAPI bool BNGetTextLineInput(char** result, const char* prompt, const char* title); + BINARYNINJACOREAPI bool BNGetIntegerInput(int64_t* result, const char* prompt, const char* title); + BINARYNINJACOREAPI bool BNGetAddressInput(uint64_t* result, const char* prompt, const char* title, + BNBinaryView* view, uint64_t currentAddr); + BINARYNINJACOREAPI bool BNGetChoiceInput(size_t* result, const char* prompt, const char* title, + const char** choices, size_t count); + BINARYNINJACOREAPI bool BNGetOpenFileNameInput(char** result, const char* prompt, const char* ext); + BINARYNINJACOREAPI bool BNGetSaveFileNameInput(char** result, const char* prompt, const char* ext, + const char* defaultName); + BINARYNINJACOREAPI bool BNGetDirectoryNameInput(char** result, const char* prompt, const char* defaultName); + #ifdef __cplusplus } #endif diff --git a/binaryview.cpp b/binaryview.cpp index 0a7f23ce..863d57b2 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1480,6 +1480,39 @@ void BinaryView::Reanalyze() } +void BinaryView::ShowPlainTextReport(const string& title, const string& contents) +{ + BNShowPlainTextReport(m_object, title.c_str(), contents.c_str()); +} + + +void BinaryView::ShowMarkdownReport(const string& title, const string& contents, const string& plainText) +{ + BNShowMarkdownReport(m_object, title.c_str(), contents.c_str(), plainText.c_str()); +} + + +void BinaryView::ShowHTMLReport(const string& title, const string& contents, const string& plainText) +{ + BNShowHTMLReport(m_object, title.c_str(), contents.c_str(), plainText.c_str()); +} + + +bool BinaryView::GetAddressInput(uint64_t& result, const string& prompt, const string& title) +{ + uint64_t currentAddress = 0; + if (m_file) + currentAddress = m_file->GetCurrentOffset(); + return BNGetAddressInput(&result, prompt.c_str(), title.c_str(), m_object, currentAddress); +} + + +bool BinaryView::GetAddressInput(uint64_t& result, const string& prompt, const string& title, uint64_t currentAddress) +{ + return BNGetAddressInput(&result, prompt.c_str(), title.c_str(), m_object, currentAddress); +} + + BinaryData::BinaryData(FileMetadata* file): BinaryView(BNCreateBinaryDataView(file->GetObject())) { } diff --git a/interaction.cpp b/interaction.cpp new file mode 100644 index 00000000..f7763679 --- /dev/null +++ b/interaction.cpp @@ -0,0 +1,286 @@ +#include +#include +#include "binaryninjaapi.h" + +using namespace std; +using namespace BinaryNinja; + + +void InteractionHandler::ShowMarkdownReport(Ref view, const string& title, const string& contents, + const string& plainText) +{ + ShowHTMLReport(view, title, MarkdownToHTML(contents), plainText); +} + + +void InteractionHandler::ShowHTMLReport(Ref view, const string& title, const string&, + const string& plainText) +{ + if (plainText.size() != 0) + ShowPlainTextReport(view, title, plainText); +} + + +bool InteractionHandler::GetIntegerInput(int64_t& result, const string& prompt, const string& title) +{ + string input; + + while (true) + { + string input; + if (!GetTextLineInput(input, prompt, title)) + return false; + if (input.size() == 0) + return false; + + errno = 0; + result = strtoll(input.c_str(), nullptr, 0); + if (errno != 0) + { + errno = 0; + result = strtoull(input.c_str(), nullptr, 0); + if (errno != 0) + continue; + } + + return true; + } +} + + +bool InteractionHandler::GetAddressInput(uint64_t& result, const string& prompt, const string& title, + Ref, uint64_t) +{ + int64_t value; + if (!GetIntegerInput(value, prompt, title)) + return false; + result = (uint64_t)value; + return true; +} + + +bool InteractionHandler::GetOpenFileNameInput(string& result, const string& prompt, const string&) +{ + return GetTextLineInput(result, prompt, "Open File"); +} + + +bool InteractionHandler::GetSaveFileNameInput(string& result, const string& prompt, const string&, const string&) +{ + return GetTextLineInput(result, prompt, "Save File"); +} + + +bool InteractionHandler::GetDirectoryNameInput(string& result, const string& prompt, const string&) +{ + return GetTextLineInput(result, prompt, "Select Directory"); +} + + +static void ShowPlainTextReportCallback(void* ctxt, BNBinaryView* view, const char* title, const char* contents) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + handler->ShowPlainTextReport(view ? new BinaryView(BNNewViewReference(view)) : nullptr, title, contents); +} + + +static void ShowMarkdownReportCallback(void* ctxt, BNBinaryView* view, const char* title, const char* contents, + const char* plaintext) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + handler->ShowMarkdownReport(view ? new BinaryView(BNNewViewReference(view)) : nullptr, title, contents, plaintext); +} + + +static void ShowHTMLReportCallback(void* ctxt, BNBinaryView* view, const char* title, const char* contents, + const char* plaintext) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + handler->ShowHTMLReport(view ? new BinaryView(BNNewViewReference(view)) : nullptr, title, contents, plaintext); +} + + +static bool GetTextLineInputCallback(void* ctxt, char** result, const char* prompt, const char* title) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + string value; + if (!handler->GetTextLineInput(value, prompt, title)) + return false; + *result = BNAllocString(value.c_str()); + return true; +} + + +static bool GetIntegerInputCallback(void* ctxt, int64_t* result, const char* prompt, const char* title) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + return handler->GetIntegerInput(*result, prompt, title); +} + + +static bool GetAddressInputCallback(void* ctxt, uint64_t* result, const char* prompt, const char* title, + BNBinaryView* view, uint64_t currentAddr) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + return handler->GetAddressInput(*result, prompt, title, view ? new BinaryView(BNNewViewReference(view)) : nullptr, + currentAddr); +} + + +static bool GetChoiceInputCallback(void* ctxt, size_t* result, const char* prompt, const char* title, + const char** choices, size_t count) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + vector choiceStrs; + for (size_t i = 0; i < count; i++) + choiceStrs.push_back(choices[i]); + return handler->GetChoiceInput(*result, prompt, title, choiceStrs); +} + + +static bool GetOpenFileNameInputCallback(void* ctxt, char** result, const char* prompt, const char* ext) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + string value; + if (!handler->GetOpenFileNameInput(value, prompt, ext)) + return false; + *result = BNAllocString(value.c_str()); + return true; +} + + +static bool GetSaveFileNameInputCallback(void* ctxt, char** result, const char* prompt, const char* ext, + const char* defaultName) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + string value; + if (!handler->GetSaveFileNameInput(value, prompt, ext, defaultName)) + return false; + *result = BNAllocString(value.c_str()); + return true; +} + + +static bool GetDirectoryNameInputCallback(void* ctxt, char** result, const char* prompt, const char* defaultName) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + string value; + if (!handler->GetDirectoryNameInput(value, prompt, defaultName)) + return false; + *result = BNAllocString(value.c_str()); + return true; +} + + +void BinaryNinja::RegisterInteractionHandler(InteractionHandler* handler) +{ + BNInteractionHandlerCallbacks cb; + cb.context = handler; + cb.showPlainTextReport = ShowPlainTextReportCallback; + cb.showMarkdownReport = ShowMarkdownReportCallback; + cb.showHTMLReport = ShowHTMLReportCallback; + cb.getTextLineInput = GetTextLineInputCallback; + cb.getIntegerInput = GetIntegerInputCallback; + cb.getAddressInput = GetAddressInputCallback; + cb.getChoiceInput = GetChoiceInputCallback; + cb.getOpenFileNameInput = GetOpenFileNameInputCallback; + cb.getSaveFileNameInput = GetSaveFileNameInputCallback; + cb.getDirectoryNameInput = GetDirectoryNameInputCallback; + BNRegisterInteractionHandler(&cb); +} + + +string BinaryNinja::MarkdownToHTML(const string& contents) +{ + char* str = BNMarkdownToHTML(contents.c_str()); + string result = str; + BNFreeString(str); + return result; +} + + +void BinaryNinja::ShowPlainTextReport(const string& title, const string& contents) +{ + BNShowPlainTextReport(nullptr, title.c_str(), contents.c_str()); +} + + +void BinaryNinja::ShowMarkdownReport(const string& title, const string& contents, const string& plainText) +{ + BNShowMarkdownReport(nullptr, title.c_str(), contents.c_str(), plainText.c_str()); +} + + +void BinaryNinja::ShowHTMLReport(const string& title, const string& contents, const string& plainText) +{ + BNShowHTMLReport(nullptr, title.c_str(), contents.c_str(), plainText.c_str()); +} + + +bool BinaryNinja::GetTextLineInput(string& result, const string& prompt, const string& title) +{ + char* value = nullptr; + if (!BNGetTextLineInput(&value, prompt.c_str(), title.c_str())) + return false; + result = value; + BNFreeString(value); + return true; +} + + +bool BinaryNinja::GetIntegerInput(int64_t& result, const string& prompt, const string& title) +{ + return BNGetIntegerInput(&result, prompt.c_str(), title.c_str()); +} + + +bool BinaryNinja::GetAddressInput(uint64_t& result, const string& prompt, const string& title) +{ + return BNGetAddressInput(&result, prompt.c_str(), title.c_str(), nullptr, 0); +} + + +bool BinaryNinja::GetChoiceInput(size_t& idx, const string& prompt, const string& title, + const vector& choices) +{ + const char** choiceStrs = new const char*[choices.size()]; + for (size_t i = 0; i < choices.size(); i++) + choiceStrs[i] = choices[i].c_str(); + bool ok = BNGetChoiceInput(&idx, prompt.c_str(), title.c_str(), choiceStrs, choices.size()); + delete[] choiceStrs; + return ok; +} + + +bool BinaryNinja::GetOpenFileNameInput(string& result, const string& prompt, const string& ext) +{ + char* value = nullptr; + if (!BNGetOpenFileNameInput(&value, prompt.c_str(), ext.c_str())) + return false; + result = value; + BNFreeString(value); + return true; +} + + +bool BinaryNinja::GetSaveFileNameInput(string& result, const string& prompt, const string& ext, + const string& defaultName) +{ + char* value = nullptr; + if (!BNGetSaveFileNameInput(&value, prompt.c_str(), ext.c_str(), defaultName.c_str())) + return false; + result = value; + BNFreeString(value); + return true; +} + + +bool BinaryNinja::GetDirectoryNameInput(string& result, const string& prompt, const string& defaultName) +{ + char* value = nullptr; + if (!BNGetDirectoryNameInput(&value, prompt.c_str(), defaultName.c_str())) + return false; + result = value; + BNFreeString(value); + return true; +} diff --git a/python/__init__.py b/python/__init__.py index 6abbdfa6..854de5c7 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -3293,6 +3293,23 @@ class BinaryView(object): """ core.BNReanalyzeAllFunctions(self.handle) + def show_plain_text_report(self, title, contents): + core.BNShowPlainTextReport(self.handle, title, contents) + + def show_markdown_report(self, title, contents, plaintext = ""): + core.BNShowMarkdownReport(self.handle, title, contents, plaintext) + + def show_html_report(self, title, contents, plaintext = ""): + core.BNShowHTMLReport(self.handle, title, contents, plaintext) + + def get_address_input(self, prompt, title, current_address = None): + if current_address is None: + current_address = self.file.offset + value = ctypes.c_ulonglong() + if not core.BNGetAddressInput(value, prompt, title, self.handle, current_address): + return None + return value.value + def __setattr__(self, name, value): try: object.__setattr__(self,name,value) @@ -10059,6 +10076,172 @@ class BackgroundTaskThread(BackgroundTask): def join(self): self.thread.join() +class InteractionHandler(object): + _interaction_handler = None + + def __init__(self): + self._cb = core.BNInteractionHandlerCallbacks() + self._cb.context = 0 + self._cb.showPlainTextReport = self._cb.showPlainTextReport.__class__(self._show_plain_text_report) + self._cb.showMarkdownReport = self._cb.showMarkdownReport.__class__(self._show_markdown_report) + self._cb.showHTMLReport = self._cb.showHTMLReport.__class__(self._show_html_report) + self._cb.getTextLineInput = self._cb.getTextLineInput.__class__(self._get_text_line_input) + self._cb.getIntegerInput = self._cb.getIntegerInput.__class__(self._get_int_input) + self._cb.getAddressInput = self._cb.getAddressInput.__class__(self._get_address_input) + self._cb.getChoiceInput = self._cb.getChoiceInput.__class__(self._get_choice_input) + self._cb.getOpenFileNameInput = self._cb.getOpenFileNameInput.__class__(self._get_open_filename_input) + self._cb.getSaveFileNameInput = self._cb.getSaveFileNameInput.__class__(self._get_save_filename_input) + self._cb.getDirectoryNameInput = self._cb.getDirectoryNameInput.__class__(self._get_directory_name_input) + + def register(self): + self.__class__._interaction_handler = self + core.BNRegisterInteractionHandler(self._cb) + + def _show_plain_text_report(self, ctxt, view, title, contents): + try: + if view: + view = BinaryView(None, handle = core.BNNewViewReference(view)) + else: + view = None + self.show_plain_text_report(view, title, contents) + except: + log_error(traceback.format_exc()) + + def _show_markdown_report(self, ctxt, view, title, contents, plaintext): + try: + if view: + view = BinaryView(None, handle = core.BNNewViewReference(view)) + else: + view = None + self.show_markdown_report(view, title, contents, plaintext) + except: + log_error(traceback.format_exc()) + + def _show_html_report(self, ctxt, view, title, contents, plaintext): + try: + if view: + view = BinaryView(None, handle = core.BNNewViewReference(view)) + else: + view = None + self.show_html_report(view, title, contents, plaintext) + except: + log_error(traceback.format_exc()) + + def _get_text_line_input(self, ctxt, result, prompt, title): + try: + value = self.get_text_line_input(prompt, title) + if value is None: + return False + result[0] = core.BNAllocString(str(value)) + return True + except: + log_error(traceback.format_exc()) + + def _get_int_input(self, ctxt, result, prompt, title): + try: + value = self.get_int_input(prompt, title) + if value is None: + return False + result[0] = value + return True + except: + log_error(traceback.format_exc()) + + def _get_address_input(self, ctxt, result, prompt, title, view, current_address): + try: + if view: + view = BinaryView(None, handle = core.BNNewViewReference(view)) + else: + view = None + value = self.get_address_input(prompt, title, view, current_address) + if value is None: + return False + result[0] = value + return True + except: + log_error(traceback.format_exc()) + + def _get_choice_input(self, ctxt, result, prompt, title, choice_buf, count): + try: + choices = [] + for i in xrange(0, count): + choices.append(choice_buf[i]) + value = self.get_choice_input(prompt, title, choices) + if value is None: + return False + result[0] = value + return True + except: + log_error(traceback.format_exc()) + + def _get_open_filename_input(self, ctxt, result, prompt, ext): + try: + value = self.get_open_filename_input(prompt, ext) + if value is None: + return False + result[0] = core.BNAllocString(str(value)) + return True + except: + log_error(traceback.format_exc()) + + def _get_save_filename_input(self, ctxt, result, prompt, ext, default_name): + try: + value = self.get_save_filename_input(prompt, ext, default_name) + if value is None: + return False + result[0] = core.BNAllocString(str(value)) + return True + except: + log_error(traceback.format_exc()) + + def _get_directory_name_input(self, ctxt, result, prompt, default_name): + try: + value = self.get_directory_name_input(prompt, default_name) + if value is None: + return False + result[0] = core.BNAllocString(str(value)) + return True + except: + log_error(traceback.format_exc()) + + def show_plain_text_report(self, view, title, contents): + pass + + def show_markdown_report(self, view, title, contents, plaintext): + self.show_html_report(view, title, markdown_to_html(contents), plaintext) + + def show_html_report(self, view, title, contents, plaintext): + if len(plaintext) != 0: + self.show_plain_text_report(view, title, plaintext) + + def get_text_line_input(self, prompt, title): + return None + + def get_int_input(self, prompt, title): + while True: + text = self.get_text_line_input(prompt, title) + if len(text) == 0: + return False + try: + return int(text) + except: + continue + + def get_address_input(self, prompt, title, view, current_address): + return get_int_input(prompt, title) + + def get_choice_input(self, prompt, title, choices): + return None + + def get_open_filename_input(self, prompt, ext): + return get_text_line_input(prompt, "Open File") + + def get_save_filename_input(self, prompt, ext, default_name): + return get_text_line_input(title, "Save File") + + def get_directory_name_input(self, prompt, default_name): + return get_text_line_input(title, "Select Directory") + def LLIL_TEMP(n): return n | 0x80000000 @@ -10374,6 +10557,71 @@ def get_worker_thread_count(): def set_worker_thread_count(count): core.BNSetWorkerThreadCount(count) +def markdown_to_html(contents): + return core.BNMarkdownToHTML(contents) + +def show_plain_text_report(title, contents): + core.BNShowPlainTextReport(None, title, contents) + +def show_markdown_report(title, contents, plaintext = ""): + core.BNShowMarkdownReport(None, title, contents, plaintext) + +def show_html_report(title, contents, plaintext = ""): + core.BNShowHTMLReport(None, title, contents, plaintext) + +def get_text_line_input(prompt, title): + value = ctypes.c_char_p() + if not core.BNGetTextLineInput(value, prompt, title): + return None + result = value.value + core.BNFreeString(ctypes.cast(value, ctypes.POINTER(ctypes.c_byte))) + return result + +def get_int_input(prompt, title): + value = ctypes.c_longlong() + if not core.BNGetIntegerInput(value, prompt, title): + return None + return value.value + +def get_address_input(prompt, title): + value = ctypes.c_ulonglong() + if not core.BNGetAddressInput(value, prompt, title, None, 0): + return None + return value.value + +def get_choice_input(prompt, title, choices): + choice_buf = (ctypes.c_char_p * len(choices))() + for i in xrange(0, len(choices)): + choice_buf[i] = str(choices[i]) + value = ctypes.c_ulonglong() + if not core.BNGetChoiceInput(value, prompt, title, choice_buf, len(choices)): + return None + return value.value + +def get_open_filename_input(prompt, ext = ""): + value = ctypes.c_char_p() + if not core.BNGetOpenFileNameInput(value, prompt, ext): + return None + result = value.value + core.BNFreeString(ctypes.cast(value, ctypes.POINTER(ctypes.c_byte))) + return result + +def get_save_filename_input(prompt, ext = "", default_name = ""): + value = ctypes.c_char_p() + if not core.BNGetSaveFileNameInput(value, prompt, ext, default_name): + return None + result = value.value + core.BNFreeString(ctypes.cast(value, ctypes.POINTER(ctypes.c_byte))) + return result + +def get_directory_name_input(prompt, default_name = ""): + value = ctypes.c_char_p() + if not core.BNGetDirectoryNameInput(value, prompt, default_name): + return None + result = value.value + core.BNFreeString(ctypes.cast(value, ctypes.POINTER(ctypes.c_byte))) + return result + bundled_plugin_path = core.BNGetBundledPluginDirectory() user_plugin_path = core.BNGetUserPluginDirectory() -- cgit v1.3.1 From 91c9990b0f51864f60e71d4004cfb2eb75154eb8 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Mon, 19 Sep 2016 23:57:39 -0400 Subject: Add API for showing a message box in the UI --- binaryninjaapi.h | 6 ++++++ binaryninjacore.h | 27 +++++++++++++++++++++++++++ interaction.cpp | 16 ++++++++++++++++ python/__init__.py | 13 +++++++++++++ 4 files changed, 62 insertions(+) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 720a8eb6..7e496591 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -402,6 +402,9 @@ namespace BinaryNinja const std::string& defaultName = ""); bool GetDirectoryNameInput(std::string& result, const std::string& prompt, const std::string& defaultName = ""); + BNMessageBoxButtonResult ShowMessageBox(const std::string& title, const std::string& text, + BNMessageBoxButtonSet buttons = OKButtonSet, BNMessageBoxIcon icon = InformationIcon); + class DataBuffer { BNDataBuffer* m_buffer; @@ -2328,5 +2331,8 @@ namespace BinaryNinja const std::string& ext = "", const std::string& defaultName = ""); virtual bool GetDirectoryNameInput(std::string& result, const std::string& prompt, const std::string& defaultName = ""); + + virtual BNMessageBoxButtonResult ShowMessageBox(const std::string& title, const std::string& text, + BNMessageBoxButtonSet buttons = OKButtonSet, BNMessageBoxIcon icon = InformationIcon) = 0; }; } diff --git a/binaryninjacore.h b/binaryninjacore.h index 084fd34d..6339b1c3 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1050,6 +1050,29 @@ extern "C" uint8_t mix, r, g, b, alpha; }; + enum BNMessageBoxIcon + { + InformationIcon, + QuestionIcon, + WarningIcon, + ErrorIcon + }; + + enum BNMessageBoxButtonSet + { + OKButtonSet, + YesNoButtonSet, + YesNoCancelButtonSet + }; + + enum BNMessageBoxButtonResult + { + NoButton = 0, + YesButton = 1, + OKButton = 2, + CancelButton = 3 + }; + struct BNInteractionHandlerCallbacks { void* context; @@ -1068,6 +1091,8 @@ extern "C" bool (*getSaveFileNameInput)(void* ctxt, char** result, const char* prompt, const char* ext, const char* defaultName); bool (*getDirectoryNameInput)(void* ctxt, char** result, const char* prompt, const char* defaultName); + BNMessageBoxButtonResult (*showMessageBox)(void* ctxt, const char* title, const char* text, + BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon); }; struct BNObjectDestructionCallbacks @@ -2082,6 +2107,8 @@ extern "C" BINARYNINJACOREAPI bool BNGetSaveFileNameInput(char** result, const char* prompt, const char* ext, const char* defaultName); BINARYNINJACOREAPI bool BNGetDirectoryNameInput(char** result, const char* prompt, const char* defaultName); + BINARYNINJACOREAPI BNMessageBoxButtonResult BNShowMessageBox(const char* title, const char* text, + BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon); #ifdef __cplusplus } diff --git a/interaction.cpp b/interaction.cpp index f7763679..432859d9 100644 --- a/interaction.cpp +++ b/interaction.cpp @@ -172,6 +172,14 @@ static bool GetDirectoryNameInputCallback(void* ctxt, char** result, const char* } +static BNMessageBoxButtonResult ShowMessageBoxCallback(void* ctxt, const char* title, const char* text, + BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + return handler->ShowMessageBox(title, text, buttons, icon); +} + + void BinaryNinja::RegisterInteractionHandler(InteractionHandler* handler) { BNInteractionHandlerCallbacks cb; @@ -186,6 +194,7 @@ void BinaryNinja::RegisterInteractionHandler(InteractionHandler* handler) cb.getOpenFileNameInput = GetOpenFileNameInputCallback; cb.getSaveFileNameInput = GetSaveFileNameInputCallback; cb.getDirectoryNameInput = GetDirectoryNameInputCallback; + cb.showMessageBox = ShowMessageBoxCallback; BNRegisterInteractionHandler(&cb); } @@ -284,3 +293,10 @@ bool BinaryNinja::GetDirectoryNameInput(string& result, const string& prompt, co BNFreeString(value); return true; } + + +BNMessageBoxButtonResult BinaryNinja::ShowMessageBox(const string& title, const string& text, + BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon) +{ + return BNShowMessageBox(title.c_str(), text.c_str(), buttons, icon); +} diff --git a/python/__init__.py b/python/__init__.py index 23059068..c8880648 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -10193,6 +10193,7 @@ class InteractionHandler(object): self._cb.getOpenFileNameInput = self._cb.getOpenFileNameInput.__class__(self._get_open_filename_input) self._cb.getSaveFileNameInput = self._cb.getSaveFileNameInput.__class__(self._get_save_filename_input) self._cb.getDirectoryNameInput = self._cb.getDirectoryNameInput.__class__(self._get_directory_name_input) + self._cb.showMessageBox = self._cb.showMessageBox.__class__(self._show_message_box) def register(self): self.__class__._interaction_handler = self @@ -10305,6 +10306,12 @@ class InteractionHandler(object): except: log_error(traceback.format_exc()) + def _show_message_box(self, ctxt, title, text, buttons, icon): + try: + return self.show_message_box(title, text, buttons, icon) + except: + log_error(traceback.format_exc()) + def show_plain_text_report(self, view, title, contents): pass @@ -10343,6 +10350,9 @@ class InteractionHandler(object): def get_directory_name_input(self, prompt, default_name): return get_text_line_input(title, "Select Directory") + def show_message_box(self, title, text, buttons, icon): + return CancelButton + class _DestructionCallbackHandler: def __init__(self): self._cb = core.BNObjectDestructionCallbacks() @@ -10743,6 +10753,9 @@ def get_directory_name_input(prompt, default_name = ""): core.BNFreeString(ctypes.cast(value, ctypes.POINTER(ctypes.c_byte))) return result +def show_message_box(title, text, buttons = core.OKButtonSet, icon = core.InformationIcon): + return core.BNShowMessageBox(title, text, buttons, icon) + bundled_plugin_path = core.BNGetBundledPluginDirectory() user_plugin_path = core.BNGetUserPluginDirectory() -- cgit v1.3.1 From ae7f75fd33a49a25f5d8d735ae876e2c4ba55339 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Thu, 22 Sep 2016 00:20:13 -0400 Subject: Adding API to create simple dialogs with multiple input fields --- binaryninjaapi.h | 30 +++++++ binaryninjacore.h | 33 +++++++ interaction.cpp | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++++ python/__init__.py | 227 ++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 544 insertions(+), 1 deletion(-) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 7e496591..a62b4239 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -276,6 +276,7 @@ namespace BinaryNinja class MainThreadAction; class MainThreadActionHandler; class InteractionHandler; + struct FormInputField; /*! Logs to the error console with the given BNLogLevel. @@ -401,6 +402,7 @@ namespace BinaryNinja bool GetSaveFileNameInput(std::string& result, const std::string& prompt, const std::string& ext = "", const std::string& defaultName = ""); bool GetDirectoryNameInput(std::string& result, const std::string& prompt, const std::string& defaultName = ""); + bool GetFormInput(std::vector& fields, const std::string& title); BNMessageBoxButtonResult ShowMessageBox(const std::string& title, const std::string& text, BNMessageBoxButtonSet buttons = OKButtonSet, BNMessageBoxIcon icon = InformationIcon); @@ -2311,6 +2313,33 @@ namespace BinaryNinja static std::vector> GetRunningTasks(); }; + struct FormInputField + { + BNFormInputFieldType type; + std::string prompt; + Ref view; // For AddressFormField + uint64_t currentAddress; // For AddressFormField + std::vector choices; // For ChoiceFormField + std::string ext; // For OpenFileNameFormField, SaveFileNameFormField + std::string defaultName; // For SaveFileNameFormField + int64_t intResult; + uint64_t addressResult; + std::string stringResult; + size_t indexResult; + + static FormInputField Label(const std::string& text); + static FormInputField Separator(); + static FormInputField TextLine(const std::string& prompt); + static FormInputField MultilineText(const std::string& prompt); + static FormInputField Integer(const std::string& prompt); + static FormInputField Address(const std::string& prompt, BinaryView* view = nullptr, uint64_t currentAddress = 0); + static FormInputField Choice(const std::string& prompt, const std::vector& choices); + static FormInputField OpenFileName(const std::string& prompt, const std::string& ext); + static FormInputField SaveFileName(const std::string& prompt, const std::string& ext, + const std::string& defaultName = ""); + static FormInputField DirectoryName(const std::string& prompt, const std::string& defaultName = ""); + }; + class InteractionHandler { public: @@ -2331,6 +2360,7 @@ namespace BinaryNinja const std::string& ext = "", const std::string& defaultName = ""); virtual bool GetDirectoryNameInput(std::string& result, const std::string& prompt, const std::string& defaultName = ""); + virtual bool GetFormInput(std::vector& fields, const std::string& title) = 0; virtual BNMessageBoxButtonResult ShowMessageBox(const std::string& title, const std::string& text, BNMessageBoxButtonSet buttons = OKButtonSet, BNMessageBoxIcon icon = InformationIcon) = 0; diff --git a/binaryninjacore.h b/binaryninjacore.h index 6339b1c3..b6d2f7ed 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1073,6 +1073,36 @@ extern "C" CancelButton = 3 }; + enum BNFormInputFieldType + { + LabelFormField, + SeparatorFormField, + TextLineFormField, + MultilineTextFormField, + IntegerFormField, + AddressFormField, + ChoiceFormField, + OpenFileNameFormField, + SaveFileNameFormField, + DirectoryNameFormField + }; + + struct BNFormInputField + { + BNFormInputFieldType type; + const char* prompt; + BNBinaryView* view; // For AddressFormField + uint64_t currentAddress; // For AddressFormField + const char** choices; // For ChoiceFormField + size_t count; // For ChoiceFormField + const char* ext; // For OpenFileNameFormField, SaveFileNameFormField + const char* defaultName; // For SaveFileNameFormField + int64_t intResult; + uint64_t addressResult; + char* stringResult; + size_t indexResult; + }; + struct BNInteractionHandlerCallbacks { void* context; @@ -1091,6 +1121,7 @@ extern "C" bool (*getSaveFileNameInput)(void* ctxt, char** result, const char* prompt, const char* ext, const char* defaultName); bool (*getDirectoryNameInput)(void* ctxt, char** result, const char* prompt, const char* defaultName); + bool (*getFormInput)(void* ctxt, BNFormInputField* fields, size_t count, const char* title); BNMessageBoxButtonResult (*showMessageBox)(void* ctxt, const char* title, const char* text, BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon); }; @@ -2107,6 +2138,8 @@ extern "C" BINARYNINJACOREAPI bool BNGetSaveFileNameInput(char** result, const char* prompt, const char* ext, const char* defaultName); BINARYNINJACOREAPI bool BNGetDirectoryNameInput(char** result, const char* prompt, const char* defaultName); + BINARYNINJACOREAPI bool BNGetFormInput(BNFormInputField* fields, size_t count, const char* title); + BINARYNINJACOREAPI void BNFreeFormInputResults(BNFormInputField* fields, size_t count); BINARYNINJACOREAPI BNMessageBoxButtonResult BNShowMessageBox(const char* title, const char* text, BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon); diff --git a/interaction.cpp b/interaction.cpp index 432859d9..fb4eb6d4 100644 --- a/interaction.cpp +++ b/interaction.cpp @@ -6,6 +6,102 @@ using namespace std; using namespace BinaryNinja; +FormInputField FormInputField::Label(const string& text) +{ + FormInputField result; + result.type = LabelFormField; + result.prompt = text; + return result; +} + + +FormInputField FormInputField::Separator() +{ + FormInputField result; + result.type = SeparatorFormField; + return result; +} + + +FormInputField FormInputField::TextLine(const string& prompt) +{ + FormInputField result; + result.type = TextLineFormField; + result.prompt = prompt; + return result; +} + + +FormInputField FormInputField::MultilineText(const string& prompt) +{ + FormInputField result; + result.type = MultilineTextFormField; + result.prompt = prompt; + return result; +} + + +FormInputField FormInputField::Integer(const string& prompt) +{ + FormInputField result; + result.type = IntegerFormField; + result.prompt = prompt; + return result; +} + + +FormInputField FormInputField::Address(const std::string& prompt, BinaryView* view, uint64_t currentAddress) +{ + FormInputField result; + result.type = AddressFormField; + result.prompt = prompt; + result.view = view; + result.currentAddress = currentAddress; + return result; +} + + +FormInputField FormInputField::Choice(const string& prompt, const vector& choices) +{ + FormInputField result; + result.type = ChoiceFormField; + result.prompt = prompt; + result.choices = choices; + return result; +} + + +FormInputField FormInputField::OpenFileName(const string& prompt, const string& ext) +{ + FormInputField result; + result.type = OpenFileNameFormField; + result.prompt = prompt; + result.ext = ext; + return result; +} + + +FormInputField FormInputField::SaveFileName(const string& prompt, const string& ext, const string& defaultName) +{ + FormInputField result; + result.type = SaveFileNameFormField; + result.prompt = prompt; + result.ext = ext; + result.defaultName = defaultName; + return result; +} + + +FormInputField FormInputField::DirectoryName(const string& prompt, const string& defaultName) +{ + FormInputField result; + result.type = DirectoryNameFormField; + result.prompt = prompt; + result.defaultName = defaultName; + return result; +} + + void InteractionHandler::ShowMarkdownReport(Ref view, const string& title, const string& contents, const string& plainText) { @@ -172,6 +268,85 @@ static bool GetDirectoryNameInputCallback(void* ctxt, char** result, const char* } +static bool GetFormInputCallback(void* ctxt, BNFormInputField* fieldBuf, size_t count, const char* title) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + + // Convert list of fields from core structure to API structure + vector fields; + for (size_t i = 0; i < count; i++) + { + vector choices; + switch (fieldBuf[i].type) + { + case SeparatorFormField: + fields.push_back(FormInputField::Separator()); + break; + case TextLineFormField: + fields.push_back(FormInputField::TextLine(fieldBuf[i].prompt)); + break; + case MultilineTextFormField: + fields.push_back(FormInputField::MultilineText(fieldBuf[i].prompt)); + break; + case IntegerFormField: + fields.push_back(FormInputField::Integer(fieldBuf[i].prompt)); + break; + case AddressFormField: + fields.push_back(FormInputField::Address(fieldBuf[i].prompt, fieldBuf[i].view ? + new BinaryView(BNNewViewReference(fieldBuf[i].view)) : nullptr, fieldBuf[i].currentAddress)); + break; + case ChoiceFormField: + for (size_t j = 0; j < fieldBuf[i].count; j++) + choices.push_back(fieldBuf[i].choices[j]); + fields.push_back(FormInputField::Choice(fieldBuf[i].prompt, choices)); + break; + case OpenFileNameFormField: + fields.push_back(FormInputField::OpenFileName(fieldBuf[i].prompt, fieldBuf[i].ext)); + break; + case SaveFileNameFormField: + fields.push_back(FormInputField::SaveFileName(fieldBuf[i].prompt, fieldBuf[i].ext, fieldBuf[i].defaultName)); + break; + case DirectoryNameFormField: + fields.push_back(FormInputField::DirectoryName(fieldBuf[i].prompt, fieldBuf[i].defaultName)); + break; + default: + fields.push_back(FormInputField::Label(fieldBuf[i].prompt)); + break; + } + } + + if (!handler->GetFormInput(fields, title)) + return false; + + // Place results into core structure + for (size_t i = 0; i < count; i++) + { + switch (fieldBuf[i].type) + { + case TextLineFormField: + case MultilineTextFormField: + case OpenFileNameFormField: + case SaveFileNameFormField: + case DirectoryNameFormField: + fieldBuf[i].stringResult = BNAllocString(fields[i].stringResult.c_str()); + break; + case IntegerFormField: + fieldBuf[i].intResult = fields[i].intResult; + break; + case AddressFormField: + fieldBuf[i].addressResult = fields[i].addressResult; + break; + case ChoiceFormField: + fieldBuf[i].indexResult = fields[i].indexResult; + break; + default: + break; + } + } + return true; +} + + static BNMessageBoxButtonResult ShowMessageBoxCallback(void* ctxt, const char* title, const char* text, BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon) { @@ -194,6 +369,7 @@ void BinaryNinja::RegisterInteractionHandler(InteractionHandler* handler) cb.getOpenFileNameInput = GetOpenFileNameInputCallback; cb.getSaveFileNameInput = GetSaveFileNameInputCallback; cb.getDirectoryNameInput = GetDirectoryNameInputCallback; + cb.getFormInput = GetFormInputCallback; cb.showMessageBox = ShowMessageBoxCallback; BNRegisterInteractionHandler(&cb); } @@ -295,6 +471,85 @@ bool BinaryNinja::GetDirectoryNameInput(string& result, const string& prompt, co } +bool BinaryNinja::GetFormInput(vector& fields, const string& title) +{ + // Construct field list in core format + BNFormInputField* fieldBuf = new BNFormInputField[fields.size()]; + for (size_t i = 0; i < fields.size(); i++) + { + fieldBuf[i].type = fields[i].type; + fieldBuf[i].prompt = fields[i].prompt.c_str(); + switch (fields[i].type) + { + case AddressFormField: + fieldBuf[i].view = fields[i].view ? fields[i].view->GetObject() : nullptr; + fieldBuf[i].currentAddress = fields[i].currentAddress; + break; + case ChoiceFormField: + fieldBuf[i].choices = new const char*[fields[i].choices.size()]; + fieldBuf[i].count = fields[i].choices.size(); + for (size_t j = 0; j < fields[i].choices.size(); j++) + fieldBuf[i].choices[j] = fields[i].choices[j].c_str(); + break; + case OpenFileNameFormField: + fieldBuf[i].ext = fields[i].ext.c_str(); + break; + case SaveFileNameFormField: + fieldBuf[i].ext = fields[i].ext.c_str(); + fieldBuf[i].defaultName = fields[i].defaultName.c_str(); + break; + case DirectoryNameFormField: + fieldBuf[i].defaultName = fields[i].defaultName.c_str(); + break; + default: + break; + } + } + + bool ok = BNGetFormInput(fieldBuf, fields.size(), title.c_str()); + + // Free any memory used by field descriptions + for (size_t i = 0; i < fields.size(); i++) + { + if (fields[i].type == ChoiceFormField) + delete[] fieldBuf[i].choices; + } + + // If user cancelled, there are no results + if (!ok) + return false; + + // Copy results to API structures + for (size_t i = 0; i < fields.size(); i++) + { + switch (fields[i].type) + { + case TextLineFormField: + case MultilineTextFormField: + case OpenFileNameFormField: + case SaveFileNameFormField: + case DirectoryNameFormField: + fields[i].stringResult = fieldBuf[i].stringResult; + break; + case IntegerFormField: + fields[i].intResult = fieldBuf[i].intResult; + break; + case AddressFormField: + fields[i].addressResult = fieldBuf[i].addressResult; + break; + case ChoiceFormField: + fields[i].indexResult = fieldBuf[i].indexResult; + break; + default: + break; + } + } + + BNFreeFormInputResults(fieldBuf, fields.size()); + return true; +} + + BNMessageBoxButtonResult BinaryNinja::ShowMessageBox(const string& title, const string& text, BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon) { diff --git a/python/__init__.py b/python/__init__.py index c8880648..847b2c06 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -10177,6 +10177,170 @@ class BackgroundTaskThread(BackgroundTask): def join(self): self.thread.join() +class LabelField(object): + def __init__(self, text): + self.text = text + + def _fill_core_struct(self, value): + value.type = core.LabelFormField + value.prompt = self.text + + def _fill_core_result(self, value): + pass + + def _get_result(self, value): + pass + +class SeparatorField(object): + def _fill_core_struct(self, value): + value.type = core.SeparatorFormField + + def _fill_core_result(self, value): + pass + + def _get_result(self, value): + pass + +class TextLineField(object): + def __init__(self, prompt): + self.prompt = prompt + self.result = None + + def _fill_core_struct(self, value): + value.type = core.TextLineFormField + value.prompt = self.prompt + + def _fill_core_result(self, value): + value.stringResult = core.BNAllocString(str(self.result)) + + def _get_result(self, value): + self.result = value.stringResult + +class MultilineTextField(object): + def __init__(self, prompt): + self.prompt = prompt + self.result = None + + def _fill_core_struct(self, value): + value.type = core.MultilineTextFormField + value.prompt = self.prompt + + def _fill_core_result(self, value): + value.stringResult = core.BNAllocString(str(self.result)) + + def _get_result(self, value): + self.result = value.stringResult + +class IntegerField(object): + def __init__(self, prompt): + self.prompt = prompt + self.result = None + + def _fill_core_struct(self, value): + value.type = core.IntegerFormField + value.prompt = self.prompt + + def _fill_core_result(self, value): + value.intResult = self.result + + def _get_result(self, value): + self.result = value.intResult + +class AddressField(object): + def __init__(self, prompt, view = None, current_address = 0): + self.prompt = prompt + self.view = view + self.current_address = current_address + self.result = None + + def _fill_core_struct(self, value): + value.type = core.AddressFormField + value.prompt = self.prompt + value.view = None + if self.view is not None: + value.view = self.view.handle + value.currentAddress = self.current_address + + def _fill_core_result(self, value): + value.addressResult = self.result + + def _get_result(self, value): + self.result = value.addressResult + +class ChoiceField(object): + def __init__(self, prompt, choices): + self.prompt = prompt + self.choices = choices + self.result = None + + def _fill_core_struct(self, value): + value.type = core.ChoiceFormField + value.prompt = self.prompt + choice_buf = (ctypes.c_char_p * len(self.choices))() + for i in xrange(0, len(self.choices)): + choice_buf[i] = str(self.choices[i]) + value.choices = choice_buf + value.count = len(self.choices) + + def _fill_core_result(self, value): + value.indexResult = self.result + + def _get_result(self, value): + self.result = value.indexResult + +class OpenFileNameField(object): + def __init__(self, prompt, ext = ""): + self.prompt = prompt + self.ext = ext + self.result = None + + def _fill_core_struct(self, value): + value.type = core.OpenFileNameFormField + value.prompt = self.prompt + value.ext = self.ext + + def _fill_core_result(self, value): + value.stringResult = core.BNAllocString(str(self.result)) + + def _get_result(self, value): + self.result = value.stringResult + +class SaveFileNameField(object): + def __init__(self, prompt, ext = "", default_name = ""): + self.prompt = prompt + self.ext = ext + self.default_name = default_name + self.result = None + + def _fill_core_struct(self, value): + value.type = core.SaveFileNameFormField + value.prompt = self.prompt + value.ext = self.ext + value.defaultName = self.default_name + + def _fill_core_result(self, value): + value.stringResult = core.BNAllocString(str(self.result)) + + def _get_result(self, value): + self.result = value.stringResult + +class DirectoryNameField(object): + def __init__(self, prompt, default_name = ""): + self.prompt = prompt + self.default_name = default_name + self.result = None + + def _fill_core_struct(self, value): + value.type = core.DirectoryNameField + value.prompt = self.prompt + value.defaultName = self.default_name + + def _fill_core_result(self, value): + value.stringResult = core.BNAllocString(str(self.result)) + + def _get_result(self, value): + self.result = value.stringResult + class InteractionHandler(object): _interaction_handler = None @@ -10193,6 +10357,7 @@ class InteractionHandler(object): self._cb.getOpenFileNameInput = self._cb.getOpenFileNameInput.__class__(self._get_open_filename_input) self._cb.getSaveFileNameInput = self._cb.getSaveFileNameInput.__class__(self._get_save_filename_input) self._cb.getDirectoryNameInput = self._cb.getDirectoryNameInput.__class__(self._get_directory_name_input) + self._cb.getFormInput = self._cb.getFormInput.__class__(self._get_form_input) self._cb.showMessageBox = self._cb.showMessageBox.__class__(self._show_message_box) def register(self): @@ -10306,6 +10471,46 @@ class InteractionHandler(object): except: log_error(traceback.format_exc()) + def _get_form_input(self, ctxt, fields, count, title): + try: + field_objs = [] + for i in xrange(0, count): + if fields[i].type == core.LabelFormField: + field_objs.append(LabelField(fields[i].prompt)) + elif fields[i].type == core.SeparatorFormField: + field_objs.append(SeparatorField()) + elif fields[i].type == core.TextLineFormField: + field_objs.append(TextLineField(fields[i].prompt)) + elif fields[i].type == core.MultilineTextFormField: + field_objs.append(MultilineTextField(fields[i].prompt)) + elif fields[i].type == core.IntegerFormField: + field_objs.append(IntegerField(fields[i].prompt)) + elif fields[i].type == core.AddressFormField: + view = None + if fields[i].view: + view = BinaryView(None, handle = core.BNNewViewReference(fields[i].view)) + field_objs.append(AddressField(fields[i].prompt, view, fields[i].currentAddress)) + elif fields[i].type == core.ChoiceFormField: + choices = [] + for i in xrange(0, fields[i].count): + choices.append(fields[i].choices[i]) + field_objs.append(ChoiceField(fields[i].prompt, choices)) + elif fields[i].type == core.OpenFileNameFormField: + field_objs.append(OpenFileNameField(fields[i].prompt, fields[i].ext)) + elif fields[i].type == core.SaveFileNameFormField: + field_objs.append(SaveFileNameField(fields[i].prompt, fields[i].ext, fields[i].defaultName)) + elif fields[i].type == core.DirectoryNameField: + field_objs.append(DirectoryNameField(fields[i].prompt, fields[i].defaultName)) + else: + field_objs.append(LabelField(fields[i].prompt)) + if not self.get_form_input(field_objs, title): + return False + for i in xrange(0, count): + field_objs[i]._fill_core_result(fields[i]) + return True + except: + log_error(traceback.format_exc()) + def _show_message_box(self, ctxt, title, text, buttons, icon): try: return self.show_message_box(title, text, buttons, icon) @@ -10350,8 +10555,11 @@ class InteractionHandler(object): def get_directory_name_input(self, prompt, default_name): return get_text_line_input(title, "Select Directory") + def get_form_input(self, fields, title): + return False + def show_message_box(self, title, text, buttons, icon): - return CancelButton + return core.CancelButton class _DestructionCallbackHandler: def __init__(self): @@ -10753,6 +10961,23 @@ def get_directory_name_input(prompt, default_name = ""): core.BNFreeString(ctypes.cast(value, ctypes.POINTER(ctypes.c_byte))) return result +def get_form_input(fields, title): + value = (core.BNFormInputField * len(fields))() + for i in xrange(0, len(fields)): + if isinstance(fields[i], str): + LabelField(fields[i])._fill_core_struct(value[i]) + elif fields[i] is None: + SeparatorField()._fill_core_struct(value[i]) + else: + fields[i]._fill_core_struct(value[i]) + if not core.BNGetFormInput(value, len(fields), title): + return False + for i in xrange(0, len(fields)): + if not (isinstance(fields[i], str) or (fields[i] is None)): + fields[i]._get_result(value[i]) + core.BNFreeFormInputResults(value, len(fields)) + return True + def show_message_box(title, text, buttons = core.OKButtonSet, icon = core.InformationIcon): return core.BNShowMessageBox(title, text, buttons, icon) -- cgit v1.3.1 From 6f4b16ff17b2c52890728293814ff16f48349402 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 29 Sep 2016 17:23:06 -0400 Subject: NOMINMAX so windows.h won't define min/max --- binaryninjaapi.h | 1 + 1 file changed, 1 insertion(+) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index a62b4239..b115263c 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -21,6 +21,7 @@ #pragma once #ifdef WIN32 +#define NOMINMAX #include #endif #include -- cgit v1.3.1