java程序ClassLoad加密的通用破解方法

想要加密java程序是比较困难的,一般的做法就是代码混淆,增加代码阅读的难度,另外就是修改Class文件的字节码,然后再虚拟机加载类的时候进行解密。修改字节码的解密方法一般是修改JDK中的ClassLoad或者自定义一个ClassLoad来解密Class。有些为了不让别人看到解密算法有些还会用C来写解密程序,再用jni来调用。

一般用改ClassLoader来加密的这种方法都可以用 javaagent 获取到解密后class。

使用 Instrumentation,开发者可以构建一个独立于应用程序的代理程序(Agent),用来监测和协助运行在 JVM 上的程序,甚至能够替换和修改某些类的定义。有了这样的功能,开发者就可以实现更为灵活的运行时虚拟机监控和 Java 类操作了,这样的特性实际上提供了一种虚拟机级别支持的 AOP 实现方式,使得开发者无需对 JDK 做任何升级和改动,就可以实现某些 AOP 的功能了。
介绍地址:
https://www.ibm.com/developerworks/cn/java/j-lo-jse61/

输出Class文件到指定目录的代码

1、新建一个maven项目

如:class-agent

2、写两个类

PreMainExecutor.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.wwh.agent;

import java.lang.instrument.Instrumentation;

public class PreMainExecutor {

public static void premain(String agentOps, Instrumentation inst) {
System.out.println("premain execute..........");
System.out.println("参数:" + agentOps);
// 添加Transformer
inst.addTransformer(new PrintClassFileAgent(agentOps));

// 可以用这个来加载jar包
// inst.appendToSystemClassLoaderSearch(jarfile);
}
}

PrintClassFileAgent.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.wwh.agent;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class PrintClassFileAgent implements ClassFileTransformer {

public static final String OUT_FILE_DIR = "/opt/logs/wwh/classFile/";

private File outFileDir;

public PrintClassFileAgent(){

}

public PrintClassFileAgent(String fileDir){
String fileOutDir = OUT_FILE_DIR;
if (fileDir != null && !"".equals(fileDir)) {
fileOutDir = fileDir;
}
outFileDir = new File(fileOutDir);
outFileDir.mkdirs();

}

public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
System.out.println("类加载器:" + loader);
System.out.println("类名称:" + className);

String pathName = className.replaceAll("[.]", "/");
pathName = pathName + ".class";

File f = new File(OUT_FILE_DIR + pathName);

f.getParentFile().mkdirs();
try {
f.createNewFile();
FileOutputStream fos = new FileOutputStream(f);
fos.write(classfileBuffer);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}

return null;
}

}

3、 修改pom文件

用于指定:Premain-Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wwh.agent</groupId>
<artifactId>class-agent</artifactId>
<version>0.0.1-SNAPSHOT</version>

<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<Premain-Class>
com.wwh.agent.PreMainExecutor
</Premain-Class>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>

</project>

用法

将上面的maven项目编译打包,将 class-agent-0.0.1-SNAPSHOT.jar 复制到目标位置。

用如下命令启动想要破解的程序:

1
2
3
4
5
java -javaagent:class-agent-0.0.1-SNAPSHOT.jar -cp runner-0.0.1-SNAPSHOT.jar com.wwh.runner.EmptyRunner

//指定输出Class文件目录的
java -javaagent:class-agent-0.0.1-SNAPSHOT.jar=/opt/xxx/out -cp runner-0.0.1-SNAPSHOT.jar com.wwh.runner.EmptyRunner

如果需要破解的程序本身就有使用javaagent,需要将上面的agent放到调用链的最后面。

1
2
java -javaagent:agentA.jar -javaagent:class-agent-0.0.1-SNAPSHOT.jar XXProgram

效果

将在目录下保存所有加载的类的class文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
E:\opt\logs\wwh\classFile>tree
......
......
├─nio
│ ├─ch
│ ├─cs
│ └─fs
├─reflect
│ ├─annotation
│ └─generics
│ ├─factory
│ ├─parser
│ ├─reflectiveObjects
│ ├─repository
│ ├─scope
│ ├─tree
│ └─visitor
├─security
│ ├─action
│ ├─jca
│ ├─provider
│ └─util
├─text
│ └─resources
│ └─zh
├─usagetracker
└─util
├─calendar
├─locale
│ └─provider
├─logging
├─resources
│ ├─en
│ └─zh
└─spi
......
......