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.jpgwhose first bytes are4D 5Ais 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 FFserve 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
@Nannotation appears, the signature is at byte offset 0 (the very start of the file).@4means "starting at byte 4,"@0x8001means byte 33,793. Offsets matter: anftypbox and austarmarker 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
IIvsMM; PCAPD4 C3 B2 A1vsA1 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 46 … 57 45 42 50 |
RIFF…WEBP |
— | 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 |
|---|---|---|---|---|---|
25 50 44 46 2D |
%PDF- |
25 25 45 4F 46 |
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 04 … 6D 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 04 … mimetypeapplication/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 46 … 57 41 56 45 |
RIFF…WAVE |
— | wav | RIFF; size @4 (LE). See RIFF table. |
| AIFF | 46 4F 52 4D … 41 49 46 46 |
FORM…AIFF |
— | 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 46 … 41 56 49 20 |
RIFF…AVI |
— | 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
mimetypeentry first so thatfile(1)can identify the type at a fixed offset without decompressing anything. That is why the EPUB stringmimetypeapplication/epub+zipsits predictably at offset 30 — a gift to bothlibmagicand 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 walksftyp → 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) |
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
%%EOFmay be followed by whitespace and is repeated in incrementally-updated files; PNG'sIENDmay 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 |
|
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 FF…FF 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
pngfooter\x49\x45\x4e\x44...and the?wildcard make these carvers good but not structure-aware: foremost will happily carve to the firstIENDeven if ancillary chunks follow, and????ftypmatches 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
ftypbrand list). When a header doesn't match anything here, dump 64–128 bytes withxxd/Format-Hex, search the bytes, and consult Gary Kessler's File Signatures Table and thelibmagicsource — 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.