diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java b/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java index bafdb5d19..a9c0e2350 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java @@ -286,13 +286,14 @@ public class BinaryXMLParser extends CommonBinaryParser { } } } + Set attrCache = new HashSet<>(); boolean attrNewLine = attributeCount != 1 && this.attrNewLine; for (int i = 0; i < attributeCount; i++) { - parseAttribute(i, attrNewLine); + parseAttribute(i, attrNewLine, attrCache); } } - private void parseAttribute(int i, boolean newLine) throws IOException { + private void parseAttribute(int i, boolean newLine, Set attrCache) throws IOException { int attributeNS = is.readInt32(); int attributeName = is.readInt32(); int attributeRawValue = is.readInt32(); @@ -300,29 +301,34 @@ public class BinaryXMLParser extends CommonBinaryParser { int attrValDataType = is.readInt8(); int attrValData = is.readInt32(); + String shortNsName = null; + if (attributeNS != -1) { + shortNsName = getAttributeNS(attributeNS); + } + String attrName = getValidTagAttributeName(getAttributeName(attributeName)); + String attrFullName = shortNsName != null ? shortNsName + ":" + attrName : attrName; + // do not dump duplicated values + if (XmlDeobf.isDuplicatedAttr(attrFullName, attrCache)) { + return; + } + if (newLine) { writer.startLine().addIndent(); } else { writer.add(' '); } - String shortNsName = null; - if (attributeNS != -1) { - shortNsName = getAttributeNS(attributeNS); - writer.add(shortNsName).add(':'); - } - String attrName = getValidTagAttributeName(getAttributeName(attributeName)); - writer.add(attrName).add("=\""); + writer.add(attrFullName).add("=\""); String decodedAttr = ManifestAttributes.getInstance().decode(attrName, attrValData); if (decodedAttr != null) { memorizePackageName(attrName, decodedAttr); - if (isDeobfCandidateAttr(shortNsName, attrName)) { + if (isDeobfCandidateAttr(attrFullName)) { decodedAttr = deobfClassName(decodedAttr); } attachClassNode(writer, attrName, decodedAttr); writer.add(StringUtils.escapeXML(decodedAttr)); } else { decodeAttribute(attributeNS, attrValDataType, attrValData, - shortNsName, attrName); + attrFullName); } if (shortNsName != null && shortNsName.equals("android")) { if (attrName.equals("pathData")) { @@ -402,7 +408,7 @@ public class BinaryXMLParser extends CommonBinaryParser { } private void decodeAttribute(int attributeNS, int attrValDataType, int attrValData, - String shortNsName, String attrName) { + String attrFullName) { if (attrValDataType == TYPE_REFERENCE) { // reference custom processing String resName = resNames.get(attrValData); @@ -424,11 +430,11 @@ public class BinaryXMLParser extends CommonBinaryParser { } } else { String str = valuesParser.decodeValue(attrValDataType, attrValData); - memorizePackageName(attrName, str); - if (isDeobfCandidateAttr(shortNsName, attrName)) { + memorizePackageName(attrFullName, str); + if (isDeobfCandidateAttr(attrFullName)) { str = deobfClassName(str); } - attachClassNode(writer, attrName, str); + attachClassNode(writer, attrFullName, str); writer.add(str != null ? StringUtils.escapeXML(str) : "null"); } } @@ -487,11 +493,11 @@ public class BinaryXMLParser extends CommonBinaryParser { return sb.toString(); } - private void attachClassNode(ICodeWriter writer, String attrName, String clsName) { + private void attachClassNode(ICodeWriter writer, String attrFullName, String clsName) { if (!writer.isMetadataSupported()) { return; } - if (clsName == null || !attrName.equals("name")) { + if (clsName == null || !attrFullName.equals("android:name")) { return; } String clsFullName; @@ -517,18 +523,12 @@ public class BinaryXMLParser extends CommonBinaryParser { return className; } - private boolean isDeobfCandidateAttr(String shortNsName, String attrName) { - String fullName; - if (shortNsName != null) { - fullName = shortNsName + ':' + attrName; - } else { - return false; - } - return "android:name".equals(fullName); + private boolean isDeobfCandidateAttr(String attrFullName) { + return "android:name".equals(attrFullName); } - private void memorizePackageName(String attrName, String attrValue) { - if ("manifest".equals(currentTag) && "package".equals(attrName)) { + private void memorizePackageName(String attrFullName, String attrValue) { + if ("manifest".equals(currentTag) && "package".equals(attrFullName)) { appPackageName = attrValue; } } diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ProtoXMLParser.java b/jadx-core/src/main/java/jadx/core/xmlgen/ProtoXMLParser.java index 2d4f0fd43..58b39efde 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ProtoXMLParser.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ProtoXMLParser.java @@ -3,8 +3,10 @@ package jadx.core.xmlgen; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Random; +import java.util.Set; import com.android.aapt.Resources.XmlAttribute; import com.android.aapt.Resources.XmlElement; @@ -58,9 +60,12 @@ public class ProtoXMLParser extends CommonProtoParser { for (int i = 0; i < e.getNamespaceDeclarationCount(); i++) { decode(e.getNamespaceDeclaration(i)); } + + Set attrCache = new HashSet<>(); for (int i = 0; i < e.getAttributeCount(); i++) { - decode(e.getAttribute(i)); + decode(e.getAttribute(i), attrCache); } + if (e.getChildCount() > 0) { writer.add('>'); writer.incIndent(); @@ -76,11 +81,13 @@ public class ProtoXMLParser extends CommonProtoParser { } } - private void decode(XmlAttribute a) { - writer.add(' '); + private void decode(XmlAttribute a, Set attrCache) { String name = getAttributeFullName(a); + if (XmlDeobf.isDuplicatedAttr(name, attrCache)) { + return; + } String value = deobfClassName(getAttributeValue(a)); - writer.add(name).add("=\"").add(StringUtils.escapeXML(value)).add('\"'); + writer.add(' ').add(name).add("=\"").add(StringUtils.escapeXML(value)).add('\"'); memorizePackageName(name, value); } diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/XmlDeobf.java b/jadx-core/src/main/java/jadx/core/xmlgen/XmlDeobf.java index b4104e476..eb0c2328e 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/XmlDeobf.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/XmlDeobf.java @@ -1,5 +1,7 @@ package jadx.core.xmlgen; +import java.util.Set; + import org.jetbrains.annotations.Nullable; import jadx.core.dex.info.ClassInfo; @@ -30,4 +32,8 @@ public class XmlDeobf { } return classInfo.getAliasFullName(); } + + public static boolean isDuplicatedAttr(String attrFullName, Set attrCache) { + return !attrCache.add(attrFullName); + } }