Support malformed resource names/namespaces by falling back to resId (#2886)

* Correct falsely-referenced attribute into an entity which is an obfuscated name

* style: correct syntax for custom attributes

* fix: remove unused import

Co-authored-by: MyAnoneNeko <MyAnoneNeko@users.noreply.github.com>
This commit is contained in:
Connor Tumbleson 2022-09-19 16:27:43 -04:00 committed by GitHub
parent 5d6c6c04d2
commit 3fff2f128e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 69 additions and 28 deletions

View File

@ -336,16 +336,26 @@ public class AXmlResourceParser implements XmlResourceParser {
}
String value = m_strings.getString(name);
String namespace = getAttributeNamespace(index);
// some attributes will return "", we must rely on the resource_id and refer to the frameworks
// to match the resource id to the name. ex: 0x101021C = versionName
if (value.length() == 0 || android_ns.equals(getAttributeNamespace(index))) {
// If attribute name is lacking or a private namespace emerges,
// retrieve the exact attribute name by its id.
if (value == null || value.length() == 0) {
try {
int resourceId = getAttributeNameResource(index);
if (resourceId != 0) {
value = mAttrDecoder.decodeManifestAttr(getAttributeNameResource(index));
if (value == null) {
value = "";
}
} catch (AndrolibException | NullPointerException ignored) {}
} catch (AndrolibException e) {
value = "";
}
} else if (! namespace.equals(android_ns)) {
try {
String obfuscatedName = mAttrDecoder.decodeManifestAttr(getAttributeNameResource(index));
if (! (obfuscatedName == null || obfuscatedName.equals(value))) {
value = obfuscatedName;
}
} catch (AndrolibException ignored) {}
}
return value;
}
@ -381,11 +391,27 @@ public class AXmlResourceParser implements XmlResourceParser {
if (mAttrDecoder != null) {
try {
String value = valueRaw == -1 ? null : ResXmlEncoders.escapeXmlChars(m_strings.getString(valueRaw));
String obfuscatedValue = mAttrDecoder.decodeManifestAttr(valueData);
if (! (value == null || obfuscatedValue == null)) {
int slashPos = value.lastIndexOf("/");
if (slashPos != -1) {
// Handle a value with a format of "@yyy/xxx"
String dir = value.substring(0, slashPos);
value = dir + "/"+ obfuscatedValue;
} else if (! value.equals(obfuscatedValue)) {
value = obfuscatedValue;
}
}
return mAttrDecoder.decode(
valueType,
valueData,
valueRaw == -1 ? null : ResXmlEncoders.escapeXmlChars(m_strings.getString(valueRaw)),
getAttributeNameResource(index));
value,
getAttributeNameResource(index)
);
} catch (AndrolibException ex) {
setFirstError(ex);
LOGGER.log(Level.WARNING, String.format("Could not decode attr value, using undecoded value "

View File

@ -18,6 +18,7 @@ package brut.androlib.res.decoder;
import brut.androlib.AndrolibException;
import brut.androlib.err.UndefinedResObjectException;
import brut.androlib.res.data.ResID;
import brut.androlib.res.data.ResPackage;
import brut.androlib.res.data.ResResSpec;
import brut.androlib.res.data.value.ResAttr;
@ -48,12 +49,26 @@ public class ResAttrDecoder {
throws AndrolibException {
if (attrResId != 0) {
ResResSpec resResSpec = getCurrentPackage().getResTable().getResSpec(attrResId);
int attrId = attrResId;
// See also: brut.androlib.res.data.ResTable.getResSpec
if (attrId >> 24 == 0) {
ResPackage pkg = getCurrentPackage();
int packageId = pkg.getId();
int pkgId = (packageId == 0 ? 2 : packageId);
attrId = (0xFF000000 & (pkgId << 24)) | attrId;
}
// Retrieve the ResSpec in a package by id
ResID resId = new ResID(attrId);
ResPackage pkg = getCurrentPackage();
if (pkg.hasResSpec(resId)) {
ResResSpec resResSpec = pkg.getResSpec(resId);
if (resResSpec != null) {
return resResSpec.getName();
}
}
}
return null;
}