未验证 提交 492a3f69 编写于 作者: Y Yaroslav Yadrov 提交者: GitHub

feat(deobf): add classname parsing for Kotlin metadata (PR #842, #758)

上级 1ce8fa8b
......@@ -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,"
......@@ -194,6 +197,7 @@ public class JadxCLIArgs {
args.setDeobfuscationMinLength(deobfuscationMinLength);
args.setDeobfuscationMaxLength(deobfuscationMaxLength);
args.setUseSourceNameAsClassAlias(deobfuscationUseSourceNameAsAlias);
args.setParseKotlinMetadata(deobfuscationParseKotlinMetadata);
args.setEscapeUnicode(escapeUnicode);
args.setRespectBytecodeAccModifiers(respectBytecodeAccessModifiers);
args.setExportAsGradleProject(exportAsGradleProject);
......@@ -275,6 +279,10 @@ public class JadxCLIArgs {
return deobfuscationUseSourceNameAsAlias;
}
public boolean isDeobfuscationParseKotlinMetadata() {
return deobfuscationParseKotlinMetadata;
}
public boolean isEscapeUnicode() {
return escapeUnicode;
}
......
......@@ -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;
......@@ -230,6 +231,14 @@ public class JadxArgs {
this.useSourceNameAsClassAlias = useSourceNameAsClassAlias;
}
public boolean isParseKotlinMetadata() {
return parseKotlinMetadata;
}
public void setParseKotlinMetadata(boolean parseKotlinMetadata) {
this.parseKotlinMetadata = parseKotlinMetadata;
}
public int getDeobfuscationMinLength() {
return deobfuscationMinLength;
}
......@@ -355,6 +364,7 @@ public class JadxArgs {
+ ", deobfuscationOn=" + deobfuscationOn
+ ", deobfuscationForceSave=" + deobfuscationForceSave
+ ", useSourceNameAsClassAlias=" + useSourceNameAsClassAlias
+ ", parseKotlinMetadata=" + parseKotlinMetadata
+ ", deobfuscationMinLength=" + deobfuscationMinLength
+ ", deobfuscationMaxLength=" + deobfuscationMaxLength
+ ", escapeUnicode=" + escapeUnicode
......
......@@ -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
......@@ -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;
......@@ -70,6 +74,7 @@ public class Deobfuscator {
this.minLength = args.getDeobfuscationMinLength();
this.maxLength = args.getDeobfuscationMaxLength();
this.useSourceNameAsAlias = args.isUseSourceNameAsClassAlias();
this.parseKotlinMetadata = args.isParseKotlinMetadata();
this.deobfPresets = new DeobfPresets(this, deobfMapFile);
}
......@@ -392,6 +397,18 @@ public class Deobfuscator {
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) {
......@@ -399,14 +416,40 @@ public class Deobfuscator {
}
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);
......
......@@ -279,6 +279,10 @@ public class JadxSettings extends JadxCLIArgs {
this.deobfuscationUseSourceNameAsAlias = deobfuscationUseSourceNameAsAlias;
}
public void setDeobfuscationParseKotlinMetadata(boolean deobfuscationParseKotlinMetadata) {
this.deobfuscationParseKotlinMetadata = deobfuscationParseKotlinMetadata;
}
public void updateRenameFlag(JadxArgs.RenameEnum flag, boolean enabled) {
if (enabled) {
renameFlags.add(flag);
......@@ -387,6 +391,7 @@ public class JadxSettings extends JadxCLIArgs {
if (fromVersion == 0) {
setDeobfuscationMinLength(3);
setDeobfuscationUseSourceNameAsAlias(true);
setDeobfuscationParseKotlinMetadata(true);
setDeobfuscationForceSave(true);
setThreadsCount(1);
setReplaceConsts(true);
......
......@@ -167,15 +167,24 @@ public class JadxSettingsWindow extends JDialog {
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;
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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=重置
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册