Skip to content

Commit 975a781

Browse files
committed
don't use jump predicting analyzer by default
1 parent 6b6fe5d commit 975a781

File tree

8 files changed

+107
-54
lines changed

8 files changed

+107
-54
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package uwu.narumi.deobfuscator.api.asm;
2+
3+
import org.objectweb.asm.tree.AbstractInsnNode;
4+
import org.objectweb.asm.tree.ClassNode;
5+
import org.objectweb.asm.tree.MethodNode;
6+
import org.objectweb.asm.tree.analysis.Frame;
7+
import org.objectweb.asm.tree.analysis.OriginalSourceValue;
8+
9+
import java.util.Map;
10+
11+
@FunctionalInterface
12+
public interface FramesProvider {
13+
Map<AbstractInsnNode, Frame<OriginalSourceValue>> compute(ClassNode classNode, MethodNode methodNode);
14+
}

deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/asm/MethodContext.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,15 @@ public InsnContext newInsnContext(AbstractInsnNode insn) {
5353
return new InsnContext(insn, this);
5454
}
5555

56+
public static MethodContext framed(ClassWrapper classWrapper, MethodNode methodNode) {
57+
return framed(classWrapper, methodNode, MethodHelper::analyzeSource);
58+
}
59+
5660
/**
5761
* Creates new {@link MethodContext} and computes its frames
5862
*/
59-
public static MethodContext framed(ClassWrapper classWrapper, MethodNode methodNode) {
60-
Map<AbstractInsnNode, Frame<OriginalSourceValue>> frames = MethodHelper.analyzeSource(classWrapper.classNode(), methodNode);
63+
public static MethodContext framed(ClassWrapper classWrapper, MethodNode methodNode, FramesProvider framesProvider) {
64+
Map<AbstractInsnNode, Frame<OriginalSourceValue>> frames = framesProvider.compute(classWrapper.classNode(), methodNode);
6165
return new MethodContext(classWrapper, methodNode, frames);
6266
}
6367

deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/helper/FramedInstructionsStream.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.objectweb.asm.tree.AbstractInsnNode;
55
import org.objectweb.asm.tree.MethodNode;
66
import uwu.narumi.deobfuscator.api.asm.ClassWrapper;
7+
import uwu.narumi.deobfuscator.api.asm.FramesProvider;
78
import uwu.narumi.deobfuscator.api.asm.InsnContext;
89
import uwu.narumi.deobfuscator.api.asm.MethodContext;
910
import uwu.narumi.deobfuscator.api.context.Context;
@@ -33,6 +34,7 @@ public static FramedInstructionsStream of(ClassWrapper scope, Context context) {
3334
private Function<Stream<ClassWrapper>, Stream<ClassWrapper>> classesStreamModifier = Function.identity();
3435
private Function<Stream<MethodNode>, Stream<MethodNode>> methodsStreamModifier = Function.identity();
3536
private Function<Stream<AbstractInsnNode>, Stream<AbstractInsnNode>> instructionsStreamModifier = Function.identity();
37+
private FramesProvider framesProvider = MethodHelper::analyzeSource;
3638
private boolean forceSync = false;
3739

3840
private FramedInstructionsStream(ClassWrapper scope, Context context) {
@@ -58,6 +60,12 @@ public FramedInstructionsStream editInstructionsStream(Function<Stream<AbstractI
5860
return this;
5961
}
6062

63+
@Contract("_ -> this")
64+
public FramedInstructionsStream framesProvider(FramesProvider framesProvider) {
65+
this.framesProvider = framesProvider;
66+
return this;
67+
}
68+
6169
@Contract(" -> this")
6270
public FramedInstructionsStream forceSync() {
6371
this.forceSync = true;
@@ -74,7 +82,7 @@ public void forEach(Consumer<InsnContext> consumer) {
7482
if (instructionsStreamModifier.apply(Arrays.stream(methodNode.instructions.toArray())).findAny().isEmpty()) return;
7583

7684
// Get frames of the method
77-
MethodContext methodContext = MethodContext.framed(classWrapper, methodNode);
85+
MethodContext methodContext = MethodContext.framed(classWrapper, methodNode, this.framesProvider);
7886

7987
// Iterate over instructions SYNC
8088
instructionsStreamModifier.apply(Arrays.stream(methodNode.instructions.toArray()))

deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/helper/MethodHelper.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,32 @@ public class MethodHelper implements Opcodes {
4040
@Unmodifiable
4141
public static Map<AbstractInsnNode, Frame<OriginalSourceValue>> analyzeSource(
4242
ClassNode classNode, MethodNode methodNode
43+
) {
44+
Map<AbstractInsnNode, Frame<OriginalSourceValue>> frames = new HashMap<>();
45+
Frame<OriginalSourceValue>[] framesArray;
46+
try {
47+
framesArray = new Analyzer<>(new OriginalSourceInterpreter()).analyze(classNode.name, methodNode);
48+
} catch (AnalyzerException e) {
49+
throw new RuntimeException("Error analyzing " + classNode.name + "#" + methodNode.name + methodNode.desc, e);
50+
}
51+
for (int i = 0; i < framesArray.length; i++) {
52+
frames.put(methodNode.instructions.get(i), framesArray[i]);
53+
}
54+
return Collections.unmodifiableMap(frames);
55+
}
56+
57+
/**
58+
* Analyzes the stack frames of the method using {@link OriginalSourceInterpreter}
59+
* and predicts jumps
60+
*
61+
* @param classNode The owner class
62+
* @param methodNode Method
63+
* @return A map which corresponds to: instruction -> its own stack frame
64+
*/
65+
@NotNull
66+
@Unmodifiable
67+
public static Map<AbstractInsnNode, Frame<OriginalSourceValue>> analyzeSourcePredictJumps(
68+
ClassNode classNode, MethodNode methodNode
4369
) {
4470
Map<AbstractInsnNode, Frame<OriginalSourceValue>> frames = new HashMap<>();
4571
Frame<OriginalSourceValue>[] framesArray;
@@ -71,7 +97,7 @@ public static Map<AbstractInsnNode, Frame<BasicValue>> analyzeBasic(
7197
try {
7298
framesArray = new Analyzer<>(new BasicInterpreter()).analyze(classNode.name, methodNode);
7399
} catch (AnalyzerException e) {
74-
throw new RuntimeException(e);
100+
throw new RuntimeException("Error analyzing " + classNode.name + "#" + methodNode.name + methodNode.desc, e);
75101
}
76102
for (int i = 0; i < framesArray.length; i++) {
77103
frames.put(methodNode.instructions.get(i), framesArray[i]);

deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/universal/UniversalFlowTransformer.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
public class UniversalFlowTransformer extends ComposedTransformer {
99
public UniversalFlowTransformer() {
1010
super(
11-
// Resolve all number operations in the first place
12-
UniversalNumberTransformer::new,
13-
1411
// Clean up redundant ifs and switches
1512
CleanRedundantJumpsTransformer::new,
1613
CleanRedundantSwitchesTransformer::new,
1714

15+
// Resolve all number operations
16+
UniversalNumberTransformer::new,
17+
1818
// Last thing will be to clean up all dead code that is unreachable
1919
DeadCodeCleanTransformer::new
2020
);

deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/universal/flow/CleanRedundantJumpsTransformer.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,34 @@
44
import org.objectweb.asm.tree.MethodNode;
55
import uwu.narumi.deobfuscator.api.helper.AsmMathHelper;
66
import uwu.narumi.deobfuscator.api.helper.FramedInstructionsStream;
7+
import uwu.narumi.deobfuscator.api.helper.MethodHelper;
78
import uwu.narumi.deobfuscator.api.transformer.Transformer;
89

910
import java.util.Optional;
1011

1112
public class CleanRedundantJumpsTransformer extends Transformer {
1213
@Override
1314
protected void transform() throws Exception {
14-
FramedInstructionsStream.of(this).forEach(insnContext -> {
15-
if (!(insnContext.insn() instanceof JumpInsnNode jumpInsn)) return;
15+
FramedInstructionsStream.of(this)
16+
.framesProvider(MethodHelper::analyzeSourcePredictJumps) // Predict jumps
17+
.forEach(insnContext -> {
18+
if (!(insnContext.insn() instanceof JumpInsnNode jumpInsn)) return;
1619

17-
Optional<Boolean> optIfResult = AsmMathHelper.predictIf(jumpInsn, insnContext.frame());
20+
Optional<Boolean> optIfResult = AsmMathHelper.predictIf(jumpInsn, insnContext.frame());
1821

19-
if (optIfResult.isEmpty()) return;
22+
if (optIfResult.isEmpty()) return;
2023

21-
boolean ifResult = optIfResult.get();
24+
boolean ifResult = optIfResult.get();
2225

23-
if (AsmMathHelper.isOneValueCondition(jumpInsn.getOpcode()) || AsmMathHelper.isTwoValuesCondition(jumpInsn.getOpcode())) {
24-
insnContext.placePops();
25-
}
26+
if (AsmMathHelper.isOneValueCondition(jumpInsn.getOpcode()) || AsmMathHelper.isTwoValuesCondition(jumpInsn.getOpcode())) {
27+
insnContext.placePops();
28+
}
2629

27-
// Replace if with corresponding GOTO or remove it
28-
processRedundantIfStatement(insnContext.methodNode(), jumpInsn, ifResult);
30+
// Replace if with corresponding GOTO or remove it
31+
processRedundantIfStatement(insnContext.methodNode(), jumpInsn, ifResult);
2932

30-
markChange();
31-
});
33+
markChange();
34+
});
3235
}
3336

3437
private void processRedundantIfStatement(MethodNode methodNode, JumpInsnNode ifStatement, boolean ifResult) {

deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/universal/flow/CleanRedundantSwitchesTransformer.java

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.objectweb.asm.tree.TableSwitchInsnNode;
77
import uwu.narumi.deobfuscator.api.helper.AsmMathHelper;
88
import uwu.narumi.deobfuscator.api.helper.FramedInstructionsStream;
9+
import uwu.narumi.deobfuscator.api.helper.MethodHelper;
910
import uwu.narumi.deobfuscator.api.transformer.Transformer;
1011

1112
import java.util.Optional;
@@ -17,34 +18,36 @@ public class CleanRedundantSwitchesTransformer extends Transformer {
1718

1819
@Override
1920
protected void transform() throws Exception {
20-
FramedInstructionsStream.of(this).forEach(insnContext -> {
21-
if (insnContext.insn().getOpcode() == LOOKUPSWITCH) {
22-
LookupSwitchInsnNode lookupSwitchInsn = (LookupSwitchInsnNode) insnContext.insn();
23-
24-
Optional<LabelNode> optPredictedJump = AsmMathHelper.predictLookupSwitch(lookupSwitchInsn, insnContext.frame());
25-
if (optPredictedJump.isEmpty()) return;
26-
27-
LabelNode predictedJump = optPredictedJump.get();
28-
// Remove value from stack
29-
insnContext.placePops();
30-
// Replace lookup switch with predicted jump
31-
insnContext.methodNode().instructions.set(lookupSwitchInsn, new JumpInsnNode(GOTO, predictedJump));
32-
33-
markChange();
34-
} else if (insnContext.insn().getOpcode() == TABLESWITCH) {
35-
TableSwitchInsnNode tableSwitchInsn = (TableSwitchInsnNode) insnContext.insn();
36-
37-
Optional<LabelNode> optPredictedJump = AsmMathHelper.predictTableSwitch(tableSwitchInsn, insnContext.frame());
38-
if (optPredictedJump.isEmpty()) return;
39-
40-
LabelNode predictedJump = optPredictedJump.get();
41-
// Remove value from stack
42-
insnContext.placePops();
43-
// Replace lookup switch with predicted jump
44-
insnContext.methodNode().instructions.set(tableSwitchInsn, new JumpInsnNode(GOTO, predictedJump));
45-
46-
markChange();
47-
}
48-
});
21+
FramedInstructionsStream.of(this)
22+
.framesProvider(MethodHelper::analyzeSourcePredictJumps) // Predict jumps
23+
.forEach(insnContext -> {
24+
if (insnContext.insn().getOpcode() == LOOKUPSWITCH) {
25+
LookupSwitchInsnNode lookupSwitchInsn = (LookupSwitchInsnNode) insnContext.insn();
26+
27+
Optional<LabelNode> optPredictedJump = AsmMathHelper.predictLookupSwitch(lookupSwitchInsn, insnContext.frame());
28+
if (optPredictedJump.isEmpty()) return;
29+
30+
LabelNode predictedJump = optPredictedJump.get();
31+
// Remove value from stack
32+
insnContext.placePops();
33+
// Replace lookup switch with predicted jump
34+
insnContext.methodNode().instructions.set(lookupSwitchInsn, new JumpInsnNode(GOTO, predictedJump));
35+
36+
markChange();
37+
} else if (insnContext.insn().getOpcode() == TABLESWITCH) {
38+
TableSwitchInsnNode tableSwitchInsn = (TableSwitchInsnNode) insnContext.insn();
39+
40+
Optional<LabelNode> optPredictedJump = AsmMathHelper.predictTableSwitch(tableSwitchInsn, insnContext.frame());
41+
if (optPredictedJump.isEmpty()) return;
42+
43+
LabelNode predictedJump = optPredictedJump.get();
44+
// Remove value from stack
45+
insnContext.placePops();
46+
// Replace lookup switch with predicted jump
47+
insnContext.methodNode().instructions.set(tableSwitchInsn, new JumpInsnNode(GOTO, predictedJump));
48+
49+
markChange();
50+
}
51+
});
4952
}
5053
}

testData/results/java/TestInlineLocalVariables.dec

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ public class TestInlineLocalVariables {
4040
System.out.println(1455.45 + (double)89.345F + "asd" + someObj);
4141

4242
try {
43-
double var12 = 3.4534535E7;
44-
4543
try {
4644
e = 45354.0F;
4745
f = "gfj";
@@ -50,11 +48,8 @@ public class TestInlineLocalVariables {
5048
} catch (Exception var10) {
5149
}
5250

53-
System.out.println(var12 + (double)e + f + someObj);
51+
System.out.println(3.4534535E7 + (double)e + f + someObj);
5452
} catch (Exception var11) {
55-
double d = 6.5654356234E7;
56-
e = 4.1454144E8F;
57-
f = "hjk";
5853
someObj = new Object();
5954
System.out.println("" + 56876758 + true + 5498489489L);
6055
System.out.println(6.5654356234E7 + (double)4.1454144E8F + "hjk" + someObj);

0 commit comments

Comments
 (0)