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的结构可以看出以下几点:

  1. dex::TypeIndex class_idx_: 无符号int类型,占2个字节。类型索引列表的索引/下标,表示的是方法所在的类
  2. uint16_t proto_idx_:无符号int类型,占2个字节。原型索引列表的索引/下标,表示的是方法的原型(签名)
  3. 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

posted @ 2022-06-26 11:09  asjhan  阅读(18)  评论(0编辑  收藏  举报  来源