Skip to content

Commit 6b8f49a

Browse files
committed
Update ZKM, Stringer, DeadCodeRemover
1 parent 7184777 commit 6b8f49a

File tree

5 files changed

+115
-52
lines changed

5 files changed

+115
-52
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@
2222
import com.javadeobfuscator.deobfuscator.Deobfuscator;
2323
import com.javadeobfuscator.deobfuscator.config.TransformerConfig;
2424
import com.javadeobfuscator.deobfuscator.exceptions.*;
25-
import org.objectweb.asm.ClassReader;
25+
import org.objectweb.asm.*;
2626
import org.objectweb.asm.tree.ClassNode;
2727
import org.objectweb.asm.tree.MethodNode;
2828
import org.slf4j.Logger;
2929
import org.slf4j.LoggerFactory;
3030

31-
public abstract class Transformer<T extends TransformerConfig> {
31+
public abstract class Transformer<T extends TransformerConfig> implements Opcodes {
3232

3333
protected Map<String, ClassNode> classes;
3434
protected Map<String, ClassNode> classpath;

src/main/java/com/javadeobfuscator/deobfuscator/transformers/general/peephole/DeadCodeRemover.java

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,44 +16,40 @@
1616

1717
package com.javadeobfuscator.deobfuscator.transformers.general.peephole;
1818

19-
import com.javadeobfuscator.deobfuscator.analyzer.MethodAnalyzer;
20-
import com.javadeobfuscator.deobfuscator.analyzer.frame.Frame;
21-
import com.javadeobfuscator.deobfuscator.config.TransformerConfig;
22-
import org.objectweb.asm.tree.AbstractInsnNode;
23-
import com.javadeobfuscator.deobfuscator.transformers.Transformer;
24-
import com.javadeobfuscator.deobfuscator.utils.Utils;
25-
26-
import java.util.Iterator;
27-
import java.util.List;
28-
import java.util.Map;
29-
import java.util.concurrent.atomic.AtomicInteger;
19+
import com.javadeobfuscator.deobfuscator.config.*;
20+
import com.javadeobfuscator.deobfuscator.transformers.*;
21+
import com.javadeobfuscator.deobfuscator.utils.*;
22+
import org.objectweb.asm.tree.*;
23+
import org.objectweb.asm.tree.analysis.*;
3024

3125
public class DeadCodeRemover extends Transformer<TransformerConfig> {
3226
@Override
3327
public boolean transform() throws Throwable {
34-
AtomicInteger deadInstructions = new AtomicInteger();
35-
classNodes().forEach(classNode -> {
36-
classNode.methods.stream().filter(methodNode -> methodNode.instructions.getFirst() != null).forEach(methodNode -> {
37-
if (methodNode.name.startsWith("DECRYPTOR_METHOD"))
38-
return;
39-
40-
Map<AbstractInsnNode, List<Frame>> f = MethodAnalyzer.analyze(classNode, methodNode).getFrames();
41-
Iterator<AbstractInsnNode> iterator = methodNode.instructions.iterator();
42-
while (iterator.hasNext()) {
43-
AbstractInsnNode next = iterator.next();
44-
if (Utils.isInstruction(next) && f.get(next) == null) {
45-
iterator.remove();
46-
deadInstructions.incrementAndGet();
47-
}
28+
int deadInstructions = 0;
29+
for (ClassNode classNode : classes.values()) {
30+
for (MethodNode methodNode : classNode.methods) {
31+
if (methodNode.instructions.getFirst() == null) continue;
32+
33+
InstructionModifier modifier = new InstructionModifier();
34+
35+
Frame<BasicValue>[] frames = new Analyzer<>(new BasicInterpreter()).analyze(classNode.name, methodNode);
36+
for (int i = 0; i < methodNode.instructions.size(); i++) {
37+
if (!Utils.isInstruction(methodNode.instructions.get(i))) continue;
38+
if (frames[i] != null) continue;
39+
40+
modifier.remove(methodNode.instructions.get(i));
41+
deadInstructions++;
4842
}
4943

44+
modifier.apply(methodNode);
45+
5046
// empty try catch nodes are illegal
5147
if (methodNode.tryCatchBlocks != null) {
5248
methodNode.tryCatchBlocks.removeIf(tryCatchBlockNode -> Utils.getNext(tryCatchBlockNode.start) == Utils.getNext(tryCatchBlockNode.end));
5349
}
54-
});
55-
});
56-
System.out.println("Removed " + deadInstructions.get() + " dead instructions");
57-
return deadInstructions.get() > 0;
50+
}
51+
}
52+
logger.info("Removed {} dead instructions", deadInstructions);
53+
return deadInstructions > 0;
5854
}
5955
}

src/main/java/com/javadeobfuscator/deobfuscator/transformers/stringer/InvokedynamicTransformer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ private int findInvokeDynamic() {
7373
AbstractInsnNode abstractInsnNode = methodNode.instructions.get(i);
7474
if (abstractInsnNode instanceof InvokeDynamicInsnNode) {
7575
InvokeDynamicInsnNode dyn = (InvokeDynamicInsnNode) abstractInsnNode;
76-
if (dyn.bsmArgs[0] instanceof String) {
76+
if (dyn.bsmArgs.length > 0 && dyn.bsmArgs[0] instanceof String) {
7777
total.incrementAndGet();
7878
}
7979
}

src/main/java/com/javadeobfuscator/deobfuscator/transformers/zelix/string/EnhancedStringEncryptionTransformer.java

Lines changed: 82 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,34 @@
1616

1717
package com.javadeobfuscator.deobfuscator.transformers.zelix.string;
1818

19+
import com.fasterxml.jackson.annotation.*;
20+
import com.google.common.base.*;
1921
import com.javadeobfuscator.deobfuscator.config.*;
2022
import com.javadeobfuscator.deobfuscator.exceptions.*;
21-
import com.javadeobfuscator.deobfuscator.executor.values.*;
2223
import com.javadeobfuscator.deobfuscator.matcher.*;
2324
import com.javadeobfuscator.deobfuscator.transformers.*;
2425
import com.javadeobfuscator.deobfuscator.utils.*;
2526
import com.javadeobfuscator.javavm.*;
2627
import com.javadeobfuscator.javavm.exceptions.*;
2728
import com.javadeobfuscator.javavm.mirrors.*;
2829
import com.javadeobfuscator.javavm.values.*;
29-
import com.javadeobfuscator.javavm.values.JavaArray;
3030
import org.objectweb.asm.*;
3131
import org.objectweb.asm.tree.*;
3232
import org.objectweb.asm.tree.analysis.*;
3333
import org.objectweb.asm.tree.analysis.Frame;
3434

3535
import java.util.*;
36-
import java.util.stream.*;
36+
import java.util.function.Supplier;
3737

3838
/**
3939
* This is a transformer for the enhanced version of Zelix string encryption
4040
*/
41-
public class EnhancedStringEncryptionTransformer extends Transformer<TransformerConfig> implements Opcodes {
41+
@TransformerConfig.ConfigOptions(configClass = EnhancedStringEncryptionTransformer.Config.class)
42+
public class EnhancedStringEncryptionTransformer extends Transformer<EnhancedStringEncryptionTransformer.Config> implements Opcodes {
4243
private static final InstructionPattern DECRYPT_PATTERN = new InstructionPattern(
4344
new LoadIntStep(),
4445
new LoadIntStep(),
45-
new InvocationStep(INVOKESTATIC, null, null, "(II)Ljava/lang/String;", false)
46+
new CapturingStep(new InvocationStep(INVOKESTATIC, null, null, "(II)Ljava/lang/String;", false), "invoke")
4647
);
4748

4849
@Override
@@ -54,25 +55,74 @@ public boolean transform() throws Throwable, WrongTransformerException {
5455
try {
5556
vm.initialize(JavaClass.forName(vm, classNode.name));
5657
} catch (VMException e) {
58+
JavaClass.forName(vm, classNode.name).setInitializationState(JavaClass.InitializationState.INITIALIZED, null); // of course we initialized it
5759
logger.debug("Exception while initializing {}, should be fine", classNode.name);
5860
logger.debug(vm.exceptionToString(e));
5961
} catch (Throwable e) {
62+
JavaClass.forName(vm, classNode.name).setInitializationState(JavaClass.InitializationState.INITIALIZED, null); // of course we initialized it
6063
logger.debug("(Severe) Exception while initializing {}, should be fine", classNode.name, e);
6164
}
65+
6266
for (MethodNode methodNode : new ArrayList<>(classNode.methods)) {
6367
InstructionModifier modifier = new InstructionModifier();
6468

69+
// If we want the slow version, memoize the analysis
70+
Supplier<Frame<SourceValue>[]> framesSupplier = Suppliers.memoize(() -> {
71+
try {
72+
return new Analyzer<>(new SourceInterpreter()).analyze(classNode.name, methodNode);
73+
} catch (AnalyzerException e) {
74+
oops("unexpected analyzer exception", e);
75+
return null;
76+
}
77+
})::get;
78+
6579
for (AbstractInsnNode insnNode : TransformerHelper.instructionIterator(methodNode)) {
66-
InstructionMatcher matcher = DECRYPT_PATTERN.matcher(insnNode);
67-
if (!matcher.find()) continue;
80+
AbstractInsnNode invocation;
81+
MethodNode decryptNode;
82+
83+
if (!getConfig().isSlowlyDetermineMagicNumbers()) {
84+
InstructionMatcher matcher = DECRYPT_PATTERN.matcher(insnNode);
85+
if (!matcher.find()) continue;
86+
87+
decryptNode = new MethodNode(ASM6, ACC_PUBLIC | ACC_STATIC, "Decryptor", "()Ljava/lang/String;", null, null);
88+
InsnList decryptInsns = new InsnList();
89+
for (AbstractInsnNode matched : matcher.getCapturedInstructions("all")) {
90+
decryptInsns.add(matched.clone(null));
91+
}
92+
decryptInsns.add(new InsnNode(ARETURN));
93+
decryptNode.instructions = decryptInsns;
94+
invocation = matcher.getCapturedInstruction("invoke");
95+
} else {
96+
if (insnNode.getOpcode() != INVOKESTATIC) continue;
97+
98+
MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode;
99+
if (!methodInsnNode.desc.equals("(II)Ljava/lang/String;")) continue;
100+
101+
Frame<SourceValue>[] frames = framesSupplier.get();
102+
if (frames == null) continue;
103+
104+
Frame<SourceValue> frame = frames[methodNode.instructions.indexOf(insnNode)];
105+
if (frame == null) continue;
106+
107+
SourceValue cst1 = frame.getStack(frame.getStackSize() - 2);
108+
SourceValue cst2 = frame.getStack(frame.getStackSize() - 1);
109+
if (cst1.insns.size() != 1) continue;
110+
if (cst2.insns.size() != 1) continue;
68111

69-
MethodNode decryptNode = new MethodNode(ASM6, ACC_PUBLIC | ACC_STATIC, "Decryptor", "()Ljava/lang/String;", null, null);
70-
InsnList decryptInsns = new InsnList();
71-
for (AbstractInsnNode matched : matcher.getCapturedInstructions("all")) {
72-
decryptInsns.add(matched.clone(null));
112+
AbstractInsnNode insn1 = cst1.insns.iterator().next();
113+
AbstractInsnNode insn2 = cst2.insns.iterator().next();
114+
if (insn1.getOpcode() != SIPUSH) continue;
115+
if (insn2.getOpcode() != SIPUSH) continue;
116+
117+
decryptNode = new MethodNode(ASM6, ACC_PUBLIC | ACC_STATIC, "Decryptor", "()Ljava/lang/String;", null, null);
118+
InsnList decryptInsns = new InsnList();
119+
decryptInsns.add(insn1.clone(null));
120+
decryptInsns.add(insn2.clone(null));
121+
decryptInsns.add(methodInsnNode.clone(null));
122+
decryptInsns.add(new InsnNode(ARETURN));
123+
decryptNode.instructions = decryptInsns;
124+
invocation = methodInsnNode;
73125
}
74-
decryptInsns.add(new InsnNode(ARETURN));
75-
decryptNode.instructions = decryptInsns;
76126

77127
JavaWrapper result;
78128

@@ -95,8 +145,7 @@ public boolean transform() throws Throwable, WrongTransformerException {
95145
String decrypted = vm.convertJavaObjectToString(result);
96146
logger.info("Decrypted string in {} {}{}: {}", classNode.name, methodNode.name, methodNode.desc, decrypted);
97147

98-
modifier.removeAll(matcher.getCapturedInstructions("all"));
99-
modifier.replace(matcher.getCapturedInstructions("all").get(0), new LdcInsnNode(decrypted));
148+
modifier.replace(invocation, new InsnNode(POP2), new LdcInsnNode(decrypted));
100149
}
101150

102151
modifier.apply(methodNode);
@@ -106,4 +155,22 @@ public boolean transform() throws Throwable, WrongTransformerException {
106155
vm.shutdown();
107156
return false;
108157
}
158+
159+
public static class Config extends TransformerConfig {
160+
161+
@JsonProperty("slowly-determine-magic-numbers")
162+
private boolean slowlyDetermineMagicNumbers;
163+
164+
public Config() {
165+
super(EnhancedStringEncryptionTransformer.class);
166+
}
167+
168+
public boolean isSlowlyDetermineMagicNumbers() {
169+
return slowlyDetermineMagicNumbers;
170+
}
171+
172+
public void setSlowlyDetermineMagicNumbers(boolean slowlyDetermineMagicNumbers) {
173+
this.slowlyDetermineMagicNumbers = slowlyDetermineMagicNumbers;
174+
}
175+
}
109176
}

src/main/java/com/javadeobfuscator/deobfuscator/utils/InstructionModifier.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616

1717
package com.javadeobfuscator.deobfuscator.utils;
1818

19-
import org.objectweb.asm.tree.AbstractInsnNode;
20-
import org.objectweb.asm.tree.InsnList;
21-
import org.objectweb.asm.tree.MethodNode;
19+
import org.objectweb.asm.tree.*;
2220

2321
import java.util.Collections;
2422
import java.util.HashMap;
@@ -42,9 +40,11 @@ public void prepend(AbstractInsnNode original, InsnList append) {
4240
prepends.put(original, append);
4341
}
4442

45-
public void replace(AbstractInsnNode original, AbstractInsnNode replacement) {
43+
public void replace(AbstractInsnNode original, AbstractInsnNode... insns) {
4644
InsnList singleton = new InsnList();
47-
singleton.add(replacement);
45+
for (AbstractInsnNode replacement : insns) {
46+
singleton.add(replacement);
47+
}
4848
replacements.put(original, singleton);
4949
}
5050

0 commit comments

Comments
 (0)