Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add classname parsing for Kotlin metadata #842

Merged
merged 1 commit into from
Feb 2, 2020
Merged
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
8 changes: 8 additions & 0 deletions jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ public class JadxCLIArgs {
@Parameter(names = { "--deobf-use-sourcename" }, description = "use source file name as class name alias")
protected boolean deobfuscationUseSourceNameAsAlias = false;

@Parameter(names = { "--deobf-parse-kotlin-metadata" }, description = "parse kotlin metadata to class and package names")
protected boolean deobfuscationParseKotlinMetadata = false;

@Parameter(
names = { "--rename-flags" },
description = "what to rename, comma-separated,"
Expand Down Expand Up @@ -194,6 +197,7 @@ public JadxArgs toJadxArgs() {
args.setDeobfuscationMinLength(deobfuscationMinLength);
args.setDeobfuscationMaxLength(deobfuscationMaxLength);
args.setUseSourceNameAsClassAlias(deobfuscationUseSourceNameAsAlias);
args.setParseKotlinMetadata(deobfuscationParseKotlinMetadata);
args.setEscapeUnicode(escapeUnicode);
args.setRespectBytecodeAccModifiers(respectBytecodeAccessModifiers);
args.setExportAsGradleProject(exportAsGradleProject);
Expand Down Expand Up @@ -275,6 +279,10 @@ public boolean isDeobfuscationUseSourceNameAsAlias() {
return deobfuscationUseSourceNameAsAlias;
}

public boolean isDeobfuscationParseKotlinMetadata() {
return deobfuscationParseKotlinMetadata;
}

public boolean isEscapeUnicode() {
return escapeUnicode;
}
Expand Down
10 changes: 10 additions & 0 deletions jadx-core/src/main/java/jadx/api/JadxArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class JadxArgs {
private boolean deobfuscationOn = false;
private boolean deobfuscationForceSave = false;
private boolean useSourceNameAsClassAlias = false;
private boolean parseKotlinMetadata = false;

private int deobfuscationMinLength = 0;
private int deobfuscationMaxLength = Integer.MAX_VALUE;
Expand Down Expand Up @@ -230,6 +231,14 @@ public void setUseSourceNameAsClassAlias(boolean useSourceNameAsClassAlias) {
this.useSourceNameAsClassAlias = useSourceNameAsClassAlias;
}

public boolean isParseKotlinMetadata() {
return parseKotlinMetadata;
}

public void setParseKotlinMetadata(boolean parseKotlinMetadata) {
this.parseKotlinMetadata = parseKotlinMetadata;
}

public int getDeobfuscationMinLength() {
return deobfuscationMinLength;
}
Expand Down Expand Up @@ -355,6 +364,7 @@ public String toString() {
+ ", deobfuscationOn=" + deobfuscationOn
+ ", deobfuscationForceSave=" + deobfuscationForceSave
+ ", useSourceNameAsClassAlias=" + useSourceNameAsClassAlias
+ ", parseKotlinMetadata=" + parseKotlinMetadata
+ ", deobfuscationMinLength=" + deobfuscationMinLength
+ ", deobfuscationMaxLength=" + deobfuscationMaxLength
+ ", escapeUnicode=" + escapeUnicode
Expand Down
49 changes: 46 additions & 3 deletions jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ public class Deobfuscator {

public static final String CLASS_NAME_SEPARATOR = ".";
public static final String INNER_CLASS_SEPARATOR = "$";
public static final String KOTLIN_METADATA_ANNOTATION = "kotlin.Metadata";
public static final String KOTLIN_METADATA_D2_PARAMETER = "d2";
public static final String KOTLIN_METADATA_CLASSNAME_REGEX = "(L.*;)";

private final JadxArgs args;
@NotNull
Expand All @@ -57,6 +60,7 @@ public class Deobfuscator {
private final int maxLength;
private final int minLength;
private final boolean useSourceNameAsAlias;
private final boolean parseKotlinMetadata;

private int pkgIndex = 0;
private int clsIndex = 0;
Expand All @@ -70,6 +74,7 @@ public Deobfuscator(JadxArgs args, @NotNull List<DexNode> dexNodes, Path deobfMa
this.minLength = args.getDeobfuscationMinLength();
this.maxLength = args.getDeobfuscationMaxLength();
this.useSourceNameAsAlias = args.isUseSourceNameAsClassAlias();
this.parseKotlinMetadata = args.isParseKotlinMetadata();

this.deobfPresets = new DeobfPresets(this, deobfMapFile);
}
Expand Down Expand Up @@ -392,21 +397,59 @@ public String getPkgAlias(ClassNode cls) {

private String makeClsAlias(ClassNode cls) {
ClassInfo classInfo = cls.getClassInfo();

String metadataClassName = "";
String metadataPackageName = "";
if (this.parseKotlinMetadata) {
String rawClassName = getRawClassNameFromMetadata(cls);
if (rawClassName != null) {
metadataClassName = rawClassName.substring(rawClassName.lastIndexOf(".") + 1, rawClassName.length() - 1);
if (rawClassName.lastIndexOf(".") != -1) {
metadataPackageName = rawClassName.substring(1, rawClassName.lastIndexOf("."));
}
}
}
String alias = null;

if (this.useSourceNameAsAlias) {
alias = getAliasFromSourceFile(cls);
}

if (alias == null) {
String clsName = classInfo.getShortName();
alias = String.format("C%04d%s", clsIndex++, prepareNamePart(clsName));
if (metadataClassName.isEmpty()) {
String clsName = classInfo.getShortName();
alias = String.format("C%04d%s", clsIndex++, prepareNamePart(clsName));
} else {
alias = metadataClassName;
}
}
PackageNode pkg;
if (metadataPackageName.isEmpty()) {
pkg = getPackageNode(classInfo.getPackage(), true);
} else {
pkg = getPackageNode(metadataPackageName, true);
}
PackageNode pkg = getPackageNode(classInfo.getPackage(), true);
clsMap.put(classInfo, new DeobfClsInfo(this, cls, pkg, alias));
return alias;
}

@Nullable
private String getRawClassNameFromMetadata(ClassNode cls) {
if (cls.getAnnotation(KOTLIN_METADATA_ANNOTATION) != null
&& cls.getAnnotation(KOTLIN_METADATA_ANNOTATION).getValues().get(KOTLIN_METADATA_D2_PARAMETER) != null
&& cls.getAnnotation(KOTLIN_METADATA_ANNOTATION).getValues().get(KOTLIN_METADATA_D2_PARAMETER) instanceof List) {
Object rawClassNameObject =
((List) cls.getAnnotation(KOTLIN_METADATA_ANNOTATION).getValues().get(KOTLIN_METADATA_D2_PARAMETER)).get(0);
if (rawClassNameObject instanceof String) {
String rawClassName = ((String) rawClassNameObject).trim().replace("/", ".");
if (rawClassName.length() > 1 && rawClassName.matches(KOTLIN_METADATA_CLASSNAME_REGEX)) {
return rawClassName;
}
}
}
return null;
}

@Nullable
private String getAliasFromSourceFile(ClassNode cls) {
SourceFileAttr sourceFileAttr = cls.get(AType.SOURCE_FILE);
Expand Down
5 changes: 5 additions & 0 deletions jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,10 @@ public void setDeobfuscationUseSourceNameAsAlias(boolean deobfuscationUseSourceN
this.deobfuscationUseSourceNameAsAlias = deobfuscationUseSourceNameAsAlias;
}

public void setDeobfuscationParseKotlinMetadata(boolean deobfuscationParseKotlinMetadata) {
this.deobfuscationParseKotlinMetadata = deobfuscationParseKotlinMetadata;
}

public void updateRenameFlag(JadxArgs.RenameEnum flag, boolean enabled) {
if (enabled) {
renameFlags.add(flag);
Expand Down Expand Up @@ -387,6 +391,7 @@ private void upgradeSettings(int fromVersion) {
if (fromVersion == 0) {
setDeobfuscationMinLength(3);
setDeobfuscationUseSourceNameAsAlias(true);
setDeobfuscationParseKotlinMetadata(true);
setDeobfuscationForceSave(true);
setThreadsCount(1);
setReplaceConsts(true);
Expand Down
11 changes: 10 additions & 1 deletion jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,24 @@ private SettingsGroup makeDeobfuscationGroup() {
needReload();
});

JCheckBox deobfKotlinMetadata = new JCheckBox();
deobfKotlinMetadata.setSelected(settings.isDeobfuscationParseKotlinMetadata());
deobfKotlinMetadata.addItemListener(e -> {
settings.setDeobfuscationParseKotlinMetadata(e.getStateChange() == ItemEvent.SELECTED);
needReload();
});

SettingsGroup deobfGroup = new SettingsGroup(NLS.str("preferences.deobfuscation"));
deobfGroup.addRow(NLS.str("preferences.deobfuscation_on"), deobfOn);
deobfGroup.addRow(NLS.str("preferences.deobfuscation_force"), deobfForce);
deobfGroup.addRow(NLS.str("preferences.deobfuscation_min_len"), minLenSpinner);
deobfGroup.addRow(NLS.str("preferences.deobfuscation_max_len"), maxLenSpinner);
deobfGroup.addRow(NLS.str("preferences.deobfuscation_source_alias"), deobfSourceAlias);
deobfGroup.addRow(NLS.str("preferences.deobfuscation_kotlin_metadata"), deobfKotlinMetadata);
deobfGroup.end();

Collection<JComponent> connectedComponents = Arrays.asList(deobfForce, minLenSpinner, maxLenSpinner, deobfSourceAlias);
Collection<JComponent> connectedComponents =
Arrays.asList(deobfForce, minLenSpinner, maxLenSpinner, deobfSourceAlias, deobfKotlinMetadata);
deobfOn.addItemListener(e -> enableComponentList(connectedComponents, e.getStateChange() == ItemEvent.SELECTED));
enableComponentList(connectedComponents, settings.isDeobfuscationOn());
return deobfGroup;
Expand Down
1 change: 1 addition & 0 deletions jadx-gui/src/main/resources/i18n/Messages_de_DE.properties
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ preferences.deobfuscation_force=Deobfuscationskartendatei umschreiben erzwingen
preferences.deobfuscation_min_len=Minimale Namenlänge
preferences.deobfuscation_max_len=Maximale Namenlänge
preferences.deobfuscation_source_alias=Quelldateiname als Klassennamen-Alias verwenden
preferences.deobfuscation_kotlin_metadata=Analysieren Sie Kotlin-Metadaten nach Klassen- und Paketnamen
preferences.save=Speichern
preferences.cancel=Abbrechen
preferences.reset=Zurücksetzen
Expand Down
1 change: 1 addition & 0 deletions jadx-gui/src/main/resources/i18n/Messages_en_US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ preferences.deobfuscation_force=Force rewrite deobfuscation map file
preferences.deobfuscation_min_len=Minimum name length
preferences.deobfuscation_max_len=Maximum name length
preferences.deobfuscation_source_alias=Use source file name as class name alias
preferences.deobfuscation_kotlin_metadata=Parse Kotlin metadata for class and package names
preferences.save=Save
preferences.cancel=Cancel
preferences.reset=Reset
Expand Down
1 change: 1 addition & 0 deletions jadx-gui/src/main/resources/i18n/Messages_es_ES.properties
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ preferences.deobfuscation_force=Forzar reescritura del fichero de ofuscación
preferences.deobfuscation_min_len=Longitud mínima del nombre
preferences.deobfuscation_max_len=Longitud máxima del nombre
preferences.deobfuscation_source_alias=Usar el nombre del source como alias para la clase
preferences.deobfuscation_kotlin_metadata=Parse Kotlin metadatos para nombres de clase y paquete
preferences.save=Guardar
preferences.cancel=Cancelar
preferences.reset=Reestablecer
Expand Down
1 change: 1 addition & 0 deletions jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ preferences.deobfuscation_force=强制覆盖反混淆映射文件
preferences.deobfuscation_min_len=最小命名长度
preferences.deobfuscation_max_len=最大命名长度
preferences.deobfuscation_source_alias=使用资源名作为类的别名
preferences.deobfuscation_kotlin_metadata=解析Kotlin元数据以获得类和包名
preferences.save=保存
preferences.cancel=取消
preferences.reset=重置
Expand Down