吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2257|回复: 6
收起左侧

[Android 原创] dex文件格式------header_item解析

[复制链接]
紫诺不离 发表于 2020-6-20 21:52
本帖最后由 紫诺不离 于 2020-6-22 10:13 编辑

授人与鱼不如授人与渔,作为初学者,最重要的是学会查看官方文档,自主学习。

首先放上google官方文档对dex解释的链接,里面相当详细的介绍了dex的格式的组成。

https://source.android.google.cn/devices/tech/dalvik/dex-format#header-item

类型指南

byte        8 位有符号整数
ubyte        8 位无符号整数
short        16 位有符号整数,采用小端字节序
ushort        16 位无符号整数,采用小端字节序
int        32 位有符号整数,采用小端字节序
uint        32 位无符号整数,采用小端字节序
long        64 位有符号整数,采用小端字节序
ulong        64 位无符号整数,采用小端字节序
sleb128        有符号 LEB128,可变长度(见下文)
uleb128        无符号 LEB128,可变长度(见下文)
uleb128p1        无符号 LEB128 加 1,可变长度(见下文)

LEB128

LEB128(“**L**ittle-**E**ndian **B**ase **128**”)表示任意有符号或无符号整数的可变长度编码。该格式借鉴了 [DWARF3](http://dwarfstd.org/Dwarf3Std.php) 规范。在 `.dex` 文件中,LEB128 仅用于对 32 位数字进行编码。

每个 LEB128 编码值均由 1-5 个字节组成,共同表示一个 32 位的值。每个字节均已设置其最高有效位(序列中的最后一个字节除外,其最高有效位已清除)。每个字节的剩余 7 位均为有效负荷,即第一个字节中有 7 个最低有效位,第二个字节中也是 7 个,依此类推。对于有符号 LEB128 (`sleb128`),序列中最后一个字节的最高有效负荷位会进行符号扩展,以生成最终值。在无符号情况 (`uleb128`) 下,任何未明确表示的位都会被解译为 `0`。

c语言对LEB128解码

void LEB128toInt(char* str)
{
    DWORD value = 0;
WORD index = 0;
    if (*str)
    {
        do {
        //左移7位加上之前的值
            value = (*str & 0X7F) << (index * 7) + value;  
            ++index;
            //判断下一个字符高位是否为1
        } while (*str++ & 0x80);
        return;
    }
    return ;
}

dex完整格式:

header        header_item         标头
string_ids        string_id_item[]        //字符串标识符列表。这些是此文件使用的所有字符串的标识符,用于内部命名(例如类型描述符)或用作代码引用的常量对象。此列表必须使用 UTF-16 代码点值按字符串内容进行排序(不采用语言区域敏感方式),且不得包含任何重复条目。
type_ids        type_id_item[]        //类型标识符列表。这些是此文件引用的所有类型(类、数组或原始类型)的标识符(无论文件中是否已定义)。此列表必须按 string_id 索引进行排序,且不得包含任何重复条目。
proto_ids        proto_id_item[]        //方法原型标识符列表。这些是此文件引用的所有原型的标识符。此列表必须按返回类型(按 type_id 索引排序)主要顺序进行排序,然后按参数列表(按 type_id 索引排序的各个参数,采用字典排序方法)进行排序。该列表不得包含任何重复条目。
field_ids        field_id_item[]        //字段标识符列表。这些是此文件引用的所有字段的标识符(无论文件中是否已定义)。此列表必须进行排序,其中定义类型(按 type_id 索引排序)是主要顺序,字段名称(按 string_id 索引排序)是中间顺序,而类型(按 type_id 索引排序)是次要顺序。该列表不得包含任何重复条目。
method_ids        method_id_item[]        //方法标识符列表。这些是此文件引用的所有方法的标识符(无论文件中是否已定义)。此列表必须进行排序,其中定义类型(按 type_id 索引排序)是主要顺序,方法名称(按 string_id 索引排序)是中间顺序,而方法原型(按 proto_id 索引排序)是次要顺序。该列表不得包含任何重复条目。
class_defs        class_def_item[]        //类定义列表。这些类必须进行排序,以便所指定类的超类和已实现的接口比引用类更早出现在该列表中。此外,对于在该列表中多次出现的同名类,其定义是无效的。
call_site_ids        call_site_id_item[]        //调用站点标识符列表。这些是此文件引用的所有调用站点的标识符(无论文件中是否已定义)。此列表必须按 call_site_off 以升序进行排序。
method_handles        method_handle_item[]        //方法句柄列表。此文件引用的所有方法句柄的列表(无论文件中是否已定义)。此列表未进行排序,而且可能包含将在逻辑上对应于不同方法句柄实例的重复项。
data        ubyte[]//        数据区,包含上面所列表格的所有支持数据。不同的项有不同的对齐要求;如有必要,则在每个项之前插入填充字节,以实现所需的对齐效果。
link_data        ubyte[]        //静态链接文件中使用的数据。本文档尚未指定本区段中数据的格式。此区段在未链接文件中为空,而运行时实现可能会在适当的情况下使用这些数据。

header_item格式

magic        ubyte[8] = DEX_FILE_MAGIC        //魔法值。如需了解详情,请参阅上文中“DEX_FILE_MAGIC”下的讨论。
checksum        uint        //文件剩余内容(除 magic 和此字段之外的所有内容)的 adler32 校验和;用于检测文件损坏情况
signature        ubyte[20]        //文件剩余内容(除 magic、checksum 和此字段之外的所有内容)的 SHA-1 签名(哈希);用于对文件进行唯一标识
file_size        uint        //整个文件(包括标头)的大小,以字节为单位
header_size        uint = 0x70        //头文件(整个区段)的大小,以字节为单位。此项允许至少一定程度的向后/向前兼容性,而不会使格式失效。
endian_tag        uint = ENDIAN_CONSTANT        //字节序标记。如需了解详情,请参阅上文中“ENDIAN_CONSTANT 和 REVERSE_ENDIAN_CONSTANT”下的讨论。
link_size        uint        //链接区段的大小;如果此文件未进行静态链接,则该值为 0
link_off        uint        //从文件开头到链接区段的偏移量,如果 link_size == 0,则该值为 0。该偏移量(如果为非零值)应该是到 link_data 区段的偏移量。本文档未指定此处所指数据的格式;此标头字段(和之前的字段)会被保留为钩子,以供运行时实现使用。
map_off        uint        //从文件开头到映射项的偏移量。该偏移量(必须为非零值)应该是到 data 区段的偏移量,而数据应采用下文中“map_list”指定的格式。
string_ids_size        uint        //字符串标识符列表中的字符串数量
string_ids_off        uint        //从文件开头到字符串标识符列表的偏移量;如果 string_ids_size == 0(不可否认是一种奇怪的极端情况),则该值为 0。该偏移量(如果为非零值)应该是到 string_ids 区段开头的偏移量。
type_ids_size        uint        //类型标识符列表中的元素数量,最多为 65535
type_ids_off        uint        //从文件开头到类型标识符列表的偏移量;如果 type_ids_size == 0(不可否认是一种奇怪的极端情况),则该值为 0。该偏移量(如果为非零值)应该是到 type_ids 区段开头的偏移量。
proto_ids_size        uint        //原型标识符列表中的元素数量,最多为 65535
proto_ids_off        uint        //从文件开头到原型标识符列表的偏移量;如果 proto_ids_size == 0(不可否认是一种奇怪的极端情况),则该值为 0。该偏移量(如果为非零值)应该是到 proto_ids 区段开头的偏移量。
field_ids_size        uint        //字段标识符列表中的元素数量
field_ids_off        uint        //从文件开头到字段标识符列表的偏移量;如果 field_ids_size == 0,则该值为 0。该偏移量(如果为非零值)应该是到 field_ids 区段开头的偏移量。
method_ids_size        uint        //方法标识符列表中的元素数量
method_ids_off        uint        //从文件开头到方法标识符列表的偏移量;如果 method_ids_size == 0,则该值为 0。该偏移量(如果为非零值)应该是到 method_ids 区段开头的偏移量。
class_defs_size        uint        //类定义列表中的元素数量
class_defs_off        uint        //从文件开头到类定义列表的偏移量;如果 class_defs_size == 0(不可否认是一种奇怪的极端情况),则该值为 0。该偏移量(如果为非零值)应该是到 class_defs 区段开头的偏移量。
data_size        uint        //data 区段的大小(以字节为单位)。该数值必须是 sizeof(uint) 的偶数倍。
data_off        uint        //从文件开头到 data 区段开头的偏移量。

有了header_item格式,那么我们就可以定义一个header_item的结构体来解析里面的内容

windows头文件中类型的定义,此处为了方便,没有自己定义。

typedef unsigned long       DWORD;
typedef int                 BOOL;
typedef unsigned char       BYTE;
typedef unsigned short      WORD;
定义结构体
#define IMAGE_SIZEOF_DEX_FILE 8
#define IMAGE_SIZEOF_DEX_SIGNATURE 20
typedef struct  _IMAGE_DEX_HEADER
{
        BYTE magic[IMAGE_SIZEOF_DEX_FILE];        。
        DWORD checksum;        
        BYTE signature[IMAGE_SIZEOF_DEX_SIGNATURE];        
        DWORD file_size;        
        DWORD header_size;        
        DWORD endian_tag;        
        DWORD link_size;        
        DWORD link_off;        
        DWORD map_off;        
        DWORD string_ids_size;        
        DWORD string_ids_off;        
        DWORD type_ids_size;        
        DWORD type_ids_off;
        DWORD proto_ids_size;        
        DWORD proto_ids_off;        
        DWORD field_ids_size;        
        DWORD field_ids_off;
        DWORD method_ids_size;        
        DWORD method_ids_off;        
        DWORD class_defs_size;        
        DWORD class_defs_off;
        DWORD data_size;                
        DWORD data_off;         
}IMAGE_DEX_HEADER, * PIMAGE_DEX_HEADER;

定义好了结构体,接下来就可以解析了。

打开一个文件

        //IpzFile为文件名字
        FILE* pFile = fopen(IpzFile, "rb");
        //定义一个结构体变量
        IMAGE_DEX_HEADER dex_header;
        if (!pFile)
        {
                MessageBox(0, TEXT("打开文件失败"), TEXT("信息"), 0);
                return fileSize;
        }
        //此时header_item数据就已经读取到结构体中了
        fread(&dex_header, sizeof(IMAGE_DEX_HEADER), 1, pFile);
        //关闭文件
                fclose(pFile);
                此时要打印或者写到文件中任由你选择。如果这个你不会,那么你要去补c语言基础了。

说了那么多,其实总结起来就两步,第一步:定义结构体,第二步:读取文件,给结构体赋值。

免费评分

参与人数 2威望 +1 吾爱币 +21 热心值 +2 收起 理由
qtfreet00 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
woshuoxiang + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 紫诺不离 发表于 2020-6-20 21:54
链接没有编辑上,现在补上 https://source.android.google.cn/devices/tech/dalvik/dex-format#header-item
chuwenjie161 发表于 2020-6-20 22:25
Abrahams 发表于 2020-6-20 22:32
wapjcxz 发表于 2020-6-21 05:03
默默学习,默默点赞
头像被屏蔽
iYolo丶moye 发表于 2020-6-21 10:20
提示: 作者被禁止或删除 内容自动屏蔽
netCheney 发表于 2020-6-21 21:46
前排学习,楼主辛苦了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 21:52

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表