summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorJordan Wiens <github@psifertex.com>2026-01-01 12:21:22 -0500
committerJordan Wiens <github@psifertex.com>2026-01-01 12:21:22 -0500
commit37a0604d805991b85a0590279ad993a19ddee7bb (patch)
treefa8054497a4761f134ab5b537dfb0dbfc9a64f32 /examples
parent2448131059638409902821451115872036230328 (diff)
add whole-file entropy calculation to triage
Diffstat (limited to 'examples')
-rw-r--r--examples/triage/entropy.cpp30
-rw-r--r--examples/triage/entropy.h11
-rw-r--r--examples/triage/fileinfo.cpp26
-rw-r--r--examples/triage/fileinfo.h10
-rw-r--r--examples/triage/view.cpp5
-rw-r--r--examples/triage/view.h2
6 files changed, 79 insertions, 5 deletions
diff --git a/examples/triage/entropy.cpp b/examples/triage/entropy.cpp
index da089fd6..dd643af7 100644
--- a/examples/triage/entropy.cpp
+++ b/examples/triage/entropy.cpp
@@ -12,6 +12,8 @@ EntropyThread::EntropyThread(BinaryViewRef data, size_t blockSize, QImage* image
m_blockSize = blockSize;
m_updated = false;
m_running = true;
+ m_averageEntropy = 0.0;
+ m_sampleCount = 0;
m_thread = std::thread([=, this]() { Run(); });
}
@@ -33,10 +35,22 @@ void EntropyThread::Run()
std::vector<float> entropy =
m_data->GetEntropy(m_data->GetStart() + ((uint64_t)i * m_blockSize), m_blockSize, m_blockSize);
int v;
+ float entropyValue = 0.0f;
if (entropy.size() == 0)
v = 0;
else
- v = (int)(entropy[0] * 255);
+ {
+ entropyValue = entropy[0];
+ v = (int)(entropyValue * 255);
+ }
+
+ // Update running average
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_sampleCount++;
+ m_averageEntropy += (entropyValue - m_averageEntropy) / m_sampleCount;
+ }
+
if (v >= 240)
{
QColor color = getThemeColor(YellowStandardHighlightColor);
@@ -54,6 +68,13 @@ void EntropyThread::Run()
}
+double EntropyThread::GetAverageEntropy() const
+{
+ std::lock_guard<std::mutex> lock(m_mutex);
+ return m_averageEntropy;
+}
+
+
EntropyWidget::EntropyWidget(QWidget* parent, TriageView* view, BinaryViewRef data) : QWidget(parent)
{
m_view = view;
@@ -106,6 +127,7 @@ void EntropyWidget::timerExpired()
{
m_thread->ResetUpdated();
update();
+ emit entropyUpdated(m_thread->GetAverageEntropy());
}
}
@@ -131,3 +153,9 @@ void EntropyWidget::mouseMoveEvent(QMouseEvent* event)
else
setToolTip(QString("File offset: 0x%1").arg(offset, 0, 16));
}
+
+
+double EntropyWidget::getAverageEntropy() const
+{
+ return m_thread->GetAverageEntropy();
+}
diff --git a/examples/triage/entropy.h b/examples/triage/entropy.h
index 821dfb7b..bd50081d 100644
--- a/examples/triage/entropy.h
+++ b/examples/triage/entropy.h
@@ -3,6 +3,7 @@
#include <QtWidgets/QWidget>
#include <QtGui/QImage>
#include <thread>
+#include <mutex>
#include "uitypes.h"
@@ -13,6 +14,9 @@ class EntropyThread
size_t m_blockSize;
bool m_updated, m_running;
std::thread m_thread;
+ double m_averageEntropy;
+ int m_sampleCount;
+ mutable std::mutex m_mutex;
public:
EntropyThread(BinaryViewRef data, size_t blockSize, QImage* image);
@@ -21,6 +25,7 @@ class EntropyThread
void Run();
bool IsUpdated() { return m_updated; }
void ResetUpdated() { m_updated = false; }
+ double GetAverageEntropy() const;
};
@@ -28,6 +33,8 @@ class TriageView;
class EntropyWidget : public QWidget
{
+ Q_OBJECT
+
TriageView* m_view;
BinaryViewRef m_data, m_rawData;
size_t m_blockSize;
@@ -40,6 +47,10 @@ class EntropyWidget : public QWidget
virtual ~EntropyWidget();
virtual QSize sizeHint() const override;
+ double getAverageEntropy() const;
+
+ Q_SIGNALS:
+ void entropyUpdated(double avgEntropy);
protected:
virtual void paintEvent(QPaintEvent* event) override;
diff --git a/examples/triage/fileinfo.cpp b/examples/triage/fileinfo.cpp
index e18c94d8..22ce2423 100644
--- a/examples/triage/fileinfo.cpp
+++ b/examples/triage/fileinfo.cpp
@@ -1,4 +1,5 @@
#include "fileinfo.h"
+#include "entropy.h"
#include "fontsettings.h"
#include "theme.h"
#include "copyablelabel.h"
@@ -129,7 +130,7 @@ void FileInfoWidget::addHashFields(BinaryViewRef view)
});
}
-FileInfoWidget::FileInfoWidget(QWidget* parent, BinaryViewRef bv)
+FileInfoWidget::FileInfoWidget(QWidget* parent, BinaryViewRef bv, EntropyWidget* entropyWidget)
{
this->m_layout = new QGridLayout();
this->m_layout->setContentsMargins(0, 0, 0, 0);
@@ -157,10 +158,33 @@ FileInfoWidget::FileInfoWidget(QWidget* parent, BinaryViewRef bv)
const auto fileSize = QString::number(view->GetLength(), 16).prepend("0x");
this->addCopyableField("Size: ", fileSize);
+ // Display entropy value from the entropy widget
+ if (entropyWidget)
+ {
+ auto& [row, column] = this->m_fieldPosition;
+ m_entropyLabel = new CopyableLabel("Calculating...", getThemeColor(AlphanumericHighlightColor));
+ m_entropyLabel->setFont(getMonospaceFont(this));
+ this->m_layout->addWidget(new QLabel("Entropy: "), row, column);
+ this->m_layout->addWidget(m_entropyLabel, row++, column + 1);
+
+ // Connect to entropy updates
+ connect(entropyWidget, &EntropyWidget::entropyUpdated, this, &FileInfoWidget::updateEntropy);
+ }
+
this->addHashFields(view);
const auto scaledWidth = UIContext::getScaledWindowSize(20, 20).width();
this->m_layout->setColumnMinimumWidth(FileInfoWidget::m_maxColumns * 3 - 1, scaledWidth);
this->m_layout->setColumnStretch(FileInfoWidget::m_maxColumns * 3 - 1, 1);
setLayout(this->m_layout);
+}
+
+
+void FileInfoWidget::updateEntropy(double avgEntropy)
+{
+ if (m_entropyLabel)
+ {
+ const auto entropyStr = QString::number(avgEntropy, 'f', 6);
+ m_entropyLabel->setText(entropyStr);
+ }
} \ No newline at end of file
diff --git a/examples/triage/fileinfo.h b/examples/triage/fileinfo.h
index 78ba578b..8eac3fbe 100644
--- a/examples/triage/fileinfo.h
+++ b/examples/triage/fileinfo.h
@@ -5,11 +5,16 @@
#include "uitypes.h"
#include "viewframe.h"
+class EntropyWidget;
+
class FileInfoWidget : public QWidget
{
+ Q_OBJECT
+
static constexpr std::int32_t m_maxColumns {2};
std::pair<std::int32_t, std::int32_t> m_fieldPosition {}; // row, column
QGridLayout* m_layout {};
+ QLabel* m_entropyLabel {};
void addField(const QString& name, const QVariant& value);
void addCopyableField(const QString& name, const QVariant& value);
@@ -17,5 +22,8 @@ class FileInfoWidget : public QWidget
void addHashFields(BinaryViewRef view);
public:
- FileInfoWidget(QWidget* parent, BinaryViewRef bv);
+ FileInfoWidget(QWidget* parent, BinaryViewRef bv, EntropyWidget* entropyWidget);
+
+ private Q_SLOTS:
+ void updateEntropy(double avgEntropy);
};
diff --git a/examples/triage/view.cpp b/examples/triage/view.cpp
index 2c563470..0e995ae2 100644
--- a/examples/triage/view.cpp
+++ b/examples/triage/view.cpp
@@ -27,13 +27,14 @@ TriageView::TriageView(QWidget* parent, BinaryViewRef data) : QScrollArea(parent
QGroupBox* entropyGroup = new QGroupBox("Entropy", container);
QVBoxLayout* entropyLayout = new QVBoxLayout();
- entropyLayout->addWidget(new EntropyWidget(entropyGroup, this, m_data));
+ m_entropyWidget = new EntropyWidget(entropyGroup, this, m_data);
+ entropyLayout->addWidget(m_entropyWidget);
entropyGroup->setLayout(entropyLayout);
layout->addWidget(entropyGroup);
QGroupBox* fileInfoGroup = new QGroupBox("File Info", container);
QVBoxLayout* fileInfoLayout = new QVBoxLayout();
- fileInfoLayout->addWidget(new FileInfoWidget(fileInfoGroup, m_data));
+ fileInfoLayout->addWidget(new FileInfoWidget(fileInfoGroup, m_data, m_entropyWidget));
fileInfoGroup->setLayout(fileInfoLayout);
layout->addWidget(fileInfoGroup);
diff --git a/examples/triage/view.h b/examples/triage/view.h
index ab4f1024..fc9c7ff3 100644
--- a/examples/triage/view.h
+++ b/examples/triage/view.h
@@ -7,6 +7,7 @@
class HeaderWidget;
+class EntropyWidget;
class TriageView : public QScrollArea, public View
{
@@ -16,6 +17,7 @@ class TriageView : public QScrollArea, public View
QPushButton* m_fullAnalysisButton = nullptr;
QSplitter* m_importExportSplitter = nullptr;
HeaderWidget* m_headerWidget = nullptr;
+ EntropyWidget* m_entropyWidget = nullptr;
public:
TriageView(QWidget* parent, BinaryViewRef data);