Projects STRLCPY jadx Commits 54a7da22
🤬
  • feat: add package node, allow to rename packages

  • Loading...
  • Skylot committed 1 year ago
    54a7da22
    1 parent 412fd0f8
  • ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
    skipped 398 lines
    399 399   annotationGen.addForField(code, f);
    400 400   
    401 401   boolean addInfoComments = f.checkCommentsLevel(CommentsLevel.INFO);
    402  - if (f.getFieldInfo().isRenamed() && addInfoComments) {
     402 + if (f.getFieldInfo().hasAlias() && addInfoComments) {
    403 403   code.newLine();
    404 404   CodeGenUtils.addRenamedComment(code, f, f.getName());
    405 405   }
    skipped 421 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java
    skipped 71 lines
    72 72   return declClass.makeRawFullName() + '.' + name + ':' + TypeGen.signature(type);
    73 73   }
    74 74   
    75  - public boolean isRenamed() {
    76  - return !name.equals(alias);
    77  - }
    78  - 
    79 75   public boolean equalsNameAndType(FieldInfo other) {
    80 76   return name.equals(other.name) && type.equals(other.type);
    81 77   }
    skipped 29 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/info/InfoStorage.java
    skipped 2 lines
    3 3  import java.util.HashMap;
    4 4  import java.util.Map;
    5 5   
     6 +import org.jetbrains.annotations.Nullable;
     7 + 
    6 8  import jadx.core.dex.instructions.args.ArgType;
    7 9   
    8 10  public class InfoStorage {
    skipped 4 lines
    13 15   private final Map<MethodInfo, MethodInfo> uniqueMethods = new HashMap<>();
    14 16   // can contain same method with different ids (from different files)
    15 17   private final Map<Integer, MethodInfo> methods = new HashMap<>();
     18 + 
     19 + private final Map<String, PackageInfo> packages = new HashMap<>();
    16 20   
    17 21   public ClassInfo getCls(ArgType type) {
    18 22   return classes.get(type);
    skipped 38 lines
    57 61   fields.put(field, field);
    58 62   return field;
    59 63   }
     64 + }
     65 + 
     66 + public @Nullable PackageInfo getPkg(String fullName) {
     67 + return packages.get(fullName);
     68 + }
     69 + 
     70 + public void putPkg(PackageInfo pkg) {
     71 + packages.put(pkg.getFullName(), pkg);
    60 72   }
    61 73  }
    62 74   
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/info/PackageInfo.java
     1 +package jadx.core.dex.info;
     2 + 
     3 +import java.util.Objects;
     4 + 
     5 +import org.jetbrains.annotations.Nullable;
     6 + 
     7 +import jadx.core.dex.nodes.RootNode;
     8 + 
     9 +public class PackageInfo {
     10 + 
     11 + private final @Nullable PackageInfo parentPkg;
     12 + private final String fullName;
     13 + private final String name;
     14 + 
     15 + public static synchronized PackageInfo fromFullPkg(RootNode root, String fullPkg) {
     16 + PackageInfo existPkg = root.getInfoStorage().getPkg(fullPkg);
     17 + if (existPkg != null) {
     18 + return existPkg;
     19 + }
     20 + PackageInfo newPkg;
     21 + int lastDot = fullPkg.lastIndexOf('.');
     22 + if (lastDot == -1) {
     23 + // unknown root pkg
     24 + newPkg = new PackageInfo(fullPkg, null, fullPkg);
     25 + } else {
     26 + PackageInfo parentPkg = fromFullPkg(root, fullPkg.substring(0, lastDot));
     27 + newPkg = new PackageInfo(fullPkg, parentPkg, fullPkg.substring(lastDot + 1));
     28 + }
     29 + root.getInfoStorage().putPkg(newPkg);
     30 + return newPkg;
     31 + }
     32 + 
     33 + public static synchronized PackageInfo fromShortName(RootNode root, @Nullable PackageInfo parent, String shortName) {
     34 + String fullPkg = parent == null ? shortName : parent.getFullName() + '.' + shortName;
     35 + PackageInfo existPkg = root.getInfoStorage().getPkg(fullPkg);
     36 + if (existPkg != null) {
     37 + return existPkg;
     38 + }
     39 + PackageInfo newPkg = new PackageInfo(fullPkg, parent, shortName);
     40 + root.getInfoStorage().putPkg(newPkg);
     41 + return newPkg;
     42 + }
     43 + 
     44 + private PackageInfo(String fullName, @Nullable PackageInfo parentPkg, String name) {
     45 + this.fullName = fullName;
     46 + this.parentPkg = parentPkg;
     47 + this.name = name;
     48 + }
     49 + 
     50 + public boolean isRoot() {
     51 + return parentPkg == null;
     52 + }
     53 + 
     54 + public boolean isDefaultPkg() {
     55 + return fullName.isEmpty();
     56 + }
     57 + 
     58 + public String getFullName() {
     59 + return fullName;
     60 + }
     61 + 
     62 + public @Nullable PackageInfo getParentPkg() {
     63 + return parentPkg;
     64 + }
     65 + 
     66 + public String getName() {
     67 + return name;
     68 + }
     69 + 
     70 + @Override
     71 + public boolean equals(Object o) {
     72 + if (this == o) {
     73 + return true;
     74 + }
     75 + if (!(o instanceof PackageInfo)) {
     76 + return false;
     77 + }
     78 + return Objects.equals(fullName, ((PackageInfo) o).getFullName());
     79 + }
     80 + 
     81 + @Override
     82 + public int hashCode() {
     83 + return fullName.hashCode();
     84 + }
     85 + 
     86 + @Override
     87 + public String toString() {
     88 + return fullName;
     89 + }
     90 +}
     91 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
    skipped 54 lines
    55 55  import static jadx.core.dex.nodes.ProcessState.LOADED;
    56 56  import static jadx.core.dex.nodes.ProcessState.NOT_LOADED;
    57 57   
    58  -public class ClassNode extends NotificationAttrNode implements IClassNode, ILoadable, ICodeNode, Comparable<ClassNode> {
     58 +public class ClassNode extends NotificationAttrNode
     59 + implements IClassNode, ILoadable, ICodeNode, IPackageUpdate, Comparable<ClassNode> {
    59 60   private static final Logger LOG = LoggerFactory.getLogger(ClassNode.class);
    60 61   
    61 62   private final RootNode root;
    62 63   private final IClassData clsData;
    63 64   
    64 65   private final ClassInfo clsInfo;
     66 + private final PackageNode packageNode;
    65 67   private AccessInfo accessFlags;
    66 68   private ArgType superClass;
    67 69   private List<ArgType> interfaces;
    skipped 36 lines
    104 106   public ClassNode(RootNode root, IClassData cls) {
    105 107   this.root = root;
    106 108   this.clsInfo = ClassInfo.fromType(root, ArgType.object(cls.getType()));
     109 + this.packageNode = PackageNode.getForClass(root, clsInfo.getPackage(), this);
    107 110   this.clsData = cls.copy();
    108 111   initialLoad(clsData);
    109 112   }
    skipped 127 lines
    237 240   this.fields = new ArrayList<>();
    238 241   this.accessFlags = new AccessInfo(accessFlags, AFType.CLASS);
    239 242   this.parentClass = this;
     243 + this.packageNode = PackageNode.getForClass(root, clsInfo.getPackage(), this);
    240 244   }
    241 245   
    242 246   private void initStaticValues(List<FieldNode> fields) {
    skipped 324 lines
    567 571   }
    568 572   }
    569 573   parentClass = this;
     574 + }
     575 + 
     576 + @Override
     577 + public void onParentPackageUpdate(PackageNode updatedPkg) {
     578 + if (isInner()) {
     579 + return;
     580 + }
     581 + getClassInfo().changePkg(packageNode.getAliasPkgInfo().getFullName());
     582 + }
     583 + 
     584 + public PackageNode getPackageNode() {
     585 + return packageNode;
    570 586   }
    571 587   
    572 588   public ClassNode getTopParentClass() {
    skipped 299 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/nodes/IPackageUpdate.java
     1 +package jadx.core.dex.nodes;
     2 + 
     3 +public interface IPackageUpdate {
     4 + 
     5 + void onParentPackageUpdate(PackageNode updatedPkg);
     6 +}
     7 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/nodes/PackageNode.java
     1 +package jadx.core.dex.nodes;
     2 + 
     3 +import java.util.ArrayList;
     4 +import java.util.List;
     5 + 
     6 +import org.jetbrains.annotations.NotNull;
     7 +import org.jetbrains.annotations.Nullable;
     8 + 
     9 +import jadx.core.dex.info.PackageInfo;
     10 + 
     11 +public class PackageNode implements IPackageUpdate, IDexNode, Comparable<PackageNode> {
     12 + 
     13 + private final RootNode root;
     14 + private final PackageInfo pkgInfo;
     15 + private final @Nullable PackageNode parentPkg;
     16 + private final List<PackageNode> subPackages = new ArrayList<>();
     17 + private final List<ClassNode> classes = new ArrayList<>();
     18 + 
     19 + private PackageInfo aliasPkgInfo;
     20 + 
     21 + public static PackageNode getForClass(RootNode root, String fullPkg, ClassNode cls) {
     22 + PackageNode pkg = getOrBuild(root, fullPkg);
     23 + pkg.getClasses().add(cls);
     24 + return pkg;
     25 + }
     26 + 
     27 + public static PackageNode getOrBuild(RootNode root, String fullPkg) {
     28 + PackageNode existPkg = root.resolvePackage(fullPkg);
     29 + if (existPkg != null) {
     30 + return existPkg;
     31 + }
     32 + PackageInfo pgkInfo = PackageInfo.fromFullPkg(root, fullPkg);
     33 + PackageNode parentPkg = getParentPkg(root, pgkInfo);
     34 + PackageNode pkgNode = new PackageNode(root, parentPkg, pgkInfo);
     35 + if (parentPkg != null) {
     36 + parentPkg.getSubPackages().add(pkgNode);
     37 + }
     38 + root.addPackage(pkgNode);
     39 + return pkgNode;
     40 + }
     41 + 
     42 + private static @Nullable PackageNode getParentPkg(RootNode root, PackageInfo pgkInfo) {
     43 + return root.resolvePackage(pgkInfo.getParentPkg());
     44 + }
     45 + 
     46 + private PackageNode(RootNode root, @Nullable PackageNode parentPkg, PackageInfo pkgInfo) {
     47 + this.root = root;
     48 + this.parentPkg = parentPkg;
     49 + this.pkgInfo = pkgInfo;
     50 + }
     51 + 
     52 + public void rename(String alias) {
     53 + rename(alias, true);
     54 + }
     55 + 
     56 + public void rename(String alias, boolean runUpdates) {
     57 + if (pkgInfo.getName().equals(alias)) {
     58 + aliasPkgInfo = pkgInfo;
     59 + return;
     60 + }
     61 + aliasPkgInfo = PackageInfo.fromShortName(root, getParentAliasPkgInfo(), alias);
     62 + if (runUpdates) {
     63 + updatePackages(this);
     64 + }
     65 + }
     66 + 
     67 + @Override
     68 + public void onParentPackageUpdate(PackageNode updatedPkg) {
     69 + aliasPkgInfo = PackageInfo.fromShortName(root, getParentAliasPkgInfo(), aliasPkgInfo.getName());
     70 + updatePackages(updatedPkg);
     71 + }
     72 + 
     73 + public void updatePackages() {
     74 + updatePackages(this);
     75 + }
     76 + 
     77 + private void updatePackages(PackageNode updatedPkg) {
     78 + for (PackageNode subPackage : subPackages) {
     79 + subPackage.onParentPackageUpdate(updatedPkg);
     80 + }
     81 + for (ClassNode cls : classes) {
     82 + cls.onParentPackageUpdate(updatedPkg);
     83 + }
     84 + }
     85 + 
     86 + public PackageInfo getPkgInfo() {
     87 + return pkgInfo;
     88 + }
     89 + 
     90 + public PackageInfo getAliasPkgInfo() {
     91 + return aliasPkgInfo;
     92 + }
     93 + 
     94 + public PackageNode getParentPkg() {
     95 + return parentPkg;
     96 + }
     97 + 
     98 + public @Nullable PackageInfo getParentAliasPkgInfo() {
     99 + return parentPkg == null ? null : parentPkg.aliasPkgInfo;
     100 + }
     101 + 
     102 + public List<PackageNode> getSubPackages() {
     103 + return subPackages;
     104 + }
     105 + 
     106 + public List<ClassNode> getClasses() {
     107 + return classes;
     108 + }
     109 + 
     110 + @Override
     111 + public String typeName() {
     112 + return "package";
     113 + }
     114 + 
     115 + @Override
     116 + public RootNode root() {
     117 + return root;
     118 + }
     119 + 
     120 + @Override
     121 + public String getInputFileName() {
     122 + return "";
     123 + }
     124 + 
     125 + @Override
     126 + public boolean equals(Object o) {
     127 + if (this == o) {
     128 + return true;
     129 + }
     130 + if (!(o instanceof PackageNode)) {
     131 + return false;
     132 + }
     133 + return pkgInfo.equals(((PackageNode) o).pkgInfo);
     134 + }
     135 + 
     136 + @Override
     137 + public int hashCode() {
     138 + return pkgInfo.hashCode();
     139 + }
     140 + 
     141 + @Override
     142 + public int compareTo(@NotNull PackageNode other) {
     143 + return getPkgInfo().getFullName().compareTo(other.getPkgInfo().getFullName());
     144 + }
     145 + 
     146 + @Override
     147 + public String toString() {
     148 + return getPkgInfo().getFullName();
     149 + }
     150 +}
     151 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
    1 1  package jadx.core.dex.nodes;
    2 2   
    3 3  import java.util.ArrayList;
     4 +import java.util.Collections;
    4 5  import java.util.Comparator;
    5 6  import java.util.HashMap;
    6 7  import java.util.List;
    skipped 30 lines
    37 38  import jadx.core.dex.info.FieldInfo;
    38 39  import jadx.core.dex.info.InfoStorage;
    39 40  import jadx.core.dex.info.MethodInfo;
     41 +import jadx.core.dex.info.PackageInfo;
    40 42  import jadx.core.dex.instructions.args.ArgType;
    41 43  import jadx.core.dex.nodes.utils.MethodUtils;
    42 44  import jadx.core.dex.nodes.utils.TypeUtils;
    skipped 33 lines
    76 78   
    77 79   private final Map<ClassInfo, ClassNode> clsMap = new HashMap<>();
    78 80   private List<ClassNode> classes = new ArrayList<>();
     81 + 
     82 + private final Map<String, PackageNode> pkgMap = new HashMap<>();
    79 83   
    80 84   private ClspGraph clsp;
    81 85   @Nullable
    skipped 254 lines
    336 340   }
    337 341   }
    338 342   return notInnerClasses;
     343 + }
     344 + 
     345 + public List<PackageNode> getPackages() {
     346 + List<PackageNode> list = new ArrayList<>(pkgMap.values());
     347 + Collections.sort(list);
     348 + return list;
     349 + }
     350 + 
     351 + public @Nullable PackageNode resolvePackage(String fullPkg) {
     352 + return pkgMap.get(fullPkg);
     353 + }
     354 + 
     355 + public @Nullable PackageNode resolvePackage(@Nullable PackageInfo pkgInfo) {
     356 + return pkgInfo == null ? null : pkgMap.get(pkgInfo.getFullName());
     357 + }
     358 + 
     359 + public void addPackage(PackageNode pkg) {
     360 + pkgMap.put(pkg.getPkgInfo().getFullName(), pkg);
    339 361   }
    340 362   
    341 363   @Nullable
    skipped 247 lines
  • ■ ■ ■ ■ ■ ■
    jadx-plugins/jadx-script/examples/build.gradle.kts
    skipped 8 lines
    9 9   implementation("org.jetbrains.kotlin:kotlin-script-runtime")
    10 10   
    11 11   implementation("io.github.microutils:kotlin-logging-jvm:3.0.2")
     12 + 
     13 + // manual imports ( IDE can't import dependencies by scripts annotations)
     14 + implementation("com.github.javafaker:javafaker:1.0.2")
    12 15  }
    13 16   
    14 17  sourceSets {
    skipped 5 lines
  • ■ ■ ■ ■ ■ ■
    jadx-plugins/jadx-script/examples/scripts/deobf2.jadx.kts
     1 +// animal deobfuscator ^_^
     2 +@file:DependsOn("com.github.javafaker:javafaker:1.0.2")
     3 + 
     4 +import com.github.javafaker.Faker
     5 +import jadx.core.deobf.NameMapper
     6 +import java.util.Random
     7 + 
     8 +val jadx = getJadxInstance()
     9 +jadx.args.isDeobfuscationOn = false
     10 +jadx.args.renameFlags = emptySet()
     11 + 
     12 +val regex = """[Oo0]+""".toRegex()
     13 +val usedNames = mutableSetOf<String>()
     14 +val faker = Faker(Random(1))
     15 +var dups = 1
     16 + 
     17 +jadx.rename.all { name, node ->
     18 + when {
     19 + name matches regex -> {
     20 + val prefix = node.typeName().first()
     21 + val alias = faker.name().firstName().cap() + faker.animal().name().cap()
     22 + makeUnique(prefix, alias)
     23 + }
     24 + else -> null
     25 + }
     26 +}
     27 + 
     28 +fun makeUnique(prefix: Char, name: String): String {
     29 + while (true) {
     30 + val resName = prefix + NameMapper.removeInvalidCharsMiddle(name)
     31 + return if (usedNames.add(resName)) resName else "$resName${dups++}"
     32 + }
     33 +}
     34 + 
     35 +jadx.afterLoad {
     36 + println("Renames count: ${usedNames.size + dups}, names: ${usedNames.size}, dups: $dups")
     37 +}
     38 + 
     39 +fun String.cap() = this.replaceFirstChar(Char::uppercaseChar)
     40 + 
  • ■ ■ ■ ■ ■
    jadx-plugins/jadx-script/jadx-script-runtime/src/main/kotlin/jadx/plugins/script/runtime/data/rename.kt
    skipped 11 lines
    12 12   }
    13 13   
    14 14   fun all(makeNewName: (String, IDexNode) -> String?) {
    15  - jadx.addPass(object : ScriptPreparePass(jadx, "RenameAll") {
     15 + jadx.addPass(object : ScriptOrderedPreparePass(
     16 + jadx,
     17 + "RenameAll",
     18 + runBefore = listOf("RenameVisitor")
     19 + ) {
    16 20   override fun init(root: IRootNode) {
    17 21   val rootNode = root as RootNode
     22 + for (pkgNode in rootNode.packages) {
     23 + makeNewName.invoke(pkgNode.pkgInfo.name, pkgNode)?.let {
     24 + pkgNode.rename(it)
     25 + }
     26 + }
    18 27   for (cls in rootNode.classes) {
    19 28   makeNewName.invoke(cls.classInfo.shortName, cls)?.let {
    20 29   cls.classInfo.changeShortName(it)
    skipped 20 lines
  • ■ ■ ■ ■ ■ ■
    jadx-plugins/jadx-script/jadx-script-runtime/src/main/kotlin/jadx/plugins/script/runtime/script.kt
    skipped 22 lines
    23 23   wholeClasspath = true
    24 24   )
    25 25   }
     26 + ide {
     27 + acceptedLocations(ScriptAcceptedLocation.Everywhere)
     28 + }
    26 29   
    27 30   baseClass(JadxScriptBaseClass::class)
    28 31   
    skipped 19 lines
Please wait...
Page is in error, reload to recover