我正在探索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,但我认为这不应该有所不同吗?
我不确定这里还有什么问题。
答案 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);
}