Skip to content

Commit 15cd04a

Browse files
committed
Enforce stricter rules for removing fields/methods
1 parent e91b6e2 commit 15cd04a

File tree

6 files changed

+72
-15
lines changed

6 files changed

+72
-15
lines changed

commonerrors/Radon.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
## RadonTransformer(V2)
2-
RadonTransformer was meant to work on the earlier versions of Radon, while RadonTransformerV2 works on the later versions. Use RadonTransformer first, and if it doesn't work, use RadonTransformerV2. Note that there are some settings in the transformer that you cannot configure without forking the project. Also, if your file has invokedynamic obfuscation, you should add all required libraries.
2+
RadonTransformer was meant to work on the earlier versions of Radon, while RadonTransformerV2 works on the later versions. Use RadonTransformer first, and if it doesn't work, use RadonTransformerV2. If the file was partially deobfuscated after running the transformer once, run it again. Also, if your file has invokedynamic obfuscation, you should add all required libraries.

commonerrors/Superblaubeere.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
## Superblaubeere27's Obfuscator
2-
One issue with this obfuscator is that it may inject local variables into the code, which prevents the file from being completely deobfuscated. In that case, use general.LocalVariableRemover, write to file, and then run the deobfuscator on the output. If you are still having issues with some features not being deobfuscated, use DeadCodeRemover and then RedundantGotoRemover to get rid of the junk code that may be in the way. Note that there are some settings which you cannot configure in this transformer without forking this project.
2+
One issue with this obfuscator is that it may inject local variables into the code, which prevents the file from being completely deobfuscated. In that case, use general.LocalVariableRemover, write to file, and then run the deobfuscator on the output. If you are still having issues with some features not being deobfuscated, use DeadCodeRemover and then RedundantGotoRemover to get rid of the junk code that may be in the way.

src/main/java/com/javadeobfuscator/deobfuscator/transformers/special/RadonTransformer.java

+15
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,21 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
231231
}
232232
}
233233
}
234+
classNodes().forEach(node -> node.methods.forEach(methodNode -> {
235+
for (AbstractInsnNode insn : methodNode.instructions) {
236+
if (insn.getOpcode() != Opcodes.GETSTATIC) {
237+
continue;
238+
}
239+
FieldInsnNode fn = (FieldInsnNode) insn;
240+
ClassNode owner = classes.get(fn.owner);
241+
if (owner == null) {
242+
continue;
243+
}
244+
FieldNode fNode = owner.fields.stream().filter(f -> f.name.equals(fn.name) && f.desc.equals(fn.desc)).findFirst().orElse(null);
245+
if(fakeFields.containsKey(owner))
246+
fakeFields.get(owner).remove(fNode);
247+
}
248+
}));
234249
fakeFields.entrySet().forEach(e -> e.getValue().forEach(f -> e.getKey().fields.remove(f)));
235250
if (getConfig().getNumberMode() == RadonConfig.NumberMode.LEGACY) {
236251
for (ClassNode classNode : classNodes()) {

src/main/java/com/javadeobfuscator/deobfuscator/transformers/special/RadonTransformerV2.java

+34-12
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
516516
}
517517
}
518518
}
519-
if (getConfig().isFlowObf()) {
519+
if (getConfig().isTryCatch()) {
520520
List<String> fakeExceptionClasses = new ArrayList<>();
521521
for (ClassNode classNode : classNodes()) {
522522
try {
@@ -559,9 +559,11 @@ && getDeobfuscator().isSubclass("java/lang/Throwable", classNode.name)) {
559559
classes.remove(s);
560560
classpath.remove(s);
561561
});
562+
}
563+
if (getConfig().isFlowObf()) {
564+
Map<ClassNode, Set<FieldNode>> remove = new HashMap<>();
562565
//Jumps
563566
for (ClassNode classNode : classNodes()) {
564-
List<FieldNode> remove = new ArrayList<>();
565567
for (MethodNode method : classNode.methods) {
566568
LinkedHashMap<LabelNode, List<AbstractInsnNode>> res = new FlowAnalyzer(method).analyze(method.instructions.getFirst(), Arrays.asList(),
567569
new HashMap<>(), true, true);
@@ -592,6 +594,9 @@ && getNextFollowGoto(ain, 3).getOpcode() == Opcodes.ATHROW) {
592594
modifier.remove(getNextFollowGoto(ain, 1));
593595
modifier.replace(ain, new JumpInsnNode(Opcodes.GOTO, ((JumpInsnNode) getNextFollowGoto(ain, 1)).label));
594596
flowObf.incrementAndGet();
597+
} else if (getNextFollowGoto(ain, 1) != null && getNextFollowGoto(ain, 1).getOpcode() == Opcodes.IFNE) {
598+
modifier.remove(getNextFollowGoto(ain, 1));
599+
modifier.remove(ain);
595600
} else {
596601
fail = true;
597602
break;
@@ -601,16 +606,13 @@ && getNextFollowGoto(ain, 3).getOpcode() == Opcodes.ATHROW) {
601606
}
602607
if (!fail) {
603608
modifier.apply(method);
604-
if (!remove.contains(field)) {
605-
remove.add(field);
606-
}
609+
remove.putIfAbsent(classNode, new HashSet<>());
610+
remove.get(classNode).add(field);
607611
}
608612
}
609-
remove.forEach(f -> classNode.fields.remove(f));
610613
}
611614
//2nd jump
612615
for (ClassNode classNode : classNodes()) {
613-
List<FieldNode> remove = new ArrayList<>();
614616
for (MethodNode method : classNode.methods) {
615617
LinkedHashMap<LabelNode, List<AbstractInsnNode>> res = new FlowAnalyzer(method).analyze(method.instructions.getFirst(), Arrays.asList(),
616618
new HashMap<>(), true, true);
@@ -664,9 +666,8 @@ && getNextFollowGoto(ain, 3).getOpcode() == Opcodes.ATHROW) {
664666
}
665667
if (pass) {
666668
modifier.apply(method);
667-
if (!remove.contains(field)) {
668-
remove.add(field);
669-
}
669+
remove.putIfAbsent(classNode, new HashSet<>());
670+
remove.get(classNode).add(field);
670671
}
671672
//Dead code
672673
InstructionModifier modifier2 = new InstructionModifier();
@@ -695,8 +696,24 @@ && getNextFollowGoto(ain, 3).getOpcode() == Opcodes.ATHROW) {
695696
}
696697
}
697698
}
698-
remove.forEach(f -> classNode.fields.remove(f));
699699
}
700+
classNodes().forEach(node -> node.methods.forEach(methodNode -> {
701+
for (AbstractInsnNode insn : methodNode.instructions) {
702+
if (insn.getOpcode() != Opcodes.GETSTATIC) {
703+
continue;
704+
}
705+
FieldInsnNode fn = (FieldInsnNode) insn;
706+
ClassNode owner = classes.get(fn.owner);
707+
if (owner == null) {
708+
continue;
709+
}
710+
FieldNode fNode = owner.fields.stream().filter(f -> f.name.equals(fn.name) && f.desc.equals(fn.desc)).findFirst().orElse(null);
711+
if(remove.containsKey(owner))
712+
remove.get(owner).remove(fNode);
713+
}
714+
}));
715+
for(Entry<ClassNode, Set<FieldNode>> entry : remove.entrySet())
716+
entry.getKey().fields.removeAll(entry.getValue());
700717
//BlockSplitter
701718
for (ClassNode classNode : classNodes()) {
702719
for (MethodNode method : classNode.methods) {
@@ -1139,7 +1156,12 @@ private void patchMethodString(ClassNode classNode) {
11391156
method.instructions.set(ain, new LdcInsnNode(4));
11401157
} else if (ain instanceof MethodInsnNode && ((MethodInsnNode) ain).name.equals("getRuntime")
11411158
&& ((MethodInsnNode) ain).owner.equals("java/lang/Runtime")) {
1142-
method.instructions.set(ain, new InsnNode(Opcodes.ACONST_NULL));
1159+
if(ain.getNext().getOpcode() == Opcodes.IFNULL)
1160+
{
1161+
method.instructions.remove(ain.getNext());
1162+
method.instructions.remove(ain);
1163+
}else
1164+
method.instructions.set(ain, new InsnNode(Opcodes.ACONST_NULL));
11431165
} else if (ain.getOpcode() == Opcodes.NEW
11441166
&& ((TypeInsnNode) ain).desc.equals("java/util/concurrent/atomic/AtomicInteger")) {
11451167
method.instructions.remove(Utils.getNext(ain));

src/main/java/com/javadeobfuscator/deobfuscator/transformers/special/RadonV2Config.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public class RadonV2Config extends TransformerConfig {
77
private boolean antiTamper = true;
88
private boolean ejector = true;
99
private boolean antiDebug = true;
10+
private boolean tryCatch = true;
1011
private boolean flowObf = true;
1112
private boolean stringPool = true;
1213
private boolean number = true;
@@ -41,6 +42,14 @@ public boolean isAntiDebug() {
4142
public void setAntiDebug(boolean antiDebug) {
4243
this.antiDebug = antiDebug;
4344
}
45+
46+
public boolean isTryCatch() {
47+
return tryCatch;
48+
}
49+
50+
public void setTryCatch(boolean tryCatch) {
51+
this.tryCatch = tryCatch;
52+
}
4453

4554
public boolean isFlowObf() {
4655
return flowObf;
@@ -49,7 +58,7 @@ public boolean isFlowObf() {
4958
public void setFlowObf(boolean flowObf) {
5059
this.flowObf = flowObf;
5160
}
52-
61+
5362
public boolean isStringPool() {
5463
return stringPool;
5564
}

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

+11
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ public class HideAccessObfuscationTransformer extends Transformer<HideAccessObfu
7070
public boolean transform() throws Throwable {
7171
List<ClassNode> decryptors = findDecryptClass();
7272
List<MethodNode> decryptMethods = new ArrayList<>();
73+
Set<ClassNode> failedClasses = new HashSet<>();
74+
Set<MethodNode> failedDecryptors = new HashSet<>();
7375

7476
AtomicInteger count = new AtomicInteger(0);
7577

@@ -156,6 +158,7 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
156158
System.out.println("Failed to decrypt invokedynamic call at class " + classNode.name
157159
+ " method " + methodNode.name + methodNode.desc);
158160
System.out.println(e.toString() + " @ " + e.getStackTrace()[0].toString());
161+
failedDecryptors.add(bootstrapMethod);
159162
continue;
160163
}else
161164
throw e;
@@ -225,6 +228,7 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
225228
System.out.println("Failed to decrypt invokespecial call at class " + classNode.name
226229
+ " method " + methodNode.name + methodNode.desc);
227230
System.out.println(e.toString() + " @ " + e.getStackTrace()[0].toString());
231+
failedClasses.add(classes.get(owner));
228232
continue;
229233
}else
230234
throw e;
@@ -364,6 +368,7 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
364368
System.out.println("Failed to decrypt encrypted method call at class " + classNode.name
365369
+ " method " + methodNode.name + methodNode.desc);
366370
System.out.println(e.toString() + " @ " + e.getStackTrace()[0].toString());
371+
failedClasses.add(classes.get(owner));
367372
continue;
368373
}else
369374
throw e;
@@ -425,6 +430,7 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
425430
System.out.println("Failed to decrypt getstatic call at class " + classNode.name
426431
+ " method " + methodNode.name + methodNode.desc);
427432
System.out.println(e.toString() + " @ " + e.getStackTrace()[0].toString());
433+
failedClasses.add(classes.get(owner));
428434
continue;
429435
}else
430436
throw e;
@@ -457,6 +463,7 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
457463
System.out.println("Failed to decrypt putstatic call at class " + classNode.name
458464
+ " method " + methodNode.name + methodNode.desc);
459465
System.out.println(e.toString() + " @ " + e.getStackTrace()[0].toString());
466+
failedClasses.add(classes.get(owner));
460467
continue;
461468
}else
462469
throw e;
@@ -489,6 +496,7 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
489496
System.out.println("Failed to decrypt getfield call at class " + classNode.name
490497
+ " method " + methodNode.name + methodNode.desc);
491498
System.out.println(e.toString() + " @ " + e.getStackTrace()[0].toString());
499+
failedClasses.add(classes.get(owner));
492500
continue;
493501
}else
494502
throw e;
@@ -522,6 +530,7 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
522530
System.out.println("Failed to decrypt putfield call at class " + classNode.name
523531
+ " method " + methodNode.name + methodNode.desc);
524532
System.out.println(e.toString() + " @ " + e.getStackTrace()[0].toString());
533+
failedClasses.add(classes.get(owner));
525534
continue;
526535
}else
527536
throw e;
@@ -543,6 +552,8 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
543552
}
544553
}));
545554
castFix(context);
555+
decryptors.removeAll(failedClasses);
556+
decryptMethods.removeAll(failedDecryptors);
546557
System.out.println("[Stringer] [HideAccessTransformer] Removed " + count.get() + " hide access");
547558
long cleanedup = cleanup(decryptors, decryptMethods);
548559
System.out.println("[Stringer] [HideAccessTransformer] Removed " + (cleanedup >> 32) + " decryptor classes");

0 commit comments

Comments
 (0)