baksmali.java revision 8eaecd53d39d14ee5edc52c49b15c4742a32742d
1/* 2 * [The "BSD licence"] 3 * Copyright (c) 2010 Ben Gruver (JesusFreke) 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29package org.jf.baksmali; 30 31import org.antlr.stringtemplate.StringTemplate; 32import org.antlr.stringtemplate.StringTemplateGroup; 33import org.jf.baksmali.Adaptors.ClassDefinition; 34import org.jf.baksmali.Renderers.*; 35import org.jf.dexlib.Code.Analysis.ClassPath; 36import org.jf.dexlib.DexFile; 37import org.jf.dexlib.ClassDefItem; 38import org.jf.dexlib.StringIdItem; 39 40import java.io.*; 41 42public class baksmali { 43 public static boolean noParameterRegisters = false; 44 public static boolean useLocalsDirective = false; 45 public static boolean useSequentialLabels = false; 46 public static boolean outputDebugInfo = true; 47 public static boolean addCodeOffsets = false; 48 public static boolean deodex = false; 49 public static boolean verify = false; 50 public static int registerInfo = 0; 51 public static String bootClassPath; 52 53 public static void disassembleDexFile(String dexFilePath, DexFile dexFile, boolean deodex, String outputDirectory, 54 String[] classPathDirs, String bootClassPath, boolean noParameterRegisters, 55 boolean useLocalsDirective, boolean useSequentialLabels, 56 boolean outputDebugInfo, boolean addCodeOffsets, int registerInfo, 57 boolean verify) 58 { 59 baksmali.noParameterRegisters = noParameterRegisters; 60 baksmali.useLocalsDirective = useLocalsDirective; 61 baksmali.useSequentialLabels = useSequentialLabels; 62 baksmali.outputDebugInfo = outputDebugInfo; 63 baksmali.addCodeOffsets = addCodeOffsets; 64 baksmali.deodex = deodex; 65 baksmali.registerInfo = registerInfo; 66 baksmali.bootClassPath = bootClassPath; 67 baksmali.verify = verify; 68 69 if (registerInfo != 0 || deodex || verify) { 70 try { 71 ClassPath.InitializeClassPath(classPathDirs, bootClassPath==null?null:bootClassPath.split(":"), 72 dexFilePath, dexFile); 73 } catch (Exception ex) { 74 System.err.println("\n\nError occured while loading boot class path files. Aborting."); 75 ex.printStackTrace(System.err); 76 System.exit(1); 77 } 78 } 79 80 File outputDirectoryFile = new File(outputDirectory); 81 if (!outputDirectoryFile.exists()) { 82 if (!outputDirectoryFile.mkdirs()) { 83 System.err.println("Can't create the output directory " + outputDirectory); 84 System.exit(1); 85 } 86 } 87 88 //load and initialize the templates 89 InputStream templateStream = baksmali.class.getClassLoader().getResourceAsStream("templates/baksmali.stg"); 90 StringTemplateGroup templates = new StringTemplateGroup(new InputStreamReader(templateStream)); 91 templates.registerRenderer(Long.class, new LongRenderer()); 92 templates.registerRenderer(Integer.class, new IntegerRenderer()); 93 templates.registerRenderer(Short.class, new ShortRenderer()); 94 templates.registerRenderer(Byte.class, new ByteRenderer()); 95 templates.registerRenderer(Float.class, new FloatRenderer()); 96 templates.registerRenderer(Character.class, new CharRenderer()); 97 templates.registerRenderer(StringIdItem.class, new StringIdItemRenderer()); 98 99 100 for (ClassDefItem classDefItem: dexFile.ClassDefsSection.getItems()) { 101 /** 102 * The path for the disassembly file is based on the package name 103 * The class descriptor will look something like: 104 * Ljava/lang/Object; 105 * Where the there is leading 'L' and a trailing ';', and the parts of the 106 * package name are separated by '/' 107 */ 108 109 String classDescriptor = classDefItem.getClassType().getTypeDescriptor(); 110 111 //validate that the descriptor is formatted like we expect 112 if (classDescriptor.charAt(0) != 'L' || 113 classDescriptor.charAt(classDescriptor.length()-1) != ';') { 114 System.err.println("Unrecognized class descriptor - " + classDescriptor + " - skipping class"); 115 continue; 116 } 117 118 //trim off the leading L and trailing ; 119 classDescriptor = classDescriptor.substring(1, classDescriptor.length()-1); 120 121 //trim off the leading 'L' and trailing ';', and get the individual package elements 122 String[] pathElements = classDescriptor.split("/"); 123 124 //build the path to the smali file to generate for this class 125 StringBuilder smaliPath = new StringBuilder(outputDirectory); 126 for (String pathElement: pathElements) { 127 smaliPath.append(File.separatorChar); 128 smaliPath.append(pathElement); 129 } 130 smaliPath.append(".smali"); 131 132 File smaliFile = new File(smaliPath.toString()); 133 134 //create and initialize the top level string template 135 ClassDefinition classDefinition = new ClassDefinition(templates, classDefItem); 136 137 StringTemplate smaliFileST = classDefinition.createTemplate(); 138 139 //generate the disassembly 140 String output = smaliFileST.toString(); 141 142 //write the disassembly 143 FileWriter writer = null; 144 try 145 { 146 File smaliParent = smaliFile.getParentFile(); 147 if (!smaliParent.exists()) { 148 if (!smaliParent.mkdirs()) { 149 System.err.println("Unable to create directory " + smaliParent.toString() + " - skipping class"); 150 continue; 151 } 152 } 153 154 if (!smaliFile.exists()){ 155 if (!smaliFile.createNewFile()) { 156 System.err.println("Unable to create file " + smaliFile.toString() + " - skipping class"); 157 continue; 158 } 159 } 160 161 writer = new FileWriter(smaliFile); 162 writer.write(output); 163 } catch (Exception ex) { 164 System.err.println("\n\nError occured while disassembling class " + classDescriptor.replace('/', '.') + " - skipping class"); 165 ex.printStackTrace(); 166 } 167 finally 168 { 169 if (writer != null) { 170 try { 171 writer.close(); 172 } catch (Throwable ex) { 173 System.err.println("\n\nError occured while closing file " + smaliFile.toString()); 174 ex.printStackTrace(); 175 } 176 } 177 } 178 179 //TODO: GROT 180 if (classDefinition.hadValidationErrors()) { 181 System.exit(1); 182 } 183 } 184 } 185} 186