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