Skip to content

Commit

Permalink
[重要] 支持字符串 AES 加密运行时解密 @4ra1n
Browse files Browse the repository at this point in the history
  • Loading branch information
4ra1n committed Dec 12, 2024
1 parent 10e311c commit 3a84718
Show file tree
Hide file tree
Showing 11 changed files with 406 additions and 3 deletions.
7 changes: 4 additions & 3 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# CHANGELOG

## 1.1.2
## 1.2.0

更新日志:

- [BUG] 避免 `advanceStringName` 和混淆标识符冲突
- [优化] 优化 `config.yaml` 模板排序和注释内容
- [重要] 支持字符串 `AES` 加密运行时解密 @4ra1n
- [BUG] 避免 `advanceStringName` 和混淆标识符冲突 @4ra1n
- [优化] 优化 `config.yaml` 模板排序和注释内容 @4ra1n

感谢以下用户的贡献:

Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@

![](img/004.png)

`1.2.0` 版本开始支持集中提取字符串后 `AES` 加密运行时解密

![](img/007.png)

本项目已深度集成到 `web-chains` 项目中 (https://github.com/Java-Chains/web-chains)

![](img/006.png)
Expand Down Expand Up @@ -179,6 +183,13 @@ enableParamName: true
# 是否对数字进行异或混淆
enableXOR: true

# 对所有字符串进行 AES 加密
enableAES: true
# 默认 AES KEY 注意长度必须是 16
aesKey: OBF_DEFAULT_KEYS
# AES 解密方法名
aesDecName: iiLLiLi

# 是否启用全局字符串提取混淆
enableAdvanceString: true
# 全局提取字符串的变量名可以自定义
Expand All @@ -197,6 +208,7 @@ enableHideField: false
# 是否开启方法隐藏
# 可以防止大部分 IDEA 版本反编译
enableHideMethod: false

```
## Thanks
Expand Down
Binary file added img/007.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
227 changes: 227 additions & 0 deletions src/main/java/me/n1ar4/clazz/obfuscator/asm/StringEncryptChanger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
package me.n1ar4.clazz.obfuscator.asm;

import me.n1ar4.clazz.obfuscator.Const;
import me.n1ar4.clazz.obfuscator.core.ObfEnv;
import me.n1ar4.clazz.obfuscator.transform.StringArrayTransformer;
import me.n1ar4.clazz.obfuscator.utils.AESUtil;
import me.n1ar4.templates.AESTemplates;
import org.objectweb.asm.*;
import sun.invoke.util.VerifyAccess;

public class StringEncryptChanger extends ClassVisitor {
private String className;
private final String aesKey;
private final String aesDecName;

public StringEncryptChanger(ClassVisitor classVisitor, String aesKey, String aesDecName) {
super(Const.ASMVersion, classVisitor);
this.aesKey = aesKey;
this.aesDecName = aesDecName;
}

@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
this.className = name;
super.visit(version, access, name, signature, superName, interfaces);
}

@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
return new StringEncryptMethodAdapter(mv, className, aesKey, aesDecName);
}

@Override
public void visitEnd() {
AESUtil.addAesDecodeCode(cv, this.aesDecName);
super.visitEnd();
}

static class StringEncryptMethodAdapter extends MethodVisitor {
private final String className;
private final String aesKey;
private final String aesDecName;

StringEncryptMethodAdapter(MethodVisitor mv, String name, String aesKey, String aesDecName) {
super(Const.ASMVersion, mv);
this.className = name;
this.aesKey = aesKey;
this.aesDecName = aesDecName;
}

@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}

@Override
public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
super.visitFieldInsn(opcode, owner, name, descriptor);
}

@Override
public void visitTypeInsn(int opcode, String type) {
super.visitTypeInsn(opcode, type);
}

@Override
public void visitAttribute(Attribute attribute) {
super.visitAttribute(attribute);
}

@Override
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
}

@Override
public MethodVisitor getDelegate() {
return super.getDelegate();
}

@Override
public void visitEnd() {
super.visitEnd();
}

@Override
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
return super.visitAnnotation(descriptor, visible);
}

@Override
public AnnotationVisitor visitAnnotationDefault() {
return super.visitAnnotationDefault();
}

@Override
public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
return super.visitInsnAnnotation(typeRef, typePath, descriptor, visible);
}

@Override
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String descriptor, boolean visible) {
return super.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, descriptor, visible);
}

@Override
public AnnotationVisitor visitParameterAnnotation(int parameter, String descriptor, boolean visible) {
return super.visitParameterAnnotation(parameter, descriptor, visible);
}

@Override
public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) {
return super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible);
}

@Override
public void visitAnnotableParameterCount(int parameterCount, boolean visible) {
super.visitAnnotableParameterCount(parameterCount, visible);
}

@Override
public void visitCode() {
super.visitCode();
}

@Override
public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) {
super.visitFrame(type, numLocal, local, numStack, stack);
}

@Override
public void visitIincInsn(int varIndex, int increment) {
super.visitIincInsn(varIndex, increment);
}

@Override
public void visitInsn(int opcode) {
super.visitInsn(opcode);
}

@Override
public void visitIntInsn(int opcode, int operand) {
super.visitIntInsn(opcode, operand);
}

@Override
public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) {
super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
}

@Override
public void visitJumpInsn(int opcode, Label label) {
super.visitJumpInsn(opcode, label);
}

@Override
public void visitLabel(Label label) {
super.visitLabel(label);
}

@Override
public void visitLdcInsn(Object value) {
if (value instanceof String) {
try {
mv.visitLdcInsn(AESTemplates.encrypt((String) value, this.aesKey));
mv.visitLdcInsn(this.aesKey);
mv.visitMethodInsn(
Opcodes.INVOKESTATIC,
className,
this.aesDecName,
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
false);
} catch (Exception ignored) {
super.visitLdcInsn(value);
}
} else {
super.visitLdcInsn(value);
}
}

@Override
public void visitLineNumber(int line, Label start) {
super.visitLineNumber(line, start);
}

@Override
public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
super.visitLocalVariable(name, descriptor, signature, start, end, index);
}

@Override
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
super.visitLookupSwitchInsn(dflt, keys, labels);
}

@Override
public void visitMaxs(int maxStack, int maxLocals) {
super.visitMaxs(maxStack, maxLocals);
}

@Override
public void visitMultiANewArrayInsn(String descriptor, int numDimensions) {
super.visitMultiANewArrayInsn(descriptor, numDimensions);
}

@Override
public void visitParameter(String name, int access) {
super.visitParameter(name, access);
}

@Override
public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
super.visitTableSwitchInsn(min, max, dflt, labels);
}

@Override
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
super.visitTryCatchBlock(start, end, handler, type);
}

@Override
public void visitVarInsn(int opcode, int varIndex) {
super.visitVarInsn(opcode, varIndex);
}
}
}
36 changes: 36 additions & 0 deletions src/main/java/me/n1ar4/clazz/obfuscator/config/BaseConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@ public class BaseConfig {
private boolean enableHideField;

private boolean enableXOR;
private boolean enableAES;
private boolean enableJunk;
private boolean enableDeleteCompileInfo;

private int junkLevel;
private int maxJunkOneClass;

private String aesKey;
private String aesDecName;
private String[] obfuscateChars;
private String[] methodBlackList;

Expand All @@ -36,6 +39,9 @@ public static BaseConfig Default() {
config.setEnableAdvanceString(true);
config.setEnableFieldName(true);
config.setEnableXOR(true);
config.setEnableAES(true);
config.setAesKey("OBF_DEFAULT_KEYS");
config.setAesDecName("iiLLiLi");
config.setEnableDeleteCompileInfo(true);
config.setEnableParamName(true);
config.setEnableMethodName(true);
Expand Down Expand Up @@ -71,6 +77,12 @@ public void show() {
ColorUtil.green(String.valueOf(enableHideField)));
System.out.println(ColorUtil.yellow("Enable XOR Obfuscate -> ") +
ColorUtil.green(String.valueOf(enableXOR)));
System.out.println(ColorUtil.yellow("Enable String AES Encrypt -> ") +
ColorUtil.green(String.valueOf(enableAES)));
System.out.println(ColorUtil.yellow("AES Decrypt KEY-> ") +
ColorUtil.green(String.valueOf(aesKey)));
System.out.println(ColorUtil.yellow("AES Decrypt Method-> ") +
ColorUtil.green(String.valueOf(aesDecName)));
System.out.println(ColorUtil.yellow("Enable Advance String Obfuscate -> ") +
ColorUtil.green(String.valueOf(enableAdvanceString)));
System.out.println(ColorUtil.cyan("[Advance String] Global List Name -> ") +
Expand All @@ -83,6 +95,30 @@ public void show() {
ColorUtil.green(String.valueOf(maxJunkOneClass)));
}

public String getAesDecName() {
return aesDecName;
}

public void setAesDecName(String aesDecName) {
this.aesDecName = aesDecName;
}

public String getAesKey() {
return aesKey;
}

public void setAesKey(String aesKey) {
this.aesKey = aesKey;
}

public boolean isEnableAES() {
return enableAES;
}

public void setEnableAES(boolean enableAES) {
this.enableAES = enableAES;
}

public boolean isEnableHideField() {
return enableHideField;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public static boolean initConfig(BaseConfig config) {
// 修复 BUG 2024/12/13
// field / method 都不应该包含这个字符串
NameUtil.exclude(config.getAdvanceStringName());
NameUtil.exclude(config.getAesDecName());
ObfEnv.ADVANCE_STRING_NAME = config.getAdvanceStringName();

return true;
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/me/n1ar4/clazz/obfuscator/core/Runner.java
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ public static void run(Path path, BaseConfig config) {
logger.info("run string array transformer finish");
}

if (config.isEnableAES()) {
StringEncryptTransformer.transform(config.getAesKey(), config.getAesDecName());
logger.info("run string aes transformer finish");
}

if (config.isEnableJunk()) {
JunkCodeTransformer.transform(config);
logger.info("run junk transformer finish");
Expand Down
Loading

0 comments on commit 3a84718

Please sign in to comment.