From d9134f7fe1293ba59cb60327b94a738a97593243 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Thu, 23 Sep 2021 22:56:49 +0200 Subject: [PATCH] store: Added support for downloading tar'd folders --- CMakeLists.txt | 29 +- external/microtar/CMakeLists.txt | 10 + external/microtar/LICENSE | 19 ++ external/microtar/README.md | 99 +++++++ external/microtar/include/microtar.h | 93 ++++++ external/microtar/source/microtar.c | 376 +++++++++++++++++++++++++ include/views/view_store.hpp | 6 +- plugins/builtin/source/lang/de_DE.cpp | 1 + plugins/builtin/source/lang/en_US.cpp | 1 + plugins/builtin/source/lang/it_IT.cpp | 1 + plugins/builtin/source/lang/zh_CN.cpp | 3 +- plugins/libimhex/CMakeLists.txt | 49 ++-- plugins/libimhex/source/views/view.cpp | 12 +- source/init/splash_window.cpp | 18 +- source/views/view_store.cpp | 56 +++- 15 files changed, 700 insertions(+), 73 deletions(-) create mode 100644 external/microtar/CMakeLists.txt create mode 100644 external/microtar/LICENSE create mode 100644 external/microtar/README.md create mode 100644 external/microtar/include/microtar.h create mode 100644 external/microtar/source/microtar.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a460126c1..dbad6a88a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,31 +22,11 @@ findLibraries() detectOS() detectArch() -if (NOT USE_SYSTEM_LLVM) - add_subdirectory(external/llvm) -else() - find_package(LLVM REQUIRED Demangle) -endif() - -if (NOT USE_SYSTEM_YARA) - add_subdirectory(external/yara) - set(YARA_LIBRARIES libyara) -else() - find_package(PkgConfig REQUIRED) - pkg_check_modules(YARA REQUIRED IMPORTED_TARGET yara) -endif() - # Add bundled dependencies add_subdirectory(plugins/libimhex) # Add include directories -include_directories(include ${MBEDTLS_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${Python_INCLUDE_DIRS}) -if (USE_SYSTEM_LLVM) - include_directories(${LLVM_INCLUDE_DIRS}) -endif() -if (USE_SYSTEM_YARA) - include_directories(${YARA_INCLUDE_DIRS}) -endif() +include_directories(include) enable_testing() add_subdirectory(tests) @@ -97,14 +77,11 @@ add_executable(imhex ${application_type} ) set_target_properties(imhex PROPERTIES CXX_VISIBILITY_PRESET hidden) -target_link_directories(imhex PRIVATE ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS}) if (WIN32) - target_link_libraries(imhex ${CMAKE_DL_LIBS} capstone LLVMDemangle libimhex ${Python_LIBRARIES} wsock32 ws2_32 - ${YARA_LIBRARIES} Dwmapi.lib dl) + target_link_libraries(imhex dl libimhex wsock32 ws2_32 Dwmapi.lib) else () - target_link_libraries(imhex ${CMAKE_DL_LIBS} capstone LLVMDemangle libimhex ${Python_LIBRARIES} dl pthread - ${YARA_LIBRARIES}) + target_link_libraries(imhex dl libimhex pthread) endif () createPackage() diff --git a/external/microtar/CMakeLists.txt b/external/microtar/CMakeLists.txt new file mode 100644 index 000000000..d15b7b382 --- /dev/null +++ b/external/microtar/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.16) +project(microtar) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + +add_library(microtar STATIC + source/microtar.c +) + +target_include_directories(microtar PUBLIC include) diff --git a/external/microtar/LICENSE b/external/microtar/LICENSE new file mode 100644 index 000000000..7e3bf17cc --- /dev/null +++ b/external/microtar/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2017 rxi + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/external/microtar/README.md b/external/microtar/README.md new file mode 100644 index 000000000..42acf49ca --- /dev/null +++ b/external/microtar/README.md @@ -0,0 +1,99 @@ +# microtar +A lightweight tar library written in ANSI C + + +## Basic Usage +The library consists of `microtar.c` and `microtar.h`. These two files can be +dropped into an existing project and compiled along with it. + + +#### Reading +```c +mtar_t tar; +mtar_header_t h; +char *p; + +/* Open archive for reading */ +mtar_open(&tar, "test.tar", "r"); + +/* Print all file names and sizes */ +while ( (mtar_read_header(&tar, &h)) != MTAR_ENULLRECORD ) { + printf("%s (%d bytes)\n", h.name, h.size); + mtar_next(&tar); +} + +/* Load and print contents of file "test.txt" */ +mtar_find(&tar, "test.txt", &h); +p = calloc(1, h.size + 1); +mtar_read_data(&tar, p, h.size); +printf("%s", p); +free(p); + +/* Close archive */ +mtar_close(&tar); +``` + +#### Writing +```c +mtar_t tar; +const char *str1 = "Hello world"; +const char *str2 = "Goodbye world"; + +/* Open archive for writing */ +mtar_open(&tar, "test.tar", "w"); + +/* Write strings to files `test1.txt` and `test2.txt` */ +mtar_write_file_header(&tar, "test1.txt", strlen(str1)); +mtar_write_data(&tar, str1, strlen(str1)); +mtar_write_file_header(&tar, "test2.txt", strlen(str2)); +mtar_write_data(&tar, str2, strlen(str2)); + +/* Finalize -- this needs to be the last thing done before closing */ +mtar_finalize(&tar); + +/* Close archive */ +mtar_close(&tar); +``` + + +## Error handling +All functions which return an `int` will return `MTAR_ESUCCESS` if the operation +is successful. If an error occurs an error value less-than-zero will be +returned; this value can be passed to the function `mtar_strerror()` to get its +corresponding error string. + + +## Wrapping a stream +If you want to read or write from something other than a file, the `mtar_t` +struct can be manually initialized with your own callback functions and a +`stream` pointer. + +All callback functions are passed a pointer to the `mtar_t` struct as their +first argument. They should return `MTAR_ESUCCESS` if the operation succeeds +without an error, or an integer below zero if an error occurs. + +After the `stream` field has been set, all required callbacks have been set and +all unused fields have been zeroset the `mtar_t` struct can be safely used with +the microtar functions. `mtar_open` *should not* be called if the `mtar_t` +struct was initialized manually. + +#### Reading +The following callbacks should be set for reading an archive from a stream: + +Name | Arguments | Description +--------|------------------------------------------|--------------------------- +`read` | `mtar_t *tar, void *data, unsigned size` | Read data from the stream +`seek` | `mtar_t *tar, unsigned pos` | Set the position indicator +`close` | `mtar_t *tar` | Close the stream + +#### Writing +The following callbacks should be set for writing an archive to a stream: + +Name | Arguments | Description +--------|------------------------------------------------|--------------------- +`write` | `mtar_t *tar, const void *data, unsigned size` | Write data to the stream + + +## License +This library is free software; you can redistribute it and/or modify it under +the terms of the MIT license. See [LICENSE](LICENSE) for details. diff --git a/external/microtar/include/microtar.h b/external/microtar/include/microtar.h new file mode 100644 index 000000000..2e73e919a --- /dev/null +++ b/external/microtar/include/microtar.h @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2017 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See `microtar.c` for details. + */ + +#ifndef MICROTAR_H +#define MICROTAR_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +#define MTAR_VERSION "0.1.0" + +enum { + MTAR_ESUCCESS = 0, + MTAR_EFAILURE = -1, + MTAR_EOPENFAIL = -2, + MTAR_EREADFAIL = -3, + MTAR_EWRITEFAIL = -4, + MTAR_ESEEKFAIL = -5, + MTAR_EBADCHKSUM = -6, + MTAR_ENULLRECORD = -7, + MTAR_ENOTFOUND = -8 +}; + +enum { + MTAR_TREG = '0', + MTAR_TLNK = '1', + MTAR_TSYM = '2', + MTAR_TCHR = '3', + MTAR_TBLK = '4', + MTAR_TDIR = '5', + MTAR_TFIFO = '6' +}; + +typedef struct { + unsigned mode; + unsigned owner; + unsigned size; + unsigned mtime; + unsigned type; + char name[100]; + char linkname[100]; +} mtar_header_t; + + +typedef struct mtar_t mtar_t; + +struct mtar_t { + int (*read)(mtar_t *tar, void *data, unsigned size); + + int (*write)(mtar_t *tar, const void *data, unsigned size); + + int (*seek)(mtar_t *tar, unsigned pos); + + int (*close)(mtar_t *tar); + + void *stream; + unsigned pos; + unsigned remaining_data; + unsigned last_header; +}; + + +const char *mtar_strerror(int err); + +int mtar_open(mtar_t *tar, const char *filename, const char *mode); +int mtar_close(mtar_t *tar); + +int mtar_seek(mtar_t *tar, unsigned pos); +int mtar_rewind(mtar_t *tar); +int mtar_next(mtar_t *tar); +int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h); +int mtar_read_header(mtar_t *tar, mtar_header_t *h); +int mtar_read_data(mtar_t *tar, void *ptr, unsigned size); + +int mtar_write_header(mtar_t *tar, const mtar_header_t *h); +int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size); +int mtar_write_dir_header(mtar_t *tar, const char *name); +int mtar_write_data(mtar_t *tar, const void *data, unsigned size); +int mtar_finalize(mtar_t *tar); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/external/microtar/source/microtar.c b/external/microtar/source/microtar.c new file mode 100644 index 000000000..a1f720578 --- /dev/null +++ b/external/microtar/source/microtar.c @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2017 rxi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include + +typedef struct { + char name[100]; + char mode[8]; + char owner[8]; + char group[8]; + char size[12]; + char mtime[12]; + char checksum[8]; + char type; + char linkname[100]; + char _padding[255]; +} mtar_raw_header_t; + + +static unsigned round_up(unsigned n, unsigned incr) { + return n + (incr - n % incr) % incr; +} + + +static unsigned checksum(const mtar_raw_header_t* rh) { + unsigned i; + unsigned char *p = (unsigned char*) rh; + unsigned res = 256; + for (i = 0; i < offsetof(mtar_raw_header_t, checksum); i++) { + res += p[i]; + } + for (i = offsetof(mtar_raw_header_t, type); i < sizeof(*rh); i++) { + res += p[i]; + } + return res; +} + + +static int tread(mtar_t *tar, void *data, unsigned size) { + int err = tar->read(tar, data, size); + tar->pos += size; + return err; +} + + +static int twrite(mtar_t *tar, const void *data, unsigned size) { + int err = tar->write(tar, data, size); + tar->pos += size; + return err; +} + + +static int write_null_bytes(mtar_t *tar, int n) { + int i, err; + char nul = '\0'; + for (i = 0; i < n; i++) { + err = twrite(tar, &nul, 1); + if (err) { + return err; + } + } + return MTAR_ESUCCESS; +} + + +static int raw_to_header(mtar_header_t *h, const mtar_raw_header_t *rh) { + unsigned chksum1, chksum2; + + /* If the checksum starts with a null byte we assume the record is NULL */ + if (*rh->checksum == '\0') { + return MTAR_ENULLRECORD; + } + + /* Build and compare checksum */ + chksum1 = checksum(rh); + sscanf(rh->checksum, "%o", &chksum2); + if (chksum1 != chksum2) { + return MTAR_EBADCHKSUM; + } + + /* Load raw header into header */ + sscanf(rh->mode, "%o", &h->mode); + sscanf(rh->owner, "%o", &h->owner); + sscanf(rh->size, "%o", &h->size); + sscanf(rh->mtime, "%o", &h->mtime); + h->type = rh->type; + strcpy(h->name, rh->name); + strcpy(h->linkname, rh->linkname); + + return MTAR_ESUCCESS; +} + + +static int header_to_raw(mtar_raw_header_t *rh, const mtar_header_t *h) { + unsigned chksum; + + /* Load header into raw header */ + memset(rh, 0, sizeof(*rh)); + sprintf(rh->mode, "%o", h->mode); + sprintf(rh->owner, "%o", h->owner); + sprintf(rh->size, "%o", h->size); + sprintf(rh->mtime, "%o", h->mtime); + rh->type = h->type ? h->type : MTAR_TREG; + strcpy(rh->name, h->name); + strcpy(rh->linkname, h->linkname); + + /* Calculate and write checksum */ + chksum = checksum(rh); + sprintf(rh->checksum, "%06o", chksum); + rh->checksum[7] = ' '; + + return MTAR_ESUCCESS; +} + + +const char* mtar_strerror(int err) { + switch (err) { + case MTAR_ESUCCESS : return "success"; + case MTAR_EFAILURE : return "failure"; + case MTAR_EOPENFAIL : return "could not open"; + case MTAR_EREADFAIL : return "could not read"; + case MTAR_EWRITEFAIL : return "could not write"; + case MTAR_ESEEKFAIL : return "could not seek"; + case MTAR_EBADCHKSUM : return "bad checksum"; + case MTAR_ENULLRECORD : return "null record"; + case MTAR_ENOTFOUND : return "file not found"; + } + return "unknown error"; +} + + +static int file_write(mtar_t *tar, const void *data, unsigned size) { + unsigned res = fwrite(data, 1, size, tar->stream); + return (res == size) ? MTAR_ESUCCESS : MTAR_EWRITEFAIL; +} + +static int file_read(mtar_t *tar, void *data, unsigned size) { + unsigned res = fread(data, 1, size, tar->stream); + return (res == size) ? MTAR_ESUCCESS : MTAR_EREADFAIL; +} + +static int file_seek(mtar_t *tar, unsigned offset) { + int res = fseek(tar->stream, offset, SEEK_SET); + return (res == 0) ? MTAR_ESUCCESS : MTAR_ESEEKFAIL; +} + +static int file_close(mtar_t *tar) { + fclose(tar->stream); + return MTAR_ESUCCESS; +} + + +int mtar_open(mtar_t *tar, const char *filename, const char *mode) { + int err; + mtar_header_t h; + + /* Init tar struct and functions */ + memset(tar, 0, sizeof(*tar)); + tar->write = file_write; + tar->read = file_read; + tar->seek = file_seek; + tar->close = file_close; + + /* Assure mode is always binary */ + if ( strchr(mode, 'r') ) mode = "rb"; + if ( strchr(mode, 'w') ) mode = "wb"; + if ( strchr(mode, 'a') ) mode = "ab"; + /* Open file */ + tar->stream = fopen(filename, mode); + if (!tar->stream) { + return MTAR_EOPENFAIL; + } + /* Read first header to check it is valid if mode is `r` */ + if (*mode == 'r') { + err = mtar_read_header(tar, &h); + if (err != MTAR_ESUCCESS) { + mtar_close(tar); + return err; + } + } + + /* Return ok */ + return MTAR_ESUCCESS; +} + + +int mtar_close(mtar_t *tar) { + return tar->close(tar); +} + + +int mtar_seek(mtar_t *tar, unsigned pos) { + int err = tar->seek(tar, pos); + tar->pos = pos; + return err; +} + + +int mtar_rewind(mtar_t *tar) { + tar->remaining_data = 0; + tar->last_header = 0; + return mtar_seek(tar, 0); +} + + +int mtar_next(mtar_t *tar) { + int err, n; + mtar_header_t h; + /* Load header */ + err = mtar_read_header(tar, &h); + if (err) { + return err; + } + /* Seek to next record */ + n = round_up(h.size, 512) + sizeof(mtar_raw_header_t); + return mtar_seek(tar, tar->pos + n); +} + + +int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h) { + int err; + mtar_header_t header; + /* Start at beginning */ + err = mtar_rewind(tar); + if (err) { + return err; + } + /* Iterate all files until we hit an error or find the file */ + while ( (err = mtar_read_header(tar, &header)) == MTAR_ESUCCESS ) { + if ( !strcmp(header.name, name) ) { + if (h) { + *h = header; + } + return MTAR_ESUCCESS; + } + mtar_next(tar); + } + /* Return error */ + if (err == MTAR_ENULLRECORD) { + err = MTAR_ENOTFOUND; + } + return err; +} + + +int mtar_read_header(mtar_t *tar, mtar_header_t *h) { + int err; + mtar_raw_header_t rh; + /* Save header position */ + tar->last_header = tar->pos; + /* Read raw header */ + err = tread(tar, &rh, sizeof(rh)); + if (err) { + return err; + } + /* Seek back to start of header */ + err = mtar_seek(tar, tar->last_header); + if (err) { + return err; + } + /* Load raw header into header struct and return */ + return raw_to_header(h, &rh); +} + + +int mtar_read_data(mtar_t *tar, void *ptr, unsigned size) { + int err; + /* If we have no remaining data then this is the first read, we get the size, + * set the remaining data and seek to the beginning of the data */ + if (tar->remaining_data == 0) { + mtar_header_t h; + /* Read header */ + err = mtar_read_header(tar, &h); + if (err) { + return err; + } + /* Seek past header and init remaining data */ + err = mtar_seek(tar, tar->pos + sizeof(mtar_raw_header_t)); + if (err) { + return err; + } + tar->remaining_data = h.size; + } + /* Read data */ + err = tread(tar, ptr, size); + if (err) { + return err; + } + tar->remaining_data -= size; + /* If there is no remaining data we've finished reading and seek back to the + * header */ + if (tar->remaining_data == 0) { + return mtar_seek(tar, tar->last_header); + } + return MTAR_ESUCCESS; +} + + +int mtar_write_header(mtar_t *tar, const mtar_header_t *h) { + mtar_raw_header_t rh; + /* Build raw header and write */ + header_to_raw(&rh, h); + tar->remaining_data = h->size; + return twrite(tar, &rh, sizeof(rh)); +} + + +int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size) { + mtar_header_t h; + /* Build header */ + memset(&h, 0, sizeof(h)); + strcpy(h.name, name); + h.size = size; + h.type = MTAR_TREG; + h.mode = 0664; + /* Write header */ + return mtar_write_header(tar, &h); +} + + +int mtar_write_dir_header(mtar_t *tar, const char *name) { + mtar_header_t h; + /* Build header */ + memset(&h, 0, sizeof(h)); + strcpy(h.name, name); + h.type = MTAR_TDIR; + h.mode = 0775; + /* Write header */ + return mtar_write_header(tar, &h); +} + + +int mtar_write_data(mtar_t *tar, const void *data, unsigned size) { + int err; + /* Write data */ + err = twrite(tar, data, size); + if (err) { + return err; + } + tar->remaining_data -= size; + /* Write padding if we've written all the data for this file */ + if (tar->remaining_data == 0) { + return write_null_bytes(tar, round_up(tar->pos, 512) - tar->pos); + } + return MTAR_ESUCCESS; +} + + +int mtar_finalize(mtar_t *tar) { + /* Write two NULL records */ + return write_null_bytes(tar, sizeof(mtar_raw_header_t) * 2); +} diff --git a/include/views/view_store.hpp b/include/views/view_store.hpp index e9e2b2b1f..e81e59101 100644 --- a/include/views/view_store.hpp +++ b/include/views/view_store.hpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace hex { @@ -19,6 +20,8 @@ namespace hex { std::string link; std::string hash; + bool isFolder; + bool downloading; bool installed; bool hasUpdate; @@ -39,8 +42,9 @@ namespace hex { Net m_net; std::future> m_apiRequest; std::future> m_download; + std::filesystem::path m_downloadPath; - std::vector m_patterns, m_includes, m_magics, m_constants; + std::vector m_patterns, m_includes, m_magics, m_constants, m_yara; void drawStore(); diff --git a/plugins/builtin/source/lang/de_DE.cpp b/plugins/builtin/source/lang/de_DE.cpp index 5d9b4cbee..599cc6cc7 100644 --- a/plugins/builtin/source/lang/de_DE.cpp +++ b/plugins/builtin/source/lang/de_DE.cpp @@ -316,6 +316,7 @@ namespace hex::plugin::builtin { { "hex.view.store.tab.libraries", "Libraries" }, { "hex.view.store.tab.magics", "Magic Files" }, { "hex.view.store.tab.constants", "Konstanten" }, + { "hex.view.store.tab.yara", "Yara Rules" }, { "hex.view.store.loading", "Store inhalt wird geladen..." }, { "hex.view.diff.name", "Diffing" }, diff --git a/plugins/builtin/source/lang/en_US.cpp b/plugins/builtin/source/lang/en_US.cpp index df08740cf..e622216af 100644 --- a/plugins/builtin/source/lang/en_US.cpp +++ b/plugins/builtin/source/lang/en_US.cpp @@ -316,6 +316,7 @@ namespace hex::plugin::builtin { { "hex.view.store.tab.libraries", "Libraries" }, { "hex.view.store.tab.magics", "Magic Files" }, { "hex.view.store.tab.constants", "Constants" }, + { "hex.view.store.tab.yara", "Yara Rules" }, { "hex.view.store.loading", "Loading store content..." }, { "hex.view.diff.name", "Diffing" }, diff --git a/plugins/builtin/source/lang/it_IT.cpp b/plugins/builtin/source/lang/it_IT.cpp index 2fa5e3a86..ef9874df1 100644 --- a/plugins/builtin/source/lang/it_IT.cpp +++ b/plugins/builtin/source/lang/it_IT.cpp @@ -315,6 +315,7 @@ namespace hex::plugin::builtin { { "hex.view.store.tab.libraries", "Librerie" }, { "hex.view.store.tab.magics", "File Magici" }, { "hex.view.store.tab.constants", "Costanti" }, + { "hex.view.store.tab.yara", "Regole di Yara" }, { "hex.view.store.loading", "Caricamento del content store..." }, //{ "hex.view.diff.name", "Diffing" }, diff --git a/plugins/builtin/source/lang/zh_CN.cpp b/plugins/builtin/source/lang/zh_CN.cpp index e5e524a15..0db97ef9d 100644 --- a/plugins/builtin/source/lang/zh_CN.cpp +++ b/plugins/builtin/source/lang/zh_CN.cpp @@ -316,7 +316,8 @@ namespace hex::plugin::builtin { { "hex.view.store.tab.libraries", "库" }, { "hex.view.store.tab.magics", "魔术数据库" }, { "hex.view.store.tab.constants", "常量" }, - { "hex.view.store.loading", "正在加载仓库内容..." }, + { "hex.view.store.tab.yara", "Yara规则" }, + { "hex.view.store.loading", "正在加载仓库内容..." }, //{ "hex.view.diff.name", "Diffing" }, /* Builtin plugin features */ diff --git a/plugins/libimhex/CMakeLists.txt b/plugins/libimhex/CMakeLists.txt index 568dc9f67..69068db53 100644 --- a/plugins/libimhex/CMakeLists.txt +++ b/plugins/libimhex/CMakeLists.txt @@ -5,6 +5,13 @@ set(CMAKE_CXX_STANDARD 20) set(BUILD_SHARED_LIBS OFF) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/ImGui ${CMAKE_CURRENT_BINARY_DIR}/external/ImGui) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/nativefiledialog ${CMAKE_CURRENT_BINARY_DIR}/external/nativefiledialog EXCLUDE_FROM_ALL) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/microtar ${CMAKE_CURRENT_BINARY_DIR}/external/microtar EXCLUDE_FROM_ALL) + +set(XDGPP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../../external/xdgpp") +set(CMAKE_USE_MBEDTLS ON) +set(BUILD_CURL_EXE OFF) +set(FPHSA_NAME_MISMATCHED ON CACHE BOOL "") if(NOT USE_SYSTEM_NLOHMANN_JSON) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/nlohmann_json ${CMAKE_CURRENT_BINARY_DIR}/external/nlohmann_json) @@ -14,7 +21,6 @@ else() set(NLOHMANN_JSON_LIBRARIES nlohmann_json::nlohmann_json) endif() -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/nativefiledialog ${CMAKE_CURRENT_BINARY_DIR}/external/nativefiledialog EXCLUDE_FROM_ALL) if(NOT USE_SYSTEM_FMT) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/fmt ${CMAKE_CURRENT_BINARY_DIR}/external/fmt) set(FMT_LIBRARIES fmt-header-only) @@ -23,11 +29,6 @@ else() set(FMT_LIBRARIES fmt::fmt) endif() -set(XDGPP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../../external/xdgpp") -set(CMAKE_USE_MBEDTLS ON) -set(BUILD_CURL_EXE OFF) -set(FPHSA_NAME_MISMATCHED ON CACHE BOOL "") - if(NOT USE_SYSTEM_CURL) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/curl ${CMAKE_CURRENT_BINARY_DIR}/external/curl EXCLUDE_FROM_ALL) set_target_properties(libcurl PROPERTIES POSITION_INDEPENDENT_CODE ON) @@ -37,6 +38,20 @@ else() pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl>=7.78.0) endif() +if (NOT USE_SYSTEM_LLVM) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/llvm ${CMAKE_CURRENT_BINARY_DIR}/external/llvm EXCLUDE_FROM_ALL) +else() + find_package(LLVM REQUIRED Demangle) +endif() + +if (NOT USE_SYSTEM_YARA) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/yara ${CMAKE_CURRENT_BINARY_DIR}/external/yara EXCLUDE_FROM_ALL) + set(YARA_LIBRARIES libyara) +else() + find_package(PkgConfig REQUIRED) + pkg_check_modules(YARA REQUIRED IMPORTED_TARGET yara) +endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") set(CMAKE_SHARED_LIBRARY_PREFIX "") @@ -83,27 +98,17 @@ if (APPLE) endif () endif () - set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/paths_mac.mm include/hex/helpers/file.hpp) + set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/paths_mac.mm) endif () add_library(libimhex SHARED ${LIBIMHEX_SOURCES}) -target_include_directories(libimhex PUBLIC include ${MBEDTLS_INCLUDE_DIR} ${XDGPP_INCLUDE_DIRS}) - -if (USE_SYSTEM_FMT) - target_include_directories(libimhex PUBLIC include ${FMT_INCLUDE_DIRS}) -endif() -if (USE_SYSTEM_CURL) - target_include_directories(libimhex PUBLIC include ${CURL_INCLUDE_DIRS}) -endif() - -target_link_directories(libimhex PUBLIC ${MBEDTLS_LIBRARY_DIR}) +target_include_directories(libimhex PUBLIC include ${MBEDTLS_INCLUDE_DIR} ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${Python_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${YARA_INCLUDE_DIRS}) +target_link_directories(libimhex PUBLIC ${MBEDTLS_LIBRARY_DIR} ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS}) if (APPLE) find_library(FOUNDATION NAMES Foundation) - target_link_libraries(libimhex PUBLIC imgui ${NLOHMANN_JSON_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FOUNDATION} nfd - ${FMT_LIBRARIES} ${LIBCURL_LIBRARIES} magic) -else () - target_link_libraries(libimhex PUBLIC imgui ${NLOHMANN_JSON_LIBRARIES} ${MBEDTLS_LIBRARIES} nfd magic - ${FMT_LIBRARIES} ${LIBCURL_LIBRARIES}) + target_link_libraries(libimhex PUBLIC ${FOUNDATION}) endif () + +target_link_libraries(libimhex PUBLIC imgui nfd magic capstone LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES}) diff --git a/plugins/libimhex/source/views/view.cpp b/plugins/libimhex/source/views/view.cpp index 50d69378a..88d60d915 100644 --- a/plugins/libimhex/source/views/view.cpp +++ b/plugins/libimhex/source/views/view.cpp @@ -24,8 +24,8 @@ namespace hex { } void View::drawCommonInterfaces() { - ImGui::SetNextWindowSize(ImVec2(200, 100) * SharedData::globalScale); - if (ImGui::BeginPopupModal("hex.common.info"_lang)) { + ImGui::SetNextWindowSizeConstraints(ImVec2(400, 100) * SharedData::globalScale, ImVec2(600, 300) * SharedData::globalScale); + if (ImGui::BeginPopupModal("hex.common.info"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::TextWrapped("%s", SharedData::popupMessage.c_str()); ImGui::NewLine(); ImGui::Separator(); @@ -35,8 +35,8 @@ namespace hex { ImGui::EndPopup(); } - ImGui::SetNextWindowSize(ImVec2(200, 100) * SharedData::globalScale); - if (ImGui::BeginPopupModal("hex.common.error"_lang)) { + ImGui::SetNextWindowSizeConstraints(ImVec2(400, 100) * SharedData::globalScale, ImVec2(600, 300) * SharedData::globalScale); + if (ImGui::BeginPopupModal("hex.common.error"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::TextWrapped("%s", SharedData::popupMessage.c_str()); ImGui::NewLine(); ImGui::Separator(); @@ -46,8 +46,8 @@ namespace hex { ImGui::EndPopup(); } - ImGui::SetNextWindowSize(ImVec2(200, 100) * SharedData::globalScale); - if (ImGui::BeginPopupModal("hex.common.fatal"_lang, nullptr)) { + ImGui::SetNextWindowSizeConstraints(ImVec2(400, 100) * SharedData::globalScale, ImVec2(600, 300) * SharedData::globalScale); + if (ImGui::BeginPopupModal("hex.common.fatal"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::TextWrapped("%s", SharedData::popupMessage.c_str()); ImGui::NewLine(); ImGui::Separator(); diff --git a/source/init/splash_window.cpp b/source/init/splash_window.cpp index f3c2ca714..16ca9d41d 100644 --- a/source/init/splash_window.cpp +++ b/source/init/splash_window.cpp @@ -25,7 +25,7 @@ using namespace std::literals::chrono_literals; namespace hex::init { - WindowSplash::WindowSplash(int &argc, char **&argv) { + WindowSplash::WindowSplash(int &argc, char **&argv) : m_window(nullptr) { SharedData::mainArgc = argc; SharedData::mainArgv = argv; @@ -57,7 +57,7 @@ namespace hex::init { { std::lock_guard guard(this->m_progressMutex); - this->m_progress += 1.0F / m_tasks.size(); + this->m_progress += 1.0F / this->m_tasks.size(); } } @@ -69,9 +69,7 @@ namespace hex::init { } bool WindowSplash::loop() { - ImGui::Texture splashTexture; - - splashTexture = ImGui::LoadImageFromMemory(splash, splash_size); + ImGui::Texture splashTexture = ImGui::LoadImageFromMemory(splash, splash_size); if (splashTexture == nullptr) { log::fatal("Could not load splash screen image!"); @@ -168,10 +166,14 @@ namespace hex::init { glfwWindowHint(GLFW_FLOATING, GLFW_TRUE); if (GLFWmonitor *monitor = glfwGetPrimaryMonitor(); monitor != nullptr) { - float xscale, yscale; - glfwGetMonitorContentScale(monitor, &xscale, &yscale); + float xScale = 0, yScale = 0; + glfwGetMonitorContentScale(monitor, &xScale, &yScale); - SharedData::globalScale = SharedData::fontScale = std::midpoint(xscale, yscale); + SharedData::globalScale = SharedData::fontScale = std::midpoint(xScale, yScale); + + if (SharedData::globalScale <= 0) { + SharedData::globalScale = 1.0; + } } this->m_window = glfwCreateWindow(640 * SharedData::globalScale, 400 * SharedData::globalScale, "ImHex", nullptr, nullptr); diff --git a/source/views/view_store.cpp b/source/views/view_store.cpp index 4d135420a..71ca4df53 100644 --- a/source/views/view_store.cpp +++ b/source/views/view_store.cpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include namespace hex { @@ -34,7 +36,7 @@ namespace hex { this->refresh(); } - auto drawTab = [this](auto title, ImHexPath pathType, auto &content, std::function downloadDoneCallback) { + auto drawTab = [this](auto title, ImHexPath pathType, auto &content, std::function downloadDoneCallback) { if (ImGui::BeginTabItem(title)) { if (ImGui::BeginTable("##pattern_language", 3, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_RowBg)) { ImGui::TableSetupScrollFreeze(0, 1); @@ -66,7 +68,34 @@ namespace hex { if (response.code == 200) { entry.installed = true; entry.hasUpdate = false; - downloadDoneCallback(); + + if (entry.isFolder) { + mtar_t ctx; + mtar_open(&ctx, this->m_downloadPath.string().c_str(), "r"); + + mtar_header_t header; + auto extractBasePath = this->m_downloadPath.parent_path() / this->m_downloadPath.stem(); + while (mtar_read_header(&ctx, &header) != MTAR_ENULLRECORD) { + auto filePath = extractBasePath / fs::path(header.name); + fs::create_directories(filePath.parent_path()); + File outputFile(filePath.string(), File::Mode::Create); + + std::vector buffer(0x10000); + for (u64 offset = 0; offset < header.size; offset += buffer.size()) { + auto readSize = std::min(buffer.size(), header.size - offset); + mtar_read_data(&ctx, buffer.data(), readSize); + + buffer.resize(readSize); + outputFile.write(buffer); + } + mtar_next(&ctx); + } + + mtar_finalize(&ctx); + mtar_close(&ctx); + } + + downloadDoneCallback(entry); } else log::error("Download failed!"); @@ -103,12 +132,17 @@ namespace hex { }; if (ImGui::BeginTabBar("storeTabs")) { - drawTab("hex.view.store.tab.patterns"_lang, ImHexPath::Patterns, this->m_patterns, []{}); - drawTab("hex.view.store.tab.libraries"_lang, ImHexPath::PatternsInclude, this->m_includes, []{}); - drawTab("hex.view.store.tab.magics"_lang, ImHexPath::Magic, this->m_magics, []{ + auto extractTar = []{ + + }; + + drawTab("hex.view.store.tab.patterns"_lang, ImHexPath::Patterns, this->m_patterns, [](auto){}); + drawTab("hex.view.store.tab.libraries"_lang, ImHexPath::PatternsInclude, this->m_includes, [](auto){}); + drawTab("hex.view.store.tab.magics"_lang, ImHexPath::Magic, this->m_magics, [](auto){ magic::compile(); }); - drawTab("hex.view.store.tab.constants"_lang, ImHexPath::Constants, this->m_constants, []{}); + drawTab("hex.view.store.tab.constants"_lang, ImHexPath::Constants, this->m_constants, [](auto){}); + drawTab("hex.view.store.tab.yara"_lang, ImHexPath::Yara, this->m_yara, [](auto){}); ImGui::EndTabBar(); } @@ -119,6 +153,7 @@ namespace hex { this->m_includes.clear(); this->m_magics.clear(); this->m_constants.clear(); + this->m_yara.clear(); this->m_apiRequest = this->m_net.getString(ImHexApiURL + "/store"s); } @@ -135,10 +170,10 @@ namespace hex { 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")) { + if (entry.contains("name") && entry.contains("desc") && entry.contains("file") && entry.contains("url") && entry.contains("hash") && entry.contains("folder")) { // Parse entry - StoreEntry storeEntry = { entry["name"], entry["desc"], entry["file"], entry["url"], entry["hash"], false, false, false }; + StoreEntry storeEntry = { entry["name"], entry["desc"], entry["file"], entry["url"], entry["hash"], entry["folder"],false, false, false }; // Check if file is installed already or has an update available for (const auto &folder : hex::getPath(pathType)) { @@ -170,6 +205,7 @@ namespace hex { parseStoreEntries(json, "includes", ImHexPath::PatternsInclude, this->m_includes); parseStoreEntries(json, "magic", ImHexPath::Magic, this->m_magics); parseStoreEntries(json, "constants", ImHexPath::Constants, this->m_constants); + parseStoreEntries(json, "yara", ImHexPath::Yara, this->m_yara); } this->m_apiRequest = { }; @@ -208,11 +244,13 @@ namespace hex { 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)); + this->m_downloadPath = hex::getPath(pathType).front() / fs::path(fileName); + this->m_download = this->m_net.downloadFile(url, this->m_downloadPath); } else { for (const auto &path : hex::getPath(pathType)) { auto fullPath = path / fs::path(fileName); if (fs::exists(fullPath)) { + this->m_downloadPath = fullPath; this->m_download = this->m_net.downloadFile(url, fullPath); } }