diff options
| author | Xusheng <xusheng@vector35.com> | 2024-07-26 15:57:14 +0800 |
|---|---|---|
| committer | Xusheng <xusheng@vector35.com> | 2024-08-02 12:17:53 +0800 |
| commit | abbae639d8ba182e8b3cf2d5a9844a9b1f9844a1 (patch) | |
| tree | 272322e3269b09201c12489d93e7fbeb614fb140 | |
| parent | 7a9a2503aae0c2b92b437b2ea7796efaae93a822 (diff) | |
Support setting user global pointer value
| -rw-r--r-- | binaryninjaapi.h | 40 | ||||
| -rw-r--r-- | binaryninjacore.h | 3 | ||||
| -rw-r--r-- | binaryview.cpp | 32 | ||||
| -rw-r--r-- | examples/triage/analysisinfo.cpp | 76 | ||||
| -rw-r--r-- | examples/triage/analysisinfo.h | 29 | ||||
| -rw-r--r-- | examples/triage/headers.cpp | 16 | ||||
| -rw-r--r-- | examples/triage/headers.h | 4 | ||||
| -rw-r--r-- | examples/triage/view.cpp | 7 | ||||
| -rw-r--r-- | function.cpp | 49 | ||||
| -rw-r--r-- | python/binaryview.py | 54 | ||||
| -rw-r--r-- | ui/possiblevaluesetdialog.h | 4 |
11 files changed, 285 insertions, 29 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 4cac3ff3..59c79631 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -4251,6 +4251,25 @@ namespace BinaryNinja { bool AutoDefined() const; }; + struct RegisterValue + { + BNRegisterValueType state; + int64_t value; + int64_t offset; + size_t size; + + bool operator==(const RegisterValue& a) const; + bool operator!=(const RegisterValue& a) const; + + RegisterValue(); + + bool IsConstant() const; + bool IsConstantData() const; + + static RegisterValue FromAPIObject(const BNRegisterValue& value); + BNRegisterValue ToAPIObject(); + }; + struct QualifiedNameAndType; struct PossibleValueSet; class Metadata; @@ -6730,6 +6749,11 @@ namespace BinaryNinja { void RemoveExternalLocation(Ref<Symbol> sourceSymbol); Ref<ExternalLocation> GetExternalLocation(Ref<Symbol> sourceSymbol); std::vector<Ref<ExternalLocation>> GetExternalLocations(); + + Confidence<RegisterValue> GetGlobalPointerValue() const; + bool UserGlobalPointerValueSet() const; + void ClearUserGlobalPointerValue(); + void SetUserGlobalPointerValue(const Confidence<RegisterValue>& value); }; class MemoryMap @@ -10286,22 +10310,6 @@ namespace BinaryNinja { /*! \ingroup function */ - struct RegisterValue - { - BNRegisterValueType state; - int64_t value; - int64_t offset; - size_t size; - - RegisterValue(); - - bool IsConstant() const; - bool IsConstantData() const; - - static RegisterValue FromAPIObject(const BNRegisterValue& value); - BNRegisterValue ToAPIObject(); - }; - struct ConstantData : public BNRegisterValue { Ref<Function> func = nullptr; diff --git a/binaryninjacore.h b/binaryninjacore.h index f0c7a22e..a17c9c24 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -3955,6 +3955,9 @@ extern "C" BINARYNINJACOREAPI void BNFreeNameSpace(BNNameSpace* name); BINARYNINJACOREAPI BNRegisterValueWithConfidence BNGetGlobalPointerValue(BNBinaryView* view); + BINARYNINJACOREAPI bool BNUserGlobalPointerValueSet(BNBinaryView* view); + BINARYNINJACOREAPI void BNClearUserGlobalPointerValue(BNBinaryView* view); + BINARYNINJACOREAPI void BNSetUserGlobalPointerValue(BNBinaryView* view, BNRegisterValueWithConfidence value); // Raw binary data view BINARYNINJACOREAPI BNBinaryView* BNCreateBinaryDataView(BNFileMetadata* file); diff --git a/binaryview.cpp b/binaryview.cpp index 861c7eb2..01ab7b95 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -5297,6 +5297,38 @@ std::vector<Ref<ExternalLocation>> BinaryView::GetExternalLocations() } +Confidence<RegisterValue> BinaryView::GetGlobalPointerValue() const +{ + BNRegisterValueWithConfidence value = BNGetGlobalPointerValue(m_object); + return Confidence<RegisterValue>(RegisterValue::FromAPIObject(value.value), value.confidence); +} + + +bool BinaryView::UserGlobalPointerValueSet() const +{ + return BNUserGlobalPointerValueSet(m_object); +} + + +void BinaryView::ClearUserGlobalPointerValue() +{ + return BNClearUserGlobalPointerValue(m_object); +} + + +void BinaryView::SetUserGlobalPointerValue(const Confidence<RegisterValue>& value) +{ + BNRegisterValueWithConfidence v; + v.confidence = value.GetConfidence(); + v.value.value = value.GetValue().value; + v.value.state = value.GetValue().state; + v.value.size = value.GetValue().size; + v.value.offset = value.GetValue().offset; + BNSetUserGlobalPointerValue(m_object, v); +} + + + Relocation::Relocation(BNRelocation* reloc) { m_object = reloc; diff --git a/examples/triage/analysisinfo.cpp b/examples/triage/analysisinfo.cpp new file mode 100644 index 00000000..a10b4472 --- /dev/null +++ b/examples/triage/analysisinfo.cpp @@ -0,0 +1,76 @@ +#include <QtCore/QTimer> +#include "analysisinfo.h" +#include "fontsettings.h" +#include "util.h" + +AnalysisInfoWidget::AnalysisInfoWidget(QWidget* parent, BinaryViewRef data): QWidget(parent), m_data(data) +{ + m_layout = new QGridLayout(); + m_layout->setContentsMargins(0, 0, 0, 0); + m_layout->setVerticalSpacing(1); + + auto* gpValueLayout = new QHBoxLayout(); + gpValueLayout->setContentsMargins(0, 0, 0, 0); + m_gpLabel = new NavigationAddressLabel(""); + m_gpLabel->setFont(getMonospaceFont(this)); + gpValueLayout->addWidget(m_gpLabel); + + m_gpExtraLabel = new QLabel; + gpValueLayout->addWidget(m_gpExtraLabel); + + m_layout->addWidget(new QLabel("Global Pointer Value:"), 0, 0); + m_layout->addLayout(gpValueLayout, 0, 1); + + const auto scaledWidth = UIContext::getScaledWindowSize(20, 20).width(); + this->m_layout->setColumnMinimumWidth(AnalysisInfoWidget::m_maxColumns * 3 - 1, scaledWidth); + this->m_layout->setColumnStretch(AnalysisInfoWidget::m_maxColumns * 3 - 1, 1); + setLayout(m_layout); + + updateDisplay(); + + auto* timer = new QTimer(this); + connect(timer, &QTimer::timeout, this, &AnalysisInfoWidget::timerExpired); + timer->setInterval(100); + timer->setSingleShot(false); + timer->start(); +} + + +AnalysisInfoWidget::~AnalysisInfoWidget() +{ + +} + + +void AnalysisInfoWidget::timerExpired() +{ + auto gpValue = m_data->GetGlobalPointerValue(); + if (gpValue == m_lastGPValue) + return; + + m_lastGPValue = gpValue; + updateDisplay(); +} + + +void AnalysisInfoWidget::updateDisplay() +{ + auto callingConvention = m_data->GetDefaultPlatform()->GetDefaultCallingConvention(); + auto gpRegister = callingConvention->GetGlobalPointerRegister(); + std::string gpString, gpExtraString; + if (gpRegister == BN_INVALID_REGISTER) + { + gpString = "N/A"; + } + else + { + auto gpValue = m_data->GetGlobalPointerValue(); + gpString = getStringForRegisterValue(m_data->GetDefaultArchitecture(), gpValue); + gpExtraString = std::string(" @ ") + m_data->GetDefaultArchitecture()->GetRegisterName(gpRegister); + if (m_data->UserGlobalPointerValueSet()) + gpExtraString += " (*)"; + } + + m_gpLabel->setText(QString::fromStdString(gpString)); + m_gpExtraLabel->setText(QString::fromStdString(gpExtraString)); +} diff --git a/examples/triage/analysisinfo.h b/examples/triage/analysisinfo.h new file mode 100644 index 00000000..4e6e6df3 --- /dev/null +++ b/examples/triage/analysisinfo.h @@ -0,0 +1,29 @@ +#pragma once + +#include <QtWidgets/QWidget> +#include <QtWidgets/QGridLayout> +#include <QtWidgets/QLabel> +#include "uitypes.h" +#include "headers.h" + +class TriageView; + +class AnalysisInfoWidget : public QWidget +{ + static constexpr std::int32_t m_maxColumns {2}; + BinaryViewRef m_data; + QGridLayout* m_layout {}; + NavigationAddressLabel* m_gpLabel; + QLabel* m_gpExtraLabel; + + BinaryNinja::Confidence<BinaryNinja::RegisterValue> m_lastGPValue; + + void updateDisplay(); + +public: + AnalysisInfoWidget(QWidget* parent, BinaryViewRef data); + virtual ~AnalysisInfoWidget(); + +private Q_SLOTS: + void timerExpired(); +}; diff --git a/examples/triage/headers.cpp b/examples/triage/headers.cpp index 1bdc31fe..6d6e2623 100644 --- a/examples/triage/headers.cpp +++ b/examples/triage/headers.cpp @@ -26,24 +26,24 @@ void NavigationLabel::mousePressEvent(QMouseEvent*) NavigationAddressLabel::NavigationAddressLabel(const QString& text) : NavigationLabel(text, getThemeColor(AddressColor), [this]() { clickEvent(); }) { - m_address = text.toULongLong(nullptr, 0); } void NavigationAddressLabel::clickEvent() { + auto address = text().toULongLong(nullptr, 0); ViewFrame* viewFrame = ViewFrame::viewFrameForWidget(this); if (viewFrame) { if (BinaryNinja::Settings::Instance()->Get<bool>("ui.view.graph.preferred") && viewFrame->getCurrentBinaryView() && - viewFrame->getCurrentBinaryView()->GetAnalysisFunctionsForAddress(m_address).size() > 0) + viewFrame->getCurrentBinaryView()->GetAnalysisFunctionsForAddress(address).size() > 0) { - viewFrame->navigate("Graph:" + viewFrame->getCurrentDataType(), m_address); + viewFrame->navigate("Graph:" + viewFrame->getCurrentDataType(), address); } else { - viewFrame->navigate("Linear:" + viewFrame->getCurrentDataType(), m_address); + viewFrame->navigate("Linear:" + viewFrame->getCurrentDataType(), address); } } } @@ -52,24 +52,24 @@ void NavigationAddressLabel::clickEvent() NavigationCodeLabel::NavigationCodeLabel(const QString& text) : NavigationLabel(text, getThemeColor(CodeSymbolColor), [this]() { clickEvent(); }) { - m_address = text.toULongLong(nullptr, 0); } void NavigationCodeLabel::clickEvent() { + auto address = text().toULongLong(nullptr, 0); ViewFrame* viewFrame = ViewFrame::viewFrameForWidget(this); if (viewFrame) { if (BinaryNinja::Settings::Instance()->Get<bool>("ui.view.graph.preferred") && viewFrame->getCurrentBinaryView() && - viewFrame->getCurrentBinaryView()->GetAnalysisFunctionsForAddress(m_address).size() > 0) + viewFrame->getCurrentBinaryView()->GetAnalysisFunctionsForAddress(address).size() > 0) { - viewFrame->navigate("Graph:" + viewFrame->getCurrentDataType(), m_address); + viewFrame->navigate("Graph:" + viewFrame->getCurrentDataType(), address); } else { - viewFrame->navigate("Linear:" + viewFrame->getCurrentDataType(), m_address); + viewFrame->navigate("Linear:" + viewFrame->getCurrentDataType(), address); } } } diff --git a/examples/triage/headers.h b/examples/triage/headers.h index a8348401..e96dead5 100644 --- a/examples/triage/headers.h +++ b/examples/triage/headers.h @@ -20,8 +20,6 @@ class NavigationLabel : public QLabel class NavigationAddressLabel : public NavigationLabel { - uint64_t m_address; - void clickEvent(); public: @@ -31,8 +29,6 @@ class NavigationAddressLabel : public NavigationLabel class NavigationCodeLabel : public NavigationLabel { - uint64_t m_address; - void clickEvent(); public: diff --git a/examples/triage/view.cpp b/examples/triage/view.cpp index 6a43d660..ad44da8c 100644 --- a/examples/triage/view.cpp +++ b/examples/triage/view.cpp @@ -12,6 +12,7 @@ #include "strings.h" #include "baseaddress.h" #include "fontsettings.h" +#include "analysisinfo.h" #include <binaryninjacore.h> TriageView::TriageView(QWidget* parent, BinaryViewRef data) : QScrollArea(parent) @@ -108,6 +109,12 @@ TriageView::TriageView(QWidget* parent, BinaryViewRef data) : QScrollArea(parent if (sectionsWidget->GetSections().size() == 0) sectionsGroup->hide(); + QGroupBox* analysisInfoGroup = new QGroupBox("Analysis Info", container); + QVBoxLayout* analysisInfoLayout = new QVBoxLayout(); + analysisInfoLayout->addWidget(new AnalysisInfoWidget(analysisInfoGroup, m_data)); + analysisInfoGroup->setLayout(analysisInfoLayout); + layout->addWidget(analysisInfoGroup); + QGroupBox* stringsGroup = new QGroupBox("Strings", container); QVBoxLayout* stringsLayout = new QVBoxLayout(); stringsLayout->addWidget(new StringsWidget(stringsGroup, this, m_data)); diff --git a/function.cpp b/function.cpp index 8497ccec..033a8453 100644 --- a/function.cpp +++ b/function.cpp @@ -104,6 +104,55 @@ Variable Variable::FromIdentifier(uint64_t id) RegisterValue::RegisterValue() : state(UndeterminedValue), value(0), offset(0), size(0) {} +bool RegisterValue::operator==(const RegisterValue& a) const +{ + switch (a.state) + { + case EntryValue: + return (state == EntryValue) && (a.value == value); + + case ConstantValue: + return (state == ConstantValue) && (a.value == value); + + case ConstantPointerValue: + return (state == ConstantPointerValue) && (a.value == value); + + case ExternalPointerValue: + return (state == ExternalPointerValue) && (a.value == value) && (a.offset == offset); + + case StackFrameOffset: + return (state == StackFrameOffset) && (a.value == value); + + case UndeterminedValue: + return state == UndeterminedValue; + + case ReturnAddressValue: + return state == ReturnAddressValue; + + case ImportedAddressValue: + return (state == ImportedAddressValue) && (a.value == value); + + case ConstantDataZeroExtendValue: + return (state == ConstantDataZeroExtendValue) && (a.value == value) && (a.size == size); + + case ConstantDataSignExtendValue: + return (state == ConstantDataSignExtendValue) && (a.value == value) && (a.size == size); + + case ConstantDataAggregateValue: + return (state == ConstantDataAggregateValue) && (a.value == value) && (a.size == size); + + default: + return false; + } +} + + +bool RegisterValue::operator!=(const RegisterValue& a) const +{ + return !((*this) == a); +} + + bool RegisterValue::IsConstant() const { return (state == ConstantValue) || (state == ConstantPointerValue); diff --git a/python/binaryview.py b/python/binaryview.py index aff1e28c..81202167 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -3326,6 +3326,60 @@ class BinaryView: return variable.RegisterValue.from_BNRegisterValue(result, self.arch) @property + def user_global_pointer_value_set(self) -> bool: + """Check whether a user global pointer value has been set""" + return core.BNUserGlobalPointerValueSet(self.handle) + + def clear_user_global_pointer_value(self): + """Clear a previously set user global pointer value, so the auto-analysis can calculate a new value""" + core.BNClearUserGlobalPointerValue(self.handle) + + def set_user_global_pointer_value(self, value: variable.RegisterValue, confidence = 255): + """ + Set a user global pointer value. This is useful when the auto analysis fails to find out the value of the global + pointer, or the value is wrong. In this case, we can call `set_user_global_pointer_value` with a + `ConstantRegisterValue` or `ConstantPointerRegisterValue`to provide a user global pointer value to assist the + analysis. + + On the other hand, if the auto analysis figures out a global pointer value, but there should not be one, we can + call `set_user_global_pointer_value` with an `Undetermined` value to override it. + + Whenever a user global pointer value is set/cleared, an analysis update must occur for it to take effect and + all functions using the global pointer to be updated. + + We can use `user_global_pointer_value_set` to query whether a user global pointer value is set, and use + `clear_user_global_pointer_value` to clear a user global pointer value. Note, `clear_user_global_pointer_value` + is different from calling `set_user_global_pointer_value` with an `Undetermined` value. The former clears the + user global pointer value and let the analysis decide the global pointer value, whereas the latte forces the + global pointer value to become undetermined. + + :param variable.RegisterValue value: the user global pointer value to be set + :param int confidence: the confidence value of the user global pointer value. In most cases this should be set + to 255. Setting a value lower than the confidence of the global pointer value from the auto analysis will cause + undesired effect. + :return: + :Example: + + >>> bv.global_pointer_value + <const ptr 0x3fd4> + >>> bv.set_user_global_pointer_value(ConstantPointerRegisterValue(0x12345678)) + >>> bv.global_pointer_value + <const ptr 0x12345678> + >>> bv.user_global_pointer_value_set + True + >>> bv.clear_user_global_pointer_value() + >>> bv.global_pointer_value + <const ptr 0x3fd4> + >>> bv.set_user_global_pointer_value(Undetermined()) + >>> bv.global_pointer_value + <undetermined> + """ + val = core.BNRegisterValueWithConfidence() + val.value = value._to_core_struct() + val.confidence = confidence + core.BNSetUserGlobalPointerValue(self.handle, val) + + @property def parameters_for_analysis(self): return core.BNGetParametersForAnalysis(self.handle) diff --git a/ui/possiblevaluesetdialog.h b/ui/possiblevaluesetdialog.h index 8f37f5bb..9291e4ea 100644 --- a/ui/possiblevaluesetdialog.h +++ b/ui/possiblevaluesetdialog.h @@ -18,6 +18,7 @@ class BINARYNINJAUIAPI PossibleValueSetDialog : public QDialog BinaryViewRef m_view; uint64_t m_addr; + bool m_registerValueOnly; QComboBox* m_combo; QLineEdit* m_input; @@ -31,7 +32,8 @@ class BINARYNINJAUIAPI PossibleValueSetDialog : public QDialog public: PossibleValueSetDialog( - QWidget* parent, BinaryViewRef view, uint64_t addr, BinaryNinja::PossibleValueSet existingValue); + QWidget* parent, BinaryViewRef view, uint64_t addr, BinaryNinja::PossibleValueSet existingValue, + const QString& title = "Set User Variable Value", bool registerValueOnly = false); BinaryNinja::PossibleValueSet getPossibleValueSet() const { return m_valueSet; } void validate(const QString& input); |
