Skip to content

borzacchiello/bhex

Repository files navigation

BHex

Tests action Ask DeepWiki

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.

Features

  • 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

Compilation

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".

Command Format

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.

Commands

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]

Info

[0x0000000] $ i?

info: prints information about the opened binary

Entropy

[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) ------------------------+

Interactive

Start an interactive session.

Search

[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

Strings

[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)

Template

[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

Seek

[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

Crc

[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)

Assemble

[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")

Disassemble

[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

Print

[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)

Diff

[0x0000000] $ df?

diff: prints the differences with another file

  df[/p] <file>
     p:  print different bytes

  file: path to the file to compare

Export

[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

Import

[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)

Write

[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

Delete

[0x0000000] $ d?

delete: delete bytes at current offset

  d <len>

Undo

[0x0000000] $ u?
undo the last write

Commit

[0x0000000] $ c?

commit: commit all writes to file

  c[/l]
     l: list uncommited changes

About

A lightweight and portable shell-based binary hex editor

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published