Skip to content

Instantly share code, notes, and snippets.

@TheAMM
Created December 8, 2021 10:42
Show Gist options
  • Save TheAMM/ec53feb26f0b4181723021ed734c89b3 to your computer and use it in GitHub Desktop.
Save TheAMM/ec53feb26f0b4181723021ed734c89b3 to your computer and use it in GitHub Desktop.
Cute hex dumper in Python
def dump_hex(binary, width=16, group_width=8, address_offset=0, print_func=print):
groups_size = int(width / group_width + 0.5)
if isinstance(binary, (bytes, bytearray, memoryview)):
binary_iterator = (binary[i:i+width] for i in range(0, len(binary), width))
else:
# Assume iterator, receive arbitrary-sized byte chunks and reassemble them
def _iter_wrapper():
extra = b''
for chunk in binary:
if extra:
chunk, extra = extra + chunk, b''
remain = len(chunk) % width
if remain:
chunk, extra = chunk[:-remain], chunk[-remain:]
yield from (chunk[i:i+width] for i in range(0, len(chunk), width))
if extra:
yield extra
binary_iterator = _iter_wrapper()
lines = []
address = address_offset
for i, row_bytes in enumerate(binary_iterator):
byte_groups = [row_bytes[i:i+group_width] for i in range(0, width, group_width)]
hex_bits = ' '.join(
' '.join(f"{b:02X}" for b in g).ljust(group_width * 3 - 1)
for g in byte_groups
)
char_bits = ' '.join(
''.join(
chr(b) if 33 <= b <= 126 else '.'
for b in g
).ljust(group_width)
for g in byte_groups
)
line = f"{i * width + address_offset:08X}: {hex_bits} {char_bits}"
print_func(line)
>>> from hexdump import hexdump
>>> hexdump(b'hello world')
00000000: 68 65 6C 6C 6F 20 77 6F  72 6C 64                 hello.wo rld

>>> hexdump(open('/dev/urandom', 'rb').read(256), width=32)
00000000: 43 E4 F6 C2 70 59 52 B7  6B 1F D1 70 33 FD 5A CA  47 93 BD 1F 9E 35 48 C7  1B AD 98 0C F9 36 D1 78  C...pYR. k..p3.Z. G....5H. .....6.x
00000020: B4 59 EE 9B 74 45 F0 49  14 1C 82 3E FC B9 9B C7  45 75 D4 8C 75 AA 1A C7  E3 4D 65 7E B6 95 BE 84  .Y..tE.I ...>.... Eu..u... .Me~....
00000040: 46 E9 97 9E 72 1A 38 6B  13 50 28 D2 A6 1D B6 0B  F1 6C B1 AD 7D 56 D7 29  B4 EC 75 0F 4D B2 3A F1  F...r.8k .P(..... .l..}V.) ..u.M.:.
00000060: 05 28 D5 97 A3 0E F8 F7  3C 37 1B 65 28 35 2D 63  31 9C 36 21 B6 A4 CD 48  50 3D FA 1A 4C 5E 19 8D  .(...... <7.e(5-c 1.6!...H P=..L^..
00000080: 67 5F B6 95 E1 5D BA FA  B9 4B 02 E7 5A 89 DD 30  5C 79 7E A3 83 B3 5F 1A  F0 4C 92 11 6E F1 BE D1  g_...].. .K..Z..0 \y~..._. .L..n...
000000A0: EA ED 5A 7F 69 E0 61 5A  DE 9D C9 E4 49 C9 51 84  35 BE 25 22 2F 30 F1 FF  7C 99 CF 26 89 76 D2 83  ..Z.i.aZ ....I.Q. 5.%"/0.. |..&.v..
000000C0: 02 E9 78 D9 0D BB 9C 1C  BB A0 34 1F E2 E1 C3 1A  76 32 04 FB BC FA D2 B2  84 B7 77 CD 23 DE CC 48  ..x..... ..4..... v2...... ..w.#..H
000000E0: AD 3F 70 0A 4B 8F 92 27  68 40 2C 80 5C A7 A4 8C  A4 75 6D 43 05 65 D6 3D  C5 EB B9 F7 B2 5C 7A C9  .?p.K..' h@,.\... .umC.e.= .....\z.

>>> hexdump(open('/dev/urandom', 'rb').read(55))
00000000: 49 8C 53 1D 7C CD 03 A0  EF 1B 22 9E 61 38 7B DB  I.S.|... ..".a8{.
00000010: 36 96 D9 31 29 34 00 35  D9 06 E8 07 D2 98 FC BD  6..1)4.5 ........
00000020: F1 99 43 C4 BB CD B5 A8  2E 78 51 0E 8B 86 07 22  ..C..... .xQ...."
00000030: 1C 28 A3 F5 EF AE 5B                              .(....[

>>> import time, random
>>> def some_gen():
...   with open('/dev/urandom', 'rb') as in_file:
...     while True:
...       yield in_file.read(random.randrange(5, 32))
...       time.sleep(0.25)
...

>>> hexdump(some_gen(), width=24, group_width=4)
00000000: 2C 69 D4 96  9B 5A ED 5B  CB 35 63 BA  54 86 BA 51  C5 A5 B7 0D  10 35 85 15  ,i.. .Z.[ .5c. T..Q .... .5..
00000018: 3A AE 59 B6  ED 5F D5 7C  FE 15 00 34  52 50 F9 19  56 41 9C 9E  2A 0F 50 6C  :.Y. ._.| ...4 RP.. VA.. *.Pl
00000030: B2 42 7C 77  D3 F3 08 CE  D6 9C DE 2F  BE 5C 45 8F  DD 09 7F D7  20 D6 F0 3C  .B|w .... .../ .\E. .... ...<
00000048: 58 A0 75 10  57 AA 03 B5  CE 42 D2 B0  AF E0 AB CE  81 92 55 77  FF FF 8F F7  X.u. W... .B.. .... ..Uw ....
00000060: F0 D0 1C BD  5F B9 4F DC  ED 71 EE 58  66 64 E9 99  E7 D1 8D B1  13 04 B9 8F  .... _.O. .q.X fd.. .... ....
00000078: C0 A0 2F B0  27 30 79 C4  C5 68 71 A6  12 E1 F9 0C  0C BA B0 69  C7 F3 41 0C  ../. '0y. .hq. .... ...i ..A.
00000090: F9 B8 AF BA  D9 9B 6F 8C  42 F7 F2 22  7A E7 E7 B4  31 43 44 CE  93 B9 85 17  .... ..o. B.." z... 1CD. ....
000000A8: 5D 62 A2 EF  EE 50 1C 88  24 48 54 56  8A 65 14 C0  89 0C FE 73  BA 10 16 63  ]b.. .P.. $HTV .e.. ...s ...c
000000C0: 8E 9B 5C 92  81 65 F5 F7  25 CE C8 EE  AC DF D3 D1  C0 F4 C8 75  8A EA 9E A0  ..\. .e.. %... .... ...u ....
000000D8: 52 9C 48 2A  08 60 97 E3  0E 96 C3 DD  A2 17 0A 46  B4 AC 57 FE  65 51 23 DD  R.H* .`.. .... ...F ..W. eQ#.
000000F0: E3 7D 80 70  47 4C BF A7  DE 8F B3 12  6D F4 F7 EF  9C A4 2E 7B  EB 0E 65 8C  .}.p GL.. .... m... ...{ ..e.
00000108: 44 B8 02 A1  CD 26 9B 86  94 0B D1 3E  06 61 4E E4  92 9C 06 B3  27 FB 67 C0  D... .&.. ...> .aN. .... '.g.
00000120: 09 BC 48 18  7B 2F 8F 98  E9 C9 0E 15  3D DB FE CF  09 83 80 95  72 62 B5 C9  ..H. {/.. .... =... .... rb..
00000138: F1 C7 A7 64  CE C1 05 8D  9C 89 3C DF  09 78 89 C4  16 35 4C 1C  36 DF 31 80  ...d .... ..<. .x.. .5L. 6.1.
00000150: 3A E6 E4 3B  76 42 23 96  BD 77 DA 26  24 E4 AE 25  72 28 AA 41  A6 CC 87 65  :..; vB#. .w.& $..% r(.A ...e
^CTraceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "hexdump.py", line 26, in hexdump
    for i, row_bytes in enumerate(binary_iterator):
  File "hexdump.py", line 10, in _iter_wrapper
    for chunk in binary:
  File "<stdin>", line 5, in some_gen
KeyboardInterrupt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment