dex解析
来源:互联网 发布:逆袭网络剧第5集 编辑:程序博客网 时间:2024/05/16 01:37
先学习dex文件格式,如图所示(图片来源于网络):
思路:
1.apk文件应用名称写死,修改为dex.zip,保存在固定的目录下,download目录下,使用函数获取路径
2.使用java中的zip类来实现dex.zip文件的解压,得到dex文件数据,并保存在内存中,java解析zip方法参考源码注释。
3.通过点击floatbutton加载classes.dex文件即可
4.进行解析
4.1先设计每个结构体都封装一个java bean类,每个类中有响应的字段解析方法,
4.2再在界面显示
--------------------------------
思路简化:
1.直接将classes.dex文件复制到download目录下
2.读取文件内容保存到byte数组中
3.通过点击floatbutton加载classes.dex文件即可
4.进行解析
4.1先设计每个结构体都封装一个java bean类,每个类中有响应的字段解析方法,
4.2再在界面显示
--------------------------------
目的在于熟悉dex文件格式,所以没有实现复杂文件操作,直接写死的路径,通过直接在程序初始化时初始化对象,所以需要将dex文件复制到downloa目录下,且命名为classes.dex,否则程序直接退出。其中使用了android文件相关操作,一些路径的标准写法
Environment.getDataDirectory()= /data
Environment.getDownloadCacheDirectory()= /cache
Environment.getExternalStorageDirectory()= /mnt/sdcard
Environment.getRootDirectory()= /system
context.getCacheDir()= /data/data/com.mt.mtpp/cache
context.getExternalCacheDir()= /mnt/sdcard/Android/data/com.mt.mtpp/cache
context.getFilesDir()= /data/data/com.mt.mtpp/files
实现功能如图所示(部分截图):
1.解析dexHeader
//// public dexHeader()throws IOException{ //1.获取文件路径, String dexPath = GetDexFilePath(); //2.获取zip文件中的classes.dex,并读取字节 //2.打开dex文件,并读取头部数据到byte中 List<Byte> byteList = new ArrayList<Byte>(); byteList = getDexHeard(dexPath); //3.需要判断魔数是否为合法dex文件64 65 78 if (!(byteList.get(0) == 0x64 && byteList.get(1) == 0x65 && byteList.get(2) == 0x78)){ IOException e = null; throw e; } //4.将缓冲区内容按格式分别存储到对应的结构(javabean)对象中 //解析dex_header并保存各节的数据到对应的javabean对象中 ParseDexHeader(byteList); }
public String GetDexFilePath() { String path = null; //获取安卓download文件下的dex.zip文件路径 File inRoot = Environment.getExternalStorageDirectory(); path = inRoot.getPath() + "/" + Environment.DIRECTORY_DOWNLOADS + "/classes.dex"; return path; } private List<Byte> getDexHeard(String dexPath) throws IOException{ File dexfile = new File(dexPath); InputStream in = null; List<Byte> bytelist = new ArrayList<Byte>(); // 一次读一个字节 in = new FileInputStream(dexfile); int tempbyte; //dex头大小为0x70 int count = 0x70; while (count != 0) { tempbyte = in.read(); bytelist.add((byte) tempbyte); count--; } in.close(); return bytelist; }
2.解析dexString
public dexString(dexHeader dexheader){ //从头部获取偏移和大小 this.byteStrSize = dexheader.stringsize; this.byteStrOff = dexheader.stringoff; //转换成int型 byte[] tempSize = new byte[4]; byte[] tempOff = new byte[4]; tempSize = bytereverse(byteStrSize); tempOff = bytereverse(byteStrOff); int intStrSize = byte2int(tempSize); //偏移 int intStrOff = byte2int(tempOff); //保存偏移值到stringID中 for (int i = 0; i < intStrSize; i++){ stringOffList.add(intStrOff); intStrOff += 4; } try { StringID strid = new StringID(); strIntsize = strid.getStrDataList(); strStringValue = strid.getStrStringList(); setStrIntsize(strIntsize); setStrStringValue(strStringValue); } catch (IOException e) { System.out.println("解析String出错!"); e.printStackTrace(); } }
3.解析dexType
public dexType(dexHeader dexheader, dexString dexstring) throws IOException { //从头部对象中获取type的大小和偏移 this.typeSize = dexheader.typesize; this.typeOff = dexheader.typeoff; //将获取的大小和偏移转化成int型 byte[] tempSize = new byte[4]; byte[] tempOff = new byte[4]; tempSize = bytereverse(typeSize); tempOff = bytereverse(typeOff); int intTypeSize = byte2int(tempSize); //偏移, int intTypeOff = byte2int(tempOff); //保存到typeOffList中 //这个偏移里面保存了字符串表中的索引 for (int i = 0; i < intTypeSize; i++){ typeOffList.add(intTypeOff); intTypeOff += 4; } //读文件取出索引值 for (int i = 0; i < typeOffList.size(); i++){ byte[] tmp = new byte[4]; int off = typeOffList.get(i); List<Byte> tByte = readDexString(GetDexFilePath(), off); //将byte转成int tmp[0] = tByte.get(0); tmp[1] = tByte.get(1); tmp[2] = tByte.get(2); tmp[3] = tByte.get(3); tmp = bytereverse(tmp); int StrIndex = byte2int(tmp); //保存index值用于显示 intindex.add(StrIndex); //在通过索引值在字符串表中找到对应字符串 String strRes = dexstring.getStrStringValue().get(StrIndex); typeStringList.add(strRes); } setIntindex(intindex); setTypeStringList(typeStringList); }
4.解析dexProto
//构造方法 public dexProto(dexHeader dexheader, dexString dexstring, dexType dextype) throws IOException { //dexheader获得偏移 //4字节短类型保存在dexString表中 //4字节返回值类型保存在dexType表中 //4字节参数偏移,找到参数的数量和索引 //参数数量,该原型有几个参数 //参数类型索引,通过类型索引在type表中找到类型值 //从头部对象中获取type的大小和偏移 this.protoSize = dexheader.protosize; this.protoOff = dexheader.protooff; //将获取的大小和偏移转化成int型 byte[] tempSize = new byte[4]; byte[] tempOff = new byte[4]; tempSize = bytereverse(protoSize); tempOff = bytereverse(protoOff); int intProtoSize = byte2int(tempSize); //偏移, int intProtoOff = byte2int(tempOff); //保存到typeOffList中 //这个偏移里面保存了字符串表中的索引 for (int i = 0; i < intProtoSize; i++){ protoOffList.add(intProtoOff); intProtoOff += 12; } //分别计算不同字段的偏移 for (int i = 0; i < protoOffList.size(); i++){ int off = protoOffList.get(i); List<Byte> tByte = readDexString(GetDexFilePath(), off); //将byte转成int byte[] protoShort = new byte[4]; protoShort[0] = tByte.get(0); protoShort[1] = tByte.get(1); protoShort[2] = tByte.get(2); protoShort[3] = tByte.get(3); protoShort = bytereverse(protoShort); int shortidx = byte2int(protoShort); protoShortList.add(shortidx); byte[] protoReturn = new byte[4]; protoReturn[0] = tByte.get(4); protoReturn[1] = tByte.get(5); protoReturn[2] = tByte.get(6); protoReturn[3] = tByte.get(7); protoReturn = bytereverse(protoReturn); int Returnidx = byte2int(protoReturn); protoReturnList.add(Returnidx); byte[] protoParam = new byte[4]; protoParam[0] = tByte.get(8); protoParam[1] = tByte.get(9); protoParam[2] = tByte.get(10); protoParam[3] = tByte.get(11); protoParam = bytereverse(protoParam); int Paramoff = byte2int(protoParam); protoParamList.add(Paramoff); } //读文件分别获取不同字段的值 //获取短类型在dexString中的索引 //读文件取出短类型索引值 for (int i = 0; i < protoShortList.size(); i++){ int value = protoShortList.get(i); //在通过索引值在字符串表中找到对应字符串 String strRes = dexstring.getStrStringValue().get(value); protoShortStringList.add(strRes); } //读文件取出返回值索引值 for (int i = 0; i < protoReturnList.size(); i++){ int value = protoReturnList.get(i); //在通过索引值在type表中找到对应字符串 String strRes = dextype.getTypeStringList().get(value); protoReturnStringList.add(strRes); } //读文件取出参数偏移 for (int i = 0; i < protoParamList.size(); i++){ byte[] tmp = new byte[4]; int off = protoParamList.get(i); List<Byte> tByte = new ArrayList<Byte>(); if (off == 0){ ParamNumList.add(0); parambyteList.add(tByte); continue; } tByte = readDexString2(GetDexFilePath(), off); //将byte转成int tmp[0] = tByte.get(0); tmp[1] = tByte.get(1); tmp[2] = tByte.get(2); tmp[3] = tByte.get(3); tmp = bytereverse(tmp); int paramnum = byte2int(tmp); //在通过索引值读文件在文件偏移处找到对应参数个数,参数索引 //参数个数list ParamNumList.add(paramnum); //保存参数list //保存参数的字节,然后再更具参数个数进行解析 //需要偏移4个字节后开始读,字节数 = 索引2字节 * 个数(paramnum的值) tByte = readDexString3(GetDexFilePath(), off + 4, paramnum); parambyteList.add(tByte); } //再根据参数个数的list来解析参数的值 for (int i = 0; i < ParamNumList.size(); i++){ if (ParamNumList.get(i) == 1){ //直接保存参数索引 byte[] tmp2 = new byte[2]; tmp2[0] = parambyteList.get(i).get(0); tmp2[1] = parambyteList.get(i).get(1); tmp2 = bytereverse2(tmp2); int paramidx = byte2int_2(tmp2); String paramString = dextype.getTypeStringList().get(paramidx); paramStringList.add(paramString); } else if (ParamNumList.get(i) == 0) { paramStringList.add("void"); } else { //参数总字节数/参数个数 = 需要分解的参数个数 int count = (parambyteList.get(i).size())/(ParamNumList.get(i)); String paramString2 = ""; while(count != 0){ //一次读2个字节,保存参数索引 byte[] tmp2 = new byte[2]; tmp2[0] = parambyteList.get(i).get(0); tmp2[1] = parambyteList.get(i).get(1); tmp2 = bytereverse2(tmp2); int paramidx = byte2int_2(tmp2); paramString2 = paramString2 + dextype.getTypeStringList().get(paramidx); count--; } paramStringList.add(paramString2); } } }
5.解析dexField
//构造函数中获取field的偏移和大小 public dexField(dexHeader dexheader, dexString dexstring, dexType dextype) throws IOException { //从头部对象中获取type的大小和偏移 this.fieldSize = dexheader.fieldsize; this.fieldOff = dexheader.fieldoff; //将获取的大小和偏移转化成int型 byte[] tempSize = new byte[4]; byte[] tempOff = new byte[4]; tempSize = bytereverse(fieldSize); tempOff = bytereverse(fieldOff); int intFiledSize = byte2int(tempSize); //偏移, int intFieldOff = byte2int(tempOff); //保存到typeOffList中 //这个偏移里面保存了字符串表中的索引 for (int i = 0; i < intFiledSize; i++){ FieldOffList.add(intFieldOff); intFieldOff += 8; } //根据偏移读取对应字段的值 for (int i = 0; i < FieldOffList.size(); i++){ int off = FieldOffList.get(i); List<Byte> tByte = readDexString(GetDexFilePath(), off); //将byte转成int //保存classid的索引 byte[] classid = new byte[2]; classid[0] = tByte.get(0); classid[1] = tByte.get(1); classid = bytereverse2(classid); int classindex = byte2int_2(classid); FieldclassidList.add(classindex); //保存typeid的索引 byte[] typeid = new byte[2]; typeid[0] = tByte.get(2); typeid[1] = tByte.get(3); typeid = bytereverse2(typeid); int typeidindex = byte2int_2(typeid); FieldtypeidList.add(typeidindex); //保存nameid的索引 byte[] nameid = new byte[4]; nameid[0] = tByte.get(4); nameid[1] = tByte.get(5); nameid[2] = tByte.get(6); nameid[3] = tByte.get(7); nameid = bytereverse(nameid); int nameindex = byte2int(nameid); FieldnameidList.add(nameindex); } //根据索引获取classid字符串 for (int i = 0; i < FieldclassidList.size(); i++){ String classStr = dextype.getTypeStringList().get(FieldclassidList.get(i)); FiledClassStrList.add(classStr); } //根据索引获取typeid字符串 for (int i = 0; i < FieldtypeidList.size(); i++){ String typeStr = dextype.getTypeStringList().get(FieldtypeidList.get(i)); FiledTypeStrList.add(typeStr); } //根据索引获取nameid字符串 for (int i = 0; i < FieldnameidList.size(); i++){ String nameStr = dexstring.getStrStringValue().get(FieldnameidList.get(i)); FiledNameStrList.add(nameStr); } }
6.解析dexMethod
//构造函数中获取field的偏移和大小 public dexMethod(dexHeader dexheader, dexString dexstring, dexType dextype, dexProto dexproto) throws IOException { //从头部对象中获取method的大小和偏移 this.methodSize = dexheader.methodsize; this.methodOff = dexheader.methodoff; //将获取的大小和偏移转化成int型 byte[] tempSize = new byte[4]; byte[] tempOff = new byte[4]; tempSize = bytereverse(methodSize); tempOff = bytereverse(methodOff); int intMethodSize = byte2int(tempSize); //偏移, int intMethodOff = byte2int(tempOff); //保存到methodOffList中 //这个偏移里面保存了字符串表中的索引 for (int i = 0; i < intMethodSize; i++){ MethodOffList.add(intMethodOff); intMethodOff += 8; } //根据偏移读取对应字段的值 for (int i = 0; i < MethodOffList.size(); i++){ int off = MethodOffList.get(i); List<Byte> tByte = readDexString(GetDexFilePath(), off); //将byte转成int //保存classid的索引 byte[] classid = new byte[2]; classid[0] = tByte.get(0); classid[1] = tByte.get(1); classid = bytereverse2(classid); int classindex = byte2int_2(classid); MethodclassidList.add(classindex); //保存typeid的索引 byte[] protoid = new byte[2]; protoid[0] = tByte.get(2); protoid[1] = tByte.get(3); protoid = bytereverse2(protoid); int protoidindex = byte2int_2(protoid); MethodprotoidList.add(protoidindex); //保存nameid的索引 byte[] nameid = new byte[4]; nameid[0] = tByte.get(4); nameid[1] = tByte.get(5); nameid[2] = tByte.get(6); nameid[3] = tByte.get(7); nameid = bytereverse(nameid); int nameindex = byte2int(nameid); MethodnameidList.add(nameindex); } //根据索引获取classid字符串 for (int i = 0; i < MethodclassidList.size(); i++){ String classStr = dextype.getTypeStringList().get(MethodclassidList.get(i)); MethodClassStrList.add(classStr); } //根据索引获取protoid字符串 for (int i = 0; i < MethodprotoidList.size(); i++){ //保存参数 String protoStr = dexproto.getParamStringList().get(MethodprotoidList.get(i)); MethodprotoStrList.add(protoStr); //保存返回值 String protoreturnStr = dexproto.getProtoReturnStringList().get(MethodprotoidList.get(i)); MethodprotoReturnStrList.add(protoreturnStr); } //根据索引获取nameid字符串 for (int i = 0; i < MethodnameidList.size(); i++){ String nameStr = dexstring.getStrStringValue().get(MethodnameidList.get(i)); MethodNameStrList.add(nameStr); } }
7.解析dexClass,未实现完整,给出类型转换函数的实现
//转换uleb128转uint // 解码uleb int byteindex = 0; public int decodeUleb128(byte[] byteAry) { int index = 0, cur; int result = byteAry[index]; index++; if (result > 0x7f) { // 判断第一个字节是否大于 0x7f cur = byteAry[index]; // 读取第二个字节 result = (result & 0x7f) | ((cur & 0x7f) << 7); //前两个字节合并 index++; if (cur > 0x7f) {//判断第二个字节是否大于0x7f cur = byteAry[index];//读取第三个字节 result |= (cur & 0x7f) << 14; index++; if (cur > 0x7f) {//判断第三个字节是否大于0x7f cur = byteAry[index];//读取第四个字节 result |= (cur & 0x7f) << 21; index++; if (cur > 0x7f) {//判断第四个字节是否大于0x7f cur = byteAry[index];//读取第五个字节 result |= cur << 28; } } } } this.byteindex = index; return result; }
有更好的实现方式可以交流学习。
- dex解析
- DEX文件格式解析
- Android Dex文件格式解析
- Android Dex文件格式解析
- Android Dex文件格式解析
- dex文件解析
- Android Dex文件格式解析
- 解析 dex 文件结构 - DexHeader
- Android Dex文件结构解析
- Android Dex文件数据结构解析
- dex2jar源码解析----解析dex文件<一>
- dex2jar源码解析----解析dex文件<二>
- dex2jar源码解析----解析dex文件<三>
- 利用ant和dedex解析classes.dex
- Dex文件头及解析机制分析
- Android动态加载Dex机制解析
- 图解Dex文件结构及解析要点
- dex2jar源码解析----dex转smail
- 面试题15 :链表中倒数第k个结点
- 【Java多线程】ReentrantReadWriteLock
- js数据结构之链表
- openmp 学习
- 开博声明
- dex解析
- C++ SDL教程翻译 Lesson 02 Getting an Image on the Screen
- git学习笔记(一)
- UMeng分享面板无法弹出解决办法
- MTK Camera上电流程分析
- JSP
- C# 简单操作word(可使用模版)
- 网易视频云:HBase RegionServer宕机案件侦查
- 简单的补间动画代码