修复和优化了多个问题
This commit is contained in:
19
CHANGELOG.MD
19
CHANGELOG.MD
@@ -1,5 +1,24 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 1.5.0
|
||||
|
||||
从该版本开始,运行混淆会自动创建一个 `class-obf-lib` 目录
|
||||
|
||||
用户如果遇到依赖报错,可以将混淆 `class` 需要的依赖 `jar` 放入该目录解决报错问题
|
||||
|
||||
更新日志:
|
||||
|
||||
- [重要] 解决某些情况下需要正确依赖才能运行的 `BUG`
|
||||
- [优化] 生成 `AES` 字符串解密方法时避免抛出异常
|
||||
- [优化] 提高解密方法内的 `Basse64` 解码兼容性
|
||||
|
||||
感谢以下用户的贡献:
|
||||
|
||||
- 4ra1n (https://github.com/4ra1n)
|
||||
- lz520520 (https://github.com/lz520520)
|
||||
|
||||
可供下载的文件都由 `Github Actions` 构建,使用 `java -jar class-obf.jar` 启动
|
||||
|
||||
## 1.4.0
|
||||
|
||||
支持将 `INVOKE*` 指令转为反射调用,结合其他配置可完成进阶混淆
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
|
||||

|
||||
|
||||
从 `1.5.0` 版本解决了缺少依赖的问题,如果你混淆时遇到报错找不到某些依赖类:
|
||||
|
||||
请将依赖的 `jar` 文件都放在当前目录下的 `class-obf-lib` 目录(会自动生成)
|
||||
|
||||
## 背景
|
||||
|
||||
`jar-analyzer` 系列曾有一款工具 `jar-obfuscator` 实现 `jar` 包的混淆
|
||||
|
||||
5
class-obf-lib/README.md
Normal file
5
class-obf-lib/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# README
|
||||
|
||||
一些情况下混淆可能需要接触依赖库
|
||||
|
||||
请将依赖放在 `class-obf-lib` 目录中
|
||||
@@ -7,6 +7,7 @@ import me.n1ar4.clazz.obfuscator.base.ClassReference;
|
||||
import me.n1ar4.clazz.obfuscator.base.MethodReference;
|
||||
import me.n1ar4.clazz.obfuscator.config.BaseCmd;
|
||||
import me.n1ar4.clazz.obfuscator.config.BaseConfig;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassLoader;
|
||||
import me.n1ar4.clazz.obfuscator.transform.*;
|
||||
import me.n1ar4.clazz.obfuscator.utils.ASMUtil;
|
||||
import me.n1ar4.clazz.obfuscator.utils.ColorUtil;
|
||||
@@ -16,6 +17,7 @@ import me.n1ar4.log.LogManager;
|
||||
import me.n1ar4.log.Logger;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
@@ -55,6 +57,19 @@ public class Runner {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
Path dirPath = Paths.get(CustomClassLoader.LIB_DIR);
|
||||
try {
|
||||
Files.createDirectory(dirPath);
|
||||
logger.info("已成功创建 {} 目录", CustomClassLoader.LIB_DIR);
|
||||
Files.write(dirPath.resolve(Paths.get("README.md")), ("# README\n" +
|
||||
"\n" +
|
||||
"一些情况下混淆可能需要接触依赖库\n" +
|
||||
"\n" +
|
||||
"请将依赖放在 `class-obf-lib` 目录中").getBytes(StandardCharsets.UTF_8));
|
||||
} catch (Exception ignored) {
|
||||
logger.warn("无法创建 {} 目录", CustomClassLoader.LIB_DIR);
|
||||
}
|
||||
|
||||
addClass(path);
|
||||
logger.info("add the input class to analyze");
|
||||
|
||||
@@ -201,51 +216,53 @@ public class Runner {
|
||||
ColorUtil.blue("#################################################################"));
|
||||
}
|
||||
|
||||
CustomClassLoader loader = new CustomClassLoader();
|
||||
|
||||
if (config.isEnableReflect()) {
|
||||
ReflectTransformer.transform();
|
||||
ReflectTransformer.transform(loader);
|
||||
logger.info("run reflect transformer finish");
|
||||
}
|
||||
|
||||
if (config.isEnableDeleteCompileInfo()) {
|
||||
DeleteInfoTransformer.transform();
|
||||
DeleteInfoTransformer.transform(loader);
|
||||
logger.info("run delete info transformer finish");
|
||||
}
|
||||
|
||||
if (config.isEnableMethodName()) {
|
||||
MethodNameTransformer.transform();
|
||||
MethodNameTransformer.transform(loader);
|
||||
logger.info("run method name transformer finish");
|
||||
}
|
||||
|
||||
if (config.isEnableFieldName()) {
|
||||
FieldNameTransformer.transform();
|
||||
FieldNameTransformer.transform(loader);
|
||||
logger.info("run field name transformer finish");
|
||||
}
|
||||
|
||||
if (config.isEnableParamName()) {
|
||||
ParameterTransformer.transform();
|
||||
ParameterTransformer.transform(loader);
|
||||
logger.info("run parameter transformer finish");
|
||||
}
|
||||
|
||||
if (config.isEnableXOR()) {
|
||||
XORTransformer.transform();
|
||||
XORTransformer.transform(loader);
|
||||
logger.info("run xor transformer finish");
|
||||
}
|
||||
|
||||
if (config.isEnableAdvanceString()) {
|
||||
StringArrayTransformer.transform();
|
||||
StringArrayTransformer.transform(loader);
|
||||
if (config.isEnableXOR()) {
|
||||
XORTransformer.transform();
|
||||
XORTransformer.transform(loader);
|
||||
}
|
||||
logger.info("run string array transformer finish");
|
||||
}
|
||||
|
||||
if (config.isEnableAES()) {
|
||||
StringEncryptTransformer.transform(config.getAesKey(), config.getAesDecName());
|
||||
StringEncryptTransformer.transform(config.getAesKey(), config.getAesDecName(), loader);
|
||||
logger.info("run string aes transformer finish");
|
||||
}
|
||||
|
||||
if (config.isEnableJunk()) {
|
||||
JunkCodeTransformer.transform(config);
|
||||
JunkCodeTransformer.transform(config, loader);
|
||||
logger.info("run junk transformer finish");
|
||||
}
|
||||
if (!config.isQuiet()) {
|
||||
|
||||
@@ -1,24 +1,64 @@
|
||||
package me.n1ar4.clazz.obfuscator.loader;
|
||||
|
||||
import me.n1ar4.clazz.obfuscator.Const;
|
||||
import me.n1ar4.log.LogManager;
|
||||
import me.n1ar4.log.Logger;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
public class CustomClassLoader extends ClassLoader {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
public static final String LIB_DIR = "class-obf-lib";
|
||||
|
||||
@Override
|
||||
public Class<?> findClass(String name) {
|
||||
byte[] b = loadClassData();
|
||||
if (b != null) {
|
||||
return defineClass(name, b, 0, b.length);
|
||||
byte[] classData = loadClassData(name);
|
||||
if (classData != null) {
|
||||
return defineClass(name, classData, 0, classData.length);
|
||||
}
|
||||
logger.warn("not found class: " + name);
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[] loadClassData() {
|
||||
try {
|
||||
return Files.readAllBytes(Const.TEMP_PATH);
|
||||
} catch (Exception ignored) {
|
||||
private byte[] loadClassData(String className) {
|
||||
File libDir = new File(LIB_DIR);
|
||||
if (!libDir.exists() || !libDir.isDirectory()) {
|
||||
return null;
|
||||
}
|
||||
File[] jarFiles = libDir.listFiles((dir, name) -> name.endsWith(".jar"));
|
||||
if (jarFiles == null) {
|
||||
return null;
|
||||
}
|
||||
for (File jarFile : jarFiles) {
|
||||
try (JarFile jar = new JarFile(jarFile)) {
|
||||
Enumeration<JarEntry> entries = jar.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
if (entry.getName().endsWith(".class")) {
|
||||
String entryClassName = entry.getName().replace("/", ".")
|
||||
.replace(".class", "");
|
||||
if (entryClassName.equals(className)) {
|
||||
try (InputStream inputStream = jar.getInputStream(entry);
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("load class error: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package me.n1ar4.clazz.obfuscator.transform;
|
||||
import me.n1ar4.clazz.obfuscator.Const;
|
||||
import me.n1ar4.clazz.obfuscator.asm.CompileInfoClassVisitor;
|
||||
import me.n1ar4.clazz.obfuscator.core.ObfEnv;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassLoader;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassWriter;
|
||||
import me.n1ar4.log.LogManager;
|
||||
import me.n1ar4.log.Logger;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
@@ -14,7 +16,7 @@ import java.nio.file.Path;
|
||||
public class DeleteInfoTransformer {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
||||
public static void transform() {
|
||||
public static void transform(CustomClassLoader loader) {
|
||||
Path classPath = Const.TEMP_PATH;
|
||||
if (!Files.exists(classPath)) {
|
||||
logger.error("class not exist: {}", classPath.toString());
|
||||
@@ -22,8 +24,8 @@ public class DeleteInfoTransformer {
|
||||
}
|
||||
try {
|
||||
ClassReader classReader = new ClassReader(Files.readAllBytes(classPath));
|
||||
ClassWriter classWriter = new ClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0);
|
||||
ClassWriter classWriter = new CustomClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0, loader);
|
||||
CompileInfoClassVisitor changer = new CompileInfoClassVisitor(classWriter);
|
||||
classReader.accept(changer, Const.ReaderASMOptions);
|
||||
Files.delete(classPath);
|
||||
|
||||
@@ -3,6 +3,8 @@ package me.n1ar4.clazz.obfuscator.transform;
|
||||
import me.n1ar4.clazz.obfuscator.Const;
|
||||
import me.n1ar4.clazz.obfuscator.asm.FieldNameClassVisitor;
|
||||
import me.n1ar4.clazz.obfuscator.core.ObfEnv;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassLoader;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassWriter;
|
||||
import me.n1ar4.log.LogManager;
|
||||
import me.n1ar4.log.Logger;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
@@ -15,7 +17,7 @@ import java.nio.file.Path;
|
||||
public class FieldNameTransformer {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
||||
public static void transform() {
|
||||
public static void transform(CustomClassLoader loader) {
|
||||
Path newClassPath = Const.TEMP_PATH;
|
||||
if (!Files.exists(newClassPath)) {
|
||||
logger.error("class not exist: {}", newClassPath.toString());
|
||||
@@ -23,8 +25,8 @@ public class FieldNameTransformer {
|
||||
}
|
||||
try {
|
||||
ClassReader classReader = new ClassReader(Files.readAllBytes(newClassPath));
|
||||
ClassWriter classWriter = new ClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0);
|
||||
ClassWriter classWriter = new CustomClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0, loader);
|
||||
FieldNameClassVisitor changer = new FieldNameClassVisitor(classWriter);
|
||||
classReader.accept(changer, Const.ReaderASMOptions);
|
||||
Files.delete(newClassPath);
|
||||
|
||||
@@ -19,7 +19,7 @@ import java.nio.file.Path;
|
||||
public class JunkCodeTransformer {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
||||
public static void transform(BaseConfig config) {
|
||||
public static void transform(BaseConfig config, CustomClassLoader loader) {
|
||||
Path newClassPath = Const.TEMP_PATH;
|
||||
if (!Files.exists(newClassPath)) {
|
||||
logger.error("class not exist: {}", newClassPath.toString());
|
||||
@@ -27,8 +27,6 @@ public class JunkCodeTransformer {
|
||||
}
|
||||
try {
|
||||
ClassReader classReader = new ClassReader(Files.readAllBytes(newClassPath));
|
||||
CustomClassLoader loader = new CustomClassLoader();
|
||||
// COMPUTE_FRAMES 需要修改 CLASSLOADER 来计算
|
||||
ClassWriter classWriter = new CustomClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0, loader);
|
||||
JunkCodeClassVisitor changer = new JunkCodeClassVisitor(classWriter, config);
|
||||
|
||||
@@ -3,6 +3,8 @@ package me.n1ar4.clazz.obfuscator.transform;
|
||||
import me.n1ar4.clazz.obfuscator.Const;
|
||||
import me.n1ar4.clazz.obfuscator.asm.MethodNameClassVisitor;
|
||||
import me.n1ar4.clazz.obfuscator.core.ObfEnv;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassLoader;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassWriter;
|
||||
import me.n1ar4.log.LogManager;
|
||||
import me.n1ar4.log.Logger;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
@@ -15,7 +17,7 @@ import java.nio.file.Path;
|
||||
public class MethodNameTransformer {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
||||
public static void transform() {
|
||||
public static void transform(CustomClassLoader loader) {
|
||||
Path newClassPath = Const.TEMP_PATH;
|
||||
if (!Files.exists(newClassPath)) {
|
||||
logger.error("class not exist: {}", newClassPath.toString());
|
||||
@@ -23,8 +25,8 @@ public class MethodNameTransformer {
|
||||
}
|
||||
try {
|
||||
ClassReader classReader = new ClassReader(Files.readAllBytes(newClassPath));
|
||||
ClassWriter classWriter = new ClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0);
|
||||
ClassWriter classWriter = new CustomClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0, loader);
|
||||
MethodNameClassVisitor changer = new MethodNameClassVisitor(classWriter);
|
||||
classReader.accept(changer, Const.ReaderASMOptions);
|
||||
Files.delete(newClassPath);
|
||||
|
||||
@@ -3,6 +3,8 @@ package me.n1ar4.clazz.obfuscator.transform;
|
||||
import me.n1ar4.clazz.obfuscator.Const;
|
||||
import me.n1ar4.clazz.obfuscator.asm.ParameterClassVisitor;
|
||||
import me.n1ar4.clazz.obfuscator.core.ObfEnv;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassLoader;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassWriter;
|
||||
import me.n1ar4.log.LogManager;
|
||||
import me.n1ar4.log.Logger;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
@@ -15,7 +17,7 @@ import java.nio.file.Path;
|
||||
public class ParameterTransformer {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
||||
public static void transform() {
|
||||
public static void transform(CustomClassLoader loader) {
|
||||
Path newClassPath = Const.TEMP_PATH;
|
||||
if (!Files.exists(newClassPath)) {
|
||||
logger.error("class not exist: {}", newClassPath.toString());
|
||||
@@ -23,8 +25,8 @@ public class ParameterTransformer {
|
||||
}
|
||||
try {
|
||||
ClassReader classReader = new ClassReader(Files.readAllBytes(newClassPath));
|
||||
ClassWriter classWriter = new ClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0);
|
||||
ClassWriter classWriter = new CustomClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0, loader);
|
||||
ParameterClassVisitor changer = new ParameterClassVisitor(classWriter);
|
||||
classReader.accept(changer, Const.ReaderASMOptions);
|
||||
Files.delete(newClassPath);
|
||||
|
||||
@@ -3,6 +3,8 @@ package me.n1ar4.clazz.obfuscator.transform;
|
||||
import me.n1ar4.clazz.obfuscator.Const;
|
||||
import me.n1ar4.clazz.obfuscator.asm.ReflectClassVisitor;
|
||||
import me.n1ar4.clazz.obfuscator.core.ObfEnv;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassLoader;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassWriter;
|
||||
import me.n1ar4.log.LogManager;
|
||||
import me.n1ar4.log.Logger;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
@@ -14,7 +16,7 @@ import java.nio.file.Path;
|
||||
public class ReflectTransformer {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
||||
public static void transform() {
|
||||
public static void transform(CustomClassLoader loader) {
|
||||
Path classPath = Const.TEMP_PATH;
|
||||
if (!Files.exists(classPath)) {
|
||||
logger.error("class not exist: {}", classPath.toString());
|
||||
@@ -22,8 +24,8 @@ public class ReflectTransformer {
|
||||
}
|
||||
try {
|
||||
ClassReader classReader = new ClassReader(Files.readAllBytes(classPath));
|
||||
ClassWriter classWriter = new ClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0);
|
||||
ClassWriter classWriter = new CustomClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0, loader);
|
||||
ReflectClassVisitor changer = new ReflectClassVisitor(classWriter);
|
||||
classReader.accept(changer, Const.ReaderASMOptions);
|
||||
Files.delete(classPath);
|
||||
|
||||
@@ -3,6 +3,8 @@ package me.n1ar4.clazz.obfuscator.transform;
|
||||
import me.n1ar4.clazz.obfuscator.Const;
|
||||
import me.n1ar4.clazz.obfuscator.asm.StringArrayClassVisitor;
|
||||
import me.n1ar4.clazz.obfuscator.core.ObfEnv;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassLoader;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassWriter;
|
||||
import me.n1ar4.log.LogManager;
|
||||
import me.n1ar4.log.Logger;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
@@ -16,7 +18,7 @@ public class StringArrayTransformer {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
public static int INDEX = 0;
|
||||
|
||||
public static void transform() {
|
||||
public static void transform(CustomClassLoader loader) {
|
||||
Path newClassPath = Const.TEMP_PATH;
|
||||
if (!Files.exists(newClassPath)) {
|
||||
logger.error("class not exist: {}", newClassPath.toString());
|
||||
@@ -25,8 +27,8 @@ public class StringArrayTransformer {
|
||||
try {
|
||||
INDEX = 0;
|
||||
ClassReader classReader = new ClassReader(Files.readAllBytes(newClassPath));
|
||||
ClassWriter classWriter = new ClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0);
|
||||
ClassWriter classWriter = new CustomClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0, loader);
|
||||
StringArrayClassVisitor changer = new StringArrayClassVisitor(classWriter);
|
||||
classReader.accept(changer, Const.ReaderASMOptions);
|
||||
Files.delete(newClassPath);
|
||||
|
||||
@@ -3,6 +3,8 @@ package me.n1ar4.clazz.obfuscator.transform;
|
||||
import me.n1ar4.clazz.obfuscator.Const;
|
||||
import me.n1ar4.clazz.obfuscator.asm.StringEncryptClassVisitor;
|
||||
import me.n1ar4.clazz.obfuscator.core.ObfEnv;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassLoader;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassWriter;
|
||||
import me.n1ar4.log.LogManager;
|
||||
import me.n1ar4.log.Logger;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
@@ -15,7 +17,7 @@ import java.nio.file.Path;
|
||||
public class StringEncryptTransformer {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
||||
public static void transform(String aesKey, String aesDecName) {
|
||||
public static void transform(String aesKey, String aesDecName, CustomClassLoader loader) {
|
||||
Path newClassPath = Const.TEMP_PATH;
|
||||
if (!Files.exists(newClassPath)) {
|
||||
logger.error("class not exist: {}", newClassPath.toString());
|
||||
@@ -23,13 +25,14 @@ public class StringEncryptTransformer {
|
||||
}
|
||||
try {
|
||||
ClassReader classReader = new ClassReader(Files.readAllBytes(newClassPath));
|
||||
ClassWriter classWriter = new ClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0);
|
||||
ClassWriter classWriter = new CustomClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0, loader);
|
||||
StringEncryptClassVisitor changer = new StringEncryptClassVisitor(classWriter, aesKey, aesDecName);
|
||||
classReader.accept(changer, Const.ReaderASMOptions);
|
||||
Files.delete(newClassPath);
|
||||
Files.write(newClassPath, classWriter.toByteArray());
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
logger.error("transform error: {}", ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package me.n1ar4.clazz.obfuscator.transform;
|
||||
import me.n1ar4.clazz.obfuscator.Const;
|
||||
import me.n1ar4.clazz.obfuscator.asm.IntToXorClassVisitor;
|
||||
import me.n1ar4.clazz.obfuscator.core.ObfEnv;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassLoader;
|
||||
import me.n1ar4.clazz.obfuscator.loader.CustomClassWriter;
|
||||
import me.n1ar4.log.LogManager;
|
||||
import me.n1ar4.log.Logger;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
@@ -15,7 +17,7 @@ import java.nio.file.Path;
|
||||
public class XORTransformer {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
||||
public static void transform() {
|
||||
public static void transform(ClassLoader loader) {
|
||||
Path newClassPath = Const.TEMP_PATH;
|
||||
if (!Files.exists(newClassPath)) {
|
||||
logger.error("class not exist: {}", newClassPath.toString());
|
||||
@@ -23,8 +25,8 @@ public class XORTransformer {
|
||||
}
|
||||
try {
|
||||
ClassReader classReader = new ClassReader(Files.readAllBytes(newClassPath));
|
||||
ClassWriter classWriter = new ClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0);
|
||||
ClassWriter classWriter = new CustomClassWriter(classReader,
|
||||
ObfEnv.config.isAsmAutoCompute() ? Const.WriterASMOptions : 0, loader);
|
||||
IntToXorClassVisitor changer = new IntToXorClassVisitor(classWriter);
|
||||
classReader.accept(changer, Const.ReaderASMOptions);
|
||||
Files.delete(newClassPath);
|
||||
|
||||
@@ -1,18 +1,30 @@
|
||||
package me.n1ar4.clazz.obfuscator.utils;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class AESUtil {
|
||||
public static void addAesDecodeCode(ClassVisitor cv, String aesDecName) {
|
||||
MethodVisitor methodVisitor = cv.visitMethod(
|
||||
ACC_PUBLIC | ACC_STATIC,
|
||||
aesDecName,
|
||||
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
|
||||
null, new String[]{"java/lang/Exception"});
|
||||
MethodVisitor methodVisitor = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, aesDecName,
|
||||
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", null, null);
|
||||
methodVisitor.visitCode();
|
||||
Label label0 = new Label();
|
||||
Label label1 = new Label();
|
||||
Label label2 = new Label();
|
||||
methodVisitor.visitTryCatchBlock(label0, label1, label2, "java/lang/Exception");
|
||||
Label label3 = new Label();
|
||||
Label label4 = new Label();
|
||||
Label label5 = new Label();
|
||||
methodVisitor.visitTryCatchBlock(label3, label4, label5, "java/lang/Exception");
|
||||
Label label6 = new Label();
|
||||
Label label7 = new Label();
|
||||
Label label8 = new Label();
|
||||
methodVisitor.visitTryCatchBlock(label6, label7, label8, "java/lang/Exception");
|
||||
Label label9 = new Label();
|
||||
Label label10 = new Label();
|
||||
methodVisitor.visitTryCatchBlock(label9, label10, label8, "java/lang/Exception");
|
||||
methodVisitor.visitLabel(label6);
|
||||
methodVisitor.visitTypeInsn(NEW, "java/lang/StringBuilder");
|
||||
methodVisitor.visitInsn(DUP);
|
||||
methodVisitor.visitVarInsn(ALOAD, 1);
|
||||
@@ -41,18 +53,100 @@ public class AESUtil {
|
||||
methodVisitor.visitInsn(ICONST_2);
|
||||
methodVisitor.visitVarInsn(ALOAD, 2);
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "javax/crypto/Cipher", "init", "(ILjava/security/Key;)V", false);
|
||||
methodVisitor.visitVarInsn(ALOAD, 3);
|
||||
methodVisitor.visitMethodInsn(INVOKESTATIC, "java/util/Base64", "getDecoder", "()Ljava/util/Base64$Decoder;", false);
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/util/Base64$Decoder", "decode", "(Ljava/lang/String;)[B", false);
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "javax/crypto/Cipher", "doFinal", "([B)[B", false);
|
||||
methodVisitor.visitInsn(ACONST_NULL);
|
||||
methodVisitor.visitVarInsn(ASTORE, 5);
|
||||
methodVisitor.visitLabel(label0);
|
||||
methodVisitor.visitLdcInsn("java.util.Base64");
|
||||
methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
|
||||
methodVisitor.visitVarInsn(ASTORE, 4);
|
||||
methodVisitor.visitVarInsn(ALOAD, 4);
|
||||
methodVisitor.visitLdcInsn("getDecoder");
|
||||
methodVisitor.visitInsn(ACONST_NULL);
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
methodVisitor.visitVarInsn(ALOAD, 4);
|
||||
methodVisitor.visitInsn(ACONST_NULL);
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
methodVisitor.visitVarInsn(ASTORE, 6);
|
||||
methodVisitor.visitVarInsn(ALOAD, 6);
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
|
||||
methodVisitor.visitLdcInsn("decode");
|
||||
methodVisitor.visitInsn(ICONST_1);
|
||||
methodVisitor.visitTypeInsn(ANEWARRAY, "java/lang/Class");
|
||||
methodVisitor.visitInsn(DUP);
|
||||
methodVisitor.visitInsn(ICONST_0);
|
||||
methodVisitor.visitLdcInsn(Type.getType(String.class));
|
||||
methodVisitor.visitInsn(AASTORE);
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
methodVisitor.visitVarInsn(ALOAD, 6);
|
||||
methodVisitor.visitInsn(ICONST_1);
|
||||
methodVisitor.visitTypeInsn(ANEWARRAY, "java/lang/Object");
|
||||
methodVisitor.visitInsn(DUP);
|
||||
methodVisitor.visitInsn(ICONST_0);
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitInsn(AASTORE);
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
methodVisitor.visitTypeInsn(CHECKCAST, "[B");
|
||||
methodVisitor.visitTypeInsn(CHECKCAST, "[B");
|
||||
methodVisitor.visitVarInsn(ASTORE, 5);
|
||||
methodVisitor.visitLabel(label1);
|
||||
methodVisitor.visitJumpInsn(GOTO, label9);
|
||||
methodVisitor.visitLabel(label2);
|
||||
methodVisitor.visitFrame(Opcodes.F_FULL, 6, new Object[]{"java/lang/String", "java/lang/String", "javax/crypto/spec/SecretKeySpec", "javax/crypto/Cipher", Opcodes.TOP, "[B"}, 1, new Object[]{"java/lang/Exception"});
|
||||
methodVisitor.visitVarInsn(ASTORE, 6);
|
||||
methodVisitor.visitLabel(label3);
|
||||
methodVisitor.visitLdcInsn("sun.misc.BASE64Decoder");
|
||||
methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
|
||||
methodVisitor.visitVarInsn(ASTORE, 4);
|
||||
methodVisitor.visitVarInsn(ALOAD, 4);
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "newInstance", "()Ljava/lang/Object;", false);
|
||||
methodVisitor.visitVarInsn(ASTORE, 7);
|
||||
methodVisitor.visitVarInsn(ALOAD, 7);
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
|
||||
methodVisitor.visitLdcInsn("decodeBuffer");
|
||||
methodVisitor.visitInsn(ICONST_1);
|
||||
methodVisitor.visitTypeInsn(ANEWARRAY, "java/lang/Class");
|
||||
methodVisitor.visitInsn(DUP);
|
||||
methodVisitor.visitInsn(ICONST_0);
|
||||
methodVisitor.visitLdcInsn(Type.getType(String.class));
|
||||
methodVisitor.visitInsn(AASTORE);
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
|
||||
methodVisitor.visitVarInsn(ALOAD, 7);
|
||||
methodVisitor.visitInsn(ICONST_1);
|
||||
methodVisitor.visitTypeInsn(ANEWARRAY, "java/lang/Object");
|
||||
methodVisitor.visitInsn(DUP);
|
||||
methodVisitor.visitInsn(ICONST_0);
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitInsn(AASTORE);
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
|
||||
methodVisitor.visitTypeInsn(CHECKCAST, "[B");
|
||||
methodVisitor.visitTypeInsn(CHECKCAST, "[B");
|
||||
methodVisitor.visitVarInsn(ASTORE, 5);
|
||||
methodVisitor.visitLabel(label4);
|
||||
methodVisitor.visitJumpInsn(GOTO, label9);
|
||||
methodVisitor.visitLabel(label5);
|
||||
methodVisitor.visitFrame(Opcodes.F_FULL, 7, new Object[]{"java/lang/String", "java/lang/String", "javax/crypto/spec/SecretKeySpec", "javax/crypto/Cipher", Opcodes.TOP, "[B", "java/lang/Exception"}, 1, new Object[]{"java/lang/Exception"});
|
||||
methodVisitor.visitVarInsn(ASTORE, 7);
|
||||
methodVisitor.visitLdcInsn("");
|
||||
methodVisitor.visitLabel(label7);
|
||||
methodVisitor.visitInsn(ARETURN);
|
||||
methodVisitor.visitLabel(label9);
|
||||
methodVisitor.visitFrame(Opcodes.F_FULL, 6, new Object[]{"java/lang/String", "java/lang/String", "javax/crypto/spec/SecretKeySpec", "javax/crypto/Cipher", "java/lang/Class", "[B"}, 0, new Object[]{});
|
||||
methodVisitor.visitVarInsn(ALOAD, 3);
|
||||
methodVisitor.visitVarInsn(ALOAD, 5);
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "javax/crypto/Cipher", "doFinal", "([B)[B", false);
|
||||
methodVisitor.visitVarInsn(ASTORE, 6);
|
||||
methodVisitor.visitTypeInsn(NEW, "java/lang/String");
|
||||
methodVisitor.visitInsn(DUP);
|
||||
methodVisitor.visitVarInsn(ALOAD, 4);
|
||||
methodVisitor.visitVarInsn(ALOAD, 6);
|
||||
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "<init>", "([B)V", false);
|
||||
methodVisitor.visitLabel(label10);
|
||||
methodVisitor.visitInsn(ARETURN);
|
||||
methodVisitor.visitMaxs(4, 5);
|
||||
methodVisitor.visitLabel(label8);
|
||||
methodVisitor.visitFrame(Opcodes.F_FULL, 2, new Object[]{"java/lang/String", "java/lang/String"}, 1, new Object[]{"java/lang/Exception"});
|
||||
methodVisitor.visitVarInsn(ASTORE, 2);
|
||||
methodVisitor.visitLdcInsn("");
|
||||
methodVisitor.visitInsn(ARETURN);
|
||||
methodVisitor.visitMaxs(6, 8);
|
||||
methodVisitor.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,14 +17,35 @@ public class AESTemplates {
|
||||
return new StringBuilder(base).reverse().toString();
|
||||
}
|
||||
|
||||
public static String decrypt(String encryptedData, String key) throws Exception {
|
||||
key = new StringBuilder(key).reverse().toString();
|
||||
encryptedData = new StringBuilder(encryptedData).reverse().toString();
|
||||
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES");
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey);
|
||||
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
|
||||
return new String(decryptedBytes);
|
||||
public static String decrypt(String encryptedData, String key) {
|
||||
try {
|
||||
key = new StringBuilder(key).reverse().toString();
|
||||
encryptedData = new StringBuilder(encryptedData).reverse().toString();
|
||||
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES");
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey);
|
||||
Class<?> base64;
|
||||
byte[] value = null;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);
|
||||
value = (byte[]) decoder.getClass().getMethod("decode",
|
||||
new Class[]{String.class}).invoke(decoder, new Object[]{encryptedData});
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder");
|
||||
Object decoder = base64.newInstance();
|
||||
value = (byte[]) decoder.getClass().getMethod("decodeBuffer",
|
||||
new Class[]{String.class}).invoke(decoder, new Object[]{encryptedData});
|
||||
} catch (Exception ex) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
byte[] decryptedBytes = cipher.doFinal(value);
|
||||
return new String(decryptedBytes);
|
||||
} catch (Exception ignored) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
Reference in New Issue
Block a user