当前位置:网站首页>DEX文件解析 - method_ids解析
DEX文件解析 - method_ids解析
2022-06-30 19:52:00 【asjhan】
在上一篇中介绍了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
边栏推荐
- 十分之坑,tar命令解压文件的时候竟然不能解析英文括号“()”
- 线下门店为什么要做新零售?
- Why must we move from Devops to bizdevops?
- PHP文件上传小结(乱码,移动失败,权限,显示图片)
- Halcon知识:盘点一下计量对象【1】
- 6-1漏洞利用-FTP漏洞利用
- 启动PHP报错ERROR: [pool www] cannot get uid for user ‘@[email protected]’
- 4.3-inch touch screen 12 channel control port programmable network central control supports mutual backup of 5 central control hosts
- arthas调试 确定问题工具包
- 如何做好测试用例设计
猜你喜欢

CADD课程学习(1)-- 药物设计基础知识

25:第三章:开发通行证服务:8:【注册/登录】接口:接收并校验“手机号和验证码”参数;(重点需要知道【利用redis来暂存数据,获取数据的】的应用场景)(使用到了【@Valid注解】参数校验)

S7-1500 PLC之间进行TCP通信的具体方法和步骤详解(图文)

Character class of regular series

【1175. 质数排列】

昨晚 Spark Summit 重要功能发布全在这里(附超清视频)

Halcon知识:盘点一下计量对象【1】

1. 爬虫之Beautifulsoup解析库&在线解析图片验证码

Why must we move from Devops to bizdevops?

新出生的机器狗,打滚1小时后自己掌握走路,吴恩达开山大弟子最新成果
随机推荐
杰理之触摸按键识别流程【篇】
杰理之检测灵敏度级别确定【篇】
十分之坑,tar命令解压文件的时候竟然不能解析英文括号“()”
一文读懂目标检测:R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD「建议收藏」
Heartbeat 与DRBD 配置过程
QQmlApplicationEngine failed to load component qrc:/main.qml:-1 No such file or directory
企业中台规划和IT架构微服务转型
dataloader 源码_DataLoader
Solution to rollback of MySQL database by mistake deletion
Inventory the six second level capabilities of Huawei cloud gaussdb (for redis)
Perl转换文件的编码类型
neo4j load csv 配置和使用
杰理之关于长按开机检测抬起问题【篇】
Tensorflow2.4实现RepVGG
The former king of fruit juice sold for 1.6 billion yuan
Playwright - 滚动条操作
【ICLR 2021】半监督目标检测:Unbiased Teacher For Semi-Supervised Object Detection
Django上传excel表格并将数据写入数据库的详细步骤
Client请求外部接口标准处理方式
PS2手柄-1「建议收藏」