feat: add options to configure "renaming" (#570) (PR #582)

This commit is contained in:
Ahmed Ashour
2019-04-12 17:08:50 +02:00
committed by skylot
parent a1bfdc6323
commit 74a72a5ce0
10 changed files with 309 additions and 47 deletions
+63 -19
View File
@@ -3,7 +3,9 @@ package jadx.api;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
public class JadxArgs {
@@ -30,11 +32,11 @@ public class JadxArgs {
private boolean useImports = true;
private boolean debugInfo = true;
private boolean isSkipResources = false;
private boolean isSkipSources = false;
private boolean skipResources = false;
private boolean skipSources = false;
private boolean isDeobfuscationOn = false;
private boolean isDeobfuscationForceSave = false;
private boolean deobfuscationOn = false;
private boolean deobfuscationForceSave = false;
private boolean useSourceNameAsClassAlias = false;
private int deobfuscationMinLength = 0;
@@ -45,7 +47,11 @@ public class JadxArgs {
private boolean respectBytecodeAccModifiers = false;
private boolean exportAsGradleProject = false;
private boolean isFsCaseSensitive;
private boolean fsCaseSensitive;
public enum RENAME {CASE, VALID, PRINTABLE}
private Set<RENAME> renameFlags = EnumSet.allOf(RENAME.class);
public JadxArgs() {
// use default options
@@ -150,35 +156,35 @@ public class JadxArgs {
}
public boolean isSkipResources() {
return isSkipResources;
return skipResources;
}
public void setSkipResources(boolean skipResources) {
isSkipResources = skipResources;
this.skipResources = skipResources;
}
public boolean isSkipSources() {
return isSkipSources;
return skipSources;
}
public void setSkipSources(boolean skipSources) {
isSkipSources = skipSources;
this.skipSources = skipSources;
}
public boolean isDeobfuscationOn() {
return isDeobfuscationOn;
return deobfuscationOn;
}
public void setDeobfuscationOn(boolean deobfuscationOn) {
isDeobfuscationOn = deobfuscationOn;
this.deobfuscationOn = deobfuscationOn;
}
public boolean isDeobfuscationForceSave() {
return isDeobfuscationForceSave;
return deobfuscationForceSave;
}
public void setDeobfuscationForceSave(boolean deobfuscationForceSave) {
isDeobfuscationForceSave = deobfuscationForceSave;
this.deobfuscationForceSave = deobfuscationForceSave;
}
public boolean isUseSourceNameAsClassAlias() {
@@ -238,11 +244,47 @@ public class JadxArgs {
}
public boolean isFsCaseSensitive() {
return isFsCaseSensitive;
return fsCaseSensitive;
}
public void setFsCaseSensitive(boolean fsCaseSensitive) {
isFsCaseSensitive = fsCaseSensitive;
this.fsCaseSensitive = fsCaseSensitive;
}
public boolean isRenameCaseSensitive() {
return renameFlags.contains(RENAME.CASE);
}
public void setRenameCaseSensitive(boolean renameCaseSensitive) {
if (renameCaseSensitive && !isRenameCaseSensitive()) {
renameFlags.add(RENAME.CASE);
} else if (!renameCaseSensitive && isRenameCaseSensitive()) {
renameFlags.remove(RENAME.CASE);
}
}
public boolean isRenameValid() {
return renameFlags.contains(RENAME.VALID);
}
public void setRenameValid(boolean renameValid) {
if (renameValid && !isRenameValid()) {
renameFlags.add(RENAME.VALID);
} else if (!renameValid && isRenameValid()) {
renameFlags.remove(RENAME.VALID);
}
}
public boolean isRenamePrintable() {
return renameFlags.contains(RENAME.PRINTABLE);
}
public void setRenamePrintable(boolean renamePrintable) {
if (renamePrintable && !isRenamePrintable()) {
renameFlags.add(RENAME.PRINTABLE);
} else if (!renamePrintable && isRenamePrintable()) {
renameFlags.remove(RENAME.PRINTABLE);
}
}
@Override
@@ -257,10 +299,10 @@ public class JadxArgs {
", fallbackMode=" + fallbackMode +
", showInconsistentCode=" + showInconsistentCode +
", useImports=" + useImports +
", isSkipResources=" + isSkipResources +
", isSkipSources=" + isSkipSources +
", isDeobfuscationOn=" + isDeobfuscationOn +
", isDeobfuscationForceSave=" + isDeobfuscationForceSave +
", skipResources=" + skipResources +
", skipSources=" + skipSources +
", deobfuscationOn=" + deobfuscationOn +
", deobfuscationForceSave=" + deobfuscationForceSave +
", useSourceNameAsClassAlias=" + useSourceNameAsClassAlias +
", deobfuscationMinLength=" + deobfuscationMinLength +
", deobfuscationMaxLength=" + deobfuscationMaxLength +
@@ -268,6 +310,8 @@ public class JadxArgs {
", replaceConsts=" + replaceConsts +
", respectBytecodeAccModifiers=" + respectBytecodeAccModifiers +
", exportAsGradleProject=" + exportAsGradleProject +
", fsCaseSensitive=" + fsCaseSensitive +
", renameFlags=" + renameFlags +
'}';
}
}
@@ -80,15 +80,13 @@ public class NameMapper {
public static boolean isValidIdentifier(String str) {
return notEmpty(str)
&& !isReserved(str)
&& VALID_JAVA_IDENTIFIER.matcher(str).matches()
&& isAllCharsPrintable(str);
&& VALID_JAVA_IDENTIFIER.matcher(str).matches();
}
public static boolean isValidFullIdentifier(String str) {
return notEmpty(str)
&& !isReserved(str)
&& VALID_JAVA_FULL_IDENTIFIER.matcher(str).matches()
&& isAllCharsPrintable(str);
&& VALID_JAVA_FULL_IDENTIFIER.matcher(str).matches();
}
public static boolean isValidIdentifierStart(int codePoint) {
@@ -43,17 +43,17 @@ public class RenameVisitor extends AbstractVisitor {
if (deobfuscationOn) {
deobfuscator.execute();
}
checkClasses(root, args.isFsCaseSensitive());
checkClasses(root, args);
}
private void checkClasses(RootNode root, boolean caseSensitive) {
private void checkClasses(RootNode root, JadxArgs args) {
List<ClassNode> classes = root.getClasses(true);
for (ClassNode cls : classes) {
checkClassName(cls);
checkFields(cls);
checkMethods(cls);
checkClassName(cls, args);
checkFields(cls, args);
checkMethods(cls, args);
}
if (!caseSensitive) {
if (!args.isFsCaseSensitive() && args.isRenameCaseSensitive()) {
Set<String> clsFullPaths = new HashSet<>(classes.size());
for (ClassNode cls : classes) {
ClassInfo clsInfo = cls.getClassInfo();
@@ -69,12 +69,12 @@ public class RenameVisitor extends AbstractVisitor {
}
}
private void checkClassName(ClassNode cls) {
private void checkClassName(ClassNode cls, JadxArgs args) {
ClassInfo classInfo = cls.getClassInfo();
ClassInfo alias = classInfo.getAlias();
String clsName = alias.getShortName();
String newShortName = fixClsShortName(clsName);
String newShortName = fixClsShortName(args, clsName);
if (!newShortName.equals(clsName)) {
classInfo.rename(cls.root(), alias.makeFullClsName(newShortName, true));
alias = classInfo.getAlias();
@@ -86,35 +86,42 @@ public class RenameVisitor extends AbstractVisitor {
}
}
private String fixClsShortName(String clsName) {
private String fixClsShortName(JadxArgs args, String clsName) {
char firstChar = clsName.charAt(0);
if (Character.isDigit(firstChar)) {
boolean renameValid = args.isRenameValid();
if (Character.isDigit(firstChar) && renameValid) {
return Consts.ANONYMOUS_CLASS_PREFIX + NameMapper.removeInvalidCharsMiddle(clsName);
}
if (firstChar == '$') {
if (firstChar == '$' && renameValid) {
return 'C' + NameMapper.removeInvalidCharsMiddle(clsName);
}
String cleanClsName = NameMapper.removeInvalidChars(clsName, "C");
if (!NameMapper.isValidIdentifier(cleanClsName)) {
String cleanClsName = args.isRenamePrintable()
? NameMapper.removeInvalidChars(clsName, "C")
: clsName;
if (renameValid && !NameMapper.isValidIdentifier(cleanClsName)) {
return 'C' + cleanClsName;
}
return cleanClsName;
}
private void checkFields(ClassNode cls) {
private void checkFields(ClassNode cls, JadxArgs args) {
Set<String> names = new HashSet<>();
for (FieldNode field : cls.getFields()) {
FieldInfo fieldInfo = field.getFieldInfo();
String fieldName = fieldInfo.getAlias();
if (!names.add(fieldName) || !NameMapper.isValidIdentifier(fieldName)) {
if (!names.add(fieldName)
|| (args.isRenameValid() && !NameMapper.isValidIdentifier(fieldName))
|| (args.isRenamePrintable() && !NameMapper.isAllCharsPrintable(fieldName))) {
deobfuscator.forceRenameField(field);
}
}
}
private void checkMethods(ClassNode cls) {
private void checkMethods(ClassNode cls, JadxArgs args) {
for (MethodNode mth : cls.getMethods()) {
if (!NameMapper.isValidIdentifier(mth.getAlias())) {
String alias = mth.getAlias();
if (args.isRenameValid() && !NameMapper.isValidIdentifier(alias)
|| (args.isRenamePrintable() && !NameMapper.isAllCharsPrintable(alias))) {
deobfuscator.forceRenameMethod(mth);
}
}