Autogenerated documentation with DeepWiki
Minimalistic and lightweight shell-based hex editor. It’s designed to have a low memory footprint, making it usable on very low-end devices.
- Print file content in various formats.
- Write/overwrite data into the file.
- Undo writes until committed.
- Enumerate (ASCII) strings.
- Search strings or binary data.
- Execute template files using a custom language (bhe), located in the
templates/
subdirectory. - Disassemble opcodes (using Capstone).
- Assemble opcodes (using Keystone).
Just run bhex <file>
to start the shell.
Supported flags:
Usage: bhex [ options ] inputfile
-h --help Print help
-w --write Open the file in write mode
-b --backup Backup original file in "filename.bk"
-2 --no_warning Disable warnings
-n --no_history Do not save command history
-c "c1; c2; ..." Execute the commands given as argument and exit
-s --script Script mode (commands from raw stdin)
command history is saved in "$HOME/.bhex_history", it can be changed setting BHEX_HISTORY_FILE environment variable
The project can be compiled using cmake. Without Captone and Keystone, it has no runtime dependencies (apart from libc), so it should be quite straightforward:
$ mkdir build
$ cd build
$ cmake ..
$ make
To enable the disassembler command, use "-DENABLE_CAPSTONE=on".
To enable the assembler command, use "-DENABLE_KEYSTONE=on".
To enable an ASAN build, use "-DASAN=on -DCMAKE_BUILD_TYPE=Debug".
To enable tests, use "-DENABLE_TESTS=on".
Every command has the following structure:
$ command_name/mod1/mod2/mod3/... arg1 arg2 ...
where the modifiers (e.g., mod1) are optional parameters of the command.
The documentation for each command can be accessed by typing "?" after the name of the command.
If you type "help" (or "h"), you get the list of commands:
[0x0000000] $ h
Available commands:
help [h]
interactive [int]
info [i]
entropy [e]
search [src]
crc [cr]
strings [str]
template [t]
seek [s]
print [p]
diff [df]
export [ex]
import [im]
assemble [as]
disas [ds]
write [w]
delete [d]
undo [u]
commit [c]
[0x0000000] $ i?
info: prints information about the opened binary
[0x0000000] $ e?
entropy: display an entropy graph
e <len> <rows>
len: number of bytes to include starting from the current offset (if omitted or '-', the whole file)
rows: number of points in the graph (if omitted, defaults to 32)
[0x0000000] $ e - 8
[ 00000000 - 000277c8 ] (5.980) ---------------------------------+
[ 000277c8 - 0004ef90 ] (6.398) -----------------------------------+
[ 0004ef90 - 00076758 ] (6.492) ------------------------------------+
[ 00076758 - 0009df20 ] (4.491) -------------------------+
[ 0009df20 - 000c56e8 ] (6.441) ------------------------------------+
[ 000c56e8 - 000eceb0 ] (6.477) ------------------------------------+
[ 000eceb0 - 00114678 ] (6.495) ------------------------------------+
[ 00114678 - 0013be40 ] (4.388) ------------------------+
Start an interactive session.
[0x0000000] $ src?
search: search a string or a sequence of bytes in the file
src[/{x, s}/sk/p] <what>
x: data is an hex string
s: data is a string (default)
sk: seek to first match
c: print context
data: either a string or an hex string
[0x0000000] $ str?
enumerate the strings in the file (i.e., sequences of printable ascii characters)
str[/n] [<num>]
n: look for null-terminated strings
num: minimum length (default: 3)
[0x0000000] $ t?
template: parse the file at current offset using a 'bhe' template file
t[/l] <name or file>
l: list available templates and structs
name: the name of the pre-loaded template/struct to use, or a path to a template file, or a filter if in list mode
[0x0000000] $ t/l
Available templates:
tar
pe
elf
Available template structs:
tar.TarHeader
pe.IMAGE_NT_HEADERS
pe.IMAGE_OPTIONAL_HEADER32
pe.DATA_DIRECTORY_ARRAY
pe.IMAGE_DATA_DIRECTORY
pe.IMAGE_FILE_HEADER
pe.IMAGE_OPTIONAL_HEADER64
pe.IMAGE_SECTION_HEADER
pe.IMAGE_DOS_HEADER
elf.Elf64_Shdr
elf.Elf64_Phdr
elf.Elf32_Phdr
elf.Elf_Ehdr
elf.ElfIdent
elf.Elf32_Shdr
[0x0000000] $ s?
seek: change current offset
s[/{+,-}] <off>
+: sum 'off' to current offset (wrap if greater than filesize)
-: subtract 'off' to current offset (wrap if lower than zero)
off: can be either a number or the character '-'.
In the latter case seek to the offset before the last seek.
NOTE: if called without arguments, print current offset
[0x0000000] $ crc?
import: calculate the CRC <name> at current offset + <off>
crc[/l] <name> [<size> <off>]
l: list the supported crc names
name: name of the CRC (or a partial name)
size: number of bytes to include in the crc (if omitted or zero, import the whole file starting from current offset)
offset: starting offset of the imported file (if omitted, import from current offset)
[0x0000000] $ as?
assemble: assemble code and write it at current offset
as[/l/i/s] <arch> "<code>"
l: list supported architectures
i: insert instead of overwrite
s: seek to the end of the write
arch: the architecture to use
code: assembly code string (e.g., "inc eax; inc ecx; ret")
[0x0000000] $ ds?
disas: disassemble code at current offset
ds[/l] <arch> [<nbytes>]
l: list supported architectures
arch: the architecture to use
nbytes: the number of opcodes to disassemble, default value: 8
[0x0000000] $ p?
print: display the data at current offset in various formats
p[/{x,w,d,q,a,C}/{le,be}/r/W/{+,-}] <nelements>
x: hex output (default)
w: words
d: dwords
q: qwords
a: as ascii
C: as C buffer
le: little-endian (default)
be: big-endian
r: raw mode (no ascii, no header and no addresses)
W: wide mode (print 32 bytes per line)
+: seek forward after printing
-: seek backwards after printing
nelements: the number of elements to display
(default: enough to display 256 bytes, if '-' the whole file)
[0x0000000] $ df?
diff: prints the differences with another file
df[/p] <file>
p: print different bytes
file: path to the file to compare
[0x0000000] $ ex?
export: write <size> bytes of the file starting from current offset to <ofile>
ex <ofile> <size>
ofile: output file
size: number of bytes to export
[0x0000000] $ im?
import: import the content of <file> at current offset
im[/{ovw,i}] <file> [<size> <offset>]
i: insert in current file (default)
ovw: overwrite current file
file: input file
size: number of bytes to import (if omitted or zero, import the whole file)
offset: starting offset of the imported file (if omitted, import from offset 0)
[0x0000000] $ w?
write: write data at current offset
w[{s,x,b,w,d,q}/{le,be}/u/i] <data>
s: string input (default)
x: hex input
b: byte
w: word
d: dword
q: qword
le: little-endian (default)
be: big-endian
u: unsigned
i: insert
data: the data to write. The format depends on the type of
write. Here there are some examples:
w/x "00 01 02 03"
w/s "a string"
w/q/be 0x1234
[0x0000000] $ d?
delete: delete bytes at current offset
d <len>
[0x0000000] $ u?
undo the last write
[0x0000000] $ c?
commit: commit all writes to file
c[/l]
l: list uncommited changes