feat: Added simple UDP Data Provider

This commit is contained in:
WerWolv
2025-05-29 18:00:29 +02:00
parent ac67e985af
commit 03884ddd05
8 changed files with 319 additions and 0 deletions

View File

@@ -68,6 +68,7 @@ add_imhex_plugin(
source/content/providers/process_memory_provider.cpp
source/content/providers/base64_provider.cpp
source/content/providers/view_provider.cpp
source/content/providers/udp_provider.cpp
source/content/tools/ascii_table.cpp
source/content/tools/base_converter.cpp

View File

@@ -0,0 +1,62 @@
#pragma once
#include <hex/helpers/fmt.hpp>
#include <hex/providers/provider.hpp>
#include <hex/helpers/udp_server.hpp>
#include <nlohmann/json.hpp>
#include <mutex>
namespace hex::plugin::builtin {
class UDPProvider : public hex::prv::Provider {
public:
UDPProvider() = default;
~UDPProvider() override = default;
[[nodiscard]] bool isAvailable() const override { return true; }
[[nodiscard]] bool isReadable() const override { return true; }
[[nodiscard]] bool isWritable() const override { return false; }
[[nodiscard]] bool isResizable() const override { return false; }
[[nodiscard]] bool isSavable() const override { return true; }
void readRaw(u64 offset, void *buffer, size_t size) override;
void writeRaw(u64 offset, const void *buffer, size_t size) override;
[[nodiscard]] u64 getActualSize() const override;
[[nodiscard]] bool hasLoadInterface() const override { return true; }
[[nodiscard]] bool drawLoadInterface() override;
bool hasInterface() const override { return true; }
void drawInterface() override;
[[nodiscard]] bool open() override;
void close() override;
void loadSettings(const nlohmann::json &) override;
[[nodiscard]] nlohmann::json storeSettings(nlohmann::json) const override;
[[nodiscard]] UnlocalizedString getTypeName() const override {
return "hex.builtin.provider.udp";
}
std::string getName() const override { return hex::format("hex.builtin.provider.udp.name"_lang, m_udpServer.getPort()); }
protected:
void receive(std::span<const u8> data);
private:
UDPServer m_udpServer;
int m_port = 0;
struct Message {
std::vector<u8> data;
std::chrono::system_clock::time_point timestamp;
};
mutable std::mutex m_mutex;
std::vector<Message> m_messages;
u64 m_selectedMessage = 0;
};
}

View File

@@ -462,6 +462,10 @@
"hex.builtin.provider.process_memory.utils.inject_dll": "Inject DLL",
"hex.builtin.provider.process_memory.utils.inject_dll.success": "Successfully injected DLL '{0}'!",
"hex.builtin.provider.process_memory.utils.inject_dll.failure": "Failed to inject DLL '{0}'!",
"hex.builtin.provider.udp": "UDP Server",
"hex.builtin.provider.udp.name": "UDP Server on Port {}",
"hex.builtin.provider.udp.port": "Server Port",
"hex.builtin.provider.udp.timestamp": "Timestamp",
"hex.builtin.provider.view": "View",
"hex.builtin.setting.experiments": "Experiments",
"hex.builtin.setting.experiments.description": "Experiments are features that are still in development and may not work correctly yet.\n\nFeel free to try them out and report any issues you encounter!",

View File

@@ -10,6 +10,7 @@
#include "content/providers/view_provider.hpp"
#include <content/providers/process_memory_provider.hpp>
#include <content/providers/base64_provider.hpp>
#include <content/providers/udp_provider.hpp>
#include <popups/popup_notification.hpp>
#include <hex/api/project_file_manager.hpp>
@@ -29,6 +30,7 @@ namespace hex::plugin::builtin {
ContentRegistry::Provider::add<NullProvider>(false);
#if !defined(OS_WEB)
ContentRegistry::Provider::add<DiskProvider>();
ContentRegistry::Provider::add<UDPProvider>();
#endif
ContentRegistry::Provider::add<GDBProvider>();
ContentRegistry::Provider::add<IntelHexProvider>();

View File

@@ -0,0 +1,122 @@
#include <imgui.h>
#include <content/providers/udp_provider.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/ui/imgui_imhex_extensions.h>
namespace hex::plugin::builtin {
bool UDPProvider::open() {
m_udpServer = UDPServer(m_port, [this](std::span<const u8> data) {
this->receive(data);
});
m_udpServer.start();
return true;
}
void UDPProvider::close() {
m_udpServer.stop();
}
void UDPProvider::receive(std::span<const u8> data) {
std::scoped_lock lock(m_mutex);
m_messages.emplace_back(
std::vector(data.begin(), data.end()),
std::chrono::system_clock::now()
);
}
u64 UDPProvider::getActualSize() const {
std::scoped_lock lock(m_mutex);
if (m_messages.empty())
return 0;
if (m_selectedMessage >= m_messages.size())
return 0;
return m_messages[m_selectedMessage].data.size();
}
void UDPProvider::readRaw(u64 offset, void* buffer, size_t size) {
std::scoped_lock lock(m_mutex);
if (m_selectedMessage >= m_messages.size())
return;
const auto &message = m_messages[m_selectedMessage];
if (offset >= message.data.size())
return;
if (offset + size > message.data.size()) {
if (offset >= message.data.size())
size = offset - message.data.size();
else
return;
}
std::memcpy(buffer, &message.data[offset], size);
}
void UDPProvider::writeRaw(u64, const void*, size_t) {
/* Not supported */
}
void UDPProvider::drawInterface() {
std::scoped_lock lock(m_mutex);
if (ImGui::BeginTable("##Messages", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImGui::GetContentRegionAvail())) {
ImGui::TableSetupColumn("hex.builtin.provider.udp.timestamp"_lang, ImGuiTableColumnFlags_WidthFixed, 32 * ImGui::CalcTextSize(" ").x);
ImGui::TableSetupColumn("hex.ui.common.size"_lang, ImGuiTableColumnFlags_WidthStretch);
ImGui::TableHeadersRow();
ImGuiListClipper clipper;
clipper.Begin(m_messages.size());
while (clipper.Step())
for (u64 i = clipper.DisplayStart; i != u64(clipper.DisplayEnd); i += 1) {
ImGui::PushID(i + 1);
const auto &message = m_messages[i];
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("{}", message.timestamp);
ImGui::SameLine();
if (ImGui::Selectable("##selectable", i == m_selectedMessage, ImGuiSelectableFlags_SpanAllColumns))
m_selectedMessage = i;
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("{}", hex::toByteString(message.data.size()));
ImGui::PopID();
}
ImGui::EndTable();
}
}
bool UDPProvider::drawLoadInterface() {
ImGui::InputInt("hex.builtin.provider.udp.port"_lang, &m_port, 0, 0);
if (m_port < 0)
m_port = 0;
else if (m_port > 0xFFFF)
m_port = 0xFFFF;
return m_port != 0;
}
void UDPProvider::loadSettings(const nlohmann::json &settings) {
Provider::loadSettings(settings);
m_port = settings.at("port").get<int>();
}
nlohmann::json UDPProvider::storeSettings(nlohmann::json settings) const {
settings["port"] = m_port;
return Provider::storeSettings(settings);
}
}