├── .github
└── workflows
│ ├── build.yml
│ ├── leak.yml
│ └── maven.yml
├── .gitignore
├── CHANGELOG.MD
├── LICENSE
├── README.md
├── check-version.bat
├── img
└── 001.png
├── package.bat
├── pom.xml
├── release
└── README.md
├── src
└── main
│ ├── java
│ └── me
│ │ └── n1ar4
│ │ ├── jar
│ │ └── obfuscator
│ │ │ ├── Const.java
│ │ │ ├── Logo.java
│ │ │ ├── Main.java
│ │ │ ├── analyze
│ │ │ ├── DiscoveryClassVisitor.java
│ │ │ ├── DiscoveryMethodAdapter.java
│ │ │ ├── MethodCallClassVisitor.java
│ │ │ └── MethodCallMethodVisitor.java
│ │ │ ├── asm
│ │ │ ├── ClassNameVisitor.java
│ │ │ ├── CompileInfoVisitor.java
│ │ │ ├── FieldNameVisitor.java
│ │ │ ├── IntToXorVisitor.java
│ │ │ ├── JunkCodeVisitor.java
│ │ │ ├── MainMethodVisitor.java
│ │ │ ├── MethodNameVisitor.java
│ │ │ ├── ParameterVisitor.java
│ │ │ ├── StringArrayVisitor.java
│ │ │ └── StringVisitor.java
│ │ │ ├── base
│ │ │ ├── ClassField.java
│ │ │ ├── ClassFileEntity.java
│ │ │ ├── ClassReference.java
│ │ │ └── MethodReference.java
│ │ │ ├── config
│ │ │ ├── BaseCmd.java
│ │ │ ├── BaseConfig.java
│ │ │ ├── Manager.java
│ │ │ └── Parser.java
│ │ │ ├── core
│ │ │ ├── AnalyzeEnv.java
│ │ │ ├── DiscoveryRunner.java
│ │ │ ├── MethodCallRunner.java
│ │ │ ├── ObfEnv.java
│ │ │ ├── ObfHashMap.java
│ │ │ └── Runner.java
│ │ │ ├── loader
│ │ │ ├── CustomClassLoader.java
│ │ │ └── CustomClassWriter.java
│ │ │ ├── templates
│ │ │ ├── StringDecrypt.java
│ │ │ └── StringDecryptDump.java
│ │ │ ├── transform
│ │ │ ├── ClassNameTransformer.java
│ │ │ ├── DeleteInfoTransformer.java
│ │ │ ├── FieldNameTransformer.java
│ │ │ ├── JunkCodeTransformer.java
│ │ │ ├── MainClassTransformer.java
│ │ │ ├── MethodNameTransformer.java
│ │ │ ├── ParameterTransformer.java
│ │ │ ├── StringArrayTransformer.java
│ │ │ ├── StringTransformer.java
│ │ │ └── XORTransformer.java
│ │ │ └── utils
│ │ │ ├── ByteUtil.java
│ │ │ ├── ColorUtil.java
│ │ │ ├── DescUtil.java
│ │ │ ├── DirUtil.java
│ │ │ ├── FileUtil.java
│ │ │ ├── IOUtils.java
│ │ │ ├── JunkUtil.java
│ │ │ ├── NameUtil.java
│ │ │ ├── PackageUtil.java
│ │ │ └── RandomUtil.java
│ │ ├── jrandom
│ │ └── core
│ │ │ └── JRandom.java
│ │ └── log
│ │ ├── Log.java
│ │ ├── LogLevel.java
│ │ ├── LogManager.java
│ │ ├── LogUtil.java
│ │ ├── Logger.java
│ │ └── LoggingStream.java
│ └── resources
│ ├── config.yaml
│ └── thanks.txt
└── test
├── README.md
├── origin.jar
├── shiro.jar
├── test-01.yaml
├── test-02.yaml
├── test-03.yaml
├── test-sb-01.yaml
└── test-sb-02.yaml
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: jar obfuscator build
2 |
3 | on:
4 | workflow_dispatch:
5 |
6 | env:
7 | VERSION: "2.0.0-RC2"
8 |
9 | jobs:
10 |
11 | build:
12 | runs-on: windows-2019
13 | steps:
14 | - name: checkout the source
15 | uses: actions/checkout@v4
16 | with:
17 | path: jar-obfuscator
18 |
19 | - name: set up java 8
20 | uses: actions/setup-java@v4
21 | with:
22 | java-version: '8'
23 | distribution: 'zulu'
24 | cache: maven
25 |
26 | - name: build core
27 | run: |
28 | .\package.bat
29 | mv .\target\jar-obfuscator-${{ env.VERSION }}-jar-with-dependencies.jar jar-obfuscator-${{ env.VERSION }}.jar
30 | working-directory: jar-obfuscator
31 |
32 | - name: upload artifact
33 | uses: actions/upload-artifact@v4
34 | with:
35 | name: jar-obfuscator
36 | path: |
37 | jar-obfuscator/jar-obfuscator-${{ env.VERSION }}.jar
38 |
--------------------------------------------------------------------------------
/.github/workflows/leak.yml:
--------------------------------------------------------------------------------
1 | name: leak check
2 |
3 | on:
4 | push:
5 | branches: [ "main" ]
6 | pull_request:
7 | branches: [ "main" ]
8 |
9 | jobs:
10 |
11 | check:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v4
15 | with:
16 | fetch-depth: 0
17 | - uses: gitleaks/gitleaks-action@v2
18 | env:
19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
20 | GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}
--------------------------------------------------------------------------------
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | name: maven check
2 |
3 | on:
4 | push:
5 | branches: [ "main" ]
6 | pull_request:
7 | branches: [ "main" ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v3
16 | - name: Set up JDK 8
17 | uses: actions/setup-java@v3
18 | with:
19 | java-version: '8'
20 | distribution: 'zulu'
21 | cache: maven
22 | - name: Build with Maven
23 | run: mvn -B package --file pom.xml
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea/modules.xml
8 | .idea/jarRepositories.xml
9 | .idea/compiler.xml
10 | .idea/libraries/
11 | *.iws
12 | *.iml
13 | *.ipr
14 |
15 | ### Eclipse ###
16 | .apt_generated
17 | .classpath
18 | .factorypath
19 | .project
20 | .settings
21 | .springBeans
22 | .sts4-cache
23 |
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | build/
31 | !**/src/main/**/build/
32 | !**/src/test/**/build/
33 |
34 | ### VS Code ###
35 | .vscode/
36 |
37 | ### Mac OS ###
38 | .DS_Store
39 |
40 | ### OTHERS ###
41 | .idea/
42 | log/
43 | *.jar
44 | *.yml
45 | *.yaml
46 | cmake-*/
47 | code-encryptor-temp/
48 | jar-obfuscator-temp/
49 | token.txt
50 |
--------------------------------------------------------------------------------
/CHANGELOG.MD:
--------------------------------------------------------------------------------
1 | # CHANGELOG
2 |
3 | ## 2.0.0-RC2
4 |
5 | 更新日志:
6 |
7 | - [重要] 开启配置 `useSpringBoot` 初步支持 `SpringBoot` 混淆
8 | - [重要] 开启配置 `useWebWar` 初步支持 `war` 包混淆
9 | - [优化] 优化 `jar` 压缩代码兼容 `SpringBoot` 等禁用压缩环境
10 |
11 | 感谢以下用户的贡献:
12 |
13 | - 4ra1n (https://github.com/4ra1n)
14 |
15 | 可供下载的文件由 `Github Actions` 构建,使用 `java -jar` 启动
16 |
17 | ## 2.0.0-RC1
18 |
19 | jar-obfuscator v2 初版 RC1 发布(非正式 仅供测试)
20 |
21 | 主要更新内容:简化配置和文档,删除某些不必要的功能,尽可能简化,更多功能日后更新
22 |
23 | 目前 `README.md` 和所有代码已经变更,如果有 `v1` 版本需求可以在 `release` 下载历史代码
24 |
25 | 感谢以下用户的贡献:
26 |
27 | - 4ra1n (https://github.com/4ra1n)
28 |
29 | 可供下载的文件由 `Github Actions` 构建,使用 `java -jar` 启动
30 |
31 | ## 0.2.0
32 |
33 | 支持了 `GUI` 界面,但没有过多测试,之后逐步完善
34 |
35 | 解决了目标代码写法存在 `class.getResource("/dir/")` 时得到 `null` 的问题,这是最终打包 `JAR` 部分的代码问题
36 |
37 | 更新日志:
38 |
39 | - [重要] 支持 `GUI` 界面(beta)
40 | - [功能] 字符串替换时处理反射字符串类名
41 | - [功能] 添加对泛型 `signature` 的处理
42 | - [优化] 优化 `builtin` 黑名单解析和注释
43 | - [BUG] 修复 `NATIVE` 的 `malloc` 错误
44 | - [BUG] 修复没有添加目录到 `JAR ENTRY` 的问题
45 | - [BUG] 花指令混淆部分遇到类加载报错解决
46 | - [BUG] 修复 `MANIFEST.MF` 没有完全修改的问题
47 |
48 | 感谢以下用户的贡献:
49 |
50 | - 4ra1n (https://github.com/4ra1n)
51 | - pcdlrzxx (https://github.com/pcdlrzxx)
52 |
53 | 可供下载的文件由 `Github Actions` 构建,使用 `java -jar` 启动
54 |
55 | ## 0.1.1
56 |
57 | 更新日志:
58 |
59 | - [功能] 花指令数添加简单的控制流
60 | - [功能] 花指令从单 `int` 类型拓展到更多
61 | - [功能] 花指令支持添加无意义的垃圾方法
62 | - [优化] 不应该对接口和枚举等类型进行花指令
63 | - [优化] 优化命令行输出的信息
64 | - [其他] 在 `CI` 增加 `Gitleaks` 检查
65 | - [其他] 提供 `Dockerfile` 和构建脚本
66 |
67 | 感谢以下用户的贡献:
68 |
69 | - 4ra1n (https://github.com/4ra1n)
70 |
71 | 可供下载的文件由 `Github Actions` 构建,使用 `java -jar` 启动
72 |
73 | ## 0.1.0
74 |
75 | 修复了一些已知问题,随机数支持直接调用 `CPU` 的 `RDRAND` 指令生成
76 |
77 | 注意,配置文件可能不兼容,请重新生成
78 |
79 | 更新日志:
80 |
81 | - [功能] 支持配置随机数来源为 `CPU` 的 `RDRAND` 指令
82 | - [功能] 类黑名单新增正则配置 `classBlackRegexList`
83 | - [功能] 对于错误和默认的 `AES KEY` 配置自动生成随机的
84 | - [BUG] 不应该对 `JNI` 类进行混淆
85 | - [BUG] 处理错误配置文件可能导致的异常
86 |
87 | 感谢以下用户的贡献:
88 |
89 | - 4ra1n (https://github.com/4ra1n)
90 |
91 | 可供下载的文件由 `Github Actions` 构建,使用 `java -jar` 启动
92 |
93 | ## 0.0.8-beta
94 |
95 | 修复了某些配置的 `BUG` 并参考 `Y4tacker` 议题提供隐藏功能
96 |
97 | 注意,配置文件可能不兼容,请重新生成
98 |
99 | 更新日志:
100 |
101 | - [功能] 通过添加 `SYNTHETIC` 使反编译时可以隐藏方法
102 | - [功能] 通过添加 `SYNTHETIC` 使反编译时可以隐藏字段
103 | - [功能] 解决报错并支持高版本 `JAVA` 的字节码加密功能
104 | - [BUG] 修复了开启包名混淆但不开启类名混淆无法生效的问题
105 | - [BUG] 不允许开启 `enablePackageName` 时使用字节码加密
106 |
107 | 感谢以下用户的贡献:
108 |
109 | - 4ra1n (https://github.com/4ra1n)
110 | - pcdlrzxx (https://github.com/pcdlrzxx)
111 | - Y4tacker (https://github.com/Y4tacker)
112 |
113 | 可供下载的文件由 `Github Actions` 构建,使用 `java -jar` 启动
114 |
115 | ## 0.0.7-beta
116 |
117 | 更新日志:
118 |
119 | - [功能] 记录贡献者列表并在启动时打印感谢信息
120 | - [功能] 增加一个新参数仅检查是否有新版本
121 | - [BUG] 修复花指令混淆功能某些情况抛出的异常
122 | - [优化] 错误的配置会在启动时输出原因并停止
123 | - [优化] 调整 `JNI` 日志级别减少无用信息
124 | - [优化] 检查字节码加密的 `Java 8` 环境
125 |
126 | 感谢以下用户的贡献:
127 |
128 | - 4ra1n (https://github.com/4ra1n)
129 | - pcdlrzxx (https://github.com/pcdlrzxx)
130 |
131 | 可供下载的文件由 `Github Actions` 构建,使用 `java -jar` 启动
132 |
133 | ## 0.0.6-beta
134 |
135 | 内置 `父类/接口->方法` 的映射黑名单,阻止某些 `@Override` 方法的混淆
136 |
137 | 注意,配置文件可能不兼容,请重新生成
138 |
139 | 更新日志:
140 |
141 | - [功能] 内置黑名单阻止某些类的继承/实现方法混淆
142 | - [功能] 启动时请求 `OSS` 检测是否有新版本可用
143 | - [功能] 字符串解密类的类名方法名可以配置
144 | - [功能] 优化命令行输出并允许彩色输出
145 |
146 | 感谢以下用户的贡献:
147 |
148 | - 4ra1n (https://github.com/4ra1n)
149 |
150 | 可供下载的文件由 `Github Actions` 构建,使用 `java -jar` 启动
151 |
152 | ## 0.0.5-beta
153 |
154 | 不建议开启 `enableMethodName` 配置,建议其他选项混合搭配测试
155 |
156 | 更新日志:
157 |
158 | - [BUG] 修复方法名混淆可能遇到的关键 `BUG`
159 | - [BUG] 方法 `OWNER` 和 `DESC` 替换不完善
160 | - [优化] 优化启动提示和日志提示信息
161 | - [优化] 进一步优化依赖缩小 `JAR` 包体积
162 | - [优化] 优化 `README` 文档提供更多配置教程
163 |
164 | 感谢以下用户的贡献:
165 |
166 | - 4ra1n (https://github.com/4ra1n)
167 |
168 | 可供下载的文件由 `Github Actions` 构建,使用 `java -jar` 启动
169 |
170 | ## 0.0.4-beta
171 |
172 | 修复关键 `BUG` 并完善配置文件注释和文档。之前的版本不开启类名混淆时,无法单独使用其他混淆方法。混淆配置有很多选项,其中部分配置会分析依赖和引用并修改,可能出现预期外的行为。另外有多种不修改引用的混淆方式,例如字符串加密和异或加密整数,可以单独搭配使用这些不修改引用的混淆方式
173 |
174 | 注意,配置文件可能不兼容,请重新生成
175 |
176 | 更新日志:
177 |
178 | - [BUG] 字符串加密编码不一致导致乱码问题
179 | - [BUG] 修复不开启类名混淆某些混淆无法运行问题
180 | - [BUG] 修复解压 `JAR` 时无法访问文件的问题
181 | - [优化] 优化 `README` 和配置文件中的注释
182 | - [优化] 提示 `MAC` 中不支持使用字节码加密
183 |
184 | 感谢以下用户的贡献:
185 |
186 | - 4ra1n (https://github.com/4ra1n)
187 |
188 | 可供下载的文件由 `Github Actions` 构建,使用 `java -jar` 启动
189 |
190 | ## 0.0.3-beta
191 |
192 | 修复了一些 `BUG` 补全配置文件和文档
193 |
194 | 注意,配置文件可能不兼容,请重新生成
195 |
196 | 更新日志:
197 |
198 | - [功能] 增加混淆类黑名单(具体内容参考配置注释)
199 | - [功能] 增加混淆项目根包名配置(具体内容参考配置注释)
200 | - [BUG] 修复混淆时引用处理的错误
201 | - [BUG] 修复 `module-info` 导致的报错
202 | - [BUG] 解压 `JAR` 文件可能存在报错终止
203 | - [BUG] 字符串加密处理的过程设置正确的 `flag`
204 | - [优化] 优化各种黑名单和配置选项的逻辑
205 | - [文档] 完善 `README` 中的实战配置文档
206 |
207 | 感谢以下用户的贡献:
208 |
209 | - 4ra1n (https://github.com/4ra1n)
210 |
211 | 可供下载的文件由 `Github Actions` 构建,使用 `java -jar` 启动
212 |
213 | ## 0.0.2-beta
214 |
215 | 注意,配置文件可能不兼容,请重新生成
216 |
217 | 更新日志:
218 |
219 | - [功能] 混淆指令使用简单的随机生成
220 | - [功能] 字符串加密的 `AES KEY` 可以配置
221 | - [功能] 允许配置临时目录是否自动删除
222 | - [优化] 花指令级别更细致的级别划分
223 | - [优化] 处理可能的 `MethodTooLargeException`
224 | - [优化] 删除无意义代码逻辑提高效率
225 | - [NATIVE] 解密字节码时不应该打印过多敏感信息
226 |
227 | 感谢以下用户的贡献:
228 |
229 | - 4ra1n (https://github.com/4ra1n)
230 |
231 | 可供下载的文件由 `Github Actions` 构建,使用 `java -jar` 启动
232 |
233 | ## 0.0.1-beta
234 |
235 | 初始版本(非稳定版本,测试有 BUG 欢迎反馈)
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 4ra1n (Jar Analyzer Team)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Jar-Obfuscator V2
2 |
3 |
4 |
5 | 
6 | 
7 | 
8 | 
9 | 
10 |
11 | [CHANGE LOG](CHANGELOG.MD)
12 |
13 | `Jar Obfuscator V2` 是一个 `JAR` 文件混淆工具
14 |
15 | - 命令行模式,简单易用
16 | - 仅单个 `JAR` 文件小于 `1 MB` 超轻量
17 | - 简洁的配置文件快速上手
18 | - 输入 `JAR` 直接输出混淆后的 `JAR`
19 |
20 | 注意:目前是 `v2` 版本,如果你需要 `v1` 版本可以从 `release` 页面下载
21 |
22 | ## 开始
23 |
24 | [前往下载](https://github.com/jar-analyzer/jar-obfuscator/releases/latest)
25 |
26 | 简单命令即可启动(第一次启动将自动生成配置文件)
27 |
28 | ```shell
29 | java -jar jar-obfuscator.jar --jar test.jar --config config.yaml
30 | ```
31 |
32 | jar-obfuscator-pro 和 jar-obfuscator-ultra 版本正在开发中 暂时不会公开
33 |
34 | | 功能 | jar-obfuscator 开源版 | jar-obfuscator-pro | jar-obfuscator-ultra |
35 | |--------------------|--------------------|--------------------|----------------------|
36 | | 类名混淆(包含引用修改) | ✅ | ✅ | ✅ |
37 | | 包名混淆(包含引用修改) | ✅ | ✅ | ✅ |
38 | | 方法名混淆(包含引用修改) | ✅ | ✅ | ✅ |
39 | | 字段名混淆(包含引用修改) | ✅ | ✅ | ✅ |
40 | | 方法参数名混淆(包含引用修改) | ✅ | ✅ | ✅ |
41 | | 删除编译调试信息 | ✅ | ✅ | ✅ |
42 | | 字符串 AES 加密运行时解密 | ✅ | ✅ | ✅ |
43 | | 字符串修改为访问全局列表方式 | ✅ | ✅ | ✅ |
44 | | 整型常数多重异或混淆 | ✅ | ✅ | ✅ |
45 | | 添加垃圾代码(可指定多级别) | ✅ | ✅ | ✅ |
46 | | IDEA 反编译时隐藏方法 | ✅ | ✅ | ✅ |
47 | | IDEA 反编译时隐藏字段 | ✅ | ✅ | ✅ |
48 | | 初步支持 SpringBoot 混淆 | ✅ | ✅ | ✅ |
49 | | 初步支持 Web WAR 混淆 | ✅ | ✅ | ✅ |
50 |
51 | ## 配置
52 |
53 | ```yaml
54 | # jar obfuscator v2 配置文件
55 | # jar obfuscator v2 by jar-analyzer team (4ra1n)
56 | # https://github.com/jar-analyzer/jar-obfuscator
57 |
58 | # 日志级别
59 | # debug info warn error
60 | logLevel: info
61 |
62 | # 如果你是 springboot 请开启
63 | useSpringBoot: false
64 | # 如果你是 war web 项目请开启
65 | useWebWar: false
66 |
67 | # 混淆字符配置
68 | # 类名方法名等信息会根据字符进行随机排列组合
69 | obfuscateChars:
70 | - "i"
71 | - "l"
72 | - "L"
73 | - "1"
74 | - "I"
75 | # 不对某些类做混淆(不混淆其中的所有内容)
76 | # 通常情况必须加入 main 入口
77 | classBlackList:
78 | - "com.test.Main"
79 | # 不对指定正则的类进行混淆
80 | # 注意这里的类名匹配是 java/lang/String 而不是 java.lang.String
81 | # 该配置和 classBlackList 同时生效
82 | classBlackRegexList:
83 | - "java/.*"
84 | - "com/intellij/.*"
85 | # 不对某些 method 名做混淆 正则
86 | # visit.* 忽略 JAVA ASM 的 visitCode visitMethod 等方法
87 | # start.* 忽略 JAVAFX 因为启动基于 start 方法
88 | # 以此类推某些方法和类是不能混淆的(类继承和接口实现等)
89 | methodBlackList:
90 | - "visit.*"
91 | - "start.*"
92 |
93 | # 开启类名混淆
94 | enableClassName: true
95 | # 开启包名混淆
96 | enablePackageName: true
97 | # 开启方法名混淆
98 | enableMethodName: true
99 | # 开启字段混淆
100 | enableFieldName: true
101 | # 开启参数名混淆
102 | enableParamName: true
103 | # 开启数字异或混淆
104 | enableXOR: true
105 |
106 | # 开启加密字符串
107 | enableEncryptString: true
108 | # 加密使用 AES KEY
109 | # 注意长度必须是 16 且不包含中文
110 | stringAesKey: Y4SuperSecretKey
111 | # 开启进阶字符串混淆
112 | enableAdvanceString: true
113 | # 进阶字符串处理参数
114 | advanceStringName: GIiIiLA
115 | # 字符串解密类名
116 | decryptClassName: org.apache.commons.collections.list.AbstractHashMap
117 | # 字符串解密方法名
118 | decryptMethodName: newMap
119 | # 字符串 AES KEY 名字
120 | decryptKeyName: LiLiLLLiiiLLiiLLi
121 |
122 | # 是否隐藏方法
123 | enableHideMethod: true
124 | # 是否隐藏字段
125 | enableHideField: true
126 |
127 | # 开启删除编译信息选项
128 | enableDeleteCompileInfo: true
129 |
130 | # 开启花指令混淆
131 | enableJunk: true
132 | # 花指令级别
133 | # 最低1 最高5
134 | # 使用 3 以上会生成垃圾方法
135 | junkLevel: 5
136 | # 一个类中的花指令数量上限
137 | maxJunkOneClass: 2000
138 |
139 | # 是否打印所有主函数
140 | showAllMainMethods: true
141 |
142 | # 是否保留临时类文件
143 | keepTempFile: false
144 | ```
145 |
146 | ## 配置指南
147 |
148 | 大概思路如下:
149 |
150 | - 通常情况必须把 `main` 入口加入 `classBlackList`
151 | - 通常需要配置 `classBlackRegexList` 拉黑所有的第三方库类(如 `org/apache/.*` 等)
152 | - 如果某些类集成或者实现某些库的接口,重写方法不允许重命名,注意配置 `methodBlackList`
153 | - 建议测试配置时不要开启 `enableJunk` 和 `enableHide*` 方法,一切没问题再开启这些
154 |
155 | ## 更新内容
156 |
157 | 2.0.0-RC2 版本已初步支持 `SpringBoot` 混淆
158 |
159 | 
--------------------------------------------------------------------------------
/check-version.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | mvn versions:display-dependency-updates
--------------------------------------------------------------------------------
/img/001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jar-analyzer/jar-obfuscator/9d12c8c12562cffbc73875f771397c143ac1d74e/img/001.png
--------------------------------------------------------------------------------
/package.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | setlocal
3 |
4 | set "MAVEN_OPTS=-Dorg.slf4j.simpleLogger.defaultLogLevel=warn"
5 | mvn -B clean package -DskipTests --file pom.xml
6 |
7 | endlocal
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | me.n1ar4.jar.obfuscator
8 | jar-obfuscator
9 | 2.0.0-RC2
10 |
11 | jar
12 | Jar Obfuscator Project V2
13 |
14 |
15 |
16 | 9.7.1
17 | 1.82
18 | 2.4
19 | 3.5.1
20 | 7.0.3
21 |
22 |
23 | 3.3.1
24 |
25 | 3.7.1
26 |
27 | 3.13.0
28 |
29 | 2.17.1
30 |
31 | 8
32 | 8
33 |
34 | UTF-8
35 |
36 | me.n1ar4.jar.obfuscator.Main
37 |
38 |
39 |
40 |
41 | org.ow2.asm
42 | asm
43 | ${asm.version}
44 |
45 |
46 | org.ow2.asm
47 | asm-commons
48 | ${asm.version}
49 |
50 |
51 | com.beust
52 | jcommander
53 | ${jcommander.version}
54 |
55 |
56 | org.yaml
57 | snakeyaml
58 | ${snake.yaml.version}
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | org.apache.maven.plugins
67 | maven-resources-plugin
68 | ${maven.resources.version}
69 |
70 |
71 | org.apache.maven.plugins
72 | maven-assembly-plugin
73 | ${maven.assembly.version}
74 |
75 |
76 | org.apache.maven.plugins
77 | maven-compiler-plugin
78 | ${maven.compiler.version}
79 |
80 |
81 | org.codehaus.mojo
82 | versions-maven-plugin
83 | ${maven.versions.version}
84 |
85 |
86 |
87 |
88 |
89 | org.codehaus.mojo
90 | versions-maven-plugin
91 |
92 |
93 |
94 |
95 | regex
96 | (.+-SNAPSHOT|.+-M\d)
97 |
98 |
99 | regex
100 | .+-(alpha|beta).*
101 |
102 |
103 | regex
104 | .*\.android.*
105 |
106 |
107 | regex
108 | .*\-RC.*
109 |
110 |
111 |
112 |
113 |
114 |
115 | org.apache.maven.plugins
116 | maven-resources-plugin
117 |
118 |
119 | org.apache.maven.plugins
120 | maven-assembly-plugin
121 |
122 |
123 | build
124 |
125 | false
126 | true
127 |
128 | jar-with-dependencies
129 |
130 |
131 |
132 | ${main.name}
133 |
134 |
135 | true
136 |
137 |
138 |
139 | package
140 |
141 | single
142 |
143 |
144 |
145 |
146 |
147 | org.apache.maven.plugins
148 | maven-compiler-plugin
149 |
150 | ${maven.compiler.source}
151 | ${maven.compiler.target}
152 |
153 |
154 |
155 |
156 |
--------------------------------------------------------------------------------
/release/README.md:
--------------------------------------------------------------------------------
1 | # RELEASE
2 |
3 | - run `check-version.bat`
4 | - change `pom.xml`
5 | - change `build.yml`
6 | - change `VERSION` in `Const.java`
7 | - build
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/Const.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator;
2 |
3 | import org.objectweb.asm.Opcodes;
4 |
5 | import java.nio.file.Path;
6 | import java.nio.file.Paths;
7 |
8 | public interface Const {
9 | String VERSION = "2.0.0-RC2";
10 | String PROJECT_URL = "https://github.com/jar-analyzer/jar-obfuscator";
11 | String TEMP_DIR = "jar-obfuscator-temp";
12 | Path configPath = Paths.get("config.yaml");
13 | int ASMVersion = Opcodes.ASM9;
14 | int AnalyzeASMOptions = 0;
15 | }
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/Logo.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator;
2 |
3 | import me.n1ar4.jar.obfuscator.utils.ColorUtil;
4 | import me.n1ar4.jar.obfuscator.utils.IOUtils;
5 |
6 | import java.io.InputStream;
7 |
8 | public class Logo {
9 | public static void printLogo() {
10 | System.out.println(ColorUtil.green(
11 | " ____.________ ___. _____ __ \n" +
12 | " | |\\_____ \\\\_ |___/ ____\\_ __ ______ ____ _____ _/ |_ ___________ \n" +
13 | " | | / | \\| __ \\ __\\ | \\/ ___// ___\\\\__ \\\\ __\\/ _ \\_ __ \\\n" +
14 | "/\\__| |/ | \\ \\_\\ \\ | | | /\\___ \\\\ \\___ / __ \\| | ( <_> ) | \\/\n" +
15 | "\\________|\\_______ /___ /__| |____//____ >\\___ >____ /__| \\____/|__| \n" +
16 | " \\/ \\/ \\/ \\/ \\/ "));
17 | System.out.println(ColorUtil.blue("Jar Obfuscator V2 - An Open-Source Java Bytecode Obfuscation Tool"));
18 | System.out.println(ColorUtil.yellow("Jar Obfuscator V2 - 一个开源的配置简单容易上手的 JAVA 字节码混淆工具"));
19 | System.out.println("Version: " + ColorUtil.red(Const.VERSION) +
20 | " URL: " + ColorUtil.red(Const.PROJECT_URL) + "\n");
21 |
22 | InputStream is = Logo.class.getClassLoader().getResourceAsStream("thanks.txt");
23 | if (is != null) {
24 | try {
25 | byte[] data = IOUtils.readAllBytes(is);
26 | String a = new String(data);
27 | String[] splits = a.split("\n");
28 | if (splits.length > 1) {
29 | System.out.println(ColorUtil.green("感谢以下用户对本项目的贡献:"));
30 | }
31 | for (String s : splits) {
32 | if (s.endsWith("\r")) {
33 | s = s.substring(0, s.length() - 1);
34 | }
35 | String[] temp = s.split(" ");
36 | System.out.println(" -> " + ColorUtil.blue(temp[0]) +
37 | " " + ColorUtil.yellow(temp[1]));
38 | }
39 | System.out.println();
40 | } catch (Exception ignored) {
41 | }
42 | }
43 |
44 | System.out.println(ColorUtil.green("感谢使用!有问题和建议欢迎在 GITHUB ISSUE 反馈"));
45 | System.out.println(ColorUtil.yellow("LINK: https://github.com/jar-analyzer/jar-obfuscator/issues/new"));
46 |
47 | System.out.println();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/Main.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator;
2 |
3 | import com.beust.jcommander.JCommander;
4 | import me.n1ar4.jar.obfuscator.config.BaseCmd;
5 | import me.n1ar4.jar.obfuscator.config.BaseConfig;
6 | import me.n1ar4.jar.obfuscator.config.Manager;
7 | import me.n1ar4.jar.obfuscator.config.Parser;
8 | import me.n1ar4.jar.obfuscator.core.Runner;
9 | import me.n1ar4.log.LogManager;
10 | import me.n1ar4.log.Logger;
11 |
12 | import java.nio.file.Files;
13 | import java.nio.file.Path;
14 | import java.nio.file.Paths;
15 |
16 | public class Main {
17 | private static final BaseCmd baseCmd = new BaseCmd();
18 | private static final Logger logger = LogManager.getLogger();
19 |
20 | public static void main(String[] args) {
21 | Logo.printLogo();
22 | Parser parser = new Parser();
23 | JCommander commander = JCommander.newBuilder()
24 | .addObject(baseCmd)
25 | .build();
26 | try {
27 | commander.parse(args);
28 | } catch (Exception ignored) {
29 | commander.usage();
30 | return;
31 | }
32 | if (baseCmd.isGenerate()) {
33 | parser.generateConfig();
34 | logger.info("generate config.yaml file");
35 | return;
36 | }
37 | if (baseCmd.getConfig() == null || baseCmd.getConfig().isEmpty()) {
38 | baseCmd.setConfig("config.yaml");
39 | }
40 | if (baseCmd.getPath() == null || baseCmd.getPath().isEmpty()) {
41 | logger.error("need --jar file");
42 | commander.usage();
43 | return;
44 | }
45 | BaseConfig config = parser.parse(Paths.get(baseCmd.getConfig()));
46 | if (config == null) {
47 | logger.warn("need config.yaml config");
48 | logger.info("generate config.yaml file");
49 | parser.generateConfig();
50 | return;
51 | }
52 | String p = baseCmd.getPath();
53 | Path path = Paths.get(p);
54 | if (!Files.exists(path)) {
55 | logger.error("jar file not exist");
56 | commander.usage();
57 | return;
58 | }
59 |
60 | boolean success = Manager.initConfig(config);
61 | if (!success) {
62 | return;
63 | }
64 |
65 | logger.info("start class obfuscate");
66 | Runner.run(path, config);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/analyze/DiscoveryClassVisitor.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.analyze;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.base.ClassReference;
5 | import me.n1ar4.jar.obfuscator.base.MethodReference;
6 | import org.objectweb.asm.*;
7 |
8 | import java.util.*;
9 |
10 | public class DiscoveryClassVisitor extends ClassVisitor {
11 | private String name;
12 | private String superName;
13 | private String[] interfaces;
14 | private boolean isInterface;
15 | private boolean isEnum;
16 | private List members;
17 | private ClassReference.Handle classHandle;
18 | private Set annotations;
19 | private final Set discoveredClasses;
20 | private final Set discoveredMethods;
21 | private final Map> fieldsInClassMap;
22 | private final List fieldsList = new ArrayList<>();
23 | private final String jar;
24 |
25 | public DiscoveryClassVisitor(Set discoveredClasses,
26 | Set discoveredMethods,
27 | Map> fieldsInClassMap,
28 | String jarName) {
29 | super(Const.ASMVersion);
30 | this.fieldsInClassMap = fieldsInClassMap;
31 | this.discoveredClasses = discoveredClasses;
32 | this.discoveredMethods = discoveredMethods;
33 | this.jar = jarName;
34 | }
35 |
36 | @Override
37 | public void visit(int version, int access, String name,
38 | String signature, String superName, String[] interfaces) {
39 | this.name = name;
40 | this.superName = superName;
41 | this.interfaces = interfaces;
42 | this.isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
43 | this.isEnum = (access & Opcodes.ACC_ENUM) != 0;
44 | this.members = new ArrayList<>();
45 | this.classHandle = new ClassReference.Handle(name);
46 | annotations = new HashSet<>();
47 | super.visit(version, access, name, signature, superName, interfaces);
48 | }
49 |
50 | @Override
51 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
52 | annotations.add(descriptor);
53 | return super.visitAnnotation(descriptor, visible);
54 | }
55 |
56 | public FieldVisitor visitField(int access, String name, String desc,
57 | String signature, Object value) {
58 | if ((access & Opcodes.ACC_STATIC) == 0) {
59 | Type type = Type.getType(desc);
60 | String typeName;
61 | if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
62 | typeName = type.getInternalName();
63 | } else {
64 | typeName = type.getDescriptor();
65 | }
66 | members.add(new ClassReference.Member(name, access, new ClassReference.Handle(typeName)));
67 | }
68 | fieldsList.add(name);
69 | return super.visitField(access, name, desc, signature, value);
70 | }
71 |
72 | @Override
73 | public MethodVisitor visitMethod(int access, String name, String desc,
74 | String signature, String[] exceptions) {
75 | boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
76 | Set mAnno = new HashSet<>();
77 | discoveredMethods.add(new MethodReference(
78 | classHandle,
79 | name,
80 | desc,
81 | isStatic,
82 | mAnno, access));
83 | MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
84 | return new DiscoveryMethodAdapter(Const.ASMVersion, mv, mAnno, this.name);
85 | }
86 |
87 | @Override
88 | public void visitEnd() {
89 | ClassReference classReference = new ClassReference(
90 | name,
91 | superName,
92 | Arrays.asList(interfaces),
93 | isInterface,
94 | isEnum,
95 | members,
96 | annotations,
97 | jar);
98 | discoveredClasses.add(classReference);
99 | fieldsInClassMap.put(name, fieldsList);
100 | super.visitEnd();
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/analyze/DiscoveryMethodAdapter.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.analyze;
2 |
3 | import me.n1ar4.jar.obfuscator.base.ClassReference;
4 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
5 | import org.objectweb.asm.AnnotationVisitor;
6 | import org.objectweb.asm.MethodVisitor;
7 |
8 | import java.util.ArrayList;
9 | import java.util.Set;
10 |
11 | public class DiscoveryMethodAdapter extends MethodVisitor {
12 | private final Set anno;
13 | private final String className;
14 | private final ArrayList strings = new ArrayList<>();
15 |
16 | protected DiscoveryMethodAdapter(int api, MethodVisitor methodVisitor,
17 | Set anno, String className) {
18 | super(api, methodVisitor);
19 | this.anno = anno;
20 | this.className = className;
21 | }
22 |
23 | @Override
24 | public void visitLdcInsn(Object value) {
25 | if (value instanceof String) {
26 | String valS = (String) value;
27 | strings.add(valS);
28 | }
29 | super.visitLdcInsn(value);
30 | }
31 |
32 | @Override
33 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
34 | anno.add(descriptor);
35 | return super.visitAnnotation(descriptor, visible);
36 | }
37 |
38 | @Override
39 | public AnnotationVisitor visitParameterAnnotation(int parameter, String descriptor, boolean visible) {
40 | anno.add(descriptor);
41 | return super.visitParameterAnnotation(parameter, descriptor, visible);
42 | }
43 |
44 | @Override
45 | public void visitEnd() {
46 | ClassReference.Handle key = new ClassReference.Handle(this.className);
47 | ArrayList list = ObfEnv.stringInClass.get(key);
48 | if (list == null) {
49 | ObfEnv.stringInClass.put(new ClassReference.Handle(this.className), this.strings);
50 | } else {
51 | list.addAll(this.strings);
52 | ObfEnv.stringInClass.put(new ClassReference.Handle(this.className), list);
53 | }
54 | super.visitEnd();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/analyze/MethodCallClassVisitor.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.analyze;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.base.MethodReference;
5 | import org.objectweb.asm.ClassVisitor;
6 | import org.objectweb.asm.MethodVisitor;
7 |
8 | import java.util.HashMap;
9 | import java.util.HashSet;
10 |
11 | public class MethodCallClassVisitor extends ClassVisitor {
12 | private String name;
13 |
14 | private final HashMap> methodCalls;
15 |
16 | public MethodCallClassVisitor(HashMap> methodCalls) {
18 | super(Const.ASMVersion);
19 | this.methodCalls = methodCalls;
20 | }
21 |
22 | @Override
23 | public void visit(int version, int access, String name, String signature,
24 | String superName, String[] interfaces) {
25 | super.visit(version, access, name, signature, superName, interfaces);
26 | this.name = name;
27 | }
28 |
29 | public MethodVisitor visitMethod(int access, String name, String desc,
30 | String signature, String[] exceptions) {
31 | MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
32 | return new MethodCallMethodVisitor(api, mv, this.name, name, desc, methodCalls);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/analyze/MethodCallMethodVisitor.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.analyze;
2 |
3 | import me.n1ar4.jar.obfuscator.base.ClassReference;
4 | import me.n1ar4.jar.obfuscator.base.MethodReference;
5 | import org.objectweb.asm.Handle;
6 | import org.objectweb.asm.MethodVisitor;
7 |
8 | import java.util.HashMap;
9 | import java.util.HashSet;
10 |
11 | public class MethodCallMethodVisitor extends MethodVisitor {
12 | private final HashSet calledMethods;
13 |
14 | public MethodCallMethodVisitor(final int api, final MethodVisitor mv,
15 | final String owner, String name, String desc,
16 | HashMap> methodCalls) {
18 | super(api, mv);
19 | this.calledMethods = new HashSet<>();
20 | methodCalls.put(
21 | new MethodReference.Handle(
22 | new ClassReference.Handle(owner), name, desc), calledMethods);
23 | }
24 |
25 | @Override
26 | public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
27 | calledMethods.add(
28 | new MethodReference.Handle(
29 | new ClassReference.Handle(owner), name, desc));
30 | super.visitMethodInsn(opcode, owner, name, desc, itf);
31 | }
32 |
33 | @Override
34 | public void visitInvokeDynamicInsn(String name, String descriptor,
35 | Handle bootstrapMethodHandle,
36 | Object... bootstrapMethodArguments) {
37 | for (Object bsmArg : bootstrapMethodArguments) {
38 | if (bsmArg instanceof Handle) {
39 | Handle handle = (Handle) bsmArg;
40 | calledMethods.add(new MethodReference.Handle(
41 | new ClassReference.Handle(handle.getOwner()),
42 | handle.getName(), handle.getDesc()));
43 | }
44 | }
45 | super.visitInvokeDynamicInsn(name, descriptor,
46 | bootstrapMethodHandle, bootstrapMethodArguments);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/asm/CompileInfoVisitor.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.asm;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import org.objectweb.asm.ClassVisitor;
5 | import org.objectweb.asm.Label;
6 | import org.objectweb.asm.MethodVisitor;
7 |
8 |
9 | public class CompileInfoVisitor extends ClassVisitor {
10 | public CompileInfoVisitor(ClassVisitor classVisitor) {
11 | super(Const.ASMVersion, classVisitor);
12 | }
13 |
14 | @Override
15 | public void visitSource(String source, String debug) {
16 | }
17 |
18 | @Override
19 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
20 | MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
21 | return new CompileInfoChangerMethodAdapter(mv);
22 | }
23 |
24 | static class CompileInfoChangerMethodAdapter extends MethodVisitor {
25 | CompileInfoChangerMethodAdapter(MethodVisitor mv) {
26 | super(Const.ASMVersion, mv);
27 | }
28 |
29 | @Override
30 | public void visitLineNumber(int line, Label start) {
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/asm/FieldNameVisitor.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.asm;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.base.ClassField;
5 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
6 | import org.objectweb.asm.*;
7 |
8 | public class FieldNameVisitor extends ClassVisitor {
9 | private String className;
10 |
11 | public FieldNameVisitor(ClassVisitor classVisitor) {
12 | super(Const.ASMVersion, classVisitor);
13 | }
14 |
15 | @Override
16 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
17 | this.className = name;
18 | super.visit(version, access, name, signature, superName, interfaces);
19 | }
20 |
21 | @Override
22 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
23 | MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
24 | return new FieldNameChangerMethodAdapter(mv);
25 | }
26 |
27 | @Override
28 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
29 | return super.visitAnnotation(descriptor, visible);
30 | }
31 |
32 | @Override
33 | public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
34 | return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
35 | }
36 |
37 | @Override
38 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
39 | ClassField cf = new ClassField();
40 | cf.setClassName(this.className);
41 | cf.setFieldName(name);
42 | ClassField newCF = ObfEnv.fieldNameObfMapping.getOrDefault(cf, cf);
43 | if (ObfEnv.config.isEnableHideField()) {
44 | access = access | Opcodes.ACC_SYNTHETIC;
45 | }
46 | return super.visitField(access, newCF.getFieldName(), descriptor, signature, value);
47 | }
48 |
49 | @Override
50 | public ModuleVisitor visitModule(String name, int access, String version) {
51 | return super.visitModule(name, access, version);
52 | }
53 |
54 | @Override
55 | public RecordComponentVisitor visitRecordComponent(String name, String descriptor, String signature) {
56 | return super.visitRecordComponent(name, descriptor, signature);
57 | }
58 |
59 | @Override
60 | public void visitAttribute(Attribute attribute) {
61 | super.visitAttribute(attribute);
62 | }
63 |
64 | @Override
65 | public void visitEnd() {
66 | super.visitEnd();
67 | }
68 |
69 | @Override
70 | public void visitInnerClass(String name, String outerName, String innerName, int access) {
71 | super.visitInnerClass(name, outerName, innerName, access);
72 | }
73 |
74 | @Override
75 | public void visitNestHost(String nestHost) {
76 | super.visitNestHost(nestHost);
77 | }
78 |
79 | @Override
80 | public void visitNestMember(String nestMember) {
81 | super.visitNestMember(nestMember);
82 | }
83 |
84 | @Override
85 | public void visitOuterClass(String owner, String name, String descriptor) {
86 | super.visitOuterClass(owner, name, descriptor);
87 | }
88 |
89 | @Override
90 | public void visitPermittedSubclass(String permittedSubclass) {
91 | super.visitPermittedSubclass(permittedSubclass);
92 | }
93 |
94 | @Override
95 | public void visitSource(String source, String debug) {
96 | super.visitSource(source, debug);
97 | }
98 |
99 | @Override
100 | public ClassVisitor getDelegate() {
101 | return super.getDelegate();
102 | }
103 |
104 | static class FieldNameChangerMethodAdapter extends MethodVisitor {
105 | FieldNameChangerMethodAdapter(MethodVisitor mv) {
106 | super(Const.ASMVersion, mv);
107 | }
108 |
109 | @Override
110 | public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
111 | super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
112 | }
113 |
114 | @Override
115 | public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
116 | ClassField cf = new ClassField();
117 | cf.setClassName(owner);
118 | cf.setFieldName(name);
119 | ClassField newCF = ObfEnv.fieldNameObfMapping.getOrDefault(cf, cf);
120 | super.visitFieldInsn(opcode, owner, newCF.getFieldName(), descriptor);
121 | }
122 |
123 | @Override
124 | public void visitTypeInsn(int opcode, String type) {
125 | super.visitTypeInsn(opcode, type);
126 | }
127 |
128 | @Override
129 | public void visitAttribute(Attribute attribute) {
130 | super.visitAttribute(attribute);
131 | }
132 |
133 | @Override
134 | public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
135 | return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
136 | }
137 |
138 | @Override
139 | public MethodVisitor getDelegate() {
140 | return super.getDelegate();
141 | }
142 |
143 | @Override
144 | public void visitEnd() {
145 | super.visitEnd();
146 | }
147 |
148 | @Override
149 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
150 | return super.visitAnnotation(descriptor, visible);
151 | }
152 |
153 | @Override
154 | public AnnotationVisitor visitAnnotationDefault() {
155 | return super.visitAnnotationDefault();
156 | }
157 |
158 | @Override
159 | public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
160 | return super.visitInsnAnnotation(typeRef, typePath, descriptor, visible);
161 | }
162 |
163 | @Override
164 | public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String descriptor, boolean visible) {
165 | return super.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, descriptor, visible);
166 | }
167 |
168 | @Override
169 | public AnnotationVisitor visitParameterAnnotation(int parameter, String descriptor, boolean visible) {
170 | return super.visitParameterAnnotation(parameter, descriptor, visible);
171 | }
172 |
173 | @Override
174 | public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
175 | return super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible);
176 | }
177 |
178 | @Override
179 | public void visitAnnotableParameterCount(int parameterCount, boolean visible) {
180 | super.visitAnnotableParameterCount(parameterCount, visible);
181 | }
182 |
183 | @Override
184 | public void visitCode() {
185 | super.visitCode();
186 | }
187 |
188 | @Override
189 | public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) {
190 | super.visitFrame(type, numLocal, local, numStack, stack);
191 | }
192 |
193 | @Override
194 | public void visitIincInsn(int varIndex, int increment) {
195 | super.visitIincInsn(varIndex, increment);
196 | }
197 |
198 | @Override
199 | public void visitInsn(int opcode) {
200 | super.visitInsn(opcode);
201 | }
202 |
203 | @Override
204 | public void visitIntInsn(int opcode, int operand) {
205 | super.visitIntInsn(opcode, operand);
206 | }
207 |
208 | @Override
209 | public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) {
210 | super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
211 | }
212 |
213 | @Override
214 | public void visitJumpInsn(int opcode, Label label) {
215 | super.visitJumpInsn(opcode, label);
216 | }
217 |
218 | @Override
219 | public void visitLabel(Label label) {
220 | super.visitLabel(label);
221 | }
222 |
223 | @Override
224 | public void visitLdcInsn(Object value) {
225 | super.visitLdcInsn(value);
226 | }
227 |
228 | @Override
229 | public void visitLineNumber(int line, Label start) {
230 | super.visitLineNumber(line, start);
231 | }
232 |
233 | @Override
234 | public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
235 | super.visitLocalVariable(name, descriptor, signature, start, end, index);
236 | }
237 |
238 | @Override
239 | public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
240 | super.visitLookupSwitchInsn(dflt, keys, labels);
241 | }
242 |
243 | @Override
244 | public void visitMaxs(int maxStack, int maxLocals) {
245 | super.visitMaxs(maxStack, maxLocals);
246 | }
247 |
248 | @Override
249 | public void visitMultiANewArrayInsn(String descriptor, int numDimensions) {
250 | super.visitMultiANewArrayInsn(descriptor, numDimensions);
251 | }
252 |
253 | @Override
254 | public void visitParameter(String name, int access) {
255 | super.visitParameter(name, access);
256 | }
257 |
258 | @Override
259 | public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
260 | super.visitTableSwitchInsn(min, max, dflt, labels);
261 | }
262 |
263 | @Override
264 | public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
265 | super.visitTryCatchBlock(start, end, handler, type);
266 | }
267 |
268 | @Override
269 | public void visitVarInsn(int opcode, int varIndex) {
270 | super.visitVarInsn(opcode, varIndex);
271 | }
272 | }
273 | }
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/asm/IntToXorVisitor.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.asm;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jrandom.core.JRandom;
5 | import org.objectweb.asm.ClassVisitor;
6 | import org.objectweb.asm.MethodVisitor;
7 | import org.objectweb.asm.Opcodes;
8 |
9 | public class IntToXorVisitor extends ClassVisitor {
10 | public IntToXorVisitor(ClassVisitor cv) {
11 | super(Opcodes.ASM9, cv);
12 | }
13 |
14 | @Override
15 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
16 | MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions);
17 | return new XORMethodAdapter(mv);
18 | }
19 |
20 | private static class XORMethodAdapter extends MethodVisitor {
21 | XORMethodAdapter(MethodVisitor mv) {
22 | super(Const.ASMVersion, mv);
23 | }
24 |
25 | @Override
26 | public void visitInsn(int opcode) {
27 | if (opcode >= Opcodes.ICONST_M1 && opcode <= Opcodes.ICONST_5) {
28 | int value = opcode - Opcodes.ICONST_0;
29 | replaceIntWithXor(value);
30 | } else {
31 | super.visitInsn(opcode);
32 | }
33 | }
34 |
35 | @Override
36 | public void visitIntInsn(int opcode, int operand) {
37 | if (opcode == Opcodes.BIPUSH || opcode == Opcodes.SIPUSH) {
38 | replaceIntWithXor(operand);
39 | } else {
40 | super.visitIntInsn(opcode, operand);
41 | }
42 | }
43 |
44 | @Override
45 | public void visitLdcInsn(Object cst) {
46 | if (cst instanceof Integer) {
47 | replaceIntWithXor((Integer) cst);
48 | } else {
49 | super.visitLdcInsn(cst);
50 | }
51 | }
52 |
53 | private void replaceIntWithXor(int value) {
54 | JRandom rand = JRandom.getInstance();
55 | int partA = 10000000 + rand.getInt(0, 90000000);
56 | int partB = partA ^ value;
57 | super.visitLdcInsn(partA);
58 | super.visitLdcInsn(partB);
59 | super.visitInsn(Opcodes.IXOR);
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/asm/MainMethodVisitor.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.asm;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import org.objectweb.asm.ClassVisitor;
5 | import org.objectweb.asm.MethodVisitor;
6 |
7 | public class MainMethodVisitor extends ClassVisitor {
8 | private boolean hasMainMethod = false;
9 |
10 | public MainMethodVisitor() {
11 | super(Const.ASMVersion);
12 | }
13 |
14 | @Override
15 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
16 | if ("main".equals(name) && descriptor.equals("([Ljava/lang/String;)V") && access == 9) {
17 | hasMainMethod = true;
18 | }
19 | return super.visitMethod(access, name, descriptor, signature, exceptions);
20 | }
21 |
22 | public boolean hasMainMethod() {
23 | return hasMainMethod;
24 | }
25 | }
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/asm/MethodNameVisitor.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.asm;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.base.ClassReference;
5 | import me.n1ar4.jar.obfuscator.base.MethodReference;
6 | import me.n1ar4.jar.obfuscator.core.AnalyzeEnv;
7 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
8 | import org.objectweb.asm.*;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | @SuppressWarnings("all")
15 | public class MethodNameVisitor extends ClassVisitor {
16 | private String owner;
17 | private final List ignoreMethods = new ArrayList<>();
18 | private final List ignoreMethodString = new ArrayList<>();
19 |
20 | public MethodNameVisitor(ClassVisitor classVisitor) {
21 | super(Const.ASMVersion, classVisitor);
22 | }
23 |
24 | @Override
25 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
26 | this.owner = name;
27 | // 查接口 不改接口方法
28 | for (String in : interfaces) {
29 | List mList = AnalyzeEnv.methodsInClassMap.get(new ClassReference.Handle(in));
30 | if (mList == null) {
31 | continue;
32 | }
33 | ignoreMethods.addAll(mList);
34 | }
35 |
36 | // 检查内置黑名单
37 | String key = null;
38 | for (Map.Entry entry : ObfEnv.classNameObfMapping.entrySet()) {
39 | if (entry.getValue().equals(name)) {
40 | key = entry.getKey();
41 | break;
42 | }
43 | }
44 | if (key != null) {
45 | List methodNames = ObfEnv.ignoredClassMethodsMapping.get(key);
46 | if (methodNames != null) {
47 | ignoreMethodString.addAll(methodNames);
48 | }
49 | }
50 | super.visit(version, access, name, signature, superName, interfaces);
51 | }
52 |
53 | @Override
54 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
55 | MethodVisitor mv;
56 |
57 | for (MethodReference mr : ignoreMethods) {
58 | if (mr.getName().equals(name) && mr.getDesc().equals(desc)) {
59 | return super.visitMethod(access, name, desc, signature, exceptions);
60 | }
61 | }
62 |
63 | for (String method : this.ignoreMethodString) {
64 | if (method.equals(name)) {
65 | return super.visitMethod(access, name, desc, signature, exceptions);
66 | }
67 | }
68 |
69 | if ("main".equals(name) && desc.equals("([Ljava/lang/String;)V") && access == 9) {
70 | mv = super.visitMethod(access, name, desc, signature, exceptions);
71 | } else if (name.equals("") || name.equals("")) {
72 | mv = super.visitMethod(access, name, desc, signature, exceptions);
73 | } else {
74 | MethodReference.Handle m = ObfEnv.methodNameObfMapping.get(new MethodReference.Handle(
75 | new ClassReference.Handle(owner),
76 | name,
77 | desc
78 | ));
79 | if (ObfEnv.config.isEnableHideMethod()) {
80 | access = access | Opcodes.ACC_SYNTHETIC;
81 | }
82 | if (m == null) {
83 | mv = super.visitMethod(access, name, desc, signature, exceptions);
84 | return new MethodNameChangerMethodAdapter(mv);
85 | } else {
86 | mv = super.visitMethod(access, m.getName(), m.getDesc(), signature, exceptions);
87 | return new MethodNameChangerMethodAdapter(mv);
88 | }
89 | }
90 | return new MethodNameChangerMethodAdapter(mv);
91 | }
92 |
93 | @Override
94 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
95 | return super.visitAnnotation(descriptor, visible);
96 | }
97 |
98 | @Override
99 | public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
100 | return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
101 | }
102 |
103 | @Override
104 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
105 | return super.visitField(access, name, descriptor, signature, value);
106 | }
107 |
108 | @Override
109 | public ModuleVisitor visitModule(String name, int access, String version) {
110 | return super.visitModule(name, access, version);
111 | }
112 |
113 | @Override
114 | public RecordComponentVisitor visitRecordComponent(String name, String descriptor, String signature) {
115 | return super.visitRecordComponent(name, descriptor, signature);
116 | }
117 |
118 | @Override
119 | public void visitAttribute(Attribute attribute) {
120 | super.visitAttribute(attribute);
121 | }
122 |
123 | @Override
124 | public void visitEnd() {
125 | super.visitEnd();
126 | }
127 |
128 | @Override
129 | public void visitInnerClass(String name, String outerName, String innerName, int access) {
130 | super.visitInnerClass(name, outerName, innerName, access);
131 | }
132 |
133 | @Override
134 | public void visitNestHost(String nestHost) {
135 | super.visitNestHost(nestHost);
136 | }
137 |
138 | @Override
139 | public void visitNestMember(String nestMember) {
140 | super.visitNestMember(nestMember);
141 | }
142 |
143 | @Override
144 | public void visitOuterClass(String owner, String name, String descriptor) {
145 | super.visitOuterClass(owner, name, descriptor);
146 | }
147 |
148 | @Override
149 | public void visitPermittedSubclass(String permittedSubclass) {
150 | super.visitPermittedSubclass(permittedSubclass);
151 | }
152 |
153 | @Override
154 | public void visitSource(String source, String debug) {
155 | super.visitSource(source, debug);
156 | }
157 |
158 | @Override
159 | public ClassVisitor getDelegate() {
160 | return super.getDelegate();
161 | }
162 |
163 | static class MethodNameChangerMethodAdapter extends MethodVisitor {
164 | MethodNameChangerMethodAdapter(MethodVisitor mv) {
165 | super(Const.ASMVersion, mv);
166 | }
167 |
168 | @Override
169 | public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
170 | MethodReference.Handle m = ObfEnv.methodNameObfMapping.get(new MethodReference.Handle(
171 | new ClassReference.Handle(owner),
172 | name,
173 | descriptor
174 | ));
175 | if (m != null) {
176 | super.visitMethodInsn(opcode, m.getClassReference().getName(), m.getName(), m.getDesc(), isInterface);
177 | return;
178 | }
179 | super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
180 | }
181 |
182 | @Override
183 | public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
184 | super.visitFieldInsn(opcode, owner, name, descriptor);
185 | }
186 |
187 | @Override
188 | public void visitTypeInsn(int opcode, String type) {
189 | super.visitTypeInsn(opcode, type);
190 | }
191 |
192 | @Override
193 | public void visitAttribute(Attribute attribute) {
194 | super.visitAttribute(attribute);
195 | }
196 |
197 | @Override
198 | public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
199 | return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
200 | }
201 |
202 | @Override
203 | public MethodVisitor getDelegate() {
204 | return super.getDelegate();
205 | }
206 |
207 | @Override
208 | public void visitEnd() {
209 | super.visitEnd();
210 | }
211 |
212 | @Override
213 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
214 | return super.visitAnnotation(descriptor, visible);
215 | }
216 |
217 | @Override
218 | public AnnotationVisitor visitAnnotationDefault() {
219 | return super.visitAnnotationDefault();
220 | }
221 |
222 | @Override
223 | public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
224 | return super.visitInsnAnnotation(typeRef, typePath, descriptor, visible);
225 | }
226 |
227 | @Override
228 | public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String descriptor, boolean visible) {
229 | return super.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, descriptor, visible);
230 | }
231 |
232 | @Override
233 | public AnnotationVisitor visitParameterAnnotation(int parameter, String descriptor, boolean visible) {
234 | return super.visitParameterAnnotation(parameter, descriptor, visible);
235 | }
236 |
237 | @Override
238 | public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
239 | return super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible);
240 | }
241 |
242 | @Override
243 | public void visitAnnotableParameterCount(int parameterCount, boolean visible) {
244 | super.visitAnnotableParameterCount(parameterCount, visible);
245 | }
246 |
247 | @Override
248 | public void visitCode() {
249 | super.visitCode();
250 | }
251 |
252 | @Override
253 | public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) {
254 | super.visitFrame(type, numLocal, local, numStack, stack);
255 | }
256 |
257 | @Override
258 | public void visitIincInsn(int varIndex, int increment) {
259 | super.visitIincInsn(varIndex, increment);
260 | }
261 |
262 | @Override
263 | public void visitInsn(int opcode) {
264 | super.visitInsn(opcode);
265 | }
266 |
267 | @Override
268 | public void visitIntInsn(int opcode, int operand) {
269 | super.visitIntInsn(opcode, operand);
270 | }
271 |
272 | @Override
273 | public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) {
274 | MethodReference.Handle m = ObfEnv.methodNameObfMapping.get(new MethodReference.Handle(
275 | new ClassReference.Handle(bootstrapMethodHandle.getOwner()),
276 | bootstrapMethodHandle.getName(),
277 | bootstrapMethodHandle.getDesc()
278 | ));
279 | Handle handle;
280 | if (m != null) {
281 | handle = new Handle(
282 | bootstrapMethodHandle.getTag(),
283 | m.getClassReference().getName(),
284 | m.getName(),
285 | m.getDesc(),
286 | bootstrapMethodHandle.isInterface());
287 | } else {
288 | handle = bootstrapMethodHandle;
289 | }
290 |
291 | for (int i = 0; i < bootstrapMethodArguments.length; i++) {
292 | Object obj = bootstrapMethodArguments[i];
293 | if (obj instanceof Handle) {
294 | Handle ho = (Handle) obj;
295 | MethodReference.Handle mo = ObfEnv.methodNameObfMapping.get(new MethodReference.Handle(
296 | new ClassReference.Handle(ho.getOwner()),
297 | ho.getName(),
298 | ho.getDesc()
299 | ));
300 | Handle tempHandle;
301 | if (mo != null) {
302 | tempHandle = new Handle(
303 | ho.getTag(),
304 | mo.getClassReference().getName(),
305 | mo.getName(),
306 | mo.getDesc(),
307 | ho.isInterface());
308 | } else {
309 | tempHandle = ho;
310 | }
311 | bootstrapMethodArguments[i] = tempHandle;
312 | }
313 | }
314 | super.visitInvokeDynamicInsn(name, descriptor, handle, bootstrapMethodArguments);
315 | }
316 |
317 | @Override
318 | public void visitJumpInsn(int opcode, Label label) {
319 | super.visitJumpInsn(opcode, label);
320 | }
321 |
322 | @Override
323 | public void visitLabel(Label label) {
324 | super.visitLabel(label);
325 | }
326 |
327 | @Override
328 | public void visitLdcInsn(Object value) {
329 | super.visitLdcInsn(value);
330 | }
331 |
332 | @Override
333 | public void visitLineNumber(int line, Label start) {
334 | super.visitLineNumber(line, start);
335 | }
336 |
337 | @Override
338 | public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
339 | super.visitLocalVariable(name, descriptor, signature, start, end, index);
340 | }
341 |
342 | @Override
343 | public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
344 | super.visitLookupSwitchInsn(dflt, keys, labels);
345 | }
346 |
347 | @Override
348 | public void visitMaxs(int maxStack, int maxLocals) {
349 | super.visitMaxs(maxStack, maxLocals);
350 | }
351 |
352 | @Override
353 | public void visitMultiANewArrayInsn(String descriptor, int numDimensions) {
354 | super.visitMultiANewArrayInsn(descriptor, numDimensions);
355 | }
356 |
357 | @Override
358 | public void visitParameter(String name, int access) {
359 | super.visitParameter(name, access);
360 | }
361 |
362 | @Override
363 | public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
364 | super.visitTableSwitchInsn(min, max, dflt, labels);
365 | }
366 |
367 | @Override
368 | public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
369 | super.visitTryCatchBlock(start, end, handler, type);
370 | }
371 |
372 | @Override
373 | public void visitVarInsn(int opcode, int varIndex) {
374 | super.visitVarInsn(opcode, varIndex);
375 | }
376 | }
377 | }
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/asm/ParameterVisitor.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.asm;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.utils.NameUtil;
5 | import org.objectweb.asm.*;
6 |
7 | import java.util.HashSet;
8 |
9 | public class ParameterVisitor extends ClassVisitor {
10 | public ParameterVisitor(ClassVisitor classVisitor) {
11 | super(Const.ASMVersion, classVisitor);
12 | }
13 |
14 | @Override
15 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
16 | super.visit(version, access, name, signature, superName, interfaces);
17 | }
18 |
19 | @Override
20 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
21 | MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
22 | return new ParameterChangerMethodAdapter(mv);
23 | }
24 |
25 | @Override
26 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
27 | return super.visitAnnotation(descriptor, visible);
28 | }
29 |
30 | @Override
31 | public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
32 | return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
33 | }
34 |
35 | @Override
36 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
37 | return super.visitField(access, name, descriptor, signature, value);
38 | }
39 |
40 | @Override
41 | public ModuleVisitor visitModule(String name, int access, String version) {
42 | return super.visitModule(name, access, version);
43 | }
44 |
45 | @Override
46 | public RecordComponentVisitor visitRecordComponent(String name, String descriptor, String signature) {
47 | return super.visitRecordComponent(name, descriptor, signature);
48 | }
49 |
50 | @Override
51 | public void visitAttribute(Attribute attribute) {
52 | super.visitAttribute(attribute);
53 | }
54 |
55 | @Override
56 | public void visitEnd() {
57 | super.visitEnd();
58 | }
59 |
60 | @Override
61 | public void visitInnerClass(String name, String outerName, String innerName, int access) {
62 | super.visitInnerClass(name, outerName, innerName, access);
63 | }
64 |
65 | @Override
66 | public void visitNestHost(String nestHost) {
67 | super.visitNestHost(nestHost);
68 | }
69 |
70 | @Override
71 | public void visitNestMember(String nestMember) {
72 | super.visitNestMember(nestMember);
73 | }
74 |
75 | @Override
76 | public void visitOuterClass(String owner, String name, String descriptor) {
77 | super.visitOuterClass(owner, name, descriptor);
78 | }
79 |
80 | @Override
81 | public void visitPermittedSubclass(String permittedSubclass) {
82 | super.visitPermittedSubclass(permittedSubclass);
83 | }
84 |
85 | @Override
86 | public void visitSource(String source, String debug) {
87 | super.visitSource(source, debug);
88 | }
89 |
90 | @Override
91 | public ClassVisitor getDelegate() {
92 | return super.getDelegate();
93 | }
94 |
95 | static class ParameterChangerMethodAdapter extends MethodVisitor {
96 | private final HashSet obfNames = new HashSet<>();
97 |
98 | ParameterChangerMethodAdapter(MethodVisitor mv) {
99 | super(Const.ASMVersion, mv);
100 | }
101 |
102 | @Override
103 | public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
104 | super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
105 | }
106 |
107 | @Override
108 | public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
109 | super.visitFieldInsn(opcode, owner, name, descriptor);
110 | }
111 |
112 | @Override
113 | public void visitTypeInsn(int opcode, String type) {
114 | super.visitTypeInsn(opcode, type);
115 | }
116 |
117 | @Override
118 | public void visitAttribute(Attribute attribute) {
119 | super.visitAttribute(attribute);
120 | }
121 |
122 | @Override
123 | public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
124 | return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
125 | }
126 |
127 | @Override
128 | public MethodVisitor getDelegate() {
129 | return super.getDelegate();
130 | }
131 |
132 | @Override
133 | public void visitEnd() {
134 | super.visitEnd();
135 | }
136 |
137 | @Override
138 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
139 | return super.visitAnnotation(descriptor, visible);
140 | }
141 |
142 | @Override
143 | public AnnotationVisitor visitAnnotationDefault() {
144 | return super.visitAnnotationDefault();
145 | }
146 |
147 | @Override
148 | public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
149 | return super.visitInsnAnnotation(typeRef, typePath, descriptor, visible);
150 | }
151 |
152 | @Override
153 | public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String descriptor, boolean visible) {
154 | return super.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, descriptor, visible);
155 | }
156 |
157 | @Override
158 | public AnnotationVisitor visitParameterAnnotation(int parameter, String descriptor, boolean visible) {
159 | return super.visitParameterAnnotation(parameter, descriptor, visible);
160 | }
161 |
162 | @Override
163 | public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
164 | return super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible);
165 | }
166 |
167 | @Override
168 | public void visitAnnotableParameterCount(int parameterCount, boolean visible) {
169 | super.visitAnnotableParameterCount(parameterCount, visible);
170 | }
171 |
172 | @Override
173 | public void visitCode() {
174 | super.visitCode();
175 | }
176 |
177 | @Override
178 | public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) {
179 | super.visitFrame(type, numLocal, local, numStack, stack);
180 | }
181 |
182 | @Override
183 | public void visitIincInsn(int varIndex, int increment) {
184 | super.visitIincInsn(varIndex, increment);
185 | }
186 |
187 | @Override
188 | public void visitInsn(int opcode) {
189 | super.visitInsn(opcode);
190 | }
191 |
192 | @Override
193 | public void visitIntInsn(int opcode, int operand) {
194 | super.visitIntInsn(opcode, operand);
195 | }
196 |
197 | @Override
198 | public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) {
199 | super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
200 | }
201 |
202 | @Override
203 | public void visitJumpInsn(int opcode, Label label) {
204 | super.visitJumpInsn(opcode, label);
205 | }
206 |
207 | @Override
208 | public void visitLabel(Label label) {
209 | super.visitLabel(label);
210 | }
211 |
212 | @Override
213 | public void visitLdcInsn(Object value) {
214 | super.visitLdcInsn(value);
215 | }
216 |
217 | @Override
218 | public void visitLineNumber(int line, Label start) {
219 | super.visitLineNumber(line, start);
220 | }
221 |
222 | @Override
223 | public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
224 | if (name.equals("this") || name.equals("super")) {
225 | super.visitLocalVariable(name, descriptor, signature, start, end, index);
226 | return;
227 | }
228 | name = NameUtil.genWithSet(obfNames);
229 | super.visitLocalVariable(name, descriptor, signature, start, end, index);
230 | }
231 |
232 | @Override
233 | public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
234 | super.visitLookupSwitchInsn(dflt, keys, labels);
235 | }
236 |
237 | @Override
238 | public void visitMaxs(int maxStack, int maxLocals) {
239 | super.visitMaxs(maxStack, maxLocals);
240 | }
241 |
242 | @Override
243 | public void visitMultiANewArrayInsn(String descriptor, int numDimensions) {
244 | super.visitMultiANewArrayInsn(descriptor, numDimensions);
245 | }
246 |
247 | @Override
248 | public void visitParameter(String name, int access) {
249 | super.visitParameter(name, access);
250 | }
251 |
252 | @Override
253 | public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
254 | super.visitTableSwitchInsn(min, max, dflt, labels);
255 | }
256 |
257 | @Override
258 | public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
259 | super.visitTryCatchBlock(start, end, handler, type);
260 | }
261 |
262 | @Override
263 | public void visitVarInsn(int opcode, int varIndex) {
264 | super.visitVarInsn(opcode, varIndex);
265 | }
266 | }
267 | }
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/asm/StringArrayVisitor.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.asm;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
5 | import me.n1ar4.jar.obfuscator.transform.StringArrayTransformer;
6 | import org.objectweb.asm.*;
7 | import org.objectweb.asm.commons.GeneratorAdapter;
8 | import org.objectweb.asm.commons.Method;
9 |
10 | import java.util.ArrayList;
11 |
12 | @SuppressWarnings("all")
13 | public class StringArrayVisitor extends ClassVisitor {
14 | private String className;
15 | private boolean isClinitPresent = false;
16 | private boolean isInterface;
17 |
18 | public StringArrayVisitor(ClassVisitor classVisitor) {
19 | super(Const.ASMVersion, classVisitor);
20 | }
21 |
22 | @Override
23 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
24 | super.visit(version, access, name, signature, superName, interfaces);
25 | this.className = name;
26 | isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
27 | super.visit(version, access, name, signature, superName, interfaces);
28 | }
29 |
30 | @Override
31 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
32 | MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
33 | if (isInterface) {
34 | return mv;
35 | }
36 | if ("".equals(name)) {
37 | isClinitPresent = true;
38 | String fieldDesc = "Ljava/util/ArrayList;";
39 | GeneratorAdapter ga = new GeneratorAdapter(mv, access, name, desc);
40 | ga.visitCode();
41 | ga.newInstance(Type.getType("Ljava/util/ArrayList;"));
42 | ga.dup();
43 | ga.invokeConstructor(Type.getType("Ljava/util/ArrayList;"), new Method("", "()V"));
44 | ga.putStatic(Type.getObjectType(className), ObfEnv.ADVANCE_STRING_NAME, Type.getType("Ljava/util/ArrayList;"));
45 | ArrayList list = ObfEnv.newStringInClass.get(className);
46 | if (list != null && !list.isEmpty()) {
47 | for (String s : list) {
48 | ga.getStatic(Type.getObjectType(className), ObfEnv.ADVANCE_STRING_NAME, Type.getType(fieldDesc));
49 | ga.push(s);
50 | ga.invokeVirtual(Type.getType("Ljava/util/ArrayList;"),
51 | new Method("add", "(Ljava/lang/Object;)Z"));
52 | ga.pop();
53 | }
54 | }
55 | // DO NOT RETURN
56 | ga.endMethod();
57 | return new StringArrayMethodAdapter(ga, className);
58 | }
59 | return new StringArrayMethodAdapter(mv, className);
60 | }
61 |
62 | @Override
63 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
64 | return super.visitAnnotation(descriptor, visible);
65 | }
66 |
67 | @Override
68 | public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
69 | return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
70 | }
71 |
72 | @Override
73 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
74 | return super.visitField(access, name, descriptor, signature, value);
75 | }
76 |
77 | @Override
78 | public ModuleVisitor visitModule(String name, int access, String version) {
79 | return super.visitModule(name, access, version);
80 | }
81 |
82 | @Override
83 | public RecordComponentVisitor visitRecordComponent(String name, String descriptor, String signature) {
84 | return super.visitRecordComponent(name, descriptor, signature);
85 | }
86 |
87 | @Override
88 | public void visitAttribute(Attribute attribute) {
89 | super.visitAttribute(attribute);
90 | }
91 |
92 | @Override
93 | public void visitEnd() {
94 | if (isInterface) {
95 | super.visitEnd();
96 | return;
97 | }
98 | String fieldDesc = "Ljava/util/ArrayList;";
99 | FieldVisitor fv = super.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC,
100 | ObfEnv.ADVANCE_STRING_NAME, fieldDesc, "Ljava/util/ArrayList;", null);
101 | if (fv != null) {
102 | fv.visitEnd();
103 | }
104 | if (!isClinitPresent) {
105 | MethodVisitor mv = super.visitMethod(Opcodes.ACC_STATIC, "", "()V", null, null);
106 | GeneratorAdapter ga = new GeneratorAdapter(mv, Opcodes.ACC_STATIC, "", "()V");
107 | ga.visitCode();
108 |
109 | ga.newInstance(Type.getType("Ljava/util/ArrayList;"));
110 | ga.dup();
111 | ga.invokeConstructor(Type.getType("Ljava/util/ArrayList;"), new Method("", "()V"));
112 | ga.putStatic(Type.getObjectType(className), ObfEnv.ADVANCE_STRING_NAME, Type.getType("Ljava/util/ArrayList;"));
113 |
114 | ArrayList list = ObfEnv.newStringInClass.get(className);
115 | if (list != null && !list.isEmpty()) {
116 | for (String s : list) {
117 | ga.getStatic(Type.getObjectType(className), ObfEnv.ADVANCE_STRING_NAME, Type.getType(fieldDesc));
118 | ga.push(s);
119 | ga.invokeVirtual(Type.getType("Ljava/util/ArrayList;"),
120 | new Method("add", "(Ljava/lang/Object;)Z"));
121 | ga.pop();
122 | }
123 | }
124 | ga.returnValue();
125 | ga.endMethod();
126 | }
127 | super.visitEnd();
128 | }
129 |
130 | @Override
131 | public void visitInnerClass(String name, String outerName, String innerName, int access) {
132 | super.visitInnerClass(name, outerName, innerName, access);
133 | }
134 |
135 | @Override
136 | public void visitNestHost(String nestHost) {
137 | super.visitNestHost(nestHost);
138 | }
139 |
140 | @Override
141 | public void visitNestMember(String nestMember) {
142 | super.visitNestMember(nestMember);
143 | }
144 |
145 | @Override
146 | public void visitOuterClass(String owner, String name, String descriptor) {
147 | super.visitOuterClass(owner, name, descriptor);
148 | }
149 |
150 | @Override
151 | public void visitPermittedSubclass(String permittedSubclass) {
152 | super.visitPermittedSubclass(permittedSubclass);
153 | }
154 |
155 | @Override
156 | public void visitSource(String source, String debug) {
157 | super.visitSource(source, debug);
158 | }
159 |
160 | @Override
161 | public ClassVisitor getDelegate() {
162 | return super.getDelegate();
163 | }
164 |
165 | static class StringArrayMethodAdapter extends MethodVisitor {
166 | private final String className;
167 |
168 | StringArrayMethodAdapter(MethodVisitor mv, String name) {
169 | super(Const.ASMVersion, mv);
170 | this.className = name;
171 | }
172 |
173 | @Override
174 | public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
175 | super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
176 | }
177 |
178 | @Override
179 | public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
180 | super.visitFieldInsn(opcode, owner, name, descriptor);
181 | }
182 |
183 | @Override
184 | public void visitTypeInsn(int opcode, String type) {
185 | super.visitTypeInsn(opcode, type);
186 | }
187 |
188 | @Override
189 | public void visitAttribute(Attribute attribute) {
190 | super.visitAttribute(attribute);
191 | }
192 |
193 | @Override
194 | public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
195 | return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
196 | }
197 |
198 | @Override
199 | public MethodVisitor getDelegate() {
200 | return super.getDelegate();
201 | }
202 |
203 | @Override
204 | public void visitEnd() {
205 | super.visitEnd();
206 | }
207 |
208 | @Override
209 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
210 | return super.visitAnnotation(descriptor, visible);
211 | }
212 |
213 | @Override
214 | public AnnotationVisitor visitAnnotationDefault() {
215 | return super.visitAnnotationDefault();
216 | }
217 |
218 | @Override
219 | public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
220 | return super.visitInsnAnnotation(typeRef, typePath, descriptor, visible);
221 | }
222 |
223 | @Override
224 | public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String descriptor, boolean visible) {
225 | return super.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, descriptor, visible);
226 | }
227 |
228 | @Override
229 | public AnnotationVisitor visitParameterAnnotation(int parameter, String descriptor, boolean visible) {
230 | return super.visitParameterAnnotation(parameter, descriptor, visible);
231 | }
232 |
233 | @Override
234 | public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
235 | return super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible);
236 | }
237 |
238 | @Override
239 | public void visitAnnotableParameterCount(int parameterCount, boolean visible) {
240 | super.visitAnnotableParameterCount(parameterCount, visible);
241 | }
242 |
243 | @Override
244 | public void visitCode() {
245 | super.visitCode();
246 | }
247 |
248 | @Override
249 | public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) {
250 | super.visitFrame(type, numLocal, local, numStack, stack);
251 | }
252 |
253 | @Override
254 | public void visitIincInsn(int varIndex, int increment) {
255 | super.visitIincInsn(varIndex, increment);
256 | }
257 |
258 | @Override
259 | public void visitInsn(int opcode) {
260 | super.visitInsn(opcode);
261 | }
262 |
263 | @Override
264 | public void visitIntInsn(int opcode, int operand) {
265 | super.visitIntInsn(opcode, operand);
266 | }
267 |
268 | @Override
269 | public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) {
270 | super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
271 | }
272 |
273 | @Override
274 | public void visitJumpInsn(int opcode, Label label) {
275 | super.visitJumpInsn(opcode, label);
276 | }
277 |
278 | @Override
279 | public void visitLabel(Label label) {
280 | super.visitLabel(label);
281 | }
282 |
283 | @Override
284 | public void visitLdcInsn(Object value) {
285 | if (value instanceof String) {
286 | visitFieldInsn(Opcodes.GETSTATIC, className, ObfEnv.ADVANCE_STRING_NAME,
287 | "Ljava/util/ArrayList;");
288 | visitIntInsn(Opcodes.SIPUSH, StringArrayTransformer.INDEX);
289 | StringArrayTransformer.INDEX++;
290 | visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/ArrayList", "get",
291 | "(I)Ljava/lang/Object;", false);
292 | visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
293 | } else {
294 | super.visitLdcInsn(value);
295 | }
296 | }
297 |
298 | @Override
299 | public void visitLineNumber(int line, Label start) {
300 | super.visitLineNumber(line, start);
301 | }
302 |
303 | @Override
304 | public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
305 | super.visitLocalVariable(name, descriptor, signature, start, end, index);
306 | }
307 |
308 | @Override
309 | public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
310 | super.visitLookupSwitchInsn(dflt, keys, labels);
311 | }
312 |
313 | @Override
314 | public void visitMaxs(int maxStack, int maxLocals) {
315 | super.visitMaxs(maxStack, maxLocals);
316 | }
317 |
318 | @Override
319 | public void visitMultiANewArrayInsn(String descriptor, int numDimensions) {
320 | super.visitMultiANewArrayInsn(descriptor, numDimensions);
321 | }
322 |
323 | @Override
324 | public void visitParameter(String name, int access) {
325 | super.visitParameter(name, access);
326 | }
327 |
328 | @Override
329 | public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
330 | super.visitTableSwitchInsn(min, max, dflt, labels);
331 | }
332 |
333 | @Override
334 | public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
335 | super.visitTryCatchBlock(start, end, handler, type);
336 | }
337 |
338 | @Override
339 | public void visitVarInsn(int opcode, int varIndex) {
340 | super.visitVarInsn(opcode, varIndex);
341 | }
342 | }
343 | }
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/asm/StringVisitor.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.asm;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.templates.StringDecrypt;
5 | import me.n1ar4.jar.obfuscator.templates.StringDecryptDump;
6 | import org.objectweb.asm.*;
7 | import org.objectweb.asm.commons.GeneratorAdapter;
8 | import org.objectweb.asm.commons.Method;
9 |
10 | import java.util.HashMap;
11 | import java.util.Map;
12 |
13 |
14 | public class StringVisitor extends ClassVisitor {
15 | private final Map fieldValues = new HashMap<>();
16 | private String className;
17 | private boolean isInterface = false;
18 | private boolean noClinit = true;
19 |
20 | public StringVisitor(ClassVisitor classVisitor) {
21 | super(Const.ASMVersion, classVisitor);
22 | }
23 |
24 | @Override
25 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
26 | super.visit(version, access, name, signature, superName, interfaces);
27 | this.className = name;
28 | isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
29 | }
30 |
31 | @Override
32 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
33 | if (name.equals("")) {
34 | noClinit = false;
35 | }
36 | MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
37 | return new StringChangerMethodAdapter(mv);
38 | }
39 |
40 | @Override
41 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
42 | return super.visitAnnotation(descriptor, visible);
43 | }
44 |
45 | @Override
46 | public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
47 | return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
48 | }
49 |
50 | @Override
51 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
52 | if (value instanceof String) {
53 | fieldValues.put(name, (String) value);
54 | }
55 | return super.visitField(access, name, descriptor, signature, null);
56 | }
57 |
58 | @Override
59 | public ModuleVisitor visitModule(String name, int access, String version) {
60 | return super.visitModule(name, access, version);
61 | }
62 |
63 | @Override
64 | public RecordComponentVisitor visitRecordComponent(String name, String descriptor, String signature) {
65 | return super.visitRecordComponent(name, descriptor, signature);
66 | }
67 |
68 | @Override
69 | public void visitAttribute(Attribute attribute) {
70 | super.visitAttribute(attribute);
71 | }
72 |
73 | @Override
74 | public void visitEnd() {
75 | if (isInterface && noClinit) {
76 | generateClinit();
77 | }
78 | super.visitEnd();
79 | }
80 |
81 | private void generateClinit() {
82 | MethodVisitor mv = cv.visitMethod(Opcodes.ACC_STATIC, "", "()V", null, null);
83 | GeneratorAdapter ga = new GeneratorAdapter(mv, Opcodes.ACC_STATIC, "", "()V");
84 | ga.visitCode();
85 |
86 | fieldValues.forEach((fieldName, encryptedValue) -> {
87 | encryptedValue = StringDecrypt.encrypt(encryptedValue);
88 | ga.push(encryptedValue);
89 | ga.invokeStatic(Type.getObjectType(StringDecryptDump.className),
90 | new Method("I", "(Ljava/lang/String;)Ljava/lang/String;"));
91 | ga.putStatic(Type.getObjectType(className), fieldName, Type.getType("Ljava/lang/String;"));
92 | });
93 |
94 | ga.returnValue();
95 | ga.endMethod();
96 | }
97 |
98 | @Override
99 | public void visitInnerClass(String name, String outerName, String innerName, int access) {
100 | super.visitInnerClass(name, outerName, innerName, access);
101 | }
102 |
103 | @Override
104 | public void visitNestHost(String nestHost) {
105 | super.visitNestHost(nestHost);
106 | }
107 |
108 | @Override
109 | public void visitNestMember(String nestMember) {
110 | super.visitNestMember(nestMember);
111 | }
112 |
113 | @Override
114 | public void visitOuterClass(String owner, String name, String descriptor) {
115 | super.visitOuterClass(owner, name, descriptor);
116 | }
117 |
118 | @Override
119 | public void visitPermittedSubclass(String permittedSubclass) {
120 | super.visitPermittedSubclass(permittedSubclass);
121 | }
122 |
123 | @Override
124 | public void visitSource(String source, String debug) {
125 | super.visitSource(source, debug);
126 | }
127 |
128 | @Override
129 | public ClassVisitor getDelegate() {
130 | return super.getDelegate();
131 | }
132 |
133 | static class StringChangerMethodAdapter extends MethodVisitor {
134 | StringChangerMethodAdapter(MethodVisitor mv) {
135 | super(Const.ASMVersion, mv);
136 | }
137 |
138 | @Override
139 | public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
140 | super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
141 | }
142 |
143 | @Override
144 | public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
145 | super.visitFieldInsn(opcode, owner, name, descriptor);
146 | }
147 |
148 | @Override
149 | public void visitTypeInsn(int opcode, String type) {
150 | super.visitTypeInsn(opcode, type);
151 | }
152 |
153 | @Override
154 | public void visitAttribute(Attribute attribute) {
155 | super.visitAttribute(attribute);
156 | }
157 |
158 | @Override
159 | public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
160 | return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
161 | }
162 |
163 | @Override
164 | public MethodVisitor getDelegate() {
165 | return super.getDelegate();
166 | }
167 |
168 | @Override
169 | public void visitEnd() {
170 | super.visitEnd();
171 | }
172 |
173 | @Override
174 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
175 | return super.visitAnnotation(descriptor, visible);
176 | }
177 |
178 | @Override
179 | public AnnotationVisitor visitAnnotationDefault() {
180 | return super.visitAnnotationDefault();
181 | }
182 |
183 | @Override
184 | public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
185 | return super.visitInsnAnnotation(typeRef, typePath, descriptor, visible);
186 | }
187 |
188 | @Override
189 | public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String descriptor, boolean visible) {
190 | return super.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, descriptor, visible);
191 | }
192 |
193 | @Override
194 | public AnnotationVisitor visitParameterAnnotation(int parameter, String descriptor, boolean visible) {
195 | return super.visitParameterAnnotation(parameter, descriptor, visible);
196 | }
197 |
198 | @Override
199 | public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
200 | return super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible);
201 | }
202 |
203 | @Override
204 | public void visitAnnotableParameterCount(int parameterCount, boolean visible) {
205 | super.visitAnnotableParameterCount(parameterCount, visible);
206 | }
207 |
208 | @Override
209 | public void visitCode() {
210 | super.visitCode();
211 | }
212 |
213 | @Override
214 | public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) {
215 | super.visitFrame(type, numLocal, local, numStack, stack);
216 | }
217 |
218 | @Override
219 | public void visitIincInsn(int varIndex, int increment) {
220 | super.visitIincInsn(varIndex, increment);
221 | }
222 |
223 | @Override
224 | public void visitInsn(int opcode) {
225 | super.visitInsn(opcode);
226 | }
227 |
228 | @Override
229 | public void visitIntInsn(int opcode, int operand) {
230 | super.visitIntInsn(opcode, operand);
231 | }
232 |
233 | @Override
234 | public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) {
235 | super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
236 | }
237 |
238 | @Override
239 | public void visitJumpInsn(int opcode, Label label) {
240 | super.visitJumpInsn(opcode, label);
241 | }
242 |
243 | @Override
244 | public void visitLabel(Label label) {
245 | super.visitLabel(label);
246 | }
247 |
248 | @Override
249 | public void visitLdcInsn(Object value) {
250 | if (value instanceof String) {
251 | String decryptedValue = StringDecrypt.encrypt((String) value);
252 | if (decryptedValue != null) {
253 | super.visitLdcInsn(decryptedValue);
254 | super.visitMethodInsn(Opcodes.INVOKESTATIC,
255 | StringDecryptDump.className,
256 | StringDecryptDump.methodName,
257 | "(Ljava/lang/String;)Ljava/lang/String;",
258 | false);
259 | return;
260 | }
261 | }
262 | super.visitLdcInsn(value);
263 | }
264 |
265 | @Override
266 | public void visitLineNumber(int line, Label start) {
267 | super.visitLineNumber(line, start);
268 | }
269 |
270 | @Override
271 | public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
272 | super.visitLocalVariable(name, descriptor, signature, start, end, index);
273 | }
274 |
275 | @Override
276 | public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
277 | super.visitLookupSwitchInsn(dflt, keys, labels);
278 | }
279 |
280 | @Override
281 | public void visitMaxs(int maxStack, int maxLocals) {
282 | super.visitMaxs(maxStack, maxLocals);
283 | }
284 |
285 | @Override
286 | public void visitMultiANewArrayInsn(String descriptor, int numDimensions) {
287 | super.visitMultiANewArrayInsn(descriptor, numDimensions);
288 | }
289 |
290 | @Override
291 | public void visitParameter(String name, int access) {
292 | super.visitParameter(name, access);
293 | }
294 |
295 | @Override
296 | public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
297 | super.visitTableSwitchInsn(min, max, dflt, labels);
298 | }
299 |
300 | @Override
301 | public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
302 | super.visitTryCatchBlock(start, end, handler, type);
303 | }
304 |
305 | @Override
306 | public void visitVarInsn(int opcode, int varIndex) {
307 | super.visitVarInsn(opcode, varIndex);
308 | }
309 | }
310 | }
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/base/ClassField.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.base;
2 |
3 | import java.util.Objects;
4 |
5 | public class ClassField {
6 | private String className;
7 | private String fieldName;
8 |
9 | public String getClassName() {
10 | return className;
11 | }
12 |
13 | public void setClassName(String className) {
14 | this.className = className;
15 | }
16 |
17 | public String getFieldName() {
18 | return fieldName;
19 | }
20 |
21 | public void setFieldName(String fieldName) {
22 | this.fieldName = fieldName;
23 | }
24 |
25 | @Override
26 | public boolean equals(Object o) {
27 | if (this == o) return true;
28 | if (o == null || getClass() != o.getClass()) return false;
29 | ClassField that = (ClassField) o;
30 | return Objects.equals(className, that.className) && Objects.equals(fieldName, that.fieldName);
31 | }
32 |
33 | @Override
34 | public int hashCode() {
35 | return Objects.hash(className, fieldName);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/base/ClassFileEntity.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.base;
2 |
3 | import me.n1ar4.log.LogManager;
4 | import me.n1ar4.log.Logger;
5 |
6 | import java.nio.file.Files;
7 | import java.nio.file.Path;
8 |
9 | public class ClassFileEntity {
10 | private static final Logger logger = LogManager.getLogger();
11 | private Path path;
12 | private String jarName;
13 |
14 | public Path getPath() {
15 | return path;
16 | }
17 |
18 | public void setPath(Path path) {
19 | this.path = path;
20 | }
21 |
22 | public String getJarName() {
23 | return jarName;
24 | }
25 |
26 | public void setJarName(String jarName) {
27 | this.jarName = jarName;
28 | }
29 |
30 | public ClassFileEntity() {
31 | }
32 |
33 | public byte[] getFile() {
34 | try {
35 | return Files.readAllBytes(this.path);
36 | } catch (Exception e) {
37 | logger.error("get file error: {}", e.toString());
38 | }
39 | return null;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/base/ClassReference.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.base;
2 |
3 | import java.util.List;
4 | import java.util.Objects;
5 | import java.util.Set;
6 |
7 | @SuppressWarnings("unused")
8 | public class ClassReference {
9 | private final String name;
10 | private final String superClass;
11 | private final List interfaces;
12 | private final boolean isInterface;
13 | private final boolean isEnum;
14 | private final List members;
15 | private final Set annotations;
16 | private final String jar;
17 |
18 | public static class Member {
19 | private final String name;
20 | private final int modifiers;
21 | private final Handle type;
22 |
23 | public Member(String name, int modifiers, Handle type) {
24 | this.name = name;
25 | this.modifiers = modifiers;
26 | this.type = type;
27 | }
28 |
29 | public String getName() {
30 | return name;
31 | }
32 |
33 | public int getModifiers() {
34 | return modifiers;
35 | }
36 |
37 | public Handle getType() {
38 | return type;
39 | }
40 | }
41 |
42 | public ClassReference(String name, String superClass, List interfaces,
43 | boolean isInterface, boolean isEnum, List members, Set annotations, String jar) {
44 | this.name = name;
45 | this.superClass = superClass;
46 | this.interfaces = interfaces;
47 | this.isInterface = isInterface;
48 | this.isEnum = isEnum;
49 | this.members = members;
50 | this.annotations = annotations;
51 | this.jar = jar;
52 | }
53 |
54 | public String getJar() {
55 | return jar;
56 | }
57 |
58 | public String getName() {
59 | return name;
60 | }
61 |
62 | public String getSuperClass() {
63 | return superClass;
64 | }
65 |
66 | public List getInterfaces() {
67 | return interfaces;
68 | }
69 |
70 | public boolean isInterface() {
71 | return isInterface;
72 | }
73 |
74 | public boolean isEnum() {
75 | return isEnum;
76 | }
77 |
78 | public List getMembers() {
79 | return members;
80 | }
81 |
82 | public Handle getHandle() {
83 | return new Handle(name);
84 | }
85 |
86 | public Set getAnnotations() {
87 | return annotations;
88 | }
89 |
90 | public static class Handle {
91 | private final String name;
92 |
93 | public Handle(String name) {
94 | this.name = name;
95 | }
96 |
97 | public String getName() {
98 | return name;
99 | }
100 |
101 | @Override
102 | public boolean equals(Object o) {
103 | if (this == o) {
104 | return true;
105 | }
106 | if (o == null || getClass() != o.getClass()) {
107 | return false;
108 | }
109 | Handle handle = (Handle) o;
110 | return Objects.equals(name, handle.name);
111 | }
112 |
113 | @Override
114 | public int hashCode() {
115 | return name != null ? name.hashCode() : 0;
116 | }
117 | }
118 |
119 | @Override
120 | public boolean equals(Object o) {
121 | if (this == o) {
122 | return true;
123 | }
124 | if (o == null || getClass() != o.getClass()) {
125 | return false;
126 | }
127 | ClassReference c = (ClassReference) o;
128 | return Objects.equals(name, c.name);
129 | }
130 |
131 | @Override
132 | public int hashCode() {
133 | return name != null ? name.hashCode() : 0;
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/base/MethodReference.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.base;
2 |
3 | import java.util.Objects;
4 | import java.util.Set;
5 |
6 | public class MethodReference {
7 | private ClassReference.Handle classReference;
8 | private final Set annotations;
9 | private final String name;
10 | private final String desc;
11 | private final int access;
12 | private final boolean isStatic;
13 |
14 | public MethodReference(ClassReference.Handle classReference,
15 | String name, String desc, boolean isStatic,
16 | Set annotations,
17 | int access) {
18 | this.classReference = classReference;
19 | this.name = name;
20 | this.desc = desc;
21 | this.isStatic = isStatic;
22 | this.annotations = annotations;
23 | this.access = access;
24 | }
25 |
26 | public void setClassReference(ClassReference.Handle classReference) {
27 | this.classReference = classReference;
28 | }
29 |
30 | public int getAccess() {
31 | return access;
32 | }
33 |
34 | public ClassReference.Handle getClassReference() {
35 | return classReference;
36 | }
37 |
38 | public String getName() {
39 | return name;
40 | }
41 |
42 | public String getDesc() {
43 | return desc;
44 | }
45 |
46 | public Set getAnnotations() {
47 | return annotations;
48 | }
49 |
50 | public boolean isStatic() {
51 | return isStatic;
52 | }
53 |
54 | public Handle getHandle() {
55 | return new Handle(classReference, name, desc);
56 | }
57 |
58 | public static class Handle {
59 | private final ClassReference.Handle classReference;
60 | private final String name;
61 | private final String desc;
62 |
63 | public Handle(ClassReference.Handle classReference, String name, String desc) {
64 | this.classReference = classReference;
65 | this.name = name;
66 | this.desc = desc;
67 | }
68 |
69 | public ClassReference.Handle getClassReference() {
70 | return classReference;
71 | }
72 |
73 | public String getName() {
74 | return name;
75 | }
76 |
77 | public String getDesc() {
78 | return desc;
79 | }
80 |
81 | @Override
82 | public boolean equals(Object o) {
83 | if (this == o) return true;
84 | if (o == null || getClass() != o.getClass()) return false;
85 | Handle handle = (Handle) o;
86 | if (!Objects.equals(classReference, handle.classReference))
87 | return false;
88 | if (!Objects.equals(name, handle.name))
89 | return false;
90 | return Objects.equals(desc, handle.desc);
91 | }
92 |
93 | @Override
94 | public int hashCode() {
95 | int result = classReference != null ? classReference.hashCode() : 0;
96 | result = 31 * result + (name != null ? name.hashCode() : 0);
97 | result = 31 * result + (desc != null ? desc.hashCode() : 0);
98 | return result;
99 | }
100 | }
101 |
102 | @Override
103 | public boolean equals(Object o) {
104 | if (this == o) return true;
105 | if (o == null || getClass() != o.getClass()) return false;
106 | MethodReference handle = (MethodReference) o;
107 | if (!Objects.equals(classReference, handle.classReference))
108 | return false;
109 | if (!Objects.equals(name, handle.name))
110 | return false;
111 | return Objects.equals(desc, handle.desc);
112 | }
113 |
114 | @Override
115 | public int hashCode() {
116 | int result = classReference != null ? classReference.hashCode() : 0;
117 | result = 31 * result + (name != null ? name.hashCode() : 0);
118 | result = 31 * result + (desc != null ? desc.hashCode() : 0);
119 | return result;
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/config/BaseCmd.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.config;
2 |
3 | import com.beust.jcommander.Parameter;
4 |
5 | public class BaseCmd {
6 | @Parameter(names = {"-j", "--jar"}, description = "jar file path")
7 | private String path;
8 | @Parameter(names = {"-c", "--config"}, description = "config yaml file")
9 | private String config;
10 | @Parameter(names = {"-g", "--generate"}, description = "generate config file")
11 | private boolean generate;
12 |
13 | public boolean isGenerate() {
14 | return generate;
15 | }
16 |
17 | public void setGenerate(boolean generate) {
18 | this.generate = generate;
19 | }
20 |
21 | public String getPath() {
22 | return path;
23 | }
24 |
25 | public void setPath(String path) {
26 | this.path = path;
27 | }
28 |
29 | public String getConfig() {
30 | return config;
31 | }
32 |
33 | public void setConfig(String config) {
34 | this.config = config;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/config/BaseConfig.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.config;
2 |
3 | public class BaseConfig {
4 | private String logLevel;
5 | private boolean useSpringBoot;
6 | private boolean useWebWar;
7 | private String[] obfuscateChars;
8 | private String[] classBlackList;
9 | private String[] classBlackRegexList;
10 | private String[] methodBlackList;
11 | private boolean enableClassName;
12 | private boolean enablePackageName;
13 | private boolean enableMethodName;
14 | private boolean enableFieldName;
15 | private boolean enableParamName;
16 | private boolean enableXOR;
17 | private boolean enableEncryptString;
18 | private String stringAesKey;
19 | private boolean enableAdvanceString;
20 | private String advanceStringName;
21 | private String decryptClassName;
22 | private String decryptMethodName;
23 | private String decryptKeyName;
24 | private boolean enableHideMethod;
25 | private boolean enableHideField;
26 | private boolean enableDeleteCompileInfo;
27 | private boolean enableJunk;
28 | private int junkLevel;
29 | private int maxJunkOneClass;
30 | private boolean showAllMainMethods;
31 | private boolean keepTempFile;
32 |
33 | public boolean isUseSpringBoot() {
34 | return useSpringBoot;
35 | }
36 |
37 | public void setUseSpringBoot(boolean useSpringBoot) {
38 | this.useSpringBoot = useSpringBoot;
39 | }
40 |
41 | public boolean isUseWebWar() {
42 | return useWebWar;
43 | }
44 |
45 | public void setUseWebWar(boolean useWebWar) {
46 | this.useWebWar = useWebWar;
47 | }
48 |
49 | public String getLogLevel() {
50 | return logLevel;
51 | }
52 |
53 | public void setLogLevel(String logLevel) {
54 | this.logLevel = logLevel;
55 | }
56 |
57 | public String[] getObfuscateChars() {
58 | return obfuscateChars;
59 | }
60 |
61 | public void setObfuscateChars(String[] obfuscateChars) {
62 | this.obfuscateChars = obfuscateChars;
63 | }
64 |
65 | public String[] getClassBlackList() {
66 | return classBlackList;
67 | }
68 |
69 | public void setClassBlackList(String[] classBlackList) {
70 | this.classBlackList = classBlackList;
71 | }
72 |
73 | public String[] getClassBlackRegexList() {
74 | return classBlackRegexList;
75 | }
76 |
77 | public void setClassBlackRegexList(String[] classBlackRegexList) {
78 | this.classBlackRegexList = classBlackRegexList;
79 | }
80 |
81 | public String[] getMethodBlackList() {
82 | return methodBlackList;
83 | }
84 |
85 | public void setMethodBlackList(String[] methodBlackList) {
86 | this.methodBlackList = methodBlackList;
87 | }
88 |
89 | public boolean isEnableClassName() {
90 | return enableClassName;
91 | }
92 |
93 | public void setEnableClassName(boolean enableClassName) {
94 | this.enableClassName = enableClassName;
95 | }
96 |
97 | public boolean isEnablePackageName() {
98 | return enablePackageName;
99 | }
100 |
101 | public void setEnablePackageName(boolean enablePackageName) {
102 | this.enablePackageName = enablePackageName;
103 | }
104 |
105 | public boolean isEnableMethodName() {
106 | return enableMethodName;
107 | }
108 |
109 | public void setEnableMethodName(boolean enableMethodName) {
110 | this.enableMethodName = enableMethodName;
111 | }
112 |
113 | public boolean isEnableFieldName() {
114 | return enableFieldName;
115 | }
116 |
117 | public void setEnableFieldName(boolean enableFieldName) {
118 | this.enableFieldName = enableFieldName;
119 | }
120 |
121 | public boolean isEnableParamName() {
122 | return enableParamName;
123 | }
124 |
125 | public void setEnableParamName(boolean enableParamName) {
126 | this.enableParamName = enableParamName;
127 | }
128 |
129 | public boolean isEnableXOR() {
130 | return enableXOR;
131 | }
132 |
133 | public void setEnableXOR(boolean enableXOR) {
134 | this.enableXOR = enableXOR;
135 | }
136 |
137 | public boolean isEnableEncryptString() {
138 | return enableEncryptString;
139 | }
140 |
141 | public void setEnableEncryptString(boolean enableEncryptString) {
142 | this.enableEncryptString = enableEncryptString;
143 | }
144 |
145 | public String getStringAesKey() {
146 | return stringAesKey;
147 | }
148 |
149 | public void setStringAesKey(String stringAesKey) {
150 | this.stringAesKey = stringAesKey;
151 | }
152 |
153 | public boolean isEnableAdvanceString() {
154 | return enableAdvanceString;
155 | }
156 |
157 | public void setEnableAdvanceString(boolean enableAdvanceString) {
158 | this.enableAdvanceString = enableAdvanceString;
159 | }
160 |
161 | public String getAdvanceStringName() {
162 | return advanceStringName;
163 | }
164 |
165 | public void setAdvanceStringName(String advanceStringName) {
166 | this.advanceStringName = advanceStringName;
167 | }
168 |
169 | public String getDecryptClassName() {
170 | return decryptClassName;
171 | }
172 |
173 | public void setDecryptClassName(String decryptClassName) {
174 | this.decryptClassName = decryptClassName;
175 | }
176 |
177 | public String getDecryptMethodName() {
178 | return decryptMethodName;
179 | }
180 |
181 | public void setDecryptMethodName(String decryptMethodName) {
182 | this.decryptMethodName = decryptMethodName;
183 | }
184 |
185 | public String getDecryptKeyName() {
186 | return decryptKeyName;
187 | }
188 |
189 | public void setDecryptKeyName(String decryptKeyName) {
190 | this.decryptKeyName = decryptKeyName;
191 | }
192 |
193 | public boolean isEnableHideMethod() {
194 | return enableHideMethod;
195 | }
196 |
197 | public void setEnableHideMethod(boolean enableHideMethod) {
198 | this.enableHideMethod = enableHideMethod;
199 | }
200 |
201 | public boolean isEnableHideField() {
202 | return enableHideField;
203 | }
204 |
205 | public void setEnableHideField(boolean enableHideField) {
206 | this.enableHideField = enableHideField;
207 | }
208 |
209 | public boolean isEnableDeleteCompileInfo() {
210 | return enableDeleteCompileInfo;
211 | }
212 |
213 | public void setEnableDeleteCompileInfo(boolean enableDeleteCompileInfo) {
214 | this.enableDeleteCompileInfo = enableDeleteCompileInfo;
215 | }
216 |
217 | public boolean isEnableJunk() {
218 | return enableJunk;
219 | }
220 |
221 | public void setEnableJunk(boolean enableJunk) {
222 | this.enableJunk = enableJunk;
223 | }
224 |
225 | public int getJunkLevel() {
226 | return junkLevel;
227 | }
228 |
229 | public void setJunkLevel(int junkLevel) {
230 | this.junkLevel = junkLevel;
231 | }
232 |
233 | public int getMaxJunkOneClass() {
234 | return maxJunkOneClass;
235 | }
236 |
237 | public void setMaxJunkOneClass(int maxJunkOneClass) {
238 | this.maxJunkOneClass = maxJunkOneClass;
239 | }
240 |
241 | public boolean isShowAllMainMethods() {
242 | return showAllMainMethods;
243 | }
244 |
245 | public void setShowAllMainMethods(boolean showAllMainMethods) {
246 | this.showAllMainMethods = showAllMainMethods;
247 | }
248 |
249 | public boolean isKeepTempFile() {
250 | return keepTempFile;
251 | }
252 |
253 | public void setKeepTempFile(boolean keepTempFile) {
254 | this.keepTempFile = keepTempFile;
255 | }
256 | }
257 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/config/Manager.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.config;
2 |
3 | import me.n1ar4.jar.obfuscator.asm.JunkCodeVisitor;
4 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
5 | import me.n1ar4.jar.obfuscator.templates.StringDecrypt;
6 | import me.n1ar4.jar.obfuscator.templates.StringDecryptDump;
7 | import me.n1ar4.jar.obfuscator.utils.NameUtil;
8 | import me.n1ar4.jrandom.core.JRandom;
9 | import me.n1ar4.log.LogLevel;
10 | import me.n1ar4.log.LogManager;
11 | import me.n1ar4.log.Logger;
12 | import me.n1ar4.log.LoggingStream;
13 |
14 | public class Manager {
15 | private static final Logger logger = LogManager.getLogger();
16 |
17 | public static boolean initConfig(BaseConfig config) {
18 | JRandom random = new JRandom();
19 | JRandom.setInstance(random);
20 |
21 | // LOG LEVEL
22 | String logLevel = config.getLogLevel();
23 | switch (logLevel) {
24 | case "debug":
25 | LogManager.setLevel(LogLevel.DEBUG);
26 | break;
27 | case "info":
28 | LogManager.setLevel(LogLevel.INFO);
29 | break;
30 | case "warn":
31 | LogManager.setLevel(LogLevel.WARN);
32 | break;
33 | case "error":
34 | LogManager.setLevel(LogLevel.ERROR);
35 | break;
36 | default:
37 | logger.error("error log level");
38 | return false;
39 | }
40 | System.setOut(new LoggingStream(System.out, logger));
41 | System.out.println("set log io-streams");
42 | System.setErr(new LoggingStream(System.err, logger));
43 | System.err.println("set log err-streams");
44 |
45 | // CHARS
46 | if (config.getObfuscateChars() == null ||
47 | config.getObfuscateChars().length < 3) {
48 | logger.warn("obfuscate chars length too small");
49 | NameUtil.CHAR_POOL = new char[]{'i', 'l', 'L', '1', 'I'};
50 | } else {
51 | char[] data = new char[config.getObfuscateChars().length];
52 | for (int i = 0; i < config.getObfuscateChars().length; i++) {
53 | String s = config.getObfuscateChars()[i];
54 | if (s == null || s.isEmpty()) {
55 | logger.error("null in obfuscate chars");
56 | return false;
57 | }
58 | data[i] = s.charAt(0);
59 | }
60 | NameUtil.CHAR_POOL = data;
61 | }
62 |
63 | JunkCodeVisitor.MAX_JUNK_NUM = config.getMaxJunkOneClass();
64 | ObfEnv.ADVANCE_STRING_NAME = config.getAdvanceStringName();
65 |
66 | StringDecrypt.changeKEY(config.getStringAesKey());
67 | StringDecryptDump.changeKEY();
68 | StringDecryptDump.initName(
69 | config.getDecryptClassName(),
70 | config.getDecryptMethodName(),
71 | config.getDecryptKeyName());
72 |
73 | return true;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/config/Parser.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.config;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.utils.IOUtils;
5 | import me.n1ar4.log.LogManager;
6 | import me.n1ar4.log.Logger;
7 | import org.yaml.snakeyaml.LoaderOptions;
8 | import org.yaml.snakeyaml.Yaml;
9 | import org.yaml.snakeyaml.constructor.Constructor;
10 | import org.yaml.snakeyaml.inspector.TagInspector;
11 |
12 | import java.io.ByteArrayInputStream;
13 | import java.io.InputStream;
14 | import java.nio.charset.StandardCharsets;
15 | import java.nio.file.Files;
16 | import java.nio.file.Path;
17 |
18 | public class Parser {
19 | private static final Logger logger = LogManager.getLogger();
20 | private String TEMPLATE;
21 | private final Yaml yaml;
22 |
23 | public Parser() {
24 | LoaderOptions options = new LoaderOptions();
25 | TagInspector taginspector =
26 | tag -> tag.getClassName().equals(BaseConfig.class.getName());
27 | options.setTagInspector(taginspector);
28 | yaml = new Yaml(new Constructor(BaseConfig.class, options));
29 | InputStream is = Parser.class.getClassLoader().getResourceAsStream("config.yaml");
30 | if (is == null) {
31 | return;
32 | }
33 | try {
34 | byte[] data = IOUtils.readAllBytes(is);
35 | TEMPLATE = new String(data, StandardCharsets.UTF_8);
36 | } catch (Exception ex) {
37 | logger.error("read template error: {}", ex);
38 | }
39 | }
40 |
41 | public void generateConfig() {
42 | try {
43 | Files.write(Const.configPath, TEMPLATE.getBytes(StandardCharsets.UTF_8));
44 | } catch (Exception ex) {
45 | logger.error("write config file error: {}", ex.toString());
46 | }
47 | }
48 |
49 | public BaseConfig parse(Path file) {
50 | if (!Files.exists(file)) {
51 | logger.error("config file not exist");
52 | return null;
53 | }
54 | try {
55 | InputStream is = new ByteArrayInputStream(Files.readAllBytes(file));
56 | return yaml.load(is);
57 | } catch (Exception ex) {
58 | logger.error("parse config error: {}", ex.toString());
59 | }
60 | return null;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/core/AnalyzeEnv.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.core;
2 |
3 | import me.n1ar4.jar.obfuscator.base.ClassFileEntity;
4 | import me.n1ar4.jar.obfuscator.base.ClassReference;
5 | import me.n1ar4.jar.obfuscator.base.MethodReference;
6 |
7 | import java.util.*;
8 |
9 | public class AnalyzeEnv {
10 | public static Set classFileList = new HashSet<>();
11 | public static final Set discoveredClasses = new HashSet<>();
12 | public static final Set discoveredMethods = new HashSet<>();
13 | public static final Map> methodsInClassMap = new HashMap<>();
14 | public static final Map> fieldsInClassMap = new HashMap<>();
15 | public static final Map classMap = new HashMap<>();
16 | public static final Map methodMap = new HashMap<>();
17 | public static final HashMap> methodCalls = new HashMap<>();
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/core/DiscoveryRunner.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.core;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.analyze.DiscoveryClassVisitor;
5 | import me.n1ar4.jar.obfuscator.base.ClassFileEntity;
6 | import me.n1ar4.jar.obfuscator.base.ClassReference;
7 | import me.n1ar4.jar.obfuscator.base.MethodReference;
8 | import me.n1ar4.log.LogManager;
9 | import me.n1ar4.log.Logger;
10 | import org.objectweb.asm.ClassReader;
11 |
12 | import java.util.List;
13 | import java.util.Map;
14 | import java.util.Set;
15 |
16 | public class DiscoveryRunner {
17 | private static final Logger logger = LogManager.getLogger();
18 |
19 | public static void start(Set classFileList,
20 | Set discoveredClasses,
21 | Set discoveredMethods,
22 | Map classMap,
23 | Map methodMap,
24 | Map> fieldsInClassMap) {
25 | logger.info("start class analyze");
26 | for (ClassFileEntity file : classFileList) {
27 | try {
28 | DiscoveryClassVisitor dcv = new DiscoveryClassVisitor(discoveredClasses,
29 | discoveredMethods, fieldsInClassMap, file.getJarName());
30 | ClassReader cr = new ClassReader(file.getFile());
31 | cr.accept(dcv, Const.AnalyzeASMOptions);
32 | } catch (Exception e) {
33 | logger.error("discovery error: {}", e.toString());
34 | }
35 | }
36 | for (ClassReference clazz : discoveredClasses) {
37 | classMap.put(clazz.getHandle(), clazz);
38 | }
39 | for (MethodReference method : discoveredMethods) {
40 | methodMap.put(method.getHandle(), method);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/core/MethodCallRunner.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.core;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.analyze.MethodCallClassVisitor;
5 | import me.n1ar4.jar.obfuscator.base.ClassFileEntity;
6 | import me.n1ar4.jar.obfuscator.base.MethodReference;
7 | import me.n1ar4.log.LogManager;
8 | import me.n1ar4.log.Logger;
9 | import org.objectweb.asm.ClassReader;
10 |
11 | import java.util.HashMap;
12 | import java.util.HashSet;
13 | import java.util.Set;
14 |
15 | public class MethodCallRunner {
16 | private static final Logger logger = LogManager.getLogger();
17 |
18 | public static void start(Set classFileList, HashMap> methodCalls) {
20 | logger.info("start analyze method calls");
21 | for (ClassFileEntity file : classFileList) {
22 | try {
23 | MethodCallClassVisitor mcv =
24 | new MethodCallClassVisitor(methodCalls);
25 | ClassReader cr = new ClassReader(file.getFile());
26 | cr.accept(mcv, Const.AnalyzeASMOptions);
27 | } catch (Exception e) {
28 | logger.error("method call error: {}", e.toString());
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/core/ObfEnv.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.core;
2 |
3 | import me.n1ar4.jar.obfuscator.base.ClassField;
4 | import me.n1ar4.jar.obfuscator.base.ClassReference;
5 | import me.n1ar4.jar.obfuscator.base.MethodReference;
6 | import me.n1ar4.jar.obfuscator.config.BaseConfig;
7 |
8 | import java.util.ArrayList;
9 | import java.util.HashMap;
10 | import java.util.List;
11 | import java.util.Map;
12 |
13 | public class ObfEnv {
14 | public static BaseConfig config = null;
15 | public static String ADVANCE_STRING_NAME = null;
16 | public static Map classNameObfMapping = new ObfHashMap();
17 | public static Map> ignoredClassMethodsMapping = new HashMap<>();
18 | public static Map methodNameObfMapping = new HashMap<>();
19 | public static Map fieldNameObfMapping = new HashMap<>();
20 | public static final HashMap> stringInClass = new HashMap<>();
21 | public static final HashMap> newStringInClass = new HashMap<>();
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/core/ObfHashMap.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.core;
2 |
3 | import java.util.HashMap;
4 |
5 |
6 | public class ObfHashMap extends HashMap {
7 | @Override
8 | public String put(String key, String value) {
9 | value = value.replaceAll("^[/\\\\]+", "");
10 | value = value.replaceAll("[/\\\\]+$", "");
11 | if (value.endsWith(".class")) {
12 | value = value.substring(0, value.length() - 6);
13 | }
14 | return super.put(key, value);
15 | }
16 |
17 | @Override
18 | public String putIfAbsent(String key, String value) {
19 | value = value.replaceAll("^[/\\\\]+", "");
20 | value = value.replaceAll("[/\\\\]+$", "");
21 | if (value.endsWith(".class")) {
22 | value = value.substring(0, value.length() - 6);
23 | }
24 | return super.putIfAbsent(key, value);
25 | }
26 | }
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/loader/CustomClassLoader.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.loader;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 |
5 | import java.nio.file.Files;
6 | import java.nio.file.Path;
7 | import java.nio.file.Paths;
8 |
9 | public class CustomClassLoader extends ClassLoader {
10 | @Override
11 | public Class> findClass(String name) {
12 | byte[] b = loadClassData(name);
13 | if (b != null) {
14 | return defineClass(name, b, 0, b.length);
15 | }
16 | return null;
17 | }
18 |
19 | private byte[] loadClassData(String name) {
20 | String classPath = name.replace('.', '/') + ".class";
21 | Path path = Paths.get(Const.TEMP_DIR).resolve(classPath);
22 | try {
23 | return Files.readAllBytes(path);
24 | } catch (Exception ignored) {
25 | return null;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/loader/CustomClassWriter.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.loader;
2 |
3 | import me.n1ar4.log.LogManager;
4 | import me.n1ar4.log.Logger;
5 | import org.objectweb.asm.ClassReader;
6 | import org.objectweb.asm.ClassWriter;
7 |
8 | public class CustomClassWriter extends ClassWriter {
9 | private static final String defaultRet = "java/lang/Object";
10 | private static final Logger logger = LogManager.getLogger();
11 | private final ClassLoader classLoader;
12 |
13 | public CustomClassWriter(ClassReader classReader, int flags, ClassLoader classLoader) {
14 | super(classReader, flags);
15 | this.classLoader = classLoader;
16 | }
17 |
18 | @Override
19 | protected String getCommonSuperClass(final String type1, final String type2) {
20 | if (type1 == null || type2 == null) {
21 | return defaultRet;
22 | }
23 | if (type1.trim().isEmpty() || type2.trim().isEmpty()) {
24 | return defaultRet;
25 | }
26 | Class> c, d;
27 | try {
28 | c = Class.forName(type1.replace('/', '.'), false, classLoader);
29 | d = Class.forName(type2.replace('/', '.'), false, classLoader);
30 | } catch (Exception e) {
31 | logger.debug("junk code obfuscate warn: {}", e.toString());
32 | return defaultRet;
33 | }
34 | if (c.isAssignableFrom(d)) {
35 | return type1;
36 | }
37 | if (d.isAssignableFrom(c)) {
38 | return type2;
39 | }
40 | if (c.isInterface() || d.isInterface()) {
41 | return defaultRet;
42 | } else {
43 | do {
44 | c = c.getSuperclass();
45 | } while (!c.isAssignableFrom(d));
46 | return c.getName().replace('.', '/');
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/templates/StringDecrypt.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.templates;
2 |
3 | import me.n1ar4.jrandom.core.JRandom;
4 | import me.n1ar4.log.LogManager;
5 | import me.n1ar4.log.Logger;
6 |
7 | import javax.crypto.Cipher;
8 | import javax.crypto.spec.SecretKeySpec;
9 | import java.nio.charset.Charset;
10 | import java.nio.charset.StandardCharsets;
11 | import java.util.Base64;
12 |
13 | public class StringDecrypt {
14 | private static final Logger logger = LogManager.getLogger();
15 | public static String KEY = null;
16 | private static final String ALGORITHM = "AES";
17 | private static final Charset CHARSET = StandardCharsets.UTF_8;
18 |
19 | public static void changeKEY(String key) {
20 | if (key == null) {
21 | KEY = JRandom.getInstance().randomString(16);
22 | logger.info("设置随机 AES_KEY 为 " + KEY);
23 | return;
24 | }
25 | if (key.equals("Y4SuperSecretKey")) {
26 | logger.warn("默认 AES_KEY 是不安全的");
27 | KEY = JRandom.getInstance().randomString(16);
28 | logger.info("设置随机 AES_KEY 为 " + KEY);
29 | } else {
30 | if (key.length() == 16) {
31 | KEY = key;
32 | logger.info("change encrypt aes key to: {}", key);
33 | } else {
34 | logger.warn("AES_KEY 长度必须是 16 当前长度是 " + key.length());
35 | KEY = JRandom.getInstance().randomString(16);
36 | logger.info("设置随机 AES_KEY 为 " + KEY);
37 | }
38 | }
39 | }
40 |
41 | public static String encrypt(String input) {
42 | try {
43 | SecretKeySpec key = new SecretKeySpec(KEY.getBytes(CHARSET), ALGORITHM);
44 | Cipher cipher = Cipher.getInstance(ALGORITHM);
45 | cipher.init(Cipher.ENCRYPT_MODE, key);
46 | byte[] encrypted = cipher.doFinal(input.getBytes(CHARSET));
47 | return new String(Base64.getEncoder().encode(encrypted), CHARSET);
48 | } catch (Exception e) {
49 | return null;
50 | }
51 | }
52 |
53 | @SuppressWarnings("unused")
54 | public static String decrypt(String encrypted) {
55 | try {
56 | SecretKeySpec key = new SecretKeySpec(KEY.getBytes(CHARSET), ALGORITHM);
57 | Cipher cipher = Cipher.getInstance(ALGORITHM);
58 | cipher.init(Cipher.DECRYPT_MODE, key);
59 | byte[] data = encrypted.getBytes(CHARSET);
60 | byte[] original = cipher.doFinal(Base64.getDecoder().decode(data));
61 | return new String(original, CHARSET);
62 | } catch (Exception e) {
63 | return null;
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/templates/StringDecryptDump.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.templates;
2 |
3 | import org.objectweb.asm.*;
4 |
5 | public class StringDecryptDump implements Opcodes {
6 | public static String AES_KEY = null;
7 | public static String className = null;
8 | public static String methodName = null;
9 | private static String keyName = null;
10 |
11 | public static void changeKEY() {
12 | AES_KEY = StringDecrypt.KEY;
13 | }
14 |
15 | public static void initName(String c, String m, String k) {
16 | String defaultClassName = "org/apache/commons/collections/list/AbstractHashMap";
17 | String defaultMethodName = "newMap";
18 | String defaultKeyName = "LiLiLLLiiiLLiiLLi";
19 | if (c == null || m == null || k == null) {
20 | className = defaultClassName;
21 | methodName = defaultMethodName;
22 | keyName = defaultKeyName;
23 | return;
24 | }
25 | c = c.replace(".", "/");
26 | if (c.isEmpty()) {
27 | className = defaultClassName;
28 | } else {
29 | className = c;
30 | }
31 | if (m.isEmpty()) {
32 | methodName = defaultMethodName;
33 | } else {
34 | methodName = m;
35 | }
36 | if (k.isEmpty()) {
37 | keyName = defaultKeyName;
38 | } else {
39 | keyName = k;
40 | }
41 | }
42 |
43 | public static byte[] dump() {
44 | ClassWriter classWriter = new ClassWriter(0);
45 | FieldVisitor fieldVisitor;
46 | MethodVisitor methodVisitor;
47 | classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, className, null, "java/lang/Object", null);
48 | classWriter.visitInnerClass("java/util/Base64$Encoder", "java/util/Base64", "Encoder", ACC_PUBLIC | ACC_STATIC);
49 | classWriter.visitInnerClass("java/util/Base64$Decoder", "java/util/Base64", "Decoder", ACC_PUBLIC | ACC_STATIC);
50 | {
51 | fieldVisitor = classWriter.visitField(ACC_PRIVATE | ACC_STATIC, keyName, "Ljava/lang/String;", null, null);
52 | fieldVisitor.visitEnd();
53 | }
54 | {
55 | fieldVisitor = classWriter.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC, "ALGORITHM", "Ljava/lang/String;", null, "AES");
56 | fieldVisitor.visitEnd();
57 | }
58 | {
59 | fieldVisitor = classWriter.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC, "CHARSET", "Ljava/nio/charset/Charset;", null, null);
60 | fieldVisitor.visitEnd();
61 | }
62 | {
63 | methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, methodName, "(Ljava/lang/String;)Ljava/lang/String;", null, null);
64 | methodVisitor.visitCode();
65 | Label label0 = new Label();
66 | Label label1 = new Label();
67 | Label label2 = new Label();
68 | methodVisitor.visitTryCatchBlock(label0, label1, label2, "java/lang/Exception");
69 | methodVisitor.visitLabel(label0);
70 | methodVisitor.visitTypeInsn(NEW, "javax/crypto/spec/SecretKeySpec");
71 | methodVisitor.visitInsn(DUP);
72 | methodVisitor.visitFieldInsn(GETSTATIC, className, keyName, "Ljava/lang/String;");
73 | methodVisitor.visitFieldInsn(GETSTATIC, className, "CHARSET", "Ljava/nio/charset/Charset;");
74 | methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", "(Ljava/nio/charset/Charset;)[B", false);
75 | methodVisitor.visitLdcInsn("AES");
76 | methodVisitor.visitMethodInsn(INVOKESPECIAL, "javax/crypto/spec/SecretKeySpec", "", "([BLjava/lang/String;)V", false);
77 | methodVisitor.visitVarInsn(ASTORE, 1);
78 | Label label3 = new Label();
79 | methodVisitor.visitLabel(label3);
80 | methodVisitor.visitLdcInsn("AES");
81 | methodVisitor.visitMethodInsn(INVOKESTATIC, "javax/crypto/Cipher", "getInstance", "(Ljava/lang/String;)Ljavax/crypto/Cipher;", false);
82 | methodVisitor.visitVarInsn(ASTORE, 2);
83 | Label label4 = new Label();
84 | methodVisitor.visitLabel(label4);
85 | methodVisitor.visitVarInsn(ALOAD, 2);
86 | methodVisitor.visitInsn(ICONST_2);
87 | methodVisitor.visitVarInsn(ALOAD, 1);
88 | methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "javax/crypto/Cipher", "init", "(ILjava/security/Key;)V", false);
89 | Label label5 = new Label();
90 | methodVisitor.visitLabel(label5);
91 | methodVisitor.visitVarInsn(ALOAD, 0);
92 | methodVisitor.visitFieldInsn(GETSTATIC, className, "CHARSET", "Ljava/nio/charset/Charset;");
93 | methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", "(Ljava/nio/charset/Charset;)[B", false);
94 | methodVisitor.visitVarInsn(ASTORE, 3);
95 | Label label6 = new Label();
96 | methodVisitor.visitLabel(label6);
97 | methodVisitor.visitVarInsn(ALOAD, 2);
98 | methodVisitor.visitMethodInsn(INVOKESTATIC, "java/util/Base64", "getDecoder", "()Ljava/util/Base64$Decoder;", false);
99 | methodVisitor.visitVarInsn(ALOAD, 3);
100 | methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/util/Base64$Decoder", "decode", "([B)[B", false);
101 | methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "javax/crypto/Cipher", "doFinal", "([B)[B", false);
102 | methodVisitor.visitVarInsn(ASTORE, 4);
103 | Label label7 = new Label();
104 | methodVisitor.visitLabel(label7);
105 | methodVisitor.visitTypeInsn(NEW, "java/lang/String");
106 | methodVisitor.visitInsn(DUP);
107 | methodVisitor.visitVarInsn(ALOAD, 4);
108 | methodVisitor.visitFieldInsn(GETSTATIC, className, "CHARSET", "Ljava/nio/charset/Charset;");
109 | methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([BLjava/nio/charset/Charset;)V", false);
110 | methodVisitor.visitLabel(label1);
111 | methodVisitor.visitInsn(ARETURN);
112 | methodVisitor.visitLabel(label2);
113 | methodVisitor.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{"java/lang/Exception"});
114 | methodVisitor.visitVarInsn(ASTORE, 1);
115 | Label label8 = new Label();
116 | methodVisitor.visitLabel(label8);
117 | methodVisitor.visitInsn(ACONST_NULL);
118 | methodVisitor.visitInsn(ARETURN);
119 | Label label9 = new Label();
120 | methodVisitor.visitLabel(label9);
121 | methodVisitor.visitLocalVariable("key", "Ljavax/crypto/spec/SecretKeySpec;", null, label3, label2, 1);
122 | methodVisitor.visitLocalVariable("cipher", "Ljavax/crypto/Cipher;", null, label4, label2, 2);
123 | methodVisitor.visitLocalVariable("data", "[B", null, label6, label2, 3);
124 | methodVisitor.visitLocalVariable("original", "[B", null, label7, label2, 4);
125 | methodVisitor.visitLocalVariable("e", "Ljava/lang/Exception;", null, label8, label9, 1);
126 | methodVisitor.visitLocalVariable("encrypted", "Ljava/lang/String;", null, label0, label9, 0);
127 | methodVisitor.visitMaxs(4, 5);
128 | methodVisitor.visitEnd();
129 | }
130 | {
131 | methodVisitor = classWriter.visitMethod(ACC_STATIC, "", "()V", null, null);
132 | methodVisitor.visitCode();
133 | Label label0 = new Label();
134 | methodVisitor.visitLabel(label0);
135 | methodVisitor.visitLdcInsn(AES_KEY);
136 | methodVisitor.visitFieldInsn(PUTSTATIC, className, keyName, "Ljava/lang/String;");
137 | Label label1 = new Label();
138 | methodVisitor.visitLabel(label1);
139 | methodVisitor.visitFieldInsn(GETSTATIC, "java/nio/charset/StandardCharsets", "UTF_8", "Ljava/nio/charset/Charset;");
140 | methodVisitor.visitFieldInsn(PUTSTATIC, className, "CHARSET", "Ljava/nio/charset/Charset;");
141 | methodVisitor.visitInsn(RETURN);
142 | methodVisitor.visitMaxs(1, 0);
143 | methodVisitor.visitEnd();
144 | }
145 | classWriter.visitEnd();
146 | return classWriter.toByteArray();
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/transform/ClassNameTransformer.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.transform;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.asm.ClassNameVisitor;
5 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
6 | import me.n1ar4.log.LogManager;
7 | import me.n1ar4.log.Logger;
8 | import org.objectweb.asm.ClassReader;
9 | import org.objectweb.asm.ClassWriter;
10 |
11 | import java.nio.file.Files;
12 | import java.nio.file.Path;
13 | import java.nio.file.Paths;
14 | import java.util.Map;
15 |
16 | public class ClassNameTransformer {
17 | private static final Logger logger = LogManager.getLogger();
18 |
19 | public static void transform() {
20 | for (Map.Entry entry : ObfEnv.classNameObfMapping.entrySet()) {
21 | String originalName = entry.getKey();
22 | String newName = entry.getValue();
23 | Path tempDir = Paths.get(Const.TEMP_DIR);
24 |
25 | if (ObfEnv.config.isUseSpringBoot()) {
26 | tempDir = tempDir.resolve("BOOT-INF/classes/");
27 | }
28 | if (ObfEnv.config.isUseWebWar()) {
29 | tempDir = tempDir.resolve("WEB-INF/classes/");
30 | }
31 |
32 | Path classPath = tempDir.resolve(Paths.get(originalName + ".class"));
33 | Path newClassPath = tempDir.resolve(Paths.get(newName + ".class"));
34 | try {
35 | Files.createDirectories(newClassPath.getParent());
36 | } catch (Exception ignored) {
37 | }
38 | if (!Files.exists(classPath)) {
39 | logger.debug("class not exist: {}", classPath.toString());
40 | continue;
41 | }
42 | try {
43 | ClassReader classReader = new ClassReader(Files.readAllBytes(classPath));
44 | ClassWriter classWriter = new ClassWriter(classReader, 0);
45 | ClassNameVisitor changer = new ClassNameVisitor(classWriter);
46 | classReader.accept(changer, Const.AnalyzeASMOptions);
47 | Files.delete(classPath);
48 | Files.write(newClassPath, classWriter.toByteArray());
49 | } catch (Exception ex) {
50 | logger.error("transform error: {}", ex.toString());
51 | }
52 | }
53 | logger.info("rename class name finish");
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/transform/DeleteInfoTransformer.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.transform;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.asm.CompileInfoVisitor;
5 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
6 | import me.n1ar4.log.LogManager;
7 | import me.n1ar4.log.Logger;
8 | import org.objectweb.asm.ClassReader;
9 | import org.objectweb.asm.ClassWriter;
10 |
11 | import java.nio.file.Files;
12 | import java.nio.file.Path;
13 | import java.nio.file.Paths;
14 | import java.util.Map;
15 |
16 | public class DeleteInfoTransformer {
17 | private static final Logger logger = LogManager.getLogger();
18 |
19 | public static void transform() {
20 | for (Map.Entry entry : ObfEnv.classNameObfMapping.entrySet()) {
21 | String originalName = entry.getKey();
22 | Path tempDir = Paths.get(Const.TEMP_DIR);
23 |
24 | if (ObfEnv.config.isUseSpringBoot()) {
25 | tempDir = tempDir.resolve("BOOT-INF/classes/");
26 | }
27 | if (ObfEnv.config.isUseWebWar()) {
28 | tempDir = tempDir.resolve("WEB-INF/classes/");
29 | }
30 |
31 | Path classPath = tempDir.resolve(Paths.get(originalName + ".class"));
32 | if (!Files.exists(classPath)) {
33 | logger.debug("class not exist: {}", classPath.toString());
34 | continue;
35 | }
36 | try {
37 | ClassReader classReader = new ClassReader(Files.readAllBytes(classPath));
38 | ClassWriter classWriter = new ClassWriter(classReader, 0);
39 | CompileInfoVisitor changer = new CompileInfoVisitor(classWriter);
40 | classReader.accept(changer, Const.AnalyzeASMOptions);
41 | Files.delete(classPath);
42 | Files.write(classPath, classWriter.toByteArray());
43 | } catch (Exception ex) {
44 | logger.error("transform error: {}", ex.toString());
45 | }
46 | }
47 | logger.info("delete compile info finish");
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/transform/FieldNameTransformer.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.transform;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.asm.FieldNameVisitor;
5 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
6 | import me.n1ar4.log.LogManager;
7 | import me.n1ar4.log.Logger;
8 | import org.objectweb.asm.ClassReader;
9 | import org.objectweb.asm.ClassWriter;
10 |
11 | import java.nio.file.Files;
12 | import java.nio.file.Path;
13 | import java.nio.file.Paths;
14 | import java.util.Map;
15 |
16 | @SuppressWarnings("all")
17 | public class FieldNameTransformer {
18 | private static final Logger logger = LogManager.getLogger();
19 |
20 | public static void transform() {
21 | for (Map.Entry entry : ObfEnv.classNameObfMapping.entrySet()) {
22 | String newName = entry.getValue();
23 | Path tempDir = Paths.get(Const.TEMP_DIR);
24 |
25 | if (ObfEnv.config.isUseSpringBoot()) {
26 | tempDir = tempDir.resolve("BOOT-INF/classes/");
27 | }
28 | if (ObfEnv.config.isUseWebWar()) {
29 | tempDir = tempDir.resolve("WEB-INF/classes/");
30 | }
31 |
32 | Path newClassPath = tempDir.resolve(Paths.get(newName + ".class"));
33 | if (!Files.exists(newClassPath)) {
34 | logger.debug("class not exist: {}", newClassPath.toString());
35 | continue;
36 | }
37 | try {
38 | ClassReader classReader = new ClassReader(Files.readAllBytes(newClassPath));
39 | ClassWriter classWriter = new ClassWriter(classReader, 0);
40 | FieldNameVisitor changer = new FieldNameVisitor(classWriter);
41 | classReader.accept(changer, Const.AnalyzeASMOptions);
42 | Files.delete(newClassPath);
43 | Files.write(newClassPath, classWriter.toByteArray());
44 | } catch (Exception ex) {
45 | logger.error("transform error: {}", ex.toString());
46 | }
47 | }
48 | logger.info("rename field name finish");
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/transform/JunkCodeTransformer.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.transform;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.asm.JunkCodeVisitor;
5 | import me.n1ar4.jar.obfuscator.config.BaseConfig;
6 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
7 | import me.n1ar4.jar.obfuscator.loader.CustomClassLoader;
8 | import me.n1ar4.jar.obfuscator.loader.CustomClassWriter;
9 | import me.n1ar4.log.LogManager;
10 | import me.n1ar4.log.Logger;
11 | import org.objectweb.asm.ClassReader;
12 | import org.objectweb.asm.ClassWriter;
13 | import org.objectweb.asm.MethodTooLargeException;
14 |
15 | import java.nio.file.Files;
16 | import java.nio.file.Path;
17 | import java.nio.file.Paths;
18 | import java.util.Map;
19 |
20 | @SuppressWarnings("all")
21 | public class JunkCodeTransformer {
22 | private static final Logger logger = LogManager.getLogger();
23 |
24 | public static void transform(BaseConfig config) {
25 | for (Map.Entry entry : ObfEnv.classNameObfMapping.entrySet()) {
26 | String newName = entry.getValue();
27 | Path tempDir = Paths.get(Const.TEMP_DIR);
28 |
29 | if (ObfEnv.config.isUseSpringBoot()) {
30 | tempDir = tempDir.resolve("BOOT-INF/classes/");
31 | }
32 | if (ObfEnv.config.isUseWebWar()) {
33 | tempDir = tempDir.resolve("WEB-INF/classes/");
34 | }
35 |
36 | Path newClassPath = tempDir.resolve(Paths.get(newName + ".class"));
37 | if (!Files.exists(newClassPath)) {
38 | logger.debug("class not exist: {}", newClassPath.toString());
39 | continue;
40 | }
41 | try {
42 | ClassReader classReader = new ClassReader(Files.readAllBytes(newClassPath));
43 | CustomClassLoader loader = new CustomClassLoader();
44 | // COMPUTE_FRAMES 需要修改 CLASSLOADER 来计算
45 | ClassWriter classWriter = new CustomClassWriter(classReader,
46 | ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS, loader);
47 | JunkCodeVisitor changer = new JunkCodeVisitor(classWriter, config);
48 | try {
49 | classReader.accept(changer, Const.AnalyzeASMOptions);
50 | } catch (Exception ignored) {
51 | // CustomClassLoader 可能会找不到类
52 | // 这个地方目前做法是跳过这个类的花指令混淆
53 | logger.debug("花指令混淆使用自定义类加载器出现错误");
54 | continue;
55 | }
56 | Files.delete(newClassPath);
57 | Files.write(newClassPath, classWriter.toByteArray());
58 | } catch (MethodTooLargeException ex) {
59 | logger.error("method too large");
60 | logger.error("please check max junk config");
61 | return;
62 | } catch (Exception ex) {
63 | logger.error("transform error: {}", ex.toString());
64 | }
65 | }
66 | logger.info("junk code transform finish");
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/transform/MainClassTransformer.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.transform;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.asm.MainMethodVisitor;
5 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
6 | import me.n1ar4.log.LogManager;
7 | import me.n1ar4.log.Logger;
8 | import org.objectweb.asm.ClassReader;
9 |
10 | import java.nio.file.Files;
11 | import java.nio.file.Path;
12 | import java.nio.file.Paths;
13 | import java.util.Map;
14 |
15 | public class MainClassTransformer {
16 | private static final Logger logger = LogManager.getLogger();
17 |
18 | public static void transform() {
19 | for (Map.Entry entry : ObfEnv.classNameObfMapping.entrySet()) {
20 | try {
21 | String originalName = entry.getKey();
22 | Path tempDir = Paths.get(Const.TEMP_DIR);
23 |
24 | if (ObfEnv.config.isUseSpringBoot()) {
25 | tempDir = tempDir.resolve("BOOT-INF/classes/");
26 | }
27 | if (ObfEnv.config.isUseWebWar()) {
28 | tempDir = tempDir.resolve("WEB-INF/classes/");
29 | }
30 |
31 | Path classPath = tempDir.resolve(Paths.get(originalName + ".class"));
32 | byte[] classBytes = Files.readAllBytes(classPath);
33 | ClassReader classReader = new ClassReader(classBytes);
34 | MainMethodVisitor checker = new MainMethodVisitor();
35 | classReader.accept(checker, Const.AnalyzeASMOptions);
36 | if (checker.hasMainMethod()) {
37 | logger.info("find main class: {}", originalName);
38 | }
39 | } catch (Exception ex) {
40 | logger.error("transform error: {}", ex.toString());
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/transform/MethodNameTransformer.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.transform;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.asm.MethodNameVisitor;
5 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
6 | import me.n1ar4.log.LogManager;
7 | import me.n1ar4.log.Logger;
8 | import org.objectweb.asm.ClassReader;
9 | import org.objectweb.asm.ClassWriter;
10 |
11 | import java.nio.file.Files;
12 | import java.nio.file.Path;
13 | import java.nio.file.Paths;
14 | import java.util.Map;
15 |
16 | @SuppressWarnings("all")
17 | public class MethodNameTransformer {
18 | private static final Logger logger = LogManager.getLogger();
19 |
20 | public static void transform() {
21 | for (Map.Entry entry : ObfEnv.classNameObfMapping.entrySet()) {
22 | String newName = entry.getValue();
23 | Path tempDir = Paths.get(Const.TEMP_DIR);
24 |
25 | if (ObfEnv.config.isUseSpringBoot()) {
26 | tempDir = tempDir.resolve("BOOT-INF/classes/");
27 | }
28 | if (ObfEnv.config.isUseWebWar()) {
29 | tempDir = tempDir.resolve("WEB-INF/classes/");
30 | }
31 |
32 | Path newClassPath = tempDir.resolve(Paths.get(newName + ".class"));
33 | if (!Files.exists(newClassPath)) {
34 | logger.debug("class not exist: {}", newClassPath.toString());
35 | continue;
36 | }
37 | try {
38 | ClassReader classReader = new ClassReader(Files.readAllBytes(newClassPath));
39 | ClassWriter classWriter = new ClassWriter(classReader, 0);
40 | MethodNameVisitor changer = new MethodNameVisitor(classWriter);
41 | classReader.accept(changer, Const.AnalyzeASMOptions);
42 | Files.delete(newClassPath);
43 | Files.write(newClassPath, classWriter.toByteArray());
44 | } catch (Exception ex) {
45 | logger.error("transform error: {}", ex.toString());
46 | }
47 | }
48 | logger.info("rename method name finish");
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/transform/ParameterTransformer.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.transform;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.asm.ParameterVisitor;
5 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
6 | import me.n1ar4.log.LogManager;
7 | import me.n1ar4.log.Logger;
8 | import org.objectweb.asm.ClassReader;
9 | import org.objectweb.asm.ClassWriter;
10 |
11 | import java.nio.file.Files;
12 | import java.nio.file.Path;
13 | import java.nio.file.Paths;
14 | import java.util.Map;
15 |
16 | @SuppressWarnings("all")
17 | public class ParameterTransformer {
18 | private static final Logger logger = LogManager.getLogger();
19 |
20 | public static void transform() {
21 | for (Map.Entry entry : ObfEnv.classNameObfMapping.entrySet()) {
22 | String newName = entry.getValue();
23 | Path tempDir = Paths.get(Const.TEMP_DIR);
24 |
25 | if (ObfEnv.config.isUseSpringBoot()) {
26 | tempDir = tempDir.resolve("BOOT-INF/classes/");
27 | }
28 | if (ObfEnv.config.isUseWebWar()) {
29 | tempDir = tempDir.resolve("WEB-INF/classes/");
30 | }
31 |
32 | Path newClassPath = tempDir.resolve(Paths.get(newName + ".class"));
33 | if (!Files.exists(newClassPath)) {
34 | logger.debug("class not exist: {}", newClassPath.toString());
35 | continue;
36 | }
37 | try {
38 | ClassReader classReader = new ClassReader(Files.readAllBytes(newClassPath));
39 | ClassWriter classWriter = new ClassWriter(classReader, 0);
40 | ParameterVisitor changer = new ParameterVisitor(classWriter);
41 | classReader.accept(changer, Const.AnalyzeASMOptions);
42 | Files.delete(newClassPath);
43 | Files.write(newClassPath, classWriter.toByteArray());
44 | } catch (Exception ex) {
45 | logger.error("transform error: {}", ex.toString());
46 | }
47 | }
48 | logger.info("rename parameter name finish");
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/transform/StringArrayTransformer.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.transform;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.asm.StringArrayVisitor;
5 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
6 | import me.n1ar4.log.LogManager;
7 | import me.n1ar4.log.Logger;
8 | import org.objectweb.asm.ClassReader;
9 | import org.objectweb.asm.ClassWriter;
10 |
11 | import java.nio.file.Files;
12 | import java.nio.file.Path;
13 | import java.nio.file.Paths;
14 | import java.util.Map;
15 |
16 | @SuppressWarnings("all")
17 | public class StringArrayTransformer {
18 | private static final Logger logger = LogManager.getLogger();
19 | public static int INDEX = 0;
20 |
21 | public static void transform() {
22 | for (Map.Entry entry : ObfEnv.classNameObfMapping.entrySet()) {
23 | String newName = entry.getValue();
24 | Path tempDir = Paths.get(Const.TEMP_DIR);
25 |
26 | if (ObfEnv.config.isUseSpringBoot()) {
27 | tempDir = tempDir.resolve("BOOT-INF/classes/");
28 | }
29 | if (ObfEnv.config.isUseWebWar()) {
30 | tempDir = tempDir.resolve("WEB-INF/classes/");
31 | }
32 |
33 | Path newClassPath = tempDir.resolve(Paths.get(newName + ".class"));
34 | if (!Files.exists(newClassPath)) {
35 | logger.debug("class not exist: {}", newClassPath.toString());
36 | continue;
37 | }
38 | try {
39 | INDEX = 0;
40 | ClassReader classReader = new ClassReader(Files.readAllBytes(newClassPath));
41 | ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS);
42 | StringArrayVisitor changer = new StringArrayVisitor(classWriter);
43 | classReader.accept(changer, ClassReader.EXPAND_FRAMES);
44 | Files.delete(newClassPath);
45 | Files.write(newClassPath, classWriter.toByteArray());
46 | } catch (Exception ex) {
47 | ex.printStackTrace();
48 | logger.error("transform error: {}", ex.toString());
49 | }
50 | }
51 | logger.info("advance encrypt string finish");
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/transform/StringTransformer.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.transform;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.asm.StringVisitor;
5 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
6 | import me.n1ar4.log.LogManager;
7 | import me.n1ar4.log.Logger;
8 | import org.objectweb.asm.ClassReader;
9 | import org.objectweb.asm.ClassWriter;
10 |
11 | import java.nio.file.Files;
12 | import java.nio.file.Path;
13 | import java.nio.file.Paths;
14 | import java.util.Map;
15 |
16 | @SuppressWarnings("all")
17 | public class StringTransformer {
18 | private static final Logger logger = LogManager.getLogger();
19 |
20 | public static void transform() {
21 | for (Map.Entry entry : ObfEnv.classNameObfMapping.entrySet()) {
22 | String newName = entry.getValue();
23 | Path tempDir = Paths.get(Const.TEMP_DIR);
24 |
25 | if (ObfEnv.config.isUseSpringBoot()) {
26 | tempDir = tempDir.resolve("BOOT-INF/classes/");
27 | }
28 | if (ObfEnv.config.isUseWebWar()) {
29 | tempDir = tempDir.resolve("WEB-INF/classes/");
30 | }
31 |
32 | Path newClassPath = tempDir.resolve(Paths.get(newName + ".class"));
33 | if (!Files.exists(newClassPath)) {
34 | logger.debug("class not exist: {}", newClassPath.toString());
35 | continue;
36 | }
37 | try {
38 | ClassReader classReader = new ClassReader(Files.readAllBytes(newClassPath));
39 | ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS);
40 | StringVisitor changer = new StringVisitor(classWriter);
41 | classReader.accept(changer, Const.AnalyzeASMOptions);
42 | Files.delete(newClassPath);
43 | Files.write(newClassPath, classWriter.toByteArray());
44 | } catch (Exception ex) {
45 | logger.error("transform error: {}", ex.toString());
46 | }
47 | }
48 | logger.info("encrypt string finish");
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/transform/XORTransformer.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.transform;
2 |
3 | import me.n1ar4.jar.obfuscator.Const;
4 | import me.n1ar4.jar.obfuscator.asm.IntToXorVisitor;
5 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
6 | import me.n1ar4.log.LogManager;
7 | import me.n1ar4.log.Logger;
8 | import org.objectweb.asm.ClassReader;
9 | import org.objectweb.asm.ClassWriter;
10 |
11 | import java.nio.file.Files;
12 | import java.nio.file.Path;
13 | import java.nio.file.Paths;
14 | import java.util.Map;
15 |
16 | @SuppressWarnings("all")
17 | public class XORTransformer {
18 | private static final Logger logger = LogManager.getLogger();
19 |
20 | public static void transform() {
21 | for (Map.Entry entry : ObfEnv.classNameObfMapping.entrySet()) {
22 | String newName = entry.getValue();
23 | Path tempDir = Paths.get(Const.TEMP_DIR);
24 |
25 | if (ObfEnv.config.isUseSpringBoot()) {
26 | tempDir = tempDir.resolve("BOOT-INF/classes/");
27 | }
28 | if (ObfEnv.config.isUseWebWar()) {
29 | tempDir = tempDir.resolve("WEB-INF/classes/");
30 | }
31 |
32 | Path newClassPath = tempDir.resolve(Paths.get(newName + ".class"));
33 | if (!Files.exists(newClassPath)) {
34 | logger.debug("class not exist: {}", newClassPath.toString());
35 | continue;
36 | }
37 | try {
38 | ClassReader classReader = new ClassReader(Files.readAllBytes(newClassPath));
39 | ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS);
40 | IntToXorVisitor changer = new IntToXorVisitor(classWriter);
41 | classReader.accept(changer, Const.AnalyzeASMOptions);
42 | Files.delete(newClassPath);
43 | Files.write(newClassPath, classWriter.toByteArray());
44 | } catch (Exception ex) {
45 | logger.error("transform error: {}", ex.toString());
46 | }
47 | }
48 | logger.info("xor transform finish");
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/utils/ByteUtil.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.utils;
2 |
3 | /**
4 | * hex string < - > byte array
5 | */
6 | @SuppressWarnings("unused")
7 | public class ByteUtil {
8 | public static byte[] hexStringToByteArray(String s) {
9 | int len = s.length();
10 | byte[] data = new byte[len / 2];
11 | for (int i = 0; i < len; i += 2) {
12 | data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
13 | + Character.digit(s.charAt(i + 1), 16));
14 | }
15 | return data;
16 | }
17 |
18 | public static String bytesToHex(byte[] bytes) {
19 | StringBuilder sb = new StringBuilder();
20 | for (byte b : bytes) {
21 | sb.append(String.format("%02X", b));
22 | }
23 | return sb.toString();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/utils/ColorUtil.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.utils;
2 |
3 | public class ColorUtil {
4 | private static final String ANSI_RESET = "\033[0m";
5 | private static final String ANSI_RED = "\033[31m";
6 | private static final String ANSI_GREEN = "\033[32m";
7 | private static final String ANSI_BLUE = "\033[34m";
8 | private static final String ANSI_YELLOW = "\033[33m";
9 |
10 | public static String red(String input) {
11 | return ANSI_RED + input + ANSI_RESET;
12 | }
13 |
14 | public static String green(String input) {
15 | return ANSI_GREEN + input + ANSI_RESET;
16 | }
17 |
18 | public static String blue(String input) {
19 | return ANSI_BLUE + input + ANSI_RESET;
20 | }
21 |
22 | public static String yellow(String input) {
23 | return ANSI_YELLOW + input + ANSI_RESET;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/utils/DescUtil.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.utils;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.regex.Matcher;
6 | import java.util.regex.Pattern;
7 |
8 | public class DescUtil {
9 | public static List extractClassNames(String descriptor) {
10 | List classNames = new ArrayList<>();
11 | Pattern pattern = Pattern.compile("L([^;]+);");
12 | Matcher matcher = pattern.matcher(descriptor);
13 | while (matcher.find()) {
14 | classNames.add(matcher.group(1));
15 | }
16 | return classNames;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/utils/DirUtil.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.utils;
2 |
3 | import me.n1ar4.jar.obfuscator.core.ObfEnv;
4 | import me.n1ar4.log.LogManager;
5 | import me.n1ar4.log.Logger;
6 |
7 | import java.io.File;
8 | import java.io.FileInputStream;
9 | import java.io.FileOutputStream;
10 | import java.io.IOException;
11 | import java.nio.file.Files;
12 | import java.nio.file.Paths;
13 | import java.util.Map;
14 | import java.util.Objects;
15 | import java.util.zip.CRC32;
16 | import java.util.zip.ZipEntry;
17 | import java.util.zip.ZipInputStream;
18 | import java.util.zip.ZipOutputStream;
19 |
20 | public class DirUtil {
21 | private static final Logger logger = LogManager.getLogger();
22 |
23 | public static void unzip(String ZipFilePath, String destDir) throws IOException {
24 | File destDirectory = new File(destDir);
25 | if (!destDirectory.exists()) {
26 | boolean s = destDirectory.mkdirs();
27 | if (!s) {
28 | logger.warn("create dir {} error", destDirectory);
29 | }
30 | }
31 | ZipInputStream ZipInputStream = new ZipInputStream(Files.newInputStream(
32 | Paths.get(ZipFilePath)));
33 | ZipEntry ZipEntry;
34 | while ((ZipEntry = ZipInputStream.getNextEntry()) != null) {
35 | File file = new File(destDir, ZipEntry.getName());
36 | if (ZipEntry.isDirectory()) {
37 | boolean s = file.mkdirs();
38 | if (!s) {
39 | logger.warn("create dir {} error", destDirectory);
40 | }
41 | } else {
42 | // BUG FIX
43 | try {
44 | Files.createDirectories(Paths.get(file.getParent()));
45 | } catch (Exception ignored) {
46 | }
47 | byte[] buffer = new byte[1024];
48 | FileOutputStream fos;
49 | try {
50 | fos = new FileOutputStream(file);
51 | } catch (Exception ignored) {
52 | continue;
53 | }
54 | int bytesRead;
55 | while ((bytesRead = ZipInputStream.read(buffer)) != -1) {
56 | fos.write(buffer, 0, bytesRead);
57 | }
58 | fos.close();
59 | }
60 | ZipInputStream.closeEntry();
61 | }
62 | ZipInputStream.close();
63 | }
64 |
65 | public static void zip(String sourceDir, String outputZip) {
66 | File sourceFolder = new File(sourceDir);
67 | try (ZipOutputStream jos = new ZipOutputStream(Files.newOutputStream(Paths.get(outputZip)))) {
68 | // 设置压缩方法为 STORED(不压缩)
69 | jos.setMethod(ZipOutputStream.STORED);
70 |
71 | if (sourceFolder.exists() && sourceFolder.isDirectory()) {
72 | File[] files = sourceFolder.listFiles();
73 | if (files != null) {
74 | for (File file : files) {
75 | addToZip(file, jos, "");
76 | }
77 | }
78 | }
79 | } catch (IOException e) {
80 | System.err.println("zip Zip error: " + e.toString());
81 | }
82 | }
83 |
84 | public static void addToZip(File source, ZipOutputStream jos, String parentDir) throws IOException {
85 | if (source.isDirectory()) {
86 | String dirPath = parentDir + source.getName() + "/";
87 | ZipEntry entry = new ZipEntry(dirPath);
88 | entry.setMethod(ZipEntry.STORED);
89 | entry.setSize(0);
90 | entry.setCompressedSize(0);
91 | entry.setCrc(0);
92 | jos.putNextEntry(entry);
93 | jos.closeEntry();
94 | for (File file : Objects.requireNonNull(source.listFiles())) {
95 | addToZip(file, jos, dirPath);
96 | }
97 | } else {
98 | String entryName = parentDir + source.getName();
99 | ZipEntry entry = new ZipEntry(entryName);
100 | entry.setMethod(ZipEntry.STORED);
101 | long size = source.length();
102 | long crc = computeCRC32(source);
103 |
104 | entry.setSize(size);
105 | entry.setCompressedSize(size);
106 | entry.setCrc(crc);
107 | jos.putNextEntry(entry);
108 | try (FileInputStream fis = new FileInputStream(source)) {
109 | byte[] buffer = new byte[1024];
110 | int bytesRead;
111 | while ((bytesRead = fis.read(buffer)) != -1) {
112 | jos.write(buffer, 0, bytesRead);
113 | }
114 | }
115 | jos.closeEntry();
116 | }
117 | }
118 |
119 | private static long computeCRC32(File file) throws IOException {
120 | CRC32 crc = new CRC32();
121 | try (FileInputStream fis = new FileInputStream(file)) {
122 | byte[] buffer = new byte[1024];
123 | int bytesRead;
124 | while ((bytesRead = fis.read(buffer)) != -1) {
125 | crc.update(buffer, 0, bytesRead);
126 | }
127 | }
128 | return crc.getValue();
129 | }
130 | public static void deleteDirectory(File directory) {
131 | File[] files = directory.listFiles();
132 | if (files != null) {
133 | for (File file : files) {
134 | if (file.isDirectory()) {
135 | deleteDirectory(file);
136 | } else {
137 | boolean s = file.delete();
138 | if (!s) {
139 | logger.debug("delete dir {} error", file);
140 | }
141 | }
142 | }
143 | }
144 | boolean s = directory.delete();
145 | if (!s) {
146 | logger.debug("delete dir {} error", directory);
147 | }
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/utils/FileUtil.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.utils;
2 |
3 | import java.nio.file.Path;
4 |
5 | public class FileUtil {
6 | public static String getFileNameWithoutExt(Path path) {
7 | String fileName = path.getFileName().toString();
8 | int dotIndex = fileName.lastIndexOf('.');
9 | if (dotIndex > 0) {
10 | fileName = fileName.substring(0, dotIndex);
11 | }
12 | return fileName;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/utils/IOUtils.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.utils;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.util.ArrayList;
6 | import java.util.Arrays;
7 | import java.util.List;
8 |
9 | public class IOUtils {
10 | private static final int DEFAULT_BUFFER_SIZE = 8192;
11 | private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
12 |
13 | public static byte[] readAllBytes(InputStream is) throws IOException {
14 | return readNBytes(is, Integer.MAX_VALUE);
15 | }
16 |
17 | public static byte[] readNBytes(InputStream is, int len) throws IOException {
18 | if (len < 0) {
19 | throw new IllegalArgumentException("len < 0");
20 | }
21 | List bufs = null;
22 | byte[] result = null;
23 | int total = 0;
24 | int remaining = len;
25 | int n;
26 | do {
27 | byte[] buf = new byte[Math.min(remaining, DEFAULT_BUFFER_SIZE)];
28 | int nread = 0;
29 | while ((n = is.read(buf, nread,
30 | Math.min(buf.length - nread, remaining))) > 0) {
31 | nread += n;
32 | remaining -= n;
33 | }
34 |
35 | if (nread > 0) {
36 | if (MAX_BUFFER_SIZE - total < nread) {
37 | throw new OutOfMemoryError("Required array size too large");
38 | }
39 | total += nread;
40 | if (result == null) {
41 | result = buf;
42 | } else {
43 | if (bufs == null) {
44 | bufs = new ArrayList<>();
45 | bufs.add(result);
46 | }
47 | bufs.add(buf);
48 | }
49 | }
50 | } while (n == 0 && remaining > 0);
51 |
52 | if (bufs == null) {
53 | if (result == null) {
54 | return new byte[0];
55 | }
56 | return result.length == total ?
57 | result : Arrays.copyOf(result, total);
58 | }
59 |
60 | result = new byte[total];
61 | int offset = 0;
62 | remaining = total;
63 | for (byte[] b : bufs) {
64 | int count = Math.min(b.length, remaining);
65 | System.arraycopy(b, 0, result, offset, count);
66 | offset += count;
67 | remaining -= count;
68 | }
69 |
70 | return result;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/utils/JunkUtil.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.utils;
2 |
3 | import me.n1ar4.jrandom.core.JRandom;
4 | import org.objectweb.asm.ClassVisitor;
5 | import org.objectweb.asm.MethodVisitor;
6 | import org.objectweb.asm.Opcodes;
7 |
8 | public class JunkUtil {
9 | public static void addHttpCode(ClassVisitor cv) {
10 | MethodVisitor newMethod = cv.visitMethod(
11 | Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
12 | JRandom.getInstance().randomString(8),
13 | "()V", null, null);
14 | newMethod.visitCode();
15 | newMethod.visitTypeInsn(Opcodes.NEW, "java/net/URL");
16 | newMethod.visitInsn(Opcodes.DUP);
17 | newMethod.visitLdcInsn("https://" + JRandom.getInstance().randomString(16));
18 | newMethod.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/net/URL", "",
19 | "(Ljava/lang/String;)V", false);
20 | newMethod.visitVarInsn(Opcodes.ASTORE, 0);
21 | newMethod.visitVarInsn(Opcodes.ALOAD, 0);
22 | newMethod.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/net/URL", "openConnection",
23 | "()Ljava/net/URLConnection;", false);
24 | newMethod.visitTypeInsn(Opcodes.CHECKCAST, "java/net/HttpURLConnection");
25 | newMethod.visitVarInsn(Opcodes.ASTORE, 1);
26 | newMethod.visitVarInsn(Opcodes.ALOAD, 1);
27 | newMethod.visitLdcInsn("GET");
28 | newMethod.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/net/HttpURLConnection",
29 | "setRequestMethod", "(Ljava/lang/String;)V", false);
30 | newMethod.visitVarInsn(Opcodes.ALOAD, 1);
31 | newMethod.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/net/HttpURLConnection",
32 | "getResponseCode", "()I", false);
33 | newMethod.visitInsn(Opcodes.POP);
34 | newMethod.visitInsn(Opcodes.RETURN);
35 | newMethod.visitMaxs(3, 2);
36 | newMethod.visitEnd();
37 | }
38 | public static void addPrintMethod(ClassVisitor cv) {
39 | MethodVisitor newMethod = cv.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
40 | JRandom.getInstance().randomString(8), "()V", null, null);
41 | newMethod.visitCode();
42 | newMethod.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
43 | newMethod.visitLdcInsn(JRandom.getInstance().randomString(32));
44 | newMethod.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println",
45 | "(Ljava/lang/String;)V", false);
46 | newMethod.visitInsn(Opcodes.RETURN);
47 | newMethod.visitMaxs(2, 1);
48 | newMethod.visitEnd();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/utils/NameUtil.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.utils;
2 |
3 | import me.n1ar4.jrandom.core.JRandom;
4 |
5 | import java.util.HashSet;
6 |
7 | @SuppressWarnings("all")
8 | public class NameUtil {
9 | public static char[] CHAR_POOL = null;
10 | private static final HashSet generatedStrings = new HashSet<>();
11 | private static final HashSet generatedMethods = new HashSet<>();
12 | private static final HashSet generatedFields = new HashSet<>();
13 | private static final HashSet packageNames = new HashSet<>();
14 |
15 | public static String genNewName() {
16 | return genBase(1);
17 | }
18 |
19 | public static String genNewMethod() {
20 | return genBase(2);
21 | }
22 |
23 | public static String genNewFields() {
24 | return genBase(3);
25 | }
26 |
27 | public static String genPackage() {
28 | return genBase(4);
29 | }
30 |
31 | public static String genWithSet(HashSet exists) {
32 | JRandom random = JRandom.getInstance();
33 | while (true) {
34 | int length = 10 + random.getInt(0, 3);
35 | StringBuilder sb = new StringBuilder();
36 | for (int i = 0; i < length; i++) {
37 | sb.append(CHAR_POOL[random.getInt(0, CHAR_POOL.length)]);
38 | }
39 | if (sb.charAt(0) == '~' || sb.charAt(0) == '1') {
40 | continue;
41 | }
42 | String result = sb.toString();
43 | if (!exists.contains(result)) {
44 | exists.add(result);
45 | return result;
46 | }
47 | }
48 | }
49 |
50 | private static String genBase(int op) {
51 | JRandom random = JRandom.getInstance();
52 | while (true) {
53 | int length = 10 + random.getInt(0, 3);
54 | StringBuilder sb = new StringBuilder();
55 | for (int i = 0; i < length; i++) {
56 | sb.append(CHAR_POOL[random.getInt(0, CHAR_POOL.length)]);
57 | }
58 | if (sb.charAt(0) == '~' || sb.charAt(0) == '1') {
59 | continue;
60 | }
61 | String result = sb.toString();
62 | if (op == 2) {
63 | if (!generatedMethods.contains(result)) {
64 | generatedMethods.add(result);
65 | return result;
66 | }
67 | } else if (op == 1) {
68 | if (!generatedStrings.contains(result)) {
69 | generatedStrings.add(result);
70 | return result;
71 | }
72 | } else if (op == 3) {
73 | if (!generatedFields.contains(result)) {
74 | generatedFields.add(result);
75 | return result;
76 | }
77 | } else if (op == 4) {
78 | if (!packageNames.contains(result)) {
79 | packageNames.add(result);
80 | return result;
81 | }
82 | } else {
83 | return null;
84 | }
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/utils/PackageUtil.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.utils;
2 |
3 | import me.n1ar4.jar.obfuscator.base.ClassReference;
4 | import me.n1ar4.jar.obfuscator.base.MethodReference;
5 | import me.n1ar4.jar.obfuscator.config.BaseConfig;
6 | import me.n1ar4.jar.obfuscator.core.AnalyzeEnv;
7 | import org.objectweb.asm.Opcodes;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 | import java.util.Map;
12 | import java.util.regex.Matcher;
13 | import java.util.regex.Pattern;
14 |
15 | public class PackageUtil {
16 | private static final List internalList = new ArrayList<>();
17 |
18 | public static void buildInternalBlackList() {
19 | // JNI 的 CLASS 默认加到黑名单里面
20 | for (Map.Entry> entry :
21 | AnalyzeEnv.methodsInClassMap.entrySet()) {
22 | String className = entry.getKey().getName();
23 | List ref = entry.getValue();
24 | for (MethodReference m : ref) {
25 | int access = m.getAccess();
26 | if ((access & Opcodes.ACC_NATIVE) != 0) {
27 | internalList.add(className);
28 | break;
29 | }
30 | }
31 | }
32 | }
33 |
34 | public static boolean inBlackClass(String className, BaseConfig config) {
35 | className = className.replace(".", "/");
36 | for (String s : config.getClassBlackList()) {
37 | s = s.replace(".", "/");
38 | if (className.equals(s)) {
39 | return true;
40 | }
41 | }
42 | for (String s : config.getClassBlackRegexList()) {
43 | className = className.replace(".", "/");
44 | Pattern pattern = Pattern.compile(s, Pattern.DOTALL);
45 | Matcher matcher = pattern.matcher(className);
46 | if (matcher.matches()) {
47 | return true;
48 | }
49 | }
50 | for (String s : internalList) {
51 | s = s.replace(".", "/");
52 | if (className.equals(s)) {
53 | return true;
54 | }
55 | }
56 | return false;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jar/obfuscator/utils/RandomUtil.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jar.obfuscator.utils;
2 |
3 | import me.n1ar4.jrandom.core.JRandom;
4 | import org.objectweb.asm.Opcodes;
5 |
6 | public class RandomUtil {
7 | public static int genInt(int start, int end) {
8 | return JRandom.getInstance().getInt(start, end);
9 | }
10 |
11 | public static int genICONSTOpcode() {
12 | switch (RandomUtil.genInt(0, 6)) {
13 | case 0:
14 | return Opcodes.ICONST_0;
15 | case 1:
16 | return Opcodes.ICONST_1;
17 | case 2:
18 | return Opcodes.ICONST_2;
19 | case 3:
20 | return Opcodes.ICONST_3;
21 | case 4:
22 | return Opcodes.ICONST_4;
23 | case 5:
24 | return Opcodes.ICONST_5;
25 | default:
26 | return 0;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/jrandom/core/JRandom.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.jrandom.core;
2 |
3 | import me.n1ar4.log.LogManager;
4 | import me.n1ar4.log.Logger;
5 |
6 | import java.security.SecureRandom;
7 | import java.util.List;
8 |
9 | @SuppressWarnings("all")
10 | public class JRandom {
11 | private static final Logger logger = LogManager.getLogger();
12 | private static final String letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
13 | private static final String alphanumeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
14 |
15 | private final SecureRandom random = new SecureRandom();
16 |
17 | private static JRandom fakeInstance = null;
18 | private static JRandom instance;
19 |
20 | public static JRandom getInstance() {
21 | if (instance != null) {
22 | return instance;
23 | } else {
24 | if (fakeInstance == null) {
25 | logger.info("使用普通的随机数模块");
26 | fakeInstance = new JRandom(System.currentTimeMillis());
27 | return fakeInstance;
28 | } else {
29 | return fakeInstance;
30 | }
31 | }
32 | }
33 |
34 | public static void setInstance(JRandom in) {
35 | instance = in;
36 | }
37 |
38 | public JRandom(long seed) {
39 | random.setSeed(System.currentTimeMillis());
40 | }
41 |
42 | public JRandom() {
43 | random.setSeed(System.currentTimeMillis());
44 | }
45 |
46 | /**
47 | * 最底层的获得随机的函数
48 | *
49 | * @return 随机的 long 类型
50 | */
51 | private long getLong() {
52 | return random.nextLong();
53 | }
54 |
55 | /**
56 | * 获得任意的 INT
57 | *
58 | * @return 随机的 INT 范围
59 | */
60 | public int getInt() {
61 | long longValue = getLong();
62 | return (int) (longValue & 0xFFFFFFFFL);
63 | }
64 |
65 | /**
66 | * 左闭右开指定范围的随机
67 | *
68 | * @param start 左
69 | * @param end 右
70 | * @return 左闭右开的 INT 随机
71 | */
72 | public int getInt(int start, int end) {
73 | if (start >= end) {
74 | throw new IllegalArgumentException("start must be less than end");
75 | }
76 | long range = (long) end - (long) start;
77 | long longValue = getLong();
78 | int randomInRange = (int) (Math.abs(longValue) % range);
79 | return start + randomInRange;
80 | }
81 |
82 | /**
83 | * 获得指定长度的字符串(大小写字母和数字且开头不是数字)
84 | *
85 | * @param length 长度
86 | * @return 随即后的值
87 | */
88 | public String randomString(int length) {
89 | if (length <= 0) {
90 | throw new IllegalArgumentException("length must be greater than 0");
91 | }
92 | StringBuilder sb = new StringBuilder(length);
93 | int firstCharIndex = getInt(0, letters.length());
94 | sb.append(letters.charAt(firstCharIndex));
95 | for (int i = 1; i < length; i++) {
96 | int charIndex = getInt(0, alphanumeric.length());
97 | sb.append(alphanumeric.charAt(charIndex));
98 | }
99 | return sb.toString();
100 | }
101 |
102 | /**
103 | * 获得随机的 BYTES
104 | *
105 | * @param length 长度
106 | * @return 随机的 BYTES
107 | */
108 | public byte[] randomBytes(int length) {
109 | if (length <= 0) {
110 | throw new IllegalArgumentException("length must be greater than 0");
111 | }
112 | byte[] bytes = new byte[length];
113 | int index = 0;
114 | while (index < length) {
115 | int intValue = getInt();
116 | for (int i = 0; i < 4 && index < length; i++) {
117 | bytes[index++] = (byte) ((intValue >>> (i * 8)) & 0xFF);
118 | }
119 | }
120 | return bytes;
121 | }
122 |
123 | /**
124 | * 获得随机的列表元素
125 | *
126 | * @param list List
127 | * @param Object
128 | * @return 随机的
129 | */
130 | public T randomEle(List list) {
131 | if (list == null || list.isEmpty()) {
132 | throw new IllegalArgumentException("list must not be null or empty");
133 | }
134 | int index = getInt(0, list.size());
135 | return list.get(index);
136 | }
137 |
138 | /**
139 | * 获得随机的 INT 字符串
140 | *
141 | * @param n 长度
142 | * @return INT 字符串
143 | */
144 | public String randomNumbers(int n) {
145 | if (n <= 0) {
146 | throw new IllegalArgumentException("length must be greater than 0");
147 | }
148 | StringBuilder sb = new StringBuilder(n);
149 | for (int i = 0; i < n; i++) {
150 | int digit = getInt(0, 10);
151 | sb.append(digit);
152 | }
153 | return sb.toString();
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/log/Log.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.log;
2 |
3 | import java.time.LocalDateTime;
4 | import java.time.format.DateTimeFormatter;
5 |
6 | class Log {
7 | static final String ANSI_RESET = "\u001B[0m";
8 | static final String ANSI_GREEN = "\u001B[32m";
9 | static final String ANSI_YELLOW = "\u001B[33m";
10 | static final String ANSI_RED = "\u001B[31m";
11 | static final String ANSI_BLUE = "\u001B[34m";
12 |
13 | static void info(String message) {
14 | log(LogLevel.INFO, message, ANSI_GREEN);
15 | }
16 |
17 | static void error(String message) {
18 | log(LogLevel.ERROR, message, ANSI_RED);
19 | }
20 |
21 | static void debug(String message) {
22 | log(LogLevel.DEBUG, message, ANSI_BLUE);
23 | }
24 |
25 | static void warn(String message) {
26 | log(LogLevel.WARN, message, ANSI_YELLOW);
27 | }
28 |
29 | static void log(LogLevel level, String message, String color) {
30 | if (level.compareTo(LogManager.logLevel) >= 0) {
31 | String timestamp = LocalDateTime.now().format(
32 | DateTimeFormatter.ofPattern("HH:mm:ss"));
33 | String className = LogUtil.getClassName();
34 | String methodName = LogUtil.getMethodName();
35 | String lineNumber = LogUtil.getLineNumber();
36 | String logMessage;
37 | if (!lineNumber.equals("-1")) {
38 | logMessage = String.format("[%s] [%s%s%s] [%s:%s:%s] %s",
39 | timestamp, color, level.name(), ANSI_RESET, className,
40 | methodName, lineNumber, message);
41 | } else {
42 | logMessage = String.format("[%s] [%s%s%s] [%s:%s] %s",
43 | timestamp, color, level.name(), ANSI_RESET, className,
44 | methodName, message);
45 | }
46 | System.out.println(logMessage);
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/log/LogLevel.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.log;
2 |
3 | public enum LogLevel {
4 | DEBUG,
5 | INFO,
6 | WARN,
7 | ERROR,
8 | }
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/log/LogManager.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.log;
2 |
3 | public class LogManager {
4 | static LogLevel logLevel = LogLevel.INFO;
5 |
6 | public static void setLevel(LogLevel level) {
7 | logLevel = level;
8 | }
9 |
10 | public static Logger getLogger() {
11 | return new Logger();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/log/LogUtil.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.log;
2 |
3 | public class LogUtil {
4 | private static final int STACK_TRACE_INDEX = 5;
5 |
6 | public static String getClassName() {
7 | String fullClassName = Thread.currentThread()
8 | .getStackTrace()[STACK_TRACE_INDEX].getClassName();
9 | int lastDotIndex = fullClassName.lastIndexOf('.');
10 | if (lastDotIndex != -1) {
11 | return fullClassName.substring(lastDotIndex + 1);
12 | } else {
13 | return fullClassName;
14 | }
15 | }
16 |
17 | public static String getMethodName() {
18 | return Thread.currentThread()
19 | .getStackTrace()[STACK_TRACE_INDEX].getMethodName();
20 | }
21 |
22 | public static String getLineNumber() {
23 | return String.valueOf(Thread.currentThread()
24 | .getStackTrace()[STACK_TRACE_INDEX].getLineNumber());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/log/Logger.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.log;
2 |
3 |
4 | public class Logger {
5 | private String formatMessage(String message, Object[] args) {
6 | int start = 0;
7 | StringBuilder sb = new StringBuilder();
8 | int argIndex = 0;
9 | while (start < message.length()) {
10 | int open = message.indexOf("{}", start);
11 | if (open == -1) {
12 | sb.append(message.substring(start));
13 | break;
14 | }
15 | sb.append(message, start, open);
16 | if (argIndex < args.length) {
17 | sb.append(args[argIndex++]);
18 | } else {
19 | sb.append("{}");
20 | }
21 | start = open + 2;
22 | }
23 | return sb.toString();
24 | }
25 |
26 | public void info(String message) {
27 | Log.info(message);
28 | }
29 |
30 | public void info(String message, Object... args) {
31 | Log.info(formatMessage(message, args));
32 | }
33 |
34 | public void error(String message) {
35 | Log.error(message);
36 | }
37 |
38 | public void error(String message, Object... args) {
39 | Log.error(formatMessage(message, args));
40 | }
41 |
42 | public void debug(String message) {
43 | Log.debug(message);
44 | }
45 |
46 | public void debug(String message, Object... args) {
47 | Log.debug(formatMessage(message, args));
48 | }
49 |
50 | public void warn(String message) {
51 | Log.warn(message);
52 | }
53 |
54 | public void warn(String message, Object... args) {
55 | Log.warn(formatMessage(message, args));
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/me/n1ar4/log/LoggingStream.java:
--------------------------------------------------------------------------------
1 | package me.n1ar4.log;
2 |
3 | import java.io.IOException;
4 | import java.io.OutputStream;
5 | import java.io.PrintStream;
6 |
7 | public class LoggingStream extends PrintStream {
8 | private final Logger logger;
9 | private final OutputStream originalOut;
10 |
11 | public LoggingStream(OutputStream out, Logger logger) {
12 | super(out);
13 | this.logger = logger;
14 | this.originalOut = out;
15 | }
16 |
17 | @Override
18 | public void println(String x) {
19 | if (!isLoggerCall()) {
20 | logger.info(x);
21 | } else {
22 | directPrintln(x);
23 | }
24 | }
25 |
26 | private boolean isLoggerCall() {
27 | for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
28 | if (element.getClassName().equals("me.n1ar4.log.Logger")) {
29 | return true;
30 | }
31 | }
32 | return false;
33 | }
34 |
35 | private void directPrintln(String x) {
36 | synchronized (this) {
37 | byte[] bytes = (x + System.lineSeparator()).getBytes();
38 | try {
39 | originalOut.write(bytes);
40 | originalOut.flush();
41 | } catch (IOException e) {
42 | setError();
43 | }
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/src/main/resources/config.yaml:
--------------------------------------------------------------------------------
1 | # jar obfuscator v2 配置文件
2 | # jar obfuscator v2 by jar-analyzer team (4ra1n)
3 | # https://github.com/jar-analyzer/jar-obfuscator
4 |
5 | # 日志级别
6 | # debug info warn error
7 | logLevel: info
8 |
9 | # 如果你是 springboot 请开启
10 | useSpringBoot: false
11 | # 如果你是 war web 项目请开启
12 | useWebWar: false
13 |
14 | # 混淆字符配置
15 | # 类名方法名等信息会根据字符进行随机排列组合
16 | obfuscateChars:
17 | - "i"
18 | - "l"
19 | - "L"
20 | - "1"
21 | - "I"
22 | # 不对某些类做混淆(不混淆其中的所有内容)
23 | # 通常情况必须加入 main 入口
24 | classBlackList:
25 | - "com.test.Main"
26 | # 不对指定正则的类进行混淆
27 | # 注意这里的类名匹配是 java/lang/String 而不是 java.lang.String
28 | # 该配置和 classBlackList 同时生效
29 | classBlackRegexList:
30 | - "java/.*"
31 | - "com/intellij/.*"
32 | # 不对某些 method 名做混淆 正则
33 | # visit.* 忽略 JAVA ASM 的 visitCode visitMethod 等方法
34 | # start.* 忽略 JAVAFX 因为启动基于 start 方法
35 | # 以此类推某些方法和类是不能混淆的(类继承和接口实现等)
36 | methodBlackList:
37 | - "visit.*"
38 | - "start.*"
39 |
40 | # 开启类名混淆
41 | enableClassName: true
42 | # 开启包名混淆
43 | enablePackageName: true
44 | # 开启方法名混淆
45 | enableMethodName: true
46 | # 开启字段混淆
47 | enableFieldName: true
48 | # 开启参数名混淆
49 | enableParamName: true
50 | # 开启数字异或混淆
51 | enableXOR: true
52 |
53 | # 开启加密字符串
54 | enableEncryptString: true
55 | # 加密使用 AES KEY
56 | # 注意长度必须是 16 且不包含中文
57 | stringAesKey: Y4SuperSecretKey
58 | # 开启进阶字符串混淆
59 | enableAdvanceString: true
60 | # 进阶字符串处理参数
61 | advanceStringName: GIiIiLA
62 | # 字符串解密类名
63 | decryptClassName: org.apache.commons.collections.list.AbstractHashMap
64 | # 字符串解密方法名
65 | decryptMethodName: newMap
66 | # 字符串 AES KEY 名字
67 | decryptKeyName: LiLiLLLiiiLLiiLLi
68 |
69 | # 是否隐藏方法
70 | enableHideMethod: true
71 | # 是否隐藏字段
72 | enableHideField: true
73 |
74 | # 开启删除编译信息选项
75 | enableDeleteCompileInfo: true
76 |
77 | # 开启花指令混淆
78 | enableJunk: true
79 | # 花指令级别
80 | # 最低1 最高5
81 | # 使用 3 以上会生成垃圾方法
82 | junkLevel: 5
83 | # 一个类中的花指令数量上限
84 | maxJunkOneClass: 2000
85 |
86 | # 是否打印所有主函数
87 | showAllMainMethods: true
88 |
89 | # 是否保留临时类文件
90 | keepTempFile: false
--------------------------------------------------------------------------------
/src/main/resources/thanks.txt:
--------------------------------------------------------------------------------
1 | 4ra1n (https://github.com/4ra1n)
2 | pcdlrzxx (https://github.com/pcdlrzxx)
3 | hadis91 (https://github.com/hadis91)
4 | Y4tacker (https://github.com/Y4tacker)
--------------------------------------------------------------------------------
/test/README.md:
--------------------------------------------------------------------------------
1 | ## TEST
2 |
3 | test-01: 仅开启 class 混淆
4 | test-02: 开启 class package 混淆
5 | test-03: 基础混淆全开
--------------------------------------------------------------------------------
/test/origin.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jar-analyzer/jar-obfuscator/9d12c8c12562cffbc73875f771397c143ac1d74e/test/origin.jar
--------------------------------------------------------------------------------
/test/shiro.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jar-analyzer/jar-obfuscator/9d12c8c12562cffbc73875f771397c143ac1d74e/test/shiro.jar
--------------------------------------------------------------------------------
/test/test-01.yaml:
--------------------------------------------------------------------------------
1 | logLevel: info
2 | useSpringBoot: false
3 | useWebWar: false
4 | obfuscateChars:
5 | - "i"
6 | - "l"
7 | - "L"
8 | - "1"
9 | - "I"
10 | classBlackList:
11 | - "me.n1ar4.fake.gui.Application"
12 | classBlackRegexList:
13 | - "java.*"
14 | - "javax.*"
15 | - "kotlin.*"
16 | - "net.*"
17 | - "okhttp3.*"
18 | - "okio.*"
19 | - "org.*"
20 | - "com.*"
21 | - "edu.*"
22 | - "javassist.*"
23 | methodBlackList:
24 | - "visit.*"
25 | - "start.*"
26 |
27 | enableClassName: true
28 | enablePackageName: false
29 | enableMethodName: false
30 | enableFieldName: false
31 | enableParamName: false
32 | enableXOR: false
33 |
34 | enableEncryptString: false
35 | stringAesKey: Y4SuperSecretKey
36 | enableAdvanceString: false
37 | advanceStringName: GIiIiLA
38 | decryptClassName: org.apache.commons.collections.list.AbstractHashMap
39 | decryptMethodName: newMap
40 | decryptKeyName: LiLiLLLiiiLLiiLLi
41 |
42 | enableHideMethod: false
43 | enableHideField: false
44 | enableDeleteCompileInfo: false
45 |
46 | enableJunk: false
47 | junkLevel: 5
48 | maxJunkOneClass: 2000
49 |
50 | showAllMainMethods: false
51 | keepTempFile: false
--------------------------------------------------------------------------------
/test/test-02.yaml:
--------------------------------------------------------------------------------
1 | logLevel: info
2 | useSpringBoot: false
3 | useWebWar: false
4 | obfuscateChars:
5 | - "i"
6 | - "l"
7 | - "L"
8 | - "1"
9 | - "I"
10 | classBlackList:
11 | - "me.n1ar4.fake.gui.Application"
12 | classBlackRegexList:
13 | - "java.*"
14 | - "javax.*"
15 | - "kotlin.*"
16 | - "net.*"
17 | - "okhttp3.*"
18 | - "okio.*"
19 | - "org.*"
20 | - "com.*"
21 | - "edu.*"
22 | - "javassist.*"
23 | methodBlackList:
24 | - "visit.*"
25 | - "start.*"
26 |
27 | enableClassName: true
28 | enablePackageName: true
29 | enableMethodName: false
30 | enableFieldName: false
31 | enableParamName: false
32 | enableXOR: false
33 |
34 | enableEncryptString: false
35 | stringAesKey: Y4SuperSecretKey
36 | enableAdvanceString: false
37 | advanceStringName: GIiIiLA
38 | decryptClassName: org.apache.commons.collections.list.AbstractHashMap
39 | decryptMethodName: newMap
40 | decryptKeyName: LiLiLLLiiiLLiiLLi
41 |
42 | enableHideMethod: false
43 | enableHideField: false
44 | enableDeleteCompileInfo: false
45 |
46 | enableJunk: false
47 | junkLevel: 5
48 | maxJunkOneClass: 2000
49 |
50 | showAllMainMethods: false
51 | keepTempFile: false
--------------------------------------------------------------------------------
/test/test-03.yaml:
--------------------------------------------------------------------------------
1 | logLevel: info
2 | useSpringBoot: false
3 | useWebWar: false
4 | obfuscateChars:
5 | - "i"
6 | - "l"
7 | - "L"
8 | - "1"
9 | - "I"
10 | classBlackList:
11 | - "me.n1ar4.fake.gui.Application"
12 | classBlackRegexList:
13 | - "java.*"
14 | - "javax.*"
15 | - "kotlin.*"
16 | - "net.*"
17 | - "okhttp3.*"
18 | - "okio.*"
19 | - "org.*"
20 | - "com.*"
21 | - "edu.*"
22 | - "javassist.*"
23 | methodBlackList:
24 | - "visit.*"
25 | - "start.*"
26 |
27 | enableClassName: true
28 | enablePackageName: true
29 | enableMethodName: true
30 | enableFieldName: true
31 | enableParamName: true
32 | enableXOR: true
33 |
34 | enableEncryptString: false
35 | stringAesKey: Y4SuperSecretKey
36 | enableAdvanceString: false
37 | advanceStringName: GIiIiLA
38 | decryptClassName: org.apache.commons.collections.list.AbstractHashMap
39 | decryptMethodName: newMap
40 | decryptKeyName: LiLiLLLiiiLLiiLLi
41 |
42 | enableHideMethod: false
43 | enableHideField: false
44 | enableDeleteCompileInfo: false
45 |
46 | enableJunk: false
47 | junkLevel: 5
48 | maxJunkOneClass: 2000
49 |
50 | showAllMainMethods: false
51 | keepTempFile: false
--------------------------------------------------------------------------------
/test/test-sb-01.yaml:
--------------------------------------------------------------------------------
1 | logLevel: info
2 | useSpringBoot: true
3 | useWebWar: false
4 | obfuscateChars:
5 | - "i"
6 | - "l"
7 | - "L"
8 | - "1"
9 | - "I"
10 | classBlackList:
11 | - "com.example.shiro.ShiroApplication"
12 | classBlackRegexList:
13 | - "java.*"
14 | - "javax.*"
15 | - "kotlin.*"
16 | - "net.*"
17 | - "okhttp3.*"
18 | - "okio.*"
19 | - "org.*"
20 | - "edu.*"
21 | - "javassist.*"
22 | methodBlackList:
23 | - "visit.*"
24 | - "start.*"
25 |
26 | enableClassName: true
27 | enablePackageName: false
28 | enableMethodName: false
29 | enableFieldName: false
30 | enableParamName: false
31 | enableXOR: false
32 |
33 | enableEncryptString: false
34 | stringAesKey: Y4SuperSecretKey
35 | enableAdvanceString: false
36 | advanceStringName: GIiIiLA
37 | decryptClassName: org.apache.commons.collections.list.AbstractHashMap
38 | decryptMethodName: newMap
39 | decryptKeyName: LiLiLLLiiiLLiiLLi
40 |
41 | enableHideMethod: false
42 | enableHideField: false
43 | enableDeleteCompileInfo: false
44 |
45 | enableJunk: false
46 | junkLevel: 5
47 | maxJunkOneClass: 2000
48 |
49 | showAllMainMethods: false
50 | keepTempFile: false
--------------------------------------------------------------------------------
/test/test-sb-02.yaml:
--------------------------------------------------------------------------------
1 | logLevel: info
2 | useSpringBoot: true
3 | useWebWar: false
4 | obfuscateChars:
5 | - "i"
6 | - "l"
7 | - "L"
8 | - "1"
9 | - "I"
10 | classBlackList:
11 | - "com.example.shiro.ShiroApplication"
12 | classBlackRegexList:
13 | - "java.*"
14 | - "javax.*"
15 | - "kotlin.*"
16 | - "net.*"
17 | - "okhttp3.*"
18 | - "okio.*"
19 | - "org.*"
20 | - "edu.*"
21 | - "javassist.*"
22 | methodBlackList:
23 | - "doGetAuthorizationInfo"
24 | - "doGetAuthenticationInfo"
25 |
26 | enableClassName: true
27 | enablePackageName: false
28 | enableMethodName: true
29 | enableFieldName: true
30 | enableParamName: true
31 | enableXOR: true
32 |
33 | enableEncryptString: true
34 | stringAesKey: Y4SuperSecretKey
35 | enableAdvanceString: true
36 | advanceStringName: GIiIiLA
37 | decryptClassName: org.apache.commons.collections.list.AbstractHashMap
38 | decryptMethodName: newMap
39 | decryptKeyName: LiLiLLLiiiLLiiLLi
40 |
41 | enableHideMethod: false
42 | enableHideField: false
43 | enableDeleteCompileInfo: false
44 |
45 | enableJunk: true
46 | junkLevel: 5
47 | maxJunkOneClass: 2000
48 |
49 | showAllMainMethods: false
50 | keepTempFile: false
--------------------------------------------------------------------------------