首页
社区
课程
招聘
[原创]dex起步探索
发表于: 2021-7-14 21:49 22920

[原创]dex起步探索

2021-7-14 21:49
22920

部分内容摘自:android软件安全权威指南:丰生强

从根源上搞懂基础的原理是很有必要的,这样有助于我们更方便的利用它的特性,达到我们的目的。

我把内容主要分为二个部分。原理探索、案例分析

我们在正向开发app编译时,编写的java代码,会编译成java字节码保存在.class后缀的文件中。然后再用dx工具将java字节码转换成dex文件(Dalvik字节码)。在转换的过程中,会将所有java字节码中的所有冗余信息组成一个常量池。例如多个class文件中都存在的字符串"hello world"。转换后将单独存放在一个地方,并且所有类共享。包括方法的签名也会组成常量池。我们将编译好的apk文件解压后就能拿到classes.dex文件。

上面拿到的classes.dex文件包含了apk的可执行代码。Dalvik虚拟机会解析加载文件并执行代码。只要我们了解这个文件格式的组成,那么就可以自己解析这个文件获取到想要的数据。

首先是安卓源码中的dalvik/libdex/DexFile.h这里可以找到dex文件的数据结构。下面贴上源码部分

为了更好的理解。dex文件格式,我们可以用010编辑器打开一个dex文件对照这个结构体来观察一下。

可以看到,这个dex文件由这8个部分组成。

dex_header:dex文件头,指定了dex文件的一些数据,记录了其他数据结构在dex文件中的物理偏移

string_ids:字符串列表(前面说的去掉冗余信息组成的常量池,全局共享使用的)

type_ids:类型签名列表(去掉冗余信息组成的常量池)

proto_ids:方法声明列表(去掉冗余信息组成的常量池)

field_ids:字段列表(去掉冗余信息组成的常量池)

method_ids:方法列表(去掉冗余信息组成的常量池)

class_def:类型结构体列表(去掉冗余信息组成的常量池)

map_list:这里记录了前面7个部分的偏移和大小。

然后我们开始逐个的看各个部分的结构。

先是贴上源码看看这个部分的结构体

这里可以看到,如果在DexHeader中,可以找到其他部分的偏移和大小,以及整个文件的大小,解析出这块数据,其他部分的任意数据,我们都可以获取到。然后再使用对应的结构体来解析。另外留意这里DexHeader的结构体的大小是固定0x70字节的。所以有的脱壳工具中会将70 00 00 00来作为特征在内存中查找dex进行脱壳(比如FRIDA-DEXDump的深度检索)

然后我们贴一下真实classes.dex文件的DexHeader数据是什么样的。

先看看字符串列表的结构体,非常简单,就是字符串的偏移,但是并不是普通的ascii字符串,而是MUTF-8编码的。这个是一个经过修改的UTF-8编码。和传统的UTF-8相似

类型签名列表的结构体也是非常简单,和上面字符串列表差不多

真实数据图如下,可以看到值类型签名都在前面,后面都是引用类型签名。

方法声明的列表的结构体较为复杂,因为方法签名必然是有几点信息构成:返回值类型、参数类型列表(就是每个参数是什么类型)。方法声明的结构体如下

同样看看这个结构的真实数据

字段描述的结构体,我们可以先想象一下,要找一个字段,我们需要些什么:字段所属的类,字段的类型,字段名称。有这些信息,就可以找到各自对应的字段了。接下来看看定义的结构体

然后看一段真实数据

方法描述的结构体,同样先了解找一个方法的几个必须项:方法所属的类,方法的签名(签名中有方法的返回值和方法的参数,也就是上面的proto_ids中记录的),方法的名称。然后下面看结构体

看看一组方法的真实数据

类定义的结构体,这个比较复杂。直接贴上结构体和原文的说明。这里大致可以看出来,和上面的原理差不多,通过这个结构体来描述类的内容。

下面同样展示一组真实数据

上面数据看到里面的class_data也是一个结构体,然后继续看这个类数据的结构体

到这里我们基本看到了在开发中,一个类的所有特征。完整的描述出了一个类的所有信息。

9、DexCode上面最后看到方法的代码是通过上面的DexCode结构体来找到的。最后看下这个结构体

到了这里,存储的就是执行的指令集了。通过执行指令来跑这个方法。下面看一组真实数据

这里看到这个类的具体描述字段和函数,还有访问标志等等信息。然后我们继续看里面函数的执行代码部分。看下面一组数据

观察的函数是MainActivity类的DoTcp函数。DexCode(也就是code_item,也叫codeOff)的偏移地址是0x127ec。

下面观察到DexCode结构体的偏移到指令集insns字段的偏移是codeOff+2+2+2+2+4+4=0x127fc(这里+的2和4是看下面结构体insns前面的字段占了多少个字节计算的,可以当做固定+16个字节)。指令集的长度是0x93。

最后看看指令集的开始数据是0x62、0xe26、0x11a、0x232。但是我们要注意前面有说明,这里是两字节空间对齐。所以,这里的值我们应该前面填充一下。

前面四个字节我们要看做0x0062、0x0e26、0x011a、0x0232。但是我们还要注意,还有个端序问题会影响字节的顺序,这里是小端序,所以我们再调整下

前面四个字节我们要看做0x6200、0x260e、0x1a01、0x3202。把这段指令集的数据看明白后,我们用gda打开这个dex文件。然后找到对应的方法,查看一下。

然后发现数据对上了。这里存储的果然就是我们dex分析方法的字节码了。

在书中的意思是,Dalvik虚拟机解析Dex后,将其映射成DexMapList的数据结构,然后在里面可以找到前面8个部分的偏移和大小。先看看结构体

每个DexMapItem对应了一块数据,例如type=kDexTypeHeaderItem则对应DexHeader的偏移地址和大小。下面看真实数据

这里就能看到string_ids的偏移和大小。如此,根据这个map_list就能找到所有块的数据了。

那么在源码中是如何使用这个数据的呢,我好奇的翻了一下。然后再dex文件优化的流程中dexSwapAndVerify函数找到了使用的地方。

这个函数中获取了DexMapList。然后交给swapMap函数来处理。

通过这里的例子。我们可以看到他是如何使用这个map_list来访问所有的部分的。到这里dex文件的格式基本差不多了。

然后我们看看一个实战的项目。大佬写的fart中的py部分就的运用了dex文件格式相关的知识。

FART

这是一个脱壳工具,使用主动调用的方式来解决二代抽取壳。脱出来的数据不止是dex。还有一种.bin的数据,这种数据可以用来辅助我们修复dex的一些没有脱出来的函数。我们先看下.bin数据是什么,下面是.bin中的一组数据

name:是随意填的,因为并不是使用name来找对应函数,而是通过method_idx

method_idx:函数的索引。

offset:函数的偏移

code_item_len:code_item的大小

ins:code_item结构体这段数据的base64编码

另外贴一下这几个数据的dump来源的代码,以防有人把ins当成指令集了。

这几个数据是一个函数最关键的片段。拿到就可以还原出最关键的code_item了。

然后看看fart.py的使用./fart.py -d 431528_29868.dex -i 431528_29868.bin。下面是执行结果,基本对这个dex进行完整的解析,打印出来大多数的数据。

我们可以通过对这个项目的阅读,直观的了解到是如何进行dex文件格式进行解析的。下面开始看看具体的实现流程

然后看看是如何加载.bin文件的

可以看到就是遍历,组装好那些数据,最后保存到一个methodTable里面,索引就是method_id。

再看看最关键的dex_parse

这里看到是通过init_header来解析dex文件中的dexHeader的。我就不贴代码了,整体就是偏移然后取数据。

这里有一点要说的是get_uleb128函数,uleb128在android里面是一个特殊的类型。是一个可变长度的类型。大致意思就是例如第一个字节的最高位,如果是1,则第二个字节也是有效数据,如果第二个字节的最高位也是1,下一个字节也是有效数据,如果最高位不是1,就结束了。最后左移拼接就ok了。

这个类型有没有很眼熟?没错,特别像是protobuf里面的varint编码。所以我觉得完全可以用protobuf包自带的varint解码来获取这个数据。也可以用这种自己写的函数来处理。

继续看后面的关键函数dex_class,这里来处理每一个类的打印

先看看初始化函数,基本和之前的initHeader的差不多,就是偏移取数据,然后保存下来。把classDef相关的数据都读取出来了。

最后就是print函数,这里比较大,就只挑最关键的部分出来说下

最后我们看下怎么获取的bin文件数据的函数

最后还有个打印指令集的部分就不贴了。感兴趣的可以自己看一看

dex2jar

这个工具基本大家都用过。功能非常强大,不过这里只分析下d2j_dex2jar功能。也就是把dex给转换成jar文件。

下载release版本直接./d2j-dex2jar.sh classes.dex,就生成出了对应的classes-dex2jar.jar文件。然后我们直接用其他分析工具就能愉快的看java代码了。那么神奇的事情是如何做到的呢。下面跟踪分析一下大佬的作品。

第一步是找到入口,根据我们上面的使用例子,先搜索下d2j-dex2jar。然后找到了下面的文件

./dex2jar/dex-tools/src/main/java/com/googlecode/dex2jar/tools/Dex2jarCmd.java

先简单的看一下这里的代码,看来这里就是入口函数了。

然后看看doMain的实现

这里调用了抽象方法,doCommandLine,所以继续看看实现

到这里就可以看出来两个最重要的部分了

1、解析dex的 MultiDexFileReader.open方法

2、执行转换的Dex2jar的to方法

下面先看看解析的处理

我们直接看参数为dex文件的情况就好了,所以继续看DexFileReader的构造函数

上面看了dexHeader的解析的核心部分,接下来我们看看转换实现to方法

继续看看doTranslate方法

我们主要观察的是dex的结构和解析,所以就不详细看转换部分了,继续看解析部分的后续accept方法

这里最关键的就是acceptClass来解析具体的类的内容

对类数据进行详细解析后,接着是对字段和方法的解析填充。先看看字段的解析处理

字段填充完毕,然后看看方法是怎么解析填充的。

继续看code_item的解析

最后的acceptInsn指令集的解析方法太大了,我就不放上来了。整个解析填充的流程就完成了。后面就使用解析好的数据进行转换的操作。

可以看到两个案例的解析的方式差不多,总体都是根据结构体的大小偏移来取得想要的数据。最后一层一层的处理。

为了方便使用和测试,我将fart的解析整理了一下,改到了python3运行的。然后整合到了我的整合怪里面。感兴趣的可以看看。刚跑通,不知道有没啥问题,后面我再慢慢修复把。

github:fridaUiTools

贴上效果图

fart的修复方案仅仅是打印出了保存的指令数据。如果我们是想要直接转成.class文件或者是jar文件。是否可行呢。

我设想了两种方案来做,但是最后都被自己给否定了。

1、bin文件中的指令数据直接插入到dex文件的对应数据中,最后保存为一个新的文件。但是这样中间插一段数据,会有大量的偏移数据要修改。

2、和dex2jar的模式一样。构造好一个fileNode对象,里面就不存在偏移的问题了。最后把里面的类数据导出成.class文件。

疑问中的目的主要是想要fart.py跑完后直接输出一个新的dex文件,里面把bin文件的函数都填充到新的dex了。然后可以用jadx之类的工具直接打开查看

最早先从修复的角度想,简单的处理就是把bin中的内容解析成codeitem后,插到method_idx的里面对应的函数去。但是由于指令集的大小和原来不一样。肯定会导致后面数据的偏移全部发生变化。

于是我分析了一下dex2jar。然后发现确实有更好的办法

和原来的目前一样。但是把修复两个字调整一下说法。具体应该叫dex转换dex
先看看dex2jar的做法是:解析dex,dex数据全部展开解析为java结构体,与偏移无关了,然后转换.class的结构,写入文件,最后打包成jar

学习到人家的思路之后。我们可以变化下自己的思路,下面是我设想的两个解决方案。目前还没有做哦。但是感觉可行性非常高

一:fart修改的解决方案
fart中定义dex的完整结构体,fart解析完dex后,直接将数据保存在结构体中,达到了偏移无关了。然后在遍历bin的数据。将code_item数据替换。然后再将整个dex结构体重新解析生成一个新的dex。

二:dex2jar的功能新增解决方案
就是给dex2jar新增一个功能。前面完全按照他的方式解析出fileNode,然后读取bin文件解析出code_item。然后替换fileNode中对应的code_item数据。然后再重新生成回dex文件。

 
struct DexFile {
    /* odex的头 */
    const DexOptHeader* pOptHeader;
 
    /* dex文件头,指定了dex文件的一些数据,记录了其他数据结构在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 {
    /* odex的头 */
    const DexOptHeader* pOptHeader;
 
    /* dex文件头,指定了dex文件的一些数据,记录了其他数据结构在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 DexHeader {
    u1  magic[8];           /* 表示是一个有效的dex文件。值一般固定为64 65 78 0A 30 33 35 00(dex.035*/
    u4  checksum;           /* adler32 checksum dex文件的校验和,用来判断文件是否已经损坏或者篡改 */
    u1  signature[kSHA1DigestLen]; /* SHA-1 hash 用来识别未经dexopt优化的dex文件*/
    u4  fileSize;           /* length of entire file 记录了包括dexHeader在内的整个dex文件的大小*/
    u4  headerSize;         /* offset to start of next section  dexHeader占用的字节数,一般都是0x70*/
    u4  endianTag;                    /* 指定dex运行环境的cpu字节序。预设是ENDIAN_CONSTANT等于0x12345678,也就是默认小端字节序 */
    u4  linkSize;                        /* 链接段的大小 */
    u4  linkOff;                        /* 链接段的偏移 */
    u4  mapOff;                            /* DexMapList结构的文件偏移 */
    u4  stringIdsSize;            /* 下面都是数据段的大小和文件偏移 */
    u4  stringIdsOff;
    u4  typeIdsSize;
    u4  typeIdsOff;
    u4  protoIdsSize;
    u4  protoIdsOff;
    u4  fieldIdsSize;
    u4  fieldIdsOff;
    u4  methodIdsSize;
    u4  methodIdsOff;
    u4  classDefsSize;
    u4  classDefsOff;
    u4  dataSize;
    u4  dataOff;
};
struct DexHeader {
    u1  magic[8];           /* 表示是一个有效的dex文件。值一般固定为64 65 78 0A 30 33 35 00(dex.035*/
    u4  checksum;           /* adler32 checksum dex文件的校验和,用来判断文件是否已经损坏或者篡改 */
    u1  signature[kSHA1DigestLen]; /* SHA-1 hash 用来识别未经dexopt优化的dex文件*/
    u4  fileSize;           /* length of entire file 记录了包括dexHeader在内的整个dex文件的大小*/
    u4  headerSize;         /* offset to start of next section  dexHeader占用的字节数,一般都是0x70*/
    u4  endianTag;                    /* 指定dex运行环境的cpu字节序。预设是ENDIAN_CONSTANT等于0x12345678,也就是默认小端字节序 */
    u4  linkSize;                        /* 链接段的大小 */
    u4  linkOff;                        /* 链接段的偏移 */
    u4  mapOff;                            /* DexMapList结构的文件偏移 */
    u4  stringIdsSize;            /* 下面都是数据段的大小和文件偏移 */
    u4  stringIdsOff;
    u4  typeIdsSize;
    u4  typeIdsOff;
    u4  protoIdsSize;
    u4  protoIdsOff;
    u4  fieldIdsSize;
    u4  fieldIdsOff;
    u4  methodIdsSize;
    u4  methodIdsOff;
    u4  classDefsSize;
    u4  classDefsOff;
    u4  dataSize;
    u4  dataOff;
};
 
 
struct DexStringId {
    u4 stringDataOff;      /* 字符串数据偏移 */
};
struct DexStringId {
    u4 stringDataOff;      /* 字符串数据偏移 */
};
struct DexTypeId {
    u4  descriptorIdx;      /* index into stringIds list for type descriptor */
};
struct DexTypeId {
    u4  descriptorIdx;      /* index into stringIds list for type descriptor */
};
 
struct DexTypeList {
    u4  size;               /* dexTypeItem的个数 */
    DexTypeItem list[1];    /* entries */
};
struct DexTypeItem {
    u2  typeIdx;            /* DexTypeId的索引 */
};
struct DexProtoId {
    u4  shortyIdx;          /* DexStringId列表的索引,方法签名字符串,由返回值和参数类型列表组合*/
    u4  returnTypeIdx;      /* DexTypeId的索引,返回值的类型 */
    u4  parametersOff;      /* 指向DexTypeList的偏移,参数类型列表 */
};
struct DexTypeList {
    u4  size;               /* dexTypeItem的个数 */
    DexTypeItem list[1];    /* entries */
};
struct DexTypeItem {
    u2  typeIdx;            /* DexTypeId的索引 */
};
struct DexProtoId {
    u4  shortyIdx;          /* DexStringId列表的索引,方法签名字符串,由返回值和参数类型列表组合*/
    u4  returnTypeIdx;      /* DexTypeId的索引,返回值的类型 */
    u4  parametersOff;      /* 指向DexTypeList的偏移,参数类型列表 */
};
 
struct DexFieldId {
    u2  classIdx;           /* 类的类型,指向DexTypeId的索引,字段所属的类 */
    u2  typeIdx;            /* 字段类型,指向DexTypeId的索引,字段的类型 */
    u4  nameIdx;            /* 字段名,指向DexStringId的索引,字段的名称 */
};
struct DexFieldId {
    u2  classIdx;           /* 类的类型,指向DexTypeId的索引,字段所属的类 */
    u2  typeIdx;            /* 字段类型,指向DexTypeId的索引,字段的类型 */
    u4  nameIdx;            /* 字段名,指向DexStringId的索引,字段的名称 */
};
 
struct DexMethodId {
    u2  classIdx;           /* 类的类型,指向DexTypeId的索引,方法所属的类 */
    u2  protoIdx;           /* 声明类型,指向DexProtoId的索引,方法的签名 */
    u4  nameIdx;            /* 方法名,指向DexStringId索引,方法的名称 */
};
struct DexMethodId {
    u2  classIdx;           /* 类的类型,指向DexTypeId的索引,方法所属的类 */
    u2  protoIdx;           /* 声明类型,指向DexProtoId的索引,方法的签名 */
    u4  nameIdx;            /* 方法名,指向DexStringId索引,方法的名称 */
};
 
struct DexClassDef {
    u4  classIdx;           /* 类的类型,指向DexTypeId的索引 */
    u4  accessFlags;                /* 访问标志 */
    u4  superclassIdx;      /* 父类的类型,指向DexTypeId的索引 */
    u4  interfacesOff;      /* 接口,指向DexTypeList的偏移,如果没有接口的声明和实现,值为0 */
    u4  sourceFileIdx;      /* 类所在的源文件名,指向DexStringId的索引 */
    u4  annotationsOff;     /* 注释,根据类型不同会有注解类,注解字段,注解方法,注解参数,没有注解值就是0,指向DexAnnotationsDirectoryItem的结构体 */
    u4  classDataOff;       /* 类的数据部分,指向DexClassData结构的偏移 */
    u4  staticValuesOff;    /* 类中的静态数据,指向DexEncodeArray结构的偏移 */
};
struct DexClassDef {
    u4  classIdx;           /* 类的类型,指向DexTypeId的索引 */
    u4  accessFlags;                /* 访问标志 */
    u4  superclassIdx;      /* 父类的类型,指向DexTypeId的索引 */
    u4  interfacesOff;      /* 接口,指向DexTypeList的偏移,如果没有接口的声明和实现,值为0 */
    u4  sourceFileIdx;      /* 类所在的源文件名,指向DexStringId的索引 */
    u4  annotationsOff;     /* 注释,根据类型不同会有注解类,注解字段,注解方法,注解参数,没有注解值就是0,指向DexAnnotationsDirectoryItem的结构体 */
    u4  classDataOff;       /* 类的数据部分,指向DexClassData结构的偏移 */
    u4  staticValuesOff;    /* 类中的静态数据,指向DexEncodeArray结构的偏移 */
};
 
 
/* expanded form of a class_data_item header */
struct DexClassDataHeader {
    u4 staticFieldsSize;                /* 静态字段的个数 */
    u4 instanceFieldsSize;            /* 实例字段的个数 */
    u4 directMethodsSize;                /* 直接方法的个数 */
    u4 virtualMethodsSize;            /* 虚方法的个数 */
};
 
/* expanded form of encoded_field */
struct DexField {
    u4 fieldIdx;    /* 指向DexFieldId的索引 */
    u4 accessFlags;    /* 访问标志 */
};
 
/* expanded form of encoded_method */
struct DexMethod {
    u4 methodIdx;    /* 指向DexMethodId的索引 */
    u4 accessFlags;     /* 访问标志 */
    u4 codeOff;      /* 指向DexCode结构的偏移 */
};
 
struct DexClassData {
    DexClassDataHeader header;                            /* 指定字段和方法的个数 */
    DexField*          staticFields;                /* 静态字段 */
    DexField*          instanceFields;            /* 实例字段 */
    DexMethod*         directMethods;                /* 直接方法 */
    DexMethod*         virtualMethods;            /* 虚方法 */
};
/* expanded form of a class_data_item header */
struct DexClassDataHeader {
    u4 staticFieldsSize;                /* 静态字段的个数 */
    u4 instanceFieldsSize;            /* 实例字段的个数 */
    u4 directMethodsSize;                /* 直接方法的个数 */
    u4 virtualMethodsSize;            /* 虚方法的个数 */
};
 
/* expanded form of encoded_field */
struct DexField {
    u4 fieldIdx;    /* 指向DexFieldId的索引 */
    u4 accessFlags;    /* 访问标志 */
};
 
/* expanded form of encoded_method */
struct DexMethod {
    u4 methodIdx;    /* 指向DexMethodId的索引 */
    u4 accessFlags;     /* 访问标志 */
    u4 codeOff;      /* 指向DexCode结构的偏移 */
};
 
struct DexClassData {
    DexClassDataHeader header;                            /* 指定字段和方法的个数 */
    DexField*          staticFields;                /* 静态字段 */
    DexField*          instanceFields;            /* 实例字段 */
    DexMethod*         directMethods;                /* 直接方法 */
    DexMethod*         virtualMethods;            /* 虚方法 */
};
 
struct DexCode {
    u2  registersSize;            /* 使用寄存器的个数 */
    u2  insSize;                        /* 参数的个数 */
    u2  outsSize;                        /* 调用其他方法时使用的寄存器个数 */
    u2  triesSize;                    /* try/catch语句的个数 */
    u4  debugInfoOff;       /* 指向调试信息的偏移 */
    u4  insnsSize;          /* 指令集的个数,以2字节为单位 */
    u2  insns[1];                        /* 指令集 */
    /* 2字节空间用于对齐 */
    /* followed by try_item[triesSize] DexTry结构体 */
    /* followed by uleb128 handlersSize */
    /* followed by catch_handler_item[handlersSize] DexCatchHandler结构体 */
};
struct DexCode {
    u2  registersSize;            /* 使用寄存器的个数 */
    u2  insSize;                        /* 参数的个数 */
    u2  outsSize;                        /* 调用其他方法时使用的寄存器个数 */
    u2  triesSize;                    /* try/catch语句的个数 */
    u4  debugInfoOff;       /* 指向调试信息的偏移 */
    u4  insnsSize;          /* 指令集的个数,以2字节为单位 */
    u2  insns[1];                        /* 指令集 */
    /* 2字节空间用于对齐 */
    /* followed by try_item[triesSize] DexTry结构体 */
    /* followed by uleb128 handlersSize */
    /* followed by catch_handler_item[handlersSize] DexCatchHandler结构体 */
};
 
 
 
 
 
 
 
 
 
 
struct DexMapItem {
    u2 type;              /* kDexType开头的类型 */
    u2 unused;                        /* 未使用,用于字节对齐 */
    u4 size;              /* 数据的大小 */
    u4 offset;            /* 指定类型数据的文件偏移 */
};
/*
 * Direct-mapped "map_list".
 */
struct DexMapList {
    u4  size;               /* 有多少个DexMapItem */
    DexMapItem list[1];     /* entries */
};
 
enum {
    kDexTypeHeaderItem               = 0x0000,
    kDexTypeStringIdItem             = 0x0001,
    kDexTypeTypeIdItem               = 0x0002,
    kDexTypeProtoIdItem              = 0x0003,
    kDexTypeFieldIdItem              = 0x0004,
    kDexTypeMethodIdItem             = 0x0005,
    kDexTypeClassDefItem             = 0x0006,
    kDexTypeCallSiteIdItem           = 0x0007,
    kDexTypeMethodHandleItem         = 0x0008,
    kDexTypeMapList                  = 0x1000,
    kDexTypeTypeList                 = 0x1001,
    kDexTypeAnnotationSetRefList     = 0x1002,
    kDexTypeAnnotationSetItem        = 0x1003,
    kDexTypeClassDataItem            = 0x2000,
    kDexTypeCodeItem                 = 0x2001,
    kDexTypeStringDataItem           = 0x2002,
    kDexTypeDebugInfoItem            = 0x2003,
    kDexTypeAnnotationItem           = 0x2004,
    kDexTypeEncodedArrayItem         = 0x2005,
    kDexTypeAnnotationsDirectoryItem = 0x2006,
};
struct DexMapItem {
    u2 type;              /* kDexType开头的类型 */
    u2 unused;                        /* 未使用,用于字节对齐 */
    u4 size;              /* 数据的大小 */
    u4 offset;            /* 指定类型数据的文件偏移 */
};
/*
 * Direct-mapped "map_list".
 */
struct DexMapList {
    u4  size;               /* 有多少个DexMapItem */
    DexMapItem list[1];     /* entries */
};
 
enum {
    kDexTypeHeaderItem               = 0x0000,
    kDexTypeStringIdItem             = 0x0001,
    kDexTypeTypeIdItem               = 0x0002,
    kDexTypeProtoIdItem              = 0x0003,
    kDexTypeFieldIdItem              = 0x0004,
    kDexTypeMethodIdItem             = 0x0005,
    kDexTypeClassDefItem             = 0x0006,
    kDexTypeCallSiteIdItem           = 0x0007,
    kDexTypeMethodHandleItem         = 0x0008,
    kDexTypeMapList                  = 0x1000,
    kDexTypeTypeList                 = 0x1001,
    kDexTypeAnnotationSetRefList     = 0x1002,
    kDexTypeAnnotationSetItem        = 0x1003,
    kDexTypeClassDataItem            = 0x2000,
    kDexTypeCodeItem                 = 0x2001,
    kDexTypeStringDataItem           = 0x2002,
    kDexTypeDebugInfoItem            = 0x2003,
    kDexTypeAnnotationItem           = 0x2004,
    kDexTypeEncodedArrayItem         = 0x2005,
    kDexTypeAnnotationsDirectoryItem = 0x2006,
};
 
 
 
//字节排序优化
int dexSwapAndVerify(u1* addr, size_t len)
{
    ...
    if (okay) {
        /*
         * Look for the map. Swap it and then use it to find and swap
         * everything else.
         */
        if (pHeader->mapOff != 0) {
            DexFile dexFile;
            DexMapList* pDexMap = (DexMapList*) (addr + pHeader->mapOff);
 
            okay = okay && swapMap(&state, pDexMap);
            okay = okay && swapEverythingButHeaderAndMap(&state, pDexMap);
 
            dexFileSetupBasicPointers(&dexFile, addr);
            state.pDexFile = &dexFile;
 
            okay = okay && crossVerifyEverything(&state, pDexMap);
        } else {
            ALOGE("ERROR: No map found; impossible to byte-swap and verify");
            okay = false;
        }
    }
        ...
    return !okay;       // 0 == success
}
//字节排序优化
int dexSwapAndVerify(u1* addr, size_t len)
{
    ...
    if (okay) {
        /*
         * Look for the map. Swap it and then use it to find and swap
         * everything else.
         */
        if (pHeader->mapOff != 0) {
            DexFile dexFile;
            DexMapList* pDexMap = (DexMapList*) (addr + pHeader->mapOff);
 
            okay = okay && swapMap(&state, pDexMap);
            okay = okay && swapEverythingButHeaderAndMap(&state, pDexMap);
 
            dexFileSetupBasicPointers(&dexFile, addr);
            state.pDexFile = &dexFile;
 
            okay = okay && crossVerifyEverything(&state, pDexMap);
        } else {
            ALOGE("ERROR: No map found; impossible to byte-swap and verify");
            okay = false;
        }
    }
        ...
    return !okay;       // 0 == success
}
static bool swapMap(CheckState* state, DexMapList* pMap)
{
    DexMapItem* item = pMap->list;
    u4 count;
    u4 dataItemCount = 0; // Total count of items in the data section.
    u4 dataItemsLeft = state->pHeader->dataSize; // See use below.
    u4 usedBits = 0;      // Bit set: one bit per section
    bool first = true;
    u4 lastOffset = 0;
 
    SWAP_FIELD4(pMap->size);
    count = pMap->size;
    const u4 sizeOfItem = (u4) sizeof(DexMapItem);
    CHECK_LIST_SIZE(item, count, sizeOfItem);
 
    while (count--) {
        SWAP_FIELD2(item->type);
        SWAP_FIELD2(item->unused);
        SWAP_FIELD4(item->size);
        SWAP_OFFSET4(item->offset);
 
        if (first) {
            first = false;
        } else if (lastOffset >= item->offset) {
            ALOGE("Out-of-order map item: %#x then %#x",
                    lastOffset, item->offset);
            return false;
        }
 
        if (item->offset >= state->pHeader->fileSize) {
            ALOGE("Map item after end of file: %x, size %#x",
                    item->offset, state->pHeader->fileSize);
            return false;
        }
 
        if (isDataSectionType(item->type)) {
            u4 icount = item->size;
 
            /*
             * This sanity check on the data section items ensures that
             * there are no more items than the number of bytes in
             * the data section.
             */
            if (icount > dataItemsLeft) {
                ALOGE("Unrealistically many items in the data section: "
                        "at least %d", dataItemCount + icount);
                return false;
            }
 
            dataItemsLeft -= icount;
            dataItemCount += icount;
        }
 
        u4 bit = mapTypeToBitMask(item->type);
 
        if (bit == 0) {
            return false;
        }
 
        if ((usedBits & bit) != 0) {
            ALOGE("Duplicate map section of type %#x", item->type);
            return false;
        }
 
        if (item->type == kDexTypeCallSiteIdItem) {
            state->pCallSiteIds = item;
        } else if (item->type == kDexTypeMethodHandleItem) {
            state->pMethodHandleItems = item;
        }
 
        usedBits |= bit;
        lastOffset = item->offset;
        item++;
    }
 
    if ((usedBits & mapTypeToBitMask(kDexTypeHeaderItem)) == 0) {
        ALOGE("Map is missing header entry");
        return false;
    }
 
    if ((usedBits & mapTypeToBitMask(kDexTypeMapList)) == 0) {
        ALOGE("Map is missing map_list entry");
        return false;
    }
 
    if (((usedBits & mapTypeToBitMask(kDexTypeStringIdItem)) == 0)
            && ((state->pHeader->stringIdsOff != 0)
                    || (state->pHeader->stringIdsSize != 0))) {
        ALOGE("Map is missing string_ids entry");
        return false;
    }
 
    if (((usedBits & mapTypeToBitMask(kDexTypeTypeIdItem)) == 0)
            && ((state->pHeader->typeIdsOff != 0)
                    || (state->pHeader->typeIdsSize != 0))) {
        ALOGE("Map is missing type_ids entry");
        return false;
    }
 
    if (((usedBits & mapTypeToBitMask(kDexTypeProtoIdItem)) == 0)
            && ((state->pHeader->protoIdsOff != 0)
                    || (state->pHeader->protoIdsSize != 0))) {
        ALOGE("Map is missing proto_ids entry");
        return false;
    }
 
    if (((usedBits & mapTypeToBitMask(kDexTypeFieldIdItem)) == 0)
            && ((state->pHeader->fieldIdsOff != 0)
                    || (state->pHeader->fieldIdsSize != 0))) {
        ALOGE("Map is missing field_ids entry");
        return false;
    }
 
    if (((usedBits & mapTypeToBitMask(kDexTypeMethodIdItem)) == 0)
            && ((state->pHeader->methodIdsOff != 0)
                    || (state->pHeader->methodIdsSize != 0))) {
        ALOGE("Map is missing method_ids entry");
        return false;
    }
 
    if (((usedBits & mapTypeToBitMask(kDexTypeClassDefItem)) == 0)
            && ((state->pHeader->classDefsOff != 0)
                    || (state->pHeader->classDefsSize != 0))) {
        ALOGE("Map is missing class_defs entry");
        return false;
    }
 
    state->pDataMap = dexDataMapAlloc(dataItemCount);
    if (state->pDataMap == NULL) {
        ALOGE("Unable to allocate data map (size %#x)", dataItemCount);
        return false;
    }
 
    return true;
}
static bool swapMap(CheckState* state, DexMapList* pMap)
{
    DexMapItem* item = pMap->list;
    u4 count;
    u4 dataItemCount = 0; // Total count of items in the data section.
    u4 dataItemsLeft = state->pHeader->dataSize; // See use below.
    u4 usedBits = 0;      // Bit set: one bit per section
    bool first = true;
    u4 lastOffset = 0;
 
    SWAP_FIELD4(pMap->size);
    count = pMap->size;
    const u4 sizeOfItem = (u4) sizeof(DexMapItem);
    CHECK_LIST_SIZE(item, count, sizeOfItem);
 
    while (count--) {
        SWAP_FIELD2(item->type);
        SWAP_FIELD2(item->unused);
        SWAP_FIELD4(item->size);
        SWAP_OFFSET4(item->offset);
 
        if (first) {
            first = false;
        } else if (lastOffset >= item->offset) {
            ALOGE("Out-of-order map item: %#x then %#x",
                    lastOffset, item->offset);
            return false;
        }
 
        if (item->offset >= state->pHeader->fileSize) {
            ALOGE("Map item after end of file: %x, size %#x",
                    item->offset, state->pHeader->fileSize);
            return false;
        }
 
        if (isDataSectionType(item->type)) {
            u4 icount = item->size;
 
            /*
             * This sanity check on the data section items ensures that
             * there are no more items than the number of bytes in
             * the data section.
             */
            if (icount > dataItemsLeft) {
                ALOGE("Unrealistically many items in the data section: "
                        "at least %d", dataItemCount + icount);
                return false;
            }
 
            dataItemsLeft -= icount;
            dataItemCount += icount;
        }
 
        u4 bit = mapTypeToBitMask(item->type);
 
        if (bit == 0) {
            return false;
        }
 
        if ((usedBits & bit) != 0) {
            ALOGE("Duplicate map section of type %#x", item->type);
            return false;
        }
 
        if (item->type == kDexTypeCallSiteIdItem) {
            state->pCallSiteIds = item;
        } else if (item->type == kDexTypeMethodHandleItem) {
            state->pMethodHandleItems = item;
        }
 
        usedBits |= bit;
        lastOffset = item->offset;
        item++;
    }
 
    if ((usedBits & mapTypeToBitMask(kDexTypeHeaderItem)) == 0) {
        ALOGE("Map is missing header entry");
        return false;
    }
 
    if ((usedBits & mapTypeToBitMask(kDexTypeMapList)) == 0) {
        ALOGE("Map is missing map_list entry");
        return false;
    }
 
    if (((usedBits & mapTypeToBitMask(kDexTypeStringIdItem)) == 0)
            && ((state->pHeader->stringIdsOff != 0)
                    || (state->pHeader->stringIdsSize != 0))) {
        ALOGE("Map is missing string_ids entry");
        return false;
    }
 
    if (((usedBits & mapTypeToBitMask(kDexTypeTypeIdItem)) == 0)
            && ((state->pHeader->typeIdsOff != 0)
                    || (state->pHeader->typeIdsSize != 0))) {
        ALOGE("Map is missing type_ids entry");
        return false;
    }
 
    if (((usedBits & mapTypeToBitMask(kDexTypeProtoIdItem)) == 0)
            && ((state->pHeader->protoIdsOff != 0)
                    || (state->pHeader->protoIdsSize != 0))) {
        ALOGE("Map is missing proto_ids entry");
        return false;
    }
 
    if (((usedBits & mapTypeToBitMask(kDexTypeFieldIdItem)) == 0)
            && ((state->pHeader->fieldIdsOff != 0)
                    || (state->pHeader->fieldIdsSize != 0))) {
        ALOGE("Map is missing field_ids entry");
        return false;
    }
 
    if (((usedBits & mapTypeToBitMask(kDexTypeMethodIdItem)) == 0)
            && ((state->pHeader->methodIdsOff != 0)
                    || (state->pHeader->methodIdsSize != 0))) {
        ALOGE("Map is missing method_ids entry");
        return false;
    }
 
    if (((usedBits & mapTypeToBitMask(kDexTypeClassDefItem)) == 0)
            && ((state->pHeader->classDefsOff != 0)
                    || (state->pHeader->classDefsSize != 0))) {
        ALOGE("Map is missing class_defs entry");
        return false;
    }
 
    state->pDataMap = dexDataMapAlloc(dataItemCount);
    if (state->pDataMap == NULL) {
        ALOGE("Unable to allocate data map (size %#x)", dataItemCount);
        return false;
    }
 
    return true;
}
 
{name:ooxx,method_idx:1830,offset:180516,code_item_len:24,ins:AQABAAEAAAB+oAMABAAAAHAQwAsAAA4A};
{name:ooxx,method_idx:1830,offset:180516,code_item_len:24,ins:AQABAAEAAAB+oAMABAAAAHAQwAsAAA4A};
 
 
 
 
 
var base64ptr = funcBase64_encode(ptr(codeitemstartaddr), codeitemlength, ptr(base64lengthptr));
var b64content = ptr(base64ptr).readCString(base64lengthptr.readInt());
funcFreeptr(ptr(base64ptr));
var content = "{name:ooxx,method_idx:" + dex_method_index_ + ",offset:" + dex_code_item_offset_ + ",code_item_len:" + codeitemlength + ",ins:" + b64content + "};";
var base64ptr = funcBase64_encode(ptr(codeitemstartaddr), codeitemlength, ptr(base64lengthptr));
var b64content = ptr(base64ptr).readCString(base64lengthptr.readInt());
funcFreeptr(ptr(base64ptr));
var content = "{name:ooxx,method_idx:" + dex_method_index_ + ",offset:" + dex_code_item_offset_ + ",code_item_len:" + codeitemlength + ",ins:" + b64content + "};";
 
def main():
    #加载dex文件
    dex = dex_parser(filename)
if __name__ == "__main__":
    #获取到参数filename和insfilename
    init()
    methodTable.clear()
    #加载.bin文件的内容,也就是insfilename设置的文件,给methodTable填充上值。每项的数据是:方法名称,方法id,方法偏移,方法大小,指令集
    parseinsfile()
    print "methodTable length:" + str(len(methodTable))
    #开始处理
    main()
def main():
    #加载dex文件
    dex = dex_parser(filename)
if __name__ == "__main__":
    #获取到参数filename和insfilename
    init()
    methodTable.clear()
    #加载.bin文件的内容,也就是insfilename设置的文件,给methodTable填充上值。每项的数据是:方法名称,方法id,方法偏移,方法大小,指令集
    parseinsfile()
    print "methodTable length:" + str(len(methodTable))
    #开始处理
    main()
def parseinsfile():
    global insfilename
    insfile=open(insfilename)
    content=insfile.read()
    insfile.close()
    #;{name:artMethod::dumpmethod DexFile_dumpDexFile'
    # dexfile name:classes.dex--
    # insfilepath:/data/data/com.wlqq/10668484_ins.bin--
    # code_item_len:40,
    # code_item_len:40,
    # ins:AgABAAIAAABLnY4ADAAAACIAFwNwEPoOAABuIP4OEAAMAR8BFwMRAQ==};
    insarray=re.findall(r"{name:(.*?),method_idx:(.*?),offset:(.*?),code_item_len:(.*?),ins:(.*?)}",content) #(.*?)最短匹配
    #按照我们前面看到的格式进行匹配数据并遍历
    for eachins in insarray:
      #这里其实是固定的ooxx
      methodname=eachins[0].replace(" ","")
      number=(int)(eachins[1])
      offset=(int)(eachins[2])
      inssize=int(eachins[3])
      ins=eachins[4]
      tempmethod=CodeItem(number,methodname,inssize,ins)
      methodTable[number]=tempmethod #添加method
def parseinsfile():
    global insfilename
    insfile=open(insfilename)
    content=insfile.read()
    insfile.close()
    #;{name:artMethod::dumpmethod DexFile_dumpDexFile'
    # dexfile name:classes.dex--
    # insfilepath:/data/data/com.wlqq/10668484_ins.bin--
    # code_item_len:40,
    # code_item_len:40,
    # ins:AgABAAIAAABLnY4ADAAAACIAFwNwEPoOAABuIP4OEAAMAR8BFwMRAQ==};
    insarray=re.findall(r"{name:(.*?),method_idx:(.*?),offset:(.*?),code_item_len:(.*?),ins:(.*?)}",content) #(.*?)最短匹配
    #按照我们前面看到的格式进行匹配数据并遍历
    for eachins in insarray:
      #这里其实是固定的ooxx
      methodname=eachins[0].replace(" ","")
      number=(int)(eachins[1])
      offset=(int)(eachins[2])
      inssize=int(eachins[3])
      ins=eachins[4]
      tempmethod=CodeItem(number,methodname,inssize,ins)
      methodTable[number]=tempmethod #添加method
 
class dex_parser:
 
    def __init__(self,filename):
        #dex的标志
        global DEX_MAGIC
        #odex的标志
        global DEX_OPT_MAGIC
        self.m_javaobject_id = 0
        #dex的文件路径
        self.m_filename = filename
        self.m_fd = open(filename,"rb")
        self.m_content = self.m_fd.read()
        self.m_fd.close()
        self.m_dex_optheader = None
        self.m_class_name_id = {}
        self.string_table = []
        #如果发现是odex文件,则填充opt_header,否则只填充dex_header
        if self.m_content[0:4] == DEX_OPT_MAGIC:
            self.init_optheader(self.m_content)
            self.init_header(self.m_content,0x40)
        elif self.m_content[0:4] == DEX_MAGIC:
            self.init_header(self.m_content,0)
        #上面填充dex_header的时候取到的string_ids的偏移位置和大小
        bOffset = self.m_stringIdsOff
        if self.m_stringIdsSize > 0:
            #遍历字符串列表
            for i in xrange(0,self.m_stringIdsSize):
                #这里是取出每个字符串的偏移地址
                offset, = struct.unpack_from("I",self.m_content,bOffset + i * 4)
                #如果是第一个则直接存放到start,然后处理下一次
                if i == 0:
                    start = offset
                else:
                    #取出上一个偏移的字符串的偏移地址,这里由于存储格式是uleb128的。要转换成真正的偏移地址。
                    skip, length = get_uleb128(self.m_content[start:start+5])
                    #上面还原出了真实的偏移,这里取字符串的地址,保存起来
                    self.string_table.append(self.m_content[start+skip:offset-1])
                    start = offset
            #处理最后的一条
            for i in xrange(start,len(self.m_content)):
                if self.m_content[i]==chr(0):
                    self.string_table.append(self.m_content[start+1:i])
                    break
        #遍历classDef。填充m_class_name_id
        for i in xrange(0,self.m_classDefSize):
            str1 = self.getclassname(i)
            self.m_class_name_id[str1] = i
        #遍历classDef,填充classdef相关的属性,并且打印,合并.bin的内容是在print中进行的。
        for i in xrange(0,self.m_classDefSize):
            str1 = self.getclassname(i)
            dex_class(self,i).printf(self)
            pass
class dex_parser:
 
    def __init__(self,filename):
        #dex的标志
        global DEX_MAGIC
        #odex的标志
        global DEX_OPT_MAGIC
        self.m_javaobject_id = 0
        #dex的文件路径
        self.m_filename = filename
        self.m_fd = open(filename,"rb")
        self.m_content = self.m_fd.read()
        self.m_fd.close()
        self.m_dex_optheader = None
        self.m_class_name_id = {}
        self.string_table = []
        #如果发现是odex文件,则填充opt_header,否则只填充dex_header
        if self.m_content[0:4] == DEX_OPT_MAGIC:
            self.init_optheader(self.m_content)
            self.init_header(self.m_content,0x40)
        elif self.m_content[0:4] == DEX_MAGIC:
            self.init_header(self.m_content,0)
        #上面填充dex_header的时候取到的string_ids的偏移位置和大小
        bOffset = self.m_stringIdsOff
        if self.m_stringIdsSize > 0:
            #遍历字符串列表
            for i in xrange(0,self.m_stringIdsSize):
                #这里是取出每个字符串的偏移地址
                offset, = struct.unpack_from("I",self.m_content,bOffset + i * 4)
                #如果是第一个则直接存放到start,然后处理下一次
                if i == 0:
                    start = offset
                else:
                    #取出上一个偏移的字符串的偏移地址,这里由于存储格式是uleb128的。要转换成真正的偏移地址。
                    skip, length = get_uleb128(self.m_content[start:start+5])
                    #上面还原出了真实的偏移,这里取字符串的地址,保存起来
                    self.string_table.append(self.m_content[start+skip:offset-1])
                    start = offset
            #处理最后的一条
            for i in xrange(start,len(self.m_content)):
                if self.m_content[i]==chr(0):
                    self.string_table.append(self.m_content[start+1:i])
                    break
        #遍历classDef。填充m_class_name_id
        for i in xrange(0,self.m_classDefSize):
            str1 = self.getclassname(i)
            self.m_class_name_id[str1] = i
        #遍历classDef,填充classdef相关的属性,并且打印,合并.bin的内容是在print中进行的。
        for i in xrange(0,self.m_classDefSize):
            str1 = self.getclassname(i)
            dex_class(self,i).printf(self)
            pass
 
 
def varint_encode(number):
    buf = b''
    while True:
        towrite = number & 0x7f
        number >>= 7
        if number:
            buf += struct.pack("B",(towrite | 0x80))
        else:
            buf +=  struct.pack("B",towrite)
            break
    return buf
def varint_decode(buff):
    shift = 0
    result = 0
    idx=0
    while True:
        if idx>len(buff):
            return ""
        i = buff[idx]
        idx+=1
        result |= (i & 0x7f) << shift
        shift += 7
        if not (i & 0x80):
            break
    return result
def varint_encode(number):
    buf = b''
    while True:
        towrite = number & 0x7f
        number >>= 7
        if number:
            buf += struct.pack("B",(towrite | 0x80))
        else:
            buf +=  struct.pack("B",towrite)
            break
    return buf
def varint_decode(buff):
    shift = 0
    result = 0
    idx=0
    while True:
        if idx>len(buff):
            return ""
        i = buff[idx]
        idx+=1
        result |= (i & 0x7f) << shift
        shift += 7
        if not (i & 0x80):
            break
    return result
 
class dex_class:
    def __init__(self,dex_object,classid):
        if classid >= dex_object.m_classDefSize:
            return ""
        offset = dex_object.m_classDefOffset + classid * struct.calcsize("8I")
        self.offset = offset
        format = "I"
        self.thisClass,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.modifiers,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.superClass,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.interfacesOff,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.sourceFileIdx,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.annotationsOff,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.classDataOff,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.staticValuesOff,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.index = classid
        self.interfacesSize = 0
        if self.interfacesOff != 0:
            self.interfacesSize, = struct.unpack_from("I",dex_object.m_content,self.interfacesOff)
        if self.classDataOff != 0:
            offset = self.classDataOff
            count,self.numStaticFields = get_uleb128(dex_object.m_content[offset:])
            offset += count
            count,self.numInstanceFields = get_uleb128(dex_object.m_content[offset:])
            offset += count
            count,self.numDirectMethods = get_uleb128(dex_object.m_content[offset:])
            offset += count
            count,self.numVirtualMethods = get_uleb128(dex_object.m_content[offset:])   
        else:
            self.numStaticFields = 0
            self.numInstanceFields = 0
            self.numDirectMethods = 0
            self.numVirtualMethods = 0
class dex_class:
    def __init__(self,dex_object,classid):
        if classid >= dex_object.m_classDefSize:
            return ""
        offset = dex_object.m_classDefOffset + classid * struct.calcsize("8I")
        self.offset = offset
        format = "I"
        self.thisClass,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.modifiers,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.superClass,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.interfacesOff,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.sourceFileIdx,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.annotationsOff,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.classDataOff,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.staticValuesOff,=struct.unpack_from(format,dex_object.m_content,offset)
        offset += struct.calcsize(format)
        self.index = classid
        self.interfacesSize = 0
        if self.interfacesOff != 0:
            self.interfacesSize, = struct.unpack_from("I",dex_object.m_content,self.interfacesOff)
        if self.classDataOff != 0:
            offset = self.classDataOff
            count,self.numStaticFields = get_uleb128(dex_object.m_content[offset:])
            offset += count
            count,self.numInstanceFields = get_uleb128(dex_object.m_content[offset:])
            offset += count

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2021-7-16 09:22 被misskings编辑 ,原因: 修改细节
收藏
免费 2
支持
分享
最新回复 (10)
雪    币: 334
活跃值: (392)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
mark
2021-7-15 01:01
0
雪    币: 6573
活跃值: (3873)
能力值: (RANK:200 )
在线值:
发帖
回帖
粉丝
3
Mark
2021-7-15 07:17
0
雪    币: 26
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
你好,king,你的个人博客上可以互动或者留言吗?
希望和你认识一下,我是做腾讯的安全招聘的;能不能留下你的邮箱我给你发邮件说明详细情况
2021-7-15 17:12
0
雪    币: 1490
活跃值: (9913)
能力值: ( LV9,RANK:240 )
在线值:
发帖
回帖
粉丝
5
wx_Ella 你好,king,你的个人博客上可以互动或者留言吗? 希望和你认识一下,我是做腾讯的安全招聘的;能不能留下你的邮箱我给你发邮件说明详细情况
可以留言互动的。额,但是我基本不看。当做笔记用的。king910827@163.com。可以发邮件联系我
2021-7-15 17:27
0
雪    币: 48
活跃值: (3424)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
Mark
2021-7-16 09:44
0
雪    币: 1230
活跃值: (1765)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
可以...最近刚好研究这个
2021-8-5 09:32
0
雪    币: 116
活跃值: (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
支持一下
2021-8-5 20:21
0
雪    币: 576
活跃值: (2035)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
mark
2021-8-5 22:37
0
雪    币: 163
活跃值: (1623)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
10
还可以把bin数据,直接添加到dex尾部,然后修改相关偏移吧
2021-8-6 11:34
0
雪    币: 159
活跃值: (695)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
请教下,偏移型dex修复转dex有更新吗?
2021-10-12 01:38
0
游客
登录 | 注册 方可回帖
返回
//