├── DumperAnalyze.iml
├── src
├── test
│ └── java
│ │ └── Test.java
└── main
│ ├── resources
│ └── META-INF
│ │ └── MANIFEST.MF
│ └── java
│ └── com
│ └── payloads
│ └── online
│ ├── DumperAgent.java
│ └── DefineTransformer.java
├── config.properties
├── README.md
├── pom.xml
└── .gitignore
/DumperAnalyze.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/test/java/Test.java:
--------------------------------------------------------------------------------
1 | public class Test {
2 |
3 | public static void main(String[] args) {
4 | System.out.println("Hello");
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/config.properties:
--------------------------------------------------------------------------------
1 | # 需要插桩修改的类
2 | class= online.payloads.main.Main
3 | # 需要插桩修改的方法
4 | method=getMain
5 | # 在方法执行前想要执行的代码 (需要Base64编码)
6 | before_code=U3lzdGVtLm91dC5wcmludGxuKCJJbmplY3QiKTsK
--------------------------------------------------------------------------------
/src/main/resources/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Premain-Class: com.payloads.online.DumperAgent
3 | Agent-Class: com.payloads.online.DumperAgent
4 | Can-Redefine-Classes: true
5 |
--------------------------------------------------------------------------------
/src/main/java/com/payloads/online/DumperAgent.java:
--------------------------------------------------------------------------------
1 | package com.payloads.online;
2 |
3 |
4 | import java.io.IOException;
5 | import java.lang.instrument.Instrumentation;
6 | public class DumperAgent {
7 |
8 | public static void premain(String agentArgs, Instrumentation inst) throws IOException {
9 | if (agentArgs != null){
10 | System.out.println(agentArgs);
11 | inst.addTransformer(new DefineTransformer(agentArgs));
12 | }
13 | }
14 |
15 | public static void agentmain(String agentArgs, Instrumentation inst) {
16 | System.out.println("agentmain");
17 | }
18 |
19 | public static void main(String[] args){
20 | System.out.println("Please use the -javaagent option to load the jar package");
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## DumperAnalyze
2 |
3 | > 最近审计了一套产品代码,发现使用了JavaAgent+Javassist技术在类加载后进行替换一部分被加密的方法,感觉也可以通过这个技术应用到其他地方,因此写了这个小工具,原理比较简单。
4 |
5 | 通过JavaAgent与Javassist技术对JVM加载的类对象进行动态插桩,可以做一些破解、加密验证的绕过等操作
6 |
7 | 使用方法:
8 |
9 | ```
10 | java -javaagent:Dumper-Analyze-1.0-SNAPSHOT-jar-with-dependencies.jar=./config.properties -jar SpringApp.jar
11 | ```
12 |
13 | JavaAgent可以通过`=`传递参数,`./config.properties` 是配置文件。
14 |
15 |
16 | ### 配置文件
17 |
18 |
19 | ```properties
20 | # 需要插桩修改的类
21 | class=online.payloads.main.Main
22 | # 需要插桩修改的方法
23 | method=getMain
24 | # 在方法执行前想要执行的代码 (需要Base64编码)
25 | # System.out.println("Inject");
26 | before_code=U3lzdGVtLm91dC5wcmludGxuKCJJbmplY3QiKTsK
27 | ```
28 |
29 | 除了`before_code`还有如下几个方式:
30 |
31 | - before_code 在执行原方法之前插入字节码
32 | - after_code 在原方法执行完毕(return)之前插入字节码
33 | - body_code 覆盖原方法
34 |
35 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | Dumper-Analyze
8 | Dumper-Analyze
9 | 1.0-SNAPSHOT
10 |
11 |
12 | UTF-8
13 | UTF-8
14 | 1.8
15 | 1.8
16 | 1.8
17 |
18 |
19 |
20 |
21 |
22 | org.apache.maven.plugins
23 | maven-assembly-plugin
24 |
25 |
26 | jar-with-dependencies
27 |
28 |
29 |
30 | com.payloads.online.DumperAgent
31 | com.payloads.online.DumperAgent
32 | com.payloads.online.DumperAgent
33 | true
34 | true
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | attached
43 |
44 | package
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | org.javassist
54 | javassist
55 | 3.26.0-GA
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### JetBrains template
3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
4 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
5 |
6 | # User-specific stuff
7 | .idea/**/workspace.xml
8 | .idea/**/tasks.xml
9 | .idea/**/usage.statistics.xml
10 | .idea/**/dictionaries
11 | .idea/**/shelf
12 |
13 | # Generated files
14 | .idea/**/contentModel.xml
15 |
16 | # Sensitive or high-churn files
17 | .idea/**/dataSources/
18 | .idea/**/dataSources.ids
19 | .idea/**/dataSources.local.xml
20 | .idea/**/sqlDataSources.xml
21 | .idea/**/dynamic.xml
22 | .idea/**/uiDesigner.xml
23 | .idea/**/dbnavigator.xml
24 |
25 | # Gradle
26 | .idea/**/gradle.xml
27 | .idea/**/libraries
28 |
29 | # Gradle and Maven with auto-import
30 | # When using Gradle or Maven with auto-import, you should exclude module files,
31 | # since they will be recreated, and may cause churn. Uncomment if using
32 | # auto-import.
33 | # .idea/modules.xml
34 | # .idea/*.iml
35 | # .idea/modules
36 | # *.iml
37 | # *.ipr
38 |
39 | # CMake
40 | cmake-build-*/
41 |
42 | # Mongo Explorer plugin
43 | .idea/**/mongoSettings.xml
44 |
45 | # File-based project format
46 | *.iws
47 |
48 | # IntelliJ
49 | out/
50 |
51 | # mpeltonen/sbt-idea plugin
52 | .idea_modules/
53 |
54 | # JIRA plugin
55 | atlassian-ide-plugin.xml
56 |
57 | # Cursive Clojure plugin
58 | .idea/replstate.xml
59 |
60 | # Crashlytics plugin (for Android Studio and IntelliJ)
61 | com_crashlytics_export_strings.xml
62 | crashlytics.properties
63 | crashlytics-build.properties
64 | fabric.properties
65 |
66 | # Editor-based Rest Client
67 | .idea/httpRequests
68 |
69 | # Android studio 3.1+ serialized cache file
70 | .idea/caches/build_file_checksums.ser
71 |
72 | ### Maven template
73 | target/
74 | pom.xml.tag
75 | pom.xml.releaseBackup
76 | pom.xml.versionsBackup
77 | pom.xml.next
78 | release.properties
79 | dependency-reduced-pom.xml
80 | buildNumber.properties
81 | .mvn/timing.properties
82 | .mvn/wrapper/maven-wrapper.jar
83 |
84 | ### Java template
85 | # Compiled class file
86 | *.class
87 |
88 | # Log file
89 | *.log
90 |
91 | # BlueJ files
92 | *.ctxt
93 |
94 | # Mobile Tools for Java (J2ME)
95 | .mtj.tmp/
96 |
97 | # Package Files #
98 | *.jar
99 | *.war
100 | *.nar
101 | *.ear
102 | *.zip
103 | *.tar.gz
104 | *.rar
105 |
106 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
107 | hs_err_pid*
108 |
109 | .DS_Store
110 | .idea
111 |
--------------------------------------------------------------------------------
/src/main/java/com/payloads/online/DefineTransformer.java:
--------------------------------------------------------------------------------
1 | package com.payloads.online;
2 | import javassist.ClassPool;
3 | import javassist.CtClass;
4 | import javassist.CtMethod;
5 | import javassist.NotFoundException;
6 | import java.util.Base64;
7 | import java.io.IOException;
8 | import java.util.Properties;
9 | import java.io.BufferedInputStream;
10 | import java.io.FileInputStream;
11 | import java.io.InputStream;
12 | import java.lang.instrument.ClassFileTransformer;
13 | import java.lang.instrument.IllegalClassFormatException;
14 | import java.security.ProtectionDomain;
15 |
16 |
17 | public class DefineTransformer implements ClassFileTransformer {
18 |
19 | private Properties propertiesLoader;
20 |
21 | public DefineTransformer(String configPath) throws IOException {
22 | InputStream in = new BufferedInputStream(new FileInputStream(configPath));
23 | propertiesLoader = new Properties();
24 | propertiesLoader.load(in);
25 | }
26 |
27 | private String getProperties(String key){
28 | String value = propertiesLoader.getProperty(key);
29 | if (value == null){
30 | return new String();
31 | }
32 | return value;
33 | }
34 |
35 | private String base64decode(String str) {
36 | byte[] decodedBytes = Base64.getDecoder().decode(str);
37 | return new String(decodedBytes);
38 | }
39 |
40 |
41 | public byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
42 | System.out.println("加载类:" + className);
43 | String packageName = className.replaceAll("/",".");
44 |
45 | if (!packageName.equals(getProperties("class"))){
46 | return null;
47 | }
48 |
49 | ClassPool classPool = ClassPool.getDefault();
50 | System.out.println("创建 ClassPool ... 处理类 : " + className);
51 |
52 | try {
53 | CtClass clazz = classPool.get(packageName);
54 | CtMethod[] Methods = clazz.getDeclaredMethods();
55 |
56 | // 获取方法名称
57 | String methodName = getProperties("method");
58 | if (methodName == null){
59 | System.out.println("获取不到方法名,请检查配置文件");
60 | return null;
61 | }
62 |
63 | // 遍历所有的对象方法
64 | for (CtMethod method : Methods){
65 | if (methodName.equals(method.getName())){
66 | String afterCode = getProperties("after_code");
67 | String bodyCode = getProperties("body_code");
68 | String beforeCode = getProperties("before_code");
69 | System.out.println("处理方法:" + method.getName());
70 |
71 | // 在执行原方法之前插入字节码
72 | if (beforeCode.length() > 0){
73 | method.insertBefore(this.base64decode(beforeCode));
74 | }
75 | // 在原方法执行完毕之前插入字节码
76 | if (afterCode.length() > 0){
77 | method.insertAfter(this.base64decode(afterCode));
78 | }
79 | // 覆盖原方法
80 | if (bodyCode.length() > 0){
81 | method.setBody(this.base64decode(bodyCode));
82 | }
83 |
84 | break;
85 | }
86 | }
87 | byte[] byteCode = clazz.toBytecode();
88 | clazz.detach();
89 | return byteCode;
90 | } catch (Exception e) {
91 | e.printStackTrace();
92 | return null;
93 | }
94 | }
95 | }
96 |
97 |
--------------------------------------------------------------------------------