ULEB128和class_def_item的Android Dex文件格式问题

时间:2014-01-21 01:36:51

标签: android dalvik dex

我正在探索Android文件格式,我遇到了一些看起来不正确的东西,但文档中没有提到。我有一个示例应用程序,我正在追踪只是为了拉出所有字段等。

我开始追踪格式,一切都很好,直到我进入class_data_item。我一直在寻找direct_methods声明,但开头的大小字段似乎没有任何意义。

我已经确认我已经开始使用正确的class_def_item(即名称和其他所有内容都是正确的)但是当我为class_data_item转到RVA(应该偏移0x18)时,我得到的字节如下(道歉)格式化):

0D 00 0B 00 22 19 01 19 01 19 01 19 01 19 01 19 01 19 01 19 01 19 01 19 01 19 01 19 01 1A 94 03 88 80 04 DC E1 08 01 82 80 04 B4

规范说前四个字段应该是字段和方法的大小,但无论我如何解释这些字节,它都是无效的。 0xb000d,0x19011922等太大而无法在上下文中理解。我在dex文件的数据部分。

我还看到了一个实例(在string_id部分中包含字符串),其中标记为leb128的项目只是一个字节。我知道leb应该是可变长度的,但无论我怎么解释它看起来都没有任何意义 - 它要么指向某个不是encoded_method的地方,要么指向乱码。此外,重复的01 19值看起来不正确。

现在我正在跟踪的示例类/方法是一个Android组件 - android / support / v4 / accessibilityservice / AccessibilityServiceInfoCompat,但我认为这不应该有所不同吗?

我不确定这里还有什么问题。

2 个答案:

答案 0 :(得分:2)

这是您提供的二进制代码段的注释转储,假设它是class_data_item

000000: 0d                 |static_fields_size = 13
000001: 00                 |instance_fields_size = 0
000002: 0b                 |direct_methods_size = 11
000003: 00                 |virtual_methods_size = 0
                           |static_fields:
                           |  static_field[0]
000004: 22                 |    field_idx_diff = 34
000005: 19                 |    access_flags = 0x19
                           |  static_field[1]
000006: 01                 |    field_idx_diff = 1
000007: 19                 |    access_flags = 0x19
                           |  static_field[2]
000008: 01                 |    field_idx_diff = 1
000009: 19                 |    access_flags = 0x19
                           |  static_field[3]
00000a: 01                 |    field_idx_diff = 1
00000b: 19                 |    access_flags = 0x19
                           |  static_field[4]
00000c: 01                 |    field_idx_diff = 1
00000d: 19                 |    access_flags = 0x19
                           |  static_field[5]
00000e: 01                 |    field_idx_diff = 1
00000f: 19                 |    access_flags = 0x19
                           |  static_field[6]
000010: 01                 |    field_idx_diff = 1
000011: 19                 |    access_flags = 0x19
                           |  static_field[7]
000012: 01                 |    field_idx_diff = 1
000013: 19                 |    access_flags = 0x19
                           |  static_field[8]
000014: 01                 |    field_idx_diff = 1
000015: 19                 |    access_flags = 0x19
                           |  static_field[9]
000016: 01                 |    field_idx_diff = 1
000017: 19                 |    access_flags = 0x19
                           |  static_field[10]
000018: 01                 |    field_idx_diff = 1
000019: 19                 |    access_flags = 0x19
                           |  static_field[11]
00001a: 01                 |    field_idx_diff = 1
00001b: 19                 |    access_flags = 0x19
                           |  static_field[12]
00001c: 01                 |    field_idx_diff = 1
00001d: 1a                 |    access_flags = 0x1a
                           |direct_methods:
                           |  direct_method[0]
00001e: 9403               |    method_idx_diff = 404
000020: 8880 04            |    access_flags = 0x10008: static|constructor
000023: dce1 08            |    code_off = code_item[0x230dc]
                           |  direct_method[1]
000026: 01                 |    method_idx_diff = 1
000027: 8280 04            |    access_flags = 0x10002: private|constructor
00002a: b4                 |

我认为你所依赖的那部分是uleb128的编码,这在dex-format文档中有详细描述。特别要注意,最重要的位是在uleb128的每个字节中设置的,除了最后一个。

例如,查看您提供的二进制数据的第一个字节 - 0x0d。你知道这是uleb128的开始。您还知道这是uleb128的 last 字节,因为它的高位未设置。

重复的01 19值是完美的。正如您在注释转储中看到的,0x19是每个字段的访问标志,0x01表示字段ID与之前的差异。因此第一个字段的字段ID是0x22,第二个字段的字段ID是0x22 + 1 = 0x23,第三个字段的字段ID是0x23 + 1 = 0x24,依此类推。

如果您想要澄清dex文件中的某个结构,我建议使用baksmali's带注释的转储功能。您可以将它与-D选项一起使用。例如,

baksmali -D blah.dump blah.dex

您将获得上面给出的那种带注释的转储,但是对于整个dex文件。

答案 1 :(得分:0)

查看Dex.java,Android在内部用来解析dex文件的类。

对于您的具体问题,这就是它读取类数据的方法:

    private ClassData readClassData() {
        int staticFieldsSize = readUleb128();
        int instanceFieldsSize = readUleb128();
        int directMethodsSize = readUleb128();
        int virtualMethodsSize = readUleb128();
        ClassData.Field[] staticFields = readFields(staticFieldsSize);
        ClassData.Field[] instanceFields = readFields(instanceFieldsSize);
        ClassData.Method[] directMethods = readMethods(directMethodsSize);
        ClassData.Method[] virtualMethods = readMethods(virtualMethodsSize);
        return new ClassData(staticFields, instanceFields, directMethods, virtualMethods);
    }