zip文件解压密码破解小助手

背景

 在网上下载了一个Java虚拟机的技术文档,本来是想观摩学习一下,但有个坑,下载下来解压需要密码,资源网站给的压缩密码不对。先试试了一下免费软件,说是免费,等了好久破解了,获取密码竟然收费,一次竟然68块大洋,虽说知识无价,但本着自己能干事自己动手,勤俭持家的态度,还是简单尝试了一下,本次记录一下,以供后续薅羊毛

思路

通过多线程+随机密码 进行逐个尝试,成功后输出密码到文件,中断破解程序,简单粗暴,细节没过多考量,密码复杂度高的时候,性能和效率会是个问题,后续在探讨了

一、项目依赖

<dependency>
      <groupId>net.lingala.zip4j</groupId>
      <artifactId>zip4j</artifactId>
      <version>1.3.2</version>
 </dependency>

二、密码生成

密码需要人工预判一下,根据实际情况,选择对应的规则生成,本次没做过多考虑,有优化

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


class PasswordRandom {
    //数字
    public static final String NUMBER = "0123456789";
    //字母
    public static final String ALPHABET = "abcdefghijklmnopqrstuvwyxz";
    //特殊符号
    public static final String SYMBOL = "~!@#$%^&*()_+[]{};,.<>?-=";

    /**
     * 获取指定的字符
     * @param includeNumber   是否包含数字
     * @param includeAlphabet 是否包含字母
     * @param includeSymbol   是否包含字符
     * @param length          字符长度
     * @return
     */
    public static List<String> getStr(boolean includeNumber, boolean includeAlphabet, boolean includeSymbol, int length) {

        List<String> result = new ArrayList<>();
        StringBuffer sb = new StringBuffer();
        if (includeNumber) {
            sb.append(NUMBER);
        }
        if (includeAlphabet) {
            sb.append(ALPHABET);
            sb.append(ALPHABET.toUpperCase());
        }
        if (includeSymbol) {
            sb.append(SYMBOL);
        }
        if (sb.length() <= length) {
            result.add(sb.toString());
        }
        char[] chars = sb.toString().toCharArray();
        String[] strings = new String[chars.length];
        for (int i = 0; i < chars.length; i++) {
            strings[i] = String.valueOf(chars[i]);
        }
        String[] allLists = getAllLists(strings, length);
        return Arrays.asList(allLists);
    }

    /**
     * 获取指定位数的数据集合
     * @param elements 基类字符数组
     * @param length   指定字符串位数
     * @return
     */
    public static String[] getAllLists(String[] elements, int length) {
        String[] allLists = new String[(int) Math.pow(elements.length, length)];
        if (length == 1) {
            return elements;
        } else {
            String[] allSublists = getAllLists(elements, length - 1);
            int arrayIndex = 0;
            for (int i = 0; i < elements.length; i++) {
                for (int j = 0; j < allSublists.length; j++) {
                    allLists[arrayIndex] = elements[i] + allSublists[j];
                    arrayIndex++;
                }
            }
            return allLists;
        }
    }

    /**
     * 获取全部字符集合,包含数字,字母,特殊字符
     * @param length
     * @return
     */
    public static List<String> getCombinationStr(int length) {
        return getStr(true, true, true, length);
    }

    /**
     * 获取数字字符集合
     * @param length
     * @return
     */
    public static List<String> getNumberStr(int length) {
        return getStr(true, false, false, length);
    }

    /**
     * 获取字母字符集合
     * @param length
     * @return
     */
    public static List<String> getAlphabetStr(int length) {
        return getStr(false, true, false, length);
    }

    /**
     * 获取特殊符号字符集合
     *
     * @param length
     * @return
     */
    public static List<String> getSymbolStr(int length) {
        return getStr(false, false, true, length);
    }

    public static void main(String[] args) {
        //固定位数的纯数字组合
        final List<String> str1 = getNumberStr(4);
        System.out.println(str1.toString());
        //固定长度的纯字母组合
        final List<String> str2 = getAlphabetStr(4);
        System.out.println(str2.toString());
        //固定长度特殊字符组合
        final List<String> str3 = getSymbolStr(4);
        System.out.println(str3.toString());
        //固定长度随机组合
        final List<String> str4 = getCombinationStr(4);
        System.out.println(str4.toString());

    }

}

三、文件解压


import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.FileHeader;


import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.List;


public class UnZipUtils {

    /**
     * @param source   原始文件路径
     * @param dest     解压路径
     * @param password 解压文件密码
     */
    public static boolean unZip(String source, String dest, String password) {
        try {
            File zipFile = new File(source);
            ZipFile zFile = new ZipFile(zipFile);
            zFile.setFileNameCharset(StandardCharsets.UTF_8.name());
            // 解压目录
            File destDir = new File(dest);
            // 目标目录不存在时,创建该文件夹
            if (!destDir.exists()) {
                destDir.mkdirs();
            }
            if (zFile.isEncrypted()) {
                // 设置密码
                zFile.setPassword(password.toCharArray());
            }
            // 将文件抽出到解压目录(解压)
            zFile.extractAll(dest);
            List<FileHeader> headerList = zFile.getFileHeaders();
            File file = null;
            for (FileHeader fileHeader : headerList) {
                if (!fileHeader.isDirectory()) {
                    file = new File(destDir, fileHeader.getFileName());
                    System.out.println(file.getAbsolutePath() + "文件解压成功!");
                }
            }
        } catch (ZipException e) {
            return false;
        }
        return true;
    }
}

四、文件处理

import org.apache.commons.lang3.StringUtils;

import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ZipPwdCracking {

    private ThreadPoolExecutor threadPoolExecutor;

    //使用线程池进行文件解压尝试处理
    public ZipPwdCracking() {
        this.threadPoolExecutor = new ThreadPoolExecutor(20, 100, 30,
                TimeUnit.SECONDS, new LinkedBlockingQueue<>(), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
    }

    //解压处理
    public String run(String source, String dest) {
        //设置密码使用类型
        List<String> numberStr = PasswordRandom.getNumberStr(4);
        //创建密码集合队列
        LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>();
        numberStr.forEach(num -> queue.offer(num));
        //开始时间
        long startTime = System.currentTimeMillis();
        while (!queue.isEmpty()) {
            threadPoolExecutor.execute(() -> {
                String name = Thread.currentThread().getName();
                String key = queue.poll();
                if (StringUtils.isNotBlank(key)) {
                    //解压
                    boolean result = UnZipUtils.unZip(source, dest, key);
                    if (result) {
                        try (FileWriter fileWriter = new FileWriter(dest + "\\pwd.txt")) {
                            fileWriter.write(key);
                            System.out.println("线程:" + name + ",密码是:" + key+",处理结束");
                            //清除队列
                            queue.clear();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    } else {
                        System.out.println("线程:" + name + "," + key + "密码错误");
                    }
                }
            });
        }

        final long endTime = System.currentTimeMillis();
        System.out.println("共花费:" + (endTime - startTime) / 1000 + "秒");
        return null;
    }


    //测试主方法
    public static void main(String[] args) {
        ZipPwdCracking pwdCracking = new ZipPwdCracking();
        String source = "D:\\temp\\测试.zip";
        String dest = "D:\\temp\\test";
        pwdCracking.run(source, dest);
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值