Shell脚本实现跨平台压缩包密码恢复:7z/RAR暴力破解实战
1. 项目概述当密码成为“薛定谔的猫”在数据交换和归档的日常工作中压缩包几乎是每个人的“老朋友”。但你是否也遇到过这样的窘境一个至关重要的7z或RAR文件密码却像被记忆橡皮擦抹去了一样怎么也想不起来。或者你接手了一个遗留项目压缩包是前任留下的密码却不知所踪。这时一个高效、可控的密码恢复工具就显得至关重要。市面上确实存在不少图形化界面的密码破解工具但它们往往功能单一、依赖特定操作系统或者在处理复杂场景时显得笨拙。而Shell脚本这个看似古老的命令行工具却能以其无与伦比的灵活性、跨平台特性和强大的可编程能力成为解决这类问题的“瑞士军刀”。今天要分享的就是如何利用Shell脚本构建一个能够跨平台Linux, macOS, 甚至通过Cygwin/WSL在Windows上运行运行的压缩包密码暴力破解工具。我们不会触及任何法律灰色地带核心目的是帮助用户在合法合规的前提下例如恢复自己遗忘的密码理解自动化、批量化任务处理的精髓。这个项目的核心价值在于“可控”与“透明”。你完全掌控破解的字典、策略和进度每一步操作都清晰可见这远比使用一个不知内部运作原理的“黑盒”软件要可靠得多。2. 核心思路与工具选型解析2.1 为什么选择Shell脚本首先我们需要明确暴力破解Brute-Force的本质它是一种穷举法通过系统性地尝试所有可能的密码组合直到找到正确的那个。这个过程天然就适合自动化。Shell脚本的优势在这里体现得淋漓尽致跨平台核心核心破解逻辑依赖于7z和unrar这两个命令行工具。它们在Linux、macOS上可以轻松通过包管理器apt,yum,brew安装在Windows上也可以通过Cygwin、MSYS2或WSLWindows Subsystem for Linux获得。脚本本身Bash在这些环境中有高度一致性。流程控制循环for、条件判断if等结构能完美地组织尝试密码的流程。外部命令集成可以无缝调用7z,unrar,crunch,john等专业工具形成工具链。资源友好相对于图形界面程序Shell脚本运行时开销极低可以将更多系统资源CPU、内存留给实际的解密测试过程。可定制性极强你可以轻松修改脚本尝试不同的字典策略、调整并行度、添加进度日志、甚至与分布式任务队列结合。2.2 核心工具链介绍我们的脚本将作为“指挥官”协调以下两个“士兵”进行实际工作7-Zip (7z)用于处理.7z格式。它是开源的命令行功能强大。关键测试命令是7z t -p$PASSWORD archive.7z该命令用指定密码测试压缩包完整性成功则返回0。RARLAB UnRAR (unrar)用于处理.rar格式。注意我们需要的是非商业版本的unrar通常包名就是unrar。关键测试命令是unrar t -p$PASSWORD archive.rar。重要提示请务必从官方或可信源获取以确保合法性。字典生成工具Crunch一个强大的单词列表生成器可以按指定的字符集和长度范围生成所有排列组合。非常适合定制化暴力破解。自定义文本文件最常见的密码字典如rockyou.txt Kali Linux 中著名字典或根据目标信息生日、姓名、常用词自己整理的字典。2.3 方案设计考量一个健壮的破解脚本需要处理以下问题格式判断自动识别压缩包是.7z还是.rar并调用对应的工具。密码输入源支持从标准输入读取、从文件字典读取、或者使用工具动态生成。性能与礼貌在可能的情况下利用简单并行如和wait加速但同时要避免耗尽系统资源。对于网络或共享资源需要特别小心。状态与日志清晰记录尝试进度、成功密码以及任何错误便于调试和恢复。可中断与恢复理想情况下脚本停止后再次运行能跳过已尝试的密码。基于以上考量我们将设计一个模块化、易于理解和修改的脚本。3. 脚本核心模块拆解与实现3.1 环境检测与依赖检查脚本的第一步必须是确保运行环境就绪。一个友好的脚本应该主动检查并提示用户而不是在运行中报晦涩的错误。#!/bin/bash # 定义颜色输出让提示信息更清晰 RED\033[0;31m GREEN\033[0;32m YELLOW\033[1;33m NC\033[0m # No Color # 依赖检查函数 check_dependency() { if ! command -v $1 /dev/null; then echo -e ${RED}[错误] 未找到命令: $1${NC} echo -e 请根据您的系统安装 echo -e Ubuntu/Debian: sudo apt-get install $2 echo -e CentOS/RHEL: sudo yum install $2 echo -e macOS: brew install $2 echo -e (Windows via WSL: 使用上述Linux发行版命令) exit 1 else echo -e ${GREEN}[OK] 已安装: $1${NC} fi } # 检查核心依赖 echo “正在检查系统依赖...” check_dependency 7z p7zip-full # 在Ubuntu上7z命令来自p7zip-full包 check_dependency unrar unrar # 非商业版本 # check_dependency crunch crunch # 如果需要动态生成字典则检查crunch # 检查输入参数 if [ $# -lt 2 ]; then echo -e ${YELLOW}用法: $0 压缩文件路径 密码字典路径${NC} echo -e 示例: $0 ./secret.7z ./passwords.txt echo -e 示例: $0 ./data.rar /usr/share/wordlists/rockyou.txt exit 1 fi ARCHIVE$1 DICT_FILE$2 # 检查压缩文件是否存在 if [ ! -f $ARCHIVE ]; then echo -e ${RED}[错误] 压缩文件不存在: $ARCHIVE${NC} exit 1 fi # 检查字典文件是否存在 if [ ! -f $DICT_FILE ]; then echo -e ${RED}[错误] 密码字典文件不存在: $DICT_FILE${NC} exit 1 fi # 判断压缩包格式并设置对应的测试命令 if [[ $ARCHIVE *.7z ]]; then TEST_CMD7z t -p\\$PASSWORD\ \$ARCHIVE\ /dev/null 21 echo “检测到 7z 格式压缩包。” elif [[ $ARCHIVE *.rar ]]; then TEST_CMDunrar t -p\\$PASSWORD\ \$ARCHIVE\ /dev/null 21 echo “检测到 RAR 格式压缩包。” else echo -e ${YELLOW}[警告] 文件扩展名非 .7z 或 .rar将尝试通用测试可能失败。${NC} # 尝试用7z测试7z支持格式较多 TEST_CMD7z t -p\\$PASSWORD\ \$ARCHIVE\ /dev/null 21 fi关键点解析command -v是检查命令是否存在的标准且高效的方法。颜色定义让输出信息层次分明错误和成功一目了然。对压缩包格式的判断基于后缀虽然不绝对准确有人会改后缀但对于大多数情况足够可靠且简单高效。更严谨的方法可以用file命令判断文件魔数但会引入额外依赖和复杂度。 /dev/null 21将命令的标准输出和错误输出都重定向到空设备让脚本运行过程更安静只显示关键信息。3.2 主破解循环逐行尝试密码这是脚本的核心逻辑从字典文件中读取每一行作为密码进行尝试。echo “开始尝试破解...” echo “” ATTEMPT0 START_TIME$(date %s) FOUND0 # 读取字典文件逐行尝试 while IFS read -r PASSWORD || [ -n $PASSWORD ]; do ((ATTEMPT)) # 简单进度显示每1000次尝试打印一次 if (( ATTEMPT % 1000 0 )); then echo -ne “[尝试次数: $ATTEMPT]\\r” fi # 执行测试命令 eval $TEST_CMD # 检查上一条命令的退出状态码 if [ $? -eq 0 ]; then END_TIME$(date %s) DURATION$((END_TIME - START_TIME)) echo -e “\\n${GREEN}${NC}” echo -e ${GREEN}[成功] 密码找到${NC} echo -e ${GREEN}压缩包: $ARCHIVE${NC} echo -e ${GREEN}密码: $PASSWORD${NC} echo -e ${GREEN}尝试次数: $ATTEMPT${NC} echo -e ${GREEN}耗时: ${DURATION} 秒${NC} echo -e ${GREEN}${NC}” FOUND1 break fi done $DICT_FILE if [ $FOUND -eq 0 ]; then END_TIME$(date %s) DURATION$((END_TIME - START_TIME)) echo -e “\\n${RED}${NC}” echo -e ${RED}[失败] 字典中所有密码尝试完毕未找到正确密码。${NC} echo -e ${RED}尝试次数: $ATTEMPT${NC} echo -e ${RED}耗时: ${DURATION} 秒${NC} echo -e ${RED}请尝试更大的字典或不同的密码策略。${NC} echo -e ${RED}${NC}” fi关键点解析while IFS read -r PASSWORD这是安全读取文件每一行的标准方法。IFS防止行首尾空格被修剪-r防止反斜杠转义被解释。|| [ -n $PASSWORD ]处理文件最后一行没有换行符的情况。eval $TEST_CMD这里使用了eval来执行我们之前根据压缩包格式拼接好的命令字符串。注意eval需谨慎使用因为如果$PASSWORD包含特殊字符或命令注入代码会有安全风险。但在我们这个场景下密码来自受控的字典文件且用于自身测试风险可控。更安全的替代方案是将命令定义为函数或者使用bash -c但会稍复杂。$?保存上一个命令的退出状态码。7z t和unrar t命令在密码正确时返回0错误时返回非0。进度显示使用\\r实现行内刷新避免刷屏。3.3 进阶功能多线程并行破解单线程破解在大型字典面前速度堪忧。我们可以利用 Shell 的作业控制Job Control实现简单的多线程显著提升速度。#!/bin/bash # ... (省略之前的依赖检查和参数处理部分) ... MAX_JOBS4 # 根据你的CPU核心数调整通常为核心数或核心数*2 ATTEMPT0 FOUND0 declare -a PIDS echo “使用 $MAX_JOBS 个并行任务进行破解...” echo “” # 创建一个命名管道用于协调 FIFO$(mktemp -u) mkfifo $FIFO exec 3$FIFO rm -f $FIFO # 初始化令牌 for ((i1; iMAX_JOBS; i)); do echo 3 done while IFS read -r PASSWORD || [ -n $PASSWORD ]; do ((ATTEMPT)) # 等待获取一个令牌代表一个可用的任务槽位 read -u 3 # 在子shell中执行测试 ( eval $TEST_CMD EXIT_CODE$? # 将令牌归还 echo 3 # 如果成功通过一个临时文件传递结果。不能直接修改父进程变量。 if [ $EXIT_CODE -eq 0 ]; then echo $PASSWORD /tmp/found_password_$$.txt # 发送信号通知父进程更简单的方法是让父进程检查文件。 # 这里我们使用 kill 发送 USR1 信号 kill -USR1 $$ fi ) PIDS($!) # 保存子进程PID # 每1000次尝试打印一次进度注意由于并行ATTEMPT是开始尝试的总数不一定是完成数 if (( ATTEMPT % 1000 0 )); then echo -ne “[已启动任务数: $ATTEMPT]\\r” fi done $DICT_FILE # 信号处理函数用于捕获成功信号 password_found() { FOUND_PASSWORD$(cat /tmp/found_password_$$.txt 2/dev/null) if [ -n $FOUND_PASSWORD ]; then echo -e “\\n${GREEN}[信号接收] 疑似成功正在确认...${NC}” # 等待所有后台任务结束 wait ${PIDS[]} 2/dev/null echo -e ${GREEN}[成功] 密码已确认: $FOUND_PASSWORD${NC} rm -f /tmp/found_password_$$.txt exit 0 fi } trap password_found USR1 # 捕获USR1信号 # 等待所有后台任务完成 wait ${PIDS[]} 2/dev/null # 所有任务结束后检查是否成功文件被创建防止信号丢失 if [ -f /tmp/found_password_$$.txt ]; then FOUND_PASSWORD$(cat /tmp/found_password_$$.txt) echo -e ${GREEN}[成功] 密码: $FOUND_PASSWORD${NC} rm -f /tmp/found_password_$$.txt exit 0 fi echo -e “\\n${RED}[失败] 所有密码尝试完毕未成功。${NC}” exit 1关键点解析命名管道 (FIFO)用于控制并发数实现一个简单的信号量。MAX_JOBS定义了最大并行任务数。作业控制将命令放入后台执行$!获取最近一个后台进程的PIDwait等待所有或指定后台进程结束。信号 (Trap)使用trap捕获USR1用户自定义信号。当某个子进程找到密码时它向父进程发送USR1信号父进程收到信号后执行password_found函数进行处理。这是一种进程间通信的简单方式。临时文件用于在子进程和父进程间传递找到的密码字符串。因为子进程无法直接修改父进程的变量。注意事项并行脚本比串行复杂得多且大量并发地调用7z/unrar可能瞬间产生高I/O和CPU负载请根据系统情况调整MAX_JOBS。此外进度显示ATTEMPT只是“已启动的任务数”由于任务完成顺序不定它不代表“已测试数”。4. 实战技巧与高阶策略4.1 字典的学问质量优于数量一个精心准备的字典能事半功倍。针对性生成如果密码可能包含目标人物的信息如姓名、生日、宠物名、公司名等用这些元素组合生成字典。可以用crunch或简单的Python脚本。# 使用 crunch 生成 6-8位由小写字母和数字组成的密码 crunch 6 8 abcdefghijklmnopqrstuvwxyz0123456789 -o custom_dict.txt字典合并与去重收集多个公共字典如 rockyou.txt, darkweb2017-top10000.txt合并后去重形成一个基础大字典。cat dict1.txt dict2.txt | sort -u combined_dict.txt规则变换对基础字典中的每个词应用规则如首字母大写、尾部添加数字password-Password,Password123,password!。Hashcat的规则模式非常强大但我们可以用Shell简单模拟while read base; do echo “${base^}” # 首字母大写 echo “${base}123” echo “${base}!” echo “${base}2023” done base_dict.txt mutated_dict.txt4.2 性能优化点使用pv监控进度如果字典文件很大可以使用pvPipe Viewer命令来显示读取进度、速度和预计剩余时间。pv -N “密码尝试” $DICT_FILE | while IFS read -r PASSWORD; do # ... 尝试逻辑 ... done将字典加载到内存对于较小的字典可以读入数组避免频繁的磁盘I/O。mapfile -t PASSWORDS $DICT_FILE for PASSWORD in ${PASSWORDS[]}; do # ... 尝试逻辑 ... done破解状态保存与恢复记录已尝试的密码行数下次从断点继续。这对于超大型字典或长时间运行的任务非常有用。RESUME_FILE“${ARCHIVE}.resume” START_LINE1 if [ -f $RESUME_FILE ]; then START_LINE$(cat $RESUME_FILE) echo “从第 $START_LINE 行恢复...” fi # 使用 tail sed 或 awk 来跳过已尝试的行 tail -n $START_LINE $DICT_FILE | while IFS read -r PASSWORD; do # ... 尝试逻辑 ... CURRENT_LINE$((CURRENT_LINE 1)) # 定期保存进度每1000次 if (( CURRENT_LINE % 1000 0 )); then echo $((START_LINE CURRENT_LINE - 1)) $RESUME_FILE fi done4.3 常见问题与排查FAQ脚本报错7z: command not found或unrar: command not found原因依赖未安装。解决根据脚本开头的提示使用系统包管理器安装。在macOS上unrar可能需要从RARLAB官网下载或通过brew install unrar安装有时包名是rar。在Windows WSL中就按对应的Linux发行版命令安装。unrar报告Cannot open: No such file or directory但文件存在原因路径包含空格或特殊字符时变量引用需要格外小心。解决确保在脚本中所有文件路径变量都用双引号括起来如$ARCHIVE。我们的脚本中已经这样做了。破解速度非常慢原因7z t和unrar t命令本身需要解压测试对于大型、高压缩率的文件每次测试开销都很大。字典太大或密码太长也会导致总时间指数级增长。解决优先使用高质量、有针对性的小字典。启用并行破解如3.3节的脚本。考虑使用更专业的工具如john(John the Ripper) 配合rar2john/7z2john提取哈希值后进行离线破解这通常比直接测试压缩包快几个数量级。但这需要学习额外的工具链。并行脚本运行后系统变得卡顿原因MAX_JOBS设置过高同时运行太多7z/unrar进程耗尽了CPU或I/O资源。解决降低MAX_JOBS的值。通常设置为CPU逻辑核心数比较合适。可以使用nproc命令动态获取MAX_JOBS$(nproc)。脚本在找到密码后没有立即停止所有后台任务原因我们的并行脚本示例中父进程收到信号后会等待所有子进程结束 (wait)。已经启动的后台任务会继续运行直到完成其当前测试。解决可以在password_found函数中在wait之前先向所有后台进程发送终止信号如kill ${PIDS[]} 2/dev/null。但要注意这可能导致资源未正确释放。对于密码破解这种场景立即终止是合理的。5. 安全、法律与伦理边界这是最重要的一节。技术本身无罪但如何使用它决定了其性质。合法用途本脚本仅适用于恢复你自己拥有合法所有权但忘记密码的文件或是在已获得明确授权的情况下对他人文件进行测试如渗透测试授权。严禁用途绝对禁止用于破解他人加密文件以窃取隐私、商业数据或任何其他未经授权的访问。这是违法行为可能涉及计算机犯罪。隐私保护脚本运行过程中尝试的密码可能会被记录在日志或系统进程列表中。在处理敏感字典或破解任务后请及时清理相关临时文件和历史记录。责任自担使用此脚本产生的任何后果由使用者自行承担。作者仅提供技术思路与教育目的的实现。最后一点个人体会编写这个脚本的过程与其说是为了“破解”不如说是一次精彩的Shell编程实战。它涵盖了环境检测、参数处理、流程控制、子进程管理、信号处理、性能优化等多个核心知识点。通过这个项目你能深刻体会到Shell脚本如何将一个个简单的命令行工具粘合起来构建出强大、自动化的解决方案。真正的价值不在于破解了几个压缩包而在于你掌握了这种“自动化思维”和“工具整合能力”。下次遇到任何重复性、机械性的任务时不妨先想想能不能写个脚本让它自己跑起来

相关新闻