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(-) 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(+) 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(+) 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