Android培训班(64)dex文件格式5
发布日期:2021-07-01 05:06:11 浏览次数:2 分类:技术文章

本文共 2178 字,大约阅读时间需要 7 分钟。

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”。到这里,就非常清楚字符串数据区的数据保存表示方式了。

转载地址:https://mysoft.blog.csdn.net/article/details/6647773 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Android培训班(65)dex文件打开
下一篇:sigmoid函数求导与自然指数

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年04月17日 18时21分28秒