summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2025-09-08 20:04:36 -0400
committerRusty Wagner <rusty.wagner@gmail.com>2025-10-21 13:52:39 -0400
commitcae26921cf2b2e564f66e58b77a3963fe36f6d2d (patch)
treebfa7ec8de23c1de758463a894583086c8d0b050e
parent11ad1fc28470b863326f7136cf9b5723a06e89d3 (diff)
Add constant renderer API
-rw-r--r--binaryninjaapi.h49
-rw-r--r--binaryninjacore.h28
-rw-r--r--binaryview.cpp6
-rw-r--r--constantrenderer.cpp151
-rw-r--r--python/__init__.py1
-rw-r--r--python/constantrenderer.py180
-rw-r--r--python/examples/encoded_strings.py58
7 files changed, 473 insertions, 0 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index fd1363b2..96105e66 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -4811,6 +4811,7 @@ namespace BinaryNinja {
public:
StringRef();
explicit StringRef(BNStringRef* ref);
+ StringRef(const std::string& str);
StringRef(const StringRef& other);
StringRef(StringRef&& other);
~StringRef();
@@ -21277,6 +21278,54 @@ namespace BinaryNinja {
std::vector<LinearDisassemblyLine>& lines
) override;
};
+
+ class ConstantRenderer : public StaticCoreRefCountObject<BNConstantRenderer>
+ {
+ std::string m_nameForRegister;
+
+ public:
+ ConstantRenderer(const std::string& name);
+ ConstantRenderer(BNConstantRenderer* renderer);
+
+ std::string GetName() const;
+
+ virtual bool IsValidForType(HighLevelILFunction* func, Type* type);
+ virtual bool RenderConstant(const HighLevelILInstruction& instr, Type* type, int64_t val,
+ HighLevelILTokenEmitter& tokens, DisassemblySettings* settings, BNOperatorPrecedence precedence);
+ virtual bool RenderConstantPointer(const HighLevelILInstruction& instr, Type* type, int64_t val,
+ HighLevelILTokenEmitter& tokens, DisassemblySettings* settings, BNSymbolDisplayType symbolDisplay,
+ BNOperatorPrecedence precedence);
+
+ /*! Registers the constant renderer.
+
+ \param renderer The constant renderer to register.
+ */
+ static void Register(ConstantRenderer* renderer);
+
+ static Ref<ConstantRenderer> GetByName(const std::string& name);
+ static std::vector<Ref<ConstantRenderer>> GetRenderers();
+
+ private:
+ static bool IsValidForTypeCallback(void* ctxt, BNHighLevelILFunction* hlil, BNType* type);
+ static bool RenderConstantCallback(void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type,
+ int64_t val, BNHighLevelILTokenEmitter* tokens, BNDisassemblySettings* settings,
+ BNOperatorPrecedence precedence);
+ static bool RenderConstantPointerCallback(void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type,
+ int64_t val, BNHighLevelILTokenEmitter* tokens, BNDisassemblySettings* settings,
+ BNSymbolDisplayType symbolDisplay, BNOperatorPrecedence precedence);
+ };
+
+ class CoreConstantRenderer : public ConstantRenderer
+ {
+ public:
+ CoreConstantRenderer(BNConstantRenderer* renderer);
+ bool IsValidForType(HighLevelILFunction* func, Type* type) override;
+ bool RenderConstant(const HighLevelILInstruction& instr, Type* type, int64_t val,
+ HighLevelILTokenEmitter& tokens, DisassemblySettings* settings, BNOperatorPrecedence precedence) override;
+ bool RenderConstantPointer(const HighLevelILInstruction& instr, Type* type, int64_t val,
+ HighLevelILTokenEmitter& tokens, DisassemblySettings* settings, BNSymbolDisplayType symbolDisplay,
+ BNOperatorPrecedence precedence) override;
+ };
} // namespace BinaryNinja
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 60850f38..89037998 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -311,6 +311,7 @@ extern "C"
typedef struct BNStringRef BNStringRef;
typedef struct BNIndirectBranchInfo BNIndirectBranchInfo;
typedef struct BNArchitectureAndAddress BNArchitectureAndAddress;
+ typedef struct BNConstantRenderer BNConstantRenderer;
typedef struct BNRemoteFileSearchMatch
{
@@ -3814,6 +3815,17 @@ extern "C"
char* value;
} BNTypeAttribute;
+ typedef struct BNCustomConstantRenderer
+ {
+ void* context;
+ bool (*isValidForType)(void* ctxt, BNHighLevelILFunction* hlil, BNType* type);
+ bool (*renderConstant)(void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type, int64_t val,
+ BNHighLevelILTokenEmitter* tokens, BNDisassemblySettings* settings, BNOperatorPrecedence precedence);
+ bool (*renderConstantPointer)(void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type, int64_t val,
+ BNHighLevelILTokenEmitter* tokens, BNDisassemblySettings* settings, BNSymbolDisplayType symbolDisplay,
+ BNOperatorPrecedence precedence);
+ } BNCustomConstantRenderer;
+
BINARYNINJACOREAPI char* BNAllocString(const char* contents);
BINARYNINJACOREAPI char* BNAllocStringWithLength(const char* contents, size_t len);
BINARYNINJACOREAPI void BNFreeString(char* str);
@@ -8690,6 +8702,22 @@ extern "C"
BINARYNINJACOREAPI const char* BNGetStringRefContents(BNStringRef* ref);
BINARYNINJACOREAPI size_t BNGetStringRefSize(BNStringRef* ref);
+ // 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 char* BNGetConstantRendererName(BNConstantRenderer* renderer);
+ BINARYNINJACOREAPI bool BNIsConstantRendererValidForType(
+ BNConstantRenderer* renderer, BNHighLevelILFunction* il, BNType* type);
+ BINARYNINJACOREAPI bool BNConstantRendererRenderConstant(BNConstantRenderer* renderer, BNHighLevelILFunction* il,
+ size_t exprIndex, BNType* type, int64_t val, BNHighLevelILTokenEmitter* tokens, BNDisassemblySettings* settings,
+ BNOperatorPrecedence precedence);
+ BINARYNINJACOREAPI bool BNConstantRendererRenderConstantPointer(BNConstantRenderer* renderer,
+ BNHighLevelILFunction* il, size_t exprIndex, BNType* type, int64_t val, BNHighLevelILTokenEmitter* tokens,
+ BNDisassemblySettings* settings, BNSymbolDisplayType symbolDisplay, BNOperatorPrecedence precedence);
+
#ifdef __cplusplus
}
#endif
diff --git a/binaryview.cpp b/binaryview.cpp
index 66b7e77f..292b11ac 100644
--- a/binaryview.cpp
+++ b/binaryview.cpp
@@ -662,6 +662,12 @@ StringRef::StringRef(BNStringRef* ref)
}
+StringRef::StringRef(const std::string& str)
+{
+ m_ref = BNCreateStringRefOfLength(str.c_str(), str.size());
+}
+
+
StringRef::StringRef(const StringRef& other)
{
m_ref = BNDuplicateStringRef(other.m_ref);
diff --git a/constantrenderer.cpp b/constantrenderer.cpp
new file mode 100644
index 00000000..1080c846
--- /dev/null
+++ b/constantrenderer.cpp
@@ -0,0 +1,151 @@
+#include "binaryninjaapi.h"
+#include "ffi.h"
+#include "highlevelilinstruction.h"
+
+using namespace BinaryNinja;
+using namespace std;
+
+
+ConstantRenderer::ConstantRenderer(const std::string& name): m_nameForRegister(name)
+{
+ m_object = nullptr;
+}
+
+
+ConstantRenderer::ConstantRenderer(BNConstantRenderer* renderer)
+{
+ m_object = renderer;
+}
+
+
+string ConstantRenderer::GetName() const
+{
+ char* name = BNGetConstantRendererName(m_object);
+ string result = name;
+ BNFreeString(name);
+ return result;
+}
+
+
+bool ConstantRenderer::IsValidForType(HighLevelILFunction*, Type*)
+{
+ return true;
+}
+
+
+bool ConstantRenderer::RenderConstant(const HighLevelILInstruction&, Type*, int64_t,
+ HighLevelILTokenEmitter&, DisassemblySettings*, BNOperatorPrecedence)
+{
+ return false;
+}
+
+
+bool ConstantRenderer::RenderConstantPointer(const HighLevelILInstruction&, Type*, int64_t,
+ HighLevelILTokenEmitter&, DisassemblySettings*, BNSymbolDisplayType, BNOperatorPrecedence)
+{
+ return false;
+}
+
+
+void ConstantRenderer::Register(ConstantRenderer* renderer)
+{
+ BNCustomConstantRenderer callbacks;
+ callbacks.context = renderer;
+ callbacks.isValidForType = IsValidForTypeCallback;
+ callbacks.renderConstant = RenderConstantCallback;
+ callbacks.renderConstantPointer = RenderConstantPointerCallback;
+
+ renderer->AddRefForRegistration();
+ renderer->m_object = BNRegisterConstantRenderer(renderer->m_nameForRegister.c_str(), &callbacks);
+}
+
+
+bool ConstantRenderer::IsValidForTypeCallback(void* ctxt, BNHighLevelILFunction* hlil, BNType* type)
+{
+ ConstantRenderer* renderer = (ConstantRenderer*)ctxt;
+ Ref<HighLevelILFunction> hlilObj = new HighLevelILFunction(BNNewHighLevelILFunctionReference(hlil));
+ Ref<Type> typeObj = new Type(BNNewTypeReference(type));
+ return renderer->IsValidForType(hlilObj, typeObj);
+}
+
+
+bool ConstantRenderer::RenderConstantCallback(void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type,
+ int64_t val, BNHighLevelILTokenEmitter* tokens, BNDisassemblySettings* settings,
+ BNOperatorPrecedence precedence)
+{
+ ConstantRenderer* renderer = (ConstantRenderer*)ctxt;
+ Ref<HighLevelILFunction> hlilObj = new HighLevelILFunction(BNNewHighLevelILFunctionReference(hlil));
+ HighLevelILInstruction instr = hlilObj->GetExpr(expr);
+ Ref<Type> typeObj = new Type(BNNewTypeReference(type));
+ Ref<HighLevelILTokenEmitter> tokenObj = new HighLevelILTokenEmitter(BNNewHighLevelILTokenEmitterReference(tokens));
+ Ref<DisassemblySettings> settingsObj = settings ? new DisassemblySettings(BNNewDisassemblySettingsReference(settings)) : nullptr;
+ return renderer->RenderConstant(instr, typeObj, val, *tokenObj, settingsObj, precedence);
+}
+
+
+bool ConstantRenderer::RenderConstantPointerCallback(void* ctxt, BNHighLevelILFunction* hlil, size_t expr, BNType* type,
+ int64_t val, BNHighLevelILTokenEmitter* tokens, BNDisassemblySettings* settings, BNSymbolDisplayType symbolDisplay,
+ BNOperatorPrecedence precedence)
+{
+ ConstantRenderer* renderer = (ConstantRenderer*)ctxt;
+ Ref<HighLevelILFunction> hlilObj = new HighLevelILFunction(BNNewHighLevelILFunctionReference(hlil));
+ HighLevelILInstruction instr = hlilObj->GetExpr(expr);
+ Ref<Type> typeObj = new Type(BNNewTypeReference(type));
+ Ref<HighLevelILTokenEmitter> tokenObj = new HighLevelILTokenEmitter(BNNewHighLevelILTokenEmitterReference(tokens));
+ Ref<DisassemblySettings> settingsObj = settings ? new DisassemblySettings(BNNewDisassemblySettingsReference(settings)) : nullptr;
+ return renderer->RenderConstantPointer(instr, typeObj, val, *tokenObj, settingsObj, symbolDisplay, precedence);
+}
+
+
+Ref<ConstantRenderer> ConstantRenderer::GetByName(const std::string& name)
+{
+ BNConstantRenderer* renderer = BNGetConstantRendererByName(name.c_str());
+ if (!renderer)
+ return nullptr;
+ return new CoreConstantRenderer(renderer);
+}
+
+
+vector<Ref<ConstantRenderer>> ConstantRenderer::GetRenderers()
+{
+ size_t count = 0;
+ BNConstantRenderer** renderers = BNGetConstantRendererList(&count);
+
+ vector<Ref<ConstantRenderer>> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i++)
+ result.push_back(new CoreConstantRenderer(renderers[i]));
+
+ BNFreeConstantRendererList(renderers);
+ return result;
+}
+
+
+CoreConstantRenderer::CoreConstantRenderer(BNConstantRenderer* renderer):
+ ConstantRenderer(renderer)
+{
+}
+
+
+bool CoreConstantRenderer::IsValidForType(HighLevelILFunction* func, Type* type)
+{
+ return BNIsConstantRendererValidForType(m_object, func->GetObject(), type->GetObject());
+}
+
+
+bool CoreConstantRenderer::RenderConstant(const HighLevelILInstruction& instr, Type* type, int64_t val,
+ HighLevelILTokenEmitter& tokens, DisassemblySettings* settings, BNOperatorPrecedence precedence)
+{
+ return BNConstantRendererRenderConstant(m_object, instr.function->GetObject(), instr.exprIndex,
+ type->GetObject(), val, tokens.GetObject(), settings ? settings->GetObject() : nullptr, precedence);
+}
+
+
+bool CoreConstantRenderer::RenderConstantPointer(const HighLevelILInstruction& instr, Type* type, int64_t val,
+ HighLevelILTokenEmitter& tokens, DisassemblySettings* settings, BNSymbolDisplayType symbolDisplay,
+ BNOperatorPrecedence precedence)
+{
+ return BNConstantRendererRenderConstantPointer(m_object, instr.function->GetObject(), instr.exprIndex,
+ type->GetObject(), val, tokens.GetObject(), settings ? settings->GetObject() : nullptr,
+ symbolDisplay, precedence);
+}
diff --git a/python/__init__.py b/python/__init__.py
index 77c64fce..acf8b293 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -82,6 +82,7 @@ from .fileaccessor import *
from .languagerepresentation import *
from .lineformatter import *
from .renderlayer import *
+from .constantrenderer 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/constantrenderer.py b/python/constantrenderer.py
new file mode 100644
index 00000000..abd98be7
--- /dev/null
+++ b/python/constantrenderer.py
@@ -0,0 +1,180 @@
+# 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.
+
+import traceback
+import ctypes
+from typing import Optional
+
+import binaryninja
+from . import _binaryninjacore as core
+from . import function
+from . import enums
+from .log import log_error_for_exception
+from . import types
+from . import highlevelil
+from . import languagerepresentation
+
+
+class _ConstantRendererMetaClass(type):
+ def __iter__(self):
+ binaryninja._init_plugins()
+ count = ctypes.c_ulonglong()
+ renderers = core.BNGetConstantRendererList(count)
+ assert renderers is not None, "core.BNGetConstantRendererList returned None"
+ try:
+ for i in range(0, count.value):
+ yield CoreConstantRenderer(handle=renderers[i])
+ finally:
+ core.BNFreeConstantRendererList(renderers)
+
+ def __getitem__(cls, value):
+ binaryninja._init_plugins()
+ renderer = core.BNGetConstantRendererByName(str(value))
+ if renderer is None:
+ raise KeyError("'%s' is not a valid renderer" % str(value))
+ return CoreConstantRenderer(handle=renderer)
+
+
+class ConstantRenderer(metaclass=_ConstantRendererMetaClass):
+ _registered_renderers = []
+ renderer_name = None
+
+ def __init__(self, handle=None):
+ if handle is not None:
+ self.handle = core.handle_of_type(handle, core.BNConstantRenderer)
+
+ def register(self):
+ if self.__class__.renderer_name is None:
+ raise ValueError("Renderer name is missing")
+ self._cb = core.BNCustomConstantRenderer()
+ self._cb.context = 0
+ if self.is_valid_for_type.__func__ != ConstantRenderer.is_valid_for_type:
+ self._cb.isValidForType = self._cb.isValidForType.__class__(self._is_valid_for_type)
+ if self.render_constant.__func__ != ConstantRenderer.render_constant:
+ self._cb.renderConstant = self._cb.renderConstant.__class__(self._render_constant)
+ if self.render_constant_pointer.__func__ != ConstantRenderer.render_constant_pointer:
+ self._cb.renderConstantPointer = self._cb.renderConstantPointer.__class__(self._render_constant_pointer)
+ self.handle = core.BNRegisterConstantRenderer(self.__class__.renderer_name, self._cb)
+ self.__class__._registered_renderers.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 ConstantRenderer._is_valid_for_type")
+ return False
+
+ def _render_constant(self, ctxt, hlil, expr, type, val, tokens, settings, precedence):
+ try:
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ type = types.Type.create(handle=core.BNNewTypeReference(type))
+ tokens = languagerepresentation.HighLevelILTokenEmitter(core.BNNewHighLevelILTokenEmitterReference(tokens))
+ if settings:
+ settings = function.DisassemblySettings(core.BNNewDisassemblySettingsReference(settings))
+ instr = hlil.get_expr(highlevelil.ExpressionIndex(expr))
+ return self.render_constant(instr, type, val, tokens, settings, precedence)
+ except:
+ log_error_for_exception("Unhandled Python exception in ConstantRenderer._render_constant_pointer")
+ return False
+
+ def _render_constant_pointer(self, ctxt, hlil, expr, type, val, tokens, settings, symbol_display, precedence):
+ try:
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ type = types.Type.create(handle=core.BNNewTypeReference(type))
+ tokens = languagerepresentation.HighLevelILTokenEmitter(core.BNNewHighLevelILTokenEmitterReference(tokens))
+ if settings:
+ settings = function.DisassemblySettings(core.BNNewDisassemblySettingsReference(settings))
+ symbol_display = enums.SymbolDisplayType(symbol_display)
+ instr = hlil.get_expr(highlevelil.ExpressionIndex(expr))
+ return self.render_constant_pointer(instr, type, val, tokens, settings, symbol_display, precedence)
+ except:
+ log_error_for_exception("Unhandled Python exception in ConstantRenderer._render_constant_pointer")
+ return False
+
+ @property
+ def name(self) -> str:
+ if hasattr(self, 'handle'):
+ return core.BNGetConstantRendererName(self.handle)
+ return self.__class__.renderer_name
+
+ def is_valid_for_type(self, func: 'highlevelil.HighLevelILFunction', type: 'types.Type') -> bool:
+ return True
+
+ def render_constant(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int,
+ tokens: 'languagerepresentation.HighLevelILTokenEmitter',
+ settings: Optional['function.DisassemblySettings'], precedence: 'enums.OperatorPrecedence'
+ ) -> bool:
+ return False
+
+ def render_constant_pointer(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int,
+ tokens: 'languagerepresentation.HighLevelILTokenEmitter',
+ settings: Optional['function.DisassemblySettings'], symbol_display: 'enums.SymbolDisplayType',
+ precedence: 'enums.OperatorPrecedence'
+ ) -> bool:
+ return False
+
+
+_renderer_cache = {}
+
+
+class CoreConstantRenderer(ConstantRenderer):
+ def __init__(self, handle: core.BNConstantRenderer):
+ super(CoreConstantRenderer, self).__init__(handle=handle)
+ if type(self) is CoreConstantRenderer:
+ global _renderer_cache
+ _renderer_cache[ctypes.addressof(handle.contents)] = self
+
+ @classmethod
+ def _from_cache(cls, handle) -> 'ConstantRenderer':
+ """
+ Look up a renderer type from a given BNConstantRenderer handle
+ :param handle: BNConstantRenderer pointer
+ :return: Renderer type instance responsible for this handle
+ """
+ global _renderer_cache
+ return _renderer_cache.get(ctypes.addressof(handle.contents)) or cls(handle)
+
+ def is_valid_for_type(self, func: 'highlevelil.HighLevelILFunction', type: 'types.Type') -> bool:
+ return core.BNIsConstantRendererValidForType(self.handle, func.handle, type.handle)
+
+ def render_constant(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int,
+ tokens: 'languagerepresentation.HighLevelILTokenEmitter',
+ settings: Optional['function.DisassemblySettings'], precedence: 'enums.OperatorPrecedence'
+ ) -> bool:
+ if settings is not None:
+ settings = settings.handle
+ return core.BNConstantRendererRenderConstant(self.handle, instr.function.handle, instr.expr_index,
+ type.handle, val, tokens.handle, settings, precedence)
+
+ def render_constant_pointer(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int,
+ tokens: 'languagerepresentation.HighLevelILTokenEmitter',
+ settings: Optional['function.DisassemblySettings'], symbol_display: 'enums.SymbolDisplayType',
+ precedence: 'enums.OperatorPrecedence'
+ ) -> bool:
+ if settings is not None:
+ settings = settings.handle
+ return core.BNConstantRendererRenderConstantPointer(self.handle, instr.function.handle, instr.expr_index,
+ type.handle, val, tokens.handle, settings, symbol_display, precedence)
diff --git a/python/examples/encoded_strings.py b/python/examples/encoded_strings.py
new file mode 100644
index 00000000..ce7d02db
--- /dev/null
+++ b/python/examples/encoded_strings.py
@@ -0,0 +1,58 @@
+from binaryninja import (ConstantRenderer, PointerType, InstructionTextToken, InstructionTextTokenType, DataBuffer)
+
+
+class EncodedStringConstantRenderer(ConstantRenderer):
+ renderer_name = "encoded_strings"
+ decoders = {
+ "xor_encoded": lambda encoded, key: encoded ^ key,
+ "sub_encoded": lambda encoded, key: (encoded - key) & 0xff,
+ "add_encoded": lambda encoded, key: (encoded + key) & 0xff
+ }
+
+ def is_valid_for_type(self, func, type):
+ if not isinstance(type, PointerType):
+ return False
+ for name in self.__class__.decoders.keys():
+ if name in type.target.attributes:
+ return True
+ return False
+
+ def render_constant_pointer(self, instr, type, val, tokens, settings, precedence):
+ if not isinstance(type, PointerType):
+ return False
+
+ values = None
+ decoder = None
+ for name in self.__class__.decoders.keys():
+ if name in type.target.attributes:
+ try:
+ values = bytes.fromhex(type.target.attributes[name])
+ decoder = self.__class__.decoders[name]
+ except:
+ return False
+ if values is None or decoder is None:
+ return False
+
+ encoded_null = "encoded_null" in type.target.attributes
+
+ result = b""
+ i = 0
+ while True:
+ byte = instr.function.view.read(val + i, 1)
+ if len(byte) != 1:
+ return False
+ if not encoded_null and byte[0] == 0:
+ break
+ byte = decoder(byte[0], values[i % len(values)])
+ if byte == 0:
+ break
+ 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
+
+
+EncodedStringConstantRenderer().register()