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

作者:郭嘉 邮箱:allenwells@163.com 博客: 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个字节最高位为1int cur = *(ptr++); //第2个字节result = (result & 0x7f) | ((cur & 0x7f) << 7);//前2个字节组合if (cur > 0x7f) { //大于0x77f表示第2个字节最高位为1cur = *(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;u1*baseAddr;/* track memory overhead for auxillary structures */intoverhead;/* additional app-specific data structures associated with the DEX *///void*auxData;};

生活比你想象的要容易得多,只要学会接受那些不可接受的,

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

相关文章:

你感兴趣的文章:

标签云: