Skip to content

Commit 7773f21

Browse files
SkidFuscator 2.0.11 Community (#119)
* Branchlock salting complete * SkidFuscator * Flow, undone * Fix string decryption for non-flow jars * API * SkidFuscator's FlowTry-Catch Transformer * Fixes to string, and cleanup * Rewrite flow transformer * Clean skidfuscator's trash * ComposedSkidTransformer * tests * Better Try-Catch handling for aggresive nested FlowException * Better Try-Catch handling for aggresive nested FlowException * Clean fix check * Fix for gp flow * Skid javadocs * tests * asd --------- Co-authored-by: EpicPlayerA10 <62206933+EpicPlayerA10@users.noreply.github.com>
1 parent 2d18e61 commit 7773f21

49 files changed

Lines changed: 1870 additions & 54 deletions

File tree

Some content is hidden

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

deobfuscator-api/src/main/java/uwu/narumi/deobfuscator/api/asm/matcher/Match.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import java.util.ArrayList;
1010
import java.util.List;
11+
import java.util.Optional;
1112
import java.util.function.Predicate;
1213

1314
/**
@@ -72,6 +73,10 @@ public MatchContext findFirstMatch(MethodContext methodContext) {
7273
return this.findAllMatches(methodContext).stream().findFirst().orElse(null);
7374
}
7475

76+
public Optional<MatchContext> findAny(MethodContext methodContext) {
77+
return this.findAllMatches(methodContext).stream().findAny();
78+
}
79+
7580
/**
7681
* @return {@link MatchContext} if matches or {@code null} if it does not match
7782
*/

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,26 @@ public static AbstractInsnNode toPop(Value value) {
141141
return value.getSize() == 1 ? new InsnNode(POP) : new InsnNode(POP2);
142142
}
143143

144+
public boolean isInsnInLabelRange(MethodNode method, LabelNode startLabel, AbstractInsnNode insn) {
145+
InsnList instructions = method.instructions;
146+
147+
int startIndex = instructions.indexOf(startLabel);
148+
if (startIndex == -1) return false;
149+
150+
int insnIndex = instructions.indexOf(insn);
151+
if (insnIndex == -1) return false;
152+
153+
int endIndex = instructions.size();
154+
for (int i = startIndex + 1; i < instructions.size(); i++) {
155+
if (instructions.get(i) instanceof LabelNode) {
156+
endIndex = i;
157+
break;
158+
}
159+
}
160+
161+
return insnIndex > startIndex && insnIndex < endIndex;
162+
}
163+
144164
/**
145165
* Update method descriptor in the current class, a superclass and interfaces
146166
*

deobfuscator-impl/src/test/java/uwu/narumi/deobfuscator/TestDeobfuscation.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,5 +239,10 @@ protected void registerAll() {
239239
.transformers(ComposedGuardProtectorTransformer::new)
240240
.inputClass(InputType.CUSTOM_CLASS, "guardprotector/Class951.class")
241241
.register();
242+
243+
test("SkidFuscator 2.0.11 - Pure hash encryption")
244+
.transformers(ComposedSkidTransformer::new)
245+
.inputJar("skidfuscator.jar")
246+
.register();
242247
}
243248
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package uwu.narumi.deobfuscator.core.other.composed;
2+
3+
import uwu.narumi.deobfuscator.api.transformer.ComposedTransformer;
4+
import uwu.narumi.deobfuscator.core.other.composed.general.ComposedGeneralFlowTransformer;
5+
import uwu.narumi.deobfuscator.core.other.impl.clean.peephole.*;
6+
import uwu.narumi.deobfuscator.core.other.impl.pool.InlineLocalVariablesTransformer;
7+
import uwu.narumi.deobfuscator.core.other.impl.pool.InlineStaticFieldTransformer;
8+
import uwu.narumi.deobfuscator.core.other.impl.skidfuscator.*;
9+
import uwu.narumi.deobfuscator.core.other.impl.universal.UniversalFlowTransformer;
10+
import uwu.narumi.deobfuscator.core.other.impl.universal.UniversalNumberTransformer;
11+
12+
/**
13+
* SkidFuscator 2.0.11 Community version
14+
* https://github.com/skidfuscatordev/skidfuscator-java-obfuscator
15+
*/
16+
public class ComposedSkidTransformer extends ComposedTransformer {
17+
18+
public ComposedSkidTransformer() {
19+
super(
20+
UniversalNumberTransformer::new,
21+
SkidNumberTransformer::new,
22+
SkidTryCatchRemoveTransformer::new,
23+
ComposedGeneralFlowTransformer::new,
24+
InlineStaticFieldTransformer::new,
25+
() -> new ComposedTransformer(true,
26+
InlineLocalVariablesTransformer::new, /* Passthrough Hash */
27+
SkidFlowTransformer::new, /* Resolve SkidFuscator's Flow */
28+
29+
UniversalFlowTransformer::new, /* Solve SkidFuscator's Switches/Jumps */
30+
31+
NopCleanTransformer::new,
32+
UnUsedLabelCleanTransformer::new,
33+
UselessGotosCleanTransformer::new,
34+
35+
() -> new ComposedTransformer(true,
36+
PopUnUsedLocalVariablesTransformer::new,
37+
UselessPopCleanTransformer::new
38+
)
39+
),
40+
SkidStringTransformer::new,
41+
SkidCleanTransformer::new
42+
);
43+
}
44+
}

deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/branchlock/BranchlockCompabilityStringTransformer.java

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -248,24 +248,4 @@ public LabelNode getLabelByKey(TableSwitchInsnNode tsi, int key) {
248248
int index = key - tsi.min;
249249
return tsi.labels.get(index);
250250
}
251-
252-
public boolean isInsnInLabelRange(MethodNode method, LabelNode startLabel, AbstractInsnNode insn) {
253-
InsnList instructions = method.instructions;
254-
255-
int startIndex = instructions.indexOf(startLabel);
256-
if (startIndex == -1) return false;
257-
258-
int insnIndex = instructions.indexOf(insn);
259-
if (insnIndex == -1) return false;
260-
261-
int endIndex = instructions.size();
262-
for (int i = startIndex + 1; i < instructions.size(); i++) {
263-
if (instructions.get(i) instanceof LabelNode) {
264-
endIndex = i;
265-
break;
266-
}
267-
}
268-
269-
return insnIndex > startIndex && insnIndex < endIndex;
270-
}
271251
}

deobfuscator-transformers/src/main/java/uwu/narumi/deobfuscator/core/other/impl/guardprotector/GuardProtectorFlowTransformer.java

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,15 @@ protected void transform() throws Exception {
3232
flowVarStore.findAllMatches(methodContext).forEach(varStore -> {
3333
FieldInsnNode fieldInsn = varStore.captures().get("stored-type").insn().asFieldInsn();
3434
if (!hasPutStatic(classWrapper.classNode(), fieldInsn)) {
35-
// FieldRef fieldRef = FieldRef.of(fieldInsn); //This doesn`t work. Fields are still present in classes (maybe because they are private static final)
36-
// context().removeField(fieldRef);
35+
classWrapper.fields().removeIf(fieldNode -> fieldNode.name.equals(fieldInsn.name) && fieldNode.desc.equals(fieldInsn.desc));
3736
boolean ifNeJump = fieldInsn.desc.equals("Z");
3837
int varIndex = ((VarInsnNode) varStore.captures().get("stored-var").insn()).var;
3938
toRemove.addAll(varStore.collectedInsns());
4039
flowVarEquations.findAllMatches(methodContext).forEach(jumpEquation -> {
4140
int loadedVarIndex = ((VarInsnNode) jumpEquation.captures().get("loaded-var").insn()).var;
4241
JumpInsnNode jump = jumpEquation.captures().get("stored-jump").insn().asJump();
4342
if ((ifNeJump && jump.getOpcode() == IFNE) || (!ifNeJump && jump.getOpcode() == IFEQ) && varIndex == loadedVarIndex) {
44-
// if (jump.label != null) {
45-
// toRemove.add(jump.label);
46-
// markChange();
47-
// methodNode.instructions.forEach(insn -> {
48-
// if (isInsnInLabelRange(methodNode, jump.label, insn)) {
49-
// toRemove.add(insn);
50-
// }
51-
// });
52-
// }
53-
methodNode.instructions.insert(jump, new JumpInsnNode(GOTO, jump.label));
43+
//methodNode.instructions.insert(jump, new JumpInsnNode(GOTO, jump.label));
5444
toRemove.addAll(jumpEquation.collectedInsns());
5545
markChange();
5646
}
@@ -79,26 +69,6 @@ protected void transform() throws Exception {
7969
}));
8070
}
8171

82-
public boolean isInsnInLabelRange(MethodNode method, LabelNode startLabel, AbstractInsnNode insn) {
83-
InsnList instructions = method.instructions;
84-
85-
int startIndex = instructions.indexOf(startLabel);
86-
if (startIndex == -1) return false;
87-
88-
int insnIndex = instructions.indexOf(insn);
89-
if (insnIndex == -1) return false;
90-
91-
int endIndex = instructions.size();
92-
for (int i = startIndex + 1; i < instructions.size(); i++) {
93-
if (instructions.get(i) instanceof LabelNode) {
94-
endIndex = i;
95-
break;
96-
}
97-
}
98-
99-
return insnIndex > startIndex && insnIndex < endIndex;
100-
}
101-
10272
boolean hasPutStatic(ClassNode classNode, FieldInsnNode target) {
10373
for (MethodNode method : classNode.methods) {
10474
for (AbstractInsnNode insn : method.instructions) {
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package uwu.narumi.deobfuscator.core.other.impl.skidfuscator;
2+
3+
import org.objectweb.asm.tree.AbstractInsnNode;
4+
import org.objectweb.asm.tree.VarInsnNode;
5+
import uwu.narumi.deobfuscator.api.asm.ClassWrapper;
6+
import uwu.narumi.deobfuscator.api.asm.FieldRef;
7+
import uwu.narumi.deobfuscator.api.asm.MethodContext;
8+
import uwu.narumi.deobfuscator.api.asm.matcher.Match;
9+
import uwu.narumi.deobfuscator.api.asm.matcher.group.SequenceMatch;
10+
import uwu.narumi.deobfuscator.api.asm.matcher.impl.FieldMatch;
11+
import uwu.narumi.deobfuscator.api.asm.matcher.impl.MethodMatch;
12+
import uwu.narumi.deobfuscator.api.asm.matcher.impl.NumberMatch;
13+
import uwu.narumi.deobfuscator.api.asm.matcher.impl.OpcodeMatch;
14+
import uwu.narumi.deobfuscator.api.transformer.Transformer;
15+
16+
import java.util.Arrays;
17+
import java.util.HashSet;
18+
import java.util.Set;
19+
20+
public class SkidCleanTransformer extends Transformer {
21+
22+
/**
23+
* Useless storing vars:
24+
* getstatic java/lang/System.out Ljava/io/PrintStream;
25+
* astore v29 - useless
26+
* invokestatic pack/tests/basics/accu/Digi.hwahaewjduusqug ()[B
27+
* iload i39
28+
* invokestatic pack/tests/basics/accu/Digi.shmyiqcznk ([BI)Ljava/lang/String;
29+
* astore v36 - useless
30+
* aload v29 - useless
31+
* aload v36 - useless
32+
* invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V
33+
*/
34+
Match uselessStoring = SequenceMatch.of(
35+
Match.of(ctx -> true),
36+
OpcodeMatch.of(ASTORE).capture("store-1"),
37+
OpcodeMatch.of(LDC),
38+
OpcodeMatch.of(ASTORE).capture("store-2"),
39+
OpcodeMatch.of(ALOAD).capture("load-1"),
40+
OpcodeMatch.of(ALOAD).capture("load-2"),
41+
MethodMatch.create()
42+
);
43+
44+
@Override
45+
protected void transform() throws Exception {
46+
/* Delete static decryption class */
47+
ClassWrapper decryptStaticClass = scopedClasses().stream().filter(classWrapper -> classWrapper.name().length() == 33 && (classWrapper.methods().size() == 3 || classWrapper.methods().size() == 2) && classWrapper.methods().stream().map(methodNode -> methodNode.desc).allMatch(desc -> desc.equals("(I)I"))).findFirst().get();
48+
context().getClassesMap().remove(decryptStaticClass.name());
49+
scopedClasses().forEach(classWrapper -> {
50+
/* Clean ASCII aheagos/etc */
51+
findClInit(classWrapper.classNode()).ifPresent(clinit -> {
52+
AbstractInsnNode firstInsn = clinit.instructions.getFirst();
53+
boolean hasASCII = false;
54+
while (firstInsn.getNext() != null) {
55+
if (firstInsn.isInteger() && firstInsn.getNext().getOpcode() == ANEWARRAY && firstInsn.getNext(2).isFieldInsn() && firstInsn.getNext(2).asFieldInsn().name.equalsIgnoreCase("nothing_to_see_here")) {
56+
hasASCII = true;
57+
break;
58+
}
59+
firstInsn = firstInsn.getNext();
60+
}
61+
62+
Set<AbstractInsnNode> toRemove = new HashSet<>();
63+
if (hasASCII) {
64+
toRemove.add(firstInsn);
65+
toRemove.add(firstInsn.getNext());
66+
toRemove.add(firstInsn.getNext(2));
67+
firstInsn = firstInsn.getNext(3);
68+
while (firstInsn != null && firstInsn.getOpcode() == GETSTATIC && firstInsn.getNext() != null && firstInsn.getNext().isInteger() && firstInsn.getNext(2) != null && firstInsn.getNext(2).isString() && firstInsn.getNext(3) != null && firstInsn.getNext(3).getOpcode() == AASTORE) {
69+
toRemove.add(firstInsn);
70+
toRemove.add(firstInsn.getNext());
71+
toRemove.add(firstInsn.getNext(2));
72+
toRemove.add(firstInsn.getNext(3));
73+
firstInsn = firstInsn.getNext(4);
74+
}
75+
toRemove.forEach(clinit.instructions::remove);
76+
classWrapper.fields().removeIf(fieldNode -> fieldNode.name.equals("nothing_to_see_here") && fieldNode.desc.equals("[Ljava/lang/String;"));
77+
markChange();
78+
}
79+
});
80+
81+
/* Clear <init> hash-int */
82+
classWrapper.fields().removeIf(fieldNode -> {
83+
boolean matchField = isAccess(fieldNode.access, ACC_PRIVATE, ACC_TRANSIENT) && fieldNode.desc.equals("I");
84+
if (matchField) {
85+
classWrapper.methods().forEach(methodNode1 -> {
86+
if (methodNode1.name.equals("<init>")) {
87+
SequenceMatch.of(
88+
NumberMatch.of(),
89+
FieldMatch.putField().fieldRef(FieldRef.of(classWrapper.classNode(), fieldNode))
90+
).findAny(MethodContext.of(classWrapper, methodNode1)).ifPresent(matchContext -> {
91+
matchContext.removeAll();
92+
markChange();
93+
});
94+
}
95+
});
96+
}
97+
return matchField;
98+
});
99+
100+
/* Clear self-class-xor from flow-obfuscation */
101+
classWrapper.methods().removeIf(methodNode -> methodNode.name.length() == 16 && isAccess(methodNode.access, ACC_PRIVATE, ACC_STATIC) && methodNode.desc.equals("(II)I") && methodNode.instructions.size() == 4);
102+
103+
classWrapper.methods().forEach(methodNode -> {
104+
MethodContext methodContext = MethodContext.of(classWrapper, methodNode);
105+
106+
uselessStoring.findAllMatches(methodContext).forEach(matchContext -> {
107+
VarInsnNode store1 = (VarInsnNode) matchContext.captures().get("store-1").insn();
108+
VarInsnNode store2 = (VarInsnNode) matchContext.captures().get("store-2").insn();
109+
VarInsnNode load1 = (VarInsnNode) matchContext.captures().get("load-1").insn();
110+
VarInsnNode load2 = (VarInsnNode) matchContext.captures().get("load-2").insn();
111+
if (store1.var == load1.var && store2.var == load2.var) {
112+
if (Arrays.stream(methodNode.instructions.toArray()).filter(insn -> !insn.equals(load1)).noneMatch(insn -> insn.getOpcode() == ALOAD && ((VarInsnNode)insn).var == store1.var)) {
113+
methodNode.instructions.remove(store1);
114+
methodNode.instructions.remove(load1);
115+
methodNode.instructions.remove(store2);
116+
methodNode.instructions.remove(load2);
117+
markChange();
118+
}
119+
}
120+
});
121+
});
122+
});
123+
}
124+
}

0 commit comments

Comments
 (0)