1
0
mirror of synced 2024-11-24 07:40:17 +01:00

views: Add simple pattern, library and magics store

This commit is contained in:
WerWolv 2021-09-03 02:34:40 +02:00
parent fcfaaacdcc
commit 4b40546750
8 changed files with 415 additions and 18 deletions

View File

@ -90,6 +90,7 @@ add_executable(imhex ${application_type}
source/views/view_data_processor.cpp
source/views/view_yara.cpp
source/views/view_constants.cpp
source/views/view_store.cpp
${imhex_icon}
)

View File

@ -2,24 +2,53 @@
#include <hex.hpp>
#include <imgui.h>
#include <hex/views/view.hpp>
#include <hex/helpers/net.hpp>
#include <hex/helpers/paths.hpp>
#include <array>
#include <future>
#include <string>
namespace hex {
namespace prv { class Provider; }
struct StoreEntry {
std::string name;
std::string description;
std::string fileName;
std::string link;
std::string hash;
class ViewTools : public View {
bool downloading;
bool installed;
bool hasUpdate;
};
class ViewStore : public View {
public:
ViewTools();
~ViewTools() override;
ViewStore();
~ViewStore() override;
void drawContent() override;
void drawMenu() override;
bool isAvailable() override { return true; }
bool hasViewMenuItemEntry() override { return false; }
private:
Net m_net;
std::future<Response<std::string>> m_apiRequest;
std::future<Response<void>> m_download;
std::vector<StoreEntry> m_patterns, m_magics, m_includes;
void drawStore();
void refresh();
void parseResponse();
void download(ImHexPath pathType, const std::string &fileName, const std::string &url, bool update);
void remove(ImHexPath pathType, const std::string &fileName);
};
}

View File

@ -24,8 +24,17 @@ namespace hex::crypt {
std::array<u8, 48> sha384(prv::Provider* &data, u64 offset, size_t size);
std::array<u8, 64> sha512(prv::Provider* &data, u64 offset, size_t size);
std::array<u8, 16> md5(const std::vector<u8> &data);
std::array<u8, 20> sha1(const std::vector<u8> &data);
std::array<u8, 28> sha224(const std::vector<u8> &data);
std::array<u8, 32> sha256(const std::vector<u8> &data);
std::array<u8, 48> sha384(const std::vector<u8> &data);
std::array<u8, 64> sha512(const std::vector<u8> &data);
std::vector<u8> decode64(const std::vector<u8> &input);
std::vector<u8> encode64(const std::vector<u8> &input);
std::vector<u8> decode16(const std::string &input);
std::string encode16(const std::vector<u8> &input);
enum class AESMode : u8 {
ECB = 0,

View File

@ -21,6 +21,11 @@ namespace hex {
T body;
};
template<>
struct Response<void> {
s32 code;
};
class Net {
public:
Net();
@ -30,6 +35,7 @@ namespace hex {
std::future<Response<nlohmann::json>> getJson(const std::string &url);
std::future<Response<std::string>> uploadFile(const std::string &url, const std::filesystem::path &filePath);
std::future<Response<void>> downloadFile(const std::string &url, const std::filesystem::path &filePath);
[[nodiscard]]
std::string encode(const std::string &input) {

View File

@ -1,9 +1,11 @@
#include <hex/helpers/crypto.hpp>
#include <hex/providers/provider.hpp>
#include <hex/helpers/utils.hpp>
#include <mbedtls/version.h>
#include <mbedtls/base64.h>
#include <mbedtls/bignum.h>
#include <mbedtls/md5.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
@ -131,6 +133,21 @@ namespace hex::crypt {
return result;
}
std::array<u8, 16> md5(const std::vector<u8> &data) {
std::array<u8, 16> result = { 0 };
mbedtls_md5_context ctx;
mbedtls_md5_init(&ctx);
mbedtls_md5_starts(&ctx);
mbedtls_md5_update(&ctx, data.data(), data.size());
mbedtls_md5_finish(&ctx, result.data());
mbedtls_md5_free(&ctx);
return result;
}
std::array<u8, 20> sha1(prv::Provider* &data, u64 offset, size_t size) {
std::array<u8, 20> result = { 0 };
@ -153,6 +170,21 @@ namespace hex::crypt {
return result;
}
std::array<u8, 20> sha1(const std::vector<u8> &data) {
std::array<u8, 20> result = { 0 };
mbedtls_sha1_context ctx;
mbedtls_sha1_init(&ctx);
mbedtls_sha1_starts(&ctx);
mbedtls_sha1_update(&ctx, data.data(), data.size());
mbedtls_sha1_finish(&ctx, result.data());
mbedtls_sha1_free(&ctx);
return result;
}
std::array<u8, 28> sha224(prv::Provider* &data, u64 offset, size_t size) {
std::array<u8, 28> result = { 0 };
@ -175,6 +207,21 @@ namespace hex::crypt {
return result;
}
std::array<u8, 28> sha224(const std::vector<u8> &data) {
std::array<u8, 28> result = { 0 };
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
mbedtls_sha256_starts(&ctx, true);
mbedtls_sha256_update(&ctx, data.data(), data.size());
mbedtls_sha256_finish(&ctx, result.data());
mbedtls_sha256_free(&ctx);
return result;
}
std::array<u8, 32> sha256(prv::Provider* &data, u64 offset, size_t size) {
std::array<u8, 32> result = { 0 };
@ -197,6 +244,21 @@ namespace hex::crypt {
return result;
}
std::array<u8, 32> sha256(const std::vector<u8> &data) {
std::array<u8, 32> result = { 0 };
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
mbedtls_sha256_starts(&ctx, false);
mbedtls_sha256_update(&ctx, data.data(), data.size());
mbedtls_sha256_finish(&ctx, result.data());
mbedtls_sha256_free(&ctx);
return result;
}
std::array<u8, 48> sha384(prv::Provider* &data, u64 offset, size_t size) {
std::array<u8, 48> result = { 0 };
@ -219,6 +281,21 @@ namespace hex::crypt {
return result;
}
std::array<u8, 48> sha384(const std::vector<u8> &data) {
std::array<u8, 48> result = { 0 };
mbedtls_sha512_context ctx;
mbedtls_sha512_init(&ctx);
mbedtls_sha512_starts(&ctx, true);
mbedtls_sha512_update(&ctx, data.data(), data.size());
mbedtls_sha512_finish(&ctx, result.data());
mbedtls_sha512_free(&ctx);
return result;
}
std::array<u8, 64> sha512(prv::Provider* &data, u64 offset, size_t size) {
std::array<u8, 64> result = { 0 };
@ -241,6 +318,22 @@ namespace hex::crypt {
return result;
}
std::array<u8, 64> sha512(const std::vector<u8> &data) {
std::array<u8, 64> result = { 0 };
mbedtls_sha512_context ctx;
mbedtls_sha512_init(&ctx);
mbedtls_sha512_starts(&ctx, false);
mbedtls_sha512_update(&ctx, data.data(), data.size());
mbedtls_sha512_finish(&ctx, result.data());
mbedtls_sha512_free(&ctx);
return result;
}
std::vector<u8> decode64(const std::vector<u8> &input) {
size_t outputSize = (3 * input.size()) / 4;
std::vector<u8> output(outputSize + 1, 0x00);
@ -263,6 +356,41 @@ namespace hex::crypt {
return output;
}
std::vector<u8> decode16(const std::string &input) {
std::vector<u8> output(input.length() / 2, 0x00);
mbedtls_mpi ctx;
mbedtls_mpi_init(&ctx);
ON_SCOPE_EXIT { mbedtls_mpi_free(&ctx); };
if (mbedtls_mpi_read_string(&ctx, 16, input.c_str()))
return { };
if (mbedtls_mpi_write_binary(&ctx, output.data(), output.size()))
return { };
return output;
}
std::string encode16(const std::vector<u8> &input) {
std::string output(input.size() * 2 + 1, 0x00);
mbedtls_mpi ctx;
mbedtls_mpi_init(&ctx);
ON_SCOPE_EXIT { mbedtls_mpi_free(&ctx); };
if (mbedtls_mpi_read_binary(&ctx, input.data(), input.size()))
return { };
size_t written = 0;
if (mbedtls_mpi_write_string(&ctx, 16, output.data(), output.size(), &written))
return { };
return output;
}
static std::vector<u8> aes(mbedtls_cipher_type_t type, mbedtls_operation_t operation, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input) {
std::vector<u8> output;

View File

@ -42,6 +42,12 @@ namespace hex {
return fread(contents, size, nmemb, file);
}
static size_t writeToFile(void *contents, size_t size, size_t nmemb, void *userdata) {
FILE *file = static_cast<FILE*>(userdata);
return fwrite(contents, size, nmemb, file);
}
static CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userdata) {
auto* cfg = static_cast<mbedtls_ssl_config*>(sslctx);
@ -203,4 +209,28 @@ namespace hex {
});
}
std::future<Response<void>> Net::downloadFile(const std::string &url, const std::filesystem::path &filePath) {
this->m_transmissionActive.lock();
return std::async(std::launch::async, [=, this]{
std::string response;
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
FILE *file = fopen(filePath.string().c_str(), "wb");
if (file == nullptr)
return Response<void> { 400 };
ON_SCOPE_EXIT { fclose(file); };
setCommonSettings(response, url, {});
curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET");
curl_easy_setopt(this->m_ctx, CURLOPT_WRITEFUNCTION, writeToFile);
curl_easy_setopt(this->m_ctx, CURLOPT_WRITEDATA, file);
auto responseCode = execute();
return Response<void> { responseCode.value_or(0) };
});
}
}

View File

@ -27,6 +27,7 @@
#include "views/view_data_processor.hpp"
#include "views/view_yara.hpp"
#include "views/view_constants.hpp"
#include "views/view_store.hpp"
#include "helpers/plugin_manager.hpp"
@ -188,6 +189,7 @@ namespace hex::init {
ContentRegistry::Views::add<ViewDataProcessor>();
ContentRegistry::Views::add<ViewYara>();
ContentRegistry::Views::add<ViewConstants>();
ContentRegistry::Views::add<ViewStore>();
return true;
}

View File

@ -1,26 +1,218 @@
#include "views/view_tools.hpp"
#include "views/view_store.hpp"
#include <hex/providers/provider.hpp>
#include <imgui.h>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui_internal.h>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/crypto.hpp>
#include <hex/helpers/logger.hpp>
#include <fstream>
#include <filesystem>
#include <nlohmann/json.hpp>
namespace hex {
ViewTools::ViewTools() : View("hex.view.tools.name") { }
using namespace std::literals::string_literals;
using namespace std::literals::chrono_literals;
ViewTools::~ViewTools() { }
namespace fs = std::filesystem;
void ViewTools::drawContent() {
if (ImGui::Begin(View::toWindowName("hex.view.tools.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
for (const auto& [name, function] : ContentRegistry::Tools::getEntries()) {
if (ImGui::CollapsingHeader(LangEntry(name))) {
function();
}
}
}
ImGui::End();
ViewStore::ViewStore() : View("hex.view.store.name") {
this->refresh();
}
void ViewTools::drawMenu() {
ViewStore::~ViewStore() { }
void ViewStore::drawStore() {
ImGui::Header("ImHex content store", true);
if (ImGui::Button("Reload")) {
this->refresh();
}
auto drawTab = [this](auto title, ImHexPath pathType, auto &content) {
if (ImGui::BeginTabItem(title)) {
if (ImGui::BeginTable("##patterns", 3, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp)) {
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_None, 1.0);
ImGui::TableSetupColumn("Description", ImGuiTableColumnFlags_None, 3.0);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_None, 1.0);
ImGui::TableHeadersRow();
for (auto &entry : content) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted(entry.name.c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(entry.description.c_str());
ImGui::TableNextColumn();
ImGui::BeginDisabled(this->m_download.valid() && this->m_download.wait_for(0s) != std::future_status::ready);
{
if (entry.downloading) {
ImGui::TextSpinner("Downloading...");
if (this->m_download.valid() && this->m_download.wait_for(0s) == std::future_status::ready) {
entry.downloading = false;
auto response = this->m_download.get();
if (response.code == 200) {
entry.installed = true;
entry.hasUpdate = false;
} else
log::error("Download failed!");
this->m_download = { };
}
} else if (entry.hasUpdate) {
if (ImGui::Button("Update")) {
this->download(pathType, entry.fileName, entry.link, true);
entry.downloading = true;
}
} else if (!entry.installed) {
if (ImGui::Button("Download")) {
this->download(pathType, entry.fileName, entry.link, false);
entry.downloading = true;
}
} else {
if (ImGui::Button("Remove")) {
this->remove(pathType, entry.fileName);
entry.installed = false;
}
}
}
ImGui::EndDisabled();
}
ImGui::EndTable();
}
ImGui::EndTabItem();
}
};
if (ImGui::BeginTabBar("storeTabs")) {
drawTab("Patterns", ImHexPath::Patterns, this->m_patterns);
drawTab("Libraries", ImHexPath::PatternsInclude, this->m_includes);
drawTab("Magic", ImHexPath::Magic, this->m_magics);
ImGui::EndTabBar();
}
}
void ViewStore::refresh() {
this->m_patterns.clear();
this->m_includes.clear();
this->m_magics.clear();
this->m_apiRequest = this->m_net.getString(ImHexApiURL + "/store"s);
}
void ViewStore::parseResponse() {
auto response = this->m_apiRequest.get();
if (response.code != 200)
ImGui::TextUnformatted("Invalid response from store API");
else {
auto json = nlohmann::json::parse(response.body);
auto parseStoreEntries = [](auto storeJson, const std::string &name, ImHexPath pathType, std::vector<StoreEntry> &results) {
// Check if the response handles the type of files
if (storeJson.contains(name)) {
for (auto &entry : storeJson[name]) {
// Check if entry is valid
if (entry.contains("name") && entry.contains("desc") && entry.contains("file") && entry.contains("url") && entry.contains("hash")) {
// Parse entry
StoreEntry storeEntry = { entry["name"], entry["desc"], entry["file"], entry["url"], entry["hash"], false, false, false };
// Check if file is installed already or has an update available
for (auto folder : hex::getPath(pathType)) {
auto path = folder / fs::path(storeEntry.fileName);
if (fs::exists(path)) {
storeEntry.installed = true;
std::ifstream file(path, std::ios::in | std::ios::binary);
std::vector<u8> data(fs::file_size(path), 0x00);
file.read(reinterpret_cast<char*>(data.data()), data.size());
auto fileHash = crypt::sha256(data);
// Compare installed file hash with hash of repo file
if (std::vector(fileHash.begin(), fileHash.end()) != crypt::decode16(storeEntry.hash))
storeEntry.hasUpdate = true;
}
}
results.push_back(storeEntry);
}
}
}
};
parseStoreEntries(json, "patterns", ImHexPath::Patterns, this->m_patterns);
parseStoreEntries(json, "includes", ImHexPath::PatternsInclude, this->m_includes);
parseStoreEntries(json, "magic", ImHexPath::Magic, this->m_magics);
this->m_apiRequest = { };
}
}
void ViewStore::drawContent() {
ImGui::SetNextWindowSizeConstraints(ImVec2(600, 400) * SharedData::globalScale, ImVec2(FLT_MAX, FLT_MAX));
if (ImGui::BeginPopupModal(View::toWindowName("hex.view.store.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_AlwaysAutoResize)) {
if (this->m_apiRequest.valid()) {
if (this->m_apiRequest.wait_for(0s) != std::future_status::ready)
ImGui::TextSpinner("Loading store content...");
else
this->parseResponse();
}
this->drawStore();
ImGui::EndPopup();
} else {
this->getWindowOpenState() = false;
}
}
void ViewStore::drawMenu() {
if (ImGui::BeginMenu("hex.menu.help"_lang)) {
if (ImGui::MenuItem("hex.view.store.name"_lang)) {
View::doLater([]{ ImGui::OpenPopup(View::toWindowName("hex.view.store.name").c_str()); });
this->getWindowOpenState() = true;
}
ImGui::EndMenu();
}
}
void ViewStore::download(ImHexPath pathType, const std::string &fileName, const std::string &url, bool update) {
if (!update) {
this->m_download = this->m_net.downloadFile(url, hex::getPath(pathType).front() / fs::path(fileName));
} else {
for (const auto &path : hex::getPath(pathType)) {
auto fullPath = path / fs::path(fileName);
if (fs::exists(fullPath)) {
this->m_download = this->m_net.downloadFile(url, fullPath);
}
}
}
}
void ViewStore::remove(ImHexPath pathType, const std::string &fileName) {
for (const auto &path : hex::getPath(pathType))
fs::remove(path / fs::path(fileName));
}
}