Skip to content
Open
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
77 changes: 68 additions & 9 deletions obfuscator/src/main/java/by/radioegor146/NativeObfuscator.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package by.radioegor146;

import by.radioegor146.bytecode.PreprocessorRunner;
import by.radioegor146.javaobf.JvmRenamerConfig;
import by.radioegor146.javaobf.JvmRenamerEntityConfig;
import by.radioegor146.source.CMakeFilesBuilder;
import by.radioegor146.source.ClassSourceBuilder;
import by.radioegor146.source.MainSourceBuilder;
Expand Down Expand Up @@ -121,7 +123,8 @@ public void process(Path inputJarPath, Path outputDir, List<Path> inputLibs,
obfuscateStrings, obfuscateConstants,
false, "MEDIUM", new ArrayList<>(), new ArrayList<>(), true,
true, true, true, false, false, false, FlowExceptionMode.STANDARD,
JavaFlowSettings.createDefault());
JavaFlowSettings.createDefault(),
JvmRenamerConfig.disabled());
}

public void process(Path inputJarPath, Path outputDir, List<Path> inputLibs,
Expand All @@ -136,7 +139,8 @@ public void process(Path inputJarPath, Path outputDir, List<Path> inputLibs,
boolean skidFlowObfuscation, boolean skidSdkInjection,
boolean skidVmHashing, boolean skidInvokeDynamicObfuscation,
FlowExceptionMode skidFlowExceptionMode,
JavaFlowSettings javaFlowSettings) throws IOException {
JavaFlowSettings javaFlowSettings,
JvmRenamerConfig jvmRenamerConfig) throws IOException {
ProtectionConfig protectionConfig = new ProtectionConfig(enableVirtualization, enableJit, flattenControlFlow,
obfuscateStrings, obfuscateConstants);
if (Files.exists(outputDir) && Files.isSameFile(inputJarPath.toRealPath().getParent(), outputDir.toRealPath())) {
Expand All @@ -153,7 +157,7 @@ public void process(Path inputJarPath, Path outputDir, List<Path> inputLibs,
Files.createDirectories(javaObfOutputDir);

Path skidOutputJar = javaObfOutputDir.resolve(inputJarPath.getFileName().toString());
Path skidConfig = createSkidConfig(javaBlackList, javaWhiteList, javaObfOutputDir, javaFlowSettings);
Path skidConfig = createSkidConfig(javaBlackList, javaWhiteList, javaObfOutputDir, javaFlowSettings, jvmRenamerConfig);
File[] skidLibs = inputLibs.stream().map(Path::toFile).toArray(File[]::new);

SkidfuscatorSession session = SkidfuscatorSession.builder()
Expand All @@ -164,7 +168,7 @@ public void process(Path inputJarPath, Path outputDir, List<Path> inputLibs,
.analytics(false)
.phantom(false)
.fuckit(false)
.renamer(false)
.renamer(jvmRenamerConfig != null && jvmRenamerConfig.isEnabled() && jvmRenamerConfig.isAnyEntityEnabled())
.debug(logger.isDebugEnabled())
.skidStringObfuscation(skidStringObfuscation)
.skidNumberObfuscation(skidNumberObfuscation)
Expand Down Expand Up @@ -578,7 +582,8 @@ public void process(ObfuscatorConfig config) throws IOException {
config.isSkidStringObfuscation(), config.isSkidNumberObfuscation(),
config.isSkidFlowObfuscation(), config.isSkidSdkInjection(),
config.isSkidVmHashing(), config.isSkidInvokeDynamicObfuscation(),
config.getSkidFlowExceptionMode(), config.getJavaFlowSettings());
config.getSkidFlowExceptionMode(), config.getJavaFlowSettings(),
config.getJvmRenamerConfig());
}

private void processWithAntiDebug(Path inputJarPath, Path outputDir, List<Path> inputLibs,
Expand All @@ -592,7 +597,8 @@ private void processWithAntiDebug(Path inputJarPath, Path outputDir, List<Path>
boolean skidFlowObfuscation, boolean skidSdkInjection,
boolean skidVmHashing, boolean skidInvokeDynamicObfuscation,
FlowExceptionMode skidFlowExceptionMode,
JavaFlowSettings javaFlowSettings) throws IOException {
JavaFlowSettings javaFlowSettings,
JvmRenamerConfig jvmRenamerConfig) throws IOException {

// Call the existing process method but with extended functionality
process(inputJarPath, outputDir, inputLibs, blackList, whiteList, plainLibName, customLibraryDirectory,
Expand All @@ -602,7 +608,8 @@ private void processWithAntiDebug(Path inputJarPath, Path outputDir, List<Path>
protectionConfig.isStringObfuscationEnabled(), protectionConfig.isConstantObfuscationEnabled(),
enableJavaObfuscation, javaObfuscationStrength, javaBlackList, javaWhiteList, enableNativeObfuscation,
skidStringObfuscation, skidNumberObfuscation, skidFlowObfuscation, skidSdkInjection, skidVmHashing,
skidInvokeDynamicObfuscation, skidFlowExceptionMode, javaFlowSettings);
skidInvokeDynamicObfuscation, skidFlowExceptionMode, javaFlowSettings,
jvmRenamerConfig);

// Generate anti-debug configuration header if any anti-debug features are enabled
if (antiDebugConfig.isAnyEnabled()) {
Expand Down Expand Up @@ -890,16 +897,18 @@ private String generateAntiDebugInitCode(AntiDebugConfig antiDebugConfig) {
private Path createSkidConfig(List<String> javaBlackList,
List<String> javaWhiteList,
Path outputDir,
JavaFlowSettings flowSettings) throws IOException {
JavaFlowSettings flowSettings,
JvmRenamerConfig renamerConfig) throws IOException {
boolean hasBlacklist = javaBlackList != null && !javaBlackList.isEmpty();
boolean hasWhitelist = javaWhiteList != null && !javaWhiteList.isEmpty();
boolean hasCustomFlow = flowSettings != null && !flowSettings.isDefault();
boolean hasRenamer = renamerConfig != null && renamerConfig.isEnabled() && renamerConfig.isAnyEntityEnabled();

if (hasWhitelist) {
logger.warn("Skidfuscator migration does not support java whitelist entries; ignoring provided list.");
}

if (!hasBlacklist && !hasCustomFlow) {
if (!hasBlacklist && !hasCustomFlow && !hasRenamer) {
return null;
}

Expand Down Expand Up @@ -945,6 +954,15 @@ private Path createSkidConfig(List<String> javaBlackList,
builder.append("]\n }\n}\n");
}

if (hasRenamer) {
if (builder.length() > 0 && builder.charAt(builder.length() - 1) != '\n') {
builder.append('\n');
}
appendRenamerSection(builder, "classRenamer", renamerConfig.getClassConfig(), true);
appendRenamerSection(builder, "methodRenamer", renamerConfig.getMethodConfig(), false);
appendRenamerSection(builder, "fieldRenamer", renamerConfig.getFieldConfig(), false);
}

if (builder.length() == 0) {
return null;
}
Expand All @@ -954,6 +972,47 @@ private Path createSkidConfig(List<String> javaBlackList,
return configPath;
}

private void appendRenamerSection(StringBuilder builder,
String sectionName,
JvmRenamerEntityConfig entity,
boolean includeClassSettings) {
if (entity == null) {
return;
}

builder.append(sectionName).append(" {\n");
builder.append(" enabled = ").append(entity.isEnabled()).append('\n');
builder.append(" type = \"").append(entity.getMode().name()).append("\"\n");
builder.append(" depth = ").append(entity.getDepth()).append('\n');

if (includeClassSettings) {
if (entity.getPrefix() != null) {
builder.append(" prefix = \"").append(escapeForHocon(entity.getPrefix())).append("\"\n");
}
if (entity.getDirectoryDepth() != null) {
builder.append(" directoryDepth = ").append(entity.getDirectoryDepth()).append('\n');
}
if (entity.getSegmentLength() != null) {
builder.append(" segmentLength = ").append(entity.getSegmentLength()).append('\n');
}
}

if (!entity.getAlphabet().isEmpty()) {
builder.append(" chars = [\n");
for (int i = 0; i < entity.getAlphabet().size(); i++) {
String token = entity.getAlphabet().get(i);
builder.append(" \"").append(escapeForHocon(token)).append("\"");
if (i + 1 < entity.getAlphabet().size()) {
builder.append(',');
}
builder.append('\n');
}
builder.append(" ]\n");
}

builder.append("}\n\n");
}

private String convertToSkidPattern(String entry) {
if (entry == null) {
return null;
Expand Down
21 changes: 19 additions & 2 deletions obfuscator/src/main/java/by/radioegor146/ObfuscatorConfig.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package by.radioegor146;

import by.radioegor146.javaobf.JvmRenamerConfig;
import dev.skidfuscator.obfuscator.FlowExceptionMode;

import java.nio.file.Path;
Expand Down Expand Up @@ -44,6 +45,7 @@ public class ObfuscatorConfig {
private final boolean skidInvokeDynamicObfuscation;
private final FlowExceptionMode skidFlowExceptionMode;
private final JavaFlowSettings javaFlowSettings;
private final JvmRenamerConfig jvmRenamerConfig;

public ObfuscatorConfig(Path inputJarPath, Path outputDir, List<Path> inputLibs,
List<String> blackList, List<String> whiteList,
Expand All @@ -57,7 +59,8 @@ public ObfuscatorConfig(Path inputJarPath, Path outputDir, List<Path> inputLibs,
boolean skidFlowObfuscation, boolean skidSdkInjection,
boolean skidVmHashing, boolean skidInvokeDynamicObfuscation,
FlowExceptionMode skidFlowExceptionMode,
JavaFlowSettings javaFlowSettings) {
JavaFlowSettings javaFlowSettings,
JvmRenamerConfig jvmRenamerConfig) {
this.inputJarPath = inputJarPath;
this.outputDir = outputDir;
this.inputLibs = inputLibs;
Expand All @@ -83,6 +86,7 @@ public ObfuscatorConfig(Path inputJarPath, Path outputDir, List<Path> inputLibs,
this.skidInvokeDynamicObfuscation = skidInvokeDynamicObfuscation;
this.skidFlowExceptionMode = skidFlowExceptionMode;
this.javaFlowSettings = javaFlowSettings == null ? JavaFlowSettings.createDefault() : javaFlowSettings;
this.jvmRenamerConfig = jvmRenamerConfig == null ? JvmRenamerConfig.disabled() : jvmRenamerConfig;
}

// Getters for basic settings
Expand Down Expand Up @@ -116,6 +120,8 @@ public ObfuscatorConfig(Path inputJarPath, Path outputDir, List<Path> inputLibs,
public FlowExceptionMode getSkidFlowExceptionMode() { return skidFlowExceptionMode; }
public JavaFlowSettings getJavaFlowSettings() { return javaFlowSettings; }

public JvmRenamerConfig getJvmRenamerConfig() { return jvmRenamerConfig; }

// Convenience methods for accessing nested configuration properties
public boolean isVirtualizationEnabled() { return protectionConfig.isVirtualizationEnabled(); }
public boolean isJitEnabled() { return protectionConfig.isJitEnabled(); }
Expand Down Expand Up @@ -161,6 +167,7 @@ public String toString() {
" skidInvokeDynamicObfuscation=%s,\n" +
" skidFlowExceptionMode=%s,\n" +
" javaFlowSettings=%s,\n" +
" jvmRenamerConfigEnabled=%s,\n" +
" protectionConfig=%s,\n" +
" antiDebugConfig=%s\n" +
"}",
Expand All @@ -170,6 +177,7 @@ public String toString() {
skidInvokeDynamicObfuscation,
skidFlowExceptionMode,
javaFlowSettings,
jvmRenamerConfig != null && jvmRenamerConfig.isEnabled(),
protectionConfig, antiDebugConfig);
}

Expand Down Expand Up @@ -202,6 +210,7 @@ public static class Builder {
private boolean skidInvokeDynamicObfuscation = false;
private FlowExceptionMode skidFlowExceptionMode = FlowExceptionMode.STANDARD;
private JavaFlowSettings javaFlowSettings = JavaFlowSettings.createDefault();
private JvmRenamerConfig jvmRenamerConfig = JvmRenamerConfig.disabled();

public Builder setInputJarPath(Path inputJarPath) {
this.inputJarPath = inputJarPath;
Expand Down Expand Up @@ -330,6 +339,13 @@ public Builder setJavaFlowSettings(JavaFlowSettings javaFlowSettings) {
return this;
}

public Builder setJvmRenamerConfig(JvmRenamerConfig jvmRenamerConfig) {
if (jvmRenamerConfig != null) {
this.jvmRenamerConfig = jvmRenamerConfig;
}
return this;
}

public ObfuscatorConfig build() {
if (inputJarPath == null || outputDir == null) {
throw new IllegalArgumentException("Input JAR path and output directory are required");
Expand All @@ -340,7 +356,8 @@ public ObfuscatorConfig build() {
javaBlackList, javaWhiteList, enableNativeObfuscation,
skidStringObfuscation, skidNumberObfuscation,
skidFlowObfuscation, skidSdkInjection, skidVmHashing,
skidInvokeDynamicObfuscation, skidFlowExceptionMode, javaFlowSettings);
skidInvokeDynamicObfuscation, skidFlowExceptionMode, javaFlowSettings,
jvmRenamerConfig);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package by.radioegor146.javaobf;

import java.util.Objects;

/**
* Aggregated JVM renamer configuration for UI/CLI flows.
*/
public final class JvmRenamerConfig {
private final boolean enabled;
private final JvmRenamerEntityConfig classConfig;
private final JvmRenamerEntityConfig methodConfig;
private final JvmRenamerEntityConfig fieldConfig;

private JvmRenamerConfig(Builder builder) {
this.enabled = builder.enabled;
this.classConfig = builder.classConfig;
this.methodConfig = builder.methodConfig;
this.fieldConfig = builder.fieldConfig;
}

public static Builder builder() {
return new Builder();
}

public static JvmRenamerConfig disabled() {
return builder().enabled(false).build();
}

public boolean isEnabled() {
return enabled;
}

public JvmRenamerEntityConfig getClassConfig() {
return classConfig;
}

public JvmRenamerEntityConfig getMethodConfig() {
return methodConfig;
}

public JvmRenamerEntityConfig getFieldConfig() {
return fieldConfig;
}

public boolean isAnyEntityEnabled() {
return (classConfig != null && classConfig.isEnabled())
|| (methodConfig != null && methodConfig.isEnabled())
|| (fieldConfig != null && fieldConfig.isEnabled());
}

public static final class Builder {
private boolean enabled = false;
private JvmRenamerEntityConfig classConfig = JvmRenamerEntityConfig.disabled();
private JvmRenamerEntityConfig methodConfig = JvmRenamerEntityConfig.disabled();
private JvmRenamerEntityConfig fieldConfig = JvmRenamerEntityConfig.disabled();

private Builder() {
}

public Builder enabled(boolean enabled) {
this.enabled = enabled;
return this;
}

public Builder classConfig(JvmRenamerEntityConfig classConfig) {
this.classConfig = Objects.requireNonNull(classConfig, "classConfig");
return this;
}

public Builder methodConfig(JvmRenamerEntityConfig methodConfig) {
this.methodConfig = Objects.requireNonNull(methodConfig, "methodConfig");
return this;
}

public Builder fieldConfig(JvmRenamerEntityConfig fieldConfig) {
this.fieldConfig = Objects.requireNonNull(fieldConfig, "fieldConfig");
return this;
}

public JvmRenamerConfig build() {
return new JvmRenamerConfig(this);
}
}
}
Loading