1 /* 2 * Copyright 2013, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 package org.jf.dexlib2.analysis; 33 34 import com.google.common.base.Splitter; 35 import com.google.common.collect.Lists; 36 import org.apache.commons.cli.*; 37 import org.jf.dexlib2.DexFileFactory; 38 import org.jf.dexlib2.dexbacked.DexBackedDexFile; 39 import org.jf.dexlib2.iface.ClassDef; 40 import org.jf.dexlib2.iface.Method; 41 import org.jf.util.ConsoleUtil; 42 43 import java.io.File; 44 import java.io.FileOutputStream; 45 import java.io.IOException; 46 import java.util.ArrayList; 47 import java.util.List; 48 49 public class DumpVtables { 50 private static final Options options; 51 52 static { 53 options = new Options(); 54 buildOptions(); 55 } 56 57 public static void main(String[] args) { 58 CommandLineParser parser = new PosixParser(); 59 CommandLine commandLine; 60 61 try { 62 commandLine = parser.parse(options, args); 63 } catch (ParseException ex) { 64 usage(); 65 return; 66 } 67 68 String[] remainingArgs = commandLine.getArgs(); 69 70 Option[] parsedOptions = commandLine.getOptions(); 71 ArrayList<String> bootClassPathDirs = Lists.newArrayList(); 72 String outFile = "vtables.txt"; 73 int apiLevel = 15; 74 75 for (int i=0; i<parsedOptions.length; i++) { 76 Option option = parsedOptions[i]; 77 String opt = option.getOpt(); 78 79 switch (opt.charAt(0)) { 80 case 'd': 81 bootClassPathDirs.add(option.getValue()); 82 break; 83 case 'o': 84 outFile = option.getValue(); 85 break; 86 case 'a': 87 apiLevel = Integer.parseInt(commandLine.getOptionValue("a")); 88 break; 89 default: 90 assert false; 91 } 92 } 93 94 if (remainingArgs.length != 1) { 95 usage(); 96 return; 97 } 98 99 String inputDexFileName = remainingArgs[0]; 100 101 File dexFileFile = new File(inputDexFileName); 102 if (!dexFileFile.exists()) { 103 System.err.println("Can't find the file " + inputDexFileName); 104 System.exit(1); 105 } 106 107 try { 108 DexBackedDexFile dexFile = DexFileFactory.loadDexFile(dexFileFile, apiLevel); 109 Iterable<String> bootClassPaths = Splitter.on(":").split("core.jar:ext.jar:framework.jar:android.policy.jar:services.jar"); 110 ClassPath classPath = ClassPath.fromClassPath(bootClassPathDirs, bootClassPaths, dexFile, apiLevel); 111 FileOutputStream outStream = new FileOutputStream(outFile); 112 113 for (ClassDef classDef: dexFile.getClasses()) { 114 ClassProto classProto = (ClassProto) classPath.getClass(classDef); 115 List<Method> methods = classProto.getVtable(); 116 String className = "Class " + classDef.getType() + " extends " + classDef.getSuperclass() + " : " + methods.size() + " methods\n"; 117 outStream.write(className.getBytes()); 118 for (int i=0;i<methods.size();i++) { 119 Method method = methods.get(i); 120 121 String methodString = i + ":" + method.getDefiningClass() + "->" + method.getName() + "("; 122 for (CharSequence parameter: method.getParameterTypes()) { 123 methodString += parameter; 124 } 125 methodString += ")" + method.getReturnType() + "\n"; 126 outStream.write(methodString.getBytes()); 127 } 128 outStream.write("\n".getBytes()); 129 } 130 outStream.close(); 131 } catch (IOException ex) { 132 System.out.println("IOException thrown when trying to open a dex file or write out vtables: " + ex); 133 } 134 135 } 136 137 /** 138 * Prints the usage message. 139 */ 140 private static void usage() { 141 int consoleWidth = ConsoleUtil.getConsoleWidth(); 142 if (consoleWidth <= 0) { 143 consoleWidth = 80; 144 } 145 146 System.out.println("java -cp baksmali.jar org.jf.dexlib2.analysis.DumpVtables -d path/to/framework/jar/files <dex-file>"); 147 } 148 149 private static void buildOptions() { 150 Option classPathDirOption = OptionBuilder.withLongOpt("bootclasspath-dir") 151 .withDescription("the base folder to look for the bootclasspath files in. Defaults to the current " + 152 "directory") 153 .hasArg() 154 .withArgName("DIR") 155 .create("d"); 156 157 Option outputFileOption = OptionBuilder.withLongOpt("out-file") 158 .withDescription("output file") 159 .hasArg() 160 .withArgName("FILE") 161 .create("o"); 162 163 Option apiLevelOption = OptionBuilder.withLongOpt("api-level") 164 .withDescription("The numeric api-level of the file being disassembled. If not " + 165 "specified, it defaults to 15 (ICS).") 166 .hasArg() 167 .withArgName("API_LEVEL") 168 .create("a"); 169 170 options.addOption(classPathDirOption); 171 options.addOption(outputFileOption); 172 options.addOption(apiLevelOption); 173 } 174 } 175