Compare commits

...

4 Commits

Author SHA1 Message Date
Skylot 5640f3b931 fix test 2024-06-02 18:21:21 +01:00
Skylot 02bc27e887 build exclude list in init method to improve performance, add default values migration 2024-06-02 18:21:04 +01:00
bagipro 794e5adb7f Change deobf-min default to 2 2024-05-09 18:22:02 +07:00
bagipro a81cec7701 Improve deobf whitelist 2024-05-08 16:16:08 +07:00
9 changed files with 106 additions and 27 deletions
+1 -1
View File
@@ -128,7 +128,7 @@ options:
--deobf - activate deobfuscation
--deobf-min - min length of name, renamed if shorter, default: 3
--deobf-max - max length of name, renamed if longer, default: 64
--deobf-whitelist - space separated list of classes (full name) and packages (ends with '.*') to exclude from deobfuscation, default: android.support.v4.* android.support.v7.* android.support.v4.os.* android.support.annotation.Px androidx.core.os.* androidx.annotation.Px
--deobf-whitelist - space separated list of classes (full name) and packages (ends with '.*') to exclude from deobfuscation, default: android.support.* android.os.* androidx.core.os.* androidx.annotation.*
--deobf-cfg-file - deobfuscation mappings file used for JADX auto-generated names (in the JOBF file format), default: same dir and name as input file with '.jobf' extension
--deobf-cfg-file-mode - set mode for handling the JADX auto-generated names' deobfuscation map file:
'read' - read if found, don't save (default)
@@ -110,7 +110,7 @@ public class JadxArgs implements Closeable {
/**
* List of classes and packages (ends with '.*') to exclude from deobfuscation
*/
private List<String> deobfuscationWhitelist = DeobfWhitelist.DEFAULT_LIST;
private List<String> deobfuscationWhitelist = new ArrayList<>(DeobfWhitelist.DEFAULT_LIST);
/**
* Nodes alias provider for deobfuscator and rename visitor
@@ -118,7 +118,6 @@ public final class JadxDecompiler implements Closeable {
loadInputFiles();
root = new RootNode(args);
root.init();
root.setDecompilerRef(this);
root.mergePasses(customPasses);
root.loadClasses(loadedInputs);
@@ -13,6 +13,7 @@ import org.slf4j.LoggerFactory;
import jadx.api.CommentsLevel;
import jadx.api.JadxArgs;
import jadx.core.deobf.DeobfuscatorVisitor;
import jadx.core.deobf.InitRenameProviders;
import jadx.core.deobf.SaveDeobfMapping;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.visitors.AnonymousClassVisitor;
@@ -102,6 +103,7 @@ public class Jadx {
passes.add(new CollectConstValues());
// rename and deobfuscation
passes.add(new InitRenameProviders());
passes.add(new DeobfuscatorVisitor());
passes.add(new SourceFileRename());
passes.add(new RenameVisitor());
@@ -0,0 +1,20 @@
package jadx.core.deobf;
import jadx.api.JadxArgs;
import jadx.core.dex.nodes.RootNode;
import jadx.core.dex.visitors.AbstractVisitor;
import jadx.core.utils.exceptions.JadxException;
public class InitRenameProviders extends AbstractVisitor {
@Override
public void init(RootNode root) throws JadxException {
JadxArgs args = root.getArgs();
if (args.isDeobfuscationOn() || !args.getRenameFlags().isEmpty()) {
args.getAliasProvider().init(root);
}
if (args.isDeobfuscationOn()) {
args.getRenameCondition().init(root);
}
}
}
@@ -5,39 +5,81 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.FieldNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.PackageNode;
import jadx.core.dex.nodes.RootNode;
import jadx.core.utils.Utils;
public class DeobfWhitelist extends AbstractDeobfCondition {
private static final Logger LOG = LoggerFactory.getLogger(DeobfWhitelist.class);
public static final List<String> DEFAULT_LIST = Arrays.asList(
"android.support.v4.*",
"android.support.v7.*",
"android.support.v4.os.*",
"android.support.annotation.Px",
"android.support.*",
"android.os.*",
"androidx.core.os.*",
"androidx.annotation.Px");
"androidx.annotation.*");
public static final String DEFAULT_STR = Utils.listToString(DEFAULT_LIST, " ");
private final Set<String> packages = new HashSet<>();
private final Set<String> classes = new HashSet<>();
private final Set<ClassNode> classes = new HashSet<>();
private boolean reportMissingItems = false;
@Override
public void init(RootNode root) {
packages.clear();
classes.clear();
for (String whitelistItem : root.getArgs().getDeobfuscationWhitelist()) {
if (!whitelistItem.isEmpty()) {
if (whitelistItem.endsWith(".*")) {
packages.add(whitelistItem.substring(0, whitelistItem.length() - 2));
} else {
classes.add(whitelistItem);
}
List<String> excludeList = root.getArgs().getDeobfuscationWhitelist();
reportMissingItems = !excludeList.equals(DEFAULT_LIST);
for (String name : excludeList) {
if (name.isEmpty()) {
continue;
}
if (name.endsWith(".*")) {
excludePackage(root, name.substring(0, name.length() - 2));
} else {
excludeClass(root, name);
}
}
LOG.debug("Excluded from deobfuscation: {} packages, {} classes", packages.size(), classes.size());
}
private void excludeClass(RootNode root, String clsFullName) {
ClassNode cls = root.resolveClass(clsFullName);
if (cls == null) {
if (reportMissingItems) {
LOG.info("Can't exclude from deobfuscation: class '{}' not found", clsFullName);
}
return;
}
excludeClsNode(cls);
}
private void excludeClsNode(ClassNode cls) {
classes.add(cls);
cls.addInfoComment("Class excluded from deobfuscation");
}
private void excludePackage(RootNode root, String fullPkgName) {
PackageNode pkg = root.resolvePackage(fullPkgName);
if (pkg == null) {
if (reportMissingItems) {
LOG.info("Can't exclude from deobfuscation: package '{}' not found", fullPkgName);
}
return;
}
excludePkgNode(pkg);
}
private void excludePkgNode(PackageNode pkg) {
packages.add(pkg.getFullName());
pkg.getClasses().forEach(this::excludeClsNode);
pkg.getSubPackages().forEach(this::excludePkgNode);
}
@Override
@@ -50,9 +92,19 @@ public class DeobfWhitelist extends AbstractDeobfCondition {
@Override
public Action check(ClassNode cls) {
if (classes.contains(cls.getClassInfo().getFullName())) {
if (classes.contains(cls)) {
return Action.FORBID_RENAME;
}
return Action.NO_ACTION;
}
@Override
public Action check(FieldNode fld) {
return check(fld.getParentClass());
}
@Override
public Action check(MethodNode mth) {
return check(mth.getParentClass());
}
}
@@ -109,15 +109,6 @@ public class RootNode {
this.typeUtils = new TypeUtils(this);
}
public void init() {
if (args.isDeobfuscationOn() || !args.getRenameFlags().isEmpty()) {
args.getAliasProvider().init(this);
}
if (args.isDeobfuscationOn()) {
args.getRenameCondition().init(this);
}
}
public void loadClasses(List<ICodeLoader> loadedInputs) {
for (ICodeLoader codeLoader : loadedInputs) {
codeLoader.visitClasses(cls -> {
@@ -1,9 +1,14 @@
package jadx.tests.integration.deobf.a;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import jadx.api.deobf.IDeobfCondition;
import jadx.api.deobf.impl.CombineDeobfConditions;
import jadx.core.deobf.conditions.AvoidClsAndPkgNamesCollision;
import jadx.core.deobf.conditions.JadxRenameConditions;
import jadx.tests.api.IntegrationTest;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
@@ -34,6 +39,11 @@ public class TestNegativeRenameCondition extends IntegrationTest {
// disable all renaming options
args.setRenameFlags(Collections.emptySet());
// disable rename by collision between class and package names
List<IDeobfCondition> list = JadxRenameConditions.buildDefaultDeobfConditions();
list.removeIf(c -> c.getClass().equals(AvoidClsAndPkgNamesCollision.class));
args.setRenameCondition(CombineDeobfConditions.combine(list));
assertThat(getClassNode(TestCls.class))
.code()
.doesNotContain("renamed from")
@@ -35,6 +35,7 @@ import jadx.api.args.ResourceNameSource;
import jadx.api.args.UserRenamesMappingsMode;
import jadx.cli.JadxCLIArgs;
import jadx.cli.LogHelper;
import jadx.core.deobf.conditions.DeobfWhitelist;
import jadx.gui.cache.code.CodeCacheMode;
import jadx.gui.cache.usage.UsageCacheMode;
import jadx.gui.settings.data.ShortcutsWrapper;
@@ -53,7 +54,7 @@ public class JadxSettings extends JadxCLIArgs {
private static final Path USER_HOME = Paths.get(System.getProperty("user.home"));
private static final int RECENT_PROJECTS_COUNT = 30;
private static final int CURRENT_SETTINGS_VERSION = 20;
private static final int CURRENT_SETTINGS_VERSION = 21;
private static final Font DEFAULT_FONT = new RSyntaxTextArea().getFont();
@@ -805,6 +806,10 @@ public class JadxSettings extends JadxCLIArgs {
tabDndGhostType = TabDndGhostType.OUTLINE;
fromVersion++;
}
if (fromVersion == 20) {
deobfuscationWhitelistStr = DeobfWhitelist.DEFAULT_STR;
fromVersion++;
}
if (fromVersion != CURRENT_SETTINGS_VERSION) {
LOG.warn("Incorrect settings upgrade. Expected version: {}, got: {}", CURRENT_SETTINGS_VERSION, fromVersion);
}