DEX文件解析 - method_ids解析
在上一篇中介绍了field_ids的解析,那么接下来就要学习method_ids
的解析。
1. method_ids结构
在android的aosp源码中,method_ids的结构如下:
aosp源码位置:art/libdexfile/dex/dex_file.h
// Raw method_id_item.
struct MethodId {
dex::TypeIndex class_idx_; // index into type_ids_ array for defining class
uint16_t proto_idx_; // index into proto_ids_ array for method prototype
dex::StringIndex name_idx_; // index into string_ids_ array for method name
private:
DISALLOW_COPY_AND_ASSIGN(MethodId);
};
StringIndex
class StringIndex {
public:
uint32_t index_;
....
....
};
TypeIndex
class TypeIndex {
public:
uint16_t index_;
....
....
};
从method
的结构可以看出以下几点:
dex::TypeIndex class_idx_
: 无符号int
类型,占2
个字节。类型索引列表的索引/下标
,表示的是方法所在的类
uint16_t proto_idx_
:无符号int
类型,占2
个字节。原型索引列表的索引/下标
,表示的是方法的原型(签名)
dex::StringIndex name_idx_
:无符号int
类型,占4
个字节。字符串索引列表的索引/下标
,表示的是方法的名称
2.010Editor解析
3.method_ids解析
/**
* 解析MethodIds
* @param raf
* @return
*/
private static List<MethodId> toParseDexMethodIds(RandomAccessFile raf) {
try {
List<MethodId> methodIdList = new ArrayList<>();
//获取到方法索引列表的文件偏移量
int method_ids_off = mDexHeader.getMethod_ids_off();
//获取到方法索引列表的大小
int method_ids_size = mDexHeader.getMethod_ids_size();
//偏移到方法索引列表位置
raf.seek(method_ids_off);
for (int i = 0; i < method_ids_size; i++) {
//获取 这个字段所在的类的类名,类名idx在类型索引列表中
int class_idx = NumConversion.byteToInt(readData(raf, 2), false);
//获取 这个字段的原型(方法签名),原型idx在原型索引列表中
int proto_idx = NumConversion.byteToInt(readData(raf,2),false);
//获取 这个字段的方法名称,方法名称idx在字符串索引列表中
int name_idx = NumConversion.byteToInt(readData(raf,4),false);
//打印数据
//获取方法名称
StringId name_string_id = mStringIds.get(name_idx);
String name_string = new String(name_string_id.getData());
//获取类
TypeId class_type_id = mTypeIds.get(class_idx);
StringId class_type_string_id = mStringIds.get(class_type_id.getTypeDescriptorIdx());
String class_type_string = new String(class_type_string_id.getData());
//获取返回值类型
ProtoId proto_id = mProtyIds.get(proto_idx);
TypeId return_type_id = mTypeIds.get(proto_id.getReturnIdx());
StringId return_type_string_id = mStringIds.get(return_type_id.getTypeDescriptorIdx());
String return_type_string = new String(return_type_string_id.getData());
//获取方法参数列表
StringBuilder sb = new StringBuilder("(");
for (int j=0;j<proto_id.getParameter_size();j++) {
int parame_idx = proto_id.getParameterIdxs()[j];
TypeId parame_type_id = mTypeIds.get(parame_idx);
StringId parame_string_id = mStringIds.get(parame_type_id.getTypeDescriptorIdx());
sb.append(new String(parame_string_id.getData()));
if (j == proto_id.getParameter_size()-1) {
sb.append(")");
}else if (proto_id.getParameter_size() != 1) {
sb.append(", ");
}
}
if (proto_id.getParameter_size() == 0) sb.append(")");
//创建实体类
MethodId methodId = new MethodId();
methodId.setClass_idx(class_idx);
methodId.setProto_idx(proto_idx);
methodId.setName_idx(name_idx);
methodIdList.add(methodId);
System.out.println(i+" 在 " + class_type_string + "类中, 方法:" +return_type_string+" "+name_string+sb.toString());
}
return methodIdList;
}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;
}
实体类MethodId
public class MethodId {
private int class_idx;
private int proto_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 getProto_idx() {
return proto_idx;
}
public void setProto_idx(int proto_idx) {
this.proto_idx = proto_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