吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 429|回复: 2
收起左侧

[Android 原创] Dex结构

[复制链接]
soma20 发表于 2026-1-21 19:58
本帖最后由 soma20 于 2026-1-23 17:47 编辑

Dex结构

前言

​        最近开始学app的加固,花了些时间把dex结构学习了一下。打算通过两篇文章对这个dex的结构做一个总结。

一、数据类型

​        要学习dex结构,首先需要了解一下dex文件当中用到的数据类型

1. 基础数据类型

dex类型 原类型 含义
u1 uint8_t ——
u2 uint16_t ——
u4 uint32_t ——
u8 uint64_t ——
sleb128 —— 有符号leb128,可变长度1-5字节
uleb128 —— 无符号leb128,可变长度1-5字节
uleb128p1 —— 无符号leb128值加1,可变长度1-5字节

2. leb128类型

​        在程序当中,一般使用给32bit来表示一个整数型的数值。不过,一般能够使用到的数值都不会太大,使用32bit来表示会有点浪费。这对于普通计算机来说问题不大,但是对于早期移动设备来说,存储空间和内存空间非常宝贵,不能浪费,所以诞生了这么一个leb128的类型。

​        leb128(Little Endian Base128),是一种变长整数压缩编码格式,使用该方法来解决整型数值占用空间大小浪费的问题。类型原理如下:

​        leb128每个字节只有7位有效数字,最高位为拓展位,如果最高位为1,则需要再次向后获取1个字节。在内存中以小端序存储。下面是在内存/文件中读取leb128uleb28uleb128p1的方式:

  • leb128

    uint32_t readUnsignedLeb128(const u1** pStream)
    {
          const u1* ptr = *pStream;
          uint32_t 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)
                                  {
                                          cur = *(ptr++);
                                          result |= cur << 28;
                                  }
                          }
                  }
          }
          *pStream = ptr;
          return result;
    }
  • uleb128

    int readSignedLeb128(const u1** pStream)
    {
          const 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
                                  {
                                          cur = *(ptr++);
                                          result |= (cur << 28);
                                  }
                          }
                  }
          }
          *pStream = ptr;
          return result;
    }
  • uleb128p1

    ​        这里如果要表示的整数范围只包含一个负数,即-1的话,直接使用sleb128编码会比较浪费,因此Android创造出了所谓的uleb128p1的编码方式,实现如下:

    readUnsignedLeb128(pStream) - 1;

3. encoded_value类型

​        关于这里的encoded_value可以等到后面学习annotation注释结构再进行了解,现在可以先跳过。

​        这里参考的是Android的官方文档:Dalvik 可执行文件格式  | Android Open Source Project

encoded_value 是(几乎)任意层次结构数据的编码片。这种编码非常精简,易于解析。

名称 格式 说明
encoded_value = (value_arg<<5) | value_type ubyte(1byte) 一种字节,低5位表示类型,高3位是附加信息,根据不同类型有不同解释
ubyte[] 用于表示值的字节,不同 value_type 字节的长度不同且采用不同的解译方式

值格式:

类型名称 value_type value_arg value格式 说明
VALUE_BYTE 0x00 0 ubyte[1] 有符号的单字节整数值
VALUE_SHORT 0x01 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_idx,方法类型索引
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_ANNOTATION 0x1d 0 encoded_annotation 接下来的数据使用encoded_anntotaion格式解析
VALUE_NULL 0x1e 0 null引用值
VALUE_BOOLEAN 0x1f 布尔值(0..1) 0表示flase,1表示true

4. encoded_array格式

名称 格式 说明
size uleb128 数组长度
values encoded_value[size] encoded_value数组

5. encoded_annotation格式

名称 格式 说明
type_idx uleb128 注释类型
size uleb128 annotation_element数组的长度
elements annotation_element[size] annotation_element结构体数组

6. annotation_element格式

名称 格式 说明
name_idx uleb128 元素名称,string_ids的索引
value encoded_value 元素值

上面这些就是用到的比较重要的数据类型和数据结构了。

二、Dex整体结构

​        dex的整体结构分为三个部分:dex文件头索引结构区data数据区,示意图如下:

1

1
1. dex文件头

​        保存了dex的文件基本信息,例如文件大小,头大小,大小端序,索引表的起始地址和偏移等等

2. 索引结构区

​        这部分保存了字符串表,类型表,方法原型表,域表,方法表等结构。这些结构当中存放的是对应数据的offset偏移,通过

fileBuf + offset

可以访问到对应的数据。

3. data数据区

​        所有的代码和数据存放在该地方。

tips

​        有关dex的结构体信息可以通过libdexfile/dex/dex_file.h - platform/art - Git at Google源代码进行了解。

三、文件头--DexHeader

​        dexHeader的定义如下:

struct Header {
    u1  magic[8];                           // 文件魔数        
    u4  checksum;                                  // adler32校验和
    u1  signature[kSHA1DigestLen];         // sha-1 哈希值 
    u4  fileSize;                           // dex文件大小
    u4  headerSize;                         // dexHeader大小
    u4  endianTag;                                        // 字节端序
    u4  linkSize;                                        // 链接段大小
    u4  linkOff;                                        // 链接段起始偏移
    u4  mapOff;                                                // DexMapList起始偏移
    u4  stringIdsSize;                                // StringIds大小
    u4  stringIdsOff;                                // StringIds偏移
    u4  typeIdsSize;                                // typeIds大小
    u4  typeIdsOff;                                        // typeIds偏移
    u4  protoIdsSize;                                // protoIds大小
    u4  protoIdsOff;                                // protoIds偏移
    u4  fieldIdsSize;                                // fieldIds大小
    u4  fieldIdsOff;                                // fieldIds偏移
    u4  methodIdsSize;                                // methodIds大小
    u4  methodIdsOff;                                // methodIds偏移
    u4  classDefsSize;                                // classDef大小
    u4  classDefsOff;                                // classDef偏移
    u4  dataSize;                                        // 数据区大小
    u4  dataOff;                                        // 数据区偏移
};

​        dex的文件头格式如上,比较简单包含了文件的基本信息,以及各种索引表、数据段的偏移和大小

四、Dex索引区

1. StringIds

​        StringIds是整个文件的字符串索引池,通过这里的索引可以找到Dex文件当中所有用到的字符串。

  • dex文件当中的字符串采用的是MUTF-8的编码,stringIds元素字符串的结构如下:
struct DexStringId{
    u4 stringOff;                        // 字符串结构偏移
};

struct dex_string{
    uleb128 len;
    u1 str[1];
};

StringIds内部每一个元素都是一个字符串的偏移,通过这个字符串的偏移可以直接找到对应的字符串结构。查找过程如下:

2

2

使用010eidt可以对照对应的字符串:

3

3

2. typeIds

​        typeIds是类型索引区,包含了该dex用到的所有类型,typeIds当中的元素定义如下:

struct dexTypeId{
    u4 descriptor_idx;                // 指向StringIds列表的索引
}

typedidstringIds当中的索引,查找方式如下:

stringIds[descriptor_idx] --> TypeString

3. DexprotoIds

​        protoIds定义了用到的方法的声明原型protoId结构如下:

struct DexProtoId{
    u4 shortyIdx;                 // 指向 StringIds, 方法签名
    u4 retType;                        // 返回值类型,指向TpyeIds
    u4 parametersOff;        // 参数列表,DexTypeList的偏移
};

​        parametersOffDexTypeList的偏移。

DexTypeList

​        该结构定义如下:

struct DexTypeList{
    u4 size;                                // DexTypeItem个数,即参数个数
    DexTypeItem list[1];        // 参数列表,从左到右
};
struct DexTypeItem{
    u2 typeIdx;                                // 指向typeIds的索引
};

各项查找方法:
这里以010edit当中分析出来的protoId[0]为例:

4

4

// 方法声明
shorty  --> StringIds[shortyIdx] -> "ILL";
retType --> StringIds[typeIds[retType]] -> "I";
param   --> StringIds[typeIds[list[0]]] -> "Ljava/lang/String";
                --> StringIds[typeIds[list[1]]] -> "Ljava/lang/String";

[原创]DEX文件格式解析:深入Android字节码结构-Android安全-看雪安全社区|专业技术交流与安全研究论坛

4. FieldIds

​        FieldIds定义了代码中所有字段的索引信息,回答了三个问题:谁的字段什么类型的字段叫什么名字。结构如下:

struct FieldId{
          u2 class_idx;                // typeIds索引
          u2 type_idx;                // typeIds索引
    u4 name_idx;                // StringIds索引
};

各个字段的查找方式:

​        这里以010edit当中field[0]为例子:

5

5

class         : stringIds[typeIds[class_idx]] --> "Lcom/kejian/test/BuildConfig;";
type        : stringIds[typeIds[class_idx]] --> "Lcom/kejian/test/R$style;";
name        : stringIds[name_idx]                        --> "APPLICATION_ID";

5. MethodIds

​        Dex文件结构中,MethodIds是方法索引区,记录了Dex文件中所有被引用或定义的方法的签名信息

struct DexMethodId{
    u2 class_idx;                // typeIds 索引
    u2 proto_idx;                // ProtoIds 索引
    u4 name_idx;                // StringIds 索引
};

查找方式:

​        使用typeIdsProtoIdsStringIds的方式进行查找,010edit分析如下:

6

6

6. DexMapList

​        DexMapList是文件的完整目录。它列出了Dex文件中所有数据段的类型、数量和位置。Header中的map_off指向这个结构。要学习DexMapList首先要了解MapItem的类型都有哪些:

  • DexMap类型:
enum MapItemType{
    kDexTypeHeaderItem = 0x0000,                 // 模式整个DexHeader结构,它占用了文件的前0x70个字节的空间
    kDexTypeStringIdItem = 0x0001,                 // stringIdsSize stringIdsSize 
    kDexTypeTypeIdItem = 0x0002,                 // typeIdsSize typeIdsOff
    kDexTypeProtoIdItem = 0x0003,                 // protoIdsSize protoIdsOff
    kDexTypeFieldIdItem = 0x0004,                 // fieldIdsSize fieldIdsSize
    kDexTypeMethodIdItem = 0x0005,                 // methodIdsSize methodIdsOff
    kDexTypeClassDefItem = 0x0006,                 // classDefsSize classDefsOff  指向的结构体为DexClassDef

    kDexTypeMapList = 0x1000,                          // DexMapItem结构
    kDexTypeTypeList = 0x1001,                         // DexTypeList结构
    kDexTypeAnnotationSetRefList = 0x1002,
    kDexTypeAnnotationSetItem = 0x1003,

    kDexTypeClassDataItem = 0x2000,         // DexClassData结构
    kDexTypeCodeItem = 0x2001,                         // DexCode结构
    kDexTypeStringDataItem = 0x2002,         // 指向DexStringId字符串列表的首地址
    kDexTypeDebugInfoItem = 0x2003,         // 调式信息偏移
    kDexTypeAnnotationItem = 0x2004,
    kDexTypeEncodedArrayItem = 0x2005,
    kDexTypeAnnotationsDirectoryItem = 0x2006,
};
  • DexMapItem
struct DexMapItem{
    u2 type;                        // MapItemType 枚举类型
    u2 unused;                        // 内存对齐填充,通常为0 
    u4 size;                        // 类型数据个数
    u4 offset;                        // 类型数据的起始偏移
};

​        MapListHeader当中的mapOff指明偏移位置。

  • DexMapList
struct DexMapList{
    u4 size;                        // 指明类型个数
    DexMapItem list[1];        // MapItem数组
};

010edit查找如下:

7

7

五、DexClassDef

​        ClassDefs是类定义区。它是整个Dex文件的核心骨架,之前的StringIdsTypeIdsMethodIds只是散落的零件,而ClassDefs则是将这些零件组装成一个完整的Java类的地方。

​        每一个DexClassDef结构体都描述了一个类所有的信息:他继承谁?实现了什么接口?源代码的文件名称是什么?他的字段和方法代码在哪里?

1. DexClassDef结构定义

​        ClassDefs的位置由Header中的class_defs_sizeclass_defs_off指定。列表当中的每一项是一个DexClassDef结构,占用32个字节,结构如下:

struct DexClassDef {
    u4 class_idx;               // TypeIdx ()
    u4 access_flags;            // 访问标志 (public, final, etc.)
    u4 superclass_idx;          // TypeIdx (父类)
    u4 interfaces_off;          // 接口列表的偏移量 (指向 TypeList)
    u4 source_file_idx;         // StringIds (源代码文件名称)
    u4 annotations_off;         // 注解目录起始偏移,指向DexAnnotationsDirectoryItem结构体
    u4 class_data_off;          // 【关键】类数据的偏移量 (指向 class_data_item)
    u4 static_values_off;        // 静态变量初始值的偏移量
};

这里面的class_idxsuperclass_idxinterfaces_offsource_file_idx的解析方式都是一些就的知识点,这里就不再提及了。有不懂的话请看前前一篇文章。

2. access_flags字段

​        这个字段存储的是class的访问标志,例如:publicfinaletc等等。可以在官方文档中查看到Dalvik 可执行文件格式  | Android Open Source Project

​        这里展示一下,具体数值对应的类型如下:

名称 对于类(和 InnerClass 注释) 对于字段 对于方法
ACC_PUBLIC 0x1 public public public
ACC_PRIVATE 0x2 private private private
ACC_PROTECTED 0x4 protected protected protected
ACC_STATIC 0x8 static static static
ACC_FINAL 0x10 final:不可子类化 final:构建后不可变 final:不可替换
ACC_SYNCHRONIZED 0x20 synchronized:调用此方法时自动获得关联锁定。注意:这一项仅在同时设置 ACC_NATIVE 的情况下才有效。
ACC_VOLATILE 0x40 volatile:有助于确保线程安全的特殊访问规则
ACC_BRIDGE 0x40 桥接方法,由编译器自动添加为类型安全桥
ACC_TRANSIENT 0x80 transient:不会通过默认序列化保存
ACC_VARARGS 0x80 最后一个参数应被编译器解译为“rest”参数
ACC_NATIVE 0x100 native:在原生代码中实现
ACC_INTERFACE 0x200 interface:可多倍实现的抽象类
ACC_ABSTRACT 0x400 abstract:不可直接实例化 abstract:不通过此类实现
ACC_STRICT 0x800 strictfp:严格的浮点运算规则
ACC_SYNTHETIC 0x1000 不在源代码中直接定义 不在源代码中直接定义 不在源代码中直接定义
ACC_ANNOTATION 0x2000 声明为注解类
ACC_ENUM 0x4000 声明为枚举类型 声明为枚举值
(未使用) 0x8000
ACC_CONSTRUCTOR 0x10000 构造函数方法(类或实例初始化程序)
ACC_DECLARED_SYNCHRONIZED 0x20000 声明了 synchronized

​        我在这里进行类型解析的时候使用了一个比较笨的方法,但是比较有效:

void Utils::printAccessFlags(u4 flags)
{
        for (u4 mask = 1; mask < 0x80000000; mask <<= 1)
    {
                AccessFlags flag = (AccessFlags)(flags & mask);
                if (flag != 0)
                        printf("%s ", accessflags[flag].c_str());
        }
}

3. annotations_off注解信息

​        annotations_offdex中注解目录的偏移量。首先来简单了解一下注解是什么:

@Deprecated                                        // 1. 类注解 (Class Annotation)
public class SimpleDemo {   
    @Deprecated                         // 2. 字段注解 (Field Annotation)
    public int myField;

    @Deprecated                                // 3. 方法注解 (Method Annotation)
    public void myMethod(@Deprecated int myParam) {}        // 4. 参数注解 (Parameter Annotation)
}

annotations是一个好几层的结构,下面一些用到的结构:

  • DexAnnotationsDirectoryItem
struct DexAnnotationsDirectoryItem {
    u4  classAnnotationsOff;  // DexAnnotationSetItem 偏移
    u4  fieldsSize;           // DexFieldAnnotationsItem 的数量
    u4  methodsSize;          // DexMethodAnnotationsItem 的数量
    u4  parametersSize;       // DexParameterAnnotationsItem 的数量
    /* followed by DexFieldAnnotationsItem[fieldsSize] */
    /* followed by DexMethodAnnotationsItem[methodsSize] */
    /* followed by DexParameterAnnotationsItem[parametersSize] */
};

这个是注解的目录信息,分别是

  • 类注解偏移:指向DexAnnotationSetItem结构
  • 字段注解数量:DexFieldAnnotationsItem项的数量
  • 方法注解数量:DexMethodAnnotationsItem项的数量
  • 参数注解数量:DexParameterAnnotationsItem项的数量

​        如果fieldsSizemethodsSizeparametersSize这三个成员不为0的话,在该结构中会多出对应的数组DexFieldAnnotationsItem[fieldsSize]DexMethodAnnotationsItem[methodsSize]DexParameterAnnotationsItem[parametersSize]

​        

  • DexAnnotationSetItem
struct DexAnnotationSetItem {
    u4  size;
    u4  entries[1];                 // DexAnnotationItem 的偏移
};

​        size指出了entries有多少项。

  • DexAnnotationItem
struct DexAnnotationItem {
    u1  visibility;
    u1  annotation[1];              /* data in encoded_annotation format */
};

​        visibility的值在官方文档当中的定义如下:

名称 说明
VISIBILITY_BUILD 0x00 预计仅在构建(例如,在编译其他代码期间)时可见
VISIBILITY_RUNTIME 0x01 预计在运行时可见
VISIBILITY_SYSTEM 0x02 预计在运行时可见,但仅对基本系统(而不是常规用户代码)可见

annotationencoded_annotation的开头,也就是说encoded_annotation是连在visibility后面的,

​        encoded_annotation结构如下:

struct encoded_annotation{
    uleb128 type_idx;                        // typeIds索引
    uleb128 size;                                // elements 的长度
    annotation_element elements[1];        // 后续紧接annotation_element结构
};

​        elements指向的是annotation_element结构:

struct annotation_element{
    uleb128 name_idx;                        // stringIds索引
    encoded_value value;                // encoded_value值
};

注意:这里的三个结构其实是紧紧连接到一起的,解析的时候需要动态解析

​        要解析类注解,就需要熟悉上面的结构体,整理这些结构之后的关系图解如下:

image-20260121214900024.png

  • DexFieldAnnotationsItem

​        该结构的作用是:记录哪个字段,带有什么注解。

struct DexFieldAnnotationsItem {
    u4  fieldIdx;
    u4  annotationsOff;             // DexAnnotationSetItem偏移
};
  • DexMethodAnnotationsItem

​        该结构的作用是:记录某个方法,带有什么注解

struct DexMethodAnnotationsItem {
    u4  methodIdx;
    u4  annotationsOff;             // DexAnnotationSetItem偏移
};

​        对于字段注解、方法注解的解析方式都是大差不差的,结构层次如下图:
image-20260122132249043.png

  • DexParameterAnnotationsItem

​        该结构的作用是:记录参数的所属的方法,以及各个参数的注释

struct DexParameterAnnotationsItem {
    u4  methodIdx;
    u4  annotationsOff;             // DexAnotationSetRefList的偏移
};
  • DexAnotationSetRefList
struct DexAnnotationSetRefList {
    u4  size;
    DexAnnotationSetRefItem list[1];
};

struct DexAnnotationSetRefItem {
    u4  annotationsOff;             // DexAnnotationSetItem的偏移
};

​        由于一个方法可能包含多个参数,即包含多个参数注解。所以参数注解的解析稍微有些不同,首先先通过DexAnotationSetRefList找到该方法的所有参数注解。接着在通过DexAnnotationSetItem获取详细的参数注解信息。

​        结构层次如下图:
image-20260122160439665.png

​        可见这个参数注解信息还是比较复杂的。不过一般情况下也遇不到

4. class_data_off字段

​        这个字段指向的是class_data_item的结构,这个结构存储了这个类真正拥有的所有变量(字段),方法信息。

接下来了解一下与这个结构有关的一些结构:

  • DexClassData
struct DexClassData {
    DexClassDataHeader header;                                        // 指定字段与方法的个数
    DexField*          staticFields;                        // static字段
    DexField*          instanceFields;                        // 实例字段
    DexMethod*         directMethods;                        // 直接方法
    DexMethod*         virtualMethods;                        // 虚方法,虚函数
};

struct DexClassDataHeader {
    u4 staticFieldsSize;                // static字段个数
    u4 instanceFieldsSize;                // 实例字段个数
    u4 directMethodsSize;            // 直接方法个数
    u4 virtualMethodsSize;                // 虚方法个数
};

​        class_data_off指向的就是DexClassData这个结构。该结构中的header存储着该类所拥有的字段个数与方法个数。而且只有当这些size不为,对应的DexField或者DexMethod指针才不为0。

  • DexField
struct DexField {
    u4 fieldIdx;                                   // fieldIds_idx
    u4 accessFlags;                                // 访问标志
};

​        该结构存放着字段在fieldIds的索引值,以及字段的属性,通过该结构可以找出一个完整的字段,如下图所示:
image-20260122162526227.png

  • DexMethod
struct DexMethod {
    u4 methodIdx;    // methodIds 索引
    u4 accessFlags;
    u4 codeOff;      // code_item 偏移量
};

​        该结构存放的是methodIds的索引值,以及方法的属性,还有方法的Code所在位置,Code结构体如下:

  • DexCode
struct DexCode {
    u2  registersSize;                // 使用寄存器个数
    u2  insSize;                        // 参数个数
    u2  outsSize;                        // 调用其他方法时使用的寄存器个数
    u2  triesSize;                        // try/catch语句的个数
    u4  debugInfoOff;       // 调试信息偏移量 dexDecodeDebugInfo
    u4  insnsSize;          // 指令集个数,两个字节为单位 
    u2  insns[1];                        // 指令集
    /* optional u2 padding */
    /* try_item[triesSize] (DexTry结构)*/
    /* uleb128 handlersSize (try/catch语句中handler个数)*/
    /* catch_handler_item[handlersSize] (DexCatchHandler结构)*/
};

​        通过这个Code结构可以获取到该方法所使用的寄存器个数参数个数,调用其他方法使用的寄存器个数,以及指令集。这里的指令集可以被反汇编成smali代码。

​        classData结构层次如下:

image-20260122164501840.png

六、总结

​        至此这里已经把Dex的大部分结构分析完了

参考

[原创]DEX文件格式解析:深入Android字节码结构-Android安全-看雪安全社区|专业技术交流与安全研究论坛


&#8203;

免费评分

参与人数 4吾爱币 +9 热心值 +4 收起 理由
qtfreet00 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
allspark + 1 + 1 用心讨论,共获提升!
zhp_king + 1 用心讨论,共获提升!
metoo2 + 1 + 1 谢谢@Thanks!

查看全部评分

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

 楼主| soma20 发表于 2026-1-23 17:51
之前将文章分开两部分,现在合并之后另外一篇的评论没了。这里放一下这位师傅的评论。 微信图片_20260123174704_11_54.png
jspx 发表于 2026-1-23 23:11
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2026-1-24 04:45

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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