【Android SDK程序逆向分析与破解系列】之二:Android可执行程序DEX分析(一)

作者:郭嘉
邮箱:[email protected]
博客:http://blog.csdn.net/allenwells
github:https://github.com/AllenWells

【Android SDK程序逆向分析与破解系列】章节索引

一 DEX文件数据结构

DEX使用的数据类型如下表所示:
技术分享

u1~u8:表示1~8字节的无符号数。
sleb128、uled128和uled128pl:DEX文件特有的LEB128数据类型。每个LEB128由1~5个字节组成,所有的字节组合在一起表示一个32位的数据。

LEB128数据类型如下表所示:
技术分享

每个字节只有7位有效位,如果第一个字节的最高位为1,则表明LEB128需要用到第2个字节,如果第2个字节最高位为1,则表明LEB128需要用到第3个字节,依次类推,知道最后的字节最高位为0.LEB128最多只会使用5个字节,如果读取5个字节后下一个字节的最高位仍为1,则表明该DEX文件无效,Dalvik虚拟机在验证DEX会失败返回。

Android系统源码中读取无符号LEB128的实现如下所示:

源码位置dalvik\libdex\Leb128.h

/*
 * 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) {    //大于0x77f表示第1个字节最高位为1
        int cur = *(ptr++); //第2个字节
        result = (result & 0x7f) | ((cur & 0x7f) << 7);//前2个字节组合
        if (cur > 0x7f) {   //大于0x77f表示第2个字节最高位为1
            cur = *(ptr++); //第3个字节
            result |= (cur & 0x7f) << 14;    //前3个字节的组合
            if (cur > 0x7f) {
                cur = *(ptr++);              //第4个字节
                result |= (cur & 0x7f) << 21;//前4个字节的组合
                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++);          //第5个字节
                    result |= cur << 28;     //前5个字节的组合
                }
            }
        }
    }

    *pStream = ptr;
    return result;
}

Android系统源码中读取有符号LEB128的实现如下所示(有符号与无符号的计算方法是一样的,只是对有符号的LEB128最后一个字节的最高有效位进行了符号扩展):

源码位置dalvik\libdex\Leb128.h

/*
 * Reads a signed 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 readSignedLeb128(const u1** pStream) {
    const u1* ptr = *pStream;
    int result = *(ptr++);

    if (result <= 0x7f) {
        result = (result << 25) >> 25;
    } else {
        int cur = *(ptr++);
        result = (result & 0x7f) | ((cur & 0x7f) << 7);
        if (cur <= 0x7f) {
            result = (result << 18) >> 18;
        } else {
            cur = *(ptr++);
            result |= (cur & 0x7f) << 14;
            if (cur <= 0x7f) {
                result = (result << 11) >> 11;
            } else {
                cur = *(ptr++);
                result |= (cur & 0x7f) << 21;
                if (cur <= 0x7f) {
                    result = (result << 4) >> 4;
                } else {
                    /*
                     * 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;
}

二 DEX文件整体结构

DEX文件由多个结构体组合而成,具体结构如下图所示:
技术分享
- dex header:DEX文件头,指定了dex文件的一些属性,并记录了其他6部分在DEX文件中的物理偏移。
- string_ids
- type_ids
- proto_ids
- field_ids
- method_ids
- class_def
- data:真实的数据存放区。
- link_data:静态链接数据区。

Android源码中DexFile结构体的定义如下所示:

DexFile结构为DEX文件被映射到内存中结构,保存各个结构的指针,还包括了DexOptHeader与DexFile尾部附加的数据。

源码位置dalvik\libdex\DexFile.h

/*
 * Structure representing a DEX file.
 *
 * Code should regard DexFile as opaque, using the API calls provided here
 * to access specific structures.
 */
struct DexFile {
    /* directly-mapped "opt" header */
    const DexOptHeader* pOptHeader;

    /* pointers to directly-mapped structs and arrays in base DEX */
    const DexHeader*    pHeader;
    const DexStringId*  pStringIds;
    const DexTypeId*    pTypeIds;
    const DexFieldId*   pFieldIds;
    const DexMethodId*  pMethodIds;
    const DexProtoId*   pProtoIds;
    const DexClassDef*  pClassDefs;
    const DexLink*      pLinkData;

    /*
     * These are mapped out of the "auxillary" section, and may not be
     * included in the file.
     */
    const DexClassLookup* pClassLookup;
    const void*         pRegisterMapPool;       // RegisterMapClassPool

    /* points to start of DEX file data */
    const u1*           baseAddr;

    /* track memory overhead for auxillary structures */
    int                 overhead;

    /* additional app-specific data structures associated with the DEX */
    //void*               auxData;
};

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。