From 0311feee9bc463700d45fede8a8927661afcb7e2 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Wed, 28 Dec 2022 23:06:49 +0100 Subject: [PATCH] feat: Further improve information view --- .../content/views/view_information.hpp | 11 +-- plugins/builtin/romfs/lang/en_US.json | 4 + .../source/content/views/view_information.cpp | 74 ++++++++++++++----- 3 files changed, 65 insertions(+), 24 deletions(-) diff --git a/plugins/builtin/include/content/views/view_information.hpp b/plugins/builtin/include/content/views/view_information.hpp index fa2b62020..e8800474d 100644 --- a/plugins/builtin/include/content/views/view_information.hpp +++ b/plugins/builtin/include/content/views/view_information.hpp @@ -21,11 +21,12 @@ namespace hex::plugin::builtin { void drawContent() override; private: - bool m_dataValid = false; - u32 m_blockSize = 0; - float m_averageEntropy = 0; - float m_highestBlockEntropy = 0; - std::vector m_blockEntropy; + bool m_dataValid = false; + u32 m_blockSize = 0; + double m_averageEntropy = -1.0; + double m_highestBlockEntropy = -1.0; + double m_plainTextCharacterPercentage = -1.0; + std::vector m_blockEntropy; std::array, 12> m_blockTypeDistributions; u64 m_processedBlockCount = 0; diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index add8ce2ac..d260f3016 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -43,6 +43,7 @@ "hex.builtin.common.offset": "Offset", "hex.builtin.common.okay": "Okay", "hex.builtin.common.open": "Open", + "hex.builtin.common.percentage": "Percentage", "hex.builtin.common.processing": "Processing", "hex.builtin.common.question": "Question", "hex.builtin.common.range": "Range", @@ -697,6 +698,9 @@ "hex.builtin.view.information.mime": "MIME Type:", "hex.builtin.view.information.name": "Data Information", "hex.builtin.view.information.region": "Analyzed region", + "hex.builtin.view.information.plain_text": "This data is most likely plain text.", + "hex.builtin.view.information.plain_text_percentage": "Plain text percentage", + "hex.builtin.view.patches.name": "Patches", "hex.builtin.view.patches.offset": "Offset", "hex.builtin.view.patches.orig": "Original value", diff --git a/plugins/builtin/source/content/views/view_information.cpp b/plugins/builtin/source/content/views/view_information.cpp index d5e21d5d6..b3be1d128 100644 --- a/plugins/builtin/source/content/views/view_information.cpp +++ b/plugins/builtin/source/content/views/view_information.cpp @@ -23,9 +23,10 @@ namespace hex::plugin::builtin { ViewInformation::ViewInformation() : View("hex.builtin.view.information.name") { EventManager::subscribe(this, [this]() { this->m_dataValid = false; - this->m_highestBlockEntropy = 0; + this->m_plainTextCharacterPercentage = -1.0; + this->m_averageEntropy = -1.0; + this->m_highestBlockEntropy = -1.0; this->m_blockEntropy.clear(); - this->m_averageEntropy = 0; this->m_blockSize = 0; this->m_valueCounts.fill(0x00); this->m_dataMimeType.clear(); @@ -60,19 +61,19 @@ namespace hex::plugin::builtin { EventManager::unsubscribe(this); } - static float calculateEntropy(std::array &valueCounts, size_t blockSize) { - float entropy = 0; + static double calculateEntropy(std::array &valueCounts, size_t blockSize) { + double entropy = 0; for (auto count : valueCounts) { if (count == 0) [[unlikely]] continue; - float probability = static_cast(count) / blockSize; + double probability = static_cast(count) / blockSize; entropy += probability * std::log2(probability); } - return (-entropy) / 8; // log2(256) = 8 + return std::min(1.0, (-entropy) / 8); // log2(256) = 8 } static std::array calculateTypeDistribution(std::array &valueCounts, size_t blockSize) { @@ -149,6 +150,9 @@ namespace hex::plugin::builtin { this->m_valueCounts.fill(0); this->m_processedBlockCount = 0; + this->m_averageEntropy = -1.0; + this->m_highestBlockEntropy = -1.0; + this->m_plainTextCharacterPercentage = -1.0; this->m_digram.process(provider, this->m_analyzedRegion.getStartAddress(), this->m_analyzedRegion.getSize()); this->m_layeredDistribution.process(provider, this->m_analyzedRegion.getStartAddress(), this->m_analyzedRegion.getSize()); @@ -157,18 +161,21 @@ namespace hex::plugin::builtin { reader.setEndAddress(provider->getBaseAddress() + provider->getSize()); u64 count = 0; + for (u8 byte : reader) { this->m_valueCounts[byte]++; blockValueCounts[byte]++; count++; - if ((count % this->m_blockSize) == 0) [[unlikely]] { + if (((count % this->m_blockSize) == 0) || count == provider->getSize()) [[unlikely]] { this->m_blockEntropy[this->m_processedBlockCount] = calculateEntropy(blockValueCounts, this->m_blockSize); { auto typeDist = calculateTypeDistribution(blockValueCounts, this->m_blockSize); for (u8 i = 0; i < typeDist.size(); i++) - this->m_blockTypeDistributions[i][this->m_processedBlockCount] = typeDist[i]; + this->m_blockTypeDistributions[i][this->m_processedBlockCount] = typeDist[i] * 100; + + } this->m_processedBlockCount += 1; @@ -182,6 +189,9 @@ namespace hex::plugin::builtin { this->m_highestBlockEntropy = *std::max_element(this->m_blockEntropy.begin(), this->m_blockEntropy.end()); else this->m_highestBlockEntropy = 0; + + this->m_plainTextCharacterPercentage = std::reduce(this->m_blockTypeDistributions[2].begin(), this->m_blockTypeDistributions[2].end()) / this->m_blockTypeDistributions[2].size(); + this->m_plainTextCharacterPercentage += std::reduce(this->m_blockTypeDistributions[4].begin(), this->m_blockTypeDistributions[4].end()) / this->m_blockTypeDistributions[4].size(); } }); } @@ -287,8 +297,8 @@ namespace hex::plugin::builtin { ImGui::TextUnformatted("hex.builtin.view.information.byte_types"_lang); if (ImPlot::BeginPlot("##byte_types", ImVec2(-1, 0), ImPlotFlags_NoChild | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect | ImPlotFlags_AntiAliased)) { - ImPlot::SetupAxes("hex.builtin.common.type"_lang, "hex.builtin.common.count"_lang, ImPlotAxisFlags_Lock, ImPlotAxisFlags_Lock); - ImPlot::SetupAxesLimits(0, this->m_blockTypeDistributions[0].size(), -0.1F, 1.1F, ImGuiCond_Always); + ImPlot::SetupAxes("hex.builtin.common.address"_lang, "hex.builtin.common.percentage"_lang, ImPlotAxisFlags_Lock, ImPlotAxisFlags_Lock); + ImPlot::SetupAxesLimits(0, this->m_blockTypeDistributions[0].size(), -0.1F, 100.1F, ImGuiCond_Always); ImPlot::SetupLegend(ImPlotLocation_South, ImPlotLegendFlags_Horizontal | ImPlotLegendFlags_Outside); constexpr static std::array Names = { "iscntrl", "isprint", "isspace", "isblank", "isgraph", "ispunct", "isalnum", "isalpha", "isupper", "islower", "isdigit", "isxdigit" }; @@ -336,7 +346,7 @@ namespace hex::plugin::builtin { } // Entropy information - if (ImGui::BeginTable("entropy", 2, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg)) { + if (ImGui::BeginTable("entropy_info", 2, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg)) { ImGui::TableSetupColumn("type"); ImGui::TableSetupColumn("value", ImGuiTableColumnFlags_WidthStretch); @@ -350,24 +360,49 @@ namespace hex::plugin::builtin { ImGui::TableNextColumn(); ImGui::TextFormatted("{}", "hex.builtin.view.information.file_entropy"_lang); ImGui::TableNextColumn(); - ImGui::TextFormatted("{:.8f}", this->m_averageEntropy); + if (this->m_averageEntropy < 0) ImGui::TextUnformatted("???"); + else ImGui::TextFormatted("{:.8f}", this->m_averageEntropy); ImGui::TableNextColumn(); ImGui::TextFormatted("{}", "hex.builtin.view.information.highest_entropy"_lang); ImGui::TableNextColumn(); - ImGui::TextFormatted("{:.8f}", this->m_highestBlockEntropy); + if (this->m_highestBlockEntropy < 0) ImGui::TextUnformatted("???"); + else ImGui::TextFormatted("{:.8f}", this->m_highestBlockEntropy); + + ImGui::TableNextColumn(); + ImGui::TextFormatted("{}", "hex.builtin.view.information.plain_text_percentage"_lang); + ImGui::TableNextColumn(); + if (this->m_plainTextCharacterPercentage < 0) ImGui::TextUnformatted("???"); + else ImGui::TextFormatted("{:.8f}", this->m_plainTextCharacterPercentage); ImGui::EndTable(); } - if (this->m_averageEntropy > 0.83 && this->m_highestBlockEntropy > 0.9) { - ImGui::NewLine(); - ImGui::TextFormattedColored(ImVec4(0.92F, 0.25F, 0.2F, 1.0F), "{}", "hex.builtin.view.information.encrypted"_lang); + ImGui::NewLine(); + + // General information + if (ImGui::BeginTable("info", 1, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg)) { + ImGui::TableSetupColumn("value", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableNextRow(); + + if (this->m_averageEntropy > 0.83 && this->m_highestBlockEntropy > 0.9) { + ImGui::TableNextColumn(); + ImGui::TextFormattedColored(ImVec4(0.92F, 0.25F, 0.2F, 1.0F), "{}", "hex.builtin.view.information.encrypted"_lang); + } + + if (this->m_plainTextCharacterPercentage > 99) { + ImGui::TableNextColumn(); + ImGui::TextFormattedColored(ImVec4(0.92F, 0.25F, 0.2F, 1.0F), "{}", "hex.builtin.view.information.plain_text"_lang); + } + + ImGui::EndTable(); } + ImGui::NewLine(); + ImGui::BeginGroup(); { - ImGui::Header("hex.builtin.view.information.digram"_lang); + ImGui::TextUnformatted("hex.builtin.view.information.digram"_lang); this->m_digram.draw(ImVec2(300, 300)); } ImGui::EndGroup(); @@ -376,10 +411,11 @@ namespace hex::plugin::builtin { ImGui::BeginGroup(); { - ImGui::Header("hex.builtin.view.information.layered_distribution"_lang); + ImGui::TextUnformatted("hex.builtin.view.information.layered_distribution"_lang); this->m_layeredDistribution.draw(ImVec2(300, 300)); } - ImGui::EndGroup(); } + ImGui::EndGroup(); + } } } ImGui::EndChild();