diff options
| -rw-r--r-- | basicblock.cpp | 6 | ||||
| -rw-r--r-- | binaryninjaapi.h | 61 | ||||
| -rw-r--r-- | binaryninjacore.h | 79 | ||||
| -rw-r--r-- | binaryview.cpp | 117 | ||||
| -rw-r--r-- | function.cpp | 31 | ||||
| -rw-r--r-- | linearviewcursor.cpp | 17 | ||||
| -rw-r--r-- | linearviewobject.cpp | 37 | ||||
| -rw-r--r-- | python/basicblock.py | 5 | ||||
| -rw-r--r-- | python/binaryview.py | 299 | ||||
| -rw-r--r-- | python/function.py | 69 | ||||
| -rw-r--r-- | suite/testcommon.py | 49 | ||||
| -rw-r--r-- | ui/addressdialog.h | 26 | ||||
| -rw-r--r-- | ui/expandablegroup.h | 27 | ||||
| -rw-r--r-- | ui/getsymbolslistthread.h | 37 | ||||
| -rw-r--r-- | ui/searchresult.h | 267 | ||||
| -rw-r--r-- | ui/typeview.h | 2 | ||||
| -rw-r--r-- | ui/viewframe.h | 50 | ||||
| -rw-r--r-- | ui/xreflist.h | 25 |
18 files changed, 1025 insertions, 179 deletions
diff --git a/basicblock.cpp b/basicblock.cpp index e2e58432..3e3fccef 100644 --- a/basicblock.cpp +++ b/basicblock.cpp @@ -475,3 +475,9 @@ Ref<MediumLevelILFunction> BasicBlock::GetMediumLevelILFunction() const return nullptr; return new MediumLevelILFunction(func); } + + +bool BasicBlock::GetInstructionContainingAddress(uint64_t addr, uint64_t* start) +{ + return BNGetBasicBlockInstructionContainingAddress(m_object, addr, start); +} diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 1cb9f1be..e70490f3 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1179,6 +1179,8 @@ __attribute__ ((format (printf, 1, 2))) BNTypeReferenceType type; }; + + struct InstructionTextToken { enum @@ -1239,6 +1241,8 @@ __attribute__ ((format (printf, 1, 2))) Ref<Function> function; Ref<BasicBlock> block; DisassemblyTextLine contents; + + static LinearDisassemblyLine FromAPIObject(BNLinearDisassemblyLine* line); }; class DisassemblySettings; @@ -1726,17 +1730,36 @@ __attribute__ ((format (printf, 1, 2))) void RegisterPlatformTypes(Platform* platform); - bool FindNextData(uint64_t start, const DataBuffer& data, uint64_t& addr, BNFindFlag flags = FindCaseSensitive); - bool FindNextText(uint64_t start, const std::string& data, uint64_t& addr, Ref<DisassemblySettings> settings, + bool FindNextData(uint64_t start, const DataBuffer& data, uint64_t& result, BNFindFlag flags = FindCaseSensitive); - bool FindNextConstant(uint64_t start, uint64_t constant, uint64_t& addr, Ref<DisassemblySettings> settings); + bool FindNextText(uint64_t start, const std::string& data, uint64_t& addr, + Ref<DisassemblySettings> settings, BNFindFlag flags = FindCaseSensitive, + BNFunctionGraphType graph = NormalFunctionGraph); + bool FindNextConstant(uint64_t start, uint64_t constant, uint64_t& addr, + Ref<DisassemblySettings> settings, BNFunctionGraphType graph = NormalFunctionGraph); - bool FindNextData(uint64_t start, uint64_t end, const DataBuffer& data, uint64_t& addr, BNFindFlag flags, - const std::function<bool(size_t current, size_t total)>& progress); - bool FindNextText(uint64_t start, uint64_t end, const std::string& data, uint64_t& addr, Ref<DisassemblySettings> settings, + bool FindNextData(uint64_t start, uint64_t end, const DataBuffer& data, uint64_t& addr, BNFindFlag flags, const std::function<bool(size_t current, size_t total)>& progress); - bool FindNextConstant(uint64_t start, uint64_t end, uint64_t constant, uint64_t& addr, Ref<DisassemblySettings> settings, + bool FindNextText(uint64_t start, uint64_t end, const std::string& data, uint64_t& addr, + Ref<DisassemblySettings> settings, BNFindFlag flags, BNFunctionGraphType graph, const std::function<bool(size_t current, size_t total)>& progress); + bool FindNextConstant(uint64_t start, uint64_t end, uint64_t constant, uint64_t& addr, + Ref<DisassemblySettings> settings, BNFunctionGraphType graph, + const std::function<bool(size_t current, size_t total)>& progress); + + bool FindAllData(uint64_t start, uint64_t end, const DataBuffer& data, BNFindFlag flags, + const std::function<bool(size_t current, size_t total)>& progress, + const std::function<bool(uint64_t addr, const DataBuffer& match)>& matchCallback); + bool FindAllText(uint64_t start, uint64_t end, const std::string& data, + Ref<DisassemblySettings> settings, BNFindFlag flags, BNFunctionGraphType graph, + const std::function<bool(size_t current, size_t total)>& progress, + const std::function<bool(uint64_t addr, const std::string& match, + const LinearDisassemblyLine& line)>& matchCallback); + bool FindAllConstant(uint64_t start, uint64_t end, uint64_t constant, + Ref<DisassemblySettings> settings, BNFunctionGraphType graph, + const std::function<bool(size_t current, size_t total)>& progress, + const std::function<bool(uint64_t addr, + const LinearDisassemblyLine& line)>& matchCallback); void Reanalyze(); @@ -2953,6 +2976,8 @@ __attribute__ ((format (printf, 1, 2))) bool IsMediumLevelILBlock() const; Ref<LowLevelILFunction> GetLowLevelILFunction() const; Ref<MediumLevelILFunction> GetMediumLevelILFunction() const; + + bool GetInstructionContainingAddress(uint64_t addr, uint64_t* start); }; struct VariableNameAndType @@ -3289,6 +3314,12 @@ __attribute__ ((format (printf, 1, 2))) BNDeadStoreElimination GetVariableDeadStoreElimination(const Variable& var); void SetVariableDeadStoreElimination(const Variable& var, BNDeadStoreElimination mode); + + uint64_t GetHighestAddress(); + uint64_t GetLowestAddress(); + std::vector<BNAddressRange> GetAddressRanges(); + + bool GetInstructionContainingAddress(Architecture* arch, uint64_t addr, uint64_t* start); }; class AdvancedFunctionAnalysisDataRequestor @@ -5529,4 +5560,20 @@ __attribute__ ((format (printf, 1, 2))) const char** m_rust_array; uint64_t m_length; }; + + struct FindParameters + { + BNFindType type; + BNFindRangeType rangeType; + BNFunctionGraphType ilType; + std::string string; + BNFindFlag flags; + bool findAll; + + uint64_t findConstant; + DataBuffer findBuffer; + + std::vector<BNAddressRange> ranges; + uint64_t totalLength; + }; } diff --git a/binaryninjacore.h b/binaryninjacore.h index 8318d8e8..9dd5e40e 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -28,14 +28,14 @@ // Current ABI version for linking to the core. This is incremented any time // there are changes to the API that affect linking, including new functions, // new types, or modifications to existing functions or types. -#define BN_CURRENT_CORE_ABI_VERSION 6 +#define BN_CURRENT_CORE_ABI_VERSION 7 // Minimum ABI version that is supported for loading of plugins. Plugins that // are linked to an ABI version less than this will not be able to load and // will require rebuilding. The minimum version is increased when there are // incompatible changes that break binary compatibility, such as changes to // existing types or functions. -#define BN_MINIMUM_CORE_ABI_VERSION 5 +#define BN_MINIMUM_CORE_ABI_VERSION 6 #ifdef __GNUC__ # ifdef BINARYNINJACORE_LIBRARY @@ -2176,6 +2176,22 @@ extern "C" FindCaseInsensitive = 1 }; + enum BNFindRangeType + { + AllRangeType, + CustomRangeType, + CurrentFunctionRangeType + }; + + enum BNFindType + { + FindTypeRawString, + FindTypeEscapedString, + FindTypeText, + FindTypeConstant, + FindTypeBytes + }; + enum BNScriptingProviderInputReadyState { NotReadyForInput, @@ -2810,19 +2826,47 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI size_t BNGetInstructionLength(BNBinaryView* view, BNArchitecture* arch, uint64_t addr); - BINARYNINJACOREAPI bool BNFindNextData(BNBinaryView* view, uint64_t start, BNDataBuffer* data, uint64_t* result, - BNFindFlag flags); - BINARYNINJACOREAPI bool BNFindNextText(BNBinaryView* view, uint64_t start, const char* data, uint64_t* result, - BNDisassemblySettings* settings, BNFindFlag flags); - BINARYNINJACOREAPI bool BNFindNextConstant(BNBinaryView* view, uint64_t start, uint64_t constant, uint64_t* result, - BNDisassemblySettings* settings); + BINARYNINJACOREAPI bool BNFindNextData(BNBinaryView* view, uint64_t start, + BNDataBuffer* data, uint64_t* result, BNFindFlag flags); + BINARYNINJACOREAPI bool BNFindNextText(BNBinaryView* view, uint64_t start, const char* data, + uint64_t* result, BNDisassemblySettings* settings, BNFindFlag flags, + BNFunctionGraphType graph); + BINARYNINJACOREAPI bool BNFindNextConstant(BNBinaryView* view, uint64_t start, + uint64_t constant, uint64_t* result, BNDisassemblySettings* settings, + BNFunctionGraphType graph); - BINARYNINJACOREAPI bool BNFindNextDataWithProgress(BNBinaryView* view, uint64_t start, uint64_t end, BNDataBuffer* data, uint64_t* result, BNFindFlag flags, + BINARYNINJACOREAPI bool BNFindNextDataWithProgress(BNBinaryView* view, uint64_t start, + uint64_t end, BNDataBuffer* data, uint64_t* result, BNFindFlag flags, void* ctxt, bool (*progress)(void* ctxt, size_t current, size_t total)); - BINARYNINJACOREAPI bool BNFindNextTextWithProgress(BNBinaryView* view, uint64_t start, uint64_t end, const char* data, uint64_t* result, - BNDisassemblySettings* settings, BNFindFlag flags, void* ctxt, bool (*progress)(void* ctxt, size_t current, size_t total)); - BINARYNINJACOREAPI bool BNFindNextConstantWithProgress(BNBinaryView* view, uint64_t start, uint64_t end, uint64_t constant, uint64_t* result, - BNDisassemblySettings* settings, void* ctxt, bool (*progress)(void* ctxt, size_t current, size_t total)); + BINARYNINJACOREAPI bool BNFindNextTextWithProgress(BNBinaryView* view, uint64_t start, + uint64_t end, const char* data, uint64_t* result, BNDisassemblySettings* settings, + BNFindFlag flags, BNFunctionGraphType graph, void* ctxt, + bool (*progress)(void* ctxt, size_t current, size_t total)); + BINARYNINJACOREAPI bool BNFindNextConstantWithProgress(BNBinaryView* view, uint64_t start, + uint64_t end, uint64_t constant, uint64_t* result, BNDisassemblySettings* settings, + BNFunctionGraphType graph, void* ctxt, + bool (*progress)(void* ctxt, size_t current, size_t total)); + + BINARYNINJACOREAPI bool BNFindAllDataWithProgress(BNBinaryView* view, uint64_t start, + uint64_t end, BNDataBuffer* data, BNFindFlag flags, + void* ctxt, bool (*progress)(void* ctxt, size_t current, size_t total), + void* matchCtxt, + bool (*matchCallback)(void* matchCtxt, uint64_t addr, BNDataBuffer* match)); + BINARYNINJACOREAPI bool BNFindAllTextWithProgress(BNBinaryView* view, uint64_t start, + uint64_t end, const char* data, BNDisassemblySettings* settings, BNFindFlag flags, + BNFunctionGraphType graph, void* ctxt, + bool (*progress)(void* ctxt, size_t current, size_t total), + void* matchCtxt, + bool (*matchCallback)(void* matchCtxt, uint64_t addr, const char* match, + BNLinearDisassemblyLine* line)); + BINARYNINJACOREAPI bool BNFindAllConstantWithProgress(BNBinaryView* view, uint64_t start, + uint64_t end, uint64_t constant, BNDisassemblySettings* settings, + BNFunctionGraphType graph, + void* ctxt, + bool (*progress)(void* ctxt, size_t current, size_t total), + void* matchCtxt, + bool (*matchCallback)(void* matchCtxt, uint64_t addr, + BNLinearDisassemblyLine* line)); BINARYNINJACOREAPI void BNAddAutoSegment(BNBinaryView* view, uint64_t start, uint64_t length, uint64_t dataOffset, uint64_t dataLength, uint32_t flags); @@ -3159,6 +3203,10 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI BNBasicBlock** BNGetBasicBlocksForAddress(BNBinaryView* view, uint64_t addr, size_t* count); BINARYNINJACOREAPI BNBasicBlock** BNGetBasicBlocksStartingAtAddress(BNBinaryView* view, uint64_t addr, size_t* count); + BINARYNINJACOREAPI uint64_t BNGetFunctionHighestAddress(BNFunction* func); + BINARYNINJACOREAPI uint64_t BNGetFunctionLowestAddress(BNFunction* func); + BINARYNINJACOREAPI BNAddressRange* BNGetFunctionAddressRanges(BNFunction* func, size_t* count); + BINARYNINJACOREAPI BNLowLevelILFunction* BNGetFunctionLowLevelIL(BNFunction* func); BINARYNINJACOREAPI BNLowLevelILFunction* BNGetFunctionLowLevelILIfAvailable(BNFunction* func); BINARYNINJACOREAPI size_t BNGetLowLevelILForInstruction(BNFunction* func, BNArchitecture* arch, uint64_t addr); @@ -3247,6 +3295,9 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI BNRegisterValueWithConfidence BNGetFunctionGlobalPointerValue(BNFunction* func); BINARYNINJACOREAPI BNRegisterValueWithConfidence BNGetFunctionRegisterValueAtExit(BNFunction* func, uint32_t reg); + BINARYNINJACOREAPI bool BNGetInstructionContainingAddress(BNFunction* func, + BNArchitecture* arch, uint64_t addr, uint64_t* start); + BINARYNINJACOREAPI BNFunction* BNGetBasicBlockFunction(BNBasicBlock* block); BINARYNINJACOREAPI BNArchitecture* BNGetBasicBlockArchitecture(BNBasicBlock* block); BINARYNINJACOREAPI BNBasicBlock* BNGetBasicBlockSource(BNBasicBlock* block); @@ -3272,6 +3323,8 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI bool BNIsMediumLevelILBasicBlock(BNBasicBlock* block); BINARYNINJACOREAPI BNLowLevelILFunction* BNGetBasicBlockLowLevelILFunction(BNBasicBlock* block); BINARYNINJACOREAPI BNMediumLevelILFunction* BNGetBasicBlockMediumLevelILFunction(BNBasicBlock* block); + BINARYNINJACOREAPI bool BNGetBasicBlockInstructionContainingAddress(BNBasicBlock* block, + uint64_t addr, uint64_t* start); BINARYNINJACOREAPI BNDisassemblyTextLine* BNGetBasicBlockDisassemblyText(BNBasicBlock* block, BNDisassemblySettings* settings, size_t* count); diff --git a/binaryview.cpp b/binaryview.cpp index 26ace8a9..bde0afca 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -2904,20 +2904,22 @@ void BinaryView::RegisterPlatformTypes(Platform* platform) } -bool BinaryView::FindNextData(uint64_t start, const DataBuffer& data, uint64_t& result, BNFindFlag flags) +bool BinaryView::FindNextData(uint64_t start, const DataBuffer& data, uint64_t& result, + BNFindFlag flags) { return BNFindNextData(m_object, start, data.GetBufferObject(), &result, flags); } bool BinaryView::FindNextText(uint64_t start, const std::string& data, uint64_t& result, - Ref<DisassemblySettings> settings, BNFindFlag flags) + Ref<DisassemblySettings> settings, BNFindFlag flags, BNFunctionGraphType graph) { - return BNFindNextText(m_object, start, data.c_str(), &result, settings->GetObject(), flags); + return BNFindNextText(m_object, start, data.c_str(), &result, settings->GetObject(), flags, graph); } -bool BinaryView::FindNextConstant(uint64_t start, uint64_t constant, uint64_t& result, Ref<DisassemblySettings> settings) +bool BinaryView::FindNextConstant(uint64_t start, uint64_t constant, uint64_t& result, + Ref<DisassemblySettings> settings, BNFunctionGraphType graph) { - return BNFindNextConstant(m_object, start, constant, &result, settings->GetObject()); + return BNFindNextConstant(m_object, start, constant, &result, settings->GetObject(), graph); } @@ -2934,6 +2936,54 @@ static bool FindProgressCallback(void* ctxt, size_t progress, size_t total) } +struct MatchCallbackContextForDataBuffer +{ + std::function<bool(uint64_t, const DataBuffer&)> func; +}; + + +static bool MatchCallbackForDataBuffer(void* ctxt, uint64_t addr, BNDataBuffer* buffer) +{ + MatchCallbackContextForDataBuffer* cb = (MatchCallbackContextForDataBuffer*)ctxt; + return cb->func(addr, DataBuffer(buffer)); +} + + +struct MatchCallbackContextForText +{ + std::function<bool(uint64_t, const string&, const LinearDisassemblyLine&)> func; +}; + + +static bool MatchCallbackForText(void* ctxt, uint64_t addr, const char* buffer, + BNLinearDisassemblyLine* line) +{ + MatchCallbackContextForText* cb = (MatchCallbackContextForText*)ctxt; + + LinearDisassemblyLine result = LinearDisassemblyLine::FromAPIObject(line); + BNFreeLinearDisassemblyLines(line, 1); + + return cb->func(addr, string(buffer), result); +} + + +struct MatchCallbackContextForConstant +{ + std::function<bool(uint64_t, const LinearDisassemblyLine&)> func; +}; + + +static bool MatchCallbackForConstant(void* ctxt, uint64_t addr, BNLinearDisassemblyLine* line) +{ + MatchCallbackContextForConstant* cb = (MatchCallbackContextForConstant*)ctxt; + + LinearDisassemblyLine result = LinearDisassemblyLine::FromAPIObject(line); + BNFreeLinearDisassemblyLines(line, 1); + + return cb->func(addr, result); +} + + bool BinaryView::FindNextData(uint64_t start, uint64_t end, const DataBuffer& data, uint64_t& addr, BNFindFlag flags, const std::function<bool(size_t current, size_t total)>& progress) { @@ -2943,21 +2993,68 @@ bool BinaryView::FindNextData(uint64_t start, uint64_t end, const DataBuffer& da } -bool BinaryView::FindNextText(uint64_t start, uint64_t end, const std::string& data, uint64_t& addr, Ref<DisassemblySettings> settings, - BNFindFlag flags, const std::function<bool(size_t current, size_t total)>& progress) +bool BinaryView::FindNextText(uint64_t start, uint64_t end, const std::string& data, + uint64_t& addr, Ref<DisassemblySettings> settings, BNFindFlag flags, BNFunctionGraphType graph, + const std::function<bool(size_t current, size_t total)>& progress) { FindProgressCallbackContext fp; fp.func = progress; - return BNFindNextTextWithProgress(m_object, start, end, data.c_str(), &addr, settings->GetObject(), flags, &fp, FindProgressCallback); + return BNFindNextTextWithProgress(m_object, start, end, data.c_str(), &addr, + settings->GetObject(), flags, graph, &fp, FindProgressCallback); } -bool BinaryView::FindNextConstant(uint64_t start, uint64_t end, uint64_t constant, uint64_t& addr, Ref<DisassemblySettings> settings, +bool BinaryView::FindNextConstant(uint64_t start, uint64_t end, uint64_t constant, uint64_t& addr, + Ref<DisassemblySettings> settings, BNFunctionGraphType graph, const std::function<bool(size_t current, size_t total)>& progress) { FindProgressCallbackContext fp; fp.func = progress; - return BNFindNextConstantWithProgress(m_object, start, end, constant, &addr, settings->GetObject(), &fp, FindProgressCallback); + return BNFindNextConstantWithProgress(m_object, start, end, constant, &addr, + settings->GetObject(), graph, &fp, FindProgressCallback); +} + + +bool BinaryView::FindAllData(uint64_t start, uint64_t end, const DataBuffer& data, + BNFindFlag flags, const std::function<bool(size_t current, size_t total)>& progress, + const std::function<bool(uint64_t addr, const DataBuffer& match)>& matchCallback) +{ + FindProgressCallbackContext fp; + fp.func = progress; + MatchCallbackContextForDataBuffer mc; + mc.func = matchCallback; + return BNFindAllDataWithProgress(m_object, start, end, data.GetBufferObject(), + flags, &fp, FindProgressCallback, &mc, MatchCallbackForDataBuffer); +} + + +bool BinaryView::FindAllText(uint64_t start, uint64_t end, const std::string& data, + Ref<DisassemblySettings> settings, BNFindFlag flags, BNFunctionGraphType graph, + const std::function<bool(size_t current, size_t total)>& progress, + const std::function<bool(uint64_t addr, const std::string& match, + const LinearDisassemblyLine& line)>& matchCallback) +{ + FindProgressCallbackContext fp; + fp.func = progress; + MatchCallbackContextForText mc; + mc.func = matchCallback; + return BNFindAllTextWithProgress(m_object, start, end, data.c_str(), settings->GetObject(), + flags, graph, &fp, FindProgressCallback, &mc, MatchCallbackForText); +} + + +bool BinaryView::FindAllConstant(uint64_t start, uint64_t end, uint64_t constant, + Ref<DisassemblySettings> settings, BNFunctionGraphType graph, + const std::function<bool(size_t current, size_t total)>& progress, + const std::function<bool(uint64_t addr, const LinearDisassemblyLine& line)>& + matchCallback) +{ + FindProgressCallbackContext fp; + fp.func = progress; + MatchCallbackContextForConstant mc; + mc.func = matchCallback; + return BNFindAllConstantWithProgress(m_object, start, end, constant, settings->GetObject(), + graph, &fp, FindProgressCallback, &mc, MatchCallbackForConstant); } diff --git a/function.cpp b/function.cpp index b671f283..45333ebf 100644 --- a/function.cpp +++ b/function.cpp @@ -2169,6 +2169,37 @@ vector<VariableReferenceSource> Function::GetHighLevelILVariableReferencesInRang } +uint64_t Function::GetHighestAddress() +{ + return BNGetFunctionHighestAddress(m_object); +} + + +uint64_t Function::GetLowestAddress() +{ + return BNGetFunctionLowestAddress(m_object); +} + + +std::vector<BNAddressRange> Function::GetAddressRanges() +{ + size_t count; + BNAddressRange* ranges = BNGetFunctionAddressRanges(m_object, &count); + + std::vector<BNAddressRange> result; + copy(&ranges[0], &ranges[count], back_inserter(result)); + BNFreeAddressRanges(ranges); + return result; +} + + +bool Function::GetInstructionContainingAddress(Architecture* arch, + uint64_t addr, uint64_t* start) +{ + return BNGetInstructionContainingAddress(m_object, arch->GetObject(), addr, start); +} + + AdvancedFunctionAnalysisDataRequestor::AdvancedFunctionAnalysisDataRequestor(Function* func): m_func(func) { if (m_func) diff --git a/linearviewcursor.cpp b/linearviewcursor.cpp index c9101594..55211e00 100644 --- a/linearviewcursor.cpp +++ b/linearviewcursor.cpp @@ -198,22 +198,7 @@ vector<LinearDisassemblyLine> LinearViewCursor::GetLines() vector<LinearDisassemblyLine> result; result.reserve(count); for (size_t i = 0; i < count; i++) - { - LinearDisassemblyLine line; - line.type = lines[i].type; - line.function = lines[i].function ? new Function(BNNewFunctionReference(lines[i].function)) : nullptr; - line.block = lines[i].block ? new BasicBlock(BNNewBasicBlockReference(lines[i].block)) : nullptr; - line.contents.addr = lines[i].contents.addr; - line.contents.instrIndex = lines[i].contents.instrIndex; - line.contents.highlight = lines[i].contents.highlight; - line.contents.tokens = InstructionTextToken::ConvertInstructionTextTokenList(lines[i].contents.tokens, lines[i].contents.count); - line.contents.tags = Tag::ConvertTagList(lines[i].contents.tags, lines[i].contents.tagCount); - line.contents.typeInfo.hasTypeInfo = lines[i].contents.typeInfo.hasTypeInfo; - line.contents.typeInfo.fieldIndex = lines[i].contents.typeInfo.fieldIndex; - line.contents.typeInfo.parentType = lines[i].contents.typeInfo.parentType ? - new Type(BNNewTypeReference(lines[i].contents.typeInfo.parentType)) : nullptr; - result.push_back(line); - } + result.push_back(LinearDisassemblyLine::FromAPIObject(&lines[i])); BNFreeLinearDisassemblyLines(lines, count); return result; diff --git a/linearviewobject.cpp b/linearviewobject.cpp index e07cd425..afd6d0c8 100644 --- a/linearviewobject.cpp +++ b/linearviewobject.cpp @@ -24,6 +24,26 @@ using namespace std; using namespace BinaryNinja; +LinearDisassemblyLine LinearDisassemblyLine::FromAPIObject(BNLinearDisassemblyLine* line) +{ + LinearDisassemblyLine result; + result.type = line->type; + result.function = line->function ? new Function(BNNewFunctionReference(line->function)) : nullptr; + result.block = line->block ? new BasicBlock(BNNewBasicBlockReference(line->block)) : nullptr; + result.contents.addr = line->contents.addr; + result.contents.instrIndex = line->contents.instrIndex; + result.contents.highlight = line->contents.highlight; + result.contents.tokens = InstructionTextToken::ConvertInstructionTextTokenList(line->contents.tokens, line->contents.count); + result.contents.tags = Tag::ConvertTagList(line->contents.tags, line->contents.tagCount); + result.contents.typeInfo.hasTypeInfo = line->contents.typeInfo.hasTypeInfo; + result.contents.typeInfo.fieldIndex = line->contents.typeInfo.fieldIndex; + result.contents.typeInfo.parentType = line->contents.typeInfo.parentType ? + new Type(BNNewTypeReference(line->contents.typeInfo.parentType)) : nullptr; + + return result; +} + + LinearViewObjectIdentifier::LinearViewObjectIdentifier(): type(SingleLinearViewObject), start(0), end(0) { @@ -135,22 +155,7 @@ vector<LinearDisassemblyLine> LinearViewObject::GetLines(LinearViewObject* prev, vector<LinearDisassemblyLine> result; result.reserve(count); for (size_t i = 0; i < count; i++) - { - LinearDisassemblyLine line; - line.type = lines[i].type; - line.function = lines[i].function ? new Function(BNNewFunctionReference(lines[i].function)) : nullptr; - line.block = lines[i].block ? new BasicBlock(BNNewBasicBlockReference(lines[i].block)) : nullptr; - line.contents.addr = lines[i].contents.addr; - line.contents.instrIndex = lines[i].contents.instrIndex; - line.contents.highlight = lines[i].contents.highlight; - line.contents.tokens = InstructionTextToken::ConvertInstructionTextTokenList(lines[i].contents.tokens, lines[i].contents.count); - line.contents.tags = Tag::ConvertTagList(lines[i].contents.tags, lines[i].contents.tagCount); - line.contents.typeInfo.hasTypeInfo = lines[i].contents.typeInfo.hasTypeInfo; - line.contents.typeInfo.fieldIndex = lines[i].contents.typeInfo.fieldIndex; - line.contents.typeInfo.parentType = lines[i].contents.typeInfo.parentType ? - new Type(BNNewTypeReference(lines[i].contents.typeInfo.parentType)) : nullptr; - result.push_back(line); - } + result.push_back(LinearDisassemblyLine::FromAPIObject(&lines[i])); BNFreeLinearDisassemblyLines(lines, count); return result; diff --git a/python/basicblock.py b/python/basicblock.py index 9882bd42..643a60c3 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -519,3 +519,8 @@ class BasicBlock(object): if isinstance(color, HighlightStandardColor): color = highlight.HighlightColor(color) core.BNSetUserBasicBlockHighlight(self.handle, color._get_core_struct()) + + def get_instruction_containing_address(addr): + start = ctypes.c_uint64() + ret = core.BNGetBasicBlockInstructionContainingAddress(self.handle, addr, start) + return ret, start.value diff --git a/python/binaryview.py b/python/binaryview.py index 463df925..02cdf191 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -20,6 +20,8 @@ # IN THE SOFTWARE. import struct +import threading +import queue import traceback import ctypes import abc @@ -33,7 +35,7 @@ from collections import defaultdict, OrderedDict from binaryninja import _binaryninjacore as core from binaryninja.enums import (AnalysisState, SymbolType, InstructionTextTokenType, Endianness, ModificationStatus, StringType, SegmentFlag, SectionSemantics, FindFlag, - TypeClass, SaveOption, BinaryViewEventType) + TypeClass, SaveOption, BinaryViewEventType, FunctionGraphType) import binaryninja from binaryninja import associateddatastore # required for _BinaryViewAssociatedDataStore from binaryninja import log @@ -46,6 +48,7 @@ from binaryninja import lineardisassembly from binaryninja import metadata from binaryninja import highlight from binaryninja import function +from binaryninja.function import AddressRange from binaryninja import settings from binaryninja import pyNativeStr @@ -1208,53 +1211,6 @@ class Section(object): return self.start + len(self) -class AddressRange(object): - def __init__(self, start, end): - self._start = start - self._end = end - - def __repr__(self): - return "<%#x-%#x>" % (self._start, self._end) - - def __len__(self): - return self._end - self.start - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self._start, self._end) == (other._start, other._end) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __hash__(self): - return hash((self._start, self._end)) - - @property - def length(self): - return self._end - self._start - - @property - def start(self): - """ """ - return self._start - - @start.setter - def start(self, value): - self._start = value - - @property - def end(self): - """ """ - return self._end - - @end.setter - def end(self, value): - self._end = value - - class TagType(object): def __init__(self, handle): self.handle = core.handle_of_type(handle, core.BNTagType) @@ -5504,13 +5460,15 @@ class BinaryView(object): return result.value - def find_next_text(self, start, text, settings=None, flags=FindFlag.FindCaseSensitive): + def find_next_text(self, start, text, settings=None, flags=FindFlag.FindCaseSensitive,\ + graph_type = FunctionGraphType.NormalFunctionGraph): """ ``find_next_text`` searches for string ``text`` occurring in the linear view output starting at the virtual address ``start`` until the end of the BinaryView. :param int start: virtual address to start searching from. :param str text: text to search for + :param DisassemblySettings settings: disassembly settings :param FindFlag flags: (optional) defaults to case-insensitive data search ==================== ============================ @@ -5519,6 +5477,7 @@ class BinaryView(object): FindCaseSensitive Case-sensitive search FindCaseInsensitive Case-insensitive search ==================== ============================ + :param FunctionGraphType graph_type: the IL to search wihtin """ if not isinstance(text, str): raise TypeError("text parameter is not str type") @@ -5528,11 +5487,13 @@ class BinaryView(object): raise TypeError("settings parameter is not DisassemblySettings type") result = ctypes.c_ulonglong() - if not core.BNFindNextText(self.handle, start, text, result, settings.handle, flags): + if not core.BNFindNextText(self.handle, start, text, result, settings.handle, flags,\ + graph_type): return None return result.value - def find_next_constant(self, start, constant, settings=None): + def find_next_constant(self, start, constant, settings=None,\ + graph_type = FunctionGraphType.NormalFunctionGraph): """ ``find_next_constant`` searches for integer constant ``constant`` occurring in the linear view output starting at the virtual address ``start`` until the end of the BinaryView. @@ -5540,6 +5501,7 @@ class BinaryView(object): :param int start: virtual address to start searching from. :param int constant: constant to search for :param DisassemblySettings settings: disassembly settings + :param FunctionGraphType graph_type: the IL to search wihtin """ if not isinstance(constant, numbers.Integral): raise TypeError("constant parameter is not integral type") @@ -5549,9 +5511,242 @@ class BinaryView(object): raise TypeError("settings parameter is not DisassemblySettings type") result = ctypes.c_ulonglong() - if not core.BNFindNextConstant(self.handle, start, constant, result, settings.handle): + if not core.BNFindNextConstant(self.handle, start, constant, result, settings.handle,\ + graph_type): return None return result.value + + class QueueGenerator: + def __init__(self, t, results): + self.thread = t + self.results = results + t.start() + + def __iter__(self): + return self + + def __next__(self): + while True: + if not self.results.empty(): + return self.results.get() + + if (not self.thread.is_alive()) and self.results.empty(): + raise StopIteration + + def find_all_data(self, start, end, data, flags = FindFlag.FindCaseSensitive,\ + progress_func = None, match_callback = None): + """ + ``find_all_data`` searches for the bytes ``data`` starting at the virtual address ``start`` + until the virtual address ``end``. Once a match is found, the ``match_callback`` is called. + + :param int start: virtual address to start searching from. + :param int end: virtual address to end the search. + :param Union[bytes, bytearray, str] data: data to search for + :param FindFlag flags: (optional) defaults to case-insensitive data search + + ==================== ============================ + FindFlag Description + ==================== ============================ + FindCaseSensitive Case-sensitive search + FindCaseInsensitive Case-insensitive search + ==================== ============================ + :param callback progress_func: optional function to be called with the current progress + and total count. This function should return a boolean value that decides whether the + search should conitnue or stop + :param callback match_callback: function that gets called when a match is found. The + callback takes two parameters, i.e., the address of the match, and the actual DataBuffer + that satisfies the search. If this parameter is None, this function becomes a generator + and yields a tuple of the matching address and the matched DataBuffer. This function + can return a boolean value that decides whether the search should conitnue or stop + :rtype bool: whether any (one or more) match is found for the search + """ + if not (isinstance(data, bytes) or isinstance(data, bytearray) or isinstance(data, str)): + raise TypeError("data parameter must be bytes, bytearray, or str") + else: + buf = databuffer.DataBuffer(data) + if not isinstance(flags, FindFlag): + raise TypeError('flag parameter must have type FindFlag') + + if progress_func: + progress_func_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, + ctypes.c_ulonglong, ctypes.c_ulonglong)\ + (lambda ctxt, cur, total: progress_func(cur, total)) + else: + progress_func_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, + ctypes.c_ulonglong, ctypes.c_ulonglong)\ + (lambda ctxt, cur, total: True) + + if match_callback: + # the `not match_callback(...) is False` tolerates the users who forget to return + # `True` from inside the callback + match_callback_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, + ctypes.c_ulonglong, ctypes.POINTER(core.BNDataBuffer))\ + (lambda ctxt, addr, match: not match_callback(addr, databuffer.DataBuffer(handle = match)) is False) + return core.BNFindAllDataWithProgress(self.handle, start, end, buf.handle, flags, + None, progress_func_obj, None, match_callback_obj) + else: + results = queue.Queue() + match_callback_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, + ctypes.c_ulonglong, ctypes.POINTER(core.BNDataBuffer))\ + (lambda ctxt, addr, match: + results.put((addr, databuffer.DataBuffer(handle = match))) or True) + + t = threading.Thread(target = lambda: core.BNFindAllDataWithProgress(self.handle, + start, end, buf.handle, flags, None, progress_func_obj, None, match_callback_obj)) + + return self.QueueGenerator(t, results) + + def _LinearDisassemblyLine_convertor(self, lines): + func = None + block = None + line = lines[0] + if line.function: + func = binaryninja.function.Function(self, core.BNNewFunctionReference(line.function)) + if line.block: + block = binaryninja.basicblock.BasicBlock(core.BNNewBasicBlockReference(line.block), self) + color = highlight.HighlightColor._from_core_struct(line.contents.highlight) + addr = line.contents.addr + tokens = binaryninja.function.InstructionTextToken.get_instruction_lines(line.contents.tokens, line.contents.count) + contents = binaryninja.function.DisassemblyTextLine(tokens, addr, color = color) + return binaryninja.lineardisassembly.LinearDisassemblyLine(line.type, func, block, contents) + + def find_all_text(self, start, end, text, settings = None, + flags = FindFlag.FindCaseSensitive, + graph_type = FunctionGraphType.NormalFunctionGraph, progress_func = None, + match_callback = None): + """ + ``find_all_text`` searches for string ``text`` occurring in the linear view output starting + at the virtual address ``start`` until the virtual address ``end``. Once a match is found, + the ``match_callback`` is called. + + :param int start: virtual address to start searching from. + :param int end: virtual address to end the search. + :param str text: text to search for + :param DisassemblySettings settings: DisassemblySettings object used to render the text + to be searched + :param FindFlag flags: (optional) defaults to case-insensitive data search + + ==================== ============================ + FindFlag Description + ==================== ============================ + FindCaseSensitive Case-sensitive search + FindCaseInsensitive Case-insensitive search + ==================== ============================ + :param FunctionGraphType graph_type: the IL to search wihtin + :param callback progress_func: optional function to be called with the current progress + and total count. This function should return a boolean value that decides whether the + search should conitnue or stop + :param callback match_callback: function that gets called when a match is found. The + callback takes three parameters, i.e., the address of the match, and the actual string + that satisfies the search, and the LinearDisassemblyLine that contains the matching + line. If this parameter is None, this function becomes a generator + and yields a tuple of the matching address, the matched string, and the matching + LinearDisassemblyLine. This function can return a boolean value that decides whether + the search should conitnue or stop + :rtype bool: whether any (one or more) match is found for the search + """ + if not isinstance(text, str): + raise TypeError("text parameter is not str type") + if settings is None: + settings = function.DisassemblySettings() + if not isinstance(settings, function.DisassemblySettings): + raise TypeError("settings parameter is not DisassemblySettings type") + if not isinstance(flags, FindFlag): + raise TypeError('flag parameter must have type FindFlag') + + if progress_func: + progress_func_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, + ctypes.c_ulonglong, ctypes.c_ulonglong)\ + (lambda ctxt, cur, total: progress_func(cur, total)) + else: + progress_func_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, + ctypes.c_ulonglong, ctypes.c_ulonglong)\ + (lambda ctxt, cur, total: True) + + if match_callback: + match_callback_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, + ctypes.c_ulonglong, ctypes.c_char_p, + ctypes.POINTER(core.BNLinearDisassemblyLine))\ + (lambda ctxt, addr, match, line: match_callback(addr, match,\ + self._LinearDisassemblyLine_convertor(line)) is False) + + return core.BNFindAllTextWithProgress(self.handle, start, end, text, + settings.handle, flags, graph_type, None, progress_func_obj, None, match_callback_obj) + else: + results = queue.Queue() + match_callback_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, + ctypes.c_ulonglong, ctypes.c_char_p, + ctypes.POINTER(core.BNLinearDisassemblyLine))\ + (lambda ctxt, addr, match, line: results.put((addr, match,\ + self._LinearDisassemblyLine_convertor(line))) or True) + + t = threading.Thread(target = lambda: core.BNFindAllTextWithProgress(self.handle, + start, end, text, settings.handle, flags, graph_type, None, progress_func_obj, None, + match_callback_obj)) + + return self.QueueGenerator(t, results) + + def find_all_constant(self, start, end, constant, settings = None, + graph_type = FunctionGraphType.NormalFunctionGraph, progress_func = None, + match_callback = None): + """ + ``find_all_constant`` searches for the integer constant ``constant`` starting at the + virtual address ``start`` until the virtual address ``end``. Once a match is found, + the ``match_callback`` is called. + + :param int start: virtual address to start searching from. + :param int end: virtual address to end the search. + :param int constant: constant to search for + :param DisassemblySettings settings: DisassemblySettings object used to render the text + to be searched + :param FunctionGraphType graph_type: the IL to search wihtin + :param callback progress_func: optional function to be called with the current progress + and total count. This function should return a boolean value that decides whether the + search should conitnue or stop + :param callback match_callback: function that gets called when a match is found. The + callback takes two parameters, i.e., the address of the match, and the + LinearDisassemblyLine that contains the matching line. If this parameter is None, + this function becomes a generator and yields the the matching address and the + matching LinearDisassemblyLine. This function can return a boolean value that + decides whether the search should conitnue or stop + :rtype bool: whether any (one or more) match is found for the search + """ + if not isinstance(constant, numbers.Integral): + raise TypeError("constant parameter is not integral type") + if settings is None: + settings = function.DisassemblySettings() + if not isinstance(settings, function.DisassemblySettings): + raise TypeError("settings parameter is not DisassemblySettings type") + + if progress_func: + progress_func_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, + ctypes.c_ulonglong, ctypes.c_ulonglong)\ + (lambda ctxt, cur, total: progress_func(cur, total)) + else: + progress_func_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, + ctypes.c_ulonglong, ctypes.c_ulonglong)\ + (lambda ctxt, cur, total: True) + + if match_callback: + match_callback_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p,\ + ctypes.c_ulonglong, ctypes.POINTER(core.BNLinearDisassemblyLine))\ + (lambda ctxt, addr, line: not match_callback(addr,\ + self._LinearDisassemblyLine_convertor(line)) is False) + + return core.BNFindAllConstantWithProgress(self.handle, start, end, constant, + settings.handle, graph_type, None, progress_func_obj, None, match_callback_obj) + else: + results = queue.Queue() + match_callback_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p,\ + ctypes.c_ulonglong, ctypes.POINTER(core.BNLinearDisassemblyLine))\ + (lambda ctxt, addr, line: results.put(addr,\ + self._LinearDisassemblyLine_convertor(line)) or True) + + t = threading.Thread(target = lambda: core.BNFindAllConstantWithProgress(self.handle, + start, end, constant, graph_type, settings.handle, None, progress_func_obj, None,\ + match_callback_obj)) + + return self.QueueGenerator(t, results) def reanalyze(self): """ diff --git a/python/function.py b/python/function.py index 1ea435f8..057f34e8 100644 --- a/python/function.py +++ b/python/function.py @@ -1280,6 +1280,53 @@ class _FunctionAssociatedDataStore(associateddatastore._AssociatedDataStore): _defaults = {} +class AddressRange(object): + def __init__(self, start, end): + self._start = start + self._end = end + + def __repr__(self): + return "<%#x-%#x>" % (self._start, self._end) + + def __len__(self): + return self._end - self.start + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return (self._start, self._end) == (other._start, other._end) + + def __ne__(self, other): + if not isinstance(other, self.__class__): + return NotImplemented + return not (self == other) + + def __hash__(self): + return hash((self._start, self._end)) + + @property + def length(self): + return self._end - self._start + + @property + def start(self): + """ """ + return self._start + + @start.setter + def start(self, value): + self._start = value + + @property + def end(self): + """ """ + return self._end + + @end.setter + def end(self, value): + self._end = value + + class Function(object): _associated_data = {} @@ -1438,12 +1485,23 @@ class Function(object): @property def highest_address(self): """The highest virtual address contained in a function.""" - return max(self, key=lambda block:block.end).end - 1 + return core.BNGetFunctionHighestAddress(self.handle) @property def lowest_address(self): """The lowest virtual address contained in a function.""" - return min(self, key=lambda block:block.start).start + return core.BNGetFunctionLowestAddress(self.handle) + + @property + def address_ranges(self): + """All of the address ranges covered by a function""" + count = ctypes.c_ulonglong(0) + range_list = core.BNGetFunctionAddressRanges(self.handle, count) + result = [] + for i in range(0, count.value): + result.append(AddressRange(range_list[i].start, range_list[i].end)) + core.BNFreeAddressRanges(range_list) + return result @property def symbol(self): @@ -3435,6 +3493,13 @@ class Function(object): core.BNFreeVariableReferenceSourceList(refs, count.value) return result + def get_instruction_containing_address(self, addr, arch = None): + arch = self.arch if arch is None else arch + start = ctypes.c_uint64() + ret = core.BNGetInstructionContainingAddress(self.handle, arch.handle, addr,\ + start) + return ret, start.value + class AdvancedFunctionAnalysisDataRequestor(object): def __init__(self, func = None): diff --git a/suite/testcommon.py b/suite/testcommon.py index 43bf934e..48eeccab 100644 --- a/suite/testcommon.py +++ b/suite/testcommon.py @@ -10,7 +10,8 @@ from binaryninja.binaryview import BinaryViewType, BinaryView from binaryninja.filemetadata import FileMetadata, SaveSettings from binaryninja.datarender import DataRenderer from binaryninja.function import InstructionTextToken, DisassemblyTextLine -from binaryninja.enums import InstructionTextTokenType, SaveOption +from binaryninja.enums import InstructionTextTokenType, SaveOption, FindFlag,\ + FunctionGraphType import subprocess import re @@ -1089,6 +1090,52 @@ class TestBuilder(Builder): self.delete_package("type_xref.bndb") return fixOutput(sorted(retinfo)) + def test_search(self): + """Search""" + retinfo = [] + file_name = self.unpackage_file("type_xref.bndb") + if not os.path.exists(file_name): + return retinfo + + with BinaryViewType.get_view_of_file(file_name) as bv: + if bv is None: + return retinfo + + for addr, match in bv.find_all_data(bv.start, bv.end, b'\xc3'): + retinfo.append('byte 0xc3 is found at address 0x%lx with DataBuffer %s' % + (addr, match.escape())) + + for addr, match, line in bv.find_all_text(bv.start, bv.end, 'test'): + retinfo.append('text "test" is found at address 0x%lx with string %s \ + line %s' % (addr, match, line)) + + for addr, line in bv.find_all_constant(bv.start, bv.end, 0x58): + retinfo.append('constant 0x58 is found at address 0x%lx with line' %\ + (addr, line)) + + def data_callback(addr, match): + retinfo.append('match found at address: 0x%lx with DataBuffer %s' % (addr, match.escape())) + + bv.find_all_data(bv.start, bv.end, b'\xc3', FindFlag.FindCaseSensitive, None, + data_callback) + + def string_callback(addr, match, line): + retinfo.append('match found at address: 0x%lx with string %s, line %s' %\ + (addr, match, line)) + + bv.find_all_text(bv.start, bv.end, 'test', None, FindFlag.FindCaseSensitive, None, + string_callback) + + def constant_callback(addr, line): + retinfo.append('match found at address: 0x%lx with constant 0x58, line %s'\ + % (addr, line)) + + bv.find_all_constant(bv.start, bv.end, 0x58, None,\ + FunctionGraphType.NormalFunctionGraph, None, constant_callback) + + self.delete_package("type_xref.bndb") + return fixOutput(sorted(retinfo)) + class VerifyBuilder(Builder): """ The VerifyBuilder is for tests that verify Binary Ninja against expected output. diff --git a/ui/addressdialog.h b/ui/addressdialog.h index eee9d836..1f67664d 100644 --- a/ui/addressdialog.h +++ b/ui/addressdialog.h @@ -11,31 +11,7 @@ #endif #include "binaryninjaapi.h" #include "uitypes.h" - -#ifdef BINARYNINJAUI_BINDINGS -// QThread has issues working in the bindings on some platforms -class GetSymbolsListThread; -#else -class BINARYNINJAUIAPI GetSymbolsListThread: public QThread -{ - Q_OBJECT - - QStringList m_allSymbols; - std::function<void()> m_completeFunc; - std::mutex m_mutex; - bool m_done; - BinaryViewRef m_view; - -protected: - virtual void run() override; - -public: - GetSymbolsListThread(BinaryViewRef view, const std::function<void()>& completeFunc); - void cancel(); - - const QStringList& getSymbols() const { return m_allSymbols; } -}; -#endif +#include "getsymbolslistthread.h" class BINARYNINJAUIAPI AddressDialogWithPreview: public QDialog diff --git a/ui/expandablegroup.h b/ui/expandablegroup.h new file mode 100644 index 00000000..164651f6 --- /dev/null +++ b/ui/expandablegroup.h @@ -0,0 +1,27 @@ +#pragma once + +#include "uitypes.h" +#include <QtWidgets/QToolButton> +#include <QtCore/QParallelAnimationGroup> +#include <QtWidgets/QScrollArea> +#include <QtCore/QPropertyAnimation> + +class BINARYNINJAUIAPI ExpandableGroup : public QWidget +{ + Q_OBJECT + +private: + QToolButton* m_button; + QParallelAnimationGroup* m_animation; + QScrollArea* m_content; + int m_duration = 100; + +private Q_SLOTS: + void toggled(bool expanded); + +public: + explicit ExpandableGroup(const QString& title = "", QWidget* parent = nullptr); + void setContentLayout(QLayout* contentLayout); + void setTitle(const QString& title) { m_button->setText(title); } + void toggle(bool expanded); +}; diff --git a/ui/getsymbolslistthread.h b/ui/getsymbolslistthread.h new file mode 100644 index 00000000..b806448a --- /dev/null +++ b/ui/getsymbolslistthread.h @@ -0,0 +1,37 @@ +#pragma once + +#ifndef BINARYNINJAUI_BINDINGS +#include <QtCore/QThread> +#include <QtCore/QEvent> +#endif +#include "binaryninjaapi.h" +#include "uitypes.h" + + +#ifdef BINARYNINJAUI_BINDINGS +// QThread has issues working in the bindings on some platforms +class GetSymbolsListThread; +#else +class BINARYNINJAUIAPI GetSymbolsListThread: public QThread +{ + Q_OBJECT + + QStringList m_allSymbols; + std::function<void()> m_completeFunc; + std::mutex m_mutex; + bool m_done; + BinaryViewRef m_view; + +protected: + virtual void run() override; + +public: + GetSymbolsListThread(BinaryViewRef view, const std::function<void()>& completeFunc); + void cancel(); + + static int m_eventType; + int GetEventType() { return GetSymbolsListThread::m_eventType; } + + const QStringList& getSymbols() const { return m_allSymbols; } +}; +#endif diff --git a/ui/searchresult.h b/ui/searchresult.h new file mode 100644 index 00000000..5905ae0d --- /dev/null +++ b/ui/searchresult.h @@ -0,0 +1,267 @@ +#pragma once + +#include <QtCore/QAbstractItemModel> +#include <QtCore/QItemSelectionModel> +#include <QtCore/QSortFilterProxyModel> +#include <QtCore/QModelIndex> +#include <QtCore/QThread> +#include <QtWidgets/QTableView> +#include <QtWidgets/QTabWidget> +#include <QtWidgets/QStyledItemDelegate> +#include <QtWidgets/QDialog> +#include <QtWidgets/QProgressBar> +#include <QtWidgets/QToolButton> +#include "binaryninjaapi.h" +#include "dockhandler.h" +#include "viewframe.h" +#include "filter.h" +#include "expandablegroup.h" + +#define FIND_RESULT_LIST_UPDATE_INTERVAL 250 +#define COLUMN_MIN_WIDTH_IN_CHAR 10 +#define COLUMN_MAX_WIDTH_IN_CHAR 30 + +class CachedTokens +{ +public: + QVariant tokens; + QVariant flattenedTokens; + bool valid; + + CachedTokens(): valid(false) {} + CachedTokens(const CachedTokens& other): + tokens(other.tokens), flattenedTokens(other.flattenedTokens), valid(other.valid) + {} +}; + + +class SearchResultItem +{ +private: + uint64_t m_addr; + BinaryNinja::DataBuffer m_buffer; + FunctionRef m_func; + CachedTokens m_tokensCache[4]; + +public: + SearchResultItem(); + SearchResultItem(uint64_t addr, const BinaryNinja::DataBuffer& buffer, + FunctionRef func); + SearchResultItem(uint64_t addr, const BinaryNinja::DataBuffer& buffer, + FunctionRef func, const BinaryNinja::DisassemblyTextLine& line, QWidget* owner); + SearchResultItem(const SearchResultItem& other); + uint64_t addr() const { return m_addr; } + BinaryNinja::DataBuffer buffer() const { return m_buffer; } + FunctionRef func() const { return m_func; } + bool operator==(const SearchResultItem& other) const { return m_addr == other.addr(); } + bool operator!=(const SearchResultItem& other) const { return m_addr != other.addr(); } + bool operator<(const SearchResultItem& other) const { return m_addr < other.addr(); } + + CachedTokens getCachedTokens(size_t i) const; + CachedTokens& getCachedTokens(size_t i); + void setCachedTokens(size_t i, QVariant tokens, QVariant flattenedTokens); +}; + +Q_DECLARE_METATYPE(SearchResultItem); + + +class BINARYNINJAUIAPI SearchResultModel: public QAbstractTableModel +{ + Q_OBJECT + +protected: + QWidget* m_owner; + BinaryViewRef m_data; + ViewFrame* m_view; + BinaryNinja::FindParameters m_params; + std::vector<SearchResultItem> m_refs; + mutable size_t m_columnWidths[4]; + // if this value is true, it means the user has overriden the automatically calculated width + // of the coumn, and we should not resize it anymore + bool m_userColumnWidth[4]; + + std::mutex m_updateMutex; + std::set<SearchResultItem> m_pendingSearchResults; + +public: + enum ColumnHeaders + { + AddressColumn = 0, + DataColumn = 1, + FunctionColumn = 2, + PreviewColumn = 3, + EndOfColumn = 4 + }; + + SearchResultModel(QWidget* parent, BinaryViewRef data, ViewFrame* view); + virtual ~SearchResultModel(); + + virtual QModelIndex index(int row, int col, const QModelIndex& parent = QModelIndex()) const override; + + void reset(); + virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override { (void) parent; return (int)m_refs.size(); } + virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override { (void) parent; return 4; } + SearchResultItem getRow(int row) const; + virtual QVariant data(const QModelIndex& i, int role) const override; + virtual QVariant headerData(int column, Qt::Orientation orientation, int role) const override; + void addItem(const SearchResultItem& addr); + void clear(); + void updateFindParameters(const BinaryNinja::FindParameters params); + void updateSearchResults(); + + size_t getColumnWidth(size_t column) const; + // This function is marked as const, but it actually modifies the mutable member m_columnWidths. + // It is called in SearchResultModel::data(), which is const. So it has to be const as well. + void updateColumnWidth(size_t column, size_t size) const; + void resetColumnWidth(); + + bool isUserColumnWidth(size_t column) const; + void setUserColumnWidth(size_t column); +}; + + +class BINARYNINJAUIAPI SearchResultFilterProxyModel: public QSortFilterProxyModel +{ + Q_OBJECT + +public: + SearchResultFilterProxyModel(QObject* parent); + virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; + virtual bool lessThan(const QModelIndex& left, const QModelIndex& right) const override; + virtual QVariant data(const QModelIndex& idx, int role) const override; +}; + + +class BINARYNINJAUIAPI SearchResultItemDelegate: public QStyledItemDelegate +{ + Q_OBJECT + + QFont m_font; + int m_baseline, m_charWidth, m_charHeight, m_charOffset; + +public: + SearchResultItemDelegate(QWidget* parent); + void updateFonts(); + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& idx) const; +}; + +class SearchResultWidget; +class BINARYNINJAUIAPI SearchResultTable: public QTableView +{ + Q_OBJECT + + ViewFrame* m_view; + SearchResultModel* m_table; + SearchResultFilterProxyModel* m_model; + SearchResultItemDelegate* m_itemDelegate; + BinaryViewRef m_data; + BinaryNinja::FindParameters m_params; + UIActionHandler m_actionHandler; + QTimer* m_updateTimer; + + int m_charWidth, m_charHeight; + + bool m_cacheThreadShouldExit; + +public: + SearchResultTable(SearchResultWidget* parent, ViewFrame* view, BinaryViewRef data); + virtual ~SearchResultTable(); + + void addSearchResult(const SearchResultItem& addr); + void updateFindParameters(const BinaryNinja::FindParameters& params); + void clearSearchResult(); + + void updateFonts(); + void updateHeaderFontAndSize(); + + virtual void keyPressEvent(QKeyEvent* e) override; + + virtual bool hasSelection() const { return selectionModel()->selectedRows().size() != 0; } + virtual QModelIndexList selectedRows() const { return selectionModel()->selectedRows(); } + + void goToResult(const QModelIndex& idx); + + int rowCount() const; + int filteredCount() const; + + void updateColumnWidth(); + void resetColumnWidth(); + + void cacheTokens(); + void terminateCacheThread() { m_cacheThreadShouldExit = true; } + + SearchResultModel* model() const { return m_table; } + +public Q_SLOTS: + void resultActivated(const QModelIndex& idx); + void updateFilter(const QString& filterText); + void updateTimerEvent(); + void columnResized(int logicalIndex, int oldSize, int newSize); + +Q_SIGNALS: + void newSelection(); +}; + +class SearchProgressBar; +class BINARYNINJAUIAPI SearchResultWidget: public QWidget, public DockContextHandler +{ + Q_OBJECT + Q_INTERFACES(DockContextHandler) + + ViewFrame* m_view; + BinaryViewRef m_data; + SearchResultTable* m_table; + QLabel* m_label; + QLineEdit* m_lineEdit; + ExpandableGroup* m_group; + SearchProgressBar* m_progress; + BinaryNinja::FindParameters m_params; + QThread* m_tokenCacheThread = nullptr; + + virtual void contextMenuEvent(QContextMenuEvent* event) override; + +public: + SearchResultWidget(ViewFrame* frame, BinaryViewRef data); + ~SearchResultWidget(); + + virtual void notifyFontChanged() override; + + void startNewFind(const BinaryNinja::FindParameters& params); + virtual QString getHeaderText(); + + void addSearchResult(uint64_t addr, const BinaryNinja::DataBuffer& match); + void addSearchResult(uint64_t addr, const BinaryNinja::DataBuffer& match, + const BinaryNinja::LinearDisassemblyLine& line); + void clearSearchResult(); + bool updateProgress(uint64_t cur, uint64_t total); + void notifySearchCompleted(); + void cacheTokens(); + void terminateCacheThread(); + bool isSearchActive() const; + +public Q_SLOTS: + void updateTotal(); +}; + + +class BINARYNINJAUIAPI SearchProgressBar: public QWidget +{ + Q_OBJECT + +private: + QProgressBar* m_progress; + QToolButton* m_cancel; + bool m_maxSet; + bool m_running; + // The minimal duration (in milliseconds) the progress bar must last, before it is displayed + int m_minimalDuration; + std::chrono::steady_clock::time_point m_lastUpdate; + +public: + explicit SearchProgressBar(QWidget* parent = nullptr); + bool updateProgress(uint64_t cur, uint64_t total); + void init(); + void reset(); + void show(); + bool isRunning() const { return m_running; } +}; diff --git a/ui/typeview.h b/ui/typeview.h index b24e3df9..b9dab368 100644 --- a/ui/typeview.h +++ b/ui/typeview.h @@ -159,7 +159,7 @@ public: virtual bool findNextData(uint64_t start, uint64_t end, const BinaryNinja::DataBuffer& data, uint64_t& addr, BNFindFlag flags, const std::function<bool (size_t current, size_t total)>& cb) override; virtual bool findNextText(uint64_t start, uint64_t end, const std::string& text, uint64_t& addr, - DisassemblySettingsRef settings, BNFindFlag flags, + DisassemblySettingsRef settings, BNFindFlag flags, BNFunctionGraphType graph, const std::function<bool (size_t current, size_t total)>& cb) override; virtual BinaryViewRef getData() override { return m_data; } virtual uint64_t getCurrentOffset() override; diff --git a/ui/viewframe.h b/ui/viewframe.h index 36072430..4d1ebf32 100644 --- a/ui/viewframe.h +++ b/ui/viewframe.h @@ -14,6 +14,7 @@ #include <stack> #include <utility> #include <vector> +#include "binaryninjaapi.h" #include "filecontext.h" #include "viewtype.h" #include "action.h" @@ -78,6 +79,7 @@ class FeatureMap; class StatusBarWidget; class ViewNavigationMode; class TransformParameterDialog; +// struct BinaryNinjaCore::LinearDisassemblyLine; class BINARYNINJAUIAPI View @@ -109,14 +111,31 @@ public: virtual bool canAssemble() { return false; } virtual bool canCompile() { return false; } - virtual bool findNextData(uint64_t start, uint64_t end, const BinaryNinja::DataBuffer& data, uint64_t& addr, BNFindFlag flags, + virtual bool findNextData(uint64_t start, uint64_t end, const BinaryNinja::DataBuffer& data, + uint64_t& addr, BNFindFlag flags, const std::function<bool (size_t current, size_t total)>& cb); - virtual bool findNextText(uint64_t start, uint64_t end, const std::string& text, uint64_t& addr, - DisassemblySettingsRef settings, BNFindFlag flags, + virtual bool findNextText(uint64_t start, uint64_t end, const std::string& text, + uint64_t& addr, DisassemblySettingsRef settings, BNFindFlag flags, + BNFunctionGraphType graph, const std::function<bool (size_t current, size_t total)>& cb); - virtual bool findNextConstant(uint64_t start, uint64_t end, uint64_t constant, uint64_t& addr, DisassemblySettingsRef settings, + virtual bool findNextConstant(uint64_t start, uint64_t end, uint64_t constant, + uint64_t& addr, DisassemblySettingsRef settings, BNFunctionGraphType graph, const std::function<bool (size_t current, size_t total)>& cb); + virtual bool findAllData(uint64_t start, uint64_t end, const BinaryNinja::DataBuffer& data, BNFindFlag flags, + const std::function<bool (size_t current, size_t total)>& cb, + const std::function<bool (uint64_t addr, const BinaryNinja::DataBuffer& match)>& matchCallback); + virtual bool findAllText(uint64_t start, uint64_t end, const std::string& data, + DisassemblySettingsRef settings, BNFindFlag flags, BNFunctionGraphType graph, + const std::function<bool (size_t current, size_t total)>& cb, + const std::function<bool (uint64_t addr, const std::string& match, + const BinaryNinja::LinearDisassemblyLine& line)>& matchCallback); + virtual bool findAllConstant(uint64_t start, uint64_t end, uint64_t constant, + DisassemblySettingsRef settings, BNFunctionGraphType graph, + const std::function<bool (size_t current, size_t total)>& cb, + const std::function<bool (uint64_t addr, + const BinaryNinja::LinearDisassemblyLine& line)>& matchCallback); + virtual BinaryViewRef getData() = 0; virtual uint64_t getCurrentOffset() = 0; virtual BNAddressRange getSelectionOffsets(); @@ -307,12 +326,12 @@ public: QString getShortFileName(); std::vector<QString> getAvailableTypes() const; - QString getCurrentView(); - QString getCurrentDataType(); - uint64_t getCurrentOffset(); - BNAddressRange getSelectionOffsets(); + QString getCurrentView() const; + QString getCurrentDataType() const; + uint64_t getCurrentOffset() const; + BNAddressRange getSelectionOffsets() const; - ViewLocation getViewLocation(); + ViewLocation getViewLocation() const; void setViewLocation(const ViewLocation& viewLocation); View* getCurrentViewInterface() const { return View::getViewFromWidget(m_view); } @@ -335,9 +354,9 @@ public: bool goToReference(BinaryViewRef data, FunctionRef func, uint64_t source, uint64_t target, bool addHistoryEntry = true); bool navigateToViewLocation(BinaryViewRef data, const ViewLocation& viewLocation, bool addHistoryEntry = true); - QString getTypeForView(QWidget* view); - QString getDataTypeForView(const QString& type); - QString getDataTypeForView(QWidget* view); + QString getTypeForView(QWidget* view) const; + QString getDataTypeForView(const QString& type) const; + QString getDataTypeForView(QWidget* view) const; bool closeRequest(); void closing(); @@ -367,6 +386,13 @@ public: void nextTag(); void prevTag(); + void startNewFind(const BinaryNinja::FindParameters& params); + bool updateSearchProgress(uint64_t cur, uint64_t total); + void notifySearchCompleted(); + void addSearchResult(uint64_t addr, const BinaryNinja::DataBuffer& match); + void addSearchResult(uint64_t addr, const BinaryNinja::DataBuffer& match, + const BinaryNinja::LinearDisassemblyLine& line); + virtual UIActionContext actionContext(); void bindActions(); static void registerActions(); diff --git a/ui/xreflist.h b/ui/xreflist.h index 625d384e..d603c599 100644 --- a/ui/xreflist.h +++ b/ui/xreflist.h @@ -5,7 +5,6 @@ #include <QtCore/QSortFilterProxyModel> #include <QtCore/QModelIndex> #include <QtGui/QImage> -#include <QtCore/QParallelAnimationGroup> #include <QtWidgets/QListView> #include <QtWidgets/QStyledItemDelegate> #include <QtWidgets/QTreeView> @@ -15,8 +14,6 @@ #include <QtWidgets/QCheckBox> #include <QtWidgets/QFrame> #include <QtWidgets/QGridLayout> -#include <QtWidgets/QScrollArea> -#include <QtWidgets/QToolButton> #include <vector> #include <deque> @@ -26,6 +23,7 @@ #include "dockhandler.h" #include "viewframe.h" #include "fontsettings.h" +#include "expandablegroup.h" class XrefHeader; class XrefItem @@ -524,27 +522,6 @@ public Q_SLOTS: }; -class BINARYNINJAUIAPI ExpandableGroup : public QWidget -{ - Q_OBJECT - -private: - QToolButton* m_button; - QParallelAnimationGroup* m_animation; - QScrollArea* m_content; - int m_duration = 100; - -private Q_SLOTS: - void toggled(bool expanded); - -public: - explicit ExpandableGroup(const QString& title = "", QWidget* parent = nullptr); - void setContentLayout(QLayout* contentLayout); - void setTitle(const QString& title) { m_button->setText(title); } - void toggle(bool expanded); -}; - - // https://github.com/CuriousCrow/QCheckboxCombo /* * QCheckboxCombo is a combobox widget that contains items with checkboxes |
