In the previous article, the analysis of proto_ids was introduced , so the next step is to learn field_ids
the analysis.
1. field_ids structure
FieldId
// Raw field_id_item.
struct FieldId {
dex::TypeIndex class_idx_; // index into type_ids_ array for defining class
dex::TypeIndex type_idx_; // index into type_ids_ array for field type
dex::StringIndex name_idx_; // index into string_ids_ array for field name
private:
DISALLOW_COPY_AND_ASSIGN(FieldId);
};
StringIndex
class StringIndex {
public:
uint32_t index_;
....
....
};
TypeIndex
class TypeIndex {
public:
uint16_t index_;
....
....
};
The following points can be seen from fieldId
the structure:
dex::TypeIndex class_idx_
: Unsignedint
type, occupying2
bytes, type index list索引/下标
, indicating the class where the field is locateddex::TypeIndex type_idx_
: Unsignedint
type, occupying2
bytes, type index list索引/下标
, indicating the type of the fielddex::StringIndex name_idx_
: Unsignedint
type, occupying4
bytes, string index list索引/下标
, representing the name (identifier) of the field
2. Analysis of 010Editor
As shown in the picture, observe carefully
3. field_ids parsing
java
language analysisfield_ids
/**
* 解析FieldIds
* @param raf
* @return
*/
private static List<FieldId> toParseDexFieldIds(RandomAccessFile raf) {
try {
List<FieldId> fieldIdList = new ArrayList<>();
//获取字段索引列表的文件偏移量
int field_ids_off = mDexHeader.getField_ids_off();
//获取字段索引列表大小
int field_ids_size = mDexHeader.getField_ids_size();
//偏移到字段索引列表位置
raf.seek(field_ids_off);
for (int i = 0; i < field_ids_size; i++) {
//获取 这个字段所在的类的类名,类名idx在类型索引列表中
int class_idx = NumConversion.byteToInt(readData(raf, 2), false);
//获取 字段的类型,字段类型idx在类型索引列表中
int type_idx = NumConversion.byteToInt(readData(raf, 2), false);
//获取 字段的名字,字段的名字idx在字符串索引类中
int field_name_idx = NumConversion.byteToInt(readData(raf, 4), false);
//获取数据
TypeId class_type_id = mTypeIds.get(class_idx);
TypeId field_type_id = mTypeIds.get(type_idx);
StringId class_type_string_id = mStringIds.get(class_type_id.getTypeDescriptorIdx());
StringId field_type_string_id = mStringIds.get(field_type_id.getTypeDescriptorIdx());
StringId field_name_string_id = mStringIds.get(field_name_idx);
String class_type_string = new String(class_type_string_id.getData());
String field_type_string = new String(field_type_string_id.getData());
String field_name_string = new String(field_name_string_id.getData());
FieldId fieldId = new FieldId();
fieldId.setClass_idx(class_idx);
fieldId.setType_idx(type_idx);
fieldId.setName_idx(field_name_idx);
fieldIdList.add(fieldId);
System.out.println("在 " + class_type_string + "类中,存在 " + field_type_string + " " + field_name_string);
}
return fieldIdList;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static byte[] readData(RandomAccessFile raf,int limit) {
byte[] buff = new byte[limit];
try {
raf.read(buff);
} catch (IOException e) {
e.printStackTrace();
}
return buff;
}
实体类FieldId
public class FieldId {
private int class_idx;
private int type_idx;
private int name_idx;
public int getClass_idx() {
return class_idx;
}
public void setClass_idx(int class_idx) {
this.class_idx = class_idx;
}
public int getType_idx() {
return type_idx;
}
public void setType_idx(int type_idx) {
this.type_idx = type_idx;
}
public int getName_idx() {
return name_idx;
}
public void setName_idx(int name_idx) {
this.name_idx = name_idx;
}
}
工具类NumConversion
public class NumConversion {
public static int byteToInt(byte[] bytes,boolean isBigEndian) {
if (bytes.length <=0 || bytes.length > 4) return -1;
int result = 0;
for (int i=0;i<bytes.length;i++) {
int b ;
if(isBigEndian){
b = (bytes[i] & 0xFF) << (8*(bytes.length-1-i));
}else {
b = (bytes[i] & 0xFF) << (8*i);
}
result = result | b;
}
return result;
}
}
asjhan for Android reverse