不认识的文件:用魔数识别文件类型,再选对分析工具
本页目录
结论先行:别看扩展名,看开头几个字节。Linux 和 macOS 上,file mystery 会直接说出格式,xxd -l 16 mystery 能看到原始文件头;Windows 上在 PowerShell 里用 Format-Hex -Path mystery -Count 16。拿这几个字节去对下面的表。如果开头是 PK,那它是个 ZIP 容器,到底是 APK、NuGet 包、JAR 还是 Office 文档,要看里面的文件名,不看开头字节。认出来以后,交给专门处理这种格式的工具。文末的对照表列出了本站的浏览器工具和对应的 REA 命令。
适合谁读:收到一个没有扩展名(或者扩展名不可信)的附件、构建产物或固件转储,想在打开之前先弄清楚它是什么的开发者。
读完你能掌握:
- 魔数是什么,为什么扩展名只能当参考。
- 开发和逆向中最常见的那些文件签名。
- 怎么区分各种基于 ZIP 的格式。
file、xxd、PowerShell 和 REA 的inspect-artifact对同一批文件分别怎么说。- 每种格式该用什么工具打开。
示例文件:一共 8 个,全是我自己做的或者来自开源发布,统一改名为 mystery-a … mystery-h,不让扩展名泄露任何信息:macOS 上用 clang 编译的 C 程序;OpenWrt 25.12.5 根文件系统里的 busybox;从 nuget.org 下载的 Newtonsoft.Json.dll 及其 .nupkg 包(MIT 许可);用 wat2wasm 生成、只有一个函数的 WebAssembly 模块;一个 gzip 压缩的文本文件;OpenWrt 的 SquashFS 镜像;以及 NuGet 包里的 PNG 图标。
把不认识的文件当成不可信的东西。先静态识别,不要双击、不要运行,也不要用会执行宏的程序打开。如果文件来自别人的系统,先确认你有权分析它。参见 REA 的 DISCLAIMER.md。
为什么开头字节比扩展名可靠
大多数二进制格式都以一个固定签名开头,也就是“魔数”,好让加载器和解析器尽快拒绝错误的输入:Linux 内核认 \x7fELF,Windows 认 MZ,浏览器的 WebAssembly 引擎认 \0asm。扩展名只是命名习惯,谁都能改;而且很多格式(APK、JAR、DOCX、NUPKG)用的是同一种容器。
签名也有局限。JSON、HAR、source map 这类文本格式没有魔数,只能靠解析来认。有些魔数会撞车,比如 CA FE BA BE 既是 macOS 通用二进制的开头,也是 Java .class 文件的开头。签名也只说明文件“自称”是什么:一个被截断或损坏的文件,开头可以完全正确,照样解析失败。
第 1 步:看文件头
$ file mystery-*
mystery-a: Mach-O 64-bit executable arm64
mystery-b: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-mips-sf.so.1, no section header
mystery-c: PE32 executable (DLL) (console) Intel 80386 Mono/.Net assembly, for MS Windows
mystery-d: Zip archive data, at least v2.0 to extract, compression method=deflate
mystery-e: WebAssembly (wasm) binary module version 0x1 (MVP)
mystery-f: gzip compressed data, was "note.txt", ... from Unix, truncated
mystery-g: Squashfs filesystem, little endian, version 4.0, xz compressed, 4626494 bytes, 1214 inodes, ...
mystery-h: PNG image data, 512 x 512, 8-bit/color RGBA, non-interlaced
这是 macOS 自带的 file 5.41。它用一个庞大的签名库读文件头,常常还会补充细节:CPU、.NET 标记、图片尺寸。但它说的每个词不一定都对:它说这个 gzip 文件 “truncated”,可 gzip -tv mystery-f 报的是 OK。真正说了算的是字节本身:
$ xxd -l 16 mystery-c
00000000: 4d5a 9000 0300 0000 0400 0000 ffff 0000 MZ..............
$ xxd -l 16 mystery-e
00000000: 0061 736d 0100 0000 0107 0160 027f 7f01 .asm.......`....
$ xxd -l 16 mystery-g
00000000: 6873 7173 be04 0000 286c 426a 0000 0400 hsqs....(lBj....
Windows 上没有 xxd,可以用 PowerShell 自带的 cmdlet。微软的 Format-Hex 文档 举的例子正好就是这个场景:把 PDF 改成一个陌生的扩展名,再用它认出来。
Format-Hex -Path .\mystery-c -Count 16
-Count 和 -Offset 需要 PowerShell 6.2 或更高版本。写这篇文章时我手边没有 Windows,这条命令没有实际运行,输出格式请以官方文档为准。
第 2 步:对照签名
下表是我的示例文件,加上几个常见的相关格式。凡是标了示例名的行,都在那个文件上用 xxd 核对过。
| 开头字节(十六进制) | ASCII | 格式 | 示例 |
|---|---|---|---|
7F 45 4C 46 |
.ELF |
ELF:Linux、Android .so、大多数固件程序 |
mystery-b |
4D 5A |
MZ |
PE/COFF:Windows EXE、DLL、.NET 程序集(PE\0\0 头的偏移存在 0x3C 处) |
mystery-c |
CF FA ED FE / CE FA ED FE |
Mach-O 64 位 / 32 位,小端 | mystery-a |
|
CA FE BA BE |
通用 Mach-O 或 Java class | ||
50 4B 03 04 |
PK.. |
ZIP 及所有基于 ZIP 的格式 | mystery-d |
00 61 73 6D |
.asm |
WebAssembly 模块(后 4 字节是版本) | mystery-e |
1F 8B |
gzip | mystery-f |
|
FD 37 7A 58 5A 00 |
.7zXZ. |
xz | (用 xz 生成) |
68 73 71 73 |
hsqs |
SquashFS 小端(大端是 sqsh) |
mystery-g |
27 05 19 56 |
U-Boot legacy uImage(固件内核) | OpenWrt .bin |
|
89 50 4E 47 0D 0A 1A 0A |
.PNG.... |
PNG | mystery-h |
62 70 6C 69 73 74 30 30 |
bplist00 |
Apple 二进制 plist | |
25 50 44 46 |
%PDF |
PDF(微软 Format-Hex 的例子) |
签名在偏移 0 是最简单的情况。固件会把好几种格式首尾相接地拼在一起,SquashFS 可能从文件中间几 MB 处才开始。这种情况要用会搜索整个文件的扫描器,见 Binwalk 3 使用指南。
第 3 步:拆开 ZIP 家族
PK\x03\x04 只能说明它是 ZIP。至于是哪一种 ZIP,要列出里面的条目:
$ unzip -l mystery-d | head
1104 03-08-2023 07:01 LICENSE.md
2413 03-08-2023 07:06 Newtonsoft.Json.nuspec
8956 03-08-2023 07:01 packageIcon.png
653 03-08-2023 07:06 [Content_Types].xml
580880 03-08-2023 07:09 lib/net20/Newtonsoft.Json.dll
有 .nuspec,再加上 lib/<框架>/ 目录,就是 NuGet 包。常见情况的特征文件:
| ZIP 里有 | 它是 |
|---|---|
AndroidManifest.xml、classes.dex、resources.arsc |
Android APK |
base/manifest/AndroidManifest.xml、BundleConfig.pb |
Android App Bundle(AAB) |
Payload/<Name>.app/ |
iOS IPA |
META-INF/MANIFEST.MF 加 .class 文件 |
Java JAR |
*.nuspec、lib/<tfm>/ |
NuGet 包 |
[Content_Types].xml 加 word/、xl/ 或 ppt/ |
Office DOCX、XLSX、PPTX |
AppxManifest.xml |
MSIX / AppX |
这一步各家工具做得不一样。REA(morluto 的开源项目)6.4.0 的 inspect-artifact 先从字节判断是不是 ZIP,然后按扩展名确定子类型:.apk、.ipa、.msix/.msixbundle、.appx/.appxbundle,其余都算普通 zip(逻辑在 dist/domain/zipPackageFormat.js)。我对 mystery-d 运行它,得到 root_format: "zip",里面 8 个 DLL 按各自的字节被归为 pe。再把同一个 NuGet 包复制成 renamed.apk,它就报 root_format: "apk"。字节一模一样,结论却不同,所以 ZIP 的子类型最好自己列一下条目再下结论。
本站的 APK/AAB 分析工具 看的是内容。把这个 NuGet 包丢进去,它照常打开 ZIP,然后报 “No AndroidManifest.xml was found.”(中文界面为“没有找到 AndroidManifest.xml。”)。它区分 APK 和 AAB 的依据是有没有 AndroidManifest.xml 或 base/manifest/AndroidManifest.xml,和文件名无关。
第 4 步:让 REA 给出全貌
对于原生程序和容器格式,rea inspect-artifact <path> 按字节分类,还会建议下一步做什么。下面是 REA 6.4.0 在 macOS 上对每个示例的结果:
| 示例 | root_format |
建议的下一步 |
|---|---|---|
mystery-a(Mach-O) |
mach-o |
open_binary |
mystery-b(ELF) |
elf |
open_binary |
mystery-c(.NET DLL) |
pe |
先 inspect_managed_artifact,再 open_binary |
mystery-d(NuGet) |
zip(图里 25 个节点) |
无 |
mystery-e、-f、-g、-h |
报错:“Cannot open artifact: unsupported binary format.” |
对 PE 文件,REA 附了一条低置信度的假设:“The PE artifact may contain managed CLI metadata or native code; inventory bytes alone do not distinguish them.” 这就是它建议先做托管检查的原因。inspect-artifact 本质上是归档和应用包的清点工具,不是通用的文件识别器:WebAssembly、gzip、SquashFS、图片都不在它的范围内,所以第一步还是 file 和 xxd。另外,它对 .pkg(xar!)和 .dmg(koly 尾部标记)的识别也要求扩展名匹配。REA 的安装见 REA 入门:安装并接入 AI 编程工具。
第 5 步:用对的工具打开
认出格式后,按下表去找工具。本站的浏览器工具在 Web Worker 里本地解析文件,不上传。2026-10-14 我用二进制、.NET、WASM、APK、ASAR 这几个工具的分析代码跑了示例文件(结果见表后),其余行列的是该格式对应的工具和命令。
| 格式 | 本站浏览器工具 | REA 6.4.0 | 相关教程 |
|---|---|---|---|
| ELF、PE、Mach-O | 原生二进制概览 | inspect-artifact,再用 Ghidra 跑 analyze |
ELF / PE / Mach-O 在线查看 |
| .NET 程序集(带 CLI 头的 PE) | .NET 元数据与 IL 查看器 | inspect-managed-artifact |
查看 .NET DLL 的目标框架 |
| APK / AAB(ZIP) | APK/AAB 分析工具 | inspect-android-package |
解包 APK 或 AAB |
| WebAssembly | WASM 转 WAT | 无 | 查看 WebAssembly |
Electron app.asar |
ASAR 查看器 | inspect-artifact(需要 .asar 文件名) |
解包 ASAR 文件 |
| HAR(JSON)或 Fiddler SAZ(ZIP) | HAR 分析工具 | inspect-web-network-capture |
HAR 文件分析指南 |
| JavaScript source map(JSON) | Source map 工具 | trace-web-source-location |
从打包代码还原源码 |
| 固件(uImage、SquashFS 等) | 无 | inspect-firmware-regions、extract-firmware(仅 Linux) |
从固件里提取 SquashFS |
| EVM 合约字节码(十六进制文本) | EVM 选择器提取 | inspect-evm-interface |
EVM 函数选择器 |
几个实测结果:
- 原生二进制概览接受任何文件,按魔数判断。它打开了
busybox(ELF32、MIPS、大端、已 strip),对 SquashFS 镜像和 WASM 模块报 “unknown magic”。 - .NET 查看器把
Newtonsoft.Json.dll读成 PE32,标志为ILONLY和STRONGNAMESIGNED,元数据版本v4.0.30319;对 Mach-O 文件则报“不是 PE 文件(缺少 MZ/PE 头)”。 - WASM 转 WAT把
mystery-e解析为版本 1,只有一个导出函数add,类型(i32, i32) -> (i32)。 - ASAR 查看器拒绝了 NuGet 的 ZIP,报“不是 ASAR 归档”。ASAR 没有固定魔数,工具检查的是前 16 字节能否构成它的 size pickle 和 header pickle。
.NET、WASM、ASAR、APK 这几个页面的文件选择框按扩展名过滤(.dll,.exe、.wasm、.asar、.apk,.aab)。文件没有扩展名的话,直接拖到页面上就行,工具检查的是内容,不是文件名。
常见问题
签名对得上,文件还可能是别的东西吗? 可能。多格式文件(polyglot)能同时是两种合法格式,在别的文件末尾拼接 ZIP 数据也很常见。偏移 0 的签名决定文件会被怎么加载,但不代表它包含的全部内容。
文本文件怎么办?
文本文件没有魔数。看它是不是合法 JSON(HAR 和 source map 都是 JSON),有没有 shebang(#!),或者让 file 根据内容猜。
Windows 上有 file 命令吗?
默认没有。用 Format-Hex 配合上面的表,或者在 WSL 里用 file。
为什么 REA 把我的 .zip 识别成 apk?
对 ZIP 容器,6.4.0 按扩展名确定子类型。把文件改回正确的名字,或者先列一下条目。
授权声明:只识别和分析你自己的文件、开源软件、CTF 题目,或你有权检查的文件。
下一步
- 深入原生二进制:ELF / PE / Mach-O 在线查看
- 内含多种格式的固件:从固件 .bin 里提取 SquashFS
- 安装 REA 并接入你的 agent:REA 入门
- 全部浏览器工具:工具