
简介一套用于破解Excel打开密码纯数字的Python源码面向Excel使用频繁、因密码遗忘或需批量解除纯数字打开密码而困扰的办公人员、运维人员以及Python学习者适用于日常办公中的紧急解锁与自动化测试场景。压缩包共2个文件1个可直接运行的.py脚本和1个.mp4操作演示视频脚本封装了针对纯数字密码的自动尝试逻辑视频则展示配置运行环境与执行破解的完整过程便于对照验证。包体大小14.55MB轻量紧凑下载后即可基于Python环境运行。源码既提供可应对常见纯数字密码场景的现成脚本也通过录屏讲解帮助读者理解密码组合生成、文档读写与循环尝试等实现要点对于希望掌握Excel自动化处理或开发密码恢复工具的开发者是很好的参考样本。已有1856人学习下载适合需要快速解决Excel密码问题的技术用户也是Python办公自动化初学者的练手项目。1. 纯数字 Excel 打开密码一个离线可穷举的密码破解问题Excel 的打开密码和多数人想的不一样它不是让 Excel 弹一个输入框来验证而是把整个 xlsx 文件加密之后再落盘。密码对不对本地就能离线判断根本不需要真正打开 Excel。于是问题就只剩一个——候选空间有多大。纯数字 6 位只有 100 万个组合8 核 CPU 上按小时算8 位就是 1 亿个组合按天算。网上这类Py破解Excel打开密码纯数字.rar分享包解压后通常是一个 Python 脚本加说明核心就是三件事用 msoffcrypto 校验候选密码、用 itertools 生成数字序列、用 multiprocessing 并行加速。那层 .rar 只是分发容器和 RAR 密码破解毫无关系。下文给一套不依赖付费工具的复现方案并说清楚 7 位以上该往哪走。2. Excel 打开密码的加密结构与密码校验原理2.1 打开密码走的是 EncryptedPackage别和另外两类保护混为一谈用 Excel 的文件 → 信息 → 保护工作簿 → 用密码进行加密得到的是真正的全文件加密。而修改权限密码工作表保护工作簿结构保护完全是另一套机制它们不加密正文只在 XML 里存一个校验值。很多人把这三类全当成Excel 密码去网上找破解工具方向从一开始就错了。保护类型存储位置是否整体加密Python 处理路径打开密码用密码进行加密OLE 容器内的 EncryptedPackage 流是msoffcrypto / Hashcat 爆破修改权限密码workbook.xml 的 fileSharing 节点否删除节点即可无需破密码工作表/工作簿结构保护sheetProtection / workbookProtection否改 XML 移除保护属性判断标准很简单用 msoffcrypto 打开文件is_encrypted()返回 False就别在这个文件上浪费时间跑穷举了它根本没有走到加密分支。修改权限这类保护直接改 XML 的代价远小于破解。2.2 Agile Encryption 的密钥派生为什么密码能离线验证加过打开密码的 xlsx文件结构是一个 OLE 复合文档CFB 容器里面有两个关键流EncryptionInfo和EncryptedPackage。EncryptionInfo明文存放加密参数盐值salt、哈希算法SHA-1/256/512、spinCount迭代次数、AES 相关参数以及加密后的 verifier 信息。校验一个密码时程序要做的是用候选密码做 PBKDF2迭代spinCount次派生 baseKey再用这个 key 解密EncryptedVerifierHash与文件里保存的 verifier 哈希比对。一致就是密码正确不一致就是错误。整个流程完全在本地完成不需要调用 Excel也不存在连续试错被锁定的机制。这套算法在微软的 [MS-OFFCRYPTO] 规范里叫 Agile EncryptionOffice 2007 之后生成的 xlsx 基本都走这条路。旧格式 .xls 用的是另一套 Standard Encryption参数和算法不同但离线可验证这个性质完全一样。对写爆破脚本的人来说区别只在 msoffcrypto 内部帮你选了哪套流程外部接口不变。2.3 openpyxl 打不开是正常的ZIP 外面套了 OLE 复合文档xlsx 本质是一个 ZIP 包OOXML 容器。加了打开密码后这个 ZIP 整体被加密成EncryptedPackage再塞进 OLE 复合文档。所以下面这些现象都是正常现象unzip -l secret.xlsx # error: [secret.xlsx]: End-of-central-directory signature not found.openpyxl 或 pandas 直接读这类文件会报文件损坏、或者说找不到 xl/ 目录——因为它们读到的根本不是 ZIP。msoffcrypto 做的事就是解开 CFB 外壳、按EncryptionInfo里的参数派生密钥、把EncryptedPackage还原成一个可被 openpyxl 读取的普通 xlsx。理解这层包装后面排错时就不会把代码写错了和文件格式不对混在一起。3. 用 msoffcrypto-tool 写纯数字爆破最小可复现版本3.1 装包与单口令手动校验前提是 Python 3.8 以上先安装依赖pip install msoffcrypto-tool装完不要急着写循环先用一个口令手动验证文件确实走的是加密分支python - PY import msoffcrypto with open(secret.xlsx, rb) as f: of msoffcrypto.OfficeFile(f) print(is_encrypted:, of.is_encrypted()) try: of.load_key(password123456) print(该密码验证通过) except msoffcrypto.exceptions.InvalidKeyError: print(密码错误, 继续穷举) PYload_key只做密钥派生和 verifier 校验不会把整个文件解密到磁盘所以它非常适合当批量校验函数。注意InvalidKeyError是 msoffcrypto 明确的密码不对信号其他异常比如文件根本不是加密文件要单独处理不能简单当成密码错误吞掉。3.2 完整脚本--min/--max/--prefix/--threads 全参数下面这份脚本是完整的纯数字穷举实现逻辑上分三块候选生成、单口令校验、进程池调度。文件不大直接整段抄走就能跑。# crack_xlsx_numeric.py import argparse import io import itertools import multiprocessing as mp import msoffcrypto DIGITS 0123456789 def parse_args(): p argparse.ArgumentParser(description纯数字 Excel 打开密码穷举) p.add_argument(--file, requiredTrue, help加密的 xlsx/xls 文件) p.add_argument(--min, typeint, default1, help最短位数, 如 6) p.add_argument(--max, typeint, default6, help最长位数, 如 6) p.add_argument(--prefix, default, help记得的固定前缀, 如 2024) p.add_argument(--threads, typeint, default0, help进程数, 0自动) return p.parse_args() def candidates(min_len, max_len, prefix): 按位数从小到大生成纯数字候选, 包含 0 开头组合。 for length in range(min_len, max_len 1): for tail in itertools.product(DIGITS, repeatlength): yield prefix .join(tail) def init_worker(path): 每个 worker 启动时把加密文件读进内存, 避免每次校验都做磁盘 IO。 global SOURCE SOURCE open(path, rb).read() def check_one(password): 校验单个密码, 命中返回密码本身, 未命中返回 None。 try: f msoffcrypto.OfficeFile(io.BytesIO(SOURCE)) f.load_key(passwordpassword) return password except msoffcrypto.exceptions.InvalidKeyError: return None def main(): a parse_args() workers a.threads or mp.cpu_count() stream candidates(a.min, a.max, a.prefix) pool mp.Pool(workers, initializerinit_worker, initargs(a.file,)) try: for found in pool.imap_unordered(check_one, stream, chunksize256): if found: pool.terminate() break finally: pool.close() pool.join() if found: print([] 打开密码 , found) else: print([-] 该区间未命中) if __name__ __main__: main()运行方式python crack_xlsx_numeric.py --file secret.xlsx --min 6 --max 6如果记得密码前两位是 68就把参数改成--prefix 68 --min 4 --max 4候选空间直接缩小 100 倍。threads留 0 时自动取 CPU 核数在容器里跑时建议显式指定避免被调度到物理核之外。提示--min 1 --max 6会从 1 位试到 6 位包含 000000 这类以 0 开头的组合确认是 6 位就把 min/max 都设成 6能少试 11 万个无谓候选。3.3 并行、chunksize 与退出时序的工程取舍每个候选要跑一次 PBKDF2这是典型的 CPU 密集任务用进程池而不是线程池。即使 hashlib 底层在某几个哈希实现里会释放 GIL整条校验链路里还有 OLE 解析、异常处理、BytesIO 构造这些纯 Python 逻辑线程很难把多核吃满进程池在 Linux/macOS 上按核数线性扩展是最稳妥的做法。chunksize256的含义是每个 worker 一次领取 256 个密码去校验。chunksize 太小进程间 IPC 的次数就会盖过实际计算太大一旦命中别的 worker 还在白算几千个候选。对单次校验耗时 50 毫秒上下的任务256 是个常用折中值。命中后的退出时序要注意主进程拿到结果就pool.terminate()然后用close()join()收尾。terminate会直接结束还在跑的 worker这没问题因为已经不需要更多结果了。一定要把这段放在try/finally里否则中途 CtrlC 时容易留下僵尸进程。Windows 上跑这份脚本check_one和init_worker必须在模块顶层定义且入口要有if __name__ __main__保护这是进程池使用 spawn 模式的硬性要求。4. 提速与边界量级表、Hashcat 分流、常见误用4.1 先按量级估时长6 位和 8 位是两个世界Excel 默认的spinCount常见是 10 万次迭代这决定了单候选耗时。下表按单核每秒 15 个候选、8 进程每秒 120 个候选估算只代表量级真实速度以你机器的实测为准。位数候选数单核耗时约8 进程耗时约5 位10 万1.9 小时14 分钟6 位100 万18.5 小时2.3 小时7 位1000 万7.7 天23 小时8 位1 亿77 天9.6 天所以 6 位以内值得用上面的 Python 脚本硬跑7 位可以挂着过夜8 位就别指望 CPU 了。真正判断该不该跑先做一个小样本计时只跑--min 1 --max 1用time测十位数的耗时再按表里的倍数换算总时长。这一步能省掉大量空等。另外迭代次数是写死在文件里的不是脚本能改的。同一份文件在 Excel 和 WPS 里加密spinCount可能不一样速度差异会直接体现在表里单核每秒这个数字上。遇到特别慢的文件第一反应应该是怀疑迭代次数偏高而不是代码写坏了。4.2 8 位以上转 Hashcat 掩码攻击模式号先验证再跑纯数字超过 7 位把 CPU 让给 GPU 更划算。常见做法是把加密文件交给 Hashcat用掩码?d表示 0-9hashcat -a 3 -m 25300 secret.xlsx ?d?d?d?d?d?d六个?d就自动覆盖 000000 到 999999和 Python 脚本里itertools.product的语义一致。2016 之后生成的 Office 文件多落在 25300 这个模式SHA-512 变体但不同版本对 Office 加密的类型划分不一致跑之前先用这条命令确认本机模式hashcat --example-hashes | grep -i -B1 -A3 Office 2016拿到示例哈希长什么样再对照自己文件对应的算法版本别背死模式号。部分 Hashcat 版本能直接读取 xlsx 文件有的版本要求先用提取脚本转成$office$*...格式的哈希串跑不通时优先检查这一步。GPU 吞吐量随显卡和迭代次数浮动给不出通用数字。但 6-7 位纯数字在 25300 这类模式上通常远快于 8 核 CPU这是它值得切工具的根本原因。切过去之后Python 脚本的角色就变成了先用小样本计时、估算掩码长度的前置工具。4.3 常见的三个误用zip 破解器、Excel COM、改了结构保护第一用 ZIP/压缩包密码破解工具处理 xlsx。xlsx 打开密码是 CFB 加 Agile 加密不是 ZIP 的 ZipCrypto 或 AES解压类工具连EncryptionInfo流都定位不到属于纯浪费时间。网上那些压缩包破解工具对本文场景完全无效。第二用 pywin32 驱动 Excel 弹窗重试。每次错误密码都要触发一次对话框单次耗时秒级试几百次后就可能触发 Excel 的保护性延迟这个方案连 5 位纯数字都跑不完没有任何竞争力。第三误把结构保护/写权限当打开密码跑。前面表格已经说明这类保护只改 XMLmsoffcrypto 会直接判定为未加密。遇到这种文件正确做法是解包改 XML 去掉保护而不是继续扩字典。5. 命中之后解密落盘、真伪校验与两个收尾技巧5.1 把找到的密码转成明文 xlsx脚本只验密码不落盘命中后单独执行一次解密import msoffcrypto with open(secret.xlsx, rb) as raw: f msoffcrypto.OfficeFile(raw) f.load_key(password找到的密码) with open(solved.xlsx, wb) as out: f.decrypt(out) head open(solved.xlsx, rb).read(2) print(解密产物是 OOXML 文件 if head bPK else 文件头异常)head bPK是便宜又可靠的自检load_key通过说明 verifier 校验成功但只有解密产物能解出 PK 头才证明整条链路真正走通。解出来的 xlsx 再交给 openpyxl 或 pandas 读取就不会再报文件损坏了。5.2 两个收尾技巧内存驻留与分段计时最后一章的落点给两个每次都用得上的技巧。第一个是分段计时拿到新文件先只跑 10 个候选用time测出单候选耗时再乘候选总数估算总时长。这个数字比任何网上查到的基准都可靠因为 CPU 型号、文件spinCount、进程数三个变量全在你的机器上。第二个技巧是收进度把输出重定向到日志文件而不是终端避免 print 刷屏拖慢进程池命中行用grep \[\]从日志里捞出来。如果文件很大第 3 章脚本里的init_worker已经把全文读进内存每个候选走 BytesIO省去磁盘 IO 波动。这个写法对 10 MB 以内的 xlsx 完全够用更大的文件建议先压缩或换 Hashcat因为 OLE 解析本身的开销也会随体积上升。下次再遇到同类文件先跑is_encrypted()确认分支再按计时结果决定用 Python 硬跑还是切 Hashcat这套流程就能在同一台机器上反复复用。本文还有配套的精品资源点击获取