Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Interpreting Raw Bytes with Hex Dumps

Hello! In the last lesson, you decoded floating-point bit patterns and saw that byte order must be settled before interpreting a multi-byte value. This lesson brings the module together: you’ll inspect a file’s actual bytes with a hex-dump tool, then decide which bytes are text, which could be integers, and what the dump cannot tell you on its own.

You can do the lab on your Mac or in an ARM64 Linux virtual machine. Allow about 35–40 minutes, including time to run and inspect the commands.


What a hex dump shows

A hex dump does not change a file. It presents its bytes in a form you can inspect: a file offset on the left, hexadecimal byte values in the middle, and a rough text view on the right. The offset is a position measured from the beginning of the file, not a memory address. Offset 00000040, for example, is hexadecimal for 64: the first byte shown is the file’s 65th byte.

Watch these portions of showing actual file bytes with hexdump by anthonywritescode. Notice the difference between bytes in a file and what a terminal chooses to display when given those bytes.

showing actual file bytes with hexdump (beginner - intermediate) anthony explains #224

The video introduces hexdump as a way to inspect file and stream bytes, then demonstrates its hex-and-text display.

Watch the byte-level view for why ordinary terminal output can be misleading. Then watch the canonical display; focus on how a non-printable control byte appears in hex even when the text column shows only a dot.

The supplied image shows a related tool, xxd. Unlike hexdump -C, its default display visually groups pairs of bytes into four-digit chunks. Those chunks are not automatically two-byte integers.

An `xxd` view of a text file starting at offset `00000040`: hexadecimal bytes occupy the middle column, while the right column shows printable characters and substitutes dots for some other bytes.

In the first line, 5248 means the two successive bytes 52 48, which spell RH in ASCII. A little later, 0a is a newline byte, represented by a dot in this display. But a dot in the text column can also be a literal period: the byte 2e is ASCII .. When that distinction matters, trust the hex bytes, not the text column.


Inspect a file whose layout you know

Create a small file with deliberately mixed contents. Run this in a terminal; python3 writes exactly the bytes specified, without adding a newline at the end:

python3 - <<'PY'
from pathlib import Path

data = (
    b"DEMO"
    + (0x12345678).to_bytes(4, "little")
    + (-2).to_bytes(2, "little", signed=True)
    + "OK\né".encode("utf-8")
    + b"\x00"
)
Path("sample.bin").write_bytes(data)
PY

hexdump -C sample.bin

You should see a 16-byte row like this, followed by a final offset of 00000010:

00000000  44 45 4d 4f 78 56 34 12  fe ff 4f 4b 0a c3 a9 00  |DEMOxV4...OK....|
00000010

Each two-digit hex value in the middle is one byte. The first byte, 44, is at offset 00; 45 is at offset 01. The byte 78 is at offset 04, not offset 08: printed hex digits are not separate file bytes. The final 00000010 marks the position just after the data. Since hexadecimal 10 is decimal 16, it also confirms the file’s length.

Here is the interpretation specified by the code that made this file:

Offsets (hex) Bytes Interpretation
00–03 44 45 4d 4f ASCII DEMO
04–07 78 56 34 12 Little-endian, 32-bit unsigned integer 0x12345678
08–09 fe ff Little-endian, 16-bit signed integer
0a–0c 4f 4b 0a ASCII OK followed by newline
0d–0e c3 a9 UTF-8 encoding of é
0f 00 A zero byte

The four integer bytes appear as 78 56 34 12 because we chose little-endian order when writing them. Their value is 0x12345678, or in decimal. Likewise, interpreting fe ff as a little-endian unsigned 16-bit value would give 0xfffe, or ; interpreting the same two bytes as signed two’s complement gives .

The text column cannot explain those choices. It happens to render the integer’s 78 56 34 bytes as xV4, but we did not put the text xV4 into the file as a text field. It renders the UTF-8 bytes c3 a9 as dots even though together they encode é. A dump supplies bytes and positions; a file format, program, or other context supplies their meaning.


Select a region and avoid a byte-order trap

Read the Linux hexdump(1) manual’s descriptions of canonical output and the controls for limiting a dump. These short entries give you a precise reference for the commands used here; the same short-form options used in this lab work on macOS as well.

hexdump(1) - Linux manual page

Read the Linux manual page to identify what -C displays and how -n and -s select part of a file. Its FORMATS section also explains why the one-byte display is a safer starting point than some multi-byte displays.

In the OPTIONS section, find -C, --canonical. Begin at “Canonical hex+ASCII display” and read through the note about hd; the text column describes its right-hand side. In the same section, find -n, --length and -s, --skip; read both entries in the length-and-skip passage. In FORMATS, read the final paragraph, beginning “Note that the default format,” through its last sentence about byte-order-independent output; pay particular attention to the byte-order warning.

Now display just eight bytes beginning at file offset 4:

hexdump -C -s 4 -n 8 sample.bin

The displayed data begins with 78 56 34 12 and continues through fe ff 4f 4b. Its starting offset is 00000004; the ending offset is 0000000c. Here -s 4 skips four file bytes, and -n 8 reads eight. These values are decimal command arguments, though the dump prints offsets in hexadecimal.

Stay with -C when establishing the actual byte sequence. Some hexdump formats combine adjacent bytes into multi-byte units and print those units using the machine’s native byte order. That can make the output look rearranged. A display format does not rearrange the bytes in the file.


Look at a file you did not create

A file’s first bytes sometimes provide a clue to its format. Try a bounded inspection of an existing executable:

hexdump -C -n 16 /bin/ls

On an ARM64 Linux system, an ELF executable commonly begins 7f 45 4c 46; the text column shows .ELF, with the initial dot standing for byte 7f. On macOS, /bin/ls is a different executable format, so expect different starting bytes. The exercise is to read what is there, not to force it to match one platform’s example.

A recognizable header is evidence about a file’s intended format, not proof that every later byte is valid. Conversely, readable characters inside a binary file do not make the whole file a text file. This is why a small, offset-aware dump is useful when debugging an unexpected file: you can check its header, an apparent newline or zero byte, or a particular integer field without asking a text viewer to interpret the entire file.


Key takeaways

Use a hex dump to establish byte values and file offsets first. Then interpret selected bytes using an explicit width, byte order, signedness, or text encoding. Treat the printable-character column as a convenience, not an authority: a dot may hide a control byte or a UTF-8 byte, and readable characters may occur inside an integer.

This completes the module on data representation. Next, you’ll move from how bits represent data to how digital logic operates on bits, starting with Boolean expressions and truth tables.

Can't find a good explanation? Sign up and we'll make it for you

Sign up