summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/triage/strings.cpp298
-rw-r--r--examples/triage/strings.h71
-rw-r--r--examples/triage/view.cpp7
3 files changed, 376 insertions, 0 deletions
diff --git a/examples/triage/strings.cpp b/examples/triage/strings.cpp
new file mode 100644
index 00000000..f9a19455
--- /dev/null
+++ b/examples/triage/strings.cpp
@@ -0,0 +1,298 @@
+#include <string.h>
+#include <algorithm>
+#include "strings.h"
+#include "view.h"
+#include "fontsettings.h"
+
+
+GenericStringsModel::GenericStringsModel(BinaryViewRef data)
+{
+ m_data = data;
+ m_totalCols = 3;
+ m_sortCol = 0;
+ m_sortOrder = Qt::AscendingOrder;
+ m_allEntries = data->GetStrings();
+ m_entries = m_allEntries;
+}
+
+
+int GenericStringsModel::columnCount(const QModelIndex&) const
+{
+ return m_totalCols;
+}
+
+
+int GenericStringsModel::rowCount(const QModelIndex& parent) const
+{
+ if (parent.isValid())
+ return 0;
+ return (int)m_entries.size();
+}
+
+
+QVariant GenericStringsModel::data(const QModelIndex& index, int role) const
+{
+ switch (role)
+ {
+ case Qt::DisplayRole:
+ if (index.row() >= (int)m_entries.size())
+ return QVariant();
+ if (index.column() == 0)
+ return QString("0x") + QString::number(m_entries[index.row()].start, 16);
+ if (index.column() == 1)
+ return QString::number(m_entries[index.row()].length);
+ if (index.column() == 2)
+ return stringRefToQString(m_entries[index.row()]).replace("\n", "\\n");
+ break;
+ case Qt::ForegroundRole:
+ if (index.column() == 0)
+ return getThemeColor(AddressColor);
+ break;
+ }
+
+ return QVariant();
+}
+
+
+QVariant GenericStringsModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Vertical)
+ return QVariant();
+ if (role != Qt::DisplayRole)
+ return QVariant();
+ if (section == 0)
+ return QString("Address");
+ if (section == 1)
+ return QString("Length");
+ if (section == 2)
+ return QString("String");
+ return QVariant();
+}
+
+
+QModelIndex GenericStringsModel::index(int row, int col, const QModelIndex& parent) const
+{
+ if (parent.isValid())
+ return QModelIndex();
+ if (row >= (int)m_entries.size())
+ return QModelIndex();
+ if (col >= m_totalCols)
+ return QModelIndex();
+ return createIndex(row, col);
+}
+
+
+QModelIndex GenericStringsModel::parent(const QModelIndex&) const
+{
+ return QModelIndex();
+}
+
+
+QString GenericStringsModel::stringRefToQString(const BNStringReference& stringRef) const
+{
+ QString qstr;
+ BinaryNinja::DataBuffer stringBuffer = m_data->ReadBuffer(stringRef.start, stringRef.length);
+
+ if (stringRef.type == BNStringType::Utf32String)
+ {
+ char32_t* data = (char32_t*)stringBuffer.GetData();
+ qstr = QString::fromUcs4(data, stringRef.length / 4);
+ }
+ else if (stringRef.type == BNStringType::Utf16String)
+ {
+ char16_t* data = (char16_t*)stringBuffer.GetData();
+ qstr = QString::fromUtf16(data, stringRef.length / 2);
+ }
+ else
+ {
+ char* data = (char*)stringBuffer.GetData();
+ qstr = QString::fromUtf8(data, stringBuffer.GetLength());
+ }
+
+ return qstr;
+}
+
+
+BNStringReference GenericStringsModel::getStringRefAt(const QModelIndex& index) const
+{
+ if (index.row() >= (int)m_entries.size())
+ return BNStringReference{};
+ return m_entries[index.row()];
+}
+
+void GenericStringsModel::performSort(int col, Qt::SortOrder order)
+{
+ std::sort(m_entries.begin(), m_entries.end(), [&](BNStringReference a, BNStringReference b) {
+ if (col == 0)
+ {
+ if (order == Qt::AscendingOrder)
+ return a.start < b.start;
+ else
+ return a.start > b.start;
+ }
+ else if (col == 1)
+ {
+ if (order == Qt::AscendingOrder)
+ return a.length < b.length;
+ else
+ return a.length > b.length;
+ }
+ else if (col == 2)
+ {
+ QString s = stringRefToQString(a);
+ QString s2 = stringRefToQString(b);
+
+ if (order == Qt::AscendingOrder)
+ return s < s2;
+ else
+ return s > s2;
+ }
+ return false;
+ });
+}
+
+
+void GenericStringsModel::sort(int col, Qt::SortOrder order)
+{
+ beginResetModel();
+ m_sortCol = col;
+ m_sortOrder = order;
+ performSort(col, order);
+ endResetModel();
+}
+
+
+void GenericStringsModel::setFilter(const std::string& filterText)
+{
+ beginResetModel();
+ m_entries.clear();
+ for (auto& entry : m_allEntries)
+ {
+ auto s = stringRefToQString(entry).toStdString();
+
+ if (FilteredView::match(s, filterText))
+ m_entries.push_back(entry);
+ }
+ performSort(m_sortCol, m_sortOrder);
+ endResetModel();
+}
+
+
+StringsTreeView::StringsTreeView(StringsWidget* parent, TriageView* view, BinaryViewRef data) : QTreeView(parent)
+{
+ m_data = data;
+ m_parent = parent;
+ m_view = view;
+
+ // Allow view-specific shortcuts when strings are focused
+ m_actionHandler.setupActionHandler(this);
+ m_actionHandler.setActionContext([=]() { return m_view->actionContext(); });
+
+ m_model = new GenericStringsModel(m_data);
+ setModel(m_model);
+ setRootIsDecorated(false);
+ setUniformRowHeights(true);
+ setSortingEnabled(true);
+ sortByColumn(0, Qt::AscendingOrder);
+
+ setFont(getMonospaceFont(this));
+
+ connect(selectionModel(), &QItemSelectionModel::currentChanged, this, &StringsTreeView::stringSelected);
+ connect(this, &QTreeView::doubleClicked, this, &StringsTreeView::stringDoubleClicked);
+}
+
+
+void StringsTreeView::stringSelected(const QModelIndex& cur, const QModelIndex&)
+{
+ BNStringReference stringRef = m_model->getStringRefAt(cur);
+ if (stringRef.start == 0)
+ return;
+
+ m_view->setCurrentOffset(stringRef.start);
+}
+
+
+void StringsTreeView::stringDoubleClicked(const QModelIndex& cur)
+{
+ BNStringReference stringRef = m_model->getStringRefAt(cur);
+ if (stringRef.start == 0)
+ return;
+
+ ViewFrame* viewFrame = ViewFrame::viewFrameForWidget(this);
+ if (viewFrame)
+ {
+ viewFrame->navigate("Linear:" + viewFrame->getCurrentDataType(), stringRef.start);
+ }
+}
+
+
+void StringsTreeView::setFilter(const std::string& filterText)
+{
+ m_model->setFilter(filterText);
+}
+
+
+void StringsTreeView::scrollToFirstItem()
+{
+ scrollToTop();
+}
+
+
+void StringsTreeView::scrollToCurrentItem()
+{
+ scrollTo(currentIndex());
+}
+
+
+void StringsTreeView::selectFirstItem()
+{
+ setCurrentIndex(m_model->index(0, 0, QModelIndex()));
+}
+
+
+void StringsTreeView::activateFirstItem()
+{
+ stringDoubleClicked(m_model->index(0, 0, QModelIndex()));
+}
+
+
+void StringsTreeView::closeFilter()
+{
+ setFocus(Qt::OtherFocusReason);
+}
+
+
+void StringsTreeView::keyPressEvent(QKeyEvent* event)
+{
+ if ((event->text().size() == 1) && (event->text()[0] > ' ') && (event->text()[0] <= '~'))
+ {
+ m_parent->showFilter(event->text());
+ event->accept();
+ }
+ else if ((event->key() == Qt::Key_Return) || (event->key() == Qt::Key_Enter))
+ {
+ QList<QModelIndex> sel = selectionModel()->selectedIndexes();
+ if (sel.size() != 0)
+ stringDoubleClicked(sel[0]);
+ }
+ QTreeView::keyPressEvent(event);
+}
+
+
+StringsWidget::StringsWidget(QWidget* parent, TriageView* view, BinaryViewRef data) : QWidget(parent)
+{
+ QVBoxLayout* layout = new QVBoxLayout();
+ layout->setContentsMargins(0, 0, 0, 0);
+ StringsTreeView* strings = new StringsTreeView(this, view, data);
+ m_filter = new FilteredView(this, strings, strings);
+ m_filter->setFilterPlaceholderText("Search strings");
+ layout->addWidget(m_filter, 1);
+ setLayout(layout);
+ setMinimumSize(UIContext::getScaledWindowSize(100, 196));
+}
+
+
+void StringsWidget::showFilter(const QString& filter)
+{
+ m_filter->showFilter(filter);
+} \ No newline at end of file
diff --git a/examples/triage/strings.h b/examples/triage/strings.h
new file mode 100644
index 00000000..9148422c
--- /dev/null
+++ b/examples/triage/strings.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#include <QtCore/QAbstractItemModel>
+#include <QtWidgets/QTreeView>
+#include "filter.h"
+
+
+class GenericStringsModel : public QAbstractItemModel
+{
+ BinaryViewRef m_data;
+ std::vector<BNStringReference> m_allEntries, m_entries;
+ int m_totalCols, m_sortCol;
+ Qt::SortOrder m_sortOrder;
+
+ void performSort(int col, Qt::SortOrder order);
+
+ public:
+ GenericStringsModel(BinaryViewRef data);
+
+ virtual int columnCount(const QModelIndex& parent) const override;
+ virtual int rowCount(const QModelIndex& parent) const override;
+ virtual QVariant data(const QModelIndex& index, int role) const override;
+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+ virtual QModelIndex index(int row, int col, const QModelIndex& parent) const override;
+ virtual QModelIndex parent(const QModelIndex& index) const override;
+ virtual void sort(int col, Qt::SortOrder order) override;
+ void setFilter(const std::string& filterText);
+
+ BNStringReference getStringRefAt(const QModelIndex& index) const;
+ QString stringRefToQString(const BNStringReference& index) const;
+};
+
+
+class TriageView;
+class StringsWidget;
+
+class StringsTreeView : public QTreeView, public FilterTarget
+{
+ BinaryViewRef m_data;
+ StringsWidget* m_parent;
+ TriageView* m_view;
+ UIActionHandler m_actionHandler;
+ GenericStringsModel* m_model;
+
+ public:
+ StringsTreeView(StringsWidget* parent, TriageView* view, BinaryViewRef data);
+
+ virtual void setFilter(const std::string& filterText) override;
+ virtual void scrollToFirstItem() override;
+ virtual void scrollToCurrentItem() override;
+ virtual void selectFirstItem() override;
+ virtual void activateFirstItem() override;
+ virtual void closeFilter() override;
+
+ protected:
+ virtual void keyPressEvent(QKeyEvent* event) override;
+
+ private Q_SLOTS:
+ void stringSelected(const QModelIndex& cur, const QModelIndex& prev);
+ void stringDoubleClicked(const QModelIndex& cur);
+};
+
+
+class StringsWidget : public QWidget
+{
+ FilteredView* m_filter;
+
+ public:
+ StringsWidget(QWidget* parent, TriageView* view, BinaryViewRef data);
+ void showFilter(const QString& filter);
+}; \ No newline at end of file
diff --git a/examples/triage/view.cpp b/examples/triage/view.cpp
index dafd41bf..87cdb61a 100644
--- a/examples/triage/view.cpp
+++ b/examples/triage/view.cpp
@@ -9,6 +9,7 @@
#include "fileinfo.h"
#include "librariesinfo.h"
#include "headers.h"
+#include "strings.h"
#include "fontsettings.h"
#include <binaryninjacore.h>
@@ -96,6 +97,12 @@ TriageView::TriageView(QWidget* parent, BinaryViewRef data) : QScrollArea(parent
if (sectionsWidget->GetSections().size() == 0)
sectionsGroup->hide();
+ QGroupBox* stringsGroup = new QGroupBox("Strings", container);
+ QVBoxLayout* stringsLayout = new QVBoxLayout();
+ stringsLayout->addWidget(new StringsWidget(stringsGroup, this, m_data));
+ stringsGroup->setLayout(stringsLayout);
+ layout->addWidget(stringsGroup);
+
QHBoxLayout* buttonLayout = new QHBoxLayout();
buttonLayout->addStretch(1);
m_fullAnalysisButton = new QPushButton("Start Full Analysis");