Dex2jar命令在Dex2jarCmd.java文件中
public static void main(String... args) {这里调用它的toMain函数,可以传递一些参数选项,选项大概有:
new Dex2jarCmd().doMain(args);
}
@Opt(opt = "e", longOpt = "exception-file", description = "detail exception file, default is $current_dir/[file-name]-error.zip", argName = "file") private Path exceptionFile; @Opt(opt = "f", longOpt = "force", hasArg = false, description = "force overwrite") private boolean forceOverwrite = false; @Opt(opt = "n", longOpt = "not-handle-exception", hasArg = false, description = "not handle any exceptions thrown by dex2jar") private boolean notHandleException = false; @Opt(opt = "o", longOpt = "output", description = "output .jar file, default is $current_dir/[file-name]-dex2jar.jar", argName = "out-jar-file") private Path output; @Opt(opt = "r", longOpt = "reuse-reg", hasArg = false, description = "reuse register while generate java .class file") private boolean reuseReg = false; @Opt(opt = "s", hasArg = false, description = "same with --topological-sort/-ts") private boolean topologicalSort1 = false; @Opt(opt = "ts", longOpt = "topological-sort", hasArg = false, description = "sort block by topological, that will generate more readable code, default enabled") private boolean topologicalSort = false; @Opt(opt = "d", longOpt = "debug-info", hasArg = false, description = "translate debug info") private boolean debugInfo = false; @Opt(opt = "p", longOpt = "print-ir", hasArg = false, description = "print ir to System.out") private boolean printIR = false; @Opt(opt = "os", longOpt = "optmize-synchronized", hasArg = false, description = "optimize-synchronized") private boolean optmizeSynchronized = false; @Opt(opt = "nc", longOpt = "no-code", hasArg = false, description = "") private boolean noCode = false;
Dex2jarCmd继承于BaseCmd
doMain函数实现在BaseCmd.java中
public void doMain(String... args) { try { initOptions(); parseSetArgs(args); doCommandLine(); } catch (HelpException e) { String msg = e.getMessage(); if (msg != null && msg.length() > 0) { System.err.println("ERROR: " + msg); } usage(); } catch (Exception e) { e.printStackTrace(System.err); } }initOptions调用initOptionFromClass,传递的是当前的Class
protected void initOptionFromClass(Class<?> clz) { if (clz == null) { return; } else { initOptionFromClass(clz.getSuperclass()); } Syntax syntax = clz.getAnnotation(Syntax.class); if (syntax != null) { this.cmdLineSyntax = syntax.syntax(); this.cmdName = syntax.cmd(); this.desc = syntax.desc(); this.onlineHelp = syntax.onlineHelp(); } Field[] fs = clz.getDeclaredFields(); for (Field f : fs) { Opt opt = f.getAnnotation(Opt.class); if (opt != null) { f.setAccessible(true); Option option = new Option(); option.field = f; option.description = opt.description(); option.hasArg = opt.hasArg(); option.required = opt.required(); if ("".equals(opt.longOpt()) && "".equals(opt.opt())) { // into automode option.longOpt = fromCamel(f.getName()); if (f.getType().equals(boolean.class)) { option.hasArg=false; try { if (f.getBoolean(this)) { throw new RuntimeException("the value of " + f + " must be false, as it is declared as no args"); } } catch (IllegalAccessException e) { throw new RuntimeException(e); } } checkConflict(option, "--" + option.longOpt); continue; } if (!opt.hasArg()) { if (!f.getType().equals(boolean.class)) { throw new RuntimeException("the type of " + f + " must be boolean, as it is declared as no args"); } try { if (f.getBoolean(this)) { throw new RuntimeException("the value of " + f + " must be false, as it is declared as no args"); } } catch (IllegalAccessException e) { throw new RuntimeException(e); } } boolean haveLongOpt = false; if (!"".equals(opt.longOpt())) { option.longOpt = opt.longOpt(); checkConflict(option, "--" + option.longOpt); haveLongOpt = true; } if (!"".equals(opt.argName())) { option.argName = opt.argName(); } if (!"".equals(opt.opt())) { option.opt = opt.opt(); checkConflict(option, "-" + option.opt); } else { if (!haveLongOpt) { throw new RuntimeException("opt or longOpt is not set in @Opt(...) " + f); } } } } }这里主要是解析里面的Syntax和Opt注解,对于opt主要是解析代码中定义的opt,把相应的信息保存到optMap,如是否是必须的,是否有参数等
回到doMain
parseSetArgs继续解析我们穿进去的参数
protected void parseSetArgs(String... args) throws IllegalArgumentException, IllegalAccessException { this.orginalArgs = args; List<String> remainsOptions = new ArrayList<String>(); Set<Option> requiredOpts = collectRequriedOptions(optMap);//收集必须的参数 Option needArgOpt = null; for (String s : args) { if (needArgOpt != null) {//是否需要参数 needArgOpt.field.set(this, convert(s, needArgOpt.field.getType())); needArgOpt = null; } else if (s.startsWith("-")) {// its a short or long option Option opt = optMap.get(s);//获取对应的Option requiredOpts.remove(opt);//从requiredOpts移除该选项 if (opt == null) { System.err.println("ERROR: Unrecognized option: " + s); throw new HelpException(); } else { if (opt.hasArg) { needArgOpt = opt; } else { opt.field.set(this, true); } } } else { remainsOptions.add(s); } } if (needArgOpt != null) {//命令行解析失败 System.err.println("ERROR: Option " + needArgOpt.getOptAndLongOpt() + " need an argument value"); throw new HelpException(); } this.remainingArgs = remainsOptions.toArray(new String[remainsOptions.size()]); if (this.printHelp) { throw new HelpException(); } if (!requiredOpts.isEmpty()) {//必须选项列表不为空,说明条件未满足 StringBuilder sb = new StringBuilder(); sb.append("ERROR: Options: "); boolean first = true; for (Option option : requiredOpts) { if (first) { first = false; } else { sb.append(" and "); } sb.append(option.getOptAndLongOpt()); } sb.append(" is required"); System.err.println(sb.toString()); throw new HelpException(); } }parseSetArgs首先收集必须的参数
然后对于我们传进去的参数,依次解析各个选项,如果是必须的选项,则从前面收集的必须选项中移除,表明该必须选项已经存在
最后doMain调用doCommandLine执行dex2jar的解析操作,doCommandLine有子类实现
protected void doCommandLine() throws Exception { if (remainingArgs.length == 0) {//没有剩余的参数了? usage(); return; } if ((exceptionFile != null || output != null) && remainingArgs.length != 1) {//-e/-o只能有一个文件 System.err.println("-e/-o can only used with one file"); return; } if (debugInfo && reuseReg) {//这两个选项不能同时使用 System.err.println("-d/-r can not use together"); return; } Path currentDir = new File(".").toPath();//获取当前目录 if (output != null) {//输出文件是否存在 if (Files.exists(output) && !forceOverwrite) { System.err.println(output + " exists, use --force to overwrite"); return; } } else { for (String fileName : remainingArgs) { Path file = currentDir.resolve(getBaseName(new File(fileName).toPath()) + "-dex2jar.jar"); //输出文件的名字,如果文件已经存在 则说明要覆盖写--force参数 if (Files.exists(file) && !forceOverwrite) { System.err.println(file + " exists, use to overwrite"); return; } } } for (String fileName : remainingArgs) { // long baseTS = System.currentTimeMillis(); String baseName = getBaseName(new File(fileName).toPath());//去掉后缀之后的名字 Path file = output == null ? currentDir.resolve(baseName + "-dex2jar.jar") : output;//输出文件名 System.err.println("dex2jar " + fileName + " -> " + file); BaseDexFileReader reader = MultiDexFileReader.open(Files.readAllBytes(new File(fileName).toPath())); BaksmaliBaseDexExceptionHandler handler = notHandleException ? null : new BaksmaliBaseDexExceptionHandler(); Dex2jar.from(reader).withExceptionHandler(handler).reUseReg(reuseReg).topoLogicalSort() .skipDebug(!debugInfo).optimizeSynchronized(this.optmizeSynchronized).printIR(printIR) .noCode(noCode).to(file); if (!notHandleException) { if (handler.hasException()) { Path errorFile = exceptionFile == null ? currentDir.resolve(baseName + "-error.zip") : exceptionFile; System.err.println("Detail Error Information in File " + errorFile); System.err.println(BaksmaliBaseDexExceptionHandler.REPORT_MESSAGE); handler.dump(errorFile, orginalArgs); } } // long endTS = System.currentTimeMillis(); // System.err.println(String.format("%.2f", (float) (endTS - baseTS) / 1000)); } }
这里进行一些检查,MultiDexFileReader.open根据文件的后缀新建合适的reader
public static BaseDexFileReader open(byte[] data) throws IOException { if (data.length < 3) { throw new IOException("File too small to be a dex/zip"); } if ("dex".equals(new String(data, 0, 3, StandardCharsets.ISO_8859_1))) {// dex return new DexFileReader(data);//dex文件 } else if ("PK".equals(new String(data, 0, 2, StandardCharsets.ISO_8859_1))) {// ZIP TreeMap<String, DexFileReader> dexFileReaders = new TreeMap<>(); try (ZipFile zipFile = new ZipFile(data)) { for (ZipEntry e : zipFile.entries()) { String entryName = e.getName(); if (entryName.startsWith("classes") && entryName.endsWith(".dex")) { if (!dexFileReaders.containsKey(entryName)) { // only the first one dexFileReaders.put(entryName, new DexFileReader(toByteArray(zipFile.getInputStream(e)))); } } } } if (dexFileReaders.size() == 0) { throw new IOException("Can not find classes.dex in zip file"); } else if (dexFileReaders.size() == 1) { return dexFileReaders.firstEntry().getValue(); } else { return new MultiDexFileReader(dexFileReaders.values()); } } throw new IOException("the src file not a .dex or zip file"); }
public DexFileReader(ByteBuffer in) { in.position(0); in = in.asReadOnlyBuffer().order(ByteOrder.LITTLE_ENDIAN);//小端模式 int magic = in.getInt() & 0x00FFFFFF; if (magic == MAGIC_DEX) {//dex ; } else if (magic == MAGIC_ODEX) { throw new DexException("Not support odex"); } else { throw new DexException("not support magic."); } int version = in.getInt() & 0x00FFFFFF;//版本号 if (version != MAGIC_035 && version != MAGIC_036) { throw new DexException("not support version."); } // skip uint checksum // and 20 bytes signature // and uint file_size // and uint header_size 0x70 skip(in, 4 + 20 + 4 + 4); int endian_tag = in.getInt(); if (endian_tag != ENDIAN_CONSTANT) { throw new DexException("not support endian_tag"); } // skip uint link_size // and uint link_off // and uint map_off skip(in, 4 + 4 + 4); //获取各个区段的大小和偏移 string_ids_size = in.getInt(); int string_ids_off = in.getInt(); type_ids_size = in.getInt(); int type_ids_off = in.getInt(); int proto_ids_size = in.getInt(); int proto_ids_off = in.getInt(); field_ids_size = in.getInt(); int field_ids_off = in.getInt(); method_ids_size = in.getInt(); int method_ids_off = in.getInt(); class_defs_size = in.getInt(); int class_defs_off = in.getInt(); // skip uint data_size data_off //获取偏移和长度获取各个块的buffer stringIdIn = slice(in, string_ids_off, string_ids_size * 4); typeIdIn = slice(in, type_ids_off, type_ids_size * 4); protoIdIn = slice(in, proto_ids_off, proto_ids_size * 12); fieldIdIn = slice(in, field_ids_off, field_ids_size * 8); methoIdIn = slice(in, method_ids_off, method_ids_size * 8); classDefIn = slice(in, class_defs_off, class_defs_size * 32); //下面又定义了几个buffer后面使用之前会改变position位置 in.position(0); annotationsDirectoryItemIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN); annotationSetItemIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN); annotationItemIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN); annotationSetRefListIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN); classDataIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN); codeItemIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN); stringDataIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN); encodedArrayItemIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN); typeListIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN); debugInfoIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN); }这里主要是解析dex的头
回到前面,后主要是调用
Dex2jar.from(reader).withExceptionHandler(handler).reUseReg(reuseReg).topoLogicalSort() .skipDebug(!debugInfo).optimizeSynchronized(this.optmizeSynchronized).printIR(printIR) .noCode(noCode).to(file);
开始dex到jar的转换
from通过reader新建一个Dex2jar,后面会调用它的doTranslate开始进行dex2jar的转换
exceptionHandler用来在解析发生异常时进行处理
然后其他的都是一些解析过程中用到的选项的配置
to开始启动解析
public void to(Path file) throws IOException {//把解析后的文件写入 .\classes-dex2jar.jar if (Files.exists(file) && Files.isDirectory(file)) {//已经存在或者为目录 doTranslate(file); } else { try (FileSystem fs = createZip(file)) { doTranslate(fs.getPath("/")); } } }最终调用doTranslate
private void doTranslate(final Path dist) throws IOException { DexFileNode fileNode = new DexFileNode();//创建一个DexFileNode的访问者 try { reader.accept(fileNode, readerConfig | DexFileReader.IGNORE_READ_EXCEPTION); } catch (Exception ex) { exceptionHandler.handleFileException(ex); } ClassVisitorFactory cvf = new ClassVisitorFactory() { @Override public ClassVisitor create(final String name) { return new ClassVisitor(Opcodes.ASM4, new ClassWriter(ClassWriter.COMPUTE_MAXS)) { @Override public void visitEnd() { super.visitEnd(); ClassWriter cw = (ClassWriter) super.cv; byte[] data; try { // FIXME handle 'java.lang.RuntimeException: Method code too large!' data = cw.toByteArray(); } catch (Exception ex) { System.err.println(String.format("ASM fail to generate .class file: %s", name)); exceptionHandler.handleFileException(ex); return; } try { Path dist1 = dist.resolve(name + ".class"); Path parent = dist1.getParent(); if (parent != null && !Files.exists(parent)) { Files.createDirectories(parent); } Files.write(dist1, data); } catch (IOException e) { e.printStackTrace(System.err); } } }; } }; new ExDex2Asm(exceptionHandler) { public void convertCode(DexMethodNode methodNode, MethodVisitor mv) { if ((readerConfig & DexFileReader.SKIP_CODE) != 0 && methodNode.method.getName().equals("<clinit>")) { // also skip clinit return; } super.convertCode(methodNode, mv); } @Override public void optimize(IrMethod irMethod) { T_cleanLabel.transform(irMethod); if (0 != (v3Config & V3.TOPOLOGICAL_SORT)) { // T_topologicalSort.transform(irMethod); } T_deadCode.transform(irMethod); T_removeLocal.transform(irMethod); T_removeConst.transform(irMethod); T_zero.transform(irMethod); if (T_npe.transformReportChanged(irMethod)) { T_deadCode.transform(irMethod); T_removeLocal.transform(irMethod); T_removeConst.transform(irMethod); } T_new.transform(irMethod); T_fillArray.transform(irMethod); T_agg.transform(irMethod); T_multiArray.transform(irMethod); T_voidInvoke.transform(irMethod); if (0 != (v3Config & V3.PRINT_IR)) { int i = 0; for (Stmt p : irMethod.stmts) { if (p.st == Stmt.ST.LABEL) { LabelStmt labelStmt = (LabelStmt) p; labelStmt.displayName = "L" + i++; } } System.out.println(irMethod); } T_type.transform(irMethod); T_unssa.transform(irMethod); T_ir2jRegAssign.transform(irMethod); T_trimEx.transform(irMethod); } @Override public void ir2j(IrMethod irMethod, MethodVisitor mv) { new IR2JConverter(0 != (V3.OPTIMIZE_SYNCHRONIZED & v3Config)).convert(irMethod, mv); } }.convertDex(fileNode, cvf); }这里开始主要是调用reader.accept进行dex文件的解析
然后后面的是把解析的dex文件转换为一个中间的IR格式,进行优化后再转换为jvm指令 进而输出到class文件,这个我们下一篇在看
我们先看accept方法
@Override public void accept(DexFileVisitor dv, int config) {//使用指定的访问者访问dex文件 for (int cid = 0; cid < class_defs_size; cid++) {//总共有多少个类 accept(dv, cid, config); } dv.visitEnd(); }
这里根据前面读到的class的数量,调用另外一个accept函数访问该类
public void accept(DexFileVisitor dv, int classIdx, int config) { classDefIn.position(classIdx * 32);//一个类结构占32未 int class_idx = classDefIn.getInt(); /* 类的类型,指向DexTypeId列表的索引 */ int access_flags = classDefIn.getInt();/* 访问标志 */ int superclass_idx = classDefIn.getInt(); /* 父类类型,指向DexTypeId列表的索引 */ int interfaces_off = classDefIn.getInt();/* 接口,指向DexTypeList的偏移 */ int source_file_idx = classDefIn.getInt();/* 源文件名,指向DexStringId列表的索引 */ int annotations_off = classDefIn.getInt();/* 注解,指向DexAnnotationsDirectoryItem结构 */ int class_data_off = classDefIn.getInt();/* 指向DexClassData结构的偏移 */ int static_values_off = classDefIn.getInt(); /* 指向DexEncodedArray结构的偏移 */ String className = getType(class_idx);//根据索引获取类名 String superClassName = getType(superclass_idx);//根据索引获取父类名 String[] interfaceNames = getTypeList(interfaces_off);//根据索引获取接口列表 try { DexClassVisitor dcv = dv.visit(access_flags, className, superClassName, interfaceNames); if (dcv != null)// 不为null { acceptClass(dcv, source_file_idx, annotations_off, class_data_off, static_values_off, config); dcv.visitEnd(); } } catch (Exception ex) { DexException dexException = new DexException(ex, "Error process class: [%d]%s", class_idx, className); if (0 != (config & IGNORE_READ_EXCEPTION)) { niceExceptionMessage(dexException, 0); } else { throw dexException; } } }
找了调用dv的visit,dv是DexFileNode
public DexClassVisitor visit(int access_flags, String className, String superClass, String[] interfaceNames) { DexClassNode cn = new DexClassNode(access_flags, className, superClass, interfaceNames);//新建一个DexClassNode clzs.add(cn);//添加到clzs return cn; }新建一个DexClassNode
public DexClassNode(int access, String className, String superClass, String[] interfaceNames) { super(); this.access = access; this.className = className; this.superClass = superClass; this.interfaceNames = interfaceNames; }回到前面的accept,调用acceptClass
private void acceptClass(DexClassVisitor dcv, int source_file_idx, int annotations_off, int class_data_off, int static_values_off, int config) { if ((config & SKIP_DEBUG) == 0) {//忽略调试 // 获取源文件 if (source_file_idx != -1) { dcv.visitSource(this.getString(source_file_idx)); } } Map<Integer, Integer> fieldAnnotationPositions; Map<Integer, Integer> methodAnnotationPositions; Map<Integer, Integer> paramAnnotationPositions; if ((config & SKIP_ANNOTATION) == 0) {//是否忽略注释 用来保存方法或者参数的注解,后面解析要用到 // 获取注解 fieldAnnotationPositions = new HashMap<Integer, Integer>(); methodAnnotationPositions = new HashMap<Integer, Integer>(); paramAnnotationPositions = new HashMap<Integer, Integer>(); if (annotations_off != 0) { // annotations_directory_item是否有注释 annotationsDirectoryItemIn.position(annotations_off);//注解偏移 int class_annotations_off = annotationsDirectoryItemIn.getInt();//类注解偏移 int field_annotation_size = annotationsDirectoryItemIn.getInt();//字段注解数量 int method_annotation_size = annotationsDirectoryItemIn.getInt();//方法注解数量 int parameter_annotation_size = annotationsDirectoryItemIn.getInt();//参数注解数量 for (int i = 0; i < field_annotation_size; i++) {//把注解对应的字段的idx和注解偏移对应起来 int field_idx = annotationsDirectoryItemIn.getInt(); int field_annotations_offset = annotationsDirectoryItemIn.getInt(); fieldAnnotationPositions.put(field_idx, field_annotations_offset); } for (int i = 0; i < method_annotation_size; i++) {//把注解对应的方法的idx和注解偏移对应起来 int method_idx = annotationsDirectoryItemIn.getInt(); int method_annotation_offset = annotationsDirectoryItemIn.getInt(); methodAnnotationPositions.put(method_idx, method_annotation_offset); } for (int i = 0; i < parameter_annotation_size; i++) {//把注解对应的参数变量的idx和注解偏移对应起来 int method_idx = annotationsDirectoryItemIn.getInt(); int parameter_annotation_offset = annotationsDirectoryItemIn.getInt(); paramAnnotationPositions.put(method_idx, parameter_annotation_offset); } if (class_annotations_off != 0) {//读取类的注解 try { read_annotation_set_item(class_annotations_off, dcv); } catch (Exception e) { throw new DexException("error on reading Annotation of class ", e); } } } } else { fieldAnnotationPositions = null; methodAnnotationPositions = null; paramAnnotationPositions = null; } if (class_data_off != 0) {//类的详细信息 ByteBuffer in = classDataIn; in.position(class_data_off);//调整到class的data偏移处 int static_fields = (int) readULeb128i(in);/* 静态字段个数 */ int instance_fields = (int) readULeb128i(in);/* 实例字段个数 */ int direct_methods = (int) readULeb128i(in); /* 直接方法个数 */ int virtual_methods = (int) readULeb128i(in);/* 虚方法个数 */ { int lastIndex = 0; { Object[] constant = null; if ((config & SKIP_FIELD_CONSTANT) == 0) {//是否忽略常量 if (static_values_off != 0) {//读取常量,final修饰的 constant = read_encoded_array_item(static_values_off); } } for (int i = 0; i < static_fields; i++) {//静态字段 Object value = null; if (constant != null && i < constant.length) { value = constant[i]; } lastIndex = acceptField(in, lastIndex, dcv, fieldAnnotationPositions, value, config);//获取静态字段 } } lastIndex = 0; for (int i = 0; i < instance_fields; i++) {//获取实例字段 lastIndex = acceptField(in, lastIndex, dcv, fieldAnnotationPositions, null, config); } lastIndex = 0; boolean firstMethod = true; for (int i = 0; i < direct_methods; i++) {//获取直接方法 lastIndex = acceptMethod(in, lastIndex, dcv, methodAnnotationPositions, paramAnnotationPositions, config, firstMethod); firstMethod = false; } lastIndex = 0; firstMethod = true; for (int i = 0; i < virtual_methods; i++) { lastIndex = acceptMethod(in, lastIndex, dcv, methodAnnotationPositions, paramAnnotationPositions, config, firstMethod); firstMethod = false; } } } }这里主要是依次调用acceptField解析字段,acceptMethod解析方法
先看acceptField
private int acceptField(ByteBuffer in, int lastIndex, DexClassVisitor dcv, Map<Integer, Integer> fieldAnnotationPositions, Object value, int config) { int diff = (int) readULeb128i(in); int field_access_flags = (int) readULeb128i(in); int field_id = lastIndex + diff; Field field = getField(field_id); // ////////////////////////////////////////////////////////////// DexFieldVisitor dfv = dcv.visitField(field_access_flags, field, value);//访问一个字段 filed中保存了字段的原型,这里传递访问标志 和值 if (dfv != null) { if ((config & SKIP_ANNOTATION) == 0) {//忽略字段注释 Integer annotation_offset = fieldAnnotationPositions.get(field_id); if (annotation_offset != null) { try { read_annotation_set_item(annotation_offset, dfv);//把注释设置到字段 } catch (Exception e) { throw new DexException(e, "while accept annotation in field:%s.", field.toString()); } } } dfv.visitEnd();//访问结束 } // ////////////////////////////////////////////////////////////// return field_id; }
private Field getField(int id) { fieldIdIn.position(id * 8);//一个filed占8个字节 int owner_idx = 0xFFFF & fieldIdIn.getShort();/* 类的类型,指向DexTypeId列表的索引 */ int type_idx = 0xFFFF & fieldIdIn.getShort();/* 字段类型,指向DexTypeId列表的索引 */ int name_idx = fieldIdIn.getInt(); /* 字段名,指向DexStringId列表的索引 */ return new Field(getType(owner_idx), getString(name_idx), getType(type_idx));//创建一个Field字段 所属类 类型 名称 }
这里要结合前面的dex文件结构,解析Field字段
下一步是acceptMethod
private int acceptMethod(ByteBuffer in, int lastIndex, DexClassVisitor cv, Map<Integer, Integer> methodAnnos, Map<Integer, Integer> parameterAnnos, int config, boolean firstMethod) { int offset = in.position(); int diff = (int) readULeb128i(in); int method_access_flags = (int) readULeb128i(in);/* 访问标志 */ int code_off = (int) readULeb128i(in);/* 指向DexCode结构的偏移 */ int method_id = lastIndex + diff;/* 指向DexMethodId的索引 */ Method method = getMethod(method_id);//获取一个Method // issue 200, methods may have same signature, we only need to keep the first one if (!firstMethod && diff == 0) { // detect a duplicated method WARN("GLITCH: duplicated method %s @%08x", method.toString(), offset); if ((config & KEEP_ALL_METHODS) == 0) { WARN("WARN: skip method %s @%08x", method.toString(), offset); return method_id; } } // issue 195, a <clinit> or <init> but not marked as ACC_CONSTRUCTOR, if (0 == (method_access_flags & DexConstants.ACC_CONSTRUCTOR) && (method.getName().equals("<init>") || method.getName().equals("<clinit>"))) { WARN("GLITCH: method %s @%08x not marked as ACC_CONSTRUCTOR", method.toString(), offset); } try { DexMethodVisitor dmv = cv.visitMethod(method_access_flags, method); if (dmv != null) { if ((config & SKIP_ANNOTATION) == 0) {//是否忽略 Integer annotation_offset = methodAnnos.get(method_id);//方法的注释 if (annotation_offset != null) { try { read_annotation_set_item(annotation_offset, dmv); } catch (Exception e) { throw new DexException(e, "while accept annotation in method:%s.", method.toString()); } } Integer parameter_annotation_offset = parameterAnnos.get(method_id);//参数的注释 if (parameter_annotation_offset != null) { try { read_annotation_set_ref_list(parameter_annotation_offset, dmv); } catch (Exception e) { throw new DexException(e, "while accept parameter annotation in method:%s.", method.toString()); } } } if (code_off != 0) {//exCode结构 boolean keep = true; if (0 != (SKIP_CODE & config)) {//是否忽略code keep = 0 != (KEEP_CLINIT & config) && method.getName().equals("<clinit>"); } if (keep) { DexCodeVisitor dcv = dmv.visitCode(); if (dcv != null) { try { acceptCode(code_off, dcv, config, (method_access_flags & DexConstants.ACC_STATIC) != 0, method);//访问code } catch (Exception e) { throw new DexException(e, "while accept code in method:[%s] @%08x", method.toString(), code_off); } } } } dmv.visitEnd(); } } catch (Exception e) { throw new DexException(e, "while accept method:[%s]", method.toString()); } return method_id; }
//根据methodid获取Method private Method getMethod(int id) { methoIdIn.position(id * 8);//调整位置 int owner_idx = 0xFFFF & methoIdIn.getShort(); /* 类的类型,指向DexTypeId列表的索引 */ int proto_idx = 0xFFFF & methoIdIn.getShort(); /* 声明类型,指向DexProtoId列表的索引 */ int name_idx = methoIdIn.getInt(); /* 方法名,指向DexStringId列表的索引 */ String[] parameterTypes; String returnType; //DexProtoId占12个字节,跳过前面的shortyIdx protoIdIn.position(proto_idx * 12 + 4); // move to position and skip shorty_idx int return_type_idx = protoIdIn.getInt();/* 返回类型 指向DexTypeId列表的索引 */ int parameters_off = protoIdIn.getInt();/* 参数列表 指向DexTypeList的偏移 */ returnType = getType(return_type_idx); parameterTypes = getTypeList(parameters_off); return new Method(getType(owner_idx), getString(name_idx), parameterTypes, returnType);//新建一个Method }
这里同样要根据前面分析的dex文件结构中的方法字段结构进行解析
然后调用
DexMethodVisitor dmv = cv.visitMethod(method_access_flags, method);
@Override//访问方法,主要是添加访问标志 public DexMethodVisitor visitMethod(int accessFlags, Method method) { if (methods == null) { methods = new ArrayList<DexMethodNode>(); } DexMethodNode methodNode = new DexMethodNode(accessFlags, method);//新建一个DexMethodNode methods.add(methodNode); return methodNode; }对于Method,这里主要是解析里面的Code,acceptCode
/* package */void acceptCode(int code_off, DexCodeVisitor dcv, int config, boolean isStatic, Method method) { ByteBuffer in = codeItemIn; in.position(code_off); int registers_size = 0xFFFF & in.getShort();/* 使用的寄存器个数 */ in.getShort();// ins_size ushort/* 参数个数 */ in.getShort();// outs_size ushort/* 调用其他方法时使用的寄存器个数 */ int tries_size = 0xFFFF & in.getShort();/* Try/Catch个数 */ int debug_info_off = in.getInt();/* 指向调试信息的偏移 */ int insns = in.getInt();/*指令集个数,以2字节为单位 */ byte[] insnsArray = new byte[insns * 2];//一个指令占两位 in.get(insnsArray); /* 指令集 */ dcv.visitRegister(registers_size);//访问寄存器 BitSet nextInsn = new BitSet(); Map<Integer, DexLabel> labelsMap = new TreeMap<Integer, DexLabel>(); Set<Integer> handlers = new HashSet<Integer>(); // 处理异常处理 if (tries_size > 0) { if ((insns & 0x01) != 0) {// skip padding in.getShort(); } findTryCatch(in, dcv, tries_size, insns, labelsMap, handlers); } // 处理debug信息 if (debug_info_off != 0 && (0 == (config & SKIP_DEBUG))) { DexDebugVisitor ddv = dcv.visitDebug(); if (ddv != null) { read_debug_info(debug_info_off, registers_size, isStatic, method, labelsMap, ddv); ddv.visitEnd(); } } BitSet badOps = new BitSet(); findLabels(insnsArray, nextInsn, badOps, labelsMap, handlers, method); acceptInsn(insnsArray, dcv, nextInsn, badOps, labelsMap); dcv.visitEnd(); }对于acceptCode,主要是调用findLabels找到里面的跳转xiangg 的标签
然后调用acceptInsn解析code里面的指令
先看findLabels
//找到方法中所有指令的起始位置,如有跳转指令则添加到labelsMap private void findLabels(byte[] insns, BitSet nextBit, BitSet badOps, Map<Integer, DexLabel> labelsMap, Set<Integer> handlers, Method method) { Queue<Integer> q = new LinkedList<Integer>(); q.add(0);//首先从索引0开始 第一个指令 q.addAll(handlers);//handlers是前面异常处理添加的 handlers.clear(); while (!q.isEmpty()) { int offset = q.poll(); if (nextBit.get(offset)) { continue; } else { nextBit.set(offset); } try { travelInsn(labelsMap, q, insns, offset); } catch (IndexOutOfBoundsException indexOutOfRange) { badOps.set(offset); WARN("GLITCH: %04x %s | not enough space for reading instruction", offset, method.toString()); } catch (BadOpException badOp) { badOps.set(offset); WARN("GLITCH: %04x %s | %s", offset, method.toString(), badOp.getMessage()); } } }从0索引开始,依次解析里面包含的跳转相关的指令
主要是调用travelInsn
//分析当前指令,没有结束的话把下一条指令偏移加入队列,如果有跳转或者分支指令添加到labelsMap表 private void travelInsn(Map<Integer, DexLabel> labelsMap, Queue<Integer> q, byte[] insns, int offset) { int u1offset = offset * 2;//指令是16的倍数,指令格式说明了该指令由多少个16位组成 if (u1offset >= insns.length) {//已经大于指令长度 throw new IndexOutOfBoundsException(); } int opcode = 0xFF & insns[u1offset];//获取操作码索引(低8位)http://blog.csdn.net/hudashi/article/details/52184035 Op op = null; if (opcode < Op.ops.length) { op = Op.ops[opcode];//获取对应的指令 } if (op == null || op.format == null) { throw new BadOpException("zero-width instruction op=0x%02x", opcode); } int target; boolean canContinue = true; if (op.canBranch()) {//是否是跳转指令 labelsMap用来存放跳转指令的标签 switch (op.format) { case kFmt10t: target = offset + insns[u1offset + 1]; if (target < 0 || target * 2 > insns.length) { throw new BadOpException("jump out of insns %s -> %04x", op, target); } q.add(target); order(labelsMap, target); break; case kFmt20t: case kFmt21t://2个16位字节(4个byte 4 * 8) 1个 寄存器 t表示跳转分支指令 target = offset + sshort(insns, u1offset + 2);//跳转的指令偏移,如果成功,则跳过下面不满足条件的指令 target表示跳转到的地址 if (target < 0 || target * 2 > insns.length) { throw new BadOpException("jump out of insns %s -> %04x", op, target); } q.add(target);//添加到队列 order(labelsMap, target);//添加到调整lablesMap break; case kFmt22t: target = offset + sshort(insns, u1offset + 2); int u = ubyte(insns, u1offset + 1); boolean cmpSameReg = (u & 0x0F) == ((u >> 4) & 0x0F); boolean skipTarget = false; if (cmpSameReg) { switch (op) { case IF_EQ: case IF_GE: case IF_LE: // means always jump, equals to goto canContinue = false; break; case IF_NE: case IF_GT: case IF_LT: // means always not jump skipTarget = true; break; default: break; } } if (!skipTarget) { if (target < 0 || target * 2 > insns.length) { throw new BadOpException("jump out of insns %s -> %04x", op, target); } q.add(target); order(labelsMap, target); } break; case kFmt30t: case kFmt31t: target = offset + sint(insns, u1offset + 2); if (target < 0 || target * 2 > insns.length) { throw new BadOpException("jump out of insns %s -> %04x", op, target); } q.add(target); order(labelsMap, target); break; default: break; } } if (op.canSwitch()) {//分支指令 labelsMap 也存分支标签 order(labelsMap, offset + op.format.size);// 首先把当前指令的大小偏移+大小是下一个指令 int u1SwitchData = 2 * (offset + sint(insns, u1offset + 2));// index table的偏移(32位 4*8)(offset+指令(8位一个byte) // +寄存器 // (8位一个byte)) if (u1SwitchData + 2 < insns.length) { switch (insns[u1SwitchData + 1]) {//根据该字段确定switch类型 case 0x01: // packed-switch-data case常量彼此相邻,使用了一个index索引表 { int size = ushort(insns, u1SwitchData + 2);//case常量个数 int b = u1SwitchData + 8;// targets for (int i = 0; i < size; i++) {//把case分支跳转添加到队列和labelsMap target = offset + sint(insns, b + i * 4); if (target < 0 || target * 2 > insns.length) { throw new BadOpException("jump out of insns %s -> %04x", op, target); } q.add(target); order(labelsMap, target); } break; } case 0x02:// sparse-switch-data case常量不相邻 { int size = ushort(insns, u1SwitchData + 2); int b = u1SwitchData + 4 + 4 * size;// targets for (int i = 0; i < size; i++) { target = offset + sint(insns, b + i * 4); if (target < 0 || target * 2 > insns.length) { throw new BadOpException("jump out of insns %s -> %04x", op, target); } q.add(target); order(labelsMap, target); } break; } default: throw new BadOpException("bad payload for %s", op); } } else { throw new BadOpException("bad payload offset for %s", op); } } if (canContinue) {//是否继续 int idx = Integer.MAX_VALUE; switch (op.indexType) {//索引类型 case kIndexStringRef://字符串索引 if (op.format == InstructionFormat.kFmt31c) { idx = uint(insns, u1offset + 2); } else {// other idx = ushort(insns, u1offset + 2); } canContinue = idx >= 0 && idx < string_ids_size; break; case kIndexTypeRef://类型索引 idx = ushort(insns, u1offset + 2); canContinue = idx < type_ids_size; break; case kIndexMethodRef://方法索引 idx = ushort(insns, u1offset + 2); canContinue = idx < method_ids_size; break; case kIndexFieldRef://字段索引 idx = ushort(insns, u1offset + 2);//读取字(指令偏移2字节) canContinue = idx < field_ids_size;//小于字段总数 则可以继续 break; default: } if (!canContinue) { throw new BadOpException("index-out-of-range for %s index: %d", op, idx); } } if (canContinue && op.canContinue()) {//是否继续执行 if (op == Op.NOP) {//是否是空操作 switch (insns[u1offset + 1]) { case 0x00: q.add(offset + op.format.size); break; case 0x01: { int size = ushort(insns, u1offset + 2); q.add(offset + (size * 2) + 4); break; } case 0x02: { int size = ushort(insns, u1offset + 2); q.add(offset + (size * 4) + 2); break; } case 0x03: { int element_width = ushort(insns, u1offset + 2); int size = uint(insns, u1offset + 4); q.add(offset + (size * element_width + 1) / 2 + 4); break; } } } else { q.add(offset + op.format.size);//把指令偏移和大小之和添加到q } } }
这里主要是获取指令的操作码,根据操作码获取指令 的格式,是否是跳转,switch指令,指令的格式等
指令格式定义了如下类型
public enum InstructionFormat {//op表示一个8位的操作码 // kFmt00x(0), // unknown format (also used for "breakpoint" opcode) kFmt10x(1), // op 该指令由一个16进制 使用0个寄存器 无额外数据 kFmt12x(1), // op vA, vB 该指令由一个16进制 使用2个寄存器 无额外数据 kFmt11n(1), // op vA, #+B 该指令由一个16进制 使用1个寄存器 有一个4位立即数 kFmt11x(1), // op vAA 该指令由一个16进制 使用1个寄存器(占8位) 无额外数据 kFmt10t(1), // op +AA 该指令由一个16进制 使用0个寄存器 跳转(占8位) // kFmt20bc(2), // [opt] op AA, thing@BBBB kFmt20t(2), // op +AAAA该指令由2个16进制 使用0个寄存器 跳转(占8位) kFmt22x(2), // op vAA, vBBBB kFmt21t(2), // op vAA, +BBBB 有2个16进制组成,使用一个寄存器,跳转分支指令 kFmt21s(2), // op vAA, #+BBBB kFmt21h(2), // op vAA, #+BBBB00000[00000000] kFmt21c(2), // op vAA, thing@BBBB kFmt23x(2), // op vAA, vBB, vCC kFmt22b(2), // op vAA, vBB, #+CC kFmt22t(2), // op vA, vB, +CCCC kFmt22s(2), // op vA, vB, #+CCCC kFmt22c(2), // op vA, vB, thing@CCCC // kFmt22cs(2), // [opt] op vA, vB, field offset CCCC kFmt30t(3), // op +AAAAAAAA kFmt32x(3), // op vAAAA, vBBBB kFmt31i(3), // op vAA, #+BBBBBBBB kFmt31t(3), // op vAA, +BBBBBBBB kFmt31c(3), // op vAA, string@BBBBBBBB kFmt35c(3), // op {vC,vD,vE,vF,vG}, thing@BBBB // kFmt35ms(3), // [opt] invoke-virtual+super kFmt3rc(3), // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB // kFmt3rms(3), // [opt] invoke-virtual+super/range kFmt51l(5), // op vAA, #+BBBBBBBBBBBBBBBB // kFmt35mi(3), // [opt] inline invoke // kFmt3rmi(3), // [opt] inline invoke/range ; public int size; InstructionFormat(int size) { this.size = size; }};然后下面是所有指令的定义
public enum Op implements CFG { NOP(0x00, "nop", kFmt10x, kIndexNone, kInstrCanContinue, false), // MOVE(0x01, "move", kFmt12x, kIndexNone, kInstrCanContinue, true), // MOVE_FROM16(0x02, "move/from16", kFmt22x, kIndexNone, kInstrCanContinue, true), // MOVE_16(0x03, "move/16", kFmt32x, kIndexNone, kInstrCanContinue, true), // MOVE_WIDE(0x04, "move-wide", kFmt12x, kIndexNone, kInstrCanContinue, true), // MOVE_WIDE_FROM16(0x05, "move-wide/from16", kFmt22x, kIndexNone, kInstrCanContinue, true), // MOVE_WIDE_16(0x06, "move-wide/16", kFmt32x, kIndexNone, kInstrCanContinue, true), // MOVE_OBJECT(0x07, "move-object", kFmt12x, kIndexNone, kInstrCanContinue, true), // MOVE_OBJECT_FROM16(0x08, "move-object/from16", kFmt22x, kIndexNone, kInstrCanContinue, true), // MOVE_OBJECT_16(0x09, "move-object/16", kFmt32x, kIndexNone, kInstrCanContinue, true), // MOVE_RESULT(0x0a, "move-result", kFmt11x, kIndexNone, kInstrCanContinue, true), // MOVE_RESULT_WIDE(0x0b, "move-result-wide", kFmt11x, kIndexNone, kInstrCanContinue, true), // MOVE_RESULT_OBJECT(0x0c, "move-result-object", kFmt11x, kIndexNone, kInstrCanContinue, true), // MOVE_EXCEPTION(0x0d, "move-exception", kFmt11x, kIndexNone, kInstrCanContinue, true), // RETURN_VOID(0x0e, "return-void", kFmt10x, kIndexNone, kInstrCanReturn, false), // RETURN(0x0f, "return", kFmt11x, kIndexNone, kInstrCanReturn, false), // RETURN_WIDE(0x10, "return-wide", kFmt11x, kIndexNone, kInstrCanReturn, false), // RETURN_OBJECT(0x11, "return-object", kFmt11x, kIndexNone, kInstrCanReturn, false), // CONST_4(0x12, "const/4", kFmt11n, kIndexNone, kInstrCanContinue, true), // CONST_16(0x13, "const/16", kFmt21s, kIndexNone, kInstrCanContinue, true), // CONST(0x14, "const", kFmt31i, kIndexNone, kInstrCanContinue, true), // CONST_HIGH16(0x15, "const/high16", kFmt21h, kIndexNone, kInstrCanContinue, true), // CONST_WIDE_16(0x16, "const-wide/16", kFmt21s, kIndexNone, kInstrCanContinue, true), // CONST_WIDE_32(0x17, "const-wide/32", kFmt31i, kIndexNone, kInstrCanContinue, true), // CONST_WIDE(0x18, "const-wide", kFmt51l, kIndexNone, kInstrCanContinue, true), // CONST_WIDE_HIGH16(0x19, "const-wide/high16", kFmt21h, kIndexNone, kInstrCanContinue, true), // CONST_STRING(0x1a, "const-string", kFmt21c, kIndexStringRef, kInstrCanContinue | kInstrCanThrow, true), // CONST_STRING_JUMBO(0x1b, "const-string/jumbo", kFmt31c, kIndexStringRef, kInstrCanContinue | kInstrCanThrow, true), // CONST_CLASS(0x1c, "const-class", kFmt21c, kIndexTypeRef, kInstrCanContinue | kInstrCanThrow, true), // MONITOR_ENTER(0x1d, "monitor-enter", kFmt11x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), // MONITOR_EXIT(0x1e, "monitor-exit", kFmt11x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), // CHECK_CAST(0x1f, "check-cast", kFmt21c, kIndexTypeRef, kInstrCanContinue | kInstrCanThrow, true), // INSTANCE_OF(0x20, "instance-of", kFmt22c, kIndexTypeRef, kInstrCanContinue | kInstrCanThrow, true), // ARRAY_LENGTH(0x21, "array-length", kFmt12x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // NEW_INSTANCE(0x22, "new-instance", kFmt21c, kIndexTypeRef, kInstrCanContinue | kInstrCanThrow, true), // NEW_ARRAY(0x23, "new-array", kFmt22c, kIndexTypeRef, kInstrCanContinue | kInstrCanThrow, true), // FILLED_NEW_ARRAY(0x24, "filled-new-array", kFmt35c, kIndexTypeRef, kInstrCanContinue | kInstrCanThrow, true), // FILLED_NEW_ARRAY_RANGE(0x25, "filled-new-array/range", kFmt3rc, kIndexTypeRef, kInstrCanContinue | kInstrCanThrow, true), // FILL_ARRAY_DATA(0x26, "fill-array-data", kFmt31t, kIndexNone, kInstrCanContinue, false), // THROW(0x27, "throw", kFmt11x, kIndexNone, kInstrCanThrow, false), // GOTO(0x28, "goto", kFmt10t, kIndexNone, kInstrCanBranch, false), // GOTO_16(0x29, "goto/16", kFmt20t, kIndexNone, kInstrCanBranch, false), // GOTO_32(0x2a, "goto/32", kFmt30t, kIndexNone, kInstrCanBranch, false), // PACKED_SWITCH(0x2b, "packed-switch", kFmt31t, kIndexNone, kInstrCanContinue | kInstrCanSwitch, false), // SPARSE_SWITCH(0x2c, "sparse-switch", kFmt31t, kIndexNone, kInstrCanContinue | kInstrCanSwitch, false), // CMPL_FLOAT(0x2d, "cmpl-float", kFmt23x, kIndexNone, kInstrCanContinue, false), // CMPG_FLOAT(0x2e, "cmpg-float", kFmt23x, kIndexNone, kInstrCanContinue, false), // CMPL_DOUBLE(0x2f, "cmpl-double", kFmt23x, kIndexNone, kInstrCanContinue, false), // CMPG_DOUBLE(0x30, "cmpg-double", kFmt23x, kIndexNone, kInstrCanContinue, false), // CMP_LONG(0x31, "cmp-long", kFmt23x, kIndexNone, kInstrCanContinue, false), // IF_EQ(0x32, "if-eq", kFmt22t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), // IF_NE(0x33, "if-ne", kFmt22t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), // IF_LT(0x34, "if-lt", kFmt22t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), // IF_GE(0x35, "if-ge", kFmt22t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), // IF_GT(0x36, "if-gt", kFmt22t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), // IF_LE(0x37, "if-le", kFmt22t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), // IF_EQZ(0x38, "if-eqz", kFmt21t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), // IF_NEZ(0x39, "if-nez", kFmt21t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), // IF_LTZ(0x3a, "if-ltz", kFmt21t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), // IF_GEZ(0x3b, "if-gez", kFmt21t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), // IF_GTZ(0x3c, "if-gtz", kFmt21t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), // IF_LEZ(0x3d, "if-lez", kFmt21t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), //// UNUSED_3E(0x3e, "unused-3e", null, kIndexUnknown, 0, false), //// UNUSED_3F(0x3f, "unused-3f", null, kIndexUnknown, 0, false), //// UNUSED_40(0x40, "unused-40", null, kIndexUnknown, 0, false), //// UNUSED_41(0x41, "unused-41", null, kIndexUnknown, 0, false), //// UNUSED_42(0x42, "unused-42", null, kIndexUnknown, 0, false), //// UNUSED_43(0x43, "unused-43", null, kIndexUnknown, 0, false), // AGET(0x44, "aget", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // AGET_WIDE(0x45, "aget-wide", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // AGET_OBJECT(0x46, "aget-object", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // AGET_BOOLEAN(0x47, "aget-boolean", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // AGET_BYTE(0x48, "aget-byte", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // AGET_CHAR(0x49, "aget-char", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // AGET_SHORT(0x4a, "aget-short", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // APUT(0x4b, "aput", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), // APUT_WIDE(0x4c, "aput-wide", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), // APUT_OBJECT(0x4d, "aput-object", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), // APUT_BOOLEAN(0x4e, "aput-boolean", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), // APUT_BYTE(0x4f, "aput-byte", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), // APUT_CHAR(0x50, "aput-char", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), // APUT_SHORT(0x51, "aput-short", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), // IGET(0x52, "iget", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), // IGET_WIDE(0x53, "iget-wide", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), // IGET_OBJECT(0x54, "iget-object", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), // IGET_BOOLEAN(0x55, "iget-boolean", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), // IGET_BYTE(0x56, "iget-byte", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), // IGET_CHAR(0x57, "iget-char", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), // IGET_SHORT(0x58, "iget-short", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), // IPUT(0x59, "iput", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), // IPUT_WIDE(0x5a, "iput-wide", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), // IPUT_OBJECT(0x5b, "iput-object", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), // IPUT_BOOLEAN(0x5c, "iput-boolean", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), // IPUT_BYTE(0x5d, "iput-byte", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), // IPUT_CHAR(0x5e, "iput-char", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), // IPUT_SHORT(0x5f, "iput-short", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), // SGET(0x60, "sget", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), // SGET_WIDE(0x61, "sget-wide", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), // SGET_OBJECT(0x62, "sget-object", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), // SGET_BOOLEAN(0x63, "sget-boolean", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), // SGET_BYTE(0x64, "sget-byte", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), // SGET_CHAR(0x65, "sget-char", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), // SGET_SHORT(0x66, "sget-short", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), // SPUT(0x67, "sput", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), // SPUT_WIDE(0x68, "sput-wide", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), // SPUT_OBJECT(0x69, "sput-object", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), // SPUT_BOOLEAN(0x6a, "sput-boolean", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), // SPUT_BYTE(0x6b, "sput-byte", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), // SPUT_CHAR(0x6c, "sput-char", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), // SPUT_SHORT(0x6d, "sput-short", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), // INVOKE_VIRTUAL(0x6e, "invoke-virtual", kFmt35c, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow | kInstrInvoke, true), // INVOKE_SUPER(0x6f, "invoke-super", kFmt35c, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow | kInstrInvoke, true), // INVOKE_DIRECT(0x70, "invoke-direct", kFmt35c, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow | kInstrInvoke, true), // INVOKE_STATIC(0x71, "invoke-static", kFmt35c, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow | kInstrInvoke, true), // INVOKE_INTERFACE(0x72, "invoke-interface", kFmt35c, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow | kInstrInvoke, true), //// UNUSED_73(0x73, "unused-73", null, kIndexUnknown, 0, false), // INVOKE_VIRTUAL_RANGE(0x74, "invoke-virtual/range", kFmt3rc, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow | kInstrInvoke, true), // INVOKE_SUPER_RANGE(0x75, "invoke-super/range", kFmt3rc, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow | kInstrInvoke, true), // INVOKE_DIRECT_RANGE(0x76, "invoke-direct/range", kFmt3rc, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow | kInstrInvoke, true), // INVOKE_STATIC_RANGE(0x77, "invoke-static/range", kFmt3rc, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow | kInstrInvoke, true), // INVOKE_INTERFACE_RANGE(0x78, "invoke-interface/range", kFmt3rc, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow | kInstrInvoke, true), //// UNUSED_79(0x79, "unused-79", null, kIndexUnknown, 0, false), //// UNUSED_7A(0x7a, "unused-7a", null, kIndexUnknown, 0, false), // NEG_INT(0x7b, "neg-int", kFmt12x, kIndexNone, kInstrCanContinue, true), // NOT_INT(0x7c, "not-int", kFmt12x, kIndexNone, kInstrCanContinue, true), // NEG_LONG(0x7d, "neg-long", kFmt12x, kIndexNone, kInstrCanContinue, true), // NOT_LONG(0x7e, "not-long", kFmt12x, kIndexNone, kInstrCanContinue, true), // NEG_FLOAT(0x7f, "neg-float", kFmt12x, kIndexNone, kInstrCanContinue, true), // NEG_DOUBLE(0x80, "neg-double", kFmt12x, kIndexNone, kInstrCanContinue, true), // INT_TO_LONG(0x81, "int-to-long", kFmt12x, kIndexNone, kInstrCanContinue, true), // INT_TO_FLOAT(0x82, "int-to-float", kFmt12x, kIndexNone, kInstrCanContinue, true), // INT_TO_DOUBLE(0x83, "int-to-double", kFmt12x, kIndexNone, kInstrCanContinue, true), // LONG_TO_INT(0x84, "long-to-int", kFmt12x, kIndexNone, kInstrCanContinue, true), // LONG_TO_FLOAT(0x85, "long-to-float", kFmt12x, kIndexNone, kInstrCanContinue, true), // LONG_TO_DOUBLE(0x86, "long-to-double", kFmt12x, kIndexNone, kInstrCanContinue, true), // FLOAT_TO_INT(0x87, "float-to-int", kFmt12x, kIndexNone, kInstrCanContinue, true), // FLOAT_TO_LONG(0x88, "float-to-long", kFmt12x, kIndexNone, kInstrCanContinue, true), // FLOAT_TO_DOUBLE(0x89, "float-to-double", kFmt12x, kIndexNone, kInstrCanContinue, true), // DOUBLE_TO_INT(0x8a, "double-to-int", kFmt12x, kIndexNone, kInstrCanContinue, true), // DOUBLE_TO_LONG(0x8b, "double-to-long", kFmt12x, kIndexNone, kInstrCanContinue, true), // DOUBLE_TO_FLOAT(0x8c, "double-to-float", kFmt12x, kIndexNone, kInstrCanContinue, true), // INT_TO_BYTE(0x8d, "int-to-byte", kFmt12x, kIndexNone, kInstrCanContinue, true), // INT_TO_CHAR(0x8e, "int-to-char", kFmt12x, kIndexNone, kInstrCanContinue, true), // INT_TO_SHORT(0x8f, "int-to-short", kFmt12x, kIndexNone, kInstrCanContinue, true), // ADD_INT(0x90, "add-int", kFmt23x, kIndexNone, kInstrCanContinue, true), // SUB_INT(0x91, "sub-int", kFmt23x, kIndexNone, kInstrCanContinue, true), // MUL_INT(0x92, "mul-int", kFmt23x, kIndexNone, kInstrCanContinue, true), // DIV_INT(0x93, "div-int", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // REM_INT(0x94, "rem-int", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // AND_INT(0x95, "and-int", kFmt23x, kIndexNone, kInstrCanContinue, true), // OR_INT(0x96, "or-int", kFmt23x, kIndexNone, kInstrCanContinue, true), // XOR_INT(0x97, "xor-int", kFmt23x, kIndexNone, kInstrCanContinue, true), // SHL_INT(0x98, "shl-int", kFmt23x, kIndexNone, kInstrCanContinue, true), // SHR_INT(0x99, "shr-int", kFmt23x, kIndexNone, kInstrCanContinue, true), // USHR_INT(0x9a, "ushr-int", kFmt23x, kIndexNone, kInstrCanContinue, true), // ADD_LONG(0x9b, "add-long", kFmt23x, kIndexNone, kInstrCanContinue, true), // SUB_LONG(0x9c, "sub-long", kFmt23x, kIndexNone, kInstrCanContinue, true), // MUL_LONG(0x9d, "mul-long", kFmt23x, kIndexNone, kInstrCanContinue, true), // DIV_LONG(0x9e, "div-long", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // REM_LONG(0x9f, "rem-long", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // AND_LONG(0xa0, "and-long", kFmt23x, kIndexNone, kInstrCanContinue, true), // OR_LONG(0xa1, "or-long", kFmt23x, kIndexNone, kInstrCanContinue, true), // XOR_LONG(0xa2, "xor-long", kFmt23x, kIndexNone, kInstrCanContinue, true), // SHL_LONG(0xa3, "shl-long", kFmt23x, kIndexNone, kInstrCanContinue, true), // SHR_LONG(0xa4, "shr-long", kFmt23x, kIndexNone, kInstrCanContinue, true), // USHR_LONG(0xa5, "ushr-long", kFmt23x, kIndexNone, kInstrCanContinue, true), // ADD_FLOAT(0xa6, "add-float", kFmt23x, kIndexNone, kInstrCanContinue, true), // SUB_FLOAT(0xa7, "sub-float", kFmt23x, kIndexNone, kInstrCanContinue, true), // MUL_FLOAT(0xa8, "mul-float", kFmt23x, kIndexNone, kInstrCanContinue, true), // DIV_FLOAT(0xa9, "div-float", kFmt23x, kIndexNone, kInstrCanContinue, true), // REM_FLOAT(0xaa, "rem-float", kFmt23x, kIndexNone, kInstrCanContinue, true), // ADD_DOUBLE(0xab, "add-double", kFmt23x, kIndexNone, kInstrCanContinue, true), // SUB_DOUBLE(0xac, "sub-double", kFmt23x, kIndexNone, kInstrCanContinue, true), // MUL_DOUBLE(0xad, "mul-double", kFmt23x, kIndexNone, kInstrCanContinue, true), // DIV_DOUBLE(0xae, "div-double", kFmt23x, kIndexNone, kInstrCanContinue, true), // REM_DOUBLE(0xaf, "rem-double", kFmt23x, kIndexNone, kInstrCanContinue, true), // ADD_INT_2ADDR(0xb0, "add-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // SUB_INT_2ADDR(0xb1, "sub-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // MUL_INT_2ADDR(0xb2, "mul-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // DIV_INT_2ADDR(0xb3, "div-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // REM_INT_2ADDR(0xb4, "rem-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // AND_INT_2ADDR(0xb5, "and-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // OR_INT_2ADDR(0xb6, "or-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // XOR_INT_2ADDR(0xb7, "xor-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // SHL_INT_2ADDR(0xb8, "shl-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // SHR_INT_2ADDR(0xb9, "shr-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // USHR_INT_2ADDR(0xba, "ushr-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // ADD_LONG_2ADDR(0xbb, "add-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // SUB_LONG_2ADDR(0xbc, "sub-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // MUL_LONG_2ADDR(0xbd, "mul-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // DIV_LONG_2ADDR(0xbe, "div-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // REM_LONG_2ADDR(0xbf, "rem-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // AND_LONG_2ADDR(0xc0, "and-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // OR_LONG_2ADDR(0xc1, "or-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // XOR_LONG_2ADDR(0xc2, "xor-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // SHL_LONG_2ADDR(0xc3, "shl-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // SHR_LONG_2ADDR(0xc4, "shr-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // USHR_LONG_2ADDR(0xc5, "ushr-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // ADD_FLOAT_2ADDR(0xc6, "add-float/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // SUB_FLOAT_2ADDR(0xc7, "sub-float/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // MUL_FLOAT_2ADDR(0xc8, "mul-float/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // DIV_FLOAT_2ADDR(0xc9, "div-float/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // REM_FLOAT_2ADDR(0xca, "rem-float/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // ADD_DOUBLE_2ADDR(0xcb, "add-double/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // SUB_DOUBLE_2ADDR(0xcc, "sub-double/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // MUL_DOUBLE_2ADDR(0xcd, "mul-double/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // DIV_DOUBLE_2ADDR(0xce, "div-double/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // REM_DOUBLE_2ADDR(0xcf, "rem-double/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), // ADD_INT_LIT16(0xd0, "add-int/lit16", kFmt22s, kIndexNone, kInstrCanContinue, true), // RSUB_INT(0xd1, "rsub-int", kFmt22s, kIndexNone, kInstrCanContinue, true), // MUL_INT_LIT16(0xd2, "mul-int/lit16", kFmt22s, kIndexNone, kInstrCanContinue, true), // DIV_INT_LIT16(0xd3, "div-int/lit16", kFmt22s, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // REM_INT_LIT16(0xd4, "rem-int/lit16", kFmt22s, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // AND_INT_LIT16(0xd5, "and-int/lit16", kFmt22s, kIndexNone, kInstrCanContinue, true), // OR_INT_LIT16(0xd6, "or-int/lit16", kFmt22s, kIndexNone, kInstrCanContinue, true), // XOR_INT_LIT16(0xd7, "xor-int/lit16", kFmt22s, kIndexNone, kInstrCanContinue, true), // ADD_INT_LIT8(0xd8, "add-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), // RSUB_INT_LIT8(0xd9, "rsub-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), // MUL_INT_LIT8(0xda, "mul-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), // DIV_INT_LIT8(0xdb, "div-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // REM_INT_LIT8(0xdc, "rem-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), // AND_INT_LIT8(0xdd, "and-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), // OR_INT_LIT8(0xde, "or-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), // XOR_INT_LIT8(0xdf, "xor-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), // SHL_INT_LIT8(0xe0, "shl-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), // SHR_INT_LIT8(0xe1, "shr-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), // USHR_INT_LIT8(0xe2, "ushr-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), // BAD_OP(-1, "bad-opcode", null, kIndexNone, 0, false), // ; public int opcode; public InstructionFormat format; /* package */InstructionIndexType indexType; /* package */int flags; public String displayName; public final static Op ops[] = new Op[256]; public boolean changeFrame; static { Op[] ops = Op.ops; for (Op op : Op.values()) { if (op.opcode >= 0) { ops[op.opcode] = op; } } } public boolean canBranch() { return 0 != (flags & kInstrCanBranch); } public boolean canContinue() { return 0 != (flags & kInstrCanContinue); } public boolean canReturn() { return 0 != (flags & kInstrCanReturn); } public boolean canSwitch() { return 0 != (flags & kInstrCanSwitch); } public boolean canThrow() { return 0 != (flags & kInstrCanThrow); } Op(int op, String displayName, InstructionFormat fmt, InstructionIndexType indexType, int flags, boolean changeFrame) { this.opcode = op; this.displayName = displayName; this.format = fmt; this.indexType = indexType; this.flags = flags; } public String toString() { return displayName; }}是否可跳转,继续等
这样 我们就把dex文件中的字段 ,方法,方法中的代码都解析完了,dex中的指令都解析成了 DexStmtNode。包括dex指令中用到的寄存器等,都保存在响应的dexStmtNode指令中。
先分析到这里,后面在分析dex转换为IR,以及优化后在转jvm指令,并写入class文件打成jar 包