python破解压缩包密码

1. 前言

2. 破解zip、7z等

2.1 快速开始

python里有个内置库zipfile可以对zip格式压缩包进行操作。

1
2
3
4
5
6
7
8
import zipfile

# 创建文件句柄
file = zipfile.ZipFile("测试.zip", 'r')
# 提取压缩包内所有内容,path为目标目录,pwd为密码,需为bytes格式
file.extractall(path='.', pwd='123'.encode('utf-8'))
# 关闭文件
file.close()

知道了如何使用代码解压文件,下面只需生成所有可能的密码,编写代码逐一调用函数,直至成功。

2.2 拓展:“深浅拷贝”

在生成密码列表的时候,需要对数字/字母进行排列组合,此时利用itertools可以方便的生成。

1
2
nums = [str(i) for i in range(10)]
password_lst = itertools.permutations(nums, 2) # 生成2位数字的所有排列,不重复

这里有2个需要注意的地方,第一个是permutations()生成的是不重复的“排列”,故上述代码生成的列表只有90个元素。

正确的姿势应该是用product()。

itertools官方文档

第二个,生成的密码列表password_lst实际上是一个迭代器,对他进行去长度实际上是遍历了一次,这时他指向最后一个元素,生命周期已然耗尽。故我们在获取长度时需要复制一个新的迭代器。

重点来了,这里涉及到深浅拷贝的问题。简单的赋值操作是浅拷贝,只是传地址,新的变量仍然指向password_lst而不是独立的。

要实现深拷贝需要用到copy模块

1
2
3
4
5
6
7
8
9
10
11
12
13
import copy

# 获取迭代器长度
def get_length(generator):
if hasattr(generator,"__len__"):
return len(generator)
else:
return sum(1 for _ in generator)

nums = [str(i) for i in range(10)]
password_lst = itertools.permutations(nums, 2)
new_lst = copy.deepcopy(password_lst)
length = get_length(new_lst)

还有一种方法,直接遍历一遍password_lst并将所有元素加入到空列表。这样做的好处是方便求长度。下面的代码都会采用这种方法。

1
2
3
nums = [str(i) for i in range(10)]
password_lst = [''.join(x) for x in itertools.product(*[nums] * 2)]
length = len(password_lst)

2.3 多线程提高效率

为了提高破解速度,还可以加入多线程,而且使用线程池(ThreadPoolExecutor),方便管理、重复利用资源。

但是在实验过程中还发现一个问题:ThreadPoolExecutor默认使用的是无界队列,尝试密码的速度跟不上生产密码的速度,会把生产任务无限添加到队列中,导致内存被占满,最终导致程序崩溃。

此处不做展示,请自行测试。

要解决这个问题,可以重写ThreadPoolExecutor类,给队列设置一个最大值,使无界队列变成有界。

代码如下

2.3.1 测试

下面来测试一下。

创建一个测试文件test.txt,并压缩成test.zip,设置密码为1234

运行程序

可以看到已经解压成功了

2.4 进度条+用时(两种方案)

2.4.1 ①子线程打印

进度条功能需要实时监控当前已完成数量,并且与生成的密码列表长度进行比对。因为主线程在不断遍历生成的密码列表,并且不断将新任务放入线程池,故不可能使用主线程进行。而线程池使用队列的形式,不可能让一个线程占用太长时间,否则后面就会卡住进行不下去。

在这种情况下,只能使用最原始的多线程方式threading开始一个子线程。threading有两种写法,这里我选择的是重写Tread类,并在run方法里写上要运行的代码。

1
2
3
4
5
6
7
8
9
10
11
class myThread (threading.Thread):   #继承父类threading.Thread
def __init__(self, name, length):
threading.Thread.__init__(self)
self.name = name
self.length = length
def run(self): #把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
global flag,process
while True:
if not flag: return
percent = process / self.length * 100
print(f"\r当期进度:{process} - {percent}%", end="")

效果

完整代码如下

2.4.2 ②tqdm第三方库

2.4.2.1 快速开始

安装

1
pip install tqdm

示例

1
2
3
4
5
from tqdm import tqdm
import time

for i in tqdm(range(6)):
time.sleep(0.5)

输出

2.4.2.2 应用

只需将tqdm写在主线程的for循环上即可

1
2
3
4
5
6
for pwd in tqdm(password_lst):
if not flag: break
f = pool.submit(extract, zfile, pwd)
f.pwd = pwd
f.pool = pool
f.add_done_callback(result)

效果:

2.5 封装

至此,程序搭建成功。

下面可以进行封装,方便调用。

完整代码如下

上面的密码本生成和文件路径都是写死的,所以除此之外,还可以通过输入来获取以上信息。而且还加入了第三方库filetype用来判断文件类型。

完整代码如下

效果如下(绿色字体为手动输入)

3. 破解rar

3.1 环境配置

安装unrar模块

1
pip install unrar

下载安装 unrar library(按照默认路径)

1
http://www.rarlab.com/rar/UnRARDLL.exe

(注:下面都是以win64位演示)

配置环境变量

系统变量中新建变量,变量名输入 UNRAR_LIB_PATH,变量值为 C:Files (x86).dll

进入目录C:Files (x86)64修改下文件名

重启pycharm

3.2 快速开始

将test.txt压缩成test.rar,密码设置为123,运行代码

1
2
3
4
5
from unrar import rarfile


file = rarfile.RarFile('test.rar') #这里写入的是需要解压的文件,别忘了加路径
file.extractall(path='.', pwd='123') #这里写入的是你想要解压到的文件夹

解压成功

需要注意的是,与zipfile不同,此处extractall()的pwd不需要encode转码,该方法会自动转码。

3.3 多线程

待续。。。


python破解压缩包密码
https://huihui486.github.io/2023/02/07/Python/python破解压缩包密码/
作者
灰灰
发布于
2023年2月7日
许可协议