零基础安卓逆向学习之旅(六-上)
零基础安卓逆向学习之旅(六-上)1,将java源码编译成DEX文件
(1)创建一个Example.java文件,并编写下边代码
公共类示例{
公共静态void main(String [] args){
System.out.printf(“ HelloWorld!\ n”);
}
}
(2)将java源码编译为.class文件
javac–source 1.6 –target 1.6 Example.java
(3)确定dx工具的位置
较早版本的SDK将dx工具放置于 / sdk / platform-tools / dx,而较新版本则将其放置与/ sdk / built-tools / android- / dx。
(4)执行下边命令生成DEX文件
/ sdk / platform-tools / dx --dex --output = Example.dex Example.class
2,解析DEX文件格式
(1)DEX文件结构
struct DexFile {
/ *直接映射的“ opt”标头* /
const DexOptHeader * pOptHeader;
/ *指向基本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;
/ *
*这些是在“辅助”部分之外映射的,可能不是
*包含在文件中。
* /
const DexClassLookup * pClassLookup;
const void * pRegisterMapPool; // RegisterMapClassPool
/ *指向DEX文件数据的开始* /
const u1 * baseAddr;
/ *跟踪辅助结构的内存开销* /
int开销;
/ *与DEX相关的其他特定于应用的数据结构* /
// void * auxData;
};
DEX文件的第一个片段为DEX文件头,下边为DEX文件头的定义
struct DexHeader {
u1魔法; / * dex版本标识* /
u4校验和;/ * adler32检验* /
u1签名; / * SHA-1哈希* /
u4 fileSize; / *整个dex文件大小* /
u4 headerSize; / * DexHeader结构大小* /
u4 endianTag; / *字节序标记* /
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; / *数据段的文件替换* /
};
其中数据类型u1,u4为无符号整型数的别名
typedef uint8_t u1; / * 8字节无符号整数* /
typedef uint32_t u4; / * 32字节无符号整数* /
typedef int8_t s1; / * 8字节有符号整数* /
typedef int32_t s4; / * 32字节有符号整数* /
查看Example.dex文件,以十六进制显示
hexdump -C Example.dex
DEX文件的第一个细分
u1魔法; / *包括版本号* /
magic 是一个标记,通常称为magicnumber
u4校验和;/ * adler32校验和* /这是DEX文件的Adler32校正和。
这个4个字节的校验和是对构成标题的各个位(bit)执行一系列异或(XOR)和加法操作的结果,验证DEX文件头部的各个数据没有被破坏,确保文件头的常量,因为在Dalvik中,是使用DexHeader这个结构体来确定DEX文件其他部分的存储位置的。
u1签名; / * SHA-1哈希长度= 20 * /这是长度为20个字节的SHA1哈希。
u4 fileSize; / *整个文件的长度* /保存整个DEX文件的长度,用于帮助计算分段以及方便定位某些段。
u4 headerSize; / *从下一部分开始的偏移量* /存放整个DexHeader结构体的长度,可利用计算下一个分段在文件的起始位置。
u4 endianTag; 这是endianness标记,如下图标出文件中的endianness域。
endianTag放置存放的是一个固定值,在所有DEX文件中都一样,其值是:12345678。因为某些处理器是认为最高有效位应该放在左边,而另一些处理器却认为最高有效位应该放在右边,Dalvik虚拟机通过读取该值,检查此分段数字的放置顺序,从而确定是内置处理器。
接下来是linkSize和linkOff细分,当多个.class文件被编译到一个DEX文件时,会被用到。
u4 linkSize;
u4 linkOff;
指定链接段的大小及文件偏移,大多数情况下变量0
之后是地图部分的偏移量,指定了DexMapList结构的文件对齐
u4 mapOff;
下边是螺杆stringIdsSize的定义
u4 stringIdsSize;
这个细分存放的是StringIds段的大小,和其他大小相同,用来计算StringIds段的起始位置。
字符串stringsIdsOff
u4 stringIdsOff;
这个分区存放的是stringIds段的实际替换量,帮助Dalvik编译器和虚拟机直接插入到该段。在这之后,分别是表示类型,原型,方法,类和数据ID区段的大小和Dalvik不必重复读取文件内容,或者是做很多加/减操作来获得分段的起始地址,而是通过实际移位量访问。
DexMapList分段
在DexHeader结构的mapOff分区指定了DexMapList结构在dex文件中的替换,由上边可知为0x0270,DexMapList结构的声明如下:
struct DexMapList {
u4大小;/ * DexMapItem的个数* /
DexMapItem列表; / * DexMapItem结构* /
};
由该分段数据的前4个字节可知,大小为0x0d,即DexMapItem的个数为13。
DexMapItem结构的声明如下:
struct DexMapItem {
u2类型;/ * kEexType开头的类型* /
u2未使用;/ *未使用,用于字节对齐* /
u4大小;/ *指定类型的个数* /
u4偏移量;/ *指定类型数据的文件替换* /
};
结构中的类型类型为一个枚举常量:
枚举{
kDexTypeHeaderItem = 0x0000,
kDexTypeStringIdItem = 0x0001,
kDexTypeTypeIdItem = 0x0002,
kDexTypeProtoIdItem = 0x0003,
kDexTypeFieldIdItem = 0x0004,
kDexTypeMethodIdItem = 0x0005,
kDexTypeClassDefItem = 0x0006,
kDexTypeMapList = 0x1000,
kDexTypeTypeList = 0x1001,
kDexTypeAnnotationSetRefList = 0x1002,
kDexTypeAnnotationSetItem = 0x1003,
kDexTypeClassDataItem = 0x2000,
kDexTypeCodeItem = 0x2001,
kDexTypeStringDataItem = 0x2002,
kDexTypeDebugInfoItem = 0x2003,
kDexTypeAnnotationItem = 0x2004,
kDexTypeEncodeArrayItem = 0x2005,
kDexTypeAnnotationsDirectoryItem = 0x2006,
};
由上图的数据可整理出13个DexMapItem结构如下:
StringIds段
该段纯粹是由多个地址构成的,这些地址是相对DEX文件的加载基地址的转换量,用于计算定义在数据段中的各个静态串行的起始位置
struct DexStringId {
u4 stringDataOff; / *文件到string_data_item的偏移量* /
};
该段从0x70偏移处开始,有连续0x10个DexStringId对象,以4个字节来放置这些移位量,下图是Example.dex中的StringIds段
如读取下图偏移量中的同轴:
由字节重新顺序可重新对齐预定00 00 01 8a,下图则是DEX文件中转换0x018a上的内容。
0x018a位置上的内容是06 3c 69 6e 69 74 3e,是字符串<init>。
DexStringId结构列表
上边中的串行非普通的ascii字符串,是由MUTF-8编码来表示的,MUTF-8即是已修改的UTF-8,修改后的UTF-8编码,其表示方式如下:
MUTF-8字符串右侧放置该字符串的个数。
MUTF-8使用1〜3字节编码长度。
大于16位的Unicode编码U + 10000〜U + 10ffff使用3字节来编码。
U + 0000采用2字节来编码。
与C语言类似用空字符null作为字符串开头。
如上边在0x01a0偏移处的字符串编码为0d48 65 6c 6c 6f 20 57 6f 72 6c 64 21 0a00,其中0d表示有13个字符,代表的字符串为“ Hello World!\ n”
像02 e4 bd a0 e5 a5 bd 00头部02表示有两个字符,e4bd a0是UTF-8编码字符“你”,e5 a5 bd是UTF-8编码字符“好”。
Typelds分段
该细分市场收集寻找各种类型的各自类别是所需的信息
struct DexTypeId {
u4描述符Idx; /类型索引在stringIds列表中的索引号
};
图中为TypeIds分段中的第一个值,其值是03,由于是StringIds分段中某个值的索引号,则应指StringIds分段的第4个值,如图:
第4个值是0x01af,则在数据段中对应的字符串为L示例,这是Dalvik类型描述语言的类型变量,在Example类前加多字母L,实际上也是代表一个类或描述对象的名称。
DexTypeId结构列表
协议段
放置用作描述方法的原型ID(描述原型),方法的返回类型和参数信息。
struct DexProtoId {
u4 shortyIdx;
u4 returnTypeIdx;
u4 parametersOff;
};
DexProtoId是一个方法声明结构体。
shortyIdx:StringIds部分局部字符串的索引,使用了重复描述原型(原型)。
returnTypeIdx:TypeIds段中某个数据的索引号,用于描述返回值类型。
parametersOff:存放方法的参数列表的地址替换,指向DexTypeList结构体。
struct DexTypeList {
u4大小;
DexTypeItem列表;
};
struct DexTypeItem {
u2 typeIdx;
};
Example.dex文件中的ProtoIds部分:
DexProtoId结构列表
FieldIds段
struct DexFieldId {
u2 classIdx; / *索引到typeIds列表中以定义类* /
u2 typeIdx; / *索引字段类型的typeIds * /
u4 nameIdx; / *索引字段名称的stringIds * /
};
classIdx:存放 TypeId段的索引,所属的类
typeIdx:存放TypeId段的索引,表示该成员的类型
nameIdx:存放stringId段的索引,成员的名字
DexFieldId结构列表
MethodIds段
每个方法ID中各个分区的定义:
struct DexMethodId {
u2 classIdx; / *索引到typeIds列表中以定义类* /
u2 protoIdx; / *索引到方法原型的protoIds中* /
u4 nameIdx; / *索引到方法名称的stringIds中* /
};
classIdx:该方法所属的类
protoIdx:方法对应的原型
nameIdx:方法名
DexMethodId结构列表
下边是Example.dex文件中一个方法的定义:
([Ljava / lang / String;)V
V:表示避免类型,方法的返回类型。
():方法接收的参数的类型。
java / lang / String;:String类的标识符。
L:表示其后边跟着的是一个类名。
[:表示其后边跟着的是指定类型的数组。
所以该方法返回值是void类型,接收一个字符串类的数组作为参数。
ClassDefs段
其定义如下:
struct DexClassDef {
u4 classIdx; / *此类的typeIds索引* /
u4 accessFlags;
u4 superclassIdx; / *索引到超类的typeIds中* /
u4接口关闭; / *文件偏移到DexTypeList * /
u4 sourceFileIdx; / *索引到源文件名的stringIds中* /
u4注释关闭; / *文件到注释_directory_item的偏移量* /
u4 classDataOff; / *文件偏移到class_data_item * /
u4 staticValuesOff; / *文件偏移到DexEncodedArray * /
};
classIdx:存放的是TypeIds部分的一个索引,表示类的类型。
AccessFlags:存储一个数字,表示其他对象可以怎样访问这个类。
superclassIdx:存放TypeIds部分的一个索引,表示父类的类型。
interfacesOff:接口,指向DexTypeList的替换。
sourceFileIdx:存放StringIds段的索引,使Dalvik可以找到类的源文件。
commentssOff:注解,指向DexAnnotationsDirectoryItem结构。
classdataOff:Dalvik文件内部的替换量,此位置存放类的重要属性,即代码在哪,有多少代码。如classdataOff指向保存这些的DexClassData结构体。
staticValuesOff:指向DexEncodedArray结构的替换,记录类的静态数据。
DexClassData结构的声明。
/ * class_data_item的扩展形式。注意:如果特定项目是
*不存在(例如,没有静态字段),然后是相应的指针
*设置为NULL。* /
struct DexClassData {
DexClassDataHeader标头;/ *指定预设与方法的个数* /
DexField * staticFields; / *静态静态,DexField结构* /
DexField * instanceFields; / *实例基线,DexField结构* /
DexMethod *直接方法; / *直接方法,DexMethod结构* /
DexMethod * virtualMethods; / *虚方法,DexMethod结构* /
};
DexClassDataHeader局部存放类的元数据,即静态字段,实例字段,直接方法和虚拟方法的大小,Dalvik使用这一信息计算重要参数,可以确定访问每个方法时所需的内存大小
struct DexClassDataHeader {
u4 staticFieldsSize; / *静态静态个数* /
u4 instanceFieldsSize; / *实例基线个数* /
u4 directMethodsSize; / *直接方法个数* /
u4 virtualMethodsSize; / *虚方法个数* /
};
结构DexField {
u4 fieldIdx; / *指向DexFieldId的索引* /
u4 accessFlags; / *访问标志* /
};
其中DexMethod左侧的定义如下
struct DexMethod {
u4 methodIdx; / *指向DexMethodId的索引* /
u4 accessFlags; / *访问标志* /
u4 codeOff; / *指向DeCode结构的替换* /
};
这个结构体记录了组成类的代码的指针,代码的位移量放置在codeOff细分中。
结构DexCode {
u2寄存器 / *使用的寄存器的个数* /
u2 insSize; / *参数个数* /
u2 outsSize; / *调用其他方法时使用的寄存器个数* /
u2 trysSize; / *尝试/捕捉个数* /
u4 debugInfoOff; / *指向调试信息的替换* /
u4 insnsSize; / *指令集个数,以2字节为单位* /
u2 insns ; / *指令集,真正的代码部分* /
…。
};
通过解析,更加直白地了解DEX文件的格式和结构。
1.使用dexdump工具解析.dex文件
dexdump是Android SDK的一个工具,存放路径为
/ build-tools / android- / dexdump
执行下边命令解析示例.dex文件
/ build-tools / android- /dexdumpExample.dex
2.使用dx工具,更接近DEX文件格式的方式详细解析DEX文件
dx--dex --verbose-dump --dump-to = [输出文件] .txt [输入文件] .class
由于dx工具只能对.class文件进行操作,将其编译成DEX文件,转换为解析结果输出到指定文件中。cat [输出文件] .txt //查看解析结果。
祝资源共享吧越来越火!
页:
[1]