summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--basicblock.cpp6
-rw-r--r--binaryninjaapi.h61
-rw-r--r--binaryninjacore.h79
-rw-r--r--binaryview.cpp117
-rw-r--r--function.cpp31
-rw-r--r--linearviewcursor.cpp17
-rw-r--r--linearviewobject.cpp37
-rw-r--r--python/basicblock.py5
-rw-r--r--python/binaryview.py299
-rw-r--r--python/function.py69
-rw-r--r--suite/testcommon.py49
-rw-r--r--ui/addressdialog.h26
-rw-r--r--ui/expandablegroup.h27
-rw-r--r--ui/getsymbolslistthread.h37
-rw-r--r--ui/searchresult.h267
-rw-r--r--ui/typeview.h2
-rw-r--r--ui/viewframe.h50
-rw-r--r--ui/xreflist.h25
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