Android培训班(64)dex文件格式5

string_ids_size和string_ids_off字段 这两个字段主要用来访问字符串资源,由于源程序里编译后,程序所需要使用到的字符串都保存在这个数据段里,以便解释执行这个dex文件代码时使用。比如调用库函数里的类名称描述,输出显示给用户查看的字符串。string_ids_size说明了有多少个字符串,而string_ids_off说明字符串数据区的开始位置。那么字符串数据区里的内容是怎么样排列的呢?下面就来分析这个字符串结构:
/*
* Direct-mapped "string_id_item".
*/
typedef struct DexStringId {
u4 stringDataOff; /* file offset to string_data_item */
} DexStringId;


从上面的结构可以看出来,这个数据区保存的只是字符串表的地址索引。如果要找到字符串的实际数据,还需要从这个地址索引找到文件的相应开始位置,然后才得到字符串数据。每一个字符串项占用4个字节。因此这个数据区的大小就为4*string_ids_size。在保存字符串实际数据区,采用UTF16的格式来保存,也就是每两个字节为一个单位保存,因此发现这里保存的字符串是交错在一起,比如直接从dex文件里使用16进制显示出来内容如下:
3c06 6e69 7469 003e


实际这段数据是描述”<init>\0”,可见字符顺序与ASCII码的顺序并不一致,再仔细一看是交错在一起的,如果按16位的方式来读取,再把低字节放在前面,高字节放在后面,再拼接到一起,就是相应的顺序了。这段数据包括字符串的长度、字符串内容、字符串结束标志。把字符串按16位读取,再交换字节顺序,就变成如下字符串:
063c 696e 6974 3e00
字符串的长度是采用固定的长度,还是变长的长度来表示呢?在dex文件里是采用变长来表示字符串的长度。因为一个字符串的长度可能是一个字节,比如小于256;或者4个字节,比如1G大小以上。由于字符串的长度,大多数都是小于256个字节,因此需要使用一种编码,既可以表示一个字节的长度,也可以表示4个字节的长度。并且1个字节的长度占绝大多数,能满足这种表示的编码方式有很多,但dex文件里采用uleb128方式。leb128编码是一种变长编码,每个字节采用7位来表达原来的数据,最高位用来表示是否有后继字节。它的编码算法如下:
/*
* Writes a 32-bit value in unsigned ULEB128 format.
*
* Returns the updated pointer.
*/
DEX_INLINE u1* writeUnsignedLeb128(u1* ptr, u4 data)
{
while (true) {
u1 out = data & 0x7f;
if (out != data) {
*ptr++ = out | 0x80;
data >>= 7;
} else {
*ptr++ = out;
break;
}
}


return ptr;
}


它的解码算法如下:
/*
* Reads an unsigned LEB128 value, updating the given pointer to point
* just past the end of the read value. This function tolerates
* non-zero high-order bits in the fifth encoded byte.
*/
DEX_INLINE int readUnsignedLeb128(const u1** pStream) {
const u1* ptr = *pStream;
int result = *(ptr++);


if (result > 0x7f) {
int cur = *(ptr++);
result = (result & 0x7f) | ((cur & 0x7f) << 7);
if (cur > 0x7f) {
cur = *(ptr++);
result |= (cur & 0x7f) << 14;
if (cur > 0x7f) {
cur = *(ptr++);
result |= (cur & 0x7f) << 21;
if (cur > 0x7f) {
/*
* Note: We don't check to see if cur is out of
* range here, meaning we tolerate garbage in the
* high four-order bits.
*/
cur = *(ptr++);
result |= cur << 28;
}
}
}
}


*pStream = ptr;
return result;
}


根据上面的算法,来分析上面例子字符串,取得第一个字节是06,最高位为0,因此没有后继字节,那么取出这个字节里7位有效数据,就是6,也就是说这个字符串是6个字节,但不包括结束字符“\0”。到这里,就非常清楚字符串数据区的数据保存表示方式了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值