Skip to content

Commit d79b6c7

Browse files
committed
improvements
1 parent c434562 commit d79b6c7

2 files changed

Lines changed: 172 additions & 34 deletions

File tree

src/main/java/me/katze225/Obfuscator.java

Lines changed: 81 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33
import lombok.Getter;
44
import me.katze225.object.ObfuscatorSettings;
55
import me.katze225.transformer.ITransformer;
6-
import me.katze225.transformer.impl.*;
6+
import me.katze225.transformer.impl.BooleansTransformer;
7+
import me.katze225.transformer.impl.DispatcherTransformer;
8+
import me.katze225.transformer.impl.ExpressionTransformer;
9+
import me.katze225.transformer.impl.NumbersTransformer;
10+
import me.katze225.transformer.impl.ShuffleTransformer;
11+
import me.katze225.transformer.impl.StringTransformer;
712
import me.katze225.utility.StringUtility;
813
import org.objectweb.asm.ClassReader;
914
import org.objectweb.asm.ClassWriter;
10-
import org.objectweb.asm.Opcodes;
1115
import org.objectweb.asm.tree.ClassNode;
1216
import org.objectweb.asm.tree.MethodNode;
1317

@@ -135,10 +139,8 @@ private void writeOutput() throws IOException {
135139
inputJar.close();
136140

137141
for (ClassNode classNode : classes.values()) {
138-
if (classNode.version <= Opcodes.V1_5) {
139-
stripFrames(classNode);
140-
}
141-
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
142+
stripFrames(classNode);
143+
ClassWriter classWriter = new CustomClassWriter(ClassWriter.COMPUTE_MAXS);
142144
try {
143145
classNode.accept(classWriter);
144146
final JarEntry jarEntry = new JarEntry(classNode.name.concat(".class"));
@@ -182,4 +184,77 @@ private byte[] toByteArray(java.io.InputStream is) throws IOException {
182184
}
183185
return buffer.toByteArray();
184186
}
187+
188+
private class CustomClassWriter extends ClassWriter {
189+
public CustomClassWriter(int flags) {
190+
super(flags);
191+
}
192+
193+
@Override
194+
protected String getCommonSuperClass(String type1, String type2) {
195+
if (type1.equals(type2)) {
196+
return type1;
197+
}
198+
if (type1.equals("java/lang/Object") || type2.equals("java/lang/Object")) {
199+
return "java/lang/Object";
200+
}
201+
202+
ClassNode class1 = classes.get(type1);
203+
ClassNode class2 = classes.get(type2);
204+
205+
if (class1 == null || class2 == null) {
206+
try {
207+
return super.getCommonSuperClass(type1, type2);
208+
} catch (Exception e) {
209+
return "java/lang/Object";
210+
}
211+
}
212+
213+
if (isAssignableFrom(type1, type2)) {
214+
return type1;
215+
}
216+
if (isAssignableFrom(type2, type1)) {
217+
return type2;
218+
}
219+
220+
String current = class1.superName;
221+
while (current != null && !current.equals("java/lang/Object")) {
222+
if (isAssignableFrom(current, type2)) {
223+
return current;
224+
}
225+
ClassNode currentNode = classes.get(current);
226+
if (currentNode == null) {
227+
break;
228+
}
229+
current = currentNode.superName;
230+
}
231+
232+
return "java/lang/Object";
233+
}
234+
235+
private boolean isAssignableFrom(String type1, String type2) {
236+
if (type1.equals(type2)) {
237+
return true;
238+
}
239+
240+
ClassNode class2 = classes.get(type2);
241+
if (class2 == null) {
242+
return false;
243+
}
244+
245+
if (type1.equals(class2.superName)) {
246+
return true;
247+
}
248+
249+
if (class2.interfaces != null && class2.interfaces.contains(type1)) {
250+
return true;
251+
}
252+
253+
if (class2.superName != null) {
254+
return isAssignableFrom(type1, class2.superName);
255+
}
256+
257+
return false;
258+
}
259+
}
185260
}

src/main/java/me/katze225/transformer/impl/DispatcherTransformer.java

Lines changed: 91 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
import java.util.ArrayList;
44
import java.util.Comparator;
5+
import java.util.HashMap;
56
import java.util.HashSet;
67
import java.util.List;
8+
import java.util.Map;
79
import java.util.Set;
810

911
import org.objectweb.asm.Type;
@@ -77,20 +79,26 @@ public void modify(org.objectweb.asm.tree.ClassNode classNode) {
7779
continue;
7880
}
7981

82+
boolean inline = RANDOM.nextBoolean();
8083
String implName = nextUniqueName(used, method.desc);
8184
used.add(methodKey(implName, method.desc));
8285

83-
MethodNode impl = new MethodNode();
84-
impl.access = toImplAccess(method.access);
85-
impl.name = implName;
86-
impl.desc = method.desc;
87-
impl.signature = method.signature;
88-
impl.exceptions = method.exceptions;
89-
impl.instructions = method.instructions;
90-
impl.tryCatchBlocks = method.tryCatchBlocks;
91-
impl.localVariables = method.localVariables;
92-
impl.maxLocals = method.maxLocals;
93-
impl.maxStack = method.maxStack;
86+
InsnList originalInsn = method.instructions;
87+
88+
if (!inline) {
89+
MethodNode impl = new MethodNode();
90+
impl.access = toImplAccess(method.access);
91+
impl.name = implName;
92+
impl.desc = method.desc;
93+
impl.signature = method.signature;
94+
impl.exceptions = method.exceptions;
95+
impl.instructions = originalInsn;
96+
impl.tryCatchBlocks = method.tryCatchBlocks;
97+
impl.localVariables = method.localVariables;
98+
impl.maxLocals = method.maxLocals;
99+
impl.maxStack = method.maxStack;
100+
classNode.methods.add(impl);
101+
}
94102

95103
method.instructions = new InsnList();
96104
method.tryCatchBlocks = new ArrayList<>();
@@ -107,14 +115,12 @@ public void modify(org.objectweb.asm.tree.ClassNode classNode) {
107115

108116
Type returnType = Type.getReturnType(method.desc);
109117
Type[] argTypes = Type.getArgumentTypes(method.desc);
110-
DispatchEntry entry = new DispatchEntry(key, implName, method.desc, returnType, argTypes, isStatic);
118+
DispatchEntry entry = new DispatchEntry(key, implName, method.desc, returnType, argTypes, isStatic, inline, originalInsn);
111119
if (isStatic) {
112120
staticEntries.add(entry);
113121
} else {
114122
instanceEntries.add(entry);
115123
}
116-
117-
classNode.methods.add(impl);
118124
}
119125

120126
if (!instanceEntries.isEmpty()) {
@@ -152,20 +158,26 @@ private static MethodNode createDispatch(String name, boolean isStatic, List<Dis
152158
DispatchEntry entry = sorted.get(i);
153159
insn.add(labels[i]);
154160

155-
if (!entry.isStatic) {
156-
insn.add(new VarInsnNode(ALOAD, 0));
157-
}
158-
for (int argIndex = 0; argIndex < entry.argTypes.length; argIndex++) {
159-
Type argType = entry.argTypes[argIndex];
160-
insn.add(new VarInsnNode(ALOAD, argsIndex));
161-
insn.add(pushInt(argIndex));
162-
insn.add(new InsnNode(AALOAD));
163-
addUnbox(insn, argType);
161+
if (entry.inline) {
162+
InsnList inlinedCode = cloneInsnList(entry.insnList);
163+
remapVarsForInline(inlinedCode, entry.argTypes, entry.isStatic, argsIndex);
164+
insn.add(inlinedCode);
165+
} else {
166+
if (!entry.isStatic) {
167+
insn.add(new VarInsnNode(ALOAD, 0));
168+
}
169+
for (int argIndex = 0; argIndex < entry.argTypes.length; argIndex++) {
170+
Type argType = entry.argTypes[argIndex];
171+
insn.add(new VarInsnNode(ALOAD, argsIndex));
172+
insn.add(pushInt(argIndex));
173+
insn.add(new InsnNode(AALOAD));
174+
addUnbox(insn, argType);
175+
}
176+
177+
int invokeOp = entry.isStatic ? INVOKESTATIC : INVOKESPECIAL;
178+
insn.add(new MethodInsnNode(invokeOp, owner, entry.implName, entry.desc, false));
179+
addBoxOrNullReturn(insn, entry.returnType);
164180
}
165-
166-
int invokeOp = entry.isStatic ? INVOKESTATIC : INVOKESPECIAL;
167-
insn.add(new MethodInsnNode(invokeOp, owner, entry.implName, entry.desc, false));
168-
addBoxOrNullReturn(insn, entry.returnType);
169181
}
170182

171183
insn.add(defaultLabel);
@@ -341,22 +353,73 @@ private static int nextUniqueKey(Set<Integer> used) {
341353
return key;
342354
}
343355

356+
private static InsnList cloneInsnList(InsnList original) {
357+
InsnList clone = new InsnList();
358+
Map<LabelNode, LabelNode> labelMap = new HashMap<>();
359+
360+
for (AbstractInsnNode insn : original) {
361+
if (insn instanceof LabelNode) {
362+
LabelNode oldLabel = (LabelNode) insn;
363+
LabelNode newLabel = new LabelNode();
364+
labelMap.put(oldLabel, newLabel);
365+
}
366+
}
367+
368+
for (AbstractInsnNode insn : original) {
369+
clone.add(insn.clone(labelMap));
370+
}
371+
372+
return clone;
373+
}
374+
375+
private static void remapVarsForInline(InsnList insn, Type[] argTypes, boolean isStatic, int argsArrayIndex) {
376+
int originalVarBase = isStatic ? 0 : 1;
377+
378+
for (AbstractInsnNode node : insn) {
379+
if (node instanceof VarInsnNode) {
380+
VarInsnNode varNode = (VarInsnNode) node;
381+
int originalIndex = varNode.var;
382+
383+
if (!isStatic && originalIndex == 0) {
384+
continue;
385+
}
386+
387+
int argIndex = originalIndex - originalVarBase;
388+
if (argIndex >= 0 && argIndex < argTypes.length) {
389+
Type argType = argTypes[argIndex];
390+
InsnList replacement = new InsnList();
391+
replacement.add(new VarInsnNode(ALOAD, argsArrayIndex));
392+
replacement.add(pushInt(argIndex));
393+
replacement.add(new InsnNode(AALOAD));
394+
addUnbox(replacement, argType);
395+
396+
insn.insert(node, replacement);
397+
insn.remove(node);
398+
}
399+
}
400+
}
401+
}
402+
344403
private static final class DispatchEntry {
345404
private final int key;
346405
private final String implName;
347406
private final String desc;
348407
private final Type returnType;
349408
private final Type[] argTypes;
350409
private final boolean isStatic;
410+
private final boolean inline;
411+
private final InsnList insnList;
351412

352413
private DispatchEntry(int key, String implName, String desc, Type returnType, Type[] argTypes,
353-
boolean isStatic) {
414+
boolean isStatic, boolean inline, InsnList insnList) {
354415
this.key = key;
355416
this.implName = implName;
356417
this.desc = desc;
357418
this.returnType = returnType;
358419
this.argTypes = argTypes;
359420
this.isStatic = isStatic;
421+
this.inline = inline;
422+
this.insnList = insnList;
360423
}
361424
}
362425
}

0 commit comments

Comments
 (0)