From 2041063aee66bf4678d20c76a03cd906921943ed Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Fri, 20 Apr 2018 11:52:25 -0700 Subject: [PATCH 001/281] 0.6.1 - InvokeDynamic fixes --- CHANGELOG.md | 4 ++ pom.xml | 2 +- src/main/java/me/itzsomebody/radon/Radon.java | 2 +- .../invokedynamic/HeavyInvokeDynamic.java | 59 ++++++++++++++----- .../invokedynamic/LightInvokeDynamic.java | 10 +++- .../invokedynamic/NormalInvokeDynamic.java | 10 +++- 6 files changed, 65 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 097e5758..acccbf72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.1 + +* Fixed an issue with the invokedynamic transformers which sometimes caused programs to crash with an access exception. + ## 0.6.0 * Added GUI console for GUI users. diff --git a/pom.xml b/pom.xml index 9338b77a..e15e559e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ me.itzsomebody Radon - 0.6.0 + 0.6.1 UTF-8 diff --git a/src/main/java/me/itzsomebody/radon/Radon.java b/src/main/java/me/itzsomebody/radon/Radon.java index 49c33558..de244046 100644 --- a/src/main/java/me/itzsomebody/radon/Radon.java +++ b/src/main/java/me/itzsomebody/radon/Radon.java @@ -14,7 +14,7 @@ public class Radon { * Static abuse variables xD */ public static String PREFIX = "[Radon]"; - public static String VERSION = "0.6.0"; + public static String VERSION = "0.6.1"; public static String AUTHORS = "ItzSomebody"; /** diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java index a766c989..bc2382ab 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java @@ -70,9 +70,10 @@ public void obfuscate() { boolean isStatic = (methodInsnNode.getOpcode() == INVOKESTATIC); String newSig = isStatic ? methodInsnNode.desc : methodInsnNode.desc.replace("(", "(Ljava/lang/Object;"); + Type returnType = Type.getReturnType(methodInsnNode.desc); switch (methodInsnNode.getOpcode()) { - case INVOKESTATIC: // invokestatic opcode - methodNode.instructions.set(insn, new InvokeDynamicInsnNode( + case INVOKESTATIC: {// invokestatic opcode + InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode( StringUtils.randomString(this.dictionary), newSig, bsmHandle, @@ -80,12 +81,17 @@ public void obfuscate() { this.STATIC_INVOCATION, this.encOwner(methodInsnNode.owner.replaceAll("/", ".")), this.encName(methodInsnNode.name), - this.encDesc(methodInsnNode.desc))); + this.encDesc(methodInsnNode.desc)); + methodNode.instructions.set(insn, indy); + if (returnType.getSort() == Type.ARRAY) { + methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); + } counter.incrementAndGet(); break; + } case INVOKEVIRTUAL: // invokevirtual opcode - case INVOKEINTERFACE: // invokeinterface opcode - methodNode.instructions.set(insn, new InvokeDynamicInsnNode( + case INVOKEINTERFACE: {// invokeinterface opcode + InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode( StringUtils.randomString(this.dictionary), newSig, bsmHandle, @@ -93,11 +99,17 @@ public void obfuscate() { this.VIRTUAL_INVOCATION, this.encOwner(methodInsnNode.owner.replaceAll("/", ".")), this.encName(methodInsnNode.name), - this.encDesc(methodInsnNode.desc))); + this.encDesc(methodInsnNode.desc)); + methodNode.instructions.set(insn, indy); + if (returnType.getSort() == Type.ARRAY) { + methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); + } counter.incrementAndGet(); break; - default: + } + default: { break; + } } } else if (insn instanceof FieldInsnNode) { FieldInsnNode fieldInsnNode = (FieldInsnNode) insn; @@ -116,8 +128,9 @@ public void obfuscate() { Type type = Type.getType(fieldInsnNode.desc); String wrappedDescription = type.getClassName(); switch (fieldInsnNode.getOpcode()) { - case GETFIELD: - methodNode.instructions.set(insn, new InvokeDynamicInsnNode( + case GETFIELD: { + Type returnType = Type.getType(fieldInsnNode.desc); + InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode( StringUtils.randomString(this.dictionary), newSig, bsmHandle, @@ -125,11 +138,17 @@ public void obfuscate() { this.VIRTUAL_GETTER, this.encOwner(fieldInsnNode.owner.replaceAll("/", ".")), this.encName(fieldInsnNode.name), - this.encDesc(wrappedDescription))); + this.encDesc(wrappedDescription)); + methodNode.instructions.set(insn, indy); + if (returnType.getSort() == Type.ARRAY) { + methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); + } counter.incrementAndGet(); break; - case GETSTATIC: - methodNode.instructions.set(insn, new InvokeDynamicInsnNode( + } + case GETSTATIC: { + Type returnType = Type.getType(fieldInsnNode.desc); + InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode( StringUtils.randomString(this.dictionary), newSig, bsmHandle, @@ -137,10 +156,15 @@ public void obfuscate() { this.STATIC_GETTER, this.encOwner(fieldInsnNode.owner.replaceAll("/", ".")), this.encName(fieldInsnNode.name), - this.encDesc(wrappedDescription))); + this.encDesc(wrappedDescription)); + methodNode.instructions.set(insn, indy); + if (returnType.getSort() == Type.ARRAY) { + methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); + } counter.incrementAndGet(); break; - case PUTFIELD: + } + case PUTFIELD: { methodNode.instructions.set(insn, new InvokeDynamicInsnNode( StringUtils.randomString(this.dictionary), newSig, @@ -152,7 +176,8 @@ public void obfuscate() { this.encDesc(wrappedDescription))); counter.incrementAndGet(); break; - case PUTSTATIC: + } + case PUTSTATIC: { methodNode.instructions.set(insn, new InvokeDynamicInsnNode( StringUtils.randomString(this.dictionary), newSig, @@ -164,8 +189,10 @@ public void obfuscate() { this.encDesc(wrappedDescription))); counter.incrementAndGet(); break; - default: + } + default: { break; + } } } } diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java index fbc2e538..1b7c56f3 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java @@ -2,6 +2,7 @@ import org.objectweb.asm.Handle; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; import me.itzsomebody.radon.methods.InvokeDynamicBSM; import me.itzsomebody.radon.transformers.AbstractTransformer; @@ -56,15 +57,20 @@ public void obfuscate() { String newSig = isStatic ? methodInsnNode.desc : methodInsnNode.desc.replace("(", "(Ljava/lang/Object;"); + Type returnType = Type.getReturnType(methodInsnNode.desc); int opcode = (isStatic) ? this.STATIC_INVOCATION : this.VIRTUAL_INVOCATION; - methodNode.instructions.set(insn, new InvokeDynamicInsnNode(StringUtils.randomString(this.dictionary), + InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode(StringUtils.randomString(this.dictionary), newSig, bsmHandle, opcode, encryptOwner(methodInsnNode.owner.replaceAll("/", ".")), encryptName(methodInsnNode.name), - encryptDesc(methodInsnNode.desc))); + encryptDesc(methodInsnNode.desc)); + methodNode.instructions.set(insn, indy); + if (returnType.getSort() == Type.ARRAY) { + methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); + } counter.incrementAndGet(); } } diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java index 47a35bac..9a5a0864 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java @@ -2,6 +2,7 @@ import org.objectweb.asm.Handle; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; import me.itzsomebody.radon.methods.InvokeDynamicBSM; import me.itzsomebody.radon.transformers.AbstractTransformer; @@ -57,16 +58,21 @@ public void obfuscate() { String newSig = isStatic ? methodInsnNode.desc : methodInsnNode.desc.replace("(", "(Ljava/lang/Object;"); + Type returnType = Type.getReturnType(methodInsnNode.desc); int opcode = (isStatic) ? this.STATIC_INVOCATION : this.VIRTUAL_INVOCATION; - methodNode.instructions.set(insn, new InvokeDynamicInsnNode( + InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode( StringUtils.randomString(this.dictionary), newSig, bsmHandle, opcode, encryptOwner(methodInsnNode.owner.replaceAll("/", ".")), encryptName(methodInsnNode.name), - encryptDesc(methodInsnNode.desc))); + encryptDesc(methodInsnNode.desc)); + methodNode.instructions.set(insn, indy); + if (returnType.getSort() == Type.ARRAY) { + methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); + } counter.incrementAndGet(); } } From 3b1612d573651a15bf8d0e05ca6d072d704dd57f Mon Sep 17 00:00:00 2001 From: x0ark <39005439+x0ark@users.noreply.github.com> Date: Sun, 6 May 2018 01:43:56 +0500 Subject: [PATCH 002/281] Use refactoring, don't replace everyhing :D --- .../java/me/itzsomebody/radon/transformers/misc/Crasher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java index d3f2b266..d811a331 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java @@ -11,7 +11,7 @@ * Transformer that applies a crashing technique by exploiting class signature parsing. *

* Crashes: - * - JD-MainGUI + * - JD-GUI * - ProCyon * - CFR *

From e7f4ebe8bc30f73b8dfa544facc3ace952e10fc0 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Fri, 11 May 2018 13:07:53 -0700 Subject: [PATCH 003/281] Reformat stuff + New StackAnalyzer --- .../radon/analyzer/StackAnalyzer.java | 368 ++++++++++-------- .../me/itzsomebody/radon/config/Config.java | 24 +- .../me/itzsomebody/radon/gui/ConsoleGUI.java | 8 +- .../me/itzsomebody/radon/gui/MainGUI.java | 234 +---------- .../radon/gui/OutputStreamRedirect.java | 2 +- .../itzsomebody/radon/internal/Bootstrap.java | 32 +- .../me/itzsomebody/radon/internal/CLI.java | 11 +- .../internal/climessages/CLIMessages.java | 1 - .../radon/methods/InvokeDynamicBSM.java | 37 +- .../radon/methods/StringEncryption.java | 5 +- .../templates/HeavyStringEncryption.java | 4 +- .../radon/templates/LightInvokeDynamic.java | 12 +- .../transformers/AbstractTransformer.java | 8 +- .../flow/HeavyFlowObfuscation.java | 16 +- .../flow/LightFlowObfuscation.java | 14 +- .../flow/NormalFlowObfuscation.java | 18 +- .../invokedynamic/HeavyInvokeDynamic.java | 19 +- .../invokedynamic/LightInvokeDynamic.java | 14 +- .../invokedynamic/NormalInvokeDynamic.java | 14 +- .../linenumbers/ObfuscateLineNumbers.java | 8 +- .../linenumbers/RemoveLineNumbers.java | 8 +- .../ObfuscateLocalVariables.java | 5 +- .../localvariables/RemoveLocalVariables.java | 5 +- .../radon/transformers/misc/Crasher.java | 4 +- .../radon/transformers/misc/Expiry.java | 3 +- .../radon/transformers/misc/HideCode.java | 3 +- .../transformers/misc/InnerClassRemover.java | 3 +- .../transformers/misc/NumberObfuscation.java | 9 +- .../radon/transformers/misc/Shuffler.java | 5 +- .../radon/transformers/misc/StringPool.java | 14 +- .../radon/transformers/misc/TrashClasses.java | 17 +- .../radon/transformers/renamer/ClassTree.java | 5 +- .../radon/transformers/renamer/Renamer.java | 12 +- .../sourcedebug/ObfuscateSourceDebug.java | 5 +- .../sourcedebug/RemoveSourceDebug.java | 5 +- .../sourcename/ObfuscateSourceName.java | 5 +- .../sourcename/RemoveSourceName.java | 5 +- .../HeavyStringEncryption.java | 4 +- .../LightStringEncryption.java | 13 +- .../NormalStringEncryption.java | 14 +- .../SuperLightStringEncryption.java | 12 +- .../radon/utils/BytecodeUtils.java | 12 +- .../me/itzsomebody/radon/utils/FileUtils.java | 3 +- .../itzsomebody/radon/utils/LoggerUtils.java | 8 +- .../itzsomebody/radon/utils/StringUtils.java | 14 +- .../radon/utils/WatermarkUtils.java | 5 +- 46 files changed, 467 insertions(+), 580 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java b/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java index 2d5a9e19..fa57b253 100644 --- a/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java +++ b/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java @@ -1,19 +1,22 @@ package me.itzsomebody.radon.analyzer; -import me.itzsomebody.radon.utils.OpcodeUtils; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; - import java.util.EmptyStackException; import java.util.HashSet; import java.util.Set; import java.util.Stack; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.MultiANewArrayInsnNode; /** - * Attempts to make a virtual machine-like object which attempts to mimic the - * JVM stack. - * TODO: MAKE IT ACTUALLY WORK LOL + * Attempts to emulate the stack in a method up to a breakpoint. * * @author ItzSomebody */ @@ -69,6 +72,33 @@ public Stack returnStackAtBreak() { break; try { switch (insn.getOpcode()) { + case NOP: + case LALOAD: // (index, arrayref) -> (long, long_top) + case DALOAD: // (index, arrayref) -> (double, double_top) + case SWAP: // (value1, value2) -> (value2, value1) + case INEG: + case LNEG: + case FNEG: + case DNEG: + case IINC: + case I2F: + case L2D: + case F2I: + case D2L: + case I2B: + case I2C: + case I2S: + case GOTO: + case RET: + case RETURN: + case NEWARRAY: + case ANEWARRAY: + case ARRAYLENGTH: + case CHECKCAST: + case INSTANCEOF: { + // Does nothing + break; + } case ACONST_NULL: case ICONST_M1: case ICONST_0: @@ -77,108 +107,120 @@ public Stack returnStackAtBreak() { case ICONST_3: case ICONST_4: case ICONST_5: - case LCONST_0: - case LCONST_1: case FCONST_0: case FCONST_1: case FCONST_2: - case DCONST_0: - case DCONST_1: case BIPUSH: case SIPUSH: - case LDC: case ILOAD: - case LLOAD: case FLOAD: - case DLOAD: case ALOAD: - case IALOAD: - case LALOAD: - case FALOAD: - case DALOAD: - case AALOAD: - case BALOAD: - case CALOAD: - case SALOAD: case DUP: case DUP_X1: case DUP_X2: - case NEW: - case GETSTATIC: - case GETFIELD: - if (DEBUG) - System.out.println("Pushing - Opcode = " + - OpcodeUtils.getOpcodeName(insn.getOpcode())); + case I2L: + case I2D: + case F2L: + case F2D: + case JSR: + case NEW: { + // Pushes one-word constant to stack stack.push(null); break; + } + case LDC: { + LdcInsnNode ldc = (LdcInsnNode) insn; + if (ldc.cst instanceof Long || ldc.cst instanceof Double) + stack.push(null); + + stack.push(null); + break; + } + case LCONST_0: + case LCONST_1: + case DCONST_0: + case DCONST_1: + case LLOAD: + case DLOAD: + case DUP2: + case DUP2_X1: + case DUP2_X2: { + // Pushes two-word constant or two one-word constants to stack + stack.push(null); + stack.push(null); + break; + } + case IALOAD: // (index, arrayref) -> (int) + case FALOAD: // (index, arrayref) -> (float) + case AALOAD: // (index, arrayref) -> (Object) + case BALOAD: // (index, arrayref) -> (byte) + case CALOAD: // (index, arrayref) -> (char) + case SALOAD: // (index, arrayref) -> (short) case ISTORE: - case LSTORE: case FSTORE: - case DSTORE: case ASTORE: - case IASTORE: - case LASTORE: - case DASTORE: - case AASTORE: - case BASTORE: - case CASTORE: - case SASTORE: case POP: - case SWAP: case IADD: - case LADD: case FADD: - case DADD: case ISUB: - case LSUB: case FSUB: - case DSUB: case IMUL: - case LMUL: case FMUL: - case DMUL: case IDIV: - case LDIV: case FDIV: - case DDIV: case IREM: - case LREM: case FREM: - case DREM: case ISHL: - case LSHL: case ISHR: - case LSHR: case IUSHR: + case LSHL: + case LSHR: case LUSHR: case IAND: - case LAND: case IOR: - case LOR: case IXOR: - case LXOR: - case LCMP: + case L2I: + case L2F: + case D2I: + case D2F: case FCMPL: case FCMPG: - case DCMPL: - case DCMPG: - case TABLESWITCH: - case LOOKUPSWITCH: - case IRETURN: - case LRETURN: - case FRETURN: - case DRETURN: - case ARETURN: - case PUTSTATIC: - case PUTFIELD: - case MONITORENTER: - case MONITOREXIT: case IFEQ: case IFNE: case IFLT: case IFGE: case IFGT: case IFLE: + case TABLESWITCH: + case LOOKUPSWITCH: + case IRETURN: + case FRETURN: + case ATHROW: + case MONITORENTER: + case MONITOREXIT: + case IFNULL: + case IFNONNULL: + case ARETURN: { + // Pops one-word constant off stack + stack.pop(); + break; + } + case LSTORE: + case DSTORE: + case POP2: + case LADD: + case DADD: + case LSUB: + case DSUB: + case LMUL: + case DMUL: + case LDIV: + case DDIV: + case LREM: + case DREM: + case LAND: + case LOR: + case LXOR: case IF_ICMPEQ: case IF_ICMPNE: case IF_ICMPLT: @@ -187,123 +229,133 @@ public Stack returnStackAtBreak() { case IF_ICMPLE: case IF_ACMPEQ: case IF_ACMPNE: - case IFNULL: - case IFNONNULL: - if (DEBUG) - System.out.println("Popping - Opcode = " + - OpcodeUtils.getOpcodeName(insn.getOpcode())); + case LRETURN: + case DRETURN: { + // Pops two-word or two one-word constant(s) off stack + stack.pop(); stack.pop(); break; - case POP2: - if (DEBUG) - System.out.println("Double popping - Opcode = " + - OpcodeUtils.getOpcodeName(insn.getOpcode())); + } + case IASTORE: + case FASTORE: + case AASTORE: + case BASTORE: + case CASTORE: + case SASTORE: + case LCMP: + case DCMPL: + case DCMPG: { + // Pops three one-word constants off stack + stack.pop(); stack.pop(); stack.pop(); break; - case DUP2: - case DUP2_X1: - case DUP2_X2: - if (DEBUG) - System.out.println("Double pushing - Opcode = " + - OpcodeUtils.getOpcodeName(insn.getOpcode())); + } + case LASTORE: + case DASTORE: { + // Pops two one-word constants and one two-word constant off stack + stack.pop(); + stack.pop(); + stack.pop(); + stack.pop(); + break; + } + case GETSTATIC: { + Type type = Type.getType(((FieldInsnNode) insn).desc); stack.push(null); + + if (type.getSort() == Type.LONG || type.getSort() == Type.DOUBLE) + stack.push(null); + break; + } + case PUTSTATIC: { + Type type = Type.getType(((FieldInsnNode) insn).desc); + stack.pop(); + + if (type.getSort() == Type.LONG || type.getSort() == Type.DOUBLE) + stack.pop(); + break; + } + case GETFIELD: { + stack.pop(); // Objectref + Type type = Type.getType(((FieldInsnNode) insn).desc); stack.push(null); + + if (type.getSort() == Type.LONG || type.getSort() == Type.DOUBLE) + stack.push(null); break; - case INEG: - case LNEG: - case FNEG: - case DNEG: - case IINC: - case I2L: - case I2F: - case I2D: - case L2I: - case L2F: - case L2D: - case F2I: - case F2L: - case F2D: - case D2I: - case D2L: - case D2F: - case I2B: - case I2C: - case I2S: - case RETURN: - case NEWARRAY: - case ANEWARRAY: - case ARRAYLENGTH: - case ATHROW: - case CHECKCAST: - case INSTANCEOF: - case GOTO: - if (DEBUG) - System.out.println("Doing nothing - Opcode = " + - OpcodeUtils.getOpcodeName(insn.getOpcode())); + } + case PUTFIELD: { + stack.pop(); // Objectref + Type type = Type.getType(((FieldInsnNode) insn).desc); + stack.pop(); + + if (type.getSort() == Type.LONG || type.getSort() == Type.DOUBLE) + stack.pop(); break; - case JSR: - case RET: - throw new IllegalArgumentException("Unsupported " + - "opcode (JSR/RET)"); + } case INVOKEVIRTUAL: case INVOKESPECIAL: - case INVOKEINTERFACE: - if (DEBUG) - System.out.println("Processing static method " + - "invocation - Opcode = " + OpcodeUtils - .getOpcodeName(insn.getOpcode())); - MethodInsnNode virtualInvoke = (MethodInsnNode) insn; + case INVOKEINTERFACE: { stack.pop(); // Objectref - for (int j = 0; j < Type.getArgumentTypes - (virtualInvoke.desc).length; j++) { + Type[] args = Type.getArgumentTypes(((MethodInsnNode) insn).desc); + Type returnType = Type.getReturnType(((MethodInsnNode) insn).desc); + for (Type type : args) { + if (type.getSort() == Type.LONG + || type.getSort() == Type.DOUBLE) + stack.pop(); + stack.pop(); } - if (!virtualInvoke.desc.endsWith(")V")) { + if (returnType.getSort() == Type.LONG + || returnType.getSort() == Type.DOUBLE) + stack.push(null); + if (returnType.getSort() != Type.VOID) stack.push(null); - } break; - case INVOKESTATIC: - if (DEBUG) - System.out.println("Processing virtual method " + - "invocation - Opcode = " + OpcodeUtils - .getOpcodeName(insn.getOpcode())); - MethodInsnNode staticInvoke = (MethodInsnNode) insn; - for (int j = 0; j < Type.getArgumentTypes - (staticInvoke.desc).length; j++) { + } + case INVOKESTATIC: { + Type[] args = Type.getArgumentTypes(((MethodInsnNode) insn).desc); + Type returnType = Type.getReturnType(((MethodInsnNode) insn).desc); + for (Type type : args) { + if (type.getSort() == Type.LONG + || type.getSort() == Type.DOUBLE) + stack.pop(); + stack.pop(); } - if (!staticInvoke.desc.endsWith(")V")) { + if (returnType.getSort() == Type.LONG + || returnType.getSort() == Type.DOUBLE) + stack.push(null); + if (returnType.getSort() != Type.VOID) stack.push(null); - } break; - case INVOKEDYNAMIC: - if (DEBUG) - System.out.println("Processing dynamic invocation" + - " - Opcode = " + OpcodeUtils - .getOpcodeName(insn.getOpcode())); - InvokeDynamicInsnNode indy = - (InvokeDynamicInsnNode) insn; - for (int j = 0; j < Type.getArgumentTypes(indy.desc) - .length; j++) { + } + case INVOKEDYNAMIC: { + Type[] args = Type.getArgumentTypes(((InvokeDynamicInsnNode) insn).desc); + Type returnType = Type.getReturnType(((InvokeDynamicInsnNode) insn).desc); + for (Type type : args) { + if (type.getSort() == Type.LONG + || type.getSort() == Type.DOUBLE) + stack.pop(); + stack.pop(); } - if (!indy.desc.endsWith(")V")) { + if (returnType.getSort() == Type.LONG + || returnType.getSort() == Type.DOUBLE) + stack.push(null); + if (returnType.getSort() != Type.VOID) stack.push(null); - } break; - case MULTIANEWARRAY: - if (DEBUG) - System.out.println("Processing multi-dimension " + - "array - Opcode = " + OpcodeUtils. - getOpcodeName(insn.getOpcode())); - MultiANewArrayInsnNode arrays - = (MultiANewArrayInsnNode) insn; - for (int j = 0; j < arrays.dims; j++) { + } + case MULTIANEWARRAY: { + for (int j = 0; j < ((MultiANewArrayInsnNode) insn).dims; j++) { stack.pop(); } - stack.push(null); // Arrayref + + stack.push(null); // arrayref break; + } } } catch (EmptyStackException empty) { if (DEBUG) empty.printStackTrace(); diff --git a/src/main/java/me/itzsomebody/radon/config/Config.java b/src/main/java/me/itzsomebody/radon/config/Config.java index 9824c4b9..647c9d08 100644 --- a/src/main/java/me/itzsomebody/radon/config/Config.java +++ b/src/main/java/me/itzsomebody/radon/config/Config.java @@ -1,6 +1,15 @@ package me.itzsomebody.radon.config; -import me.itzsomebody.radon.transformers.*; +import java.io.File; +import java.io.InputStream; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.transformers.flow.HeavyFlowObfuscation; import me.itzsomebody.radon.transformers.flow.LightFlowObfuscation; import me.itzsomebody.radon.transformers.flow.NormalFlowObfuscation; @@ -11,7 +20,12 @@ import me.itzsomebody.radon.transformers.linenumbers.RemoveLineNumbers; import me.itzsomebody.radon.transformers.localvariables.ObfuscateLocalVariables; import me.itzsomebody.radon.transformers.localvariables.RemoveLocalVariables; -import me.itzsomebody.radon.transformers.misc.*; +import me.itzsomebody.radon.transformers.misc.Crasher; +import me.itzsomebody.radon.transformers.misc.HideCode; +import me.itzsomebody.radon.transformers.misc.InnerClassRemover; +import me.itzsomebody.radon.transformers.misc.NumberObfuscation; +import me.itzsomebody.radon.transformers.misc.Shuffler; +import me.itzsomebody.radon.transformers.misc.StringPool; import me.itzsomebody.radon.transformers.renamer.Renamer; import me.itzsomebody.radon.transformers.sourcedebug.ObfuscateSourceDebug; import me.itzsomebody.radon.transformers.sourcedebug.RemoveSourceDebug; @@ -23,12 +37,6 @@ import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; import org.yaml.snakeyaml.Yaml; -import java.io.File; -import java.io.InputStream; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; - /** * Big config class that looks horrible and has lots of docs to make the code * look a lot longer than it actually is LOL diff --git a/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java b/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java index 70bc2fd8..7a9f3f00 100644 --- a/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java @@ -1,12 +1,11 @@ package me.itzsomebody.radon.gui; -import me.itzsomebody.radon.Radon; - -import javax.swing.*; import java.awt.*; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.PrintStream; +import javax.swing.*; +import me.itzsomebody.radon.Radon; /** * Makes a "console" GUI so users can see log events when they use the @@ -69,10 +68,11 @@ public void windowClosing(WindowEvent e) { thisFrame.dispose(); } }); - this.thisFrame.setBounds(400, 400, 400, 400); + this.thisFrame.setBounds(400, 400, 600, 400); this.consolePanel = new JPanel(new BorderLayout()); this.consoleOutput = new JTextArea(); + this.consoleOutput.setFont(new Font("Arial", Font.PLAIN, 12)); this.consoleOutput.setEditable(false); this.consoleScrollPane = new JScrollPane(this.consoleOutput); this.consolePanel.add(this.consoleScrollPane, "Center"); diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java index 26931123..2e51c128 100644 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java @@ -1,9 +1,20 @@ package me.itzsomebody.radon.gui; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import javax.swing.*; import me.itzsomebody.radon.Radon; import me.itzsomebody.radon.config.Config; import me.itzsomebody.radon.internal.Bootstrap; -import me.itzsomebody.radon.transformers.*; +import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.transformers.flow.LightFlowObfuscation; import me.itzsomebody.radon.transformers.flow.NormalFlowObfuscation; import me.itzsomebody.radon.transformers.invokedynamic.HeavyInvokeDynamic; @@ -13,7 +24,13 @@ import me.itzsomebody.radon.transformers.linenumbers.RemoveLineNumbers; import me.itzsomebody.radon.transformers.localvariables.ObfuscateLocalVariables; import me.itzsomebody.radon.transformers.localvariables.RemoveLocalVariables; -import me.itzsomebody.radon.transformers.misc.*; +import me.itzsomebody.radon.transformers.misc.Crasher; +import me.itzsomebody.radon.transformers.misc.Expiry; +import me.itzsomebody.radon.transformers.misc.HideCode; +import me.itzsomebody.radon.transformers.misc.InnerClassRemover; +import me.itzsomebody.radon.transformers.misc.NumberObfuscation; +import me.itzsomebody.radon.transformers.misc.Shuffler; +import me.itzsomebody.radon.transformers.misc.StringPool; import me.itzsomebody.radon.transformers.renamer.Renamer; import me.itzsomebody.radon.transformers.sourcedebug.ObfuscateSourceDebug; import me.itzsomebody.radon.transformers.sourcedebug.RemoveSourceDebug; @@ -25,24 +42,6 @@ import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; import me.itzsomebody.radon.utils.WatermarkUtils; -import javax.swing.*; -import java.awt.BorderLayout; -import java.awt.GridBagLayout; -import java.awt.GridBagConstraints; - -import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -import java.awt.Font; - /** * This is pretty much all Eclipse WindowBuilder @@ -1279,201 +1278,6 @@ public void actionPerformed(ActionEvent arg0) { } btnObfuscate.setText("Processing..."); btnObfuscate.setEnabled(false); - /*SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - File output = null; - try { - - HashMap libs = new HashMap<>(); - for (int i = 0; i < libList.getSize(); i++) { - libs.put(libList.get(i), new File(libList.get(i))); - } - - File input = new File(inputField.getText()); - if (!input.exists()) { - JOptionPane.showMessageDialog(null, - "Input JAR does not exist.", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - output = new File(outputField.getText()); - - int trashChance; - try { - trashChance = - Integer.valueOf(trashChanceField.getText()); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, - "Please enter numbers only for the " + - "number of desired trash " + - "classes.", "Error", - JOptionPane.ERROR_MESSAGE); - return; - } - List exempts = new ArrayList<>(); - for (int i = 0; i < exemptList.size(); i++) { - exempts.add(exemptList.get(i)); - } - boolean spigotMode = chckbxSpigotPlugin.isSelected(); - List transformers - = new ArrayList<>(); - - if (chckbxClassRenammer.isSelected()) { - transformers.add(new Renamer(spigotMode)); - } - if (chckbxInnerClasses.isSelected()) { - transformers.add(new InnerClassRemover()); - } - if (chckbxNumberObfuscation.isSelected()) { - transformers.add(new NumberObfuscation()); - } - if (chckbxInvokeDynamic.isSelected()) { - switch (comboBox_1.getSelectedIndex()) { - case 0: - transformers.add(new LightInvokeDynamic()); - break; - case 1: - transformers.add(new NormalInvokeDynamic()); - break; - case 2: - transformers.add(new HeavyInvokeDynamic()); - break; - } - } - if (chckbxAddExpiration.isSelected()) { - if (!expirationDateField.getText().isEmpty() - && !expirationMessageField.getText() - .isEmpty()) { - long expireTime = - new SimpleDateFormat("MM/dd/yyyy") - .parse(expirationDateField - .getText()).getTime(); - transformers.add(new Expiry(expireTime, - expirationMessageField.getText())); - } - } - if (chckbxStringEncryption.isSelected()) { - switch (comboBox.getSelectedIndex()) { - case 0: - transformers.add(new SuperLightStringEncryption(spigotMode)); - break; - case 1: - transformers.add(new LightStringEncryption(spigotMode)); - break; - case 2: - transformers.add(new NormalStringEncryption(spigotMode)); - break; - case 3: - transformers.add(new HeavyStringEncryption(spigotMode)); - break; - } - } - if (chckbxFlow.isSelected()) { - switch (comboBox_2.getSelectedIndex()) { - case 0: - transformers.add(new LightFlowObfuscation()); - break; - case 1: - transformers.add(new NormalFlowObfuscation()); - break; - } - } - if (chckbxSpringPool.isSelected()) { - transformers.add(new StringPool()); - } - if (chckbxShuffler.isSelected()) { - transformers.add(new Shuffler()); - } - if (chckbxLocalVariables.isSelected()) { - switch (comboBox_3.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateLocalVariables()); - break; - case 1: - transformers.add(new RemoveLocalVariables()); - break; - } - } - if (chckbxLineObfuscation.isSelected()) { - switch (comboBox_5.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateLineNumbers()); - break; - case 1: - transformers.add(new RemoveLineNumbers()); - break; - } - } - if (chckbxSourceName.isSelected()) { - switch (comboBox_123.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateSourceName()); - break; - case 1: - transformers.add(new RemoveSourceName()); - break; - } - } - if (chckbxSourceDebug.isSelected()) { - switch (comboBox_1234.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateSourceDebug()); - break; - case 1: - transformers.add(new RemoveSourceDebug()); - break; - } - } - if (chckbxCrasher.isSelected()) { - transformers.add(new Crasher()); - } - if (chckbxHidecode.isSelected()) { - transformers.add(new HideCode(spigotMode)); - } - - int trashClasses = -1; - if (chckbxTrashClasses.isSelected()) { - trashClasses = trashChance; - } - - int watermarkType = -1; - if (chckbxAddWatermark.isSelected()) { - watermarkType = comboBox_05.getSelectedIndex(); - } - - int dictionary = dictionaryComboBox.getSelectedIndex(); - - new ConsoleGUI(); - Bootstrap bootstrap = new Bootstrap( - input, - output, - libs, - exempts, - transformers, - trashClasses, - waterMarkMessageField.getText(), - watermarkType, - new String(watermarkPassword.getPassword()), - dictionary); - bootstrap.startTheParty(false); - JOptionPane.showMessageDialog(null, - "Successfully processed file!", - "Done", JOptionPane.INFORMATION_MESSAGE); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, t.getMessage(), - "Error", JOptionPane.ERROR_MESSAGE); - t.printStackTrace(); - if (output != null) { - output.delete(); - } - } finally { - btnObfuscate.setEnabled(true); - btnObfuscate.setText(" Process "); - } - } - });*/ - SwingWorker sw = new SwingWorker() { @Override protected Object doInBackground() throws Exception { diff --git a/src/main/java/me/itzsomebody/radon/gui/OutputStreamRedirect.java b/src/main/java/me/itzsomebody/radon/gui/OutputStreamRedirect.java index 9eee6d79..9552bd29 100644 --- a/src/main/java/me/itzsomebody/radon/gui/OutputStreamRedirect.java +++ b/src/main/java/me/itzsomebody/radon/gui/OutputStreamRedirect.java @@ -1,7 +1,7 @@ package me.itzsomebody.radon.gui; -import javax.swing.*; import java.io.OutputStream; +import javax.swing.*; /** * Redirects all PrintStreams to the provided JTextArea. diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index 23d0b914..cdcd2925 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -1,26 +1,32 @@ package me.itzsomebody.radon.internal; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; import me.itzsomebody.radon.Radon; +import me.itzsomebody.radon.config.Config; +import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.transformers.misc.Expiry; import me.itzsomebody.radon.transformers.misc.TrashClasses; import me.itzsomebody.radon.transformers.renamer.Renamer; +import me.itzsomebody.radon.utils.FileUtils; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.NumberUtils; +import me.itzsomebody.radon.utils.StringUtils; import org.apache.commons.io.IOUtils; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.config.Config; -import me.itzsomebody.radon.transformers.*; -import me.itzsomebody.radon.utils.*; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.*; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; -import java.util.zip.ZipOutputStream; +import org.objectweb.asm.tree.ClassNode; /** * Bootstraps and runs the obfuscation process. diff --git a/src/main/java/me/itzsomebody/radon/internal/CLI.java b/src/main/java/me/itzsomebody/radon/internal/CLI.java index ed8fa0d5..94325cd6 100644 --- a/src/main/java/me/itzsomebody/radon/internal/CLI.java +++ b/src/main/java/me/itzsomebody/radon/internal/CLI.java @@ -1,15 +1,14 @@ package me.itzsomebody.radon.internal; -import me.itzsomebody.radon.config.Config; -import me.itzsomebody.radon.internal.climessages.CLIMessages; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.Radon; -import me.itzsomebody.radon.utils.WatermarkUtils; - import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.List; +import me.itzsomebody.radon.Radon; +import me.itzsomebody.radon.config.Config; +import me.itzsomebody.radon.internal.climessages.CLIMessages; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.WatermarkUtils; /** * CLI class to manage command line usage diff --git a/src/main/java/me/itzsomebody/radon/internal/climessages/CLIMessages.java b/src/main/java/me/itzsomebody/radon/internal/climessages/CLIMessages.java index 5bb160cf..6b13b687 100644 --- a/src/main/java/me/itzsomebody/radon/internal/climessages/CLIMessages.java +++ b/src/main/java/me/itzsomebody/radon/internal/climessages/CLIMessages.java @@ -1,6 +1,5 @@ package me.itzsomebody.radon.internal.climessages; -import me.itzsomebody.radon.Radon; import me.itzsomebody.radon.utils.LoggerUtils; /** diff --git a/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSM.java b/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSM.java index 03c218d4..ea4ded4e 100644 --- a/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSM.java +++ b/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSM.java @@ -1,13 +1,14 @@ package me.itzsomebody.radon.methods; +import java.lang.invoke.ConstantCallSite; +import me.itzsomebody.radon.transformers.invokedynamic.HeavyInvokeDynamic; +import me.itzsomebody.radon.transformers.invokedynamic.LightInvokeDynamic; +import me.itzsomebody.radon.transformers.invokedynamic.NormalInvokeDynamic; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; -import me.itzsomebody.radon.transformers.invokedynamic.*; import org.objectweb.asm.tree.MethodNode; -import java.lang.invoke.ConstantCallSite; - /** * That returns methods needed to produce a {@link ConstantCallSite} for * the appropriate InvokeDynamic transformer. @@ -724,7 +725,7 @@ public static MethodNode heavyBSM(String methodName, String className) { mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", "", "()V", false); mv.visitInsn(ATHROW); mv.visitLabel(l9); - mv.visitFrame(Opcodes.F_APPEND,2, new Object[] {"java/lang/Object", "java/lang/Object"}, 0, null); + mv.visitFrame(Opcodes.F_APPEND, 2, new Object[]{"java/lang/Object", "java/lang/Object"}, 0, null); mv.visitVarInsn(ALOAD, 3); mv.visitVarInsn(ASTORE, 11); Label l11 = new Label(); @@ -752,7 +753,7 @@ public static MethodNode heavyBSM(String methodName, String className) { mv.visitJumpInsn(GOTO, l15); Label l16 = new Label(); mv.visitLabel(l16); - mv.visitFrame(Opcodes.F_FULL, 16, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", Opcodes.INTEGER}, 0, new Object[] {}); + mv.visitFrame(Opcodes.F_FULL, 16, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", Opcodes.INTEGER}, 0, new Object[]{}); mv.visitVarInsn(ALOAD, 14); mv.visitVarInsn(ILOAD, 15); mv.visitVarInsn(ALOAD, 13); @@ -801,7 +802,7 @@ public static MethodNode heavyBSM(String methodName, String className) { mv.visitJumpInsn(GOTO, l23); Label l24 = new Label(); mv.visitLabel(l24); - mv.visitFrame(Opcodes.F_FULL, 19, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", Opcodes.INTEGER}, 0, new Object[] {}); + mv.visitFrame(Opcodes.F_FULL, 19, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", Opcodes.INTEGER}, 0, new Object[]{}); mv.visitVarInsn(ALOAD, 17); mv.visitVarInsn(ILOAD, 18); mv.visitVarInsn(ALOAD, 16); @@ -849,7 +850,7 @@ public static MethodNode heavyBSM(String methodName, String className) { mv.visitJumpInsn(GOTO, l31); Label l32 = new Label(); mv.visitLabel(l32); - mv.visitFrame(Opcodes.F_FULL, 22, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", Opcodes.INTEGER}, 0, new Object[] {}); + mv.visitFrame(Opcodes.F_FULL, 22, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", Opcodes.INTEGER}, 0, new Object[]{}); mv.visitVarInsn(ALOAD, 20); mv.visitVarInsn(ILOAD, 21); mv.visitVarInsn(ALOAD, 19); @@ -883,9 +884,9 @@ public static MethodNode heavyBSM(String methodName, String className) { Label l36 = new Label(); Label l37 = new Label(); Label l38 = new Label(); - mv.visitTableSwitchInsn(0, 1, l38, new Label[] { l36, l37 }); + mv.visitTableSwitchInsn(0, 1, l38, new Label[]{l36, l37}); mv.visitLabel(l36); - mv.visitFrame(Opcodes.F_FULL, 22, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String"}, 0, new Object[] {}); + mv.visitFrame(Opcodes.F_FULL, 22, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String"}, 0, new Object[]{}); mv.visitVarInsn(ALOAD, 4); mv.visitVarInsn(ASTORE, 22); Label l39 = new Label(); @@ -901,7 +902,7 @@ public static MethodNode heavyBSM(String methodName, String className) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false); mv.visitVarInsn(ASTORE, 24); mv.visitLabel(l0); - mv.visitFrame(Opcodes.F_APPEND,3, new Object[] {"java/lang/Object", "java/lang/reflect/Field", "java/lang/Class"}, 0, null); + mv.visitFrame(Opcodes.F_APPEND, 3, new Object[]{"java/lang/Object", "java/lang/reflect/Field", "java/lang/Class"}, 0, null); mv.visitVarInsn(ALOAD, 24); mv.visitVarInsn(ALOAD, 18); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", false); @@ -910,7 +911,7 @@ public static MethodNode heavyBSM(String methodName, String className) { Label l41 = new Label(); mv.visitJumpInsn(GOTO, l41); mv.visitLabel(l2); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/NoSuchFieldException"}); + mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{"java/lang/NoSuchFieldException"}); mv.visitVarInsn(ASTORE, 25); Label l42 = new Label(); mv.visitLabel(l42); @@ -940,7 +941,7 @@ public static MethodNode heavyBSM(String methodName, String className) { Label l47 = new Label(); Label l48 = new Label(); Label l49 = new Label(); - mv.visitTableSwitchInsn(0, 3, l49, new Label[] { l45, l46, l47, l48 }); + mv.visitTableSwitchInsn(0, 3, l49, new Label[]{l45, l46, l47, l48}); mv.visitLabel(l45); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitVarInsn(ALOAD, 12); @@ -1002,7 +1003,7 @@ public static MethodNode heavyBSM(String methodName, String className) { mv.visitLabel(l55); mv.visitJumpInsn(GOTO, l51); mv.visitLabel(l37); - mv.visitFrame(Opcodes.F_CHOP,3, null, 0, null); + mv.visitFrame(Opcodes.F_CHOP, 3, null, 0, null); mv.visitVarInsn(ALOAD, 4); mv.visitVarInsn(ASTORE, 25); Label l56 = new Label(); @@ -1020,9 +1021,9 @@ public static MethodNode heavyBSM(String methodName, String className) { Label l58 = new Label(); Label l59 = new Label(); Label l60 = new Label(); - mv.visitTableSwitchInsn(0, 1, l60, new Label[] { l58, l59 }); + mv.visitTableSwitchInsn(0, 1, l60, new Label[]{l58, l59}); mv.visitLabel(l58); - mv.visitFrame(Opcodes.F_FULL, 27, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String", Opcodes.TOP, Opcodes.TOP, Opcodes.TOP, "java/lang/Object", "java/lang/invoke/MethodType"}, 0, new Object[] {}); + mv.visitFrame(Opcodes.F_FULL, 27, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String", Opcodes.TOP, Opcodes.TOP, Opcodes.TOP, "java/lang/Object", "java/lang/invoke/MethodType"}, 0, new Object[]{}); mv.visitVarInsn(ALOAD, 12); mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); mv.visitVarInsn(ALOAD, 15); @@ -1053,11 +1054,11 @@ public static MethodNode heavyBSM(String methodName, String className) { mv.visitLabel(l63); mv.visitJumpInsn(GOTO, l51); mv.visitLabel(l38); - mv.visitFrame(Opcodes.F_FULL, 22, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String"}, 0, new Object[] {}); + mv.visitFrame(Opcodes.F_FULL, 22, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String"}, 0, new Object[]{}); mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, 10); mv.visitLabel(l51); - mv.visitFrame(Opcodes.F_FULL, 22, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/invoke/MethodHandle", "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String"}, 0, new Object[] {}); + mv.visitFrame(Opcodes.F_FULL, 22, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/invoke/MethodHandle", "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String"}, 0, new Object[]{}); mv.visitVarInsn(ALOAD, 10); mv.visitVarInsn(ALOAD, 2); mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodType"); @@ -1072,7 +1073,7 @@ public static MethodNode heavyBSM(String methodName, String className) { mv.visitLabel(l4); mv.visitInsn(ARETURN); mv.visitLabel(l5); - mv.visitFrame(Opcodes.F_FULL, 13, new Object[] {"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object"}, 1, new Object[] {"java/lang/Throwable"}); + mv.visitFrame(Opcodes.F_FULL, 13, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object"}, 1, new Object[]{"java/lang/Throwable"}); mv.visitVarInsn(ASTORE, 13); Label l65 = new Label(); mv.visitLabel(l65); diff --git a/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java b/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java index e25b5d84..d9ff9abb 100644 --- a/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java @@ -1,9 +1,12 @@ package me.itzsomebody.radon.methods; +import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; +import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; +import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; +import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.MethodNode; -import me.itzsomebody.radon.transformers.stringencryption.*; /** * Class containing {@link MethodNode}s needed to decrypt a {@link String} for the diff --git a/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java index ce939440..5cfb7322 100644 --- a/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java @@ -1,10 +1,10 @@ package me.itzsomebody.radon.templates; -import javax.crypto.*; -import javax.crypto.spec.SecretKeySpec; import java.security.MessageDigest; import java.util.Arrays; import java.util.Base64; +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; public class HeavyStringEncryption { public static String decrypt(Object strToDecrypt, Object random, Object secret) { diff --git a/src/main/java/me/itzsomebody/radon/templates/LightInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/templates/LightInvokeDynamic.java index 2d1767d6..b8bd4922 100644 --- a/src/main/java/me/itzsomebody/radon/templates/LightInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/templates/LightInvokeDynamic.java @@ -7,12 +7,12 @@ class LightInvokeDynamic { public static Object LightInvokeDynamic(Object lookupName, - Object callerName, - Object callerType, - Object opcodeIndicator, - Object originalClassName, - Object originalMethodName, - Object originalMethodSignature) { + Object callerName, + Object callerType, + Object opcodeIndicator, + Object originalClassName, + Object originalMethodName, + Object originalMethodSignature) { try { char[] encClassNameChars = originalClassName.toString().toCharArray(); char[] classNameChars = new char[encClassNameChars.length]; diff --git a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java index 3010b092..0802abe1 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java @@ -1,12 +1,14 @@ package me.itzsomebody.radon.transformers; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import me.itzsomebody.radon.utils.CustomRegexUtils; import org.objectweb.asm.Opcodes; import org.objectweb.asm.commons.CodeSizeEvaluator; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import me.itzsomebody.radon.utils.CustomRegexUtils; - -import java.util.*; /** * Abstract class used to make transformers. diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java index fb011282..8008bcd8 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java @@ -1,15 +1,23 @@ package me.itzsomebody.radon.transformers.flow; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.analyzer.StackAnalyzer; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.NumberUtils; import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.tree.*; - -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; /** * This transformer attempts to increase flow obsucurity by making additional diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java index 20083f9a..ed4f140b 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java @@ -1,15 +1,15 @@ package me.itzsomebody.radon.transformers.flow; -import me.itzsomebody.radon.utils.NumberUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.tree.*; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.utils.StringUtils; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; /** * Transformer that sets GOTO->LABEL instructions as a condition which is always true. diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java index fe3b3976..fdaed2a4 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java @@ -1,17 +1,21 @@ package me.itzsomebody.radon.transformers.flow; +import java.util.Stack; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.analyzer.StackAnalyzer; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.NumberUtils; import me.itzsomebody.radon.utils.StringUtils; - -import java.util.Stack; -import java.util.concurrent.atomic.AtomicInteger; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; /** * Transformer that applies multiple (skidded) flow obfuscations. diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java index bc2382ab..74a13a21 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java @@ -1,19 +1,20 @@ package me.itzsomebody.radon.transformers.invokedynamic; -import org.objectweb.asm.Handle; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.methods.InvokeDynamicBSM; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.StringUtils; - -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.TypeInsnNode; /** * Transformer that applies an InvokeDynamic obfuscation to field and diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java index 1b7c56f3..e2edaefc 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java @@ -1,16 +1,18 @@ package me.itzsomebody.radon.transformers.invokedynamic; -import org.objectweb.asm.Handle; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.methods.InvokeDynamicBSM; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.StringUtils; - -import java.util.concurrent.atomic.AtomicInteger; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.TypeInsnNode; /** * Transformer that applies an InvokeDynamic obfuscation which diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java index 9a5a0864..4a19f401 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java @@ -1,16 +1,18 @@ package me.itzsomebody.radon.transformers.invokedynamic; -import org.objectweb.asm.Handle; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.methods.InvokeDynamicBSM; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.StringUtils; - -import java.util.concurrent.atomic.AtomicInteger; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.TypeInsnNode; /** * Transformer that applies an InvokeDynamic which attempts to prevent diff --git a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java index 37f455ff..af815ccf 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java +++ b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java @@ -1,14 +1,12 @@ package me.itzsomebody.radon.transformers.linenumbers; -import org.objectweb.asm.tree.*; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.NumberUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.LineNumberNode; /** * Transformer that applies a line number obfuscation by changing the diff --git a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java index 2a7187c3..bba079ea 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java +++ b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java @@ -1,13 +1,11 @@ package me.itzsomebody.radon.transformers.linenumbers; -import org.objectweb.asm.tree.*; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.LineNumberNode; /** * Transformer that applies a line number obfuscation by removing them. diff --git a/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java b/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java index 62e579dd..4339e16f 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java +++ b/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java @@ -1,13 +1,10 @@ package me.itzsomebody.radon.transformers.localvariables; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.StringUtils; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - /** * Transformer that applies a local variable obfuscation by changing the names. * diff --git a/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java b/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java index cb4a35f2..784f1bb3 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java +++ b/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java @@ -1,12 +1,9 @@ package me.itzsomebody.radon.transformers.localvariables; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.LoggerUtils; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - /** * Transformer that applies a local variable obfuscation by removing t * diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java index d3f2b266..4579612d 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java @@ -1,12 +1,10 @@ package me.itzsomebody.radon.transformers.misc; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.StringUtils; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; - /** * Transformer that applies a crashing technique by exploiting class signature parsing. *

diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java index a3bccf57..6e3c62e5 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java @@ -1,11 +1,10 @@ package me.itzsomebody.radon.transformers.misc; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; -import java.util.concurrent.atomic.AtomicInteger; - /** * Transformer that adds an expiration block of code to methods. * diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java b/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java index 72e73aea..e26bea2e 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java @@ -1,11 +1,10 @@ package me.itzsomebody.radon.transformers.misc; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; -import java.util.concurrent.atomic.AtomicInteger; - /** * Transformer that applies a code hiding technique by applying synthetic modifiers to the class, fields, and methods. * Known to have problems with Spigot plugins with EventHandlers. diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/InnerClassRemover.java b/src/main/java/me/itzsomebody/radon/transformers/misc/InnerClassRemover.java index a4e2d444..814eecbe 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/InnerClassRemover.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/InnerClassRemover.java @@ -1,10 +1,9 @@ package me.itzsomebody.radon.transformers.misc; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.LoggerUtils; -import java.util.concurrent.atomic.AtomicInteger; - /** * Transformer which removes innerclass infomation. * diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java index deb4b818..6270e03d 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java @@ -1,14 +1,13 @@ package me.itzsomebody.radon.transformers.misc; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; -import org.objectweb.asm.tree.*; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.NumberUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; /** * Transformer that splits up integers into simple arithmetic evaluations. diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Shuffler.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Shuffler.java index a5f22c99..d4dbe153 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Shuffler.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/Shuffler.java @@ -1,10 +1,9 @@ package me.itzsomebody.radon.transformers.misc; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; - import java.util.Collections; import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.transformers.AbstractTransformer; +import me.itzsomebody.radon.utils.LoggerUtils; /** * Transformer which shuffles class members. diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java b/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java index 3ff18d74..11b574ad 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java @@ -1,15 +1,17 @@ package me.itzsomebody.radon.transformers.misc; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; -import org.objectweb.asm.Label; -import org.objectweb.asm.tree.*; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; +import org.objectweb.asm.Label; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; /** * Transformer that takes all the strings in a class and pools them into a diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java b/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java index 115aa023..f81743ed 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java @@ -1,11 +1,22 @@ package me.itzsomebody.radon.transformers.misc; +import me.itzsomebody.radon.utils.NumberUtils; +import me.itzsomebody.radon.utils.StringUtils; import org.objectweb.asm.Handle; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; -import me.itzsomebody.radon.utils.NumberUtils; -import me.itzsomebody.radon.utils.StringUtils; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.IincInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; /** * Not really a transformer. This "transformer" generates trash classes full diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/ClassTree.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/ClassTree.java index 5ad56458..c3c1c846 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/ClassTree.java +++ b/src/main/java/me/itzsomebody/radon/transformers/renamer/ClassTree.java @@ -1,12 +1,11 @@ package me.itzsomebody.radon.transformers.renamer; +import java.util.HashSet; +import java.util.Set; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.MethodNode; -import java.util.HashSet; -import java.util.Set; - /** * Specifies subclasses and parents of a class. * diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java index 724eb0b5..d4e8065d 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java @@ -1,5 +1,10 @@ package me.itzsomebody.radon.transformers.renamer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; @@ -8,10 +13,9 @@ import org.objectweb.asm.commons.ClassRemapper; import org.objectweb.asm.commons.Remapper; import org.objectweb.asm.commons.SimpleRemapper; -import org.objectweb.asm.tree.*; - -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.MethodNode; /** * Transformer that renames classes and their members. diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java b/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java index 765ebd54..e7011fcc 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java +++ b/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java @@ -1,13 +1,10 @@ package me.itzsomebody.radon.transformers.sourcedebug; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.StringUtils; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - /** * Transformer that obfuscates the source debug attribute by changing the * corresponding value. diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/RemoveSourceDebug.java b/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/RemoveSourceDebug.java index 1a1db406..3cd00e8b 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/RemoveSourceDebug.java +++ b/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/RemoveSourceDebug.java @@ -1,12 +1,9 @@ package me.itzsomebody.radon.transformers.sourcedebug; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.LoggerUtils; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - /** * Transformer that obfuscates the source debug attribute by changing the * corresponding value. diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java b/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java index 27c82225..c194fcdc 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java +++ b/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java @@ -1,13 +1,10 @@ package me.itzsomebody.radon.transformers.sourcename; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.StringUtils; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - /** * Transformer that obfuscates the source name attribute by changing the * corresponding value. diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcename/RemoveSourceName.java b/src/main/java/me/itzsomebody/radon/transformers/sourcename/RemoveSourceName.java index f6c64ff8..d91c6ad0 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcename/RemoveSourceName.java +++ b/src/main/java/me/itzsomebody/radon/transformers/sourcename/RemoveSourceName.java @@ -1,12 +1,9 @@ package me.itzsomebody.radon.transformers.sourcename; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.LoggerUtils; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - /** * Transformer that obfuscates the source name attribute by removing the * attribute entirely. diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java index 0ad537ff..16601c63 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java @@ -1,10 +1,10 @@ package me.itzsomebody.radon.transformers.stringencryption; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.methods.StringEncryption; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.NumberUtils; import me.itzsomebody.radon.utils.StringUtils; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; @@ -12,8 +12,6 @@ import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; -import java.util.concurrent.atomic.AtomicInteger; - public class HeavyStringEncryption extends AbstractTransformer { /** * Indication to not encrypt strings containing Spigot placeholders diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java index a4076b2e..107f3117 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java @@ -1,17 +1,16 @@ package me.itzsomebody.radon.transformers.stringencryption; -import me.itzsomebody.radon.utils.NumberUtils; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.methods.StringEncryption; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.NumberUtils; import me.itzsomebody.radon.utils.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; /** * Transformer that encrypts strings using a stacktrace-backed method. diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java index db6ee342..96e01915 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java @@ -1,17 +1,17 @@ package me.itzsomebody.radon.transformers.stringencryption; -import me.itzsomebody.radon.utils.NumberUtils; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.methods.StringEncryption; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.NumberUtils; import me.itzsomebody.radon.utils.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; /** * Transformer that encrypts strings the same way {@link LightStringEncryption} diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java index 9149b7ec..ed31534d 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java @@ -1,17 +1,15 @@ package me.itzsomebody.radon.transformers.stringencryption; -import me.itzsomebody.radon.utils.NumberUtils; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; +import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.methods.StringEncryption; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.NumberUtils; import me.itzsomebody.radon.utils.StringUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; /** * Transformer that encrypts strings using an extremely simple XOR algorithm. diff --git a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java index 2ffa3b10..4f2ebc85 100644 --- a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java @@ -2,7 +2,17 @@ import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TypeInsnNode; /** * Utils used for operating on bytecode. diff --git a/src/main/java/me/itzsomebody/radon/utils/FileUtils.java b/src/main/java/me/itzsomebody/radon/utils/FileUtils.java index 70971ab5..af4b61ef 100644 --- a/src/main/java/me/itzsomebody/radon/utils/FileUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/FileUtils.java @@ -2,7 +2,6 @@ import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.util.zip.ZipOutputStream; /** @@ -37,7 +36,7 @@ public static String renameExistingFile(File existing) { /** * Writes a bytes to a {@link ZipOutputStream}. * - * @param zos the {@link ZipOutputStream} to write to. + * @param zos the {@link ZipOutputStream} to write to. * @param data bytes to write to output * @throws IOException if an error happens while writing to output stream. */ diff --git a/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java b/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java index 0b890f36..faa7e194 100644 --- a/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java @@ -1,13 +1,13 @@ package me.itzsomebody.radon.utils; -import me.itzsomebody.radon.Radon; - -import java.io.*; -import java.nio.charset.StandardCharsets; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; +import me.itzsomebody.radon.Radon; /** * Utils to print fancy stuff in the console and to write log file. diff --git a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java index be66b0c3..3e961015 100644 --- a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java @@ -1,11 +1,17 @@ package me.itzsomebody.radon.utils; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; +import java.util.Collection; +import java.util.List; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; -import java.security.MessageDigest; -import java.util.*; - -import me.itzsomebody.radon.transformers.stringencryption.*; +import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; +import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; +import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; +import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; /** * Utils for operating, and generating {@link String}s. diff --git a/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java b/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java index 1d68a771..aae8145a 100644 --- a/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java @@ -1,8 +1,5 @@ package me.itzsomebody.radon.utils; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.tree.ClassNode; - import java.io.File; import java.io.InputStream; import java.util.ArrayList; @@ -10,6 +7,8 @@ import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; /** * Watermarking utils for the obfuscator. From c54c9380222124f49185a781b13a536ccc0014d4 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Fri, 11 May 2018 13:09:46 -0700 Subject: [PATCH 004/281] Different way of determining how to set ClassWriter flags --- .../itzsomebody/radon/internal/Bootstrap.java | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index cdcd2925..0020405a 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -235,41 +235,41 @@ public void startTheParty(boolean doInit) throws Throwable { this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Writing classes to output")); for (ClassNode classNode : this.classes.values()) { - ClassWriter cw = new CustomClassWriter(ClassWriter.COMPUTE_FRAMES); - - if (this.watermarkMsg != null) { - if (this.watermarkType == 0 - && NumberUtils.getRandomInt(10) >= 5) { - cw.newUTF8("WMID: " - + StringUtils.aesEncrypt(this.watermarkMsg, this.watermarkKey)); - - this.logStrings.add(LoggerUtils.stdOut("Watermarking " - + this.watermarkMsg + " into " + classNode.name)); - } else if (this.watermarkType == 1 - && NumberUtils.getRandomInt(10) >= 5) { - classNode.signature = - StringUtils.aesEncrypt("WMID: " + this.watermarkMsg, - this.watermarkKey); - - this.logStrings.add(LoggerUtils.stdOut("Watermarking " - + this.watermarkMsg + " into " + classNode.name)); - } + ClassWriter cw; + + if (classNode.version > Opcodes.V1_5) { + cw = new CustomClassWriter(ClassWriter.COMPUTE_FRAMES); + } else { + cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); } - cw.newUTF8("RADON" + Radon.VERSION); // :D try { classNode.accept(cw); - } catch (Throwable t) { - if (t.getMessage() != null - && t.getMessage().contains("JSR/RET")) { - cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); - classNode.accept(cw); - } else { - this.logStrings.add(LoggerUtils - .stdOut("Error while writing " - + classNode.name + " -> " + t.getMessage())); - throw t; + if (this.watermarkMsg != null) { + if (this.watermarkType == 0 + && NumberUtils.getRandomInt(10) >= 5) { + cw.newUTF8("WMID: " + + StringUtils.aesEncrypt(this.watermarkMsg, this.watermarkKey)); + + this.logStrings.add(LoggerUtils.stdOut("Watermarking " + + this.watermarkMsg + " into " + classNode.name)); + } else if (this.watermarkType == 1 + && NumberUtils.getRandomInt(10) >= 5) { + classNode.signature = + StringUtils.aesEncrypt("WMID: " + this.watermarkMsg, + this.watermarkKey); + + this.logStrings.add(LoggerUtils.stdOut("Watermarking " + + this.watermarkMsg + " into " + classNode.name)); + } } + + cw.newUTF8("RADON" + Radon.VERSION); // :D + } catch (Throwable t) { + this.logStrings.add(LoggerUtils + .stdOut("Error while writing " + + classNode.name + " -> " + t.getMessage())); + throw t; } ZipEntry newEntry = new ZipEntry(classNode.name From dfcdf22e0ff91b8397708bd289476c938b1bf135 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Fri, 11 May 2018 13:13:26 -0700 Subject: [PATCH 005/281] version change --- CHANGELOG.md | 5 +++++ pom.xml | 2 +- src/main/java/me/itzsomebody/radon/Radon.java | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acccbf72..161ad320 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.7.0 + +* Completely rewrote StackAnalyzer. +* Changed some internals. + ## 0.6.1 * Fixed an issue with the invokedynamic transformers which sometimes caused programs to crash with an access exception. diff --git a/pom.xml b/pom.xml index e15e559e..bb7b1d30 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ me.itzsomebody Radon - 0.6.1 + 0.7.0 UTF-8 diff --git a/src/main/java/me/itzsomebody/radon/Radon.java b/src/main/java/me/itzsomebody/radon/Radon.java index de244046..3aaa33ae 100644 --- a/src/main/java/me/itzsomebody/radon/Radon.java +++ b/src/main/java/me/itzsomebody/radon/Radon.java @@ -14,7 +14,7 @@ public class Radon { * Static abuse variables xD */ public static String PREFIX = "[Radon]"; - public static String VERSION = "0.6.1"; + public static String VERSION = "0.7.0"; public static String AUTHORS = "ItzSomebody"; /** From bf9331963bbde151560d593a1f5b9f93f958aa83 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Fri, 11 May 2018 13:42:41 -0700 Subject: [PATCH 006/281] Lots of changes --- CHANGELOG.md | 5 + pom.xml | 7 +- src/main/java/me/itzsomebody/radon/Radon.java | 2 +- .../itzsomebody/radon/config/ConfigEnum.java | 35 +++ .../radon/config/ConfigWriter.java | 205 ++++++++++++++++ .../me/itzsomebody/radon/gui/MainGUI.java | 225 +++++++++++++++++- .../itzsomebody/radon/internal/Bootstrap.java | 56 +++-- .../transformers/AbstractTransformer.java | 26 ++ .../radon/transformers/renamer/Renamer.java | 29 ++- .../radon/utils/BytecodeUtils.java | 27 --- .../me/itzsomebody/radon/utils/FileUtils.java | 29 ++- .../resources/META-INF/commons-io-license.txt | 203 ---------------- 12 files changed, 580 insertions(+), 269 deletions(-) create mode 100644 src/main/java/me/itzsomebody/radon/config/ConfigEnum.java create mode 100644 src/main/java/me/itzsomebody/radon/config/ConfigWriter.java delete mode 100644 src/main/resources/META-INF/commons-io-license.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 161ad320..02484bc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.8.0 + +* Changed even more internals. +* Resources can now be processed by obfuscator. + ## 0.7.0 * Completely rewrote StackAnalyzer. diff --git a/pom.xml b/pom.xml index bb7b1d30..5a374dfc 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ me.itzsomebody Radon - 0.7.0 + 0.8.0 UTF-8 @@ -74,11 +74,6 @@ - - commons-io - commons-io - 2.6 - org.yaml snakeyaml diff --git a/src/main/java/me/itzsomebody/radon/Radon.java b/src/main/java/me/itzsomebody/radon/Radon.java index 3aaa33ae..7ea03992 100644 --- a/src/main/java/me/itzsomebody/radon/Radon.java +++ b/src/main/java/me/itzsomebody/radon/Radon.java @@ -14,7 +14,7 @@ public class Radon { * Static abuse variables xD */ public static String PREFIX = "[Radon]"; - public static String VERSION = "0.7.0"; + public static String VERSION = "0.8.0"; public static String AUTHORS = "ItzSomebody"; /** diff --git a/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java b/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java new file mode 100644 index 00000000..66c95e16 --- /dev/null +++ b/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java @@ -0,0 +1,35 @@ +package me.itzsomebody.radon.config; + +/** + * Enums of config objects :D + * + * @author ItzSomebody + */ +public enum ConfigEnum { + INPUT, + OUTPUT, + LIBRARIES, + EXEMPTS, + STRING_ENCRYPTION, + FLOW_OBFUSCATION, + INVOKEDYNAMIC, + LOCAL_VARIABLES, + CRASHER, + HIDER, + STRING_POOL, + LINE_NUMBERS, + NUMBERS, + SOURCE_NAME, + SOURCE_DEBUG, + TRASH_CLASSES, + WATERMARK_MSG, + WATERMARK_KEY, + WATERMARK_TYPE, + SPIGOT_PLUGIN, + RENAMER, + EXPIRATION_TIME, + EXPIRATION_MESSAGE, + SHUFFLER, + DICTIONARY, + INNERCLASSES +} diff --git a/src/main/java/me/itzsomebody/radon/config/ConfigWriter.java b/src/main/java/me/itzsomebody/radon/config/ConfigWriter.java new file mode 100644 index 00000000..dc8eb7e5 --- /dev/null +++ b/src/main/java/me/itzsomebody/radon/config/ConfigWriter.java @@ -0,0 +1,205 @@ +package me.itzsomebody.radon.config; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Constructs a config in memory and writes to file. + * + * @author ItzSomebody + */ +public class ConfigWriter { + /** + * Key -> Value map. + */ + private Map keyValueMap; + + /** + * Lines to write to config. + */ + private List lines = new ArrayList<>(); + + /** + * Creates a new ConfigWriter object. + * + * @param keyValueMap Key -> Value map. + */ + public ConfigWriter(Map keyValueMap) { + this.keyValueMap = keyValueMap; + } + + /** + * Parses all options into a virtual config. + */ + public void parseOptions() { + Object result = this.keyValueMap.get(ConfigEnum.INPUT); + if (result != null) { + lines.add("Input: \"" + result.toString().replace("\\", "/") + "\""); + } + + result = this.keyValueMap.get(ConfigEnum.OUTPUT); + if (result != null) { + lines.add("Output: \"" + result.toString().replace("\\", "/") + "\""); + } + + result = this.keyValueMap.get(ConfigEnum.STRING_ENCRYPTION); + if (result != null) { + lines.add("StringEncryption: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.INVOKEDYNAMIC); + if (result != null) { + lines.add("InvokeDynamic: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.FLOW_OBFUSCATION); + if (result != null) { + lines.add("FlowObfuscation: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.LOCAL_VARIABLES); + if (result != null) { + lines.add("LocalVariableObfuscation: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.CRASHER); + if (result != null) { + lines.add("Crasher: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.HIDER); + if (result != null) { + lines.add("HideCode: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.STRING_POOL); + if (result != null) { + lines.add("StringPool: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.LINE_NUMBERS); + if (result != null) { + lines.add("LineNumberObfuscation: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.NUMBERS); + if (result != null) { + lines.add("NumberObfuscation: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.SOURCE_NAME); + if (result != null) { + lines.add("SourceNameObfuscation: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.SOURCE_DEBUG); + if (result != null) { + lines.add("SourceDebugObfuscation: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.TRASH_CLASSES); + if (result != null) { + lines.add("TrashClasses: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.WATERMARK_MSG); + if (result != null) { + lines.add("WatermarkMessage: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.WATERMARK_TYPE); + if (result != null) { + lines.add("WatermarkType: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.WATERMARK_KEY); + if (result != null) { + lines.add("WatermarkKey: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.SPIGOT_PLUGIN); + if (result != null) { + lines.add("SpigotPlugin: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.RENAMER); + if (result != null) { + lines.add("Renamer: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.EXPIRATION_TIME); + if (result != null) { + lines.add("ExpiryTime: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.EXPIRATION_MESSAGE); + if (result != null) { + lines.add("ExpiryMessage: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.SHUFFLER); + if (result != null) { + lines.add("Shuffler: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.DICTIONARY); + if (result != null) { + lines.add("Dictionary: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.INNERCLASSES); + if (result != null) { + lines.add("InnerClassRemover: " + result); + } + + result = this.keyValueMap.get(ConfigEnum.LIBRARIES); + if (result != null) { + List libs = (List) result; + if (!libs.isEmpty()) { + lines.add("Libraries: "); + for (String lib : libs) { + lines.add(" - \"" + lib.replace("\\", "/") + "\""); + } + } + } + + result = this.keyValueMap.get(ConfigEnum.EXEMPTS); + if (result != null) { + List exempts = (List) result; + if (!exempts.isEmpty()) { + lines.add("Exempts: "); + for (String exempt : exempts) { + lines.add(" - \"" + exempt + "\""); + } + } + } + } + + /** + * Writes config to a file. + * + * @throws IOException if the file already exists, is an output or some + * other weird thing happens. + */ + public void writeConfig(String path) throws IOException { + File output = new File(path); + if (output.exists()) + throw new IOException(path + " already exists!"); + + if (output.isDirectory()) + throw new IOException(path + " needs to be a file, not a directory"); + + output.createNewFile(); + BufferedWriter stream = new BufferedWriter(new FileWriter(output)); + for (String line : this.lines) { + stream.write(line); + stream.write('\n'); + } + stream.close(); + } +} diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java index 2e51c128..92ee27eb 100644 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java @@ -10,9 +10,12 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.swing.*; import me.itzsomebody.radon.Radon; import me.itzsomebody.radon.config.Config; +import me.itzsomebody.radon.config.ConfigEnum; +import me.itzsomebody.radon.config.ConfigWriter; import me.itzsomebody.radon.internal.Bootstrap; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.transformers.flow.LightFlowObfuscation; @@ -1501,8 +1504,9 @@ public void run() { throw new IOException("Config file does " + "not exist."); + FileInputStream fis = new FileInputStream(config); Config configParser - = new Config(new FileInputStream(config)); + = new Config(fis); configParser.loadIntoMap(); configParser.sortExempts(); configParser.checkConfig(); @@ -1756,6 +1760,9 @@ public void run() { int dictionary = configParser.getDictionaryType(); dictionaryComboBox.setSelectedIndex(dictionary); + fis.close(); + + lastPath = chooser.getSelectedFile(); } catch (Throwable t) { JOptionPane.showMessageDialog(null, t.getMessage(), "Error", @@ -1770,6 +1777,222 @@ public void run() { btnLoadConfiguration.setToolTipText("Loads config for pre-defined " + "settings."); panel_6.add(btnLoadConfiguration); + JButton saveConfigButton = new JButton("Save configuration"); + saveConfigButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + JFileChooser chooser = new JFileChooser(); + chooser.setMultiSelectionEnabled(false); + chooser.setFileSelectionMode(0); + int result = chooser.showOpenDialog(frmRadonObfuscator); + if (result == 0) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + try { + Map settings = new HashMap<>(); + if (inputField.getText() != null + && !inputField.getText().isEmpty()) { + settings.put(ConfigEnum.INPUT, inputField.getText()); + } + + if (outputField.getText() != null + && !outputField.getText().isEmpty()) { + settings.put(ConfigEnum.OUTPUT, outputField.getText()); + } + + if (chckbxStringEncryption.isSelected()) { + switch (comboBox.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.STRING_ENCRYPTION, "SuperLight"); + break; + case 1: + settings.put(ConfigEnum.STRING_ENCRYPTION, "Light"); + break; + case 2: + settings.put(ConfigEnum.STRING_ENCRYPTION, "Normal"); + break; + case 3: + settings.put(ConfigEnum.STRING_ENCRYPTION, "Heavy"); + break; + } + } + + if (chckbxInvokeDynamic.isSelected()) { + switch (comboBox_1.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.INVOKEDYNAMIC, "Light"); + break; + case 1: + settings.put(ConfigEnum.INVOKEDYNAMIC, "Normal"); + break; + case 2: + settings.put(ConfigEnum.INVOKEDYNAMIC, "Heavy"); + break; + } + } + + if (chckbxFlow.isSelected()) { + switch (comboBox_2.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.FLOW_OBFUSCATION, "Light"); + break; + case 1: + settings.put(ConfigEnum.FLOW_OBFUSCATION, "Normal"); + break; + case 2: + settings.put(ConfigEnum.FLOW_OBFUSCATION, "Heavy"); + break; + } + } + + if (chckbxLocalVariables.isSelected()) { + switch (comboBox_3.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.LOCAL_VARIABLES, "Obfuscate"); + break; + case 1: + settings.put(ConfigEnum.LOCAL_VARIABLES, "Remove"); + break; + } + } + + if (chckbxCrasher.isSelected()) { + settings.put(ConfigEnum.CRASHER, "true"); + } + + if (chckbxHidecode.isSelected()) { + settings.put(ConfigEnum.HIDER, "true"); + } + + if (chckbxSpringPool.isSelected()) { + settings.put(ConfigEnum.STRING_POOL, "true"); + } + + if (chckbxLineObfuscation.isSelected()) { + switch (comboBox_5.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.LINE_NUMBERS, "Obfuscate"); + break; + case 1: + settings.put(ConfigEnum.LINE_NUMBERS, "Remove"); + break; + } + } + + if (chckbxNumberObfuscation.isSelected()) { + settings.put(ConfigEnum.NUMBERS, "true"); + } + + if (chckbxSourceName.isSelected()) { + switch (comboBox_123.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.SOURCE_NAME, "Obfuscate"); + break; + case 1: + settings.put(ConfigEnum.SOURCE_NAME, "Remove"); + break; + } + } + + if (chckbxSourceDebug.isSelected()) { + switch (comboBox_1234.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.SOURCE_DEBUG, "Obfuscate"); + break; + case 1: + settings.put(ConfigEnum.SOURCE_DEBUG, "Remove"); + break; + } + } + + if (chckbxTrashClasses.isSelected()) { + if (trashChanceField.getText() != null + && !trashChanceField.getText().isEmpty()) { + settings.put(ConfigEnum.TRASH_CLASSES, trashChanceField.getText()); + } + } + + if (chckbxAddWatermark.isSelected()) { + if (waterMarkMessageField.getText() != null + && !waterMarkMessageField.getText().isEmpty() + && watermarkPassword.getText() != null + && !watermarkPassword.getText().isEmpty()) { + switch (comboBox_05.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.WATERMARK_TYPE, "ConstantPool"); + break; + case 1: + settings.put(ConfigEnum.WATERMARK_TYPE, "Signature"); + break; + } + + settings.put(ConfigEnum.WATERMARK_MSG, waterMarkMessageField.getText()); + settings.put(ConfigEnum.WATERMARK_KEY, watermarkPassword.getText()); + } + } + + if (chckbxSpigotPlugin.isSelected()) { + settings.put(ConfigEnum.SPIGOT_PLUGIN, "true"); + } + + if (chckbxClassRenammer.isSelected()) { + settings.put(ConfigEnum.RENAMER, "true"); + } + + if (chckbxAddExpiration.isSelected()) { + if (expirationMessageField.getText() != null + && !expireMessageLabel.getText().isEmpty() + && expirationDateField.getText() != null + && !expirationDateField.getText().isEmpty()) { + settings.put(ConfigEnum.EXPIRATION_MESSAGE, expirationMessageField.getText()); + settings.put(ConfigEnum.EXPIRATION_TIME, expirationDateField.getText()); + } + } + + if (chckbxShuffler.isSelected()) { + settings.put(ConfigEnum.SHUFFLER, "true"); + } + + settings.put(ConfigEnum.DICTIONARY, String.valueOf(dictionaryComboBox.getSelectedIndex())); + + if (chckbxInnerClasses.isSelected()) { + settings.put(ConfigEnum.INNERCLASSES, "true"); + } + + List libs = new ArrayList<>(); + for (int i = 0; i < libList.size(); i++) { + String lib = libList.get(i); + libs.add(lib); + } + + settings.put(ConfigEnum.LIBRARIES, libs); + + List exempts = new ArrayList<>(); + for (int i = 0; i < exemptList.size(); i++) { + String exempt = exemptList.get(i); + exempts.add(exempt); + } + + settings.put(ConfigEnum.EXEMPTS, exempts); + + ConfigWriter writer = new ConfigWriter(settings); + writer.parseOptions(); + writer.writeConfig(chooser.getSelectedFile().getAbsolutePath()); + + lastPath = chooser.getSelectedFile(); + } catch (Throwable t) { + JOptionPane.showMessageDialog(null, + t.getMessage(), "Error", + JOptionPane.ERROR_MESSAGE); + t.printStackTrace(); + } + } + }); + } + } + }); + panel_6.add(saveConfigButton); this.frmRadonObfuscator.setVisible(true); } } diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index 0020405a..c6f38b4d 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -22,7 +22,6 @@ import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.NumberUtils; import me.itzsomebody.radon.utils.StringUtils; -import org.apache.commons.io.IOUtils; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; @@ -49,6 +48,11 @@ public class Bootstrap { // Eyyy bootstrap bill */ private Map extraClasses = new HashMap<>(); + /** + * Resources which "pass through" the obfuscator. + */ + private Map passThru = new HashMap<>(); + /** * Config object */ @@ -194,9 +198,9 @@ public void startTheParty(boolean doInit) throws Throwable { for (AbstractTransformer transformer : this.transformers) { if (transformer instanceof Renamer) { - transformer.init(this.classes, this.classPath, this.exempts, this.dictionary); + transformer.init(this.classes, this.classPath, this.passThru, this.exempts, this.dictionary); } else { - transformer.init(this.classes, this.exempts, this.dictionary); + transformer.init(this.classes, this.extraClasses, this.exempts, this.dictionary); } transformer.obfuscate(); this.logStrings.addAll(transformer.getLogStrings()); @@ -227,7 +231,8 @@ public void startTheParty(boolean doInit) throws Throwable { newEntry.setTime(this.currentTime); newEntry.setCompressedSize(-1); this.zos.putNextEntry(newEntry); - FileUtils.writeToZip(this.zos, cw.toByteArray()); + this.zos.write(cw.toByteArray()); + this.zos.closeEntry(); } } @@ -277,7 +282,19 @@ public void startTheParty(boolean doInit) throws Throwable { newEntry.setTime(this.currentTime); newEntry.setCompressedSize(-1); this.zos.putNextEntry(newEntry); - FileUtils.writeToZip(this.zos, cw.toByteArray()); + this.zos.write(cw.toByteArray()); + this.zos.closeEntry(); + } + + // Write resources to output + this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); + this.logStrings.add(LoggerUtils.stdOut("Writing resources to output")); + for (String name : this.passThru.keySet()) { + ZipEntry newEntry = new ZipEntry(name); + newEntry.setTime(this.currentTime); + this.zos.putNextEntry(newEntry); + this.zos.write(this.passThru.get(name)); + this.zos.closeEntry(); } this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); @@ -414,7 +431,7 @@ private void loadClassPath() throws RuntimeException { entries = zipFile.entries(); while (entries.hasMoreElements()) { zipEntry = entries.nextElement(); - if (zipEntry.getName().endsWith(".class")) { + if (zipEntry.getName().endsWith(".class") && !zipEntry.isDirectory()) { ClassReader cr = new ClassReader(zipFile .getInputStream(zipEntry)); ClassNode classNode = new ClassNode(); @@ -457,23 +474,20 @@ private void loadInput() throws RuntimeException { entries = zipFile.entries(); while (entries.hasMoreElements()) { zipEntry = entries.nextElement(); - if (zipEntry.getName().endsWith(".class")) { - ClassReader cr = new ClassReader(zipFile - .getInputStream(zipEntry)); - ClassNode classNode = new ClassNode(); - classNode.libraryNode = false; + if (!zipEntry.isDirectory()) { + if (zipEntry.getName().endsWith(".class")) { + ClassReader cr = new ClassReader(zipFile + .getInputStream(zipEntry)); + ClassNode classNode = new ClassNode(); + classNode.libraryNode = false; - // We will manually compute stack frames later - cr.accept(classNode, ClassReader.SKIP_FRAMES); + // We will manually compute stack frames later + cr.accept(classNode, ClassReader.SKIP_FRAMES); - this.classes.put(classNode.name, classNode); - } else { - ZipEntry newEntry = new ZipEntry(zipEntry); - newEntry.setTime(this.currentTime); - newEntry.setCompressedSize(-1); - this.zos.putNextEntry(newEntry); - FileUtils.writeToZip(zos, IOUtils.toByteArray(zipFile - .getInputStream(zipEntry))); + this.classes.put(classNode.name, classNode); + } else { + this.passThru.put(zipEntry.getName(), FileUtils.toByteArray(zipFile.getInputStream(zipEntry))); + } } } zipFile.close(); diff --git a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java index 0802abe1..8a348989 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java @@ -26,6 +26,11 @@ public abstract class AbstractTransformer implements Opcodes { */ private Map classPath; + /** + * Resources. + */ + protected Map passThru; + /** * Exempt information. */ @@ -72,6 +77,27 @@ public void init(Map classes, this.logStrings = new ArrayList<>(); } + /** + * The other-other init method. + * + * @param classes the classes. + * @param classPath the almighty classpath. (Bow down to it) + * @param passThru the manifest. + * @param exempts the exempted classes. + */ + public void init(Map classes, + Map classPath, + Map passThru, + List exempts, + int dictionary) { + this.classes = classes; + this.classPath = classPath; + this.exempts = exempts; + this.passThru = passThru; + this.dictionary = dictionary; + this.logStrings = new ArrayList<>(); + } + /** * Returns {@link AbstractTransformer#classes}. * diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java index d4e8065d..d1a71e67 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java @@ -1,5 +1,6 @@ package me.itzsomebody.radon.transformers.renamer; +import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -75,8 +76,7 @@ public void obfuscate() { } }); - if (!this.exempted(classNode.name, "Renamer") - && !BytecodeUtils.isMain(classNode, this.spigotMode)) { + if (!this.exempted(classNode.name, "Renamer")) { int packages = NumberUtils.getRandomInt(2) + 1; StringBuilder newName = new StringBuilder(); for (int i = 0; i < packages; i++) { @@ -114,6 +114,31 @@ public void obfuscate() { } this.logStrings.add(LoggerUtils.stdOut("Mapped " + counter + " members.")); + current = System.currentTimeMillis(); + + // Fix screw ups in resources. + this.logStrings.add(LoggerUtils.stdOut("Attempting to map class names in resources")); + AtomicInteger fixed = new AtomicInteger(); + passThru.forEach((name, byteArray) -> { + if (name.equals("META-INF/MANIFEST.MF") + || (name.equals("plugin.yml") && spigotMode)) { + String stringVer = new String(byteArray); + for (String mapping : mappings.keySet()) { + if (stringVer.contains(mapping.replace("/", "."))) { + stringVer = stringVer.replace(mapping.replace("/", "."), mappings.get(mapping).replace("/", ".")); + } + } + + try { + passThru.put(name, stringVer.getBytes("UTF-8")); + fixed.incrementAndGet(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + throw new RuntimeException(e.getMessage()); + } + } + }); + this.logStrings.add(LoggerUtils.stdOut("Mapped " + fixed + " names in resources. [" + tookThisLong(current) + "ms]")); this.logStrings.add(LoggerUtils.stdOut("Finished applying mappings. [" + String.valueOf(System.currentTimeMillis() - current) + "ms]")); } diff --git a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java index 4f2ebc85..0f2d3bcf 100644 --- a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java @@ -3,7 +3,6 @@ import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.IntInsnNode; @@ -20,32 +19,6 @@ * @author ItzSomebody */ public class BytecodeUtils { - /** - * Checks if the input class is a main method. - * - * @param clazz {@link ClassNode} to check for main methods. - * @param spigotMode if obfuscator should consider the input - * {@link ClassNode} as a Spigot/Bukkit/Bungee plugin. - * @return true if the input {@link ClassNode} contains a main method, - * false if not. - */ - public static boolean isMain(ClassNode clazz, boolean spigotMode) { - if (spigotMode) { - if (clazz.superName.equals("org/bukkit/plugin/java/JavaPlugin") - || clazz.superName.equals("net/md_5/bungee/api/plugin/Plugin")) { - return true; - } - } - - for (MethodNode methodNode : clazz.methods) { - if (methodNode.name.equals("main") - || methodNode.name.equals("premain")) { - return true; - } - } - return false; - } - /** * Returns access modifier without private or protected so that class * renaming works properly. diff --git a/src/main/java/me/itzsomebody/radon/utils/FileUtils.java b/src/main/java/me/itzsomebody/radon/utils/FileUtils.java index af4b61ef..496112d3 100644 --- a/src/main/java/me/itzsomebody/radon/utils/FileUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/FileUtils.java @@ -1,7 +1,9 @@ package me.itzsomebody.radon.utils; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.util.zip.ZipOutputStream; /** @@ -34,15 +36,26 @@ public static String renameExistingFile(File existing) { } /** - * Writes a bytes to a {@link ZipOutputStream}. + * Creates a byte array from a given {@link InputStream}. * - * @param zos the {@link ZipOutputStream} to write to. - * @param data bytes to write to output - * @throws IOException if an error happens while writing to output stream. + * @param in {@link InputStream} to convert to a byte array. + * @return a byte array from the inputted */ - public static void writeToZip(ZipOutputStream zos, byte[] data) - throws IOException { - zos.write(data); - zos.closeEntry(); + public static byte[] toByteArray(InputStream in) { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + while (in.available() > 0) { + int data = in.read(buffer); + out.write(buffer, 0, data); + } + + in.close(); + out.close(); + return out.toByteArray(); + } catch (IOException ioe) { + ioe.printStackTrace(); + throw new RuntimeException(ioe.getMessage()); + } } } diff --git a/src/main/resources/META-INF/commons-io-license.txt b/src/main/resources/META-INF/commons-io-license.txt deleted file mode 100644 index 6b0b1270..00000000 --- a/src/main/resources/META-INF/commons-io-license.txt +++ /dev/null @@ -1,203 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - From e17f4d3d43c332d0707447c45bc7f02303939988 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Wed, 16 May 2018 12:38:50 -0700 Subject: [PATCH 007/281] 0.8.1 - Heavy flow transformer + some other changes --- .../me/itzsomebody/radon/gui/MainGUI.java | 11 +- .../itzsomebody/radon/internal/Bootstrap.java | 97 ++++++++++-- .../flow/HeavyFlowObfuscation.java | 149 ++++++++++-------- .../flow/NormalFlowObfuscation.java | 71 +++++---- 4 files changed, 215 insertions(+), 113 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java index 92ee27eb..bc16aa38 100644 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java @@ -18,6 +18,7 @@ import me.itzsomebody.radon.config.ConfigWriter; import me.itzsomebody.radon.internal.Bootstrap; import me.itzsomebody.radon.transformers.AbstractTransformer; +import me.itzsomebody.radon.transformers.flow.HeavyFlowObfuscation; import me.itzsomebody.radon.transformers.flow.LightFlowObfuscation; import me.itzsomebody.radon.transformers.flow.NormalFlowObfuscation; import me.itzsomebody.radon.transformers.invokedynamic.HeavyInvokeDynamic; @@ -393,7 +394,7 @@ public void actionPerformed(ActionEvent e) { gbc_comboBox_2.gridx = 9; gbc_comboBox_2.gridy = 2; - String[] flows = {"Light", "Normal"}; + String[] flows = {"Light", "Normal", "Heavy"}; for (String s : flows) { comboBox_2.addItem(s); } @@ -1379,6 +1380,9 @@ protected Object doInBackground() throws Exception { case 1: transformers.add(new NormalFlowObfuscation()); break; + case 2: + transformers.add(new HeavyFlowObfuscation()); + break; } } if (chckbxSpringPool.isSelected()) { @@ -1569,6 +1573,11 @@ public void run() { chckbxFlow.setSelected(true); comboBox_2.setSelectedIndex(1); comboBox_2.setEnabled(true); + } else if (flowObfuscationMode + instanceof HeavyFlowObfuscation) { + chckbxFlow.setSelected(true); + comboBox_2.setSelectedIndex(2); + comboBox_2.setEnabled(true); } AbstractTransformer invokeDynamicMode = diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index c6f38b4d..abdce5f1 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -3,11 +3,15 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; @@ -17,6 +21,7 @@ import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.transformers.misc.Expiry; import me.itzsomebody.radon.transformers.misc.TrashClasses; +import me.itzsomebody.radon.transformers.renamer.ClassTree; import me.itzsomebody.radon.transformers.renamer.Renamer; import me.itzsomebody.radon.utils.FileUtils; import me.itzsomebody.radon.utils.LoggerUtils; @@ -53,6 +58,11 @@ public class Bootstrap { // Eyyy bootstrap bill */ private Map passThru = new HashMap<>(); + /** + * Class hiearchy. + */ + private Map hierarchy = new HashMap<>(); + /** * Config object */ @@ -218,6 +228,9 @@ public void startTheParty(boolean doInit) throws Throwable { + String.valueOf(this.trashClasses) + " trash classes")); } + this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); + this.createTrees(); + if (this.extraClasses.values().size() != 0) { this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Writing generated classes to output")); @@ -502,8 +515,44 @@ private void loadInput() throws RuntimeException { this.classPath.putAll(this.classes); } + /** + * Creates {@link ClassTree}s needed for renaming. + */ + private void createTrees() { + long executionTime = System.currentTimeMillis(); + this.logStrings.add(LoggerUtils.stdOut("Creating class hierarchy.")); + classPath.values().forEach(classNode -> { + classNode.methods.forEach(methodNode -> { + methodNode.owner = classNode.name; + }); + classNode.fields.forEach(fieldNode -> { + fieldNode.owner = classNode.name; + }); + ClassTree classTree = new ClassTree(classNode.name, classNode.libraryNode); + classTree.parentClasses.add(classNode.superName); + classTree.parentClasses.addAll(classNode.interfaces); + classes.values().forEach(anotherClass -> { + if (anotherClass.interfaces != null + && anotherClass.interfaces.contains(classNode.name)) { + classTree.subClasses.add(anotherClass.name); + } + + if (anotherClass.superName != null + && anotherClass.superName.equals(classNode.name)) { + classTree.subClasses.add(anotherClass.name); + } + }); + + classTree.methods.addAll(classNode.methods); + classTree.fields.addAll(classNode.fields); + hierarchy.put(classNode.name, classTree); + }); + this.logStrings.add(LoggerUtils.stdOut("Finished creating class hierarchy. [" + (System.currentTimeMillis() - executionTime) + "ms]")); + } + /** * CustomClassWriter that doesn't use the internal Java classpath. + * Concept taken from Java-Deobfuscator by samczsun * * @author ItzSomebody */ @@ -520,7 +569,16 @@ protected String getCommonSuperClass(final String type1, return "java/lang/Object"; } - return deriveCommonSuperName(type1, type2); + String first = deriveCommonSuperName(type1, type2); + String second = deriveCommonSuperName(type2, type1); + if (!first.equals("java/lang/Object")) { + return first; + } + if (!second.equals("java/lang/Object")) { + return second; + } + + return getCommonSuperClass(returnClazz(type1).superName, returnClazz(type2).superName); } /** @@ -533,23 +591,18 @@ protected String getCommonSuperClass(final String type1, private String deriveCommonSuperName(String type1, String type2) { ClassNode first = returnClazz(type1); ClassNode second = returnClazz(type2); - if (isAssignableFrom(first, second)) { return type1; - } - - if (isAssignableFrom(second, first)) { + } else if (isAssignableFrom(first, second)) { return type2; - } - - if ((first.access & Opcodes.ACC_INTERFACE) == 0 - || (second.access & Opcodes.ACC_INTERFACE) == 0) { + } else if (Modifier.isInterface(first.access) || Modifier.isInterface(second.access)) { return "java/lang/Object"; } else { do { - first = returnClazz(first.superName); + type1 = first.superName; + first = returnClazz(type1); } while (!isAssignableFrom(first, second)); - return first.name; + return type1; } } @@ -578,8 +631,26 @@ private ClassNode returnClazz(String ref) { * @return true/false based on if clazz1 is the superclass of clazz2. */ private boolean isAssignableFrom(ClassNode clazz1, ClassNode clazz2) { - return (clazz1.name.equals("java/lang/Object") - || clazz1.superName.equals(clazz2.name)); + if (clazz1.name.equals("java/lang/Object")) { + return true; + } + if (clazz1.name.equals(clazz2.name)) { + return true; + } + ClassTree firstTree = hierarchy.get(clazz1.name); + if (firstTree == null) { + throw new RuntimeException("Could not find " + clazz1.name + " in the built class hiearchy"); + } + Set children = new HashSet<>(); + LinkedList searchThese = new LinkedList<>(firstTree.subClasses); + while (!searchThese.isEmpty()) { + String s = searchThese.poll(); + if (children.add(s)) { + ClassTree tempTree = hierarchy.get(s); + searchThese.addAll(tempTree.subClasses); + } + } + return children.contains(clazz2.name); } } } diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java index 8008bcd8..b0f89f41 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java @@ -1,28 +1,27 @@ package me.itzsomebody.radon.transformers.flow; -import java.util.ArrayList; -import java.util.List; +import java.lang.reflect.Modifier; import java.util.Stack; import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.analyzer.StackAnalyzer; import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.NumberUtils; import me.itzsomebody.radon.utils.StringUtils; +import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LineNumberNode; +import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.VarInsnNode; /** - * This transformer attempts to increase flow obsucurity by making additional - * jumps to other inserted flow obfuscation instructions. - * TODO: Fix this + * Transformer that does the same as {@link NormalFlowObfuscation}, but with + * a couple extra fake jumps. * * @author ItzSomebody */ @@ -35,57 +34,63 @@ public void obfuscate() { long current = System.currentTimeMillis(); this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started heavy flow obfuscation transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { + classNodes().parallelStream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { FieldNode field = new FieldNode(ACC_PUBLIC + ACC_STATIC + ACC_FINAL, StringUtils.randomString(this.dictionary), "Z", null, null); classNode.fields.add(field); - classNode.methods.stream().filter(methodNode -> - !exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Flow") - && !methodNode.name.equals("") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { - methodNode.owner = classNode.name; + classNode.methods.parallelStream().filter(methodNode -> + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Flow") + && !Modifier.isAbstract(methodNode.access)).forEach(methodNode -> { int varIndex = methodNode.maxLocals; - List jumps = new ArrayList<>(); - AbstractInsnNode[] untouched = methodNode.instructions.toArray(); - LabelNode exitNode = exitLabel(methodNode); - for (AbstractInsnNode insn : untouched) { + methodNode.maxLocals++; + methodNode.owner = classNode.name; + AbstractInsnNode[] untouchedList = methodNode.instructions.toArray(); + LabelNode labelNode = exitLabel(methodNode); + boolean calledSuper = false; + for (AbstractInsnNode insn : untouchedList) { + if (this.methodSize(methodNode) > 60000) break; + if (methodNode.name.equals("")) { + if (insn instanceof MethodInsnNode) { + if (insn.getOpcode() == INVOKESPECIAL + && insn.getPrevious() instanceof VarInsnNode + && ((VarInsnNode) insn.getPrevious()).var == 0) { + calledSuper = true; + } + } + } if (insn != methodNode.instructions.getFirst() - && insn != methodNode.instructions.getLast()) { + && !(insn instanceof LineNumberNode)) { + if (methodNode.name.equals("") && !calledSuper) + continue; StackAnalyzer sa = new StackAnalyzer(methodNode, insn); Stack stack = sa.returnStackAtBreak(); if (stack.isEmpty()) { // We need to make sure stack is empty before making jumps methodNode.instructions.insertBefore(insn, new VarInsnNode(ILOAD, varIndex)); - JumpInsnNode jump = new JumpInsnNode(IFNE, exitNode); - jumps.add(jump); - methodNode.instructions.insertBefore(insn, jump); + methodNode.instructions.insertBefore(insn, + new JumpInsnNode(IFNE, labelNode)); counter.incrementAndGet(); } } - - if (insn.getOpcode() == GOTO) { - methodNode.instructions.insertBefore(insn, - new VarInsnNode(ILOAD, varIndex)); - methodNode.instructions.insertBefore(insn, - new InsnNode(ICONST_0)); - methodNode.instructions.insert(insn, - new InsnNode(ATHROW)); - methodNode.instructions.insert(insn, - new InsnNode(ACONST_NULL)); - methodNode.instructions.set(insn, - new JumpInsnNode(IF_ICMPEQ, - ((JumpInsnNode) insn).label)); - counter.incrementAndGet(); - } - } - - if (jumps.size() > 1) { - JumpInsnNode exitJump = jumps.get(NumberUtils.getRandomInt(jumps.size())); - LabelNode exitJumpLb = new LabelNode(); - methodNode.instructions.insertBefore(exitJump.getPrevious(), exitJumpLb); - jumps.remove(exitJump); - - for (JumpInsnNode jump : jumps) { - jump.label = exitJumpLb; + if (insn instanceof JumpInsnNode) { + if (insn.getOpcode() == GOTO) { + methodNode.instructions.insertBefore(insn, + new VarInsnNode(ILOAD, varIndex)); + methodNode.instructions.insertBefore(insn, + new InsnNode(ICONST_0)); + methodNode.instructions.insert(insn, + new InsnNode(ATHROW)); + methodNode.instructions.insert(insn, + new InsnNode(ACONST_NULL)); + methodNode.instructions.set(insn, + new JumpInsnNode(IF_ICMPEQ, + ((JumpInsnNode) insn).label)); + counter.incrementAndGet(); + } else if (insn.getOpcode() >= IFEQ + || insn.getOpcode() <= IF_ICMPLE) { + methodNode.instructions.insert(insn, new JumpInsnNode(IFNE, ((JumpInsnNode) insn).label)); + methodNode.instructions.insert(insn, new VarInsnNode(ILOAD, varIndex)); + counter.incrementAndGet(); + } } } methodNode.instructions.insertBefore(methodNode.instructions @@ -114,29 +119,37 @@ private LabelNode exitLabel(MethodNode methodNode) { AbstractInsnNode target = methodNode.instructions.getFirst(); methodNode.instructions.insertBefore(target, new JumpInsnNode(GOTO, escapeNode)); methodNode.instructions.insertBefore(target, lb); - if (methodNode.desc.endsWith(")V")) { - methodNode.instructions.insertBefore(target, new InsnNode(RETURN)); - } else if (methodNode.desc.endsWith(")B") - || methodNode.desc.endsWith(")S") - || methodNode.desc.endsWith(")I") - || methodNode.desc.endsWith(")Z") - || methodNode.desc.endsWith(")C")) { - methodNode.instructions.insertBefore(target, new InsnNode(ICONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(IRETURN)); - } else if (methodNode.desc.endsWith(")J")) { - methodNode.instructions.insertBefore(target, new InsnNode(LCONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(LRETURN)); - } else if (methodNode.desc.endsWith(")F")) { - methodNode.instructions.insertBefore(target, new InsnNode(FCONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(FRETURN)); - } else if (methodNode.desc.endsWith(")D")) { - methodNode.instructions.insertBefore(target, new InsnNode(DCONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(DRETURN)); - } else { - methodNode.instructions.insertBefore(target, new InsnNode(ACONST_NULL)); - methodNode.instructions.insertBefore(target, new InsnNode(ARETURN)); + Type returnType = Type.getReturnType(methodNode.desc); + switch (returnType.getSort()) { + case Type.VOID: + methodNode.instructions.insertBefore(target, new InsnNode(RETURN)); + break; + case Type.BOOLEAN: + case Type.CHAR: + case Type.BYTE: + case Type.SHORT: + case Type.INT: + methodNode.instructions.insertBefore(target, new InsnNode(ICONST_0)); + methodNode.instructions.insertBefore(target, new InsnNode(IRETURN)); + break; + case Type.LONG: + methodNode.instructions.insertBefore(target, new InsnNode(LCONST_0)); + methodNode.instructions.insertBefore(target, new InsnNode(LRETURN)); + break; + case Type.FLOAT: + methodNode.instructions.insertBefore(target, new InsnNode(FCONST_0)); + methodNode.instructions.insertBefore(target, new InsnNode(FRETURN)); + break; + case Type.DOUBLE: + methodNode.instructions.insertBefore(target, new InsnNode(DCONST_0)); + methodNode.instructions.insertBefore(target, new InsnNode(DRETURN)); + break; + default: + methodNode.instructions.insertBefore(target, new InsnNode(ACONST_NULL)); + methodNode.instructions.insertBefore(target, new InsnNode(ARETURN)); + break; } - methodNode.instructions.insert(target, escapeNode); + methodNode.instructions.insertBefore(target, escapeNode); return lb; } diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java index fdaed2a4..8429a7c5 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java @@ -1,24 +1,28 @@ package me.itzsomebody.radon.transformers.flow; +import java.lang.reflect.Modifier; import java.util.Stack; import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.analyzer.StackAnalyzer; import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.StringUtils; +import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LineNumberNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.VarInsnNode; /** - * Transformer that applies multiple (skidded) flow obfuscations. + * Transformer that does the same as {@link LightFlowObfuscation}, but also + * inserts conditionals which always evaluate to false where the stack is + * empty. * * @author ItzSomebody */ @@ -31,13 +35,13 @@ public void obfuscate() { long current = System.currentTimeMillis(); this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started normal flow obfuscation transformer")); - classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { + classNodes().parallelStream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { FieldNode field = new FieldNode(ACC_PUBLIC + ACC_STATIC + ACC_FINAL, StringUtils.randomString(this.dictionary), "Z", null, null); classNode.fields.add(field); - classNode.methods.stream().filter(methodNode -> + classNode.methods.parallelStream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Flow") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { + && !Modifier.isAbstract(methodNode.access)).forEach(methodNode -> { int varIndex = methodNode.maxLocals; methodNode.maxLocals++; methodNode.owner = classNode.name; @@ -56,10 +60,7 @@ public void obfuscate() { } } if (insn != methodNode.instructions.getFirst() - //&& !(insn instanceof LineNumberNode) - //&& insn.getPrevious() != null - //&& insn.getPrevious().getOpcode() != ASTORE - /*&& insn.getOpcode() != ASTORE*/) { + && !(insn instanceof LineNumberNode)) { if (methodNode.name.equals("") && !calledSuper) continue; StackAnalyzer sa = new StackAnalyzer(methodNode, insn); @@ -114,29 +115,37 @@ private LabelNode exitLabel(MethodNode methodNode) { AbstractInsnNode target = methodNode.instructions.getFirst(); methodNode.instructions.insertBefore(target, new JumpInsnNode(GOTO, escapeNode)); methodNode.instructions.insertBefore(target, lb); - if (methodNode.desc.endsWith(")V")) { - methodNode.instructions.insertBefore(target, new InsnNode(RETURN)); - } else if (methodNode.desc.endsWith(")B") - || methodNode.desc.endsWith(")S") - || methodNode.desc.endsWith(")I") - || methodNode.desc.endsWith(")Z") - || methodNode.desc.endsWith(")C")) { - methodNode.instructions.insertBefore(target, new InsnNode(ICONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(IRETURN)); - } else if (methodNode.desc.endsWith(")J")) { - methodNode.instructions.insertBefore(target, new InsnNode(LCONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(LRETURN)); - } else if (methodNode.desc.endsWith(")F")) { - methodNode.instructions.insertBefore(target, new InsnNode(FCONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(FRETURN)); - } else if (methodNode.desc.endsWith(")D")) { - methodNode.instructions.insertBefore(target, new InsnNode(DCONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(DRETURN)); - } else { - methodNode.instructions.insertBefore(target, new InsnNode(ACONST_NULL)); - methodNode.instructions.insertBefore(target, new InsnNode(ARETURN)); + Type returnType = Type.getReturnType(methodNode.desc); + switch (returnType.getSort()) { + case Type.VOID: + methodNode.instructions.insertBefore(target, new InsnNode(RETURN)); + break; + case Type.BOOLEAN: + case Type.CHAR: + case Type.BYTE: + case Type.SHORT: + case Type.INT: + methodNode.instructions.insertBefore(target, new InsnNode(ICONST_0)); + methodNode.instructions.insertBefore(target, new InsnNode(IRETURN)); + break; + case Type.LONG: + methodNode.instructions.insertBefore(target, new InsnNode(LCONST_0)); + methodNode.instructions.insertBefore(target, new InsnNode(LRETURN)); + break; + case Type.FLOAT: + methodNode.instructions.insertBefore(target, new InsnNode(FCONST_0)); + methodNode.instructions.insertBefore(target, new InsnNode(FRETURN)); + break; + case Type.DOUBLE: + methodNode.instructions.insertBefore(target, new InsnNode(DCONST_0)); + methodNode.instructions.insertBefore(target, new InsnNode(DRETURN)); + break; + default: + methodNode.instructions.insertBefore(target, new InsnNode(ACONST_NULL)); + methodNode.instructions.insertBefore(target, new InsnNode(ARETURN)); + break; } - methodNode.instructions.insert(target, escapeNode); + methodNode.instructions.insertBefore(target, escapeNode); return lb; } From 9d05ab34b53bd0045c155e0d11f66a1199c9b9ce Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Wed, 16 May 2018 12:41:48 -0700 Subject: [PATCH 008/281] Forgot to change maven project version again xD --- CHANGELOG.md | 6 ++++++ pom.xml | 2 +- src/main/java/me/itzsomebody/radon/Radon.java | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02484bc6..0bfddab9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.8.1 + +* Changed the CustomClassWriter a bit. +* Heavy Flow transformer now implemented into GUI. +* Changed up the way the heavy flow transformer works due to the old one not working whatsoever. + ## 0.8.0 * Changed even more internals. diff --git a/pom.xml b/pom.xml index 5a374dfc..2d6ec0e0 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ me.itzsomebody Radon - 0.8.0 + 0.8.1 UTF-8 diff --git a/src/main/java/me/itzsomebody/radon/Radon.java b/src/main/java/me/itzsomebody/radon/Radon.java index 7ea03992..3152ccc7 100644 --- a/src/main/java/me/itzsomebody/radon/Radon.java +++ b/src/main/java/me/itzsomebody/radon/Radon.java @@ -14,7 +14,7 @@ public class Radon { * Static abuse variables xD */ public static String PREFIX = "[Radon]"; - public static String VERSION = "0.8.0"; + public static String VERSION = "0.8.1"; public static String AUTHORS = "ItzSomebody"; /** From 6ce100a6c0378724bd00fa612db85ac7d9fe4896 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Sat, 19 May 2018 07:34:30 -0700 Subject: [PATCH 009/281] 0.8.2 - Warning about trash classes + spigot --- CHANGELOG.md | 4 ++++ src/main/java/me/itzsomebody/radon/gui/MainGUI.java | 4 ++++ src/main/java/me/itzsomebody/radon/internal/Bootstrap.java | 3 +++ 3 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bfddab9..3f5aed46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.8.2 + +* Added warning about mixing Spigot's anti-piracy and trash classes together. + ## 0.8.1 * Changed the CustomClassWriter a bit. diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java index bc16aa38..6f53e7dd 100644 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java @@ -1450,6 +1450,10 @@ protected Object doInBackground() throws Exception { int dictionary = dictionaryComboBox.getSelectedIndex(); + if (trashClasses != 1 && spigotMode) { + throw new RuntimeException("Trash classes are not compatible with Spigot's anti-piracy injection."); + } + new ConsoleGUI(); Bootstrap bootstrap = new Bootstrap( input, diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index abdce5f1..d7946327 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -418,6 +418,9 @@ private void init() throws RuntimeException { this.logStrings.add(LoggerUtils.stdOut("Output already exists, renamed to " + FileUtils.renameExistingFile(this.output))); } + if (this.trashClasses != 1 && this.config.getSpigotBool()) { + throw new RuntimeException("Trash classes are not compatible with Spigot's anti-piracy injection."); + } this.zos = new ZipOutputStream(new FileOutputStream(this.output)); } catch (Throwable t) { t.printStackTrace(); From af9a82bc105fd51ec0d6cd79f068b8934271be6a Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Sat, 19 May 2018 07:35:35 -0700 Subject: [PATCH 010/281] Changed version number to 0.8.2 --- pom.xml | 2 +- src/main/java/me/itzsomebody/radon/Radon.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2d6ec0e0..5f008607 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ me.itzsomebody Radon - 0.8.1 + 0.8.2 UTF-8 diff --git a/src/main/java/me/itzsomebody/radon/Radon.java b/src/main/java/me/itzsomebody/radon/Radon.java index 3152ccc7..ff86ea46 100644 --- a/src/main/java/me/itzsomebody/radon/Radon.java +++ b/src/main/java/me/itzsomebody/radon/Radon.java @@ -14,7 +14,7 @@ public class Radon { * Static abuse variables xD */ public static String PREFIX = "[Radon]"; - public static String VERSION = "0.8.1"; + public static String VERSION = "0.8.2"; public static String AUTHORS = "ItzSomebody"; /** From a66c15693f656fe2e963e8cd98f381041640090a Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Mon, 4 Jun 2018 13:07:12 -0700 Subject: [PATCH 011/281] Apply GPL --- src/main/java/me/itzsomebody/radon/Radon.java | 17 ++++++++++++++++ .../radon/analyzer/StackAnalyzer.java | 17 ++++++++++++++++ .../me/itzsomebody/radon/config/Config.java | 17 ++++++++++++++++ .../itzsomebody/radon/config/ConfigEnum.java | 17 ++++++++++++++++ .../radon/config/ConfigWriter.java | 17 ++++++++++++++++ .../me/itzsomebody/radon/gui/ConsoleGUI.java | 17 ++++++++++++++++ .../me/itzsomebody/radon/gui/MainGUI.java | 17 ++++++++++++++++ .../radon/gui/OutputStreamRedirect.java | 17 ++++++++++++++++ .../itzsomebody/radon/internal/Bootstrap.java | 17 ++++++++++++++++ .../me/itzsomebody/radon/internal/CLI.java | 17 ++++++++++++++++ .../internal/climessages/CLIMessages.java | 17 ++++++++++++++++ .../radon/methods/InvokeDynamicBSM.java | 17 ++++++++++++++++ .../radon/methods/StringEncryption.java | 17 ++++++++++++++++ .../radon/templates/HeavyInvokeDynamic.java | 17 ++++++++++++++++ .../templates/HeavyStringEncryption.java | 17 ++++++++++++++++ .../radon/templates/LightInvokeDynamic.java | 17 ++++++++++++++++ .../templates/LightStringEncryption.java | 17 ++++++++++++++++ .../radon/templates/NormalInvokeDynamic.java | 17 ++++++++++++++++ .../templates/NormalStringEncryption.java | 17 ++++++++++++++++ .../templates/SuperLightStringEncryption.java | 17 ++++++++++++++++ .../transformers/AbstractTransformer.java | 17 ++++++++++++++++ .../flow/HeavyFlowObfuscation.java | 17 ++++++++++++++++ .../flow/LightFlowObfuscation.java | 17 ++++++++++++++++ .../flow/NormalFlowObfuscation.java | 17 ++++++++++++++++ .../invokedynamic/HeavyInvokeDynamic.java | 17 ++++++++++++++++ .../invokedynamic/LightInvokeDynamic.java | 17 ++++++++++++++++ .../invokedynamic/NormalInvokeDynamic.java | 17 ++++++++++++++++ .../linenumbers/ObfuscateLineNumbers.java | 17 ++++++++++++++++ .../linenumbers/RemoveLineNumbers.java | 17 ++++++++++++++++ .../ObfuscateLocalVariables.java | 17 ++++++++++++++++ .../localvariables/RemoveLocalVariables.java | 17 ++++++++++++++++ .../radon/transformers/misc/Crasher.java | 17 ++++++++++++++++ .../radon/transformers/misc/Expiry.java | 17 ++++++++++++++++ .../radon/transformers/misc/HideCode.java | 17 ++++++++++++++++ .../transformers/misc/InnerClassRemover.java | 17 ++++++++++++++++ .../transformers/misc/NumberObfuscation.java | 17 ++++++++++++++++ .../radon/transformers/misc/Shuffler.java | 17 ++++++++++++++++ .../radon/transformers/misc/StringPool.java | 17 ++++++++++++++++ .../radon/transformers/misc/TrashClasses.java | 17 ++++++++++++++++ .../radon/transformers/renamer/ClassTree.java | 20 +++++++++++++++++++ .../radon/transformers/renamer/Renamer.java | 17 ++++++++++++++++ .../sourcedebug/ObfuscateSourceDebug.java | 17 ++++++++++++++++ .../sourcedebug/RemoveSourceDebug.java | 17 ++++++++++++++++ .../sourcename/ObfuscateSourceName.java | 17 ++++++++++++++++ .../sourcename/RemoveSourceName.java | 17 ++++++++++++++++ .../HeavyStringEncryption.java | 17 ++++++++++++++++ .../LightStringEncryption.java | 17 ++++++++++++++++ .../NormalStringEncryption.java | 17 ++++++++++++++++ .../SuperLightStringEncryption.java | 17 ++++++++++++++++ .../radon/utils/BytecodeUtils.java | 17 ++++++++++++++++ .../radon/utils/CustomRegexUtils.java | 17 ++++++++++++++++ .../me/itzsomebody/radon/utils/FileUtils.java | 17 ++++++++++++++++ .../itzsomebody/radon/utils/LoggerUtils.java | 17 ++++++++++++++++ .../itzsomebody/radon/utils/NumberUtils.java | 17 ++++++++++++++++ .../itzsomebody/radon/utils/OpcodeUtils.java | 17 ++++++++++++++++ .../itzsomebody/radon/utils/StringUtils.java | 17 ++++++++++++++++ .../radon/utils/WatermarkUtils.java | 17 ++++++++++++++++ 57 files changed, 972 insertions(+) diff --git a/src/main/java/me/itzsomebody/radon/Radon.java b/src/main/java/me/itzsomebody/radon/Radon.java index ff86ea46..8b2221e6 100644 --- a/src/main/java/me/itzsomebody/radon/Radon.java +++ b/src/main/java/me/itzsomebody/radon/Radon.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon; import me.itzsomebody.radon.gui.MainGUI; diff --git a/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java b/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java index fa57b253..cb47309b 100644 --- a/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java +++ b/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.analyzer; import java.util.EmptyStackException; diff --git a/src/main/java/me/itzsomebody/radon/config/Config.java b/src/main/java/me/itzsomebody/radon/config/Config.java index 647c9d08..80bf3ded 100644 --- a/src/main/java/me/itzsomebody/radon/config/Config.java +++ b/src/main/java/me/itzsomebody/radon/config/Config.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.config; import java.io.File; diff --git a/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java b/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java index 66c95e16..45002a95 100644 --- a/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java +++ b/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.config; /** diff --git a/src/main/java/me/itzsomebody/radon/config/ConfigWriter.java b/src/main/java/me/itzsomebody/radon/config/ConfigWriter.java index dc8eb7e5..f42d2f03 100644 --- a/src/main/java/me/itzsomebody/radon/config/ConfigWriter.java +++ b/src/main/java/me/itzsomebody/radon/config/ConfigWriter.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.config; import java.io.BufferedWriter; diff --git a/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java b/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java index 7a9f3f00..6216ee91 100644 --- a/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.gui; import java.awt.*; diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java index 6f53e7dd..1ad9a66e 100644 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.gui; import java.awt.*; diff --git a/src/main/java/me/itzsomebody/radon/gui/OutputStreamRedirect.java b/src/main/java/me/itzsomebody/radon/gui/OutputStreamRedirect.java index 9552bd29..e7b99785 100644 --- a/src/main/java/me/itzsomebody/radon/gui/OutputStreamRedirect.java +++ b/src/main/java/me/itzsomebody/radon/gui/OutputStreamRedirect.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.gui; import java.io.OutputStream; diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index d7946327..d6d0a6d1 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.internal; import java.io.File; diff --git a/src/main/java/me/itzsomebody/radon/internal/CLI.java b/src/main/java/me/itzsomebody/radon/internal/CLI.java index 94325cd6..4d87db1e 100644 --- a/src/main/java/me/itzsomebody/radon/internal/CLI.java +++ b/src/main/java/me/itzsomebody/radon/internal/CLI.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.internal; import java.io.File; diff --git a/src/main/java/me/itzsomebody/radon/internal/climessages/CLIMessages.java b/src/main/java/me/itzsomebody/radon/internal/climessages/CLIMessages.java index 6b13b687..7e25844d 100644 --- a/src/main/java/me/itzsomebody/radon/internal/climessages/CLIMessages.java +++ b/src/main/java/me/itzsomebody/radon/internal/climessages/CLIMessages.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.internal.climessages; import me.itzsomebody.radon.utils.LoggerUtils; diff --git a/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSM.java b/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSM.java index ea4ded4e..f9be7e34 100644 --- a/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSM.java +++ b/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSM.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.methods; import java.lang.invoke.ConstantCallSite; diff --git a/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java b/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java index d9ff9abb..12b7d349 100644 --- a/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.methods; import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; diff --git a/src/main/java/me/itzsomebody/radon/templates/HeavyInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/templates/HeavyInvokeDynamic.java index bd4b90d6..432784a5 100644 --- a/src/main/java/me/itzsomebody/radon/templates/HeavyInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/templates/HeavyInvokeDynamic.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.templates; import java.lang.invoke.ConstantCallSite; diff --git a/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java index 5cfb7322..d9b152a3 100644 --- a/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.templates; import java.security.MessageDigest; diff --git a/src/main/java/me/itzsomebody/radon/templates/LightInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/templates/LightInvokeDynamic.java index b8bd4922..7094eeb6 100644 --- a/src/main/java/me/itzsomebody/radon/templates/LightInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/templates/LightInvokeDynamic.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.templates; import java.lang.invoke.ConstantCallSite; diff --git a/src/main/java/me/itzsomebody/radon/templates/LightStringEncryption.java b/src/main/java/me/itzsomebody/radon/templates/LightStringEncryption.java index 7f5024ba..3058d5ad 100644 --- a/src/main/java/me/itzsomebody/radon/templates/LightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/templates/LightStringEncryption.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.templates; class LightStringEncryption { diff --git a/src/main/java/me/itzsomebody/radon/templates/NormalInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/templates/NormalInvokeDynamic.java index 48a17c60..4254d67d 100644 --- a/src/main/java/me/itzsomebody/radon/templates/NormalInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/templates/NormalInvokeDynamic.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.templates; import java.lang.invoke.ConstantCallSite; diff --git a/src/main/java/me/itzsomebody/radon/templates/NormalStringEncryption.java b/src/main/java/me/itzsomebody/radon/templates/NormalStringEncryption.java index f6613ee7..387d10a2 100644 --- a/src/main/java/me/itzsomebody/radon/templates/NormalStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/templates/NormalStringEncryption.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.templates; class NormalStringEncryption { diff --git a/src/main/java/me/itzsomebody/radon/templates/SuperLightStringEncryption.java b/src/main/java/me/itzsomebody/radon/templates/SuperLightStringEncryption.java index 2a9cb6ab..6ccd44b3 100644 --- a/src/main/java/me/itzsomebody/radon/templates/SuperLightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/templates/SuperLightStringEncryption.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.templates; class SuperLightStringEncryption { diff --git a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java index 8a348989..5b2ec797 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers; import java.util.ArrayList; diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java index b0f89f41..f46a6521 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.flow; import java.lang.reflect.Modifier; diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java index ed4f140b..311cf858 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.flow; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java index 8429a7c5..a5a1d358 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.flow; import java.lang.reflect.Modifier; diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java index 74a13a21..2a1eaf70 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.invokedynamic; import java.lang.reflect.Modifier; diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java index e2edaefc..6f97c69e 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.invokedynamic; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java index 4a19f401..ff4d52cf 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.invokedynamic; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java index af815ccf..b8e24611 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java +++ b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.linenumbers; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java index bba079ea..d5310d3a 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java +++ b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.linenumbers; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java b/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java index 4339e16f..02861bea 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java +++ b/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.localvariables; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java b/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java index 784f1bb3..1bf921d1 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java +++ b/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.localvariables; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java index a84ef680..271f591c 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.misc; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java index 6e3c62e5..9eeaa9de 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.misc; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java b/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java index e26bea2e..b79c57f2 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.misc; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/InnerClassRemover.java b/src/main/java/me/itzsomebody/radon/transformers/misc/InnerClassRemover.java index 814eecbe..5f87c183 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/InnerClassRemover.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/InnerClassRemover.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.misc; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java index 6270e03d..605a3429 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.misc; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Shuffler.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Shuffler.java index d4dbe153..64033206 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Shuffler.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/Shuffler.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.misc; import java.util.Collections; diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java b/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java index 11b574ad..37dabde8 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.misc; import java.util.ArrayList; diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java b/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java index f81743ed..9634d6c8 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.misc; import me.itzsomebody.radon.utils.NumberUtils; diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/ClassTree.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/ClassTree.java index c3c1c846..cc04b03b 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/ClassTree.java +++ b/src/main/java/me/itzsomebody/radon/transformers/renamer/ClassTree.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.renamer; import java.util.HashSet; @@ -17,6 +34,9 @@ public class ClassTree { */ public String className; + /** + * Attached class node. + */ public ClassNode classNode; /** diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java index d1a71e67..2a683d40 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.renamer; import java.io.UnsupportedEncodingException; diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java b/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java index e7011fcc..bd7c5751 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java +++ b/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.sourcedebug; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/RemoveSourceDebug.java b/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/RemoveSourceDebug.java index 3cd00e8b..8dacd247 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/RemoveSourceDebug.java +++ b/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/RemoveSourceDebug.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.sourcedebug; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java b/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java index c194fcdc..3c71e308 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java +++ b/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.sourcename; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcename/RemoveSourceName.java b/src/main/java/me/itzsomebody/radon/transformers/sourcename/RemoveSourceName.java index d91c6ad0..cea1753a 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcename/RemoveSourceName.java +++ b/src/main/java/me/itzsomebody/radon/transformers/sourcename/RemoveSourceName.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.sourcename; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java index 16601c63..5710cbf7 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.stringencryption; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java index 107f3117..8eaca058 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.stringencryption; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java index 96e01915..5a90b516 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.stringencryption; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java index ed31534d..3fc7124c 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.transformers.stringencryption; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java index 0f2d3bcf..1e06ae4a 100644 --- a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.utils; import org.objectweb.asm.Label; diff --git a/src/main/java/me/itzsomebody/radon/utils/CustomRegexUtils.java b/src/main/java/me/itzsomebody/radon/utils/CustomRegexUtils.java index d386119c..efcc96d6 100644 --- a/src/main/java/me/itzsomebody/radon/utils/CustomRegexUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/CustomRegexUtils.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.utils; /** diff --git a/src/main/java/me/itzsomebody/radon/utils/FileUtils.java b/src/main/java/me/itzsomebody/radon/utils/FileUtils.java index 496112d3..ac52e8bc 100644 --- a/src/main/java/me/itzsomebody/radon/utils/FileUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/FileUtils.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.utils; import java.io.ByteArrayOutputStream; diff --git a/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java b/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java index faa7e194..7059a896 100644 --- a/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.utils; import java.io.BufferedWriter; diff --git a/src/main/java/me/itzsomebody/radon/utils/NumberUtils.java b/src/main/java/me/itzsomebody/radon/utils/NumberUtils.java index 54f82b2d..f602b074 100644 --- a/src/main/java/me/itzsomebody/radon/utils/NumberUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/NumberUtils.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.utils; import java.util.concurrent.ThreadLocalRandom; diff --git a/src/main/java/me/itzsomebody/radon/utils/OpcodeUtils.java b/src/main/java/me/itzsomebody/radon/utils/OpcodeUtils.java index f1f0d61a..f7736ea8 100644 --- a/src/main/java/me/itzsomebody/radon/utils/OpcodeUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/OpcodeUtils.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.utils; import org.objectweb.asm.Opcodes; diff --git a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java index 3e961015..7b8995c9 100644 --- a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.utils; import java.security.MessageDigest; diff --git a/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java b/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java index aae8145a..be3b4a76 100644 --- a/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + package me.itzsomebody.radon.utils; import java.io.File; From df8d85bece9604316ad672e6d1df044ce50253c8 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Mon, 4 Jun 2018 13:16:05 -0700 Subject: [PATCH 012/281] License file --- src/main/resources/META-INF/license.txt | 674 ++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 src/main/resources/META-INF/license.txt diff --git a/src/main/resources/META-INF/license.txt b/src/main/resources/META-INF/license.txt new file mode 100644 index 00000000..1a3517aa --- /dev/null +++ b/src/main/resources/META-INF/license.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + Radon + Copyright (C) 2018 ItzSomebody + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Radon Copyright (C) 2018 ItzSomebody + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. From d388590b673fa0b5cfc395a3894e52547413fd1d Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Sun, 24 Jun 2018 09:14:47 -0700 Subject: [PATCH 013/281] Oops, didn't notice that --- .../radon/transformers/linenumbers/ObfuscateLineNumbers.java | 5 +++-- .../radon/transformers/linenumbers/RemoveLineNumbers.java | 5 +++-- .../transformers/localvariables/ObfuscateLocalVariables.java | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java index b8e24611..9b925c15 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java +++ b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java @@ -17,6 +17,7 @@ package me.itzsomebody.radon.transformers.linenumbers; +import java.lang.reflect.Modifier; import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; @@ -43,8 +44,8 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("Started line obfuscation transformer")); this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "LineNumbers")).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LineNumbers")) - .filter(methodNode -> !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LineNumbers") + && !Modifier.isAbstract(methodNode.access)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (insn instanceof LineNumberNode) { LineNumberNode lineNumberNode = (LineNumberNode) insn; diff --git a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java index d5310d3a..2d246f8f 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java +++ b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java @@ -17,6 +17,7 @@ package me.itzsomebody.radon.transformers.linenumbers; +import java.lang.reflect.Modifier; import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; @@ -41,8 +42,8 @@ public void obfuscate() { this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "LineNumbers")).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LineNumbers")) - .filter(methodNode -> !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LineNumbers") + && !Modifier.isAbstract(methodNode.access)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (insn instanceof LineNumberNode) { methodNode.instructions.remove(insn); diff --git a/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java b/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java index 02861bea..b0807661 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java +++ b/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java @@ -38,8 +38,8 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("Started local variable obfuscation transformer")); this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "LocalVars")).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LocalVars")) - .filter(methodNode -> methodNode.localVariables != null).forEach(methodNode -> { + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LocalVars") + && methodNode.localVariables != null).forEach(methodNode -> { methodNode.localVariables.forEach(localVariableNode -> { localVariableNode.name = StringUtils.crazyString(); counter.incrementAndGet(); From 4c26b2b6b5f38d3d42a51d66e8ae01a9866297ab Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Sun, 24 Jun 2018 09:19:39 -0700 Subject: [PATCH 014/281] Possible fix for HideCode? --- .../me/itzsomebody/radon/config/Config.java | 2 +- .../me/itzsomebody/radon/gui/MainGUI.java | 2 +- .../linenumbers/ObfuscateLineNumbers.java | 1 - .../localvariables/RemoveLocalVariables.java | 4 +- .../radon/transformers/misc/HideCode.java | 49 +++++++------------ .../radon/utils/BytecodeUtils.java | 32 ++++++++++++ 6 files changed, 54 insertions(+), 36 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/config/Config.java b/src/main/java/me/itzsomebody/radon/config/Config.java index 80bf3ded..4b0b079a 100644 --- a/src/main/java/me/itzsomebody/radon/config/Config.java +++ b/src/main/java/me/itzsomebody/radon/config/Config.java @@ -763,7 +763,7 @@ public AbstractTransformer getHideCodeType() "true/false"); boolean s = (Boolean) value; if (s) { - return new HideCode(getSpigotBool()); + return new HideCode(); } } else { throw new IllegalArgumentException("HideCode arg is null"); diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java index 1ad9a66e..93eb264d 100644 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java @@ -1452,7 +1452,7 @@ protected Object doInBackground() throws Exception { transformers.add(new Crasher()); } if (chckbxHidecode.isSelected()) { - transformers.add(new HideCode(spigotMode)); + transformers.add(new HideCode()); } int trashClasses = -1; diff --git a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java index 9b925c15..ae71b96b 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java +++ b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java @@ -20,7 +20,6 @@ import java.lang.reflect.Modifier; import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.NumberUtils; import org.objectweb.asm.tree.AbstractInsnNode; diff --git a/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java b/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java index 1bf921d1..45f2015a 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java +++ b/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java @@ -37,8 +37,8 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("Started local variable removal transformer")); this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "LocalVars")).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LocalVars")) - .filter(methodNode -> methodNode.localVariables != null).forEach(methodNode -> { + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LocalVars") + && methodNode.localVariables != null).forEach(methodNode -> { counter.addAndGet(methodNode.localVariables.size()); methodNode.localVariables = null; }); diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java b/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java index b79c57f2..cc5359aa 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java @@ -24,25 +24,10 @@ /** * Transformer that applies a code hiding technique by applying synthetic modifiers to the class, fields, and methods. - * Known to have problems with Spigot plugins with EventHandlers. * * @author ItzSomebody */ public class HideCode extends AbstractTransformer { - /** - * TODO: Indication to check for EventHandlers before attempting to add synthetic modifier. - */ - private boolean spigotMode; - - /** - * Constructor used to create a {@link HideCode} object. - * - * @param spigotMode TODO: indication to check for EventHandlers. - */ - public HideCode(boolean spigotMode) { - this.spigotMode = spigotMode; - } - /** * Applies obfuscation. */ @@ -52,32 +37,34 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started hide code transformer")); this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "HideCode")).forEach(classNode -> { - if (!BytecodeUtils.isSyntheticMethod(classNode.access)) { + if (!BytecodeUtils.isSyntheticMethod(classNode.access) + && !BytecodeUtils.hasAnnotations(classNode)) { classNode.access |= ACC_SYNTHETIC; counter.incrementAndGet(); } classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "HideCode")) - .forEach(methodNode -> { - boolean hidOnce = false; - if (!BytecodeUtils.isSyntheticMethod(methodNode.access)) { - methodNode.access |= ACC_SYNTHETIC; - hidOnce = true; - } + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "HideCode") + && !BytecodeUtils.hasAnnotations(methodNode)).forEach(methodNode -> { + boolean hidOnce = false; + if (!BytecodeUtils.isSyntheticMethod(methodNode.access)) { + methodNode.access |= ACC_SYNTHETIC; + hidOnce = true; + } - if (!BytecodeUtils.isBridgeMethod(methodNode.access) - && !methodNode.name.startsWith("<")) { - methodNode.access |= ACC_BRIDGE; - hidOnce = true; - } + if (!BytecodeUtils.isBridgeMethod(methodNode.access) + && !methodNode.name.startsWith("<")) { + methodNode.access |= ACC_BRIDGE; + hidOnce = true; + } - if (hidOnce) counter.incrementAndGet(); - }); + if (hidOnce) counter.incrementAndGet(); + }); if (classNode.fields != null) classNode.fields.stream().filter(fieldNode -> - !exempted(classNode.name + '.' + fieldNode.name, "HideCode")).forEach(fieldNode -> { + !exempted(classNode.name + '.' + fieldNode.name, "HideCode") + && !BytecodeUtils.hasAnnotations(fieldNode)).forEach(fieldNode -> { if (!BytecodeUtils.isSyntheticMethod(fieldNode.access)) { fieldNode.access |= ACC_SYNTHETIC; counter.incrementAndGet(); diff --git a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java index 1e06ae4a..eba6539f 100644 --- a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java @@ -20,6 +20,8 @@ import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.IntInsnNode; @@ -248,4 +250,34 @@ public static boolean containsGoto(MethodNode methodNode) { return false; } + + /** + * Returns true if provided {@link MethodNode} has any annotations. Otherwise, false. + * + * @param methodNode {@link MethodNode} to check. + * @return true if provided {@link MethodNode} has any annotations. Otherwise, false. + */ + public static boolean hasAnnotations(MethodNode methodNode) { + return (methodNode.visibleAnnotations != null && methodNode.visibleAnnotations.isEmpty()); + } + + /** + * Returns true if provided {@link FieldNode} has any annotations. Otherwise, false. + * + * @param fieldNode {@link FieldNode} to check. + * @return true if provided {@link FieldNode} has any annotations. Otherwise, false. + */ + public static boolean hasAnnotations(FieldNode fieldNode) { + return (fieldNode.visibleAnnotations != null && fieldNode.visibleAnnotations.isEmpty()); + } + + /** + * Returns true if provided {@link ClassNode} has any annotations. Otherwise, false. + * + * @param classNode {@link ClassNode} to check. + * @return true if provided {@link ClassNode} has any annotations. Otherwise, false. + */ + public static boolean hasAnnotations(ClassNode classNode) { + return (classNode.visibleAnnotations != null && classNode.visibleAnnotations.isEmpty()); + } } From d7724f6512e135cf31d4cc84379ef5ecc825a2c6 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Wed, 27 Jun 2018 10:54:25 -0700 Subject: [PATCH 015/281] 0.8.3 - Some bugfixes, still needs some work before release --- CHANGELOG.md | 5 ++++ pom.xml | 2 +- src/main/java/me/itzsomebody/radon/Radon.java | 2 +- .../me/itzsomebody/radon/gui/MainGUI.java | 2 +- .../transformers/AbstractTransformer.java | 12 ++++++++++ .../flow/HeavyFlowObfuscation.java | 6 ++--- .../flow/LightFlowObfuscation.java | 2 +- .../flow/NormalFlowObfuscation.java | 6 ++--- .../invokedynamic/HeavyInvokeDynamic.java | 2 +- .../invokedynamic/LightInvokeDynamic.java | 2 +- .../invokedynamic/NormalInvokeDynamic.java | 2 +- .../linenumbers/ObfuscateLineNumbers.java | 2 +- .../linenumbers/RemoveLineNumbers.java | 2 +- .../radon/transformers/misc/Expiry.java | 4 +++- .../radon/transformers/misc/HideCode.java | 8 +++---- .../transformers/misc/NumberObfuscation.java | 4 ++-- .../radon/transformers/misc/StringPool.java | 2 +- .../radon/transformers/renamer/Renamer.java | 2 +- .../HeavyStringEncryption.java | 2 +- .../LightStringEncryption.java | 2 +- .../NormalStringEncryption.java | 2 +- .../SuperLightStringEncryption.java | 2 +- .../radon/utils/BytecodeUtils.java | 24 ++++++------------- 23 files changed, 54 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f5aed46..ae263803 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.8.3 + +* Added compensation for the fact that methods with the native flag don't have instructions in them. +* Fixed the trash classes & spigot mode warning reported by kangarko. + ## 0.8.2 * Added warning about mixing Spigot's anti-piracy and trash classes together. diff --git a/pom.xml b/pom.xml index 5f008607..19d7417b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ me.itzsomebody Radon - 0.8.2 + 0.8.3 UTF-8 diff --git a/src/main/java/me/itzsomebody/radon/Radon.java b/src/main/java/me/itzsomebody/radon/Radon.java index 8b2221e6..7a13ab51 100644 --- a/src/main/java/me/itzsomebody/radon/Radon.java +++ b/src/main/java/me/itzsomebody/radon/Radon.java @@ -31,7 +31,7 @@ public class Radon { * Static abuse variables xD */ public static String PREFIX = "[Radon]"; - public static String VERSION = "0.8.2"; + public static String VERSION = "0.8.3"; public static String AUTHORS = "ItzSomebody"; /** diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java index 93eb264d..9812e4d8 100644 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java @@ -1467,7 +1467,7 @@ protected Object doInBackground() throws Exception { int dictionary = dictionaryComboBox.getSelectedIndex(); - if (trashClasses != 1 && spigotMode) { + if (chckbxTrashClasses.isSelected() && spigotMode) { throw new RuntimeException("Trash classes are not compatible with Spigot's anti-piracy injection."); } diff --git a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java index 5b2ec797..c19aaf1b 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java @@ -17,6 +17,7 @@ package me.itzsomebody.radon.transformers; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -29,6 +30,7 @@ /** * Abstract class used to make transformers. + * TODO: Allow dependency injection of class trees. * * @author ItzSomebody */ @@ -207,6 +209,16 @@ protected int methodSize(MethodNode methodNode) { return cse.getMaxSize(); } + /** + * Returns true if this is not either an abstract method, or a native method. + * + * @param methodNode the {@link MethodNode} to check. + * @return true if this is not either an abstract method, or a native method. + */ + protected boolean hasInstructions(MethodNode methodNode) { + return (Modifier.isNative(methodNode.access) || Modifier.isAbstract(methodNode.access)); + } + /** * Returns a {@link List} of {@link String}s that were outputted into the * console by transformer. diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java index f46a6521..e1e97513 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java @@ -51,13 +51,13 @@ public void obfuscate() { long current = System.currentTimeMillis(); this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started heavy flow obfuscation transformer")); - classNodes().parallelStream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { + classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { FieldNode field = new FieldNode(ACC_PUBLIC + ACC_STATIC + ACC_FINAL, StringUtils.randomString(this.dictionary), "Z", null, null); classNode.fields.add(field); - classNode.methods.parallelStream().filter(methodNode -> + classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Flow") - && !Modifier.isAbstract(methodNode.access)).forEach(methodNode -> { + && hasInstructions(methodNode)).forEach(methodNode -> { int varIndex = methodNode.maxLocals; methodNode.maxLocals++; methodNode.owner = classNode.name; diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java index 311cf858..e9db589f 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java @@ -50,7 +50,7 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("Started light flow obfuscation transformer.")); classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { String fieldName = StringUtils.randomString(this.dictionary); - classNode.methods.stream().filter(methodNode -> !BytecodeUtils.isAbstractMethod(methodNode.access) + classNode.methods.stream().filter(methodNode -> hasInstructions(methodNode) && !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Flow") && BytecodeUtils.containsGoto(methodNode)).forEach(methodNode -> { for (AbstractInsnNode ain : methodNode.instructions.toArray()) { diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java index a5a1d358..1899039c 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java @@ -52,13 +52,13 @@ public void obfuscate() { long current = System.currentTimeMillis(); this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started normal flow obfuscation transformer")); - classNodes().parallelStream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { + classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { FieldNode field = new FieldNode(ACC_PUBLIC + ACC_STATIC + ACC_FINAL, StringUtils.randomString(this.dictionary), "Z", null, null); classNode.fields.add(field); - classNode.methods.parallelStream().filter(methodNode -> + classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Flow") - && !Modifier.isAbstract(methodNode.access)).forEach(methodNode -> { + && hasInstructions(methodNode)).forEach(methodNode -> { int varIndex = methodNode.maxLocals; methodNode.maxLocals++; methodNode.owner = classNode.name; diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java index 2a1eaf70..782f8e44 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java @@ -80,7 +80,7 @@ public void obfuscate() { && classNode.version >= 51).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "InvokeDynamic") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { + && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (this.methodSize(methodNode) > 60000) break; if (insn instanceof MethodInsnNode) { diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java index 6f97c69e..00057495 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java @@ -66,7 +66,7 @@ public void obfuscate() { && classNode.version >= 51).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "InvokeDynamic") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { + && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (this.methodSize(methodNode) > 60000) break; if (insn instanceof MethodInsnNode diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java index ff4d52cf..88ca71e0 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java @@ -67,7 +67,7 @@ public void obfuscate() { && classNode.version >= 51).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "InvokeDynamic") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { + && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (this.methodSize(methodNode) > 60000) break; if (insn instanceof MethodInsnNode diff --git a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java index ae71b96b..62357f6e 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java +++ b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java @@ -44,7 +44,7 @@ public void obfuscate() { this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "LineNumbers")).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LineNumbers") - && !Modifier.isAbstract(methodNode.access)).forEach(methodNode -> { + && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (insn instanceof LineNumberNode) { LineNumberNode lineNumberNode = (LineNumberNode) insn; diff --git a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java index 2d246f8f..ffd02e81 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java +++ b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java @@ -43,7 +43,7 @@ public void obfuscate() { !this.exempted(classNode.name, "LineNumbers")).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LineNumbers") - && !Modifier.isAbstract(methodNode.access)).forEach(methodNode -> { + && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (insn instanceof LineNumberNode) { methodNode.instructions.remove(insn); diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java index 9eeaa9de..07a2fb90 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java @@ -62,7 +62,9 @@ public void obfuscate() { this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Expiry")).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Expiry") - && methodNode.name.equals("") && methodSize(methodNode) < 60000).forEach(methodNode -> { + && methodNode.name.equals("") + && methodSize(methodNode) < 60000 + && hasInstructions(methodNode)).forEach(methodNode -> { methodNode.instructions.insertBefore(methodNode.instructions.getFirst(), BytecodeUtils.returnExpiry(this.expiryTime, this.expiryMsg)); counter.incrementAndGet(); diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java b/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java index cc5359aa..fa41333b 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java @@ -37,7 +37,7 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started hide code transformer")); this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "HideCode")).forEach(classNode -> { - if (!BytecodeUtils.isSyntheticMethod(classNode.access) + if (!BytecodeUtils.isSynthetic(classNode.access) && !BytecodeUtils.hasAnnotations(classNode)) { classNode.access |= ACC_SYNTHETIC; counter.incrementAndGet(); @@ -47,12 +47,12 @@ public void obfuscate() { !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "HideCode") && !BytecodeUtils.hasAnnotations(methodNode)).forEach(methodNode -> { boolean hidOnce = false; - if (!BytecodeUtils.isSyntheticMethod(methodNode.access)) { + if (!BytecodeUtils.isSynthetic(methodNode.access)) { methodNode.access |= ACC_SYNTHETIC; hidOnce = true; } - if (!BytecodeUtils.isBridgeMethod(methodNode.access) + if (!BytecodeUtils.isBridge(methodNode.access) && !methodNode.name.startsWith("<")) { methodNode.access |= ACC_BRIDGE; hidOnce = true; @@ -65,7 +65,7 @@ public void obfuscate() { classNode.fields.stream().filter(fieldNode -> !exempted(classNode.name + '.' + fieldNode.name, "HideCode") && !BytecodeUtils.hasAnnotations(fieldNode)).forEach(fieldNode -> { - if (!BytecodeUtils.isSyntheticMethod(fieldNode.access)) { + if (!BytecodeUtils.isSynthetic(fieldNode.access)) { fieldNode.access |= ACC_SYNTHETIC; counter.incrementAndGet(); } diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java index 605a3429..dedf2513 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java @@ -43,8 +43,8 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("Started number obfuscation transformer")); this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Numbers")).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Numbers")) - .filter(methodNode -> !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Numbers") + && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (methodSize(methodNode) > 60000) break; if (BytecodeUtils.isIntInsn(insn)) { diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java b/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java index 37dabde8..9782fdd6 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java @@ -61,7 +61,7 @@ public void obfuscate() { List stringslist = new ArrayList<>(); classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringPool") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { + && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (insn instanceof LdcInsnNode) { Object cst = ((LdcInsnNode) insn).cst; diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java index 2a683d40..85df5b27 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java @@ -75,7 +75,7 @@ public void obfuscate() { long current = System.currentTimeMillis(); AtomicInteger counter = new AtomicInteger(); this.classNodes().forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> !BytecodeUtils.isNativeMethod(methodNode.access) + classNode.methods.stream().filter(methodNode -> !BytecodeUtils.isNative(methodNode.access) && !methodNode.name.equals("main") && !methodNode.name.equals("premain") && !methodNode.name.startsWith("<") diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java index 5710cbf7..8163b657 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java @@ -59,7 +59,7 @@ public void obfuscate() { this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { + && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (methodSize(methodNode) > 60000) break; if (insn instanceof LdcInsnNode) { diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java index 8eaca058..3ebd764f 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java @@ -64,7 +64,7 @@ public void obfuscate() { this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { + && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (methodSize(methodNode) > 60000) break; if (insn instanceof LdcInsnNode) { diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java index 5a90b516..ce8128c8 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java @@ -66,7 +66,7 @@ public void obfuscate() { this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { + && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (methodSize(methodNode) > 60000) break; if (insn instanceof LdcInsnNode) { diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java index 3fc7124c..cd735f79 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java @@ -63,7 +63,7 @@ public void obfuscate() { this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") - && !BytecodeUtils.isAbstractMethod(methodNode.access)).forEach(methodNode -> { + && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (methodSize(methodNode) > 60000) break; if (insn instanceof LdcInsnNode) { diff --git a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java index eba6539f..20d0d586 100644 --- a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java @@ -126,37 +126,27 @@ public static AbstractInsnNode getNumberInsn(long number) { * @param access method access to check. * @return true if access has native modifier. */ - public static boolean isNativeMethod(int access) { - return (access & Opcodes.ACC_NATIVE) != 0; - } - - /** - * Returns true if access has abstract modifier. - * - * @param access method access to check. - * @return true if access has abstract modifier. - */ - public static boolean isAbstractMethod(int access) { - return (access & Opcodes.ACC_ABSTRACT) != 0; + public static boolean isNative(int access) { + return (access & Opcodes.ACC_SYNTHETIC) != 0; } /** * Returns true if access has synthetic modifier. * * @param access method access to check. - * @return true if access has abstract modifier. + * @return true if access has synthetic modifier. */ - public static boolean isSyntheticMethod(int access) { + public static boolean isSynthetic(int access) { return (access & Opcodes.ACC_SYNTHETIC) != 0; } /** - * Returns true if access has bride modifier. + * Returns true if access has bridge modifier. * * @param access method access to check. - * @return true if access has abstract modifier. + * @return true if access has bridge modifier. */ - public static boolean isBridgeMethod(int access) { + public static boolean isBridge(int access) { return (access & Opcodes.ACC_BRIDGE) != 0; } From 15468b26af452de464e4613316720ad34a3eb8a3 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Wed, 27 Jun 2018 11:25:27 -0700 Subject: [PATCH 016/281] Oops, better fix that --- .../radon/transformers/AbstractTransformer.java | 2 +- .../radon/transformers/renamer/Renamer.java | 3 ++- .../java/me/itzsomebody/radon/utils/BytecodeUtils.java | 10 ---------- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java index c19aaf1b..f800afcb 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java @@ -216,7 +216,7 @@ protected int methodSize(MethodNode methodNode) { * @return true if this is not either an abstract method, or a native method. */ protected boolean hasInstructions(MethodNode methodNode) { - return (Modifier.isNative(methodNode.access) || Modifier.isAbstract(methodNode.access)); + return (!Modifier.isNative(methodNode.access) && !Modifier.isAbstract(methodNode.access)); } /** diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java index 85df5b27..07f085cb 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java @@ -18,6 +18,7 @@ package me.itzsomebody.radon.transformers.renamer; import java.io.UnsupportedEncodingException; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -75,7 +76,7 @@ public void obfuscate() { long current = System.currentTimeMillis(); AtomicInteger counter = new AtomicInteger(); this.classNodes().forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> !BytecodeUtils.isNative(methodNode.access) + classNode.methods.stream().filter(methodNode -> !Modifier.isNative(methodNode.access) && !methodNode.name.equals("main") && !methodNode.name.equals("premain") && !methodNode.name.startsWith("<") diff --git a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java index 20d0d586..f7da9c41 100644 --- a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java @@ -120,16 +120,6 @@ public static AbstractInsnNode getNumberInsn(long number) { } } - /** - * Returns true if access has native modifier. - * - * @param access method access to check. - * @return true if access has native modifier. - */ - public static boolean isNative(int access) { - return (access & Opcodes.ACC_SYNTHETIC) != 0; - } - /** * Returns true if access has synthetic modifier. * From 4f27fa2022b6db8e58b8c005e7bb7874859621c0 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Fri, 29 Jun 2018 10:10:19 -0700 Subject: [PATCH 017/281] Cleanup of MainGUI class --- .../me/itzsomebody/radon/gui/MainGUI.java | 1967 ++++++++--------- 1 file changed, 927 insertions(+), 1040 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java index 9812e4d8..86c8fb1a 100644 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java @@ -150,29 +150,22 @@ private void initialize() { gbc_btnNewButton.insets = new Insets(0, 0, 5, 5); gbc_btnNewButton.gridx = 11; gbc_btnNewButton.gridy = 1; - btnNewButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JFileChooser chooser = new JFileChooser(); - if (inputField.getText() != null - && !inputField.getText().isEmpty()) { - chooser.setSelectedFile(new File(inputField.getText())); - } - chooser.setMultiSelectionEnabled(false); - chooser.setFileSelectionMode(0); - if (lastPath != null) - chooser.setCurrentDirectory(lastPath); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - inputField.setText(chooser.getSelectedFile() - .getAbsolutePath()); - lastPath = chooser.getSelectedFile(); - } - }); - } + btnNewButton.addActionListener((e) -> { + JFileChooser chooser = new JFileChooser(); + if (inputField.getText() != null + && !inputField.getText().isEmpty()) { + chooser.setSelectedFile(new File(inputField.getText())); + } + chooser.setMultiSelectionEnabled(false); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + if (lastPath != null) + chooser.setCurrentDirectory(lastPath); + int result = chooser.showOpenDialog(frmRadonObfuscator); + if (result == 0) { + SwingUtilities.invokeLater(() -> { + inputField.setText(chooser.getSelectedFile().getAbsolutePath()); + lastPath = chooser.getSelectedFile(); + }); } }); panel_4.add(btnNewButton, gbc_btnNewButton); @@ -202,29 +195,22 @@ public void run() { 5); gbc_btnNewButton_1.gridx = 11; gbc_btnNewButton_1.gridy = 2; - btnNewButton_1.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JFileChooser chooser = new JFileChooser(); - if (outputField.getText() != null - && !outputField.getText().isEmpty()) { - chooser.setSelectedFile(new File(outputField.getText())); - } - chooser.setMultiSelectionEnabled(false); - chooser.setFileSelectionMode(0); - if (lastPath != null) - chooser.setCurrentDirectory(lastPath); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - outputField.setText(chooser.getSelectedFile() - .getAbsolutePath()); - lastPath = chooser.getSelectedFile(); - } - }); - } + btnNewButton_1.addActionListener((e) -> { + JFileChooser chooser = new JFileChooser(); + if (outputField.getText() != null + && !outputField.getText().isEmpty()) { + chooser.setSelectedFile(new File(outputField.getText())); + } + chooser.setMultiSelectionEnabled(false); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + if (lastPath != null) + chooser.setCurrentDirectory(lastPath); + int result = chooser.showOpenDialog(frmRadonObfuscator); + if (result == 0) { + SwingUtilities.invokeLater(() -> { + outputField.setText(chooser.getSelectedFile().getAbsolutePath()); + lastPath = chooser.getSelectedFile(); + }); } }); panel_4.add(btnNewButton_1, gbc_btnNewButton_1); @@ -268,31 +254,25 @@ public void run() { scrollPane_2.setViewportView(list_2); JButton btnNewButton_6 = new JButton("Add"); - btnNewButton_6.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JFileChooser chooser = new JFileChooser(); - if (inputField.getText() != null - && !inputField.getText().isEmpty()) { - chooser.setSelectedFile(new File(inputField.getText())); - } - chooser.setMultiSelectionEnabled(true); - chooser.setFileSelectionMode(0); - if (lastPath != null) - chooser.setCurrentDirectory(lastPath); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - for (File file : chooser.getSelectedFiles()) { - libList.addElement(file.getAbsolutePath()); - } + btnNewButton_6.addActionListener((e) -> { + JFileChooser chooser = new JFileChooser(); + if (inputField.getText() != null + && !inputField.getText().isEmpty()) { + chooser.setSelectedFile(new File(inputField.getText())); + } + chooser.setMultiSelectionEnabled(true); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + if (lastPath != null) + chooser.setCurrentDirectory(lastPath); + int result = chooser.showOpenDialog(frmRadonObfuscator); + if (result == 0) { + SwingUtilities.invokeLater(() -> { + for (File file : chooser.getSelectedFiles()) { + libList.addElement(file.getAbsolutePath()); + } - lastPath = chooser.getSelectedFile(); - } - }); - } + lastPath = chooser.getSelectedFile(); + }); } }); GridBagConstraints gbc_btnNewButton_6 = new GridBagConstraints(); @@ -303,15 +283,13 @@ public void run() { panel_4.add(btnNewButton_6, gbc_btnNewButton_6); JButton btnNewButton_7 = new JButton("Remove"); - btnNewButton_7.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - List removeList = list_2.getSelectedValuesList(); - if (removeList.isEmpty()) - return; - - for (String s : removeList) { - libList.removeElement(s); - } + btnNewButton_7.addActionListener((e) -> { + List removeList = list_2.getSelectedValuesList(); + if (removeList.isEmpty()) + return; + + for (String s : removeList) { + libList.removeElement(s); } }); GridBagConstraints gbc_btnNewButton_7 = new GridBagConstraints(); @@ -345,7 +323,6 @@ public void actionPerformed(ActionEvent arg0) { for (String s : encryptions) { comboBox.addItem(s); } - panel.add(comboBox, gbc_comboBox); JCheckBox chckbxStringEncryption = new JCheckBox("String Encryption"); @@ -354,17 +331,12 @@ public void actionPerformed(ActionEvent arg0) { gbc_chckbxStringEncryption.insets = new Insets(0, 0, 5, 5); gbc_chckbxStringEncryption.gridx = 0; gbc_chckbxStringEncryption.gridy = 0; - chckbxStringEncryption.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxStringEncryption.isSelected()) { - comboBox.setEnabled(true); - } else if (!chckbxStringEncryption.isSelected()) { - comboBox.setEnabled(false); - } + chckbxStringEncryption.addActionListener((e) -> { + if (chckbxStringEncryption.isSelected()) { + comboBox.setEnabled(true); + } else if (!chckbxStringEncryption.isSelected()) { + comboBox.setEnabled(false); } - }); panel.add(chckbxStringEncryption, gbc_chckbxStringEncryption); @@ -379,7 +351,6 @@ public void actionPerformed(ActionEvent e) { for (String s : invokeDynamics) { comboBox_1.addItem(s); } - panel.add(comboBox_1, gbc_comboBox_1); JCheckBox chckbxInvokeDynamic = new JCheckBox("InvokeDynamic"); @@ -388,17 +359,12 @@ public void actionPerformed(ActionEvent e) { gbc_chckbxNewCheckBox_1.insets = new Insets(0, 0, 5, 5); gbc_chckbxNewCheckBox_1.gridx = 0; gbc_chckbxNewCheckBox_1.gridy = 1; - chckbxInvokeDynamic.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxInvokeDynamic.isSelected()) { - comboBox_1.setEnabled(true); - } else if (!chckbxInvokeDynamic.isSelected()) { - comboBox_1.setEnabled(false); - } + chckbxInvokeDynamic.addActionListener((e) -> { + if (chckbxInvokeDynamic.isSelected()) { + comboBox_1.setEnabled(true); + } else if (!chckbxInvokeDynamic.isSelected()) { + comboBox_1.setEnabled(false); } - }); panel.add(chckbxInvokeDynamic, gbc_chckbxNewCheckBox_1); @@ -410,12 +376,10 @@ public void actionPerformed(ActionEvent e) { gbc_comboBox_2.insets = new Insets(0, 0, 5, 5); gbc_comboBox_2.gridx = 9; gbc_comboBox_2.gridy = 2; - String[] flows = {"Light", "Normal", "Heavy"}; for (String s : flows) { comboBox_2.addItem(s); } - panel.add(comboBox_2, gbc_comboBox_2); JCheckBox chckbxFlow = new JCheckBox("Flow"); @@ -424,17 +388,12 @@ public void actionPerformed(ActionEvent e) { gbc_chckbxFlow.anchor = GridBagConstraints.WEST; gbc_chckbxFlow.gridx = 0; gbc_chckbxFlow.gridy = 2; - chckbxFlow.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxFlow.isSelected()) { - comboBox_2.setEnabled(true); - } else if (!chckbxFlow.isSelected()) { - comboBox_2.setEnabled(false); - } + chckbxFlow.addActionListener((e) -> { + if (chckbxFlow.isSelected()) { + comboBox_2.setEnabled(true); + } else if (!chckbxFlow.isSelected()) { + comboBox_2.setEnabled(false); } - }); panel.add(chckbxFlow, gbc_chckbxFlow); @@ -445,12 +404,10 @@ public void actionPerformed(ActionEvent e) { gbc_comboBox_3.insets = new Insets(0, 0, 5, 5); gbc_comboBox_3.gridx = 9; gbc_comboBox_3.gridy = 3; - String[] localVariables = {"Obfuscate", "Remove"}; for (String s : localVariables) { comboBox_3.addItem(s); } - panel.add(comboBox_3, gbc_comboBox_3); JCheckBox chckbxLocalVariables = new JCheckBox("Local Variables"); @@ -459,17 +416,12 @@ public void actionPerformed(ActionEvent e) { gbc_chckbxNewCheckBox_2.anchor = GridBagConstraints.WEST; gbc_chckbxNewCheckBox_2.gridx = 0; gbc_chckbxNewCheckBox_2.gridy = 3; - chckbxLocalVariables.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxLocalVariables.isSelected()) { - comboBox_3.setEnabled(true); - } else if (!chckbxLocalVariables.isSelected()) { - comboBox_3.setEnabled(false); - } + chckbxLocalVariables.addActionListener((e) -> { + if (chckbxLocalVariables.isSelected()) { + comboBox_3.setEnabled(true); + } else if (!chckbxLocalVariables.isSelected()) { + comboBox_3.setEnabled(false); } - }); panel.add(chckbxLocalVariables, gbc_chckbxNewCheckBox_2); @@ -492,17 +444,12 @@ public void actionPerformed(ActionEvent e) { gbc_chckbxNewCheckBox_3.anchor = GridBagConstraints.WEST; gbc_chckbxNewCheckBox_3.gridx = 0; gbc_chckbxNewCheckBox_3.gridy = 7; - chckbxTrashClasses.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxTrashClasses.isSelected()) { - trashChanceField.setEditable(true); - } else if (!chckbxTrashClasses.isSelected()) { - trashChanceField.setEditable(false); - } + chckbxTrashClasses.addActionListener((e) -> { + if (chckbxTrashClasses.isSelected()) { + trashChanceField.setEditable(true); + } else if (!chckbxTrashClasses.isSelected()) { + trashChanceField.setEditable(false); } - }); panel.add(chckbxTrashClasses, gbc_chckbxNewCheckBox_3); @@ -513,12 +460,10 @@ public void actionPerformed(ActionEvent e) { gbc_comboBox_4.insets = new Insets(0, 0, 5, 5); gbc_comboBox_4.gridx = 9; gbc_comboBox_4.gridy = 5; - String[] sourceNameTypes = {"Obfuscate", "Remove"}; for (String s : sourceNameTypes) { comboBox_123.addItem(s); } - panel.add(comboBox_123, gbc_comboBox_4); JCheckBox chckbxSourceName = new JCheckBox("Source Name"); @@ -527,14 +472,11 @@ public void actionPerformed(ActionEvent e) { gbc_chckbxNewCheckBox_123.insets = new Insets(0, 0, 5, 5); gbc_chckbxNewCheckBox_123.gridx = 0; gbc_chckbxNewCheckBox_123.gridy = 5; - chckbxSourceName.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxSourceName.isSelected()) { - comboBox_123.setEnabled(true); - } else { - comboBox_123.setEnabled(false); - } + chckbxSourceName.addActionListener((e) -> { + if (chckbxSourceName.isSelected()) { + comboBox_123.setEnabled(true); + } else { + comboBox_123.setEnabled(false); } }); panel.add(chckbxSourceName, gbc_chckbxNewCheckBox_123); @@ -546,7 +488,6 @@ public void actionPerformed(ActionEvent e) { gbc_comboBox1234.insets = new Insets(0, 0, 5, 5); gbc_comboBox1234.gridx = 9; gbc_comboBox1234.gridy = 6; - String[] sourceDebugTypes = {"Obfuscate", "Remove"}; for (String s : sourceDebugTypes) { comboBox_1234.addItem(s); @@ -559,14 +500,11 @@ public void actionPerformed(ActionEvent e) { gbc_SourceDebug.insets = new Insets(0, 0, 5, 5); gbc_SourceDebug.gridx = 0; gbc_SourceDebug.gridy = 6; - chckbxSourceDebug.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxSourceDebug.isSelected()) { - comboBox_1234.setEnabled(true); - } else { - comboBox_1234.setEnabled(false); - } + chckbxSourceDebug.addActionListener((e) -> { + if (chckbxSourceDebug.isSelected()) { + comboBox_1234.setEnabled(true); + } else { + comboBox_1234.setEnabled(false); } }); panel.add(chckbxSourceDebug, gbc_SourceDebug); @@ -578,12 +516,10 @@ public void actionPerformed(ActionEvent e) { gbc_comboBox_5.insets = new Insets(0, 0, 5, 5); gbc_comboBox_5.gridx = 9; gbc_comboBox_5.gridy = 4; - String[] lineTypes = {"Obfuscate", "Remove"}; for (String s : lineTypes) { comboBox_5.addItem(s); } - panel.add(comboBox_5, gbc_comboBox_5); JCheckBox chckbxLineObfuscation = new JCheckBox("Lines"); @@ -592,14 +528,11 @@ public void actionPerformed(ActionEvent e) { gbc_chckbxNewCheckBox_10.insets = new Insets(0, 0, 5, 5); gbc_chckbxNewCheckBox_10.gridx = 0; gbc_chckbxNewCheckBox_10.gridy = 4; - chckbxLineObfuscation.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (chckbxLineObfuscation.isSelected()) { - comboBox_5.setEnabled(true); - } else { - comboBox_5.setEnabled(false); - } + chckbxLineObfuscation.addActionListener((e) -> { + if (chckbxLineObfuscation.isSelected()) { + comboBox_5.setEnabled(true); + } else { + comboBox_5.setEnabled(false); } }); panel.add(chckbxLineObfuscation, gbc_chckbxNewCheckBox_10); @@ -750,21 +683,16 @@ public void actionPerformed(ActionEvent e) { gbc_chckbxNewCheckBox_8.insets = new Insets(0, 0, 5, 5); gbc_chckbxNewCheckBox_8.gridx = 0; gbc_chckbxNewCheckBox_8.gridy = 0; - chckbxAddWatermark.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - if (chckbxAddWatermark.isSelected()) { - watermarkPassword.setEnabled(true); - waterMarkMessageField.setEnabled(true); - comboBox_05.setEnabled(true); - } else if (!chckbxAddWatermark.isSelected()) { - watermarkPassword.setEnabled(false); - waterMarkMessageField.setEnabled(false); - comboBox_05.setEnabled(false); - } + chckbxAddWatermark.addActionListener((e) -> { + if (chckbxAddWatermark.isSelected()) { + watermarkPassword.setEnabled(true); + waterMarkMessageField.setEnabled(true); + comboBox_05.setEnabled(true); + } else if (!chckbxAddWatermark.isSelected()) { + watermarkPassword.setEnabled(false); + waterMarkMessageField.setEnabled(false); + comboBox_05.setEnabled(false); } - }); panel_2.add(chckbxAddWatermark, gbc_chckbxNewCheckBox_8); @@ -803,25 +731,19 @@ public void actionPerformed(ActionEvent arg0) { this.extractorInput.setColumns(10); JButton btnNewButton_4 = new JButton("Select"); - btnNewButton_4.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - JFileChooser chooser = new JFileChooser(); - if (extractorInput.getText() != null - && !extractorInput.getText().isEmpty()) { - chooser.setSelectedFile(new File(extractorInput.getText())); - } - chooser.setMultiSelectionEnabled(false); - chooser.setFileSelectionMode(0); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - extractorInput.setText(chooser.getSelectedFile() - .getAbsolutePath()); - } - }); - } + btnNewButton_4.addActionListener((e) -> { + JFileChooser chooser = new JFileChooser(); + if (extractorInput.getText() != null + && !extractorInput.getText().isEmpty()) { + chooser.setSelectedFile(new File(extractorInput.getText())); + } + chooser.setMultiSelectionEnabled(false); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + int result = chooser.showOpenDialog(frmRadonObfuscator); + if (result == 0) { + SwingUtilities.invokeLater(() -> + extractorInput.setText(chooser.getSelectedFile().getAbsolutePath()) + ); } }); GridBagConstraints gbc_btnNewButton_4 = new GridBagConstraints(); @@ -848,7 +770,7 @@ public void run() { gbc_passwordField_1.gridy = 9; panel_2.add(this.extractorKey, gbc_passwordField_1); - DefaultListModel listModel = new DefaultListModel(); + DefaultListModel listModel = new DefaultListModel<>(); JScrollPane scrollPane = new JScrollPane(); GridBagConstraints gbc_scrollPane = new GridBagConstraints(); @@ -859,7 +781,7 @@ public void run() { gbc_scrollPane.gridy = 10; panel_2.add(scrollPane, gbc_scrollPane); - JList list_1 = new JList(listModel); + JList list_1 = new JList<>(listModel); scrollPane.setViewportView(list_1); JButton btnNewButton_5 = new JButton("Extract"); @@ -867,50 +789,44 @@ public void run() { gbc_btnNewButton_5.insets = new Insets(0, 0, 5, 5); gbc_btnNewButton_5.gridx = 11; gbc_btnNewButton_5.gridy = 9; - btnNewButton_5.addActionListener(new ActionListener() { - - @SuppressWarnings("deprecation") - @Override - public void actionPerformed(ActionEvent arg0) { - listModel.clear(); - - if (extractorInput.getText() == null - || extractorInput.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, "No file specified!", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } + btnNewButton_5.addActionListener((e) -> { + listModel.clear(); + + if (extractorInput.getText() == null + || extractorInput.getText().isEmpty()) { + JOptionPane.showMessageDialog(null, "No file specified!", + "Error", JOptionPane.ERROR_MESSAGE); + return; + } - if (extractorKey.getText() == null || extractorKey.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, "No key entered!", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } + if (extractorKey.getPassword() == null || new String(extractorKey.getPassword()).isEmpty()) { + JOptionPane.showMessageDialog(null, "No key entered!", + "Error", JOptionPane.ERROR_MESSAGE); + return; + } - if (!extractorInput.getText().endsWith(".jar")) { - JOptionPane.showMessageDialog(null, - "Only Jars are allowed!", "Error", - JOptionPane.ERROR_MESSAGE); - return; + if (!extractorInput.getText().endsWith(".jar")) { + JOptionPane.showMessageDialog(null, + "Only Jars are allowed!", "Error", + JOptionPane.ERROR_MESSAGE); + return; + } + try { + File input = new File(extractorInput.getText()); + List foundIds = + WatermarkUtils.extractWatermark(input, + new String(extractorKey.getPassword())); + for (String s : foundIds) { + listModel.addElement(s); } - try { - File input = new File(extractorInput.getText()); - List foundIds = - WatermarkUtils.extractWatermark(input, - new String(extractorKey.getPassword())); - for (String s : foundIds) { - listModel.addElement(s); - } - JOptionPane.showMessageDialog(null, - "Finished! Found: " + - String.valueOf(foundIds.size()) + " IDs", - "Info", JOptionPane.INFORMATION_MESSAGE); - } catch (Throwable t) { - t.printStackTrace(); - } + JOptionPane.showMessageDialog(null, + "Finished! Found: " + + String.valueOf(foundIds.size()) + " IDs", + "Info", JOptionPane.INFORMATION_MESSAGE); + } catch (Throwable t) { + t.printStackTrace(); } - }); panel_2.add(btnNewButton_5, gbc_btnNewButton_5); @@ -969,19 +885,14 @@ public void actionPerformed(ActionEvent arg0) { gbc_AddExpiration.insets = new Insets(0, 0, 5, 5); gbc_AddExpiration.gridx = 0; gbc_AddExpiration.gridy = 0; - chckbxAddExpiration.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - if (chckbxAddExpiration.isSelected()) { - expirationDateField.setEnabled(true); - expirationMessageField.setEnabled(true); - } else if (!chckbxAddExpiration.isSelected()) { - expirationDateField.setEnabled(false); - expirationMessageField.setEnabled(false); - } + chckbxAddExpiration.addActionListener((e) -> { + if (chckbxAddExpiration.isSelected()) { + expirationDateField.setEnabled(true); + expirationMessageField.setEnabled(true); + } else if (!chckbxAddExpiration.isSelected()) { + expirationDateField.setEnabled(false); + expirationMessageField.setEnabled(false); } - }); otherPanel.add(chckbxAddExpiration, gbc_AddExpiration); @@ -1001,12 +912,10 @@ public void actionPerformed(ActionEvent arg0) { gbc_dictionaryComboBox.insets = new Insets(0, 0, 5, 5); gbc_dictionaryComboBox.gridx = 11; gbc_dictionaryComboBox.gridy = 5; - String[] dictionaries = {"0", "1", "2"}; for (String s : dictionaries) { dictionaryComboBox.addItem(s); } - otherPanel.add(dictionaryComboBox, gbc_dictionaryComboBox); JLabel chckbxDictionary = new JLabel("Dictionary:"); @@ -1023,18 +932,12 @@ public void actionPerformed(ActionEvent arg0) { gbc_garbageCollector.insets = new Insets(0, 0, 5, 5); gbc_garbageCollector.gridx = 11; gbc_garbageCollector.gridy = 6; - garbageCollector.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - JOptionPane.showMessageDialog(null, ((Runtime.getRuntime().maxMemory() / 1000000) - (Runtime.getRuntime().freeMemory() / 1000000)) + "mb in use before garbage collector."); - System.gc(); - } - }); - } - }); + garbageCollector.addActionListener((e) -> + SwingUtilities.invokeLater(() -> { + JOptionPane.showMessageDialog(null, ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1000000) + "mb in use before garbage collector."); + System.gc(); + }) + ); otherPanel.add(garbageCollector, gbc_garbageCollector); JPanel panel_3 = new JPanel(); @@ -1060,7 +963,6 @@ public void run() { "Flow", "LocalVars", "SourceName", "SourceDebug", "LineNumbers", "StringPool", "Crasher", "HideCode", "Numbers", "Shuffler", "InnerClasses", "Renamer", "Expiry"}; - for (String s : options) { comboBox_04.addItem(s); } @@ -1093,67 +995,64 @@ public void run() { this.exemptField.setColumns(10); JButton btnNewButton_2 = new JButton("Add"); - btnNewButton_2.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (!exemptField.getText().equals("") - && exemptField.getText() != null - && !exemptField.getText().isEmpty()) { - if (comboBox_04.getSelectedIndex() == 0) { - exemptList.addElement("Class: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 1) { - exemptList.addElement("Method: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 2) { - exemptList.addElement("Field: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 3) { - exemptList.addElement("StringEncryption: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 4) { - exemptList.addElement("InvokeDynamic: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 5) { - exemptList.addElement("Flow: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 6) { - exemptList.addElement("LocalVars: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 7) { - exemptList.addElement("SourceName: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 8) { - exemptList.addElement("SourceDebug: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 9) { - exemptList.addElement("LineNumbers: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 10) { - exemptList.addElement("StringPool: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 11) { - exemptList.addElement("Crasher: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 12) { - exemptList.addElement("HideCode: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 13) { - exemptList.addElement("Numbers: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 14) { - exemptList.addElement("Shuffler: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 15) { - exemptList.addElement("InnerClasses: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 16) { - exemptList.addElement("Renamer: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 17) { - exemptList.addElement("Expiry: " + exemptField.getText()); - exemptField.setText(""); - } + btnNewButton_2.addActionListener((e) -> { + if (!exemptField.getText().equals("") + && exemptField.getText() != null + && !exemptField.getText().isEmpty()) { + if (comboBox_04.getSelectedIndex() == 0) { + exemptList.addElement("Class: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 1) { + exemptList.addElement("Method: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 2) { + exemptList.addElement("Field: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 3) { + exemptList.addElement("StringEncryption: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 4) { + exemptList.addElement("InvokeDynamic: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 5) { + exemptList.addElement("Flow: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 6) { + exemptList.addElement("LocalVars: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 7) { + exemptList.addElement("SourceName: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 8) { + exemptList.addElement("SourceDebug: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 9) { + exemptList.addElement("LineNumbers: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 10) { + exemptList.addElement("StringPool: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 11) { + exemptList.addElement("Crasher: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 12) { + exemptList.addElement("HideCode: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 13) { + exemptList.addElement("Numbers: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 14) { + exemptList.addElement("Shuffler: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 15) { + exemptList.addElement("InnerClasses: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 16) { + exemptList.addElement("Renamer: " + exemptField.getText()); + exemptField.setText(""); + } else if (comboBox_04.getSelectedIndex() == 17) { + exemptList.addElement("Expiry: " + exemptField.getText()); + exemptField.setText(""); } } }); @@ -1164,16 +1063,13 @@ public void actionPerformed(ActionEvent e) { panel_3.add(btnNewButton_2, gbc_btnNewButton_2); JButton btnNewButton_3 = new JButton("Remove"); - btnNewButton_3.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - List removeList = list.getSelectedValuesList(); - if (removeList.isEmpty()) - return; - - for (String s : removeList) { - exemptList.removeElement(s); - } + btnNewButton_3.addActionListener((e) -> { + List removeList = list.getSelectedValuesList(); + if (removeList.isEmpty()) + return; + + for (String s : removeList) { + exemptList.removeElement(s); } }); GridBagConstraints gbc_btnNewButton_3 = new GridBagConstraints(); @@ -1213,297 +1109,297 @@ public void actionPerformed(ActionEvent e) { panel_1.add(panel_5, BorderLayout.EAST); JButton btnObfuscate = new JButton(" Process "); - btnObfuscate.addActionListener(new ActionListener() { - @SuppressWarnings("deprecation") - public void actionPerformed(ActionEvent arg0) { - if (inputField.getText().isEmpty() - || inputField.getText() == null - || !inputField.getText().endsWith(".jar")) { - JOptionPane.showMessageDialog(null, - "Invalid input JAR", "Error", - JOptionPane.ERROR_MESSAGE); - return; - } + btnObfuscate.addActionListener((e) -> { + if (inputField.getText().isEmpty() + || inputField.getText() == null + || !inputField.getText().endsWith(".jar")) { + JOptionPane.showMessageDialog(null, + "Invalid input JAR", "Error", + JOptionPane.ERROR_MESSAGE); + return; + } - if (outputField.getText().isEmpty() - || outputField.getText() == null - || !outputField.getText().endsWith(".jar")) { - JOptionPane.showMessageDialog(null, - "Invalid output JAR", "Error", - JOptionPane.ERROR_MESSAGE); - return; - } + if (outputField.getText().isEmpty() + || outputField.getText() == null + || !outputField.getText().endsWith(".jar")) { + JOptionPane.showMessageDialog(null, + "Invalid output JAR", "Error", + JOptionPane.ERROR_MESSAGE); + return; + } - if (outputField.getText().equals(inputField.getText())) { - JOptionPane.showMessageDialog(null, - "Output JAR can not have the same name as input " + - "JAR", "Error", JOptionPane.ERROR_MESSAGE); - return; - } + if (outputField.getText().equals(inputField.getText())) { + JOptionPane.showMessageDialog(null, + "Output JAR can not have the same name as input " + + "JAR", "Error", JOptionPane.ERROR_MESSAGE); + return; + } - if (!chckbxStringEncryption.isSelected() - && !chckbxInvokeDynamic.isSelected() - && !chckbxFlow.isSelected() - && !chckbxLocalVariables.isSelected() - && !chckbxTrashClasses.isSelected() - && !chckbxSpringPool.isSelected() - && !chckbxCrasher.isSelected() - && !chckbxHidecode.isSelected() - && !chckbxClassRenammer.isSelected() - && !chckbxNumberObfuscation.isSelected() - && !chckbxAddWatermark.isSelected() - && !chckbxLineObfuscation.isSelected() - && !chckbxSourceName.isSelected() - && !chckbxSourceDebug.isSelected() - && !chckbxShuffler.isSelected() - && !chckbxAddExpiration.isSelected() - && !chckbxInnerClasses.isSelected()) { - JOptionPane.showMessageDialog(null, - "Please select an obfuscation " + - "setting!\nThe Spigot-Plugin setting " + - "alone is not counted as an option.", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } + if (!chckbxStringEncryption.isSelected() + && !chckbxInvokeDynamic.isSelected() + && !chckbxFlow.isSelected() + && !chckbxLocalVariables.isSelected() + && !chckbxTrashClasses.isSelected() + && !chckbxSpringPool.isSelected() + && !chckbxCrasher.isSelected() + && !chckbxHidecode.isSelected() + && !chckbxClassRenammer.isSelected() + && !chckbxNumberObfuscation.isSelected() + && !chckbxAddWatermark.isSelected() + && !chckbxLineObfuscation.isSelected() + && !chckbxSourceName.isSelected() + && !chckbxSourceDebug.isSelected() + && !chckbxShuffler.isSelected() + && !chckbxAddExpiration.isSelected() + && !chckbxInnerClasses.isSelected()) { + JOptionPane.showMessageDialog(null, + "Please select an obfuscation " + + "setting!\nThe Spigot-Plugin setting " + + "alone is not counted as an option.", + "Error", JOptionPane.ERROR_MESSAGE); + return; + } - if (chckbxAddWatermark.isSelected() - && waterMarkMessageField.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, - "You must enter a message to be watermarked.", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } + if (chckbxAddWatermark.isSelected() + && waterMarkMessageField.getText().isEmpty()) { + JOptionPane.showMessageDialog(null, + "You must enter a message to be watermarked.", + "Error", JOptionPane.ERROR_MESSAGE); + return; + } - if (chckbxAddWatermark.isSelected() - && watermarkPassword.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, - "You must enter a key to encrypt the watermark message.", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } + if (chckbxAddWatermark.isSelected() + && new String(watermarkPassword.getPassword()).isEmpty()) { + JOptionPane.showMessageDialog(null, + "You must enter a key to encrypt the watermark message.", + "Error", JOptionPane.ERROR_MESSAGE); + return; + } - if (chckbxAddExpiration.isSelected() - && expirationMessageField.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, - "You must enter an expiration message.", "Error", - JOptionPane.ERROR_MESSAGE); - return; - } + if (chckbxAddExpiration.isSelected() + && expirationMessageField.getText().isEmpty()) { + JOptionPane.showMessageDialog(null, + "You must enter an expiration message.", "Error", + JOptionPane.ERROR_MESSAGE); + return; + } - if (chckbxAddExpiration.isSelected() - && expirationDateField.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, - "You must enter an expiration date.", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - btnObfuscate.setText("Processing..."); - btnObfuscate.setEnabled(false); - SwingWorker sw = new SwingWorker() { - @Override - protected Object doInBackground() throws Exception { - File output = null; - try { + if (chckbxAddExpiration.isSelected() + && expirationDateField.getText().isEmpty()) { + JOptionPane.showMessageDialog(null, + "You must enter an expiration date.", + "Error", JOptionPane.ERROR_MESSAGE); + return; + } + btnObfuscate.setText("Processing..."); + btnObfuscate.setEnabled(false); + SwingWorker sw = new SwingWorker() { + @Override + protected Object doInBackground() { + File output = null; + try { + + HashMap libs = new HashMap<>(); + for (int i = 0; i < libList.getSize(); i++) { + libs.put(libList.get(i), new File(libList.get(i))); + } - HashMap libs = new HashMap<>(); - for (int i = 0; i < libList.getSize(); i++) { - libs.put(libList.get(i), new File(libList.get(i))); - } + File input = new File(inputField.getText()); + if (!input.exists()) { + JOptionPane.showMessageDialog(null, + "Input JAR does not exist.", + "Error", JOptionPane.ERROR_MESSAGE); + return null; + } + output = new File(outputField.getText()); - File input = new File(inputField.getText()); - if (!input.exists()) { - JOptionPane.showMessageDialog(null, - "Input JAR does not exist.", - "Error", JOptionPane.ERROR_MESSAGE); - return null; - } - output = new File(outputField.getText()); - - int trashChance; - try { - trashChance = - Integer.valueOf(trashChanceField.getText()); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, - "Please enter numbers only for the " + - "number of desired trash " + - "classes.", "Error", - JOptionPane.ERROR_MESSAGE); - return null; - } - List exempts = new ArrayList<>(); - for (int i = 0; i < exemptList.size(); i++) { - exempts.add(exemptList.get(i)); - } - boolean spigotMode = chckbxSpigotPlugin.isSelected(); - List transformers - = new ArrayList<>(); + int trashChance; + try { + trashChance = + Integer.valueOf(trashChanceField.getText()); + } catch (Throwable t) { + JOptionPane.showMessageDialog(null, + "Please enter numbers only for the " + + "number of desired trash " + + "classes.", "Error", + JOptionPane.ERROR_MESSAGE); + return null; + } + List exempts = new ArrayList<>(); + for (int i = 0; i < exemptList.size(); i++) { + exempts.add(exemptList.get(i)); + } + boolean spigotMode = chckbxSpigotPlugin.isSelected(); + List transformers + = new ArrayList<>(); - if (chckbxClassRenammer.isSelected()) { - transformers.add(new Renamer(spigotMode)); - } - if (chckbxInnerClasses.isSelected()) { - transformers.add(new InnerClassRemover()); - } - if (chckbxNumberObfuscation.isSelected()) { - transformers.add(new NumberObfuscation()); - } - if (chckbxInvokeDynamic.isSelected()) { - switch (comboBox_1.getSelectedIndex()) { - case 0: - transformers.add(new LightInvokeDynamic()); - break; - case 1: - transformers.add(new NormalInvokeDynamic()); - break; - case 2: - transformers.add(new HeavyInvokeDynamic()); - break; - } - } - if (chckbxAddExpiration.isSelected()) { - if (!expirationDateField.getText().isEmpty() - && !expirationMessageField.getText() - .isEmpty()) { - long expireTime = - new SimpleDateFormat("MM/dd/yyyy") - .parse(expirationDateField - .getText()).getTime(); - transformers.add(new Expiry(expireTime, - expirationMessageField.getText())); - } - } - if (chckbxStringEncryption.isSelected()) { - switch (comboBox.getSelectedIndex()) { - case 0: - transformers.add(new SuperLightStringEncryption(spigotMode)); - break; - case 1: - transformers.add(new LightStringEncryption(spigotMode)); - break; - case 2: - transformers.add(new NormalStringEncryption(spigotMode)); - break; - case 3: - transformers.add(new HeavyStringEncryption(spigotMode)); - break; - } - } - if (chckbxFlow.isSelected()) { - switch (comboBox_2.getSelectedIndex()) { - case 0: - transformers.add(new LightFlowObfuscation()); - break; - case 1: - transformers.add(new NormalFlowObfuscation()); - break; - case 2: - transformers.add(new HeavyFlowObfuscation()); - break; - } - } - if (chckbxSpringPool.isSelected()) { - transformers.add(new StringPool()); + if (chckbxClassRenammer.isSelected()) { + transformers.add(new Renamer(spigotMode)); + } + if (chckbxInnerClasses.isSelected()) { + transformers.add(new InnerClassRemover()); + } + if (chckbxNumberObfuscation.isSelected()) { + transformers.add(new NumberObfuscation()); + } + if (chckbxInvokeDynamic.isSelected()) { + switch (comboBox_1.getSelectedIndex()) { + case 0: + transformers.add(new LightInvokeDynamic()); + break; + case 1: + transformers.add(new NormalInvokeDynamic()); + break; + case 2: + transformers.add(new HeavyInvokeDynamic()); + break; } - if (chckbxShuffler.isSelected()) { - transformers.add(new Shuffler()); + } + if (chckbxAddExpiration.isSelected()) { + if (!expirationDateField.getText().isEmpty() + && !expirationMessageField.getText() + .isEmpty()) { + long expireTime = + new SimpleDateFormat("MM/dd/yyyy") + .parse(expirationDateField + .getText()).getTime(); + transformers.add(new Expiry(expireTime, + expirationMessageField.getText())); } - if (chckbxLocalVariables.isSelected()) { - switch (comboBox_3.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateLocalVariables()); - break; - case 1: - transformers.add(new RemoveLocalVariables()); - break; - } + } + if (chckbxStringEncryption.isSelected()) { + switch (comboBox.getSelectedIndex()) { + case 0: + transformers.add(new SuperLightStringEncryption(spigotMode)); + break; + case 1: + transformers.add(new LightStringEncryption(spigotMode)); + break; + case 2: + transformers.add(new NormalStringEncryption(spigotMode)); + break; + case 3: + transformers.add(new HeavyStringEncryption(spigotMode)); + break; } - if (chckbxLineObfuscation.isSelected()) { - switch (comboBox_5.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateLineNumbers()); - break; - case 1: - transformers.add(new RemoveLineNumbers()); - break; - } + } + if (chckbxFlow.isSelected()) { + switch (comboBox_2.getSelectedIndex()) { + case 0: + transformers.add(new LightFlowObfuscation()); + break; + case 1: + transformers.add(new NormalFlowObfuscation()); + break; + case 2: + transformers.add(new HeavyFlowObfuscation()); + break; } - if (chckbxSourceName.isSelected()) { - switch (comboBox_123.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateSourceName()); - break; - case 1: - transformers.add(new RemoveSourceName()); - break; - } + } + if (chckbxSpringPool.isSelected()) { + transformers.add(new StringPool()); + } + if (chckbxShuffler.isSelected()) { + transformers.add(new Shuffler()); + } + if (chckbxLocalVariables.isSelected()) { + switch (comboBox_3.getSelectedIndex()) { + case 0: + transformers.add(new ObfuscateLocalVariables()); + break; + case 1: + transformers.add(new RemoveLocalVariables()); + break; } - if (chckbxSourceDebug.isSelected()) { - switch (comboBox_1234.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateSourceDebug()); - break; - case 1: - transformers.add(new RemoveSourceDebug()); - break; - } + } + if (chckbxLineObfuscation.isSelected()) { + switch (comboBox_5.getSelectedIndex()) { + case 0: + transformers.add(new ObfuscateLineNumbers()); + break; + case 1: + transformers.add(new RemoveLineNumbers()); + break; } - if (chckbxCrasher.isSelected()) { - transformers.add(new Crasher()); + } + if (chckbxSourceName.isSelected()) { + switch (comboBox_123.getSelectedIndex()) { + case 0: + transformers.add(new ObfuscateSourceName()); + break; + case 1: + transformers.add(new RemoveSourceName()); + break; } - if (chckbxHidecode.isSelected()) { - transformers.add(new HideCode()); + } + if (chckbxSourceDebug.isSelected()) { + switch (comboBox_1234.getSelectedIndex()) { + case 0: + transformers.add(new ObfuscateSourceDebug()); + break; + case 1: + transformers.add(new RemoveSourceDebug()); + break; } + } + if (chckbxCrasher.isSelected()) { + transformers.add(new Crasher()); + } + if (chckbxHidecode.isSelected()) { + transformers.add(new HideCode()); + } - int trashClasses = -1; - if (chckbxTrashClasses.isSelected()) { - trashClasses = trashChance; - } + int trashClasses = -1; + if (chckbxTrashClasses.isSelected()) { + trashClasses = trashChance; + } - int watermarkType = -1; - if (chckbxAddWatermark.isSelected()) { - watermarkType = comboBox_05.getSelectedIndex(); - } + int watermarkType = -1; + if (chckbxAddWatermark.isSelected()) { + watermarkType = comboBox_05.getSelectedIndex(); + } - int dictionary = dictionaryComboBox.getSelectedIndex(); + int dictionary = dictionaryComboBox.getSelectedIndex(); - if (chckbxTrashClasses.isSelected() && spigotMode) { - throw new RuntimeException("Trash classes are not compatible with Spigot's anti-piracy injection."); - } + if (chckbxTrashClasses.isSelected() && spigotMode) { + throw new RuntimeException("Trash classes are not compatible with Spigot's anti-piracy injection."); + } - new ConsoleGUI(); - Bootstrap bootstrap = new Bootstrap( - input, - output, - libs, - exempts, - transformers, - trashClasses, - waterMarkMessageField.getText(), - watermarkType, - new String(watermarkPassword.getPassword()), - dictionary); - bootstrap.startTheParty(false); - JOptionPane.showMessageDialog(null, - "Successfully processed file!", - "Done", JOptionPane.INFORMATION_MESSAGE); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, t.getMessage(), - "Error", JOptionPane.ERROR_MESSAGE); - t.printStackTrace(); - if (output != null) { - output.delete(); + new ConsoleGUI(); + Bootstrap bootstrap = new Bootstrap( + input, + output, + libs, + exempts, + transformers, + trashClasses, + waterMarkMessageField.getText(), + watermarkType, + new String(watermarkPassword.getPassword()), + dictionary); + bootstrap.startTheParty(false); + JOptionPane.showMessageDialog(null, + "Successfully processed file!", + "Done", JOptionPane.INFORMATION_MESSAGE); + } catch (Throwable t) { + JOptionPane.showMessageDialog(null, t.getMessage(), + "Error", JOptionPane.ERROR_MESSAGE); + t.printStackTrace(); + if (output != null) { + if (!output.delete()) { + JOptionPane.showMessageDialog(null, "Failed to delete fault output.", + "Error", JOptionPane.ERROR_MESSAGE); } - } finally { - btnObfuscate.setEnabled(true); - btnObfuscate.setText(" Process "); } - return null; + } finally { + btnObfuscate.setEnabled(true); + btnObfuscate.setText(" Process "); } - }; + return null; + } + }; - sw.execute(); - } + sw.execute(); }); panel_5.add(btnObfuscate); @@ -1511,515 +1407,506 @@ protected Object doInBackground() throws Exception { panel_1.add(panel_6, BorderLayout.WEST); JButton btnLoadConfiguration = new JButton("Load Configuration"); - btnLoadConfiguration.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JFileChooser chooser = new JFileChooser(); - chooser.setMultiSelectionEnabled(false); - chooser.setFileSelectionMode(0); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - try { - File config = new File(chooser.getSelectedFile() - .getAbsolutePath()); - if (!config.exists()) - throw new IOException("Config file does " + - "not exist."); - - FileInputStream fis = new FileInputStream(config); - Config configParser - = new Config(fis); - configParser.loadIntoMap(); - configParser.sortExempts(); - configParser.checkConfig(); - - inputField.setText(configParser.getInput() - .getAbsolutePath()); - outputField.setText(configParser.getOutput() - .getAbsolutePath()); - libList.clear(); - for (String s : configParser.getLibraries() - .keySet()) { - libList.addElement(s); - } + btnLoadConfiguration.addActionListener((e) -> { + JFileChooser chooser = new JFileChooser(); + chooser.setMultiSelectionEnabled(false); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + int result = chooser.showOpenDialog(frmRadonObfuscator); + if (result == 0) { + SwingUtilities.invokeLater(() -> { + try { + File config = new File(chooser.getSelectedFile() + .getAbsolutePath()); + if (!config.exists()) + throw new IOException("Config file does " + + "not exist."); + + FileInputStream fis = new FileInputStream(config); + Config configParser + = new Config(fis); + configParser.loadIntoMap(); + configParser.sortExempts(); + configParser.checkConfig(); + + inputField.setText(configParser.getInput() + .getAbsolutePath()); + outputField.setText(configParser.getOutput() + .getAbsolutePath()); + libList.clear(); + for (String s : configParser.getLibraries() + .keySet()) { + libList.addElement(s); + } - List exempts = configParser.getExempts(); - if (exempts != null) { - exemptList.clear(); - for (String s : exempts) { - exemptList.addElement(s); - } - } + List exempts = configParser.getExempts(); + if (exempts != null) { + exemptList.clear(); + for (String s : exempts) { + exemptList.addElement(s); + } + } - AbstractTransformer stringEncryptionMode - = configParser.getStringEncryptionType(); - if (stringEncryptionMode == null) { - chckbxStringEncryption.setSelected(false); - } else if (stringEncryptionMode - instanceof SuperLightStringEncryption) { - chckbxStringEncryption.setSelected(true); - comboBox.setSelectedIndex(0); - comboBox.setEnabled(true); - } else if (stringEncryptionMode - instanceof LightStringEncryption) { - chckbxStringEncryption.setSelected(true); - comboBox.setSelectedIndex(1); - comboBox.setEnabled(true); - } else if (stringEncryptionMode - instanceof NormalStringEncryption) { - chckbxStringEncryption.setSelected(true); - comboBox.setSelectedIndex(2); - comboBox.setEnabled(true); - } else if (stringEncryptionMode - instanceof HeavyStringEncryption) { - chckbxStringEncryption.setSelected(true); - comboBox.setSelectedIndex(3); - comboBox.setEnabled(true); - } + AbstractTransformer stringEncryptionMode + = configParser.getStringEncryptionType(); + if (stringEncryptionMode == null) { + chckbxStringEncryption.setSelected(false); + } else if (stringEncryptionMode + instanceof SuperLightStringEncryption) { + chckbxStringEncryption.setSelected(true); + comboBox.setSelectedIndex(0); + comboBox.setEnabled(true); + } else if (stringEncryptionMode + instanceof LightStringEncryption) { + chckbxStringEncryption.setSelected(true); + comboBox.setSelectedIndex(1); + comboBox.setEnabled(true); + } else if (stringEncryptionMode + instanceof NormalStringEncryption) { + chckbxStringEncryption.setSelected(true); + comboBox.setSelectedIndex(2); + comboBox.setEnabled(true); + } else if (stringEncryptionMode + instanceof HeavyStringEncryption) { + chckbxStringEncryption.setSelected(true); + comboBox.setSelectedIndex(3); + comboBox.setEnabled(true); + } - AbstractTransformer flowObfuscationMode = - configParser.getFlowObfuscationType(); - if (flowObfuscationMode == null) { - chckbxFlow.setSelected(false); - } else if (flowObfuscationMode - instanceof LightFlowObfuscation) { - chckbxFlow.setSelected(true); - comboBox_2.setSelectedIndex(0); - comboBox_2.setEnabled(true); - } else if (flowObfuscationMode - instanceof NormalFlowObfuscation) { - chckbxFlow.setSelected(true); - comboBox_2.setSelectedIndex(1); - comboBox_2.setEnabled(true); - } else if (flowObfuscationMode - instanceof HeavyFlowObfuscation) { - chckbxFlow.setSelected(true); - comboBox_2.setSelectedIndex(2); - comboBox_2.setEnabled(true); - } + AbstractTransformer flowObfuscationMode = + configParser.getFlowObfuscationType(); + if (flowObfuscationMode == null) { + chckbxFlow.setSelected(false); + } else if (flowObfuscationMode + instanceof LightFlowObfuscation) { + chckbxFlow.setSelected(true); + comboBox_2.setSelectedIndex(0); + comboBox_2.setEnabled(true); + } else if (flowObfuscationMode + instanceof NormalFlowObfuscation) { + chckbxFlow.setSelected(true); + comboBox_2.setSelectedIndex(1); + comboBox_2.setEnabled(true); + } else if (flowObfuscationMode + instanceof HeavyFlowObfuscation) { + chckbxFlow.setSelected(true); + comboBox_2.setSelectedIndex(2); + comboBox_2.setEnabled(true); + } - AbstractTransformer invokeDynamicMode = - configParser.getInvokeDynamicType(); - if (invokeDynamicMode == null) { - chckbxInvokeDynamic.setSelected(false); - } else if (invokeDynamicMode - instanceof LightInvokeDynamic) { - chckbxInvokeDynamic.setSelected(true); - comboBox_1.setSelectedIndex(0); - comboBox_1.setEnabled(true); - } else if (invokeDynamicMode - instanceof NormalInvokeDynamic) { - chckbxInvokeDynamic.setSelected(true); - comboBox_1.setSelectedIndex(1); - comboBox_1.setEnabled(true); - } else if (invokeDynamicMode - instanceof HeavyInvokeDynamic) { - chckbxInvokeDynamic.setSelected(true); - comboBox_1.setSelectedIndex(2); - comboBox_1.setEnabled(true); - } + AbstractTransformer invokeDynamicMode = + configParser.getInvokeDynamicType(); + if (invokeDynamicMode == null) { + chckbxInvokeDynamic.setSelected(false); + } else if (invokeDynamicMode + instanceof LightInvokeDynamic) { + chckbxInvokeDynamic.setSelected(true); + comboBox_1.setSelectedIndex(0); + comboBox_1.setEnabled(true); + } else if (invokeDynamicMode + instanceof NormalInvokeDynamic) { + chckbxInvokeDynamic.setSelected(true); + comboBox_1.setSelectedIndex(1); + comboBox_1.setEnabled(true); + } else if (invokeDynamicMode + instanceof HeavyInvokeDynamic) { + chckbxInvokeDynamic.setSelected(true); + comboBox_1.setSelectedIndex(2); + comboBox_1.setEnabled(true); + } - AbstractTransformer localVariablesMode = - configParser.getLocalVariableObfuscationType(); - if (localVariablesMode == null) { - chckbxLocalVariables.setSelected(false); - } else if (localVariablesMode - instanceof ObfuscateLocalVariables) { - chckbxLocalVariables.setSelected(true); - comboBox_3.setSelectedIndex(0); - comboBox_3.setEnabled(true); - } else if (localVariablesMode - instanceof RemoveLocalVariables) { - chckbxLocalVariables.setSelected(true); - comboBox_3.setSelectedIndex(1); - comboBox_3.setEnabled(true); - } + AbstractTransformer localVariablesMode = + configParser.getLocalVariableObfuscationType(); + if (localVariablesMode == null) { + chckbxLocalVariables.setSelected(false); + } else if (localVariablesMode + instanceof ObfuscateLocalVariables) { + chckbxLocalVariables.setSelected(true); + comboBox_3.setSelectedIndex(0); + comboBox_3.setEnabled(true); + } else if (localVariablesMode + instanceof RemoveLocalVariables) { + chckbxLocalVariables.setSelected(true); + comboBox_3.setSelectedIndex(1); + comboBox_3.setEnabled(true); + } - AbstractTransformer crasherMode = - configParser.getCrasherType(); - if (crasherMode instanceof Crasher) { - chckbxCrasher.setSelected(true); - } else { - chckbxCrasher.setSelected(false); - } + AbstractTransformer crasherMode = + configParser.getCrasherType(); + if (crasherMode instanceof Crasher) { + chckbxCrasher.setSelected(true); + } else { + chckbxCrasher.setSelected(false); + } - AbstractTransformer hideCodeMode = - configParser.getHideCodeType(); - if (hideCodeMode instanceof HideCode) { - chckbxHidecode.setSelected(true); - } else { - chckbxHidecode.setSelected(false); - } + AbstractTransformer hideCodeMode = + configParser.getHideCodeType(); + if (hideCodeMode instanceof HideCode) { + chckbxHidecode.setSelected(true); + } else { + chckbxHidecode.setSelected(false); + } - AbstractTransformer lineRemoverMode = - configParser.getLineNumberObfuscationType(); - if (lineRemoverMode == null) { - chckbxLineObfuscation.setSelected(false); - } else if (lineRemoverMode - instanceof ObfuscateLineNumbers) { - chckbxLineObfuscation.setSelected(true); - comboBox_5.setSelectedIndex(0); - comboBox_5.setEnabled(true); - } else if (lineRemoverMode - instanceof RemoveLineNumbers) { - chckbxLineObfuscation.setSelected(true); - comboBox_5.setSelectedIndex(1); - comboBox_5.setEnabled(true); - } + AbstractTransformer lineRemoverMode = + configParser.getLineNumberObfuscationType(); + if (lineRemoverMode == null) { + chckbxLineObfuscation.setSelected(false); + } else if (lineRemoverMode + instanceof ObfuscateLineNumbers) { + chckbxLineObfuscation.setSelected(true); + comboBox_5.setSelectedIndex(0); + comboBox_5.setEnabled(true); + } else if (lineRemoverMode + instanceof RemoveLineNumbers) { + chckbxLineObfuscation.setSelected(true); + comboBox_5.setSelectedIndex(1); + comboBox_5.setEnabled(true); + } - AbstractTransformer numberObfuscationMode = - configParser.getNumberObfuscationType(); - if (numberObfuscationMode - instanceof NumberObfuscation) { - chckbxNumberObfuscation.setSelected(true); - } else { - chckbxNumberObfuscation.setSelected(false); - } + AbstractTransformer numberObfuscationMode = + configParser.getNumberObfuscationType(); + if (numberObfuscationMode + instanceof NumberObfuscation) { + chckbxNumberObfuscation.setSelected(true); + } else { + chckbxNumberObfuscation.setSelected(false); + } - AbstractTransformer sourceNameObfuscationMode = - configParser.getSourceNameObfuscationType(); - if (sourceNameObfuscationMode == null) { - chckbxSourceName.setSelected(false); - } else if (sourceNameObfuscationMode - instanceof ObfuscateSourceName) { - chckbxSourceName.setSelected(true); - comboBox_123.setSelectedIndex(0); - comboBox_123.setEnabled(true); - } else if (sourceNameObfuscationMode - instanceof RemoveSourceName) { - chckbxSourceName.setSelected(true); - comboBox_123.setSelectedIndex(1); - comboBox_123.setEnabled(true); - } + AbstractTransformer sourceNameObfuscationMode = + configParser.getSourceNameObfuscationType(); + if (sourceNameObfuscationMode == null) { + chckbxSourceName.setSelected(false); + } else if (sourceNameObfuscationMode + instanceof ObfuscateSourceName) { + chckbxSourceName.setSelected(true); + comboBox_123.setSelectedIndex(0); + comboBox_123.setEnabled(true); + } else if (sourceNameObfuscationMode + instanceof RemoveSourceName) { + chckbxSourceName.setSelected(true); + comboBox_123.setSelectedIndex(1); + comboBox_123.setEnabled(true); + } - AbstractTransformer sourceDebugObfuscationMode = - configParser.getSourceDebugObfuscationType(); - if (sourceDebugObfuscationMode == null) { - chckbxSourceDebug.setSelected(false); - } else if (sourceDebugObfuscationMode - instanceof ObfuscateSourceDebug) { - chckbxSourceDebug.setSelected(true); - comboBox_1234.setSelectedIndex(0); - comboBox_1234.setEnabled(true); - } else if (sourceDebugObfuscationMode - instanceof RemoveSourceDebug) { - chckbxSourceDebug.setSelected(true); - comboBox_1234.setSelectedIndex(1); - comboBox_1234.setEnabled(true); - } + AbstractTransformer sourceDebugObfuscationMode = + configParser.getSourceDebugObfuscationType(); + if (sourceDebugObfuscationMode == null) { + chckbxSourceDebug.setSelected(false); + } else if (sourceDebugObfuscationMode + instanceof ObfuscateSourceDebug) { + chckbxSourceDebug.setSelected(true); + comboBox_1234.setSelectedIndex(0); + comboBox_1234.setEnabled(true); + } else if (sourceDebugObfuscationMode + instanceof RemoveSourceDebug) { + chckbxSourceDebug.setSelected(true); + comboBox_1234.setSelectedIndex(1); + comboBox_1234.setEnabled(true); + } - AbstractTransformer stringPoolMode = - configParser.getStringPoolType(); - if (stringPoolMode instanceof StringPool) { - chckbxSpringPool.setSelected(true); - } else { - chckbxSpringPool.setSelected(false); - } + AbstractTransformer stringPoolMode = + configParser.getStringPoolType(); + if (stringPoolMode instanceof StringPool) { + chckbxSpringPool.setSelected(true); + } else { + chckbxSpringPool.setSelected(false); + } - AbstractTransformer shufflerMode = - configParser.getShufflerType(); - if (shufflerMode instanceof Shuffler) { - chckbxShuffler.setSelected(true); - } else { - chckbxShuffler.setSelected(false); - } + AbstractTransformer shufflerMode = + configParser.getShufflerType(); + if (shufflerMode instanceof Shuffler) { + chckbxShuffler.setSelected(true); + } else { + chckbxShuffler.setSelected(false); + } - AbstractTransformer innerClassMode = - configParser.getInnerClassRemoverType(); - if (innerClassMode instanceof InnerClassRemover) { - chckbxInnerClasses.setSelected(true); - } else { - chckbxInnerClasses.setSelected(false); - } + AbstractTransformer innerClassMode = + configParser.getInnerClassRemoverType(); + if (innerClassMode instanceof InnerClassRemover) { + chckbxInnerClasses.setSelected(true); + } else { + chckbxInnerClasses.setSelected(false); + } - AbstractTransformer renamer = - configParser.getRenamerType(); - if (renamer instanceof Renamer) { - chckbxClassRenammer.setSelected(true); - } else { - chckbxClassRenammer.setSelected(false); - } + AbstractTransformer renamer = + configParser.getRenamerType(); + if (renamer instanceof Renamer) { + chckbxClassRenammer.setSelected(true); + } else { + chckbxClassRenammer.setSelected(false); + } - if (configParser.getSpigotBool()) { - chckbxSpigotPlugin.setSelected(true); - } else { - chckbxSpigotPlugin.setSelected(false); - } + if (configParser.getSpigotBool()) { + chckbxSpigotPlugin.setSelected(true); + } else { + chckbxSpigotPlugin.setSelected(false); + } - int trashClassesChance = - configParser.getTrashClasses(); - if (trashClassesChance == -1) { - chckbxTrashClasses.setSelected(false); - } else { - chckbxTrashClasses.setSelected(true); - trashChanceField.setText(String - .valueOf(trashClassesChance)); - trashChanceField.setEditable(true); - } + int trashClassesChance = + configParser.getTrashClasses(); + if (trashClassesChance == -1) { + chckbxTrashClasses.setSelected(false); + } else { + chckbxTrashClasses.setSelected(true); + trashChanceField.setText(String + .valueOf(trashClassesChance)); + trashChanceField.setEditable(true); + } - waterMarkMessageField.setText(configParser - .getWatermarkMsg()); - watermarkPassword.setText(configParser - .getWatermarkKey()); - - int watermarkType = - configParser.getWatermarkType(); - if (configParser.getWatermarkType() != -1) { - chckbxAddWatermark.setSelected(true); - waterMarkMessageField.setEnabled(true); - watermarkPassword.setEnabled(true); - comboBox_05.setEnabled(true); - comboBox_05.setSelectedIndex(watermarkType); - } + waterMarkMessageField.setText(configParser + .getWatermarkMsg()); + watermarkPassword.setText(configParser + .getWatermarkKey()); + + int watermarkType = + configParser.getWatermarkType(); + if (configParser.getWatermarkType() != -1) { + chckbxAddWatermark.setSelected(true); + waterMarkMessageField.setEnabled(true); + watermarkPassword.setEnabled(true); + comboBox_05.setEnabled(true); + comboBox_05.setSelectedIndex(watermarkType); + } - if (configParser.getExpiryMsg() != null - && configParser.getExpiryTime() != -1) { - expirationMessageField.setText(configParser - .getExpiryMsg()); - expirationMessageField.setEnabled(true); - expirationDateField.setText(String - .valueOf(new SimpleDateFormat("MM/dd/yyyy") - .format(configParser.getExpiryTime()))); - expirationDateField.setEnabled(true); - chckbxAddExpiration.setSelected(true); - } + if (configParser.getExpiryMsg() != null + && configParser.getExpiryTime() != -1) { + expirationMessageField.setText(configParser + .getExpiryMsg()); + expirationMessageField.setEnabled(true); + expirationDateField.setText(String + .valueOf(new SimpleDateFormat("MM/dd/yyyy") + .format(configParser.getExpiryTime()))); + expirationDateField.setEnabled(true); + chckbxAddExpiration.setSelected(true); + } - int dictionary = configParser.getDictionaryType(); - dictionaryComboBox.setSelectedIndex(dictionary); - fis.close(); + int dictionary = configParser.getDictionaryType(); + dictionaryComboBox.setSelectedIndex(dictionary); + fis.close(); - lastPath = chooser.getSelectedFile(); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, - t.getMessage(), "Error", - JOptionPane.ERROR_MESSAGE); - t.printStackTrace(); - } - } - }); - } + lastPath = chooser.getSelectedFile(); + } catch (Throwable t) { + JOptionPane.showMessageDialog(null, + t.getMessage(), "Error", + JOptionPane.ERROR_MESSAGE); + t.printStackTrace(); + } + }); } }); btnLoadConfiguration.setToolTipText("Loads config for pre-defined " + "settings."); panel_6.add(btnLoadConfiguration); JButton saveConfigButton = new JButton("Save configuration"); - saveConfigButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JFileChooser chooser = new JFileChooser(); - chooser.setMultiSelectionEnabled(false); - chooser.setFileSelectionMode(0); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - try { - Map settings = new HashMap<>(); - if (inputField.getText() != null - && !inputField.getText().isEmpty()) { - settings.put(ConfigEnum.INPUT, inputField.getText()); - } + saveConfigButton.addActionListener((e) -> { + JFileChooser chooser = new JFileChooser(); + chooser.setMultiSelectionEnabled(false); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + int result = chooser.showOpenDialog(frmRadonObfuscator); + if (result == 0) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + try { + Map settings = new HashMap<>(); + if (inputField.getText() != null + && !inputField.getText().isEmpty()) { + settings.put(ConfigEnum.INPUT, inputField.getText()); + } - if (outputField.getText() != null - && !outputField.getText().isEmpty()) { - settings.put(ConfigEnum.OUTPUT, outputField.getText()); - } + if (outputField.getText() != null + && !outputField.getText().isEmpty()) { + settings.put(ConfigEnum.OUTPUT, outputField.getText()); + } - if (chckbxStringEncryption.isSelected()) { - switch (comboBox.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.STRING_ENCRYPTION, "SuperLight"); - break; - case 1: - settings.put(ConfigEnum.STRING_ENCRYPTION, "Light"); - break; - case 2: - settings.put(ConfigEnum.STRING_ENCRYPTION, "Normal"); - break; - case 3: - settings.put(ConfigEnum.STRING_ENCRYPTION, "Heavy"); - break; - } + if (chckbxStringEncryption.isSelected()) { + switch (comboBox.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.STRING_ENCRYPTION, "SuperLight"); + break; + case 1: + settings.put(ConfigEnum.STRING_ENCRYPTION, "Light"); + break; + case 2: + settings.put(ConfigEnum.STRING_ENCRYPTION, "Normal"); + break; + case 3: + settings.put(ConfigEnum.STRING_ENCRYPTION, "Heavy"); + break; } + } - if (chckbxInvokeDynamic.isSelected()) { - switch (comboBox_1.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.INVOKEDYNAMIC, "Light"); - break; - case 1: - settings.put(ConfigEnum.INVOKEDYNAMIC, "Normal"); - break; - case 2: - settings.put(ConfigEnum.INVOKEDYNAMIC, "Heavy"); - break; - } + if (chckbxInvokeDynamic.isSelected()) { + switch (comboBox_1.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.INVOKEDYNAMIC, "Light"); + break; + case 1: + settings.put(ConfigEnum.INVOKEDYNAMIC, "Normal"); + break; + case 2: + settings.put(ConfigEnum.INVOKEDYNAMIC, "Heavy"); + break; } + } - if (chckbxFlow.isSelected()) { - switch (comboBox_2.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.FLOW_OBFUSCATION, "Light"); - break; - case 1: - settings.put(ConfigEnum.FLOW_OBFUSCATION, "Normal"); - break; - case 2: - settings.put(ConfigEnum.FLOW_OBFUSCATION, "Heavy"); - break; - } + if (chckbxFlow.isSelected()) { + switch (comboBox_2.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.FLOW_OBFUSCATION, "Light"); + break; + case 1: + settings.put(ConfigEnum.FLOW_OBFUSCATION, "Normal"); + break; + case 2: + settings.put(ConfigEnum.FLOW_OBFUSCATION, "Heavy"); + break; } + } - if (chckbxLocalVariables.isSelected()) { - switch (comboBox_3.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.LOCAL_VARIABLES, "Obfuscate"); - break; - case 1: - settings.put(ConfigEnum.LOCAL_VARIABLES, "Remove"); - break; - } + if (chckbxLocalVariables.isSelected()) { + switch (comboBox_3.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.LOCAL_VARIABLES, "Obfuscate"); + break; + case 1: + settings.put(ConfigEnum.LOCAL_VARIABLES, "Remove"); + break; } + } - if (chckbxCrasher.isSelected()) { - settings.put(ConfigEnum.CRASHER, "true"); - } + if (chckbxCrasher.isSelected()) { + settings.put(ConfigEnum.CRASHER, "true"); + } - if (chckbxHidecode.isSelected()) { - settings.put(ConfigEnum.HIDER, "true"); - } + if (chckbxHidecode.isSelected()) { + settings.put(ConfigEnum.HIDER, "true"); + } + + if (chckbxSpringPool.isSelected()) { + settings.put(ConfigEnum.STRING_POOL, "true"); + } - if (chckbxSpringPool.isSelected()) { - settings.put(ConfigEnum.STRING_POOL, "true"); + if (chckbxLineObfuscation.isSelected()) { + switch (comboBox_5.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.LINE_NUMBERS, "Obfuscate"); + break; + case 1: + settings.put(ConfigEnum.LINE_NUMBERS, "Remove"); + break; } + } - if (chckbxLineObfuscation.isSelected()) { - switch (comboBox_5.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.LINE_NUMBERS, "Obfuscate"); - break; - case 1: - settings.put(ConfigEnum.LINE_NUMBERS, "Remove"); - break; - } + if (chckbxNumberObfuscation.isSelected()) { + settings.put(ConfigEnum.NUMBERS, "true"); + } + + if (chckbxSourceName.isSelected()) { + switch (comboBox_123.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.SOURCE_NAME, "Obfuscate"); + break; + case 1: + settings.put(ConfigEnum.SOURCE_NAME, "Remove"); + break; } + } - if (chckbxNumberObfuscation.isSelected()) { - settings.put(ConfigEnum.NUMBERS, "true"); + if (chckbxSourceDebug.isSelected()) { + switch (comboBox_1234.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.SOURCE_DEBUG, "Obfuscate"); + break; + case 1: + settings.put(ConfigEnum.SOURCE_DEBUG, "Remove"); + break; } + } - if (chckbxSourceName.isSelected()) { - switch (comboBox_123.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.SOURCE_NAME, "Obfuscate"); - break; - case 1: - settings.put(ConfigEnum.SOURCE_NAME, "Remove"); - break; - } + if (chckbxTrashClasses.isSelected()) { + if (trashChanceField.getText() != null + && !trashChanceField.getText().isEmpty()) { + settings.put(ConfigEnum.TRASH_CLASSES, trashChanceField.getText()); } + } - if (chckbxSourceDebug.isSelected()) { - switch (comboBox_1234.getSelectedIndex()) { + if (chckbxAddWatermark.isSelected()) { + if (waterMarkMessageField.getText() != null + && !waterMarkMessageField.getText().isEmpty() + && watermarkPassword.getText() != null + && !watermarkPassword.getText().isEmpty()) { + switch (comboBox_05.getSelectedIndex()) { case 0: - settings.put(ConfigEnum.SOURCE_DEBUG, "Obfuscate"); + settings.put(ConfigEnum.WATERMARK_TYPE, "ConstantPool"); break; case 1: - settings.put(ConfigEnum.SOURCE_DEBUG, "Remove"); + settings.put(ConfigEnum.WATERMARK_TYPE, "Signature"); break; } - } - - if (chckbxTrashClasses.isSelected()) { - if (trashChanceField.getText() != null - && !trashChanceField.getText().isEmpty()) { - settings.put(ConfigEnum.TRASH_CLASSES, trashChanceField.getText()); - } - } - if (chckbxAddWatermark.isSelected()) { - if (waterMarkMessageField.getText() != null - && !waterMarkMessageField.getText().isEmpty() - && watermarkPassword.getText() != null - && !watermarkPassword.getText().isEmpty()) { - switch (comboBox_05.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.WATERMARK_TYPE, "ConstantPool"); - break; - case 1: - settings.put(ConfigEnum.WATERMARK_TYPE, "Signature"); - break; - } - - settings.put(ConfigEnum.WATERMARK_MSG, waterMarkMessageField.getText()); - settings.put(ConfigEnum.WATERMARK_KEY, watermarkPassword.getText()); - } + settings.put(ConfigEnum.WATERMARK_MSG, waterMarkMessageField.getText()); + settings.put(ConfigEnum.WATERMARK_KEY, watermarkPassword.getText()); } + } - if (chckbxSpigotPlugin.isSelected()) { - settings.put(ConfigEnum.SPIGOT_PLUGIN, "true"); - } + if (chckbxSpigotPlugin.isSelected()) { + settings.put(ConfigEnum.SPIGOT_PLUGIN, "true"); + } - if (chckbxClassRenammer.isSelected()) { - settings.put(ConfigEnum.RENAMER, "true"); - } + if (chckbxClassRenammer.isSelected()) { + settings.put(ConfigEnum.RENAMER, "true"); + } - if (chckbxAddExpiration.isSelected()) { - if (expirationMessageField.getText() != null - && !expireMessageLabel.getText().isEmpty() - && expirationDateField.getText() != null - && !expirationDateField.getText().isEmpty()) { - settings.put(ConfigEnum.EXPIRATION_MESSAGE, expirationMessageField.getText()); - settings.put(ConfigEnum.EXPIRATION_TIME, expirationDateField.getText()); - } + if (chckbxAddExpiration.isSelected()) { + if (expirationMessageField.getText() != null + && !expireMessageLabel.getText().isEmpty() + && expirationDateField.getText() != null + && !expirationDateField.getText().isEmpty()) { + settings.put(ConfigEnum.EXPIRATION_MESSAGE, expirationMessageField.getText()); + settings.put(ConfigEnum.EXPIRATION_TIME, expirationDateField.getText()); } + } - if (chckbxShuffler.isSelected()) { - settings.put(ConfigEnum.SHUFFLER, "true"); - } + if (chckbxShuffler.isSelected()) { + settings.put(ConfigEnum.SHUFFLER, "true"); + } - settings.put(ConfigEnum.DICTIONARY, String.valueOf(dictionaryComboBox.getSelectedIndex())); + settings.put(ConfigEnum.DICTIONARY, String.valueOf(dictionaryComboBox.getSelectedIndex())); - if (chckbxInnerClasses.isSelected()) { - settings.put(ConfigEnum.INNERCLASSES, "true"); - } + if (chckbxInnerClasses.isSelected()) { + settings.put(ConfigEnum.INNERCLASSES, "true"); + } - List libs = new ArrayList<>(); - for (int i = 0; i < libList.size(); i++) { - String lib = libList.get(i); - libs.add(lib); - } + List libs = new ArrayList<>(); + for (int i = 0; i < libList.size(); i++) { + String lib = libList.get(i); + libs.add(lib); + } - settings.put(ConfigEnum.LIBRARIES, libs); + settings.put(ConfigEnum.LIBRARIES, libs); - List exempts = new ArrayList<>(); - for (int i = 0; i < exemptList.size(); i++) { - String exempt = exemptList.get(i); - exempts.add(exempt); - } + List exempts = new ArrayList<>(); + for (int i = 0; i < exemptList.size(); i++) { + String exempt = exemptList.get(i); + exempts.add(exempt); + } - settings.put(ConfigEnum.EXEMPTS, exempts); + settings.put(ConfigEnum.EXEMPTS, exempts); - ConfigWriter writer = new ConfigWriter(settings); - writer.parseOptions(); - writer.writeConfig(chooser.getSelectedFile().getAbsolutePath()); + ConfigWriter writer = new ConfigWriter(settings); + writer.parseOptions(); + writer.writeConfig(chooser.getSelectedFile().getAbsolutePath()); - lastPath = chooser.getSelectedFile(); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, - t.getMessage(), "Error", - JOptionPane.ERROR_MESSAGE); - t.printStackTrace(); - } + lastPath = chooser.getSelectedFile(); + } catch (Throwable t) { + JOptionPane.showMessageDialog(null, + t.getMessage(), "Error", + JOptionPane.ERROR_MESSAGE); + t.printStackTrace(); } - }); - } + } + }); } }); panel_6.add(saveConfigButton); From 61ab78bc01d8893a0d6b56bac4244f2693fda58f Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Fri, 29 Jun 2018 10:14:13 -0700 Subject: [PATCH 018/281] Converted rest of anonymous classes in MainGUI to lambda expressions --- .../me/itzsomebody/radon/gui/MainGUI.java | 323 +++++++++--------- 1 file changed, 159 insertions(+), 164 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java index 86c8fb1a..a56e2db9 100644 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java @@ -18,8 +18,6 @@ package me.itzsomebody.radon.gui; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -82,7 +80,7 @@ public class MainGUI { private JPasswordField watermarkPassword; private JTextField extractorInput; private JPasswordField extractorKey; - private File lastPath; // TODO: Use this for last file selection path + private File lastPath; /** * Create the application. @@ -1704,207 +1702,204 @@ protected Object doInBackground() { chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); int result = chooser.showOpenDialog(frmRadonObfuscator); if (result == 0) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - try { - Map settings = new HashMap<>(); - if (inputField.getText() != null - && !inputField.getText().isEmpty()) { - settings.put(ConfigEnum.INPUT, inputField.getText()); - } + SwingUtilities.invokeLater(() -> { + try { + Map settings = new HashMap<>(); + if (inputField.getText() != null + && !inputField.getText().isEmpty()) { + settings.put(ConfigEnum.INPUT, inputField.getText()); + } - if (outputField.getText() != null - && !outputField.getText().isEmpty()) { - settings.put(ConfigEnum.OUTPUT, outputField.getText()); - } + if (outputField.getText() != null + && !outputField.getText().isEmpty()) { + settings.put(ConfigEnum.OUTPUT, outputField.getText()); + } - if (chckbxStringEncryption.isSelected()) { - switch (comboBox.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.STRING_ENCRYPTION, "SuperLight"); - break; - case 1: - settings.put(ConfigEnum.STRING_ENCRYPTION, "Light"); - break; - case 2: - settings.put(ConfigEnum.STRING_ENCRYPTION, "Normal"); - break; - case 3: - settings.put(ConfigEnum.STRING_ENCRYPTION, "Heavy"); - break; - } + if (chckbxStringEncryption.isSelected()) { + switch (comboBox.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.STRING_ENCRYPTION, "SuperLight"); + break; + case 1: + settings.put(ConfigEnum.STRING_ENCRYPTION, "Light"); + break; + case 2: + settings.put(ConfigEnum.STRING_ENCRYPTION, "Normal"); + break; + case 3: + settings.put(ConfigEnum.STRING_ENCRYPTION, "Heavy"); + break; } + } - if (chckbxInvokeDynamic.isSelected()) { - switch (comboBox_1.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.INVOKEDYNAMIC, "Light"); - break; - case 1: - settings.put(ConfigEnum.INVOKEDYNAMIC, "Normal"); - break; - case 2: - settings.put(ConfigEnum.INVOKEDYNAMIC, "Heavy"); - break; - } + if (chckbxInvokeDynamic.isSelected()) { + switch (comboBox_1.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.INVOKEDYNAMIC, "Light"); + break; + case 1: + settings.put(ConfigEnum.INVOKEDYNAMIC, "Normal"); + break; + case 2: + settings.put(ConfigEnum.INVOKEDYNAMIC, "Heavy"); + break; } + } - if (chckbxFlow.isSelected()) { - switch (comboBox_2.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.FLOW_OBFUSCATION, "Light"); - break; - case 1: - settings.put(ConfigEnum.FLOW_OBFUSCATION, "Normal"); - break; - case 2: - settings.put(ConfigEnum.FLOW_OBFUSCATION, "Heavy"); - break; - } + if (chckbxFlow.isSelected()) { + switch (comboBox_2.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.FLOW_OBFUSCATION, "Light"); + break; + case 1: + settings.put(ConfigEnum.FLOW_OBFUSCATION, "Normal"); + break; + case 2: + settings.put(ConfigEnum.FLOW_OBFUSCATION, "Heavy"); + break; } + } - if (chckbxLocalVariables.isSelected()) { - switch (comboBox_3.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.LOCAL_VARIABLES, "Obfuscate"); - break; - case 1: - settings.put(ConfigEnum.LOCAL_VARIABLES, "Remove"); - break; - } + if (chckbxLocalVariables.isSelected()) { + switch (comboBox_3.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.LOCAL_VARIABLES, "Obfuscate"); + break; + case 1: + settings.put(ConfigEnum.LOCAL_VARIABLES, "Remove"); + break; } + } - if (chckbxCrasher.isSelected()) { - settings.put(ConfigEnum.CRASHER, "true"); - } + if (chckbxCrasher.isSelected()) { + settings.put(ConfigEnum.CRASHER, "true"); + } - if (chckbxHidecode.isSelected()) { - settings.put(ConfigEnum.HIDER, "true"); - } + if (chckbxHidecode.isSelected()) { + settings.put(ConfigEnum.HIDER, "true"); + } - if (chckbxSpringPool.isSelected()) { - settings.put(ConfigEnum.STRING_POOL, "true"); + if (chckbxSpringPool.isSelected()) { + settings.put(ConfigEnum.STRING_POOL, "true"); + } + + if (chckbxLineObfuscation.isSelected()) { + switch (comboBox_5.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.LINE_NUMBERS, "Obfuscate"); + break; + case 1: + settings.put(ConfigEnum.LINE_NUMBERS, "Remove"); + break; } + } - if (chckbxLineObfuscation.isSelected()) { - switch (comboBox_5.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.LINE_NUMBERS, "Obfuscate"); - break; - case 1: - settings.put(ConfigEnum.LINE_NUMBERS, "Remove"); - break; - } + if (chckbxNumberObfuscation.isSelected()) { + settings.put(ConfigEnum.NUMBERS, "true"); + } + + if (chckbxSourceName.isSelected()) { + switch (comboBox_123.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.SOURCE_NAME, "Obfuscate"); + break; + case 1: + settings.put(ConfigEnum.SOURCE_NAME, "Remove"); + break; } + } - if (chckbxNumberObfuscation.isSelected()) { - settings.put(ConfigEnum.NUMBERS, "true"); + if (chckbxSourceDebug.isSelected()) { + switch (comboBox_1234.getSelectedIndex()) { + case 0: + settings.put(ConfigEnum.SOURCE_DEBUG, "Obfuscate"); + break; + case 1: + settings.put(ConfigEnum.SOURCE_DEBUG, "Remove"); + break; } + } - if (chckbxSourceName.isSelected()) { - switch (comboBox_123.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.SOURCE_NAME, "Obfuscate"); - break; - case 1: - settings.put(ConfigEnum.SOURCE_NAME, "Remove"); - break; - } + if (chckbxTrashClasses.isSelected()) { + if (trashChanceField.getText() != null + && !trashChanceField.getText().isEmpty()) { + settings.put(ConfigEnum.TRASH_CLASSES, trashChanceField.getText()); } + } - if (chckbxSourceDebug.isSelected()) { - switch (comboBox_1234.getSelectedIndex()) { + if (chckbxAddWatermark.isSelected()) { + if (waterMarkMessageField.getText() != null + && !waterMarkMessageField.getText().isEmpty() + && watermarkPassword.getPassword() != null + && !new String(watermarkPassword.getPassword()).isEmpty()) { + switch (comboBox_05.getSelectedIndex()) { case 0: - settings.put(ConfigEnum.SOURCE_DEBUG, "Obfuscate"); + settings.put(ConfigEnum.WATERMARK_TYPE, "ConstantPool"); break; case 1: - settings.put(ConfigEnum.SOURCE_DEBUG, "Remove"); + settings.put(ConfigEnum.WATERMARK_TYPE, "Signature"); break; } - } - - if (chckbxTrashClasses.isSelected()) { - if (trashChanceField.getText() != null - && !trashChanceField.getText().isEmpty()) { - settings.put(ConfigEnum.TRASH_CLASSES, trashChanceField.getText()); - } - } - if (chckbxAddWatermark.isSelected()) { - if (waterMarkMessageField.getText() != null - && !waterMarkMessageField.getText().isEmpty() - && watermarkPassword.getText() != null - && !watermarkPassword.getText().isEmpty()) { - switch (comboBox_05.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.WATERMARK_TYPE, "ConstantPool"); - break; - case 1: - settings.put(ConfigEnum.WATERMARK_TYPE, "Signature"); - break; - } - - settings.put(ConfigEnum.WATERMARK_MSG, waterMarkMessageField.getText()); - settings.put(ConfigEnum.WATERMARK_KEY, watermarkPassword.getText()); - } + settings.put(ConfigEnum.WATERMARK_MSG, waterMarkMessageField.getText()); + settings.put(ConfigEnum.WATERMARK_KEY, new String(watermarkPassword.getPassword())); } + } - if (chckbxSpigotPlugin.isSelected()) { - settings.put(ConfigEnum.SPIGOT_PLUGIN, "true"); - } + if (chckbxSpigotPlugin.isSelected()) { + settings.put(ConfigEnum.SPIGOT_PLUGIN, "true"); + } - if (chckbxClassRenammer.isSelected()) { - settings.put(ConfigEnum.RENAMER, "true"); - } + if (chckbxClassRenammer.isSelected()) { + settings.put(ConfigEnum.RENAMER, "true"); + } - if (chckbxAddExpiration.isSelected()) { - if (expirationMessageField.getText() != null - && !expireMessageLabel.getText().isEmpty() - && expirationDateField.getText() != null - && !expirationDateField.getText().isEmpty()) { - settings.put(ConfigEnum.EXPIRATION_MESSAGE, expirationMessageField.getText()); - settings.put(ConfigEnum.EXPIRATION_TIME, expirationDateField.getText()); - } + if (chckbxAddExpiration.isSelected()) { + if (expirationMessageField.getText() != null + && !expireMessageLabel.getText().isEmpty() + && expirationDateField.getText() != null + && !expirationDateField.getText().isEmpty()) { + settings.put(ConfigEnum.EXPIRATION_MESSAGE, expirationMessageField.getText()); + settings.put(ConfigEnum.EXPIRATION_TIME, expirationDateField.getText()); } + } - if (chckbxShuffler.isSelected()) { - settings.put(ConfigEnum.SHUFFLER, "true"); - } + if (chckbxShuffler.isSelected()) { + settings.put(ConfigEnum.SHUFFLER, "true"); + } - settings.put(ConfigEnum.DICTIONARY, String.valueOf(dictionaryComboBox.getSelectedIndex())); + settings.put(ConfigEnum.DICTIONARY, String.valueOf(dictionaryComboBox.getSelectedIndex())); - if (chckbxInnerClasses.isSelected()) { - settings.put(ConfigEnum.INNERCLASSES, "true"); - } + if (chckbxInnerClasses.isSelected()) { + settings.put(ConfigEnum.INNERCLASSES, "true"); + } - List libs = new ArrayList<>(); - for (int i = 0; i < libList.size(); i++) { - String lib = libList.get(i); - libs.add(lib); - } + List libs = new ArrayList<>(); + for (int i = 0; i < libList.size(); i++) { + String lib = libList.get(i); + libs.add(lib); + } - settings.put(ConfigEnum.LIBRARIES, libs); + settings.put(ConfigEnum.LIBRARIES, libs); - List exempts = new ArrayList<>(); - for (int i = 0; i < exemptList.size(); i++) { - String exempt = exemptList.get(i); - exempts.add(exempt); - } + List exempts = new ArrayList<>(); + for (int i = 0; i < exemptList.size(); i++) { + String exempt = exemptList.get(i); + exempts.add(exempt); + } - settings.put(ConfigEnum.EXEMPTS, exempts); + settings.put(ConfigEnum.EXEMPTS, exempts); - ConfigWriter writer = new ConfigWriter(settings); - writer.parseOptions(); - writer.writeConfig(chooser.getSelectedFile().getAbsolutePath()); + ConfigWriter writer = new ConfigWriter(settings); + writer.parseOptions(); + writer.writeConfig(chooser.getSelectedFile().getAbsolutePath()); - lastPath = chooser.getSelectedFile(); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, - t.getMessage(), "Error", - JOptionPane.ERROR_MESSAGE); - t.printStackTrace(); - } + lastPath = chooser.getSelectedFile(); + } catch (Throwable t) { + JOptionPane.showMessageDialog(null, + t.getMessage(), "Error", + JOptionPane.ERROR_MESSAGE); + t.printStackTrace(); } }); } From 6a11b099639ee1b55378cb6c465ab1d9193f845a Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Fri, 29 Jun 2018 10:22:18 -0700 Subject: [PATCH 019/281] Dependency inject the Bootstrap instance instead of per-case dependency injection. --- .../itzsomebody/radon/internal/Bootstrap.java | 70 ++++++++++----- .../transformers/AbstractTransformer.java | 89 +++++++------------ .../radon/transformers/renamer/Renamer.java | 23 +++-- 3 files changed, 89 insertions(+), 93 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index d6d0a6d1..19b938e1 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -39,7 +39,6 @@ import me.itzsomebody.radon.transformers.misc.Expiry; import me.itzsomebody.radon.transformers.misc.TrashClasses; import me.itzsomebody.radon.transformers.renamer.ClassTree; -import me.itzsomebody.radon.transformers.renamer.Renamer; import me.itzsomebody.radon.utils.FileUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.NumberUtils; @@ -146,17 +145,12 @@ public class Bootstrap { // Eyyy bootstrap bill */ private List logStrings; - /** - * {@link Long} used for entry times. - */ - private long currentTime; - /** * Constructor used for CLI to create a {@link Bootstrap} object. * * @param config {@link Config} object. */ - public Bootstrap(Config config) { + Bootstrap(Config config) { this.config = config; } @@ -219,16 +213,12 @@ public void startTheParty(boolean doInit) throws Throwable { } this.zos = new ZipOutputStream(new FileOutputStream(output)); } - this.currentTime = System.currentTimeMillis(); + long currentTime = System.currentTimeMillis(); this.loadClassPath(); this.loadInput(); for (AbstractTransformer transformer : this.transformers) { - if (transformer instanceof Renamer) { - transformer.init(this.classes, this.classPath, this.passThru, this.exempts, this.dictionary); - } else { - transformer.init(this.classes, this.extraClasses, this.exempts, this.dictionary); - } + transformer.init(this, this.exempts, this.dictionary); transformer.obfuscate(); this.logStrings.addAll(transformer.getLogStrings()); } @@ -258,7 +248,7 @@ public void startTheParty(boolean doInit) throws Throwable { classNode.accept(cw); ZipEntry newEntry = new ZipEntry(classNode.name + ".class"); - newEntry.setTime(this.currentTime); + newEntry.setTime(currentTime); newEntry.setCompressedSize(-1); this.zos.putNextEntry(newEntry); this.zos.write(cw.toByteArray()); @@ -309,7 +299,7 @@ public void startTheParty(boolean doInit) throws Throwable { ZipEntry newEntry = new ZipEntry(classNode.name + ".class"); - newEntry.setTime(this.currentTime); + newEntry.setTime(currentTime); newEntry.setCompressedSize(-1); this.zos.putNextEntry(newEntry); this.zos.write(cw.toByteArray()); @@ -321,7 +311,7 @@ public void startTheParty(boolean doInit) throws Throwable { this.logStrings.add(LoggerUtils.stdOut("Writing resources to output")); for (String name : this.passThru.keySet()) { ZipEntry newEntry = new ZipEntry(name); - newEntry.setTime(this.currentTime); + newEntry.setTime(currentTime); this.zos.putNextEntry(newEntry); this.zos.write(this.passThru.get(name)); this.zos.closeEntry(); @@ -542,12 +532,12 @@ private void createTrees() { long executionTime = System.currentTimeMillis(); this.logStrings.add(LoggerUtils.stdOut("Creating class hierarchy.")); classPath.values().forEach(classNode -> { - classNode.methods.forEach(methodNode -> { - methodNode.owner = classNode.name; - }); - classNode.fields.forEach(fieldNode -> { - fieldNode.owner = classNode.name; - }); + classNode.methods.forEach(methodNode -> + methodNode.owner = classNode.name + ); + classNode.fields.forEach(fieldNode -> + fieldNode.owner = classNode.name + ); ClassTree classTree = new ClassTree(classNode.name, classNode.libraryNode); classTree.parentClasses.add(classNode.superName); classTree.parentClasses.addAll(classNode.interfaces); @@ -570,6 +560,42 @@ private void createTrees() { this.logStrings.add(LoggerUtils.stdOut("Finished creating class hierarchy. [" + (System.currentTimeMillis() - executionTime) + "ms]")); } + /** + * Returns the loaded input {@link ClassNode}s. + * + * @return the loaded input {@link ClassNode}s. + */ + public Map getClasses() { + return this.classes; + } + + /** + * Returns the loaded class path. + * + * @return the loaded class path. + */ + public Map getClassPath() { + return this.classPath; + } + + /** + * Returns the map of extra classes. + * + * @return the map of extra classes. + */ + public Map getExtraClasses() { + return this.extraClasses; + } + + /** + * Returns the loaded resources. + * + * @return the loaded resources. + */ + public Map getPassThru() { + return this.passThru; + } + /** * CustomClassWriter that doesn't use the internal Java classpath. * Concept taken from Java-Deobfuscator by samczsun diff --git a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java index f800afcb..ce72c3cd 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java @@ -22,6 +22,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import me.itzsomebody.radon.internal.Bootstrap; import me.itzsomebody.radon.utils.CustomRegexUtils; import org.objectweb.asm.Opcodes; import org.objectweb.asm.commons.CodeSizeEvaluator; @@ -36,19 +37,9 @@ */ public abstract class AbstractTransformer implements Opcodes { /** - * The classes in the input. + * Bootstrap instance. */ - private Map classes; - - /** - * The almighty classpath. - */ - private Map classPath; - - /** - * Resources. - */ - protected Map passThru; + private Bootstrap bootstrap; /** * Exempt information. @@ -66,91 +57,71 @@ public abstract class AbstractTransformer implements Opcodes { protected List logStrings; /** - * Init method. + * Dependency injection method. * - * @param classes the classes. + * @param bootstrap instance of {@link Bootstrap}. * @param exempts exempt information. */ - public void init(Map classes, + public void init(Bootstrap bootstrap, List exempts, int dictionary) { - this.classes = classes; + this.bootstrap = bootstrap; this.exempts = exempts; this.dictionary = dictionary; this.logStrings = new ArrayList<>(); } /** - * The other init method. + * Returns the loaded input {@link ClassNode}s. * - * @param classes the classes. - * @param classPath the almighty classpath. (Bow down to it) - * @param exempts the exempted classes. + * @return the loaded input {@link ClassNode}s. */ - public void init(Map classes, - Map classPath, - List exempts, int dictionary) { - this.classes = classes; - this.classPath = classPath; - this.exempts = exempts; - this.dictionary = dictionary; - this.logStrings = new ArrayList<>(); + protected Map getClassMap() { + return this.bootstrap.getClasses(); } /** - * The other-other init method. + * Returns the map of extra classes. * - * @param classes the classes. - * @param classPath the almighty classpath. (Bow down to it) - * @param passThru the manifest. - * @param exempts the exempted classes. - */ - public void init(Map classes, - Map classPath, - Map passThru, - List exempts, - int dictionary) { - this.classes = classes; - this.classPath = classPath; - this.exempts = exempts; - this.passThru = passThru; - this.dictionary = dictionary; - this.logStrings = new ArrayList<>(); + * @return the map of extra classes. + */ + protected Map getExtraClassesMap() { + return this.bootstrap.getExtraClasses(); } /** - * Returns {@link AbstractTransformer#classes}. + * Returns the loaded class path. * - * @return {@link AbstractTransformer#classes}. + * @return the loaded class path. */ - protected Map getClassMap() { - return this.classes; + protected Map getClassPathMap() { + return this.bootstrap.getClassPath(); } /** - * Returns {@link AbstractTransformer#classPath}. + * Returns the loaded resources. * - * @return {@link AbstractTransformer#classPath}. + * @return the loaded resources. */ - protected Map getClassPathMap() { - return this.classPath; + protected Map getPassThru() { + return this.bootstrap.getPassThru(); } /** - * Returns the values of {@link AbstractTransformer#classes}. + * Returns only the loaded {@link ClassNode}s. * - * @return the values of {@link AbstractTransformer#classes}. + * @return only the loaded {@link ClassNode}s. */ protected Collection classNodes() { - return this.classes.values(); + return this.getClassMap().values(); } /** - * Returns the keyset of {@link AbstractTransformer#classes}. + * Returns only the names of the loaded {@link ClassNode}s. * - * @return the keyset of {@link AbstractTransformer#classes}. + * @return only the names of the loaded {@link ClassNode}s. */ protected Collection classNames() { - return this.classes.keySet(); + return this.getClassMap().keySet(); } /** diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java index 07f085cb..808cd257 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java @@ -108,7 +108,6 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("Finished generated mappings. [" + String.valueOf(System.currentTimeMillis() - current) + "ms]")); this.logStrings.add(LoggerUtils.stdOut("Applying mappings.")); - current = System.currentTimeMillis(); // Apply mapping Remapper simpleRemapper = new SimpleRemapper(this.mappings); @@ -137,7 +136,7 @@ public void obfuscate() { // Fix screw ups in resources. this.logStrings.add(LoggerUtils.stdOut("Attempting to map class names in resources")); AtomicInteger fixed = new AtomicInteger(); - passThru.forEach((name, byteArray) -> { + getPassThru().forEach((name, byteArray) -> { if (name.equals("META-INF/MANIFEST.MF") || (name.equals("plugin.yml") && spigotMode)) { String stringVer = new String(byteArray); @@ -148,7 +147,7 @@ public void obfuscate() { } try { - passThru.put(name, stringVer.getBytes("UTF-8")); + getPassThru().put(name, stringVer.getBytes("UTF-8")); fixed.incrementAndGet(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); @@ -168,19 +167,19 @@ private void createTrees() { long current = System.currentTimeMillis(); this.logStrings.add(LoggerUtils.stdOut("Creating class hierarchy.")); this.getClassPathMap().values().forEach(classNode -> { - classNode.methods.forEach(methodNode -> { - methodNode.owner = classNode.name; - }); - classNode.fields.forEach(fieldNode -> { - fieldNode.owner = classNode.name; - }); + classNode.methods.forEach(methodNode -> + methodNode.owner = classNode.name + ); + classNode.fields.forEach(fieldNode -> + fieldNode.owner = classNode.name + ); ClassTree classTree = new ClassTree(classNode.name, classNode.libraryNode); classTree.parentClasses.add(classNode.superName); classTree.parentClasses.addAll(classNode.interfaces); this.classNodes().stream().filter(node -> node.superName.equals(classNode.name) - || node.interfaces.contains(classNode.name)).forEach(node -> { - classTree.subClasses.add(node.name); - }); + || node.interfaces.contains(classNode.name)).forEach(node -> + classTree.subClasses.add(node.name) + ); classTree.methods.addAll(classNode.methods); classTree.fields.addAll(classNode.fields); From 1870bd9dcb73e00855b551e00763fb7cc6b33abf Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Sat, 30 Jun 2018 11:39:30 -0700 Subject: [PATCH 020/281] Fixed an oopsie in ConsoleGUI class + considering a template for a new heavy string encryption --- .../me/itzsomebody/radon/gui/ConsoleGUI.java | 2 +- .../templates/HeavyStringEncryption.java | 236 ++++++------------ 2 files changed, 80 insertions(+), 158 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java b/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java index 6216ee91..52ccf9c9 100644 --- a/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java @@ -76,7 +76,7 @@ private void init() { this.thisFrame = new JFrame(); this.thisFrame.setTitle(Radon.PREFIX + " " + Radon.VERSION); this.thisFrame.setResizable(true); - this.thisFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + this.thisFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); this.thisFrame.setLocationRelativeTo(null); this.thisFrame.addWindowListener(new WindowAdapter() { @Override diff --git a/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java index d9b152a3..879dbbef 100644 --- a/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java @@ -17,167 +17,89 @@ package me.itzsomebody.radon.templates; -import java.security.MessageDigest; -import java.util.Arrays; -import java.util.Base64; -import javax.crypto.Cipher; -import javax.crypto.spec.SecretKeySpec; +import java.util.WeakHashMap; public class HeavyStringEncryption { - public static String decrypt(Object strToDecrypt, Object random, Object secret) { - boolean flow1 = true; - boolean flow2 = random != null; - do { - if (flow1 != flow2) { - random = strToDecrypt; - } - try { - while (!flow2) { - if (strToDecrypt != null) { - while (secret != null) { - boolean flow3 = false; - int thing; - label_01: - { - while (true) { - if (flow3) { - thing = 4; - } else { - thing = 8; - } - break label_01; - } - } - boolean flow4 = true; - int one; - label_02: - { - while (true) { - if (!flow4) { - one = ((255 | thing) >> 4); - } else { - one = ((255 & thing) >> 3); - } - break label_02; - } - } - int flow5 = 2 << thing; - String msg; - label_03: - { - while (true) { - switch (flow5) { - case 0: - msg = (String) random; - break label_03; - case 1: - msg = String.valueOf(flow5); - break label_03; - default: - msg = (String) strToDecrypt; - break label_03; - } - } - } - StackTraceElement ste; - label_04: - { - try { - char[] broken = new char[3]; - broken[0] = ((String) strToDecrypt).toCharArray()[0]; - broken[1] = ((String) strToDecrypt).toCharArray()[1]; - broken[2] = ((String) strToDecrypt).toCharArray()[2]; - broken[3] = ((String) strToDecrypt).toCharArray()[3]; - ste = new Throwable().getStackTrace()[one | 255]; - throw null; - } catch (Throwable t) { - ste = new Throwable().getStackTrace()[one - 1]; - break label_04; - } - } - int key1 = ste.getClassName().hashCode(); - int key2 = ste.getMethodName().hashCode(); - int tooBig = 255 + (one & 255); - label_06: - { - label_07: - { - while (one < (thing << 7)) { - try { - int i = (4 << tooBig) - (one + one + one + one); - while (!flow3) { - char[] chars = msg.toCharArray(); - char[] returnThis = new char[chars.length]; - try { - label_08: - { - label_09: - { - while (!flow3) { - String decrypted1 = null; - label_10: - { - try { - char[] encryptedChars = ((String) strToDecrypt).toCharArray(); - char[] decryptedChars = new char[encryptedChars.length]; - int j = 0; - while (j < encryptedChars.length) { - decryptedChars[j] = (char) (ste.getMethodName().hashCode() ^ ste.getClassName().hashCode() ^ encryptedChars[j]); - j++; - } + private static WeakHashMap decrypted; + private static int key1; + private static int key2; + + static { + decrypted = new WeakHashMap<>(); + StackTraceElement ste = Thread.currentThread().getStackTrace()[1]; + key1 = ste.getClassName().hashCode(); + key2 = ste.getMethodName().hashCode(); + } + + private static int getHashy(char[] chars) { + int hash = 1; + for (int i = 0; i < chars.length; i++) { + int thisChar = chars[i]; + int var1 = thisChar & 255; + int var2 = thisChar | 255; + int var3 = thisChar ^ 255; + int var4 = var1 << 4 | var2 >>> 4; + int var5 = var3 << 3 | var4 >>> 6; + var1 &= var4 << 2 | var1 >>> 2; + var3 |= var1 >> 4 | var2 << 2; + var2 ^= var5 >>> 4 | var3 << 6; + var4 += var2; + var5 = var1 >>> 5 | var3 << 2; + hash ^= var1 ^ var2 ^ var3 ^ var4 ^ var5; + } + + return hash; + } + + private static String returnCache(int hashy) { + return decrypted.get(hashy); + } + + private static void cacheString(String string, int hashy) { + decrypted.put(hashy, string); + } - decrypted1 = new String(decryptedChars); + public static String decrypt(Object encryptedString, Object useless, int key5) { + char[] chars = ((String) encryptedString).toCharArray(); + int hash = getHashy(chars); + String cacheResult = returnCache(hash); + if (cacheResult != null) + return cacheResult; - if (i > 255) { - break label_09; - } else { - break label_10; - } - } catch (Throwable t) { - throw null; - } - } - try { - SecretKeySpec secretKey; - byte[] key = ((String) secret).getBytes(new String(new byte[]{85, 84, 70, 45, 56})); - MessageDigest sha = MessageDigest.getInstance(new String(new byte[]{83, 72, 65, 45, 49})); - key = sha.digest(key); - key = Arrays.copyOf(key, 16); - secretKey = new SecretKeySpec(key, new String(new byte[]{65, 69, 83})); - Cipher cipher = Cipher.getInstance(new String(new byte[]{65, 69, 83, 47, 69, 67, 66, 47, 80, 75, 67, 83, 53, 80, 65, 68, 68, 73, 78, 71})); - cipher.init(Cipher.DECRYPT_MODE, secretKey); - return new String(cipher.doFinal(Base64.getDecoder().decode(decrypted1))); - } catch (Throwable t) { - if (one == 1) { - break label_08; - } else { - break label_09; - } - } - } - } - return (String) random; - } - return new String(returnThis); - } catch (Throwable t) { - return null; - } - } - } catch (Throwable t) { - return null; - } - } - } - } - } - } else { - throw null; - } - } - } catch (Throwable t) { - throw null; + StackTraceElement[] stes = Thread.currentThread().getStackTrace(); + int key3 = stes[2].getClassName().hashCode(); + int key4 = stes[2].getMethodName().hashCode(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < chars.length; i++) { + switch (i % 8) { + case 0: + sb.append((char) (key5 ^ key3 ^ chars[i])); + break; + case 1: + sb.append((char) (key4 ^ key2 ^ chars[i])); + break; + case 2: + sb.append((char) (key3 ^ key1 ^ chars[i])); + break; + case 3: + sb.append((char) (key2 ^ key5 ^ chars[i])); + break; + case 4: + sb.append((char) (key1 ^ key4 ^ chars[i])); + break; + case 5: + sb.append((char) (key2 ^ key3 ^ chars[i])); + break; + case 6: + sb.append((char) (key3 ^ key4 ^ chars[i])); + break; + case 7: + sb.append((char) (key4 ^ key5 ^ chars[i])); + break; } - } while (!flow2); - throw null; + } + String result = sb.toString(); + cacheString(result, hash); + return result; } } From fa4cfb28298ab02465bf173fba874d258e4f3713 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Sat, 30 Jun 2018 11:54:05 -0700 Subject: [PATCH 021/281] Un-did the supposed fix to ConsoleGUI --- src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java b/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java index 52ccf9c9..6216ee91 100644 --- a/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java @@ -76,7 +76,7 @@ private void init() { this.thisFrame = new JFrame(); this.thisFrame.setTitle(Radon.PREFIX + " " + Radon.VERSION); this.thisFrame.setResizable(true); - this.thisFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + this.thisFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); this.thisFrame.setLocationRelativeTo(null); this.thisFrame.addWindowListener(new WindowAdapter() { @Override From 5581e3c3c9fb90998185e4b11815468ccb8c22a5 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Mon, 2 Jul 2018 10:07:47 -0700 Subject: [PATCH 022/281] Changes to issue template --- ISSUE_TEMPLATE.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 670bcca7..a8226b88 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,13 +1,14 @@ **Which version of Radon are you using? (Do not say "latest", if you do, your issue will be immediately closed)** -**What kind of Jar file did you obfuscate?** +**What kind of Jar file did you obfuscate? (Android/Standalone/Plugin)** **What transformers did you use which caused an error?** * Transformer1 * Transformer2 * Transformer3 +* etc. -**Is Radon the issue or the jar Radon obfuscated the issue?** +**Is Radon the issue or the jar Radon obfuscated the issue? (if the obfuscated jar is the issue, make sure to provide the jar)** **What is the error produced? (Copy-and-paste error into [PasteBin](http://pastebin.com) or [HasteBin](http://hastebin.com) and link it here)** From a45bbea69f5ad83973e30a78ae9a60550ca46780 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Mon, 2 Jul 2018 10:12:58 -0700 Subject: [PATCH 023/281] Update the todos --- .../me/itzsomebody/radon/transformers/AbstractTransformer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java index ce72c3cd..98823b4a 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java @@ -31,7 +31,6 @@ /** * Abstract class used to make transformers. - * TODO: Allow dependency injection of class trees. * * @author ItzSomebody */ From 198b6e7df944473a61731d08761bb912bcc8c075 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Mon, 2 Jul 2018 10:18:39 -0700 Subject: [PATCH 024/281] Changed up the heavy string encryption transformer --- pom.xml | 2 +- src/main/java/me/itzsomebody/radon/Radon.java | 2 +- .../radon/classes/StringDecryptionClass.java | 499 ++++++++++++++++++ .../itzsomebody/radon/internal/Bootstrap.java | 1 + .../HeavyStringEncryption.java | 85 +-- .../itzsomebody/radon/utils/StringUtils.java | 79 +-- 6 files changed, 589 insertions(+), 79 deletions(-) create mode 100644 src/main/java/me/itzsomebody/radon/classes/StringDecryptionClass.java diff --git a/pom.xml b/pom.xml index 19d7417b..0e812887 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ me.itzsomebody Radon - 0.8.3 + 0.9.0 UTF-8 diff --git a/src/main/java/me/itzsomebody/radon/Radon.java b/src/main/java/me/itzsomebody/radon/Radon.java index 7a13ab51..ca6d02f5 100644 --- a/src/main/java/me/itzsomebody/radon/Radon.java +++ b/src/main/java/me/itzsomebody/radon/Radon.java @@ -31,7 +31,7 @@ public class Radon { * Static abuse variables xD */ public static String PREFIX = "[Radon]"; - public static String VERSION = "0.8.3"; + public static String VERSION = "0.9.0"; public static String AUTHORS = "ItzSomebody"; /** diff --git a/src/main/java/me/itzsomebody/radon/classes/StringDecryptionClass.java b/src/main/java/me/itzsomebody/radon/classes/StringDecryptionClass.java new file mode 100644 index 00000000..8e887db5 --- /dev/null +++ b/src/main/java/me/itzsomebody/radon/classes/StringDecryptionClass.java @@ -0,0 +1,499 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + + +package me.itzsomebody.radon.classes; + +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; + +public class StringDecryptionClass implements Opcodes { + public static ClassNode getHeavyDecrypt(String className, String decryptorMethodName, + String cacheFieldName, String key1FieldName, + String key2FieldName, String hashMethodName, + String hashGetterMethodName, String hashSetterMethodName) { + + ClassNode cw = new ClassNode(); + FieldVisitor fv; + MethodVisitor mv; + + cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, className, null, "java/lang/Object", null); + + { + fv = cw.visitField(ACC_PRIVATE + ACC_STATIC, cacheFieldName, "Ljava/util/HashMap;", "Ljava/util/HashMap;", null); + fv.visitEnd(); + } + { + fv = cw.visitField(ACC_PRIVATE + ACC_STATIC, key1FieldName, "I", null, null); + fv.visitEnd(); + } + { + fv = cw.visitField(ACC_PRIVATE + ACC_STATIC, key2FieldName, "I", null, null); + fv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_STATIC, "", "()V", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitTypeInsn(NEW, "java/util/HashMap"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "", "()V", false); + mv.visitFieldInsn(PUTSTATIC, className, cacheFieldName, "Ljava/util/HashMap;"); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getStackTrace", "()[Ljava/lang/StackTraceElement;", false); + mv.visitInsn(ICONST_1); + mv.visitInsn(AALOAD); + mv.visitVarInsn(ASTORE, 0); + Label l2 = new Label(); + mv.visitLabel(l2); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getClassName", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); + mv.visitFieldInsn(PUTSTATIC, className, key1FieldName, "I"); + Label l3 = new Label(); + mv.visitLabel(l3); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getMethodName", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); + mv.visitFieldInsn(PUTSTATIC, className, key2FieldName, "I"); + Label l4 = new Label(); + mv.visitLabel(l4); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, hashMethodName, "([C)I", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitInsn(ICONST_1); + mv.visitVarInsn(ISTORE, 1); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 2); + Label l2 = new Label(); + mv.visitLabel(l2); + Label l3 = new Label(); + mv.visitJumpInsn(GOTO, l3); + Label l4 = new Label(); + mv.visitLabel(l4); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ILOAD, 2); + mv.visitInsn(CALOAD); + mv.visitVarInsn(ISTORE, 3); + Label l5 = new Label(); + mv.visitLabel(l5); + mv.visitVarInsn(ILOAD, 3); + mv.visitIntInsn(SIPUSH, 255); + mv.visitInsn(IAND); + mv.visitVarInsn(ISTORE, 4); + Label l6 = new Label(); + mv.visitLabel(l6); + mv.visitVarInsn(ILOAD, 3); + mv.visitIntInsn(SIPUSH, 255); + mv.visitInsn(IOR); + mv.visitVarInsn(ISTORE, 5); + Label l7 = new Label(); + mv.visitLabel(l7); + mv.visitVarInsn(ILOAD, 3); + mv.visitIntInsn(SIPUSH, 255); + mv.visitInsn(IXOR); + mv.visitVarInsn(ISTORE, 6); + Label l8 = new Label(); + mv.visitLabel(l8); + mv.visitVarInsn(ILOAD, 4); + mv.visitInsn(ICONST_4); + mv.visitInsn(ISHL); + mv.visitVarInsn(ILOAD, 5); + mv.visitInsn(ICONST_4); + mv.visitInsn(IUSHR); + mv.visitInsn(IOR); + mv.visitVarInsn(ISTORE, 7); + Label l9 = new Label(); + mv.visitLabel(l9); + mv.visitVarInsn(ILOAD, 6); + mv.visitInsn(ICONST_3); + mv.visitInsn(ISHL); + mv.visitVarInsn(ILOAD, 7); + mv.visitIntInsn(BIPUSH, 6); + mv.visitInsn(IUSHR); + mv.visitInsn(IOR); + mv.visitVarInsn(ISTORE, 8); + Label l10 = new Label(); + mv.visitLabel(l10); + mv.visitVarInsn(ILOAD, 4); + mv.visitVarInsn(ILOAD, 7); + mv.visitInsn(ICONST_2); + mv.visitInsn(ISHL); + mv.visitVarInsn(ILOAD, 4); + mv.visitInsn(ICONST_2); + mv.visitInsn(IUSHR); + mv.visitInsn(IOR); + mv.visitInsn(IAND); + mv.visitVarInsn(ISTORE, 4); + Label l11 = new Label(); + mv.visitLabel(l11); + mv.visitVarInsn(ILOAD, 6); + mv.visitVarInsn(ILOAD, 4); + mv.visitInsn(ICONST_4); + mv.visitInsn(ISHR); + mv.visitVarInsn(ILOAD, 5); + mv.visitInsn(ICONST_2); + mv.visitInsn(ISHL); + mv.visitInsn(IOR); + mv.visitInsn(IOR); + mv.visitVarInsn(ISTORE, 6); + Label l12 = new Label(); + mv.visitLabel(l12); + mv.visitVarInsn(ILOAD, 5); + mv.visitVarInsn(ILOAD, 8); + mv.visitInsn(ICONST_4); + mv.visitInsn(IUSHR); + mv.visitVarInsn(ILOAD, 6); + mv.visitIntInsn(BIPUSH, 6); + mv.visitInsn(ISHL); + mv.visitInsn(IOR); + mv.visitInsn(IXOR); + mv.visitVarInsn(ISTORE, 5); + Label l13 = new Label(); + mv.visitLabel(l13); + mv.visitVarInsn(ILOAD, 7); + mv.visitVarInsn(ILOAD, 5); + mv.visitInsn(IADD); + mv.visitVarInsn(ISTORE, 7); + Label l14 = new Label(); + mv.visitLabel(l14); + mv.visitVarInsn(ILOAD, 4); + mv.visitInsn(ICONST_5); + mv.visitInsn(IUSHR); + mv.visitVarInsn(ILOAD, 6); + mv.visitInsn(ICONST_2); + mv.visitInsn(ISHL); + mv.visitInsn(IOR); + mv.visitVarInsn(ISTORE, 8); + Label l15 = new Label(); + mv.visitLabel(l15); + mv.visitVarInsn(ILOAD, 1); + mv.visitVarInsn(ILOAD, 4); + mv.visitVarInsn(ILOAD, 5); + mv.visitInsn(IXOR); + mv.visitVarInsn(ILOAD, 6); + mv.visitInsn(IXOR); + mv.visitVarInsn(ILOAD, 7); + mv.visitInsn(IXOR); + mv.visitVarInsn(ILOAD, 8); + mv.visitInsn(IXOR); + mv.visitInsn(IXOR); + mv.visitVarInsn(ISTORE, 1); + Label l16 = new Label(); + mv.visitLabel(l16); + mv.visitIincInsn(2, 1); + mv.visitLabel(l3); + mv.visitVarInsn(ILOAD, 2); + mv.visitVarInsn(ALOAD, 0); + mv.visitInsn(ARRAYLENGTH); + mv.visitJumpInsn(IF_ICMPLT, l4); + Label l17 = new Label(); + mv.visitLabel(l17); + mv.visitVarInsn(ILOAD, 1); + mv.visitInsn(IRETURN); + Label l18 = new Label(); + mv.visitLabel(l18); + mv.visitMaxs(4, 9); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, hashGetterMethodName, "(I)Ljava/lang/String;", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitFieldInsn(GETSTATIC, className, cacheFieldName, "Ljava/util/HashMap;"); + mv.visitVarInsn(ILOAD, 0); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/HashMap", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", false); + mv.visitTypeInsn(CHECKCAST, "java/lang/String"); + mv.visitInsn(ARETURN); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitMaxs(2, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, hashSetterMethodName, "(Ljava/lang/String;I)V", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitFieldInsn(GETSTATIC, className, cacheFieldName, "Ljava/util/HashMap;"); + mv.visitVarInsn(ILOAD, 1); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/HashMap", "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false); + mv.visitInsn(POP); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitInsn(RETURN); + Label l2 = new Label(); + mv.visitLabel(l2); + mv.visitMaxs(3, 2); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, decryptorMethodName, "(Ljava/lang/Object;Ljava/lang/Object;I)Ljava/lang/String;", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitTypeInsn(CHECKCAST, "java/lang/String"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); + mv.visitVarInsn(ASTORE, 3); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitVarInsn(ALOAD, 3); + mv.visitMethodInsn(INVOKESTATIC, className, hashMethodName, "([C)I", false); + mv.visitVarInsn(ISTORE, 4); + Label l2 = new Label(); + mv.visitLabel(l2); + mv.visitVarInsn(ILOAD, 4); + mv.visitMethodInsn(INVOKESTATIC, className, hashGetterMethodName, "(I)Ljava/lang/String;", false); + mv.visitVarInsn(ASTORE, 5); + Label l3 = new Label(); + mv.visitLabel(l3); + mv.visitVarInsn(ALOAD, 5); + Label l4 = new Label(); + mv.visitJumpInsn(IFNULL, l4); + Label l5 = new Label(); + mv.visitLabel(l5); + mv.visitVarInsn(ALOAD, 5); + mv.visitInsn(ARETURN); + mv.visitLabel(l4); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getStackTrace", "()[Ljava/lang/StackTraceElement;", false); + mv.visitVarInsn(ASTORE, 6); + Label l6 = new Label(); + mv.visitLabel(l6); + mv.visitVarInsn(ALOAD, 6); + mv.visitInsn(ICONST_2); + mv.visitInsn(AALOAD); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getClassName", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); + mv.visitVarInsn(ISTORE, 7); + Label l7 = new Label(); + mv.visitLabel(l7); + mv.visitVarInsn(ALOAD, 6); + mv.visitInsn(ICONST_2); + mv.visitInsn(AALOAD); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getMethodName", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); + mv.visitVarInsn(ISTORE, 8); + Label l8 = new Label(); + mv.visitLabel(l8); + mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "", "()V", false); + mv.visitVarInsn(ASTORE, 9); + Label l9 = new Label(); + mv.visitLabel(l9); + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 10); + Label l10 = new Label(); + mv.visitLabel(l10); + Label l11 = new Label(); + mv.visitJumpInsn(GOTO, l11); + Label l12 = new Label(); + mv.visitLabel(l12); + mv.visitVarInsn(ILOAD, 10); + mv.visitIntInsn(BIPUSH, 8); + mv.visitInsn(IREM); + Label l13 = new Label(); + Label l14 = new Label(); + Label l15 = new Label(); + Label l16 = new Label(); + Label l17 = new Label(); + Label l18 = new Label(); + Label l19 = new Label(); + Label l20 = new Label(); + Label l21 = new Label(); + mv.visitTableSwitchInsn(0, 7, l21, l13, l14, l15, l16, l17, l18, l19, l20); + mv.visitLabel(l13); + mv.visitVarInsn(ALOAD, 9); + mv.visitVarInsn(ILOAD, 2); + mv.visitVarInsn(ILOAD, 7); + mv.visitInsn(IXOR); + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ILOAD, 10); + mv.visitInsn(CALOAD); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + Label l22 = new Label(); + mv.visitLabel(l22); + mv.visitJumpInsn(GOTO, l21); + mv.visitLabel(l14); + mv.visitVarInsn(ALOAD, 9); + mv.visitVarInsn(ILOAD, 8); + mv.visitFieldInsn(GETSTATIC, className, key2FieldName, "I"); + mv.visitInsn(IXOR); + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ILOAD, 10); + mv.visitInsn(CALOAD); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + Label l23 = new Label(); + mv.visitLabel(l23); + mv.visitJumpInsn(GOTO, l21); + mv.visitLabel(l15); + mv.visitVarInsn(ALOAD, 9); + mv.visitVarInsn(ILOAD, 7); + mv.visitFieldInsn(GETSTATIC, className, key1FieldName, "I"); + mv.visitInsn(IXOR); + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ILOAD, 10); + mv.visitInsn(CALOAD); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + Label l24 = new Label(); + mv.visitLabel(l24); + mv.visitJumpInsn(GOTO, l21); + mv.visitLabel(l16); + mv.visitVarInsn(ALOAD, 9); + mv.visitFieldInsn(GETSTATIC, className, key2FieldName, "I"); + mv.visitVarInsn(ILOAD, 2); + mv.visitInsn(IXOR); + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ILOAD, 10); + mv.visitInsn(CALOAD); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + Label l25 = new Label(); + mv.visitLabel(l25); + mv.visitJumpInsn(GOTO, l21); + mv.visitLabel(l17); + mv.visitVarInsn(ALOAD, 9); + mv.visitFieldInsn(GETSTATIC, className, key1FieldName, "I"); + mv.visitVarInsn(ILOAD, 8); + mv.visitInsn(IXOR); + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ILOAD, 10); + mv.visitInsn(CALOAD); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + Label l26 = new Label(); + mv.visitLabel(l26); + mv.visitJumpInsn(GOTO, l21); + mv.visitLabel(l18); + mv.visitVarInsn(ALOAD, 9); + mv.visitFieldInsn(GETSTATIC, className, key2FieldName, "I"); + mv.visitVarInsn(ILOAD, 7); + mv.visitInsn(IXOR); + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ILOAD, 10); + mv.visitInsn(CALOAD); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + Label l27 = new Label(); + mv.visitLabel(l27); + mv.visitJumpInsn(GOTO, l21); + mv.visitLabel(l19); + mv.visitVarInsn(ALOAD, 9); + mv.visitVarInsn(ILOAD, 7); + mv.visitVarInsn(ILOAD, 8); + mv.visitInsn(IXOR); + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ILOAD, 10); + mv.visitInsn(CALOAD); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + Label l28 = new Label(); + mv.visitLabel(l28); + mv.visitJumpInsn(GOTO, l21); + mv.visitLabel(l20); + mv.visitVarInsn(ALOAD, 9); + mv.visitVarInsn(ILOAD, 8); + mv.visitVarInsn(ILOAD, 2); + mv.visitInsn(IXOR); + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ILOAD, 10); + mv.visitInsn(CALOAD); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + mv.visitLabel(l21); + mv.visitIincInsn(10, 1); + mv.visitLabel(l11); + mv.visitVarInsn(ILOAD, 10); + mv.visitVarInsn(ALOAD, 3); + mv.visitInsn(ARRAYLENGTH); + mv.visitJumpInsn(IF_ICMPLT, l12); + Label l29 = new Label(); + mv.visitLabel(l29); + mv.visitVarInsn(ALOAD, 9); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false); + mv.visitVarInsn(ASTORE, 10); + Label l30 = new Label(); + mv.visitLabel(l30); + mv.visitVarInsn(ALOAD, 10); + mv.visitVarInsn(ILOAD, 4); + mv.visitMethodInsn(INVOKESTATIC, className, hashSetterMethodName, "(Ljava/lang/String;I)V", false); + Label l31 = new Label(); + mv.visitLabel(l31); + mv.visitVarInsn(ALOAD, 10); + mv.visitInsn(ARETURN); + Label l32 = new Label(); + mv.visitLabel(l32); + mv.visitMaxs(4, 11); + mv.visitEnd(); + } + cw.visitEnd(); + + return cw; + } +} \ No newline at end of file diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index 19b938e1..4bbcc112 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -50,6 +50,7 @@ /** * Bootstraps and runs the obfuscation process. + * TODO: Create class hierarchy more efficiently. * * @author ItzSomebody */ diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java index 8163b657..4f0d61d9 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java @@ -18,13 +18,15 @@ package me.itzsomebody.radon.transformers.stringencryption; import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.methods.StringEncryption; +import me.itzsomebody.radon.classes.StringDecryptionClass; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.NumberUtils; import me.itzsomebody.radon.utils.StringUtils; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; @@ -55,51 +57,52 @@ public void obfuscate() { long current = System.currentTimeMillis(); this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started heavy string encryption transformer")); - String[] decryptorPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary)}; - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") - && hasInstructions(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (methodSize(methodNode) > 60000) break; - if (insn instanceof LdcInsnNode) { - Object cst = ((LdcInsnNode) insn).cst; + String[] decryptorPath = new String[]{StringUtils.randomClassName(classNames(), this.dictionary), StringUtils.randomString(this.dictionary)}; + this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> + classNode.methods.stream().filter(methodNode -> + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.name, "StringEncryption") + && hasInstructions(methodNode)).forEach(methodNode -> { + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (methodSize(methodNode) > 60000) break; + if (insn instanceof LdcInsnNode) { + Object cst = ((LdcInsnNode) insn).cst; - if (cst instanceof String) { - if (this.spigotMode && - ((String) cst).contains("%%__USER__%%") - || ((String) cst).contains("%%__RESOURCE__%%") - || ((String) cst).contains("%%__NONCE__%%")) - continue; + if (cst instanceof String) { + if (this.spigotMode && + ((String) cst).contains("%%__USER__%%") + || ((String) cst).contains("%%__RESOURCE__%%") + || ((String) cst).contains("%%__NONCE__%%")) + continue; - String keyLdc = StringUtils.randomString(this.dictionary); - ((LdcInsnNode) insn).cst = - StringUtils.heavyEncrypt(((String) ((LdcInsnNode) insn).cst), - keyLdc, decryptorPath[0].replace("/", "."), - decryptorPath[1]); - methodNode.instructions.insert(insn, - new MethodInsnNode(Opcodes.INVOKESTATIC, - decryptorPath[0], decryptorPath[1], - "(Ljava/lang/Object;" + - "Ljava/lang/Object;" + - "Ljava/lang/Object;)" + - "Ljava/lang/String;", - false)); - methodNode.instructions.insert(insn, - new LdcInsnNode(keyLdc)); - methodNode.instructions.insert(insn, - new InsnNode(ACONST_NULL)); - counter.incrementAndGet(); + int key1 = decryptorPath[0].replace("/", ".").hashCode(); + int key2 = "".hashCode(); + int key3 = classNode.name.replace("/", ".").hashCode(); + int key4 = methodNode.name.hashCode(); + int key5 = NumberUtils.getRandomInt(); + ((LdcInsnNode) insn).cst = + StringUtils.heavyEncrypt(((String) ((LdcInsnNode) insn).cst), key1, key2, key3, key4, key5); + methodNode.instructions.insert(insn, + new MethodInsnNode(Opcodes.INVOKESTATIC, + decryptorPath[0], decryptorPath[1], + "(Ljava/lang/Object;Ljava/lang/Object;I)Ljava/lang/String;", + false)); + methodNode.instructions.insert(insn, BytecodeUtils.getNumberInsn(key5)); + methodNode.instructions.insert(insn, new InsnNode(SWAP)); + methodNode.instructions.insert(insn, new InsnNode(POP)); + methodNode.instructions.insert(insn, new InsnNode(DUP_X1)); + methodNode.instructions.insert(insn, new InsnNode(ACONST_NULL)); + counter.incrementAndGet(); + } } } - } - }); - }); + }) + ); - this.classNodes().stream().filter(classNode -> classNode.name.equals(decryptorPath[0])).forEach(classNode -> { - classNode.methods.add(StringEncryption.heavyMethod(decryptorPath[1])); - classNode.access = BytecodeUtils.accessFixer(classNode.access); - }); + ClassNode decryptor = StringDecryptionClass.getHeavyDecrypt(decryptorPath[0], decryptorPath[1], + StringUtils.randomString(this.dictionary), StringUtils.randomString(this.dictionary), + StringUtils.randomString(this.dictionary), StringUtils.randomString(this.dictionary), + StringUtils.randomString(this.dictionary), StringUtils.randomString(this.dictionary)); + this.getClassMap().put(decryptor.name, decryptor); logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); } diff --git a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java index 7b8995c9..8f4e312f 100644 --- a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java @@ -278,8 +278,7 @@ public static String aesDecrypt(String strToDecrypt, String secret) { * @return a generated classname based on current class packages. */ public static String randomClassName(Collection theClassNames, int dictionary) { - List classNames = new ArrayList<>(); - classNames.addAll(theClassNames); + List classNames = new ArrayList<>(theClassNames); String randomClass = classNames.get(NumberUtils. getRandomInt(classNames.size())); @@ -302,12 +301,9 @@ public static String randomClassName(Collection theClassNames, int dicti * @return a generated classname based on current class packages. */ public static String randomClass(Collection theClassNames) { - List classNames = new ArrayList<>(); - classNames.addAll(theClassNames); + List classNames = new ArrayList<>(theClassNames); - String randomClass = classNames.get(NumberUtils - .getRandomInt(classNames.size())); - return randomClass; + return classNames.get(NumberUtils.getRandomInt(classNames.size())); } /** @@ -333,38 +329,49 @@ public static String normalEncrypt(String className, String methodName, } /** - * Returns encrypted {@link String} used by {@link HeavyStringEncryption}. + * Encrypts string for use in {@link HeavyStringEncryption}. * - * @param msg the string to encrypt. - * @param secret the key for AES to use. - * @param className the class name the string is contained in. - * @param methodName the method name the string is contained in. - * @return encrypted {@link String} used by {@link HeavyStringEncryption}. + * @param msg {@link String} to encrypt. + * @param key1 decryptor's containing class's name's hashcode. + * @param key2 hashcode of . + * @param key3 hashcode of the string's containing class's name's hashcode. + * @param key4 hashcode of the string's containing method's name's hashcode. + * @param key5 random integer to ensure randomization. + * @return {@link String} as the encrypted variant of the inputted string. */ - public static String heavyEncrypt(String msg, String secret, - String className, String methodName) { - char[] base64Chars; - try { - SecretKeySpec secretKey; - byte[] key = secret.getBytes("UTF-8"); - MessageDigest sha = MessageDigest.getInstance("SHA-1"); - key = sha.digest(key); - key = Arrays.copyOf(key, 16); - secretKey = new SecretKeySpec(key, "AES"); - Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); - cipher.init(Cipher.ENCRYPT_MODE, secretKey); - base64Chars = Base64.getEncoder().encodeToString(cipher. - doFinal(msg.getBytes("UTF-8"))).toCharArray(); - } catch (Throwable t) { - throw new IllegalStateException("Was unable to encrypt string " + - msg + " using " + secret); - } - char[] returnThis = new char[base64Chars.length]; - for (int i = 0; i < returnThis.length; i++) { - returnThis[i] = (char) (base64Chars[i] ^ className.hashCode() ^ - methodName.hashCode()); + public static String heavyEncrypt(String msg, int key1, int key2, int key3, int key4, int key5) { + char[] chars = msg.toCharArray(); + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < chars.length; i++) { + switch (i % 8) { + case 0: + sb.append((char) (chars[i] ^ key3 ^ key5)); + break; + case 1: + sb.append((char) (chars[i] ^ key2 ^ key4)); + break; + case 2: + sb.append((char) (chars[i] ^ key1 ^ key3)); + break; + case 3: + sb.append((char) (chars[i] ^ key5 ^ key2)); + break; + case 4: + sb.append((char) (chars[i] ^ key4 ^ key1)); + break; + case 5: + sb.append((char) (chars[i] ^ key3 ^ key2)); + break; + case 6: + sb.append((char) (chars[i] ^ key4 ^ key3)); + break; + case 7: + sb.append((char) (chars[i] ^ key5 ^ key4)); + break; + } } - return new String(returnThis); + return sb.toString(); } } From 79581dae85fd56ff7dc036677a5be2d0afaa649b Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Mon, 2 Jul 2018 10:20:40 -0700 Subject: [PATCH 025/281] It's official, bye bye old heavy string encryption transformer --- .../radon/methods/StringEncryption.java | 749 +----------------- 1 file changed, 1 insertion(+), 748 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java b/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java index 12b7d349..2118f5ae 100644 --- a/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java @@ -17,7 +17,6 @@ package me.itzsomebody.radon.methods; -import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; @@ -405,7 +404,7 @@ public static MethodNode normalMethod(String decryptionMethodName) { Label l50 = new Label(); Label l51 = new Label(); Label l52 = new Label(); - mv.visitTableSwitchInsn(0, 1, l52, new Label[]{l50, l51}); + mv.visitTableSwitchInsn(0, 1, l52, l50, l51); mv.visitLabel(l50); mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, 0, null); @@ -750,750 +749,4 @@ public static MethodNode normalMethod(String decryptionMethodName) { return mv; } - - /** - * Returns a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link HeavyStringEncryption}. - * - * @param decryptionMethodName used to determine the name of the - * generated {@link MethodNode}. - * @return a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link HeavyStringEncryption}. - */ - public static MethodNode heavyMethod(String decryptionMethodName) { - MethodNode mv = new MethodNode(ACC_PUBLIC + ACC_STATIC + - ACC_SYNTHETIC + ACC_BRIDGE, decryptionMethodName, - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)" + - "Ljava/lang/String;", null, null); - mv.visitCode(); - Label l0 = new Label(); - Label l1 = new Label(); - mv.visitTryCatchBlock(l0, l1, l1, "java/lang/Throwable"); - Label l2 = new Label(); - Label l3 = new Label(); - Label l4 = new Label(); - mv.visitTryCatchBlock(l2, l3, l4, "java/lang/Throwable"); - Label l5 = new Label(); - Label l6 = new Label(); - Label l7 = new Label(); - mv.visitTryCatchBlock(l5, l6, l7, "java/lang/Throwable"); - Label l8 = new Label(); - Label l9 = new Label(); - mv.visitTryCatchBlock(l8, l6, l9, "java/lang/Throwable"); - Label l10 = new Label(); - mv.visitTryCatchBlock(l7, l10, l9, "java/lang/Throwable"); - Label l11 = new Label(); - Label l12 = new Label(); - mv.visitTryCatchBlock(l11, l12, l9, "java/lang/Throwable"); - Label l13 = new Label(); - Label l14 = new Label(); - mv.visitTryCatchBlock(l13, l6, l14, "java/lang/Throwable"); - mv.visitTryCatchBlock(l7, l10, l14, "java/lang/Throwable"); - mv.visitTryCatchBlock(l11, l12, l14, "java/lang/Throwable"); - Label l15 = new Label(); - mv.visitTryCatchBlock(l9, l15, l14, "java/lang/Throwable"); - Label l16 = new Label(); - Label l17 = new Label(); - mv.visitTryCatchBlock(l16, l6, l17, "java/lang/Throwable"); - mv.visitTryCatchBlock(l7, l10, l17, "java/lang/Throwable"); - mv.visitTryCatchBlock(l11, l12, l17, "java/lang/Throwable"); - mv.visitTryCatchBlock(l9, l15, l17, "java/lang/Throwable"); - Label l18 = new Label(); - mv.visitTryCatchBlock(l14, l18, l17, "java/lang/Throwable"); - Label l19 = new Label(); - Label l20 = new Label(); - mv.visitTryCatchBlock(l19, l20, l17, "java/lang/Throwable"); - Label l21 = new Label(); - mv.visitLabel(l21); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ISTORE, 3); - Label l22 = new Label(); - mv.visitLabel(l22); - mv.visitVarInsn(ALOAD, 1); - Label l23 = new Label(); - mv.visitJumpInsn(IFNULL, l23); - mv.visitInsn(ICONST_1); - Label l24 = new Label(); - mv.visitJumpInsn(GOTO, l24); - mv.visitLabel(l23); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitInsn(ICONST_0); - mv.visitLabel(l24); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{Opcodes.INTEGER}); - mv.visitVarInsn(ISTORE, 4); - Label l25 = new Label(); - mv.visitLabel(l25); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitVarInsn(ILOAD, 3); - mv.visitVarInsn(ILOAD, 4); - Label l26 = new Label(); - mv.visitJumpInsn(IF_ICMPEQ, l26); - Label l27 = new Label(); - mv.visitLabel(l27); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ASTORE, 1); - mv.visitLabel(l16); - mv.visitJumpInsn(GOTO, l26); - Label l28 = new Label(); - mv.visitLabel(l28); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 0); - Label l29 = new Label(); - mv.visitJumpInsn(IFNULL, l29); - Label l30 = new Label(); - mv.visitLabel(l30); - Label l31 = new Label(); - mv.visitJumpInsn(GOTO, l31); - Label l32 = new Label(); - mv.visitLabel(l32); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 5); - Label l33 = new Label(); - mv.visitLabel(l33); - mv.visitVarInsn(ILOAD, 5); - Label l34 = new Label(); - mv.visitJumpInsn(IFEQ, l34); - Label l35 = new Label(); - mv.visitLabel(l35); - mv.visitInsn(ICONST_4); - mv.visitVarInsn(ISTORE, 6); - Label l36 = new Label(); - mv.visitLabel(l36); - Label l37 = new Label(); - mv.visitJumpInsn(GOTO, l37); - mv.visitLabel(l34); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitIntInsn(BIPUSH, 8); - mv.visitVarInsn(ISTORE, 6); - mv.visitLabel(l37); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ISTORE, 7); - Label l38 = new Label(); - mv.visitLabel(l38); - mv.visitVarInsn(ILOAD, 7); - Label l39 = new Label(); - mv.visitJumpInsn(IFNE, l39); - Label l40 = new Label(); - mv.visitLabel(l40); - mv.visitIntInsn(SIPUSH, 255); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(IOR); - mv.visitInsn(ICONST_4); - mv.visitInsn(ISHR); - mv.visitVarInsn(ISTORE, 8); - Label l41 = new Label(); - mv.visitLabel(l41); - Label l42 = new Label(); - mv.visitJumpInsn(GOTO, l42); - mv.visitLabel(l39); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitIntInsn(SIPUSH, 255); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(IAND); - mv.visitInsn(ICONST_3); - mv.visitInsn(ISHR); - mv.visitVarInsn(ISTORE, 8); - mv.visitLabel(l42); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitInsn(ICONST_2); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(ISHL); - mv.visitVarInsn(ISTORE, 9); - Label l43 = new Label(); - mv.visitLabel(l43); - mv.visitVarInsn(ILOAD, 9); - Label l44 = new Label(); - Label l45 = new Label(); - Label l46 = new Label(); - mv.visitTableSwitchInsn(0, 1, l46, new Label[]{l44, l45}); - mv.visitLabel(l44); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitVarInsn(ASTORE, 10); - Label l47 = new Label(); - mv.visitLabel(l47); - mv.visitJumpInsn(GOTO, l0); - mv.visitLabel(l45); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 9); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", - "(I)Ljava/lang/String;", false); - mv.visitVarInsn(ASTORE, 10); - Label l48 = new Label(); - mv.visitLabel(l48); - mv.visitJumpInsn(GOTO, l0); - mv.visitLabel(l46); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitVarInsn(ASTORE, 10); - mv.visitLabel(l0); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{"java/lang/String"}, - 0, null); - mv.visitInsn(ICONST_3); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 12); - Label l49 = new Label(); - mv.visitLabel(l49); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_0); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l50 = new Label(); - mv.visitLabel(l50); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_1); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l51 = new Label(); - mv.visitLabel(l51); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_2); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_2); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l52 = new Label(); - mv.visitLabel(l52); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_3); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_3); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l53 = new Label(); - mv.visitLabel(l53); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", - "()Ljava/lang/Thread;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getStackTrace", - "()[Ljava/lang/StackTraceElement;", false); - mv.visitVarInsn(ILOAD, 8); - mv.visitIntInsn(SIPUSH, 255); - mv.visitInsn(IOR); - mv.visitInsn(AALOAD); - mv.visitVarInsn(ASTORE, 11); - Label l54 = new Label(); - mv.visitLabel(l54); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l1); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 12); - Label l55 = new Label(); - mv.visitLabel(l55); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", - "()Ljava/lang/Thread;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getStackTrace", - "()[Ljava/lang/StackTraceElement;", false); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(AALOAD); - mv.visitVarInsn(ASTORE, 11); - Label l56 = new Label(); - mv.visitLabel(l56); - mv.visitVarInsn(ALOAD, 11); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getClassName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitVarInsn(ISTORE, 12); - Label l57 = new Label(); - mv.visitLabel(l57); - mv.visitVarInsn(ALOAD, 11); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getMethodName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitVarInsn(ISTORE, 13); - Label l58 = new Label(); - mv.visitLabel(l58); - mv.visitIntInsn(SIPUSH, 255); - mv.visitVarInsn(ILOAD, 8); - mv.visitIntInsn(SIPUSH, 255); - mv.visitInsn(IAND); - mv.visitInsn(IADD); - mv.visitVarInsn(ISTORE, 14); - Label l59 = new Label(); - mv.visitLabel(l59); - mv.visitJumpInsn(GOTO, l19); - mv.visitLabel(l13); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, "java/lang/String", - "java/lang/StackTraceElement", Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitInsn(ICONST_4); - mv.visitVarInsn(ILOAD, 14); - mv.visitInsn(ISHL); - mv.visitVarInsn(ILOAD, 8); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(IADD); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(IADD); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(IADD); - mv.visitInsn(ISUB); - mv.visitVarInsn(ISTORE, 15); - Label l60 = new Label(); - mv.visitLabel(l60); - mv.visitVarInsn(ILOAD, 5); - mv.visitJumpInsn(IFNE, l19); - Label l61 = new Label(); - mv.visitLabel(l61); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 16); - Label l62 = new Label(); - mv.visitLabel(l62); - mv.visitVarInsn(ALOAD, 16); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 17); - mv.visitLabel(l8); - mv.visitVarInsn(ILOAD, 5); - Label l63 = new Label(); - mv.visitJumpInsn(IFNE, l63); - Label l64 = new Label(); - mv.visitLabel(l64); - mv.visitInsn(ACONST_NULL); - mv.visitVarInsn(ASTORE, 18); - mv.visitLabel(l2); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 19); - Label l65 = new Label(); - mv.visitLabel(l65); - mv.visitVarInsn(ALOAD, 19); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 20); - Label l66 = new Label(); - mv.visitLabel(l66); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 21); - Label l67 = new Label(); - mv.visitLabel(l67); - Label l68 = new Label(); - mv.visitJumpInsn(GOTO, l68); - Label l69 = new Label(); - mv.visitLabel(l69); - mv.visitFrame(Opcodes.F_FULL, 22, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, "java/lang/String", - "java/lang/StackTraceElement", Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER, - "[C", "[C", "java/lang/String", "[C", "[C", - Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 20); - mv.visitVarInsn(ILOAD, 21); - mv.visitVarInsn(ALOAD, 11); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getMethodName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitVarInsn(ALOAD, 11); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getClassName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitInsn(IXOR); - mv.visitVarInsn(ALOAD, 19); - mv.visitVarInsn(ILOAD, 21); - mv.visitInsn(CALOAD); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l70 = new Label(); - mv.visitLabel(l70); - mv.visitIincInsn(21, 1); - mv.visitLabel(l68); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 21); - mv.visitVarInsn(ALOAD, 19); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l69); - Label l71 = new Label(); - mv.visitLabel(l71); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 20); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitVarInsn(ASTORE, 18); - Label l72 = new Label(); - mv.visitLabel(l72); - mv.visitVarInsn(ILOAD, 15); - mv.visitIntInsn(SIPUSH, 255); - mv.visitJumpInsn(IF_ICMPLE, l5); - mv.visitLabel(l3); - mv.visitJumpInsn(GOTO, l63); - mv.visitLabel(l4); - mv.visitFrame(Opcodes.F_FULL, 19, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, "java/lang/String", - "java/lang/StackTraceElement", Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER, - "[C", "[C", "java/lang/String"}, - 1, new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 19); - Label l73 = new Label(); - mv.visitLabel(l73); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l5); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_5); - mv.visitIntInsn(NEWARRAY, T_BYTE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_0); - mv.visitIntInsn(BIPUSH, 85); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_1); - mv.visitIntInsn(BIPUSH, 84); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_2); - mv.visitIntInsn(BIPUSH, 70); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_3); - mv.visitIntInsn(BIPUSH, 45); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_4); - mv.visitIntInsn(BIPUSH, 56); - mv.visitInsn(BASTORE); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([B)V", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", - "(Ljava/lang/String;)[B", false); - mv.visitVarInsn(ASTORE, 20); - Label l74 = new Label(); - mv.visitLabel(l74); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_5); - mv.visitIntInsn(NEWARRAY, T_BYTE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_0); - mv.visitIntInsn(BIPUSH, 83); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_1); - mv.visitIntInsn(BIPUSH, 72); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_2); - mv.visitIntInsn(BIPUSH, 65); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_3); - mv.visitIntInsn(BIPUSH, 45); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_4); - mv.visitIntInsn(BIPUSH, 49); - mv.visitInsn(BASTORE); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([B)V", false); - mv.visitMethodInsn(INVOKESTATIC, "java/security/MessageDigest", - "getInstance", "(Ljava/lang/String;)" + - "Ljava/security/MessageDigest;", false); - mv.visitVarInsn(ASTORE, 21); - Label l75 = new Label(); - mv.visitLabel(l75); - mv.visitVarInsn(ALOAD, 21); - mv.visitVarInsn(ALOAD, 20); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/security/MessageDigest", - "digest", "([B)[B", false); - mv.visitVarInsn(ASTORE, 20); - Label l76 = new Label(); - mv.visitLabel(l76); - mv.visitVarInsn(ALOAD, 20); - mv.visitIntInsn(BIPUSH, 16); - mv.visitMethodInsn(INVOKESTATIC, "java/util/Arrays", "copyOf", - "([BI)[B", false); - mv.visitVarInsn(ASTORE, 20); - Label l77 = new Label(); - mv.visitLabel(l77); - mv.visitTypeInsn(NEW, "javax/crypto/spec/SecretKeySpec"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 20); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_3); - mv.visitIntInsn(NEWARRAY, T_BYTE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_0); - mv.visitIntInsn(BIPUSH, 65); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_1); - mv.visitIntInsn(BIPUSH, 69); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_2); - mv.visitIntInsn(BIPUSH, 83); - mv.visitInsn(BASTORE); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([B)V", false); - mv.visitMethodInsn(INVOKESPECIAL, "javax/crypto/spec/SecretKeySpec", - "", "([BLjava/lang/String;)V", false); - mv.visitVarInsn(ASTORE, 19); - Label l78 = new Label(); - mv.visitLabel(l78); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 20); - mv.visitIntInsn(NEWARRAY, T_BYTE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_0); - mv.visitIntInsn(BIPUSH, 65); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_1); - mv.visitIntInsn(BIPUSH, 69); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_2); - mv.visitIntInsn(BIPUSH, 83); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_3); - mv.visitIntInsn(BIPUSH, 47); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_4); - mv.visitIntInsn(BIPUSH, 69); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_5); - mv.visitIntInsn(BIPUSH, 67); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 6); - mv.visitIntInsn(BIPUSH, 66); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 7); - mv.visitIntInsn(BIPUSH, 47); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 8); - mv.visitIntInsn(BIPUSH, 80); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 9); - mv.visitIntInsn(BIPUSH, 75); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 10); - mv.visitIntInsn(BIPUSH, 67); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 11); - mv.visitIntInsn(BIPUSH, 83); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 12); - mv.visitIntInsn(BIPUSH, 53); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 13); - mv.visitIntInsn(BIPUSH, 80); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 14); - mv.visitIntInsn(BIPUSH, 65); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 15); - mv.visitIntInsn(BIPUSH, 68); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 16); - mv.visitIntInsn(BIPUSH, 68); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 17); - mv.visitIntInsn(BIPUSH, 73); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 18); - mv.visitIntInsn(BIPUSH, 78); - mv.visitInsn(BASTORE); - mv.visitInsn(DUP); - mv.visitIntInsn(BIPUSH, 19); - mv.visitIntInsn(BIPUSH, 71); - mv.visitInsn(BASTORE); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([B)V", false); - mv.visitMethodInsn(INVOKESTATIC, "javax/crypto/Cipher", "getInstance", - "(Ljava/lang/String;)Ljavax/crypto/Cipher;", false); - mv.visitVarInsn(ASTORE, 22); - Label l79 = new Label(); - mv.visitLabel(l79); - mv.visitVarInsn(ALOAD, 22); - mv.visitInsn(ICONST_2); - mv.visitVarInsn(ALOAD, 19); - mv.visitMethodInsn(INVOKEVIRTUAL, "javax/crypto/Cipher", "init", - "(ILjava/security/Key;)V", false); - Label l80 = new Label(); - mv.visitLabel(l80); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 22); - mv.visitMethodInsn(INVOKESTATIC, "java/util/Base64", "getDecoder", - "()Ljava/util/Base64$Decoder;", false); - mv.visitVarInsn(ALOAD, 18); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/Base64$Decoder", "decode", - "(Ljava/lang/String;)[B", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "javax/crypto/Cipher", "doFinal", - "([B)[B", false); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([B)V", false); - mv.visitLabel(l6); - mv.visitInsn(ARETURN); - mv.visitLabel(l7); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 19); - Label l81 = new Label(); - mv.visitLabel(l81); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(ICONST_1); - mv.visitJumpInsn(IF_ICMPNE, l63); - Label l82 = new Label(); - mv.visitLabel(l82); - mv.visitJumpInsn(GOTO, l11); - mv.visitLabel(l63); - mv.visitFrame(Opcodes.F_CHOP, 1, null, 0, null); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitLabel(l10); - mv.visitInsn(ARETURN); - mv.visitLabel(l11); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 17); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitLabel(l12); - mv.visitInsn(ARETURN); - mv.visitLabel(l9); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 18); - mv.visitLabel(l15); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitLabel(l14); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, "java/lang/String", - "java/lang/StackTraceElement", Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER}, - 1, new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 15); - mv.visitLabel(l18); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitLabel(l19); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 8); - mv.visitVarInsn(ILOAD, 6); - mv.visitIntInsn(BIPUSH, 7); - mv.visitInsn(ISHL); - mv.visitJumpInsn(IF_ICMPLT, l13); - mv.visitLabel(l31); - mv.visitFrame(Opcodes.F_FULL, 5, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - Opcodes.INTEGER, Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 2); - mv.visitJumpInsn(IFNONNULL, l32); - Label l83 = new Label(); - mv.visitLabel(l83); - mv.visitJumpInsn(GOTO, l26); - mv.visitLabel(l29); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l26); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l28); - mv.visitLabel(l20); - Label l84 = new Label(); - mv.visitJumpInsn(GOTO, l84); - mv.visitLabel(l17); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 5); - Label l85 = new Label(); - mv.visitLabel(l85); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l84); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l25); - Label l86 = new Label(); - mv.visitLabel(l86); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - Label l87 = new Label(); - mv.visitLabel(l87); - mv.visitMaxs(9, 23); - mv.visitEnd(); - - return mv; - } } From 8df1baf564ea797fa61ec9bf8fdd62ff292e1b89 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Mon, 2 Jul 2018 10:25:58 -0700 Subject: [PATCH 026/281] Updated changelog + rewrote string pool --- CHANGELOG.md | 5 ++ .../radon/transformers/misc/StringPool.java | 61 ++++++++++++------- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae263803..31b35066 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.9.0 +* Changed all anonymous inner classes in MainGUI class to lambdas. +* Brand new heavy string encryption transformer. +* Rewrote the string pool transformer. + ## 0.8.3 * Added compensation for the fact that methods with the native flag don't have instructions in them. diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java b/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java index 9782fdd6..b02de572 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java @@ -26,14 +26,18 @@ import me.itzsomebody.radon.utils.StringUtils; import org.objectweb.asm.Label; import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; /** * Transformer that takes all the strings in a class and pools them into a - * method. When the string is needed, the - * string pool method is called with an index number. + * field. When the string is needed, the string pool field is called with + * an index number. * * @author ItzSomebody */ @@ -48,6 +52,11 @@ public class StringPool extends AbstractTransformer { */ private String[] strings; + /** + * Field path. + */ + private String[] fieldName = new String[2]; + /** * Applies obfuscation. */ @@ -56,11 +65,13 @@ public void obfuscate() { long current = System.currentTimeMillis(); this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started string pool transformer.")); - this.randName = StringUtils.randomString(this.dictionary); this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringPool")).forEach(classNode -> { + this.randName = StringUtils.randomString(this.dictionary); + this.fieldName[0] = classNode.name; + this.fieldName[1] = StringUtils.randomString(this.dictionary); List stringslist = new ArrayList<>(); classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringPool") + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.name, "StringPool") && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (insn instanceof LdcInsnNode) { @@ -71,10 +82,9 @@ && hasInstructions(methodNode)).forEach(methodNode -> { int indexNumber = stringslist.size() - 1; - methodNode.instructions.insertBefore(insn, - BytecodeUtils.getNumberInsn(indexNumber)); - methodNode.instructions.set(insn, - new MethodInsnNode(INVOKESTATIC, classNode.name, randName, "(I)Ljava/lang/String;", false)); + methodNode.instructions.insertBefore(insn, new FieldInsnNode(GETSTATIC, classNode.name, this.fieldName[1], "[Ljava/lang/String;")); + methodNode.instructions.insertBefore(insn, BytecodeUtils.getNumberInsn(indexNumber)); + methodNode.instructions.set(insn, new InsnNode(AALOAD)); counter.incrementAndGet(); } } @@ -86,6 +96,22 @@ && hasInstructions(methodNode)).forEach(methodNode -> { this.strings[i] = stringslist.get(i); } classNode.methods.add(stringPool()); + + MethodNode clinit = classNode.methods.stream().filter(methodNode -> methodNode.name.equals("")).findFirst().orElse(null); + if (clinit == null) { + clinit = new MethodNode(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "", "()V", null, null); + InsnList insns = new InsnList(); + insns.add(new MethodInsnNode(INVOKESTATIC, classNode.name, randName, "()V", false)); + insns.add(new InsnNode(RETURN)); + clinit.instructions = insns; + classNode.methods.add(clinit); + } else { + clinit.instructions.insertBefore(clinit.instructions.getFirst(), new MethodInsnNode(INVOKESTATIC, classNode.name, randName, "()V", false)); + } + FieldNode fieldNode = new FieldNode(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, this.fieldName[1], "[Ljava/lang/String;", null, null); + if (classNode.fields == null) + classNode.fields = new ArrayList<>(); + classNode.fields.add(fieldNode); } }); this.logStrings.add(LoggerUtils.stdOut("Pooled " + counter + " strings.")); @@ -98,7 +124,7 @@ && hasInstructions(methodNode)).forEach(methodNode -> { * @return string pool method which contains all the strings. */ private MethodNode stringPool() { - MethodNode method = new MethodNode(ACC_PUBLIC + ACC_STATIC + ACC_SYNTHETIC + ACC_BRIDGE, randName, "(I)Ljava/lang/String;", null, null); + MethodNode method = new MethodNode(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC + ACC_BRIDGE, randName, "()V", null, null); method.visitCode(); @@ -133,19 +159,10 @@ private MethodNode stringPool() { method.visitLdcInsn(this.strings[i]); method.visitInsn(AASTORE); } - method.visitVarInsn(ASTORE, 1); - Label l1 = new Label(); - method.visitLabel(l1); - method.visitVarInsn(ALOAD, 1); - method.visitVarInsn(ILOAD, 0); - method.visitInsn(AALOAD); - method.visitVarInsn(ASTORE, 2); - Label l2 = new Label(); - method.visitLabel(l2); - method.visitVarInsn(ALOAD, 2); - method.visitInsn(ARETURN); - - method.visitMaxs(4, 3); + method.visitFieldInsn(PUTSTATIC, this.fieldName[0], this.fieldName[1], "[Ljava/lang/String;"); + method.visitInsn(RETURN); + + method.visitMaxs(3, 0); method.visitEnd(); From 876d02987b7e914504ec1f984658df3bed78fa9e Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Mon, 2 Jul 2018 10:27:47 -0700 Subject: [PATCH 027/281] Oops, should add that as well :P --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31b35066..a376c067 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * Changed all anonymous inner classes in MainGUI class to lambdas. * Brand new heavy string encryption transformer. * Rewrote the string pool transformer. +* Rewrote some internals including dependency injection of the Bootstrap instance instead of per-case depedency injection. ## 0.8.3 From 5d197b59b09f75b52c32cc4cad88b637204da686 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Mon, 2 Jul 2018 10:29:02 -0700 Subject: [PATCH 028/281] And... yet another todo --- src/main/java/me/itzsomebody/radon/internal/Bootstrap.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index 4bbcc112..78367bb8 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -51,6 +51,7 @@ /** * Bootstraps and runs the obfuscation process. * TODO: Create class hierarchy more efficiently. + * TODO: Renaming classes causes exempts on other classes to not work. * * @author ItzSomebody */ From 02a8b78d512b6540b237cc114285bd242ddf7397 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Mon, 2 Jul 2018 10:32:07 -0700 Subject: [PATCH 029/281] Readme update now lol --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1b800602..82340334 100644 --- a/README.md +++ b/README.md @@ -134,14 +134,14 @@ This table describes the current obfuscation settings Radon has. ## Credits -* [OW2 ASM](http://asm.ow2.org) - ObjectWeb ASM. -* [SnakeYaml](http://www.snakeyaml.org) - SnameYAML. +* [OW2 ASM](http://asm.ow2.org) - Bytecode manipulation framework. +* [SnakeYaml](http://www.snakeyaml.org) - Configuration parser. * [VincBreaker](https://github.com/Vinc0682) - Author of Smoke obfuscator which I took some ideas from. (i.e. Renaming classes as spaces and splitting numbers into bitwise xor operations) * [WindowBuilder by Eclipse](https://www.eclipse.org/windowbuilder/) - Used to make GUI (yes I know it's Java Swing, I didn't feel like remaking it in JavaFX) -* [Licel](https://licelus.com) - Makers of IndyProtect. -* [Allatori Dev Team](http://www.allatori.com) - Makers of Allatori Java Obfuscator. +* [Licel](https://licelus.com) - Makers of IndyProtect which I used as a reference for my invokedynamic transformers. +* [Allatori Dev Team](http://www.allatori.com) - Makers of Allatori Java Obfuscator which I borrowed the concept of watermarking and expiration obfuscation from. * [Artel](https://gitlab.com/artel) - Beta tester. ## License -GNU General Public License v3.0 \ No newline at end of file +GNU General Public License v3.0 (The cancer license) \ No newline at end of file From b2c61362cdc0121cd92678c1b78ce08cc6a1435f Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Mon, 2 Jul 2018 10:50:31 -0700 Subject: [PATCH 030/281] Update the readme again -_- --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 82340334..1d4e3d48 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ This table describes the current obfuscation settings Radon has. | Obfuscation Type | Description | | --- | --- | -| StringEncryption | This takes the strings in your program and encrypts them. Each of the current settings are symmetrical and will NOT prevent reverse-engineers from figuring out what your program does. The super light setting uses an extremely simple xor algorithm and is not secure. The light setting uses a simple algorithm which encrypts the strings for speed. There is minimal flow obfuscation in the light setting so be aware this offers minimal protection. The normal string encryption setting is basically a flow-obfuscated version of the light string encryption, it is intended to make the decryption method more confusing. The heavy method uses AES to encrypt the strings. | +| StringEncryption | This takes the strings in your program and encrypts them. Each of the current settings are symmetrical and will NOT prevent reverse-engineers from figuring out what your program does. The super light setting uses an extremely simple xor algorithm and is not secure. The light setting uses a simple algorithm which encrypts the strings for speed. There is minimal flow obfuscation in the light setting so be aware this offers minimal protection. The normal string encryption setting is basically a flow-obfuscated version of the light string encryption, it is intended to make the decryption method more confusing. The heavy method is stacktrace-backed by both the caller and method name. | | FlowObfuscation | This attempts to confuse the program flow to make the decompiled code harder to understand. The light setting replaces all gotos in the program with conditionals which always evaluate to true. The light setting usually doesn't affect decompiler results by much unless you have methods with some certain flow control situations. The normal flow obfuscation attempts to find places in the bytecode where the stack is empty. It uses an injected predicate which is used to make false jumps and add some extra throw-nulls in random places. | | InvokeDynamic | This abuses Java 7's new opcode, the invokedynamic. This replaces certain member access with dynamic invocations. The light invokedynamic transformer is very simple and replaces invokestatic, invokevirtual and invokeinterface with invokedynamics. This is easily reversed by experienced reverse-engineers so don't rely on this. The normal invokedynamic protection is a very slight improvement to the light settings, but still is easy to reverse. The heavy invokedynamic hides invokestatic, invokevirtual, getstatic, putstatic, getfield and putfield opcodes with invokedynamics. | | LocalVariableObfuscation | This attempts to prevent local variable analysis. The obfuscation setting changes the names of the local variables to hard-to-read UTF-8 characters. The remove setting removes the local variable information completely destroying the ability to recover the local variable names. Removal setting tends to shrink jar size since it removes information in the code. | From 55ba97d871470d4b60d0227d5928e4d5b2af8757 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Mon, 2 Jul 2018 10:54:52 -0700 Subject: [PATCH 031/281] Welp, here we go again. Another readme update --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1d4e3d48..4d14754b 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ This table describes the current obfuscation settings Radon has. | Obfuscation Type | Description | | --- | --- | | StringEncryption | This takes the strings in your program and encrypts them. Each of the current settings are symmetrical and will NOT prevent reverse-engineers from figuring out what your program does. The super light setting uses an extremely simple xor algorithm and is not secure. The light setting uses a simple algorithm which encrypts the strings for speed. There is minimal flow obfuscation in the light setting so be aware this offers minimal protection. The normal string encryption setting is basically a flow-obfuscated version of the light string encryption, it is intended to make the decryption method more confusing. The heavy method is stacktrace-backed by both the caller and method name. | -| FlowObfuscation | This attempts to confuse the program flow to make the decompiled code harder to understand. The light setting replaces all gotos in the program with conditionals which always evaluate to true. The light setting usually doesn't affect decompiler results by much unless you have methods with some certain flow control situations. The normal flow obfuscation attempts to find places in the bytecode where the stack is empty. It uses an injected predicate which is used to make false jumps and add some extra throw-nulls in random places. | +| FlowObfuscation | This attempts to confuse the program flow to make the decompiled code harder to understand. The light setting replaces all gotos in the program with conditionals which always evaluate to true. The light setting usually doesn't affect decompiler results by much unless you have methods with some certain flow control situations. The normal flow obfuscation attempts to find places in the bytecode where the stack is empty. It uses an injected predicate which is used to make false jumps and add some extra throw-nulls in random places. The heavy setting takes the normal flow one step further by inserting a conditional which is always true after all conditional statements found in the bytecode. | | InvokeDynamic | This abuses Java 7's new opcode, the invokedynamic. This replaces certain member access with dynamic invocations. The light invokedynamic transformer is very simple and replaces invokestatic, invokevirtual and invokeinterface with invokedynamics. This is easily reversed by experienced reverse-engineers so don't rely on this. The normal invokedynamic protection is a very slight improvement to the light settings, but still is easy to reverse. The heavy invokedynamic hides invokestatic, invokevirtual, getstatic, putstatic, getfield and putfield opcodes with invokedynamics. | | LocalVariableObfuscation | This attempts to prevent local variable analysis. The obfuscation setting changes the names of the local variables to hard-to-read UTF-8 characters. The remove setting removes the local variable information completely destroying the ability to recover the local variable names. Removal setting tends to shrink jar size since it removes information in the code. | | Crasher | This adds an invalid signature to classes. The intention of this transformer is to crash a majority of decompiles which attempt to take class signatures into account of the output. This crashes JD-GUI, Procyon, CFR and Javap. | @@ -125,7 +125,7 @@ This table describes the current obfuscation settings Radon has. | NumberObfuscation | This splits integers into a xor expression making it difficult to determine what number is being used. This is defeated by Krakatau. | | SourceNameObfuscation | This attempts to obscure stacktrace output by removing sourcefile debug information. The obfuscation setting sets all the source file names to random ones. The removal setting removes them entirely from your code. The removal setting also shrinks the size of the jar. | | SourceDebugObfuscation | This attempts to obscure source debug information. The obfuscation setting sets all the source debug values to random ones. The removal setting removes them entirely from your code. The removal setting also shrinks the size of the jar. | -| TrashClasses | This generates garbage classes which aren't used to attempt to hide the ones that are actually used. This also prevents JByteEdit usage. | +| TrashClasses | This generates garbage classes which aren't used to attempt to hide the ones that are actually used. This also prevents JByteEdit usage which is a widely used tool by people who implement Minecraft plugin cracks. | | Watermark | This marks a message into the classes which is intended for customer-identification. The constant pool option marks the message into the constant pool of each class. The signature option marks the messages into the class signature. | | Renamer | This renames classes, methods and fields from their original names to random UTF-8 strings. | | Shuffler | This simply changes the order of class members (methods and fields). | From 800720b490dd2dd2b05ccafee69a030040e32176 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Tue, 3 Jul 2018 10:30:40 -0700 Subject: [PATCH 032/281] Better handling of when transformers are enabled --- .../me/itzsomebody/radon/gui/MainGUI.java | 25 ------------------- .../itzsomebody/radon/internal/Bootstrap.java | 5 ++++ 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java index a56e2db9..e6ca7354 100644 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java @@ -1133,31 +1133,6 @@ private void initialize() { return; } - if (!chckbxStringEncryption.isSelected() - && !chckbxInvokeDynamic.isSelected() - && !chckbxFlow.isSelected() - && !chckbxLocalVariables.isSelected() - && !chckbxTrashClasses.isSelected() - && !chckbxSpringPool.isSelected() - && !chckbxCrasher.isSelected() - && !chckbxHidecode.isSelected() - && !chckbxClassRenammer.isSelected() - && !chckbxNumberObfuscation.isSelected() - && !chckbxAddWatermark.isSelected() - && !chckbxLineObfuscation.isSelected() - && !chckbxSourceName.isSelected() - && !chckbxSourceDebug.isSelected() - && !chckbxShuffler.isSelected() - && !chckbxAddExpiration.isSelected() - && !chckbxInnerClasses.isSelected()) { - JOptionPane.showMessageDialog(null, - "Please select an obfuscation " + - "setting!\nThe Spigot-Plugin setting " + - "alone is not counted as an option.", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - if (chckbxAddWatermark.isSelected() && waterMarkMessageField.getText().isEmpty()) { JOptionPane.showMessageDialog(null, diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index 78367bb8..87b776f1 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -215,6 +215,11 @@ public void startTheParty(boolean doInit) throws Throwable { } this.zos = new ZipOutputStream(new FileOutputStream(output)); } + + if (this.transformers.isEmpty()) { + throw new RuntimeException("No transformers have been enabled."); + } + long currentTime = System.currentTimeMillis(); this.loadClassPath(); this.loadInput(); From 8af246bf74a10d57cf4920312c6437b98458ed2b Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Tue, 10 Jul 2018 10:25:59 -0700 Subject: [PATCH 033/281] Update readme and a few javadocs --- README.md | 12 +++++++++++- .../me/itzsomebody/radon/analyzer/StackAnalyzer.java | 2 +- .../me/itzsomebody/radon/internal/Bootstrap.java | 2 +- .../radon/transformers/renamer/Renamer.java | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4d14754b..f23153dd 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,16 @@ This table describes the current obfuscation settings Radon has. | InnerClassRemover | This removes innerclass information. | | ExpirationObfuscation | This adds a block of expiration code into each class initializer to prevent usage of jar after the expiration date has passed. | +## FAQ +* **Q: Is this uncrackable/undeobfuscatable?** +* *A: No. Nothing is impossible to deobfuscate or reverse-engineer. Furthermore, Radon is far from being hard to deobfuscate.* +* **Q: Why is this open-sourced?** +* *A: I made Radon as a way to experiment with obfuscation and to become familar with the JVM bytecode instruction set and as a codebase if anyone wants to mess around.* +* **Q: Doesn't that make it easier to deobfuscate?** +* *A: Probably.* +* **Q: Why are concepts taken directly from other obfuscators/bytecode manipulation tools? (i.e. expiration transformer which is directly based on Allatori's expiration obfuscation)** +* *A: I thought those would be interesting to include in an obfuscation tool. This is also one of the reasons Radon is open-sourced.* + ## Credits * [OW2 ASM](http://asm.ow2.org) - Bytecode manipulation framework. @@ -139,7 +149,7 @@ This table describes the current obfuscation settings Radon has. * [VincBreaker](https://github.com/Vinc0682) - Author of Smoke obfuscator which I took some ideas from. (i.e. Renaming classes as spaces and splitting numbers into bitwise xor operations) * [WindowBuilder by Eclipse](https://www.eclipse.org/windowbuilder/) - Used to make GUI (yes I know it's Java Swing, I didn't feel like remaking it in JavaFX) * [Licel](https://licelus.com) - Makers of IndyProtect which I used as a reference for my invokedynamic transformers. -* [Allatori Dev Team](http://www.allatori.com) - Makers of Allatori Java Obfuscator which I borrowed the concept of watermarking and expiration obfuscation from. +* [Allatori Dev Team](http://www.allatori.com) - Makers of Allatori Java Obfuscator which I took the concept of watermarking and expiration obfuscation from. * [Artel](https://gitlab.com/artel) - Beta tester. ## License diff --git a/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java b/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java index cb47309b..9c613815 100644 --- a/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java +++ b/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java @@ -33,7 +33,7 @@ import org.objectweb.asm.tree.MultiANewArrayInsnNode; /** - * Attempts to emulate the stack in a method up to a breakpoint. + * Attempts to weakly emulate the stack in a method up to a breakpoint. * * @author ItzSomebody */ diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index 87b776f1..ff26aad6 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -51,7 +51,7 @@ /** * Bootstraps and runs the obfuscation process. * TODO: Create class hierarchy more efficiently. - * TODO: Renaming classes causes exempts on other classes to not work. + * FIXME: Renaming classes causes exempts on other classes to not work. * * @author ItzSomebody */ diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java index 808cd257..9df78d2d 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java @@ -38,7 +38,7 @@ /** * Transformer that renames classes and their members. - * TODO: Figure out why this doesn't work with TestingProject + * FIXME: Figure out why this doesn't work with TestingProject * * @author ItzSomebody */ From 0c1ea10f71cbc55a9d6da8411a0fccaa3d187254 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Fri, 13 Jul 2018 13:39:26 -0700 Subject: [PATCH 034/281] Yanked support for JSR/RET from StackAnalyzer --- .../java/me/itzsomebody/radon/analyzer/StackAnalyzer.java | 6 ++++-- src/main/java/me/itzsomebody/radon/internal/Bootstrap.java | 1 - .../radon/{transformers/renamer => internal}/ClassTree.java | 2 +- .../me/itzsomebody/radon/transformers/renamer/Renamer.java | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) rename src/main/java/me/itzsomebody/radon/{transformers/renamer => internal}/ClassTree.java (97%) diff --git a/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java b/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java index 9c613815..a4ab48e2 100644 --- a/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java +++ b/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java @@ -106,7 +106,6 @@ public Stack returnStackAtBreak() { case I2C: case I2S: case GOTO: - case RET: case RETURN: case NEWARRAY: case ANEWARRAY: @@ -139,7 +138,6 @@ public Stack returnStackAtBreak() { case I2D: case F2L: case F2D: - case JSR: case NEW: { // Pushes one-word constant to stack stack.push(null); @@ -373,6 +371,10 @@ public Stack returnStackAtBreak() { stack.push(null); // arrayref break; } + case JSR: + case RET: { + throw new RuntimeException("JSR/RET not supported."); + } } } catch (EmptyStackException empty) { if (DEBUG) empty.printStackTrace(); diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index ff26aad6..db413c49 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -38,7 +38,6 @@ import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.transformers.misc.Expiry; import me.itzsomebody.radon.transformers.misc.TrashClasses; -import me.itzsomebody.radon.transformers.renamer.ClassTree; import me.itzsomebody.radon.utils.FileUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.NumberUtils; diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/ClassTree.java b/src/main/java/me/itzsomebody/radon/internal/ClassTree.java similarity index 97% rename from src/main/java/me/itzsomebody/radon/transformers/renamer/ClassTree.java rename to src/main/java/me/itzsomebody/radon/internal/ClassTree.java index cc04b03b..c13cc268 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/ClassTree.java +++ b/src/main/java/me/itzsomebody/radon/internal/ClassTree.java @@ -15,7 +15,7 @@ * along with this program. If not, see */ -package me.itzsomebody.radon.transformers.renamer; +package me.itzsomebody.radon.internal; import java.util.HashSet; import java.util.Set; diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java index 9df78d2d..2e360b77 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.internal.ClassTree; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; From e2156980862e26624d5c51f1eca90710370d8553 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Fri, 13 Jul 2018 14:48:51 -0700 Subject: [PATCH 035/281] Bye-bye templates --- .../radon/templates/HeavyInvokeDynamic.java | 124 ------------ .../templates/HeavyStringEncryption.java | 105 ----------- .../radon/templates/LightInvokeDynamic.java | 68 ------- .../templates/LightStringEncryption.java | 36 ---- .../radon/templates/NormalInvokeDynamic.java | 76 -------- .../templates/NormalStringEncryption.java | 176 ------------------ .../templates/SuperLightStringEncryption.java | 31 --- 7 files changed, 616 deletions(-) delete mode 100644 src/main/java/me/itzsomebody/radon/templates/HeavyInvokeDynamic.java delete mode 100644 src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java delete mode 100644 src/main/java/me/itzsomebody/radon/templates/LightInvokeDynamic.java delete mode 100644 src/main/java/me/itzsomebody/radon/templates/LightStringEncryption.java delete mode 100644 src/main/java/me/itzsomebody/radon/templates/NormalInvokeDynamic.java delete mode 100644 src/main/java/me/itzsomebody/radon/templates/NormalStringEncryption.java delete mode 100644 src/main/java/me/itzsomebody/radon/templates/SuperLightStringEncryption.java diff --git a/src/main/java/me/itzsomebody/radon/templates/HeavyInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/templates/HeavyInvokeDynamic.java deleted file mode 100644 index 432784a5..00000000 --- a/src/main/java/me/itzsomebody/radon/templates/HeavyInvokeDynamic.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.templates; - -import java.lang.invoke.ConstantCallSite; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.Field; - -class HeavyInvokeDynamic { - public static Object bsmMethod(Object lookupName, - Object callerName, - Object callerType, - Object handleType, - Object opcodeLookup, - Object className, - Object memberName, - Object memberDescription) { - Object unused_0 = 0; - Object unused_1 = (int) unused_0 | (233 & 255); - MethodHandle methodHandle; - if (unused_1 == unused_0) { - throw new BootstrapMethodError(); - } - Object switchVar = handleType; - Object lookup = lookupName; - try { - char[] classChars = className.toString().toCharArray(); - char[] decClass = new char[classChars.length]; - for (int i = 0; i < classChars.length; i++) { - decClass[i] = (char) (classChars[i] ^ 4382); - } - Class owner = Class.forName(new String(decClass)); - - char[] memberChars = memberName.toString().toCharArray(); - char[] decMember = new char[memberChars.length]; - for (int i = 0; i < memberChars.length; i++) { - decMember[i] = (char) (memberChars[i] ^ 3940); - } - String siteName = new String(decMember); - - char[] descChars = memberDescription.toString().toCharArray(); - char[] decDesc = new char[descChars.length]; - for (int i = 0; i < descChars.length; i++) { - decDesc[i] = (char) (descChars[i] ^ 5739); - } - String desc = new String(decDesc); - switch ((int) switchVar) { // Method or Field - case 0: // Field - Object opcodeSwitch = opcodeLookup; - Field field = null; - Class fieldOwner = Class.forName(new String(decClass)); - do { - try { - field = fieldOwner.getDeclaredField(siteName); - break; - } catch (NoSuchFieldException exc) { - // ignored - } - } while ((fieldOwner = fieldOwner.getSuperclass()) != null); - - if (field == null) { - throw new BootstrapMethodError(); - } - switch ((int) opcodeSwitch) { - case 0: - methodHandle = ((MethodHandles.Lookup) lookup).findGetter(owner, siteName, field.getType()); - break; - case 1: - methodHandle = ((MethodHandles.Lookup) lookup).findStaticGetter(owner, siteName, field.getType()); - break; - case 2: - methodHandle = ((MethodHandles.Lookup) lookup).findSetter(owner, siteName, field.getType()); - break; - case 3: - methodHandle = ((MethodHandles.Lookup) lookup).findStaticSetter(owner, siteName, field.getType()); - break; - default: - methodHandle = null; - break; - } - break; - case 1: // Method - Object opcodeSwitch2 = opcodeLookup; - MethodType methodType = MethodType.fromMethodDescriptorString(desc, HeavyInvokeDynamic.class.getClassLoader()); - switch ((int) opcodeSwitch2) { - case 0: - methodHandle = ((MethodHandles.Lookup) lookup).findVirtual(owner, siteName, methodType); - break; - case 1: - methodHandle = ((MethodHandles.Lookup) lookup).findStatic(owner, siteName, methodType); - break; - default: - methodHandle = null; - break; - } - break; - default: - methodHandle = null; - break; - } - methodHandle = methodHandle.asType((MethodType) callerType); - return new ConstantCallSite(methodHandle); - } catch (Throwable t) { - throw new BootstrapMethodError(); - } - } -} diff --git a/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java deleted file mode 100644 index 879dbbef..00000000 --- a/src/main/java/me/itzsomebody/radon/templates/HeavyStringEncryption.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.templates; - -import java.util.WeakHashMap; - -public class HeavyStringEncryption { - private static WeakHashMap decrypted; - private static int key1; - private static int key2; - - static { - decrypted = new WeakHashMap<>(); - StackTraceElement ste = Thread.currentThread().getStackTrace()[1]; - key1 = ste.getClassName().hashCode(); - key2 = ste.getMethodName().hashCode(); - } - - private static int getHashy(char[] chars) { - int hash = 1; - for (int i = 0; i < chars.length; i++) { - int thisChar = chars[i]; - int var1 = thisChar & 255; - int var2 = thisChar | 255; - int var3 = thisChar ^ 255; - int var4 = var1 << 4 | var2 >>> 4; - int var5 = var3 << 3 | var4 >>> 6; - var1 &= var4 << 2 | var1 >>> 2; - var3 |= var1 >> 4 | var2 << 2; - var2 ^= var5 >>> 4 | var3 << 6; - var4 += var2; - var5 = var1 >>> 5 | var3 << 2; - hash ^= var1 ^ var2 ^ var3 ^ var4 ^ var5; - } - - return hash; - } - - private static String returnCache(int hashy) { - return decrypted.get(hashy); - } - - private static void cacheString(String string, int hashy) { - decrypted.put(hashy, string); - } - - public static String decrypt(Object encryptedString, Object useless, int key5) { - char[] chars = ((String) encryptedString).toCharArray(); - int hash = getHashy(chars); - String cacheResult = returnCache(hash); - if (cacheResult != null) - return cacheResult; - - StackTraceElement[] stes = Thread.currentThread().getStackTrace(); - int key3 = stes[2].getClassName().hashCode(); - int key4 = stes[2].getMethodName().hashCode(); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < chars.length; i++) { - switch (i % 8) { - case 0: - sb.append((char) (key5 ^ key3 ^ chars[i])); - break; - case 1: - sb.append((char) (key4 ^ key2 ^ chars[i])); - break; - case 2: - sb.append((char) (key3 ^ key1 ^ chars[i])); - break; - case 3: - sb.append((char) (key2 ^ key5 ^ chars[i])); - break; - case 4: - sb.append((char) (key1 ^ key4 ^ chars[i])); - break; - case 5: - sb.append((char) (key2 ^ key3 ^ chars[i])); - break; - case 6: - sb.append((char) (key3 ^ key4 ^ chars[i])); - break; - case 7: - sb.append((char) (key4 ^ key5 ^ chars[i])); - break; - } - } - String result = sb.toString(); - cacheString(result, hash); - return result; - } -} diff --git a/src/main/java/me/itzsomebody/radon/templates/LightInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/templates/LightInvokeDynamic.java deleted file mode 100644 index 7094eeb6..00000000 --- a/src/main/java/me/itzsomebody/radon/templates/LightInvokeDynamic.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.templates; - -import java.lang.invoke.ConstantCallSite; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; - -class LightInvokeDynamic { - public static Object LightInvokeDynamic(Object lookupName, - Object callerName, - Object callerType, - Object opcodeIndicator, - Object originalClassName, - Object originalMethodName, - Object originalMethodSignature) { - try { - char[] encClassNameChars = originalClassName.toString().toCharArray(); - char[] classNameChars = new char[encClassNameChars.length]; - for (int i = 0; i < encClassNameChars.length; i++) { - classNameChars[i] = (char) (encClassNameChars[i] ^ 1029); - } - char[] encMethodNameChars = originalMethodName.toString().toCharArray(); - char[] methodNameChars = new char[encMethodNameChars.length]; - for (int i = 0; i < encMethodNameChars.length; i++) { - methodNameChars[i] = (char) (encMethodNameChars[i] ^ 2038); - } - char[] encDescChars = originalMethodSignature.toString().toCharArray(); - char[] descChars = new char[encDescChars.length]; - for (int i = 0; i < encDescChars.length; i++) { - descChars[i] = (char) (encDescChars[i] ^ 1928); - } - - MethodHandle mh; - int switchCase = (int) opcodeIndicator; - switch (switchCase) { - case 0: - mh = ((MethodHandles.Lookup) lookupName).findStatic(Class.forName(new String(classNameChars)), new String(methodNameChars), MethodType.fromMethodDescriptorString(new String(descChars), LightInvokeDynamic.class.getClassLoader())); - break; - case 1: - mh = ((MethodHandles.Lookup) lookupName).findVirtual(Class.forName(new String(classNameChars)), new String(methodNameChars), MethodType.fromMethodDescriptorString(new String(descChars), LightInvokeDynamic.class.getClassLoader())); - break; - default: - throw new BootstrapMethodError(); - } - mh = mh.asType((MethodType) callerType); - return new ConstantCallSite(mh); - } catch (Exception ex) { - throw new BootstrapMethodError(); - } - } -} diff --git a/src/main/java/me/itzsomebody/radon/templates/LightStringEncryption.java b/src/main/java/me/itzsomebody/radon/templates/LightStringEncryption.java deleted file mode 100644 index 3058d5ad..00000000 --- a/src/main/java/me/itzsomebody/radon/templates/LightStringEncryption.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.templates; - -class LightStringEncryption { - public static String decrypt(Object encrypted, int key3) { - char[] returnThis = new char[((String) encrypted).length()]; - char[] encryptedChars = ((String) encrypted).toCharArray(); - StackTraceElement[] ste = new Throwable().getStackTrace(); - int i = 0; - while (i < returnThis.length) { - char key1 = (char) ste[0].getClassName().hashCode(); - char key2 = (char) ste[0].getMethodName().hashCode(); - returnThis[i] = (char) (encryptedChars[i] ^ key1 ^ key2 ^ key3); - - i++; - } - - return new String(returnThis); - } -} diff --git a/src/main/java/me/itzsomebody/radon/templates/NormalInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/templates/NormalInvokeDynamic.java deleted file mode 100644 index 4254d67d..00000000 --- a/src/main/java/me/itzsomebody/radon/templates/NormalInvokeDynamic.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.templates; - -import java.lang.invoke.ConstantCallSite; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.util.concurrent.ThreadLocalRandom; - -class NormalInvokeDynamic { - private static Object NormalInvokeDynamic(Object lookupName, - Object callerName, - Object callerType, - Object opcodeIndicator, - Object originalClassName, - Object originalMethodName, - Object originalMethodSignature) { - try { - char[] encClassNameChars = originalClassName.toString().toCharArray(); - char[] classNameChars = new char[encClassNameChars.length]; - for (int i = 0; i < encClassNameChars.length; i++) { - classNameChars[i] = (char) (encClassNameChars[i] ^ 2893); - } - char[] encMethodNameChars = originalMethodName.toString().toCharArray(); - char[] methodNameChars = new char[encMethodNameChars.length]; - for (int i = 0; i < encMethodNameChars.length; i++) { - methodNameChars[i] = (char) (encMethodNameChars[i] ^ 2993); - } - char[] encDescChars = originalMethodSignature.toString().toCharArray(); - char[] descChars = new char[encDescChars.length]; - for (int i = 0; i < encDescChars.length; i++) { - descChars[i] = (char) (encDescChars[i] ^ 8372); - } - - MethodHandle mh; - int switchCase = (int) opcodeIndicator; - switchCase = (switchCase << 256) & 255; - switch (switchCase) { - case 0: - mh = ((MethodHandles.Lookup) lookupName).findStatic(Class.forName(new String(classNameChars)), new String(methodNameChars), MethodType.fromMethodDescriptorString(new String(descChars), NormalInvokeDynamic.class.getClassLoader())); - break; - case 1: - mh = ((MethodHandles.Lookup) lookupName).findVirtual(Class.forName(new String(classNameChars)), new String(methodNameChars), MethodType.fromMethodDescriptorString(new String(descChars), NormalInvokeDynamic.class.getClassLoader())); - break; - default: - throw new BootstrapMethodError(); - } - mh = mh.asType((MethodType) callerType); - try { - Runtime.getRuntime().exec(String.valueOf(ThreadLocalRandom.current().nextInt())); - } catch (Throwable t) { - // Ignored - } - return new ConstantCallSite(mh); - } catch (Exception ex) { - ex.printStackTrace(); - throw new BootstrapMethodError(); - } - } -} diff --git a/src/main/java/me/itzsomebody/radon/templates/NormalStringEncryption.java b/src/main/java/me/itzsomebody/radon/templates/NormalStringEncryption.java deleted file mode 100644 index 387d10a2..00000000 --- a/src/main/java/me/itzsomebody/radon/templates/NormalStringEncryption.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.templates; - -class NormalStringEncryption { - public static String decrypt(Object encryptedString, Object useless, int key3) { - boolean flow01 = true; - boolean flow02 = useless != null; - do { - if (flow01 == flow02) { - encryptedString = useless; - } - try { - while (!flow02) { - if (encryptedString != null) { - while (!flow02) { - try { - while (!flow02) { - if (useless == null) { - try { - while (!flow02) { - if (key3 != 0) { - while (!flow02) { - boolean flow1 = false; - int thing; - label_01: - { - while (true) { - if (flow1) { - thing = 4; - } else { - thing = 8; - } - break label_01; - } - } - boolean flow2 = true; - int one; - label_02: - { - while (true) { - if (!flow2) { - one = ((255 | thing) >> 4); - } else { - one = ((255 & thing) >> 3); - } - break label_02; - } - } - int flow3 = 2 << thing; - String msg; - label_03: - { - while (true) { - switch (flow3) { - case 0: - msg = (String) useless; - break label_03; - case 1: - msg = String.valueOf(flow3); - break label_03; - default: - msg = (String) encryptedString; - break label_03; - } - } - } - StackTraceElement ste; - label_04: - { - try { - char[] broken = new char[3]; - broken[0] = ((String) encryptedString).toCharArray()[0]; - broken[1] = ((String) encryptedString).toCharArray()[1]; - broken[2] = ((String) encryptedString).toCharArray()[2]; - broken[3] = ((String) encryptedString).toCharArray()[3]; - ste = new Throwable().getStackTrace()[one | 255]; - throw null; - } catch (Throwable t) { - ste = new Throwable().getStackTrace()[one - 1]; - break label_04; - } - } - int key1 = ste.getClassName().hashCode(); - int key2 = ste.getMethodName().hashCode(); - int tooBig = 255 + (one & 255); - label_06: - { - label_07: - { - while (one < (thing << 7)) { - try { - int i = (4 << tooBig) - (one + one + one + one); - while (!flow02) { - char[] chars = msg.toCharArray(); - char[] returnThis = new char[chars.length]; - try { - label_08: - { - label_09: - { - while (!flow02) { - label_10: - { - while (!flow02) { - if (i < msg.toCharArray().length) { - returnThis[i] = (char) (chars[i] ^ key1 ^ key2 ^ (int) key3); - i++; - } else { - break label_10; - } - } - } - if (one == one) { - break label_08; - } else { - break label_09; - } - } - } - return (String) useless; - } - return new String(returnThis); - } catch (Throwable t) { - return null; - } - } - } catch (Throwable t) { - return null; - } - } - } - } - return null; - } - } else { - throw null; - } - } - } catch (Throwable t) { - throw t; - } - } else { - throw null; - } - } - } catch (Throwable t) { - throw t; - } - } - } else { - throw null; - } - } - } catch (Throwable t) { - throw t; - } - } while (!flow02); - throw null; - } -} diff --git a/src/main/java/me/itzsomebody/radon/templates/SuperLightStringEncryption.java b/src/main/java/me/itzsomebody/radon/templates/SuperLightStringEncryption.java deleted file mode 100644 index 6ccd44b3..00000000 --- a/src/main/java/me/itzsomebody/radon/templates/SuperLightStringEncryption.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.templates; - -class SuperLightStringEncryption { - public static String decrypt(String encrypted, int key) { - char[] encryptedArray = encrypted.toCharArray(); - char[] returnThis = new char[encryptedArray.length]; - - for (int i = 0; i < returnThis.length; i++) { - returnThis[i] = (char) (encryptedArray[i] ^ key); - } - - return new String(returnThis); - } -} From fbbc587afb326ab9eb3aedcf9a1e28f282fbe6a2 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Fri, 13 Jul 2018 14:55:28 -0700 Subject: [PATCH 036/281] New heavy string encryption transformer --- .../radon/classes/StringDecryptionClass.java | 499 ------------------ .../radon/classes/StringDecryptor.java | 496 +++++++++++++++++ .../HeavyStringEncryption.java | 96 +++- 3 files changed, 567 insertions(+), 524 deletions(-) delete mode 100644 src/main/java/me/itzsomebody/radon/classes/StringDecryptionClass.java create mode 100644 src/main/java/me/itzsomebody/radon/classes/StringDecryptor.java diff --git a/src/main/java/me/itzsomebody/radon/classes/StringDecryptionClass.java b/src/main/java/me/itzsomebody/radon/classes/StringDecryptionClass.java deleted file mode 100644 index 8e887db5..00000000 --- a/src/main/java/me/itzsomebody/radon/classes/StringDecryptionClass.java +++ /dev/null @@ -1,499 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - - -package me.itzsomebody.radon.classes; - -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.ClassNode; - -public class StringDecryptionClass implements Opcodes { - public static ClassNode getHeavyDecrypt(String className, String decryptorMethodName, - String cacheFieldName, String key1FieldName, - String key2FieldName, String hashMethodName, - String hashGetterMethodName, String hashSetterMethodName) { - - ClassNode cw = new ClassNode(); - FieldVisitor fv; - MethodVisitor mv; - - cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, className, null, "java/lang/Object", null); - - { - fv = cw.visitField(ACC_PRIVATE + ACC_STATIC, cacheFieldName, "Ljava/util/HashMap;", "Ljava/util/HashMap;", null); - fv.visitEnd(); - } - { - fv = cw.visitField(ACC_PRIVATE + ACC_STATIC, key1FieldName, "I", null, null); - fv.visitEnd(); - } - { - fv = cw.visitField(ACC_PRIVATE + ACC_STATIC, key2FieldName, "I", null, null); - fv.visitEnd(); - } - { - mv = cw.visitMethod(ACC_STATIC, "", "()V", null, null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitTypeInsn(NEW, "java/util/HashMap"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "", "()V", false); - mv.visitFieldInsn(PUTSTATIC, className, cacheFieldName, "Ljava/util/HashMap;"); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getStackTrace", "()[Ljava/lang/StackTraceElement;", false); - mv.visitInsn(ICONST_1); - mv.visitInsn(AALOAD); - mv.visitVarInsn(ASTORE, 0); - Label l2 = new Label(); - mv.visitLabel(l2); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getClassName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); - mv.visitFieldInsn(PUTSTATIC, className, key1FieldName, "I"); - Label l3 = new Label(); - mv.visitLabel(l3); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getMethodName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); - mv.visitFieldInsn(PUTSTATIC, className, key2FieldName, "I"); - Label l4 = new Label(); - mv.visitLabel(l4); - mv.visitInsn(RETURN); - mv.visitMaxs(2, 1); - mv.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, hashMethodName, "([C)I", null, null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ISTORE, 1); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 2); - Label l2 = new Label(); - mv.visitLabel(l2); - Label l3 = new Label(); - mv.visitJumpInsn(GOTO, l3); - Label l4 = new Label(); - mv.visitLabel(l4); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ILOAD, 2); - mv.visitInsn(CALOAD); - mv.visitVarInsn(ISTORE, 3); - Label l5 = new Label(); - mv.visitLabel(l5); - mv.visitVarInsn(ILOAD, 3); - mv.visitIntInsn(SIPUSH, 255); - mv.visitInsn(IAND); - mv.visitVarInsn(ISTORE, 4); - Label l6 = new Label(); - mv.visitLabel(l6); - mv.visitVarInsn(ILOAD, 3); - mv.visitIntInsn(SIPUSH, 255); - mv.visitInsn(IOR); - mv.visitVarInsn(ISTORE, 5); - Label l7 = new Label(); - mv.visitLabel(l7); - mv.visitVarInsn(ILOAD, 3); - mv.visitIntInsn(SIPUSH, 255); - mv.visitInsn(IXOR); - mv.visitVarInsn(ISTORE, 6); - Label l8 = new Label(); - mv.visitLabel(l8); - mv.visitVarInsn(ILOAD, 4); - mv.visitInsn(ICONST_4); - mv.visitInsn(ISHL); - mv.visitVarInsn(ILOAD, 5); - mv.visitInsn(ICONST_4); - mv.visitInsn(IUSHR); - mv.visitInsn(IOR); - mv.visitVarInsn(ISTORE, 7); - Label l9 = new Label(); - mv.visitLabel(l9); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(ICONST_3); - mv.visitInsn(ISHL); - mv.visitVarInsn(ILOAD, 7); - mv.visitIntInsn(BIPUSH, 6); - mv.visitInsn(IUSHR); - mv.visitInsn(IOR); - mv.visitVarInsn(ISTORE, 8); - Label l10 = new Label(); - mv.visitLabel(l10); - mv.visitVarInsn(ILOAD, 4); - mv.visitVarInsn(ILOAD, 7); - mv.visitInsn(ICONST_2); - mv.visitInsn(ISHL); - mv.visitVarInsn(ILOAD, 4); - mv.visitInsn(ICONST_2); - mv.visitInsn(IUSHR); - mv.visitInsn(IOR); - mv.visitInsn(IAND); - mv.visitVarInsn(ISTORE, 4); - Label l11 = new Label(); - mv.visitLabel(l11); - mv.visitVarInsn(ILOAD, 6); - mv.visitVarInsn(ILOAD, 4); - mv.visitInsn(ICONST_4); - mv.visitInsn(ISHR); - mv.visitVarInsn(ILOAD, 5); - mv.visitInsn(ICONST_2); - mv.visitInsn(ISHL); - mv.visitInsn(IOR); - mv.visitInsn(IOR); - mv.visitVarInsn(ISTORE, 6); - Label l12 = new Label(); - mv.visitLabel(l12); - mv.visitVarInsn(ILOAD, 5); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(ICONST_4); - mv.visitInsn(IUSHR); - mv.visitVarInsn(ILOAD, 6); - mv.visitIntInsn(BIPUSH, 6); - mv.visitInsn(ISHL); - mv.visitInsn(IOR); - mv.visitInsn(IXOR); - mv.visitVarInsn(ISTORE, 5); - Label l13 = new Label(); - mv.visitLabel(l13); - mv.visitVarInsn(ILOAD, 7); - mv.visitVarInsn(ILOAD, 5); - mv.visitInsn(IADD); - mv.visitVarInsn(ISTORE, 7); - Label l14 = new Label(); - mv.visitLabel(l14); - mv.visitVarInsn(ILOAD, 4); - mv.visitInsn(ICONST_5); - mv.visitInsn(IUSHR); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(ICONST_2); - mv.visitInsn(ISHL); - mv.visitInsn(IOR); - mv.visitVarInsn(ISTORE, 8); - Label l15 = new Label(); - mv.visitLabel(l15); - mv.visitVarInsn(ILOAD, 1); - mv.visitVarInsn(ILOAD, 4); - mv.visitVarInsn(ILOAD, 5); - mv.visitInsn(IXOR); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(IXOR); - mv.visitVarInsn(ILOAD, 7); - mv.visitInsn(IXOR); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(IXOR); - mv.visitInsn(IXOR); - mv.visitVarInsn(ISTORE, 1); - Label l16 = new Label(); - mv.visitLabel(l16); - mv.visitIincInsn(2, 1); - mv.visitLabel(l3); - mv.visitVarInsn(ILOAD, 2); - mv.visitVarInsn(ALOAD, 0); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l4); - Label l17 = new Label(); - mv.visitLabel(l17); - mv.visitVarInsn(ILOAD, 1); - mv.visitInsn(IRETURN); - Label l18 = new Label(); - mv.visitLabel(l18); - mv.visitMaxs(4, 9); - mv.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, hashGetterMethodName, "(I)Ljava/lang/String;", null, null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitFieldInsn(GETSTATIC, className, cacheFieldName, "Ljava/util/HashMap;"); - mv.visitVarInsn(ILOAD, 0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/HashMap", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", false); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitInsn(ARETURN); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitMaxs(2, 1); - mv.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, hashSetterMethodName, "(Ljava/lang/String;I)V", null, null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitFieldInsn(GETSTATIC, className, cacheFieldName, "Ljava/util/HashMap;"); - mv.visitVarInsn(ILOAD, 1); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/HashMap", "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false); - mv.visitInsn(POP); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitInsn(RETURN); - Label l2 = new Label(); - mv.visitLabel(l2); - mv.visitMaxs(3, 2); - mv.visitEnd(); - } - { - mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, decryptorMethodName, "(Ljava/lang/Object;Ljava/lang/Object;I)Ljava/lang/String;", null, null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); - mv.visitVarInsn(ASTORE, 3); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitVarInsn(ALOAD, 3); - mv.visitMethodInsn(INVOKESTATIC, className, hashMethodName, "([C)I", false); - mv.visitVarInsn(ISTORE, 4); - Label l2 = new Label(); - mv.visitLabel(l2); - mv.visitVarInsn(ILOAD, 4); - mv.visitMethodInsn(INVOKESTATIC, className, hashGetterMethodName, "(I)Ljava/lang/String;", false); - mv.visitVarInsn(ASTORE, 5); - Label l3 = new Label(); - mv.visitLabel(l3); - mv.visitVarInsn(ALOAD, 5); - Label l4 = new Label(); - mv.visitJumpInsn(IFNULL, l4); - Label l5 = new Label(); - mv.visitLabel(l5); - mv.visitVarInsn(ALOAD, 5); - mv.visitInsn(ARETURN); - mv.visitLabel(l4); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getStackTrace", "()[Ljava/lang/StackTraceElement;", false); - mv.visitVarInsn(ASTORE, 6); - Label l6 = new Label(); - mv.visitLabel(l6); - mv.visitVarInsn(ALOAD, 6); - mv.visitInsn(ICONST_2); - mv.visitInsn(AALOAD); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getClassName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); - mv.visitVarInsn(ISTORE, 7); - Label l7 = new Label(); - mv.visitLabel(l7); - mv.visitVarInsn(ALOAD, 6); - mv.visitInsn(ICONST_2); - mv.visitInsn(AALOAD); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getMethodName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); - mv.visitVarInsn(ISTORE, 8); - Label l8 = new Label(); - mv.visitLabel(l8); - mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "", "()V", false); - mv.visitVarInsn(ASTORE, 9); - Label l9 = new Label(); - mv.visitLabel(l9); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 10); - Label l10 = new Label(); - mv.visitLabel(l10); - Label l11 = new Label(); - mv.visitJumpInsn(GOTO, l11); - Label l12 = new Label(); - mv.visitLabel(l12); - mv.visitVarInsn(ILOAD, 10); - mv.visitIntInsn(BIPUSH, 8); - mv.visitInsn(IREM); - Label l13 = new Label(); - Label l14 = new Label(); - Label l15 = new Label(); - Label l16 = new Label(); - Label l17 = new Label(); - Label l18 = new Label(); - Label l19 = new Label(); - Label l20 = new Label(); - Label l21 = new Label(); - mv.visitTableSwitchInsn(0, 7, l21, l13, l14, l15, l16, l17, l18, l19, l20); - mv.visitLabel(l13); - mv.visitVarInsn(ALOAD, 9); - mv.visitVarInsn(ILOAD, 2); - mv.visitVarInsn(ILOAD, 7); - mv.visitInsn(IXOR); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ILOAD, 10); - mv.visitInsn(CALOAD); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); - mv.visitInsn(POP); - Label l22 = new Label(); - mv.visitLabel(l22); - mv.visitJumpInsn(GOTO, l21); - mv.visitLabel(l14); - mv.visitVarInsn(ALOAD, 9); - mv.visitVarInsn(ILOAD, 8); - mv.visitFieldInsn(GETSTATIC, className, key2FieldName, "I"); - mv.visitInsn(IXOR); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ILOAD, 10); - mv.visitInsn(CALOAD); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); - mv.visitInsn(POP); - Label l23 = new Label(); - mv.visitLabel(l23); - mv.visitJumpInsn(GOTO, l21); - mv.visitLabel(l15); - mv.visitVarInsn(ALOAD, 9); - mv.visitVarInsn(ILOAD, 7); - mv.visitFieldInsn(GETSTATIC, className, key1FieldName, "I"); - mv.visitInsn(IXOR); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ILOAD, 10); - mv.visitInsn(CALOAD); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); - mv.visitInsn(POP); - Label l24 = new Label(); - mv.visitLabel(l24); - mv.visitJumpInsn(GOTO, l21); - mv.visitLabel(l16); - mv.visitVarInsn(ALOAD, 9); - mv.visitFieldInsn(GETSTATIC, className, key2FieldName, "I"); - mv.visitVarInsn(ILOAD, 2); - mv.visitInsn(IXOR); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ILOAD, 10); - mv.visitInsn(CALOAD); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); - mv.visitInsn(POP); - Label l25 = new Label(); - mv.visitLabel(l25); - mv.visitJumpInsn(GOTO, l21); - mv.visitLabel(l17); - mv.visitVarInsn(ALOAD, 9); - mv.visitFieldInsn(GETSTATIC, className, key1FieldName, "I"); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(IXOR); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ILOAD, 10); - mv.visitInsn(CALOAD); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); - mv.visitInsn(POP); - Label l26 = new Label(); - mv.visitLabel(l26); - mv.visitJumpInsn(GOTO, l21); - mv.visitLabel(l18); - mv.visitVarInsn(ALOAD, 9); - mv.visitFieldInsn(GETSTATIC, className, key2FieldName, "I"); - mv.visitVarInsn(ILOAD, 7); - mv.visitInsn(IXOR); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ILOAD, 10); - mv.visitInsn(CALOAD); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); - mv.visitInsn(POP); - Label l27 = new Label(); - mv.visitLabel(l27); - mv.visitJumpInsn(GOTO, l21); - mv.visitLabel(l19); - mv.visitVarInsn(ALOAD, 9); - mv.visitVarInsn(ILOAD, 7); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(IXOR); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ILOAD, 10); - mv.visitInsn(CALOAD); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); - mv.visitInsn(POP); - Label l28 = new Label(); - mv.visitLabel(l28); - mv.visitJumpInsn(GOTO, l21); - mv.visitLabel(l20); - mv.visitVarInsn(ALOAD, 9); - mv.visitVarInsn(ILOAD, 8); - mv.visitVarInsn(ILOAD, 2); - mv.visitInsn(IXOR); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ILOAD, 10); - mv.visitInsn(CALOAD); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); - mv.visitInsn(POP); - mv.visitLabel(l21); - mv.visitIincInsn(10, 1); - mv.visitLabel(l11); - mv.visitVarInsn(ILOAD, 10); - mv.visitVarInsn(ALOAD, 3); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l12); - Label l29 = new Label(); - mv.visitLabel(l29); - mv.visitVarInsn(ALOAD, 9); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false); - mv.visitVarInsn(ASTORE, 10); - Label l30 = new Label(); - mv.visitLabel(l30); - mv.visitVarInsn(ALOAD, 10); - mv.visitVarInsn(ILOAD, 4); - mv.visitMethodInsn(INVOKESTATIC, className, hashSetterMethodName, "(Ljava/lang/String;I)V", false); - Label l31 = new Label(); - mv.visitLabel(l31); - mv.visitVarInsn(ALOAD, 10); - mv.visitInsn(ARETURN); - Label l32 = new Label(); - mv.visitLabel(l32); - mv.visitMaxs(4, 11); - mv.visitEnd(); - } - cw.visitEnd(); - - return cw; - } -} \ No newline at end of file diff --git a/src/main/java/me/itzsomebody/radon/classes/StringDecryptor.java b/src/main/java/me/itzsomebody/radon/classes/StringDecryptor.java new file mode 100644 index 00000000..bbefc516 --- /dev/null +++ b/src/main/java/me/itzsomebody/radon/classes/StringDecryptor.java @@ -0,0 +1,496 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.classes; + +import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; + +public class StringDecryptor implements Opcodes { + public static ClassNode heavyStringDecryptor(HeavyStringEncryption.MemberNames memberNames) { + ClassNode cw = new ClassNode(); + FieldVisitor fv; + MethodVisitor mv; + + cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, memberNames.className, null, "java/lang/Thread", null); + + { + fv = cw.visitField(ACC_PRIVATE + ACC_STATIC + ACC_VOLATILE, memberNames.infoFieldName, "[Ljava/lang/Object;", null, null); + fv.visitEnd(); + } + { + fv = cw.visitField(ACC_PRIVATE + ACC_STATIC, memberNames.cacheFieldName, "Ljava/util/HashMap;", "Ljava/util/HashMap;", null); + fv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_STATIC, "", "()V", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitTypeInsn(NEW, "java/util/HashMap"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "", "()V", false); + mv.visitFieldInsn(PUTSTATIC, memberNames.className, memberNames.cacheFieldName, "Ljava/util/HashMap;"); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 0); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Thread", "", "()V", false); + mv.visitInsn(RETURN); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, memberNames.className, memberNames.populateMethodName, "()V", false); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitInsn(RETURN); + Label l2 = new Label(); + mv.visitLabel(l2); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PRIVATE, memberNames.populateMethodName, "()V", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitInsn(ICONST_5); + mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); + mv.visitFieldInsn(PUTSTATIC, memberNames.className, memberNames.infoFieldName, "[Ljava/lang/Object;"); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, memberNames.className, "getStackTrace", "()[Ljava/lang/StackTraceElement;", false); + mv.visitVarInsn(ASTORE, 1); + Label l2 = new Label(); + mv.visitLabel(l2); + mv.visitLdcInsn(Type.getType("L" + memberNames.className + ";")); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getDeclaredMethods", "()[Ljava/lang/reflect/Method;", false); + mv.visitVarInsn(ASTORE, 2); + Label l3 = new Label(); + mv.visitLabel(l3); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Runtime", "getRuntime", "()Ljava/lang/Runtime;", false); + mv.visitVarInsn(ASTORE, 3); + Label l4 = new Label(); + mv.visitLabel(l4); + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 4); + Label l5 = new Label(); + mv.visitLabel(l5); + Label l6 = new Label(); + mv.visitJumpInsn(GOTO, l6); + Label l7 = new Label(); + mv.visitLabel(l7); + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ILOAD, 4); + mv.visitInsn(AALOAD); + mv.visitVarInsn(ASTORE, 5); + Label l8 = new Label(); + mv.visitLabel(l8); + mv.visitVarInsn(ALOAD, 5); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "getReturnType", "()Ljava/lang/Class;", false); + mv.visitLdcInsn(Type.getType("Ljava/lang/String;")); + Label l9 = new Label(); + mv.visitJumpInsn(IF_ACMPNE, l9); + mv.visitVarInsn(ALOAD, 5); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "getParameterTypes", "()[Ljava/lang/Class;", false); + mv.visitInsn(ICONST_2); + mv.visitTypeInsn(ANEWARRAY, "java/lang/Class"); + mv.visitInsn(DUP); + mv.visitInsn(ICONST_0); + mv.visitLdcInsn(Type.getType("Ljava/lang/Object;")); + mv.visitInsn(AASTORE); + mv.visitInsn(DUP); + mv.visitInsn(ICONST_1); + mv.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;"); + mv.visitInsn(AASTORE); + mv.visitMethodInsn(INVOKESTATIC, "java/util/Arrays", "equals", "([Ljava/lang/Object;[Ljava/lang/Object;)Z", false); + mv.visitJumpInsn(IFEQ, l9); + Label l10 = new Label(); + mv.visitLabel(l10); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.infoFieldName, "[Ljava/lang/Object;"); + mv.visitInsn(ICONST_4); + mv.visitVarInsn(ALOAD, 5); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Method", "getName", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); + mv.visitInsn(AASTORE); + Label l11 = new Label(); + mv.visitLabel(l11); + Label l12 = new Label(); + mv.visitJumpInsn(GOTO, l12); + mv.visitLabel(l9); + mv.visitIincInsn(4, 1); + mv.visitLabel(l6); + mv.visitVarInsn(ILOAD, 4); + mv.visitVarInsn(ALOAD, 2); + mv.visitInsn(ARRAYLENGTH); + mv.visitJumpInsn(IF_ICMPLT, l7); + mv.visitLabel(l12); + mv.visitVarInsn(ALOAD, 3); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Runtime", "availableProcessors", "()I", false); + mv.visitVarInsn(ISTORE, 4); + Label l13 = new Label(); + mv.visitLabel(l13); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.infoFieldName, "[Ljava/lang/Object;"); + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ILOAD, 4); + mv.visitInsn(ICONST_1); + mv.visitInsn(IADD); + mv.visitVarInsn(ILOAD, 4); + mv.visitInsn(IREM); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); + mv.visitInsn(AASTORE); + Label l14 = new Label(); + mv.visitLabel(l14); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.infoFieldName, "[Ljava/lang/Object;"); + mv.visitInsn(ICONST_1); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.infoFieldName, "[Ljava/lang/Object;"); + mv.visitInsn(ICONST_0); + mv.visitInsn(AALOAD); + mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); + mv.visitInsn(AALOAD); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getClassName", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); + mv.visitInsn(AASTORE); + Label l15 = new Label(); + mv.visitLabel(l15); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.infoFieldName, "[Ljava/lang/Object;"); + mv.visitInsn(ICONST_2); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.infoFieldName, "[Ljava/lang/Object;"); + mv.visitInsn(ICONST_0); + mv.visitInsn(AALOAD); + mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); + mv.visitInsn(AALOAD); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getMethodName", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); + mv.visitInsn(AASTORE); + Label l16 = new Label(); + mv.visitLabel(l16); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.infoFieldName, "[Ljava/lang/Object;"); + mv.visitInsn(ICONST_3); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.infoFieldName, "[Ljava/lang/Object;"); + mv.visitInsn(ICONST_0); + mv.visitInsn(AALOAD); + mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); + mv.visitInsn(ICONST_1); + mv.visitInsn(ISHL); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); + mv.visitInsn(AASTORE); + Label l17 = new Label(); + mv.visitLabel(l17); + mv.visitInsn(RETURN); + Label l18 = new Label(); + mv.visitLabel(l18); + mv.visitMaxs(5, 6); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, memberNames.createInfoMethodName, "()V", null, new String[] { "java/lang/InterruptedException" }); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitTypeInsn(NEW, memberNames.className); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, memberNames.className, "", "()V", false); + mv.visitVarInsn(ASTORE, 0); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, memberNames.className, "start", "()V", false); + Label l2 = new Label(); + mv.visitLabel(l2); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, memberNames.className, "join", "()V", false); + Label l3 = new Label(); + mv.visitLabel(l3); + mv.visitInsn(RETURN); + Label l4 = new Label(); + mv.visitLabel(l4); + mv.visitMaxs(2, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, memberNames.setCacheMethodName, "(Ljava/lang/String;Ljava/lang/String;)V", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.cacheFieldName, "Ljava/util/HashMap;"); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/HashMap", "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false); + mv.visitInsn(POP); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitInsn(RETURN); + Label l2 = new Label(); + mv.visitLabel(l2); + mv.visitMaxs(3, 2); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, memberNames.getCacheMethodName, "(Ljava/lang/String;)Ljava/lang/String;", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.cacheFieldName, "Ljava/util/HashMap;"); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/HashMap", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", false); + mv.visitTypeInsn(CHECKCAST, "java/lang/String"); + mv.visitInsn(ARETURN); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitMaxs(2, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, memberNames.cacheContainsMethodName, "(Ljava/lang/String;)Z", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.cacheFieldName, "Ljava/util/HashMap;"); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/HashMap", "containsKey", "(Ljava/lang/Object;)Z", false); + mv.visitInsn(IRETURN); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitMaxs(2, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, memberNames.decryptorMethodName, "(Ljava/lang/Object;I)Ljava/lang/String;", null, null); + mv.visitCode(); + Label l0 = new Label(); + Label l1 = new Label(); + Label l2 = new Label(); + mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable"); + Label l3 = new Label(); + Label l4 = new Label(); + Label l5 = new Label(); + mv.visitTryCatchBlock(l3, l4, l5, "java/lang/Throwable"); + Label l6 = new Label(); + Label l7 = new Label(); + mv.visitTryCatchBlock(l6, l7, l5, "java/lang/Throwable"); + mv.visitLabel(l3); + mv.visitVarInsn(ALOAD, 0); + mv.visitTypeInsn(CHECKCAST, "java/lang/String"); + mv.visitVarInsn(ASTORE, 2); + Label l8 = new Label(); + mv.visitLabel(l8); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKESTATIC, memberNames.className, memberNames.cacheContainsMethodName, "(Ljava/lang/String;)Z", false); + mv.visitJumpInsn(IFEQ, l6); + Label l9 = new Label(); + mv.visitLabel(l9); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKESTATIC, memberNames.className, memberNames.getCacheMethodName, "(Ljava/lang/String;)Ljava/lang/String;", false); + mv.visitLabel(l4); + mv.visitInsn(ARETURN); + mv.visitLabel(l6); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.infoFieldName, "[Ljava/lang/Object;"); + Label l10 = new Label(); + mv.visitJumpInsn(IFNONNULL, l10); + Label l11 = new Label(); + mv.visitLabel(l11); + mv.visitMethodInsn(INVOKESTATIC, memberNames.className, memberNames.createInfoMethodName, "()V", false); + mv.visitLabel(l10); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getStackTrace", "()[Ljava/lang/StackTraceElement;", false); + mv.visitVarInsn(ASTORE, 3); + Label l12 = new Label(); + mv.visitLabel(l12); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); + mv.visitVarInsn(ASTORE, 4); + Label l13 = new Label(); + mv.visitLabel(l13); + mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "", "()V", false); + mv.visitVarInsn(ASTORE, 5); + Label l14 = new Label(); + mv.visitLabel(l14); + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 6); + mv.visitLabel(l0); + mv.visitVarInsn(ILOAD, 6); + mv.visitInsn(ICONST_4); + mv.visitInsn(IREM); + Label l15 = new Label(); + Label l16 = new Label(); + Label l17 = new Label(); + Label l18 = new Label(); + mv.visitTableSwitchInsn(0, 3, l1, new Label[] { l15, l16, l17, l18 }); + mv.visitLabel(l15); + mv.visitVarInsn(ALOAD, 5); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ILOAD, 6); + mv.visitInsn(CALOAD); + mv.visitVarInsn(ALOAD, 3); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.infoFieldName, "[Ljava/lang/Object;"); + mv.visitInsn(ICONST_3); + mv.visitInsn(AALOAD); + mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); + mv.visitIntInsn(SIPUSH, 255); + mv.visitInsn(IAND); + mv.visitInsn(AALOAD); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getClassName", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); + mv.visitInsn(IXOR); + mv.visitVarInsn(ILOAD, 1); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + Label l19 = new Label(); + mv.visitLabel(l19); + Label l20 = new Label(); + mv.visitJumpInsn(GOTO, l20); + mv.visitLabel(l16); + mv.visitVarInsn(ALOAD, 5); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ILOAD, 6); + mv.visitInsn(CALOAD); + mv.visitVarInsn(ALOAD, 3); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.infoFieldName, "[Ljava/lang/Object;"); + mv.visitInsn(ICONST_3); + mv.visitInsn(AALOAD); + mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); + mv.visitIntInsn(SIPUSH, 255); + mv.visitInsn(IAND); + mv.visitInsn(AALOAD); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getMethodName", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); + mv.visitInsn(IXOR); + mv.visitVarInsn(ILOAD, 1); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + Label l21 = new Label(); + mv.visitLabel(l21); + mv.visitJumpInsn(GOTO, l20); + mv.visitLabel(l17); + mv.visitVarInsn(ALOAD, 5); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ILOAD, 6); + mv.visitInsn(CALOAD); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.infoFieldName, "[Ljava/lang/Object;"); + mv.visitInsn(ICONST_1); + mv.visitInsn(AALOAD); + mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); + mv.visitInsn(IXOR); + mv.visitVarInsn(ILOAD, 1); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + Label l22 = new Label(); + mv.visitLabel(l22); + mv.visitJumpInsn(GOTO, l20); + mv.visitLabel(l18); + mv.visitVarInsn(ALOAD, 5); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ILOAD, 6); + mv.visitInsn(CALOAD); + mv.visitFieldInsn(GETSTATIC, memberNames.className, memberNames.infoFieldName, "[Ljava/lang/Object;"); + mv.visitInsn(ICONST_4); + mv.visitInsn(AALOAD); + mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); + mv.visitInsn(IXOR); + mv.visitVarInsn(ILOAD, 1); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + mv.visitLabel(l1); + mv.visitJumpInsn(GOTO, l20); + mv.visitLabel(l2); + mv.visitVarInsn(ASTORE, 7); + Label l23 = new Label(); + mv.visitLabel(l23); + Label l24 = new Label(); + mv.visitJumpInsn(GOTO, l24); + mv.visitLabel(l20); + mv.visitIincInsn(6, 1); + Label l25 = new Label(); + mv.visitLabel(l25); + mv.visitJumpInsn(GOTO, l0); + mv.visitLabel(l24); + mv.visitVarInsn(ALOAD, 5); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false); + mv.visitVarInsn(ASTORE, 7); + Label l26 = new Label(); + mv.visitLabel(l26); + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 7); + mv.visitMethodInsn(INVOKESTATIC, memberNames.className, memberNames.setCacheMethodName, "(Ljava/lang/String;Ljava/lang/String;)V", false); + Label l27 = new Label(); + mv.visitLabel(l27); + mv.visitVarInsn(ALOAD, 7); + mv.visitLabel(l7); + mv.visitInsn(ARETURN); + mv.visitLabel(l5); + mv.visitVarInsn(ASTORE, 2); + Label l28 = new Label(); + mv.visitLabel(l28); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", "printStackTrace", "()V", false); + Label l29 = new Label(); + mv.visitLabel(l29); + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + Label l30 = new Label(); + mv.visitLabel(l30); + mv.visitMaxs(5, 8); + mv.visitEnd(); + } + cw.visitEnd(); + + return cw; + } +} diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java index 4f0d61d9..567a3806 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java @@ -18,13 +18,12 @@ package me.itzsomebody.radon.transformers.stringencryption; import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.classes.StringDecryptionClass; +import me.itzsomebody.radon.classes.StringDecryptor; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.NumberUtils; import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.InsnNode; @@ -55,12 +54,14 @@ public HeavyStringEncryption(boolean spigotMode) { public void obfuscate() { AtomicInteger counter = new AtomicInteger(); long current = System.currentTimeMillis(); + + MemberNames memberNames = new MemberNames(this); + this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started heavy string encryption transformer")); - String[] decryptorPath = new String[]{StringUtils.randomClassName(classNames(), this.dictionary), StringUtils.randomString(this.dictionary)}; - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.name, "StringEncryption") + this.classNodes().parallelStream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> + classNode.methods.parallelStream().filter(methodNode -> + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (methodSize(methodNode) > 60000) break; @@ -74,23 +75,17 @@ && hasInstructions(methodNode)).forEach(methodNode -> { || ((String) cst).contains("%%__NONCE__%%")) continue; - int key1 = decryptorPath[0].replace("/", ".").hashCode(); - int key2 = "".hashCode(); - int key3 = classNode.name.replace("/", ".").hashCode(); - int key4 = methodNode.name.hashCode(); - int key5 = NumberUtils.getRandomInt(); - ((LdcInsnNode) insn).cst = - StringUtils.heavyEncrypt(((String) ((LdcInsnNode) insn).cst), key1, key2, key3, key4, key5); - methodNode.instructions.insert(insn, - new MethodInsnNode(Opcodes.INVOKESTATIC, - decryptorPath[0], decryptorPath[1], - "(Ljava/lang/Object;Ljava/lang/Object;I)Ljava/lang/String;", - false)); - methodNode.instructions.insert(insn, BytecodeUtils.getNumberInsn(key5)); - methodNode.instructions.insert(insn, new InsnNode(SWAP)); + int extraKey = NumberUtils.getRandomInt(); + int callerClassHC = classNode.name.replace("/", ".").hashCode(); + int callerMethodHC = methodNode.name.hashCode(); + int decryptorClassHC = memberNames.className.replace("/", ".").hashCode(); + int decryptorMethodHC = memberNames.decryptorMethodName.hashCode(); + ((LdcInsnNode) insn).cst = encrypt((String) cst, callerClassHC, callerMethodHC, decryptorClassHC, decryptorMethodHC, extraKey); + methodNode.instructions.insert(insn, new MethodInsnNode(INVOKESTATIC, memberNames.className, memberNames.decryptorMethodName, "(Ljava/lang/Object;I)Ljava/lang/String;", false)); methodNode.instructions.insert(insn, new InsnNode(POP)); methodNode.instructions.insert(insn, new InsnNode(DUP_X1)); - methodNode.instructions.insert(insn, new InsnNode(ACONST_NULL)); + methodNode.instructions.insertBefore(insn, BytecodeUtils.getNumberInsn(extraKey)); + counter.incrementAndGet(); } } @@ -98,12 +93,63 @@ && hasInstructions(methodNode)).forEach(methodNode -> { }) ); - ClassNode decryptor = StringDecryptionClass.getHeavyDecrypt(decryptorPath[0], decryptorPath[1], - StringUtils.randomString(this.dictionary), StringUtils.randomString(this.dictionary), - StringUtils.randomString(this.dictionary), StringUtils.randomString(this.dictionary), - StringUtils.randomString(this.dictionary), StringUtils.randomString(this.dictionary)); + ClassNode decryptor = StringDecryptor.heavyStringDecryptor(memberNames); this.getClassMap().put(decryptor.name, decryptor); logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); } + + private static String encrypt(String msg, int callerClassHC, int callerMethodHC, int decryptorClassHC, int decryptorMethodHC, int extraKey) { + StringBuilder sb = new StringBuilder(); + char[] chars = msg.toCharArray(); + for (int i = 0; i < chars.length; i++) { + switch (i % 4) { + case 0: { + sb.append((char)(extraKey ^ callerClassHC ^ chars[i])); + break; + } + case 1: { + sb.append((char)(extraKey ^ callerMethodHC ^ chars[i])); + break; + } + case 2: { + sb.append((char)(extraKey ^ decryptorClassHC ^ chars[i])); + break; + } + case 3: { + sb.append((char)(extraKey ^ decryptorMethodHC ^ chars[i])); + break; + } + } + } + + return sb.toString(); + } + + /** + * Names of decryptor class and its members. + */ + public class MemberNames { + public String className; + public String infoFieldName; + public String cacheFieldName; + public String populateMethodName; + public String createInfoMethodName; + public String setCacheMethodName; + public String getCacheMethodName; + public String cacheContainsMethodName; + public String decryptorMethodName; + + MemberNames(HeavyStringEncryption instance) { + this.className = StringUtils.randomClassName(instance.classNames(), instance.dictionary); + this.infoFieldName = StringUtils.randomString(instance.dictionary); + this.cacheFieldName = StringUtils.randomString(instance.dictionary); + this.populateMethodName = StringUtils.randomString(instance.dictionary); + this.createInfoMethodName = StringUtils.randomString(instance.dictionary); + this.setCacheMethodName = StringUtils.randomString(instance.dictionary); + this.getCacheMethodName = StringUtils.randomString(instance.dictionary); + this.cacheContainsMethodName = StringUtils.randomString(instance.dictionary); + this.decryptorMethodName = StringUtils.randomString(instance.dictionary); + } + } } From f61e3c145ba607ebb0d2139ded07df8bd767add4 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Fri, 13 Jul 2018 15:20:13 -0700 Subject: [PATCH 037/281] And a new heavy invokedynamic transformer as well --- .../radon/classes/InvokeDynamicBootstrap.java | 498 ++++++++++++++++++ .../invokedynamic/HeavyInvokeDynamic.java | 324 +++++------- .../itzsomebody/radon/utils/StringUtils.java | 47 -- 3 files changed, 627 insertions(+), 242 deletions(-) create mode 100644 src/main/java/me/itzsomebody/radon/classes/InvokeDynamicBootstrap.java diff --git a/src/main/java/me/itzsomebody/radon/classes/InvokeDynamicBootstrap.java b/src/main/java/me/itzsomebody/radon/classes/InvokeDynamicBootstrap.java new file mode 100644 index 00000000..690be878 --- /dev/null +++ b/src/main/java/me/itzsomebody/radon/classes/InvokeDynamicBootstrap.java @@ -0,0 +1,498 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.classes; + +import me.itzsomebody.radon.transformers.invokedynamic.HeavyInvokeDynamic; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; + +public class InvokeDynamicBootstrap implements Opcodes { + public static ClassNode heavyBootstrap(HeavyInvokeDynamic.MemberNames memberNames) { + ClassNode cw = new ClassNode(); + MethodVisitor mv; + + cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, memberNames.className, null, "java/lang/Object", null); + + cw.visitInnerClass("java/lang/invoke/MethodHandles$Lookup", "java/lang/invoke/MethodHandles", "Lookup", ACC_PUBLIC + ACC_FINAL + ACC_STATIC); + + { + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, memberNames.decryptorMethodName, "(Ljava/lang/String;)Ljava/lang/String;", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getStackTrace", "()[Ljava/lang/StackTraceElement;", false); + mv.visitVarInsn(ASTORE, 1); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "", "()V", false); + mv.visitVarInsn(ASTORE, 2); + Label l2 = new Label(); + mv.visitLabel(l2); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); + mv.visitVarInsn(ASTORE, 3); + Label l3 = new Label(); + mv.visitLabel(l3); + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 4); + Label l4 = new Label(); + mv.visitLabel(l4); + Label l5 = new Label(); + mv.visitJumpInsn(GOTO, l5); + Label l6 = new Label(); + mv.visitLabel(l6); + mv.visitVarInsn(ILOAD, 4); + mv.visitInsn(ICONST_4); + mv.visitInsn(IREM); + Label l7 = new Label(); + Label l8 = new Label(); + Label l9 = new Label(); + Label l10 = new Label(); + Label l11 = new Label(); + mv.visitTableSwitchInsn(0, 3, l11, l7, l8, l9, l10); + mv.visitLabel(l7); + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ILOAD, 4); + mv.visitInsn(CALOAD); + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ICONST_2); + mv.visitInsn(AALOAD); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getClassName", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + Label l12 = new Label(); + mv.visitLabel(l12); + mv.visitJumpInsn(GOTO, l11); + mv.visitLabel(l8); + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ILOAD, 4); + mv.visitInsn(CALOAD); + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ICONST_2); + mv.visitInsn(AALOAD); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getMethodName", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + Label l13 = new Label(); + mv.visitLabel(l13); + mv.visitJumpInsn(GOTO, l11); + mv.visitLabel(l9); + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ILOAD, 4); + mv.visitInsn(CALOAD); + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ICONST_1); + mv.visitInsn(AALOAD); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getClassName", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + Label l14 = new Label(); + mv.visitLabel(l14); + mv.visitJumpInsn(GOTO, l11); + mv.visitLabel(l10); + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ILOAD, 4); + mv.visitInsn(CALOAD); + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ICONST_1); + mv.visitInsn(AALOAD); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", "getMethodName", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(C)Ljava/lang/StringBuilder;", false); + mv.visitInsn(POP); + mv.visitLabel(l11); + mv.visitIincInsn(4, 1); + mv.visitLabel(l5); + mv.visitVarInsn(ILOAD, 4); + mv.visitVarInsn(ALOAD, 3); + mv.visitInsn(ARRAYLENGTH); + mv.visitJumpInsn(IF_ICMPLT, l6); + Label l15 = new Label(); + mv.visitLabel(l15); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false); + mv.visitInsn(ARETURN); + Label l16 = new Label(); + mv.visitLabel(l16); + mv.visitMaxs(4, 5); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, memberNames.bootstrapMethodName, "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", null, null); + mv.visitCode(); + Label l0 = new Label(); + Label l1 = new Label(); + Label l2 = new Label(); + mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable"); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(CHECKCAST, "java/lang/String"); + mv.visitMethodInsn(INVOKESTATIC, memberNames.className, memberNames.decryptorMethodName, "(Ljava/lang/String;)Ljava/lang/String;", false); + mv.visitLdcInsn("<>"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "split", "(Ljava/lang/String;)[Ljava/lang/String;", false); + mv.visitVarInsn(ASTORE, 3); + Label l3 = new Label(); + mv.visitLabel(l3); + mv.visitVarInsn(ALOAD, 3); + mv.visitInsn(ICONST_0); + mv.visitInsn(AALOAD); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false); + mv.visitVarInsn(ASTORE, 4); + Label l4 = new Label(); + mv.visitLabel(l4); + mv.visitVarInsn(ALOAD, 3); + mv.visitInsn(ICONST_1); + mv.visitInsn(AALOAD); + mv.visitVarInsn(ASTORE, 5); + Label l5 = new Label(); + mv.visitLabel(l5); + mv.visitVarInsn(ALOAD, 3); + mv.visitInsn(ICONST_2); + mv.visitInsn(AALOAD); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "parseInt", "(Ljava/lang/String;)I", false); + mv.visitVarInsn(ISTORE, 6); + Label l6 = new Label(); + mv.visitLabel(l6); + mv.visitVarInsn(ALOAD, 0); + mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); + mv.visitVarInsn(ASTORE, 7); + Label l7 = new Label(); + mv.visitLabel(l7); + mv.visitInsn(ACONST_NULL); + mv.visitVarInsn(ASTORE, 8); + Label l8 = new Label(); + mv.visitLabel(l8); + mv.visitVarInsn(ILOAD, 6); + Label l9 = new Label(); + Label l10 = new Label(); + Label l11 = new Label(); + Label l12 = new Label(); + Label l13 = new Label(); + Label l14 = new Label(); + Label l15 = new Label(); + Label l16 = new Label(); + mv.visitTableSwitchInsn(0, 6, l16, l9, l10, l11, l12, l13, l14, l15); + mv.visitLabel(l9); + mv.visitVarInsn(ALOAD, 7); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ALOAD, 5); + mv.visitVarInsn(ALOAD, 3); + mv.visitInsn(ICONST_3); + mv.visitInsn(AALOAD); + mv.visitLdcInsn(Type.getType("L" + memberNames.className + ";")); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "fromMethodDescriptorString", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStatic", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); + mv.visitVarInsn(ASTORE, 8); + Label l17 = new Label(); + mv.visitLabel(l17); + mv.visitJumpInsn(GOTO, l16); + mv.visitLabel(l10); + mv.visitVarInsn(ALOAD, 7); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ALOAD, 5); + mv.visitVarInsn(ALOAD, 3); + mv.visitInsn(ICONST_3); + mv.visitInsn(AALOAD); + mv.visitLdcInsn(Type.getType("L" + memberNames.className + ";")); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "fromMethodDescriptorString", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findVirtual", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); + mv.visitVarInsn(ASTORE, 8); + Label l18 = new Label(); + mv.visitLabel(l18); + mv.visitJumpInsn(GOTO, l16); + mv.visitLabel(l11); + mv.visitVarInsn(ALOAD, 7); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ALOAD, 5); + mv.visitVarInsn(ALOAD, 3); + mv.visitInsn(ICONST_3); + mv.visitInsn(AALOAD); + mv.visitLdcInsn(Type.getType("L" + memberNames.className + ";")); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "fromMethodDescriptorString", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;", false); + mv.visitVarInsn(ALOAD, 3); + mv.visitInsn(ICONST_4); + mv.visitInsn(AALOAD); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findSpecial", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;", false); + mv.visitVarInsn(ASTORE, 8); + Label l19 = new Label(); + mv.visitLabel(l19); + mv.visitJumpInsn(GOTO, l16); + mv.visitLabel(l12); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ALOAD, 5); + mv.visitMethodInsn(INVOKESTATIC, memberNames.className, memberNames.searchMethodName, "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;", false); + mv.visitVarInsn(ASTORE, 9); + Label l20 = new Label(); + mv.visitLabel(l20); + mv.visitVarInsn(ALOAD, 9); + mv.visitJumpInsn(IFNULL, l16); + Label l21 = new Label(); + mv.visitLabel(l21); + mv.visitVarInsn(ALOAD, 7); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ALOAD, 5); + mv.visitVarInsn(ALOAD, 9); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getType", "()Ljava/lang/Class;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStaticGetter", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;", false); + mv.visitVarInsn(ASTORE, 8); + Label l22 = new Label(); + mv.visitLabel(l22); + mv.visitJumpInsn(GOTO, l16); + mv.visitLabel(l13); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ALOAD, 5); + mv.visitMethodInsn(INVOKESTATIC, memberNames.className, memberNames.searchMethodName, "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;", false); + mv.visitVarInsn(ASTORE, 9); + Label l23 = new Label(); + mv.visitLabel(l23); + mv.visitVarInsn(ALOAD, 9); + mv.visitJumpInsn(IFNULL, l16); + Label l24 = new Label(); + mv.visitLabel(l24); + mv.visitVarInsn(ALOAD, 7); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ALOAD, 5); + mv.visitVarInsn(ALOAD, 9); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getType", "()Ljava/lang/Class;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findGetter", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;", false); + mv.visitVarInsn(ASTORE, 8); + Label l25 = new Label(); + mv.visitLabel(l25); + mv.visitJumpInsn(GOTO, l16); + mv.visitLabel(l14); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ALOAD, 5); + mv.visitMethodInsn(INVOKESTATIC, memberNames.className, memberNames.searchMethodName, "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;", false); + mv.visitVarInsn(ASTORE, 9); + Label l26 = new Label(); + mv.visitLabel(l26); + mv.visitVarInsn(ALOAD, 9); + mv.visitJumpInsn(IFNULL, l16); + Label l27 = new Label(); + mv.visitLabel(l27); + mv.visitVarInsn(ALOAD, 7); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ALOAD, 5); + mv.visitVarInsn(ALOAD, 9); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getType", "()Ljava/lang/Class;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStaticSetter", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;", false); + mv.visitVarInsn(ASTORE, 8); + Label l28 = new Label(); + mv.visitLabel(l28); + mv.visitJumpInsn(GOTO, l16); + mv.visitLabel(l15); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ALOAD, 5); + mv.visitMethodInsn(INVOKESTATIC, memberNames.className, memberNames.searchMethodName, "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;", false); + mv.visitVarInsn(ASTORE, 9); + Label l29 = new Label(); + mv.visitLabel(l29); + mv.visitVarInsn(ALOAD, 9); + mv.visitJumpInsn(IFNULL, l16); + Label l30 = new Label(); + mv.visitLabel(l30); + mv.visitVarInsn(ALOAD, 7); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ALOAD, 5); + mv.visitVarInsn(ALOAD, 9); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getType", "()Ljava/lang/Class;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findSetter", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;", false); + mv.visitVarInsn(ASTORE, 8); + mv.visitLabel(l16); + mv.visitTypeInsn(NEW, "java/lang/invoke/ConstantCallSite"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 8); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodType"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "asType", "(Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", "", "(Ljava/lang/invoke/MethodHandle;)V", false); + mv.visitLabel(l1); + mv.visitInsn(ARETURN); + mv.visitLabel(l2); + mv.visitVarInsn(ASTORE, 3); + Label l31 = new Label(); + mv.visitLabel(l31); + mv.visitVarInsn(ALOAD, 3); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", "printStackTrace", "()V", false); + Label l32 = new Label(); + mv.visitLabel(l32); + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + Label l33 = new Label(); + mv.visitLabel(l33); + mv.visitMaxs(6, 10); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, memberNames.searchMethodName, "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;", "(Ljava/lang/Class<*>;Ljava/lang/String;)Ljava/lang/reflect/Field;", null); + mv.visitCode(); + Label l0 = new Label(); + Label l1 = new Label(); + Label l2 = new Label(); + mv.visitTryCatchBlock(l0, l1, l2, "java/lang/NoSuchFieldException"); + Label l3 = new Label(); + Label l4 = new Label(); + Label l5 = new Label(); + mv.visitTryCatchBlock(l3, l4, l5, "java/lang/NoSuchFieldException"); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", false); + mv.visitVarInsn(ASTORE, 2); + Label l6 = new Label(); + mv.visitLabel(l6); + mv.visitVarInsn(ALOAD, 2); + mv.visitInsn(ICONST_1); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "setAccessible", "(Z)V", false); + Label l7 = new Label(); + mv.visitLabel(l7); + mv.visitVarInsn(ALOAD, 2); + mv.visitLabel(l1); + mv.visitInsn(ARETURN); + mv.visitLabel(l2); + mv.visitVarInsn(ASTORE, 2); + mv.visitLabel(l3); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getSuperclass", "()Ljava/lang/Class;", false); + mv.visitVarInsn(ASTORE, 3); + Label l8 = new Label(); + mv.visitLabel(l8); + mv.visitVarInsn(ALOAD, 3); + Label l9 = new Label(); + mv.visitJumpInsn(IFNONNULL, l9); + Label l10 = new Label(); + mv.visitLabel(l10); + mv.visitTypeInsn(NEW, "java/lang/NoSuchFieldException"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoSuchFieldException", "", "()V", false); + mv.visitInsn(ATHROW); + mv.visitLabel(l9); + mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKESTATIC, memberNames.className, memberNames.searchMethodName, "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;", false); + mv.visitInsn(DUP); + mv.visitVarInsn(ASTORE, 4); + Label l11 = new Label(); + mv.visitLabel(l11); + Label l12 = new Label(); + mv.visitJumpInsn(IFNULL, l12); + Label l13 = new Label(); + mv.visitLabel(l13); + mv.visitVarInsn(ALOAD, 4); + mv.visitLabel(l4); + mv.visitInsn(ARETURN); + mv.visitLabel(l5); + mv.visitVarInsn(ASTORE, 3); + Label l14 = new Label(); + mv.visitLabel(l14); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getInterfaces", "()[Ljava/lang/Class;", false); + mv.visitVarInsn(ASTORE, 4); + Label l15 = new Label(); + mv.visitLabel(l15); + mv.visitVarInsn(ALOAD, 4); + Label l16 = new Label(); + mv.visitJumpInsn(IFNONNULL, l16); + Label l17 = new Label(); + mv.visitLabel(l17); + mv.visitTypeInsn(NEW, "java/lang/RuntimeException"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "", "()V", false); + mv.visitInsn(ATHROW); + mv.visitLabel(l16); + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 5); + Label l18 = new Label(); + mv.visitLabel(l18); + Label l19 = new Label(); + mv.visitJumpInsn(GOTO, l19); + Label l20 = new Label(); + mv.visitLabel(l20); + mv.visitVarInsn(ALOAD, 4); + mv.visitVarInsn(ILOAD, 5); + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKESTATIC, memberNames.className, memberNames.searchMethodName, "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;", false); + mv.visitInsn(DUP); + mv.visitVarInsn(ASTORE, 6); + Label l21 = new Label(); + mv.visitLabel(l21); + Label l22 = new Label(); + mv.visitJumpInsn(IFNULL, l22); + Label l23 = new Label(); + mv.visitLabel(l23); + mv.visitVarInsn(ALOAD, 6); + mv.visitInsn(ARETURN); + mv.visitLabel(l22); + mv.visitIincInsn(5, 1); + mv.visitLabel(l19); + mv.visitVarInsn(ILOAD, 5); + mv.visitVarInsn(ALOAD, 4); + mv.visitInsn(ARRAYLENGTH); + mv.visitJumpInsn(IF_ICMPLT, l20); + mv.visitLabel(l12); + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + Label l24 = new Label(); + mv.visitLabel(l24); + mv.visitMaxs(2, 7); + mv.visitEnd(); + } + cw.visitEnd(); + + return cw; + } +} diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java index 782f8e44..b2661b20 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java @@ -20,14 +20,14 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.methods.InvokeDynamicBSM; +import me.itzsomebody.radon.classes.InvokeDynamicBootstrap; import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.StringUtils; import org.objectweb.asm.Handle; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.InvokeDynamicInsnNode; import org.objectweb.asm.tree.MethodInsnNode; @@ -40,239 +40,173 @@ * @author ItzSomebody. */ public class HeavyInvokeDynamic extends AbstractTransformer { - // Magic numbers - private int METHOD_INVOCATION = 1; - private int FIELD_INVOCATION = 0; - - private int STATIC_INVOCATION = 1; - private int VIRTUAL_INVOCATION = 0; - - private int VIRTUAL_GETTER = 0; - private int STATIC_GETTER = 1; - private int VIRTUAL_SETTER = 2; - private int STATIC_SETTER = 3; - /** * Applies obfuscation. */ public void obfuscate() { AtomicInteger counter = new AtomicInteger(); long current = System.currentTimeMillis(); + + MemberNames memberNames = new MemberNames(this); + + ArrayList finals = new ArrayList<>(); + this.classNodes().forEach(classNode -> + classNode.fields.stream().filter(fieldNode -> Modifier.isFinal(fieldNode.access)).forEach(fieldNode -> + finals.add(classNode.name + '.' + fieldNode.name) + ) + ); this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started heavy invokedynamic transformer")); - String[] bsmPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary)}; - Handle bsmHandle = new Handle(H_INVOKESTATIC, - bsmPath[0], - bsmPath[1], - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;)Ljava/lang/Object;", - false); + Handle bsmHandle = new Handle(H_INVOKESTATIC, memberNames.className, memberNames.bootstrapMethodName, "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false); + this.classNodes().parallelStream().filter(classNode -> !this.exempted(classNode.name, "InvokeDynamic") + && classNode.version >= 51).forEach(classNode -> + classNode.methods.parallelStream().filter(methodNode -> + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "InvokeDynamic") + && hasInstructions(methodNode)).forEach(methodNode -> { + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (this.methodSize(methodNode) > 60000) break; + if (insn instanceof MethodInsnNode) { + MethodInsnNode methodInsnNode = (MethodInsnNode) insn; + if (!methodInsnNode.name.equals("")) { + boolean isStatic = (methodInsnNode.getOpcode() == INVOKESTATIC); + String newSig = isStatic ? methodInsnNode.desc : methodInsnNode.desc.replace("(", "(Ljava/lang/Object;"); + Type returnType = Type.getReturnType(methodInsnNode.desc); + Type[] args = Type.getArgumentTypes(newSig); + for (int i = 0; i < args.length; i++) { + Type arg = args[i]; + if (arg.getSort() == Type.OBJECT) { + args[i] = Type.getType("Ljava/lang/Object;"); + } + } + newSig = Type.getMethodDescriptor(returnType, args); + StringBuilder sb = new StringBuilder(); + sb.append(methodInsnNode.owner.replace("/", ".")).append("<>").append(methodInsnNode.name).append("<>"); + + switch (insn.getOpcode()) { + case INVOKEINTERFACE: + case INVOKEVIRTUAL: { + sb.append("1<>").append(methodInsnNode.desc); + break; + } + case INVOKESPECIAL: { + sb.append("2<>").append(methodInsnNode.desc).append("<>").append(classNode.name.replace("/", ".")); + break; + } + case INVOKESTATIC: { + sb.append("0<>").append(methodInsnNode.desc); + break; + } + } - ArrayList finals = new ArrayList<>(); - this.classNodes().forEach(classNode -> { - classNode.fields.stream().filter(fieldNode -> Modifier.isFinal(fieldNode.access)).forEach(fieldNode -> { - finals.add(classNode.name + '.' + fieldNode.name); - }); - }); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "InvokeDynamic") - && classNode.version >= 51).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "InvokeDynamic") - && hasInstructions(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (this.methodSize(methodNode) > 60000) break; - if (insn instanceof MethodInsnNode) { - MethodInsnNode methodInsnNode = (MethodInsnNode) insn; - boolean isStatic = (methodInsnNode.getOpcode() == INVOKESTATIC); - String newSig = - isStatic ? methodInsnNode.desc : methodInsnNode.desc.replace("(", "(Ljava/lang/Object;"); - Type returnType = Type.getReturnType(methodInsnNode.desc); - switch (methodInsnNode.getOpcode()) { - case INVOKESTATIC: {// invokestatic opcode InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode( - StringUtils.randomString(this.dictionary), + encrypt(sb.toString(), memberNames), newSig, - bsmHandle, - this.METHOD_INVOCATION, - this.STATIC_INVOCATION, - this.encOwner(methodInsnNode.owner.replaceAll("/", ".")), - this.encName(methodInsnNode.name), - this.encDesc(methodInsnNode.desc)); + bsmHandle + ); + methodNode.instructions.set(insn, indy); if (returnType.getSort() == Type.ARRAY) { methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); } counter.incrementAndGet(); - break; } - case INVOKEVIRTUAL: // invokevirtual opcode - case INVOKEINTERFACE: {// invokeinterface opcode - InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode( - StringUtils.randomString(this.dictionary), - newSig, - bsmHandle, - this.METHOD_INVOCATION, - this.VIRTUAL_INVOCATION, - this.encOwner(methodInsnNode.owner.replaceAll("/", ".")), - this.encName(methodInsnNode.name), - this.encDesc(methodInsnNode.desc)); - methodNode.instructions.set(insn, indy); - if (returnType.getSort() == Type.ARRAY) { - methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); + } else if (insn instanceof FieldInsnNode) { + if (!methodNode.name.equals("")) { + FieldInsnNode fieldInsnNode = (FieldInsnNode) insn; + + if (finals.contains(fieldInsnNode.owner + '.' + fieldInsnNode.name)) { + continue; } - counter.incrementAndGet(); - break; - } - default: { - break; - } - } - } else if (insn instanceof FieldInsnNode) { - FieldInsnNode fieldInsnNode = (FieldInsnNode) insn; - if (finals.contains(fieldInsnNode.owner + '.' + fieldInsnNode.name)) { - continue; - } - boolean isStatic = (fieldInsnNode.getOpcode() == GETSTATIC - || fieldInsnNode.getOpcode() == PUTSTATIC); - boolean isSetter = (fieldInsnNode.getOpcode() == PUTFIELD - || fieldInsnNode.getOpcode() == PUTSTATIC); - String newSig - = (isSetter) ? "(" + fieldInsnNode.desc + ")V" : "()" + fieldInsnNode.desc; - if (!isStatic) - newSig = newSig.replace("(", "(Ljava/lang/Object;"); - Type type = Type.getType(fieldInsnNode.desc); - String wrappedDescription = type.getClassName(); - switch (fieldInsnNode.getOpcode()) { - case GETFIELD: { - Type returnType = Type.getType(fieldInsnNode.desc); - InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode( - StringUtils.randomString(this.dictionary), - newSig, - bsmHandle, - this.FIELD_INVOCATION, - this.VIRTUAL_GETTER, - this.encOwner(fieldInsnNode.owner.replaceAll("/", ".")), - this.encName(fieldInsnNode.name), - this.encDesc(wrappedDescription)); - methodNode.instructions.set(insn, indy); - if (returnType.getSort() == Type.ARRAY) { - methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); + boolean isStatic = (fieldInsnNode.getOpcode() == GETSTATIC || fieldInsnNode.getOpcode() == PUTSTATIC); + boolean isSetter = (fieldInsnNode.getOpcode() == PUTFIELD || fieldInsnNode.getOpcode() == PUTSTATIC); + String newSig = (isSetter) ? "(" + fieldInsnNode.desc + ")V" : "()" + fieldInsnNode.desc; + if (!isStatic) + newSig = newSig.replace("(", "(Ljava/lang/Object;"); + + StringBuilder sb = new StringBuilder(); + sb.append(fieldInsnNode.owner.replace("/", ".")).append("<>").append(fieldInsnNode.name).append("<>"); + + switch (insn.getOpcode()) { + case GETSTATIC: { + sb.append("3"); + break; + } + case GETFIELD: { + sb.append("4"); + break; + } + case PUTSTATIC: { + sb.append("5"); + break; + } + case PUTFIELD: { + sb.append("6"); + break; + } } - counter.incrementAndGet(); - break; - } - case GETSTATIC: { - Type returnType = Type.getType(fieldInsnNode.desc); + InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode( - StringUtils.randomString(this.dictionary), + encrypt(sb.toString(), memberNames), newSig, - bsmHandle, - this.FIELD_INVOCATION, - this.STATIC_GETTER, - this.encOwner(fieldInsnNode.owner.replaceAll("/", ".")), - this.encName(fieldInsnNode.name), - this.encDesc(wrappedDescription)); + bsmHandle + ); + methodNode.instructions.set(insn, indy); - if (returnType.getSort() == Type.ARRAY) { - methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); - } - counter.incrementAndGet(); - break; - } - case PUTFIELD: { - methodNode.instructions.set(insn, new InvokeDynamicInsnNode( - StringUtils.randomString(this.dictionary), - newSig, - bsmHandle, - this.FIELD_INVOCATION, - this.VIRTUAL_SETTER, - this.encOwner(fieldInsnNode.owner.replaceAll("/", ".")), - this.encName(fieldInsnNode.name), - this.encDesc(wrappedDescription))); - counter.incrementAndGet(); - break; - } - case PUTSTATIC: { - methodNode.instructions.set(insn, new InvokeDynamicInsnNode( - StringUtils.randomString(this.dictionary), - newSig, - bsmHandle, - this.FIELD_INVOCATION, - this.STATIC_SETTER, - this.encOwner(fieldInsnNode.owner.replaceAll("/", ".")), - this.encName(fieldInsnNode.name), - this.encDesc(wrappedDescription))); counter.incrementAndGet(); - break; - } - default: { - break; } } } - } - }); - }); + }) + ); - this.classNodes().stream().filter(classNode -> classNode.name.equals(bsmPath[0])).forEach(classNode -> { - classNode.methods.add(InvokeDynamicBSM.heavyBSM(bsmPath[1], classNode.name)); - classNode.access = BytecodeUtils.accessFixer(classNode.access); - }); + ClassNode decryptor = InvokeDynamicBootstrap.heavyBootstrap(memberNames); + this.getClassMap().put(decryptor.name, decryptor); this.logStrings.add(LoggerUtils.stdOut("Hid " + counter + " field and/or method accesses with invokedynamics.")); this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); } - /** - * Returns string with a simple encryption. - * - * @param msg inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encOwner(String msg) { - char[] chars = msg.toCharArray(); - char[] encChars = new char[chars.length]; - - for (int i = 0; i < chars.length; i++) { - encChars[i] = (char) (chars[i] ^ 4382); - } - - return new String(encChars); - } - - /** - * Returns string with a simple encryption. - * - * @param msg inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encName(String msg) { + private static String encrypt(String msg, MemberNames memberNames) { char[] chars = msg.toCharArray(); - char[] encChars = new char[chars.length]; - + StringBuilder sb = new StringBuilder(); for (int i = 0; i < chars.length; i++) { - encChars[i] = (char) (chars[i] ^ 3940); + switch (i % 4) { + case 0: { + sb.append((char) (chars[i] ^ memberNames.className.replace("/", ".").hashCode())); + break; + } + case 1: { + sb.append((char) (chars[i] ^ memberNames.bootstrapMethodName.hashCode())); + break; + } + case 2: { + sb.append((char) (chars[i] ^ memberNames.className.replace("/", ".").hashCode())); + break; + } + case 3: { + sb.append((char) (chars[i] ^ memberNames.decryptorMethodName.hashCode())); + break; + } + } } - return new String(encChars); + return sb.toString(); } /** - * Returns string with a simple encryption. - * - * @param msg inputed string to be encrypted. - * @return string with a simple encryption. + * Names of bootstrap class and members. */ - private String encDesc(String msg) { - char[] chars = msg.toCharArray(); - char[] encChars = new char[chars.length]; - - for (int i = 0; i < chars.length; i++) { - encChars[i] = (char) (chars[i] ^ 5739); + public class MemberNames { + public String className; + public String decryptorMethodName; + public String bootstrapMethodName; + public String searchMethodName; + + MemberNames(HeavyInvokeDynamic instance) { + this.className = StringUtils.randomClassName(instance.classNames(), instance.dictionary); + this.decryptorMethodName = StringUtils.randomString(instance.dictionary); + this.bootstrapMethodName = StringUtils.randomString(instance.dictionary); + this.searchMethodName = StringUtils.randomString(instance.dictionary); } - - return new String(encChars); } } \ No newline at end of file diff --git a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java index 8f4e312f..50f16941 100644 --- a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java @@ -327,51 +327,4 @@ public static String normalEncrypt(String className, String methodName, return new String(returnThis); } - - /** - * Encrypts string for use in {@link HeavyStringEncryption}. - * - * @param msg {@link String} to encrypt. - * @param key1 decryptor's containing class's name's hashcode. - * @param key2 hashcode of . - * @param key3 hashcode of the string's containing class's name's hashcode. - * @param key4 hashcode of the string's containing method's name's hashcode. - * @param key5 random integer to ensure randomization. - * @return {@link String} as the encrypted variant of the inputted string. - */ - public static String heavyEncrypt(String msg, int key1, int key2, int key3, int key4, int key5) { - char[] chars = msg.toCharArray(); - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < chars.length; i++) { - switch (i % 8) { - case 0: - sb.append((char) (chars[i] ^ key3 ^ key5)); - break; - case 1: - sb.append((char) (chars[i] ^ key2 ^ key4)); - break; - case 2: - sb.append((char) (chars[i] ^ key1 ^ key3)); - break; - case 3: - sb.append((char) (chars[i] ^ key5 ^ key2)); - break; - case 4: - sb.append((char) (chars[i] ^ key4 ^ key1)); - break; - case 5: - sb.append((char) (chars[i] ^ key3 ^ key2)); - break; - case 6: - sb.append((char) (chars[i] ^ key4 ^ key3)); - break; - case 7: - sb.append((char) (chars[i] ^ key5 ^ key4)); - break; - } - } - - return sb.toString(); - } } From 8ee7379bfb5cfdb735631b96c4040ad9e7a2ff70 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Fri, 13 Jul 2018 16:05:49 -0700 Subject: [PATCH 038/281] Some changes to number obfuscation transformer --- .../transformers/misc/NumberObfuscation.java | 79 ++++++++++--------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java index dedf2513..61016c3e 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java @@ -27,57 +27,64 @@ import org.objectweb.asm.tree.InsnNode; /** - * Transformer that splits up integers into simple arithmetic evaluations. + * Transformer that splits up integers into simple bitwise evaluations. * * @author ItzSomebody - * @author VincBreaker (Sorry Vinc, I just had to steal the idea of Smoke's number obfuscation lol) */ public class NumberObfuscation extends AbstractTransformer { /** - * Applies obfuscation.}. + * Applies obfuscation. */ public void obfuscate() { AtomicInteger counter = new AtomicInteger(); long current = System.currentTimeMillis(); this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started number obfuscation transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Numbers")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Numbers") - && hasInstructions(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (methodSize(methodNode) > 60000) break; - if (BytecodeUtils.isIntInsn(insn)) { - int originalNum = BytecodeUtils.getIntNumber(insn); - int value1 = NumberUtils.getRandomInt(); - int value2 = originalNum ^ value1; + this.logStrings.add(LoggerUtils.stdOut("Started normal number obfuscation transformer")); + this.classNodes().parallelStream().filter(classNode -> !this.exempted(classNode.name, "Numbers")).forEach(classNode -> + classNode.methods.parallelStream().filter(methodNode -> + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Numbers") + && hasInstructions(methodNode)).forEach(methodNode -> { + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (methodSize(methodNode) > 60000) break; + if (BytecodeUtils.isIntInsn(insn)) { + int originalNum = BytecodeUtils.getIntNumber(insn); + int value1 = NumberUtils.getRandomInt(); + int value2 = originalNum ^ value1; - InsnList insnList = new InsnList(); - insnList.add(BytecodeUtils.getNumberInsn(value1)); - insnList.add(BytecodeUtils.getNumberInsn(value2)); - insnList.add(new InsnNode(IXOR)); + InsnList insnList = new InsnList(); + insnList.add(BytecodeUtils.getNumberInsn(value1)); + insnList.add(BytecodeUtils.getNumberInsn(NumberUtils.getRandomInt())); + insnList.add(new InsnNode(SWAP)); + insnList.add(new InsnNode(DUP_X1)); + insnList.add(new InsnNode(POP2)); + insnList.add(BytecodeUtils.getNumberInsn(value2)); + insnList.add(new InsnNode(IXOR)); - methodNode.instructions.insertBefore(insn, insnList); - methodNode.instructions.remove(insn); - counter.incrementAndGet(); - } else if (BytecodeUtils.isLongInsn(insn)) { - long originalNum = BytecodeUtils.getLongNumber(insn); - long value1 = NumberUtils.getRandomLong(); - long value2 = originalNum ^ value1; + methodNode.instructions.insertBefore(insn, insnList); + methodNode.instructions.remove(insn); + counter.incrementAndGet(); + } else if (BytecodeUtils.isLongInsn(insn)) { + long originalNum = BytecodeUtils.getLongNumber(insn); + long value1 = NumberUtils.getRandomLong(); + long value2 = originalNum ^ value1; - InsnList insnList = new InsnList(); - insnList.add(BytecodeUtils.getNumberInsn(value1)); - insnList.add(BytecodeUtils.getNumberInsn(value2)); - insnList.add(new InsnNode(LXOR)); + InsnList insnList = new InsnList(); + insnList.add(BytecodeUtils.getNumberInsn(NumberUtils.getRandomLong())); + insnList.add(BytecodeUtils.getNumberInsn(value1)); + insnList.add(new InsnNode(DUP2_X2)); + insnList.add(new InsnNode(POP2)); + insnList.add(new InsnNode(POP2)); + insnList.add(BytecodeUtils.getNumberInsn(value2)); + insnList.add(new InsnNode(LXOR)); - methodNode.instructions.insertBefore(insn, insnList); - methodNode.instructions.remove(insn); - counter.incrementAndGet(); + methodNode.instructions.insertBefore(insn, insnList); + methodNode.instructions.remove(insn); + counter.incrementAndGet(); + } } - } - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Split " + counter + " numbers into bitwise xor instructions.")); + }) + ); + this.logStrings.add(LoggerUtils.stdOut("Split " + counter + " numbers into math instructions.")); this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); } } From 43ddb8768e9334fb1979ee0fe7bef90f469d7740 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Fri, 13 Jul 2018 16:07:20 -0700 Subject: [PATCH 039/281] Changed a couple strings in number obf transformer --- .../radon/transformers/misc/NumberObfuscation.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java index 61016c3e..8dafc922 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java @@ -39,7 +39,7 @@ public void obfuscate() { AtomicInteger counter = new AtomicInteger(); long current = System.currentTimeMillis(); this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started normal number obfuscation transformer")); + this.logStrings.add(LoggerUtils.stdOut("Started number obfuscation transformer")); this.classNodes().parallelStream().filter(classNode -> !this.exempted(classNode.name, "Numbers")).forEach(classNode -> classNode.methods.parallelStream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Numbers") @@ -84,7 +84,7 @@ && hasInstructions(methodNode)).forEach(methodNode -> { } }) ); - this.logStrings.add(LoggerUtils.stdOut("Split " + counter + " numbers into math instructions.")); + this.logStrings.add(LoggerUtils.stdOut("Split " + counter + " numbers into bitwise xor instructions.")); this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); } } From 4c20d8e191421c3756d768e99d43f0757ae1b6ea Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 18:25:00 -0400 Subject: [PATCH 040/281] Remove repeat code from ConfigWriter --- .../itzsomebody/radon/config/ConfigEnum.java | 63 ++++--- .../radon/config/ConfigWriter.java | 168 ++++-------------- 2 files changed, 67 insertions(+), 164 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java b/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java index 45002a95..e5653ccf 100644 --- a/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java +++ b/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java @@ -23,30 +23,41 @@ * @author ItzSomebody */ public enum ConfigEnum { - INPUT, - OUTPUT, - LIBRARIES, - EXEMPTS, - STRING_ENCRYPTION, - FLOW_OBFUSCATION, - INVOKEDYNAMIC, - LOCAL_VARIABLES, - CRASHER, - HIDER, - STRING_POOL, - LINE_NUMBERS, - NUMBERS, - SOURCE_NAME, - SOURCE_DEBUG, - TRASH_CLASSES, - WATERMARK_MSG, - WATERMARK_KEY, - WATERMARK_TYPE, - SPIGOT_PLUGIN, - RENAMER, - EXPIRATION_TIME, - EXPIRATION_MESSAGE, - SHUFFLER, - DICTIONARY, - INNERCLASSES + INPUT("Input"), + OUTPUT("Output"), + LIBRARIES("Libraries"), + EXEMPTS("Exempts"), + STRING_ENCRYPTION("StringEncryption"), + FLOW_OBFUSCATION("FlowObfuscation"), + INVOKEDYNAMIC("InvokeDynamic"), + LOCAL_VARIABLES("LocalVariableObfuscation"), + CRASHER("Crasher"), + HIDER("HideCode"), + STRING_POOL("StringPool"), + LINE_NUMBERS("LineNumberObfuscation"), + NUMBERS("NumberObfuscation"), + SOURCE_NAME("SourceNameObfuscation"), + SOURCE_DEBUG("SourceDebugObfuscation"), + TRASH_CLASSES("TrashClasses"), + WATERMARK_MSG("WatermarkMessage"), + WATERMARK_KEY("WatermarkKey"), + WATERMARK_TYPE("WatermarkType"), + SPIGOT_PLUGIN("SpigotPlugin"), // TODO: Remove this + RENAMER("Renamer"), + EXPIRATION_TIME("ExpiryTime"), + EXPIRATION_MESSAGE("ExpiryMessage"), + SHUFFLER("Shuffler"), + DICTIONARY("Dictionary"), + INNERCLASSES("InnerClassRemover"); + + private final String text; + + private ConfigEnum(String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } } diff --git a/src/main/java/me/itzsomebody/radon/config/ConfigWriter.java b/src/main/java/me/itzsomebody/radon/config/ConfigWriter.java index f42d2f03..f4436048 100644 --- a/src/main/java/me/itzsomebody/radon/config/ConfigWriter.java +++ b/src/main/java/me/itzsomebody/radon/config/ConfigWriter.java @@ -54,145 +54,37 @@ public ConfigWriter(Map keyValueMap) { * Parses all options into a virtual config. */ public void parseOptions() { - Object result = this.keyValueMap.get(ConfigEnum.INPUT); - if (result != null) { - lines.add("Input: \"" + result.toString().replace("\\", "/") + "\""); - } - - result = this.keyValueMap.get(ConfigEnum.OUTPUT); - if (result != null) { - lines.add("Output: \"" + result.toString().replace("\\", "/") + "\""); - } - - result = this.keyValueMap.get(ConfigEnum.STRING_ENCRYPTION); - if (result != null) { - lines.add("StringEncryption: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.INVOKEDYNAMIC); - if (result != null) { - lines.add("InvokeDynamic: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.FLOW_OBFUSCATION); - if (result != null) { - lines.add("FlowObfuscation: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.LOCAL_VARIABLES); - if (result != null) { - lines.add("LocalVariableObfuscation: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.CRASHER); - if (result != null) { - lines.add("Crasher: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.HIDER); - if (result != null) { - lines.add("HideCode: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.STRING_POOL); - if (result != null) { - lines.add("StringPool: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.LINE_NUMBERS); - if (result != null) { - lines.add("LineNumberObfuscation: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.NUMBERS); - if (result != null) { - lines.add("NumberObfuscation: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.SOURCE_NAME); - if (result != null) { - lines.add("SourceNameObfuscation: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.SOURCE_DEBUG); - if (result != null) { - lines.add("SourceDebugObfuscation: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.TRASH_CLASSES); - if (result != null) { - lines.add("TrashClasses: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.WATERMARK_MSG); - if (result != null) { - lines.add("WatermarkMessage: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.WATERMARK_TYPE); - if (result != null) { - lines.add("WatermarkType: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.WATERMARK_KEY); - if (result != null) { - lines.add("WatermarkKey: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.SPIGOT_PLUGIN); - if (result != null) { - lines.add("SpigotPlugin: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.RENAMER); - if (result != null) { - lines.add("Renamer: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.EXPIRATION_TIME); - if (result != null) { - lines.add("ExpiryTime: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.EXPIRATION_MESSAGE); - if (result != null) { - lines.add("ExpiryMessage: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.SHUFFLER); - if (result != null) { - lines.add("Shuffler: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.DICTIONARY); - if (result != null) { - lines.add("Dictionary: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.INNERCLASSES); - if (result != null) { - lines.add("InnerClassRemover: " + result); - } - - result = this.keyValueMap.get(ConfigEnum.LIBRARIES); - if (result != null) { - List libs = (List) result; - if (!libs.isEmpty()) { - lines.add("Libraries: "); - for (String lib : libs) { - lines.add(" - \"" + lib.replace("\\", "/") + "\""); - } + for (ConfigEnum conf : ConfigEnum.values()) { + // Get config for enum value, if it exists, add line + Object result = keyValueMap.get(conf); + if (result == null) { + continue; } - } - - result = this.keyValueMap.get(ConfigEnum.EXEMPTS); - if (result != null) { - List exempts = (List) result; - if (!exempts.isEmpty()) { - lines.add("Exempts: "); - for (String exempt : exempts) { - lines.add(" - \"" + exempt + "\""); - } + switch (conf) { + case LIBRARIES: + List libs = (List) result; + if (!libs.isEmpty()) { + lines.add("Libraries: "); + for (String lib : libs) { + lines.add(" - \"" + lib.replace("\\", "/") + "\""); + } + } + break; + case EXEMPTS: + List exempts = (List) result; + if (!exempts.isEmpty()) { + lines.add("Exempts: "); + for (String exempt : exempts) { + lines.add(" - \"" + exempt + "\""); + } + } + break; + case INPUT: + case OUTPUT: + lines.add(conf + ": \"" + result.toString().replace("\\", "/") + "\""); + break; + default: + lines.add(conf + ": " + result); } } } From 96a1cbe9318ca7c2cab90dcf1fb8aef006c3816d Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 18:34:03 -0400 Subject: [PATCH 041/281] Remove repeat code from Config --- .../me/itzsomebody/radon/config/Config.java | 33 +++---------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/config/Config.java b/src/main/java/me/itzsomebody/radon/config/Config.java index 4b0b079a..ab69a0ee 100644 --- a/src/main/java/me/itzsomebody/radon/config/Config.java +++ b/src/main/java/me/itzsomebody/radon/config/Config.java @@ -64,41 +64,18 @@ public class Config { /** * Valid keys for element map loaded from config. */ - private ArrayList VALIDKEYS = new ArrayList() { + private final static ArrayList VALIDKEYS = new ArrayList() { { - add("Input"); - add("Output"); - add("Libraries"); - add("Exempts"); - add("StringEncryption"); - add("FlowObfuscation"); - add("InvokeDynamic"); - add("LocalVariableObfuscation"); - add("Crasher"); - add("HideCode"); - add("StringPool"); - add("LineNumberObfuscation"); - add("NumberObfuscation"); - add("SourceNameObfuscation"); - add("SourceDebugObfuscation"); - add("TrashClasses"); - add("WatermarkMessage"); - add("WatermarkType"); - add("WatermarkKey"); - add("SpigotPlugin"); - add("Renamer"); - add("ExpiryTime"); - add("ExpiryMessage"); - add("Shuffler"); - add("InnerClassRemover"); - add("Dictionary"); + for (ConfigEnum conf : ConfigEnum.values()) { + add(conf.toString()); + } } }; /** * The config object as {@link InputStream}. */ - private InputStream config; + private final InputStream config; /** * The element map object as {@link Map}. From 9238a7fa3f22c019dd1a72f390ae63cd72553819 Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 18:38:39 -0400 Subject: [PATCH 042/281] Fix window not being centered --- src/main/java/me/itzsomebody/radon/gui/MainGUI.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java index e6ca7354..6ade9d0d 100644 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; import javax.swing.*; + import me.itzsomebody.radon.Radon; import me.itzsomebody.radon.config.Config; import me.itzsomebody.radon.config.ConfigEnum; @@ -100,7 +101,8 @@ private void initialize() { } this.frmRadonObfuscator = new JFrame(); this.frmRadonObfuscator.setTitle(Radon.PREFIX + " " + Radon.VERSION); - this.frmRadonObfuscator.setBounds(100, 100, 440, 570); + this.frmRadonObfuscator.setSize(440, 570); + this.frmRadonObfuscator.setLocationRelativeTo(null); this.frmRadonObfuscator.setResizable(true); this.frmRadonObfuscator .setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); From 2bc4f1298dce8e9556b716b48acafd4408d885ad Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 18:39:49 -0400 Subject: [PATCH 043/281] Fix window not being centered - Console --- src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java b/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java index 6216ee91..711cfd68 100644 --- a/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java @@ -85,8 +85,8 @@ public void windowClosing(WindowEvent e) { thisFrame.dispose(); } }); - this.thisFrame.setBounds(400, 400, 600, 400); - + this.thisFrame.setSize(600, 400); + this.thisFrame.setLocationRelativeTo(null); this.consolePanel = new JPanel(new BorderLayout()); this.consoleOutput = new JTextArea(); this.consoleOutput.setFont(new Font("Arial", Font.PLAIN, 12)); From 67b9b5643581ab4d2a59f15cfc22f7e7aed40e57 Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 19:11:16 -0400 Subject: [PATCH 044/281] Cleanup of utility classes, potentially fix faulty annotation detection --- .../transformers/AbstractTransformer.java | 10 +- .../invokedynamic/LightInvokeDynamic.java | 2 +- .../invokedynamic/NormalInvokeDynamic.java | 2 +- .../radon/transformers/misc/Expiry.java | 2 +- .../transformers/misc/NumberObfuscation.java | 12 +- .../radon/transformers/misc/StringPool.java | 2 +- .../radon/transformers/renamer/Renamer.java | 6 +- .../HeavyStringEncryption.java | 2 +- .../LightStringEncryption.java | 4 +- .../NormalStringEncryption.java | 4 +- .../SuperLightStringEncryption.java | 4 +- .../radon/utils/BytecodeUtils.java | 348 ++++++++++++++++- .../me/itzsomebody/radon/utils/FileUtils.java | 10 +- .../itzsomebody/radon/utils/LoggerUtils.java | 2 +- ...{CustomRegexUtils.java => MatchUtils.java} | 15 +- .../itzsomebody/radon/utils/OpcodeUtils.java | 356 ------------------ .../itzsomebody/radon/utils/StringUtils.java | 140 ++----- 17 files changed, 405 insertions(+), 516 deletions(-) rename src/main/java/me/itzsomebody/radon/utils/{CustomRegexUtils.java => MatchUtils.java} (69%) delete mode 100644 src/main/java/me/itzsomebody/radon/utils/OpcodeUtils.java diff --git a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java index 98823b4a..50b6b78a 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java @@ -23,7 +23,7 @@ import java.util.List; import java.util.Map; import me.itzsomebody.radon.internal.Bootstrap; -import me.itzsomebody.radon.utils.CustomRegexUtils; +import me.itzsomebody.radon.utils.MatchUtils; import org.objectweb.asm.Opcodes; import org.objectweb.asm.commons.CodeSizeEvaluator; import org.objectweb.asm.tree.ClassNode; @@ -146,19 +146,19 @@ protected boolean exempted(String checkThis, String exemptId) { String exemptKey = exemptId + ": "; for (String exempt : this.exempts) { if (exempt.startsWith(exemptKey)) { - if (CustomRegexUtils.isMatched(exempt.replace(exemptKey, ""), checkThis)) { + if (MatchUtils.isMatched(exempt.replace(exemptKey, ""), checkThis)) { return true; } } else if (exempt.startsWith("Class: ")) { - if (CustomRegexUtils.isMatched(exempt.replace("Class: ", ""), checkThis)) { + if (MatchUtils.isMatched(exempt.replace("Class: ", ""), checkThis)) { return true; } } else if (exempt.startsWith("Method: ")) { - if (CustomRegexUtils.isMatched(exempt.replace("Method: ", ""), checkThis)) { + if (MatchUtils.isMatched(exempt.replace("Method: ", ""), checkThis)) { return true; } } else if (exempt.startsWith("Field: ")) { - if (CustomRegexUtils.isMatched(exempt.replace("Field: ", ""), checkThis)) { + if (MatchUtils.isMatched(exempt.replace("Field: ", ""), checkThis)) { return true; } } diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java index 00057495..f80b1dd6 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java @@ -98,7 +98,7 @@ && hasInstructions(methodNode)).forEach(methodNode -> { this.classNodes().stream().filter(classNode -> classNode.name.equals(bsmPath[0])).forEach(classNode -> { classNode.methods.add(InvokeDynamicBSM.lightBSM(bsmPath[1], classNode.name)); - classNode.access = BytecodeUtils.accessFixer(classNode.access); + classNode.access = BytecodeUtils.makePublic(classNode.access); }); this.logStrings.add(LoggerUtils.stdOut("Replaced " + counter + " method invocations with invokedynamics.")); this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java index 88ca71e0..aaf2fdc7 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java @@ -100,7 +100,7 @@ && hasInstructions(methodNode)).forEach(methodNode -> { this.classNodes().stream().filter(classNode -> classNode.name.equals(bsmPath[0])).forEach(classNode -> { classNode.methods.add(InvokeDynamicBSM.normalBSM(bsmPath[1], classNode.name)); - classNode.access = BytecodeUtils.accessFixer(classNode.access); + classNode.access = BytecodeUtils.makePublic(classNode.access); }); this.logStrings.add(LoggerUtils.stdOut("Replaced " + counter + " method invocations with invokedynamics.")); this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java index 07a2fb90..23ce2db1 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java @@ -66,7 +66,7 @@ public void obfuscate() { && methodSize(methodNode) < 60000 && hasInstructions(methodNode)).forEach(methodNode -> { methodNode.instructions.insertBefore(methodNode.instructions.getFirst(), - BytecodeUtils.returnExpiry(this.expiryTime, this.expiryMsg)); + BytecodeUtils.createExpiry(this.expiryTime, this.expiryMsg)); counter.incrementAndGet(); }); }); diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java index 8dafc922..99627772 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java @@ -52,12 +52,12 @@ && hasInstructions(methodNode)).forEach(methodNode -> { int value2 = originalNum ^ value1; InsnList insnList = new InsnList(); - insnList.add(BytecodeUtils.getNumberInsn(value1)); - insnList.add(BytecodeUtils.getNumberInsn(NumberUtils.getRandomInt())); + insnList.add(BytecodeUtils.createNumberInsn(value1)); + insnList.add(BytecodeUtils.createNumberInsn(NumberUtils.getRandomInt())); insnList.add(new InsnNode(SWAP)); insnList.add(new InsnNode(DUP_X1)); insnList.add(new InsnNode(POP2)); - insnList.add(BytecodeUtils.getNumberInsn(value2)); + insnList.add(BytecodeUtils.createNumberInsn(value2)); insnList.add(new InsnNode(IXOR)); methodNode.instructions.insertBefore(insn, insnList); @@ -69,12 +69,12 @@ && hasInstructions(methodNode)).forEach(methodNode -> { long value2 = originalNum ^ value1; InsnList insnList = new InsnList(); - insnList.add(BytecodeUtils.getNumberInsn(NumberUtils.getRandomLong())); - insnList.add(BytecodeUtils.getNumberInsn(value1)); + insnList.add(BytecodeUtils.createNumberInsn(NumberUtils.getRandomLong())); + insnList.add(BytecodeUtils.createNumberInsn(value1)); insnList.add(new InsnNode(DUP2_X2)); insnList.add(new InsnNode(POP2)); insnList.add(new InsnNode(POP2)); - insnList.add(BytecodeUtils.getNumberInsn(value2)); + insnList.add(BytecodeUtils.createNumberInsn(value2)); insnList.add(new InsnNode(LXOR)); methodNode.instructions.insertBefore(insn, insnList); diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java b/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java index b02de572..46c8f7e5 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java @@ -83,7 +83,7 @@ && hasInstructions(methodNode)).forEach(methodNode -> { int indexNumber = stringslist.size() - 1; methodNode.instructions.insertBefore(insn, new FieldInsnNode(GETSTATIC, classNode.name, this.fieldName[1], "[Ljava/lang/String;")); - methodNode.instructions.insertBefore(insn, BytecodeUtils.getNumberInsn(indexNumber)); + methodNode.instructions.insertBefore(insn, BytecodeUtils.createNumberInsn(indexNumber)); methodNode.instructions.set(insn, new InsnNode(AALOAD)); counter.incrementAndGet(); } diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java index 2e360b77..0b656d28 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java @@ -115,14 +115,14 @@ public void obfuscate() { for (ClassNode classNode : new ArrayList<>(this.classNodes())) { ClassNode copy = new ClassNode(); classNode.accept(new ClassRemapper(copy, simpleRemapper)); - copy.access = BytecodeUtils.accessFixer(copy.access); + copy.access = BytecodeUtils.makePublic(copy.access); for (MethodNode methodNode : copy.methods) { - methodNode.access = BytecodeUtils.accessFixer(methodNode.access); + methodNode.access = BytecodeUtils.makePublic(methodNode.access); } if (copy.fields != null) { for (FieldNode fieldNode : copy.fields) { - fieldNode.access = BytecodeUtils.accessFixer(fieldNode.access); + fieldNode.access = BytecodeUtils.makePublic(fieldNode.access); } } diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java index 567a3806..1360255c 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java @@ -84,7 +84,7 @@ && hasInstructions(methodNode)).forEach(methodNode -> { methodNode.instructions.insert(insn, new MethodInsnNode(INVOKESTATIC, memberNames.className, memberNames.decryptorMethodName, "(Ljava/lang/Object;I)Ljava/lang/String;", false)); methodNode.instructions.insert(insn, new InsnNode(POP)); methodNode.instructions.insert(insn, new InsnNode(DUP_X1)); - methodNode.instructions.insertBefore(insn, BytecodeUtils.getNumberInsn(extraKey)); + methodNode.instructions.insertBefore(insn, BytecodeUtils.createNumberInsn(extraKey)); counter.incrementAndGet(); } diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java index 3ebd764f..49453144 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java @@ -89,7 +89,7 @@ && hasInstructions(methodNode)).forEach(methodNode -> { "Ljava/lang/String;", false)); methodNode.instructions.insert(insn, - BytecodeUtils.getNumberInsn(key3)); + BytecodeUtils.createNumberInsn(key3)); counter.incrementAndGet(); } } @@ -99,7 +99,7 @@ && hasInstructions(methodNode)).forEach(methodNode -> { this.classNodes().stream().filter(classNode -> classNode.name.equals(decryptorPath[0])).forEach(classNode -> { classNode.methods.add(StringEncryption.lightMethod(decryptorPath[1])); - classNode.access = BytecodeUtils.accessFixer(classNode.access); + classNode.access = BytecodeUtils.makePublic(classNode.access); }); logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java index ce8128c8..45a74ace 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java @@ -92,7 +92,7 @@ && hasInstructions(methodNode)).forEach(methodNode -> { "Ljava/lang/String;", false)); methodNode.instructions.insert(insn, - BytecodeUtils.getNumberInsn(key3)); + BytecodeUtils.createNumberInsn(key3)); methodNode.instructions.insert(insn, new InsnNode(ACONST_NULL)); counter.incrementAndGet(); @@ -104,7 +104,7 @@ && hasInstructions(methodNode)).forEach(methodNode -> { this.classNodes().stream().filter(classNode -> classNode.name.equals(decryptorPath[0])).forEach(classNode -> { classNode.methods.add(StringEncryption.normalMethod(decryptorPath[1])); - classNode.access = BytecodeUtils.accessFixer(classNode.access); + classNode.access = BytecodeUtils.makePublic(classNode.access); }); logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java index cd735f79..d7a1b3cc 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java @@ -86,7 +86,7 @@ && hasInstructions(methodNode)).forEach(methodNode -> { "Ljava/lang/String;", false)); methodNode.instructions.insert(insn, - BytecodeUtils.getNumberInsn(key)); + BytecodeUtils.createNumberInsn(key)); counter.incrementAndGet(); } } @@ -96,7 +96,7 @@ && hasInstructions(methodNode)).forEach(methodNode -> { this.classNodes().stream().filter(classNode -> classNode.name.equals(decryptorPath[0])).forEach(classNode -> { classNode.methods.add(StringEncryption.superLightMethod(decryptorPath[1])); - classNode.access = BytecodeUtils.accessFixer(classNode.access); + classNode.access = BytecodeUtils.makePublic(classNode.access); }); logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); diff --git a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java index f7da9c41..b63657f4 100644 --- a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java @@ -45,7 +45,7 @@ public class BytecodeUtils { * @param access input access as {@link Integer}. * @return new {@link Integer} without restrictive flags. */ - public static int accessFixer(int access) { + public static int makePublic(int access) { int a = access; if ((a & Opcodes.ACC_PRIVATE) != 0) { a ^= Opcodes.ACC_PRIVATE; @@ -65,7 +65,7 @@ public static int accessFixer(int access) { * @param expiryTime a {@link Long} representation of the expiration date. * @return an {@link InsnList} with bytecode instructions for expiration. */ - public static InsnList returnExpiry(long expiryTime, String expiredMsg) { + public static InsnList createExpiry(long expiryTime, String expiredMsg) { InsnList expiryCode = new InsnList(); LabelNode injectedLabel = new LabelNode(new Label()); @@ -94,7 +94,7 @@ public static InsnList returnExpiry(long expiryTime, String expiredMsg) { * @param number the {@link Integer} for the obfuscator to contemplate. * @return a bytecode instruction representing an int. */ - public static AbstractInsnNode getNumberInsn(int number) { + public static AbstractInsnNode createNumberInsn(int number) { if (number >= -1 && number <= 5) { return new InsnNode(number + 3); } else if (number >= -128 && number <= 127) { @@ -112,7 +112,7 @@ public static AbstractInsnNode getNumberInsn(int number) { * @param number the {@link Long} for the obfuscator to contemplate. * @return a bytecode instruction representing a long. */ - public static AbstractInsnNode getNumberInsn(long number) { + public static AbstractInsnNode createNumberInsn(long number) { if (number >= 0 && number <= 1) { return new InsnNode((int) (number + 9)); } else { @@ -179,7 +179,6 @@ public static boolean isLongInsn(AbstractInsnNode insn) { */ public static int getIntNumber(AbstractInsnNode insn) { int opcode = insn.getOpcode(); - if (opcode >= Opcodes.ICONST_M1 && opcode <= Opcodes.ICONST_5) { return opcode - 3; } else if (insn instanceof IntInsnNode @@ -189,7 +188,6 @@ public static int getIntNumber(AbstractInsnNode insn) { && ((LdcInsnNode) insn).cst instanceof Integer) { return (Integer) ((LdcInsnNode) insn).cst; } - throw new IllegalStateException("Unexpected instruction"); } @@ -203,14 +201,12 @@ public static int getIntNumber(AbstractInsnNode insn) { */ public static long getLongNumber(AbstractInsnNode insn) { int opcode = insn.getOpcode(); - if (opcode >= Opcodes.LCONST_0 && opcode <= Opcodes.LCONST_1) { return opcode - 9; } else if (insn instanceof LdcInsnNode && ((LdcInsnNode) insn).cst instanceof Long) { return (Long) ((LdcInsnNode) insn).cst; } - throw new IllegalStateException("Unexpected instruction"); } @@ -227,7 +223,6 @@ public static boolean containsGoto(MethodNode methodNode) { return true; } } - return false; } @@ -238,7 +233,7 @@ public static boolean containsGoto(MethodNode methodNode) { * @return true if provided {@link MethodNode} has any annotations. Otherwise, false. */ public static boolean hasAnnotations(MethodNode methodNode) { - return (methodNode.visibleAnnotations != null && methodNode.visibleAnnotations.isEmpty()); + return methodNode.visibleAnnotations != null && !methodNode.visibleAnnotations.isEmpty(); } /** @@ -248,7 +243,7 @@ public static boolean hasAnnotations(MethodNode methodNode) { * @return true if provided {@link FieldNode} has any annotations. Otherwise, false. */ public static boolean hasAnnotations(FieldNode fieldNode) { - return (fieldNode.visibleAnnotations != null && fieldNode.visibleAnnotations.isEmpty()); + return fieldNode.visibleAnnotations != null && !fieldNode.visibleAnnotations.isEmpty(); } /** @@ -258,6 +253,335 @@ public static boolean hasAnnotations(FieldNode fieldNode) { * @return true if provided {@link ClassNode} has any annotations. Otherwise, false. */ public static boolean hasAnnotations(ClassNode classNode) { - return (classNode.visibleAnnotations != null && classNode.visibleAnnotations.isEmpty()); + return classNode.visibleAnnotations != null && !classNode.visibleAnnotations.isEmpty(); + } + + // TODO: Unused, this can be removed. + /** + * Returns a {@link String} representation of inputted opcode. + * + * @param opcode the opcode to get a name from. + * @return a {@link String} representation of inputted opcode. + */ + public static String getOpcodeName(int opcode) { + switch (opcode) { + case Opcodes.NOP: + return "nop"; + case Opcodes.ACONST_NULL: + return "aconst_null"; + case Opcodes.ICONST_M1: + return "iconst_m1"; + case Opcodes.ICONST_0: + return "iconst_0"; + case Opcodes.ICONST_1: + return "iconst_1"; + case Opcodes.ICONST_2: + return "iconst_2"; + case Opcodes.ICONST_3: + return "iconst_3"; + case Opcodes.ICONST_4: + return "iconst_4"; + case Opcodes.ICONST_5: + return "iconst_5"; + case Opcodes.LCONST_0: + return "lconst_0"; + case Opcodes.LCONST_1: + return "lconst_1"; + case Opcodes.FCONST_0: + return "fconst_0"; + case Opcodes.FCONST_1: + return "fconst_1"; + case Opcodes.FCONST_2: + return "fconst_2"; + case Opcodes.DCONST_0: + return "dconst_0"; + case Opcodes.DCONST_1: + return "dconst_1"; + case Opcodes.BIPUSH: + return "bipush"; + case Opcodes.SIPUSH: + return "sipush"; + case Opcodes.LDC: + return "ldc"; + case Opcodes.ILOAD: + return "iload"; + case Opcodes.LLOAD: + return "lload"; + case Opcodes.FLOAD: + return "fload"; + case Opcodes.DLOAD: + return "dload"; + case Opcodes.ALOAD: + return "aload"; + case Opcodes.IALOAD: + return "iaload"; + case Opcodes.LALOAD: + return "laload"; + case Opcodes.FALOAD: + return "faload"; + case Opcodes.DALOAD: + return "daload"; + case Opcodes.AALOAD: + return "aaload"; + case Opcodes.BALOAD: + return "baload"; + case Opcodes.CALOAD: + return "caload"; + case Opcodes.SALOAD: + return "saload"; + case Opcodes.ISTORE: + return "istore"; + case Opcodes.LSTORE: + return "lstore"; + case Opcodes.FSTORE: + return "fstore"; + case Opcodes.DSTORE: + return "dstore"; + case Opcodes.ASTORE: + return "astore"; + case Opcodes.IASTORE: + return "iastore"; + case Opcodes.LASTORE: + return "lastore"; + case Opcodes.FASTORE: + return "fastore"; + case Opcodes.DASTORE: + return "dastore"; + case Opcodes.AASTORE: + return "aastore"; + case Opcodes.BASTORE: + return "bastore"; + case Opcodes.CASTORE: + return "castore"; + case Opcodes.SASTORE: + return "sastore"; + case Opcodes.POP: + return "pop"; + case Opcodes.POP2: + return "pop2"; + case Opcodes.DUP: + return "dup"; + case Opcodes.DUP_X1: + return "dup_x1"; + case Opcodes.DUP_X2: + return "dup_x2"; + case Opcodes.DUP2: + return "dup2"; + case Opcodes.DUP2_X1: + return "dup2_x1"; + case Opcodes.DUP2_X2: + return "dup2_x2"; + case Opcodes.SWAP: + return "swap"; + case Opcodes.IADD: + return "iadd"; + case Opcodes.LADD: + return "ladd"; + case Opcodes.FADD: + return "fadd"; + case Opcodes.DADD: + return "dadd"; + case Opcodes.ISUB: + return "isub"; + case Opcodes.LSUB: + return "lsub"; + case Opcodes.FSUB: + return "fsub"; + case Opcodes.DSUB: + return "dsub"; + case Opcodes.IMUL: + return "imul"; + case Opcodes.LMUL: + return "lmul"; + case Opcodes.FMUL: + return "fmul"; + case Opcodes.DMUL: + return "dmul"; + case Opcodes.IDIV: + return "idiv"; + case Opcodes.LDIV: + return "ldiv"; + case Opcodes.FDIV: + return "fdiv"; + case Opcodes.DDIV: + return "ddiv"; + case Opcodes.IREM: + return "irem"; + case Opcodes.LREM: + return "lrem"; + case Opcodes.FREM: + return "frem"; + case Opcodes.DREM: + return "drem"; + case Opcodes.INEG: + return "ineg"; + case Opcodes.LNEG: + return "lneg"; + case Opcodes.FNEG: + return "fneg"; + case Opcodes.DNEG: + return "dneg"; + case Opcodes.ISHL: + return "ishl"; + case Opcodes.LSHL: + return "lshl"; + case Opcodes.ISHR: + return "ishr"; + case Opcodes.LSHR: + return "lshr"; + case Opcodes.IUSHR: + return "iushr"; + case Opcodes.LUSHR: + return "lushr"; + case Opcodes.IAND: + return "iand"; + case Opcodes.LAND: + return "land"; + case Opcodes.IOR: + return "ior"; + case Opcodes.LOR: + return "lor"; + case Opcodes.IXOR: + return "ixor"; + case Opcodes.LXOR: + return "lxor"; + case Opcodes.IINC: + return "iinc"; + case Opcodes.I2L: + return "i2l"; + case Opcodes.I2F: + return "i2f"; + case Opcodes.I2D: + return "i2d"; + case Opcodes.L2I: + return "l2i"; + case Opcodes.L2F: + return "l2f"; + case Opcodes.L2D: + return "l2d"; + case Opcodes.F2I: + return "f2i"; + case Opcodes.F2L: + return "f2l"; + case Opcodes.F2D: + return "f2d"; + case Opcodes.D2I: + return "d2i"; + case Opcodes.D2L: + return "d2l"; + case Opcodes.D2F: + return "d2f"; + case Opcodes.I2B: + return "i2b"; + case Opcodes.I2C: + return "i2c"; + case Opcodes.I2S: + return "i2s"; + case Opcodes.LCMP: + return "lcmp"; + case Opcodes.FCMPL: + return "fcmpl"; + case Opcodes.FCMPG: + return "fcmpg"; + case Opcodes.DCMPL: + return "dcmpl"; + case Opcodes.DCMPG: + return "dcmpg"; + case Opcodes.IFEQ: + return "ifeq"; + case Opcodes.IFNE: + return "ifne"; + case Opcodes.IFLT: + return "iflt"; + case Opcodes.IFGE: + return "ifge"; + case Opcodes.IFGT: + return "ifgt"; + case Opcodes.IFLE: + return "ifle"; + case Opcodes.IF_ICMPEQ: + return "if_icmpeq"; + case Opcodes.IF_ICMPNE: + return "if_icmpne"; + case Opcodes.IF_ICMPLT: + return "if_icmplt"; + case Opcodes.IF_ICMPGE: + return "if_icmpge"; + case Opcodes.IF_ICMPGT: + return "if_icmpgt"; + case Opcodes.IF_ICMPLE: + return "if_icmple"; + case Opcodes.IF_ACMPEQ: + return "if_acmpeq"; + case Opcodes.IF_ACMPNE: + return "if_acmpne"; + case Opcodes.GOTO: + return "goto"; + case Opcodes.JSR: + return "jsr"; + case Opcodes.RET: + return "ret"; + case Opcodes.TABLESWITCH: + return "tableswitch"; + case Opcodes.LOOKUPSWITCH: + return "lookupswitch"; + case Opcodes.IRETURN: + return "ireturn"; + case Opcodes.LRETURN: + return "lreturn"; + case Opcodes.FRETURN: + return "freturn"; + case Opcodes.DRETURN: + return "dreturn"; + case Opcodes.ARETURN: + return "areturn"; + case Opcodes.RETURN: + return "return"; + case Opcodes.GETSTATIC: + return "getstatic"; + case Opcodes.PUTSTATIC: + return "putstatic"; + case Opcodes.GETFIELD: + return "getfield"; + case Opcodes.PUTFIELD: + return "putfield"; + case Opcodes.INVOKEVIRTUAL: + return "invokevirtual"; + case Opcodes.INVOKESPECIAL: + return "invokespecial"; + case Opcodes.INVOKESTATIC: + return "invokestatic"; + case Opcodes.INVOKEINTERFACE: + return "invokeinterface"; + case Opcodes.INVOKEDYNAMIC: + return "invokedynamic"; + case Opcodes.NEW: + return "new"; + case Opcodes.NEWARRAY: + return "newarray"; + case Opcodes.ANEWARRAY: + return "anewarray"; + case Opcodes.ARRAYLENGTH: + return "arraylength"; + case Opcodes.ATHROW: + return "athrow"; + case Opcodes.CHECKCAST: + return "checkcast"; + case Opcodes.INSTANCEOF: + return "instanceof"; + case Opcodes.MONITORENTER: + return "monitorenter"; + case Opcodes.MONITOREXIT: + return "monitorexit"; + case Opcodes.MULTIANEWARRAY: + return "multianewarray"; + case Opcodes.IFNULL: + return "ifnull"; + case Opcodes.IFNONNULL: + return "ifnonnull"; + case -1: + return "debugging"; + } + throw new IllegalArgumentException("Unknown opcode"); } } diff --git a/src/main/java/me/itzsomebody/radon/utils/FileUtils.java b/src/main/java/me/itzsomebody/radon/utils/FileUtils.java index ac52e8bc..fd43fded 100644 --- a/src/main/java/me/itzsomebody/radon/utils/FileUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/FileUtils.java @@ -37,11 +37,9 @@ public class FileUtils { */ public static String renameExistingFile(File existing) { int i = 0; - while (true) { i++; - String newName = existing.getAbsolutePath() + ".BACKUP-" - + String.valueOf(i); + String newName = existing.getAbsolutePath() + ".BACKUP-" + i; File backUpName = new File(newName); if (!backUpName.exists()) { existing.renameTo(backUpName); @@ -49,7 +47,6 @@ public static String renameExistingFile(File existing) { return newName; } } - } /** @@ -59,16 +56,13 @@ public static String renameExistingFile(File existing) { * @return a byte array from the inputted */ public static byte[] toByteArray(InputStream in) { - try { - ByteArrayOutputStream out = new ByteArrayOutputStream(); + try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { byte[] buffer = new byte[1024]; while (in.available() > 0) { int data = in.read(buffer); out.write(buffer, 0, data); } - in.close(); - out.close(); return out.toByteArray(); } catch (IOException ioe) { ioe.printStackTrace(); diff --git a/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java b/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java index 7059a896..8bf09430 100644 --- a/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java @@ -35,7 +35,7 @@ public class LoggerUtils { /** * The {@link SimpleDateFormat} that will be used for logging. */ - private static SimpleDateFormat FORMAT + private final static SimpleDateFormat FORMAT = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss"); /** diff --git a/src/main/java/me/itzsomebody/radon/utils/CustomRegexUtils.java b/src/main/java/me/itzsomebody/radon/utils/MatchUtils.java similarity index 69% rename from src/main/java/me/itzsomebody/radon/utils/CustomRegexUtils.java rename to src/main/java/me/itzsomebody/radon/utils/MatchUtils.java index efcc96d6..bf6b3452 100644 --- a/src/main/java/me/itzsomebody/radon/utils/CustomRegexUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/MatchUtils.java @@ -22,18 +22,17 @@ * * @author ItzSomebody */ -public class CustomRegexUtils { +public class MatchUtils { /** * Returns true/false based on if input is matched to this specific rule. * - * @param customregex a {@link String} which is used as a "custom regex" - * statement. - * @param string a {@link String} to try to match. + * @param pattern a {@link String} which is used as a pattern matching statement. + * This includes wildcard '*' support. + * @param string a {@link String} to try to match. * @return true/false based on if input is matched to this specific rule. */ - public static boolean isMatched(String customregex, String string) { - return (customregex.equals(string) - || (customregex.contains("*") - && string.contains(customregex.split("\\*")[0]))); + public static boolean isMatched(String pattern, String string) { + return (pattern.equals(string) || + (pattern.contains("*") && string.contains(pattern.split("\\*")[0]))); } } diff --git a/src/main/java/me/itzsomebody/radon/utils/OpcodeUtils.java b/src/main/java/me/itzsomebody/radon/utils/OpcodeUtils.java deleted file mode 100644 index f7736ea8..00000000 --- a/src/main/java/me/itzsomebody/radon/utils/OpcodeUtils.java +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.utils; - -import org.objectweb.asm.Opcodes; - -/** - * Contains one utility which maps opcodes to strings for legibility. - * - * @author ItzSomebody - */ -public class OpcodeUtils implements Opcodes { - /** - * Returns a {@link String} representation of inputted opcode. - * - * @param opcode the opcode to get a name from. - * @return a {@link String} representation of inputted opcode. - */ - public static String getOpcodeName(int opcode) { - switch (opcode) { - case NOP: - return "nop"; - case ACONST_NULL: - return "aconst_null"; - case ICONST_M1: - return "iconst_m1"; - case ICONST_0: - return "iconst_0"; - case ICONST_1: - return "iconst_1"; - case ICONST_2: - return "iconst_2"; - case ICONST_3: - return "iconst_3"; - case ICONST_4: - return "iconst_4"; - case ICONST_5: - return "iconst_5"; - case LCONST_0: - return "lconst_0"; - case LCONST_1: - return "lconst_1"; - case FCONST_0: - return "fconst_0"; - case FCONST_1: - return "fconst_1"; - case FCONST_2: - return "fconst_2"; - case DCONST_0: - return "dconst_0"; - case DCONST_1: - return "dconst_1"; - case BIPUSH: - return "bipush"; - case SIPUSH: - return "sipush"; - case LDC: - return "ldc"; - case ILOAD: - return "iload"; - case LLOAD: - return "lload"; - case FLOAD: - return "fload"; - case DLOAD: - return "dload"; - case ALOAD: - return "aload"; - case IALOAD: - return "iaload"; - case LALOAD: - return "laload"; - case FALOAD: - return "faload"; - case DALOAD: - return "daload"; - case AALOAD: - return "aaload"; - case BALOAD: - return "baload"; - case CALOAD: - return "caload"; - case SALOAD: - return "saload"; - case ISTORE: - return "istore"; - case LSTORE: - return "lstore"; - case FSTORE: - return "fstore"; - case DSTORE: - return "dstore"; - case ASTORE: - return "astore"; - case IASTORE: - return "iastore"; - case LASTORE: - return "lastore"; - case FASTORE: - return "fastore"; - case DASTORE: - return "dastore"; - case AASTORE: - return "aastore"; - case BASTORE: - return "bastore"; - case CASTORE: - return "castore"; - case SASTORE: - return "sastore"; - case POP: - return "pop"; - case POP2: - return "pop2"; - case DUP: - return "dup"; - case DUP_X1: - return "dup_x1"; - case DUP_X2: - return "dup_x2"; - case DUP2: - return "dup2"; - case DUP2_X1: - return "dup2_x1"; - case DUP2_X2: - return "dup2_x2"; - case SWAP: - return "swap"; - case IADD: - return "iadd"; - case LADD: - return "ladd"; - case FADD: - return "fadd"; - case DADD: - return "dadd"; - case ISUB: - return "isub"; - case LSUB: - return "lsub"; - case FSUB: - return "fsub"; - case DSUB: - return "dsub"; - case IMUL: - return "imul"; - case LMUL: - return "lmul"; - case FMUL: - return "fmul"; - case DMUL: - return "dmul"; - case IDIV: - return "idiv"; - case LDIV: - return "ldiv"; - case FDIV: - return "fdiv"; - case DDIV: - return "ddiv"; - case IREM: - return "irem"; - case LREM: - return "lrem"; - case FREM: - return "frem"; - case DREM: - return "drem"; - case INEG: - return "ineg"; - case LNEG: - return "lneg"; - case FNEG: - return "fneg"; - case DNEG: - return "dneg"; - case ISHL: - return "ishl"; - case LSHL: - return "lshl"; - case ISHR: - return "ishr"; - case LSHR: - return "lshr"; - case IUSHR: - return "iushr"; - case LUSHR: - return "lushr"; - case IAND: - return "iand"; - case LAND: - return "land"; - case IOR: - return "ior"; - case LOR: - return "lor"; - case IXOR: - return "ixor"; - case LXOR: - return "lxor"; - case IINC: - return "iinc"; - case I2L: - return "i2l"; - case I2F: - return "i2f"; - case I2D: - return "i2d"; - case L2I: - return "l2i"; - case L2F: - return "l2f"; - case L2D: - return "l2d"; - case F2I: - return "f2i"; - case F2L: - return "f2l"; - case F2D: - return "f2d"; - case D2I: - return "d2i"; - case D2L: - return "d2l"; - case D2F: - return "d2f"; - case I2B: - return "i2b"; - case I2C: - return "i2c"; - case I2S: - return "i2s"; - case LCMP: - return "lcmp"; - case FCMPL: - return "fcmpl"; - case FCMPG: - return "fcmpg"; - case DCMPL: - return "dcmpl"; - case DCMPG: - return "dcmpg"; - case IFEQ: - return "ifeq"; - case IFNE: - return "ifne"; - case IFLT: - return "iflt"; - case IFGE: - return "ifge"; - case IFGT: - return "ifgt"; - case IFLE: - return "ifle"; - case IF_ICMPEQ: - return "if_icmpeq"; - case IF_ICMPNE: - return "if_icmpne"; - case IF_ICMPLT: - return "if_icmplt"; - case IF_ICMPGE: - return "if_icmpge"; - case IF_ICMPGT: - return "if_icmpgt"; - case IF_ICMPLE: - return "if_icmple"; - case IF_ACMPEQ: - return "if_acmpeq"; - case IF_ACMPNE: - return "if_acmpne"; - case GOTO: - return "goto"; - case JSR: - return "jsr"; - case RET: - return "ret"; - case TABLESWITCH: - return "tableswitch"; - case LOOKUPSWITCH: - return "lookupswitch"; - case IRETURN: - return "ireturn"; - case LRETURN: - return "lreturn"; - case FRETURN: - return "freturn"; - case DRETURN: - return "dreturn"; - case ARETURN: - return "areturn"; - case RETURN: - return "return"; - case GETSTATIC: - return "getstatic"; - case PUTSTATIC: - return "putstatic"; - case GETFIELD: - return "getfield"; - case PUTFIELD: - return "putfield"; - case INVOKEVIRTUAL: - return "invokevirtual"; - case INVOKESPECIAL: - return "invokespecial"; - case INVOKESTATIC: - return "invokestatic"; - case INVOKEINTERFACE: - return "invokeinterface"; - case INVOKEDYNAMIC: - return "invokedynamic"; - case NEW: - return "new"; - case NEWARRAY: - return "newarray"; - case ANEWARRAY: - return "anewarray"; - case ARRAYLENGTH: - return "arraylength"; - case ATHROW: - return "athrow"; - case CHECKCAST: - return "checkcast"; - case INSTANCEOF: - return "instanceof"; - case MONITORENTER: - return "monitorenter"; - case MONITOREXIT: - return "monitorexit"; - case MULTIANEWARRAY: - return "multianewarray"; - case IFNULL: - return "ifnull"; - case IFNONNULL: - return "ifnonnull"; - case -1: - return "debugging"; - } - - throw new IllegalArgumentException("Unknown opcode"); - } -} diff --git a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java index 50f16941..cc3f9284 100644 --- a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java @@ -25,7 +25,7 @@ import java.util.List; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; -import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; + import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; @@ -36,21 +36,30 @@ * @author ItzSomebody */ public class StringUtils { + private final static char[] DICT_ALPHA_NUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".toCharArray(); + private final static char[] DICT_SPACES = new char[]{ + '\u2000', '\u2001', '\u2002', '\u2003', '\u2004', '\u2005', '\u2006', '\u2007', '\u2008', '\u2009', '\u200A', '\u200B', '\u200C', '\u200D', '\u200E', '\u200F' + }; + private final static char[] DICT_MISC = new char[]{ + '\ua6ac', '\ua6ea', '\ua6ba', '\ua6a3', '\ua6a4', '\ua6b5', '\ua6b0', '\ua6a8' + }; + /** * Returns the proper string generation type given a dictionary type to use. * * @param dictionary an integer indicating which pre-defined string * generation type to use. + * @param len Length of the string to generate. * @return the proper string generation type given a dictionary type to use. */ - public static String randomString(int dictionary) { + public static String randomString(int dictionary, int len) { switch (dictionary) { case 0: - return crazyString(); + return crazyString(len); case 1: - return crazyKey(); + return crazyKey(len); case 2: - return alphaNumString(); + return alphaNumString(len); default: throw new IllegalArgumentException("Illegal dictionary type " + dictionary); } @@ -59,125 +68,44 @@ public static String randomString(int dictionary) { /** * Generates and returns a pseudo-random alpha-numeric string. * + * @param len Length of the string to generate. * @return a pseudo-random alpha-numeric string. */ - public static String alphaNumString() { - int numberOfChars = 4; - char[] alphaNum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".toCharArray(); - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < numberOfChars; i++) { - sb.append(alphaNum[NumberUtils.getRandomInt(alphaNum.length)]); + public static String alphaNumString(int len) { + char[] buildString = new char[len]; + for (int i = 0; i < len; i++) { + buildString[i] = DICT_ALPHA_NUM[NumberUtils.getRandomInt(DICT_ALPHA_NUM.length)]; } - - return sb.toString(); + return new String(buildString); } /** - * Generates a {@link String} with a length of 10 consisting of spaces. + * Generates a {@link String} consisting only of DICT_SPACES. * Stole this idea from NeonObf and Smoke. * - * @return a built {@link String} consisting of spaces. + * @param len Length of the string to generate. + * @return a built {@link String} consisting of DICT_SPACES. */ - public static String crazyString() { - int numberOfChars = 10; // Just so I can do a quick switch. - char[] buildString = new char[numberOfChars]; - - for (int i = 0; i < numberOfChars; i++) { - switch (NumberUtils.getRandomInt(16)) { - case 0: - buildString[i] = '\u2000'; - break; - case 1: - buildString[i] = '\u2001'; - break; - case 2: - buildString[i] = '\u2002'; - break; - case 3: - buildString[i] = '\u2003'; - break; - case 4: - buildString[i] = '\u2004'; - break; - case 5: - buildString[i] = '\u2005'; - break; - case 6: - buildString[i] = '\u2006'; - break; - case 7: - buildString[i] = '\u2007'; - break; - case 8: - buildString[i] = '\u2008'; - break; - case 9: - buildString[i] = '\u2009'; - break; - case 10: - buildString[i] = '\u200A'; - break; - case 11: - buildString[i] = '\u200B'; - break; - case 12: - buildString[i] = '\u200C'; - break; - case 13: - buildString[i] = '\u200D'; - break; - case 14: - buildString[i] = '\u200E'; - break; - case 15: - buildString[i] = '\u200F'; - break; - } + public static String crazyString(int len) { + char[] buildString = new char[len]; + for (int i = 0; i < len; i++) { + buildString[i] = DICT_SPACES[NumberUtils.getRandomInt(DICT_SPACES.length)]; } - return new String(buildString); } /** * Alternative generator to the method above. * + * @param len Length of the string to generate. * @return a {@link String} consisting of characters the JVM doesn't * recognize. */ - public static String crazyKey() { - int numberOfChars = 10; // Just so I can do a quick switch. - char[] buildString = new char[numberOfChars]; - - for (int i = 0; i < numberOfChars; i++) { - switch (NumberUtils.getRandomInt(8)) { - case 0: - buildString[i] = '\ua6ac'; - break; - case 1: - buildString[i] = '\ua6ea'; - break; - case 2: - buildString[i] = '\ua6ba'; - break; - case 3: - buildString[i] = '\ua6a3'; - break; - case 4: - buildString[i] = '\ua6a4'; - break; - case 5: - buildString[i] = '\ua6b5'; - break; - case 6: - buildString[i] = '\ua6b0'; - break; - case 7: - buildString[i] = '\ua6a8'; - break; - } + public static String crazyKey(int len) { + char[] buildString = new char[len]; + for (int i = 0; i < len; i++) { + buildString[i] = DICT_MISC[NumberUtils.getRandomInt(DICT_MISC.length)]; } - return new String(buildString); } @@ -277,7 +205,7 @@ public static String aesDecrypt(String strToDecrypt, String secret) { * * @return a generated classname based on current class packages. */ - public static String randomClassName(Collection theClassNames, int dictionary) { + public static String randomClassName(Collection theClassNames, int dictionary, int len) { List classNames = new ArrayList<>(theClassNames); String randomClass = classNames.get(NumberUtils. @@ -290,7 +218,7 @@ public static String randomClassName(Collection theClassNames, int dicti sb.append("/"); } - sb.append(StringUtils.randomString(dictionary)); + sb.append(StringUtils.randomString(dictionary, len)); return new String(sb); } From 9b92d4dc15ec0d3440ed6224a82b76acad02afa8 Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 19:16:06 -0400 Subject: [PATCH 045/281] Add TODO note for fix for #18 --- .../java/me/itzsomebody/radon/transformers/renamer/Renamer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java index 0b656d28..48a752df 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java @@ -138,6 +138,7 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("Attempting to map class names in resources")); AtomicInteger fixed = new AtomicInteger(); getPassThru().forEach((name, byteArray) -> { + // TODO: If the class name is "Main" (in default package) then this breaks the manifest. if (name.equals("META-INF/MANIFEST.MF") || (name.equals("plugin.yml") && spigotMode)) { String stringVer = new String(byteArray); From cc2b310dbb63f7b6475ebf7bbc04bd15e44a4d4c Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 20:58:21 -0400 Subject: [PATCH 046/281] Update transformers: Add variable for name generation length Remove duplicate code where possible --- .../me/itzsomebody/radon/config/Config.java | 12 +- .../itzsomebody/radon/config/ConfigEnum.java | 2 +- .../me/itzsomebody/radon/gui/MainGUI.java | 10 +- .../itzsomebody/radon/internal/Bootstrap.java | 4 +- ...SM.java => InvokeDynamicBSMGenerator.java} | 2 +- ...on.java => StringEncryptionGenerator.java} | 10 +- .../flow/HeavyFlowObfuscation.java | 4 +- .../flow/LightFlowObfuscation.java | 6 +- .../flow/NormalFlowObfuscation.java | 4 +- .../invokedynamic/HeavyInvokeDynamic.java | 13 +- .../invokedynamic/LightInvokeDynamic.java | 37 ++--- .../invokedynamic/NormalInvokeDynamic.java | 132 +----------------- .../ObfuscateLocalVariables.java | 6 +- .../radon/transformers/misc/Crasher.java | 6 +- .../radon/transformers/misc/StringPool.java | 8 +- .../radon/transformers/misc/TrashClasses.java | 26 ++-- .../radon/transformers/renamer/Renamer.java | 11 +- .../sourcedebug/ObfuscateSourceDebug.java | 6 +- .../sourcename/ObfuscateSourceName.java | 6 +- .../HeavyStringEncryption.java | 94 +++++++------ .../LightStringEncryption.java | 87 +++--------- .../NormalStringEncryption.java | 95 ++++--------- ...on.java => VeryLightStringEncryption.java} | 86 +++++++----- .../itzsomebody/radon/utils/StringUtils.java | 6 +- 24 files changed, 265 insertions(+), 408 deletions(-) rename src/main/java/me/itzsomebody/radon/methods/{InvokeDynamicBSM.java => InvokeDynamicBSMGenerator.java} (99%) rename src/main/java/me/itzsomebody/radon/methods/{StringEncryption.java => StringEncryptionGenerator.java} (98%) rename src/main/java/me/itzsomebody/radon/transformers/stringencryption/{SuperLightStringEncryption.java => VeryLightStringEncryption.java} (56%) diff --git a/src/main/java/me/itzsomebody/radon/config/Config.java b/src/main/java/me/itzsomebody/radon/config/Config.java index ab69a0ee..b7056342 100644 --- a/src/main/java/me/itzsomebody/radon/config/Config.java +++ b/src/main/java/me/itzsomebody/radon/config/Config.java @@ -51,7 +51,7 @@ import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; +import me.itzsomebody.radon.transformers.stringencryption.VeryLightStringEncryption; import org.yaml.snakeyaml.Yaml; /** @@ -333,8 +333,8 @@ public void sortExempts() throws IllegalArgumentException { this.methodExempts.add(exempt.replace("Method: ", "")); } else if (exempt.startsWith("Field: ")) { this.fieldExempts.add(exempt.replace("Field: ", "")); - } else if (exempt.startsWith("StringEncryption: ")) { - this.stringEncExempts.add(exempt.replace("StringEncryption: ", "")); + } else if (exempt.startsWith("StringEncryptionGenerator: ")) { + this.stringEncExempts.add(exempt.replace("StringEncryptionGenerator: ", "")); } else if (exempt.startsWith("InvokeDynamic: ")) { this.indyExempts.add(exempt.replace("InvokeDynamic: ", "")); } else if (exempt.startsWith("Flow: ")) { @@ -391,15 +391,15 @@ public List getExempts() { */ public AbstractTransformer getStringEncryptionType() throws IllegalArgumentException { - if (this.map.containsKey("StringEncryption")) { - Object value = this.map.get("StringEncryption"); + if (this.map.containsKey("StringEncryptionGenerator")) { + Object value = this.map.get("StringEncryptionGenerator"); if (value != null) { if (!(value instanceof String)) throw new IllegalArgumentException("String encryption arg" + " must be a string"); String s = (String) value; if (s.equalsIgnoreCase("SuperLight")) { - return new SuperLightStringEncryption(this.getSpigotBool()); + return new VeryLightStringEncryption(this.getSpigotBool()); } else if (s.equalsIgnoreCase("Light")) { return new LightStringEncryption(this.getSpigotBool()); } else if (s.equalsIgnoreCase("Normal")) { diff --git a/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java b/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java index e5653ccf..4120a235 100644 --- a/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java +++ b/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java @@ -27,7 +27,7 @@ public enum ConfigEnum { OUTPUT("Output"), LIBRARIES("Libraries"), EXEMPTS("Exempts"), - STRING_ENCRYPTION("StringEncryption"), + STRING_ENCRYPTION("StringEncryptionGenerator"), FLOW_OBFUSCATION("FlowObfuscation"), INVOKEDYNAMIC("InvokeDynamic"), LOCAL_VARIABLES("LocalVariableObfuscation"), diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java index 6ade9d0d..f1744e27 100644 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java @@ -59,7 +59,7 @@ import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; +import me.itzsomebody.radon.transformers.stringencryption.VeryLightStringEncryption; import me.itzsomebody.radon.utils.WatermarkUtils; @@ -959,7 +959,7 @@ private void initialize() { gbc_comboBox_04.fill = GridBagConstraints.HORIZONTAL; gbc_comboBox_04.gridx = 1; gbc_comboBox_04.gridy = 12; - String[] options = {"Class", "Method", "Field", "StringEncryption", "InvokeDynamic", + String[] options = {"Class", "Method", "Field", "StringEncryptionGenerator", "InvokeDynamic", "Flow", "LocalVars", "SourceName", "SourceDebug", "LineNumbers", "StringPool", "Crasher", "HideCode", "Numbers", "Shuffler", "InnerClasses", "Renamer", "Expiry"}; @@ -1009,7 +1009,7 @@ private void initialize() { exemptList.addElement("Field: " + exemptField.getText()); exemptField.setText(""); } else if (comboBox_04.getSelectedIndex() == 3) { - exemptList.addElement("StringEncryption: " + exemptField.getText()); + exemptList.addElement("StringEncryptionGenerator: " + exemptField.getText()); exemptField.setText(""); } else if (comboBox_04.getSelectedIndex() == 4) { exemptList.addElement("InvokeDynamic: " + exemptField.getText()); @@ -1245,7 +1245,7 @@ protected Object doInBackground() { if (chckbxStringEncryption.isSelected()) { switch (comboBox.getSelectedIndex()) { case 0: - transformers.add(new SuperLightStringEncryption(spigotMode)); + transformers.add(new VeryLightStringEncryption(spigotMode)); break; case 1: transformers.add(new LightStringEncryption(spigotMode)); @@ -1426,7 +1426,7 @@ protected Object doInBackground() { if (stringEncryptionMode == null) { chckbxStringEncryption.setSelected(false); } else if (stringEncryptionMode - instanceof SuperLightStringEncryption) { + instanceof VeryLightStringEncryption) { chckbxStringEncryption.setSelected(true); comboBox.setSelectedIndex(0); comboBox.setEnabled(true); diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index db413c49..336e97cc 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -231,9 +231,11 @@ public void startTheParty(boolean doInit) throws Throwable { if (this.trashClasses != -1) { this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); + // TODO: make this variable a config option + int len = 4; for (int i = 0; i < this.trashClasses; i++) { TrashClasses trashClass = - new TrashClasses(StringUtils.randomClassName(this.classes.keySet(), this.dictionary)); + new TrashClasses(StringUtils.randomClassName(this.classes.keySet(), this.dictionary, len)); ClassNode classNode = trashClass.returnTrashClass(); this.extraClasses.put(classNode.name, classNode); } diff --git a/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSM.java b/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSMGenerator.java similarity index 99% rename from src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSM.java rename to src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSMGenerator.java index f9be7e34..82a27f93 100644 --- a/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSM.java +++ b/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSMGenerator.java @@ -33,7 +33,7 @@ * @author ItzSomebody * @author ASMifier by OW2 */ -public class InvokeDynamicBSM implements Opcodes { +public class InvokeDynamicBSMGenerator implements Opcodes { /** * Returns a {@link MethodNode} that returns a {@link ConstantCallSite} * statically linked to a method for {@link LightInvokeDynamic}. diff --git a/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java b/src/main/java/me/itzsomebody/radon/methods/StringEncryptionGenerator.java similarity index 98% rename from src/main/java/me/itzsomebody/radon/methods/StringEncryption.java rename to src/main/java/me/itzsomebody/radon/methods/StringEncryptionGenerator.java index 2118f5ae..8a8a8575 100644 --- a/src/main/java/me/itzsomebody/radon/methods/StringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/methods/StringEncryptionGenerator.java @@ -19,27 +19,27 @@ import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; +import me.itzsomebody.radon.transformers.stringencryption.VeryLightStringEncryption; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.MethodNode; /** * Class containing {@link MethodNode}s needed to decrypt a {@link String} for the - * appropriate StringEncryption transformer. + * appropriate StringEncryptionGenerator transformer. * * @author ItzSomebody * @author ASMifier by OW2 */ -public class StringEncryption implements Opcodes { +public class StringEncryptionGenerator implements Opcodes { /** * Returns a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link SuperLightStringEncryption}. + * decrypt strings encrypted by {@link VeryLightStringEncryption}. * * @param decryptionMethodName used to determine the name of the * generated {@link MethodNode}. * @return a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link SuperLightStringEncryption}. + * decrypt strings encrypted by {@link VeryLightStringEncryption}. */ public static MethodNode superLightMethod(String decryptionMethodName) { MethodNode mv = new MethodNode(ACC_PUBLIC + ACC_STATIC diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java index e1e97513..287aea4a 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java @@ -42,7 +42,7 @@ * * @author ItzSomebody */ -public class HeavyFlowObfuscation extends AbstractTransformer { +public class HeavyFlowObfuscation extends LightFlowObfuscation { /** * Applies obfuscation. */ @@ -53,7 +53,7 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("Started heavy flow obfuscation transformer")); classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { FieldNode field = new FieldNode(ACC_PUBLIC + ACC_STATIC + - ACC_FINAL, StringUtils.randomString(this.dictionary), "Z", null, null); + ACC_FINAL, StringUtils.randomString(this.dictionary, len), "Z", null, null); classNode.fields.add(field); classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Flow") diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java index e9db589f..ae884b38 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java @@ -40,6 +40,10 @@ * @author ItzSomebody */ public class LightFlowObfuscation extends AbstractTransformer { + /** + * Length of names to generate. + */ + protected int len = 10; /** * Applies obfuscation. */ @@ -49,7 +53,7 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started light flow obfuscation transformer.")); classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { - String fieldName = StringUtils.randomString(this.dictionary); + String fieldName = StringUtils.randomString(this.dictionary, len); classNode.methods.stream().filter(methodNode -> hasInstructions(methodNode) && !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Flow") && BytecodeUtils.containsGoto(methodNode)).forEach(methodNode -> { diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java index 1899039c..f73e712a 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java @@ -43,7 +43,7 @@ * * @author ItzSomebody */ -public class NormalFlowObfuscation extends AbstractTransformer { +public class NormalFlowObfuscation extends LightFlowObfuscation { /** * Applies obfuscation. */ @@ -54,7 +54,7 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("Started normal flow obfuscation transformer")); classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { FieldNode field = new FieldNode(ACC_PUBLIC + ACC_STATIC + - ACC_FINAL, StringUtils.randomString(this.dictionary), "Z", null, null); + ACC_FINAL, StringUtils.randomString(this.dictionary, len), "Z", null, null); classNode.fields.add(field); classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Flow") diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java index b2661b20..2f3a8785 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java @@ -39,16 +39,15 @@ * * @author ItzSomebody. */ -public class HeavyInvokeDynamic extends AbstractTransformer { +public class HeavyInvokeDynamic extends LightInvokeDynamic { /** * Applies obfuscation. */ + @Override public void obfuscate() { AtomicInteger counter = new AtomicInteger(); long current = System.currentTimeMillis(); - MemberNames memberNames = new MemberNames(this); - ArrayList finals = new ArrayList<>(); this.classNodes().forEach(classNode -> classNode.fields.stream().filter(fieldNode -> Modifier.isFinal(fieldNode.access)).forEach(fieldNode -> @@ -203,10 +202,10 @@ public class MemberNames { public String searchMethodName; MemberNames(HeavyInvokeDynamic instance) { - this.className = StringUtils.randomClassName(instance.classNames(), instance.dictionary); - this.decryptorMethodName = StringUtils.randomString(instance.dictionary); - this.bootstrapMethodName = StringUtils.randomString(instance.dictionary); - this.searchMethodName = StringUtils.randomString(instance.dictionary); + this.className = StringUtils.randomClassName(instance.classNames(), instance.dictionary, len); + this.decryptorMethodName = StringUtils.randomString(instance.dictionary, len); + this.bootstrapMethodName = StringUtils.randomString(instance.dictionary, len); + this.searchMethodName = StringUtils.randomString(instance.dictionary, len); } } } \ No newline at end of file diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java index f80b1dd6..9f7f716d 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java @@ -18,7 +18,8 @@ package me.itzsomebody.radon.transformers.invokedynamic; import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.methods.InvokeDynamicBSM; + +import me.itzsomebody.radon.methods.InvokeDynamicBSMGenerator; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; @@ -26,10 +27,7 @@ import org.objectweb.asm.Handle; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.InvokeDynamicInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.TypeInsnNode; +import org.objectweb.asm.tree.*; /** * Transformer that applies an InvokeDynamic obfuscation which @@ -42,8 +40,12 @@ public class LightInvokeDynamic extends AbstractTransformer { /* * Magic numbers */ - private int VIRTUAL_INVOCATION = 1; - private int STATIC_INVOCATION = 0; + public static final int VIRTUAL_INVOCATION = 1; + public static final int STATIC_INVOCATION = 0; + /** + * Length of names to generate. + */ + protected int len = 10; /** * Applies obfuscation. @@ -52,8 +54,8 @@ public void obfuscate() { AtomicInteger counter = new AtomicInteger(); long current = System.currentTimeMillis(); this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started light invokedynamic transformer")); - String[] bsmPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary)}; + this.logStrings.add(LoggerUtils.stdOut("Started invokedynamic transformer")); + String[] bsmPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary, len)}; Handle bsmHandle = new Handle(Opcodes.H_INVOKESTATIC, bsmPath[0], bsmPath[1], @@ -61,7 +63,6 @@ public void obfuscate() { "Ljava/lang/Object;Ljava/lang/Object;" + "Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "InvokeDynamic") && classNode.version >= 51).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> @@ -79,7 +80,7 @@ && hasInstructions(methodNode)).forEach(methodNode -> { Type returnType = Type.getReturnType(methodInsnNode.desc); int opcode = (isStatic) ? this.STATIC_INVOCATION : this.VIRTUAL_INVOCATION; - InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode(StringUtils.randomString(this.dictionary), + InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode(StringUtils.randomString(this.dictionary, len), newSig, bsmHandle, opcode, @@ -95,15 +96,19 @@ && hasInstructions(methodNode)).forEach(methodNode -> { } }); }); - - this.classNodes().stream().filter(classNode -> classNode.name.equals(bsmPath[0])).forEach(classNode -> { - classNode.methods.add(InvokeDynamicBSM.lightBSM(bsmPath[1], classNode.name)); - classNode.access = BytecodeUtils.makePublic(classNode.access); - }); + // Add BSM method + ClassNode bsmHost = getClassMap().get(bsmPath[0]); + addBSM(bsmHost, bsmPath[1]); + // Do logging this.logStrings.add(LoggerUtils.stdOut("Replaced " + counter + " method invocations with invokedynamics.")); this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); } + protected void addBSM(ClassNode bsmHost, String methodName) { + bsmHost.methods.add(InvokeDynamicBSMGenerator.lightBSM(methodName, bsmHost.name)); + bsmHost.access = BytecodeUtils.makePublic(bsmHost.access); + } + /** * Returns string with a simple encryption. * diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java index aaf2fdc7..e0acb563 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java @@ -17,19 +17,9 @@ package me.itzsomebody.radon.transformers.invokedynamic; -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.methods.InvokeDynamicBSM; -import me.itzsomebody.radon.transformers.AbstractTransformer; +import me.itzsomebody.radon.methods.InvokeDynamicBSMGenerator; import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.Handle; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.InvokeDynamicInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.TypeInsnNode; +import org.objectweb.asm.tree.*; /** * Transformer that applies an InvokeDynamic which attempts to prevent @@ -39,118 +29,10 @@ * @author ItzSomebody * @author Licel (transformer based on IndyProtector) */ -public class NormalInvokeDynamic extends AbstractTransformer { - /* - * Magic numbers - */ - private int VIRTUAL_INVOCATION = 1; - private int STATIC_INVOCATION = 0; - - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started normal invokedynamic transformer")); - String[] bsmPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary)}; - Handle bsmHandle = new Handle(Opcodes.H_INVOKESTATIC, - bsmPath[0], - bsmPath[1], - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", - false); - - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "InvokeDynamic") - && classNode.version >= 51).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "InvokeDynamic") - && hasInstructions(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (this.methodSize(methodNode) > 60000) break; - if (insn instanceof MethodInsnNode - && insn.getOpcode() != INVOKESPECIAL) { - MethodInsnNode methodInsnNode = (MethodInsnNode) insn; - boolean isStatic = (methodInsnNode.getOpcode() == Opcodes.INVOKESTATIC); - - String newSig = - isStatic ? methodInsnNode.desc : methodInsnNode.desc.replace("(", "(Ljava/lang/Object;"); - Type returnType = Type.getReturnType(methodInsnNode.desc); - int opcode = (isStatic) ? this.STATIC_INVOCATION : this.VIRTUAL_INVOCATION; - - InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode( - StringUtils.randomString(this.dictionary), - newSig, - bsmHandle, - opcode, - encryptOwner(methodInsnNode.owner.replaceAll("/", ".")), - encryptName(methodInsnNode.name), - encryptDesc(methodInsnNode.desc)); - methodNode.instructions.set(insn, indy); - if (returnType.getSort() == Type.ARRAY) { - methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); - } - counter.incrementAndGet(); - } - } - }); - }); - - this.classNodes().stream().filter(classNode -> classNode.name.equals(bsmPath[0])).forEach(classNode -> { - classNode.methods.add(InvokeDynamicBSM.normalBSM(bsmPath[1], classNode.name)); - classNode.access = BytecodeUtils.makePublic(classNode.access); - }); - this.logStrings.add(LoggerUtils.stdOut("Replaced " + counter + " method invocations with invokedynamics.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } - - /** - * Returns string with a simple encryption. - * - * @param owner inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encryptOwner(String owner) { - char[] encClassNameChars = owner.toCharArray(); - char[] classNameChars = new char[encClassNameChars.length]; - for (int i = 0; i < encClassNameChars.length; i++) { - classNameChars[i] = (char) (encClassNameChars[i] ^ 2893); - } - - return new String(classNameChars); - } - - /** - * Returns string with a simple encryption. - * - * @param name inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encryptName(String name) { - char[] encMethodNameChars = name.toCharArray(); - char[] methodNameChars = new char[encMethodNameChars.length]; - for (int i = 0; i < encMethodNameChars.length; i++) { - methodNameChars[i] = (char) (encMethodNameChars[i] ^ 2993); - } - - return new String(methodNameChars); - } - - /** - * Returns string with a simple encryption. - * - * @param desc inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encryptDesc(String desc) { - char[] encDescChars = desc.toCharArray(); - char[] descChars = new char[encDescChars.length]; - for (int i = 0; i < encDescChars.length; i++) { - descChars[i] = (char) (encDescChars[i] ^ 8372); - } - - return new String(descChars); +public class NormalInvokeDynamic extends LightInvokeDynamic { + @Override + protected void addBSM(ClassNode bsmHost, String methodName) { + bsmHost.methods.add(InvokeDynamicBSMGenerator.normalBSM(methodName, bsmHost.name)); + bsmHost.access = BytecodeUtils.makePublic(bsmHost.access); } } diff --git a/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java b/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java index b0807661..f5b37109 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java +++ b/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java @@ -28,6 +28,10 @@ * @author ItzSomebody */ public class ObfuscateLocalVariables extends AbstractTransformer { + /** + * Length of names to generate. + */ + private static int len = 10; /** * Applies obfuscation. */ @@ -41,7 +45,7 @@ public void obfuscate() { !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LocalVars") && methodNode.localVariables != null).forEach(methodNode -> { methodNode.localVariables.forEach(localVariableNode -> { - localVariableNode.name = StringUtils.crazyString(); + localVariableNode.name = StringUtils.crazyString(len); counter.incrementAndGet(); }); }); diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java index 271f591c..b86d3c6a 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java @@ -34,6 +34,10 @@ * @author ItzSomebody */ public class Crasher extends AbstractTransformer { + /** + * Length of names to generate. + */ + private int len = 10; /** * Applies obfuscation. */ @@ -44,7 +48,7 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("Started crasher transformer.")); this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Crasher")).forEach(classNode -> { if (classNode.signature == null) { - classNode.signature = StringUtils.crazyString(); + classNode.signature = StringUtils.crazyString(len); counter.incrementAndGet(); } }); diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java b/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java index 46c8f7e5..2d809a23 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java @@ -42,6 +42,10 @@ * @author ItzSomebody */ public class StringPool extends AbstractTransformer { + /** + * Length of names to generate. + */ + private int len = 10; /** * Path to pool method. */ @@ -66,9 +70,9 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started string pool transformer.")); this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringPool")).forEach(classNode -> { - this.randName = StringUtils.randomString(this.dictionary); + this.randName = StringUtils.randomString(this.dictionary, len); this.fieldName[0] = classNode.name; - this.fieldName[1] = StringUtils.randomString(this.dictionary); + this.fieldName[1] = StringUtils.randomString(this.dictionary, len); List stringslist = new ArrayList<>(); classNode.methods.stream().filter(methodNode -> !this.exempted(classNode.name + '.' + methodNode.name + methodNode.name, "StringPool") diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java b/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java index 9634d6c8..8670c172 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java @@ -42,6 +42,10 @@ * @author ItzSomebody */ public class TrashClasses { + /** + * Length of names to generate. + */ + private static int len = 10; /** * Class name for the trash class. */ @@ -107,7 +111,7 @@ private ClassNode createClass(String className) { private MethodNode methodGen() { String randDesc = descGen(); MethodNode method = new MethodNode(Opcodes.ACC_STATIC + - Opcodes.ACC_PRIVATE, StringUtils.crazyString(), randDesc, + Opcodes.ACC_PRIVATE, StringUtils.crazyString(len), randDesc, null, null); int instructions = NumberUtils.getRandomInt(30) + 30; @@ -177,11 +181,11 @@ private static AbstractInsnNode junkInsns() { switch (index) { case 0: return new MethodInsnNode(Opcodes.INVOKESTATIC, - StringUtils.crazyString(), StringUtils.crazyString(), + StringUtils.crazyString(len), StringUtils.crazyString(len), "(Ljava/lang/String;)V", false); case 1: return new FieldInsnNode(Opcodes.GETFIELD, - StringUtils.crazyString(), StringUtils.crazyString(), + StringUtils.crazyString(len), StringUtils.crazyString(len), "I"); case 2: return new InsnNode(NumberUtils.getRandomInt(16)); @@ -199,17 +203,17 @@ private static AbstractInsnNode junkInsns() { case 8: return new InsnNode(NumberUtils.getRandomInt(5)); case 9: - return new LdcInsnNode(StringUtils.crazyString()); + return new LdcInsnNode(StringUtils.crazyString(len)); case 10: return new IincInsnNode(NumberUtils.getRandomInt(16), NumberUtils.getRandomInt(16)); case 11: return new MethodInsnNode(Opcodes.INVOKESPECIAL, - StringUtils.crazyString(), StringUtils.crazyString(), + StringUtils.crazyString(len), StringUtils.crazyString(len), "()V", false); case 12: return new MethodInsnNode(Opcodes.INVOKEVIRTUAL, - StringUtils.crazyString(), StringUtils.crazyString(), + StringUtils.crazyString(len), StringUtils.crazyString(len), "(Ljava/lang/Object;)Ljava/lang/Object;", false); case 13: return new VarInsnNode(Opcodes.ILOAD, @@ -218,14 +222,14 @@ private static AbstractInsnNode junkInsns() { return new InsnNode(Opcodes.ATHROW); case 15: return new MethodInsnNode(Opcodes.INVOKEINTERFACE, - StringUtils.crazyString(), StringUtils.crazyString(), + StringUtils.crazyString(len), StringUtils.crazyString(len), "(I)I", false); case 16: - Handle handle = new Handle(6, StringUtils.crazyString(), - StringUtils.crazyString(), StringUtils.crazyString(), + Handle handle = new Handle(6, StringUtils.crazyString(len), + StringUtils.crazyString(len), StringUtils.crazyString(len), false); - return new InvokeDynamicInsnNode(StringUtils.crazyString(), - StringUtils.crazyString(), handle, + return new InvokeDynamicInsnNode(StringUtils.crazyString(len), + StringUtils.crazyString(len), handle, NumberUtils.getRandomInt(5), NumberUtils.getRandomInt(5), NumberUtils.getRandomInt(5), diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java index 48a752df..59d8a1ea 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java @@ -59,6 +59,11 @@ public class Renamer extends AbstractTransformer { */ private boolean spigotMode; + /** + * Length of names to generate. + */ + private int len = 10; + /** * Constructor used to create a {@link Renamer} object. */ @@ -83,14 +88,14 @@ public void obfuscate() { && !methodNode.name.startsWith("<") && !methodNode.name.contains("lambda")).forEach(methodNode -> { if (this.weCanRenameMethod(methodNode)) { - String newName = StringUtils.randomString(this.dictionary); + String newName = StringUtils.randomString(this.dictionary, len); this.renameMethodTree(new ArrayList<>(), methodNode, classNode.name, newName); } }); classNode.fields.forEach(fieldNode -> { if (this.weCanRenameField(fieldNode)) { - String newName = StringUtils.randomString(this.dictionary); + String newName = StringUtils.randomString(this.dictionary, len); this.renameFieldTree(new ArrayList<>(), fieldNode, classNode.name, newName); } }); @@ -99,7 +104,7 @@ public void obfuscate() { int packages = NumberUtils.getRandomInt(2) + 1; StringBuilder newName = new StringBuilder(); for (int i = 0; i < packages; i++) { - newName.append(StringUtils.randomString(this.dictionary)).append('/'); + newName.append(StringUtils.randomString(this.dictionary, len)).append('/'); } this.mappings.put(classNode.name, newName.substring(0, newName.length() - 1)); diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java b/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java index bd7c5751..3d82ba48 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java +++ b/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java @@ -29,6 +29,10 @@ * @author ItzSomebody */ public class ObfuscateSourceDebug extends AbstractTransformer { + /** + * Length of names to generate. + */ + private int len = 10; /** * Applies obfuscation. */ @@ -37,7 +41,7 @@ public void obfuscate() { long current = System.currentTimeMillis(); this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started source debug obfuscation transformer")); - String newDebug = StringUtils.crazyString(); + String newDebug = StringUtils.crazyString(len); this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "SourceDebug") && classNode.sourceDebug != null).forEach(classNode -> { classNode.sourceDebug = newDebug; diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java b/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java index 3c71e308..a4161a3c 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java +++ b/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java @@ -29,6 +29,10 @@ * @author ItzSomebody */ public class ObfuscateSourceName extends AbstractTransformer { + /** + * Length of names to generate. + */ + private int len = 64; /** * Applies obfuscation. */ @@ -37,7 +41,7 @@ public void obfuscate() { long current = System.currentTimeMillis(); this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started source name obfuscation transformer")); - String newName = StringUtils.crazyString() + ".java"; + String newName = StringUtils.crazyString(len) + ".java"; this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "SourceName")).forEach(classNode -> { classNode.sourceFile = newName; counter.incrementAndGet(); diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java index 1360255c..cf65af1f 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java @@ -18,25 +18,17 @@ package me.itzsomebody.radon.transformers.stringencryption; import java.util.concurrent.atomic.AtomicInteger; + import me.itzsomebody.radon.classes.StringDecryptor; -import me.itzsomebody.radon.transformers.AbstractTransformer; +import me.itzsomebody.radon.methods.StringEncryptionGenerator; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.NumberUtils; import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.LdcInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; - -public class HeavyStringEncryption extends AbstractTransformer { - /** - * Indication to not encrypt strings containing Spigot placeholders - * (%%__USER__%%, %%__RESOURCE__%% and %%__NONCE__%%). - */ - private boolean spigotMode; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.*; +public class HeavyStringEncryption extends VeryLightStringEncryption { /** * Constructor used to create a {@link HeavyStringEncryption} object. * @@ -45,79 +37,95 @@ public class HeavyStringEncryption extends AbstractTransformer { * %%__NONCE__%%). */ public HeavyStringEncryption(boolean spigotMode) { - this.spigotMode = spigotMode; + super(spigotMode); } /** * Applies obfuscation. */ + @Override public void obfuscate() { AtomicInteger counter = new AtomicInteger(); long current = System.currentTimeMillis(); - MemberNames memberNames = new MemberNames(this); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started heavy string encryption transformer")); - this.classNodes().parallelStream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> + this.classNodes().parallelStream().filter(classNode -> !this.exempted(classNode.name, "StringEncryptionGenerator")).forEach(classNode -> classNode.methods.parallelStream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryptionGenerator") && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (methodSize(methodNode) > 60000) break; if (insn instanceof LdcInsnNode) { - Object cst = ((LdcInsnNode) insn).cst; - - if (cst instanceof String) { - if (this.spigotMode && - ((String) cst).contains("%%__USER__%%") - || ((String) cst).contains("%%__RESOURCE__%%") - || ((String) cst).contains("%%__NONCE__%%")) + LdcInsnNode ldc = (LdcInsnNode) insn; + if (ldc.cst instanceof String) { + String cst = (String) ldc.cst; + if (spigotCheck(cst)) continue; - int extraKey = NumberUtils.getRandomInt(); int callerClassHC = classNode.name.replace("/", ".").hashCode(); int callerMethodHC = methodNode.name.hashCode(); int decryptorClassHC = memberNames.className.replace("/", ".").hashCode(); int decryptorMethodHC = memberNames.decryptorMethodName.hashCode(); - ((LdcInsnNode) insn).cst = encrypt((String) cst, callerClassHC, callerMethodHC, decryptorClassHC, decryptorMethodHC, extraKey); + ldc.cst = encrypt(cst, callerClassHC, callerMethodHC, decryptorClassHC, decryptorMethodHC, extraKey); methodNode.instructions.insert(insn, new MethodInsnNode(INVOKESTATIC, memberNames.className, memberNames.decryptorMethodName, "(Ljava/lang/Object;I)Ljava/lang/String;", false)); methodNode.instructions.insert(insn, new InsnNode(POP)); methodNode.instructions.insert(insn, new InsnNode(DUP_X1)); methodNode.instructions.insertBefore(insn, BytecodeUtils.createNumberInsn(extraKey)); - counter.incrementAndGet(); } } } }) ); - + // Add decrypt method ClassNode decryptor = StringDecryptor.heavyStringDecryptor(memberNames); - this.getClassMap().put(decryptor.name, decryptor); + getClassMap().put(decryptor.name, decryptor); + // Do logging logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); } + @Override + protected void addDecryptor(ClassNode decryptor, String methodName) { + decryptor.methods.add(StringEncryptionGenerator.lightMethod(methodName)); + decryptor.access = BytecodeUtils.makePublic(decryptor.access); + } + + @Override + protected void encrypt(MethodNode methodNode, String[] decryptorPath, LdcInsnNode ldc, String cst) { + int key = NumberUtils.getRandomInt(); + ldc.cst = StringUtils.lightEncrypt(cst, + decryptorPath[0].replace("/", "."), + decryptorPath[1], key); + methodNode.instructions.insert(ldc, + new MethodInsnNode(Opcodes.INVOKESTATIC, + decryptorPath[0], decryptorPath[1], + "(Ljava/lang/Object;I)" + + "Ljava/lang/String;", + false)); + methodNode.instructions.insert(ldc, BytecodeUtils.createNumberInsn(key)); + } + private static String encrypt(String msg, int callerClassHC, int callerMethodHC, int decryptorClassHC, int decryptorMethodHC, int extraKey) { StringBuilder sb = new StringBuilder(); char[] chars = msg.toCharArray(); for (int i = 0; i < chars.length; i++) { switch (i % 4) { case 0: { - sb.append((char)(extraKey ^ callerClassHC ^ chars[i])); + sb.append((char) (extraKey ^ callerClassHC ^ chars[i])); break; } case 1: { - sb.append((char)(extraKey ^ callerMethodHC ^ chars[i])); + sb.append((char) (extraKey ^ callerMethodHC ^ chars[i])); break; } case 2: { - sb.append((char)(extraKey ^ decryptorClassHC ^ chars[i])); + sb.append((char) (extraKey ^ decryptorClassHC ^ chars[i])); break; } case 3: { - sb.append((char)(extraKey ^ decryptorMethodHC ^ chars[i])); + sb.append((char) (extraKey ^ decryptorMethodHC ^ chars[i])); break; } } @@ -141,15 +149,15 @@ public class MemberNames { public String decryptorMethodName; MemberNames(HeavyStringEncryption instance) { - this.className = StringUtils.randomClassName(instance.classNames(), instance.dictionary); - this.infoFieldName = StringUtils.randomString(instance.dictionary); - this.cacheFieldName = StringUtils.randomString(instance.dictionary); - this.populateMethodName = StringUtils.randomString(instance.dictionary); - this.createInfoMethodName = StringUtils.randomString(instance.dictionary); - this.setCacheMethodName = StringUtils.randomString(instance.dictionary); - this.getCacheMethodName = StringUtils.randomString(instance.dictionary); - this.cacheContainsMethodName = StringUtils.randomString(instance.dictionary); - this.decryptorMethodName = StringUtils.randomString(instance.dictionary); + this.className = StringUtils.randomClassName(instance.classNames(), instance.dictionary, len); + this.infoFieldName = StringUtils.randomString(instance.dictionary, len); + this.cacheFieldName = StringUtils.randomString(instance.dictionary, len); + this.populateMethodName = StringUtils.randomString(instance.dictionary, len); + this.createInfoMethodName = StringUtils.randomString(instance.dictionary, len); + this.setCacheMethodName = StringUtils.randomString(instance.dictionary, len); + this.getCacheMethodName = StringUtils.randomString(instance.dictionary, len); + this.cacheContainsMethodName = StringUtils.randomString(instance.dictionary, len); + this.decryptorMethodName = StringUtils.randomString(instance.dictionary, len); } } } diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java index 49453144..f2460b52 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java @@ -17,30 +17,19 @@ package me.itzsomebody.radon.transformers.stringencryption; -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.methods.StringEncryption; -import me.itzsomebody.radon.transformers.AbstractTransformer; +import me.itzsomebody.radon.methods.StringEncryptionGenerator; import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.NumberUtils; import me.itzsomebody.radon.utils.StringUtils; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.LdcInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.*; /** * Transformer that encrypts strings using a stacktrace-backed method. * * @author ItzSomebody */ -public class LightStringEncryption extends AbstractTransformer { - /** - * Indication to not encrypt strings containing Spigot placeholders - * (%%__USER__%%, %%__RESOURCE__%% and %%__NONCE__%%). - */ - private boolean spigotMode; - +public class LightStringEncryption extends VeryLightStringEncryption { /** * Constructor used to create a {@link LightStringEncryption} object. * @@ -49,59 +38,27 @@ public class LightStringEncryption extends AbstractTransformer { * and %%__NONCE__%%). */ public LightStringEncryption(boolean spigotMode) { - this.spigotMode = spigotMode; + super(spigotMode); } - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started light string encryption transformer")); - String[] decryptorPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary)}; - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") - && hasInstructions(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (methodSize(methodNode) > 60000) break; - if (insn instanceof LdcInsnNode) { - Object cst = ((LdcInsnNode) insn).cst; - - if (cst instanceof String) { - if (this.spigotMode && - ((String) cst).contains("%%__USER__%%") - || ((String) cst).contains("%%__RESOURCE__%%") - || ((String) cst).contains("%%__NONCE__%%")) - continue; - - int key3 = NumberUtils.getRandomInt(); - ((LdcInsnNode) insn).cst = - StringUtils.lightEncrypt(((String) ((LdcInsnNode) insn).cst), - decryptorPath[0].replace("/", "."), - decryptorPath[1], key3); - methodNode.instructions.insert(insn, - new MethodInsnNode(Opcodes.INVOKESTATIC, - decryptorPath[0], decryptorPath[1], - "(Ljava/lang/Object;I)" + - "Ljava/lang/String;", - false)); - methodNode.instructions.insert(insn, - BytecodeUtils.createNumberInsn(key3)); - counter.incrementAndGet(); - } - } - } - }); - }); + @Override + protected void addDecryptor(ClassNode decryptor, String methodName) { + decryptor.methods.add(StringEncryptionGenerator.lightMethod(methodName)); + decryptor.access = BytecodeUtils.makePublic(decryptor.access); + } - this.classNodes().stream().filter(classNode -> classNode.name.equals(decryptorPath[0])).forEach(classNode -> { - classNode.methods.add(StringEncryption.lightMethod(decryptorPath[1])); - classNode.access = BytecodeUtils.makePublic(classNode.access); - }); - logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); - logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); + @Override + protected void encrypt(MethodNode methodNode, String[] decryptorPath, LdcInsnNode ldc, String cst) { + int key = NumberUtils.getRandomInt(); + ldc.cst = StringUtils.lightEncrypt(cst, + decryptorPath[0].replace("/", "."), + decryptorPath[1], key); + methodNode.instructions.insert(ldc, + new MethodInsnNode(Opcodes.INVOKESTATIC, + decryptorPath[0], decryptorPath[1], + "(Ljava/lang/Object;I)" + + "Ljava/lang/String;", + false)); + methodNode.instructions.insert(ldc, BytecodeUtils.createNumberInsn(key)); } } diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java index 45a74ace..6726f23a 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java @@ -17,18 +17,13 @@ package me.itzsomebody.radon.transformers.stringencryption; -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.methods.StringEncryption; -import me.itzsomebody.radon.transformers.AbstractTransformer; +import me.itzsomebody.radon.methods.StringEncryptionGenerator; import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; + import me.itzsomebody.radon.utils.NumberUtils; import me.itzsomebody.radon.utils.StringUtils; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.LdcInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.*; /** * Transformer that encrypts strings the same way {@link LightStringEncryption} @@ -36,13 +31,7 @@ * * @author ItzSomebody */ -public class NormalStringEncryption extends AbstractTransformer { - /** - * Indication to not encrypt strings containing Spigot placeholders - * (%%__USER__%%, %%__RESOURCE__%% and %%__NONCE__%%). - */ - private boolean spigotMode; - +public class NormalStringEncryption extends VeryLightStringEncryption { /** * Constructor used to create a {@link NormalStringEncryption} object. * @@ -51,62 +40,30 @@ public class NormalStringEncryption extends AbstractTransformer { * %%__NONCE__%%). */ public NormalStringEncryption(boolean spigotMode) { - this.spigotMode = spigotMode; + super(spigotMode); } - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started normal string encryption transformer")); - String[] decryptorPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary)}; - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") - && hasInstructions(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (methodSize(methodNode) > 60000) break; - if (insn instanceof LdcInsnNode) { - Object cst = ((LdcInsnNode) insn).cst; - - if (cst instanceof String) { - if (this.spigotMode && - ((String) cst).contains("%%__USER__%%") - || ((String) cst).contains("%%__RESOURCE__%%") - || ((String) cst).contains("%%__NONCE__%%")) - continue; - - int key3 = NumberUtils.getRandomInt(25000) + 25000; - ((LdcInsnNode) insn).cst = - StringUtils.normalEncrypt(decryptorPath[0].replace("/", "."), - decryptorPath[1], key3, - ((String) ((LdcInsnNode) insn).cst)); - methodNode.instructions.insert(insn, - new MethodInsnNode(Opcodes.INVOKESTATIC, - decryptorPath[0], decryptorPath[1], - "(Ljava/lang/Object;" + - "Ljava/lang/Object;I)" + - "Ljava/lang/String;", - false)); - methodNode.instructions.insert(insn, - BytecodeUtils.createNumberInsn(key3)); - methodNode.instructions.insert(insn, - new InsnNode(ACONST_NULL)); - counter.incrementAndGet(); - } - } - } - }); - }); + @Override + protected void addDecryptor(ClassNode decryptor, String methodName) { + decryptor.methods.add(StringEncryptionGenerator.normalMethod(methodName)); + decryptor.access = BytecodeUtils.makePublic(decryptor.access); + } - this.classNodes().stream().filter(classNode -> classNode.name.equals(decryptorPath[0])).forEach(classNode -> { - classNode.methods.add(StringEncryption.normalMethod(decryptorPath[1])); - classNode.access = BytecodeUtils.makePublic(classNode.access); - }); - logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); - logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); + @Override + protected void encrypt(MethodNode methodNode, String[] decryptorPath, LdcInsnNode ldc, String cst) { + int key = NumberUtils.getRandomInt(25000) + 25000; + ldc.cst = StringUtils.normalEncrypt( + decryptorPath[0].replace("/", "."), + decryptorPath[1], key, + cst); + methodNode.instructions.insert(ldc, + new MethodInsnNode(Opcodes.INVOKESTATIC, + decryptorPath[0], decryptorPath[1], + "(Ljava/lang/Object;" + + "Ljava/lang/Object;I)" + + "Ljava/lang/String;", + false)); + methodNode.instructions.insert(ldc, BytecodeUtils.createNumberInsn(key)); + methodNode.instructions.insert(ldc, new InsnNode(ACONST_NULL)); } } diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/VeryLightStringEncryption.java similarity index 56% rename from src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java rename to src/main/java/me/itzsomebody/radon/transformers/stringencryption/VeryLightStringEncryption.java index d7a1b3cc..e2476820 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/VeryLightStringEncryption.java @@ -18,28 +18,30 @@ package me.itzsomebody.radon.transformers.stringencryption; import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.methods.StringEncryption; + +import me.itzsomebody.radon.methods.StringEncryptionGenerator; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.NumberUtils; import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.LdcInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.*; /** * Transformer that encrypts strings using an extremely simple XOR algorithm. * * @author ItzSomebody */ -public class SuperLightStringEncryption extends AbstractTransformer { +public class VeryLightStringEncryption extends AbstractTransformer { + /** + * Length of names to generate. + */ + protected final int len = 64; /** * Indication to not encrypt strings containing Spigot placeholders * (%%__USER__%%, %%__RESOURCE__%% and %%__NONCE__%%). */ - private boolean spigotMode; - + protected final boolean spigotMode; /** * Constructor used to create a {@link LightStringEncryption} object. * @@ -47,7 +49,7 @@ public class SuperLightStringEncryption extends AbstractTransformer { * placeholders (%%__USER__%%, %%__RESOURCE__%% * and %%__NONCE__%%). */ - public SuperLightStringEncryption(boolean spigotMode) { + public VeryLightStringEncryption(boolean spigotMode) { this.spigotMode = spigotMode; } @@ -58,47 +60,59 @@ public void obfuscate() { AtomicInteger counter = new AtomicInteger(); long current = System.currentTimeMillis(); this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started super light string encryption transformer")); - String[] decryptorPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary)}; - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> { + this.logStrings.add(LoggerUtils.stdOut("Started string encryption transformer")); + String[] decryptorPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary, len)}; + this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryptionGenerator")).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryptionGenerator") && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (methodSize(methodNode) > 60000) break; if (insn instanceof LdcInsnNode) { - Object cst = ((LdcInsnNode) insn).cst; - - if (cst instanceof String) { - if (spigotMode && - ((String) cst).contains("%%__USER__%%") - || ((String) cst).contains("%%__RESOURCE__%%") - || ((String) cst).contains("%%__NONCE__%%")) + LdcInsnNode ldc = (LdcInsnNode) insn; + if (ldc.cst instanceof String) { + String cst = (String) ldc.cst; + if (spigotCheck(cst)) continue; - - int key = NumberUtils.getRandomInt(); - ((LdcInsnNode) insn).cst = - StringUtils.superLightEncrypt(((String) ((LdcInsnNode) insn).cst), key); - methodNode.instructions.insert(insn, - new MethodInsnNode(INVOKESTATIC, decryptorPath[0], - decryptorPath[1], - "(Ljava/lang/String;I)" + - "Ljava/lang/String;", - false)); - methodNode.instructions.insert(insn, - BytecodeUtils.createNumberInsn(key)); + encrypt(methodNode,decryptorPath, ldc, cst); counter.incrementAndGet(); } } } }); }); - - this.classNodes().stream().filter(classNode -> classNode.name.equals(decryptorPath[0])).forEach(classNode -> { - classNode.methods.add(StringEncryption.superLightMethod(decryptorPath[1])); - classNode.access = BytecodeUtils.makePublic(classNode.access); - }); + // Add decrypt method + ClassNode decryptor = getClassMap().get(decryptorPath[0]); + addDecryptor(decryptor, decryptorPath[1]); + // Do logging logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); } + + protected boolean spigotCheck(String cst) { + return spigotMode && + (cst).contains("%%__USER__%%") + || (cst).contains("%%__RESOURCE__%%") + || (cst).contains("%%__NONCE__%%"); + } + + protected void addDecryptor(ClassNode decryptor, String methodName) { + decryptor.methods.add(StringEncryptionGenerator.superLightMethod(methodName)); + decryptor.access = BytecodeUtils.makePublic(decryptor.access); + } + + protected void encrypt(MethodNode methodNode, String[] decryptorPath, LdcInsnNode ldc, String cst) { + int key = NumberUtils.getRandomInt(); + ldc.cst = StringUtils.superLightEncrypt(cst, key); + methodNode.instructions.insert(ldc, + new MethodInsnNode( + INVOKESTATIC, + decryptorPath[0], + decryptorPath[1], + "(Ljava/lang/String;I)Ljava/lang/String;", + false)); + methodNode.instructions.insert(ldc, BytecodeUtils.createNumberInsn(key)); + } + + } diff --git a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java index cc3f9284..8a7646f1 100644 --- a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java @@ -28,7 +28,7 @@ import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; +import me.itzsomebody.radon.transformers.stringencryption.VeryLightStringEncryption; /** * Utils for operating, and generating {@link String}s. @@ -110,11 +110,11 @@ public static String crazyKey(int len) { } /** - * Returns an encrypted string used by {@link SuperLightStringEncryption}. + * Returns an encrypted string used by {@link VeryLightStringEncryption}. * * @param msg string to encrypt. * @param key random integer - * @return an encrypted string used by {@link SuperLightStringEncryption}. + * @return an encrypted string used by {@link VeryLightStringEncryption}. */ public static String superLightEncrypt(String msg, int key) { char[] encryptedArray = msg.toCharArray(); From 4512a5b98bdb6475c4f1d959ac88ecea42c7c62d Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 21:00:44 -0400 Subject: [PATCH 047/281] Clarify todo msg for removing 'SpigotPlugin' config enum --- src/main/java/me/itzsomebody/radon/config/ConfigEnum.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java b/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java index 4120a235..ed430e9b 100644 --- a/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java +++ b/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java @@ -42,7 +42,7 @@ public enum ConfigEnum { WATERMARK_MSG("WatermarkMessage"), WATERMARK_KEY("WatermarkKey"), WATERMARK_TYPE("WatermarkType"), - SPIGOT_PLUGIN("SpigotPlugin"), // TODO: Remove this + SPIGOT_PLUGIN("SpigotPlugin"), // TODO: Remove this, replace with custom rules that allow users to exclude conflicts RENAMER("Renamer"), EXPIRATION_TIME("ExpiryTime"), EXPIRATION_MESSAGE("ExpiryMessage"), From a4e7c536196ab38ddd7a085991065ee9d026761c Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 21:14:36 -0400 Subject: [PATCH 048/281] Minor cleaning of internal package --- .../itzsomebody/radon/internal/Bootstrap.java | 15 +++--- .../me/itzsomebody/radon/internal/CLI.java | 34 ++++++++++--- .../itzsomebody/radon/internal/ClassTree.java | 10 ++-- .../internal/climessages/CLIMessages.java | 50 ------------------- 4 files changed, 41 insertions(+), 68 deletions(-) delete mode 100644 src/main/java/me/itzsomebody/radon/internal/climessages/CLIMessages.java diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index 336e97cc..7ea0ee0c 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -33,6 +33,7 @@ import java.util.zip.ZipException; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; + import me.itzsomebody.radon.Radon; import me.itzsomebody.radon.config.Config; import me.itzsomebody.radon.transformers.AbstractTransformer; @@ -58,27 +59,27 @@ public class Bootstrap { // Eyyy bootstrap bill /** * HashMap that stores all of the loaded classes. */ - private Map classPath = new HashMap<>(); + private final Map classPath = new HashMap<>(); /** * HashMap that stores all of the input classes (and as they are obfuscated). */ - private Map classes = new HashMap<>(); + private final Map classes = new HashMap<>(); /** * Extra classes that are generated by the obfuscator. */ - private Map extraClasses = new HashMap<>(); + private final Map extraClasses = new HashMap<>(); /** * Resources which "pass through" the obfuscator. */ - private Map passThru = new HashMap<>(); + private final Map passThru = new HashMap<>(); /** * Class hiearchy. */ - private Map hierarchy = new HashMap<>(); + private final Map hierarchy = new HashMap<>(); /** * Config object @@ -541,10 +542,10 @@ private void createTrees() { this.logStrings.add(LoggerUtils.stdOut("Creating class hierarchy.")); classPath.values().forEach(classNode -> { classNode.methods.forEach(methodNode -> - methodNode.owner = classNode.name + methodNode.owner = classNode.name ); classNode.fields.forEach(fieldNode -> - fieldNode.owner = classNode.name + fieldNode.owner = classNode.name ); ClassTree classTree = new ClassTree(classNode.name, classNode.libraryNode); classTree.parentClasses.add(classNode.superName); diff --git a/src/main/java/me/itzsomebody/radon/internal/CLI.java b/src/main/java/me/itzsomebody/radon/internal/CLI.java index 4d87db1e..69e56a9a 100644 --- a/src/main/java/me/itzsomebody/radon/internal/CLI.java +++ b/src/main/java/me/itzsomebody/radon/internal/CLI.java @@ -23,7 +23,6 @@ import java.util.List; import me.itzsomebody.radon.Radon; import me.itzsomebody.radon.config.Config; -import me.itzsomebody.radon.internal.climessages.CLIMessages; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.WatermarkUtils; @@ -63,10 +62,10 @@ private void startTheParty() { case "-help": case "help": case "/help": - CLIMessages.helpMsg(); + helpMsg(); break; default: - CLIMessages.usageMsg(); + usageMsg(); } } else if (this.args.length == 2) { switch (this.args[0].toLowerCase()) { @@ -90,7 +89,7 @@ private void startTheParty() { } break; default: - CLIMessages.usageMsg(); + usageMsg(); break; } } else if (this.args.length == 3) { @@ -116,11 +115,34 @@ private void startTheParty() { } break; default: - CLIMessages.usageMsg(); + usageMsg(); break; } } else { - CLIMessages.usageMsg(); + usageMsg(); } } + + /** + * Prints usage message into console. + */ + private static void usageMsg() { + LoggerUtils.stdOut("Usage: java -jar Radon.jar --config example" + + ".config"); + LoggerUtils.stdOut("USage: java -jar Radon.jar --help"); + LoggerUtils.stdOut("Usage: java -jar Radon.jar"); + } + + /** + * Prints help message into console. + */ + private static void helpMsg() { + LoggerUtils.stdOut("CLI Usage:\t\tjava -jar Radon.jar --config " + + "example.config"); + LoggerUtils.stdOut("Credits:\t\tjava -jar Radon.jar --version"); + LoggerUtils.stdOut("Help Menu:\t\tjava -jar Radon.jar --help"); + LoggerUtils.stdOut("Watermark Extraction:\tjava -jar Radon.jar " + + "--extract Input.jar exampleKey"); + LoggerUtils.stdOut("MainGUI Usage:\t\tjava -jar Radon.jar"); + } } diff --git a/src/main/java/me/itzsomebody/radon/internal/ClassTree.java b/src/main/java/me/itzsomebody/radon/internal/ClassTree.java index c13cc268..a6e84b87 100644 --- a/src/main/java/me/itzsomebody/radon/internal/ClassTree.java +++ b/src/main/java/me/itzsomebody/radon/internal/ClassTree.java @@ -32,7 +32,7 @@ public class ClassTree { /** * Class name. */ - public String className; + public final String className; /** * Attached class node. @@ -42,22 +42,22 @@ public class ClassTree { /** * Set of classes that inherit this class. */ - public Set subClasses = new HashSet<>(); + public final Set subClasses = new HashSet<>(); /** * Set of classes that this class inherits. */ - public Set parentClasses = new HashSet<>(); + public final Set parentClasses = new HashSet<>(); /** * Set of methods that this class contains. */ - public Set methods = new HashSet<>(); + public final Set methods = new HashSet<>(); /** * Set of fields that this class contains. */ - public Set fields = new HashSet<>(); + public final Set fields = new HashSet<>(); /** * Indication of this class being a library (external) class. diff --git a/src/main/java/me/itzsomebody/radon/internal/climessages/CLIMessages.java b/src/main/java/me/itzsomebody/radon/internal/climessages/CLIMessages.java deleted file mode 100644 index 7e25844d..00000000 --- a/src/main/java/me/itzsomebody/radon/internal/climessages/CLIMessages.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.internal.climessages; - -import me.itzsomebody.radon.utils.LoggerUtils; - -/** - * Class of static abuse LOL - * - * @author ItzSomebody - */ -public class CLIMessages { - /** - * Prints usage message into console. - */ - public static void usageMsg() { - LoggerUtils.stdOut("Usage: java -jar Radon.jar --config example" + - ".config"); - LoggerUtils.stdOut("USage: java -jar Radon.jar --help"); - LoggerUtils.stdOut("Usage: java -jar Radon.jar"); - } - - /** - * Prints help message into console. - */ - public static void helpMsg() { - LoggerUtils.stdOut("CLI Usage:\t\tjava -jar Radon.jar --config " + - "example.config"); - LoggerUtils.stdOut("Credits:\t\tjava -jar Radon.jar --version"); - LoggerUtils.stdOut("Help Menu:\t\tjava -jar Radon.jar --help"); - LoggerUtils.stdOut("Watermark Extraction:\tjava -jar Radon.jar " + - "--extract Input.jar exampleKey"); - LoggerUtils.stdOut("MainGUI Usage:\t\tjava -jar Radon.jar"); - } -} From 6a86dd25c381afaf3bca1397265238b3f35b565f Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 21:19:20 -0400 Subject: [PATCH 049/281] merge 'classes' and 'methods' into 'generator' package --- .../InvokeDynamicBSMGenerator.java | 420 +----------------- .../InvokeDynamicBootstrapGenerator.java} | 4 +- .../StringDecryptorGenerator.java} | 4 +- .../StringEncryptionGenerator.java | 2 +- .../invokedynamic/HeavyInvokeDynamic.java | 5 +- .../invokedynamic/LightInvokeDynamic.java | 2 +- .../invokedynamic/NormalInvokeDynamic.java | 2 +- .../HeavyStringEncryption.java | 6 +- .../LightStringEncryption.java | 2 +- .../NormalStringEncryption.java | 2 +- .../VeryLightStringEncryption.java | 2 +- 11 files changed, 17 insertions(+), 434 deletions(-) rename src/main/java/me/itzsomebody/radon/{methods => generate}/InvokeDynamicBSMGenerator.java (57%) rename src/main/java/me/itzsomebody/radon/{classes/InvokeDynamicBootstrap.java => generate/InvokeDynamicBootstrapGenerator.java} (99%) rename src/main/java/me/itzsomebody/radon/{classes/StringDecryptor.java => generate/StringDecryptorGenerator.java} (99%) rename src/main/java/me/itzsomebody/radon/{methods => generate}/StringEncryptionGenerator.java (99%) diff --git a/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSMGenerator.java b/src/main/java/me/itzsomebody/radon/generate/InvokeDynamicBSMGenerator.java similarity index 57% rename from src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSMGenerator.java rename to src/main/java/me/itzsomebody/radon/generate/InvokeDynamicBSMGenerator.java index 82a27f93..4effd5c8 100644 --- a/src/main/java/me/itzsomebody/radon/methods/InvokeDynamicBSMGenerator.java +++ b/src/main/java/me/itzsomebody/radon/generate/InvokeDynamicBSMGenerator.java @@ -15,9 +15,10 @@ * along with this program. If not, see */ -package me.itzsomebody.radon.methods; +package me.itzsomebody.radon.generate; import java.lang.invoke.ConstantCallSite; + import me.itzsomebody.radon.transformers.invokedynamic.HeavyInvokeDynamic; import me.itzsomebody.radon.transformers.invokedynamic.LightInvokeDynamic; import me.itzsomebody.radon.transformers.invokedynamic.NormalInvokeDynamic; @@ -688,421 +689,4 @@ public static MethodNode normalBSM(String bsmName, String className) { mv.visitEnd(); return mv; } - - /** - * Returns a {@link MethodNode} that returns a {@link ConstantCallSite} - * statically linked to a method for {@link HeavyInvokeDynamic}. - * - * @param methodName used to determine the name of the generated - * {@link MethodNode}. - * @param className used to determine the classname to use as loader. - * @return a {@link MethodNode} that returns a {@link ConstantCallSite} - * statically linked to a method for {@link HeavyInvokeDynamic}. - */ - public static MethodNode heavyBSM(String methodName, String className) { - MethodNode mv = new MethodNode(ACC_PUBLIC + ACC_STATIC + - ACC_BRIDGE + ACC_SYNTHETIC, methodName, - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;)Ljava/lang/Object;", null, null); - mv.visitCode(); - Label l0 = new Label(); - Label l1 = new Label(); - Label l2 = new Label(); - mv.visitTryCatchBlock(l0, l1, l2, "java/lang/NoSuchFieldException"); - Label l3 = new Label(); - Label l4 = new Label(); - Label l5 = new Label(); - mv.visitTryCatchBlock(l3, l4, l5, "java/lang/Throwable"); - Label l6 = new Label(); - mv.visitLabel(l6); - mv.visitInsn(ICONST_0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); - mv.visitVarInsn(ASTORE, 8); - Label l7 = new Label(); - mv.visitLabel(l7); - mv.visitVarInsn(ALOAD, 8); - mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); - mv.visitIntInsn(SIPUSH, 233); - mv.visitInsn(IOR); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); - mv.visitVarInsn(ASTORE, 9); - Label l8 = new Label(); - mv.visitLabel(l8); - mv.visitVarInsn(ALOAD, 9); - mv.visitVarInsn(ALOAD, 8); - Label l9 = new Label(); - mv.visitJumpInsn(IF_ACMPNE, l9); - Label l10 = new Label(); - mv.visitLabel(l10); - mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", "", "()V", false); - mv.visitInsn(ATHROW); - mv.visitLabel(l9); - mv.visitFrame(Opcodes.F_APPEND, 2, new Object[]{"java/lang/Object", "java/lang/Object"}, 0, null); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ASTORE, 11); - Label l11 = new Label(); - mv.visitLabel(l11); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ASTORE, 12); - mv.visitLabel(l3); - mv.visitVarInsn(ALOAD, 5); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); - mv.visitVarInsn(ASTORE, 13); - Label l12 = new Label(); - mv.visitLabel(l12); - mv.visitVarInsn(ALOAD, 13); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 14); - Label l13 = new Label(); - mv.visitLabel(l13); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 15); - Label l14 = new Label(); - mv.visitLabel(l14); - Label l15 = new Label(); - mv.visitJumpInsn(GOTO, l15); - Label l16 = new Label(); - mv.visitLabel(l16); - mv.visitFrame(Opcodes.F_FULL, 16, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 14); - mv.visitVarInsn(ILOAD, 15); - mv.visitVarInsn(ALOAD, 13); - mv.visitVarInsn(ILOAD, 15); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 4382); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l17 = new Label(); - mv.visitLabel(l17); - mv.visitIincInsn(15, 1); - mv.visitLabel(l15); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 15); - mv.visitVarInsn(ALOAD, 13); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l16); - Label l18 = new Label(); - mv.visitLabel(l18); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 14); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false); - mv.visitVarInsn(ASTORE, 15); - Label l19 = new Label(); - mv.visitLabel(l19); - mv.visitVarInsn(ALOAD, 6); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); - mv.visitVarInsn(ASTORE, 16); - Label l20 = new Label(); - mv.visitLabel(l20); - mv.visitVarInsn(ALOAD, 16); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 17); - Label l21 = new Label(); - mv.visitLabel(l21); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 18); - Label l22 = new Label(); - mv.visitLabel(l22); - Label l23 = new Label(); - mv.visitJumpInsn(GOTO, l23); - Label l24 = new Label(); - mv.visitLabel(l24); - mv.visitFrame(Opcodes.F_FULL, 19, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 17); - mv.visitVarInsn(ILOAD, 18); - mv.visitVarInsn(ALOAD, 16); - mv.visitVarInsn(ILOAD, 18); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 3940); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l25 = new Label(); - mv.visitLabel(l25); - mv.visitIincInsn(18, 1); - mv.visitLabel(l23); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 18); - mv.visitVarInsn(ALOAD, 16); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l24); - Label l26 = new Label(); - mv.visitLabel(l26); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 17); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); - mv.visitVarInsn(ASTORE, 18); - Label l27 = new Label(); - mv.visitLabel(l27); - mv.visitVarInsn(ALOAD, 7); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); - mv.visitVarInsn(ASTORE, 19); - Label l28 = new Label(); - mv.visitLabel(l28); - mv.visitVarInsn(ALOAD, 19); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 20); - Label l29 = new Label(); - mv.visitLabel(l29); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 21); - Label l30 = new Label(); - mv.visitLabel(l30); - Label l31 = new Label(); - mv.visitJumpInsn(GOTO, l31); - Label l32 = new Label(); - mv.visitLabel(l32); - mv.visitFrame(Opcodes.F_FULL, 22, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 20); - mv.visitVarInsn(ILOAD, 21); - mv.visitVarInsn(ALOAD, 19); - mv.visitVarInsn(ILOAD, 21); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 5739); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l33 = new Label(); - mv.visitLabel(l33); - mv.visitIincInsn(21, 1); - mv.visitLabel(l31); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 21); - mv.visitVarInsn(ALOAD, 19); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l32); - Label l34 = new Label(); - mv.visitLabel(l34); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 20); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); - mv.visitVarInsn(ASTORE, 21); - Label l35 = new Label(); - mv.visitLabel(l35); - mv.visitVarInsn(ALOAD, 11); - mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); - Label l36 = new Label(); - Label l37 = new Label(); - Label l38 = new Label(); - mv.visitTableSwitchInsn(0, 1, l38, new Label[]{l36, l37}); - mv.visitLabel(l36); - mv.visitFrame(Opcodes.F_FULL, 22, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String"}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 4); - mv.visitVarInsn(ASTORE, 22); - Label l39 = new Label(); - mv.visitLabel(l39); - mv.visitInsn(ACONST_NULL); - mv.visitVarInsn(ASTORE, 23); - Label l40 = new Label(); - mv.visitLabel(l40); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 14); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false); - mv.visitVarInsn(ASTORE, 24); - mv.visitLabel(l0); - mv.visitFrame(Opcodes.F_APPEND, 3, new Object[]{"java/lang/Object", "java/lang/reflect/Field", "java/lang/Class"}, 0, null); - mv.visitVarInsn(ALOAD, 24); - mv.visitVarInsn(ALOAD, 18); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", false); - mv.visitVarInsn(ASTORE, 23); - mv.visitLabel(l1); - Label l41 = new Label(); - mv.visitJumpInsn(GOTO, l41); - mv.visitLabel(l2); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{"java/lang/NoSuchFieldException"}); - mv.visitVarInsn(ASTORE, 25); - Label l42 = new Label(); - mv.visitLabel(l42); - mv.visitVarInsn(ALOAD, 24); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getSuperclass", "()Ljava/lang/Class;", false); - mv.visitInsn(DUP); - mv.visitVarInsn(ASTORE, 24); - mv.visitJumpInsn(IFNONNULL, l0); - mv.visitLabel(l41); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 23); - Label l43 = new Label(); - mv.visitJumpInsn(IFNONNULL, l43); - Label l44 = new Label(); - mv.visitLabel(l44); - mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", "", "()V", false); - mv.visitInsn(ATHROW); - mv.visitLabel(l43); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 22); - mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); - Label l45 = new Label(); - Label l46 = new Label(); - Label l47 = new Label(); - Label l48 = new Label(); - Label l49 = new Label(); - mv.visitTableSwitchInsn(0, 3, l49, new Label[]{l45, l46, l47, l48}); - mv.visitLabel(l45); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 12); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitVarInsn(ALOAD, 15); - mv.visitVarInsn(ALOAD, 18); - mv.visitVarInsn(ALOAD, 23); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getType", "()Ljava/lang/Class;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findGetter", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 10); - Label l50 = new Label(); - mv.visitLabel(l50); - Label l51 = new Label(); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l46); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 12); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitVarInsn(ALOAD, 15); - mv.visitVarInsn(ALOAD, 18); - mv.visitVarInsn(ALOAD, 23); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getType", "()Ljava/lang/Class;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStaticGetter", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 10); - Label l52 = new Label(); - mv.visitLabel(l52); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l47); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 12); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitVarInsn(ALOAD, 15); - mv.visitVarInsn(ALOAD, 18); - mv.visitVarInsn(ALOAD, 23); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getType", "()Ljava/lang/Class;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findSetter", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 10); - Label l53 = new Label(); - mv.visitLabel(l53); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l48); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 12); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitVarInsn(ALOAD, 15); - mv.visitVarInsn(ALOAD, 18); - mv.visitVarInsn(ALOAD, 23); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getType", "()Ljava/lang/Class;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStaticSetter", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 10); - Label l54 = new Label(); - mv.visitLabel(l54); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l49); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitInsn(ACONST_NULL); - mv.visitVarInsn(ASTORE, 10); - Label l55 = new Label(); - mv.visitLabel(l55); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l37); - mv.visitFrame(Opcodes.F_CHOP, 3, null, 0, null); - mv.visitVarInsn(ALOAD, 4); - mv.visitVarInsn(ASTORE, 25); - Label l56 = new Label(); - mv.visitLabel(l56); - mv.visitVarInsn(ALOAD, 21); - mv.visitLdcInsn(Type.getType("L" + className + ";")); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "fromMethodDescriptorString", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;", false); - mv.visitVarInsn(ASTORE, 26); - Label l57 = new Label(); - mv.visitLabel(l57); - mv.visitVarInsn(ALOAD, 25); - mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); - Label l58 = new Label(); - Label l59 = new Label(); - Label l60 = new Label(); - mv.visitTableSwitchInsn(0, 1, l60, new Label[]{l58, l59}); - mv.visitLabel(l58); - mv.visitFrame(Opcodes.F_FULL, 27, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String", Opcodes.TOP, Opcodes.TOP, Opcodes.TOP, "java/lang/Object", "java/lang/invoke/MethodType"}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 12); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitVarInsn(ALOAD, 15); - mv.visitVarInsn(ALOAD, 18); - mv.visitVarInsn(ALOAD, 26); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findVirtual", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 10); - Label l61 = new Label(); - mv.visitLabel(l61); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l59); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 12); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitVarInsn(ALOAD, 15); - mv.visitVarInsn(ALOAD, 18); - mv.visitVarInsn(ALOAD, 26); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStatic", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 10); - Label l62 = new Label(); - mv.visitLabel(l62); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l60); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitInsn(ACONST_NULL); - mv.visitVarInsn(ASTORE, 10); - Label l63 = new Label(); - mv.visitLabel(l63); - mv.visitJumpInsn(GOTO, l51); - mv.visitLabel(l38); - mv.visitFrame(Opcodes.F_FULL, 22, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String"}, 0, new Object[]{}); - mv.visitInsn(ACONST_NULL); - mv.visitVarInsn(ASTORE, 10); - mv.visitLabel(l51); - mv.visitFrame(Opcodes.F_FULL, 22, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/invoke/MethodHandle", "java/lang/Object", "java/lang/Object", "[C", "[C", "java/lang/Class", "[C", "[C", "java/lang/String", "[C", "[C", "java/lang/String"}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 10); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodType"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "asType", "(Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 10); - Label l64 = new Label(); - mv.visitLabel(l64); - mv.visitTypeInsn(NEW, "java/lang/invoke/ConstantCallSite"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", "", "(Ljava/lang/invoke/MethodHandle;)V", false); - mv.visitLabel(l4); - mv.visitInsn(ARETURN); - mv.visitLabel(l5); - mv.visitFrame(Opcodes.F_FULL, 13, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", Opcodes.TOP, "java/lang/Object", "java/lang/Object"}, 1, new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 13); - Label l65 = new Label(); - mv.visitLabel(l65); - mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", "", "()V", false); - mv.visitInsn(ATHROW); - Label l66 = new Label(); - mv.visitLabel(l66); - mv.visitMaxs(4, 27); - mv.visitEnd(); - - return mv; - } } diff --git a/src/main/java/me/itzsomebody/radon/classes/InvokeDynamicBootstrap.java b/src/main/java/me/itzsomebody/radon/generate/InvokeDynamicBootstrapGenerator.java similarity index 99% rename from src/main/java/me/itzsomebody/radon/classes/InvokeDynamicBootstrap.java rename to src/main/java/me/itzsomebody/radon/generate/InvokeDynamicBootstrapGenerator.java index 690be878..5b207e09 100644 --- a/src/main/java/me/itzsomebody/radon/classes/InvokeDynamicBootstrap.java +++ b/src/main/java/me/itzsomebody/radon/generate/InvokeDynamicBootstrapGenerator.java @@ -15,7 +15,7 @@ * along with this program. If not, see */ -package me.itzsomebody.radon.classes; +package me.itzsomebody.radon.generate; import me.itzsomebody.radon.transformers.invokedynamic.HeavyInvokeDynamic; import org.objectweb.asm.Label; @@ -24,7 +24,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; -public class InvokeDynamicBootstrap implements Opcodes { +public class InvokeDynamicBootstrapGenerator implements Opcodes { public static ClassNode heavyBootstrap(HeavyInvokeDynamic.MemberNames memberNames) { ClassNode cw = new ClassNode(); MethodVisitor mv; diff --git a/src/main/java/me/itzsomebody/radon/classes/StringDecryptor.java b/src/main/java/me/itzsomebody/radon/generate/StringDecryptorGenerator.java similarity index 99% rename from src/main/java/me/itzsomebody/radon/classes/StringDecryptor.java rename to src/main/java/me/itzsomebody/radon/generate/StringDecryptorGenerator.java index bbefc516..00ee379a 100644 --- a/src/main/java/me/itzsomebody/radon/classes/StringDecryptor.java +++ b/src/main/java/me/itzsomebody/radon/generate/StringDecryptorGenerator.java @@ -15,7 +15,7 @@ * along with this program. If not, see */ -package me.itzsomebody.radon.classes; +package me.itzsomebody.radon.generate; import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; import org.objectweb.asm.FieldVisitor; @@ -25,7 +25,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; -public class StringDecryptor implements Opcodes { +public class StringDecryptorGenerator implements Opcodes { public static ClassNode heavyStringDecryptor(HeavyStringEncryption.MemberNames memberNames) { ClassNode cw = new ClassNode(); FieldVisitor fv; diff --git a/src/main/java/me/itzsomebody/radon/methods/StringEncryptionGenerator.java b/src/main/java/me/itzsomebody/radon/generate/StringEncryptionGenerator.java similarity index 99% rename from src/main/java/me/itzsomebody/radon/methods/StringEncryptionGenerator.java rename to src/main/java/me/itzsomebody/radon/generate/StringEncryptionGenerator.java index 8a8a8575..3e608e5b 100644 --- a/src/main/java/me/itzsomebody/radon/methods/StringEncryptionGenerator.java +++ b/src/main/java/me/itzsomebody/radon/generate/StringEncryptionGenerator.java @@ -15,7 +15,7 @@ * along with this program. If not, see */ -package me.itzsomebody.radon.methods; +package me.itzsomebody.radon.generate; import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java index 2f3a8785..1cddda23 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java @@ -20,8 +20,7 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.classes.InvokeDynamicBootstrap; -import me.itzsomebody.radon.transformers.AbstractTransformer; +import me.itzsomebody.radon.generate.InvokeDynamicBootstrapGenerator; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.StringUtils; import org.objectweb.asm.Handle; @@ -159,7 +158,7 @@ && hasInstructions(methodNode)).forEach(methodNode -> { }) ); - ClassNode decryptor = InvokeDynamicBootstrap.heavyBootstrap(memberNames); + ClassNode decryptor = InvokeDynamicBootstrapGenerator.heavyBootstrap(memberNames); this.getClassMap().put(decryptor.name, decryptor); this.logStrings.add(LoggerUtils.stdOut("Hid " + counter + " field and/or method accesses with invokedynamics.")); this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java index 9f7f716d..e4d5bb3d 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java @@ -19,7 +19,7 @@ import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.methods.InvokeDynamicBSMGenerator; +import me.itzsomebody.radon.generate.InvokeDynamicBSMGenerator; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java index e0acb563..c783d996 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java +++ b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java @@ -17,7 +17,7 @@ package me.itzsomebody.radon.transformers.invokedynamic; -import me.itzsomebody.radon.methods.InvokeDynamicBSMGenerator; +import me.itzsomebody.radon.generate.InvokeDynamicBSMGenerator; import me.itzsomebody.radon.utils.BytecodeUtils; import org.objectweb.asm.tree.*; diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java index cf65af1f..8c59f174 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java @@ -19,8 +19,8 @@ import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.classes.StringDecryptor; -import me.itzsomebody.radon.methods.StringEncryptionGenerator; +import me.itzsomebody.radon.generate.StringDecryptorGenerator; +import me.itzsomebody.radon.generate.StringEncryptionGenerator; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.NumberUtils; @@ -79,7 +79,7 @@ && hasInstructions(methodNode)).forEach(methodNode -> { }) ); // Add decrypt method - ClassNode decryptor = StringDecryptor.heavyStringDecryptor(memberNames); + ClassNode decryptor = StringDecryptorGenerator.heavyStringDecryptor(memberNames); getClassMap().put(decryptor.name, decryptor); // Do logging logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java index f2460b52..02da5180 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java @@ -17,7 +17,7 @@ package me.itzsomebody.radon.transformers.stringencryption; -import me.itzsomebody.radon.methods.StringEncryptionGenerator; +import me.itzsomebody.radon.generate.StringEncryptionGenerator; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.NumberUtils; import me.itzsomebody.radon.utils.StringUtils; diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java index 6726f23a..4eda05b3 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java @@ -17,7 +17,7 @@ package me.itzsomebody.radon.transformers.stringencryption; -import me.itzsomebody.radon.methods.StringEncryptionGenerator; +import me.itzsomebody.radon.generate.StringEncryptionGenerator; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.NumberUtils; diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/VeryLightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/VeryLightStringEncryption.java index e2476820..1fa06cbd 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/VeryLightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/VeryLightStringEncryption.java @@ -19,7 +19,7 @@ import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.methods.StringEncryptionGenerator; +import me.itzsomebody.radon.generate.StringEncryptionGenerator; import me.itzsomebody.radon.transformers.AbstractTransformer; import me.itzsomebody.radon.utils.BytecodeUtils; import me.itzsomebody.radon.utils.LoggerUtils; From b32bdfb2a7b9c0c81a044da309ab095519715650 Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 21:32:17 -0400 Subject: [PATCH 050/281] Minor cleaning of Bootstrap --- .../itzsomebody/radon/internal/Bootstrap.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index 7ea0ee0c..18c5cee0 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -372,9 +372,6 @@ private void init() throws RuntimeException { AbstractTransformer transformer; // Specific order of adding transformers, feel free to change if // you wish. - if ((transformer = this.config.getRenamerType()) != null) { - this.transformers.add(transformer); - } if ((transformer = this.config.getInnerClassRemoverType()) != null) { this.transformers.add(transformer); } @@ -403,20 +400,16 @@ private void init() throws RuntimeException { if ((transformer = this.config.getShufflerType()) != null) { this.transformers.add(transformer); } - if ((transformer = this.config.getLocalVariableObfuscationType()) - != null) { + if ((transformer = this.config.getLocalVariableObfuscationType()) != null) { this.transformers.add(transformer); } - if ((transformer = this.config.getLineNumberObfuscationType()) != - null) { + if ((transformer = this.config.getLineNumberObfuscationType()) != null) { this.transformers.add(transformer); } - if ((transformer = this.config.getSourceNameObfuscationType()) != - null) { + if ((transformer = this.config.getSourceNameObfuscationType()) != null) { this.transformers.add(transformer); } - if ((transformer = this.config.getSourceDebugObfuscationType()) - != null) { + if ((transformer = this.config.getSourceDebugObfuscationType()) != null) { this.transformers.add(transformer); } if ((transformer = this.config.getCrasherType()) != null) { @@ -425,6 +418,11 @@ private void init() throws RuntimeException { if ((transformer = this.config.getHideCodeType()) != null) { this.transformers.add(transformer); } + // This is last to prevent confusing logic when looking up values in the name-to-node map + // returning nodes that have their names not matching the key. + if ((transformer = this.config.getRenamerType()) != null) { + this.transformers.add(transformer); + } this.trashClasses = this.config.getTrashClasses(); this.watermarkMsg = this.config.getWatermarkMsg(); this.watermarkType = this.config.getWatermarkType(); From ff96231d5053a1098d0541dae13bd3b33ef5647c Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 21:55:50 -0400 Subject: [PATCH 051/281] Remove unused method --- .../radon/utils/BytecodeUtils.java | 329 ------------------ 1 file changed, 329 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java index b63657f4..68f6b3a1 100644 --- a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java @@ -255,333 +255,4 @@ public static boolean hasAnnotations(FieldNode fieldNode) { public static boolean hasAnnotations(ClassNode classNode) { return classNode.visibleAnnotations != null && !classNode.visibleAnnotations.isEmpty(); } - - // TODO: Unused, this can be removed. - /** - * Returns a {@link String} representation of inputted opcode. - * - * @param opcode the opcode to get a name from. - * @return a {@link String} representation of inputted opcode. - */ - public static String getOpcodeName(int opcode) { - switch (opcode) { - case Opcodes.NOP: - return "nop"; - case Opcodes.ACONST_NULL: - return "aconst_null"; - case Opcodes.ICONST_M1: - return "iconst_m1"; - case Opcodes.ICONST_0: - return "iconst_0"; - case Opcodes.ICONST_1: - return "iconst_1"; - case Opcodes.ICONST_2: - return "iconst_2"; - case Opcodes.ICONST_3: - return "iconst_3"; - case Opcodes.ICONST_4: - return "iconst_4"; - case Opcodes.ICONST_5: - return "iconst_5"; - case Opcodes.LCONST_0: - return "lconst_0"; - case Opcodes.LCONST_1: - return "lconst_1"; - case Opcodes.FCONST_0: - return "fconst_0"; - case Opcodes.FCONST_1: - return "fconst_1"; - case Opcodes.FCONST_2: - return "fconst_2"; - case Opcodes.DCONST_0: - return "dconst_0"; - case Opcodes.DCONST_1: - return "dconst_1"; - case Opcodes.BIPUSH: - return "bipush"; - case Opcodes.SIPUSH: - return "sipush"; - case Opcodes.LDC: - return "ldc"; - case Opcodes.ILOAD: - return "iload"; - case Opcodes.LLOAD: - return "lload"; - case Opcodes.FLOAD: - return "fload"; - case Opcodes.DLOAD: - return "dload"; - case Opcodes.ALOAD: - return "aload"; - case Opcodes.IALOAD: - return "iaload"; - case Opcodes.LALOAD: - return "laload"; - case Opcodes.FALOAD: - return "faload"; - case Opcodes.DALOAD: - return "daload"; - case Opcodes.AALOAD: - return "aaload"; - case Opcodes.BALOAD: - return "baload"; - case Opcodes.CALOAD: - return "caload"; - case Opcodes.SALOAD: - return "saload"; - case Opcodes.ISTORE: - return "istore"; - case Opcodes.LSTORE: - return "lstore"; - case Opcodes.FSTORE: - return "fstore"; - case Opcodes.DSTORE: - return "dstore"; - case Opcodes.ASTORE: - return "astore"; - case Opcodes.IASTORE: - return "iastore"; - case Opcodes.LASTORE: - return "lastore"; - case Opcodes.FASTORE: - return "fastore"; - case Opcodes.DASTORE: - return "dastore"; - case Opcodes.AASTORE: - return "aastore"; - case Opcodes.BASTORE: - return "bastore"; - case Opcodes.CASTORE: - return "castore"; - case Opcodes.SASTORE: - return "sastore"; - case Opcodes.POP: - return "pop"; - case Opcodes.POP2: - return "pop2"; - case Opcodes.DUP: - return "dup"; - case Opcodes.DUP_X1: - return "dup_x1"; - case Opcodes.DUP_X2: - return "dup_x2"; - case Opcodes.DUP2: - return "dup2"; - case Opcodes.DUP2_X1: - return "dup2_x1"; - case Opcodes.DUP2_X2: - return "dup2_x2"; - case Opcodes.SWAP: - return "swap"; - case Opcodes.IADD: - return "iadd"; - case Opcodes.LADD: - return "ladd"; - case Opcodes.FADD: - return "fadd"; - case Opcodes.DADD: - return "dadd"; - case Opcodes.ISUB: - return "isub"; - case Opcodes.LSUB: - return "lsub"; - case Opcodes.FSUB: - return "fsub"; - case Opcodes.DSUB: - return "dsub"; - case Opcodes.IMUL: - return "imul"; - case Opcodes.LMUL: - return "lmul"; - case Opcodes.FMUL: - return "fmul"; - case Opcodes.DMUL: - return "dmul"; - case Opcodes.IDIV: - return "idiv"; - case Opcodes.LDIV: - return "ldiv"; - case Opcodes.FDIV: - return "fdiv"; - case Opcodes.DDIV: - return "ddiv"; - case Opcodes.IREM: - return "irem"; - case Opcodes.LREM: - return "lrem"; - case Opcodes.FREM: - return "frem"; - case Opcodes.DREM: - return "drem"; - case Opcodes.INEG: - return "ineg"; - case Opcodes.LNEG: - return "lneg"; - case Opcodes.FNEG: - return "fneg"; - case Opcodes.DNEG: - return "dneg"; - case Opcodes.ISHL: - return "ishl"; - case Opcodes.LSHL: - return "lshl"; - case Opcodes.ISHR: - return "ishr"; - case Opcodes.LSHR: - return "lshr"; - case Opcodes.IUSHR: - return "iushr"; - case Opcodes.LUSHR: - return "lushr"; - case Opcodes.IAND: - return "iand"; - case Opcodes.LAND: - return "land"; - case Opcodes.IOR: - return "ior"; - case Opcodes.LOR: - return "lor"; - case Opcodes.IXOR: - return "ixor"; - case Opcodes.LXOR: - return "lxor"; - case Opcodes.IINC: - return "iinc"; - case Opcodes.I2L: - return "i2l"; - case Opcodes.I2F: - return "i2f"; - case Opcodes.I2D: - return "i2d"; - case Opcodes.L2I: - return "l2i"; - case Opcodes.L2F: - return "l2f"; - case Opcodes.L2D: - return "l2d"; - case Opcodes.F2I: - return "f2i"; - case Opcodes.F2L: - return "f2l"; - case Opcodes.F2D: - return "f2d"; - case Opcodes.D2I: - return "d2i"; - case Opcodes.D2L: - return "d2l"; - case Opcodes.D2F: - return "d2f"; - case Opcodes.I2B: - return "i2b"; - case Opcodes.I2C: - return "i2c"; - case Opcodes.I2S: - return "i2s"; - case Opcodes.LCMP: - return "lcmp"; - case Opcodes.FCMPL: - return "fcmpl"; - case Opcodes.FCMPG: - return "fcmpg"; - case Opcodes.DCMPL: - return "dcmpl"; - case Opcodes.DCMPG: - return "dcmpg"; - case Opcodes.IFEQ: - return "ifeq"; - case Opcodes.IFNE: - return "ifne"; - case Opcodes.IFLT: - return "iflt"; - case Opcodes.IFGE: - return "ifge"; - case Opcodes.IFGT: - return "ifgt"; - case Opcodes.IFLE: - return "ifle"; - case Opcodes.IF_ICMPEQ: - return "if_icmpeq"; - case Opcodes.IF_ICMPNE: - return "if_icmpne"; - case Opcodes.IF_ICMPLT: - return "if_icmplt"; - case Opcodes.IF_ICMPGE: - return "if_icmpge"; - case Opcodes.IF_ICMPGT: - return "if_icmpgt"; - case Opcodes.IF_ICMPLE: - return "if_icmple"; - case Opcodes.IF_ACMPEQ: - return "if_acmpeq"; - case Opcodes.IF_ACMPNE: - return "if_acmpne"; - case Opcodes.GOTO: - return "goto"; - case Opcodes.JSR: - return "jsr"; - case Opcodes.RET: - return "ret"; - case Opcodes.TABLESWITCH: - return "tableswitch"; - case Opcodes.LOOKUPSWITCH: - return "lookupswitch"; - case Opcodes.IRETURN: - return "ireturn"; - case Opcodes.LRETURN: - return "lreturn"; - case Opcodes.FRETURN: - return "freturn"; - case Opcodes.DRETURN: - return "dreturn"; - case Opcodes.ARETURN: - return "areturn"; - case Opcodes.RETURN: - return "return"; - case Opcodes.GETSTATIC: - return "getstatic"; - case Opcodes.PUTSTATIC: - return "putstatic"; - case Opcodes.GETFIELD: - return "getfield"; - case Opcodes.PUTFIELD: - return "putfield"; - case Opcodes.INVOKEVIRTUAL: - return "invokevirtual"; - case Opcodes.INVOKESPECIAL: - return "invokespecial"; - case Opcodes.INVOKESTATIC: - return "invokestatic"; - case Opcodes.INVOKEINTERFACE: - return "invokeinterface"; - case Opcodes.INVOKEDYNAMIC: - return "invokedynamic"; - case Opcodes.NEW: - return "new"; - case Opcodes.NEWARRAY: - return "newarray"; - case Opcodes.ANEWARRAY: - return "anewarray"; - case Opcodes.ARRAYLENGTH: - return "arraylength"; - case Opcodes.ATHROW: - return "athrow"; - case Opcodes.CHECKCAST: - return "checkcast"; - case Opcodes.INSTANCEOF: - return "instanceof"; - case Opcodes.MONITORENTER: - return "monitorenter"; - case Opcodes.MONITOREXIT: - return "monitorexit"; - case Opcodes.MULTIANEWARRAY: - return "multianewarray"; - case Opcodes.IFNULL: - return "ifnull"; - case Opcodes.IFNONNULL: - return "ifnonnull"; - case -1: - return "debugging"; - } - throw new IllegalArgumentException("Unknown opcode"); - } } From 95e65c727de67a3062b910c149d5e911a28e0ee8 Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 21:56:12 -0400 Subject: [PATCH 052/281] Fix issue with Manifest breaking with renaming --- .../itzsomebody/radon/transformers/renamer/Renamer.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java index 59d8a1ea..8b8cc6f2 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java @@ -143,13 +143,15 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("Attempting to map class names in resources")); AtomicInteger fixed = new AtomicInteger(); getPassThru().forEach((name, byteArray) -> { - // TODO: If the class name is "Main" (in default package) then this breaks the manifest. if (name.equals("META-INF/MANIFEST.MF") || (name.equals("plugin.yml") && spigotMode)) { String stringVer = new String(byteArray); for (String mapping : mappings.keySet()) { - if (stringVer.contains(mapping.replace("/", "."))) { - stringVer = stringVer.replace(mapping.replace("/", "."), mappings.get(mapping).replace("/", ".")); + String original = mapping.replace("/", "."); + if (stringVer.contains(original)) { + // Regex that ensures that class names that match words in the manifest don't break the manifest + // Example: name == Main + stringVer = stringVer.replaceAll("(?<=[: ])" + original, mappings.get(mapping).replace("/", ".")); } } From ea3fde8df9b0be96ccfcc06c41b75d72ddec1f90 Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 22:03:23 -0400 Subject: [PATCH 053/281] No IntelliJ, I did not want you to rename those strings... --- src/main/java/me/itzsomebody/radon/gui/MainGUI.java | 4 ++-- .../transformers/stringencryption/HeavyStringEncryption.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java index f1744e27..5d8f0e72 100644 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java @@ -959,7 +959,7 @@ private void initialize() { gbc_comboBox_04.fill = GridBagConstraints.HORIZONTAL; gbc_comboBox_04.gridx = 1; gbc_comboBox_04.gridy = 12; - String[] options = {"Class", "Method", "Field", "StringEncryptionGenerator", "InvokeDynamic", + String[] options = {"Class", "Method", "Field", "StringEncryption", "InvokeDynamic", "Flow", "LocalVars", "SourceName", "SourceDebug", "LineNumbers", "StringPool", "Crasher", "HideCode", "Numbers", "Shuffler", "InnerClasses", "Renamer", "Expiry"}; @@ -1009,7 +1009,7 @@ private void initialize() { exemptList.addElement("Field: " + exemptField.getText()); exemptField.setText(""); } else if (comboBox_04.getSelectedIndex() == 3) { - exemptList.addElement("StringEncryptionGenerator: " + exemptField.getText()); + exemptList.addElement("StringEncryption: " + exemptField.getText()); exemptField.setText(""); } else if (comboBox_04.getSelectedIndex() == 4) { exemptList.addElement("InvokeDynamic: " + exemptField.getText()); diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java index 8c59f174..ce4f6eee 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java @@ -50,9 +50,9 @@ public void obfuscate() { MemberNames memberNames = new MemberNames(this); this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started heavy string encryption transformer")); - this.classNodes().parallelStream().filter(classNode -> !this.exempted(classNode.name, "StringEncryptionGenerator")).forEach(classNode -> + this.classNodes().parallelStream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> classNode.methods.parallelStream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryptionGenerator") + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (methodSize(methodNode) > 60000) break; From fb0f680c4efe4b9e35998c70c15bf56dc2d311cf Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 22:05:20 -0400 Subject: [PATCH 054/281] Revert accidental rename --- src/main/java/me/itzsomebody/radon/config/Config.java | 4 ++-- .../radon/generate/StringEncryptionGenerator.java | 6 +++--- src/main/java/me/itzsomebody/radon/gui/MainGUI.java | 6 +++--- .../stringencryption/HeavyStringEncryption.java | 2 +- .../stringencryption/LightStringEncryption.java | 2 +- .../stringencryption/NormalStringEncryption.java | 2 +- ...tringEncryption.java => SuperLightStringEncryption.java} | 4 ++-- src/main/java/me/itzsomebody/radon/utils/StringUtils.java | 6 +++--- 8 files changed, 16 insertions(+), 16 deletions(-) rename src/main/java/me/itzsomebody/radon/transformers/stringencryption/{VeryLightStringEncryption.java => SuperLightStringEncryption.java} (97%) diff --git a/src/main/java/me/itzsomebody/radon/config/Config.java b/src/main/java/me/itzsomebody/radon/config/Config.java index b7056342..52ec8332 100644 --- a/src/main/java/me/itzsomebody/radon/config/Config.java +++ b/src/main/java/me/itzsomebody/radon/config/Config.java @@ -51,7 +51,7 @@ import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.VeryLightStringEncryption; +import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; import org.yaml.snakeyaml.Yaml; /** @@ -399,7 +399,7 @@ public AbstractTransformer getStringEncryptionType() " must be a string"); String s = (String) value; if (s.equalsIgnoreCase("SuperLight")) { - return new VeryLightStringEncryption(this.getSpigotBool()); + return new SuperLightStringEncryption(this.getSpigotBool()); } else if (s.equalsIgnoreCase("Light")) { return new LightStringEncryption(this.getSpigotBool()); } else if (s.equalsIgnoreCase("Normal")) { diff --git a/src/main/java/me/itzsomebody/radon/generate/StringEncryptionGenerator.java b/src/main/java/me/itzsomebody/radon/generate/StringEncryptionGenerator.java index 3e608e5b..a68fb5a9 100644 --- a/src/main/java/me/itzsomebody/radon/generate/StringEncryptionGenerator.java +++ b/src/main/java/me/itzsomebody/radon/generate/StringEncryptionGenerator.java @@ -19,7 +19,7 @@ import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.VeryLightStringEncryption; +import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.MethodNode; @@ -34,12 +34,12 @@ public class StringEncryptionGenerator implements Opcodes { /** * Returns a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link VeryLightStringEncryption}. + * decrypt strings encrypted by {@link SuperLightStringEncryption}. * * @param decryptionMethodName used to determine the name of the * generated {@link MethodNode}. * @return a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link VeryLightStringEncryption}. + * decrypt strings encrypted by {@link SuperLightStringEncryption}. */ public static MethodNode superLightMethod(String decryptionMethodName) { MethodNode mv = new MethodNode(ACC_PUBLIC + ACC_STATIC diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java index 5d8f0e72..6ade9d0d 100644 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java @@ -59,7 +59,7 @@ import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.VeryLightStringEncryption; +import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; import me.itzsomebody.radon.utils.WatermarkUtils; @@ -1245,7 +1245,7 @@ protected Object doInBackground() { if (chckbxStringEncryption.isSelected()) { switch (comboBox.getSelectedIndex()) { case 0: - transformers.add(new VeryLightStringEncryption(spigotMode)); + transformers.add(new SuperLightStringEncryption(spigotMode)); break; case 1: transformers.add(new LightStringEncryption(spigotMode)); @@ -1426,7 +1426,7 @@ protected Object doInBackground() { if (stringEncryptionMode == null) { chckbxStringEncryption.setSelected(false); } else if (stringEncryptionMode - instanceof VeryLightStringEncryption) { + instanceof SuperLightStringEncryption) { chckbxStringEncryption.setSelected(true); comboBox.setSelectedIndex(0); comboBox.setEnabled(true); diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java index ce4f6eee..12521e3b 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java @@ -28,7 +28,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.*; -public class HeavyStringEncryption extends VeryLightStringEncryption { +public class HeavyStringEncryption extends SuperLightStringEncryption { /** * Constructor used to create a {@link HeavyStringEncryption} object. * diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java index 02da5180..3cf439ca 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java @@ -29,7 +29,7 @@ * * @author ItzSomebody */ -public class LightStringEncryption extends VeryLightStringEncryption { +public class LightStringEncryption extends SuperLightStringEncryption { /** * Constructor used to create a {@link LightStringEncryption} object. * diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java index 4eda05b3..d1e133b0 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java @@ -31,7 +31,7 @@ * * @author ItzSomebody */ -public class NormalStringEncryption extends VeryLightStringEncryption { +public class NormalStringEncryption extends SuperLightStringEncryption { /** * Constructor used to create a {@link NormalStringEncryption} object. * diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/VeryLightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java similarity index 97% rename from src/main/java/me/itzsomebody/radon/transformers/stringencryption/VeryLightStringEncryption.java rename to src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java index 1fa06cbd..6b3d5e34 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/VeryLightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java @@ -32,7 +32,7 @@ * * @author ItzSomebody */ -public class VeryLightStringEncryption extends AbstractTransformer { +public class SuperLightStringEncryption extends AbstractTransformer { /** * Length of names to generate. */ @@ -49,7 +49,7 @@ public class VeryLightStringEncryption extends AbstractTransformer { * placeholders (%%__USER__%%, %%__RESOURCE__%% * and %%__NONCE__%%). */ - public VeryLightStringEncryption(boolean spigotMode) { + public SuperLightStringEncryption(boolean spigotMode) { this.spigotMode = spigotMode; } diff --git a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java index 8a7646f1..cc3f9284 100644 --- a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java +++ b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java @@ -28,7 +28,7 @@ import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.VeryLightStringEncryption; +import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; /** * Utils for operating, and generating {@link String}s. @@ -110,11 +110,11 @@ public static String crazyKey(int len) { } /** - * Returns an encrypted string used by {@link VeryLightStringEncryption}. + * Returns an encrypted string used by {@link SuperLightStringEncryption}. * * @param msg string to encrypt. * @param key random integer - * @return an encrypted string used by {@link VeryLightStringEncryption}. + * @return an encrypted string used by {@link SuperLightStringEncryption}. */ public static String superLightEncrypt(String msg, int key) { char[] encryptedArray = msg.toCharArray(); From 78ac70ef6f4d9f296abd43d21b0190ee75307989 Mon Sep 17 00:00:00 2001 From: Col-E Date: Thu, 19 Jul 2018 22:08:22 -0400 Subject: [PATCH 055/281] That should be it for fixing accidental IntelliJ renames --- src/main/java/me/itzsomebody/radon/config/Config.java | 8 ++++---- src/main/java/me/itzsomebody/radon/config/ConfigEnum.java | 2 +- .../radon/generate/StringEncryptionGenerator.java | 2 +- .../stringencryption/SuperLightStringEncryption.java | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/config/Config.java b/src/main/java/me/itzsomebody/radon/config/Config.java index 52ec8332..ab69a0ee 100644 --- a/src/main/java/me/itzsomebody/radon/config/Config.java +++ b/src/main/java/me/itzsomebody/radon/config/Config.java @@ -333,8 +333,8 @@ public void sortExempts() throws IllegalArgumentException { this.methodExempts.add(exempt.replace("Method: ", "")); } else if (exempt.startsWith("Field: ")) { this.fieldExempts.add(exempt.replace("Field: ", "")); - } else if (exempt.startsWith("StringEncryptionGenerator: ")) { - this.stringEncExempts.add(exempt.replace("StringEncryptionGenerator: ", "")); + } else if (exempt.startsWith("StringEncryption: ")) { + this.stringEncExempts.add(exempt.replace("StringEncryption: ", "")); } else if (exempt.startsWith("InvokeDynamic: ")) { this.indyExempts.add(exempt.replace("InvokeDynamic: ", "")); } else if (exempt.startsWith("Flow: ")) { @@ -391,8 +391,8 @@ public List getExempts() { */ public AbstractTransformer getStringEncryptionType() throws IllegalArgumentException { - if (this.map.containsKey("StringEncryptionGenerator")) { - Object value = this.map.get("StringEncryptionGenerator"); + if (this.map.containsKey("StringEncryption")) { + Object value = this.map.get("StringEncryption"); if (value != null) { if (!(value instanceof String)) throw new IllegalArgumentException("String encryption arg" + diff --git a/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java b/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java index ed430e9b..aa8ec372 100644 --- a/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java +++ b/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java @@ -27,7 +27,7 @@ public enum ConfigEnum { OUTPUT("Output"), LIBRARIES("Libraries"), EXEMPTS("Exempts"), - STRING_ENCRYPTION("StringEncryptionGenerator"), + STRING_ENCRYPTION("StringEncryption"), FLOW_OBFUSCATION("FlowObfuscation"), INVOKEDYNAMIC("InvokeDynamic"), LOCAL_VARIABLES("LocalVariableObfuscation"), diff --git a/src/main/java/me/itzsomebody/radon/generate/StringEncryptionGenerator.java b/src/main/java/me/itzsomebody/radon/generate/StringEncryptionGenerator.java index a68fb5a9..fb1e68f8 100644 --- a/src/main/java/me/itzsomebody/radon/generate/StringEncryptionGenerator.java +++ b/src/main/java/me/itzsomebody/radon/generate/StringEncryptionGenerator.java @@ -26,7 +26,7 @@ /** * Class containing {@link MethodNode}s needed to decrypt a {@link String} for the - * appropriate StringEncryptionGenerator transformer. + * appropriate StringEncryption transformer. * * @author ItzSomebody * @author ASMifier by OW2 diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java index 6b3d5e34..00846ee0 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java +++ b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java @@ -62,9 +62,9 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Started string encryption transformer")); String[] decryptorPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary, len)}; - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryptionGenerator")).forEach(classNode -> { + this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> { classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryptionGenerator") + !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") && hasInstructions(methodNode)).forEach(methodNode -> { for (AbstractInsnNode insn : methodNode.instructions.toArray()) { if (methodSize(methodNode) > 60000) break; From 990096afcf9f89952f60664cd16bd26cce758d72 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Wed, 1 Aug 2018 19:42:50 -0700 Subject: [PATCH 056/281] Some random changes which I forgot that I made --- .../me/itzsomebody/radon/config/Config.java | 2 +- .../me/itzsomebody/radon/gui/MainGUI.java | 2 +- .../itzsomebody/radon/internal/Bootstrap.java | 214 +++++++++--------- .../transformers/AbstractTransformer.java | 2 +- .../flow/HeavyFlowObfuscation.java | 1 - .../flow/NormalFlowObfuscation.java | 1 - .../{renamer => misc}/Renamer.java | 78 ++----- 7 files changed, 121 insertions(+), 179 deletions(-) rename src/main/java/me/itzsomebody/radon/transformers/{renamer => misc}/Renamer.java (80%) diff --git a/src/main/java/me/itzsomebody/radon/config/Config.java b/src/main/java/me/itzsomebody/radon/config/Config.java index 4b0b079a..b7b20e82 100644 --- a/src/main/java/me/itzsomebody/radon/config/Config.java +++ b/src/main/java/me/itzsomebody/radon/config/Config.java @@ -43,7 +43,7 @@ import me.itzsomebody.radon.transformers.misc.NumberObfuscation; import me.itzsomebody.radon.transformers.misc.Shuffler; import me.itzsomebody.radon.transformers.misc.StringPool; -import me.itzsomebody.radon.transformers.renamer.Renamer; +import me.itzsomebody.radon.transformers.misc.Renamer; import me.itzsomebody.radon.transformers.sourcedebug.ObfuscateSourceDebug; import me.itzsomebody.radon.transformers.sourcedebug.RemoveSourceDebug; import me.itzsomebody.radon.transformers.sourcename.ObfuscateSourceName; diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java index e6ca7354..33c743d0 100644 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java @@ -50,7 +50,7 @@ import me.itzsomebody.radon.transformers.misc.NumberObfuscation; import me.itzsomebody.radon.transformers.misc.Shuffler; import me.itzsomebody.radon.transformers.misc.StringPool; -import me.itzsomebody.radon.transformers.renamer.Renamer; +import me.itzsomebody.radon.transformers.misc.Renamer; import me.itzsomebody.radon.transformers.sourcedebug.ObfuscateSourceDebug; import me.itzsomebody.radon.transformers.sourcedebug.RemoveSourceDebug; import me.itzsomebody.radon.transformers.sourcename.ObfuscateSourceName; diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index db413c49..b8f34a9b 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; @@ -49,7 +50,6 @@ /** * Bootstraps and runs the obfuscation process. - * TODO: Create class hierarchy more efficiently. * FIXME: Renaming classes causes exempts on other classes to not work. * * @author ItzSomebody @@ -205,12 +205,10 @@ public void startTheParty(boolean doInit) throws Throwable { this.logStrings = new ArrayList<>(); if (doInit) { this.init(); - this.logStrings.add(LoggerUtils.stdOut("Successfully parsed " + - "config")); + this.logStrings.add(LoggerUtils.stdOut("Successfully parsed config")); } else { if (output.exists()) { - logStrings.add(LoggerUtils.stdOut("Output already exists, renamed to " - + FileUtils.renameExistingFile(output))); + logStrings.add(LoggerUtils.stdOut("Output already exists, renamed to " + FileUtils.renameExistingFile(output))); } this.zos = new ZipOutputStream(new FileOutputStream(output)); } @@ -237,13 +235,9 @@ public void startTheParty(boolean doInit) throws Throwable { ClassNode classNode = trashClass.returnTrashClass(); this.extraClasses.put(classNode.name, classNode); } - this.logStrings.add(LoggerUtils.stdOut("Generated " - + String.valueOf(this.trashClasses) + " trash classes")); + this.logStrings.add(LoggerUtils.stdOut("Generated " + String.valueOf(this.trashClasses) + " trash classes")); } - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.createTrees(); - if (this.extraClasses.values().size() != 0) { this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Writing generated classes to output")); @@ -266,45 +260,27 @@ public void startTheParty(boolean doInit) throws Throwable { this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Writing classes to output")); for (ClassNode classNode : this.classes.values()) { - ClassWriter cw; - - if (classNode.version > Opcodes.V1_5) { - cw = new CustomClassWriter(ClassWriter.COMPUTE_FRAMES); - } else { - cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); - } + ClassWriter cw = new CustomClassWriter(ClassWriter.COMPUTE_FRAMES); try { classNode.accept(cw); if (this.watermarkMsg != null) { - if (this.watermarkType == 0 - && NumberUtils.getRandomInt(10) >= 5) { - cw.newUTF8("WMID: " - + StringUtils.aesEncrypt(this.watermarkMsg, this.watermarkKey)); - - this.logStrings.add(LoggerUtils.stdOut("Watermarking " - + this.watermarkMsg + " into " + classNode.name)); - } else if (this.watermarkType == 1 - && NumberUtils.getRandomInt(10) >= 5) { - classNode.signature = - StringUtils.aesEncrypt("WMID: " + this.watermarkMsg, - this.watermarkKey); - - this.logStrings.add(LoggerUtils.stdOut("Watermarking " - + this.watermarkMsg + " into " + classNode.name)); + if (this.watermarkType == 0 && NumberUtils.getRandomInt(10) >= 5) { + cw.newUTF8("WMID: " + StringUtils.aesEncrypt(this.watermarkMsg, this.watermarkKey)); + this.logStrings.add(LoggerUtils.stdOut("Watermarking " + this.watermarkMsg + " into " + classNode.name)); + } else if (this.watermarkType == 1 && NumberUtils.getRandomInt(10) >= 5) { + classNode.signature = StringUtils.aesEncrypt("WMID: " + this.watermarkMsg, this.watermarkKey); + this.logStrings.add(LoggerUtils.stdOut("Watermarking " + this.watermarkMsg + " into " + classNode.name)); } } cw.newUTF8("RADON" + Radon.VERSION); // :D } catch (Throwable t) { - this.logStrings.add(LoggerUtils - .stdOut("Error while writing " - + classNode.name + " -> " + t.getMessage())); + this.logStrings.add(LoggerUtils.stdOut("Error while writing " + classNode.name + " -> " + t.getMessage())); throw t; } - ZipEntry newEntry = new ZipEntry(classNode.name - + ".class"); + ZipEntry newEntry = new ZipEntry(classNode.name + ".class"); newEntry.setTime(currentTime); newEntry.setCompressedSize(-1); this.zos.putNextEntry(newEntry); @@ -437,8 +413,7 @@ private void init() throws RuntimeException { this.zos = new ZipOutputStream(new FileOutputStream(this.output)); } catch (Throwable t) { t.printStackTrace(); - throw new RuntimeException("Error while loading config: " - + t.getMessage()); + throw new RuntimeException("Error while loading config: " + t.getMessage()); } } @@ -461,14 +436,14 @@ private void loadClassPath() throws RuntimeException { while (entries.hasMoreElements()) { zipEntry = entries.nextElement(); if (zipEntry.getName().endsWith(".class") && !zipEntry.isDirectory()) { - ClassReader cr = new ClassReader(zipFile - .getInputStream(zipEntry)); + ClassReader cr = new ClassReader(zipFile.getInputStream(zipEntry)); ClassNode classNode = new ClassNode(); classNode.libraryNode = true; - // We don't need code in methods for libs - cr.accept(classNode, ClassReader.SKIP_DEBUG | - ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE); + cr.accept(classNode, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE); + classNode.methods.forEach(methodNode -> methodNode.owner = classNode.name); + classNode.fields.forEach(fieldNode -> fieldNode.owner = classNode.name); + this.classPath.put(classNode.name, classNode); @@ -476,11 +451,9 @@ private void loadClassPath() throws RuntimeException { } zipFile.close(); } catch (ZipException ze) { - throw new RuntimeException("There was an error opening " - + lib.getAbsolutePath() + " as a zip!"); + throw new RuntimeException("There was an error opening " + lib.getAbsolutePath() + " as a zip!"); } catch (IOException ioe) { - throw new RuntimeException("Library " + lib.getAbsolutePath() - + " does not exist!"); + throw new RuntimeException("Library " + lib.getAbsolutePath() + " does not exist!"); } } } @@ -497,21 +470,20 @@ private void loadInput() throws RuntimeException { Enumeration entries; ZipEntry zipEntry; try { - this.logStrings.add(LoggerUtils.stdOut("Loading classes of " - + this.input.getAbsolutePath())); + this.logStrings.add(LoggerUtils.stdOut("Loading classes of " + this.input.getAbsolutePath())); zipFile = new ZipFile(this.input); entries = zipFile.entries(); while (entries.hasMoreElements()) { zipEntry = entries.nextElement(); if (!zipEntry.isDirectory()) { if (zipEntry.getName().endsWith(".class")) { - ClassReader cr = new ClassReader(zipFile - .getInputStream(zipEntry)); + ClassReader cr = new ClassReader(zipFile.getInputStream(zipEntry)); ClassNode classNode = new ClassNode(); classNode.libraryNode = false; - // We will manually compute stack frames later cr.accept(classNode, ClassReader.SKIP_FRAMES); + classNode.methods.forEach(methodNode -> methodNode.owner = classNode.name); + classNode.fields.forEach(fieldNode -> fieldNode.owner = classNode.name); this.classes.put(classNode.name, classNode); } else { @@ -521,49 +493,90 @@ private void loadInput() throws RuntimeException { } zipFile.close(); } catch (ZipException ze) { - throw new RuntimeException("There was an error opening " - + this.input.getAbsolutePath() + " as a zip!"); + throw new RuntimeException("There was an error opening " + this.input.getAbsolutePath() + " as a zip!"); } catch (IOException ioe) { - throw new RuntimeException("Input " - + this.input.getAbsolutePath() + " does not exist!"); + throw new RuntimeException("Input " + this.input.getAbsolutePath() + " does not exist!"); } this.classPath.putAll(this.classes); } - /** - * Creates {@link ClassTree}s needed for renaming. - */ - private void createTrees() { - long executionTime = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("Creating class hierarchy.")); - classPath.values().forEach(classNode -> { - classNode.methods.forEach(methodNode -> - methodNode.owner = classNode.name - ); - classNode.fields.forEach(fieldNode -> - fieldNode.owner = classNode.name - ); - ClassTree classTree = new ClassTree(classNode.name, classNode.libraryNode); - classTree.parentClasses.add(classNode.superName); - classTree.parentClasses.addAll(classNode.interfaces); - classes.values().forEach(anotherClass -> { - if (anotherClass.interfaces != null - && anotherClass.interfaces.contains(classNode.name)) { - classTree.subClasses.add(anotherClass.name); + private void loadHierachyAll(ClassNode classNode) { + Set processed = new HashSet<>(); + LinkedList toLoad = new LinkedList<>(); + toLoad.add(classNode); + while (!toLoad.isEmpty()) { + for (ClassNode toProcess : loadHierachy(toLoad.poll())) { + if (processed.add(toProcess.name)) { + toLoad.add(toProcess); } + } + } + } - if (anotherClass.superName != null - && anotherClass.superName.equals(classNode.name)) { - classTree.subClasses.add(anotherClass.name); - } - }); + private ClassTree getOrCreateClassTree(String name) { + if (!this.hierarchy.containsKey(name)) { + this.hierarchy.put(name, new ClassTree(name, classPath.get(name).libraryNode)); + } + return this.hierarchy.get(name); + } + + private List loadHierachy(ClassNode specificNode) { + if (specificNode.name.equals("java/lang/Object")) { + return Collections.emptyList(); + } + if ((specificNode.access & Opcodes.ACC_INTERFACE) != 0) { + getOrCreateClassTree(specificNode.name).parentClasses.add("java/lang/Object"); + return Collections.emptyList(); + } + List toProcess = new ArrayList<>(); - classTree.methods.addAll(classNode.methods); - classTree.fields.addAll(classNode.fields); - hierarchy.put(classNode.name, classTree); - }); - this.logStrings.add(LoggerUtils.stdOut("Finished creating class hierarchy. [" + (System.currentTimeMillis() - executionTime) + "ms]")); + ClassTree thisTree = getOrCreateClassTree(specificNode.name); + ClassNode superClass = returnClazz(specificNode.superName); + if (superClass == null) { + throw new IllegalArgumentException("Could not load " + specificNode.name); + } + ClassTree superTree = getOrCreateClassTree(superClass.name); + superTree.subClasses.add(specificNode.name); + thisTree.parentClasses.add(superClass.name); + toProcess.add(superClass); + + for (String interfaceReference : specificNode.interfaces) { + ClassNode interfaceNode = returnClazz(interfaceReference); + if (interfaceNode == null) { + throw new IllegalArgumentException("Could not load " + interfaceReference); + } + ClassTree interfaceTree = getOrCreateClassTree(interfaceReference); + interfaceTree.subClasses.add(specificNode.name); + thisTree.parentClasses.add(interfaceReference); + toProcess.add(interfaceNode); + } + return toProcess; + } + + public ClassTree getClassTree(String classNode) { + ClassTree tree = this.hierarchy.get(classNode); + if (tree == null) { + loadHierachyAll(returnClazz(classNode)); + return getClassTree(classNode); + } + return tree; + } + + /** + * Returns the {@link ClassNode} object from {@link Bootstrap#classPath} + * if it exists. + * + * @param ref class name to fetch from {@link Bootstrap#classPath}. + * @return the {@link ClassNode} object from {@link Bootstrap#classPath} + * if it exists. + */ + private ClassNode returnClazz(String ref) { + ClassNode clazz = classPath.get(ref); + if (clazz == null) { + throw new RuntimeException(ref + " does not exist in classpath!"); + } + return clazz; } /** @@ -658,23 +671,6 @@ private String deriveCommonSuperName(String type1, String type2) { } } - /** - * Returns the {@link ClassNode} object from {@link Bootstrap#classPath} - * if it exists. - * - * @param ref class name to fetch from {@link Bootstrap#classPath}. - * @return the {@link ClassNode} object from {@link Bootstrap#classPath} - * if it exists. - */ - private ClassNode returnClazz(String ref) { - ClassNode clazz = classPath.get(ref); - if (clazz == null) { - throw new RuntimeException(ref - + " does not exist in classpath!"); - } - return clazz; - } - /** * Returns true/false based on if clazz1 is the superclass of clazz2. * @@ -689,16 +685,16 @@ private boolean isAssignableFrom(ClassNode clazz1, ClassNode clazz2) { if (clazz1.name.equals(clazz2.name)) { return true; } - ClassTree firstTree = hierarchy.get(clazz1.name); - if (firstTree == null) { - throw new RuntimeException("Could not find " + clazz1.name + " in the built class hiearchy"); - } + ClassTree firstTree = getClassTree(clazz1.name); + //if (firstTree == null) { + // throw new RuntimeException("Could not find " + clazz1.name + " in the built class hiearchy"); + //} Set children = new HashSet<>(); LinkedList searchThese = new LinkedList<>(firstTree.subClasses); while (!searchThese.isEmpty()) { String s = searchThese.poll(); if (children.add(s)) { - ClassTree tempTree = hierarchy.get(s); + ClassTree tempTree = getClassTree(clazz2.name); searchThese.addAll(tempTree.subClasses); } } diff --git a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java index 98823b4a..b89b2855 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java @@ -38,7 +38,7 @@ public abstract class AbstractTransformer implements Opcodes { /** * Bootstrap instance. */ - private Bootstrap bootstrap; + protected Bootstrap bootstrap; /** * Exempt information. diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java index e1e97513..71bc9ad9 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java @@ -17,7 +17,6 @@ package me.itzsomebody.radon.transformers.flow; -import java.lang.reflect.Modifier; import java.util.Stack; import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.analyzer.StackAnalyzer; diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java index 1899039c..51740117 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java +++ b/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java @@ -17,7 +17,6 @@ package me.itzsomebody.radon.transformers.flow; -import java.lang.reflect.Modifier; import java.util.Stack; import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.analyzer.StackAnalyzer; diff --git a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Renamer.java similarity index 80% rename from src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java rename to src/main/java/me/itzsomebody/radon/transformers/misc/Renamer.java index 2e360b77..56ac2342 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/renamer/Renamer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/Renamer.java @@ -15,7 +15,7 @@ * along with this program. If not, see */ -package me.itzsomebody.radon.transformers.renamer; +package me.itzsomebody.radon.transformers.misc; import java.io.UnsupportedEncodingException; import java.lang.reflect.Modifier; @@ -49,11 +49,6 @@ public class Renamer extends AbstractTransformer { */ private Map mappings = new HashMap<>(); - /** - * Used to determine how the classes interact with each other. - */ - private Map hierarchy = new HashMap<>(); - /** * Indication to look for Bukkit/Bungee main methods. */ @@ -73,7 +68,6 @@ public void obfuscate() { this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); this.logStrings.add(LoggerUtils.stdOut("Starting renamer transformer")); this.logStrings.add(LoggerUtils.stdOut("Generating mappings.")); - this.createTrees(); long current = System.currentTimeMillis(); AtomicInteger counter = new AtomicInteger(); this.classNodes().forEach(classNode -> { @@ -106,8 +100,7 @@ public void obfuscate() { counter.incrementAndGet(); } }); - this.logStrings.add(LoggerUtils.stdOut("Finished generated mappings. [" + - String.valueOf(System.currentTimeMillis() - current) + "ms]")); + this.logStrings.add(LoggerUtils.stdOut("Finished generated mappings. [" + String.valueOf(System.currentTimeMillis() - current) + "ms]")); this.logStrings.add(LoggerUtils.stdOut("Applying mappings.")); // Apply mapping @@ -157,36 +150,7 @@ public void obfuscate() { } }); this.logStrings.add(LoggerUtils.stdOut("Mapped " + fixed + " names in resources. [" + tookThisLong(current) + "ms]")); - this.logStrings.add(LoggerUtils.stdOut("Finished applying mappings. [" + - String.valueOf(System.currentTimeMillis() - current) + "ms]")); - } - - /** - * Creates {@link ClassTree}s needed for renaming. - */ - private void createTrees() { - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("Creating class hierarchy.")); - this.getClassPathMap().values().forEach(classNode -> { - classNode.methods.forEach(methodNode -> - methodNode.owner = classNode.name - ); - classNode.fields.forEach(fieldNode -> - fieldNode.owner = classNode.name - ); - ClassTree classTree = new ClassTree(classNode.name, classNode.libraryNode); - classTree.parentClasses.add(classNode.superName); - classTree.parentClasses.addAll(classNode.interfaces); - this.classNodes().stream().filter(node -> node.superName.equals(classNode.name) - || node.interfaces.contains(classNode.name)).forEach(node -> - classTree.subClasses.add(node.name) - ); - - classTree.methods.addAll(classNode.methods); - classTree.fields.addAll(classNode.fields); - this.hierarchy.put(classNode.name, classTree); - }); - this.logStrings.add(LoggerUtils.stdOut("Finished creating class hierarchy. [" + tookThisLong(current) + "ms]")); + this.logStrings.add(LoggerUtils.stdOut("Finished applying mappings. [" + String.valueOf(System.currentTimeMillis() - current) + "ms]")); } /** @@ -196,13 +160,7 @@ private void createTrees() { * @return true if we can rename a method without running into errors. */ private boolean weCanRenameMethod(MethodNode methodNode) { - for (ClassTree ct : this.hierarchy.values()) { - if (ct.subClasses.contains(methodNode.owner) - && this.isLibInheritedMN(new ArrayList<>(), methodNode, methodNode.owner)) { - return false; - } - } - return true; + return !this.isLibInheritedMN(new ArrayList<>(), methodNode, methodNode.owner); } /** @@ -214,7 +172,7 @@ private boolean weCanRenameMethod(MethodNode methodNode) { * @return true if the method we input is inherited from a library class. */ private boolean isLibInheritedMN(List visited, MethodNode methodNode, String className) { - ClassTree ct = this.hierarchy.get(className); + ClassTree ct = this.bootstrap.getClassTree(className); if (ct == null) throw new RuntimeException(className + " doesn't exist in classpath."); if (!visited.contains(ct)) { @@ -232,15 +190,13 @@ private boolean isLibInheritedMN(List visited, MethodNode methodNode, return true; } for (String parentClass : ct.parentClasses) { - if (parentClass != null - && this.isLibInheritedMN(visited, methodNode, parentClass)) { + if (parentClass != null && this.isLibInheritedMN(visited, methodNode, parentClass)) { return true; } } for (String subClass : ct.subClasses) { - if (subClass != null - && this.isLibInheritedMN(visited, methodNode, subClass)) { + if (subClass != null && this.isLibInheritedMN(visited, methodNode, subClass)) { return true; } } @@ -258,7 +214,7 @@ private boolean isLibInheritedMN(List visited, MethodNode methodNode, * @param newName the new name of the method. */ private void renameMethodTree(List visited, MethodNode methodNode, String className, String newName) { - ClassTree ct = this.hierarchy.get(className); + ClassTree ct = this.bootstrap.getClassTree(className); if (ct == null) throw new RuntimeException(className + " doesn't exist in classpath."); if (!ct.libraryNode && !visited.contains(ct)) { @@ -280,13 +236,7 @@ private void renameMethodTree(List visited, MethodNode methodNode, St * @return true if we can rename a field without running into errors. */ private boolean weCanRenameField(FieldNode fieldNode) { - for (ClassTree ct : this.hierarchy.values()) { - if (ct.subClasses.contains(fieldNode.owner) - && this.isLibInheritedFN(new ArrayList<>(), fieldNode, fieldNode.owner)) { - return false; - } - } - return true; + return this.isLibInheritedFN(new ArrayList<>(), fieldNode, fieldNode.owner); } /** @@ -297,7 +247,7 @@ private boolean weCanRenameField(FieldNode fieldNode) { * @return true if the method we input is inherited from a library class. */ private boolean isLibInheritedFN(List visited, FieldNode fieldNode, String className) { - ClassTree ct = this.hierarchy.get(className); + ClassTree ct = this.bootstrap.getClassTree(className); if (ct == null) throw new RuntimeException(className + " doesn't exist in classpath."); if (!visited.contains(ct)) { @@ -315,15 +265,13 @@ private boolean isLibInheritedFN(List visited, FieldNode fieldNode, S return true; } for (String parentClass : ct.parentClasses) { - if (parentClass != null - && this.isLibInheritedFN(visited, fieldNode, parentClass)) { + if (parentClass != null && this.isLibInheritedFN(visited, fieldNode, parentClass)) { return true; } } for (String subClass : ct.subClasses) { - if (subClass != null - && this.isLibInheritedFN(visited, fieldNode, subClass)) { + if (subClass != null && this.isLibInheritedFN(visited, fieldNode, subClass)) { return true; } } @@ -343,7 +291,7 @@ private boolean isLibInheritedFN(List visited, FieldNode fieldNode, S */ private void renameFieldTree(List visited, FieldNode fieldNode, String className, String newName) { - ClassTree ct = this.hierarchy.get(className); + ClassTree ct = this.bootstrap.getClassTree(className); if (ct == null) throw new RuntimeException(className + " doesn't exist in classpath."); if (!ct.libraryNode && !visited.contains(ct)) { From db55e45d781433d6d2af86c327756acc4315da25 Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Wed, 1 Aug 2018 21:39:14 -0700 Subject: [PATCH 057/281] Fixes bug ccausing renamer transformer to not search any methods at all --- .../itzsomebody/radon/internal/Bootstrap.java | 14 +++---- .../itzsomebody/radon/internal/ClassTree.java | 10 ----- .../radon/transformers/misc/Renamer.java | 38 +++++++++---------- 3 files changed, 26 insertions(+), 36 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index f9f00e09..09e8537e 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -218,6 +218,7 @@ public void startTheParty(boolean doInit) throws Throwable { long currentTime = System.currentTimeMillis(); this.loadClassPath(); this.loadInput(); + this.buildInheritance(); for (AbstractTransformer transformer : this.transformers) { transformer.init(this, this.exempts, this.dictionary); @@ -230,8 +231,7 @@ public void startTheParty(boolean doInit) throws Throwable { // TODO: make this variable a config option int len = 4; for (int i = 0; i < this.trashClasses; i++) { - TrashClasses trashClass = - new TrashClasses(StringUtils.randomClassName(this.classes.keySet(), this.dictionary, len)); + TrashClasses trashClass = new TrashClasses(StringUtils.randomClassName(this.classes.keySet(), this.dictionary, len)); ClassNode classNode = trashClass.returnTrashClass(); this.extraClasses.put(classNode.name, classNode); } @@ -442,7 +442,6 @@ private void loadClassPath() throws RuntimeException { classNode.methods.forEach(methodNode -> methodNode.owner = classNode.name); classNode.fields.forEach(fieldNode -> fieldNode.owner = classNode.name); - this.classPath.put(classNode.name, classNode); } } @@ -500,7 +499,7 @@ private void loadInput() throws RuntimeException { public ClassTree getTree(String ref) { if (!hierarchy.containsKey(ref)) { - ClassNode wrapper = classPath.get(ref); + ClassNode wrapper = returnClazz(ref); buildHierarchy(wrapper, null); } @@ -509,15 +508,16 @@ public ClassTree getTree(String ref) { private void buildHierarchy(ClassNode classNode, ClassNode sub) { if (hierarchy.get(classNode.name) == null) { - ClassTree tree = new ClassTree(); + ClassTree tree = new ClassTree(classNode.name, classNode.libraryNode); + tree.classNode = classNode; if (classNode.superName != null) { tree.parentClasses.add(classNode.superName); - buildHierarchy(classPath.get(classNode.superName), ); + buildHierarchy(returnClazz(classNode.superName), classNode); } if (classNode.interfaces != null && !classNode.interfaces.isEmpty()) { for (String s : classNode.interfaces) { tree.parentClasses.add(s); - buildHierarchy(classPath.get(s), classNode); + buildHierarchy(returnClazz(s), classNode); } } hierarchy.put(classNode.name, tree); diff --git a/src/main/java/me/itzsomebody/radon/internal/ClassTree.java b/src/main/java/me/itzsomebody/radon/internal/ClassTree.java index a6e84b87..9920f68d 100644 --- a/src/main/java/me/itzsomebody/radon/internal/ClassTree.java +++ b/src/main/java/me/itzsomebody/radon/internal/ClassTree.java @@ -49,16 +49,6 @@ public class ClassTree { */ public final Set parentClasses = new HashSet<>(); - /** - * Set of methods that this class contains. - */ - public final Set methods = new HashSet<>(); - - /** - * Set of fields that this class contains. - */ - public final Set fields = new HashSet<>(); - /** * Indication of this class being a library (external) class. */ diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Renamer.java index df04fc68..3e58036e 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Renamer.java +++ b/src/main/java/me/itzsomebody/radon/transformers/misc/Renamer.java @@ -21,7 +21,7 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; -import java.util.List; +import java.util.HashSet; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import me.itzsomebody.radon.internal.ClassTree; @@ -77,20 +77,20 @@ public void obfuscate() { AtomicInteger counter = new AtomicInteger(); this.classNodes().forEach(classNode -> { classNode.methods.stream().filter(methodNode -> !Modifier.isNative(methodNode.access) - && !methodNode.name.equals("main") - && !methodNode.name.equals("premain") - && !methodNode.name.startsWith("<") - && !methodNode.name.contains("lambda")).forEach(methodNode -> { + && !methodNode.name.equals("main") + && !methodNode.name.equals("premain") + && !methodNode.name.startsWith("<") + && !methodNode.name.contains("lambda")).forEach(methodNode -> { if (this.weCanRenameMethod(methodNode)) { String newName = StringUtils.randomString(this.dictionary, len); - this.renameMethodTree(new ArrayList<>(), methodNode, classNode.name, newName); + this.renameMethodTree(new HashSet<>(), methodNode, classNode.name, newName); } }); classNode.fields.forEach(fieldNode -> { if (this.weCanRenameField(fieldNode)) { String newName = StringUtils.randomString(this.dictionary, len); - this.renameFieldTree(new ArrayList<>(), fieldNode, classNode.name, newName); + this.renameFieldTree(new HashSet<>(), fieldNode, classNode.name, newName); } }); @@ -137,10 +137,10 @@ public void obfuscate() { AtomicInteger fixed = new AtomicInteger(); getPassThru().forEach((name, byteArray) -> { if (name.equals("META-INF/MANIFEST.MF") - || (name.equals("plugin.yml") && spigotMode)) { + || (name.equals("plugin.yml") && spigotMode)) { String stringVer = new String(byteArray); for (String mapping : mappings.keySet()) { - String original = mapping.replace("/", "."); + String original = mapping.replace("/", "."); if (stringVer.contains(original)) { // Regex that ensures that class names that match words in the manifest don't break the manifest // Example: name == Main @@ -168,25 +168,25 @@ public void obfuscate() { * @return true if we can rename a method without running into errors. */ private boolean weCanRenameMethod(MethodNode methodNode) { - return !this.isLibInheritedMN(new ArrayList<>(), methodNode, methodNode.owner); + return !this.isLibInheritedMN(new HashSet<>(), methodNode, methodNode.owner); } /** * Attempts to determine if the method we input is inherited from a library class or is exempted. * - * @param visited a list of {@link ClassTree}s which contain the {@link MethodNode}s we already checked. + * @param visited a set of {@link ClassTree}s which contain the {@link MethodNode}s we already checked. * @param methodNode {@link MethodNode} we want to check if we can rename without causing the JVM to spit lots of errors. * @param className the name of the class we want to check * @return true if the method we input is inherited from a library class. */ - private boolean isLibInheritedMN(List visited, MethodNode methodNode, String className) { + private boolean isLibInheritedMN(HashSet visited, MethodNode methodNode, String className) { ClassTree ct = this.bootstrap.getTree(className); if (ct == null) throw new RuntimeException(className + " doesn't exist in classpath."); if (!visited.contains(ct)) { visited.add(ct); if (!methodNode.owner.equals(className)) { - for (MethodNode mn : ct.methods) { + for (MethodNode mn : ct.classNode.methods) { if (mn.name.equals(methodNode.name) && mn.desc.equals(methodNode.desc)) { if (ct.libraryNode) { return true; @@ -216,12 +216,12 @@ private boolean isLibInheritedMN(List visited, MethodNode methodNode, /** * Renames the methods in an inheritance tree to prevent inheritance errors. * - * @param visited a list of {@link ClassTree}s which contain the {@link MethodNode}s we already renamed. + * @param visited a set of {@link ClassTree}s which contain the {@link MethodNode}s we already renamed. * @param methodNode the method information. * @param className the class we are currently browsing through. * @param newName the new name of the method. */ - private void renameMethodTree(List visited, MethodNode methodNode, String className, String newName) { + private void renameMethodTree(HashSet visited, MethodNode methodNode, String className, String newName) { ClassTree ct = this.bootstrap.getTree(className); if (ct == null) throw new RuntimeException(className + " doesn't exist in classpath."); @@ -244,7 +244,7 @@ private void renameMethodTree(List visited, MethodNode methodNode, St * @return true if we can rename a field without running into errors. */ private boolean weCanRenameField(FieldNode fieldNode) { - return this.isLibInheritedFN(new ArrayList<>(), fieldNode, fieldNode.owner); + return this.isLibInheritedFN(new HashSet<>(), fieldNode, fieldNode.owner); } /** @@ -254,14 +254,14 @@ private boolean weCanRenameField(FieldNode fieldNode) { * @param className the name of the class we want to check * @return true if the method we input is inherited from a library class. */ - private boolean isLibInheritedFN(List visited, FieldNode fieldNode, String className) { + private boolean isLibInheritedFN(HashSet visited, FieldNode fieldNode, String className) { ClassTree ct = this.bootstrap.getTree(className); if (ct == null) throw new RuntimeException(className + " doesn't exist in classpath."); if (!visited.contains(ct)) { visited.add(ct); if (!fieldNode.owner.equals(className)) { - for (MethodNode mn : ct.methods) { + for (MethodNode mn : ct.classNode.methods) { if (mn.name.equals(fieldNode.name) && mn.desc.equals(fieldNode.desc)) { if (ct.libraryNode) { return true; @@ -297,7 +297,7 @@ private boolean isLibInheritedFN(List visited, FieldNode fieldNode, S * @param className the class we are currently browsing through. * @param newName the new name of the method. */ - private void renameFieldTree(List visited, FieldNode fieldNode, + private void renameFieldTree(HashSet visited, FieldNode fieldNode, String className, String newName) { ClassTree ct = this.bootstrap.getTree(className); if (ct == null) From c1e9faac1e6be2da5bd604e468582a36ae80c40a Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Wed, 1 Aug 2018 21:41:07 -0700 Subject: [PATCH 058/281] Move renamer back to the top of transformer priority list --- .../java/me/itzsomebody/radon/internal/Bootstrap.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index 09e8537e..8f85a141 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -345,6 +345,9 @@ private void init() throws RuntimeException { AbstractTransformer transformer; // Specific order of adding transformers, feel free to change if // you wish. + if ((transformer = this.config.getRenamerType()) != null) { + this.transformers.add(transformer); + } if ((transformer = this.config.getInnerClassRemoverType()) != null) { this.transformers.add(transformer); } @@ -391,11 +394,6 @@ private void init() throws RuntimeException { if ((transformer = this.config.getHideCodeType()) != null) { this.transformers.add(transformer); } - // This is last to prevent confusing logic when looking up values in the name-to-node map - // returning nodes that have their names not matching the key. - if ((transformer = this.config.getRenamerType()) != null) { - this.transformers.add(transformer); - } this.trashClasses = this.config.getTrashClasses(); this.watermarkMsg = this.config.getWatermarkMsg(); this.watermarkType = this.config.getWatermarkType(); From 71fd29a98b9d5d5d34a8892bb3a37742bc5930a2 Mon Sep 17 00:00:00 2001 From: ArtelGG <21347579+ArtelGG@users.noreply.github.com> Date: Mon, 13 Aug 2018 13:17:31 -0400 Subject: [PATCH 059/281] Remove forced file watermark for now --- src/main/java/me/itzsomebody/radon/internal/Bootstrap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java index 8f85a141..46d0bbf6 100644 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java @@ -301,7 +301,7 @@ public void startTheParty(boolean doInit) throws Throwable { this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); if (this.zos != null) { - this.zos.setComment("Obfuscation by Radon obfuscator developed by ItzSomebody"); // Cause why not xD + //this.zos.setComment("Obfuscation by Radon obfuscator developed by ItzSomebody"); // Cause why not xD this.zos.close(); this.logStrings.add(LoggerUtils.stdOut("Finished processing file.")); } From 3d5a17563e966e5663f8fada128cd69d8b83316f Mon Sep 17 00:00:00 2001 From: ItzSomebody <23221108+ItzSomebody@users.noreply.github.com> Date: Mon, 13 Aug 2018 13:35:12 -0700 Subject: [PATCH 060/281] Surprise! Recode --- .gitignore | 2 +- CHANGELOG.md | 3 + README.md | 365 +- Radon-GUI/pom.xml | 56 + .../java/me/itzsomebody/radon/gui/Main.java | 43 + .../me/itzsomebody/radon/gui/RadonGUI.java | 206 + .../gui/StringEncryptionExclusionGUI.java | 119 + .../radon/gui/tabs/ConsoleTab.java | 71 + .../radon/gui/tabs/ExclusionsTab.java | 123 + .../radon/gui/tabs/InputOutputTab.java | 268 ++ .../radon/gui/tabs/MiscellaneousTab.java | 243 ++ .../radon/gui/tabs/ObfuscationTab.java | 536 +++ .../radon/gui/tabs/OptimizationTab.java | 99 + .../radon/gui/tabs/ShrinkingTab.java | 134 + .../radon/gui/tabs/WatermarkingTab.java | 223 ++ .../src}/main/resources/META-INF/license.txt | 0 Radon-Program/pom.xml | 87 + .../main/java/me/itzsomebody/radon}/CLI.java | 53 +- .../me/itzsomebody/radon/Dictionaries.java | 77 + .../main/java/me/itzsomebody/radon/Main.java | 40 +- .../main/java/me/itzsomebody/radon/Radon.java | 337 ++ .../me/itzsomebody/radon/SessionInfo.java | 89 + .../me/itzsomebody/radon/asm/ClassTree.java | 31 + .../itzsomebody/radon/asm/ClassWrapper.java | 42 + .../itzsomebody/radon/asm/FieldWrapper.java | 34 + .../itzsomebody/radon/asm/MemberRemapper.java | 33 + .../itzsomebody/radon/asm/MethodWrapper.java | 34 + .../itzsomebody/radon/asm/StackEmulator.java | 51 +- .../radon/asm/UsedInstructionsFinder.java | 64 + .../radon/config/ConfigurationParser.java | 533 +++ .../radon/config/ConfigurationSettings.java | 48 +- .../radon/config/ConfigurationWriter.java | 232 ++ .../radon/exceptions/BadInputException.java | 21 + .../ByteArrayConversionException.java | 26 + .../ConfigurationParseException.java | 24 + .../IllegalConfigurationKeyException.java | 7 + .../IllegalConfigurationValueException.java | 11 + .../IllegalDictionaryException.java | 21 + .../exceptions/InputNotFoundException.java | 21 + .../exceptions/MissingClassException.java | 24 + .../exceptions/NoTransformersException.java | 21 + .../exceptions/OutputWriteException.java | 21 + .../WatermarkExtractionException.java | 28 + .../radon/exclusions/Exclusion.java | 83 + .../radon/exclusions/ExclusionManager.java | 43 + .../radon/exclusions/ExclusionType.java | 48 + .../radon/transformers/Transformer.java | 90 + .../transformers/miscellaneous/Crasher.java | 51 + .../miscellaneous/TrashClasses.java | 192 + .../miscellaneous/expiration/Expiration.java | 101 + .../expiration/ExpirationSetup.java | 40 +- .../watermarker/Watermarker.java | 103 + .../watermarker/WatermarkerSetup.java | 36 + .../obfuscators/flow/FlowObfuscation.java | 45 + .../flow/HeavyFlowObfuscation.java | 104 + .../flow/LightFlowObfuscation.java | 71 + .../flow/NormalFlowObfuscation.java | 126 +- .../invokedynamic/HeavyInvokeDynamic.java | 185 +- .../invokedynamic/InvokeDynamic.java | 45 + .../invokedynamic/LightInvokeDynamic.java | 322 ++ .../invokedynamic/NormalInvokeDynamic.java | 350 ++ .../obfuscators/miscellaneous/HideCode.java | 76 + .../miscellaneous/LineNumbers.java | 68 + .../miscellaneous/LocalVariables.java | 69 + .../miscellaneous/MemberShuffler.java | 52 + .../miscellaneous/SourceDebug.java | 59 + .../obfuscators/miscellaneous/SourceName.java | 59 + .../numbers/HeavyNumberObfuscation.java | 87 + .../numbers/LightNumberObfuscation.java | 88 + .../numbers/NormalNumberObfuscation.java | 174 + .../numbers/NumberObfuscation.java | 45 + .../obfuscators/renamer/Renamer.java | 289 ++ .../obfuscators/renamer/RenamerSetup.java | 36 + .../strings/HeavyStringEncryption.java | 127 +- .../strings/LightStringEncryption.java | 35 + .../strings/NormalStringEncryption.java | 35 + .../obfuscators/strings/StringEncryption.java | 66 + .../strings/StringEncryptionSetup.java | 32 + .../obfuscators/strings/StringPool.java | 147 + .../optimizers/GotoGotoRemover.java | 58 + .../optimizers/GotoReturnRemover.java | 58 + .../transformers/optimizers/NopRemover.java | 50 + .../transformers/optimizers/Optimizer.java | 28 + .../optimizers/OptimizerDelegator.java | 54 + .../optimizers/OptimizerSetup.java | 42 + .../shrinkers/AttributesRemover.java | 43 + .../shrinkers/DebugInfoRemover.java | 58 + .../InvisibleAnnotationsRemover.java | 57 + .../transformers/shrinkers/Shrinker.java | 28 + .../shrinkers/ShrinkerDelegator.java | 69 + .../transformers/shrinkers/ShrinkerSetup.java | 60 + .../shrinkers/UnusedCodeRemover.java | 68 + .../shrinkers/UnusedMembersRemover.java | 31 + .../shrinkers/VisibleAnnotationsRemover.java | 57 + .../itzsomebody/radon/utils/AccessUtils.java | 52 + .../radon/utils/BytecodeUtils.java | 148 + .../me/itzsomebody/radon/utils/IOUtils.java | 20 +- .../itzsomebody/radon/utils/LoggerUtils.java | 55 +- .../itzsomebody/radon/utils/RandomUtils.java | 48 + .../itzsomebody/radon/utils/StringUtils.java | 108 + .../radon/utils/WatermarkUtils.java | 122 + .../main/resources/META-INF/asm-license.txt | 0 .../src/main/resources/META-INF/license.txt | 674 ++++ .../resources/META-INF/snakeyaml-license.txt | 0 pom.xml | 63 +- .../me/itzsomebody/radon/config/Config.java | 1051 ----- .../radon/config/ConfigWriter.java | 114 - .../generate/InvokeDynamicBSMGenerator.java | 692 ---- .../generate/StringEncryptionGenerator.java | 752 ---- .../me/itzsomebody/radon/gui/ConsoleGUI.java | 112 - .../me/itzsomebody/radon/gui/MainGUI.java | 1887 --------- .../radon/gui/OutputStreamRedirect.java | 53 - .../itzsomebody/radon/internal/Bootstrap.java | 669 ---- .../itzsomebody/radon/internal/ClassTree.java | 66 - .../transformers/AbstractTransformer.java | 207 - .../flow/HeavyFlowObfuscation.java | 172 - .../flow/LightFlowObfuscation.java | 78 - .../invokedynamic/HeavyInvokeDynamic.java | 210 - .../invokedynamic/LightInvokeDynamic.java | 159 - .../invokedynamic/NormalInvokeDynamic.java | 38 - .../linenumbers/ObfuscateLineNumbers.java | 61 - .../linenumbers/RemoveLineNumbers.java | 58 - .../ObfuscateLocalVariables.java | 56 - .../localvariables/RemoveLocalVariables.java | 49 - .../radon/transformers/misc/Crasher.java | 58 - .../radon/transformers/misc/Expiry.java | 76 - .../radon/transformers/misc/HideCode.java | 77 - .../transformers/misc/InnerClassRemover.java | 46 - .../transformers/misc/NumberObfuscation.java | 90 - .../radon/transformers/misc/Renamer.java | 316 -- .../radon/transformers/misc/Shuffler.java | 50 - .../radon/transformers/misc/StringPool.java | 175 - .../radon/transformers/misc/TrashClasses.java | 250 -- .../sourcedebug/ObfuscateSourceDebug.java | 53 - .../sourcedebug/RemoveSourceDebug.java | 47 - .../sourcename/ObfuscateSourceName.java | 52 - .../sourcename/RemoveSourceName.java | 47 - .../HeavyStringEncryption.java | 163 - .../LightStringEncryption.java | 64 - .../NormalStringEncryption.java | 69 - .../SuperLightStringEncryption.java | 118 - .../radon/utils/BytecodeUtils.java | 258 -- .../itzsomebody/radon/utils/NumberUtils.java | 71 - .../itzsomebody/radon/utils/StringUtils.java | 258 -- .../radon/utils/WatermarkUtils.java | 96 - .../org/objectweb/asm/AnnotationVisitor.java | 149 - .../org/objectweb/asm/AnnotationWriter.java | 422 -- .../java/org/objectweb/asm/Attribute.java | 327 -- .../java/org/objectweb/asm/ByteVector.java | 366 -- .../java/org/objectweb/asm/ClassReader.java | 3495 ----------------- .../java/org/objectweb/asm/ClassVisitor.java | 293 -- .../java/org/objectweb/asm/ClassWriter.java | 906 ----- .../java/org/objectweb/asm/Constants.java | 176 - src/main/java/org/objectweb/asm/Context.java | 164 - .../java/org/objectweb/asm/CurrentFrame.java | 56 - src/main/java/org/objectweb/asm/Edge.java | 93 - .../java/org/objectweb/asm/FieldVisitor.java | 135 - .../java/org/objectweb/asm/FieldWriter.java | 352 -- src/main/java/org/objectweb/asm/Frame.java | 1484 ------- src/main/java/org/objectweb/asm/Handle.java | 197 - src/main/java/org/objectweb/asm/Handler.java | 200 - src/main/java/org/objectweb/asm/Label.java | 673 ---- .../java/org/objectweb/asm/MethodVisitor.java | 779 ---- .../java/org/objectweb/asm/MethodWriter.java | 2378 ----------- .../java/org/objectweb/asm/ModuleVisitor.java | 175 - .../java/org/objectweb/asm/ModuleWriter.java | 287 -- src/main/java/org/objectweb/asm/Opcodes.java | 331 -- src/main/java/org/objectweb/asm/Symbol.java | 273 -- .../java/org/objectweb/asm/SymbolTable.java | 1239 ------ src/main/java/org/objectweb/asm/Type.java | 953 ----- src/main/java/org/objectweb/asm/TypePath.java | 211 - .../java/org/objectweb/asm/TypeReference.java | 440 --- .../objectweb/asm/commons/AdviceAdapter.java | 633 --- .../asm/commons/AnalyzerAdapter.java | 920 ----- .../asm/commons/AnnotationRemapper.java | 73 - .../objectweb/asm/commons/ClassRemapper.java | 172 - .../asm/commons/CodeSizeEvaluator.java | 213 - .../objectweb/asm/commons/FieldRemapper.java | 67 - .../asm/commons/GeneratorAdapter.java | 1493 ------- .../asm/commons/InstructionAdapter.java | 1154 ------ .../asm/commons/JSRInlinerAdapter.java | 716 ---- .../asm/commons/LocalVariablesSorter.java | 357 -- .../org/objectweb/asm/commons/Method.java | 255 -- .../objectweb/asm/commons/MethodRemapper.java | 229 -- .../asm/commons/ModuleHashesAttribute.java | 122 - .../objectweb/asm/commons/ModuleRemapper.java | 103 - .../commons/ModuleResolutionAttribute.java | 100 - .../asm/commons/ModuleTargetAttribute.java | 77 - .../org/objectweb/asm/commons/Remapper.java | 258 -- .../commons/RemappingAnnotationAdapter.java | 76 - .../asm/commons/RemappingClassAdapter.java | 155 - .../asm/commons/RemappingFieldAdapter.java | 69 - .../asm/commons/RemappingMethodAdapter.java | 236 -- .../commons/RemappingSignatureAdapter.java | 156 - .../asm/commons/SerialVersionUIDAdder.java | 554 --- .../asm/commons/SignatureRemapper.java | 158 - .../objectweb/asm/commons/SimpleRemapper.java | 73 - .../asm/commons/StaticInitMerger.java | 101 - .../asm/commons/TableSwitchGenerator.java | 53 - .../asm/commons/TryCatchBlockSorter.java | 105 - .../asm/signature/SignatureReader.java | 254 -- .../asm/signature/SignatureVisitor.java | 220 -- .../asm/signature/SignatureWriter.java | 252 -- .../objectweb/asm/tree/AbstractInsnNode.java | 304 -- .../objectweb/asm/tree/AnnotationNode.java | 233 -- .../org/objectweb/asm/tree/ClassNode.java | 430 -- .../org/objectweb/asm/tree/FieldInsnNode.java | 101 - .../org/objectweb/asm/tree/FieldNode.java | 282 -- .../org/objectweb/asm/tree/FrameNode.java | 189 - .../org/objectweb/asm/tree/IincInsnNode.java | 79 - .../objectweb/asm/tree/InnerClassNode.java | 89 - .../java/org/objectweb/asm/tree/InsnList.java | 593 --- .../java/org/objectweb/asm/tree/InsnNode.java | 74 - .../org/objectweb/asm/tree/IntInsnNode.java | 82 - .../asm/tree/InvokeDynamicInsnNode.java | 101 - .../org/objectweb/asm/tree/JumpInsnNode.java | 88 - .../org/objectweb/asm/tree/LabelNode.java | 76 - .../org/objectweb/asm/tree/LdcInsnNode.java | 75 - .../objectweb/asm/tree/LineNumberNode.java | 79 - .../asm/tree/LocalVariableAnnotationNode.java | 141 - .../objectweb/asm/tree/LocalVariableNode.java | 104 - .../asm/tree/LookupSwitchInsnNode.java | 100 - .../objectweb/asm/tree/MethodInsnNode.java | 130 - .../org/objectweb/asm/tree/MethodNode.java | 843 ---- .../objectweb/asm/tree/ModuleExportNode.java | 82 - .../org/objectweb/asm/tree/ModuleNode.java | 249 -- .../objectweb/asm/tree/ModuleOpenNode.java | 82 - .../objectweb/asm/tree/ModuleProvideNode.java | 71 - .../objectweb/asm/tree/ModuleRequireNode.java | 77 - .../asm/tree/MultiANewArrayInsnNode.java | 79 - .../org/objectweb/asm/tree/ParameterNode.java | 71 - .../asm/tree/TableSwitchInsnNode.java | 102 - .../objectweb/asm/tree/TryCatchBlockNode.java | 135 - .../asm/tree/TypeAnnotationNode.java | 87 - .../org/objectweb/asm/tree/TypeInsnNode.java | 86 - .../UnsupportedClassVersionException.java | 14 - .../java/org/objectweb/asm/tree/Util.java | 158 - .../org/objectweb/asm/tree/VarInsnNode.java | 85 - 238 files changed, 9719 insertions(+), 40859 deletions(-) create mode 100644 Radon-GUI/pom.xml create mode 100644 Radon-GUI/src/main/java/me/itzsomebody/radon/gui/Main.java create mode 100644 Radon-GUI/src/main/java/me/itzsomebody/radon/gui/RadonGUI.java create mode 100644 Radon-GUI/src/main/java/me/itzsomebody/radon/gui/StringEncryptionExclusionGUI.java create mode 100644 Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ConsoleTab.java create mode 100644 Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ExclusionsTab.java create mode 100644 Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/InputOutputTab.java create mode 100644 Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/MiscellaneousTab.java create mode 100644 Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ObfuscationTab.java create mode 100644 Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/OptimizationTab.java create mode 100644 Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ShrinkingTab.java create mode 100644 Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/WatermarkingTab.java rename {src => Radon-GUI/src}/main/resources/META-INF/license.txt (100%) create mode 100644 Radon-Program/pom.xml rename {src/main/java/me/itzsomebody/radon/internal => Radon-Program/src/main/java/me/itzsomebody/radon}/CLI.java (68%) create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/Dictionaries.java rename src/main/java/me/itzsomebody/radon/Radon.java => Radon-Program/src/main/java/me/itzsomebody/radon/Main.java (67%) create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/Radon.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/SessionInfo.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/asm/ClassTree.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/asm/ClassWrapper.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/asm/FieldWrapper.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/asm/MemberRemapper.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/asm/MethodWrapper.java rename src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java => Radon-Program/src/main/java/me/itzsomebody/radon/asm/StackEmulator.java (92%) create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/asm/UsedInstructionsFinder.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/config/ConfigurationParser.java rename src/main/java/me/itzsomebody/radon/config/ConfigEnum.java => Radon-Program/src/main/java/me/itzsomebody/radon/config/ConfigurationSettings.java (52%) create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/config/ConfigurationWriter.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/BadInputException.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/ByteArrayConversionException.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/ConfigurationParseException.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/IllegalConfigurationKeyException.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/IllegalConfigurationValueException.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/IllegalDictionaryException.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/InputNotFoundException.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/MissingClassException.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/NoTransformersException.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/OutputWriteException.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/WatermarkExtractionException.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/exclusions/Exclusion.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/exclusions/ExclusionManager.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/exclusions/ExclusionType.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/Transformer.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/Crasher.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/TrashClasses.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/expiration/Expiration.java rename src/main/java/me/itzsomebody/radon/utils/MatchUtils.java => Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/expiration/ExpirationSetup.java (52%) create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/watermarker/Watermarker.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/watermarker/WatermarkerSetup.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/flow/FlowObfuscation.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/flow/HeavyFlowObfuscation.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/flow/LightFlowObfuscation.java rename {src/main/java/me/itzsomebody/radon/transformers => Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators}/flow/NormalFlowObfuscation.java (54%) rename src/main/java/me/itzsomebody/radon/generate/InvokeDynamicBootstrapGenerator.java => Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/HeavyInvokeDynamic.java (72%) create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/InvokeDynamic.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/LightInvokeDynamic.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/NormalInvokeDynamic.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/HideCode.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/LineNumbers.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/LocalVariables.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/MemberShuffler.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/SourceDebug.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/SourceName.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/HeavyNumberObfuscation.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/LightNumberObfuscation.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/NormalNumberObfuscation.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/NumberObfuscation.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/renamer/Renamer.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/renamer/RenamerSetup.java rename src/main/java/me/itzsomebody/radon/generate/StringDecryptorGenerator.java => Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/HeavyStringEncryption.java (80%) create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/LightStringEncryption.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/NormalStringEncryption.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/StringEncryption.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/StringEncryptionSetup.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/StringPool.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/GotoGotoRemover.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/GotoReturnRemover.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/NopRemover.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/Optimizer.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/OptimizerDelegator.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/OptimizerSetup.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/AttributesRemover.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/DebugInfoRemover.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/InvisibleAnnotationsRemover.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/Shrinker.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/ShrinkerDelegator.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/ShrinkerSetup.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/UnusedCodeRemover.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/UnusedMembersRemover.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/VisibleAnnotationsRemover.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/utils/AccessUtils.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java rename src/main/java/me/itzsomebody/radon/utils/FileUtils.java => Radon-Program/src/main/java/me/itzsomebody/radon/utils/IOUtils.java (87%) rename {src => Radon-Program/src}/main/java/me/itzsomebody/radon/utils/LoggerUtils.java (63%) create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/utils/RandomUtils.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/utils/StringUtils.java create mode 100644 Radon-Program/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java rename {src => Radon-Program/src}/main/resources/META-INF/asm-license.txt (100%) create mode 100644 Radon-Program/src/main/resources/META-INF/license.txt rename {src => Radon-Program/src}/main/resources/META-INF/snakeyaml-license.txt (100%) delete mode 100644 src/main/java/me/itzsomebody/radon/config/Config.java delete mode 100644 src/main/java/me/itzsomebody/radon/config/ConfigWriter.java delete mode 100644 src/main/java/me/itzsomebody/radon/generate/InvokeDynamicBSMGenerator.java delete mode 100644 src/main/java/me/itzsomebody/radon/generate/StringEncryptionGenerator.java delete mode 100644 src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java delete mode 100644 src/main/java/me/itzsomebody/radon/gui/MainGUI.java delete mode 100644 src/main/java/me/itzsomebody/radon/gui/OutputStreamRedirect.java delete mode 100644 src/main/java/me/itzsomebody/radon/internal/Bootstrap.java delete mode 100644 src/main/java/me/itzsomebody/radon/internal/ClassTree.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/misc/InnerClassRemover.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/misc/Renamer.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/misc/Shuffler.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/sourcedebug/RemoveSourceDebug.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/sourcename/RemoveSourceName.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java delete mode 100644 src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java delete mode 100644 src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java delete mode 100644 src/main/java/me/itzsomebody/radon/utils/NumberUtils.java delete mode 100644 src/main/java/me/itzsomebody/radon/utils/StringUtils.java delete mode 100644 src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java delete mode 100644 src/main/java/org/objectweb/asm/AnnotationVisitor.java delete mode 100644 src/main/java/org/objectweb/asm/AnnotationWriter.java delete mode 100644 src/main/java/org/objectweb/asm/Attribute.java delete mode 100644 src/main/java/org/objectweb/asm/ByteVector.java delete mode 100644 src/main/java/org/objectweb/asm/ClassReader.java delete mode 100644 src/main/java/org/objectweb/asm/ClassVisitor.java delete mode 100644 src/main/java/org/objectweb/asm/ClassWriter.java delete mode 100644 src/main/java/org/objectweb/asm/Constants.java delete mode 100644 src/main/java/org/objectweb/asm/Context.java delete mode 100644 src/main/java/org/objectweb/asm/CurrentFrame.java delete mode 100644 src/main/java/org/objectweb/asm/Edge.java delete mode 100644 src/main/java/org/objectweb/asm/FieldVisitor.java delete mode 100644 src/main/java/org/objectweb/asm/FieldWriter.java delete mode 100644 src/main/java/org/objectweb/asm/Frame.java delete mode 100644 src/main/java/org/objectweb/asm/Handle.java delete mode 100644 src/main/java/org/objectweb/asm/Handler.java delete mode 100644 src/main/java/org/objectweb/asm/Label.java delete mode 100644 src/main/java/org/objectweb/asm/MethodVisitor.java delete mode 100644 src/main/java/org/objectweb/asm/MethodWriter.java delete mode 100644 src/main/java/org/objectweb/asm/ModuleVisitor.java delete mode 100644 src/main/java/org/objectweb/asm/ModuleWriter.java delete mode 100644 src/main/java/org/objectweb/asm/Opcodes.java delete mode 100644 src/main/java/org/objectweb/asm/Symbol.java delete mode 100644 src/main/java/org/objectweb/asm/SymbolTable.java delete mode 100644 src/main/java/org/objectweb/asm/Type.java delete mode 100644 src/main/java/org/objectweb/asm/TypePath.java delete mode 100644 src/main/java/org/objectweb/asm/TypeReference.java delete mode 100644 src/main/java/org/objectweb/asm/commons/AdviceAdapter.java delete mode 100644 src/main/java/org/objectweb/asm/commons/AnalyzerAdapter.java delete mode 100644 src/main/java/org/objectweb/asm/commons/AnnotationRemapper.java delete mode 100644 src/main/java/org/objectweb/asm/commons/ClassRemapper.java delete mode 100644 src/main/java/org/objectweb/asm/commons/CodeSizeEvaluator.java delete mode 100644 src/main/java/org/objectweb/asm/commons/FieldRemapper.java delete mode 100644 src/main/java/org/objectweb/asm/commons/GeneratorAdapter.java delete mode 100644 src/main/java/org/objectweb/asm/commons/InstructionAdapter.java delete mode 100644 src/main/java/org/objectweb/asm/commons/JSRInlinerAdapter.java delete mode 100644 src/main/java/org/objectweb/asm/commons/LocalVariablesSorter.java delete mode 100644 src/main/java/org/objectweb/asm/commons/Method.java delete mode 100644 src/main/java/org/objectweb/asm/commons/MethodRemapper.java delete mode 100644 src/main/java/org/objectweb/asm/commons/ModuleHashesAttribute.java delete mode 100644 src/main/java/org/objectweb/asm/commons/ModuleRemapper.java delete mode 100644 src/main/java/org/objectweb/asm/commons/ModuleResolutionAttribute.java delete mode 100644 src/main/java/org/objectweb/asm/commons/ModuleTargetAttribute.java delete mode 100644 src/main/java/org/objectweb/asm/commons/Remapper.java delete mode 100644 src/main/java/org/objectweb/asm/commons/RemappingAnnotationAdapter.java delete mode 100644 src/main/java/org/objectweb/asm/commons/RemappingClassAdapter.java delete mode 100644 src/main/java/org/objectweb/asm/commons/RemappingFieldAdapter.java delete mode 100644 src/main/java/org/objectweb/asm/commons/RemappingMethodAdapter.java delete mode 100644 src/main/java/org/objectweb/asm/commons/RemappingSignatureAdapter.java delete mode 100644 src/main/java/org/objectweb/asm/commons/SerialVersionUIDAdder.java delete mode 100644 src/main/java/org/objectweb/asm/commons/SignatureRemapper.java delete mode 100644 src/main/java/org/objectweb/asm/commons/SimpleRemapper.java delete mode 100644 src/main/java/org/objectweb/asm/commons/StaticInitMerger.java delete mode 100644 src/main/java/org/objectweb/asm/commons/TableSwitchGenerator.java delete mode 100644 src/main/java/org/objectweb/asm/commons/TryCatchBlockSorter.java delete mode 100644 src/main/java/org/objectweb/asm/signature/SignatureReader.java delete mode 100644 src/main/java/org/objectweb/asm/signature/SignatureVisitor.java delete mode 100644 src/main/java/org/objectweb/asm/signature/SignatureWriter.java delete mode 100644 src/main/java/org/objectweb/asm/tree/AbstractInsnNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/AnnotationNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/ClassNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/FieldInsnNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/FieldNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/FrameNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/IincInsnNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/InnerClassNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/InsnList.java delete mode 100644 src/main/java/org/objectweb/asm/tree/InsnNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/IntInsnNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/InvokeDynamicInsnNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/JumpInsnNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/LabelNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/LdcInsnNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/LineNumberNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/LocalVariableAnnotationNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/LocalVariableNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/LookupSwitchInsnNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/MethodInsnNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/MethodNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/ModuleExportNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/ModuleNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/ModuleOpenNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/ModuleProvideNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/ModuleRequireNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/MultiANewArrayInsnNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/ParameterNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/TableSwitchInsnNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/TryCatchBlockNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/TypeAnnotationNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/TypeInsnNode.java delete mode 100644 src/main/java/org/objectweb/asm/tree/UnsupportedClassVersionException.java delete mode 100644 src/main/java/org/objectweb/asm/tree/Util.java delete mode 100644 src/main/java/org/objectweb/asm/tree/VarInsnNode.java diff --git a/.gitignore b/.gitignore index 4ab9605d..a590cd17 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,7 @@ target/ dependency-reduced-pom.xml # Eclipse -.settings/ +.setup/ bin/ .classpath .project diff --git a/CHANGELOG.md b/CHANGELOG.md index a376c067..8c038dec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 1.0.0 +* Rewrote everything. + ## 0.9.0 * Changed all anonymous inner classes in MainGUI class to lambdas. * Brand new heavy string encryption transformer. diff --git a/README.md b/README.md index f23153dd..4930c735 100644 --- a/README.md +++ b/README.md @@ -1,136 +1,264 @@ -# Radon Java Obfuscator ![Build Status](https://travis-ci.org/ItzSomebody/Radon.svg?branch=master) -Yet another Java obfuscator. If I forgot to credit you, just make a pull-request or open an issue. +# Radon Java Obfuscator -Licenses get to go with the manifest in src/META-INF (yay!) +Usage: `java -jar Radon-Program.jar ExampleConfig.yml` -Usage: ```java -jar Radon.jar --config exampleconfig.yml``` +Alternatively, you can also use `java -jar Radon-Program.jar --help` for help. -Alternatively, you can also use ```java -jar Radon.jar --help``` for help. - -Example config: +Example configuration: ```yaml -Input: "C:/Users/Buddy/Desktop/RadonOBF/Counter.jar" -Output: "C:/Users/Buddy/Desktop/Counter-OBF.jar" -StringEncryption: Normal +Input: "C:/Users/ItzSomebody/Desktop/Example.jar" +Output: "C:/Users/ItzSomebody/Desktop/Example-OBF.jar" +StringEncryption: + Enabled: true + Mode: Heavy + StringPool: false + Exclusions: + - "Example String #1" + - "Example String #2" + - "Example String #3" InvokeDynamic: Heavy -FlowObfuscation: Normal -LocalVariableObfuscation: Remove -LineNumberObfuscation: Remove -SourceNameObfuscation: Remove -SourceDebugObfuscation: Remove -HideCode: True -Crasher: True -Shuffler: True -InnerClassRemover: True -StringPool: True -NumberObfuscation: True -TrashClasses: 50 -Renamer: True -WatermarkType: ConstantPool -WatermarkMessage: ItzSomebody -WatermarkKey: PASSWORD -ExpiryTime: 5/25/2018 -ExpiryMessage: "YOUR SOFTWARE TRIAL HAS ENDED!!! YOU MUST NOW PAY $100000000 FOR THE FULL VERSION LULZ" +NumberObfuscation: Heavy +FlowObfuscation: Heavy +LocalVariableObfuscation: + Enabled: true + Remove: true +LineNumberObfuscation: + Enabled: true + Remove: true +SourceNameObfuscation: + Enabled: true + Remove: true +SourceDebugObfuscation: + Enabled: true + Remove: true +HideCode: true +Shuffler: true +Crasher: true +Renamer: + Enabled: true + Repackage: "NotTheDefaultPackage" + AdaptResources: + - "META-INF/MANIFEST.MF" + - "Example.resource" +Optimizer: + Enabled: true + RemoveGotoGoto: true + RemoveGotoReturn: true + RemoveNopInstructions: true +Shrinker: + Enabled: true + RemoveAttributes: true + RemoveDebug: true + RemoveInvisibleAnnotations: true + RemoveVisibleAnnotations: true + RemoveUnusedCode: true + RemoveUnusedMembers: true +Watermarker: + Enabled: true + Message: "This copy belongs to ItzSomebody" + Key: "SuperSecureKey" +Expiration: + Enabled: true + InjectJOptionPane: true + Message: "Sorry, but your software trial has passed the expiration date. Please pay the ItzSomebody Corporation 30 billion USD to the paypal address non-existant@troll.email to receive the full version." + Expires: "12/31/2018" +Dictionary: Spaces +TrashClasses: 30 Libraries: - "C:/Program Files/Java/jre1.8.0_xxx/lib/rt.jar" -Exempts: - - "Class: org/objectweb/asm/*" - - "StringPool: me/itzsomebody/counter/Counter$1" - - "InvokeDynamic: me/itzsomebody/counter/Counter" - - "Renamer: me/itzsomebody/counter/Counter$1" - - "Renamer: me/itzsomebody/counter/Counter.process(*" + - "C:/Program Files/Java/jre1.8.0_xxx/lib/jce.jar" +Exclusions: + - "Global: me/itzsomebody/example/excludeallthis.*" + - "InvokeDynamic: me/itzsomebody/example/excludethisaswell.*" ``` -Valid config options you can use: +## Configuration Format +**Input:** + +The input key only takes one argument, a **string** providing the input file to the obfuscator. + +**Output:** + +The output key only takes one argument, a **string** providing the output file to the obfuscator to write the obfuscated result to. + +**StringEncryption:** -| Option | Expected Value(s) | Desc | +The string encryption key takes several arguments. + +| Key | Expected value(s) | Description | | --- | --- | --- | -| Input | String | Input file to obfuscate | -| Output | String | Output file to dump result of obfuscation | -| Libraries | String List | Libraries used to compile the input | -| Exempts | String List | Exempted classes, methods, or fields from obfuscation | -| StringEncryption | String (SuperLight/Light/Normal/Heavy) | Type of string encryption to apply | -| FlowObfuscation | String (Light/Normal) | Type of flow obfuscation to apply | -| InvokeDynamic | String (Light/Normal/Heavy) | Type of invokedynamic obfuscation to apply | -| LocalVariableObfuscation | String (Obfuscate/Remove) | Type of local variable obfuscation to apply | -| Crasher | Boolean | Determines if the decompiler crasher should be applied | -| HideCode | Boolean | Determines if synthetic modifiers should be applied | -| StringPool | Boolean | Determines if strings should be pooled | -| LineNumberObfuscation | String (Obfuscate/Remove) | Type of line number obfuscation to apply | -| NumberObfuscation | Boolean | Determines if integers should be split into simple math expressions | -| SourceNameObfuscation | String (Obfuscate/Remove) | Type of source name obfuscation to apply | -| SourceDebugObfuscation | String (Obfuscate/Remove) | Type of source debug obfuscation to apply | -| TrashClasses | Integer | Number of trash classes to generate | -| WatermarkMessage | String | Message to watermark into the output | -| WatermarkType | String (ConstantPool/Signature) | Type of watermark to apply | -| WatermarkKey | String | Key used to encrypt watermarks | -| SpigotPlugin | String | Determines if input should be treated as a spigot/bungee plugin | -| Renamer | Boolean | Determines if obfuscator should rename classes and methods | -| Shuffler | Boolean | Determines if obfuscator should re-arrange class members | -| InnerClassRemover | Boolean | Determines if obfuscator should remove inner-class information | -| ExpiryTime | String | Message to insert for expiry obfuscation (useful for trialware) | -| ExpiryMessage | String | Message to show when set your trialware goes past expiration date (rip) | -| Dictionary | Integer | Type of string generation to use in obfuscation. | - -## Dictionary types - -Valid dictionary types you can use: - -| Option | Description | -| --- | --- | -| 0 | (Default) Generates a string containing 10 characters composed entirely out of space-like characters. | -| 1 | Generates a string containing 10 characters unrecognized by the JVM causing them to show as white-boxes. | -| 2 | Generates an alpha-numeric string of length 4. | +| Enabled | Boolean | Determines if the string encryption transformer should be enabled. | +| Mode | String | Determines which type of string encryption to apply. Valid modes are: **Light**, **Normal** and **Heavy**. | +| StringPool | Boolean | Determines if strings should also be pooled on top of the string encryption. | +| Exclusions | List of Strings | Strings to prevent from being encrypted/pooled. Anything strings found in the input which contain these strings will be left untouched in the output. | + +**InvokeDynamic:** + +The invokedynamic key only takes one argument: a **string** determining which kind of invokedynamic to apply to the output jar. Valid modes are **Light**, **Normal** and **Heavy**. -## Exempting +**FlowObfuscation:** -The character '\*' can be used as a wildcard for "anything which starts with before this". So "me/itzsomebody/\*" will match "me/itzsomebody/ExampleClass1", "me/itzsomebody/example/ExampleClass2". This also works on method matching, "me/itzsomebody/example/Example.exampleMethod(*" will match any method which has the name "exampleMethod" in "me/itzsomebody/example/Example". +The flow obfuscation key only takes one argument: a **string** determining which kind of flow obfuscation to apply to the output jar. Valid modes are **Light**, **Normal** and **Heavy**. -Valid exempt types you can use: +**LocalVariableObfuscation:** -| Option | Expected Value(s) | Desc | +The local variables obfuscation key takes two arguments. + +| Key | Expected value(s) | Description | +| --- | --- | --- | +| Enabled | Boolean | Determines if local variable names should be obfuscated. | +| Remove | Boolean | Determines if local variable names should be removed altogether. | + +**LineNumberObfuscation:** + +The line number obfuscation key takes two arguments. + +| Key | Expected value(s) | Description | | --- | --- | --- | -| Class | Fully qualified name of internal class name (i.e. me/itzsomebody/counter/Counter) | Exempts entire classes from obfuscation. | -| Method | Fully qualified name of internal owner name + '.' + internal method name + internal method descriptor (i.e. me/itzsomebody/counter/Counter.exampleMethod()V) | Exempts entire method from obfuscation. | -| Field | Fully qualified name of internal owner name + '.' + internal field name | Exempts field from obfuscation. | -| StringEncryption | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter) | Exempts class or method from string encryption. | -| InvokeDynamic | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter) | Exempts class or method from invokedynamic obfuscation. | -| Flow | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter) | Exempts class or method from flow control obfuscation. | -| LocalVars | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter) | Exempts class or method from local variable obfuscation. | -| SourceName | Fully qualified internal name (i.e. me/itzsomebody/counter/Counter) | Exempts class source from name obfuscation. | -| SourceDebug | Fully qualified internal name (i.e. me/itzsomebody/counter/Counter) | Exempts class source from debug obfuscation. | -| LineNumbers | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter) | Exempts class or method from line number obfuscation. | -| StringPool | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter) | Exempts class or method from string pooling. | -| Crasher | Fully qualified internal name (i.e. me/itzsomebody/counter/Counter) | Exempts class from being added an invalid class signature. | -| HideCode | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter.exampleField or ) | Exempts class, method or field from hide code obfuscation. | -| Numbers | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter) | Exempts class or method number obfuscation. | -| Shuffler | Fully qualified internal name (i.e. me/itzsomebody/counter/Counter) | Exempts class from member shuffling. | -| InnerClasses | Fully qualified internal name (i.e. me/itzsomebody/counter/Counter) | Exempts class from inner-class information removal. | -| Renamer | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter.exampleField or ) | Exempts class, method or field from renaming. | -| Expiry | Fully qualified internal name (member name must be seperated from owner by a '.') (i.e. me/itzsomebody/counter/Counter.exampleMethod()V or me/itzsomebody/counter/Counter.exampleField or ) | Exempts class, method or field from expiration. | - -## Obfuscation description -This table describes the current obfuscation settings Radon has. - -| Obfuscation Type | Description | +| Enabled | Boolean | Determines if line numbers should be obfuscated. | +| Remove | Boolean | Determines if should be removed altogether. | + +**SourceNameObfuscation:** + +The source name obfuscation key takes two arguments. + +| Key | Expected value(s) | Description | +| --- | --- | --- | +| Enabled | Boolean | Determines if source names should be obfuscated. | +| Remove | Boolean | Determines if source names should be removed altogether. | + +**SourceDebugObfuscation:** + +The source debug obfuscation key takes two arguments. + +| Key | Expected value(s) | Description | +| --- | --- | --- | +| Enabled | Boolean | Determines if source debug information should be obfuscated. | +| Remove | Boolean | Determines if source debug information should be removed altogether. | + +**HideCode:** + +The hide code key takes only one argument: a **boolean** determining if hide code obfuscation should be applied. + +**Shuffler:** + +The shuffler key takes only one argument: a **boolean** determining if member shuffling should be applied. + +**Crasher:** + +The hide code key takes only one argument: a **boolean** determining if crashers should be applied. + +**Renamer:** + +The renamer key takes several arguments. + +| Key | Expected value(s) | Description | +| --- | --- | --- | +| Enabled | Boolean | Determines if identifier renaming should be enabled. | +| Repackage | String | Moves all classes into this package. | +| AdaptResources | List of Strings | Regular expressions which tell the obfuscator which resources to attempt to adapt the updated class mappings to. | + +**Optimizer:** + +The optimizer key takes several arguments. + +| Key | Expected value(s) | Description | +| --- | --- | --- | +| Enabled | Boolean | Determines if optimization should be enabled. | +| RemoveGotoGoto | Boolean | Determines if goto-goto sequences should be optimized. | +| RemoveGotoReturn | Boolean | Determines if goto-return sequences should be optimized. | +| RemoveNopInstructions | Boolean | Determines if nop instructions should be removed. | + +**Shrinker:** + +The shrinker key takes several arguments. + +| Key | Expected value(s) | Description | +| --- | --- | --- | +| Enabled | Boolean | Determines if shrinking should be enabled. | +| RemoveAttributes | Boolean | Determines if miscellaneous class attributes should be removed. | +| RemoveDebug | Boolean | Determines if miscellaneous debugging info (inner classes, outer class, outer method, etc.) should be removed. | +| RemoveInvisibleAnnotations | Boolean | Determines if invisible annotations should be removed. | +| RemoveVisibleAnnotations | Boolean | Determines if visible annotations should be removed. | +| RemoveUnusedCode | Boolean | Determines if unused code should be removed. | +| RemoveUnusedMembers | Boolean | Determines if unused members. | + +**Watermarker:** + +The watermarker key takes several arguments. + +| Key | Expected value(s) | Description | +| --- | --- | --- | +| Enabled | Boolean | Determines if watermarking should be enabled. | +| Message | String | Message to embed. | +| Key | String | Key to encrypt message with. | + +**Expiration:** + +The expiration key takes several arguments. + +| Key | Expected value(s) | Description | +| --- | --- | --- | +| Enabled | Boolean | Determines if expiration should be enabled. | +| InjectJOptionPane | Boolean | Determines if a JOptionPane should be injected into the code along with the Throwable. | +| Message | String | Message to show when the expiration date passes. | +| Expires | String | MM/dd/yyyy-formatted string of when the expiration date occurs. | + +**Dictionary:** + +The dictionary key takes only one argument: a **string** determining which dictionary to use when generating new names for classes and its members. Valid dictionaries are: **Spaces**, **Unrecognized**, **Alphabetical** and **Alphanumeric**. + +**TrashClasses:** + +The trash classes key takes only one argument: a **integer** determining how many trash classes should be generated. Any integer less than or equal to zero will disable trash classes. + +**Libraries:** + +The libraries key only takes one argument: a **list of strings** containing the paths of libraries the input jar is dependant on. + +**Exclusions:** + +The exclusions key takes only one argument: a **list of strings** containing exempts detailing how Radon should treat each class. + +## Exclusions + +Exclusions takes the following format: `: ` to dictate how Radon should treat exclusions. Exclusion statements are treated as **regular expressions**. + +To exclude methods, you must use the format: `: \.`. Similarly, fields are excluded in the format `: \.`. + +All classes, methods, and fields are checked against exclusion __***at their internal bytecode representations***__. This means that + +```java +package me.itzsomebody; + +public class Test { + public static void main(String[] args) { + System.out.println("Test"); + } +} +``` + +will be seen as `me/itzsomebody/Test.main([Ljava/lang/String)V` to Radon. Valid exclusion types you can use are: + +| Exclusion Type | Description | | --- | --- | -| StringEncryption | This takes the strings in your program and encrypts them. Each of the current settings are symmetrical and will NOT prevent reverse-engineers from figuring out what your program does. The super light setting uses an extremely simple xor algorithm and is not secure. The light setting uses a simple algorithm which encrypts the strings for speed. There is minimal flow obfuscation in the light setting so be aware this offers minimal protection. The normal string encryption setting is basically a flow-obfuscated version of the light string encryption, it is intended to make the decryption method more confusing. The heavy method is stacktrace-backed by both the caller and method name. | -| FlowObfuscation | This attempts to confuse the program flow to make the decompiled code harder to understand. The light setting replaces all gotos in the program with conditionals which always evaluate to true. The light setting usually doesn't affect decompiler results by much unless you have methods with some certain flow control situations. The normal flow obfuscation attempts to find places in the bytecode where the stack is empty. It uses an injected predicate which is used to make false jumps and add some extra throw-nulls in random places. The heavy setting takes the normal flow one step further by inserting a conditional which is always true after all conditional statements found in the bytecode. | -| InvokeDynamic | This abuses Java 7's new opcode, the invokedynamic. This replaces certain member access with dynamic invocations. The light invokedynamic transformer is very simple and replaces invokestatic, invokevirtual and invokeinterface with invokedynamics. This is easily reversed by experienced reverse-engineers so don't rely on this. The normal invokedynamic protection is a very slight improvement to the light settings, but still is easy to reverse. The heavy invokedynamic hides invokestatic, invokevirtual, getstatic, putstatic, getfield and putfield opcodes with invokedynamics. | -| LocalVariableObfuscation | This attempts to prevent local variable analysis. The obfuscation setting changes the names of the local variables to hard-to-read UTF-8 characters. The remove setting removes the local variable information completely destroying the ability to recover the local variable names. Removal setting tends to shrink jar size since it removes information in the code. | -| Crasher | This adds an invalid signature to classes. The intention of this transformer is to crash a majority of decompiles which attempt to take class signatures into account of the output. This crashes JD-GUI, Procyon, CFR and Javap. | -| HideCode | This adds certain access flag modifiers to members of your code. Synthetic modifiers are added to classes, methods and fields and bridge modifiers are added to methods which aren't initializer methods (\ and \). | -| StringPool | This adds a method into the class which takes all the strings in the class and pools them into the added method. | -| LineNumberObfuscation | This attempts to obscure stacktrace output by changing line number debug information. The obfuscation setting sets line numbers to random ones. The removal setting removes them from your code entirely. The removal setting also shrinks the size of the jar. | -| NumberObfuscation | This splits integers into a xor expression making it difficult to determine what number is being used. This is defeated by Krakatau. | -| SourceNameObfuscation | This attempts to obscure stacktrace output by removing sourcefile debug information. The obfuscation setting sets all the source file names to random ones. The removal setting removes them entirely from your code. The removal setting also shrinks the size of the jar. | -| SourceDebugObfuscation | This attempts to obscure source debug information. The obfuscation setting sets all the source debug values to random ones. The removal setting removes them entirely from your code. The removal setting also shrinks the size of the jar. | -| TrashClasses | This generates garbage classes which aren't used to attempt to hide the ones that are actually used. This also prevents JByteEdit usage which is a widely used tool by people who implement Minecraft plugin cracks. | -| Watermark | This marks a message into the classes which is intended for customer-identification. The constant pool option marks the message into the constant pool of each class. The signature option marks the messages into the class signature. | -| Renamer | This renames classes, methods and fields from their original names to random UTF-8 strings. | -| Shuffler | This simply changes the order of class members (methods and fields). | -| InnerClassRemover | This removes innerclass information. | -| ExpirationObfuscation | This adds a block of expiration code into each class initializer to prevent usage of jar after the expiration date has passed. | +| Global | Exempts a class/method/field from any kind of tampering (except for watermarking). | +| StringEncryption | Exempts a class/method from having its string literals encrypted. | +| InvokeDynamic | Exempts a class/method from having its method calls hidden with invokedynamic instructions. | +| FlowObfuscation | Exempts a class/method from having its methods flow-obfuscated. | +| LineNumbers | Exempts a class/method from having its line numbers tampered with. | +| LocalVariables | Exempts a class/method from having its local variables tampered with. | +| NumberObfuscation | Exempts a class/method from having its integer and long constants obfuscated. | +| HideCode | Exempts a class/method/field from having access codes added into its flags. | +| Crasher | Exempts a class from having an invalid type signature being added. | +| Expiration | Exempts a class/method from having an expiration code block being inserted. | +| Optimizer | Exempts a class/method from attempting to be optimized. | +| Shrinker | Exempts a class/methods from attempting to strip information/code Radon deems unnecessary. | +| Shuffler | Exempts a class from having its members (methods and fields) order randomized. | +| SourceName | Exempts a class from having its source name debugging information being tampered with. | +| SourceDebug | Exempts a class from having its source debug information being tampered with. | +| StringPool | Exempts a class/method from having its string literals pooled. | +| Renamer | Exempts a class/method/field from being renamed. | ## FAQ * **Q: Is this uncrackable/undeobfuscatable?** @@ -142,15 +270,14 @@ This table describes the current obfuscation settings Radon has. * **Q: Why are concepts taken directly from other obfuscators/bytecode manipulation tools? (i.e. expiration transformer which is directly based on Allatori's expiration obfuscation)** * *A: I thought those would be interesting to include in an obfuscation tool. This is also one of the reasons Radon is open-sourced.* -## Credits +## Attribution * [OW2 ASM](http://asm.ow2.org) - Bytecode manipulation framework. -* [SnakeYaml](http://www.snakeyaml.org) - Configuration parser. +* [SnakeYaml](http://www.snakeyaml.org) - YAML parser. * [VincBreaker](https://github.com/Vinc0682) - Author of Smoke obfuscator which I took some ideas from. (i.e. Renaming classes as spaces and splitting numbers into bitwise xor operations) * [WindowBuilder by Eclipse](https://www.eclipse.org/windowbuilder/) - Used to make GUI (yes I know it's Java Swing, I didn't feel like remaking it in JavaFX) * [Licel](https://licelus.com) - Makers of IndyProtect which I used as a reference for my invokedynamic transformers. * [Allatori Dev Team](http://www.allatori.com) - Makers of Allatori Java Obfuscator which I took the concept of watermarking and expiration obfuscation from. -* [Artel](https://gitlab.com/artel) - Beta tester. ## License diff --git a/Radon-GUI/pom.xml b/Radon-GUI/pom.xml new file mode 100644 index 00000000..b4ce6201 --- /dev/null +++ b/Radon-GUI/pom.xml @@ -0,0 +1,56 @@ + + + + Radon + me.itzsomebody + 1.0.0 + + 4.0.0 + Radon-GUI + + src/main/java + + + src/main/resources + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + me.itzsomebody.radon.gui.Main + true + custom + Radon-Program.jar + + + + + + maven-compiler-plugin + 3.7.0 + + 1.8 + 1.8 + + -XDignore.symbol.file + + true + + + + + + + me.itzsomebody + Radon-Program + 1.0.0 + + + \ No newline at end of file diff --git a/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/Main.java b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/Main.java new file mode 100644 index 00000000..510ad50e --- /dev/null +++ b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/Main.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.gui; + +import java.io.File; +import javax.swing.*; + +public class Main { + public static void main(String[] args) { + runChecks(); + new RadonGUI(); + } + + private static void runChecks() { + File file = new File("Radon-Program.jar"); + if (!file.exists()) { + JOptionPane.showMessageDialog(null, "Radon-Program.jar was not found in directory.", "Radon not found.", JOptionPane.ERROR_MESSAGE); + throw new RuntimeException(); + } + + try { + Class.forName("me.itzsomebody.radon.Radon"); + } catch (ClassNotFoundException e) { + JOptionPane.showMessageDialog(null, "me.itzsomebody.radon.Radon class was not found.", "Radon instance class not found.", JOptionPane.ERROR_MESSAGE); + throw new RuntimeException(); + } + } +} diff --git a/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/RadonGUI.java b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/RadonGUI.java new file mode 100644 index 00000000..6ea7fae6 --- /dev/null +++ b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/RadonGUI.java @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.gui; + +import java.awt.*; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.util.ArrayList; +import javax.swing.*; +import me.itzsomebody.radon.Main; +import me.itzsomebody.radon.Radon; +import me.itzsomebody.radon.SessionInfo; +import me.itzsomebody.radon.config.ConfigurationWriter; +import me.itzsomebody.radon.gui.tabs.ConsoleTab; +import me.itzsomebody.radon.gui.tabs.ExclusionsTab; +import me.itzsomebody.radon.gui.tabs.InputOutputTab; +import me.itzsomebody.radon.gui.tabs.MiscellaneousTab; +import me.itzsomebody.radon.gui.tabs.ObfuscationTab; +import me.itzsomebody.radon.gui.tabs.OptimizationTab; +import me.itzsomebody.radon.gui.tabs.ShrinkingTab; +import me.itzsomebody.radon.gui.tabs.WatermarkingTab; +import me.itzsomebody.radon.transformers.Transformer; + +class RadonGUI extends JFrame { + RadonGUI() { + setTitle(Main.PREFIX + " - " + Main.VERSION); + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + // Ignored + } + setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + setSize(700, 570); + setLocationRelativeTo(null); + + JTabbedPane tabsPane = new JTabbedPane(JTabbedPane.LEFT); + getContentPane().add(tabsPane, BorderLayout.CENTER); + + InputOutputTab inputOutputTab = new InputOutputTab(); + tabsPane.addTab("Input-Output", null, inputOutputTab, null); + + ObfuscationTab obfuscationPanel = new ObfuscationTab(); + tabsPane.addTab("Obfuscation", null, obfuscationPanel, null); + + OptimizationTab optimizationPanel = new OptimizationTab(); + tabsPane.addTab("Optimization", null, optimizationPanel, null); + + ShrinkingTab shrinkingPanel = new ShrinkingTab(); + tabsPane.addTab("Shrinking", null, shrinkingPanel, null); + + WatermarkingTab watermarkingPanel = new WatermarkingTab(); + tabsPane.addTab("Watermarking", null, watermarkingPanel, null); + + MiscellaneousTab miscPanel = new MiscellaneousTab(); + tabsPane.addTab("Miscellaneous", null, miscPanel, null); + + ExclusionsTab exclusionPanel = new ExclusionsTab(); + tabsPane.addTab("Exclusions", null, exclusionPanel, null); + + ConsoleTab consolePanel = new ConsoleTab(); + tabsPane.addTab("Console", null, consolePanel, null); + + JPanel bottomToolBar = new JPanel(); + getContentPane().add(bottomToolBar, BorderLayout.SOUTH); + bottomToolBar.setLayout(new BorderLayout(0, 0)); + + JPanel toolBarPanel = new JPanel(); + bottomToolBar.add(toolBarPanel, BorderLayout.EAST); + + JButton loadConfigButton = new JButton("Load Configuration"); + loadConfigButton.addActionListener((e) -> { + // TODO + }); + toolBarPanel.add(loadConfigButton); + + JButton saveConfigButton = new JButton("Save Configuration"); + saveConfigButton.addActionListener((e) -> { + JFileChooser chooser = new JFileChooser(); + chooser.setMultiSelectionEnabled(false); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + int result = chooser.showOpenDialog(this); + if (result == 0) { + SwingUtilities.invokeLater(() -> { + try { + SessionInfo sessionInfo = new SessionInfo(); + + sessionInfo.setInput(new File(inputOutputTab.getInputPath())); + sessionInfo.setOutput(new File(inputOutputTab.getOutputPath())); + sessionInfo.setLibraries(inputOutputTab.getLibraries()); + + ArrayList transformers = new ArrayList<>(); + transformers.add(shrinkingPanel.getShrinker()); + transformers.add(optimizationPanel.getOptimizer()); + transformers.add(obfuscationPanel.getRenamer()); + transformers.add(obfuscationPanel.getNumberObfuscation()); + transformers.add(obfuscationPanel.getInvokeDynamic()); + transformers.add(obfuscationPanel.getStringEncryption()); + transformers.add(obfuscationPanel.getStringPool()); + transformers.add(obfuscationPanel.getFlowObfuscation()); + transformers.add(obfuscationPanel.getShuffler()); + transformers.add(obfuscationPanel.getLocalVarObfuscation()); + transformers.add(obfuscationPanel.getLineNumberObfuscation()); + transformers.add(obfuscationPanel.getSourceNameObfuscation()); + transformers.add(obfuscationPanel.getSourceDebugObfuscation()); + transformers.add(obfuscationPanel.getCrasher()); + transformers.add(obfuscationPanel.getHideCodeObfuscation()); + transformers.add(miscPanel.getExpiration()); + transformers.add(watermarkingPanel.getWatermarker()); + sessionInfo.setTransformers(transformers); + + sessionInfo.setExclusions(exclusionPanel.getExclusions()); + + sessionInfo.setTrashClasses(miscPanel.getTrashClasses()); + sessionInfo.setDictionaryType(miscPanel.getDictionary()); + + ConfigurationWriter writer = new ConfigurationWriter(sessionInfo); + File file = chooser.getSelectedFile(); + BufferedWriter bw = new BufferedWriter(new FileWriter(file)); + bw.write(writer.dump()); + bw.close(); + } catch (Throwable t) { + JOptionPane.showMessageDialog(null, "Error while creating config, check console for details.", "Error", JOptionPane.ERROR_MESSAGE); + } + }); + } + }); + toolBarPanel.add(saveConfigButton); + + JButton processButton = new JButton("Process"); + processButton.addActionListener((e) -> { + consolePanel.resetConsole(); + processButton.setText("Processing..."); + processButton.setEnabled(false); + + SwingWorker sw = new SwingWorker() { + @Override + protected Object doInBackground() { + try { + SessionInfo sessionInfo = new SessionInfo(); + + sessionInfo.setInput(new File(inputOutputTab.getInputPath())); + sessionInfo.setOutput(new File(inputOutputTab.getOutputPath())); + sessionInfo.setLibraries(inputOutputTab.getLibraries()); + + ArrayList transformers = new ArrayList<>(); + transformers.add(shrinkingPanel.getShrinker()); + transformers.add(optimizationPanel.getOptimizer()); + transformers.add(obfuscationPanel.getRenamer()); + transformers.add(obfuscationPanel.getNumberObfuscation()); + transformers.add(obfuscationPanel.getInvokeDynamic()); + transformers.add(obfuscationPanel.getStringEncryption()); + transformers.add(obfuscationPanel.getStringPool()); + transformers.add(obfuscationPanel.getFlowObfuscation()); + transformers.add(obfuscationPanel.getShuffler()); + transformers.add(obfuscationPanel.getLocalVarObfuscation()); + transformers.add(obfuscationPanel.getLineNumberObfuscation()); + transformers.add(obfuscationPanel.getSourceNameObfuscation()); + transformers.add(obfuscationPanel.getSourceDebugObfuscation()); + transformers.add(obfuscationPanel.getCrasher()); + transformers.add(obfuscationPanel.getHideCodeObfuscation()); + transformers.add(miscPanel.getExpiration()); + transformers.add(watermarkingPanel.getWatermarker()); + sessionInfo.setTransformers(transformers); + + sessionInfo.setExclusions(exclusionPanel.getExclusions()); + + sessionInfo.setTrashClasses(miscPanel.getTrashClasses()); + sessionInfo.setDictionaryType(miscPanel.getDictionary()); + + Radon radon = new Radon(sessionInfo); + radon.partyTime(); + + JOptionPane.showMessageDialog(null, "Processed successfully.", "Done", JOptionPane.INFORMATION_MESSAGE); + } catch (Throwable t) { + t.printStackTrace(); + JOptionPane.showMessageDialog(null, "Error happened while processing, check the console for details.", "Error", JOptionPane.ERROR_MESSAGE); + } finally { + processButton.setText("Process"); + processButton.setEnabled(true); + } + return null; + } + }; + + sw.execute(); + }); + toolBarPanel.add(processButton); + setVisible(true); + } +} diff --git a/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/StringEncryptionExclusionGUI.java b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/StringEncryptionExclusionGUI.java new file mode 100644 index 00000000..d992f6c8 --- /dev/null +++ b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/StringEncryptionExclusionGUI.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.gui; + +import java.awt.*; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.List; +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import me.itzsomebody.radon.gui.tabs.ObfuscationTab; + +public class StringEncryptionExclusionGUI extends JFrame { + public StringEncryptionExclusionGUI() { + setTitle("String Exclusions"); + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + // Ignored + } + setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + setSize(450, 300); + setLocationRelativeTo(null); + JPanel contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + GridBagLayout gbl_contentPane = new GridBagLayout(); + gbl_contentPane.columnWidths = new int[]{0, 0, 0, 0}; + gbl_contentPane.rowHeights = new int[]{0, 0, 0}; + gbl_contentPane.columnWeights = new double[]{1.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_contentPane.rowWeights = new double[]{1.0, 0.0, Double.MIN_VALUE}; + contentPane.setLayout(gbl_contentPane); + + JScrollPane exclusionScrollPane = new JScrollPane(); + GridBagConstraints gbc_exclusionScrollPane = new GridBagConstraints(); + gbc_exclusionScrollPane.gridwidth = 3; + gbc_exclusionScrollPane.insets = new Insets(5, 5, 5, 5); + gbc_exclusionScrollPane.fill = GridBagConstraints.BOTH; + gbc_exclusionScrollPane.gridx = 0; + gbc_exclusionScrollPane.gridy = 0; + contentPane.add(exclusionScrollPane, gbc_exclusionScrollPane); + + DefaultListModel exclusionList = new DefaultListModel<>(); + for (String s : ObfuscationTab.stringExclusions) { + exclusionList.addElement(s); + } + JList exclusionJList = new JList<>(exclusionList); + exclusionScrollPane.setViewportView(exclusionJList); + + JTextField exclusionField = new JTextField(); + GridBagConstraints gbc_exclusionField = new GridBagConstraints(); + gbc_exclusionField.insets = new Insets(0, 5, 5, 5); + gbc_exclusionField.fill = GridBagConstraints.HORIZONTAL; + gbc_exclusionField.gridx = 0; + gbc_exclusionField.gridy = 1; + contentPane.add(exclusionField, gbc_exclusionField); + exclusionField.setColumns(10); + + JButton exclusionAddButton = new JButton("Add"); + GridBagConstraints gbc_exclusionAddButton = new GridBagConstraints(); + gbc_exclusionAddButton.fill = GridBagConstraints.HORIZONTAL; + gbc_exclusionAddButton.insets = new Insets(0, 0, 5, 5); + gbc_exclusionAddButton.gridx = 1; + gbc_exclusionAddButton.gridy = 1; + exclusionAddButton.addActionListener((e) -> { + if (exclusionField.getText() != null && !exclusionField.getText().isEmpty()) { + if (!ObfuscationTab.stringExclusions.contains(exclusionField.getText())) { + exclusionList.addElement(exclusionField.getText()); + } + exclusionField.setText(null); + } + }); + contentPane.add(exclusionAddButton, gbc_exclusionAddButton); + + JButton exclusionRemoveButton = new JButton("Remove"); + GridBagConstraints gbc_exclusionRemoveButton = new GridBagConstraints(); + gbc_exclusionRemoveButton.insets = new Insets(0, 0, 5, 5); + gbc_exclusionRemoveButton.fill = GridBagConstraints.HORIZONTAL; + gbc_exclusionRemoveButton.gridx = 2; + gbc_exclusionRemoveButton.gridy = 1; + exclusionRemoveButton.addActionListener((e) -> { + List removeList = exclusionJList.getSelectedValuesList(); + if (removeList.isEmpty()) + return; + + for (String s : removeList) { + exclusionList.removeElement(s); + } + }); + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + for (int i = 0; i < exclusionList.size(); i++) { + if (!ObfuscationTab.stringExclusions.contains(exclusionList.get(i))) { + ObfuscationTab.stringExclusions.add(exclusionList.get(i)); + } + } + dispose(); + } + }); + contentPane.add(exclusionRemoveButton, gbc_exclusionRemoveButton); + setVisible(true); + } +} diff --git a/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ConsoleTab.java b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ConsoleTab.java new file mode 100644 index 00000000..355d91b6 --- /dev/null +++ b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ConsoleTab.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.gui.tabs; + +import java.awt.*; +import java.io.OutputStream; +import java.io.PrintStream; +import javax.swing.*; +import javax.swing.border.TitledBorder; + +public class ConsoleTab extends JPanel { + private JTextArea consoleTextArea; + + public ConsoleTab() { + GridBagLayout gbl_this = new GridBagLayout(); + gbl_this.columnWidths = new int[]{0, 0}; + gbl_this.rowHeights = new int[]{0, 0}; + gbl_this.columnWeights = new double[]{1.0, Double.MIN_VALUE}; + gbl_this.rowWeights = new double[]{1.0, Double.MIN_VALUE}; + this.setBorder(new TitledBorder("Console")); + this.setLayout(gbl_this); + + JScrollPane consoleScrollPane = new JScrollPane(); + GridBagConstraints gbc_consoleScrollPane = new GridBagConstraints(); + gbc_consoleScrollPane.fill = GridBagConstraints.BOTH; + gbc_consoleScrollPane.gridx = 0; + gbc_consoleScrollPane.gridy = 0; + this.add(consoleScrollPane, gbc_consoleScrollPane); + + consoleTextArea = new JTextArea(); + consoleTextArea.setEditable(false); + consoleScrollPane.setViewportView(consoleTextArea); + + PrintStream customPrintStream = new PrintStream(new OutputStreamRedirect(consoleTextArea)); + System.setOut(customPrintStream); + System.setErr(customPrintStream); + } + + class OutputStreamRedirect extends OutputStream { + private JTextArea consoleOutput; + + private OutputStreamRedirect(JTextArea consoleOutput) { + this.consoleOutput = consoleOutput; + } + + @Override + public void write(int b) { + this.consoleOutput.append(String.valueOf((char) b)); + this.consoleOutput.setCaretPosition(this.consoleOutput.getDocument().getLength()); + } + } + + public void resetConsole() { + consoleTextArea.setText(null); + } +} diff --git a/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ExclusionsTab.java b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ExclusionsTab.java new file mode 100644 index 00000000..8270ad0f --- /dev/null +++ b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ExclusionsTab.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.gui.tabs; + +import java.awt.*; +import java.util.List; +import javax.swing.*; +import me.itzsomebody.radon.exclusions.Exclusion; +import me.itzsomebody.radon.exclusions.ExclusionManager; +import me.itzsomebody.radon.exclusions.ExclusionType; + +public class ExclusionsTab extends JPanel { + private DefaultListModel exclusions; + + public ExclusionsTab() { + GridBagLayout gbl_this = new GridBagLayout(); + gbl_this.columnWidths = new int[]{0, 0, 0, 0, 0}; + gbl_this.rowHeights = new int[]{0, 0, 0}; + gbl_this.columnWeights = new double[]{0.0, 1.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_this.rowWeights = new double[]{1.0, 0.0, Double.MIN_VALUE}; + this.setLayout(gbl_this); + + JScrollPane exclusionScrollPane = new JScrollPane(); + GridBagConstraints gbc_exclusionScrollPane = new GridBagConstraints(); + gbc_exclusionScrollPane.gridwidth = 4; + gbc_exclusionScrollPane.insets = new Insets(5, 5, 5, 5); + gbc_exclusionScrollPane.fill = GridBagConstraints.BOTH; + gbc_exclusionScrollPane.gridx = 0; + gbc_exclusionScrollPane.gridy = 0; + this.add(exclusionScrollPane, gbc_exclusionScrollPane); + + exclusions = new DefaultListModel<>(); + JList exclusionList = new JList<>(exclusions); + exclusionScrollPane.setViewportView(exclusionList); + + JComboBox exclusionComboBox = new JComboBox<>(); + GridBagConstraints gbc_exclusionComboBox = new GridBagConstraints(); + gbc_exclusionComboBox.insets = new Insets(0, 5, 5, 5); + gbc_exclusionComboBox.fill = GridBagConstraints.HORIZONTAL; + gbc_exclusionComboBox.gridx = 0; + gbc_exclusionComboBox.gridy = 1; + exclusionComboBox.addItem(ExclusionType.GLOBAL.getValue()); + exclusionComboBox.addItem(ExclusionType.STRING_ENCRYPTION.getValue()); + exclusionComboBox.addItem(ExclusionType.INVOKEDYNAMIC.getValue()); + exclusionComboBox.addItem(ExclusionType.FLOW_OBFUSCATION.getValue()); + exclusionComboBox.addItem(ExclusionType.LINE_NUMBERS.getValue()); + exclusionComboBox.addItem(ExclusionType.LOCAL_VARIABLES.getValue()); + exclusionComboBox.addItem(ExclusionType.NUMBER_OBFUSCATION.getValue()); + exclusionComboBox.addItem(ExclusionType.HIDE_CODE.getValue()); + exclusionComboBox.addItem(ExclusionType.CRASHER.getValue()); + exclusionComboBox.addItem(ExclusionType.EXPIRATION.getValue()); + exclusionComboBox.addItem(ExclusionType.OPTIMIZER.getValue()); + exclusionComboBox.addItem(ExclusionType.SHRINKER.getValue()); + exclusionComboBox.addItem(ExclusionType.SHUFFLER.getValue()); + exclusionComboBox.addItem(ExclusionType.SOURCE_NAME.getValue()); + exclusionComboBox.addItem(ExclusionType.SOURCE_DEBUG.getValue()); + exclusionComboBox.addItem(ExclusionType.STRING_POOL.getValue()); + exclusionComboBox.addItem(ExclusionType.RENAMER.getValue()); + this.add(exclusionComboBox, gbc_exclusionComboBox); + + JTextField exclusionField = new JTextField(); + GridBagConstraints gbc_exclusionField = new GridBagConstraints(); + gbc_exclusionField.insets = new Insets(0, 0, 5, 5); + gbc_exclusionField.fill = GridBagConstraints.HORIZONTAL; + gbc_exclusionField.gridx = 1; + gbc_exclusionField.gridy = 1; + this.add(exclusionField, gbc_exclusionField); + exclusionField.setColumns(10); + + JButton exclusionAddButton = new JButton("Add"); + GridBagConstraints gbc_exclusionAddButton = new GridBagConstraints(); + gbc_exclusionAddButton.insets = new Insets(0, 0, 5, 5); + gbc_exclusionAddButton.gridx = 2; + gbc_exclusionAddButton.gridy = 1; + exclusionAddButton.addActionListener((e) -> { + if (exclusionField.getText() != null && !exclusionField.getText().isEmpty()) { + exclusions.addElement(exclusionComboBox.getItemAt(exclusionComboBox.getSelectedIndex()) + ": " + exclusionField.getText()); + exclusionField.setText(null); + } + }); + this.add(exclusionAddButton, gbc_exclusionAddButton); + + JButton exclusionRemoveButton = new JButton("Remove"); + GridBagConstraints gbc_exclusionRemoveButton = new GridBagConstraints(); + gbc_exclusionRemoveButton.insets = new Insets(0, 0, 5, 5); + gbc_exclusionRemoveButton.gridx = 3; + gbc_exclusionRemoveButton.gridy = 1; + exclusionRemoveButton.addActionListener((e) -> { + List removeList = exclusionList.getSelectedValuesList(); + if (removeList.isEmpty()) + return; + + for (String s : removeList) { + exclusions.removeElement(s); + } + }); + this.add(exclusionRemoveButton, gbc_exclusionRemoveButton); + } + + public ExclusionManager getExclusions() { + ExclusionManager manager = new ExclusionManager(); + for (int i = 0; i < exclusions.size(); i++) { + manager.addExclusion(new Exclusion(exclusions.get(i))); + } + + return manager; + } +} diff --git a/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/InputOutputTab.java b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/InputOutputTab.java new file mode 100644 index 00000000..faafc6ab --- /dev/null +++ b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/InputOutputTab.java @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.gui.tabs; + +import java.awt.*; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import javax.swing.*; +import javax.swing.border.TitledBorder; + +public class InputOutputTab extends JPanel { + private JTextField inputField; + private JTextField outputField; + private DefaultListModel libraryList; + private File lastPath; + + public InputOutputTab() { + GridBagLayout gbl_this = new GridBagLayout(); + gbl_this.columnWidths = new int[]{0, 0}; + gbl_this.rowHeights = new int[]{0, 378, 0}; + gbl_this.columnWeights = new double[]{1.0, Double.MIN_VALUE}; + gbl_this.rowWeights = new double[]{0.0, 1.0, Double.MIN_VALUE}; + this.setLayout(gbl_this); + + JPanel inputOutputPanel = new JPanel(); + GridBagConstraints gbc_inputOutputPanel = new GridBagConstraints(); + gbc_inputOutputPanel.insets = new Insets(0, 0, 5, 0); + gbc_inputOutputPanel.fill = GridBagConstraints.BOTH; + gbc_inputOutputPanel.gridx = 0; + gbc_inputOutputPanel.gridy = 0; + inputOutputPanel.setBorder(new TitledBorder("Input-Output")); + this.add(inputOutputPanel, gbc_inputOutputPanel); + + GridBagLayout gbl_inputOutputPanel = new GridBagLayout(); + gbl_inputOutputPanel.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gbl_inputOutputPanel.rowHeights = new int[]{0, 0, 0}; + gbl_inputOutputPanel.columnWeights = new double[]{0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_inputOutputPanel.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE}; + inputOutputPanel.setLayout(gbl_inputOutputPanel); + + JLabel inputLabel = new JLabel("Input:"); + GridBagConstraints gbc_inputLabel = new GridBagConstraints(); + gbc_inputLabel.anchor = GridBagConstraints.EAST; + gbc_inputLabel.insets = new Insets(5, 5, 5, 5); + gbc_inputLabel.gridx = 0; + gbc_inputLabel.gridy = 0; + inputOutputPanel.add(inputLabel, gbc_inputLabel); + + this.inputField = new JTextField(); + GridBagConstraints gbc_inputField = new GridBagConstraints(); + gbc_inputField.gridwidth = 17; + gbc_inputField.insets = new Insets(5, 0, 5, 5); + gbc_inputField.fill = GridBagConstraints.BOTH; + gbc_inputField.gridx = 1; + gbc_inputField.gridy = 0; + inputOutputPanel.add(inputField, gbc_inputField); + inputField.setColumns(10); + + JButton inputButton = new JButton("Select"); + GridBagConstraints gbc_inputButton = new GridBagConstraints(); + gbc_inputButton.fill = GridBagConstraints.BOTH; + gbc_inputButton.insets = new Insets(5, 0, 5, 5); + gbc_inputButton.gridx = 18; + gbc_inputButton.gridy = 0; + inputButton.addActionListener((e) -> { + JFileChooser chooser = new JFileChooser(); + if (inputField.getText() != null && !inputField.getText().isEmpty()) { + chooser.setSelectedFile(new File(inputField.getText())); + } + chooser.setMultiSelectionEnabled(false); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + if (lastPath != null) + chooser.setCurrentDirectory(lastPath); + int result = chooser.showOpenDialog(this); + if (result == 0) { + SwingUtilities.invokeLater(() -> { + inputField.setText(chooser.getSelectedFile().getAbsolutePath()); + lastPath = chooser.getSelectedFile(); + }); + } + }); + inputOutputPanel.add(inputButton, gbc_inputButton); + + JLabel outputLabel = new JLabel("Output:"); + GridBagConstraints gbc_outputLabel = new GridBagConstraints(); + gbc_outputLabel.anchor = GridBagConstraints.EAST; + gbc_outputLabel.insets = new Insets(0, 5, 5, 5); + gbc_outputLabel.gridx = 0; + gbc_outputLabel.gridy = 1; + inputOutputPanel.add(outputLabel, gbc_outputLabel); + + this.outputField = new JTextField(); + GridBagConstraints gbc_outputField = new GridBagConstraints(); + gbc_outputField.gridwidth = 17; + gbc_outputField.insets = new Insets(0, 0, 5, 5); + gbc_outputField.fill = GridBagConstraints.BOTH; + gbc_outputField.gridx = 1; + gbc_outputField.gridy = 1; + inputOutputPanel.add(outputField, gbc_outputField); + outputField.setColumns(10); + + JButton outputButton = new JButton("Select"); + GridBagConstraints gbc_outputButton = new GridBagConstraints(); + gbc_outputButton.fill = GridBagConstraints.BOTH; + gbc_outputButton.insets = new Insets(0, 0, 5, 5); + gbc_outputButton.gridx = 18; + gbc_outputButton.gridy = 1; + outputButton.addActionListener((e) -> { + JFileChooser chooser = new JFileChooser(); + if (outputField.getText() != null && !outputField.getText().isEmpty()) { + chooser.setSelectedFile(new File(outputField.getText())); + } + chooser.setMultiSelectionEnabled(false); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + if (lastPath != null) + chooser.setCurrentDirectory(lastPath); + int result = chooser.showOpenDialog(this); + if (result == 0) { + SwingUtilities.invokeLater(() -> { + outputField.setText(chooser.getSelectedFile().getAbsolutePath()); + lastPath = chooser.getSelectedFile(); + }); + } + }); + inputOutputPanel.add(outputButton, gbc_outputButton); + + JPanel librariesPanel = new JPanel(); + GridBagConstraints gbc_librariesPanel = new GridBagConstraints(); + gbc_librariesPanel.fill = GridBagConstraints.BOTH; + gbc_librariesPanel.gridx = 0; + gbc_librariesPanel.gridy = 1; + librariesPanel.setBorder(new TitledBorder("Libraries")); + this.add(librariesPanel, gbc_librariesPanel); + + GridBagLayout gbl_librariesPanel = new GridBagLayout(); + gbl_librariesPanel.columnWidths = new int[]{500, 33}; + gbl_librariesPanel.rowHeights = new int[]{0, 0}; + gbl_librariesPanel.columnWeights = new double[]{1.0, 0.0}; + gbl_librariesPanel.rowWeights = new double[]{1.0, Double.MIN_VALUE}; + librariesPanel.setLayout(gbl_librariesPanel); + + JScrollPane librariesPane = new JScrollPane(); + GridBagConstraints gbc_librariesPane = new GridBagConstraints(); + gbc_librariesPane.insets = new Insets(0, 0, 0, 5); + gbc_librariesPane.fill = GridBagConstraints.BOTH; + gbc_librariesPane.gridx = 0; + gbc_librariesPane.gridy = 0; + librariesPanel.add(librariesPane, gbc_librariesPane); + + libraryList = new DefaultListModel<>(); + String jreHome = System.getProperty("java.home"); + if (jreHome != null) { + libraryList.addElement(jreHome + "/lib/rt.jar"); + libraryList.addElement(jreHome + "/lib/jce.jar"); + } + JList librariesJList = new JList<>(libraryList); + librariesPane.setViewportView(librariesJList); + + JPanel librariesButtonPanel = new JPanel(); + GridBagConstraints gbc_librariesButtonPanel = new GridBagConstraints(); + gbc_librariesButtonPanel.fill = GridBagConstraints.BOTH; + gbc_librariesButtonPanel.gridx = 1; + gbc_librariesButtonPanel.gridy = 0; + librariesPanel.add(librariesButtonPanel, gbc_librariesButtonPanel); + + GridBagLayout gbl_librariesButtonPanel = new GridBagLayout(); + gbl_librariesButtonPanel.columnWidths = new int[]{0, 0}; + gbl_librariesButtonPanel.rowHeights = new int[]{0, 0, 0, 0, 0}; + gbl_librariesButtonPanel.columnWeights = new double[]{0.0, Double.MIN_VALUE}; + gbl_librariesButtonPanel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + librariesButtonPanel.setLayout(gbl_librariesButtonPanel); + + JButton librariesAddButton = new JButton("Add"); + GridBagConstraints gbc_librariesAddButton = new GridBagConstraints(); + gbc_librariesAddButton.fill = GridBagConstraints.HORIZONTAL; + gbc_librariesAddButton.insets = new Insets(0, 0, 5, 5); + gbc_librariesAddButton.gridx = 0; + gbc_librariesAddButton.gridy = 0; + librariesAddButton.addActionListener((e) -> { + JFileChooser chooser = new JFileChooser(); + if (inputField.getText() != null && !inputField.getText().isEmpty()) { + chooser.setSelectedFile(new File(inputField.getText())); + } + chooser.setMultiSelectionEnabled(true); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + if (lastPath != null) + chooser.setCurrentDirectory(lastPath); + int result = chooser.showOpenDialog(this); + if (result == 0) { + SwingUtilities.invokeLater(() -> { + for (File file : chooser.getSelectedFiles()) { + libraryList.addElement(file.getAbsolutePath()); + } + + lastPath = chooser.getSelectedFile(); + }); + } + }); + librariesButtonPanel.add(librariesAddButton, gbc_librariesAddButton); + + JButton librariesRemoveButton = new JButton("Remove"); + GridBagConstraints gbc_librariesRemoveButton = new GridBagConstraints(); + gbc_librariesRemoveButton.insets = new Insets(0, 0, 5, 5); + gbc_librariesRemoveButton.fill = GridBagConstraints.HORIZONTAL; + gbc_librariesRemoveButton.gridx = 0; + gbc_librariesRemoveButton.gridy = 1; + librariesRemoveButton.addActionListener((e) -> { + List removeList = librariesJList.getSelectedValuesList(); + if (removeList.isEmpty()) + return; + + for (String s : removeList) { + libraryList.removeElement(s); + } + }); + librariesButtonPanel.add(librariesRemoveButton, gbc_librariesRemoveButton); + + JButton librariesResetButton = new JButton("Reset"); + GridBagConstraints gbc_librariesResetButton = new GridBagConstraints(); + gbc_librariesResetButton.fill = GridBagConstraints.HORIZONTAL; + gbc_librariesResetButton.insets = new Insets(0, 0, 5, 5); + gbc_librariesResetButton.gridx = 0; + gbc_librariesResetButton.gridy = 2; + librariesResetButton.addActionListener((e) -> { + libraryList.clear(); + + String javaHome = System.getProperty("java.home"); + if (javaHome != null) { + libraryList.addElement(javaHome + "/lib/rt.jar"); + libraryList.addElement(javaHome + "/lib/jce.jar"); + } + }); + librariesButtonPanel.add(librariesResetButton, gbc_librariesResetButton); + } + + public String getInputPath() { + return this.inputField.getText(); + } + + public String getOutputPath() { + return this.outputField.getText(); + } + + public List getLibraries() { + ArrayList libs = new ArrayList<>(); + for (int i = 0; i < this.libraryList.size(); i++) { + libs.add(new File(this.libraryList.get(i))); + } + + return libs; + } +} diff --git a/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/MiscellaneousTab.java b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/MiscellaneousTab.java new file mode 100644 index 00000000..6cfd8f4b --- /dev/null +++ b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/MiscellaneousTab.java @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.gui.tabs; + +import java.awt.*; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import me.itzsomebody.radon.Dictionaries; +import me.itzsomebody.radon.Main; +import me.itzsomebody.radon.transformers.miscellaneous.expiration.Expiration; +import me.itzsomebody.radon.transformers.miscellaneous.expiration.ExpirationSetup; + +public class MiscellaneousTab extends JPanel { + private JCheckBox expirationSwingCheckBox; + private JTextField expirationMessageField; + private JTextField expirationExpiresField; + private JCheckBox expirationEnabledCheckBox; + private JComboBox dictionaryComboBox; + private JTextField trashClassesField; + + public MiscellaneousTab() { + GridBagLayout gbl_this = new GridBagLayout(); + gbl_this.columnWidths = new int[]{0, 0}; + gbl_this.rowHeights = new int[]{0, 0, 0}; + gbl_this.columnWeights = new double[]{1.0, Double.MIN_VALUE}; + gbl_this.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE}; + this.setLayout(gbl_this); + + JPanel expirationPanel = new JPanel(); + GridBagConstraints gbc_expirationPanel = new GridBagConstraints(); + gbc_expirationPanel.insets = new Insets(0, 0, 5, 0); + gbc_expirationPanel.fill = GridBagConstraints.BOTH; + gbc_expirationPanel.gridx = 0; + gbc_expirationPanel.gridy = 0; + this.add(expirationPanel, gbc_expirationPanel); + GridBagLayout gbl_expirationPanel = new GridBagLayout(); + gbl_expirationPanel.columnWidths = new int[]{0, 0}; + gbl_expirationPanel.rowHeights = new int[]{0, 29, 0}; + gbl_expirationPanel.columnWeights = new double[]{1.0, Double.MIN_VALUE}; + gbl_expirationPanel.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE}; + expirationPanel.setBorder(new TitledBorder("Expiration")); + expirationPanel.setLayout(gbl_expirationPanel); + + JPanel expirationSetupPanel = new JPanel(); + GridBagConstraints gbc_expirationSetupPanel = new GridBagConstraints(); + gbc_expirationSetupPanel.fill = GridBagConstraints.HORIZONTAL; + gbc_expirationSetupPanel.gridx = 0; + gbc_expirationSetupPanel.gridy = 1; + expirationSetupPanel.setBorder(new TitledBorder("Setup")); + expirationPanel.add(expirationSetupPanel, gbc_expirationSetupPanel); + GridBagLayout gbl_expirationSetupPanel = new GridBagLayout(); + gbl_expirationSetupPanel.columnWidths = new int[]{0, 0, 0}; + gbl_expirationSetupPanel.rowHeights = new int[]{0, 0, 0, 0}; + gbl_expirationSetupPanel.columnWeights = new double[]{0.0, 1.0, Double.MIN_VALUE}; + gbl_expirationSetupPanel.rowWeights = new double[]{0.0, 0.0, 0.0, Double.MIN_VALUE}; + expirationSetupPanel.setLayout(gbl_expirationSetupPanel); + + expirationSwingCheckBox = new JCheckBox("Inject JOptionPane Message"); + GridBagConstraints gbc_expirationSwingCheckBox = new GridBagConstraints(); + gbc_expirationSwingCheckBox.anchor = GridBagConstraints.WEST; + gbc_expirationSwingCheckBox.gridwidth = 2; + gbc_expirationSwingCheckBox.insets = new Insets(0, 0, 5, 5); + gbc_expirationSwingCheckBox.gridx = 0; + gbc_expirationSwingCheckBox.gridy = 0; + expirationSwingCheckBox.setEnabled(false); + expirationSetupPanel.add(expirationSwingCheckBox, gbc_expirationSwingCheckBox); + + JLabel expirationMessageLabel = new JLabel("Message:"); + GridBagConstraints gbc_expirationMessageLabel = new GridBagConstraints(); + gbc_expirationMessageLabel.anchor = GridBagConstraints.EAST; + gbc_expirationMessageLabel.insets = new Insets(0, 5, 5, 5); + gbc_expirationMessageLabel.gridx = 0; + gbc_expirationMessageLabel.gridy = 1; + expirationSetupPanel.add(expirationMessageLabel, gbc_expirationMessageLabel); + + expirationMessageField = new JTextField(); + GridBagConstraints gbc_expirationMessageField = new GridBagConstraints(); + gbc_expirationMessageField.insets = new Insets(0, 0, 5, 5); + gbc_expirationMessageField.fill = GridBagConstraints.HORIZONTAL; + gbc_expirationMessageField.gridx = 1; + gbc_expirationMessageField.gridy = 1; + expirationMessageField.setEditable(false); + expirationSetupPanel.add(expirationMessageField, gbc_expirationMessageField); + expirationMessageField.setColumns(10); + + JLabel expirationExpiresLabel = new JLabel("Expires:"); + GridBagConstraints gbc_expirationExpiresLabel = new GridBagConstraints(); + gbc_expirationExpiresLabel.anchor = GridBagConstraints.EAST; + gbc_expirationExpiresLabel.insets = new Insets(0, 0, 0, 5); + gbc_expirationExpiresLabel.gridx = 0; + gbc_expirationExpiresLabel.gridy = 2; + expirationSetupPanel.add(expirationExpiresLabel, gbc_expirationExpiresLabel); + + expirationExpiresField = new JTextField(); + GridBagConstraints gbc_expirationExpiresField = new GridBagConstraints(); + gbc_expirationExpiresField.insets = new Insets(0, 0, 5, 5); + gbc_expirationExpiresField.fill = GridBagConstraints.HORIZONTAL; + gbc_expirationExpiresField.gridx = 1; + gbc_expirationExpiresField.gridy = 2; + expirationExpiresField.setEditable(false); + expirationSetupPanel.add(expirationExpiresField, gbc_expirationExpiresField); + expirationExpiresField.setColumns(10); + + expirationEnabledCheckBox = new JCheckBox("Enabled"); + GridBagConstraints gbc_expirationEnabledCheckBox = new GridBagConstraints(); + gbc_expirationEnabledCheckBox.anchor = GridBagConstraints.WEST; + gbc_expirationEnabledCheckBox.insets = new Insets(0, 0, 5, 0); + gbc_expirationEnabledCheckBox.gridx = 0; + gbc_expirationEnabledCheckBox.gridy = 0; + expirationEnabledCheckBox.addActionListener((e) -> { + boolean enable = expirationEnabledCheckBox.isSelected(); + + expirationSwingCheckBox.setEnabled(enable); + expirationMessageField.setEditable(enable); + expirationExpiresField.setEditable(enable); + }); + expirationPanel.add(expirationEnabledCheckBox, gbc_expirationEnabledCheckBox); + + JPanel miscOtherPanel = new JPanel(); + GridBagConstraints gbc_miscOtherPanel = new GridBagConstraints(); + gbc_miscOtherPanel.fill = GridBagConstraints.BOTH; + gbc_miscOtherPanel.gridx = 0; + gbc_miscOtherPanel.gridy = 1; + this.add(miscOtherPanel, gbc_miscOtherPanel); + GridBagLayout gbl_miscOtherPanel = new GridBagLayout(); + gbl_miscOtherPanel.columnWidths = new int[]{0, 0, 0}; + gbl_miscOtherPanel.rowHeights = new int[]{32, 0, 0}; + gbl_miscOtherPanel.columnWeights = new double[]{0.0, 1.0, Double.MIN_VALUE}; + gbl_miscOtherPanel.rowWeights = new double[]{1.0, 1.0, Double.MIN_VALUE}; + miscOtherPanel.setBorder(new TitledBorder("Other")); + miscOtherPanel.setLayout(gbl_miscOtherPanel); + + JButton garbagCollectorButton = new JButton("Garbage Collector"); + GridBagConstraints gbc_garbagCollectorButton = new GridBagConstraints(); + gbc_garbagCollectorButton.fill = GridBagConstraints.HORIZONTAL; + gbc_garbagCollectorButton.insets = new Insets(0, 5, 0, 5); + gbc_garbagCollectorButton.gridx = 0; + gbc_garbagCollectorButton.gridy = 0; + garbagCollectorButton.addActionListener((e) -> SwingUtilities.invokeLater(() -> { + JOptionPane.showMessageDialog(null, ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1000000) + "mb in use before garbage collection."); + System.gc(); + })); + miscOtherPanel.add(garbagCollectorButton, gbc_garbagCollectorButton); + + JPanel dictionaryPanel = new JPanel(); + GridBagConstraints gbc_dictionaryPanel = new GridBagConstraints(); + gbc_dictionaryPanel.insets = new Insets(0, 0, 5, 0); + gbc_dictionaryPanel.anchor = GridBagConstraints.EAST; + gbc_dictionaryPanel.fill = GridBagConstraints.VERTICAL; + gbc_dictionaryPanel.gridx = 1; + gbc_dictionaryPanel.gridy = 0; + dictionaryPanel.setBorder(new TitledBorder("Dictionary")); + miscOtherPanel.add(dictionaryPanel, gbc_dictionaryPanel); + GridBagLayout gbl_dictionaryPanel = new GridBagLayout(); + gbl_dictionaryPanel.columnWidths = new int[]{0, 0}; + gbl_dictionaryPanel.rowHeights = new int[]{0, 0}; + gbl_dictionaryPanel.columnWeights = new double[]{1.0, Double.MIN_VALUE}; + gbl_dictionaryPanel.rowWeights = new double[]{0.0, Double.MIN_VALUE}; + dictionaryPanel.setLayout(gbl_dictionaryPanel); + + dictionaryComboBox = new JComboBox<>(); + GridBagConstraints gbc_dictionaryComboBox = new GridBagConstraints(); + gbc_dictionaryComboBox.insets = new Insets(0, 5, 5, 5); + gbc_dictionaryComboBox.fill = GridBagConstraints.HORIZONTAL; + gbc_dictionaryComboBox.gridx = 0; + gbc_dictionaryComboBox.gridy = 0; + dictionaryComboBox.addItem(Dictionaries.SPACES.getValue()); + dictionaryComboBox.addItem(Dictionaries.UNRECOGNIZED.getValue()); + dictionaryComboBox.addItem(Dictionaries.ALPHABETICAL.getValue()); + dictionaryComboBox.addItem(Dictionaries.ALPHANUMERIC.getValue()); + dictionaryPanel.add(dictionaryComboBox, gbc_dictionaryComboBox); + + JPanel trashClassPanel = new JPanel(); + GridBagConstraints gbc_trashClassPanel = new GridBagConstraints(); + gbc_trashClassPanel.insets = new Insets(0, 0, 5, 0); + gbc_trashClassPanel.anchor = GridBagConstraints.EAST; + gbc_trashClassPanel.fill = GridBagConstraints.VERTICAL; + gbc_trashClassPanel.gridx = 1; + gbc_trashClassPanel.gridy = 1; + trashClassPanel.setBorder(new TitledBorder("Trash Classes")); + miscOtherPanel.add(trashClassPanel, gbc_trashClassPanel); + GridBagLayout gbl_trashClassPanel = new GridBagLayout(); + gbl_trashClassPanel.columnWidths = new int[]{0, 0}; + gbl_trashClassPanel.rowHeights = new int[]{0, 0}; + gbl_trashClassPanel.columnWeights = new double[]{1.0, Double.MIN_VALUE}; + gbl_trashClassPanel.rowWeights = new double[]{0.0, Double.MIN_VALUE}; + trashClassPanel.setLayout(gbl_trashClassPanel); + + trashClassesField = new JTextField(); + GridBagConstraints gbc_trashClassesField = new GridBagConstraints(); + gbc_trashClassesField.insets = new Insets(0, 0, 5, 5); + gbc_trashClassesField.fill = GridBagConstraints.HORIZONTAL; + gbc_trashClassesField.gridx = 0; + gbc_trashClassesField.gridy = 0; + trashClassesField.setText("0"); + trashClassPanel.add(trashClassesField, gbc_trashClassesField); + trashClassesField.setColumns(10); + + JButton aboutButton = new JButton("About"); + GridBagConstraints gbc_aboutButton = new GridBagConstraints(); + gbc_aboutButton.fill = GridBagConstraints.HORIZONTAL; + gbc_aboutButton.insets = new Insets(0, 5, 5, 5); + gbc_aboutButton.gridx = 0; + gbc_aboutButton.gridy = 1; + aboutButton.addActionListener((e) -> JOptionPane.showMessageDialog(null, Main.PROPAGANDA_GARBAGE)); + miscOtherPanel.add(aboutButton, gbc_aboutButton); + } + + public Expiration getExpiration() { + try { + return (expirationEnabledCheckBox.isSelected()) ? new Expiration(new ExpirationSetup(expirationMessageField.getText(), + new SimpleDateFormat("MM/dd/yyyy").parse(expirationExpiresField.getText()).getTime(), expirationSwingCheckBox.isSelected())) : null; + } catch (ParseException e) { + e.printStackTrace(); + throw new RuntimeException(); + } + } + + public int getTrashClasses() { + return Integer.valueOf(trashClassesField.getText()); + } + + public Dictionaries getDictionary() { + return Dictionaries.intToDictionary(dictionaryComboBox.getSelectedIndex()); + } +} diff --git a/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ObfuscationTab.java b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ObfuscationTab.java new file mode 100644 index 00000000..0d1f2e23 --- /dev/null +++ b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ObfuscationTab.java @@ -0,0 +1,536 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.gui.tabs; + +import java.awt.*; +import java.util.ArrayList; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import me.itzsomebody.radon.gui.StringEncryptionExclusionGUI; +import me.itzsomebody.radon.transformers.miscellaneous.Crasher; +import me.itzsomebody.radon.transformers.obfuscators.flow.FlowObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.flow.HeavyFlowObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.flow.LightFlowObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.flow.NormalFlowObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.invokedynamic.HeavyInvokeDynamic; +import me.itzsomebody.radon.transformers.obfuscators.invokedynamic.InvokeDynamic; +import me.itzsomebody.radon.transformers.obfuscators.invokedynamic.LightInvokeDynamic; +import me.itzsomebody.radon.transformers.obfuscators.invokedynamic.NormalInvokeDynamic; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.HideCode; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.LineNumbers; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.LocalVariables; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.MemberShuffler; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.SourceDebug; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.SourceName; +import me.itzsomebody.radon.transformers.obfuscators.numbers.HeavyNumberObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.numbers.LightNumberObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.numbers.NormalNumberObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.numbers.NumberObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.renamer.Renamer; +import me.itzsomebody.radon.transformers.obfuscators.renamer.RenamerSetup; +import me.itzsomebody.radon.transformers.obfuscators.strings.HeavyStringEncryption; +import me.itzsomebody.radon.transformers.obfuscators.strings.LightStringEncryption; +import me.itzsomebody.radon.transformers.obfuscators.strings.NormalStringEncryption; +import me.itzsomebody.radon.transformers.obfuscators.strings.StringEncryption; +import me.itzsomebody.radon.transformers.obfuscators.strings.StringEncryptionSetup; +import me.itzsomebody.radon.transformers.obfuscators.strings.StringPool; + +public class ObfuscationTab extends JPanel { + public static ArrayList stringExclusions = new ArrayList<>(); + private JComboBox stringEncryptionTypeSelector; + private JCheckBox stringPoolCheckBox; + private JCheckBox stringEncryptionEnabledCheckBox; + + private JCheckBox renamingRepackageCheckBox; + private JTextField renamingRepackageField; + private JCheckBox renamingAdaptResources; + private JTextField renamingResourcesField; + private JCheckBox renamingEnabledCheckBox; + + private JComboBox invokeDynamicComboBox; + private JCheckBox invokeDynamicCheckBox; + + private JComboBox flowComboBox; + private JCheckBox flowCheckBox; + + private JComboBox numberObfuscationComboBox; + private JCheckBox numberObfuscationCheckBox; + + private JCheckBox localVarsRemove; + private JCheckBox localVarCheckBox; + + private JCheckBox lineNumbersRemove; + private JCheckBox lineNumbersCheckBox; + + private JCheckBox sourceNameRemove; + private JCheckBox sourceNameCheckBox; + + private JCheckBox sourceDebugRemove; + private JCheckBox sourceDebugCheckBox; + + private JCheckBox hideCodeCheckBox; + private JCheckBox shufflerCheckBox; + private JCheckBox crasherCheckBox; + + public ObfuscationTab() { + GridBagLayout gbl_this = new GridBagLayout(); + gbl_this.columnWidths = new int[]{0, 0}; + gbl_this.rowHeights = new int[]{35, 25, 162, 0}; + gbl_this.columnWeights = new double[]{1.0, Double.MIN_VALUE}; + gbl_this.rowWeights = new double[]{0.0, 0.0, 0.0, Double.MIN_VALUE}; + this.setLayout(gbl_this); + + JPanel stringEncryptionPanel = new JPanel(); + GridBagConstraints gbc_stringEncryptionPanel = new GridBagConstraints(); + gbc_stringEncryptionPanel.insets = new Insets(0, 0, 5, 0); + gbc_stringEncryptionPanel.fill = GridBagConstraints.BOTH; + gbc_stringEncryptionPanel.gridx = 0; + gbc_stringEncryptionPanel.gridy = 0; + this.add(stringEncryptionPanel, gbc_stringEncryptionPanel); + GridBagLayout gbl_stringEncryptionPanel = new GridBagLayout(); + gbl_stringEncryptionPanel.columnWidths = new int[]{0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gbl_stringEncryptionPanel.rowHeights = new int[]{0, 0, 0}; + gbl_stringEncryptionPanel.columnWeights = new double[]{1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_stringEncryptionPanel.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE}; + stringEncryptionPanel.setBorder(new TitledBorder("String Encryption")); + stringEncryptionPanel.setLayout(gbl_stringEncryptionPanel); + + stringEncryptionTypeSelector = new JComboBox<>(); + GridBagConstraints gbc_stringEncryptionTypeSelector = new GridBagConstraints(); + gbc_stringEncryptionTypeSelector.fill = GridBagConstraints.HORIZONTAL; + gbc_stringEncryptionTypeSelector.insets = new Insets(0, 0, 5, 5); + gbc_stringEncryptionTypeSelector.gridx = 15; + gbc_stringEncryptionTypeSelector.gridy = 0; + stringEncryptionTypeSelector.addItem("Light"); + stringEncryptionTypeSelector.addItem("Normal"); + stringEncryptionTypeSelector.addItem("Heavy"); + stringEncryptionTypeSelector.setEnabled(false); + stringEncryptionPanel.add(stringEncryptionTypeSelector, gbc_stringEncryptionTypeSelector); + + stringPoolCheckBox = new JCheckBox("Pool Strings"); + GridBagConstraints gbc_stringPoolCheckBox = new GridBagConstraints(); + gbc_stringPoolCheckBox.anchor = GridBagConstraints.WEST; + gbc_stringPoolCheckBox.insets = new Insets(0, 0, 5, 5); + gbc_stringPoolCheckBox.gridx = 0; + gbc_stringPoolCheckBox.gridy = 1; + stringPoolCheckBox.setEnabled(false); + stringEncryptionPanel.add(stringPoolCheckBox, gbc_stringPoolCheckBox); + + JButton stringEncryptionExclusionButtons = new JButton("Exclusions"); + GridBagConstraints gbc_stringEncryptionExclusionButtons = new GridBagConstraints(); + gbc_stringEncryptionExclusionButtons.anchor = GridBagConstraints.EAST; + gbc_stringEncryptionExclusionButtons.insets = new Insets(0, 0, 5, 5); + gbc_stringEncryptionExclusionButtons.gridx = 15; + gbc_stringEncryptionExclusionButtons.gridy = 1; + stringEncryptionExclusionButtons.setEnabled(false); + stringEncryptionExclusionButtons.addActionListener((e) -> new StringEncryptionExclusionGUI()); + stringEncryptionPanel.add(stringEncryptionExclusionButtons, gbc_stringEncryptionExclusionButtons); + + stringEncryptionEnabledCheckBox = new JCheckBox("Enabled"); + GridBagConstraints gbc_stringEncryptionEnabledCheckBox = new GridBagConstraints(); + gbc_stringEncryptionEnabledCheckBox.anchor = GridBagConstraints.WEST; + gbc_stringEncryptionEnabledCheckBox.insets = new Insets(0, 0, 5, 5); + gbc_stringEncryptionEnabledCheckBox.gridx = 0; + gbc_stringEncryptionEnabledCheckBox.gridy = 0; + stringEncryptionEnabledCheckBox.addActionListener((e) -> { + boolean enable = stringEncryptionEnabledCheckBox.isSelected(); + stringEncryptionTypeSelector.setEnabled(enable); + stringPoolCheckBox.setEnabled(enable); + stringEncryptionExclusionButtons.setEnabled(enable); + }); + stringEncryptionPanel.add(stringEncryptionEnabledCheckBox, gbc_stringEncryptionEnabledCheckBox); + + JPanel renamingPanel = new JPanel(); + GridBagConstraints gbc_renamingPanel = new GridBagConstraints(); + gbc_renamingPanel.insets = new Insets(0, 0, 5, 0); + gbc_renamingPanel.fill = GridBagConstraints.BOTH; + gbc_renamingPanel.gridx = 0; + gbc_renamingPanel.gridy = 1; + renamingPanel.setBorder(new TitledBorder("Renaming")); + this.add(renamingPanel, gbc_renamingPanel); + GridBagLayout gbl_renamingPanel = new GridBagLayout(); + gbl_renamingPanel.columnWidths = new int[]{0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gbl_renamingPanel.rowHeights = new int[]{0, 0, 0, 0}; + gbl_renamingPanel.columnWeights = new double[]{1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, Double.MIN_VALUE}; + gbl_renamingPanel.rowWeights = new double[]{0.0, 0.0, 0.0, Double.MIN_VALUE}; + renamingPanel.setLayout(gbl_renamingPanel); + + renamingRepackageCheckBox = new JCheckBox("Repackage"); + GridBagConstraints gbc_renamingRepackageCheckBox = new GridBagConstraints(); + gbc_renamingRepackageCheckBox.anchor = GridBagConstraints.WEST; + gbc_renamingRepackageCheckBox.insets = new Insets(0, 0, 5, 5); + gbc_renamingRepackageCheckBox.gridx = 0; + gbc_renamingRepackageCheckBox.gridy = 1; + renamingRepackageCheckBox.setEnabled(false); + renamingPanel.add(renamingRepackageCheckBox, gbc_renamingRepackageCheckBox); + + renamingRepackageField = new JTextField(); + GridBagConstraints gbc_renamingRepackageField = new GridBagConstraints(); + gbc_renamingRepackageField.gridwidth = 2; + gbc_renamingRepackageField.insets = new Insets(0, 0, 5, 5); + gbc_renamingRepackageField.fill = GridBagConstraints.HORIZONTAL; + gbc_renamingRepackageField.gridx = 14; + gbc_renamingRepackageField.gridy = 1; + renamingRepackageField.setEditable(false); + renamingPanel.add(renamingRepackageField, gbc_renamingRepackageField); + renamingRepackageField.setColumns(10); + + renamingAdaptResources = new JCheckBox("Adapt Resources"); + GridBagConstraints gbc_renamingAdaptResources = new GridBagConstraints(); + gbc_renamingAdaptResources.anchor = GridBagConstraints.WEST; + gbc_renamingAdaptResources.insets = new Insets(0, 0, 5, 5); + gbc_renamingAdaptResources.gridx = 0; + gbc_renamingAdaptResources.gridy = 2; + renamingAdaptResources.setEnabled(false); + renamingPanel.add(renamingAdaptResources, gbc_renamingAdaptResources); + + renamingResourcesField = new JTextField(); + GridBagConstraints gbc_renamingResourcesField = new GridBagConstraints(); + gbc_renamingResourcesField.gridwidth = 2; + gbc_renamingResourcesField.insets = new Insets(0, 0, 5, 5); + gbc_renamingResourcesField.fill = GridBagConstraints.HORIZONTAL; + gbc_renamingResourcesField.gridx = 14; + gbc_renamingResourcesField.gridy = 2; + renamingResourcesField.setEditable(false); + renamingPanel.add(renamingResourcesField, gbc_renamingResourcesField); + renamingResourcesField.setColumns(10); + + renamingEnabledCheckBox = new JCheckBox("Enabled"); + GridBagConstraints gbc_renamingEnabledCheckBox = new GridBagConstraints(); + gbc_renamingEnabledCheckBox.insets = new Insets(0, 0, 5, 5); + gbc_renamingEnabledCheckBox.anchor = GridBagConstraints.WEST; + gbc_renamingEnabledCheckBox.gridx = 0; + gbc_renamingEnabledCheckBox.gridy = 0; + renamingEnabledCheckBox.addActionListener((e) -> { + boolean enable = renamingEnabledCheckBox.isSelected(); + renamingRepackageCheckBox.setEnabled(enable); + renamingRepackageField.setEditable(enable); + renamingAdaptResources.setEnabled(enable); + renamingResourcesField.setEditable(enable); + }); + renamingPanel.add(renamingEnabledCheckBox, gbc_renamingEnabledCheckBox); + + JPanel otherPanel = new JPanel(); + GridBagConstraints gbc_otherPanel = new GridBagConstraints(); + gbc_otherPanel.fill = GridBagConstraints.BOTH; + gbc_otherPanel.gridx = 0; + gbc_otherPanel.gridy = 2; + otherPanel.setBorder(new TitledBorder("Other")); + this.add(otherPanel, gbc_otherPanel); + GridBagLayout gbl_otherPanel = new GridBagLayout(); + gbl_otherPanel.columnWidths = new int[]{74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gbl_otherPanel.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + gbl_otherPanel.columnWeights = new double[]{1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + gbl_otherPanel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + otherPanel.setLayout(gbl_otherPanel); + + invokeDynamicComboBox = new JComboBox<>(); + GridBagConstraints gbc_invokeDynamicComboBox = new GridBagConstraints(); + gbc_invokeDynamicComboBox.fill = GridBagConstraints.HORIZONTAL; + gbc_invokeDynamicComboBox.insets = new Insets(0, 0, 5, 0); + gbc_invokeDynamicComboBox.gridx = 15; + gbc_invokeDynamicComboBox.gridy = 0; + invokeDynamicComboBox.addItem("Light"); + invokeDynamicComboBox.addItem("Normal"); + invokeDynamicComboBox.addItem("Heavy"); + invokeDynamicComboBox.setEnabled(false); + otherPanel.add(invokeDynamicComboBox, gbc_invokeDynamicComboBox); + + invokeDynamicCheckBox = new JCheckBox("InvokeDynamic"); + GridBagConstraints gbc_invokeDynamicCheckBox = new GridBagConstraints(); + gbc_invokeDynamicCheckBox.anchor = GridBagConstraints.WEST; + gbc_invokeDynamicCheckBox.insets = new Insets(0, 0, 5, 5); + gbc_invokeDynamicCheckBox.gridx = 0; + gbc_invokeDynamicCheckBox.gridy = 0; + invokeDynamicCheckBox.addActionListener((e) -> invokeDynamicComboBox.setEnabled(invokeDynamicCheckBox.isSelected())); + otherPanel.add(invokeDynamicCheckBox, gbc_invokeDynamicCheckBox); + + flowComboBox = new JComboBox<>(); + GridBagConstraints gbc_flowComboBox = new GridBagConstraints(); + gbc_flowComboBox.fill = GridBagConstraints.HORIZONTAL; + gbc_flowComboBox.insets = new Insets(0, 0, 5, 0); + gbc_flowComboBox.gridx = 15; + gbc_flowComboBox.gridy = 1; + flowComboBox.addItem("Light"); + flowComboBox.addItem("Normal"); + flowComboBox.addItem("Heavy"); + flowComboBox.setEnabled(false); + otherPanel.add(flowComboBox, gbc_flowComboBox); + + flowCheckBox = new JCheckBox("Flow Obfuscation"); + GridBagConstraints gbc_flowCheckBox = new GridBagConstraints(); + gbc_flowCheckBox.anchor = GridBagConstraints.WEST; + gbc_flowCheckBox.insets = new Insets(0, 0, 5, 5); + gbc_flowCheckBox.gridx = 0; + gbc_flowCheckBox.gridy = 1; + flowCheckBox.addActionListener((e) -> flowComboBox.setEnabled(flowCheckBox.isSelected())); + otherPanel.add(flowCheckBox, gbc_flowCheckBox); + + numberObfuscationComboBox = new JComboBox<>(); + GridBagConstraints gbc_numberObfuscationComboBox = new GridBagConstraints(); + gbc_numberObfuscationComboBox.insets = new Insets(0, 0, 5, 0); + gbc_numberObfuscationComboBox.fill = GridBagConstraints.HORIZONTAL; + gbc_numberObfuscationComboBox.gridx = 15; + gbc_numberObfuscationComboBox.gridy = 2; + numberObfuscationComboBox.addItem("Light"); + numberObfuscationComboBox.addItem("Normal"); + numberObfuscationComboBox.addItem("Heavy"); + numberObfuscationComboBox.setEnabled(false); + otherPanel.add(numberObfuscationComboBox, gbc_numberObfuscationComboBox); + + numberObfuscationCheckBox = new JCheckBox("Number Obfuscation"); + GridBagConstraints gbc_numberObfuscationCheckBox = new GridBagConstraints(); + gbc_numberObfuscationCheckBox.anchor = GridBagConstraints.WEST; + gbc_numberObfuscationCheckBox.insets = new Insets(0, 0, 5, 5); + gbc_numberObfuscationCheckBox.gridx = 0; + gbc_numberObfuscationCheckBox.gridy = 2; + numberObfuscationCheckBox.addActionListener((e) -> numberObfuscationComboBox.setEnabled(numberObfuscationCheckBox.isSelected())); + otherPanel.add(numberObfuscationCheckBox, gbc_numberObfuscationCheckBox); + + localVarsRemove = new JCheckBox("Remove"); + GridBagConstraints gbc_localVarsRemove = new GridBagConstraints(); + gbc_localVarsRemove.fill = GridBagConstraints.HORIZONTAL; + gbc_localVarsRemove.insets = new Insets(0, 0, 5, 0); + gbc_localVarsRemove.gridx = 15; + gbc_localVarsRemove.gridy = 3; + localVarsRemove.setEnabled(false); + otherPanel.add(localVarsRemove, gbc_localVarsRemove); + + localVarCheckBox = new JCheckBox("Local Variables"); + GridBagConstraints gbc_localVarCheckBox = new GridBagConstraints(); + gbc_localVarCheckBox.anchor = GridBagConstraints.WEST; + gbc_localVarCheckBox.insets = new Insets(0, 0, 5, 5); + gbc_localVarCheckBox.gridx = 0; + gbc_localVarCheckBox.gridy = 3; + localVarCheckBox.addActionListener((e) -> localVarsRemove.setEnabled(localVarCheckBox.isSelected())); + otherPanel.add(localVarCheckBox, gbc_localVarCheckBox); + + lineNumbersRemove = new JCheckBox("Remove"); + GridBagConstraints gbc_lineNumbersRemove = new GridBagConstraints(); + gbc_lineNumbersRemove.fill = GridBagConstraints.HORIZONTAL; + gbc_lineNumbersRemove.insets = new Insets(0, 0, 5, 0); + gbc_lineNumbersRemove.gridx = 15; + gbc_lineNumbersRemove.gridy = 4; + lineNumbersRemove.setEnabled(false); + otherPanel.add(lineNumbersRemove, gbc_lineNumbersRemove); + + lineNumbersCheckBox = new JCheckBox("Line Numbers"); + GridBagConstraints gbc_lineNumbersCheckBox = new GridBagConstraints(); + gbc_lineNumbersCheckBox.anchor = GridBagConstraints.WEST; + gbc_lineNumbersCheckBox.insets = new Insets(0, 0, 5, 5); + gbc_lineNumbersCheckBox.gridx = 0; + gbc_lineNumbersCheckBox.gridy = 4; + lineNumbersCheckBox.addActionListener((e) -> lineNumbersRemove.setEnabled(lineNumbersCheckBox.isSelected())); + otherPanel.add(lineNumbersCheckBox, gbc_lineNumbersCheckBox); + + sourceNameRemove = new JCheckBox("Remove"); + GridBagConstraints gbc_sourceNameRemove = new GridBagConstraints(); + gbc_sourceNameRemove.fill = GridBagConstraints.HORIZONTAL; + gbc_sourceNameRemove.insets = new Insets(0, 0, 5, 0); + gbc_sourceNameRemove.gridx = 15; + gbc_sourceNameRemove.gridy = 5; + sourceNameRemove.setEnabled(false); + otherPanel.add(sourceNameRemove, gbc_sourceNameRemove); + + sourceNameCheckBox = new JCheckBox("Source Name"); + GridBagConstraints gbc_sourceNameCheckBox = new GridBagConstraints(); + gbc_sourceNameCheckBox.anchor = GridBagConstraints.WEST; + gbc_sourceNameCheckBox.insets = new Insets(0, 0, 5, 5); + gbc_sourceNameCheckBox.gridx = 0; + gbc_sourceNameCheckBox.gridy = 5; + sourceNameCheckBox.addActionListener((e) -> sourceNameRemove.setEnabled(sourceNameCheckBox.isSelected())); + otherPanel.add(sourceNameCheckBox, gbc_sourceNameCheckBox); + + sourceDebugRemove = new JCheckBox("Remove"); + GridBagConstraints gbc_sourceDebugRemove = new GridBagConstraints(); + gbc_sourceDebugRemove.fill = GridBagConstraints.HORIZONTAL; + gbc_sourceDebugRemove.insets = new Insets(0, 0, 5, 0); + gbc_sourceDebugRemove.gridx = 15; + gbc_sourceDebugRemove.gridy = 6; + sourceDebugRemove.setEnabled(false); + otherPanel.add(sourceDebugRemove, gbc_sourceDebugRemove); + + sourceDebugCheckBox = new JCheckBox("Source Debug"); + GridBagConstraints gbc_sourceDebugCheckBox = new GridBagConstraints(); + gbc_sourceDebugCheckBox.anchor = GridBagConstraints.WEST; + gbc_sourceDebugCheckBox.insets = new Insets(0, 0, 5, 5); + gbc_sourceDebugCheckBox.gridx = 0; + gbc_sourceDebugCheckBox.gridy = 6; + sourceDebugCheckBox.addActionListener((e) -> sourceDebugRemove.setEnabled(sourceDebugCheckBox.isSelected())); + otherPanel.add(sourceDebugCheckBox, gbc_sourceDebugCheckBox); + + hideCodeCheckBox = new JCheckBox("Hide Code"); + GridBagConstraints gbc_hideCodeCheckBox = new GridBagConstraints(); + gbc_hideCodeCheckBox.anchor = GridBagConstraints.WEST; + gbc_hideCodeCheckBox.insets = new Insets(0, 0, 5, 5); + gbc_hideCodeCheckBox.gridx = 0; + gbc_hideCodeCheckBox.gridy = 7; + otherPanel.add(hideCodeCheckBox, gbc_hideCodeCheckBox); + + shufflerCheckBox = new JCheckBox("Shuffler"); + GridBagConstraints gbc_shufflerCheckBox = new GridBagConstraints(); + gbc_shufflerCheckBox.anchor = GridBagConstraints.WEST; + gbc_shufflerCheckBox.insets = new Insets(0, 0, 5, 5); + gbc_shufflerCheckBox.gridx = 0; + gbc_shufflerCheckBox.gridy = 8; + otherPanel.add(shufflerCheckBox, gbc_shufflerCheckBox); + + crasherCheckBox = new JCheckBox("Crasher"); + GridBagConstraints gbc_crasherCheckBox = new GridBagConstraints(); + gbc_crasherCheckBox.anchor = GridBagConstraints.WEST; + gbc_crasherCheckBox.insets = new Insets(0, 0, 0, 5); + gbc_crasherCheckBox.gridx = 0; + gbc_crasherCheckBox.gridy = 9; + otherPanel.add(crasherCheckBox, gbc_crasherCheckBox); + } + + public StringEncryption getStringEncryption() { + if (stringEncryptionEnabledCheckBox.isSelected()) { + StringEncryptionSetup setup = new StringEncryptionSetup(stringExclusions); + StringEncryption encryptionTransformer; + + switch (stringEncryptionTypeSelector.getSelectedIndex()) { + case 0: { + encryptionTransformer = new LightStringEncryption(setup); + break; + } + case 1: { + encryptionTransformer = new NormalStringEncryption(setup); + break; + } + case 2: { + encryptionTransformer = new HeavyStringEncryption(setup); + break; + } + default: { + throw new IllegalStateException(String.format("Bad string encryption type %d.", stringEncryptionTypeSelector.getSelectedIndex())); + } + } + + return encryptionTransformer; + } else { + return null; + } + } + + public StringPool getStringPool() { + return (stringEncryptionEnabledCheckBox.isSelected() && stringPoolCheckBox.isSelected()) ? new StringPool(new StringEncryptionSetup(stringExclusions)) : null; + } + + public Renamer getRenamer() { + if (renamingEnabledCheckBox.isSelected()) { + String[] resources = (renamingAdaptResources.isSelected() && renamingResourcesField.getText() != null && !renamingResourcesField.getText().isEmpty()) ? renamingResourcesField.getText().split(",") : null; + String repackageName = (renamingRepackageCheckBox.isSelected() && renamingRepackageField.getText() != null && !renamingRepackageField.getText().isEmpty()) ? renamingRepackageField.getText() : null; + + return new Renamer(new RenamerSetup(resources, repackageName)); + } else { + return null; + } + } + + public InvokeDynamic getInvokeDynamic() { + if (invokeDynamicCheckBox.isSelected()) { + switch (invokeDynamicComboBox.getSelectedIndex()) { + case 0: { + return new LightInvokeDynamic(); + } + case 1: { + return new NormalInvokeDynamic(); + } + case 2: { + return new HeavyInvokeDynamic(); + } + default: { + throw new IllegalStateException(String.format("Bad invokedynamic type %d.", invokeDynamicComboBox.getSelectedIndex())); + } + } + } else { + return null; + } + } + + public FlowObfuscation getFlowObfuscation() { + if (flowCheckBox.isSelected()) { + switch (flowComboBox.getSelectedIndex()) { + case 0: { + return new LightFlowObfuscation(); + } + case 1: { + return new NormalFlowObfuscation(); + } + case 2: { + return new HeavyFlowObfuscation(); + } + default: { + throw new IllegalStateException(String.format("Bad flow obfuscation type %d.", flowComboBox.getSelectedIndex())); + } + } + } else { + return null; + } + } + + public NumberObfuscation getNumberObfuscation() { + if (numberObfuscationCheckBox.isSelected()) { + switch (numberObfuscationComboBox.getSelectedIndex()) { + case 0: { + return new LightNumberObfuscation(); + } + case 1: { + return new NormalNumberObfuscation(); + } + case 2: { + return new HeavyNumberObfuscation(); + } + default: { + throw new IllegalStateException(String.format("Bad number obfuscation type %d.", flowComboBox.getSelectedIndex())); + } + } + } else { + return null; + } + } + + public LocalVariables getLocalVarObfuscation() { + return (localVarCheckBox.isSelected()) ? new LocalVariables(localVarsRemove.isSelected()) : null; + } + + public LineNumbers getLineNumberObfuscation() { + return (lineNumbersCheckBox.isSelected()) ? new LineNumbers(lineNumbersRemove.isSelected()) : null; + } + + public SourceName getSourceNameObfuscation() { + return (sourceNameCheckBox.isSelected()) ? new SourceName(sourceNameRemove.isSelected()) : null; + } + + public SourceDebug getSourceDebugObfuscation() { + return (sourceDebugCheckBox.isSelected()) ? new SourceDebug(sourceDebugRemove.isSelected()) : null; + } + + public HideCode getHideCodeObfuscation() { + return (hideCodeCheckBox.isSelected()) ? new HideCode() : null; + } + + public MemberShuffler getShuffler() { + return (shufflerCheckBox.isSelected()) ? new MemberShuffler() : null; + } + + public Crasher getCrasher() { + return (crasherCheckBox.isSelected()) ? new Crasher() : null; + } +} diff --git a/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/OptimizationTab.java b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/OptimizationTab.java new file mode 100644 index 00000000..11b6bc95 --- /dev/null +++ b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/OptimizationTab.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.gui.tabs; + +import java.awt.*; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import me.itzsomebody.radon.transformers.optimizers.OptimizerDelegator; +import me.itzsomebody.radon.transformers.optimizers.OptimizerSetup; + +public class OptimizationTab extends JPanel { + private JCheckBox gotoGotoCheckBox; + private JCheckBox gotoReturnCheckBox; + private JCheckBox nopCheckBox; + private JCheckBox optimizationEnabledCheckBox; + + public OptimizationTab() { + GridBagLayout gbl_this = new GridBagLayout(); + gbl_this.columnWidths = new int[]{0, 0}; + gbl_this.rowHeights = new int[]{0, 0, 0}; + gbl_this.columnWeights = new double[]{1.0, Double.MIN_VALUE}; + gbl_this.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE}; + this.setBorder(new TitledBorder("Optimizer")); + this.setLayout(gbl_this); + + JPanel optimizationSetupPanel = new JPanel(); + GridBagConstraints gbc_optimizationSetupPanel = new GridBagConstraints(); + gbc_optimizationSetupPanel.fill = GridBagConstraints.BOTH; + gbc_optimizationSetupPanel.gridx = 0; + gbc_optimizationSetupPanel.gridy = 1; + this.add(optimizationSetupPanel, gbc_optimizationSetupPanel); + GridBagLayout gbl_optimizationSetupPanel = new GridBagLayout(); + gbl_optimizationSetupPanel.columnWidths = new int[]{0, 0}; + gbl_optimizationSetupPanel.rowHeights = new int[]{0, 0, 0, 0}; + gbl_optimizationSetupPanel.columnWeights = new double[]{0.0, Double.MIN_VALUE}; + gbl_optimizationSetupPanel.rowWeights = new double[]{0.0, 0.0, 0.0, Double.MIN_VALUE}; + optimizationSetupPanel.setBorder(new TitledBorder("Setup")); + optimizationSetupPanel.setLayout(gbl_optimizationSetupPanel); + + gotoGotoCheckBox = new JCheckBox("Remove Goto-Goto Sequences"); + GridBagConstraints gbc_gotoGotoCheckBox = new GridBagConstraints(); + gbc_gotoGotoCheckBox.anchor = GridBagConstraints.WEST; + gbc_gotoGotoCheckBox.insets = new Insets(0, 0, 5, 0); + gbc_gotoGotoCheckBox.gridx = 0; + gbc_gotoGotoCheckBox.gridy = 0; + gotoGotoCheckBox.setEnabled(false); + optimizationSetupPanel.add(gotoGotoCheckBox, gbc_gotoGotoCheckBox); + + gotoReturnCheckBox = new JCheckBox("Remove Goto-Return Sequences"); + GridBagConstraints gbc_gotoReturnCheckBox = new GridBagConstraints(); + gbc_gotoReturnCheckBox.anchor = GridBagConstraints.WEST; + gbc_gotoReturnCheckBox.insets = new Insets(0, 0, 5, 0); + gbc_gotoReturnCheckBox.gridx = 0; + gbc_gotoReturnCheckBox.gridy = 1; + gotoReturnCheckBox.setEnabled(false); + optimizationSetupPanel.add(gotoReturnCheckBox, gbc_gotoReturnCheckBox); + + nopCheckBox = new JCheckBox("Remove Nop Instructions"); + GridBagConstraints gbc_nopCheckBox = new GridBagConstraints(); + gbc_nopCheckBox.anchor = GridBagConstraints.WEST; + gbc_nopCheckBox.gridx = 0; + gbc_nopCheckBox.gridy = 2; + nopCheckBox.setEnabled(false); + optimizationSetupPanel.add(nopCheckBox, gbc_nopCheckBox); + + optimizationEnabledCheckBox = new JCheckBox("Enabled"); + GridBagConstraints gbc_optimizationEnabledCheckBox = new GridBagConstraints(); + gbc_optimizationEnabledCheckBox.insets = new Insets(0, 0, 5, 0); + gbc_optimizationEnabledCheckBox.anchor = GridBagConstraints.WEST; + gbc_optimizationEnabledCheckBox.gridx = 0; + gbc_optimizationEnabledCheckBox.gridy = 0; + optimizationEnabledCheckBox.addActionListener((e) -> { + boolean enable = optimizationEnabledCheckBox.isSelected(); + gotoGotoCheckBox.setEnabled(enable); + gotoReturnCheckBox.setEnabled(enable); + nopCheckBox.setEnabled(enable); + }); + this.add(optimizationEnabledCheckBox, gbc_optimizationEnabledCheckBox); + } + + public OptimizerDelegator getOptimizer() { + return (optimizationEnabledCheckBox.isSelected()) ? new OptimizerDelegator(new OptimizerSetup(nopCheckBox.isSelected(), gotoGotoCheckBox.isSelected(), gotoReturnCheckBox.isSelected())) : null; + } +} diff --git a/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ShrinkingTab.java b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ShrinkingTab.java new file mode 100644 index 00000000..25fd1ec6 --- /dev/null +++ b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/ShrinkingTab.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.gui.tabs; + +import java.awt.*; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import me.itzsomebody.radon.transformers.shrinkers.ShrinkerDelegator; +import me.itzsomebody.radon.transformers.shrinkers.ShrinkerSetup; + +public class ShrinkingTab extends JPanel { + private JCheckBox attributesCheckBox; + private JCheckBox debugInfoCheckBox; + private JCheckBox invisibleAnnotationsCheckBox; + private JCheckBox visibleAnnotationsCheckBox; + private JCheckBox unusedCodeCheckBox; + private JCheckBox unusedMembersCheckBox; + private JCheckBox shrinkerEnabledCheckBox; + + public ShrinkingTab() { + GridBagLayout gbl_this = new GridBagLayout(); + gbl_this.columnWidths = new int[]{0, 0}; + gbl_this.rowHeights = new int[]{0, 0, 0}; + gbl_this.columnWeights = new double[]{1.0, Double.MIN_VALUE}; + gbl_this.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE}; + this.setBorder(new TitledBorder("Shrinker")); + this.setLayout(gbl_this); + + JPanel shrinkerSetupPanel = new JPanel(); + GridBagConstraints gbc_shrinkerSetupPanel = new GridBagConstraints(); + gbc_shrinkerSetupPanel.fill = GridBagConstraints.BOTH; + gbc_shrinkerSetupPanel.gridx = 0; + gbc_shrinkerSetupPanel.gridy = 1; + this.add(shrinkerSetupPanel, gbc_shrinkerSetupPanel); + GridBagLayout gbl_shrinkerSetupPanel = new GridBagLayout(); + gbl_shrinkerSetupPanel.columnWidths = new int[]{0, 0}; + gbl_shrinkerSetupPanel.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0}; + gbl_shrinkerSetupPanel.columnWeights = new double[]{0.0, Double.MIN_VALUE}; + gbl_shrinkerSetupPanel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + shrinkerSetupPanel.setBorder(new TitledBorder("Setup")); + shrinkerSetupPanel.setLayout(gbl_shrinkerSetupPanel); + + attributesCheckBox = new JCheckBox("Remove Attributes"); + GridBagConstraints gbc_attributesCheckBox = new GridBagConstraints(); + gbc_attributesCheckBox.anchor = GridBagConstraints.WEST; + gbc_attributesCheckBox.insets = new Insets(0, 0, 5, 0); + gbc_attributesCheckBox.gridx = 0; + gbc_attributesCheckBox.gridy = 0; + attributesCheckBox.setEnabled(false); + shrinkerSetupPanel.add(attributesCheckBox, gbc_attributesCheckBox); + + debugInfoCheckBox = new JCheckBox("Remove Unneeded Debugging Information"); + GridBagConstraints gbc_debugInfoCheckBox = new GridBagConstraints(); + gbc_debugInfoCheckBox.insets = new Insets(0, 0, 5, 0); + gbc_debugInfoCheckBox.gridx = 0; + gbc_debugInfoCheckBox.gridy = 1; + debugInfoCheckBox.setEnabled(false); + debugInfoCheckBox.setToolTipText("Removes innerclasses, outerclass, outermethod, etc."); + shrinkerSetupPanel.add(debugInfoCheckBox, gbc_debugInfoCheckBox); + + invisibleAnnotationsCheckBox = new JCheckBox("Remove Invisible Annotations"); + GridBagConstraints gbc_invisibleAnnotationsCheckBox = new GridBagConstraints(); + gbc_invisibleAnnotationsCheckBox.anchor = GridBagConstraints.WEST; + gbc_invisibleAnnotationsCheckBox.insets = new Insets(0, 0, 5, 0); + gbc_invisibleAnnotationsCheckBox.gridx = 0; + gbc_invisibleAnnotationsCheckBox.gridy = 2; + invisibleAnnotationsCheckBox.setEnabled(false); + shrinkerSetupPanel.add(invisibleAnnotationsCheckBox, gbc_invisibleAnnotationsCheckBox); + + visibleAnnotationsCheckBox = new JCheckBox("Remove Visible Annotations"); + GridBagConstraints gbc_visibleAnnotationsCheckBox = new GridBagConstraints(); + gbc_visibleAnnotationsCheckBox.anchor = GridBagConstraints.WEST; + gbc_visibleAnnotationsCheckBox.insets = new Insets(0, 0, 5, 0); + gbc_visibleAnnotationsCheckBox.gridx = 0; + gbc_visibleAnnotationsCheckBox.gridy = 3; + visibleAnnotationsCheckBox.setEnabled(false); + shrinkerSetupPanel.add(visibleAnnotationsCheckBox, gbc_visibleAnnotationsCheckBox); + + unusedCodeCheckBox = new JCheckBox("Remove Unused Code"); + GridBagConstraints gbc_unusedCodeCheckBox = new GridBagConstraints(); + gbc_unusedCodeCheckBox.anchor = GridBagConstraints.WEST; + gbc_unusedCodeCheckBox.insets = new Insets(0, 0, 5, 0); + gbc_unusedCodeCheckBox.gridx = 0; + gbc_unusedCodeCheckBox.gridy = 4; + unusedCodeCheckBox.setEnabled(false); + shrinkerSetupPanel.add(unusedCodeCheckBox, gbc_unusedCodeCheckBox); + + unusedMembersCheckBox = new JCheckBox("Remove Unused Members"); + GridBagConstraints gbc_unusedMembersCheckBox = new GridBagConstraints(); + gbc_unusedMembersCheckBox.insets = new Insets(0, 0, 5, 0); + gbc_unusedMembersCheckBox.anchor = GridBagConstraints.WEST; + gbc_unusedMembersCheckBox.gridx = 0; + gbc_unusedMembersCheckBox.gridy = 5; + unusedMembersCheckBox.setEnabled(false); + shrinkerSetupPanel.add(unusedMembersCheckBox, gbc_unusedMembersCheckBox); + + shrinkerEnabledCheckBox = new JCheckBox("Enabled"); + GridBagConstraints gbc_shrinkerEnabledCheckBox = new GridBagConstraints(); + gbc_shrinkerEnabledCheckBox.insets = new Insets(0, 0, 5, 0); + gbc_shrinkerEnabledCheckBox.anchor = GridBagConstraints.WEST; + gbc_shrinkerEnabledCheckBox.gridx = 0; + gbc_shrinkerEnabledCheckBox.gridy = 0; + shrinkerEnabledCheckBox.addActionListener((e) -> { + boolean enable = shrinkerEnabledCheckBox.isSelected(); + attributesCheckBox.setEnabled(enable); + debugInfoCheckBox.setEnabled(enable); + invisibleAnnotationsCheckBox.setEnabled(enable); + visibleAnnotationsCheckBox.setEnabled(enable); + unusedCodeCheckBox.setEnabled(enable); + unusedMembersCheckBox.setEnabled(enable); + }); + this.add(shrinkerEnabledCheckBox, gbc_shrinkerEnabledCheckBox); + } + + public ShrinkerDelegator getShrinker() { + return (shrinkerEnabledCheckBox.isSelected()) ? new ShrinkerDelegator(new ShrinkerSetup(visibleAnnotationsCheckBox.isSelected(), invisibleAnnotationsCheckBox.isSelected(), attributesCheckBox.isSelected(), + debugInfoCheckBox.isSelected(), unusedCodeCheckBox.isSelected(), unusedMembersCheckBox.isSelected())) : null; + } +} diff --git a/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/WatermarkingTab.java b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/WatermarkingTab.java new file mode 100644 index 00000000..311c88bf --- /dev/null +++ b/Radon-GUI/src/main/java/me/itzsomebody/radon/gui/tabs/WatermarkingTab.java @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.gui.tabs; + +import java.awt.*; +import java.io.File; +import java.util.List; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import javax.swing.*; +import javax.swing.border.TitledBorder; +import me.itzsomebody.radon.exceptions.WatermarkExtractionException; +import me.itzsomebody.radon.transformers.miscellaneous.watermarker.Watermarker; +import me.itzsomebody.radon.transformers.miscellaneous.watermarker.WatermarkerSetup; +import me.itzsomebody.radon.utils.WatermarkUtils; + +public class WatermarkingTab extends JPanel { + private JTextField watermarkMessageField; + private JTextField watermarkKeyField; + private JCheckBox watermarkerEnabledCheckBox; + + public WatermarkingTab() { + GridBagLayout gbl_this = new GridBagLayout(); + gbl_this.columnWidths = new int[]{0, 0}; + gbl_this.rowHeights = new int[]{0, 0, 0, 0}; + gbl_this.columnWeights = new double[]{1.0, Double.MIN_VALUE}; + gbl_this.rowWeights = new double[]{0.0, 0.0, 1.0, Double.MIN_VALUE}; + this.setBorder(new TitledBorder("Watermarker")); + this.setLayout(gbl_this); + + JPanel watermarkerSetupPanel = new JPanel(); + GridBagConstraints gbc_watermarkerSetupPanel = new GridBagConstraints(); + gbc_watermarkerSetupPanel.insets = new Insets(0, 0, 5, 0); + gbc_watermarkerSetupPanel.fill = GridBagConstraints.BOTH; + gbc_watermarkerSetupPanel.gridx = 0; + gbc_watermarkerSetupPanel.gridy = 1; + this.add(watermarkerSetupPanel, gbc_watermarkerSetupPanel); + watermarkerSetupPanel.setBorder(new TitledBorder("Setup")); + GridBagLayout gbl_watermarkerSetupPanel = new GridBagLayout(); + gbl_watermarkerSetupPanel.columnWidths = new int[]{0, 0, 0}; + gbl_watermarkerSetupPanel.rowHeights = new int[]{0, 0, 0}; + gbl_watermarkerSetupPanel.columnWeights = new double[]{0.0, 1.0, Double.MIN_VALUE}; + gbl_watermarkerSetupPanel.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE}; + watermarkerSetupPanel.setLayout(gbl_watermarkerSetupPanel); + + JLabel watermarkMessageLabel = new JLabel("Message:"); + GridBagConstraints gbc_watermarkMessageLabel = new GridBagConstraints(); + gbc_watermarkMessageLabel.anchor = GridBagConstraints.EAST; + gbc_watermarkMessageLabel.insets = new Insets(0, 5, 5, 5); + gbc_watermarkMessageLabel.gridx = 0; + gbc_watermarkMessageLabel.gridy = 0; + watermarkerSetupPanel.add(watermarkMessageLabel, gbc_watermarkMessageLabel); + + watermarkMessageField = new JTextField(); + GridBagConstraints gbc_watermarkMessageField = new GridBagConstraints(); + gbc_watermarkMessageField.insets = new Insets(0, 0, 5, 5); + gbc_watermarkMessageField.fill = GridBagConstraints.HORIZONTAL; + gbc_watermarkMessageField.gridx = 1; + gbc_watermarkMessageField.gridy = 0; + watermarkMessageField.setEditable(false); + watermarkerSetupPanel.add(watermarkMessageField, gbc_watermarkMessageField); + watermarkMessageField.setColumns(10); + + JLabel watermarkKeyLabel = new JLabel("Key:"); + GridBagConstraints gbc_watermarkKeyLabel = new GridBagConstraints(); + gbc_watermarkKeyLabel.anchor = GridBagConstraints.EAST; + gbc_watermarkKeyLabel.insets = new Insets(0, 0, 5, 5); + gbc_watermarkKeyLabel.gridx = 0; + gbc_watermarkKeyLabel.gridy = 1; + watermarkerSetupPanel.add(watermarkKeyLabel, gbc_watermarkKeyLabel); + + watermarkKeyField = new JTextField(); + GridBagConstraints gbc_watermarkKeyField = new GridBagConstraints(); + gbc_watermarkKeyField.insets = new Insets(0, 0, 5, 5); + gbc_watermarkKeyField.fill = GridBagConstraints.HORIZONTAL; + gbc_watermarkKeyField.gridx = 1; + gbc_watermarkKeyField.gridy = 1; + watermarkKeyField.setEditable(false); + watermarkerSetupPanel.add(watermarkKeyField, gbc_watermarkKeyField); + watermarkKeyField.setColumns(10); + + JPanel watermarkerExtractor = new JPanel(); + GridBagConstraints gbc_watermarkerExtractor = new GridBagConstraints(); + gbc_watermarkerExtractor.fill = GridBagConstraints.BOTH; + gbc_watermarkerExtractor.gridx = 0; + gbc_watermarkerExtractor.gridy = 2; + watermarkerExtractor.setBorder(new TitledBorder("Extractor")); + this.add(watermarkerExtractor, gbc_watermarkerExtractor); + GridBagLayout gbl_watermarkerExtractor = new GridBagLayout(); + gbl_watermarkerExtractor.columnWidths = new int[]{0, 0, 0, 0}; + gbl_watermarkerExtractor.rowHeights = new int[]{0, 0, 0, 0}; + gbl_watermarkerExtractor.columnWeights = new double[]{0.0, 1.0, 0.0, Double.MIN_VALUE}; + gbl_watermarkerExtractor.rowWeights = new double[]{0.0, 0.0, 1.0, Double.MIN_VALUE}; + watermarkerExtractor.setLayout(gbl_watermarkerExtractor); + + JLabel watermarkExtractorInput = new JLabel("Input:"); + GridBagConstraints gbc_watermarkExtractorInput = new GridBagConstraints(); + gbc_watermarkExtractorInput.anchor = GridBagConstraints.EAST; + gbc_watermarkExtractorInput.insets = new Insets(0, 5, 5, 5); + gbc_watermarkExtractorInput.gridx = 0; + gbc_watermarkExtractorInput.gridy = 0; + watermarkerExtractor.add(watermarkExtractorInput, gbc_watermarkExtractorInput); + + JTextField watermarkExtractorInputField = new JTextField(); + GridBagConstraints gbc_watermarkExtractorInputField = new GridBagConstraints(); + gbc_watermarkExtractorInputField.insets = new Insets(0, 0, 5, 5); + gbc_watermarkExtractorInputField.fill = GridBagConstraints.HORIZONTAL; + gbc_watermarkExtractorInputField.gridx = 1; + gbc_watermarkExtractorInputField.gridy = 0; + watermarkerExtractor.add(watermarkExtractorInputField, gbc_watermarkExtractorInputField); + watermarkExtractorInputField.setColumns(10); + + JButton watermarkExtractorInputButton = new JButton("Select"); + GridBagConstraints gbc_watermarkExtractorInputButton = new GridBagConstraints(); + gbc_watermarkExtractorInputButton.fill = GridBagConstraints.HORIZONTAL; + gbc_watermarkExtractorInputButton.insets = new Insets(0, 0, 5, 5); + gbc_watermarkExtractorInputButton.gridx = 2; + gbc_watermarkExtractorInputButton.gridy = 0; + watermarkExtractorInputButton.addActionListener((e) -> { + JFileChooser chooser = new JFileChooser(); + chooser.setMultiSelectionEnabled(false); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + int result = chooser.showOpenDialog(this); + if (result == 0) { + SwingUtilities.invokeLater(() -> watermarkExtractorInputField.setText(chooser.getSelectedFile().getAbsolutePath())); + } + }); + watermarkerExtractor.add(watermarkExtractorInputButton, gbc_watermarkExtractorInputButton); + + JLabel watermarkExtractorKeyLabel = new JLabel("Key:"); + GridBagConstraints gbc_watermarkExtractorKeyLabel = new GridBagConstraints(); + gbc_watermarkExtractorKeyLabel.anchor = GridBagConstraints.EAST; + gbc_watermarkExtractorKeyLabel.insets = new Insets(0, 0, 5, 5); + gbc_watermarkExtractorKeyLabel.gridx = 0; + gbc_watermarkExtractorKeyLabel.gridy = 1; + watermarkerExtractor.add(watermarkExtractorKeyLabel, gbc_watermarkExtractorKeyLabel); + + JTextField watermarkExtractorKeyField = new JTextField(); + GridBagConstraints gbc_watermarkExtractorKeyField = new GridBagConstraints(); + gbc_watermarkExtractorKeyField.insets = new Insets(0, 0, 5, 5); + gbc_watermarkExtractorKeyField.fill = GridBagConstraints.HORIZONTAL; + gbc_watermarkExtractorKeyField.gridx = 1; + gbc_watermarkExtractorKeyField.gridy = 1; + watermarkerExtractor.add(watermarkExtractorKeyField, gbc_watermarkExtractorKeyField); + watermarkExtractorKeyField.setColumns(10); + + JScrollPane watermarkExtractorScrollPane = new JScrollPane(); + GridBagConstraints gbc_watermarkExtractorScrollPane = new GridBagConstraints(); + gbc_watermarkExtractorScrollPane.gridwidth = 3; + gbc_watermarkExtractorScrollPane.insets = new Insets(0, 5, 5, 5); + gbc_watermarkExtractorScrollPane.fill = GridBagConstraints.BOTH; + gbc_watermarkExtractorScrollPane.gridx = 0; + gbc_watermarkExtractorScrollPane.gridy = 2; + watermarkerExtractor.add(watermarkExtractorScrollPane, gbc_watermarkExtractorScrollPane); + + DefaultListModel extractionList = new DefaultListModel<>(); + JList watermarkExtractorList = new JList<>(extractionList); + watermarkExtractorScrollPane.setViewportView(watermarkExtractorList); + + JButton watermarkExtractorButton = new JButton("Extract"); + GridBagConstraints gbc_watermarkExtractorButton = new GridBagConstraints(); + gbc_watermarkExtractorButton.fill = GridBagConstraints.HORIZONTAL; + gbc_watermarkExtractorButton.insets = new Insets(0, 0, 5, 5); + gbc_watermarkExtractorButton.gridx = 2; + gbc_watermarkExtractorButton.gridy = 1; + watermarkExtractorButton.addActionListener((e) -> { + extractionList.clear(); + File file = new File(watermarkExtractorInputField.getText()); + if (!file.exists()) { + throw new WatermarkExtractionException(String.format("Could not find input file %s.", watermarkExtractorInputField.getText())); + } + + try { + ZipFile zipFile = new ZipFile(file); + List ids = WatermarkUtils.extractIds(zipFile, watermarkExtractorKeyField.getText()); + + for (String id : ids) { + extractionList.addElement(id); + } + } catch (ZipException ze) { + ze.printStackTrace(); + throw new WatermarkExtractionException("Could not load input file as a zip."); + } catch (Throwable t) { + t.printStackTrace(); + throw new WatermarkExtractionException(); + } + }); + watermarkerExtractor.add(watermarkExtractorButton, gbc_watermarkExtractorButton); + + watermarkerEnabledCheckBox = new JCheckBox("Enabled"); + GridBagConstraints gbc_watermarkerEnabledCheckBox = new GridBagConstraints(); + gbc_watermarkerEnabledCheckBox.insets = new Insets(0, 0, 5, 0); + gbc_watermarkerEnabledCheckBox.anchor = GridBagConstraints.WEST; + gbc_watermarkerEnabledCheckBox.gridx = 0; + gbc_watermarkerEnabledCheckBox.gridy = 0; + watermarkerEnabledCheckBox.addActionListener((e) -> { + boolean enable = watermarkerEnabledCheckBox.isSelected(); + + watermarkMessageField.setEditable(enable); + watermarkKeyField.setEditable(enable); + }); + this.add(watermarkerEnabledCheckBox, gbc_watermarkerEnabledCheckBox); + } + + public Watermarker getWatermarker() { + return (watermarkerEnabledCheckBox.isSelected()) ? new Watermarker(new WatermarkerSetup(watermarkMessageField.getText(), watermarkKeyField.getText())) : null; + } +} diff --git a/src/main/resources/META-INF/license.txt b/Radon-GUI/src/main/resources/META-INF/license.txt similarity index 100% rename from src/main/resources/META-INF/license.txt rename to Radon-GUI/src/main/resources/META-INF/license.txt diff --git a/Radon-Program/pom.xml b/Radon-Program/pom.xml new file mode 100644 index 00000000..db757ac1 --- /dev/null +++ b/Radon-Program/pom.xml @@ -0,0 +1,87 @@ + + + + Radon + me.itzsomebody + 1.0.0 + + 4.0.0 + Radon-Program + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + me.itzsomebody.radon.Main + + + + + + maven-compiler-plugin + 3.7.0 + + 1.8 + 1.8 + + -XDignore.symbol.file + + true + + + + org.apache.maven.plugins + maven-shade-plugin + 3.1.0 + + + package + + shade + + + + + *:* + + + + + + + + + + + org.ow2.asm + asm + 6.1 + + + org.ow2.asm + asm-tree + 6.1 + + + org.ow2.asm + asm-commons + 6.1 + + + org.ow2.asm + asm-analysis + 6.1 + + + org.ow2.asm + asm-util + 6.1 + + + \ No newline at end of file diff --git a/src/main/java/me/itzsomebody/radon/internal/CLI.java b/Radon-Program/src/main/java/me/itzsomebody/radon/CLI.java similarity index 68% rename from src/main/java/me/itzsomebody/radon/internal/CLI.java rename to Radon-Program/src/main/java/me/itzsomebody/radon/CLI.java index 69e56a9a..a7f75c6d 100644 --- a/src/main/java/me/itzsomebody/radon/internal/CLI.java +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/CLI.java @@ -15,14 +15,14 @@ * along with this program. If not, see */ -package me.itzsomebody.radon.internal; +package me.itzsomebody.radon; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.List; -import me.itzsomebody.radon.Radon; -import me.itzsomebody.radon.config.Config; +import java.util.zip.ZipFile; +import me.itzsomebody.radon.config.ConfigurationParser; import me.itzsomebody.radon.utils.LoggerUtils; import me.itzsomebody.radon.utils.WatermarkUtils; @@ -31,9 +31,9 @@ * * @author ItzSomebody */ -public class CLI { +class CLI { /** - * Args passed down from {@link Radon#main(String[])}. + * Args passed down from {@link Main#main(String[])}. */ private String[] args; @@ -42,7 +42,7 @@ public class CLI { * * @param args array of {@link String}s from command line arguments. */ - public CLI(String[] args) { + CLI(String[] args) { this.args = args; this.startTheParty(); } @@ -53,11 +53,6 @@ public CLI(String[] args) { private void startTheParty() { if (this.args.length == 1) { switch (this.args[0].toLowerCase()) { - case "--version": - case "-version": - case "version": - case "/version": - break; case "--help": case "-help": case "help": @@ -74,19 +69,16 @@ private void startTheParty() { case "config": case "/config": File file = new File(this.args[1]); - Config config; + ConfigurationParser config; try { - config = new Config(new FileInputStream(file)); + config = new ConfigurationParser(new FileInputStream(file)); } catch (FileNotFoundException exc) { - LoggerUtils.stdOut("Config file not found"); + LoggerUtils.stdOut("Configuration file not found"); return; } - Bootstrap bootstrap = new Bootstrap(config); - try { - bootstrap.startTheParty(true); - } catch (Throwable t) { - t.printStackTrace(); - } + + Radon radon = new Radon(config.createSessionFromConfig()); + radon.partyTime(); break; default: usageMsg(); @@ -104,8 +96,7 @@ private void startTheParty() { } try { - List ids = WatermarkUtils - .extractWatermark(leaked, this.args[2]); + List ids = WatermarkUtils.extractIds(new ZipFile(leaked), this.args[2]); for (String id : ids) { LoggerUtils.stdOut(id); } @@ -127,22 +118,18 @@ private void startTheParty() { * Prints usage message into console. */ private static void usageMsg() { - LoggerUtils.stdOut("Usage: java -jar Radon.jar --config example" + - ".config"); - LoggerUtils.stdOut("USage: java -jar Radon.jar --help"); - LoggerUtils.stdOut("Usage: java -jar Radon.jar"); + LoggerUtils.stdOut("Usage: java -jar Radon-Program.jar --config example.config"); + LoggerUtils.stdOut("USage: java -jar Radon-Program.jar --help"); + LoggerUtils.stdOut("Usage: java -jar Radon-Program.jar"); } /** * Prints help message into console. */ private static void helpMsg() { - LoggerUtils.stdOut("CLI Usage:\t\tjava -jar Radon.jar --config " + - "example.config"); - LoggerUtils.stdOut("Credits:\t\tjava -jar Radon.jar --version"); - LoggerUtils.stdOut("Help Menu:\t\tjava -jar Radon.jar --help"); - LoggerUtils.stdOut("Watermark Extraction:\tjava -jar Radon.jar " + - "--extract Input.jar exampleKey"); - LoggerUtils.stdOut("MainGUI Usage:\t\tjava -jar Radon.jar"); + LoggerUtils.stdOut("CLI Usage:\t\tjava -jar Radon-Program.jar --config example.config"); + LoggerUtils.stdOut("Help Menu:\t\tjava -jar Radon-Program.jar --help"); + LoggerUtils.stdOut("Watermark Extraction:\tjava -jar Radon-Program.jar --extract Input.jar exampleKey"); + LoggerUtils.stdOut("Radon GUI Usage:\t\tjava -jar Radon-GUI.jar"); } } diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/Dictionaries.java b/Radon-Program/src/main/java/me/itzsomebody/radon/Dictionaries.java new file mode 100644 index 00000000..83c492a8 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/Dictionaries.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon; + +import me.itzsomebody.radon.exceptions.IllegalDictionaryException; + +public enum Dictionaries { + SPACES("Spaces"), + UNRECOGNIZED("Unrecognized"), + ALPHABETICAL("Alphabetical"), + ALPHANUMERIC("Alphanumeric"); + + private String value; + + Dictionaries(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static Dictionaries intToDictionary(int type) { + switch (type) { + case 0: { + return SPACES; + } + case 1: { + return UNRECOGNIZED; + } + case 2: { + return ALPHABETICAL; + } + case 3: { + return ALPHANUMERIC; + } + default: { + throw new IllegalDictionaryException(); + } + } + } + + public static Dictionaries stringToDictionary(String s) { + switch (s.toLowerCase()) { + case "spaces": { + return SPACES; + } + case "unrecognized": { + return UNRECOGNIZED; + } + case "alphabetical": { + return ALPHABETICAL; + } + case "alphanumeric": { + return ALPHANUMERIC; + } + default: { + throw new IllegalDictionaryException(); + } + } + } +} diff --git a/src/main/java/me/itzsomebody/radon/Radon.java b/Radon-Program/src/main/java/me/itzsomebody/radon/Main.java similarity index 67% rename from src/main/java/me/itzsomebody/radon/Radon.java rename to Radon-Program/src/main/java/me/itzsomebody/radon/Main.java index ca6d02f5..b67f8b64 100644 --- a/src/main/java/me/itzsomebody/radon/Radon.java +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/Main.java @@ -5,34 +5,37 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ package me.itzsomebody.radon; -import me.itzsomebody.radon.gui.MainGUI; -import me.itzsomebody.radon.internal.CLI; import me.itzsomebody.radon.utils.LoggerUtils; -/** - * The main class :D - * - * @author ItzSomebody +/* + * TODO: Allow toggling of dictionaries for all transformers. + * TODO: Renamer transformer should correct strings used for reflection. (i.e. Class.forName("me.itzsomebody.Thing")) + * TODO: Finish string encryption transformers. + * TODO: Make the logger system non-static. (ew, static abuse) + * TODO: Add JavaDocs. + * TODO: Fix UnusedCodeRemover. + * TODO: Make the UnusedMembersRemover transformer. */ -public class Radon { +public class Main { /** * Static abuse variables xD */ - public static String PREFIX = "[Radon]"; - public static String VERSION = "0.9.0"; - public static String AUTHORS = "ItzSomebody"; + public static final String PREFIX = "[Radon]"; + public static final String VERSION = "1.0.0"; + public static final String CONTRIBUTORS = "ItzSomebody, x0ark, Col-E and ArtelGG"; + public static final String PROPAGANDA_GARBAGE = String.format("Radon is a free and open-source java obfuscator with contributions from %s.\nVersion: %s\nWebsite: https://github.com/ItzSomebody/Radon", Main.CONTRIBUTORS, Main.VERSION); /** * Main method. @@ -41,14 +44,7 @@ public class Radon { */ public static void main(String[] args) { coolThingInConsole(); - - switch (args.length) { - case 0: - new MainGUI(); - break; - default: - new CLI(args); - } + new CLI(args); } /** @@ -68,7 +64,7 @@ private static void coolThingInConsole() { System.out.println("##############################################"); System.out.println(""); System.out.println(""); - LoggerUtils.stdOut("Version: " + Radon.VERSION); - LoggerUtils.stdOut("Authors: " + Radon.AUTHORS); + LoggerUtils.stdOut("Version: " + VERSION); + LoggerUtils.stdOut("Contributors: " + CONTRIBUTORS); } } diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/Radon.java b/Radon-Program/src/main/java/me/itzsomebody/radon/Radon.java new file mode 100644 index 00000000..c20eb2f2 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/Radon.java @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; +import jdk.internal.org.objectweb.asm.Opcodes; +import me.itzsomebody.radon.asm.ClassTree; +import me.itzsomebody.radon.asm.ClassWrapper; +import me.itzsomebody.radon.exceptions.BadInputException; +import me.itzsomebody.radon.exceptions.InputNotFoundException; +import me.itzsomebody.radon.exceptions.MissingClassException; +import me.itzsomebody.radon.exceptions.NoTransformersException; +import me.itzsomebody.radon.exceptions.OutputWriteException; +import me.itzsomebody.radon.utils.IOUtils; +import me.itzsomebody.radon.utils.LoggerUtils; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.commons.JSRInlinerAdapter; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +public class Radon { + public SessionInfo sessionInfo; + private Map hierarchy = new HashMap<>(); + public Map classes = new HashMap<>(); + public Map classPath = new HashMap<>(); + public Map resources = new HashMap<>(); + + public Radon(SessionInfo sessionInfo) { + this.sessionInfo = sessionInfo; + } + + public void partyTime() { + loadClassPath(); + loadInput(); + buildInheritance(); + executeTransformers(); + writeOutput(); + LoggerUtils.logWriter(); + } + + private void writeOutput() { + File output = this.sessionInfo.getOutput(); + LoggerUtils.stdOut(String.format("Writing output to \"%s\".", output.getAbsolutePath())); + if (output.exists()) { + LoggerUtils.stdOut(String.format("Output file already exists, renamed to %s.", IOUtils.renameExistingFile(output))); + } + + try { + ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(output)); + + this.classes.values().forEach(classWrapper -> { + try { + ZipEntry entry = new ZipEntry(classWrapper.classNode.name + ".class"); + entry.setCompressedSize(-1); + + ClassWriter cw = new CustomClassWriter(ClassWriter.COMPUTE_FRAMES); + cw.newUTF8("RADON" + Main.VERSION); + try { + classWrapper.classNode.accept(cw); + } catch (Throwable t) { + LoggerUtils.stdErr(String.format("Error writing class %s.", classWrapper.classNode.name + ".class")); + t.printStackTrace(); + cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + classWrapper.classNode.accept(cw); + } + + zos.putNextEntry(entry); + zos.write(cw.toByteArray()); + zos.closeEntry(); + } catch (Throwable t) { + LoggerUtils.stdErr(String.format("Error writing class %s. Skipping.", classWrapper.classNode.name + ".class")); + t.printStackTrace(); + } + }); + + this.resources.forEach((name, bytes) -> { + try { + ZipEntry entry = new ZipEntry(name); + entry.setCompressedSize(-1); + + zos.putNextEntry(entry); + zos.write(bytes); + zos.closeEntry(); + } catch (Throwable t) { + LoggerUtils.stdErr(String.format("Error writing resource %s. Skipping.", name)); + t.printStackTrace(); + } + }); + + zos.setComment(Main.PROPAGANDA_GARBAGE); + zos.close(); + } catch (Throwable t) { + t.printStackTrace(); + throw new OutputWriteException(); + } + } + + private void loadClassPath() { + for (File file : this.sessionInfo.getLibraries()) { + if (file.exists()) { + LoggerUtils.stdOut(String.format("Loading library \"%s\".", file.getAbsolutePath())); + try { + ZipFile zipFile = new ZipFile(file); + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + if (!entry.isDirectory() && entry.getName().endsWith(".class")) { + try { + ClassReader cr = new ClassReader(zipFile.getInputStream(entry)); + ClassNode classNode = new ClassNode(); + cr.accept(classNode, ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); + ClassWrapper classWrapper = new ClassWrapper(classNode, true); + + this.classPath.put(classWrapper.originalName, classWrapper); + } catch (Throwable t) { + // Don't care. + } + } + } + } catch (ZipException e) { + LoggerUtils.stdErr(String.format("Library \"%s\" could not be opened as a zip file.", file.getAbsolutePath())); + e.printStackTrace(); + } catch (IOException e) { + LoggerUtils.stdErr(String.format("IOException happened while trying to load classes from \"%s\".", file.getAbsolutePath())); + e.printStackTrace(); + } + } else { + LoggerUtils.stdWarn(String.format("Library \"%s\" could not be found and will be ignored.", file.getAbsolutePath())); + } + } + } + + private void loadInput() { + File input = this.sessionInfo.getInput(); + if (input.exists()) { + LoggerUtils.stdOut(String.format("Loading input \"%s\".", input.getAbsolutePath())); + try { + ZipFile zipFile = new ZipFile(input); + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + if (!entry.isDirectory()) { + if (entry.getName().endsWith(".class")) { + try { + ClassReader cr = new ClassReader(zipFile.getInputStream(entry)); + ClassNode classNode = new ClassNode(); + cr.accept(classNode, ClassReader.SKIP_FRAMES); + if (classNode.version <= Opcodes.V1_5) { + for (int i = 0; i < classNode.methods.size(); i++) { + MethodNode methodNode = classNode.methods.get(i); + JSRInlinerAdapter adapter = new JSRInlinerAdapter(methodNode, methodNode.access, methodNode.name, methodNode.desc, methodNode.signature, methodNode.exceptions.toArray(new String[0])); + methodNode.accept(adapter); + classNode.methods.set(i, adapter); + } + } + ClassWrapper classWrapper = new ClassWrapper(classNode, false); + + this.classPath.put(classWrapper.originalName, classWrapper); + this.classes.put(classWrapper.originalName, classWrapper); + } catch (Throwable t) { + LoggerUtils.stdWarn(String.format("Could not load %s as a class.", entry.getName())); + this.resources.put(entry.getName(), IOUtils.toByteArray(zipFile.getInputStream(entry))); + } + } else { + this.resources.put(entry.getName(), IOUtils.toByteArray(zipFile.getInputStream(entry))); + } + } + } + } catch (ZipException e) { + LoggerUtils.stdErr(String.format("Input file \"%s\" could not be opened as a zip file.", input.getAbsolutePath())); + e.printStackTrace(); + throw new BadInputException(); + } catch (IOException e) { + LoggerUtils.stdErr(String.format("IOException happened while trying to load classes from \"%s\".", input.getAbsolutePath())); + e.printStackTrace(); + throw new BadInputException(); + } + } else { + LoggerUtils.stdErr(String.format("Unable to find \"%s\".", input.getAbsolutePath())); + throw new InputNotFoundException(); + } + } + + public ClassTree getTree(String ref) { + if (!hierarchy.containsKey(ref)) { + ClassWrapper wrapper = classPath.get(ref); + buildHierarchy(wrapper, null); + } + + return hierarchy.get(ref); + } + + private void buildHierarchy(ClassWrapper classWrapper, ClassWrapper sub) { + if (hierarchy.get(classWrapper.classNode.name) == null) { + ClassTree tree = new ClassTree(classWrapper); + if (classWrapper.classNode.superName != null) { + tree.parentClasses.add(classWrapper.classNode.superName); + buildHierarchy(classPath.get(classWrapper.classNode.superName), classWrapper); + } + if (classWrapper.classNode.interfaces != null && !classWrapper.classNode.interfaces.isEmpty()) { + for (String s : classWrapper.classNode.interfaces) { + tree.parentClasses.add(s); + buildHierarchy(classPath.get(s), classWrapper); + } + } + hierarchy.put(classWrapper.classNode.name, tree); + } + if (sub != null) { + hierarchy.get(classWrapper.classNode.name).subClasses.add(sub.classNode.name); + } + } + + private void buildInheritance() { + classes.values().forEach(classWrapper -> buildHierarchy(classWrapper, null)); + } + + private void executeTransformers() { + if (this.sessionInfo.getTransformers().isEmpty()) { + throw new NoTransformersException(); + } + LoggerUtils.stdOut("------------------------------------------------"); + this.sessionInfo.getTransformers().stream().filter(Objects::nonNull).forEach(transformer -> { + long current = System.currentTimeMillis(); + LoggerUtils.stdOut(String.format("Running %s transformer.", transformer.getName())); + transformer.init(this); + transformer.transform(); + LoggerUtils.stdOut(String.format("Finished running %s transformer. [%dms]", transformer.getName(), (System.currentTimeMillis() - current))); + LoggerUtils.stdOut("------------------------------------------------"); + }); + } + + class CustomClassWriter extends ClassWriter { + private CustomClassWriter(int flags) { + super(flags); + } + + @Override + protected String getCommonSuperClass(final String type1, final String type2) { + if (type1.equals("java/lang/Object") || type2.equals("java/lang/Object")) { + return "java/lang/Object"; + } + + String first = deriveCommonSuperName(type1, type2); + String second = deriveCommonSuperName(type2, type1); + if (!first.equals("java/lang/Object")) { + return first; + } + if (!second.equals("java/lang/Object")) { + return second; + } + + return getCommonSuperClass(returnClazz(type1).superName, returnClazz(type2).superName); + } + + private String deriveCommonSuperName(String type1, String type2) { + ClassNode first = returnClazz(type1); + ClassNode second = returnClazz(type2); + if (isAssignableFrom(type1, type2)) { + return type1; + } else if (isAssignableFrom(type2, type1)) { + return type2; + } else if (Modifier.isInterface(first.access) || Modifier.isInterface(second.access)) { + return "java/lang/Object"; + } else { + do { + type1 = first.superName; + first = returnClazz(type1); + } while (!isAssignableFrom(type1, type2)); + return type1; + } + } + + private ClassNode returnClazz(String ref) { + ClassWrapper clazz = classPath.get(ref); + if (clazz == null) { + throw new MissingClassException(ref + " does not exist in classpath!"); + } + return clazz.classNode; + } + + private boolean isAssignableFrom(String type1, String type2) { + if (type1.equals("java/lang/Object")) + return true; + if (type1.equals(type2)) { + return true; + } + returnClazz(type1); + returnClazz(type2); + ClassTree firstTree = getTree(type1); + if (firstTree == null) { + throw new RuntimeException("Could not find " + type1 + " in the built class hierarchy"); + } + Set allChildren = new HashSet<>(); + LinkedList toProcess = new LinkedList<>(); + toProcess.addAll(firstTree.subClasses); + while (!toProcess.isEmpty()) { + String s = toProcess.poll(); + if (allChildren.add(s)) { + returnClazz(s); + ClassTree tempTree = getTree(s); + toProcess.addAll(tempTree.subClasses); + } + } + return allChildren.contains(type2); + } + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/SessionInfo.java b/Radon-Program/src/main/java/me/itzsomebody/radon/SessionInfo.java new file mode 100644 index 00000000..a9f99fcf --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/SessionInfo.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon; + +import java.io.File; +import java.util.List; +import me.itzsomebody.radon.exclusions.ExclusionManager; +import me.itzsomebody.radon.transformers.Transformer; + +public class SessionInfo { + private File input; + private File output; + private List libraries; + private List transformers; + private ExclusionManager exclusions; + private int trashClasses; + private Dictionaries dictionaryType; + + public void setInput(File input) { + this.input = input; + } + + public File getInput() { + return this.input; + } + + public void setOutput(File output) { + this.output = output; + } + + public File getOutput() { + return this.output; + } + + public void setLibraries(List libraries) { + this.libraries = libraries; + } + + public List getLibraries() { + return libraries; + } + + public void setTransformers(List transformers) { + this.transformers = transformers; + } + + public List getTransformers() { + return this.transformers; + } + + public void setExclusions(ExclusionManager exclusions) { + this.exclusions = exclusions; + } + + public ExclusionManager getExclusions() { + return this.exclusions; + } + + public void setTrashClasses(int trashClasses) { + this.trashClasses = trashClasses; + } + + public int getTrashClasses() { + return this.trashClasses; + } + + public void setDictionaryType(Dictionaries dictionaryType) { + this.dictionaryType = dictionaryType; + } + + public Dictionaries getDictionaryType() { + return this.dictionaryType; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/asm/ClassTree.java b/Radon-Program/src/main/java/me/itzsomebody/radon/asm/ClassTree.java new file mode 100644 index 00000000..562fa006 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/asm/ClassTree.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.asm; + +import java.util.HashSet; +import java.util.Set; + +public class ClassTree { + public ClassWrapper classWrapper; + public Set parentClasses = new HashSet<>(); + public Set subClasses = new HashSet<>(); + + public ClassTree(ClassWrapper classWrapper) { + this.classWrapper = classWrapper; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/asm/ClassWrapper.java b/Radon-Program/src/main/java/me/itzsomebody/radon/asm/ClassWrapper.java new file mode 100644 index 00000000..bc76a4fd --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/asm/ClassWrapper.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.asm; + +import java.util.ArrayList; +import org.objectweb.asm.tree.ClassNode; + +public class ClassWrapper { + public ClassNode classNode; + public String originalName; + public boolean libraryNode; + + public ArrayList methods = new ArrayList<>(); + public ArrayList fields = new ArrayList<>(); + + public ClassWrapper(ClassNode classNode, boolean libraryNode) { + this.classNode = classNode; + this.originalName = classNode.name; + this.libraryNode = libraryNode; + + ClassWrapper instance = this; + classNode.methods.forEach(methodNode -> methods.add(new MethodWrapper(methodNode, instance, methodNode.name, methodNode.desc))); + if (classNode.fields != null) { + classNode.fields.forEach(fieldNode -> fields.add(new FieldWrapper(fieldNode, instance, fieldNode.name, fieldNode.desc))); + } + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/asm/FieldWrapper.java b/Radon-Program/src/main/java/me/itzsomebody/radon/asm/FieldWrapper.java new file mode 100644 index 00000000..ffe687d6 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/asm/FieldWrapper.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.asm; + +import org.objectweb.asm.tree.FieldNode; + +public class FieldWrapper { + public FieldNode fieldNode; + public ClassWrapper owner; + public String originalName; + public String originalDescription; + + public FieldWrapper(FieldNode fieldNode, ClassWrapper owner, String originalName, String originalDescription) { + this.fieldNode = fieldNode; + this.owner = owner; + this.originalName = originalName; + this.originalDescription = originalDescription; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/asm/MemberRemapper.java b/Radon-Program/src/main/java/me/itzsomebody/radon/asm/MemberRemapper.java new file mode 100644 index 00000000..4f82ea7a --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/asm/MemberRemapper.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.asm; + +import java.util.Map; +import org.objectweb.asm.commons.SimpleRemapper; + +public class MemberRemapper extends SimpleRemapper { + public MemberRemapper(final Map mappings) { + super(mappings); + } + + @Override + public String mapFieldName(String owner, String name, String desc) { + String remappedName = map(owner + '.' + name + '.' + desc); + return (remappedName != null) ? remappedName : name; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/asm/MethodWrapper.java b/Radon-Program/src/main/java/me/itzsomebody/radon/asm/MethodWrapper.java new file mode 100644 index 00000000..da727c6b --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/asm/MethodWrapper.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.asm; + +import org.objectweb.asm.tree.MethodNode; + +public class MethodWrapper { + public MethodNode methodNode; + public ClassWrapper owner; + public String originalName; + public String originalDescription; + + public MethodWrapper(MethodNode methodNode, ClassWrapper owner, String originalName, String originalDescription) { + this.methodNode = methodNode; + this.owner = owner; + this.originalName = originalName; + this.originalDescription = originalDescription; + } +} diff --git a/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java b/Radon-Program/src/main/java/me/itzsomebody/radon/asm/StackEmulator.java similarity index 92% rename from src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java rename to Radon-Program/src/main/java/me/itzsomebody/radon/asm/StackEmulator.java index a4ab48e2..a1c9d6a3 100644 --- a/src/main/java/me/itzsomebody/radon/analyzer/StackAnalyzer.java +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/asm/StackEmulator.java @@ -15,7 +15,7 @@ * along with this program. If not, see */ -package me.itzsomebody.radon.analyzer; +package me.itzsomebody.radon.asm; import java.util.EmptyStackException; import java.util.HashSet; @@ -33,51 +33,55 @@ import org.objectweb.asm.tree.MultiANewArrayInsnNode; /** - * Attempts to weakly emulate the stack in a method up to a breakpoint. + * Attempts to emulate the stack in a method up to a breakpoint. * * @author ItzSomebody */ -public class StackAnalyzer implements Opcodes { +public class StackEmulator implements Opcodes { /** * {@link MethodNode} we are checking. */ private MethodNode methodNode; + /** * {@link AbstractInsnNode} opcode which is the breakpoint. */ private AbstractInsnNode breakPoint; + /** - * Debug boolean; + * {@link HashSet} of {@link AbstractInsnNode}s where the stack is empty */ - private boolean DEBUG = false; + private Set emptyAt; /** - * Constructor to create a {@link StackAnalyzer} object. + * Constructor to create a {@link StackEmulator} object. * * @param methodNode the method node we want to check. * @param breakPoint the opcode we want to break on. */ - public StackAnalyzer(MethodNode methodNode, AbstractInsnNode breakPoint) { + public StackEmulator(MethodNode methodNode, AbstractInsnNode breakPoint) { this.methodNode = methodNode; this.breakPoint = breakPoint; + this.emptyAt = new HashSet<>(); + execute(false); } /** - * Returns a simulated stack of the Java bytecode instructions up to the - * specified breakpoint. + * Returns {@link HashSet} of {@link AbstractInsnNode}s where the stack is empty. * - * @return a simulated stack of the Java bytecode instructions up to the - * specified breakpoint. + * @return {@link HashSet} of {@link AbstractInsnNode}s where the stack is empty. */ - public Stack returnStackAtBreak() { - if (DEBUG) - System.out.println("Entering " + this.methodNode.owner + '.' - + this.methodNode.name + this.methodNode.desc); + public Set getEmptyAt() { + return this.emptyAt; + } + + /** + * Weakly emulates stack execution until no more instructions are left or the breakpoint is reached. + */ + private void execute(boolean debug) { Stack stack = new Stack<>(); // Simulated stack Set excHandlers = new HashSet<>(); - methodNode.tryCatchBlocks.forEach(tryCatchBlockNode -> { - excHandlers.add(tryCatchBlockNode.handler); - }); + methodNode.tryCatchBlocks.forEach(tryCatchBlockNode -> excHandlers.add(tryCatchBlockNode.handler)); for (int i = 0; i < this.methodNode.instructions.size(); i++) { AbstractInsnNode insn = this.methodNode.instructions.get(i); if (insn instanceof LabelNode @@ -85,6 +89,8 @@ public Stack returnStackAtBreak() { stack.clear(); // Stack gets cleared and exception is pushed. stack.push(null); } + if (stack.isEmpty()) + this.emptyAt.add(insn); if (this.breakPoint == insn) break; try { @@ -106,6 +112,7 @@ public Stack returnStackAtBreak() { case I2C: case I2S: case GOTO: + case RET: case RETURN: case NEWARRAY: case ANEWARRAY: @@ -138,6 +145,7 @@ public Stack returnStackAtBreak() { case I2D: case F2L: case F2D: + case JSR: case NEW: { // Pushes one-word constant to stack stack.push(null); @@ -371,15 +379,10 @@ public Stack returnStackAtBreak() { stack.push(null); // arrayref break; } - case JSR: - case RET: { - throw new RuntimeException("JSR/RET not supported."); - } } } catch (EmptyStackException empty) { - if (DEBUG) empty.printStackTrace(); + if (debug) empty.printStackTrace(); } } - return stack; } } \ No newline at end of file diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/asm/UsedInstructionsFinder.java b/Radon-Program/src/main/java/me/itzsomebody/radon/asm/UsedInstructionsFinder.java new file mode 100644 index 00000000..520c0918 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/asm/UsedInstructionsFinder.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.asm; + +import java.util.HashSet; +import java.util.Set; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.JumpInsnNode; + +/** + * Runs through all possible execution flows of a set of instructions to figure + * what instructions are used. + * + * @author ItzSomebody + */ +public class UsedInstructionsFinder { + private InsnList instructions; + private Set usedInstructions = new HashSet<>(); + + public UsedInstructionsFinder(InsnList instructions) { + this.instructions = instructions; + } + + public Set getUsedInstructions() { + execute(instructions.getFirst()); + return usedInstructions; + } + + private void execute(AbstractInsnNode insn) { + while (true) { + if (insn == null || usedInstructions.contains(insn)) { + return; + } + + usedInstructions.add(insn); + if (insn.getOpcode() >= Opcodes.IRETURN && insn.getOpcode() <= Opcodes.RETURN) { + return; + } else if ((insn.getOpcode() >= Opcodes.IFEQ && insn.getOpcode() <= Opcodes.IF_ACMPNE) || insn.getOpcode() == Opcodes.IFNULL || insn.getOpcode() == Opcodes.IFNONNULL || insn.getOpcode() == Opcodes.GOTO) { + execute(((JumpInsnNode) insn).label); + } else if (insn.getOpcode() == Opcodes.JSR || insn.getOpcode() == Opcodes.RET) { + throw new RuntimeException("Did not expect JSR/RET instruction"); + } + + insn = insn.getNext(); + } + } +} \ No newline at end of file diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/config/ConfigurationParser.java b/Radon-Program/src/main/java/me/itzsomebody/radon/config/ConfigurationParser.java new file mode 100644 index 00000000..97177ba1 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/config/ConfigurationParser.java @@ -0,0 +1,533 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.config; + +import java.io.File; +import java.io.InputStream; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import me.itzsomebody.radon.Dictionaries; +import me.itzsomebody.radon.SessionInfo; +import me.itzsomebody.radon.exceptions.IllegalConfigurationKeyException; +import me.itzsomebody.radon.exceptions.IllegalConfigurationValueException; +import me.itzsomebody.radon.exclusions.Exclusion; +import me.itzsomebody.radon.exclusions.ExclusionManager; +import me.itzsomebody.radon.transformers.Transformer; +import me.itzsomebody.radon.transformers.miscellaneous.Crasher; +import me.itzsomebody.radon.transformers.miscellaneous.expiration.Expiration; +import me.itzsomebody.radon.transformers.miscellaneous.expiration.ExpirationSetup; +import me.itzsomebody.radon.transformers.miscellaneous.watermarker.Watermarker; +import me.itzsomebody.radon.transformers.miscellaneous.watermarker.WatermarkerSetup; +import me.itzsomebody.radon.transformers.obfuscators.flow.FlowObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.invokedynamic.InvokeDynamic; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.HideCode; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.LineNumbers; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.LocalVariables; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.MemberShuffler; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.SourceDebug; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.SourceName; +import me.itzsomebody.radon.transformers.obfuscators.numbers.NumberObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.renamer.Renamer; +import me.itzsomebody.radon.transformers.obfuscators.renamer.RenamerSetup; +import me.itzsomebody.radon.transformers.obfuscators.strings.StringEncryption; +import me.itzsomebody.radon.transformers.obfuscators.strings.StringEncryptionSetup; +import me.itzsomebody.radon.transformers.obfuscators.strings.StringPool; +import me.itzsomebody.radon.transformers.optimizers.Optimizer; +import me.itzsomebody.radon.transformers.optimizers.OptimizerDelegator; +import me.itzsomebody.radon.transformers.optimizers.OptimizerSetup; +import me.itzsomebody.radon.transformers.shrinkers.Shrinker; +import me.itzsomebody.radon.transformers.shrinkers.ShrinkerDelegator; +import me.itzsomebody.radon.transformers.shrinkers.ShrinkerSetup; +import org.yaml.snakeyaml.Yaml; + +/** + * A big mess which somehow parses the configuration files. + * + * @author ItzSomebody + */ +public class ConfigurationParser { + private Map map; + private final static Set VALID_KEYS = new HashSet() { + { + for (ConfigurationSettings setting : ConfigurationSettings.values()) { + add(setting.getValue()); + } + } + }; + + public ConfigurationParser(InputStream in) { + this.map = new Yaml().load(in); + this.map.keySet().forEach(s -> { + if (!VALID_KEYS.contains(s)) { + throw new IllegalConfigurationKeyException(s); + } + }); + } + + public SessionInfo createSessionFromConfig() { + SessionInfo info = new SessionInfo(); + info.setInput(getInput()); + info.setOutput(getOutput()); + info.setLibraries(getLibraries()); + info.setTransformers(getTransformers()); + info.setExclusions(getExclusions()); + info.setTrashClasses(getTrashClasses()); + info.setDictionaryType(getDictionary()); + + return info; + } + + private File getInput() { + Object o = map.get(ConfigurationSettings.INPUT.getValue()); + if (!(o instanceof String)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.INPUT.getValue(), String.class, o.getClass()); + } + + return new File((String) o); + } + + private File getOutput() { + Object o = map.get(ConfigurationSettings.OUTPUT.getValue()); + if (!(o instanceof String)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.OUTPUT.getValue(), String.class, o.getClass()); + } + + return new File((String) o); + } + + private List getLibraries() { + Object o = map.get(ConfigurationSettings.LIBRARIES.getValue()); + if (!(o instanceof List)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.LIBRARIES.getValue(), List.class, o.getClass()); + } + + ArrayList libraries = new ArrayList<>(); + List libs = (List) o; + for (Object lib : libs) { + try { + String s = (String) lib; + libraries.add(new File(s)); + } catch (ClassCastException e) { + throw new IllegalConfigurationValueException(ConfigurationSettings.LIBRARIES.getValue(), String.class, lib.getClass()); + } + } + + return libraries; + } + + private List getTransformers() { + ArrayList transformers = new ArrayList<>(); + transformers.add(getShrinkerTransformer()); + transformers.add(getOptimizerTransformer()); + transformers.add(getRenamerTransformer()); + transformers.add(getNumberObfuscationTransformer()); + transformers.add(getInvokeDynamicTransformer()); + List stringEncrypters = getStringEncryptionTransformers(); + if (stringEncrypters != null) { + transformers.addAll(stringEncrypters); + } + transformers.add(getFlowObfuscationTransformer()); + transformers.add(getShufflerTransformer()); + transformers.add(getLocalVariablesTransformer()); + transformers.add(getLineNumbersTransformer()); + transformers.add(getSourceNameTransformer()); + transformers.add(getSourceDebugTransformer()); + transformers.add(getCrasherTransformer()); + transformers.add(getHideCodeTransformer()); + transformers.add(getExpirationTransformer()); + transformers.add(getWatermarkerTransformer()); + + return transformers; + } + + private Shrinker getShrinkerTransformer() { + Object o = map.get(ConfigurationSettings.SHRINKER.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof Map)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.SHRINKER.getValue(), Map.class, o.getClass()); + } + + try { + Map shrinkerSettings = (Map) o; + if (!shrinkerSettings.get("Enabled")) { + return null; + } + + boolean attributes = shrinkerSettings.getOrDefault("RemoveAttributes", false); + boolean debug = shrinkerSettings.getOrDefault("RemoveDebug", false); + boolean invisibleAnnotations = shrinkerSettings.getOrDefault("RemoveInvisibleAnnotations", false); + boolean visibleAnnotations = shrinkerSettings.getOrDefault("RemoveVisibleAnnotations", false); + boolean unusedCode = shrinkerSettings.getOrDefault("RemoveUnusedCode", false); + boolean unusedMembers = shrinkerSettings.getOrDefault("RemoveUnusedMembers", false); + + return new ShrinkerDelegator(new ShrinkerSetup(visibleAnnotations, invisibleAnnotations, attributes, debug, unusedCode, unusedMembers)); + } catch (ClassCastException e) { + throw new IllegalConfigurationValueException("Error while parsing shrinker setup: " + e.getMessage()); + } + } + + private Optimizer getOptimizerTransformer() { + Object o = map.get(ConfigurationSettings.OPTIMIZER.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof Map)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.OPTIMIZER.getValue(), Map.class, o.getClass()); + } + + try { + Map optimizerSettings = (Map) o; + if (!optimizerSettings.get("Enabled")) { + return null; + } + + boolean gotoGoto = optimizerSettings.getOrDefault("RemoveGotoGoto", false); + boolean gotoReturn = optimizerSettings.getOrDefault("RemoveGotoReturn", false); + boolean nopInstructions = optimizerSettings.getOrDefault("RemoveNopInstructions", false); + + return new OptimizerDelegator(new OptimizerSetup(nopInstructions, gotoGoto, gotoReturn)); + } catch (ClassCastException e) { + throw new IllegalConfigurationValueException("Error while parsing optimizer setup: " + e.getMessage()); + } + } + + private Renamer getRenamerTransformer() { + Object o = map.get(ConfigurationSettings.RENAMER.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof Map)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.RENAMER.getValue(), Map.class, o.getClass()); + } + + try { + Map renamerSettings = (Map) o; + if (!(boolean) renamerSettings.get("Enabled")) { + return null; + } + Object[] objects = ((List) renamerSettings.getOrDefault("AdaptResources", new ArrayList())).toArray(); + String[] adaptThese = Arrays.copyOf(objects, objects.length, String[].class); + String repackageName = (String) renamerSettings.get("Repackage"); + + return new Renamer(new RenamerSetup(adaptThese, repackageName)); + } catch (ClassCastException e) { + throw new IllegalConfigurationValueException("Error while parsing renamer setup: " + e.getMessage()); + } + } + + private NumberObfuscation getNumberObfuscationTransformer() { + Object o = map.get(ConfigurationSettings.NUMBER_OBFUSCATION.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof String)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.NUMBER_OBFUSCATION.getValue(), String.class, o.getClass()); + } + String s = (String) o; + if (!s.equals("Light") && !s.equals("Normal") && !s.equals("Heavy")) { + throw new IllegalConfigurationValueException("Expected Light, Normal or Heavy as mode for number obfuscation. Got " + s + " instead."); + } + + return NumberObfuscation.getTransformerFromString(s); + } + + private InvokeDynamic getInvokeDynamicTransformer() { + Object o = map.get(ConfigurationSettings.INVOKEDYNAMIC.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof String)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.INVOKEDYNAMIC.getValue(), String.class, o.getClass()); + } + String s = (String) o; + if (!s.equals("Light") && !s.equals("Normal") && !s.equals("Heavy")) { + throw new IllegalConfigurationValueException("Expected Light, Normal or Heavy as mode for invokedynamic obfuscation. Got " + s + " instead."); + } + + return InvokeDynamic.getTransformerFromString(s); + } + + private List getStringEncryptionTransformers() { + Object o = map.get(ConfigurationSettings.STRING_ENCRYPTION.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof Map)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.STRING_ENCRYPTION.getValue(), Map.class, o.getClass()); + } + Map settings = (Map) o; + if (!(boolean) settings.get("Enabled")) { + return null; + } + String s = (String) settings.get("Mode"); + if (!s.equals("Light") && !s.equals("Normal") && !s.equals("Heavy")) { + throw new IllegalConfigurationValueException("Expected Light, Normal or Heavy as mode for string encryption. Got " + s + " instead."); + } + boolean pool = (boolean) settings.getOrDefault("StringPool", false); + List exclusions = (List) settings.getOrDefault("Exclusions", new ArrayList()); + + ArrayList things = new ArrayList<>(); + things.add(StringEncryption.getTransformerFromString(s, new StringEncryptionSetup(exclusions))); + if (pool) { + things.add(new StringPool(new StringEncryptionSetup(exclusions))); + } + + return things; + } + + private FlowObfuscation getFlowObfuscationTransformer() { + Object o = map.get(ConfigurationSettings.FLOW_OBFUSCATION.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof String)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.FLOW_OBFUSCATION.getValue(), String.class, o.getClass()); + } + String s = (String) o; + if (!s.equals("Light") && !s.equals("Normal") && !s.equals("Heavy")) { + throw new IllegalConfigurationValueException("Expected Light, Normal or Heavy as mode for flow obfuscation. Got " + s + " instead."); + } + + return FlowObfuscation.getTransformerFromString(s); + } + + private MemberShuffler getShufflerTransformer() { + Object o = map.get(ConfigurationSettings.SHUFFLER.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof Boolean)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.SHUFFLER.getValue(), Boolean.class, o.getClass()); + } + + return ((boolean) o) ? new MemberShuffler() : null; + } + + private LocalVariables getLocalVariablesTransformer() { + Object o = map.get(ConfigurationSettings.LOCAL_VARIABLES.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof Map)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.LOCAL_VARIABLES.getValue(), Map.class, o.getClass()); + } + + try { + Map settings = (Map) o; + if (!settings.get("Enabled")) { + return null; + } + + return new LocalVariables(settings.getOrDefault("Remove", false)); + } catch (ClassCastException e) { + throw new IllegalConfigurationValueException("Error while parsing local variable obfuscation setup: " + e.getMessage()); + } + } + + private LineNumbers getLineNumbersTransformer() { + Object o = map.get(ConfigurationSettings.LINE_NUMBERS.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof Map)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.LINE_NUMBERS.getValue(), Map.class, o.getClass()); + } + + try { + Map settings = (Map) o; + if (!settings.get("Enabled")) { + return null; + } + + return new LineNumbers(settings.getOrDefault("Remove", false)); + } catch (ClassCastException e) { + throw new IllegalConfigurationValueException("Error while parsing line number obfuscation setup: " + e.getMessage()); + } + } + + private SourceName getSourceNameTransformer() { + Object o = map.get(ConfigurationSettings.SOURCE_NAME.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof Map)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.SOURCE_NAME.getValue(), Map.class, o.getClass()); + } + + try { + Map settings = (Map) o; + if (!settings.get("Enabled")) { + return null; + } + + return new SourceName(settings.getOrDefault("Remove", false)); + } catch (ClassCastException e) { + throw new IllegalConfigurationValueException("Error while parsing source name obfuscation setup: " + e.getMessage()); + } + } + + private SourceDebug getSourceDebugTransformer() { + Object o = map.get(ConfigurationSettings.SOURCE_DEBUG.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof Map)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.SOURCE_DEBUG.getValue(), Map.class, o.getClass()); + } + + try { + Map settings = (Map) o; + if (!settings.get("Enabled")) { + return null; + } + + return new SourceDebug(settings.getOrDefault("Remove", false)); + } catch (ClassCastException e) { + throw new IllegalConfigurationValueException("Error while parsing source debug obfuscation setup: " + e.getMessage()); + } + } + + private Crasher getCrasherTransformer() { + Object o = map.get(ConfigurationSettings.CRASHER.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof Boolean)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.CRASHER.getValue(), Boolean.class, o.getClass()); + } + + return ((Boolean) o) ? new Crasher() : null; + } + + private HideCode getHideCodeTransformer() { + Object o = map.get(ConfigurationSettings.HIDE_CODE.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof Boolean)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.HIDE_CODE.getValue(), Boolean.class, o.getClass()); + } + + return ((Boolean) o) ? new HideCode() : null; + } + + private Expiration getExpirationTransformer() { + Object o = map.get(ConfigurationSettings.EXPIRATION.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof Map)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.EXPIRATION.getValue(), Map.class, o.getClass()); + } + + try { + Map settings = (Map) o; + if (!(boolean) settings.get("Enabled")) { + return null; + } + + boolean injectJOptionPane = (Boolean) settings.get("InjectJOptionPane"); + String expirationMessage = (String) settings.get("Message"); + long expirationDate = new SimpleDateFormat("MM/dd/yyyy").parse((String) settings.get("Expires")).getTime(); + + return new Expiration(new ExpirationSetup(expirationMessage, expirationDate, injectJOptionPane)); + } catch (ClassCastException | ParseException e) { + throw new IllegalConfigurationValueException("Error while parsing expiration setup: " + e.getMessage()); + } + } + + private Watermarker getWatermarkerTransformer() { + Object o = map.get(ConfigurationSettings.WATERMARK.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof Map)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.WATERMARK.getValue(), Map.class, o.getClass()); + } + + try { + Map settings = (Map) o; + if (!(Boolean) settings.get("Enabled")) { + return null; + } + + String message = (String) settings.get("Message"); + String key = (String) settings.get("Key"); + + return new Watermarker(new WatermarkerSetup(message, key)); + } catch (ClassCastException e) { + throw new IllegalConfigurationValueException("Error while parsing watermark setup: " + e.getMessage()); + } + } + + private ExclusionManager getExclusions() { + ExclusionManager exclusions = new ExclusionManager(); + Object o = map.get(ConfigurationSettings.EXCLUSIONS.getValue()); + if (o == null) { + return null; + } + if (!(o instanceof List)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.EXCLUSIONS.getValue(), List.class, o.getClass()); + } + + try { + List list = (List) o; + list.forEach(s -> { + exclusions.addExclusion(new Exclusion(s)); + }); + } catch (ClassCastException e) { + throw new IllegalConfigurationValueException("Error while parsing exclusion setup: " + e.getMessage()); + } + + return exclusions; + } + + private int getTrashClasses() { + Object o = map.get(ConfigurationSettings.TRASH_CLASSES.getValue()); + if (o == null) { + return -1; + } + if (!(o instanceof Integer)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.TRASH_CLASSES.getValue(), Integer.class, o.getClass()); + } + return (int) o; + } + + private Dictionaries getDictionary() { + Object o = map.get(ConfigurationSettings.DICTIONARY.getValue()); + if (o == null) { + return Dictionaries.ALPHABETICAL; + } + if (!(o instanceof String) && !(o instanceof Integer)) { + throw new IllegalConfigurationValueException(ConfigurationSettings.DICTIONARY.getValue(), String.class, o.getClass()); + } + if (o instanceof String) { + return Dictionaries.stringToDictionary((String) o); + } else { + return Dictionaries.intToDictionary((int) o); + } + } +} diff --git a/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java b/Radon-Program/src/main/java/me/itzsomebody/radon/config/ConfigurationSettings.java similarity index 52% rename from src/main/java/me/itzsomebody/radon/config/ConfigEnum.java rename to Radon-Program/src/main/java/me/itzsomebody/radon/config/ConfigurationSettings.java index aa8ec372..08b5b46e 100644 --- a/src/main/java/me/itzsomebody/radon/config/ConfigEnum.java +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/config/ConfigurationSettings.java @@ -17,47 +17,37 @@ package me.itzsomebody.radon.config; -/** - * Enums of config objects :D - * - * @author ItzSomebody - */ -public enum ConfigEnum { +public enum ConfigurationSettings { INPUT("Input"), OUTPUT("Output"), LIBRARIES("Libraries"), - EXEMPTS("Exempts"), + EXCLUSIONS("Exclusions"), STRING_ENCRYPTION("StringEncryption"), FLOW_OBFUSCATION("FlowObfuscation"), INVOKEDYNAMIC("InvokeDynamic"), - LOCAL_VARIABLES("LocalVariableObfuscation"), + LINE_NUMBERS("LineNumbers"), + LOCAL_VARIABLES("LocalVariables"), + NUMBER_OBFUSCATION("NumberObfuscation"), + HIDE_CODE("HideCode"), CRASHER("Crasher"), - HIDER("HideCode"), - STRING_POOL("StringPool"), - LINE_NUMBERS("LineNumberObfuscation"), - NUMBERS("NumberObfuscation"), - SOURCE_NAME("SourceNameObfuscation"), - SOURCE_DEBUG("SourceDebugObfuscation"), - TRASH_CLASSES("TrashClasses"), - WATERMARK_MSG("WatermarkMessage"), - WATERMARK_KEY("WatermarkKey"), - WATERMARK_TYPE("WatermarkType"), - SPIGOT_PLUGIN("SpigotPlugin"), // TODO: Remove this, replace with custom rules that allow users to exclude conflicts - RENAMER("Renamer"), - EXPIRATION_TIME("ExpiryTime"), - EXPIRATION_MESSAGE("ExpiryMessage"), + EXPIRATION("Expiration"), + WATERMARK("Watermarker"), + OPTIMIZER("Optimizer"), + SHRINKER("Shrinker"), SHUFFLER("Shuffler"), + SOURCE_NAME("SourceName"), + SOURCE_DEBUG("SourceDebug"), + RENAMER("Renamer"), DICTIONARY("Dictionary"), - INNERCLASSES("InnerClassRemover"); + TRASH_CLASSES("TrashClasses"); - private final String text; + private String value; - private ConfigEnum(String text) { - this.text = text; + ConfigurationSettings(String value) { + this.value = value; } - @Override - public String toString() { - return text; + public String getValue() { + return value; } } diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/config/ConfigurationWriter.java b/Radon-Program/src/main/java/me/itzsomebody/radon/config/ConfigurationWriter.java new file mode 100644 index 00000000..317a57ce --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/config/ConfigurationWriter.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.config; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; +import me.itzsomebody.radon.SessionInfo; +import me.itzsomebody.radon.transformers.Transformer; +import me.itzsomebody.radon.transformers.miscellaneous.Crasher; +import me.itzsomebody.radon.transformers.miscellaneous.expiration.Expiration; +import me.itzsomebody.radon.transformers.miscellaneous.watermarker.Watermarker; +import me.itzsomebody.radon.transformers.obfuscators.flow.FlowObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.flow.HeavyFlowObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.flow.LightFlowObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.flow.NormalFlowObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.invokedynamic.HeavyInvokeDynamic; +import me.itzsomebody.radon.transformers.obfuscators.invokedynamic.InvokeDynamic; +import me.itzsomebody.radon.transformers.obfuscators.invokedynamic.LightInvokeDynamic; +import me.itzsomebody.radon.transformers.obfuscators.invokedynamic.NormalInvokeDynamic; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.HideCode; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.LineNumbers; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.LocalVariables; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.MemberShuffler; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.SourceDebug; +import me.itzsomebody.radon.transformers.obfuscators.miscellaneous.SourceName; +import me.itzsomebody.radon.transformers.obfuscators.numbers.HeavyNumberObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.numbers.LightNumberObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.numbers.NormalNumberObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.numbers.NumberObfuscation; +import me.itzsomebody.radon.transformers.obfuscators.renamer.Renamer; +import me.itzsomebody.radon.transformers.obfuscators.strings.HeavyStringEncryption; +import me.itzsomebody.radon.transformers.obfuscators.strings.LightStringEncryption; +import me.itzsomebody.radon.transformers.obfuscators.strings.NormalStringEncryption; +import me.itzsomebody.radon.transformers.obfuscators.strings.StringEncryption; +import me.itzsomebody.radon.transformers.obfuscators.strings.StringPool; +import me.itzsomebody.radon.transformers.optimizers.OptimizerDelegator; +import me.itzsomebody.radon.transformers.shrinkers.ShrinkerDelegator; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; + +/** + * Another big mess which somehow works. + * + * @author ItzSomebody + */ +public class ConfigurationWriter { + private Map documentMap = new LinkedHashMap<>(); + + public ConfigurationWriter(SessionInfo info) { + if (info.getInput() != null) { + documentMap.put("Input", info.getInput().getAbsolutePath()); + } + if (info.getOutput() != null) { + documentMap.put("Output", info.getOutput().getAbsolutePath()); + } + if (info.getTransformers() != null) { + for (Transformer transformer : info.getTransformers()) { + if (transformer instanceof StringEncryption) { + StringEncryption encryption = (StringEncryption) transformer; + documentMap.putIfAbsent(ConfigurationSettings.STRING_ENCRYPTION.getValue(), new LinkedHashMap()); + ((LinkedHashMap) documentMap.get(ConfigurationSettings.STRING_ENCRYPTION.getValue())).putIfAbsent("Enabled", true); + + if (transformer instanceof LightStringEncryption) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.STRING_ENCRYPTION.getValue())).put("Mode", "Light"); + } else if (transformer instanceof NormalStringEncryption) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.STRING_ENCRYPTION.getValue())).put("Mode", "Normal"); + } else if (transformer instanceof HeavyStringEncryption) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.STRING_ENCRYPTION.getValue())).put("Mode", "Heavy"); + } else if (transformer instanceof StringPool) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.STRING_ENCRYPTION.getValue())).put("StringPool", true); + } + + if (encryption.getExcludedStrings() != null) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.STRING_ENCRYPTION.getValue())).putIfAbsent("Exclusions", encryption.getExcludedStrings()); + } + } else if (transformer instanceof InvokeDynamic) { + if (transformer instanceof LightInvokeDynamic) { + documentMap.put(ConfigurationSettings.INVOKEDYNAMIC.getValue(), "Light"); + } else if (transformer instanceof NormalInvokeDynamic) { + documentMap.put(ConfigurationSettings.INVOKEDYNAMIC.getValue(), "Normal"); + } else if (transformer instanceof HeavyInvokeDynamic) { + documentMap.put(ConfigurationSettings.INVOKEDYNAMIC.getValue(), "Heavy"); + } + } else if (transformer instanceof NumberObfuscation) { + if (transformer instanceof LightNumberObfuscation) { + documentMap.put(ConfigurationSettings.NUMBER_OBFUSCATION.getValue(), "Light"); + } else if (transformer instanceof NormalNumberObfuscation) { + documentMap.put(ConfigurationSettings.NUMBER_OBFUSCATION.getValue(), "Normal"); + } else if (transformer instanceof HeavyNumberObfuscation) { + documentMap.put(ConfigurationSettings.NUMBER_OBFUSCATION.getValue(), "Heavy"); + } + } else if (transformer instanceof FlowObfuscation) { + if (transformer instanceof LightFlowObfuscation) { + documentMap.put(ConfigurationSettings.FLOW_OBFUSCATION.getValue(), "Light"); + } else if (transformer instanceof NormalFlowObfuscation) { + documentMap.put(ConfigurationSettings.FLOW_OBFUSCATION.getValue(), "Normal"); + } else if (transformer instanceof HeavyFlowObfuscation) { + documentMap.put(ConfigurationSettings.FLOW_OBFUSCATION.getValue(), "Heavy"); + } + } else if (transformer instanceof LocalVariables) { + documentMap.putIfAbsent(ConfigurationSettings.LOCAL_VARIABLES.getValue(), new LinkedHashMap()); + ((LinkedHashMap) documentMap.get(ConfigurationSettings.LOCAL_VARIABLES.getValue())).put("Enabled", true); + ((LinkedHashMap) documentMap.get(ConfigurationSettings.LOCAL_VARIABLES.getValue())).put("Remove", ((LocalVariables) transformer).isRemove()); + } else if (transformer instanceof LineNumbers) { + documentMap.putIfAbsent(ConfigurationSettings.LINE_NUMBERS.getValue(), new LinkedHashMap()); + ((LinkedHashMap) documentMap.get(ConfigurationSettings.LINE_NUMBERS.getValue())).put("Enabled", true); + ((LinkedHashMap) documentMap.get(ConfigurationSettings.LINE_NUMBERS.getValue())).put("Remove", ((LineNumbers) transformer).isRemove()); + } else if (transformer instanceof SourceName) { + documentMap.putIfAbsent(ConfigurationSettings.SOURCE_NAME.getValue(), new LinkedHashMap()); + ((LinkedHashMap) documentMap.get(ConfigurationSettings.SOURCE_NAME.getValue())).put("Enabled", true); + ((LinkedHashMap) documentMap.get(ConfigurationSettings.SOURCE_NAME.getValue())).put("Remove", ((SourceName) transformer).isRemove()); + } else if (transformer instanceof SourceDebug) { + documentMap.putIfAbsent(ConfigurationSettings.SOURCE_DEBUG.getValue(), new LinkedHashMap()); + ((LinkedHashMap) documentMap.get(ConfigurationSettings.SOURCE_DEBUG.getValue())).put("Enabled", true); + ((LinkedHashMap) documentMap.get(ConfigurationSettings.SOURCE_DEBUG.getValue())).put("Remove", ((SourceDebug) transformer).isRemove()); + } else if (transformer instanceof HideCode) { + documentMap.put(ConfigurationSettings.HIDE_CODE.getValue(), true); + } else if (transformer instanceof MemberShuffler) { + documentMap.put(ConfigurationSettings.SHUFFLER.getValue(), true); + } else if (transformer instanceof Crasher) { + documentMap.put(ConfigurationSettings.CRASHER.getValue(), true); + } else if (transformer instanceof Renamer) { + Renamer renamer = (Renamer) transformer; + documentMap.putIfAbsent(ConfigurationSettings.RENAMER.getValue(), new LinkedHashMap()); + ((LinkedHashMap) documentMap.get(ConfigurationSettings.RENAMER.getValue())).put("Enabled", true); + if (renamer.getSetup().getRepackageName() != null) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.RENAMER.getValue())).put("Repackage", renamer.getSetup().getRepackageName()); + } + if (renamer.getSetup().getAdaptTheseResources() != null) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.RENAMER.getValue())).put("AdaptResources", Arrays.asList(renamer.getSetup().getAdaptTheseResources())); + } + } else if (transformer instanceof OptimizerDelegator) { + OptimizerDelegator optimizer = (OptimizerDelegator) transformer; + documentMap.putIfAbsent(ConfigurationSettings.OPTIMIZER.getValue(), new LinkedHashMap()); + ((LinkedHashMap) documentMap.get(ConfigurationSettings.OPTIMIZER.getValue())).put("Enabled", true); + if (optimizer.getSetup().isGotoGotoEnabled()) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.OPTIMIZER.getValue())).put("RemoveGotoGoto", true); + } + if (optimizer.getSetup().isGotoReturnEnabled()) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.OPTIMIZER.getValue())).put("RemoveGotoReturn", true); + } + if (optimizer.getSetup().isNopRemoverEnabled()) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.OPTIMIZER.getValue())).put("RemoveNopInstructions", true); + } + } else if (transformer instanceof ShrinkerDelegator) { + ShrinkerDelegator shrinker = (ShrinkerDelegator) transformer; + documentMap.putIfAbsent(ConfigurationSettings.SHRINKER.getValue(), new LinkedHashMap()); + ((LinkedHashMap) documentMap.get(ConfigurationSettings.SHRINKER.getValue())).put("Enabled", true); + if (shrinker.getSetup().isRemoveAttributes()) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.SHRINKER.getValue())).put("RemoveAttributes", true); + } + if (shrinker.getSetup().isRemoveDebug()) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.SHRINKER.getValue())).put("RemoveDebug", true); + } + if (shrinker.getSetup().isRemoveInvisibleAnnotations()) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.SHRINKER.getValue())).put("RemoveInvisibleAnnotations", true); + } + if (shrinker.getSetup().isRemoveVisibleAnnotations()) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.SHRINKER.getValue())).put("RemoveVisibleAnnotations", true); + } + if (shrinker.getSetup().isRemoveUnusedCode()) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.SHRINKER.getValue())).put("RemoveUnusedCode", true); + } + if (shrinker.getSetup().isRemoveUnusedMembers()) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.SHRINKER.getValue())).put("RemoveUnusedMembers", true); + } + } else if (transformer instanceof Watermarker) { + Watermarker watermarker = (Watermarker) transformer; + documentMap.putIfAbsent(ConfigurationSettings.WATERMARK.getValue(), new LinkedHashMap()); + ((LinkedHashMap) documentMap.get(ConfigurationSettings.WATERMARK.getValue())).put("Enabled", true); + if (watermarker.getSetup().getMessage() != null) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.WATERMARK.getValue())).put("Message", watermarker.getSetup().getMessage()); + } + if (watermarker.getSetup().getKey() != null) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.WATERMARK.getValue())).put("Key", watermarker.getSetup().getKey()); + } + } else if (transformer instanceof Expiration) { + Expiration expiration = (Expiration) transformer; + documentMap.putIfAbsent(ConfigurationSettings.EXPIRATION.getValue(), new LinkedHashMap()); + ((LinkedHashMap) documentMap.get(ConfigurationSettings.EXPIRATION.getValue())).put("Enabled", true); + if (expiration.getSetup().getMessage() != null) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.EXPIRATION.getValue())).put("Message", expiration.getSetup().getMessage()); + } + ((LinkedHashMap) documentMap.get(ConfigurationSettings.EXPIRATION.getValue())).put("Expires", new SimpleDateFormat("MM/dd/yyyy").format(new Date(expiration.getSetup().getExpires()))); + if (expiration.getSetup().isInjectJOptionPane()) { + ((LinkedHashMap) documentMap.get(ConfigurationSettings.EXPIRATION.getValue())).put("InjectJOptionPane", expiration.getSetup().isInjectJOptionPane()); + } + } + } + } + if (info.getDictionaryType() != null) { + documentMap.put("Dictionary", info.getDictionaryType().getValue()); + } + documentMap.put("TrashClasses", info.getTrashClasses()); + if (info.getLibraries() != null) { + ArrayList libs = new ArrayList<>(); + info.getLibraries().forEach(file -> libs.add(file.getAbsolutePath())); + documentMap.put("Libraries", libs); + } + if (info.getExclusions() != null) { + ArrayList exclusions = new ArrayList<>(); + info.getExclusions().getExclusions().forEach(exclusion -> exclusions.add(exclusion.getExclusionType().getValue() + ": " + exclusion.getExclusion().toString())); + documentMap.put("Exclusions", exclusions); + } + } + + public String dump() { + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + options.setIndent(4); + return new Yaml(options).dump(documentMap); + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/BadInputException.java b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/BadInputException.java new file mode 100644 index 00000000..cb6a22b0 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/BadInputException.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.exceptions; + +public class BadInputException extends RuntimeException { +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/ByteArrayConversionException.java b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/ByteArrayConversionException.java new file mode 100644 index 00000000..0f7a2eb9 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/ByteArrayConversionException.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.exceptions; + +import java.io.IOException; + +public class ByteArrayConversionException extends RuntimeException { + public ByteArrayConversionException(IOException ioe) { + super(ioe.getMessage()); + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/ConfigurationParseException.java b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/ConfigurationParseException.java new file mode 100644 index 00000000..7a6b514e --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/ConfigurationParseException.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.exceptions; + +public class ConfigurationParseException extends RuntimeException { + public ConfigurationParseException(String uhoh) { + super(uhoh); + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/IllegalConfigurationKeyException.java b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/IllegalConfigurationKeyException.java new file mode 100644 index 00000000..42541576 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/IllegalConfigurationKeyException.java @@ -0,0 +1,7 @@ +package me.itzsomebody.radon.exceptions; + +public class IllegalConfigurationKeyException extends RuntimeException { + public IllegalConfigurationKeyException(String msg) { + super(msg); + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/IllegalConfigurationValueException.java b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/IllegalConfigurationValueException.java new file mode 100644 index 00000000..278cc136 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/IllegalConfigurationValueException.java @@ -0,0 +1,11 @@ +package me.itzsomebody.radon.exceptions; + +public class IllegalConfigurationValueException extends RuntimeException { + public IllegalConfigurationValueException(String msg) { + super(msg); + } + + public IllegalConfigurationValueException(String value, Class expected, Class gotInstead) { + super(String.format("Value %s was expected to be %s, got %s instead.", value, expected.getName(), gotInstead.getName())); + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/IllegalDictionaryException.java b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/IllegalDictionaryException.java new file mode 100644 index 00000000..910eaa0b --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/IllegalDictionaryException.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.exceptions; + +public class IllegalDictionaryException extends IllegalArgumentException { +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/InputNotFoundException.java b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/InputNotFoundException.java new file mode 100644 index 00000000..73874f43 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/InputNotFoundException.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.exceptions; + +public class InputNotFoundException extends RuntimeException { +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/MissingClassException.java b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/MissingClassException.java new file mode 100644 index 00000000..d12d34be --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/MissingClassException.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.exceptions; + +public class MissingClassException extends RuntimeException { + public MissingClassException(String msg) { + super(msg); + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/NoTransformersException.java b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/NoTransformersException.java new file mode 100644 index 00000000..fa26c179 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/NoTransformersException.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.exceptions; + +public class NoTransformersException extends RuntimeException { +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/OutputWriteException.java b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/OutputWriteException.java new file mode 100644 index 00000000..dd2c2ab4 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/OutputWriteException.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.exceptions; + +public class OutputWriteException extends RuntimeException { +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/WatermarkExtractionException.java b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/WatermarkExtractionException.java new file mode 100644 index 00000000..9b14dc3e --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/exceptions/WatermarkExtractionException.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.exceptions; + +public class WatermarkExtractionException extends RuntimeException { + public WatermarkExtractionException() { + super(); + } + + public WatermarkExtractionException(String msg) { + super(msg); + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/exclusions/Exclusion.java b/Radon-Program/src/main/java/me/itzsomebody/radon/exclusions/Exclusion.java new file mode 100644 index 00000000..cdd5d753 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/exclusions/Exclusion.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.exclusions; + +import java.util.regex.Pattern; + +public class Exclusion { + private Pattern exclusion; + private ExclusionType exclusionType; + + public Exclusion(String exclusion) { + if (exclusion.startsWith(ExclusionType.GLOBAL.getValue())) { + initFields(exclusion, ExclusionType.GLOBAL); + } else if (exclusion.startsWith(ExclusionType.STRING_ENCRYPTION.getValue())) { + initFields(exclusion, ExclusionType.STRING_ENCRYPTION); + } else if (exclusion.startsWith(ExclusionType.INVOKEDYNAMIC.getValue())) { + initFields(exclusion, ExclusionType.INVOKEDYNAMIC); + } else if (exclusion.startsWith(ExclusionType.FLOW_OBFUSCATION.getValue())) { + initFields(exclusion, ExclusionType.FLOW_OBFUSCATION); + } else if (exclusion.startsWith(ExclusionType.LINE_NUMBERS.getValue())) { + initFields(exclusion, ExclusionType.LINE_NUMBERS); + } else if (exclusion.startsWith(ExclusionType.LOCAL_VARIABLES.getValue())) { + initFields(exclusion, ExclusionType.LOCAL_VARIABLES); + } else if (exclusion.startsWith(ExclusionType.NUMBER_OBFUSCATION.getValue())) { + initFields(exclusion, ExclusionType.NUMBER_OBFUSCATION); + } else if (exclusion.startsWith(ExclusionType.HIDE_CODE.getValue())) { + initFields(exclusion, ExclusionType.HIDE_CODE); + } else if (exclusion.startsWith(ExclusionType.CRASHER.getValue())) { + initFields(exclusion, ExclusionType.CRASHER); + } else if (exclusion.startsWith(ExclusionType.EXPIRATION.getValue())) { + initFields(exclusion, ExclusionType.EXPIRATION); + } else if (exclusion.startsWith(ExclusionType.OPTIMIZER.getValue())) { + initFields(exclusion, ExclusionType.OPTIMIZER); + } else if (exclusion.startsWith(ExclusionType.SHRINKER.getValue())) { + initFields(exclusion, ExclusionType.SHRINKER); + } else if (exclusion.startsWith(ExclusionType.SHUFFLER.getValue())) { + initFields(exclusion, ExclusionType.SHUFFLER); + } else if (exclusion.startsWith(ExclusionType.SOURCE_NAME.getValue())) { + initFields(exclusion, ExclusionType.SOURCE_NAME); + } else if (exclusion.startsWith(ExclusionType.SOURCE_DEBUG.getValue())) { + initFields(exclusion, ExclusionType.SOURCE_DEBUG); + } else if (exclusion.startsWith(ExclusionType.STRING_POOL.getValue())) { + initFields(exclusion, ExclusionType.STRING_POOL); + } else if (exclusion.startsWith(ExclusionType.RENAMER.getValue())) { + initFields(exclusion, ExclusionType.RENAMER); + } else { + this.exclusion = Pattern.compile(exclusion); + this.exclusionType = ExclusionType.GLOBAL; + } + } + + private void initFields(String exclusion, ExclusionType type) { + this.exclusion = Pattern.compile(exclusion.substring(type.getValue().length() + 2)); + this.exclusionType = type; + } + + public ExclusionType getExclusionType() { + return this.exclusionType; + } + + public boolean matches(String other) { + return this.exclusion.matcher(other).matches(); + } + + public Pattern getExclusion() { + return exclusion; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/exclusions/ExclusionManager.java b/Radon-Program/src/main/java/me/itzsomebody/radon/exclusions/ExclusionManager.java new file mode 100644 index 00000000..cd9a1e6d --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/exclusions/ExclusionManager.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.exclusions; + +import java.util.ArrayList; +import java.util.List; + +public class ExclusionManager { + private List exclusions = new ArrayList<>(); + + public List getExclusions() { + return this.exclusions; + } + + public void addExclusion(Exclusion exclusion) { + this.exclusions.add(exclusion); + } + + public boolean isExcluded(String pattern, ExclusionType type) { + for (Exclusion exclusion : this.exclusions) { + if ((exclusion.getExclusionType() == type || exclusion.getExclusionType() == ExclusionType.GLOBAL) && exclusion.matches(pattern)) { + return true; + } + } + + return false; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/exclusions/ExclusionType.java b/Radon-Program/src/main/java/me/itzsomebody/radon/exclusions/ExclusionType.java new file mode 100644 index 00000000..0bbc23e0 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/exclusions/ExclusionType.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.exclusions; + +public enum ExclusionType { + GLOBAL("Global"), + STRING_ENCRYPTION("StringEncryption"), + INVOKEDYNAMIC("InvokeDynamic"), + FLOW_OBFUSCATION("FlowObfuscation"), + LINE_NUMBERS("LineNumbers"), + LOCAL_VARIABLES("LocalVariables"), + NUMBER_OBFUSCATION("NumberObfuscation"), + HIDE_CODE("HideCode"), + CRASHER("Crasher"), + EXPIRATION("Expiration"), + OPTIMIZER("Optimizer"), + SHRINKER("Shrinker"), + SHUFFLER("Shuffler"), + SOURCE_NAME("SourceName"), + SOURCE_DEBUG("SourceDebug"), + STRING_POOL("StringPool"), + RENAMER("Renamer"); + + private String value; + + ExclusionType(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/Transformer.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/Transformer.java new file mode 100644 index 00000000..5d4e3d78 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/Transformer.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers; + +import java.util.Collection; +import java.util.Map; +import me.itzsomebody.radon.Radon; +import me.itzsomebody.radon.asm.ClassWrapper; +import me.itzsomebody.radon.asm.FieldWrapper; +import me.itzsomebody.radon.asm.MethodWrapper; +import me.itzsomebody.radon.exclusions.ExclusionType; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.commons.CodeSizeEvaluator; +import org.objectweb.asm.tree.MethodNode; + +public abstract class Transformer implements Opcodes { + protected Radon radon; + + public void init(Radon radon) { + this.radon = radon; + } + + protected boolean excluded(String str) { + return this.radon.sessionInfo.getExclusions().isExcluded(str, getExclusionType()); + } + + protected boolean excluded(ClassWrapper classWrapper) { + return this.excluded(classWrapper.originalName); + } + + protected boolean excluded(MethodWrapper methodWrapper) { + return this.excluded(methodWrapper.owner.originalName + '.' + methodWrapper.originalName + methodWrapper.originalDescription); + } + + protected boolean excluded(FieldWrapper fieldWrapper) { + return this.excluded(fieldWrapper.owner.originalName + '.' + fieldWrapper.originalName + '.' + fieldWrapper.originalDescription); + } + + protected int getSizeLeeway(MethodNode methodNode) { + CodeSizeEvaluator cse = new CodeSizeEvaluator(null); + methodNode.accept(cse); + // Max allowed method size is 65534 (https://docs.oracle.com/javase/specs/jvms/se10/html/jvms-4.html#jvms-4.7.3) + return (65534 - cse.getMaxSize()); + } + + protected boolean hasInstructions(MethodNode methodNode) { + return methodNode.instructions != null && methodNode.instructions.size() > 0; + } + + protected long tookThisLong(long from) { + return System.currentTimeMillis() - from; + } + + protected Map getClasses() { + return this.radon.classes; + } + + protected Collection getClassWrappers() { + return this.radon.classes.values(); + } + + protected Map getClassPath() { + return this.radon.classPath; + } + + protected Map getResources() { + return this.radon.resources; + } + + public abstract void transform(); + + public abstract String getName(); + + protected abstract ExclusionType getExclusionType(); +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/Crasher.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/Crasher.java new file mode 100644 index 00000000..60148334 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/Crasher.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.miscellaneous; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.RandomUtils; +import me.itzsomebody.radon.utils.StringUtils; +import org.objectweb.asm.tree.ClassNode; + +public class Crasher extends Transformer { + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + + this.getClassWrappers().parallelStream().filter(classWrapper -> excluded(classWrapper) && classWrapper.classNode.signature == null).forEach(classWrapper -> { + ClassNode classNode = classWrapper.classNode; + classNode.signature = StringUtils.randomSpacesString(RandomUtils.getRandomInt(10)); + counter.incrementAndGet(); + }); + + LoggerUtils.stdOut(String.format("Added %d crashers.", counter.get())); + } + + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.CRASHER; + } + + @Override + public String getName() { + return "Crasher"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/TrashClasses.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/TrashClasses.java new file mode 100644 index 00000000..36e0a898 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/TrashClasses.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.miscellaneous; + +import me.itzsomebody.radon.Main; +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.RandomUtils; +import me.itzsomebody.radon.utils.StringUtils; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Handle; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.IincInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +public class TrashClasses extends Transformer { + @Override + public void transform() { + for (int i = 0; i < this.radon.sessionInfo.getTrashClasses(); i++) { + ClassNode classNode = generateClass(); + ClassWriter cw = new ClassWriter(0); + cw.newUTF8("RADON" + Main.VERSION); + classNode.accept(cw); + + this.getResources().put(classNode.name, cw.toByteArray()); + } + + LoggerUtils.stdOut(String.format("Generated %d trash classes.", this.radon.sessionInfo.getTrashClasses())); + } + + private ClassNode generateClass() { + ClassNode classNode = createClass(StringUtils.randomClassName(this.getClasses().keySet())); + int methodsToGenerate = RandomUtils.getRandomInt(3) + 2; + + for (int i = 0; i < methodsToGenerate; i++) { + classNode.methods.add(methodGen()); + } + + return classNode; + } + + private ClassNode createClass(String className) { + ClassNode classNode = new ClassNode(); + classNode.visit(49, ACC_SUPER + ACC_PUBLIC, className, null, "java/lang/Object", null); + + MethodVisitor mv = classNode.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + + classNode.visitEnd(); + + return classNode; + } + + private MethodNode methodGen() { + String randDesc = descGen(); + MethodNode method = new MethodNode(ACC_STATIC + ACC_PRIVATE, StringUtils.randomSpacesString(8), randDesc, null, null); + int instructions = RandomUtils.getRandomInt(30) + 30; + + InsnList insns = new InsnList(); + + for (int i = 0; i < instructions; ++i) { + insns.add(junkInsns()); + } + + if (randDesc.endsWith(")Ljava/lang/String;") + || randDesc.endsWith(")Ljava/lang/Object;")) { + insns.add(new VarInsnNode(ALOAD, + RandomUtils.getRandomInt(30))); + insns.add(new InsnNode(ARETURN)); + } else if (randDesc.endsWith(")Z")) { + if (RandomUtils.getRandomInt(1) == 1) { + insns.add(new InsnNode(ICONST_0)); + } else { + insns.add(new InsnNode(ICONST_1)); + } + + insns.add(new InsnNode(IRETURN)); + } else if (randDesc.endsWith(")V")) { + insns.add(new InsnNode(RETURN)); + } + + method.instructions = insns; + return method; + } + + private String descGen() { + switch (RandomUtils.getRandomInt(7)) { + case 0: + return "(Ljava/lang/String;)Ljava/lang/String;"; + case 1: + return "(Ljava/lang/Object;)Ljava/lang/Object;"; + case 2: + return "(I)Z"; + case 3: + return "()V"; + case 4: + return "(B)V"; + case 5: + return "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"; + case 6: // False BSM lol + default: + return "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"; + } + } + + private static AbstractInsnNode junkInsns() { + int index = RandomUtils.getRandomInt(20); + switch (index) { + case 0: + return new MethodInsnNode(INVOKESTATIC, StringUtils.randomSpacesString(8), StringUtils.randomSpacesString(8), "(Ljava/lang/String;)V", false); + case 1: + return new FieldInsnNode(GETFIELD, StringUtils.randomSpacesString(8), StringUtils.randomSpacesString(8), "I"); + case 2: + return new InsnNode(RandomUtils.getRandomInt(16)); + case 3: + return new VarInsnNode(ALOAD, RandomUtils.getRandomInt(30)); + case 4: + return new IntInsnNode(BIPUSH, RandomUtils.getRandomInt(255)); + case 5: + return new IntInsnNode(SIPUSH, RandomUtils.getRandomInt(25565)); + case 6: + case 7: + case 8: + return new InsnNode(RandomUtils.getRandomInt(5)); + case 9: + return new LdcInsnNode(StringUtils.randomSpacesString(8)); + case 10: + return new IincInsnNode(RandomUtils.getRandomInt(16), RandomUtils.getRandomInt(16)); + case 11: + return new MethodInsnNode(INVOKESPECIAL, StringUtils.randomSpacesString(8), StringUtils.randomSpacesString(8), "()V", false); + case 12: + return new MethodInsnNode(INVOKEVIRTUAL, StringUtils.randomSpacesString(8), StringUtils.randomSpacesString(8), "(Ljava/lang/Object;)Ljava/lang/Object;", false); + case 13: + return new VarInsnNode(ILOAD, RandomUtils.getRandomInt(30)); + case 14: + return new InsnNode(ATHROW); + case 15: + return new MethodInsnNode(INVOKEINTERFACE, StringUtils.randomSpacesString(8), StringUtils.randomSpacesString(8), "(I)I", false); + case 16: + Handle handle = new Handle(6, StringUtils.randomSpacesString(8), StringUtils.randomSpacesString(8), StringUtils.randomSpacesString(8), false); + return new InvokeDynamicInsnNode(StringUtils.randomSpacesString(8), StringUtils.randomSpacesString(8), handle, RandomUtils.getRandomInt(5), RandomUtils.getRandomInt(5), RandomUtils.getRandomInt(5), RandomUtils.getRandomInt(5), RandomUtils.getRandomInt(5)); + case 17: + return new IntInsnNode(ANEWARRAY, RandomUtils.getRandomInt(30)); + case 18: + return new VarInsnNode(ASTORE, RandomUtils.getRandomInt(30)); + case 19: + default: + return new VarInsnNode(ISTORE, RandomUtils.getRandomInt(30)); + } + } + + @Override + protected ExclusionType getExclusionType() { + return null; + } + + @Override + public String getName() { + return null; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/expiration/Expiration.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/expiration/Expiration.java new file mode 100644 index 00000000..161ab522 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/expiration/Expiration.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.miscellaneous.expiration; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; +import me.itzsomebody.radon.utils.LoggerUtils; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.TypeInsnNode; + +public class Expiration extends Transformer { + private ExpirationSetup setup; + + public Expiration(ExpirationSetup setup) { + this.setup = setup; + } + + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + + getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> { + ClassNode classNode = classWrapper.classNode; + + classNode.methods.stream().filter(methodNode -> methodNode.name.equals("")).forEach(methodNode -> { + InsnList expirationCode = createExpiration(); + methodNode.instructions.insertBefore(methodNode.instructions.getFirst(), expirationCode); + counter.incrementAndGet(); + }); + }); + + LoggerUtils.stdOut(String.format("Added %d expiration code blocks.", counter.get())); + } + + private InsnList createExpiration() { + InsnList expiryCode = new InsnList(); + LabelNode injectedLabel = new LabelNode(new Label()); + + expiryCode.add(new TypeInsnNode(NEW, "java/util/Date")); + expiryCode.add(new InsnNode(DUP)); + expiryCode.add(new MethodInsnNode(INVOKESPECIAL, "java/util/Date", "", "()V", false)); + expiryCode.add(new TypeInsnNode(NEW, "java/util/Date")); + expiryCode.add(new InsnNode(DUP)); + expiryCode.add(new LdcInsnNode(this.setup.getExpires())); + expiryCode.add(new MethodInsnNode(INVOKESPECIAL, "java/util/Date", "", "(J)V", false)); + expiryCode.add(new MethodInsnNode(INVOKEVIRTUAL, "java/util/Date", "after", "(Ljava/util/Date;)Z", false)); + expiryCode.add(new JumpInsnNode(IFEQ, injectedLabel)); + expiryCode.add(new TypeInsnNode(NEW, "java/lang/Throwable")); + expiryCode.add(new InsnNode(DUP)); + expiryCode.add(new LdcInsnNode(this.setup.getMessage())); + if (this.setup.isInjectJOptionPane()) { + expiryCode.add(new InsnNode(DUP)); + expiryCode.add(new InsnNode(ACONST_NULL)); + expiryCode.add(new InsnNode(SWAP)); + expiryCode.add(new MethodInsnNode(INVOKESTATIC, "javax/swing/JOptionPane", "showMessageDialog", "(Ljava/awt/Component;Ljava/lang/Object;)V", false)); + } + expiryCode.add(new MethodInsnNode(INVOKESPECIAL, "java/lang/Throwable", "", "(Ljava/lang/String;)V", false)); + expiryCode.add(new InsnNode(ATHROW)); + expiryCode.add(injectedLabel); + + return expiryCode; + } + + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.EXPIRATION; + } + + @Override + public String getName() { + return "Expiration"; + } + + public ExpirationSetup getSetup() { + return setup; + } +} diff --git a/src/main/java/me/itzsomebody/radon/utils/MatchUtils.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/expiration/ExpirationSetup.java similarity index 52% rename from src/main/java/me/itzsomebody/radon/utils/MatchUtils.java rename to Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/expiration/ExpirationSetup.java index bf6b3452..d82bcc24 100644 --- a/src/main/java/me/itzsomebody/radon/utils/MatchUtils.java +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/expiration/ExpirationSetup.java @@ -15,24 +15,28 @@ * along with this program. If not, see */ -package me.itzsomebody.radon.utils; +package me.itzsomebody.radon.transformers.miscellaneous.expiration; -/** - * Custom-defined Regex rules. - * - * @author ItzSomebody - */ -public class MatchUtils { - /** - * Returns true/false based on if input is matched to this specific rule. - * - * @param pattern a {@link String} which is used as a pattern matching statement. - * This includes wildcard '*' support. - * @param string a {@link String} to try to match. - * @return true/false based on if input is matched to this specific rule. - */ - public static boolean isMatched(String pattern, String string) { - return (pattern.equals(string) || - (pattern.contains("*") && string.contains(pattern.split("\\*")[0]))); +public class ExpirationSetup { + private String message; + private long expires; + private boolean injectJOptionPane; + + public ExpirationSetup(String message, long expires, boolean injectJOptionPane) { + this.message = message; + this.expires = expires; + this.injectJOptionPane = injectJOptionPane; + } + + public String getMessage() { + return message; + } + + public long getExpires() { + return expires; + } + + public boolean isInjectJOptionPane() { + return injectJOptionPane; } } diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/watermarker/Watermarker.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/watermarker/Watermarker.java new file mode 100644 index 00000000..a8d47458 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/watermarker/Watermarker.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.miscellaneous.watermarker; + +import java.util.ArrayList; +import java.util.Stack; +import me.itzsomebody.radon.asm.ClassWrapper; +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; +import me.itzsomebody.radon.utils.BytecodeUtils; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.RandomUtils; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +public class Watermarker extends Transformer { + private WatermarkerSetup setup; + + public Watermarker(WatermarkerSetup setup) { + this.setup = setup; + } + + @Override + public void transform() { + ArrayList classWrappers = new ArrayList<>(this.getClassWrappers()); + + for (int i = 0; i < 3; i++) { // Two extra injections helps with reliability of watermark to be extracted + Stack watermark = cipheredWatermark(); + while (!watermark.isEmpty()) { + ClassWrapper classWrapper = classWrappers.get(RandomUtils.getRandomInt(classWrappers.size())); + + MethodNode methodNode = classWrapper.classNode.methods.get(RandomUtils.getRandomInt(classWrapper.classNode.methods.size())); + if (hasInstructions(methodNode)) { + methodNode.instructions.insertBefore(methodNode.instructions.getFirst(), createInstructions(watermark, methodNode)); + } + } + } + + LoggerUtils.stdOut("Successfully embedded watermark."); + } + + private static InsnList createInstructions(Stack watermark, MethodNode methodNode) { + int xorKey = RandomUtils.getRandomInt(); + int watermarkChar = watermark.pop() ^ xorKey; + int indexXorKey = RandomUtils.getRandomInt(); + int watermarkIndex = watermark.size() ^ indexXorKey; + + InsnList instructions = new InsnList(); + instructions.add(BytecodeUtils.getNumberInsn(xorKey)); + instructions.add(BytecodeUtils.getNumberInsn(watermarkChar)); + instructions.add(BytecodeUtils.getNumberInsn(indexXorKey)); + instructions.add(BytecodeUtils.getNumberInsn(watermarkIndex)); + instructions.add(new VarInsnNode(ISTORE, methodNode.localVariables.size() + 1)); // Local variable x where x is the max locals allowed in method can be the top of a long or double + instructions.add(new VarInsnNode(ISTORE, methodNode.localVariables.size() + 2)); + instructions.add(new VarInsnNode(ISTORE, methodNode.localVariables.size() + 3)); + instructions.add(new VarInsnNode(ISTORE, methodNode.localVariables.size() + 4)); + + return instructions; + } + + // Really weak cipher, lul. + private Stack cipheredWatermark() { + char[] messageChars = setup.getMessage().toCharArray(); + char[] keyChars = setup.getKey().toCharArray(); + Stack returnThis = new Stack<>(); + + for (int i = 0; i < messageChars.length; i++) { + returnThis.push((char) (messageChars[i] ^ keyChars[i % keyChars.length])); + } + + return returnThis; + } + + @Override + protected ExclusionType getExclusionType() { + return null; + } + + @Override + public String getName() { + return "Watermarker"; + } + + public WatermarkerSetup getSetup() { + return setup; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/watermarker/WatermarkerSetup.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/watermarker/WatermarkerSetup.java new file mode 100644 index 00000000..93c8a648 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/miscellaneous/watermarker/WatermarkerSetup.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.miscellaneous.watermarker; + +public class WatermarkerSetup { + private String message; + private String key; + + public WatermarkerSetup(String message, String key) { + this.message = message; + this.key = key; + } + + public String getMessage() { + return message; + } + + public String getKey() { + return key; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/flow/FlowObfuscation.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/flow/FlowObfuscation.java new file mode 100644 index 00000000..86c89032 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/flow/FlowObfuscation.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.flow; + +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; + +public abstract class FlowObfuscation extends Transformer { + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.FLOW_OBFUSCATION; + } + + public static FlowObfuscation getTransformerFromString(String s) { + switch (s.toLowerCase()) { + case "light": { + return new LightFlowObfuscation(); + } + case "normal": { + return new NormalFlowObfuscation(); + } + case "heavy": { + return new HeavyFlowObfuscation(); + } + default: { + throw new RuntimeException("Did not expect " + s + " as a flow obfuscation mode"); + } + } + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/flow/HeavyFlowObfuscation.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/flow/HeavyFlowObfuscation.java new file mode 100644 index 00000000..ca0ec896 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/flow/HeavyFlowObfuscation.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.flow; + +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.asm.StackEmulator; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.RandomUtils; +import me.itzsomebody.radon.utils.StringUtils; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LineNumberNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +public class HeavyFlowObfuscation extends NormalFlowObfuscation { + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> { + ClassNode classNode = classWrapper.classNode; + FieldNode field = new FieldNode(ACC_PUBLIC + ACC_STATIC + ACC_FINAL, StringUtils.randomSpacesString(RandomUtils.getRandomInt(10)), "Z", null, null); + + classNode.fields.add(field); + classWrapper.methods.parallelStream().filter(methodWrapper -> !excluded(methodWrapper) && hasInstructions(methodWrapper.methodNode)).forEach(methodWrapper -> { + MethodNode methodNode = methodWrapper.methodNode; + int leeway = getSizeLeeway(methodNode); + int varIndex = methodNode.maxLocals; + methodNode.maxLocals++; + AbstractInsnNode[] untouchedList = methodNode.instructions.toArray(); + LabelNode labelNode = exitLabel(methodNode); + boolean calledSuper = false; + Set emptyAt = new StackEmulator(methodNode, methodNode.instructions.getLast()).getEmptyAt(); + for (AbstractInsnNode insn : untouchedList) { + if (leeway < 10000) { + break; + } + if (methodNode.name.equals("")) { + if (insn instanceof MethodInsnNode) { + if (insn.getOpcode() == INVOKESPECIAL && insn.getPrevious() instanceof VarInsnNode && ((VarInsnNode) insn.getPrevious()).var == 0) { + calledSuper = true; + } + } + } + if (insn != methodNode.instructions.getFirst() && !(insn instanceof LineNumberNode)) { + if (methodNode.name.equals("") && !calledSuper) + continue; + if (emptyAt.contains(insn)) { // We need to make sure stack is empty before making jumps + methodNode.instructions.insertBefore(insn, new VarInsnNode(ILOAD, varIndex)); + methodNode.instructions.insertBefore(insn, new JumpInsnNode(IFNE, labelNode)); + leeway -= 5; + counter.incrementAndGet(); + } + } + if (insn.getOpcode() == GOTO) { + methodNode.instructions.insertBefore(insn, new VarInsnNode(ILOAD, varIndex)); + methodNode.instructions.insert(insn, new InsnNode(ATHROW)); + methodNode.instructions.insert(insn, new InsnNode(ACONST_NULL)); + methodNode.instructions.set(insn, new JumpInsnNode(IFEQ, ((JumpInsnNode) insn).label)); + leeway -= 7; + counter.incrementAndGet(); + } else if (insn.getOpcode() >= IFEQ && insn.getOpcode() <= IF_ICMPLE) { + methodNode.instructions.insert(insn, new JumpInsnNode(IFNE, ((JumpInsnNode) insn).label)); + methodNode.instructions.insert(insn, new VarInsnNode(ILOAD, varIndex)); + leeway -= 7; + counter.incrementAndGet(); + } + } + methodNode.instructions.insertBefore(methodNode.instructions.getFirst(), new VarInsnNode(ISTORE, varIndex)); + methodNode.instructions.insertBefore(methodNode.instructions.getFirst(), new FieldInsnNode(GETSTATIC, classNode.name, field.name, "Z")); + }); + }); + + LoggerUtils.stdOut(String.format("Added %d fake jump sequences", counter.get())); + } + + @Override + public String getName() { + return "Heavy flow obfuscation"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/flow/LightFlowObfuscation.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/flow/LightFlowObfuscation.java new file mode 100644 index 00000000..66a75c9b --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/flow/LightFlowObfuscation.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.flow; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.RandomUtils; +import me.itzsomebody.radon.utils.StringUtils; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class LightFlowObfuscation extends FlowObfuscation { + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> { + ClassNode classNode = classWrapper.classNode; + String fieldName = StringUtils.randomSpacesString(RandomUtils.getRandomInt(10)); + + classWrapper.methods.parallelStream().filter(methodWrapper -> !excluded(methodWrapper) && hasInstructions(methodWrapper.methodNode)).forEach(methodWrapper -> { + MethodNode methodNode = methodWrapper.methodNode; + int leeway = getSizeLeeway(methodNode); + + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (leeway < 10000) { + break; + } + + if (insn.getOpcode() == GOTO) { + methodNode.instructions.insertBefore(insn, new FieldInsnNode(GETSTATIC, classNode.name, fieldName, "Z")); + methodNode.instructions.insert(insn, new InsnNode(ATHROW)); + methodNode.instructions.insert(insn, new InsnNode(ACONST_NULL)); + methodNode.instructions.set(insn, new JumpInsnNode(IFEQ, ((JumpInsnNode) insn).label)); + leeway -= 7; + counter.incrementAndGet(); + } + } + }); + + classNode.fields.add(new FieldNode(ACC_PUBLIC + ACC_STATIC + ACC_FINAL, fieldName, "Z", null, true)); + }); + + LoggerUtils.stdOut(String.format("Added %d fake throw-null sequences", counter.get())); + } + + @Override + public String getName() { + return "Light flow obfuscation"; + } +} diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/flow/NormalFlowObfuscation.java similarity index 54% rename from src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java rename to Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/flow/NormalFlowObfuscation.java index f01e5bbe..06160919 100644 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/NormalFlowObfuscation.java +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/flow/NormalFlowObfuscation.java @@ -15,16 +15,17 @@ * along with this program. If not, see */ -package me.itzsomebody.radon.transformers.flow; +package me.itzsomebody.radon.transformers.obfuscators.flow; -import java.util.Stack; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.analyzer.StackAnalyzer; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.asm.StackEmulator; +import me.itzsomebody.radon.utils.BytecodeUtils; +import me.itzsomebody.radon.utils.RandomUtils; import me.itzsomebody.radon.utils.StringUtils; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.InsnNode; @@ -35,97 +36,68 @@ import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.VarInsnNode; -/** - * Transformer that does the same as {@link LightFlowObfuscation}, but also - * inserts conditionals which always evaluate to false where the stack is - * empty. - * - * @author ItzSomebody - */ -public class NormalFlowObfuscation extends LightFlowObfuscation { - /** - * Applies obfuscation. - */ - public void obfuscate() { +public class NormalFlowObfuscation extends FlowObfuscation { + @Override + public void transform() { AtomicInteger counter = new AtomicInteger(); long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started normal flow obfuscation transformer")); - classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { - FieldNode field = new FieldNode(ACC_PUBLIC + ACC_STATIC + - ACC_FINAL, StringUtils.randomString(this.dictionary, len), "Z", null, null); + + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> { + ClassNode classNode = classWrapper.classNode; + FieldNode field = new FieldNode(ACC_PUBLIC + ACC_STATIC + ACC_FINAL, StringUtils.randomSpacesString(RandomUtils.getRandomInt(10)), "Z", null, null); + classNode.fields.add(field); - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Flow") - && hasInstructions(methodNode)).forEach(methodNode -> { + classWrapper.methods.parallelStream().filter(methodWrapper -> !excluded(methodWrapper) && hasInstructions(methodWrapper.methodNode)).forEach(methodWrapper -> { + MethodNode methodNode = methodWrapper.methodNode; + int leeway = getSizeLeeway(methodNode); int varIndex = methodNode.maxLocals; methodNode.maxLocals++; - methodNode.owner = classNode.name; AbstractInsnNode[] untouchedList = methodNode.instructions.toArray(); LabelNode labelNode = exitLabel(methodNode); boolean calledSuper = false; + Set emptyAt = new StackEmulator(methodNode, methodNode.instructions.getLast()).getEmptyAt(); for (AbstractInsnNode insn : untouchedList) { - if (this.methodSize(methodNode) > 60000) break; + if (leeway < 10000) { + break; + } if (methodNode.name.equals("")) { if (insn instanceof MethodInsnNode) { - if (insn.getOpcode() == INVOKESPECIAL - && insn.getPrevious() instanceof VarInsnNode - && ((VarInsnNode) insn.getPrevious()).var == 0) { + if (insn.getOpcode() == INVOKESPECIAL && insn.getPrevious() instanceof VarInsnNode && ((VarInsnNode) insn.getPrevious()).var == 0) { calledSuper = true; } } } - if (insn != methodNode.instructions.getFirst() - && !(insn instanceof LineNumberNode)) { + if (insn != methodNode.instructions.getFirst() && !(insn instanceof LineNumberNode)) { if (methodNode.name.equals("") && !calledSuper) continue; - StackAnalyzer sa = new StackAnalyzer(methodNode, insn); - Stack stack = sa.returnStackAtBreak(); - if (stack.isEmpty()) { // We need to make sure stack is empty before making jumps + if (emptyAt.contains(insn)) { // We need to make sure stack is empty before making jumps methodNode.instructions.insertBefore(insn, new VarInsnNode(ILOAD, varIndex)); - methodNode.instructions.insertBefore(insn, - new JumpInsnNode(IFNE, labelNode)); + methodNode.instructions.insertBefore(insn, new JumpInsnNode(IFNE, labelNode)); + leeway -= 5; counter.incrementAndGet(); } } - if (insn instanceof JumpInsnNode) { - if (insn.getOpcode() == GOTO) { - methodNode.instructions.insertBefore(insn, - new VarInsnNode(ILOAD, varIndex)); - methodNode.instructions.insertBefore(insn, - new InsnNode(ICONST_0)); - methodNode.instructions.insert(insn, - new InsnNode(ATHROW)); - methodNode.instructions.insert(insn, - new InsnNode(ACONST_NULL)); - methodNode.instructions.set(insn, - new JumpInsnNode(IF_ICMPEQ, - ((JumpInsnNode) insn).label)); - counter.incrementAndGet(); - } + if (insn.getOpcode() == GOTO) { + methodNode.instructions.insertBefore(insn, new FieldInsnNode(GETSTATIC, classNode.name, field.name, "Z")); + methodNode.instructions.insert(insn, new InsnNode(ATHROW)); + methodNode.instructions.insert(insn, new InsnNode(ACONST_NULL)); + methodNode.instructions.set(insn, new JumpInsnNode(IFEQ, ((JumpInsnNode) insn).label)); + leeway -= 7; + counter.incrementAndGet(); } } - methodNode.instructions.insertBefore(methodNode.instructions - .getFirst(), new VarInsnNode(ISTORE, varIndex)); - methodNode.instructions.insertBefore(methodNode.instructions - .getFirst(), new FieldInsnNode(GETSTATIC, - classNode.name, field.name, "Z")); + methodNode.instructions.insertBefore(methodNode.instructions.getFirst(), new VarInsnNode(ISTORE, varIndex)); + methodNode.instructions.insertBefore(methodNode.instructions.getFirst(), new FieldInsnNode(GETSTATIC, classNode.name, field.name, "Z")); }); }); - this.logStrings.add(LoggerUtils.stdOut("Added " + counter + " instruction sets.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); } - /** - * Inserts an "exit" label into the start of the method node which is used - * by the transformer to branch the stack into a false jump. - * - * @param methodNode current {@link MethodNode} to insert an exit code - * block into. - * @return a {@link LabelNode} used to branch the stack with a false - * conditional. - */ - private LabelNode exitLabel(MethodNode methodNode) { + @Override + public String getName() { + return "Normal flow obfuscation"; + } + + LabelNode exitLabel(MethodNode methodNode) { LabelNode lb = new LabelNode(); LabelNode escapeNode = new LabelNode(); AbstractInsnNode target = methodNode.instructions.getFirst(); @@ -137,23 +109,31 @@ private LabelNode exitLabel(MethodNode methodNode) { methodNode.instructions.insertBefore(target, new InsnNode(RETURN)); break; case Type.BOOLEAN: + methodNode.instructions.insertBefore(target, BytecodeUtils.getNumberInsn(RandomUtils.getRandomInt(2))); + methodNode.instructions.insertBefore(target, new InsnNode(IRETURN)); case Type.CHAR: + methodNode.instructions.insertBefore(target, BytecodeUtils.getNumberInsn(RandomUtils.getRandomInt(Character.MAX_VALUE + 1))); + methodNode.instructions.insertBefore(target, new InsnNode(IRETURN)); case Type.BYTE: + methodNode.instructions.insertBefore(target, BytecodeUtils.getNumberInsn(RandomUtils.getRandomInt(Byte.MAX_VALUE + 1))); + methodNode.instructions.insertBefore(target, new InsnNode(IRETURN)); case Type.SHORT: + methodNode.instructions.insertBefore(target, BytecodeUtils.getNumberInsn(RandomUtils.getRandomInt(Short.MAX_VALUE + 1))); + methodNode.instructions.insertBefore(target, new InsnNode(IRETURN)); case Type.INT: - methodNode.instructions.insertBefore(target, new InsnNode(ICONST_0)); + methodNode.instructions.insertBefore(target, BytecodeUtils.getNumberInsn(RandomUtils.getRandomInt())); methodNode.instructions.insertBefore(target, new InsnNode(IRETURN)); break; case Type.LONG: - methodNode.instructions.insertBefore(target, new InsnNode(LCONST_0)); + methodNode.instructions.insertBefore(target, BytecodeUtils.getNumberInsn(RandomUtils.getRandomLong())); methodNode.instructions.insertBefore(target, new InsnNode(LRETURN)); break; case Type.FLOAT: - methodNode.instructions.insertBefore(target, new InsnNode(FCONST_0)); + methodNode.instructions.insertBefore(target, BytecodeUtils.getNumberInsn(RandomUtils.getRandomFloat())); methodNode.instructions.insertBefore(target, new InsnNode(FRETURN)); break; case Type.DOUBLE: - methodNode.instructions.insertBefore(target, new InsnNode(DCONST_0)); + methodNode.instructions.insertBefore(target, BytecodeUtils.getNumberInsn(RandomUtils.getRandomDouble())); methodNode.instructions.insertBefore(target, new InsnNode(DRETURN)); break; default: diff --git a/src/main/java/me/itzsomebody/radon/generate/InvokeDynamicBootstrapGenerator.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/HeavyInvokeDynamic.java similarity index 72% rename from src/main/java/me/itzsomebody/radon/generate/InvokeDynamicBootstrapGenerator.java rename to Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/HeavyInvokeDynamic.java index 5b207e09..d52878c2 100644 --- a/src/main/java/me/itzsomebody/radon/generate/InvokeDynamicBootstrapGenerator.java +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/HeavyInvokeDynamic.java @@ -15,17 +15,178 @@ * along with this program. If not, see */ -package me.itzsomebody.radon.generate; +package me.itzsomebody.radon.transformers.obfuscators.invokedynamic; -import me.itzsomebody.radon.transformers.invokedynamic.HeavyInvokeDynamic; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.asm.ClassWrapper; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.StringUtils; +import org.objectweb.asm.Handle; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TypeInsnNode; -public class InvokeDynamicBootstrapGenerator implements Opcodes { - public static ClassNode heavyBootstrap(HeavyInvokeDynamic.MemberNames memberNames) { +public class HeavyInvokeDynamic extends InvokeDynamic { + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + MemberNames memberNames = new MemberNames(); + ArrayList finals = new ArrayList<>(); + this.getClassPath().values().forEach(classWrapper -> { + ClassNode classNode = classWrapper.classNode; + + classNode.fields.stream().filter(fieldNode -> Modifier.isFinal(fieldNode.access)).forEach(fieldNode -> finals.add(classNode.name + '.' + fieldNode.name)); + }); + Handle bsmHandle = new Handle(H_INVOKESTATIC, memberNames.className, memberNames.bootstrapMethodName, "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false); + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper) && classWrapper.classNode.version >= V1_7).forEach(classWrapper -> { + ClassNode classNode = classWrapper.classNode; + + classWrapper.methods.parallelStream().filter(methodWrapper -> !excluded(methodWrapper) && hasInstructions(methodWrapper.methodNode)).forEach(methodWrapper -> { + MethodNode methodNode = methodWrapper.methodNode; + + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (insn instanceof MethodInsnNode) { + MethodInsnNode methodInsnNode = (MethodInsnNode) insn; + if (!methodInsnNode.name.equals("")) { + boolean isStatic = (methodInsnNode.getOpcode() == INVOKESTATIC); + String newSig = isStatic ? methodInsnNode.desc : methodInsnNode.desc.replace("(", "(Ljava/lang/Object;"); + Type returnType = Type.getReturnType(methodInsnNode.desc); + Type[] args = Type.getArgumentTypes(newSig); + for (int i = 0; i < args.length; i++) { + Type arg = args[i]; + if (arg.getSort() == Type.OBJECT) { + args[i] = Type.getType("Ljava/lang/Object;"); + } + } + newSig = Type.getMethodDescriptor(returnType, args); + StringBuilder sb = new StringBuilder(); + sb.append(methodInsnNode.owner.replace("/", ".")).append("<>").append(methodInsnNode.name).append("<>"); + + switch (insn.getOpcode()) { + case INVOKEINTERFACE: + case INVOKEVIRTUAL: { + sb.append("1<>").append(methodInsnNode.desc); + break; + } + case INVOKESPECIAL: { + sb.append("2<>").append(methodInsnNode.desc).append("<>").append(classNode.name.replace("/", ".")); + break; + } + case INVOKESTATIC: { + sb.append("0<>").append(methodInsnNode.desc); + break; + } + } + + InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode( + encrypt(sb.toString(), memberNames), + newSig, + bsmHandle + ); + + methodNode.instructions.set(insn, indy); + if (returnType.getSort() == Type.ARRAY) { + methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); + } + counter.incrementAndGet(); + } + } else if (insn instanceof FieldInsnNode) { + if (!methodNode.name.equals("")) { + FieldInsnNode fieldInsnNode = (FieldInsnNode) insn; + + if (finals.contains(fieldInsnNode.owner + '.' + fieldInsnNode.name)) { + continue; + } + + boolean isStatic = (fieldInsnNode.getOpcode() == GETSTATIC || fieldInsnNode.getOpcode() == PUTSTATIC); + boolean isSetter = (fieldInsnNode.getOpcode() == PUTFIELD || fieldInsnNode.getOpcode() == PUTSTATIC); + String newSig = (isSetter) ? "(" + fieldInsnNode.desc + ")V" : "()" + fieldInsnNode.desc; + if (!isStatic) + newSig = newSig.replace("(", "(Ljava/lang/Object;"); + + StringBuilder sb = new StringBuilder(); + sb.append(fieldInsnNode.owner.replace("/", ".")).append("<>").append(fieldInsnNode.name).append("<>"); + + switch (insn.getOpcode()) { + case GETSTATIC: { + sb.append("3"); + break; + } + case GETFIELD: { + sb.append("4"); + break; + } + case PUTSTATIC: { + sb.append("5"); + break; + } + case PUTFIELD: { + sb.append("6"); + break; + } + } + + InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode( + encrypt(sb.toString(), memberNames), + newSig, + bsmHandle + ); + + methodNode.instructions.set(insn, indy); + counter.incrementAndGet(); + } + } + } + }); + }); + + ClassNode decryptor = createBootstrap(memberNames); + this.getClasses().put(decryptor.name, new ClassWrapper(decryptor, false)); + LoggerUtils.stdOut(String.format("Hid %d field and/or method accesses with invokedynamics.", counter.get())); + } + + @Override + public String getName() { + return "Heavy invokedynamic"; + } + + private static String encrypt(String msg, MemberNames memberNames) { + char[] chars = msg.toCharArray(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < chars.length; i++) { + switch (i % 4) { + case 0: { + sb.append((char) (chars[i] ^ memberNames.className.replace("/", ".").hashCode())); + break; + } + case 1: { + sb.append((char) (chars[i] ^ memberNames.bootstrapMethodName.hashCode())); + break; + } + case 2: { + sb.append((char) (chars[i] ^ memberNames.className.replace("/", ".").hashCode())); + break; + } + case 3: { + sb.append((char) (chars[i] ^ memberNames.decryptorMethodName.hashCode())); + break; + } + } + } + + return sb.toString(); + } + + private static ClassNode createBootstrap(MemberNames memberNames) { ClassNode cw = new ClassNode(); MethodVisitor mv; @@ -495,4 +656,18 @@ public static ClassNode heavyBootstrap(HeavyInvokeDynamic.MemberNames memberName return cw; } + + private class MemberNames { + private String className; + private String decryptorMethodName; + private String bootstrapMethodName; + private String searchMethodName; + + private MemberNames() { + this.className = StringUtils.randomClassName(getClasses().keySet()); + this.decryptorMethodName = StringUtils.randomAlphaString(4); + this.bootstrapMethodName = StringUtils.randomAlphaString(4); + this.searchMethodName = StringUtils.randomAlphaString(4); + } + } } diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/InvokeDynamic.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/InvokeDynamic.java new file mode 100644 index 00000000..d26db6c6 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/InvokeDynamic.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.invokedynamic; + +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; + +public abstract class InvokeDynamic extends Transformer { + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.INVOKEDYNAMIC; + } + + public static InvokeDynamic getTransformerFromString(String s) { + switch (s.toLowerCase()) { + case "light": { + return new LightInvokeDynamic(); + } + case "normal": { + return new NormalInvokeDynamic(); + } + case "heavy": { + return new HeavyInvokeDynamic(); + } + default: { + throw new RuntimeException("Did not expect " + s + " as a invokedynamic obfuscation mode"); + } + } + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/LightInvokeDynamic.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/LightInvokeDynamic.java new file mode 100644 index 00000000..3a9bf874 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/LightInvokeDynamic.java @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.invokedynamic; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.utils.AccessUtils; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.StringUtils; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TypeInsnNode; + +public class LightInvokeDynamic extends InvokeDynamic { + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + String[] bsmPath = new String[]{StringUtils.randomClassName(getClasses().keySet()), StringUtils.randomAlphaString(4)}; + Handle bsmHandle = new Handle(Opcodes.H_INVOKESTATIC, bsmPath[0], bsmPath[1], "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false); + this.getClassWrappers().stream().filter(classWrapper -> !excluded(classWrapper) && classWrapper.classNode.version >= V1_7).forEach(classWrapper -> + classWrapper.methods.stream().filter(methodWrapper -> !excluded(methodWrapper) && hasInstructions(methodWrapper.methodNode)).forEach(methodWrapper -> { + MethodNode methodNode = methodWrapper.methodNode; + + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (insn instanceof MethodInsnNode && insn.getOpcode() != INVOKESPECIAL) { + MethodInsnNode methodInsnNode = (MethodInsnNode) insn; + boolean isStatic = (methodInsnNode.getOpcode() == Opcodes.INVOKESTATIC); + + String newSig = isStatic ? methodInsnNode.desc : methodInsnNode.desc.replace("(", "(Ljava/lang/Object;"); + Type returnType = Type.getReturnType(methodInsnNode.desc); + int opcode = (isStatic) ? 0 : 1; + + InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode(StringUtils.randomSpacesString(10), + newSig, + bsmHandle, + opcode, + encrypt(methodInsnNode.owner.replaceAll("/", "."), 1029), + encrypt(methodInsnNode.name, 2038), + encrypt(methodInsnNode.desc, 1928)); + methodNode.instructions.set(insn, indy); + if (returnType.getSort() == Type.ARRAY) { + methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); + } + counter.incrementAndGet(); + } + } + }) + ); + + ClassNode bsmHost = getClasses().get(bsmPath[0]).classNode; + bsmHost.methods.add(createBootstrap(bsmPath[1], bsmHost.name)); + bsmHost.access = AccessUtils.makePublic(bsmHost.access); + LoggerUtils.stdOut(String.format("Replaced %d method invocations with invokedynamics.", counter.get())); + } + + private static String encrypt(String msg, int key) { + char[] encClassNameChars = msg.toCharArray(); + char[] classNameChars = new char[encClassNameChars.length]; + for (int i = 0; i < encClassNameChars.length; i++) { + classNameChars[i] = (char) (encClassNameChars[i] ^ key); + } + + return new String(classNameChars); + } + + @Override + public String getName() { + return "Light invokedynamic"; + } + + private static MethodNode createBootstrap(String bsmName, String className) { + MethodNode mv = new MethodNode(ACC_PUBLIC + ACC_STATIC + ACC_SYNTHETIC + ACC_BRIDGE, bsmName, "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", null, null); + mv.visitCode(); + Label l0 = new Label(); + Label l1 = new Label(); + Label l2 = new Label(); + mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception"); + mv.visitLabel(l0); + mv.visitVarInsn(ALOAD, 4); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); + mv.visitVarInsn(ASTORE, 7); + Label l3 = new Label(); + mv.visitLabel(l3); + mv.visitVarInsn(ALOAD, 7); + mv.visitInsn(ARRAYLENGTH); + mv.visitIntInsn(NEWARRAY, T_CHAR); + mv.visitVarInsn(ASTORE, 8); + Label l4 = new Label(); + mv.visitLabel(l4); + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 9); + Label l5 = new Label(); + mv.visitLabel(l5); + Label l6 = new Label(); + mv.visitJumpInsn(GOTO, l6); + Label l7 = new Label(); + mv.visitLabel(l7); + mv.visitFrame(F_APPEND, 3, new Object[]{"[C", "[C", INTEGER}, 0, null); + mv.visitVarInsn(ALOAD, 8); + mv.visitVarInsn(ILOAD, 9); + mv.visitVarInsn(ALOAD, 7); + mv.visitVarInsn(ILOAD, 9); + mv.visitInsn(CALOAD); + mv.visitIntInsn(SIPUSH, 1029); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitInsn(CASTORE); + Label l8 = new Label(); + mv.visitLabel(l8); + mv.visitIincInsn(9, 1); + mv.visitLabel(l6); + mv.visitFrame(F_SAME, 0, null, 0, null); + mv.visitVarInsn(ILOAD, 9); + mv.visitVarInsn(ALOAD, 7); + mv.visitInsn(ARRAYLENGTH); + mv.visitJumpInsn(IF_ICMPLT, l7); + Label l9 = new Label(); + mv.visitLabel(l9); + mv.visitVarInsn(ALOAD, 5); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); + mv.visitVarInsn(ASTORE, 9); + Label l10 = new Label(); + mv.visitLabel(l10); + mv.visitVarInsn(ALOAD, 9); + mv.visitInsn(ARRAYLENGTH); + mv.visitIntInsn(NEWARRAY, T_CHAR); + mv.visitVarInsn(ASTORE, 10); + Label l11 = new Label(); + mv.visitLabel(l11); + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 11); + Label l12 = new Label(); + mv.visitLabel(l12); + Label l13 = new Label(); + mv.visitJumpInsn(GOTO, l13); + Label l14 = new Label(); + mv.visitLabel(l14); + mv.visitFrame(F_FULL, 12, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "[C", "[C", "[C", "[C", INTEGER}, 0, new Object[]{}); + mv.visitVarInsn(ALOAD, 10); + mv.visitVarInsn(ILOAD, 11); + mv.visitVarInsn(ALOAD, 9); + mv.visitVarInsn(ILOAD, 11); + mv.visitInsn(CALOAD); + mv.visitIntInsn(SIPUSH, 2038); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitInsn(CASTORE); + Label l15 = new Label(); + mv.visitLabel(l15); + mv.visitIincInsn(11, 1); + mv.visitLabel(l13); + mv.visitFrame(F_SAME, 0, null, 0, null); + mv.visitVarInsn(ILOAD, 11); + mv.visitVarInsn(ALOAD, 9); + mv.visitInsn(ARRAYLENGTH); + mv.visitJumpInsn(IF_ICMPLT, l14); + Label l16 = new Label(); + mv.visitLabel(l16); + mv.visitVarInsn(ALOAD, 6); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); + mv.visitVarInsn(ASTORE, 11); + Label l17 = new Label(); + mv.visitLabel(l17); + mv.visitVarInsn(ALOAD, 11); + mv.visitInsn(ARRAYLENGTH); + mv.visitIntInsn(NEWARRAY, T_CHAR); + mv.visitVarInsn(ASTORE, 12); + Label l18 = new Label(); + mv.visitLabel(l18); + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 13); + Label l19 = new Label(); + mv.visitLabel(l19); + Label l20 = new Label(); + mv.visitJumpInsn(GOTO, l20); + Label l21 = new Label(); + mv.visitLabel(l21); + mv.visitFrame(F_FULL, 14, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "[C", "[C", "[C", "[C", "[C", "[C", INTEGER}, 0, new Object[]{}); + mv.visitVarInsn(ALOAD, 12); + mv.visitVarInsn(ILOAD, 13); + mv.visitVarInsn(ALOAD, 11); + mv.visitVarInsn(ILOAD, 13); + mv.visitInsn(CALOAD); + mv.visitIntInsn(SIPUSH, 1928); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitInsn(CASTORE); + Label l22 = new Label(); + mv.visitLabel(l22); + mv.visitIincInsn(13, 1); + mv.visitLabel(l20); + mv.visitFrame(F_SAME, 0, null, 0, null); + mv.visitVarInsn(ILOAD, 13); + mv.visitVarInsn(ALOAD, 11); + mv.visitInsn(ARRAYLENGTH); + mv.visitJumpInsn(IF_ICMPLT, l21); + Label l23 = new Label(); + mv.visitLabel(l23); + mv.visitVarInsn(ALOAD, 3); + mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); + mv.visitVarInsn(ISTORE, 14); + Label l24 = new Label(); + mv.visitLabel(l24); + mv.visitVarInsn(ILOAD, 14); + Label l25 = new Label(); + Label l26 = new Label(); + Label l27 = new Label(); + mv.visitTableSwitchInsn(0, 1, l27, l25, l26); + mv.visitLabel(l25); + mv.visitFrame(F_FULL, 15, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "[C", "[C", "[C", "[C", "[C", "[C", TOP, INTEGER}, 0, new Object[]{}); + mv.visitVarInsn(ALOAD, 0); + mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); + mv.visitTypeInsn(NEW, "java/lang/String"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 8); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false); + mv.visitTypeInsn(NEW, "java/lang/String"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 10); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); + mv.visitTypeInsn(NEW, "java/lang/String"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 12); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); + mv.visitLdcInsn(Type.getType("L" + className + ";")); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "fromMethodDescriptorString", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStatic", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); + mv.visitVarInsn(ASTORE, 13); + Label l28 = new Label(); + mv.visitLabel(l28); + Label l29 = new Label(); + mv.visitJumpInsn(GOTO, l29); + mv.visitLabel(l26); + mv.visitFrame(F_SAME, 0, null, 0, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); + mv.visitTypeInsn(NEW, "java/lang/String"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 8); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false); + mv.visitTypeInsn(NEW, "java/lang/String"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 10); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); + mv.visitTypeInsn(NEW, "java/lang/String"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 12); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); + mv.visitLdcInsn(Type.getType("L" + className + ";")); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "fromMethodDescriptorString", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findVirtual", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); + mv.visitVarInsn(ASTORE, 13); + Label l30 = new Label(); + mv.visitLabel(l30); + mv.visitJumpInsn(GOTO, l29); + mv.visitLabel(l27); + mv.visitFrame(F_SAME, 0, null, 0, null); + mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", "", "()V", false); + mv.visitInsn(ATHROW); + mv.visitLabel(l29); + mv.visitFrame(F_FULL, 15, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "[C", "[C", "[C", "[C", "[C", "[C", "java/lang/invoke/MethodHandle", INTEGER}, 0, new Object[]{}); + mv.visitVarInsn(ALOAD, 13); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodType"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "asType", "(Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); + mv.visitVarInsn(ASTORE, 13); + Label l31 = new Label(); + mv.visitLabel(l31); + mv.visitTypeInsn(NEW, "java/lang/invoke/ConstantCallSite"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 13); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", "", "(Ljava/lang/invoke/MethodHandle;)V", false); + mv.visitLabel(l1); + mv.visitInsn(ARETURN); + mv.visitLabel(l2); + mv.visitFrame(F_FULL, 7, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object"}, 1, new Object[]{"java/lang/Exception"}); + mv.visitVarInsn(ASTORE, 7); + Label l32 = new Label(); + mv.visitLabel(l32); + mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", "", "()V", false); + mv.visitInsn(ATHROW); + Label l33 = new Label(); + mv.visitLabel(l33); + mv.visitMaxs(6, 15); + mv.visitEnd(); + + return mv; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/NormalInvokeDynamic.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/NormalInvokeDynamic.java new file mode 100644 index 00000000..f0bf368c --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/invokedynamic/NormalInvokeDynamic.java @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.invokedynamic; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.utils.AccessUtils; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.StringUtils; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TypeInsnNode; + +public class NormalInvokeDynamic extends InvokeDynamic { + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + String[] bsmPath = new String[]{StringUtils.randomClassName(getClasses().keySet()), StringUtils.randomAlphaString(4)}; + Handle bsmHandle = new Handle(Opcodes.H_INVOKESTATIC, bsmPath[0], bsmPath[1], "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false); + this.getClassWrappers().stream().filter(classWrapper -> !excluded(classWrapper) && classWrapper.classNode.version >= V1_7).forEach(classWrapper -> + classWrapper.methods.stream().filter(methodWrapper -> !excluded(methodWrapper) && hasInstructions(methodWrapper.methodNode)).forEach(methodWrapper -> { + MethodNode methodNode = methodWrapper.methodNode; + + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (insn instanceof MethodInsnNode && insn.getOpcode() != INVOKESPECIAL) { + MethodInsnNode methodInsnNode = (MethodInsnNode) insn; + boolean isStatic = (methodInsnNode.getOpcode() == Opcodes.INVOKESTATIC); + + String newSig = isStatic ? methodInsnNode.desc : methodInsnNode.desc.replace("(", "(Ljava/lang/Object;"); + Type returnType = Type.getReturnType(methodInsnNode.desc); + int opcode = (isStatic) ? 0 : 1; + + InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode(StringUtils.randomSpacesString(10), + newSig, + bsmHandle, + opcode, + encrypt(methodInsnNode.owner.replaceAll("/", "."), 2893), + encrypt(methodInsnNode.name, 2993), + encrypt(methodInsnNode.desc, 8372)); + methodNode.instructions.set(insn, indy); + if (returnType.getSort() == Type.ARRAY) { + methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); + } + counter.incrementAndGet(); + } + } + }) + ); + + ClassNode bsmHost = getClasses().get(bsmPath[0]).classNode; + bsmHost.methods.add(createBootstrap(bsmPath[1], bsmHost.name)); + bsmHost.access = AccessUtils.makePublic(bsmHost.access); + LoggerUtils.stdOut(String.format("Replaced %d method invocations with invokedynamics.", counter.get())); + } + + private static String encrypt(String msg, int key) { + char[] encClassNameChars = msg.toCharArray(); + char[] classNameChars = new char[encClassNameChars.length]; + for (int i = 0; i < encClassNameChars.length; i++) { + classNameChars[i] = (char) (encClassNameChars[i] ^ key); + } + + return new String(classNameChars); + } + + @Override + public String getName() { + return "Normal invokedynamic"; + } + + private static MethodNode createBootstrap(String bsmName, String className) { + MethodNode mv = new MethodNode(ACC_PUBLIC + ACC_STATIC + ACC_SYNTHETIC + ACC_BRIDGE, bsmName, "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", null, null); + mv.visitCode(); + Label l0 = new Label(); + Label l1 = new Label(); + Label l2 = new Label(); + mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable"); + Label l3 = new Label(); + Label l4 = new Label(); + Label l5 = new Label(); + mv.visitTryCatchBlock(l3, l4, l5, "java/lang/Exception"); + mv.visitLabel(l3); + mv.visitVarInsn(ALOAD, 4); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); + mv.visitVarInsn(ASTORE, 7); + Label l6 = new Label(); + mv.visitLabel(l6); + mv.visitVarInsn(ALOAD, 7); + mv.visitInsn(ARRAYLENGTH); + mv.visitIntInsn(NEWARRAY, T_CHAR); + mv.visitVarInsn(ASTORE, 8); + Label l7 = new Label(); + mv.visitLabel(l7); + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 9); + Label l8 = new Label(); + mv.visitLabel(l8); + Label l9 = new Label(); + mv.visitJumpInsn(GOTO, l9); + Label l10 = new Label(); + mv.visitLabel(l10); + mv.visitFrame(F_APPEND, 3, new Object[]{"[C", "[C", INTEGER}, 0, null); + mv.visitVarInsn(ALOAD, 8); + mv.visitVarInsn(ILOAD, 9); + mv.visitVarInsn(ALOAD, 7); + mv.visitVarInsn(ILOAD, 9); + mv.visitInsn(CALOAD); + mv.visitIntInsn(SIPUSH, 2893); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitInsn(CASTORE); + Label l11 = new Label(); + mv.visitLabel(l11); + mv.visitIincInsn(9, 1); + mv.visitLabel(l9); + mv.visitFrame(F_SAME, 0, null, 0, null); + mv.visitVarInsn(ILOAD, 9); + mv.visitVarInsn(ALOAD, 7); + mv.visitInsn(ARRAYLENGTH); + mv.visitJumpInsn(IF_ICMPLT, l10); + Label l12 = new Label(); + mv.visitLabel(l12); + mv.visitVarInsn(ALOAD, 5); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); + mv.visitVarInsn(ASTORE, 9); + Label l13 = new Label(); + mv.visitLabel(l13); + mv.visitVarInsn(ALOAD, 9); + mv.visitInsn(ARRAYLENGTH); + mv.visitIntInsn(NEWARRAY, T_CHAR); + mv.visitVarInsn(ASTORE, 10); + Label l14 = new Label(); + mv.visitLabel(l14); + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 11); + Label l15 = new Label(); + mv.visitLabel(l15); + Label l16 = new Label(); + mv.visitJumpInsn(GOTO, l16); + Label l17 = new Label(); + mv.visitLabel(l17); + mv.visitFrame(F_FULL, 12, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "[C", "[C", "[C", "[C", INTEGER}, 0, new Object[]{}); + mv.visitVarInsn(ALOAD, 10); + mv.visitVarInsn(ILOAD, 11); + mv.visitVarInsn(ALOAD, 9); + mv.visitVarInsn(ILOAD, 11); + mv.visitInsn(CALOAD); + mv.visitIntInsn(SIPUSH, 2993); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitInsn(CASTORE); + Label l18 = new Label(); + mv.visitLabel(l18); + mv.visitIincInsn(11, 1); + mv.visitLabel(l16); + mv.visitFrame(F_SAME, 0, null, 0, null); + mv.visitVarInsn(ILOAD, 11); + mv.visitVarInsn(ALOAD, 9); + mv.visitInsn(ARRAYLENGTH); + mv.visitJumpInsn(IF_ICMPLT, l17); + Label l19 = new Label(); + mv.visitLabel(l19); + mv.visitVarInsn(ALOAD, 6); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false); + mv.visitVarInsn(ASTORE, 11); + Label l20 = new Label(); + mv.visitLabel(l20); + mv.visitVarInsn(ALOAD, 11); + mv.visitInsn(ARRAYLENGTH); + mv.visitIntInsn(NEWARRAY, T_CHAR); + mv.visitVarInsn(ASTORE, 12); + Label l21 = new Label(); + mv.visitLabel(l21); + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 13); + Label l22 = new Label(); + mv.visitLabel(l22); + Label l23 = new Label(); + mv.visitJumpInsn(GOTO, l23); + Label l24 = new Label(); + mv.visitLabel(l24); + mv.visitFrame(F_FULL, 14, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "[C", "[C", "[C", "[C", "[C", "[C", INTEGER}, 0, new Object[]{}); + mv.visitVarInsn(ALOAD, 12); + mv.visitVarInsn(ILOAD, 13); + mv.visitVarInsn(ALOAD, 11); + mv.visitVarInsn(ILOAD, 13); + mv.visitInsn(CALOAD); + mv.visitIntInsn(SIPUSH, 8372); + mv.visitInsn(IXOR); + mv.visitInsn(I2C); + mv.visitInsn(CASTORE); + Label l25 = new Label(); + mv.visitLabel(l25); + mv.visitIincInsn(13, 1); + mv.visitLabel(l23); + mv.visitFrame(F_SAME, 0, null, 0, null); + mv.visitVarInsn(ILOAD, 13); + mv.visitVarInsn(ALOAD, 11); + mv.visitInsn(ARRAYLENGTH); + mv.visitJumpInsn(IF_ICMPLT, l24); + Label l26 = new Label(); + mv.visitLabel(l26); + mv.visitVarInsn(ALOAD, 3); + mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false); + mv.visitVarInsn(ISTORE, 14); + Label l27 = new Label(); + mv.visitLabel(l27); + mv.visitVarInsn(ILOAD, 14); + mv.visitIntInsn(SIPUSH, 256); + mv.visitInsn(ISHL); + mv.visitIntInsn(SIPUSH, 255); + mv.visitInsn(IAND); + mv.visitVarInsn(ISTORE, 14); + Label l28 = new Label(); + mv.visitLabel(l28); + mv.visitVarInsn(ILOAD, 14); + Label l29 = new Label(); + Label l30 = new Label(); + Label l31 = new Label(); + mv.visitTableSwitchInsn(0, 1, l31, l29, l30); + mv.visitLabel(l29); + mv.visitFrame(F_FULL, 15, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "[C", "[C", "[C", "[C", "[C", "[C", TOP, INTEGER}, 0, new Object[]{}); + mv.visitVarInsn(ALOAD, 0); + mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); + mv.visitTypeInsn(NEW, "java/lang/String"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 8); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false); + mv.visitTypeInsn(NEW, "java/lang/String"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 10); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); + mv.visitTypeInsn(NEW, "java/lang/String"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 12); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); + mv.visitLdcInsn(Type.getType("L" + className + ";")); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "fromMethodDescriptorString", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStatic", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); + mv.visitVarInsn(ASTORE, 13); + Label l32 = new Label(); + mv.visitLabel(l32); + Label l33 = new Label(); + mv.visitJumpInsn(GOTO, l33); + mv.visitLabel(l30); + mv.visitFrame(F_SAME, 0, null, 0, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); + mv.visitTypeInsn(NEW, "java/lang/String"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 8); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false); + mv.visitTypeInsn(NEW, "java/lang/String"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 10); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); + mv.visitTypeInsn(NEW, "java/lang/String"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 12); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", "([C)V", false); + mv.visitLdcInsn(Type.getType("L" + className + ";")); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "fromMethodDescriptorString", "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/invoke/MethodType;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findVirtual", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); + mv.visitVarInsn(ASTORE, 13); + Label l34 = new Label(); + mv.visitLabel(l34); + mv.visitJumpInsn(GOTO, l33); + mv.visitLabel(l31); + mv.visitFrame(F_SAME, 0, null, 0, null); + mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", "", "()V", false); + mv.visitInsn(ATHROW); + mv.visitLabel(l33); + mv.visitFrame(F_FULL, 15, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "[C", "[C", "[C", "[C", "[C", "[C", "java/lang/invoke/MethodHandle", INTEGER}, 0, new Object[]{}); + mv.visitVarInsn(ALOAD, 13); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodType"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "asType", "(Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); + mv.visitVarInsn(ASTORE, 13); + mv.visitLabel(l0); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Runtime", "getRuntime", "()Ljava/lang/Runtime;", false); + mv.visitMethodInsn(INVOKESTATIC, "java/util/concurrent/ThreadLocalRandom", "current", "()Ljava/util/concurrent/ThreadLocalRandom;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/concurrent/ThreadLocalRandom", "nextInt", "()I", false); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(I)Ljava/lang/String;", false); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Runtime", "exec", "(Ljava/lang/String;)Ljava/lang/Process;", false); + mv.visitInsn(POP); + mv.visitLabel(l1); + Label l35 = new Label(); + mv.visitJumpInsn(GOTO, l35); + mv.visitLabel(l2); + mv.visitFrame(F_SAME1, 0, null, 1, new Object[]{"java/lang/Throwable"}); + mv.visitVarInsn(ASTORE, 15); + mv.visitLabel(l35); + mv.visitFrame(F_SAME, 0, null, 0, null); + mv.visitTypeInsn(NEW, "java/lang/invoke/ConstantCallSite"); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 13); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", "", "(Ljava/lang/invoke/MethodHandle;)V", false); + mv.visitLabel(l4); + mv.visitInsn(ARETURN); + mv.visitLabel(l5); + mv.visitFrame(F_FULL, 7, new Object[]{"java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object", "java/lang/Object"}, 1, new Object[]{"java/lang/Exception"}); + mv.visitVarInsn(ASTORE, 7); + Label l36 = new Label(); + mv.visitLabel(l36); + mv.visitVarInsn(ALOAD, 7); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V", false); + Label l37 = new Label(); + mv.visitLabel(l37); + mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", "", "()V", false); + mv.visitInsn(ATHROW); + Label l38 = new Label(); + mv.visitLabel(l38); + mv.visitMaxs(6, 16); + mv.visitEnd(); + return mv; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/HideCode.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/HideCode.java new file mode 100644 index 00000000..435696c1 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/HideCode.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.miscellaneous; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; +import me.itzsomebody.radon.utils.AccessUtils; +import me.itzsomebody.radon.utils.BytecodeUtils; +import me.itzsomebody.radon.utils.LoggerUtils; +import org.objectweb.asm.tree.ClassNode; + +public class HideCode extends Transformer { + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> { + ClassNode classNode = classWrapper.classNode; + if (!AccessUtils.isSynthetic(classNode.access) && !BytecodeUtils.hasAnnotations(classNode)) { + classNode.access |= ACC_SYNTHETIC; + counter.incrementAndGet(); + } + + classNode.methods.parallelStream().filter(methodNode -> !BytecodeUtils.hasAnnotations(methodNode)).forEach(methodNode -> { + boolean hidOnce = false; + if (!AccessUtils.isSynthetic(methodNode.access)) { + methodNode.access |= ACC_SYNTHETIC; + hidOnce = true; + } + + if (!AccessUtils.isBridge(methodNode.access) && !methodNode.name.startsWith("<")) { + methodNode.access |= ACC_BRIDGE; + hidOnce = true; + } + + if (hidOnce) + counter.incrementAndGet(); + }); + + if (classNode.fields != null) + classNode.fields.parallelStream().filter(fieldNode -> !BytecodeUtils.hasAnnotations(fieldNode) + && !AccessUtils.isSynthetic(fieldNode.access)).forEach(fieldNode -> { + fieldNode.access |= ACC_SYNTHETIC; + counter.incrementAndGet(); + }); + }); + + LoggerUtils.stdOut(String.format("Hid %d members.", counter.get())); + } + + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.HIDE_CODE; + } + + @Override + public String getName() { + return "Hide code"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/LineNumbers.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/LineNumbers.java new file mode 100644 index 00000000..0b536e14 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/LineNumbers.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.miscellaneous; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; +import me.itzsomebody.radon.utils.RandomUtils; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.LineNumberNode; + +public class LineNumbers extends Transformer { + private boolean remove; + + public LineNumbers(boolean remove) { + this.remove = remove; + } + + public boolean isRemove() { + return remove; + } + + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> { + classWrapper.classNode.methods.parallelStream().filter(this::hasInstructions).forEach(methodNode -> { + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (insn instanceof LineNumberNode) { + if (remove) { + methodNode.instructions.remove(insn); + } else { + ((LineNumberNode) insn).line = RandomUtils.getRandomInt(); + } + + counter.incrementAndGet(); + } + } + }); + }); + } + + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.LINE_NUMBERS; + } + + @Override + public String getName() { + return "Line numbers"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/LocalVariables.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/LocalVariables.java new file mode 100644 index 00000000..317d7a4b --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/LocalVariables.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.miscellaneous; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.RandomUtils; +import me.itzsomebody.radon.utils.StringUtils; + +public class LocalVariables extends Transformer { + private boolean remove; + + public LocalVariables(boolean remove) { + this.remove = remove; + } + + public boolean isRemove() { + return remove; + } + + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> + classWrapper.classNode.methods.parallelStream().filter(methodNode -> methodNode.localVariables != null).forEach(methodNode -> { + counter.addAndGet(methodNode.localVariables.size()); + + if (remove) { + methodNode.localVariables = null; + } else { + methodNode.localVariables.forEach(localVariableNode -> { + localVariableNode.name = StringUtils.randomSpacesString(RandomUtils.getRandomInt(10)); + localVariableNode.desc = "L" + localVariableNode.name + ";"; + }); + } + }) + ); + + LoggerUtils.stdOut(String.format("Removed %d local variables.", counter.get())); + } + + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.LINE_NUMBERS; + } + + @Override + public String getName() { + return "Local variables"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/MemberShuffler.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/MemberShuffler.java new file mode 100644 index 00000000..2b1c8d0f --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/MemberShuffler.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.miscellaneous; + +import java.util.Collections; +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; +import me.itzsomebody.radon.utils.LoggerUtils; + +public class MemberShuffler extends Transformer { + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> { + Collections.shuffle(classWrapper.classNode.methods); + counter.addAndGet(classWrapper.classNode.methods.size()); + if (classWrapper.classNode.fields != null) { + Collections.shuffle(classWrapper.classNode.fields); + counter.addAndGet(classWrapper.classNode.fields.size()); + } + }); + + LoggerUtils.stdOut(String.format("Shuffled %d members.", counter.get())); + } + + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.SHUFFLER; + } + + @Override + public String getName() { + return "Member Shuffler"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/SourceDebug.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/SourceDebug.java new file mode 100644 index 00000000..0cc480ad --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/SourceDebug.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.miscellaneous; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.RandomUtils; +import me.itzsomebody.radon.utils.StringUtils; + +public class SourceDebug extends Transformer { + private boolean remove; + + public SourceDebug(boolean remove) { + this.remove = remove; + } + + public boolean isRemove() { + return remove; + } + + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + + String newName = (remove) ? null : StringUtils.randomSpacesString(RandomUtils.getRandomInt(10)) + ".java"; + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> { + classWrapper.classNode.sourceDebug = newName; + counter.incrementAndGet(); + }); + LoggerUtils.stdOut(String.format("Obfuscated %d source debug attributes.", counter.get())); + } + + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.SOURCE_NAME; + } + + @Override + public String getName() { + return "Source debug"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/SourceName.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/SourceName.java new file mode 100644 index 00000000..f4f17927 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/miscellaneous/SourceName.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.miscellaneous; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.RandomUtils; +import me.itzsomebody.radon.utils.StringUtils; + +public class SourceName extends Transformer { + private boolean remove; + + public SourceName(boolean remove) { + this.remove = remove; + } + + public boolean isRemove() { + return remove; + } + + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + + String newName = (remove) ? null : StringUtils.randomSpacesString(RandomUtils.getRandomInt(10)) + ".java"; + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> { + classWrapper.classNode.sourceFile = newName; + counter.incrementAndGet(); + }); + LoggerUtils.stdOut(String.format("Obfuscated %d source name attributes.", counter.get())); + } + + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.SOURCE_NAME; + } + + @Override + public String getName() { + return "Source name"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/HeavyNumberObfuscation.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/HeavyNumberObfuscation.java new file mode 100644 index 00000000..6b114622 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/HeavyNumberObfuscation.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.numbers; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.utils.BytecodeUtils; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.RandomUtils; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class HeavyNumberObfuscation extends NumberObfuscation { + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> + classWrapper.methods.parallelStream().filter(methodWrapper -> !excluded(methodWrapper) && hasInstructions(methodWrapper.methodNode)).forEach(methodWrapper -> { + MethodNode methodNode = methodWrapper.methodNode; + int leeway = getSizeLeeway(methodNode); + + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (leeway < 10000) + break; + if (BytecodeUtils.isIntInsn(insn)) { + int originalNum = BytecodeUtils.getIntNumber(insn); + int value1 = RandomUtils.getRandomInt(); + int value2 = originalNum ^ value1; + + InsnList insnList = new InsnList(); + insnList.add(BytecodeUtils.getNumberInsn(value1)); + insnList.add(new InsnNode(I2L)); + insnList.add(BytecodeUtils.getNumberInsn(value2)); + insnList.add(new InsnNode(I2L)); + insnList.add(new InsnNode(LXOR)); + insnList.add(new InsnNode(L2I)); + + methodNode.instructions.insertBefore(insn, insnList); + methodNode.instructions.remove(insn); + leeway -= 10; + counter.incrementAndGet(); + } else if (BytecodeUtils.isLongInsn(insn)) { + long originalNum = BytecodeUtils.getLongNumber(insn); + long value1 = RandomUtils.getRandomLong(); + long value2 = originalNum ^ value1; + + InsnList insnList = new InsnList(); + insnList.add(BytecodeUtils.getNumberInsn(RandomUtils.getRandomLong())); + insnList.add(BytecodeUtils.getNumberInsn(value1)); + insnList.add(new InsnNode(DUP2_X2)); + insnList.add(new InsnNode(POP2)); + insnList.add(new InsnNode(POP2)); + insnList.add(BytecodeUtils.getNumberInsn(value2)); + insnList.add(new InsnNode(LXOR)); + + methodNode.instructions.insertBefore(insn, insnList); + methodNode.instructions.remove(insn); + leeway -= 15; + counter.incrementAndGet(); + } + } + }) + ); + LoggerUtils.stdOut(String.format("Obfuscated %d numbers.", counter.get())); + } + + @Override + public String getName() { + return "Heavy number obfuscation"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/LightNumberObfuscation.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/LightNumberObfuscation.java new file mode 100644 index 00000000..1901a05c --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/LightNumberObfuscation.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.numbers; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.utils.BytecodeUtils; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.RandomUtils; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class LightNumberObfuscation extends NumberObfuscation { + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> + classWrapper.methods.parallelStream().filter(methodWrapper -> !excluded(methodWrapper) && hasInstructions(methodWrapper.methodNode)).forEach(methodWrapper -> { + MethodNode methodNode = methodWrapper.methodNode; + int leeway = getSizeLeeway(methodNode); + + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (leeway < 10000) + break; + if (BytecodeUtils.isIntInsn(insn)) { + int originalNum = BytecodeUtils.getIntNumber(insn); + int value1 = RandomUtils.getRandomInt(); + int value2 = originalNum ^ value1; + + InsnList insnList = new InsnList(); + insnList.add(BytecodeUtils.getNumberInsn(value1)); + insnList.add(BytecodeUtils.getNumberInsn(RandomUtils.getRandomInt())); + insnList.add(new InsnNode(SWAP)); + insnList.add(new InsnNode(DUP_X1)); + insnList.add(new InsnNode(POP2)); + insnList.add(BytecodeUtils.getNumberInsn(value2)); + insnList.add(new InsnNode(IXOR)); + + methodNode.instructions.insertBefore(insn, insnList); + methodNode.instructions.remove(insn); + leeway -= 10; + counter.incrementAndGet(); + } else if (BytecodeUtils.isLongInsn(insn)) { + long originalNum = BytecodeUtils.getLongNumber(insn); + long value1 = RandomUtils.getRandomLong(); + long value2 = originalNum ^ value1; + + InsnList insnList = new InsnList(); + insnList.add(BytecodeUtils.getNumberInsn(RandomUtils.getRandomLong())); + insnList.add(BytecodeUtils.getNumberInsn(value1)); + insnList.add(new InsnNode(DUP2_X2)); + insnList.add(new InsnNode(POP2)); + insnList.add(new InsnNode(POP2)); + insnList.add(BytecodeUtils.getNumberInsn(value2)); + insnList.add(new InsnNode(LXOR)); + + methodNode.instructions.insertBefore(insn, insnList); + methodNode.instructions.remove(insn); + leeway -= 15; + counter.incrementAndGet(); + } + } + }) + ); + LoggerUtils.stdOut(String.format("Split %d numbers into bitwise xor instructions.", counter.get())); + } + + @Override + public String getName() { + return "Light number obfuscation"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/NormalNumberObfuscation.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/NormalNumberObfuscation.java new file mode 100644 index 00000000..777610d8 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/NormalNumberObfuscation.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.numbers; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.utils.BytecodeUtils; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.RandomUtils; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class NormalNumberObfuscation extends NumberObfuscation { + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> + classWrapper.methods.parallelStream().filter(methodWrapper -> !excluded(methodWrapper) && hasInstructions(methodWrapper.methodNode)).forEach(methodWrapper -> { + MethodNode methodNode = methodWrapper.methodNode; + int leeway = getSizeLeeway(methodNode); + + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (leeway < 10000) + break; + if (BytecodeUtils.isIntInsn(insn)) { + int originalNum = BytecodeUtils.getIntNumber(insn); + switch (RandomUtils.getRandomInt(3)) { + case 0: { + int value1 = RandomUtils.getRandomInt(255) + 20; + int value2 = RandomUtils.getRandomInt(value1) + value1; + int value3 = originalNum - value1 + value2; // You kids say algebra is useless??? + InsnList insnList = new InsnList(); + insnList.add(BytecodeUtils.getNumberInsn(value1)); + insnList.add(BytecodeUtils.getNumberInsn(value2)); + insnList.add(new InsnNode(ISUB)); + insnList.add(BytecodeUtils.getNumberInsn(value3)); + insnList.add(new InsnNode(IADD)); + methodNode.instructions.insertBefore(insn, insnList); + methodNode.instructions.remove(insn); + leeway -= 8; + counter.incrementAndGet(); + break; + } + case 1: { + int value1 = RandomUtils.getRandomInt(255) + 20; + int value2 = RandomUtils.getRandomInt(value1) + value1; + int value3 = RandomUtils.getRandomInt(value2 + 1); + int value4 = originalNum - value1 + value2 - value3; // You kids say algebra is useless??? + InsnList insnList = new InsnList(); + insnList.add(BytecodeUtils.getNumberInsn(value1)); + insnList.add(BytecodeUtils.getNumberInsn(value2)); + insnList.add(new InsnNode(ISUB)); + insnList.add(BytecodeUtils.getNumberInsn(value3)); + insnList.add(new InsnNode(IADD)); + insnList.add(BytecodeUtils.getNumberInsn(value4)); + insnList.add(new InsnNode(IADD)); + methodNode.instructions.insertBefore(insn, insnList); + methodNode.instructions.remove(insn); + leeway -= 10; + counter.incrementAndGet(); + break; + } + case 2: { + int value1 = RandomUtils.getRandomInt(255) + 20; + int value2 = RandomUtils.getRandomInt(value1) + value1; + int value3 = RandomUtils.getRandomInt(value2 + 1); + int value4 = RandomUtils.getRandomInt(value3 + 1); + int value5 = originalNum - value1 + value2 - value3 + value4; // You kids say algebra is useless??? + InsnList insnList = new InsnList(); + insnList.add(BytecodeUtils.getNumberInsn(value1)); + insnList.add(BytecodeUtils.getNumberInsn(value2)); + insnList.add(new InsnNode(ISUB)); + insnList.add(BytecodeUtils.getNumberInsn(value3)); + insnList.add(new InsnNode(IADD)); + insnList.add(BytecodeUtils.getNumberInsn(value4)); + insnList.add(new InsnNode(ISUB)); + insnList.add(BytecodeUtils.getNumberInsn(value5)); + insnList.add(new InsnNode(IADD)); + methodNode.instructions.insertBefore(insn, insnList); + methodNode.instructions.remove(insn); + leeway -= 12; + counter.incrementAndGet(); + break; + } + } + } else if (BytecodeUtils.isLongInsn(insn)) { + long originalNum = BytecodeUtils.getLongNumber(insn); + switch (RandomUtils.getRandomInt(3)) { + case 0: { + long value1 = RandomUtils.getRandomLong(255) + 20; + long value2 = RandomUtils.getRandomLong(value1) + value1; + long value3 = originalNum - value1 + value2; // You kids say algebra is useless??? + InsnList insnList = new InsnList(); + insnList.add(BytecodeUtils.getNumberInsn(value1)); + insnList.add(BytecodeUtils.getNumberInsn(value2)); + insnList.add(new InsnNode(LSUB)); + insnList.add(BytecodeUtils.getNumberInsn(value3)); + insnList.add(new InsnNode(LADD)); + methodNode.instructions.insertBefore(insn, insnList); + methodNode.instructions.remove(insn); + leeway -= 15; + counter.incrementAndGet(); + break; + } + case 1: { + long value1 = RandomUtils.getRandomInt(255) + 20; + long value2 = RandomUtils.getRandomInt((int) value1) + value1; + long value3 = RandomUtils.getRandomInt((int) (value2 + 1)); + long value4 = originalNum - value1 + value2 - value3; // You kids say algebra is useless??? + InsnList insnList = new InsnList(); + insnList.add(BytecodeUtils.getNumberInsn(value1)); + insnList.add(BytecodeUtils.getNumberInsn(value2)); + insnList.add(new InsnNode(LSUB)); + insnList.add(BytecodeUtils.getNumberInsn(value3)); + insnList.add(new InsnNode(LADD)); + insnList.add(BytecodeUtils.getNumberInsn(value4)); + insnList.add(new InsnNode(LADD)); + methodNode.instructions.insertBefore(insn, insnList); + methodNode.instructions.remove(insn); + leeway -= 17; + counter.incrementAndGet(); + break; + } + case 2: { + long value1 = RandomUtils.getRandomInt(255) + 20; + long value2 = RandomUtils.getRandomInt((int) value1) + value1; + long value3 = RandomUtils.getRandomInt((int) (value2 + 1)); + long value4 = RandomUtils.getRandomInt((int) (value3 + 1)); + long value5 = originalNum - value1 + value2 - value3 + value4; // You kids say algebra is useless??? + InsnList insnList = new InsnList(); + insnList.add(BytecodeUtils.getNumberInsn(value1)); + insnList.add(BytecodeUtils.getNumberInsn(value2)); + insnList.add(new InsnNode(LSUB)); + insnList.add(BytecodeUtils.getNumberInsn(value3)); + insnList.add(new InsnNode(LADD)); + insnList.add(BytecodeUtils.getNumberInsn(value4)); + insnList.add(new InsnNode(LSUB)); + insnList.add(BytecodeUtils.getNumberInsn(value5)); + insnList.add(new InsnNode(LADD)); + methodNode.instructions.insertBefore(insn, insnList); + methodNode.instructions.remove(insn); + leeway -= 20; + counter.incrementAndGet(); + break; + } + } + } + } + }) + ); + LoggerUtils.stdOut(String.format("Split %d numbers into math instructions.", counter.get())); + } + + @Override + public String getName() { + return "Normal number obfuscation"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/NumberObfuscation.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/NumberObfuscation.java new file mode 100644 index 00000000..7495c0ee --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/numbers/NumberObfuscation.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.numbers; + +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; + +public abstract class NumberObfuscation extends Transformer { + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.NUMBER_OBFUSCATION; + } + + public static NumberObfuscation getTransformerFromString(String s) { + switch (s.toLowerCase()) { + case "light": { + return new LightNumberObfuscation(); + } + case "normal": { + return new NormalNumberObfuscation(); + } + case "heavy": { + return new HeavyNumberObfuscation(); + } + default: { + throw new RuntimeException("Did not expect " + s + " as a number obfuscation mode"); + } + } + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/renamer/Renamer.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/renamer/Renamer.java new file mode 100644 index 00000000..9a283461 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/renamer/Renamer.java @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.renamer; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Pattern; +import me.itzsomebody.radon.asm.ClassTree; +import me.itzsomebody.radon.asm.ClassWrapper; +import me.itzsomebody.radon.asm.FieldWrapper; +import me.itzsomebody.radon.asm.MemberRemapper; +import me.itzsomebody.radon.asm.MethodWrapper; +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; +import me.itzsomebody.radon.utils.AccessUtils; +import me.itzsomebody.radon.utils.IOUtils; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.StringUtils; +import org.objectweb.asm.commons.ClassRemapper; +import org.objectweb.asm.commons.Remapper; +import org.objectweb.asm.commons.SimpleRemapper; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.MethodNode; + +public class Renamer extends Transformer { + private RenamerSetup setup; + private HashMap mappings = new HashMap<>(); + + public Renamer(RenamerSetup setup) { + this.setup = setup; + } + + @Override + public void transform() { + LoggerUtils.stdOut("Generating mappings."); + long current = System.currentTimeMillis(); + AtomicInteger classCounter = new AtomicInteger(); + this.getClassWrappers().forEach(classWrapper -> { + classWrapper.methods.stream().filter(methodWrapper -> !AccessUtils.isNative(methodWrapper.methodNode.access) && !methodWrapper.methodNode.name.equals("main") && !methodWrapper.methodNode.name.equals("premain") && !methodWrapper.methodNode.name.startsWith("<")).forEach(methodWrapper -> { + if (canRenameMethodTree(new HashSet<>(), methodWrapper, classWrapper.originalName)) { + this.renameMethodTree(new HashSet<>(), methodWrapper, classWrapper.originalName, StringUtils.randomAlphaString(5)); + } + }); + + classWrapper.fields.forEach(fieldWrapper -> { + if (canRenameFieldTree(new HashSet<>(), fieldWrapper, classWrapper.originalName)) { + this.renameFieldTree(new HashSet<>(), fieldWrapper, classWrapper.originalName, StringUtils.randomAlphaString(5)); + } + }); + + if (!this.excluded(classWrapper)) { + this.mappings.put(classWrapper.originalName, (setup.getRepackageName() != null) ? setup.getRepackageName() + '/' + StringUtils.alphaString(classCounter.get()) : StringUtils.alphaString(classCounter.get())); + classCounter.incrementAndGet(); + } + }); + LoggerUtils.stdOut(String.format("Finished generated mappings. [%dms]", tookThisLong(current))); + LoggerUtils.stdOut("Applying mappings."); + current = System.currentTimeMillis(); + + // Apply mapping + Remapper simpleRemapper = new MemberRemapper(this.mappings); + for (ClassWrapper classWrapper : new ArrayList<>(this.getClassWrappers())) { + ClassNode classNode = classWrapper.classNode; + + ClassNode copy = new ClassNode(); + classNode.accept(new ClassRemapper(copy, simpleRemapper)); + copy.access = AccessUtils.makePublic(copy.access); + for (int i = 0; i < copy.methods.size(); i++) { + MethodNode methodNode = copy.methods.get(i); + methodNode.access = AccessUtils.makePublic(methodNode.access); + classWrapper.methods.get(i).methodNode = methodNode; + } + + if (copy.fields != null) { + for (int i = 0; i < copy.fields.size(); i++) { + FieldNode fieldNode = copy.fields.get(i); + fieldNode.access = AccessUtils.makePublic(fieldNode.access); + classWrapper.fields.get(i).fieldNode = fieldNode; + } + } + + classWrapper.classNode = copy; + this.getClasses().remove(classWrapper.originalName); + this.getClasses().put(classWrapper.classNode.name, classWrapper); + this.getClassPath().put(classWrapper.classNode.name, classWrapper); + } + + LoggerUtils.stdOut(String.format("Mapped %d members. [%dms]", mappings.size(), tookThisLong(current))); + current = System.currentTimeMillis(); + + // Fix screw ups in resources. + LoggerUtils.stdOut("Attempting to map class names in resources"); + AtomicInteger fixed = new AtomicInteger(); + getResources().forEach((name, byteArray) -> { + if (setup.getAdaptTheseResources() != null) { + for (String s : setup.getAdaptTheseResources()) { + Pattern pattern = Pattern.compile(s); + + if (pattern.matcher(name).matches()) { + String stringVer = new String(byteArray); + for (String mapping : mappings.keySet()) { + String original = mapping.replace("/", "."); + if (stringVer.contains(original)) { + // Regex that ensures that class names that match words in the manifest don't break the manifest + // Example: name == Main + if (name.equals("META-INF/MANIFEST.MF") || name.equals("plugin.yml") || name.equals("bungee.yml")) { + stringVer = stringVer.replaceAll("(?<=[: ])" + original, mappings.get(mapping).replace("/", ".")); + } else { + stringVer = stringVer.replace(original, mappings.get(mapping).replace("/", ".")); + } + } + } + + try { + getResources().put(name, stringVer.getBytes("UTF-8")); + fixed.incrementAndGet(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + throw new RuntimeException(e.getMessage()); + } + } + } + } + }); + LoggerUtils.stdOut(String.format("Mapped %d names in resources. [%dms]", fixed.get(), tookThisLong(current))); + dumpMappings(); + } + + private boolean canRenameMethodTree(HashSet visited, MethodWrapper methodWrapper, String owner) { + ClassTree tree = this.radon.getTree(owner); + if (!visited.contains(tree)) { + visited.add(tree); + if (mappings.containsKey(owner + '.' + methodWrapper.originalName + methodWrapper.originalDescription)) { + return true; + } + if (excluded(owner + '.' + methodWrapper.originalName + methodWrapper.originalDescription)) { + return false; + } + if (!methodWrapper.owner.originalName.equals(owner) && tree.classWrapper.libraryNode) { + for (MethodNode mn : tree.classWrapper.classNode.methods) { + if (mn.name.equals(methodWrapper.originalName) && mn.desc.equals(methodWrapper.originalDescription)) { + return false; + } + } + } + for (String parent : tree.parentClasses) { + if (parent != null && !canRenameMethodTree(visited, methodWrapper, parent)) { + return false; + } + } + for (String sub : tree.subClasses) { + if (sub != null && !canRenameMethodTree(visited, methodWrapper, sub)) { + return false; + } + } + } + + return true; + } + + private void renameMethodTree(HashSet visited, MethodWrapper MethodWrapper, String className, String newName) { + ClassTree tree = this.radon.getTree(className); + + if (!tree.classWrapper.libraryNode && !visited.contains(tree)) { + mappings.put(className + '.' + MethodWrapper.originalName + MethodWrapper.originalDescription, newName); + visited.add(tree); + for (String parentClass : tree.parentClasses) { + this.renameMethodTree(visited, MethodWrapper, parentClass, newName); + } + for (String subClass : tree.subClasses) { + this.renameMethodTree(visited, MethodWrapper, subClass, newName); + } + } + } + + private boolean canRenameFieldTree(HashSet visited, FieldWrapper fieldWrapper, String owner) { + ClassTree tree = this.radon.getTree(owner); + if (!visited.contains(tree)) { + visited.add(tree); + if (mappings.containsKey(owner + '.' + fieldWrapper.originalName + '.' + fieldWrapper.originalDescription)) { + return true; + } + if (excluded(owner + '.' + fieldWrapper.originalName + '.' + fieldWrapper.originalDescription)) { + return false; + } + if (!fieldWrapper.owner.originalName.equals(owner) && tree.classWrapper.libraryNode) { + for (FieldNode fn : tree.classWrapper.classNode.fields) { + if (fieldWrapper.originalName.equals(fn.name) && fieldWrapper.originalDescription.equals(fn.desc)) { + return false; + } + } + } + for (String parent : tree.parentClasses) { + if (parent != null && !canRenameFieldTree(visited, fieldWrapper, parent)) { + return false; + } + } + for (String sub : tree.subClasses) { + if (sub != null && !canRenameFieldTree(visited, fieldWrapper, sub)) { + return false; + } + } + } + + return true; + } + + private void renameFieldTree(HashSet visited, FieldWrapper fieldWrapper, String owner, String newName) { + ClassTree tree = this.radon.getTree(owner); + + if (!tree.classWrapper.libraryNode && !visited.contains(tree)) { + mappings.put(owner + '.' + fieldWrapper.originalName + '.' + fieldWrapper.originalDescription, newName); + visited.add(tree); + for (String parentClass : tree.parentClasses) { + this.renameFieldTree(visited, fieldWrapper, parentClass, newName); + } + for (String subClass : tree.subClasses) { + this.renameFieldTree(visited, fieldWrapper, subClass, newName); + } + } + } + + private void dumpMappings() { + long current = System.currentTimeMillis(); + LoggerUtils.stdOut("Dumping mappings."); + File file = new File("mappings.txt"); + if (file.exists()) { + IOUtils.renameExistingFile(file); + } + + try { + file.createNewFile(); + BufferedWriter bw = new BufferedWriter(new FileWriter(file)); + + mappings.forEach((oldName, newName) -> { + try { + bw.append(oldName).append(" -> ").append(newName).append('\n'); + } catch (IOException ioe) { + LoggerUtils.stdErr(String.format("Ran into an error trying to append \"%s -> %s\"", oldName, newName)); + ioe.printStackTrace(); + } + }); + + bw.close(); + LoggerUtils.stdOut(String.format("Finished dumping mappings at %s. [%dms]", file.getAbsolutePath(), tookThisLong(current))); + } catch (Throwable t) { + LoggerUtils.stdErr("Ran into an error trying to create the mappings file."); + t.printStackTrace(); + ; + } + } + + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.RENAMER; + } + + @Override + public String getName() { + return "Renamer"; + } + + public RenamerSetup getSetup() { + return setup; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/renamer/RenamerSetup.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/renamer/RenamerSetup.java new file mode 100644 index 00000000..9b3527a5 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/renamer/RenamerSetup.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.renamer; + +public class RenamerSetup { + private String[] adaptTheseResources; + private String repackageName; + + public RenamerSetup(String[] adaptTheseResources, String repackageName) { + this.adaptTheseResources = adaptTheseResources; + this.repackageName = repackageName; + } + + public String[] getAdaptTheseResources() { + return adaptTheseResources; + } + + public String getRepackageName() { + return repackageName; + } +} diff --git a/src/main/java/me/itzsomebody/radon/generate/StringDecryptorGenerator.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/HeavyStringEncryption.java similarity index 80% rename from src/main/java/me/itzsomebody/radon/generate/StringDecryptorGenerator.java rename to Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/HeavyStringEncryption.java index 00ee379a..b231ac74 100644 --- a/src/main/java/me/itzsomebody/radon/generate/StringDecryptorGenerator.java +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/HeavyStringEncryption.java @@ -15,18 +15,107 @@ * along with this program. If not, see */ -package me.itzsomebody.radon.generate; +package me.itzsomebody.radon.transformers.obfuscators.strings; -import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.asm.ClassWrapper; +import me.itzsomebody.radon.utils.BytecodeUtils; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.RandomUtils; +import me.itzsomebody.radon.utils.StringUtils; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; -public class StringDecryptorGenerator implements Opcodes { - public static ClassNode heavyStringDecryptor(HeavyStringEncryption.MemberNames memberNames) { +public class HeavyStringEncryption extends StringEncryption { + public HeavyStringEncryption(StringEncryptionSetup setup) { + super(setup); + } + + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + MemberNames memberNames = new MemberNames(); + + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> classWrapper.methods.parallelStream().filter(methodWrapper -> !excluded(methodWrapper) && hasInstructions(methodWrapper.methodNode)).forEach(methodWrapper -> { + MethodNode methodNode = methodWrapper.methodNode; + int leeway = getSizeLeeway(methodNode); + + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (leeway < 10000) { + break; + } + if (insn instanceof LdcInsnNode) { + LdcInsnNode ldc = (LdcInsnNode) insn; + if (ldc.cst instanceof String) { + String cst = (String) ldc.cst; + + if (!excludedString(cst)) { + int extraKey = RandomUtils.getRandomInt(); + int callerClassHC = classWrapper.classNode.name.replace("/", ".").hashCode(); + int callerMethodHC = methodNode.name.hashCode(); + int decryptorClassHC = memberNames.className.replace("/", ".").hashCode(); + int decryptorMethodHC = memberNames.decryptorMethodName.hashCode(); + ldc.cst = encrypt(cst, callerClassHC, callerMethodHC, decryptorClassHC, decryptorMethodHC, extraKey); + methodNode.instructions.insert(insn, new MethodInsnNode(INVOKESTATIC, memberNames.className, memberNames.decryptorMethodName, "(Ljava/lang/Object;I)Ljava/lang/String;", false)); + methodNode.instructions.insert(insn, new InsnNode(POP)); + methodNode.instructions.insert(insn, new InsnNode(DUP_X1)); + methodNode.instructions.insertBefore(insn, BytecodeUtils.getNumberInsn(extraKey)); + leeway -= 10; + counter.incrementAndGet(); + + } + } + } + } + })); + // Add decrypt method + ClassNode decryptor = createDecryptor(memberNames); + getClasses().put(decryptor.name, new ClassWrapper(decryptor, false)); + + LoggerUtils.stdOut(String.format("Encrypted %d strings.", counter.get())); + } + + @Override + public String getName() { + return "Heavy string encryption"; + } + + private static String encrypt(String msg, int callerClassHC, int callerMethodHC, int decryptorClassHC, int decryptorMethodHC, int extraKey) { + StringBuilder sb = new StringBuilder(); + char[] chars = msg.toCharArray(); + for (int i = 0; i < chars.length; i++) { + switch (i % 4) { + case 0: { + sb.append((char) (extraKey ^ callerClassHC ^ chars[i])); + break; + } + case 1: { + sb.append((char) (extraKey ^ callerMethodHC ^ chars[i])); + break; + } + case 2: { + sb.append((char) (extraKey ^ decryptorClassHC ^ chars[i])); + break; + } + case 3: { + sb.append((char) (extraKey ^ decryptorMethodHC ^ chars[i])); + break; + } + } + } + + return sb.toString(); + } + + private static ClassNode createDecryptor(MemberNames memberNames) { ClassNode cw = new ClassNode(); FieldVisitor fv; MethodVisitor mv; @@ -226,7 +315,7 @@ public static ClassNode heavyStringDecryptor(HeavyStringEncryption.MemberNames m mv.visitEnd(); } { - mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, memberNames.createInfoMethodName, "()V", null, new String[] { "java/lang/InterruptedException" }); + mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC, memberNames.createInfoMethodName, "()V", null, new String[]{"java/lang/InterruptedException"}); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); @@ -360,7 +449,7 @@ public static ClassNode heavyStringDecryptor(HeavyStringEncryption.MemberNames m Label l16 = new Label(); Label l17 = new Label(); Label l18 = new Label(); - mv.visitTableSwitchInsn(0, 3, l1, new Label[] { l15, l16, l17, l18 }); + mv.visitTableSwitchInsn(0, 3, l1, l15, l16, l17, l18); mv.visitLabel(l15); mv.visitVarInsn(ALOAD, 5); mv.visitVarInsn(ALOAD, 4); @@ -493,4 +582,28 @@ public static ClassNode heavyStringDecryptor(HeavyStringEncryption.MemberNames m return cw; } + + private class MemberNames { + private String className; + private String infoFieldName; + private String cacheFieldName; + private String populateMethodName; + private String createInfoMethodName; + private String setCacheMethodName; + private String getCacheMethodName; + private String cacheContainsMethodName; + private String decryptorMethodName; + + private MemberNames() { + this.className = StringUtils.randomClassName(getClasses().keySet()); + this.infoFieldName = StringUtils.randomAlphaString(4); + this.cacheFieldName = StringUtils.randomAlphaString(4); + this.populateMethodName = StringUtils.randomAlphaString(4); + this.createInfoMethodName = StringUtils.randomAlphaString(4); + this.setCacheMethodName = StringUtils.randomAlphaString(4); + this.getCacheMethodName = StringUtils.randomAlphaString(4); + this.cacheContainsMethodName = StringUtils.randomAlphaString(4); + this.decryptorMethodName = StringUtils.randomAlphaString(4); + } + } } diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/LightStringEncryption.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/LightStringEncryption.java new file mode 100644 index 00000000..c539524d --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/LightStringEncryption.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.strings; + +// TODO: Make it, looool. +public class LightStringEncryption extends StringEncryption { + public LightStringEncryption(StringEncryptionSetup setup) { + super(setup); + } + + @Override + public void transform() { + + } + + @Override + public String getName() { + return "Light string encryption"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/NormalStringEncryption.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/NormalStringEncryption.java new file mode 100644 index 00000000..052ea6e8 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/NormalStringEncryption.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.strings; + +// TODO: Make it, looool. +public class NormalStringEncryption extends StringEncryption { + public NormalStringEncryption(StringEncryptionSetup setup) { + super(setup); + } + + @Override + public void transform() { + + } + + @Override + public String getName() { + return "Normal string encryption"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/StringEncryption.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/StringEncryption.java new file mode 100644 index 00000000..9a14a84a --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/StringEncryption.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.strings; + +import java.util.List; +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; + +public abstract class StringEncryption extends Transformer { + protected StringEncryptionSetup setup; + + public StringEncryption(StringEncryptionSetup setup) { + this.setup = setup; + } + + protected boolean excludedString(String str) { + for (String s : this.setup.getExemptedStrings()) { + if (str.contains(s)) { + return true; + } + } + + return false; + } + + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.STRING_ENCRYPTION; + } + + public List getExcludedStrings() { + return this.setup.getExemptedStrings(); + } + + public static StringEncryption getTransformerFromString(String s, StringEncryptionSetup setup) { + switch (s.toLowerCase()) { + case "light": { + return new LightStringEncryption(setup); + } + case "normal": { + return new NormalStringEncryption(setup); + } + case "heavy": { + return new HeavyStringEncryption(setup); + } + default: { + throw new RuntimeException("Did not expect " + s + " as a string obfuscation mode"); + } + } + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/StringEncryptionSetup.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/StringEncryptionSetup.java new file mode 100644 index 00000000..af255280 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/StringEncryptionSetup.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.strings; + +import java.util.List; + +public class StringEncryptionSetup { + private final List exemptedStrings; + + public StringEncryptionSetup(List exemptedStrings) { + this.exemptedStrings = exemptedStrings; + } + + public List getExemptedStrings() { + return this.exemptedStrings; + } +} \ No newline at end of file diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/StringPool.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/StringPool.java new file mode 100644 index 00000000..3a7d6c28 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/obfuscators/strings/StringPool.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.obfuscators.strings; + +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.utils.BytecodeUtils; +import me.itzsomebody.radon.utils.LoggerUtils; +import me.itzsomebody.radon.utils.StringUtils; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class StringPool extends StringEncryption { + public StringPool(StringEncryptionSetup setup) { + super(setup); + } + + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> { + ArrayList strList = new ArrayList<>(); + String methodName = StringUtils.randomAlphaString(4); + String fieldName = StringUtils.randomAlphaString(4); + + classWrapper.methods.parallelStream().filter(methodWrapper -> !excluded(methodWrapper) && hasInstructions(methodWrapper.methodNode)).forEach(methodWrapper -> { + MethodNode methodNode = methodWrapper.methodNode; + + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (insn instanceof LdcInsnNode) { + Object cst = ((LdcInsnNode) insn).cst; + + if (cst instanceof String) { + String str = (String) cst; + + if (!excludedString(str)) { + strList.add(str); + + int indexNumber = strList.size() - 1; + + methodNode.instructions.insertBefore(insn, new FieldInsnNode(GETSTATIC, classWrapper.classNode.name, fieldName, "[Ljava/lang/String;")); + methodNode.instructions.insertBefore(insn, BytecodeUtils.getNumberInsn(indexNumber)); + methodNode.instructions.set(insn, new InsnNode(AALOAD)); + counter.incrementAndGet(); + } + } + } + } + }); + + if (strList.size() != 0) { + classWrapper.classNode.methods.add(stringPool(classWrapper.classNode.name, methodName, fieldName, strList)); + + MethodNode clinit = classWrapper.classNode.methods.stream().filter(methodNode -> methodNode.name.equals("")).findFirst().orElse(null); + if (clinit == null) { + clinit = new MethodNode(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "", "()V", null, null); + InsnList insns = new InsnList(); + insns.add(new MethodInsnNode(INVOKESTATIC, classWrapper.classNode.name, methodName, "()V", false)); + insns.add(new InsnNode(RETURN)); + clinit.instructions = insns; + classWrapper.classNode.methods.add(clinit); + } else { + clinit.instructions.insertBefore(clinit.instructions.getFirst(), new MethodInsnNode(INVOKESTATIC, classWrapper.classNode.name, methodName, "()V", false)); + } + FieldNode fieldNode = new FieldNode(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, fieldName, "[Ljava/lang/String;", null, null); + if (classWrapper.classNode.fields == null) + classWrapper.classNode.fields = new ArrayList<>(); + classWrapper.classNode.fields.add(fieldNode); + } + }); + LoggerUtils.stdOut(String.format("Pooled %d strings.", counter.get())); + } + + private MethodNode stringPool(String className, String methodName, String fieldName, ArrayList strings) { + MethodNode method = new MethodNode(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC + ACC_BRIDGE, methodName, "()V", null, null); + + method.visitCode(); + int numberOfStrings = strings.size(); + if (numberOfStrings <= 5) { + method.visitInsn(numberOfStrings + 3); + } else if (numberOfStrings <= 127) { + method.visitIntInsn(BIPUSH, strings.size()); + } else if (numberOfStrings <= 32767) { + method.visitIntInsn(SIPUSH, strings.size()); + } else { + method.visitLdcInsn(strings.size()); + } + + method.visitTypeInsn(ANEWARRAY, "java/lang/String"); + + for (int i = 0; i < strings.size(); i++) { + method.visitInsn(DUP); + + if (i <= 5) { + method.visitInsn(i + 3); + } else if (i <= 127) { + method.visitIntInsn(BIPUSH, i); + } else if (i <= 32767) { + method.visitIntInsn(SIPUSH, i); + } else { + method.visitLdcInsn(i); + } + + method.visitLdcInsn(strings.get(i)); + method.visitInsn(AASTORE); + } + method.visitFieldInsn(PUTSTATIC, className, fieldName, "[Ljava/lang/String;"); + method.visitInsn(RETURN); + method.visitMaxs(3, 0); + method.visitEnd(); + + return method; + } + + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.STRING_POOL; + } + + @Override + public String getName() { + return "String pool"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/GotoGotoRemover.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/GotoGotoRemover.java new file mode 100644 index 00000000..5094d2e9 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/GotoGotoRemover.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.optimizers; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.utils.LoggerUtils; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class GotoGotoRemover extends Optimizer { + @Override + public void transform() { + AtomicInteger count = new AtomicInteger(); + long current = System.currentTimeMillis(); + + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> + classWrapper.methods.parallelStream().filter(methodWrapper -> !excluded(methodWrapper) && hasInstructions(methodWrapper.methodNode)).forEach(methodWrapper -> { + MethodNode methodNode = methodWrapper.methodNode; + + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (insn.getOpcode() == GOTO) { + JumpInsnNode gotoJump = (JumpInsnNode) insn; + AbstractInsnNode insnAfterTarget = gotoJump.label.getNext(); + if (insnAfterTarget != null && insnAfterTarget.getOpcode() == GOTO) { + JumpInsnNode secGoto = (JumpInsnNode) insnAfterTarget; + gotoJump.label = secGoto.label; + count.incrementAndGet(); + } + } + } + }) + ); + + LoggerUtils.stdOut(String.format("Normalized %d GOTO->GOTO sequences. [%dms]", count.get(), tookThisLong(current))); + } + + @Override + public String getName() { + return "GOTO->GOTO Remover"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/GotoReturnRemover.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/GotoReturnRemover.java new file mode 100644 index 00000000..f255dda2 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/GotoReturnRemover.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.optimizers; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.utils.BytecodeUtils; +import me.itzsomebody.radon.utils.LoggerUtils; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class GotoReturnRemover extends Optimizer { + @Override + public void transform() { + AtomicInteger count = new AtomicInteger(); + long current = System.currentTimeMillis(); + + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> + classWrapper.methods.parallelStream().filter(methodWrapper -> !excluded(methodWrapper) && hasInstructions(methodWrapper.methodNode)).forEach(methodWrapper -> { + MethodNode methodNode = methodWrapper.methodNode; + + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (insn.getOpcode() == GOTO) { + JumpInsnNode gotoJump = (JumpInsnNode) insn; + AbstractInsnNode insnAfterTarget = gotoJump.label.getNext(); + if (insnAfterTarget != null && BytecodeUtils.isReturn(insnAfterTarget.getOpcode())) { + methodNode.instructions.set(insn, new InsnNode(insnAfterTarget.getOpcode())); + count.incrementAndGet(); + } + } + } + }) + ); + + LoggerUtils.stdOut(String.format("Normalized %d GOTO->RETURN sequences. [%dms]", count.get(), tookThisLong(current))); + } + + @Override + public String getName() { + return "GOTO->Return Remover"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/NopRemover.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/NopRemover.java new file mode 100644 index 00000000..9bb00101 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/NopRemover.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.optimizers; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.utils.LoggerUtils; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class NopRemover extends Optimizer { + @Override + public void transform() { + AtomicInteger count = new AtomicInteger(); + long current = System.currentTimeMillis(); + + this.getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> + classWrapper.methods.parallelStream().filter(methodWrapper -> !excluded(methodWrapper) && hasInstructions(methodWrapper.methodNode)).forEach(methodWrapper -> { + MethodNode methodNode = methodWrapper.methodNode; + + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (insn.getOpcode() == NOP) { + methodNode.instructions.remove(insn); + } + } + }) + ); + + LoggerUtils.stdOut(String.format("Removed %d NOP instructions. [%dms]", count.get(), tookThisLong(current))); + } + + @Override + public String getName() { + return "NOP Remover"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/Optimizer.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/Optimizer.java new file mode 100644 index 00000000..3aa72a84 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/Optimizer.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.optimizers; + +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; + +public abstract class Optimizer extends Transformer { + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.OPTIMIZER; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/OptimizerDelegator.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/OptimizerDelegator.java new file mode 100644 index 00000000..96ef08ed --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/OptimizerDelegator.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.optimizers; + +public class OptimizerDelegator extends Optimizer { + private OptimizerSetup setup; + + public OptimizerDelegator(OptimizerSetup setup) { + this.setup = setup; + } + + @Override + public void transform() { + if (this.setup.isNopRemoverEnabled()) { + NopRemover nopRemover = new NopRemover(); + nopRemover.init(this.radon); + nopRemover.transform(); + } + if (this.setup.isGotoGotoEnabled()) { + GotoGotoRemover gotoGotoRemover = new GotoGotoRemover(); + gotoGotoRemover.init(this.radon); + gotoGotoRemover.transform(); + } + if (this.setup.isGotoReturnEnabled()) { + GotoReturnRemover gotoReturnRemover = new GotoReturnRemover(); + gotoReturnRemover.init(this.radon); + gotoReturnRemover.transform(); + } + } + + @Override + public String getName() { + return "Optimizer"; + } + + public OptimizerSetup getSetup() { + return setup; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/OptimizerSetup.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/OptimizerSetup.java new file mode 100644 index 00000000..de12bc96 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/optimizers/OptimizerSetup.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.optimizers; + +public class OptimizerSetup { + private boolean nopRemoverEnabled; + private boolean gotoGotoEnabled; + private boolean gotoReturnEnabled; + + public OptimizerSetup(boolean nopRemoverEnabled, boolean gotoGotoEnabled, boolean gotoReturnEnabled) { + this.nopRemoverEnabled = nopRemoverEnabled; + this.gotoGotoEnabled = gotoGotoEnabled; + this.gotoReturnEnabled = gotoReturnEnabled; + } + + public boolean isNopRemoverEnabled() { + return this.nopRemoverEnabled; + } + + public boolean isGotoGotoEnabled() { + return this.gotoGotoEnabled; + } + + public boolean isGotoReturnEnabled() { + return this.gotoReturnEnabled; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/AttributesRemover.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/AttributesRemover.java new file mode 100644 index 00000000..e6c920d9 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/AttributesRemover.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.shrinkers; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.utils.LoggerUtils; +import org.objectweb.asm.tree.ClassNode; + +public class AttributesRemover extends Shrinker { + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + + getClassWrappers().parallelStream().filter(classWrapper -> excluded(classWrapper) && classWrapper.classNode.attrs != null).forEach(classWrapper -> { + ClassNode classNode = classWrapper.classNode; + + counter.addAndGet(classNode.attrs.size()); + classNode.attrs.clear(); + }); + + LoggerUtils.stdOut(String.format("Removed %d attributes.", counter.get())); + } + + @Override + public String getName() { + return "Attributes Remover"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/DebugInfoRemover.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/DebugInfoRemover.java new file mode 100644 index 00000000..2fe2f6a0 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/DebugInfoRemover.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.shrinkers; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.utils.LoggerUtils; +import org.objectweb.asm.tree.ClassNode; + +public class DebugInfoRemover extends Shrinker { + @Override + public void transform() { + AtomicInteger outerClasses = new AtomicInteger(); + AtomicInteger outerMethods = new AtomicInteger(); + AtomicInteger innerClasses = new AtomicInteger(); + + getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> { + ClassNode classNode = classWrapper.classNode; + + if (classNode.outerClass != null) { + outerClasses.incrementAndGet(); + classNode.outerClass = null; + } + + if (classNode.outerMethod != null) { + outerMethods.incrementAndGet(); + classNode.outerMethod = null; + classNode.outerMethodDesc = null; + } + + if (classNode.innerClasses != null) { + innerClasses.addAndGet(classNode.innerClasses.size()); + classNode.innerClasses.clear(); + } + }); + + LoggerUtils.stdOut(String.format("Removed %d inner classes, %d outer classes and %d outer methods.", innerClasses.get(), outerClasses.get(), outerMethods.get())); + } + + @Override + public String getName() { + return "Debug Info Remover"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/InvisibleAnnotationsRemover.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/InvisibleAnnotationsRemover.java new file mode 100644 index 00000000..69900c89 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/InvisibleAnnotationsRemover.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.shrinkers; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.utils.LoggerUtils; +import org.objectweb.asm.tree.ClassNode; + +public class InvisibleAnnotationsRemover extends Shrinker { + @Override + public void transform() { + AtomicInteger classAnnotations = new AtomicInteger(); + AtomicInteger methodAnnotations = new AtomicInteger(); + AtomicInteger fieldAnnotations = new AtomicInteger(); + + getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> { + ClassNode classNode = classWrapper.classNode; + + if (classNode.invisibleAnnotations != null) { + classAnnotations.addAndGet(classNode.invisibleAnnotations.size()); + classNode.invisibleAnnotations.clear(); + } + + classWrapper.fields.parallelStream().filter(fieldWrapper -> !excluded(fieldWrapper) && fieldWrapper.fieldNode.invisibleAnnotations != null).forEach(fieldWrapper -> { + fieldAnnotations.addAndGet(fieldWrapper.fieldNode.invisibleAnnotations.size()); + fieldWrapper.fieldNode.invisibleAnnotations.clear(); + }); + + classWrapper.methods.parallelStream().filter(methodWrapper -> !excluded(methodWrapper) && methodWrapper.methodNode.invisibleAnnotations != null).forEach(methodWrapper -> { + methodAnnotations.addAndGet(methodWrapper.methodNode.invisibleAnnotations.size()); + methodWrapper.methodNode.invisibleAnnotations.clear(); + }); + }); + + LoggerUtils.stdOut(String.format("Removed %d class, %d method and %d field invisible annotations.", classAnnotations.get(), methodAnnotations.get(), fieldAnnotations.get())); + } + + @Override + public String getName() { + return "Invisible Annotations Remover"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/Shrinker.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/Shrinker.java new file mode 100644 index 00000000..d813eb1f --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/Shrinker.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.shrinkers; + +import me.itzsomebody.radon.exclusions.ExclusionType; +import me.itzsomebody.radon.transformers.Transformer; + +public abstract class Shrinker extends Transformer { + @Override + protected ExclusionType getExclusionType() { + return ExclusionType.SHRINKER; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/ShrinkerDelegator.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/ShrinkerDelegator.java new file mode 100644 index 00000000..cbdc36b9 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/ShrinkerDelegator.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.shrinkers; + +public class ShrinkerDelegator extends Shrinker { + private ShrinkerSetup setup; + + public ShrinkerDelegator(ShrinkerSetup setup) { + this.setup = setup; + } + + @Override + public void transform() { + if (this.setup.isRemoveVisibleAnnotations()) { + VisibleAnnotationsRemover visibleAnnotationsRemover = new VisibleAnnotationsRemover(); + visibleAnnotationsRemover.init(this.radon); + visibleAnnotationsRemover.transform(); + } + if (this.setup.isRemoveInvisibleAnnotations()) { + InvisibleAnnotationsRemover invisibleAnnotationsRemover = new InvisibleAnnotationsRemover(); + invisibleAnnotationsRemover.init(this.radon); + invisibleAnnotationsRemover.transform(); + } + if (this.setup.isRemoveAttributes()) { + AttributesRemover attributesRemover = new AttributesRemover(); + attributesRemover.init(this.radon); + attributesRemover.transform(); + } + if (this.setup.isRemoveDebug()) { + DebugInfoRemover debugInfoRemover = new DebugInfoRemover(); + debugInfoRemover.init(this.radon); + debugInfoRemover.transform(); + } + if (this.setup.isRemoveUnusedCode()) { + UnusedCodeRemover unusedCodeRemover = new UnusedCodeRemover(); + unusedCodeRemover.init(this.radon); + unusedCodeRemover.transform(); + } + if (this.setup.isRemoveUnusedMembers()) { + UnusedMembersRemover unusedMembersRemover = new UnusedMembersRemover(); + unusedMembersRemover.init(this.radon); + unusedMembersRemover.transform(); + } + } + + @Override + public String getName() { + return "Shrinker"; + } + + public ShrinkerSetup getSetup() { + return setup; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/ShrinkerSetup.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/ShrinkerSetup.java new file mode 100644 index 00000000..ce8058b3 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/ShrinkerSetup.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.shrinkers; + +public class ShrinkerSetup { + private boolean removeVisibleAnnotations; + private boolean removeInvisibleAnnotations; + private boolean removeAttributes; + private boolean removeDebug; + private boolean removeUnusedCode; + private boolean removeUnusedMembers; + + public ShrinkerSetup(boolean removeVisibleAnnotations, boolean removeInvisibleAnnotations, boolean removeAttributes, boolean removeDebug, boolean removeUnusedCode, boolean removeUnusedMembers) { + this.removeVisibleAnnotations = removeVisibleAnnotations; + this.removeInvisibleAnnotations = removeInvisibleAnnotations; + this.removeAttributes = removeAttributes; + this.removeDebug = removeDebug; + this.removeUnusedCode = removeUnusedCode; + this.removeUnusedMembers = removeUnusedMembers; + } + + public boolean isRemoveVisibleAnnotations() { + return this.removeVisibleAnnotations; + } + + public boolean isRemoveInvisibleAnnotations() { + return this.removeInvisibleAnnotations; + } + + public boolean isRemoveAttributes() { + return this.removeAttributes; + } + + public boolean isRemoveDebug() { + return this.removeDebug; + } + + public boolean isRemoveUnusedCode() { + return this.removeUnusedCode; + } + + public boolean isRemoveUnusedMembers() { + return this.removeUnusedMembers; + } +} \ No newline at end of file diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/UnusedCodeRemover.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/UnusedCodeRemover.java new file mode 100644 index 00000000..3b7cb953 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/UnusedCodeRemover.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.shrinkers; + +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.asm.UsedInstructionsFinder; +import me.itzsomebody.radon.utils.LoggerUtils; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; + +/** + * FIXME: COMPLETELY BROKEN + */ +public class UnusedCodeRemover extends Shrinker { + @Override + public void transform() { + AtomicInteger counter = new AtomicInteger(); + + getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> { + ClassNode classNode = classWrapper.classNode; + + classNode.methods.parallelStream().filter(this::hasInstructions).forEach(methodNode -> { + Set usedInstructions = new UsedInstructionsFinder(methodNode.instructions).getUsedInstructions(); + methodNode.localVariables.forEach(localVariableNode -> { + usedInstructions.add(localVariableNode.start); + usedInstructions.add(localVariableNode.end); + }); + methodNode.tryCatchBlocks.forEach(tryCatchBlockNode -> { + usedInstructions.add(tryCatchBlockNode.start); + usedInstructions.add(tryCatchBlockNode.end); + usedInstructions.add(tryCatchBlockNode.handler); + }); + int originalSize = methodNode.instructions.size(); + + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (!usedInstructions.contains(insn)) { + methodNode.instructions.remove(insn); + } + } + + counter.getAndAdd(originalSize - methodNode.instructions.size()); + }); + }); + + LoggerUtils.stdOut(String.format("Removed %d unused instructions.", counter.get())); + } + + @Override + public String getName() { + return "Unused Code Remover"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/UnusedMembersRemover.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/UnusedMembersRemover.java new file mode 100644 index 00000000..738f466b --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/UnusedMembersRemover.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.shrinkers; + +// TODO: Make this +public class UnusedMembersRemover extends Shrinker { + @Override + public void transform() { + + } + + @Override + public String getName() { + return "Unused Members Remover"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/VisibleAnnotationsRemover.java b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/VisibleAnnotationsRemover.java new file mode 100644 index 00000000..2bf07eaa --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/transformers/shrinkers/VisibleAnnotationsRemover.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.transformers.shrinkers; + +import java.util.concurrent.atomic.AtomicInteger; +import me.itzsomebody.radon.utils.LoggerUtils; +import org.objectweb.asm.tree.ClassNode; + +public class VisibleAnnotationsRemover extends Shrinker { + @Override + public void transform() { + AtomicInteger classAnnotations = new AtomicInteger(); + AtomicInteger methodAnnotations = new AtomicInteger(); + AtomicInteger fieldAnnotations = new AtomicInteger(); + + getClassWrappers().parallelStream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> { + ClassNode classNode = classWrapper.classNode; + + if (classNode.visibleAnnotations != null) { + classAnnotations.addAndGet(classNode.visibleAnnotations.size()); + classNode.visibleAnnotations.clear(); + } + + classWrapper.fields.parallelStream().filter(fieldWrapper -> !excluded(fieldWrapper) && fieldWrapper.fieldNode.visibleAnnotations != null).forEach(fieldWrapper -> { + fieldAnnotations.addAndGet(fieldWrapper.fieldNode.visibleAnnotations.size()); + fieldWrapper.fieldNode.visibleAnnotations.clear(); + }); + + classWrapper.methods.parallelStream().filter(methodWrapper -> !excluded(methodWrapper) && methodWrapper.methodNode.visibleAnnotations != null).forEach(methodWrapper -> { + methodAnnotations.addAndGet(methodWrapper.methodNode.visibleAnnotations.size()); + methodWrapper.methodNode.visibleAnnotations.clear(); + }); + }); + + LoggerUtils.stdOut(String.format("Removed %d class, %d method and %d field invisible annotations.", classAnnotations.get(), methodAnnotations.get(), fieldAnnotations.get())); + } + + @Override + public String getName() { + return "Visible Annotations Remover"; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/utils/AccessUtils.java b/Radon-Program/src/main/java/me/itzsomebody/radon/utils/AccessUtils.java new file mode 100644 index 00000000..02a87f28 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/utils/AccessUtils.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.utils; + +import org.objectweb.asm.Opcodes; + +public class AccessUtils { + public static boolean isAbstract(int access) { + return (Opcodes.ACC_ABSTRACT & access) != 0; + } + + public static boolean isNative(int access) { + return (Opcodes.ACC_NATIVE & access) != 0; + } + + public static boolean isSynthetic(int access) { + return (Opcodes.ACC_SYNTHETIC & access) != 0; + } + + public static boolean isBridge(int access) { + return (Opcodes.ACC_BRIDGE & access) != 0; + } + + public static int makePublic(int access) { + int a = access; + if ((a & Opcodes.ACC_PRIVATE) != 0) { + a ^= Opcodes.ACC_PRIVATE; + } + if ((a & Opcodes.ACC_PROTECTED) != 0) { + a ^= Opcodes.ACC_PROTECTED; + } + if ((a & Opcodes.ACC_PUBLIC) == 0) { + a |= Opcodes.ACC_PUBLIC; + } + return a; + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java b/Radon-Program/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java new file mode 100644 index 00000000..65d726b2 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.utils; + +import jdk.internal.org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.FrameNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.LineNumberNode; +import org.objectweb.asm.tree.MethodNode; + +public class BytecodeUtils { + public static boolean isInstruction(AbstractInsnNode insn) { + return !(insn instanceof FrameNode) && !(insn instanceof LineNumberNode) && !(insn instanceof LabelNode); + } + + public static AbstractInsnNode getNext(AbstractInsnNode node) { + AbstractInsnNode next = node.getNext(); + while (!isInstruction(next)) { + next = next.getNext(); + } + return next; + } + + public static boolean isReturn(int opcode) { + return (opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN); + } + + public static boolean hasAnnotations(ClassNode classNode) { + return (classNode.visibleAnnotations != null && !classNode.visibleAnnotations.isEmpty()) + || (classNode.invisibleAnnotations != null && !classNode.invisibleAnnotations.isEmpty()); + } + + public static boolean hasAnnotations(MethodNode methodNode) { + return (methodNode.visibleAnnotations != null && !methodNode.visibleAnnotations.isEmpty()) + || (methodNode.invisibleAnnotations != null && !methodNode.invisibleAnnotations.isEmpty()); + } + + public static boolean hasAnnotations(FieldNode fieldNode) { + return (fieldNode.visibleAnnotations != null && !fieldNode.visibleAnnotations.isEmpty()) + || (fieldNode.invisibleAnnotations != null && !fieldNode.invisibleAnnotations.isEmpty()); + } + + public static boolean isIntInsn(AbstractInsnNode insn) { + if (insn == null) { + return false; + } + int opcode = insn.getOpcode(); + return ((opcode >= org.objectweb.asm.Opcodes.ICONST_M1 && opcode <= org.objectweb.asm.Opcodes.ICONST_5) + || opcode == org.objectweb.asm.Opcodes.BIPUSH + || opcode == org.objectweb.asm.Opcodes.SIPUSH + || (insn instanceof LdcInsnNode + && ((LdcInsnNode) insn).cst instanceof Integer)); + } + + public static boolean isLongInsn(AbstractInsnNode insn) { + int opcode = insn.getOpcode(); + return (opcode == org.objectweb.asm.Opcodes.LCONST_0 + || opcode == org.objectweb.asm.Opcodes.LCONST_1 + || (insn instanceof LdcInsnNode + && ((LdcInsnNode) insn).cst instanceof Long)); + } + + public static AbstractInsnNode getNumberInsn(int number) { + if (number >= -1 && number <= 5) { + return new InsnNode(number + 3); + } else if (number >= -128 && number <= 127) { + return new IntInsnNode(Opcodes.BIPUSH, number); + } else if (number >= -32768 && number <= 32767) { + return new IntInsnNode(Opcodes.SIPUSH, number); + } else { + return new LdcInsnNode(number); + } + } + + public static AbstractInsnNode getNumberInsn(long number) { + if (number >= 0 && number <= 1) { + return new InsnNode((int) (number + 9)); + } else { + return new LdcInsnNode(number); + } + } + + public static AbstractInsnNode getNumberInsn(float number) { + if (number >= 0 && number <= 2) { + return new InsnNode((int) (number + 11)); + } else { + return new LdcInsnNode(number); + } + } + + public static AbstractInsnNode getNumberInsn(double number) { + if (number >= 0 && number <= 1) { + return new InsnNode((int) (number + 14)); + } else { + return new LdcInsnNode(number); + } + } + + public static int getIntNumber(AbstractInsnNode insn) { + int opcode = insn.getOpcode(); + + if (opcode >= org.objectweb.asm.Opcodes.ICONST_M1 && opcode <= org.objectweb.asm.Opcodes.ICONST_5) { + return opcode - 3; + } else if (insn instanceof IntInsnNode + && insn.getOpcode() != org.objectweb.asm.Opcodes.NEWARRAY) { + return ((IntInsnNode) insn).operand; + } else if (insn instanceof LdcInsnNode + && ((LdcInsnNode) insn).cst instanceof Integer) { + return (Integer) ((LdcInsnNode) insn).cst; + } + + throw new IllegalArgumentException("Unexpected instruction"); + } + + public static long getLongNumber(AbstractInsnNode insn) { + int opcode = insn.getOpcode(); + + if (opcode >= org.objectweb.asm.Opcodes.LCONST_0 && opcode <= org.objectweb.asm.Opcodes.LCONST_1) { + return opcode - 9; + } else if (insn instanceof LdcInsnNode + && ((LdcInsnNode) insn).cst instanceof Long) { + return (Long) ((LdcInsnNode) insn).cst; + } + + throw new IllegalArgumentException("Unexpected instruction"); + } +} diff --git a/src/main/java/me/itzsomebody/radon/utils/FileUtils.java b/Radon-Program/src/main/java/me/itzsomebody/radon/utils/IOUtils.java similarity index 87% rename from src/main/java/me/itzsomebody/radon/utils/FileUtils.java rename to Radon-Program/src/main/java/me/itzsomebody/radon/utils/IOUtils.java index fd43fded..8b91a310 100644 --- a/src/main/java/me/itzsomebody/radon/utils/FileUtils.java +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/utils/IOUtils.java @@ -21,14 +21,9 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.util.zip.ZipOutputStream; +import me.itzsomebody.radon.exceptions.ByteArrayConversionException; -/** - * Utils for operating on files in general. - * - * @author ItzSomebody - */ -public class FileUtils { +public class IOUtils { /** * Renames an existing file to EXISTINGFILE.jar.BACKUP-X. * @@ -37,9 +32,10 @@ public class FileUtils { */ public static String renameExistingFile(File existing) { int i = 0; + while (true) { i++; - String newName = existing.getAbsolutePath() + ".BACKUP-" + i; + String newName = existing.getAbsolutePath() + ".BACKUP-" + String.valueOf(i); File backUpName = new File(newName); if (!backUpName.exists()) { existing.renameTo(backUpName); @@ -47,6 +43,7 @@ public static String renameExistingFile(File existing) { return newName; } } + } /** @@ -56,17 +53,20 @@ public static String renameExistingFile(File existing) { * @return a byte array from the inputted */ public static byte[] toByteArray(InputStream in) { - try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; while (in.available() > 0) { int data = in.read(buffer); out.write(buffer, 0, data); } + in.close(); + out.close(); return out.toByteArray(); } catch (IOException ioe) { ioe.printStackTrace(); - throw new RuntimeException(ioe.getMessage()); + throw new ByteArrayConversionException(ioe); } } } diff --git a/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java b/Radon-Program/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java similarity index 63% rename from src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java rename to Radon-Program/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java index 8bf09430..8b04fd49 100644 --- a/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/utils/LoggerUtils.java @@ -24,10 +24,11 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; -import me.itzsomebody.radon.Radon; +import me.itzsomebody.radon.Main; /** * Utils to print fancy stuff in the console and to write log file. + * TODO: Kind of static abuse-ish. Maybe rewrite to use virtual instance instead of static? * * @author ItzSomebody */ @@ -35,15 +36,14 @@ public class LoggerUtils { /** * The {@link SimpleDateFormat} that will be used for logging. */ - private final static SimpleDateFormat FORMAT - = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss"); + private static SimpleDateFormat FORMAT = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss"); + + private static List strings = new ArrayList<>(); /** - * Writes an inputted {@link ArrayList} of {@link String}s to a log file. - * - * @param strings {@link String}s to write to log file. + * Writes strings to log. */ - public static void logWriter(List strings) { + public static void logWriter() { BufferedWriter bw; try { File log = new File("Radon.log"); @@ -64,15 +64,17 @@ public static void logWriter(List strings) { bw.append("##############################################\n"); bw.append("\n"); bw.append("\n"); - bw.append("Version: " + Radon.VERSION + "\n"); - bw.append("Author: " + Radon.AUTHORS + "\n"); + bw.append("Version: ").append(Main.VERSION).append('\n'); + bw.append("Contributors: ").append(Main.CONTRIBUTORS).append('\n'); for (String msg : strings) { bw.append(msg); bw.newLine(); } + strings.clear(); bw.close(); } catch (Throwable t) { - stdOut("Error: " + t.getMessage()); + stdErr("Error occurred while writing log."); + t.printStackTrace(); } } @@ -81,12 +83,37 @@ public static void logWriter(List strings) { * a {@link String}. * * @param string to write to the console. - * @return formatted {@link String}. */ - public static String stdOut(String string) { + public static void stdOut(String string) { + String date = FORMAT.format(new Date(System.currentTimeMillis())); + String formatted = "[" + date + "] INFO: " + string; + System.out.println(formatted); + strings.add(formatted); + } + + /** + * Prints a formatted message into the console and returns the result as + * a {@link String}. + * + * @param string to write to the console. + */ + public static void stdErr(String string) { + String date = FORMAT.format(new Date(System.currentTimeMillis())); + String formatted = "[" + date + "] ERROR: " + string; + System.out.println(formatted); + strings.add(formatted); + } + + /** + * Prints a formatted message into the console and returns the result as + * a {@link String}. + * + * @param string to write to the console. + */ + public static void stdWarn(String string) { String date = FORMAT.format(new Date(System.currentTimeMillis())); - String formatted = "[" + date + "] " + Radon.PREFIX + " - " + string; + String formatted = "[" + date + "] WARNING: " + string; System.out.println(formatted); - return formatted; + strings.add(formatted); } } diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/utils/RandomUtils.java b/Radon-Program/src/main/java/me/itzsomebody/radon/utils/RandomUtils.java new file mode 100644 index 00000000..d16e8b5c --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/utils/RandomUtils.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.utils; + +import java.util.concurrent.ThreadLocalRandom; + +public class RandomUtils { + private static ThreadLocalRandom random = ThreadLocalRandom.current(); + + public static int getRandomInt() { + return random.nextInt(); + } + + public static int getRandomInt(int bounds) { + return random.nextInt(bounds); + } + + public static long getRandomLong() { + return random.nextLong(); + } + + public static long getRandomLong(long bounds) { + return random.nextLong(bounds); + } + + public static float getRandomFloat() { + return random.nextFloat(); + } + + public static double getRandomDouble() { + return random.nextDouble(); + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/utils/StringUtils.java b/Radon-Program/src/main/java/me/itzsomebody/radon/utils/StringUtils.java new file mode 100644 index 00000000..ba53e0a5 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/utils/StringUtils.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.utils; + +import java.util.ArrayList; +import java.util.Collection; + +public class StringUtils { + private static char ALPHA_NUM[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray(); + private static char ALPHA[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray(); + + public static String randomSpacesString(int length) { + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < length; i++) { + sb.append((char) (RandomUtils.getRandomInt(16) + '\u2000')); + } + + return sb.toString(); + } + + public static String unrecognizedCharsString(int length) { + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < length; i++) { + sb.append((char) (RandomUtils.getRandomInt(8) + '\ua6ac')); + } + + return sb.toString(); + } + + public static String alphaString(int i) { + char buf[] = new char[33]; + boolean negative = (i < 0); + int charPos = 32; + + if (!negative) { + i = -i; + } + + while (i <= -ALPHA.length) { + buf[charPos--] = ALPHA[-(i % ALPHA.length)]; + i = i / ALPHA.length; + } + buf[charPos] = ALPHA[-i]; + + if (negative) { + buf[--charPos] = '-'; + } + + return new String(buf, charPos, (33 - charPos)); + } + + public static String alphaNumericString(int i) { + char buf[] = new char[33]; + boolean negative = (i < 0); + int charPos = 32; + + if (!negative) { + i = -i; + } + + while (i <= -ALPHA_NUM.length) { + buf[charPos--] = ALPHA_NUM[-(i % ALPHA_NUM.length)]; + i = i / ALPHA_NUM.length; + } + buf[charPos] = ALPHA_NUM[-i]; + + if (negative) { + buf[--charPos] = '-'; + } + + return new String(buf, charPos, (33 - charPos)); + } + + public static String randomAlphaString(int length) { + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < length; i++) { + sb.append(ALPHA[RandomUtils.getRandomInt(ALPHA.length)]); + } + + return sb.toString(); + } + + public static String randomClassName(Collection classNames) { + ArrayList list = new ArrayList<>(classNames); + String first = list.get(RandomUtils.getRandomInt(classNames.size())); + String second = list.get(RandomUtils.getRandomInt(classNames.size())); + + return first + '$' + second.substring(second.lastIndexOf("/") + 1, second.length()); + } +} diff --git a/Radon-Program/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java b/Radon-Program/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java new file mode 100644 index 00000000..2e19df35 --- /dev/null +++ b/Radon-Program/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2018 ItzSomebody + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package me.itzsomebody.radon.utils; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +public class WatermarkUtils { + public static List extractIds(ZipFile zipFile, String key) throws Throwable { + ArrayList ids = new ArrayList<>(); + Enumeration entries = zipFile.entries(); + Map classes = new HashMap<>(); + try { + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + if (!entry.isDirectory() && entry.getName().endsWith(".class")) { + try { + ClassReader cr = new ClassReader(zipFile.getInputStream(entry)); + ClassNode classNode = new ClassNode(); + cr.accept(classNode, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); + classes.put(classNode.name, classNode); + } catch (Throwable t) { + // Ignored + } + } + } + } finally { + zipFile.close(); + } + + Map embedMap = new LinkedHashMap<>(); + for (ClassNode classNode : classes.values()) { + for (MethodNode methodNode : classNode.methods) { + for (AbstractInsnNode insn : methodNode.instructions.toArray()) { + if (BytecodeUtils.isIntInsn(insn)) { + if (BytecodeUtils.isIntInsn(insn.getNext())) { + if (BytecodeUtils.isIntInsn(insn.getNext().getNext())) { + if (BytecodeUtils.isIntInsn(insn.getNext().getNext().getNext())) { + if (insn.getNext().getNext().getNext().getNext() != null && insn.getNext().getNext().getNext().getNext().getOpcode() == Opcodes.ISTORE + && insn.getNext().getNext().getNext().getNext().getNext() != null && insn.getNext().getNext().getNext().getNext().getNext().getOpcode() == Opcodes.ISTORE + && insn.getNext().getNext().getNext().getNext().getNext().getNext() != null && insn.getNext().getNext().getNext().getNext().getNext().getNext().getOpcode() == Opcodes.ISTORE + && insn.getNext().getNext().getNext().getNext().getNext().getNext().getNext() != null && insn.getNext().getNext().getNext().getNext().getNext().getNext().getNext().getOpcode() == Opcodes.ISTORE) { + char character = (char) (BytecodeUtils.getIntNumber(insn) ^ BytecodeUtils.getIntNumber(insn.getNext())); + int index = BytecodeUtils.getIntNumber(insn.getNext().getNext()) ^ BytecodeUtils.getIntNumber(insn.getNext().getNext().getNext()); + embedMap.put(index, character); + } + } + } + } + } + } + } + } + if (enoughInfo(embedMap)) { + String result = decrypt(constructString(embedMap), key); + ids.add("Watermark: " + result); + } + + return ids; + } + + private static boolean enoughInfo(Map embedMap) { + if (embedMap.size() < 1) { + return false; + } + + for (int i = 0; i < embedMap.size(); i++) { + if (!embedMap.containsKey(i)) { + return false; + } + } + + return true; + } + + private static String constructString(Map embedMap) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < embedMap.size(); i++) { + sb.append((char) embedMap.get(i)); + } + + return sb.toString(); + } + + private static String decrypt(String enc, String key) { + char[] messageChars = enc.toCharArray(); + char[] keyChars = key.toCharArray(); + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < messageChars.length; i++) { + sb.append((char) (messageChars[i] ^ keyChars[i % keyChars.length])); + } + + return sb.toString(); + } +} diff --git a/src/main/resources/META-INF/asm-license.txt b/Radon-Program/src/main/resources/META-INF/asm-license.txt similarity index 100% rename from src/main/resources/META-INF/asm-license.txt rename to Radon-Program/src/main/resources/META-INF/asm-license.txt diff --git a/Radon-Program/src/main/resources/META-INF/license.txt b/Radon-Program/src/main/resources/META-INF/license.txt new file mode 100644 index 00000000..1a3517aa --- /dev/null +++ b/Radon-Program/src/main/resources/META-INF/license.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + Radon + Copyright (C) 2018 ItzSomebody + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Radon Copyright (C) 2018 ItzSomebody + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/src/main/resources/META-INF/snakeyaml-license.txt b/Radon-Program/src/main/resources/META-INF/snakeyaml-license.txt similarity index 100% rename from src/main/resources/META-INF/snakeyaml-license.txt rename to Radon-Program/src/main/resources/META-INF/snakeyaml-license.txt diff --git a/pom.xml b/pom.xml index 0e812887..c52b5874 100644 --- a/pom.xml +++ b/pom.xml @@ -6,65 +6,15 @@ me.itzsomebody Radon - 0.9.0 + pom + 1.0.0 UTF-8 - - src/main/java - - - src/main/resources - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - me.itzsomebody.radon.Radon - - - - - - maven-compiler-plugin - 3.7.0 - - 1.8 - 1.8 - - -XDignore.symbol.file - - true - - - - org.apache.maven.plugins - maven-shade-plugin - 3.1.0 - - - package - - shade - - - - - *:* - - - - - - - - - + + Radon-Program + Radon-GUI + Sonatype-public @@ -72,7 +22,6 @@ http://oss.sonatype.org/content/groups/public/ - org.yaml diff --git a/src/main/java/me/itzsomebody/radon/config/Config.java b/src/main/java/me/itzsomebody/radon/config/Config.java deleted file mode 100644 index 8740bf3a..00000000 --- a/src/main/java/me/itzsomebody/radon/config/Config.java +++ /dev/null @@ -1,1051 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.config; - -import java.io.File; -import java.io.InputStream; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.transformers.flow.HeavyFlowObfuscation; -import me.itzsomebody.radon.transformers.flow.LightFlowObfuscation; -import me.itzsomebody.radon.transformers.flow.NormalFlowObfuscation; -import me.itzsomebody.radon.transformers.invokedynamic.HeavyInvokeDynamic; -import me.itzsomebody.radon.transformers.invokedynamic.LightInvokeDynamic; -import me.itzsomebody.radon.transformers.invokedynamic.NormalInvokeDynamic; -import me.itzsomebody.radon.transformers.linenumbers.ObfuscateLineNumbers; -import me.itzsomebody.radon.transformers.linenumbers.RemoveLineNumbers; -import me.itzsomebody.radon.transformers.localvariables.ObfuscateLocalVariables; -import me.itzsomebody.radon.transformers.localvariables.RemoveLocalVariables; -import me.itzsomebody.radon.transformers.misc.Crasher; -import me.itzsomebody.radon.transformers.misc.HideCode; -import me.itzsomebody.radon.transformers.misc.InnerClassRemover; -import me.itzsomebody.radon.transformers.misc.NumberObfuscation; -import me.itzsomebody.radon.transformers.misc.Shuffler; -import me.itzsomebody.radon.transformers.misc.StringPool; -import me.itzsomebody.radon.transformers.misc.Renamer; -import me.itzsomebody.radon.transformers.sourcedebug.ObfuscateSourceDebug; -import me.itzsomebody.radon.transformers.sourcedebug.RemoveSourceDebug; -import me.itzsomebody.radon.transformers.sourcename.ObfuscateSourceName; -import me.itzsomebody.radon.transformers.sourcename.RemoveSourceName; -import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; -import org.yaml.snakeyaml.Yaml; - -/** - * Big config class that looks horrible and has lots of docs to make the code - * look a lot longer than it actually is LOL - * - * @author ItzSomebody - */ -public class Config { - /** - * Valid keys for element map loaded from config. - */ - private final static ArrayList VALIDKEYS = new ArrayList() { - { - for (ConfigEnum conf : ConfigEnum.values()) { - add(conf.toString()); - } - } - }; - - /** - * The config object as {@link InputStream}. - */ - private final InputStream config; - - /** - * The element map object as {@link Map}. - */ - private Map map; - - /** - * The exempt list as {@link ArrayList}. - */ - private List exempts; - - /** - * Exempted classes from any obfuscation. - */ - public List classExempts; - - /** - * Exempted methods from any obfuscation. - */ - public List methodExempts; - - /** - * Exempted fields from any obfuscation. - */ - public List fieldExempts; - - /** - * Exempted classes/methods from string encryption, - */ - public List stringEncExempts; - - /** - * Exempted classes/methods from invokedynamics. - */ - public List indyExempts; - - /** - * Exempted classes/methods from flow control obfuscation. - */ - public List flowExempts; - - /** - * Exempted classes/methods from local variable obfuscation. - */ - public List localVarExempts; - - /** - * Exempted classes from source name obfuscation. - */ - public List sourceNameExempts; - - /** - * Exempted classes from source debug obfuscation. - */ - public List sourceDebugExempts; - - /** - * Exempted classes/methods from line number obfuscation. - */ - public List lineNumbersExempts; - - /** - * Exempted classes/methods from string pooling. - */ - public List stringPoolExempts; - - /** - * Exempted classes from crashers. - */ - public List crasherExempts; - - /** - * Exempted classes/methods/fields from hide code obfuscation. - */ - public List hideCodeExempts; - - /** - * Exempted classes/methods from number obfuscation. - */ - public List numberExempts; - - /** - * Exempted classes from member shuffling. - */ - public List shufflerExempts; - - /** - * Exempted classes from inner-class information removal. - */ - public List innerClassExempts; - - /** - * Exempted classes/methods/fields from renaming. - */ - public List renamerExempts; - - /** - * Exempted classes/methods/fields from expiration. - */ - public List expiryExempts; - - /** - * Constructs a new {@link Config} - * - * @param config the {@link InputStream} to read from. - */ - public Config(InputStream config) { - this.config = config; - } - - /** - * Loads the configuration elements into {@link Config#map} - * using {@link Config#config}. - */ - public void loadIntoMap() { - this.map = new Yaml().load(this.config); - } - - /** - * Checks config for unrecognized keys. - * - * @throws IllegalArgumentException if argument is unrecognized. - */ - public void checkConfig() throws IllegalArgumentException { - for (String key : this.map.keySet()) { - if (!this.VALIDKEYS.contains(key)) { - throw new IllegalArgumentException("Invalid key: " + key); - } - } - } - - /** - * Returns the input element from {@link Config#map} as {@link File}. - * - * @return Returns the input element from {@link Config#map} as - * {@link File}. - * @throws IllegalArgumentException if input is null or not a - * {@link String}. - */ - public File getInput() throws IllegalArgumentException { - Object path = this.map.get("Input"); - if (path == null) - throw new IllegalArgumentException("Input not specified in config!"); - if (!(path instanceof String)) - throw new IllegalArgumentException("Input arg must be a string"); - - return new File((String) path); - } - - /** - * Returns the output element from {@link Config#map} as {@link File}. - * - * @return Returns the output element from {@link Config#map} as - * {@link File}. - * @throws IllegalArgumentException if output is not specified as a - * {@link String}. - */ - public File getOutput() throws IllegalArgumentException { - Object path = this.map.get("Output"); - if (path == null) { - return new File(getInput().getName().replace(".jar", - "-OBF.jar")); - } else { - if (!(path instanceof String)) - throw new IllegalArgumentException("Output arg must be a string"); - return new File((String) path); - } - } - - /** - * Returns the library element from {@link Config#map} as a {@link HashMap}. - * - * @return Returns the library element from {@link Config#map} as a - * {@link HashMap}. or each list element is not a {@link String}. - */ - public HashMap getLibraries() throws - IllegalArgumentException { - HashMap libs = new HashMap<>(); - Object o = this.map.get("Libraries"); - if (o != null) { - if (!(o instanceof List)) - throw new IllegalArgumentException("Libraries must be " + - "represented as list"); - List list = (List) o; - for (Object element : list) { - if (!(element instanceof String)) - throw new IllegalArgumentException("Library args must be " + - "string(s)"); - String lib = (String) element; - libs.put(lib, new File(lib)); - } - } - - return libs; - } - - /** - * Loads the exempt element from {@link Config#map} into - * {@link Config#exempts}. - * - * @throws IllegalArgumentException if the exempt element is not a list or - * each list element is not a {@link String}. - */ - private void setExempts() throws IllegalArgumentException { - this.exempts = new ArrayList<>(); - Object o = this.map.get("Exempts"); - if (o != null) { - if (!(o instanceof List)) - throw new IllegalArgumentException("Exempts must be " + - "represented as list"); - List list = (List) o; - for (Object object : list) { - if (!(object instanceof String)) - throw new IllegalArgumentException("Exemps must be string(s)"); - String value = (String) object; - - this.exempts.add(value); - } - } - } - - /** - * Sorts the elements in {@link Config#exempts} into - * {@link Config#classExempts}, {@link Config#methodExempts} and - * {@link Config#fieldExempts}. - * - * @throws IllegalArgumentException if exempt type is unknown. - */ - public void sortExempts() throws IllegalArgumentException { - this.setExempts(); - this.classExempts = new ArrayList<>(); - this.methodExempts = new ArrayList<>(); - this.fieldExempts = new ArrayList<>(); - this.stringEncExempts = new ArrayList<>(); - this.indyExempts = new ArrayList<>(); - this.flowExempts = new ArrayList<>(); - this.localVarExempts = new ArrayList<>(); - this.sourceNameExempts = new ArrayList<>(); - this.sourceDebugExempts = new ArrayList<>(); - this.lineNumbersExempts = new ArrayList<>(); - this.stringPoolExempts = new ArrayList<>(); - this.crasherExempts = new ArrayList<>(); - this.hideCodeExempts = new ArrayList<>(); - this.numberExempts = new ArrayList<>(); - this.shufflerExempts = new ArrayList<>(); - this.innerClassExempts = new ArrayList<>(); - this.renamerExempts = new ArrayList<>(); - this.expiryExempts = new ArrayList<>(); - - if (this.exempts != null) { - for (String exempt : this.exempts) { - if (exempt.startsWith("Class: ")) { - this.classExempts.add(exempt.replace("Class: ", "")); - } else if (exempt.startsWith("Method: ")) { - this.methodExempts.add(exempt.replace("Method: ", "")); - } else if (exempt.startsWith("Field: ")) { - this.fieldExempts.add(exempt.replace("Field: ", "")); - } else if (exempt.startsWith("StringEncryption: ")) { - this.stringEncExempts.add(exempt.replace("StringEncryption: ", "")); - } else if (exempt.startsWith("InvokeDynamic: ")) { - this.indyExempts.add(exempt.replace("InvokeDynamic: ", "")); - } else if (exempt.startsWith("Flow: ")) { - this.flowExempts.add(exempt.replace("Flow: ", "")); - } else if (exempt.startsWith("LocalVars: ")) { - this.localVarExempts.add(exempt.replace("LocalVars: ", "")); - } else if (exempt.startsWith("SourceName: ")) { - this.sourceNameExempts.add(exempt.replace("SourceName: ", "")); - } else if (exempt.startsWith("SourceDebug: ")) { - this.sourceDebugExempts.add(exempt.replace("SourceDebug: ", "")); - } else if (exempt.startsWith("LineNumbers: ")) { - this.lineNumbersExempts.add(exempt.replace("LineNumbers: ", "")); - } else if (exempt.startsWith("StringPool: ")) { - this.stringPoolExempts.add(exempt.replace("StringPool: ", "")); - } else if (exempt.startsWith("Crasher: ")) { - this.crasherExempts.add(exempt.replace("Crasher: ", "")); - } else if (exempt.startsWith("HideCode: ")) { - this.hideCodeExempts.add(exempt.replace("HideCode: ", "")); - } else if (exempt.startsWith("Numbers: ")) { - this.numberExempts.add(exempt.replace("Numbers: ", "")); - } else if (exempt.startsWith("Shuffler: ")) { - this.shufflerExempts.add(exempt.replace("Shuffler: ", "")); - } else if (exempt.startsWith("InnerClasses: ")) { - this.innerClassExempts.add(exempt.replace("InnerClasses: ", "")); - } else if (exempt.startsWith("Renamer: ")) { - this.renamerExempts.add(exempt.replace("Renamer: ", "")); - } else if (exempt.startsWith("Expiry")) { - this.expiryExempts.add(exempt.replace("Expiry: ", "")); - } else { - throw new IllegalArgumentException("Unrecognized exempt type: " + exempt); - } - } - } - } - - /** - * Returns the exempt element from {@link Config#map} as {@link List}. - * - * @return Returns the exempt element from {@link Config#map} as - * {@link List}. - */ - public List getExempts() { - return this.exempts; - } - - /** - * Returns the string encryption type from {@link Config#map} as - * an {@link AbstractTransformer}.Defaults to null if null. - * - * @return Returns the string encryption type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public AbstractTransformer getStringEncryptionType() - throws IllegalArgumentException { - if (this.map.containsKey("StringEncryption")) { - Object value = this.map.get("StringEncryption"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("String encryption arg" + - " must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("SuperLight")) { - return new SuperLightStringEncryption(this.getSpigotBool()); - } else if (s.equalsIgnoreCase("Light")) { - return new LightStringEncryption(this.getSpigotBool()); - } else if (s.equalsIgnoreCase("Normal")) { - return new NormalStringEncryption(this.getSpigotBool()); - } else if (s.equalsIgnoreCase("Heavy")) { - return new HeavyStringEncryption(this.getSpigotBool()); - } else { - throw new IllegalArgumentException("Invalid string " + - "encryption type: " + s); - } - } else { - throw new IllegalArgumentException("String encryption type is" + - " null"); - } - } - - return null; - } - - /** - * Returns the invokedynamic type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * - * @return Returns the invokedynamic type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public AbstractTransformer getInvokeDynamicType() - throws IllegalArgumentException { - if (this.map.containsKey("InvokeDynamic")) { - Object value = this.map.get("InvokeDynamic"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("InvokeDynamic arg " + - "must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("Light")) { - return new LightInvokeDynamic(); - } else if (s.equalsIgnoreCase("Normal")) { - return new NormalInvokeDynamic(); - } else if (s.equalsIgnoreCase("Heavy")) { - return new HeavyInvokeDynamic(); - } else { - throw new IllegalArgumentException("Invalid invokedynamic" + - " type: " + s); - } - } else { - throw new IllegalArgumentException("InvokeDynamic type is null"); - } - } - - return null; - } - - /** - * Returns the flow obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * - * @return Returns the flow obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public AbstractTransformer getFlowObfuscationType() - throws IllegalArgumentException { - if (this.map.containsKey("FlowObfuscation")) { - Object value = this.map.get("FlowObfuscation"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("Flow obfuscation arg " + - "must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("Light")) { - return new LightFlowObfuscation(); - } else if (s.equalsIgnoreCase("Normal")) { - return new NormalFlowObfuscation(); - } else if (s.equalsIgnoreCase("Heavy")) { - return new HeavyFlowObfuscation(); - } else { - throw new IllegalArgumentException("Invalid flow " + - "obfuscation type: " + s); - } - } else { - throw new IllegalArgumentException("Flow obfuscation type is " + - "null"); - } - } - - return null; - } - - /** - * Returns the local variable obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * - * @return Returns the local variable obfuscation type from - * {@link Config#map} as an {@link AbstractTransformer}. Defaults to null - * if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public AbstractTransformer getLocalVariableObfuscationType() - throws IllegalArgumentException { - if (this.map.containsKey("LocalVariableObfuscation")) { - Object value = this.map.get("LocalVariableObfuscation"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("Local variable " + - "obfuscation arg must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("Obfuscate")) { - return new ObfuscateLocalVariables(); - } else if (s.equalsIgnoreCase("Remove")) { - return new RemoveLocalVariables(); - } else { - throw new IllegalArgumentException("Invalid local " + - "variable obfuscation type: " + s); - } - } else { - throw new IllegalArgumentException("Local variable " + - "obfuscation type is null"); - } - } - - return null; - } - - /** - * Returns the line number obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * - * @return Returns the line number obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public AbstractTransformer getLineNumberObfuscationType() - throws IllegalArgumentException { - if (this.map.containsKey("LineNumberObfuscation")) { - Object value = this.map.get("LineNumberObfuscation"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("Line number " + - "obfuscation arg must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("Obfuscate")) { - return new ObfuscateLineNumbers(); - } else if (s.equalsIgnoreCase("Remove")) { - return new RemoveLineNumbers(); - } else { - throw new IllegalArgumentException("Invalid line number " + - "obfuscation type: " + s); - } - } else { - throw new IllegalArgumentException("Line number obfuscation " + - "type is null"); - } - } - - return null; - } - - /** - * Returns the source name obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * - * @return Returns the source name obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public AbstractTransformer getSourceNameObfuscationType() - throws IllegalArgumentException { - if (this.map.containsKey("SourceNameObfuscation")) { - Object value = this.map.get("SourceNameObfuscation"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("Source name " + - "obfuscation arg must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("Obfuscate")) { - return new ObfuscateSourceName(); - } else if (s.equalsIgnoreCase("Remove")) { - return new RemoveSourceName(); - } else { - throw new IllegalArgumentException("Invalid source name " + - "obfuscation type: " + s); - } - } else { - throw new IllegalArgumentException("Source name obfuscation " + - "type is null"); - } - } - - return null; - } - - /** - * Returns the source debug obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * - * @return Returns the source debug obfuscation type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public AbstractTransformer getSourceDebugObfuscationType() - throws IllegalArgumentException { - if (this.map.containsKey("SourceDebugObfuscation")) { - Object value = this.map.get("SourceDebugObfuscation"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("Source debug " + - "obfuscation arg must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("Obfuscate")) { - return new ObfuscateSourceDebug(); - } else if (s.equalsIgnoreCase("Remove")) { - return new RemoveSourceDebug(); - } else { - throw new IllegalArgumentException("Invalid source debug " + - "obfuscation type: " + s); - } - } else { - throw new IllegalArgumentException("Source debug obfuscation " + - "type is null"); - } - } - - return null; - } - - /** - * Returns the shuffler type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false - * - * @return Returns the shuffler type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * @throws IllegalArgumentException if value from key is null or - * not a {@link Boolean} - */ - public AbstractTransformer getShufflerType() - throws IllegalArgumentException { - if (this.map.containsKey("Shuffler")) { - Object value = this.map.get("Shuffler"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("Shuffler arg must be " + - "true/false"); - boolean s = (Boolean) value; - if (s) { - return new Shuffler(); - } - } else { - throw new IllegalArgumentException("Shuffler arg is null"); - } - } - - return null; - } - - /** - * Returns the inner class remover type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null or false - * - * @return Returns the inner class remover type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null or false. - * @throws IllegalArgumentException if value from key is null or not - * a {@link Boolean} - */ - public AbstractTransformer getInnerClassRemoverType() - throws IllegalArgumentException { - if (this.map.containsKey("InnerClassRemover")) { - Object value = this.map.get("InnerClassRemover"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("InnerClassRemover arg" + - " must be true/false"); - boolean s = (Boolean) value; - if (s) { - return new InnerClassRemover(); - } - } else { - throw new IllegalArgumentException("InnerClassRemover arg is " + - "null"); - } - } - - return null; - } - - /** - * Returns the crasher type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false - * - * @return Returns the crasher type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * @throws IllegalArgumentException if value from key is null or - * not a {@link Boolean} - */ - public AbstractTransformer getCrasherType() - throws IllegalArgumentException { - if (this.map.containsKey("Crasher")) { - Object value = this.map.get("Crasher"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("Crasher arg must be " + - "true/false"); - boolean s = (Boolean) value; - if (s) { - return new Crasher(); - } - } else { - throw new IllegalArgumentException("Crasher arg is null"); - } - } - - return null; - } - - /** - * Returns the hide code type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * - * @return Returns the hide code type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * @throws IllegalArgumentException if value from key is null or not - * a {@link Boolean} - */ - public AbstractTransformer getHideCodeType() - throws IllegalArgumentException { - if (this.map.containsKey("HideCode")) { - Object value = this.map.get("HideCode"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("HideCode arg must be " + - "true/false"); - boolean s = (Boolean) value; - if (s) { - return new HideCode(); - } - } else { - throw new IllegalArgumentException("HideCode arg is null"); - } - } - - return null; - } - - /** - * Returns the number of trash classes from {@link Config#map} as an - * {@link Integer}. Defaults to null if null. - * - * @return Returns the number of trash classes from {@link Config#map} as an - * {@link Integer}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is null or not a - * {@link Integer} - */ - public int getTrashClasses() throws IllegalArgumentException { - if (this.map.containsKey("TrashClasses")) { - Object value = this.map.get("TrashClasses"); - if (value != null) { - if (!(value instanceof Integer)) - throw new IllegalArgumentException("TrashClasses arg must" + - " be an Integer"); - return (Integer) value; - } else { - throw new IllegalArgumentException("TrashClasses arg is null"); - } - } - - return -1; - } - - - /** - * Returns the watermark message from {@link Config#map} as a - * {@link String}. Defaults to null if null. - * - * @return Returns the crasher type from {@link Config#map} as a - * {@link String}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is null or - * not a {@link String} - */ - public String getWatermarkMsg() throws IllegalArgumentException { - if (this.map.containsKey("WatermarkMessage")) { - Object value = this.map.get("WatermarkMessage"); - if (value != null) { - return value.toString(); - } else { - throw new IllegalArgumentException("Watermark message is null"); - } - } - - return null; - } - - /** - * Returns the watermark type from {@link Config#map} as an - * {@link Integer}. Defaults to -1 if null. - * - * @return Returns the crasher type from {@link Config#map} - * as an {@link Integer}. Defaults to -1 if null. - * @throws IllegalArgumentException if value from key is unexpected, - * null or not a {@link String} - */ - public int getWatermarkType() throws IllegalArgumentException { - if (this.map.containsKey("WatermarkType")) { - Object value = this.map.get("WatermarkType"); - if (value != null) { - if (!(value instanceof String)) - throw new IllegalArgumentException("Watermark type arg " + - "must be a string"); - String s = (String) value; - if (s.equalsIgnoreCase("ConstantPool")) { - return 0; - } else if (s.equalsIgnoreCase("Signature")) { - return 1; - } else { - throw new IllegalArgumentException("Invalid watermark " + - "type arg: " + value); - } - } else { - throw new IllegalArgumentException("Watermark type arg is null"); - } - } - - return -1; - } - - /** - * Returns the watermark key from {@link Config#map} as a - * {@link String}. Defaults to null if null. - * - * @return Returns the crasher type from {@link Config#map} as a - * {@link String}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is null - * or not a {@link String} - */ - public String getWatermarkKey() throws IllegalArgumentException { - if (this.map.containsKey("WatermarkKey")) { - Object value = this.map.get("WatermarkKey"); - if (value != null) { - return value.toString(); - } else { - throw new IllegalArgumentException("Watermark key is null"); - } - } - - return null; - } - - /** - * Returns the boolean value of a spigot plugin from {@link Config#map} - * as a {@link Boolean}. Defaults to false if null. - * - * @return Returns the boolean value of a spigot plugin from - * {@link Config#map} as a {@link Boolean}. Defaults to false if null. - * @throws IllegalArgumentException if value from key is null or not - * a {@link Boolean} - */ - public boolean getSpigotBool() throws IllegalArgumentException { - if (this.map.containsKey("SpigotPlugin")) { - Object value = this.map.get("SpigotPlugin"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("Spigot plugin arg " + - "must be true/false"); - return (Boolean) value; - } else { - throw new IllegalArgumentException("Spigot plugin arg is null"); - } - } - - return false; - } - - /** - * Returns the renamer type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null or false. - * - * @return Returns the renamer type from {@link Config#map} - * as an {@link AbstractTransformer}. Defaults to null if null or false. - * @throws IllegalArgumentException if value from key is null or not - * a {@link Boolean} - */ - public AbstractTransformer getRenamerType() - throws IllegalArgumentException { - if (this.map.containsKey("Renamer")) { - Object value = this.map.get("Renamer"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("Renamer arg must be" + - " true/false"); - boolean s = (Boolean) value; - if (s) { - return new Renamer(getSpigotBool()); - } - } else { - throw new IllegalArgumentException("Renamer arg is null"); - } - } - - return null; - } - - /** - * Returns the string pool type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * - * @return Returns the string pool type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * @throws IllegalArgumentException if value from key is null or not - * a {@link Boolean} - */ - public AbstractTransformer getStringPoolType() - throws IllegalArgumentException { - if (this.map.containsKey("StringPool")) { - Object value = this.map.get("StringPool"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("String pool arg must " + - "be true/false"); - boolean s = (Boolean) value; - if (s) { - return new StringPool(); - } - } else { - throw new IllegalArgumentException("String pool arg is null"); - } - } - - return null; - } - - /** - * Returns the number obfuscation type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * - * @return Returns the number obfuscation type from {@link Config#map} as an - * {@link AbstractTransformer}. Defaults to null if null or false. - * @throws IllegalArgumentException if value from key is null or not - * a {@link Boolean} - */ - public AbstractTransformer getNumberObfuscationType() - throws IllegalArgumentException { - if (this.map.containsKey("NumberObfuscation")) { - Object value = this.map.get("NumberObfuscation"); - if (value != null) { - if (!(value instanceof Boolean)) - throw new IllegalArgumentException("Number obfuscation " + - "arg must be true/false"); - boolean s = (Boolean) value; - if (s) { - return new NumberObfuscation(); - } - } else { - throw new IllegalArgumentException("Number obfuscation arg is" + - " null"); - } - } - - return null; - } - - /** - * Returns the expiry time from {@link Config#map} as - * {@link Long}. Defaults to -1. - * - * @return the expiry time from {@link Config#map} as - * {@link Long}. Defaults to -1. - * @throws IllegalArgumentException if value from key is null or not a - * {@link String}, and/or is not a - * proper date format. - */ - public long getExpiryTime() throws IllegalArgumentException { - if (this.map.containsKey("ExpiryTime")) { - Object value = this.map.get("ExpiryTime"); - if (value != null) { - if (!(value instanceof String)) { - throw new IllegalArgumentException("Expiry time must be a" + - " string in simple date format"); - } - - String time = (String) value; - try { - SimpleDateFormat format - = new SimpleDateFormat("MM/dd/yyyy"); - Date date = format.parse(time); - return date.getTime(); - } catch (ParseException e) { - throw new IllegalArgumentException("Could not parse date " + - "as MM/dd/yyyy"); - } - } - } - - return -1; - } - - /** - * Returns the expiry message from {@link Config#map} as - * {@link Integer}. Defaults to null if null. - * - * @return Returns the crasher type from {@link Config#map} as - * {@link String}. Defaults to null if null. - * @throws IllegalArgumentException if value from key is null or - * not a {@link String}. - */ - public String getExpiryMsg() throws IllegalArgumentException { - if (this.map.containsKey("ExpiryMessage")) { - Object value = this.map.get("ExpiryMessage"); - if (value != null) { - return value.toString(); - } else { - throw new IllegalArgumentException("Expiry message is null"); - } - } - - return null; - } - - /** - * Returns the dictionary type from {@link Config#map} as an - * {@link Integer}. Defaults to 0 if null; - * - * @return Returns the dictionary type from {@link Config#map} as an - * {@link Integer}. Defaults to 0 if null. - * @throws IllegalArgumentException if value from key is null or not - * an {@link Integer} - */ - public int getDictionaryType() - throws IllegalArgumentException { - if (this.map.containsKey("Dictionary")) { - Object value = this.map.get("Dictionary"); - if (value != null) { - if (!(value instanceof Integer)) - throw new IllegalArgumentException("Dictionary arg must " + - "be an integer"); - return (Integer) value; - } else { - throw new IllegalArgumentException("Dictionary arg is null"); - } - } else { - return 0; - } - } -} diff --git a/src/main/java/me/itzsomebody/radon/config/ConfigWriter.java b/src/main/java/me/itzsomebody/radon/config/ConfigWriter.java deleted file mode 100644 index f4436048..00000000 --- a/src/main/java/me/itzsomebody/radon/config/ConfigWriter.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.config; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * Constructs a config in memory and writes to file. - * - * @author ItzSomebody - */ -public class ConfigWriter { - /** - * Key -> Value map. - */ - private Map keyValueMap; - - /** - * Lines to write to config. - */ - private List lines = new ArrayList<>(); - - /** - * Creates a new ConfigWriter object. - * - * @param keyValueMap Key -> Value map. - */ - public ConfigWriter(Map keyValueMap) { - this.keyValueMap = keyValueMap; - } - - /** - * Parses all options into a virtual config. - */ - public void parseOptions() { - for (ConfigEnum conf : ConfigEnum.values()) { - // Get config for enum value, if it exists, add line - Object result = keyValueMap.get(conf); - if (result == null) { - continue; - } - switch (conf) { - case LIBRARIES: - List libs = (List) result; - if (!libs.isEmpty()) { - lines.add("Libraries: "); - for (String lib : libs) { - lines.add(" - \"" + lib.replace("\\", "/") + "\""); - } - } - break; - case EXEMPTS: - List exempts = (List) result; - if (!exempts.isEmpty()) { - lines.add("Exempts: "); - for (String exempt : exempts) { - lines.add(" - \"" + exempt + "\""); - } - } - break; - case INPUT: - case OUTPUT: - lines.add(conf + ": \"" + result.toString().replace("\\", "/") + "\""); - break; - default: - lines.add(conf + ": " + result); - } - } - } - - /** - * Writes config to a file. - * - * @throws IOException if the file already exists, is an output or some - * other weird thing happens. - */ - public void writeConfig(String path) throws IOException { - File output = new File(path); - if (output.exists()) - throw new IOException(path + " already exists!"); - - if (output.isDirectory()) - throw new IOException(path + " needs to be a file, not a directory"); - - output.createNewFile(); - BufferedWriter stream = new BufferedWriter(new FileWriter(output)); - for (String line : this.lines) { - stream.write(line); - stream.write('\n'); - } - stream.close(); - } -} diff --git a/src/main/java/me/itzsomebody/radon/generate/InvokeDynamicBSMGenerator.java b/src/main/java/me/itzsomebody/radon/generate/InvokeDynamicBSMGenerator.java deleted file mode 100644 index 4effd5c8..00000000 --- a/src/main/java/me/itzsomebody/radon/generate/InvokeDynamicBSMGenerator.java +++ /dev/null @@ -1,692 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.generate; - -import java.lang.invoke.ConstantCallSite; - -import me.itzsomebody.radon.transformers.invokedynamic.HeavyInvokeDynamic; -import me.itzsomebody.radon.transformers.invokedynamic.LightInvokeDynamic; -import me.itzsomebody.radon.transformers.invokedynamic.NormalInvokeDynamic; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.MethodNode; - -/** - * That returns methods needed to produce a {@link ConstantCallSite} for - * the appropriate InvokeDynamic transformer. - * - * @author ItzSomebody - * @author ASMifier by OW2 - */ -public class InvokeDynamicBSMGenerator implements Opcodes { - /** - * Returns a {@link MethodNode} that returns a {@link ConstantCallSite} - * statically linked to a method for {@link LightInvokeDynamic}. - * - * @param bsmName used to determine the name of the generated - * {@link MethodNode}. - * @return a {@link MethodNode} that returns a {@link ConstantCallSite} - * statically linked to a method for {@link LightInvokeDynamic}. - */ - public static MethodNode lightBSM(String bsmName, String className) { - MethodNode mv = new MethodNode(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC - + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_BRIDGE, - bsmName, - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;)" + - "Ljava/lang/Object;", - null, - null); - mv.visitCode(); - Label l0 = new Label(); - Label l1 = new Label(); - Label l2 = new Label(); - mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception"); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 4); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", - "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 7); - Label l3 = new Label(); - mv.visitLabel(l3); - mv.visitVarInsn(ALOAD, 7); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 8); - Label l4 = new Label(); - mv.visitLabel(l4); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 9); - Label l5 = new Label(); - mv.visitLabel(l5); - Label l6 = new Label(); - mv.visitJumpInsn(GOTO, l6); - Label l7 = new Label(); - mv.visitLabel(l7); - mv.visitFrame(Opcodes.F_APPEND, 3, new Object[]{"[C", "[C", - Opcodes.INTEGER}, 0, null); - mv.visitVarInsn(ALOAD, 8); - mv.visitVarInsn(ILOAD, 9); - mv.visitVarInsn(ALOAD, 7); - mv.visitVarInsn(ILOAD, 9); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 1029); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l8 = new Label(); - mv.visitLabel(l8); - mv.visitIincInsn(9, 1); - mv.visitLabel(l6); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, - null); - mv.visitVarInsn(ILOAD, 9); - mv.visitVarInsn(ALOAD, 7); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l7); - Label l9 = new Label(); - mv.visitLabel(l9); - mv.visitVarInsn(ALOAD, 5); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", - "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 9); - Label l10 = new Label(); - mv.visitLabel(l10); - mv.visitVarInsn(ALOAD, 9); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 10); - Label l11 = new Label(); - mv.visitLabel(l11); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 11); - Label l12 = new Label(); - mv.visitLabel(l12); - Label l13 = new Label(); - mv.visitJumpInsn(GOTO, l13); - Label l14 = new Label(); - mv.visitLabel(l14); - mv.visitFrame(Opcodes.F_FULL, 12, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object", - "[C", "[C", "[C", "[C", Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 10); - mv.visitVarInsn(ILOAD, 11); - mv.visitVarInsn(ALOAD, 9); - mv.visitVarInsn(ILOAD, 11); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 2038); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l15 = new Label(); - mv.visitLabel(l15); - mv.visitIincInsn(11, 1); - mv.visitLabel(l13); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 11); - mv.visitVarInsn(ALOAD, 9); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l14); - Label l16 = new Label(); - mv.visitLabel(l16); - mv.visitVarInsn(ALOAD, 6); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", - "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 11); - Label l17 = new Label(); - mv.visitLabel(l17); - mv.visitVarInsn(ALOAD, 11); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 12); - Label l18 = new Label(); - mv.visitLabel(l18); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 13); - Label l19 = new Label(); - mv.visitLabel(l19); - Label l20 = new Label(); - mv.visitJumpInsn(GOTO, l20); - Label l21 = new Label(); - mv.visitLabel(l21); - mv.visitFrame(Opcodes.F_FULL, 14, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object", "[C", - "[C", "[C", "[C", "[C", "[C", Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 12); - mv.visitVarInsn(ILOAD, 13); - mv.visitVarInsn(ALOAD, 11); - mv.visitVarInsn(ILOAD, 13); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 1928); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l22 = new Label(); - mv.visitLabel(l22); - mv.visitIincInsn(13, 1); - mv.visitLabel(l20); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 13); - mv.visitVarInsn(ALOAD, 11); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l21); - Label l23 = new Label(); - mv.visitLabel(l23); - mv.visitVarInsn(ALOAD, 3); - mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", - "()I", false); - mv.visitVarInsn(ISTORE, 14); - Label l24 = new Label(); - mv.visitLabel(l24); - mv.visitVarInsn(ILOAD, 14); - Label l25 = new Label(); - Label l26 = new Label(); - Label l27 = new Label(); - mv.visitTableSwitchInsn(0, 1, l27, new Label[]{l25, l26}); - mv.visitLabel(l25); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", "[C", "[C", - "[C", "[C", "[C", "[C", Opcodes.TOP, Opcodes.INTEGER}, - 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 8); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", - "(Ljava/lang/String;)Ljava/lang/Class;", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 12); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitLdcInsn(Type.getType("L" + className + ";")); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", - "()Ljava/lang/ClassLoader;", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", - "fromMethodDescriptorString", - "(Ljava/lang/String;Ljava/lang/ClassLoader;)" + - "Ljava/lang/invoke/MethodType;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", - "findStatic", - "(Ljava/lang/Class;Ljava/lang/String;" + - "Ljava/lang/invoke/MethodType;)" + - "Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 13); - Label l28 = new Label(); - mv.visitLabel(l28); - Label l29 = new Label(); - mv.visitJumpInsn(GOTO, l29); - mv.visitLabel(l26); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 8); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", - "(Ljava/lang/String;)Ljava/lang/Class;", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 12); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitLdcInsn(Type.getType("L" + className + ";")); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", - "()Ljava/lang/ClassLoader;", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", - "fromMethodDescriptorString", "(Ljava/lang/String;" + - "Ljava/lang/ClassLoader;)" + - "Ljava/lang/invoke/MethodType;", - false); - mv.visitMethodInsn(INVOKEVIRTUAL, - "java/lang/invoke/MethodHandles$Lookup", "findVirtual", - "(Ljava/lang/Class;Ljava/lang/String;" + - "Ljava/lang/invoke/MethodType;)" + - "Ljava/lang/invoke/MethodHandle;", - false); - mv.visitVarInsn(ASTORE, 13); - Label l30 = new Label(); - mv.visitLabel(l30); - mv.visitJumpInsn(GOTO, l29); - mv.visitLabel(l27); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", "", "()V", - false); - mv.visitInsn(ATHROW); - mv.visitLabel(l29); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object", - "[C", "[C", "[C", "[C", "[C", "[C", - "java/lang/invoke/MethodHandle", Opcodes.INTEGER}, - 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 13); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodType"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", - "asType", "(Ljava/lang/invoke/MethodType;)" + - "Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 13); - Label l31 = new Label(); - mv.visitLabel(l31); - mv.visitTypeInsn(NEW, "java/lang/invoke/ConstantCallSite"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 13); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", - "", "(Ljava/lang/invoke/MethodHandle;)V", false); - mv.visitLabel(l1); - mv.visitInsn(ARETURN); - mv.visitLabel(l2); - mv.visitFrame(Opcodes.F_FULL, 7, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", "java/lang/Object"}, - 1, new Object[]{"java/lang/Exception"}); - mv.visitVarInsn(ASTORE, 7); - Label l32 = new Label(); - mv.visitLabel(l32); - mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", - "", "()V", false); - mv.visitInsn(ATHROW); - Label l33 = new Label(); - mv.visitLabel(l33); - mv.visitMaxs(6, 15); - mv.visitEnd(); - - return mv; - } - - /** - * Returns a {@link MethodNode} that returns a {@link ConstantCallSite} - * statically linked to a method for {@link NormalInvokeDynamic}. - * - * @param bsmName used to determine the name of the generated - * {@link MethodNode}. - * @return a {@link MethodNode} that returns a {@link ConstantCallSite} - * statically linked to a method for {@link NormalInvokeDynamic}. - */ - public static MethodNode normalBSM(String bsmName, String className) { - MethodNode mv = new MethodNode(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC - + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_BRIDGE, - bsmName, - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;)" + - "Ljava/lang/Object;", - null, - null); - mv.visitCode(); - Label l0 = new Label(); - Label l1 = new Label(); - Label l2 = new Label(); - mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable"); - Label l3 = new Label(); - Label l4 = new Label(); - Label l5 = new Label(); - mv.visitTryCatchBlock(l3, l4, l5, "java/lang/Exception"); - mv.visitLabel(l3); - mv.visitVarInsn(ALOAD, 4); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", - "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 7); - Label l6 = new Label(); - mv.visitLabel(l6); - mv.visitVarInsn(ALOAD, 7); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 8); - Label l7 = new Label(); - mv.visitLabel(l7); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 9); - Label l8 = new Label(); - mv.visitLabel(l8); - Label l9 = new Label(); - mv.visitJumpInsn(GOTO, l9); - Label l10 = new Label(); - mv.visitLabel(l10); - mv.visitFrame(Opcodes.F_APPEND, 3, new Object[]{"[C", "[C", - Opcodes.INTEGER}, 0, null); - mv.visitVarInsn(ALOAD, 8); - mv.visitVarInsn(ILOAD, 9); - mv.visitVarInsn(ALOAD, 7); - mv.visitVarInsn(ILOAD, 9); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 2893); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l11 = new Label(); - mv.visitLabel(l11); - mv.visitIincInsn(9, 1); - mv.visitLabel(l9); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 9); - mv.visitVarInsn(ALOAD, 7); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l10); - Label l12 = new Label(); - mv.visitLabel(l12); - mv.visitVarInsn(ALOAD, 5); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", - "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 9); - Label l13 = new Label(); - mv.visitLabel(l13); - mv.visitVarInsn(ALOAD, 9); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 10); - Label l14 = new Label(); - mv.visitLabel(l14); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 11); - Label l15 = new Label(); - mv.visitLabel(l15); - Label l16 = new Label(); - mv.visitJumpInsn(GOTO, l16); - Label l17 = new Label(); - mv.visitLabel(l17); - mv.visitFrame(Opcodes.F_FULL, 12, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "[C", "[C", "[C", "[C", Opcodes.INTEGER}, - 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 10); - mv.visitVarInsn(ILOAD, 11); - mv.visitVarInsn(ALOAD, 9); - mv.visitVarInsn(ILOAD, 11); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 2993); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l18 = new Label(); - mv.visitLabel(l18); - mv.visitIincInsn(11, 1); - mv.visitLabel(l16); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 11); - mv.visitVarInsn(ALOAD, 9); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l17); - Label l19 = new Label(); - mv.visitLabel(l19); - mv.visitVarInsn(ALOAD, 6); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", - "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 11); - Label l20 = new Label(); - mv.visitLabel(l20); - mv.visitVarInsn(ALOAD, 11); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 12); - Label l21 = new Label(); - mv.visitLabel(l21); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 13); - Label l22 = new Label(); - mv.visitLabel(l22); - Label l23 = new Label(); - mv.visitJumpInsn(GOTO, l23); - Label l24 = new Label(); - mv.visitLabel(l24); - mv.visitFrame(Opcodes.F_FULL, 14, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "[C", "[C", "[C", "[C", "[C", "[C", Opcodes.INTEGER}, - 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 12); - mv.visitVarInsn(ILOAD, 13); - mv.visitVarInsn(ALOAD, 11); - mv.visitVarInsn(ILOAD, 13); - mv.visitInsn(CALOAD); - mv.visitIntInsn(SIPUSH, 8372); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l25 = new Label(); - mv.visitLabel(l25); - mv.visitIincInsn(13, 1); - mv.visitLabel(l23); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 13); - mv.visitVarInsn(ALOAD, 11); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l24); - Label l26 = new Label(); - mv.visitLabel(l26); - mv.visitVarInsn(ALOAD, 3); - mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", - "()I", false); - mv.visitVarInsn(ISTORE, 14); - Label l27 = new Label(); - mv.visitLabel(l27); - mv.visitVarInsn(ILOAD, 14); - mv.visitIntInsn(SIPUSH, 256); - mv.visitInsn(ISHL); - mv.visitIntInsn(SIPUSH, 255); - mv.visitInsn(IAND); - mv.visitVarInsn(ISTORE, 14); - Label l28 = new Label(); - mv.visitLabel(l28); - mv.visitVarInsn(ILOAD, 14); - Label l29 = new Label(); - Label l30 = new Label(); - Label l31 = new Label(); - mv.visitTableSwitchInsn(0, 1, l31, new Label[]{l29, l30}); - mv.visitLabel(l29); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "[C", "[C", "[C", "[C", "[C", "[C", - Opcodes.TOP, Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 8); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", - "(Ljava/lang/String;)Ljava/lang/Class;", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 12); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitLdcInsn(Type.getType("L" + className + ";")); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", - "()Ljava/lang/ClassLoader;", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", - "fromMethodDescriptorString", - "(Ljava/lang/String;Ljava/lang/ClassLoader;)" + - "Ljava/lang/invoke/MethodType;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, - "java/lang/invoke/MethodHandles$Lookup", "findStatic", - "(Ljava/lang/Class;Ljava/lang/String;" + - "Ljava/lang/invoke/MethodType;)" + - "Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 13); - Label l32 = new Label(); - mv.visitLabel(l32); - Label l33 = new Label(); - mv.visitJumpInsn(GOTO, l33); - mv.visitLabel(l30); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodHandles$Lookup"); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 8); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", - "(Ljava/lang/String;)Ljava/lang/Class;", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 12); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitLdcInsn(Type.getType("L" + className + ";")); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", - "()Ljava/lang/ClassLoader;", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", - "fromMethodDescriptorString", - "(Ljava/lang/String;Ljava/lang/ClassLoader;)" + - "Ljava/lang/invoke/MethodType;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, - "java/lang/invoke/MethodHandles$Lookup", "findVirtual", - "(Ljava/lang/Class;Ljava/lang/String;" + - "Ljava/lang/invoke/MethodType;)" + - "Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 13); - Label l34 = new Label(); - mv.visitLabel(l34); - mv.visitJumpInsn(GOTO, l33); - mv.visitLabel(l31); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", - "", "()V", false); - mv.visitInsn(ATHROW); - mv.visitLabel(l33); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "[C", "[C", "[C", "[C", "[C", "[C", - "java/lang/invoke/MethodHandle", Opcodes.INTEGER}, - 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 13); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, "java/lang/invoke/MethodType"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", - "asType", - "(Ljava/lang/invoke/MethodType;)" + - "Ljava/lang/invoke/MethodHandle;", false); - mv.visitVarInsn(ASTORE, 13); - mv.visitLabel(l0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Runtime", - "getRuntime", "()Ljava/lang/Runtime;", false); - mv.visitMethodInsn(INVOKESTATIC, - "java/util/concurrent/ThreadLocalRandom", "current", - "()Ljava/util/concurrent/ThreadLocalRandom;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, - "java/util/concurrent/ThreadLocalRandom", "nextInt", - "()I", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", - "(I)Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Runtime", "exec", - "(Ljava/lang/String;)Ljava/lang/Process;", false); - mv.visitInsn(POP); - mv.visitLabel(l1); - Label l35 = new Label(); - mv.visitJumpInsn(GOTO, l35); - mv.visitLabel(l2); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 15); - mv.visitLabel(l35); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitTypeInsn(NEW, "java/lang/invoke/ConstantCallSite"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 13); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/invoke/ConstantCallSite", - "", "(Ljava/lang/invoke/MethodHandle;)V", false); - mv.visitLabel(l4); - mv.visitInsn(ARETURN); - mv.visitLabel(l5); - mv.visitFrame(Opcodes.F_FULL, 7, new Object[]{"java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object", - "java/lang/Object", "java/lang/Object"}, - 1, new Object[]{"java/lang/Exception"}); - mv.visitVarInsn(ASTORE, 7); - Label l36 = new Label(); - mv.visitLabel(l36); - mv.visitVarInsn(ALOAD, 7); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Exception", - "printStackTrace", "()V", false); - Label l37 = new Label(); - mv.visitLabel(l37); - mv.visitTypeInsn(NEW, "java/lang/BootstrapMethodError"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/BootstrapMethodError", - "", "()V", false); - mv.visitInsn(ATHROW); - Label l38 = new Label(); - mv.visitLabel(l38); - mv.visitMaxs(6, 16); - mv.visitEnd(); - return mv; - } -} diff --git a/src/main/java/me/itzsomebody/radon/generate/StringEncryptionGenerator.java b/src/main/java/me/itzsomebody/radon/generate/StringEncryptionGenerator.java deleted file mode 100644 index fb1e68f8..00000000 --- a/src/main/java/me/itzsomebody/radon/generate/StringEncryptionGenerator.java +++ /dev/null @@ -1,752 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.generate; - -import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.MethodNode; - -/** - * Class containing {@link MethodNode}s needed to decrypt a {@link String} for the - * appropriate StringEncryption transformer. - * - * @author ItzSomebody - * @author ASMifier by OW2 - */ -public class StringEncryptionGenerator implements Opcodes { - /** - * Returns a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link SuperLightStringEncryption}. - * - * @param decryptionMethodName used to determine the name of the - * generated {@link MethodNode}. - * @return a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link SuperLightStringEncryption}. - */ - public static MethodNode superLightMethod(String decryptionMethodName) { - MethodNode mv = new MethodNode(ACC_PUBLIC + ACC_STATIC - + ACC_SYNTHETIC + ACC_BRIDGE, decryptionMethodName, - "(Ljava/lang/String;I)Ljava/lang/String;", null, - null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 2); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitVarInsn(ALOAD, 2); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 3); - Label l2 = new Label(); - mv.visitLabel(l2); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 4); - Label l3 = new Label(); - mv.visitLabel(l3); - Label l4 = new Label(); - mv.visitJumpInsn(GOTO, l4); - Label l5 = new Label(); - mv.visitLabel(l5); - mv.visitFrame(Opcodes.F_APPEND, 3, new Object[]{"[C", "[C", - Opcodes.INTEGER}, 0, null); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ILOAD, 4); - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ILOAD, 4); - mv.visitInsn(CALOAD); - mv.visitVarInsn(ILOAD, 1); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l6 = new Label(); - mv.visitLabel(l6); - mv.visitIincInsn(4, 1); - mv.visitLabel(l4); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitVarInsn(ALOAD, 3); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l5); - Label l7 = new Label(); - mv.visitLabel(l7); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 3); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitInsn(ARETURN); - Label l8 = new Label(); - mv.visitLabel(l8); - mv.visitMaxs(4, 5); - mv.visitEnd(); - - return mv; - } - - /** - * Returns a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link LightStringEncryption}. - * - * @param decryptMethodName used to determine the name of the generated - * {@link MethodNode}. - * @return a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link LightStringEncryption}. - */ - public static MethodNode lightMethod(String decryptMethodName) { - MethodNode mv = new MethodNode(ACC_PUBLIC + ACC_STATIC + - ACC_SYNTHETIC + ACC_BRIDGE, decryptMethodName, - "(Ljava/lang/Object;I)Ljava/lang/String;", null, null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "length", "()I", - false); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 2); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 3); - Label l2 = new Label(); - mv.visitLabel(l2); - mv.visitTypeInsn(NEW, "java/lang/Throwable"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Throwable", "", - "()V", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", - "getStackTrace", "()[Ljava/lang/StackTraceElement;", false); - mv.visitVarInsn(ASTORE, 4); - Label l3 = new Label(); - mv.visitLabel(l3); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 5); - Label l4 = new Label(); - mv.visitLabel(l4); - Label l5 = new Label(); - mv.visitJumpInsn(GOTO, l5); - Label l6 = new Label(); - mv.visitLabel(l6); - mv.visitFrame(Opcodes.F_FULL, 6, new Object[]{"java/lang/Object", - Opcodes.INTEGER, "[C", "[C", "[Ljava/lang/StackTraceElement;", - Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitVarInsn(ALOAD, 4); - mv.visitInsn(ICONST_0); - mv.visitInsn(AALOAD); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getClassName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitInsn(I2C); - mv.visitVarInsn(ISTORE, 6); - Label l7 = new Label(); - mv.visitLabel(l7); - mv.visitVarInsn(ALOAD, 4); - mv.visitInsn(ICONST_0); - mv.visitInsn(AALOAD); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getMethodName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitInsn(I2C); - mv.visitVarInsn(ISTORE, 7); - Label l8 = new Label(); - mv.visitLabel(l8); - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ILOAD, 5); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ILOAD, 5); - mv.visitInsn(CALOAD); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(IXOR); - mv.visitVarInsn(ILOAD, 7); - mv.visitInsn(IXOR); - mv.visitVarInsn(ILOAD, 1); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l9 = new Label(); - mv.visitLabel(l9); - mv.visitIincInsn(5, 1); - mv.visitLabel(l5); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 5); - mv.visitVarInsn(ALOAD, 2); - mv.visitInsn(ARRAYLENGTH); - mv.visitJumpInsn(IF_ICMPLT, l6); - Label l10 = new Label(); - mv.visitLabel(l10); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitInsn(ARETURN); - Label l11 = new Label(); - mv.visitLabel(l11); - mv.visitMaxs(4, 8); - mv.visitEnd(); - - return mv; - } - - /** - * Returns a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link NormalStringEncryption}. - * - * @param decryptionMethodName used to determine the name of the - * generated {@link MethodNode}. - * @return a {@link MethodNode} that returns a {@link String} needed to - * decrypt strings encrypted by {@link NormalStringEncryption}. - */ - public static MethodNode normalMethod(String decryptionMethodName) { - MethodNode mv = new MethodNode(ACC_PUBLIC + ACC_STATIC + - ACC_BRIDGE + ACC_SYNTHETIC, decryptionMethodName, - "(Ljava/lang/Object;Ljava/lang/Object;I)Ljava/lang/String;", - null, null); - mv.visitCode(); - Label l0 = new Label(); - Label l1 = new Label(); - mv.visitTryCatchBlock(l0, l1, l1, "java/lang/Throwable"); - Label l2 = new Label(); - Label l3 = new Label(); - Label l4 = new Label(); - mv.visitTryCatchBlock(l2, l3, l4, "java/lang/Throwable"); - Label l5 = new Label(); - Label l6 = new Label(); - mv.visitTryCatchBlock(l5, l6, l4, "java/lang/Throwable"); - Label l7 = new Label(); - Label l8 = new Label(); - mv.visitTryCatchBlock(l7, l3, l8, "java/lang/Throwable"); - mv.visitTryCatchBlock(l5, l6, l8, "java/lang/Throwable"); - Label l9 = new Label(); - mv.visitTryCatchBlock(l4, l9, l8, "java/lang/Throwable"); - Label l10 = new Label(); - Label l11 = new Label(); - mv.visitTryCatchBlock(l10, l3, l11, "java/lang/Throwable"); - mv.visitTryCatchBlock(l5, l6, l11, "java/lang/Throwable"); - mv.visitTryCatchBlock(l4, l9, l11, "java/lang/Throwable"); - Label l12 = new Label(); - mv.visitTryCatchBlock(l8, l12, l11, "java/lang/Throwable"); - Label l13 = new Label(); - Label l14 = new Label(); - mv.visitTryCatchBlock(l13, l14, l11, "java/lang/Throwable"); - Label l15 = new Label(); - Label l16 = new Label(); - mv.visitTryCatchBlock(l15, l16, l11, "java/lang/Throwable"); - Label l17 = new Label(); - Label l18 = new Label(); - mv.visitTryCatchBlock(l17, l3, l18, "java/lang/Throwable"); - mv.visitTryCatchBlock(l5, l6, l18, "java/lang/Throwable"); - mv.visitTryCatchBlock(l4, l9, l18, "java/lang/Throwable"); - mv.visitTryCatchBlock(l8, l12, l18, "java/lang/Throwable"); - mv.visitTryCatchBlock(l13, l14, l18, "java/lang/Throwable"); - Label l19 = new Label(); - mv.visitTryCatchBlock(l15, l19, l18, "java/lang/Throwable"); - Label l20 = new Label(); - Label l21 = new Label(); - mv.visitTryCatchBlock(l20, l3, l21, "java/lang/Throwable"); - mv.visitTryCatchBlock(l5, l6, l21, "java/lang/Throwable"); - mv.visitTryCatchBlock(l4, l9, l21, "java/lang/Throwable"); - mv.visitTryCatchBlock(l8, l12, l21, "java/lang/Throwable"); - mv.visitTryCatchBlock(l13, l14, l21, "java/lang/Throwable"); - Label l22 = new Label(); - mv.visitTryCatchBlock(l15, l22, l21, "java/lang/Throwable"); - Label l23 = new Label(); - mv.visitLabel(l23); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ISTORE, 3); - Label l24 = new Label(); - mv.visitLabel(l24); - mv.visitVarInsn(ALOAD, 1); - Label l25 = new Label(); - mv.visitJumpInsn(IFNULL, l25); - mv.visitInsn(ICONST_1); - Label l26 = new Label(); - mv.visitJumpInsn(GOTO, l26); - mv.visitLabel(l25); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitInsn(ICONST_0); - mv.visitLabel(l26); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{Opcodes.INTEGER}); - mv.visitVarInsn(ISTORE, 4); - Label l27 = new Label(); - mv.visitLabel(l27); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitVarInsn(ILOAD, 3); - mv.visitVarInsn(ILOAD, 4); - Label l28 = new Label(); - mv.visitJumpInsn(IF_ICMPNE, l28); - Label l29 = new Label(); - mv.visitLabel(l29); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ASTORE, 0); - mv.visitLabel(l20); - mv.visitJumpInsn(GOTO, l28); - Label l30 = new Label(); - mv.visitLabel(l30); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 0); - Label l31 = new Label(); - mv.visitJumpInsn(IFNULL, l31); - Label l32 = new Label(); - mv.visitLabel(l32); - Label l33 = new Label(); - mv.visitJumpInsn(GOTO, l33); - mv.visitLabel(l17); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 1); - Label l34 = new Label(); - mv.visitJumpInsn(IFNONNULL, l34); - mv.visitLabel(l10); - Label l35 = new Label(); - mv.visitJumpInsn(GOTO, l35); - Label l36 = new Label(); - mv.visitLabel(l36); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 2); - mv.visitJumpInsn(IFEQ, l15); - Label l37 = new Label(); - mv.visitLabel(l37); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFNE, l35); - Label l38 = new Label(); - mv.visitLabel(l38); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 5); - Label l39 = new Label(); - mv.visitLabel(l39); - mv.visitVarInsn(ILOAD, 5); - Label l40 = new Label(); - mv.visitJumpInsn(IFEQ, l40); - Label l41 = new Label(); - mv.visitLabel(l41); - mv.visitInsn(ICONST_4); - mv.visitVarInsn(ISTORE, 6); - Label l42 = new Label(); - mv.visitLabel(l42); - Label l43 = new Label(); - mv.visitJumpInsn(GOTO, l43); - mv.visitLabel(l40); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitIntInsn(BIPUSH, 8); - mv.visitVarInsn(ISTORE, 6); - mv.visitLabel(l43); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ISTORE, 7); - Label l44 = new Label(); - mv.visitLabel(l44); - mv.visitVarInsn(ILOAD, 7); - Label l45 = new Label(); - mv.visitJumpInsn(IFNE, l45); - Label l46 = new Label(); - mv.visitLabel(l46); - mv.visitIntInsn(SIPUSH, 255); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(IOR); - mv.visitInsn(ICONST_4); - mv.visitInsn(ISHR); - mv.visitVarInsn(ISTORE, 8); - Label l47 = new Label(); - mv.visitLabel(l47); - Label l48 = new Label(); - mv.visitJumpInsn(GOTO, l48); - mv.visitLabel(l45); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitIntInsn(SIPUSH, 255); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(IAND); - mv.visitInsn(ICONST_3); - mv.visitInsn(ISHR); - mv.visitVarInsn(ISTORE, 8); - mv.visitLabel(l48); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitInsn(ICONST_2); - mv.visitVarInsn(ILOAD, 6); - mv.visitInsn(ISHL); - mv.visitVarInsn(ISTORE, 9); - Label l49 = new Label(); - mv.visitLabel(l49); - mv.visitVarInsn(ILOAD, 9); - Label l50 = new Label(); - Label l51 = new Label(); - Label l52 = new Label(); - mv.visitTableSwitchInsn(0, 1, l52, l50, l51); - mv.visitLabel(l50); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, - 0, null); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitVarInsn(ASTORE, 10); - Label l53 = new Label(); - mv.visitLabel(l53); - mv.visitJumpInsn(GOTO, l0); - mv.visitLabel(l51); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 9); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", - "(I)Ljava/lang/String;", false); - mv.visitVarInsn(ASTORE, 10); - Label l54 = new Label(); - mv.visitLabel(l54); - mv.visitJumpInsn(GOTO, l0); - mv.visitLabel(l52); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitVarInsn(ASTORE, 10); - mv.visitLabel(l0); - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{"java/lang/String"}, - 0, null); - mv.visitInsn(ICONST_3); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 12); - Label l55 = new Label(); - mv.visitLabel(l55); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_0); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l56 = new Label(); - mv.visitLabel(l56); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_1); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l57 = new Label(); - mv.visitLabel(l57); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_2); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_2); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l58 = new Label(); - mv.visitLabel(l58); - mv.visitVarInsn(ALOAD, 12); - mv.visitInsn(ICONST_3); - mv.visitVarInsn(ALOAD, 0); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ICONST_3); - mv.visitInsn(CALOAD); - mv.visitInsn(CASTORE); - Label l59 = new Label(); - mv.visitLabel(l59); - mv.visitTypeInsn(NEW, "java/lang/Throwable"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Throwable", "", - "()V", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", - "getStackTrace", "()[Ljava/lang/StackTraceElement;", false); - mv.visitVarInsn(ILOAD, 8); - mv.visitIntInsn(SIPUSH, 255); - mv.visitInsn(IOR); - mv.visitInsn(AALOAD); - mv.visitVarInsn(ASTORE, 11); - Label l60 = new Label(); - mv.visitLabel(l60); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l1); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 12); - Label l61 = new Label(); - mv.visitLabel(l61); - mv.visitTypeInsn(NEW, "java/lang/Throwable"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Throwable", "", - "()V", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", "getStackTrace", - "()[Ljava/lang/StackTraceElement;", false); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(ICONST_1); - mv.visitInsn(ISUB); - mv.visitInsn(AALOAD); - mv.visitVarInsn(ASTORE, 11); - Label l62 = new Label(); - mv.visitLabel(l62); - mv.visitVarInsn(ALOAD, 11); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getClassName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitVarInsn(ISTORE, 12); - Label l63 = new Label(); - mv.visitLabel(l63); - mv.visitVarInsn(ALOAD, 11); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StackTraceElement", - "getMethodName", "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "hashCode", - "()I", false); - mv.visitVarInsn(ISTORE, 13); - Label l64 = new Label(); - mv.visitLabel(l64); - mv.visitIntInsn(SIPUSH, 255); - mv.visitVarInsn(ILOAD, 8); - mv.visitIntInsn(SIPUSH, 255); - mv.visitInsn(IAND); - mv.visitInsn(IADD); - mv.visitVarInsn(ISTORE, 14); - Label l65 = new Label(); - mv.visitLabel(l65); - mv.visitJumpInsn(GOTO, l13); - mv.visitLabel(l7); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER, - "java/lang/String", "java/lang/StackTraceElement", - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER}, - 0, new Object[]{}); - mv.visitInsn(ICONST_4); - mv.visitVarInsn(ILOAD, 14); - mv.visitInsn(ISHL); - mv.visitVarInsn(ILOAD, 8); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(IADD); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(IADD); - mv.visitVarInsn(ILOAD, 8); - mv.visitInsn(IADD); - mv.visitInsn(ISUB); - mv.visitVarInsn(ISTORE, 15); - Label l66 = new Label(); - mv.visitLabel(l66); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFNE, l13); - Label l67 = new Label(); - mv.visitLabel(l67); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitVarInsn(ASTORE, 16); - Label l68 = new Label(); - mv.visitLabel(l68); - mv.visitVarInsn(ALOAD, 16); - mv.visitInsn(ARRAYLENGTH); - mv.visitIntInsn(NEWARRAY, T_CHAR); - mv.visitVarInsn(ASTORE, 17); - mv.visitLabel(l2); - mv.visitVarInsn(ILOAD, 4); - Label l69 = new Label(); - mv.visitJumpInsn(IFNE, l69); - Label l70 = new Label(); - mv.visitLabel(l70); - Label l71 = new Label(); - mv.visitJumpInsn(GOTO, l71); - Label l72 = new Label(); - mv.visitLabel(l72); - mv.visitFrame(Opcodes.F_APPEND, 3, new Object[]{Opcodes.INTEGER, - "[C", "[C"}, 0, null); - mv.visitVarInsn(ILOAD, 15); - mv.visitVarInsn(ALOAD, 10); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "toCharArray", - "()[C", false); - mv.visitInsn(ARRAYLENGTH); - Label l73 = new Label(); - mv.visitJumpInsn(IF_ICMPGE, l73); - Label l74 = new Label(); - mv.visitLabel(l74); - mv.visitVarInsn(ALOAD, 17); - mv.visitVarInsn(ILOAD, 15); - mv.visitVarInsn(ALOAD, 16); - mv.visitVarInsn(ILOAD, 15); - mv.visitInsn(CALOAD); - mv.visitVarInsn(ILOAD, 12); - mv.visitInsn(IXOR); - mv.visitVarInsn(ILOAD, 13); - mv.visitInsn(IXOR); - mv.visitVarInsn(ILOAD, 2); - mv.visitInsn(IXOR); - mv.visitInsn(I2C); - mv.visitInsn(CASTORE); - Label l75 = new Label(); - mv.visitLabel(l75); - mv.visitIincInsn(15, 1); - mv.visitLabel(l71); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l72); - mv.visitLabel(l73); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 8); - mv.visitVarInsn(ILOAD, 8); - mv.visitJumpInsn(IF_ICMPNE, l69); - Label l76 = new Label(); - mv.visitLabel(l76); - mv.visitJumpInsn(GOTO, l5); - mv.visitLabel(l69); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, "java/lang/String"); - mv.visitLabel(l3); - mv.visitInsn(ARETURN); - mv.visitLabel(l5); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitTypeInsn(NEW, "java/lang/String"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 17); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/String", "", - "([C)V", false); - mv.visitLabel(l6); - mv.visitInsn(ARETURN); - mv.visitLabel(l4); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 18); - mv.visitLabel(l9); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitLabel(l8); - mv.visitFrame(Opcodes.F_FULL, 15, new Object[]{"java/lang/Object", - "java/lang/Object", Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER, - "java/lang/String", "java/lang/StackTraceElement", - Opcodes.INTEGER, Opcodes.INTEGER, Opcodes.INTEGER}, - 1, new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 15); - mv.visitLabel(l12); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitLabel(l13); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 8); - mv.visitVarInsn(ILOAD, 6); - mv.visitIntInsn(BIPUSH, 7); - mv.visitInsn(ISHL); - mv.visitJumpInsn(IF_ICMPLT, l7); - mv.visitLabel(l14); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitLabel(l15); - mv.visitFrame(Opcodes.F_FULL, 5, new Object[]{"java/lang/Object", - "java/lang/Object", Opcodes.INTEGER, - Opcodes.INTEGER, Opcodes.INTEGER}, - 0, new Object[]{}); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l35); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l36); - mv.visitLabel(l16); - Label l77 = new Label(); - mv.visitJumpInsn(GOTO, l77); - mv.visitLabel(l11); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 5); - Label l78 = new Label(); - mv.visitLabel(l78); - mv.visitVarInsn(ALOAD, 5); - mv.visitInsn(ATHROW); - mv.visitLabel(l34); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l77); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l17); - mv.visitLabel(l19); - mv.visitJumpInsn(GOTO, l33); - mv.visitLabel(l18); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 5); - Label l79 = new Label(); - mv.visitLabel(l79); - mv.visitVarInsn(ALOAD, 5); - mv.visitInsn(ATHROW); - mv.visitLabel(l33); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l77); - Label l80 = new Label(); - mv.visitLabel(l80); - mv.visitJumpInsn(GOTO, l28); - mv.visitLabel(l31); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - mv.visitLabel(l28); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l30); - mv.visitLabel(l22); - Label l81 = new Label(); - mv.visitJumpInsn(GOTO, l81); - mv.visitLabel(l21); - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ASTORE, 5); - Label l82 = new Label(); - mv.visitLabel(l82); - mv.visitVarInsn(ALOAD, 5); - mv.visitInsn(ATHROW); - mv.visitLabel(l81); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitVarInsn(ILOAD, 4); - mv.visitJumpInsn(IFEQ, l27); - Label l83 = new Label(); - mv.visitLabel(l83); - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ATHROW); - Label l84 = new Label(); - mv.visitLabel(l84); - mv.visitMaxs(4, 19); - mv.visitEnd(); - - return mv; - } -} diff --git a/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java b/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java deleted file mode 100644 index 711cfd68..00000000 --- a/src/main/java/me/itzsomebody/radon/gui/ConsoleGUI.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.gui; - -import java.awt.*; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.io.PrintStream; -import javax.swing.*; -import me.itzsomebody.radon.Radon; - -/** - * Makes a "console" GUI so users can see log events when they use the - * GUI rather than the CLI. - * - * @author ItzSomebody - */ -public class ConsoleGUI { - /** - * This GUI JFrame. - */ - private JFrame thisFrame; - - /** - * Just the panel. - */ - private JPanel consolePanel; - - /** - * Scroll pane for the JTextArea. - */ - private JScrollPane consoleScrollPane; - - /** - * Logging area. - */ - private JTextArea consoleOutput; - /** - * Original PrintStream (System.out) so we can restore it later when needed. - */ - private PrintStream stdOut; - - /** - * Original PrintStream (System.err) so we can restore it later when needed. - */ - private PrintStream stdErr; - - /** - * Constructor to create a Console GUI. - */ - public ConsoleGUI() { - this.stdOut = System.out; - this.stdErr = System.err; - this.init(); - } - - /** - * Initializes the JFrame and its contents. - */ - private void init() { - this.thisFrame = new JFrame(); - this.thisFrame.setTitle(Radon.PREFIX + " " + Radon.VERSION); - this.thisFrame.setResizable(true); - this.thisFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - this.thisFrame.setLocationRelativeTo(null); - this.thisFrame.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - resetPrintStream(); - thisFrame.dispose(); - } - }); - this.thisFrame.setSize(600, 400); - this.thisFrame.setLocationRelativeTo(null); - this.consolePanel = new JPanel(new BorderLayout()); - this.consoleOutput = new JTextArea(); - this.consoleOutput.setFont(new Font("Arial", Font.PLAIN, 12)); - this.consoleOutput.setEditable(false); - this.consoleScrollPane = new JScrollPane(this.consoleOutput); - this.consolePanel.add(this.consoleScrollPane, "Center"); - this.thisFrame.getContentPane().add(this.consolePanel); - - PrintStream customPrintStream = new PrintStream(new OutputStreamRedirect(this.consoleOutput)); - System.setOut(customPrintStream); - System.setErr(customPrintStream); - - this.thisFrame.setVisible(true); - } - - /** - * Restores the default PrintStreams when the logging window is closed - */ - private void resetPrintStream() { - System.setOut(this.stdOut); - System.setErr(this.stdErr); - } -} diff --git a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java b/src/main/java/me/itzsomebody/radon/gui/MainGUI.java deleted file mode 100644 index 24b3d1f1..00000000 --- a/src/main/java/me/itzsomebody/radon/gui/MainGUI.java +++ /dev/null @@ -1,1887 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.gui; - -import java.awt.*; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javax.swing.*; - -import me.itzsomebody.radon.Radon; -import me.itzsomebody.radon.config.Config; -import me.itzsomebody.radon.config.ConfigEnum; -import me.itzsomebody.radon.config.ConfigWriter; -import me.itzsomebody.radon.internal.Bootstrap; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.transformers.flow.HeavyFlowObfuscation; -import me.itzsomebody.radon.transformers.flow.LightFlowObfuscation; -import me.itzsomebody.radon.transformers.flow.NormalFlowObfuscation; -import me.itzsomebody.radon.transformers.invokedynamic.HeavyInvokeDynamic; -import me.itzsomebody.radon.transformers.invokedynamic.LightInvokeDynamic; -import me.itzsomebody.radon.transformers.invokedynamic.NormalInvokeDynamic; -import me.itzsomebody.radon.transformers.linenumbers.ObfuscateLineNumbers; -import me.itzsomebody.radon.transformers.linenumbers.RemoveLineNumbers; -import me.itzsomebody.radon.transformers.localvariables.ObfuscateLocalVariables; -import me.itzsomebody.radon.transformers.localvariables.RemoveLocalVariables; -import me.itzsomebody.radon.transformers.misc.Crasher; -import me.itzsomebody.radon.transformers.misc.Expiry; -import me.itzsomebody.radon.transformers.misc.HideCode; -import me.itzsomebody.radon.transformers.misc.InnerClassRemover; -import me.itzsomebody.radon.transformers.misc.NumberObfuscation; -import me.itzsomebody.radon.transformers.misc.Shuffler; -import me.itzsomebody.radon.transformers.misc.StringPool; -import me.itzsomebody.radon.transformers.misc.Renamer; -import me.itzsomebody.radon.transformers.sourcedebug.ObfuscateSourceDebug; -import me.itzsomebody.radon.transformers.sourcedebug.RemoveSourceDebug; -import me.itzsomebody.radon.transformers.sourcename.ObfuscateSourceName; -import me.itzsomebody.radon.transformers.sourcename.RemoveSourceName; -import me.itzsomebody.radon.transformers.stringencryption.HeavyStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; -import me.itzsomebody.radon.utils.WatermarkUtils; - - -/** - * This is pretty much all Eclipse WindowBuilder - * - * @author ItzSomebody - * @author Eclipse WindowBuilder - */ -public class MainGUI { - private JFrame frmRadonObfuscator; - private JTextField inputField; - private JTextField outputField; - private JTextField exemptField; - private JTextField trashChanceField; - private JTextField waterMarkMessageField; - private JTextField expirationDateField; - private JTextField expirationMessageField; - private JPasswordField watermarkPassword; - private JTextField extractorInput; - private JPasswordField extractorKey; - private File lastPath; - - /** - * Create the application. - */ - public MainGUI() { - initialize(); - } - - /** - * Initialize the contents of the frame. - */ - private void initialize() { - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (Exception exception) { - // exception.printStackTrace(); - } - this.frmRadonObfuscator = new JFrame(); - this.frmRadonObfuscator.setTitle(Radon.PREFIX + " " + Radon.VERSION); - this.frmRadonObfuscator.setSize(440, 570); - this.frmRadonObfuscator.setLocationRelativeTo(null); - this.frmRadonObfuscator.setResizable(true); - this.frmRadonObfuscator - .setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - this.frmRadonObfuscator.getContentPane() - .setLayout(new BorderLayout(0, 0)); - - JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); - this.frmRadonObfuscator.getContentPane().add(tabbedPane); - - JPanel panel_4 = new JPanel(); - tabbedPane.addTab("Files", null, panel_4, null); - GridBagLayout gbl_panel_4 = new GridBagLayout(); - gbl_panel_4.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0}; - gbl_panel_4.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0}; - gbl_panel_4.columnWeights = new double[]{0.0, 0.0, 1.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - gbl_panel_4.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, Double.MIN_VALUE}; - panel_4.setLayout(gbl_panel_4); - - JLabel lblInput = new JLabel("Input:"); - GridBagConstraints gbc_lblInput = new GridBagConstraints(); - gbc_lblInput.anchor = GridBagConstraints.EAST; - gbc_lblInput.insets = new Insets(0, 0, 5, 5); - gbc_lblInput.gridx = 1; - gbc_lblInput.gridy = 1; - panel_4.add(lblInput, gbc_lblInput); - - this.inputField = new JTextField(); - GridBagConstraints gbc_textField_1 = new GridBagConstraints(); - gbc_textField_1.gridwidth = 9; - gbc_textField_1.insets = new Insets(0, 0, 5, 5); - gbc_textField_1.fill = GridBagConstraints.HORIZONTAL; - gbc_textField_1.gridx = 2; - gbc_textField_1.gridy = 1; - panel_4.add(this.inputField, gbc_textField_1); - this.inputField.setColumns(10); - - JButton btnNewButton = new JButton("Select"); - GridBagConstraints gbc_btnNewButton = new GridBagConstraints(); - gbc_btnNewButton.fill = GridBagConstraints.HORIZONTAL; - gbc_btnNewButton.insets = new Insets(0, 0, 5, 5); - gbc_btnNewButton.gridx = 11; - gbc_btnNewButton.gridy = 1; - btnNewButton.addActionListener((e) -> { - JFileChooser chooser = new JFileChooser(); - if (inputField.getText() != null - && !inputField.getText().isEmpty()) { - chooser.setSelectedFile(new File(inputField.getText())); - } - chooser.setMultiSelectionEnabled(false); - chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - if (lastPath != null) - chooser.setCurrentDirectory(lastPath); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(() -> { - inputField.setText(chooser.getSelectedFile().getAbsolutePath()); - lastPath = chooser.getSelectedFile(); - }); - } - }); - panel_4.add(btnNewButton, gbc_btnNewButton); - - JLabel lblOutput = new JLabel("Output:"); - GridBagConstraints gbc_lblOutput = new GridBagConstraints(); - gbc_lblOutput.insets = new Insets(0, 0, 5, 5); - gbc_lblOutput.anchor = GridBagConstraints.EAST; - gbc_lblOutput.gridx = 1; - gbc_lblOutput.gridy = 2; - panel_4.add(lblOutput, gbc_lblOutput); - - this.outputField = new JTextField(); - GridBagConstraints gbc_textField_2 = new GridBagConstraints(); - gbc_textField_2.gridwidth = 9; - gbc_textField_2.insets = new Insets(0, 0, 5, 5); - gbc_textField_2.fill = GridBagConstraints.HORIZONTAL; - gbc_textField_2.gridx = 2; - gbc_textField_2.gridy = 2; - panel_4.add(this.outputField, gbc_textField_2); - this.outputField.setColumns(10); - - JButton btnNewButton_1 = new JButton("Select"); - GridBagConstraints gbc_btnNewButton_1 = new GridBagConstraints(); - gbc_btnNewButton_1.fill = GridBagConstraints.HORIZONTAL; - gbc_btnNewButton_1.insets = new Insets(0, 0, 5, - 5); - gbc_btnNewButton_1.gridx = 11; - gbc_btnNewButton_1.gridy = 2; - btnNewButton_1.addActionListener((e) -> { - JFileChooser chooser = new JFileChooser(); - if (outputField.getText() != null - && !outputField.getText().isEmpty()) { - chooser.setSelectedFile(new File(outputField.getText())); - } - chooser.setMultiSelectionEnabled(false); - chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - if (lastPath != null) - chooser.setCurrentDirectory(lastPath); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(() -> { - outputField.setText(chooser.getSelectedFile().getAbsolutePath()); - lastPath = chooser.getSelectedFile(); - }); - } - }); - panel_4.add(btnNewButton_1, gbc_btnNewButton_1); - - JSeparator separator_2 = new JSeparator(); - GridBagConstraints gbc_separator_2 = new GridBagConstraints(); - gbc_separator_2.fill = GridBagConstraints.HORIZONTAL; - gbc_separator_2.gridwidth = 13; - gbc_separator_2.insets = new Insets(0, 0, 5, 0); - gbc_separator_2.gridx = 0; - gbc_separator_2.gridy = 3; - panel_4.add(separator_2, gbc_separator_2); - - JLabel lblNewLabel_6 = new JLabel("Libraries:"); - GridBagConstraints gbc_lblNewLabel_6 = new GridBagConstraints(); - gbc_lblNewLabel_6.anchor = GridBagConstraints.EAST; - gbc_lblNewLabel_6.insets = new Insets(0, 0, 5, 0); - gbc_lblNewLabel_6.gridx = 1; - gbc_lblNewLabel_6.gridy = 4; - panel_4.add(lblNewLabel_6, gbc_lblNewLabel_6); - - JScrollPane scrollPane_2 = new JScrollPane(); - GridBagConstraints gbc_scrollPane_2 = new GridBagConstraints(); - gbc_scrollPane_2.gridheight = 13; - gbc_scrollPane_2.gridwidth = 9; - gbc_scrollPane_2.insets = new Insets(0, 0, 5, 5); - gbc_scrollPane_2.fill = GridBagConstraints.BOTH; - gbc_scrollPane_2.gridx = 2; - gbc_scrollPane_2.gridy = 4; - panel_4.add(scrollPane_2, gbc_scrollPane_2); - - DefaultListModel libList = new DefaultListModel<>(); - String jreHome = System.getProperty("java.home"); - if (jreHome != null) { - libList.addElement(jreHome + "/lib/rt.jar"); - libList.addElement(jreHome + "/lib/jce.jar"); - } - - JList list_2 = new JList<>(libList); - list_2.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - scrollPane_2.setViewportView(list_2); - - JButton btnNewButton_6 = new JButton("Add"); - btnNewButton_6.addActionListener((e) -> { - JFileChooser chooser = new JFileChooser(); - if (inputField.getText() != null - && !inputField.getText().isEmpty()) { - chooser.setSelectedFile(new File(inputField.getText())); - } - chooser.setMultiSelectionEnabled(true); - chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - if (lastPath != null) - chooser.setCurrentDirectory(lastPath); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(() -> { - for (File file : chooser.getSelectedFiles()) { - libList.addElement(file.getAbsolutePath()); - } - - lastPath = chooser.getSelectedFile(); - }); - } - }); - GridBagConstraints gbc_btnNewButton_6 = new GridBagConstraints(); - gbc_btnNewButton_6.fill = GridBagConstraints.HORIZONTAL; - gbc_btnNewButton_6.insets = new Insets(0, 0, 5, 5); - gbc_btnNewButton_6.gridx = 11; - gbc_btnNewButton_6.gridy = 15; - panel_4.add(btnNewButton_6, gbc_btnNewButton_6); - - JButton btnNewButton_7 = new JButton("Remove"); - btnNewButton_7.addActionListener((e) -> { - List removeList = list_2.getSelectedValuesList(); - if (removeList.isEmpty()) - return; - - for (String s : removeList) { - libList.removeElement(s); - } - }); - GridBagConstraints gbc_btnNewButton_7 = new GridBagConstraints(); - gbc_btnNewButton_7.fill = GridBagConstraints.HORIZONTAL; - gbc_btnNewButton_7.insets = new Insets(0, 0, 5, 5); - gbc_btnNewButton_7.gridx = 11; - gbc_btnNewButton_7.gridy = 16; - panel_4.add(btnNewButton_7, gbc_btnNewButton_7); - - JPanel panel = new JPanel(); - tabbedPane.addTab("Obfuscation", null, panel, null); - GridBagLayout gbl_panel = new GridBagLayout(); - gbl_panel.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 75, 0, 0}; - gbl_panel.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0}; - gbl_panel.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, Double.MIN_VALUE}; - gbl_panel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - Double.MIN_VALUE}; - panel.setLayout(gbl_panel); - - JComboBox comboBox = new JComboBox<>(); - comboBox.setEnabled(false); - GridBagConstraints gbc_comboBox = new GridBagConstraints(); - gbc_comboBox.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox.insets = new Insets(0, 0, 5, 5); - gbc_comboBox.gridx = 9; - gbc_comboBox.gridy = 0; - String[] encryptions = {"SuperLight", "Light", "Normal", "Heavy"}; - for (String s : encryptions) { - comboBox.addItem(s); - } - panel.add(comboBox, gbc_comboBox); - - JCheckBox chckbxStringEncryption = new JCheckBox("String Encryption"); - GridBagConstraints gbc_chckbxStringEncryption = new GridBagConstraints(); - gbc_chckbxStringEncryption.anchor = GridBagConstraints.WEST; - gbc_chckbxStringEncryption.insets = new Insets(0, 0, 5, 5); - gbc_chckbxStringEncryption.gridx = 0; - gbc_chckbxStringEncryption.gridy = 0; - chckbxStringEncryption.addActionListener((e) -> { - if (chckbxStringEncryption.isSelected()) { - comboBox.setEnabled(true); - } else if (!chckbxStringEncryption.isSelected()) { - comboBox.setEnabled(false); - } - }); - panel.add(chckbxStringEncryption, gbc_chckbxStringEncryption); - - JComboBox comboBox_1 = new JComboBox<>(); - comboBox_1.setEnabled(false); - GridBagConstraints gbc_comboBox_1 = new GridBagConstraints(); - gbc_comboBox_1.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox_1.insets = new Insets(0, 0, 5, 5); - gbc_comboBox_1.gridx = 9; - gbc_comboBox_1.gridy = 1; - String[] invokeDynamics = {"Light", "Normal", "Heavy"}; - for (String s : invokeDynamics) { - comboBox_1.addItem(s); - } - panel.add(comboBox_1, gbc_comboBox_1); - - JCheckBox chckbxInvokeDynamic = new JCheckBox("InvokeDynamic"); - GridBagConstraints gbc_chckbxNewCheckBox_1 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_1.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_1.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_1.gridx = 0; - gbc_chckbxNewCheckBox_1.gridy = 1; - chckbxInvokeDynamic.addActionListener((e) -> { - if (chckbxInvokeDynamic.isSelected()) { - comboBox_1.setEnabled(true); - } else if (!chckbxInvokeDynamic.isSelected()) { - comboBox_1.setEnabled(false); - } - }); - - panel.add(chckbxInvokeDynamic, gbc_chckbxNewCheckBox_1); - - JComboBox comboBox_2 = new JComboBox<>(); - comboBox_2.setEnabled(false); - GridBagConstraints gbc_comboBox_2 = new GridBagConstraints(); - gbc_comboBox_2.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox_2.insets = new Insets(0, 0, 5, 5); - gbc_comboBox_2.gridx = 9; - gbc_comboBox_2.gridy = 2; - String[] flows = {"Light", "Normal", "Heavy"}; - for (String s : flows) { - comboBox_2.addItem(s); - } - panel.add(comboBox_2, gbc_comboBox_2); - - JCheckBox chckbxFlow = new JCheckBox("Flow"); - GridBagConstraints gbc_chckbxFlow = new GridBagConstraints(); - gbc_chckbxFlow.insets = new Insets(0, 0, 5, 5); - gbc_chckbxFlow.anchor = GridBagConstraints.WEST; - gbc_chckbxFlow.gridx = 0; - gbc_chckbxFlow.gridy = 2; - chckbxFlow.addActionListener((e) -> { - if (chckbxFlow.isSelected()) { - comboBox_2.setEnabled(true); - } else if (!chckbxFlow.isSelected()) { - comboBox_2.setEnabled(false); - } - }); - panel.add(chckbxFlow, gbc_chckbxFlow); - - JComboBox comboBox_3 = new JComboBox<>(); - comboBox_3.setEnabled(false); - GridBagConstraints gbc_comboBox_3 = new GridBagConstraints(); - gbc_comboBox_3.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox_3.insets = new Insets(0, 0, 5, 5); - gbc_comboBox_3.gridx = 9; - gbc_comboBox_3.gridy = 3; - String[] localVariables = {"Obfuscate", "Remove"}; - for (String s : localVariables) { - comboBox_3.addItem(s); - } - panel.add(comboBox_3, gbc_comboBox_3); - - JCheckBox chckbxLocalVariables = new JCheckBox("Local Variables"); - GridBagConstraints gbc_chckbxNewCheckBox_2 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_2.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_2.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_2.gridx = 0; - gbc_chckbxNewCheckBox_2.gridy = 3; - chckbxLocalVariables.addActionListener((e) -> { - if (chckbxLocalVariables.isSelected()) { - comboBox_3.setEnabled(true); - } else if (!chckbxLocalVariables.isSelected()) { - comboBox_3.setEnabled(false); - } - }); - panel.add(chckbxLocalVariables, gbc_chckbxNewCheckBox_2); - - this.trashChanceField = new JTextField(); - this.trashChanceField.setToolTipText("Number of trash classes to " + - "generate"); - this.trashChanceField.setEditable(false); - this.trashChanceField.setText("10"); - GridBagConstraints gbc_textField = new GridBagConstraints(); - gbc_textField.fill = GridBagConstraints.HORIZONTAL; - gbc_textField.insets = new Insets(0, 0, 5, 5); - gbc_textField.gridx = 9; - gbc_textField.gridy = 7; - panel.add(this.trashChanceField, gbc_textField); - this.trashChanceField.setColumns(3); - - JCheckBox chckbxTrashClasses = new JCheckBox("Trash Classes"); - GridBagConstraints gbc_chckbxNewCheckBox_3 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_3.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_3.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_3.gridx = 0; - gbc_chckbxNewCheckBox_3.gridy = 7; - chckbxTrashClasses.addActionListener((e) -> { - if (chckbxTrashClasses.isSelected()) { - trashChanceField.setEditable(true); - } else if (!chckbxTrashClasses.isSelected()) { - trashChanceField.setEditable(false); - } - }); - panel.add(chckbxTrashClasses, gbc_chckbxNewCheckBox_3); - - JComboBox comboBox_123 = new JComboBox<>(); - comboBox_123.setEnabled(false); - GridBagConstraints gbc_comboBox_4 = new GridBagConstraints(); - gbc_comboBox_4.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox_4.insets = new Insets(0, 0, 5, 5); - gbc_comboBox_4.gridx = 9; - gbc_comboBox_4.gridy = 5; - String[] sourceNameTypes = {"Obfuscate", "Remove"}; - for (String s : sourceNameTypes) { - comboBox_123.addItem(s); - } - panel.add(comboBox_123, gbc_comboBox_4); - - JCheckBox chckbxSourceName = new JCheckBox("Source Name"); - GridBagConstraints gbc_chckbxNewCheckBox_123 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_123.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_123.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_123.gridx = 0; - gbc_chckbxNewCheckBox_123.gridy = 5; - chckbxSourceName.addActionListener((e) -> { - if (chckbxSourceName.isSelected()) { - comboBox_123.setEnabled(true); - } else { - comboBox_123.setEnabled(false); - } - }); - panel.add(chckbxSourceName, gbc_chckbxNewCheckBox_123); - - JComboBox comboBox_1234 = new JComboBox<>(); - comboBox_1234.setEnabled(false); - GridBagConstraints gbc_comboBox1234 = new GridBagConstraints(); - gbc_comboBox1234.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox1234.insets = new Insets(0, 0, 5, 5); - gbc_comboBox1234.gridx = 9; - gbc_comboBox1234.gridy = 6; - String[] sourceDebugTypes = {"Obfuscate", "Remove"}; - for (String s : sourceDebugTypes) { - comboBox_1234.addItem(s); - } - panel.add(comboBox_1234, gbc_comboBox1234); - - JCheckBox chckbxSourceDebug = new JCheckBox("Source Debug"); - GridBagConstraints gbc_SourceDebug = new GridBagConstraints(); - gbc_SourceDebug.anchor = GridBagConstraints.WEST; - gbc_SourceDebug.insets = new Insets(0, 0, 5, 5); - gbc_SourceDebug.gridx = 0; - gbc_SourceDebug.gridy = 6; - chckbxSourceDebug.addActionListener((e) -> { - if (chckbxSourceDebug.isSelected()) { - comboBox_1234.setEnabled(true); - } else { - comboBox_1234.setEnabled(false); - } - }); - panel.add(chckbxSourceDebug, gbc_SourceDebug); - - JComboBox comboBox_5 = new JComboBox<>(); - comboBox_5.setEnabled(false); - GridBagConstraints gbc_comboBox_5 = new GridBagConstraints(); - gbc_comboBox_5.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox_5.insets = new Insets(0, 0, 5, 5); - gbc_comboBox_5.gridx = 9; - gbc_comboBox_5.gridy = 4; - String[] lineTypes = {"Obfuscate", "Remove"}; - for (String s : lineTypes) { - comboBox_5.addItem(s); - } - panel.add(comboBox_5, gbc_comboBox_5); - - JCheckBox chckbxLineObfuscation = new JCheckBox("Lines"); - GridBagConstraints gbc_chckbxNewCheckBox_10 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_10.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_10.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_10.gridx = 0; - gbc_chckbxNewCheckBox_10.gridy = 4; - chckbxLineObfuscation.addActionListener((e) -> { - if (chckbxLineObfuscation.isSelected()) { - comboBox_5.setEnabled(true); - } else { - comboBox_5.setEnabled(false); - } - }); - panel.add(chckbxLineObfuscation, gbc_chckbxNewCheckBox_10); - - JCheckBox chckbxSpringPool = new JCheckBox("String Pool"); - GridBagConstraints gbc_chckbxNewCheckBox = new GridBagConstraints(); - gbc_chckbxNewCheckBox.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox.anchor = GridBagConstraints.NORTHWEST; - gbc_chckbxNewCheckBox.gridx = 0; - gbc_chckbxNewCheckBox.gridy = 8; - panel.add(chckbxSpringPool, gbc_chckbxNewCheckBox); - - JCheckBox chckbxCrasher = new JCheckBox("Crasher"); - GridBagConstraints gbc_chckbxAntidecompiler = new GridBagConstraints(); - gbc_chckbxAntidecompiler.anchor = GridBagConstraints.WEST; - gbc_chckbxAntidecompiler.insets = new Insets(0, 0, 5, 5); - gbc_chckbxAntidecompiler.gridx = 0; - gbc_chckbxAntidecompiler.gridy = 9; - panel.add(chckbxCrasher, gbc_chckbxAntidecompiler); - - JCheckBox chckbxHidecode = new JCheckBox("Hide Code"); - GridBagConstraints gbc_chckbxNewCheckBox_4 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_4.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_4.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_4.gridx = 0; - gbc_chckbxNewCheckBox_4.gridy = 10; - panel.add(chckbxHidecode, gbc_chckbxNewCheckBox_4); - - JCheckBox chckbxNumberObfuscation - = new JCheckBox("Number Obfuscation"); - GridBagConstraints gbc_chckbxNewCheckBox_9 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_9.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_9.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_9.gridx = 0; - gbc_chckbxNewCheckBox_9.gridy = 11; - panel.add(chckbxNumberObfuscation, gbc_chckbxNewCheckBox_9); - - JCheckBox chckbxSpigotPlugin = new JCheckBox("Spigot Plugin"); - chckbxSpigotPlugin.setToolTipText("Prevents string encryption from " + - "encrypting strings that contain %%__USER__%% or " + - "%%__RESOURCE__%% or %%__NONCE__%%."); - GridBagConstraints gbc_chckbxNewCheckBox_7 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_7.anchor = GridBagConstraints.WEST; - gbc_chckbxNewCheckBox_7.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_7.gridx = 0; - gbc_chckbxNewCheckBox_7.gridy = 12; - panel.add(chckbxSpigotPlugin, gbc_chckbxNewCheckBox_7); - - JCheckBox chckbxClassRenammer = new JCheckBox("Member Renamer"); - GridBagConstraints gbc_chckbxClassRenammer = new GridBagConstraints(); - gbc_chckbxClassRenammer.anchor = GridBagConstraints.WEST; - gbc_chckbxClassRenammer.insets = new Insets(0, 0, 5, 5); - gbc_chckbxClassRenammer.gridx = 0; - gbc_chckbxClassRenammer.gridy = 13; - panel.add(chckbxClassRenammer, gbc_chckbxClassRenammer); - - JCheckBox chckbxShuffler = new JCheckBox("Member Shuffler"); - GridBagConstraints gbc_chckbxShuffler = new GridBagConstraints(); - gbc_chckbxShuffler.anchor = GridBagConstraints.WEST; - gbc_chckbxShuffler.insets = new Insets(0, 0, 5, 5); - gbc_chckbxShuffler.gridx = 0; - gbc_chckbxShuffler.gridy = 14; - panel.add(chckbxShuffler, gbc_chckbxShuffler); - - JCheckBox chckbxInnerClasses - = new JCheckBox("InnerClasses Remover"); - GridBagConstraints gbc_chckbxInnerClasses = new GridBagConstraints(); - gbc_chckbxInnerClasses.anchor = GridBagConstraints.WEST; - gbc_chckbxInnerClasses.insets = new Insets(0, 0, 5, 5); - gbc_chckbxInnerClasses.gridx = 0; - gbc_chckbxInnerClasses.gridy = 15; - panel.add(chckbxInnerClasses, gbc_chckbxInnerClasses); - - JPanel panel_2 = new JPanel(); - tabbedPane.addTab("Watermark", null, panel_2, null); - GridBagLayout gbl_panel_2 = new GridBagLayout(); - gbl_panel_2.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 59, 0, 0}; - gbl_panel_2.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - gbl_panel_2.columnWeights = new double[]{0.0, 1.0, 1.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - gbl_panel_2.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE}; - panel_2.setLayout(gbl_panel_2); - - JLabel lblNewLabel_1 = new JLabel("Message:"); - GridBagConstraints gbc_lblNewLabel_1 = new GridBagConstraints(); - gbc_lblNewLabel_1.insets = new Insets(0, 0, 5, 5); - gbc_lblNewLabel_1.anchor = GridBagConstraints.EAST; - gbc_lblNewLabel_1.gridx = 0; - gbc_lblNewLabel_1.gridy = 2; - panel_2.add(lblNewLabel_1, gbc_lblNewLabel_1); - - this.waterMarkMessageField = new JTextField(); - this.waterMarkMessageField.setEnabled(false); - GridBagConstraints gbc_textField_4 = new GridBagConstraints(); - gbc_textField_4.gridwidth = 11; - gbc_textField_4.insets = new Insets(0, 0, 5, 5); - gbc_textField_4.fill = GridBagConstraints.HORIZONTAL; - gbc_textField_4.gridx = 1; - gbc_textField_4.gridy = 2; - panel_2.add(this.waterMarkMessageField, gbc_textField_4); - this.waterMarkMessageField.setColumns(10); - - JLabel lblNewLabel_2 = new JLabel("Key:"); - GridBagConstraints gbc_lblNewLabel_2 = new GridBagConstraints(); - gbc_lblNewLabel_2.insets = new Insets(0, 0, 5, 5); - gbc_lblNewLabel_2.anchor = GridBagConstraints.EAST; - gbc_lblNewLabel_2.gridx = 0; - gbc_lblNewLabel_2.gridy = 3; - panel_2.add(lblNewLabel_2, gbc_lblNewLabel_2); - - this.watermarkPassword = new JPasswordField(); - this.watermarkPassword.setEnabled(false); - GridBagConstraints gbc_passwordField = new GridBagConstraints(); - gbc_passwordField.gridwidth = 11; - gbc_passwordField.insets = new Insets(0, 0, 5, 5); - gbc_passwordField.fill = GridBagConstraints.HORIZONTAL; - gbc_passwordField.gridx = 1; - gbc_passwordField.gridy = 3; - panel_2.add(this.watermarkPassword, gbc_passwordField); - - JLabel lblNewLabel_3 = new JLabel("Embed Type:"); - GridBagConstraints gbc_lblNewLabel_3 = new GridBagConstraints(); - gbc_lblNewLabel_3.insets = new Insets(0, 0, 5, 5); - gbc_lblNewLabel_3.anchor = GridBagConstraints.EAST; - gbc_lblNewLabel_3.gridx = 0; - gbc_lblNewLabel_3.gridy = 4; - panel_2.add(lblNewLabel_3, gbc_lblNewLabel_3); - - JComboBox comboBox_05 = new JComboBox<>(); - comboBox_05.setEnabled(false); - GridBagConstraints gbc_comboBox_05 = new GridBagConstraints(); - gbc_comboBox_05.anchor = GridBagConstraints.WEST; - gbc_comboBox_05.gridwidth = 6; - gbc_comboBox_05.insets = new Insets(0, 0, 5, 5); - gbc_comboBox_05.gridx = 1; - gbc_comboBox_05.gridy = 4; - String[] watermarks = {"Constant Pool", "Signature"}; - for (String s : watermarks) { - comboBox_05.addItem(s); - } - panel_2.add(comboBox_05, gbc_comboBox_05); - - - JCheckBox chckbxAddWatermark = new JCheckBox("Watermark"); - GridBagConstraints gbc_chckbxNewCheckBox_8 = new GridBagConstraints(); - gbc_chckbxNewCheckBox_8.insets = new Insets(0, 0, 5, 5); - gbc_chckbxNewCheckBox_8.gridx = 0; - gbc_chckbxNewCheckBox_8.gridy = 0; - chckbxAddWatermark.addActionListener((e) -> { - if (chckbxAddWatermark.isSelected()) { - watermarkPassword.setEnabled(true); - waterMarkMessageField.setEnabled(true); - comboBox_05.setEnabled(true); - } else if (!chckbxAddWatermark.isSelected()) { - watermarkPassword.setEnabled(false); - waterMarkMessageField.setEnabled(false); - comboBox_05.setEnabled(false); - } - }); - panel_2.add(chckbxAddWatermark, gbc_chckbxNewCheckBox_8); - - JSeparator separator_1 = new JSeparator(); - GridBagConstraints gbc_separator_1 = new GridBagConstraints(); - gbc_separator_1.insets = new Insets(0, 0, 5, 0); - gbc_separator_1.fill = GridBagConstraints.HORIZONTAL; - gbc_separator_1.gridwidth = 13; - gbc_separator_1.gridx = 0; - gbc_separator_1.gridy = 5; - panel_2.add(separator_1, gbc_separator_1); - - JLabel lblNewLabel = new JLabel("Extractor:"); - GridBagConstraints gbc_lblNewLabel = new GridBagConstraints(); - gbc_lblNewLabel.insets = new Insets(0, 0, 5, 5); - gbc_lblNewLabel.gridx = 0; - gbc_lblNewLabel.gridy = 6; - panel_2.add(lblNewLabel, gbc_lblNewLabel); - - JLabel lblNewLabel_4 = new JLabel("Input:"); - GridBagConstraints gbc_lblNewLabel_4 = new GridBagConstraints(); - gbc_lblNewLabel_4.anchor = GridBagConstraints.EAST; - gbc_lblNewLabel_4.insets = new Insets(0, 0, 5, 5); - gbc_lblNewLabel_4.gridx = 0; - gbc_lblNewLabel_4.gridy = 8; - panel_2.add(lblNewLabel_4, gbc_lblNewLabel_4); - - this.extractorInput = new JTextField(); - GridBagConstraints gbc_textField_5 = new GridBagConstraints(); - gbc_textField_5.gridwidth = 10; - gbc_textField_5.insets = new Insets(0, 0, 5, 5); - gbc_textField_5.fill = GridBagConstraints.HORIZONTAL; - gbc_textField_5.gridx = 1; - gbc_textField_5.gridy = 8; - panel_2.add(this.extractorInput, gbc_textField_5); - this.extractorInput.setColumns(10); - - JButton btnNewButton_4 = new JButton("Select"); - btnNewButton_4.addActionListener((e) -> { - JFileChooser chooser = new JFileChooser(); - if (extractorInput.getText() != null - && !extractorInput.getText().isEmpty()) { - chooser.setSelectedFile(new File(extractorInput.getText())); - } - chooser.setMultiSelectionEnabled(false); - chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(() -> - extractorInput.setText(chooser.getSelectedFile().getAbsolutePath()) - ); - } - }); - GridBagConstraints gbc_btnNewButton_4 = new GridBagConstraints(); - gbc_btnNewButton_4.fill = GridBagConstraints.HORIZONTAL; - gbc_btnNewButton_4.insets = new Insets(0, 0, 5, 5); - gbc_btnNewButton_4.gridx = 11; - gbc_btnNewButton_4.gridy = 8; - panel_2.add(btnNewButton_4, gbc_btnNewButton_4); - - JLabel lblNewLabel_5 = new JLabel("Key:"); - GridBagConstraints gbc_lblNewLabel_5 = new GridBagConstraints(); - gbc_lblNewLabel_5.anchor = GridBagConstraints.EAST; - gbc_lblNewLabel_5.insets = new Insets(0, 0, 5, 5); - gbc_lblNewLabel_5.gridx = 0; - gbc_lblNewLabel_5.gridy = 9; - panel_2.add(lblNewLabel_5, gbc_lblNewLabel_5); - - this.extractorKey = new JPasswordField(); - GridBagConstraints gbc_passwordField_1 = new GridBagConstraints(); - gbc_passwordField_1.gridwidth = 10; - gbc_passwordField_1.insets = new Insets(0, 0, 5, 5); - gbc_passwordField_1.fill = GridBagConstraints.HORIZONTAL; - gbc_passwordField_1.gridx = 1; - gbc_passwordField_1.gridy = 9; - panel_2.add(this.extractorKey, gbc_passwordField_1); - - DefaultListModel listModel = new DefaultListModel<>(); - - JScrollPane scrollPane = new JScrollPane(); - GridBagConstraints gbc_scrollPane = new GridBagConstraints(); - gbc_scrollPane.gridwidth = 13; - gbc_scrollPane.insets = new Insets(0, 4, 3, 5); - gbc_scrollPane.fill = GridBagConstraints.BOTH; - gbc_scrollPane.gridx = 0; - gbc_scrollPane.gridy = 10; - panel_2.add(scrollPane, gbc_scrollPane); - - JList list_1 = new JList<>(listModel); - scrollPane.setViewportView(list_1); - - JButton btnNewButton_5 = new JButton("Extract"); - GridBagConstraints gbc_btnNewButton_5 = new GridBagConstraints(); - gbc_btnNewButton_5.insets = new Insets(0, 0, 5, 5); - gbc_btnNewButton_5.gridx = 11; - gbc_btnNewButton_5.gridy = 9; - btnNewButton_5.addActionListener((e) -> { - listModel.clear(); - - if (extractorInput.getText() == null - || extractorInput.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, "No file specified!", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - - if (extractorKey.getPassword() == null || new String(extractorKey.getPassword()).isEmpty()) { - JOptionPane.showMessageDialog(null, "No key entered!", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - - if (!extractorInput.getText().endsWith(".jar")) { - JOptionPane.showMessageDialog(null, - "Only Jars are allowed!", "Error", - JOptionPane.ERROR_MESSAGE); - return; - } - try { - File input = new File(extractorInput.getText()); - List foundIds = - WatermarkUtils.extractWatermark(input, - new String(extractorKey.getPassword())); - for (String s : foundIds) { - listModel.addElement(s); - } - - JOptionPane.showMessageDialog(null, - "Finished! Found: " + - String.valueOf(foundIds.size()) + " IDs", - "Info", JOptionPane.INFORMATION_MESSAGE); - } catch (Throwable t) { - t.printStackTrace(); - } - }); - panel_2.add(btnNewButton_5, gbc_btnNewButton_5); - - JPanel otherPanel = new JPanel(); - tabbedPane.addTab("Other", null, otherPanel, null); - GridBagLayout gbl_otherPanel = new GridBagLayout(); - gbl_otherPanel.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 59, 0, 0}; - gbl_otherPanel.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0}; - gbl_otherPanel.columnWeights = new double[]{0.0, 1.0, 1.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - gbl_otherPanel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE}; - otherPanel.setLayout(gbl_otherPanel); - - JLabel expireMessageLabel = new JLabel("Message:"); - GridBagConstraints gbc_expireMessageLabel = new GridBagConstraints(); - gbc_expireMessageLabel.insets = new Insets(0, 0, 5, 5); - gbc_expireMessageLabel.anchor = GridBagConstraints.EAST; - gbc_expireMessageLabel.gridx = 0; - gbc_expireMessageLabel.gridy = 2; - otherPanel.add(expireMessageLabel, gbc_expireMessageLabel); - - this.expirationMessageField = new JTextField(); - this.expirationMessageField.setEnabled(false); - GridBagConstraints gbc_messageField = new GridBagConstraints(); - gbc_messageField.gridwidth = 11; - gbc_messageField.insets = new Insets(0, 0, 5, 5); - gbc_messageField.fill = GridBagConstraints.HORIZONTAL; - gbc_messageField.gridx = 1; - gbc_messageField.gridy = 2; - otherPanel.add(this.expirationMessageField, gbc_messageField); - this.expirationMessageField.setColumns(10); - - JLabel expiresLabel = new JLabel("Expires:"); - GridBagConstraints gbc_expiresLabel = new GridBagConstraints(); - gbc_expiresLabel.insets = new Insets(0, 0, 5, 5); - gbc_expiresLabel.anchor = GridBagConstraints.EAST; - gbc_expiresLabel.gridx = 0; - gbc_expiresLabel.gridy = 3; - otherPanel.add(expiresLabel, gbc_expiresLabel); - - this.expirationDateField = new JTextField(); - this.expirationDateField.setEnabled(false); - GridBagConstraints gbc_dateField = new GridBagConstraints(); - gbc_dateField.gridwidth = 11; - gbc_dateField.insets = new Insets(0, 0, 5, 5); - gbc_dateField.fill = GridBagConstraints.HORIZONTAL; - gbc_dateField.gridx = 1; - gbc_dateField.gridy = 3; - otherPanel.add(this.expirationDateField, gbc_dateField); - - JCheckBox chckbxAddExpiration = new JCheckBox("Expiration"); - GridBagConstraints gbc_AddExpiration = new GridBagConstraints(); - gbc_AddExpiration.insets = new Insets(0, 0, 5, 5); - gbc_AddExpiration.gridx = 0; - gbc_AddExpiration.gridy = 0; - chckbxAddExpiration.addActionListener((e) -> { - if (chckbxAddExpiration.isSelected()) { - expirationDateField.setEnabled(true); - expirationMessageField.setEnabled(true); - } else if (!chckbxAddExpiration.isSelected()) { - expirationDateField.setEnabled(false); - expirationMessageField.setEnabled(false); - } - }); - otherPanel.add(chckbxAddExpiration, gbc_AddExpiration); - - JSeparator expireSeparator = new JSeparator(); - GridBagConstraints gbc_expireSeparator = new GridBagConstraints(); - gbc_expireSeparator.insets = new Insets(0, 0, 5, 0); - gbc_expireSeparator.fill = GridBagConstraints.HORIZONTAL; - gbc_expireSeparator.gridwidth = 13; - gbc_expireSeparator.gridx = 0; - gbc_expireSeparator.gridy = 4; - otherPanel.add(expireSeparator, gbc_expireSeparator); - - JComboBox dictionaryComboBox = new JComboBox<>(); - dictionaryComboBox.setEnabled(true); - GridBagConstraints gbc_dictionaryComboBox = new GridBagConstraints(); - gbc_dictionaryComboBox.fill = GridBagConstraints.HORIZONTAL; - gbc_dictionaryComboBox.insets = new Insets(0, 0, 5, 5); - gbc_dictionaryComboBox.gridx = 11; - gbc_dictionaryComboBox.gridy = 5; - String[] dictionaries = {"0", "1", "2"}; - for (String s : dictionaries) { - dictionaryComboBox.addItem(s); - } - otherPanel.add(dictionaryComboBox, gbc_dictionaryComboBox); - - JLabel chckbxDictionary = new JLabel("Dictionary:"); - GridBagConstraints gbc_chckbxDictionary = new GridBagConstraints(); - gbc_chckbxDictionary.anchor = GridBagConstraints.WEST; - gbc_chckbxDictionary.insets = new Insets(0, 5, 5, 5); - gbc_chckbxDictionary.gridx = 0; - gbc_chckbxDictionary.gridy = 5; - otherPanel.add(chckbxDictionary, gbc_chckbxDictionary); - - JButton garbageCollector = new JButton("GC"); - GridBagConstraints gbc_garbageCollector = new GridBagConstraints(); - gbc_garbageCollector.fill = GridBagConstraints.HORIZONTAL; - gbc_garbageCollector.insets = new Insets(0, 0, 5, 5); - gbc_garbageCollector.gridx = 11; - gbc_garbageCollector.gridy = 6; - garbageCollector.addActionListener((e) -> - SwingUtilities.invokeLater(() -> { - JOptionPane.showMessageDialog(null, ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1000000) + "mb in use before garbage collector."); - System.gc(); - }) - ); - otherPanel.add(garbageCollector, gbc_garbageCollector); - - JPanel panel_3 = new JPanel(); - tabbedPane.addTab("Exempt", null, panel_3, null); - GridBagLayout gbl_panel_3 = new GridBagLayout(); - gbl_panel_3.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0}; - gbl_panel_3.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0}; - gbl_panel_3.columnWeights = new double[]{0.0, 1.0, 1.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - gbl_panel_3.rowWeights = new double[]{0.0, 1.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; - panel_3.setLayout(gbl_panel_3); - - JComboBox comboBox_04 = new JComboBox<>(); - GridBagConstraints gbc_comboBox_04 = new GridBagConstraints(); - gbc_comboBox_04.insets = new Insets(0, 5, 5, 5); - gbc_comboBox_04.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBox_04.gridx = 1; - gbc_comboBox_04.gridy = 12; - String[] options = {"Class", "Method", "Field", "StringEncryption", "InvokeDynamic", - "Flow", "LocalVars", "SourceName", "SourceDebug", "LineNumbers", "StringPool", - "Crasher", "HideCode", "Numbers", "Shuffler", "InnerClasses", "Renamer", - "Expiry"}; - for (String s : options) { - comboBox_04.addItem(s); - } - - JScrollPane scrollPane_1 = new JScrollPane(); - GridBagConstraints gbc_scrollPane_1 = new GridBagConstraints(); - gbc_scrollPane_1.gridheight = 11; - gbc_scrollPane_1.gridwidth = 11; - gbc_scrollPane_1.insets = new Insets(0, 4, 5, 5); - gbc_scrollPane_1.fill = GridBagConstraints.BOTH; - gbc_scrollPane_1.gridx = 1; - gbc_scrollPane_1.gridy = 1; - panel_3.add(scrollPane_1, gbc_scrollPane_1); - - DefaultListModel exemptList = new DefaultListModel<>(); - - JList list = new JList<>(exemptList); - list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - scrollPane_1.setViewportView(list); - panel_3.add(comboBox_04, gbc_comboBox_04); - - this.exemptField = new JTextField(); - GridBagConstraints gbc_textField_3 = new GridBagConstraints(); - gbc_textField_3.gridwidth = 8; - gbc_textField_3.insets = new Insets(0, 0, 5, 5); - gbc_textField_3.fill = GridBagConstraints.HORIZONTAL; - gbc_textField_3.gridx = 2; - gbc_textField_3.gridy = 12; - panel_3.add(this.exemptField, gbc_textField_3); - this.exemptField.setColumns(10); - - JButton btnNewButton_2 = new JButton("Add"); - btnNewButton_2.addActionListener((e) -> { - if (!exemptField.getText().equals("") - && exemptField.getText() != null - && !exemptField.getText().isEmpty()) { - if (comboBox_04.getSelectedIndex() == 0) { - exemptList.addElement("Class: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 1) { - exemptList.addElement("Method: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 2) { - exemptList.addElement("Field: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 3) { - exemptList.addElement("StringEncryption: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 4) { - exemptList.addElement("InvokeDynamic: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 5) { - exemptList.addElement("Flow: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 6) { - exemptList.addElement("LocalVars: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 7) { - exemptList.addElement("SourceName: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 8) { - exemptList.addElement("SourceDebug: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 9) { - exemptList.addElement("LineNumbers: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 10) { - exemptList.addElement("StringPool: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 11) { - exemptList.addElement("Crasher: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 12) { - exemptList.addElement("HideCode: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 13) { - exemptList.addElement("Numbers: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 14) { - exemptList.addElement("Shuffler: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 15) { - exemptList.addElement("InnerClasses: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 16) { - exemptList.addElement("Renamer: " + exemptField.getText()); - exemptField.setText(""); - } else if (comboBox_04.getSelectedIndex() == 17) { - exemptList.addElement("Expiry: " + exemptField.getText()); - exemptField.setText(""); - } - } - }); - GridBagConstraints gbc_btnNewButton_2 = new GridBagConstraints(); - gbc_btnNewButton_2.insets = new Insets(0, 0, 5, 5); - gbc_btnNewButton_2.gridx = 10; - gbc_btnNewButton_2.gridy = 12; - panel_3.add(btnNewButton_2, gbc_btnNewButton_2); - - JButton btnNewButton_3 = new JButton("Remove"); - btnNewButton_3.addActionListener((e) -> { - List removeList = list.getSelectedValuesList(); - if (removeList.isEmpty()) - return; - - for (String s : removeList) { - exemptList.removeElement(s); - } - }); - GridBagConstraints gbc_btnNewButton_3 = new GridBagConstraints(); - gbc_btnNewButton_3.insets = new Insets(0, 0, 5, 5); - gbc_btnNewButton_3.gridx = 11; - gbc_btnNewButton_3.gridy = 12; - panel_3.add(btnNewButton_3, gbc_btnNewButton_3); - - JPanel panel_7 = new JPanel(); - tabbedPane.addTab("About", null, panel_7, null); - GridBagLayout gbl_panel_7 = new GridBagLayout(); - gbl_panel_7.columnWidths = new int[]{0, 0}; - gbl_panel_7.rowHeights = new int[]{0, 0}; - gbl_panel_7.columnWeights = new double[]{1.0, Double.MIN_VALUE}; - gbl_panel_7.rowWeights = new double[]{1.0, Double.MIN_VALUE}; - panel_7.setLayout(gbl_panel_7); - - JTextArea txtrPizzaObfuscatorAuthors = new JTextArea(); - txtrPizzaObfuscatorAuthors.setFont(new Font("Arial", Font.PLAIN, 12)); - txtrPizzaObfuscatorAuthors.setText(Radon.PREFIX + "\nVersion: " + - Radon.VERSION + "\nAuthor: " + Radon.AUTHORS); - txtrPizzaObfuscatorAuthors.setLineWrap(true); - txtrPizzaObfuscatorAuthors.setEditable(false); - GridBagConstraints gbc_txtrPizzaObfuscatorAuthors = - new GridBagConstraints(); - gbc_txtrPizzaObfuscatorAuthors.fill = GridBagConstraints.BOTH; - gbc_txtrPizzaObfuscatorAuthors.insets = new Insets(0, 2, 0, 0); - gbc_txtrPizzaObfuscatorAuthors.gridx = 0; - gbc_txtrPizzaObfuscatorAuthors.gridy = 0; - panel_7.add(txtrPizzaObfuscatorAuthors, gbc_txtrPizzaObfuscatorAuthors); - - JPanel panel_1 = new JPanel(); - this.frmRadonObfuscator.getContentPane().add(panel_1, BorderLayout.SOUTH); - panel_1.setLayout(new BorderLayout(0, 0)); - - JPanel panel_5 = new JPanel(); - panel_1.add(panel_5, BorderLayout.EAST); - - JButton btnObfuscate = new JButton(" Process "); - btnObfuscate.addActionListener((e) -> { - if (inputField.getText().isEmpty() - || inputField.getText() == null - || !inputField.getText().endsWith(".jar")) { - JOptionPane.showMessageDialog(null, - "Invalid input JAR", "Error", - JOptionPane.ERROR_MESSAGE); - return; - } - - if (outputField.getText().isEmpty() - || outputField.getText() == null - || !outputField.getText().endsWith(".jar")) { - JOptionPane.showMessageDialog(null, - "Invalid output JAR", "Error", - JOptionPane.ERROR_MESSAGE); - return; - } - - if (outputField.getText().equals(inputField.getText())) { - JOptionPane.showMessageDialog(null, - "Output JAR can not have the same name as input " + - "JAR", "Error", JOptionPane.ERROR_MESSAGE); - return; - } - - if (chckbxAddWatermark.isSelected() - && waterMarkMessageField.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, - "You must enter a message to be watermarked.", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - - if (chckbxAddWatermark.isSelected() - && new String(watermarkPassword.getPassword()).isEmpty()) { - JOptionPane.showMessageDialog(null, - "You must enter a key to encrypt the watermark message.", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - - if (chckbxAddExpiration.isSelected() - && expirationMessageField.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, - "You must enter an expiration message.", "Error", - JOptionPane.ERROR_MESSAGE); - return; - } - - if (chckbxAddExpiration.isSelected() - && expirationDateField.getText().isEmpty()) { - JOptionPane.showMessageDialog(null, - "You must enter an expiration date.", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - btnObfuscate.setText("Processing..."); - btnObfuscate.setEnabled(false); - SwingWorker sw = new SwingWorker() { - @Override - protected Object doInBackground() { - File output = null; - try { - - HashMap libs = new HashMap<>(); - for (int i = 0; i < libList.getSize(); i++) { - libs.put(libList.get(i), new File(libList.get(i))); - } - - File input = new File(inputField.getText()); - if (!input.exists()) { - JOptionPane.showMessageDialog(null, - "Input JAR does not exist.", - "Error", JOptionPane.ERROR_MESSAGE); - return null; - } - output = new File(outputField.getText()); - - int trashChance; - try { - trashChance = - Integer.valueOf(trashChanceField.getText()); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, - "Please enter numbers only for the " + - "number of desired trash " + - "classes.", "Error", - JOptionPane.ERROR_MESSAGE); - return null; - } - List exempts = new ArrayList<>(); - for (int i = 0; i < exemptList.size(); i++) { - exempts.add(exemptList.get(i)); - } - boolean spigotMode = chckbxSpigotPlugin.isSelected(); - List transformers - = new ArrayList<>(); - - if (chckbxClassRenammer.isSelected()) { - transformers.add(new Renamer(spigotMode)); - } - if (chckbxInnerClasses.isSelected()) { - transformers.add(new InnerClassRemover()); - } - if (chckbxNumberObfuscation.isSelected()) { - transformers.add(new NumberObfuscation()); - } - if (chckbxInvokeDynamic.isSelected()) { - switch (comboBox_1.getSelectedIndex()) { - case 0: - transformers.add(new LightInvokeDynamic()); - break; - case 1: - transformers.add(new NormalInvokeDynamic()); - break; - case 2: - transformers.add(new HeavyInvokeDynamic()); - break; - } - } - if (chckbxAddExpiration.isSelected()) { - if (!expirationDateField.getText().isEmpty() - && !expirationMessageField.getText() - .isEmpty()) { - long expireTime = - new SimpleDateFormat("MM/dd/yyyy") - .parse(expirationDateField - .getText()).getTime(); - transformers.add(new Expiry(expireTime, - expirationMessageField.getText())); - } - } - if (chckbxStringEncryption.isSelected()) { - switch (comboBox.getSelectedIndex()) { - case 0: - transformers.add(new SuperLightStringEncryption(spigotMode)); - break; - case 1: - transformers.add(new LightStringEncryption(spigotMode)); - break; - case 2: - transformers.add(new NormalStringEncryption(spigotMode)); - break; - case 3: - transformers.add(new HeavyStringEncryption(spigotMode)); - break; - } - } - if (chckbxFlow.isSelected()) { - switch (comboBox_2.getSelectedIndex()) { - case 0: - transformers.add(new LightFlowObfuscation()); - break; - case 1: - transformers.add(new NormalFlowObfuscation()); - break; - case 2: - transformers.add(new HeavyFlowObfuscation()); - break; - } - } - if (chckbxSpringPool.isSelected()) { - transformers.add(new StringPool()); - } - if (chckbxShuffler.isSelected()) { - transformers.add(new Shuffler()); - } - if (chckbxLocalVariables.isSelected()) { - switch (comboBox_3.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateLocalVariables()); - break; - case 1: - transformers.add(new RemoveLocalVariables()); - break; - } - } - if (chckbxLineObfuscation.isSelected()) { - switch (comboBox_5.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateLineNumbers()); - break; - case 1: - transformers.add(new RemoveLineNumbers()); - break; - } - } - if (chckbxSourceName.isSelected()) { - switch (comboBox_123.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateSourceName()); - break; - case 1: - transformers.add(new RemoveSourceName()); - break; - } - } - if (chckbxSourceDebug.isSelected()) { - switch (comboBox_1234.getSelectedIndex()) { - case 0: - transformers.add(new ObfuscateSourceDebug()); - break; - case 1: - transformers.add(new RemoveSourceDebug()); - break; - } - } - if (chckbxCrasher.isSelected()) { - transformers.add(new Crasher()); - } - if (chckbxHidecode.isSelected()) { - transformers.add(new HideCode()); - } - - int trashClasses = -1; - if (chckbxTrashClasses.isSelected()) { - trashClasses = trashChance; - } - - int watermarkType = -1; - if (chckbxAddWatermark.isSelected()) { - watermarkType = comboBox_05.getSelectedIndex(); - } - - int dictionary = dictionaryComboBox.getSelectedIndex(); - - if (chckbxTrashClasses.isSelected() && spigotMode) { - throw new RuntimeException("Trash classes are not compatible with Spigot's anti-piracy injection."); - } - - new ConsoleGUI(); - Bootstrap bootstrap = new Bootstrap( - input, - output, - libs, - exempts, - transformers, - trashClasses, - waterMarkMessageField.getText(), - watermarkType, - new String(watermarkPassword.getPassword()), - dictionary); - bootstrap.startTheParty(false); - JOptionPane.showMessageDialog(null, - "Successfully processed file!", - "Done", JOptionPane.INFORMATION_MESSAGE); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, t.getMessage(), - "Error", JOptionPane.ERROR_MESSAGE); - t.printStackTrace(); - if (output != null) { - if (!output.delete()) { - JOptionPane.showMessageDialog(null, "Failed to delete fault output.", - "Error", JOptionPane.ERROR_MESSAGE); - } - } - } finally { - btnObfuscate.setEnabled(true); - btnObfuscate.setText(" Process "); - } - return null; - } - }; - - sw.execute(); - }); - panel_5.add(btnObfuscate); - - JPanel panel_6 = new JPanel(); - panel_1.add(panel_6, BorderLayout.WEST); - - JButton btnLoadConfiguration = new JButton("Load Configuration"); - btnLoadConfiguration.addActionListener((e) -> { - JFileChooser chooser = new JFileChooser(); - chooser.setMultiSelectionEnabled(false); - chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(() -> { - try { - File config = new File(chooser.getSelectedFile() - .getAbsolutePath()); - if (!config.exists()) - throw new IOException("Config file does " + - "not exist."); - - FileInputStream fis = new FileInputStream(config); - Config configParser - = new Config(fis); - configParser.loadIntoMap(); - configParser.sortExempts(); - configParser.checkConfig(); - - inputField.setText(configParser.getInput() - .getAbsolutePath()); - outputField.setText(configParser.getOutput() - .getAbsolutePath()); - libList.clear(); - for (String s : configParser.getLibraries() - .keySet()) { - libList.addElement(s); - } - - List exempts = configParser.getExempts(); - if (exempts != null) { - exemptList.clear(); - for (String s : exempts) { - exemptList.addElement(s); - } - } - - AbstractTransformer stringEncryptionMode - = configParser.getStringEncryptionType(); - if (stringEncryptionMode == null) { - chckbxStringEncryption.setSelected(false); - } else if (stringEncryptionMode - instanceof SuperLightStringEncryption) { - chckbxStringEncryption.setSelected(true); - comboBox.setSelectedIndex(0); - comboBox.setEnabled(true); - } else if (stringEncryptionMode - instanceof LightStringEncryption) { - chckbxStringEncryption.setSelected(true); - comboBox.setSelectedIndex(1); - comboBox.setEnabled(true); - } else if (stringEncryptionMode - instanceof NormalStringEncryption) { - chckbxStringEncryption.setSelected(true); - comboBox.setSelectedIndex(2); - comboBox.setEnabled(true); - } else if (stringEncryptionMode - instanceof HeavyStringEncryption) { - chckbxStringEncryption.setSelected(true); - comboBox.setSelectedIndex(3); - comboBox.setEnabled(true); - } - - AbstractTransformer flowObfuscationMode = - configParser.getFlowObfuscationType(); - if (flowObfuscationMode == null) { - chckbxFlow.setSelected(false); - } else if (flowObfuscationMode - instanceof LightFlowObfuscation) { - chckbxFlow.setSelected(true); - comboBox_2.setSelectedIndex(0); - comboBox_2.setEnabled(true); - } else if (flowObfuscationMode - instanceof NormalFlowObfuscation) { - chckbxFlow.setSelected(true); - comboBox_2.setSelectedIndex(1); - comboBox_2.setEnabled(true); - } else if (flowObfuscationMode - instanceof HeavyFlowObfuscation) { - chckbxFlow.setSelected(true); - comboBox_2.setSelectedIndex(2); - comboBox_2.setEnabled(true); - } - - AbstractTransformer invokeDynamicMode = - configParser.getInvokeDynamicType(); - if (invokeDynamicMode == null) { - chckbxInvokeDynamic.setSelected(false); - } else if (invokeDynamicMode - instanceof LightInvokeDynamic) { - chckbxInvokeDynamic.setSelected(true); - comboBox_1.setSelectedIndex(0); - comboBox_1.setEnabled(true); - } else if (invokeDynamicMode - instanceof NormalInvokeDynamic) { - chckbxInvokeDynamic.setSelected(true); - comboBox_1.setSelectedIndex(1); - comboBox_1.setEnabled(true); - } else if (invokeDynamicMode - instanceof HeavyInvokeDynamic) { - chckbxInvokeDynamic.setSelected(true); - comboBox_1.setSelectedIndex(2); - comboBox_1.setEnabled(true); - } - - AbstractTransformer localVariablesMode = - configParser.getLocalVariableObfuscationType(); - if (localVariablesMode == null) { - chckbxLocalVariables.setSelected(false); - } else if (localVariablesMode - instanceof ObfuscateLocalVariables) { - chckbxLocalVariables.setSelected(true); - comboBox_3.setSelectedIndex(0); - comboBox_3.setEnabled(true); - } else if (localVariablesMode - instanceof RemoveLocalVariables) { - chckbxLocalVariables.setSelected(true); - comboBox_3.setSelectedIndex(1); - comboBox_3.setEnabled(true); - } - - AbstractTransformer crasherMode = - configParser.getCrasherType(); - if (crasherMode instanceof Crasher) { - chckbxCrasher.setSelected(true); - } else { - chckbxCrasher.setSelected(false); - } - - AbstractTransformer hideCodeMode = - configParser.getHideCodeType(); - if (hideCodeMode instanceof HideCode) { - chckbxHidecode.setSelected(true); - } else { - chckbxHidecode.setSelected(false); - } - - AbstractTransformer lineRemoverMode = - configParser.getLineNumberObfuscationType(); - if (lineRemoverMode == null) { - chckbxLineObfuscation.setSelected(false); - } else if (lineRemoverMode - instanceof ObfuscateLineNumbers) { - chckbxLineObfuscation.setSelected(true); - comboBox_5.setSelectedIndex(0); - comboBox_5.setEnabled(true); - } else if (lineRemoverMode - instanceof RemoveLineNumbers) { - chckbxLineObfuscation.setSelected(true); - comboBox_5.setSelectedIndex(1); - comboBox_5.setEnabled(true); - } - - AbstractTransformer numberObfuscationMode = - configParser.getNumberObfuscationType(); - if (numberObfuscationMode - instanceof NumberObfuscation) { - chckbxNumberObfuscation.setSelected(true); - } else { - chckbxNumberObfuscation.setSelected(false); - } - - AbstractTransformer sourceNameObfuscationMode = - configParser.getSourceNameObfuscationType(); - if (sourceNameObfuscationMode == null) { - chckbxSourceName.setSelected(false); - } else if (sourceNameObfuscationMode - instanceof ObfuscateSourceName) { - chckbxSourceName.setSelected(true); - comboBox_123.setSelectedIndex(0); - comboBox_123.setEnabled(true); - } else if (sourceNameObfuscationMode - instanceof RemoveSourceName) { - chckbxSourceName.setSelected(true); - comboBox_123.setSelectedIndex(1); - comboBox_123.setEnabled(true); - } - - AbstractTransformer sourceDebugObfuscationMode = - configParser.getSourceDebugObfuscationType(); - if (sourceDebugObfuscationMode == null) { - chckbxSourceDebug.setSelected(false); - } else if (sourceDebugObfuscationMode - instanceof ObfuscateSourceDebug) { - chckbxSourceDebug.setSelected(true); - comboBox_1234.setSelectedIndex(0); - comboBox_1234.setEnabled(true); - } else if (sourceDebugObfuscationMode - instanceof RemoveSourceDebug) { - chckbxSourceDebug.setSelected(true); - comboBox_1234.setSelectedIndex(1); - comboBox_1234.setEnabled(true); - } - - - AbstractTransformer stringPoolMode = - configParser.getStringPoolType(); - if (stringPoolMode instanceof StringPool) { - chckbxSpringPool.setSelected(true); - } else { - chckbxSpringPool.setSelected(false); - } - - AbstractTransformer shufflerMode = - configParser.getShufflerType(); - if (shufflerMode instanceof Shuffler) { - chckbxShuffler.setSelected(true); - } else { - chckbxShuffler.setSelected(false); - } - - AbstractTransformer innerClassMode = - configParser.getInnerClassRemoverType(); - if (innerClassMode instanceof InnerClassRemover) { - chckbxInnerClasses.setSelected(true); - } else { - chckbxInnerClasses.setSelected(false); - } - - AbstractTransformer renamer = - configParser.getRenamerType(); - if (renamer instanceof Renamer) { - chckbxClassRenammer.setSelected(true); - } else { - chckbxClassRenammer.setSelected(false); - } - - if (configParser.getSpigotBool()) { - chckbxSpigotPlugin.setSelected(true); - } else { - chckbxSpigotPlugin.setSelected(false); - } - - int trashClassesChance = - configParser.getTrashClasses(); - if (trashClassesChance == -1) { - chckbxTrashClasses.setSelected(false); - } else { - chckbxTrashClasses.setSelected(true); - trashChanceField.setText(String - .valueOf(trashClassesChance)); - trashChanceField.setEditable(true); - } - - waterMarkMessageField.setText(configParser - .getWatermarkMsg()); - watermarkPassword.setText(configParser - .getWatermarkKey()); - - int watermarkType = - configParser.getWatermarkType(); - if (configParser.getWatermarkType() != -1) { - chckbxAddWatermark.setSelected(true); - waterMarkMessageField.setEnabled(true); - watermarkPassword.setEnabled(true); - comboBox_05.setEnabled(true); - comboBox_05.setSelectedIndex(watermarkType); - } - - if (configParser.getExpiryMsg() != null - && configParser.getExpiryTime() != -1) { - expirationMessageField.setText(configParser - .getExpiryMsg()); - expirationMessageField.setEnabled(true); - expirationDateField.setText(String - .valueOf(new SimpleDateFormat("MM/dd/yyyy") - .format(configParser.getExpiryTime()))); - expirationDateField.setEnabled(true); - chckbxAddExpiration.setSelected(true); - } - - int dictionary = configParser.getDictionaryType(); - dictionaryComboBox.setSelectedIndex(dictionary); - fis.close(); - - lastPath = chooser.getSelectedFile(); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, - t.getMessage(), "Error", - JOptionPane.ERROR_MESSAGE); - t.printStackTrace(); - } - }); - } - }); - btnLoadConfiguration.setToolTipText("Loads config for pre-defined " + - "settings."); - panel_6.add(btnLoadConfiguration); - JButton saveConfigButton = new JButton("Save configuration"); - saveConfigButton.addActionListener((e) -> { - JFileChooser chooser = new JFileChooser(); - chooser.setMultiSelectionEnabled(false); - chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - int result = chooser.showOpenDialog(frmRadonObfuscator); - if (result == 0) { - SwingUtilities.invokeLater(() -> { - try { - Map settings = new HashMap<>(); - if (inputField.getText() != null - && !inputField.getText().isEmpty()) { - settings.put(ConfigEnum.INPUT, inputField.getText()); - } - - if (outputField.getText() != null - && !outputField.getText().isEmpty()) { - settings.put(ConfigEnum.OUTPUT, outputField.getText()); - } - - if (chckbxStringEncryption.isSelected()) { - switch (comboBox.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.STRING_ENCRYPTION, "SuperLight"); - break; - case 1: - settings.put(ConfigEnum.STRING_ENCRYPTION, "Light"); - break; - case 2: - settings.put(ConfigEnum.STRING_ENCRYPTION, "Normal"); - break; - case 3: - settings.put(ConfigEnum.STRING_ENCRYPTION, "Heavy"); - break; - } - } - - if (chckbxInvokeDynamic.isSelected()) { - switch (comboBox_1.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.INVOKEDYNAMIC, "Light"); - break; - case 1: - settings.put(ConfigEnum.INVOKEDYNAMIC, "Normal"); - break; - case 2: - settings.put(ConfigEnum.INVOKEDYNAMIC, "Heavy"); - break; - } - } - - if (chckbxFlow.isSelected()) { - switch (comboBox_2.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.FLOW_OBFUSCATION, "Light"); - break; - case 1: - settings.put(ConfigEnum.FLOW_OBFUSCATION, "Normal"); - break; - case 2: - settings.put(ConfigEnum.FLOW_OBFUSCATION, "Heavy"); - break; - } - } - - if (chckbxLocalVariables.isSelected()) { - switch (comboBox_3.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.LOCAL_VARIABLES, "Obfuscate"); - break; - case 1: - settings.put(ConfigEnum.LOCAL_VARIABLES, "Remove"); - break; - } - } - - if (chckbxCrasher.isSelected()) { - settings.put(ConfigEnum.CRASHER, "true"); - } - - if (chckbxHidecode.isSelected()) { - settings.put(ConfigEnum.HIDER, "true"); - } - - if (chckbxSpringPool.isSelected()) { - settings.put(ConfigEnum.STRING_POOL, "true"); - } - - if (chckbxLineObfuscation.isSelected()) { - switch (comboBox_5.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.LINE_NUMBERS, "Obfuscate"); - break; - case 1: - settings.put(ConfigEnum.LINE_NUMBERS, "Remove"); - break; - } - } - - if (chckbxNumberObfuscation.isSelected()) { - settings.put(ConfigEnum.NUMBERS, "true"); - } - - if (chckbxSourceName.isSelected()) { - switch (comboBox_123.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.SOURCE_NAME, "Obfuscate"); - break; - case 1: - settings.put(ConfigEnum.SOURCE_NAME, "Remove"); - break; - } - } - - if (chckbxSourceDebug.isSelected()) { - switch (comboBox_1234.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.SOURCE_DEBUG, "Obfuscate"); - break; - case 1: - settings.put(ConfigEnum.SOURCE_DEBUG, "Remove"); - break; - } - } - - if (chckbxTrashClasses.isSelected()) { - if (trashChanceField.getText() != null - && !trashChanceField.getText().isEmpty()) { - settings.put(ConfigEnum.TRASH_CLASSES, trashChanceField.getText()); - } - } - - if (chckbxAddWatermark.isSelected()) { - if (waterMarkMessageField.getText() != null - && !waterMarkMessageField.getText().isEmpty() - && watermarkPassword.getPassword() != null - && !new String(watermarkPassword.getPassword()).isEmpty()) { - switch (comboBox_05.getSelectedIndex()) { - case 0: - settings.put(ConfigEnum.WATERMARK_TYPE, "ConstantPool"); - break; - case 1: - settings.put(ConfigEnum.WATERMARK_TYPE, "Signature"); - break; - } - - settings.put(ConfigEnum.WATERMARK_MSG, waterMarkMessageField.getText()); - settings.put(ConfigEnum.WATERMARK_KEY, new String(watermarkPassword.getPassword())); - } - } - - if (chckbxSpigotPlugin.isSelected()) { - settings.put(ConfigEnum.SPIGOT_PLUGIN, "true"); - } - - if (chckbxClassRenammer.isSelected()) { - settings.put(ConfigEnum.RENAMER, "true"); - } - - if (chckbxAddExpiration.isSelected()) { - if (expirationMessageField.getText() != null - && !expireMessageLabel.getText().isEmpty() - && expirationDateField.getText() != null - && !expirationDateField.getText().isEmpty()) { - settings.put(ConfigEnum.EXPIRATION_MESSAGE, expirationMessageField.getText()); - settings.put(ConfigEnum.EXPIRATION_TIME, expirationDateField.getText()); - } - } - - if (chckbxShuffler.isSelected()) { - settings.put(ConfigEnum.SHUFFLER, "true"); - } - - settings.put(ConfigEnum.DICTIONARY, String.valueOf(dictionaryComboBox.getSelectedIndex())); - - if (chckbxInnerClasses.isSelected()) { - settings.put(ConfigEnum.INNERCLASSES, "true"); - } - - List libs = new ArrayList<>(); - for (int i = 0; i < libList.size(); i++) { - String lib = libList.get(i); - libs.add(lib); - } - - settings.put(ConfigEnum.LIBRARIES, libs); - - List exempts = new ArrayList<>(); - for (int i = 0; i < exemptList.size(); i++) { - String exempt = exemptList.get(i); - exempts.add(exempt); - } - - settings.put(ConfigEnum.EXEMPTS, exempts); - - ConfigWriter writer = new ConfigWriter(settings); - writer.parseOptions(); - writer.writeConfig(chooser.getSelectedFile().getAbsolutePath()); - - lastPath = chooser.getSelectedFile(); - } catch (Throwable t) { - JOptionPane.showMessageDialog(null, - t.getMessage(), "Error", - JOptionPane.ERROR_MESSAGE); - t.printStackTrace(); - } - }); - } - }); - panel_6.add(saveConfigButton); - this.frmRadonObfuscator.setVisible(true); - } -} diff --git a/src/main/java/me/itzsomebody/radon/gui/OutputStreamRedirect.java b/src/main/java/me/itzsomebody/radon/gui/OutputStreamRedirect.java deleted file mode 100644 index e7b99785..00000000 --- a/src/main/java/me/itzsomebody/radon/gui/OutputStreamRedirect.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.gui; - -import java.io.OutputStream; -import javax.swing.*; - -/** - * Redirects all PrintStreams to the provided JTextArea. - * - * @author ItzSomebody - */ -public class OutputStreamRedirect extends OutputStream { - /** - * Target JTextArea to log everything to. - */ - private JTextArea consoleOutput; - - /** - * Constructor to create an OutputStreamRedirect. - * - * @param consoleOutput target JTextArea to log everything to. - */ - public OutputStreamRedirect(JTextArea consoleOutput) { - this.consoleOutput = consoleOutput; - } - - /** - * Writes the specified byte to this output stream. - * - * @param b the byte code. - */ - @Override - public void write(int b) { - this.consoleOutput.append(String.valueOf((char) b)); - this.consoleOutput.setCaretPosition(this.consoleOutput.getDocument().getLength()); - } -} diff --git a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java b/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java deleted file mode 100644 index 46d0bbf6..00000000 --- a/src/main/java/me/itzsomebody/radon/internal/Bootstrap.java +++ /dev/null @@ -1,669 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.internal; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; -import java.util.zip.ZipOutputStream; -import me.itzsomebody.radon.Radon; -import me.itzsomebody.radon.config.Config; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.transformers.misc.Expiry; -import me.itzsomebody.radon.transformers.misc.TrashClasses; -import me.itzsomebody.radon.utils.FileUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.NumberUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.tree.ClassNode; - -/** - * Bootstraps and runs the obfuscation process. - * FIXME: Renaming classes causes exempts on other classes to not work. - * - * @author ItzSomebody - */ -public class Bootstrap { // Eyyy bootstrap bill - /** - * HashMap that stores all of the loaded classes. - */ - private final Map classPath = new HashMap<>(); - - /** - * HashMap that stores all of the input classes (and as they are obfuscated). - */ - private final Map classes = new HashMap<>(); - - /** - * Extra classes that are generated by the obfuscator. - */ - private final Map extraClasses = new HashMap<>(); - - /** - * Resources which "pass through" the obfuscator. - */ - private final Map passThru = new HashMap<>(); - - /** - * Class hiearchy. - */ - private final Map hierarchy = new HashMap<>(); - - /** - * Config object - */ - private Config config; - - /** - * Input file that read from. - */ - private File input; - - /** - * Output file that will be the obfuscation result. - */ - private File output; - - /** - * A {@link ZipOutputStream} which we use to write changes to the classes. - */ - private ZipOutputStream zos; - - /** - * A HashMap that stores the locations to each of the libraries that will - * be loaded into the classpath. - */ - private HashMap libs; - - /** - * Exempt information. - */ - private List exempts; - - /** - * Transformers that will be used. - */ - private List transformers; - - /** - * Dictionary type to use - */ - private int dictionary; - - /** - * Integer that determines how many trash classes to generate if any at all. - */ - private int trashClasses; - - /** - * String to be watermarked into the output if any at all. - */ - private String watermarkMsg; - - /** - * Integer that determines which watermarking technique to use if any at all. - */ - private int watermarkType; - - /** - * String to encrypt {@link Bootstrap#watermarkMsg} if any at all. - */ - private String watermarkKey; - - /** - * Strings to write to log. - */ - private List logStrings; - - /** - * Constructor used for CLI to create a {@link Bootstrap} object. - * - * @param config {@link Config} object. - */ - Bootstrap(Config config) { - this.config = config; - } - - /** - * Constructor used for MainGUI to create a {@link Bootstrap} object. - * - * @param input the input {@link File}. - * @param output the output {@link File}. - * @param libs the {@link HashMap} of libraries. - * @param exempts exempt information. - * @param transformers transformers that will be run. - * @param trashClasses number of trash classes to generate as - * {@link Integer}. - * @param watermarkMsg {@link String} to watermark into the output. - * @param watermarkType watermark type as {@link Integer}. - * @param watermarkKey {@link String} to encrypt watermark message. - * @param dictionary dictionary type used for string generation. - */ - public Bootstrap( - File input, - File output, - HashMap libs, - List exempts, - List transformers, - int trashClasses, - String watermarkMsg, - int watermarkType, - String watermarkKey, - int dictionary) { - this.input = input; - this.output = output; - this.libs = libs; - this.exempts = exempts; - this.transformers = transformers; - this.trashClasses = trashClasses; - this.watermarkMsg = watermarkMsg; - this.watermarkType = watermarkType; - this.watermarkKey = watermarkKey; - this.dictionary = dictionary; - } - - /** - * Actual obfuscation starts here. - * - * @param doInit should obfuscator read and set variables according to - * values of {@link Bootstrap#config}? - * @throws Throwable if any errors are thrown. - */ - public void startTheParty(boolean doInit) throws Throwable { - try { - this.logStrings = new ArrayList<>(); - if (doInit) { - this.init(); - this.logStrings.add(LoggerUtils.stdOut("Successfully parsed config")); - } else { - if (output.exists()) { - logStrings.add(LoggerUtils.stdOut("Output already exists, renamed to " + FileUtils.renameExistingFile(output))); - } - this.zos = new ZipOutputStream(new FileOutputStream(output)); - } - - if (this.transformers.isEmpty()) { - throw new RuntimeException("No transformers have been enabled."); - } - - long currentTime = System.currentTimeMillis(); - this.loadClassPath(); - this.loadInput(); - this.buildInheritance(); - - for (AbstractTransformer transformer : this.transformers) { - transformer.init(this, this.exempts, this.dictionary); - transformer.obfuscate(); - this.logStrings.addAll(transformer.getLogStrings()); - } - - if (this.trashClasses != -1) { - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - // TODO: make this variable a config option - int len = 4; - for (int i = 0; i < this.trashClasses; i++) { - TrashClasses trashClass = new TrashClasses(StringUtils.randomClassName(this.classes.keySet(), this.dictionary, len)); - ClassNode classNode = trashClass.returnTrashClass(); - this.extraClasses.put(classNode.name, classNode); - } - this.logStrings.add(LoggerUtils.stdOut("Generated " + String.valueOf(this.trashClasses) + " trash classes")); - } - - if (this.extraClasses.values().size() != 0) { - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Writing generated classes to output")); - - // Write the contents of extraClasses to zos - for (ClassNode classNode : this.extraClasses.values()) { - ClassWriter cw = new ClassWriter(0); - classNode.accept(cw); - - ZipEntry newEntry = new ZipEntry(classNode.name + ".class"); - newEntry.setTime(currentTime); - newEntry.setCompressedSize(-1); - this.zos.putNextEntry(newEntry); - this.zos.write(cw.toByteArray()); - this.zos.closeEntry(); - } - } - - // Write the contents of classes to zos and recompute maxlocals, maxstack and stackframes - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Writing classes to output")); - for (ClassNode classNode : this.classes.values()) { - ClassWriter cw = new CustomClassWriter(ClassWriter.COMPUTE_FRAMES); - - try { - classNode.accept(cw); - if (this.watermarkMsg != null) { - if (this.watermarkType == 0 && NumberUtils.getRandomInt(10) >= 5) { - cw.newUTF8("WMID: " + StringUtils.aesEncrypt(this.watermarkMsg, this.watermarkKey)); - this.logStrings.add(LoggerUtils.stdOut("Watermarking " + this.watermarkMsg + " into " + classNode.name)); - } else if (this.watermarkType == 1 && NumberUtils.getRandomInt(10) >= 5) { - classNode.signature = StringUtils.aesEncrypt("WMID: " + this.watermarkMsg, this.watermarkKey); - this.logStrings.add(LoggerUtils.stdOut("Watermarking " + this.watermarkMsg + " into " + classNode.name)); - } - } - - cw.newUTF8("RADON" + Radon.VERSION); // :D - } catch (Throwable t) { - this.logStrings.add(LoggerUtils.stdOut("Error while writing " + classNode.name + " -> " + t.getMessage())); - throw t; - } - - ZipEntry newEntry = new ZipEntry(classNode.name + ".class"); - newEntry.setTime(currentTime); - newEntry.setCompressedSize(-1); - this.zos.putNextEntry(newEntry); - this.zos.write(cw.toByteArray()); - this.zos.closeEntry(); - } - - // Write resources to output - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Writing resources to output")); - for (String name : this.passThru.keySet()) { - ZipEntry newEntry = new ZipEntry(name); - newEntry.setTime(currentTime); - this.zos.putNextEntry(newEntry); - this.zos.write(this.passThru.get(name)); - this.zos.closeEntry(); - } - - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - if (this.zos != null) { - //this.zos.setComment("Obfuscation by Radon obfuscator developed by ItzSomebody"); // Cause why not xD - this.zos.close(); - this.logStrings.add(LoggerUtils.stdOut("Finished processing file.")); - } - } catch (Throwable t) { - this.logStrings.add(LoggerUtils.stdOut("Error happened while processing: " - + t.getMessage())); - - if (zos != null) { - zos.close(); - } - if (this.output.delete()) { - this.logStrings.add(LoggerUtils.stdOut("Deleted output.")); - } else { - this.logStrings.add(LoggerUtils.stdOut("Unable to delete faulty output.")); - } - - t.printStackTrace(); - throw new RuntimeException(t.getMessage()); - } finally { - this.logStrings.add(LoggerUtils.stdOut("Writing log.")); - LoggerUtils.logWriter(this.logStrings); - } - } - - /** - * Nice big init method that loads details from the configuration file. - * - * @throws RuntimeException if some error pops up while parsing values - * from {@link Bootstrap#config}. - */ - private void init() throws RuntimeException { - try { - this.config.loadIntoMap(); - this.config.sortExempts(); - this.config.checkConfig(); - this.exempts = this.config.getExempts(); - this.input = this.config.getInput(); - this.output = this.config.getOutput(); - this.libs = this.config.getLibraries(); - this.transformers = new ArrayList<>(); - AbstractTransformer transformer; - // Specific order of adding transformers, feel free to change if - // you wish. - if ((transformer = this.config.getRenamerType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getInnerClassRemoverType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getNumberObfuscationType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getInvokeDynamicType()) != null) { - this.transformers.add(transformer); - } - String expireMsg; - long expireTime; - if ((expireMsg = this.config.getExpiryMsg()) != null - && (expireTime = this.config.getExpiryTime()) != -1) { - transformer = new Expiry(expireTime, expireMsg); - this.transformers.add(transformer); - } - if ((transformer = this.config.getStringEncryptionType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getFlowObfuscationType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getStringPoolType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getShufflerType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getLocalVariableObfuscationType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getLineNumberObfuscationType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getSourceNameObfuscationType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getSourceDebugObfuscationType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getCrasherType()) != null) { - this.transformers.add(transformer); - } - if ((transformer = this.config.getHideCodeType()) != null) { - this.transformers.add(transformer); - } - this.trashClasses = this.config.getTrashClasses(); - this.watermarkMsg = this.config.getWatermarkMsg(); - this.watermarkType = this.config.getWatermarkType(); - this.watermarkKey = this.config.getWatermarkKey(); - this.dictionary = this.config.getDictionaryType(); - if (this.output.exists()) { - this.logStrings.add(LoggerUtils.stdOut("Output already exists, renamed to " - + FileUtils.renameExistingFile(this.output))); - } - if (this.trashClasses != 1 && this.config.getSpigotBool()) { - throw new RuntimeException("Trash classes are not compatible with Spigot's anti-piracy injection."); - } - this.zos = new ZipOutputStream(new FileOutputStream(this.output)); - } catch (Throwable t) { - t.printStackTrace(); - throw new RuntimeException("Error while loading config: " + t.getMessage()); - } - } - - /** - * Loads library classes into classpath. - * - * @throws RuntimeException if library cannot be be opened as Zip or some - * IOE happens. - */ - private void loadClassPath() throws RuntimeException { - ZipFile zipFile; - Enumeration entries; - ZipEntry zipEntry; - for (File lib : this.libs.values()) { - try { - this.logStrings.add(LoggerUtils.stdOut("Loading library " - + lib.getAbsolutePath())); - zipFile = new ZipFile(lib); - entries = zipFile.entries(); - while (entries.hasMoreElements()) { - zipEntry = entries.nextElement(); - if (zipEntry.getName().endsWith(".class") && !zipEntry.isDirectory()) { - ClassReader cr = new ClassReader(zipFile.getInputStream(zipEntry)); - ClassNode classNode = new ClassNode(); - classNode.libraryNode = true; - // We don't need code in methods for libs - cr.accept(classNode, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE); - classNode.methods.forEach(methodNode -> methodNode.owner = classNode.name); - classNode.fields.forEach(fieldNode -> fieldNode.owner = classNode.name); - - this.classPath.put(classNode.name, classNode); - } - } - zipFile.close(); - } catch (ZipException ze) { - throw new RuntimeException("There was an error opening " + lib.getAbsolutePath() + " as a zip!"); - } catch (IOException ioe) { - throw new RuntimeException("Library " + lib.getAbsolutePath() + " does not exist!"); - } - } - } - - /** - * Loads input JAR classes and adds them to {@link Bootstrap#extraClasses} - * and {@link Bootstrap#classes}. - * - * @throws RuntimeException if input cannot be be opened as Zip or some - * IOE happens. - */ - private void loadInput() throws RuntimeException { - ZipFile zipFile; - Enumeration entries; - ZipEntry zipEntry; - try { - this.logStrings.add(LoggerUtils.stdOut("Loading classes of " + this.input.getAbsolutePath())); - zipFile = new ZipFile(this.input); - entries = zipFile.entries(); - while (entries.hasMoreElements()) { - zipEntry = entries.nextElement(); - if (!zipEntry.isDirectory()) { - if (zipEntry.getName().endsWith(".class")) { - ClassReader cr = new ClassReader(zipFile.getInputStream(zipEntry)); - ClassNode classNode = new ClassNode(); - classNode.libraryNode = false; - // We will manually compute stack frames later - cr.accept(classNode, ClassReader.SKIP_FRAMES); - classNode.methods.forEach(methodNode -> methodNode.owner = classNode.name); - classNode.fields.forEach(fieldNode -> fieldNode.owner = classNode.name); - - this.classes.put(classNode.name, classNode); - } else { - this.passThru.put(zipEntry.getName(), FileUtils.toByteArray(zipFile.getInputStream(zipEntry))); - } - } - } - zipFile.close(); - } catch (ZipException ze) { - throw new RuntimeException("There was an error opening " + this.input.getAbsolutePath() + " as a zip!"); - } catch (IOException ioe) { - throw new RuntimeException("Input " + this.input.getAbsolutePath() + " does not exist!"); - } - - this.classPath.putAll(this.classes); - } - - public ClassTree getTree(String ref) { - if (!hierarchy.containsKey(ref)) { - ClassNode wrapper = returnClazz(ref); - buildHierarchy(wrapper, null); - } - - return hierarchy.get(ref); - } - - private void buildHierarchy(ClassNode classNode, ClassNode sub) { - if (hierarchy.get(classNode.name) == null) { - ClassTree tree = new ClassTree(classNode.name, classNode.libraryNode); - tree.classNode = classNode; - if (classNode.superName != null) { - tree.parentClasses.add(classNode.superName); - buildHierarchy(returnClazz(classNode.superName), classNode); - } - if (classNode.interfaces != null && !classNode.interfaces.isEmpty()) { - for (String s : classNode.interfaces) { - tree.parentClasses.add(s); - buildHierarchy(returnClazz(s), classNode); - } - } - hierarchy.put(classNode.name, tree); - } - if (sub != null) { - hierarchy.get(classNode.name).subClasses.add(sub.name); - } - } - - private void buildInheritance() { - classes.values().forEach(classWrapper -> { - buildHierarchy(classWrapper, null); - }); - } - - /** - * Returns the {@link ClassNode} object from {@link Bootstrap#classPath} - * if it exists. - * - * @param ref class name to fetch from {@link Bootstrap#classPath}. - * @return the {@link ClassNode} object from {@link Bootstrap#classPath} - * if it exists. - */ - private ClassNode returnClazz(String ref) { - ClassNode clazz = classPath.get(ref); - if (clazz == null) { - throw new RuntimeException(ref + " does not exist in classpath!"); - } - return clazz; - } - - /** - * Returns the loaded input {@link ClassNode}s. - * - * @return the loaded input {@link ClassNode}s. - */ - public Map getClasses() { - return this.classes; - } - - /** - * Returns the loaded class path. - * - * @return the loaded class path. - */ - public Map getClassPath() { - return this.classPath; - } - - /** - * Returns the map of extra classes. - * - * @return the map of extra classes. - */ - public Map getExtraClasses() { - return this.extraClasses; - } - - /** - * Returns the loaded resources. - * - * @return the loaded resources. - */ - public Map getPassThru() { - return this.passThru; - } - - /** - * CustomClassWriter that doesn't use the internal Java classpath. - * Concept taken from Java-Deobfuscator by samczsun - * - * @author ItzSomebody - */ - class CustomClassWriter extends ClassWriter { - private CustomClassWriter(int flags) { - super(flags); - } - - @Override - protected String getCommonSuperClass(final String type1, - final String type2) { - if (type1.equals("java/lang/Object") - || type2.equals("java/lang/Object")) { - return "java/lang/Object"; - } - - String first = deriveCommonSuperName(type1, type2); - String second = deriveCommonSuperName(type2, type1); - if (!first.equals("java/lang/Object")) { - return first; - } - if (!second.equals("java/lang/Object")) { - return second; - } - - return getCommonSuperClass(returnClazz(type1).superName, returnClazz(type2).superName); - } - - /** - * Attempts to find the common superclass. - * - * @param type1 first class name to lookup. - * @param type2 second class name to lookup. - * @return the common superclass. - */ - private String deriveCommonSuperName(String type1, String type2) { - ClassNode first = returnClazz(type1); - ClassNode second = returnClazz(type2); - if (isAssignableFrom(first, second)) { - return type1; - } else if (isAssignableFrom(first, second)) { - return type2; - } else if (Modifier.isInterface(first.access) || Modifier.isInterface(second.access)) { - return "java/lang/Object"; - } else { - do { - type1 = first.superName; - first = returnClazz(type1); - } while (!isAssignableFrom(first, second)); - return type1; - } - } - - /** - * Returns true/false based on if clazz1 is the superclass of clazz2. - * - * @param clazz1 possible superclass. - * @param clazz2 class to check if assignable from clazz1. - * @return true/false based on if clazz1 is the superclass of clazz2. - */ - private boolean isAssignableFrom(ClassNode clazz1, ClassNode clazz2) { - if (clazz1.name.equals("java/lang/Object")) { - return true; - } - if (clazz1.name.equals(clazz2.name)) { - return true; - } - ClassTree firstTree = getTree(clazz1.name); - Set children = new HashSet<>(); - LinkedList searchThese = new LinkedList<>(firstTree.subClasses); - while (!searchThese.isEmpty()) { - String s = searchThese.poll(); - if (children.add(s)) { - ClassTree tempTree = getTree(clazz2.name); - searchThese.addAll(tempTree.subClasses); - } - } - return children.contains(clazz2.name); - } - } -} diff --git a/src/main/java/me/itzsomebody/radon/internal/ClassTree.java b/src/main/java/me/itzsomebody/radon/internal/ClassTree.java deleted file mode 100644 index 9920f68d..00000000 --- a/src/main/java/me/itzsomebody/radon/internal/ClassTree.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.internal; - -import java.util.HashSet; -import java.util.Set; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldNode; -import org.objectweb.asm.tree.MethodNode; - -/** - * Specifies subclasses and parents of a class. - * - * @author ItzSomebody - */ -public class ClassTree { - /** - * Class name. - */ - public final String className; - - /** - * Attached class node. - */ - public ClassNode classNode; - - /** - * Set of classes that inherit this class. - */ - public final Set subClasses = new HashSet<>(); - - /** - * Set of classes that this class inherits. - */ - public final Set parentClasses = new HashSet<>(); - - /** - * Indication of this class being a library (external) class. - */ - public boolean libraryNode; - - /** - * Constructor to make a {@link ClassTree} object. - * - * @param className name to assign to this {@link ClassTree}. - */ - public ClassTree(String className, boolean libraryNode) { - this.className = className; - this.libraryNode = libraryNode; - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java b/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java deleted file mode 100644 index 83692bc4..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/AbstractTransformer.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers; - -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import me.itzsomebody.radon.internal.Bootstrap; -import me.itzsomebody.radon.utils.MatchUtils; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.commons.CodeSizeEvaluator; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; - -/** - * Abstract class used to make transformers. - * - * @author ItzSomebody - */ -public abstract class AbstractTransformer implements Opcodes { - /** - * Bootstrap instance. - */ - protected Bootstrap bootstrap; - - /** - * Exempt information. - */ - private List exempts; - - /** - * Dictionary for naming. - */ - protected int dictionary; - - /** - * Logged strings from transformer console output. - */ - protected List logStrings; - - /** - * Dependency injection method. - * - * @param bootstrap instance of {@link Bootstrap}. - * @param exempts exempt information. - */ - public void init(Bootstrap bootstrap, - List exempts, int dictionary) { - this.bootstrap = bootstrap; - this.exempts = exempts; - this.dictionary = dictionary; - this.logStrings = new ArrayList<>(); - } - - /** - * Returns the loaded input {@link ClassNode}s. - * - * @return the loaded input {@link ClassNode}s. - */ - protected Map getClassMap() { - return this.bootstrap.getClasses(); - } - - /** - * Returns the map of extra classes. - * - * @return the map of extra classes. - */ - protected Map getExtraClassesMap() { - return this.bootstrap.getExtraClasses(); - } - - /** - * Returns the loaded class path. - * - * @return the loaded class path. - */ - protected Map getClassPathMap() { - return this.bootstrap.getClassPath(); - } - - /** - * Returns the loaded resources. - * - * @return the loaded resources. - */ - protected Map getPassThru() { - return this.bootstrap.getPassThru(); - } - - /** - * Returns only the loaded {@link ClassNode}s. - * - * @return only the loaded {@link ClassNode}s. - */ - protected Collection classNodes() { - return this.getClassMap().values(); - } - - /** - * Returns only the names of the loaded {@link ClassNode}s. - * - * @return only the names of the loaded {@link ClassNode}s. - */ - protected Collection classNames() { - return this.getClassMap().keySet(); - } - - /** - * Returns a {@link Long} which indicates how long a transformer - * processed the classes. - * - * @param started time started. - * @return a {@link Long} which indicates how long a transformer - * processed the classes - */ - protected long tookThisLong(long started) { - return System.currentTimeMillis() - started; - } - - /** - * Returns true if member is exempted from obfuscation. - * - * @param checkThis string to check for exempt. - * @param exemptId per-transformer exempt identifier. - * @return true if member is exempted from obfuscation. - */ - protected boolean exempted(String checkThis, String exemptId) { - String exemptKey = exemptId + ": "; - for (String exempt : this.exempts) { - if (exempt.startsWith(exemptKey)) { - if (MatchUtils.isMatched(exempt.replace(exemptKey, ""), checkThis)) { - return true; - } - } else if (exempt.startsWith("Class: ")) { - if (MatchUtils.isMatched(exempt.replace("Class: ", ""), checkThis)) { - return true; - } - } else if (exempt.startsWith("Method: ")) { - if (MatchUtils.isMatched(exempt.replace("Method: ", ""), checkThis)) { - return true; - } - } else if (exempt.startsWith("Field: ")) { - if (MatchUtils.isMatched(exempt.replace("Field: ", ""), checkThis)) { - return true; - } - } - } - - return false; - } - - /** - * Get's the current size of the method. - * - * @param methodNode the input method to evaluate the size of. - * @return the current size of the method. - */ - protected int methodSize(MethodNode methodNode) { - CodeSizeEvaluator cse = new CodeSizeEvaluator(null); - methodNode.accept(cse); - return cse.getMaxSize(); - } - - /** - * Returns true if this is not either an abstract method, or a native method. - * - * @param methodNode the {@link MethodNode} to check. - * @return true if this is not either an abstract method, or a native method. - */ - protected boolean hasInstructions(MethodNode methodNode) { - return (!Modifier.isNative(methodNode.access) && !Modifier.isAbstract(methodNode.access)); - } - - /** - * Returns a {@link List} of {@link String}s that were outputted into the - * console by transformer. - * - * @return a {@link List} of {@link String}s that were outputted into the - * console by transformer. - */ - public List getLogStrings() { - return this.logStrings; - } - - /** - * Obfuscation time. - */ - public abstract void obfuscate(); -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java deleted file mode 100644 index 34ca1cb6..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/HeavyFlowObfuscation.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.flow; - -import java.util.Stack; -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.analyzer.StackAnalyzer; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.FieldInsnNode; -import org.objectweb.asm.tree.FieldNode; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.JumpInsnNode; -import org.objectweb.asm.tree.LabelNode; -import org.objectweb.asm.tree.LineNumberNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.MethodNode; -import org.objectweb.asm.tree.VarInsnNode; - -/** - * Transformer that does the same as {@link NormalFlowObfuscation}, but with - * a couple extra fake jumps. - * - * @author ItzSomebody - */ -public class HeavyFlowObfuscation extends LightFlowObfuscation { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started heavy flow obfuscation transformer")); - classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { - FieldNode field = new FieldNode(ACC_PUBLIC + ACC_STATIC + - ACC_FINAL, StringUtils.randomString(this.dictionary, len), "Z", null, null); - classNode.fields.add(field); - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Flow") - && hasInstructions(methodNode)).forEach(methodNode -> { - int varIndex = methodNode.maxLocals; - methodNode.maxLocals++; - methodNode.owner = classNode.name; - AbstractInsnNode[] untouchedList = methodNode.instructions.toArray(); - LabelNode labelNode = exitLabel(methodNode); - boolean calledSuper = false; - for (AbstractInsnNode insn : untouchedList) { - if (this.methodSize(methodNode) > 60000) break; - if (methodNode.name.equals("")) { - if (insn instanceof MethodInsnNode) { - if (insn.getOpcode() == INVOKESPECIAL - && insn.getPrevious() instanceof VarInsnNode - && ((VarInsnNode) insn.getPrevious()).var == 0) { - calledSuper = true; - } - } - } - if (insn != methodNode.instructions.getFirst() - && !(insn instanceof LineNumberNode)) { - if (methodNode.name.equals("") && !calledSuper) - continue; - StackAnalyzer sa = new StackAnalyzer(methodNode, insn); - Stack stack = sa.returnStackAtBreak(); - if (stack.isEmpty()) { // We need to make sure stack is empty before making jumps - methodNode.instructions.insertBefore(insn, new VarInsnNode(ILOAD, varIndex)); - methodNode.instructions.insertBefore(insn, - new JumpInsnNode(IFNE, labelNode)); - counter.incrementAndGet(); - } - } - if (insn instanceof JumpInsnNode) { - if (insn.getOpcode() == GOTO) { - methodNode.instructions.insertBefore(insn, - new VarInsnNode(ILOAD, varIndex)); - methodNode.instructions.insertBefore(insn, - new InsnNode(ICONST_0)); - methodNode.instructions.insert(insn, - new InsnNode(ATHROW)); - methodNode.instructions.insert(insn, - new InsnNode(ACONST_NULL)); - methodNode.instructions.set(insn, - new JumpInsnNode(IF_ICMPEQ, - ((JumpInsnNode) insn).label)); - counter.incrementAndGet(); - } else if (insn.getOpcode() >= IFEQ - || insn.getOpcode() <= IF_ICMPLE) { - methodNode.instructions.insert(insn, new JumpInsnNode(IFNE, ((JumpInsnNode) insn).label)); - methodNode.instructions.insert(insn, new VarInsnNode(ILOAD, varIndex)); - counter.incrementAndGet(); - } - } - } - methodNode.instructions.insertBefore(methodNode.instructions - .getFirst(), new VarInsnNode(ISTORE, varIndex)); - methodNode.instructions.insertBefore(methodNode.instructions - .getFirst(), new FieldInsnNode(GETSTATIC, - classNode.name, field.name, "Z")); - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Added " + counter + " instruction sets.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } - - /** - * Inserts an "exit" label into the start of the method node which is used - * by the transformer to branch the stack into a false jump. - * - * @param methodNode current {@link MethodNode} to insert an exit code - * block into. - * @return a {@link LabelNode} used to branch the stack with a false - * conditional. - */ - private LabelNode exitLabel(MethodNode methodNode) { - LabelNode lb = new LabelNode(); - LabelNode escapeNode = new LabelNode(); - AbstractInsnNode target = methodNode.instructions.getFirst(); - methodNode.instructions.insertBefore(target, new JumpInsnNode(GOTO, escapeNode)); - methodNode.instructions.insertBefore(target, lb); - Type returnType = Type.getReturnType(methodNode.desc); - switch (returnType.getSort()) { - case Type.VOID: - methodNode.instructions.insertBefore(target, new InsnNode(RETURN)); - break; - case Type.BOOLEAN: - case Type.CHAR: - case Type.BYTE: - case Type.SHORT: - case Type.INT: - methodNode.instructions.insertBefore(target, new InsnNode(ICONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(IRETURN)); - break; - case Type.LONG: - methodNode.instructions.insertBefore(target, new InsnNode(LCONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(LRETURN)); - break; - case Type.FLOAT: - methodNode.instructions.insertBefore(target, new InsnNode(FCONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(FRETURN)); - break; - case Type.DOUBLE: - methodNode.instructions.insertBefore(target, new InsnNode(DCONST_0)); - methodNode.instructions.insertBefore(target, new InsnNode(DRETURN)); - break; - default: - methodNode.instructions.insertBefore(target, new InsnNode(ACONST_NULL)); - methodNode.instructions.insertBefore(target, new InsnNode(ARETURN)); - break; - } - methodNode.instructions.insertBefore(target, escapeNode); - - return lb; - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java deleted file mode 100644 index ae884b38..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/flow/LightFlowObfuscation.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.flow; - -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.FieldInsnNode; -import org.objectweb.asm.tree.FieldNode; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.JumpInsnNode; - -/** - * Transformer that sets GOTO->LABEL instructions as a condition which is always true. - *

- * getstatic injectedBool (true) - * iconst_1 - * if_icmpeq LABEL - * aconst_null - * athrow - * - * @author ItzSomebody - */ -public class LightFlowObfuscation extends AbstractTransformer { - /** - * Length of names to generate. - */ - protected int len = 10; - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started light flow obfuscation transformer.")); - classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Flow")).forEach(classNode -> { - String fieldName = StringUtils.randomString(this.dictionary, len); - classNode.methods.stream().filter(methodNode -> hasInstructions(methodNode) - && !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Flow") - && BytecodeUtils.containsGoto(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode ain : methodNode.instructions.toArray()) { - if (this.methodSize(methodNode) > 60000) break; - if (ain.getOpcode() == GOTO) { - methodNode.instructions.insertBefore(ain, new FieldInsnNode(GETSTATIC, classNode.name, fieldName, "Z")); - methodNode.instructions.insertBefore(ain, new InsnNode(ICONST_1)); - methodNode.instructions.insert(ain, new InsnNode(ATHROW)); - methodNode.instructions.insert(ain, new InsnNode(ACONST_NULL)); - methodNode.instructions.set(ain, new JumpInsnNode(IF_ICMPEQ, ((JumpInsnNode) ain).label)); - counter.incrementAndGet(); - } - } - }); - classNode.fields.add(new FieldNode(ACC_PUBLIC + ACC_STATIC + - ACC_FINAL, fieldName, "Z", null, true)); - }); - this.logStrings.add(LoggerUtils.stdOut("Added " + counter + " instruction sets.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java deleted file mode 100644 index 1cddda23..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/HeavyInvokeDynamic.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.invokedynamic; - -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.generate.InvokeDynamicBootstrapGenerator; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.Handle; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldInsnNode; -import org.objectweb.asm.tree.InvokeDynamicInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.TypeInsnNode; - -/** - * Transformer that applies an InvokeDynamic obfuscation to field and - * (virtual and static) method access. - * - * @author ItzSomebody. - */ -public class HeavyInvokeDynamic extends LightInvokeDynamic { - /** - * Applies obfuscation. - */ - @Override - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - MemberNames memberNames = new MemberNames(this); - ArrayList finals = new ArrayList<>(); - this.classNodes().forEach(classNode -> - classNode.fields.stream().filter(fieldNode -> Modifier.isFinal(fieldNode.access)).forEach(fieldNode -> - finals.add(classNode.name + '.' + fieldNode.name) - ) - ); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started heavy invokedynamic transformer")); - Handle bsmHandle = new Handle(H_INVOKESTATIC, memberNames.className, memberNames.bootstrapMethodName, "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false); - this.classNodes().parallelStream().filter(classNode -> !this.exempted(classNode.name, "InvokeDynamic") - && classNode.version >= 51).forEach(classNode -> - classNode.methods.parallelStream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "InvokeDynamic") - && hasInstructions(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (this.methodSize(methodNode) > 60000) break; - if (insn instanceof MethodInsnNode) { - MethodInsnNode methodInsnNode = (MethodInsnNode) insn; - if (!methodInsnNode.name.equals("")) { - boolean isStatic = (methodInsnNode.getOpcode() == INVOKESTATIC); - String newSig = isStatic ? methodInsnNode.desc : methodInsnNode.desc.replace("(", "(Ljava/lang/Object;"); - Type returnType = Type.getReturnType(methodInsnNode.desc); - Type[] args = Type.getArgumentTypes(newSig); - for (int i = 0; i < args.length; i++) { - Type arg = args[i]; - if (arg.getSort() == Type.OBJECT) { - args[i] = Type.getType("Ljava/lang/Object;"); - } - } - newSig = Type.getMethodDescriptor(returnType, args); - StringBuilder sb = new StringBuilder(); - sb.append(methodInsnNode.owner.replace("/", ".")).append("<>").append(methodInsnNode.name).append("<>"); - - switch (insn.getOpcode()) { - case INVOKEINTERFACE: - case INVOKEVIRTUAL: { - sb.append("1<>").append(methodInsnNode.desc); - break; - } - case INVOKESPECIAL: { - sb.append("2<>").append(methodInsnNode.desc).append("<>").append(classNode.name.replace("/", ".")); - break; - } - case INVOKESTATIC: { - sb.append("0<>").append(methodInsnNode.desc); - break; - } - } - - InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode( - encrypt(sb.toString(), memberNames), - newSig, - bsmHandle - ); - - methodNode.instructions.set(insn, indy); - if (returnType.getSort() == Type.ARRAY) { - methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); - } - counter.incrementAndGet(); - } - } else if (insn instanceof FieldInsnNode) { - if (!methodNode.name.equals("")) { - FieldInsnNode fieldInsnNode = (FieldInsnNode) insn; - - if (finals.contains(fieldInsnNode.owner + '.' + fieldInsnNode.name)) { - continue; - } - - boolean isStatic = (fieldInsnNode.getOpcode() == GETSTATIC || fieldInsnNode.getOpcode() == PUTSTATIC); - boolean isSetter = (fieldInsnNode.getOpcode() == PUTFIELD || fieldInsnNode.getOpcode() == PUTSTATIC); - String newSig = (isSetter) ? "(" + fieldInsnNode.desc + ")V" : "()" + fieldInsnNode.desc; - if (!isStatic) - newSig = newSig.replace("(", "(Ljava/lang/Object;"); - - StringBuilder sb = new StringBuilder(); - sb.append(fieldInsnNode.owner.replace("/", ".")).append("<>").append(fieldInsnNode.name).append("<>"); - - switch (insn.getOpcode()) { - case GETSTATIC: { - sb.append("3"); - break; - } - case GETFIELD: { - sb.append("4"); - break; - } - case PUTSTATIC: { - sb.append("5"); - break; - } - case PUTFIELD: { - sb.append("6"); - break; - } - } - - InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode( - encrypt(sb.toString(), memberNames), - newSig, - bsmHandle - ); - - methodNode.instructions.set(insn, indy); - counter.incrementAndGet(); - } - } - } - }) - ); - - ClassNode decryptor = InvokeDynamicBootstrapGenerator.heavyBootstrap(memberNames); - this.getClassMap().put(decryptor.name, decryptor); - this.logStrings.add(LoggerUtils.stdOut("Hid " + counter + " field and/or method accesses with invokedynamics.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } - - private static String encrypt(String msg, MemberNames memberNames) { - char[] chars = msg.toCharArray(); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < chars.length; i++) { - switch (i % 4) { - case 0: { - sb.append((char) (chars[i] ^ memberNames.className.replace("/", ".").hashCode())); - break; - } - case 1: { - sb.append((char) (chars[i] ^ memberNames.bootstrapMethodName.hashCode())); - break; - } - case 2: { - sb.append((char) (chars[i] ^ memberNames.className.replace("/", ".").hashCode())); - break; - } - case 3: { - sb.append((char) (chars[i] ^ memberNames.decryptorMethodName.hashCode())); - break; - } - } - } - - return sb.toString(); - } - - /** - * Names of bootstrap class and members. - */ - public class MemberNames { - public String className; - public String decryptorMethodName; - public String bootstrapMethodName; - public String searchMethodName; - - MemberNames(HeavyInvokeDynamic instance) { - this.className = StringUtils.randomClassName(instance.classNames(), instance.dictionary, len); - this.decryptorMethodName = StringUtils.randomString(instance.dictionary, len); - this.bootstrapMethodName = StringUtils.randomString(instance.dictionary, len); - this.searchMethodName = StringUtils.randomString(instance.dictionary, len); - } - } -} \ No newline at end of file diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java deleted file mode 100644 index e4d5bb3d..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/LightInvokeDynamic.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.invokedynamic; - -import java.util.concurrent.atomic.AtomicInteger; - -import me.itzsomebody.radon.generate.InvokeDynamicBSMGenerator; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.Handle; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; - -/** - * Transformer that applies an InvokeDynamic obfuscation which - * produces opcode via string concatenation. - * - * @author ItzSomebody - * @author Licel (transformer is based on IndyProtector) - */ -public class LightInvokeDynamic extends AbstractTransformer { - /* - * Magic numbers - */ - public static final int VIRTUAL_INVOCATION = 1; - public static final int STATIC_INVOCATION = 0; - /** - * Length of names to generate. - */ - protected int len = 10; - - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started invokedynamic transformer")); - String[] bsmPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary, len)}; - Handle bsmHandle = new Handle(Opcodes.H_INVOKESTATIC, - bsmPath[0], - bsmPath[1], - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", - false); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "InvokeDynamic") - && classNode.version >= 51).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "InvokeDynamic") - && hasInstructions(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (this.methodSize(methodNode) > 60000) break; - if (insn instanceof MethodInsnNode - && insn.getOpcode() != INVOKESPECIAL) { - MethodInsnNode methodInsnNode = (MethodInsnNode) insn; - boolean isStatic = (methodInsnNode.getOpcode() == Opcodes.INVOKESTATIC); - - String newSig = - isStatic ? methodInsnNode.desc : methodInsnNode.desc.replace("(", "(Ljava/lang/Object;"); - Type returnType = Type.getReturnType(methodInsnNode.desc); - int opcode = (isStatic) ? this.STATIC_INVOCATION : this.VIRTUAL_INVOCATION; - - InvokeDynamicInsnNode indy = new InvokeDynamicInsnNode(StringUtils.randomString(this.dictionary, len), - newSig, - bsmHandle, - opcode, - encryptOwner(methodInsnNode.owner.replaceAll("/", ".")), - encryptName(methodInsnNode.name), - encryptDesc(methodInsnNode.desc)); - methodNode.instructions.set(insn, indy); - if (returnType.getSort() == Type.ARRAY) { - methodNode.instructions.insert(indy, new TypeInsnNode(CHECKCAST, returnType.getInternalName())); - } - counter.incrementAndGet(); - } - } - }); - }); - // Add BSM method - ClassNode bsmHost = getClassMap().get(bsmPath[0]); - addBSM(bsmHost, bsmPath[1]); - // Do logging - this.logStrings.add(LoggerUtils.stdOut("Replaced " + counter + " method invocations with invokedynamics.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } - - protected void addBSM(ClassNode bsmHost, String methodName) { - bsmHost.methods.add(InvokeDynamicBSMGenerator.lightBSM(methodName, bsmHost.name)); - bsmHost.access = BytecodeUtils.makePublic(bsmHost.access); - } - - /** - * Returns string with a simple encryption. - * - * @param owner inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encryptOwner(String owner) { - char[] encClassNameChars = owner.toCharArray(); - char[] classNameChars = new char[encClassNameChars.length]; - for (int i = 0; i < encClassNameChars.length; i++) { - classNameChars[i] = (char) (encClassNameChars[i] ^ 1029); - } - - return new String(classNameChars); - } - - /** - * Returns string with a simple encryption. - * - * @param name inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encryptName(String name) { - char[] encMethodNameChars = name.toCharArray(); - char[] methodNameChars = new char[encMethodNameChars.length]; - for (int i = 0; i < encMethodNameChars.length; i++) { - methodNameChars[i] = (char) (encMethodNameChars[i] ^ 2038); - } - - return new String(methodNameChars); - } - - /** - * Returns string with a simple encryption. - * - * @param desc inputed string to be encrypted. - * @return string with a simple encryption. - */ - private String encryptDesc(String desc) { - char[] encDescChars = desc.toCharArray(); - char[] descChars = new char[encDescChars.length]; - for (int i = 0; i < encDescChars.length; i++) { - descChars[i] = (char) (encDescChars[i] ^ 1928); - } - - return new String(descChars); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java b/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java deleted file mode 100644 index c783d996..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/invokedynamic/NormalInvokeDynamic.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.invokedynamic; - -import me.itzsomebody.radon.generate.InvokeDynamicBSMGenerator; -import me.itzsomebody.radon.utils.BytecodeUtils; -import org.objectweb.asm.tree.*; - -/** - * Transformer that applies an InvokeDynamic which attempts to prevent - * deobfuscation to happen if {@link Runtime#getRuntime()} is disabled. - * Specifically java-deobfuscator's MethodExecutor. - * - * @author ItzSomebody - * @author Licel (transformer based on IndyProtector) - */ -public class NormalInvokeDynamic extends LightInvokeDynamic { - @Override - protected void addBSM(ClassNode bsmHost, String methodName) { - bsmHost.methods.add(InvokeDynamicBSMGenerator.normalBSM(methodName, bsmHost.name)); - bsmHost.access = BytecodeUtils.makePublic(bsmHost.access); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java deleted file mode 100644 index 62357f6e..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/ObfuscateLineNumbers.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.linenumbers; - -import java.lang.reflect.Modifier; -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.NumberUtils; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.LineNumberNode; - -/** - * Transformer that applies a line number obfuscation by changing the - * corresponding numbers linked to labels - * to random numbers. - * - * @author ItzSomebody - */ -public class ObfuscateLineNumbers extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started line obfuscation transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "LineNumbers")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LineNumbers") - && hasInstructions(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (insn instanceof LineNumberNode) { - LineNumberNode lineNumberNode = (LineNumberNode) insn; - methodNode.instructions.set(insn, - new LineNumberNode(NumberUtils.getRandomInt(Integer.MAX_VALUE), lineNumberNode.start)); - counter.incrementAndGet(); - } - } - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Obfuscated " + counter + " line numbers.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java b/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java deleted file mode 100644 index ffd02e81..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/linenumbers/RemoveLineNumbers.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.linenumbers; - -import java.lang.reflect.Modifier; -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.LineNumberNode; - -/** - * Transformer that applies a line number obfuscation by removing them. - * - * @author ItzSomebody - */ -public class RemoveLineNumbers extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started line removal transformer")); - this.classNodes().stream().filter(classNode -> - !this.exempted(classNode.name, "LineNumbers")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LineNumbers") - && hasInstructions(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (insn instanceof LineNumberNode) { - methodNode.instructions.remove(insn); - counter.incrementAndGet(); - } - } - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Removed " + counter + " line numbers.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java b/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java deleted file mode 100644 index f5b37109..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/localvariables/ObfuscateLocalVariables.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.localvariables; - -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; - -/** - * Transformer that applies a local variable obfuscation by changing the names. - * - * @author ItzSomebody - */ -public class ObfuscateLocalVariables extends AbstractTransformer { - /** - * Length of names to generate. - */ - private static int len = 10; - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started local variable obfuscation transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "LocalVars")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LocalVars") - && methodNode.localVariables != null).forEach(methodNode -> { - methodNode.localVariables.forEach(localVariableNode -> { - localVariableNode.name = StringUtils.crazyString(len); - counter.incrementAndGet(); - }); - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Obfuscated " + counter + " local variables.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java b/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java deleted file mode 100644 index 45f2015a..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/localvariables/RemoveLocalVariables.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.localvariables; - -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; - -/** - * Transformer that applies a local variable obfuscation by removing t - * - * @author ItzSomebody - */ -public class RemoveLocalVariables extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started local variable removal transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "LocalVars")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "LocalVars") - && methodNode.localVariables != null).forEach(methodNode -> { - counter.addAndGet(methodNode.localVariables.size()); - methodNode.localVariables = null; - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Removed " + counter + " local variables.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java deleted file mode 100644 index b86d3c6a..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Crasher.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.misc; - -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; - -/** - * Transformer that applies a crashing technique by exploiting class signature parsing. - *

- * Crashes: - * - JD-GUI - * - ProCyon - * - CFR - *

- * - * @author ItzSomebody - */ -public class Crasher extends AbstractTransformer { - /** - * Length of names to generate. - */ - private int len = 10; - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started crasher transformer.")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Crasher")).forEach(classNode -> { - if (classNode.signature == null) { - classNode.signature = StringUtils.crazyString(len); - counter.incrementAndGet(); - } - }); - this.logStrings.add(LoggerUtils.stdOut("Added " + counter + " crashers.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java deleted file mode 100644 index 23ce2db1..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Expiry.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.misc; - -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; - -/** - * Transformer that adds an expiration block of code to methods. - * - * @author ItzSomebody - * @author Allatori Dev Team (transformer based on Allatori's - * expiration obfuscation) - */ -public class Expiry extends AbstractTransformer { - /** - * The expiry time as a {@link Long}. - */ - private long expiryTime; - - /** - * The expiry message to display when expiry time is exceeded. - */ - private String expiryMsg; - - /** - * Constructor used to create an {@link Expiry} object. - * - * @param expiryTime expiration time as a {@link Long}. - * @param expiryMsg expiration message as a {@link String}. - */ - public Expiry(long expiryTime, String expiryMsg) { - this.expiryTime = expiryTime; - this.expiryMsg = expiryMsg; - } - - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started expiry transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Expiry")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Expiry") - && methodNode.name.equals("") - && methodSize(methodNode) < 60000 - && hasInstructions(methodNode)).forEach(methodNode -> { - methodNode.instructions.insertBefore(methodNode.instructions.getFirst(), - BytecodeUtils.createExpiry(this.expiryTime, this.expiryMsg)); - counter.incrementAndGet(); - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Added " + counter + " expiration code blocks.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java b/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java deleted file mode 100644 index fa41333b..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/HideCode.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.misc; - -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; - -/** - * Transformer that applies a code hiding technique by applying synthetic modifiers to the class, fields, and methods. - * - * @author ItzSomebody - */ -public class HideCode extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started hide code transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "HideCode")).forEach(classNode -> { - if (!BytecodeUtils.isSynthetic(classNode.access) - && !BytecodeUtils.hasAnnotations(classNode)) { - classNode.access |= ACC_SYNTHETIC; - counter.incrementAndGet(); - } - - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "HideCode") - && !BytecodeUtils.hasAnnotations(methodNode)).forEach(methodNode -> { - boolean hidOnce = false; - if (!BytecodeUtils.isSynthetic(methodNode.access)) { - methodNode.access |= ACC_SYNTHETIC; - hidOnce = true; - } - - if (!BytecodeUtils.isBridge(methodNode.access) - && !methodNode.name.startsWith("<")) { - methodNode.access |= ACC_BRIDGE; - hidOnce = true; - } - - if (hidOnce) counter.incrementAndGet(); - }); - - if (classNode.fields != null) - classNode.fields.stream().filter(fieldNode -> - !exempted(classNode.name + '.' + fieldNode.name, "HideCode") - && !BytecodeUtils.hasAnnotations(fieldNode)).forEach(fieldNode -> { - if (!BytecodeUtils.isSynthetic(fieldNode.access)) { - fieldNode.access |= ACC_SYNTHETIC; - counter.incrementAndGet(); - } - }); - }); - this.logStrings.add(LoggerUtils.stdOut("Hid " + counter + " members.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/InnerClassRemover.java b/src/main/java/me/itzsomebody/radon/transformers/misc/InnerClassRemover.java deleted file mode 100644 index 5f87c183..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/InnerClassRemover.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.misc; - -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; - -/** - * Transformer which removes innerclass infomation. - * - * @author ItzSomebody - */ -public class InnerClassRemover extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started inner class removal transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "InnerClasses") - && classNode.innerClasses != null).forEach(classNode -> { - counter.addAndGet(classNode.innerClasses.size()); - classNode.innerClasses.clear(); - }); - this.logStrings.add(LoggerUtils.stdOut("Removed " + counter + " inner class infos.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java b/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java deleted file mode 100644 index 99627772..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/NumberObfuscation.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.misc; - -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.NumberUtils; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.InsnList; -import org.objectweb.asm.tree.InsnNode; - -/** - * Transformer that splits up integers into simple bitwise evaluations. - * - * @author ItzSomebody - */ -public class NumberObfuscation extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started number obfuscation transformer")); - this.classNodes().parallelStream().filter(classNode -> !this.exempted(classNode.name, "Numbers")).forEach(classNode -> - classNode.methods.parallelStream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "Numbers") - && hasInstructions(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (methodSize(methodNode) > 60000) break; - if (BytecodeUtils.isIntInsn(insn)) { - int originalNum = BytecodeUtils.getIntNumber(insn); - int value1 = NumberUtils.getRandomInt(); - int value2 = originalNum ^ value1; - - InsnList insnList = new InsnList(); - insnList.add(BytecodeUtils.createNumberInsn(value1)); - insnList.add(BytecodeUtils.createNumberInsn(NumberUtils.getRandomInt())); - insnList.add(new InsnNode(SWAP)); - insnList.add(new InsnNode(DUP_X1)); - insnList.add(new InsnNode(POP2)); - insnList.add(BytecodeUtils.createNumberInsn(value2)); - insnList.add(new InsnNode(IXOR)); - - methodNode.instructions.insertBefore(insn, insnList); - methodNode.instructions.remove(insn); - counter.incrementAndGet(); - } else if (BytecodeUtils.isLongInsn(insn)) { - long originalNum = BytecodeUtils.getLongNumber(insn); - long value1 = NumberUtils.getRandomLong(); - long value2 = originalNum ^ value1; - - InsnList insnList = new InsnList(); - insnList.add(BytecodeUtils.createNumberInsn(NumberUtils.getRandomLong())); - insnList.add(BytecodeUtils.createNumberInsn(value1)); - insnList.add(new InsnNode(DUP2_X2)); - insnList.add(new InsnNode(POP2)); - insnList.add(new InsnNode(POP2)); - insnList.add(BytecodeUtils.createNumberInsn(value2)); - insnList.add(new InsnNode(LXOR)); - - methodNode.instructions.insertBefore(insn, insnList); - methodNode.instructions.remove(insn); - counter.incrementAndGet(); - } - } - }) - ); - this.logStrings.add(LoggerUtils.stdOut("Split " + counter + " numbers into bitwise xor instructions.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Renamer.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Renamer.java deleted file mode 100644 index 3e58036e..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Renamer.java +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.misc; - -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.internal.ClassTree; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.NumberUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.commons.ClassRemapper; -import org.objectweb.asm.commons.Remapper; -import org.objectweb.asm.commons.SimpleRemapper; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldNode; -import org.objectweb.asm.tree.MethodNode; - -/** - * Transformer that renames classes and their members. - * FIXME: Figure out why this doesn't work with TestingProject - * - * @author ItzSomebody - */ -public class Renamer extends AbstractTransformer { - /** - * Used for class, method and field renamming. Format is oldName -> newName. - */ - private Map mappings = new HashMap<>(); - - /** - * Indication to look for Bukkit/Bungee main methods. - */ - private boolean spigotMode; - - /** - * Length of names to generate. - */ - private int len = 10; - - /** - * Constructor used to create a {@link Renamer} object. - */ - public Renamer(boolean spigotMode) { - this.spigotMode = spigotMode; - } - - /** - * Applies obfuscation. - */ - public void obfuscate() { - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Starting renamer transformer")); - this.logStrings.add(LoggerUtils.stdOut("Generating mappings.")); - long current = System.currentTimeMillis(); - AtomicInteger counter = new AtomicInteger(); - this.classNodes().forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> !Modifier.isNative(methodNode.access) - && !methodNode.name.equals("main") - && !methodNode.name.equals("premain") - && !methodNode.name.startsWith("<") - && !methodNode.name.contains("lambda")).forEach(methodNode -> { - if (this.weCanRenameMethod(methodNode)) { - String newName = StringUtils.randomString(this.dictionary, len); - this.renameMethodTree(new HashSet<>(), methodNode, classNode.name, newName); - } - }); - - classNode.fields.forEach(fieldNode -> { - if (this.weCanRenameField(fieldNode)) { - String newName = StringUtils.randomString(this.dictionary, len); - this.renameFieldTree(new HashSet<>(), fieldNode, classNode.name, newName); - } - }); - - if (!this.exempted(classNode.name, "Renamer")) { - int packages = NumberUtils.getRandomInt(2) + 1; - StringBuilder newName = new StringBuilder(); - for (int i = 0; i < packages; i++) { - newName.append(StringUtils.randomString(this.dictionary, len)).append('/'); - } - - this.mappings.put(classNode.name, newName.substring(0, newName.length() - 1)); - counter.incrementAndGet(); - } - }); - this.logStrings.add(LoggerUtils.stdOut("Finished generated mappings. [" + String.valueOf(System.currentTimeMillis() - current) + "ms]")); - this.logStrings.add(LoggerUtils.stdOut("Applying mappings.")); - - // Apply mapping - Remapper simpleRemapper = new SimpleRemapper(this.mappings); - for (ClassNode classNode : new ArrayList<>(this.classNodes())) { - ClassNode copy = new ClassNode(); - classNode.accept(new ClassRemapper(copy, simpleRemapper)); - copy.access = BytecodeUtils.makePublic(copy.access); - for (MethodNode methodNode : copy.methods) { - methodNode.access = BytecodeUtils.makePublic(methodNode.access); - } - - if (copy.fields != null) { - for (FieldNode fieldNode : copy.fields) { - fieldNode.access = BytecodeUtils.makePublic(fieldNode.access); - } - } - - this.getClassMap().remove(classNode.name); - this.getClassPathMap().put(copy.name, copy); - this.getClassMap().put(copy.name, copy); - } - - this.logStrings.add(LoggerUtils.stdOut("Mapped " + counter + " members.")); - current = System.currentTimeMillis(); - - // Fix screw ups in resources. - this.logStrings.add(LoggerUtils.stdOut("Attempting to map class names in resources")); - AtomicInteger fixed = new AtomicInteger(); - getPassThru().forEach((name, byteArray) -> { - if (name.equals("META-INF/MANIFEST.MF") - || (name.equals("plugin.yml") && spigotMode)) { - String stringVer = new String(byteArray); - for (String mapping : mappings.keySet()) { - String original = mapping.replace("/", "."); - if (stringVer.contains(original)) { - // Regex that ensures that class names that match words in the manifest don't break the manifest - // Example: name == Main - stringVer = stringVer.replaceAll("(?<=[: ])" + original, mappings.get(mapping).replace("/", ".")); - } - } - - try { - getPassThru().put(name, stringVer.getBytes("UTF-8")); - fixed.incrementAndGet(); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - throw new RuntimeException(e.getMessage()); - } - } - }); - this.logStrings.add(LoggerUtils.stdOut("Mapped " + fixed + " names in resources. [" + tookThisLong(current) + "ms]")); - this.logStrings.add(LoggerUtils.stdOut("Finished applying mappings. [" + String.valueOf(System.currentTimeMillis() - current) + "ms]")); - } - - /** - * Ultimately determines if we can rename a method without running into errors. - * - * @param methodNode {@link MethodNode} we want to check if we can rename without causing the JVM to spit lots of errors. - * @return true if we can rename a method without running into errors. - */ - private boolean weCanRenameMethod(MethodNode methodNode) { - return !this.isLibInheritedMN(new HashSet<>(), methodNode, methodNode.owner); - } - - /** - * Attempts to determine if the method we input is inherited from a library class or is exempted. - * - * @param visited a set of {@link ClassTree}s which contain the {@link MethodNode}s we already checked. - * @param methodNode {@link MethodNode} we want to check if we can rename without causing the JVM to spit lots of errors. - * @param className the name of the class we want to check - * @return true if the method we input is inherited from a library class. - */ - private boolean isLibInheritedMN(HashSet visited, MethodNode methodNode, String className) { - ClassTree ct = this.bootstrap.getTree(className); - if (ct == null) - throw new RuntimeException(className + " doesn't exist in classpath."); - if (!visited.contains(ct)) { - visited.add(ct); - if (!methodNode.owner.equals(className)) { - for (MethodNode mn : ct.classNode.methods) { - if (mn.name.equals(methodNode.name) && mn.desc.equals(methodNode.desc)) { - if (ct.libraryNode) { - return true; - } - } - } - } - if (exempted(className + '.' + methodNode.name + methodNode.desc, "Renamer")) { - return true; - } - for (String parentClass : ct.parentClasses) { - if (parentClass != null && this.isLibInheritedMN(visited, methodNode, parentClass)) { - return true; - } - } - - for (String subClass : ct.subClasses) { - if (subClass != null && this.isLibInheritedMN(visited, methodNode, subClass)) { - return true; - } - } - } - - return false; - } - - /** - * Renames the methods in an inheritance tree to prevent inheritance errors. - * - * @param visited a set of {@link ClassTree}s which contain the {@link MethodNode}s we already renamed. - * @param methodNode the method information. - * @param className the class we are currently browsing through. - * @param newName the new name of the method. - */ - private void renameMethodTree(HashSet visited, MethodNode methodNode, String className, String newName) { - ClassTree ct = this.bootstrap.getTree(className); - if (ct == null) - throw new RuntimeException(className + " doesn't exist in classpath."); - if (!ct.libraryNode && !visited.contains(ct)) { - mappings.put(className + '.' + methodNode.name + methodNode.desc, newName); - visited.add(ct); - for (String parentClass : ct.parentClasses) { - this.renameMethodTree(visited, methodNode, parentClass, newName); - } - for (String subClass : ct.subClasses) { - this.renameMethodTree(visited, methodNode, subClass, newName); - } - } - } - - /** - * Ultimately determines if we can rename a field without running into errors. - * - * @param fieldNode {@link FieldNode} we want to check if we can rename without causing the JVM to spit lots of errors. - * @return true if we can rename a field without running into errors. - */ - private boolean weCanRenameField(FieldNode fieldNode) { - return this.isLibInheritedFN(new HashSet<>(), fieldNode, fieldNode.owner); - } - - /** - * Attempts to determine if the method we input is inherited from a library class or is exempted. - * - * @param fieldNode {@link FieldNode} we want to check if we can rename without causing the JVM to spit lots of errors. - * @param className the name of the class we want to check - * @return true if the method we input is inherited from a library class. - */ - private boolean isLibInheritedFN(HashSet visited, FieldNode fieldNode, String className) { - ClassTree ct = this.bootstrap.getTree(className); - if (ct == null) - throw new RuntimeException(className + " doesn't exist in classpath."); - if (!visited.contains(ct)) { - visited.add(ct); - if (!fieldNode.owner.equals(className)) { - for (MethodNode mn : ct.classNode.methods) { - if (mn.name.equals(fieldNode.name) && mn.desc.equals(fieldNode.desc)) { - if (ct.libraryNode) { - return true; - } - } - } - } - if (exempted(className + '.' + fieldNode.name, "Renamer")) { - return true; - } - for (String parentClass : ct.parentClasses) { - if (parentClass != null && this.isLibInheritedFN(visited, fieldNode, parentClass)) { - return true; - } - } - - for (String subClass : ct.subClasses) { - if (subClass != null && this.isLibInheritedFN(visited, fieldNode, subClass)) { - return true; - } - } - } - - return false; - } - - /** - * Renames the methods in an inheritance tree to prevent inheritance errors. - * - * @param visited a list of {@link ClassTree}s which contain the - * {@link MethodNode}s we already renamed. - * @param fieldNode the method information. - * @param className the class we are currently browsing through. - * @param newName the new name of the method. - */ - private void renameFieldTree(HashSet visited, FieldNode fieldNode, - String className, String newName) { - ClassTree ct = this.bootstrap.getTree(className); - if (ct == null) - throw new RuntimeException(className + " doesn't exist in classpath."); - if (!ct.libraryNode && !visited.contains(ct)) { - this.mappings.put(className + '.' + fieldNode.name, newName); - visited.add(ct); - for (String parentClass : ct.parentClasses) { - this.renameFieldTree(visited, fieldNode, parentClass, newName); - } - for (String subClass : ct.subClasses) { - this.renameFieldTree(visited, fieldNode, subClass, newName); - } - } - } -} \ No newline at end of file diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/Shuffler.java b/src/main/java/me/itzsomebody/radon/transformers/misc/Shuffler.java deleted file mode 100644 index 64033206..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/Shuffler.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.misc; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; - -/** - * Transformer which shuffles class members. - * - * @author ItzSomebody - */ -public class Shuffler extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started shuffle transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "Shuffler")).forEach(classNode -> { - Collections.shuffle(classNode.methods); - counter.addAndGet(classNode.methods.size()); - if (classNode.fields != null) { - Collections.shuffle(classNode.fields); - counter.addAndGet(classNode.fields.size()); - } - }); - this.logStrings.add(LoggerUtils.stdOut("Shuffled " + counter + " members.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java b/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java deleted file mode 100644 index 2d809a23..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/StringPool.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.misc; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.Label; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.FieldInsnNode; -import org.objectweb.asm.tree.FieldNode; -import org.objectweb.asm.tree.InsnList; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.LdcInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.MethodNode; - -/** - * Transformer that takes all the strings in a class and pools them into a - * field. When the string is needed, the string pool field is called with - * an index number. - * - * @author ItzSomebody - */ -public class StringPool extends AbstractTransformer { - /** - * Length of names to generate. - */ - private int len = 10; - /** - * Path to pool method. - */ - private String randName; - - /** - * Array of {@link String}s that will be pooled - */ - private String[] strings; - - /** - * Field path. - */ - private String[] fieldName = new String[2]; - - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started string pool transformer.")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringPool")).forEach(classNode -> { - this.randName = StringUtils.randomString(this.dictionary, len); - this.fieldName[0] = classNode.name; - this.fieldName[1] = StringUtils.randomString(this.dictionary, len); - List stringslist = new ArrayList<>(); - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.name, "StringPool") - && hasInstructions(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (insn instanceof LdcInsnNode) { - Object cst = ((LdcInsnNode) insn).cst; - - if (cst instanceof String) { - stringslist.add((String) cst); - - int indexNumber = stringslist.size() - 1; - - methodNode.instructions.insertBefore(insn, new FieldInsnNode(GETSTATIC, classNode.name, this.fieldName[1], "[Ljava/lang/String;")); - methodNode.instructions.insertBefore(insn, BytecodeUtils.createNumberInsn(indexNumber)); - methodNode.instructions.set(insn, new InsnNode(AALOAD)); - counter.incrementAndGet(); - } - } - } - }); - if (stringslist.size() != 0) { - this.strings = new String[stringslist.size()]; - for (int i = 0; i < stringslist.size(); i++) { - this.strings[i] = stringslist.get(i); - } - classNode.methods.add(stringPool()); - - MethodNode clinit = classNode.methods.stream().filter(methodNode -> methodNode.name.equals("")).findFirst().orElse(null); - if (clinit == null) { - clinit = new MethodNode(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "", "()V", null, null); - InsnList insns = new InsnList(); - insns.add(new MethodInsnNode(INVOKESTATIC, classNode.name, randName, "()V", false)); - insns.add(new InsnNode(RETURN)); - clinit.instructions = insns; - classNode.methods.add(clinit); - } else { - clinit.instructions.insertBefore(clinit.instructions.getFirst(), new MethodInsnNode(INVOKESTATIC, classNode.name, randName, "()V", false)); - } - FieldNode fieldNode = new FieldNode(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, this.fieldName[1], "[Ljava/lang/String;", null, null); - if (classNode.fields == null) - classNode.fields = new ArrayList<>(); - classNode.fields.add(fieldNode); - } - }); - this.logStrings.add(LoggerUtils.stdOut("Pooled " + counter + " strings.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } - - /** - * String pool method which contains all the strings. - * - * @return string pool method which contains all the strings. - */ - private MethodNode stringPool() { - MethodNode method = new MethodNode(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC + ACC_BRIDGE, randName, "()V", null, null); - - method.visitCode(); - - Label l0 = new Label(); - method.visitLabel(l0); - int numberOfStrings = this.strings.length; - if (numberOfStrings <= 5) { - method.visitInsn(numberOfStrings + 3); - } else if (numberOfStrings <= 127) { - method.visitIntInsn(BIPUSH, this.strings.length); - } else if (numberOfStrings <= 32767) { - method.visitIntInsn(SIPUSH, this.strings.length); - } else { - method.visitLdcInsn(this.strings.length); - } - - method.visitTypeInsn(ANEWARRAY, "java/lang/String"); - - for (int i = 0; i < this.strings.length; i++) { - method.visitInsn(DUP); - - if (i <= 5) { - method.visitInsn(i + 3); - } else if (i <= 127) { - method.visitIntInsn(BIPUSH, i); - } else if (i <= 32767) { - method.visitIntInsn(SIPUSH, i); - } else { - method.visitLdcInsn(i); - } - - method.visitLdcInsn(this.strings[i]); - method.visitInsn(AASTORE); - } - method.visitFieldInsn(PUTSTATIC, this.fieldName[0], this.fieldName[1], "[Ljava/lang/String;"); - method.visitInsn(RETURN); - - method.visitMaxs(3, 0); - - method.visitEnd(); - - return method; - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java b/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java deleted file mode 100644 index 8670c172..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/misc/TrashClasses.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.misc; - -import me.itzsomebody.radon.utils.NumberUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.Handle; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldInsnNode; -import org.objectweb.asm.tree.IincInsnNode; -import org.objectweb.asm.tree.InsnList; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.IntInsnNode; -import org.objectweb.asm.tree.InvokeDynamicInsnNode; -import org.objectweb.asm.tree.LdcInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.MethodNode; -import org.objectweb.asm.tree.VarInsnNode; - -/** - * Not really a transformer. This "transformer" generates trash classes full - * of useless Java bytecode that does nothing. - * - * @author ItzSomebody - */ -public class TrashClasses { - /** - * Length of names to generate. - */ - private static int len = 10; - /** - * Class name for the trash class. - */ - private String trashClassName; - - /** - * Constructor used to create a {@link TrashClasses} object. - * - * @param trashClassName class name for the trash class. - */ - public TrashClasses(String trashClassName) { - this.trashClassName = trashClassName; - } - - /** - * Returns a fully built trash class. - * - * @return a fully built trash class. - */ - public ClassNode returnTrashClass() { - ClassNode classNode = createClass(trashClassName); - int methodsToGenerate = NumberUtils.getRandomInt(3) + 2; - - for (int i = 0; i < methodsToGenerate; i++) { - classNode.methods.add(methodGen()); - } - - return classNode; - } - - /** - * Builds and returns an empty class. - * - * @param className the string used for the class name. - * @return an empty {@link ClassNode}. - */ - private ClassNode createClass(String className) { - ClassNode classNode = new ClassNode(); - - classNode.visit(49, Opcodes.ACC_SUPER + Opcodes.ACC_PUBLIC, - className, null, "java/lang/Object", null); - - MethodVisitor mv = classNode.visitMethod(Opcodes.ACC_PUBLIC, "", - "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(Opcodes.ALOAD, 0); - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", - "", "()V", false); - mv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - - classNode.visitEnd(); - - return classNode; - } - - /** - * Builds and returns a {@link MethodNode}. - * - * @return a {@link MethodNode}. - */ - private MethodNode methodGen() { - String randDesc = descGen(); - MethodNode method = new MethodNode(Opcodes.ACC_STATIC + - Opcodes.ACC_PRIVATE, StringUtils.crazyString(len), randDesc, - null, null); - int instructions = NumberUtils.getRandomInt(30) + 30; - - InsnList insns = new InsnList(); - - for (int i = 0; i < instructions; ++i) { - insns.add(junkInsns()); - } - - if (randDesc.endsWith(")Ljava/lang/String;") - || randDesc.endsWith(")Ljava/lang/Object;")) { - insns.add(new VarInsnNode(Opcodes.ALOAD, - NumberUtils.getRandomInt(30))); - insns.add(new InsnNode(Opcodes.ARETURN)); - } else if (randDesc.endsWith(")Z")) { - if (NumberUtils.getRandomInt(1) == 1) { - insns.add(new InsnNode(Opcodes.ICONST_0)); - } else { - insns.add(new InsnNode(Opcodes.ICONST_1)); - } - - insns.add(new InsnNode(Opcodes.IRETURN)); - } else if (randDesc.endsWith(")V")) { - insns.add(new InsnNode(Opcodes.RETURN)); - } - - method.instructions = insns; - return method; - } - - /** - * Generates a description for a trash method. - * - * @return generated description for a trash method. - */ - private String descGen() { - switch (NumberUtils.getRandomInt(7)) { - case 0: - return "(Ljava/lang/String;)Ljava/lang/String;"; - case 1: - return "(Ljava/lang/Object;)Ljava/lang/Object;"; - case 2: - return "(I)Z"; - case 3: - return "()V"; - case 4: - return "(B)V"; - case 5: - return "(Ljava/lang/Object;Ljava/lang/Object;" + - "Ljava/lang/Object;)Ljava/lang/Object;"; - case 6: // False BSM lol - default: - return "(Ljava/lang/invoke/MethodHandles$Lookup;" + - "Ljava/lang/String;Ljava/lang/invoke/MethodType;" + - "ILjava/lang/String;Ljava/lang/String;" + - "Ljava/lang/String;)Ljava/lang/Object;"; - } - } - - /** - * Returns a random opcode instruction to add to trash methods. - * - * @return a random opcode instruction to add to trash methods. - */ - private static AbstractInsnNode junkInsns() { - int index = NumberUtils.getRandomInt(20); - switch (index) { - case 0: - return new MethodInsnNode(Opcodes.INVOKESTATIC, - StringUtils.crazyString(len), StringUtils.crazyString(len), - "(Ljava/lang/String;)V", false); - case 1: - return new FieldInsnNode(Opcodes.GETFIELD, - StringUtils.crazyString(len), StringUtils.crazyString(len), - "I"); - case 2: - return new InsnNode(NumberUtils.getRandomInt(16)); - case 3: - return new VarInsnNode(Opcodes.ALOAD, - NumberUtils.getRandomInt(30)); - case 4: - return new IntInsnNode(Opcodes.BIPUSH, - NumberUtils.getRandomInt(255)); - case 5: - return new IntInsnNode(Opcodes.SIPUSH, - NumberUtils.getRandomInt(25565)); - case 6: - case 7: - case 8: - return new InsnNode(NumberUtils.getRandomInt(5)); - case 9: - return new LdcInsnNode(StringUtils.crazyString(len)); - case 10: - return new IincInsnNode(NumberUtils.getRandomInt(16), - NumberUtils.getRandomInt(16)); - case 11: - return new MethodInsnNode(Opcodes.INVOKESPECIAL, - StringUtils.crazyString(len), StringUtils.crazyString(len), - "()V", false); - case 12: - return new MethodInsnNode(Opcodes.INVOKEVIRTUAL, - StringUtils.crazyString(len), StringUtils.crazyString(len), - "(Ljava/lang/Object;)Ljava/lang/Object;", false); - case 13: - return new VarInsnNode(Opcodes.ILOAD, - NumberUtils.getRandomInt(30)); - case 14: - return new InsnNode(Opcodes.ATHROW); - case 15: - return new MethodInsnNode(Opcodes.INVOKEINTERFACE, - StringUtils.crazyString(len), StringUtils.crazyString(len), - "(I)I", false); - case 16: - Handle handle = new Handle(6, StringUtils.crazyString(len), - StringUtils.crazyString(len), StringUtils.crazyString(len), - false); - return new InvokeDynamicInsnNode(StringUtils.crazyString(len), - StringUtils.crazyString(len), handle, - NumberUtils.getRandomInt(5), - NumberUtils.getRandomInt(5), - NumberUtils.getRandomInt(5), - NumberUtils.getRandomInt(5), - NumberUtils.getRandomInt(5)); - case 17: - return new IntInsnNode(Opcodes.ANEWARRAY, - NumberUtils.getRandomInt(30)); - case 18: - return new VarInsnNode(Opcodes.ASTORE, - NumberUtils.getRandomInt(30)); - case 19: - default: - return new VarInsnNode(Opcodes.ISTORE, - NumberUtils.getRandomInt(30)); - } - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java b/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java deleted file mode 100644 index 3d82ba48..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/ObfuscateSourceDebug.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.sourcedebug; - -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; - -/** - * Transformer that obfuscates the source debug attribute by changing the - * corresponding value. - * - * @author ItzSomebody - */ -public class ObfuscateSourceDebug extends AbstractTransformer { - /** - * Length of names to generate. - */ - private int len = 10; - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started source debug obfuscation transformer")); - String newDebug = StringUtils.crazyString(len); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "SourceDebug") - && classNode.sourceDebug != null).forEach(classNode -> { - classNode.sourceDebug = newDebug; - counter.incrementAndGet(); - }); - this.logStrings.add(LoggerUtils.stdOut("Obfuscated " + counter + " source debug attributes.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/RemoveSourceDebug.java b/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/RemoveSourceDebug.java deleted file mode 100644 index 8dacd247..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcedebug/RemoveSourceDebug.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.sourcedebug; - -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; - -/** - * Transformer that obfuscates the source debug attribute by changing the - * corresponding value. - * - * @author ItzSomebody - */ -public class RemoveSourceDebug extends AbstractTransformer { - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started source debug removal transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "SourceDebug") - && classNode.sourceDebug != null).forEach(classNode -> { - classNode.sourceDebug = null; - counter.incrementAndGet(); - }); - this.logStrings.add(LoggerUtils.stdOut("Removed " + counter + " source debug attributes.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java b/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java deleted file mode 100644 index a4161a3c..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcename/ObfuscateSourceName.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.sourcename; - -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.StringUtils; - -/** - * Transformer that obfuscates the source name attribute by changing the - * corresponding value. - * - * @author ItzSomebody - */ -public class ObfuscateSourceName extends AbstractTransformer { - /** - * Length of names to generate. - */ - private int len = 64; - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started source name obfuscation transformer")); - String newName = StringUtils.crazyString(len) + ".java"; - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "SourceName")).forEach(classNode -> { - classNode.sourceFile = newName; - counter.incrementAndGet(); - }); - this.logStrings.add(LoggerUtils.stdOut("Obfuscated " + counter + " source name attributes.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/sourcename/RemoveSourceName.java b/src/main/java/me/itzsomebody/radon/transformers/sourcename/RemoveSourceName.java deleted file mode 100644 index cea1753a..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/sourcename/RemoveSourceName.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.sourcename; - -import java.util.concurrent.atomic.AtomicInteger; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.LoggerUtils; - -/** - * Transformer that obfuscates the source name attribute by removing the - * attribute entirely. - * - * @author ItzSomebody - */ -public class RemoveSourceName extends AbstractTransformer { - /** - * Applies obfuscation to. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started source name removal transformer")); - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "SourceName") - && classNode.sourceFile != null).forEach(classNode -> { - classNode.sourceFile = null; - counter.incrementAndGet(); - }); - this.logStrings.add(LoggerUtils.stdOut("Removed " + counter + " source name attributes.")); - this.logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java deleted file mode 100644 index 12521e3b..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/HeavyStringEncryption.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.stringencryption; - -import java.util.concurrent.atomic.AtomicInteger; - -import me.itzsomebody.radon.generate.StringDecryptorGenerator; -import me.itzsomebody.radon.generate.StringEncryptionGenerator; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.NumberUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; - -public class HeavyStringEncryption extends SuperLightStringEncryption { - /** - * Constructor used to create a {@link HeavyStringEncryption} object. - * - * @param spigotMode indication to not encrypt strings containing Spigot - * placeholders (%%__USER__%%, %%__RESOURCE__%% and - * %%__NONCE__%%). - */ - public HeavyStringEncryption(boolean spigotMode) { - super(spigotMode); - } - - /** - * Applies obfuscation. - */ - @Override - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - MemberNames memberNames = new MemberNames(this); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started heavy string encryption transformer")); - this.classNodes().parallelStream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> - classNode.methods.parallelStream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") - && hasInstructions(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (methodSize(methodNode) > 60000) break; - if (insn instanceof LdcInsnNode) { - LdcInsnNode ldc = (LdcInsnNode) insn; - if (ldc.cst instanceof String) { - String cst = (String) ldc.cst; - if (spigotCheck(cst)) - continue; - int extraKey = NumberUtils.getRandomInt(); - int callerClassHC = classNode.name.replace("/", ".").hashCode(); - int callerMethodHC = methodNode.name.hashCode(); - int decryptorClassHC = memberNames.className.replace("/", ".").hashCode(); - int decryptorMethodHC = memberNames.decryptorMethodName.hashCode(); - ldc.cst = encrypt(cst, callerClassHC, callerMethodHC, decryptorClassHC, decryptorMethodHC, extraKey); - methodNode.instructions.insert(insn, new MethodInsnNode(INVOKESTATIC, memberNames.className, memberNames.decryptorMethodName, "(Ljava/lang/Object;I)Ljava/lang/String;", false)); - methodNode.instructions.insert(insn, new InsnNode(POP)); - methodNode.instructions.insert(insn, new InsnNode(DUP_X1)); - methodNode.instructions.insertBefore(insn, BytecodeUtils.createNumberInsn(extraKey)); - counter.incrementAndGet(); - } - } - } - }) - ); - // Add decrypt method - ClassNode decryptor = StringDecryptorGenerator.heavyStringDecryptor(memberNames); - getClassMap().put(decryptor.name, decryptor); - // Do logging - logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); - logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } - - @Override - protected void addDecryptor(ClassNode decryptor, String methodName) { - decryptor.methods.add(StringEncryptionGenerator.lightMethod(methodName)); - decryptor.access = BytecodeUtils.makePublic(decryptor.access); - } - - @Override - protected void encrypt(MethodNode methodNode, String[] decryptorPath, LdcInsnNode ldc, String cst) { - int key = NumberUtils.getRandomInt(); - ldc.cst = StringUtils.lightEncrypt(cst, - decryptorPath[0].replace("/", "."), - decryptorPath[1], key); - methodNode.instructions.insert(ldc, - new MethodInsnNode(Opcodes.INVOKESTATIC, - decryptorPath[0], decryptorPath[1], - "(Ljava/lang/Object;I)" + - "Ljava/lang/String;", - false)); - methodNode.instructions.insert(ldc, BytecodeUtils.createNumberInsn(key)); - } - - private static String encrypt(String msg, int callerClassHC, int callerMethodHC, int decryptorClassHC, int decryptorMethodHC, int extraKey) { - StringBuilder sb = new StringBuilder(); - char[] chars = msg.toCharArray(); - for (int i = 0; i < chars.length; i++) { - switch (i % 4) { - case 0: { - sb.append((char) (extraKey ^ callerClassHC ^ chars[i])); - break; - } - case 1: { - sb.append((char) (extraKey ^ callerMethodHC ^ chars[i])); - break; - } - case 2: { - sb.append((char) (extraKey ^ decryptorClassHC ^ chars[i])); - break; - } - case 3: { - sb.append((char) (extraKey ^ decryptorMethodHC ^ chars[i])); - break; - } - } - } - - return sb.toString(); - } - - /** - * Names of decryptor class and its members. - */ - public class MemberNames { - public String className; - public String infoFieldName; - public String cacheFieldName; - public String populateMethodName; - public String createInfoMethodName; - public String setCacheMethodName; - public String getCacheMethodName; - public String cacheContainsMethodName; - public String decryptorMethodName; - - MemberNames(HeavyStringEncryption instance) { - this.className = StringUtils.randomClassName(instance.classNames(), instance.dictionary, len); - this.infoFieldName = StringUtils.randomString(instance.dictionary, len); - this.cacheFieldName = StringUtils.randomString(instance.dictionary, len); - this.populateMethodName = StringUtils.randomString(instance.dictionary, len); - this.createInfoMethodName = StringUtils.randomString(instance.dictionary, len); - this.setCacheMethodName = StringUtils.randomString(instance.dictionary, len); - this.getCacheMethodName = StringUtils.randomString(instance.dictionary, len); - this.cacheContainsMethodName = StringUtils.randomString(instance.dictionary, len); - this.decryptorMethodName = StringUtils.randomString(instance.dictionary, len); - } - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java deleted file mode 100644 index 3cf439ca..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/LightStringEncryption.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.stringencryption; - -import me.itzsomebody.radon.generate.StringEncryptionGenerator; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.NumberUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; - -/** - * Transformer that encrypts strings using a stacktrace-backed method. - * - * @author ItzSomebody - */ -public class LightStringEncryption extends SuperLightStringEncryption { - /** - * Constructor used to create a {@link LightStringEncryption} object. - * - * @param spigotMode indication to not encrypt strings containing Spigot - * placeholders(%%__USER__%%, %%__RESOURCE__%% - * and %%__NONCE__%%). - */ - public LightStringEncryption(boolean spigotMode) { - super(spigotMode); - } - - @Override - protected void addDecryptor(ClassNode decryptor, String methodName) { - decryptor.methods.add(StringEncryptionGenerator.lightMethod(methodName)); - decryptor.access = BytecodeUtils.makePublic(decryptor.access); - } - - @Override - protected void encrypt(MethodNode methodNode, String[] decryptorPath, LdcInsnNode ldc, String cst) { - int key = NumberUtils.getRandomInt(); - ldc.cst = StringUtils.lightEncrypt(cst, - decryptorPath[0].replace("/", "."), - decryptorPath[1], key); - methodNode.instructions.insert(ldc, - new MethodInsnNode(Opcodes.INVOKESTATIC, - decryptorPath[0], decryptorPath[1], - "(Ljava/lang/Object;I)" + - "Ljava/lang/String;", - false)); - methodNode.instructions.insert(ldc, BytecodeUtils.createNumberInsn(key)); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java deleted file mode 100644 index d1e133b0..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/NormalStringEncryption.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.stringencryption; - -import me.itzsomebody.radon.generate.StringEncryptionGenerator; -import me.itzsomebody.radon.utils.BytecodeUtils; - -import me.itzsomebody.radon.utils.NumberUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; - -/** - * Transformer that encrypts strings the same way {@link LightStringEncryption} - * does, but with flow obfuscation in the decryption method. - * - * @author ItzSomebody - */ -public class NormalStringEncryption extends SuperLightStringEncryption { - /** - * Constructor used to create a {@link NormalStringEncryption} object. - * - * @param spigotMode indication to not encrypt strings containing Spigot - * placeholders (%%__USER__%%, %%__RESOURCE__%% and - * %%__NONCE__%%). - */ - public NormalStringEncryption(boolean spigotMode) { - super(spigotMode); - } - - @Override - protected void addDecryptor(ClassNode decryptor, String methodName) { - decryptor.methods.add(StringEncryptionGenerator.normalMethod(methodName)); - decryptor.access = BytecodeUtils.makePublic(decryptor.access); - } - - @Override - protected void encrypt(MethodNode methodNode, String[] decryptorPath, LdcInsnNode ldc, String cst) { - int key = NumberUtils.getRandomInt(25000) + 25000; - ldc.cst = StringUtils.normalEncrypt( - decryptorPath[0].replace("/", "."), - decryptorPath[1], key, - cst); - methodNode.instructions.insert(ldc, - new MethodInsnNode(Opcodes.INVOKESTATIC, - decryptorPath[0], decryptorPath[1], - "(Ljava/lang/Object;" + - "Ljava/lang/Object;I)" + - "Ljava/lang/String;", - false)); - methodNode.instructions.insert(ldc, BytecodeUtils.createNumberInsn(key)); - methodNode.instructions.insert(ldc, new InsnNode(ACONST_NULL)); - } -} diff --git a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java b/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java deleted file mode 100644 index 00846ee0..00000000 --- a/src/main/java/me/itzsomebody/radon/transformers/stringencryption/SuperLightStringEncryption.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.transformers.stringencryption; - -import java.util.concurrent.atomic.AtomicInteger; - -import me.itzsomebody.radon.generate.StringEncryptionGenerator; -import me.itzsomebody.radon.transformers.AbstractTransformer; -import me.itzsomebody.radon.utils.BytecodeUtils; -import me.itzsomebody.radon.utils.LoggerUtils; -import me.itzsomebody.radon.utils.NumberUtils; -import me.itzsomebody.radon.utils.StringUtils; -import org.objectweb.asm.tree.*; - -/** - * Transformer that encrypts strings using an extremely simple XOR algorithm. - * - * @author ItzSomebody - */ -public class SuperLightStringEncryption extends AbstractTransformer { - /** - * Length of names to generate. - */ - protected final int len = 64; - /** - * Indication to not encrypt strings containing Spigot placeholders - * (%%__USER__%%, %%__RESOURCE__%% and %%__NONCE__%%). - */ - protected final boolean spigotMode; - /** - * Constructor used to create a {@link LightStringEncryption} object. - * - * @param spigotMode indication to not encrypt strings containing Spigot - * placeholders (%%__USER__%%, %%__RESOURCE__%% - * and %%__NONCE__%%). - */ - public SuperLightStringEncryption(boolean spigotMode) { - this.spigotMode = spigotMode; - } - - /** - * Applies obfuscation. - */ - public void obfuscate() { - AtomicInteger counter = new AtomicInteger(); - long current = System.currentTimeMillis(); - this.logStrings.add(LoggerUtils.stdOut("------------------------------------------------")); - this.logStrings.add(LoggerUtils.stdOut("Started string encryption transformer")); - String[] decryptorPath = new String[]{StringUtils.randomClass(classNames()), StringUtils.randomString(this.dictionary, len)}; - this.classNodes().stream().filter(classNode -> !this.exempted(classNode.name, "StringEncryption")).forEach(classNode -> { - classNode.methods.stream().filter(methodNode -> - !this.exempted(classNode.name + '.' + methodNode.name + methodNode.desc, "StringEncryption") - && hasInstructions(methodNode)).forEach(methodNode -> { - for (AbstractInsnNode insn : methodNode.instructions.toArray()) { - if (methodSize(methodNode) > 60000) break; - if (insn instanceof LdcInsnNode) { - LdcInsnNode ldc = (LdcInsnNode) insn; - if (ldc.cst instanceof String) { - String cst = (String) ldc.cst; - if (spigotCheck(cst)) - continue; - encrypt(methodNode,decryptorPath, ldc, cst); - counter.incrementAndGet(); - } - } - } - }); - }); - // Add decrypt method - ClassNode decryptor = getClassMap().get(decryptorPath[0]); - addDecryptor(decryptor, decryptorPath[1]); - // Do logging - logStrings.add(LoggerUtils.stdOut("Encrypted " + counter + " strings.")); - logStrings.add(LoggerUtils.stdOut("Finished. [" + tookThisLong(current) + "ms]")); - } - - protected boolean spigotCheck(String cst) { - return spigotMode && - (cst).contains("%%__USER__%%") - || (cst).contains("%%__RESOURCE__%%") - || (cst).contains("%%__NONCE__%%"); - } - - protected void addDecryptor(ClassNode decryptor, String methodName) { - decryptor.methods.add(StringEncryptionGenerator.superLightMethod(methodName)); - decryptor.access = BytecodeUtils.makePublic(decryptor.access); - } - - protected void encrypt(MethodNode methodNode, String[] decryptorPath, LdcInsnNode ldc, String cst) { - int key = NumberUtils.getRandomInt(); - ldc.cst = StringUtils.superLightEncrypt(cst, key); - methodNode.instructions.insert(ldc, - new MethodInsnNode( - INVOKESTATIC, - decryptorPath[0], - decryptorPath[1], - "(Ljava/lang/String;I)Ljava/lang/String;", - false)); - methodNode.instructions.insert(ldc, BytecodeUtils.createNumberInsn(key)); - } - - -} diff --git a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java b/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java deleted file mode 100644 index 68f6b3a1..00000000 --- a/src/main/java/me/itzsomebody/radon/utils/BytecodeUtils.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.utils; - -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldNode; -import org.objectweb.asm.tree.InsnList; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.IntInsnNode; -import org.objectweb.asm.tree.JumpInsnNode; -import org.objectweb.asm.tree.LabelNode; -import org.objectweb.asm.tree.LdcInsnNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.MethodNode; -import org.objectweb.asm.tree.TypeInsnNode; - -/** - * Utils used for operating on bytecode. - * - * @author ItzSomebody - */ -public class BytecodeUtils { - /** - * Returns access modifier without private or protected so that class - * renaming works properly. - * - * @param access input access as {@link Integer}. - * @return new {@link Integer} without restrictive flags. - */ - public static int makePublic(int access) { - int a = access; - if ((a & Opcodes.ACC_PRIVATE) != 0) { - a ^= Opcodes.ACC_PRIVATE; - } - if ((a & Opcodes.ACC_PROTECTED) != 0) { - a ^= Opcodes.ACC_PROTECTED; - } - if ((a & Opcodes.ACC_PUBLIC) == 0) { - a |= Opcodes.ACC_PUBLIC; - } - return a; - } - - /** - * Returns an {@link InsnList} with bytecode instructions for expiration. - * - * @param expiryTime a {@link Long} representation of the expiration date. - * @return an {@link InsnList} with bytecode instructions for expiration. - */ - public static InsnList createExpiry(long expiryTime, String expiredMsg) { - InsnList expiryCode = new InsnList(); - LabelNode injectedLabel = new LabelNode(new Label()); - - expiryCode.add(new TypeInsnNode(Opcodes.NEW, "java/util/Date")); - expiryCode.add(new InsnNode(Opcodes.DUP)); - expiryCode.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/util/Date", "", "()V", false)); - expiryCode.add(new TypeInsnNode(Opcodes.NEW, "java/util/Date")); - expiryCode.add(new InsnNode(Opcodes.DUP)); - expiryCode.add(new LdcInsnNode(expiryTime)); - expiryCode.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/util/Date", "", "(J)V", false)); - expiryCode.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/util/Date", "after", "(Ljava/util/Date;)Z", false)); - expiryCode.add(new JumpInsnNode(Opcodes.IFEQ, injectedLabel)); - expiryCode.add(new TypeInsnNode(Opcodes.NEW, "java/lang/Throwable")); - expiryCode.add(new InsnNode(Opcodes.DUP)); - expiryCode.add(new LdcInsnNode(expiredMsg)); - expiryCode.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/Throwable", "", "(Ljava/lang/String;)V", false)); - expiryCode.add(new InsnNode(Opcodes.ATHROW)); - expiryCode.add(injectedLabel); - - return expiryCode; - } - - /** - * Returns a bytecode instruction representing an int. - * - * @param number the {@link Integer} for the obfuscator to contemplate. - * @return a bytecode instruction representing an int. - */ - public static AbstractInsnNode createNumberInsn(int number) { - if (number >= -1 && number <= 5) { - return new InsnNode(number + 3); - } else if (number >= -128 && number <= 127) { - return new IntInsnNode(Opcodes.BIPUSH, number); - } else if (number >= -32768 && number <= 32767) { - return new IntInsnNode(Opcodes.SIPUSH, number); - } else { - return new LdcInsnNode(number); - } - } - - /** - * Returns a bytecode instruction representing a long. - * - * @param number the {@link Long} for the obfuscator to contemplate. - * @return a bytecode instruction representing a long. - */ - public static AbstractInsnNode createNumberInsn(long number) { - if (number >= 0 && number <= 1) { - return new InsnNode((int) (number + 9)); - } else { - return new LdcInsnNode(number); - } - } - - /** - * Returns true if access has synthetic modifier. - * - * @param access method access to check. - * @return true if access has synthetic modifier. - */ - public static boolean isSynthetic(int access) { - return (access & Opcodes.ACC_SYNTHETIC) != 0; - } - - /** - * Returns true if access has bridge modifier. - * - * @param access method access to check. - * @return true if access has bridge modifier. - */ - public static boolean isBridge(int access) { - return (access & Opcodes.ACC_BRIDGE) != 0; - } - - /** - * Returns true if input pushes an integer. - * - * @param insn {@link AbstractInsnNode} to check. - * @return true if input pushes an integer. - */ - public static boolean isIntInsn(AbstractInsnNode insn) { - int opcode = insn.getOpcode(); - return ((opcode >= Opcodes.ICONST_M1 && opcode <= Opcodes.ICONST_5) - || opcode == Opcodes.BIPUSH - || opcode == Opcodes.SIPUSH - || (insn instanceof LdcInsnNode - && ((LdcInsnNode) insn).cst instanceof Integer)); - } - - /** - * Returns true if input pushes a long. - * - * @param insn {@link AbstractInsnNode} to check. - * @return true if input pushes a long. - */ - public static boolean isLongInsn(AbstractInsnNode insn) { - int opcode = insn.getOpcode(); - return (opcode == Opcodes.LCONST_0 - || opcode == Opcodes.LCONST_1 - || (insn instanceof LdcInsnNode - && ((LdcInsnNode) insn).cst instanceof Long)); - } - - /** - * Returns {@link Integer} represented by bytecode instruction and/or - * operand. - * - * @param insn {@link AbstractInsnNode} to check. - * @return {@link Integer} represented by bytecode instruction and/or - * operand. - */ - public static int getIntNumber(AbstractInsnNode insn) { - int opcode = insn.getOpcode(); - if (opcode >= Opcodes.ICONST_M1 && opcode <= Opcodes.ICONST_5) { - return opcode - 3; - } else if (insn instanceof IntInsnNode - && insn.getOpcode() != Opcodes.NEWARRAY) { - return ((IntInsnNode) insn).operand; - } else if (insn instanceof LdcInsnNode - && ((LdcInsnNode) insn).cst instanceof Integer) { - return (Integer) ((LdcInsnNode) insn).cst; - } - throw new IllegalStateException("Unexpected instruction"); - } - - /** - * Returns {@link Long} represented by bytecode instruction and/or - * operand. - * - * @param insn {@link AbstractInsnNode} to check. - * @return {@link Long} represented by bytecode instruction and/or - * operand. - */ - public static long getLongNumber(AbstractInsnNode insn) { - int opcode = insn.getOpcode(); - if (opcode >= Opcodes.LCONST_0 && opcode <= Opcodes.LCONST_1) { - return opcode - 9; - } else if (insn instanceof LdcInsnNode - && ((LdcInsnNode) insn).cst instanceof Long) { - return (Long) ((LdcInsnNode) insn).cst; - } - throw new IllegalStateException("Unexpected instruction"); - } - - /** - * Checks if input methodNode contains goto opcode. - * - * @param methodNode input methodNode. - * @return true if input methodNode contains goto opcode. - */ - public static boolean containsGoto(MethodNode methodNode) { - for (int i = 0; i < methodNode.instructions.size(); i++) { - AbstractInsnNode insn = methodNode.instructions.get(i); - if (insn instanceof JumpInsnNode && insn.getOpcode() == Opcodes.GOTO) { - return true; - } - } - return false; - } - - /** - * Returns true if provided {@link MethodNode} has any annotations. Otherwise, false. - * - * @param methodNode {@link MethodNode} to check. - * @return true if provided {@link MethodNode} has any annotations. Otherwise, false. - */ - public static boolean hasAnnotations(MethodNode methodNode) { - return methodNode.visibleAnnotations != null && !methodNode.visibleAnnotations.isEmpty(); - } - - /** - * Returns true if provided {@link FieldNode} has any annotations. Otherwise, false. - * - * @param fieldNode {@link FieldNode} to check. - * @return true if provided {@link FieldNode} has any annotations. Otherwise, false. - */ - public static boolean hasAnnotations(FieldNode fieldNode) { - return fieldNode.visibleAnnotations != null && !fieldNode.visibleAnnotations.isEmpty(); - } - - /** - * Returns true if provided {@link ClassNode} has any annotations. Otherwise, false. - * - * @param classNode {@link ClassNode} to check. - * @return true if provided {@link ClassNode} has any annotations. Otherwise, false. - */ - public static boolean hasAnnotations(ClassNode classNode) { - return classNode.visibleAnnotations != null && !classNode.visibleAnnotations.isEmpty(); - } -} diff --git a/src/main/java/me/itzsomebody/radon/utils/NumberUtils.java b/src/main/java/me/itzsomebody/radon/utils/NumberUtils.java deleted file mode 100644 index f602b074..00000000 --- a/src/main/java/me/itzsomebody/radon/utils/NumberUtils.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.utils; - -import java.util.concurrent.ThreadLocalRandom; - -/** - * Number utils. - * - * @author ItzSomebody - */ -public class NumberUtils { - /** - * Gets a random {@link Integer} from {@link ThreadLocalRandom#nextInt()}. - * - * @return a random {@link Integer} from - * {@link ThreadLocalRandom#nextInt()}. - */ - public static int getRandomInt() { - return ThreadLocalRandom.current().nextInt(); - } - - /** - * Gets a random {@link Integer} from - * {@link ThreadLocalRandom#nextInt(int)}. - * - * @param bounds {@link Integer} used to define the bounds of the random. - * @return a random {@link Integer} from - * {@link ThreadLocalRandom#nextInt(int)}. - */ - public static int getRandomInt(int bounds) { - return ThreadLocalRandom.current().nextInt(bounds); - } - - /** - * Gets a random {@link Long} from {@link ThreadLocalRandom#nextLong()}. - * - * @return a random {@link Integer} from - * {@link ThreadLocalRandom#nextLong()}. - */ - public static long getRandomLong() { - return ThreadLocalRandom.current().nextLong(); - } - - /** - * Gets a random {@link Long} from - * {@link ThreadLocalRandom#nextLong(long)}. - * - * @param bounds {@link Long} used to define the bounds of the random. - * @return a random {@link Integer} from - * {@link ThreadLocalRandom#nextLong(long)}. - */ - public static long getRandomLong(int bounds) { - return ThreadLocalRandom.current().nextLong(bounds); - } -} diff --git a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java b/src/main/java/me/itzsomebody/radon/utils/StringUtils.java deleted file mode 100644 index cc3f9284..00000000 --- a/src/main/java/me/itzsomebody/radon/utils/StringUtils.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.utils; - -import java.security.MessageDigest; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Base64; -import java.util.Collection; -import java.util.List; -import javax.crypto.Cipher; -import javax.crypto.spec.SecretKeySpec; - -import me.itzsomebody.radon.transformers.stringencryption.LightStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.NormalStringEncryption; -import me.itzsomebody.radon.transformers.stringencryption.SuperLightStringEncryption; - -/** - * Utils for operating, and generating {@link String}s. - * - * @author ItzSomebody - */ -public class StringUtils { - private final static char[] DICT_ALPHA_NUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".toCharArray(); - private final static char[] DICT_SPACES = new char[]{ - '\u2000', '\u2001', '\u2002', '\u2003', '\u2004', '\u2005', '\u2006', '\u2007', '\u2008', '\u2009', '\u200A', '\u200B', '\u200C', '\u200D', '\u200E', '\u200F' - }; - private final static char[] DICT_MISC = new char[]{ - '\ua6ac', '\ua6ea', '\ua6ba', '\ua6a3', '\ua6a4', '\ua6b5', '\ua6b0', '\ua6a8' - }; - - /** - * Returns the proper string generation type given a dictionary type to use. - * - * @param dictionary an integer indicating which pre-defined string - * generation type to use. - * @param len Length of the string to generate. - * @return the proper string generation type given a dictionary type to use. - */ - public static String randomString(int dictionary, int len) { - switch (dictionary) { - case 0: - return crazyString(len); - case 1: - return crazyKey(len); - case 2: - return alphaNumString(len); - default: - throw new IllegalArgumentException("Illegal dictionary type " + dictionary); - } - } - - /** - * Generates and returns a pseudo-random alpha-numeric string. - * - * @param len Length of the string to generate. - * @return a pseudo-random alpha-numeric string. - */ - public static String alphaNumString(int len) { - char[] buildString = new char[len]; - for (int i = 0; i < len; i++) { - buildString[i] = DICT_ALPHA_NUM[NumberUtils.getRandomInt(DICT_ALPHA_NUM.length)]; - } - return new String(buildString); - } - - /** - * Generates a {@link String} consisting only of DICT_SPACES. - * Stole this idea from NeonObf and Smoke. - * - * @param len Length of the string to generate. - * @return a built {@link String} consisting of DICT_SPACES. - */ - public static String crazyString(int len) { - char[] buildString = new char[len]; - for (int i = 0; i < len; i++) { - buildString[i] = DICT_SPACES[NumberUtils.getRandomInt(DICT_SPACES.length)]; - } - return new String(buildString); - } - - /** - * Alternative generator to the method above. - * - * @param len Length of the string to generate. - * @return a {@link String} consisting of characters the JVM doesn't - * recognize. - */ - public static String crazyKey(int len) { - char[] buildString = new char[len]; - for (int i = 0; i < len; i++) { - buildString[i] = DICT_MISC[NumberUtils.getRandomInt(DICT_MISC.length)]; - } - return new String(buildString); - } - - /** - * Returns an encrypted string used by {@link SuperLightStringEncryption}. - * - * @param msg string to encrypt. - * @param key random integer - * @return an encrypted string used by {@link SuperLightStringEncryption}. - */ - public static String superLightEncrypt(String msg, int key) { - char[] encryptedArray = msg.toCharArray(); - char[] returnThis = new char[encryptedArray.length]; - - for (int i = 0; i < returnThis.length; i++) { - returnThis[i] = (char) (encryptedArray[i] ^ key); - } - - return new String(returnThis); - } - - /** - * Returns an encrypted string used by {@link LightStringEncryption}. - * - * @param msg string to encrypt. - * @param className name of the class the msg is in. - * @param methodName name of the method the msg is in. - * @param key3 random integer - * @return an encrypted string used by {@link LightStringEncryption}. - */ - public static String lightEncrypt(String msg, String className, - String methodName, int key3) { - char[] chars = msg.toCharArray(); - char[] returnThis = new char[chars.length]; - for (int i = 0; i < returnThis.length; i++) { - char key2 = (char) methodName.hashCode(); - char key1 = (char) className.hashCode(); - returnThis[i] = (char) (key3 ^ key2 ^ key1 ^ chars[i]); - } - - return new String(returnThis); - } - - /** - * Returns {@link String} encrypted with AES symmetrical encryption - * algorithm to encrypt {@link String}s. - * - * @param msg {@link String} to encrypt. - * @param secret {@link String} to use as a key. - * @return encrypted {@link String} - */ - public static String aesEncrypt(String msg, String secret) { - try { - SecretKeySpec secretKey; - byte[] key = secret.getBytes("UTF-8"); - MessageDigest sha = MessageDigest.getInstance("SHA-1"); - key = sha.digest(key); - key = Arrays.copyOf(key, 16); - secretKey = new SecretKeySpec(key, "AES"); - Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); - cipher.init(Cipher.ENCRYPT_MODE, secretKey); - return Base64.getEncoder().encodeToString(cipher.doFinal(msg. - getBytes("UTF-8"))); - } catch (Throwable t) { - throw new IllegalStateException("Was unable to encrypt string " + - msg + " using " + secret); - } - } - - /** - * Returns {@link String} decrypted AES encrypted {@link String}s. - * - * @param strToDecrypt {@link String} to decrypt. - * @param secret {@link String} to use as a key. - * @return decrypted {@link String} - */ - public static String aesDecrypt(String strToDecrypt, String secret) { - try { - SecretKeySpec secretKey; - byte[] key = secret.getBytes("UTF-8"); - MessageDigest sha = MessageDigest.getInstance("SHA-1"); - key = sha.digest(key); - key = Arrays.copyOf(key, 16); - secretKey = new SecretKeySpec(key, "AES"); - Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING"); - cipher.init(Cipher.DECRYPT_MODE, secretKey); - return new String(cipher.doFinal(Base64.getDecoder() - .decode(strToDecrypt))); - } catch (Throwable t) { - throw new IllegalStateException("Was unable to decrypt string " + - strToDecrypt + " using " + secret); - } - } - - /** - * Returns a generated classname based on current class packages. - * - * @return a generated classname based on current class packages. - */ - public static String randomClassName(Collection theClassNames, int dictionary, int len) { - List classNames = new ArrayList<>(theClassNames); - - String randomClass = classNames.get(NumberUtils. - getRandomInt(classNames.size())); - String[] split = randomClass.split("/"); - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < split.length - 1; i++) { - sb.append(split[i]); - sb.append("/"); - } - - sb.append(StringUtils.randomString(dictionary, len)); - - return new String(sb); - } - - /** - * Returns a generated classname based on current class packages. - * - * @return a generated classname based on current class packages. - */ - public static String randomClass(Collection theClassNames) { - List classNames = new ArrayList<>(theClassNames); - - return classNames.get(NumberUtils.getRandomInt(classNames.size())); - } - - /** - * Returns encrypted {@link String} used by {@link NormalStringEncryption}. - * - * @param className the className to get hashcode from. - * @param methodName the methodName to get hashcode from. - * @param key3 the extra key to ensure a different encryption each - * time. - * @param msg the string to encrypt - * @return encrypted {@link String} used by {@link NormalStringEncryption}. - */ - public static String normalEncrypt(String className, String methodName, - int key3, String msg) { - char[] chars = msg.toCharArray(); - char[] returnThis = new char[chars.length]; - for (int i = 0; i < chars.length; i++) { - returnThis[i] = (char) (key3 ^ methodName.hashCode() ^ - className.hashCode() ^ chars[i]); - } - - return new String(returnThis); - } -} diff --git a/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java b/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java deleted file mode 100644 index be3b4a76..00000000 --- a/src/main/java/me/itzsomebody/radon/utils/WatermarkUtils.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2018 ItzSomebody - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - */ - -package me.itzsomebody.radon.utils; - -import java.io.File; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.tree.ClassNode; - -/** - * Watermarking utils for the obfuscator. - * - * @author ItzSomebody - */ -public class WatermarkUtils { // TODO: Add more secure watermark injection - /** - * Extracts injected watermarks by console and stores them in a - * {@link List} as a {@link String}. - * - * @param jarFile file to extract watermarks from. - * @param key {@link String} to use to decrypt encrypted watemark - * messages. - * @return a {@link List} of all extracted watermarks. - * @throws Throwable should some virtual-disaster should happen. - */ - public static List extractWatermark(File jarFile, String key) - throws Throwable { - List foundIds = new ArrayList<>(); - ZipFile zipFile = new ZipFile(jarFile); - Enumeration entries = zipFile.entries(); - try { - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - if (!entry.isDirectory() && entry.getName().endsWith(".class")) { - try (InputStream in = zipFile.getInputStream(entry)) { - ClassReader cr = new ClassReader(in); - ClassNode classNode = new ClassNode(); - cr.accept(classNode, ClassReader.SKIP_FRAMES - | ClassReader.SKIP_DEBUG); - char[] buf = new char[cr.getMaxStringLength()]; - - try { - for (int i = 0; i < cr.getItemCount(); i++) { - int getItem = cr.getItem(i); - String UTF = cr.readUTF8(getItem, buf); - if (UTF != null && UTF.startsWith("WMID: ")) { - if (UTF.length() > 6) { - String getId = StringUtils.aesDecrypt(UTF.substring(6, UTF.length()), key); - foundIds.add("Watermarked ID in constant pool of " + entry.getName() + " -> " + getId); - } - } - } - } catch (Throwable t) { - // ignored; - } - - - if (classNode.signature != null) { - try { - String decrypted = StringUtils.aesDecrypt(classNode.signature, key); - if (decrypted.startsWith("WMID: ")) { - foundIds.add("Watermarked ID in class signature of " + entry.getName() + " -> " + decrypted); - } - } catch (Throwable t) { - // ignored - } - } - } - } - } - } finally { - zipFile.close(); - } - return foundIds; - } -} diff --git a/src/main/java/org/objectweb/asm/AnnotationVisitor.java b/src/main/java/org/objectweb/asm/AnnotationVisitor.java deleted file mode 100644 index a4b2dff0..00000000 --- a/src/main/java/org/objectweb/asm/AnnotationVisitor.java +++ /dev/null @@ -1,149 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A visitor to visit a Java annotation. The methods of this class must be called in the following - * order: ( visit | visitEnum | visitAnnotation | visitArray )* - * visitEnd. - * - * @author Eric Bruneton - * @author Eugene Kuleshov - */ -public abstract class AnnotationVisitor { - - /** - * The ASM API version implemented by this visitor. The value of this field must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - protected final int api; - - /** - * The annotation visitor to which this visitor must delegate method calls. May be null. - */ - protected AnnotationVisitor av; - - /** - * Constructs a new {@link AnnotationVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - public AnnotationVisitor(final int api) { - this(api, null); - } - - /** - * Constructs a new {@link AnnotationVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param annotationVisitor the annotation visitor to which this visitor must delegate method - * calls. May be null. - */ - public AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) { - if (api < Opcodes.ASM4 || api > Opcodes.ASM6) { - throw new IllegalArgumentException(); - } - this.api = api; - this.av = annotationVisitor; - } - - /** - * Visits a primitive value of the annotation. - * - * @param name the value name. - * @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link - * Character}, {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double}, - * {@link String} or {@link Type} of {@link Type#OBJECT} or {@link Type#ARRAY} sort. This - * value can also be an array of byte, boolean, short, char, int, long, float or double values - * (this is equivalent to using {@link #visitArray} and visiting each array element in turn, - * but is more convenient). - */ - public void visit(final String name, final Object value) { - if (av != null) { - av.visit(name, value); - } - } - - /** - * Visits an enumeration value of the annotation. - * - * @param name the value name. - * @param descriptor the class descriptor of the enumeration class. - * @param value the actual enumeration value. - */ - public void visitEnum(final String name, final String descriptor, final String value) { - if (av != null) { - av.visitEnum(name, descriptor, value); - } - } - - /** - * Visits a nested annotation value of the annotation. - * - * @param name the value name. - * @param descriptor the class descriptor of the nested annotation class. - * @return a visitor to visit the actual nested annotation value, or null if this visitor - * is not interested in visiting this nested annotation. The nested annotation value must - * be fully visited before calling other methods on this annotation visitor. - */ - public AnnotationVisitor visitAnnotation(final String name, final String descriptor) { - if (av != null) { - return av.visitAnnotation(name, descriptor); - } - return null; - } - - /** - * Visits an array value of the annotation. Note that arrays of primitive types (such as byte, - * boolean, short, char, int, long, float or double) can be passed as value to {@link #visit - * visit}. This is what {@link ClassReader} does. - * - * @param name the value name. - * @return a visitor to visit the actual array value elements, or null if this visitor is - * not interested in visiting these values. The 'name' parameters passed to the methods of - * this visitor are ignored. All the array values must be visited before calling other - * methods on this annotation visitor. - */ - public AnnotationVisitor visitArray(final String name) { - if (av != null) { - return av.visitArray(name); - } - return null; - } - - /** - * Visits the end of the annotation. - */ - public void visitEnd() { - if (av != null) { - av.visitEnd(); - } - } -} diff --git a/src/main/java/org/objectweb/asm/AnnotationWriter.java b/src/main/java/org/objectweb/asm/AnnotationWriter.java deleted file mode 100644 index 130d359b..00000000 --- a/src/main/java/org/objectweb/asm/AnnotationWriter.java +++ /dev/null @@ -1,422 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * An {@link AnnotationVisitor} that generates a corresponding 'annotation' or 'type_annotation' - * structure, as defined in the Java Virtual Machine Specification (JVMS). AnnotationWriter - * instances can be chained in a doubly linked list, from which Runtime[In]Visible[Type]Annotations - * attributes can be generated with the {@link #putAnnotations} method. Similarly, arrays of such - * lists can be used to generate Runtime[In]VisibleParameterAnnotations attributes. - * - * @author Eric Bruneton - * @author Eugene Kuleshov - * @see JVMS - * 4.7.16 - * @see JVMS - * 4.7.20 - */ -final class AnnotationWriter extends AnnotationVisitor { - - /** - * Where the constants used in this AnnotationWriter must be stored. - */ - private final SymbolTable symbolTable; - - /** - * Whether values are named or not. AnnotationWriter instances used for annotation default and - * annotation arrays use unnamed values (i.e. they generate an 'element_value' structure for each - * value, instead of an element_name_index followed by an element_value). - */ - private final boolean useNamedValues; - - /** - * The 'annotation' or 'type_annotation' JVMS structure corresponding to the annotation values - * visited so far. All the fields of these structures, except the last one - the - * element_value_pairs array, must be set before this ByteVector is passed to the constructor - * (num_element_value_pairs can be set to 0, it is reset to the correct value in {@link - * #visitEnd()}). The element_value_pairs array is filled incrementally in the various visit() - * methods. - * - *

Note: as an exception to the above rules, for AnnotationDefault attributes (which contain a - * single element_value by definition), this ByteVector is initially empty when passed to the - * constructor, and {@link #numElementValuePairsOffset} is set to -1. - */ - private final ByteVector annotation; - - /** - * The offset in {@link #annotation} where {@link #numElementValuePairs} must be stored (or -1 for - * the case of AnnotationDefault attributes). - */ - private final int numElementValuePairsOffset; - - /** - * The number of element value pairs visited so far. - */ - private int numElementValuePairs; - - /** - * The previous AnnotationWriter. This field is used to store the list of annotations of a - * Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations - * (annotation values of annotation type), or for AnnotationDefault attributes. - */ - private final AnnotationWriter previousAnnotation; - - /** - * The next AnnotationWriter. This field is used to store the list of annotations of a - * Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations - * (annotation values of annotation type), or for AnnotationDefault attributes. - */ - private AnnotationWriter nextAnnotation; - - // ----------------------------------------------------------------------------------------------- - // Constructors - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a new {@link AnnotationWriter}. - * - * @param symbolTable where the constants used in this AnnotationWriter must be stored. - * @param useNamedValues whether values are named or not. AnnotationDefault and annotation arrays - * use unnamed values. - * @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to - * the visited content must be stored. This ByteVector must already contain all the fields of - * the structure except the last one (the element_value_pairs array). - * @param previousAnnotation the previously visited annotation of the - * Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in - * other cases (e.g. nested or array annotations). - */ - AnnotationWriter( - final SymbolTable symbolTable, - final boolean useNamedValues, - final ByteVector annotation, - final AnnotationWriter previousAnnotation) { - super(Opcodes.ASM6); - this.symbolTable = symbolTable; - this.useNamedValues = useNamedValues; - this.annotation = annotation; - // By hypothesis, num_element_value_pairs is stored in the last unsigned short of 'annotation'. - this.numElementValuePairsOffset = annotation.length == 0 ? -1 : annotation.length - 2; - this.previousAnnotation = previousAnnotation; - if (previousAnnotation != null) { - previousAnnotation.nextAnnotation = this; - } - } - - /** - * Constructs a new {@link AnnotationWriter} using named values. - * - * @param symbolTable where the constants used in this AnnotationWriter must be stored. - * @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to - * the visited content must be stored. This ByteVector must already contain all the fields of - * the structure except the last one (the element_value_pairs array). - * @param previousAnnotation the previously visited annotation of the - * Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in - * other cases (e.g. nested or array annotations). - */ - AnnotationWriter( - final SymbolTable symbolTable, - final ByteVector annotation, - final AnnotationWriter previousAnnotation) { - this(symbolTable, /* useNamedValues = */ true, annotation, previousAnnotation); - } - - // ----------------------------------------------------------------------------------------------- - // Implementation of the AnnotationVisitor abstract class - // ----------------------------------------------------------------------------------------------- - - @Override - public void visit(final String name, final Object value) { - // Case of an element_value with a const_value_index, class_info_index or array_index field. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1. - ++numElementValuePairs; - if (useNamedValues) { - annotation.putShort(symbolTable.addConstantUtf8(name)); - } - if (value instanceof String) { - annotation.put12('s', symbolTable.addConstantUtf8((String) value)); - } else if (value instanceof Byte) { - annotation.put12('B', symbolTable.addConstantInteger(((Byte) value).byteValue()).index); - } else if (value instanceof Boolean) { - int booleanValue = ((Boolean) value).booleanValue() ? 1 : 0; - annotation.put12('Z', symbolTable.addConstantInteger(booleanValue).index); - } else if (value instanceof Character) { - annotation.put12('C', symbolTable.addConstantInteger(((Character) value).charValue()).index); - } else if (value instanceof Short) { - annotation.put12('S', symbolTable.addConstantInteger(((Short) value).shortValue()).index); - } else if (value instanceof Type) { - annotation.put12('c', symbolTable.addConstantUtf8(((Type) value).getDescriptor())); - } else if (value instanceof byte[]) { - byte[] byteArray = (byte[]) value; - annotation.put12('[', byteArray.length); - for (byte byteValue : byteArray) { - annotation.put12('B', symbolTable.addConstantInteger(byteValue).index); - } - } else if (value instanceof boolean[]) { - boolean[] booleanArray = (boolean[]) value; - annotation.put12('[', booleanArray.length); - for (boolean booleanValue : booleanArray) { - annotation.put12('Z', symbolTable.addConstantInteger(booleanValue ? 1 : 0).index); - } - } else if (value instanceof short[]) { - short[] shortArray = (short[]) value; - annotation.put12('[', shortArray.length); - for (short shortValue : shortArray) { - annotation.put12('S', symbolTable.addConstantInteger(shortValue).index); - } - } else if (value instanceof char[]) { - char[] charArray = (char[]) value; - annotation.put12('[', charArray.length); - for (char charValue : charArray) { - annotation.put12('C', symbolTable.addConstantInteger(charValue).index); - } - } else if (value instanceof int[]) { - int[] intArray = (int[]) value; - annotation.put12('[', intArray.length); - for (int intValue : intArray) { - annotation.put12('I', symbolTable.addConstantInteger(intValue).index); - } - } else if (value instanceof long[]) { - long[] longArray = (long[]) value; - annotation.put12('[', longArray.length); - for (long longValue : longArray) { - annotation.put12('J', symbolTable.addConstantLong(longValue).index); - } - } else if (value instanceof float[]) { - float[] floatArray = (float[]) value; - annotation.put12('[', floatArray.length); - for (float floatValue : floatArray) { - annotation.put12('F', symbolTable.addConstantFloat(floatValue).index); - } - } else if (value instanceof double[]) { - double[] doubleArray = (double[]) value; - annotation.put12('[', doubleArray.length); - for (double doubleValue : doubleArray) { - annotation.put12('D', symbolTable.addConstantDouble(doubleValue).index); - } - } else { - Symbol symbol = symbolTable.addConstant(value); - annotation.put12(".s.IFJDCS".charAt(symbol.tag), symbol.index); - } - } - - @Override - public void visitEnum(final String name, final String descriptor, final String value) { - // Case of an element_value with an enum_const_value field. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1. - ++numElementValuePairs; - if (useNamedValues) { - annotation.putShort(symbolTable.addConstantUtf8(name)); - } - annotation - .put12('e', symbolTable.addConstantUtf8(descriptor)) - .putShort(symbolTable.addConstantUtf8(value)); - } - - @Override - public AnnotationVisitor visitAnnotation(final String name, final String descriptor) { - // Case of an element_value with an annotation_value field. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1. - ++numElementValuePairs; - if (useNamedValues) { - annotation.putShort(symbolTable.addConstantUtf8(name)); - } - // Write tag and type_index, and reserve 2 bytes for num_element_value_pairs. - annotation.put12('@', symbolTable.addConstantUtf8(descriptor)).putShort(0); - return new AnnotationWriter(symbolTable, annotation, null); - } - - @Override - public AnnotationVisitor visitArray(final String name) { - // Case of an element_value with an array_value field. - // https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1 - ++numElementValuePairs; - if (useNamedValues) { - annotation.putShort(symbolTable.addConstantUtf8(name)); - } - // Write tag, and reserve 2 bytes for num_values. Here we take advantage of the fact that the - // end of an element_value of array type is similar to the end of an 'annotation' structure: an - // unsigned short num_values followed by num_values element_value, versus an unsigned short - // num_element_value_pairs, followed by num_element_value_pairs { element_name_index, - // element_value } tuples. This allows us to use an AnnotationWriter with unnamed values to - // visit the array elements. Its num_element_value_pairs will correspond to the number of array - // elements and will be stored in what is in fact num_values. - annotation.put12('[', 0); - return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, annotation, null); - } - - @Override - public void visitEnd() { - if (numElementValuePairsOffset != -1) { - byte[] data = annotation.data; - data[numElementValuePairsOffset] = (byte) (numElementValuePairs >>> 8); - data[numElementValuePairsOffset + 1] = (byte) numElementValuePairs; - } - } - - // ----------------------------------------------------------------------------------------------- - // Utility methods - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the size of a Runtime[In]Visible[Type]Annotations attribute containing this annotation - * and all its predecessors (see {@link #previousAnnotation}. Also adds the attribute name - * to the constant pool of the class (if not null). - * - * @param attributeName one of "Runtime[In]Visible[Type]Annotations", or null. - * @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing this - * annotation and all its predecessors. This includes the size of the attribute_name_index and - * attribute_length fields. - */ - int computeAnnotationsSize(final String attributeName) { - if (attributeName != null) { - symbolTable.addConstantUtf8(attributeName); - } - // The attribute_name_index, attribute_length and num_annotations fields use 8 bytes. - int attributeSize = 8; - AnnotationWriter annotationWriter = this; - while (annotationWriter != null) { - attributeSize += annotationWriter.annotation.length; - annotationWriter = annotationWriter.previousAnnotation; - } - return attributeSize; - } - - /** - * Puts a Runtime[In]Visible[Type]Annotations attribute containing this annotations and all its - * predecessors (see {@link #previousAnnotation} in the given ByteVector. Annotations are - * put in the same order they have been visited. - * - * @param attributeNameIndex the constant pool index of the attribute name (one of - * "Runtime[In]Visible[Type]Annotations"). - * @param output where the attribute must be put. - */ - void putAnnotations(final int attributeNameIndex, final ByteVector output) { - int attributeLength = 2; // For num_annotations. - int numAnnotations = 0; - AnnotationWriter annotationWriter = this; - AnnotationWriter firstAnnotation = null; - while (annotationWriter != null) { - // In case the user forgot to call visitEnd(). - annotationWriter.visitEnd(); - attributeLength += annotationWriter.annotation.length; - numAnnotations++; - firstAnnotation = annotationWriter; - annotationWriter = annotationWriter.previousAnnotation; - } - output.putShort(attributeNameIndex); - output.putInt(attributeLength); - output.putShort(numAnnotations); - annotationWriter = firstAnnotation; - while (annotationWriter != null) { - output.putByteArray(annotationWriter.annotation.data, 0, annotationWriter.annotation.length); - annotationWriter = annotationWriter.nextAnnotation; - } - } - - /** - * Returns the size of a Runtime[In]VisibleParameterAnnotations attribute containing all the - * annotation lists from the given AnnotationWriter sub-array. Also adds the attribute name to the - * constant pool of the class. - * - * @param attributeName one of "Runtime[In]VisibleParameterAnnotations". - * @param annotationWriters an array of AnnotationWriter lists (designated by their last - * element). - * @param annotableParameterCount the number of elements in annotationWriters to take into account - * (elements [0..annotableParameterCount[ are taken into account). - * @return the size in bytes of a Runtime[In]VisibleParameterAnnotations attribute corresponding - * to the given sub-array of AnnotationWriter lists. This includes the size of the - * attribute_name_index and attribute_length fields. - */ - static int computeParameterAnnotationsSize( - final String attributeName, - final AnnotationWriter[] annotationWriters, - final int annotableParameterCount) { - // Note: attributeName is added to the constant pool by the call to computeAnnotationsSize - // below. This assumes that there is at least one non-null element in the annotationWriters - // sub-array (which is ensured by the lazy instantiation of this array in MethodWriter). - // The attribute_name_index, attribute_length and num_parameters fields use 7 bytes, and each - // element of the parameter_annotations array uses 2 bytes for its num_annotations field. - int attributeSize = 7 + 2 * annotableParameterCount; - for (int i = 0; i < annotableParameterCount; ++i) { - AnnotationWriter annotationWriter = annotationWriters[i]; - attributeSize += - annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(attributeName) - 8; - } - return attributeSize; - } - - /** - * Puts a Runtime[In]VisibleParameterAnnotations attribute containing all the annotation lists - * from the given AnnotationWriter sub-array in the given ByteVector. - * - * @param attributeNameIndex constant pool index of the attribute name (one of - * Runtime[In]VisibleParameterAnnotations). - * @param annotationWriters an array of AnnotationWriter lists (designated by their last - * element). - * @param annotableParameterCount the number of elements in annotationWriters to put (elements - * [0..annotableParameterCount[ are put). - * @param output where the attribute must be put. - */ - static void putParameterAnnotations( - final int attributeNameIndex, - final AnnotationWriter[] annotationWriters, - final int annotableParameterCount, - final ByteVector output) { - // The num_parameters field uses 1 byte, and each element of the parameter_annotations array - // uses 2 bytes for its num_annotations field. - int attributeLength = 1 + 2 * annotableParameterCount; - for (int i = 0; i < annotableParameterCount; ++i) { - AnnotationWriter annotationWriter = annotationWriters[i]; - attributeLength += - annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(null) - 8; - } - output.putShort(attributeNameIndex); - output.putInt(attributeLength); - output.putByte(annotableParameterCount); - for (int i = 0; i < annotableParameterCount; ++i) { - AnnotationWriter annotationWriter = annotationWriters[i]; - AnnotationWriter firstAnnotation = null; - int numAnnotations = 0; - while (annotationWriter != null) { - // In case user the forgot to call visitEnd(). - annotationWriter.visitEnd(); - numAnnotations++; - firstAnnotation = annotationWriter; - annotationWriter = annotationWriter.previousAnnotation; - } - output.putShort(numAnnotations); - annotationWriter = firstAnnotation; - while (annotationWriter != null) { - output.putByteArray( - annotationWriter.annotation.data, 0, annotationWriter.annotation.length); - annotationWriter = annotationWriter.nextAnnotation; - } - } - } -} diff --git a/src/main/java/org/objectweb/asm/Attribute.java b/src/main/java/org/objectweb/asm/Attribute.java deleted file mode 100644 index c9732f5f..00000000 --- a/src/main/java/org/objectweb/asm/Attribute.java +++ /dev/null @@ -1,327 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A non standard class, field, method or code attribute, as defined in the Java Virtual Machine - * Specification (JVMS). - * - * @author Eric Bruneton - * @author Eugene Kuleshov - * @see JVMS - * 4.7 - * @see JVMS - * 4.7.3 - */ -public class Attribute { - - /** - * The type of this attribute, also called its name in the JVMS. - */ - public final String type; - - /** - * The raw content of this attribute, only used for unknown attributes (see {@link #isUnknown()}). - * The 6 header bytes of the attribute (attribute_name_index and attribute_length) are not - * included. - */ - private byte[] content; - - /** - * The next attribute in this attribute list (Attribute instances can be linked via this field to - * store a list of class, field, method or code attributes). May be null. - */ - Attribute nextAttribute; - - /** - * Constructs a new empty attribute. - * - * @param type the type of the attribute. - */ - protected Attribute(final String type) { - this.type = type; - } - - /** - * Returns true if this type of attribute is unknown. This means that the attribute - * content can't be parsed to extract constant pool references, labels, etc. Instead, the - * attribute content is read as an opaque byte array, and written back as is. This can lead to - * invalid attributes, if the content actually contains constant pool references, labels, or other - * symbolic references that need to be updated when there are changes to the constant pool, the - * method bytecode, etc. The default implementation of this method always returns true. - * - * @return true if this type of attribute is unknown. - */ - public boolean isUnknown() { - return true; - } - - /** - * Returns true if this type of attribute is a code attribute. - * - * @return true if this type of attribute is a code attribute. - */ - public boolean isCodeAttribute() { - return false; - } - - /** - * Returns the labels corresponding to this attribute. - * - * @return the labels corresponding to this attribute, or null if this attribute is not a - * code attribute that contains labels. - */ - protected Label[] getLabels() { - return new Label[0]; - } - - /** - * Reads a {@link #type} attribute. This method must return a new {@link Attribute} object, - * of type {@link #type}, corresponding to the 'length' bytes starting at 'offset', in the given - * ClassReader. - * - * @param classReader the class that contains the attribute to be read. - * @param offset index of the first byte of the attribute's content in {@link ClassReader#b}. The - * 6 attribute header bytes (attribute_name_index and attribute_length) are not taken into - * account here. - * @param length the length of the attribute's content (excluding the 6 attribute header bytes). - * @param charBuffer the buffer to be used to call the ClassReader methods requiring a - * 'charBuffer' parameter. - * @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute - * in {@link ClassReader#b}, or -1 if the attribute to be read is not a code attribute. The 6 - * attribute header bytes (attribute_name_index and attribute_length) are not taken into - * account here. - * @param labels the labels of the method's code, or null if the attribute to be read is - * not a code attribute. - * @return a new {@link Attribute} object corresponding to the specified bytes. - */ - protected Attribute read( - final ClassReader classReader, - final int offset, - final int length, - final char[] charBuffer, - final int codeAttributeOffset, - final Label[] labels) { - Attribute attribute = new Attribute(type); - attribute.content = new byte[length]; - System.arraycopy(classReader.b, offset, attribute.content, 0, length); - return attribute; - } - - /** - * Returns the byte array form of the content of this attribute. The 6 header bytes - * (attribute_name_index and attribute_length) must not be added in the returned - * ByteVector. - * - * @param classWriter the class to which this attribute must be added. This parameter can be used - * to add the items that corresponds to this attribute to the constant pool of this class. - * @param code the bytecode of the method corresponding to this code attribute, or null - * if this attribute is not a code attribute. Corresponds to the 'code' field of the Code - * attribute. - * @param codeLength the length of the bytecode of the method corresponding to this code - * attribute, or 0 if this attribute is not a code attribute. Corresponds to the 'code_length' - * field of the Code attribute. - * @param maxStack the maximum stack size of the method corresponding to this code attribute, or - * -1 if this attribute is not a code attribute. - * @param maxLocals the maximum number of local variables of the method corresponding to this code - * attribute, or -1 if this attribute is not a code attribute. - * @return the byte array form of this attribute. - */ - protected ByteVector write( - final ClassWriter classWriter, - final byte[] code, - final int codeLength, - final int maxStack, - final int maxLocals) { - return new ByteVector(content); - } - - /** - * Returns the number of attributes of the attribute list that begins with this attribute. - * - * @return the number of attributes of the attribute list that begins with this attribute. - */ - final int getAttributeCount() { - int count = 0; - Attribute attribute = this; - while (attribute != null) { - count += 1; - attribute = attribute.nextAttribute; - } - return count; - } - - /** - * Returns the total size in bytes of all the attributes in the attribute list that begins with - * this attribute. This size includes the 6 header bytes (attribute_name_index and - * attribute_length) per attribute. Also adds the attribute type names to the constant pool. - * - * @param symbolTable where the constants used in the attributes must be stored. - * @return the size of all the attributes in this attribute list. This size includes the size of - * the attribute headers. - */ - final int computeAttributesSize(final SymbolTable symbolTable) { - final byte[] code = null; - final int codeLength = 0; - final int maxStack = -1; - final int maxLocals = -1; - return computeAttributesSize(symbolTable, code, codeLength, maxStack, maxLocals); - } - - /** - * Returns the total size in bytes of all the attributes in the attribute list that begins with - * this attribute. This size includes the 6 header bytes (attribute_name_index and - * attribute_length) per attribute. Also adds the attribute type names to the constant pool. - * - * @param symbolTable where the constants used in the attributes must be stored. - * @param code the bytecode of the method corresponding to these code attributes, or null - * if they are not code attributes. Corresponds to the 'code' field of the Code attribute. - * @param codeLength the length of the bytecode of the method corresponding to these code - * attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of - * the Code attribute. - * @param maxStack the maximum stack size of the method corresponding to these code attributes, or - * -1 if they are not code attributes. - * @param maxLocals the maximum number of local variables of the method corresponding to these - * code attributes, or -1 if they are not code attribute. - * @return the size of all the attributes in this attribute list. This size includes the size of - * the attribute headers. - */ - final int computeAttributesSize( - final SymbolTable symbolTable, - final byte[] code, - final int codeLength, - final int maxStack, - final int maxLocals) { - final ClassWriter classWriter = symbolTable.classWriter; - int size = 0; - Attribute attribute = this; - while (attribute != null) { - symbolTable.addConstantUtf8(attribute.type); - size += 6 + attribute.write(classWriter, code, codeLength, maxStack, maxLocals).length; - attribute = attribute.nextAttribute; - } - return size; - } - - /** - * Puts all the attributes of the attribute list that begins with this attribute, in the given - * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per - * attribute. - * - * @param symbolTable where the constants used in the attributes must be stored. - * @param output where the attributes must be written. - */ - final void putAttributes(final SymbolTable symbolTable, final ByteVector output) { - final byte[] code = null; - final int codeLength = 0; - final int maxStack = -1; - final int maxLocals = -1; - putAttributes(symbolTable, code, codeLength, maxStack, maxLocals, output); - } - - /** - * Puts all the attributes of the attribute list that begins with this attribute, in the given - * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per - * attribute. - * - * @param symbolTable where the constants used in the attributes must be stored. - * @param code the bytecode of the method corresponding to these code attributes, or null - * if they are not code attributes. Corresponds to the 'code' field of the Code attribute. - * @param codeLength the length of the bytecode of the method corresponding to these code - * attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of - * the Code attribute. - * @param maxStack the maximum stack size of the method corresponding to these code attributes, or - * -1 if they are not code attributes. - * @param maxLocals the maximum number of local variables of the method corresponding to these - * code attributes, or -1 if they are not code attribute. - * @param output where the attributes must be written. - */ - final void putAttributes( - final SymbolTable symbolTable, - final byte[] code, - final int codeLength, - final int maxStack, - final int maxLocals, - final ByteVector output) { - final ClassWriter classWriter = symbolTable.classWriter; - Attribute attribute = this; - while (attribute != null) { - ByteVector attributeContent = - attribute.write(classWriter, code, codeLength, maxStack, maxLocals); - // Put attribute_name_index and attribute_length. - output.putShort(symbolTable.addConstantUtf8(attribute.type)).putInt(attributeContent.length); - output.putByteArray(attributeContent.data, 0, attributeContent.length); - attribute = attribute.nextAttribute; - } - } - - /** - * A set of attribute prototypes (attributes with the same type are considered equal). - */ - static final class Set { - - private static final int SIZE_INCREMENT = 6; - - private int size; - private Attribute[] data = new Attribute[SIZE_INCREMENT]; - - void addAttributes(final Attribute attributeList) { - Attribute attribute = attributeList; - while (attribute != null) { - if (!contains(attribute)) { - add(attribute); - } - attribute = attribute.nextAttribute; - } - } - - Attribute[] toArray() { - Attribute[] result = new Attribute[size]; - System.arraycopy(data, 0, result, 0, size); - return result; - } - - private boolean contains(final Attribute attribute) { - for (int i = 0; i < size; ++i) { - if (data[i].type.equals(attribute.type)) { - return true; - } - } - return false; - } - - private void add(final Attribute attribute) { - if (size >= data.length) { - Attribute[] newData = new Attribute[data.length + SIZE_INCREMENT]; - System.arraycopy(data, 0, newData, 0, size); - data = newData; - } - data[size++] = attribute; - } - } -} diff --git a/src/main/java/org/objectweb/asm/ByteVector.java b/src/main/java/org/objectweb/asm/ByteVector.java deleted file mode 100644 index fd3ec214..00000000 --- a/src/main/java/org/objectweb/asm/ByteVector.java +++ /dev/null @@ -1,366 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream - * on top of a ByteArrayOutputStream, but is more efficient. - * - * @author Eric Bruneton - */ -public class ByteVector { - - /** - * The content of this vector. Only the first {@link #length} bytes contain real data. - */ - byte[] data; - - /** - * The actual number of bytes in this vector. - */ - int length; - - /** - * Constructs a new {@link ByteVector} with a default initial capacity. - */ - public ByteVector() { - data = new byte[64]; - } - - /** - * Constructs a new {@link ByteVector} with the given initial capacity. - * - * @param initialCapacity the initial capacity of the byte vector to be constructed. - */ - public ByteVector(final int initialCapacity) { - data = new byte[initialCapacity]; - } - - /** - * Constructs a new {@link ByteVector} from the given initial data. - * - * @param data the initial data of the new byte vector. - */ - ByteVector(final byte[] data) { - this.data = data; - this.length = data.length; - } - - /** - * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param byteValue a byte. - * @return this byte vector. - */ - public ByteVector putByte(final int byteValue) { - int currentLength = length; - if (currentLength + 1 > data.length) { - enlarge(1); - } - data[currentLength++] = (byte) byteValue; - length = currentLength; - return this; - } - - /** - * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param byteValue1 a byte. - * @param byteValue2 another byte. - * @return this byte vector. - */ - final ByteVector put11(final int byteValue1, final int byteValue2) { - int currentLength = length; - if (currentLength + 2 > data.length) { - enlarge(2); - } - byte[] currentData = data; - currentData[currentLength++] = (byte) byteValue1; - currentData[currentLength++] = (byte) byteValue2; - length = currentLength; - return this; - } - - /** - * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param shortValue a short. - * @return this byte vector. - */ - public ByteVector putShort(final int shortValue) { - int currentLength = length; - if (currentLength + 2 > data.length) { - enlarge(2); - } - byte[] currentData = data; - currentData[currentLength++] = (byte) (shortValue >>> 8); - currentData[currentLength++] = (byte) shortValue; - length = currentLength; - return this; - } - - /** - * Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if - * necessary. - * - * @param byteValue a byte. - * @param shortValue a short. - * @return this byte vector. - */ - final ByteVector put12(final int byteValue, final int shortValue) { - int currentLength = length; - if (currentLength + 3 > data.length) { - enlarge(3); - } - byte[] currentData = data; - currentData[currentLength++] = (byte) byteValue; - currentData[currentLength++] = (byte) (shortValue >>> 8); - currentData[currentLength++] = (byte) shortValue; - length = currentLength; - return this; - } - - /** - * Puts two bytes and a short into this byte vector. The byte vector is automatically enlarged if - * necessary. - * - * @param byteValue1 a byte. - * @param byteValue2 another byte. - * @param shortValue a short. - * @return this byte vector. - */ - final ByteVector put112(final int byteValue1, final int byteValue2, final int shortValue) { - int currentLength = length; - if (currentLength + 4 > data.length) { - enlarge(4); - } - byte[] currentData = data; - currentData[currentLength++] = (byte) byteValue1; - currentData[currentLength++] = (byte) byteValue2; - currentData[currentLength++] = (byte) (shortValue >>> 8); - currentData[currentLength++] = (byte) shortValue; - length = currentLength; - return this; - } - - /** - * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param intValue an int. - * @return this byte vector. - */ - public ByteVector putInt(final int intValue) { - int currentLength = length; - if (currentLength + 4 > data.length) { - enlarge(4); - } - byte[] currentData = data; - currentData[currentLength++] = (byte) (intValue >>> 24); - currentData[currentLength++] = (byte) (intValue >>> 16); - currentData[currentLength++] = (byte) (intValue >>> 8); - currentData[currentLength++] = (byte) intValue; - length = currentLength; - return this; - } - - /** - * Puts one byte and two shorts into this byte vector. The byte vector is automatically enlarged - * if necessary. - * - * @param byteValue a byte. - * @param shortValue1 a short. - * @param shortValue2 another short. - * @return this byte vector. - */ - final ByteVector put122(final int byteValue, final int shortValue1, final int shortValue2) { - int currentLength = length; - if (currentLength + 5 > data.length) { - enlarge(5); - } - byte[] currentData = data; - currentData[currentLength++] = (byte) byteValue; - currentData[currentLength++] = (byte) (shortValue1 >>> 8); - currentData[currentLength++] = (byte) shortValue1; - currentData[currentLength++] = (byte) (shortValue2 >>> 8); - currentData[currentLength++] = (byte) shortValue2; - length = currentLength; - return this; - } - - /** - * Puts a long into this byte vector. The byte vector is automatically enlarged if necessary. - * - * @param longValue a long. - * @return this byte vector. - */ - public ByteVector putLong(final long longValue) { - int currentLength = length; - if (currentLength + 8 > data.length) { - enlarge(8); - } - byte[] currentData = data; - int intValue = (int) (longValue >>> 32); - currentData[currentLength++] = (byte) (intValue >>> 24); - currentData[currentLength++] = (byte) (intValue >>> 16); - currentData[currentLength++] = (byte) (intValue >>> 8); - currentData[currentLength++] = (byte) intValue; - intValue = (int) longValue; - currentData[currentLength++] = (byte) (intValue >>> 24); - currentData[currentLength++] = (byte) (intValue >>> 16); - currentData[currentLength++] = (byte) (intValue >>> 8); - currentData[currentLength++] = (byte) intValue; - length = currentLength; - return this; - } - - /** - * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if - * necessary. - * - * @param stringValue a String whose UTF8 encoded length must be less than 65536. - * @return this byte vector. - */ - public ByteVector putUTF8(final String stringValue) { - int charLength = stringValue.length(); - if (charLength > 65535) { - throw new IllegalArgumentException(); - } - int currentLength = length; - if (currentLength + 2 + charLength > data.length) { - enlarge(2 + charLength); - } - byte[] currentData = data; - // Optimistic algorithm: instead of computing the byte length and then serializing the string - // (which requires two loops), we assume the byte length is equal to char length (which is the - // most frequent case), and we start serializing the string right away. During the - // serialization, if we find that this assumption is wrong, we continue with the general method. - currentData[currentLength++] = (byte) (charLength >>> 8); - currentData[currentLength++] = (byte) charLength; - for (int i = 0; i < charLength; ++i) { - char charValue = stringValue.charAt(i); - if (charValue >= '\u0001' && charValue <= '\u007F') { - currentData[currentLength++] = (byte) charValue; - } else { - length = currentLength; - return encodeUTF8(stringValue, i, 65535); - } - } - length = currentLength; - return this; - } - - /** - * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if - * necessary. The string length is encoded in two bytes before the encoded characters, if there is - * space for that (i.e. if this.length - offset - 2 >= 0). - * - * @param stringValue the String to encode. - * @param offset the index of the first character to encode. The previous characters are supposed - * to have already been encoded, using only one byte per character. - * @param maxByteLength the maximum byte length of the encoded string, including the already - * encoded characters. - * @return this byte vector. - */ - final ByteVector encodeUTF8(final String stringValue, final int offset, final int maxByteLength) { - int charLength = stringValue.length(); - int byteLength = offset; - for (int i = offset; i < charLength; ++i) { - char charValue = stringValue.charAt(i); - if (charValue >= '\u0001' && charValue <= '\u007F') { - byteLength++; - } else if (charValue <= '\u07FF') { - byteLength += 2; - } else { - byteLength += 3; - } - } - if (byteLength > maxByteLength) { - throw new IllegalArgumentException(); - } - // Compute where 'byteLength' must be stored in 'data', and store it at this location. - int byteLengthOffset = length - offset - 2; - if (byteLengthOffset >= 0) { - data[byteLengthOffset] = (byte) (byteLength >>> 8); - data[byteLengthOffset + 1] = (byte) byteLength; - } - if (length + byteLength - offset > data.length) { - enlarge(byteLength - offset); - } - int currentLength = length; - for (int i = offset; i < charLength; ++i) { - char charValue = stringValue.charAt(i); - if (charValue >= '\u0001' && charValue <= '\u007F') { - data[currentLength++] = (byte) charValue; - } else if (charValue <= '\u07FF') { - data[currentLength++] = (byte) (0xC0 | charValue >> 6 & 0x1F); - data[currentLength++] = (byte) (0x80 | charValue & 0x3F); - } else { - data[currentLength++] = (byte) (0xE0 | charValue >> 12 & 0xF); - data[currentLength++] = (byte) (0x80 | charValue >> 6 & 0x3F); - data[currentLength++] = (byte) (0x80 | charValue & 0x3F); - } - } - length = currentLength; - return this; - } - - /** - * Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if - * necessary. - * - * @param byteArrayValue an array of bytes. May be null to put byteLength null - * bytes into this byte vector. - * @param byteOffset index of the first byte of byteArrayValue that must be copied. - * @param byteLength number of bytes of byteArrayValue that must be copied. - * @return this byte vector. - */ - public ByteVector putByteArray( - final byte[] byteArrayValue, final int byteOffset, final int byteLength) { - if (length + byteLength > data.length) { - enlarge(byteLength); - } - if (byteArrayValue != null) { - System.arraycopy(byteArrayValue, byteOffset, data, length, byteLength); - } - length += byteLength; - return this; - } - - /** - * Enlarges this byte vector so that it can receive 'size' more bytes. - * - * @param size number of additional bytes that this byte vector should be able to receive. - */ - private void enlarge(final int size) { - int doubleCapacity = 2 * data.length; - int minimalCapacity = length + size; - byte[] newData = new byte[doubleCapacity > minimalCapacity ? doubleCapacity : minimalCapacity]; - System.arraycopy(data, 0, newData, 0, length); - data = newData; - } -} diff --git a/src/main/java/org/objectweb/asm/ClassReader.java b/src/main/java/org/objectweb/asm/ClassReader.java deleted file mode 100644 index abb1350f..00000000 --- a/src/main/java/org/objectweb/asm/ClassReader.java +++ /dev/null @@ -1,3495 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * A parser to make a {@link ClassVisitor} visit a ClassFile structure, as defined in the Java - * Virtual Machine Specification (JVMS). This class parses the ClassFile content and calls the - * appropriate visit methods of a given {@link ClassVisitor} for each field, method and bytecode - * instruction encountered. - * - * @author Eric Bruneton - * @author Eugene Kuleshov - * @see JVMS 4 - */ -public class ClassReader { - - /** - * A flag to skip the Code attributes. If this flag is set the Code attributes are neither parsed - * nor visited. - */ - public static final int SKIP_CODE = 1; - - /** - * A flag to skip the SourceFile, SourceDebugExtension, LocalVariableTable, LocalVariableTypeTable - * and LineNumberTable attributes. If this flag is set these attributes are neither parsed nor - * visited (i.e. {@link ClassVisitor#visitSource}, {@link MethodVisitor#visitLocalVariable} and - * {@link MethodVisitor#visitLineNumber} are not called). - */ - public static final int SKIP_DEBUG = 2; - - /** - * A flag to skip the StackMap and StackMapTable attributes. If this flag is set these attributes - * are neither parsed nor visited (i.e. {@link MethodVisitor#visitFrame} is not called). This flag - * is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is used: it avoids visiting frames - * that will be ignored and recomputed from scratch. - */ - public static final int SKIP_FRAMES = 4; - - /** - * A flag to expand the stack map frames. By default stack map frames are visited in their - * original format (i.e. "expanded" for classes whose version is less than V1_6, and "compressed" - * for the other classes). If this flag is set, stack map frames are always visited in expanded - * format (this option adds a decompression/compression step in ClassReader and ClassWriter which - * degrades performance quite a lot). - */ - public static final int EXPAND_FRAMES = 8; - - /** - * A flag to expand the ASM specific instructions into an equivalent sequence of standard bytecode - * instructions. When resolving a forward jump it may happen that the signed 2 bytes offset - * reserved for it is not sufficient to store the bytecode offset. In this case the jump - * instruction is replaced with a temporary ASM specific instruction using an unsigned 2 bytes - * offset (see {@link Label#resolve}). This internal flag is used to re-read classes containing - * such instructions, in order to replace them with standard instructions. In addition, when this - * flag is used, goto_w and jsr_w are not converted into goto and jsr, to make sure that - * infinite loops where a goto_w is replaced with a goto in ClassReader and converted back to a - * goto_w in ClassWriter cannot occur. - */ - static final int EXPAND_ASM_INSNS = 256; - - /** - * The size of the temporary byte array used to read class input streams chunk by chunk. - */ - private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096; - - /** - * A byte array containing the JVMS ClassFile structure to be parsed. The content of this array - * must not be modified. This field is intended for {@link Attribute} sub classes, and is normally - * not needed by class visitors. - * - *

NOTE: the ClassFile structure can start at any offset within this array, i.e. it does not - * necessarily start at offset 0. Use {@link #getItem} and {@link #header} to get correct - * ClassFile element offsets within this byte array. - */ - public final byte[] b; - - /** - * The offset in bytes, in {@link #b}, of each cp_info entry of the ClassFile's constant_pool - * array, plus one. In other words, the offset of constant pool entry i is given by - * cpInfoOffsets[i] - 1, i.e. its cp_info's tag field is given by b[cpInfoOffsets[i] - 1]. - */ - private final int[] cpInfoOffsets; - - /** - * The String objects corresponding to the CONSTANT_Utf8 items. This cache avoids multiple parsing - * of a given CONSTANT_Utf8 constant pool item. - */ - private final String[] constantUtf8Values; - - /** - * A conservative estimate of the maximum length of the strings contained in the constant pool of - * the class. - */ - private final int maxStringLength; - - /** - * The offset in bytes, in {@link #b}, of the ClassFile's access_flags field. - */ - public final int header; - - // ----------------------------------------------------------------------------------------------- - // Constructors - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a new {@link ClassReader} object. - * - * @param classFile the JVMS ClassFile structure to be read. - */ - public ClassReader(final byte[] classFile) { - this(classFile, 0, classFile.length); - } - - /** - * Constructs a new {@link ClassReader} object. - * - * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read. - * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read. - * @param classFileLength the length in bytes of the ClassFile to be read. - */ - public ClassReader( - final byte[] classFileBuffer, final int classFileOffset, final int classFileLength) { - this(classFileBuffer, classFileOffset, /* checkClassVersion = */ true); - } - - /** - * Constructs a new {@link ClassReader} object. This internal constructor must not be exposed - * as a public API. - * - * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read. - * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read. - * @param checkClassVersion whether to check the class version or not. - */ - ClassReader( - final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion) { - this.b = classFileBuffer; - // Check the class' major_version. This field is after the magic and minor_version fields, which - // use 4 and 2 bytes respectively. - if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V10) { - throw new IllegalArgumentException( - "Unsupported class file major version " + readShort(classFileOffset + 6)); - } - // Create the constant pool arrays. The constant_pool_count field is after the magic, - // minor_version and major_version fields, which use 4, 2 and 2 bytes respectively. - int constantPoolCount = readUnsignedShort(classFileOffset + 8); - cpInfoOffsets = new int[constantPoolCount]; - constantUtf8Values = new String[constantPoolCount]; - // Compute the offset of each constant pool entry, as well as a conservative estimate of the - // maximum length of the constant pool strings. The first constant pool entry is after the - // magic, minor_version, major_version and constant_pool_count fields, which use 4, 2, 2 and 2 - // bytes respectively. - int currentCpInfoIndex = 1; - int currentCpInfoOffset = classFileOffset + 10; - int currentMaxStringLength = 0; - // The offset of the other entries depend on the total size of all the previous entries. - while (currentCpInfoIndex < constantPoolCount) { - cpInfoOffsets[currentCpInfoIndex++] = currentCpInfoOffset + 1; - int cpInfoSize; - switch (classFileBuffer[currentCpInfoOffset]) { - case Symbol.CONSTANT_FIELDREF_TAG: - case Symbol.CONSTANT_METHODREF_TAG: - case Symbol.CONSTANT_INTERFACE_METHODREF_TAG: - case Symbol.CONSTANT_INTEGER_TAG: - case Symbol.CONSTANT_FLOAT_TAG: - case Symbol.CONSTANT_NAME_AND_TYPE_TAG: - case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG: - cpInfoSize = 5; - break; - case Symbol.CONSTANT_LONG_TAG: - case Symbol.CONSTANT_DOUBLE_TAG: - cpInfoSize = 9; - currentCpInfoIndex++; - break; - case Symbol.CONSTANT_UTF8_TAG: - cpInfoSize = 3 + readUnsignedShort(currentCpInfoOffset + 1); - if (cpInfoSize > currentMaxStringLength) { - // The size in bytes of this CONSTANT_Utf8 structure provides a conservative estimate - // of the length in characters of the corresponding string, and is much cheaper to - // compute than this exact length. - currentMaxStringLength = cpInfoSize; - } - break; - case Symbol.CONSTANT_METHOD_HANDLE_TAG: - cpInfoSize = 4; - break; - case Symbol.CONSTANT_CLASS_TAG: - case Symbol.CONSTANT_STRING_TAG: - case Symbol.CONSTANT_METHOD_TYPE_TAG: - case Symbol.CONSTANT_PACKAGE_TAG: - case Symbol.CONSTANT_MODULE_TAG: - cpInfoSize = 3; - break; - default: - throw new IllegalArgumentException(); - } - currentCpInfoOffset += cpInfoSize; - } - this.maxStringLength = currentMaxStringLength; - // The Classfile's access_flags field is just after the last constant pool entry. - this.header = currentCpInfoOffset; - } - - /** - * Constructs a new {@link ClassReader} object. - * - * @param inputStream an input stream of the JVMS ClassFile structure to be read. This input - * stream must contain nothing more than the ClassFile structure itself. It is read from its - * current position to its end. - * @throws IOException if a problem occurs during reading. - */ - public ClassReader(final InputStream inputStream) throws IOException { - this(readStream(inputStream, false)); - } - - /** - * Constructs a new {@link ClassReader} object. - * - * @param className the fully qualified name of the class to be read. The ClassFile structure is - * retrieved with the current class loader's {@link ClassLoader#getSystemResourceAsStream}. - * @throws IOException if an exception occurs during reading. - */ - public ClassReader(final String className) throws IOException { - this( - readStream( - ClassLoader.getSystemResourceAsStream(className.replace('.', '/') + ".class"), true)); - } - - /** - * Reads the given input stream and returns its content as a byte array. - * - * @param inputStream an input stream. - * @param close true to close the input stream after reading. - * @return the content of the given input stream. - * @throws IOException if a problem occurs during reading. - */ - private static byte[] readStream(final InputStream inputStream, final boolean close) - throws IOException { - if (inputStream == null) { - throw new IOException("Class not found"); - } - try { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - byte[] data = new byte[INPUT_STREAM_DATA_CHUNK_SIZE]; - int bytesRead; - while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) { - outputStream.write(data, 0, bytesRead); - } - outputStream.flush(); - return outputStream.toByteArray(); - } finally { - if (close) { - inputStream.close(); - } - } - } - - // ----------------------------------------------------------------------------------------------- - // Accessors - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the class's access flags (see {@link Opcodes}). This value may not reflect Deprecated - * and Synthetic flags when bytecode is before 1.5 and those flags are represented by attributes. - * - * @return the class access flags. - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public int getAccess() { - return readUnsignedShort(header); - } - - /** - * Returns the internal name of the class (see {@link Type#getInternalName()}). - * - * @return the internal class name. - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public String getClassName() { - // this_class is just after the access_flags field (using 2 bytes). - return readClass(header + 2, new char[maxStringLength]); - } - - /** - * Returns the internal of name of the super class (see {@link Type#getInternalName()}). For - * interfaces, the super class is {@link Object}. - * - * @return the internal name of the super class, or null for {@link Object} class. - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public String getSuperName() { - // super_class is after the access_flags and this_class fields (2 bytes each). - return readClass(header + 4, new char[maxStringLength]); - } - - /** - * Returns the internal names of the implemented interfaces (see {@link Type#getInternalName()}). - * - * @return the internal names of the directly implemented interfaces. Inherited implemented - * interfaces are not returned. - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public String[] getInterfaces() { - // interfaces_count is after the access_flags, this_class and super_class fields (2 bytes each). - int currentOffset = header + 6; - int interfacesCount = readUnsignedShort(currentOffset); - String[] interfaces = new String[interfacesCount]; - if (interfacesCount > 0) { - char[] charBuffer = new char[maxStringLength]; - for (int i = 0; i < interfacesCount; ++i) { - currentOffset += 2; - interfaces[i] = readClass(currentOffset, charBuffer); - } - } - return interfaces; - } - - // ----------------------------------------------------------------------------------------------- - // Public methods - // ----------------------------------------------------------------------------------------------- - - /** - * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this - * {@link ClassReader}. - * - * @param classVisitor the visitor that must visit this class. - * @param parsingOptions the options to use to parse this class. One or more of {@link - * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}. - */ - public void accept(final ClassVisitor classVisitor, final int parsingOptions) { - accept(classVisitor, new Attribute[0], parsingOptions); - } - - /** - * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this - * {@link ClassReader}. - * - * @param classVisitor the visitor that must visit this class. - * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of - * the class. Any attribute whose type is not equal to the type of one the prototypes will not - * be parsed: its byte array value will be passed unchanged to the ClassWriter. This may - * corrupt it if this value contains references to the constant pool, or has syntactic or - * semantic links with a class element that has been transformed by a class adapter between - * the reader and the writer. - * @param parsingOptions the options to use to parse this class. One or more of {@link - * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}. - */ - public void accept( - final ClassVisitor classVisitor, - final Attribute[] attributePrototypes, - final int parsingOptions) { - Context context = new Context(); - context.attributePrototypes = attributePrototypes; - context.parsingOptions = parsingOptions; - context.charBuffer = new char[maxStringLength]; - - // Read the access_flags, this_class, super_class, interface_count and interfaces fields. - char[] charBuffer = context.charBuffer; - int currentOffset = header; - int accessFlags = readUnsignedShort(currentOffset); - String thisClass = readClass(currentOffset + 2, charBuffer); - String superClass = readClass(currentOffset + 4, charBuffer); - String[] interfaces = new String[readUnsignedShort(currentOffset + 6)]; - currentOffset += 8; - for (int i = 0; i < interfaces.length; ++i) { - interfaces[i] = readClass(currentOffset, charBuffer); - currentOffset += 2; - } - - // Read the class attributes (the variables are ordered as in Section 4.7 of the JVMS). - // Attribute offsets exclude the attribute_name_index and attribute_length fields. - // - The offset of the InnerClasses attribute, or 0. - int innerClassesOffset = 0; - // - The offset of the EnclosingMethod attribute, or 0. - int enclosingMethodOffset = 0; - // - The string corresponding to the Signature attribute, or null. - String signature = null; - // - The string corresponding to the SourceFile attribute, or null. - String sourceFile = null; - // - The string corresponding to the SourceDebugExtension attribute, or null. - String sourceDebugExtension = null; - // - The offset of the RuntimeVisibleAnnotations attribute, or 0. - int runtimeVisibleAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. - int runtimeInvisibleAnnotationsOffset = 0; - // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. - int runtimeVisibleTypeAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. - int runtimeInvisibleTypeAnnotationsOffset = 0; - // - The offset of the Module attribute, or 0. - int moduleOffset = 0; - // - The offset of the ModulePackages attribute, or 0. - int modulePackagesOffset = 0; - // - The string corresponding to the ModuleMainClass attribute, or null. - String moduleMainClass = null; - // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). - // This list in the reverse order or their order in the ClassFile structure. - Attribute attributes = null; - - int currentAttributeOffset = getFirstAttributeOffset(); - for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { - // Read the attribute_info's attribute_name and attribute_length fields. - String attributeName = readUTF8(currentAttributeOffset, charBuffer); - int attributeLength = readInt(currentAttributeOffset + 2); - currentAttributeOffset += 6; - // The tests are sorted in decreasing frequency order (based on frequencies observed on - // typical classes). - if (Constants.SOURCE_FILE.equals(attributeName)) { - sourceFile = readUTF8(currentAttributeOffset, charBuffer); - } else if (Constants.INNER_CLASSES.equals(attributeName)) { - innerClassesOffset = currentAttributeOffset; - } else if (Constants.ENCLOSING_METHOD.equals(attributeName)) { - enclosingMethodOffset = currentAttributeOffset; - } else if (Constants.SIGNATURE.equals(attributeName)) { - signature = readUTF8(currentAttributeOffset, charBuffer); - } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleAnnotationsOffset = currentAttributeOffset; - } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleTypeAnnotationsOffset = currentAttributeOffset; - } else if (Constants.DEPRECATED.equals(attributeName)) { - accessFlags |= Opcodes.ACC_DEPRECATED; - } else if (Constants.SYNTHETIC.equals(attributeName)) { - accessFlags |= Opcodes.ACC_SYNTHETIC; - } else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) { - sourceDebugExtension = - readUTF(currentAttributeOffset, attributeLength, new char[attributeLength]); - } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleAnnotationsOffset = currentAttributeOffset; - } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleTypeAnnotationsOffset = currentAttributeOffset; - } else if (Constants.MODULE.equals(attributeName)) { - moduleOffset = currentAttributeOffset; - } else if (Constants.MODULE_MAIN_CLASS.equals(attributeName)) { - moduleMainClass = readClass(currentAttributeOffset, charBuffer); - } else if (Constants.MODULE_PACKAGES.equals(attributeName)) { - modulePackagesOffset = currentAttributeOffset; - } else if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) { - // Read the num_bootstrap_methods field and create an array of this size. - int[] bootstrapMethodOffsets = new int[readUnsignedShort(currentAttributeOffset)]; - // Compute and store the offset of each 'bootstrap_methods' array field entry. - int currentBootstrapMethodOffset = currentAttributeOffset + 2; - for (int j = 0; j < bootstrapMethodOffsets.length; ++j) { - bootstrapMethodOffsets[j] = currentBootstrapMethodOffset; - // Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each), - // as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2). - currentBootstrapMethodOffset += - 4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2; - } - context.bootstrapMethodOffsets = bootstrapMethodOffsets; - } else { - Attribute attribute = - readAttribute( - attributePrototypes, - attributeName, - currentAttributeOffset, - attributeLength, - charBuffer, - -1, - null); - attribute.nextAttribute = attributes; - attributes = attribute; - } - currentAttributeOffset += attributeLength; - } - - // Visit the class declaration. The minor_version and major_version fields start 6 bytes before - // the first constant pool entry, which itself starts at cpInfoOffsets[1] - 1 (by definition). - classVisitor.visit( - readInt(cpInfoOffsets[1] - 7), accessFlags, thisClass, signature, superClass, interfaces); - - // Visit the SourceFile and SourceDebugExtenstion attributes. - if ((parsingOptions & SKIP_DEBUG) == 0 - && (sourceFile != null || sourceDebugExtension != null)) { - classVisitor.visitSource(sourceFile, sourceDebugExtension); - } - - // Visit the Module, ModulePackages and ModuleMainClass attributes. - if (moduleOffset != 0) { - readModule(classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass); - } - - // Visit the EnclosingMethod attribute. - if (enclosingMethodOffset != 0) { - String className = readClass(enclosingMethodOffset, charBuffer); - int methodIndex = readUnsignedShort(enclosingMethodOffset + 2); - String name = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex], charBuffer); - String type = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex] + 2, charBuffer); - classVisitor.visitOuterClass(className, name, type); - } - - // Visit the RuntimeVisibleAnnotations attribute. - if (runtimeVisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleAnnotations attribute. - if (runtimeInvisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeVisibleTypeAnnotations attribute. - if (runtimeVisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - classVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleTypeAnnotations attribute. - if (runtimeInvisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - classVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the non standard attributes. - while (attributes != null) { - // Copy and reset the nextAttribute field so that it can also be used in ClassWriter. - Attribute nextAttribute = attributes.nextAttribute; - attributes.nextAttribute = null; - classVisitor.visitAttribute(attributes); - attributes = nextAttribute; - } - - // Visit the InnerClasses attribute. - if (innerClassesOffset != 0) { - int numberOfClasses = readUnsignedShort(innerClassesOffset); - int currentClassesOffset = innerClassesOffset + 2; - while (numberOfClasses-- > 0) { - classVisitor.visitInnerClass( - readClass(currentClassesOffset, charBuffer), - readClass(currentClassesOffset + 2, charBuffer), - readUTF8(currentClassesOffset + 4, charBuffer), - readUnsignedShort(currentClassesOffset + 6)); - currentClassesOffset += 8; - } - } - - // Visit the fields and methods. - int fieldsCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (fieldsCount-- > 0) { - currentOffset = readField(classVisitor, context, currentOffset); - } - int methodsCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (methodsCount-- > 0) { - currentOffset = readMethod(classVisitor, context, currentOffset); - } - - // Visit the end of the class. - classVisitor.visitEnd(); - } - - // ---------------------------------------------------------------------------------------------- - // Methods to parse modules, fields and methods - // ---------------------------------------------------------------------------------------------- - - /** - * Reads the module attribute and visit it. - * - * @param classVisitor the current class visitor - * @param context information about the class being parsed. - * @param moduleOffset the offset of the Module attribute (excluding the attribute_info's - * attribute_name_index and attribute_length fields). - * @param modulePackagesOffset the offset of the ModulePackages attribute (excluding the - * attribute_info's attribute_name_index and attribute_length fields), or 0. - * @param moduleMainClass the string corresponding to the ModuleMainClass attribute, or null. - */ - private void readModule( - final ClassVisitor classVisitor, - final Context context, - final int moduleOffset, - final int modulePackagesOffset, - final String moduleMainClass) { - char[] buffer = context.charBuffer; - - // Read the module_name_index, module_flags and module_version_index fields and visit them. - int currentOffset = moduleOffset; - String moduleName = readModule(currentOffset, buffer); - int moduleFlags = readUnsignedShort(currentOffset + 2); - String moduleVersion = readUTF8(currentOffset + 4, buffer); - currentOffset += 6; - ModuleVisitor moduleVisitor = classVisitor.visitModule(moduleName, moduleFlags, moduleVersion); - if (moduleVisitor == null) { - return; - } - - // Visit the ModuleMainClass attribute. - if (moduleMainClass != null) { - moduleVisitor.visitMainClass(moduleMainClass); - } - - // Visit the ModulePackages attribute. - if (modulePackagesOffset != 0) { - int packageCount = readUnsignedShort(modulePackagesOffset); - int currentPackageOffset = modulePackagesOffset + 2; - while (packageCount-- > 0) { - moduleVisitor.visitPackage(readPackage(currentPackageOffset, buffer)); - currentPackageOffset += 2; - } - } - - // Read the 'requires_count' and 'requires' fields. - int requiresCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (requiresCount-- > 0) { - // Read the requires_index, requires_flags and requires_version fields and visit them. - String requires = readModule(currentOffset, buffer); - int requiresFlags = readUnsignedShort(currentOffset + 2); - String requiresVersion = readUTF8(currentOffset + 4, buffer); - currentOffset += 6; - moduleVisitor.visitRequire(requires, requiresFlags, requiresVersion); - } - - // Read the 'exports_count' and 'exports' fields. - int exportsCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (exportsCount-- > 0) { - // Read the exports_index, exports_flags, exports_to_count and exports_to_index fields - // and visit them. - String exports = readPackage(currentOffset, buffer); - int exportsFlags = readUnsignedShort(currentOffset + 2); - int exportsToCount = readUnsignedShort(currentOffset + 4); - currentOffset += 6; - String[] exportsTo = null; - if (exportsToCount != 0) { - exportsTo = new String[exportsToCount]; - for (int i = 0; i < exportsToCount; ++i) { - exportsTo[i] = readModule(currentOffset, buffer); - currentOffset += 2; - } - } - moduleVisitor.visitExport(exports, exportsFlags, exportsTo); - } - - // Reads the 'opens_count' and 'opens' fields. - int opensCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (opensCount-- > 0) { - // Read the opens_index, opens_flags, opens_to_count and opens_to_index fields and visit them. - String opens = readPackage(currentOffset, buffer); - int opensFlags = readUnsignedShort(currentOffset + 2); - int opensToCount = readUnsignedShort(currentOffset + 4); - currentOffset += 6; - String[] opensTo = null; - if (opensToCount != 0) { - opensTo = new String[opensToCount]; - for (int i = 0; i < opensToCount; ++i) { - opensTo[i] = readModule(currentOffset, buffer); - currentOffset += 2; - } - } - moduleVisitor.visitOpen(opens, opensFlags, opensTo); - } - - // Read the 'uses_count' and 'uses' fields. - int usesCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (usesCount-- > 0) { - moduleVisitor.visitUse(readClass(currentOffset, buffer)); - currentOffset += 2; - } - - // Read the 'provides_count' and 'provides' fields. - int providesCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (providesCount-- > 0) { - // Read the provides_index, provides_with_count and provides_with_index fields and visit them. - String provides = readClass(currentOffset, buffer); - int providesWithCount = readUnsignedShort(currentOffset + 2); - currentOffset += 4; - String[] providesWith = new String[providesWithCount]; - for (int i = 0; i < providesWithCount; ++i) { - providesWith[i] = readClass(currentOffset, buffer); - currentOffset += 2; - } - moduleVisitor.visitProvide(provides, providesWith); - } - - // Visit the end of the module attributes. - moduleVisitor.visitEnd(); - } - - /** - * Reads a JVMS field_info structure and makes the given visitor visit it. - * - * @param classVisitor the visitor that must visit the field. - * @param context information about the class being parsed. - * @param fieldInfoOffset the start offset of the field_info structure. - * @return the offset of the first byte following the field_info structure. - */ - private int readField( - final ClassVisitor classVisitor, final Context context, final int fieldInfoOffset) { - char[] charBuffer = context.charBuffer; - - // Read the access_flags, name_index and descriptor_index fields. - int currentOffset = fieldInfoOffset; - int accessFlags = readUnsignedShort(currentOffset); - String name = readUTF8(currentOffset + 2, charBuffer); - String descriptor = readUTF8(currentOffset + 4, charBuffer); - currentOffset += 6; - - // Read the field attributes (the variables are ordered as in Section 4.7 of the JVMS). - // Attribute offsets exclude the attribute_name_index and attribute_length fields. - // - The value corresponding to the ConstantValue attribute, or null. - Object constantValue = null; - // - The string corresponding to the Signature attribute, or null. - String signature = null; - // - The offset of the RuntimeVisibleAnnotations attribute, or 0. - int runtimeVisibleAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. - int runtimeInvisibleAnnotationsOffset = 0; - // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. - int runtimeVisibleTypeAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. - int runtimeInvisibleTypeAnnotationsOffset = 0; - // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). - // This list in the reverse order or their order in the ClassFile structure. - Attribute attributes = null; - - int attributesCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (attributesCount-- > 0) { - // Read the attribute_info's attribute_name and attribute_length fields. - String attributeName = readUTF8(currentOffset, charBuffer); - int attributeLength = readInt(currentOffset + 2); - currentOffset += 6; - // The tests are sorted in decreasing frequency order (based on frequencies observed on - // typical classes). - if (Constants.CONSTANT_VALUE.equals(attributeName)) { - int constantvalueIndex = readUnsignedShort(currentOffset); - constantValue = constantvalueIndex == 0 ? null : readConst(constantvalueIndex, charBuffer); - } else if (Constants.SIGNATURE.equals(attributeName)) { - signature = readUTF8(currentOffset, charBuffer); - } else if (Constants.DEPRECATED.equals(attributeName)) { - accessFlags |= Opcodes.ACC_DEPRECATED; - } else if (Constants.SYNTHETIC.equals(attributeName)) { - accessFlags |= Opcodes.ACC_SYNTHETIC; - } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleTypeAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleTypeAnnotationsOffset = currentOffset; - } else { - Attribute attribute = - readAttribute( - context.attributePrototypes, - attributeName, - currentOffset, - attributeLength, - charBuffer, - -1, - null); - attribute.nextAttribute = attributes; - attributes = attribute; - } - currentOffset += attributeLength; - } - - // Visit the field declaration. - FieldVisitor fieldVisitor = - classVisitor.visitField(accessFlags, name, descriptor, signature, constantValue); - if (fieldVisitor == null) { - return currentOffset; - } - - // Visit the RuntimeVisibleAnnotations attribute. - if (runtimeVisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleAnnotations attribute. - if (runtimeInvisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeVisibleTypeAnnotations attribute. - if (runtimeVisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - fieldVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleTypeAnnotations attribute. - if (runtimeInvisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - fieldVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the non standard attributes. - while (attributes != null) { - // Copy and reset the nextAttribute field so that it can also be used in FieldWriter. - Attribute nextAttribute = attributes.nextAttribute; - attributes.nextAttribute = null; - fieldVisitor.visitAttribute(attributes); - attributes = nextAttribute; - } - - // Visit the end of the field. - fieldVisitor.visitEnd(); - return currentOffset; - } - - /** - * Reads a JVMS method_info structure and makes the given visitor visit it. - * - * @param classVisitor the visitor that must visit the method. - * @param context information about the class being parsed. - * @param methodInfoOffset the start offset of the method_info structure. - * @return the offset of the first byte following the method_info structure. - */ - private int readMethod( - final ClassVisitor classVisitor, final Context context, final int methodInfoOffset) { - char[] charBuffer = context.charBuffer; - - // Read the access_flags, name_index and descriptor_index fields. - int currentOffset = methodInfoOffset; - context.currentMethodAccessFlags = readUnsignedShort(currentOffset); - context.currentMethodName = readUTF8(currentOffset + 2, charBuffer); - context.currentMethodDescriptor = readUTF8(currentOffset + 4, charBuffer); - currentOffset += 6; - - // Read the method attributes (the variables are ordered as in Section 4.7 of the JVMS). - // Attribute offsets exclude the attribute_name_index and attribute_length fields. - // - The offset of the Code attribute, or 0. - int codeOffset = 0; - // - The offset of the Exceptions attribute, or 0. - int exceptionsOffset = 0; - // - The strings corresponding to the Exceptions attribute, or null. - String[] exceptions = null; - // - The string corresponding to the Signature attribute, or null. - int signature = 0; - // - The offset of the RuntimeVisibleAnnotations attribute, or 0. - int runtimeVisibleAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. - int runtimeInvisibleAnnotationsOffset = 0; - // - The offset of the RuntimeVisibleParameterAnnotations attribute, or 0. - int runtimeVisibleParameterAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleParameterAnnotations attribute, or 0. - int runtimeInvisibleParameterAnnotationsOffset = 0; - // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. - int runtimeVisibleTypeAnnotationsOffset = 0; - // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. - int runtimeInvisibleTypeAnnotationsOffset = 0; - // - The offset of the AnnotationDefault attribute, or 0. - int annotationDefaultOffset = 0; - // - The offset of the MethodParameters attribute, or 0. - int methodParametersOffset = 0; - // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). - // This list in the reverse order or their order in the ClassFile structure. - Attribute attributes = null; - - int attributesCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (attributesCount-- > 0) { - // Read the attribute_info's attribute_name and attribute_length fields. - String attributeName = readUTF8(currentOffset, charBuffer); - int attributeLength = readInt(currentOffset + 2); - currentOffset += 6; - // The tests are sorted in decreasing frequency order (based on frequencies observed on - // typical classes). - if (Constants.CODE.equals(attributeName)) { - if ((context.parsingOptions & SKIP_CODE) == 0) { - codeOffset = currentOffset; - } - } else if (Constants.EXCEPTIONS.equals(attributeName)) { - exceptionsOffset = currentOffset; - exceptions = new String[readUnsignedShort(exceptionsOffset)]; - int currentExceptionOffset = exceptionsOffset + 2; - for (int i = 0; i < exceptions.length; ++i) { - exceptions[i] = readClass(currentExceptionOffset, charBuffer); - currentExceptionOffset += 2; - } - } else if (Constants.SIGNATURE.equals(attributeName)) { - signature = readUnsignedShort(currentOffset); - } else if (Constants.DEPRECATED.equals(attributeName)) { - context.currentMethodAccessFlags |= Opcodes.ACC_DEPRECATED; - } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleTypeAnnotationsOffset = currentOffset; - } else if (Constants.ANNOTATION_DEFAULT.equals(attributeName)) { - annotationDefaultOffset = currentOffset; - } else if (Constants.SYNTHETIC.equals(attributeName)) { - context.currentMethodAccessFlags |= Opcodes.ACC_SYNTHETIC; - } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleTypeAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) { - runtimeVisibleParameterAnnotationsOffset = currentOffset; - } else if (Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) { - runtimeInvisibleParameterAnnotationsOffset = currentOffset; - } else if (Constants.METHOD_PARAMETERS.equals(attributeName)) { - methodParametersOffset = currentOffset; - } else { - Attribute attribute = - readAttribute( - context.attributePrototypes, - attributeName, - currentOffset, - attributeLength, - charBuffer, - -1, - null); - attribute.nextAttribute = attributes; - attributes = attribute; - } - currentOffset += attributeLength; - } - - // Visit the method declaration. - MethodVisitor methodVisitor = - classVisitor.visitMethod( - context.currentMethodAccessFlags, - context.currentMethodName, - context.currentMethodDescriptor, - signature == 0 ? null : readUTF(signature, charBuffer), - exceptions); - if (methodVisitor == null) { - return currentOffset; - } - - // If the returned MethodVisitor is in fact a MethodWriter, it means there is no method - // adapter between the reader and the writer. If, in addition, the writer's constant pool was - // copied from this reader (mw.getSource() == this), and the signature and exceptions of the - // method have not been changed, then it is possible to skip all visit events and just copy the - // original code of the method to the writer (the access_flags, name_index and descriptor_index - // can have been changed, this is not important since they are not copied from the reader). - if (methodVisitor instanceof MethodWriter) { - MethodWriter methodWriter = (MethodWriter) methodVisitor; - if (methodWriter.getSource() == this && signature == methodWriter.signatureIndex) { - boolean sameExceptions = false; - if (exceptions == null) { - sameExceptions = methodWriter.numberOfExceptions == 0; - } else if (exceptions.length == methodWriter.numberOfExceptions) { - sameExceptions = true; - int currentExceptionOffset = exceptionsOffset + 2; - for (int i = 0; i < exceptions.length; ++i) { - if (methodWriter.exceptionIndexTable[i] != readUnsignedShort(currentExceptionOffset)) { - sameExceptions = false; - break; - } - currentExceptionOffset += 2; - } - } - if (sameExceptions) { - // We do not copy directly the code into methodWriter to save a byte array copy operation. - // The real copy will be done in {@link MethodWriter#putMethodInfo}. - methodWriter.sourceOffset = methodInfoOffset + 6; - methodWriter.sourceLength = currentOffset - methodWriter.sourceOffset; - return currentOffset; - } - } - } - - // Visit the MethodParameters attribute. - if (methodParametersOffset != 0) { - int parametersCount = readByte(methodParametersOffset); - int currentParameterOffset = methodParametersOffset + 1; - while (parametersCount-- > 0) { - // Read the name_index and access_flags fields and visit them. - methodVisitor.visitParameter( - readUTF8(currentParameterOffset, charBuffer), - readUnsignedShort(currentParameterOffset + 2)); - currentParameterOffset += 4; - } - } - - // Visit the AnnotationDefault attribute. - if (annotationDefaultOffset != 0) { - AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault(); - readElementValue(annotationVisitor, annotationDefaultOffset, null, charBuffer); - if (annotationVisitor != null) { - annotationVisitor.visitEnd(); - } - } - - // Visit the RuntimeVisibleAnnotations attribute. - if (runtimeVisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleAnnotations attribute. - if (runtimeInvisibleAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeVisibleTypeAnnotations attribute. - if (runtimeVisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - methodVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeInvisibleTypeAnnotations attribute. - if (runtimeInvisibleTypeAnnotationsOffset != 0) { - int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset); - int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2; - while (numAnnotations-- > 0) { - // Parse the target_type, target_info and target_path fields. - currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentAnnotationOffset = - readElementValues( - methodVisitor.visitTypeAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - } - - // Visit the RuntimeVisibleParameterAnnotations attribute. - if (runtimeVisibleParameterAnnotationsOffset != 0) { - readParameterAnnotations( - methodVisitor, context, runtimeVisibleParameterAnnotationsOffset, /* visible = */ true); - } - - // Visit the RuntimeInvisibleParameterAnnotations attribute. - if (runtimeInvisibleParameterAnnotationsOffset != 0) { - readParameterAnnotations( - methodVisitor, - context, - runtimeInvisibleParameterAnnotationsOffset, - /* visible = */ false); - } - - // Visit the non standard attributes. - while (attributes != null) { - // Copy and reset the nextAttribute field so that it can also be used in MethodWriter. - Attribute nextAttribute = attributes.nextAttribute; - attributes.nextAttribute = null; - methodVisitor.visitAttribute(attributes); - attributes = nextAttribute; - } - - // Visit the Code attribute. - if (codeOffset != 0) { - methodVisitor.visitCode(); - readCode(methodVisitor, context, codeOffset); - } - - // Visit the end of the method. - methodVisitor.visitEnd(); - return currentOffset; - } - - // ---------------------------------------------------------------------------------------------- - // Methods to parse a Code attribute - // ---------------------------------------------------------------------------------------------- - - /** - * Reads a JVMS 'Code' attribute and makes the given visitor visit it. - * - * @param methodVisitor the visitor that must visit the Code attribute. - * @param context information about the class being parsed. - * @param codeOffset the start offset in {@link #b} of the Code attribute, excluding its - * attribute_name_index and attribute_length fields. - */ - private void readCode( - final MethodVisitor methodVisitor, final Context context, final int codeOffset) { - int currentOffset = codeOffset; - - // Read the max_stack, max_locals and code_length fields. - final byte[] classFileBuffer = b; - final char[] charBuffer = context.charBuffer; - final int maxStack = readUnsignedShort(currentOffset); - final int maxLocals = readUnsignedShort(currentOffset + 2); - final int codeLength = readInt(currentOffset + 4); - currentOffset += 8; - - // Read the bytecode 'code' array to create a label for each referenced instruction. - final int bytecodeStartOffset = currentOffset; - final int bytecodeEndOffset = currentOffset + codeLength; - final Label[] labels = context.currentMethodLabels = new Label[codeLength + 1]; - while (currentOffset < bytecodeEndOffset) { - final int bytecodeOffset = currentOffset - bytecodeStartOffset; - final int opcode = classFileBuffer[currentOffset] & 0xFF; - switch (opcode) { - case Constants.NOP: - case Constants.ACONST_NULL: - case Constants.ICONST_M1: - case Constants.ICONST_0: - case Constants.ICONST_1: - case Constants.ICONST_2: - case Constants.ICONST_3: - case Constants.ICONST_4: - case Constants.ICONST_5: - case Constants.LCONST_0: - case Constants.LCONST_1: - case Constants.FCONST_0: - case Constants.FCONST_1: - case Constants.FCONST_2: - case Constants.DCONST_0: - case Constants.DCONST_1: - case Constants.IALOAD: - case Constants.LALOAD: - case Constants.FALOAD: - case Constants.DALOAD: - case Constants.AALOAD: - case Constants.BALOAD: - case Constants.CALOAD: - case Constants.SALOAD: - case Constants.IASTORE: - case Constants.LASTORE: - case Constants.FASTORE: - case Constants.DASTORE: - case Constants.AASTORE: - case Constants.BASTORE: - case Constants.CASTORE: - case Constants.SASTORE: - case Constants.POP: - case Constants.POP2: - case Constants.DUP: - case Constants.DUP_X1: - case Constants.DUP_X2: - case Constants.DUP2: - case Constants.DUP2_X1: - case Constants.DUP2_X2: - case Constants.SWAP: - case Constants.IADD: - case Constants.LADD: - case Constants.FADD: - case Constants.DADD: - case Constants.ISUB: - case Constants.LSUB: - case Constants.FSUB: - case Constants.DSUB: - case Constants.IMUL: - case Constants.LMUL: - case Constants.FMUL: - case Constants.DMUL: - case Constants.IDIV: - case Constants.LDIV: - case Constants.FDIV: - case Constants.DDIV: - case Constants.IREM: - case Constants.LREM: - case Constants.FREM: - case Constants.DREM: - case Constants.INEG: - case Constants.LNEG: - case Constants.FNEG: - case Constants.DNEG: - case Constants.ISHL: - case Constants.LSHL: - case Constants.ISHR: - case Constants.LSHR: - case Constants.IUSHR: - case Constants.LUSHR: - case Constants.IAND: - case Constants.LAND: - case Constants.IOR: - case Constants.LOR: - case Constants.IXOR: - case Constants.LXOR: - case Constants.I2L: - case Constants.I2F: - case Constants.I2D: - case Constants.L2I: - case Constants.L2F: - case Constants.L2D: - case Constants.F2I: - case Constants.F2L: - case Constants.F2D: - case Constants.D2I: - case Constants.D2L: - case Constants.D2F: - case Constants.I2B: - case Constants.I2C: - case Constants.I2S: - case Constants.LCMP: - case Constants.FCMPL: - case Constants.FCMPG: - case Constants.DCMPL: - case Constants.DCMPG: - case Constants.IRETURN: - case Constants.LRETURN: - case Constants.FRETURN: - case Constants.DRETURN: - case Constants.ARETURN: - case Constants.RETURN: - case Constants.ARRAYLENGTH: - case Constants.ATHROW: - case Constants.MONITORENTER: - case Constants.MONITOREXIT: - case Constants.ILOAD_0: - case Constants.ILOAD_1: - case Constants.ILOAD_2: - case Constants.ILOAD_3: - case Constants.LLOAD_0: - case Constants.LLOAD_1: - case Constants.LLOAD_2: - case Constants.LLOAD_3: - case Constants.FLOAD_0: - case Constants.FLOAD_1: - case Constants.FLOAD_2: - case Constants.FLOAD_3: - case Constants.DLOAD_0: - case Constants.DLOAD_1: - case Constants.DLOAD_2: - case Constants.DLOAD_3: - case Constants.ALOAD_0: - case Constants.ALOAD_1: - case Constants.ALOAD_2: - case Constants.ALOAD_3: - case Constants.ISTORE_0: - case Constants.ISTORE_1: - case Constants.ISTORE_2: - case Constants.ISTORE_3: - case Constants.LSTORE_0: - case Constants.LSTORE_1: - case Constants.LSTORE_2: - case Constants.LSTORE_3: - case Constants.FSTORE_0: - case Constants.FSTORE_1: - case Constants.FSTORE_2: - case Constants.FSTORE_3: - case Constants.DSTORE_0: - case Constants.DSTORE_1: - case Constants.DSTORE_2: - case Constants.DSTORE_3: - case Constants.ASTORE_0: - case Constants.ASTORE_1: - case Constants.ASTORE_2: - case Constants.ASTORE_3: - currentOffset += 1; - break; - case Constants.IFEQ: - case Constants.IFNE: - case Constants.IFLT: - case Constants.IFGE: - case Constants.IFGT: - case Constants.IFLE: - case Constants.IF_ICMPEQ: - case Constants.IF_ICMPNE: - case Constants.IF_ICMPLT: - case Constants.IF_ICMPGE: - case Constants.IF_ICMPGT: - case Constants.IF_ICMPLE: - case Constants.IF_ACMPEQ: - case Constants.IF_ACMPNE: - case Constants.GOTO: - case Constants.JSR: - case Constants.IFNULL: - case Constants.IFNONNULL: - createLabel(bytecodeOffset + readShort(currentOffset + 1), labels); - currentOffset += 3; - break; - case Constants.ASM_IFEQ: - case Constants.ASM_IFNE: - case Constants.ASM_IFLT: - case Constants.ASM_IFGE: - case Constants.ASM_IFGT: - case Constants.ASM_IFLE: - case Constants.ASM_IF_ICMPEQ: - case Constants.ASM_IF_ICMPNE: - case Constants.ASM_IF_ICMPLT: - case Constants.ASM_IF_ICMPGE: - case Constants.ASM_IF_ICMPGT: - case Constants.ASM_IF_ICMPLE: - case Constants.ASM_IF_ACMPEQ: - case Constants.ASM_IF_ACMPNE: - case Constants.ASM_GOTO: - case Constants.ASM_JSR: - case Constants.ASM_IFNULL: - case Constants.ASM_IFNONNULL: - createLabel(bytecodeOffset + readUnsignedShort(currentOffset + 1), labels); - currentOffset += 3; - break; - case Constants.GOTO_W: - case Constants.JSR_W: - case Constants.ASM_GOTO_W: - createLabel(bytecodeOffset + readInt(currentOffset + 1), labels); - currentOffset += 5; - break; - case Constants.WIDE: - switch (classFileBuffer[currentOffset + 1] & 0xFF) { - case Constants.ILOAD: - case Constants.FLOAD: - case Constants.ALOAD: - case Constants.LLOAD: - case Constants.DLOAD: - case Constants.ISTORE: - case Constants.FSTORE: - case Constants.ASTORE: - case Constants.LSTORE: - case Constants.DSTORE: - case Constants.RET: - currentOffset += 4; - break; - case Constants.IINC: - currentOffset += 6; - break; - default: - throw new IllegalArgumentException(); - } - break; - case Constants.TABLESWITCH: - // Skip 0 to 3 padding bytes. - currentOffset += 4 - (bytecodeOffset & 3); - // Read the default label and the number of table entries. - createLabel(bytecodeOffset + readInt(currentOffset), labels); - int numTableEntries = readInt(currentOffset + 8) - readInt(currentOffset + 4) + 1; - currentOffset += 12; - // Read the table labels. - while (numTableEntries-- > 0) { - createLabel(bytecodeOffset + readInt(currentOffset), labels); - currentOffset += 4; - } - break; - case Constants.LOOKUPSWITCH: - // Skip 0 to 3 padding bytes. - currentOffset += 4 - (bytecodeOffset & 3); - // Read the default label and the number of switch cases. - createLabel(bytecodeOffset + readInt(currentOffset), labels); - int numSwitchCases = readInt(currentOffset + 4); - currentOffset += 8; - // Read the switch labels. - while (numSwitchCases-- > 0) { - createLabel(bytecodeOffset + readInt(currentOffset + 4), labels); - currentOffset += 8; - } - break; - case Constants.ILOAD: - case Constants.LLOAD: - case Constants.FLOAD: - case Constants.DLOAD: - case Constants.ALOAD: - case Constants.ISTORE: - case Constants.LSTORE: - case Constants.FSTORE: - case Constants.DSTORE: - case Constants.ASTORE: - case Constants.RET: - case Constants.BIPUSH: - case Constants.NEWARRAY: - case Constants.LDC: - currentOffset += 2; - break; - case Constants.SIPUSH: - case Constants.LDC_W: - case Constants.LDC2_W: - case Constants.GETSTATIC: - case Constants.PUTSTATIC: - case Constants.GETFIELD: - case Constants.PUTFIELD: - case Constants.INVOKEVIRTUAL: - case Constants.INVOKESPECIAL: - case Constants.INVOKESTATIC: - case Constants.NEW: - case Constants.ANEWARRAY: - case Constants.CHECKCAST: - case Constants.INSTANCEOF: - case Constants.IINC: - currentOffset += 3; - break; - case Constants.INVOKEINTERFACE: - case Constants.INVOKEDYNAMIC: - currentOffset += 5; - break; - case Constants.MULTIANEWARRAY: - currentOffset += 4; - break; - default: - throw new IllegalArgumentException(); - } - } - - // Read the 'exception_table_length' and 'exception_table' field to create a label for each - // referenced instruction, and to make methodVisitor visit the corresponding try catch blocks. - { - int exceptionTableLength = readUnsignedShort(currentOffset); - currentOffset += 2; - while (exceptionTableLength-- > 0) { - Label start = createLabel(readUnsignedShort(currentOffset), labels); - Label end = createLabel(readUnsignedShort(currentOffset + 2), labels); - Label handler = createLabel(readUnsignedShort(currentOffset + 4), labels); - String catchType = - readUTF8(cpInfoOffsets[readUnsignedShort(currentOffset + 6)], charBuffer); - currentOffset += 8; - methodVisitor.visitTryCatchBlock(start, end, handler, catchType); - } - } - - // Read the Code attributes to create a label for each referenced instruction (the variables - // are ordered as in Section 4.7 of the JVMS). Attribute offsets exclude the - // attribute_name_index and attribute_length fields. - // - The offset of the current 'stack_map_frame' in the StackMap[Table] attribute, or 0. - // Initially, this is the offset of the first 'stack_map_frame' entry. Then this offset is - // updated after each stack_map_frame is read. - int stackMapFrameOffset = 0; - // - The end offset of the StackMap[Table] attribute, or 0. - int stackMapTableEndOffset = 0; - // - Whether the stack map frames are compressed (i.e. in a StackMapTable) or not. - boolean compressedFrames = true; - // - The offset of the LocalVariableTable attribute, or 0. - int localVariableTableOffset = 0; - // - The offset of the LocalVariableTypeTable attribute, or 0. - int localVariableTypeTableOffset = 0; - // - The offset of each 'type_annotation' entry in the RuntimeVisibleTypeAnnotations - // attribute, or null. - int[] visibleTypeAnnotationOffsets = null; - // - The offset of each 'type_annotation' entry in the RuntimeInvisibleTypeAnnotations - // attribute, or null. - int[] invisibleTypeAnnotationOffsets = null; - // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). - // This list in the reverse order or their order in the ClassFile structure. - Attribute attributes = null; - - int attributesCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (attributesCount-- > 0) { - // Read the attribute_info's attribute_name and attribute_length fields. - String attributeName = readUTF8(currentOffset, charBuffer); - int attributeLength = readInt(currentOffset + 2); - currentOffset += 6; - if (Constants.LOCAL_VARIABLE_TABLE.equals(attributeName)) { - if ((context.parsingOptions & SKIP_DEBUG) == 0) { - localVariableTableOffset = currentOffset; - // Parse the attribute to find the corresponding (debug only) labels. - int currentLocalVariableTableOffset = currentOffset; - int localVariableTableLength = readUnsignedShort(currentLocalVariableTableOffset); - currentLocalVariableTableOffset += 2; - while (localVariableTableLength-- > 0) { - int startPc = readUnsignedShort(currentLocalVariableTableOffset); - createDebugLabel(startPc, labels); - int length = readUnsignedShort(currentLocalVariableTableOffset + 2); - createDebugLabel(startPc + length, labels); - // Skip the name_index, descriptor_index and index fields (2 bytes each). - currentLocalVariableTableOffset += 10; - } - } - } else if (Constants.LOCAL_VARIABLE_TYPE_TABLE.equals(attributeName)) { - localVariableTypeTableOffset = currentOffset; - // Here we do not extract the labels corresponding to the attribute content. We assume they - // are the same or a subset of those of the LocalVariableTable attribute. - } else if (Constants.LINE_NUMBER_TABLE.equals(attributeName)) { - if ((context.parsingOptions & SKIP_DEBUG) == 0) { - // Parse the attribute to find the corresponding (debug only) labels. - int currentLineNumberTableOffset = currentOffset; - int lineNumberTableLength = readUnsignedShort(currentLineNumberTableOffset); - currentLineNumberTableOffset += 2; - while (lineNumberTableLength-- > 0) { - int startPc = readUnsignedShort(currentLineNumberTableOffset); - int lineNumber = readUnsignedShort(currentLineNumberTableOffset + 2); - currentLineNumberTableOffset += 4; - createDebugLabel(startPc, labels); - labels[startPc].addLineNumber(lineNumber); - } - } - } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - visibleTypeAnnotationOffsets = - readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ true); - // Here we do not extract the labels corresponding to the attribute content. This would - // require a full parsing of the attribute, which would need to be repeated when parsing - // the bytecode instructions (see below). Instead, the content of the attribute is read one - // type annotation at a time (i.e. after a type annotation has been visited, the next type - // annotation is read), and the labels it contains are also extracted one annotation at a - // time. This assumes that type annotations are ordered by increasing bytecode offset. - } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) { - invisibleTypeAnnotationOffsets = - readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ false); - // Same comment as above for the RuntimeVisibleTypeAnnotations attribute. - } else if (Constants.STACK_MAP_TABLE.equals(attributeName)) { - if ((context.parsingOptions & SKIP_FRAMES) == 0) { - stackMapFrameOffset = currentOffset + 2; - stackMapTableEndOffset = currentOffset + attributeLength; - } - // Here we do not extract the labels corresponding to the attribute content. This would - // require a full parsing of the attribute, which would need to be repeated when parsing - // the bytecode instructions (see below). Instead, the content of the attribute is read one - // frame at a time (i.e. after a frame has been visited, the next frame is read), and the - // labels it contains are also extracted one frame at a time. Thanks to the ordering of - // frames, having only a "one frame lookahead" is not a problem, i.e. it is not possible to - // see an offset smaller than the offset of the current instruction and for which no Label - // exist. Except for UNINITIALIZED type offsets. We solve this by parsing the stack map - // table without a full decoding (see below). - } else if ("StackMap".equals(attributeName)) { - if ((context.parsingOptions & SKIP_FRAMES) == 0) { - stackMapFrameOffset = currentOffset + 2; - stackMapTableEndOffset = currentOffset + attributeLength; - compressedFrames = false; - } - // IMPORTANT! Here we assume that the frames are ordered, as in the StackMapTable attribute, - // although this is not guaranteed by the attribute format. This allows an incremental - // extraction of the labels corresponding to this attribute (see the comment above for the - // StackMapTable attribute). - } else { - Attribute attribute = - readAttribute( - context.attributePrototypes, - attributeName, - currentOffset, - attributeLength, - charBuffer, - codeOffset, - labels); - attribute.nextAttribute = attributes; - attributes = attribute; - } - currentOffset += attributeLength; - } - - // Initialize the context fields related to stack map frames, and generate the first - // (implicit) stack map frame, if needed. - final boolean expandFrames = (context.parsingOptions & EXPAND_FRAMES) != 0; - if (stackMapFrameOffset != 0) { - // The bytecode offset of the first explicit frame is not offset_delta + 1 but only - // offset_delta. Setting the implicit frame offset to -1 allows us to use of the - // "offset_delta + 1" rule in all cases. - context.currentFrameOffset = -1; - context.currentFrameType = 0; - context.currentFrameLocalCount = 0; - context.currentFrameLocalCountDelta = 0; - context.currentFrameLocalTypes = new Object[maxLocals]; - context.currentFrameStackCount = 0; - context.currentFrameStackTypes = new Object[maxStack]; - if (expandFrames) { - computeImplicitFrame(context); - } - // Find the labels for UNINITIALIZED frame types. Instead of decoding each element of the - // stack map table, we look for 3 consecutive bytes that "look like" an UNINITIALIZED type - // (tag ITEM_Uninitialized, offset within bytecode bounds, NEW instruction at this offset). - // We may find false positives (i.e. not real UNINITIALIZED types), but this should be rare, - // and the only consequence will be the creation of an unneeded label. This is better than - // creating a label for each NEW instruction, and faster than fully decoding the whole stack - // map table. - for (int offset = stackMapFrameOffset; offset < stackMapTableEndOffset - 2; ++offset) { - if (classFileBuffer[offset] == Frame.ITEM_UNINITIALIZED) { - int potentialBytecodeOffset = readUnsignedShort(offset + 1); - if (potentialBytecodeOffset >= 0 - && potentialBytecodeOffset < codeLength - && (classFileBuffer[bytecodeStartOffset + potentialBytecodeOffset] & 0xFF) - == Opcodes.NEW) { - createLabel(potentialBytecodeOffset, labels); - } - } - } - } - if (expandFrames && (context.parsingOptions & EXPAND_ASM_INSNS) != 0) { - // Expanding the ASM specific instructions can introduce F_INSERT frames, even if the method - // does not currently have any frame. These inserted frames must be computed by simulating the - // effect of the bytecode instructions, one by one, starting from the implicit first frame. - // For this, MethodWriter needs to know maxLocals before the first instruction is visited. To - // ensure this, we visit the implicit first frame here (passing only maxLocals - the rest is - // computed in MethodWriter). - methodVisitor.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null); - } - - // Visit the bytecode instructions. First, introduce state variables for the incremental parsing - // of the type annotations. - - // Index of the next runtime visible type annotation to read (in the - // visibleTypeAnnotationOffsets array). - int currentVisibleTypeAnnotationIndex = 0; - // The bytecode offset of the next runtime visible type annotation to read, or -1. - int currentVisibleTypeAnnotationBytecodeOffset = - getTypeAnnotationBytecodeOffset(visibleTypeAnnotationOffsets, 0); - // Index of the next runtime invisible type annotation to read (in the - // invisibleTypeAnnotationOffsets array). - int currentInvisibleTypeAnnotationIndex = 0; - // The bytecode offset of the next runtime invisible type annotation to read, or -1. - int currentInvisibleTypeAnnotationBytecodeOffset = - getTypeAnnotationBytecodeOffset(invisibleTypeAnnotationOffsets, 0); - - // Whether a F_INSERT stack map frame must be inserted before the current instruction. - boolean insertFrame = false; - - // The delta to subtract from a goto_w or jsr_w opcode to get the corresponding goto or jsr - // opcode, or 0 if goto_w and jsr_w must be left unchanged (i.e. when expanding ASM specific - // instructions). - final int wideJumpOpcodeDelta = - (context.parsingOptions & EXPAND_ASM_INSNS) == 0 ? Constants.WIDE_JUMP_OPCODE_DELTA : 0; - - currentOffset = bytecodeStartOffset; - while (currentOffset < bytecodeEndOffset) { - final int currentBytecodeOffset = currentOffset - bytecodeStartOffset; - - // Visit the label and the line number(s) for this bytecode offset, if any. - Label currentLabel = labels[currentBytecodeOffset]; - if (currentLabel != null) { - currentLabel.accept(methodVisitor, (context.parsingOptions & SKIP_DEBUG) == 0); - } - - // Visit the stack map frame for this bytecode offset, if any. - while (stackMapFrameOffset != 0 - && (context.currentFrameOffset == currentBytecodeOffset - || context.currentFrameOffset == -1)) { - // If there is a stack map frame for this offset, make methodVisitor visit it, and read the - // next stack map frame if there is one. - if (context.currentFrameOffset != -1) { - if (!compressedFrames || expandFrames) { - methodVisitor.visitFrame( - Opcodes.F_NEW, - context.currentFrameLocalCount, - context.currentFrameLocalTypes, - context.currentFrameStackCount, - context.currentFrameStackTypes); - } else { - methodVisitor.visitFrame( - context.currentFrameType, - context.currentFrameLocalCountDelta, - context.currentFrameLocalTypes, - context.currentFrameStackCount, - context.currentFrameStackTypes); - } - // Since there is already a stack map frame for this bytecode offset, there is no need to - // insert a new one. - insertFrame = false; - } - if (stackMapFrameOffset < stackMapTableEndOffset) { - stackMapFrameOffset = - readStackMapFrame(stackMapFrameOffset, compressedFrames, expandFrames, context); - } else { - stackMapFrameOffset = 0; - } - } - - // Insert a stack map frame for this bytecode offset, if requested by setting insertFrame to - // true during the previous iteration. The actual frame content is computed in MethodWriter. - if (insertFrame) { - if ((context.parsingOptions & EXPAND_FRAMES) != 0) { - methodVisitor.visitFrame(Constants.F_INSERT, 0, null, 0, null); - } - insertFrame = false; - } - - // Visit the instruction at this bytecode offset. - int opcode = classFileBuffer[currentOffset] & 0xFF; - switch (opcode) { - case Constants.NOP: - case Constants.ACONST_NULL: - case Constants.ICONST_M1: - case Constants.ICONST_0: - case Constants.ICONST_1: - case Constants.ICONST_2: - case Constants.ICONST_3: - case Constants.ICONST_4: - case Constants.ICONST_5: - case Constants.LCONST_0: - case Constants.LCONST_1: - case Constants.FCONST_0: - case Constants.FCONST_1: - case Constants.FCONST_2: - case Constants.DCONST_0: - case Constants.DCONST_1: - case Constants.IALOAD: - case Constants.LALOAD: - case Constants.FALOAD: - case Constants.DALOAD: - case Constants.AALOAD: - case Constants.BALOAD: - case Constants.CALOAD: - case Constants.SALOAD: - case Constants.IASTORE: - case Constants.LASTORE: - case Constants.FASTORE: - case Constants.DASTORE: - case Constants.AASTORE: - case Constants.BASTORE: - case Constants.CASTORE: - case Constants.SASTORE: - case Constants.POP: - case Constants.POP2: - case Constants.DUP: - case Constants.DUP_X1: - case Constants.DUP_X2: - case Constants.DUP2: - case Constants.DUP2_X1: - case Constants.DUP2_X2: - case Constants.SWAP: - case Constants.IADD: - case Constants.LADD: - case Constants.FADD: - case Constants.DADD: - case Constants.ISUB: - case Constants.LSUB: - case Constants.FSUB: - case Constants.DSUB: - case Constants.IMUL: - case Constants.LMUL: - case Constants.FMUL: - case Constants.DMUL: - case Constants.IDIV: - case Constants.LDIV: - case Constants.FDIV: - case Constants.DDIV: - case Constants.IREM: - case Constants.LREM: - case Constants.FREM: - case Constants.DREM: - case Constants.INEG: - case Constants.LNEG: - case Constants.FNEG: - case Constants.DNEG: - case Constants.ISHL: - case Constants.LSHL: - case Constants.ISHR: - case Constants.LSHR: - case Constants.IUSHR: - case Constants.LUSHR: - case Constants.IAND: - case Constants.LAND: - case Constants.IOR: - case Constants.LOR: - case Constants.IXOR: - case Constants.LXOR: - case Constants.I2L: - case Constants.I2F: - case Constants.I2D: - case Constants.L2I: - case Constants.L2F: - case Constants.L2D: - case Constants.F2I: - case Constants.F2L: - case Constants.F2D: - case Constants.D2I: - case Constants.D2L: - case Constants.D2F: - case Constants.I2B: - case Constants.I2C: - case Constants.I2S: - case Constants.LCMP: - case Constants.FCMPL: - case Constants.FCMPG: - case Constants.DCMPL: - case Constants.DCMPG: - case Constants.IRETURN: - case Constants.LRETURN: - case Constants.FRETURN: - case Constants.DRETURN: - case Constants.ARETURN: - case Constants.RETURN: - case Constants.ARRAYLENGTH: - case Constants.ATHROW: - case Constants.MONITORENTER: - case Constants.MONITOREXIT: - methodVisitor.visitInsn(opcode); - currentOffset += 1; - break; - case Constants.ILOAD_0: - case Constants.ILOAD_1: - case Constants.ILOAD_2: - case Constants.ILOAD_3: - case Constants.LLOAD_0: - case Constants.LLOAD_1: - case Constants.LLOAD_2: - case Constants.LLOAD_3: - case Constants.FLOAD_0: - case Constants.FLOAD_1: - case Constants.FLOAD_2: - case Constants.FLOAD_3: - case Constants.DLOAD_0: - case Constants.DLOAD_1: - case Constants.DLOAD_2: - case Constants.DLOAD_3: - case Constants.ALOAD_0: - case Constants.ALOAD_1: - case Constants.ALOAD_2: - case Constants.ALOAD_3: - opcode -= Constants.ILOAD_0; - methodVisitor.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); - currentOffset += 1; - break; - case Constants.ISTORE_0: - case Constants.ISTORE_1: - case Constants.ISTORE_2: - case Constants.ISTORE_3: - case Constants.LSTORE_0: - case Constants.LSTORE_1: - case Constants.LSTORE_2: - case Constants.LSTORE_3: - case Constants.FSTORE_0: - case Constants.FSTORE_1: - case Constants.FSTORE_2: - case Constants.FSTORE_3: - case Constants.DSTORE_0: - case Constants.DSTORE_1: - case Constants.DSTORE_2: - case Constants.DSTORE_3: - case Constants.ASTORE_0: - case Constants.ASTORE_1: - case Constants.ASTORE_2: - case Constants.ASTORE_3: - opcode -= Constants.ISTORE_0; - methodVisitor.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3); - currentOffset += 1; - break; - case Constants.IFEQ: - case Constants.IFNE: - case Constants.IFLT: - case Constants.IFGE: - case Constants.IFGT: - case Constants.IFLE: - case Constants.IF_ICMPEQ: - case Constants.IF_ICMPNE: - case Constants.IF_ICMPLT: - case Constants.IF_ICMPGE: - case Constants.IF_ICMPGT: - case Constants.IF_ICMPLE: - case Constants.IF_ACMPEQ: - case Constants.IF_ACMPNE: - case Constants.GOTO: - case Constants.JSR: - case Constants.IFNULL: - case Constants.IFNONNULL: - methodVisitor.visitJumpInsn( - opcode, labels[currentBytecodeOffset + readShort(currentOffset + 1)]); - currentOffset += 3; - break; - case Constants.GOTO_W: - case Constants.JSR_W: - methodVisitor.visitJumpInsn( - opcode - wideJumpOpcodeDelta, - labels[currentBytecodeOffset + readInt(currentOffset + 1)]); - currentOffset += 5; - break; - case Constants.ASM_IFEQ: - case Constants.ASM_IFNE: - case Constants.ASM_IFLT: - case Constants.ASM_IFGE: - case Constants.ASM_IFGT: - case Constants.ASM_IFLE: - case Constants.ASM_IF_ICMPEQ: - case Constants.ASM_IF_ICMPNE: - case Constants.ASM_IF_ICMPLT: - case Constants.ASM_IF_ICMPGE: - case Constants.ASM_IF_ICMPGT: - case Constants.ASM_IF_ICMPLE: - case Constants.ASM_IF_ACMPEQ: - case Constants.ASM_IF_ACMPNE: - case Constants.ASM_GOTO: - case Constants.ASM_JSR: - case Constants.ASM_IFNULL: - case Constants.ASM_IFNONNULL: { - // A forward jump with an offset > 32767. In this case we automatically replace ASM_GOTO - // with GOTO_W, ASM_JSR with JSR_W and ASM_IFxxx with IFNOTxxx GOTO_W L:..., - // where IFNOTxxx is the "opposite" opcode of ASMS_IFxxx (e.g. IFNE for ASM_IFEQ) and - // where designates the instruction just after the GOTO_W. - // First, change the ASM specific opcodes ASM_IFEQ ... ASM_JSR, ASM_IFNULL and - // ASM_IFNONNULL to IFEQ ... JSR, IFNULL and IFNONNULL. - opcode = - opcode < Constants.ASM_IFNULL - ? opcode - Constants.ASM_OPCODE_DELTA - : opcode - Constants.ASM_IFNULL_OPCODE_DELTA; - Label target = labels[currentBytecodeOffset + readUnsignedShort(currentOffset + 1)]; - if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { - // Replace GOTO with GOTO_W and JSR with JSR_W. - methodVisitor.visitJumpInsn(opcode + Constants.WIDE_JUMP_OPCODE_DELTA, target); - } else { - // Compute the "opposite" of opcode. This can be done by flipping the least - // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ - // (with a pre and post offset by 1). - opcode = opcode < Opcodes.GOTO ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1; - Label endif = createLabel(currentBytecodeOffset + 3, labels); - methodVisitor.visitJumpInsn(opcode, endif); - methodVisitor.visitJumpInsn(Constants.GOTO_W, target); - // endif designates the instruction just after GOTO_W, and is visited as part of the - // next instruction. Since it is a jump target, we need to insert a frame here. - insertFrame = true; - } - currentOffset += 3; - break; - } - case Constants.ASM_GOTO_W: { - // Replace ASM_GOTO_W with GOTO_W. - methodVisitor.visitJumpInsn( - Constants.GOTO_W, labels[currentBytecodeOffset + readInt(currentOffset + 1)]); - // The instruction just after is a jump target (because ASM_GOTO_W is used in patterns - // IFNOTxxx ASM_GOTO_W L:..., see MethodWriter), so we need to insert a frame - // here. - insertFrame = true; - currentOffset += 5; - break; - } - case Constants.WIDE: - opcode = classFileBuffer[currentOffset + 1] & 0xFF; - if (opcode == Opcodes.IINC) { - methodVisitor.visitIincInsn( - readUnsignedShort(currentOffset + 2), readShort(currentOffset + 4)); - currentOffset += 6; - } else { - methodVisitor.visitVarInsn(opcode, readUnsignedShort(currentOffset + 2)); - currentOffset += 4; - } - break; - case Constants.TABLESWITCH: { - // Skip 0 to 3 padding bytes. - currentOffset += 4 - (currentBytecodeOffset & 3); - // Read the instruction. - Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)]; - int low = readInt(currentOffset + 4); - int high = readInt(currentOffset + 8); - currentOffset += 12; - Label[] table = new Label[high - low + 1]; - for (int i = 0; i < table.length; ++i) { - table[i] = labels[currentBytecodeOffset + readInt(currentOffset)]; - currentOffset += 4; - } - methodVisitor.visitTableSwitchInsn(low, high, defaultLabel, table); - break; - } - case Constants.LOOKUPSWITCH: { - // Skip 0 to 3 padding bytes. - currentOffset += 4 - (currentBytecodeOffset & 3); - // Read the instruction. - Label defaultLabel = labels[currentBytecodeOffset + readInt(currentOffset)]; - int nPairs = readInt(currentOffset + 4); - currentOffset += 8; - int[] keys = new int[nPairs]; - Label[] values = new Label[nPairs]; - for (int i = 0; i < nPairs; ++i) { - keys[i] = readInt(currentOffset); - values[i] = labels[currentBytecodeOffset + readInt(currentOffset + 4)]; - currentOffset += 8; - } - methodVisitor.visitLookupSwitchInsn(defaultLabel, keys, values); - break; - } - case Constants.ILOAD: - case Constants.LLOAD: - case Constants.FLOAD: - case Constants.DLOAD: - case Constants.ALOAD: - case Constants.ISTORE: - case Constants.LSTORE: - case Constants.FSTORE: - case Constants.DSTORE: - case Constants.ASTORE: - case Constants.RET: - methodVisitor.visitVarInsn(opcode, classFileBuffer[currentOffset + 1] & 0xFF); - currentOffset += 2; - break; - case Constants.BIPUSH: - case Constants.NEWARRAY: - methodVisitor.visitIntInsn(opcode, classFileBuffer[currentOffset + 1]); - currentOffset += 2; - break; - case Constants.SIPUSH: - methodVisitor.visitIntInsn(opcode, readShort(currentOffset + 1)); - currentOffset += 3; - break; - case Constants.LDC: - methodVisitor.visitLdcInsn( - readConst(classFileBuffer[currentOffset + 1] & 0xFF, charBuffer)); - currentOffset += 2; - break; - case Constants.LDC_W: - case Constants.LDC2_W: - methodVisitor.visitLdcInsn(readConst(readUnsignedShort(currentOffset + 1), charBuffer)); - currentOffset += 3; - break; - case Constants.GETSTATIC: - case Constants.PUTSTATIC: - case Constants.GETFIELD: - case Constants.PUTFIELD: - case Constants.INVOKEVIRTUAL: - case Constants.INVOKESPECIAL: - case Constants.INVOKESTATIC: - case Constants.INVOKEINTERFACE: { - int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)]; - int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; - String owner = readClass(cpInfoOffset, charBuffer); - String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); - String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); - if (opcode < Opcodes.INVOKEVIRTUAL) { - methodVisitor.visitFieldInsn(opcode, owner, name, descriptor); - } else { - boolean isInterface = - classFileBuffer[cpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG; - methodVisitor.visitMethodInsn(opcode, owner, name, descriptor, isInterface); - } - if (opcode == Opcodes.INVOKEINTERFACE) { - currentOffset += 5; - } else { - currentOffset += 3; - } - break; - } - case Constants.INVOKEDYNAMIC: { - int cpInfoOffset = cpInfoOffsets[readUnsignedShort(currentOffset + 1)]; - int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)]; - String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); - String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); - int bootstrapMethodOffset = - context.bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)]; - Handle handle = - (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); - Object[] boostrapMethodArguments = - new Object[readUnsignedShort(bootstrapMethodOffset + 2)]; - bootstrapMethodOffset += 4; - for (int i = 0; i < boostrapMethodArguments.length; i++) { - boostrapMethodArguments[i] = - readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer); - bootstrapMethodOffset += 2; - } - methodVisitor.visitInvokeDynamicInsn(name, descriptor, handle, boostrapMethodArguments); - currentOffset += 5; - break; - } - case Constants.NEW: - case Constants.ANEWARRAY: - case Constants.CHECKCAST: - case Constants.INSTANCEOF: - methodVisitor.visitTypeInsn(opcode, readClass(currentOffset + 1, charBuffer)); - currentOffset += 3; - break; - case Constants.IINC: - methodVisitor.visitIincInsn( - classFileBuffer[currentOffset + 1] & 0xFF, classFileBuffer[currentOffset + 2]); - currentOffset += 3; - break; - case Constants.MULTIANEWARRAY: - methodVisitor.visitMultiANewArrayInsn( - readClass(currentOffset + 1, charBuffer), classFileBuffer[currentOffset + 3] & 0xFF); - currentOffset += 4; - break; - default: - throw new AssertionError(); - } - - // Visit the runtime visible instruction annotations, if any. - while (visibleTypeAnnotationOffsets != null - && currentVisibleTypeAnnotationIndex < visibleTypeAnnotationOffsets.length - && currentVisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) { - if (currentVisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) { - // Parse the target_type, target_info and target_path fields. - int currentAnnotationOffset = - readTypeAnnotationTarget( - context, visibleTypeAnnotationOffsets[currentVisibleTypeAnnotationIndex]); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - readElementValues( - methodVisitor.visitInsnAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ true), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - currentVisibleTypeAnnotationBytecodeOffset = - getTypeAnnotationBytecodeOffset( - visibleTypeAnnotationOffsets, ++currentVisibleTypeAnnotationIndex); - } - - // Visit the runtime invisible instruction annotations, if any. - while (invisibleTypeAnnotationOffsets != null - && currentInvisibleTypeAnnotationIndex < invisibleTypeAnnotationOffsets.length - && currentInvisibleTypeAnnotationBytecodeOffset <= currentBytecodeOffset) { - if (currentInvisibleTypeAnnotationBytecodeOffset == currentBytecodeOffset) { - // Parse the target_type, target_info and target_path fields. - int currentAnnotationOffset = - readTypeAnnotationTarget( - context, invisibleTypeAnnotationOffsets[currentInvisibleTypeAnnotationIndex]); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer); - currentAnnotationOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - readElementValues( - methodVisitor.visitInsnAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - annotationDescriptor, - /* visible = */ false), - currentAnnotationOffset, - /* named = */ true, - charBuffer); - } - currentInvisibleTypeAnnotationBytecodeOffset = - getTypeAnnotationBytecodeOffset( - invisibleTypeAnnotationOffsets, ++currentInvisibleTypeAnnotationIndex); - } - } - if (labels[codeLength] != null) { - methodVisitor.visitLabel(labels[codeLength]); - } - - // Visit LocalVariableTable and LocalVariableTypeTable attributes. - if (localVariableTableOffset != 0 && (context.parsingOptions & SKIP_DEBUG) == 0) { - // The (start_pc, index, signature_index) fields of each entry of the LocalVariableTypeTable. - int[] typeTable = null; - if (localVariableTypeTableOffset != 0) { - typeTable = new int[readUnsignedShort(localVariableTypeTableOffset) * 3]; - currentOffset = localVariableTypeTableOffset + 2; - int typeTableIndex = typeTable.length; - while (typeTableIndex > 0) { - // Store the offset of 'signature_index', and the value of 'index' and 'start_pc'. - typeTable[--typeTableIndex] = currentOffset + 6; - typeTable[--typeTableIndex] = readUnsignedShort(currentOffset + 8); - typeTable[--typeTableIndex] = readUnsignedShort(currentOffset); - currentOffset += 10; - } - } - int localVariableTableLength = readUnsignedShort(localVariableTableOffset); - currentOffset = localVariableTableOffset + 2; - while (localVariableTableLength-- > 0) { - int startPc = readUnsignedShort(currentOffset); - int length = readUnsignedShort(currentOffset + 2); - String name = readUTF8(currentOffset + 4, charBuffer); - String descriptor = readUTF8(currentOffset + 6, charBuffer); - int index = readUnsignedShort(currentOffset + 8); - currentOffset += 10; - String signature = null; - if (typeTable != null) { - for (int i = 0; i < typeTable.length; i += 3) { - if (typeTable[i] == startPc && typeTable[i + 1] == index) { - signature = readUTF8(typeTable[i + 2], charBuffer); - break; - } - } - } - methodVisitor.visitLocalVariable( - name, descriptor, signature, labels[startPc], labels[startPc + length], index); - } - } - - // Visit the local variable type annotations of the RuntimeVisibleTypeAnnotations attribute. - if (visibleTypeAnnotationOffsets != null) { - for (int i = 0; i < visibleTypeAnnotationOffsets.length; ++i) { - int targetType = readByte(visibleTypeAnnotationOffsets[i]); - if (targetType == TypeReference.LOCAL_VARIABLE - || targetType == TypeReference.RESOURCE_VARIABLE) { - // Parse the target_type, target_info and target_path fields. - currentOffset = readTypeAnnotationTarget(context, visibleTypeAnnotationOffsets[i]); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentOffset, charBuffer); - currentOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - readElementValues( - methodVisitor.visitLocalVariableAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - context.currentLocalVariableAnnotationRangeStarts, - context.currentLocalVariableAnnotationRangeEnds, - context.currentLocalVariableAnnotationRangeIndices, - annotationDescriptor, - /* visible = */ true), - currentOffset, - /* named = */ true, - charBuffer); - } - } - } - - // Visit the local variable type annotations of the RuntimeInvisibleTypeAnnotations attribute. - if (invisibleTypeAnnotationOffsets != null) { - for (int i = 0; i < invisibleTypeAnnotationOffsets.length; ++i) { - int targetType = readByte(invisibleTypeAnnotationOffsets[i]); - if (targetType == TypeReference.LOCAL_VARIABLE - || targetType == TypeReference.RESOURCE_VARIABLE) { - // Parse the target_type, target_info and target_path fields. - currentOffset = readTypeAnnotationTarget(context, invisibleTypeAnnotationOffsets[i]); - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentOffset, charBuffer); - currentOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - readElementValues( - methodVisitor.visitLocalVariableAnnotation( - context.currentTypeAnnotationTarget, - context.currentTypeAnnotationTargetPath, - context.currentLocalVariableAnnotationRangeStarts, - context.currentLocalVariableAnnotationRangeEnds, - context.currentLocalVariableAnnotationRangeIndices, - annotationDescriptor, - /* visible = */ false), - currentOffset, - /* named = */ true, - charBuffer); - } - } - } - - // Visit the non standard attributes. - while (attributes != null) { - // Copy and reset the nextAttribute field so that it can also be used in MethodWriter. - Attribute nextAttribute = attributes.nextAttribute; - attributes.nextAttribute = null; - methodVisitor.visitAttribute(attributes); - attributes = nextAttribute; - } - - // Visit the max stack and max locals values. - methodVisitor.visitMaxs(maxStack, maxLocals); - } - - /** - * Returns the label corresponding to the given bytecode offset. The default implementation of - * this method creates a label for the given offset if it has not been already created. - * - * @param bytecodeOffset a bytecode offset in a method. - * @param labels the already created labels, indexed by their offset. If a label already exists - * for bytecodeOffset this method must not create a new one. Otherwise it must store the new - * label in this array. - * @return a non null Label, which must be equal to labels[bytecodeOffset]. - */ - protected Label readLabel(final int bytecodeOffset, final Label[] labels) { - if (labels[bytecodeOffset] == null) { - labels[bytecodeOffset] = new Label(); - } - return labels[bytecodeOffset]; - } - - /** - * Creates a label without the {@link Label#FLAG_DEBUG_ONLY} flag set, for the given bytecode - * offset. The label is created with a call to {@link #readLabel} and its {@link - * Label#FLAG_DEBUG_ONLY} flag is cleared. - * - * @param bytecodeOffset a bytecode offset in a method. - * @param labels the already created labels, indexed by their offset. - * @return a Label without the {@link Label#FLAG_DEBUG_ONLY} flag set. - */ - private Label createLabel(final int bytecodeOffset, final Label[] labels) { - Label label = readLabel(bytecodeOffset, labels); - label.flags &= ~Label.FLAG_DEBUG_ONLY; - return label; - } - - /** - * Creates a label with the {@link Label#FLAG_DEBUG_ONLY} flag set, if there is no already - * existing label for the given bytecode offset (otherwise does nothing). The label is created - * with a call to {@link #readLabel}. - * - * @param bytecodeOffset a bytecode offset in a method. - * @param labels the already created labels, indexed by their offset. - */ - private void createDebugLabel(final int bytecodeOffset, final Label[] labels) { - if (labels[bytecodeOffset] == null) { - readLabel(bytecodeOffset, labels).flags |= Label.FLAG_DEBUG_ONLY; - } - } - - // ---------------------------------------------------------------------------------------------- - // Methods to parse annotations, type annotations and parameter annotations - // ---------------------------------------------------------------------------------------------- - - /** - * Parses a Runtime[In]VisibleTypeAnnotations attribute to find the offset of each type_annotation - * entry it contains, to find the corresponding labels, and to visit the try catch block - * annotations. - * - * @param methodVisitor the method visitor to be used to visit the try catch block annotations. - * @param context information about the class being parsed. - * @param runtimeTypeAnnotationsOffset the start offset of a Runtime[In]VisibleTypeAnnotations - * attribute, excluding the attribute_info's attribute_name_index and attribute_length fields. - * @param visible true if the attribute to parse is a RuntimeVisibleTypeAnnotations attribute, - * false it is a RuntimeInvisibleTypeAnnotations attribute. - * @return the start offset of each entry of the Runtime[In]VisibleTypeAnnotations_attribute's - * 'annotations' array field. - */ - private int[] readTypeAnnotations( - final MethodVisitor methodVisitor, - final Context context, - final int runtimeTypeAnnotationsOffset, - final boolean visible) { - char[] charBuffer = context.charBuffer; - int currentOffset = runtimeTypeAnnotationsOffset; - // Read the num_annotations field and create an array to store the type_annotation offsets. - int[] typeAnnotationsOffsets = new int[readUnsignedShort(currentOffset)]; - currentOffset += 2; - // Parse the 'annotations' array field. - for (int i = 0; i < typeAnnotationsOffsets.length; ++i) { - typeAnnotationsOffsets[i] = currentOffset; - // Parse the type_annotation's target_type and the target_info fields. The size of the - // target_info field depends on the value of target_type. - int targetType = readInt(currentOffset); - switch (targetType >>> 24) { - case TypeReference.LOCAL_VARIABLE: - case TypeReference.RESOURCE_VARIABLE: - // A localvar_target has a variable size, which depends on the value of their table_length - // field. It also references bytecode offsets, for which we need labels. - int tableLength = readUnsignedShort(currentOffset + 1); - currentOffset += 3; - while (tableLength-- > 0) { - int startPc = readUnsignedShort(currentOffset); - int length = readUnsignedShort(currentOffset + 2); - // Skip the index field (2 bytes). - currentOffset += 6; - createLabel(startPc, context.currentMethodLabels); - createLabel(startPc + length, context.currentMethodLabels); - } - break; - case TypeReference.CAST: - case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: - case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: - case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: - case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: - currentOffset += 4; - break; - case TypeReference.CLASS_EXTENDS: - case TypeReference.CLASS_TYPE_PARAMETER_BOUND: - case TypeReference.METHOD_TYPE_PARAMETER_BOUND: - case TypeReference.THROWS: - case TypeReference.EXCEPTION_PARAMETER: - case TypeReference.INSTANCEOF: - case TypeReference.NEW: - case TypeReference.CONSTRUCTOR_REFERENCE: - case TypeReference.METHOD_REFERENCE: - currentOffset += 3; - break; - case TypeReference.CLASS_TYPE_PARAMETER: - case TypeReference.METHOD_TYPE_PARAMETER: - case TypeReference.METHOD_FORMAL_PARAMETER: - case TypeReference.FIELD: - case TypeReference.METHOD_RETURN: - case TypeReference.METHOD_RECEIVER: - default: - // TypeReference type which can't be used in Code attribute, or which is unknown. - throw new IllegalArgumentException(); - } - // Parse the rest of the type_annotation structure, starting with the target_path structure - // (whose size depends on its path_length field). - int pathLength = readByte(currentOffset); - if ((targetType >>> 24) == TypeReference.EXCEPTION_PARAMETER) { - // Parse the target_path structure and create a corresponding TypePath. - TypePath path = pathLength == 0 ? null : new TypePath(b, currentOffset); - currentOffset += 1 + 2 * pathLength; - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentOffset, charBuffer); - currentOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentOffset = - readElementValues( - methodVisitor.visitTryCatchAnnotation( - targetType & 0xFFFFFF00, path, annotationDescriptor, visible), - currentOffset, - /* named = */ true, - charBuffer); - } else { - // We don't want to visit the other target_type annotations, so we just skip them (which - // requires some parsing because the element_value_pairs array has a variable size). First, - // skip the target_path structure: - currentOffset += 3 + 2 * pathLength; - // Then skip the num_element_value_pairs and element_value_pairs fields (by reading them - // with a null AnnotationVisitor). - currentOffset = - readElementValues( - /* annotationVisitor = */ null, currentOffset, /* named = */ true, charBuffer); - } - } - return typeAnnotationsOffsets; - } - - /** - * Returns the bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or - * -1 if there is no such type_annotation of if it does not have a bytecode offset. - * - * @param typeAnnotationOffsets the offset of each 'type_annotation' entry in a - * Runtime[In]VisibleTypeAnnotations attribute, or null. - * @param typeAnnotationIndex the index a 'type_annotation' entry in typeAnnotationOffsets. - * @return bytecode offset corresponding to the specified JVMS 'type_annotation' structure, or -1 - * if there is no such type_annotation of if it does not have a bytecode offset. - */ - private int getTypeAnnotationBytecodeOffset( - final int[] typeAnnotationOffsets, final int typeAnnotationIndex) { - if (typeAnnotationOffsets == null - || typeAnnotationIndex >= typeAnnotationOffsets.length - || readByte(typeAnnotationOffsets[typeAnnotationIndex]) < TypeReference.INSTANCEOF) { - return -1; - } - return readUnsignedShort(typeAnnotationOffsets[typeAnnotationIndex] + 1); - } - - /** - * Parses the header of a JVMS type_annotation structure to extract its target_type, target_info - * and target_path (the result is stored in the given context), and returns the start offset of - * the rest of the type_annotation structure. - * - * @param context information about the class being parsed. This is where the extracted - * target_type and target_path must be stored. - * @param typeAnnotationOffset the start offset of a type_annotation structure. - * @return the start offset of the rest of the type_annotation structure. - */ - private int readTypeAnnotationTarget(final Context context, final int typeAnnotationOffset) { - int currentOffset = typeAnnotationOffset; - // Parse and store the target_type structure. - int targetType = readInt(typeAnnotationOffset); - switch (targetType >>> 24) { - case TypeReference.CLASS_TYPE_PARAMETER: - case TypeReference.METHOD_TYPE_PARAMETER: - case TypeReference.METHOD_FORMAL_PARAMETER: - targetType &= 0xFFFF0000; - currentOffset += 2; - break; - case TypeReference.FIELD: - case TypeReference.METHOD_RETURN: - case TypeReference.METHOD_RECEIVER: - targetType &= 0xFF000000; - currentOffset += 1; - break; - case TypeReference.LOCAL_VARIABLE: - case TypeReference.RESOURCE_VARIABLE: - targetType &= 0xFF000000; - int tableLength = readUnsignedShort(currentOffset + 1); - currentOffset += 3; - context.currentLocalVariableAnnotationRangeStarts = new Label[tableLength]; - context.currentLocalVariableAnnotationRangeEnds = new Label[tableLength]; - context.currentLocalVariableAnnotationRangeIndices = new int[tableLength]; - for (int i = 0; i < tableLength; ++i) { - int startPc = readUnsignedShort(currentOffset); - int length = readUnsignedShort(currentOffset + 2); - int index = readUnsignedShort(currentOffset + 4); - currentOffset += 6; - context.currentLocalVariableAnnotationRangeStarts[i] = - createLabel(startPc, context.currentMethodLabels); - context.currentLocalVariableAnnotationRangeEnds[i] = - createLabel(startPc + length, context.currentMethodLabels); - context.currentLocalVariableAnnotationRangeIndices[i] = index; - } - break; - case TypeReference.CAST: - case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: - case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: - case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: - case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: - targetType &= 0xFF0000FF; - currentOffset += 4; - break; - case TypeReference.CLASS_EXTENDS: - case TypeReference.CLASS_TYPE_PARAMETER_BOUND: - case TypeReference.METHOD_TYPE_PARAMETER_BOUND: - case TypeReference.THROWS: - case TypeReference.EXCEPTION_PARAMETER: - targetType &= 0xFFFFFF00; - currentOffset += 3; - break; - case TypeReference.INSTANCEOF: - case TypeReference.NEW: - case TypeReference.CONSTRUCTOR_REFERENCE: - case TypeReference.METHOD_REFERENCE: - targetType &= 0xFF000000; - currentOffset += 3; - break; - default: - throw new IllegalArgumentException(); - } - context.currentTypeAnnotationTarget = targetType; - // Parse and store the target_path structure. - int pathLength = readByte(currentOffset); - context.currentTypeAnnotationTargetPath = - pathLength == 0 ? null : new TypePath(b, currentOffset); - // Return the start offset of the rest of the type_annotation structure. - return currentOffset + 1 + 2 * pathLength; - } - - /** - * Reads a Runtime[In]VisibleParameterAnnotations attribute and makes the given visitor visit it. - * - * @param methodVisitor the visitor that must visit the parameter annotations. - * @param context information about the class being parsed. - * @param runtimeParameterAnnotationsOffset the start offset of a - * Runtime[In]VisibleParameterAnnotations attribute, excluding the attribute_info's - * attribute_name_index and attribute_length fields. - * @param visible true if the attribute to parse is a RuntimeVisibleParameterAnnotations - * attribute, false it is a RuntimeInvisibleParameterAnnotations attribute. - */ - private void readParameterAnnotations( - final MethodVisitor methodVisitor, - final Context context, - final int runtimeParameterAnnotationsOffset, - final boolean visible) { - int currentOffset = runtimeParameterAnnotationsOffset; - int numParameters = b[currentOffset++] & 0xFF; - methodVisitor.visitAnnotableParameterCount(numParameters, visible); - char[] charBuffer = context.charBuffer; - for (int i = 0; i < numParameters; ++i) { - int numAnnotations = readUnsignedShort(currentOffset); - currentOffset += 2; - while (numAnnotations-- > 0) { - // Parse the type_index field. - String annotationDescriptor = readUTF8(currentOffset, charBuffer); - currentOffset += 2; - // Parse num_element_value_pairs and element_value_pairs and visit these values. - currentOffset = - readElementValues( - methodVisitor.visitParameterAnnotation(i, annotationDescriptor, visible), - currentOffset, - /* named = */ true, - charBuffer); - } - } - } - - /** - * Reads the element values of a JVMS 'annotation' structure and makes the given visitor visit - * them. This method can also be used to read the values of the JVMS 'array_value' field of an - * annotation's 'element_value'. - * - * @param annotationVisitor the visitor that must visit the values. - * @param annotationOffset the start offset of an 'annotation' structure (excluding its type_index - * field) or of an 'array_value' structure. - * @param named if the annotation values are named or not. This should be true to parse the values - * of a JVMS 'annotation' structure, and false to parse the JVMS 'array_value' of an - * annotation's element_value. - * @param charBuffer the buffer used to read strings in the constant pool. - * @return the end offset of the JVMS 'annotation' or 'array_value' structure. - */ - private int readElementValues( - final AnnotationVisitor annotationVisitor, - final int annotationOffset, - final boolean named, - final char[] charBuffer) { - int currentOffset = annotationOffset; - // Read the num_element_value_pairs field (or num_values field for an array_value). - int numElementValuePairs = readUnsignedShort(currentOffset); - currentOffset += 2; - if (named) { - // Parse the element_value_pairs array. - while (numElementValuePairs-- > 0) { - String elementName = readUTF8(currentOffset, charBuffer); - currentOffset = - readElementValue(annotationVisitor, currentOffset + 2, elementName, charBuffer); - } - } else { - // Parse the array_value array. - while (numElementValuePairs-- > 0) { - currentOffset = - readElementValue(annotationVisitor, currentOffset, /* named = */ null, charBuffer); - } - } - if (annotationVisitor != null) { - annotationVisitor.visitEnd(); - } - return currentOffset; - } - - /** - * Reads a JVMS 'element_value' structure and makes the given visitor visit it. - * - * @param annotationVisitor the visitor that must visit the element_value structure. - * @param elementValueOffset the start offset in {@link #b} of the element_value structure to be - * read. - * @param elementName the name of the element_value structure to be read, or null. - * @param charBuffer the buffer used to read strings in the constant pool. - * @return the end offset of the JVMS 'element_value' structure. - */ - private int readElementValue( - final AnnotationVisitor annotationVisitor, - final int elementValueOffset, - final String elementName, - final char[] charBuffer) { - int currentOffset = elementValueOffset; - if (annotationVisitor == null) { - switch (b[currentOffset] & 0xFF) { - case 'e': // enum_const_value - return currentOffset + 5; - case '@': // annotation_value - return readElementValues(null, currentOffset + 3, /* named = */ true, charBuffer); - case '[': // array_value - return readElementValues(null, currentOffset + 1, /* named = */ false, charBuffer); - default: - return currentOffset + 3; - } - } - switch (b[currentOffset++] & 0xFF) { - case 'B': // const_value_index, CONSTANT_Integer - annotationVisitor.visit( - elementName, (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); - currentOffset += 2; - break; - case 'C': // const_value_index, CONSTANT_Integer - annotationVisitor.visit( - elementName, (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); - currentOffset += 2; - break; - case 'D': // const_value_index, CONSTANT_Double - case 'F': // const_value_index, CONSTANT_Float - case 'I': // const_value_index, CONSTANT_Integer - case 'J': // const_value_index, CONSTANT_Long - annotationVisitor.visit( - elementName, readConst(readUnsignedShort(currentOffset), charBuffer)); - currentOffset += 2; - break; - case 'S': // const_value_index, CONSTANT_Integer - annotationVisitor.visit( - elementName, (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset)])); - currentOffset += 2; - break; - - case 'Z': // const_value_index, CONSTANT_Integer - annotationVisitor.visit( - elementName, - readInt(cpInfoOffsets[readUnsignedShort(currentOffset)]) == 0 - ? Boolean.FALSE - : Boolean.TRUE); - currentOffset += 2; - break; - case 's': // const_value_index, CONSTANT_Utf8 - annotationVisitor.visit(elementName, readUTF8(currentOffset, charBuffer)); - currentOffset += 2; - break; - case 'e': // enum_const_value - annotationVisitor.visitEnum( - elementName, - readUTF8(currentOffset, charBuffer), - readUTF8(currentOffset + 2, charBuffer)); - currentOffset += 4; - break; - case 'c': // class_info - annotationVisitor.visit(elementName, Type.getType(readUTF8(currentOffset, charBuffer))); - currentOffset += 2; - break; - case '@': // annotation_value - currentOffset = - readElementValues( - annotationVisitor.visitAnnotation(elementName, readUTF8(currentOffset, charBuffer)), - currentOffset + 2, - true, - charBuffer); - break; - case '[': // array_value - int numValues = readUnsignedShort(currentOffset); - currentOffset += 2; - if (numValues == 0) { - return readElementValues( - annotationVisitor.visitArray(elementName), - currentOffset - 2, - /* named = */ false, - charBuffer); - } - switch (b[currentOffset] & 0xFF) { - case 'B': - byte[] byteValues = new byte[numValues]; - for (int i = 0; i < numValues; i++) { - byteValues[i] = (byte) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); - currentOffset += 3; - } - annotationVisitor.visit(elementName, byteValues); - break; - case 'Z': - boolean[] booleanValues = new boolean[numValues]; - for (int i = 0; i < numValues; i++) { - booleanValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]) != 0; - currentOffset += 3; - } - annotationVisitor.visit(elementName, booleanValues); - break; - case 'S': - short[] shortValues = new short[numValues]; - for (int i = 0; i < numValues; i++) { - shortValues[i] = (short) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); - currentOffset += 3; - } - annotationVisitor.visit(elementName, shortValues); - break; - case 'C': - char[] charValues = new char[numValues]; - for (int i = 0; i < numValues; i++) { - charValues[i] = (char) readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); - currentOffset += 3; - } - annotationVisitor.visit(elementName, charValues); - break; - case 'I': - int[] intValues = new int[numValues]; - for (int i = 0; i < numValues; i++) { - intValues[i] = readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); - currentOffset += 3; - } - annotationVisitor.visit(elementName, intValues); - break; - case 'J': - long[] longValues = new long[numValues]; - for (int i = 0; i < numValues; i++) { - longValues[i] = readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)]); - currentOffset += 3; - } - annotationVisitor.visit(elementName, longValues); - break; - case 'F': - float[] floatValues = new float[numValues]; - for (int i = 0; i < numValues; i++) { - floatValues[i] = - Float.intBitsToFloat( - readInt(cpInfoOffsets[readUnsignedShort(currentOffset + 1)])); - currentOffset += 3; - } - annotationVisitor.visit(elementName, floatValues); - break; - case 'D': - double[] doubleValues = new double[numValues]; - for (int i = 0; i < numValues; i++) { - doubleValues[i] = - Double.longBitsToDouble( - readLong(cpInfoOffsets[readUnsignedShort(currentOffset + 1)])); - currentOffset += 3; - } - annotationVisitor.visit(elementName, doubleValues); - break; - default: - currentOffset = - readElementValues( - annotationVisitor.visitArray(elementName), - currentOffset - 2, - /* named = */ false, - charBuffer); - break; - } - break; - default: - throw new IllegalArgumentException(); - } - return currentOffset; - } - - // ---------------------------------------------------------------------------------------------- - // Methods to parse stack map frames - // ---------------------------------------------------------------------------------------------- - - /** - * Computes the implicit frame of the method currently being parsed (as defined in the given - * {@link Context}) and stores it in the given context. - * - * @param context information about the class being parsed. - */ - private void computeImplicitFrame(final Context context) { - String methodDescriptor = context.currentMethodDescriptor; - Object[] locals = context.currentFrameLocalTypes; - int nLocal = 0; - if ((context.currentMethodAccessFlags & Opcodes.ACC_STATIC) == 0) { - if ("".equals(context.currentMethodName)) { - locals[nLocal++] = Opcodes.UNINITIALIZED_THIS; - } else { - locals[nLocal++] = readClass(header + 2, context.charBuffer); - } - } - // Parse the method descriptor, one argument type descriptor at each iteration. Start by - // skipping the first method descriptor character, which is always '('. - int currentMethodDescritorOffset = 1; - while (true) { - int currentArgumentDescriptorStartOffset = currentMethodDescritorOffset; - switch (methodDescriptor.charAt(currentMethodDescritorOffset++)) { - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - locals[nLocal++] = Opcodes.INTEGER; - break; - case 'F': - locals[nLocal++] = Opcodes.FLOAT; - break; - case 'J': - locals[nLocal++] = Opcodes.LONG; - break; - case 'D': - locals[nLocal++] = Opcodes.DOUBLE; - break; - case '[': - while (methodDescriptor.charAt(currentMethodDescritorOffset) == '[') { - ++currentMethodDescritorOffset; - } - if (methodDescriptor.charAt(currentMethodDescritorOffset) == 'L') { - ++currentMethodDescritorOffset; - while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') { - ++currentMethodDescritorOffset; - } - } - locals[nLocal++] = - methodDescriptor.substring( - currentArgumentDescriptorStartOffset, ++currentMethodDescritorOffset); - break; - case 'L': - while (methodDescriptor.charAt(currentMethodDescritorOffset) != ';') { - ++currentMethodDescritorOffset; - } - locals[nLocal++] = - methodDescriptor.substring( - currentArgumentDescriptorStartOffset + 1, currentMethodDescritorOffset++); - break; - default: - context.currentFrameLocalCount = nLocal; - return; - } - } - } - - /** - * Reads a JVMS 'stack_map_frame' structure and stores the result in the given {@link Context} - * object. This method can also be used to read a full_frame structure, excluding its frame_type - * field (this is used to parse the legacy StackMap attributes). - * - * @param stackMapFrameOffset the start offset in {@link #b} of the stack_map_frame_value - * structure to be read, or the start offset of a full_frame structure (excluding its - * frame_type field). - * @param compressed true to read a 'stack_map_frame' structure, false to read a 'full_frame' - * structure without its frame_type field. - * @param expand if the stack map frame must be expanded. See {@link #EXPAND_FRAMES}. - * @param context where the parsed stack map frame must be stored. - * @return the end offset of the JVMS 'stack_map_frame' or 'full_frame' structure. - */ - private int readStackMapFrame( - final int stackMapFrameOffset, - final boolean compressed, - final boolean expand, - final Context context) { - int currentOffset = stackMapFrameOffset; - final char[] charBuffer = context.charBuffer; - final Label[] labels = context.currentMethodLabels; - int frameType; - if (compressed) { - // Read the frame_type field. - frameType = b[currentOffset++] & 0xFF; - } else { - frameType = Frame.FULL_FRAME; - context.currentFrameOffset = -1; - } - int offsetDelta; - context.currentFrameLocalCountDelta = 0; - if (frameType < Frame.SAME_LOCALS_1_STACK_ITEM_FRAME) { - offsetDelta = frameType; - context.currentFrameType = Opcodes.F_SAME; - context.currentFrameStackCount = 0; - } else if (frameType < Frame.RESERVED) { - offsetDelta = frameType - Frame.SAME_LOCALS_1_STACK_ITEM_FRAME; - currentOffset = - readVerificationTypeInfo( - currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels); - context.currentFrameType = Opcodes.F_SAME1; - context.currentFrameStackCount = 1; - } else if (frameType >= Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { - offsetDelta = readUnsignedShort(currentOffset); - currentOffset += 2; - if (frameType == Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { - currentOffset = - readVerificationTypeInfo( - currentOffset, context.currentFrameStackTypes, 0, charBuffer, labels); - context.currentFrameType = Opcodes.F_SAME1; - context.currentFrameStackCount = 1; - } else if (frameType >= Frame.CHOP_FRAME && frameType < Frame.SAME_FRAME_EXTENDED) { - context.currentFrameType = Opcodes.F_CHOP; - context.currentFrameLocalCountDelta = Frame.SAME_FRAME_EXTENDED - frameType; - context.currentFrameLocalCount -= context.currentFrameLocalCountDelta; - context.currentFrameStackCount = 0; - } else if (frameType == Frame.SAME_FRAME_EXTENDED) { - context.currentFrameType = Opcodes.F_SAME; - context.currentFrameStackCount = 0; - } else if (frameType < Frame.FULL_FRAME) { - int local = expand ? context.currentFrameLocalCount : 0; - for (int k = frameType - Frame.SAME_FRAME_EXTENDED; k > 0; k--) { - currentOffset = - readVerificationTypeInfo( - currentOffset, context.currentFrameLocalTypes, local++, charBuffer, labels); - } - context.currentFrameType = Opcodes.F_APPEND; - context.currentFrameLocalCountDelta = frameType - Frame.SAME_FRAME_EXTENDED; - context.currentFrameLocalCount += context.currentFrameLocalCountDelta; - context.currentFrameStackCount = 0; - } else { - final int numberOfLocals = readUnsignedShort(currentOffset); - currentOffset += 2; - context.currentFrameType = Opcodes.F_FULL; - context.currentFrameLocalCountDelta = numberOfLocals; - context.currentFrameLocalCount = numberOfLocals; - for (int local = 0; local < numberOfLocals; ++local) { - currentOffset = - readVerificationTypeInfo( - currentOffset, context.currentFrameLocalTypes, local, charBuffer, labels); - } - final int numberOfStackItems = readUnsignedShort(currentOffset); - currentOffset += 2; - context.currentFrameStackCount = numberOfStackItems; - for (int stack = 0; stack < numberOfStackItems; ++stack) { - currentOffset = - readVerificationTypeInfo( - currentOffset, context.currentFrameStackTypes, stack, charBuffer, labels); - } - } - } else { - throw new IllegalArgumentException(); - } - context.currentFrameOffset += offsetDelta + 1; - createLabel(context.currentFrameOffset, labels); - return currentOffset; - } - - /** - * Reads a JVMS 'verification_type_info' structure and stores it at the given index in the given - * array. - * - * @param verificationTypeInfoOffset the start offset of the 'verification_type_info' structure to - * read. - * @param frame the array where the parsed type must be stored. - * @param index the index in 'frame' where the parsed type must be stored. - * @param charBuffer the buffer used to read strings in the constant pool. - * @param labels the labels of the method currently being parsed, indexed by their offset. If the - * parsed type is an ITEM_Uninitialized, a new label for the corresponding NEW instruction is - * stored in this array if it does not already exist. - * @return the end offset of the JVMS 'verification_type_info' structure. - */ - private int readVerificationTypeInfo( - final int verificationTypeInfoOffset, - final Object[] frame, - final int index, - final char[] charBuffer, - final Label[] labels) { - int currentOffset = verificationTypeInfoOffset; - int tag = b[currentOffset++] & 0xFF; - switch (tag) { - case Frame.ITEM_TOP: - frame[index] = Opcodes.TOP; - break; - case Frame.ITEM_INTEGER: - frame[index] = Opcodes.INTEGER; - break; - case Frame.ITEM_FLOAT: - frame[index] = Opcodes.FLOAT; - break; - case Frame.ITEM_DOUBLE: - frame[index] = Opcodes.DOUBLE; - break; - case Frame.ITEM_LONG: - frame[index] = Opcodes.LONG; - break; - case Frame.ITEM_NULL: - frame[index] = Opcodes.NULL; - break; - case Frame.ITEM_UNINITIALIZED_THIS: - frame[index] = Opcodes.UNINITIALIZED_THIS; - break; - case Frame.ITEM_OBJECT: - frame[index] = readClass(currentOffset, charBuffer); - currentOffset += 2; - break; - case Frame.ITEM_UNINITIALIZED: - frame[index] = createLabel(readUnsignedShort(currentOffset), labels); - currentOffset += 2; - break; - default: - throw new IllegalArgumentException(); - } - return currentOffset; - } - - // ---------------------------------------------------------------------------------------------- - // Methods to parse attributes - // ---------------------------------------------------------------------------------------------- - - /** - * @return the offset in {@link #b} of the first ClassFile's 'attributes' array field entry. - */ - final int getFirstAttributeOffset() { - // Skip the access_flags, this_class, super_class, and interfaces_count fields (using 2 bytes - // each), as well as the interfaces array field (2 bytes per interface). - int currentOffset = header + 8 + readUnsignedShort(header + 6) * 2; - - // Read the fields_count field. - int fieldsCount = readUnsignedShort(currentOffset); - currentOffset += 2; - // Skip the 'fields' array field. - while (fieldsCount-- > 0) { - // Invariant: currentOffset is the offset of a field_info structure. - // Skip the access_flags, name_index and descriptor_index fields (2 bytes each), and read the - // attributes_count field. - int attributesCount = readUnsignedShort(currentOffset + 6); - currentOffset += 8; - // Skip the 'attributes' array field. - while (attributesCount-- > 0) { - // Invariant: currentOffset is the offset of an attribute_info structure. - // Read the attribute_length field (2 bytes after the start of the attribute_info) and skip - // this many bytes, plus 6 for the attribute_name_index and attribute_length fields - // (yielding the total size of the attribute_info structure). - currentOffset += 6 + readInt(currentOffset + 2); - } - } - - // Skip the methods_count and 'methods' fields, using the same method as above. - int methodsCount = readUnsignedShort(currentOffset); - currentOffset += 2; - while (methodsCount-- > 0) { - int attributesCount = readUnsignedShort(currentOffset + 6); - currentOffset += 8; - while (attributesCount-- > 0) { - currentOffset += 6 + readInt(currentOffset + 2); - } - } - - // Skip the ClassFile's attributes_count field. - return currentOffset + 2; - } - - /** - * Reads a non standard JVMS 'attribute' structure in {@link #b}. - * - * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of - * the class. Any attribute whose type is not equal to the type of one the prototypes will not - * be parsed: its byte array value will be passed unchanged to the ClassWriter. - * @param type the type of the attribute. - * @param offset the start offset of the JVMS 'attribute' structure in {@link #b}. The 6 attribute - * header bytes (attribute_name_index and attribute_length) are not taken into account here. - * @param length the length of the attribute's content (excluding the 6 attribute header bytes). - * @param charBuffer the buffer to be used to read strings in the constant pool. - * @param codeAttributeOffset the start offset of the enclosing Code attribute in {@link #b}, or - * -1 if the attribute to be read is not a code attribute. The 6 attribute header bytes - * (attribute_name_index and attribute_length) are not taken into account here. - * @param labels the labels of the method's code, or null if the attribute to be read is - * not a code attribute. - * @return the attribute that has been read. - */ - private Attribute readAttribute( - final Attribute[] attributePrototypes, - final String type, - final int offset, - final int length, - final char[] charBuffer, - final int codeAttributeOffset, - final Label[] labels) { - for (int i = 0; i < attributePrototypes.length; ++i) { - if (attributePrototypes[i].type.equals(type)) { - return attributePrototypes[i].read( - this, offset, length, charBuffer, codeAttributeOffset, labels); - } - } - return new Attribute(type).read(this, offset, length, null, -1, null); - } - - // ----------------------------------------------------------------------------------------------- - // Utility methods: low level parsing - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the number of entries in the class's constant pool table. - * - * @return the number of entries in the class's constant pool table. - */ - public int getItemCount() { - return cpInfoOffsets.length; - } - - /** - * Returns the start offset in {@link #b} of a JVMS 'cp_info' structure (i.e. a constant pool - * entry), plus one. This method is intended for {@link Attribute} sub classes, and is normally - * not needed by class generators or adapters. - * - * @param constantPoolEntryIndex the index a constant pool entry in the class's constant pool - * table. - * @return the start offset in {@link #b} of the corresponding JVMS 'cp_info' structure, plus one. - */ - public int getItem(final int constantPoolEntryIndex) { - return cpInfoOffsets[constantPoolEntryIndex]; - } - - /** - * Returns a conservative estimate of the maximum length of the strings contained in the class's - * constant pool table. - * - * @return a conservative estimate of the maximum length of the strings contained in the class's - * constant pool table. - */ - public int getMaxStringLength() { - return maxStringLength; - } - - /** - * Reads a byte value in {@link #b}. This method is intended for {@link Attribute} sub classes, - * and is normally not needed by class generators or adapters. - * - * @param offset the start offset of the value to be read in {@link #b}. - * @return the read value. - */ - public int readByte(final int offset) { - return b[offset] & 0xFF; - } - - /** - * Reads an unsigned short value in {@link #b}. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start index of the value to be read in {@link #b}. - * @return the read value. - */ - public int readUnsignedShort(final int offset) { - byte[] classFileBuffer = b; - return ((classFileBuffer[offset] & 0xFF) << 8) | (classFileBuffer[offset + 1] & 0xFF); - } - - /** - * Reads a signed short value in {@link #b}. This method is intended for {@link Attribute} sub - * classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of the value to be read in {@link #b}. - * @return the read value. - */ - public short readShort(final int offset) { - byte[] classFileBuffer = b; - return (short) (((classFileBuffer[offset] & 0xFF) << 8) | (classFileBuffer[offset + 1] & 0xFF)); - } - - /** - * Reads a signed int value in {@link #b}. This method is intended for {@link Attribute} sub - * classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of the value to be read in {@link #b}. - * @return the read value. - */ - public int readInt(final int offset) { - byte[] classFileBuffer = b; - return ((classFileBuffer[offset] & 0xFF) << 24) - | ((classFileBuffer[offset + 1] & 0xFF) << 16) - | ((classFileBuffer[offset + 2] & 0xFF) << 8) - | (classFileBuffer[offset + 3] & 0xFF); - } - - /** - * Reads a signed long value in {@link #b}. This method is intended for {@link Attribute} sub - * classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of the value to be read in {@link #b}. - * @return the read value. - */ - public long readLong(final int offset) { - long l1 = readInt(offset); - long l0 = readInt(offset + 4) & 0xFFFFFFFFL; - return (l1 << 32) | l0; - } - - /** - * Reads a CONSTANT_Utf8 constant pool entry in {@link #b}. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the - * index of a CONSTANT_Utf8 entry in the class's constant pool table. - * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified CONSTANT_Utf8 entry. - */ - public String readUTF8(final int offset, final char[] charBuffer) { - int constantPoolEntryIndex = readUnsignedShort(offset); - if (offset == 0 || constantPoolEntryIndex == 0) { - return null; - } - return readUTF(constantPoolEntryIndex, charBuffer); - } - - /** - * Reads a CONSTANT_Utf8 constant pool entry in {@link #b}. - * - * @param constantPoolEntryIndex the index of a CONSTANT_Utf8 entry in the class's constant pool - * table. - * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified CONSTANT_Utf8 entry. - */ - final String readUTF(final int constantPoolEntryIndex, final char[] charBuffer) { - String value = constantUtf8Values[constantPoolEntryIndex]; - if (value != null) { - return value; - } - int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; - return constantUtf8Values[constantPoolEntryIndex] = - readUTF(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer); - } - - /** - * Reads an UTF8 string in {@link #b}. - * - * @param utfOffset the start offset of the UTF8 string to be read. - * @param utfLength the length of the UTF8 string to be read. - * @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified UTF8 string. - */ - private String readUTF(final int utfOffset, final int utfLength, final char[] charBuffer) { - int currentOffset = utfOffset; - int endOffset = currentOffset + utfLength; - int strLength = 0; - byte[] classFileBuffer = b; - while (currentOffset < endOffset) { - int currentByte = classFileBuffer[currentOffset++]; - if ((currentByte & 0x80) == 0) { - charBuffer[strLength++] = (char) (currentByte & 0x7F); - } else if ((currentByte & 0xE0) == 0xC0) { - charBuffer[strLength++] = - (char) (((currentByte & 0x1F) << 6) + (classFileBuffer[currentOffset++] & 0x3F)); - } else { - charBuffer[strLength++] = - (char) - (((currentByte & 0xF) << 12) - + ((classFileBuffer[currentOffset++] & 0x3F) << 6) - + (classFileBuffer[currentOffset++] & 0x3F)); - } - } - return new String(charBuffer, 0, strLength); - } - - /** - * Reads a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, CONSTANT_Module or - * CONSTANT_Package constant pool entry in {@link #b}. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the - * index of a CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType, CONSTANT_Module or - * CONSTANT_Package entry in class's constant pool table. - * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified constant pool entry. - */ - private String readStringish(final int offset, final char[] charBuffer) { - // Get the start offset of the cp_info structure (plus one), and read the CONSTANT_Utf8 entry - // designated by the first two bytes of this cp_info. - return readUTF8(cpInfoOffsets[readUnsignedShort(offset)], charBuffer); - } - - /** - * Reads a CONSTANT_Class constant pool entry in {@link #b}. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the - * index of a CONSTANT_Class entry in class's constant pool table. - * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified CONSTANT_Class entry. - */ - public String readClass(final int offset, final char[] charBuffer) { - return readStringish(offset, charBuffer); - } - - /** - * Reads a CONSTANT_Module constant pool entry in {@link #b}. This method is intended for - * {@link Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the - * index of a CONSTANT_Module entry in class's constant pool table. - * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified CONSTANT_Module entry. - */ - public String readModule(final int offset, final char[] charBuffer) { - return readStringish(offset, charBuffer); - } - - /** - * Reads a CONSTANT_Package constant pool entry in {@link #b}. This method is intended for - * {@link Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param offset the start offset of an unsigned short value in {@link #b}, whose value is the - * index of a CONSTANT_Package entry in class's constant pool table. - * @param charBuffer the buffer to be used to read the item. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the String corresponding to the specified CONSTANT_Package entry. - */ - public String readPackage(final int offset, final char[] charBuffer) { - return readStringish(offset, charBuffer); - } - - /** - * Reads a numeric or string constant pool entry in {@link #b}. This method is intended for - * {@link Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param constantPoolEntryIndex the index of a CONSTANT_Integer, CONSTANT_Float, CONSTANT_Long, - * CONSTANT_Double, CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType or - * CONSTANT_MethodHandle entry in the class's constant pool. - * @param charBuffer the buffer to be used to read strings. This buffer must be sufficiently - * large. It is not automatically resized. - * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, - * {@link Type} or {@link Handle} corresponding to the specified constant pool entry. - */ - public Object readConst(final int constantPoolEntryIndex, final char[] charBuffer) { - int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex]; - switch (b[cpInfoOffset - 1]) { - case Symbol.CONSTANT_INTEGER_TAG: - return readInt(cpInfoOffset); - case Symbol.CONSTANT_FLOAT_TAG: - return Float.intBitsToFloat(readInt(cpInfoOffset)); - case Symbol.CONSTANT_LONG_TAG: - return readLong(cpInfoOffset); - case Symbol.CONSTANT_DOUBLE_TAG: - return Double.longBitsToDouble(readLong(cpInfoOffset)); - case Symbol.CONSTANT_CLASS_TAG: - return Type.getObjectType(readUTF8(cpInfoOffset, charBuffer)); - case Symbol.CONSTANT_STRING_TAG: - return readUTF8(cpInfoOffset, charBuffer); - case Symbol.CONSTANT_METHOD_TYPE_TAG: - return Type.getMethodType(readUTF8(cpInfoOffset, charBuffer)); - case Symbol.CONSTANT_METHOD_HANDLE_TAG: - int referenceKind = readByte(cpInfoOffset); - int referenceCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 1)]; - int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(referenceCpInfoOffset + 2)]; - String owner = readClass(referenceCpInfoOffset, charBuffer); - String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer); - String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer); - boolean isInterface = - b[referenceCpInfoOffset - 1] == Symbol.CONSTANT_INTERFACE_METHODREF_TAG; - return new Handle(referenceKind, owner, name, descriptor, isInterface); - default: - throw new IllegalArgumentException(); - } - } -} diff --git a/src/main/java/org/objectweb/asm/ClassVisitor.java b/src/main/java/org/objectweb/asm/ClassVisitor.java deleted file mode 100644 index 88a19e47..00000000 --- a/src/main/java/org/objectweb/asm/ClassVisitor.java +++ /dev/null @@ -1,293 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A visitor to visit a Java class. The methods of this class must be called in the following order: - * visit [ visitSource ] [ visitModule ][ visitOuterClass ] ( - * visitAnnotation | visitTypeAnnotation | visitAttribute )* ( - * visitInnerClass | visitField | visitMethod )* visitEnd. - * - * @author Eric Bruneton - */ -public abstract class ClassVisitor { - - /** - * The ASM API version implemented by this visitor. The value of this field must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - protected final int api; - - /** - * The class visitor to which this visitor must delegate method calls. May be null. - */ - protected ClassVisitor cv; - - /** - * Constructs a new {@link ClassVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - public ClassVisitor(final int api) { - this(api, null); - } - - /** - * Constructs a new {@link ClassVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param classVisitor the class visitor to which this visitor must delegate method calls. May be - * null. - */ - public ClassVisitor(final int api, final ClassVisitor classVisitor) { - if (api < Opcodes.ASM4 || api > Opcodes.ASM6) { - throw new IllegalArgumentException(); - } - this.api = api; - this.cv = classVisitor; - } - - /** - * Visits the header of the class. - * - * @param version the class version. The minor version is stored in the 16 most significant bits, - * and the major version in the 16 least significant bits. - * @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if - * the class is deprecated. - * @param name the internal name of the class (see {@link Type#getInternalName()}). - * @param signature the signature of this class. May be null if the class is not a - * generic one, and does not extend or implement generic classes or interfaces. - * @param superName the internal of name of the super class (see {@link Type#getInternalName()}). - * For interfaces, the super class is {@link Object}. May be null, but only for the - * {@link Object} class. - * @param interfaces the internal names of the class's interfaces (see {@link - * Type#getInternalName()}). May be null. - */ - public void visit( - final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces) { - if (cv != null) { - cv.visit(version, access, name, signature, superName, interfaces); - } - } - - /** - * Visits the source of the class. - * - * @param source the name of the source file from which the class was compiled. May be - * null. - * @param debug additional debug information to compute the correspondence between source and - * compiled elements of the class. May be null. - */ - public void visitSource(final String source, final String debug) { - if (cv != null) { - cv.visitSource(source, debug); - } - } - - /** - * Visit the module corresponding to the class. - * - * @param name the fully qualified name (using dots) of the module. - * @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code - * ACC_MANDATED}. - * @param version the module version, or null. - * @return a visitor to visit the module values, or null if this visitor is not - * interested in visiting this module. - */ - public ModuleVisitor visitModule(final String name, final int access, final String version) { - if (api < Opcodes.ASM6) { - throw new UnsupportedOperationException(); - } - if (cv != null) { - return cv.visitModule(name, access, version); - } - return null; - } - - /** - * Visits the enclosing class of the class. This method must be called only if the class has an - * enclosing class. - * - * @param owner internal name of the enclosing class of the class. - * @param name the name of the method that contains the class, or null if the class is - * not enclosed in a method of its enclosing class. - * @param descriptor the descriptor of the method that contains the class, or null if the - * class is not enclosed in a method of its enclosing class. - */ - public void visitOuterClass(final String owner, final String name, final String descriptor) { - if (cv != null) { - cv.visitOuterClass(owner, name, descriptor); - } - } - - /** - * Visits an annotation of the class. - * - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { - if (cv != null) { - return cv.visitAnnotation(descriptor, visible); - } - return null; - } - - /** - * Visits an annotation on a type in the class signature. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link - * TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See - * {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or - * static inner type within 'typeRef'. May be null if the annotation targets - * 'typeRef' as a whole. - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitTypeAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(); - } - if (cv != null) { - return cv.visitTypeAnnotation(typeRef, typePath, descriptor, visible); - } - return null; - } - - /** - * Visits a non standard attribute of the class. - * - * @param attribute an attribute. - */ - public void visitAttribute(final Attribute attribute) { - if (cv != null) { - cv.visitAttribute(attribute); - } - } - - /** - * Visits information about an inner class. This inner class is not necessarily a member of the - * class being visited. - * - * @param name the internal name of an inner class (see {@link Type#getInternalName()}). - * @param outerName the internal name of the class to which the inner class belongs (see {@link - * Type#getInternalName()}). May be null for not member classes. - * @param innerName the (simple) name of the inner class inside its enclosing class. May be - * null for anonymous inner classes. - * @param access the access flags of the inner class as originally declared in the enclosing - * class. - */ - public void visitInnerClass( - final String name, final String outerName, final String innerName, final int access) { - if (cv != null) { - cv.visitInnerClass(name, outerName, innerName, access); - } - } - - /** - * Visits a field of the class. - * - * @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if - * the field is synthetic and/or deprecated. - * @param name the field's name. - * @param descriptor the field's descriptor (see {@link Type}). - * @param signature the field's signature. May be null if the field's type does not use - * generic types. - * @param value the field's initial value. This parameter, which may be null if the field - * does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link - * Long}, a {@link Double} or a {@link String} (for int, float, - * long or String fields respectively). This parameter is only used for - * static fields. Its value is ignored for non static fields, which must be initialized - * through bytecode instructions in constructors or methods. - * @return a visitor to visit field annotations and attributes, or null if this class - * visitor is not interested in visiting these annotations and attributes. - */ - public FieldVisitor visitField( - final int access, - final String name, - final String descriptor, - final String signature, - final Object value) { - if (cv != null) { - return cv.visitField(access, name, descriptor, signature, value); - } - return null; - } - - /** - * Visits a method of the class. This method must return a new {@link MethodVisitor} - * instance (or null) each time it is called, i.e., it should not return a previously - * returned visitor. - * - * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if - * the method is synthetic and/or deprecated. - * @param name the method's name. - * @param descriptor the method's descriptor (see {@link Type}). - * @param signature the method's signature. May be null if the method parameters, return - * type and exceptions do not use generic types. - * @param exceptions the internal names of the method's exception classes (see {@link - * Type#getInternalName()}). May be null. - * @return an object to visit the byte code of the method, or null if this class visitor - * is not interested in visiting the code of this method. - */ - public MethodVisitor visitMethod( - final int access, - final String name, - final String descriptor, - final String signature, - final String[] exceptions) { - if (cv != null) { - return cv.visitMethod(access, name, descriptor, signature, exceptions); - } - return null; - } - - /** - * Visits the end of the class. This method, which is the last one to be called, is used to inform - * the visitor that all the fields and methods of the class have been visited. - */ - public void visitEnd() { - if (cv != null) { - cv.visitEnd(); - } - } -} diff --git a/src/main/java/org/objectweb/asm/ClassWriter.java b/src/main/java/org/objectweb/asm/ClassWriter.java deleted file mode 100644 index 5981f7fc..00000000 --- a/src/main/java/org/objectweb/asm/ClassWriter.java +++ /dev/null @@ -1,906 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A {@link ClassVisitor} that generates a corresponding ClassFile structure, as defined in the Java - * Virtual Machine Specification (JVMS). It can be used alone, to generate a Java class "from - * scratch", or with one or more {@link ClassReader} and adapter {@link ClassVisitor} to generate a - * modified class from one or more existing Java classes. - * - * @author Eric Bruneton - * @see JVMS 4 - */ -public class ClassWriter extends ClassVisitor { - - /** - * A flag to automatically compute the maximum stack size and the maximum number of local - * variables of methods. If this flag is set, then the arguments of the {@link - * MethodVisitor#visitMaxs} method of the {@link MethodVisitor} returned by the {@link - * #visitMethod} method will be ignored, and computed automatically from the signature and the - * bytecode of each method. - * - * @see #ClassWriter(int) - */ - public static final int COMPUTE_MAXS = 1; - - /** - * A flag to automatically compute the stack map frames of methods from scratch. If this flag is - * set, then the calls to the {@link MethodVisitor#visitFrame} method are ignored, and the stack - * map frames are recomputed from the methods bytecode. The arguments of the {@link - * MethodVisitor#visitMaxs} method are also ignored and recomputed from the bytecode. In other - * words, {@link #COMPUTE_FRAMES} implies {@link #COMPUTE_MAXS}. - * - * @see #ClassWriter(int) - */ - public static final int COMPUTE_FRAMES = 2; - - // Note: fields are ordered as in the ClassFile structure, and those related to attributes are - // ordered as in Section 4.7 of the JVMS. - - /** - * The minor_version and major_version fields of the JVMS ClassFile structure. minor_version is - * stored in the 16 most significant bits, and major_version in the 16 least significant bits. - */ - private int version; - - /** - * The symbol table for this class (contains the constant_pool and the BootstrapMethods). - */ - private final SymbolTable symbolTable; - - /** - * The access_flags field of the JVMS ClassFile structure. This field can contain ASM specific - * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the - * ClassFile structure. - */ - private int accessFlags; - - /** - * The this_class field of the JVMS ClassFile structure. - */ - private int thisClass; - - /** - * The super_class field of the JVMS ClassFile structure. - */ - private int superClass; - - /** - * The interface_count field of the JVMS ClassFile structure. - */ - private int interfaceCount; - - /** - * The 'interfaces' array of the JVMS ClassFile structure. - */ - private int[] interfaces; - - /** - * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their - * {@link FieldWriter#fv} field. This field stores the first element of this list. - */ - private FieldWriter firstField; - - /** - * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their - * {@link FieldWriter#fv} field. This field stores the last element of this list. - */ - private FieldWriter lastField; - - /** - * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their - * {@link MethodWriter#mv} field. This field stores the first element of this list. - */ - private MethodWriter firstMethod; - - /** - * The methods of this class, stored in a linked list of {@link MethodWriter} linked via their - * {@link MethodWriter#mv} field. This field stores the last element of this list. - */ - private MethodWriter lastMethod; - - /** - * The number_of_classes field of the InnerClasses attribute, or 0. - */ - private int numberOfClasses; - - /** - * The 'classes' array of the InnerClasses attribute, or null. - */ - private ByteVector classes; - - /** - * The class_index field of the EnclosingMethod attribute, or 0. - */ - private int enclosingClassIndex; - - /** - * The method_index field of the EnclosingMethod attribute. - */ - private int enclosingMethodIndex; - - /** - * The signature_index field of the Signature attribute, or 0. - */ - private int signatureIndex; - - /** - * The source_file_index field of the SourceFile attribute, or 0. - */ - private int sourceFileIndex; - - /** - * The debug_extension field of the SourceDebugExtension attribute, or null. - */ - private ByteVector debugExtension; - - /** - * The last runtime visible annotation of this class. The previous ones can be accessed with the - * {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeVisibleAnnotation; - - /** - * The last runtime invisible annotation of this class. The previous ones can be accessed with the - * {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeInvisibleAnnotation; - - /** - * The last runtime visible type annotation of this class. The previous ones can be accessed with - * the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeVisibleTypeAnnotation; - - /** - * The last runtime invisible type annotation of this class. The previous ones can be accessed - * with the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeInvisibleTypeAnnotation; - - /** - * The Module attribute of this class, or null. - */ - private ModuleWriter moduleWriter; - - /** - * The first non standard attribute of this class. The next ones can be accessed with the {@link - * Attribute#nextAttribute} field. May be null. - * - *

WARNING: this list stores the attributes in the reverse order of their visit. - * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link - * #toByteArray} method writes the attributes in the order defined by this list, i.e. in the - * reverse order specified by the user. - */ - private Attribute firstAttribute; - - /** - * Indicates what must be automatically computed in {@link MethodWriter}. Must be one of {@link - * MethodWriter#COMPUTE_NOTHING}, {@link MethodWriter#COMPUTE_MAX_STACK_AND_LOCAL}, {@link - * MethodWriter#COMPUTE_INSERTED_FRAMES}, or {@link MethodWriter#COMPUTE_ALL_FRAMES}. - */ - private int compute; - - // ----------------------------------------------------------------------------------------------- - // Constructor - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a new {@link ClassWriter} object. - * - * @param flags option flags that can be used to modify the default behavior of this class. Must - * be zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. - */ - public ClassWriter(final int flags) { - this(null, flags); - } - - /** - * Constructs a new {@link ClassWriter} object and enables optimizations for "mostly add" bytecode - * transformations. These optimizations are the following: - * - *

    - *
  • The constant pool and bootstrap methods from the original class are copied as is in the - * new class, which saves time. New constant pool entries and new bootstrap methods will be - * added at the end if necessary, but unused constant pool entries or bootstrap methods - * won't be removed. - *
  • Methods that are not transformed are copied as is in the new class, directly from the - * original class bytecode (i.e. without emitting visit events for all the method - * instructions), which saves a lot of time. Untransformed methods are detected by - * the fact that the {@link ClassReader} receives {@link MethodVisitor} objects that come - * from a {@link ClassWriter} (and not from any other {@link ClassVisitor} instance). - *
- * - * @param classReader the {@link ClassReader} used to read the original class. It will be used to - * copy the entire constant pool and bootstrap methods from the original class and also to - * copy other fragments of original bytecode where applicable. - * @param flags option flags that can be used to modify the default behavior of this class.Must be - * zero or more of {@link #COMPUTE_MAXS} and {@link #COMPUTE_FRAMES}. These option flags do - * not affect methods that are copied as is in the new class. This means that neither the - * maximum stack size nor the stack frames will be computed for these methods. - */ - public ClassWriter(final ClassReader classReader, final int flags) { - super(Opcodes.ASM6); - symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader); - if ((flags & COMPUTE_FRAMES) != 0) { - this.compute = MethodWriter.COMPUTE_ALL_FRAMES; - } else if ((flags & COMPUTE_MAXS) != 0) { - this.compute = MethodWriter.COMPUTE_MAX_STACK_AND_LOCAL; - } else { - this.compute = MethodWriter.COMPUTE_NOTHING; - } - } - - // ----------------------------------------------------------------------------------------------- - // Implementation of the ClassVisitor abstract class - // ----------------------------------------------------------------------------------------------- - - @Override - public final void visit( - final int version, - final int access, - final String name, - final String signature, - final String superName, - final String[] interfaces) { - this.version = version; - this.accessFlags = access; - this.thisClass = symbolTable.setMajorVersionAndClassName(version & 0xFFFF, name); - if (signature != null) { - this.signatureIndex = symbolTable.addConstantUtf8(signature); - } - this.superClass = superName == null ? 0 : symbolTable.addConstantClass(superName).index; - if (interfaces != null && interfaces.length > 0) { - interfaceCount = interfaces.length; - this.interfaces = new int[interfaceCount]; - for (int i = 0; i < interfaceCount; ++i) { - this.interfaces[i] = symbolTable.addConstantClass(interfaces[i]).index; - } - } - } - - @Override - public final void visitSource(final String file, final String debug) { - if (file != null) { - sourceFileIndex = symbolTable.addConstantUtf8(file); - } - if (debug != null) { - debugExtension = new ByteVector().encodeUTF8(debug, 0, Integer.MAX_VALUE); - } - } - - @Override - public final ModuleVisitor visitModule( - final String name, final int access, final String version) { - return moduleWriter = - new ModuleWriter( - symbolTable, - symbolTable.addConstantModule(name).index, - access, - version == null ? 0 : symbolTable.addConstantUtf8(version)); - } - - @Override - public final void visitOuterClass( - final String owner, final String name, final String descriptor) { - enclosingClassIndex = symbolTable.addConstantClass(owner).index; - if (name != null && descriptor != null) { - enclosingMethodIndex = symbolTable.addConstantNameAndType(name, descriptor); - } - } - - @Override - public final AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { - // Create a ByteVector to hold an 'annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16. - ByteVector annotation = new ByteVector(); - // Write type_index and reserve space for num_element_value_pairs. - annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastRuntimeVisibleAnnotation = - new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation); - } else { - return lastRuntimeInvisibleAnnotation = - new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation); - } - } - - @Override - public final AnnotationVisitor visitTypeAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - // Create a ByteVector to hold a 'type_annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. - ByteVector typeAnnotation = new ByteVector(); - // Write target_type, target_info, and target_path. - TypeReference.putTarget(typeRef, typeAnnotation); - TypePath.put(typePath, typeAnnotation); - // Write type_index and reserve space for num_element_value_pairs. - typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastRuntimeVisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation); - } else { - return lastRuntimeInvisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation); - } - } - - @Override - public final void visitAttribute(final Attribute attribute) { - // Store the attributes in the reverse order of their visit by this method. - attribute.nextAttribute = firstAttribute; - firstAttribute = attribute; - } - - @Override - public final void visitInnerClass( - final String name, final String outerName, final String innerName, final int access) { - if (classes == null) { - classes = new ByteVector(); - } - // Section 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the constant_pool table - // which represents a class or interface C that is not a package member must have exactly one - // corresponding entry in the classes array". To avoid duplicates we keep track in the info - // field of the Symbol of each CONSTANT_Class_info entry C whether an inner class entry has - // already been added for C. If so, we store the index of this inner class entry (plus one) in - // the info field. This trick allows duplicate detection in O(1) time. - Symbol nameSymbol = symbolTable.addConstantClass(name); - if (nameSymbol.info == 0) { - ++numberOfClasses; - classes.putShort(nameSymbol.index); - classes.putShort(outerName == null ? 0 : symbolTable.addConstantClass(outerName).index); - classes.putShort(innerName == null ? 0 : symbolTable.addConstantUtf8(innerName)); - classes.putShort(access); - nameSymbol.info = numberOfClasses; - } else { - // Compare the inner classes entry nameSymbol.info - 1 with the arguments of this method and - // throw an exception if there is a difference? - } - } - - @Override - public final FieldVisitor visitField( - final int access, - final String name, - final String descriptor, - final String signature, - final Object value) { - FieldWriter fieldWriter = - new FieldWriter(symbolTable, access, name, descriptor, signature, value); - if (firstField == null) { - firstField = fieldWriter; - } else { - lastField.fv = fieldWriter; - } - return lastField = fieldWriter; - } - - @Override - public final MethodVisitor visitMethod( - final int access, - final String name, - final String descriptor, - final String signature, - final String[] exceptions) { - MethodWriter methodWriter = - new MethodWriter(symbolTable, access, name, descriptor, signature, exceptions, compute); - if (firstMethod == null) { - firstMethod = methodWriter; - } else { - lastMethod.mv = methodWriter; - } - return lastMethod = methodWriter; - } - - @Override - public final void visitEnd() { - // Nothing to do. - } - - // ----------------------------------------------------------------------------------------------- - // Other public methods - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the content of the class file that was built by this ClassWriter. - * - * @return the binary content of the JVMS ClassFile structure that was built by this ClassWriter. - */ - public byte[] toByteArray() { - // First step: compute the size in bytes of the ClassFile structure. - // The magic field uses 4 bytes, 10 mandatory fields (minor_version, major_version, - // constant_pool_count, access_flags, this_class, super_class, interfaces_count, fields_count, - // methods_count and attributes_count) use 2 bytes each, and each interface uses 2 bytes too. - int size = 24 + 2 * interfaceCount; - int fieldsCount = 0; - FieldWriter fieldWriter = firstField; - while (fieldWriter != null) { - ++fieldsCount; - size += fieldWriter.computeFieldInfoSize(); - fieldWriter = (FieldWriter) fieldWriter.fv; - } - int methodsCount = 0; - MethodWriter methodWriter = firstMethod; - while (methodWriter != null) { - ++methodsCount; - size += methodWriter.computeMethodInfoSize(); - methodWriter = (MethodWriter) methodWriter.mv; - } - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - int attributesCount = 0; - if (classes != null) { - ++attributesCount; - size += 8 + classes.length; - symbolTable.addConstantUtf8(Constants.INNER_CLASSES); - } - if (enclosingClassIndex != 0) { - ++attributesCount; - size += 10; - symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD); - } - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) { - ++attributesCount; - size += 6; - symbolTable.addConstantUtf8(Constants.SYNTHETIC); - } - if (signatureIndex != 0) { - ++attributesCount; - size += 8; - symbolTable.addConstantUtf8(Constants.SIGNATURE); - } - if (sourceFileIndex != 0) { - ++attributesCount; - size += 8; - symbolTable.addConstantUtf8(Constants.SOURCE_FILE); - } - if (debugExtension != null) { - ++attributesCount; - size += 6 + debugExtension.length; - symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION); - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - ++attributesCount; - size += 6; - symbolTable.addConstantUtf8(Constants.DEPRECATED); - } - if (lastRuntimeVisibleAnnotation != null) { - ++attributesCount; - size += - lastRuntimeVisibleAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_ANNOTATIONS); - } - if (lastRuntimeInvisibleAnnotation != null) { - ++attributesCount; - size += - lastRuntimeInvisibleAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_ANNOTATIONS); - } - if (lastRuntimeVisibleTypeAnnotation != null) { - ++attributesCount; - size += - lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - ++attributesCount; - size += - lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); - } - if (symbolTable.computeBootstrapMethodsSize() > 0) { - ++attributesCount; - size += symbolTable.computeBootstrapMethodsSize(); - } - if (moduleWriter != null) { - attributesCount += moduleWriter.getAttributeCount(); - size += moduleWriter.computeAttributesSize(); - } - if (firstAttribute != null) { - attributesCount += firstAttribute.getAttributeCount(); - size += firstAttribute.computeAttributesSize(symbolTable); - } - // IMPORTANT: this must be the last part of the ClassFile size computation, because the previous - // statements can add attribute names to the constant pool, thereby changing its size! - size += symbolTable.getConstantPoolLength(); - if (symbolTable.getConstantPoolCount() > 0xFFFF) { - throw new IndexOutOfBoundsException("Class file too large!"); - } - - // Second step: allocate a ByteVector of the correct size (in order to avoid any array copy in - // dynamic resizes) and fill it with the ClassFile content. - ByteVector result = new ByteVector(size); - result.putInt(0xCAFEBABE).putInt(version); - symbolTable.putConstantPool(result); - int mask = (version & 0xFFFF) < Opcodes.V1_5 ? Opcodes.ACC_SYNTHETIC : 0; - result.putShort(accessFlags & ~mask).putShort(thisClass).putShort(superClass); - result.putShort(interfaceCount); - for (int i = 0; i < interfaceCount; ++i) { - result.putShort(interfaces[i]); - } - result.putShort(fieldsCount); - fieldWriter = firstField; - while (fieldWriter != null) { - fieldWriter.putFieldInfo(result); - fieldWriter = (FieldWriter) fieldWriter.fv; - } - result.putShort(methodsCount); - boolean hasFrames = false; - boolean hasAsmInstructions = false; - methodWriter = firstMethod; - while (methodWriter != null) { - hasFrames |= methodWriter.hasFrames(); - hasAsmInstructions |= methodWriter.hasAsmInstructions(); - methodWriter.putMethodInfo(result); - methodWriter = (MethodWriter) methodWriter.mv; - } - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - result.putShort(attributesCount); - if (classes != null) { - result - .putShort(symbolTable.addConstantUtf8(Constants.INNER_CLASSES)) - .putInt(classes.length + 2) - .putShort(numberOfClasses) - .putByteArray(classes.data, 0, classes.length); - } - if (enclosingClassIndex != 0) { - result - .putShort(symbolTable.addConstantUtf8(Constants.ENCLOSING_METHOD)) - .putInt(4) - .putShort(enclosingClassIndex) - .putShort(enclosingMethodIndex); - } - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && (version & 0xFFFF) < Opcodes.V1_5) { - result.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0); - } - if (signatureIndex != 0) { - result - .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE)) - .putInt(2) - .putShort(signatureIndex); - } - if (sourceFileIndex != 0) { - result - .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_FILE)) - .putInt(2) - .putShort(sourceFileIndex); - } - if (debugExtension != null) { - int length = debugExtension.length; - result - .putShort(symbolTable.addConstantUtf8(Constants.SOURCE_DEBUG_EXTENSION)) - .putInt(length) - .putByteArray(debugExtension.data, 0, length); - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - result.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0); - } - if (lastRuntimeVisibleAnnotation != null) { - lastRuntimeVisibleAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), result); - } - if (lastRuntimeInvisibleAnnotation != null) { - lastRuntimeInvisibleAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), result); - } - if (lastRuntimeVisibleTypeAnnotation != null) { - lastRuntimeVisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), result); - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - lastRuntimeInvisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), result); - } - symbolTable.putBootstrapMethods(result); - if (moduleWriter != null) { - moduleWriter.putAttributes(result); - } - if (firstAttribute != null) { - firstAttribute.putAttributes(symbolTable, result); - } - - // Third step: do a ClassReader->ClassWriter round trip if the generated class contains ASM - // specific instructions due to large forward jumps. - if (hasAsmInstructions) { - Attribute[] attributes = getAttributePrototypes(); - firstField = null; - lastField = null; - firstMethod = null; - lastMethod = null; - lastRuntimeVisibleAnnotation = null; - lastRuntimeInvisibleAnnotation = null; - lastRuntimeVisibleTypeAnnotation = null; - lastRuntimeInvisibleTypeAnnotation = null; - moduleWriter = null; - firstAttribute = null; - compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING; - new ClassReader(result.data, 0, /* checkClassVersion = */ false) - .accept( - this, - attributes, - (hasFrames ? ClassReader.EXPAND_FRAMES : 0) | ClassReader.EXPAND_ASM_INSNS); - return toByteArray(); - } else { - return result.data; - } - } - - /** - * Returns the prototypes of the attributes used by this class, its fields and its methods. - * - * @return the prototypes of the attributes used by this class, its fields and its methods. - */ - private Attribute[] getAttributePrototypes() { - Attribute.Set attributePrototypes = new Attribute.Set(); - attributePrototypes.addAttributes(firstAttribute); - FieldWriter fieldWriter = firstField; - while (fieldWriter != null) { - fieldWriter.collectAttributePrototypes(attributePrototypes); - fieldWriter = (FieldWriter) fieldWriter.fv; - } - MethodWriter methodWriter = firstMethod; - while (methodWriter != null) { - methodWriter.collectAttributePrototypes(attributePrototypes); - methodWriter = (MethodWriter) methodWriter.mv; - } - return attributePrototypes.toArray(); - } - - // ----------------------------------------------------------------------------------------------- - // Utility methods: constant pool management for Attribute sub classes - // ----------------------------------------------------------------------------------------------- - - /** - * Adds a number or string constant to the constant pool of the class being build. Does nothing if - * the constant pool already contains a similar item. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param value the value of the constant to be added to the constant pool. This parameter must be - * an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}. - * @return the index of a new or already existing constant item with the given value. - */ - public int newConst(final Object value) { - return symbolTable.addConstant(value).index; - } - - /** - * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the constant - * pool already contains a similar item. This method is intended for {@link Attribute} sub - * classes, and is normally not needed by class generators or adapters. - * - * @param value the String value. - * @return the index of a new or already existing UTF8 item. - */ - public int newUTF8(final String value) { - return symbolTable.addConstantUtf8(value); - } - - /** - * Adds a class reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param value the internal name of the class. - * @return the index of a new or already existing class reference item. - */ - public int newClass(final String value) { - return symbolTable.addConstantClass(value).index; - } - - /** - * Adds a method type reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param methodDescriptor method descriptor of the method type. - * @return the index of a new or already existing method type reference item. - */ - public int newMethodType(final String methodDescriptor) { - return symbolTable.addConstantMethodType(methodDescriptor).index; - } - - /** - * Adds a module reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param moduleName name of the module. - * @return the index of a new or already existing module reference item. - */ - public int newModule(final String moduleName) { - return symbolTable.addConstantModule(moduleName).index; - } - - /** - * Adds a package reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param packageName name of the package in its internal form. - * @return the index of a new or already existing module reference item. - */ - public int newPackage(final String packageName) { - return symbolTable.addConstantPackage(packageName).index; - } - - /** - * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool - * already contains a similar item. This method is intended for {@link Attribute} sub classes, - * and is normally not needed by class generators or adapters. - * - * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link - * Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link - * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, - * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of the field or method owner class. - * @param name the name of the field or method. - * @param descriptor the descriptor of the field or method. - * @return the index of a new or already existing method type reference item. - * @deprecated this method is superseded by {@link #newHandle(int, String, String, String, - * boolean)}. - */ - @Deprecated - public int newHandle( - final int tag, final String owner, final String name, final String descriptor) { - return newHandle(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE); - } - - /** - * Adds a handle to the constant pool of the class being build. Does nothing if the constant pool - * already contains a similar item. This method is intended for {@link Attribute} sub classes, - * and is normally not needed by class generators or adapters. - * - * @param tag the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, {@link - * Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link - * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, - * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of the field or method owner class. - * @param name the name of the field or method. - * @param descriptor the descriptor of the field or method. - * @param isInterface true if the owner is an interface. - * @return the index of a new or already existing method type reference item. - */ - public int newHandle( - final int tag, - final String owner, - final String name, - final String descriptor, - final boolean isInterface) { - return symbolTable.addConstantMethodHandle(tag, owner, name, descriptor, isInterface).index; - } - - /** - * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing if - * the constant pool already contains a similar item. This method is intended for {@link - * Attribute} sub classes, and is normally not needed by class generators or adapters. - * - * @param name name of the invoked method. - * @param descriptor descriptor of the invoke method. - * @param bootstrapMethodHandle the bootstrap method. - * @param bootstrapMethodArguments the bootstrap method constant arguments. - * @return the index of a new or already existing invokedynamic reference item. - */ - public int newInvokeDynamic( - final String name, - final String descriptor, - final Handle bootstrapMethodHandle, - final Object... bootstrapMethodArguments) { - return symbolTable.addConstantInvokeDynamic( - name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments) - .index; - } - - /** - * Adds a field reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param owner the internal name of the field's owner class. - * @param name the field's name. - * @param descriptor the field's descriptor. - * @return the index of a new or already existing field reference item. - */ - public int newField(final String owner, final String name, final String descriptor) { - return symbolTable.addConstantFieldref(owner, name, descriptor).index; - } - - /** - * Adds a method reference to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param owner the internal name of the method's owner class. - * @param name the method's name. - * @param descriptor the method's descriptor. - * @param isInterface true if owner is an interface. - * @return the index of a new or already existing method reference item. - */ - public int newMethod( - final String owner, final String name, final String descriptor, final boolean isInterface) { - return symbolTable.addConstantMethodref(owner, name, descriptor, isInterface).index; - } - - /** - * Adds a name and type to the constant pool of the class being build. Does nothing if the - * constant pool already contains a similar item. This method is intended for {@link Attribute} - * sub classes, and is normally not needed by class generators or adapters. - * - * @param name a name. - * @param descriptor a type descriptor. - * @return the index of a new or already existing name and type item. - */ - public int newNameType(final String name, final String descriptor) { - return symbolTable.addConstantNameAndType(name, descriptor); - } - - // ----------------------------------------------------------------------------------------------- - // Default method to compute common super classes when computing stack map frames - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the common super type of the two given types. The default implementation of this method - * loads the two given classes and uses the java.lang.Class methods to find the common - * super class. It can be overridden to compute this common super type in other ways, in - * particular without actually loading any class, or to take into account the class that is - * currently being generated by this ClassWriter, which can of course not be loaded since it is - * under construction. - * - * @param type1 the internal name of a class. - * @param type2 the internal name of another class. - * @return the internal name of the common super class of the two given classes. - */ - protected String getCommonSuperClass(final String type1, final String type2) { - ClassLoader classLoader = getClass().getClassLoader(); - Class class1; - try { - class1 = Class.forName(type1.replace('/', '.'), false, classLoader); - } catch (Exception e) { - throw new TypeNotPresentException(type1, e); - } - Class class2; - try { - class2 = Class.forName(type2.replace('/', '.'), false, classLoader); - } catch (Exception e) { - throw new TypeNotPresentException(type2, e); - } - if (class1.isAssignableFrom(class2)) { - return type1; - } - if (class2.isAssignableFrom(class1)) { - return type2; - } - if (class1.isInterface() || class2.isInterface()) { - return "java/lang/Object"; - } else { - do { - class1 = class1.getSuperclass(); - } while (!class1.isAssignableFrom(class2)); - return class1.getName().replace('.', '/'); - } - } -} diff --git a/src/main/java/org/objectweb/asm/Constants.java b/src/main/java/org/objectweb/asm/Constants.java deleted file mode 100644 index e0ec65de..00000000 --- a/src/main/java/org/objectweb/asm/Constants.java +++ /dev/null @@ -1,176 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * Defines additional JVM opcodes, access flags and constants which are not part of the ASM public - * API. - * - * @author Eric Bruneton - * @see JVMS 6 - */ -final class Constants implements Opcodes { - - private Constants() { - } - - // The ClassFile attribute names, in the order they are defined in - // https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7-300. - - static final String CONSTANT_VALUE = "ConstantValue"; - static final String CODE = "Code"; - static final String STACK_MAP_TABLE = "StackMapTable"; - static final String EXCEPTIONS = "Exceptions"; - static final String INNER_CLASSES = "InnerClasses"; - static final String ENCLOSING_METHOD = "EnclosingMethod"; - static final String SYNTHETIC = "Synthetic"; - static final String SIGNATURE = "Signature"; - static final String SOURCE_FILE = "SourceFile"; - static final String SOURCE_DEBUG_EXTENSION = "SourceDebugExtension"; - static final String LINE_NUMBER_TABLE = "LineNumberTable"; - static final String LOCAL_VARIABLE_TABLE = "LocalVariableTable"; - static final String LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable"; - static final String DEPRECATED = "Deprecated"; - static final String RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations"; - static final String RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations"; - static final String RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations"; - static final String RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = - "RuntimeInvisibleParameterAnnotations"; - static final String RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations"; - static final String RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations"; - static final String ANNOTATION_DEFAULT = "AnnotationDefault"; - static final String BOOTSTRAP_METHODS = "BootstrapMethods"; - static final String METHOD_PARAMETERS = "MethodParameters"; - static final String MODULE = "Module"; - static final String MODULE_PACKAGES = "ModulePackages"; - static final String MODULE_MAIN_CLASS = "ModuleMainClass"; - - // ASM specific access flags. - // WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard - // access flags, and also to make sure that these flags are automatically filtered out when - // written in class files (because access flags are stored using 16 bits only). - - static final int ACC_CONSTRUCTOR = 0x40000; // method access flag. - - // ASM specific stack map frame types, used in {@link ClassVisitor#visitFrame}. - - /** - * A frame inserted between already existing frames. This internal stack map frame type (in - * addition to the ones declared in {@link Opcodes}) can only be used if the frame content can be - * computed from the previous existing frame and from the instructions between this existing frame - * and the inserted one, without any knowledge of the type hierarchy. This kind of frame is only - * used when an unconditional jump is inserted in a method while expanding an ASM specific - * instruction. Keep in sync with Opcodes.java. - */ - static final int F_INSERT = 256; - - // The JVM opcode values which are not part of the ASM public API. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html. - - static final int LDC_W = 19; - static final int LDC2_W = 20; - static final int ILOAD_0 = 26; - static final int ILOAD_1 = 27; - static final int ILOAD_2 = 28; - static final int ILOAD_3 = 29; - static final int LLOAD_0 = 30; - static final int LLOAD_1 = 31; - static final int LLOAD_2 = 32; - static final int LLOAD_3 = 33; - static final int FLOAD_0 = 34; - static final int FLOAD_1 = 35; - static final int FLOAD_2 = 36; - static final int FLOAD_3 = 37; - static final int DLOAD_0 = 38; - static final int DLOAD_1 = 39; - static final int DLOAD_2 = 40; - static final int DLOAD_3 = 41; - static final int ALOAD_0 = 42; - static final int ALOAD_1 = 43; - static final int ALOAD_2 = 44; - static final int ALOAD_3 = 45; - static final int ISTORE_0 = 59; - static final int ISTORE_1 = 60; - static final int ISTORE_2 = 61; - static final int ISTORE_3 = 62; - static final int LSTORE_0 = 63; - static final int LSTORE_1 = 64; - static final int LSTORE_2 = 65; - static final int LSTORE_3 = 66; - static final int FSTORE_0 = 67; - static final int FSTORE_1 = 68; - static final int FSTORE_2 = 69; - static final int FSTORE_3 = 70; - static final int DSTORE_0 = 71; - static final int DSTORE_1 = 72; - static final int DSTORE_2 = 73; - static final int DSTORE_3 = 74; - static final int ASTORE_0 = 75; - static final int ASTORE_1 = 76; - static final int ASTORE_2 = 77; - static final int ASTORE_3 = 78; - static final int WIDE = 196; - static final int GOTO_W = 200; - static final int JSR_W = 201; - - // Constants to convert between normal and wide jump instructions. - - // The delta between the GOTO_W and JSR_W opcodes and GOTO and JUMP. - static final int WIDE_JUMP_OPCODE_DELTA = GOTO_W - GOTO; - - // Constants to convert JVM opcodes to the equivalent ASM specific opcodes, and vice versa. - - // The delta between the ASM_IFEQ, ..., ASM_IF_ACMPNE, ASM_GOTO and ASM_JSR opcodes - // and IFEQ, ..., IF_ACMPNE, GOTO and JSR. - static final int ASM_OPCODE_DELTA = 49; - - // The delta between the ASM_IFNULL and ASM_IFNONNULL opcodes and IFNULL and IFNONNULL. - static final int ASM_IFNULL_OPCODE_DELTA = 20; - - // ASM specific opcodes, used for long forward jump instructions. - - static final int ASM_IFEQ = IFEQ + ASM_OPCODE_DELTA; - static final int ASM_IFNE = IFNE + ASM_OPCODE_DELTA; - static final int ASM_IFLT = IFLT + ASM_OPCODE_DELTA; - static final int ASM_IFGE = IFGE + ASM_OPCODE_DELTA; - static final int ASM_IFGT = IFGT + ASM_OPCODE_DELTA; - static final int ASM_IFLE = IFLE + ASM_OPCODE_DELTA; - static final int ASM_IF_ICMPEQ = IF_ICMPEQ + ASM_OPCODE_DELTA; - static final int ASM_IF_ICMPNE = IF_ICMPNE + ASM_OPCODE_DELTA; - static final int ASM_IF_ICMPLT = IF_ICMPLT + ASM_OPCODE_DELTA; - static final int ASM_IF_ICMPGE = IF_ICMPGE + ASM_OPCODE_DELTA; - static final int ASM_IF_ICMPGT = IF_ICMPGT + ASM_OPCODE_DELTA; - static final int ASM_IF_ICMPLE = IF_ICMPLE + ASM_OPCODE_DELTA; - static final int ASM_IF_ACMPEQ = IF_ACMPEQ + ASM_OPCODE_DELTA; - static final int ASM_IF_ACMPNE = IF_ACMPNE + ASM_OPCODE_DELTA; - static final int ASM_GOTO = GOTO + ASM_OPCODE_DELTA; - static final int ASM_JSR = JSR + ASM_OPCODE_DELTA; - static final int ASM_IFNULL = IFNULL + ASM_IFNULL_OPCODE_DELTA; - static final int ASM_IFNONNULL = IFNONNULL + ASM_IFNULL_OPCODE_DELTA; - static final int ASM_GOTO_W = 220; -} diff --git a/src/main/java/org/objectweb/asm/Context.java b/src/main/java/org/objectweb/asm/Context.java deleted file mode 100644 index 330ef5d5..00000000 --- a/src/main/java/org/objectweb/asm/Context.java +++ /dev/null @@ -1,164 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. - -package org.objectweb.asm; - -/** - * Information about a class being parsed in a {@link ClassReader}. - * - * @author Eric Bruneton - */ -final class Context { - - /** - * The prototypes of the attributes that must be parsed in this class. - */ - Attribute[] attributePrototypes; - - /** - * The options used to parse this class. One or more of {@link ClassReader#SKIP_CODE}, {@link - * ClassReader#SKIP_DEBUG}, {@link ClassReader#SKIP_FRAMES}, {@link ClassReader#EXPAND_FRAMES} or - * {@link ClassReader#EXPAND_ASM_INSNS}. - */ - int parsingOptions; - - /** - * The buffer used to read strings in the constant pool. - */ - char[] charBuffer; - - /** - * The start offsets in {@link ClassReader#b} of each element of the bootstrap_methods array (in - * the BootstrapMethod attribute). - * - * @see JVMS - * 4.7.23 - */ - int[] bootstrapMethodOffsets; - - // Information about the current method, i.e. the one read in the current (or latest) call - // to {@link ClassReader#readMethod()}. - - /** - * The access flags of the current method. - */ - int currentMethodAccessFlags; - - /** - * The name of the current method. - */ - String currentMethodName; - - /** - * The descriptor of the current method. - */ - String currentMethodDescriptor; - - /** - * The labels of the current method, indexed by bytecode offset (only bytecode offsets for which a - * label is needed have a non null associated Label). - */ - Label[] currentMethodLabels; - - // Information about the current type annotation target, i.e. the one read in the current - // (or latest) call to {@link ClassReader#readAnnotationTarget()}. - - /** - * The target_type and target_info of the current type annotation target, encoded as described in - * {@link TypeReference}. - */ - int currentTypeAnnotationTarget; - - /** - * The target_path of the current type annotation target. - */ - TypePath currentTypeAnnotationTargetPath; - - /** - * The start of each local variable range in the current local variable annotation. - */ - Label[] currentLocalVariableAnnotationRangeStarts; - - /** - * The end of each local variable range in the current local variable annotation. - */ - Label[] currentLocalVariableAnnotationRangeEnds; - - /** - * The local variable index of each local variable range in the current local variable annotation. - */ - int[] currentLocalVariableAnnotationRangeIndices; - - // Information about the current stack map frame, i.e. the one read in the current (or latest) - // call to {@link ClassReader#readFrame()}. - - /** - * The bytecode offset of the current stack map frame. - */ - int currentFrameOffset; - - /** - * The type of the current stack map frame. One of {@link Opcodes#F_FULL}, {@link - * Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or {@link Opcodes#F_SAME1}. - */ - int currentFrameType; - - /** - * The number of local variable types in the current stack map frame. Each type is represented - * with a single array element (even long and double). - */ - int currentFrameLocalCount; - - /** - * The delta number of local variable types in the current stack map frame (each type is - * represented with a single array element - even long and double). This is the number of local - * variable types in this frame, minus the number of local variable types in the previous frame. - */ - int currentFrameLocalCountDelta; - - /** - * The types of the local variables in the current stack map frame. Each type is represented with - * a single array element (even long and double), using the format described in {@link - * MethodVisitor#visitFrame}. Depending on {@link #currentFrameType}, this contains the types of - * all the local variables, or only those of the additional ones (compared to the previous frame). - */ - Object[] currentFrameLocalTypes; - - /** - * The number stack element types in the current stack map frame. Each type is represented with a - * single array element (even long and double). - */ - int currentFrameStackCount; - - /** - * The types of the stack elements in the current stack map frame. Each type is represented with a - * single array element (even long and double), using the format described in {@link - * MethodVisitor#visitFrame}. - */ - Object[] currentFrameStackTypes; -} diff --git a/src/main/java/org/objectweb/asm/CurrentFrame.java b/src/main/java/org/objectweb/asm/CurrentFrame.java deleted file mode 100644 index 69cfe12a..00000000 --- a/src/main/java/org/objectweb/asm/CurrentFrame.java +++ /dev/null @@ -1,56 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. - -package org.objectweb.asm; - -/** - * Information about the input stack map frame at the "current" instruction of a method. This is - * implemented as a Frame subclass for a "basic block" containing only one instruction. - * - * @author Eric Bruneton - */ -final class CurrentFrame extends Frame { - - CurrentFrame(final Label owner) { - super(owner); - } - - /** - * Sets this CurrentFrame to the input stack map frame of the next "current" instruction, i.e. the - * instruction just after the given one. It is assumed that the value of this object when this - * method is called is the stack map frame status just before the given instruction is executed. - */ - @Override - void execute( - final int opcode, final int arg, final Symbol symbolArg, final SymbolTable symbolTable) { - super.execute(opcode, arg, symbolArg, symbolTable); - Frame successor = new Frame(null); - merge(symbolTable, successor, 0); - copyFrom(successor); - } -} diff --git a/src/main/java/org/objectweb/asm/Edge.java b/src/main/java/org/objectweb/asm/Edge.java deleted file mode 100644 index dff553d2..00000000 --- a/src/main/java/org/objectweb/asm/Edge.java +++ /dev/null @@ -1,93 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * An edge in the control flow graph of a method. Each node of this graph is a basic block, - * represented with the Label corresponding to its first instruction. Each edge goes from one node - * to another, i.e. from one basic block to another (called the predecessor and successor blocks, - * respectively). An edge corresponds either to a jump or ret instruction or to an exception - * handler. - * - * @author Eric Bruneton - * @see Label - */ -final class Edge { - - /** - * A control flow graph edge corresponding to a jump or ret instruction. Only used with {@link - * ClassWriter#COMPUTE_FRAMES}. - */ - static final int JUMP = 0; - - /** - * A control flow graph edge corresponding to an exception handler. Only used with {@link - * ClassWriter#COMPUTE_MAXS}. - */ - static final int EXCEPTION = 0x7FFFFFFF; - - /** - * Information about this control flow graph edge. - * - *
    - *
  • If {@link ClassWriter#COMPUTE_MAXS} is used, this field contains either a stack size - * delta (for an edge corresponding to a jump instruction), or the value EXCEPTION (for an - * edge corresponding to an exception handler). The stack size delta is the stack size just - * after the jump instruction, minus the stack size at the beginning of the predecessor - * basic block, i.e. the one containing the jump instruction. - *
  • If {@link ClassWriter#COMPUTE_FRAMES} is used, this field contains either the value JUMP - * (for an edge corresponding to a jump instruction), or the index, in the {@link - * ClassWriter} type table, of the exception type that is handled (for an edge corresponding - * to an exception handler). - *
- */ - final int info; - - /** - * The successor block of this control flow graph edge. - */ - final Label successor; - - /** - * The next edge in the list of outgoing edges of a basic block. See {@link Label#outgoingEdges}. - */ - Edge nextEdge; - - /** - * Constructs a new Edge. - * - * @param info see {@link #info}. - * @param successor see {@link #successor}. - * @param nextEdge see {@link #nextEdge}. - */ - Edge(final int info, final Label successor, final Edge nextEdge) { - this.info = info; - this.successor = successor; - this.nextEdge = nextEdge; - } -} diff --git a/src/main/java/org/objectweb/asm/FieldVisitor.java b/src/main/java/org/objectweb/asm/FieldVisitor.java deleted file mode 100644 index e2f2979a..00000000 --- a/src/main/java/org/objectweb/asm/FieldVisitor.java +++ /dev/null @@ -1,135 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A visitor to visit a Java field. The methods of this class must be called in the following order: - * ( visitAnnotation | visitTypeAnnotation | visitAttribute )* - * visitEnd. - * - * @author Eric Bruneton - */ -public abstract class FieldVisitor { - - /** - * The ASM API version implemented by this visitor. The value of this field must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - protected final int api; - - /** - * The field visitor to which this visitor must delegate method calls. May be null. - */ - protected FieldVisitor fv; - - /** - * Constructs a new {@link FieldVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - public FieldVisitor(final int api) { - this(api, null); - } - - /** - * Constructs a new {@link FieldVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param fieldVisitor the field visitor to which this visitor must delegate method calls. May be - * null. - */ - public FieldVisitor(final int api, final FieldVisitor fieldVisitor) { - if (api < Opcodes.ASM4 || api > Opcodes.ASM6) { - throw new IllegalArgumentException(); - } - this.api = api; - this.fv = fieldVisitor; - } - - /** - * Visits an annotation of the field. - * - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { - if (fv != null) { - return fv.visitAnnotation(descriptor, visible); - } - return null; - } - - /** - * Visits an annotation on the type of the field. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#FIELD}. See {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or - * static inner type within 'typeRef'. May be null if the annotation targets - * 'typeRef' as a whole. - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitTypeAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(); - } - if (fv != null) { - return fv.visitTypeAnnotation(typeRef, typePath, descriptor, visible); - } - return null; - } - - /** - * Visits a non standard attribute of the field. - * - * @param attribute an attribute. - */ - public void visitAttribute(final Attribute attribute) { - if (fv != null) { - fv.visitAttribute(attribute); - } - } - - /** - * Visits the end of the field. This method, which is the last one to be called, is used to inform - * the visitor that all the annotations and attributes of the field have been visited. - */ - public void visitEnd() { - if (fv != null) { - fv.visitEnd(); - } - } -} diff --git a/src/main/java/org/objectweb/asm/FieldWriter.java b/src/main/java/org/objectweb/asm/FieldWriter.java deleted file mode 100644 index f57a0eef..00000000 --- a/src/main/java/org/objectweb/asm/FieldWriter.java +++ /dev/null @@ -1,352 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A {@link FieldVisitor} that generates a corresponding 'field_info' structure, as defined in the - * Java Virtual Machine Specification (JVMS). - * - * @author Eric Bruneton - * @see JVMS - * 4.5 - */ -final class FieldWriter extends FieldVisitor { - - /** - * Where the constants used in this FieldWriter must be stored. - */ - private final SymbolTable symbolTable; - - // Note: fields are ordered as in the field_info structure, and those related to attributes are - // ordered as in Section 4.7 of the JVMS. - - /** - * The access_flags field of the field_info JVMS structure. This field can contain ASM specific - * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the - * ClassFile structure. - */ - private final int accessFlags; - - /** - * The name_index field of the field_info JVMS structure. - */ - private final int nameIndex; - - /** - * The descriptor_index field of the field_info JVMS structure. - */ - private final int descriptorIndex; - - /** - * The signature_index field of the Signature attribute of this field_info, or 0 if there is no - * Signature attribute. - */ - private int signatureIndex; - - /** - * The constantvalue_index field of the ConstantValue attribute of this field_info, or 0 if there - * is no ConstantValue attribute. - */ - private int constantValueIndex; - - /** - * The last runtime visible annotation of this field. The previous ones can be accessed with the - * {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeVisibleAnnotation; - - /** - * The last runtime invisible annotation of this field. The previous ones can be accessed with the - * {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeInvisibleAnnotation; - - /** - * The last runtime visible type annotation of this field. The previous ones can be accessed with - * the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeVisibleTypeAnnotation; - - /** - * The last runtime invisible type annotation of this field. The previous ones can be accessed - * with the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeInvisibleTypeAnnotation; - - /** - * The first non standard attribute of this field. The next ones can be accessed with the {@link - * Attribute#nextAttribute} field. May be null. - * - *

WARNING: this list stores the attributes in the reverse order of their visit. - * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link - * #putFieldInfo} method writes the attributes in the order defined by this list, i.e. in the - * reverse order specified by the user. - */ - private Attribute firstAttribute; - - // ----------------------------------------------------------------------------------------------- - // Constructor - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a new {@link FieldWriter}. - * - * @param symbolTable where the constants used in this FieldWriter must be stored. - * @param access the field's access flags (see {@link Opcodes}). - * @param name the field's name. - * @param descriptor the field's descriptor (see {@link Type}). - * @param signature the field's signature. May be null. - * @param constantValue the field's constant value. May be null. - */ - FieldWriter( - final SymbolTable symbolTable, - final int access, - final String name, - final String descriptor, - final String signature, - final Object constantValue) { - super(Opcodes.ASM6); - this.symbolTable = symbolTable; - this.accessFlags = access; - this.nameIndex = symbolTable.addConstantUtf8(name); - this.descriptorIndex = symbolTable.addConstantUtf8(descriptor); - if (signature != null) { - this.signatureIndex = symbolTable.addConstantUtf8(signature); - } - if (constantValue != null) { - this.constantValueIndex = symbolTable.addConstant(constantValue).index; - } - } - - // ----------------------------------------------------------------------------------------------- - // Implementation of the FieldVisitor abstract class - // ----------------------------------------------------------------------------------------------- - - @Override - public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { - // Create a ByteVector to hold an 'annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16. - ByteVector annotation = new ByteVector(); - // Write type_index and reserve space for num_element_value_pairs. - annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastRuntimeVisibleAnnotation = - new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation); - } else { - return lastRuntimeInvisibleAnnotation = - new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation); - } - } - - @Override - public AnnotationVisitor visitTypeAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - // Create a ByteVector to hold a 'type_annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. - ByteVector typeAnnotation = new ByteVector(); - // Write target_type, target_info, and target_path. - TypeReference.putTarget(typeRef, typeAnnotation); - TypePath.put(typePath, typeAnnotation); - // Write type_index and reserve space for num_element_value_pairs. - typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastRuntimeVisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation); - } else { - return lastRuntimeInvisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation); - } - } - - @Override - public void visitAttribute(final Attribute attribute) { - // Store the attributes in the reverse order of their visit by this method. - attribute.nextAttribute = firstAttribute; - firstAttribute = attribute; - } - - @Override - public void visitEnd() { - // Nothing to do. - } - - // ----------------------------------------------------------------------------------------------- - // Utility methods - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the size of the field_info JVMS structure generated by this FieldWriter. Also adds the - * names of the attributes of this field in the constant pool. - * - * @return the size in bytes of the field_info JVMS structure. - */ - int computeFieldInfoSize() { - // The access_flags, name_index, descriptor_index and attributes_count fields use 8 bytes. - int size = 8; - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - if (constantValueIndex != 0) { - // ConstantValue attributes always use 8 bytes. - symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE); - size += 8; - } - // Before Java 1.5, synthetic fields are represented with a Synthetic attribute. - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 - && symbolTable.getMajorVersion() < Opcodes.V1_5) { - // Synthetic attributes always use 6 bytes. - symbolTable.addConstantUtf8(Constants.SYNTHETIC); - size += 6; - } - if (signatureIndex != 0) { - // Signature attributes always use 8 bytes. - symbolTable.addConstantUtf8(Constants.SIGNATURE); - size += 8; - } - // ACC_DEPRECATED is ASM specific, the ClassFile format uses a Deprecated attribute instead. - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - // Deprecated attributes always use 6 bytes. - symbolTable.addConstantUtf8(Constants.DEPRECATED); - size += 6; - } - if (lastRuntimeVisibleAnnotation != null) { - size += - lastRuntimeVisibleAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_ANNOTATIONS); - } - if (lastRuntimeInvisibleAnnotation != null) { - size += - lastRuntimeInvisibleAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_ANNOTATIONS); - } - if (lastRuntimeVisibleTypeAnnotation != null) { - size += - lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - size += - lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); - } - if (firstAttribute != null) { - size += firstAttribute.computeAttributesSize(symbolTable); - } - return size; - } - - /** - * Puts the content of the field_info JVMS structure generated by this FieldWriter into the given - * ByteVector. - * - * @param output where the field_info structure must be put. - */ - void putFieldInfo(final ByteVector output) { - boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5; - // Put the access_flags, name_index and descriptor_index fields. - int mask = useSyntheticAttribute ? Opcodes.ACC_SYNTHETIC : 0; - output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex); - // Compute and put the attributes_count field. - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - int attributesCount = 0; - if (constantValueIndex != 0) { - ++attributesCount; - } - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) { - ++attributesCount; - } - if (signatureIndex != 0) { - ++attributesCount; - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - ++attributesCount; - } - if (lastRuntimeVisibleAnnotation != null) { - ++attributesCount; - } - if (lastRuntimeInvisibleAnnotation != null) { - ++attributesCount; - } - if (lastRuntimeVisibleTypeAnnotation != null) { - ++attributesCount; - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - ++attributesCount; - } - if (firstAttribute != null) { - attributesCount += firstAttribute.getAttributeCount(); - } - output.putShort(attributesCount); - // Put the field_info attributes. - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - if (constantValueIndex != 0) { - output - .putShort(symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE)) - .putInt(2) - .putShort(constantValueIndex); - } - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) { - output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0); - } - if (signatureIndex != 0) { - output - .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE)) - .putInt(2) - .putShort(signatureIndex); - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0); - } - if (lastRuntimeVisibleAnnotation != null) { - lastRuntimeVisibleAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output); - } - if (lastRuntimeInvisibleAnnotation != null) { - lastRuntimeInvisibleAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output); - } - if (lastRuntimeVisibleTypeAnnotation != null) { - lastRuntimeVisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output); - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - lastRuntimeInvisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output); - } - if (firstAttribute != null) { - firstAttribute.putAttributes(symbolTable, output); - } - } - - /** - * Collects the attributes of this field into the given set of attribute prototypes. - * - * @param attributePrototypes a set of attribute prototypes. - */ - final void collectAttributePrototypes(final Attribute.Set attributePrototypes) { - attributePrototypes.addAttributes(firstAttribute); - } -} diff --git a/src/main/java/org/objectweb/asm/Frame.java b/src/main/java/org/objectweb/asm/Frame.java deleted file mode 100644 index a729f37c..00000000 --- a/src/main/java/org/objectweb/asm/Frame.java +++ /dev/null @@ -1,1484 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * The input and output stack map frames of a basic block. - * - *

Stack map frames are computed in two steps: - * - *

    - *
  • During the visit of each instruction in MethodWriter, the state of the frame at the end of - * the current basic block is updated by simulating the action of the instruction on the - * previous state of this so called "output frame". - *
  • After all instructions have been visited, a fix point algorithm is used in MethodWriter to - * compute the "input frame" of each basic block (i.e. the stack map frame at the beginning of - * the basic block). See {@link MethodWriter#computeAllFrames}. - *
- * - *

Output stack map frames are computed relatively to the input frame of the basic block, which - * is not yet known when output frames are computed. It is therefore necessary to be able to - * represent abstract types such as "the type at position x in the input frame locals" or "the type - * at position x from the top of the input frame stack" or even "the type at position x in the input - * frame, with y more (or less) array dimensions". This explains the rather complicated type format - * used in this class, explained below. - * - *

The local variables and the operand stack of input and output frames contain values called - * "abstract types" hereafter. An abstract type is represented with 4 fields named DIM, KIND, FLAGS - * and VALUE, packed in a single int value for better performance and memory efficiency: - * - *

- *   =====================================
- *   |.DIM|KIND|FLAG|...............VALUE|
- *   =====================================
- * 
- * - *
    - *
  • the DIM field, stored in the 4 most significant bits, is a signed number of array - * dimensions (from -8 to 7, included). It can be retrieved with {@link #DIM_MASK} and a right - * shift of {@link #DIM_SHIFT}. - *
  • the KIND field, stored in 4 bits, indicates the kind of VALUE used. These 4 bits can be - * retrieved with {@link #KIND_MASK} and, without any shift, must be equal to {@link - * #CONSTANT_KIND}, {@link #REFERENCE_KIND}, {@link #UNINITIALIZED_KIND}, {@link #LOCAL_KIND} - * or {@link #STACK_KIND}. - *
  • the FLAGS field, stored in 4 bits, contains up to 4 boolean flags. Currently only one flag - * is defined, namely {@link #TOP_IF_LONG_OR_DOUBLE_FLAG}. - *
  • the VALUE field, stored in the remaining 20 bits, contains either - *
      - *
    • one of the constants {@link #ITEM_TOP}, {@link #ITEM_ASM_BOOLEAN}, {@link - * #ITEM_ASM_BYTE}, {@link #ITEM_ASM_CHAR} or {@link #ITEM_ASM_SHORT}, {@link - * #ITEM_INTEGER}, {@link #ITEM_FLOAT}, {@link #ITEM_LONG}, {@link #ITEM_DOUBLE}, {@link - * #ITEM_NULL} or {@link #ITEM_UNINITIALIZED_THIS}, if KIND is equal to {@link - * #CONSTANT_KIND}. - *
    • the index of a {@link Symbol#TYPE_TAG} {@link Symbol} in the type table of a {@link - * SymbolTable}, if KIND is equal to {@link #REFERENCE_KIND}. - *
    • the index of an {@link Symbol#UNINITIALIZED_TYPE_TAG} {@link Symbol} in the type - * table of a SymbolTable, if KIND is equal to {@link #UNINITIALIZED_KIND}. - *
    • the index of a local variable in the input stack frame, if KIND is equal to {@link - * #LOCAL_KIND}. - *
    • a position relatively to the top of the stack of the input stack frame, if KIND is - * equal to {@link #STACK_KIND}, - *
    - *
- * - *

Output frames can contain abstract types of any kind and with a positive or negative array - * dimension (and even unassigned types, represented by 0 - which does not correspond to any valid - * abstract type value). Input frames can only contain CONSTANT_KIND, REFERENCE_KIND or - * UNINITIALIZED_KIND abstract types of positive or null array dimension. In all cases the type - * table contains only internal type names (array type descriptors are forbidden - array dimensions - * must be represented through the DIM field). - * - *

The LONG and DOUBLE types are always represented by using two slots (LONG + TOP or DOUBLE + - * TOP), for local variables as well as in the operand stack. This is necessary to be able to - * simulate DUPx_y instructions, whose effect would be dependent on the concrete types represented - * by the abstract types in the stack (which are not always known). - * - * @author Eric Bruneton - */ -class Frame { - - // Constants used in the StackMapTable attribute. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.4. - - static final int SAME_FRAME = 0; - static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; - static final int RESERVED = 128; - static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; - static final int CHOP_FRAME = 248; - static final int SAME_FRAME_EXTENDED = 251; - static final int APPEND_FRAME = 252; - static final int FULL_FRAME = 255; - - static final int ITEM_TOP = 0; - static final int ITEM_INTEGER = 1; - static final int ITEM_FLOAT = 2; - static final int ITEM_DOUBLE = 3; - static final int ITEM_LONG = 4; - static final int ITEM_NULL = 5; - static final int ITEM_UNINITIALIZED_THIS = 6; - static final int ITEM_OBJECT = 7; - static final int ITEM_UNINITIALIZED = 8; - // Additional, ASM specific constants used in abstract types below. - private static final int ITEM_ASM_BOOLEAN = 9; - private static final int ITEM_ASM_BYTE = 10; - private static final int ITEM_ASM_CHAR = 11; - private static final int ITEM_ASM_SHORT = 12; - - // Bitmasks to get each field of an abstract type. - - private static final int DIM_MASK = 0xF0000000; - private static final int KIND_MASK = 0x0F000000; - private static final int FLAGS_MASK = 0x00F00000; - private static final int VALUE_MASK = 0x000FFFFF; - - // Constants to manipulate the DIM field of an abstract type. - - /** - * The number of right shift bits to use to get the array dimensions of an abstract type. - */ - private static final int DIM_SHIFT = 28; - - /** - * The constant to be added to an abstract type to get one with one more array dimension. - */ - private static final int ARRAY_OF = +1 << DIM_SHIFT; - - /** - * The constant to be added to an abstract type to get one with one less array dimension. - */ - private static final int ELEMENT_OF = -1 << DIM_SHIFT; - - // Possible values for the KIND field of an abstract type. - - private static final int CONSTANT_KIND = 0x01000000; - private static final int REFERENCE_KIND = 0x02000000; - private static final int UNINITIALIZED_KIND = 0x03000000; - private static final int LOCAL_KIND = 0x04000000; - private static final int STACK_KIND = 0x05000000; - - // Possible flags for the FLAGS field of an abstract type. - - /** - * A flag used for LOCAL_KIND and STACK_KIND abstract types, indicating that if the resolved, - * concrete type is LONG or DOUBLE, TOP should be used instead (because the value has been - * partially overridden with an xSTORE instruction). - */ - private static final int TOP_IF_LONG_OR_DOUBLE_FLAG = 0x00100000 & FLAGS_MASK; - - // Useful predefined abstract types (all the possible CONSTANT_KIND types). - - private static final int TOP = CONSTANT_KIND | ITEM_TOP; - private static final int BOOLEAN = CONSTANT_KIND | ITEM_ASM_BOOLEAN; - private static final int BYTE = CONSTANT_KIND | ITEM_ASM_BYTE; - private static final int CHAR = CONSTANT_KIND | ITEM_ASM_CHAR; - private static final int SHORT = CONSTANT_KIND | ITEM_ASM_SHORT; - private static final int INTEGER = CONSTANT_KIND | ITEM_INTEGER; - private static final int FLOAT = CONSTANT_KIND | ITEM_FLOAT; - private static final int LONG = CONSTANT_KIND | ITEM_LONG; - private static final int DOUBLE = CONSTANT_KIND | ITEM_DOUBLE; - private static final int NULL = CONSTANT_KIND | ITEM_NULL; - private static final int UNINITIALIZED_THIS = CONSTANT_KIND | ITEM_UNINITIALIZED_THIS; - - // ----------------------------------------------------------------------------------------------- - // Instance fields - // ----------------------------------------------------------------------------------------------- - - /** - * The basic block to which these input and output stack map frames correspond. - */ - Label owner; - - /** - * The input stack map frame locals. This is an array of abstract types. - */ - private int[] inputLocals; - - /** - * The input stack map frame stack. This is an array of abstract types. - */ - private int[] inputStack; - - /** - * The output stack map frame locals. This is an array of abstract types. - */ - private int[] outputLocals; - - /** - * The output stack map frame stack. This is an array of abstract types. - */ - private int[] outputStack; - - /** - * The start of the output stack, relatively to the input stack. This offset is always negative or - * null. A null offset means that the output stack must be appended to the input stack. A -n - * offset means that the first n output stack elements must replace the top n input stack - * elements, and that the other elements must be appended to the input stack. - */ - private short outputStackStart; - - /** - * The index of the top stack element in {@link #outputStack}. - */ - private short outputStackTop; - - /** - * The number of types that are initialized in the basic block. See {@link #initializations}. - */ - private int initializationCount; - - /** - * The abstract types that are initialized in the basic block. A constructor invocation on an - * UNINITIALIZED or UNINITIALIZED_THIS abstract type must replace every occurrence of this - * type in the local variables and in the operand stack. This cannot be done during the first step - * of the algorithm since, during this step, the local variables and the operand stack types are - * still abstract. It is therefore necessary to store the abstract types of the constructors which - * are invoked in the basic block, in order to do this replacement during the second step of the - * algorithm, where the frames are fully computed. Note that this array can contain abstract types - * that are relative to the input locals or to the input stack. - */ - private int[] initializations; - - // ----------------------------------------------------------------------------------------------- - // Static methods to get abstract types from other type formats - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the abstract type corresponding to the given public API frame element type. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param type a frame element type described using the same format as in {@link - * MethodVisitor#visitFrame}, i.e. either {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link - * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL}, or - * {@link Opcodes#UNINITIALIZED_THIS}, or the internal name of a class, or a Label designating - * a NEW instruction (for uninitialized types). - * @return the abstract type corresponding to the given frame element type. - */ - static int getAbstractTypeFromApiFormat(final SymbolTable symbolTable, final Object type) { - if (type instanceof Integer) { - return CONSTANT_KIND | ((Integer) type).intValue(); - } else if (type instanceof String) { - String descriptor = Type.getObjectType((String) type).getDescriptor(); - return getAbstractTypeFromDescriptor(symbolTable, descriptor, 0); - } else { - return UNINITIALIZED_KIND - | symbolTable.addUninitializedType("", ((Label) type).bytecodeOffset); - } - } - - /** - * Returns the abstract type corresponding to the internal name of a class. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param internalName the internal name of a class. This must not be an array type - * descriptor. - * @return the abstract type value corresponding to the given internal name. - */ - static int getAbstractTypeFromInternalName( - final SymbolTable symbolTable, final String internalName) { - return REFERENCE_KIND | symbolTable.addType(internalName); - } - - /** - * Returns the abstract type corresponding to the given type descriptor. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param buffer a string ending with a type descriptor. - * @param offset the start offset of the type descriptor in buffer. - * @return the abstract type corresponding to the given type descriptor. - */ - private static int getAbstractTypeFromDescriptor( - final SymbolTable symbolTable, final String buffer, final int offset) { - String internalName; - switch (buffer.charAt(offset)) { - case 'V': - return 0; - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - return INTEGER; - case 'F': - return FLOAT; - case 'J': - return LONG; - case 'D': - return DOUBLE; - case 'L': - internalName = buffer.substring(offset + 1, buffer.length() - 1); - return REFERENCE_KIND | symbolTable.addType(internalName); - case '[': - int elementDescriptorOffset = offset + 1; - while (buffer.charAt(elementDescriptorOffset) == '[') { - ++elementDescriptorOffset; - } - int typeValue; - switch (buffer.charAt(elementDescriptorOffset)) { - case 'Z': - typeValue = BOOLEAN; - break; - case 'C': - typeValue = CHAR; - break; - case 'B': - typeValue = BYTE; - break; - case 'S': - typeValue = SHORT; - break; - case 'I': - typeValue = INTEGER; - break; - case 'F': - typeValue = FLOAT; - break; - case 'J': - typeValue = LONG; - break; - case 'D': - typeValue = DOUBLE; - break; - case 'L': - internalName = buffer.substring(elementDescriptorOffset + 1, buffer.length() - 1); - typeValue = REFERENCE_KIND | symbolTable.addType(internalName); - break; - default: - throw new IllegalArgumentException(); - } - return ((elementDescriptorOffset - offset) << DIM_SHIFT) | typeValue; - default: - throw new IllegalArgumentException(); - } - } - - // ----------------------------------------------------------------------------------------------- - // Constructor - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a new Frame. - * - * @param owner the basic block to which these input and output stack map frames correspond. - */ - Frame(final Label owner) { - this.owner = owner; - } - - /** - * Sets this frame to the value of the given frame. - * - *

WARNING: after this method is called the two frames share the same data structures. It is - * recommended to discard the given frame to avoid unexpected side effects. - * - * @param frame The new frame value. - */ - final void copyFrom(final Frame frame) { - inputLocals = frame.inputLocals; - inputStack = frame.inputStack; - outputStackStart = 0; - outputLocals = frame.outputLocals; - outputStack = frame.outputStack; - outputStackTop = frame.outputStackTop; - initializationCount = frame.initializationCount; - initializations = frame.initializations; - } - - // ----------------------------------------------------------------------------------------------- - // Methods related to the input frame - // ----------------------------------------------------------------------------------------------- - - /** - * Sets the input frame from the given method description. This method is used to initialize the - * first frame of a method, which is implicit (i.e. not stored explicitly in the StackMapTable - * attribute). - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param access the method's access flags. - * @param descriptor the method descriptor. - * @param maxLocals the maximum number of local variables of the method. - */ - final void setInputFrameFromDescriptor( - final SymbolTable symbolTable, - final int access, - final String descriptor, - final int maxLocals) { - inputLocals = new int[maxLocals]; - inputStack = new int[0]; - int inputLocalIndex = 0; - if ((access & Opcodes.ACC_STATIC) == 0) { - if ((access & Constants.ACC_CONSTRUCTOR) == 0) { - inputLocals[inputLocalIndex++] = - REFERENCE_KIND | symbolTable.addType(symbolTable.getClassName()); - } else { - inputLocals[inputLocalIndex++] = UNINITIALIZED_THIS; - } - } - for (Type argumentType : Type.getArgumentTypes(descriptor)) { - int abstractType = - getAbstractTypeFromDescriptor(symbolTable, argumentType.getDescriptor(), 0); - inputLocals[inputLocalIndex++] = abstractType; - if (abstractType == LONG || abstractType == DOUBLE) { - inputLocals[inputLocalIndex++] = TOP; - } - } - while (inputLocalIndex < maxLocals) { - inputLocals[inputLocalIndex++] = TOP; - } - } - - /** - * Sets the input frame from the given public API frame description. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param nLocal the number of local variables. - * @param local the local variable types, described using the same format as in {@link - * MethodVisitor#visitFrame}. - * @param nStack the number of operand stack elements. - * @param stack the operand stack types, described using the same format as in {@link - * MethodVisitor#visitFrame}. - */ - final void setInputFrameFromApiFormat( - final SymbolTable symbolTable, - final int nLocal, - final Object[] local, - final int nStack, - final Object[] stack) { - int inputLocalIndex = 0; - for (int i = 0; i < nLocal; ++i) { - inputLocals[inputLocalIndex++] = getAbstractTypeFromApiFormat(symbolTable, local[i]); - if (local[i] == Opcodes.LONG || local[i] == Opcodes.DOUBLE) { - inputLocals[inputLocalIndex++] = TOP; - } - } - while (inputLocalIndex < inputLocals.length) { - inputLocals[inputLocalIndex++] = TOP; - } - int nStackTop = 0; - for (int i = 0; i < nStack; ++i) { - if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) { - ++nStackTop; - } - } - inputStack = new int[nStack + nStackTop]; - int inputStackIndex = 0; - for (int i = 0; i < nStack; ++i) { - inputStack[inputStackIndex++] = getAbstractTypeFromApiFormat(symbolTable, stack[i]); - if (stack[i] == Opcodes.LONG || stack[i] == Opcodes.DOUBLE) { - inputStack[inputStackIndex++] = TOP; - } - } - outputStackTop = 0; - initializationCount = 0; - } - - final int getInputStackSize() { - return inputStack.length; - } - - // ----------------------------------------------------------------------------------------------- - // Methods related to the output frame - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the abstract type stored at the given local variable index in the output frame. - * - * @param localIndex the index of the local variable whose value must be returned. - * @return the abstract type stored at the given local variable index in the output frame. - */ - private int getLocal(final int localIndex) { - if (outputLocals == null || localIndex >= outputLocals.length) { - // If this local has never been assigned in this basic block, it is still equal to its value - // in the input frame. - return LOCAL_KIND | localIndex; - } else { - int abstractType = outputLocals[localIndex]; - if (abstractType == 0) { - // If this local has never been assigned in this basic block, so it is still equal to its - // value in the input frame. - abstractType = outputLocals[localIndex] = LOCAL_KIND | localIndex; - } - return abstractType; - } - } - - /** - * Replaces the abstract type stored at the given local variable index in the output frame. - * - * @param localIndex the index of the output frame local variable that must be set. - * @param abstractType the value that must be set. - */ - private void setLocal(final int localIndex, final int abstractType) { - // Create and/or resize the output local variables array if necessary. - if (outputLocals == null) { - outputLocals = new int[10]; - } - int outputLocalsLength = outputLocals.length; - if (localIndex >= outputLocalsLength) { - int[] newOutputLocals = new int[Math.max(localIndex + 1, 2 * outputLocalsLength)]; - System.arraycopy(outputLocals, 0, newOutputLocals, 0, outputLocalsLength); - outputLocals = newOutputLocals; - } - // Set the local variable. - outputLocals[localIndex] = abstractType; - } - - /** - * Pushes the given abstract type on the output frame stack. - * - * @param abstractType an abstract type. - */ - private void push(final int abstractType) { - // Create and/or resize the output stack array if necessary. - if (outputStack == null) { - outputStack = new int[10]; - } - int outputStackLength = outputStack.length; - if (outputStackTop >= outputStackLength) { - int[] newOutputStack = new int[Math.max(outputStackTop + 1, 2 * outputStackLength)]; - System.arraycopy(outputStack, 0, newOutputStack, 0, outputStackLength); - outputStack = newOutputStack; - } - // Pushes the abstract type on the output stack. - outputStack[outputStackTop++] = abstractType; - // Updates the maximum size reached by the output stack, if needed (note that this size is - // relative to the input stack size, which is not known yet). - short outputStackSize = (short) (outputStackStart + outputStackTop); - if (outputStackSize > owner.outputStackMax) { - owner.outputStackMax = outputStackSize; - } - } - - /** - * Pushes the abstract type corresponding to the given descriptor on the output frame stack. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param descriptor a type or method descriptor (in which case its return type is pushed). - */ - private void push(final SymbolTable symbolTable, final String descriptor) { - int typeDescriptorOffset = descriptor.charAt(0) == '(' ? descriptor.indexOf(')') + 1 : 0; - int abstractType = getAbstractTypeFromDescriptor(symbolTable, descriptor, typeDescriptorOffset); - if (abstractType != 0) { - push(abstractType); - if (abstractType == LONG || abstractType == DOUBLE) { - push(TOP); - } - } - } - - /** - * Pops an abstract type from the output frame stack and returns its value. - * - * @return the abstract type that has been popped from the output frame stack. - */ - private int pop() { - if (outputStackTop > 0) { - return outputStack[--outputStackTop]; - } else { - // If the output frame stack is empty, pop from the input stack. - return STACK_KIND | -(--outputStackStart); - } - } - - /** - * Pops the given number of abstract types from the output frame stack. - * - * @param elements the number of abstract types that must be popped. - */ - private void pop(final int elements) { - if (outputStackTop >= elements) { - outputStackTop -= elements; - } else { - // If the number of elements to be popped is greater than the number of elements in the output - // stack, clear it, and pop the remaining elements from the input stack. - outputStackStart -= elements - outputStackTop; - outputStackTop = 0; - } - } - - /** - * Pops as many abstract types from the output frame stack as described by the given descriptor. - * - * @param descriptor a type or method descriptor (in which case its argument types are popped). - */ - private void pop(final String descriptor) { - char firstDescriptorChar = descriptor.charAt(0); - if (firstDescriptorChar == '(') { - pop((Type.getArgumentsAndReturnSizes(descriptor) >> 2) - 1); - } else if (firstDescriptorChar == 'J' || firstDescriptorChar == 'D') { - pop(2); - } else { - pop(1); - } - } - - // ----------------------------------------------------------------------------------------------- - // Methods to handle uninitialized types - // ----------------------------------------------------------------------------------------------- - - /** - * Adds an abstract type to the list of types on which a constructor is invoked in the basic - * block. - * - * @param abstractType an abstract type on a which a constructor is invoked. - */ - private void addInitializedType(final int abstractType) { - // Create and/or resize the initializations array if necessary. - if (initializations == null) { - initializations = new int[2]; - } - int initializationsLength = initializations.length; - if (initializationCount >= initializationsLength) { - int[] newInitializations = - new int[Math.max(initializationCount + 1, 2 * initializationsLength)]; - System.arraycopy(initializations, 0, newInitializations, 0, initializationsLength); - initializations = newInitializations; - } - // Store the abstract type. - initializations[initializationCount++] = abstractType; - } - - /** - * Returns the "initialized" abstract type corresponding to the given abstract type. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param abstractType an abstract type. - * @return the REFERENCE_KIND abstract type corresponding to abstractType if it is - * UNINITIALIZED_THIS or an UNINITIALIZED_KIND abstract type for one of the types on which a - * constructor is invoked in the basic block. Otherwise returns abstractType. - */ - private int getInitializedType(final SymbolTable symbolTable, final int abstractType) { - if (abstractType == UNINITIALIZED_THIS - || (abstractType & (DIM_MASK | KIND_MASK)) == UNINITIALIZED_KIND) { - for (int i = 0; i < initializationCount; ++i) { - int initializedType = initializations[i]; - int dim = initializedType & DIM_MASK; - int kind = initializedType & KIND_MASK; - int value = initializedType & VALUE_MASK; - if (kind == LOCAL_KIND) { - initializedType = dim + inputLocals[value]; - } else if (kind == STACK_KIND) { - initializedType = dim + inputStack[inputStack.length - value]; - } - if (abstractType == initializedType) { - if (abstractType == UNINITIALIZED_THIS) { - return REFERENCE_KIND | symbolTable.addType(symbolTable.getClassName()); - } else { - return REFERENCE_KIND - | symbolTable.addType(symbolTable.getType(abstractType & VALUE_MASK).value); - } - } - } - } - return abstractType; - } - - // ----------------------------------------------------------------------------------------------- - // Main method, to simulate the execution of each instruction on the output frame - // ----------------------------------------------------------------------------------------------- - - /** - * Simulates the action of the given instruction on the output stack frame. - * - * @param opcode the opcode of the instruction. - * @param arg the numeric operand of the instruction, if any. - * @param argSymbol the Symbol operand of the instruction, if any. - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - */ - void execute( - final int opcode, final int arg, final Symbol argSymbol, final SymbolTable symbolTable) { - // Abstract types popped from the stack or read from local variables. - int abstractType1; - int abstractType2; - int abstractType3; - int abstractType4; - switch (opcode) { - case Opcodes.NOP: - case Opcodes.INEG: - case Opcodes.LNEG: - case Opcodes.FNEG: - case Opcodes.DNEG: - case Opcodes.I2B: - case Opcodes.I2C: - case Opcodes.I2S: - case Opcodes.GOTO: - case Opcodes.RETURN: - break; - case Opcodes.ACONST_NULL: - push(NULL); - break; - case Opcodes.ICONST_M1: - case Opcodes.ICONST_0: - case Opcodes.ICONST_1: - case Opcodes.ICONST_2: - case Opcodes.ICONST_3: - case Opcodes.ICONST_4: - case Opcodes.ICONST_5: - case Opcodes.BIPUSH: - case Opcodes.SIPUSH: - case Opcodes.ILOAD: - push(INTEGER); - break; - case Opcodes.LCONST_0: - case Opcodes.LCONST_1: - case Opcodes.LLOAD: - push(LONG); - push(TOP); - break; - case Opcodes.FCONST_0: - case Opcodes.FCONST_1: - case Opcodes.FCONST_2: - case Opcodes.FLOAD: - push(FLOAT); - break; - case Opcodes.DCONST_0: - case Opcodes.DCONST_1: - case Opcodes.DLOAD: - push(DOUBLE); - push(TOP); - break; - case Opcodes.LDC: - switch (argSymbol.tag) { - case Symbol.CONSTANT_INTEGER_TAG: - push(INTEGER); - break; - case Symbol.CONSTANT_LONG_TAG: - push(LONG); - push(TOP); - break; - case Symbol.CONSTANT_FLOAT_TAG: - push(FLOAT); - break; - case Symbol.CONSTANT_DOUBLE_TAG: - push(DOUBLE); - push(TOP); - break; - case Symbol.CONSTANT_CLASS_TAG: - push(REFERENCE_KIND | symbolTable.addType("java/lang/Class")); - break; - case Symbol.CONSTANT_STRING_TAG: - push(REFERENCE_KIND | symbolTable.addType("java/lang/String")); - break; - case Symbol.CONSTANT_METHOD_TYPE_TAG: - push(REFERENCE_KIND | symbolTable.addType("java/lang/invoke/MethodType")); - break; - case Symbol.CONSTANT_METHOD_HANDLE_TAG: - push(REFERENCE_KIND | symbolTable.addType("java/lang/invoke/MethodHandle")); - break; - default: - throw new AssertionError(); - } - break; - case Opcodes.ALOAD: - push(getLocal(arg)); - break; - case Opcodes.LALOAD: - case Opcodes.D2L: - pop(2); - push(LONG); - push(TOP); - break; - case Opcodes.DALOAD: - case Opcodes.L2D: - pop(2); - push(DOUBLE); - push(TOP); - break; - case Opcodes.AALOAD: - pop(1); - abstractType1 = pop(); - push(abstractType1 == NULL ? abstractType1 : ELEMENT_OF + abstractType1); - break; - case Opcodes.ISTORE: - case Opcodes.FSTORE: - case Opcodes.ASTORE: - abstractType1 = pop(); - setLocal(arg, abstractType1); - if (arg > 0) { - int previousLocalType = getLocal(arg - 1); - if (previousLocalType == LONG || previousLocalType == DOUBLE) { - setLocal(arg - 1, TOP); - } else if ((previousLocalType & KIND_MASK) == LOCAL_KIND - || (previousLocalType & KIND_MASK) == STACK_KIND) { - // The type of the previous local variable is not known yet, but if it later appears - // to be LONG or DOUBLE, we should then use TOP instead. - setLocal(arg - 1, previousLocalType | TOP_IF_LONG_OR_DOUBLE_FLAG); - } - } - break; - case Opcodes.LSTORE: - case Opcodes.DSTORE: - pop(1); - abstractType1 = pop(); - setLocal(arg, abstractType1); - setLocal(arg + 1, TOP); - if (arg > 0) { - int previousLocalType = getLocal(arg - 1); - if (previousLocalType == LONG || previousLocalType == DOUBLE) { - setLocal(arg - 1, TOP); - } else if ((previousLocalType & KIND_MASK) == LOCAL_KIND - || (previousLocalType & KIND_MASK) == STACK_KIND) { - // The type of the previous local variable is not known yet, but if it later appears - // to be LONG or DOUBLE, we should then use TOP instead. - setLocal(arg - 1, previousLocalType | TOP_IF_LONG_OR_DOUBLE_FLAG); - } - } - break; - case Opcodes.IASTORE: - case Opcodes.BASTORE: - case Opcodes.CASTORE: - case Opcodes.SASTORE: - case Opcodes.FASTORE: - case Opcodes.AASTORE: - pop(3); - break; - case Opcodes.LASTORE: - case Opcodes.DASTORE: - pop(4); - break; - case Opcodes.POP: - case Opcodes.IFEQ: - case Opcodes.IFNE: - case Opcodes.IFLT: - case Opcodes.IFGE: - case Opcodes.IFGT: - case Opcodes.IFLE: - case Opcodes.IRETURN: - case Opcodes.FRETURN: - case Opcodes.ARETURN: - case Opcodes.TABLESWITCH: - case Opcodes.LOOKUPSWITCH: - case Opcodes.ATHROW: - case Opcodes.MONITORENTER: - case Opcodes.MONITOREXIT: - case Opcodes.IFNULL: - case Opcodes.IFNONNULL: - pop(1); - break; - case Opcodes.POP2: - case Opcodes.IF_ICMPEQ: - case Opcodes.IF_ICMPNE: - case Opcodes.IF_ICMPLT: - case Opcodes.IF_ICMPGE: - case Opcodes.IF_ICMPGT: - case Opcodes.IF_ICMPLE: - case Opcodes.IF_ACMPEQ: - case Opcodes.IF_ACMPNE: - case Opcodes.LRETURN: - case Opcodes.DRETURN: - pop(2); - break; - case Opcodes.DUP: - abstractType1 = pop(); - push(abstractType1); - push(abstractType1); - break; - case Opcodes.DUP_X1: - abstractType1 = pop(); - abstractType2 = pop(); - push(abstractType1); - push(abstractType2); - push(abstractType1); - break; - case Opcodes.DUP_X2: - abstractType1 = pop(); - abstractType2 = pop(); - abstractType3 = pop(); - push(abstractType1); - push(abstractType3); - push(abstractType2); - push(abstractType1); - break; - case Opcodes.DUP2: - abstractType1 = pop(); - abstractType2 = pop(); - push(abstractType2); - push(abstractType1); - push(abstractType2); - push(abstractType1); - break; - case Opcodes.DUP2_X1: - abstractType1 = pop(); - abstractType2 = pop(); - abstractType3 = pop(); - push(abstractType2); - push(abstractType1); - push(abstractType3); - push(abstractType2); - push(abstractType1); - break; - case Opcodes.DUP2_X2: - abstractType1 = pop(); - abstractType2 = pop(); - abstractType3 = pop(); - abstractType4 = pop(); - push(abstractType2); - push(abstractType1); - push(abstractType4); - push(abstractType3); - push(abstractType2); - push(abstractType1); - break; - case Opcodes.SWAP: - abstractType1 = pop(); - abstractType2 = pop(); - push(abstractType1); - push(abstractType2); - break; - case Opcodes.IALOAD: - case Opcodes.BALOAD: - case Opcodes.CALOAD: - case Opcodes.SALOAD: - case Opcodes.IADD: - case Opcodes.ISUB: - case Opcodes.IMUL: - case Opcodes.IDIV: - case Opcodes.IREM: - case Opcodes.IAND: - case Opcodes.IOR: - case Opcodes.IXOR: - case Opcodes.ISHL: - case Opcodes.ISHR: - case Opcodes.IUSHR: - case Opcodes.L2I: - case Opcodes.D2I: - case Opcodes.FCMPL: - case Opcodes.FCMPG: - pop(2); - push(INTEGER); - break; - case Opcodes.LADD: - case Opcodes.LSUB: - case Opcodes.LMUL: - case Opcodes.LDIV: - case Opcodes.LREM: - case Opcodes.LAND: - case Opcodes.LOR: - case Opcodes.LXOR: - pop(4); - push(LONG); - push(TOP); - break; - case Opcodes.FALOAD: - case Opcodes.FADD: - case Opcodes.FSUB: - case Opcodes.FMUL: - case Opcodes.FDIV: - case Opcodes.FREM: - case Opcodes.L2F: - case Opcodes.D2F: - pop(2); - push(FLOAT); - break; - case Opcodes.DADD: - case Opcodes.DSUB: - case Opcodes.DMUL: - case Opcodes.DDIV: - case Opcodes.DREM: - pop(4); - push(DOUBLE); - push(TOP); - break; - case Opcodes.LSHL: - case Opcodes.LSHR: - case Opcodes.LUSHR: - pop(3); - push(LONG); - push(TOP); - break; - case Opcodes.IINC: - setLocal(arg, INTEGER); - break; - case Opcodes.I2L: - case Opcodes.F2L: - pop(1); - push(LONG); - push(TOP); - break; - case Opcodes.I2F: - pop(1); - push(FLOAT); - break; - case Opcodes.I2D: - case Opcodes.F2D: - pop(1); - push(DOUBLE); - push(TOP); - break; - case Opcodes.F2I: - case Opcodes.ARRAYLENGTH: - case Opcodes.INSTANCEOF: - pop(1); - push(INTEGER); - break; - case Opcodes.LCMP: - case Opcodes.DCMPL: - case Opcodes.DCMPG: - pop(4); - push(INTEGER); - break; - case Opcodes.JSR: - case Opcodes.RET: - throw new IllegalArgumentException("JSR/RET are not supported with computeFrames option"); - case Opcodes.GETSTATIC: - push(symbolTable, argSymbol.value); - break; - case Opcodes.PUTSTATIC: - pop(argSymbol.value); - break; - case Opcodes.GETFIELD: - pop(1); - push(symbolTable, argSymbol.value); - break; - case Opcodes.PUTFIELD: - pop(argSymbol.value); - pop(); - break; - case Opcodes.INVOKEVIRTUAL: - case Opcodes.INVOKESPECIAL: - case Opcodes.INVOKESTATIC: - case Opcodes.INVOKEINTERFACE: - pop(argSymbol.value); - if (opcode != Opcodes.INVOKESTATIC) { - abstractType1 = pop(); - if (opcode == Opcodes.INVOKESPECIAL && argSymbol.name.charAt(0) == '<') { - addInitializedType(abstractType1); - } - } - push(symbolTable, argSymbol.value); - break; - case Opcodes.INVOKEDYNAMIC: - pop(argSymbol.value); - push(symbolTable, argSymbol.value); - break; - case Opcodes.NEW: - push(UNINITIALIZED_KIND | symbolTable.addUninitializedType(argSymbol.value, arg)); - break; - case Opcodes.NEWARRAY: - pop(); - switch (arg) { - case Opcodes.T_BOOLEAN: - push(ARRAY_OF | BOOLEAN); - break; - case Opcodes.T_CHAR: - push(ARRAY_OF | CHAR); - break; - case Opcodes.T_BYTE: - push(ARRAY_OF | BYTE); - break; - case Opcodes.T_SHORT: - push(ARRAY_OF | SHORT); - break; - case Opcodes.T_INT: - push(ARRAY_OF | INTEGER); - break; - case Opcodes.T_FLOAT: - push(ARRAY_OF | FLOAT); - break; - case Opcodes.T_DOUBLE: - push(ARRAY_OF | DOUBLE); - break; - case Opcodes.T_LONG: - push(ARRAY_OF | LONG); - break; - default: - throw new IllegalArgumentException(); - } - break; - case Opcodes.ANEWARRAY: - String arrayElementType = argSymbol.value; - pop(); - if (arrayElementType.charAt(0) == '[') { - push(symbolTable, '[' + arrayElementType); - } else { - push(ARRAY_OF | REFERENCE_KIND | symbolTable.addType(arrayElementType)); - } - break; - case Opcodes.CHECKCAST: - String castType = argSymbol.value; - pop(); - if (castType.charAt(0) == '[') { - push(symbolTable, castType); - } else { - push(REFERENCE_KIND | symbolTable.addType(castType)); - } - break; - case Opcodes.MULTIANEWARRAY: - pop(arg); - push(symbolTable, argSymbol.value); - break; - default: - throw new IllegalArgumentException(); - } - } - - // ----------------------------------------------------------------------------------------------- - // Frame merging methods, used in the second step of the stack map frame computation algorithm - // ----------------------------------------------------------------------------------------------- - - /** - * Merges the input frame of the given {@link Frame} with the input and output frames of this - * {@link Frame}. Returns true if the given frame has been changed by this operation (the - * input and output frames of this {@link Frame} are never changed). - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param dstFrame the {@link Frame} whose input frame must be updated. This should be the frame - * of a successor, in the control flow graph, of the basic block corresponding to this frame. - * @param catchTypeIndex if 'frame' corresponds to an exception handler basic block, the type - * table index of the caught exception type, otherwise 0. - * @return true if the input frame of 'frame' has been changed by this operation. - */ - final boolean merge( - final SymbolTable symbolTable, final Frame dstFrame, final int catchTypeIndex) { - boolean frameChanged = false; - - // Compute the concrete types of the local variables at the end of the basic block corresponding - // to this frame, by resolving its abstract output types, and merge these concrete types with - // those of the local variables in the input frame of dstFrame. - int nLocal = inputLocals.length; - int nStack = inputStack.length; - if (dstFrame.inputLocals == null) { - dstFrame.inputLocals = new int[nLocal]; - frameChanged = true; - } - for (int i = 0; i < nLocal; ++i) { - int concreteOutputType; - if (outputLocals != null && i < outputLocals.length) { - int abstractOutputType = outputLocals[i]; - if (abstractOutputType == 0) { - // If the local variable has never been assigned in this basic block, it is equal to its - // value at the beginning of the block. - concreteOutputType = inputLocals[i]; - } else { - int dim = abstractOutputType & DIM_MASK; - int kind = abstractOutputType & KIND_MASK; - if (kind == LOCAL_KIND) { - // By definition, a LOCAL_KIND type designates the concrete type of a local variable at - // the beginning of the basic block corresponding to this frame (which is known when - // this method is called, but was not when the abstract type was computed). - concreteOutputType = dim + inputLocals[abstractOutputType & VALUE_MASK]; - if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0 - && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) { - concreteOutputType = TOP; - } - } else if (kind == STACK_KIND) { - // By definition, a STACK_KIND type designates the concrete type of a local variable at - // the beginning of the basic block corresponding to this frame (which is known when - // this method is called, but was not when the abstract type was computed). - concreteOutputType = dim + inputStack[nStack - (abstractOutputType & VALUE_MASK)]; - if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0 - && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) { - concreteOutputType = TOP; - } - } else { - concreteOutputType = abstractOutputType; - } - } - } else { - // If the local variable has never been assigned in this basic block, it is equal to its - // value at the beginning of the block. - concreteOutputType = inputLocals[i]; - } - // concreteOutputType might be an uninitialized type from the input locals or from the input - // stack. However, if a constructor has been called for this class type in the basic block, - // then this type is no longer uninitialized at the end of basic block. - if (initializations != null) { - concreteOutputType = getInitializedType(symbolTable, concreteOutputType); - } - frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputLocals, i); - } - - // If dstFrame is an exception handler block, it can be reached from any instruction of the - // basic block corresponding to this frame, in particular from the first one. Therefore, the - // input locals of dstFrame should be compatible (i.e. merged) with the input locals of this - // frame (and the input stack of dstFrame should be compatible, i.e. merged, with a one - // element stack containing the caught exception type). - if (catchTypeIndex > 0) { - for (int i = 0; i < nLocal; ++i) { - frameChanged |= merge(symbolTable, inputLocals[i], dstFrame.inputLocals, i); - } - if (dstFrame.inputStack == null) { - dstFrame.inputStack = new int[1]; - frameChanged = true; - } - frameChanged |= merge(symbolTable, catchTypeIndex, dstFrame.inputStack, 0); - return frameChanged; - } - - // Compute the concrete types of the stack operands at the end of the basic block corresponding - // to this frame, by resolving its abstract output types, and merge these concrete types with - // those of the stack operands in the input frame of dstFrame. - int nInputStack = inputStack.length + outputStackStart; - if (dstFrame.inputStack == null) { - dstFrame.inputStack = new int[nInputStack + outputStackTop]; - frameChanged = true; - } - // First, do this for the stack operands that have not been popped in the basic block - // corresponding to this frame, and which are therefore equal to their value in the input - // frame (except for uninitialized types, which may have been initialized). - for (int i = 0; i < nInputStack; ++i) { - int concreteOutputType = inputStack[i]; - if (initializations != null) { - concreteOutputType = getInitializedType(symbolTable, concreteOutputType); - } - frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputStack, i); - } - // Then, do this for the stack operands that have pushed in the basic block (this code is the - // same as the one above for local variables). - for (int i = 0; i < outputStackTop; ++i) { - int concreteOutputType; - int abstractOutputType = outputStack[i]; - int dim = abstractOutputType & DIM_MASK; - int kind = abstractOutputType & KIND_MASK; - if (kind == LOCAL_KIND) { - concreteOutputType = dim + inputLocals[abstractOutputType & VALUE_MASK]; - if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0 - && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) { - concreteOutputType = TOP; - } - } else if (kind == STACK_KIND) { - concreteOutputType = dim + inputStack[nStack - (abstractOutputType & VALUE_MASK)]; - if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0 - && (concreteOutputType == LONG || concreteOutputType == DOUBLE)) { - concreteOutputType = TOP; - } - } else { - concreteOutputType = abstractOutputType; - } - if (initializations != null) { - concreteOutputType = getInitializedType(symbolTable, concreteOutputType); - } - frameChanged |= merge(symbolTable, concreteOutputType, dstFrame.inputStack, nInputStack + i); - } - return frameChanged; - } - - /** - * Merges the type at the given index in the given abstract type array with the given type. - * Returns true if the type array has been modified by this operation. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param sourceType the abstract type with which the abstract type array element must be merged. - * This type should be of {@link #CONSTANT_KIND}, {@link #REFERENCE_KIND} or {@link - * #UNINITIALIZED_KIND} kind, with positive or null array dimensions. - * @param dstTypes an array of abstract types. These types should be of {@link #CONSTANT_KIND}, - * {@link #REFERENCE_KIND} or {@link #UNINITIALIZED_KIND} kind, with positive or null array - * dimensions. - * @param dstIndex the index of the type that must be merged in dstTypes. - * @return true if the type array has been modified by this operation. - */ - private static boolean merge( - final SymbolTable symbolTable, - final int sourceType, - final int[] dstTypes, - final int dstIndex) { - int dstType = dstTypes[dstIndex]; - if (dstType == sourceType) { - // If the types are equal, merge(sourceType, dstType) = dstType, so there is no change. - return false; - } - int srcType = sourceType; - if ((sourceType & ~DIM_MASK) == NULL) { - if (dstType == NULL) { - return false; - } - srcType = NULL; - } - if (dstType == 0) { - // If dstTypes[dstIndex] has never been assigned, merge(srcType, dstType) = srcType. - dstTypes[dstIndex] = srcType; - return true; - } - int mergedType; - if ((dstType & DIM_MASK) != 0 || (dstType & KIND_MASK) == REFERENCE_KIND) { - // If dstType is a reference type of any array dimension. - if (srcType == NULL) { - // If srcType is the NULL type, merge(srcType, dstType) = dstType, so there is no change. - return false; - } else if ((srcType & (DIM_MASK | KIND_MASK)) == (dstType & (DIM_MASK | KIND_MASK))) { - // If srcType has the same array dimension and the same kind as dstType. - if ((dstType & KIND_MASK) == REFERENCE_KIND) { - // If srcType and dstType are reference types with the same array dimension, - // merge(srcType, dstType) = dim(srcType) | common super class of srcType and dstType. - mergedType = - (srcType & DIM_MASK) - | REFERENCE_KIND - | symbolTable.addMergedType(srcType & VALUE_MASK, dstType & VALUE_MASK); - } else { - // If srcType and dstType are array types of equal dimension but different element types, - // merge(srcType, dstType) = dim(srcType) - 1 | java/lang/Object. - int mergedDim = ELEMENT_OF + (srcType & DIM_MASK); - mergedType = mergedDim | REFERENCE_KIND | symbolTable.addType("java/lang/Object"); - } - } else if ((srcType & DIM_MASK) != 0 || (srcType & KIND_MASK) == REFERENCE_KIND) { - // If srcType is any other reference or array type, - // merge(srcType, dstType) = min(srcDdim, dstDim) | java/lang/Object - // where srcDim is the array dimension of srcType, minus 1 if srcType is an array type - // with a non reference element type (and similarly for dstDim). - int srcDim = srcType & DIM_MASK; - if (srcDim != 0 && (srcType & KIND_MASK) != REFERENCE_KIND) { - srcDim = ELEMENT_OF + srcDim; - } - int dstDim = dstType & DIM_MASK; - if (dstDim != 0 && (dstType & KIND_MASK) != REFERENCE_KIND) { - dstDim = ELEMENT_OF + dstDim; - } - mergedType = - Math.min(srcDim, dstDim) | REFERENCE_KIND | symbolTable.addType("java/lang/Object"); - } else { - // If srcType is any other type, merge(srcType, dstType) = TOP. - mergedType = TOP; - } - } else if (dstType == NULL) { - // If dstType is the NULL type, merge(srcType, dstType) = srcType, or TOP if srcType is not a - // an array type or a reference type. - mergedType = - (srcType & DIM_MASK) != 0 || (srcType & KIND_MASK) == REFERENCE_KIND ? srcType : TOP; - } else { - // If dstType is any other type, merge(srcType, dstType) = TOP whatever srcType. - mergedType = TOP; - } - if (mergedType != dstType) { - dstTypes[dstIndex] = mergedType; - return true; - } - return false; - } - - // ----------------------------------------------------------------------------------------------- - // Frame output methods, to generate StackMapFrame attributes - // ----------------------------------------------------------------------------------------------- - - /** - * Makes the given {@link MethodWriter} visit the input frame of this {@link Frame}. The visit is - * done with the {@link MethodWriter#visitFrameStart}, {@link MethodWriter#visitAbstractType} and - * {@link MethodWriter#visitFrameEnd} methods. - * - * @param methodWriter the {@link MethodWriter} that should visit the input frame of this {@link - * Frame}. - */ - final void accept(final MethodWriter methodWriter) { - // Compute the number of locals, ignoring TOP types that are just after a LONG or a DOUBLE, and - // all trailing TOP types. - int[] localTypes = inputLocals; - int nLocal = 0; - int nTrailingTop = 0; - int i = 0; - while (i < localTypes.length) { - int localType = localTypes[i]; - i += (localType == LONG || localType == DOUBLE) ? 2 : 1; - if (localType == TOP) { - nTrailingTop++; - } else { - nLocal += nTrailingTop + 1; - nTrailingTop = 0; - } - } - // Compute the stack size, ignoring TOP types that are just after a LONG or a DOUBLE. - int[] stackTypes = inputStack; - int nStack = 0; - i = 0; - while (i < stackTypes.length) { - int stackType = stackTypes[i]; - i += (stackType == LONG || stackType == DOUBLE) ? 2 : 1; - nStack++; - } - // Visit the frame and its content. - int frameIndex = methodWriter.visitFrameStart(owner.bytecodeOffset, nLocal, nStack); - i = 0; - while (nLocal-- > 0) { - int localType = localTypes[i]; - i += (localType == LONG || localType == DOUBLE) ? 2 : 1; - methodWriter.visitAbstractType(frameIndex++, localType); - } - i = 0; - while (nStack-- > 0) { - int stackType = stackTypes[i]; - i += (stackType == LONG || stackType == DOUBLE) ? 2 : 1; - methodWriter.visitAbstractType(frameIndex++, stackType); - } - methodWriter.visitFrameEnd(); - } - - /** - * Put the given abstract type in the given ByteVector, using the JVMS verification_type_info - * format used in StackMapTable attributes. - * - * @param symbolTable the type table to use to lookup and store type {@link Symbol}. - * @param abstractType an abstract type, restricted to {@link Frame#CONSTANT_KIND}, {@link - * Frame#REFERENCE_KIND} or {@link Frame#UNINITIALIZED_KIND} types. - * @param output where the abstract type must be put. - * @see JVMS - * 4.7.4 - */ - static void putAbstractType( - final SymbolTable symbolTable, final int abstractType, final ByteVector output) { - int arrayDimensions = (abstractType & Frame.DIM_MASK) >> DIM_SHIFT; - if (arrayDimensions == 0) { - int typeValue = abstractType & VALUE_MASK; - switch (abstractType & KIND_MASK) { - case CONSTANT_KIND: - output.putByte(typeValue); - break; - case REFERENCE_KIND: - output - .putByte(ITEM_OBJECT) - .putShort(symbolTable.addConstantClass(symbolTable.getType(typeValue).value).index); - break; - case UNINITIALIZED_KIND: - output.putByte(ITEM_UNINITIALIZED).putShort((int) symbolTable.getType(typeValue).data); - break; - default: - throw new AssertionError(); - } - } else { - // Case of an array type, we need to build its descriptor first. - StringBuilder typeDescriptor = new StringBuilder(); - while (arrayDimensions-- > 0) { - typeDescriptor.append('['); - } - if ((abstractType & KIND_MASK) == REFERENCE_KIND) { - typeDescriptor - .append('L') - .append(symbolTable.getType(abstractType & VALUE_MASK).value) - .append(';'); - } else { - switch (abstractType & VALUE_MASK) { - case Frame.ITEM_ASM_BOOLEAN: - typeDescriptor.append('Z'); - break; - case Frame.ITEM_ASM_BYTE: - typeDescriptor.append('B'); - break; - case Frame.ITEM_ASM_CHAR: - typeDescriptor.append('C'); - break; - case Frame.ITEM_ASM_SHORT: - typeDescriptor.append('S'); - break; - case Frame.ITEM_INTEGER: - typeDescriptor.append('I'); - break; - case Frame.ITEM_FLOAT: - typeDescriptor.append('F'); - break; - case Frame.ITEM_LONG: - typeDescriptor.append('J'); - break; - case Frame.ITEM_DOUBLE: - typeDescriptor.append('D'); - break; - default: - throw new AssertionError(); - } - } - output - .putByte(ITEM_OBJECT) - .putShort(symbolTable.addConstantClass(typeDescriptor.toString()).index); - } - } -} diff --git a/src/main/java/org/objectweb/asm/Handle.java b/src/main/java/org/objectweb/asm/Handle.java deleted file mode 100644 index d475f10c..00000000 --- a/src/main/java/org/objectweb/asm/Handle.java +++ /dev/null @@ -1,197 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. - -package org.objectweb.asm; - -/** - * A reference to a field or a method. - * - * @author Remi Forax - * @author Eric Bruneton - */ -public final class Handle { - - /** - * The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD}, - * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link - * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, - * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - */ - final int tag; - - /** - * The internal name of the class that owns the field or method designated by this handle. - */ - final String owner; - - /** - * The name of the field or method designated by this handle. - */ - final String name; - - /** - * The descriptor of the field or method designated by this handle. - */ - final String descriptor; - - /** - * Whether the owner is an interface or not. - */ - final boolean isInterface; - - /** - * Constructs a new field or method handle. - * - * @param tag the kind of field or method designated by this Handle. Must be {@link - * Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link - * Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, - * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link - * Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of the class that owns the field or method designated by this - * handle. - * @param name the name of the field or method designated by this handle. - * @param descriptor the descriptor of the field or method designated by this handle. - * @deprecated this constructor has been superseded by {@link #Handle(int, String, String, String, - * boolean)}. - */ - @Deprecated - public Handle(final int tag, final String owner, final String name, final String descriptor) { - this(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE); - } - - /** - * Constructs a new field or method handle. - * - * @param tag the kind of field or method designated by this Handle. Must be {@link - * Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link - * Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, - * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link - * Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of the class that owns the field or method designated by this - * handle. - * @param name the name of the field or method designated by this handle. - * @param descriptor the descriptor of the field or method designated by this handle. - * @param isInterface whether the owner is an interface or not. - */ - public Handle( - final int tag, - final String owner, - final String name, - final String descriptor, - final boolean isInterface) { - this.tag = tag; - this.owner = owner; - this.name = name; - this.descriptor = descriptor; - this.isInterface = isInterface; - } - - /** - * Returns the kind of field or method designated by this handle. - * - * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, - * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link - * Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link - * Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - */ - public int getTag() { - return tag; - } - - /** - * Returns the internal name of the class that owns the field or method designated by this handle. - * - * @return the internal name of the class that owns the field or method designated by this handle. - */ - public String getOwner() { - return owner; - } - - /** - * Returns the name of the field or method designated by this handle. - * - * @return the name of the field or method designated by this handle. - */ - public String getName() { - return name; - } - - /** - * Returns the descriptor of the field or method designated by this handle. - * - * @return the descriptor of the field or method designated by this handle. - */ - public String getDesc() { - return descriptor; - } - - /** - * Returns true if the owner of the field or method designated by this handle is an interface. - * - * @return true if the owner of the field or method designated by this handle is an interface. - */ - public boolean isInterface() { - return isInterface; - } - - @Override - public boolean equals(final Object object) { - if (object == this) { - return true; - } - if (!(object instanceof Handle)) { - return false; - } - Handle handle = (Handle) object; - return tag == handle.tag - && isInterface == handle.isInterface - && owner.equals(handle.owner) - && name.equals(handle.name) - && descriptor.equals(handle.descriptor); - } - - @Override - public int hashCode() { - return tag - + (isInterface ? 64 : 0) - + owner.hashCode() * name.hashCode() * descriptor.hashCode(); - } - - /** - * Returns the textual representation of this handle. The textual representation is: - * - *

    - *
  • for a reference to a class: owner "." name descriptor " (" tag ")", - *
  • for a reference to an interface: owner "." name descriptor " (" tag " itf)". - *
- */ - @Override - public String toString() { - return owner + '.' + name + descriptor + " (" + tag + (isInterface ? " itf" : "") + ')'; - } -} diff --git a/src/main/java/org/objectweb/asm/Handler.java b/src/main/java/org/objectweb/asm/Handler.java deleted file mode 100644 index c5d34585..00000000 --- a/src/main/java/org/objectweb/asm/Handler.java +++ /dev/null @@ -1,200 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * Information about an exception handler. Corresponds to an element of the exception_table array of - * a Code attribute, as defined in the Java Virtual Machine Specification (JVMS). Handler instances - * can be chained together, with their {@link #nextHandler} field, to describe a full JVMS - * exception_table array. - * - * @author Eric Bruneton - * @see JVMS - * 4.7.3 - */ -final class Handler { - - /** - * The start_pc field of this JVMS exception_table entry. Corresponds to the beginning of the - * exception handler's scope (inclusive). - */ - final Label startPc; - - /** - * The end_pc field of this JVMS exception_table entry. Corresponds to the end of the exception - * handler's scope (exclusive). - */ - final Label endPc; - - /** - * The handler_pc field of this JVMS exception_table entry. Corresponding to the beginning of the - * exception handler's code. - */ - final Label handlerPc; - - /** - * The catch_type field of this JVMS exception_table entry. This is the constant pool index of the - * internal name of the type of exceptions handled by this handler, or 0 to catch any exceptions. - */ - final int catchType; - - /** - * The internal name of the type of exceptions handled by this handler, or null to catch - * any exceptions. - */ - final String catchTypeDescriptor; - - /** - * The next exception handler. - */ - Handler nextHandler; - - /** - * Constructs a new Handler. - * - * @param startPc the start_pc field of this JVMS exception_table entry. - * @param endPc the end_pc field of this JVMS exception_table entry. - * @param handlerPc the handler_pc field of this JVMS exception_table entry. - * @param catchType The catch_type field of this JVMS exception_table entry. - * @param catchTypeDescriptor The internal name of the type of exceptions handled by this handler, - * or null to catch any exceptions. - */ - Handler( - final Label startPc, - final Label endPc, - final Label handlerPc, - final int catchType, - final String catchTypeDescriptor) { - this.startPc = startPc; - this.endPc = endPc; - this.handlerPc = handlerPc; - this.catchType = catchType; - this.catchTypeDescriptor = catchTypeDescriptor; - } - - /** - * Constructs a new Handler from the given one, with a different scope. - * - * @param handler an existing Handler. - * @param startPc the start_pc field of this JVMS exception_table entry. - * @param endPc the end_pc field of this JVMS exception_table entry. - */ - Handler(final Handler handler, final Label startPc, final Label endPc) { - this(startPc, endPc, handler.handlerPc, handler.catchType, handler.catchTypeDescriptor); - this.nextHandler = handler.nextHandler; - } - - /** - * Removes the range between start and end from the Handler list that begins with the given - * element. - * - * @param firstHandler the beginning of a Handler list. May be null. - * @param start the start of the range to be removed. - * @param end the end of the range to be removed. Maybe null. - * @return the exception handler list with the start-end range removed. - */ - static Handler removeRange(final Handler firstHandler, final Label start, final Label end) { - if (firstHandler == null) { - return null; - } else { - firstHandler.nextHandler = removeRange(firstHandler.nextHandler, start, end); - } - int handlerStart = firstHandler.startPc.bytecodeOffset; - int handlerEnd = firstHandler.endPc.bytecodeOffset; - int rangeStart = start.bytecodeOffset; - int rangeEnd = end == null ? Integer.MAX_VALUE : end.bytecodeOffset; - // Return early if [handlerStart,handlerEnd[ and [rangeStart,rangeEnd[ don't intersect. - if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) { - return firstHandler; - } - if (rangeStart <= handlerStart) { - if (rangeEnd >= handlerEnd) { - // If [handlerStart,handlerEnd[ is included in [rangeStart,rangeEnd[, remove firstHandler. - return firstHandler.nextHandler; - } else { - // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [rangeEnd,handlerEnd[ - return new Handler(firstHandler, end, firstHandler.endPc); - } - } else if (rangeEnd >= handlerEnd) { - // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [handlerStart,rangeStart[ - return new Handler(firstHandler, firstHandler.startPc, start); - } else { - // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = - // [handlerStart,rangeStart[ + [rangeEnd,handerEnd[ - firstHandler.nextHandler = new Handler(firstHandler, end, firstHandler.endPc); - return new Handler(firstHandler, firstHandler.startPc, start); - } - } - - /** - * Returns the number of elements of the Handler list that begins with the given element. - * - * @param firstHandler the beginning of a Handler list. May be null. - * @return the number of elements of the Handler list that begins with 'handler'. - */ - static int getExceptionTableLength(final Handler firstHandler) { - int length = 0; - Handler handler = firstHandler; - while (handler != null) { - length++; - handler = handler.nextHandler; - } - return length; - } - - /** - * Returns the size in bytes of the JVMS exception_table corresponding to the Handler list that - * begins with the given element. This includes the exception_table_length field. - * - * @param firstHandler the beginning of a Handler list. May be null. - * @return the size in bytes of the exception_table_length and exception_table structures. - */ - static int getExceptionTableSize(final Handler firstHandler) { - return 2 + 8 * getExceptionTableLength(firstHandler); - } - - /** - * Puts the JVMS exception_table corresponding to the Handler list that begins with the given - * element. This includes the exception_table_length field. - * - * @param firstHandler the beginning of a Handler list. May be null. - * @param output where the exception_table_length and exception_table structures must be put. - */ - static void putExceptionTable(final Handler firstHandler, final ByteVector output) { - output.putShort(getExceptionTableLength(firstHandler)); - Handler handler = firstHandler; - while (handler != null) { - output - .putShort(handler.startPc.bytecodeOffset) - .putShort(handler.endPc.bytecodeOffset) - .putShort(handler.handlerPc.bytecodeOffset) - .putShort(handler.catchType); - handler = handler.nextHandler; - } - } -} diff --git a/src/main/java/org/objectweb/asm/Label.java b/src/main/java/org/objectweb/asm/Label.java deleted file mode 100644 index c75a406e..00000000 --- a/src/main/java/org/objectweb/asm/Label.java +++ /dev/null @@ -1,673 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A position in the bytecode of a method. Labels are used for jump, goto, and switch instructions, - * and for try catch blocks. A label designates the instruction that is just after. Note - * however that there can be other elements between a label and the instruction it designates (such - * as other labels, stack map frames, line numbers, etc.). - * - * @author Eric Bruneton - */ -public class Label { - - /** - * A flag indicating that a label is only used for debug attributes. Such a label is not the start - * of a basic block, the target of a jump instruction, or an exception handler. It can be safely - * ignored in control flow graph analysis algorithms (for optimization purposes). - */ - static final int FLAG_DEBUG_ONLY = 1; - - /** - * A flag indicating that a label is the target of a jump instruction, or the start of an - * exception handler. - */ - static final int FLAG_JUMP_TARGET = 2; - - /** - * A flag indicating that the bytecode offset of a label is known. - */ - static final int FLAG_RESOLVED = 4; - - /** - * A flag indicating that a label corresponds to a reachable basic block. - */ - static final int FLAG_REACHABLE = 8; - - /** - * A flag indicating that the basic block corresponding to a label ends with a subroutine call. By - * construction in {@link MethodWriter#visitJumpInsn}, labels with this flag set have at least two - * outgoing edges: - * - *
    - *
  • the first one corresponds to the instruction that follows the jsr instruction in the - * bytecode, i.e. where execution continues when it returns from the jsr call. This is a - * virtual control flow edge, since execution never goes directly from the jsr to the next - * instruction. Instead, it goes to the subroutine and eventually returns to the instruction - * following the jsr. This virtual edge is used to compute the real outgoing edges of the - * basic blocks ending with a ret instruction, in {@link #addSubroutineRetSuccessors}. - *
  • the second one corresponds to the target of the jsr instruction, - *
- */ - static final int FLAG_SUBROUTINE_CALLER = 16; - - /** - * A flag indicating that the basic block corresponding to a label is the start of a subroutine. - */ - static final int FLAG_SUBROUTINE_START = 32; - - /** - * A flag indicating that the basic block corresponding to a label is part of a subroutine. - */ - static final int FLAG_SUBROUTINE_BODY = 64; - - /** - * A flag indicating that the basic block corresponding to a label is the end of a subroutine. - */ - static final int FLAG_SUBROUTINE_END = 128; - - /** - * The number of elements to add to the {@link #otherLineNumbers} array when it needs to be - * resized to store a new source line number. - */ - static final int LINE_NUMBERS_CAPACITY_INCREMENT = 4; - - /** - * The number of elements to add to the {@link #values} array when it needs to be resized to store - * a new value. - */ - static final int VALUES_CAPACITY_INCREMENT = 6; - - /** - * The bit mask to extract the type of a forward reference to this label. The extracted type is - * either {@link #FORWARD_REFERENCE_TYPE_SHORT} or {@link #FORWARD_REFERENCE_TYPE_WIDE}. - * - * @see #values - */ - static final int FORWARD_REFERENCE_TYPE_MASK = 0xF0000000; - - /** - * The type of forward references stored with two bytes in the bytecode. This is the case, for - * instance, of a forward reference from an ifnull instruction. - */ - static final int FORWARD_REFERENCE_TYPE_SHORT = 0x10000000; - - /** - * The type of forward references stored in four bytes in the bytecode. This is the case, for - * instance, of a forward reference from a lookupswitch instruction. - */ - static final int FORWARD_REFERENCE_TYPE_WIDE = 0x20000000; - - /** - * The bit mask to extract the 'handle' of a forward reference to this label. The extracted handle - * is the bytecode offset where the forward reference value is stored (using either 2 or 4 bytes, - * as indicated by the {@link #FORWARD_REFERENCE_TYPE_MASK}). - * - * @see #values - */ - static final int FORWARD_REFERENCE_HANDLE_MASK = 0x0FFFFFFF; - - /** - * A sentinel element used to indicate the end of a list of labels. - * - * @see #nextListElement - */ - static final Label EMPTY_LIST = new Label(); - - /** - * A user managed state associated with this label. Warning: this field is used by the ASM tree - * package. In order to use it with the ASM tree package you must override the getLabelNode method - * in MethodNode. - */ - public Object info; - - /** - * The type and status of this label or its corresponding basic block. Must be zero or more of - * {@link #FLAG_DEBUG_ONLY}, {@link #FLAG_JUMP_TARGET}, {@link #FLAG_RESOLVED}, {@link - * #FLAG_REACHABLE}, {@link #FLAG_SUBROUTINE_CALLER}, {@link #FLAG_SUBROUTINE_START}, {@link - * #FLAG_SUBROUTINE_BODY}, {@link #FLAG_SUBROUTINE_END}. - */ - short flags; - - /** - * The source line number corresponding to this label, or 0. If there are several source line - * numbers corresponding to this label, the first one is stored in this field, and the remaining - * ones are stored in {@link #otherLineNumbers}. - */ - private short lineNumber; - - /** - * The source line numbers corresponding to this label, in addition to {@link #lineNumber}, or - * null. The first element of this array is the number n of source line numbers it contains, which - * are stored between indices 1 and n (inclusive). - */ - private int[] otherLineNumbers; - - /** - * The offset of this label in the bytecode of its method, in bytes. This value is set if and only - * if the {@link #FLAG_RESOLVED} flag is set. - */ - int bytecodeOffset; - - /** - * The number of elements actually used in the {@link #values} array. - */ - private short valueCount; - - /** - * The additional values associated with this label. - * - *
    - *
  • before {@link MethodWriter#computeMaxStackAndLocal}, this array contains the forward - * references to this label. Each forward reference is described with two consecutive - * integers noted 'sourceInsnBytecodeOffset' and 'reference': - *
      - *
    • 'sourceInsnBytecodeOffset' is the bytecode offset of the instruction that contains - * the forward reference, - *
    • 'reference' contains the type and the offset in the bytecode where the forward - * reference value must be stored, which can be extracted with {@link - * #FORWARD_REFERENCE_TYPE_MASK} and {@link #FORWARD_REFERENCE_HANDLE_MASK}. - *
    - * For instance, for an ifnull instruction at bytecode offset x, 'source' is equal to x, and - * 'reference' is of type {@link #FORWARD_REFERENCE_TYPE_SHORT} with value x + 1 (because - * the ifnull instruction uses a 2 bytes bytecode offset operand stored one byte after the - * start of the instruction itself). For the default case of a lookupswitch instruction at - * bytecode offset x, 'source' is equal to x, and 'reference' is of type {@link - * #FORWARD_REFERENCE_TYPE_WIDE} with value between x + 1 and x + 4 (because the - * lookupswitch instruction uses a 4 bytes bytecode offset operand stored one to four bytes - * after the start of the instruction itself). - *
  • during {@link MethodWriter#computeMaxStackAndLocal}, this array is used as a bit field in - * order to store, for each basic block, the set of subroutines to which it belongs - * (subroutines are numbered from 0 to n, and a basic block belongs to subroutine i if and - * only if the bit number i of this bit field is set). - *
- */ - private int[] values; - - // ----------------------------------------------------------------------------------------------- - - // Fields for the control flow and data flow graph analysis algorithms (used to compute the - // maximum stack size or the stack map frames). A control flow graph contains one node per "basic - // block", and one edge per "jump" from one basic block to another. Each node (i.e., each basic - // block) is represented with the Label object that corresponds to the first instruction of this - // basic block. Each node also stores the list of its successors in the graph, as a linked list of - // Edge objects. - // - // The control flow analysis algorithms used to compute the maximum stack size or the stack map - // frames are similar and use two steps. The first step, during the visit of each instruction, - // builds information about the state of the local variables and the operand stack at the end of - // each basic block, called the "output frame", relatively to the frame state at the - // beginning of the basic block, which is called the "input frame", and which is unknown - // during this step. The second step, in {@link MethodWriter#computeAllFrames} and {@link - // MethodWriter#computeMaxStackAndLocal}, is a fix point algorithm - // that computes information about the input frame of each basic block, from the input state of - // the first basic block (known from the method signature), and by the using the previously - // computed relative output frames. - // - // The algorithm used to compute the maximum stack size only computes the relative output and - // absolute input stack heights, while the algorithm used to compute stack map frames computes - // relative output frames and absolute input frames. - - /** - * The number of elements in the input stack of the basic block corresponding to this label. This - * field is computed in {@link MethodWriter#computeMaxStackAndLocal}. - */ - short inputStackSize; - - /** - * The number of elements in the output stack, at the end of the basic block corresponding to this - * label. This field is only computed for basic blocks that end with a RET instruction. - */ - short outputStackSize; - - /** - * The maximum height reached by the output stack, relatively to the top of the input stack, in - * the basick block corresponding to this label. This maximum is always positive or null. - */ - short outputStackMax; - - /** - * The input and output stack map frames of the basic block corresponding to this label. This - * field is only used when the {@link MethodWriter#COMPUTE_ALL_FRAMES} or {@link - * MethodWriter#COMPUTE_INSERTED_FRAMES} option is used. - */ - Frame frame; - - /** - * The successor of this label, in the order they are visited in {@link MethodVisitor#visitLabel}. - * This linked list does not include labels used for debug info only. If the {@link - * MethodWriter#COMPUTE_ALL_FRAMES} or {@link MethodWriter#COMPUTE_INSERTED_FRAMES} option is used - * then it does not contain either successive labels that denote the same bytecode offset (in this - * case only the first label appears in this list). - */ - Label nextBasicBlock; - - /** - * The outgoing edges of the basic block corresponding to this label, in the control flow graph of - * its method. These edges are stored in a linked list of {@link Edge} objects, linked to each - * other by their {@link Edge#nextEdge} field. - */ - Edge outgoingEdges; - - /** - * The next element in the list of labels to which this label belongs, or null if it does not - * belong to any list. All lists of labels must end with the {@link #EMPTY_LIST} sentinel, in - * order to ensure that this field is null if and only if this label does not belong to a list of - * labels. Note that there can be several lists of labels at the same time, but that a label can - * belong to at most one list at a time (unless some lists share a common tail, but this is not - * used in practice). - * - *

List of labels are used in {@link MethodWriter#computeAllFrames} and {@link - * MethodWriter#computeMaxStackAndLocal} to compute stack map frames and the maximum stack size, - * respectively, as well as in {@link #markSubroutine} and {@link #addSubroutineRetSuccessors} to - * compute the basic blocks belonging to subroutines and their outgoing edges. Outside of these - * methods, this field should be null (this property is a precondition and a postcondition of - * these methods). - */ - Label nextListElement; - - // ----------------------------------------------------------------------------------------------- - // Constructor and accessors - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a new label. - */ - public Label() { - // Nothing to do. - } - - /** - * Returns the bytecode offset corresponding to this label. This offset is computed from the start - * of the method's bytecode. This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. - * - * @return the bytecode offset corresponding to this label. - * @throws IllegalStateException if this label is not resolved yet. - */ - public int getOffset() { - if ((flags & FLAG_RESOLVED) == 0) { - throw new IllegalStateException("Label offset position has not been resolved yet"); - } - return bytecodeOffset; - } - - /** - * Returns the "canonical" {@link Label} instance corresponding to this label's bytecode offset, - * if known, otherwise the label itself. The canonical instance is the first label (in the order - * of their visit by {@link MethodVisitor#visitLabel}) corresponding to this bytecode offset. It - * cannot be known for labels which have not been visited yet. - * - *

This method should only be used when the {@link MethodWriter#COMPUTE_ALL_FRAMES} option - * is used. - * - * @return the label itself if {@link #frame} is null, otherwise the Label's frame owner. This - * corresponds to the "canonical" label instance described above thanks to the way the label - * frame is set in {@link MethodWriter#visitLabel}. - */ - final Label getCanonicalInstance() { - return frame == null ? this : frame.owner; - } - - // ----------------------------------------------------------------------------------------------- - // Methods to manage line numbers - // ----------------------------------------------------------------------------------------------- - - /** - * Adds a source line number corresponding to this label. - * - * @param lineNumber a source line number (which should be strictly positive). - */ - final void addLineNumber(final int lineNumber) { - if (this.lineNumber == 0) { - this.lineNumber = (short) lineNumber; - } else { - if (otherLineNumbers == null) { - otherLineNumbers = new int[LINE_NUMBERS_CAPACITY_INCREMENT]; - } - int otherLineNumberIndex = ++otherLineNumbers[0]; - if (otherLineNumberIndex >= otherLineNumbers.length) { - int[] newLineNumbers = new int[otherLineNumbers.length + VALUES_CAPACITY_INCREMENT]; - System.arraycopy(otherLineNumbers, 0, newLineNumbers, 0, otherLineNumbers.length); - otherLineNumbers = newLineNumbers; - } - otherLineNumbers[otherLineNumberIndex] = lineNumber; - } - } - - /** - * Makes the given visitor visit this label and its source line numbers, if applicable. - * - * @param methodVisitor a method visitor. - * @param visitLineNumbers whether to visit of the label's source line numbers, if any. - */ - final void accept(final MethodVisitor methodVisitor, final boolean visitLineNumbers) { - methodVisitor.visitLabel(this); - if (visitLineNumbers && lineNumber != 0) { - methodVisitor.visitLineNumber(lineNumber & 0xFFFF, this); - if (otherLineNumbers != null) { - for (int i = 1; i <= otherLineNumbers[0]; ++i) { - methodVisitor.visitLineNumber(otherLineNumbers[i], this); - } - } - } - } - - // ----------------------------------------------------------------------------------------------- - // Methods to compute offsets and to manage forward references - // ----------------------------------------------------------------------------------------------- - - /** - * Puts a reference to this label in the bytecode of a method. If the bytecode offset of the label - * is known, the relative bytecode offset between the label and the instruction referencing it is - * computed and written directly. Otherwise, a null relative offset is written and a new forward - * reference is declared for this label. - * - * @param code the bytecode of the method. This is where the reference is appended. - * @param sourceInsnBytecodeOffset the bytecode offset of the instruction that contains the - * reference to be appended. - * @param wideReference whether the reference must be stored in 4 bytes (instead of 2 bytes). - */ - final void put( - final ByteVector code, final int sourceInsnBytecodeOffset, final boolean wideReference) { - if ((flags & FLAG_RESOLVED) == 0) { - if (wideReference) { - addForwardReference(sourceInsnBytecodeOffset, FORWARD_REFERENCE_TYPE_WIDE, code.length); - code.putInt(-1); - } else { - addForwardReference(sourceInsnBytecodeOffset, FORWARD_REFERENCE_TYPE_SHORT, code.length); - code.putShort(-1); - } - } else { - if (wideReference) { - code.putInt(bytecodeOffset - sourceInsnBytecodeOffset); - } else { - code.putShort(bytecodeOffset - sourceInsnBytecodeOffset); - } - } - } - - /** - * Adds a forward reference to this label. This method must be called only for a true forward - * reference, i.e. only if this label is not resolved yet. For backward references, the relative - * bytecode offset of the reference can be, and must be, computed and stored directly. - * - * @param sourceInsnBytecodeOffset the bytecode offset of the instruction that contains the - * reference stored at referenceHandle. - * @param referenceType either {@link #FORWARD_REFERENCE_TYPE_SHORT} or {@link - * #FORWARD_REFERENCE_TYPE_WIDE}. - * @param referenceHandle the offset in the bytecode where the forward reference value must be - * stored. - */ - private void addForwardReference( - final int sourceInsnBytecodeOffset, final int referenceType, final int referenceHandle) { - if (values == null) { - values = new int[VALUES_CAPACITY_INCREMENT]; - } - if (valueCount >= values.length) { - int[] newValues = new int[values.length + VALUES_CAPACITY_INCREMENT]; - System.arraycopy(values, 0, newValues, 0, values.length); - values = newValues; - } - values[valueCount++] = sourceInsnBytecodeOffset; - values[valueCount++] = referenceType | referenceHandle; - } - - /** - * Sets the bytecode offset of this label to the given value and resolves the forward references - * to this label, if any. This method must be called when this label is added to the bytecode of - * the method, i.e. when its bytecode offset becomes known. This method fills in the blanks that - * where left in the bytecode by each forward reference previously added to this label. - * - * @param code the bytecode of the method. - * @param bytecodeOffset the bytecode offset of this label. - * @return true if a blank that was left for this label was too small to store the - * offset. In such a case the corresponding jump instruction is replaced with an equivalent - * ASM specific instruction using an unsigned two bytes offset. These ASM specific - * instructions are later replaced with standard bytecode instructions with wider offsets (4 - * bytes instead of 2), in ClassReader. - */ - final boolean resolve(final byte[] code, final int bytecodeOffset) { - this.flags |= FLAG_RESOLVED; - this.bytecodeOffset = bytecodeOffset; - boolean hasAsmInstructions = false; - for (int i = 0; i < valueCount; i += 2) { - final int sourceInsnBytecodeOffset = values[i]; - final int reference = values[i + 1]; - final int relativeOffset = bytecodeOffset - sourceInsnBytecodeOffset; - int handle = reference & FORWARD_REFERENCE_HANDLE_MASK; - if ((reference & FORWARD_REFERENCE_TYPE_MASK) == FORWARD_REFERENCE_TYPE_SHORT) { - if (relativeOffset < Short.MIN_VALUE || relativeOffset > Short.MAX_VALUE) { - // Change the opcode of the jump instruction, in order to be able to find it later in - // ClassReader. These ASM specific opcodes are similar to jump instruction opcodes, except - // that the 2 bytes offset is unsigned (and can therefore represent values from 0 to - // 65535, which is sufficient since the size of a method is limited to 65535 bytes). - int opcode = code[sourceInsnBytecodeOffset] & 0xFF; - if (opcode < Opcodes.IFNULL) { - // Change IFEQ ... JSR to ASM_IFEQ ... ASM_JSR. - code[sourceInsnBytecodeOffset] = (byte) (opcode + Constants.ASM_OPCODE_DELTA); - } else { - // Change IFNULL and IFNONNULL to ASM_IFNULL and ASM_IFNONNULL. - code[sourceInsnBytecodeOffset] = (byte) (opcode + Constants.ASM_IFNULL_OPCODE_DELTA); - } - hasAsmInstructions = true; - } - code[handle++] = (byte) (relativeOffset >>> 8); - code[handle] = (byte) relativeOffset; - } else { - code[handle++] = (byte) (relativeOffset >>> 24); - code[handle++] = (byte) (relativeOffset >>> 16); - code[handle++] = (byte) (relativeOffset >>> 8); - code[handle] = (byte) relativeOffset; - } - } - return hasAsmInstructions; - } - - // ----------------------------------------------------------------------------------------------- - // Methods related to subroutines - // ----------------------------------------------------------------------------------------------- - - /** - * Finds the basic blocks that belong to the subroutine starting with the basic block - * corresponding to this label, and marks these blocks as belonging to this subroutine. This - * method follows the control flow graph to find all the blocks that are reachable from the - * current basic block WITHOUT following any jsr target. - * - *

Note: a precondition and postcondition of this method is that all labels must have a null - * {@link #nextListElement}. - * - * @param subroutineId the id of the subroutine starting with the basic block corresponding to - * this label. - * @param numSubroutine the total number of subroutines in the method. - */ - final void markSubroutine(final int subroutineId, final int numSubroutine) { - // Data flow algorithm: put this basic block in a list of blocks to process (which are blocks - // belonging to subroutine subroutineId) and, while there are blocks to process, remove one from - // the list, mark it as belonging to the subroutine, and add its successor basic blocks in the - // control flow graph to the list of blocks to process (if not already done). - Label listOfBlocksToProcess = this; - listOfBlocksToProcess.nextListElement = EMPTY_LIST; - while (listOfBlocksToProcess != EMPTY_LIST) { - // Remove a basic block from the list of blocks to process. - Label basicBlock = listOfBlocksToProcess; - listOfBlocksToProcess = listOfBlocksToProcess.nextListElement; - basicBlock.nextListElement = null; - - // If it is not already marked as belonging to the subroutine subroutineId, mark it and add - // its successors to the list of blocks to process (unless already done). - if (!basicBlock.isInSubroutine(subroutineId)) { - basicBlock.addToSubroutine(subroutineId, numSubroutine); - listOfBlocksToProcess = basicBlock.pushSuccessors(listOfBlocksToProcess); - } - } - } - - /** - * Finds the basic blocks that end a subroutine starting with the basic block corresponding to - * this label and, for each one of them, adds an outgoing edge to the basic block following the - * given subroutine call. In other words, completes the control flow graph by adding the edges - * corresponding to the return from this subroutine, when called from the given caller basic - * block. - * - *

Note: a precondition and postcondition of this method is that all labels must have a null - * {@link #nextListElement}. - * - * @param subroutineCaller a basic block that ends with a jsr to the basic block corresponding to - * this label. This label is supposed to correspond to the start of a subroutine. - */ - final void addSubroutineRetSuccessors(final Label subroutineCaller) { - // Data flow algorithm: put this basic block in a list blocks to process (which are blocks - // belonging to a subroutine starting with this label) and, while there are blocks to process, - // remove one from the list, put it in a list of blocks that have been processed, add a return - // edge to the successor of subroutineCaller if applicable, and add its successor basic blocks - // in the control flow graph to the list of blocks to process (if not already done). - Label listOfProcessedBlocks = EMPTY_LIST; - Label listOfBlocksToProcess = this; - listOfBlocksToProcess.nextListElement = EMPTY_LIST; - while (listOfBlocksToProcess != EMPTY_LIST) { - // Move a basic block from the list of blocks to process to the list of processed blocks. - Label basicBlock = listOfBlocksToProcess; - listOfBlocksToProcess = basicBlock.nextListElement; - basicBlock.nextListElement = listOfProcessedBlocks; - listOfProcessedBlocks = basicBlock; - - // Add an edge from this block to the successor of the caller basic block, if this block is - // the end of a subroutine and if this block and subroutineCaller do not belong to a common - // subroutine. - if ((basicBlock.flags & FLAG_SUBROUTINE_END) != 0 - && !basicBlock.isInSameSubroutine(subroutineCaller)) { - basicBlock.outgoingEdges = - new Edge( - basicBlock.outputStackSize, - // By construction, the first outgoing edge of a basic block that ends with a jsr - // instruction leads to the jsr continuation block, i.e. where execution continues - // when ret is called (see {@link #FLAG_SUBROUTINE_CALLER}). - subroutineCaller.outgoingEdges.successor, - basicBlock.outgoingEdges); - } - // Add its successors to the list of blocks to process. Note that {@link #pushSuccessors} does - // not push basic blocks which are already in a list. Here this means either in the list of - // blocks to process, or in the list of already processed blocks. This second list is - // important to make sure we don't reprocess an already processed block. - listOfBlocksToProcess = basicBlock.pushSuccessors(listOfBlocksToProcess); - } - // Reset the {@link #nextListElement} of all the basic blocks that have been processed to null, - // so that this method can be called again with a different subroutine or subroutine caller. - while (listOfProcessedBlocks != EMPTY_LIST) { - Label newListOfProcessedBlocks = listOfProcessedBlocks.nextListElement; - listOfProcessedBlocks.nextListElement = null; - listOfProcessedBlocks = newListOfProcessedBlocks; - } - } - - /** - * Adds the successors of this label in the method's control flow graph (except those - * corresponding to a jsr target, and those already in a list of labels) to the given list of - * blocks to process, and returns the new list. - * - * @param listOfLabelsToProcess a list of basic blocks to process, linked together with their - * {@link #nextListElement} field. - * @return the new list of blocks to process. - */ - private Label pushSuccessors(final Label listOfLabelsToProcess) { - Label newListOfLabelsToProcess = listOfLabelsToProcess; - Edge outgoingEdge = outgoingEdges; - while (outgoingEdge != null) { - // By construction, the second outgoing edge of a basic block that ends with a jsr instruction - // leads to the jsr target (see {@link #FLAG_SUBROUTINE_CALLER}). - boolean isJsrTarget = - (flags & Label.FLAG_SUBROUTINE_CALLER) != 0 && outgoingEdge == outgoingEdges.nextEdge; - if (!isJsrTarget && outgoingEdge.successor.nextListElement == null) { - // Add this successor to the list of blocks to process, if it does not already belong to a - // list of labels. - outgoingEdge.successor.nextListElement = newListOfLabelsToProcess; - newListOfLabelsToProcess = outgoingEdge.successor; - } - outgoingEdge = outgoingEdge.nextEdge; - } - return newListOfLabelsToProcess; - } - - /** - * @param subroutineId a subroutine id, between 0 and the total number of subroutines in the - * method. - * @return whether this basic block belongs to the given subroutine. - */ - private boolean isInSubroutine(final int subroutineId) { - if ((flags & Label.FLAG_SUBROUTINE_BODY) != 0) { - return (values[subroutineId / 32] & (1 << (subroutineId % 32))) != 0; - } - return false; - } - - /** - * @param basicBlock another basic block. - * @return whether this basic block and the given one belong to a common subroutine. - */ - private boolean isInSameSubroutine(final Label basicBlock) { - if ((flags & FLAG_SUBROUTINE_BODY) == 0 || (basicBlock.flags & FLAG_SUBROUTINE_BODY) == 0) { - return false; - } - for (int i = 0; i < values.length; ++i) { - if ((values[i] & basicBlock.values[i]) != 0) { - return true; - } - } - return false; - } - - /** - * Marks the basic block corresponding to this label as belonging to the given subroutine. - * - * @param subroutineId a subroutine id, between 0 and numSubroutine (inclusive). - * @param numSubroutine the total number of subroutines in the method. - */ - private void addToSubroutine(final int subroutineId, final int numSubroutine) { - if ((flags & FLAG_SUBROUTINE_BODY) == 0) { - flags |= FLAG_SUBROUTINE_BODY; - values = new int[numSubroutine / 32 + 1]; - } - values[subroutineId / 32] |= (1 << (subroutineId % 32)); - } - - // ----------------------------------------------------------------------------------------------- - // Overridden Object methods - // ----------------------------------------------------------------------------------------------- - - /** - * Returns a string representation of this label. - * - * @return a string representation of this label. - */ - @Override - public String toString() { - return "L" + System.identityHashCode(this); - } -} diff --git a/src/main/java/org/objectweb/asm/MethodVisitor.java b/src/main/java/org/objectweb/asm/MethodVisitor.java deleted file mode 100644 index a7658e70..00000000 --- a/src/main/java/org/objectweb/asm/MethodVisitor.java +++ /dev/null @@ -1,779 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A visitor to visit a Java method. The methods of this class must be called in the following - * order: ( visitParameter )* [ visitAnnotationDefault ] ( - * visitAnnotation | visitAnnotableParameterCount | - * visitParameterAnnotation visitTypeAnnotation | visitAttribute )* [ - * visitCode ( visitFrame | visitXInsn | visitLabel | - * visitInsnAnnotation | visitTryCatchBlock | visitTryCatchAnnotation | - * visitLocalVariable | visitLocalVariableAnnotation | visitLineNumber )* - * visitMaxs ] visitEnd. In addition, the visitXInsn and - * visitLabel methods must be called in the sequential order of the bytecode instructions - * of the visited code, visitInsnAnnotation must be called after the annotated - * instruction, visitTryCatchBlock must be called before the labels passed as - * arguments have been visited, visitTryCatchBlockAnnotation must be called after - * the corresponding try catch block has been visited, and the visitLocalVariable, - * visitLocalVariableAnnotation and visitLineNumber methods must be called - * after the labels passed as arguments have been visited. - * - * @author Eric Bruneton - */ -public abstract class MethodVisitor { - - private static final String REQUIRES_ASM5 = "This feature requires ASM5"; - - /** - * The ASM API version implemented by this visitor. The value of this field must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - protected final int api; - - /** - * The method visitor to which this visitor must delegate method calls. May be null. - */ - protected MethodVisitor mv; - - /** - * Constructs a new {@link MethodVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - */ - public MethodVisitor(final int api) { - this(api, null); - } - - /** - * Constructs a new {@link MethodVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param methodVisitor the method visitor to which this visitor must delegate method calls. May - * be null. - */ - public MethodVisitor(final int api, final MethodVisitor methodVisitor) { - if (api < Opcodes.ASM4 || api > Opcodes.ASM6) { - throw new IllegalArgumentException(); - } - this.api = api; - this.mv = methodVisitor; - } - - // ----------------------------------------------------------------------------------------------- - // Parameters, annotations and non standard attributes - // ----------------------------------------------------------------------------------------------- - - /** - * Visits a parameter of this method. - * - * @param name parameter name or null if none is provided. - * @param access the parameter's access flags, only ACC_FINAL, ACC_SYNTHETIC - * or/and ACC_MANDATED are allowed (see {@link Opcodes}). - */ - public void visitParameter(final String name, final int access) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(REQUIRES_ASM5); - } - if (mv != null) { - mv.visitParameter(name, access); - } - } - - /** - * Visits the default value of this annotation interface method. - * - * @return a visitor to the visit the actual default value of this annotation interface method, or - * null if this visitor is not interested in visiting this default value. The 'name' - * parameters passed to the methods of this annotation visitor are ignored. Moreover, exacly - * one visit method must be called on this annotation visitor, followed by visitEnd. - */ - public AnnotationVisitor visitAnnotationDefault() { - if (mv != null) { - return mv.visitAnnotationDefault(); - } - return null; - } - - /** - * Visits an annotation of this method. - * - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { - if (mv != null) { - return mv.visitAnnotation(descriptor, visible); - } - return null; - } - - /** - * Visits an annotation on a type in the method signature. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#METHOD_TYPE_PARAMETER}, {@link - * TypeReference#METHOD_TYPE_PARAMETER_BOUND}, {@link TypeReference#METHOD_RETURN}, {@link - * TypeReference#METHOD_RECEIVER}, {@link TypeReference#METHOD_FORMAL_PARAMETER} or {@link - * TypeReference#THROWS}. See {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or - * static inner type within 'typeRef'. May be null if the annotation targets - * 'typeRef' as a whole. - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitTypeAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(REQUIRES_ASM5); - } - if (mv != null) { - return mv.visitTypeAnnotation(typeRef, typePath, descriptor, visible); - } - return null; - } - - /** - * Visits the number of method parameters that can have annotations. By default (i.e. when this - * method is not called), all the method parameters defined by the method descriptor can have - * annotations. - * - * @param parameterCount the number of method parameters than can have annotations. This number - * must be less or equal than the number of parameter types in the method descriptor. It can - * be strictly less when a method has synthetic parameters and when these parameters are - * ignored when computing parameter indices for the purpose of parameter annotations (see - * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18). - * @param visible true to define the number of method parameters that can have - * annotations visible at runtime, false to define the number of method parameters - * that can have annotations invisible at runtime. - */ - public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) { - if (mv != null) { - mv.visitAnnotableParameterCount(parameterCount, visible); - } - } - - /** - * Visits an annotation of a parameter this method. - * - * @param parameter the parameter index. This index must be strictly smaller than the number of - * parameters in the method descriptor, and strictly smaller than the parameter count - * specified in {@link #visitAnnotableParameterCount}. Important note: a parameter index i - * is not required to correspond to the i'th parameter descriptor in the method - * descriptor, in particular in case of synthetic parameters (see - * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18). - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitParameterAnnotation( - final int parameter, final String descriptor, final boolean visible) { - if (mv != null) { - return mv.visitParameterAnnotation(parameter, descriptor, visible); - } - return null; - } - - /** - * Visits a non standard attribute of this method. - * - * @param attribute an attribute. - */ - public void visitAttribute(final Attribute attribute) { - if (mv != null) { - mv.visitAttribute(attribute); - } - } - - /** - * Starts the visit of the method's code, if any (i.e. non abstract method). - */ - public void visitCode() { - if (mv != null) { - mv.visitCode(); - } - } - - /** - * Visits the current state of the local variables and operand stack elements. This method must(*) - * be called just before any instruction i that follows an unconditional branch - * instruction such as GOTO or THROW, that is the target of a jump instruction, or that starts an - * exception handler block. The visited types must describe the values of the local variables and - * of the operand stack elements just before i is executed.
- *
- * (*) this is mandatory only for classes whose version is greater than or equal to {@link - * Opcodes#V1_6}.
- *
- * The frames of a method must be given either in expanded form, or in compressed form (all frames - * must use the same format, i.e. you must not mix expanded and compressed frames within a single - * method): - * - *

    - *
  • In expanded form, all frames must have the F_NEW type. - *
  • In compressed form, frames are basically "deltas" from the state of the previous frame: - *
      - *
    • {@link Opcodes#F_SAME} representing frame with exactly the same locals as the - * previous frame and with the empty stack. - *
    • {@link Opcodes#F_SAME1} representing frame with exactly the same locals as the - * previous frame and with single value on the stack ( nStack is 1 and - * stack[0] contains value for the type of the stack item). - *
    • {@link Opcodes#F_APPEND} representing frame with current locals are the same as the - * locals in the previous frame, except that additional locals are defined ( - * nLocal is 1, 2 or 3 and local elements contains values - * representing added types). - *
    • {@link Opcodes#F_CHOP} representing frame with current locals are the same as the - * locals in the previous frame, except that the last 1-3 locals are absent and with - * the empty stack (nLocals is 1, 2 or 3). - *
    • {@link Opcodes#F_FULL} representing complete frame data. - *
    - *
- * - *
- * In both cases the first frame, corresponding to the method's parameters and access flags, is - * implicit and must not be visited. Also, it is illegal to visit two or more frames for the same - * code location (i.e., at least one instruction must be visited between two calls to visitFrame). - * - * @param type the type of this stack map frame. Must be {@link Opcodes#F_NEW} for expanded - * frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link - * Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames. - * @param nLocal the number of local variables in the visited frame. - * @param local the local variable types in this frame. This array must not be modified. Primitive - * types are represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link - * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL} or - * {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a single element). - * Reference types are represented by String objects (representing internal names), and - * uninitialized types by Label objects (this label designates the NEW instruction that - * created this uninitialized value). - * @param nStack the number of operand stack elements in the visited frame. - * @param stack the operand stack types in this frame. This array must not be modified. Its - * content has the same format as the "local" array. - * @throws IllegalStateException if a frame is visited just after another one, without any - * instruction between the two (unless this frame is a Opcodes#F_SAME frame, in which case it - * is silently ignored). - */ - public void visitFrame( - final int type, - final int nLocal, - final Object[] local, - final int nStack, - final Object[] stack) { - if (mv != null) { - mv.visitFrame(type, nLocal, local, nStack, stack); - } - } - - // ----------------------------------------------------------------------------------------------- - // Normal instructions - // ----------------------------------------------------------------------------------------------- - - /** - * Visits a zero operand instruction. - * - * @param opcode the opcode of the instruction to be visited. This opcode is either NOP, - * ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, - * LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD, - * FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE, DASTORE, - * AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, - * SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, - * FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR, - * LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, - * D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN, - * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or MONITOREXIT. - */ - public void visitInsn(final int opcode) { - if (mv != null) { - mv.visitInsn(opcode); - } - } - - /** - * Visits an instruction with a single int operand. - * - * @param opcode the opcode of the instruction to be visited. This opcode is either BIPUSH, SIPUSH - * or NEWARRAY. - * @param operand the operand of the instruction to be visited.
- * When opcode is BIPUSH, operand value should be between Byte.MIN_VALUE and Byte.MAX_VALUE. - *
- * When opcode is SIPUSH, operand value should be between Short.MIN_VALUE and Short.MAX_VALUE. - *
- * When opcode is NEWARRAY, operand value should be one of {@link Opcodes#T_BOOLEAN}, {@link - * Opcodes#T_CHAR}, {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, {@link Opcodes#T_BYTE}, - * {@link Opcodes#T_SHORT}, {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. - */ - public void visitIntInsn(final int opcode, final int operand) { - if (mv != null) { - mv.visitIntInsn(opcode, operand); - } - } - - /** - * Visits a local variable instruction. A local variable instruction is an instruction that loads - * or stores the value of a local variable. - * - * @param opcode the opcode of the local variable instruction to be visited. This opcode is either - * ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET. - * @param var the operand of the instruction to be visited. This operand is the index of a local - * variable. - */ - public void visitVarInsn(final int opcode, final int var) { - if (mv != null) { - mv.visitVarInsn(opcode, var); - } - } - - /** - * Visits a type instruction. A type instruction is an instruction that takes the internal name of - * a class as parameter. - * - * @param opcode the opcode of the type instruction to be visited. This opcode is either NEW, - * ANEWARRAY, CHECKCAST or INSTANCEOF. - * @param type the operand of the instruction to be visited. This operand must be the internal - * name of an object or array class (see {@link Type#getInternalName()}). - */ - public void visitTypeInsn(final int opcode, final String type) { - if (mv != null) { - mv.visitTypeInsn(opcode, type); - } - } - - /** - * Visits a field instruction. A field instruction is an instruction that loads or stores the - * value of a field of an object. - * - * @param opcode the opcode of the type instruction to be visited. This opcode is either - * GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. - * @param owner the internal name of the field's owner class (see {@link Type#getInternalName()}). - * @param name the field's name. - * @param descriptor the field's descriptor (see {@link Type}). - */ - public void visitFieldInsn( - final int opcode, final String owner, final String name, final String descriptor) { - if (mv != null) { - mv.visitFieldInsn(opcode, owner, name, descriptor); - } - } - - /** - * Visits a method instruction. A method instruction is an instruction that invokes a method. - * - * @param opcode the opcode of the type instruction to be visited. This opcode is either - * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE. - * @param owner the internal name of the method's owner class (see {@link - * Type#getInternalName()}). - * @param name the method's name. - * @param descriptor the method's descriptor (see {@link Type}). - * @deprecated - */ - @Deprecated - public void visitMethodInsn( - final int opcode, final String owner, final String name, final String descriptor) { - if (api >= Opcodes.ASM5) { - boolean isInterface = opcode == Opcodes.INVOKEINTERFACE; - visitMethodInsn(opcode, owner, name, descriptor, isInterface); - return; - } - if (mv != null) { - mv.visitMethodInsn(opcode, owner, name, descriptor); - } - } - - /** - * Visits a method instruction. A method instruction is an instruction that invokes a method. - * - * @param opcode the opcode of the type instruction to be visited. This opcode is either - * INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE. - * @param owner the internal name of the method's owner class (see {@link - * Type#getInternalName()}). - * @param name the method's name. - * @param descriptor the method's descriptor (see {@link Type}). - * @param isInterface if the method's owner class is an interface. - */ - public void visitMethodInsn( - final int opcode, - final String owner, - final String name, - final String descriptor, - final boolean isInterface) { - if (api < Opcodes.ASM5) { - if (isInterface != (opcode == Opcodes.INVOKEINTERFACE)) { - throw new IllegalArgumentException("INVOKESPECIAL/STATIC on interfaces requires ASM5"); - } - visitMethodInsn(opcode, owner, name, descriptor); - return; - } - if (mv != null) { - mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface); - } - } - - /** - * Visits an invokedynamic instruction. - * - * @param name the method's name. - * @param descriptor the method's descriptor (see {@link Type}). - * @param bootstrapMethodHandle the bootstrap method. - * @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be - * an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link - * Type} or {@link Handle} value. This method is allowed to modify the content of the array so - * a caller should expect that this array may change. - */ - public void visitInvokeDynamicInsn( - final String name, - final String descriptor, - final Handle bootstrapMethodHandle, - final Object... bootstrapMethodArguments) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(REQUIRES_ASM5); - } - if (mv != null) { - mv.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); - } - } - - /** - * Visits a jump instruction. A jump instruction is an instruction that may jump to another - * instruction. - * - * @param opcode the opcode of the type instruction to be visited. This opcode is either IFEQ, - * IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, - * IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL. - * @param label the operand of the instruction to be visited. This operand is a label that - * designates the instruction to which the jump instruction may jump. - */ - public void visitJumpInsn(final int opcode, final Label label) { - if (mv != null) { - mv.visitJumpInsn(opcode, label); - } - } - - /** - * Visits a label. A label designates the instruction that will be visited just after it. - * - * @param label a {@link Label} object. - */ - public void visitLabel(final Label label) { - if (mv != null) { - mv.visitLabel(label); - } - } - - // ----------------------------------------------------------------------------------------------- - // Special instructions - // ----------------------------------------------------------------------------------------------- - - /** - * Visits a LDC instruction. Note that new constant types may be added in future versions of the - * Java Virtual Machine. To easily detect new constant types, implementations of this method - * should check for unexpected constant types, like this: - * - *
-     * if (cst instanceof Integer) {
-     *     // ...
-     * } else if (cst instanceof Float) {
-     *     // ...
-     * } else if (cst instanceof Long) {
-     *     // ...
-     * } else if (cst instanceof Double) {
-     *     // ...
-     * } else if (cst instanceof String) {
-     *     // ...
-     * } else if (cst instanceof Type) {
-     *     int sort = ((Type) cst).getSort();
-     *     if (sort == Type.OBJECT) {
-     *         // ...
-     *     } else if (sort == Type.ARRAY) {
-     *         // ...
-     *     } else if (sort == Type.METHOD) {
-     *         // ...
-     *     } else {
-     *         // throw an exception
-     *     }
-     * } else if (cst instanceof Handle) {
-     *     // ...
-     * } else {
-     *     // throw an exception
-     * }
-     * 
- * - * @param value the constant to be loaded on the stack. This parameter must be a non null {@link - * Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link - * Type} of OBJECT or ARRAY sort for .class constants, for classes whose version is - * 49.0, a {@link Type} of METHOD sort or a {@link Handle} for MethodType and MethodHandle - * constants, for classes whose version is 51.0. - */ - public void visitLdcInsn(final Object value) { - if (api < Opcodes.ASM5 - && (value instanceof Handle - || (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) { - throw new UnsupportedOperationException(REQUIRES_ASM5); - } - if (mv != null) { - mv.visitLdcInsn(value); - } - } - - /** - * Visits an IINC instruction. - * - * @param var index of the local variable to be incremented. - * @param increment amount to increment the local variable by. - */ - public void visitIincInsn(final int var, final int increment) { - if (mv != null) { - mv.visitIincInsn(var, increment); - } - } - - /** - * Visits a TABLESWITCH instruction. - * - * @param min the minimum key value. - * @param max the maximum key value. - * @param dflt beginning of the default handler block. - * @param labels beginnings of the handler blocks. labels[i] is the beginning of the - * handler block for the min + i key. - */ - public void visitTableSwitchInsn( - final int min, final int max, final Label dflt, final Label... labels) { - if (mv != null) { - mv.visitTableSwitchInsn(min, max, dflt, labels); - } - } - - /** - * Visits a LOOKUPSWITCH instruction. - * - * @param dflt beginning of the default handler block. - * @param keys the values of the keys. - * @param labels beginnings of the handler blocks. labels[i] is the beginning of the - * handler block for the keys[i] key. - */ - public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { - if (mv != null) { - mv.visitLookupSwitchInsn(dflt, keys, labels); - } - } - - /** - * Visits a MULTIANEWARRAY instruction. - * - * @param descriptor an array type descriptor (see {@link Type}). - * @param numDimensions the number of dimensions of the array to allocate. - */ - public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { - if (mv != null) { - mv.visitMultiANewArrayInsn(descriptor, numDimensions); - } - } - - /** - * Visits an annotation on an instruction. This method must be called just after the - * annotated instruction. It can be called several times for the same instruction. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#INSTANCEOF}, {@link TypeReference#NEW}, {@link - * TypeReference#CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE}, {@link - * TypeReference#CAST}, {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link - * TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT}, {@link - * TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link - * TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or - * static inner type within 'typeRef'. May be null if the annotation targets - * 'typeRef' as a whole. - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitInsnAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(REQUIRES_ASM5); - } - if (mv != null) { - return mv.visitInsnAnnotation(typeRef, typePath, descriptor, visible); - } - return null; - } - - // ----------------------------------------------------------------------------------------------- - // Exceptions table entries, debug information, max stack and max locals - // ----------------------------------------------------------------------------------------------- - - /** - * Visits a try catch block. - * - * @param start the beginning of the exception handler's scope (inclusive). - * @param end the end of the exception handler's scope (exclusive). - * @param handler the beginning of the exception handler's code. - * @param type the internal name of the type of exceptions handled by the handler, or - * null to catch any exceptions (for "finally" blocks). - * @throws IllegalArgumentException if one of the labels has already been visited by this visitor - * (by the {@link #visitLabel} method). - */ - public void visitTryCatchBlock( - final Label start, final Label end, final Label handler, final String type) { - if (mv != null) { - mv.visitTryCatchBlock(start, end, handler, type); - } - } - - /** - * Visits an annotation on an exception handler type. This method must be called after the - * {@link #visitTryCatchBlock} for the annotated exception handler. It can be called several times - * for the same exception handler. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#EXCEPTION_PARAMETER}. See {@link TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or - * static inner type within 'typeRef'. May be null if the annotation targets - * 'typeRef' as a whole. - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitTryCatchAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(REQUIRES_ASM5); - } - if (mv != null) { - return mv.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible); - } - return null; - } - - /** - * Visits a local variable declaration. - * - * @param name the name of a local variable. - * @param descriptor the type descriptor of this local variable. - * @param signature the type signature of this local variable. May be null if the local - * variable type does not use generic types. - * @param start the first instruction corresponding to the scope of this local variable - * (inclusive). - * @param end the last instruction corresponding to the scope of this local variable (exclusive). - * @param index the local variable's index. - * @throws IllegalArgumentException if one of the labels has not already been visited by this - * visitor (by the {@link #visitLabel} method). - */ - public void visitLocalVariable( - final String name, - final String descriptor, - final String signature, - final Label start, - final Label end, - final int index) { - if (mv != null) { - mv.visitLocalVariable(name, descriptor, signature, start, end, index); - } - } - - /** - * Visits an annotation on a local variable type. - * - * @param typeRef a reference to the annotated type. The sort of this type reference must be - * {@link TypeReference#LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE}. See {@link - * TypeReference}. - * @param typePath the path to the annotated type argument, wildcard bound, array element type, or - * static inner type within 'typeRef'. May be null if the annotation targets - * 'typeRef' as a whole. - * @param start the fist instructions corresponding to the continuous ranges that make the scope - * of this local variable (inclusive). - * @param end the last instructions corresponding to the continuous ranges that make the scope of - * this local variable (exclusive). This array must have the same size as the 'start' array. - * @param index the local variable's index in each range. This array must have the same size as - * the 'start' array. - * @param descriptor the class descriptor of the annotation class. - * @param visible true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if this visitor is not - * interested in visiting this annotation. - */ - public AnnotationVisitor visitLocalVariableAnnotation( - final int typeRef, - final TypePath typePath, - final Label[] start, - final Label[] end, - final int[] index, - final String descriptor, - final boolean visible) { - if (api < Opcodes.ASM5) { - throw new UnsupportedOperationException(REQUIRES_ASM5); - } - if (mv != null) { - return mv.visitLocalVariableAnnotation( - typeRef, typePath, start, end, index, descriptor, visible); - } - return null; - } - - /** - * Visits a line number declaration. - * - * @param line a line number. This number refers to the source file from which the class was - * compiled. - * @param start the first instruction corresponding to this line number. - * @throws IllegalArgumentException if start has not already been visited by this visitor - * (by the {@link #visitLabel} method). - */ - public void visitLineNumber(final int line, final Label start) { - if (mv != null) { - mv.visitLineNumber(line, start); - } - } - - /** - * Visits the maximum stack size and the maximum number of local variables of the method. - * - * @param maxStack maximum stack size of the method. - * @param maxLocals maximum number of local variables for the method. - */ - public void visitMaxs(final int maxStack, final int maxLocals) { - if (mv != null) { - mv.visitMaxs(maxStack, maxLocals); - } - } - - /** - * Visits the end of the method. This method, which is the last one to be called, is used to - * inform the visitor that all the annotations and attributes of the method have been visited. - */ - public void visitEnd() { - if (mv != null) { - mv.visitEnd(); - } - } -} diff --git a/src/main/java/org/objectweb/asm/MethodWriter.java b/src/main/java/org/objectweb/asm/MethodWriter.java deleted file mode 100644 index b8b8ad96..00000000 --- a/src/main/java/org/objectweb/asm/MethodWriter.java +++ /dev/null @@ -1,2378 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A {@link MethodVisitor} that generates a corresponding 'method_info' structure, as defined in the - * Java Virtual Machine Specification (JVMS). - * - * @author Eric Bruneton - * @author Eugene Kuleshov - * @see JVMS - * 4.6 - */ -final class MethodWriter extends MethodVisitor { - - /** - * Indicates that all the stack map frames must be computed. In this case the maximum stack size - * and the maximum number of local variables is also computed. - */ - static final int COMPUTE_ALL_FRAMES = 3; - - /** - * Indicates that the stack map frames of type F_INSERT must be computed. The other frames are not - * computed. They should all be of type F_NEW and should be sufficient to compute the content of - * the F_INSERT frames, together with the bytecode instructions between a F_NEW and a F_INSERT - * frame - and without any knowledge of the type hierarchy (by definition of F_INSERT). - */ - static final int COMPUTE_INSERTED_FRAMES = 2; - - /** - * Indicates that the maximum stack size and the maximum number of local variables must be - * computed. - */ - static final int COMPUTE_MAX_STACK_AND_LOCAL = 1; - - /** - * Indicates that nothing must be computed. - */ - static final int COMPUTE_NOTHING = 0; - - /** - * Indicates that {@link #STACK_SIZE_DELTA} is not applicable (not constant or never used). - */ - private static final int NA = 0; - - /** - * The stack size variation corresponding to each JVM opcode. The stack size variation for opcode - * 'o' is given by the array element at index 'o'. - * - * @see JVMS 6 - */ - private static final int[] STACK_SIZE_DELTA = { - 0, // nop = 0 (0x0) - 1, // aconst_null = 1 (0x1) - 1, // iconst_m1 = 2 (0x2) - 1, // iconst_0 = 3 (0x3) - 1, // iconst_1 = 4 (0x4) - 1, // iconst_2 = 5 (0x5) - 1, // iconst_3 = 6 (0x6) - 1, // iconst_4 = 7 (0x7) - 1, // iconst_5 = 8 (0x8) - 2, // lconst_0 = 9 (0x9) - 2, // lconst_1 = 10 (0xa) - 1, // fconst_0 = 11 (0xb) - 1, // fconst_1 = 12 (0xc) - 1, // fconst_2 = 13 (0xd) - 2, // dconst_0 = 14 (0xe) - 2, // dconst_1 = 15 (0xf) - 1, // bipush = 16 (0x10) - 1, // sipush = 17 (0x11) - 1, // ldc = 18 (0x12) - NA, // ldc_w = 19 (0x13) - NA, // ldc2_w = 20 (0x14) - 1, // iload = 21 (0x15) - 2, // lload = 22 (0x16) - 1, // fload = 23 (0x17) - 2, // dload = 24 (0x18) - 1, // aload = 25 (0x19) - NA, // iload_0 = 26 (0x1a) - NA, // iload_1 = 27 (0x1b) - NA, // iload_2 = 28 (0x1c) - NA, // iload_3 = 29 (0x1d) - NA, // lload_0 = 30 (0x1e) - NA, // lload_1 = 31 (0x1f) - NA, // lload_2 = 32 (0x20) - NA, // lload_3 = 33 (0x21) - NA, // fload_0 = 34 (0x22) - NA, // fload_1 = 35 (0x23) - NA, // fload_2 = 36 (0x24) - NA, // fload_3 = 37 (0x25) - NA, // dload_0 = 38 (0x26) - NA, // dload_1 = 39 (0x27) - NA, // dload_2 = 40 (0x28) - NA, // dload_3 = 41 (0x29) - NA, // aload_0 = 42 (0x2a) - NA, // aload_1 = 43 (0x2b) - NA, // aload_2 = 44 (0x2c) - NA, // aload_3 = 45 (0x2d) - -1, // iaload = 46 (0x2e) - 0, // laload = 47 (0x2f) - -1, // faload = 48 (0x30) - 0, // daload = 49 (0x31) - -1, // aaload = 50 (0x32) - -1, // baload = 51 (0x33) - -1, // caload = 52 (0x34) - -1, // saload = 53 (0x35) - -1, // istore = 54 (0x36) - -2, // lstore = 55 (0x37) - -1, // fstore = 56 (0x38) - -2, // dstore = 57 (0x39) - -1, // astore = 58 (0x3a) - NA, // istore_0 = 59 (0x3b) - NA, // istore_1 = 60 (0x3c) - NA, // istore_2 = 61 (0x3d) - NA, // istore_3 = 62 (0x3e) - NA, // lstore_0 = 63 (0x3f) - NA, // lstore_1 = 64 (0x40) - NA, // lstore_2 = 65 (0x41) - NA, // lstore_3 = 66 (0x42) - NA, // fstore_0 = 67 (0x43) - NA, // fstore_1 = 68 (0x44) - NA, // fstore_2 = 69 (0x45) - NA, // fstore_3 = 70 (0x46) - NA, // dstore_0 = 71 (0x47) - NA, // dstore_1 = 72 (0x48) - NA, // dstore_2 = 73 (0x49) - NA, // dstore_3 = 74 (0x4a) - NA, // astore_0 = 75 (0x4b) - NA, // astore_1 = 76 (0x4c) - NA, // astore_2 = 77 (0x4d) - NA, // astore_3 = 78 (0x4e) - -3, // iastore = 79 (0x4f) - -4, // lastore = 80 (0x50) - -3, // fastore = 81 (0x51) - -4, // dastore = 82 (0x52) - -3, // aastore = 83 (0x53) - -3, // bastore = 84 (0x54) - -3, // castore = 85 (0x55) - -3, // sastore = 86 (0x56) - -1, // pop = 87 (0x57) - -2, // pop2 = 88 (0x58) - 1, // dup = 89 (0x59) - 1, // dup_x1 = 90 (0x5a) - 1, // dup_x2 = 91 (0x5b) - 2, // dup2 = 92 (0x5c) - 2, // dup2_x1 = 93 (0x5d) - 2, // dup2_x2 = 94 (0x5e) - 0, // swap = 95 (0x5f) - -1, // iadd = 96 (0x60) - -2, // ladd = 97 (0x61) - -1, // fadd = 98 (0x62) - -2, // dadd = 99 (0x63) - -1, // isub = 100 (0x64) - -2, // lsub = 101 (0x65) - -1, // fsub = 102 (0x66) - -2, // dsub = 103 (0x67) - -1, // imul = 104 (0x68) - -2, // lmul = 105 (0x69) - -1, // fmul = 106 (0x6a) - -2, // dmul = 107 (0x6b) - -1, // idiv = 108 (0x6c) - -2, // ldiv = 109 (0x6d) - -1, // fdiv = 110 (0x6e) - -2, // ddiv = 111 (0x6f) - -1, // irem = 112 (0x70) - -2, // lrem = 113 (0x71) - -1, // frem = 114 (0x72) - -2, // drem = 115 (0x73) - 0, // ineg = 116 (0x74) - 0, // lneg = 117 (0x75) - 0, // fneg = 118 (0x76) - 0, // dneg = 119 (0x77) - -1, // ishl = 120 (0x78) - -1, // lshl = 121 (0x79) - -1, // ishr = 122 (0x7a) - -1, // lshr = 123 (0x7b) - -1, // iushr = 124 (0x7c) - -1, // lushr = 125 (0x7d) - -1, // iand = 126 (0x7e) - -2, // land = 127 (0x7f) - -1, // ior = 128 (0x80) - -2, // lor = 129 (0x81) - -1, // ixor = 130 (0x82) - -2, // lxor = 131 (0x83) - 0, // iinc = 132 (0x84) - 1, // i2l = 133 (0x85) - 0, // i2f = 134 (0x86) - 1, // i2d = 135 (0x87) - -1, // l2i = 136 (0x88) - -1, // l2f = 137 (0x89) - 0, // l2d = 138 (0x8a) - 0, // f2i = 139 (0x8b) - 1, // f2l = 140 (0x8c) - 1, // f2d = 141 (0x8d) - -1, // d2i = 142 (0x8e) - 0, // d2l = 143 (0x8f) - -1, // d2f = 144 (0x90) - 0, // i2b = 145 (0x91) - 0, // i2c = 146 (0x92) - 0, // i2s = 147 (0x93) - -3, // lcmp = 148 (0x94) - -1, // fcmpl = 149 (0x95) - -1, // fcmpg = 150 (0x96) - -3, // dcmpl = 151 (0x97) - -3, // dcmpg = 152 (0x98) - -1, // ifeq = 153 (0x99) - -1, // ifne = 154 (0x9a) - -1, // iflt = 155 (0x9b) - -1, // ifge = 156 (0x9c) - -1, // ifgt = 157 (0x9d) - -1, // ifle = 158 (0x9e) - -2, // if_icmpeq = 159 (0x9f) - -2, // if_icmpne = 160 (0xa0) - -2, // if_icmplt = 161 (0xa1) - -2, // if_icmpge = 162 (0xa2) - -2, // if_icmpgt = 163 (0xa3) - -2, // if_icmple = 164 (0xa4) - -2, // if_acmpeq = 165 (0xa5) - -2, // if_acmpne = 166 (0xa6) - 0, // goto = 167 (0xa7) - 1, // jsr = 168 (0xa8) - 0, // ret = 169 (0xa9) - -1, // tableswitch = 170 (0xaa) - -1, // lookupswitch = 171 (0xab) - -1, // ireturn = 172 (0xac) - -2, // lreturn = 173 (0xad) - -1, // freturn = 174 (0xae) - -2, // dreturn = 175 (0xaf) - -1, // areturn = 176 (0xb0) - 0, // return = 177 (0xb1) - NA, // getstatic = 178 (0xb2) - NA, // putstatic = 179 (0xb3) - NA, // getfield = 180 (0xb4) - NA, // putfield = 181 (0xb5) - NA, // invokevirtual = 182 (0xb6) - NA, // invokespecial = 183 (0xb7) - NA, // invokestatic = 184 (0xb8) - NA, // invokeinterface = 185 (0xb9) - NA, // invokedynamic = 186 (0xba) - 1, // new = 187 (0xbb) - 0, // newarray = 188 (0xbc) - 0, // anewarray = 189 (0xbd) - 0, // arraylength = 190 (0xbe) - NA, // athrow = 191 (0xbf) - 0, // checkcast = 192 (0xc0) - 0, // instanceof = 193 (0xc1) - -1, // monitorenter = 194 (0xc2) - -1, // monitorexit = 195 (0xc3) - NA, // wide = 196 (0xc4) - NA, // multianewarray = 197 (0xc5) - -1, // ifnull = 198 (0xc6) - -1, // ifnonnull = 199 (0xc7) - NA, // goto_w = 200 (0xc8) - NA // jsr_w = 201 (0xc9) - }; - - /** - * Where the constants used in this MethodWriter must be stored. - */ - private final SymbolTable symbolTable; - - // Note: fields are ordered as in the method_info structure, and those related to attributes are - // ordered as in Section 4.7 of the JVMS. - - /** - * The access_flags field of the method_info JVMS structure. This field can contain ASM specific - * access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the - * ClassFile structure. - */ - private final int accessFlags; - - /** - * The name_index field of the method_info JVMS structure. - */ - private final int nameIndex; - - /** - * The descriptor_index field of the method_info JVMS structure. - */ - private final int descriptorIndex; - - /** - * The descriptor of this method. - */ - private final String descriptor; - - // Code attribute fields and sub attributes: - - /** - * The max_stack field of the Code attribute. - */ - private int maxStack; - - /** - * The max_locals field of the Code attribute. - */ - private int maxLocals; - - /** - * The 'code' field of the Code attribute. - */ - private final ByteVector code = new ByteVector(); - - /** - * The first element in the exception handler list (used to generate the exception_table of the - * Code attribute). The next ones can be accessed with the {@link Handler#nextHandler} field. May - * be null. - */ - private Handler firstHandler; - - /** - * The last element in the exception handler list (used to generate the exception_table of the - * Code attribute). The next ones can be accessed with the {@link Handler#nextHandler} field. May - * be null. - */ - private Handler lastHandler; - - /** - * The line_number_table_length field of the LineNumberTable code attribute. - */ - private int lineNumberTableLength; - - /** - * The line_number_table array of the LineNumberTable code attribute, or null. - */ - private ByteVector lineNumberTable; - - /** - * The local_variable_table_length field of the LocalVariableTable code attribute. - */ - private int localVariableTableLength; - - /** - * The local_variable_table array of the LocalVariableTable code attribute, or null. - */ - private ByteVector localVariableTable; - - /** - * The local_variable_type_table_length field of the LocalVariableTypeTable code attribute. - */ - private int localVariableTypeTableLength; - - /** - * The local_variable_type_table array of the LocalVariableTypeTable code attribute, or - * null. - */ - private ByteVector localVariableTypeTable; - - /** - * The number_of_entries field of the StackMapTable code attribute. - */ - private int stackMapTableNumberOfEntries; - - /** - * The 'entries' array of the StackMapTable code attribute. - */ - private ByteVector stackMapTableEntries; - - /** - * The last runtime visible type annotation of the Code attribute. The previous ones can be - * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastCodeRuntimeVisibleTypeAnnotation; - - /** - * The last runtime invisible type annotation of the Code attribute. The previous ones can be - * accessed with the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastCodeRuntimeInvisibleTypeAnnotation; - - /** - * The first non standard attribute of the Code attribute. The next ones can be accessed with the - * {@link Attribute#nextAttribute} field. May be null. - * - *

WARNING: this list stores the attributes in the reverse order of their visit. - * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link - * #putMethodInfo} method writes the attributes in the order defined by this list, i.e. in the - * reverse order specified by the user. - */ - private Attribute firstCodeAttribute; - - // Other method_info attributes: - - /** - * The number_of_exceptions field of the Exceptions attribute. - */ - final int numberOfExceptions; - - /** - * The exception_index_table array of the Exceptions attribute, or null. - */ - final int[] exceptionIndexTable; - - /** - * The signature_index field of the Signature attribute. - */ - final int signatureIndex; - - /** - * The last runtime visible annotation of this method. The previous ones can be accessed with the - * {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeVisibleAnnotation; - - /** - * The last runtime invisible annotation of this method. The previous ones can be accessed with - * the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeInvisibleAnnotation; - - /** - * The number of method parameters that can have runtime visible annotations, or 0. - */ - private int visibleAnnotableParameterCount; - - /** - * The runtime visible parameter annotations of this method. Each array element contains the last - * annotation of a parameter (which can be null - the previous ones can be accessed with - * the {@link AnnotationWriter#previousAnnotation} field). May be null. - */ - private AnnotationWriter[] lastRuntimeVisibleParameterAnnotations; - - /** - * The number of method parameters that can have runtime visible annotations, or 0. - */ - private int invisibleAnnotableParameterCount; - - /** - * The runtime invisible parameter annotations of this method. Each array element contains the - * last annotation of a parameter (which can be null - the previous ones can be accessed - * with the {@link AnnotationWriter#previousAnnotation} field). May be null. - */ - private AnnotationWriter[] lastRuntimeInvisibleParameterAnnotations; - - /** - * The last runtime visible type annotation of this method. The previous ones can be accessed with - * the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeVisibleTypeAnnotation; - - /** - * The last runtime invisible type annotation of this method. The previous ones can be accessed - * with the {@link AnnotationWriter#previousAnnotation} field. May be null. - */ - private AnnotationWriter lastRuntimeInvisibleTypeAnnotation; - - /** - * The default_value field of the AnnotationDefault attribute, or null. - */ - private ByteVector defaultValue; - - /** - * The parameters_count field of the MethodParameters attribute. - */ - private int parametersCount; - - /** - * The 'parameters' array of the MethodParameters attribute, or null. - */ - private ByteVector parameters; - - /** - * The first non standard attribute of this method. The next ones can be accessed with the {@link - * Attribute#nextAttribute} field. May be null. - * - *

WARNING: this list stores the attributes in the reverse order of their visit. - * firstAttribute is actually the last attribute visited in {@link #visitAttribute}. The {@link - * #putMethodInfo} method writes the attributes in the order defined by this list, i.e. in the - * reverse order specified by the user. - */ - private Attribute firstAttribute; - - // ----------------------------------------------------------------------------------------------- - // Fields used to compute the maximum stack size and number of locals, and the stack map frames - // ----------------------------------------------------------------------------------------------- - - /** - * Indicates what must be computed. Must be one of {@link #COMPUTE_ALL_FRAMES}, {@link - * #COMPUTE_INSERTED_FRAMES}, {@link #COMPUTE_MAX_STACK_AND_LOCAL} or {@link #COMPUTE_NOTHING}. - */ - private final int compute; - - /** - * The first basic block of the method. The next ones (in bytecode offset order) can be accessed - * with the {@link Label#nextBasicBlock} field. - */ - private Label firstBasicBlock; - - /** - * The last basic block of the method (in bytecode offset order). This field is updated each time - * a basic block is encountered, and is used to append it at the end of the basic block list. - */ - private Label lastBasicBlock; - - /** - * The current basic block, i.e. the basic block of the last visited instruction. When {@link - * #compute} is equal to {@link #COMPUTE_ALL_FRAMES}, this field is null for unreachable - * code. When {@link #compute} is equal to {@link #COMPUTE_INSERTED_FRAMES}, this field stays - * unchanged throughout the whole method (i.e. the whole code is seen as a single basic block; - * indeed, the existing frames are sufficient by hypothesis to compute any intermediate frame - * without using any control flow graph). - */ - private Label currentBasicBlock; - - /** - * The relative stack size after the last visited instruction. This size is relative to the - * beginning of {@link #currentBasicBlock}, i.e. the true stack size after the last visited - * instruction is equal to the {@link Label#inputStackSize} of the current basic block plus {@link - * #relativeStackSize}. - */ - private int relativeStackSize; - - /** - * The maximum relative stack size after the last visited instruction. This size is relative to - * the beginning of {@link #currentBasicBlock}, i.e. the true maximum stack size after the last - * visited instruction is equal to the {@link Label#inputStackSize} of the current basic block - * plus {@link #maxRelativeStackSize}. - */ - private int maxRelativeStackSize; - - /** - * The number of local variables in the last visited stack map frame. - */ - private int currentLocals; - - /** - * The bytecode offset of the last frame that was written in {@link #stackMapTableEntries}. - */ - private int previousFrameOffset; - - /** - * The last frame that was written in {@link #stackMapTableEntries}. This field has the same - * format as {@link #currentFrame}. - */ - private int[] previousFrame; - - /** - * The current stack map frame. The first element contains the bytecode offset of the instruction - * to which the frame corresponds, the second element is the number of locals and the third one is - * the number of stack elements. The local variables start at index 3 and are followed by the - * operand stack elements. In summary frame[0] = offset, frame[1] = nLocal, frame[2] = nStack, - * frame[3] = nLocal. Local variables and operand stack entries contain abstract types, as defined - * in {@link Frame}, but restricted to {@link Frame#CONSTANT_KIND}, {@link Frame#REFERENCE_KIND} - * or {@link Frame#UNINITIALIZED_KIND} abstract types. Long and double types use only one array - * entry. - */ - private int[] currentFrame; - - /** - * The number of subroutines in this method. - */ - private int numSubroutines; - - // ----------------------------------------------------------------------------------------------- - // Other miscellaneous status fields - // ----------------------------------------------------------------------------------------------- - - /** - * Whether the bytecode of this method contains ASM specific instructions. - */ - private boolean hasAsmInstructions; - - /** - * The start offset of the last visited instruction. Used to set the offset field of type - * annotations of type 'offset_target' (see JVMS - * 4.7.20.1). - */ - private int lastBytecodeOffset; - - /** - * The offset in bytes in {@link #getSource} from which the method_info for this method (excluding - * its first 6 bytes) must be copied, or 0. - */ - int sourceOffset; - - /** - * The length in bytes in {@link #getSource} which must be copied to get the method_info for this - * method (excluding its first 6 bytes for access_flags, name_index and descriptor_index). - */ - int sourceLength; - - // ----------------------------------------------------------------------------------------------- - // Constructor and accessors - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a new {@link MethodWriter}. - * - * @param symbolTable where the constants used in this AnnotationWriter must be stored. - * @param access the method's access flags (see {@link Opcodes}). - * @param name the method's name. - * @param descriptor the method's descriptor (see {@link Type}). - * @param signature the method's signature. May be null. - * @param exceptions the internal names of the method's exceptions. May be null. - * @param compute indicates what must be computed (see #compute). - */ - MethodWriter( - final SymbolTable symbolTable, - final int access, - final String name, - final String descriptor, - final String signature, - final String[] exceptions, - final int compute) { - super(Opcodes.ASM6); - this.symbolTable = symbolTable; - this.accessFlags = "".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access; - this.nameIndex = symbolTable.addConstantUtf8(name); - this.descriptorIndex = symbolTable.addConstantUtf8(descriptor); - this.descriptor = descriptor; - this.signatureIndex = signature == null ? 0 : symbolTable.addConstantUtf8(signature); - if (exceptions != null && exceptions.length > 0) { - numberOfExceptions = exceptions.length; - this.exceptionIndexTable = new int[numberOfExceptions]; - for (int i = 0; i < numberOfExceptions; ++i) { - this.exceptionIndexTable[i] = symbolTable.addConstantClass(exceptions[i]).index; - } - } else { - numberOfExceptions = 0; - this.exceptionIndexTable = null; - } - this.compute = compute; - if (compute != COMPUTE_NOTHING) { - // Update maxLocals and currentLocals. - int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2; - if ((access & Opcodes.ACC_STATIC) != 0) { - --argumentsSize; - } - maxLocals = argumentsSize; - currentLocals = argumentsSize; - // Create and visit the label for the first basic block. - firstBasicBlock = new Label(); - visitLabel(firstBasicBlock); - } - } - - ClassReader getSource() { - return symbolTable.getSource(); - } - - boolean hasFrames() { - return stackMapTableNumberOfEntries > 0; - } - - boolean hasAsmInstructions() { - return hasAsmInstructions; - } - - // ----------------------------------------------------------------------------------------------- - // Implementation of the MethodVisitor abstract class - // ----------------------------------------------------------------------------------------------- - - @Override - public void visitParameter(final String name, final int access) { - if (parameters == null) { - parameters = new ByteVector(); - } - ++parametersCount; - parameters.putShort((name == null) ? 0 : symbolTable.addConstantUtf8(name)).putShort(access); - } - - @Override - public AnnotationVisitor visitAnnotationDefault() { - defaultValue = new ByteVector(); - return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, defaultValue, null); - } - - @Override - public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { - // Create a ByteVector to hold an 'annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16. - ByteVector annotation = new ByteVector(); - // Write type_index and reserve space for num_element_value_pairs. - annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastRuntimeVisibleAnnotation = - new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation); - } else { - return lastRuntimeInvisibleAnnotation = - new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation); - } - } - - @Override - public AnnotationVisitor visitTypeAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - // Create a ByteVector to hold a 'type_annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. - ByteVector typeAnnotation = new ByteVector(); - // Write target_type, target_info, and target_path. - TypeReference.putTarget(typeRef, typeAnnotation); - TypePath.put(typePath, typeAnnotation); - // Write type_index and reserve space for num_element_value_pairs. - typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastRuntimeVisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation); - } else { - return lastRuntimeInvisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation); - } - } - - @Override - public void visitAnnotableParameterCount(final int parameterCount, final boolean visible) { - if (visible) { - visibleAnnotableParameterCount = parameterCount; - } else { - invisibleAnnotableParameterCount = parameterCount; - } - } - - @Override - public AnnotationVisitor visitParameterAnnotation( - final int parameter, final String annotationDescriptor, final boolean visible) { - // Create a ByteVector to hold an 'annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16. - ByteVector annotation = new ByteVector(); - // Write type_index and reserve space for num_element_value_pairs. - annotation.putShort(symbolTable.addConstantUtf8(annotationDescriptor)).putShort(0); - if (visible) { - if (lastRuntimeVisibleParameterAnnotations == null) { - lastRuntimeVisibleParameterAnnotations = - new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; - } - return lastRuntimeVisibleParameterAnnotations[parameter] = - new AnnotationWriter( - symbolTable, annotation, lastRuntimeVisibleParameterAnnotations[parameter]); - } else { - if (lastRuntimeInvisibleParameterAnnotations == null) { - lastRuntimeInvisibleParameterAnnotations = - new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; - } - return lastRuntimeInvisibleParameterAnnotations[parameter] = - new AnnotationWriter( - symbolTable, annotation, lastRuntimeInvisibleParameterAnnotations[parameter]); - } - } - - @Override - public void visitAttribute(final Attribute attribute) { - // Store the attributes in the reverse order of their visit by this method. - if (attribute.isCodeAttribute()) { - attribute.nextAttribute = firstCodeAttribute; - firstCodeAttribute = attribute; - } else { - attribute.nextAttribute = firstAttribute; - firstAttribute = attribute; - } - } - - @Override - public void visitCode() { - // Nothing to do. - } - - @Override - public void visitFrame( - final int type, - final int nLocal, - final Object[] local, - final int nStack, - final Object[] stack) { - if (compute == COMPUTE_ALL_FRAMES) { - return; - } - - if (compute == COMPUTE_INSERTED_FRAMES) { - if (currentBasicBlock.frame == null) { - // This should happen only once, for the implicit first frame (which is explicitly visited - // in ClassReader if the EXPAND_ASM_INSNS option is used - and COMPUTE_INSERTED_FRAMES - // can't be set if EXPAND_ASM_INSNS is not used). - currentBasicBlock.frame = new CurrentFrame(currentBasicBlock); - currentBasicBlock.frame.setInputFrameFromDescriptor( - symbolTable, accessFlags, descriptor, nLocal); - currentBasicBlock.frame.accept(this); - } else { - if (type == Opcodes.F_NEW) { - currentBasicBlock.frame.setInputFrameFromApiFormat( - symbolTable, nLocal, local, nStack, stack); - } else { - // In this case type is equal to F_INSERT by hypothesis, and currentBlock.frame contains - // the stack map frame at the current instruction, computed from the last F_NEW frame - // and the bytecode instructions in between (via calls to CurrentFrame#execute). - } - currentBasicBlock.frame.accept(this); - } - } else if (type == Opcodes.F_NEW) { - if (previousFrame == null) { - int argumentsSize = Type.getArgumentsAndReturnSizes(descriptor) >> 2; - Frame implicitFirstFrame = new Frame(new Label()); - implicitFirstFrame.setInputFrameFromDescriptor( - symbolTable, accessFlags, descriptor, argumentsSize); - implicitFirstFrame.accept(this); - } - currentLocals = nLocal; - int frameIndex = visitFrameStart(code.length, nLocal, nStack); - for (int i = 0; i < nLocal; ++i) { - currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, local[i]); - } - for (int i = 0; i < nStack; ++i) { - currentFrame[frameIndex++] = Frame.getAbstractTypeFromApiFormat(symbolTable, stack[i]); - } - visitFrameEnd(); - } else { - int offsetDelta; - if (stackMapTableEntries == null) { - stackMapTableEntries = new ByteVector(); - offsetDelta = code.length; - } else { - offsetDelta = code.length - previousFrameOffset - 1; - if (offsetDelta < 0) { - if (type == Opcodes.F_SAME) { - return; - } else { - throw new IllegalStateException(); - } - } - } - - switch (type) { - case Opcodes.F_FULL: - currentLocals = nLocal; - stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(nLocal); - for (int i = 0; i < nLocal; ++i) { - putFrameType(local[i]); - } - stackMapTableEntries.putShort(nStack); - for (int i = 0; i < nStack; ++i) { - putFrameType(stack[i]); - } - break; - case Opcodes.F_APPEND: - currentLocals += nLocal; - stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + nLocal).putShort(offsetDelta); - for (int i = 0; i < nLocal; ++i) { - putFrameType(local[i]); - } - break; - case Opcodes.F_CHOP: - currentLocals -= nLocal; - stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED - nLocal).putShort(offsetDelta); - break; - case Opcodes.F_SAME: - if (offsetDelta < 64) { - stackMapTableEntries.putByte(offsetDelta); - } else { - stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta); - } - break; - case Opcodes.F_SAME1: - if (offsetDelta < 64) { - stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta); - } else { - stackMapTableEntries - .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) - .putShort(offsetDelta); - } - putFrameType(stack[0]); - break; - default: - throw new IllegalArgumentException(); - } - - previousFrameOffset = code.length; - ++stackMapTableNumberOfEntries; - } - - maxStack = Math.max(maxStack, nStack); - maxLocals = Math.max(maxLocals, currentLocals); - } - - @Override - public void visitInsn(final int opcode) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - code.putByte(opcode); - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(opcode, 0, null, null); - } else { - int size = relativeStackSize + STACK_SIZE_DELTA[opcode]; - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) { - endCurrentBasicBlockWithNoSuccessor(); - } - } - } - - @Override - public void visitIntInsn(final int opcode, final int operand) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - if (opcode == Opcodes.SIPUSH) { - code.put12(opcode, operand); - } else { // BIPUSH or NEWARRAY - code.put11(opcode, operand); - } - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(opcode, operand, null, null); - } else if (opcode != Opcodes.NEWARRAY) { - // The stack size delta is 1 for BIPUSH or SIPUSH, and 0 for NEWARRAY. - int size = relativeStackSize + 1; - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - } - } - - @Override - public void visitVarInsn(final int opcode, final int var) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - if (var < 4 && opcode != Opcodes.RET) { - int optimizedOpcode; - if (opcode < Opcodes.ISTORE) { - optimizedOpcode = Constants.ILOAD_0 + ((opcode - Opcodes.ILOAD) << 2) + var; - } else { - optimizedOpcode = Constants.ISTORE_0 + ((opcode - Opcodes.ISTORE) << 2) + var; - } - code.putByte(optimizedOpcode); - } else if (var >= 256) { - code.putByte(Constants.WIDE).put12(opcode, var); - } else { - code.put11(opcode, var); - } - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(opcode, var, null, null); - } else { - if (opcode == Opcodes.RET) { - // No stack size delta. - currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_END; - currentBasicBlock.outputStackSize = (short) relativeStackSize; - endCurrentBasicBlockWithNoSuccessor(); - } else { // xLOAD or xSTORE - int size = relativeStackSize + STACK_SIZE_DELTA[opcode]; - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - } - } - if (compute != COMPUTE_NOTHING) { - int currentMaxLocals; - if (opcode == Opcodes.LLOAD - || opcode == Opcodes.DLOAD - || opcode == Opcodes.LSTORE - || opcode == Opcodes.DSTORE) { - currentMaxLocals = var + 2; - } else { - currentMaxLocals = var + 1; - } - if (currentMaxLocals > maxLocals) { - maxLocals = currentMaxLocals; - } - } - if (opcode >= Opcodes.ISTORE && compute == COMPUTE_ALL_FRAMES && firstHandler != null) { - // If there are exception handler blocks, each instruction within a handler range is, in - // theory, a basic block (since execution can jump from this instruction to the exception - // handler). As a consequence, the local variable types at the beginning of the handler - // block should be the merge of the local variable types at all the instructions within the - // handler range. However, instead of creating a basic block for each instruction, we can - // get the same result in a more efficient way. Namely, by starting a new basic block after - // each xSTORE instruction, which is what we do here. - visitLabel(new Label()); - } - } - - @Override - public void visitTypeInsn(final int opcode, final String type) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - Symbol typeSymbol = symbolTable.addConstantClass(type); - code.put12(opcode, typeSymbol.index); - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(opcode, lastBytecodeOffset, typeSymbol, symbolTable); - } else if (opcode == Opcodes.NEW) { - // The stack size delta is 1 for NEW, and 0 for ANEWARRAY, CHECKCAST, or INSTANCEOF. - int size = relativeStackSize + 1; - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - } - } - - @Override - public void visitFieldInsn( - final int opcode, final String owner, final String name, final String descriptor) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - Symbol fieldrefSymbol = symbolTable.addConstantFieldref(owner, name, descriptor); - code.put12(opcode, fieldrefSymbol.index); - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(opcode, 0, fieldrefSymbol, symbolTable); - } else { - int size; - char firstDescChar = descriptor.charAt(0); - switch (opcode) { - case Opcodes.GETSTATIC: - size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 2 : 1); - break; - case Opcodes.PUTSTATIC: - size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -2 : -1); - break; - case Opcodes.GETFIELD: - size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? 1 : 0); - break; - case Opcodes.PUTFIELD: - default: - size = relativeStackSize + (firstDescChar == 'D' || firstDescChar == 'J' ? -3 : -2); - break; - } - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - } - } - - @Override - public void visitMethodInsn( - final int opcode, - final String owner, - final String name, - final String descriptor, - final boolean isInterface) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - Symbol methodrefSymbol = symbolTable.addConstantMethodref(owner, name, descriptor, isInterface); - if (opcode == Opcodes.INVOKEINTERFACE) { - code.put12(Opcodes.INVOKEINTERFACE, methodrefSymbol.index) - .put11(methodrefSymbol.getArgumentsAndReturnSizes() >> 2, 0); - } else { - code.put12(opcode, methodrefSymbol.index); - } - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(opcode, 0, methodrefSymbol, symbolTable); - } else { - int argumentsAndReturnSize = methodrefSymbol.getArgumentsAndReturnSizes(); - int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2); - int size; - if (opcode == Opcodes.INVOKESTATIC) { - size = relativeStackSize + stackSizeDelta + 1; - } else { - size = relativeStackSize + stackSizeDelta; - } - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - } - } - - @Override - public void visitInvokeDynamicInsn( - final String name, - final String descriptor, - final Handle bootstrapMethodHandle, - final Object... bootstrapMethodArguments) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - Symbol invokeDynamicSymbol = - symbolTable.addConstantInvokeDynamic( - name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments); - code.put12(Opcodes.INVOKEDYNAMIC, invokeDynamicSymbol.index); - code.putShort(0); - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, invokeDynamicSymbol, symbolTable); - } else { - int argumentsAndReturnSize = invokeDynamicSymbol.getArgumentsAndReturnSizes(); - int stackSizeDelta = (argumentsAndReturnSize & 3) - (argumentsAndReturnSize >> 2) + 1; - int size = relativeStackSize + stackSizeDelta; - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - } - } - - @Override - public void visitJumpInsn(final int opcode, final Label label) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - // Compute the 'base' opcode, i.e. GOTO or JSR if opcode is GOTO_W or JSR_W, otherwise opcode. - int baseOpcode = - opcode >= Constants.GOTO_W ? opcode - Constants.WIDE_JUMP_OPCODE_DELTA : opcode; - boolean nextInsnIsJumpTarget = false; - if ((label.flags & Label.FLAG_RESOLVED) != 0 - && label.bytecodeOffset - code.length < Short.MIN_VALUE) { - // Case of a backward jump with an offset < -32768. In this case we automatically replace GOTO - // with GOTO_W, JSR with JSR_W and IFxxx with IFNOTxxx GOTO_W L:..., where - // IFNOTxxx is the "opposite" opcode of IFxxx (e.g. IFNE for IFEQ) and where designates - // the instruction just after the GOTO_W. - if (baseOpcode == Opcodes.GOTO) { - code.putByte(Constants.GOTO_W); - } else if (baseOpcode == Opcodes.JSR) { - code.putByte(Constants.JSR_W); - } else { - // Put the "opposite" opcode of baseOpcode. This can be done by flipping the least - // significant bit for IFNULL and IFNONNULL, and similarly for IFEQ ... IF_ACMPEQ (with a - // pre and post offset by 1). The jump offset is 8 bytes (3 for IFNOTxxx, 5 for GOTO_W). - code.putByte(baseOpcode >= Opcodes.IFNULL ? baseOpcode ^ 1 : ((baseOpcode + 1) ^ 1) - 1); - code.putShort(8); - // Here we could put a GOTO_W in theory, but if ASM specific instructions are used in this - // method or another one, and if the class has frames, we will need to insert a frame after - // this GOTO_W during the additional ClassReader -> ClassWriter round trip to remove the ASM - // specific instructions. To not miss this additional frame, we need to use an ASM_GOTO_W - // here, which has the unfortunate effect of forcing this additional round trip (which in - // some case would not have been really necessary, but we can't know this at this point). - code.putByte(Constants.ASM_GOTO_W); - hasAsmInstructions = true; - // The instruction after the GOTO_W becomes the target of the IFNOT instruction. - nextInsnIsJumpTarget = true; - } - label.put(code, code.length - 1, true); - } else if (baseOpcode != opcode) { - // Case of a GOTO_W or JSR_W specified by the user (normally ClassReader when used to remove - // ASM specific instructions). In this case we keep the original instruction. - code.putByte(opcode); - label.put(code, code.length - 1, true); - } else { - // Case of a jump with an offset >= -32768, or of a jump with an unknown offset. In these - // cases we store the offset in 2 bytes (which will be increased via a ClassReader -> - // ClassWriter round trip if it turns out that 2 bytes are not sufficient). - code.putByte(baseOpcode); - label.put(code, code.length - 1, false); - } - - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - Label nextBasicBlock = null; - if (compute == COMPUTE_ALL_FRAMES) { - currentBasicBlock.frame.execute(baseOpcode, 0, null, null); - // Record the fact that 'label' is the target of a jump instruction. - label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET; - // Add 'label' as a successor of the current basic block. - addSuccessorToCurrentBasicBlock(Edge.JUMP, label); - if (baseOpcode != Opcodes.GOTO) { - // The next instruction starts a new basic block (except for GOTO: by default the code - // following a goto is unreachable - unless there is an explicit label for it - and we - // should not compute stack frame types for its instructions). - nextBasicBlock = new Label(); - } - } else if (compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(baseOpcode, 0, null, null); - } else { - if (baseOpcode == Opcodes.JSR) { - // Record the fact that 'label' designates a subroutine, if not already done. - if ((label.flags & Label.FLAG_SUBROUTINE_START) == 0) { - label.flags |= Label.FLAG_SUBROUTINE_START; - ++numSubroutines; - } - currentBasicBlock.flags |= Label.FLAG_SUBROUTINE_CALLER; - // Note that, by construction in this method, a block which calls a subroutine has at - // least two successors in the control flow graph: the first one (added below) leads to - // the instruction after the JSR, while the second one (added here) leads to the JSR - // target. Note that the first successor is virtual (it does not correspond to a possible - // execution path): it is only used to compute the successors of the basic blocks ending - // with a ret, in {@link Label#addSubroutineRetSuccessors}. - addSuccessorToCurrentBasicBlock(relativeStackSize + 1, label); - // The instruction after the JSR starts a new basic block. - nextBasicBlock = new Label(); - } else { - // No need to update maxRelativeStackSize (the stack size delta is always negative). - relativeStackSize += STACK_SIZE_DELTA[baseOpcode]; - addSuccessorToCurrentBasicBlock(relativeStackSize, label); - } - } - // If the next instruction starts a new basic block, call visitLabel to add the label of this - // instruction as a successor of the current block, and to start a new basic block. - if (nextBasicBlock != null) { - if (nextInsnIsJumpTarget) { - nextBasicBlock.flags |= Label.FLAG_JUMP_TARGET; - } - visitLabel(nextBasicBlock); - } - if (baseOpcode == Opcodes.GOTO) { - endCurrentBasicBlockWithNoSuccessor(); - } - } - } - - @Override - public void visitLabel(final Label label) { - // Resolve the forward references to this label, if any. - hasAsmInstructions |= label.resolve(code.data, code.length); - // visitLabel starts a new basic block (except for debug only labels), so we need to update the - // previous and current block references and list of successors. - if ((label.flags & Label.FLAG_DEBUG_ONLY) != 0) { - return; - } - if (compute == COMPUTE_ALL_FRAMES) { - if (currentBasicBlock != null) { - if (label.bytecodeOffset == currentBasicBlock.bytecodeOffset) { - // We use {@link Label#getCanonicalInstance} to store the state of a basic block in only - // one place, but this does not work for labels which have not been visited yet. - // Therefore, when we detect here two labels having the same bytecode offset, we need to - // - consolidate the state scattered in these two instances into the canonical instance: - currentBasicBlock.flags |= (label.flags & Label.FLAG_JUMP_TARGET); - // - make sure the two instances share the same Frame instance (the implementation of - // {@link Label#getCanonicalInstance} relies on this property; here label.frame should be - // null): - label.frame = currentBasicBlock.frame; - // - and make sure to NOT assign 'label' into 'currentBasicBlock' or 'lastBasicBlock', so - // that they still refer to the canonical instance for this bytecode offset. - return; - } - // End the current basic block (with one new successor). - addSuccessorToCurrentBasicBlock(Edge.JUMP, label); - } - // Append 'label' at the end of the basic block list. - if (lastBasicBlock != null) { - if (label.bytecodeOffset == lastBasicBlock.bytecodeOffset) { - // Same comment as above. - lastBasicBlock.flags |= (label.flags & Label.FLAG_JUMP_TARGET); - // Here label.frame should be null. - label.frame = lastBasicBlock.frame; - currentBasicBlock = lastBasicBlock; - return; - } - lastBasicBlock.nextBasicBlock = label; - } - lastBasicBlock = label; - // Make it the new current basic block. - currentBasicBlock = label; - // Here label.frame should be null. - label.frame = new Frame(label); - } else if (compute == COMPUTE_INSERTED_FRAMES) { - if (currentBasicBlock == null) { - // This case should happen only once, for the visitLabel call in the constructor. Indeed, if - // compute is equal to COMPUTE_INSERTED_FRAMES, currentBasicBlock stays unchanged. - currentBasicBlock = label; - } else { - // Update the frame owner so that a correct frame offset is computed in Frame.accept(). - currentBasicBlock.frame.owner = label; - } - } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) { - if (currentBasicBlock != null) { - // End the current basic block (with one new successor). - currentBasicBlock.outputStackMax = (short) maxRelativeStackSize; - addSuccessorToCurrentBasicBlock(relativeStackSize, label); - } - // Start a new current basic block, and reset the current and maximum relative stack sizes. - currentBasicBlock = label; - relativeStackSize = 0; - maxRelativeStackSize = 0; - // Append the new basic block at the end of the basic block list. - if (lastBasicBlock != null) { - lastBasicBlock.nextBasicBlock = label; - } - lastBasicBlock = label; - } - } - - @Override - public void visitLdcInsn(final Object value) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - Symbol constantSymbol = symbolTable.addConstant(value); - int constantIndex = constantSymbol.index; - boolean isLongOrDouble = - constantSymbol.tag == Symbol.CONSTANT_LONG_TAG - || constantSymbol.tag == Symbol.CONSTANT_DOUBLE_TAG; - if (isLongOrDouble) { - code.put12(Constants.LDC2_W, constantIndex); - } else if (constantIndex >= 256) { - code.put12(Constants.LDC_W, constantIndex); - } else { - code.put11(Opcodes.LDC, constantIndex); - } - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute(Opcodes.LDC, 0, constantSymbol, symbolTable); - } else { - int size = relativeStackSize + (isLongOrDouble ? 2 : 1); - if (size > maxRelativeStackSize) { - maxRelativeStackSize = size; - } - relativeStackSize = size; - } - } - } - - @Override - public void visitIincInsn(final int var, final int increment) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - if ((var > 255) || (increment > 127) || (increment < -128)) { - code.putByte(Constants.WIDE).put12(Opcodes.IINC, var).putShort(increment); - } else { - code.putByte(Opcodes.IINC).put11(var, increment); - } - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null - && (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES)) { - currentBasicBlock.frame.execute(Opcodes.IINC, var, null, null); - } - if (compute != COMPUTE_NOTHING) { - int currentMaxLocals = var + 1; - if (currentMaxLocals > maxLocals) { - maxLocals = currentMaxLocals; - } - } - } - - @Override - public void visitTableSwitchInsn( - final int min, final int max, final Label dflt, final Label... labels) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - code.putByte(Opcodes.TABLESWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4); - dflt.put(code, lastBytecodeOffset, true); - code.putInt(min).putInt(max); - for (Label label : labels) { - label.put(code, lastBytecodeOffset, true); - } - // If needed, update the maximum stack size and number of locals, and stack map frames. - visitSwitchInsn(dflt, labels); - } - - @Override - public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - code.putByte(Opcodes.LOOKUPSWITCH).putByteArray(null, 0, (4 - code.length % 4) % 4); - dflt.put(code, lastBytecodeOffset, true); - code.putInt(labels.length); - for (int i = 0; i < labels.length; ++i) { - code.putInt(keys[i]); - labels[i].put(code, lastBytecodeOffset, true); - } - // If needed, update the maximum stack size and number of locals, and stack map frames. - visitSwitchInsn(dflt, labels); - } - - private void visitSwitchInsn(final Label dflt, final Label[] labels) { - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES) { - currentBasicBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null); - // Add all the labels as successors of the current basic block. - addSuccessorToCurrentBasicBlock(Edge.JUMP, dflt); - dflt.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET; - for (Label label : labels) { - addSuccessorToCurrentBasicBlock(Edge.JUMP, label); - label.getCanonicalInstance().flags |= Label.FLAG_JUMP_TARGET; - } - } else { - // No need to update maxRelativeStackSize (the stack size delta is always negative). - --relativeStackSize; - // Add all the labels as successors of the current basic block. - addSuccessorToCurrentBasicBlock(relativeStackSize, dflt); - for (Label label : labels) { - addSuccessorToCurrentBasicBlock(relativeStackSize, label); - } - } - // End the current basic block. - endCurrentBasicBlockWithNoSuccessor(); - } - } - - @Override - public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) { - lastBytecodeOffset = code.length; - // Add the instruction to the bytecode of the method. - Symbol descSymbol = symbolTable.addConstantClass(descriptor); - code.put12(Opcodes.MULTIANEWARRAY, descSymbol.index).putByte(numDimensions); - // If needed, update the maximum stack size and number of locals, and stack map frames. - if (currentBasicBlock != null) { - if (compute == COMPUTE_ALL_FRAMES || compute == COMPUTE_INSERTED_FRAMES) { - currentBasicBlock.frame.execute( - Opcodes.MULTIANEWARRAY, numDimensions, descSymbol, symbolTable); - } else { - // No need to update maxRelativeStackSize (the stack size delta is always negative). - relativeStackSize += 1 - numDimensions; - } - } - } - - @Override - public AnnotationVisitor visitInsnAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - // Create a ByteVector to hold a 'type_annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. - ByteVector typeAnnotation = new ByteVector(); - // Write target_type, target_info, and target_path. - TypeReference.putTarget((typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8), typeAnnotation); - TypePath.put(typePath, typeAnnotation); - // Write type_index and reserve space for num_element_value_pairs. - typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastCodeRuntimeVisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation); - } else { - return lastCodeRuntimeInvisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation); - } - } - - @Override - public void visitTryCatchBlock( - final Label start, final Label end, final Label handler, final String type) { - Handler newHandler = - new Handler( - start, end, handler, type != null ? symbolTable.addConstantClass(type).index : 0, type); - if (firstHandler == null) { - firstHandler = newHandler; - } else { - lastHandler.nextHandler = newHandler; - } - lastHandler = newHandler; - } - - @Override - public AnnotationVisitor visitTryCatchAnnotation( - final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { - // Create a ByteVector to hold a 'type_annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. - ByteVector typeAnnotation = new ByteVector(); - // Write target_type, target_info, and target_path. - TypeReference.putTarget(typeRef, typeAnnotation); - TypePath.put(typePath, typeAnnotation); - // Write type_index and reserve space for num_element_value_pairs. - typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastCodeRuntimeVisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation); - } else { - return lastCodeRuntimeInvisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation); - } - } - - @Override - public void visitLocalVariable( - final String name, - final String descriptor, - final String signature, - final Label start, - final Label end, - final int index) { - if (signature != null) { - if (localVariableTypeTable == null) { - localVariableTypeTable = new ByteVector(); - } - ++localVariableTypeTableLength; - localVariableTypeTable - .putShort(start.bytecodeOffset) - .putShort(end.bytecodeOffset - start.bytecodeOffset) - .putShort(symbolTable.addConstantUtf8(name)) - .putShort(symbolTable.addConstantUtf8(signature)) - .putShort(index); - } - if (localVariableTable == null) { - localVariableTable = new ByteVector(); - } - ++localVariableTableLength; - localVariableTable - .putShort(start.bytecodeOffset) - .putShort(end.bytecodeOffset - start.bytecodeOffset) - .putShort(symbolTable.addConstantUtf8(name)) - .putShort(symbolTable.addConstantUtf8(descriptor)) - .putShort(index); - if (compute != COMPUTE_NOTHING) { - char firstDescChar = descriptor.charAt(0); - int currentMaxLocals = index + (firstDescChar == 'J' || firstDescChar == 'D' ? 2 : 1); - if (currentMaxLocals > maxLocals) { - maxLocals = currentMaxLocals; - } - } - } - - @Override - public AnnotationVisitor visitLocalVariableAnnotation( - final int typeRef, - final TypePath typePath, - final Label[] start, - final Label[] end, - final int[] index, - final String descriptor, - final boolean visible) { - // Create a ByteVector to hold a 'type_annotation' JVMS structure. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. - ByteVector typeAnnotation = new ByteVector(); - // Write target_type, target_info, and target_path. - typeAnnotation.putByte(typeRef >>> 24).putShort(start.length); - for (int i = 0; i < start.length; ++i) { - typeAnnotation - .putShort(start[i].bytecodeOffset) - .putShort(end[i].bytecodeOffset - start[i].bytecodeOffset) - .putShort(index[i]); - } - TypePath.put(typePath, typeAnnotation); - // Write type_index and reserve space for num_element_value_pairs. - typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0); - if (visible) { - return lastCodeRuntimeVisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation); - } else { - return lastCodeRuntimeInvisibleTypeAnnotation = - new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation); - } - } - - @Override - public void visitLineNumber(final int line, final Label start) { - if (lineNumberTable == null) { - lineNumberTable = new ByteVector(); - } - ++lineNumberTableLength; - lineNumberTable.putShort(start.bytecodeOffset); - lineNumberTable.putShort(line); - } - - @Override - public void visitMaxs(final int maxStack, final int maxLocals) { - if (compute == COMPUTE_ALL_FRAMES) { - computeAllFrames(); - } else if (compute == COMPUTE_MAX_STACK_AND_LOCAL) { - computeMaxStackAndLocal(); - } else { - this.maxStack = maxStack; - this.maxLocals = maxLocals; - } - } - - /** - * Computes all the stack map frames of the method, from scratch. - */ - private void computeAllFrames() { - // Complete the control flow graph with exception handler blocks. - Handler handler = firstHandler; - while (handler != null) { - String catchTypeDescriptor = - handler.catchTypeDescriptor == null ? "java/lang/Throwable" : handler.catchTypeDescriptor; - int catchType = Frame.getAbstractTypeFromInternalName(symbolTable, catchTypeDescriptor); - // Mark handlerBlock as an exception handler. - Label handlerBlock = handler.handlerPc.getCanonicalInstance(); - handlerBlock.flags |= Label.FLAG_JUMP_TARGET; - // Add handlerBlock as a successor of all the basic blocks in the exception handler range. - Label handlerRangeBlock = handler.startPc.getCanonicalInstance(); - Label handlerRangeEnd = handler.endPc.getCanonicalInstance(); - while (handlerRangeBlock != handlerRangeEnd) { - handlerRangeBlock.outgoingEdges = - new Edge(catchType, handlerBlock, handlerRangeBlock.outgoingEdges); - handlerRangeBlock = handlerRangeBlock.nextBasicBlock; - } - handler = handler.nextHandler; - } - - // Create and visit the first (implicit) frame. - Frame firstFrame = firstBasicBlock.frame; - firstFrame.setInputFrameFromDescriptor(symbolTable, accessFlags, descriptor, this.maxLocals); - firstFrame.accept(this); - - // Fix point algorithm: add the first basic block to a list of blocks to process (i.e. blocks - // whose stack map frame has changed) and, while there are blocks to process, remove one from - // the list and update the stack map frames of its successor blocks in the control flow graph - // (which might change them, in which case these blocks must be processed too, and are thus - // added to the list of blocks to process). Also compute the maximum stack size of the method, - // as a by-product. - Label listOfBlocksToProcess = firstBasicBlock; - listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST; - int maxStackSize = 0; - while (listOfBlocksToProcess != Label.EMPTY_LIST) { - // Remove a basic block from the list of blocks to process. - Label basicBlock = listOfBlocksToProcess; - listOfBlocksToProcess = listOfBlocksToProcess.nextListElement; - basicBlock.nextListElement = null; - // By definition, basicBlock is reachable. - basicBlock.flags |= Label.FLAG_REACHABLE; - // Update the (absolute) maximum stack size. - int maxBlockStackSize = basicBlock.frame.getInputStackSize() + basicBlock.outputStackMax; - if (maxBlockStackSize > maxStackSize) { - maxStackSize = maxBlockStackSize; - } - // Update the successor blocks of basicBlock in the control flow graph. - Edge outgoingEdge = basicBlock.outgoingEdges; - while (outgoingEdge != null) { - Label successorBlock = outgoingEdge.successor.getCanonicalInstance(); - boolean successorBlockChanged = - basicBlock.frame.merge(symbolTable, successorBlock.frame, outgoingEdge.info); - if (successorBlockChanged && successorBlock.nextListElement == null) { - // If successorBlock has changed it must be processed. Thus, if it is not already in the - // list of blocks to process, add it to this list. - successorBlock.nextListElement = listOfBlocksToProcess; - listOfBlocksToProcess = successorBlock; - } - outgoingEdge = outgoingEdge.nextEdge; - } - } - - // Loop over all the basic blocks and visit the stack map frames that must be stored in the - // StackMapTable attribute. Also replace unreachable code with NOP* ATHROW, and remove it from - // exception handler ranges. - Label basicBlock = firstBasicBlock; - while (basicBlock != null) { - if ((basicBlock.flags & (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) - == (Label.FLAG_JUMP_TARGET | Label.FLAG_REACHABLE)) { - basicBlock.frame.accept(this); - } - if ((basicBlock.flags & Label.FLAG_REACHABLE) == 0) { - // Find the start and end bytecode offsets of this unreachable block. - Label nextBasicBlock = basicBlock.nextBasicBlock; - int startOffset = basicBlock.bytecodeOffset; - int endOffset = (nextBasicBlock == null ? code.length : nextBasicBlock.bytecodeOffset) - 1; - if (endOffset >= startOffset) { - // Replace its instructions with NOP ... NOP ATHROW. - for (int i = startOffset; i < endOffset; ++i) { - code.data[i] = Opcodes.NOP; - } - code.data[endOffset] = (byte) Opcodes.ATHROW; - // Emit a frame for this unreachable block, with no local and a Throwable on the stack - // (so that the ATHROW could consume this Throwable if it were reachable). - int frameIndex = visitFrameStart(startOffset, /* nLocal = */ 0, /* nStack = */ 1); - currentFrame[frameIndex] = - Frame.getAbstractTypeFromInternalName(symbolTable, "java/lang/Throwable"); - visitFrameEnd(); - // Remove this unreachable basic block from the exception handler ranges. - firstHandler = Handler.removeRange(firstHandler, basicBlock, nextBasicBlock); - // The maximum stack size is now at least one, because of the Throwable declared above. - maxStackSize = Math.max(maxStackSize, 1); - } - } - basicBlock = basicBlock.nextBasicBlock; - } - - this.maxStack = maxStackSize; - } - - /** - * Computes the maximum stack size of the method. - */ - private void computeMaxStackAndLocal() { - // Complete the control flow graph with exception handler blocks. - Handler handler = firstHandler; - while (handler != null) { - Label handlerBlock = handler.handlerPc; - Label handlerRangeBlock = handler.startPc; - Label handlerRangeEnd = handler.endPc; - // Add handlerBlock as a successor of all the basic blocks in the exception handler range. - while (handlerRangeBlock != handlerRangeEnd) { - if ((handlerRangeBlock.flags & Label.FLAG_SUBROUTINE_CALLER) == 0) { - handlerRangeBlock.outgoingEdges = - new Edge(Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges); - } else { - // If handlerRangeBlock is a JSR block, add handlerBlock after the first two outgoing - // edges to preserve the hypothesis about JSR block successors order (see - // {@link #visitJumpInsn}). - handlerRangeBlock.outgoingEdges.nextEdge.nextEdge = - new Edge( - Edge.EXCEPTION, handlerBlock, handlerRangeBlock.outgoingEdges.nextEdge.nextEdge); - } - handlerRangeBlock = handlerRangeBlock.nextBasicBlock; - } - handler = handler.nextHandler; - } - - // Complete the control flow graph with the successor blocks of subroutines, if needed. - if (numSubroutines > 0) { - // First step: find the subroutines. This step determines, for each basic block, to which - // subroutine(s) it belongs. Start with the main "subroutine": - int subroutineId = 0; - firstBasicBlock.markSubroutine(subroutineId, numSubroutines); - // Then, loop over all the basic blocks to find those that belong to real subroutines. - Label basicBlock = firstBasicBlock; - while (basicBlock != null) { - if ((basicBlock.flags & Label.FLAG_SUBROUTINE_START) != 0 - && (basicBlock.flags & Label.FLAG_SUBROUTINE_BODY) == 0) { - // If this subroutine has not been marked yet, find its basic blocks. - subroutineId += 1; - basicBlock.markSubroutine(subroutineId, numSubroutines); - } - basicBlock = basicBlock.nextBasicBlock; - } - // Second step: find the successors in the control flow graph of each subroutine basic block - // 'r' ending with a RET instruction. These successors are the virtual successors of the basic - // blocks ending with JSR instructions (see {@link #visitJumpInsn)} that can reach 'r'. - basicBlock = firstBasicBlock; - while (basicBlock != null) { - if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) { - // By construction, jsr targets are stored in the second outgoing edge of basic blocks - // that ends with a jsr instruction (see {@link #FLAG_SUBROUTINE_CALLER}). - Label subroutine = basicBlock.outgoingEdges.nextEdge.successor; - subroutine.addSubroutineRetSuccessors(basicBlock); - } - basicBlock = basicBlock.nextBasicBlock; - } - } - - // Data flow algorithm: put the first basic block in a list of blocks to process (i.e. blocks - // whose input stack size has changed) and, while there are blocks to process, remove one - // from the list, update the input stack size of its successor blocks in the control flow - // graph, and add these blocks to the list of blocks to process (if not already done). - Label listOfBlocksToProcess = firstBasicBlock; - listOfBlocksToProcess.nextListElement = Label.EMPTY_LIST; - int maxStackSize = 0; - while (listOfBlocksToProcess != Label.EMPTY_LIST) { - // Remove a basic block from the list of blocks to process. Note that we don't reset - // basicBlock.nextListElement to null on purpose, to make sure we don't reprocess already - // processed basic blocks. - Label basicBlock = listOfBlocksToProcess; - listOfBlocksToProcess = listOfBlocksToProcess.nextListElement; - // Compute the (absolute) input stack size and maximum stack size of this block. - int inputStackTop = basicBlock.inputStackSize; - int maxBlockStackSize = inputStackTop + basicBlock.outputStackMax; - // Update the absolute maximum stack size of the method. - if (maxBlockStackSize > maxStackSize) { - maxStackSize = maxBlockStackSize; - } - // Update the input stack size of the successor blocks of basicBlock in the control flow - // graph, and add these blocks to the list of blocks to process, if not already done. - Edge outgoingEdge = basicBlock.outgoingEdges; - if ((basicBlock.flags & Label.FLAG_SUBROUTINE_CALLER) != 0) { - // Ignore the first outgoing edge of the basic blocks ending with a jsr: these are virtual - // edges which lead to the instruction just after the jsr, and do not correspond to a - // possible execution path (see {@link #visitJumpInsn} and - // {@link Label#FLAG_SUBROUTINE_CALLER}). - outgoingEdge = outgoingEdge.nextEdge; - } - while (outgoingEdge != null) { - Label successorBlock = outgoingEdge.successor; - if (successorBlock.nextListElement == null) { - successorBlock.inputStackSize = - (short) (outgoingEdge.info == Edge.EXCEPTION ? 1 : inputStackTop + outgoingEdge.info); - successorBlock.nextListElement = listOfBlocksToProcess; - listOfBlocksToProcess = successorBlock; - } - outgoingEdge = outgoingEdge.nextEdge; - } - } - this.maxStack = Math.max(maxStack, maxStackSize); - } - - @Override - public void visitEnd() { - // Nothing to do. - } - - // ----------------------------------------------------------------------------------------------- - // Utility methods: control flow analysis algorithm - // ----------------------------------------------------------------------------------------------- - - /** - * Adds a successor to {@link #currentBasicBlock} in the control flow graph. - * - * @param info information about the control flow edge to be added. - * @param successor the successor block to be added to the current basic block. - */ - private void addSuccessorToCurrentBasicBlock(final int info, final Label successor) { - currentBasicBlock.outgoingEdges = new Edge(info, successor, currentBasicBlock.outgoingEdges); - } - - /** - * Ends the current basic block. This method must be used in the case where the current basic - * block does not have any successor. - * - *

WARNING: this method must be called after the currently visited instruction has been put in - * {@link #code} (if frames are computed, this method inserts a new Label to start a new basic - * block after the current instruction). - */ - private void endCurrentBasicBlockWithNoSuccessor() { - if (compute == COMPUTE_ALL_FRAMES) { - Label nextBasicBlock = new Label(); - nextBasicBlock.frame = new Frame(nextBasicBlock); - nextBasicBlock.resolve(code.data, code.length); - lastBasicBlock.nextBasicBlock = nextBasicBlock; - lastBasicBlock = nextBasicBlock; - } else { - currentBasicBlock.outputStackMax = (short) maxRelativeStackSize; - } - if (compute != COMPUTE_INSERTED_FRAMES) { - currentBasicBlock = null; - } - } - - // ----------------------------------------------------------------------------------------------- - // Utility methods: stack map frames - // ----------------------------------------------------------------------------------------------- - - /** - * Starts the visit of a new stack map frame, stored in {@link #currentFrame}. - * - * @param offset the bytecode offset of the instruction to which the frame corresponds. - * @param nLocal the number of local variables in the frame. - * @param nStack the number of stack elements in the frame. - * @return the index of the next element to be written in this frame. - */ - int visitFrameStart(final int offset, final int nLocal, final int nStack) { - int frameLength = 3 + nLocal + nStack; - if (currentFrame == null || currentFrame.length < frameLength) { - currentFrame = new int[frameLength]; - } - currentFrame[0] = offset; - currentFrame[1] = nLocal; - currentFrame[2] = nStack; - return 3; - } - - /** - * Sets an abstract type in {@link #currentFrame}. - * - * @param frameIndex the index of the element to be set in {@link #currentFrame}. - * @param abstractType an abstract type. - */ - void visitAbstractType(final int frameIndex, final int abstractType) { - currentFrame[frameIndex] = abstractType; - } - - /** - * Ends the visit of {@link #currentFrame} by writing it in the StackMapTable entries and by - * updating the StackMapTable number_of_entries (except if the current frame is the first one, - * which is implicit in StackMapTable). Then resets {@link #currentFrame} to null. - */ - void visitFrameEnd() { - if (previousFrame != null) { - if (stackMapTableEntries == null) { - stackMapTableEntries = new ByteVector(); - } - putFrame(); - ++stackMapTableNumberOfEntries; - } - previousFrame = currentFrame; - currentFrame = null; - } - - /** - * Compresses and writes {@link #currentFrame} in a new StackMapTable entry. - */ - private void putFrame() { - final int nLocal = currentFrame[1]; - final int nStack = currentFrame[2]; - if (symbolTable.getMajorVersion() < Opcodes.V1_6) { - // Generate a StackMap attribute entry, which are always uncompressed. - stackMapTableEntries.putShort(currentFrame[0]).putShort(nLocal); - putAbstractTypes(3, 3 + nLocal); - stackMapTableEntries.putShort(nStack); - putAbstractTypes(3 + nLocal, 3 + nLocal + nStack); - return; - } - final int offsetDelta = - stackMapTableNumberOfEntries == 0 - ? currentFrame[0] - : currentFrame[0] - previousFrame[0] - 1; - final int previousNlocal = previousFrame[1]; - final int nLocalDelta = nLocal - previousNlocal; - int type = Frame.FULL_FRAME; - if (nStack == 0) { - switch (nLocalDelta) { - case -3: - case -2: - case -1: - type = Frame.CHOP_FRAME; - break; - case 0: - type = offsetDelta < 64 ? Frame.SAME_FRAME : Frame.SAME_FRAME_EXTENDED; - break; - case 1: - case 2: - case 3: - type = Frame.APPEND_FRAME; - break; - default: - // Keep the FULL_FRAME type. - break; - } - } else if (nLocalDelta == 0 && nStack == 1) { - type = - offsetDelta < 63 - ? Frame.SAME_LOCALS_1_STACK_ITEM_FRAME - : Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; - } - if (type != Frame.FULL_FRAME) { - // Verify if locals are the same as in the previous frame. - int frameIndex = 3; - for (int i = 0; i < previousNlocal && i < nLocal; i++) { - if (currentFrame[frameIndex] != previousFrame[frameIndex]) { - type = Frame.FULL_FRAME; - break; - } - frameIndex++; - } - } - switch (type) { - case Frame.SAME_FRAME: - stackMapTableEntries.putByte(offsetDelta); - break; - case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME: - stackMapTableEntries.putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME + offsetDelta); - putAbstractTypes(3 + nLocal, 4 + nLocal); - break; - case Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: - stackMapTableEntries - .putByte(Frame.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) - .putShort(offsetDelta); - putAbstractTypes(3 + nLocal, 4 + nLocal); - break; - case Frame.SAME_FRAME_EXTENDED: - stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED).putShort(offsetDelta); - break; - case Frame.CHOP_FRAME: - stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + nLocalDelta).putShort(offsetDelta); - break; - case Frame.APPEND_FRAME: - stackMapTableEntries.putByte(Frame.SAME_FRAME_EXTENDED + nLocalDelta).putShort(offsetDelta); - putAbstractTypes(3 + previousNlocal, 3 + nLocal); - break; - case Frame.FULL_FRAME: - default: - stackMapTableEntries.putByte(Frame.FULL_FRAME).putShort(offsetDelta).putShort(nLocal); - putAbstractTypes(3, 3 + nLocal); - stackMapTableEntries.putShort(nStack); - putAbstractTypes(3 + nLocal, 3 + nLocal + nStack); - } - } - - /** - * Puts some abstract types of {@link #currentFrame} in {@link #stackMapTableEntries} , using the - * JVMS verification_type_info format used in StackMapTable attributes. - * - * @param start index of the first type in {@link #currentFrame} to write. - * @param end index of last type in {@link #currentFrame} to write (exclusive). - */ - private void putAbstractTypes(final int start, final int end) { - for (int i = start; i < end; ++i) { - Frame.putAbstractType(symbolTable, currentFrame[i], stackMapTableEntries); - } - } - - /** - * Puts the given public API frame element type in {@link #stackMapTableEntries} , using the JVMS - * verification_type_info format used in StackMapTable attributes. - * - * @param type a frame element type described using the same format as in {@link - * MethodVisitor#visitFrame}, i.e. either {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link - * Opcodes#FLOAT}, {@link Opcodes#LONG}, {@link Opcodes#DOUBLE}, {@link Opcodes#NULL}, or - * {@link Opcodes#UNINITIALIZED_THIS}, or the internal name of a class, or a Label designating - * a NEW instruction (for uninitialized types). - */ - private void putFrameType(final Object type) { - if (type instanceof Integer) { - stackMapTableEntries.putByte(((Integer) type).intValue()); - } else if (type instanceof String) { - stackMapTableEntries - .putByte(Frame.ITEM_OBJECT) - .putShort(symbolTable.addConstantClass((String) type).index); - } else { - stackMapTableEntries - .putByte(Frame.ITEM_UNINITIALIZED) - .putShort(((Label) type).bytecodeOffset); - } - } - - // ----------------------------------------------------------------------------------------------- - // Utility methods - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the size of the method_info JVMS structure generated by this MethodWriter. Also add the - * names of the attributes of this method in the constant pool. - * - * @return the size in bytes of the method_info JVMS structure. - */ - int computeMethodInfoSize() { - // If this method_info must be copied from an existing one, the size computation is trivial. - if (sourceOffset != 0) { - // sourceLength excludes the first 6 bytes for access_flags, name_index and descriptor_index. - return 6 + sourceLength; - } - // 2 bytes each for access_flags, name_index, descriptor_index and attributes_count. - int size = 8; - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - if (code.length > 0) { - if (code.length > 65535) { - throw new IndexOutOfBoundsException("Method code too large!"); - } - symbolTable.addConstantUtf8(Constants.CODE); - // The Code attribute has 6 header bytes, plus 2, 2, 4 and 2 bytes respectively for max_stack, - // max_locals, code_length and attributes_count, plus the bytecode and the exception table. - size += 16 + code.length + Handler.getExceptionTableSize(firstHandler); - if (stackMapTableEntries != null) { - boolean useStackMapTable = symbolTable.getMajorVersion() >= Opcodes.V1_6; - symbolTable.addConstantUtf8(useStackMapTable ? Constants.STACK_MAP_TABLE : "StackMap"); - // 6 header bytes and 2 bytes for number_of_entries. - size += 8 + stackMapTableEntries.length; - } - if (lineNumberTable != null) { - symbolTable.addConstantUtf8(Constants.LINE_NUMBER_TABLE); - // 6 header bytes and 2 bytes for line_number_table_length. - size += 8 + lineNumberTable.length; - } - if (localVariableTable != null) { - symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TABLE); - // 6 header bytes and 2 bytes for local_variable_table_length. - size += 8 + localVariableTable.length; - } - if (localVariableTypeTable != null) { - symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TYPE_TABLE); - // 6 header bytes and 2 bytes for local_variable_type_table_length. - size += 8 + localVariableTypeTable.length; - } - if (lastCodeRuntimeVisibleTypeAnnotation != null) { - size += - lastCodeRuntimeVisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - } - if (lastCodeRuntimeInvisibleTypeAnnotation != null) { - size += - lastCodeRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); - } - if (firstCodeAttribute != null) { - size += - firstCodeAttribute.computeAttributesSize( - symbolTable, code.data, code.length, maxStack, maxLocals); - } - } - if (numberOfExceptions > 0) { - symbolTable.addConstantUtf8(Constants.EXCEPTIONS); - size += 8 + 2 * numberOfExceptions; - } - boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5; - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) { - symbolTable.addConstantUtf8(Constants.SYNTHETIC); - size += 6; - } - if (signatureIndex != 0) { - symbolTable.addConstantUtf8(Constants.SIGNATURE); - size += 8; - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - symbolTable.addConstantUtf8(Constants.DEPRECATED); - size += 6; - } - if (lastRuntimeVisibleAnnotation != null) { - size += - lastRuntimeVisibleAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_ANNOTATIONS); - } - if (lastRuntimeInvisibleAnnotation != null) { - size += - lastRuntimeInvisibleAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_ANNOTATIONS); - } - if (lastRuntimeVisibleParameterAnnotations != null) { - size += - AnnotationWriter.computeParameterAnnotationsSize( - Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, - lastRuntimeVisibleParameterAnnotations, - visibleAnnotableParameterCount == 0 - ? lastRuntimeVisibleParameterAnnotations.length - : visibleAnnotableParameterCount); - } - if (lastRuntimeInvisibleParameterAnnotations != null) { - size += - AnnotationWriter.computeParameterAnnotationsSize( - Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, - lastRuntimeInvisibleParameterAnnotations, - invisibleAnnotableParameterCount == 0 - ? lastRuntimeInvisibleParameterAnnotations.length - : invisibleAnnotableParameterCount); - } - if (lastRuntimeVisibleTypeAnnotation != null) { - size += - lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - size += - lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); - } - if (defaultValue != null) { - symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT); - size += 6 + defaultValue.length; - } - if (parameters != null) { - symbolTable.addConstantUtf8(Constants.METHOD_PARAMETERS); - // 6 header bytes and 1 byte for parameters_count. - size += 7 + parameters.length; - } - if (firstAttribute != null) { - size += firstAttribute.computeAttributesSize(symbolTable); - } - return size; - } - - /** - * Puts the content of the method_info JVMS structure generated by this MethodWriter into the - * given ByteVector. - * - * @param output where the method_info structure must be put. - */ - void putMethodInfo(final ByteVector output) { - boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5; - int mask = useSyntheticAttribute ? Opcodes.ACC_SYNTHETIC : 0; - output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex); - // If this method_info must be copied from an existing one, copy it now and return early. - if (sourceOffset != 0) { - output.putByteArray(getSource().b, sourceOffset, sourceLength); - return; - } - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - int attributeCount = 0; - if (code.length > 0) { - ++attributeCount; - } - if (numberOfExceptions > 0) { - ++attributeCount; - } - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) { - ++attributeCount; - } - if (signatureIndex != 0) { - ++attributeCount; - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - ++attributeCount; - } - if (lastRuntimeVisibleAnnotation != null) { - ++attributeCount; - } - if (lastRuntimeInvisibleAnnotation != null) { - ++attributeCount; - } - if (lastRuntimeVisibleParameterAnnotations != null) { - ++attributeCount; - } - if (lastRuntimeInvisibleParameterAnnotations != null) { - ++attributeCount; - } - if (lastRuntimeVisibleTypeAnnotation != null) { - ++attributeCount; - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - ++attributeCount; - } - if (defaultValue != null) { - ++attributeCount; - } - if (parameters != null) { - ++attributeCount; - } - if (firstAttribute != null) { - attributeCount += firstAttribute.getAttributeCount(); - } - // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. - output.putShort(attributeCount); - if (code.length > 0) { - // 2, 2, 4 and 2 bytes respectively for max_stack, max_locals, code_length and - // attributes_count, plus the bytecode and the exception table. - int size = 10 + code.length + Handler.getExceptionTableSize(firstHandler); - int codeAttributeCount = 0; - if (stackMapTableEntries != null) { - // 6 header bytes and 2 bytes for number_of_entries. - size += 8 + stackMapTableEntries.length; - ++codeAttributeCount; - } - if (lineNumberTable != null) { - // 6 header bytes and 2 bytes for line_number_table_length. - size += 8 + lineNumberTable.length; - ++codeAttributeCount; - } - if (localVariableTable != null) { - // 6 header bytes and 2 bytes for local_variable_table_length. - size += 8 + localVariableTable.length; - ++codeAttributeCount; - } - if (localVariableTypeTable != null) { - // 6 header bytes and 2 bytes for local_variable_type_table_length. - size += 8 + localVariableTypeTable.length; - ++codeAttributeCount; - } - if (lastCodeRuntimeVisibleTypeAnnotation != null) { - size += - lastCodeRuntimeVisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - ++codeAttributeCount; - } - if (lastCodeRuntimeInvisibleTypeAnnotation != null) { - size += - lastCodeRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( - Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); - ++codeAttributeCount; - } - if (firstCodeAttribute != null) { - size += - firstCodeAttribute.computeAttributesSize( - symbolTable, code.data, code.length, maxStack, maxLocals); - codeAttributeCount += firstCodeAttribute.getAttributeCount(); - } - output - .putShort(symbolTable.addConstantUtf8(Constants.CODE)) - .putInt(size) - .putShort(maxStack) - .putShort(maxLocals) - .putInt(code.length) - .putByteArray(code.data, 0, code.length); - Handler.putExceptionTable(firstHandler, output); - output.putShort(codeAttributeCount); - if (stackMapTableEntries != null) { - boolean useStackMapTable = symbolTable.getMajorVersion() >= Opcodes.V1_6; - output - .putShort( - symbolTable.addConstantUtf8( - useStackMapTable ? Constants.STACK_MAP_TABLE : "StackMap")) - .putInt(2 + stackMapTableEntries.length) - .putShort(stackMapTableNumberOfEntries) - .putByteArray(stackMapTableEntries.data, 0, stackMapTableEntries.length); - } - if (lineNumberTable != null) { - output - .putShort(symbolTable.addConstantUtf8(Constants.LINE_NUMBER_TABLE)) - .putInt(2 + lineNumberTable.length) - .putShort(lineNumberTableLength) - .putByteArray(lineNumberTable.data, 0, lineNumberTable.length); - } - if (localVariableTable != null) { - output - .putShort(symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TABLE)) - .putInt(2 + localVariableTable.length) - .putShort(localVariableTableLength) - .putByteArray(localVariableTable.data, 0, localVariableTable.length); - } - if (localVariableTypeTable != null) { - output - .putShort(symbolTable.addConstantUtf8(Constants.LOCAL_VARIABLE_TYPE_TABLE)) - .putInt(2 + localVariableTypeTable.length) - .putShort(localVariableTypeTableLength) - .putByteArray(localVariableTypeTable.data, 0, localVariableTypeTable.length); - } - if (lastCodeRuntimeVisibleTypeAnnotation != null) { - lastCodeRuntimeVisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output); - } - if (lastCodeRuntimeInvisibleTypeAnnotation != null) { - lastCodeRuntimeInvisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output); - } - if (firstCodeAttribute != null) { - firstCodeAttribute.putAttributes( - symbolTable, code.data, code.length, maxStack, maxLocals, output); - } - } - if (numberOfExceptions > 0) { - output - .putShort(symbolTable.addConstantUtf8(Constants.EXCEPTIONS)) - .putInt(2 + 2 * numberOfExceptions) - .putShort(numberOfExceptions); - for (int exceptionIndex : exceptionIndexTable) { - output.putShort(exceptionIndex); - } - } - if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) { - output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0); - } - if (signatureIndex != 0) { - output - .putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE)) - .putInt(2) - .putShort(signatureIndex); - } - if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { - output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0); - } - if (lastRuntimeVisibleAnnotation != null) { - lastRuntimeVisibleAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output); - } - if (lastRuntimeInvisibleAnnotation != null) { - lastRuntimeInvisibleAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output); - } - if (lastRuntimeVisibleParameterAnnotations != null) { - AnnotationWriter.putParameterAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS), - lastRuntimeVisibleParameterAnnotations, - visibleAnnotableParameterCount == 0 - ? lastRuntimeVisibleParameterAnnotations.length - : visibleAnnotableParameterCount, - output); - } - if (lastRuntimeInvisibleParameterAnnotations != null) { - AnnotationWriter.putParameterAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS), - lastRuntimeInvisibleParameterAnnotations, - invisibleAnnotableParameterCount == 0 - ? lastRuntimeInvisibleParameterAnnotations.length - : invisibleAnnotableParameterCount, - output); - } - if (lastRuntimeVisibleTypeAnnotation != null) { - lastRuntimeVisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output); - } - if (lastRuntimeInvisibleTypeAnnotation != null) { - lastRuntimeInvisibleTypeAnnotation.putAnnotations( - symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output); - } - if (defaultValue != null) { - output - .putShort(symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT)) - .putInt(defaultValue.length) - .putByteArray(defaultValue.data, 0, defaultValue.length); - } - if (parameters != null) { - output - .putShort(symbolTable.addConstantUtf8(Constants.METHOD_PARAMETERS)) - .putInt(1 + parameters.length) - .putByte(parametersCount) - .putByteArray(parameters.data, 0, parameters.length); - } - if (firstAttribute != null) { - firstAttribute.putAttributes(symbolTable, output); - } - } - - /** - * Collects the attributes of this method into the given set of attribute prototypes. - * - * @param attributePrototypes a set of attribute prototypes. - */ - final void collectAttributePrototypes(final Attribute.Set attributePrototypes) { - attributePrototypes.addAttributes(firstAttribute); - attributePrototypes.addAttributes(firstCodeAttribute); - } -} diff --git a/src/main/java/org/objectweb/asm/ModuleVisitor.java b/src/main/java/org/objectweb/asm/ModuleVisitor.java deleted file mode 100644 index 85cc070f..00000000 --- a/src/main/java/org/objectweb/asm/ModuleVisitor.java +++ /dev/null @@ -1,175 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A visitor to visit a Java module. The methods of this class must be called in the following - * order: visitMainClass | ( visitPackage | visitRequire | - * visitExport | visitOpen | visitUse | visitProvide )* - * visitEnd. - * - * @author Remi Forax - * @author Eric Bruneton - */ -public abstract class ModuleVisitor { - /** - * The ASM API version implemented by this visitor. The value of this field must be {@link - * Opcodes#ASM6}. - */ - protected final int api; - - /** - * The module visitor to which this visitor must delegate method calls. May be null. - */ - protected ModuleVisitor mv; - - /** - * Constructs a new {@link ModuleVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}. - */ - public ModuleVisitor(final int api) { - this(api, null); - } - - /** - * Constructs a new {@link ModuleVisitor}. - * - * @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}. - * @param moduleVisitor the module visitor to which this visitor must delegate method calls. May - * be null. - */ - public ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) { - if (api != Opcodes.ASM6) { - throw new IllegalArgumentException(); - } - this.api = api; - this.mv = moduleVisitor; - } - - /** - * Visit the main class of the current module. - * - * @param mainClass the internal name of the main class of the current module. - */ - public void visitMainClass(final String mainClass) { - if (mv != null) { - mv.visitMainClass(mainClass); - } - } - - /** - * Visit a package of the current module. - * - * @param packaze the internal name of a package. - */ - public void visitPackage(final String packaze) { - if (mv != null) { - mv.visitPackage(packaze); - } - } - - /** - * Visits a dependence of the current module. - * - * @param module the fully qualified name (using dots) of the dependence. - * @param access the access flag of the dependence among {@code ACC_TRANSITIVE}, {@code - * ACC_STATIC_PHASE}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}. - * @param version the module version at compile time, or null. - */ - public void visitRequire(final String module, final int access, final String version) { - if (mv != null) { - mv.visitRequire(module, access, version); - } - } - - /** - * Visit an exported package of the current module. - * - * @param packaze the internal name of the exported package. - * @param access the access flag of the exported package, valid values are among {@code - * ACC_SYNTHETIC} and {@code ACC_MANDATED}. - * @param modules the fully qualified names (using dots) of the modules that can access the public - * classes of the exported package, or null. - */ - public void visitExport(final String packaze, final int access, final String... modules) { - if (mv != null) { - mv.visitExport(packaze, access, modules); - } - } - - /** - * Visit an open package of the current module. - * - * @param packaze the internal name of the opened package. - * @param access the access flag of the opened package, valid values are among {@code - * ACC_SYNTHETIC} and {@code ACC_MANDATED}. - * @param modules the fully qualified names (using dots) of the modules that can use deep - * reflection to the classes of the open package, or null. - */ - public void visitOpen(final String packaze, final int access, final String... modules) { - if (mv != null) { - mv.visitOpen(packaze, access, modules); - } - } - - /** - * Visit a service used by the current module. The name must be the internal name of an interface - * or a class. - * - * @param service the internal name of the service. - */ - public void visitUse(final String service) { - if (mv != null) { - mv.visitUse(service); - } - } - - /** - * Visit an implementation of a service. - * - * @param service the internal name of the service. - * @param providers the internal names of the implementations of the service (there is at least - * one provider). - */ - public void visitProvide(final String service, final String... providers) { - if (mv != null) { - mv.visitProvide(service, providers); - } - } - - /** - * Visits the end of the module. This method, which is the last one to be called, is used to - * inform the visitor that everything have been visited. - */ - public void visitEnd() { - if (mv != null) { - mv.visitEnd(); - } - } -} diff --git a/src/main/java/org/objectweb/asm/ModuleWriter.java b/src/main/java/org/objectweb/asm/ModuleWriter.java deleted file mode 100644 index 773de762..00000000 --- a/src/main/java/org/objectweb/asm/ModuleWriter.java +++ /dev/null @@ -1,287 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * A {@link ModuleVisitor} that generates the corresponding Module, ModulePackages and - * ModuleMainClass attributes, as defined in the Java Virtual Machine Specification (JVMS). - * - * @author Remi Forax - * @author Eric Bruneton - * @see JVMS - * 4.7.25 - * @see JVMS - * 4.7.26 - * @see JVMS - * 4.7.27 - */ -final class ModuleWriter extends ModuleVisitor { - - /** - * Where the constants used in this AnnotationWriter must be stored. - */ - private final SymbolTable symbolTable; - - /** - * The module_name_index field of the JVMS Module attribute. - */ - private final int moduleNameIndex; - - /** - * The module_flags field of the JVMS Module attribute. - */ - private final int moduleFlags; - - /** - * The module_version_index field of the JVMS Module attribute. - */ - private final int moduleVersionIndex; - - /** - * The requires_count field of the JVMS Module attribute. - */ - private int requiresCount; - - /** - * The binary content of the 'requires' array of the JVMS Module attribute. - */ - private final ByteVector requires; - - /** - * The exports_count field of the JVMS Module attribute. - */ - private int exportsCount; - - /** - * The binary content of the 'exports' array of the JVMS Module attribute. - */ - private final ByteVector exports; - - /** - * The opens_count field of the JVMS Module attribute. - */ - private int opensCount; - - /** - * The binary content of the 'opens' array of the JVMS Module attribute. - */ - private final ByteVector opens; - - /** - * The uses_count field of the JVMS Module attribute. - */ - private int usesCount; - - /** - * The binary content of the 'uses_index' array of the JVMS Module attribute. - */ - private final ByteVector usesIndex; - - /** - * The provides_count field of the JVMS Module attribute. - */ - private int providesCount; - - /** - * The binary content of the 'provides' array of the JVMS Module attribute. - */ - private final ByteVector provides; - - /** - * The provides_count field of the JVMS ModulePackages attribute. - */ - private int packageCount; - - /** - * The binary content of the 'package_index' array of the JVMS ModulePackages attribute. - */ - private final ByteVector packageIndex; - - /** - * The main_class_index field of the JVMS ModuleMainClass attribute, or 0. - */ - private int mainClassIndex; - - ModuleWriter(final SymbolTable symbolTable, final int name, final int access, final int version) { - super(Opcodes.ASM6); - this.symbolTable = symbolTable; - this.moduleNameIndex = name; - this.moduleFlags = access; - this.moduleVersionIndex = version; - this.requires = new ByteVector(); - this.exports = new ByteVector(); - this.opens = new ByteVector(); - this.usesIndex = new ByteVector(); - this.provides = new ByteVector(); - this.packageIndex = new ByteVector(); - } - - @Override - public void visitMainClass(final String mainClass) { - this.mainClassIndex = symbolTable.addConstantClass(mainClass).index; - } - - @Override - public void visitPackage(final String packaze) { - packageIndex.putShort(symbolTable.addConstantPackage(packaze).index); - packageCount++; - } - - @Override - public void visitRequire(final String module, final int access, final String version) { - requires - .putShort(symbolTable.addConstantModule(module).index) - .putShort(access) - .putShort(version == null ? 0 : symbolTable.addConstantUtf8(version)); - requiresCount++; - } - - @Override - public void visitExport(final String packaze, final int access, final String... modules) { - exports.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access); - if (modules == null) { - exports.putShort(0); - } else { - exports.putShort(modules.length); - for (String module : modules) { - exports.putShort(symbolTable.addConstantModule(module).index); - } - } - exportsCount++; - } - - @Override - public void visitOpen(final String packaze, final int access, final String... modules) { - opens.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access); - if (modules == null) { - opens.putShort(0); - } else { - opens.putShort(modules.length); - for (String module : modules) { - opens.putShort(symbolTable.addConstantModule(module).index); - } - } - opensCount++; - } - - @Override - public void visitUse(final String service) { - usesIndex.putShort(symbolTable.addConstantClass(service).index); - usesCount++; - } - - @Override - public void visitProvide(final String service, final String... providers) { - provides.putShort(symbolTable.addConstantClass(service).index); - provides.putShort(providers.length); - for (String provider : providers) { - provides.putShort(symbolTable.addConstantClass(provider).index); - } - providesCount++; - } - - @Override - public void visitEnd() { - // Nothing to do. - } - - /** - * Returns the number of Module, ModulePackages and ModuleMainClass attributes generated by this - * ModuleWriter. - * - * @return the number of Module, ModulePackages and ModuleMainClass attributes (between 1 and 3). - */ - int getAttributeCount() { - return 1 + (packageCount > 0 ? 1 : 0) + (mainClassIndex > 0 ? 1 : 0); - } - - /** - * Returns the size of the Module, ModulePackages and ModuleMainClass attributes generated by this - * ModuleWriter. Also add the names of these attributes in the constant pool. - * - * @return the size in bytes of the Module, ModulePackages and ModuleMainClass attributes. - */ - int computeAttributesSize() { - symbolTable.addConstantUtf8(Constants.MODULE); - // 6 attribute header bytes, 6 bytes for name, flags and version, and 5 * 2 bytes for counts. - int size = - 22 + requires.length + exports.length + opens.length + usesIndex.length + provides.length; - if (packageCount > 0) { - symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES); - // 6 attribute header bytes, and 2 bytes for package_count. - size += 8 + packageIndex.length; - } - if (mainClassIndex > 0) { - symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS); - // 6 attribute header bytes, and 2 bytes for main_class_index. - size += 8; - } - return size; - } - - /** - * Puts the Module, ModulePackages and ModuleMainClass attributes generated by this ModuleWriter - * in the given ByteVector. - * - * @param output where the attributes must be put. - */ - void putAttributes(final ByteVector output) { - // 6 bytes for name, flags and version, and 5 * 2 bytes for counts. - int moduleAttributeLength = - 16 + requires.length + exports.length + opens.length + usesIndex.length + provides.length; - output - .putShort(symbolTable.addConstantUtf8(Constants.MODULE)) - .putInt(moduleAttributeLength) - .putShort(moduleNameIndex) - .putShort(moduleFlags) - .putShort(moduleVersionIndex) - .putShort(requiresCount) - .putByteArray(requires.data, 0, requires.length) - .putShort(exportsCount) - .putByteArray(exports.data, 0, exports.length) - .putShort(opensCount) - .putByteArray(opens.data, 0, opens.length) - .putShort(usesCount) - .putByteArray(usesIndex.data, 0, usesIndex.length) - .putShort(providesCount) - .putByteArray(provides.data, 0, provides.length); - if (packageCount > 0) { - output - .putShort(symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES)) - .putInt(2 + packageIndex.length) - .putShort(packageCount) - .putByteArray(packageIndex.data, 0, packageIndex.length); - } - if (mainClassIndex > 0) { - output - .putShort(symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS)) - .putInt(2) - .putShort(mainClassIndex); - } - } -} diff --git a/src/main/java/org/objectweb/asm/Opcodes.java b/src/main/java/org/objectweb/asm/Opcodes.java deleted file mode 100644 index ed3faeb8..00000000 --- a/src/main/java/org/objectweb/asm/Opcodes.java +++ /dev/null @@ -1,331 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * The JVM opcodes, access flags and array type codes. This interface does not define all the JVM - * opcodes because some opcodes are automatically handled. For example, the xLOAD and xSTORE opcodes - * are automatically replaced by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and - * xSTORE_n opcodes are therefore not defined in this interface. Likewise for LDC, automatically - * replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and JSR_W. - * - * @author Eric Bruneton - * @author Eugene Kuleshov - * @see JVMS 6 - */ -public interface Opcodes { - - // ASM API versions. - - int ASM4 = 4 << 16 | 0 << 8; - int ASM5 = 5 << 16 | 0 << 8; - int ASM6 = 6 << 16 | 0 << 8; - - // Java ClassFile versions (the minor version is stored in the 16 most significant bits, and the - // major version in the 16 least significant bits). - - int V1_1 = 3 << 16 | 45; - int V1_2 = 0 << 16 | 46; - int V1_3 = 0 << 16 | 47; - int V1_4 = 0 << 16 | 48; - int V1_5 = 0 << 16 | 49; - int V1_6 = 0 << 16 | 50; - int V1_7 = 0 << 16 | 51; - int V1_8 = 0 << 16 | 52; - int V9 = 0 << 16 | 53; - int V10 = 0 << 16 | 54; - - // Access flags values, defined in - // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.1-200-E.1 - // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.5-200-A.1 - // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.6-200-A.1 - // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.25 - - int ACC_PUBLIC = 0x0001; // class, field, method - int ACC_PRIVATE = 0x0002; // class, field, method - int ACC_PROTECTED = 0x0004; // class, field, method - int ACC_STATIC = 0x0008; // field, method - int ACC_FINAL = 0x0010; // class, field, method, parameter - int ACC_SUPER = 0x0020; // class - int ACC_SYNCHRONIZED = 0x0020; // method - int ACC_OPEN = 0x0020; // module - int ACC_TRANSITIVE = 0x0020; // module requires - int ACC_VOLATILE = 0x0040; // field - int ACC_BRIDGE = 0x0040; // method - int ACC_STATIC_PHASE = 0x0040; // module requires - int ACC_VARARGS = 0x0080; // method - int ACC_TRANSIENT = 0x0080; // field - int ACC_NATIVE = 0x0100; // method - int ACC_INTERFACE = 0x0200; // class - int ACC_ABSTRACT = 0x0400; // class, method - int ACC_STRICT = 0x0800; // method - int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module * - int ACC_ANNOTATION = 0x2000; // class - int ACC_ENUM = 0x4000; // class(?) field inner - int ACC_MANDATED = 0x8000; // parameter, module, module * - int ACC_MODULE = 0x8000; // class - - // ASM specific access flags. - // WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard - // access flags, and also to make sure that these flags are automatically filtered out when - // written in class files (because access flags are stored using 16 bits only). - - int ACC_DEPRECATED = 0x20000; // class, field, method - - // Possible values for the type operand of the NEWARRAY instruction. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html#jvms-6.5.newarray. - - int T_BOOLEAN = 4; - int T_CHAR = 5; - int T_FLOAT = 6; - int T_DOUBLE = 7; - int T_BYTE = 8; - int T_SHORT = 9; - int T_INT = 10; - int T_LONG = 11; - - // Possible values for the reference_kind field of CONSTANT_MethodHandle_info structures. - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4.8. - - int H_GETFIELD = 1; - int H_GETSTATIC = 2; - int H_PUTFIELD = 3; - int H_PUTSTATIC = 4; - int H_INVOKEVIRTUAL = 5; - int H_INVOKESTATIC = 6; - int H_INVOKESPECIAL = 7; - int H_NEWINVOKESPECIAL = 8; - int H_INVOKEINTERFACE = 9; - - // ASM specific stack map frame types, used in {@link ClassVisitor#visitFrame}. - - /** - * An expanded frame. See {@link ClassReader#EXPAND_FRAMES}. - */ - int F_NEW = -1; - - /** - * A compressed frame with complete frame data. - */ - int F_FULL = 0; - - /** - * A compressed frame where locals are the same as the locals in the previous frame, except that - * additional 1-3 locals are defined, and with an empty stack. - */ - int F_APPEND = 1; - - /** - * A compressed frame where locals are the same as the locals in the previous frame, except that - * the last 1-3 locals are absent and with an empty stack. - */ - int F_CHOP = 2; - - /** - * A compressed frame with exactly the same locals as the previous frame and with an empty stack. - */ - int F_SAME = 3; - - /** - * A compressed frame with exactly the same locals as the previous frame and with a single value - * on the stack. - */ - int F_SAME1 = 4; - - // Standard stack map frame element types, used in {@link ClassVisitor#visitFrame}. - - Integer TOP = Frame.ITEM_TOP; - Integer INTEGER = Frame.ITEM_INTEGER; - Integer FLOAT = Frame.ITEM_FLOAT; - Integer DOUBLE = Frame.ITEM_DOUBLE; - Integer LONG = Frame.ITEM_LONG; - Integer NULL = Frame.ITEM_NULL; - Integer UNINITIALIZED_THIS = Frame.ITEM_UNINITIALIZED_THIS; - - // The JVM opcode values (with the MethodVisitor method name used to visit them in comment, and - // where '-' means 'same method name as on the previous line'). - // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html. - - int NOP = 0; // visitInsn - int ACONST_NULL = 1; // - - int ICONST_M1 = 2; // - - int ICONST_0 = 3; // - - int ICONST_1 = 4; // - - int ICONST_2 = 5; // - - int ICONST_3 = 6; // - - int ICONST_4 = 7; // - - int ICONST_5 = 8; // - - int LCONST_0 = 9; // - - int LCONST_1 = 10; // - - int FCONST_0 = 11; // - - int FCONST_1 = 12; // - - int FCONST_2 = 13; // - - int DCONST_0 = 14; // - - int DCONST_1 = 15; // - - int BIPUSH = 16; // visitIntInsn - int SIPUSH = 17; // - - int LDC = 18; // visitLdcInsn - int ILOAD = 21; // visitVarInsn - int LLOAD = 22; // - - int FLOAD = 23; // - - int DLOAD = 24; // - - int ALOAD = 25; // - - int IALOAD = 46; // visitInsn - int LALOAD = 47; // - - int FALOAD = 48; // - - int DALOAD = 49; // - - int AALOAD = 50; // - - int BALOAD = 51; // - - int CALOAD = 52; // - - int SALOAD = 53; // - - int ISTORE = 54; // visitVarInsn - int LSTORE = 55; // - - int FSTORE = 56; // - - int DSTORE = 57; // - - int ASTORE = 58; // - - int IASTORE = 79; // visitInsn - int LASTORE = 80; // - - int FASTORE = 81; // - - int DASTORE = 82; // - - int AASTORE = 83; // - - int BASTORE = 84; // - - int CASTORE = 85; // - - int SASTORE = 86; // - - int POP = 87; // - - int POP2 = 88; // - - int DUP = 89; // - - int DUP_X1 = 90; // - - int DUP_X2 = 91; // - - int DUP2 = 92; // - - int DUP2_X1 = 93; // - - int DUP2_X2 = 94; // - - int SWAP = 95; // - - int IADD = 96; // - - int LADD = 97; // - - int FADD = 98; // - - int DADD = 99; // - - int ISUB = 100; // - - int LSUB = 101; // - - int FSUB = 102; // - - int DSUB = 103; // - - int IMUL = 104; // - - int LMUL = 105; // - - int FMUL = 106; // - - int DMUL = 107; // - - int IDIV = 108; // - - int LDIV = 109; // - - int FDIV = 110; // - - int DDIV = 111; // - - int IREM = 112; // - - int LREM = 113; // - - int FREM = 114; // - - int DREM = 115; // - - int INEG = 116; // - - int LNEG = 117; // - - int FNEG = 118; // - - int DNEG = 119; // - - int ISHL = 120; // - - int LSHL = 121; // - - int ISHR = 122; // - - int LSHR = 123; // - - int IUSHR = 124; // - - int LUSHR = 125; // - - int IAND = 126; // - - int LAND = 127; // - - int IOR = 128; // - - int LOR = 129; // - - int IXOR = 130; // - - int LXOR = 131; // - - int IINC = 132; // visitIincInsn - int I2L = 133; // visitInsn - int I2F = 134; // - - int I2D = 135; // - - int L2I = 136; // - - int L2F = 137; // - - int L2D = 138; // - - int F2I = 139; // - - int F2L = 140; // - - int F2D = 141; // - - int D2I = 142; // - - int D2L = 143; // - - int D2F = 144; // - - int I2B = 145; // - - int I2C = 146; // - - int I2S = 147; // - - int LCMP = 148; // - - int FCMPL = 149; // - - int FCMPG = 150; // - - int DCMPL = 151; // - - int DCMPG = 152; // - - int IFEQ = 153; // visitJumpInsn - int IFNE = 154; // - - int IFLT = 155; // - - int IFGE = 156; // - - int IFGT = 157; // - - int IFLE = 158; // - - int IF_ICMPEQ = 159; // - - int IF_ICMPNE = 160; // - - int IF_ICMPLT = 161; // - - int IF_ICMPGE = 162; // - - int IF_ICMPGT = 163; // - - int IF_ICMPLE = 164; // - - int IF_ACMPEQ = 165; // - - int IF_ACMPNE = 166; // - - int GOTO = 167; // - - int JSR = 168; // - - int RET = 169; // visitVarInsn - int TABLESWITCH = 170; // visiTableSwitchInsn - int LOOKUPSWITCH = 171; // visitLookupSwitch - int IRETURN = 172; // visitInsn - int LRETURN = 173; // - - int FRETURN = 174; // - - int DRETURN = 175; // - - int ARETURN = 176; // - - int RETURN = 177; // - - int GETSTATIC = 178; // visitFieldInsn - int PUTSTATIC = 179; // - - int GETFIELD = 180; // - - int PUTFIELD = 181; // - - int INVOKEVIRTUAL = 182; // visitMethodInsn - int INVOKESPECIAL = 183; // - - int INVOKESTATIC = 184; // - - int INVOKEINTERFACE = 185; // - - int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn - int NEW = 187; // visitTypeInsn - int NEWARRAY = 188; // visitIntInsn - int ANEWARRAY = 189; // visitTypeInsn - int ARRAYLENGTH = 190; // visitInsn - int ATHROW = 191; // - - int CHECKCAST = 192; // visitTypeInsn - int INSTANCEOF = 193; // - - int MONITORENTER = 194; // visitInsn - int MONITOREXIT = 195; // - - int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn - int IFNULL = 198; // visitJumpInsn - int IFNONNULL = 199; // - -} diff --git a/src/main/java/org/objectweb/asm/Symbol.java b/src/main/java/org/objectweb/asm/Symbol.java deleted file mode 100644 index cb9157de..00000000 --- a/src/main/java/org/objectweb/asm/Symbol.java +++ /dev/null @@ -1,273 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * An entry of the constant pool, of the BootstrapMethods attribute, or of the (ASM specific) type - * table of a class. - * - * @author Eric Bruneton - * @see JVMS - * 4.4 - * @see JVMS - * 4.7.23 - */ -abstract class Symbol { - - // Tag values for the constant pool entries (using the same order as in the JVMS). - - /** - * The tag value of CONSTANT_Class_info JVMS structures. - */ - static final int CONSTANT_CLASS_TAG = 7; - - /** - * The tag value of CONSTANT_Fieldref_info JVMS structures. - */ - static final int CONSTANT_FIELDREF_TAG = 9; - - /** - * The tag value of CONSTANT_Methodref_info JVMS structures. - */ - static final int CONSTANT_METHODREF_TAG = 10; - - /** - * The tag value of CONSTANT_InterfaceMethodref_info JVMS structures. - */ - static final int CONSTANT_INTERFACE_METHODREF_TAG = 11; - - /** - * The tag value of CONSTANT_String_info JVMS structures. - */ - static final int CONSTANT_STRING_TAG = 8; - - /** - * The tag value of CONSTANT_Integer_info JVMS structures. - */ - static final int CONSTANT_INTEGER_TAG = 3; - - /** - * The tag value of CONSTANT_Float_info JVMS structures. - */ - static final int CONSTANT_FLOAT_TAG = 4; - - /** - * The tag value of CONSTANT_Long_info JVMS structures. - */ - static final int CONSTANT_LONG_TAG = 5; - - /** - * The tag value of CONSTANT_Double_info JVMS structures. - */ - static final int CONSTANT_DOUBLE_TAG = 6; - - /** - * The tag value of CONSTANT_NameAndType_info JVMS structures. - */ - static final int CONSTANT_NAME_AND_TYPE_TAG = 12; - - /** - * The tag value of CONSTANT_Utf8_info JVMS structures. - */ - static final int CONSTANT_UTF8_TAG = 1; - - /** - * The tag value of CONSTANT_MethodHandle_info JVMS structures. - */ - static final int CONSTANT_METHOD_HANDLE_TAG = 15; - - /** - * The tag value of CONSTANT_MethodType_info JVMS structures. - */ - static final int CONSTANT_METHOD_TYPE_TAG = 16; - - /** - * The tag value of CONSTANT_InvokeDynamic_info JVMS structures. - */ - static final int CONSTANT_INVOKE_DYNAMIC_TAG = 18; - - /** - * The tag value of CONSTANT_Module_info JVMS structures. - */ - static final int CONSTANT_MODULE_TAG = 19; - - /** - * The tag value of CONSTANT_Package_info JVMS structures. - */ - static final int CONSTANT_PACKAGE_TAG = 20; - - // Tag values for the BootstrapMethods attribute entries (ASM specific tag). - - /** - * The tag value of the BootstrapMethods attribute entries. - */ - static final int BOOTSTRAP_METHOD_TAG = 64; - - // Tag values for the type table entries (ASM specific tags). - - /** - * The tag value of a normal type entry in the (ASM specific) type table of a class. - */ - static final int TYPE_TAG = 128; - - /** - * The tag value of an {@link Frame#ITEM_UNINITIALIZED} type entry in the type table of a class. - */ - static final int UNINITIALIZED_TYPE_TAG = 129; - - /** - * The tag value of a merged type entry in the (ASM specific) type table of a class. - */ - static final int MERGED_TYPE_TAG = 130; - - // Instance fields. - - /** - * The index of this symbol in the constant pool, in the BootstrapMethods attribute, or in the - * (ASM specific) type table of a class (depending on the {@link #tag} value). - */ - final int index; - - /** - * A tag indicating the type of this symbol. Must be one of the static tag values defined in this - * class. - */ - final int tag; - - /** - * The internal name of the owner class of this symbol. Only used for {@link - * #CONSTANT_FIELDREF_TAG}, {@link #CONSTANT_METHODREF_TAG}, {@link - * #CONSTANT_INTERFACE_METHODREF_TAG}, and {@link #CONSTANT_METHOD_HANDLE_TAG} symbols. - */ - final String owner; - - /** - * The name of the class field or method corresponding to this symbol. Only used for {@link - * #CONSTANT_FIELDREF_TAG}, {@link #CONSTANT_METHODREF_TAG}, {@link - * #CONSTANT_INTERFACE_METHODREF_TAG}, {@link #CONSTANT_NAME_AND_TYPE_TAG}, {@link - * #CONSTANT_METHOD_HANDLE_TAG} and {@link #CONSTANT_INVOKE_DYNAMIC_TAG} symbols. - */ - final String name; - - /** - * The string value of this symbol. This is: - * - *

    - *
  • a field or method descriptor for {@link #CONSTANT_FIELDREF_TAG}, {@link - * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG}, {@link - * #CONSTANT_NAME_AND_TYPE_TAG}, {@link #CONSTANT_METHOD_HANDLE_TAG}, {@link - * #CONSTANT_METHOD_TYPE_TAG} and {@link #CONSTANT_INVOKE_DYNAMIC_TAG} symbols, - *
  • an arbitrary string for {@link #CONSTANT_UTF8_TAG} and {@link #CONSTANT_STRING_TAG} - * symbols, - *
  • an internal class name for {@link #CONSTANT_CLASS_TAG}, {@link #TYPE_TAG} and {@link - * #UNINITIALIZED_TYPE_TAG} symbols, - *
  • null for the other types of symbol. - *
- */ - final String value; - - /** - * The numeric value of this symbol. This is: - * - *
    - *
  • the symbol's value for {@link #CONSTANT_INTEGER_TAG},{@link #CONSTANT_FLOAT_TAG}, {@link - * #CONSTANT_LONG_TAG}, {@link #CONSTANT_DOUBLE_TAG}, - *
  • the CONSTANT_MethodHandle_info reference_kind field value for {@link - * #CONSTANT_METHOD_HANDLE_TAG} symbols, - *
  • the CONSTANT_InvokeDynamic_info bootstrap_method_attr_index field value for {@link - * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols, - *
  • the offset of a bootstrap method in the BootstrapMethods boostrap_methods array, for - * {@link #BOOTSTRAP_METHOD_TAG} symbols, - *
  • the bytecode offset of the NEW instruction that created an {@link - * Frame#ITEM_UNINITIALIZED} type for {@link #UNINITIALIZED_TYPE_TAG} symbols, - *
  • the indices (in the class' type table) of two {@link #TYPE_TAG} source types for {@link - * #MERGED_TYPE_TAG} symbols, - *
  • 0 for the other types of symbol. - *
- */ - final long data; - - /** - * Additional information about this symbol, generally computed lazily. Warning: the value of - * this field is ignored when comparing Symbol instances (to avoid duplicate entries in a - * SymbolTable). Therefore, this field should only contain data that can be computed from the - * other fields of this class. It contains: - * - *
    - *
  • the {@link Type#getArgumentsAndReturnSizes} of the symbol's method descriptor for {@link - * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link - * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols, - *
  • the index in the InnerClasses_attribute 'classes' array (plus one) corresponding to this - * class, for {@link #CONSTANT_CLASS_TAG} symbols, - *
  • the index (in the class' type table) of the merged type of the two source types for - * {@link #MERGED_TYPE_TAG} symbols, - *
  • 0 for the other types of symbol, or if this field has not been computed yet. - *
- */ - int info; - - /** - * Constructs a new Symbol. This constructor can't be used directly because the Symbol class is - * abstract. Instead, use the factory methods of the {@link SymbolTable} class. - * - * @param index the symbol index in the constant pool, in the BootstrapMethods attribute, or in - * the (ASM specific) type table of a class (depending on 'tag'). - * @param tag the symbol type. Must be one of the static tag values defined in this class. - * @param owner The internal name of the symbol's owner class. Maybe null. - * @param name The name of the symbol's corresponding class field or method. Maybe null. - * @param value The string value of this symbol. Maybe null. - * @param data The numeric value of this symbol. - */ - Symbol( - final int index, - final int tag, - final String owner, - final String name, - final String value, - final long data) { - this.index = index; - this.tag = tag; - this.owner = owner; - this.name = name; - this.value = value; - this.data = data; - } - - /** - * @return the result {@link Type#getArgumentsAndReturnSizes} on {@link #value} (memoized in - * {@link #info} for efficiency). This should only be used for {@link - * #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link - * #CONSTANT_INVOKE_DYNAMIC_TAG} symbols. - */ - int getArgumentsAndReturnSizes() { - if (info == 0) { - info = Type.getArgumentsAndReturnSizes(value); - } - return info; - } -} diff --git a/src/main/java/org/objectweb/asm/SymbolTable.java b/src/main/java/org/objectweb/asm/SymbolTable.java deleted file mode 100644 index a90fdd2d..00000000 --- a/src/main/java/org/objectweb/asm/SymbolTable.java +++ /dev/null @@ -1,1239 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -/** - * The constant pool entries, the BootstrapMethods attribute entries and the (ASM specific) type - * table entries of a class. - * - * @author Eric Bruneton - * @see JVMS - * 4.4 - * @see JVMS - * 4.7.23 - */ -final class SymbolTable { - - /** - * An entry of a SymbolTable. This concrete and private subclass of {@link Symbol} adds two fields - * which are only used inside SymbolTable, to implement hash sets of symbols (in order to avoid - * duplicate symbols). See {@link #entries}. - * - * @author Eric Bruneton - */ - private static class Entry extends Symbol { - - /** - * The hash code of this entry. - */ - final int hashCode; - - /** - * Another entry (and so on recursively) having the same hash code (modulo the size of {@link - * #entries}) as this one. - */ - Entry next; - - Entry( - final int index, - final int tag, - final String owner, - final String name, - final String value, - final long data, - final int hashCode) { - super(index, tag, owner, name, value, data); - this.hashCode = hashCode; - } - - Entry(final int index, final int tag, final String value, final int hashCode) { - super(index, tag, /* owner = */ null, /* name = */ null, value, /* data = */ 0); - this.hashCode = hashCode; - } - - Entry(final int index, final int tag, final String value, final long data, final int hashCode) { - super(index, tag, /* owner = */ null, /* name = */ null, value, data); - this.hashCode = hashCode; - } - - Entry( - final int index, final int tag, final String name, final String value, final int hashCode) { - super(index, tag, /* owner = */ null, name, value, /* data = */ 0); - this.hashCode = hashCode; - } - - Entry(final int index, final int tag, final long data, final int hashCode) { - super(index, tag, /* owner = */ null, /* name = */ null, /* value = */ null, data); - this.hashCode = hashCode; - } - } - - /** - * The ClassWriter to which this SymbolTable belongs. This is only used to get access to {@link - * ClassWriter#getCommonSuperClass} and to serialize custom attributes with {@link - * Attribute#write}. - */ - final ClassWriter classWriter; - - /** - * The ClassReader from which this SymbolTable was constructed, or null if it was - * constructed from scratch. - */ - private final ClassReader sourceClassReader; - - /** - * The major version number of the class to which this symbol table belongs. - */ - private int majorVersion; - - /** - * The internal name of the class to which this symbol table belongs. - */ - private String className; - - /** - * The total number of {@link Entry} instances in {@link #entries}. This includes entries that are - * accessible (recursively) via {@link Entry#next}. - */ - private int entryCount; - - /** - * A hash set of all the entries in this SymbolTable (this includes the constant pool entries, the - * bootstrap method entries and the type table entries). Each {@link Entry} instance is stored at - * the array index given by its hash code modulo the array size. If several entries must be stored - * at the same array index, they are linked together via their {@link Entry#next} field. The - * factory methods of this class make sure that this table does not contain duplicated entries. - */ - private Entry[] entries; - - /** - * The number of constant pool items in {@link #constantPool}, plus 1. The first constant pool - * item has index 1, and long and double items count for two items. - */ - private int constantPoolCount; - - /** - * The content of the ClassFile's constant_pool JVMS structure corresponding to this SymbolTable. - * The ClassFile's constant_pool_count field is not included. - */ - private ByteVector constantPool; - - /** - * The number of bootstrap methods in {@link #bootstrapMethods}. Corresponds to the - * BootstrapMethods_attribute's num_bootstrap_methods field value. - */ - private int bootstrapMethodCount; - - /** - * The content of the BootstrapMethods attribute 'bootstrap_methods' array corresponding to this - * SymbolTable. Note that the first 6 bytes of the BootstrapMethods_attribute, and its - * num_bootstrap_methods field, are not included. - */ - private ByteVector bootstrapMethods; - - /** - * The actual number of elements in {@link #typeTable}. These elements are stored from index 0 to - * typeCount (excluded). The other array entries are empty. - */ - private int typeCount; - - /** - * An ASM specific type table used to temporarily store internal names that will not necessarily - * be stored in the constant pool. This type table is used by the control flow and data flow - * analysis algorithm used to compute stack map frames from scratch. This array stores {@link - * Symbol#TYPE_TAG} and {@link Symbol#UNINITIALIZED_TYPE_TAG}) Symbol. The type symbol at index - * i has its {@link Symbol#index} equal to i (and vice versa). - */ - private Entry[] typeTable; - - /** - * Constructs a new, empty SymbolTable for the given ClassWriter. - * - * @param classWriter a ClassWriter. - */ - SymbolTable(final ClassWriter classWriter) { - this.classWriter = classWriter; - this.sourceClassReader = null; - this.entries = new Entry[256]; - this.constantPoolCount = 1; - this.constantPool = new ByteVector(); - } - - /** - * Constructs a new SymbolTable for the given ClassWriter, initialized with the constant pool and - * bootstrap methods of the given ClassReader. - * - * @param classWriter a ClassWriter. - * @param classReader the ClassReader whose constant pool and bootstrap methods must be copied to - * initialize the SymbolTable. - */ - SymbolTable(final ClassWriter classWriter, final ClassReader classReader) { - this.classWriter = classWriter; - this.sourceClassReader = classReader; - - // Copy the constant pool binary content. - byte[] inputBytes = classReader.b; - int constantPoolOffset = classReader.getItem(1) - 1; - int constantPoolLength = classReader.header - constantPoolOffset; - constantPoolCount = classReader.getItemCount(); - constantPool = new ByteVector(constantPoolLength); - constantPool.putByteArray(inputBytes, constantPoolOffset, constantPoolLength); - - // Add the constant pool items in the symbol table entries. Reserve enough space in 'entries' to - // avoid too many hash set collisions (entries is not dynamically resized by the addConstant* - // method calls below), and to account for bootstrap method entries. - entries = new Entry[constantPoolCount * 2]; - char[] charBuffer = new char[classReader.getMaxStringLength()]; - int itemIndex = 1; - while (itemIndex < constantPoolCount) { - int itemOffset = classReader.getItem(itemIndex); - int itemTag = inputBytes[itemOffset - 1]; - int nameAndTypeItemOffset; - switch (itemTag) { - case Symbol.CONSTANT_FIELDREF_TAG: - case Symbol.CONSTANT_METHODREF_TAG: - case Symbol.CONSTANT_INTERFACE_METHODREF_TAG: - nameAndTypeItemOffset = - classReader.getItem(classReader.readUnsignedShort(itemOffset + 2)); - addConstantMemberReference( - itemIndex, - itemTag, - classReader.readClass(itemOffset, charBuffer), - classReader.readUTF8(nameAndTypeItemOffset, charBuffer), - classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer)); - break; - case Symbol.CONSTANT_INTEGER_TAG: - case Symbol.CONSTANT_FLOAT_TAG: - addConstantInteger(itemIndex, itemTag, classReader.readInt(itemOffset)); - break; - case Symbol.CONSTANT_NAME_AND_TYPE_TAG: - addConstantNameAndType( - itemIndex, - classReader.readUTF8(itemOffset, charBuffer), - classReader.readUTF8(itemOffset + 2, charBuffer)); - break; - case Symbol.CONSTANT_LONG_TAG: - case Symbol.CONSTANT_DOUBLE_TAG: - addConstantLong(itemIndex, itemTag, classReader.readLong(itemOffset)); - break; - case Symbol.CONSTANT_UTF8_TAG: - addConstantUtf8(itemIndex, classReader.readUTF(itemIndex, charBuffer)); - break; - case Symbol.CONSTANT_METHOD_HANDLE_TAG: - int memberRefItemOffset = - classReader.getItem(classReader.readUnsignedShort(itemOffset + 1)); - nameAndTypeItemOffset = - classReader.getItem(classReader.readUnsignedShort(memberRefItemOffset + 2)); - addConstantMethodHandle( - itemIndex, - classReader.readByte(itemOffset), - classReader.readClass(memberRefItemOffset, charBuffer), - classReader.readUTF8(nameAndTypeItemOffset, charBuffer), - classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer)); - break; - case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG: - nameAndTypeItemOffset = - classReader.getItem(classReader.readUnsignedShort(itemOffset + 2)); - addConstantInvokeDynamic( - itemIndex, - classReader.readUTF8(nameAndTypeItemOffset, charBuffer), - classReader.readUTF8(nameAndTypeItemOffset + 2, charBuffer), - classReader.readUnsignedShort(itemOffset)); - break; - case Symbol.CONSTANT_STRING_TAG: - case Symbol.CONSTANT_CLASS_TAG: - case Symbol.CONSTANT_METHOD_TYPE_TAG: - case Symbol.CONSTANT_MODULE_TAG: - case Symbol.CONSTANT_PACKAGE_TAG: - addConstantUtf8Reference( - itemIndex, itemTag, classReader.readUTF8(itemOffset, charBuffer)); - break; - default: - throw new IllegalArgumentException(); - } - itemIndex += - (itemTag == Symbol.CONSTANT_LONG_TAG || itemTag == Symbol.CONSTANT_DOUBLE_TAG) ? 2 : 1; - } - - // Copy the BootstrapMethods 'bootstrap_methods' array binary content, if any. - int currentAttributeOffset = classReader.getFirstAttributeOffset(); - for (int i = classReader.readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { - String attributeName = classReader.readUTF8(currentAttributeOffset, charBuffer); - if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) { - bootstrapMethodCount = classReader.readUnsignedShort(currentAttributeOffset + 6); - break; - } - currentAttributeOffset += 6 + classReader.readInt(currentAttributeOffset + 2); - } - if (bootstrapMethodCount > 0) { - // Compute the offset and the length of the BootstrapMethods 'bootstrap_methods' array. - int bootstrapMethodsOffset = currentAttributeOffset + 8; - int bootstrapMethodsLength = classReader.readInt(currentAttributeOffset + 2) - 2; - bootstrapMethods = new ByteVector(bootstrapMethodsLength); - bootstrapMethods.putByteArray(inputBytes, bootstrapMethodsOffset, bootstrapMethodsLength); - - // Add each bootstrap method in the symbol table entries. - int currentOffset = bootstrapMethodsOffset; - for (int i = 0; i < bootstrapMethodCount; i++) { - int offset = currentOffset - bootstrapMethodsOffset; - int bootstrapMethodRef = classReader.readUnsignedShort(currentOffset); - currentOffset += 2; - int numBootstrapArguments = classReader.readUnsignedShort(currentOffset); - currentOffset += 2; - int hashCode = classReader.readConst(bootstrapMethodRef, charBuffer).hashCode(); - while (numBootstrapArguments-- > 0) { - int bootstrapArgument = classReader.readUnsignedShort(currentOffset); - currentOffset += 2; - hashCode ^= classReader.readConst(bootstrapArgument, charBuffer).hashCode(); - } - add(new Entry(i, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode & 0x7FFFFFFF)); - } - } - } - - /** - * @return the ClassReader from which this SymbolTable was constructed, or null if it was - * constructed from scratch. - */ - ClassReader getSource() { - return sourceClassReader; - } - - /** - * @return the major version of the class to which this symbol table belongs. - */ - int getMajorVersion() { - return majorVersion; - } - - /** - * @return the internal name of the class to which this symbol table belongs. - */ - String getClassName() { - return className; - } - - /** - * Sets the major version and the name of the class to which this symbol table belongs. Also adds - * the class name to the constant pool. - * - * @param majorVersion a major ClassFile version number. - * @param className an internal class name. - * @return the constant pool index of a new or already existing Symbol with the given class name. - */ - int setMajorVersionAndClassName(final int majorVersion, final String className) { - this.majorVersion = majorVersion; - this.className = className; - return addConstantClass(className).index; - } - - /** - * @return the number of items in this symbol table's constant_pool array (plus 1). - */ - int getConstantPoolCount() { - return constantPoolCount; - } - - /** - * @return the length in bytes of this symbol table's constant_pool array. - */ - int getConstantPoolLength() { - return constantPool.length; - } - - /** - * Puts this symbol table's constant_pool array in the given ByteVector, preceded by the - * constant_pool_count value. - * - * @param output where the JVMS ClassFile's constant_pool array must be put. - */ - void putConstantPool(final ByteVector output) { - output.putShort(constantPoolCount).putByteArray(constantPool.data, 0, constantPool.length); - } - - /** - * Returns the size in bytes of this symbol table's BootstrapMethods attribute. Also adds the - * attribute name in the constant pool. - * - * @return the size in bytes of this symbol table's BootstrapMethods attribute. - */ - int computeBootstrapMethodsSize() { - if (bootstrapMethods != null) { - addConstantUtf8(Constants.BOOTSTRAP_METHODS); - return 8 + bootstrapMethods.length; - } else { - return 0; - } - } - - /** - * Puts this symbol table's BootstrapMethods attribute in the given ByteVector. This includes the - * 6 attribute header bytes and the num_bootstrap_methods value. - * - * @param output where the JVMS BootstrapMethods attribute must be put. - */ - void putBootstrapMethods(final ByteVector output) { - if (bootstrapMethods != null) { - output - .putShort(addConstantUtf8(Constants.BOOTSTRAP_METHODS)) - .putInt(bootstrapMethods.length + 2) - .putShort(bootstrapMethodCount) - .putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length); - } - } - - // ----------------------------------------------------------------------------------------------- - // Generic symbol table entries management. - // ----------------------------------------------------------------------------------------------- - - /** - * @param hashCode a {@link Entry#hashCode} value. - * @return the list of entries which can potentially have the given hash code. The list is stored - * via the {@link Entry#next} field. - */ - private Entry get(final int hashCode) { - return entries[hashCode % entries.length]; - } - - /** - * Puts the given entry in the {@link #entries} hash set. This method does not check - * whether {@link #entries} already contains a similar entry or not. {@link #entries} is resized - * if necessary to avoid hash collisions (multiple entries needing to be stored at the same {@link - * #entries} array index) as much as possible, with reasonable memory usage. - * - * @param entry an Entry (which must not already be contained in {@link #entries}). - * @return the given entry - */ - private Entry put(final Entry entry) { - if (entryCount > (entries.length * 3) / 4) { - int currentCapacity = entries.length; - int newCapacity = currentCapacity * 2 + 1; - Entry[] newEntries = new Entry[newCapacity]; - for (int i = currentCapacity - 1; i >= 0; --i) { - Entry currentEntry = entries[i]; - while (currentEntry != null) { - int newCurrentEntryIndex = currentEntry.hashCode % newCapacity; - Entry nextEntry = currentEntry.next; - currentEntry.next = newEntries[newCurrentEntryIndex]; - newEntries[newCurrentEntryIndex] = currentEntry; - currentEntry = nextEntry; - } - } - entries = newEntries; - } - entryCount++; - int index = entry.hashCode % entries.length; - entry.next = entries[index]; - return entries[index] = entry; - } - - /** - * Adds the given entry in the {@link #entries} hash set. This method does not check - * whether {@link #entries} already contains a similar entry or not, and does not resize - * {@link #entries} if necessary. - * - * @param entry an Entry (which must not already be contained in {@link #entries}). - */ - private void add(final Entry entry) { - entryCount++; - int index = entry.hashCode % entries.length; - entry.next = entries[index]; - entries[index] = entry; - } - - // ----------------------------------------------------------------------------------------------- - // Constant pool entries management. - // ----------------------------------------------------------------------------------------------- - - /** - * Adds a number or string constant to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value the value of the constant to be added to the constant pool. This parameter must be - * an {@link Integer}, {@link Byte}, {@link Character}, {@link Short}, {@link Boolean}, {@link - * Float}, {@link Long}, {@link Double}, {@link String}, {@link Type} or {@link Handle}. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstant(final Object value) { - if (value instanceof Integer) { - return addConstantInteger(((Integer) value).intValue()); - } else if (value instanceof Byte) { - return addConstantInteger(((Byte) value).intValue()); - } else if (value instanceof Character) { - return addConstantInteger(((Character) value).charValue()); - } else if (value instanceof Short) { - return addConstantInteger(((Short) value).intValue()); - } else if (value instanceof Boolean) { - return addConstantInteger(((Boolean) value).booleanValue() ? 1 : 0); - } else if (value instanceof Float) { - return addConstantFloat(((Float) value).floatValue()); - } else if (value instanceof Long) { - return addConstantLong(((Long) value).longValue()); - } else if (value instanceof Double) { - return addConstantDouble(((Double) value).doubleValue()); - } else if (value instanceof String) { - return addConstantString((String) value); - } else if (value instanceof Type) { - Type type = (Type) value; - int typeSort = type.getSort(); - if (typeSort == Type.OBJECT) { - return addConstantClass(type.getInternalName()); - } else if (typeSort == Type.METHOD) { - return addConstantMethodType(type.getDescriptor()); - } else { // type is a primitive or array type. - return addConstantClass(type.getDescriptor()); - } - } else if (value instanceof Handle) { - Handle handle = (Handle) value; - return addConstantMethodHandle( - handle.tag, handle.owner, handle.name, handle.descriptor, handle.isInterface); - } else { - throw new IllegalArgumentException("value " + value); - } - } - - /** - * Adds a CONSTANT_Class_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value the internal name of a class. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantClass(final String value) { - return addConstantUtf8Reference(Symbol.CONSTANT_CLASS_TAG, value); - } - - /** - * Adds a CONSTANT_Fieldref_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param owner the internal name of a class. - * @param name a field name. - * @param descriptor a field descriptor. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantFieldref(final String owner, final String name, final String descriptor) { - return addConstantMemberReference(Symbol.CONSTANT_FIELDREF_TAG, owner, name, descriptor); - } - - /** - * Adds a CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to the constant pool of this - * symbol table. Does nothing if the constant pool already contains a similar item. - * - * @param owner the internal name of a class. - * @param name a method name. - * @param descriptor a method descriptor. - * @param isInterface whether owner is an interface or not. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantMethodref( - final String owner, final String name, final String descriptor, final boolean isInterface) { - int tag = isInterface ? Symbol.CONSTANT_INTERFACE_METHODREF_TAG : Symbol.CONSTANT_METHODREF_TAG; - return addConstantMemberReference(tag, owner, name, descriptor); - } - - /** - * Adds a CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info to - * the constant pool of this symbol table. Does nothing if the constant pool already contains a - * similar item. - * - * @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG} - * or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}. - * @param owner the internal name of a class. - * @param name a field or method name. - * @param descriptor a field or method descriptor. - * @return a new or already existing Symbol with the given value. - */ - private Entry addConstantMemberReference( - final int tag, final String owner, final String name, final String descriptor) { - int hashCode = hash(tag, owner, name, descriptor); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == tag - && entry.hashCode == hashCode - && entry.owner.equals(owner) - && entry.name.equals(name) - && entry.value.equals(descriptor)) { - return entry; - } - entry = entry.next; - } - constantPool.put122( - tag, addConstantClass(owner).index, addConstantNameAndType(name, descriptor)); - return put(new Entry(constantPoolCount++, tag, owner, name, descriptor, 0, hashCode)); - } - - /** - * Adds a new CONSTANT_Fieldref_info, CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info - * to the constant pool of this symbol table. - * - * @param index the constant pool index of the new Symbol. - * @param tag one of {@link Symbol#CONSTANT_FIELDREF_TAG}, {@link Symbol#CONSTANT_METHODREF_TAG} - * or {@link Symbol#CONSTANT_INTERFACE_METHODREF_TAG}. - * @param owner the internal name of a class. - * @param name a field or method name. - * @param descriptor a field or method descriptor. - */ - private void addConstantMemberReference( - final int index, - final int tag, - final String owner, - final String name, - final String descriptor) { - add(new Entry(index, tag, owner, name, descriptor, 0, hash(tag, owner, name, descriptor))); - } - - /** - * Adds a CONSTANT_String_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value a string. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantString(final String value) { - return addConstantUtf8Reference(Symbol.CONSTANT_STRING_TAG, value); - } - - /** - * Adds a CONSTANT_Integer_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value an int. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantInteger(final int value) { - return addConstantInteger(Symbol.CONSTANT_INTEGER_TAG, value); - } - - /** - * Adds a CONSTANT_Float_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value a float. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantFloat(final float value) { - return addConstantInteger(Symbol.CONSTANT_FLOAT_TAG, Float.floatToRawIntBits(value)); - } - - /** - * Adds a CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol table. - * Does nothing if the constant pool already contains a similar item. - * - * @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}. - * @param value an int or float. - * @return a constant pool constant with the given tag and primitive values. - */ - private Symbol addConstantInteger(final int tag, final int value) { - int hashCode = hash(tag, value); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) { - return entry; - } - entry = entry.next; - } - constantPool.putByte(tag).putInt(value); - return put(new Entry(constantPoolCount++, tag, value, hashCode)); - } - - /** - * Adds a new CONSTANT_Integer_info or CONSTANT_Float_info to the constant pool of this symbol - * table. - * - * @param index the constant pool index of the new Symbol. - * @param tag one of {@link Symbol#CONSTANT_INTEGER_TAG} or {@link Symbol#CONSTANT_FLOAT_TAG}. - * @param value an int or float. - */ - private void addConstantInteger(final int index, final int tag, final int value) { - add(new Entry(index, tag, value, hash(tag, value))); - } - - /** - * Adds a CONSTANT_Long_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value a long. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantLong(final long value) { - return addConstantLong(Symbol.CONSTANT_LONG_TAG, value); - } - - /** - * Adds a CONSTANT_Double_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value a double. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantDouble(final double value) { - return addConstantLong(Symbol.CONSTANT_DOUBLE_TAG, Double.doubleToRawLongBits(value)); - } - - /** - * Adds a CONSTANT_Long_info or CONSTANT_Double_info to the constant pool of this symbol table. - * Does nothing if the constant pool already contains a similar item. - * - * @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}. - * @param value a long or double. - * @return a constant pool constant with the given tag and primitive values. - */ - private Symbol addConstantLong(final int tag, final long value) { - int hashCode = hash(tag, value); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == tag && entry.hashCode == hashCode && entry.data == value) { - return entry; - } - entry = entry.next; - } - int index = constantPoolCount; - constantPool.putByte(tag).putLong(value); - constantPoolCount += 2; - return put(new Entry(index, tag, value, hashCode)); - } - - /** - * Adds a new CONSTANT_Double_info to the constant pool of this symbol table. - * - * @param index the constant pool index of the new Symbol. - * @param tag one of {@link Symbol#CONSTANT_LONG_TAG} or {@link Symbol#CONSTANT_DOUBLE_TAG}. - * @param value a long or double. - */ - private void addConstantLong(final int index, final int tag, final long value) { - add(new Entry(index, tag, value, hash(tag, value))); - } - - /** - * Adds a CONSTANT_NameAndType_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param name a field or method name. - * @param descriptor a field or method descriptor. - * @return a new or already existing Symbol with the given value. - */ - int addConstantNameAndType(final String name, final String descriptor) { - final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG; - int hashCode = hash(tag, name, descriptor); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == tag - && entry.hashCode == hashCode - && entry.name.equals(name) - && entry.value.equals(descriptor)) { - return entry.index; - } - entry = entry.next; - } - constantPool.put122(tag, addConstantUtf8(name), addConstantUtf8(descriptor)); - return put(new Entry(constantPoolCount++, tag, name, descriptor, hashCode)).index; - } - - /** - * Adds a new CONSTANT_NameAndType_info to the constant pool of this symbol table. - * - * @param index the constant pool index of the new Symbol. - * @param name a field or method name. - * @param descriptor a field or method descriptor. - */ - private void addConstantNameAndType(final int index, final String name, final String descriptor) { - final int tag = Symbol.CONSTANT_NAME_AND_TYPE_TAG; - add(new Entry(index, tag, name, descriptor, hash(tag, name, descriptor))); - } - - /** - * Adds a CONSTANT_Utf8_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param value a string. - * @return a new or already existing Symbol with the given value. - */ - int addConstantUtf8(final String value) { - int hashCode = hash(Symbol.CONSTANT_UTF8_TAG, value); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == Symbol.CONSTANT_UTF8_TAG - && entry.hashCode == hashCode - && entry.value.equals(value)) { - return entry.index; - } - entry = entry.next; - } - constantPool.putByte(Symbol.CONSTANT_UTF8_TAG).putUTF8(value); - return put(new Entry(constantPoolCount++, Symbol.CONSTANT_UTF8_TAG, value, hashCode)).index; - } - - /** - * Adds a new CONSTANT_String_info to the constant pool of this symbol table. - * - * @param index the constant pool index of the new Symbol. - * @param value a string. - */ - private void addConstantUtf8(final int index, final String value) { - add(new Entry(index, Symbol.CONSTANT_UTF8_TAG, value, hash(Symbol.CONSTANT_UTF8_TAG, value))); - } - - /** - * Adds a CONSTANT_MethodHandle_info to the constant pool of this symbol table. Does nothing if - * the constant pool already contains a similar item. - * - * @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link - * Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link - * Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link - * Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of a class of interface. - * @param name a field or method name. - * @param descriptor a field or method descriptor. - * @param isInterface whether owner is an interface or not. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantMethodHandle( - final int referenceKind, - final String owner, - final String name, - final String descriptor, - final boolean isInterface) { - final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG; - // Note that we don't need to include isInterface in the hash computation, because it is - // redundant with owner (we can't have the same owner with different isInterface values). - int hashCode = hash(tag, owner, name, descriptor, referenceKind); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == tag - && entry.hashCode == hashCode - && entry.data == referenceKind - && entry.owner.equals(owner) - && entry.name.equals(name) - && entry.value.equals(descriptor)) { - return entry; - } - entry = entry.next; - } - if (referenceKind <= Opcodes.H_PUTSTATIC) { - constantPool.put112(tag, referenceKind, addConstantFieldref(owner, name, descriptor).index); - } else { - constantPool.put112( - tag, referenceKind, addConstantMethodref(owner, name, descriptor, isInterface).index); - } - return put( - new Entry(constantPoolCount++, tag, owner, name, descriptor, referenceKind, hashCode)); - } - - /** - * Adds a new CONSTANT_MethodHandle_info to the constant pool of this symbol table. - * - * @param index the constant pool index of the new Symbol. - * @param referenceKind one of {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link - * Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link - * Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link - * Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}. - * @param owner the internal name of a class of interface. - * @param name a field or method name. - * @param descriptor a field or method descriptor. - */ - private void addConstantMethodHandle( - final int index, - final int referenceKind, - final String owner, - final String name, - final String descriptor) { - final int tag = Symbol.CONSTANT_METHOD_HANDLE_TAG; - int hashCode = hash(tag, owner, name, descriptor, referenceKind); - add(new Entry(index, tag, owner, name, descriptor, referenceKind, hashCode)); - } - - /** - * Adds a CONSTANT_MethodType_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param methodDescriptor a method descriptor. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantMethodType(final String methodDescriptor) { - return addConstantUtf8Reference(Symbol.CONSTANT_METHOD_TYPE_TAG, methodDescriptor); - } - - /** - * Adds a CONSTANT_InvokeDynamic_info to the constant pool of this symbol table. Also adds the - * related bootstrap method to the BootstrapMethods of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param name a method name. - * @param descriptor a method descriptor. - * @param bootstrapMethodHandle a bootstrap method handle. - * @param bootstrapMethodArguments the bootstrap method arguments. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantInvokeDynamic( - final String name, - final String descriptor, - final Handle bootstrapMethodHandle, - final Object... bootstrapMethodArguments) { - Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments); - return addConstantInvokeDynamic(name, descriptor, bootstrapMethod.index); - } - - /** - * Adds a CONSTANT_InvokeDynamic_info to the constant pool of this symbol table. Does nothing if - * the constant pool already contains a similar item. - * - * @param name a method name. - * @param descriptor a method descriptor. - * @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute. - * @return a new or already existing Symbol with the given value. - */ - private Symbol addConstantInvokeDynamic( - final String name, final String descriptor, final int bootstrapMethodIndex) { - final int tag = Symbol.CONSTANT_INVOKE_DYNAMIC_TAG; - int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == tag - && entry.hashCode == hashCode - && entry.data == bootstrapMethodIndex - && entry.name.equals(name) - && entry.value.equals(descriptor)) { - return entry; - } - entry = entry.next; - } - constantPool.put122(tag, bootstrapMethodIndex, addConstantNameAndType(name, descriptor)); - return put( - new Entry( - constantPoolCount++, tag, null, name, descriptor, bootstrapMethodIndex, hashCode)); - } - - /** - * Adds a new CONSTANT_InvokeDynamic_info to the constant pool of this symbol table. - * - * @param index the constant pool index of the new Symbol. - * @param name a method name. - * @param descriptor a method descriptor. - * @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute. - */ - private void addConstantInvokeDynamic( - final int index, final String name, final String descriptor, final int bootstrapMethodIndex) { - final int tag = Symbol.CONSTANT_INVOKE_DYNAMIC_TAG; - int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex); - add(new Entry(index, tag, null, name, descriptor, bootstrapMethodIndex, hashCode)); - } - - /** - * Adds a CONSTANT_Module_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param moduleName a fully qualified name (using dots) of a module. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantModule(final String moduleName) { - return addConstantUtf8Reference(Symbol.CONSTANT_MODULE_TAG, moduleName); - } - - /** - * Adds a CONSTANT_Package_info to the constant pool of this symbol table. Does nothing if the - * constant pool already contains a similar item. - * - * @param packageName the internal name of a package. - * @return a new or already existing Symbol with the given value. - */ - Symbol addConstantPackage(final String packageName) { - return addConstantUtf8Reference(Symbol.CONSTANT_PACKAGE_TAG, packageName); - } - - /** - * Adds a CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info, - * CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table. Does - * nothing if the constant pool already contains a similar item. - * - * @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link - * Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link - * Symbol#CONSTANT_PACKAGE_TAG}. - * @param value an internal class name, an arbitrary string, a method descriptor, a module or a - * package name, depending on tag. - * @return a new or already existing Symbol with the given value. - */ - private Symbol addConstantUtf8Reference(final int tag, final String value) { - int hashCode = hash(tag, value); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == tag && entry.hashCode == hashCode && entry.value.equals(value)) { - return entry; - } - entry = entry.next; - } - constantPool.put12(tag, addConstantUtf8(value)); - return put(new Entry(constantPoolCount++, tag, value, hashCode)); - } - - /** - * Adds a new CONSTANT_Class_info, CONSTANT_String_info, CONSTANT_MethodType_info, - * CONSTANT_Module_info or CONSTANT_Package_info to the constant pool of this symbol table. - * - * @param index the constant pool index of the new Symbol. - * @param tag one of {@link Symbol#CONSTANT_CLASS_TAG}, {@link Symbol#CONSTANT_STRING_TAG}, {@link - * Symbol#CONSTANT_METHOD_TYPE_TAG}, {@link Symbol#CONSTANT_MODULE_TAG} or {@link - * Symbol#CONSTANT_PACKAGE_TAG}. - * @param value an internal class name, an arbitrary string, a method descriptor, a module or a - * package name, depending on tag. - */ - private void addConstantUtf8Reference(final int index, final int tag, final String value) { - add(new Entry(index, tag, value, hash(tag, value))); - } - - // ----------------------------------------------------------------------------------------------- - // Bootstrap method entries management. - // ----------------------------------------------------------------------------------------------- - - /** - * Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if - * the BootstrapMethods already contains a similar bootstrap method. - * - * @param bootstrapMethodHandle a bootstrap method handle. - * @param bootstrapMethodArguments the bootstrap method arguments. - * @return a new or already existing Symbol with the given value. - */ - Symbol addBootstrapMethod( - final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments) { - ByteVector bootstrapMethodsAttribute = bootstrapMethods; - if (bootstrapMethodsAttribute == null) { - bootstrapMethodsAttribute = bootstrapMethods = new ByteVector(); - } - - // Write the bootstrap method in the BootstrapMethods table. This is necessary to be able to - // compare it with existing ones, and will be reverted below if there is already a similar - // bootstrap method. - int bootstrapMethodOffset = bootstrapMethodsAttribute.length; - bootstrapMethodsAttribute.putShort( - addConstantMethodHandle( - bootstrapMethodHandle.tag, - bootstrapMethodHandle.owner, - bootstrapMethodHandle.name, - bootstrapMethodHandle.descriptor, - bootstrapMethodHandle.isInterface()) - .index); - int numBootstrapArguments = bootstrapMethodArguments.length; - bootstrapMethodsAttribute.putShort(numBootstrapArguments); - for (int i = 0; i < numBootstrapArguments; i++) { - bootstrapMethodsAttribute.putShort(addConstant(bootstrapMethodArguments[i]).index); - } - - // Compute the length and the hash code of the bootstrap method. - int bootstrapMethodlength = bootstrapMethodsAttribute.length - bootstrapMethodOffset; - int hashCode = bootstrapMethodHandle.hashCode(); - for (int i = 0; i < numBootstrapArguments; i++) { - hashCode ^= bootstrapMethodArguments[i].hashCode(); - } - hashCode &= 0x7FFFFFFF; - - // Add the bootstrap method to the symbol table or revert the above changes. - return addBootstrapMethod(bootstrapMethodOffset, bootstrapMethodlength, hashCode); - } - - /** - * Adds a bootstrap method to the BootstrapMethods attribute of this symbol table. Does nothing if - * the BootstrapMethods already contains a similar bootstrap method (more precisely, reverts the - * content of {@link #bootstrapMethods} to remove the last, duplicate bootstrap method). - * - * @param offset the offset of the last bootstrap method in {@link #bootstrapMethods}, in bytes. - * @param length the length of this bootstrap method in {@link #bootstrapMethods}, in bytes. - * @param hashCode the hash code of this bootstrap method. - * @return a new or already existing Symbol with the given value. - */ - private Symbol addBootstrapMethod(final int offset, final int length, final int hashCode) { - final byte[] bootstrapMethodsData = bootstrapMethods.data; - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == Symbol.BOOTSTRAP_METHOD_TAG && entry.hashCode == hashCode) { - int otherOffset = (int) entry.data; - boolean isSameBootstrapMethod = true; - for (int i = 0; i < length; ++i) { - if (bootstrapMethodsData[offset + i] != bootstrapMethodsData[otherOffset + i]) { - isSameBootstrapMethod = false; - break; - } - } - if (isSameBootstrapMethod) { - bootstrapMethods.length = offset; // Revert to old position. - return entry; - } - } - entry = entry.next; - } - return put(new Entry(bootstrapMethodCount++, Symbol.BOOTSTRAP_METHOD_TAG, offset, hashCode)); - } - - // ----------------------------------------------------------------------------------------------- - // Type table entries management. - // ----------------------------------------------------------------------------------------------- - - /** - * @param typeIndex a type table index. - * @return the type table element whose index is given. - */ - Symbol getType(final int typeIndex) { - return typeTable[typeIndex]; - } - - /** - * Adds a type in the type table of this symbol table. Does nothing if the type table already - * contains a similar type. - * - * @param value an internal class name. - * @return the index of a new or already existing type Symbol with the given value. - */ - int addType(final String value) { - int hashCode = hash(Symbol.TYPE_TAG, value); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == Symbol.TYPE_TAG && entry.hashCode == hashCode && entry.value.equals(value)) { - return entry.index; - } - entry = entry.next; - } - return addType(new Entry(typeCount, Symbol.TYPE_TAG, value, hashCode)); - } - - /** - * Adds an {@link Frame#ITEM_UNINITIALIZED} type in the type table of this symbol table. Does - * nothing if the type table already contains a similar type. - * - * @param value an internal class name. - * @param bytecodeOffset the bytecode offset of the NEW instruction that created this {@link - * Frame#ITEM_UNINITIALIZED} type value. - * @return the index of a new or already existing type Symbol with the given value. - */ - int addUninitializedType(final String value, final int bytecodeOffset) { - int hashCode = hash(Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == Symbol.UNINITIALIZED_TYPE_TAG - && entry.hashCode == hashCode - && entry.data == bytecodeOffset - && entry.value.equals(value)) { - return entry.index; - } - entry = entry.next; - } - return addType( - new Entry(typeCount, Symbol.UNINITIALIZED_TYPE_TAG, value, bytecodeOffset, hashCode)); - } - - /** - * Adds a merged type in the type table of this symbol table. Does nothing if the type table - * already contains a similar type. - * - * @param typeTableIndex1 a {@link Symbol#TYPE_TAG} type, specified by its index in the type - * table. - * @param typeTableIndex2 another {@link Symbol#TYPE_TAG} type, specified by its index in the type - * table. - * @return the index of a new or already existing {@link Symbol#TYPE_TAG} type Symbol, - * corresponding to the common super class of the given types. - */ - int addMergedType(final int typeTableIndex1, final int typeTableIndex2) { - // TODO sort the arguments? The merge result should be independent of their order. - long data = typeTableIndex1 | (((long) typeTableIndex2) << 32); - int hashCode = hash(Symbol.MERGED_TYPE_TAG, typeTableIndex1 + typeTableIndex2); - Entry entry = get(hashCode); - while (entry != null) { - if (entry.tag == Symbol.MERGED_TYPE_TAG && entry.hashCode == hashCode && entry.data == data) { - return entry.info; - } - entry = entry.next; - } - String type1 = typeTable[typeTableIndex1].value; - String type2 = typeTable[typeTableIndex2].value; - int commonSuperTypeIndex = addType(classWriter.getCommonSuperClass(type1, type2)); - put(new Entry(typeCount, Symbol.MERGED_TYPE_TAG, data, hashCode)).info = commonSuperTypeIndex; - return commonSuperTypeIndex; - } - - /** - * Adds the given type Symbol to {@link #typeTable}. - * - * @param entry a {@link Symbol#TYPE_TAG} or {@link Symbol#UNINITIALIZED_TYPE_TAG} type symbol. - * The index of this Symbol must be equal to the current value of {@link #typeCount}. - * @return the index in {@link #typeTable} where the given type was added, which is also equal to - * entry's index by hypothesis. - */ - private int addType(final Entry entry) { - if (typeTable == null) { - typeTable = new Entry[16]; - } - if (typeCount == typeTable.length) { - Entry[] newTypeTable = new Entry[2 * typeTable.length]; - System.arraycopy(typeTable, 0, newTypeTable, 0, typeTable.length); - typeTable = newTypeTable; - } - typeTable[typeCount++] = entry; - return put(entry).index; - } - - // ----------------------------------------------------------------------------------------------- - // Static helper methods to compute hash codes. - // ----------------------------------------------------------------------------------------------- - - private static int hash(final int tag, final int value) { - return 0x7FFFFFFF & (tag + value); - } - - private static int hash(final int tag, final long value) { - return 0x7FFFFFFF & (tag + (int) value + (int) (value >>> 32)); - } - - private static int hash(final int tag, final String value) { - return 0x7FFFFFFF & (tag + value.hashCode()); - } - - private static int hash(final int tag, final String value1, final int value2) { - return 0x7FFFFFFF & (tag + value1.hashCode() + value2); - } - - private static int hash(final int tag, final String value1, final String value2) { - return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode()); - } - - private static int hash( - final int tag, final String value1, final String value2, final int value3) { - return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * (value3 + 1)); - } - - private static int hash( - final int tag, final String value1, final String value2, final String value3) { - return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode()); - } - - private static int hash( - final int tag, - final String value1, - final String value2, - final String value3, - final int value4) { - return 0x7FFFFFFF & (tag + value1.hashCode() * value2.hashCode() * value3.hashCode() * value4); - } -} diff --git a/src/main/java/org/objectweb/asm/Type.java b/src/main/java/org/objectweb/asm/Type.java deleted file mode 100644 index 9b204401..00000000 --- a/src/main/java/org/objectweb/asm/Type.java +++ /dev/null @@ -1,953 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; - -/** - * A Java field or method type. This class can be used to make it easier to manipulate type and - * method descriptors. - * - * @author Eric Bruneton - * @author Chris Nokleberg - */ -public class Type { - - /** - * The sort of the void type. See {@link #getSort}. - */ - public static final int VOID = 0; - - /** - * The sort of the boolean type. See {@link #getSort}. - */ - public static final int BOOLEAN = 1; - - /** - * The sort of the char type. See {@link #getSort}. - */ - public static final int CHAR = 2; - - /** - * The sort of the byte type. See {@link #getSort}. - */ - public static final int BYTE = 3; - - /** - * The sort of the short type. See {@link #getSort}. - */ - public static final int SHORT = 4; - - /** - * The sort of the int type. See {@link #getSort}. - */ - public static final int INT = 5; - - /** - * The sort of the float type. See {@link #getSort}. - */ - public static final int FLOAT = 6; - - /** - * The sort of the long type. See {@link #getSort}. - */ - public static final int LONG = 7; - - /** - * The sort of the double type. See {@link #getSort}. - */ - public static final int DOUBLE = 8; - - /** - * The sort of array reference types. See {@link #getSort}. - */ - public static final int ARRAY = 9; - - /** - * The sort of object reference types. See {@link #getSort}. - */ - public static final int OBJECT = 10; - - /** - * The sort of method types. See {@link #getSort}. - */ - public static final int METHOD = 11; - - /** - * The (private) sort of object reference types represented with an internal name. - */ - private static final int INTERNAL = 12; - - /** - * The descriptors of the primitive types. - */ - private static final char[] PRIMITIVE_DESCRIPTORS = - new char[]{'V', 'Z', 'C', 'B', 'S', 'I', 'F', 'J', 'D'}; - - /** - * The void type. - */ - public static final Type VOID_TYPE = new Type(VOID, PRIMITIVE_DESCRIPTORS, VOID, 1); - - /** - * The boolean type. - */ - public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, PRIMITIVE_DESCRIPTORS, BOOLEAN, 1); - - /** - * The char type. - */ - public static final Type CHAR_TYPE = new Type(CHAR, PRIMITIVE_DESCRIPTORS, CHAR, 1); - - /** - * The byte type. - */ - public static final Type BYTE_TYPE = new Type(BYTE, PRIMITIVE_DESCRIPTORS, BYTE, 1); - - /** - * The short type. - */ - public static final Type SHORT_TYPE = new Type(SHORT, PRIMITIVE_DESCRIPTORS, SHORT, 1); - - /** - * The int type. - */ - public static final Type INT_TYPE = new Type(INT, PRIMITIVE_DESCRIPTORS, INT, 1); - - /** - * The float type. - */ - public static final Type FLOAT_TYPE = new Type(FLOAT, PRIMITIVE_DESCRIPTORS, FLOAT, 1); - - /** - * The long type. - */ - public static final Type LONG_TYPE = new Type(LONG, PRIMITIVE_DESCRIPTORS, LONG, 1); - - /** - * The double type. - */ - public static final Type DOUBLE_TYPE = new Type(DOUBLE, PRIMITIVE_DESCRIPTORS, DOUBLE, 1); - - // ----------------------------------------------------------------------------------------------- - // Fields - // ----------------------------------------------------------------------------------------------- - - /** - * The sort of this type. Either {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, - * {@link #SHORT}, {@link #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, - * {@link #OBJECT}, {@link #METHOD} or {@link #INTERNAL}. - */ - private final int sort; - - /** - * A buffer containing the value of this field or method type. This value is an internal name for - * {@link #OBJECT} and {@link #INTERNAL} types, and a field or method descriptor in the other - * cases. - * - *

For {@link #OBJECT} types, this field also contains the descriptor: the {@link #valueLength} - * chars after {@link #valueOffset} contain the internal name, and the {@link #valueLength} + 2 - * chars after {@link #valueOffset} - 1 contain the descriptor. - */ - private final char[] valueBuffer; - - /** - * The offset of the value of this Java field or method type in {@link #valueBuffer}. This value - * is an internal name for {@link #OBJECT} and {@link #INTERNAL} types, and a field or method - * descriptor in the other cases. - */ - private final int valueOffset; - - /** - * The length of the value of this Java field or method type in {@link #valueBuffer}. This value - * is an internal name for {@link #OBJECT} and {@link #INTERNAL} types, and a field or method - * descriptor in the other cases. - */ - private final int valueLength; - - // ----------------------------------------------------------------------------------------------- - // Constructors - // ----------------------------------------------------------------------------------------------- - - /** - * Constructs a reference type. - * - * @param sort the sort of this type, see {@link #sort}. - * @param valueBuffer a buffer containing the value of this field or method type. - * @param valueOffset the offset of the value of this field or method type in valueBuffer. - * @param valueLength the length of the value of this field or method type. - */ - private Type( - final int sort, final char[] valueBuffer, final int valueOffset, final int valueLength) { - this.sort = sort; - this.valueBuffer = valueBuffer; - this.valueOffset = valueOffset; - this.valueLength = valueLength; - } - - /** - * Returns the {@link Type} corresponding to the given type descriptor. - * - * @param typeDescriptor a field or method type descriptor. - * @return the {@link Type} corresponding to the given type descriptor. - */ - public static Type getType(final String typeDescriptor) { - final char[] valueBuffer = typeDescriptor.toCharArray(); - return getType(valueBuffer, 0, valueBuffer.length); - } - - /** - * Returns the {@link Type} corresponding to the given internal name. - * - * @param internalName an internal name. - * @return the {@link Type} corresponding to the given internal name. - */ - public static Type getObjectType(final String internalName) { - final char[] valueBuffer = internalName.toCharArray(); - return new Type(valueBuffer[0] == '[' ? ARRAY : INTERNAL, valueBuffer, 0, valueBuffer.length); - } - - /** - * Returns the {@link Type} corresponding to the given method descriptor. Equivalent to - * Type.getType(methodDescriptor). - * - * @param methodDescriptor a method descriptor. - * @return the {@link Type} corresponding to the given method descriptor. - */ - public static Type getMethodType(final String methodDescriptor) { - final char[] valueBuffer = methodDescriptor.toCharArray(); - return new Type(METHOD, valueBuffer, 0, valueBuffer.length); - } - - /** - * Returns the method {@link Type} corresponding to the given argument and return types. - * - * @param returnType the return type of the method. - * @param argumentTypes the argument types of the method. - * @return the method {@link Type} corresponding to the given argument and return types. - */ - public static Type getMethodType(final Type returnType, final Type... argumentTypes) { - return getType(getMethodDescriptor(returnType, argumentTypes)); - } - - /** - * Returns the {@link Type} corresponding to the given class. - * - * @param clazz a class. - * @return the {@link Type} corresponding to the given class. - */ - public static Type getType(final Class clazz) { - if (clazz.isPrimitive()) { - if (clazz == Integer.TYPE) { - return INT_TYPE; - } else if (clazz == Void.TYPE) { - return VOID_TYPE; - } else if (clazz == Boolean.TYPE) { - return BOOLEAN_TYPE; - } else if (clazz == Byte.TYPE) { - return BYTE_TYPE; - } else if (clazz == Character.TYPE) { - return CHAR_TYPE; - } else if (clazz == Short.TYPE) { - return SHORT_TYPE; - } else if (clazz == Double.TYPE) { - return DOUBLE_TYPE; - } else if (clazz == Float.TYPE) { - return FLOAT_TYPE; - } else if (clazz == Long.TYPE) { - return LONG_TYPE; - } else { - throw new AssertionError(); - } - } else { - return getType(getDescriptor(clazz)); - } - } - - /** - * Returns the method {@link Type} corresponding to the given constructor. - * - * @param constructor a {@link Constructor} object. - * @return the method {@link Type} corresponding to the given constructor. - */ - public static Type getType(final Constructor constructor) { - return getType(getConstructorDescriptor(constructor)); - } - - /** - * Returns the method {@link Type} corresponding to the given method. - * - * @param method a {@link Method} object. - * @return the method {@link Type} corresponding to the given method. - */ - public static Type getType(final Method method) { - return getType(getMethodDescriptor(method)); - } - - /** - * Returns the {@link Type} values corresponding to the argument types of the given method - * descriptor. - * - * @param methodDescriptor a method descriptor. - * @return the {@link Type} values corresponding to the argument types of the given method - * descriptor. - */ - public static Type[] getArgumentTypes(final String methodDescriptor) { - // First step: compute the number of argument types in methodDescriptor. - final char[] valueBuffer = methodDescriptor.toCharArray(); - int numArgumentTypes = 0; - // Skip the first character, which is always a '('. - int currentOffset = 1; - // Parse the argument types, one at a each loop iteration. - while (valueBuffer[currentOffset] != ')') { - while (valueBuffer[currentOffset] == '[') { - currentOffset++; - } - if (valueBuffer[currentOffset++] == 'L') { - while (valueBuffer[currentOffset++] != ';') { - // Skip the argument descriptor content. - } - } - ++numArgumentTypes; - } - - // Second step: create a Type instance for each argument type. - Type[] argumentTypes = new Type[numArgumentTypes]; - // Skip the first character, which is always a '('. - currentOffset = 1; - // Parse and create the argument types, one at each loop iteration. - int currentArgumentTypeIndex = 0; - while (valueBuffer[currentOffset] != ')') { - final int currentArgumentTypeOffset = currentOffset; - while (valueBuffer[currentOffset] == '[') { - currentOffset++; - } - if (valueBuffer[currentOffset++] == 'L') { - while (valueBuffer[currentOffset++] != ';') { - // Skip the argument descriptor content. - } - } - argumentTypes[currentArgumentTypeIndex++] = - getType( - valueBuffer, currentArgumentTypeOffset, currentOffset - currentArgumentTypeOffset); - } - return argumentTypes; - } - - /** - * Returns the {@link Type} values corresponding to the argument types of the given method. - * - * @param method a method. - * @return the {@link Type} values corresponding to the argument types of the given method. - */ - public static Type[] getArgumentTypes(final Method method) { - Class[] classes = method.getParameterTypes(); - Type[] types = new Type[classes.length]; - for (int i = classes.length - 1; i >= 0; --i) { - types[i] = getType(classes[i]); - } - return types; - } - - /** - * Returns the {@link Type} corresponding to the return type of the given method descriptor. - * - * @param methodDescriptor a method descriptor. - * @return the {@link Type} corresponding to the return type of the given method descriptor. - */ - public static Type getReturnType(final String methodDescriptor) { - final char[] valueBuffer = methodDescriptor.toCharArray(); - // Skip the first character, which is always a '('. - int currentOffset = 1; - // Skip the argument types, one at a each loop iteration. - while (valueBuffer[currentOffset] != ')') { - while (valueBuffer[currentOffset] == '[') { - currentOffset++; - } - if (valueBuffer[currentOffset++] == 'L') { - while (valueBuffer[currentOffset++] != ';') { - // Skip the argument descriptor content. - } - } - } - return getType(valueBuffer, currentOffset + 1, valueBuffer.length - currentOffset - 1); - } - - /** - * Returns the {@link Type} corresponding to the return type of the given method. - * - * @param method a method. - * @return the {@link Type} corresponding to the return type of the given method. - */ - public static Type getReturnType(final Method method) { - return getType(method.getReturnType()); - } - - /** - * Computes the size of the arguments and of the return value of a method. - * - * @param methodDescriptor a method descriptor. - * @return the size of the arguments of the method (plus one for the implicit this argument), - * argumentsSize, and the size of its return value, returnSize, packed into a single int i = - * (argumentsSize << 2) | returnSize (argumentsSize is therefore equal to i - * >> 2, and returnSize to i & 0x03). - */ - public static int getArgumentsAndReturnSizes(final String methodDescriptor) { - int argumentsSize = 1; - // Skip the first character, which is always a '('. - int currentOffset = 1; - int currentChar = methodDescriptor.charAt(currentOffset); - // Parse the argument types and compute their size, one at a each loop iteration. - while (currentChar != ')') { - if (currentChar == 'J' || currentChar == 'D') { - currentOffset++; - argumentsSize += 2; - } else { - while (methodDescriptor.charAt(currentOffset) == '[') { - currentOffset++; - } - if (methodDescriptor.charAt(currentOffset++) == 'L') { - while (methodDescriptor.charAt(currentOffset++) != ';') { - // Skip the argument descriptor content. - } - } - argumentsSize += 1; - } - currentChar = methodDescriptor.charAt(currentOffset); - } - currentChar = methodDescriptor.charAt(currentOffset + 1); - if (currentChar == 'V') { - return argumentsSize << 2; - } else { - int returnSize = (currentChar == 'J' || currentChar == 'D') ? 2 : 1; - return argumentsSize << 2 | returnSize; - } - } - - /** - * Returns the {@link Type} corresponding to the given field or method descriptor. - * - * @param descriptorBuffer a buffer containing the field or method descriptor. - * @param descriptorOffset the offset of the field or method descriptor in descriptorBuffer. - * @param descriptorLength the length of the field or method descriptor. - * @return the {@link Type} corresponding to the given type descriptor. - */ - private static Type getType( - final char[] descriptorBuffer, final int descriptorOffset, final int descriptorLength) { - switch (descriptorBuffer[descriptorOffset]) { - case 'V': - return VOID_TYPE; - case 'Z': - return BOOLEAN_TYPE; - case 'C': - return CHAR_TYPE; - case 'B': - return BYTE_TYPE; - case 'S': - return SHORT_TYPE; - case 'I': - return INT_TYPE; - case 'F': - return FLOAT_TYPE; - case 'J': - return LONG_TYPE; - case 'D': - return DOUBLE_TYPE; - case '[': - return new Type(ARRAY, descriptorBuffer, descriptorOffset, descriptorLength); - case 'L': - return new Type(OBJECT, descriptorBuffer, descriptorOffset + 1, descriptorLength - 2); - case '(': - return new Type(METHOD, descriptorBuffer, descriptorOffset, descriptorLength); - default: - throw new IllegalArgumentException(); - } - } - - // ----------------------------------------------------------------------------------------------- - // Accessors - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the sort of this type. - * - * @return {@link #VOID}, {@link #BOOLEAN}, {@link #CHAR}, {@link #BYTE}, {@link #SHORT}, {@link - * #INT}, {@link #FLOAT}, {@link #LONG}, {@link #DOUBLE}, {@link #ARRAY}, {@link #OBJECT} or - * {@link #METHOD}. - */ - public int getSort() { - return sort == INTERNAL ? OBJECT : sort; - } - - /** - * Returns the number of dimensions of this array type. This method should only be used for an - * array type. - * - * @return the number of dimensions of this array type. - */ - public int getDimensions() { - int numDimensions = 1; - while (valueBuffer[valueOffset + numDimensions] == '[') { - numDimensions++; - } - return numDimensions; - } - - /** - * Returns the type of the elements of this array type. This method should only be used for an - * array type. - * - * @return Returns the type of the elements of this array type. - */ - public Type getElementType() { - final int numDimensions = getDimensions(); - return getType(valueBuffer, valueOffset + numDimensions, valueLength - numDimensions); - } - - /** - * Returns the binary name of the class corresponding to this type. This method must not be used - * on method types. - * - * @return the binary name of the class corresponding to this type. - */ - public String getClassName() { - switch (sort) { - case VOID: - return "void"; - case BOOLEAN: - return "boolean"; - case CHAR: - return "char"; - case BYTE: - return "byte"; - case SHORT: - return "short"; - case INT: - return "int"; - case FLOAT: - return "float"; - case LONG: - return "long"; - case DOUBLE: - return "double"; - case ARRAY: - StringBuilder stringBuilder = new StringBuilder(getElementType().getClassName()); - for (int i = getDimensions(); i > 0; --i) { - stringBuilder.append("[]"); - } - return stringBuilder.toString(); - case OBJECT: - case INTERNAL: - return new String(valueBuffer, valueOffset, valueLength).replace('/', '.'); - default: - throw new AssertionError(); - } - } - - /** - * Returns the internal name of the class corresponding to this object or array type. The internal - * name of a class is its fully qualified name (as returned by Class.getName(), where '.' are - * replaced by '/'). This method should only be used for an object or array type. - * - * @return the internal name of the class corresponding to this object type. - */ - public String getInternalName() { - return new String(valueBuffer, valueOffset, valueLength); - } - - /** - * Returns the argument types of methods of this type. This method should only be used for method - * types. - * - * @return the argument types of methods of this type. - */ - public Type[] getArgumentTypes() { - return getArgumentTypes(getDescriptor()); - } - - /** - * Returns the return type of methods of this type. This method should only be used for method - * types. - * - * @return the return type of methods of this type. - */ - public Type getReturnType() { - return getReturnType(getDescriptor()); - } - - /** - * Returns the size of the arguments and of the return value of methods of this type. This method - * should only be used for method types. - * - * @return the size of the arguments of the method (plus one for the implicit this argument), - * argumentsSize, and the size of its return value, returnSize, packed into a single int i = - * (argumentsSize << 2) | returnSize (argumentsSize is therefore equal to i - * >> 2, and returnSize to i & 0x03). - */ - public int getArgumentsAndReturnSizes() { - return getArgumentsAndReturnSizes(getDescriptor()); - } - - // ----------------------------------------------------------------------------------------------- - // Conversion to type descriptors - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the descriptor corresponding to this type. - * - * @return the descriptor corresponding to this type. - */ - public String getDescriptor() { - if (sort == OBJECT) { - return new String(valueBuffer, valueOffset - 1, valueLength + 2); - } else if (sort == INTERNAL) { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append('L'); - stringBuilder.append(valueBuffer, valueOffset, valueLength); - stringBuilder.append(';'); - return stringBuilder.toString(); - } else { - return new String(valueBuffer, valueOffset, valueLength); - } - } - - /** - * Returns the descriptor corresponding to the given argument and return types. - * - * @param returnType the return type of the method. - * @param argumentTypes the argument types of the method. - * @return the descriptor corresponding to the given argument and return types. - */ - public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append('('); - for (int i = 0; i < argumentTypes.length; ++i) { - argumentTypes[i].appendDescriptor(stringBuilder); - } - stringBuilder.append(')'); - returnType.appendDescriptor(stringBuilder); - return stringBuilder.toString(); - } - - /** - * Appends the descriptor corresponding to this type to the given string buffer. - * - * @param stringBuilder the string builder to which the descriptor must be appended. - */ - private void appendDescriptor(final StringBuilder stringBuilder) { - if (sort == OBJECT) { - stringBuilder.append(valueBuffer, valueOffset - 1, valueLength + 2); - } else if (sort == INTERNAL) { - stringBuilder.append('L'); - stringBuilder.append(valueBuffer, valueOffset, valueLength); - stringBuilder.append(';'); - } else { - stringBuilder.append(valueBuffer, valueOffset, valueLength); - } - } - - // ----------------------------------------------------------------------------------------------- - // Direct conversion from classes to type descriptors, - // without intermediate Type objects - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the internal name of the given class. The internal name of a class is its fully - * qualified name, as returned by Class.getName(), where '.' are replaced by '/'. - * - * @param clazz an object or array class. - * @return the internal name of the given class. - */ - public static String getInternalName(final Class clazz) { - return clazz.getName().replace('.', '/'); - } - - /** - * Returns the descriptor corresponding to the given class. - * - * @param clazz an object class, a primitive class or an array class. - * @return the descriptor corresponding to the given class. - */ - public static String getDescriptor(final Class clazz) { - StringBuilder stringBuilder = new StringBuilder(); - appendDescriptor(stringBuilder, clazz); - return stringBuilder.toString(); - } - - /** - * Returns the descriptor corresponding to the given constructor. - * - * @param constructor a {@link Constructor} object. - * @return the descriptor of the given constructor. - */ - public static String getConstructorDescriptor(final Constructor constructor) { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append('('); - Class[] parameters = constructor.getParameterTypes(); - for (int i = 0; i < parameters.length; ++i) { - appendDescriptor(stringBuilder, parameters[i]); - } - return stringBuilder.append(")V").toString(); - } - - /** - * Returns the descriptor corresponding to the given method. - * - * @param method a {@link Method} object. - * @return the descriptor of the given method. - */ - public static String getMethodDescriptor(final Method method) { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append('('); - Class[] parameters = method.getParameterTypes(); - for (int i = 0; i < parameters.length; ++i) { - appendDescriptor(stringBuilder, parameters[i]); - } - stringBuilder.append(')'); - appendDescriptor(stringBuilder, method.getReturnType()); - return stringBuilder.toString(); - } - - /** - * Appends the descriptor of the given class to the given string builder. - * - * @param stringBuilder the string builder to which the descriptor must be appended. - * @param clazz the class whose descriptor must be computed. - */ - private static void appendDescriptor(final StringBuilder stringBuilder, final Class clazz) { - Class currentClass = clazz; - while (currentClass.isArray()) { - stringBuilder.append('['); - currentClass = currentClass.getComponentType(); - } - if (currentClass.isPrimitive()) { - char descriptor; - if (currentClass == Integer.TYPE) { - descriptor = 'I'; - } else if (currentClass == Void.TYPE) { - descriptor = 'V'; - } else if (currentClass == Boolean.TYPE) { - descriptor = 'Z'; - } else if (currentClass == Byte.TYPE) { - descriptor = 'B'; - } else if (currentClass == Character.TYPE) { - descriptor = 'C'; - } else if (currentClass == Short.TYPE) { - descriptor = 'S'; - } else if (currentClass == Double.TYPE) { - descriptor = 'D'; - } else if (currentClass == Float.TYPE) { - descriptor = 'F'; - } else if (currentClass == Long.TYPE) { - descriptor = 'J'; - } else { - throw new AssertionError(); - } - stringBuilder.append(descriptor); - } else { - stringBuilder.append('L'); - String name = currentClass.getName(); - int nameLength = name.length(); - for (int i = 0; i < nameLength; ++i) { - char car = name.charAt(i); - stringBuilder.append(car == '.' ? '/' : car); - } - stringBuilder.append(';'); - } - } - - // ----------------------------------------------------------------------------------------------- - // Corresponding size and opcodes - // ----------------------------------------------------------------------------------------------- - - /** - * Returns the size of values of this type. This method must not be used for method types. - * - * @return the size of values of this type, i.e., 2 for long and double, 0 for - * void and 1 otherwise. - */ - public int getSize() { - switch (sort) { - case VOID: - return 0; - case BOOLEAN: - case CHAR: - case BYTE: - case SHORT: - case INT: - case FLOAT: - case ARRAY: - case OBJECT: - case INTERNAL: - return 1; - case LONG: - case DOUBLE: - return 2; - default: - throw new AssertionError(); - } - } - - /** - * Returns a JVM instruction opcode adapted to this {@link Type}. This method must not be used for - * method types. - * - * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD, ISTORE, IALOAD, - * IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL, ISHR, IUSHR, IAND, IOR, IXOR and - * IRETURN. - * @return an opcode that is similar to the given opcode, but adapted to this {@link Type}. For - * example, if this type is float and opcode is IRETURN, this method returns - * FRETURN. - */ - public int getOpcode(final int opcode) { - if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { - switch (sort) { - case BOOLEAN: - case BYTE: - return opcode + (Opcodes.BALOAD - Opcodes.IALOAD); - case CHAR: - return opcode + (Opcodes.CALOAD - Opcodes.IALOAD); - case SHORT: - return opcode + (Opcodes.SALOAD - Opcodes.IALOAD); - case INT: - return opcode; - case FLOAT: - return opcode + (Opcodes.FALOAD - Opcodes.IALOAD); - case LONG: - return opcode + (Opcodes.LALOAD - Opcodes.IALOAD); - case DOUBLE: - return opcode + (Opcodes.DALOAD - Opcodes.IALOAD); - case ARRAY: - case OBJECT: - case INTERNAL: - return opcode + (Opcodes.AALOAD - Opcodes.IALOAD); - case METHOD: - case VOID: - throw new UnsupportedOperationException(); - default: - throw new AssertionError(); - } - } else { - switch (sort) { - case VOID: - if (opcode != Opcodes.IRETURN) { - throw new UnsupportedOperationException(); - } - return Opcodes.RETURN; - case BOOLEAN: - case BYTE: - case CHAR: - case SHORT: - case INT: - return opcode; - case FLOAT: - return opcode + (Opcodes.FRETURN - Opcodes.IRETURN); - case LONG: - return opcode + (Opcodes.LRETURN - Opcodes.IRETURN); - case DOUBLE: - return opcode + (Opcodes.DRETURN - Opcodes.IRETURN); - case ARRAY: - case OBJECT: - case INTERNAL: - if (opcode != Opcodes.ILOAD && opcode != Opcodes.ISTORE && opcode != Opcodes.IRETURN) { - throw new UnsupportedOperationException(); - } - return opcode + (Opcodes.ARETURN - Opcodes.IRETURN); - case METHOD: - throw new UnsupportedOperationException(); - default: - throw new AssertionError(); - } - } - } - - // ----------------------------------------------------------------------------------------------- - // Equals, hashCode and toString - // ----------------------------------------------------------------------------------------------- - - /** - * Tests if the given object is equal to this type. - * - * @param object the object to be compared to this type. - * @return true if the given object is equal to this type. - */ - @Override - public boolean equals(final Object object) { - if (this == object) { - return true; - } - if (!(object instanceof Type)) { - return false; - } - Type other = (Type) object; - if ((sort == INTERNAL ? OBJECT : sort) != (other.sort == INTERNAL ? OBJECT : other.sort)) { - return false; - } - int start = valueOffset; - int end = start + valueLength; - int otherStart = other.valueOffset; - int otherEnd = otherStart + other.valueLength; - // Compare the values. - if (end - start != otherEnd - otherStart) { - return false; - } - for (int i = start, j = otherStart; i < end; i++, j++) { - if (valueBuffer[i] != other.valueBuffer[j]) { - return false; - } - } - return true; - } - - /** - * Returns a hash code value for this type. - * - * @return a hash code value for this type. - */ - @Override - public int hashCode() { - int hashCode = 13 * (sort == INTERNAL ? OBJECT : sort); - if (sort >= ARRAY) { - for (int i = valueOffset, end = valueOffset + valueLength; i < end; i++) { - hashCode = 17 * (hashCode + valueBuffer[i]); - } - } - return hashCode; - } - - /** - * Returns a string representation of this type. - * - * @return the descriptor of this type. - */ - @Override - public String toString() { - return getDescriptor(); - } -} diff --git a/src/main/java/org/objectweb/asm/TypePath.java b/src/main/java/org/objectweb/asm/TypePath.java deleted file mode 100644 index 9d6e99fc..00000000 --- a/src/main/java/org/objectweb/asm/TypePath.java +++ /dev/null @@ -1,211 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. - -package org.objectweb.asm; - -/** - * The path to a type argument, wildcard bound, array element type, or static inner type within an - * enclosing type. - * - * @author Eric Bruneton - */ -public class TypePath { - - /** - * A type path step that steps into the element type of an array type. See {@link #getStep}. - */ - public static final int ARRAY_ELEMENT = 0; - - /** - * A type path step that steps into the nested type of a class type. See {@link #getStep}. - */ - public static final int INNER_TYPE = 1; - - /** - * A type path step that steps into the bound of a wildcard type. See {@link #getStep}. - */ - public static final int WILDCARD_BOUND = 2; - - /** - * A type path step that steps into a type argument of a generic type. See {@link #getStep}. - */ - public static final int TYPE_ARGUMENT = 3; - - /** - * The byte array where the 'type_path' structure - as defined in the Java Virtual Machine - * Specification (JVMS) - corresponding to this TypePath is stored. The first byte of the - * structure in this array is given by {@link #typePathOffset}. - * - * @see JVMS - * 4.7.20.2 - */ - private final byte[] typePathContainer; - - /** - * The offset of the first byte of the type_path JVMS structure in {@link #typePathContainer}. - */ - private final int typePathOffset; - - /** - * Constructs a new TypePath. - * - * @param typePathContainer a byte array containing a type_path JVMS structure. - * @param typePathOffset the offset of the first byte of the type_path structure in - * typePathContainer. - */ - TypePath(final byte[] typePathContainer, final int typePathOffset) { - this.typePathContainer = typePathContainer; - this.typePathOffset = typePathOffset; - } - - /** - * Returns the length of this path, i.e. its number of steps. - * - * @return the length of this path. - */ - public int getLength() { - // path_length is stored in the first byte of a type_path. - return typePathContainer[typePathOffset]; - } - - /** - * Returns the value of the given step of this path. - * - * @param index an index between 0 and {@link #getLength()}, exclusive. - * @return one of {@link #ARRAY_ELEMENT}, {@link #INNER_TYPE}, {@link #WILDCARD_BOUND}, or {@link - * #TYPE_ARGUMENT}. - */ - public int getStep(final int index) { - // Returns the type_path_kind of the path element of the given index. - return typePathContainer[typePathOffset + 2 * index + 1]; - } - - /** - * Returns the index of the type argument that the given step is stepping into. This method should - * only be used for steps whose value is {@link #TYPE_ARGUMENT}. - * - * @param index an index between 0 and {@link #getLength()}, exclusive. - * @return the index of the type argument that the given step is stepping into. - */ - public int getStepArgument(final int index) { - // Returns the type_argument_index of the path element of the given index. - return typePathContainer[typePathOffset + 2 * index + 2]; - } - - /** - * Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath - * object. - * - * @param typePath a type path in string form, in the format used by {@link #toString()}. May be - * null or empty. - * @return the corresponding TypePath object, or null if the path is empty. - */ - public static TypePath fromString(final String typePath) { - if (typePath == null || typePath.length() == 0) { - return null; - } - int typePathLength = typePath.length(); - ByteVector output = new ByteVector(typePathLength); - output.putByte(0); - int typePathIndex = 0; - while (typePathIndex < typePathLength) { - char c = typePath.charAt(typePathIndex++); - if (c == '[') { - output.put11(ARRAY_ELEMENT, 0); - } else if (c == '.') { - output.put11(INNER_TYPE, 0); - } else if (c == '*') { - output.put11(WILDCARD_BOUND, 0); - } else if (c >= '0' && c <= '9') { - int typeArg = c - '0'; - while (typePathIndex < typePathLength) { - c = typePath.charAt(typePathIndex++); - if (c >= '0' && c <= '9') { - typeArg = typeArg * 10 + c - '0'; - } else if (c == ';') { - break; - } else { - throw new IllegalArgumentException(); - } - } - output.put11(TYPE_ARGUMENT, typeArg); - } else { - throw new IllegalArgumentException(); - } - } - output.data[0] = (byte) (output.length / 2); - return new TypePath(output.data, 0); - } - - /** - * Returns a string representation of this type path. {@link #ARRAY_ELEMENT} steps are represented - * with '[', {@link #INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND} steps with '*' and {@link - * #TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'. - */ - @Override - public String toString() { - int length = getLength(); - StringBuilder result = new StringBuilder(length * 2); - for (int i = 0; i < length; ++i) { - switch (getStep(i)) { - case ARRAY_ELEMENT: - result.append('['); - break; - case INNER_TYPE: - result.append('.'); - break; - case WILDCARD_BOUND: - result.append('*'); - break; - case TYPE_ARGUMENT: - result.append(getStepArgument(i)).append(';'); - break; - default: - throw new AssertionError(); - } - } - return result.toString(); - } - - /** - * Puts the type_path JVMS structure corresponding to the given TypePath into the given - * ByteVector. - * - * @param typePath a TypePath instance, or null for empty paths. - * @param output where the type path must be put. - */ - static void put(final TypePath typePath, final ByteVector output) { - if (typePath == null) { - output.putByte(0); - } else { - int length = typePath.typePathContainer[typePath.typePathOffset] * 2 + 1; - output.putByteArray(typePath.typePathContainer, typePath.typePathOffset, length); - } - } -} diff --git a/src/main/java/org/objectweb/asm/TypeReference.java b/src/main/java/org/objectweb/asm/TypeReference.java deleted file mode 100644 index 3a11d380..00000000 --- a/src/main/java/org/objectweb/asm/TypeReference.java +++ /dev/null @@ -1,440 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. - -package org.objectweb.asm; - -/** - * A reference to a type appearing in a class, field or method declaration, or on an instruction. - * Such a reference designates the part of the class where the referenced type is appearing (e.g. an - * 'extends', 'implements' or 'throws' clause, a 'new' instruction, a 'catch' clause, a type cast, a - * local variable declaration, etc). - * - * @author Eric Bruneton - */ -public class TypeReference { - - /** - * The sort of type references that target a type parameter of a generic class. See {@link - * #getSort}. - */ - public static final int CLASS_TYPE_PARAMETER = 0x00; - - /** - * The sort of type references that target a type parameter of a generic method. See {@link - * #getSort}. - */ - public static final int METHOD_TYPE_PARAMETER = 0x01; - - /** - * The sort of type references that target the super class of a class or one of the interfaces it - * implements. See {@link #getSort}. - */ - public static final int CLASS_EXTENDS = 0x10; - - /** - * The sort of type references that target a bound of a type parameter of a generic class. See - * {@link #getSort}. - */ - public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11; - - /** - * The sort of type references that target a bound of a type parameter of a generic method. See - * {@link #getSort}. - */ - public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12; - - /** - * The sort of type references that target the type of a field. See {@link #getSort}. - */ - public static final int FIELD = 0x13; - - /** - * The sort of type references that target the return type of a method. See {@link #getSort}. - */ - public static final int METHOD_RETURN = 0x14; - - /** - * The sort of type references that target the receiver type of a method. See {@link #getSort}. - */ - public static final int METHOD_RECEIVER = 0x15; - - /** - * The sort of type references that target the type of a formal parameter of a method. See {@link - * #getSort}. - */ - public static final int METHOD_FORMAL_PARAMETER = 0x16; - - /** - * The sort of type references that target the type of an exception declared in the throws clause - * of a method. See {@link #getSort}. - */ - public static final int THROWS = 0x17; - - /** - * The sort of type references that target the type of a local variable in a method. See {@link - * #getSort}. - */ - public static final int LOCAL_VARIABLE = 0x40; - - /** - * The sort of type references that target the type of a resource variable in a method. See {@link - * #getSort}. - */ - public static final int RESOURCE_VARIABLE = 0x41; - - /** - * The sort of type references that target the type of the exception of a 'catch' clause in a - * method. See {@link #getSort}. - */ - public static final int EXCEPTION_PARAMETER = 0x42; - - /** - * The sort of type references that target the type declared in an 'instanceof' instruction. See - * {@link #getSort}. - */ - public static final int INSTANCEOF = 0x43; - - /** - * The sort of type references that target the type of the object created by a 'new' instruction. - * See {@link #getSort}. - */ - public static final int NEW = 0x44; - - /** - * The sort of type references that target the receiver type of a constructor reference. See - * {@link #getSort}. - */ - public static final int CONSTRUCTOR_REFERENCE = 0x45; - - /** - * The sort of type references that target the receiver type of a method reference. See {@link - * #getSort}. - */ - public static final int METHOD_REFERENCE = 0x46; - - /** - * The sort of type references that target the type declared in an explicit or implicit cast - * instruction. See {@link #getSort}. - */ - public static final int CAST = 0x47; - - /** - * The sort of type references that target a type parameter of a generic constructor in a - * constructor call. See {@link #getSort}. - */ - public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; - - /** - * The sort of type references that target a type parameter of a generic method in a method call. - * See {@link #getSort}. - */ - public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; - - /** - * The sort of type references that target a type parameter of a generic constructor in a - * constructor reference. See {@link #getSort}. - */ - public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; - - /** - * The sort of type references that target a type parameter of a generic method in a method - * reference. See {@link #getSort}. - */ - public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; - - /** - * The target_type and target_info structures - as defined in the Java Virtual Machine - * Specification (JVMS) - corresponding to this type reference. target_type uses one byte, and all - * the target_info union fields use up to 3 bytes (except localvar_target, handled with the - * specific method {@link MethodVisitor#visitLocalVariableAnnotation}). Thus, both structures can - * be stored in an int. - * - *

This int field stores target_type (called the TypeReference 'sort' in the public API of this - * class) in its most significant byte, followed by the target_info fields. Depending on - * target_type, 1, 2 or even 3 least significant bytes of this field are unused. target_info - * fields which reference bytecode offsets are set to 0 (these offsets are ignored in ClassReader, - * and recomputed in MethodWriter). - * - * @see JVMS - * 4.7.20 - * @see JVMS - * 4.7.20.1 - */ - private final int targetTypeAndInfo; - - /** - * Constructs a new TypeReference. - * - * @param typeRef the int encoded value of the type reference, as received in a visit method - * related to type annotations, such as {@link ClassVisitor#visitTypeAnnotation}. - */ - public TypeReference(final int typeRef) { - this.targetTypeAndInfo = typeRef; - } - - /** - * Returns a type reference of the given sort. - * - * @param sort one of {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link - * #LOCAL_VARIABLE}, {@link #RESOURCE_VARIABLE}, {@link #INSTANCEOF}, {@link #NEW}, {@link - * #CONSTRUCTOR_REFERENCE}, or {@link #METHOD_REFERENCE}. - * @return a type reference of the given sort. - */ - public static TypeReference newTypeReference(final int sort) { - return new TypeReference(sort << 24); - } - - /** - * Returns a reference to a type parameter of a generic class or method. - * - * @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}. - * @param paramIndex the type parameter index. - * @return a reference to the given generic class or method type parameter. - */ - public static TypeReference newTypeParameterReference(final int sort, final int paramIndex) { - return new TypeReference((sort << 24) | (paramIndex << 16)); - } - - /** - * Returns a reference to a type parameter bound of a generic class or method. - * - * @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}. - * @param paramIndex the type parameter index. - * @param boundIndex the type bound index within the above type parameters. - * @return a reference to the given generic class or method type parameter bound. - */ - public static TypeReference newTypeParameterBoundReference( - final int sort, final int paramIndex, final int boundIndex) { - return new TypeReference((sort << 24) | (paramIndex << 16) | (boundIndex << 8)); - } - - /** - * Returns a reference to the super class or to an interface of the 'implements' clause of a - * class. - * - * @param itfIndex the index of an interface in the 'implements' clause of a class, or -1 to - * reference the super class of the class. - * @return a reference to the given super type of a class. - */ - public static TypeReference newSuperTypeReference(final int itfIndex) { - return new TypeReference((CLASS_EXTENDS << 24) | ((itfIndex & 0xFFFF) << 8)); - } - - /** - * Returns a reference to the type of a formal parameter of a method. - * - * @param paramIndex the formal parameter index. - * @return a reference to the type of the given method formal parameter. - */ - public static TypeReference newFormalParameterReference(final int paramIndex) { - return new TypeReference((METHOD_FORMAL_PARAMETER << 24) | (paramIndex << 16)); - } - - /** - * Returns a reference to the type of an exception, in a 'throws' clause of a method. - * - * @param exceptionIndex the index of an exception in a 'throws' clause of a method. - * @return a reference to the type of the given exception. - */ - public static TypeReference newExceptionReference(final int exceptionIndex) { - return new TypeReference((THROWS << 24) | (exceptionIndex << 8)); - } - - /** - * Returns a reference to the type of the exception declared in a 'catch' clause of a method. - * - * @param tryCatchBlockIndex the index of a try catch block (using the order in which they are - * visited with visitTryCatchBlock). - * @return a reference to the type of the given exception. - */ - public static TypeReference newTryCatchReference(final int tryCatchBlockIndex) { - return new TypeReference((EXCEPTION_PARAMETER << 24) | (tryCatchBlockIndex << 8)); - } - - /** - * Returns a reference to the type of a type argument in a constructor or method call or - * reference. - * - * @param sort one of {@link #CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link - * #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link - * #METHOD_REFERENCE_TYPE_ARGUMENT}. - * @param argIndex the type argument index. - * @return a reference to the type of the given type argument. - */ - public static TypeReference newTypeArgumentReference(final int sort, final int argIndex) { - return new TypeReference((sort << 24) | argIndex); - } - - /** - * Returns the sort of this type reference. - * - * @return one of {@link #CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER}, {@link - * #CLASS_EXTENDS}, {@link #CLASS_TYPE_PARAMETER_BOUND}, {@link #METHOD_TYPE_PARAMETER_BOUND}, - * {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link - * #METHOD_FORMAL_PARAMETER}, {@link #THROWS}, {@link #LOCAL_VARIABLE}, {@link - * #RESOURCE_VARIABLE}, {@link #EXCEPTION_PARAMETER}, {@link #INSTANCEOF}, {@link #NEW}, - * {@link #CONSTRUCTOR_REFERENCE}, {@link #METHOD_REFERENCE}, {@link #CAST}, {@link - * #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link - * #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}. - */ - public int getSort() { - return targetTypeAndInfo >>> 24; - } - - /** - * Returns the index of the type parameter referenced by this type reference. This method must - * only be used for type references whose sort is {@link #CLASS_TYPE_PARAMETER}, {@link - * #METHOD_TYPE_PARAMETER}, {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link - * #METHOD_TYPE_PARAMETER_BOUND}. - * - * @return a type parameter index. - */ - public int getTypeParameterIndex() { - return (targetTypeAndInfo & 0x00FF0000) >> 16; - } - - /** - * Returns the index of the type parameter bound, within the type parameter {@link - * #getTypeParameterIndex}, referenced by this type reference. This method must only be used for - * type references whose sort is {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link - * #METHOD_TYPE_PARAMETER_BOUND}. - * - * @return a type parameter bound index. - */ - public int getTypeParameterBoundIndex() { - return (targetTypeAndInfo & 0x0000FF00) >> 8; - } - - /** - * Returns the index of the "super type" of a class that is referenced by this type reference. - * This method must only be used for type references whose sort is {@link #CLASS_EXTENDS}. - * - * @return the index of an interface in the 'implements' clause of a class, or -1 if this type - * reference references the type of the super class. - */ - public int getSuperTypeIndex() { - return (short) ((targetTypeAndInfo & 0x00FFFF00) >> 8); - } - - /** - * Returns the index of the formal parameter whose type is referenced by this type reference. This - * method must only be used for type references whose sort is {@link #METHOD_FORMAL_PARAMETER}. - * - * @return a formal parameter index. - */ - public int getFormalParameterIndex() { - return (targetTypeAndInfo & 0x00FF0000) >> 16; - } - - /** - * Returns the index of the exception, in a 'throws' clause of a method, whose type is referenced - * by this type reference. This method must only be used for type references whose sort is {@link - * #THROWS}. - * - * @return the index of an exception in the 'throws' clause of a method. - */ - public int getExceptionIndex() { - return (targetTypeAndInfo & 0x00FFFF00) >> 8; - } - - /** - * Returns the index of the try catch block (using the order in which they are visited with - * visitTryCatchBlock), whose 'catch' type is referenced by this type reference. This method must - * only be used for type references whose sort is {@link #EXCEPTION_PARAMETER} . - * - * @return the index of an exception in the 'throws' clause of a method. - */ - public int getTryCatchBlockIndex() { - return (targetTypeAndInfo & 0x00FFFF00) >> 8; - } - - /** - * Returns the index of the type argument referenced by this type reference. This method must only - * be used for type references whose sort is {@link #CAST}, {@link - * #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link - * #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}. - * - * @return a type parameter index. - */ - public int getTypeArgumentIndex() { - return targetTypeAndInfo & 0xFF; - } - - /** - * Returns the int encoded value of this type reference, suitable for use in visit methods related - * to type annotations, like visitTypeAnnotation. - * - * @return the int encoded value of this type reference. - */ - public int getValue() { - return targetTypeAndInfo; - } - - /** - * Puts the given target_type and target_info JVMS structures into the given ByteVector. - * - * @param targetTypeAndInfo a target_type and a target_info structures encoded as in {@link - * #targetTypeAndInfo}. LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported. - * @param output where the type reference must be put. - */ - static void putTarget(final int targetTypeAndInfo, final ByteVector output) { - switch (targetTypeAndInfo >>> 24) { - case CLASS_TYPE_PARAMETER: - case METHOD_TYPE_PARAMETER: - case METHOD_FORMAL_PARAMETER: - output.putShort(targetTypeAndInfo >>> 16); - break; - case FIELD: - case METHOD_RETURN: - case METHOD_RECEIVER: - output.putByte(targetTypeAndInfo >>> 24); - break; - case CAST: - case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: - case METHOD_INVOCATION_TYPE_ARGUMENT: - case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: - case METHOD_REFERENCE_TYPE_ARGUMENT: - output.putInt(targetTypeAndInfo); - break; - case CLASS_EXTENDS: - case CLASS_TYPE_PARAMETER_BOUND: - case METHOD_TYPE_PARAMETER_BOUND: - case THROWS: - case EXCEPTION_PARAMETER: - case INSTANCEOF: - case NEW: - case CONSTRUCTOR_REFERENCE: - case METHOD_REFERENCE: - output.put12(targetTypeAndInfo >>> 24, (targetTypeAndInfo & 0xFFFF00) >> 8); - break; - default: - throw new IllegalArgumentException(); - } - } -} diff --git a/src/main/java/org/objectweb/asm/commons/AdviceAdapter.java b/src/main/java/org/objectweb/asm/commons/AdviceAdapter.java deleted file mode 100644 index aa1b1023..00000000 --- a/src/main/java/org/objectweb/asm/commons/AdviceAdapter.java +++ /dev/null @@ -1,633 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm.commons; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.objectweb.asm.Handle; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; - -/** - * A {@link org.objectweb.asm.MethodVisitor} to insert before, after and around advices in methods - * and constructors. - * - *

The behavior for constructors is like this: - * - *

    - *
  1. as long as the INVOKESPECIAL for the object initialization has not been reached, every - * bytecode instruction is dispatched in the ctor code visitor - *
  2. when this one is reached, it is only added in the ctor code visitor and a JP invoke is - * added - *
  3. after that, only the other code visitor receives the instructions - *
- * - * @author Eugene Kuleshov - * @author Eric Bruneton - */ -public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes { - - private static final Object THIS = new Object(); - - private static final Object OTHER = new Object(); - - protected int methodAccess; - - protected String methodDesc; - - private boolean constructor; - - private boolean superInitialized; - - private List stackFrame; - - private Map> branches; - - /** - * Constructs a new {@link AdviceAdapter}. - * - * @param api the ASM API version implemented by this visitor. Must be one of {@link - * Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. - * @param mv the method visitor to which this adapter delegates calls. - * @param access the method's access flags (see {@link Opcodes}). - * @param name the method's name. - * @param desc the method's descriptor (see {@link Type Type}). - */ - protected AdviceAdapter( - final int api, - final MethodVisitor mv, - final int access, - final String name, - final String desc) { - super(api, mv, access, name, desc); - methodAccess = access; - methodDesc = desc; - constructor = "".equals(name); - } - - @Override - public void visitCode() { - super.visitCode(); - if (constructor) { - stackFrame = new ArrayList(); - branches = new HashMap>(); - } else { - superInitialized = true; - onMethodEnter(); - } - } - - @Override - public void visitLabel(final Label label) { - super.visitLabel(label); - if (constructor && branches != null) { - List frame = branches.get(label); - if (frame != null) { - stackFrame = frame; - branches.remove(label); - } - } - } - - @Override - public void visitInsn(final int opcode) { - if (constructor) { - int s; - switch (opcode) { - case RETURN: // empty stack - onMethodExit(opcode); - break; - case IRETURN: // 1 before n/a after - case FRETURN: // 1 before n/a after - case ARETURN: // 1 before n/a after - case ATHROW: // 1 before n/a after - popValue(); - onMethodExit(opcode); - break; - case LRETURN: // 2 before n/a after - case DRETURN: // 2 before n/a after - popValue(); - popValue(); - onMethodExit(opcode); - break; - case NOP: - case LALOAD: // remove 2 add 2 - case DALOAD: // remove 2 add 2 - case LNEG: - case DNEG: - case FNEG: - case INEG: - case L2D: - case D2L: - case F2I: - case I2B: - case I2C: - case I2S: - case I2F: - case ARRAYLENGTH: - break; - case ACONST_NULL: - case ICONST_M1: - case ICONST_0: - case ICONST_1: - case ICONST_2: - case ICONST_3: - case ICONST_4: - case ICONST_5: - case FCONST_0: - case FCONST_1: - case FCONST_2: - case F2L: // 1 before 2 after - case F2D: - case I2L: - case I2D: - pushValue(OTHER); - break; - case LCONST_0: - case LCONST_1: - case DCONST_0: - case DCONST_1: - pushValue(OTHER); - pushValue(OTHER); - break; - case IALOAD: // remove 2 add 1 - case FALOAD: // remove 2 add 1 - case AALOAD: // remove 2 add 1 - case BALOAD: // remove 2 add 1 - case CALOAD: // remove 2 add 1 - case SALOAD: // remove 2 add 1 - case POP: - case IADD: - case FADD: - case ISUB: - case LSHL: // 3 before 2 after - case LSHR: // 3 before 2 after - case LUSHR: // 3 before 2 after - case L2I: // 2 before 1 after - case L2F: // 2 before 1 after - case D2I: // 2 before 1 after - case D2F: // 2 before 1 after - case FSUB: - case FMUL: - case FDIV: - case FREM: - case FCMPL: // 2 before 1 after - case FCMPG: // 2 before 1 after - case IMUL: - case IDIV: - case IREM: - case ISHL: - case ISHR: - case IUSHR: - case IAND: - case IOR: - case IXOR: - case MONITORENTER: - case MONITOREXIT: - popValue(); - break; - case POP2: - case LSUB: - case LMUL: - case LDIV: - case LREM: - case LADD: - case LAND: - case LOR: - case LXOR: - case DADD: - case DMUL: - case DSUB: - case DDIV: - case DREM: - popValue(); - popValue(); - break; - case IASTORE: - case FASTORE: - case AASTORE: - case BASTORE: - case CASTORE: - case SASTORE: - case LCMP: // 4 before 1 after - case DCMPL: - case DCMPG: - popValue(); - popValue(); - popValue(); - break; - case LASTORE: - case DASTORE: - popValue(); - popValue(); - popValue(); - popValue(); - break; - case DUP: - pushValue(peekValue()); - break; - case DUP_X1: - s = stackFrame.size(); - stackFrame.add(s - 2, stackFrame.get(s - 1)); - break; - case DUP_X2: - s = stackFrame.size(); - stackFrame.add(s - 3, stackFrame.get(s - 1)); - break; - case DUP2: - s = stackFrame.size(); - stackFrame.add(s - 2, stackFrame.get(s - 1)); - stackFrame.add(s - 2, stackFrame.get(s - 1)); - break; - case DUP2_X1: - s = stackFrame.size(); - stackFrame.add(s - 3, stackFrame.get(s - 1)); - stackFrame.add(s - 3, stackFrame.get(s - 1)); - break; - case DUP2_X2: - s = stackFrame.size(); - stackFrame.add(s - 4, stackFrame.get(s - 1)); - stackFrame.add(s - 4, stackFrame.get(s - 1)); - break; - case SWAP: - s = stackFrame.size(); - stackFrame.add(s - 2, stackFrame.get(s - 1)); - stackFrame.remove(s); - break; - } - } else { - switch (opcode) { - case RETURN: - case IRETURN: - case FRETURN: - case ARETURN: - case LRETURN: - case DRETURN: - case ATHROW: - onMethodExit(opcode); - break; - } - } - super.visitInsn(opcode); - } - - @Override - public void visitVarInsn(final int opcode, final int var) { - super.visitVarInsn(opcode, var); - if (constructor) { - switch (opcode) { - case ILOAD: - case FLOAD: - pushValue(OTHER); - break; - case LLOAD: - case DLOAD: - pushValue(OTHER); - pushValue(OTHER); - break; - case ALOAD: - pushValue(var == 0 ? THIS : OTHER); - break; - case ASTORE: - case ISTORE: - case FSTORE: - popValue(); - break; - case LSTORE: - case DSTORE: - popValue(); - popValue(); - break; - } - } - } - - @Override - public void visitFieldInsn( - final int opcode, final String owner, final String name, final String desc) { - super.visitFieldInsn(opcode, owner, name, desc); - if (constructor) { - char c = desc.charAt(0); - boolean longOrDouble = c == 'J' || c == 'D'; - switch (opcode) { - case GETSTATIC: - pushValue(OTHER); - if (longOrDouble) { - pushValue(OTHER); - } - break; - case PUTSTATIC: - popValue(); - if (longOrDouble) { - popValue(); - } - break; - case PUTFIELD: - popValue(); - popValue(); - if (longOrDouble) { - popValue(); - } - break; - // case GETFIELD: - default: - if (longOrDouble) { - pushValue(OTHER); - } - } - } - } - - @Override - public void visitIntInsn(final int opcode, final int operand) { - super.visitIntInsn(opcode, operand); - if (constructor && opcode != NEWARRAY) { - pushValue(OTHER); - } - } - - @Override - public void visitLdcInsn(final Object cst) { - super.visitLdcInsn(cst); - if (constructor) { - pushValue(OTHER); - if (cst instanceof Double || cst instanceof Long) { - pushValue(OTHER); - } - } - } - - @Override - public void visitMultiANewArrayInsn(final String desc, final int dims) { - super.visitMultiANewArrayInsn(desc, dims); - if (constructor) { - for (int i = 0; i < dims; i++) { - popValue(); - } - pushValue(OTHER); - } - } - - @Override - public void visitTypeInsn(final int opcode, final String type) { - super.visitTypeInsn(opcode, type); - // ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack - if (constructor && opcode == NEW) { - pushValue(OTHER); - } - } - - @Deprecated - @Override - public void visitMethodInsn( - final int opcode, final String owner, final String name, final String desc) { - if (api >= Opcodes.ASM5) { - super.visitMethodInsn(opcode, owner, name, desc); - return; - } - doVisitMethodInsn(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE); - } - - @Override - public void visitMethodInsn( - final int opcode, - final String owner, - final String name, - final String desc, - final boolean itf) { - if (api < Opcodes.ASM5) { - super.visitMethodInsn(opcode, owner, name, desc, itf); - return; - } - doVisitMethodInsn(opcode, owner, name, desc, itf); - } - - private void doVisitMethodInsn( - int opcode, final String owner, final String name, final String desc, final boolean itf) { - mv.visitMethodInsn(opcode, owner, name, desc, itf); - if (constructor) { - Type[] types = Type.getArgumentTypes(desc); - for (int i = 0; i < types.length; i++) { - popValue(); - if (types[i].getSize() == 2) { - popValue(); - } - } - switch (opcode) { - // case INVOKESTATIC: - // break; - case INVOKEINTERFACE: - case INVOKEVIRTUAL: - popValue(); // objectref - break; - case INVOKESPECIAL: - Object type = popValue(); // objectref - if (type == THIS && !superInitialized) { - onMethodEnter(); - superInitialized = true; - // once super has been initialized it is no longer - // necessary to keep track of stack state - constructor = false; - } - break; - } - - Type returnType = Type.getReturnType(desc); - if (returnType != Type.VOID_TYPE) { - pushValue(OTHER); - if (returnType.getSize() == 2) { - pushValue(OTHER); - } - } - } - } - - @Override - public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { - super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); - if (constructor) { - Type[] types = Type.getArgumentTypes(desc); - for (int i = 0; i < types.length; i++) { - popValue(); - if (types[i].getSize() == 2) { - popValue(); - } - } - - Type returnType = Type.getReturnType(desc); - if (returnType != Type.VOID_TYPE) { - pushValue(OTHER); - if (returnType.getSize() == 2) { - pushValue(OTHER); - } - } - } - } - - @Override - public void visitJumpInsn(final int opcode, final Label label) { - super.visitJumpInsn(opcode, label); - if (constructor) { - switch (opcode) { - case IFEQ: - case IFNE: - case IFLT: - case IFGE: - case IFGT: - case IFLE: - case IFNULL: - case IFNONNULL: - popValue(); - break; - case IF_ICMPEQ: - case IF_ICMPNE: - case IF_ICMPLT: - case IF_ICMPGE: - case IF_ICMPGT: - case IF_ICMPLE: - case IF_ACMPEQ: - case IF_ACMPNE: - popValue(); - popValue(); - break; - case JSR: - pushValue(OTHER); - break; - } - addBranch(label); - } - } - - @Override - public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { - super.visitLookupSwitchInsn(dflt, keys, labels); - if (constructor) { - popValue(); - addBranches(dflt, labels); - } - } - - @Override - public void visitTableSwitchInsn( - final int min, final int max, final Label dflt, final Label... labels) { - super.visitTableSwitchInsn(min, max, dflt, labels); - if (constructor) { - popValue(); - addBranches(dflt, labels); - } - } - - @Override - public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { - super.visitTryCatchBlock(start, end, handler, type); - if (constructor && !branches.containsKey(handler)) { - List stackFrame = new ArrayList(); - stackFrame.add(OTHER); - branches.put(handler, stackFrame); - } - } - - private void addBranches(final Label dflt, final Label[] labels) { - addBranch(dflt); - for (int i = 0; i < labels.length; i++) { - addBranch(labels[i]); - } - } - - private void addBranch(final Label label) { - if (branches.containsKey(label)) { - return; - } - branches.put(label, new ArrayList(stackFrame)); - } - - private Object popValue() { - return stackFrame.remove(stackFrame.size() - 1); - } - - private Object peekValue() { - return stackFrame.get(stackFrame.size() - 1); - } - - private void pushValue(final Object o) { - stackFrame.add(o); - } - - /** - * Called at the beginning of the method or after super class call in the constructor.
- *
- * Custom code can use or change all the local variables, but should not change state of the - * stack. - */ - protected void onMethodEnter() { - } - - /** - * Called before explicit exit from the method using either return or throw. Top element on the - * stack contains the return value or exception instance. For example: - * - *
-     *   public void onMethodExit(int opcode) {
-     *     if(opcode==RETURN) {
-     *         visitInsn(ACONST_NULL);
-     *     } else if(opcode==ARETURN || opcode==ATHROW) {
-     *         dup();
-     *     } else {
-     *         if(opcode==LRETURN || opcode==DRETURN) {
-     *             dup2();
-     *         } else {
-     *             dup();
-     *         }
-     *         box(Type.getReturnType(this.methodDesc));
-     *     }
-     *     visitIntInsn(SIPUSH, opcode);
-     *     visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
-     *   }
-     *
-     *   // an actual call back method
-     *   public static void onExit(Object param, int opcode) {
-     *     ...
-     * 
- * - *
- *
- * Custom code can use or change all the local variables, but should not change state of the - * stack. - * - * @param opcode one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, DRETURN or ATHROW - */ - protected void onMethodExit(int opcode) { - } - - // TODO onException, onMethodCall -} diff --git a/src/main/java/org/objectweb/asm/commons/AnalyzerAdapter.java b/src/main/java/org/objectweb/asm/commons/AnalyzerAdapter.java deleted file mode 100644 index 48b8807e..00000000 --- a/src/main/java/org/objectweb/asm/commons/AnalyzerAdapter.java +++ /dev/null @@ -1,920 +0,0 @@ -// ASM: a very small and fast Java bytecode manipulation framework -// Copyright (c) 2000-2011 INRIA, France Telecom -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holders nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -package org.objectweb.asm.commons; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.objectweb.asm.Handle; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; - -/** - * A {@link MethodVisitor} that keeps track of stack map frame changes between {@link - * #visitFrame(int, int, Object[], int, Object[]) visitFrame} calls. This adapter must be used with - * the {@link org.objectweb.asm.ClassReader#EXPAND_FRAMES} option. Each visitX instruction - * delegates to the next visitor in the chain, if any, and then simulates the effect of this - * instruction on the stack map frame, represented by {@link #locals} and {@link #stack}. The next - * visitor in the chain can get the state of the stack map frame before each instruction by - * reading the value of these fields in its visitX methods (this requires a reference to the - * AnalyzerAdapter that is before it in the chain). If this adapter is used with a class that does - * not contain stack map table attributes (i.e., pre Java 6 classes) then this adapter may not be - * able to compute the stack map frame for each instruction. In this case no exception is thrown but - * the {@link #locals} and {@link #stack} fields will be null for these instructions. - * - * @author Eric Bruneton - */ -public class AnalyzerAdapter extends MethodVisitor { - - /** - * List of the local variable slots for current execution frame. Primitive types are - * represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link - * Opcodes#LONG}, {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link - * Opcodes#UNINITIALIZED_THIS} (long and double are represented by two elements, the second one - * being TOP). Reference types are represented by String objects (representing internal names), - * and uninitialized types by Label objects (this label designates the NEW instruction that - * created this uninitialized value). This field is null for unreachable instructions. - */ - public List locals; - - /** - * List of the operand stack slots for current execution frame. Primitive types are - * represented by {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link - * Opcodes#LONG}, {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or {@link - * Opcodes#UNINITIALIZED_THIS} (long and double are represented by two elements, the second one - * being TOP). Reference types are represented by String objects (representing internal names), - * and uninitialized types by Label objects (this label designates the NEW instruction that - * created this uninitialized value). This field is null for unreachable instructions. - */ - public List stack; - - /** - * The labels that designate the next instruction to be visited. May be null. - */ - private List