summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXusheng <xusheng@vector35.com>2024-07-26 15:57:14 +0800
committerXusheng <xusheng@vector35.com>2024-08-02 12:17:53 +0800
commitabbae639d8ba182e8b3cf2d5a9844a9b1f9844a1 (patch)
tree272322e3269b09201c12489d93e7fbeb614fb140
parent7a9a2503aae0c2b92b437b2ea7796efaae93a822 (diff)
Support setting user global pointer value
-rw-r--r--binaryninjaapi.h40
-rw-r--r--binaryninjacore.h3
-rw-r--r--binaryview.cpp32
-rw-r--r--examples/triage/analysisinfo.cpp76
-rw-r--r--examples/triage/analysisinfo.h29
-rw-r--r--examples/triage/headers.cpp16
-rw-r--r--examples/triage/headers.h4
-rw-r--r--examples/triage/view.cpp7
-rw-r--r--function.cpp49
-rw-r--r--python/binaryview.py54
-rw-r--r--ui/possiblevaluesetdialog.h4
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);