Appendix A — File Signatures Reference

Purpose. A keyboard-side lookup of file signatures (magic numbers) — headers, footers, offsets, extensions, and carving notes — for identifying file types by content and for recovering files when the file system is gone. This is the reference table promised in Chapter 7 — File Carving; read that chapter for the why, keep this open for the what.

A file signature (also magic number) is a short, fixed byte sequence at a known position — almost always the first few bytes — that identifies a file's format independent of its name or extension. Two disciplines lean on this constantly:

  • Recovery and carving (💾) — when the metadata that says "this run of sectors is a file" has been wiped (a reformat, an overwritten MFT, a dead partition table), the only way to find a file is to recognize its bytes. Carvers scan raw sectors for a known header, then read or compute where the file ends. See Chapter 6 — Logical Recovery for when metadata survives and carving is not needed.
  • Forensic typing and masquerade detection (🔍) — the extension is a label a user (or an adversary) chose; the magic number is ground truth. A file named vacation.jpg whose first bytes are 4D 5A is a Windows executable wearing a costume. Extension-vs-signature mismatch is a classic anti-forensic tell — see Chapter 30 — Anti-Forensics and the masquerade workflow at the end of this appendix.

Recovery vs. Forensics. The same three bytes FF D8 FF serve both masters. To the recovery tech they say "a JPEG starts here — carve it and give the client their photo back." To the examiner they say "this object is a JPEG regardless of what the file table claims — and if the file table claims otherwise, that discrepancy is itself evidence." Recognize the bytes once; choose your purpose second.


A.1 How to read this appendix

  • Hex notation. Bytes are shown space-separated in uppercase hex: FF D8 FF. In code and tool configs they appear escaped: \xFF\xD8\xFF (C/foremost/scalpel/YARA) or \xff\xd8\xff. Printable bytes are sometimes shown as ASCII in quotes: %PDF, "PK", "ftyp".
  • Offset. Unless a @N annotation appears, the signature is at byte offset 0 (the very start of the file). @4 means "starting at byte 4," @0x8001 means byte 33,793. Offsets matter: an ftyp box and a ustar marker live deep inside their files, not at the front.
  • Endianness. Some formats exist in both little-endian (Intel) and big-endian (Motorola/network) flavors, and the magic number itself tells you which (TIFF II vs MM; PCAP D4 C3 B2 A1 vs A1 B2 C3 D4). Byte order is reviewed in Chapter 2 — How Data Is Stored.
  • Footer. Many formats have no reliable terminal marker — their length lives in a header field or in internal structures. "—" in the footer column means no fixed footer; size from header or max-carve (see A.7 Carving Strategy).
  • "It identifies the type, not the truth." A valid signature proves a byte run claims to be a format. It does not prove the file is intact, uncorrupted, or contiguous. Always validate (parse/decode) before you trust a carve.

A.2 Images

Format Header (hex) ASCII Footer (hex) Ext Notes
JPEG (JFIF) FF D8 FF E0 ···· FF D9 jpg, jpeg After E0: 00 10 4A 46 49 46 00 (..JFIF.).
JPEG (Exif) FF D8 FF E1 ···· FF D9 jpg, jpeg After E1: ....45 78 69 66 00 (Exif.). Camera files; holds EXIF/GPS — see Ch. 20.
JPEG (generic) FF D8 FF ··· FF D9 jpg 4th byte varies (E0/E1/E8/DB/EE/C0). FF D8 FF is the safe header to carve on.
JPEG 2000 00 00 00 0C 6A 50 20 20 0D 0A ..jP .. jp2, j2k Different format; not "JPEG."
PNG 89 50 4E 47 0D 0A 1A 0A .PNG.... 49 45 4E 44 AE 42 60 82 png Footer = IEND chunk + its fixed CRC AE 42 60 82. Header's 0D 0A/1A/0A detect bad text transfers.
GIF (87a) 47 49 46 38 37 61 GIF87a 3B gif Trailer is single byte 3B; carvers use 00 3B.
GIF (89a) 47 49 46 38 39 61 GIF89a 3B gif Animated/transparency variant. Carve header as 47 49 46 38.
BMP 42 4D BM bmp Bytes @2 = file size (4-byte LE) — structure-aware carve.
TIFF (LE) 49 49 2A 00 II*. tif, tiff II = Intel/little-endian. IFD-chained; no footer.
TIFF (BE) 4D 4D 00 2A MM.* tif, tiff MM = Motorola/big-endian.
Canon RAW 49 49 2A 00 10 00 00 00 43 52 II*····CR cr2 TIFF-based; 43 52 (CR) @8. NEF/ARW/DNG/ORF are also TIFF-based — see A.6.
WebP 52 49 46 4657 45 42 50 RIFFWEBP webp RIFF container; WEBP @8. See RIFF table.
HEIF/HEIC 66 74 79 70 68 65 69 63 @4 ftypheic heic, heif ISO BMFF; brands heic/heix/mif1/hevc. iPhone photos.
AVIF 66 74 79 70 61 76 69 66 @4 ftypavif avif ISO BMFF still image (AV1).
ICO 00 00 01 00 .... ico 00 00 02 00 = cursor (.cur). Short header → false positives.
Photoshop 38 42 50 53 8BPS psd
DICOM 44 49 43 4D @0x80 DICM dcm Medical imaging; magic @128. Carve a 132-byte preamble.
SVG 3C 3F 78 6D 6C / 3C 73 76 67 <?xml / <svg 3C 2F 73 76 67 3E svg XML text; no binary magic — content-sniffed.

A.3 Documents and e-books

Format Header (hex) ASCII Footer (hex) Ext Notes
PDF 25 50 44 46 2D %PDF- 25 25 45 4F 46 pdf Footer %%EOF may repeat (incremental updates) — carve to the last one; often trailed by 0D/0A.
RTF 7B 5C 72 74 66 31 {\rtf1 7D rtf Plain-text markup; ends with }.
Legacy Office (OLE2/CFBF) D0 CF 11 E0 A1 B1 1A E1 ···· doc, xls, ppt, msg, msi Compound File Binary. Disambiguate by internal streams — see A.6.4.
OOXML (Word/Excel/PowerPoint) 50 4B 03 04 PK.. 50 4B 05 06 docx, xlsx, pptx A ZIP. Disambiguate by entries — see A.6.1.
OpenDocument 50 4B 03 046D 69 6D 65 74 79 70 65 @30 PK..mimetype 50 4B 05 06 odt, ods, odp ZIP with stored mimetype entry first; value @38.
EPUB 50 4B 03 04mimetypeapplication/epub+zip @30 50 4B 05 06 epub ZIP; file(1) matches the literal string @30.
MOBI / Kindle 42 4F 4F 4B 4D 4F 42 49 @60 BOOKMOBI mobi PalmDOC container; magic @60.
OneNote E4 52 5C 7B 8C D8 17 4D one GUID-style header.

A.4 Archives and compression

Format Header (hex) ASCII Footer (hex) Ext Notes
ZIP 50 4B 03 04 PK.. 50 4B 05 06 zip Local file header. Empty archive = EOCD only 50 4B 05 06; spanned = 50 4B 07 08. EOCD is 22 B + comment — read comment length for exact end.
RAR (1.5–4.x) 52 61 72 21 1A 07 00 Rar!·· rar 7-byte marker.
RAR (5.0+) 52 61 72 21 1A 07 01 00 Rar!·· rar 8-byte marker (note the extra 01).
7-Zip 37 7A BC AF 27 1C 7z···· 7z
GZIP 1F 8B 08 ··· gz 08 = deflate. Trailer = 4-B CRC32 + 4-B ISIZE (size mod 2³²).
BZIP2 42 5A 68 BZh bz2 4th byte 31–39 = block size.
XZ FD 37 7A 58 5A 00 ·7zXZ· 59 5A xz
ZSTD 28 B5 2F FD zst
LZ4 (frame) 04 22 4D 18 lz4
TAR 75 73 74 61 72 @257 ustar tar POSIX marker @0x101; followed by 00 30 30 or 20 20.
CAB 4D 53 43 46 MSCF cab Microsoft Cabinet.
Zlib stream 78 01 / 78 9C / 78 DA (raw) 78 9C = default, 78 DA = best compression. Embedded everywhere (PNG/PDF/Git).

A.5 Audio, video, and containers

Format Header (hex) ASCII Footer (hex) Ext Notes
MP3 (ID3v2) 49 44 33 ID3 mp3 Tag prefix; audio frames follow. ID3v1 "TAG" 128 B from EOF (optional).
MP3 (raw frame) FF FB / FF FA / FF F3 / FF F2 mp3 11-bit frame sync (FF Ex/FF Fx). Very short → many false hits; validate.
FLAC 66 4C 61 43 fLaC flac
OGG 4F 67 67 53 OggS ogg, oga, ogv Vorbis/Opus/Theora container.
WAV 52 49 46 4657 41 56 45 RIFFWAVE wav RIFF; size @4 (LE). See RIFF table.
AIFF 46 4F 52 4D41 49 46 46 FORMAIFF aiff IFF/big-endian cousin of RIFF.
WMA / WMV / ASF 30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 00 62 CE 6C asf, wma, wmv 16-byte ASF header GUID.
AVI 52 49 46 4641 56 49 20 RIFFAVI avi RIFF; AVI (trailing space) @8.
MP4 / M4A / M4V 66 74 79 70 @4 ftyp mp4, m4a, m4v ISO BMFF; brand @8. See ftyp table.
QuickTime MOV 66 74 79 70 71 74 20 20 @4 ftypqt mov ISO BMFF brand qt. Also moov/mdat top-level atoms.
3GP (mobile) 66 74 79 70 33 67 70 @4 ftyp3gp 3gp Phone video; common in mobile forensics (Ch. 24).
Matroska / WebM 1A 45 DF A3 ·E·· mkv, webm EBML header. WebM is an MKV subset.
FLV 46 4C 56 FLV flv Flash video; legacy but still recovered.
SWF 46 57 53 / 43 57 53 / 5A 57 53 FWS/CWS/ZWS swf Uncompressed / zlib / LZMA.

A.6 Databases, email, and system artifacts

Format Header (hex) ASCII Footer Ext Notes
SQLite 3 53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00 SQLite format 3. sqlite, db 16-byte string. Page-structured; size = page_size × page_count (both in the 100-B header). Ubiquitous in browser/app/mobile forensics.
SQLite WAL 37 7F 06 82 / 37 7F 06 83 wal Write-ahead log; holds uncommitted rows — recover deleted records.
ESE / EDB EF CD AB 89 @4 edb Extensible Storage Engine: Exchange, Windows Search, SRUM, WebCacheV01. Magic @4.
Outlook PST/OST 21 42 44 4E !BDN pst, ost Mail store — see Ch. 19.
Registry hive 72 65 67 66 regf (none) NTUSER.DAT, SYSTEM, SOFTWARE, etc. — Ch. 16.
Windows EVTX log 45 6C 66 46 69 6C 65 00 ElfFile. evtx Modern Windows event log.
Windows EVT log 30 00 00 00 4C 66 4C 65 0···LfLe evt Legacy (pre-Vista) event log.
Prefetch (Win 8+) 4D 41 4D 04 MAM· pf MAM/LZXPRESS-compressed; decompresses to SCCA.
Prefetch (raw) 53 43 43 41 @4 SCCA @4 pf Version @0, SCCA @4. Execution evidence.
Windows shortcut 4C 00 00 00 01 14 02 00 L······· lnk Header size 0x4C + LNK CLSID. Tracks file access.
Thumbcache 43 4D 4D 4D CMMM db thumbcache_*.db — image thumbnails survive deletion.
EML message 52 65 63 65 69 76 65 64 3A / 46 72 6F 6D 20 Received: / From eml, mbox RFC 822 text; header-sniffed, no binary magic.

A.7 Executables, code, and fonts

Format Header (hex) ASCII Footer Ext Notes
PE (Windows EXE/DLL) 4D 5A MZ exe, dll, sys DOS stub; real PE header 50 45 00 00 (PE\0\0) at the offset in field e_lfanew (@0x3C). Malware triage: Ch. 32.
ELF (Linux/Unix) 7F 45 4C 46 ·ELF (none), so, o Byte 4: 01=32-bit 02=64-bit. Byte 5: 01=LE 02=BE.
Mach-O (64-bit) FE ED FA CF (none), dylib macOS/iOS. 32-bit = FE ED FA CE. Byte-swapped = CF FA ED FE.
Mach-O / Java FAT CA FE BA BE class Collision: Java .class and Mach-O universal binary. Java has a 2-byte minor+major version next; Mach-O has a small nfat_arch. Disambiguate by context.
Android DEX 64 65 78 0A 30 33 35 00 dex.035. dex Dalvik bytecode; 035 is a version.
WebAssembly 00 61 73 6D .asm wasm Followed by 4-byte version 01 00 00 00.
Shell script 23 21 #! sh Shebang, e.g. #!/bin/sh.
MSI installer D0 CF 11 E0 A1 B1 1A E1 msi OLE2 — see A.6.4.
TrueType font 00 01 00 00 00 ttf OpenType = 4F 54 54 4F (OTTO). WOFF = 77 4F 46 46.

A.8 Disk, partition, and forensic-image formats

These matter at the container layer — what you mount, image, or carve inside of. See Chapter 14 — Forensic Acquisition.

Format Header (hex) ASCII Footer Ext Notes
Raw / dd image (none) dd, img, raw, 001 Pure sector copy — no signature. The signature is whatever was at LBA 0 (MBR/GPT/boot sector).
MBR boot sector 55 AA @510 (in image) Boot signature in the last 2 bytes of sector 0. Partition table @446.
GPT header 45 46 49 20 50 41 52 54 @0x200 EFI PART (in image) GPT header in LBA 1 (byte 512).
EnCase E01 (EWF) 45 56 46 09 0D 0A FF 00 EVF····· E01 Expert Witness Format. EWF2/Ex01 = 45 56 46 32 0D 0A 81 00.
AFF4 50 4B 03 04 (ZIP) PK.. aff4 A ZIP container; identify by internal container.description.
VHD (fixed/dyn) footer 63 6F 6E 65 63 74 69 78 conectix (same) vhd Cookie in the footer (and copy at start of dynamic disks: cxsparse).
VHDX 76 68 64 78 66 69 6C 65 vhdxfile vhdx Hyper-V gen-2 disk.
VMDK (sparse) 4B 44 4D 56 KDMV vmdk Hosted sparse extent. Descriptor-only VMDKs start with text # Disk DescriptorFile.
QCOW2 51 46 49 FB QFI· qcow2 QEMU disk image.
ISO 9660 43 44 30 30 31 @0x8001 CD001 iso Volume descriptor at sector 16 (byte 32,769). UDF adds 42 45 41 30 31 (BEA01).

A.9 Network captures, crypto, and miscellany

Format Header (hex) ASCII Footer Ext Notes
PCAP (µs, LE) D4 C3 B2 A1 pcap Classic libpcap. Big-endian = A1 B2 C3 D4. Nanosecond = 4D 3C B2 A1 / A1 B2 3C 4D.
PCAPNG 0A 0D 0D 0A pcapng Section Header Block; byte-order magic 1A 2B 3C 4D follows. Ch. 23.
DER cert/key 30 82 der, cer ASN.1 SEQUENCE; length follows.
PEM cert/key 2D 2D 2D 2D 2D 42 45 47 49 4E -----BEGIN -----END... pem, crt Base64 text.
PGP (armored) 2D 2D 2D 2D 2D 42 45 47 49 4E 20 50 47 50 -----BEGIN PGP asc, gpg Encrypted artifacts — Ch. 29.
LUKS volume 4C 55 4B 53 BA BE LUKS·· (volume) Encrypted Linux container. Its presence is itself a finding.
SQLite-backed .plist (binary) 62 70 6C 69 73 74 30 30 bplist00 plist Apple binary property list — macOS/iOS forensics (Ch. 17).
Java JAR / Android APK 50 4B 03 04 PK.. 50 4B 05 06 jar, apk ZIP; JAR has META-INF/MANIFEST.MF, APK has AndroidManifest.xml.
BitTorrent 64 38 3A 61 6E 6E 6F 75 6E 63 65 d8:announce torrent Bencoded text.

A.10 Container disambiguation

A single magic number frequently maps to many real formats. These are the four families that cause the most confusion in the field.

A.10.1 ZIP-based formats (OOXML, ODF, EPUB, JAR/APK)

All begin with the ZIP local-file-header magic 50 4B 03 04. They differ only in their contents. Peek inside (unzip the central directory, or 7z l, or read the first entry name at offset 30):

Real type Tell-tale entry / marker Ext
Word (OOXML) [Content_Types].xml + word/document.xml docx, docm
Excel (OOXML) [Content_Types].xml + xl/workbook.xml xlsx, xlsm
PowerPoint (OOXML) [Content_Types].xml + ppt/presentation.xml pptx, pptm
OpenDocument stored entry mimetype @30, value application/vnd.oasis.opendocument.* @38 odt, ods, odp
EPUB literal mimetypeapplication/epub+zip @30 epub
Java JAR META-INF/MANIFEST.MF jar
Android APK AndroidManifest.xml + classes.dex apk
Generic ZIP none of the above zip

Tool Tip. ODF and EPUB authors deliberately put an uncompressed mimetype entry first so that file(1) can identify the type at a fixed offset without decompressing anything. That is why the EPUB string mimetypeapplication/epub+zip sits predictably at offset 30 — a gift to both libmagic and your carver.

A.10.2 ISO BMFF "ftyp" brands (MP4 family)

The ISO Base Media File Format puts a 4-byte box size first, then 66 74 79 70 (ftyp) @4, then a 4-byte major brand @8 that tells you what it really is:

Brand @8 (hex) ASCII Real type
69 73 6F 6D isom MP4 (ISO base)
6D 70 34 31 / 6D 70 34 32 mp41 / mp42 MP4 v1 / v2
4D 34 41 20 M4A iTunes audio
4D 34 56 20 M4V iTunes video
71 74 20 20 qt QuickTime MOV
33 67 70 35 3gp5 3GPP mobile video
68 65 69 63 heic HEIF image
61 76 69 66 avif AVIF image

Tool Tip. Carve ISO BMFF on the ftyp @4 marker, not on the leading size bytes (which vary). A robust carver reads each top-level box's 32-bit size field and walks ftyp → moov → mdat … to find the true end — there is no footer.

A.10.3 RIFF form types

RIFF starts with 52 49 46 46 (RIFF), a 4-byte little-endian total-size-minus-8 @4, then a 4-byte form type @8:

Form type @8 ASCII Real type
41 56 49 20 AVI AVI video
57 41 56 45 WAVE WAV audio
57 45 42 50 WEBP WebP image
41 43 4F 4E ACON Animated cursor (.ani)
52 4D 49 44 RMID RIFF MIDI

Because the RIFF header carries its own size, RIFF files are a textbook case for structure-aware carving: read the size at offset 4, carve exactly that many bytes plus 8.

A.10.4 OLE2 / CFBF (legacy Office)

D0 CF 11 E0 A1 B1 1A E1 is the Compound File Binary Format — a tiny FAT-like file system inside a file. Word, Excel, PowerPoint, Outlook .msg, .msi, and more all share it. Identify the real type by the named streams inside:

Internal stream / clue Real type
WordDocument .doc
Workbook (or Book) .xls
PowerPoint Document .ppt
__properties_version1.0 + __substg1.0_* .msg (Outlook)
!Sentinel / SummaryInformation only generic OLE / .msi

A.10.5 TIFF-based RAW photo formats

Many camera RAW formats are TIFF under the hood, so they share 49 49 2A 00 (II*) or 4D 4D 00 2A (MM). Disambiguate by the maker note / second magic:

RAW type Distinguisher Ext
Canon CR (43 52) @8 (CR2); CRW differs cr2, crw
Nikon TIFF + NIKON maker note nef
Sony TIFF (II*) arw
Adobe DNG TIFF + DNG tags dng
Olympus IIRO/IIRS variants orf

A.11 Footers and end-of-file markers

Footers are precious — when present and reliable, they let you carve a file at its exact end. But most binary formats do not have one; they store length in a header or in internal structures. Memorize which is which.

Has a reliable footer Footer (hex) No footer — length is structural
JPEG FF D9 BMP (size @2), TIFF (IFD chain)
PNG 49 45 4E 44 AE 42 60 82 RIFF/WAV/AVI/WebP (size @4)
GIF 3B (carve 00 3B) MP4/MOV/HEIC (box sizes)
PDF 25 25 45 4F 46 (last one) MP3 (frame stream; ID3v1 "TAG" optional)
ZIP/OOXML 50 4B 05 06 (+ comment) SQLite (page_size × page_count)
XZ 59 5A ELF/PE (section/program headers)
RTF 7D (}) GZIP (CRC+size trailer, not a marker)

Limitation. A footer signature is not always the file's last byte. ZIP's End-Of-Central-Directory record is followed by 18+ bytes plus a variable comment; PDF's %%EOF may be followed by whitespace and is repeated in incrementally-updated files; PNG's IEND may be followed by ancillary data appended by some tools. Carve to the footer, then read the format's length fields to trim or extend precisely. Naïve "stop at first footer" carving truncates incrementally-saved PDFs and ZIPs.


A.12 Reverse lookup — "I see these bytes, what is it?"

You are staring at a hex dump and need to name it fast. Sorted by first byte. (For full disambiguation of shared headers, jump to A.10.)

First bytes Likely format(s)
00 00 01 00 / 00 00 02 00 ICO / CUR
00 00 01 BA / 00 00 01 B3 MPEG-PS / MPEG video
00 61 73 6D WebAssembly
1A 45 DF A3 Matroska / WebM
1F 8B 08 GZIP
21 42 44 4E Outlook PST/OST
25 50 44 46 PDF
28 B5 2F FD Zstandard
30 26 B2 75 ASF / WMV / WMA
37 7A BC AF 27 1C 7-Zip
38 42 50 53 Photoshop PSD
42 4D BMP
42 5A 68 BZIP2
43 57 53 / 46 57 53 SWF (Flash)
45 56 46 09 EnCase E01 image
47 49 46 38 GIF
49 44 33 MP3 (ID3v2)
49 49 2A 00 / 4D 4D 00 2A TIFF / camera RAW
4D 5A Windows PE (EXE/DLL)
4D 53 43 46 Microsoft CAB
50 4B 03 04 ZIP / OOXML / ODF / EPUB / JAR / APK
52 61 72 21 1A 07 RAR
52 49 46 46 RIFF → AVI / WAV / WebP (@8)
53 51 4C 69 74 65 SQLite 3
66 74 79 70 @4 MP4 / MOV / HEIC / 3GP / AVIF (@8)
7B 5C 72 74 66 RTF
7F 45 4C 46 ELF
89 50 4E 47 PNG
CA FE BA BE Java .class or Mach-O FAT
D0 CF 11 E0 A1 B1 1A E1 OLE2 → DOC/XLS/PPT/MSG/MSI
D4 C3 B2 A1 / A1 B2 C3 D4 PCAP capture
FD 37 7A 58 5A 00 XZ
FE ED FA CE / FE ED FA CF Mach-O (32/64-bit)
FF D8 FF JPEG
FF FB / FF FA / FF F3 MP3 (raw frame)

A.13 Carving strategy — header/footer, max-size, and fragmentation

A signature tells you where a file starts. The hard part is knowing where it ends and whether it is in one piece. Four strategies, in rough order of reliability:

1. Header-footer carving. The format has both a known header and a reliable footer (JPEG FF D8 FFFF D9; PDF %PDF%%EOF; GIF…00 3B; ZIP…50 4B 05 06). Carve from header to footer. Best case. Cautions: footers can repeat (carve to the last %%EOF) and may be followed by trailing bytes (read length fields to trim).

2. Header + embedded length (structure-aware). No footer, but the format stores its own size: BMP (@2), RIFF (@4), ISO BMFF box sizes, SQLite (page_size × page_count), ELF/PE section headers. Read the length and carve exactly. Most robust when available — immune to false footers and tolerant of trailing data.

3. Header + maximum-size carving. No footer and no usable length (raw MP3, many video streams, plain text). Carve from the header up to a configured maximum (e.g., foremost's per-type cap). You will over-carve — trailing garbage rides along — and downstream validation/parsing trims it. Pick the cap carefully: too small truncates large files; too large wastes disk and time and swallows the next file.

4. Validation / semantic carving. Don't trust the bytes — parse them. A carved JPEG that fully decodes is almost certainly intact; one that decodes halfway then errors flags a fragment boundary or corruption. PhotoRec, Scalpel's validation mode, and bulk_extractor lean on this to set correct ends and to reject false positives. Always validate the carve before reporting it.

Fragmentation — the real enemy

Carving's core assumption is that a file occupies one contiguous run of sectors. File systems break that promise: appends, deletion-and-reuse, copy-on-write, and SSD wear-leveling all scatter a file across the volume. (Recoverability on SSDs is further crushed by TRIM — see Chapter 9 — SSD and Flash Recovery.)

Contiguous (easy):
  [ HDR ........................... FTR ]      one run; carve HDR → FTR

Bifragmented (two pieces, a gap between):
  [ HDR ...... frag1 ]   [ other data ]   [ frag2 ...... FTR ]
   \____ file part ___/   \____ gap ___/    \___ file part ___/
   Bifragment Gap Carving: try gap = 1,2,3,… clusters,
   reassemble, VALIDATE (decode) at each — keep the gap that decodes.

Highly fragmented (3+ pieces):
  [HDR.f1]  [x]  [f2]  [y]  [f3..FTR]
   → SmartCarving / content-based reassembly; far harder, often partial.

Practical consequences and tactics:

  • Cluster alignment. Fragments begin on cluster boundaries (commonly 4 KiB / 8 sectors). Search candidate fragment starts on aligned offsets, not every byte — fewer false positives, far faster.
  • Bifragment gap carving (BGC). For two-fragment files with a known footer, brute-force the gap size between header-fragment and footer-fragment, validating each reconstruction. Works well for JPEG/PDF where a decoder gives a clean pass/fail signal.
  • SmartCarving. For 3+ fragments, statistical/content models reassemble pieces (Pal & Memon). Expensive and imperfect; expect partial recovery.
  • Validation is what makes fragmentation survivable. Without a decode/parse step, a fragmented carve yields a header followed by the wrong data — a file that opens to garbage. The validator is what tells truth from coincidence.
  • Know when to stop (Theme #5). A heavily fragmented file on a busy, partly-overwritten volume may be unrecoverable. "Partial JPEG recovered; lower two-thirds corrupt due to fragmentation across an overwritten region" is an honest, professional result — see the recovery limits discussion in Chapter 7.

False positives and short signatures

Signature length is everything. A 2-byte magic like BMP's 42 4D or MP3's FF FB collides constantly with random and compressed data — a gigabyte of entropy contains thousands of accidental FF FB pairs. Longer signatures (PNG's 8 bytes, SQLite's 16) are nearly false-positive-free. Mitigations: prefer the longest reliable header; require correct offset (a real ftyp is at byte 4, not scattered mid-file); and validate every hit.

Embedded and nested files

Files contain files. A JPEG carries a smaller JPEG thumbnail inside its EXIF; an OOXML/ODF document is a ZIP full of XML and embedded media; a PST holds thousands of messages and attachments; an installer wraps a CAB. A naïve scanner will surface the inner objects as independent carves — sometimes useful (an embedded image you wanted), sometimes noise (ten thumbnail fragments of one photo). Tools like binwalk exist specifically to recursively find and extract nested signatures. Decide per case whether nested extraction helps or clutters your evidence set.


A.14 Tool configuration and recipes

foremost / scalpel configuration

foremost and scalpel (a foremost fork) share a config grammar: extension case-sensitive max-size header [footer] [flag]. Bytes are C-escaped (\xNN); ? is a single-byte wildcard (foremost); REVERSE searches for the footer backward from the max-size window (ideal for PDF/ZIP, whose footers can repeat).

# ext  case  max-size    header (hex)                          footer (hex)            flag
  jpg   y    20000000    \xff\xd8\xff\xe0                      \xff\xd9
  jpg   y    20000000    \xff\xd8\xff\xe1                      \xff\xd9
  png   y    20000000    \x89PNG\x0d\x0a\x1a\x0a               \x49\x45\x4e\x44\xae\x42\x60\x82
  gif   y    20000000    \x47\x49\x46\x38\x39\x61              \x00\x3b
  gif   y    20000000    \x47\x49\x46\x38\x37\x61              \x00\x3b
  pdf   y    50000000    %PDF                                  %%EOF                   REVERSE
  doc   y    25000000    \xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1
  zip   y    50000000    PK\x03\x04                            PK\x05\x06              REVERSE
  rar   y    50000000    Rar!\x1a\x07\x00
  mov   y    100000000   ????ftyp
  sqlite y   50000000    SQLite\x20format\x203\x00
  htm   n    500000      <html                                 </html>
# Run foremost over a forensic image, into ./carved/, using your config:
foremost -v -T -c ./mycarve.conf -i suspect.dd -o ./carved

# Scalpel (same config grammar), with its preview/audit pass:
scalpel -c ./scalpel.conf -o ./carved suspect.dd

Limitation. The png footer \x49\x45\x4e\x44... and the ? wildcard make these carvers good but not structure-aware: foremost will happily carve to the first IEND even if ancillary chunks follow, and ????ftyp matches the marker but ignores box-length fields. For length-bearing formats (RIFF, ISO BMFF, SQLite), a parser-driven tool (PhotoRec, custom script) beats a flat config.

PhotoRec (signature carver, no config)

photorec            # interactive: pick disk → partition → file types → dest
photorec /d ./out /cmd suspect.dd search    # scripted run

PhotoRec ships ~480 built-in signatures and validates many of them (it parses, not just pattern-matches), which is why it recovers cleanly where flat carvers leave corrupt tails. It ignores the file system entirely — perfect after a reformat.

binwalk (firmware / nested signatures)

binwalk firmware.bin          # list every embedded signature + offset
binwalk -e firmware.bin       # extract them (recursively with -M)
binwalk -E firmware.bin       # entropy map: spot encrypted/compressed regions

file / libmagic (single-object typing)

file mystery.bin                       # human-readable type
file -i mystery.bin                    # MIME type
file -m ./custom.magic mystery.bin     # use a custom magic database

A custom magic rule (offset, type, test value, message):

0    string    \x89PNG\x0d\x0a\x1a\x0a    PNG image data
0    beshort   0xFFD8                     JPEG image data
0    string    SQLite\ format\ 3          SQLite 3.x database

YARA (hunting a signature across many files)

rule jpeg_at_start {
    meta:
        author = "DataField Project"
        desc   = "JPEG SOI marker at file start"
    strings:
        $soi = { FF D8 FF }
    condition:
        $soi at 0
}

rule masquerade_pe_in_image {
    strings:
        $mz  = { 4D 5A }
    condition:
        $mz at 0          // an .jpg/.png that is really a PE — see A.15
}

Python — identify a file and scan for carving offsets

import mmap

# (description, magic, offset, footer-or-None, extension)
SIGNATURES = [
    ("JPEG",            b"\xFF\xD8\xFF",                       0, b"\xFF\xD9", "jpg"),
    ("PNG",             b"\x89PNG\r\n\x1a\n",                  0, b"IEND\xAE\x42\x60\x82", "png"),
    ("GIF",             b"GIF8",                               0, b"\x00\x3B", "gif"),
    ("PDF",             b"%PDF-",                              0, b"%%EOF",  "pdf"),
    ("ZIP/OOXML/JAR",   b"PK\x03\x04",                         0, b"PK\x05\x06", "zip"),
    ("RAR v1.5-4",      b"Rar!\x1a\x07\x00",                   0, None,      "rar"),
    ("RAR v5",          b"Rar!\x1a\x07\x01\x00",               0, None,      "rar"),
    ("7-Zip",           b"7z\xBC\xAF\x27\x1C",                 0, None,      "7z"),
    ("GZIP",            b"\x1F\x8B\x08",                       0, None,      "gz"),
    ("BMP",             b"BM",                                 0, None,      "bmp"),
    ("TIFF (LE)",       b"II*\x00",                            0, None,      "tif"),
    ("TIFF (BE)",       b"MM\x00*",                            0, None,      "tif"),
    ("SQLite 3",        b"SQLite format 3\x00",               0, None,      "sqlite"),
    ("MS Office (OLE)", b"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1",   0, None,     "doc/xls/ppt"),
    ("PE/EXE",          b"MZ",                                 0, None,      "exe"),
    ("ELF",             b"\x7FELF",                            0, None,      "elf"),
    ("ISO BMFF",        b"ftyp",                               4, None,      "mp4/mov/heic"),
    ("RIFF",            b"RIFF",                               0, None,      "avi/wav/webp"),
    ("MP3 (ID3)",       b"ID3",                                0, None,      "mp3"),
]

def identify(path):
    """Return (description, extension) by content, or (None, None)."""
    with open(path, "rb") as f:
        head = f.read(64)
    for desc, magic, off, _footer, ext in SIGNATURES:
        if head[off:off + len(magic)] == magic:
            return desc, ext
    return None, None

def find_offsets(image_path, magic):
    """Yield every byte offset where `magic` appears (carving seed scan)."""
    with open(image_path, "rb") as f:
        mm = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
        i = mm.find(magic)
        while i != -1:
            yield i
            i = mm.find(magic, i + 1)
        mm.close()

# Example: locate every JPEG start in a raw image
# for off in find_offsets("suspect.dd", b"\xFF\xD8\xFF"):
#     print(f"JPEG SOI candidate at offset {off} (0x{off:X})")

The reusable, validated version of this scanner lives in Appendix B — Python Forensics Toolkit.

bash — find header offsets with grep/xxd

# First 16 bytes of a file, hex + ASCII:
xxd -l 16 mystery.bin

# Byte offsets of every JPEG SOI in a raw image (-b = byte offset, -a = treat as text):
grep -abo -P '\xFF\xD8\xFF' suspect.dd | head

# Hunt the ZIP local-file-header magic:
grep -abo -P 'PK\x03\x04' suspect.dd | head

PowerShell — read the first bytes on Windows

# Windows PowerShell 5.1:
$bytes = Get-Content -Path .\mystery.bin -Encoding Byte -TotalCount 16
# PowerShell 7+:
# $bytes = Get-Content -Path .\mystery.bin -AsByteStream -TotalCount 16
($bytes | ForEach-Object { '{0:X2}' -f $_ }) -join ' '

The full command-line cheat sheet for these tools (with flags and chain-of-custody notes) is Appendix H — Command-Line Reference.


A.15 Forensic use — extension / signature mismatch detection

The most common forensic application of this appendix is masquerade detection: comparing what a file is named against what its bytes say. A renamed or double-extension file is a deliberate hide — and detecting it is a quiet win for the examiner (Anchor Case #2, the employee covering their tracks).

import os

EXT_TO_MAGIC = {
    ".jpg":  [b"\xFF\xD8\xFF"],
    ".jpeg": [b"\xFF\xD8\xFF"],
    ".png":  [b"\x89PNG\r\n\x1a\n"],
    ".pdf":  [b"%PDF-"],
    ".docx": [b"PK\x03\x04"],
    ".zip":  [b"PK\x03\x04"],
    ".exe":  [b"MZ"],
}

def mismatch(path):
    ext = os.path.splitext(path)[1].lower()
    expected = EXT_TO_MAGIC.get(ext)
    if not expected:
        return None                      # unknown extension; no opinion
    with open(path, "rb") as f:
        head = f.read(8)
    return not any(head.startswith(m) for m in expected)   # True = suspicious

# A 'family_photo.jpg' that returns True is a file whose contents are NOT a JPEG.

Ethics Note. Signature analysis routinely surfaces files that have nothing to do with your authorized scope, and occasionally surfaces material you are legally obligated to report. Stay inside the warrant or engagement scope, and follow the mandatory-reporting and well-being guidance in Chapter 28 — Ethics. A magic-number scan that wanders outside scope is a finding you may not be allowed to keep.

Chain of Custody. Run signature analysis and carving on your verified working copy, never the original (Theme #2). Carving reads raw sectors; do it against the forensic image whose hash you recorded at acquisition (Chapter 14). Document the tool, version, config/signatures used, and the offsets recovered so the carve is reproducible and defensible.


A.16 Caveats and accuracy

  • Signatures evolve. Formats add brands and versions (note RAR4 vs RAR5, EWF vs EWF2, the growing ftyp brand list). When a header doesn't match anything here, dump 64–128 bytes with xxd/Format-Hex, search the bytes, and consult Gary Kessler's File Signatures Table and the libmagic source — both cited in the Bibliography.
  • Position matters. ftyp @4, ustar @257, CD001 @0x8001, ESE @4 — a byte string found at the wrong offset is probably coincidence, not a file.
  • Type ≠ integrity ≠ relevance. A matching signature means the bytes claim a format. It says nothing about whether the file is complete, uncorrupted, contiguous, or pertinent to your case. Validate, then judge.
  • This appendix pairs with Appendix G — File System Reference (where files live when metadata survives), Appendix B — Python Forensics Toolkit (working scanner/carver code), and Appendix H — Command-Line Reference (the carving tools). Terms used here are defined in the Glossary.

Reference companion to Chapter 7 — File Carving. Keep it next to the keyboard.