fix(res): avoid duplicated XML attributes (PR #2112)
Co-authored-by: bagipro <bugi@bugi>
This commit is contained in:
@@ -286,13 +286,14 @@ public class BinaryXMLParser extends CommonBinaryParser {
|
||||
}
|
||||
}
|
||||
}
|
||||
Set<String> 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<String> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String> 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<String> 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<String> attrCache) {
|
||||
return !attrCache.add(attrFullName);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user