news 2026/5/11 22:23:48

OOXML 文档格式剖析:哈希、ZIP结构与识别

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OOXML 文档格式剖析:哈希、ZIP结构与识别

OOXML标准

Office Open XML(缩写:Open XML、OpenXML或OOXML),是微软(Microsoft)开发的一种基于 XML以ZIP格式压缩的电子文件范式,用于支持文件、表格、备忘录、幻灯片等文件格式。

  • 标准化:2006 年成为 ECMA 标准(ECMA-376),2008 年进一步成为国际标准(ISO/IEC 29500)。
  • 替代旧格式:取代了早期 Office 使用的私有二进制格式(.doc.xls.ppt),使文档结构更加开放和透明。
  • 本质特征:OOXML 不是“新的独立压缩格式”,而是建立在 ZIP 容器和 OPC(Open Packaging Conventions,开放包装约定)之上的 XML 文档包

一、哈希值与后缀名验证

修改文件后缀名不会改变文件内容本身。因此,同一个 OOXML 文件从.docx/.xlsx/.pptx改名为.zip后,其哈希值应保持一致

改后缀这一操作,改变的是操作系统或软件如何“解释”该文件,而不是文件本体的二进制内容

利用哈希值验证其原后缀标准与改为.zip用于查看二进制的对比

这也是为什么:

WordOOXML.docxWordOOXML.zip,如果只是重命名而没有二次保存或重新打包,那么其MD5SHA1SHA256等哈希值应一致。

二、文件结构

OOXML 文件本质上是一个ZIP 压缩包。如果你将.docx.xlsx.pptx的后缀改为.zip并解压。

例如:docx文件后缀改为zip后会看到类似这样的内部结构:

document.docx ├── [Content_Types].xml ← 定义包内各部件的 MIME / Content-Type ├── _rels/ ← 关系文件,描述各部件之间的引用关系 │ └── .rels ├── word/ ← Word 文档主体内容 │ ├── document.xml ← 实际正文内容 │ ├── styles.xml ← 样式定义 │ ├── theme/ │ └── media/ ← 嵌入图片、音频、视频等资源 └── docProps/ ← 文档属性(作者、标题、创建时间等)

对于不同 OOXML 子类型,主目录会有所变化:

  • Word 文档:word/
  • Excel 工作簿:xl/
  • PowerPoint 演示文稿:ppt/

2.1 核心路径说明

文件路径说明
[Content_Types].xmlOPC/OOXML 包的核心标识文件,定义各部件内容类型
_rels/.rels包级关系定义文件,用于指定主文档部件
docProps/文档属性目录,常见为core.xmlapp.xml
word/document.xmlWord 文档主体
xl/workbook.xmlExcel 工作簿主体
ppt/presentation.xmlPowerPoint 演示文稿主体

2.2 结构层面的关键结论

  • 仅凭文件扩展名不足以认定 OOXML

  • 仅凭PK 03 04也不足以认定 OOXML的具体指向

  • 要严格认定某文件是 OOXML,除了 ZIP 容器外,还应检查其是否满足 OPC 结构,即至少存在:

    • [Content_Types].xml
    • _rels/.rels

  • 在此基础上,再根据下面内容进一步区分 Word、Excel、PowerPoint,分别为word/xl/ppt/

三、Magic Bytes

3.1.zip

PKZIP 最初由 Phil Katz编写,PKZIP是一种文件归档计算机程序,以引入流行的ZIP文件格式而闻名。

  • .zip.apk.jar.docx.xlsx.pptx.odt.epub.xpi

FormatExtension(s)Hex SignatureASCII/StringNotes
ZIP (.zip, .apk, .jar, .docx, .xlsx, .pptx)ZIP 固定签名50 4B 03 04PK..Standard ZIP archive
ZIP (empty)中央目录结束记录(EOCD)50 4B 05 06PK..Empty ZIP archive
ZIP (spanned)是另一类 ZIP 记录标记50 4B 07 08PK..Spanned ZIP archive

它们属于 ZIP 的不同结构位置,不是一段连续固定的起始魔术字节。

3.2 OOXML 魔术字节

普通未加密的 OOXML 文件(如docx/xlsx/pptx本质上是 ZIP 容器,因此:

  • OOXML 的基础容器魔术字节也是50 4B 03 04
  • 它没有像老式DOC/XLS/PPT那样独立、稳定、唯一的专属固定文件头

换言之:

50 4B 03 04可以说明该文件是ZIP 或 ZIP-based container,但不能仅凭这一点就断定它一定是 OOXML

3.2.1 样本不同产生不同

参考链接:The structure of a PKZip file

一般可见
50 4B 03 04 14 00 06 00
50 4B 03 04 0A 00 00 00
50 4B 03 04 14 00 01 00

这些字段会随着:

  • 压缩器实现差异、是否加密、压缩选项

  • 是否使用 data descriptor

  • 生成器不同(Microsoft Office、LibreOffice、WPS、第三方库、Python创建)而发生变化

3.2.2 为什么不能只靠文件头判断 OOXML

因为以下格式也都可能以50 4B 03 04开头:

  • .zip.apk.jar.docx.xlsx.pptx.odt.epub.xpi
  • 以及其他任意 ZIP-based 容器

因此:

  • PK 03 04只能说明“这是 ZIP 家族或 ZIP-based 容器”
  • 不能单独证明该文件是 OOXML

四、OOXML 的依据

4.1 步骤

(1)要认定某 ZIP-based 文件是 OOXML,应进一步检查:

  • [Content_Types].xml
  • _rels/.rels
  • docProps/
  • word/xl/ppt/

(2)推荐的识别优先级如下:

  1. 看文件头是否为50 4B 03 04
  2. 列出 ZIP 内部条目
  3. 检查是否存在[Content_Types].xml
  4. 检查是否存在_rels/.rels
  5. 根据主部件判断类型:
    • word/document.xml
    • xl/workbook.xml
    • ppt/presentation.xml
  6. 解析[Content_Types].xml进行最终确认

4.2 OOXML 常见类型与主部件

OOXML Format Family – ISO/IEC 29500 and ECMA 376

文件类型主目录主部件
docx/docm/dotx/dotmword/word/document.xml
xlsx/xlsm/xltx/xltm/xlamxl/xl/workbook.xml
pptx/pptm/potx/potm/ppsx/ppsm/ppam/sldx/sldmppt/ppt/presentation.xml或 slide 主部件

4.3 认识MIME

MIME(Multipurpose Internet Mail Extensions)是一种用于描述消息内容类型的标准,用以标识文档、文件或字节流的性质与格式。

MIME 消息可以包含文本图像音频视频以及其他应用程序特定的数据。

浏览器通常依据MIME 类型(而非文件扩展名)来决定如何处理 URL,因此 Web 服务器在响应头中设置正确的 MIME 类型至关重要。一旦配置有误,浏览器可能无法正确解析文件内容,导致网站功能异常,下载的文件也会被错误处理。

MIME 类型文件扩展名(文件名后缀)
application/vnd.openxmlformats-officedocument.wordprocessingml.document.docx
application/vnd.openxmlformats-officedocument.wordprocessingml.template.dotx
importosimportmimetypesimportzipfileimportxml.etree.ElementTreeasETfromtypingimportList,Tupledefget_file_mime_info(file_path:str)->Tuple[str,str,str]:""" 获取文件的 MIME 信息 """file_name=os.path.basename(file_path)_,ext=os.path.splitext(file_name)ifnotext:ext=""mime_type,_=mimetypes.guess_type(file_path)ifmime_typeisNone:mime_type="application/octet-stream"return(file_name,ext,mime_type)defget_ooxml_content_type(file_path:str)->str:""" 从 OOXML 文件中提取主文档部件的 ContentType """ooxml_extensions=('.docx','.docm','.dotx','.dotm','.xlsx','.xlsm','.xltx','.xltm','.xlam','.pptx','.pptm','.potx','.potm','.ppsx','.ppsm','.ppam','.sldx','.sldm')_,ext=os.path.splitext(file_path)ifext.lower()notinooxml_extensions:return"非OOXML文件"try:withzipfile.ZipFile(file_path,'r')aszf:if'[Content_Types].xml'notinzf.namelist():return"无Content_Types.xml"withzf.open('[Content_Types].xml')asf:tree=ET.parse(f)root=tree.getroot()# 定义命名空间ns={'ct':'http://schemas.openxmlformats.org/package/2006/content-types'}# 查找主文档部件# Word: /word/document.xml# Excel: /xl/workbook.xml# PowerPoint: /ppt/presentation.xmlmain_parts=['/word/document.xml','/xl/workbook.xml','/ppt/presentation.xml']forpart_nameinmain_parts:foroverrideinroot.findall('ct:Override',ns):ifoverride.get('PartName')==part_name:returnoverride.get('ContentType','')return"未找到主文档部件"exceptExceptionase:returnf"解析失败:{str(e)}"defprint_file_info(file_list:List[str])->None:""" 按指定格式输出文件信息 """print("文件列表信息:")print("-"*120)forfile_pathinfile_list:ifos.path.exists(file_path):file_name,ext,mime_type=get_file_mime_info(file_path)content_type=get_ooxml_content_type(file_path)print(f"\n【{file_name}】")print(f"文件名 - 后缀名 - MIME:{file_name}-{ext}-{mime_type}")print(f"文件名 - 后缀名 - Content_Types:{file_name}-{ext}-{content_type}")else:print(f"\n【{file_path}】")print(f"{file_path}- 不存在")print("-"*120)defscan_directory_files(directory:str=".")->List[str]:""" 扫描指定目录中的所有文件 """files=[]forentryinos.listdir(directory):entry_path=os.path.join(directory,entry)ifos.path.isfile(entry_path):files.append(entry_path)returnsorted(files)if__name__=="__main__":print("=== 扫描当前目录 ===")directory_files=scan_directory_files(".")print_file_info(directory_files)

五、特殊

在讨论 OOXML 魔术字节时,必须注意一个容易被忽略的问题:

  • 普通未加密 OOXML:外层通常是 ZIP,开头为50 4B 03 04
  • 某些加密的现代 Office 文档:外层可能被封装为 OLE/CFBF,开头会变成:
D0 CF 11 E0 A1 B1 1A E1

这意味着:

  • 如果仅靠PK 03 04去判断“所有 OOXML”,结论并不完整
  • 更准确的说法应是:
    • 普通未加密 OOXML 的外层容器头通常为 ZIP
    • 部分加密 OOXML 会表现为复合OLE文档内的加密OPC包存储。

六、参考依据

  • pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT

  • MSHTML & OOXML (.docx) Analysis | Oste’s Blog

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/11 22:17:39

5G与NVMe SSD如何重塑数据中心架构

1. 5G与NVMe SSD如何重塑现代数据中心架构过去十年间,数据中心经历了从集中式大型设施向分布式边缘架构的转型。根据IDC最新报告,到2025年全球将有超过75%的企业数据在传统数据中心或云之外的边缘位置处理。这一变革的核心驱动力来自两大技术革命&#x…

作者头像 李华
网站建设 2026/5/11 22:12:10

碧蓝航线Perseus补丁:零偏移设计实现全皮肤解锁的终极指南

碧蓝航线Perseus补丁:零偏移设计实现全皮肤解锁的终极指南 【免费下载链接】Perseus Azur Lane scripts patcher. 项目地址: https://gitcode.com/gh_mirrors/pers/Perseus 在碧蓝航线这款广受欢迎的海战游戏中,玩家们常常为那些精美的限定皮肤只…

作者头像 李华