Skip to content

Commit d418cbe

Browse files
authored
Implement SkidSuite2 transformer (#143)
1 parent 978fa4f commit d418cbe

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed

src/main/java/com/javadeobfuscator/deobfuscator/transformers/Transformers.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ public static class Zelix {
6060
public static final Class<? extends Transformer> FLOW_OBFUSCATION = com.javadeobfuscator.deobfuscator.transformers.zelix.FlowObfuscationTransformer.class;
6161
}
6262

63+
public static class SkidSuite {
64+
public static final Class<? extends Transformer> STRING_ENCRYPTION = com.javadeobfuscator.deobfuscator.transformers.skidsuite2.StringEncryptionTransformer.class;
65+
}
66+
6367
public static class Normalizer {
6468
public static final Class<? extends Transformer> PACKAGE_NORMALIZER = com.javadeobfuscator.deobfuscator.transformers.normalizer.PackageNormalizer.class;
6569
public static final Class<? extends Transformer> CLASS_NORMALIZER = com.javadeobfuscator.deobfuscator.transformers.normalizer.ClassNormalizer.class;
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/*
2+
* Copyright 2017 Sam Sun <[email protected]>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.javadeobfuscator.deobfuscator.transformers.skidsuite2;
18+
19+
import com.javadeobfuscator.deobfuscator.analyzer.AnalyzerResult;
20+
import com.javadeobfuscator.deobfuscator.analyzer.MethodAnalyzer;
21+
import com.javadeobfuscator.deobfuscator.analyzer.frame.*;
22+
import com.javadeobfuscator.deobfuscator.config.TransformerConfig;
23+
import com.javadeobfuscator.deobfuscator.executor.Context;
24+
import com.javadeobfuscator.deobfuscator.executor.MethodExecutor;
25+
import com.javadeobfuscator.deobfuscator.executor.defined.JVMComparisonProvider;
26+
import com.javadeobfuscator.deobfuscator.executor.defined.JVMMethodProvider;
27+
import com.javadeobfuscator.deobfuscator.executor.providers.DelegatingProvider;
28+
import com.javadeobfuscator.deobfuscator.executor.values.JavaInteger;
29+
import com.javadeobfuscator.deobfuscator.executor.values.JavaObject;
30+
import com.javadeobfuscator.deobfuscator.executor.values.JavaValue;
31+
import com.javadeobfuscator.deobfuscator.transformers.Transformer;
32+
import org.objectweb.asm.Opcodes;
33+
import org.objectweb.asm.tree.*;
34+
35+
import java.util.ArrayList;
36+
import java.util.HashMap;
37+
import java.util.List;
38+
import java.util.Map;
39+
import java.util.concurrent.atomic.AtomicInteger;
40+
41+
// I can't believe this has to exist
42+
public class StringEncryptionTransformer extends Transformer<TransformerConfig> {
43+
@Override
44+
public boolean transform() throws Throwable {
45+
46+
AtomicInteger counter = new AtomicInteger();
47+
48+
DelegatingProvider provider = new DelegatingProvider();
49+
provider.register(new JVMMethodProvider());
50+
provider.register(new JVMComparisonProvider());
51+
52+
classNodes().forEach(wrappedClassNode -> {
53+
wrappedClassNode.classNode.methods.forEach(methodNode -> {
54+
AnalyzerResult result = MethodAnalyzer.analyze(wrappedClassNode.classNode, methodNode);
55+
56+
Map<AbstractInsnNode, InsnList> replacements = new HashMap<>();
57+
58+
insns:
59+
for (int index = 0; index < methodNode.instructions.size(); index++) {
60+
AbstractInsnNode current = methodNode.instructions.get(index);
61+
if (!(current instanceof MethodInsnNode))
62+
continue;
63+
64+
MethodInsnNode methodInsnNode = (MethodInsnNode) current;
65+
if (methodInsnNode.getOpcode() != Opcodes.INVOKESTATIC)
66+
continue;
67+
68+
if (!methodInsnNode.desc.equals("([CLjava/lang/String;I)Ljava/lang/String;"))
69+
continue;
70+
71+
MethodFrame frame = (MethodFrame) result.getFrames().get(methodInsnNode).get(0);
72+
73+
List<JavaValue> args = new ArrayList<>();
74+
Map<AbstractInsnNode, InsnList> localReplacements = new HashMap<>();
75+
76+
for (Frame arg : frame.getArgs()) {
77+
if (arg instanceof LdcFrame) {
78+
Object cst = ((LdcFrame) arg).getConstant();
79+
if (cst == null) {
80+
continue insns;
81+
}
82+
if (cst instanceof String) {
83+
args.add(new JavaObject(cst, "java/lang/String"));
84+
} else {
85+
args.add(new JavaInteger(((Number) cst).intValue()));
86+
}
87+
} else if (arg instanceof NewArrayFrame) {
88+
NewArrayFrame newArrayFrame = (NewArrayFrame) arg;
89+
90+
{
91+
InsnList list = new InsnList();
92+
list.add(new InsnNode(Opcodes.POP));
93+
list.add(new InsnNode(Opcodes.ACONST_NULL));
94+
localReplacements.put(result.getMapping().get(newArrayFrame), list);
95+
}
96+
97+
if (newArrayFrame.getLength() instanceof LdcFrame) {
98+
char[] arr = new char[((Number) ((LdcFrame) newArrayFrame.getLength()).getConstant()).intValue()];
99+
JavaObject obj = new JavaObject(arr, "[C");
100+
for (Frame child0 : arg.getChildren()) {
101+
if (child0 instanceof ArrayStoreFrame) {
102+
ArrayStoreFrame arrayStoreFrame = (ArrayStoreFrame) child0;
103+
if (arrayStoreFrame.getIndex() instanceof LdcFrame && arrayStoreFrame.getObject() instanceof LdcFrame) {
104+
{
105+
InsnList list = new InsnList();
106+
list.add(new InsnNode(Opcodes.POP2));
107+
list.add(new InsnNode(Opcodes.POP));
108+
localReplacements.put(result.getMapping().get(arrayStoreFrame), list);
109+
}
110+
arr[((Number) ((LdcFrame) arrayStoreFrame.getIndex()).getConstant()).intValue()] = (char) ((Number) ((LdcFrame) arrayStoreFrame.getObject()).getConstant()).intValue();
111+
} else {
112+
continue insns;
113+
}
114+
}
115+
}
116+
args.add(obj);
117+
} else {
118+
continue insns;
119+
}
120+
}
121+
}
122+
123+
if (classes.containsKey(methodInsnNode.owner)) {
124+
Context context = new Context(provider);
125+
context.push(wrappedClassNode.classNode.name, methodNode.name, wrappedClassNode.constantPoolSize);
126+
ClassNode innerClassNode = classes.get(methodInsnNode.owner).classNode;
127+
MethodNode decrypterNode = innerClassNode.methods.stream().filter(mn -> mn.name.equals(methodInsnNode.name) && mn.desc.equals(methodInsnNode.desc)).findFirst().orElse(null);
128+
try {
129+
Object o = MethodExecutor.execute(wrappedClassNode, decrypterNode, args, null, context);
130+
InsnList list = new InsnList();
131+
for (int i = 0; i < args.size(); i++) {
132+
list.add(new InsnNode(Opcodes.POP));
133+
}
134+
list.add(new LdcInsnNode(o));
135+
methodNode.instructions.insertBefore(methodInsnNode, list);
136+
methodNode.instructions.remove(methodInsnNode);
137+
replacements.putAll(localReplacements);
138+
counter.getAndIncrement();
139+
} catch (Throwable t) {
140+
System.out.println("Error while decrypting string. " + methodInsnNode.owner + " " + methodInsnNode.name + methodInsnNode.desc);
141+
t.printStackTrace(System.out);
142+
}
143+
}
144+
}
145+
146+
replacements.forEach((k, v) -> {
147+
methodNode.instructions.insertBefore(k, v);
148+
methodNode.instructions.remove(k);
149+
});
150+
});
151+
});
152+
153+
System.out.println("[SkidSuite2] [StringEncryptionTransformer] Decrypted " + counter + " strings");
154+
return true;
155+
}
156+
}

0 commit comments

Comments
 (0)