A hex dump displays each byte as two hexadecimal digits, usually beside an offset and an ASCII gutter. It lets you inspect file headers, protocol fields, and hidden text without asking an application to interpret the whole file first.
This guide explains the output formats from xxd, hexdump, and POSIX od, then shows how to reverse or parse them. Use the hex decoder when you have a plain byte column and need to inspect its text interpretation.
What Is a Hex Dump?
A hex dump is a representation of binary data where each byte is shown as a two-digit hexadecimal number. Instead of showing you the raw binary (which would be unreadable streams of 1s and 0s), hex dumps present data in a compact, human-scannable format.
Each byte has a value from 0 to 255, or 00 to FF in hex. A typical dump places 16 bytes on each row and shows printable ASCII beside them.
Anatomy of a Hex Dump
Here's a typical hex dump of a simple text file containing "Hello, World!\n":
00000000: 4865 6c6c 6f2c 2057 6f72 6c64 210a Hello, World!.
Let's break down the three parts:
1. Offset (Address)
00000000: is the byte offset from the start of the file. The first byte is at offset 0; the row after 16 bytes begins at hex offset 10.
Many common dump formats display offsets in hexadecimal. In such output, 00000010 means byte 16, 00000020 means byte 32, and 000000FF means byte 255. Tools such as od can display offsets in other bases, so check the selected format.
2. Hex Bytes
4865 6c6c 6f2c 2057 6f72 6c64 210a contains the byte values in hexadecimal, grouped according to the tool's output format. Each pair is one byte:
| Hex | Decimal | ASCII |
|---|---|---|
| 48 | 72 | H |
| 65 | 101 | e |
| 6c | 108 | l |
| 6c | 108 | l |
| 6f | 111 | o |
| 2c | 44 | , |
| 20 | 32 | (space) |
| 57 | 87 | W |
| 6f | 111 | o |
| 72 | 114 | r |
| 6c | 108 | l |
| 64 | 100 | d |
| 21 | 33 | ! |
| 0a | 10 | (newline) |
You can paste these hex values into hextoascii.co and instantly see the decoded text.
3. ASCII Representation
Hello, World!. is the printable ASCII gutter. The dot stands in for the line-feed byte 0A, which is not printable.
Command-Line Tools for Hex Dumps
xxd
xxd is distributed with Vim and is commonly available on Unix-like systems, though minimal installations may not include it.
# Basic hex dump
xxd file.bin
# Output:
# 00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR
# Limit to first 64 bytes
xxd -l 64 file.bin
# Show in plain hex (no ASCII column)
xxd -p file.bin
# Set columns per line (default 16)
xxd -c 32 file.bin
# Reverse: convert hex dump back to binary
xxd -r hexdump.txt > restored.bin
# Seek to offset (skip first 100 bytes)
xxd -s 100 file.bin
The -r flag reverses an xxd dump after you inspect or edit it. Use a separate output file and compare it with the original before replacing data.
hexdump
hexdump (or hd) offers more formatting control:
# Canonical format (most readable, same as `hd`)
hexdump -C file.bin
# Output:
# 00000000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 |.PNG........IHDR|
# First 32 bytes only
hexdump -C -n 32 file.bin
# Skip first 1024 bytes
hexdump -C -s 1024 file.bin
# Custom format: offset + hex bytes
hexdump -e '"%08.8_ax: " 16/1 "%02x " "\n"' file.bin
# Just the hex, no formatting
hexdump -v -e '/1 "%02x "' file.bin
od
od (octal dump) is specified by POSIX and is the most portable choice across POSIX environments:
# Portable hex and character views
od -A x -t x1 -t c -v file.bin
# Output:
# 0000000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52
# 211 P N G \r \n 032 \n \0 \0 \0 \r I H D R
# Two-byte hex words
od -A x -t x2 file.bin
# First 48 bytes
od -A x -t x1 -t c -N 48 file.bin
Quick Comparison
| Tool | Best For | Reverse? | Everywhere? |
|---|---|---|---|
xxd |
General use, binary editing | ✅ -r flag |
Ships with Vim |
hexdump |
Custom formatting | ❌ | Most Unix |
od |
POSIX compliance | ❌ | POSIX standard |
Reading a Hex Dump: Step-by-Step Walkthrough
Let's read a real hex dump. Here's the first 96 bytes of a PNG image:
00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR
00000010: 0000 0100 0000 0100 0802 0000 00d3 107e ...............~
00000020: 8f00 0000 0173 5247 4200 aece 1ce9 0000 .....sRGB.......
00000030: 0004 6741 4d41 0000 b18f 0bfc 6105 0000 ..gAMA......a...
00000040: 0009 7048 5973 0000 0e74 0000 0e74 01de ..pHYs...t...t..
00000050: 661f 7800 0020 0049 4441 5478 5ced ddb7 f.x.. .IDATx\...
Line 1 (offset 0x00):
89 50 4E 47→ The first four bytes of the PNG signature (89followed byPNGin ASCII)0D 0A 1A 0A→ DOS/Unix line ending test bytes (part of the PNG spec)00 00 00 0D→ Chunk length: 13 bytes49 48 44 52→ Chunk type:IHDR(image header)
Line 2 (offset 0x10):
00 00 01 00→ Image width: 256 pixels00 00 01 00→ Image height: 256 pixels08→ Bit depth: 802→ Color type: 2 (truecolor RGB)
Line 3 (offset 0x20):
73 52 47 42→ Chunk type:sRGB(color space)
The offset locates each field, the byte column shows the stored values, and the ASCII gutter provides landmarks such as PNG and IHDR. A format specification is still required to interpret field lengths and byte order.
Common File Signatures (Magic Bytes)
Many binary file formats start with recognizable magic bytes or file signatures. They can help identify a format without trusting its extension, although not every format has a unique signature.
| File Type | Magic Bytes (Hex) | ASCII | Offset |
|---|---|---|---|
| PNG | 89 50 4E 47 0D 0A 1A 0A |
.PNG.... |
0 |
| JPEG | FF D8 FF |
... |
0 |
| GIF87a | 47 49 46 38 37 61 |
GIF87a |
0 |
| GIF89a | 47 49 46 38 39 61 |
GIF89a |
0 |
25 50 44 46 2D |
%PDF- |
0 | |
| ZIP local-file header | 50 4B 03 04 |
PK.. |
0 |
| GZIP | 1F 8B |
.. |
0 |
| ELF | 7F 45 4C 46 |
.ELF |
0 |
| SQLite 3 | 53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00 |
SQLite format 3 + NUL |
0 |
| WebAssembly | 00 61 73 6D |
.asm |
0 |
Quick File Identification
# Check the first 8 bytes of a mystery file
xxd -l 8 mystery_file
# Output: 89504e47 0d0a1a0a (the complete PNG signature)
# The `file` command does this automatically
file mystery_file
# mystery_file: PNG image data, 256 x 256, 8-bit/color RGB
A matching header supports a format identification, but it does not validate the rest of the file. Parse the complete structure and use a trusted digest when integrity matters.
Converting Hex Dumps Programmatically
Python
# Read a file as hex dump
def hex_dump(filepath, bytes_per_line=16):
with open(filepath, 'rb') as f:
offset = 0
while chunk := f.read(bytes_per_line):
hex_part = ' '.join(f'{b:02x}' for b in chunk)
ascii_part = ''.join(
chr(b) if 32 <= b < 127 else '.' for b in chunk
)
print(f'{offset:08x}: {hex_part:<{bytes_per_line*3}} {ascii_part}')
offset += len(chunk)
hex_dump('example.bin')
# Convert hex string to bytes
hex_str = '48656c6c6f20576f726c64'
data = bytes.fromhex(hex_str)
print(data.decode('utf-8')) # "Hello World"
# Convert bytes to hex string
text = 'Hello World'
hex_output = text.encode('utf-8').hex()
print(hex_output) # "48656c6c6f20576f726c64"
# Parse a hex dump back to binary
import re
def parse_hex_dump(dump_text):
"""Parse lines emitted by the hex_dump() function above."""
result = bytearray()
for line in dump_text.splitlines():
if not line.strip():
continue
match = re.match(r'^[0-9a-f]+:\s+(.*)$', line, re.I)
if not match:
raise ValueError(f'Invalid dump line: {line!r}')
# The generator separates its byte column and ASCII gutter with
# two or more spaces. Validate every byte token explicitly.
hex_column = re.split(r'\s{2,}', match.group(1), maxsplit=1)[0]
tokens = hex_column.split()
if not tokens or any(
re.fullmatch(r'[0-9a-f]{2}', token, re.I) is None
for token in tokens
):
raise ValueError(f'Invalid byte column: {line!r}')
result.extend(int(token, 16) for token in tokens)
return bytes(result)
# Identify file type by magic bytes
SIGNATURES = {
b'\x89PNG\r\n\x1a\n': 'PNG image',
b'\xff\xd8\xff': 'JPEG image',
b'%PDF-': 'PDF document',
b'PK\x03\x04': 'ZIP archive',
b'\x1f\x8b': 'GZIP stream',
b'\x7fELF': 'ELF binary',
b'SQLite format 3\x00': 'SQLite database',
b'\x00asm': 'WebAssembly module',
}
def identify_file(filepath):
with open(filepath, 'rb') as f:
header = f.read(16)
for sig, name in SIGNATURES.items():
if header.startswith(sig):
return f'{name} candidate'
return 'Unknown signature'
print(identify_file('photo.png')) # "PNG image candidate"
JavaScript (Node.js)
const fs = require('fs');
// Generate a hex dump
function hexDump(buffer, bytesPerLine = 16) {
const lines = [];
for (let i = 0; i < buffer.length; i += bytesPerLine) {
const slice = buffer.slice(i, i + bytesPerLine);
const offset = i.toString(16).padStart(8, '0');
const hex = [...slice]
.map(b => b.toString(16).padStart(2, '0'))
.join(' ');
const ascii = [...slice]
.map(b => (b >= 32 && b < 127) ? String.fromCharCode(b) : '.')
.join('');
lines.push(`${offset}: ${hex.padEnd(bytesPerLine * 3)} ${ascii}`);
}
return lines.join('\n');
}
const buf = fs.readFileSync('example.bin');
console.log(hexDump(buf));
// Hex string to text
function hexToText(hex) {
const clean = hex.replace(/\s+/g, '');
if (clean.length % 2 !== 0 || !/^[0-9a-f]*$/i.test(clean)) {
throw new TypeError('Expected an even number of hex digits');
}
const bytes = clean.match(/.{2}/g)?.map(b => parseInt(b, 16)) ?? [];
return Buffer.from(bytes).toString('utf-8');
}
console.log(hexToText('48 65 6c 6c 6f')); // "Hello"
// Text to hex string
function textToHex(text) {
return Buffer.from(text, 'utf-8')
.toString('hex')
.match(/.{2}/g)
.join(' ');
}
console.log(textToHex('Hello')); // "48 65 6c 6c 6f"
Bash One-Liners
# Hex string to ASCII text
echo "48656c6c6f" | xxd -r -p
# Output: Hello
# ASCII text to hex string
echo -n "Hello" | xxd -p
# Output: 48656c6c6f
# Compare two binary files at hex level
diff <(xxd file1.bin) <(xxd file2.bin)
# Extract bytes at specific offset (bytes 4-7 of a file)
dd if=file.bin bs=1 skip=4 count=4 2>/dev/null | xxd -p
# Find a hex pattern in a file
xxd file.bin | grep "504b 0304"
# Patch a single byte at offset 0x10 to value 0xFF
printf '\xff' | dd of=file.bin bs=1 seek=16 conv=notrunc
Real-World Use Cases
Debugging Network Packets
When a REST API returns garbled data or a WebSocket connection drops, hex-dumping the raw bytes reveals the truth. Tools like Wireshark show hex dumps of every packet. You can identify:
- Malformed headers
- Encoding mismatches (UTF-8 vs Latin-1)
- Unexpected null bytes in payloads
- Protocol-level framing errors
If you capture raw bytes, paste them into hextoascii.co for quick visual decoding.
Forensics and Incident Response
Digital forensics relies heavily on hex analysis:
- File carving: Finding files embedded in disk images by scanning for magic bytes
- Metadata extraction: Reading EXIF data from images, embedded timestamps
- Malware analysis: Examining PE headers, finding embedded strings
- Data recovery: Identifying file boundaries in corrupted storage
Reverse Engineering Binary Protocols
When protocol documentation is missing or stale, compare captures of known messages to form and test hypotheses about the byte layout:
Request 1: 01 00 00 05 48 65 6c 6c 6f → length=5, data="Hello"
Request 2: 01 00 00 03 48 69 21 → length=3, data="Hi!"
The pattern emerges: byte 0 is a type flag, bytes 1-3 are a big-endian length prefix, and the rest is the payload.
Checking File Type (Not Integrity)
A quick header check can show whether a file begins with the signature expected for its claimed format, but it cannot prove that the rest of the file is complete or unmodified:
# Check for the common ZIP local-file header
xxd -l 4 download.zip
# Should show: 504b 0304 → PK..
Use a trusted checksum or cryptographic hash to verify transfer integrity, and parse the complete file with a format-aware tool to detect structural truncation or corruption.
Debugging Encoding Issues
Hex dumps expose the bytes behind mojibake, missing characters, and byte-order marks. For example, é is C3 A9 in UTF-8 and E9 in Latin-1. The text encoding guide explains why a byte pattern still needs format or protocol context.
Related Decoding References
Use these references alongside command-line inspection:
- Hex decoder: compare ASCII, Latin-1, and UTF-8 interpretations of a plain byte string.
- RFC 4648 Base64: identify Base64 input and decode it to bytes before creating a hex dump.
Keep the original bytes when testing a possible decoding so you can reverse the operation.
FAQ
What is a hex dump?
A hex dump is a display of binary data where each byte is represented as a two-digit hexadecimal number (00–FF). It typically shows three columns: the byte offset, the hex values, and the ASCII interpretation. It's used for inspecting files, debugging protocols, and analyzing binary data.
How do I create a hex dump on Linux or Mac?
Use xxd filename for a familiar hex dump, hexdump -C filename for canonical format, or od -A x -t x1 -t c -v filename for portable hexadecimal and character views from a POSIX-defined utility. Availability and option syntax vary by operating system, so check the local manual. Use the tool's length option to limit output to the first N bytes.
How do I convert a hex dump back to a binary file?
With xxd, use the reverse flag: xxd -r hexdump.txt > output.bin. For plain hex strings (no offsets), use xxd -r -p hex.txt > output.bin. You can also use hextoascii.co for quick online conversion.
What are magic bytes?
Magic bytes (or file signatures) are byte sequences associated with a file format, often at the beginning of a file. A match is evidence for a format, not proof that the complete file is valid. For example, PNG begins with 89 50 4E 47 0D 0A 1A 0A, PDF begins with %PDF-, and a ZIP local-file header can begin with 50 4B 03 04. The Unix file utility combines signature rules and other checks to classify input.
How do I find a specific byte sequence in a file?
Use xxd file.bin | grep "pattern" for a quick search, or grep -boa -P '\x89\x50\x4e\x47' file.bin for binary pattern matching. Python's bytes.find() method works for programmatic searches.
What's the difference between hexdump, xxd, and od?
xxd provides a convenient reversible format, hexdump offers custom format strings on systems that include it, and od is defined by POSIX. Choose based on the required output and what is installed rather than assuming all three are present.
Why do hex dumps show dots (.) for some characters?
Dots represent bytes outside printable ASCII 0x20-0x7E, including controls, DEL, and values above 0x7F. Replacing them in the gutter prevents terminal control sequences and invisible characters from changing the display; the hex column still preserves their values.
Can I edit a binary file using hex dumps?
Yes. With xxd: dump the file (xxd file.bin > hex.txt), edit hex.txt in any text editor, then reverse it (xxd -r hex.txt > modified.bin). For single-byte patches, use printf '\xNN' | dd of=file.bin bs=1 seek=OFFSET conv=notrunc. For serious hex editing, tools like hexedit or bless provide a proper GUI.