Compare commits

...

16 Commits

Author SHA1 Message Date
WerWolv
4402120ffc Added the capstone disassembler and a disassembler window 2020-11-22 23:07:50 +01:00
WerWolv
b3fffdf530 Fixed automatic pattern loading 2020-11-22 23:06:17 +01:00
WerWolv
8d6d959e17 No need to manually set table colors 2020-11-22 20:41:54 +01:00
WerWolv
43f5cc622e Allow loading of huge files efficiently 2020-11-22 19:43:35 +01:00
WerWolv
5f025bcbcc Fixed UTF-8 decoding to not work 2020-11-22 16:22:23 +01:00
WerWolv
8297e22f10 Added global big and little endian support to the pattern parser 2020-11-22 16:22:02 +01:00
WerWolv
989eade5d7 Added big and little endian support to inspector 2020-11-22 15:32:37 +01:00
WerWolv
cd4de2ff96 Fixed data inspector to only show unsigned values 2020-11-22 12:50:49 +01:00
WerWolv
73d66365e9 Updated cheat sheet page 2020-11-22 11:20:01 +01:00
WerWolv
fbd4e593d2 Make array and pointer pattern data display more consistent with other types 2020-11-22 02:25:25 +01:00
WerWolv
033ef3889a Fixed enums failing to validate 2020-11-22 02:25:03 +01:00
WerWolv
0ce1b5d40b Added simple pointer type inside structs 2020-11-21 23:00:09 +01:00
WerWolv
ed4ed6b433 Added array sizes based on other local variables 2020-11-21 20:19:33 +01:00
WerWolv
4cd18b8358 Added auto loading patterns based on MIME types 2020-11-21 14:39:16 +01:00
WerWolv
fb85f272a1 Added pragmas to pattern language 2020-11-21 14:39:01 +01:00
WerWolv
28bb28b79c Also rename data inspector window 2020-11-21 14:37:09 +01:00
31 changed files with 1050 additions and 257 deletions

View File

@@ -5,9 +5,11 @@ set(CMAKE_CXX_STANDARD 20)
find_package(PkgConfig REQUIRED)
pkg_search_module(GLFW REQUIRED glfw3)
pkg_search_module(GLM REQUIRED glm)
pkg_search_module(CAPSTONE REQUIRED capstone)
find_package(OpenGL REQUIRED)
include_directories(include ${GLFW_INCLUDE_DIRS} libs/ImGui/include libs/glad/include)
include_directories(include ${GLFW_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} libs/ImGui/include libs/glad/include)
SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -DIMGUI_IMPL_OPENGL_LOADER_GLAD")
if (WIN32)
@@ -37,6 +39,7 @@ add_executable(ImHex
source/views/view_tools.cpp
source/views/view_strings.cpp
source/views/view_data_inspector.cpp
source/views/view_disassembler.cpp
libs/glad/source/glad.c
@@ -53,9 +56,9 @@ add_executable(ImHex
)
if (WIN32)
target_link_libraries(ImHex libglfw3.a libgcc.a libstdc++.a libmagic.a libgnurx.a libtre.a libintl.a libiconv.a shlwapi.lib ws2_32.lib libcrypto.a libwinpthread.a)
target_link_libraries(ImHex libglfw3.a libgcc.a libstdc++.a libmagic.a libgnurx.a libtre.a libintl.a libiconv.a shlwapi.lib libcrypto.a libwinpthread.a libcapstone.a)
endif (WIN32)
if (UNIX)
target_link_libraries(ImHex libglfw.so libmagic.so libcrypto.so libdl.so)
target_link_libraries(ImHex libglfw.so libmagic.so libcrypto.so libdl.so libcapstone.so)
endif (UNIX)

View File

@@ -16,4 +16,10 @@ using s64 = std::int64_t;
using s128 = __int128_t;
#include "lang/result.hpp"
#include "lang/results.hpp"
#include "lang/results.hpp"
#if defined(__EMX__) || defined (WIN32)
#define MAGIC_PATH_SEPARATOR ";"
#else
#define MAGIC_PATH_SEPARATOR ":"
#endif

View File

@@ -31,20 +31,24 @@ namespace hex::lang {
class ASTNodeVariableDecl : public ASTNode {
public:
explicit ASTNodeVariableDecl(const Token::TypeToken::Type &type, const std::string &name, const std::string& customTypeName = "", std::optional<u64> offset = { }, size_t arraySize = 1)
: ASTNode(Type::VariableDecl), m_type(type), m_name(name), m_customTypeName(customTypeName), m_offset(offset), m_arraySize(arraySize) { }
explicit ASTNodeVariableDecl(const Token::TypeToken::Type &type, const std::string &name, const std::string& customTypeName = "", std::optional<u64> offset = { }, size_t arraySize = 1, std::optional<std::string> arraySizeVariable = { }, std::optional<u8> pointerSize = { })
: ASTNode(Type::VariableDecl), m_type(type), m_name(name), m_customTypeName(customTypeName), m_offset(offset), m_arraySize(arraySize), m_arraySizeVariable(arraySizeVariable), m_pointerSize(pointerSize) { }
const Token::TypeToken::Type& getVariableType() const { return this->m_type; }
const std::string& getCustomVariableTypeName() const { return this->m_customTypeName; }
const std::string& getVariableName() const { return this->m_name; };
std::optional<u64> getOffset() const { return this->m_offset; }
size_t getArraySize() const { return this->m_arraySize; }
std::optional<std::string> getArraySizeVariable() const { return this->m_arraySizeVariable; }
std::optional<u8> getPointerSize() const { return this->m_pointerSize; }
private:
Token::TypeToken::Type m_type;
std::string m_name, m_customTypeName;
std::optional<u64> m_offset;
size_t m_arraySize;
std::optional<std::string> m_arraySizeVariable;
std::optional<u8> m_pointerSize;
};
class ASTNodeScope : public ASTNode {

View File

@@ -2,9 +2,11 @@
#include <hex.hpp>
#include "providers/provider.hpp"
#include "lang/pattern_data.hpp"
#include "ast_node.hpp"
#include <bit>
#include <string>
#include <unordered_map>
#include <vector>
@@ -13,12 +15,15 @@ namespace hex::lang {
class Evaluator {
public:
Evaluator();
Evaluator(prv::Provider* &provider, std::endian dataEndianess);
std::pair<Result, std::vector<PatternData*>> evaluate(const std::vector<ASTNode*>& ast);
private:
std::unordered_map<std::string, ASTNode*> m_types;
prv::Provider* &m_provider;
std::endian m_dataEndianess;
std::pair<PatternData*, size_t> createStructPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createUnionPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);

View File

@@ -51,8 +51,11 @@ namespace hex::lang {
[[nodiscard]] u64 getOffset() const { return this->m_offset; }
[[nodiscard]] size_t getSize() const { return this->m_size; }
[[nodiscard]] u32 getColor() const { return this->m_color; }
[[nodiscard]] const std::string& getName() const { return this->m_name; }
void setName(std::string name) { this->m_name = name; }
[[nodiscard]] u32 getColor() const { return this->m_color; }
void setColor(u32 color) { this->m_color = color; }
virtual void createEntry(prv::Provider* &provider) = 0;
virtual std::string getTypeName() = 0;
@@ -92,6 +95,11 @@ namespace hex::lang {
provider->read(left->getOffset(), leftBuffer.data(), left->getSize());
provider->read(right->getOffset(), rightBuffer.data(), right->getSize());
if (PatternData::s_endianess != std::endian::native) {
std::reverse(leftBuffer.begin(), leftBuffer.end());
std::reverse(rightBuffer.begin(), rightBuffer.end());
}
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return leftBuffer > rightBuffer;
else
@@ -114,6 +122,7 @@ namespace hex::lang {
}
static void resetPalette() { PatternData::s_paletteOffset = 0; }
static void setEndianess(std::endian endianess) { PatternData::s_endianess = endianess; }
protected:
void createDefaultEntry(std::string value) {
@@ -133,6 +142,9 @@ namespace hex::lang {
ImGui::Text("%s", value.c_str());
}
protected:
static inline std::endian s_endianess = std::endian::native;
private:
Type m_type;
u64 m_offset;
@@ -142,6 +154,7 @@ namespace hex::lang {
std::string m_name;
static inline u8 s_paletteOffset = 0;
};
class PatternDataPadding : public PatternData {
@@ -156,6 +169,56 @@ namespace hex::lang {
}
};
class PatternDataPointer : public PatternData {
public:
PatternDataPointer(u64 offset, size_t size, const std::string &name, PatternData *pointedAt, u32 color = 0)
: PatternData(Type::Unsigned, offset, size, name, color), m_pointedAt(pointedAt) {
this->m_pointedAt->setName("*" + this->m_pointedAt->getName());
}
void createEntry(prv::Provider* &provider) override {
u64 data = 0;
provider->read(this->getOffset(), &data, this->getSize());
data = hex::changeEndianess(data, this->getSize(), PatternData::s_endianess);
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip);
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04lx", this->getSize());
ImGui::TableNextColumn();
ImGui::Text("%s", this->getTypeName().c_str());
ImGui::TableNextColumn();
ImGui::Text("*(0x%0*llx)", this->getSize() * 2, data);
if (open) {
this->m_pointedAt->createEntry(provider);
ImGui::TreePop();
}
}
virtual std::optional<u32> highlightBytes(size_t offset) {
if (offset >= this->getOffset() && offset < (this->getOffset() + this->getSize()))
return this->getColor();
else if (auto color = this->m_pointedAt->highlightBytes(offset); color.has_value())
return color.value();
else
return { };
}
std::string getTypeName() override {
return "Pointer";
}
private:
PatternData *m_pointedAt;
};
class PatternDataUnsigned : public PatternData {
public:
PatternDataUnsigned(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(Type::Unsigned, offset, size, name, color) { }
@@ -163,6 +226,7 @@ namespace hex::lang {
void createEntry(prv::Provider* &provider) override {
u64 data = 0;
provider->read(this->getOffset(), &data, this->getSize());
data = hex::changeEndianess(data, this->getSize(), PatternData::s_endianess);
this->createDefaultEntry(hex::format("%lu (0x%0*lx)", data, this->getSize() * 2, data));
}
@@ -186,6 +250,7 @@ namespace hex::lang {
void createEntry(prv::Provider* &provider) override {
u64 data = 0;
provider->read(this->getOffset(), &data, this->getSize());
data = hex::changeEndianess(data, this->getSize(), PatternData::s_endianess);
s64 signedData = signedData = hex::signExtend(data, this->getSize(), 64);
@@ -213,10 +278,14 @@ namespace hex::lang {
if (this->getSize() == 4) {
float data = 0;
provider->read(this->getOffset(), &data, 4);
data = hex::changeEndianess(data, 4, PatternData::s_endianess);
formatData = data;
} else if (this->getSize() == 8) {
double data = 0;
provider->read(this->getOffset(), &data, 8);
data = hex::changeEndianess(data, 8, PatternData::s_endianess);
formatData = data;
}
@@ -273,7 +342,7 @@ namespace hex::lang {
void createEntry(prv::Provider* &provider) override {
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip);
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_AlphaPreview);
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
@@ -436,6 +505,7 @@ namespace hex::lang {
void createEntry(prv::Provider* &provider) override {
u64 value = 0;
provider->read(this->getOffset(), &value, this->getSize());
value = hex::changeEndianess(value, this->getSize(), PatternData::s_endianess);
std::string valueString = this->m_enumName + "::";
@@ -451,7 +521,7 @@ namespace hex::lang {
if (!foundValue)
valueString += "???";
this->createDefaultEntry(hex::format("%s (0x0*lx)", valueString.c_str(), this->getSize() * 2, value));
this->createDefaultEntry(hex::format("%s (0x%0*lx)", valueString.c_str(), this->getSize() * 2, value));
}
std::string getTypeName() override {
@@ -471,6 +541,7 @@ namespace hex::lang {
void createEntry(prv::Provider* &provider) override {
u64 value = 0;
provider->read(this->getOffset(), &value, this->getSize());
value = hex::changeEndianess(value, this->getSize(), PatternData::s_endianess);
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
ImGui::TableNextColumn();

View File

@@ -4,9 +4,11 @@
#include "token.hpp"
#include <string>
#include <utility>
#include <functional>
#include <set>
#include <string>
#include <unordered_map>
#include <utility>
namespace hex::lang {
@@ -14,10 +16,16 @@ namespace hex::lang {
public:
Preprocessor();
std::pair<Result, std::string> preprocess(const std::string& code, bool applyDefines = true);
std::pair<Result, std::string> preprocess(const std::string& code, bool initialRun = true);
void addPragmaHandler(std::string pragmaType, std::function<bool(std::string)> function);
void addDefaultPragramHandlers();
private:
std::unordered_map<std::string, std::function<bool(std::string)>> m_pragmaHandlers;
std::set<std::pair<std::string, std::string>> m_defines;
std::set<std::pair<std::string, std::string>> m_pragmas;
};
}

View File

@@ -38,7 +38,8 @@ namespace hex::lang {
enum class Operator {
AtDeclaration,
Assignment,
Inherit
Inherit,
Star
} op;
} operatorToken;
struct IntegerToken {

View File

@@ -19,7 +19,7 @@ namespace hex::prv {
void read(u64 offset, void *buffer, size_t size) override;
void write(u64 offset, void *buffer, size_t size) override;
size_t getSize() override;
size_t getActualSize() override;
std::vector<std::pair<std::string, std::string>> getDataInformation() override;

View File

@@ -2,6 +2,7 @@
#include <hex.hpp>
#include <cmath>
#include <string>
#include <vector>
@@ -9,6 +10,8 @@ namespace hex::prv {
class Provider {
public:
constexpr static size_t PageSize = 0x1000'0000;
Provider() = default;
virtual ~Provider() = default;
@@ -18,9 +21,24 @@ namespace hex::prv {
virtual void read(u64 offset, void *buffer, size_t size) = 0;
virtual void write(u64 offset, void *buffer, size_t size) = 0;
virtual size_t getSize() = 0;
virtual size_t getActualSize() = 0;
u32 getPageCount() { return std::ceil(this->getActualSize() / double(PageSize)); }
u32 getCurrentPage() const { return this->m_currPage; }
void setCurrentPage(u32 page) { if (page < getPageCount()) this->m_currPage = page; }
virtual size_t getBaseAddress() {
return PageSize * this->m_currPage;
}
virtual size_t getSize() {
return std::min(this->getActualSize() - PageSize * this->m_currPage, PageSize);
}
virtual std::vector<std::pair<std::string, std::string>> getDataInformation() = 0;
protected:
u32 m_currPage = 0;
};
}

View File

@@ -9,6 +9,12 @@
#include <string>
#include <vector>
#ifdef __MINGW32__
#include <winsock.h>
#else
#include <arpa/inet.h>
#endif
#include "lang/token.hpp"
namespace hex {
@@ -80,6 +86,43 @@ namespace hex {
return (value & mask) >> to;
}
template<typename T>
struct always_false : std::false_type {};
template<typename T>
constexpr T changeEndianess(T value, std::endian endian) {
if (endian == std::endian::native)
return value;
if constexpr (sizeof(T) == 1)
return value;
else if constexpr (sizeof(T) == 2)
return __builtin_bswap16(value);
else if constexpr (sizeof(T) == 4)
return __builtin_bswap32(value);
else if constexpr (sizeof(T) == 8)
return __builtin_bswap64(value);
else
static_assert(always_false<T>::value, "Invalid type provided!");
}
template<typename T>
constexpr T changeEndianess(T value, size_t size, std::endian endian) {
if (endian == std::endian::native)
return value;
if (size == 1)
return value;
else if (size == 2)
return __builtin_bswap16(value);
else if (size == 4)
return __builtin_bswap32(value);
else if (size == 8)
return __builtin_bswap64(value);
else
throw std::invalid_argument("Invalid value size!");
}
class ScopeExit {
public:

View File

@@ -2,6 +2,7 @@
#include "views/view.hpp"
#include <bit>
#include <cstdio>
#include <ctime>
#include <string>
@@ -53,6 +54,8 @@ namespace hex {
bool m_windowOpen = true;
bool m_shouldInvalidate = true;
std::endian m_endianess = std::endian::native;
PreviewData m_previewData = { 0 };
size_t m_validBytes = 0;
std::vector<std::pair<std::string, std::string>> m_cachedData;

View File

@@ -0,0 +1,49 @@
#pragma once
#include "views/view.hpp"
#include <capstone/capstone.h>
#include <cstdio>
#include <string>
#include <vector>
namespace hex {
namespace prv { class Provider; }
struct Disassembly {
u64 address;
u64 offset;
std::string bytes;
std::string opcodeString;
};
class ViewDisassembler : public View {
public:
explicit ViewDisassembler(prv::Provider* &dataProvider);
~ViewDisassembler() override;
void createView() override;
void createMenu() override;
private:
prv::Provider* &m_dataProvider;
bool m_windowOpen = true;
bool m_shouldInvalidate = false;
u64 m_baseAddress = 0;
u64 m_codeOffset = 0;
u64 m_codeSize = 0;
cs_arch m_architecture = CS_ARCH_ARM;
cs_mode m_modeBasicARM = cs_mode(0), m_modeExtraARM = cs_mode(0), m_modeBasicMIPS = cs_mode(0), m_modeBasicPPC = cs_mode(0), m_modeBasicX86 = cs_mode(0);
bool m_littleEndianMode = true, m_micoMode = false, m_sparcV9Mode = false;
std::vector<Disassembly> m_disassembly;
};
}

View File

@@ -23,13 +23,16 @@ namespace hex {
prv::Provider* &m_dataProvider;
bool m_windowOpen = true;
bool m_dataValid = false;
u32 m_blockSize = 0;
float m_averageEntropy = 0;
float m_highestBlockEntropy = 0;
std::vector<float> m_blockEntropy;
std::array<float, 256> m_valueCounts = { 0 };
bool m_shouldInvalidate = true;
bool m_shouldInvalidate = false;
std::pair<u64, u64> m_analyzedRegion = { 0, 0 };
std::string m_fileDescription;
std::string m_mimeType;

View File

@@ -9,7 +9,7 @@
#include <concepts>
#include <cstring>
#include <filesystem>
#include "ImGuiFileBrowser.h"
#include "TextEditor.h"
@@ -27,11 +27,13 @@ namespace hex {
private:
std::vector<lang::PatternData*> &m_patternData;
prv::Provider* &m_dataProvider;
std::filesystem::path m_possiblePatternFile;
bool m_windowOpen = true;
TextEditor m_textEditor;
imgui_addons::ImGuiFileBrowser m_fileBrowser;
void loadPatternFile(std::string path);
void clearPatternData();
void parsePattern(char *buffer);
};

View File

@@ -547,18 +547,6 @@ struct MemoryEditor
ImGui::SameLine();
ImGui::Text(format_range, s.AddrDigitsCount, base_display_addr, s.AddrDigitsCount, base_display_addr + mem_size - 1);
ImGui::SameLine();
ImGui::PushItemWidth((s.AddrDigitsCount + 1) * s.GlyphWidth + style.FramePadding.x * 2.0f);
if (ImGui::InputText("##addr", AddrInputBuf, 32, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_EnterReturnsTrue))
{
size_t goto_addr;
if (sscanf(AddrInputBuf, "%" _PRISizeT "X", &goto_addr) == 1)
{
GotoAddr = goto_addr - base_display_addr;
HighlightMin = HighlightMax = (size_t)-1;
}
}
ImGui::PopItemWidth();
if (GotoAddr != (size_t)-1)
{

View File

@@ -5,8 +5,8 @@
namespace hex::lang {
Evaluator::Evaluator() {
Evaluator::Evaluator(prv::Provider* &provider, std::endian dataEndianess) : m_provider(provider), m_dataEndianess(dataEndianess) {
PatternData::setEndianess(dataEndianess);
}
std::pair<PatternData*, size_t> Evaluator::createStructPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) {
@@ -21,54 +21,71 @@ namespace hex::lang {
for (const auto &node : structNode->getNodes()) {
const auto &member = static_cast<ASTNodeVariableDecl*>(node);
u64 memberOffset = 0;
if (member->getPointerSize().has_value()) {
this->m_provider->read(offset + structSize, &memberOffset, member->getPointerSize().value());
memberOffset = hex::changeEndianess(memberOffset, member->getPointerSize().value(), this->m_dataEndianess);
}
else
memberOffset = offset + structSize;
const auto typeDeclNode = static_cast<ASTNodeTypeDecl*>(this->m_types[member->getCustomVariableTypeName()]);
PatternData *pattern = nullptr;
u64 memberSize = 0;
if (member->getVariableType() == Token::TypeToken::Type::Signed8Bit && member->getArraySize() > 1) {
const auto &[pattern, size] = this->createStringPattern(member, offset + structSize);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
structSize += size;
std::tie(pattern, memberSize) = this->createStringPattern(member, memberOffset);
} else if (member->getVariableType() == Token::TypeToken::Type::CustomType
&& typeDeclNode != nullptr && typeDeclNode->getAssignedType() == Token::TypeToken::Type::Signed8Bit
&& member->getArraySize() > 1) {
const auto &[pattern, size] = this->createStringPattern(member, offset + structSize);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
structSize += size;
std::tie(pattern, memberSize) = this->createStringPattern(member, memberOffset);
}
else if (member->getArraySize() > 1) {
const auto &[pattern, size] = this->createArrayPattern(member, offset + structSize);
std::tie(pattern, memberSize) = this->createArrayPattern(member, memberOffset);
}
else if (member->getArraySizeVariable().has_value()) {
std::optional<size_t> arraySize;
if (pattern == nullptr)
for (auto &prevMember : members) {
if (prevMember->getPatternType() == PatternData::Type::Unsigned && prevMember->getName() == member->getArraySizeVariable()) {
u64 value = 0;
this->m_provider->read(prevMember->getOffset(), &value, prevMember->getSize());
value = hex::changeEndianess(value, prevMember->getSize(), this->m_dataEndianess);
arraySize = value;
}
}
if (!arraySize.has_value())
return { nullptr, 0 };
members.push_back(pattern);
structSize += size;
ASTNodeVariableDecl *processedMember = new ASTNodeVariableDecl(member->getVariableType(), member->getVariableName(), member->getCustomVariableTypeName(), member->getOffset(), arraySize.value());
std::tie(pattern, memberSize) = this->createArrayPattern(processedMember, memberOffset);
}
else if (member->getVariableType() != Token::TypeToken::Type::CustomType) {
const auto &[pattern, size] = this->createBuiltInTypePattern(member, offset + structSize);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
structSize += size;
std::tie(pattern, memberSize) = this->createBuiltInTypePattern(member, memberOffset);
}
else {
const auto &[pattern, size] = this->createCustomTypePattern(member, offset + structSize);
std::tie(pattern, memberSize) = this->createCustomTypePattern(member, memberOffset);
}
if (pattern == nullptr)
return { nullptr, 0 };
if (pattern == nullptr)
return { nullptr, 0 };
if (member->getPointerSize().has_value()) {
members.push_back(new PatternDataPointer(offset + structSize, member->getPointerSize().value(), member->getVariableName(), pattern));
structSize += member->getPointerSize().value();
}
else {
members.push_back(pattern);
structSize += size;
structSize += memberSize;
}
}
@@ -87,54 +104,74 @@ namespace hex::lang {
for (const auto &node : unionNode->getNodes()) {
const auto &member = static_cast<ASTNodeVariableDecl*>(node);
u64 memberOffset = 0;
if (member->getPointerSize().has_value()) {
this->m_provider->read(offset + unionSize, &memberOffset, member->getPointerSize().value());
memberOffset = hex::changeEndianess(memberOffset, member->getPointerSize().value(), this->m_dataEndianess);
}
else
memberOffset = offset;
const auto typeDeclNode = static_cast<ASTNodeTypeDecl*>(this->m_types[member->getCustomVariableTypeName()]);
PatternData *pattern = nullptr;
u64 memberSize = 0;
if (member->getVariableType() == Token::TypeToken::Type::Signed8Bit && member->getArraySize() > 1) {
const auto &[pattern, size] = this->createStringPattern(member, offset);
std::tie(pattern, memberSize) = this->createStringPattern(member, memberOffset);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
unionSize = std::max(size, unionSize);
} else if (member->getVariableType() == Token::TypeToken::Type::CustomType
&& typeDeclNode != nullptr && typeDeclNode->getAssignedType() == Token::TypeToken::Type::Signed8Bit
&& member->getArraySize() > 1) {
const auto &[pattern, size] = this->createStringPattern(member, offset);
std::tie(pattern, memberSize) = this->createStringPattern(member, memberOffset);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
unionSize = std::max(size, unionSize);
}
else if (member->getArraySize() > 1) {
const auto &[pattern, size] = this->createArrayPattern(member, offset);
std::tie(pattern, memberSize) = this->createArrayPattern(member, memberOffset);
if (pattern == nullptr)
}
else if (member->getArraySizeVariable().has_value()) {
std::optional<size_t> arraySize;
for (auto &prevMember : members) {
if (prevMember->getPatternType() == PatternData::Type::Unsigned && prevMember->getName() == member->getArraySizeVariable()) {
u64 value = 0;
this->m_provider->read(prevMember->getOffset(), &value, prevMember->getSize());
value = hex::changeEndianess(value, prevMember->getSize(), this->m_dataEndianess);
arraySize = value;
}
}
if (!arraySize.has_value())
return { nullptr, 0 };
members.push_back(pattern);
unionSize = std::max(size, unionSize);
ASTNodeVariableDecl *processedMember = new ASTNodeVariableDecl(member->getVariableType(), member->getVariableName(), member->getCustomVariableTypeName(), member->getOffset(), arraySize.value());
std::tie(pattern, memberSize) = this->createArrayPattern(processedMember, memberOffset);
}
else if (member->getVariableType() != Token::TypeToken::Type::CustomType) {
const auto &[pattern, size] = this->createBuiltInTypePattern(member, offset);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
unionSize = std::max(size, unionSize);
std::tie(pattern, memberSize) = this->createBuiltInTypePattern(member, memberOffset);
}
else {
const auto &[pattern, size] = this->createCustomTypePattern(member, offset);
std::tie(pattern, memberSize) = this->createCustomTypePattern(member, memberOffset);
}
if (pattern == nullptr)
return { nullptr, 0 };
if (pattern == nullptr)
return { nullptr, 0 };
if (member->getPointerSize().has_value()) {
members.push_back(new PatternDataPointer(offset, member->getPointerSize().value(), member->getVariableName(), pattern));
unionSize = std::max(size_t(member->getPointerSize().value()), unionSize);
}
else {
members.push_back(pattern);
unionSize = std::max(size, unionSize);
unionSize = std::max(memberSize, unionSize);
}
}
@@ -173,18 +210,27 @@ namespace hex::lang {
std::pair<PatternData*, size_t> Evaluator::createArrayPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) {
std::vector<PatternData*> entries;
auto arraySizeVariable = varDeclNode->getArraySizeVariable();
size_t arrayOffset = 0;
std::optional<u32> arrayColor;
for (u32 i = 0; i < varDeclNode->getArraySize(); i++) {
ASTNodeVariableDecl *nonArrayVarDeclNode = new ASTNodeVariableDecl(varDeclNode->getVariableType(), "[" + std::to_string(i) + "]", varDeclNode->getCustomVariableTypeName(), varDeclNode->getOffset(), 1);
if (varDeclNode->getVariableType() == Token::TypeToken::Type::Padding) {
return { new PatternDataPadding(offset, varDeclNode->getArraySize()), varDeclNode->getArraySize() };
} else if (varDeclNode->getVariableType() != Token::TypeToken::Type::CustomType) {
const auto &[pattern, size] = this->createBuiltInTypePattern(nonArrayVarDeclNode, offset + arrayOffset);
const auto& [pattern, size] = this->createBuiltInTypePattern(nonArrayVarDeclNode, offset + arrayOffset);
if (pattern == nullptr)
return { nullptr, 0 };
if (!arrayColor.has_value())
arrayColor = pattern->getColor();
pattern->setColor(arrayColor.value());
entries.push_back(pattern);
arrayOffset += size;
} else {
@@ -193,6 +239,11 @@ namespace hex::lang {
if (pattern == nullptr)
return { nullptr, 0 };
if (!arrayColor.has_value())
arrayColor = pattern->getColor();
pattern->setColor(arrayColor.value());
entries.push_back(pattern);
arrayOffset += size;
}

View File

@@ -128,6 +128,9 @@ namespace hex::lang {
} else if (c == ':') {
tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::Inherit } });
offset += 1;
} else if (c == '*') {
tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::Star } });
offset += 1;
} else if (std::isalpha(c)) {
std::string identifier = matchTillInvalid(&code[offset], [](char c) -> bool { return std::isalnum(c) || c == '_'; });

View File

@@ -1,5 +1,7 @@
#include "lang/parser.hpp"
#include "utils.hpp"
#include <optional>
namespace hex::lang {
@@ -35,18 +37,44 @@ namespace hex::lang {
return new ASTNodeVariableDecl(Token::TypeToken::Type::CustomType, curr[-2].identifierToken.identifier, curr[-3].identifierToken.identifier);
}
ASTNode* parseBuiltinPointerVariableDecl(TokenIter &curr) {
auto pointerType = curr[-2].typeToken.type;
if (!isUnsigned(pointerType) || curr[-5].operatorToken.op != Token::OperatorToken::Operator::Star || curr[-3].operatorToken.op != Token::OperatorToken::Operator::Inherit)
return nullptr;
return new ASTNodeVariableDecl(curr[-6].typeToken.type, curr[-4].identifierToken.identifier, "", { }, 1, { }, getTypeSize(pointerType));
}
ASTNode* parseCustomTypePointerVariableDecl(TokenIter &curr) {
auto pointerType = curr[-2].typeToken.type;
if (!isUnsigned(pointerType) || curr[-5].operatorToken.op != Token::OperatorToken::Operator::Star || curr[-3].operatorToken.op != Token::OperatorToken::Operator::Inherit)
return nullptr;
return new ASTNodeVariableDecl(Token::TypeToken::Type::CustomType, curr[-4].identifierToken.identifier, curr[-6].identifierToken.identifier, { }, 1, { }, getTypeSize(pointerType));
}
ASTNode* parseBuiltinArrayDecl(TokenIter &curr) {
return new ASTNodeVariableDecl(curr[-6].typeToken.type, curr[-5].identifierToken.identifier, "", { }, curr[-3].integerToken.integer);
}
ASTNode* parsePaddingDecl(TokenIter &curr) {
return new ASTNodeVariableDecl(curr[-5].typeToken.type, "", "", { }, curr[-3].integerToken.integer);
}
ASTNode* parseCustomTypeArrayDecl(TokenIter &curr) {
return new ASTNodeVariableDecl(Token::TypeToken::Type::CustomType, curr[-5].identifierToken.identifier, curr[-6].identifierToken.identifier, { }, curr[-3].integerToken.integer);
}
ASTNode* parseBuiltinVariableArrayDecl(TokenIter &curr) {
return new ASTNodeVariableDecl(curr[-6].typeToken.type, curr[-5].identifierToken.identifier, "", { }, 0, curr[-3].identifierToken.identifier);
}
ASTNode* parseCustomTypeVariableArrayDecl(TokenIter &curr) {
return new ASTNodeVariableDecl(Token::TypeToken::Type::CustomType, curr[-5].identifierToken.identifier, curr[-6].identifierToken.identifier, { }, 0, curr[-3].identifierToken.identifier);
}
ASTNode* parsePaddingDecl(TokenIter &curr) {
return new ASTNodeVariableDecl(curr[-5].typeToken.type, "", "", { }, curr[-3].integerToken.integer);
}
ASTNode* parseFreeBuiltinVariableDecl(TokenIter &curr) {
return new ASTNodeVariableDecl(curr[-5].typeToken.type, curr[-4].identifierToken.identifier, "", curr[-2].integerToken.integer);
}
@@ -68,13 +96,20 @@ namespace hex::lang {
nodes.push_back(parseBuiltinArrayDecl(curr));
else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Integer, Token::Type::ArrayClose, Token::Type::EndOfExpression}))
nodes.push_back(parseCustomTypeArrayDecl(curr));
else if (tryConsume(curr, {Token::Type::Type, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Identifier, Token::Type::ArrayClose, Token::Type::EndOfExpression}))
nodes.push_back(parseBuiltinVariableArrayDecl(curr));
else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Identifier, Token::Type::ArrayClose, Token::Type::EndOfExpression}))
nodes.push_back(parseCustomTypeVariableArrayDecl(curr));
else if (tryConsume(curr, {Token::Type::Type, Token::Type::ArrayOpen, Token::Type::Integer, Token::Type::ArrayClose, Token::Type::EndOfExpression})) {
if (curr[-5].typeToken.type != Token::TypeToken::Type::Padding) {
for(auto &node : nodes) delete node;
return nullptr;
}
nodes.push_back(parsePaddingDecl(curr));
}
} else if (tryConsume(curr, {Token::Type::Type, Token::Type::Operator, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::EndOfExpression}))
nodes.push_back(parseBuiltinPointerVariableDecl(curr));
else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Operator, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::EndOfExpression}))
nodes.push_back(parseCustomTypePointerVariableDecl(curr));
else break;
}
@@ -99,6 +134,10 @@ namespace hex::lang {
nodes.push_back(parseBuiltinArrayDecl(curr));
else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Integer, Token::Type::ArrayClose, Token::Type::EndOfExpression}))
nodes.push_back(parseCustomTypeArrayDecl(curr));
else if (tryConsume(curr, {Token::Type::Type, Token::Type::Operator, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::EndOfExpression}))
nodes.push_back(parseBuiltinPointerVariableDecl(curr));
else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Operator, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::EndOfExpression}))
nodes.push_back(parseCustomTypePointerVariableDecl(curr));
else break;
}

View File

@@ -6,11 +6,13 @@ namespace hex::lang {
}
std::pair<Result, std::string> Preprocessor::preprocess(const std::string& code, bool applyDefines) {
std::pair<Result, std::string> Preprocessor::preprocess(const std::string& code, bool initialRun) {
u32 offset = 0;
if (applyDefines)
if (initialRun) {
this->m_defines.clear();
this->m_pragmas.clear();
}
std::string output;
output.reserve(code.length());
@@ -76,45 +78,103 @@ namespace hex::lang {
std::string defineName;
while (!std::isblank(code[offset])) {
defineName += code[offset];
offset += 1;
if (offset >= code.length() || code[offset] == '\n' || code[offset] == '\r')
return { ResultPreprocessingError, "" };
offset += 1;
}
while (std::isblank(code[offset]))
offset += 1;
std::string replaceValue;
do {
while (code[offset] != '\n' && code[offset] != '\r') {
if (offset >= code.length())
return { ResultPreprocessingError, "" };
replaceValue += code[offset];
offset += 1;
} while (code[offset] != '\n' && code[offset] != '\r');
}
if (replaceValue.empty())
return { ResultPreprocessingError, "" };
this->m_defines.emplace(defineName, replaceValue);
}
} else if (code.substr(offset, 6) == "pragma") {
offset += 6;
while (std::isblank(code[offset]))
offset += 1;
std::string pragmaKey;
while (!std::isblank(code[offset])) {
pragmaKey += code[offset];
if (offset >= code.length() || code[offset] == '\n' || code[offset] == '\r')
return { ResultPreprocessingError, "" };
offset += 1;
}
while (std::isblank(code[offset]))
offset += 1;
std::string pragmaValue;
while (code[offset] != '\n' && code[offset] != '\r') {
if (offset >= code.length())
return { ResultPreprocessingError, "" };
pragmaValue += code[offset];
offset += 1;
}
if (pragmaValue.empty())
return { ResultPreprocessingError, "" };
this->m_pragmas.emplace(pragmaKey, pragmaValue);
} else
return { ResultPreprocessingError, "" };
}
output += code[offset];
offset += 1;
}
if (applyDefines) {
if (initialRun) {
// Apply defines
for (const auto &[define, value] : this->m_defines) {
s32 index = 0;
while((index = output.find(define, index)) != std::string::npos) {
if (index > 0) {
output.replace(index, define.length(), value);
index += value.length();
}
output.replace(index, define.length(), value);
index += value.length();
}
}
// Handle pragmas
for (const auto &[type, value] : this->m_pragmas) {
if (this->m_pragmaHandlers.contains(type)) {
if (!this->m_pragmaHandlers[type](value))
return { ResultPreprocessingError, { } };
} else
return { ResultPreprocessingError, { } };
}
}
return { ResultSuccess, output };
}
void Preprocessor::addPragmaHandler(std::string pragmaType, std::function<bool(std::string)> function) {
if (!this->m_pragmaHandlers.contains(pragmaType))
this->m_pragmaHandlers.emplace(pragmaType, function);
}
void Preprocessor::addDefaultPragramHandlers() {
this->addPragmaHandler("MIME", [](std::string value) {
return !std::all_of(value.begin(), value.end(), isspace) && !value.ends_with('\n') && !value.ends_with('\r');
});
this->addPragmaHandler("endian", [](std::string value) {
return value == "big" || value == "little" || value == "native";
});
}
}

View File

@@ -21,6 +21,10 @@ namespace hex::lang {
auto varDeclNode = static_cast<ASTNodeVariableDecl*>(node);
if (!typeNames.insert(varDeclNode->getVariableName()).second)
return false;
if (varDeclNode->getArraySize() == 0 && !varDeclNode->getArraySizeVariable().has_value() ||
varDeclNode->getArraySize() != 0 && varDeclNode->getArraySizeVariable().has_value())
return false;
}
break;
case ASTNode::Type::TypeDecl:
@@ -33,7 +37,7 @@ namespace hex::lang {
if (typeDeclNode->getAssignedType() == Token::TypeToken::Type::CustomType && !typeNames.contains(typeDeclNode->getAssignedCustomTypeName()))
return false;
}
break;
break;
case ASTNode::Type::Struct:
{
// Check for duplicate type name
@@ -47,7 +51,7 @@ namespace hex::lang {
if (!memberNames.insert(static_cast<ASTNodeVariableDecl*>(member)->getVariableName()).second)
return false;
}
break;
break;
case ASTNode::Type::Enum:
{
// Check for duplicate type name
@@ -61,6 +65,7 @@ namespace hex::lang {
if (!constantNames.insert(name).second)
return false;
}
break;
case ASTNode::Type::Bitfield:
{
// Check for duplicate type name
@@ -82,7 +87,7 @@ namespace hex::lang {
if (bitfieldSize > 64)
return false;
}
break;
break;
}
}

View File

@@ -10,6 +10,7 @@
#include "views/view_tools.hpp"
#include "views/view_strings.hpp"
#include "views/view_data_inspector.hpp"
#include "views/view_disassembler.hpp"
#include "providers/provider.hpp"
@@ -21,7 +22,6 @@ int main() {
// Shared Data
std::vector<hex::lang::PatternData*> patternData;
hex::prv::Provider *dataProvider = nullptr;
// Create views
window.addView<hex::ViewHexEditor>(dataProvider, patternData);
window.addView<hex::ViewPattern>(dataProvider, patternData);
@@ -30,8 +30,9 @@ int main() {
window.addView<hex::ViewHashes>(dataProvider);
window.addView<hex::ViewInformation>(dataProvider);
window.addView<hex::ViewStrings>(dataProvider);
window.addView<hex::ViewHelp>();
window.addView<hex::ViewDisassembler>(dataProvider);
window.addView<hex::ViewTools>();
window.addView<hex::ViewHelp>();
window.loop();

View File

@@ -22,7 +22,6 @@ namespace hex::prv {
this->m_file = fopen(path.data(), "rb");
this->m_writable = false;
}
}
FileProvider::~FileProvider() {
@@ -48,7 +47,7 @@ namespace hex::prv {
if ((offset + size) > this->getSize() || buffer == nullptr || size == 0)
return;
fseeko64(this->m_file, offset, SEEK_SET);
fseeko64(this->m_file, this->getCurrentPage() * PageSize + offset, SEEK_SET);
fread(buffer, 1, size, this->m_file);
}
@@ -56,11 +55,11 @@ namespace hex::prv {
if (buffer == nullptr || size == 0)
return;
fseeko64(this->m_file, offset, SEEK_SET);
fseeko64(this->m_file, this->getCurrentPage() * PageSize + offset, SEEK_SET);
fwrite(buffer, 1, size, this->m_file);
}
size_t FileProvider::getSize() {
size_t FileProvider::getActualSize() {
fseeko64(this->m_file, 0, SEEK_END);
return ftello64(this->m_file);
}
@@ -69,7 +68,7 @@ namespace hex::prv {
std::vector<std::pair<std::string, std::string>> result;
result.emplace_back("File path", this->m_path);
result.emplace_back("Size", hex::toByteString(this->getSize()));
result.emplace_back("Size", hex::toByteString(this->getActualSize()));
if (this->m_fileStatsValid) {
result.emplace_back("Creation time", ctime(&this->m_fileStats.st_ctime));

View File

@@ -41,31 +41,36 @@ namespace hex {
this->m_cachedData.emplace_back("Binary (8 bit)", binary);
}
this->m_cachedData.emplace_back("uint8_t", hex::format("%u", this->m_previewData.unsigned8));
this->m_cachedData.emplace_back("int8_t", hex::format("%d", this->m_previewData.unsigned8));
this->m_cachedData.emplace_back("uint16_t", hex::format("%u", this->m_previewData.unsigned16));
this->m_cachedData.emplace_back("int16_t", hex::format("%d", this->m_previewData.unsigned16));
this->m_cachedData.emplace_back("uint32_t", hex::format("%lu", this->m_previewData.unsigned32));
this->m_cachedData.emplace_back("int32_t", hex::format("%ld", this->m_previewData.unsigned32));
this->m_cachedData.emplace_back("uint64_t", hex::format("%llu", this->m_previewData.unsigned64));
this->m_cachedData.emplace_back("int64_t", hex::format("%lld", this->m_previewData.unsigned64));
this->m_cachedData.emplace_back("uint8_t", hex::format("%u", hex::changeEndianess(this->m_previewData.unsigned8, this->m_endianess)));
this->m_cachedData.emplace_back("int8_t", hex::format("%d", hex::changeEndianess(this->m_previewData.signed8, this->m_endianess)));
this->m_cachedData.emplace_back("uint16_t", hex::format("%u", hex::changeEndianess(this->m_previewData.unsigned16, this->m_endianess)));
this->m_cachedData.emplace_back("int16_t", hex::format("%d", hex::changeEndianess(this->m_previewData.signed16, this->m_endianess)));
this->m_cachedData.emplace_back("uint32_t", hex::format("%lu", hex::changeEndianess(this->m_previewData.unsigned32, this->m_endianess)));
this->m_cachedData.emplace_back("int32_t", hex::format("%ld", hex::changeEndianess(this->m_previewData.signed32, this->m_endianess)));
this->m_cachedData.emplace_back("uint64_t", hex::format("%llu", hex::changeEndianess(this->m_previewData.unsigned64, this->m_endianess)));
this->m_cachedData.emplace_back("int64_t", hex::format("%lld", hex::changeEndianess(this->m_previewData.signed64, this->m_endianess)));
this->m_cachedData.emplace_back("ANSI Character / char8_t", hex::format("%c", this->m_previewData.ansiChar));
this->m_cachedData.emplace_back("Wide Character / char16_t", hex::format("%lc", this->m_previewData.wideChar));
this->m_cachedData.emplace_back("ANSI Character / char8_t", hex::format("%c", hex::changeEndianess(this->m_previewData.ansiChar, this->m_endianess)));
this->m_cachedData.emplace_back("Wide Character / char16_t", hex::format("%lc", hex::changeEndianess(this->m_previewData.wideChar, this->m_endianess)));
{
char buffer[5] = { 0 };
char codepointString[5] = { 0 };
u32 codepoint = 0;
std::memcpy(buffer, &this->m_previewData.utf8Char, 4);
u32 utf8 = 0;
ImTextCharFromUtf8(&utf8, buffer, buffer + 4);
this->m_cachedData.emplace_back("UTF-8 code point", hex::format("U+%08lx", utf8));
u8 codepointSize = ImTextCharFromUtf8(&codepoint, buffer, buffer + 4);
std::memcpy(codepointString, &codepoint, std::min(codepointSize, u8(4)));
this->m_cachedData.emplace_back("UTF-8 code point", hex::format("'%s' (U+%04lx)", codepoint == 0xFFFD ? "Invalid" : codepointString, codepoint));
}
this->m_cachedData.emplace_back("float (32 bit)", hex::format("%e", this->m_previewData.float32));
this->m_cachedData.emplace_back("double (64 bit)", hex::format("%e", this->m_previewData.float64));
this->m_cachedData.emplace_back("float (32 bit)", hex::format("%e", hex::changeEndianess(this->m_previewData.float32, this->m_endianess)));
this->m_cachedData.emplace_back("double (64 bit)", hex::format("%e", hex::changeEndianess(this->m_previewData.float64, this->m_endianess)));
#if defined(_WIN64)
{
std::tm * ptm = _localtime32(&this->m_previewData.time32);
auto endianAdjustedTime = hex::changeEndianess(this->m_previewData.time32, this->m_endianess);
std::tm * ptm = _localtime32(&endianAdjustedTime);
char buffer[32];
if (std::strftime(buffer, 32, "%a, %d.%m.%Y %H:%M:%S", ptm))
this->m_cachedData.emplace_back("__time32_t", buffer);
@@ -74,7 +79,8 @@ namespace hex {
}
{
std::tm * ptm = _localtime64(&this->m_previewData.time64);
auto endianAdjustedTime = hex::changeEndianess(this->m_previewData.time64, this->m_endianess);
std::tm * ptm = _localtime64(&endianAdjustedTime);
char buffer[64];
if (std::strftime(buffer, 64, "%a, %d.%m.%Y %H:%M:%S", ptm) != 0)
this->m_cachedData.emplace_back("__time64_t", buffer);
@@ -83,7 +89,8 @@ namespace hex {
}
#else
{
std::tm * ptm = localtime(&this->m_previewData.time);
auto endianAdjustedTime = hex::changeEndianess(this->m_previewData.time, this->m_endianess);
std::tm * ptm = localtime(&endianAdjustedTime);
char buffer[64];
if (std::strftime(buffer, 64, "%a, %d.%m.%Y %H:%M:%S", ptm) != 0)
this->m_cachedData.emplace_back("time_t", buffer);
@@ -93,30 +100,29 @@ namespace hex {
#endif
this->m_cachedData.emplace_back("GUID", hex::format("{%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}",
this->m_previewData.guid.data1, this->m_previewData.guid.data2, this->m_previewData.guid.data3,
hex::changeEndianess(this->m_previewData.guid.data1, this->m_endianess),
hex::changeEndianess(this->m_previewData.guid.data2, this->m_endianess),
hex::changeEndianess(this->m_previewData.guid.data3, this->m_endianess),
this->m_previewData.guid.data4[0], this->m_previewData.guid.data4[1], this->m_previewData.guid.data4[2], this->m_previewData.guid.data4[3],
this->m_previewData.guid.data4[4], this->m_previewData.guid.data4[5], this->m_previewData.guid.data4[6], this->m_previewData.guid.data4[7]));
}
if (ImGui::Begin("Data Preview", &this->m_windowOpen)) {
if (ImGui::Begin("Data Inspector", &this->m_windowOpen)) {
if (this->m_dataProvider != nullptr && this->m_dataProvider->isReadable()) {
if (ImGui::BeginChild("##scrolling")) {
if (ImGui::BeginTable("##datainspector", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) {
if (ImGui::BeginChild("##scrolling", ImVec2(0, ImGui::GetWindowHeight() - 60))) {
if (ImGui::BeginTable("##datainspector", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody)) {
ImGui::TableSetupColumn("Name");
ImGui::TableSetupColumn("Value");
ImGui::TableHeadersRow();
u32 rowCount = 0;
for (const auto &[name, value] : this->m_cachedData) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted(name.c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(value.c_str());
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,
((rowCount % 2) == 0) ? 0xFF101010 : 0xFF303030);
rowCount++;
}
{
@@ -124,11 +130,8 @@ namespace hex {
ImGui::TableNextColumn();
ImGui::TextUnformatted("RGBA Color");
ImGui::TableNextColumn();
ImGui::ColorButton("##nolabel", ImColor(this->m_previewData.unsigned32),
ImGui::ColorButton("##nolabel", ImColor(hex::changeEndianess(this->m_previewData.unsigned32, this->m_endianess)),
ImGuiColorEditFlags_None, ImVec2(ImGui::GetColumnWidth(), 15));
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,
((rowCount % 2) == 0) ? 0xFF101010 : 0xFF303030);
rowCount++;
}
@@ -136,6 +139,16 @@ namespace hex {
}
}
ImGui::EndChild();
if (ImGui::RadioButton("Little Endian", this->m_endianess == std::endian::little)) {
this->m_endianess = std::endian::little;
this->m_shouldInvalidate = true;
}
ImGui::SameLine();
if (ImGui::RadioButton("Big Endian", this->m_endianess == std::endian::big)) {
this->m_endianess = std::endian::big;
this->m_shouldInvalidate = true;
}
}
}
ImGui::End();

View File

@@ -0,0 +1,268 @@
#include "views/view_disassembler.hpp"
#include "providers/provider.hpp"
#include "utils.hpp"
#include <cstring>
using namespace std::literals::string_literals;
namespace hex {
ViewDisassembler::ViewDisassembler(prv::Provider* &dataProvider) : View(), m_dataProvider(dataProvider) {
View::subscribeEvent(Events::DataChanged, [this](const void*){
this->m_shouldInvalidate = true;
});
}
ViewDisassembler::~ViewDisassembler() {
View::unsubscribeEvent(Events::DataChanged);
}
void ViewDisassembler::createView() {
if (!this->m_windowOpen)
return;
if (this->m_shouldInvalidate) {
this->m_disassembly.clear();
csh capstoneHandle;
cs_insn *instructions = nullptr;
cs_mode mode = cs_mode(this->m_modeBasicARM | this->m_modeExtraARM | this->m_modeBasicMIPS | this->m_modeBasicX86 | this->m_modeBasicPPC);
if (this->m_littleEndianMode)
mode = cs_mode(mode | CS_MODE_LITTLE_ENDIAN);
else
mode = cs_mode(mode | CS_MODE_BIG_ENDIAN);
if (this->m_micoMode)
mode = cs_mode(mode | CS_MODE_MICRO);
if (this->m_sparcV9Mode)
mode = cs_mode(mode | CS_MODE_V9);
if (cs_open(this->m_architecture, mode, &capstoneHandle) == CS_ERR_OK) {
std::vector<u8> buffer(2048, 0x00);
for (u64 address = 0; address < this->m_codeSize; address += 2048) {
size_t bufferSize = std::min(u64(2048), this->m_codeSize - address);
this->m_dataProvider->read(this->m_codeOffset + address, buffer.data(), bufferSize);
size_t instructionCount = cs_disasm(capstoneHandle, buffer.data(), buffer.size(), this->m_baseAddress + address, 0, &instructions);
if (instructionCount == 0)
break;
u64 usedBytes = 0;
for (u32 instr = 0; instr < instructionCount; instr++) {
Disassembly disassembly = { 0 };
disassembly.address = instructions[instr].address;
disassembly.offset = this->m_codeOffset + address + usedBytes;
disassembly.opcodeString = instructions[instr].mnemonic + " "s + instructions[instr].op_str;
for (u8 i = 0; i < instructions[instr].size; i++)
disassembly.bytes += hex::format("%02X ", instructions[instr].bytes[i]);
disassembly.bytes.pop_back();
this->m_disassembly.push_back(disassembly);
usedBytes += instructions[instr].size;
}
if (instructionCount < bufferSize)
address -= (bufferSize - usedBytes);
cs_free(instructions, instructionCount);
}
cs_close(&capstoneHandle);
}
this->m_shouldInvalidate = false;
}
if (ImGui::Begin("Disassembler", &this->m_windowOpen)) {
if (this->m_dataProvider != nullptr && this->m_dataProvider->isReadable()) {
constexpr static const char * const ArchitectureNames[] = { "ARM32", "ARM64", "MIPS", "x86", "PowerPC", "Sparc", "SystemZ", "XCore", "68K", "TMS320C64x", "680X", "Ethereum" };
ImGui::InputScalar("Base address", ImGuiDataType_U64, &this->m_baseAddress, nullptr, nullptr, "%llx", ImGuiInputTextFlags_CharsHexadecimal);
ImGui::NewLine();
ImGui::InputScalar("Code start offset", ImGuiDataType_U64, &this->m_codeOffset, nullptr, nullptr, "%llx", ImGuiInputTextFlags_CharsHexadecimal);
ImGui::InputScalar("Code size", ImGuiDataType_U64, &this->m_codeSize, nullptr, nullptr, "%llx", ImGuiInputTextFlags_CharsHexadecimal);
ImGui::NewLine();
ImGui::Separator();
ImGui::NewLine();
ImGui::Combo("Architecture", reinterpret_cast<int*>(&this->m_architecture), ArchitectureNames, 12);
if (ImGui::BeginChild("modes", ImVec2(0, 100), true)) {
if (ImGui::RadioButton("Little Endian", this->m_littleEndianMode))
this->m_littleEndianMode = true;
ImGui::SameLine();
if (ImGui::RadioButton("Big Endian", !this->m_littleEndianMode))
this->m_littleEndianMode = false;
ImGui::NewLine();
switch (this->m_architecture) {
case CS_ARCH_ARM:
this->m_modeBasicMIPS = cs_mode(0);
this->m_modeBasicX86 = cs_mode(0);
this->m_modeBasicPPC = cs_mode(0);
this->m_micoMode = false;
this->m_sparcV9Mode = false;
if (ImGui::RadioButton("ARM mode", this->m_modeBasicARM == CS_MODE_ARM))
this->m_modeBasicARM = CS_MODE_ARM;
ImGui::SameLine();
if (ImGui::RadioButton("Thumb mode", this->m_modeBasicARM == CS_MODE_THUMB))
this->m_modeBasicARM = CS_MODE_THUMB;
if (ImGui::RadioButton("Default mode", (this->m_modeExtraARM & (CS_MODE_MCLASS | CS_MODE_V8)) == 0))
this->m_modeExtraARM = cs_mode(0);
ImGui::SameLine();
if (ImGui::RadioButton("Cortex-M mode", (this->m_modeExtraARM & (CS_MODE_MCLASS | CS_MODE_V8)) == CS_MODE_MCLASS))
this->m_modeExtraARM = CS_MODE_MCLASS;
ImGui::SameLine();
if (ImGui::RadioButton("ARMv8 mode", (this->m_modeExtraARM & (CS_MODE_MCLASS | CS_MODE_V8)) == CS_MODE_V8))
this->m_modeExtraARM = CS_MODE_V8;
break;
case CS_ARCH_MIPS:
this->m_modeBasicARM = cs_mode(0);
this->m_modeExtraARM = cs_mode(0);
this->m_modeBasicX86 = cs_mode(0);
this->m_modeBasicPPC = cs_mode(0);
this->m_sparcV9Mode = false;
if (ImGui::RadioButton("MIPS32 mode", this->m_modeBasicMIPS == CS_MODE_MIPS32))
this->m_modeBasicMIPS = CS_MODE_MIPS32;
ImGui::SameLine();
if (ImGui::RadioButton("MIPS64 mode", this->m_modeBasicMIPS == CS_MODE_MIPS64))
this->m_modeBasicMIPS = CS_MODE_MIPS64;
ImGui::SameLine();
if (ImGui::RadioButton("MIPS32R6 mode", this->m_modeBasicMIPS == CS_MODE_MIPS32R6))
this->m_modeBasicMIPS = CS_MODE_MIPS32R6;
ImGui::Checkbox("Micro Mode", &this->m_micoMode);
break;
case CS_ARCH_X86:
this->m_modeBasicARM = cs_mode(0);
this->m_modeExtraARM = cs_mode(0);
this->m_modeBasicMIPS = cs_mode(0);
this->m_modeBasicPPC = cs_mode(0);
this->m_micoMode = false;
this->m_sparcV9Mode = false;
if (ImGui::RadioButton("16-bit mode", this->m_modeBasicX86 == CS_MODE_16))
this->m_modeBasicX86 = CS_MODE_16;
ImGui::SameLine();
if (ImGui::RadioButton("32-bit mode", this->m_modeBasicX86 == CS_MODE_32))
this->m_modeBasicX86 = CS_MODE_32;
ImGui::SameLine();
if (ImGui::RadioButton("64-bit mode", this->m_modeBasicX86 == CS_MODE_64))
this->m_modeBasicX86 = CS_MODE_64;
break;
case CS_ARCH_PPC:
this->m_modeBasicARM = cs_mode(0);
this->m_modeExtraARM = cs_mode(0);
this->m_modeBasicMIPS = cs_mode(0);
this->m_modeBasicX86 = cs_mode(0);
this->m_micoMode = false;
this->m_sparcV9Mode = false;
if (ImGui::RadioButton("32-bit mode", this->m_modeBasicPPC == CS_MODE_32))
this->m_modeBasicPPC = CS_MODE_32;
ImGui::SameLine();
if (ImGui::RadioButton("64-bit mode", this->m_modeBasicPPC == CS_MODE_64))
this->m_modeBasicPPC = CS_MODE_64;
break;
case CS_ARCH_SPARC:
this->m_modeBasicARM = cs_mode(0);
this->m_modeExtraARM = cs_mode(0);
this->m_modeBasicMIPS = cs_mode(0);
this->m_modeBasicX86 = cs_mode(0);
this->m_modeBasicPPC = cs_mode(0);
this->m_micoMode = false;
ImGui::Checkbox("Sparc V9 mode", &this->m_sparcV9Mode);
break;
case CS_ARCH_ARM64:
case CS_ARCH_SYSZ:
case CS_ARCH_XCORE:
case CS_ARCH_M68K:
case CS_ARCH_TMS320C64X:
case CS_ARCH_M680X:
case CS_ARCH_EVM:
this->m_modeBasicARM = cs_mode(0);
this->m_modeExtraARM = cs_mode(0);
this->m_modeBasicMIPS = cs_mode(0);
this->m_modeBasicX86 = cs_mode(0);
this->m_modeBasicPPC = cs_mode(0);
this->m_micoMode = false;
this->m_sparcV9Mode = false;
break;
}
ImGui::EndChild();
}
ImGui::NewLine();
if (ImGui::Button("Disassemble"))
this->m_shouldInvalidate = true;
ImGui::NewLine();
ImGui::Separator();
ImGui::NewLine();
if (ImGui::BeginChild("##scrolling")) {
if (ImGui::BeginTable("##disassembly", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody)) {
ImGui::TableSetupColumn("Address");
ImGui::TableSetupColumn("Offset");
ImGui::TableSetupColumn("Bytes");
ImGui::TableSetupColumn("Disassembly");
ImGuiListClipper clipper;
clipper.Begin(this->m_disassembly.size());
ImGui::TableHeadersRow();
while (clipper.Step()) {
for (u64 i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("0x%llx", this->m_disassembly[i].address);
ImGui::TableNextColumn();
ImGui::Text("0x%llx", this->m_disassembly[i].offset);
ImGui::TableNextColumn();
ImGui::TextUnformatted(this->m_disassembly[i].bytes.c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(this->m_disassembly[i].opcodeString.c_str());
}
}
clipper.End();
ImGui::EndTable();
}
}
ImGui::EndChild();
}
}
ImGui::End();
}
void ViewDisassembler::createMenu() {
if (ImGui::BeginMenu("View")) {
ImGui::MenuItem("Disassembler View", "", &this->m_windowOpen);
ImGui::EndMenu();
}
}
}

View File

@@ -6,11 +6,7 @@
#include <vector>
#ifdef __MINGW32__
#include <winsock.h>
#else
#include <arpa/inet.h>
#endif
#include "utils.hpp"
namespace hex {
@@ -27,7 +23,7 @@ namespace hex {
static void formatBigHexInt(auto dataArray, char *buffer, size_t bufferSize) {
for (int i = 0; i < dataArray.size(); i++)
snprintf(buffer + 8 * i, bufferSize - 8 * i, "%08X", htonl(dataArray[i]));
snprintf(buffer + 8 * i, bufferSize - 8 * i, "%08X", hex::changeEndianess(dataArray[i], std::endian::big));
}
void ViewHashes::createView() {

View File

@@ -32,6 +32,7 @@ namespace hex {
ImGui::BulletText("imgui_club by ocornut");
ImGui::BulletText("ImGui-Addons by gallickgunner");
ImGui::BulletText("ImGuiColorTextEdit by BalazsJako");
ImGui::BulletText("capstone by aquynh");
ImGui::NewLine();
ImGui::BulletText("GNU libmagic");
ImGui::BulletText("OpenSSL libcrypto");
@@ -78,6 +79,15 @@ namespace hex {
"#include \"mypattern.hexpat\""
);
DrawTitle("Pragma directives");
ImGui::TextWrapped(
"Pragma directives are used to give ImHex additional information about the code being read. Currently "
"the following directives are supported.");
DrawCodeSegment("pragma", 30,
"// Allow this file to be loaded as pattern when a file identified as application/x-executable gets loaded"
"#pragma MIME application/x-executable\n"
);
DrawTitle("Built-in types");
ImGui::TextWrapped(
"The following built-in types are available for use");
@@ -92,10 +102,13 @@ namespace hex {
DrawTitle("Variables and Arrays");
ImGui::TextWrapped(
"Normal variables as well as arrays are used to highlight and display values.");
DrawCodeSegment("vars arrays", 30,
"Normal variables as well as arrays are used to highlight and display values. "
"It is possible to create arrays within structs and unions that use the value of a previously "
"declared variable as size.");
DrawCodeSegment("vars arrays", 45,
"u32 variable;\n"
"s8 string[16];"
"s8 string[16];\n"
"u8 customSizedArray[variable];"
);
DrawTitle("Structs");
@@ -108,7 +121,7 @@ namespace hex {
" u8 version;\n"
" padding[4];\n"
" Flags flags;\n"
"}"
"};"
);
DrawTitle("Unions");
@@ -119,7 +132,16 @@ namespace hex {
"union Color {\n"
" u32 rgba;\n"
" Components components;\n"
"}"
"};"
);
DrawTitle("Pointers");
ImGui::TextWrapped(
"\"Another possible type of member in structs and unions are pointers. They are variables"
"whose value is used as an offset from the start of the file to locate the actual offset. "
"The leading type is treated as the data being pointed to and the trailing type as the size of the pointer.");
DrawCodeSegment("pointer", 55,
"Data *data : u16;"
);
DrawTitle("Bitfields");
@@ -131,7 +153,7 @@ namespace hex {
" r : 1;\n"
" w : 1;\n"
" x : 1;\n"
"}"
"};"
);
DrawTitle("Enum");
@@ -145,7 +167,7 @@ namespace hex {
" Windows = 0x10,\n"
" MacOSX,\n"
" Linux\n"
"}"
"};"
);
DrawTitle("Using declarations");

View File

@@ -70,9 +70,32 @@ namespace hex {
size_t dataSize = (this->m_dataProvider == nullptr || !this->m_dataProvider->isReadable()) ? 0x00 : this->m_dataProvider->getSize();
this->m_memoryEditor.DrawWindow("Hex Editor", this, dataSize);
this->m_memoryEditor.DrawWindow("Hex Editor", this, dataSize, dataSize == 0 ? 0x00 : this->m_dataProvider->getBaseAddress());
if (dataSize != 0x00) {
ImGui::Begin("Hex Editor");
ImGui::SameLine();
ImGui::Text("Page %d / %d", this->m_dataProvider->getCurrentPage() + 1, this->m_dataProvider->getPageCount());
ImGui::SameLine();
if (ImGui::ArrowButton("prevPage", ImGuiDir_Left)) {
this->m_dataProvider->setCurrentPage(this->m_dataProvider->getCurrentPage() - 1);
size_t dataPreviewStart = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
View::postEvent(Events::ByteSelected, &dataPreviewStart);
}
ImGui::SameLine();
if (ImGui::ArrowButton("nextPage", ImGuiDir_Right)) {
this->m_dataProvider->setCurrentPage(this->m_dataProvider->getCurrentPage() + 1);
size_t dataPreviewStart = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
View::postEvent(Events::ByteSelected, &dataPreviewStart);
}
ImGui::End();
this->drawSearchPopup();
this->drawGotoPopup();
}
@@ -578,8 +601,8 @@ R"(
if (ImGui::BeginTabItem("Begin")) {
ImGui::InputScalar("##nolabel", ImGuiDataType_U64, &this->m_gotoAddress, nullptr, nullptr, "%llx", ImGuiInputTextFlags_CharsHexadecimal);
if (this->m_gotoAddress >= this->m_dataProvider->getSize())
this->m_gotoAddress = this->m_dataProvider->getSize() - 1;
if (this->m_gotoAddress >= this->m_dataProvider->getActualSize())
this->m_gotoAddress = this->m_dataProvider->getActualSize() - 1;
newOffset = this->m_gotoAddress;
@@ -596,9 +619,9 @@ R"(
s64 currHighlightStart = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
newOffset = this->m_gotoAddress + currHighlightStart;
if (newOffset >= this->m_dataProvider->getSize()) {
newOffset = this->m_dataProvider->getSize() - 1;
this->m_gotoAddress = (this->m_dataProvider->getSize() - 1) - currHighlightStart;
if (newOffset >= this->m_dataProvider->getActualSize()) {
newOffset = this->m_dataProvider->getActualSize() - 1;
this->m_gotoAddress = (this->m_dataProvider->getActualSize() - 1) - currHighlightStart;
} else if (newOffset < 0) {
newOffset = 0;
this->m_gotoAddress = -currHighlightStart;
@@ -609,15 +632,16 @@ R"(
if (ImGui::BeginTabItem("End")) {
ImGui::InputScalar("##nolabel", ImGuiDataType_U64, &this->m_gotoAddress, nullptr, nullptr, "%llx", ImGuiInputTextFlags_CharsHexadecimal);
if (this->m_gotoAddress >= this->m_dataProvider->getSize())
this->m_gotoAddress = this->m_dataProvider->getSize() - 1;
if (this->m_gotoAddress >= this->m_dataProvider->getActualSize())
this->m_gotoAddress = this->m_dataProvider->getActualSize() - 1;
newOffset = (this->m_dataProvider->getSize() - 1) - this->m_gotoAddress;
newOffset = (this->m_dataProvider->getActualSize() - 1) - this->m_gotoAddress;
ImGui::EndTabItem();
}
if (ImGui::Button("Goto")) {
this->m_dataProvider->setCurrentPage(std::floor(newOffset / double(prv::Provider::PageSize)));
this->m_memoryEditor.GotoAddr = newOffset;
this->m_memoryEditor.DataPreviewAddr = newOffset;
this->m_memoryEditor.DataPreviewAddrEnd = newOffset;

View File

@@ -12,18 +12,20 @@
#include <magic.h>
#if defined(__EMX__) || defined (WIN32)
#define MAGIC_PATH_SEPARATOR ";"
#else
#define MAGIC_PATH_SEPARATOR ":"
#endif
namespace hex {
ViewInformation::ViewInformation(prv::Provider* &dataProvider) : View(), m_dataProvider(dataProvider) {
ViewInformation::ViewInformation(prv::Provider* &dataProvider)
: View(), m_dataProvider(dataProvider) {
View::subscribeEvent(Events::DataChanged, [this](const void*) {
this->m_shouldInvalidate = true;
this->m_dataValid = false;
this->m_highestBlockEntropy = 0;
this->m_blockEntropy.clear();
this->m_averageEntropy = 0;
this->m_blockSize = 0;
this->m_valueCounts.fill(0x00);
this->m_mimeType = "";
this->m_fileDescription = "";
this->m_analyzedRegion = { 0, 0 };
});
}
@@ -54,6 +56,8 @@ namespace hex {
if (this->m_dataProvider != nullptr && this->m_dataProvider->isReadable()) {
if (this->m_shouldInvalidate) {
this->m_analyzedRegion = { this->m_dataProvider->getBaseAddress(), this->m_dataProvider->getBaseAddress() + this->m_dataProvider->getSize() };
{
this->m_blockSize = std::ceil(this->m_dataProvider->getSize() / 2048.0F);
std::vector<u8> buffer(this->m_blockSize, 0x00);
@@ -95,12 +99,10 @@ namespace hex {
{
magic_t cookie = magic_open(MAGIC_NONE);
if (magic_load(cookie, magicFiles.c_str()) == -1)
goto skip_description;
this->m_fileDescription = magic_buffer(cookie, buffer.data(), buffer.size());
skip_description:
if (magic_load(cookie, magicFiles.c_str()) != -1)
this->m_fileDescription = magic_buffer(cookie, buffer.data(), buffer.size());
else
this->m_fileDescription = "";
magic_close(cookie);
}
@@ -108,12 +110,10 @@ namespace hex {
{
magic_t cookie = magic_open(MAGIC_MIME);
if (magic_load(cookie, magicFiles.c_str()) == -1)
goto skip_mime;
this->m_mimeType = magic_buffer(cookie, buffer.data(), buffer.size());
skip_mime:
if (magic_load(cookie, magicFiles.c_str()) != -1)
this->m_mimeType = magic_buffer(cookie, buffer.data(), buffer.size());
else
this->m_mimeType = "";
magic_close(cookie);
}
@@ -122,53 +122,67 @@ namespace hex {
this->m_shouldInvalidate = false;
this->m_dataValid = true;
}
}
ImGui::NewLine();
for (auto &[name, value] : this->m_dataProvider->getDataInformation()) {
ImGui::LabelText(name.c_str(), "%s", value.c_str());
}
if (ImGui::Button("Analyze current page"))
this->m_shouldInvalidate = true;
ImGui::NewLine();
ImGui::Separator();
ImGui::NewLine();
if (!this->m_fileDescription.empty()) {
ImGui::TextUnformatted("Description:");
ImGui::TextWrapped("%s", this->m_fileDescription.c_str());
if (this->m_dataValid) {
for (auto &[name, value] : this->m_dataProvider->getDataInformation()) {
ImGui::LabelText(name.c_str(), "%s", value.c_str());
}
ImGui::LabelText("Analyzed region", "0x%llx - 0x%llx", this->m_analyzedRegion.first, this->m_analyzedRegion.second);
ImGui::NewLine();
}
if (!this->m_mimeType.empty()) {
ImGui::TextUnformatted("MIME Type:");
ImGui::TextWrapped("%s", this->m_mimeType.c_str());
ImGui::Separator();
ImGui::NewLine();
}
ImGui::Separator();
ImGui::NewLine();
if (!this->m_fileDescription.empty()) {
ImGui::TextUnformatted("Description:");
ImGui::TextWrapped("%s", this->m_fileDescription.c_str());
ImGui::NewLine();
}
ImGui::Text("Byte Distribution");
ImGui::PlotHistogram("##nolabel", this->m_valueCounts.data(), 256, 0, nullptr, FLT_MAX, FLT_MAX, ImVec2(0, 100));
if (!this->m_mimeType.empty()) {
ImGui::TextUnformatted("MIME Type:");
ImGui::TextWrapped("%s", this->m_mimeType.c_str());
ImGui::NewLine();
}
ImGui::NewLine();
ImGui::Separator();
ImGui::NewLine();
ImGui::Text("Entropy");
ImGui::PlotLines("##nolabel", this->m_blockEntropy.data(), this->m_blockEntropy.size(), 0, nullptr, FLT_MAX, FLT_MAX, ImVec2(0, 100));
ImGui::NewLine();
ImGui::LabelText("Block size", "2048 blocks à %lu bytes", this->m_blockSize);
ImGui::LabelText("Average entropy", "%.8f", this->m_averageEntropy);
ImGui::LabelText("Highest entropy block", "%.8f", this->m_highestBlockEntropy);
if (this->m_averageEntropy > 0.83 && this->m_highestBlockEntropy > 0.9) {
ImGui::Separator();
ImGui::NewLine();
ImGui::TextColored(ImVec4(0.92F, 0.25F, 0.2F, 1.0F), "This data is most likely encrypted or compressed!");
ImGui::Text("Byte Distribution");
ImGui::PlotHistogram("##nolabel", this->m_valueCounts.data(), 256, 0, nullptr, FLT_MAX, FLT_MAX,ImVec2(0, 100));
ImGui::NewLine();
ImGui::Separator();
ImGui::NewLine();
ImGui::Text("Entropy");
ImGui::PlotLines("##nolabel", this->m_blockEntropy.data(), this->m_blockEntropy.size(), 0, nullptr, FLT_MAX, FLT_MAX, ImVec2(0, 100));
ImGui::NewLine();
ImGui::LabelText("Block size", "2048 blocks à %lu bytes", this->m_blockSize);
ImGui::LabelText("Average entropy", "%.8f", this->m_averageEntropy);
ImGui::LabelText("Highest entropy block", "%.8f", this->m_highestBlockEntropy);
if (this->m_averageEntropy > 0.83 && this->m_highestBlockEntropy > 0.9) {
ImGui::NewLine();
ImGui::TextColored(ImVec4(0.92F, 0.25F, 0.2F, 1.0F),"This data is most likely encrypted or compressed!");
}
}
}

View File

@@ -7,6 +7,8 @@
#include "lang/evaluator.hpp"
#include "utils.hpp"
#include <magic.h>
namespace hex {
static const TextEditor::LanguageDefinition& PatternLanguage() {
@@ -71,6 +73,67 @@ namespace hex {
this->m_textEditor.SetLanguageDefinition(PatternLanguage());
this->m_textEditor.SetShowWhitespaces(false);
View::subscribeEvent(Events::DataChanged, [this](const void* userData) {
lang::Preprocessor preprocessor;
std::string magicFiles;
std::error_code error;
for (const auto &entry : std::filesystem::directory_iterator("magic", error)) {
if (entry.is_regular_file() && entry.path().extension() == ".mgc")
magicFiles += entry.path().string() + MAGIC_PATH_SEPARATOR;
}
std::vector<u8> buffer(std::min(this->m_dataProvider->getSize(), size_t(0xFF'FFFF)), 0x00);
this->m_dataProvider->read(0, buffer.data(), buffer.size());
std::string mimeType;
magic_t cookie = magic_open(MAGIC_MIME_TYPE);
if (magic_load(cookie, magicFiles.c_str()) != -1)
mimeType = magic_buffer(cookie, buffer.data(), buffer.size());
magic_close(cookie);
bool foundCorrectType = false;
preprocessor.addPragmaHandler("MIME", [&mimeType, &foundCorrectType](std::string value) {
if (value == mimeType) {
foundCorrectType = true;
return true;
}
return !std::all_of(value.begin(), value.end(), isspace) && !value.ends_with('\n') && !value.ends_with('\r');
});
preprocessor.addDefaultPragramHandlers();
for (auto &entry : std::filesystem::directory_iterator("patterns")) {
if (!entry.is_regular_file())
continue;
FILE *file = fopen(entry.path().string().c_str(), "r");
if (file == nullptr)
continue;
fseek(file, 0, SEEK_END);
size_t size = ftell(file);
rewind(file);
std::vector<char> buffer( size + 1, 0x00);
fread(buffer.data(), 1, size, file);
fclose(file);
preprocessor.preprocess(buffer.data());
if (foundCorrectType) {
this->m_possiblePatternFile = entry.path();
ImGui::OpenPopup("Accept Pattern");
ImGui::SetNextWindowSize(ImVec2(200, 100));
break;
}
}
});
}
ViewPattern::~ViewPattern() {
@@ -107,32 +170,54 @@ namespace hex {
ImGui::End();
if (this->m_fileBrowser.showFileDialog("Open Hex Pattern", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(0, 0), ".hexpat")) {
this->loadPatternFile(this->m_fileBrowser.selected_path);
}
FILE *file = fopen(this->m_fileBrowser.selected_path.c_str(), "rb");
if (ImGui::BeginPopupModal("Accept Pattern", nullptr, ImGuiWindowFlags_NoResize)) {
ImGui::TextUnformatted("A pattern compatible with this data type has been found:");
ImGui::Text("%ls", this->m_possiblePatternFile.filename().c_str());
ImGui::NewLine();
ImGui::Text("Do you want to load it?");
ImGui::NewLine();
if (file != nullptr) {
char *buffer;
fseek(file, 0, SEEK_END);
size_t size = ftell(file);
rewind(file);
buffer = new char[size + 1];
fread(buffer, size, 1, file);
buffer[size] = 0x00;
fclose(file);
this->parsePattern(buffer);
this->m_textEditor.SetText(buffer);
delete[] buffer;
if (ImGui::Button("Yes", ImVec2(40, 20))) {
this->loadPatternFile(this->m_possiblePatternFile.string());
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("No", ImVec2(40, 20))) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
void ViewPattern::loadPatternFile(std::string path) {
FILE *file = fopen(path.c_str(), "rb");
if (file != nullptr) {
char *buffer;
fseek(file, 0, SEEK_END);
size_t size = ftell(file);
rewind(file);
buffer = new char[size + 1];
fread(buffer, size, 1, file);
buffer[size] = 0x00;
fclose(file);
this->parsePattern(buffer);
this->m_textEditor.SetText(buffer);
delete[] buffer;
}
}
void ViewPattern::clearPatternData() {
for (auto &data : this->m_patternData)
delete data;
@@ -153,24 +238,38 @@ namespace hex {
}
void ViewPattern::parsePattern(char *buffer) {
hex::lang::Preprocessor preprocessor;
hex::lang::Lexer lexer;
hex::lang::Parser parser;
hex::lang::Validator validator;
hex::lang::Evaluator evaluator;
this->clearPatternData();
this->postEvent(Events::PatternChanged);
hex::lang::Preprocessor preprocessor;
std::endian dataEndianess = std::endian::native;
preprocessor.addPragmaHandler("endian", [&dataEndianess](std::string value) {
if (value == "big") {
dataEndianess = std::endian::big;
return true;
} else if (value == "little") {
dataEndianess = std::endian::little;
return true;
} else if (value == "native") {
dataEndianess = std::endian::native;
return true;
} else
return false;
});
preprocessor.addDefaultPragramHandlers();
auto [preprocessingResult, preprocesedCode] = preprocessor.preprocess(buffer);
if (preprocessingResult.failed())
return;
hex::lang::Lexer lexer;
auto [lexResult, tokens] = lexer.lex(preprocesedCode);
if (lexResult.failed()) {
return;
}
hex::lang::Parser parser;
auto [parseResult, ast] = parser.parse(tokens);
if (parseResult.failed()) {
return;
@@ -178,11 +277,13 @@ namespace hex {
hex::ScopeExit deleteAst([&ast]{ for(auto &node : ast) delete node; });
hex::lang::Validator validator;
auto validatorResult = validator.validate(ast);
if (!validatorResult) {
return;
}
hex::lang::Evaluator evaluator(this->m_dataProvider, dataEndianess);
auto [evaluateResult, patternData] = evaluator.evaluate(ast);
if (evaluateResult.failed()) {
return;

View File

@@ -18,7 +18,7 @@ namespace hex {
}
static bool beginPatternDataTable(prv::Provider* &provider, const std::vector<lang::PatternData*> &patterns, std::vector<lang::PatternData*> &sortedPatterns) {
if (ImGui::BeginTable("##patterndatatable", 6, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg)) {
if (ImGui::BeginTable("##patterndatatable", 6, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody)) {
ImGui::TableSetupColumn("Color", 0, -1, ImGui::GetID("color"));
ImGui::TableSetupColumn("Name", 0, -1, ImGui::GetID("name"));
ImGui::TableSetupColumn("Offset", 0, -1, ImGui::GetID("offset"));
@@ -60,13 +60,8 @@ namespace hex {
if (this->m_sortedPatternData.size() > 0) {
ImGui::TableHeadersRow();
u32 rowCount = 0;
for (auto &patternData : this->m_sortedPatternData) {
for (auto &patternData : this->m_sortedPatternData)
patternData->createEntry(this->m_dataProvider);
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,
((rowCount % 2) == 0) ? 0xFF101010 : 0xFF303030);
rowCount++;
}
}

View File

@@ -8,7 +8,7 @@ namespace hex {
ViewStrings::ViewStrings(prv::Provider* &dataProvider) : View(), m_dataProvider(dataProvider) {
View::subscribeEvent(Events::DataChanged, [this](const void*){
this->m_shouldInvalidate = true;
this->m_foundStrings.clear();
});
this->m_filter = new char[0xFFFF];
@@ -64,6 +64,8 @@ namespace hex {
this->m_shouldInvalidate = true;
ImGui::InputText("Filter", this->m_filter, 0xFFFF);
if (ImGui::Button("Extract"))
this->m_shouldInvalidate = true;
ImGui::Separator();
ImGui::NewLine();
@@ -72,7 +74,7 @@ namespace hex {
if (ImGui::BeginTable("##strings", 3,
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable |
ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg)) {
ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody)) {
ImGui::TableSetupColumn("Offset", 0, -1, ImGui::GetID("offset"));
ImGui::TableSetupColumn("Size", 0, -1, ImGui::GetID("size"));
ImGui::TableSetupColumn("String", 0, -1, ImGui::GetID("string"));
@@ -111,7 +113,6 @@ namespace hex {
clipper.Begin(this->m_foundStrings.size());
while (clipper.Step()) {
u32 rowCount = clipper.DisplayStart;
for (u64 i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
auto &foundString = this->m_foundStrings[i];
@@ -126,9 +127,6 @@ namespace hex {
ImGui::Text("0x%04lx", foundString.size);
ImGui::TableNextColumn();
ImGui::Text("%s", foundString.string.c_str());
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,
((rowCount % 2) == 0) ? 0xFF101010 : 0xFF303030);
rowCount++;
}
}
clipper.End();