- DEX 文件中会出现的数据类型
类型 | 含义 |
u1 | 等同于 uint8_t,表示 1 字节的无符号 数 |
u2 | 等同于 uint16_t,表示 2 字节的无符号数 |
u4 | 等同于 uint32_t,表示 4 字节的无符号数 |
u8 | 等同于 uint64_t,表示 8 字节的无符号数 |
sleb128 | 有符号 LEB128,可变长度 1~5 字节 |
uleb128 | 无符号 LEB128,可变长度 1~5 字节 |
uleb128p1 | 无符号 LEB128 值加1,可变长 1~5 字节 |
sleb128、uleb128、uleb128p1:
- 小端结尾的,第一个字节代表的是整形值的最低 7 比特位的值,第二个字节代表次低 7 位,以此类推。所以代码中每发现要多用一个字节,都要多向左移动 7 位
- sleb128 需要进行符号位扩展,先左移到最左边,再算术右移同样的位数实现
- uleb128p1 是将其当做 uleb128 编码的值进行解码,然后再减一。解码时要减一,那么反过来编码时就要加一
- DEX 文件整体结构
结构体表示:
struct DexFile
{
DexHeader Header;
DexStringId StringIds[stringIdsSize];
DexTypeId TypeIds[typeIdsSize];
DexProtoId ProtoIds[protoIdsSize];
DexFieldId FieldIds[fieldIdsSize];
DexMethodId MethodIds[methodIdsSize];
DexClassDef ClassDefs[classDefsSize];
DexData Data[];
DexLink LinkData;
};
- DexHeader
DexHeader 结构的数据分为 “索引结构区” 和 “数据区”,“索引结构区” 中各数据结构的偏移地址都是从 DexHeader 结构的 stringIdsOff~classDefsOff 字段的值指定的,它们并非真正的类数据,而是指向 DEX 文件的 data 数据区相对于 Dex 头的偏移或结构索引。
下面所说的偏移都是指相对于 Dex 头的偏移
结构体表示:
typedef struct _DexHeader
{
u1 magic[8]; // dex 版本标识,"dex.035"
u4 checksum; // adler32 检验
u1 signature[kSHA1DigestLen]; // SHA-1 哈希值,20个字节
u4 fileSize; // 整个 dex 文件大小
u4 headerSize; // DexHeader 结构大小,0x70
u4 endianTag; // 字节序标记,小端 "0x12345678",大端"0x78563412"
u4 linkSize; // 链接段大小
u4 linkOff; // 链接段偏移
u4 mapOff; // DexMapList 的偏移
u4 stringIdsSize; // DexStringId 的个数
u4 stringIdsOff; // DexStringId 的偏移 字符串
u4 typeIdsSize; // DexTypeId 的个数
u4 typedeIdsOff; // DexTypeId 的偏移 类型
u4 protoIdsSize; // DexProtoId 的个数
u4 protoIdsOff; // DexProtoId 的偏移 声明
u4 fieldIdsSize; // DexFieldId 的个数
u4 fieldIdsOff; // DexFieldId 的偏移 字段
u4 methodIdsSize; // DexMethodId 的个数
u4 methodIdsOff; // DexMethodId 的偏移 方法
u4 classDefsSize; // DexClassDef 的个数
u4 classDefsOff; // DexClassDef 的偏移 类
u4 dataSize; // 数据段的大小
u4 dataOff; // 数据段的偏移
}DexHeader, *PDexHeader;
magic | 标识一个有效的 dex 文件,一般是 "dex.035" |
checksum | DEX 文件的校验和 |
signature | 文件的哈希值,20个字节 |
fileSize | 记录包括 DexHeader 在内的整个dex 文件的大小 |
headerSize | 记录 DexHeader 结构本身占用的字节数,目前为 0x70 |
endianTag | 指定 dex 运行环境的 CPU 字节序,小端:"0x12345678",大端:"0x78563412" |
linkSize | 表示链接段的大小,如果为 0 表示该 DEX 文件不是静态链接 |
linkOff | 表示链接段距离 Dex 头的偏移,如果 linkSize 为 0,此值也为 0 |
- mapOff 字段
指定 DexMapList 结构距离 Dex 头的偏移
DexMapList 结构体:
struct DexMapList
{
u4 size; // DexMapItem 的个数
DexMapItem list[1]; // DexMapItem 结构
};
- size:表示接下来有多少个 DexMapItem
- list:是一个 DexMapItem 结构体数组
struct DexMapItem
{
u2 type; // kDexType 开头的类型
u2 unused; // 未使用,用于对齐
u4 size; // 指定类型的个数
u4 offset; // 指定类型数据的文件偏移
};
- type:一个枚举常量
enum { kDexTypeHeaderItem = 0x0000, // 对应 DexHeader kDexTypeStringIdItem = 0x0001, // 对应 stringIdsSize 与 stringIdsOff 字段 kDexTypeTypeIdItem = 0x0002, // 对应 typeIdsSize 与 typeIdsOff 字段 kDexTypeProtoIdItem = 0x0003, // 对应 protoIdsSize 与 protoIdsOff 字段 kDexTypeFieldIdItem = 0x0004, // 对应 fieldIdsSize 与 fieldIdsOff 字段 kDexTypeMethodIdItem = 0x0005, // 对应 methodIdsSize 与 methodIdsOff 字段 kDexTypeClassDefItem = 0x0006, // 对应 classDefsSize 与 classDefsOff 字段 kDexTypeMapList = 0x1000, kDexTypeTypeList = 0x1001, kDexTypeAnnotationSetRefList = 0x1002, kDexTypeAnnotationSetItem = 0x1003, kDexTypeClassDataItem = 0x2000, kDexTypeCodeItem = 0x2001, kDexTypeStringDataItem = 0x2002, kDexTypeDebugInfoItem = 0x2003, kDexTypeAnnotationItem = 0x2004, kDexTypeEncodeArrayItem = 0x2005, kDexTypeAnnotationsDirectoryItem = 0x2006 };
- size:指定类型的个数
- offset:指定类型数据的偏移
- type:一个枚举常量
- DexStringId 结构体(stringIdsSize 与 stringIdsOff 字段)
typedef struct _DexStringId
{
u4 stringDataOff; // 指向 MUTF-8 字符串的偏移
}DexStringId, *PDexStringId;
1) 使用 1~3 字节编码长度
2) 大于 16 位的 Unicode 编码 U+10000~U+10FFFF 使用 3 字节来编码
3) U+0000 采用 2 字节编码
4) 采用空字符 null 作为结尾
5) 第一个字节存放字节个数(不包含自已)
- DexTypeId 结构体(typeIdsSize 与 typeIdsOff 字段)
是一个类型结构体
typedef struct _DexTypeId
{
u4 descriptorIdx; // 指向 DexStringId 列表的索引
}DexTypeId, *PDexTypeId;
- descriptorIdx:指向 DexStringId 列表的索引,它对应的字符串代表了具体类的类型
- DexProtoId 结构体(protoIdsSize 与 protoIdsOff 字段)
是一个方法声明结构体,
方法声明 = 返回类型 + 参数列表
typedef struct _DexProtoId
{
u4 shortyIdx; // 方法声明字符串,指向 DexStringId 列表的索引
u4 returnTypeIdx; // 方法返回类型字符串,指向 DexStringId 列表的索引
u4 parametersOff; // 方法的参数列表,指向 DexTypeList 结构体的偏移
}DexProtoId, *PDexProtoId;
- shortyIdx:方法声明字符串,方法声明 = 返回类型 + 参数列表
- returnTypeIdx:方法返回类型字符串
- parametersOff:指向一个 DexTypeList 结构体,存放了方法的参数列表
DexTypeList 结构体:
typedef struct _DexTypeList
{
u4 size; // 接下来 DexTypeItem 的个数
DexTypeItem* list; // DexTypeItem 结构
}DexTypeList, *PDexTypeList;
- size:接下来 DexTypeItem 的个数
- list:是一个 DexTypeItem 结构体数组
typedef struct _DexTypeItem
{
u2 typeIdx; // 指向 DexTypeId 列表的索引
}DexTypeItem, *PDexTypeItem;
- typeIdx:DexTypeId 列表的索引
- DexFieldId 结构体(fieldIdsSize 与 fieldIdsOff 字段)
指明了字段所有的类、字段的类型以及字段名
typedef struct _DexFieldId
{
u2 classIdx; // 类的类型,指向 DexTypeId 列表的索引
u2 typeIdx; // 字段的类型,指向 DexTypeId 列表的索引
u4 nameIdx; // 字段名,指向 DexStringId 列表的索引
}DexFieldId, *PDexFieldId;
- classIdx:类的类型
- typeIdx:字段的类型
- nameIdx:字段名
- DexMethodId 结构体(methodIdsSize 与 methodIdsOff 字段)
方法结构体
typedef struct _DexMethodId
{
u2 classIdx; // 类的类型,指向 DexTypeId 列表的索引
u2 protoIdx; // 声明的类型,指向 DexProtoId 列表的索引
u4 nameIdx; // 方法名,指向 DexStringId 列表的索引
}DexMethodId, *PDexMethodId;
- classIdx:类的类型
- protoIdx:声明的类型
- nameIdx:方法名
- DexClassDef 结构体(classDefsSize 和 classDefsOff 字段)
typedef struct _DexClassDef
{
u4 classIdx; // 类的类型,指向 DexTypeId 列表的索引
u4 accessFlags; // 访问标志
u4 superclassIdx; // 父类类型,指向 DexTypeId 列表的索引
u4 interfacesOff; // 接口,指向 DexTypeList 的偏移,否则为0
u4 sourceFileIdx; // 源文件名,指向 DexStringId 列表的索引
u4 annotationsOff; // 注解,指向 DexAnnotationsDirectoryItem 结构,或者为 0
u4 classDataOff; // 指向 DexClassData 结构的偏移,类的数据部分
u4 staticValuesOff; // 指向 DexEncodedArray 结构的偏移,记录了类中的静态数据,主要是静态方法
}DexClassDef, *PDexClassDef;
- classIdx:类的类型,指向 DexTypeId 列表的索引
- accessFlags:访问标志
- superclassIdx:父类类型,指向 DexTypeId 列表的索引
- interfacesOff:接口,指向 DexTypeList 的偏移,如果没有,则为 0
- sourceFileIdx:源文件名,指向 DexStringId 列表的索引
- annotationsOff:注解,指向 DexAnnotationsDirectoryItem 结构,或者为 0
- classDataOff:指向 DexClassData 结构的偏移,类的数据部分
- staticValuesOff:指向 DexEncodeArray 结构的偏移,记录了类中的静态数据,没有则为 0
DexClassData 结构体:
typedef struct _DexClassData
{
DexClassDataHeader header; // 指定字段与方法的个数
DexField* staticFields; // 静态字段,DexField 结构
DexField* instanceFields; // 实例字段,DexField 结构
DexMethod* directMethods; // 直接方法,DexMethod 结构
DexMethod* virtualMethods; // 虚方法,DexMethod 结构
}DexClassData, *PDexClassData;
- header:DexClassDataHeader 结构体,指定字段与方法的个数
- staticFields:静态字段,DexField 结构体数组
- instanceFields:实例字段,DexField 结构体数组
- directMethods:直接方法,DexMthod 结构体数组
- virtualMethods:虚方法,DexMethod 结构体数组
DexClassDataHeader 结构体:
typedef struct _DexClassDataHeader
{
uleb128 staticFieldsSize; // 静态字段个数
uleb128 instanceFieldsSize; // 实例字段个数
uleb128 directMethodsSize; // 直接方法个数
uleb128 virtualMethodsSize; // 虚方法个数
}DexClassDataHeader, *PDexClassDataHeader;
- staticFieldsSize:静态字段个数
- instanceFieldsSize:实例字段个数
- directMethodsSize:直接方法个数
- virtualMethodsSize:虚方法个数
DexField 结构体:
typedef struct _DexField
{
uleb128 fieldIdx; // 指向 DexFieldId 的索引
uleb128 accessFlags; // 访问标志
}DexField, *PDexField;
- fieldIdx:字段描述,指向 DexFieldId 的索引
- accessFlags:访问标志
DexMethod 结构体:
typedef struct _DexMethod
{
uleb128 methodIdx; // 指向 DexMethodId 的索引
uleb128 accessFlags; // 访问标志
uleb128 codeOff; // 指向 DexCode 结构的偏移
}DexMethod, *PDexMethod;
- methodIdx:方法描述,指向 DexMethodId 的索引
- accessFlags:访问标志
- codeOff:指向 DexCode 结构的偏移
DexCode 结构体:
typedef struct _DexCode
{
u2 registersSize; // 使用的寄存器个数
u2 insSize; // 参数个数
u2 outsSize; // 调用其他方法时使用的寄存器个数
u2 triesSize; // Try/Catch 个数
u4 debbugInfoOff; // 指向调试信息的偏移
u4 insnsSize; // 指令集个数,以 2 字节为单位
u2* insns; // 指令集
}DexCode, *PDexCode;
为了熟悉 Dex 文件格式,写了一个程序去解析 Dex 文件里的类的信息,程序比较粗糙,学习为主
dex.h
/*
* Dex 文件中数据结构的声明
*/
#pragma once
#include <string>
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef uint8_t u1;
typedef uint16_t u2;
typedef uint32_t u4;
typedef uint64_t u8;
typedef unsigned int uleb128;
typedef unsigned int uleb128p1;
typedef int sleb128;
#define kSHA1DigestLen 20
enum {
ACC_PUBLIC = 0x00000001, // class, field, method, ic
ACC_PRIVATE = 0x00000002, // field, method, ic
ACC_PROTECTED = 0x00000004, // field, method, ic
ACC_STATIC = 0x00000008, // field, method, ic
ACC_FINAL = 0x00000010, // class, field, method, ic
ACC_SYNCHRONIZED = 0x00000020, // method (only allowed on natives)
ACC_SUPER = 0x00000020, // class (not used in Dalvik)
ACC_VOLATILE = 0x00000040, // field
ACC_BRIDGE = 0x00000040, // method (1.5)
ACC_TRANSIENT = 0x00000080, // field
ACC_VARARGS = 0x00000080, // method (1.5)
ACC_NATIVE = 0x00000100, // method
ACC_INTERFACE = 0x00000200, // class, ic
ACC_ABSTRACT = 0x00000400, // class, method, ic
ACC_STRICT = 0x00000800, // method
ACC_SYNTHETIC = 0x00001000, // field, method, ic
ACC_ANNOTATION = 0x00002000, // class, ic (1.5)
ACC_ENUM = 0x00004000, // class, field, ic (1.5)
ACC_CONSTRUCTOR = 0x00010000, // method (Dalvik only)
ACC_DECLARED_SYNCHRONIZED =
0x00020000, // method (Dalvik only)
ACC_CLASS_MASK =
(ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT
| ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM),
ACC_INNER_CLASS_MASK =
(ACC_CLASS_MASK | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC),
ACC_FIELD_MASK =
(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL
| ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM),
ACC_METHOD_MASK =
(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL
| ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE
| ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR
| ACC_DECLARED_SYNCHRONIZED),
};
/*
* DexHeader
*/
typedef struct _DexHeader
{
u1 magic[8]; // dex 版本标识,"dex.035"
u4 checksum; // adler32 检验
u1 signature[kSHA1DigestLen]; // SHA-1 哈希值,20个字节
u4 fileSize; // 整个 dex 文件大小
u4 headerSize; // DexHeader 结构大小,0x70
u4 endianTag; // 字节序标记,小端 "0x12345678",大端"0x78563412"
u4 linkSize; // 链接段大小
u4 linkOff; // 链接段偏移
u4 mapOff; // DexMapList 的偏移
u4 stringIdsSize; // DexStringId 的个数
u4 stringIdsOff; // DexStringId 的偏移 字符串
u4 typeIdsSize; // DexTypeId 的个数
u4 typedeIdsOff; // DexTypeId 的偏移 类型
u4 protoIdsSize; // DexProtoId 的个数
u4 protoIdsOff; // DexProtoId 的偏移 声明
u4 fieldIdsSize; // DexFieldId 的个数
u4 fieldIdsOff; // DexFieldId 的偏移 字段
u4 methodIdsSize; // DexMethodId 的个数
u4 methodIdsOff; // DexMethodId 的偏移 方法
u4 classDefsSize; // DexClassDef 的个数
u4 classDefsOff; // DexClassDef 的偏移 类
u4 dataSize; // 数据段的大小
u4 dataOff; // 数据段的偏移
}DexHeader, *PDexHeader;
/*
* DexStringId
*/
typedef struct _DexStringId
{
u4 stringDataOff; // 指向 MUTF-8 字符串的偏移
}DexStringId, *PDexStringId;
/*
* DexTypeId
*/
typedef struct _DexTypeId
{
u4 descriptorIdx; // 指向 DexStringId 列表的索引
}DexTypeId, *PDexTypeId;
/*
* DexProtoId
*/
typedef struct _DexProtoId
{
u4 shortyIdx; // 方法声明字符串,指向 DexStringId 列表的索引,方法声明 = 返回类型+参数列表
u4 returnTypeIdx; // 方法返回类型字符串,指向 DexStringId 列表的索引
u4 parametersOff; // 方法的参数列表,指向 DexTypeList 结构体的偏移
}DexProtoId, *PDexProtoId;
/*
* DexFieldId
*/
typedef struct _DexFieldId
{
u2 classIdx; // 类的类型,指向 DexTypeId 列表的索引
u2 typeIdx; // 字段的类型,指向 DexTypeId 列表的索引
u4 nameIdx; // 字段名,指向 DexStringId 列表的索引
}DexFieldId, *PDexFieldId;
/*
* DexMethodId
*/
typedef struct _DexMethodId
{
u2 classIdx; // 类的类型,指向 DexTypeId 列表的索引
u2 protoIdx; // 声明的类型,指向 DexProtoId 列表的索引
u4 nameIdx; // 方法名,指向 DexStringId 列表的索引
}DexMethodId, *PDexMethodId;
typedef struct _DexClassDataHeader
{
uleb128 staticFieldsSize; // 静态字段个数
uleb128 instanceFieldsSize; // 实例字段个数
uleb128 directMethodsSize; // 直接方法个数
uleb128 virtualMethodsSize; // 虚方法个数
}DexClassDataHeader, *PDexClassDataHeader;
typedef struct _DexField
{
uleb128 fieldIdx; // 指向 DexFieldId 的索引
uleb128 accessFlags; // 访问标志
}DexField, *PDexField;
typedef struct _DexMethod
{
uleb128 methodIdx; // 指向 DexMethodId 的索引
uleb128 accessFlags; // 访问标志
uleb128 codeOff; // 指向 DexCode 结构的偏移
}DexMethod, *PDexMethod;
/*
* DexCode
*/
typedef struct _DexCode
{
u2 registersSize; // 使用的寄存器个数
u2 insSize; // 参数个数
u2 outsSize; // 调用其他方法时使用的寄存器个数
u2 triesSize; // Try/Catch 个数
u4 debbugInfoOff; // 指向调试信息的偏移
u4 insnsSize; // 指令集个数,以 2 字节为单位
u2* insns; // 指令集
}DexCode, *PDexCode;
/*
* DexClassDef
*/
typedef struct _DexClassDef
{
u4 classIdx; // 类的类型,指向 DexTypeId 列表的索引
u4 accessFlags; // 访问标志
u4 superclassIdx; // 父类类型,指向 DexTypeId 列表的索引
u4 interfacesOff; // 接口,指向 DexTypeList 的偏移,否则为0
u4 sourceFileIdx; // 源文件名,指向 DexStringId 列表的索引
u4 annotationsOff; // 注解,指向 DexAnnotationsDirectoryItem 结构,或者为 0
u4 classDataOff; // 指向 DexClassData 结构的偏移,类的数据部分
u4 staticValuesOff; // 指向 DexEncodedArray 结构的偏移,记录了类中的静态数据
}DexClassDef, *PDexClassDef;
/*
* DexClassData
*/
typedef struct _DexClassData
{
DexClassDataHeader header; // 指定字段与方法的个数
DexField* staticFields; // 静态字段,DexField 结构
DexField* instanceFields; // 实例字段,DexField 结构
DexMethod* directMethods; // 直接方法,DexMethod 结构
DexMethod* virtualMethods; // 虚方法,DexMethod 结构
}DexClassData, *PDexClassData;
/*
* DexData
*/
typedef struct _DexData
{
}DexData, *PDexData;
/*
* DexLink
*/
typedef struct _DexLink
{
}DexLink, *PDexLink;
/*
* DexTypeItem
*/
typedef struct _DexTypeItem
{
u2 typeIdx; // 指向 DexTypeId 列表的索引
}DexTypeItem, *PDexTypeItem;
/*
* DexTypeList
*/
typedef struct _DexTypeList
{
u4 size; // 接下来 DexTypeItem 的个数
DexTypeItem* list; // DexTypeItem 结构
}DexTypeList, *PDexTypeList;
/*
* DexFile
*/
class DexFile
{
// Dex 文件结构
private:
PDexHeader dexHeader; // dex 头
PDexStringId stringIds; // 字符串
PDexTypeId typeIds; // 类型
PDexProtoId protoIds; // 声明
PDexFieldId fieldIds; // 字段
PDexMethodId methodIds; // 方法
PDexClassDef classDefs; // 类
PDexData data; // 数据
PDexLink linkData; // 静态链接数据区,对于未优化的 Dex 文件始终为空
public:
DexFile(char* file);
void parseAllClass();
private:
std::string parseStringId(u4 index);
std::string parseTypeId(u4 index);
std::string parseProtoId(u4 index);
std::string parseFieldId(u4 index);
std::string parseMethodId(u4 index);
std::string parseClassDef(u4 index);
std::string parseDataTypeList(PDexTypeList);
std::string parseClassData(PDexClassData);
private:
/*
* MUTF8 转换成 ASCII
*/
inline char* MUTF8ToASCII(char *stream)
{
char* ptr = stream + 1;
return ptr;
}
/*
* int to string
*/
std::string IntToString(int num);
int uleb128ToInt(u1**);
int sleb128ToInt(u1**);
};
dex.cpp
/*
* 解析 Dex 文件
*/
#include "dex.h"
#include <sstream>
#include <string>
#include <iostream>
void DexFile::parseAllClass()
{
for (u4 i = 0; i < dexHeader->classDefsSize; ++i)
{
std::cout << parseClassDef(i) << std::endl;
std::cout << std::endl;
}
}
DexFile::DexFile(char* file)
{
// dex 头
dexHeader = reinterpret_cast<PDexHeader>(file);
if (dexHeader == nullptr)
{
return;
}
else
{
// 字符串
if (dexHeader->stringIdsOff != 0)
{
stringIds = reinterpret_cast<PDexStringId>((dexHeader->stringIdsOff) + reinterpret_cast<char*>(dexHeader));
}
else
{
stringIds = nullptr;
}
// 类型
if (dexHeader->typedeIdsOff == 0)
{
typeIds = nullptr;
}
else
{
typeIds = reinterpret_cast<PDexTypeId>((dexHeader->typedeIdsOff) + reinterpret_cast<char*>(dexHeader));
}
// 声明
if (dexHeader->protoIdsOff == 0)
{
protoIds = nullptr;
}
else
{
protoIds = reinterpret_cast<PDexProtoId>((dexHeader->protoIdsOff) + reinterpret_cast<char*>(dexHeader));
}
// 字段
if (dexHeader->fieldIdsOff == 0)
{
fieldIds = nullptr;
}
else
{
fieldIds = reinterpret_cast<PDexFieldId>((dexHeader->fieldIdsOff) + reinterpret_cast<char*>(dexHeader));
}
// 方法
if (dexHeader->methodIdsOff == 0)
{
methodIds = nullptr;
}
else
{
methodIds = reinterpret_cast<PDexMethodId>((dexHeader->methodIdsOff) + reinterpret_cast<char*>(dexHeader));
}
// 类
if (dexHeader->classDefsOff == 0)
{
classDefs = nullptr;
}
else
{
classDefs = reinterpret_cast<PDexClassDef>((dexHeader->classDefsOff) + reinterpret_cast<char*>(dexHeader));
}
// 数据
if (dexHeader->dataOff == 0)
{
data = nullptr;
}
else
{
data = reinterpret_cast<PDexData>((dexHeader->dataOff) + reinterpret_cast<char*>(dexHeader));
}
// 静态链接数据区
if (dexHeader->linkOff == 0)
{
linkData = nullptr;
}
else
{
linkData = reinterpret_cast<PDexLink>((dexHeader->linkOff) + reinterpret_cast<char*>(dexHeader));
}
}
return;
}
/*
* 根据索引获取字符串
* DexStringId 结构体
* typedef struct _DexStringId
* {
* u4 stringDataOff; // 指向 MUTF-8 字符串的偏移
* }DexStringId, *PDexStringId;
*/
std::string DexFile::parseStringId(u4 index)
{
return std::string(MUTF8ToASCII(reinterpret_cast<char *>(stringIds[index].stringDataOff + reinterpret_cast<char*>(dexHeader))));
}
/*
* 根据索引获取类型
* DexTypeId 结构体
* typedef struct _DexTypeId
* {
* u4 descriptorIdx; // 指向 DexStringId 列表的索引
* }DexTypeId, *PDexTypeId;
*/
std::string DexFile::parseTypeId(u4 index)
{
return parseStringId(typeIds[index].descriptorIdx);
}
/*
* 根据索引解析方法声明
* DexProtoId 结构体
* typedef struct _DexProtoId
* {
* u4 shortyIdx; // 方法声明字符串,指向 DexStringId 列表的索引,方法声明 = 返回类型+参数列表
* u4 returnTypeIdx; // 方法返回类型字符串,指向 DexStringId 列表的索引
* u4 parametersOff; // 方法的参数列表,指向 DexTypeList 结构的偏移
* }DexProtoId, *PDexProtoId;
*/
std::string DexFile::parseProtoId(u4 index)
{
// 方法声明 = 返回类型+参数列表
std::string funcString = parseStringId(protoIds[index].shortyIdx);
// 参数
if (protoIds[index].parametersOff != 0)
{
funcString.append(parseDataTypeList(reinterpret_cast<PDexTypeList>((protoIds[index].parametersOff) + reinterpret_cast<char*>(dexHeader))));
}
// 返回值
funcString.append(parseTypeId(protoIds[index].returnTypeIdx));
return funcString;
}
/*
* 根据索引解析字段
* DexFieldId 结构体
* typedef struct _DexFieldId
* {
* u2 classIdx; // 类的类型,指向 DexTypeId 列表的索引
* u2 typeIdx; // 字段的类型,指向 DexTypeId 列表的索引
* u4 nameIdx; // 字段名,指向 DexStringId 列表的索引
* }DexFieldId, *PDexFieldId;
*/
std::string DexFile::parseFieldId(u4 index)
{
std::string fieldString = parseTypeId(fieldIds[index].classIdx);
fieldString.append(parseTypeId(fieldIds[index].typeIdx));
fieldString.append(parseStringId(fieldIds[index].nameIdx));
return fieldString;
}
/*
* 根据索引解析方法
* DexMethodId 结构体
* typedef struct _DexMethodId
* {
* u2 classIdx; // 类的类型,指向 DexTypeId 列表的索引
* u2 protoIdx; // 声明的类型,指向 DexProtoId 列表的索引
* u4 nameIdx; // 方法名,指向 DexStringId 列表的索引
* }DexMethodId, *PDexMethodId;
*/
std::string DexFile::parseMethodId(u4 index)
{
std::string methodString = parseTypeId(methodIds[index].classIdx);
methodString.append(parseProtoId(methodIds[index].protoIdx));
methodString.append(parseStringId(methodIds[index].nameIdx));
return methodString;
}
/*
* 根据索引解析类
* DexClassDef 结构
* typedef struct _DexClassDef
* {
* u4 classIdx; // 类的类型,指向 DexTypeId 列表的索引
* u4 accessFlags; // 类的访问标志
* u4 superclassIdx; // 父类类型索引值,指向 DexTypeId 列表的索引,如果没有父类?
* u4 interfacesOff; // 接口,如果有指向 DexTypeList 结构,否则为0
* u4 sourceFileIdx; // 源文件名,指向 DexStringId 列表的索引
* u4 annotationsOff; // 注解,指向 DexAnnotationsDirectoryItem,或者为0
* u4 classDataOff; // 指向 DexClassData 结构的偏移,类的数据部分
* u4 staticValuesOff; // 指向 DexEncodeArray 结构的偏移,记录了类中的静态数据
*/
std::string DexFile::parseClassDef(u4 index)
{
std::string classString = "类类型:";
// 类类型
classString.append(parseTypeId(classDefs[index].classIdx));
// 类的访问标志
// 父类
classString.append("\n父类:");
classString.append(parseTypeId(classDefs[index].superclassIdx));
// 接口
if (classDefs[index].interfacesOff != 0)
{
classString.append("\n接口:");
classString.append(parseDataTypeList(reinterpret_cast<PDexTypeList>((classDefs[index].interfacesOff) + reinterpret_cast<char*>(dexHeader))));
}
// 源文件名
classString.append("\n源文件名:");
classString.append(parseStringId(classDefs[index].sourceFileIdx));
// 注解
// 暂时不处理
// 类的数据
if (classDefs[index].classDataOff != 0)
{
classString.append(parseClassData(reinterpret_cast<PDexClassData>((classDefs[index].classDataOff) + reinterpret_cast<char*>(dexHeader))));
}
// 类的静态数据
if (classDefs[index].staticValuesOff != 0)
{
// do something
}
return classString;
}
/*
* DexClassData 结构体
* typedef struct _DexClassData
* {
* DexClassDataHeader header; // 指定字段与方法的个数
* DexField* staticFields; // 静态字段
* DexField* instanceFields; // 实例字段
* DexMethod* directMethods; // 直接方法
* DexMethod* virtualMethods; // 虚方法
* }DexClassData, *PDexClassData;
*
* DexClassDataHeader 结构体
* typedef struct _DexClassDataHeader
* {
* uleb128 staticFieldsSize; // 静态字段个数
* uleb128 instanceFieldsSize; // 实例字段个数
* uleb128 directMethodsSize; // 直接方法个数
* uleb128 virtualMethodsSize; // 虚方法个数
* }DexClassDataHeader, *PDexClassDataHeader;
*/
std::string DexFile::parseClassData(PDexClassData classData)
{
u1* ptr = reinterpret_cast<u1*>(classData);
std::string str = "";
u4 staticFieldsSize = uleb128ToInt(&ptr);
u4 instanceFieldsSize = uleb128ToInt(&ptr);
u4 directMethodsSize = uleb128ToInt(&ptr);
u4 virtualMethodsSize = uleb128ToInt(&ptr);
// 静态字段
if (staticFieldsSize != 0)
{
str.append("\n静态字段个数:");
str.append(IntToString(staticFieldsSize));
// 解析 DexField
for (u4 i = 0; i < staticFieldsSize; ++i)
{
str.append("\n静态字段:");
str.append(parseFieldId(uleb128ToInt(&ptr)));
str.append("\n访问标志:");
str.append(IntToString(uleb128ToInt(&ptr)));
}
}
// 实例字段
if (instanceFieldsSize != 0)
{
str.append("\n实例字段个数:");
str.append(IntToString(instanceFieldsSize));
// 解析 DexField
for (u4 i = 0; i < instanceFieldsSize; ++i)
{
str.append("\n实例字段:");
str.append(parseFieldId(uleb128ToInt(&ptr)));
str.append("\n访问标志");
str.append(IntToString(uleb128ToInt(&ptr)));
}
}
// 直接方法
if (directMethodsSize != 0)
{
str.append("\n直接方法个数:");
str.append(IntToString(directMethodsSize));
// 解析 DexMethod
for (u4 i = 0; i < directMethodsSize; ++i)
{
str.append("\n直接方法:");
str.append(parseMethodId(uleb128ToInt(&ptr)));
str.append("\n访问标志:");
str.append(IntToString(uleb128ToInt(&ptr)));
str.append("\nDexCode的偏移:");
str.append(IntToString(uleb128ToInt(&ptr)));
}
}
// 虚方法
if (virtualMethodsSize != 0)
{
str.append("\n虚方法个数:");
str.append(IntToString(virtualMethodsSize));
// 解析 DexMethod
for (u4 i = 0; i < virtualMethodsSize; ++i)
{
str.append("\n虚方法:");
str.append(parseMethodId(uleb128ToInt(&ptr)));
str.append("\n访问标志:");
str.append(IntToString(uleb128ToInt(&ptr)));
str.append("\nDexCode的偏移:");
str.append(IntToString(uleb128ToInt(&ptr)));
}
}
return str;
}
/************************************************
* DexTypeList 结构体
* typedef struct _DexTypeList
* {
* u4 size; // 接下来 DexTypeItem 的个数
* PDexTypeItem list; // DexTypeItem 结构
* }DexTypeList, *PDexTypeList;
*
* DexTypeItem 结构体
* typedef struct _DexTypeItem
* {
* u2 typeIdx; // 指向 DexTypeId 列表的索引
* }DexTypeItem, *PDexTypeItem;
************************************************/
std::string DexFile::parseDataTypeList(PDexTypeList typeList)
{
std::string str = "";
PDexTypeItem ptr = reinterpret_cast<PDexTypeItem>((reinterpret_cast<char*>(typeList)) + sizeof(u4));
for (u4 i = 0; i < typeList->size; ++i)
{
str.append(parseTypeId(ptr[i].typeIdx));
}
return str;
}
int DexFile::uleb128ToInt(u1** pStream)
{
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;
}
int DexFile::sleb128ToInt(u1** pStream)
{
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;
}
std::string DexFile::IntToString(int num)
{
std::stringstream strStream;
std::string str;
strStream << num;
strStream >> str;
return str;
}