在上一篇中介绍了type_ids的解析,那么接下来就要学习proto_ids 的解析。
1. proto_ids结构
在android 的aosp 源码中,proto_ids 的结构如下: aosp 源码位置:art/libdexfile/dex/dex_file.h
ProtoId
struct ProtoId {
dex::StringIndex shorty_idx_;
dex::TypeIndex return_type_idx_;
uint16_t pad_;
uint32_t parameters_off_;
private:
DISALLOW_COPY_AND_ASSIGN(ProtoId);
};
StringIndex
class StringIndex {
public:
uint32_t index_;
....
....
};
TypeIndex
class TypeIndex {
public:
uint16_t index_;
....
....
};
从protoId 的结构可以看出以下几点:
dex::StringIndex shorty_idx_ : 无符号int 类型,占4 个字节。字符串索引列表的索引/下标 ,表示的是一个简短描述符 dex::TypeIndex return_type_idx_ :无符号int 类型,占2 个字节。类型索引列表的索引/下标 ,表示的是返回值类型 uint16_t pad_ :无符号int 类型,占2 个字节。用于填充,无实际意义,默认为0uint32_t parameters_off_ :无符号int 类型,占4 个字节。参数列表在dex文件中偏移量。指向一个参数列表。
分析方法参数列表的文件偏移量(uint32_t parameters_off_) 对应的方法参数列表结构
- 通过
GetProtoParameters 方法获取到方法的参数列表
const TypeList* GetProtoParameters(const ProtoId& proto_id) const {
return DataPointer<TypeList>(proto_id.parameters_off_);
}
- 在
TypeList 结构中,可以发现其结构为: uint32_t size_ :无符号int 类型,占4 个字节。表示的是参数列表的大小(参数的个数) TypeItem list_[1] :参数列表, TypeItem 类型内部存储着TypeIndex ,而TypeIndex 有存储着uint16_t index_ ,所以TypeItem 类型占2 个字节。每2 个字节表示1 个参数
class TypeList {
public:
uint32_t Size() const {
return size_;
}
const TypeItem& GetTypeItem(uint32_t idx) const {
DCHECK_LT(idx, this->size_);
return this->list_[idx];
}
......
......
private:
uint32_t size_;
TypeItem list_[1];
DISALLOW_COPY_AND_ASSIGN(TypeList);
};
2. 010Editor解析
如图,仔细观察
3. proto_ids解析
java 语言解析proto_ids
private static List<ProtoId> toParseDexProtoIds(RandomAccessFile raf) {
try {
List<ProtoId> protoIdList = new ArrayList<>();
int proto_ids_off = mDexHeader.getProto_ids_off();
int proto_ids_size = mDexHeader.getProto_ids_size();
raf.seek(proto_ids_off);
for (int i=0;i<proto_ids_size;i++) {
int shorty_idx = NumConversion.byteToInt(readData(raf, 4),false);
int return_idx = NumConversion.byteToInt(readData(raf, 4),false);
int parameter_off = NumConversion.byteToInt(readData(raf,4),false);
if(parameter_off > 0) {
long curOff = raf.getFilePointer();
raf.seek(parameter_off);
int parameter_size = NumConversion.byteToInt(readData(raf,4),false);
int[] parameterIds = new int[parameter_size];
for (int j=0;j<parameterIds.length;j++) {
int parameter_id = NumConversion.byteToInt(readData(raf,2),false);
parameterIds[j] = parameter_id;
}
StringId shortyStringId = mStringIds.get(shorty_idx);
String shortyData = new String(shortyStringId.getData());
TypeId typeId = mTypeIds.get(return_idx);
StringId stringId = mStringIds.get(typeId.getTypeDescriptorIdx());
String returnData = new String(stringId.getData());
StringBuilder sb = new StringBuilder("(");
for (int j=0;j<parameterIds.length;j++) {
int parameter_idx = parameterIds[j];
TypeId typeId1 = mTypeIds.get(parameter_idx);
StringId paramterStringId = mStringIds.get(typeId1.getTypeDescriptorIdx());
String paramterData = new String(paramterStringId.getData());
sb.append(paramterData);
if (j == parameterIds.length-1) {
sb.append(")");
}else if(parameterIds.length != 1){
sb.append(", ");
}
}
ProtoId protoId = new ProtoId();
protoId.setShortyIdx(shorty_idx);
protoId.setReturnIdx(return_idx);
protoId.setParameterOff(parameter_off);
protoId.setParameter_size(parameter_size);
protoId.setParameterIdxs(parameterIds);
protoIdList.add(protoId);
System.out.println("索引:"+i+" shorty:"+shortyData+" -> "+returnData+" "+sb.toString());
raf.seek(curOff);
}else {
StringId shortyStringId = mStringIds.get(shorty_idx);
String shortyData = new String(shortyStringId.getData());
TypeId typeId = mTypeIds.get(return_idx);
StringId stringId = mStringIds.get(typeId.getTypeDescriptorIdx());
String returnData = new String(stringId.getData());
ProtoId protoId = new ProtoId();
protoId.setShortyIdx(shorty_idx);
protoId.setReturnIdx(return_idx);
protoId.setParameterOff(parameter_off);
protoIdList.add(protoId);
System.out.println("索引:"+i+" shorty:"+shortyData+" -> "+returnData+" ()");
}
}
return protoIdList;
}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;
}
实体类ProtoId
public class ProtoId {
private int shortyIdx;;
private int returnIdx;
private int parameterOff;
private int parameter_size;
private int[] parameterIdxs;
}
工具类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
|