破解Excel打开密码:从加密结构到纯数字密码暴力破解实践
简介这是一套面向Python初学者的Excel加密文件密码破解实战源码聚焦纯数字密码场景讲解如何利用Python脚本对Excel文件进行密码探测与解锁适合需要处理个人文件密码遗忘或学习Excel安全机制的技术人员。资源包共2个文件包含一个可运行的Python脚本和一段演示操作视频脚本逻辑清晰视频能直观展示运行效果与注意事项。压缩包整体仅14.55MB轻量易下载。目前已有1856人学习使用兼具实用性与教学价值。通过这份资料读者能掌握破解纯数字Excel密码的基本思路学会使用Python调用相关库逐位穷举或字典探测并能在演示视频的引导下快速调通环境、上手运行为更深层的办公自动化或密码恢复需求打下基础。1. 破解Excel打开密码先理解加密包再谈跑字典处理“Excel打开密码纯数字”这种需求时第一反应是写个for循环从000000试到999999但真动手就会发现Excel根不给你“试错”的机会错误密码不会返回“密码错误”的提示而是直接拒绝整个文件。绕过这个障碍的办法是先把加密文件拆开找到验证密码的那一段数据再在本地把候选密码重放一遍。这篇会走一遍完整流程从xlsx的加密结构、msoffcrypto-tool提取加密参数到纯数字密码的生成与多进程加速最后落在结果验证和几个容易翻车的坑上。适合要做数据恢复、处理内部加密报表、或想搞懂ECMA-376加密协议的人前提是处理的文件本身有合法访问权限。2. 拆开加密文件从EncryptionInfo里拿到密码验证器2.1 Agile加密下密码到底怎么被固定成二进制现代xlsx/xlsm文件Office 2007默认走的是ECMA-376 Agile Encryption规范打开密码不参与文件内容的直接加解密。加密包的物理结构是CFB复合文档里面有两个关键流EncryptionInfo和EncryptedPackage。EncryptionInfo是“密码验证器”的所在地它包含算法标识、salt、迭代次数、密钥长度以及encryptedVerifierHashInput和encryptedVerifierHashValue两个密文段。你的密码经过派生后必须能正确解出这两段才算验证通过。密码派生走的是固定循环把密码以UTF-16LE编码和salt一起反复做SHA-512每轮结果作为下一轮输入共迭代10万次左右实际次数记录在spinCount里。最终得到的hash截断成密钥长度再用这个密钥去解验证段。也就是说破解的判定逻辑是确定的一个候选密码派生出的密钥如果能同时解开那两段数据它就是文件密码。这个结构决定了我们不需要碰EncryptedPackage只要解析EncryptionInfo就能在自己的代码里重构出验证过程。纯数字密码空间最大也就10的n次方比起盲目调库解密手动重放验证逻辑能快一到两个数量级。2.2 用msoffcrypto-tool提取加密参数msoffcrypto-tool是处理这类文件的标准工具它把CFB里的EncryptionInfo解析成对象属性省去手动翻二进制。安装依赖pycryptodome和olefile然后执行import msoffcrypto import io with open(encrypted.xlsx, rb) as f: off msoffcrypto.OfficeFile(f) print(是否加密:, off.is_encrypted()) # 先加载一个占位密码触发内部encryption_info解析 try: off.load_key(password000000, verify_passwordFalse) except Exception as e: # 此时结构已经加载密码不对会抛错但不影响观察属性 pass enc off.encryption_info print(算法:, enc.cipher_algorithm) print(salt长度:, len(enc.salt)) print(迭代次数:, enc.iterations) print(密钥位数:, enc.key_bits)这段代码的核心目的是拿到加密参数对象。关键参数含义如下参数作用说明salt密码派生时掺入的随机数据每个文件唯一不可省略iterationsSHA-512循环次数Agile默认值约100000取自spinCountkey_bits派生密钥长度常见128/256决定AES密钥字节数encrypted_verifier_hash_input验证明文段解密后是“验证输入”对其做SHA-512encrypted_verifier_hash_value验证比对段解密后应与上面计算的hash一致注意load_key在传入密码时会立即做派生验证如果密码错误且verify_passwordTrue默认抛出的异常会中断后续观察。这里传verify_passwordFalse跳过自动验证仅加载结构。2.3 Hash校验路径为什么离线爆破比循环decrypt快一个量级直接走msoffcrypto.decrypt()把整个EncryptedPackage解出来每次要处理整个文件体积的数据还要对每个候选密码做相同的AES解密。而手动校验只需要解密两个很小的密文块一个验证输入段通常几十字节一个验证hash段。解密量相差上千倍瓶颈从磁盘和AES大块解密转移到了SHA-512派生循环本身。这也决定了破解脚本的设计思路候选密码生成器和验证器分开。生成器负责按数字空间递推验证器只做派生和小块AES解密命中后再用decrypt()完整解密一次避免误报。实际测试中完整的decrypt()路径每秒只能跑几个候选而手动校验路径单核每秒能处理150个以上8进程可以到1000。3. 纯数字候选空间的剪枝设计与核心循环3.1 位数未知时的空间估算与剪枝原则纯数字密码最常见的场景是用户设了固定位数但没人记得是4位还是6位。盲目从1位跑到8位会浪费大量时间在低概率空段上所以先估算成本位数候选数量单核估算耗时150次/秒8进程估算1-4位11110约74秒约10秒5位90000约10分钟约75秒6位900000约1.7小时约13分钟7位9000000约16.7小时约2小时8位90000000约7天约21小时实际剪枝原则三条。应优先按“记忆中可能用到的位数”分隔区间而不是一次性全跑。应优先跑4-6位这是绝大多数纯数字密码的重灾区。应把零开头的密码视为正常候选比如“0123”Excel允许这种密码很多脚本写range()时顺手丢掉了前导零。3.2 核心实现用hashlib重放派生过程完成校验下面这段是可运行的判定器手工重放ECMA-376的SHA-512派生循环验证候选密码import hashlib import itertools import msoffcrypto import io def derive_key(password: str, salt: bytes, iterations: int, key_bytes: int) - bytes: # Excel AgileSHA-512(salt UTF-16LE密码)逐轮迭代 h hashlib.sha512(salt password.encode(utf-16-le)).digest() for _ in range(iterations - 1): h hashlib.sha512(h).digest() return h[:key_bytes] def verify_candidate(enc_info, candidate: str) - bool: key derive_key(candidate, enc_info.salt, enc_info.iterations, enc_info.key_bits // 8) # 解密VerifierHashInput from Crypto.Cipher import AES iv enc_info.salt[:16] aes AES.new(key, AES.MODE_CBC, iv) verifier_input aes.decrypt(bytes(enc_info.encrypted_verifier_hash_input)) verifier_input verifier_input[:64] # SHA-512输出长度 # 对明文做SHA-512作为比对基准 digest hashlib.sha512(verifier_input).digest() # 解密VerifierHashValue与digest比较 aes2 AES.new(key, AES.MODE_CBC, iv) verifier_hash aes2.decrypt(bytes(enc_info.encrypted_verifier_hash_value)) return digest verifier_hash[:len(digest)] def brute_force(enc_info, max_digits: int): # 纯数字候选利用itertools.product保留前导零 for length in range(1, max_digits 1): for digits_tuple in itertools.product(0123456789, repeatlength): candidate .join(digits_tuple) if verify_candidate(enc_info, candidate): return candidate return None逻辑分三层。derive_key严格按照规范把密码转UTF-16LE与salt拼接后做SHA-512循环哈希最后一轮截断到key_bytesverify_candidate用派生密钥以CBC模式解密两段小数据比较哈希值brute_force用itertools.product生成带前导零的数字串。注意encrypted_verifier_hash_input在部分版本库里是bytes类型如果取出来是bytearray用bytes()包一下即可。这个脚本依赖enc_info的属性名不同版本的msoffcrypto-tool对字段命名有差异。动手前先跑2.2节的代码把enc.__dict__打印出来核对键名属性名不一致就直接改verify_candidate里的引用。3.3 参数怎么调迭代次数、内存约束、多文件批量iterations不是所有文件都一样旧版Office生成的xlsx可能只有1万次新版默认10万次。验证器不需要死用固定值直接从enc_info.iterations读取这会让老文件跑得更快。内存方面itertools.product不提前生成完整列表每个候选用完即释放跑8位数空间内存占用也稳定在百MB以内。批量处理多个文件时把enc_info的加载做成函数复用def load_enc_info(path: str): with open(path, rb) as f: off msoffcrypto.OfficeFile(f) off.load_key(password000000, verify_passwordFalse) return off.encryption_info这里有个关键点如果文件实际没有打开密码load_key会报“文件未加密”的错。批量前先用off.is_encrypted()过滤一遍避免无意义地中止任务。4. 多进程提速与长任务断点续跑4.1 按整数区间切分候选交给多个worker上一章的brute_force是单线程6位密码跑到十几分钟还能忍7位以上就必须切分并发。纯数字候选可以按十进制整数区间切分每个worker拿到[start, end)就独立跑互不依赖。这里用ProcessPoolExecutor而不是线程池原因是SHA-512循环是CPU密集型多进程能绕开GIL限制。from concurrent.futures import ProcessPoolExecutor def hunt_range(enc_info, start: int, end: int, digits: int): for number in range(start, end): candidate str(number).zfill(digits) if verify_candidate(enc_info, candidate): return candidate return None def parallel_brute(enc_info, digits: int, processes: int 8, batch_step: int 100000): limit 10 ** digits with ProcessPoolExecutor(max_workersprocesses) as pool: futures [] start 0 while start limit: end min(start batch_step, limit) futures.append(pool.submit(hunt_range, enc_info, start, end, digits)) start end for future in futures: result future.result() if result: # 命中后取消未完成任务 for other in futures: other.cancel() return result return None每个worker一次领10万个候选跑完再领下一批。这样做的考虑是如果密码恰好落在某个区间其他worker的未完成批次可以被cancel()掉整体响应更快。需要留意的是enc_info对象通过参数传给子进程时会被pickle其内部包含的bytes字段序列化开销不大但最好在worker函数内部重新加载文件而不是传递整个对象否则大salt和密文段反复拷贝会影响性能。4.2 实测吞吐量参考与耗时推算按前面代码的纯手工校验路径单进程每秒大约能完成150次派生比较这个数字会随CPU主频和pycryptodome的AES实现有浮动。多进程的吞吐量和核数基本线性相关进程数每秒候选数100万候选耗时1000万候选耗时1约150约1.8小时约18小时4约550约30分钟约5小时8约1000约16分钟约2.7小时如果机器的hashlib底层带了SHA-NI硬件加速单进程能冲到200以上。但注意只有派生循环用到了hashlibAES解开那两个小数据段仍是固定开销所以“验证一次”的成本不会降到0。4.3 断点续跑与日志设计跑7位以上密码时进程崩溃或手动停掉是常事。断点续跑的思路很简单worker每处理完一个batch就把batch结束位置写进本地文件重启时读取最后位置继续。顺手在同一个文件里记录尝试过的最大数字方便事后核对覆盖范围。import os PROGRESS_FILE progress.txt def load_progress(): if os.path.exists(PROGRESS_FILE): with open(PROGRESS_FILE, r) as f: return int(f.read().strip()) return 0 def save_progress(position: int): with open(PROGRESS_FILE, w) as f: f.write(str(position))写盘频率不要太高每10万batch写一次即可避免磁盘IO拖慢主循环。也可以在hunt_range返回None时更新进度命中的时候删除进度文件避免下次误读旧状态。日志建议记录启动时间、当前区间、累计尝试数、每秒吞吐量而不是每个候选都打一行否则输出本身会成为新瓶颈。5. 结果验证与排错把试出来的密码真正用起来5.1 候选密码的完整解密验证暴力循环命中后先用msoffcrypto做一次完整解密再确认解出来的文件是合法zip压缩包。这一步能过滤极小概率的哈希碰撞误报def full_decrypt(path: str, password: str) - bytes: with open(path, rb) as f: off msoffcrypto.OfficeFile(f) off.load_key(passwordpassword) output io.BytesIO() off.decrypt(output) return output.getvalue() data full_decrypt(encrypted.xlsx, found_password) assert data[:2] bPK, 解密结果不是zip格式密码疑似误报 with open(decrypted.xlsx, wb) as f: f.write(data)注意如果原始文件同时有打开密码和工作表保护这段代码只能解除打开密码工作表的写保护需要在解出的xlsx里继续处理。5.2 打开密码、写保护密码与老xls格式的区分排错时先确认你手里的文件到底带的是哪种锁。打开密码会体现在文件流里is_encrypted()返回True上面整套方案都适用。写保护密码存在xl/workbook.xml里的workbookProtection标签中is_encrypted()返回False直接用zipfile读文件再改XML即可解除。两者同时存在时先用本方法解打开密码再用zipfile改写XML。老版本.xls文件Office 2003及以前的加密机制完全不同走的是RC4 自有salt结构msoffcrypto虽然能解析部分老文件但salt、iterations等属性可能不存在。报KeyError或AttributeError时先确认文件扩展名和实际格式必要时用file命令查看二进制头不要把时间浪费在错误协议上。5.3 用一个标定样本文件校验整套脚本最容易被忽略的环节是验证脚本自身是否正确。写一段自检代码生成一个密码已知的加密文件跑完整流程from msoffcrypto.format.ooxml import OOXMLFile # 实际接口随版本略有差异 # 用msoffcrypto官方示例方式生成加密文件 # 设置密码为 0427确保是纯数字且含前导零 # 再用 brute_force 跑预期几秒内返回 0427如果自检文件跑不出预期密码问题大概率出在enc_info属性名或derive_key的迭代方式上而不是目标文件本身。这个方法在换msoffcrypto大版本后尤其有用——我踩过verifier_hash_input被改名导致破解程序静默失败的坑自检样本帮我把问题隔离到了升级动作上。正式跑目标文件前先把自检样本的日志留存一份确认“脚本在当前环境是可验证的”再切换目标文件这个顺序能省下最贵的调试时间。本文还有配套的精品资源点击获取

相关新闻

多库房集群智慧档案系统:分布式采集与统一运维架构设计

多库房集群智慧档案系统:分布式采集与统一运维架构设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/21 16:19:31 阅读更多 →
Matlab电梯群控仿真:从建模到性能评估

Matlab电梯群控仿真:从建模到性能评估

简介:面向数学建模和电梯调度算法研究的MATLAB电梯群控仿真代码包,适合参赛学生、自动化专业学习者及优化控制方向开发者。代码包围绕电梯群控中的派梯策略、行程时间计算、乘客等待评估等核心模块展开,提供完整可运行的程序框架。压缩包共23…

2026/9/22 5:15:09 阅读更多 →
C语言数组指针与二级指针核心解析

C语言数组指针与二级指针核心解析

1. 指针的本质与内存视角指针是C语言中最强大也最容易让人困惑的特性之一。要真正理解数组指针和二级指针的区别,我们必须从计算机内存的基本工作原理说起。在32位系统中,每个内存地址对应一个32位(4字节)的存储单元,可…

2026/9/20 11:57:19 阅读更多 →

最新新闻

面试被问原理答不上?3个买耳麦场景教你看懂完整示例

面试被问原理答不上?3个买耳麦场景教你看懂完整示例

面试被问原理答不上?3个买耳麦场景教你看懂完整示例 面试现场,当面试官抛出“解释一下底层逻辑”时,你是否瞬间大脑空白,只能尴尬地重复背过的概念?这种“面试被问原理答不上来”的窘境,往往源于我们只知其然,不知其所以然。今天,我们换个角度,不聊…

2026/9/22 18:08:26 阅读更多 →
3步搞定八门神器安装教程,附完整示例避坑

3步搞定八门神器安装教程,附完整示例避坑

3步搞定八门神器安装教程,附完整示例避坑 官方文档那一堆英文术语和版本号,看得人头大?别急,我直接给你一份能跑的 完整示例 ,把八门神器安装过程中的坑全填平。 考点梳理:面试官到底在考什么?…

2026/9/22 18:08:26 阅读更多 →
魔兽世界sf发布网站速查手册:版本升级API全变后的底层原理与实战避坑

魔兽世界sf发布网站速查手册:版本升级API全变后的底层原理与实战避坑

魔兽世界sf发布网站速查手册:版本升级API全变后的底层原理与实战避坑 版本升级后 API 全变了? 别急着骂娘,先打开这份 速查手册 。 这不是玄学,是接口契约破裂后的必然震荡。 想搞定 魔兽世界sf发布网站 ,得先看懂底层数据流。…

2026/9/22 18:08:26 阅读更多 →
图解原理拆解 ljm 面试题,拒绝配置卡半天

图解原理拆解 ljm 面试题,拒绝配置卡半天

图解原理拆解 ljm 面试题,拒绝配置卡半天 刚接触 ljm 的同学,是不是经常被环境配置搞崩溃?明明照着文档敲命令,结果依赖冲突、版本不兼容,半天都跑不起来。别急,这不是你的问题,是大多数人在 ljm…

2026/9/22 18:08:26 阅读更多 →
3个图解原理教你怎么知道代码慢在哪

3个图解原理教你怎么知道代码慢在哪

3个图解原理教你怎么知道代码慢在哪 学会语法却不知怎么搭项目,这种痛苦我太懂了。很多人写代码像盲人摸象,感觉卡顿时,第一反应是“加硬件”或者“重写”,结果越改越乱。其实,性能优化不是玄学,而是一门基于数据的科学。你不需要凭感觉猜测哪里慢,你…

2026/9/22 18:08:26 阅读更多 →
淘宝排名靠前技巧揭秘:3个源码级优化点,面试必问的底层逻辑

淘宝排名靠前技巧揭秘:3个源码级优化点,面试必问的底层逻辑

淘宝排名靠前技巧揭秘:3个源码级优化点,面试必问的底层逻辑 官方文档堆砌术语,读完还是不会用?这行混久了都知道,真正的硬核知识往往藏在底层实现里。今天不扯虚的,直接拆解淘宝搜索排名的核心逻辑。很多开发者在面试中被问倒,不是不懂业务,而是不懂…

2026/9/22 18:07:24 阅读更多 →

日新闻

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天 配置环境就卡半天?别怪机器慢,多半是你没选对工具链。在Java、Go或Python的项目现场, 手写实现…

2026/9/22 0:00:41 阅读更多 →
剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑 面试被问原理答不上来,是不是常态?别慌。很多开发者对着 GitHub 开源仓库里的代码发呆,看似简单实则暗藏玄机。今天这份【剑帝加点】速查手册,直接带你拆解核心实现,把面试必考的原理讲透。…

2026/9/22 0:00:41 阅读更多 →
手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优 复制来的代码跑不通不知道怎么调?别慌,这种“复制粘贴地狱”在开发圈太常见了。尤其是做 图片压缩网站…

2026/9/22 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/22 4:32:41 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/22 4:38:57 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/22 8:51:04 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/22 2:43:42 阅读更多 →