想要加密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 ...... ......
|