未验证 提交 3c05b051 编写于 作者: S Skylot

fix: check names from Kotlin metadata before use (#1364)

上级 bdb2efdb
package jadx.core.deobf;
public class ClsAliasPair {
private final String pkg;
private final String name;
public ClsAliasPair(String pkg, String name) {
this.pkg = pkg;
this.name = name;
}
public String getPkg() {
return pkg;
}
public String getName() {
return name;
}
@Override
public String toString() {
return pkg + '.' + name;
}
}
......@@ -386,10 +386,10 @@ public class Deobfuscator {
String alias = null;
String pkgName = null;
if (this.parseKotlinMetadata) {
ClassInfo kotlinCls = KotlinMetadataUtils.getClassName(cls);
ClsAliasPair kotlinCls = KotlinMetadataUtils.getClassAlias(cls);
if (kotlinCls != null) {
alias = prepareNameFull(kotlinCls.getShortName(), "C");
pkgName = kotlinCls.getPackage();
alias = kotlinCls.getName();
pkgName = kotlinCls.getPkg();
}
}
if (alias == null && this.useSourceNameAsAlias) {
......@@ -601,20 +601,6 @@ public class Deobfuscator {
return NameMapper.removeInvalidCharsMiddle(name);
}
private String prepareNameFull(String name, String prefix) {
if (name.length() > maxLength) {
return makeHashName(name, prefix);
}
String result = NameMapper.removeInvalidChars(name, prefix);
if (result.isEmpty()) {
return makeHashName(name, prefix);
}
if (NameMapper.isReserved(result)) {
return prefix + result;
}
return result;
}
private static String makeHashName(String name, String invalidPrefix) {
return invalidPrefix + 'x' + Integer.toHexString(name.hashCode());
}
......
......@@ -6,6 +6,16 @@ import jadx.core.dex.attributes.AttrNode;
public class RenameReasonAttr implements IJadxAttribute {
public static RenameReasonAttr forNode(AttrNode node) {
RenameReasonAttr renameReasonAttr = node.get(AType.RENAME_REASON);
if (renameReasonAttr != null) {
return renameReasonAttr;
}
RenameReasonAttr newAttr = new RenameReasonAttr();
node.addAttr(newAttr);
return newAttr;
}
private String description;
public RenameReasonAttr() {
......
......@@ -9,8 +9,12 @@ import org.slf4j.LoggerFactory;
import jadx.api.plugins.input.data.annotations.EncodedType;
import jadx.api.plugins.input.data.annotations.EncodedValue;
import jadx.api.plugins.input.data.annotations.IAnnotation;
import jadx.core.deobf.ClsAliasPair;
import jadx.core.deobf.NameMapper;
import jadx.core.dex.attributes.nodes.RenameReasonAttr;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.utils.Utils;
// TODO: parse data from d1 (protobuf encoded) to get original method names and other useful info
public class KotlinMetadataUtils {
......@@ -18,13 +22,12 @@ public class KotlinMetadataUtils {
private static final String KOTLIN_METADATA_ANNOTATION = "Lkotlin/Metadata;";
private static final String KOTLIN_METADATA_D2_PARAMETER = "d2";
private static final String KOTLIN_METADATA_CLASSNAME_REGEX = "(L.*;)";
/**
* Try to get class info from Kotlin Metadata annotation
*/
@Nullable
public static ClassInfo getClassName(ClassNode cls) {
public static ClsAliasPair getClassAlias(ClassNode cls) {
IAnnotation metadataAnnotation = cls.getAnnotation(KOTLIN_METADATA_ANNOTATION);
List<EncodedValue> d2Param = getParamAsList(metadataAnnotation, KOTLIN_METADATA_D2_PARAMETER);
if (d2Param == null || d2Param.isEmpty()) {
......@@ -36,8 +39,14 @@ public class KotlinMetadataUtils {
}
try {
String rawClassName = ((String) firstValue.getValue()).trim();
if (rawClassName.matches(KOTLIN_METADATA_CLASSNAME_REGEX)) {
return ClassInfo.fromName(cls.root(), rawClassName);
if (rawClassName.isEmpty()) {
return null;
}
String clsName = Utils.cleanObjectName(rawClassName);
ClsAliasPair alias = splitAndCheckClsName(cls, clsName);
if (alias != null) {
RenameReasonAttr.forNode(cls).append("from Kotlin metadata");
return alias;
}
} catch (Exception e) {
LOG.error("Failed to parse kotlin metadata", e);
......@@ -45,6 +54,54 @@ public class KotlinMetadataUtils {
return null;
}
// Don't use ClassInfo facility to not pollute class into cache
private static ClsAliasPair splitAndCheckClsName(ClassNode originCls, String fullClsName) {
if (!NameMapper.isValidFullIdentifier(fullClsName)) {
return null;
}
String pkg;
String name;
int dot = fullClsName.lastIndexOf('.');
if (dot == -1) {
pkg = "";
name = fullClsName;
} else {
pkg = fullClsName.substring(0, dot);
name = fullClsName.substring(dot + 1);
}
ClassInfo originClsInfo = originCls.getClassInfo();
String originName = originClsInfo.getShortName();
if (originName.equals(name)
|| name.contains("$")
|| !NameMapper.isValidIdentifier(name)
|| countPkgParts(originClsInfo.getPackage()) != countPkgParts(pkg)
|| pkg.startsWith("java.")) {
return null;
}
ClassNode newClsNode = originCls.root().resolveClass(fullClsName);
if (newClsNode != null) {
// class with alias name already exist
return null;
}
return new ClsAliasPair(pkg, name);
}
private static int countPkgParts(String pkg) {
if (pkg.isEmpty()) {
return 0;
}
int count = 1;
int pos = 0;
while (true) {
pos = pkg.indexOf('.', pos);
if (pos == -1) {
return count;
}
pos++;
count++;
}
}
@SuppressWarnings("unchecked")
private static List<EncodedValue> getParamAsList(IAnnotation annotation, String paramName) {
if (annotation == null) {
......
......@@ -28,7 +28,8 @@ public class TestKotlinMetadata extends SmaliTest {
prepareArgs(true);
assertThat(getClassNodeFromSmali())
.code()
.containsOne("class TestMetaData {");
.containsOne("class TestMetaData {")
.containsOne("reason: from Kotlin metadata");
}
@Test
......@@ -42,6 +43,7 @@ public class TestKotlinMetadata extends SmaliTest {
private void prepareArgs(boolean parseKotlinMetadata) {
enableDeobfuscation();
args.setDeobfuscationMinLength(100); // rename everything
args.setDeobfuscationForceSave(true);
getArgs().setParseKotlinMetadata(parseKotlinMetadata);
disableCompilation();
}
......
......@@ -14,7 +14,7 @@
"\u0000\u0014\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\u0008\u0002\n\u0002\u0010\u0008\n\u0002\u0008\u0004\u0018\u00002\u00020\u0001B\u0005\u00a2\u0006\u0002\u0010\u0002J\u0015\u0010\u0005\u001a\u00020\u00042\u0006\u0010\u0006\u001a\u00020\u0004H\u0007\u00a2\u0006\u0002\u0008\u0007R\u0010\u0010\u0003\u001a\u00020\u00048\u0006X\u0087D\u00a2\u0006\u0002\n\u0000\u00a8\u0006\u0008"
}
d2 = {
"LTestMetaData;",
"Ljadx/TestMetaData;",
"",
"()V",
"id",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册