Skip to content

Commit af3594d

Browse files
committed
feat: various string obfs
1 parent d1a6479 commit af3594d

37 files changed

+4458
-8
lines changed

dev.skidfuscator.obfuscator/build.gradle

+20
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ dependencies {
2020
api project(':commons')
2121
api project(':pure-analysis')
2222

23+
implementation project(':sdk')
2324
implementation 'com.github.lukfor:magic-progress:0.3.2'
2425
implementation 'com.github.matomo-org:matomo-java-tracker:v1.7'
2526
api 'com.github.Col-E:jphantom:1.4.3'
@@ -45,6 +46,25 @@ tasks.withType(JavaCompile) {
4546
]
4647
}
4748

49+
jar {
50+
into('resources') {
51+
from project(':sdk').tasks.jar.archiveFile
52+
rename { String filename ->
53+
'sdk.jar'
54+
}
55+
}
56+
}
57+
58+
// Add SDK jar to test resources
59+
processTestResources {
60+
from(project(':sdk').tasks.jar.archiveFile) {
61+
into 'resources'
62+
rename { String filename ->
63+
'sdk.jar'
64+
}
65+
}
66+
}
67+
4868
test {
4969
useJUnitPlatform()
5070
}

dev.skidfuscator.obfuscator/src/main/java/dev/skidfuscator/obfuscator/Skidfuscator.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,13 @@
5353
import dev.skidfuscator.obfuscator.transform.impl.flow.exception.BasicExceptionTransformer;
5454
import dev.skidfuscator.obfuscator.transform.impl.flow.interprocedural.InterproceduralTransformer;
5555
import dev.skidfuscator.obfuscator.transform.impl.flow.interprocedural.RandomInitTransformer;
56+
import dev.skidfuscator.obfuscator.transform.impl.hash.StringEqualsIgnoreCaseHashTranformer;
5657
import dev.skidfuscator.obfuscator.transform.impl.misc.AhegaoTransformer;
5758
import dev.skidfuscator.obfuscator.transform.impl.number.NumberTransformer;
5859
import dev.skidfuscator.obfuscator.transform.impl.pure.PureHashTransformer;
60+
import dev.skidfuscator.obfuscator.transform.impl.sdk.SdkInjectorTransformer;
5961
import dev.skidfuscator.obfuscator.transform.impl.string.StringEncryptionType;
60-
import dev.skidfuscator.obfuscator.transform.impl.string.StringTransformer;
62+
import dev.skidfuscator.obfuscator.transform.impl.hash.StringEqualsHashTranformer;
6163
import dev.skidfuscator.obfuscator.transform.impl.string.StringTransformerV2;
6264
import dev.skidfuscator.obfuscator.util.ConsoleColors;
6365
import dev.skidfuscator.obfuscator.util.MapleJarUtil;
@@ -84,7 +86,6 @@
8486
import org.objectweb.asm.Opcodes;
8587
import org.piwik.java.tracking.PiwikRequest;
8688
import org.topdank.byteengineer.commons.data.JarContents;
87-
import org.topdank.byteengineer.commons.data.JarResource;
8889

8990
import java.io.File;
9091
import java.io.IOException;
@@ -703,6 +704,9 @@ public List<Transformer> getTransformers() {
703704
new BasicExceptionTransformer(this),
704705
new BasicRangeTransformer(this),
705706
new PureHashTransformer(this),
707+
new SdkInjectorTransformer(this),
708+
new StringEqualsHashTranformer(this),
709+
new StringEqualsIgnoreCaseHashTranformer(this),
706710
/*
707711
new FlatteningFlowTransformer(this),*/
708712
new AhegaoTransformer(this)

dev.skidfuscator.obfuscator/src/main/java/dev/skidfuscator/obfuscator/number/pure/VmHashTransformer.java

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import dev.xdark.ssvm.mirror.member.JavaMethod;
2525
import dev.xdark.ssvm.mirror.type.InstanceClass;
2626
import dev.xdark.ssvm.natives.SystemPropsNatives;
27-
import jdk.internal.util.SystemProps;
2827
import lombok.Data;
2928
import lombok.SneakyThrows;
3029
import org.mapleir.app.service.CompleteResolvingJarDumper;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package dev.skidfuscator.obfuscator.transform.impl.hash;
2+
3+
import dev.skidfuscator.obfuscator.Skidfuscator;
4+
import dev.skidfuscator.obfuscator.event.EventPriority;
5+
import dev.skidfuscator.obfuscator.event.annotation.Listen;
6+
import dev.skidfuscator.obfuscator.event.impl.transform.method.RunMethodTransformEvent;
7+
import dev.skidfuscator.obfuscator.skidasm.SkidMethodNode;
8+
import dev.skidfuscator.obfuscator.skidasm.cfg.SkidBlock;
9+
import dev.skidfuscator.obfuscator.transform.AbstractTransformer;
10+
import dev.skidfuscator.obfuscator.util.cfg.Variables;
11+
import org.mapleir.ir.cfg.BasicBlock;
12+
import org.mapleir.ir.cfg.ControlFlowGraph;
13+
import org.mapleir.ir.code.Expr;
14+
import org.mapleir.ir.code.Stmt;
15+
import org.mapleir.ir.code.expr.ConstantExpr;
16+
import org.mapleir.ir.code.expr.VarExpr;
17+
import org.mapleir.ir.code.expr.invoke.InvocationExpr;
18+
import org.mapleir.ir.code.expr.invoke.StaticInvocationExpr;
19+
import sdk.LongHashFunction;
20+
21+
import java.util.HashSet;
22+
23+
public class StringEqualsHashTranformer extends AbstractTransformer {
24+
public StringEqualsHashTranformer(final Skidfuscator skidfuscator) {
25+
super(skidfuscator, "String Equals Hash");
26+
}
27+
28+
@Listen(EventPriority.LOWEST)
29+
void handle(final RunMethodTransformEvent event) {
30+
final SkidMethodNode methodNode = event.getMethodNode();
31+
32+
if (methodNode.isAbstract()
33+
|| methodNode.isInit()) {
34+
this.skip();
35+
return;
36+
}
37+
38+
if (methodNode.node.instructions.size() > 10000) {
39+
this.fail();
40+
return;
41+
}
42+
43+
final ControlFlowGraph cfg = methodNode.getCfg();
44+
45+
if (cfg == null) {
46+
this.fail();
47+
return;
48+
}
49+
50+
for (BasicBlock vertex : new HashSet<>(cfg.vertices())) {
51+
if (vertex.isFlagSet(SkidBlock.FLAG_NO_OPAQUE))
52+
continue;
53+
54+
if (methodNode.isClinit()) {
55+
continue;
56+
}
57+
58+
for (Stmt stmt : new HashSet<>(vertex)) {
59+
for (Expr expr : stmt.enumerateOnlyChildren()) {
60+
if (expr instanceof InvocationExpr invocationExpr) {
61+
final boolean isEqualsMethod =
62+
invocationExpr.getOwner().equals("java/lang/String")
63+
&& invocationExpr.getName().equals("equals")
64+
&& invocationExpr.getDesc().equals("(Ljava/lang/Object;)Z");
65+
66+
if (methodNode.owner.getName().contains("BlowfishTest")) {
67+
System.out.println(expr);
68+
}
69+
70+
if (!isEqualsMethod)
71+
continue;
72+
73+
System.out.println(String.format("Found %s with matching%n", expr));
74+
75+
final Expr[] args = invocationExpr.getArgumentExprs();
76+
Expr arg0 = args[0];
77+
Expr arg1 = args[1];
78+
79+
if (arg0 instanceof VarExpr var0) {
80+
arg0 = Variables.getDefinition(cfg, var0);
81+
}
82+
83+
if (arg1 instanceof VarExpr var1) {
84+
arg1 = Variables.getDefinition(cfg, var1);
85+
}
86+
87+
final boolean isArg0Constant = arg0 instanceof ConstantExpr;
88+
final boolean isArg1Constant = arg1 instanceof ConstantExpr;
89+
90+
if (isArg0Constant == isArg1Constant) {
91+
continue;
92+
}
93+
94+
ConstantExpr constantExpr = isArg0Constant ? (ConstantExpr) arg0 : (ConstantExpr) arg1;
95+
Expr otherExpr = isArg0Constant ? arg1 : arg0;
96+
97+
constantExpr.setConstant(
98+
"" + LongHashFunction.xx3().hashChars((String) constantExpr.getConstant())
99+
);
100+
otherExpr.getParent().overwrite(otherExpr, new StaticInvocationExpr(
101+
new Expr[] { otherExpr.copy() },
102+
"sdk/SDK",
103+
"hash",
104+
"(Ljava/lang/String;)Ljava/lang/String;"
105+
));
106+
this.success();
107+
}
108+
}
109+
}
110+
}
111+
}
112+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package dev.skidfuscator.obfuscator.transform.impl.hash;
2+
3+
import dev.skidfuscator.obfuscator.Skidfuscator;
4+
import dev.skidfuscator.obfuscator.event.annotation.Listen;
5+
import dev.skidfuscator.obfuscator.event.impl.transform.method.RunMethodTransformEvent;
6+
import dev.skidfuscator.obfuscator.skidasm.SkidMethodNode;
7+
import dev.skidfuscator.obfuscator.skidasm.cfg.SkidBlock;
8+
import dev.skidfuscator.obfuscator.transform.AbstractTransformer;
9+
import dev.skidfuscator.obfuscator.util.cfg.Variables;
10+
import org.mapleir.ir.cfg.BasicBlock;
11+
import org.mapleir.ir.cfg.ControlFlowGraph;
12+
import org.mapleir.ir.code.Expr;
13+
import org.mapleir.ir.code.Stmt;
14+
import org.mapleir.ir.code.expr.ConstantExpr;
15+
import org.mapleir.ir.code.expr.VarExpr;
16+
import org.mapleir.ir.code.expr.invoke.InvocationExpr;
17+
import org.mapleir.ir.code.expr.invoke.StaticInvocationExpr;
18+
import org.mapleir.ir.code.expr.invoke.VirtualInvocationExpr;
19+
import sdk.LongHashFunction;
20+
21+
import java.util.HashSet;
22+
23+
public class StringEqualsIgnoreCaseHashTranformer extends AbstractTransformer {
24+
public StringEqualsIgnoreCaseHashTranformer(final Skidfuscator skidfuscator) {
25+
super(skidfuscator, "String EqIgCase Hash");
26+
}
27+
28+
@Listen
29+
void handle(final RunMethodTransformEvent event) {
30+
final SkidMethodNode methodNode = event.getMethodNode();
31+
32+
if (methodNode.isAbstract()
33+
|| methodNode.isInit()) {
34+
this.skip();
35+
return;
36+
}
37+
38+
if (methodNode.node.instructions.size() > 10000) {
39+
this.fail();
40+
return;
41+
}
42+
43+
final ControlFlowGraph cfg = methodNode.getCfg();
44+
45+
if (cfg == null) {
46+
this.fail();
47+
return;
48+
}
49+
50+
for (BasicBlock vertex : new HashSet<>(cfg.vertices())) {
51+
if (vertex.isFlagSet(SkidBlock.FLAG_NO_OPAQUE))
52+
continue;
53+
54+
if (methodNode.isClinit() && this.heuristicSizeSkip(methodNode, 8.f)) {
55+
continue;
56+
}
57+
58+
for (Stmt stmt : new HashSet<>(vertex)) {
59+
for (Expr expr : stmt.enumerateOnlyChildren()) {
60+
if (expr instanceof InvocationExpr invocationExpr) {
61+
final boolean isEqualsMethod =
62+
invocationExpr.getOwner().equals("java/lang/String")
63+
&& invocationExpr.getName().equals("equalsIgnoreCase")
64+
&& invocationExpr.getDesc().equals("(Ljava/lang/String;)Z");
65+
66+
if (!isEqualsMethod)
67+
continue;
68+
69+
System.out.println(String.format("Found %s with matching", expr));
70+
71+
final Expr[] args = invocationExpr.getArgumentExprs();
72+
Expr arg0 = args[0];
73+
Expr arg1 = args[1];
74+
75+
if (arg0 instanceof VarExpr var0) {
76+
arg0 = Variables.getDefinition(cfg, var0);
77+
}
78+
79+
if (arg1 instanceof VarExpr var1) {
80+
arg1 = Variables.getDefinition(cfg, var1);
81+
}
82+
83+
final boolean isArg0Constant = arg0 instanceof ConstantExpr;
84+
final boolean isArg1Constant = arg1 instanceof ConstantExpr;
85+
86+
if (isArg0Constant == isArg1Constant) {
87+
continue;
88+
}
89+
90+
ConstantExpr constantExpr = isArg0Constant ? (ConstantExpr) arg0 : (ConstantExpr) arg1;
91+
Expr otherExpr = isArg0Constant ? arg1 : arg0;
92+
93+
constantExpr.setConstant(
94+
"" + LongHashFunction.xx3().hashChars(((String) constantExpr.getConstant()).toLowerCase())
95+
);
96+
otherExpr.getParent().overwrite(otherExpr, new StaticInvocationExpr(
97+
new Expr[] { new VirtualInvocationExpr(
98+
InvocationExpr.CallType.VIRTUAL,
99+
new Expr[]{otherExpr.copy()},
100+
"java/lang/String",
101+
"toLowerCase",
102+
"()Ljava/lang/String;"
103+
)},
104+
"sdk/SDK",
105+
"hash",
106+
"(Ljava/lang/String;)Ljava/lang/String;"
107+
));
108+
this.success();
109+
}
110+
}
111+
}
112+
}
113+
}
114+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package dev.skidfuscator.obfuscator.transform.impl.sdk;
2+
3+
import dev.skidfuscator.obfuscator.Skidfuscator;
4+
import dev.skidfuscator.obfuscator.event.annotation.Listen;
5+
import dev.skidfuscator.obfuscator.event.impl.transform.skid.InitSkidTransformEvent;
6+
import dev.skidfuscator.obfuscator.transform.AbstractTransformer;
7+
import dev.skidfuscator.obfuscator.util.MapleJarUtil;
8+
import org.mapleir.asm.ClassNode;
9+
import org.topdank.byteengineer.commons.data.JarClassData;
10+
import org.topdank.byteio.in.SingleJarDownloader;
11+
12+
import java.io.*;
13+
import java.nio.file.Files;
14+
15+
import static dev.skidfuscator.obfuscator.util.JdkDownloader.CACHE_DIR;
16+
17+
public class SdkInjectorTransformer extends AbstractTransformer {
18+
public SdkInjectorTransformer(Skidfuscator skidfuscator) {
19+
super(skidfuscator, "SDK");
20+
}
21+
22+
@Listen
23+
void handle(final InitSkidTransformEvent event) {
24+
try {
25+
// Create cache directory if it doesn't exist
26+
if (!Files.exists(CACHE_DIR)) {
27+
Files.createDirectories(CACHE_DIR);
28+
}
29+
30+
// Extract SDK jar from resources to cache
31+
File sdkFile = CACHE_DIR.resolve("sdk.jar").toFile();
32+
try (InputStream is = getClass().getClassLoader().getResourceAsStream("resources/sdk.jar");
33+
OutputStream os = new FileOutputStream(sdkFile)) {
34+
if (is == null) {
35+
throw new IOException("Could not find sdk.jar in resources");
36+
}
37+
byte[] buffer = new byte[8192];
38+
int bytesRead;
39+
while ((bytesRead = is.read(buffer)) != -1) {
40+
os.write(buffer, 0, bytesRead);
41+
}
42+
}
43+
44+
// Import the SDK jar classes
45+
final SingleJarDownloader<ClassNode> downloader = MapleJarUtil.importJar(
46+
sdkFile,
47+
skidfuscator
48+
);
49+
50+
// Add SDK classes to the input jar
51+
for (JarClassData classData : downloader.getJarContents().getClassContents()) {
52+
skidfuscator.getJarContents().getClassContents().add(classData);
53+
}
54+
55+
} catch (IOException e) {
56+
throw new RuntimeException("Failed to inject SDK", e);
57+
}
58+
}
59+
}

dev.skidfuscator.obfuscator/src/main/java/dev/skidfuscator/obfuscator/util/JdkDownloader.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public class JdkDownloader {
4040
}
4141
}
4242

43-
private static final Path CACHE_DIR = Paths.get(System.getProperty("user.home"), ".ssvm", "jdk");
43+
public static final Path CACHE_DIR = Paths.get(System.getProperty("user.home"), ".ssvm", "jdk");
4444

4545
public static Path getCachedJdk() throws IOException {
4646
String cacheName;

0 commit comments

Comments
 (0)