文件魔数识别

把文件拖进来,看它开口的第一句话——文件头里的那几个固定字节才是真正的身份,改扩展名骗不了它。文件只在本地读取。

对任何类型的文件都有效,包括被改了后缀的、没有后缀的、以及伪装成图片的可执行文件。只读取开头 64 KB,几十 GB 的镜像也是秒出结果。

还没选文件,把文件拖到这一块或者点「选择文件」。

扩展名是给人看的,文件头才是给程序看的

在绝大多数系统里,扩展名只是文件名里的一段普通文本,随便改。Windows 默认隐藏已知类型的扩展名,于是 发票.pdf.exe 会显示成「发票.pdf」,这是钓鱼邮件最常用的一招。上传校验也常常栽在这里:只检查后缀名,攻击者把 webshell 命名成 photo.jpg 就能绕过,而服务器的图片处理库只要按内容解析就可能出问题;反过来只允许 jpg 却不知道有些相机生成的是 image/jpeg 之外的类型,也会误拦正常文件。

正确的做法是读取内容判定类型,也就是这个工具做的事:服务端用 libmagic(file 命令背后就是它)、Python 的 python-magic、Java 的 Apache Tika,或者各语言的文件类型库;然后以「内容识别的类型」为准做白名单,扩展名只作为辅助。更进一步还要校验结构是否真的合法——魔数对了不代表文件合法,把 HTML 内容前面拼上 GIF89a 就是经典的图片马。

为什么要钻进 ZIP 里看

DOCX、XLSX、PPTX、ODT、EPUB、JAR、APK、以及 Chrome 的 crx、VS Code 的 vsix,全都是 ZIP 容器,前四个字节一模一样(PK\x03\x04)。只认魔数的话它们会全部被报成「ZIP 压缩包」,等于没识别。

所以工具会继续读 ZIP 的本地文件头,把前几个条目的名字取出来比对:出现 [Content_Types].xml 且带 word/ 前缀就是 DOCX,带 xl/ 是 XLSX,带 ppt/ 是 PPTX;有 AndroidManifest.xml 加 classes.dex 就是 APK;有 META-INF/MANIFEST.MF 是 JAR;有一个不压缩的 mimetype 条目写着 application/epub+zip 就是 EPUB。这正是 file 命令和系统里「文件类型」显示的判断依据。

需要说明的是,这套判断只读头部 64 KB。如果 ZIP 的第一个条目非常大(比如一个几百 MB 的视频被打成 APK 的资源包),后续条目名会落在读取窗口之外,这时只能给出「ZIP 容器」的结论,并在下面把能读到的条目列出来。

你手里的文件可能同时是两种东西

这叫 polyglot(多态文件):把 GIF 的头部拼在 JavaScript 前面,浏览器当脚本加载时忽略报错继续执行,当图片加载时也能显示;再比如同一个文件既是合法 ZIP 又是合法 PDF。它常被用来绕过只检查单一格式的校验链,比如上传一个「图片」实则会被当作脚本执行。防御思路是:不要依赖单一判定,上传后重新编码(把图片解出来再存成新文件)能彻底洗掉藏在元数据或头部里的多余内容,比任何黑名单都可靠。

这个工具的权威性边界

签名表是手工整理的,取值来自各家格式规范和一些公开资料,覆盖了常见格式,但工业界最全的库是 libmagic 的 magic 数据库(几千条规则,还包含大量「看偏移 2 的字符串」这类启发式)。所以本工具适合做快速判断、排查「这文件到底是什么」,不适合当作安全产品里唯一的类型判定环节。对于没有固定签名的格式(纯文本、CSV、各种源码、以 XML 为基础的格式),这里只能给出兜底结论;判断文本还是二进制用的依据是「这段字节能否按 UTF-8 正常解码」,所以一个 UTF-8 编码的 .txt 会报成纯文本,而 GBK 编码的中文文本可能被误判为未知二进制——这一点请注意。