Hexalyzer is an app for inspecting and modifying firmware files and binary data. Any hex or binary encoded file can technically be opened.
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.
When the tag is available, the installers 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.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. It is designed to handle memory-sparse firmware files using a BTreeMap buffer.
-
Sparse Data Support: Uses
BTreeMap<usize, u8>to store data, meaning files with large gaps between memory segments don't consume unnecessary RAM. -
Data editing: Allows updating single bytes, byte slices, and supports relocation to a new start address.
-
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 contiguous segments
// Since it uses a BTreeMap, keys are always sorted by address
for (addr, byte) in ih.iter().take(10) {
println!("{:X}: {:02X}", addr, byte);
}
}
}v0.1.0 (2026-01-09) - Initial Release
- 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.
- BTreeMap lookups in a tight render loop
-
Issue:
ui_centralpanel.rsrepeatedly callsih.get_byte(addr)per cell (BTreeMap::gethas O(log n) time complexity). -
Impact: multiplied across all visible bytes each frame → wastes CPU.
-
Fix: prefetch visible window once per frame into a small
Vec<Option<u8>>and index into it.
- 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...
- Data representated as
BTreeMap<usize, u8>
-
Memory-heavy and slow for contiguous data. Typical firmware is largely contiguous; a byte-per-node map scales poorly beyond ~100–300k bytes.
-
Possible solution: represent data as contiguous segments
BTreeMap<usize, Vec<u8>>, where key is the offset (aka start address of the contiguous segment) and value is the data vector.
- 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.
- Make CLI for
intelhexlib - Support Copy, Undo, Redo, etc.
- Support ELF format
- Show the current address of the selected byte
- Add timestamp (time since epoch) type in the data inspector
- Saving an entire app state / session?
