文件魔数速查:前 8 字节决定一切

· 约 4 分钟 🔬 Hex 二进制查看

文件扩展名是给人看的,魔数(magic number)才是给程序看的。前几字节就能识别一个文件是 PNG / JPEG / PDF / ZIP 还是别的什么——这是计算机识别文件类型的金标准。

为什么需要魔数

操作系统和大多数程序都不信任扩展名:

  • macOS Finder 显示缩略图先看魔数
  • Linux file 命令完全靠魔数(不看扩展名)
  • 浏览器 Content-Type sniffing 看响应体前几字节
  • 上传文件的服务器要校验魔数防 webshell

shell.php 命名为 cat.jpg 上传,再通过 URL 执行 PHP——是经典漏洞。正确防御:服务端验证文件实际是不是 JPEG(看魔数 + 解码尝试),不光看扩展名。

30 个常见格式速查表

图片

格式魔数(hex)魔数(ASCII)
PNG89 50 4E 47 0D 0A 1A 0A‰PNG\r\n\x1A\n
JPEGFF D8 FF-
GIF87a47 49 46 38 37 61GIF87a
GIF89a47 49 46 38 39 61GIF89a
BMP42 4DBM
WebP52 49 46 46 ?? ?? ?? ?? 57 45 42 50RIFF....WEBP
TIFF (LE)49 49 2A 00II*\0
TIFF (BE)4D 4D 00 2AMM\0*
HEIC?? ?? ?? ?? 66 74 79 70 68 65 69 63....ftypheic
AVIF?? ?? ?? ?? 66 74 79 70 61 76 69 66....ftypavif
ICO00 00 01 00-
PSD38 42 50 538BPS

文档 / 容器

格式魔数ASCII
PDF25 50 44 46 2D%PDF-
ZIP / DOCX / JAR / APK50 4B 03 04PK\x03\x04
RAR (v1.5+)52 61 72 21 1A 07 00Rar!\x1A\x07\x00
RAR552 61 72 21 1A 07 01 00Rar!\x1A\x07\x01\x00
7Z37 7A BC AF 27 1C7z¼¯'\x1C
TAR (POSIX)offset 257: 75 73 74 61 72ustar
GZIP1F 8B-
BZIP242 5A 68BZh
XZFD 37 7A 58 5A 00\xFD7zXZ\0
ZSTD28 B5 2F FD-

音频 / 视频

格式魔数ASCII
MP3 (with ID3v2)49 44 33ID3
MP3 (no ID3)FF FB / FF F3 / FF F2-
FLAC66 4C 61 43fLaC
OGG4F 67 67 53OggS
WAV52 49 46 46 ?? ?? ?? ?? 57 41 56 45RIFF....WAVE
MP4 / HEIF?? ?? ?? ?? 66 74 79 70....ftyp
MKV / WebM1A 45 DF A3EBML header

可执行 / 库

格式魔数ASCII
Windows PE (EXE/DLL)4D 5AMZ
Linux ELF7F 45 4C 46\x7FELF
macOS Mach-O 64 (LE)CF FA ED FE-
macOS Universal BinaryCA FE BA BE-
Java classCA FE BA BE同 Universal Binary(按字节长度区分)
WebAssembly00 61 73 6D\0asm

数据库 / 数据

格式魔数ASCII
SQLite53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00SQLite format 3\0
Parquet末尾 50 41 52 31末尾 PAR1
HDF589 48 44 46 0D 0A 1A 0A-

字体

格式魔数ASCII
TTF00 01 00 00-
OTF4F 54 54 4FOTTO
WOFF77 4F 46 46wOFF
WOFF277 4F 46 32wOF2

为什么 PNG 魔数这么诡异

89 50 4E 47 0D 0A 1A 0A 看起来像随机字节,实际是精心设计

  • 89 —— 高位 1 的非 ASCII 字节,让 7-bit 文本传输(如老 SMTP)无法保留,触发明确错误而不是悄悄破坏
  • 50 4E 47 —— “PNG” 的 ASCII,便于人眼识别
  • 0D 0A —— Windows 换行 CRLF,FTP 文本模式会把它转换成 0A
  • 1A —— DOS 文件结束符(Ctrl+Z)—— 在 Windows type 命令下会让输出停止
  • 0A —— Unix 换行 LF —— FTP 文本模式会把它转换成 0D 0A

整套设计的目标——传输过程中任何一种字节级损坏都会破坏魔数,立即被检测到。这是 1996 年 PNG 设计的远见——比同期 GIF / JPEG 的简单魔数好得多。

怎么用 Hex 工具识别陌生文件

打开 Hex 二进制查看,拖入文件:

  1. 看第一行第一组 —— 16 个字节,对照上面表格
  2. 工具自动识别 + 展开结构树 —— 主流格式直接给出 chunk / box / segment 列表
  3. 滚到末尾验证 —— 看格式必需的尾标记是不是完整

实战例子 1:文件没扩展名

拖入后第一行 89 50 4E 47 0D 0A 1A 0A —— PNG。后面工具展开 IHDR/IDAT/IEND chunk,能看到尺寸、位深度、颜色类型。

实战例子 2:扩展名是 .docx 但打不开

拖入后看到 50 4B 03 04 —— ZIP。尝试解压看结构——如果有 [Content_Types].xml + word/document.xml 是正常 DOCX;只有 META-INF/MANIFEST.MF 是 JAR;都没有就是普通 ZIP 文件被改了扩展名。

实战例子 3:怀疑图片里嵌了别的东西

拖入 JPEG 后跳到末尾。正常应当以 FF D9 结束。如果 FF D9 后面还有几 KB / 几 MB 字节——很可能是 polyglot 隐写。搜 50 4B 03 04(ZIP 魔数)能直接发现嵌入的 ZIP 附件。

实战例子 4:可执行文件来源识别

拖入 .exe 看到 4D 5A —— Windows PE。继续看 0x3C 偏移处的 PE header 偏移,跳过去看 machine type 字段——4C 01 = i386,64 86 = AMD64,AA 64 = ARM64——能立刻知道是哪个架构编译的。

真实世界的安全意义

魔数是文件类型识别的硬基础

  • 杀毒软件扫描时按魔数走对应解析器
  • 沙箱判断是不是动态可执行
  • CDN的 Content-Type 自动判断
  • 邮件附件过滤真正的 EXE 即使改成 .txt 也能拦下
  • 取证分析恢复无扩展名的删除文件靠魔数

你也应该这样做 —— 上传文件的服务端别只看扩展名,前几字节比对魔数白名单是基本卫生。

配套工具

下次拿到一个陌生二进制文件,第一步永远是看魔数。八字节定一切。

❓ 常见问题

为什么不能信任文件扩展名?

扩展名是给文件管理器看的,不是给程序看的——任何人能 mv photo.jpg photo.png,文件内容不变但扩展名换了。真正的程序读文件先看魔数——浏览器显示图片时不会信任 .png 扩展名,而是读前 8 字节判断 89 50 4E 47 0D 0A 1A 0A 才认为是 PNG。安全场景必须查魔数——上传文件时只查扩展名是经典漏洞,攻击者把 PHP shell 命名为 .jpg 上传后通过 URL 执行;正确做法是同时验证扩展名 + 魔数 + MIME(最可信的是魔数)。Linux 的 file 命令、macOS 的 Quick Look、Web 浏览器的 Content-Type sniffing 全靠魔数。

几个字节才算"魔数"?为什么有的格式只 2 字节有的 16 字节?

长度由格式设计者决定——目标是"在合理字节数内能唯一区分"。2 字节:JPEG FF D8、ZIP 50 4B、Mach-O FE ED FA CE——历史早期 + 设计极致简洁。4 字节:PDF %PDF、TIFF 49 49 2A 00 / 4D 4D 00 2A、AVI/WAV RIFF——主流分水岭。8 字节:PNG 89 50 4E 47 0D 0A 1A 0A——故意混入非 ASCII 字节(0x89、0x1A)和换行符,目的是检测传输过程中的 ASCII / 二进制模式错误——FTP 文本模式传输会把 0x0D 0x0A 互转,把 0x1A(DOS 文件结尾标记)当文件结束,魔数破坏了立刻能查出。16+ 字节:少数严格格式如 SQLite header 53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00("SQLite format 3\0")。

改了文件后缀但魔数没改,能正常打开吗?

取决于程序怎么处理——(1) 图片浏览器 / 编辑器几乎都先看魔数:把 cat.jpg 改成 cat.png 仍能在 Finder / Explorer 双击打开(系统按魔数选默认程序);(2) 网络传输:HTTP 协议看 Content-Type 头,浏览器渲染图片或下载行为按 Content-Type 决定;(3) 某些笨工具只看扩展名,把改后缀的文件当那种类型解析,会立刻报错——这其实是"feature",不是 bug,告诉用户"这文件不对劲";(4) Office / Adobe 系列通常也看魔数兼容用户瞎改后缀的情况。结论——绝大多数现代程序看魔数,但某些 CLI 工具或脚手架严格看扩展名,所以保留正确扩展名仍是好习惯。

ZIP / DOCX / JAR / APK 用同样魔数,怎么区分?

它们物理上都是 ZIP 文件——魔数都是 50 4B 03 04(PK + version)。区分方式是看内部结构——(1) DOCX / XLSX / PPTX:解压后第一个文件是 [Content_Types].xml,主目录有 word/xl/ppt/ 等;(2) JAR:解压后有 META-INF/MANIFEST.MF;(3) APK:JAR 的子集,多了 AndroidManifest.xmlclasses.dex;(4) EPUB:解压后有 META-INF/container.xml + 目录指向 OPF 文件;(5) 普通 ZIP:上述都没有。file --mime-type 命令对 Office 系会输出 application/vnd.openxmlformats-officedocument.wordprocessingml.document 等具体类型,就是按这个判断的。Hex 工具看到 50 4B 后再展开中央目录看文件名就能识别。

为什么有些 GIF / JPEG 文件后面还有别的内容?

叫做 "polyglot" 或 "stego" —— 多种格式合二为一。常见情况——(1) 图片末尾追加 ZIP:JPEG 在 EOI(FF D9)后追加 ZIP 文件,浏览器只看到图片,但 unzip 工具能解出附件——CTF 题和图片隐写常用;(2) Polyglot 文件:精心构造的字节序列同时是 GIF 和 PDF 和 ZIP——多用于绕过过滤;(3) EXIF 巨型 thumbnail:JPEG 里 APP1 EXIF 段嵌一张 thumbnail JPEG;(4) PNG iTXt 段嵌入数据:合法但被滥用做隐写。Hex 工具能直观看到——文件应该结束的位置(如 PNG 的 IEND)后面还有字节就值得警惕,可能是隐藏 payload。

PE / Mach-O / ELF 三大可执行文件格式怎么认?

Windows PE4D 5A("MZ",致敬 PE 设计者 Mark Zbikowski),后面跟 DOS stub,0x3C 偏移处是 PE header 的偏移,PE header 起始 50 45 00 00("PE\0\0")。macOS Mach-O:4 个魔数选一——FE ED FA CE (32-bit BE) / FE ED FA CF (64-bit BE) / CE FA ED FE (32-bit LE) / CF FA ED FE (64-bit LE)。Linux ELF7F 45 4C 46("\x7FELF"),紧跟一字节 EI_CLASS 标志位(1=32 / 2=64)和一字节 EI_DATA(1=LE / 2=BE)。Universal Binary(macOS 多架构):CA FE BA BE("cafebabe"),后面是 fat header 列表。Hex 工具识别这些后能进一步看 machine type(i386 / AMD64 / ARM64)和 entry point。

文件被截断了能从魔数看出来吗?

部分格式能——PNG / JPEG / GIF / ZIP / PDF / GZIP 都有明确的"结束标记",没看到说明被截了。PNG:必须以 49 45 4E 44 AE 42 60 82(IEND chunk)结尾——8 字节固定值;JPEG:必须以 FF D9(EOI)结尾;GIF:必须以 3B(trailer)结尾;ZIP:必须包含 EOCD 记录 50 4B 05 06(在文件末尾向前最多 64 KB 内);PDF:必须以 %%EOF 结尾;GZIP:末尾 8 字节是 CRC32 + ISIZE,CRC 不对说明数据损坏。Hex 工具的"跳到末尾"功能能直接验证。文件中间数据损坏比较难只靠魔数发现,要按格式 spec 验证 chunk 校验和。

🔬 打开 Hex 二进制查看 拖入任意文件→十六进制+ASCII 三栏视图·魔数识别·PNG/JPEG/GIF/PDF/ZIP/GZIP 结构解析·点击 chunk 高亮·本地不上传