summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binaryninjaapi.h166
-rw-r--r--binaryninjacore.h94
-rw-r--r--binaryview.cpp58
-rw-r--r--highlevelil.cpp22
-rw-r--r--highlevelilinstruction.cpp18
-rw-r--r--highlevelilinstruction.h4
-rw-r--r--python/__init__.py1
-rw-r--r--python/binaryview.py188
-rw-r--r--python/examples/encoded_strings.py25
-rw-r--r--python/highlevelil.py24
-rw-r--r--python/stringrecognizer.py293
-rw-r--r--rust/src/disassembly.rs6
-rw-r--r--stringrecognizer.cpp300
-rw-r--r--ui/stringsview.h2
14 files changed, 1180 insertions, 21 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index 96105e66..ecdeabdf 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -4074,6 +4074,7 @@ namespace BinaryNinja {
class Segment;
class Component;
class TypeArchive;
+ struct DerivedString;
/*!
@@ -4107,6 +4108,8 @@ namespace BinaryNinja {
static void StringFoundCallback(void* ctxt, BNBinaryView* data, BNStringType type, uint64_t offset, size_t len);
static void StringRemovedCallback(void* ctxt, BNBinaryView* data, BNStringType type, uint64_t offset, size_t len);
+ static void DerivedStringFoundCallback(void* ctxt, BNBinaryView* data, BNDerivedString* str);
+ static void DerivedStringRemovedCallback(void* ctxt, BNBinaryView* data, BNDerivedString* str);
static void TypeDefinedCallback(void* ctxt, BNBinaryView* data, BNQualifiedName* name, BNType* type);
static void TypeUndefinedCallback(void* ctxt, BNBinaryView* data, BNQualifiedName* name, BNType* type);
static void TypeReferenceChangedCallback(void* ctx, BNBinaryView* data, BNQualifiedName* name, BNType* type);
@@ -4203,6 +4206,8 @@ namespace BinaryNinja {
UndoEntryTaken = 1ULL << 50,
RedoEntryTaken = 1ULL << 51,
Rebased = 1ULL << 52,
+ DerivedStringFound = 1ULL << 53,
+ DerivedStringRemoved = 1ULL << 54,
BinaryDataUpdates = DataWritten | DataInserted | DataRemoved,
FunctionLifetime = FunctionAdded | FunctionRemoved,
@@ -4213,7 +4218,7 @@ namespace BinaryNinja {
TagUpdates = TagLifetime | TagUpdated,
SymbolLifetime = SymbolAdded | SymbolRemoved,
SymbolUpdates = SymbolLifetime | SymbolUpdated,
- StringUpdates = StringFound | StringRemoved,
+ StringUpdates = StringFound | StringRemoved | DerivedStringFound | DerivedStringRemoved,
TypeLifetime = TypeDefined | TypeUndefined,
TypeUpdates = TypeLifetime | TypeReferenceChanged | TypeFieldReferenceChanged,
SegmentLifetime = SegmentAdded | SegmentRemoved,
@@ -4350,6 +4355,16 @@ namespace BinaryNinja {
(void)offset;
(void)len;
}
+ virtual void OnDerivedStringFound(BinaryView* data, const DerivedString& str)
+ {
+ (void)data;
+ (void)str;
+ }
+ virtual void OnDerivedStringRemoved(BinaryView* data, const DerivedString& str)
+ {
+ (void)data;
+ (void)str;
+ }
virtual void OnTypeDefined(BinaryView* data, const QualifiedName& name, Type* type)
{
(void)data;
@@ -4823,7 +4838,7 @@ namespace BinaryNinja {
const char* c_str() const;
size_t size() const;
- BNStringRef* GetObject() { return m_ref; }
+ BNStringRef* GetObject() const { return m_ref; }
bool operator==(const StringRef& other) const { return this->operator std::string_view() == other.operator std::string_view(); }
bool operator!=(const StringRef& other) const { return this->operator std::string_view() != other.operator std::string_view(); }
@@ -5357,6 +5372,89 @@ namespace BinaryNinja {
std::vector<TypeReferenceSource> typeRefs;
};
+ class CustomStringType: public StaticCoreRefCountObject<BNCustomStringType>
+ {
+ public:
+ CustomStringType(BNCustomStringType* type);
+ std::string GetName() const;
+ std::string GetStringPrefix() const;
+ std::string GetStringPostfix() const;
+
+ static Ref<CustomStringType> Register(
+ const std::string& name, const std::string& stringPrefix = "", const std::string& stringPostfix = "");
+ };
+
+ struct DerivedStringLocation
+ {
+ BNDerivedStringLocationType locationType;
+ uint64_t addr;
+ uint64_t len;
+
+ bool operator==(const DerivedStringLocation& other) const
+ {
+ if (locationType != other.locationType)
+ return false;
+ if (addr != other.addr)
+ return false;
+ return len == other.len;
+ }
+
+ bool operator!=(const DerivedStringLocation& other) const
+ {
+ return !(*this == other);
+ }
+
+ bool operator<(const DerivedStringLocation& other) const
+ {
+ if (addr < other.addr)
+ return true;
+ if (addr > other.addr)
+ return false;
+ if (len < other.len)
+ return true;
+ if (len > other.len)
+ return false;
+ return locationType < other.locationType;
+ }
+ };
+
+ struct DerivedString
+ {
+ StringRef value;
+ std::optional<DerivedStringLocation> location;
+ Ref<CustomStringType> customType;
+
+ bool operator==(const DerivedString& other) const
+ {
+ if (value != other.value)
+ return false;
+ if (location != other.location)
+ return false;
+ return customType == other.customType;
+ }
+
+ bool operator!=(const DerivedString& other) const
+ {
+ return !(*this == other);
+ }
+
+ bool operator<(const DerivedString& other) const
+ {
+ if (value < other.value)
+ return true;
+ if (other.value < value)
+ return false;
+ if (location < other.location)
+ return true;
+ if (other.location < location)
+ return false;
+ return customType < other.customType;
+ }
+
+ BNDerivedString ToAPIObject(bool owned) const;
+ static DerivedString FromAPIObject(BNDerivedString* str, bool owned);
+ };
+
struct QualifiedNameAndType;
struct PossibleValueSet;
class Metadata;
@@ -7132,6 +7230,10 @@ namespace BinaryNinja {
*/
std::vector<BNStringReference> GetStrings(uint64_t start, uint64_t len);
+ std::vector<DerivedString> GetDerivedStrings();
+ std::vector<ReferenceSource> GetDerivedStringCodeReferences(
+ const DerivedString& str, std::optional<size_t> maxItems = std::nullopt);
+
/*! Sets up a call back function to be called when analysis has been completed.
This is helpful when using `UpdateAnalysis` which does not wait for analysis completion before returning.
@@ -15441,6 +15543,10 @@ namespace BinaryNinja {
std::set<Variable> GetVariables();
std::set<Variable> GetAliasedVariables();
std::set<SSAVariable> GetSSAVariables();
+
+ void SetDerivedStringReferenceForExpr(size_t expr, const DerivedString& str);
+ void RemoveDerivedStringReferenceForExpr(size_t expr);
+ std::optional<DerivedString> GetDerivedStringReferenceForExpr(size_t expr);
};
struct LineFormatterSettings
@@ -21326,6 +21432,62 @@ namespace BinaryNinja {
HighLevelILTokenEmitter& tokens, DisassemblySettings* settings, BNSymbolDisplayType symbolDisplay,
BNOperatorPrecedence precedence) override;
};
+
+ class StringRecognizer : public StaticCoreRefCountObject<BNStringRecognizer>
+ {
+ std::string m_nameForRegister;
+
+ public:
+ StringRecognizer(const std::string& name);
+ StringRecognizer(BNStringRecognizer* renderer);
+
+ std::string GetName() const;
+
+ virtual bool IsValidForType(HighLevelILFunction* func, Type* type);
+ virtual std::optional<DerivedString> RecognizeConstant(
+ const HighLevelILInstruction& instr, Type* type, int64_t val);
+ virtual std::optional<DerivedString> RecognizeConstantPointer(
+ const HighLevelILInstruction& instr, Type* type, int64_t val);
+ virtual std::optional<DerivedString> RecognizeExternPointer(
+ const HighLevelILInstruction& instr, Type* type, int64_t val, uint64_t offset);
+ virtual std::optional<DerivedString> RecognizeImport(
+ const HighLevelILInstruction& instr, Type* type, int64_t val);
+
+ /*! Registers the string recognizer.
+
+ \param recognizer The string recognizer to register.
+ */
+ static void Register(StringRecognizer* recognizer);
+
+ static Ref<StringRecognizer> GetByName(const std::string& name);
+ static std::vector<Ref<StringRecognizer>> GetRecognizers();
+
+ private:
+ static bool IsValidForTypeCallback(void* ctxt, BNHighLevelILFunction* hlil, BNType* type);
+ static bool RecognizeConstantCallback(
+ void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type, int64_t val, BNDerivedString* result);
+ static bool RecognizeConstantPointerCallback(
+ void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type, int64_t val, BNDerivedString* result);
+ static bool RecognizeExternPointerCallback(void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type,
+ int64_t val, uint64_t offset, BNDerivedString* result);
+ static bool RecognizeImportCallback(
+ void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type, int64_t val, BNDerivedString* result);
+ };
+
+ class CoreStringRecognizer : public StringRecognizer
+ {
+ public:
+ CoreStringRecognizer(BNStringRecognizer* recognizer);
+ bool IsValidForType(HighLevelILFunction* func, Type* type) override;
+ std::optional<DerivedString> RecognizeConstant(
+ const HighLevelILInstruction& instr, Type* type, int64_t val) override;
+ std::optional<DerivedString> RecognizeConstantPointer(
+ const HighLevelILInstruction& instr, Type* type, int64_t val) override;
+ std::optional<DerivedString> RecognizeExternPointer(
+ const HighLevelILInstruction& instr, Type* type, int64_t val, uint64_t offset) override;
+ std::optional<DerivedString> RecognizeImport(
+ const HighLevelILInstruction& instr, Type* type, int64_t val) override;
+ };
} // namespace BinaryNinja
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 89037998..3e34662c 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -37,14 +37,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 137
+#define BN_CURRENT_CORE_ABI_VERSION 138
// 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 136
+#define BN_MINIMUM_CORE_ABI_VERSION 138
#ifdef __GNUC__
#ifdef BINARYNINJACORE_LIBRARY
@@ -312,6 +312,8 @@ extern "C"
typedef struct BNIndirectBranchInfo BNIndirectBranchInfo;
typedef struct BNArchitectureAndAddress BNArchitectureAndAddress;
typedef struct BNConstantRenderer BNConstantRenderer;
+ typedef struct BNStringRecognizer BNStringRecognizer;
+ typedef struct BNCustomStringType BNCustomStringType;
typedef struct BNRemoteFileSearchMatch
{
@@ -468,7 +470,8 @@ extern "C"
StringDisplayTokenContext = 10, // For displaying strings which aren't associated with an address
ContentCollapsedContext = 11,
ContentExpandedContext = 12,
- ContentCollapsiblePadding = 13
+ ContentCollapsiblePadding = 13,
+ DerivedStringReferenceTokenContext = 14
} BNInstructionTextTokenContext;
typedef enum BNLinearDisassemblyLineType
@@ -1639,6 +1642,27 @@ extern "C"
size_t nameCount;
} BNQualifiedName;
+ typedef enum BNDerivedStringLocationType
+ {
+ DataBackedStringLocation,
+ CodeStringLocation
+ } BNDerivedStringLocationType;
+
+ typedef struct BNDerivedStringLocation
+ {
+ BNDerivedStringLocationType locationType;
+ uint64_t addr;
+ uint64_t len;
+ } BNDerivedStringLocation;
+
+ typedef struct BNDerivedString
+ {
+ BNStringRef* value;
+ bool locationValid;
+ BNDerivedStringLocation location;
+ BNCustomStringType* customType;
+ } BNDerivedString;
+
typedef struct BNBinaryDataNotification
{
void* context;
@@ -1664,6 +1688,8 @@ extern "C"
void (*symbolUpdated)(void* ctxt, BNBinaryView* view, BNSymbol* sym);
void (*stringFound)(void* ctxt, BNBinaryView* view, BNStringType type, uint64_t offset, size_t len);
void (*stringRemoved)(void* ctxt, BNBinaryView* view, BNStringType type, uint64_t offset, size_t len);
+ void (*derivedStringFound)(void* ctxt, BNBinaryView* view, BNDerivedString* str);
+ void (*derivedStringRemoved)(void* ctxt, BNBinaryView* view, BNDerivedString* str);
void (*typeDefined)(void* ctxt, BNBinaryView* view, BNQualifiedName* name, BNType* type);
void (*typeUndefined)(void* ctxt, BNBinaryView* view, BNQualifiedName* name, BNType* type);
void (*typeReferenceChanged)(void* ctxt, BNBinaryView* view, BNQualifiedName* name, BNType* type);
@@ -3826,6 +3852,27 @@ extern "C"
BNOperatorPrecedence precedence);
} BNCustomConstantRenderer;
+ typedef struct BNCustomStringRecognizer
+ {
+ void* context;
+ bool (*isValidForType)(void* ctxt, BNHighLevelILFunction* hlil, BNType* type);
+ bool (*recognizeConstant)(
+ void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type, int64_t val, BNDerivedString* result);
+ bool (*recognizeConstantPointer)(
+ void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type, int64_t val, BNDerivedString* result);
+ bool (*recognizeExternPointer)(void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type, int64_t val,
+ uint64_t offset, BNDerivedString* result);
+ bool (*recognizeImport)(
+ void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type, int64_t val, BNDerivedString* result);
+ } BNCustomStringRecognizer;
+
+ typedef struct BNCustomStringTypeInfo
+ {
+ char* name;
+ char* stringPrefix;
+ char* stringPostfix;
+ } BNCustomStringTypeInfo;
+
BINARYNINJACOREAPI char* BNAllocString(const char* contents);
BINARYNINJACOREAPI char* BNAllocStringWithLength(const char* contents, size_t len);
BINARYNINJACOREAPI void BNFreeString(char* str);
@@ -5273,6 +5320,11 @@ extern "C"
BNBinaryView* view, uint64_t start, uint64_t len, size_t* count);
BINARYNINJACOREAPI void BNFreeStringReferenceList(BNStringReference* strings);
+ BINARYNINJACOREAPI BNDerivedString* BNGetDerivedStrings(BNBinaryView* view, size_t* count);
+ BINARYNINJACOREAPI BNReferenceSource* BNGetDerivedStringCodeReferences(
+ BNBinaryView* view, BNDerivedString* str, size_t* count, bool limit, size_t maxItems);
+ BINARYNINJACOREAPI void BNFreeDerivedStringList(BNDerivedString* strings, size_t count);
+
BINARYNINJACOREAPI BNVariableNameAndType* BNGetStackLayout(BNFunction* func, size_t* count);
BINARYNINJACOREAPI void BNFreeVariableNameAndTypeList(BNVariableNameAndType* vars, size_t count);
BINARYNINJACOREAPI void BNCreateAutoStackVariable(
@@ -6577,6 +6629,12 @@ extern "C"
BINARYNINJACOREAPI bool BNHighLevelILExprEqual(
BNHighLevelILFunction* leftFunc, size_t leftExpr, BNHighLevelILFunction* rightFunc, size_t rightExpr);
+ BINARYNINJACOREAPI void BNSetHighLevelILDerivedStringReferenceForExpr(
+ BNHighLevelILFunction* func, size_t expr, BNDerivedString* str);
+ BINARYNINJACOREAPI void BNRemoveHighLevelILDerivedStringReferenceForExpr(BNHighLevelILFunction* func, size_t expr);
+ BINARYNINJACOREAPI bool BNGetHighLevelILDerivedStringReferenceForExpr(
+ BNHighLevelILFunction* func, size_t expr, BNDerivedString* out);
+
// Type Libraries
BINARYNINJACOREAPI BNTypeLibrary* BNNewTypeLibrary(BNArchitecture* arch, const char* name);
BINARYNINJACOREAPI BNTypeLibrary* BNNewTypeLibraryReference(BNTypeLibrary* lib);
@@ -8701,13 +8759,15 @@ extern "C"
BINARYNINJACOREAPI BNStringRef* BNDuplicateStringRef(BNStringRef* ref);
BINARYNINJACOREAPI const char* BNGetStringRefContents(BNStringRef* ref);
BINARYNINJACOREAPI size_t BNGetStringRefSize(BNStringRef* ref);
+ BINARYNINJACOREAPI BNStringRef* BNCreateStringRef(const char* str);
+ BINARYNINJACOREAPI BNStringRef* BNCreateStringRefOfLength(const char* str, size_t len);
// Constant Renderers
BINARYNINJACOREAPI BNConstantRenderer* BNRegisterConstantRenderer(
const char* name, BNCustomConstantRenderer* renderer);
BINARYNINJACOREAPI BNConstantRenderer* BNGetConstantRendererByName(const char* name);
BINARYNINJACOREAPI BNConstantRenderer** BNGetConstantRendererList(size_t* count);
- BINARYNINJACOREAPI void BNFreeConstantRendererList(BNLanguageRepresentationFunctionType** renderers);
+ BINARYNINJACOREAPI void BNFreeConstantRendererList(BNConstantRenderer** renderers);
BINARYNINJACOREAPI char* BNGetConstantRendererName(BNConstantRenderer* renderer);
BINARYNINJACOREAPI bool BNIsConstantRendererValidForType(
BNConstantRenderer* renderer, BNHighLevelILFunction* il, BNType* type);
@@ -8718,6 +8778,32 @@ extern "C"
BNHighLevelILFunction* il, size_t exprIndex, BNType* type, int64_t val, BNHighLevelILTokenEmitter* tokens,
BNDisassemblySettings* settings, BNSymbolDisplayType symbolDisplay, BNOperatorPrecedence precedence);
+ // String recognizers
+ BINARYNINJACOREAPI BNCustomStringType* BNRegisterCustomStringType(BNCustomStringTypeInfo* info);
+ BINARYNINJACOREAPI BNCustomStringType* BNGetCustomStringTypeByName(const char* name);
+ BINARYNINJACOREAPI BNCustomStringType* BNGetCustomStringTypeByID(uint32_t id);
+ BINARYNINJACOREAPI BNCustomStringType** BNGetCustomStringTypeList(size_t* count);
+ BINARYNINJACOREAPI void BNFreeCustomStringTypeList(BNCustomStringType** types);
+ BINARYNINJACOREAPI char* BNGetCustomStringTypeName(BNCustomStringType* type);
+ BINARYNINJACOREAPI char* BNGetCustomStringTypePrefix(BNCustomStringType* type);
+ BINARYNINJACOREAPI char* BNGetCustomStringTypePostfix(BNCustomStringType* type);
+ BINARYNINJACOREAPI BNStringRecognizer* BNRegisterStringRecognizer(
+ const char* name, BNCustomStringRecognizer* recognizer);
+ BINARYNINJACOREAPI BNStringRecognizer* BNGetStringRecognizerByName(const char* name);
+ BINARYNINJACOREAPI BNStringRecognizer** BNGetStringRecognizerList(size_t* count);
+ BINARYNINJACOREAPI void BNFreeStringRecognizerList(BNStringRecognizer** recognizers);
+ BINARYNINJACOREAPI char* BNGetStringRecognizerName(BNStringRecognizer* recognizer);
+ BINARYNINJACOREAPI bool BNIsStringRecognizerValidForType(
+ BNStringRecognizer* recognizer, BNHighLevelILFunction* il, BNType* type);
+ BINARYNINJACOREAPI bool BNStringRecognizerRecognizeConstant(BNStringRecognizer* recognizer,
+ BNHighLevelILFunction* il, size_t exprIndex, BNType* type, int64_t val, BNDerivedString* out);
+ BINARYNINJACOREAPI bool BNStringRecognizerRecognizeConstantPointer(BNStringRecognizer* recognizer,
+ BNHighLevelILFunction* il, size_t exprIndex, BNType* type, int64_t val, BNDerivedString* out);
+ BINARYNINJACOREAPI bool BNStringRecognizerRecognizeExternPointer(BNStringRecognizer* recognizer,
+ BNHighLevelILFunction* il, size_t exprIndex, BNType* type, int64_t val, uint64_t offset, BNDerivedString* out);
+ BINARYNINJACOREAPI bool BNStringRecognizerRecognizeImport(BNStringRecognizer* recognizer, BNHighLevelILFunction* il,
+ size_t exprIndex, BNType* type, int64_t val, BNDerivedString* out);
+
#ifdef __cplusplus
}
#endif
diff --git a/binaryview.cpp b/binaryview.cpp
index 292b11ac..3499f2ac 100644
--- a/binaryview.cpp
+++ b/binaryview.cpp
@@ -222,6 +222,22 @@ void BinaryDataNotification::StringRemovedCallback(
}
+void BinaryDataNotification::DerivedStringFoundCallback(void* ctxt, BNBinaryView* data, BNDerivedString* str)
+{
+ BinaryDataNotification* notify = (BinaryDataNotification*)ctxt;
+ Ref<BinaryView> view = new BinaryView(BNNewViewReference(data));
+ notify->OnDerivedStringFound(view, DerivedString::FromAPIObject(str, false));
+}
+
+
+void BinaryDataNotification::DerivedStringRemovedCallback(void* ctxt, BNBinaryView* data, BNDerivedString* str)
+{
+ BinaryDataNotification* notify = (BinaryDataNotification*)ctxt;
+ Ref<BinaryView> view = new BinaryView(BNNewViewReference(data));
+ notify->OnDerivedStringRemoved(view, DerivedString::FromAPIObject(str, false));
+}
+
+
void BinaryDataNotification::TypeDefinedCallback(void* ctxt, BNBinaryView* data, BNQualifiedName* name, BNType* type)
{
BinaryDataNotification* notify = (BinaryDataNotification*)ctxt;
@@ -556,6 +572,8 @@ BinaryDataNotification::BinaryDataNotification()
m_callbacks.symbolRemoved = SymbolRemovedCallback;
m_callbacks.stringFound = StringFoundCallback;
m_callbacks.stringRemoved = StringRemovedCallback;
+ m_callbacks.derivedStringFound = DerivedStringFoundCallback;
+ m_callbacks.derivedStringRemoved = DerivedStringRemovedCallback;
m_callbacks.typeDefined = TypeDefinedCallback;
m_callbacks.typeUndefined = TypeUndefinedCallback;
m_callbacks.typeReferenceChanged = TypeReferenceChangedCallback;
@@ -615,6 +633,8 @@ BinaryDataNotification::BinaryDataNotification(NotificationTypes notifications)
m_callbacks.symbolRemoved = (notifications & NotificationType::SymbolRemoved) ? SymbolRemovedCallback : nullptr;
m_callbacks.stringFound = (notifications & NotificationType::StringFound) ? StringFoundCallback : nullptr;
m_callbacks.stringRemoved = (notifications & NotificationType::StringRemoved) ? StringRemovedCallback : nullptr;
+ m_callbacks.derivedStringFound = (notifications & NotificationType::DerivedStringFound) ? DerivedStringFoundCallback : nullptr;
+ m_callbacks.derivedStringRemoved = (notifications & NotificationType::DerivedStringRemoved) ? DerivedStringRemovedCallback : nullptr;
m_callbacks.typeDefined = (notifications & NotificationType::TypeDefined) ? TypeDefinedCallback : nullptr;
m_callbacks.typeUndefined = (notifications & NotificationType::TypeUndefined) ? TypeUndefinedCallback : nullptr;
m_callbacks.typeReferenceChanged = (notifications & NotificationType::TypeReferenceChanged) ? TypeReferenceChangedCallback : nullptr;
@@ -670,7 +690,7 @@ StringRef::StringRef(const std::string& str)
StringRef::StringRef(const StringRef& other)
{
- m_ref = BNDuplicateStringRef(other.m_ref);
+ m_ref = other.m_ref ? BNDuplicateStringRef(other.m_ref) : nullptr;
}
@@ -4013,6 +4033,42 @@ vector<BNStringReference> BinaryView::GetStrings(uint64_t start, uint64_t len)
}
+vector<DerivedString> BinaryView::GetDerivedStrings()
+{
+ size_t count;
+ BNDerivedString* strings = BNGetDerivedStrings(m_object, &count);
+ vector<DerivedString> result;
+ for (size_t i = 0; i < count; i++)
+ result.push_back(DerivedString::FromAPIObject(&strings[i], false));
+ BNFreeDerivedStringList(strings, count);
+ return result;
+}
+
+
+vector<ReferenceSource> BinaryView::GetDerivedStringCodeReferences(
+ const DerivedString& str, std::optional<size_t> maxItems)
+{
+ BNDerivedString derivedStr = str.ToAPIObject(false);
+
+ size_t count;
+ BNReferenceSource* refs = BNGetDerivedStringCodeReferences(
+ m_object, &derivedStr, &count, maxItems.has_value(), maxItems.value_or(0));
+ vector<ReferenceSource> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i++)
+ {
+ ReferenceSource src;
+ src.func = new Function(BNNewFunctionReference(refs[i].func));
+ src.arch = new CoreArchitecture(refs[i].arch);
+ src.addr = refs[i].addr;
+ result.push_back(src);
+ }
+
+ BNFreeCodeReferences(refs, count);
+ return result;
+}
+
+
// The caller of this function must hold a reference to the returned Ref<AnalysisCompletionEvent>.
// Otherwise, it can be freed before the callback is triggered, leading to a crash.
Ref<AnalysisCompletionEvent> BinaryView::AddAnalysisCompletionEvent(const function<void()>& callback)
diff --git a/highlevelil.cpp b/highlevelil.cpp
index 84d74eb3..5f1323eb 100644
--- a/highlevelil.cpp
+++ b/highlevelil.cpp
@@ -645,6 +645,28 @@ set<SSAVariable> HighLevelILFunction::GetSSAVariables()
}
+void HighLevelILFunction::SetDerivedStringReferenceForExpr(size_t expr, const DerivedString& str)
+{
+ BNDerivedString strObj = str.ToAPIObject(false);
+ BNSetHighLevelILDerivedStringReferenceForExpr(m_object, expr, &strObj);
+}
+
+
+void HighLevelILFunction::RemoveDerivedStringReferenceForExpr(size_t expr)
+{
+ BNRemoveHighLevelILDerivedStringReferenceForExpr(m_object, expr);
+}
+
+
+optional<DerivedString> HighLevelILFunction::GetDerivedStringReferenceForExpr(size_t expr)
+{
+ BNDerivedString str;
+ if (!BNGetHighLevelILDerivedStringReferenceForExpr(m_object, expr, &str))
+ return std::nullopt;
+ return DerivedString::FromAPIObject(&str, true);
+}
+
+
HighLevelILTokenEmitter::CurrentExprGuard::CurrentExprGuard(HighLevelILTokenEmitter& parent, const BNTokenEmitterExpr& expr):
m_parent(&parent)
{
diff --git a/highlevelilinstruction.cpp b/highlevelilinstruction.cpp
index 964e1af9..6fe43618 100644
--- a/highlevelilinstruction.cpp
+++ b/highlevelilinstruction.cpp
@@ -1012,6 +1012,24 @@ void HighLevelILInstructionBase::ClearAttribute(BNILInstructionAttribute attribu
}
+std::optional<DerivedString> HighLevelILInstructionBase::GetDerivedStringReference() const
+{
+ return function->GetDerivedStringReferenceForExpr(exprIndex);
+}
+
+
+void HighLevelILInstructionBase::SetDerivedStringReference(const DerivedString& str)
+{
+ function->SetDerivedStringReferenceForExpr(exprIndex, str);
+}
+
+
+void HighLevelILInstructionBase::RemoveDerivedStringReference()
+{
+ function->RemoveDerivedStringReferenceForExpr(exprIndex);
+}
+
+
size_t HighLevelILInstructionBase::GetInstructionIndex() const
{
return function->GetInstructionForExpr(exprIndex);
diff --git a/highlevelilinstruction.h b/highlevelilinstruction.h
index 2e10c485..9be7d7c5 100644
--- a/highlevelilinstruction.h
+++ b/highlevelilinstruction.h
@@ -405,6 +405,10 @@ namespace BinaryNinja
void SetAttribute(BNILInstructionAttribute attribute, bool state = true);
void ClearAttribute(BNILInstructionAttribute attribute);
+ std::optional<DerivedString> GetDerivedStringReference() const;
+ void SetDerivedStringReference(const DerivedString& str);
+ void RemoveDerivedStringReference();
+
size_t GetInstructionIndex() const;
HighLevelILInstruction GetInstruction() const;
diff --git a/python/__init__.py b/python/__init__.py
index acf8b293..02703972 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -83,6 +83,7 @@ from .languagerepresentation import *
from .lineformatter import *
from .renderlayer import *
from .constantrenderer import *
+from .stringrecognizer import *
# We import each of these by name to prevent conflicts between
# log.py and the function 'log' which we don't import below
from .log import (
diff --git a/python/binaryview.py b/python/binaryview.py
index 9e42d8fb..e38c334c 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -45,7 +45,7 @@ from . import decorators
from .enums import (
AnalysisState, SymbolType, Endianness, ModificationStatus, StringType, SegmentFlag, SectionSemantics, FindFlag,
TypeClass, BinaryViewEventType, FunctionGraphType, TagReferenceType, TagTypeType, RegisterValueType, DisassemblyOption,
- RelocationType
+ RelocationType, DerivedStringLocationType
)
from .exceptions import RelocationWriteException, ExternalLinkException
@@ -82,6 +82,7 @@ from . import typecontainer
from . import externallibrary
from . import project
from . import undo
+from . import stringrecognizer
PathType = Union[str, os.PathLike]
@@ -216,6 +217,8 @@ class NotificationType(IntFlag):
UndoEntryTaken = 1 << 50
RedoEntryTaken = 1 << 51
Rebased = 1 << 52
+ DerivedStringFound = 1 << 53
+ DerivedStringRemoved = 1 << 54
BinaryDataUpdates = DataWritten | DataInserted | DataRemoved
FunctionLifetime = FunctionAdded | FunctionRemoved
@@ -226,7 +229,7 @@ class NotificationType(IntFlag):
TagUpdates = TagLifetime | TagUpdated
SymbolLifetime = SymbolAdded | SymbolRemoved
SymbolUpdates = SymbolLifetime | SymbolUpdated
- StringUpdates = StringFound | StringRemoved
+ StringUpdates = StringFound | StringRemoved | DerivedStringFound | DerivedStringRemoved
TypeLifetime = TypeDefined | TypeUndefined
TypeUpdates = TypeLifetime | TypeReferenceChanged | TypeFieldReferenceChanged
SegmentLifetime = SegmentAdded | SegmentRemoved
@@ -390,6 +393,12 @@ class BinaryDataNotification:
def string_removed(self, view: 'BinaryView', string_type: StringType, offset: int, length: int) -> None:
pass
+ def derived_string_found(self, view: 'BinaryView', string: 'DerivedString') -> None:
+ pass
+
+ def derived_string_removed(self, view: 'BinaryView', string: 'DerivedString') -> None:
+ pass
+
def type_defined(self, view: 'BinaryView', name: '_types.QualifiedName', type: '_types.Type') -> None:
pass
@@ -518,6 +527,136 @@ class StringReference:
return self._view
+class StringRef:
+ def __init__(self, handle):
+ self.handle = core.handle_of_type(handle, core.BNStringRef)
+
+ def __del__(self):
+ if core is not None:
+ core.BNFreeStringRef(self.handle)
+
+ def __bytes__(self):
+ # Do not call the wrapper BNGetStringRefContents here, it will crash as the generator
+ # does not understand that this API gives a direct reference to the string
+ value_ptr = core._BNGetStringRefContents(self.handle)
+ value_len = core.BNGetStringRefSize(self.handle)
+ buf = ctypes.create_string_buffer(value_len)
+ ctypes.memmove(buf, value_ptr, value_len)
+ return bytes(buf.raw)
+
+ def __str__(self):
+ return core.pyNativeStr(bytes(self))
+
+ def __len__(self):
+ return core.BNGetStringRefSize(self.handle)
+
+ def __repr__(self):
+ return repr(str(self))
+
+ def __eq__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return bytes(self) == bytes(other)
+
+ def __ne__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return not (self == other)
+
+ def __lt__(self, other) -> bool:
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return bytes(self) < bytes(self)
+
+ def __gt__(self, other) -> bool:
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return bytes(self) > bytes(other)
+
+ def __le__(self, other) -> bool:
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return bytes(self) <= bytes(other)
+
+ def __ge__(self, other) -> bool:
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return bytes(self) >= bytes(other)
+
+ def __hash__(self):
+ return hash(bytes(self))
+
+
+@dataclass(frozen=True)
+class DerivedStringLocation:
+ location_type: 'DerivedStringLocationType'
+ address: int
+ length: int
+
+
+@dataclass(frozen=True)
+class DerivedString:
+ value: 'StringRef'
+ location: Optional[DerivedStringLocation]
+ custom_type: Optional[stringrecognizer.CustomStringType]
+
+ def __init__(
+ self, value: Union['StringRef', str, bytes, bytearray, 'databuffer.DataBuffer'],
+ location: Optional[DerivedStringLocation], custom_type: Optional[stringrecognizer.CustomStringType]
+ ):
+ if isinstance(value, str):
+ value = value.encode("utf-8")
+ value = StringRef(core.BNCreateStringRefOfLength(value, len(value)))
+ elif isinstance(value, bytes):
+ value = StringRef(core.BNCreateStringRefOfLength(value, len(value)))
+ elif isinstance(value, bytearray):
+ value = bytes(value)
+ value = StringRef(core.BNCreateStringRefOfLength(value, len(value)))
+ elif isinstance(value, databuffer.DataBuffer):
+ value = bytes(value)
+ value = StringRef(core.BNCreateStringRefOfLength(value, len(value)))
+ elif not isinstance(value, StringRef):
+ value = str(value).encode("utf-8")
+ value = StringRef(core.BNCreateStringRefOfLength(value, len(value)))
+
+ object.__setattr__(self, "value", value)
+ object.__setattr__(self, "location", location)
+ object.__setattr__(self, "custom_type", custom_type)
+
+ def _to_core_struct(self, owned: bool) -> 'core.BNDerivedString':
+ result = core.BNDerivedString()
+ if owned:
+ result.value = core.BNDuplicateStringRef(self.value.handle)
+ else:
+ result.value = self.value.handle
+ result.locationValid = self.location is not None
+ if result.locationValid:
+ result.location.locationType = self.location.location_type
+ result.location.addr = self.location.address
+ result.location.len = self.location.length
+ if self.custom_type is None:
+ result.customType = None
+ else:
+ result.customType = self.custom_type.handle
+ return result
+
+ @staticmethod
+ def _from_core_struct(obj: 'core.BNDerivedString', owned: bool) -> 'DerivedString':
+ if owned:
+ value = StringRef(obj.value)
+ else:
+ value = StringRef(core.BNDuplicateStringRef(obj.value))
+ if obj.locationValid:
+ location = DerivedStringLocation(DerivedStringLocationType(obj.location.locationType), obj.location.addr, obj.location.len)
+ else:
+ location = None
+ if obj.customType:
+ custom_type = stringrecognizer.CustomStringType(obj.customType)
+ else:
+ custom_type = None
+ return DerivedString(value, location, custom_type)
+
+
class AnalysisCompletionEvent:
"""
The ``AnalysisCompletionEvent`` object provides an asynchronous mechanism for receiving
@@ -701,6 +840,8 @@ class BinaryDataNotificationCallbacks:
self._cb.symbolUpdated = self._cb.symbolUpdated.__class__(self._symbol_updated)
self._cb.stringFound = self._cb.stringFound.__class__(self._string_found)
self._cb.stringRemoved = self._cb.stringRemoved.__class__(self._string_removed)
+ self._cb.derivedStringFound = self._cb.derivedStringFound.__class__(self._derived_string_found)
+ self._cb.derivedStringRemoved = self._cb.derivedStringRemoved.__class__(self._derived_string_removed)
self._cb.typeDefined = self._cb.typeDefined.__class__(self._type_defined)
self._cb.typeUndefined = self._cb.typeUndefined.__class__(self._type_undefined)
self._cb.typeReferenceChanged = self._cb.typeReferenceChanged.__class__(self._type_ref_changed)
@@ -774,6 +915,10 @@ class BinaryDataNotificationCallbacks:
self._cb.stringFound = self._cb.stringFound.__class__(self._string_found)
if notify.notifications & NotificationType.StringRemoved:
self._cb.stringRemoved = self._cb.stringRemoved.__class__(self._string_removed)
+ if notify.notifications & NotificationType.DerivedStringFound:
+ self._cb.derivedStringFound = self._cb.derivedStringFound.__class__(self._derived_string_found)
+ if notify.notifications & NotificationType.DerivedStringRemoved:
+ self._cb.derivedStringRemoved = self._cb.derivedStringRemoved.__class__(self._derived_string_removed)
if notify.notifications & NotificationType.TypeDefined:
self._cb.typeDefined = self._cb.typeDefined.__class__(self._type_defined)
if notify.notifications & NotificationType.TypeUndefined:
@@ -1017,6 +1162,18 @@ class BinaryDataNotificationCallbacks:
except:
log_error_for_exception("Unhandled Python exception in BinaryDataNotificationCallbacks._string_removed")
+ def _derived_string_found(self, ctxt, view: core.BNBinaryView, string) -> None:
+ try:
+ self._notify.derived_string_found(self._view, DerivedString._from_core_struct(string[0], False))
+ except:
+ log_error_for_exception("Unhandled Python exception in BinaryDataNotificationCallbacks._derived_string_found")
+
+ def _derived_string_removed(self, ctxt, view: core.BNBinaryView, string) -> None:
+ try:
+ self._notify.derived_string_removed(self._view, DerivedString._from_core_struct(string[0], False))
+ except:
+ log_error_for_exception("Unhandled Python exception in BinaryDataNotificationCallbacks._derived_string_removed")
+
def _type_defined(self, ctxt, view: core.BNBinaryView, name: str, type_obj: '_types.Type') -> None:
try:
qualified_name = _types.QualifiedName._from_core_struct(name[0])
@@ -3402,6 +3559,19 @@ class BinaryView:
return self.get_strings()
@property
+ def derived_strings(self) -> List['DerivedString']:
+ count = ctypes.c_ulonglong(0)
+ strings = core.BNGetDerivedStrings(self.handle, count)
+ assert strings is not None, "core.BNGetDerivedStrings returned None"
+ try:
+ result = []
+ for i in range(0, count.value):
+ result.append(DerivedString._from_core_struct(strings[i], False))
+ return result
+ finally:
+ core.BNFreeDerivedStringList(strings, count.value)
+
+ @property
def saved(self) -> bool:
"""boolean state of whether or not the file has been saved (read/write)"""
return self._file.saved
@@ -5818,6 +5988,20 @@ class BinaryView:
core.BNFreeTypeReferences(refs, count.value)
return result
+ def get_derived_string_code_refs(self, str: 'DerivedString', max_items: Optional[int] = None) -> Generator['ReferenceSource', None, None]:
+ count = ctypes.c_ulonglong(0)
+ has_max_items = max_items is not None
+ max_items_value = max_items if has_max_items else 0
+ core_str = str._to_core_struct(False)
+ refs = core.BNGetDerivedStringCodeReferences(self.handle, core_str, count, has_max_items, max_items_value)
+ assert refs is not None, "core.BNGetDerivedStringCodeReferences returned None"
+
+ try:
+ for i in range(0, count.value):
+ yield ReferenceSource._from_core_struct(self, refs[i])
+ finally:
+ core.BNFreeCodeReferences(refs, count.value)
+
def add_data_ref(self, from_addr: int, to_addr: int) -> None:
"""
``add_data_ref`` adds an auto data cross-reference (xref) from the address ``from_addr`` to the address ``to_addr``.
diff --git a/python/examples/encoded_strings.py b/python/examples/encoded_strings.py
index ce7d02db..691d116c 100644
--- a/python/examples/encoded_strings.py
+++ b/python/examples/encoded_strings.py
@@ -1,8 +1,11 @@
-from binaryninja import (ConstantRenderer, PointerType, InstructionTextToken, InstructionTextTokenType, DataBuffer)
+from binaryninja import (StringRecognizer, CustomStringType, DataBuffer, DerivedString, DerivedStringLocation,
+ DerivedStringLocationType, PointerType, InstructionTextToken, InstructionTextTokenType)
+encoded_string_type = CustomStringType.register("Encoded", "", "_enc")
-class EncodedStringConstantRenderer(ConstantRenderer):
- renderer_name = "encoded_strings"
+
+class EncodedStringRecognizer(StringRecognizer):
+ recognizer_name = "encoded_strings"
decoders = {
"xor_encoded": lambda encoded, key: encoded ^ key,
"sub_encoded": lambda encoded, key: (encoded - key) & 0xff,
@@ -17,9 +20,9 @@ class EncodedStringConstantRenderer(ConstantRenderer):
return True
return False
- def render_constant_pointer(self, instr, type, val, tokens, settings, precedence):
+ def recognize_constant_pointer(self, instr, type, val):
if not isinstance(type, PointerType):
- return False
+ return None
values = None
decoder = None
@@ -29,9 +32,9 @@ class EncodedStringConstantRenderer(ConstantRenderer):
values = bytes.fromhex(type.target.attributes[name])
decoder = self.__class__.decoders[name]
except:
- return False
+ return None
if values is None or decoder is None:
- return False
+ return None
encoded_null = "encoded_null" in type.target.attributes
@@ -49,10 +52,8 @@ class EncodedStringConstantRenderer(ConstantRenderer):
result += bytes([byte])
i += 1
- tokens.append(InstructionTextToken(InstructionTextTokenType.BraceToken, "\""))
- tokens.append(InstructionTextToken(InstructionTextTokenType.StringToken, DataBuffer(result).escape()))
- tokens.append(InstructionTextToken(InstructionTextTokenType.BraceToken, "\"_enc"))
- return True
+ loc = DerivedStringLocation(DerivedStringLocationType.DataBackedStringLocation, val, i)
+ return DerivedString(result, loc, encoded_string_type)
-EncodedStringConstantRenderer().register()
+EncodedStringRecognizer().register()
diff --git a/python/highlevelil.py b/python/highlevelil.py
index ce264e19..ef1b3de2 100644
--- a/python/highlevelil.py
+++ b/python/highlevelil.py
@@ -41,6 +41,7 @@ from . import highlight
from . import flowgraph
from . import variable
from . import databuffer
+from . import stringrecognizer
from . import types as _types
from .interaction import show_graph_report
from .commonil import (
@@ -973,6 +974,13 @@ class HighLevelILInstruction(BaseILInstruction):
hash ^= rotl(discriminator, 47)
return hash
+ @property
+ def derived_string_reference(self) -> Optional['binaryview.DerivedString']:
+ str = core.BNDerivedString()
+ if not core.BNGetHighLevelILDerivedStringReferenceForExpr(self.function.handle, self.expr_index, str):
+ return None
+ return binaryview.DerivedString._from_core_struct(str, True)
+
@dataclass(frozen=True, repr=False, eq=False)
class HighLevelILUnaryBase(HighLevelILInstruction, UnaryOperation):
@@ -3003,6 +3011,22 @@ class HighLevelILFunction:
result |= flag.value
core.BNSetHighLevelILExprAttributes(self.handle, expr, result)
+ def set_derived_string_reference_for_expr(self, expr: InstructionOrExpression, str: 'binaryview.DerivedString'):
+ if isinstance(expr, HighLevelILInstruction):
+ expr = expr.expr_index
+ elif isinstance(expr, int):
+ expr = ExpressionIndex(expr)
+
+ str_obj = str._to_core_struct(False)
+ core.BNSetHighLevelILDerivedStringReferenceForExpr(self.handle, expr, str_obj)
+
+ def remove_derived_string_reference_for_expr(self, expr: InstructionOrExpression):
+ if isinstance(expr, HighLevelILInstruction):
+ expr = expr.expr_index
+ elif isinstance(expr, int):
+ expr = ExpressionIndex(expr)
+ core.BNRemoveHighLevelILDerivedStringReferenceForExpr(self.handle, expr)
+
def nop(self, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
"""
``nop`` no operation, this instruction does nothing
diff --git a/python/stringrecognizer.py b/python/stringrecognizer.py
new file mode 100644
index 00000000..8f503d8b
--- /dev/null
+++ b/python/stringrecognizer.py
@@ -0,0 +1,293 @@
+# Copyright (c) 2015-2025 Vector 35 Inc
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+from typing import Optional, Union
+from dataclasses import dataclass
+import ctypes
+
+import binaryninja
+from . import _binaryninjacore as core
+from .log import log_error_for_exception
+from . import types
+from . import highlevelil
+from . import binaryview
+
+
+class _CustomStringTypeMetaClass(type):
+ def __iter__(self):
+ binaryninja._init_plugins()
+ count = ctypes.c_ulonglong()
+ types = core.BNGetCustomStringTypeList(count)
+ assert types is not None, "core.BNGetCustomStringTypeList returned None"
+ try:
+ for i in range(0, count.value):
+ yield CustomStringType(handle=types[i])
+ finally:
+ core.BNFreeCustomStringTypeList(types)
+
+ def __getitem__(cls, value):
+ binaryninja._init_plugins()
+ string_type = core.BNGetCustomStringTypeByName(str(value))
+ if string_type is None:
+ raise KeyError("'%s' is not a valid type" % str(value))
+ return CustomStringType(handle=string_type)
+
+
+class CustomStringType(metaclass=_CustomStringTypeMetaClass):
+ def __init__(self, handle):
+ self.handle = core.handle_of_type(handle, core.BNCustomStringType)
+
+ def __str__(self):
+ return self.name
+
+ def __repr__(self):
+ return f"<{self.__class__.__name__}: {self.name}>"
+
+ def __eq__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(other.handle.contents)
+
+ def __ne__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return not (self == other)
+
+ def __hash__(self):
+ return hash(ctypes.addressof(self.handle.contents))
+
+ @staticmethod
+ def register(name: str, string_prefix="", string_postfix="") -> 'CustomStringType':
+ info = core.BNCustomStringTypeInfo()
+ info.name = name
+ info.stringPrefix = string_prefix
+ info.stringPostfix = string_postfix
+ handle = core.BNRegisterCustomStringType(info)
+ return CustomStringType(handle)
+
+ @property
+ def name(self) -> str:
+ return core.BNGetCustomStringTypeName(self.handle)
+
+ @property
+ def string_prefix(self) -> str:
+ return core.BNGetCustomStringTypePrefix(self.handle)
+
+ @property
+ def string_postfix(self) -> str:
+ return core.BNGetCustomStringTypePostfix(self.handle)
+
+
+class _StringRecognizerMetaClass(type):
+ def __iter__(self):
+ binaryninja._init_plugins()
+ count = ctypes.c_ulonglong()
+ recognizers = core.BNGetStringRecognizerList(count)
+ assert recognizers is not None, "core.BNGetStringRecognizerList returned None"
+ try:
+ for i in range(0, count.value):
+ yield CoreStringRecognizer(handle=recognizers[i])
+ finally:
+ core.BNFreeStringRecognizerList(recognizers)
+
+ def __getitem__(cls, value):
+ binaryninja._init_plugins()
+ recognizer = core.BNGetStringRecognizerByName(str(value))
+ if recognizer is None:
+ raise KeyError("'%s' is not a valid recognizer" % str(value))
+ return CoreStringRecognizer(handle=recognizer)
+
+
+class StringRecognizer(metaclass=_StringRecognizerMetaClass):
+ _registered_recognizers = []
+ recognizer_name = None
+
+ def __init__(self, handle=None):
+ if handle is not None:
+ self.handle = core.handle_of_type(handle, core.BNStringRecognizer)
+
+ def register(self):
+ if self.__class__.recognizer_name is None:
+ raise ValueError("Recognizer name is missing")
+ self._cb = core.BNCustomStringRecognizer()
+ self._cb.context = 0
+ if self.is_valid_for_type.__func__ != StringRecognizer.is_valid_for_type:
+ self._cb.isValidForType = self._cb.isValidForType.__class__(self._is_valid_for_type)
+ if self.recognize_constant.__func__ != StringRecognizer.recognize_constant:
+ self._cb.recognizeConstant = self._cb.recognizeConstant.__class__(self._recognize_constant)
+ if self.recognize_constant_pointer.__func__ != StringRecognizer.recognize_constant_pointer:
+ self._cb.recognizeConstantPointer = self._cb.recognizeConstantPointer.__class__(
+ self._recognize_constant_pointer)
+ if self.recognize_extern_pointer.__func__ != StringRecognizer.recognize_extern_pointer:
+ self._cb.recognizeExternPointer = self._cb.recognizeExternPointer.__class__(self._recognize_extern_pointer)
+ if self.recognize_import.__func__ != StringRecognizer.recognize_import:
+ self._cb.recognizeImport = self._cb.recognizeImport.__class__(self._recognize_import)
+ self.handle = core.BNRegisterStringRecognizer(self.__class__.recognizer_name, self._cb)
+ self.__class__._registered_recognizers.append(self)
+
+ def _is_valid_for_type(self, ctxt, hlil, type):
+ try:
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ type = types.Type.create(handle=core.BNNewTypeReference(type))
+ return self.is_valid_for_type(hlil, type)
+ except:
+ log_error_for_exception("Unhandled Python exception in StringRecognizer._is_valid_for_type")
+ return False
+
+ def _recognize_constant(self, ctxt, hlil, expr, type, val, result):
+ try:
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ type = types.Type.create(handle=core.BNNewTypeReference(type))
+ instr = hlil.get_expr(highlevelil.ExpressionIndex(expr))
+ ref = self.recognize_constant(instr, type, val)
+ if ref is None:
+ return False
+ result[0] = ref._to_core_struct(True)
+ return True
+ except:
+ log_error_for_exception("Unhandled Python exception in StringRecognizer._recognize_constant")
+ return False
+
+ def _recognize_constant_pointer(self, ctxt, hlil, expr, type, val, result):
+ try:
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ type = types.Type.create(handle=core.BNNewTypeReference(type))
+ instr = hlil.get_expr(highlevelil.ExpressionIndex(expr))
+ ref = self.recognize_constant_pointer(instr, type, val)
+ if ref is None:
+ return False
+ result[0] = ref._to_core_struct(True)
+ return True
+ except:
+ log_error_for_exception("Unhandled Python exception in StringRecognizer._recognize_constant_pointer")
+ return False
+
+ def _recognize_extern_pointer(self, ctxt, hlil, expr, type, val, offset, result):
+ try:
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ type = types.Type.create(handle=core.BNNewTypeReference(type))
+ instr = hlil.get_expr(highlevelil.ExpressionIndex(expr))
+ ref = self.recognize_extern_pointer(instr, type, val, offset)
+ if ref is None:
+ return False
+ result[0] = ref._to_core_struct(True)
+ return True
+ except:
+ log_error_for_exception("Unhandled Python exception in StringRecognizer._recognize_extern_pointer")
+ return False
+
+ def _recognize_import(self, ctxt, hlil, expr, type, val, result):
+ try:
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ type = types.Type.create(handle=core.BNNewTypeReference(type))
+ instr = hlil.get_expr(highlevelil.ExpressionIndex(expr))
+ ref = self.recognize_import(instr, type, val)
+ if ref is None:
+ return False
+ result[0] = ref._to_core_struct(True)
+ return True
+ except:
+ log_error_for_exception("Unhandled Python exception in StringRecognizer._recognize_import")
+ return False
+
+ @property
+ def name(self) -> str:
+ if hasattr(self, 'handle'):
+ return core.BNGetStringRecognizerName(self.handle)
+ return self.__class__.recognizer_name
+
+ def is_valid_for_type(self, func: 'highlevelil.HighLevelILFunction', type: 'types.Type') -> bool:
+ return True
+
+ def recognize_constant(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int
+ ) -> Optional['binaryview.DerivedString']:
+ return None
+
+ def recognize_constant_pointer(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int
+ ) -> Optional['binaryview.DerivedString']:
+ return None
+
+ def recognize_extern_pointer(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int, offset: int
+ ) -> Optional['binaryview.DerivedString']:
+ return None
+
+ def recognize_import(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int
+ ) -> Optional['binaryview.DerivedString']:
+ return None
+
+
+_recognizer_cache = {}
+
+
+class CoreStringRecognizer(StringRecognizer):
+ def __init__(self, handle: core.BNStringRecognizer):
+ super(CoreStringRecognizer, self).__init__(handle=handle)
+ if type(self) is CoreStringRecognizer:
+ global _recognizer_cache
+ _recognizer_cache[ctypes.addressof(handle.contents)] = self
+
+ @classmethod
+ def _from_cache(cls, handle) -> 'StringRecognizer':
+ """
+ Look up a recognizer from a given BNStringRecognizer handle
+ :param handle: BNStringRecognizer pointer
+ :return: Recognizer instance responsible for this handle
+ """
+ global _recognizer_cache
+ return _recognizer_cache.get(ctypes.addressof(handle.contents)) or cls(handle)
+
+ def is_valid_for_type(self, func: 'highlevelil.HighLevelILFunction', type: 'types.Type') -> bool:
+ return core.BNIsStringRecognizerValidForType(self.handle, func.handle, type.handle)
+
+ def recognize_constant(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int
+ ) -> Optional['binaryview.DerivedString']:
+ string = core.BNDerivedString()
+ if not core.BNStringRecognizerRecognizeConstant(self.handle, instr.function.handle, instr.expr_index, type.handle, val, string):
+ return None
+ return binaryview.DerivedString._from_core_struct(string, True)
+
+ def recognize_constant_pointer(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int
+ ) -> Optional['binaryview.DerivedString']:
+ string = core.BNDerivedString()
+ if not core.BNStringRecognizerRecognizeConstantPointer(self.handle, instr.function.handle, instr.expr_index, type.handle, val, string):
+ return None
+ return binaryview.DerivedString._from_core_struct(string, True)
+
+ def recognize_extern_pointer(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int, offset: int
+ ) -> Optional['binaryview.DerivedString']:
+ string = core.BNDerivedString()
+ if not core.BNStringRecognizerRecognizeExternPointer(self.handle, instr.function.handle, instr.expr_index, type.handle, val, offset, string):
+ return None
+ return binaryview.DerivedString._from_core_struct(string, True)
+
+ def recognize_import(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int
+ ) -> Optional['binaryview.DerivedString']:
+ string = core.BNDerivedString()
+ if not core.BNStringRecognizerRecognizeImport(self.handle, instr.function.handle, instr.expr_index, type.handle, val, string):
+ return None
+ return binaryview.DerivedString._from_core_struct(string, True)
diff --git a/rust/src/disassembly.rs b/rust/src/disassembly.rs
index cd5a860d..75bf28fa 100644
--- a/rust/src/disassembly.rs
+++ b/rust/src/disassembly.rs
@@ -975,6 +975,8 @@ pub enum InstructionTextTokenContext {
Expanded,
/// Use only with [`InstructionTextTokenKind::CollapseStateIndicator`]
CollapsiblePadding,
+ /// Use only with [`InstructionTextTokenKind::String`]
+ DerivedStringReference,
}
impl From<BNInstructionTextTokenContext> for InstructionTextTokenContext {
@@ -1002,6 +1004,9 @@ impl From<BNInstructionTextTokenContext> for InstructionTextTokenContext {
BNInstructionTextTokenContext::ContentCollapsedContext => Self::Collapsed,
BNInstructionTextTokenContext::ContentExpandedContext => Self::Expanded,
BNInstructionTextTokenContext::ContentCollapsiblePadding => Self::CollapsiblePadding,
+ BNInstructionTextTokenContext::DerivedStringReferenceTokenContext => {
+ Self::DerivedStringReference
+ }
}
}
}
@@ -1023,6 +1028,7 @@ impl From<InstructionTextTokenContext> for BNInstructionTextTokenContext {
InstructionTextTokenContext::Collapsed => Self::ContentCollapsedContext,
InstructionTextTokenContext::Expanded => Self::ContentExpandedContext,
InstructionTextTokenContext::CollapsiblePadding => Self::ContentCollapsiblePadding,
+ InstructionTextTokenContext::DerivedStringReference => Self::DerivedStringReferenceTokenContext,
}
}
}
diff --git a/stringrecognizer.cpp b/stringrecognizer.cpp
new file mode 100644
index 00000000..dc6ac2f8
--- /dev/null
+++ b/stringrecognizer.cpp
@@ -0,0 +1,300 @@
+#include "binaryninjaapi.h"
+#include "ffi.h"
+#include "highlevelilinstruction.h"
+
+using namespace BinaryNinja;
+using namespace std;
+
+
+BNDerivedString DerivedString::ToAPIObject(bool owned) const
+{
+ BNDerivedString result;
+ result.value = owned ? BNDuplicateStringRef(value.GetObject()) : value.GetObject();
+ result.locationValid = location.has_value();
+ if (location.has_value())
+ {
+ result.location.locationType = location->locationType;
+ result.location.addr = location->addr;
+ result.location.len = location->len;
+ }
+ else
+ {
+ result.location.locationType = DataBackedStringLocation;
+ result.location.addr = 0;
+ result.location.len = 0;
+ }
+ result.customType = customType ? customType->GetObject() : nullptr;
+ return result;
+}
+
+
+DerivedString DerivedString::FromAPIObject(BNDerivedString* str, bool owned)
+{
+ DerivedString result;
+ result.value = StringRef(owned ? str->value : BNDuplicateStringRef(str->value));
+ if (str->locationValid)
+ result.location = {str->location.locationType, str->location.addr, str->location.len};
+ result.customType = str->customType ? new CustomStringType(str->customType) : nullptr;
+ return result;
+}
+
+
+CustomStringType::CustomStringType(BNCustomStringType* type)
+{
+ m_object = type;
+}
+
+
+string CustomStringType::GetName() const
+{
+ char* name = BNGetCustomStringTypeName(m_object);
+ string result = name;
+ BNFreeString(name);
+ return result;
+}
+
+
+string CustomStringType::GetStringPrefix() const
+{
+ char* prefix = BNGetCustomStringTypePrefix(m_object);
+ string result = prefix;
+ BNFreeString(prefix);
+ return result;
+}
+
+
+string CustomStringType::GetStringPostfix() const
+{
+ char* postfix = BNGetCustomStringTypePostfix(m_object);
+ string result = postfix;
+ BNFreeString(postfix);
+ return result;
+}
+
+
+Ref<CustomStringType> CustomStringType::Register(
+ const std::string& name, const std::string& stringPrefix, const std::string& stringPostfix)
+{
+ BNCustomStringTypeInfo info;
+ info.name = (char*)name.c_str();
+ info.stringPrefix = (char*)stringPrefix.c_str();
+ info.stringPostfix = (char*)stringPostfix.c_str();
+ BNCustomStringType* result = BNRegisterCustomStringType(&info);
+ return new CustomStringType(result);
+}
+
+
+StringRecognizer::StringRecognizer(const std::string& name): m_nameForRegister(name)
+{
+ m_object = nullptr;
+}
+
+
+StringRecognizer::StringRecognizer(BNStringRecognizer* recognizer)
+{
+ m_object = recognizer;
+}
+
+
+string StringRecognizer::GetName() const
+{
+ char* name = BNGetStringRecognizerName(m_object);
+ string result = name;
+ BNFreeString(name);
+ return result;
+}
+
+
+bool StringRecognizer::IsValidForType(HighLevelILFunction*, Type*)
+{
+ return true;
+}
+
+
+std::optional<DerivedString> StringRecognizer::RecognizeConstant(const HighLevelILInstruction&, Type*, int64_t)
+{
+ return std::nullopt;
+}
+
+
+std::optional<DerivedString> StringRecognizer::RecognizeConstantPointer(const HighLevelILInstruction&, Type*, int64_t)
+{
+ return std::nullopt;
+}
+
+
+std::optional<DerivedString> StringRecognizer::RecognizeExternPointer(
+ const HighLevelILInstruction&, Type*, int64_t, uint64_t)
+{
+ return std::nullopt;
+}
+
+
+std::optional<DerivedString> StringRecognizer::RecognizeImport(const HighLevelILInstruction&, Type*, int64_t)
+{
+ return std::nullopt;
+}
+
+
+void StringRecognizer::Register(StringRecognizer* recognizer)
+{
+ BNCustomStringRecognizer callbacks;
+ callbacks.context = recognizer;
+ callbacks.isValidForType = IsValidForTypeCallback;
+ callbacks.recognizeConstant = RecognizeConstantCallback;
+ callbacks.recognizeConstantPointer = RecognizeConstantPointerCallback;
+ callbacks.recognizeExternPointer = RecognizeExternPointerCallback;
+ callbacks.recognizeImport = RecognizeImportCallback;
+
+ recognizer->AddRefForRegistration();
+ recognizer->m_object = BNRegisterStringRecognizer(recognizer->m_nameForRegister.c_str(), &callbacks);
+}
+
+
+bool StringRecognizer::IsValidForTypeCallback(void* ctxt, BNHighLevelILFunction* hlil, BNType* type)
+{
+ StringRecognizer* recognizer = (StringRecognizer*)ctxt;
+ Ref<HighLevelILFunction> hlilObj = new HighLevelILFunction(BNNewHighLevelILFunctionReference(hlil));
+ Ref<Type> typeObj = new Type(BNNewTypeReference(type));
+ return recognizer->IsValidForType(hlilObj, typeObj);
+}
+
+
+bool StringRecognizer::RecognizeConstantCallback(
+ void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type, int64_t val, BNDerivedString* result)
+{
+ StringRecognizer* recognizer = (StringRecognizer*)ctxt;
+ Ref<HighLevelILFunction> hlilObj = new HighLevelILFunction(BNNewHighLevelILFunctionReference(hlil));
+ HighLevelILInstruction instr = hlilObj->GetExpr(expr);
+ Ref<Type> typeObj = new Type(BNNewTypeReference(type));
+ auto str = recognizer->RecognizeConstant(instr, typeObj, val);
+ if (!str.has_value())
+ return false;
+ *result = str->ToAPIObject(true);
+ return true;
+}
+
+
+bool StringRecognizer::RecognizeConstantPointerCallback(
+ void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type, int64_t val, BNDerivedString* result)
+{
+ StringRecognizer* recognizer = (StringRecognizer*)ctxt;
+ Ref<HighLevelILFunction> hlilObj = new HighLevelILFunction(BNNewHighLevelILFunctionReference(hlil));
+ HighLevelILInstruction instr = hlilObj->GetExpr(expr);
+ Ref<Type> typeObj = new Type(BNNewTypeReference(type));
+ auto str = recognizer->RecognizeConstantPointer(instr, typeObj, val);
+ if (!str.has_value())
+ return false;
+ *result = str->ToAPIObject(true);
+ return true;
+}
+
+
+bool StringRecognizer::RecognizeExternPointerCallback(void* ctxt, BNHighLevelILFunction* hlil, size_t expr,
+ BNType* type, int64_t val, uint64_t offset, BNDerivedString* result)
+{
+ StringRecognizer* recognizer = (StringRecognizer*)ctxt;
+ Ref<HighLevelILFunction> hlilObj = new HighLevelILFunction(BNNewHighLevelILFunctionReference(hlil));
+ HighLevelILInstruction instr = hlilObj->GetExpr(expr);
+ Ref<Type> typeObj = new Type(BNNewTypeReference(type));
+ auto str = recognizer->RecognizeExternPointer(instr, typeObj, val, offset);
+ if (!str.has_value())
+ return false;
+ *result = str->ToAPIObject(true);
+ return true;
+}
+
+
+bool StringRecognizer::RecognizeImportCallback(
+ void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type, int64_t val, BNDerivedString* result)
+{
+ StringRecognizer* recognizer = (StringRecognizer*)ctxt;
+ Ref<HighLevelILFunction> hlilObj = new HighLevelILFunction(BNNewHighLevelILFunctionReference(hlil));
+ HighLevelILInstruction instr = hlilObj->GetExpr(expr);
+ Ref<Type> typeObj = new Type(BNNewTypeReference(type));
+ auto str = recognizer->RecognizeImport(instr, typeObj, val);
+ if (!str.has_value())
+ return false;
+ *result = str->ToAPIObject(true);
+ return true;
+}
+
+
+Ref<StringRecognizer> StringRecognizer::GetByName(const std::string& name)
+{
+ BNStringRecognizer* recognizer = BNGetStringRecognizerByName(name.c_str());
+ if (!recognizer)
+ return nullptr;
+ return new CoreStringRecognizer(recognizer);
+}
+
+
+vector<Ref<StringRecognizer>> StringRecognizer::GetRecognizers()
+{
+ size_t count = 0;
+ BNStringRecognizer** recognizers = BNGetStringRecognizerList(&count);
+
+ vector<Ref<StringRecognizer>> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i++)
+ result.push_back(new CoreStringRecognizer(recognizers[i]));
+
+ BNFreeStringRecognizerList(recognizers);
+ return result;
+}
+
+
+CoreStringRecognizer::CoreStringRecognizer(BNStringRecognizer* recognizer):
+ StringRecognizer(recognizer)
+{
+}
+
+
+bool CoreStringRecognizer::IsValidForType(HighLevelILFunction* func, Type* type)
+{
+ return BNIsStringRecognizerValidForType(m_object, func->GetObject(), type->GetObject());
+}
+
+
+std::optional<DerivedString> CoreStringRecognizer::RecognizeConstant(
+ const HighLevelILInstruction& instr, Type* type, int64_t val)
+{
+ BNDerivedString str;
+ if (!BNStringRecognizerRecognizeConstant(m_object, instr.function->GetObject(), instr.exprIndex,
+ type->GetObject(), val, &str))
+ return std::nullopt;
+ return DerivedString::FromAPIObject(&str, true);
+}
+
+
+std::optional<DerivedString> CoreStringRecognizer::RecognizeConstantPointer(
+ const HighLevelILInstruction& instr, Type* type, int64_t val)
+{
+ BNDerivedString str;
+ if (!BNStringRecognizerRecognizeConstantPointer(m_object, instr.function->GetObject(), instr.exprIndex,
+ type->GetObject(), val, &str))
+ return std::nullopt;
+ return DerivedString::FromAPIObject(&str, true);
+}
+
+
+std::optional<DerivedString> CoreStringRecognizer::RecognizeExternPointer(
+ const HighLevelILInstruction& instr, Type* type, int64_t val, uint64_t offset)
+{
+ BNDerivedString str;
+ if (!BNStringRecognizerRecognizeExternPointer(m_object, instr.function->GetObject(), instr.exprIndex,
+ type->GetObject(), val, offset, &str))
+ return std::nullopt;
+ return DerivedString::FromAPIObject(&str, true);
+}
+
+
+std::optional<DerivedString> CoreStringRecognizer::RecognizeImport(
+ const HighLevelILInstruction& instr, Type* type, int64_t val)
+{
+ BNDerivedString str;
+ if (!BNStringRecognizerRecognizeImport(m_object, instr.function->GetObject(), instr.exprIndex,
+ type->GetObject(), val, &str))
+ return std::nullopt;
+ return DerivedString::FromAPIObject(&str, true);
+}
diff --git a/ui/stringsview.h b/ui/stringsview.h
index 800e25c5..99c66b79 100644
--- a/ui/stringsview.h
+++ b/ui/stringsview.h
@@ -79,6 +79,8 @@ class BINARYNINJAUIAPI StringsListModel : public QAbstractItemModel, public Bina
virtual void OnStringFound(BinaryNinja::BinaryView* data, BNStringType type, uint64_t offset, size_t len) override;
virtual void OnStringRemoved(BinaryNinja::BinaryView* data, BNStringType type, uint64_t offset, size_t len) override;
+ virtual void OnDerivedStringFound(BinaryNinja::BinaryView* data, const BinaryNinja::DerivedString& str) override;
+ virtual void OnDerivedStringRemoved(BinaryNinja::BinaryView* data, const BinaryNinja::DerivedString& str) override;
void updateStrings();
virtual void sort(int col, Qt::SortOrder order) override;