aapt部分源码分析

aapt部分源码分析

之前由于二进制修改AndroidManifest.xml失败,一开始只插入属性的字符和标签node发现失败,比较后发现要插入资源id,但是还是无法生效。

之前修改的方法都可以正常安装应用,正常启动,而且xml解析都没问题,插入的debuggable="true"就是无法生效。了解到可以aapt list打印相应属性。

aapt list -v -a |grep debuggable

成功的xml:
A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff

失败的xml:
A: android:debuggable=(type 0x12)0xffffffff

发现是缺少资源id,即使在XmlResourceMapType中插入资源id,还是无法识别。
所以尝试在aapt源码中看一下,是怎么查找到资源id的。

list打印AndroidManifest.xml部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
for (i=0; i<N; i++) {
uint32_t res = block->getAttributeNameResID(i);
ns16 = block->getAttributeNamespace(i, &len);
String8 ns = build_namespace(namespaces, ns16);
String8 name(block->getAttributeName(i, &len));
printf("%sA: ", prefix.string());
if (res) {
printf("%s%s(0x%08x)", ns.string(), name.string(), res);
} else {
printf("%s%s", ns.string(), name.string());
}
Res_value value;
block->getAttributeValue(i, &value);
if (value.dataType == Res_value::TYPE_NULL) {
printf("=(null)");
} else if (value.dataType == Res_value::TYPE_REFERENCE) {
printf("=@0x%x", (int)value.data);
} else if (value.dataType == Res_value::TYPE_ATTRIBUTE) {
printf("=?0x%x", (int)value.data);
} else if (value.dataType == Res_value::TYPE_STRING) {
printf("=\"%s\"",
ResTable::normalizeForOutput(String8(block->getAttributeStringValue(i,
&len)).string()).string());
} else {
printf("=(type 0x%x)0x%x", (int)value.dataType, (int)value.data);
}
const char16_t* val = block->getAttributeStringValue(i, &len);
if (val != NULL) {
printf(" (Raw: \"%s\")", ResTable::normalizeForOutput(String8(val).string()).
string());
}
printf("\n");
}

这个部分关键:

1
2
3
4
5
6
printf("%sA: ", prefix.string());
if (res) {
printf("%s%s(0x%08x)", ns.string(), name.string(), res);
} else {
printf("%s%s", ns.string(), name.string());
}

Resid初始化:

1
2
3
4
5
6
7
8
9
if (type == RES_STRING_POOL_TYPE) {
mStrings.setTo(chunk, size);
} else if (type == RES_XML_RESOURCE_MAP_TYPE) {
mResIds = (const uint32_t*)
(((const uint8_t*)chunk)+dtohs(chunk->headerSize));
mNumResIds = (dtohl(chunk->size)-dtohs(chunk->headerSize))/ sizeof(uint32_t);
} else if (type >= RES_XML_FIRST_CHUNK_TYPE
&& type <= RES_XML_LAST_CHUNK_TYPE) {
...

mResIds指向RES_XML_RESOURCE_MAP_TYPE开头
mNumResIds为资源id数目

因为mResIds是顺序的,问题不在这儿,那么是由标签属性名来查找对应资源id的.

1
2
3
4
5
6
7
8
9
10
int32_t ResXMLParser::getElementNamespaceID() const
{
if (mEventCode == START_TAG) {
return dtohl(((const ResXMLTree_attrExt*)mCurExt)->ns.index);
}
if (mEventCode == END_TAG) {
return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->ns.index);
}
return -1;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int32_t ResXMLParser::getAttributeNameID(size_t idx) const
{
if (mEventCode == START_TAG) {
const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
if (idx < dtohs(tag->attributeCount)) {
const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
(((const uint8_t*)tag)
+ dtohs(tag->attributeStart)
+ (dtohs(tag->attributeSize)*idx));
return dtohl(attr->name.index);
}
}
return -1;
}

由这两个函数可以看出,是根据index来确定标签属性名字符或命名空间名字符。

所以像A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff格式的输出流程如下:

  • 顺序存储XmlResourceMapType中资源id
  • 顺序遍历tag,获取tag属性的index(在string pool的索引)
  • 如果在string pool中的index正好是Resid中的索引,即该tag属性的资源id为对应index的值。

所以我们插入的属性字符在string pool尾部,而Resid中值太少,无法将0x0101000f的index和string pool 中的字符debuggable的index匹配,所以输出时并不输出资源值。

我们可以在XmlResourceMapType中填充一些资源值,把debuggable的资源值撑到和string pool中字符debuggable的index值一致。

a-w500

a-w500

我插入一些相同的资源值,撑到二者index一致,当然Resid header里的size要改,chunk header里size也要改。

修改完后,放入apk中,在输出就可以看到了

修改虽然成功,但是发现debuggable还是无法生效。

最后意外的发现,修改debuggable属性的位置就可以了

debuggable不生效:

1
2
3
4
A: android:label(0x01010001)=@0x7f070000
A: android:icon(0x01010002)=@0x7f020001
A: android:allowBackup(0x01010280)=(type 0x12)0xffffffff
A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff

debuggable生效:

1
2
3
4
A: android:label(0x01010001)=@0x7f070000
A: android:icon(0x01010002)=@0x7f020001
A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
A: android:allowBackup(0x01010280)=(type 0x12)0xffffffff

不清楚为什么标签属性位置也会影响?太坑了。。。