-
-
Dex文件结构-ReadDex解析器实现
-
发表于: 1天前 1030
-
近期学习DEX文件结构为学习APP加壳脱壳打基础,自实现了一个简易的DEX解析器加深理解
DEX文件结构整体看不复杂,深究时发现DexCLassDef结构非常复杂,编码的数据结构,嵌套和指向关系
本文作为近期学习的一个阶段总结以及知识分享,后期再完善Todo部分
由于本人水平有限,文章错漏之处还望大佬批评指正
环境&工具:
010editor 15.0.1 (13.0.1有bug,打开大文件分析时容易崩溃)
Clion 2024.2.3
JDK 11.0.23
MinGW 14.2.0
Android Studio
自行编译dex文件供后续分析
可能遇到报错如下,这是因为d8需要java11+的环境,不支持java8
Android源码 http://androidxref.com/2.3.7/xref/dalvik/libdex/DexFile.h 定义了dex文件用到的数据结构
sleb128、uleb128、uleb128p1是Dex文件中特有的LEB128类型.在下述Android源码位置可以找到LEB128的实现.http://androidxref.com/2.3.7/xref/dalvik/libdex/Leb128.h
每个LEB128由1-5字节组成,所有字节组合在一起表示一个32位的数据, 每个字节只有低7位为有效位,最高位标识是否需要使用额外字节
如果第1个字节的最高位为1,表示LEB128需要使用第2个字节,如果第2个字节的最高位为1,表示会使用第3个字节,依次类推,直到最后一个字节的最高位为0
uleb128读取代码如下
值得注意的是参数为二级指针,也就是说,调用该函数时会移动一级指针,一级指针的偏移量即为读取到的uleb128的大小
为方便使用自定义了myReadUnsignedLeb128函数,参数为一级指针,返回读取的数据及其大小
参考Android官方文档https://source.android.com/docs/core/dalvik/dex-format?hl=zh-cn#encoding
解析代码参考以下文档,只找到了java代码
http://androidxref.com/2.3.7/xref/cts/tools/dex-tools/src/dex/reader/DexEncodedValueImpl.java
http://androidxref.com/2.3.7/xref/dalvik/dx/src/com/android/dx/dex/file/ValueEncoder.java
解析DexClassDef结构时,Annotation的annotation_element和encoded_array_item会使用该编码
编码格式如下,1字节的头用于指定value格式和大小,后续紧跟数据,需要根据类型解析
value_type枚举定义如下
解析代码如下(该函数在解析DexClassDef的Annotation时才会使用,可先忽略)
parseEncodedValue函数会自动读取单个encoded_value并返回解析后的字符串(类型:值 的键值对形式)以及value占用的真实字节数
由于encoded_array.values数组元素为encoded_value,所以每个元素的大小不固定,不能当作一般的数组解析
该类型主要在DexClassDef的Annotations部分使用,此处仅做介绍
dex文件整体结构分为: dex文件头, 索引结构区, data数据区, 示意图如下:
dex文件头
保存了dex文件的基本信息, 例如文件大小,dex头大小,大小端序,索引表的起始地址和大小等
索引结构区
这部分保存了字符串表,类型表,方法原型表,域表,方法表等结构
根据这些表和索引可以访问到对应数据
data数据区
所有的代码和数据存放在该区域
dex文件结构体的定义在Android源码目录/dalvik/libdex/DexFile.h中可以找到,其中定义的dex文件结构体如下:
为方便使用仅保留部分字段,编写相关函数如下
通过字节buffer或文件路径创建DexFile类并初始化各个字段
DexHeader定义如下
打印DexHeader
效果如下
定义如下
注意dex文件的字符串采用MUTF-8编码,与UTF-8区别如下:
MUTF-8字符串头部保存的是字符串长度,是uleb128类型
相关函数定义如下,解析StringId
打印所有StringId,没有做MUTF编码处理,直接打印ASCII字符串
效果如下,没有做编码处理故可能出现乱码
定义如下
descriptorIdx为DexStringID表的索引,对应字符串表示类的类型
例如此处DexTypeID[3].descriptorIdx=6, 而DexStringID[6]对应的字符串为"Ljava/lang/String;"
和StringId类似,TypeId的解析代码如下,通过索引获取StringId及其对应的字符串
打印所有TypeId
效果如下
DexProtoId是**方法声明(方法签名)**的结构体,保存方法(函数)的返回值类型和参数类型列表,没有函数名,定义如下
parametersOff是DexTypeList的文件偏移
结构定义如下
例如此处DexProtoID[1]
方法声明 DexStringID[shortyIdx]="VL"
返回类型 DexStringID[DexTypeID[returnTypeIdx]]="V"
参数列表 DexStringID[DexTypeID[typeIdx]]="Ljava/lang/String;"
解析代码如下
打印所有ProtoId
效果如下
DexFieldID结构体指明了成员变量所在的类,类型以及变量名
寻找方法类似,out是java.lang.System类的成员,类型为java.io.PrintStream
解析代码如下
打印所有ProtoId
效果如下
DexMethodId结构体指明了方法所在的类、方法声明(签名)以及方法名, 即完整的方法声明
寻找方法
对应解析代码如下
打印所有MethodId
效果如下
Dalvik虚拟机解析dex文件后,映射为DexMapList的数据结构, 该结构由DexHeader.mapOff指明位置
type是枚举常量,用于判断类型
size指定了类型个数,在dex文件中连续存放, offset是起始地址文件偏移
例如DexMapList[1] type=string_id_item, size=0xF, offset=0x70
和DexStringID表正好对应,起始地址,表项数
解析代码如下
打印效果如下
该结构较为复杂(这部分相关代码比前文所有结构代码之和都大)
有了对Dex文件的基本了解和上面各个结构的基础,才能解析该结构
DexClassDef保存了类的相关信息,定义如下
解析代码如下
将ClassDef结构划分为4部分解析: BasicInfo, Annotations, ClassData, StaticValues, 从classIdx到sourceFileIx属于BasicInfo
每部分使用单独的打印函数进行处理
代码如下
效果如下
annotationsOff指向该结构,用于指向类的所有注解,定义如下
printClassDefAnnotations函数用于打印该结构,根据不同注解类型调用不同函数解析
visibility表示注释的可见性,主要有以下几种情况:
annotation是采用encoded_annotation格式的注释内容, encoded_annotation格式如下:
annotation_element元素格式如下:
解析代码如下
效果如下, 打印类注解及其包含的encoded_element内容
定义如下
由于指向DexAnnotationSetItem结构,故解析方式和类注解类似
效果如下
定义如下
解析方法类似
效果如下
定义如下
DexAnotationSetRefList结构体定义如下
解析方法略有不同,代码如下
效果如下
定义在http://androidxref.com/2.3.7/xref/dalvik/libdex/DexClass.h中
注意: DexClass.h定义的结构体中,u4类型实际类型为uleb128
内部的结构体定义如下:
注意u4均为uleb128,所以这些结构大小不固定,无法通过sizeof计算,需要手动计算
其中codeOff指向DexCode结构,定义如下
解析代码如下,
效果如下
定义如下
encoded_array格式定义如下:
解析代码如下
效果如下
JVM是java语言的虚拟机,运行.class文件
Dalvik是google设计的用于Android平台的虚拟机,运行.dex文件
JVM基于栈,DVM基于寄存器,可以做到更好的提前优化,并且运行速度更快
Android 4.4首次提出ART虚拟机,在Android 5.0后弃用Dalvik,默认使用ART,运行oat文件
DVM应用运行时,字节码需要通过即时编译器JIT转换为机器码运行
ART则在应用第一次安装时,预先将字节码编译为机器码,该过程称之为预编译(AOT Ahead of time)
.java文件 经javac编译后生成 .class 文件 再通过dx/d8生成.dex文件
Dalvik虚拟机运行.dex文件,一个apk包内可能含有多个dex文件
Android5.0前,使用Dalvik虚拟机,ODEX是Dalvik对Dex文件优化后的产物, 通常存放在/data/dalvik-cache目录下
运行程序时直接加载odex文件,避免重复验证和优化
Android 5.0后,使用ART虚拟机, .odex实际上是OAT文件(ART定制的ELF文件)
OAT文件是Android4.4中引入的, Android5.0后,系统默认虚拟机为ART
OAT文件即是ART虚拟机对Dex优化后的产物,是Android定制的ELF文件
OAT文件结构随Android版本变化而变化,没有向后兼容性
VDEX文件在Android 8.0后引入, 不是Android系统的可执行文件,
Android 8.0后, dex2oat将class.dex优化生成2个文件: OAT文件(.odex)和VDEX文件(.vdex)
.art文件是一种ELF可执行文件 借助odex文件优化生成, 记录应用启动的热点函数相关地址,便于寻址加速
art文件结构随android版本变化,无向后兼容性
Dalvik 可执行文件格式 Android官方文档
从JVM到Dalivk再到ART(class,dex,odex,vdex,ELF)
android的dex,odex,oat,vdex,art文件格式
附件: ReadDex.zip 工程项目压缩包
public
class
HelloDEX{
public
static
void
main(String[] args){
System.out.println(
"Hello Dex!"
);
}
}
public
class
HelloDEX{
public
static
void
main(String[] args){
System.out.println(
"Hello Dex!"
);
}
}
Error: A JNI error has occurred, please check your installation
and
try
again
Exception
in
thread
"main"
java.lang.UnsupportedClassVersionError: com
/
android
/
tools
/
r8
/
D8 has been compiled by a more recent version of the Java Runtime (
class
file
version
55.0
), this version of the Java Runtime only recognizes
class
file
versions up to
52.0
Error: A JNI error has occurred, please check your installation
and
try
again
Exception
in
thread
"main"
java.lang.UnsupportedClassVersionError: com
/
android
/
tools
/
r8
/
D8 has been compiled by a more recent version of the Java Runtime (
class
file
version
55.0
), this version of the Java Runtime only recognizes
class
file
versions up to
52.0
自定义类型 | 原类型 | 含义 |
---|---|---|
s1 | int8_t | 有符号单字节 |
u1 | uint8_t | 无符号单字节 |
s2 | int16_t | |
u2 | uint16_t | |
s4 | int32_t | |
u4 | uint32_t | |
s8 | int64_t | |
u8 | uint64_t | |
sleb128 | 无 | 有符号LEB128,可变长度 |
uleb128 | 无 | 无符号LEB128,可变长度 |
uleb128p1 | 无 | 等于ULEB128加1,可变长度 |
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;
}
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;
}
// 传入指针直接读取数据并返回数据和读取的大小(可选)
int
myReadUnsignedLeb128(
const
u1* pData,
size_t
* readSize) {
const
u1** pStream = &pData;
u4 result=readUnsignedLeb128(pStream);
if
(readSize)
*readSize=unsignedLeb128Size(result);
return
result;
}
// 传入指针直接读取数据并返回数据和读取的大小(可选)
int
myReadUnsignedLeb128(
const
u1* pData,
size_t
* readSize) {
const
u1** pStream = &pData;
u4 result=readUnsignedLeb128(pStream);
if
(readSize)
*readSize=unsignedLeb128Size(result);
return
result;
}
名称 | 格式 | 说明 |
---|---|---|
(value_arg << 5) | value_type | ubyte | 高3位为value_arg的值,低5位为value_type的值,value_type指定value的格式。 |
value | ubyte[] | 用于表示值的字节,不同 value_type 字节的长度不同且采用不同的解译方式;不过一律采用小端字节序。 |
类型名称 | value_type | value_arg | value格式 | 说明 |
---|---|---|---|---|
VALUE_BYTE | 0x00 | (无;必须为 0 ) |
ubyte[1] | 有符号的单字节整数值 |
VALUE_SHORT | 0x02 | size - 1 (0…1) | ubyte[size] | 有符号的双字节整数值,符号扩展 |
VALUE_CHAR | 0x03 | size - 1 (0…1) | ubyte[size] | 无符号的双字节整数值,零扩展 |
VALUE_INT | 0x04 | size - 1 (0…3) | ubyte[size] | 有符号的四字节整数值,符号扩展 |
VALUE_LONG | 0x06 | size - 1 (0…7) | ubyte[size] | 有符号的八字节整数值,符号扩展 |
VALUE_FLOAT | 0x10 | size - 1 (0…3) | ubyte[size] | 四字节位模式,向右零扩展,系统会将其解译为 IEEE754 32 位浮点值 |
VALUE_DOUBLE | 0x11 | size - 1 (0…7) | ubyte[size] | 八字节位模式,向右零扩展,系统会将其解译为 IEEE754 64 位浮点值 |
VALUE_METHOD_TYPE | 0x15 | size - 1 (0…3) | ubyte[size] | 无符号(零扩展)四字节整数值,会被解译为要编入 proto_ids 区段的索引;表示方法类型值 |
VALUE_METHOD_HANDLE | 0x16 | size - 1 (0…3) | ubyte[size] | 无符号(零扩展)四字节整数值,会被解译为要编入 method_handles 区段的索引;表示方法句柄值 |
VALUE_STRING | 0x17 | size - 1 (0…3) | ubyte[size] | 无符号(零扩展)四字节整数值,会被解译为要编入 string_ids 区段的索引;表示字符串值 |
VALUE_TYPE | 0x18 | size - 1 (0…3) | ubyte[size] | 无符号(零扩展)四字节整数值,会被解译为要编入 type_ids 区段的索引;表示反射类型/类值 |
VALUE_FIELD | 0x19 | size - 1 (0…3) | ubyte[size] | 无符号(零扩展)四字节整数值,会被解译为要编入 field_ids 区段的索引;表示反射字段值 |
VALUE_METHOD | 0x1a | size - 1 (0…3) | ubyte[size] | 无符号(零扩展)四字节整数值,会被解译为要编入 method_ids 区段的索引;表示反射方法值 |
VALUE_ENUM | 0x1b | size - 1 (0…3) | ubyte[size] | 无符号(零扩展)四字节整数值,会被解译为要编入 field_ids 区段的索引;表示枚举类型常量的值 |
VALUE_ARRAY | 0x1c | (无;必须为 0 ) |
encoded_array | 值的数组,采用下文“encoded_array 格式”所指定的格式。value 的大小隐含在编码中。 |
VALUE_ANNOTATION | 0x1d | (无;必须为 0 ) |
encoded_annotation | 子注解,采用下文“encoded_annotation 格式”所指定的格式。value 的大小隐含在编码中。 |
VALUE_NULL | 0x1e | (无;必须为 0 ) |
(无) |
null 引用值 |
VALUE_BOOLEAN | 0x1f | 布尔值 (0…1) | (无) | 一位值;0 表示 false ,1 表示 true 。该位在 value_arg 中表示。 |
// 读取EncodedValue, 由于大小不固定, 故直接以数组赋值形式取值
void
DexFile::getEncodedValue(ubyte* pDest,
const
ubyte* pValue,
int
size) {
for
(
int
i=0;i<size;i++) {
pDest[i]=pValue[i];
}
}
// 解析EncodedValue, 返回解析后的字符串以及value真实大小 Todo: 完善解析逻辑,剩余3个分支
std::string DexFile::parseEncodedValue(ubyte* pEncodedValue,
size_t
& valueRealSize) {
ubyte valueArg = GetValueArg(pEncodedValue[0]);
// arg=size-1,值占用的字节数<=对应类型大小,不含头部的单字节
ubyte valueType = GetValueType(pEncodedValue[0]);
// 假如int=0时,占2字节,头1字节,值0占1字节,所以要同时判断arg和type
if
(valueArg==0) {
//arg==0时,要确定是arg固定为0的特殊类型还是其他类型
//特殊类型只有1字节头,其他类型是1字节头+1字节数据
bool
isSpecialType=
false
;
switch
(valueType) {
case
VALUE_BYTE:
case
VALUE_ARRAY:
case
VALUE_ANNOTATION:
case
VALUE_NULL:
case
VALUE_BOOLEAN:
isSpecialType=
true
;
break
;
}
if
(isSpecialType)
valueRealSize=1;
else
valueRealSize=2;
}
else
valueRealSize=valueArg+2;
// 头部1字节+实际大小 size=head+arg+1
int
readValueSize=valueArg+1;
// 需要读取的字节数
ubyte* pValue=&pEncodedValue[1];
std::string result;
unsigned
int
index=0;
switch
(valueType) {
// 有符号单字节
case
VALUE_BYTE: {
char
byte=0;
getEncodedValue((ubyte*)&byte,pValue,readValueSize);
result=
"byte:"
+std::format(
"0x{:x}"
,byte);
break
;
}
// 有符号双字节
case
VALUE_SHORT: {
short
value_short=0;
getEncodedValue((ubyte*)&value_short,pValue,readValueSize);
result=
"short:"
+std::format(
"0x{:x}"
,value_short);
break
;
}
// 无符号双字节
case
VALUE_CHAR: {
unsigned
short
value_char=0;
getEncodedValue((ubyte*)&value_char,pValue,readValueSize);
result=
"char:"
+std::format(
"0x{:x}"
,value_char);
break
;
}
// 有符号4字节
case
VALUE_INT: {
int
value_int=0;
getEncodedValue((ubyte*)&value_int,pValue,readValueSize);
result=
"int:"
+std::format(
"0x{:x}"
,value_int);
break
;
}
// 有符号8字节
case
VALUE_LONG: {
long
long
value_long=0;
getEncodedValue((ubyte*)&value_long,pValue,readValueSize);
result=
"long:"
+std::format(
"0x{:x}"
,value_long);
break
;
}
// 4字节浮点
case
VALUE_FLOAT: {
float
value_float=0;
getEncodedValue((ubyte*)&value_float,pValue,readValueSize);
result=
"float:"
+std::format(
"{:f}"
,value_float);
break
;
}
// 8字节浮点
case
VALUE_DOUBLE: {
double
value_double=0;
getEncodedValue((ubyte*)&value_double,pValue,readValueSize);
result=
"double:"
+std::format(
"{:f}"
,value_double);
break
;
}
// 无符号4字节索引 指向对应结构
case
VALUE_METHOD_TYPE: {
// ProtoId
getEncodedValue((ubyte*)&index,pValue,readValueSize);
result=
"MethodType:"
+std::format(
"0x{:x}"
,index)+
" "
+getProtoIdDataByIndex(index);
break
;
}
// todo: 这部分没有定义的成员指向,暂时不知如何解析,参考 https://source.android.com/docs/core/runtime/dex-format?hl=zh-cn#method-handle-item
case
VALUE_METHOD_HANDLE: {
// MethodHandles
getEncodedValue((ubyte*)&index,pValue,readValueSize);
result=
"MethodHandle Index:"
+std::format(
"0x{:x}"
,index);
break
;
}
case
VALUE_STRING: {
// StringId
getEncodedValue((ubyte*)&index,pValue,readValueSize);
result=
"String:"
+getStringIdDataByIndex(index);
break
;
}
case
VALUE_TYPE: {
// TypeId
getEncodedValue((ubyte*)&index,pValue,readValueSize);
result=
"Type:"
+parseString(getTypeIdDataByIndex(index));
break
;
}
case
VALUE_FIELD: {
// FieldId
getEncodedValue((ubyte*)&index,pValue,readValueSize);
result=
"Field:"
+parseString(getFieldIdDataByIndex(index));
break
;
}
case
VALUE_METHOD: {
// MethodId
getEncodedValue((ubyte*)&index,pValue,readValueSize);
result=
"Method:"
+parseString(getMethodIdDataByIndex(index));
break
;
}
case
VALUE_ENUM: {
// FieldId
getEncodedValue((ubyte*)&index,pValue,readValueSize);
result=
"Enum:"
+parseString(getFieldIdDataByIndex(index));
break
;
}
// todo encoded_array和encoded_annotation结构,不太容易解析
case
VALUE_ARRAY: {
//getEncodedValue((ubyte*)&index,pValue,readValueSize);
// DexEncodedArray encodedArray;//直接解析貌似不正确
// getEncodedValue((ubyte*)&encodedArray,pValue,readValueSize);
// printClassDefStaticValues(encodedArray);
// int sizeLen=0;
// u4 size=myReadUnsignedLeb128(pValue,&sizeLen);
// u1* pValues=pValue+sizeLen;
// printf("EncodedArray contains %d values\n",size);
// unsigned int offset=0;// offset保存前方已访问的结构大小
// for(int i=0;i<size;i++) {
// printf("%s\n",parseEncodedValue(pValues+offset,offset).c_str());
// }
//system("pause");
break
;
}
case
VALUE_ANNOTATION:
result=
"Todo......"
;
break
;
case
VALUE_NULL:
result=
"null"
;
break
;
// boolean的值存在value_arg中
case
VALUE_BOOLEAN:
result=
"bool:"
;
if
(valueArg)
result+=
"true"
;
else
result+=
"false"
;
break
;
default
:
result=
"Unknown value type"
;
}
return
result;
}
// 读取EncodedValue, 由于大小不固定, 故直接以数组赋值形式取值
void
DexFile::getEncodedValue(ubyte* pDest,
const
ubyte* pValue,
int
size) {
for
(
int
i=0;i<size;i++) {
pDest[i]=pValue[i];
}
}
// 解析EncodedValue, 返回解析后的字符串以及value真实大小 Todo: 完善解析逻辑,剩余3个分支
std::string DexFile::parseEncodedValue(ubyte* pEncodedValue,
size_t
& valueRealSize) {
ubyte valueArg = GetValueArg(pEncodedValue[0]);
// arg=size-1,值占用的字节数<=对应类型大小,不含头部的单字节
ubyte valueType = GetValueType(pEncodedValue[0]);
// 假如int=0时,占2字节,头1字节,值0占1字节,所以要同时判断arg和type
if
(valueArg==0) {
//arg==0时,要确定是arg固定为0的特殊类型还是其他类型
//特殊类型只有1字节头,其他类型是1字节头+1字节数据
bool
isSpecialType=
false
;
switch
(valueType) {
case
VALUE_BYTE:
case
VALUE_ARRAY:
case
VALUE_ANNOTATION:
case
VALUE_NULL:
case
VALUE_BOOLEAN:
isSpecialType=
true
;
break
;
}
if
(isSpecialType)
valueRealSize=1;
else
valueRealSize=2;
}
else
valueRealSize=valueArg+2;
// 头部1字节+实际大小 size=head+arg+1
int
readValueSize=valueArg+1;
// 需要读取的字节数
ubyte* pValue=&pEncodedValue[1];
std::string result;
unsigned
int
index=0;
switch
(valueType) {
// 有符号单字节
case
VALUE_BYTE: {
char
byte=0;
getEncodedValue((ubyte*)&byte,pValue,readValueSize);
result=
"byte:"
+std::format(
"0x{:x}"
,byte);
break
;
}
// 有符号双字节
case
VALUE_SHORT: {
short
value_short=0;
getEncodedValue((ubyte*)&value_short,pValue,readValueSize);
result=
"short:"
+std::format(
"0x{:x}"
,value_short);
break
;
}
// 无符号双字节
case
VALUE_CHAR: {
unsigned
short
value_char=0;
getEncodedValue((ubyte*)&value_char,pValue,readValueSize);
result=
"char:"
+std::format(
"0x{:x}"
,value_char);
break
;
}
// 有符号4字节
case
VALUE_INT: {
int
value_int=0;
getEncodedValue((ubyte*)&value_int,pValue,readValueSize);
result=
"int:"
+std::format(
"0x{:x}"
,value_int);
break
;
}
// 有符号8字节
case
VALUE_LONG: {
long
long
value_long=0;
getEncodedValue((ubyte*)&value_long,pValue,readValueSize);
result=
"long:"
+std::format(
"0x{:x}"
,value_long);
break
;
}
// 4字节浮点
case
VALUE_FLOAT: {
float
value_float=0;
getEncodedValue((ubyte*)&value_float,pValue,readValueSize);
result=
"float:"
+std::format(
"{:f}"
,value_float);
break
;
}
// 8字节浮点
case
VALUE_DOUBLE: {
double
value_double=0;
getEncodedValue((ubyte*)&value_double,pValue,readValueSize);
result=
"double:"
+std::format(
"{:f}"
,value_double);
break
;
}
// 无符号4字节索引 指向对应结构
case
VALUE_METHOD_TYPE: {
// ProtoId
getEncodedValue((ubyte*)&index,pValue,readValueSize);
result=
"MethodType:"
+std::format(
"0x{:x}"
,index)+
" "
+getProtoIdDataByIndex(index);
break
;
}
// todo: 这部分没有定义的成员指向,暂时不知如何解析,参考 https://source.android.com/docs/core/runtime/dex-format?hl=zh-cn#method-handle-item
case
VALUE_METHOD_HANDLE: {
// MethodHandles
getEncodedValue((ubyte*)&index,pValue,readValueSize);
result=
"MethodHandle Index:"
+std::format(
"0x{:x}"
,index);
break
;
}
case
VALUE_STRING: {
// StringId
getEncodedValue((ubyte*)&index,pValue,readValueSize);
result=
"String:"
+getStringIdDataByIndex(index);
break
;
}
case
VALUE_TYPE: {
// TypeId
getEncodedValue((ubyte*)&index,pValue,readValueSize);
result=
"Type:"
+parseString(getTypeIdDataByIndex(index));
break
;
}
case
VALUE_FIELD: {
// FieldId
getEncodedValue((ubyte*)&index,pValue,readValueSize);
result=
"Field:"
+parseString(getFieldIdDataByIndex(index));
break
;
}
case
VALUE_METHOD: {
// MethodId
getEncodedValue((ubyte*)&index,pValue,readValueSize);
result=
"Method:"
+parseString(getMethodIdDataByIndex(index));
break
;
}
case
VALUE_ENUM: {
// FieldId
getEncodedValue((ubyte*)&index,pValue,readValueSize);
result=
"Enum:"
+parseString(getFieldIdDataByIndex(index));
break
;
}
// todo encoded_array和encoded_annotation结构,不太容易解析
case
VALUE_ARRAY: {
//getEncodedValue((ubyte*)&index,pValue,readValueSize);
// DexEncodedArray encodedArray;//直接解析貌似不正确
// getEncodedValue((ubyte*)&encodedArray,pValue,readValueSize);
// printClassDefStaticValues(encodedArray);
// int sizeLen=0;
// u4 size=myReadUnsignedLeb128(pValue,&sizeLen);
// u1* pValues=pValue+sizeLen;
// printf("EncodedArray contains %d values\n",size);
// unsigned int offset=0;// offset保存前方已访问的结构大小
// for(int i=0;i<size;i++) {
// printf("%s\n",parseEncodedValue(pValues+offset,offset).c_str());
// }
//system("pause");
break
;
}
case
VALUE_ANNOTATION:
result=
"Todo......"
;
break
;
case
VALUE_NULL:
result=
"null"
;
break
;
// boolean的值存在value_arg中
case
VALUE_BOOLEAN:
result=
"bool:"
;
if
(valueArg)
result+=
"true"
;
else
result+=
"false"
;
break
;
default
:
result=
"Unknown value type"
;
}
return
result;
}
名称 | 格式 | 说明 |
---|---|---|
size | uleb128 | 数组中的元素数量 |
values | encoded_value[size] | 采用本部分所指定格式的一系列 size encoded_value 字节序列;依序串联。 |
名称 | 格式 | 说明 |
---|---|---|
type_idx | uleb128 | 注释的类型。这种类型必须是“类”(而非“数组”或“基元”)。 |
size | uleb128 | 此注解中 name-value 映射的数量 |
elements | annotation_element[size] | 注解的元素,直接以内嵌形式(不作为偏移量)表示。元素必须按 string_id 索引以升序进行排序。 |
名称 | 格式 | 说明 |
---|---|---|
name_idx | uleb128 | 元素名称,表示为要编入 string_ids 区段的索引。该字符串必须符合上文定义的 MemberName 的语法。 |
value | encoded_value | 元素值 |
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;
};
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;
};
class
DexFile {
u1* baseAddr{nullptr};
DexHeader* pHeader{nullptr};
DexStringId* pStringIds{nullptr};
DexTypeId* pTypeIds{nullptr};
DexFieldId* pFieldIds{nullptr};
DexMethodId* pMethodIds{nullptr};
DexProtoId* pProtoIds{nullptr};
DexClassDef* pClassDefs{nullptr};
void
initFields(unsigned
char
*buffer);
}
// Init functions
void
DexFile::initFields(unsigned
char
* buffer) {
if
(buffer==nullptr) {
printf
(
"Null pointer provided!\n"
);
exit
(0);
}
baseAddr=buffer;
pHeader=(DexHeader*)baseAddr;
pStringIds=(DexStringId*)(baseAddr+pHeader->stringIdsOff);
pTypeIds=(DexTypeId*)(baseAddr+pHeader->typeIdsOff);
pFieldIds=(DexFieldId*)(baseAddr+pHeader->fieldIdsOff);
pMethodIds=(DexMethodId*)(baseAddr+pHeader->methodIdsOff);
pProtoIds=(DexProtoId*)(baseAddr+pHeader->protoIdsOff);
pClassDefs=(DexClassDef*)(baseAddr+pHeader->classDefsOff);
}
DexFile::DexFile(unsigned
char
*buffer) {
initFields(buffer);
}
DexFile::DexFile(std::string filePath) {
size_t
fileLength=0;
initFields(readFileToBytes(filePath, fileLength));
}
DexFile::~DexFile() {
delete
baseAddr;
}
class
DexFile {
u1* baseAddr{nullptr};
DexHeader* pHeader{nullptr};
DexStringId* pStringIds{nullptr};
DexTypeId* pTypeIds{nullptr};
DexFieldId* pFieldIds{nullptr};
DexMethodId* pMethodIds{nullptr};
DexProtoId* pProtoIds{nullptr};
DexClassDef* pClassDefs{nullptr};
void
initFields(unsigned
char
*buffer);
}
// Init functions
void
DexFile::initFields(unsigned
char
* buffer) {
if
(buffer==nullptr) {
printf
(
"Null pointer provided!\n"
);
exit
(0);
}
baseAddr=buffer;
pHeader=(DexHeader*)baseAddr;
pStringIds=(DexStringId*)(baseAddr+pHeader->stringIdsOff);
pTypeIds=(DexTypeId*)(baseAddr+pHeader->typeIdsOff);
pFieldIds=(DexFieldId*)(baseAddr+pHeader->fieldIdsOff);
pMethodIds=(DexMethodId*)(baseAddr+pHeader->methodIdsOff);
pProtoIds=(DexProtoId*)(baseAddr+pHeader->protoIdsOff);
pClassDefs=(DexClassDef*)(baseAddr+pHeader->classDefsOff);
}
DexFile::DexFile(unsigned
char
*buffer) {
initFields(buffer);
}
DexFile::DexFile(std::string filePath) {
size_t
fileLength=0;
initFields(readFileToBytes(filePath, fileLength));
}
DexFile::~DexFile() {
delete
baseAddr;
}
typedef
struct
DexHeader {
u1 magic[8];
//Dex版本号 dex.035 .035即为版本号
u4 checksum;
//adler32检验,如果修改了Dex文件,需要修正这个值,否则会运行不起来
u1 signature[kSHA1DigestLen];
//SHA-1值,Android不检测该值,但如果修改了Dex文件,最好修复该值,再修checksum
u4 fileSize;
//整个dex文件的大小
u4 headerSize;
//DexHeader结构的大小,固定为0x70
u4 endianTag;
//字节序标记,若该字段按小端方式读出来为0x12345678,则整个Dex文件就是小端方式.如果按大端方式读出来为0x12345678,那整个Dex文件就是大端方式
u4 linkSize;
//链接段大小
u4 linkOff;
//链接段偏移
u4 mapOff;
//DexMapList文件偏移
u4 stringIdsSize;
//DexStringId个数
u4 stringIdsOff;
//DexStringId文件偏移
u4 typeIdsSize;
//DexTypeId个数
u4 typeIdsOff;
//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;
typedef
struct
DexHeader {
u1 magic[8];
//Dex版本号 dex.035 .035即为版本号
u4 checksum;
//adler32检验,如果修改了Dex文件,需要修正这个值,否则会运行不起来
u1 signature[kSHA1DigestLen];
//SHA-1值,Android不检测该值,但如果修改了Dex文件,最好修复该值,再修checksum
u4 fileSize;
//整个dex文件的大小
u4 headerSize;
//DexHeader结构的大小,固定为0x70
u4 endianTag;
//字节序标记,若该字段按小端方式读出来为0x12345678,则整个Dex文件就是小端方式.如果按大端方式读出来为0x12345678,那整个Dex文件就是大端方式
u4 linkSize;
//链接段大小
u4 linkOff;
//链接段偏移
u4 mapOff;
//DexMapList文件偏移
u4 stringIdsSize;
//DexStringId个数
u4 stringIdsOff;
//DexStringId文件偏移
u4 typeIdsSize;
//DexTypeId个数
u4 typeIdsOff;
//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;
void
DexFile::printDexHeader() {
printf
(
"DexHeader:\n"
);
printf
(
"\tmagic: "
);printHexBytes(pHeader->magic,
sizeof
(pHeader->magic));
printf
(
"\n"
);
printf
(
"\tchecksum: %#x\n"
,pHeader->checksum);
printf
(
"\tsignature: "
);printHexBytes(pHeader->signature,kSHA1DigestLen);
printf
(
"\n"
);
printf
(
"\tFileSize: %#x\n"
,pHeader->fileSize);
printf
(
"\tHeaderSize: %#x\n"
,pHeader->headerSize);
printf
(
"\tEndianTag: %#x\n"
,pHeader->endianTag);
printf
(
"\tLinkOff: %#x\n"
,pHeader->linkOff);
printf
(
"\tLinkSize: %#x\n"
,pHeader->linkSize);
printf
(
"\tMapOff: %#x\n"
,pHeader->mapOff);
printf
(
"\tStringIDs Offset: %#x\n"
,pHeader->stringIdsOff);
printf
(
"\tNum of StringIDs: %#x\n"
,pHeader->stringIdsSize);
printf
(
"\tTypeIDs Offset: %#x\n"
,pHeader->typeIdsOff);
printf
(
"\tNum of TypeIDs: %#x\n"
,pHeader->typeIdsSize);
printf
(
"\tProtoIDs Offset: %#x\n"
,pHeader->protoIdsOff);
printf
(
"\tNum of ProtoIDs: %#x\n"
,pHeader->protoIdsSize);
printf
(
"\tFieldIDs Offset: %#x\n"
,pHeader->fieldIdsOff);
printf
(
"\tNum of FieldIDs: %#x\n"
,pHeader->fieldIdsSize);
printf
(
"\tMethodIDs Offset: %#x\n"
,pHeader->methodIdsOff);
printf
(
"\tNum of MethodIDs: %#x\n"
,pHeader->methodIdsSize);
printf
(
"\tClassDefs Offset: %#x\n"
,pHeader->classDefsOff);
printf
(
"\tNum of ClassDefs: %#x\n"
,pHeader->classDefsSize);
printf
(
"\tData Offset: %#x\n"
,pHeader->dataOff);
printf
(
"\tSize of Data: %#x\n"
,pHeader->dataSize);
printf
(
"DexHeader End\n"
);
}
void
DexFile::printDexHeader() {
printf
(
"DexHeader:\n"
);
printf
(
"\tmagic: "
);printHexBytes(pHeader->magic,
sizeof
(pHeader->magic));
printf
(
"\n"
);
printf
(
"\tchecksum: %#x\n"
,pHeader->checksum);
printf
(
"\tsignature: "
);printHexBytes(pHeader->signature,kSHA1DigestLen);
printf
(
"\n"
);
printf
(
"\tFileSize: %#x\n"
,pHeader->fileSize);
printf
(
"\tHeaderSize: %#x\n"
,pHeader->headerSize);
printf
(
"\tEndianTag: %#x\n"
,pHeader->endianTag);
printf
(
"\tLinkOff: %#x\n"
,pHeader->linkOff);
printf
(
"\tLinkSize: %#x\n"
,pHeader->linkSize);
printf
(
"\tMapOff: %#x\n"
,pHeader->mapOff);
printf
(
"\tStringIDs Offset: %#x\n"
,pHeader->stringIdsOff);
printf
(
"\tNum of StringIDs: %#x\n"
,pHeader->stringIdsSize);
printf
(
"\tTypeIDs Offset: %#x\n"
,pHeader->typeIdsOff);
printf
(
"\tNum of TypeIDs: %#x\n"
,pHeader->typeIdsSize);
printf
(
"\tProtoIDs Offset: %#x\n"
,pHeader->protoIdsOff);
printf
(
"\tNum of ProtoIDs: %#x\n"
,pHeader->protoIdsSize);
printf
(
"\tFieldIDs Offset: %#x\n"
,pHeader->fieldIdsOff);
printf
(
"\tNum of FieldIDs: %#x\n"
,pHeader->fieldIdsSize);
printf
(
"\tMethodIDs Offset: %#x\n"
,pHeader->methodIdsOff);
printf
(
"\tNum of MethodIDs: %#x\n"
,pHeader->methodIdsSize);
printf
(
"\tClassDefs Offset: %#x\n"
,pHeader->classDefsOff);
printf
(
"\tNum of ClassDefs: %#x\n"
,pHeader->classDefsSize);
printf
(
"\tData Offset: %#x\n"
,pHeader->dataOff);
printf
(
"\tSize of Data: %#x\n"
,pHeader->dataSize);
printf
(
"DexHeader End\n"
);
}
struct
DexStringId {
u4 stringDataOff;
/* 字符串的文件偏移量 */
};
//伪结构表示如下:
struct
string_data_item {
uleb128 utf16_size;
//字符串长度
ubyte[] data;
//字符串数据
}
struct
DexStringId {
u4 stringDataOff;
/* 字符串的文件偏移量 */
};
//伪结构表示如下:
struct
string_data_item {
uleb128 utf16_size;
//字符串长度
ubyte[] data;
//字符串数据
}
// StringId functions
// 通过索引获取对应StringId
DexStringId DexFile::getStringIdByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->stringIdsSize-1)) {
return
pStringIds[index];
}
printf
(
"No such index: %x\n"
,index);
exit
(0);
}
// 解析StringId 获取字符串长度
size_t
DexFile::getStringDataLength(DexStringId& stringId) {
const
u1* ptr = baseAddr + stringId.stringDataOff;
size_t
size=0;
myReadUnsignedLeb128(ptr,&size);
return
size;
}
// 解析StringId 获取字符串
std::string DexFile::getStringIdData(
const
DexStringId& stringId) {
const
u1* ptr = baseAddr + stringId.stringDataOff;
while
(*(ptr++) > 0x7f);
// Skip the uleb128 length.
return
(
char
*)ptr;
}
// 通过索引获取StringId的字符串
std::string DexFile::getStringIdDataByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->stringIdsSize-1)) {
return
getStringIdData(pStringIds[index]);
}
return
nullptr;
}
// StringId functions
// 通过索引获取对应StringId
DexStringId DexFile::getStringIdByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->stringIdsSize-1)) {
return
pStringIds[index];
}
printf
(
"No such index: %x\n"
,index);
exit
(0);
}
// 解析StringId 获取字符串长度
size_t
DexFile::getStringDataLength(DexStringId& stringId) {
const
u1* ptr = baseAddr + stringId.stringDataOff;
size_t
size=0;
myReadUnsignedLeb128(ptr,&size);
return
size;
}
// 解析StringId 获取字符串
std::string DexFile::getStringIdData(
const
DexStringId& stringId) {
const
u1* ptr = baseAddr + stringId.stringDataOff;
while
(*(ptr++) > 0x7f);
// Skip the uleb128 length.
return
(
char
*)ptr;
}
// 通过索引获取StringId的字符串
std::string DexFile::getStringIdDataByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->stringIdsSize-1)) {
return
getStringIdData(pStringIds[index]);
}
return
nullptr;
}
void
DexFile::printStringIds() {
printf
(
"StringIds:\n"
);
printf
(
"\tNums\t\tStrings\n"
);
for
(
int
i=0;i<pHeader->stringIdsSize;i++) {
printf
(
"\t%08x\t%s\n"
,i,getStringIdDataByIndex(i).c_str());
}
printf
(
"StringIds End\n"
);
}
void
DexFile::printStringIds() {
printf
(
"StringIds:\n"
);
printf
(
"\tNums\t\tStrings\n"
);
for
(
int
i=0;i<pHeader->stringIdsSize;i++) {
printf
(
"\t%08x\t%s\n"
,i,getStringIdDataByIndex(i).c_str());
}
printf
(
"StringIds End\n"
);
}
typedef
struct
DexTypeId {
u4 descriptorIdx;
//指向DexStringId列表的索引
} DexTypeId;
typedef
struct
DexTypeId {
u4 descriptorIdx;
//指向DexStringId列表的索引
} DexTypeId;
// TypeId functions
// 通过索引获取对应TypeId
DexTypeId DexFile::getTypeIdByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->typeIdsSize-1)) {
return
pTypeIds[index];
}
printf
(
"No such index: %x\n"
,index);
exit
(0);
}
// 通过索引获取TypeId对应的字符串
std::string DexFile::getTypeIdDataByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->typeIdsSize-1)) {
return
getStringIdDataByIndex(pTypeIds[index].descriptorIdx);
}
return
nullptr;
}
// TypeId functions
// 通过索引获取对应TypeId
DexTypeId DexFile::getTypeIdByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->typeIdsSize-1)) {
return
pTypeIds[index];
}
printf
(
"No such index: %x\n"
,index);
exit
(0);
}
// 通过索引获取TypeId对应的字符串
std::string DexFile::getTypeIdDataByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->typeIdsSize-1)) {
return
getStringIdDataByIndex(pTypeIds[index].descriptorIdx);
}
return
nullptr;
}
void
DexFile::printTypeIds() {
printf
(
"TypeIds:\n"
);
printf
(
"\tNums\t\tTypeIds\n"
);
for
(
int
i=0;i<pHeader->typeIdsSize;i++) {
printf
(
"\t%08x\t%s\n"
,i,getTypeIdDataByIndex(i).c_str());
}
printf
(
"TypeIds End\n"
);
}
void
DexFile::printTypeIds() {
printf
(
"TypeIds:\n"
);
printf
(
"\tNums\t\tTypeIds\n"
);
for
(
int
i=0;i<pHeader->typeIdsSize;i++) {
printf
(
"\t%08x\t%s\n"
,i,getTypeIdDataByIndex(i).c_str());
}
printf
(
"TypeIds End\n"
);
}
typedef
struct
DexProtoId {
u4 shortyIdx;
//方法声明字符串,指向DexStringId列表的索引
u4 returnTypeIdx;
//方法返回类型字符串,指向DexTypeId列表的索引
u4 parametersOff;
//方法的参数列表,指向DexTypeList列表的索引
} DexProtoId;
typedef
struct
DexProtoId {
u4 shortyIdx;
//方法声明字符串,指向DexStringId列表的索引
u4 returnTypeIdx;
//方法返回类型字符串,指向DexTypeId列表的索引
u4 parametersOff;
//方法的参数列表,指向DexTypeList列表的索引
} DexProtoId;
typedef
struct
DexTypeList {
u4 size;
//DexTypeItem个数, 即参数个数
DexTypeItem list[size];
//DexTypeItem数组, 按从左到右的顺序保存了方法的参数
} DexTypeList;
typedef
struct
DexTypeItem {
u2 typeIdx;
//指向DexTypeId列表的索引
} DexTypeItem;
typedef
struct
DexTypeList {
u4 size;
//DexTypeItem个数, 即参数个数
DexTypeItem list[size];
//DexTypeItem数组, 按从左到右的顺序保存了方法的参数
} DexTypeList;
typedef
struct
DexTypeItem {
u2 typeIdx;
//指向DexTypeId列表的索引
} DexTypeItem;
// ProtoId functions
const
DexProtoId DexFile::getProtoIdByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->protoIdsSize-1)) {
return
pProtoIds[index];
}
illegalIndex(index);
}
std::string DexFile::getProtoIdShorty(
const
DexProtoId& protoId) {
return
getStringIdDataByIndex(protoId.shortyIdx);
}
std::string DexFile::getProtoIdReturnType(
const
DexProtoId& protoId) {
return
getTypeIdDataByIndex(protoId.returnTypeIdx);
}
// 获取ProtoId的参数列表,解析TypeList结构
std::vector<std::string> DexFile::getProtoIdParameters(
const
DexProtoId& protoId) {
std::vector<std::string> parameters;
//无参数
if
(protoId.parametersOff==0) {
return
parameters;
}
//解析TypeList结构 获取参数列表
DexTypeList* typeList=(DexTypeList*)(baseAddr+protoId.parametersOff);
for
(
int
i=0;i<typeList->size;i++) {
parameters.push_back(getTypeIdDataByIndex(typeList->list[i].typeIdx));
}
return
parameters;
}
// 解析DexProtoId结构体 返回解析后的字符串
std::string DexFile::parseProtoId(
const
DexProtoId& protoId) {
std::string shorty=getProtoIdShorty(protoId);
//c++的string类型会自动遍历const char*字符串并复制
std::string return_type = getProtoIdReturnType(protoId);
std::vector<std::string> parameters=getProtoIdParameters(protoId);
std::string result;
result+=parseString(return_type)+
" ("
;
//解析参数
for
(
int
i=0;i<parameters.size();i++) {
result+=parseString(parameters[i]);
if
(i!=parameters.size()-1)
//多个参数以,分隔
result+=
","
;
}
result+=
")"
;
return
result;
}
// 通过索引解析ProtoId,返回解析后的对应字符串
std::string DexFile::getProtoIdDataByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->protoIdsSize-1)) {
return
parseProtoId(getProtoIdByIndex(index));
}
return
nullptr;
}
// ProtoId functions
const
DexProtoId DexFile::getProtoIdByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->protoIdsSize-1)) {
return
pProtoIds[index];
}
illegalIndex(index);
}
std::string DexFile::getProtoIdShorty(
const
DexProtoId& protoId) {
return
getStringIdDataByIndex(protoId.shortyIdx);
}
std::string DexFile::getProtoIdReturnType(
const
DexProtoId& protoId) {
return
getTypeIdDataByIndex(protoId.returnTypeIdx);
}
// 获取ProtoId的参数列表,解析TypeList结构
std::vector<std::string> DexFile::getProtoIdParameters(
const
DexProtoId& protoId) {
std::vector<std::string> parameters;
//无参数
if
(protoId.parametersOff==0) {
return
parameters;
}
//解析TypeList结构 获取参数列表
DexTypeList* typeList=(DexTypeList*)(baseAddr+protoId.parametersOff);
for
(
int
i=0;i<typeList->size;i++) {
parameters.push_back(getTypeIdDataByIndex(typeList->list[i].typeIdx));
}
return
parameters;
}
// 解析DexProtoId结构体 返回解析后的字符串
std::string DexFile::parseProtoId(
const
DexProtoId& protoId) {
std::string shorty=getProtoIdShorty(protoId);
//c++的string类型会自动遍历const char*字符串并复制
std::string return_type = getProtoIdReturnType(protoId);
std::vector<std::string> parameters=getProtoIdParameters(protoId);
std::string result;
result+=parseString(return_type)+
" ("
;
//解析参数
for
(
int
i=0;i<parameters.size();i++) {
result+=parseString(parameters[i]);
if
(i!=parameters.size()-1)
//多个参数以,分隔
result+=
","
;
}
result+=
")"
;
return
result;
}
// 通过索引解析ProtoId,返回解析后的对应字符串
std::string DexFile::getProtoIdDataByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->protoIdsSize-1)) {
return
parseProtoId(getProtoIdByIndex(index));
}
return
nullptr;
}
void
DexFile::printProtoIds() {
printf
(
"ProtoIds:\n"
);
printf
(
"\tNums\t\tProtoIds\n"
);
for
(
int
i=0;i<pHeader->protoIdsSize;i++) {
printf
(
"\t%08x\t%s\n"
,i,getProtoIdDataByIndex(i).c_str());
}
printf
(
"ProtoIds End\n"
);
}
void
DexFile::printProtoIds() {
printf
(
"ProtoIds:\n"
);
printf
(
"\tNums\t\tProtoIds\n"
);
for
(
int
i=0;i<pHeader->protoIdsSize;i++) {
printf
(
"\t%08x\t%s\n"
,i,getProtoIdDataByIndex(i).c_str());
}
printf
(
"ProtoIds End\n"
);
}
typedef
struct
DexFieldId {
u2 classIdx;
//类的类型,指向DexTypeId列表的索引
u2 typeIdx;
//字段类型,指向DexTypeId列表的索引
u4 nameIdx;
//字段名,指向DexStringId列表的索引
} DexFieldId;
typedef
struct
DexFieldId {
u2 classIdx;
//类的类型,指向DexTypeId列表的索引
u2 typeIdx;
//字段类型,指向DexTypeId列表的索引
u4 nameIdx;
//字段名,指向DexStringId列表的索引
} DexFieldId;
// FieldId functions
const
DexFieldId DexFile::getFieldIdByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->fieldIdsSize-1)) {
return
pFieldIds[index];
}
illegalIndex(index);
}
// 获取FieldId所在类类名
std::string DexFile::getFieldIdClass(
const
DexFieldId& fieldId) {
return
getTypeIdDataByIndex(fieldId.classIdx);
}
// 获取FieldId类型
std::string DexFile::getFieldIdType(
const
DexFieldId& fieldId) {
return
getTypeIdDataByIndex(fieldId.typeIdx);
}
// 获取FieldId名称
std::string DexFile::getFieldIdName(
const
DexFieldId& fieldId) {
return
getStringIdDataByIndex(fieldId.nameIdx);
}
// 解析DexFieldId结构,字段所在类,类型,名称
std::string DexFile::parseFieldId(
const
DexFieldId& fieldId) {
std::string fieldClass=getFieldIdClass(fieldId);
std::string fieldType=getFieldIdType(fieldId);
std::string fieldName=getFieldIdName(fieldId);
return
parseString(fieldType)+
" "
+parseString(fieldClass)+
"."
+fieldName;
}
// 通过索引获取FieldId对应的字符串
std::string DexFile::getFieldIdDataByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->fieldIdsSize-1)) {
return
parseFieldId(getFieldIdByIndex(index));
}
return
nullptr;
}
// FieldId functions
const
DexFieldId DexFile::getFieldIdByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->fieldIdsSize-1)) {
return
pFieldIds[index];
}
illegalIndex(index);
}
// 获取FieldId所在类类名
std::string DexFile::getFieldIdClass(
const
DexFieldId& fieldId) {
return
getTypeIdDataByIndex(fieldId.classIdx);
}
// 获取FieldId类型
std::string DexFile::getFieldIdType(
const
DexFieldId& fieldId) {
return
getTypeIdDataByIndex(fieldId.typeIdx);
}
// 获取FieldId名称
std::string DexFile::getFieldIdName(
const
DexFieldId& fieldId) {
return
getStringIdDataByIndex(fieldId.nameIdx);
}
// 解析DexFieldId结构,字段所在类,类型,名称
std::string DexFile::parseFieldId(
const
DexFieldId& fieldId) {
std::string fieldClass=getFieldIdClass(fieldId);
std::string fieldType=getFieldIdType(fieldId);
std::string fieldName=getFieldIdName(fieldId);
return
parseString(fieldType)+
" "
+parseString(fieldClass)+
"."
+fieldName;
}
// 通过索引获取FieldId对应的字符串
std::string DexFile::getFieldIdDataByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->fieldIdsSize-1)) {
return
parseFieldId(getFieldIdByIndex(index));
}
return
nullptr;
}
void
DexFile::printFieldIds() {
printf
(
"FieldIds:\n"
);
printf
(
"\tNums\t\tFieldIds\n"
);
for
(
int
i=0;i<pHeader->fieldIdsSize;i++) {
printf
(
"\t%08x\t%s\n"
,i,getFieldIdDataByIndex(i).c_str());
}
printf
(
"FieldId End\n"
);
}
void
DexFile::printFieldIds() {
printf
(
"FieldIds:\n"
);
printf
(
"\tNums\t\tFieldIds\n"
);
for
(
int
i=0;i<pHeader->fieldIdsSize;i++) {
printf
(
"\t%08x\t%s\n"
,i,getFieldIdDataByIndex(i).c_str());
}
printf
(
"FieldId End\n"
);
}
struct
DexMethodId {
u2 classIdx;
/* 方法的所属的类,指向DexTypeId列表的索引 */
u2 protoIdx;
/* 声明类型,指向DexProtoId列表的索引 */
u4 nameIdx;
/* 方法名,指向DexStringId列表的索引 */
};
struct
DexMethodId {
u2 classIdx;
/* 方法的所属的类,指向DexTypeId列表的索引 */
u2 protoIdx;
/* 声明类型,指向DexProtoId列表的索引 */
u4 nameIdx;
/* 方法名,指向DexStringId列表的索引 */
};
// MethodId functions
const
DexMethodId DexFile::getMethodIdByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->methodIdsSize-1)) {
return
pMethodIds[index];
}
illegalIndex(index);
}
// 获取MethodId所在类名
std::string DexFile::getMethodIdClass(
const
DexMethodId& methodId) {
return
getTypeIdDataByIndex(methodId.classIdx);
}
// 获取MethodId对应方法签名
std::string DexFile::getMethodIdProto(
const
DexMethodId& methodId) {
return
getProtoIdDataByIndex(methodId.protoIdx);
}
// 获取MethodId对应方法名
std::string DexFile::getMethodIdName(
const
DexMethodId& methodId) {
return
getStringIdDataByIndex(methodId.nameIdx);
}
// 解析DexMethodId结构
std::string DexFile::parseMethodId(
const
DexMethodId& methodId) {
std::string methodProto=getMethodIdProto(methodId);
//解析class并拼接name
std::string methodFullName=parseString(getMethodIdClass(methodId))+getMethodIdName(methodId);
//拼接proto和class.name
return
methodProto.insert(methodProto.find(
' '
)+1,methodFullName);
}
// 通过索引获取MethodId对应字符串
std::string DexFile::getMethodIdDataByIndex(u4 index) {
if
(checkIndexIsLegal(index,pHeader->methodIdsSize-1)) {
return
parseMethodId(getMethodIdByIndex(index));
}
return
nullptr;
}
// MethodId functions
const
DexMethodId DexFile::getMethodIdByIndex(u4 index) {
赞赏
- Dex文件结构-ReadDex解析器实现 1031
- [原创] ELF文件结构浅析-解析器和加载器实现 6698
- PE文件解析基础 13782
- 植物大战僵尸修改器制作--从入门到入土 19375