Skip to content

Commit

Permalink
Support malformed resource names/namespaces by falling back to resId (#…
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
iBotPeaches and MyAnoneNeko committed Sep 19, 2022
1 parent 5d6c6c0 commit 3fff2f1
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -336,16 +336,26 @@ public String getAttributeName(int index) {
}

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));
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;
}
Expand Down Expand Up @@ -381,11 +391,27 @@ public String getAttributeValue(int index) {

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));
valueType,
valueData,
value,
getAttributeNameResource(index)
);
} catch (AndrolibException ex) {
setFirstError(ex);
LOGGER.log(Level.WARNING, String.format("Could not decode attr value, using undecoded value "
Expand Down Expand Up @@ -807,9 +833,9 @@ private void doNext() throws IOException {
if (m_strings == null) {
m_reader.skipCheckInt(CHUNK_AXML_FILE, CHUNK_AXML_FILE_BROKEN);

/*
* chunkSize
*/
/*
* chunkSize
*/
m_reader.skipInt();
m_strings = StringBlock.read(m_reader);
m_namespaces.increaseDepth();
Expand Down Expand Up @@ -863,18 +889,18 @@ private void doNext() throws IOException {
}

// Common header.
/* chunkSize */m_reader.skipInt();
/* chunkSize */m_reader.skipInt();
int lineNumber = m_reader.readInt();
/* 0xFFFFFFFF */m_reader.skipInt();
/* 0xFFFFFFFF */m_reader.skipInt();

if (chunkType == CHUNK_XML_START_NAMESPACE || chunkType == CHUNK_XML_END_NAMESPACE) {
if (chunkType == CHUNK_XML_START_NAMESPACE) {
int prefix = m_reader.readInt();
int uri = m_reader.readInt();
m_namespaces.push(prefix, uri);
} else {
/* prefix */m_reader.skipInt();
/* uri */m_reader.skipInt();
/* prefix */m_reader.skipInt();
/* uri */m_reader.skipInt();
m_namespaces.pop();
}
continue;
Expand All @@ -885,7 +911,7 @@ private void doNext() throws IOException {
if (chunkType == CHUNK_XML_START_TAG) {
m_namespaceUri = m_reader.readInt();
m_name = m_reader.readInt();
/* flags? */m_reader.skipInt();
/* flags? */m_reader.skipInt();
int attributeCount = m_reader.readInt();
m_idAttribute = (attributeCount >>> 16) - 1;
attributeCount &= 0xFFFF;
Expand All @@ -912,8 +938,8 @@ private void doNext() throws IOException {

if (chunkType == CHUNK_XML_TEXT) {
m_name = m_reader.readInt();
/* ? */m_reader.skipInt();
/* ? */m_reader.skipInt();
/* ? */m_reader.skipInt();
/* ? */m_reader.skipInt();
m_event = TEXT;
break;
}
Expand All @@ -927,10 +953,10 @@ private void setFirstError(AndrolibException error) {
}

// ///////////////////////////////// data
/*
* All values are essentially indices, e.g. m_name is an index of name in
* m_strings.
*/
/*
* All values are essentially indices, e.g. m_name is an index of name in
* m_strings.
*/
private ExtDataInput m_reader;
private ResAttrDecoder mAttrDecoder;
private AndrolibException mFirstError;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

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;
Expand Down Expand Up @@ -48,10 +49,24 @@ public String decodeManifestAttr(int attrResId)
throws AndrolibException {

if (attrResId != 0) {
ResResSpec resResSpec = getCurrentPackage().getResTable().getResSpec(attrResId);
int attrId = attrResId;

if (resResSpec != null) {
return resResSpec.getName();
// 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();
}
}
}

Expand Down

0 comments on commit 3fff2f1

Please sign in to comment.