Hexalyzer is an app for inspecting and modifying firmware files and binary data. Any hex or binary encoded file can technically be opened. Recommended for embedded firmware analysis.
Hexalyzer project contains two main parts:
- A modern GUI application that can display and edit contents of HEX and BIN files.
- A standalone Intel HEX parsing library.
Use cargo packager to build an installer for your platform.
Go into hexalyzer directory cd hexalyzer and run:
cargo build --releasecargo packager --release
This will create .exe installer for Windows, and .dmg installer for
macOS. Linux was not tested but should work too.
To build the CLI tool, run
cargo build -p intelhexlib --features cli --release
When the tag is available, the installers and CLI will be attached.
I had bunch of issues with generating Windows installer and the
final executable correctly. Before building, you need to run
cargo add --build winresource which helps setup the icon on the
executable.
In addition, if you want to install the app in certain folders, e.g.,
C:\Program Files\Hexalyzer, you need to run the installer with
admin rights, the same goes for uninstalling.
-
Open a File: Use the
File → Open File...menu or drag and drop a.hexor.binfile into the main window. -
Navigate: Use the scroll area to browse the data. The center panel displays the hex values and their ASCII equivalents side-by-side. Use side panel to jump to a specific hex address or search for a byte / ASCII value(s).
-
Edit: Click on a byte to edit its value. Changes are tracked and can be reverted if needed.
-
Inspect: Use the side panel to see how the selected bytes are interpreted as different data types (integers, floats, etc.). Multibyte selection is possible!
The top menubar provides access to the core file management and data transformation tools:
Open file...: Browse your system to load a file into a new tab.Export file...: Save your current session to a new file.Close file: Close the current tab.
Relocate...: Relocate the current file to a new start address.Merge...: Merge selected file into the current one. Before merging, new start addresses can be specified for both files.Restore byte changes: Discard all changes made to the current file.
Switch between displaying 16 or 32 bytes per row.
Displays version information and credits for the Hexalyzer project.
The core of Hexalyzer is powered by a standalone Intel HEX parsing library intelhexlib. It is designed to
handle memory-sparse firmware files using a BTreeMap buffer.
-
Sparse Data Support: Uses
BTreeMap<usize, Vec<u8>>to store data, meaning files with large gaps between memory segments don't consume unnecessary RAM. Performance remains optimized by storing contiguous chunks. The key represents the starting address, and theVec<u8>contains the payload which ensures fast lookups. -
Data editing: Allows updating single bytes, byte ranges, supports relocation to a new start address, merging, etc.
-
Flexible API: Allows for easy parsing and update of hex data as well as straightforward integration into other projects.
use hexalyzer::intelhex::IntelHex;
use std::path::PathBuf;
fn main() {
// Load and parse a file
let path = PathBuf::from("firmware.hex");
if let Ok(mut ih) = IntelHex::from_hex(&path) {
println!("Loaded {} bytes from {:?}", ih.size, ih.filepath);
// Access data at a specific address
let address: usize = 0x0800_0000;
if let Some(byte) = ih.get_byte(address) {
println!("Byte at {:X}: {:02X}", address, byte);
}
// Update data at a specific address
let new_value = 0x0F;
let res = ih.update_byte(address, new_value);
if res.is_ok() {
println!("Updated byte at {:X} to: {:02X}", address, new_value);
} else {
println!("Error during update: {:?}", res.unwrap_err().to_string())
}
// Iterate over all bytes, ignoring address gaps.
// Since it uses a BTreeMap, keys are always sorted by address.
// To iterate over contiguous chunks, use ih.iter() instead.
for (addr, byte) in ih.bytes().take(10) {
println!("{:X}: {:02X}", addr, byte);
}
}
}A CLI tool hexcli is also available for parsing and editing Intel HEX files.
Its functionality includes:
- Getting info about a file.
- Relocating the file to a new start address.
- Converting a file to between BIN and HEX formats.
- Merging multiple files into a single one (mixing BIN and HEX files is allowed).
----------------------------------------------------------------
| Intel HEX Utility | v0.2.0 - Copyright (c) 2026 Ihar Hlukhau |
----------------------------------------------------------------
Usage:
hexcli info <input>
hexcli relocate <input> <output> [options]
hexcli convert <input> <output> [options]
hexcli merge <output> <input1>[:addr] ... <inputN>[:addr]
Options:
--address <val> Base address for relocate / convert from BIN to HEX
--gap-fill <val> Byte to fill gaps when converting / merging to BIN (default: 0xFF)
Examples:
hexcli info firmware.hex
hexcli relocate firmware.hex firmware_shifted.hex --address 0x1000
hexcli convert firmware.hex firmware.bin --gap-fill 0x00
hexcli merge final.hex firmware1.hex firmware2.bin:0xFF00
v0.1.0 (2026-01-14) - Initial Release
v0.2.0 (2026-01-30) - Release with added usability features and improved performance
- Per-frame allocations in the hex grid
-
Issue: app creates 16/32
Buttons + 16/32Labels per row; each byte formats strings (format!("{:02X}")); search, edits, etc. copy data around. -
Impact: hundreds of widgets and heap allocations per frame → high CPU pressure.
-
Potential fix: render whole row as a single galley (
LayoutJob) for hex and another for ASCII; detect hovered/selected cell via math on mouse position instead of individual widgets.
- Virtual scroll over (potentially huge) sparse ranges
-
Issue: hex files can have address gaps, these gaps are displayed as empty rows.
-
Impact: although it is used in some other hex viewer apps, it is not ideal for UX.
-
Fix: compress gaps into a separator. The problem is that jump/search/etc offset calculations have to be adjusted accordingly.
- Tabs are hacky to say the least...
- UI tightly couples rendering and model details
-
HexSession owns data, selection, editing, search, and paints per-byte widgets directly. Harder to unit test, refactor and optimize.
-
Possible solution: introduce a ViewModel layer: compute a lightweight "visible page" (bytes, ascii, selection masks) separate from painting. The painter consumes this without hitting the data layer repeatedly.
- Synchronous tasks on the main thread
-
File load/save and potentially large searches run on the UI thread without the possibility to cancel.
-
Possible solution: job system with background workers; add cancel and progress.
- Support Copy, Undo, Redo, etc.
- Support ELF format
- Add timestamp (time since epoch) type in the data inspector
- Saving an entire app state / session
