Android 解析DEX文件

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 1. DEX文件简介1). 基本格式Android DEX文件格式--非虫大神杰作.pngdex-file-general-structure.

1. DEX文件简介

1). 基本格式
img_44dda2cbb40f28c643bd38c4a08894d6.png
Android DEX文件格式--非虫大神杰作.png
img_4a9cafdd0e27ebdd976b03e67347dca1.png
dex-file-general-structure.png
  • Dex Header: header文件头
  • String Table: 字符串的索引
  • Type Table: 类型的索引
  • Proto Table: 方法原型的索引
  • Field Table: 域的索引
  • Method Table: 方法索引
  • Class Def Table: 类的定义区
  • Data Section: 数据区
1). Dex Header

dex文件里的header,描述.dex文件的文件信息,及其它各个区域的索引。

/**
 * DEX 头部信息类型
 * 主要分为两部分:
 *  1). 魔数 + 签名 + 文件大小等信息
 *  2). 后面的各个数据结构的大小和偏移值,成对出现
 * 
 * struct DexHeader {
        u1  magic[8];           // includes version number
        u4  checksum;           // adler32 checksum 
        u1  signature[kSHA1DigestLen]; // SHA-1 hash
        u4  fileSize;           // length of entire file
        u4  headerSize;         // offset to start of next section
        u4  endianTag;
        u4  linkSize;
        u4  linkOff;
        u4  mapOff;
        u4  stringIdsSize;
        u4  stringIdsOff;
        u4  typeIdsSize;
        u4  typeIdsOff;
        u4  protoIdsSize;
        u4  protoIdsOff;
        u4  fieldIdsSize;
        u4  fieldIdsOff;
        u4  methodIdsSize;
        u4  methodIdsOff;
        u4  classDefsSize;
        u4  classDefsOff;
        u4  dataSize;
        u4  dataOff;
    };
 * 
 * @author mazaiting
 */
public class HeaderType {
    /**8个字节,一般是常量,为使.dex文件能够被识别出来,必须出现在.dex文件的最开头位置
     *  数组的值一般可以转换为一个字符串: { 0x64 0x65 0x78 0x0a 0x30 0x33 0x35 0x00 } = "dex\n035\0"
     *  中间是一个 ‘\n' 符号 ,后面 035 是 Dex 文件格式的版本 。
     */
    public byte[] magic = new byte[8];
    /**文件校验码,使用alder32算法校验文件出去magic,checknum外余下所有文件区域用于检查文件错误*/
    public int checkSum;
    /**采用SHA-1算法hash出去magic,checknum和signature外余下所有的文件区域,用于唯一识别本文件*/
    public byte[] signAture = new byte[20];
    /**DEX文件的大小*/
    public int fileSize;
    /**header区域的大小,单位Byte,一般固定为0x70常量*/
    public int headerSize;
    /**大小端标签,标准.dex文件为小端,此项一般固定为0x12345678常量*/
    public int endianTag;
    /**链接数据的大小*/
    public int linkSize;
    /**链接数据的偏移值*/
    public int linkOff;
    /**map item的偏移地址,该item属于data区里的内容,值要大于等于dataOff的大小*/
    public int mapOff;
    /**DEX中用到的所有字符串内容的大小*/
    public int stringIdsSize;
    /**DEX中用到的所有字符串内容的偏移量*/
    public int stringIdsOff;
    /**DEX中类型数据结构的大小*/
    public int typeIdsSize;
    /**DEX中类型数据结构的偏移值*/
    public int typeIdsOff;
    /**DEX中的元数据信息数据结构的大小*/
    public int protoIdsSize;
    /**DEX中的元数据信息数据结构的偏移值*/
    public int protoIdsOff;
    /**DEX中字段信息数据结构的大小*/
    public int fieldIdsSize;
    /**DEX中字段信息数据结构的偏移值*/
    public int fieldIdsOff;
    /**DEX中方法信息数据结构的大小*/
    public int methodIdsSize;
    /**DEX中方法信息数据结构的偏移值*/
    public int methodIdsOff;
    /**DEX中的类信息数据结构的大小*/
    public int classDefsSize;
    /**DEX中的类信息数据结构的偏移值*/
    public int classDefsOff;
    /**DEX中数据区域的结构信息的大小*/
    public int dataSize;
    /**DEX中数据区域的结构信息的偏移值*/
    public int dataOff;
    
    @Override
    public String toString(){
        return "magic:"+Util.bytesToHexString(magic)+"\n"
                + "checksum:"+checkSum + "\n"
                + "siganature:"+Util.bytesToHexString(signAture) + "\n"
                + "file_size:"+fileSize + "\n"
                + "header_size:"+headerSize + "\n"
                + "endian_tag:"+endianTag + "\n"
                + "link_size:"+linkSize + "\n"
                + "link_off:"+Util.bytesToHexString(Util.int2Byte(linkOff)) + "\n"
                + "map_off:"+Util.bytesToHexString(Util.int2Byte(mapOff)) + "\n"
                + "string_ids_size:"+stringIdsSize + "\n"
                + "string_ids_off:"+Util.bytesToHexString(Util.int2Byte(stringIdsOff)) + "\n"
                + "type_ids_size:"+typeIdsSize + "\n"
                + "type_ids_off:"+Util.bytesToHexString(Util.int2Byte(typeIdsOff)) + "\n"
                + "proto_ids_size:"+protoIdsSize + "\n"
                + "proto_ids_off:"+Util.bytesToHexString(Util.int2Byte(protoIdsOff)) + "\n"
                + "field_ids_size:"+fieldIdsSize + "\n"
                + "field_ids_off:"+Util.bytesToHexString(Util.int2Byte(fieldIdsOff)) + "\n"
                + "method_ids_size:"+methodIdsSize + "\n"
                + "method_ids_off:"+Util.bytesToHexString(Util.int2Byte(methodIdsOff)) + "\n"
                + "class_defs_size:"+classDefsSize + "\n"
                + "class_defs_off:"+Util.bytesToHexString(Util.int2Byte(classDefsOff)) + "\n"
                + "data_size:"+dataSize + "\n"
                + "data_off:"+Util.bytesToHexString(Util.int2Byte(dataOff));
    }
}
img_9a1f317c4bf53b37ba6b29498df56ec6.png
图1.png
2). String Table

string_ids区索引.dex文件所有的字符串

/**
 * 索引.dex文件所有的字符串
 * 
 * struct DexStringId {
        u4 stringDataOff;      // file offset to string_data_item
    };
 * @author mazaiting
 */
public class StringIdsItem {
    /**字符串数据的偏移地址*/
    public int stringDataOff;
    
    /**
     * 获取当前类属性所占字节大小
     * @return
     */
    public static int getSize() {
        return 4;
    }
    
    @Override
    public String toString() {
        return Util.bytesToHexString(Util.int2Byte(stringDataOff));
    }
}

string_data_off是一个偏移地址,指向的数据结构为string_data_item.

/**
 * StringIdsItem中stringDataOff指向的数据结构
 * struct string_data_item {
        uleb128 utf16_size;
        ubyte data;
    }
 * @author mazaiting
 */
public class StringDataItem {
    /**LEB128 ( little endian base 128 ) 格式 ,是基于 1 个 Byte 的一种不定长度的
        编码方式 。若第一个 Byte 的最高位为 1 ,则表示还需要下一个 Byte 来描述 ,直至最后一个 Byte 的最高
        位为 0 。每个 Byte 的其余 Bit 用来表示数据*/
    public byte data;
    public List<Byte> utf16Size = new ArrayList<>();
}
3). Type Table

主要描述dex中所有的类型,如类类型,基本类型等信息,type_ids区索引了dex文件里的所有数据类型,包括class类型,数据类型(array types) 和基本类型(primitive types).

/**
 * DEX所有类型,基本类型等信息
 * type_ids 区索引了 dex 文件里的所有数据类型 ,包括 class 类型 ,数组类型(array types)和基本类型(primitive types)
 * 
 * struct DexTypeId {
    u4  descriptorIdx;      // index into stringIds list for type descriptor 
    };
 * @author mazaiting
 */
public class TypeIdsItem {
    /**
     * ID索引
     */
    public int descriptorIdx;
    
    /**
     * 获取所属
     * @return
     */
    public static int getSize() {
        return 4;
    }
}
4). Proto Table

proto是method prototype代表java语言里的一个method的原型

/**
 * proto 的意思是 method prototype 代表 java 语言里的一个 method 的原型 。proto_ids 里的元素为 proto_id_item ,
 * 
 * struct DexProtoId {
        u4  shortyIdx;          // index into stringIds for shorty descriptor
        u4  returnTypeIdx;      // index into typeIds list for return type 
        u4  parametersOff;      // file offset to type_list for parameter types
    };
 *
 * @author mazaiting
 */
public class ProtoIdsItem {
    /**值为一个string_ids的index号,用来说明该method原型*/
    public int shortyIdx;
    /**值为一个type_ids的index,表示该method原型的返回值类型*/
    public int returnTypeIdx;
    /**指定method原型的参数列表type_list,若method没有参数,则值为0. 参数的格式是type_list*/
    public int parametersOff;
    
    // 这个不是公共字段,而是为了存储方法原型中的参数类型名和参数个数
    public List<String> paramtersList = new ArrayList<>();
    public int paramterCount;
    
    /**
     * 获取当前类字节数
     * @return
     */
    public static int getSize() {
        return 4 + 4 + 4;
    }
    
    @Override
    public String toString() {
        return "shortyIdx:"+shortyIdx+",returnTypeIdx:"+returnTypeIdx+",parametersOff:"+parametersOff;
    }
}
5). Field Table

field_ids区里面存放的是dex文件引用的所有field

/**
 * field_ids区里存放的是dex文件引用的所有的field,本区元素格式是field_id_item
 * 
 * struct DexFieldId {
        u2  classIdx;           // index into typeIds list for defining class
        u2  typeIdx;            // index into typeIds for field type
        u4  nameIdx;            // index into stringIds for field name
    };
 * 
 * @author mazaiting
 */
public class FieldIdsItem {
    /**
     * field所属的class类型,class_idx的值时type_ids的一个index,指向所属的类
     */
    public short classIdx;
    /**
     * field的类型,值是type_ids的一个index
     */
    public short typeIdx;
    /**
     * field的名称,它的值是string_ids的一个index
     */
    public int nameIdx;
    
    /**
     * 当前区域所占字节大小
     * @return
     */
    public static int getSize() {
        return 2 + 2 + 4;
    }
    
    @Override
    public String toString() {
        return "classIdx: " + classIdx + ",typeIdx: " + typeIdx + ",nameIdx: " + nameIdx;
    }
}
6). Method Table

method_ids是索引区的最后一个条目,它索引了dex文件里的所有的method.

/**
 * method_ids是索引区的最后一个条目,它索引了dex文件里的所有method.
 * method_ids的元素格式是method_id_item
 * 
 * struct DexMethodId {
        u2  classIdx;           // index into typeIds list for defining class
        u2  protoIdx;           // index into protoIds for method prototype
        u4  nameIdx;            // index into stringIds for method name
    };
 * 
 * @author mazaiting
 */
public class MethodIdsItem {
    /**
     * method所属的class类型,class_idx的值是type_ids的一个index,必须指向一个class类型
     */
    public short classIdx;
    /**
     * method的原型,指向proto_ids的一个index
     */
    public short protoIdx;
    /**
     * method的名称,值为string_ids的一个index
     */
    public int nameIdx;
    
    public static int getSize() {
        return 2 + 2 + 4;
    }

    @Override
    public String toString(){
        return "classIdx: " + classIdx + ",protoIdx: " + protoIdx + ",nameIdx: " + nameIdx;
    }

}
7). Class Def Table

class_defs区域里存放着class definitions,class的定义。它的结构较dex区要复杂,有的数据直接指向data区

/**
 * class_defs区域里存放着class definitions,有些数据直接指向了data区
 * 
 * struct DexClassDef {
        u4  classIdx;           /* index into typeIds for this class
        u4  accessFlags;
        u4  superclassIdx;      /* index into typeIds for superclass
        u4  interfacesOff;      /* file offset to DexTypeList
        u4  sourceFileIdx;      /* index into stringIds for source file name
        u4  annotationsOff;     /* file offset to annotations_directory_item
        u4  classDataOff;       /* file offset to class_data_item
        u4  staticValuesOff;    /* file offset to DexEncodedArray
    };
 * 
 * @author mazaiting
 */
public class ClassDefItem {
    /**
     * 描述具体的class类型,值是type_ids的一个index,值必须是一个class类型,不能是数组雷兴国或者基本类型
     */
    public int classIdx;
    /**
     * 描述class的访问类型,如public,final,static等
     */
    public int accessFlags;
    /**
     * 描述父类的类型,值必须是一个class类型,不能是数组雷兴国或者基本类型
     */
    public int superClassIdx;
    /**
     * 值为偏移地址,被指向的数据结构为type_list,class若没有interfaces,值为0
     */
    public int interfacesOff;
    /**
     * 表示源代码文件的信息,值为string_ids的一个index。若此项信息丢失,此项赋值为NO_INDEX=0xFFFFFFFF
     */
    public int sourceFileIdx;
    /**
     * 值为偏移地址,指向的内容是该class的注解,位置在data区,格式为annotations_directory_item,若没有此项,值为0
     */
    public int annotationsOff;
    /**
     * 值为偏移地址,指向的内容是该class的使用到的数据,位置在data区,格式为class_data_item。无偶没有此项,则值为0
     */
    public int classDataOff;
    /**
     * 值为偏移地址,指向data区里的一个列表,格式为encoded_array_item。若没有此项,值为0.
     */
    public int staticValueOff;
    
    /**
     * enum {
            ACC_PUBLIC       = 0x00000001,       // class, field, method, ic
            ACC_PRIVATE      = 0x00000002,       // field, method, ic
            ACC_PROTECTED    = 0x00000004,       // field, method, ic
            ACC_STATIC       = 0x00000008,       // field, method, ic
            ACC_FINAL        = 0x00000010,       // class, field, method, ic
            ACC_SYNCHRONIZED = 0x00000020,       // method (only allowed on natives)
            ACC_SUPER        = 0x00000020,       // class (not used in Dalvik)
            ACC_VOLATILE     = 0x00000040,       // field
            ACC_BRIDGE       = 0x00000040,       // method (1.5)
            ACC_TRANSIENT    = 0x00000080,       // field
            ACC_VARARGS      = 0x00000080,       // method (1.5)
            ACC_NATIVE       = 0x00000100,       // method
            ACC_INTERFACE    = 0x00000200,       // class, ic
            ACC_ABSTRACT     = 0x00000400,       // class, method, ic
            ACC_STRICT       = 0x00000800,       // method
            ACC_SYNTHETIC    = 0x00001000,       // field, method, ic
            ACC_ANNOTATION   = 0x00002000,       // class, ic (1.5)
            ACC_ENUM         = 0x00004000,       // class, field, ic (1.5)
            ACC_CONSTRUCTOR  = 0x00010000,       // method (Dalvik only)
            ACC_DECLARED_SYNCHRONIZED =
                               0x00020000,       // method (Dalvik only)
            ACC_CLASS_MASK =
                (ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT
                        | ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM),
            ACC_INNER_CLASS_MASK =
                (ACC_CLASS_MASK | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC),
            ACC_FIELD_MASK =
                (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL
                        | ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM),
            ACC_METHOD_MASK =
                (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL
                        | ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE
                        | ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR
                        | ACC_DECLARED_SYNCHRONIZED),
        };

     */
    
    /**
     * 访问修饰符
     */
    public static final int 
        ACC_PUBLIC       = 0x00000001,       // class, field, method, ic
        ACC_PRIVATE      = 0x00000002,       // field, method, ic
        ACC_PROTECTED    = 0x00000004,       // field, method, ic
        ACC_STATIC       = 0x00000008,       // field, method, ic
        ACC_FINAL        = 0x00000010,       // class, field, method, ic
        ACC_SYNCHRONIZED = 0x00000020,       // method (only allowed on natives)
        ACC_SUPER        = 0x00000020,       // class (not used in Dalvik)
        ACC_VOLATILE     = 0x00000040,       // field
        ACC_BRIDGE       = 0x00000040,       // method (1.5)
        ACC_TRANSIENT    = 0x00000080,       // field
        ACC_VARARGS      = 0x00000080,       // method (1.5)
        ACC_NATIVE       = 0x00000100,       // method
        ACC_INTERFACE    = 0x00000200,       // class, ic
        ACC_ABSTRACT     = 0x00000400,       // class, method, ic
        ACC_STRICT       = 0x00000800,       // method
        ACC_SYNTHETIC    = 0x00001000,       // field, method, ic
        ACC_ANNOTATION   = 0x00002000,       // class, ic (1.5)
        ACC_ENUM         = 0x00004000,       // class, field, ic (1.5)
        ACC_CONSTRUCTOR  = 0x00010000,       // method (Dalvik only)
        ACC_DECLARED_SYNCHRONIZED =
                           0x00020000,       // method (Dalvik only)
        ACC_CLASS_MASK =
            (ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT
                    | ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM),
        ACC_INNER_CLASS_MASK =
            (ACC_CLASS_MASK | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC),
        ACC_FIELD_MASK =
            (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL
                    | ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM),
        ACC_METHOD_MASK =
            (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL
                    | ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE
                    | ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR
                    | ACC_DECLARED_SYNCHRONIZED);

    /**
     * 获取当前区域所占字节数
     * @return
     */
    public static int getSize() {
        return 4 * 8;
    }
    
    @Override
    public String toString(){
        return "classIdx: " + classIdx + ",accessFlags: " + accessFlags + ",superClassIdx: " + superClassIdx + 
                ",iterfacesOff: " + interfacesOff + ",sourceFileIdx: " + sourceFileIdx + ",annotationsOff: " + 
                annotationsOff + ",classDataOff: " + classDataOff + ",staticValueOff: " + staticValueOff;
    }

}

class_data_off指向data区里的class_data_itetm结构,class_data_item里存放着本class使用到的各种数据.

/**
 * class_data_off指向data区里的class_data_item结构,class_data_item里存放着本class使用到的各种数据
 * 
 *  struct class_data_item  {
        uleb128 static_fields_size;
        uleb128 instance_fields_size;
        uleb128 direct_methods_size;
        uleb128 virtual_methods_size;
        encoded_field static_fields [ static_fields_size ];
        encoded_field instance_fields [ instance_fields_size ];
        encoded_method direct_methods [ direct_method_size ];
        encoded_method virtual_methods [ virtual_methods_size ];
    };

 * 
 * @author mazaiting
 */
public class ClassDataItem {
    /**
     * 静态字段的大小
     */
    public int staticFieldsSize;
    /**
     * 实例化字段的大小
     */
    public int instanceFieldsSize;
    /**
     * 实现方法的大小
     */
    public int directMethodsSize;
    /**
     * 虚拟方法的大小
     */
    public int virtualMethodsSize;
    /**
     * 静态字段数组
     */
    public EncodeField[] staticFields;
    /**
     * 实例化字段数组
     */
    public EncodeField[] instanceFields;
    /**
     * 实现方法数组
     */
    public EncodeMethod[] directMethods;
    /**
     * 虚拟方法的数组
     */
    public EncodeMethod[] virtualMethods;
    
    @Override
    public String toString(){
        return "staticFieldsSize: " + staticFieldsSize + ",instanceFieldsSize: " + instanceFieldsSize
                + ",directMethodsSize:" + directMethodsSize + ",virtualMethodsSize: " + virtualMethodsSize
                + "\n" + getFieldsAndMethods();
    }



    private String getFieldsAndMethods() {
        StringBuilder sb = new StringBuilder();
        sb.append("staticFields:\n");
        for(int i=0;i<staticFields.length;i++){
            sb.append(staticFields[i]+"\n");
        }
        sb.append("instanceFields:\n");
        for(int i=0;i<instanceFields.length;i++){
            sb.append(instanceFields[i]+"\n");
        }
        sb.append("directMethods:\n");
        for(int i=0;i<directMethods.length;i++){
            sb.append(directMethods[i]+"\n");
        }
        sb.append("virtualMethods:\n");
        for(int i=0;i<virtualMethods.length;i++){
            sb.append(virtualMethods[i]+"\n");
        }
        return sb.toString();
    }

}
8). Data Section
/**
 * 代码条目
 * 
 *  (1) 一个 .dex 文件被分成了 9 个区 ,其中有一个索引区叫做class_defs , 索引了 .dex 里面用到的 class ,以及对这个 class 的描述 。
 *  (2) class_defs 区 , 里面其实是class_def_item 结构 。这个结构里描述了 LHello; 的各种信息 ,诸如名称 ,superclass , access flag,
 *       interface 等 。class_def_item 里有一个元素 class_data_off , 指向data 区里的一个 class_data_item 结构 ,
 *       用来描述 class 使用到的各种数据 。自此以后的结构都归于 data区了 。
 *  (3) class_data_item 结构 ,里描述值着 class 里使用到的 static field , instance field , direct_method ,和 virtual_method 
 *      的数目和描述 。例子 Hello.dex 里 ,只有 2 个 direct_method , 其余的 field 和method 的数目都为 0 。描述 direct_method 的结构叫
 *      做 encoded_method ,是用来详细描述某个 method的 。
 *  (4) encoded_method 结构 ,描述某个 method 的 method 类型 , access flags 和一个指向 code_item的偏移地址 ,里面存放的是该 method 
 *      的具体实现 。
 *  (5) code_item ,结构里描述着某个 method 的具体实现 。
 * 
 * struct DexCode {
        u2  registersSize;
        u2  insSize;
        u2  outsSize;
        u2  triesSize;
        u4  debugInfoOff;       /* file offset to debug info stream
        u4  insnsSize;          /* size of the insns array, in u2 units
        u2  insns[1];
        /* followed by optional u2 padding
        /* followed by try_item[triesSize]
        /* followed by uleb128 handlersSize
        /* followed by catch_handler_item[handlersSize]
    };
 * 
 * @author mazaiting
 *
 */
public class CodeItem {
    /**
     * 本段代码使用到的寄存器数目
     */
    public short registersSize;
    /**
     * method传入参数的数目
     */
    public short insSize;
    /**
     * 本段代码调用其他方法时需要的参数个数
     */
    public short outsSize;
    /**
     * try_item结构的个数
     */
    public short triesSize;
    /**
     * 偏移地址,指向本段代码的debug信息存放位置,是一个debug_info_item结构
     */
    public int debugInfoOff;
    /**
     * 指令列表的大小,以16-bit为单位。insns是instructions的缩写
     */
    public int insnsSize;
    /**
     * insns数组
     */
    public short[] insns;
    
    /**tries和handlers用于处理java中的exception*/
    
    @Override
    public String toString(){
        return "registersSize: " + registersSize + ",insSize: " + insSize + ",outsSize: " + outsSize + 
                ",triesSize: " + triesSize + ",debugInfoOff: " + debugInfoOff + ",insnsSize: " + insnsSize 
                + "\ninsns: " + getInsnsStr();
    }
    
    private String getInsnsStr(){
        StringBuilder sb = new StringBuilder();
        if (insns != null && insns.length > 0) {
            for(int i=0;i<insns.length;i++){
                sb.append(Util.bytesToHexString(Util.short2Byte(insns[i]))+",");
            }   
        }
        
        return sb.toString();
    }
}

参考文章

Android逆向之旅---解析编译之后的Dex文件格式

代码下载

目录
相关文章
|
17天前
|
Java 开发工具 Android开发
Android与iOS开发环境搭建全解析####
本文深入探讨了Android与iOS两大移动操作系统的开发环境搭建流程,旨在为初学者及有一定基础的开发者提供详尽指南。我们将从开发工具的选择、环境配置到第一个简单应用的创建,一步步引导读者步入移动应用开发的殿堂。无论你是Android Studio的新手还是Xcode的探索者,本文都将为你扫清开发道路上的障碍,助你快速上手并享受跨平台移动开发的乐趣。 ####
|
24天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
64 2
|
2月前
|
Java
Java“解析时到达文件末尾”解决
在Java编程中,“解析时到达文件末尾”通常指在读取或处理文件时提前遇到了文件结尾,导致程序无法继续读取所需数据。解决方法包括:确保文件路径正确,检查文件是否完整,使用正确的文件读取模式(如文本或二进制),以及确保读取位置正确。合理设置缓冲区大小和循环条件也能避免此类问题。
421 2
|
2月前
|
ARouter Android开发
Android不同module布局文件重名被覆盖
Android不同module布局文件重名被覆盖
|
10天前
|
存储 Linux API
深入探索Android系统架构:从内核到应用层的全面解析
本文旨在为读者提供一份详尽的Android系统架构分析,从底层的Linux内核到顶层的应用程序框架。我们将探讨Android系统的模块化设计、各层之间的交互机制以及它们如何共同协作以支持丰富多样的应用生态。通过本篇文章,开发者和爱好者可以更深入理解Android平台的工作原理,从而优化开发流程和提升应用性能。
|
2月前
|
自然语言处理 数据处理 Python
python操作和解析ppt文件 | python小知识
本文将带你从零开始,了解PPT解析的工具、工作原理以及常用的基本操作,并提供具体的代码示例和必要的说明【10月更文挑战第4天】
403 60
|
1月前
|
存储
文件太大不能拷贝到U盘怎么办?实用解决方案全解析
当我们试图将一个大文件拷贝到U盘时,却突然跳出提示“对于目标文件系统目标文件过大”。这种情况让人感到迷茫,尤其是在急需备份或传输数据的时候。那么,文件太大为什么会无法拷贝到U盘?又该如何解决?本文将详细分析这背后的原因,并提供几个实用的方法,帮助你顺利将文件传输到U盘。
|
19天前
|
安全 Java Linux
深入解析Android系统架构及其对开发者的意义####
【10月更文挑战第21天】 本文旨在为读者揭开Android操作系统架构的神秘面纱,探讨其如何塑造现代移动应用开发格局。通过剖析Linux内核、硬件抽象层、运行时环境及应用程序框架等关键组件,揭示Android平台的强大功能与灵活性。文章强调了理解Android架构对于开发者优化应用性能、提升用户体验的重要性,并展望了未来技术趋势下Android的发展方向。 ####
29 0
|
2月前
|
数据安全/隐私保护 流计算 开发者
python知识点100篇系列(18)-解析m3u8文件的下载视频
【10月更文挑战第6天】m3u8是苹果公司推出的一种视频播放标准,采用UTF-8编码,主要用于记录视频的网络地址。HLS(Http Live Streaming)是苹果公司提出的一种基于HTTP的流媒体传输协议,通过m3u8索引文件按序访问ts文件,实现音视频播放。本文介绍了如何通过浏览器找到m3u8文件,解析m3u8文件获取ts文件地址,下载ts文件并解密(如有必要),最后使用ffmpeg合并ts文件为mp4文件。
|
2月前
|
开发工具 Android开发 iOS开发
深入解析安卓与iOS开发环境的优劣
【10月更文挑战第4天】 本文将深入探讨安卓和iOS两大主流移动操作系统的开发环境,从技术架构、开发工具、用户体验等方面进行详细比较。通过分析各自的优势和不足,帮助开发者更好地理解这两个平台的异同,从而为项目选择最合适的开发平台提供参考。
27 3