diff options
| -rw-r--r-- | binaryninjaapi.h | 3 | ||||
| -rw-r--r-- | binaryninjacore.h | 2 | ||||
| -rw-r--r-- | binaryview.cpp | 21 | ||||
| -rw-r--r-- | function.cpp | 19 | ||||
| -rw-r--r-- | python/binaryview.py | 44 | ||||
| -rw-r--r-- | ui/clickablelabel.h | 17 | ||||
| -rw-r--r-- | ui/commands.h | 5 | ||||
| -rw-r--r-- | ui/flowgraphwidget.h | 2 | ||||
| -rw-r--r-- | ui/linearview.h | 2 | ||||
| -rw-r--r-- | ui/possiblevaluesetdialog.h | 60 | ||||
| -rw-r--r-- | ui/typedialog.h | 2 |
11 files changed, 167 insertions, 10 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 99d74b16..d399a71c 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1370,6 +1370,7 @@ __attribute__ ((format (printf, 1, 2))) }; struct QualifiedNameAndType; + struct PossibleValueSet; class Metadata; class QueryMetadataException: public std::exception { @@ -1659,6 +1660,8 @@ __attribute__ ((format (printf, 1, 2))) uint64_t GetPreviousDataBeforeAddress(uint64_t addr); uint64_t GetPreviousDataVariableStartBeforeAddress(uint64_t addr); + bool ParsePossibleValueSetString(const std::string& value, BNRegisterValueType state, PossibleValueSet& result, uint64_t here, std::string& errors); + bool ParseTypeString(const std::string& text, QualifiedNameAndType& result, std::string& errors, const std::set<QualifiedName>& typesAllowRedefinition = {}); bool ParseTypeString(const std::string& text, std::map<QualifiedName, Ref<Type>>& types, diff --git a/binaryninjacore.h b/binaryninjacore.h index 9a93f367..bf691026 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -3390,6 +3390,8 @@ __attribute__ ((format (printf, 1, 2))) BINARYNINJACOREAPI void BNClearUserVariableValue(BNFunction* func, const BNVariable* var, const BNArchitectureAndAddress* defSite); BINARYNINJACOREAPI BNUserVariableValue* BNGetAllUserVariableValues(BNFunction *func, size_t* count); BINARYNINJACOREAPI void BNFreeUserVariableValues(BNUserVariableValue* result); + BINARYNINJACOREAPI bool BNParsePossibleValueSetString(BNBinaryView* view, const char* valueText, BNRegisterValueType state, + BNPossibleValueSet* result, uint64_t here, char** errors); BINARYNINJACOREAPI void BNRequestFunctionDebugReport(BNFunction* func, const char* name); diff --git a/binaryview.cpp b/binaryview.cpp index 8d78c4b3..3953cee6 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -2446,6 +2446,27 @@ uint64_t BinaryView::GetPreviousDataVariableStartBeforeAddress(uint64_t addr) } +bool BinaryView::ParsePossibleValueSetString(const string& value, BNRegisterValueType state, PossibleValueSet& result, uint64_t here, string& errors) +{ + BNPossibleValueSet res; + char* errorStr; + + if (!BNParsePossibleValueSetString(m_object, value.c_str(), state, &res, here, &errorStr)) + { + if (!errorStr) + errors = ""; + else + errors = errorStr; + BNFreeString(errorStr); + return false; + } + + result = PossibleValueSet::FromAPIObject(res); + errors = ""; + return true; +} + + bool BinaryView::ParseTypeString(const string& text, QualifiedNameAndType& result, string& errors, const std::set<QualifiedName>& typesAllowRedefinition) { diff --git a/function.cpp b/function.cpp index ecb81a67..168decc2 100644 --- a/function.cpp +++ b/function.cpp @@ -1773,17 +1773,18 @@ Ref<FlowGraph> Function::GetUnresolvedStackAdjustmentGraph() void Function::SetUserVariableValue(const Variable& var, uint64_t defAddr, PossibleValueSet& value) { - auto mlil = GetMediumLevelIL(); - auto varDefs = mlil->GetVariableDefinitions(var); + Ref<MediumLevelILFunction> mlil = GetMediumLevelIL(); + const set<size_t>& varDefs = mlil->GetVariableDefinitions(var); if (varDefs.size() == 0) { LogError("Could not get definition for Variable"); return; } bool found = false; - for (const auto& site : varDefs) + for (auto& site : varDefs) { - if (site == defAddr) + const MediumLevelILInstruction& instr = mlil->GetInstruction(site); + if (instr.address == defAddr) { found = true; break; @@ -1810,16 +1811,18 @@ void Function::SetUserVariableValue(const Variable& var, uint64_t defAddr, Possi void Function::ClearUserVariableValue(const Variable& var, uint64_t defAddr) { - auto mlil = GetMediumLevelIL(); - auto varDefs = mlil->GetVariableDefinitions(var); + Ref<MediumLevelILFunction> mlil = GetMediumLevelIL(); + const set<size_t>& varDefs = mlil->GetVariableDefinitions(var); if (varDefs.size() == 0) { LogError("Could not get definition for Variable"); + return; } bool found = false; - for (auto site : varDefs) + for (auto& site : varDefs) { - if (site == defAddr) + const MediumLevelILInstruction& instr = mlil->GetInstruction(site); + if (instr.address == defAddr) { found = true; break; diff --git a/python/binaryview.py b/python/binaryview.py index 1cd57bf9..39af851c 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -4677,6 +4677,50 @@ class BinaryView(object): core.BNFreeTypeParserResult(parse) return types.TypeParserResult(type_dict, variables, functions) + def parse_possiblevalueset_string(self, value, state, here=0): + r""" + Evaluates a string representation of a PossibleValueSet into an instance of the ``PossibleValueSet`` value. + + .. note:: Values are evaluated based on the rules as specified for :py:meth:`parse_expression` API. This implies that a ``ConstantValue [0x4000].d`` can be provided given that 4 bytes can be read at ``0x4000``. All constants are considered to be in hexadecimal form by default. + + The parser uses the following rules: + - ConstantValue - ``<value>`` + - ConstantPointerValue - ``<value>`` + - StackFrameOffset - ``<value>`` + - SignedRangeValue - ``<value>:<value>:<value>{,<value>:<value>:<value>}*`` (Multiple ValueRanges can be provided by separating them by commas) + - UnsignedRangeValue - ``<value>:<value>:<value>{,<value>:<value>:<value>}*`` (Multiple ValueRanges can be provided by separating them by commas) + - InSetOfValues - ``<value>{,<value>}*`` + - NotInSetOfValues - ``<value>{,<value>}*`` + + :param str value: PossibleValueSet value to be parsed + :param RegisterValueType state: State for which the value is to be parsed + :param int here: (optional) Base address for relative expressions, defaults to zero + :rtype: PossibleValueSet + :Example: + + >>> psv_c = bv.parse_possiblevalueset_string("400", RegisterValueType.ConstantValue) + >>> psv_c + <const 0x400> + >>> psv_ur = bv.parse_possiblevalueset_string("1:10:1", RegisterValueType.UnsignedRangeValue) + >>> psv_ur + <unsigned ranges: [<range: 0x1 to 0x10>]> + >>> psv_is = bv.parse_possiblevalueset_string("1,2,3", RegisterValueType.InSetOfValues) + >>> psv_is + <in set([0x1, 0x2, 0x3])> + >>> + """ + result = core.BNPossibleValueSet(); + errors = ctypes.c_char_p(); + if not core.BNParsePossibleValueSetString(self.handle, value, state, result, here, errors): + if errors: + error_str = errors.value.decode("utf-8") + else: + error_str = "Error parsing specified PossibleValueSet" + core.BNFreePossibleValueSet(result) + core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) + raise ValueError(error_str) + return function.PossibleValueSet(self.arch, result) + def get_type_by_name(self, name): """ ``get_type_by_name`` returns the defined type whose name corresponds with the provided ``name`` diff --git a/ui/clickablelabel.h b/ui/clickablelabel.h new file mode 100644 index 00000000..df261494 --- /dev/null +++ b/ui/clickablelabel.h @@ -0,0 +1,17 @@ +#pragma once + +#include <QtWidgets/QLabel> + +class BINARYNINJAUIAPI ClickableLabel: public QLabel +{ + Q_OBJECT + +public: + ClickableLabel(QWidget* parent = nullptr, const QString& name = ""): QLabel(parent) { setText(name); } + +signals: + void clicked(); + +protected: + void mouseReleaseEvent(QMouseEvent* event) override { if (event->button() == Qt::LeftButton) emit clicked(); } +}; diff --git a/ui/commands.h b/ui/commands.h index cdbf16ff..d033fd21 100644 --- a/ui/commands.h +++ b/ui/commands.h @@ -22,6 +22,9 @@ bool BINARYNINJAUIAPI inputNewType(QWidget* parent, BinaryViewRef data, Function bool BINARYNINJAUIAPI createInferredMember(QWidget* parent, BinaryViewRef data, HighlightTokenState& highlight, FunctionRef func, BNFunctionGraphType type); +bool BINARYNINJAUIAPI inputPossibleValueSet(QWidget* parent, BinaryViewRef data, FunctionRef currentFunction, + HighlightTokenState& highlight, uint64_t defSiteAddress); + bool BINARYNINJAUIAPI overwriteCode(BinaryViewRef data, ArchitectureRef arch, uint64_t addr, size_t len, const BinaryNinja::DataBuffer& buffer); bool BINARYNINJAUIAPI overwriteCode(BinaryViewRef data, ArchitectureRef arch, @@ -33,4 +36,4 @@ StructureRef BINARYNINJAUIAPI getInnerMostStructureContainingOffset(BinaryViewRe const std::vector<std::string>& nameList, size_t nameIndex, size_t& offset, TypeRef& type, std::string& typeName); // Auto generate a structure name -std::string BINARYNINJAUIAPI createStructureName(BinaryViewRef data);
\ No newline at end of file +std::string BINARYNINJAUIAPI createStructureName(BinaryViewRef data); diff --git a/ui/flowgraphwidget.h b/ui/flowgraphwidget.h index 2a3a8b78..a6e02076 100644 --- a/ui/flowgraphwidget.h +++ b/ui/flowgraphwidget.h @@ -284,6 +284,8 @@ private Q_SLOTS: void followPointer(); void defineName(); void undefineName(); + void setUserVariableValue(); + void clearUserVariableValue(); void defineFuncName(); void undefineFunc(); void createFunc(); diff --git a/ui/linearview.h b/ui/linearview.h index 26c3e9d8..00f02c76 100644 --- a/ui/linearview.h +++ b/ui/linearview.h @@ -197,6 +197,8 @@ private Q_SLOTS: void defineNameAtAddr(uint64_t addr); void defineName(); void undefineName(); + void setUserVariableValue(); + void clearUserVariableValue(); void createFunc(); void createFuncWithPlatform(PlatformRef platform); void defineFuncName(); diff --git a/ui/possiblevaluesetdialog.h b/ui/possiblevaluesetdialog.h new file mode 100644 index 00000000..5b5550a3 --- /dev/null +++ b/ui/possiblevaluesetdialog.h @@ -0,0 +1,60 @@ +#pragma once + +#include <QtWidgets/QDialog> +#include <QtWidgets/QLabel> +#include <QtCore/QStringListModel> +#include <QtWidgets/QComboBox> +#include <QtWidgets/QLineEdit> +#include <QtCore/QTimer> +#include <QtCore/QThread> +#include <QToolTip> +#include "binaryninjaapi.h" +#include "dialogtextedit.h" +#include "clickablelabel.h" + +class BINARYNINJAUIAPI PossibleValueSetDialog: public QDialog +{ + Q_OBJECT + + QComboBox* m_combo; + QLineEdit* m_value; + QStringListModel* m_model; + QLabel* m_prompt; + QString m_promptText; + ClickableLabel* m_valueLabel; + BinaryViewRef m_view; + bool m_resultValid; + QStringList m_historyEntries; + int m_historySize; + QFont m_defaultFont; + bool m_initialTextSelection; + BinaryNinja::PossibleValueSet m_valueSet; + QPushButton* m_acceptButton; + QPalette m_defaultPalette; + QString m_parseError; + uint64_t m_here; + QTimer* m_updateTimer; + +private Q_SLOTS: + void accepted(); + void checkParse(); + void updateTimerEvent(); + void showHelp(); + void stateChanged(const QString&); + +public: + PossibleValueSetDialog(QWidget* parent, BinaryViewRef view, uint64_t here); + BinaryNinja::PossibleValueSet getPossibleValueSet() const { return m_valueSet; } + static BNRegisterValueType getRegisterValueTypeFromString(const std::string& stateStr); +}; + +static const QStringList valueSets = { + "ConstantValue", + "ConstantPointerValue", + "StackFrameOffset", + "SignedRangeValue", + "UnsignedRangeValue", + "InSetOfValues", + "NotInSetOfValues", + "UndeterminedValue", +}; diff --git a/ui/typedialog.h b/ui/typedialog.h index 34b68c07..00a722bc 100644 --- a/ui/typedialog.h +++ b/ui/typedialog.h @@ -64,4 +64,4 @@ public: const QString& prompt = "Enter Type Name", const QString& existing=""); ~TypeDialog() { delete m_updateThread; } BinaryNinja::QualifiedNameAndType getType() const { return m_type; } -};
\ No newline at end of file +}; |
