【问题标题】:Encrypting an executable jar加密可执行jar
【发布时间】:2018-12-05 00:43:06
【问题描述】:

为了了解基础知识,我使用 Eclipse 编写代码并创建我的可执行 jar 文件。

一些背景研究:
我知道您可以反编译 jar 文件并查看源代码。事实上,像 JD GUI 这样的免费程序可以轻松反编译 jar 文件并显示其所有内容。这是一个问题,尤其是如果您想分发一个 java 程序。
当我了解到这一点后,我立即开始四处寻找解决方案,但找不到一个直接的答案。

问题:
我的问题是,你如何加密 jar 文件,或者至少加密类文件,这样如果你反编译它就无法读取?
我一直看到的一个解决方案是您可以混淆您的代码,但这样做的问题是您的代码仍然必须能够运行,因此可以通过一些努力对混淆进行逆向工程。我能想到的唯一其他解决方案是拥有两个单独的 jar 文件,以便其中一个 jar 文件被加密并需要另一个 jar 文件对其进行解密。现在,在你说“他们可以反编译另一个 jar 并用它来解密第一个 jar”之前。我的想法是使用用于解密第一个 jar 的密码。理论上用户可以知道确切的解密方法,但没有密语(cipher)就完全没用了。

我的问题:
我将如何实现这一点?我在问如何运行 jar 文件以使用用户指定的密码加密/解密另一个 jar?
请随意提供示例代码,我正在寻找任何可以得到的帮助。

提前致谢!

【问题讨论】:

  • "但是如果没有密语(密码)就完全没用......" 但是没有地方可以保存使用 jd gui 等基本工具不容易找到的秘密你提到了。
  • 这就是软件许可的用途……你无法阻止某人对你的代码进行逆向工程。添加加密层只会为攻击者增加一个额外的步骤。您将不得不以某种方式将解密密钥分发给最终用户,那么如何阻止他们使用它来解密 JAR?
  • 好奇心让我问:什么编程概念值得窃取,仅仅通过查看输入和输出,然后形成规范来进行逆向工程并不容易。从那并将其交给软件工程团队,并附有“编写此应用程序”的说明。顺便说一句,软件团队可能会比最初有这个好主意的“贷款狼”程序员更好地实现它。哦,这在几乎每个国家都是 100% 合法的。我同意@JakeHolzinger - 软件许可证是最实用的方法。
  • @JamesKPolk,你是对的,只是解密方法不像 (cipher.equals(secretWord)) {decrypt();} 这将是一个使用“数学”的算法使用确切的密码解密代码。查看 AES 256 以更好地理解它。

标签: java security encryption


【解决方案1】:

假设您有一个 JAR 文件,其中一些类在编译后已被加密。

假设您有一个名为SecureMain 的加密类,您想要解密并执行它:

public class SecureMain implements Runnable {

    @Override
    public void run() {
        System.out.println("Running...");
    }

}

给定以下 JAR 文件结构:

org
`---stackoveflow
    `---example
        |---EncryptedClassLoader.class
        |---Main.class
        `---SecureMain.enc

带有enc 文件扩展名的文件是使用一些密钥加密的。

EncryptedClassLoader可以实现类文件在加载前解密:

public class EncryptedClassLoader extends ClassLoader {

    private final SecretKeySpec key;

    public EncryptedClassLoader(SecretKeySpec key) {
        this.key = key;
    }

    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            String[] segments = name.split("\\.");
            String filePath = String.join("/", segments) + ".enc";
            byte[] bytes = decryptResource(filePath);
            return defineClass(name, bytes, 0, bytes.length);
        } catch (Exception e) {
            throw new ClassNotFoundException("Unable to load class: " + name, e);
        }
    }

    private byte[] decryptResource(String filePath) throws Exception {
        File file = new File(getResource(filePath).getFile());
        byte[] bytes = Files.readAllBytes(file.toPath());
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(bytes);
    }

}

然后可以实现Main类从命令行参数加载密钥,然后加载执行加密的SecureMain类:

public class Main {

    public static void main(String[] args) throws Exception {
        byte[] bytes = Base64.getDecoder().decode(args[0]);
        SecretKeySpec key = new SecretKeySpec(bytes, "AES");
        ClassLoader loader = new EncryptedClassLoader(key);
        Class<?> cls = loader.loadClass("com.stackoverflow.example.SecureMain");
        Runnable main = (Runnable) cls.newInstance();
        main.run();
    }

}

最后应该使用作为参数传递的密钥来执行 JAR。

java -jar myjar.jar <base64 encoded key>

【讨论】:

  • 非常感谢。我稍后会对此进行测试,所以现在我不会“接受答案”,以防万一其他人有其他解决方案。顺便问一下,那个命令是在 cmd/PowerShell 中执行的吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-07
  • 2020-10-15
  • 1970-01-01
  • 2014-10-02
  • 2023-03-15
  • 1970-01-01
相关资源
最近更新 更多