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