Skip to content

Commit 56e6d9f

Browse files
authored
Migrate away from WrappedClassNode (#150)
1 parent ea924e3 commit 56e6d9f

File tree

50 files changed

+876
-1184
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+876
-1184
lines changed

src/main/java/com/javadeobfuscator/deobfuscator/Deobfuscator.java

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616

1717
package com.javadeobfuscator.deobfuscator;
1818

19+
import com.javadeobfuscator.deobfuscator.asm.ConstantPool;
1920
import com.javadeobfuscator.deobfuscator.config.Configuration;
2021
import com.javadeobfuscator.deobfuscator.config.TransformerConfig;
2122
import com.javadeobfuscator.deobfuscator.exceptions.NoClassInPathException;
2223
import com.javadeobfuscator.deobfuscator.transformers.Transformer;
2324
import com.javadeobfuscator.deobfuscator.utils.ClassTree;
2425
import com.javadeobfuscator.deobfuscator.utils.Utils;
25-
import com.javadeobfuscator.deobfuscator.utils.WrappedClassNode;
2626
import org.apache.commons.io.IOUtils;
2727
import org.objectweb.asm.ClassReader;
2828
import org.objectweb.asm.ClassWriter;
@@ -52,14 +52,17 @@
5252
import java.util.zip.ZipOutputStream;
5353

5454
public class Deobfuscator {
55-
private Map<String, WrappedClassNode> classpath = new HashMap<>();
56-
private Map<String, WrappedClassNode> classes = new HashMap<>();
55+
private Map<String, ClassNode> classpath = new HashMap<>();
56+
private Map<String, ClassNode> classes = new HashMap<>();
5757
private Map<String, ClassTree> hierachy = new HashMap<>();
5858
private Set<ClassNode> libraryClassnodes = new HashSet<>();
5959

6060
// Entries from the input jar that will be passed through to the output
6161
private Map<String, byte[]> inputPassthrough = new HashMap<>();
6262

63+
// Constant pool data since ClassNodes don't support custom data
64+
private Map<ClassNode, ConstantPool> constantPools = new HashMap<>();
65+
6366
private final Configuration configuration;
6467
private final Logger logger = LoggerFactory.getLogger(Deobfuscator.class);
6568

@@ -74,8 +77,20 @@ public Deobfuscator(Configuration configuration) {
7477
*/
7578
private static final boolean DELETE_USELESS_CLASSES = false;
7679

77-
private Map<String, WrappedClassNode> loadClasspathFile(File file) throws IOException {
78-
Map<String, WrappedClassNode> map = new HashMap<>();
80+
public ConstantPool getConstantPool(ClassNode classNode) {
81+
return this.constantPools.get(classNode);
82+
}
83+
84+
public void setConstantPool(ClassNode owner, ConstantPool pool) {
85+
this.constantPools.put(owner, pool);
86+
}
87+
88+
public Map<ClassNode, ConstantPool> getConstantPools() {
89+
return this.constantPools;
90+
}
91+
92+
private Map<String, ClassNode> loadClasspathFile(File file) throws IOException {
93+
Map<String, ClassNode> map = new HashMap<>();
7994

8095
ZipFile zipIn = new ZipFile(file);
8196
Enumeration<? extends ZipEntry> entries = zipIn.entries();
@@ -85,8 +100,9 @@ private Map<String, WrappedClassNode> loadClasspathFile(File file) throws IOExce
85100
ClassReader reader = new ClassReader(zipIn.getInputStream(ent));
86101
ClassNode node = new ClassNode();
87102
reader.accept(node, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
88-
WrappedClassNode wrappedClassNode = new WrappedClassNode(node, reader.getItemCount());
89-
map.put(node.name, wrappedClassNode);
103+
map.put(node.name, node);
104+
105+
setConstantPool(node, new ConstantPool(reader));
90106
}
91107
}
92108
zipIn.close();
@@ -108,7 +124,7 @@ private void loadClasspath() throws IOException {
108124
}
109125
}
110126
}
111-
libraryClassnodes.addAll(classpath.values().stream().map(WrappedClassNode::getClassNode).collect(Collectors.toList()));
127+
libraryClassnodes.addAll(classpath.values());
112128
}
113129
}
114130

@@ -152,6 +168,8 @@ private void loadInput() throws IOException {
152168
ClassNode node = new ClassNode();
153169
reader.accept(node, ClassReader.SKIP_FRAMES);
154170

171+
setConstantPool(node, new ConstantPool(reader));
172+
155173
if (!isClassIgnored(node)) {
156174
for (int i = 0; i < node.methods.size(); i++) {
157175
MethodNode methodNode = node.methods.get(i);
@@ -160,11 +178,10 @@ private void loadInput() throws IOException {
160178
node.methods.set(i, adapter);
161179
}
162180

163-
WrappedClassNode wr = new WrappedClassNode(node, reader.getItemCount());
164-
classes.put(node.name, wr);
181+
classes.put(node.name, node);
165182
passthrough = false;
166183
} else {
167-
classpath.put(node.name, new WrappedClassNode(node, reader.getItemCount()));
184+
classpath.put(node.name, node);
168185
}
169186
} catch (IllegalArgumentException x) {
170187
logger.error("Could not parse {} (is it a class file?)", next.getName(), x);
@@ -185,18 +202,18 @@ private void loadInput() throws IOException {
185202
*/
186203
@Deprecated
187204
private void computeCallers() {
188-
Map<MethodNode, List<Entry<WrappedClassNode, MethodNode>>> callers = new HashMap<>();
189-
classes.values().forEach(wrappedClassNode -> {
190-
wrappedClassNode.classNode.methods.forEach(methodNode -> {
205+
Map<MethodNode, List<Entry<ClassNode, MethodNode>>> callers = new HashMap<>();
206+
classes.values().forEach(classNode -> {
207+
classNode.methods.forEach(methodNode -> {
191208
for (int i = 0; i < methodNode.instructions.size(); i++) {
192209
AbstractInsnNode node = methodNode.instructions.get(i);
193210
if (node instanceof MethodInsnNode) {
194211
MethodInsnNode mn = (MethodInsnNode) node;
195-
WrappedClassNode targetNode = classes.get(mn.owner);
212+
ClassNode targetNode = classes.get(mn.owner);
196213
if (targetNode != null) {
197-
MethodNode targetMethod = targetNode.classNode.methods.stream().filter(m -> m.name.equals(mn.name) && m.desc.equals(mn.desc)).findFirst().orElse(null);
214+
MethodNode targetMethod = targetNode.methods.stream().filter(m -> m.name.equals(mn.name) && m.desc.equals(mn.desc)).findFirst().orElse(null);
198215
if (targetMethod != null) {
199-
callers.computeIfAbsent(targetMethod, k -> new ArrayList<>()).add(new SimpleEntry<>(wrappedClassNode, methodNode));
216+
callers.computeIfAbsent(targetMethod, k -> new ArrayList<>()).add(new SimpleEntry<>(classNode, methodNode));
200217
}
201218
}
202219
}
@@ -229,7 +246,7 @@ public void start() throws Throwable {
229246

230247
logger.info("Writing");
231248
if (DEBUG) {
232-
classes.values().stream().map(wrappedClassNode -> wrappedClassNode.classNode).forEach(Utils::printClass);
249+
classes.values().forEach(Utils::printClass);
233250
}
234251

235252
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(configuration.getOutput()));
@@ -244,7 +261,7 @@ public void start() throws Throwable {
244261
}
245262
});
246263

247-
classes.values().stream().map(wrappedClassNode -> wrappedClassNode.classNode).forEach(classNode -> {
264+
classes.values().forEach(classNode -> {
248265
try {
249266
byte[] b = toByteArray(classNode);
250267
if (b != null) {
@@ -267,27 +284,27 @@ public boolean runFromConfig(TransformerConfig config) throws Throwable {
267284
}
268285

269286
public ClassNode assureLoaded(String ref) {
270-
WrappedClassNode clazz = classpath.get(ref);
287+
ClassNode clazz = classpath.get(ref);
271288
if (clazz == null) {
272289
throw new NoClassInPathException(ref);
273290
}
274-
return clazz.classNode;
291+
return clazz;
275292
}
276293

277294
public ClassNode assureLoadedElseRemove(String referencer, String ref) {
278-
WrappedClassNode clazz = classpath.get(ref);
295+
ClassNode clazz = classpath.get(ref);
279296
if (clazz == null) {
280297
classes.remove(referencer);
281298
classpath.remove(referencer);
282299
return null;
283300
}
284-
return clazz.classNode;
301+
return clazz;
285302
}
286303

287304
public void loadHierachy() {
288305
Set<String> processed = new HashSet<>();
289306
LinkedList<ClassNode> toLoad = new LinkedList<>();
290-
toLoad.addAll(this.classes.values().stream().map(wrappedClassNode -> wrappedClassNode.classNode).collect(Collectors.toList()));
307+
toLoad.addAll(this.classes.values());
291308
while (!toLoad.isEmpty()) {
292309
for (ClassNode toProcess : loadHierachy(toLoad.poll())) {
293310
if (processed.add(toProcess.name)) {

src/main/java/com/javadeobfuscator/deobfuscator/analyzer/MethodAnalyzer.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@
4343
import org.objectweb.asm.tree.TypeInsnNode;
4444
import org.objectweb.asm.tree.VarInsnNode;
4545
import com.javadeobfuscator.deobfuscator.utils.PrimitiveUtils;
46-
import com.javadeobfuscator.deobfuscator.utils.Utils;
47-
import com.javadeobfuscator.deobfuscator.utils.WrappedClassNode;
4846

4947
import java.lang.reflect.Modifier;
5048
import java.util.AbstractMap;
@@ -221,11 +219,6 @@
221219
public class MethodAnalyzer {
222220
private static final boolean DEBUG = false;
223221

224-
@Deprecated
225-
public static AnalyzerResult analyze(WrappedClassNode classNode, MethodNode method) {
226-
return analyze(classNode.classNode, method);
227-
}
228-
229222
public static AnalyzerResult analyze(ClassNode classNode, MethodNode method) {
230223
if (Modifier.isAbstract(method.access) || Modifier.isNative(method.access)) {
231224
return AnalyzerResult.EMPTY_RESULT;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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.asm;
18+
19+
import org.objectweb.asm.ClassReader;
20+
21+
public class ConstantPool {
22+
private final ClassReader classReader;
23+
24+
// todo load constants lazily (to prevent abuse with large constant pools)
25+
public ConstantPool(ClassReader classReader) {
26+
this.classReader = classReader;
27+
}
28+
29+
public int getSize() {
30+
return this.classReader.getItemCount();
31+
}
32+
}

src/main/java/com/javadeobfuscator/deobfuscator/executor/Context.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package com.javadeobfuscator.deobfuscator.executor;
22

3+
import com.javadeobfuscator.deobfuscator.asm.ConstantPool;
34
import com.javadeobfuscator.deobfuscator.executor.providers.Provider;
45
import com.javadeobfuscator.deobfuscator.executor.values.JavaValue;
56
import org.objectweb.asm.tree.AbstractInsnNode;
6-
import com.javadeobfuscator.deobfuscator.utils.WrappedClassNode;
7+
import org.objectweb.asm.tree.ClassNode;
78

89
import java.io.File;
910
import java.util.*;
@@ -13,7 +14,8 @@ public class Context { //FIXME clinit classes
1314
private List<StackTraceElement> context = new ArrayList<>();
1415

1516
public Provider provider;
16-
public Map<String, WrappedClassNode> dictionary;
17+
public Map<String, ClassNode> dictionary;
18+
public Map<ClassNode, ConstantPool> constantPools;
1719

1820
public Set<String> clinit = new HashSet<>();
1921

src/main/java/com/javadeobfuscator/deobfuscator/executor/MethodExecutor.java

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.function.BiFunction;
2525

2626
import com.google.common.base.Optional;
27+
import com.javadeobfuscator.deobfuscator.asm.ConstantPool;
2728
import com.javadeobfuscator.deobfuscator.executor.defined.types.JavaClass;
2829
import com.javadeobfuscator.deobfuscator.executor.exceptions.*;
2930
import com.javadeobfuscator.deobfuscator.executor.values.JavaAddress;
@@ -42,7 +43,6 @@
4243
import org.objectweb.asm.tree.*;
4344
import com.javadeobfuscator.deobfuscator.utils.PrimitiveUtils;
4445
import com.javadeobfuscator.deobfuscator.utils.Utils;
45-
import com.javadeobfuscator.deobfuscator.utils.WrappedClassNode;
4646

4747
public class MethodExecutor {
4848
private static final boolean VERIFY;
@@ -59,7 +59,7 @@ public class MethodExecutor {
5959
DEBUG_METHODS_WITH_DESC = Arrays.asList();
6060
}
6161

62-
public static <T> T execute(WrappedClassNode classNode, MethodNode method, List<JavaValue> args, Object instance, Context context) {
62+
public static <T> T execute(ClassNode classNode, MethodNode method, List<JavaValue> args, Object instance, Context context) {
6363
if (context == null)
6464
throw new IllegalArgumentException("Null context");
6565
List<JavaValue> stack = new LinkedList<>();
@@ -326,15 +326,15 @@ private static void doFloatMathReturnInteger(List<JavaValue> stack, BiFunction<F
326326
/*
327327
* Main executor. This will go through each instruction and execute the instruction using a switch statement
328328
*/
329-
private static <T> T execute(WrappedClassNode classNode, MethodNode method, AbstractInsnNode now, List<JavaValue> stack, List<JavaValue> locals, Context context) {
330-
context.push(classNode.classNode.name, method.name, classNode.constantPoolSize);
329+
private static <T> T execute(ClassNode classNode, MethodNode method, AbstractInsnNode now, List<JavaValue> stack, List<JavaValue> locals, Context context) {
330+
context.push(classNode.name, method.name, 0); // constantPoolSize isn't even used, is it?
331331
if (DEBUG) {
332-
System.out.println("Executing " + classNode.classNode.name + " " + method.name + method.desc);
332+
System.out.println("Executing " + classNode.name + " " + method.name + method.desc);
333333
}
334334
forever:
335335
while (true) {
336336
try {
337-
if (DEBUG && (DEBUG_CLASSES.isEmpty() || DEBUG_CLASSES.contains(classNode.classNode.name)) && (DEBUG_METHODS_WITH_DESC.isEmpty() || DEBUG_METHODS_WITH_DESC.contains(method.name + method.desc))) {
337+
if (DEBUG && (DEBUG_CLASSES.isEmpty() || DEBUG_CLASSES.contains(classNode.name)) && (DEBUG_METHODS_WITH_DESC.isEmpty() || DEBUG_METHODS_WITH_DESC.contains(method.name + method.desc))) {
338338
System.out.println("\t Stack: " + stack);
339339
System.out.println("\t Locals: " + locals);
340340
System.out.println();
@@ -1118,9 +1118,8 @@ private static <T> T execute(WrappedClassNode classNode, MethodNode method, Abst
11181118
}
11191119
break;
11201120
} catch (NoSuchMethodHandlerException | IllegalArgumentException t) {
1121-
WrappedClassNode ownerWrappedClass = context.dictionary.get(owner);
1122-
if (ownerWrappedClass != null) {
1123-
ClassNode ownerClass = ownerWrappedClass.classNode;
1121+
ClassNode ownerClass = context.dictionary.get(owner);
1122+
if (ownerClass != null) {
11241123
if (ownerClass.superName != null) {
11251124
owner = ownerClass.superName;
11261125
continue;
@@ -1187,9 +1186,8 @@ private static <T> T execute(WrappedClassNode classNode, MethodNode method, Abst
11871186
}
11881187
break;
11891188
} catch (NoSuchMethodHandlerException | IllegalArgumentException t) {
1190-
WrappedClassNode ownerWrappedClass = context.dictionary.get(owner);
1191-
if (ownerWrappedClass != null) {
1192-
ClassNode ownerClass = ownerWrappedClass.classNode;
1189+
ClassNode ownerClass = context.dictionary.get(owner);
1190+
if (ownerClass != null) {
11931191
if (ownerClass.superName != null) {
11941192
owner = ownerClass.superName;
11951193
continue;
@@ -1478,9 +1476,8 @@ private static <T> T execute(WrappedClassNode classNode, MethodNode method, Abst
14781476
now = tcbn.handler;
14791477
continue forever;
14801478
} else {
1481-
WrappedClassNode wr = context.dictionary.get(Type.getType(toThrow.getClass()).getInternalName());
1482-
if (wr.classNode != null) {
1483-
ClassNode cn = wr.classNode;
1479+
ClassNode cn = context.dictionary.get(Type.getType(toThrow.getClass()).getInternalName());
1480+
if (cn != null) {
14841481
boolean ok = false;
14851482
while (cn != null) {
14861483
if (cn.name.equals(tcbn.type)) {
@@ -1490,10 +1487,7 @@ private static <T> T execute(WrappedClassNode classNode, MethodNode method, Abst
14901487
if (cn.superName == null) {
14911488
break;
14921489
}
1493-
wr = context.dictionary.get(cn.superName);
1494-
if (wr != null) {
1495-
cn = wr.classNode;
1496-
}
1490+
cn = context.dictionary.get(cn.superName);
14971491
}
14981492
if (ok) {
14991493
stack.clear();
@@ -1511,7 +1505,7 @@ private static <T> T execute(WrappedClassNode classNode, MethodNode method, Abst
15111505
now = now.getNext();
15121506
} catch (ExecutionException e) {
15131507
if (e.clazz.isEmpty()) {
1514-
e.clazz = classNode.classNode.name;
1508+
e.clazz = classNode.name;
15151509
e.method = method.name + method.desc;
15161510
}
15171511
throw e;
@@ -1528,9 +1522,8 @@ private static <T> T execute(WrappedClassNode classNode, MethodNode method, Abst
15281522
now = tcbn.handler;
15291523
continue forever;
15301524
} else {
1531-
WrappedClassNode wr = context.dictionary.get(Type.getType(t.getClass()).getInternalName());
1532-
if (wr.classNode != null) {
1533-
ClassNode cn = wr.classNode;
1525+
ClassNode cn = context.dictionary.get(Type.getType(t.getClass()).getInternalName());
1526+
if (cn != null) {
15341527
boolean ok = false;
15351528
while (cn != null) {
15361529
if (cn.name.equals(tcbn.type)) {
@@ -1540,10 +1533,7 @@ private static <T> T execute(WrappedClassNode classNode, MethodNode method, Abst
15401533
if (cn.superName == null) {
15411534
break;
15421535
}
1543-
wr = context.dictionary.get(cn.superName);
1544-
if (wr != null) {
1545-
cn = wr.classNode;
1546-
}
1536+
cn = context.dictionary.get(cn.superName);
15471537
}
15481538
if (ok) {
15491539
stack.clear();

0 commit comments

Comments
 (0)