Skip to content

A lightweight and portable shell-based binary hex editor

License

Notifications You must be signed in to change notification settings

borzacchiello/bhex

Repository files navigation

BHex

 ____  _    _
|  _ \| |  | |
| |_) | |__| | _____  __
|  _ <|  __  |/ _ \ \/ /
| |_) | |  | |  __/>  <
|____/|_|  |_|\___/_/\_\

Minimalistic and lightweight shell-based hex editor.

It is designed to have a low memory footprint. This makes the program usable on very low-end devices.

Supported features:

  • print file content in various format
  • 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 (look in the templates subdirectory to see some example)
  • 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 strightforward:

$ 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 of a each command can be accessed 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]
    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] <data>
     x:  data is an hex string
     s:  data is a string (default)
     sk: seek to first match
     p:  print blocks info

  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/ls] <name or file>
     l:  list available templates
     ls: list available structs

  name: the name of the pre-loaded template/struct to use, of a path to a template file

[0x0000000] $ t/l/ls

Available templates:
  elf
  tar

Available template structs:
  elf.Elf64_Shdr
  elf.Elf64_Phdr
  elf.Elf32_Phdr
  elf.Elf_Ehdr
  elf.ElfIdent
  elf.Elf32_Shdr
  tar.TarHeader

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

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}/{le,be}/r/{+,-}] <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)
     +:  seek forward after printing
     -:  seek backwards after printing

  nelements: the number of elements to display
  (default: enough to display 256 bytes)

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 all the writes to file

About

A lightweight and portable shell-based binary hex editor

Resources

License

Stars

Watchers

Forks

Packages

No packages published