ImHex
Platform | Windows, Linux, macOS, online |
---|---|
Release date | 2020/11/12 |
Homepage | Homepage |
Download | Download links on the homepage |
Games | None |
ImHex is a powerful hex editor with many additional tools built it.
In addition to editing binary files, it features a powerful pattern language, which allows you to mark up parts of the file, to help you visualise the structure of the file. Particularly useful when trying to understand an undocumented file format.
It also has many additional features built-in including data visualization, a graphing calculator, LLVM demangler, diffing and disassemblers for 18 different architectures.
It's still a work in progress, and has some quirks, but it is under active development. Your mileage might vary
Platform and license
It's written in c++ and is completely free and open source under the GPLv2.
Documentation
Pattern Language documentation
Disassembler architectures
- ARM
- AArch64
- MIPS
- Intel x86
- PowerPC
- SPARC
- SystemZ
- XCore
- Motorola 68K
- TMS320C64x
- M680x
- Ethereum Virtual Machine
- MOS Technology 65xx
- WebAssembly
- Berkeley Packet Filter
- RISC-V
- SuperH
- Tricore
Example pattern script
This script which can be run in ImHex, marks up the individual files in a DAT Format (Fury of the Furries) file, and decompresses each into a separate file within a virtual file system in the ImHex editor.
/*! Deconstruct a Fury of the Furries DAT archive Running this pattern will extract and decompress the archive into the Virtual Filesystem */ #pragma endian little #pragma pattern_limit 2000000 import std.string; import std.core; import std.io; import hex.core; import type.base; std::mem::Section currentSection; s32 currentOffset = 0; // Is the archived file compressed enum Compressed : u8 { Yes, No }; fn addSpace() { u8 space[18] @ 0 in currentSection; for (u8 i = 0, i < 18, i = i + 1) { space[i] = 0x20; } }; // Copy a run length section from earlier in the compressed file fn outputRunLengthCopy(auto length, auto offset) { while (length > 0) { std::mem::copy_section_to_section(currentSection, offset + 18, currentSection, currentOffset + 18, 1); offset = offset + 1; currentOffset = currentOffset + 1; length = length - 1; } }; // A pair of bytes representing a run length struct CompressionPair { u16 shadowPair [[hidden, no_unique_address]]; u8 length = ((shadowPair >> 8) & 0x0f) + 3; u16 offset = ((shadowPair >> 12) << 8) + (shadowPair & 0xff) + 18; s32 fullOffset = offset + (currentOffset & 0xfffff000); if (fullOffset >= currentOffset) { fullOffset = fullOffset - 4096; } str comment = std::string::to_string(length) + " bytes @ " + type::impl::format_number(fullOffset, "0x{:02X}"); u16 pair [[comment(comment)]]; outputRunLengthCopy(length, fullOffset); } [[inline]]; // A single byte literal struct CompressionLiteral { u8 byte; } [[inline]]; // Either a single byte literal, or a run-length pair struct CompressionItem { u8 index = std::core::array_index(); u8 flag = (parent.flags >> index) & 0x01; if (flag) { CompressionLiteral byte; std::mem::copy_value_to_section(byte, currentSection, currentOffset + 18); currentOffset = currentOffset + 1; } else { CompressionPair pair; } if ($ >= parent.parent.parent.end) { break; } } [[inline]]; // A set up up to 8 compression items controlled by a flag bitfield struct CompressionBlock { u8 flags [[color("008800")]]; CompressionItem parts[8] [[inline]]; }; // A compressed data file struct CompressedData { CompressionBlock data[while($ < parent.end)]; } [[inline]]; // A single file within the archive struct File { char name[13] [[color("00ff00")]]; u32 uncompressedSize [[color("00ee00")]]; u32 compressedSize [[color("00dd00")]]; // create decompression section Compressed isCompressed [[color("00cc00")]]; currentSection = std::mem::create_section(name); std::mem::set_section_size(currentSection, uncompressedSize + 18); addSpace(); u8 buffer[uncompressedSize] @ 18 in currentSection; currentOffset = 0; u32 end = $ + compressedSize; if (isCompressed == 0) { CompressedData compressedData [[color("000000")]]; } else { u8 data[compressedSize] [[color("000000")]]; std::mem::copy_value_to_section(data, currentSection, 18); } str fileName = std::string::to_string(name); hex::core::add_virtual_file(fileName, buffer); std::mem::delete_section(currentSection); } [[name(name)]]; // A dat archive struct Archive { u16 fileCount [[color("ff0000"), name("Number of files")]]; File files[fileCount] [[inline]]; } [[inline]]; Archive archive @ 0x00;