├── LICENSE
├── README.md
├── pom.xml
└── src
└── main
└── java
└── me
└── ANONIMUS
└── deobf
├── Deobfuscator.java
├── DeobfuscatorInitializer.java
├── transformer
├── Transformer.java
└── impl
│ ├── AnnotationRemoverTransformer.java
│ ├── DebugInfoRemoverTransformer.java
│ ├── FixAccessTransformer.java
│ ├── IllegalSignatureRemoverTransformer.java
│ ├── IllegalVarargsRemoverTransformer.java
│ ├── InvalidTryCatchRemoverTransformer.java
│ ├── LocalVariableRemoverTransformer.java
│ ├── UnknownAttributeRemoverTransformer.java
│ ├── WatermarkTransformer.java
│ ├── name
│ ├── ClassNameTransformer.java
│ ├── FieldNameTransformer.java
│ └── MethodNameTransformer.java
│ ├── optimization
│ ├── GotoInlinerTransformer.java
│ └── NopRemoverTransformer.java
│ ├── shrinking
│ ├── InnerClassTransformer.java
│ ├── LineNumberRemoverTransformer.java
│ ├── SignatureRemoverTransformer.java
│ ├── SourceDebugRemoverTransformer.java
│ └── SourceFileRemoverTransformer.java
│ └── string
│ ├── AllatoriStringTransformer.java
│ ├── AlpheratzTeamStringTransformer.java
│ ├── DashoStringTransformer.java
│ ├── SuperBlaubeere27StringTransformer.java
│ └── qProtectStringTransformer.java
└── util
└── BytecodeUtils.java
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Ikos3k
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Java Deobfuscator
2 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | JavaDeobfuscator
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | org.apache.maven.plugins
14 | maven-compiler-plugin
15 |
16 | 8
17 | 8
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | org.projectlombok
26 | lombok
27 | 1.18.16
28 | provided
29 |
30 |
31 | org.ow2.asm
32 | asm
33 | 7.1
34 |
35 |
36 | org.ow2.asm
37 | asm-analysis
38 | 7.1
39 |
40 |
41 | org.ow2.asm
42 | asm-commons
43 | 7.1
44 |
45 |
46 | org.ow2.asm
47 | asm-tree
48 | 7.1
49 |
50 |
51 | org.ow2.asm
52 | asm-util
53 | 7.1
54 |
55 |
56 | commons-io
57 | commons-io
58 | 2.6
59 |
60 |
61 | org.apache.commons
62 | commons-lang3
63 | 3.11
64 |
65 |
66 |
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/Deobfuscator.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf;
2 |
3 | import lombok.Getter;
4 | import me.ANONIMUS.deobf.transformer.Transformer;
5 | import me.ANONIMUS.deobf.transformer.impl.WatermarkTransformer;
6 | import me.ANONIMUS.deobf.util.BytecodeUtils;
7 | import org.apache.commons.io.IOUtils;
8 | import org.objectweb.asm.ClassReader;
9 | import org.objectweb.asm.tree.ClassNode;
10 | import org.objectweb.asm.tree.analysis.AnalyzerException;
11 |
12 | import java.io.File;
13 | import java.io.FileOutputStream;
14 | import java.io.IOException;
15 | import java.io.InputStream;
16 | import java.util.*;
17 | import java.util.jar.JarEntry;
18 | import java.util.jar.JarFile;
19 | import java.util.jar.JarOutputStream;
20 |
21 | @Getter
22 | public class Deobfuscator {
23 | private static Deobfuscator instance;
24 |
25 | private final List transformers;
26 | private final Map files;
27 | private final List classes;
28 |
29 | public Deobfuscator() {
30 | instance = this;
31 |
32 | this.files = new HashMap<>();
33 | this.classes = new ArrayList<>();
34 | this.transformers = new ArrayList<>();
35 | }
36 |
37 | public void run(String[] args) {
38 | if (args.length == 0) {
39 | System.err.println("[ERROR] Input file must be specified");
40 | return;
41 | }
42 |
43 | String input = args[0];
44 | if (!input.endsWith(".jar")) {
45 | input += ".jar";
46 | }
47 |
48 | File in = new File(input);
49 | if (!in.exists()) {
50 | System.err.println("[ERROR] Input file not found");
51 | return;
52 | }
53 |
54 | File out = new File(input.substring(0, input.length() - ".jar".length()) + "Deobf.jar");
55 | if (out.exists() && !out.delete()) {
56 | System.err.println("[ERROR] Could not delete out file");
57 | return;
58 | }
59 |
60 | loadJar(in);
61 | System.out.println("[INFO] Successful loaded " + in.getName() + " [" + classes.size() + " class] [" + files.size() + " files]");
62 |
63 | transformers.add(new WatermarkTransformer());
64 |
65 | System.out.println();
66 | transformers.forEach(transformer -> {
67 | System.out.println(transformer.getClass().getSimpleName() + " running...");
68 | try {
69 | transformer.visit(classes);
70 | } catch (AnalyzerException e) {
71 | System.err.println("[ERROR] An error has occurred in " + transformer.getClass().getSimpleName());
72 | e.printStackTrace();
73 | }
74 | });
75 |
76 | System.out.println();
77 | System.out.println("[INFO] Finished, saving the file...");
78 | saveJar(out);
79 | }
80 |
81 | private void loadJar(File file) {
82 | try (JarFile jarFile = new JarFile(file)) {
83 | final Enumeration entries = jarFile.entries();
84 | while (entries.hasMoreElements()) {
85 | final JarEntry jarEntry = entries.nextElement();
86 | try (InputStream inputStream = jarFile.getInputStream(jarEntry)) {
87 | final byte[] bytes = IOUtils.toByteArray(inputStream);
88 | if (!jarEntry.getName().endsWith(".class")) {
89 | files.put(jarEntry.getName(), bytes);
90 | continue;
91 | }
92 |
93 | try {
94 | if (BytecodeUtils.checkClassVerify(bytes)) {
95 | final ClassNode classNode = new ClassNode();
96 | new ClassReader(bytes).accept(classNode, ClassReader.EXPAND_FRAMES);
97 | this.classes.add(classNode);
98 | }
99 | } catch (Exception e) {
100 | System.err.println("[ERROR] There was an error loading " + jarEntry.getName());
101 | }
102 | }
103 | }
104 | } catch (IOException ex) {
105 | ex.printStackTrace();
106 | }
107 | }
108 |
109 | private void saveJar(File out) {
110 | try (JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(out))) {
111 | for (ClassNode classNode : this.classes) {
112 | jarOutputStream.putNextEntry(new JarEntry(classNode.name + ".class"));
113 | jarOutputStream.write(BytecodeUtils.toByteArray(classNode));
114 | jarOutputStream.closeEntry();
115 | }
116 |
117 | for (Map.Entry entry : this.files.entrySet()) {
118 | jarOutputStream.putNextEntry(new JarEntry(entry.getKey()));
119 | jarOutputStream.write(entry.getValue());
120 | jarOutputStream.closeEntry();
121 | }
122 | System.out.println("[INFO] Successful saved " + out.getName());
123 | } catch (Exception e) {
124 | e.printStackTrace();
125 | }
126 | }
127 |
128 | public Deobfuscator addTransformer(Transformer transformer) {
129 | if (!transformers.contains(transformer))
130 | transformers.add(transformer);
131 | return this;
132 | }
133 |
134 | public static Deobfuscator getInstance() {
135 | return instance;
136 | }
137 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/DeobfuscatorInitializer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf;
2 |
3 | public class DeobfuscatorInitializer {
4 | public static void main(String[] args) {
5 | new Deobfuscator()
6 | // .addTransformer(new LocalVariableRemoverTransformer())
7 | // .addTransformer(new SignatureRemoverTransformer())
8 | // .addTransformer(new FieldNameTransformer())
9 | .run(args);
10 | }
11 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/Transformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer;
2 |
3 | import me.ANONIMUS.deobf.util.BytecodeUtils;
4 | import org.objectweb.asm.Opcodes;
5 | import org.objectweb.asm.tree.ClassNode;
6 | import org.objectweb.asm.tree.analysis.AnalyzerException;
7 |
8 | import java.util.List;
9 |
10 | public abstract class Transformer extends BytecodeUtils implements Opcodes {
11 | public abstract void visit(List classMap) throws AnalyzerException;
12 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/AnnotationRemoverTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.ClassNode;
5 |
6 | import java.util.List;
7 |
8 | public class AnnotationRemoverTransformer extends Transformer {
9 | @Override
10 | public void visit(List classMap) {
11 | classMap.forEach(classNode -> {
12 | classNode.invisibleAnnotations = null;
13 | classNode.visibleAnnotations = null;
14 |
15 | classNode.methods.forEach(methodNode -> {
16 | methodNode.invisibleAnnotations = null;
17 | methodNode.visibleAnnotations = null;
18 | });
19 |
20 | classNode.fields.forEach(fieldNode -> {
21 | fieldNode.invisibleAnnotations = null;
22 | fieldNode.visibleAnnotations = null;
23 | });
24 | });
25 | }
26 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/DebugInfoRemoverTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl;
2 |
3 | import me.ANONIMUS.deobf.Deobfuscator;
4 | import me.ANONIMUS.deobf.transformer.Transformer;
5 | import me.ANONIMUS.deobf.util.BytecodeUtils;
6 | import org.objectweb.asm.ClassReader;
7 | import org.objectweb.asm.tree.ClassNode;
8 | import org.objectweb.asm.tree.analysis.AnalyzerException;
9 |
10 | import java.util.List;
11 |
12 | public class DebugInfoRemoverTransformer extends Transformer {
13 | @Override
14 | public void visit(List classMap) throws AnalyzerException {
15 | classMap.forEach(classNode -> {
16 | ClassNode classNodeCopy = new ClassNode();
17 | new ClassReader(BytecodeUtils.toByteArray(classNode)).accept(classNodeCopy, ClassReader.SKIP_DEBUG);
18 |
19 | Deobfuscator.getInstance().getClasses().remove(classNode);
20 | Deobfuscator.getInstance().getClasses().add(classNode);
21 | });
22 | }
23 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/FixAccessTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.ClassNode;
5 |
6 | import java.util.List;
7 |
8 | public class FixAccessTransformer extends Transformer {
9 | @Override
10 | public void visit(List classMap) {
11 | classMap.forEach(classNode -> {
12 | classNode.access = fixAccess(classNode.access);
13 | classNode.methods.forEach(methodNode -> {
14 | methodNode.access = fixAccess(methodNode.access);
15 | if (methodNode.parameters != null) {
16 | methodNode.parameters.forEach(pn -> pn.access = fixAccess(pn.access));
17 | }
18 | });
19 | classNode.fields.forEach(fieldNode -> fieldNode.access = fixAccess(fieldNode.access));
20 | });
21 | }
22 |
23 | public int fixAccess(int access) {
24 | int acc = ACC_PUBLIC;
25 | if (isStatic(access)) {
26 | acc = addAccess(acc, ACC_STATIC);
27 | }
28 | if (isAbstract(access)) {
29 | acc = addAccess(acc, ACC_ABSTRACT);
30 | }
31 | if (isInterface(access)) {
32 | acc = addAccess(acc, ACC_INTERFACE);
33 | }
34 | return acc;
35 | }
36 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/IllegalSignatureRemoverTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.ClassNode;
5 | import org.objectweb.asm.util.CheckClassAdapter;
6 |
7 | import java.util.List;
8 |
9 | public class IllegalSignatureRemoverTransformer extends Transformer {
10 | @Override
11 | public void visit(List classMap) {
12 | classMap.forEach(classNode -> {
13 | if (classNode.signature != null) {
14 | try {
15 | CheckClassAdapter.checkClassSignature(classNode.signature);
16 | } catch (IllegalArgumentException | StringIndexOutOfBoundsException ignored) {
17 | classNode.signature = null;
18 | }
19 | }
20 | classNode.methods.forEach(methodNode -> {
21 | if (methodNode.signature != null) {
22 | try {
23 | CheckClassAdapter.checkMethodSignature(methodNode.signature);
24 | } catch (IllegalArgumentException | StringIndexOutOfBoundsException ignored) {
25 | methodNode.signature = null;
26 | }
27 | }
28 | });
29 | classNode.fields.forEach(fieldNode -> {
30 | if (fieldNode.signature != null) {
31 | try {
32 | CheckClassAdapter.checkFieldSignature(fieldNode.signature);
33 | } catch (IllegalArgumentException | StringIndexOutOfBoundsException ignored) {
34 | fieldNode.signature = null;
35 | }
36 | }
37 | });
38 | });
39 | }
40 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/IllegalVarargsRemoverTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.Type;
5 | import org.objectweb.asm.tree.ClassNode;
6 |
7 | import java.util.List;
8 |
9 | public class IllegalVarargsRemoverTransformer extends Transformer {
10 | @Override
11 | public void visit(List classMap) {
12 | classMap.forEach(classNode -> classNode.methods.forEach(methodNode -> {
13 | Type[] args = Type.getArgumentTypes(methodNode.desc);
14 | if (args.length > 0 && args[args.length - 1].getSort() != Type.ARRAY) {
15 | methodNode.access = removeAccess(methodNode.access, ACC_VARARGS);
16 | }
17 | }));
18 | }
19 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/InvalidTryCatchRemoverTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.AbstractInsnNode;
5 | import org.objectweb.asm.tree.ClassNode;
6 | import org.objectweb.asm.tree.analysis.Analyzer;
7 | import org.objectweb.asm.tree.analysis.AnalyzerException;
8 | import org.objectweb.asm.tree.analysis.BasicInterpreter;
9 | import org.objectweb.asm.tree.analysis.Frame;
10 |
11 | import java.util.List;
12 |
13 | public class InvalidTryCatchRemoverTransformer extends Transformer {
14 | @Override
15 | public void visit(List classMap) throws AnalyzerException {
16 | classMap.forEach(classNode -> classNode.methods.forEach(methodNode -> {
17 | methodNode.tryCatchBlocks.removeIf(tcb -> tcb.start == tcb.end || methodNode.instructions.indexOf(tcb.start) >= methodNode.instructions.indexOf(tcb.end));
18 |
19 | Analyzer> analyzer = new Analyzer<>(new BasicInterpreter());
20 | try {
21 | analyzer.analyze(classNode.name, methodNode);
22 | } catch (AnalyzerException ignored) {
23 | return;
24 | }
25 | Frame>[] frames = analyzer.getFrames();
26 | AbstractInsnNode[] insns = methodNode.instructions.toArray();
27 | for (int i = 0; i < frames.length; i++) {
28 | AbstractInsnNode insn = insns[i];
29 | if (frames[i] == null && insn.getType() != AbstractInsnNode.LABEL) {
30 | methodNode.instructions.remove(insn);
31 | insns[i] = null;
32 | }
33 | }
34 | }));
35 | }
36 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/LocalVariableRemoverTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.ClassNode;
5 |
6 | import java.util.List;
7 |
8 | public class LocalVariableRemoverTransformer extends Transformer {
9 | @Override
10 | public void visit(List classMap) {
11 | classMap.forEach(classNode -> classNode.methods.forEach(methodNode -> methodNode.localVariables = null));
12 | }
13 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/UnknownAttributeRemoverTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.Attribute;
5 | import org.objectweb.asm.tree.ClassNode;
6 | import org.objectweb.asm.tree.analysis.AnalyzerException;
7 |
8 | import java.util.Arrays;
9 | import java.util.List;
10 |
11 | public class UnknownAttributeRemoverTransformer extends Transformer {
12 | @Override
13 | public void visit(List classMap) throws AnalyzerException {
14 | Arrays.stream(classMap.toArray(new ClassNode[0])).filter(classNode -> classNode.attrs != null).forEach(classNode -> classNode.attrs.stream().filter(Attribute::isUnknown).forEach(attr -> classNode.attrs.remove(attr)));
15 | }
16 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/WatermarkTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.ClassNode;
5 | import org.objectweb.asm.tree.MethodNode;
6 |
7 | import java.util.List;
8 |
9 | public class WatermarkTransformer extends Transformer {
10 | @Override
11 | public void visit(List classMap) {
12 | final MethodNode methodNode = createMethod();
13 | classMap.stream().filter(classNode -> !isInterface(classNode.access) && !isAbstract(classNode.access) && !isAnnotation(classNode.access)).forEach(classNode -> classNode.methods.add(methodNode));
14 | }
15 |
16 | private MethodNode createMethod() {
17 | final MethodNode methodNode = new MethodNode(ACC_PROTECTED, "hi", createDescription(DESC_STRING, DESC_EMPTY), null, null);
18 | methodNode.visitCode();
19 | methodNode.visitLdcInsn("github: " + "https://github.com/Ikos3k");
20 | methodNode.visitVarInsn(ASTORE, 0);
21 | methodNode.visitLdcInsn("deobf by ANONIMUS(Ikos3k)");
22 | methodNode.visitInsn(ARETURN);
23 | methodNode.visitEnd();
24 | return methodNode;
25 | }
26 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/name/ClassNameTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl.name;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.ClassNode;
5 |
6 | import java.util.Collections;
7 | import java.util.HashMap;
8 | import java.util.List;
9 | import java.util.Map;
10 | import java.util.stream.Collectors;
11 |
12 | public class ClassNameTransformer extends Transformer {
13 | @Override
14 | public void visit(List classMap) {
15 | Map remap = new HashMap<>();
16 |
17 | List keys = classMap.stream().map(c -> c.name).collect(Collectors.toList());
18 | Collections.shuffle(keys);
19 | int i = 0;
20 | for (String key : keys) {
21 | ClassNode cn = getClassNode(key, classMap);
22 | if (!isMainClass(cn)) {
23 | remap.put(cn.name, "class_" + i);
24 | i++;
25 | }
26 | }
27 | applyMappings(classMap, remap);
28 | }
29 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/name/FieldNameTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl.name;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.ClassNode;
5 | import org.objectweb.asm.tree.FieldNode;
6 |
7 | import java.util.*;
8 | import java.util.stream.Collectors;
9 |
10 | public class FieldNameTransformer extends Transformer {
11 | @Override
12 | public void visit(List classMap) {
13 | Map remap = new HashMap<>();
14 |
15 | List fields = new ArrayList<>();
16 | classMap.forEach(c -> fields.addAll(c.fields));
17 | Collections.shuffle(fields);
18 | int i = 0;
19 | for (FieldNode f : fields) {
20 | Stack nodeStack = new Stack<>();
21 | nodeStack.add(getOwner(f, classMap));
22 | while (nodeStack.size() > 0) {
23 | ClassNode node = nodeStack.pop();
24 | remap.put(node.name + "." + f.name, "field_" + i);
25 | nodeStack.addAll(classMap.stream().
26 | filter(cn -> cn.superName.equals(node.name)).
27 | collect(Collectors.toList()));
28 | }
29 | i++;
30 | }
31 | applyMappings(classMap, remap);
32 | }
33 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/name/MethodNameTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl.name;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.ClassNode;
5 | import org.objectweb.asm.tree.MethodNode;
6 |
7 | import java.util.*;
8 |
9 | public class MethodNameTransformer extends Transformer {
10 | @Override
11 | public void visit(List classMap) {
12 | Map remap = new HashMap<>();
13 |
14 | List methods = new LinkedList<>();
15 | classMap.forEach(c -> methods.addAll(c.methods));
16 |
17 | Collections.shuffle(methods);
18 | int i = 0;
19 | methods:
20 | for (MethodNode m : methods) {
21 | ClassNode owner = getOwner(m, classMap);
22 |
23 | if (isInitializer(m) || isNative(m.access) || isMainMethod(m)) {
24 | continue;
25 | }
26 | Stack nodeStack = new Stack<>();
27 | nodeStack.add(owner);
28 | while (nodeStack.size() > 0) {
29 | ClassNode node = nodeStack.pop();
30 | if (node != owner && getMethod(node, m.name, m.desc) != null)
31 | continue methods;
32 | ClassNode parent = getClassNode(node.superName, classMap);
33 | if (parent != null)
34 | nodeStack.push(parent);
35 | Set interfaces = new HashSet<>();
36 | for (String str : node.interfaces.toArray(new String[0])) {
37 | ClassNode cn = getClassNode(str, classMap);
38 | if (cn != null) {
39 | interfaces.add(cn);
40 | }
41 | }
42 | nodeStack.addAll(interfaces);
43 | }
44 | nodeStack.add(owner);
45 | while (nodeStack.size() > 0) {
46 | ClassNode node = nodeStack.pop();
47 | remap.put(node.name + '.' + m.name + m.desc, "method_" + i);
48 | classMap.stream().filter(c -> c.superName.equals(node.name) || c.interfaces.contains(node.name)).forEach(nodeStack::push);
49 | }
50 | i++;
51 | }
52 | applyMappings(classMap, remap);
53 | }
54 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/optimization/GotoInlinerTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl.optimization;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.AbstractInsnNode;
5 | import org.objectweb.asm.tree.ClassNode;
6 | import org.objectweb.asm.tree.JumpInsnNode;
7 |
8 | import java.util.Arrays;
9 | import java.util.List;
10 |
11 | public class GotoInlinerTransformer extends Transformer {
12 | @Override
13 | public void visit(List classMap) {
14 | classMap.forEach(classNode ->
15 | classNode.methods.forEach(methodNode ->
16 | Arrays.stream(methodNode.instructions.toArray()).filter(abstractInsnNode -> abstractInsnNode.getOpcode() == GOTO).forEach(abstractInsnNode -> {
17 | final JumpInsnNode gotoJump = (JumpInsnNode) abstractInsnNode;
18 | final AbstractInsnNode insnAfterTarget = gotoJump.label.getNext();
19 | if (insnAfterTarget == null)
20 | return;
21 |
22 | if (insnAfterTarget.getOpcode() != GOTO)
23 | return;
24 |
25 | gotoJump.label = ((JumpInsnNode) insnAfterTarget).label;
26 | })
27 | )
28 | );
29 | }
30 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/optimization/NopRemoverTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl.optimization;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.ClassNode;
5 |
6 | import java.util.Arrays;
7 | import java.util.List;
8 |
9 | public class NopRemoverTransformer extends Transformer {
10 | @Override
11 | public void visit(List classMap) {
12 | classMap.forEach(classNode -> classNode.methods.forEach(methodNode -> Arrays.stream(methodNode.instructions.toArray()).filter(insnNode -> insnNode.getOpcode() == NOP).forEach(insnNode -> methodNode.instructions.remove(insnNode))));
13 | }
14 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/shrinking/InnerClassTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl.shrinking;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.ClassNode;
5 |
6 | import java.util.List;
7 |
8 | public class InnerClassTransformer extends Transformer {
9 | @Override
10 | public void visit(List classMap) {
11 | classMap.forEach(classNode -> {
12 | classNode.outerClass = null;
13 | classNode.outerMethod = null;
14 | classNode.outerMethodDesc = null;
15 | classNode.innerClasses.clear();
16 | });
17 | }
18 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/shrinking/LineNumberRemoverTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl.shrinking;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.AbstractInsnNode;
5 | import org.objectweb.asm.tree.ClassNode;
6 | import org.objectweb.asm.tree.LineNumberNode;
7 |
8 | import java.util.Iterator;
9 | import java.util.List;
10 |
11 | public class LineNumberRemoverTransformer extends Transformer {
12 | @Override
13 | public void visit(List classMap) {
14 | classMap.forEach(classNode -> classNode.methods.forEach(methodNode -> {
15 | Iterator it = methodNode.instructions.iterator();
16 | while (it.hasNext()) {
17 | if (it.next() instanceof LineNumberNode) {
18 | it.remove();
19 | }
20 | }
21 | }));
22 | }
23 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/shrinking/SignatureRemoverTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl.shrinking;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.ClassNode;
5 | import org.objectweb.asm.tree.analysis.AnalyzerException;
6 |
7 | import java.util.List;
8 |
9 | public class SignatureRemoverTransformer extends Transformer {
10 | @Override
11 | public void visit(List classMap) throws AnalyzerException {
12 | classMap.forEach(classNode -> {
13 | classNode.signature = null;
14 | classNode.methods.forEach(methodNode -> methodNode.signature = null);
15 | classNode.fields.forEach(fieldNode -> fieldNode.signature = null);
16 | });
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/shrinking/SourceDebugRemoverTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl.shrinking;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.ClassNode;
5 | import org.objectweb.asm.tree.analysis.AnalyzerException;
6 |
7 | import java.util.List;
8 |
9 | public class SourceDebugRemoverTransformer extends Transformer {
10 | @Override
11 | public void visit(List classMap) throws AnalyzerException {
12 | classMap.forEach(classNode -> classNode.sourceDebug = null);
13 | }
14 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/shrinking/SourceFileRemoverTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl.shrinking;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.ClassNode;
5 | import org.objectweb.asm.tree.analysis.AnalyzerException;
6 |
7 | import java.util.List;
8 |
9 | public class SourceFileRemoverTransformer extends Transformer {
10 | @Override
11 | public void visit(List classMap) throws AnalyzerException {
12 | classMap.forEach(classNode -> classNode.sourceFile = null);
13 | }
14 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/string/AllatoriStringTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl.string;
2 |
3 | import lombok.AllArgsConstructor;
4 | import me.ANONIMUS.deobf.transformer.Transformer;
5 | import org.objectweb.asm.tree.AbstractInsnNode;
6 | import org.objectweb.asm.tree.ClassNode;
7 | import org.objectweb.asm.tree.LdcInsnNode;
8 |
9 | import java.util.List;
10 |
11 | @AllArgsConstructor
12 | public class AllatoriStringTransformer extends Transformer {
13 | private final int mode;
14 | private final boolean removeWatermark;
15 |
16 | @Override
17 | public void visit(List classMap) {
18 | classMap.forEach(classNode -> classNode.methods.forEach(methodNode -> {
19 | AbstractInsnNode[] abstractInsnNodes = methodNode.instructions.toArray();
20 | for (AbstractInsnNode abstractInsnNode : abstractInsnNodes) {
21 | if (abstractInsnNode.getType() == AbstractInsnNode.LDC_INSN) {
22 | LdcInsnNode ldcInsnNode = (LdcInsnNode) abstractInsnNode;
23 | if (ldcInsnNode.cst instanceof String) {
24 | if (ldcInsnNode.getNext() != null && ldcInsnNode.getNext().getOpcode() == INVOKESTATIC) {
25 | ldcInsnNode.cst = getDecryptedString((String) ldcInsnNode.cst, mode);
26 | methodNode.instructions.remove(ldcInsnNode.getNext());
27 | }
28 | }
29 | }
30 | }
31 | }));
32 | if (removeWatermark) {
33 | classMap.forEach(classNode -> classNode.methods.forEach(methodNode -> {
34 | if (isMainMethod(methodNode)) {
35 | AbstractInsnNode[] abstractInsnNodes = methodNode.instructions.toArray();
36 | for (AbstractInsnNode abstractInsnNode : abstractInsnNodes) {
37 | if (abstractInsnNode instanceof LdcInsnNode) {
38 | LdcInsnNode ldcInsnNode = (LdcInsnNode) abstractInsnNode;
39 | if (ldcInsnNode.cst instanceof String && ldcInsnNode.cst.equals("\n################################################\n# #\n# ## # # ## ### ### ## ### #\n# # # # # # # # # # # # # #\n# ### # # ### # # # ## # #\n# # # ### ### # # # ### # # ### #\n# #\n# Obfuscation by Allatori Obfuscator v6.5 DEMO #\n# #\n# http://www.allatori.com #\n# #\n################################################\n")) {
40 | methodNode.instructions.remove(ldcInsnNode.getPrevious());
41 | methodNode.instructions.remove(ldcInsnNode.getNext().getNext());
42 | methodNode.instructions.remove(ldcInsnNode.getNext());
43 | methodNode.instructions.remove(ldcInsnNode);
44 | }
45 | }
46 | }
47 | }
48 | }));
49 | }
50 | }
51 |
52 | private String getDecryptedString(String string, int mode) {
53 | switch (mode) {
54 | case 0: {
55 | return decrypt0(string);
56 | }
57 | case 1: {
58 | return decrypt1(string);
59 | }
60 | case 2: {
61 | return decrypt2(string);
62 | }
63 | case 3: {
64 | return decrypt3(string);
65 | }
66 | case 4: {
67 | return decrypt4(string);
68 | }
69 | case 5: {
70 | return decrypt5(string);
71 | }
72 | case 6: {
73 | return decrypt6(string);
74 | }
75 | case 7: {
76 | return decrypt7(string);
77 | }
78 | }
79 | return string;
80 | }
81 |
82 | private String decrypt0(String s) {
83 | int n2;
84 | char[] array = new char[s.length()];
85 | int i = n2 = array.length - 1;
86 | int c = 115;
87 | while (i >= 0) {
88 | int n3 = n2;
89 | char c2 = (char) (s.charAt(n2) ^ c);
90 | char c3 = (char) ((char) (n3 ^ c) & 0x3F);
91 | array[n3] = c2;
92 | if (--n2 < 0) break;
93 | int n4 = n2;
94 | char c4 = (char) (s.charAt(n2) ^ c3);
95 | c = (char) ((char) (n4 ^ c3) & 0x3F);
96 | array[n4] = c4;
97 | i = --n2;
98 | }
99 | return new String(array);
100 | }
101 |
102 | private String decrypt1(String s) {
103 | int n2;
104 | char[] array = new char[s.length()];
105 | int i = n2 = array.length - 1;
106 | int c = 116;
107 | while (i >= 0) {
108 | int n3 = n2;
109 | char c2 = (char) (s.charAt(n2) ^ c);
110 | char c3 = (char) ((char) (n3 ^ c) & 0x3F);
111 | array[n3] = c2;
112 | if (--n2 < 0) break;
113 | int n4 = n2;
114 | char c4 = (char) (s.charAt(n2) ^ c3);
115 | c = (char) ((char) (n4 ^ c3) & 0x3F);
116 | array[n4] = c4;
117 | i = --n2;
118 | }
119 | return new String(array);
120 | }
121 |
122 | private String decrypt2(String s) {
123 | int i = s.length();
124 | char[] a = new char[i];
125 | int i0 = i - 1;
126 | while (i0 >= 0) {
127 | int i1 = s.charAt(i0);
128 | int i2 = i0 + -1;
129 | int i3 = (char) (i1 ^ 105);
130 | a[i0] = (char) i3;
131 | if (i2 >= 0) {
132 | i0 = i2 + -1;
133 | int i4 = s.charAt(i2);
134 | int i5 = (char) (i4 ^ 59);
135 | a[i2] = (char) i5;
136 | }
137 | }
138 | return new String(a);
139 | }
140 |
141 | private String decrypt3(String s) {
142 | int n = s.length();
143 | int n2 = n - 1;
144 | char[] arrc = new char[n];
145 | int n3 = 5 << 3 ^ 2;
146 | int n4 = n2;
147 | int n5 = (3 ^ 5) << 4 ^ 2 << 1;
148 | while (n4 >= 0) {
149 | int n6 = n2--;
150 | arrc[n6] = (char) (s.charAt(n6) ^ n5);
151 | if (n2 < 0) break;
152 | int n7 = n2--;
153 | arrc[n7] = (char) (s.charAt(n7) ^ n3);
154 | n4 = n2;
155 | }
156 | return new String(arrc);
157 | }
158 |
159 | private String decrypt4(String a) {
160 | final int n = (0x2 ^ 0x5) << 4;
161 | final int n2 = 2;
162 | final int n3 = n ^ (n2 << n2 ^ 0x1);
163 | final int n4 = (0x2 ^ 0x5) << 3 ^ 0x2;
164 | final int length = a.length();
165 | final char[] array = new char[length];
166 | int n5;
167 | int i = n5 = length - 1;
168 | final char c = (char) n4;
169 | while (i >= 0) {
170 | final int n7 = n5;
171 | final char char1 = a.charAt(n7);
172 | --n5;
173 | array[n7] = (char) (char1 ^ n3);
174 | if (n5 < 0) {
175 | break;
176 | }
177 | final int n8 = n5--;
178 | array[n8] = (char) (a.charAt(n8) ^ c);
179 | i = n5;
180 | }
181 | return new String(array);
182 | }
183 |
184 | private String decrypt5(String a) {
185 | final int n = 4;
186 | final int n2 = n << n ^ 2 << 1;
187 | final int n3 = (0x3 ^ 0x5) << 4 ^ 0x3;
188 | final int length = a.length();
189 | final char[] array = new char[length];
190 | int n4;
191 | int i = n4 = length - 1;
192 | final char c = (char) n3;
193 | while (i >= 0) {
194 | final int n6 = n4;
195 | final char char1 = a.charAt(n6);
196 | --n4;
197 | array[n6] = (char) (char1 ^ n2);
198 | if (n4 < 0) {
199 | break;
200 | }
201 | final int n7 = n4--;
202 | array[n7] = (char) (a.charAt(n7) ^ c);
203 | i = n4;
204 | }
205 | return new String(array);
206 | }
207 |
208 | private String decrypt6(String a) {
209 | final int n = 4;
210 | final int n2 = n << n ^ 3 << 1;
211 | final int n3 = (0x3 ^ 0x5) << 4;
212 | final int n4 = 1;
213 | final int n5 = n3 ^ n4 << n4;
214 | final int length = a.length();
215 | final char[] array = new char[length];
216 | int n6;
217 | int i = n6 = length - 1;
218 | final char c = (char) n5;
219 | while (i >= 0) {
220 | final int n8 = n6;
221 | final char char1 = a.charAt(n8);
222 | --n6;
223 | array[n8] = (char) (char1 ^ n2);
224 | if (n6 < 0) {
225 | break;
226 | }
227 | final int n9 = n6--;
228 | array[n9] = (char) (a.charAt(n9) ^ c);
229 | i = n6;
230 | }
231 | return new String(array);
232 | }
233 |
234 | private String decrypt7(String a) {
235 | final int n = (0x3 ^ 0x5) << 3 ^ 0x5;
236 | final int n2 = 4;
237 | final int n3 = n2 << n2 ^ (0x3 ^ 0x5) << 1;
238 | final int length = a.length();
239 | final char[] array = new char[length];
240 | int n4;
241 | int i = n4 = length - 1;
242 | final char c = (char) n3;
243 | while (i >= 0) {
244 | final int n6 = n4;
245 | final char char1 = a.charAt(n6);
246 | --n4;
247 | array[n6] = (char) (char1 ^ n);
248 | if (n4 < 0) {
249 | break;
250 | }
251 | final int n7 = n4--;
252 | array[n7] = (char) (a.charAt(n7) ^ c);
253 | i = n4;
254 | }
255 | return new String(array);
256 | }
257 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/string/AlpheratzTeamStringTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl.string;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.Type;
5 | import org.objectweb.asm.tree.*;
6 |
7 | import java.util.List;
8 |
9 | public class AlpheratzTeamStringTransformer extends Transformer {
10 | @Override
11 | public void visit(List classMap) {
12 | classMap.forEach(classNode -> classNode.methods.forEach(methodNode -> {
13 | AbstractInsnNode[] abstractInsnNodes = methodNode.instructions.toArray();
14 | for (AbstractInsnNode abstractInsnNode : abstractInsnNodes) {
15 | if (abstractInsnNode.getType() == AbstractInsnNode.LDC_INSN) {
16 | LdcInsnNode ldcInsnNode = (LdcInsnNode) abstractInsnNode;
17 | AbstractInsnNode abInsnNodeNEXT = ldcInsnNode.getNext();
18 | if (ldcInsnNode.cst instanceof String && abInsnNodeNEXT.getType() == AbstractInsnNode.METHOD_INSN) {
19 | final Type cType = getClassType(classNode, ((MethodInsnNode) abInsnNodeNEXT).name);
20 | if (cType != null) {
21 | String className = cType.toString().replaceFirst("L", "").replace(";", "");
22 | ldcInsnNode.cst = decrypt((String) ldcInsnNode.cst, computeConstantPoolSize(getClassNode(className, classMap)));
23 | methodNode.instructions.remove(abInsnNodeNEXT);
24 | }
25 | }
26 | }
27 | }
28 | }));
29 | }
30 |
31 | private Type getClassType(ClassNode classNode, String name) {
32 | for (MethodNode mn : classNode.methods) {
33 | if (mn.name.equals(name)) {
34 | for (AbstractInsnNode ab : mn.instructions.toArray()) {
35 | if (ab.getType() == AbstractInsnNode.METHOD_INSN && ab.getNext().getType() == AbstractInsnNode.LDC_INSN) {
36 | LdcInsnNode ldcInsnNode = (LdcInsnNode) ab.getNext();
37 | if (((MethodInsnNode) ab).owner.equals("sun/misc/SharedSecrets") && ldcInsnNode.cst instanceof Type) {
38 | return (Type) ldcInsnNode.cst;
39 | }
40 | }
41 | }
42 | }
43 | }
44 | return null;
45 | }
46 |
47 | private String decrypt(final String str, int key) {
48 | final char[] c = str.toCharArray();
49 | for (int i = 0; i < c.length; i++) {
50 | c[i] ^= key;
51 | }
52 | return new String(c);
53 | }
54 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/string/DashoStringTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl.string;
2 |
3 | import lombok.AllArgsConstructor;
4 | import me.ANONIMUS.deobf.transformer.Transformer;
5 | import org.objectweb.asm.tree.AbstractInsnNode;
6 | import org.objectweb.asm.tree.ClassNode;
7 | import org.objectweb.asm.tree.LdcInsnNode;
8 | import org.objectweb.asm.tree.analysis.AnalyzerException;
9 |
10 | import java.util.List;
11 |
12 | @AllArgsConstructor
13 | public class DashoStringTransformer extends Transformer {
14 | private final int mode;
15 |
16 | @Override
17 | public void visit(List classMap) throws AnalyzerException {
18 | classMap.forEach(classNode -> classNode.methods.forEach(methodNode -> {
19 | for (AbstractInsnNode insn : methodNode.instructions.toArray()) {
20 | if (insn instanceof LdcInsnNode && ((LdcInsnNode) insn).cst instanceof String && insn.getNext() != null && isIntInsn(insn.getNext())) {
21 | AbstractInsnNode abstractInsnNodeNEXT = insn.getNext();
22 | methodNode.instructions.set(abstractInsnNodeNEXT, new LdcInsnNode(getDecryptedString((String) ((LdcInsnNode) insn).cst, getIntNumber(abstractInsnNodeNEXT), mode)));
23 | methodNode.instructions.remove(insn);
24 | }
25 | }
26 | }));
27 | }
28 |
29 | private String getDecryptedString(String string, int key, int mode) {
30 | switch (mode) {
31 | case 0: {
32 | return decrypt0(string, key);
33 | }
34 | case 1: {
35 | return decrypt1(string, key);
36 | }
37 | }
38 | return string;
39 | }
40 |
41 | private String decrypt0(String string, int n) {
42 | char[] cArray = string.toCharArray();
43 | int n2 = cArray.length;
44 | int n3 = 0;
45 | int n4 = (4 << 4 + 1) - 1 ^ 0x20;
46 | while (n3 != n2) {
47 | int n5 = n3++;
48 | int n6 = n & n4 ^ cArray[n5];
49 | ++n;
50 | cArray[n5] = (char) n6;
51 | }
52 | return String.valueOf(cArray, 0, n2).intern();
53 | }
54 |
55 | private String decrypt1(String string, int n) {
56 | n += 5;
57 | char[] cArray = string.toCharArray();
58 | int n2 = cArray.length;
59 | int n3 = 0;
60 | int n4 = (4 << 1 + 4) - 1 ^ 0x20;
61 | while (n3 != n2) {
62 | int n5 = n3++;
63 | int n6 = cArray[n5] ^ n & n4;
64 | n += 7;
65 | cArray[n5] = (char) n6;
66 | }
67 | return String.valueOf(cArray, 0, n2).intern();
68 | }
69 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/string/SuperBlaubeere27StringTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl.string;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.*;
5 |
6 | import javax.crypto.Cipher;
7 | import javax.crypto.spec.SecretKeySpec;
8 | import java.nio.charset.StandardCharsets;
9 | import java.security.MessageDigest;
10 | import java.util.ArrayList;
11 | import java.util.Arrays;
12 | import java.util.Base64;
13 | import java.util.List;
14 |
15 | public class SuperBlaubeere27StringTransformer extends Transformer {
16 | @Override
17 | public void visit(List classMap) {
18 | classMap.forEach(classNode -> {
19 | List methods = new ArrayList<>();
20 | classNode.methods.forEach(methodNode -> {
21 | AbstractInsnNode[] abstractInsnNodes = methodNode.instructions.toArray();
22 | for (AbstractInsnNode abstractInsnNode : abstractInsnNodes) {
23 | if (abstractInsnNode.getType() == AbstractInsnNode.LDC_INSN) {
24 | LdcInsnNode ldcInsnNode = (LdcInsnNode) abstractInsnNode;
25 | if (ldcInsnNode.getNext() != null && ldcInsnNode.getNext() instanceof LdcInsnNode) {
26 | LdcInsnNode ldcInsnNodeNext = (LdcInsnNode) ldcInsnNode.getNext();
27 | if (ldcInsnNodeNext.getNext().getOpcode() == INVOKESTATIC && ldcInsnNodeNext.getNext().getType() == AbstractInsnNode.METHOD_INSN) {
28 | String name = ((MethodInsnNode) ldcInsnNodeNext.getNext()).name;
29 | for (MethodNode mn : classNode.methods) {
30 | if (mn.name.equals(name) && mn.desc.equals(createDescription(DESC_STRING, DESC_STRING, DESC_STRING))) {
31 | ldcInsnNodeNext.cst = decrypt(mn, (String) ldcInsnNode.cst, (String) ldcInsnNodeNext.cst);
32 | methodNode.instructions.remove(ldcInsnNodeNext.getNext());
33 | methodNode.instructions.remove(ldcInsnNode);
34 | if (!methods.contains(mn))
35 | methods.add(mn);
36 | }
37 | }
38 | }
39 | }
40 | }
41 | }
42 | });
43 | classNode.methods.removeAll(methods);
44 | });
45 | }
46 |
47 | private String decrypt(MethodNode methodNode, String obj, String key) {
48 | if (hasInstructions(methodNode.instructions, DUP, LDC, INVOKESTATIC, ALOAD, GETSTATIC, INVOKEVIRTUAL, INVOKEVIRTUAL, LDC) && hasStrings(methodNode.instructions, "MD5", "Blowfish")) {
49 | return ll(obj, key);
50 | }
51 | if (hasInstructions(methodNode.instructions, DUP, LDC, INVOKESTATIC, ALOAD, GETSTATIC, INVOKEVIRTUAL, INVOKEVIRTUAL, BIPUSH) && hasStrings(methodNode.instructions, "MD5")) {
52 | return lI(obj, key);
53 | }
54 | if (hasInstructions(methodNode.instructions, DUP, LDC, INVOKESTATIC, ALOAD, LDC, INVOKEVIRTUAL, INVOKEVIRTUAL, LDC) && hasStrings(methodNode.instructions, "SHA-256", "AES")) {
55 | return l(obj, key);
56 | }
57 | if (hasInstructions(methodNode.instructions, DUP, INVOKESTATIC, ALOAD, GETSTATIC, INVOKEVIRTUAL, INVOKEVIRTUAL, GETSTATIC, INVOKESPECIAL)) {
58 | return I(obj, key);
59 | }
60 | return null;
61 | }
62 |
63 | private String l(String obj, String key) {
64 | try {
65 | SecretKeySpec keySpec = new SecretKeySpec(MessageDigest.getInstance("SHA-256").digest(key.getBytes(StandardCharsets.UTF_8)), "AES");
66 | Cipher des = Cipher.getInstance("AES");
67 | des.init(2, keySpec);
68 | return new String(des.doFinal(Base64.getDecoder().decode(obj.getBytes(StandardCharsets.UTF_8))), StandardCharsets.UTF_8);
69 | } catch (Exception var4) {
70 | return null;
71 | }
72 | }
73 |
74 | private String lI(String obj, String key) {
75 | try {
76 | SecretKeySpec keySpec = new SecretKeySpec(Arrays.copyOf(MessageDigest.getInstance("MD5").digest(key.getBytes(StandardCharsets.UTF_8)), 8), "DES");
77 | Cipher des = Cipher.getInstance("DES");
78 | des.init(2, keySpec);
79 | return new String(des.doFinal(Base64.getDecoder().decode(obj.getBytes(StandardCharsets.UTF_8))), StandardCharsets.UTF_8);
80 | } catch (Exception var4) {
81 | return null;
82 | }
83 | }
84 |
85 | private String I(String obj, String key) {
86 | obj = new String(Base64.getDecoder().decode(obj.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
87 | StringBuilder sb = new StringBuilder();
88 | char[] keyChars = key.toCharArray();
89 | int i = 0;
90 | char[] var5 = obj.toCharArray();
91 |
92 | for (char c : var5) {
93 | sb.append((char) (c ^ keyChars[i % keyChars.length]));
94 | ++i;
95 | }
96 |
97 | return sb.toString();
98 | }
99 |
100 | private String ll(String obj, String key) {
101 | try {
102 | SecretKeySpec keySpec = new SecretKeySpec(MessageDigest.getInstance("MD5").digest(key.getBytes(StandardCharsets.UTF_8)), "Blowfish");
103 | Cipher des = Cipher.getInstance("Blowfish");
104 | des.init(2, keySpec);
105 | return new String(des.doFinal(Base64.getDecoder().decode(obj.getBytes(StandardCharsets.UTF_8))), StandardCharsets.UTF_8);
106 | } catch (Exception var4) {
107 | return null;
108 | }
109 | }
110 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/transformer/impl/string/qProtectStringTransformer.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.transformer.impl.string;
2 |
3 | import me.ANONIMUS.deobf.transformer.Transformer;
4 | import org.objectweb.asm.tree.AbstractInsnNode;
5 | import org.objectweb.asm.tree.ClassNode;
6 | import org.objectweb.asm.tree.InsnNode;
7 | import org.objectweb.asm.tree.LdcInsnNode;
8 |
9 | import java.util.List;
10 |
11 | public class qProtectStringTransformer extends Transformer {
12 | @Override
13 | public void visit(List classMap) {
14 | classMap.forEach(classNode -> classNode.methods.forEach(methodNode -> {
15 | for (AbstractInsnNode insn : methodNode.instructions.toArray()) {
16 | if (insn instanceof LdcInsnNode && ((LdcInsnNode) insn).cst instanceof String && insn.getPrevious() instanceof InsnNode && insn.getPrevious().getPrevious() instanceof LdcInsnNode) {
17 | methodNode.instructions.remove(insn.getNext());
18 | methodNode.instructions.set(insn, new LdcInsnNode(decrypt((String) ((LdcInsnNode) insn).cst)));
19 | }
20 | }
21 | }));
22 | }
23 |
24 | private String decrypt(String var0) {
25 | try {
26 | char[] var1 = var0.toCharArray();
27 | char[] var3 = new char[]{'䠲', '⎅', '⎆', '頓', '鄥', '䖂', 'ओ', '㐢', 'ࡓ', 'ܤ'};
28 | char[] var10000 = new char[]{'䠠', '萃', '蝓', '㠂', '㡀', '㢔', '蜹', 'း', '茄', '㌳'};
29 |
30 | for (int i = 0; i < var1.length; i++) {
31 | var1[i] ^= var3[i % 10] ^ var10000[i % 10];
32 | }
33 | return new String(var1);
34 | } catch (Exception var7) {
35 | return var0;
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/src/main/java/me/ANONIMUS/deobf/util/BytecodeUtils.java:
--------------------------------------------------------------------------------
1 | package me.ANONIMUS.deobf.util;
2 |
3 | import org.objectweb.asm.ClassReader;
4 | import org.objectweb.asm.ClassWriter;
5 | import org.objectweb.asm.Opcodes;
6 | import org.objectweb.asm.commons.ClassRemapper;
7 | import org.objectweb.asm.commons.SimpleRemapper;
8 | import org.objectweb.asm.tree.*;
9 |
10 | import java.util.ArrayList;
11 | import java.util.Collection;
12 | import java.util.List;
13 | import java.util.Map;
14 | import java.util.function.Consumer;
15 | import java.util.function.Predicate;
16 | import java.util.stream.IntStream;
17 |
18 | public class BytecodeUtils implements Opcodes {
19 | public boolean isMainMethod(MethodNode methodNode) {
20 | return methodNode.name.equals("main") && methodNode.desc.equals(createDescription(DESC_VOID, DESC_ARRAY_STRING)) && isPublic(methodNode.access) && isStatic(methodNode.access);
21 | }
22 |
23 | public boolean isInitializer(final MethodNode methodNode) {
24 | return methodNode.name.contains("<") || methodNode.name.contains(">");
25 | }
26 |
27 | public static boolean checkClassVerify(byte[] bytes) {
28 | return String.format("%X%X%X%X", bytes[0], bytes[1], bytes[2], bytes[3]).equals("CAFEBABE");
29 | }
30 |
31 | public boolean isMainClass(ClassNode classNode) {
32 | for (MethodNode method : classNode.methods)
33 | if (isMainMethod(method))
34 | return true;
35 | return false;
36 | }
37 |
38 | public boolean isIntInsn(AbstractInsnNode insn) {
39 | if (insn == null) {
40 | return false;
41 | }
42 | int opcode = insn.getOpcode();
43 | return ((opcode >= ICONST_M1 && opcode <= ICONST_5)
44 | || opcode == BIPUSH
45 | || opcode == SIPUSH
46 | || (insn instanceof LdcInsnNode
47 | && ((LdcInsnNode) insn).cst instanceof Integer));
48 | }
49 |
50 | public int getIntNumber(AbstractInsnNode insn) {
51 | final int opcode = insn.getOpcode();
52 | if (opcode >= ICONST_M1 && opcode <= ICONST_5)
53 | return opcode - 3;
54 | else if (insn instanceof IntInsnNode && insn.getOpcode() != NEWARRAY)
55 | return ((IntInsnNode) insn).operand;
56 | else if (insn instanceof LdcInsnNode && ((LdcInsnNode) insn).cst instanceof Integer)
57 | return (Integer) ((LdcInsnNode) insn).cst;
58 | throw new IllegalStateException("Unexpected instruction");
59 | }
60 |
61 | public void forEach(InsnList instructions, Class type, Consumer consumer) {
62 | AbstractInsnNode[] array = instructions.toArray();
63 | for (AbstractInsnNode node : array) {
64 | if (node.getClass() == type) {
65 | consumer.accept((T) node);
66 | }
67 | }
68 | }
69 |
70 | public void forEach(InsnList instructions, Consumer consumer) {
71 | forEach(instructions, AbstractInsnNode.class, consumer);
72 | }
73 |
74 | public void applyMappings(List classMap, Map remap) {
75 | SimpleRemapper remapper = new SimpleRemapper(remap);
76 | for (ClassNode node : new ArrayList<>(classMap)) {
77 | ClassNode copy = new ClassNode();
78 | ClassRemapper adapter = new ClassRemapper(copy, remapper);
79 | node.accept(adapter);
80 | classMap.remove(node);
81 | classMap.add(copy);
82 | }
83 | }
84 |
85 |
86 | public T findFirst(Collection collection, Predicate predicate) {
87 | for (T t : collection)
88 | if (predicate.test(t))
89 | return t;
90 | return null;
91 | }
92 |
93 | public MethodNode getMethod(ClassNode node, String name, String desc) {
94 | return findFirst(node.methods, m -> m.name.equals(name) && m.desc.equals(desc));
95 | }
96 |
97 | public ClassNode getOwner(MethodNode m, List classMap) {
98 | return findFirst(classMap, c -> c.methods.contains(m));
99 | }
100 |
101 | public ClassNode getOwner(FieldNode f, List classMap) {
102 | return findFirst(classMap, c -> c.fields.contains(f));
103 | }
104 |
105 | public ClassNode getClassNode(String name, List classMap) {
106 | return findFirst(classMap, c -> c.name.equals(name));
107 | }
108 |
109 | public final byte DESC_EMPTY = -1;
110 | public final byte DESC_VOID = 0;
111 | public final byte DESC_OBJECT = 1;
112 | public final byte DESC_STRING = 2;
113 | public final byte DESC_INTEGER = 3;
114 | public final byte DESC_CLASS = 4;
115 | public final byte DESC_BOOLEAN_TYPE = 5;
116 | public final byte DESC_INT = 6;
117 | public final byte DESC_LONG = 7;
118 | public final byte DESC_FLOAT = 8;
119 | public final byte DESC_DOUBLE = 9;
120 | public final byte DESC_SHORT = 10;
121 | public final byte DESC_BOOLEAN = 11;
122 | public final byte DESC_CHAR = 12;
123 | public final byte DESC_BYTE = 13;
124 |
125 | public final byte DESC_ARRAY_OBJECT = 101;
126 | public final byte DESC_ARRAY_STRING = 102;
127 | public final byte DESC_ARRAY_INTEGER = 103;
128 | public final byte DESC_ARRAY_CLASS = 104;
129 | public final byte DESC_ARRAY_BOOLEAN_TYPE = 105;
130 | public final byte DESC_ARRAY_INT = 106;
131 | public final byte DESC_ARRAY_LONG = 107;
132 | public final byte DESC_ARRAY_FLOAT = 108;
133 | public final byte DESC_ARRAY_DOUBLE = 109;
134 | public final byte DESC_ARRAY_SHORT = 110;
135 | public final byte DESC_ARRAY_BOOLEAN = 111;
136 | public final byte DESC_ARRAY_CHAR = 112;
137 | public final byte DESC_ARRAY_BYTE = 113;
138 |
139 | public String createDescription(byte returnType, byte... arguments) {
140 | StringBuilder desc = new StringBuilder();
141 | if (arguments.length > 0)
142 | desc.append("(");
143 | IntStream.range(0, arguments.length).forEach(i -> desc.append(getDescription(arguments[i])));
144 | if (arguments.length > 0) {
145 | desc.append(")");
146 | }
147 | return desc.append(getDescription(returnType)).toString();
148 | }
149 |
150 | private String getDescription(byte type) {
151 | if (type > 100) {
152 | return "[" + getDescription((byte) (type - 100));
153 | }
154 | switch (type) {
155 | case -1:
156 | return "";
157 | case 0:
158 | return "V";
159 | case 2:
160 | return "Ljava/lang/String;";
161 | case 3:
162 | return "Ljava/lang/Integer;";
163 | case 4:
164 | return "Ljava/lang/Class;";
165 | case 5:
166 | return "Ljava/lang/Boolean;";
167 | case 6:
168 | return "I";
169 | case 7:
170 | return "J";
171 | case 8:
172 | return "F";
173 | case 9:
174 | return "D";
175 | case 10:
176 | return "S";
177 | case 11:
178 | return "Z";
179 | case 12:
180 | return "C";
181 | case 13:
182 | return "B";
183 | default:
184 | return "Ljava/lang/Object;";
185 | }
186 | }
187 |
188 | public boolean hasInstructions(InsnList insnList, int... opcodes) {
189 | AbstractInsnNode[] abstractInsnNodes = insnList.toArray();
190 | if (opcodes.length > abstractInsnNodes.length) {
191 | return false;
192 | }
193 |
194 | int i = 0;
195 | for (int opcode : opcodes) {
196 | for (AbstractInsnNode ab : abstractInsnNodes) {
197 | if (ab.getOpcode() == opcode) {
198 | i++;
199 | }
200 | }
201 | }
202 | return i >= opcodes.length;
203 | }
204 |
205 | public boolean hasStrings(InsnList insnList, String... strings) {
206 | AbstractInsnNode[] abstractInsnNodes = insnList.toArray();
207 | if (strings.length > abstractInsnNodes.length) {
208 | return false;
209 | }
210 |
211 | int i = 0;
212 | for (String s : strings) {
213 | for (AbstractInsnNode ab : insnList.toArray()) {
214 | if (ab.getType() == AbstractInsnNode.LDC_INSN) {
215 | LdcInsnNode ldcInsnNode = (LdcInsnNode) ab;
216 | if (ldcInsnNode.cst.equals(s)) {
217 | i++;
218 | }
219 | }
220 | }
221 | }
222 | return i >= strings.length;
223 | }
224 |
225 | public static byte[] toByteArray(ClassNode classNode) {
226 | ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
227 | try {
228 | classNode.accept(writer);
229 | return writer.toByteArray();
230 | } catch (Throwable t) {
231 | writer = new ClassWriter(0);
232 | classNode.accept(writer);
233 | return writer.toByteArray();
234 | }
235 | }
236 |
237 | public int computeConstantPoolSize(ClassNode classNode) {
238 | return new ClassReader(toByteArray(classNode)).getItemCount();
239 | }
240 |
241 | public int addAccess(int access, int... add) {
242 | for (int a : add) {
243 | if ((access & a) == 0) {
244 | access |= a;
245 | }
246 | }
247 | return access;
248 | }
249 |
250 | public int removeAccess(int access, int... remove) {
251 | for (int r : remove) {
252 | if ((access & r) != 0) {
253 | access &= ~r;
254 | }
255 | }
256 | return access;
257 | }
258 |
259 | public int setAccess(int... add) {
260 | int access = 0;
261 | for (int a : add) {
262 | access |= a;
263 | }
264 | return access;
265 | }
266 |
267 | public boolean hasAccess(int access, int... check) {
268 | for (int a : check) {
269 | if ((access & a) == 0) {
270 | return false;
271 | }
272 | }
273 | return true;
274 | }
275 |
276 | public boolean isPublic(int access) {
277 | return (access & ACC_PUBLIC) != 0;
278 | }
279 |
280 | public boolean isProtected(int access) {
281 | return (access & ACC_PROTECTED) != 0;
282 | }
283 |
284 | public boolean isPrivate(int access) {
285 | return (access & ACC_PRIVATE) != 0;
286 | }
287 |
288 | public boolean isStatic(int access) {
289 | return (access & ACC_STATIC) != 0;
290 | }
291 |
292 | public boolean isStaticPhase(int access) {
293 | return (access & ACC_STATIC_PHASE) != 0;
294 | }
295 |
296 | public boolean isStrict(int access) {
297 | return (access & ACC_STRICT) != 0;
298 | }
299 |
300 | public boolean isSuper(int access) {
301 | return (access & ACC_SUPER) != 0;
302 | }
303 |
304 | public boolean isNative(int access) {
305 | return (access & ACC_NATIVE) != 0;
306 | }
307 |
308 | public boolean isMandated(int access) {
309 | return (access & ACC_MANDATED) != 0;
310 | }
311 |
312 | public boolean isModule(int access) {
313 | return (access & ACC_MODULE) != 0;
314 | }
315 |
316 | public boolean isOpen(int access) {
317 | return (access & ACC_OPEN) != 0;
318 | }
319 |
320 | public boolean isAbstract(int access) {
321 | return (access & ACC_ABSTRACT) != 0;
322 | }
323 |
324 | public boolean isFinal(int access) {
325 | return (access & ACC_FINAL) != 0;
326 | }
327 |
328 | public boolean isSynthetic(int access) {
329 | return (access & ACC_SYNTHETIC) != 0;
330 | }
331 |
332 | public boolean isTransient(int access) {
333 | return (access & ACC_TRANSIENT) != 0;
334 | }
335 |
336 | public boolean isTransitive(int access) {
337 | return (access & ACC_TRANSITIVE) != 0;
338 | }
339 |
340 | public boolean isVolatile(int access) {
341 | return (access & ACC_VOLATILE) != 0;
342 | }
343 |
344 | public boolean isVarargs(int access) {
345 | return (access & ACC_VARARGS) != 0;
346 | }
347 |
348 | public boolean isBridge(int access) {
349 | return (access & ACC_BRIDGE) != 0;
350 | }
351 |
352 | public boolean isSynchronized(int access) {
353 | return (access & ACC_SYNCHRONIZED) != 0;
354 | }
355 |
356 | public boolean isInterface(int access) {
357 | return (access & ACC_INTERFACE) != 0;
358 | }
359 |
360 | public boolean isEnum(int access) {
361 | return (access & ACC_ENUM) != 0;
362 | }
363 |
364 | public boolean isAnnotation(int access) {
365 | return (access & ACC_ANNOTATION) != 0;
366 | }
367 |
368 | public boolean isDeprecated(int access) {
369 | return (access & ACC_DEPRECATED) != 0;
370 | }
371 | }
--------------------------------------------------------------------------------