baksmali.java revision 630f5dc2dcaa811410ae1f9209e377d2e89d8e5c
1/* 2 * [The "BSD licence"] 3 * Copyright (c) 2009 Ben Gruver 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.DexFile; 36import org.jf.dexlib.ClassDefItem; 37import org.jf.dexlib.StringIdItem; 38import org.jf.dexlib.Util.Deodexerant; 39import org.jf.dexlib.Util.DeodexUtil; 40 41import java.io.*; 42 43public class baksmali { 44 public static boolean noParameterRegisters = false; 45 public static boolean useLocalsDirective = false; 46 public static boolean useIndexedLabels = false; 47 public static boolean outputDebugInfo = true; 48 public static DeodexUtil deodexUtil = null; 49 50 public static void disassembleDexFile(DexFile dexFile, Deodexerant deodexerant, String outputDirectory, 51 boolean noParameterRegisters, boolean useLocalsDirective, 52 boolean useIndexedLabels, boolean outputDebugInfo) 53 { 54 baksmali.noParameterRegisters = noParameterRegisters; 55 baksmali.useLocalsDirective = useLocalsDirective; 56 baksmali.useIndexedLabels = useIndexedLabels; 57 baksmali.outputDebugInfo = outputDebugInfo; 58 59 if (deodexerant != null) { 60 baksmali.deodexUtil = new DeodexUtil(deodexerant); 61 } 62 63 File outputDirectoryFile = new File(outputDirectory); 64 if (!outputDirectoryFile.exists()) { 65 if (!outputDirectoryFile.mkdirs()) { 66 System.err.println("Can't create the output directory " + outputDirectory); 67 System.exit(1); 68 } 69 } 70 71 //load and initialize the templates 72 InputStream templateStream = baksmali.class.getClassLoader().getResourceAsStream("templates/baksmali.stg"); 73 StringTemplateGroup templates = new StringTemplateGroup(new InputStreamReader(templateStream)); 74 templates.registerRenderer(Long.class, new LongRenderer()); 75 templates.registerRenderer(Integer.class, new IntegerRenderer()); 76 templates.registerRenderer(Short.class, new ShortRenderer()); 77 templates.registerRenderer(Byte.class, new ByteRenderer()); 78 templates.registerRenderer(Float.class, new FloatRenderer()); 79 templates.registerRenderer(Character.class, new CharRenderer()); 80 templates.registerRenderer(StringIdItem.class, new StringIdItemRenderer()); 81 82 83 for (ClassDefItem classDefItem: dexFile.ClassDefsSection.getItems()) { 84 /** 85 * The path for the disassembly file is based on the package name 86 * The class descriptor will look something like: 87 * Ljava/lang/Object; 88 * Where the there is leading 'L' and a trailing ';', and the parts of the 89 * package name are separated by '/' 90 */ 91 92 String classDescriptor = classDefItem.getClassType().getTypeDescriptor(); 93 94 //validate that the descriptor is formatted like we expect 95 if (classDescriptor.charAt(0) != 'L' || 96 classDescriptor.charAt(classDescriptor.length()-1) != ';') { 97 System.err.println("Unrecognized class descriptor - " + classDescriptor + " - skipping class"); 98 continue; 99 } 100 101 //trim off the leading L and trailing ; 102 classDescriptor = classDescriptor.substring(1, classDescriptor.length()-1); 103 104 //trim off the leading 'L' and trailing ';', and get the individual package elements 105 String[] pathElements = classDescriptor.split("/"); 106 107 //build the path to the smali file to generate for this class 108 StringBuilder smaliPath = new StringBuilder(outputDirectory); 109 for (String pathElement: pathElements) { 110 smaliPath.append(File.separatorChar); 111 smaliPath.append(pathElement); 112 } 113 smaliPath.append(".smali"); 114 115 File smaliFile = new File(smaliPath.toString()); 116 117 //create and initialize the top level string template 118 ClassDefinition classDefinition = new ClassDefinition(templates, classDefItem); 119 120 StringTemplate smaliFileST = classDefinition.makeTemplate(); 121 122 //generate the disassembly 123 String output = smaliFileST.toString(); 124 125 //write the disassembly 126 FileWriter writer = null; 127 try 128 { 129 File smaliParent = smaliFile.getParentFile(); 130 if (!smaliParent.exists()) { 131 if (!smaliParent.mkdirs()) { 132 System.err.println("Unable to create directory " + smaliParent.toString() + " - skipping class"); 133 continue; 134 } 135 } 136 137 if (!smaliFile.exists()){ 138 if (!smaliFile.createNewFile()) { 139 System.err.println("Unable to create file " + smaliFile.toString() + " - skipping class"); 140 continue; 141 } 142 } 143 144 writer = new FileWriter(smaliFile); 145 writer.write(output); 146 } catch (Throwable ex) { 147 System.err.println("\n\nError occured while disassembling class " + classDescriptor.replace('/', '.') + " - skipping class"); 148 ex.printStackTrace(); 149 } 150 finally 151 { 152 if (writer != null) { 153 try { 154 writer.close(); 155 } catch (Throwable ex) { 156 System.err.println("\n\nError occured while closing file " + smaliFile.toString()); 157 ex.printStackTrace(); 158 } 159 } 160 } 161 } 162 } 163} 164