Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;

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

public Optional<MatchContext> findAny(MethodContext methodContext) {
return this.findAllMatches(methodContext).stream().findAny();
}

/**
* @return {@link MatchContext} if matches or {@code null} if it does not match
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,26 @@ public static AbstractInsnNode toPop(Value value) {
return value.getSize() == 1 ? new InsnNode(POP) : new InsnNode(POP2);
}

public boolean isInsnInLabelRange(MethodNode method, LabelNode startLabel, AbstractInsnNode insn) {
InsnList instructions = method.instructions;

int startIndex = instructions.indexOf(startLabel);
if (startIndex == -1) return false;

int insnIndex = instructions.indexOf(insn);
if (insnIndex == -1) return false;

int endIndex = instructions.size();
for (int i = startIndex + 1; i < instructions.size(); i++) {
if (instructions.get(i) instanceof LabelNode) {
endIndex = i;
break;
}
}

return insnIndex > startIndex && insnIndex < endIndex;
}

/**
* Update method descriptor in the current class, a superclass and interfaces
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,5 +239,10 @@ protected void registerAll() {
.transformers(ComposedGuardProtectorTransformer::new)
.inputClass(InputType.CUSTOM_CLASS, "guardprotector/Class951.class")
.register();

test("SkidFuscator 2.0.11 - Pure hash encryption")
.transformers(ComposedSkidTransformer::new)
.inputJar("skidfuscator.jar")
.register();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package uwu.narumi.deobfuscator.core.other.composed;

import uwu.narumi.deobfuscator.api.transformer.ComposedTransformer;
import uwu.narumi.deobfuscator.core.other.composed.general.ComposedGeneralFlowTransformer;
import uwu.narumi.deobfuscator.core.other.impl.clean.peephole.*;
import uwu.narumi.deobfuscator.core.other.impl.pool.InlineLocalVariablesTransformer;
import uwu.narumi.deobfuscator.core.other.impl.pool.InlineStaticFieldTransformer;
import uwu.narumi.deobfuscator.core.other.impl.skidfuscator.*;
import uwu.narumi.deobfuscator.core.other.impl.universal.UniversalFlowTransformer;
import uwu.narumi.deobfuscator.core.other.impl.universal.UniversalNumberTransformer;

/**
* SkidFuscator 2.0.11 Community version
* https://github.com/skidfuscatordev/skidfuscator-java-obfuscator
*/
public class ComposedSkidTransformer extends ComposedTransformer {

public ComposedSkidTransformer() {
super(
UniversalNumberTransformer::new,
SkidNumberTransformer::new,
SkidTryCatchRemoveTransformer::new,
ComposedGeneralFlowTransformer::new,
InlineStaticFieldTransformer::new,
() -> new ComposedTransformer(true,
InlineLocalVariablesTransformer::new, /* Passthrough Hash */
SkidFlowTransformer::new, /* Resolve SkidFuscator's Flow */

UniversalFlowTransformer::new, /* Solve SkidFuscator's Switches/Jumps */

NopCleanTransformer::new,
UnUsedLabelCleanTransformer::new,
UselessGotosCleanTransformer::new,

() -> new ComposedTransformer(true,
PopUnUsedLocalVariablesTransformer::new,
UselessPopCleanTransformer::new
)
),
SkidStringTransformer::new,
SkidCleanTransformer::new
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -248,24 +248,4 @@ public LabelNode getLabelByKey(TableSwitchInsnNode tsi, int key) {
int index = key - tsi.min;
return tsi.labels.get(index);
}

public boolean isInsnInLabelRange(MethodNode method, LabelNode startLabel, AbstractInsnNode insn) {
InsnList instructions = method.instructions;

int startIndex = instructions.indexOf(startLabel);
if (startIndex == -1) return false;

int insnIndex = instructions.indexOf(insn);
if (insnIndex == -1) return false;

int endIndex = instructions.size();
for (int i = startIndex + 1; i < instructions.size(); i++) {
if (instructions.get(i) instanceof LabelNode) {
endIndex = i;
break;
}
}

return insnIndex > startIndex && insnIndex < endIndex;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,15 @@ protected void transform() throws Exception {
flowVarStore.findAllMatches(methodContext).forEach(varStore -> {
FieldInsnNode fieldInsn = varStore.captures().get("stored-type").insn().asFieldInsn();
if (!hasPutStatic(classWrapper.classNode(), fieldInsn)) {
// FieldRef fieldRef = FieldRef.of(fieldInsn); //This doesn`t work. Fields are still present in classes (maybe because they are private static final)
// context().removeField(fieldRef);
classWrapper.fields().removeIf(fieldNode -> fieldNode.name.equals(fieldInsn.name) && fieldNode.desc.equals(fieldInsn.desc));
boolean ifNeJump = fieldInsn.desc.equals("Z");
int varIndex = ((VarInsnNode) varStore.captures().get("stored-var").insn()).var;
toRemove.addAll(varStore.collectedInsns());
flowVarEquations.findAllMatches(methodContext).forEach(jumpEquation -> {
int loadedVarIndex = ((VarInsnNode) jumpEquation.captures().get("loaded-var").insn()).var;
JumpInsnNode jump = jumpEquation.captures().get("stored-jump").insn().asJump();
if ((ifNeJump && jump.getOpcode() == IFNE) || (!ifNeJump && jump.getOpcode() == IFEQ) && varIndex == loadedVarIndex) {
// if (jump.label != null) {
// toRemove.add(jump.label);
// markChange();
// methodNode.instructions.forEach(insn -> {
// if (isInsnInLabelRange(methodNode, jump.label, insn)) {
// toRemove.add(insn);
// }
// });
// }
methodNode.instructions.insert(jump, new JumpInsnNode(GOTO, jump.label));
//methodNode.instructions.insert(jump, new JumpInsnNode(GOTO, jump.label));
toRemove.addAll(jumpEquation.collectedInsns());
markChange();
}
Expand Down Expand Up @@ -79,26 +69,6 @@ protected void transform() throws Exception {
}));
}

public boolean isInsnInLabelRange(MethodNode method, LabelNode startLabel, AbstractInsnNode insn) {
InsnList instructions = method.instructions;

int startIndex = instructions.indexOf(startLabel);
if (startIndex == -1) return false;

int insnIndex = instructions.indexOf(insn);
if (insnIndex == -1) return false;

int endIndex = instructions.size();
for (int i = startIndex + 1; i < instructions.size(); i++) {
if (instructions.get(i) instanceof LabelNode) {
endIndex = i;
break;
}
}

return insnIndex > startIndex && insnIndex < endIndex;
}

boolean hasPutStatic(ClassNode classNode, FieldInsnNode target) {
for (MethodNode method : classNode.methods) {
for (AbstractInsnNode insn : method.instructions) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package uwu.narumi.deobfuscator.core.other.impl.skidfuscator;

import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
import uwu.narumi.deobfuscator.api.asm.ClassWrapper;
import uwu.narumi.deobfuscator.api.asm.FieldRef;
import uwu.narumi.deobfuscator.api.asm.MethodContext;
import uwu.narumi.deobfuscator.api.asm.matcher.Match;
import uwu.narumi.deobfuscator.api.asm.matcher.group.SequenceMatch;
import uwu.narumi.deobfuscator.api.asm.matcher.impl.FieldMatch;
import uwu.narumi.deobfuscator.api.asm.matcher.impl.MethodMatch;
import uwu.narumi.deobfuscator.api.asm.matcher.impl.NumberMatch;
import uwu.narumi.deobfuscator.api.asm.matcher.impl.OpcodeMatch;
import uwu.narumi.deobfuscator.api.transformer.Transformer;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class SkidCleanTransformer extends Transformer {

/**
* Useless storing vars:
* getstatic java/lang/System.out Ljava/io/PrintStream;
* astore v29 - useless
* invokestatic pack/tests/basics/accu/Digi.hwahaewjduusqug ()[B
* iload i39
* invokestatic pack/tests/basics/accu/Digi.shmyiqcznk ([BI)Ljava/lang/String;
* astore v36 - useless
* aload v29 - useless
* aload v36 - useless
* invokevirtual java/io/PrintStream.println (Ljava/lang/String;)V
*/
Match uselessStoring = SequenceMatch.of(
Match.of(ctx -> true),
OpcodeMatch.of(ASTORE).capture("store-1"),
OpcodeMatch.of(LDC),
OpcodeMatch.of(ASTORE).capture("store-2"),
OpcodeMatch.of(ALOAD).capture("load-1"),
OpcodeMatch.of(ALOAD).capture("load-2"),
MethodMatch.create()
);

@Override
protected void transform() throws Exception {
/* Delete static decryption class */
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();
context().getClassesMap().remove(decryptStaticClass.name());
scopedClasses().forEach(classWrapper -> {
/* Clean ASCII aheagos/etc */
findClInit(classWrapper.classNode()).ifPresent(clinit -> {
AbstractInsnNode firstInsn = clinit.instructions.getFirst();
boolean hasASCII = false;
while (firstInsn.getNext() != null) {
if (firstInsn.isInteger() && firstInsn.getNext().getOpcode() == ANEWARRAY && firstInsn.getNext(2).isFieldInsn() && firstInsn.getNext(2).asFieldInsn().name.equalsIgnoreCase("nothing_to_see_here")) {
hasASCII = true;
break;
}
firstInsn = firstInsn.getNext();
}

Set<AbstractInsnNode> toRemove = new HashSet<>();
if (hasASCII) {
toRemove.add(firstInsn);
toRemove.add(firstInsn.getNext());
toRemove.add(firstInsn.getNext(2));
firstInsn = firstInsn.getNext(3);
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) {
toRemove.add(firstInsn);
toRemove.add(firstInsn.getNext());
toRemove.add(firstInsn.getNext(2));
toRemove.add(firstInsn.getNext(3));
firstInsn = firstInsn.getNext(4);
}
toRemove.forEach(clinit.instructions::remove);
classWrapper.fields().removeIf(fieldNode -> fieldNode.name.equals("nothing_to_see_here") && fieldNode.desc.equals("[Ljava/lang/String;"));
markChange();
}
});

/* Clear <init> hash-int */
classWrapper.fields().removeIf(fieldNode -> {
boolean matchField = isAccess(fieldNode.access, ACC_PRIVATE, ACC_TRANSIENT) && fieldNode.desc.equals("I");
if (matchField) {
classWrapper.methods().forEach(methodNode1 -> {
if (methodNode1.name.equals("<init>")) {
SequenceMatch.of(
NumberMatch.of(),
FieldMatch.putField().fieldRef(FieldRef.of(classWrapper.classNode(), fieldNode))
).findAny(MethodContext.of(classWrapper, methodNode1)).ifPresent(matchContext -> {
matchContext.removeAll();
markChange();
});
}
});
}
return matchField;
});

/* Clear self-class-xor from flow-obfuscation */
classWrapper.methods().removeIf(methodNode -> methodNode.name.length() == 16 && isAccess(methodNode.access, ACC_PRIVATE, ACC_STATIC) && methodNode.desc.equals("(II)I") && methodNode.instructions.size() == 4);

classWrapper.methods().forEach(methodNode -> {
MethodContext methodContext = MethodContext.of(classWrapper, methodNode);

uselessStoring.findAllMatches(methodContext).forEach(matchContext -> {
VarInsnNode store1 = (VarInsnNode) matchContext.captures().get("store-1").insn();
VarInsnNode store2 = (VarInsnNode) matchContext.captures().get("store-2").insn();
VarInsnNode load1 = (VarInsnNode) matchContext.captures().get("load-1").insn();
VarInsnNode load2 = (VarInsnNode) matchContext.captures().get("load-2").insn();
if (store1.var == load1.var && store2.var == load2.var) {
if (Arrays.stream(methodNode.instructions.toArray()).filter(insn -> !insn.equals(load1)).noneMatch(insn -> insn.getOpcode() == ALOAD && ((VarInsnNode)insn).var == store1.var)) {
methodNode.instructions.remove(store1);
methodNode.instructions.remove(load1);
methodNode.instructions.remove(store2);
methodNode.instructions.remove(load2);
markChange();
}
}
});
});
});
}
}
Loading