吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 11988|回复: 28
收起左侧

[Android 原创] DEX文件解析---1、dex文件头解析

[复制链接]
windy_ll 发表于 2019-11-17 22:54
本帖最后由 windy_ll 于 2022-3-29 21:37 编辑

DEX文件解析---1、dex文件头解析


一、dex文件

    dex文件是Android平台上可执行文件的一种文件类型。它的文件格式可以下面这张图概括:

    dex文件头一般固定为0x70个字节大小,包含标志、版本号、校验码、sha-1签名以及其他一些方法、类的数量和偏移地址等信息。如下图所示:


二、dex文件头各字段解析

    dex文件头包含以下各个字段:  

  1. magic:包含了dex文件标识符以及版本,从0x00开始,长度为8个字节  
  2. checksum:dex文件校验码,偏移量为:0x08,长度为4个字节。  
  3. signature:dex sha-1签名,偏移量为0x0c,长度为20个字节  
  4. file_szie:dex文件大小,偏移量为0x20,长度为4个字节  
  5. header_size:dex文件头大小,偏移量为0x24,长度为4个字节,一般为0x70  
  6. endian_tag:dex文件判断字节序是否交换,偏移量为0x28,长度为4个字节,一般情况下为0x78563412  
  7. link_size:dex文件链接段大小,为0则表示为静态链接,偏移量为0x2c,长度为4个字节  
  8. link_off:dex文件链接段偏移位置,偏移量为0x30,长度为4个字节   
  9. map_off:dex文件中map数据段偏移位置,偏移位置为0x34,长度为4个字节   
  10. string_ids_size:dex文件包含的字符串数量,偏移量为0x38,长度为4个字节  
  11. string_ids_off:dex文件字符串开始偏移位置,偏移量为0x3c,长度为4个字节  
  12. type_ids_size:dex文件类数量,偏移量为0x40,长度为4个字节  
  13. type_ids_off:dex文件类偏移位置,偏移量为0x44,长度为4个字节  
  14. photo_ids_size:dex文件中方法原型数量,偏移量为0x48,长度为4个字节  
  15. photo_ids_off:dex文件中方法原型偏移位置,偏移量为0x4c,长度为4个字节  
  16. field_ids_size:dex文件中字段数量,偏移量为0x50,长度为4个字节  
  17. field_ids_off:dex文件中字段偏移位置,偏移量为0x54,长度为4个字节  
  18. method_ids_size:dex文件中方法数量,偏移量为0x58,长度为4个字节  
  19. method_ids_off:dex文件中方法偏移位置,偏移量为0x5c,长度为4个字节  
  20. class_defs_size:dex文件中类定义数量,偏移量为0x60,长度为4个字节  
  21. class_defs_off:dex文件中类定义偏移位置,偏移量为0x64,长度为4个字节
  22. data_size:dex数据段大小,偏移量为0x68,长度为4个字节  
  23. data_off:dex数据段偏移位置,偏移量为0x6c,长度为4个字节

三、dex文件头代码解析示例(python)

    dex使用open函数以二进制打开文件,然后使用seek函数移动文件指针,例如magic就是f.seek(0x00),然后读取相应信息的字节数即可,例如读取版本号f.seek(0x04) f.read(4),然后做相应打印操作就行,dex文件头较简单,不涉及编码等,所以解析起来感觉脑子都不用带。。。。。具体代码可以看下面或者github,下面附上代码运行图:


四、dex文件头解析实现代码(python实现)

import binascii

def parserHeader(f):
f.seek(0x00)
magic_mask = f.read(4)
magic_mask = binascii.b2a_hex(magic_mask)
magic_mask = str(magic_mask,encoding='utf-8')
print('文件标识符: ',end='')
print(magic_mask)  

f.seek(0x04)
magic_version = f.read(4)
magic_version = binascii.b2a_hex(magic_version)
magic_version = str(magic_version,encoding='utf-8')
print('文件版本: ',end='')
print(magic_version)

f.seek(0x08)
checksum = f.read(4)
checksum = binascii.b2a_hex(checksum)
checksum = str(checksum,encoding='utf-8')
print('校验码: ',end='')
print(checksum)

f.seek(0x0c)
signature = f.read(20)
signature = binascii.b2a_hex(signature)
signature = str(signature,encoding='utf-8')
print('SHA-1签名: ',end='')
print(signature)

f.seek(0x20)
file_size = f.read(4)
a = bytearray(file_size)
a.reverse()
file_size = bytes(a)
file_size = binascii.b2a_hex(file_size)
file_size = str(file_size,encoding='utf-8')
print('文件大小: ',end='')
print(int(file_size,16),end='')
print(' byte')

f.seek(0x24)
header_size = f.read(4)
a = bytearray(header_size)
a.reverse()
header_size = bytes(a)
header_size = binascii.b2a_hex(header_size)
header_size = str(header_size,encoding='utf-8')
print('文件头大小: ',end='')
print(int(header_size,16),end='')
print(' byte')

f.seek(0x28)
endian_tag = f.read(4)
endian_tag = binascii.b2a_hex(endian_tag)
endian_tag = str(endian_tag,encoding='utf-8')
print('字节序交换标志: ',end='')
print(endian_tag)

f.seek(0x2c)
link_size = f.read(4)
a = bytearray(link_size)
a.reverse()
link_size = bytes(a)
link_size = binascii.b2a_hex(link_size)
link_size = str(link_size,encoding='utf-8')
print('链接段大小: ',end='')
print(int(link_size,16),end='')
print(' byte')

f.seek(0x30)
link_off = f.read(4)
a = bytearray(link_off)
a.reverse()
link_off = bytes(a)
link_off = binascii.b2a_hex(link_off)
link_off = str(link_off,encoding='utf-8')
print('链接段偏移位置: ',end='')
print(hex(int(link_off,16)))

f.seek(0x34)
map_off = f.read(4)
a = bytearray(map_off)
a.reverse()
map_off = bytes(a)
map_off = binascii.b2a_hex(map_off)
map_off = str(map_off,encoding='utf-8')
print('map数据偏移位置: ',end='')
print(hex(int(map_off,16)))

f.seek(0x38)
stringidsSize = f.read(4)
a = bytearray(stringidsSize)
a.reverse()
stringidsSize = bytes(a)
stringidsSize = binascii.b2a_hex(stringidsSize)
stringidsSize = str(stringidsSize,encoding='utf-8')
print('字符串数量: ',end='')
print(int(stringidsSize,16),end='')
print('(',end='')
print(hex(int(stringidsSize,16)),end='')
print(')')

f.seek(0x3c)
string_ids_off = f.read(4)
a = bytearray(string_ids_off)
a.reverse()
string_ids_off = bytes(a)
string_ids_off = binascii.b2a_hex(string_ids_off)
string_ids_off = str(string_ids_off,encoding='utf-8')
print('字符串偏移位置: ',end='')
print(hex(int(string_ids_off,16)))

f.seek(0x40)
type_ids_size = f.read(4)
a = bytearray(type_ids_size)
a.reverse()
type_ids_size = bytes(a)
type_ids_size = binascii.b2a_hex(type_ids_size)
type_ids_size = str(type_ids_size,encoding='utf-8')
print('类数量: ',end='')
print(int(type_ids_size,16),end='')
print('(',end='')
print(hex(int(type_ids_size,16)),end='')
print(')')

f.seek(0x44)
type_ids_off = f.read(4)
a = bytearray(type_ids_off)
a.reverse()
type_ids_off = bytes(a)
type_ids_off = binascii.b2a_hex(type_ids_off)
type_ids_off = str(type_ids_off,encoding='utf-8')
print('类偏移位置: ',end='')
print(hex(int(type_ids_off,16)))

f.seek(0x48)
photo_ids_size = f.read(4)
a = bytearray(photo_ids_size)
a.reverse()
photo_ids_size = bytes(a)
photo_ids_size = binascii.b2a_hex(photo_ids_size)
photo_ids_size = str(photo_ids_size,encoding='utf-8')
print('方法原型数量: ',end='')
print(int(photo_ids_size,16),end='')
print('(',end='')
print(hex(int(photo_ids_size,16)),end='')
print(')')

f.seek(0x4c)
photo_ids_off = f.read(4)
a = bytearray(photo_ids_off)
a.reverse()
photo_ids_off = bytes(a)
photo_ids_off = binascii.b2a_hex(photo_ids_off)
photo_ids_off = str(photo_ids_off,encoding='utf-8')
print('方法原型偏移位置: ',end='')
print(hex(int(photo_ids_off,16)))

f.seek(0x50)
field_ids_size = f.read(4)
a = bytearray(field_ids_size)
a.reverse()
field_ids_size = bytes(a)
field_ids_size = binascii.b2a_hex(field_ids_size)
field_ids_size = str(field_ids_size,encoding='utf-8')
print('字段数量: ',end='')
print(int(field_ids_size,16),end='')
print('(',end='')
print(hex(int(field_ids_size,16)),end='')
print(')')

f.seek(0x54)
field_ids_off = f.read(4)
a = bytearray(field_ids_off)
a.reverse()
field_ids_off = bytes(a)
field_ids_off = binascii.b2a_hex(field_ids_off)
field_ids_off = str(field_ids_off,encoding='utf-8')
print('字段偏移位置: ',end='')
print(hex(int(field_ids_off,16)))

f.seek(0x58)
method_ids_size = f.read(4)
a = bytearray(method_ids_size)
a.reverse()
method_ids_size = bytes(a)
method_ids_size = binascii.b2a_hex(method_ids_size)
method_ids_size = str(method_ids_size,encoding='utf-8')
print('方法数量: ',end='')
print(int(method_ids_size,16),end='')
print('(',end='')
print(hex(int(method_ids_size,16)),end='')
print(')')

f.seek(0x5c)
method_ids_off = f.read(4)
a = bytearray(method_ids_off)
a.reverse()
method_ids_off = bytes(a)
method_ids_off = binascii.b2a_hex(method_ids_off)
method_ids_off = str(method_ids_off,encoding='utf-8')
print('方法偏移位置: ',end='')
print(hex(int(method_ids_off,16)))

f.seek(0x60)
class_defs_size = f.read(4)
a = bytearray(class_defs_size)
a.reverse()
class_defs_size = bytes(a)
class_defs_size = binascii.b2a_hex(class_defs_size)
class_defs_size = str(class_defs_size,encoding='utf-8')
print('类定义数量: ',end='')
print(int(class_defs_size,16),end='')
print('(',end='')
print(hex(int(class_defs_size,16)),end='')
print(')')

f.seek(0x64)
class_defs_off = f.read(4)
a = bytearray(class_defs_off)
a.reverse()
class_defs_off = bytes(a)
class_defs_off = binascii.b2a_hex(class_defs_off)
class_defs_off = str(class_defs_off,encoding='utf-8')
print('类定义偏移位置: ',end='')
print(hex(int(class_defs_off,16)))

f.seek(0x68)
data_size = f.read(4)
a = bytearray(data_size)
a.reverse()
data_size = bytes(a)
data_size = binascii.b2a_hex(data_size)
data_size = str(data_size,encoding='utf-8')
print('数据段大小: ',end='')
print(int(data_size,16),end='')
print('(',end='')
print(hex(int(data_size,16)),end='')
print(')')

f.seek(0x6c)
data_off = f.read(4)
a = bytearray(data_off)
a.reverse()
data_off = bytes(a)
data_off = binascii.b2a_hex(data_off)
data_off = str(data_off,encoding='utf-8')
print('数据段偏移位置: ',end='')
print(hex(int(data_off,16)))

if __name__ == '__main__':
f = open("C:\\Users\\admin\\Desktop\\android_nx\\classes.dex", 'rb', True)
parserHeader(f)
f.close()

五、相关链接

  参考链接  

  某作者github链接(相关附件下载):https://github.com/windy-purple/parserDex  

  PS:部分图片来自于网络,侵删
    同系列文章链接:
      DEX文件解析---2、Dex文件checksum(校验和)解析
      DEX文件解析--3、dex文件字符串解析
      DEX文件解析--4、dex类的类型解析
      DEX文件解析--5、dex方法原型解析
      DEX文件解析--6、dex文件字段和方法定义解析
       DEX文件解析--7、类及其类数据解析(完结篇)

免费评分

参与人数 14威望 +1 吾爱币 +20 热心值 +13 收起 理由
breezehan + 1 + 1 热心回复!
moment668 + 1 谢谢@Thanks!
luechenying + 1 + 1 图挂了楼主
到处感怀 + 1 + 1 用心讨论,共获提升!
fcguo800 + 1 + 1 谢谢@Thanks!
qtfreet00 + 1 + 9 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
叶隽 + 1 学习到了,感谢分享
fei8255 + 1 + 1 谢谢@Thanks!
jingsenzhou + 1 + 1 谢谢@Thanks!
听雨客舟 + 1 + 1 谢谢分享!学习了
四糸乃是工具人 + 1 热心回复!
letdown_nn + 1 + 1 热心回复!
sxwzxc + 1 + 1 我很赞同!
monsterbaby521 + 1 + 1 谢谢@Thanks!

查看全部评分

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

 楼主| windy_ll 发表于 2020-1-17 20:56
一介书生1212 发表于 2020-1-17 16:39
android中一个dex文件的最大方法数是65536,也就是2个字节长度。在dex文件的头中标识了方法数的长度是4个字 ...

这个你应该跟设计安卓的官方反映,跟我说这种东西一点用都木有
小小金 发表于 2020-8-19 08:07
一介书生1212 发表于 2020-1-17 16:39
android中一个dex文件的最大方法数是65536,也就是2个字节长度。在dex文件的头中标识了方法数的长度是4个字 ...

系统设计讲究一个冗余,方便以后扩展?反正用不到也才2字节
lucky. 发表于 2019-11-17 23:54
flashlaser 发表于 2019-11-18 08:35
学习了!谢谢分享!
vevei_ps 发表于 2019-11-18 08:37
学习了~学习了~~
ping170 发表于 2019-11-18 09:38
正需要,谢谢帮主!请问还有其它我们不知道的秘密吗
latvro 发表于 2019-11-18 10:13
向你学习,感谢分享
 楼主| windy_ll 发表于 2019-11-18 11:34
ping170 发表于 2019-11-18 09:38
正需要,谢谢帮主!请问还有其它我们不知道的秘密吗

以后有时间会继续写这个系列的
Xinxj 发表于 2019-11-18 13:23
棒棒哒,要向你学习
已默然 发表于 2019-11-18 13:32

学习了~学习了~~向楼主学习
pxjianing 发表于 2019-11-18 14:58
之前看过一个类似的文章,但感觉这个讲的更好,学习了~
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-12-23 07:24

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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