1. 项目概述从一道CTF题到ZIP伪加密的真相最近在带新人刷BUUCTF的题目又遇到了那道经典的“ZIP伪加密”题。看着新手们对着加密的压缩包一筹莫展四处寻找“暴力破解”工具或者试图用“Ziperello”这类软件去撞密码结果当然是徒劳无功。这让我想起自己刚入门时踩过的坑也让我觉得有必要把“伪加密”这个看似神秘、实则原理简单的小技巧彻底讲透。今天我们就用最经典的十六进制编辑器WinHex手把手带你5分钟搞定ZIP伪加密并顺带把BUUCTF那道真题给破了。这不仅是CTF比赛中的一个小考点更是理解计算机底层数据存储、文件格式规范的绝佳入门案例。无论你是安全爱好者、逆向新手还是单纯对“为什么一个没密码的压缩包却提示要密码”感到好奇这篇实战指南都能让你豁然开朗。所谓“伪加密”顾名思义就是“虚假的加密”。它并没有使用任何复杂的加密算法如AES-256对文件内容进行变换而仅仅是通过修改ZIP文件格式中几个特定的标志位来“欺骗”解压软件让它误以为这个文件是加密的从而弹出一个输入密码的对话框。实际上文件的原始数据就明明白白地躺在那里只要你知道去哪里改、改什么瞬间就能让它“原形毕露”。这种方法在早期的CTF Misc杂项题目中非常常见考察的就是选手对常见文件格式的熟悉程度和基本的十六进制编辑能力。2. ZIP文件格式核心解析一切修改的基石要破解伪加密我们必须先成为“造物主”了解ZIP文件的内部构造。一个ZIP文件并非一团乱麻它有着非常严谨的结构主要由三大部分组成本地文件头Local File Header、文件数据File Data和中央目录Central Directory。而与我们今天的主题——“加密状态”息息相关的正是本地文件头和中央目录文件头中的两个关键字段。2.1 核心结构本地文件头与中央目录当你用压缩软件创建一个ZIP包时对于包内的每一个文件ZIP格式都会为它生成两部分元数据。首先是本地文件头它紧跟在每个文件的实际数据前面。你可以把它想象成文件的“身份证”里面记录了文件名、压缩方法、修改时间等基本信息当然也包括了最重要的通用位标记General Purpose Bit Flag。这个字段的长度是2字节16位每一位都代表一个特定的标志。其中第0位bit 0如果被设置为1就表示该文件使用了传统PKWARE加密一种较弱的加密方式。在伪加密中攻击者就是通过手动将这个bit从0改成1来“宣称”此文件已加密。其次是中央目录它位于ZIP文件的末尾部分可以看作是整个压缩包的“总目录”或“索引”。中央目录里为每个文件又保存了一份文件头信息Central Directory File Header其内容与本地文件头大部分是重复的也包括一个完全相同的通用位标记字段。这里有一个至关重要的细节大多数现代解压软件如Windows资源管理器、Bandizip、7-Zip等在判断一个文件是否加密时主要依据的是中央目录里的这个标志位而不是本地文件头的标志位。这就引出了伪加密的两种基本类型全局伪加密只修改了中央目录文件头中的加密位而本地文件头的加密位仍是0。用一些老旧的或行为特殊的解压软件比如某些命令行工具可能可以直接解压但用主流软件打开就会提示加密。完全伪加密同时修改了本地文件头和中央目录文件头中的加密位。这是最“逼真”的伪加密几乎所有软件都会认为它是加密的。注意我们后续的破解操作核心就是将这两个地方被置1的加密位重新修改为0。2.2 定位关键字段WinHex中的搜索技巧知道了要改哪里下一步就是找到它们。在WinHex中盲目滚动查找是不现实的。这里我们需要利用ZIP格式的另一个特性文件头签名。每一种结构都有其固定的、唯一的魔术数字Magic Number。本地文件头签名50 4B 03 04即PK.. PK是PKZIP创始人Phil Katz的缩写中央目录文件头签名50 4B 01 02中央目录结束标记50 4B 05 06EOCD End Of Central Directory在WinHex中我们可以使用“搜索 - 查找十六进制数值”功能CtrlF直接搜索504B0304来定位每一个文件的本地文件头开始位置。而中央目录则通常通过搜索504B0102来定位或者先找到EOCD (504B0506)因为它里面记录了中央目录的起始偏移量。找到这些签名后我们需要计算加密位在结构中的具体位置。以50 4B 03 04开头的本地文件头为例其标准结构如下偏移量从文件头开始计算为0偏移 0x00 - 0x03: 签名50 4B 03 04偏移 0x04 - 0x05: 解压所需版本偏移 0x06 - 0x07:通用位标记General Purpose Bit Flag-关键偏移 0x08 - 0x09: 压缩方法... 后续还有其他字段。所以加密位就位于文件头开始后的第6和第7个字节即偏移0x06和0x07。这是一个2字节的整数我们需要关注它的最低位bit 0。3. Winhex实战5分钟破解伪加密全流程理论铺垫完毕现在进入最激动人心的实战环节。请准备好你的WinHex和一个伪加密的ZIP文件你可以先尝试完成BUUCTF的题目来获取一个。3.1 第一步使用WinHex打开目标ZIP文件启动WinHex。点击菜单栏的“文件” - “打开”选择你的伪加密ZIP文件。文件内容将以十六进制右侧和ASCII左侧的形式展现在你面前。左侧的ASCII栏如果出现乱码是正常的因为压缩数据是非文本。3.2 第二步定位并修改中央目录的加密位首要目标如前所述现代解压软件主要看这里。搜索中央目录签名按下Ctrl F在弹出的对话框中选择“十六进制数值”在文本框中输入504B0102然后点击“确定”。WinHex会高亮显示找到的第一个位置这很可能就是中央目录的开始。提示如果文件内有多个文件中央目录里也会有多个504B0102的记录每个对应一个文件。我们通常从第一个开始检查。计算并检查加密位找到50 4B 01 02后从这组签名的第一个字节50开始计算偏移。50是偏移0。4B是偏移1。03是偏移2不对这是本地文件头的第三个字节。对于中央目录签名504B010250是签名第一部分。 更准确的方法是WinHex的界面左下角会显示当前光标所在的“偏移量”。将光标移动到50这个字节上记下这个偏移地址比如0x12345678。那么通用位标记就在这个地址再往后数6个字节的位置即0x12345678 0x06 0x1234567E。解读与修改将光标移动到计算出的地址例如0x1234567E你会看到两个字节例如09 00。这两个字节就是通用位标记。判断是否加密我们需要看这两个字节组成的16位整数的最低一位bit 0。在Little-Endian小端序PC常见存储中低位字节在前。所以09 00表示数值是0x0009二进制0000 0000 0000 1001。bit 0是1表示加密。另一个常见值是00 00表示未加密。01 000x0001同样表示加密。执行修改我们的目标是将bit 0从1变成0。对于09 00二进制1001减去1即可得到08 00二进制1000。对于01 00减去1得到00 00。直接在WinHex中双击这两个字节将其修改为08 00或00 00。3.3 第三步定位并修改本地文件头的加密位彻底清除为了确保万无一失我们最好把本地文件头的加密位也改掉。搜索本地文件头签名按下Ctrl F搜索504B0304。这会定位到第一个也可能是唯一一个文件的本地文件头开始。计算并检查加密位同样从50这个字节开始向后偏移6个字节。找到通用位标记。执行修改检查其值如果是09 00或01 00同样将其修改为08 00或00 00。3.4 第四步保存并验证点击菜单栏的“文件” - “保存”或直接按Ctrl S保存你对文件所做的修改。关闭WinHex。现在尝试用任意解压软件如Bandizip、7-Zip、WinRAR打开你刚才修改的ZIP文件。你会发现之前要求输入密码的提示消失了可以直接解压出里面的文件了实操心得在修改时务必确认你修改的是“通用位标记”General Purpose Bit Flag而不是其他字段。一个快速验证的方法是修改前后这个字段附近的其他字节如压缩方法、修改时间应该是没有变化的。如果你不小心改错了其他字节可能会导致ZIP文件损坏无法打开。此时别慌关闭时不保存重新打开原始文件再操作即可。4. BUUCTF真题“ZIP伪加密”实战解析现在我们把学到的技能应用到BUUCTF平台那道名为“ZIP伪加密”的经典题目上。这道题是绝佳的练手材料。下载题目附件从BUUCTF平台下载该题目的附件通常就是一个名为flag.zip或类似名称的文件。初步尝试直接双击用解压软件打开你会看到里面有一个文件比如flag.txt但尝试解压时软件会提示你输入密码。这符合伪加密的特征。使用WinHex分析用WinHex打开这个ZIP文件。首先搜索504B0102定位中央目录。你会发现通用位标记的值可能是09 00。再搜索504B0304定位本地文件头。你会发现这里的通用位标记可能是00 00。这正是一种典型的全局伪加密只在中央目录声明了加密本地文件头并未加密。所以我们只需要修改中央目录的那个09 00为08 00即可。执行修改与获取Flag在WinHex中将中央目录的09 00改为08 00。保存文件。关闭WinHex再次解压ZIP文件。此时应该可以毫无阻碍地解压出flag.txt。打开flag.txt里面包含的就是这道题的Flag格式通常为flag{...}或BUUCTF{...}。通过这道题你可以清晰地看到出题人是如何设置陷阱的也能深刻理解为什么只改一个地方就能“破解”密码。这比任何理论说教都来得直观。5. 深入探究伪加密的变种与高级技巧掌握了基础方法我们来看看一些更复杂的情况和相关的扩展知识让你在遇到“变种题”时也能游刃有余。5.1 多重文件与深度伪加密如果一个ZIP包里有多个文件并且每个文件都被设置了伪加密那么你需要对每一个文件的记录进行修改。具体步骤如下搜索第一个504B0304修改其后的加密位。按F3键“查找下一个”WinHex会定位到下一个本地文件头继续修改。重复此过程直到所有本地文件头修改完毕。转到文件末尾附近搜索504B0102修改第一个中央目录记录的加密位。再次按F3修改下一个中央目录记录直到所有记录修改完毕。这个过程略显繁琐但原理完全一样。在CTF比赛中为了增加难度出题人可能会将成百上千个无用文件与一个关键文件一起伪加密考验你的耐心和脚本能力当然用Python的zipfile库写个几行代码自动处理会更高效。5.2 使用010 Editor与模板解析WinHex是手动党的利器但对于想更直观、更专业分析文件格式的人来说010 Editor是更好的选择。它支持“模板”功能可以像解析数据结构一样解析文件。用010 Editor打开ZIP文件。点击菜单 “Templates” - “Run Template”选择内置的ZIP.bt模板。软件会自动解析整个ZIP结构并以树状图和结构体字段的形式展示出来。你可以直接看到每个LocalFileHeader和CentralDirectoryFileHeader结构体其中的gpFlag字段一目了然。你可以直接在解析视图里修改gpFlag的值比如将0x0009改为0x0008然后保存文件。这种方法避免了手动计算偏移量的麻烦不易出错尤其适合分析结构复杂的文件。5.3 伪加密与真加密的识别如何区分一个ZIP是伪加密还是真加密这里有几个关键点伪加密用WinHex等工具查看文件数据区50 4B 03 04签名之后直到文件数据结束的内容通常是可读的或有规律的如果是文本文件甚至能看到部分原文。因为数据本身未加密。通用位标记通常只设置加密位bit 0其他位可能为0。例如0x0009除了加密位bit 3也可能被设置表示有数据描述符这是正常情况。压缩方法字段通常是08 00Deflated或00 00Stored不压缩。真加密如传统PKZIP加密文件数据区的内容是完全随机、不可读的因为经过了加密运算。通用位标记的加密位bit 0同样为1。关键区别真加密的文件其文件数据部分是完全混乱的而伪加密的文件数据是完好的压缩流。真加密如AES-256加密WinRAR/7-Zip常用这属于强加密。通用位标记中不仅加密位为1还会使用特定的压缩方法值如63 00表示AES加密。数据区同样完全不可读。这种加密无法通过修改标志位破解只能依靠密码学手段或弱密码爆破。一个简单的识别流程拿到一个加密ZIP先用WinHex打开搜索504B0304看其后的加密位。如果是00 09之类再往后翻看一段数据如果数据看起来“不像乱码”比如有重复的0x00、0x780x9C等zlib压缩头特征那很可能是伪加密。如果数据完全是随机的字节那就是真加密了。6. 常见问题与排查技巧实录在实际操作和教学过程中我总结了一些新手最容易踩的坑和对应的解决方法。6.1 修改后ZIP文件损坏无法打开这是最常见的问题通常是因为改错了字节。症状用解压软件打开时提示“文件已损坏”或“不可预料的压缩文件末端”。原因排查偏移计算错误最可能的原因。请再次确认你是从50 4B 03 04或50 4B 01 02的第一个字节50开始向后数第6和第7个字节偏移6和7而不是从04或02开始数。误改其他字段不小心修改了“压缩方法”、“修改时间”或“CRC32”等关键字段。这些字段一旦错误文件必然损坏。未保存或保存错文件确保点击了保存CtrlS。解决方案永远保留原始文件的备份如果修改后损坏直接关闭WinHex选择不保存然后用备份文件重新开始。在修改时可以只改动目标字节其他部分用眼睛余光确认没有变动。6.2 搜索不到504B0102或504B0304签名可能原因1文件不是标准ZIP格式。有些文件虽然扩展名是.zip但可能是其他格式如.jar, .apk, .docx等它们本质是ZIP但内部结构更复杂或者文件头部已损坏。可能原因2WinHex搜索设置问题。确保在搜索对话框的“方向”选择了“全部”并且搜索的是“十六进制数值”而不是文本。可能原因3题目是“双图层”伪加密。极少数情况下出题人可能会将文件数据本身也进行一些无害的变换比如异或一个固定值但标志位修改仍然是破解的第一步。先确保你能找到并修改标志位。6.3 修改了标志位但依然提示需要密码可能原因1未修改所有必要位置。如果是“完全伪加密”你需要同时修改本地文件头和中央目录文件头的加密位。只改一处另一处仍然会触发软件的加密判断。可能原因2解压软件缓存。有些解压软件会缓存ZIP文件信息。尝试彻底关闭解压软件甚至重启一下再打开修改后的ZIP文件。可能原因3文件确实是真加密。请用上述第5.3节的方法判断是否为真加密。如果数据区是乱码那你遇到的就是真正的密码保护伪加密破解法无效。6.4 在CTF中遇到“伪加密”的变体CTF出题人为了增加难度可能会玩一些花样加密位不在bit 0极其罕见但理论上通用位标记的其他位如果被错误解读也可能导致软件行为异常。但标准就是bit 099.9%的题目都遵循此标准。结合其他Misc技巧例如伪加密的ZIP解压后得到一个图片图片需要改高度LSB隐写或者一个文档需要修复文件头。伪加密只是第一层“障眼法”。使用Python脚本批量处理如果题目是成百上千个文件的伪加密手动修改不现实。这时可以写一个简单的Python脚本import zipfile import io import struct with open(encrypted.zip, rb) as f: data bytearray(f.read()) # 修复本地文件头 i 0 while i len(data): if data[i:i4] bPK\x03\x04: # 将通用位标记偏移6的加密位清零 flags struct.unpack(H, data[i6:i8])[0] data[i6:i8] struct.pack(H, flags ~1) # 将bit 0置0 i 1 # 修复中央目录类似逻辑搜索PK\x01\x02 i 0 while i len(data): if data[i:i4] bPK\x01\x02: flags struct.unpack(H, data[i8:i10])[0] # 注意中央目录中通用位标记在偏移8 data[i8:i10] struct.pack(H, flags ~1) i 1 with open(fixed.zip, wb) as f: f.write(data) print(伪加密已修复保存为 fixed.zip)这个脚本自动遍历整个文件修复所有加密位一劳永逸。掌握这种方法你就能从“手工劳动者”升级为“自动化工程师”。