Skip to content

Commit

Permalink
feat: various string obfs
Browse files Browse the repository at this point in the history
  • Loading branch information
terminalsin committed Dec 23, 2024
1 parent d1a6479 commit af3594d
Show file tree
Hide file tree
Showing 37 changed files with 4,458 additions and 8 deletions.
20 changes: 20 additions & 0 deletions dev.skidfuscator.obfuscator/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies {
api project(':commons')
api project(':pure-analysis')

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

jar {
into('resources') {
from project(':sdk').tasks.jar.archiveFile
rename { String filename ->
'sdk.jar'
}
}
}

// Add SDK jar to test resources
processTestResources {
from(project(':sdk').tasks.jar.archiveFile) {
into 'resources'
rename { String filename ->
'sdk.jar'
}
}
}

test {
useJUnitPlatform()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,13 @@
import dev.skidfuscator.obfuscator.transform.impl.flow.exception.BasicExceptionTransformer;
import dev.skidfuscator.obfuscator.transform.impl.flow.interprocedural.InterproceduralTransformer;
import dev.skidfuscator.obfuscator.transform.impl.flow.interprocedural.RandomInitTransformer;
import dev.skidfuscator.obfuscator.transform.impl.hash.StringEqualsIgnoreCaseHashTranformer;
import dev.skidfuscator.obfuscator.transform.impl.misc.AhegaoTransformer;
import dev.skidfuscator.obfuscator.transform.impl.number.NumberTransformer;
import dev.skidfuscator.obfuscator.transform.impl.pure.PureHashTransformer;
import dev.skidfuscator.obfuscator.transform.impl.sdk.SdkInjectorTransformer;
import dev.skidfuscator.obfuscator.transform.impl.string.StringEncryptionType;
import dev.skidfuscator.obfuscator.transform.impl.string.StringTransformer;
import dev.skidfuscator.obfuscator.transform.impl.hash.StringEqualsHashTranformer;
import dev.skidfuscator.obfuscator.transform.impl.string.StringTransformerV2;
import dev.skidfuscator.obfuscator.util.ConsoleColors;
import dev.skidfuscator.obfuscator.util.MapleJarUtil;
Expand All @@ -84,7 +86,6 @@
import org.objectweb.asm.Opcodes;
import org.piwik.java.tracking.PiwikRequest;
import org.topdank.byteengineer.commons.data.JarContents;
import org.topdank.byteengineer.commons.data.JarResource;

import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -703,6 +704,9 @@ public List<Transformer> getTransformers() {
new BasicExceptionTransformer(this),
new BasicRangeTransformer(this),
new PureHashTransformer(this),
new SdkInjectorTransformer(this),
new StringEqualsHashTranformer(this),
new StringEqualsIgnoreCaseHashTranformer(this),
/*
new FlatteningFlowTransformer(this),*/
new AhegaoTransformer(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import dev.xdark.ssvm.mirror.member.JavaMethod;
import dev.xdark.ssvm.mirror.type.InstanceClass;
import dev.xdark.ssvm.natives.SystemPropsNatives;
import jdk.internal.util.SystemProps;
import lombok.Data;
import lombok.SneakyThrows;
import org.mapleir.app.service.CompleteResolvingJarDumper;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package dev.skidfuscator.obfuscator.transform.impl.hash;

import dev.skidfuscator.obfuscator.Skidfuscator;
import dev.skidfuscator.obfuscator.event.EventPriority;
import dev.skidfuscator.obfuscator.event.annotation.Listen;
import dev.skidfuscator.obfuscator.event.impl.transform.method.RunMethodTransformEvent;
import dev.skidfuscator.obfuscator.skidasm.SkidMethodNode;
import dev.skidfuscator.obfuscator.skidasm.cfg.SkidBlock;
import dev.skidfuscator.obfuscator.transform.AbstractTransformer;
import dev.skidfuscator.obfuscator.util.cfg.Variables;
import org.mapleir.ir.cfg.BasicBlock;
import org.mapleir.ir.cfg.ControlFlowGraph;
import org.mapleir.ir.code.Expr;
import org.mapleir.ir.code.Stmt;
import org.mapleir.ir.code.expr.ConstantExpr;
import org.mapleir.ir.code.expr.VarExpr;
import org.mapleir.ir.code.expr.invoke.InvocationExpr;
import org.mapleir.ir.code.expr.invoke.StaticInvocationExpr;
import sdk.LongHashFunction;

import java.util.HashSet;

public class StringEqualsHashTranformer extends AbstractTransformer {
public StringEqualsHashTranformer(final Skidfuscator skidfuscator) {
super(skidfuscator, "String Equals Hash");
}

@Listen(EventPriority.LOWEST)
void handle(final RunMethodTransformEvent event) {
final SkidMethodNode methodNode = event.getMethodNode();

if (methodNode.isAbstract()
|| methodNode.isInit()) {
this.skip();
return;
}

if (methodNode.node.instructions.size() > 10000) {
this.fail();
return;
}

final ControlFlowGraph cfg = methodNode.getCfg();

if (cfg == null) {
this.fail();
return;
}

for (BasicBlock vertex : new HashSet<>(cfg.vertices())) {
if (vertex.isFlagSet(SkidBlock.FLAG_NO_OPAQUE))
continue;

if (methodNode.isClinit()) {
continue;
}

for (Stmt stmt : new HashSet<>(vertex)) {
for (Expr expr : stmt.enumerateOnlyChildren()) {
if (expr instanceof InvocationExpr invocationExpr) {
final boolean isEqualsMethod =
invocationExpr.getOwner().equals("java/lang/String")
&& invocationExpr.getName().equals("equals")
&& invocationExpr.getDesc().equals("(Ljava/lang/Object;)Z");

if (methodNode.owner.getName().contains("BlowfishTest")) {
System.out.println(expr);
}

if (!isEqualsMethod)
continue;

System.out.println(String.format("Found %s with matching%n", expr));

final Expr[] args = invocationExpr.getArgumentExprs();
Expr arg0 = args[0];
Expr arg1 = args[1];

if (arg0 instanceof VarExpr var0) {
arg0 = Variables.getDefinition(cfg, var0);
}

if (arg1 instanceof VarExpr var1) {
arg1 = Variables.getDefinition(cfg, var1);
}

final boolean isArg0Constant = arg0 instanceof ConstantExpr;
final boolean isArg1Constant = arg1 instanceof ConstantExpr;

if (isArg0Constant == isArg1Constant) {
continue;
}

ConstantExpr constantExpr = isArg0Constant ? (ConstantExpr) arg0 : (ConstantExpr) arg1;
Expr otherExpr = isArg0Constant ? arg1 : arg0;

constantExpr.setConstant(
"" + LongHashFunction.xx3().hashChars((String) constantExpr.getConstant())
);
otherExpr.getParent().overwrite(otherExpr, new StaticInvocationExpr(
new Expr[] { otherExpr.copy() },
"sdk/SDK",
"hash",
"(Ljava/lang/String;)Ljava/lang/String;"
));
this.success();
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package dev.skidfuscator.obfuscator.transform.impl.hash;

import dev.skidfuscator.obfuscator.Skidfuscator;
import dev.skidfuscator.obfuscator.event.annotation.Listen;
import dev.skidfuscator.obfuscator.event.impl.transform.method.RunMethodTransformEvent;
import dev.skidfuscator.obfuscator.skidasm.SkidMethodNode;
import dev.skidfuscator.obfuscator.skidasm.cfg.SkidBlock;
import dev.skidfuscator.obfuscator.transform.AbstractTransformer;
import dev.skidfuscator.obfuscator.util.cfg.Variables;
import org.mapleir.ir.cfg.BasicBlock;
import org.mapleir.ir.cfg.ControlFlowGraph;
import org.mapleir.ir.code.Expr;
import org.mapleir.ir.code.Stmt;
import org.mapleir.ir.code.expr.ConstantExpr;
import org.mapleir.ir.code.expr.VarExpr;
import org.mapleir.ir.code.expr.invoke.InvocationExpr;
import org.mapleir.ir.code.expr.invoke.StaticInvocationExpr;
import org.mapleir.ir.code.expr.invoke.VirtualInvocationExpr;
import sdk.LongHashFunction;

import java.util.HashSet;

public class StringEqualsIgnoreCaseHashTranformer extends AbstractTransformer {
public StringEqualsIgnoreCaseHashTranformer(final Skidfuscator skidfuscator) {
super(skidfuscator, "String EqIgCase Hash");
}

@Listen
void handle(final RunMethodTransformEvent event) {
final SkidMethodNode methodNode = event.getMethodNode();

if (methodNode.isAbstract()
|| methodNode.isInit()) {
this.skip();
return;
}

if (methodNode.node.instructions.size() > 10000) {
this.fail();
return;
}

final ControlFlowGraph cfg = methodNode.getCfg();

if (cfg == null) {
this.fail();
return;
}

for (BasicBlock vertex : new HashSet<>(cfg.vertices())) {
if (vertex.isFlagSet(SkidBlock.FLAG_NO_OPAQUE))
continue;

if (methodNode.isClinit() && this.heuristicSizeSkip(methodNode, 8.f)) {
continue;
}

for (Stmt stmt : new HashSet<>(vertex)) {
for (Expr expr : stmt.enumerateOnlyChildren()) {
if (expr instanceof InvocationExpr invocationExpr) {
final boolean isEqualsMethod =
invocationExpr.getOwner().equals("java/lang/String")
&& invocationExpr.getName().equals("equalsIgnoreCase")
&& invocationExpr.getDesc().equals("(Ljava/lang/String;)Z");

if (!isEqualsMethod)
continue;

System.out.println(String.format("Found %s with matching", expr));

final Expr[] args = invocationExpr.getArgumentExprs();
Expr arg0 = args[0];
Expr arg1 = args[1];

if (arg0 instanceof VarExpr var0) {
arg0 = Variables.getDefinition(cfg, var0);
}

if (arg1 instanceof VarExpr var1) {
arg1 = Variables.getDefinition(cfg, var1);
}

final boolean isArg0Constant = arg0 instanceof ConstantExpr;
final boolean isArg1Constant = arg1 instanceof ConstantExpr;

if (isArg0Constant == isArg1Constant) {
continue;
}

ConstantExpr constantExpr = isArg0Constant ? (ConstantExpr) arg0 : (ConstantExpr) arg1;
Expr otherExpr = isArg0Constant ? arg1 : arg0;

constantExpr.setConstant(
"" + LongHashFunction.xx3().hashChars(((String) constantExpr.getConstant()).toLowerCase())
);
otherExpr.getParent().overwrite(otherExpr, new StaticInvocationExpr(
new Expr[] { new VirtualInvocationExpr(
InvocationExpr.CallType.VIRTUAL,
new Expr[]{otherExpr.copy()},
"java/lang/String",
"toLowerCase",
"()Ljava/lang/String;"
)},
"sdk/SDK",
"hash",
"(Ljava/lang/String;)Ljava/lang/String;"
));
this.success();
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package dev.skidfuscator.obfuscator.transform.impl.sdk;

import dev.skidfuscator.obfuscator.Skidfuscator;
import dev.skidfuscator.obfuscator.event.annotation.Listen;
import dev.skidfuscator.obfuscator.event.impl.transform.skid.InitSkidTransformEvent;
import dev.skidfuscator.obfuscator.transform.AbstractTransformer;
import dev.skidfuscator.obfuscator.util.MapleJarUtil;
import org.mapleir.asm.ClassNode;
import org.topdank.byteengineer.commons.data.JarClassData;
import org.topdank.byteio.in.SingleJarDownloader;

import java.io.*;
import java.nio.file.Files;

import static dev.skidfuscator.obfuscator.util.JdkDownloader.CACHE_DIR;

public class SdkInjectorTransformer extends AbstractTransformer {
public SdkInjectorTransformer(Skidfuscator skidfuscator) {
super(skidfuscator, "SDK");
}

@Listen
void handle(final InitSkidTransformEvent event) {
try {
// Create cache directory if it doesn't exist
if (!Files.exists(CACHE_DIR)) {
Files.createDirectories(CACHE_DIR);
}

// Extract SDK jar from resources to cache
File sdkFile = CACHE_DIR.resolve("sdk.jar").toFile();
try (InputStream is = getClass().getClassLoader().getResourceAsStream("resources/sdk.jar");
OutputStream os = new FileOutputStream(sdkFile)) {
if (is == null) {
throw new IOException("Could not find sdk.jar in resources");
}
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
}

// Import the SDK jar classes
final SingleJarDownloader<ClassNode> downloader = MapleJarUtil.importJar(
sdkFile,
skidfuscator
);

// Add SDK classes to the input jar
for (JarClassData classData : downloader.getJarContents().getClassContents()) {
skidfuscator.getJarContents().getClassContents().add(classData);
}

} catch (IOException e) {
throw new RuntimeException("Failed to inject SDK", e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class JdkDownloader {
}
}

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

public static Path getCachedJdk() throws IOException {
String cacheName;
Expand Down
Loading

0 comments on commit af3594d

Please sign in to comment.