9.2 PyZIP-Crack-CLI.py

import itertools
import argparse
import zipfile
import chardet
import signal
import sys
import threading

# Define a global variable to signal the password cracking loop to stop
stop_event = threading.Event()

# Define a signal handler to catch the SIGINT signal
def signal_handler(sig, frame):
    global stop_event
    print('\nExited')
    stop_event.set()
    sys.exit()

def extract_zip(zip_file, start_length, max_length, charset, wordlist=None):
    # filler to prevent print artifacting
    filler = " " * (max_length // 2) # use // to prevent float values

    # Loop through all possible password combinations
    if wordlist:
        with open(wordlist, 'r', errors='ignore') as f:
            passwords = f.read().splitlines()

        # Filter the passwords list to only include passwords within the desired length range
        passwords = [password for password in passwords if start_length <= len(password) <= max_length]

        # Print a message indicating that the dict attack is starting
        print("Starting dictionary attack...")

        # Use the wordlist until it is exhausted, then switch to the brute-force attack
        for i, password in enumerate(passwords, start=1):
            if stop_event.is_set():
                return None

            progress = f"Trying password from wordlist: {password} (on: {i} out of: {len(passwords)}){filler}"
            print("\r" + progress, end="", flush=True)

            try:
                zip_file.extractall(pwd=password.encode())
                print('\n\nPassword found:', password)
                print('Total attempts:', i)   # Print the total number of attempts made
                return password
            except Exception:
                pass

        print('\nWordlist exhausted, switching to brute-force attack...')

    # Generate all possible password combinations
    passwords = (''.join(password) for length in range(start_length, max_length+1) for password in     itertools.product(charset, repeat=length))

    # Print a message indicating that the brute-force attack is starting
    print("\nStarting brute-force attack...")

    for i, password in enumerate(passwords, start=1):
        if len(password) > max_length:
            break

        if stop_event.is_set():
            return None

        progress = f"Trying password: {password} (on iteration: {i} of cycle: {len(password)})"
        print("\r" + progress, end="", flush=True)

        # Attempt to extract the ZIP file with the current password
        try:
            zip_file.extractall(pwd=password.encode())
            print('\n\nPassword found:', password)
            print('Total attempts:', i)   # Print the total number of attempts made
            return password
        except Exception:
            global count
            count = i
            pass

    # If no password was found, print the total number of attempts made and return None
    print('\n\nPassword not found.')
    print('Total attempts:', count)
    return None

if __name__ == '__main__':
    # Parse command-line arguments
    parser = argparse.ArgumentParser(description='Extract a ZIP file using a brute-force attack.')
    parser.add_argument('-zip', type=str, required=True, help='The path to the ZIP file.')
    parser.add_argument('-min', type=int, default=1, help='The starting length of the password to try.')
    parser.add_argument('-max', type=int, default=8, help='The maximum length of the password to try.')
    parser.add_argument('-wordlist', type=str, help='The path to a file containing a list of possible passwords.')
    parser.add_argument('-charset', type=str, default='abcdefghijklmnopqrstuvwxyz', help='The character set to use for the brute-force attack.')
    args = parser.parse_args()

    # Check if no arguments were provided
    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit()

    # Register the signal handler
    signal.signal(signal.SIGINT, signal_handler)

    # Open the ZIP file
    try:
        zip_file = zipfile.ZipFile(args.zip)
    except Exception as e:
        parser.error('Failed to open ZIP file: ' + str(e))

    # Extract the ZIP file using a brute-force attack
    password = extract_zip(zip_file, args.min, args.max, args.charset, args.wordlist)

# PS D:\git-python\办公自动化> python.exe '.\9.2 PyZIP-Crack-CLI.py.py' -zip ./files/合并PDF-密码.zip -min 2 -max 8 -wordlist ./files/rockyou.txt
# Starting dictionary attack...
# Trying password from wordlist: 123456 (on: 1 out of: 7702674)

# Password found: 123456
# Total attempts: 1