原理说明 程序分成两个py文件,
一个利用 itertools 标准库,用生成器生成密码,解决密码文件占用过多内存的问题。
一个用多进程+多线程来百分百利用CPU进行密码历遍。

解压 zip 文件用到 zipfile 标准库, 解压 rar 文件用到 rarfile 库,需用 pip install rarfile 进行安装。
其中 rar 库需要调用 UnRAR.exe 文件,该文件在 winRAR 安装目录中,只要把这个文件拷贝到代码目录中就可以了。如果没有这个文件,运行时会报错提示 UnRAR 未安装。

这是打包好,可直接运行的的破解软件

首先创建 generate_pass_word.py 文件

from itertools import chain, product, permutations, combinations_with_replacement


class Generate_pass_word:
    def __init__(self):
        self.num = [str(i) for i in range(0, 10)]
        self.lower_letter = 'abcdefghijklmnopqrstuvwxyz'
        self.upper_letter = self.lower_letter.upper()
        self.simple_char = '@#$&%^*!'
        self.minority_char = ",./?;:\'\"\\|,。;:”“‘~·`()(){}[]【】"

    def num_password_1_6(self, n=6):  # 生成1~6位数的数字密码组合。
        num_password = ''
        for i in range(1, n + 1):
            num_password = chain(num_password, product(self.num, repeat=i))
        for i in num_password:
            yield ''.join(i)

    def num_password_n(self, n):  # 生成n位数的数字密码组合。
        num_password = product(self.num, repeat=n)
        for i in num_password:
            yield ''.join(i)

    def low_letter_password_1_6(self, n=6):  # 生成1~6位数的小写字母密码组合。
        low_letter_password = ''
        for i in range(1, n + 1):
            low_letter_password = chain(low_letter_password, product(self.lower_letter, repeat=i))
        for i in low_letter_password:
            yield ''.join(i)

    def low_letter_password_n(self, n):  # 生成n位数的小写字母密码组合。
        low_letter_password = product(self.lower_letter, repeat=n)
        for i in low_letter_password:
            yield ''.join(i)

    def upper_letter_password(self, n=6):  # 生成1~6位数的大写字母密码组合。
        for i in self.low_letter_password_1_6(n):
            yield i.upper()

# =================  所有字符的密码组合  ======================
    def all_letter_password_1_4(self, simple=True):      # 由数字、字母、字符组成的 1到4位 密码。
        dic = {'num': self.num,
               "lower_letter": self.lower_letter,
               "upper_letter": self.upper_letter,
               "char": self.simple_char,
               }
        if simple:
            pass
        else:
            dic['char'] = self.simple_char + self.minority_char

        gene_password_1 = self.simple_char + self.minority_char     # 1 位数密码

        gene_password_2 = ''                                    # 2 位数密码
        group = []         # 存放密码类型的组成
        for i in combinations_with_replacement(dic.keys(), 2):  # 先有放回的取出两种类型的密码。
            for r in permutations(i):                           # 对取出的密码进行排列组合。
                group.append(r)
        pass_group = set(group)                                 # 去除重复项。
        pass_group.discard(('num', 'num'))                      # 去除纯数字和纯字母的。
        pass_group.discard(('lower_letter', 'lower_letter'))
        pass_group.discard(('upper_letter', 'upper_letter'))
        for i in pass_group:
            x, y = i
            gene_password_2 = chain(gene_password_2, product(dic[x],dic[y]))

        gene_password_3 = ''
        group = []  # 存放密码类型的组成
        for i in combinations_with_replacement(dic.keys(), 3):  # 先有放回的取出两种类型的密码。
            for r in permutations(i):  # 对取出的密码进行排列组合。
                group.append(r)
        pass_group = set(group)  # 去除重复项。
        pass_group.discard(('num',)*3)  # 去除纯数字和纯字母的。
        pass_group.discard(('lower_letter',)*3)
        pass_group.discard(('upper_letter',)*3)
        for i in pass_group:
            x, y, z = i
            gene_password_3 = chain(gene_password_3, product(dic[x], dic[y], dic[z]))

        gene_password_4 = ''
        group = []  # 存放密码类型的组成
        for i in combinations_with_replacement(dic.keys(), 4):  # 先有放回的取出两种类型的密码。
            for r in permutations(i):  # 对取出的密码进行排列组合。
                group.append(r)
        pass_group = set(group)  # 去除重复项。
        pass_group.discard(('num',)*4)  # 去除纯数字和纯字母的。
        pass_group.discard(('lower_letter',)*4)
        pass_group.discard(('upper_letter',)*4)
        for i in pass_group:
            x, y, z, n = i
            gene_password_4 = chain(gene_password_4, product(dic[x], dic[y], dic[z], dic[n]))

        for i in chain(gene_password_1,gene_password_2,gene_password_3,gene_password_4):
            yield ''.join(i)

    def all_letter_password_n(self, n, simple=True,):      # 由数字、字母、字符组成的 n 位密码。
        dic = {'num': self.num,
               "lower_letter": self.lower_letter,
               "upper_letter": self.upper_letter,
               "char": self.simple_char,
               }
        if simple:
            pass
        else:
            dic['char'] = self.simple_char + self.minority_char
        for i in combinations_with_replacement(dic.keys(), n):         # 先有放回的取出 n 种类型的密码。
            g = set(permutations(i))               # 先对n种类型密码排列组合,然后去除排列组合中的重复项。
            g.discard(('num',) * n)                   # 去除纯数字的组合,discard()即使去除元素不存在,也不报错。
            g.discard(('lower_letter',) * n)       # 去除纯小写字母的组合。
            g.discard(('upper_letter',) * n)      # 去除纯大写字母的组合。
            for i in g:                                        # 历遍组合。
                for r in product(*[dic[d] for d in i]):  
                    yield ''.join(r)

创建 运行文件 unpack.py

from zipfile import is_zipfile, ZipFile
from rarfile import is_rarfile, RarFile, RarCRCError
from multiprocessing import Manager, Pool, freeze_support, cpu_count
from itertools import chain, cycle
from threading import Thread
import os, time
from generate_pass_word import Generate_pass_word


def unpack(flg, password, read_path, save_path):
    if is_zipfile(read_path):                                  # 先判断该文件是不是zip压缩文件。
        compress_file = ZipFile(read_path)
        while flg.run:
            try:    
                pwd = next(password)      # 获取一个密码。
                # print(pwd)
                compress_file.extractall(path=save_path, pwd=pwd.encode('utf-8'))      # 密码需要编码
                print(f'\n解压密码为:{pwd}')
                with open(os.path.join(save_path, '密码.txt'), 'w') as f:
                    f.write(f'解压密码为:{pwd}')
                compress_file.close()
                flg.run = False
            # except BadZipFile as e:
            #     flg.run = False
            #     print('11压缩文件损坏, 程序退出……', e)
            except StopIteration:
                break
            except Exception as e:
                pass
                #print(e, f'  {pwd}')
                
    else:                       # 判断该文件是不是rar压缩文件。
        compress_file = RarFile(read_path)
        while flg.run:
            try:    
                pwd = next(password)                          # 获取一个密码。
                # print(pwd)
                compress_file.extractall(path=save_path, pwd=pwd)        # 密码不需要编码。
                print(f'\n解压密码为:{pwd}')
                with open(os.path.join(save_path, '密码.txt'), 'w') as f:
                    f.write(f'解压密码为:{pwd}')
                compress_file.close()
                flg.run = False
            except RarCRCError:
                flg.run = False
                print('压缩文件损坏, 程序退出……')
            except StopIteration:
                break
            except Exception as e:
                pass
                # print(e)


def process_num(flg, dict_file):
    # print('process_num  已运行')
    read_path = dict_file['read_path']
    save_path = dict_file['save_path']
    g = Generate_pass_word()
    gen_pwd_1_6 = g.num_password_1_6()
    gen_pwd_7_8 = chain(g.num_password_n(7), g.num_password_n(8))
    gen_pwd_9 = g.num_password_n(9)
    gen_pwd_10 = g.num_password_n(10)
    t1 = Thread(target=unpack, args=(flg, gen_pwd_1_6, read_path, save_path))
    t2 = Thread(target=unpack, args=(flg, gen_pwd_7_8, read_path, save_path))
    t3 = Thread(target=unpack, args=(flg, gen_pwd_9, read_path, save_path))
    t4 = Thread(target=unpack, args=(flg, gen_pwd_10, read_path, save_path))
    t1.start()
    t2.start()
    t3.start()
    t4.start()
    t1.join()
    t2.join()
    t3.join()
    t4.join()


def process_letter(flg, dict_file):
    # print('process_letter  已运行')
    read_path = dict_file['read_path']
    save_path = dict_file['save_path']
    g = Generate_pass_word()
    let_pwd_1_6 = g.low_letter_password_1_6()
    let_pwd_7_8 = chain(g.low_letter_password_n(7), g.low_letter_password_n(8))
    let_pwd_9 = g.low_letter_password_n(9)
    let_pwd_10 = g.low_letter_password_n(10)
    let_up_pwd = g.upper_letter_password()
    t1 = Thread(target=unpack, args=(flg, let_pwd_1_6, read_path, save_path))
    t2 = Thread(target=unpack, args=(flg, let_pwd_7_8, read_path, save_path))
    t3 = Thread(target=unpack, args=(flg, let_pwd_9, read_path, save_path))
    t4 = Thread(target=unpack, args=(flg, let_pwd_10, read_path, save_path))
    t5 = Thread(target=unpack, args=(flg, let_up_pwd, read_path, save_path))
    t1.start()
    t2.start()
    t3.start()
    t4.start()
    t5.start()
    t1.join()
    t2.join()
    t3.join()
    t4.join()
    t5.join()


def process_mixture_1_8(flg, dict_file):
    # print('process_mixture_1_8  已运行')
    read_path = dict_file['read_path']
    save_path = dict_file['save_path']
    g = Generate_pass_word()
    pwd_1_4 = g.all_letter_password_1_4()
    pwd_5_6 = chain(g.all_letter_password_n(5), g.all_letter_password_n(6))
    pwd_7 = g.all_letter_password_n(7)
    pwd_8 = g.all_letter_password_n(8)
    t1 = Thread(target=unpack, args=(flg, pwd_1_4, read_path, save_path))
    t2 = Thread(target=unpack, args=(flg, pwd_5_6, read_path, save_path))
    t3 = Thread(target=unpack, args=(flg, pwd_7, read_path, save_path))
    t4 = Thread(target=unpack, args=(flg, pwd_8, read_path, save_path))
    t1.start()
    t2.start()
    t3.start()
    t4.start()
    t1.join()
    t2.join()
    t3.join()
    t4.join()


def process_mixture_9_10(flg, dict_file):
    # print('process_mixture_9_10  已运行')
    read_path = dict_file['read_path']
    save_path = dict_file['save_path']
    g = Generate_pass_word()
    pwd_9 = g.all_letter_password_n(9)
    pwd_10 = g.all_letter_password_n(10)
    t1 = Thread(target=unpack, args=(flg, pwd_9, read_path, save_path))
    t2 = Thread(target=unpack, args=(flg, pwd_10, read_path, save_path))
    t1.start()
    t2.start()
    t1.join()
    t2.join()


def schedule(flg):
    for i in cycle(['|', '/', '—', '\\']):
        if flg.run:
            print(f'{i} {i} {i} {i} {i} {i}', flush=True, end='')
            time.sleep(0.6)
            print('\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b', flush=True, end='')
        else:
            print('\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b', flush=True, end='')
            break


if __name__ == '__main__':
    freeze_support()
    print('该程序可破解10位之内的密码。\n联系:yan-dream@qq.com')
    path = input('\n请输入压缩文件的完整路径名:\n>>> ')
    read_path = os.path.abspath(path)
    print(read_path)

    if not os.path.exists(read_path) or (not is_zipfile(read_path) and not is_rarfile(read_path)):
        print('该文件不是ZIP、ARA压缩文件!\n\
        程序 3秒后 退出……')
        time.sleep(3)
        os._exit(1)

    # 先创建一个存放的目录。
    dir_path = os.path.dirname(path)
    file_name = os.path.basename(path)
    save_path = os.path.join(dir_path, file_name.split('.')[0])
    dict_file = {'read_path': read_path,
                 'dir_path': dir_path,
                 'file_name': file_name,
                 'save_path': save_path}

    if not os.path.isdir(save_path):
        os.makedirs(save_path)

    Flg = Manager().Namespace()
    Flg.run = True
    print(f'{time.ctime()} 开始对 《{file_name}》 进行密码破解,请等待……')
    Thread(target=schedule, args=(Flg,), daemon=True).start()

    if cpu_count() <= 4:
        cpu_num = cpu_count()
    else:
        cpu_num = 4
    pool = Pool(processes=cpu_num)
    pool.apply_async(process_num, args=(Flg, dict_file))
    pool.apply_async(process_letter, args=(Flg, dict_file))
    pool.apply_async(process_mixture_1_8, args=(Flg, dict_file))
    pool.apply_async(process_mixture_9_10, args=(Flg, dict_file))
    pool.close()
    pool.join()
    if not Flg.run:
        print('\n解压密码保存在 密码.txt 文件中。\n')
        print('单击右上角 X,退出程序。')
        time.sleep(300)
    print('程序结束。')
    time.sleep(3)