main.java revision c9be5e13034da9827b5598a6257376164745b827
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package org.jf.baksmali; 18 19import org.apache.commons.cli.*; 20import org.jf.baksmali.Deodex.Deodexerant; 21import org.jf.dexlib.DexFile; 22 23import java.io.File; 24import java.io.InputStream; 25import java.io.IOException; 26import java.util.Properties; 27 28public class main { 29 30 public static final String VERSION; 31 32 private static final Options options; 33 34 static { 35 options = new Options(); 36 buildOptions(); 37 38 InputStream templateStream = baksmali.class.getClassLoader().getResourceAsStream("baksmali.properties"); 39 Properties properties = new Properties(); 40 String version = "(unknown)"; 41 try { 42 properties.load(templateStream); 43 version = properties.getProperty("application.version"); 44 } catch (IOException ex) { 45 } 46 VERSION = version; 47 } 48 49 /** 50 * This class is uninstantiable. 51 */ 52 private main() { 53 } 54 55 /** 56 * Run! 57 */ 58 public static void main(String[] args) { 59 CommandLineParser parser = new PosixParser(); 60 CommandLine commandLine; 61 62 try { 63 commandLine = parser.parse(options, args); 64 } catch (ParseException ex) { 65 usage(); 66 return; 67 } 68 69 boolean disassemble = true; 70 boolean doDump = false; 71 boolean write = false; 72 boolean sort = false; 73 boolean fixRegisters = false; 74 boolean noParameterRegisters = false; 75 boolean useLocalsDirective = false; 76 boolean useSequentialLabels = false; 77 boolean outputDebugInfo = true; 78 boolean verboseRegisterInfo = false; 79 80 String outputDirectory = "out"; 81 String dumpFileName = null; 82 String outputDexFileName = null; 83 String inputDexFileName = null; 84 String deodexerantHost = null; 85 String bootClassPath = "core.jar:ext.jar:framework.jar:android.policy.jar:services.jar"; 86 int deodexerantPort = 0; 87 88 String[] remainingArgs = commandLine.getArgs(); 89 90 if (commandLine.hasOption("v")) { 91 version(); 92 return; 93 } 94 95 if (commandLine.hasOption("?")) { 96 usage(); 97 return; 98 } 99 100 if (remainingArgs.length != 1) { 101 usage(); 102 return; 103 } 104 105 inputDexFileName = remainingArgs[0]; 106 107 if (commandLine.hasOption("n")) { 108 disassemble = false; 109 } 110 111 if (commandLine.hasOption("d")) { 112 doDump = true; 113 dumpFileName = commandLine.getOptionValue("d", inputDexFileName + ".dump"); 114 } 115 116 if (commandLine.hasOption("w")) { 117 write = true; 118 outputDexFileName = commandLine.getOptionValue("w"); 119 } 120 121 if (commandLine.hasOption("o")) { 122 outputDirectory = commandLine.getOptionValue("o"); 123 } 124 125 if (commandLine.hasOption("s")) { 126 sort = true; 127 } 128 129 if (commandLine.hasOption("f")) { 130 fixRegisters = true; 131 } 132 133 if (commandLine.hasOption("p")) { 134 noParameterRegisters = true; 135 } 136 137 if (commandLine.hasOption("l")) { 138 useLocalsDirective = true; 139 } 140 141 if (commandLine.hasOption("i")) { 142 useSequentialLabels = true; 143 } 144 145 if (commandLine.hasOption("b")) { 146 outputDebugInfo = false; 147 } 148 149 if (commandLine.hasOption("r")) { 150 verboseRegisterInfo = true; 151 } 152 153 if (commandLine.hasOption("c")) { 154 bootClassPath = commandLine.getOptionValue("c"); 155 } 156 157 if (commandLine.hasOption("x")) { 158 String deodexerantAddress = commandLine.getOptionValue("x"); 159 String[] parts = deodexerantAddress.split(":"); 160 if (parts.length != 2) { 161 System.err.println("Invalid deodexerant address. Expecting :<port> or <host>:<port>"); 162 System.exit(1); 163 } 164 165 deodexerantHost = parts[0]; 166 if (deodexerantHost.length() == 0) { 167 deodexerantHost = "localhost"; 168 } 169 try { 170 deodexerantPort = Integer.parseInt(parts[1]); 171 } catch (NumberFormatException ex) { 172 System.err.println("Invalid port \"" + deodexerantPort + "\" for deodexerant address"); 173 System.exit(1); 174 } 175 } 176 177 try { 178 File dexFileFile = new File(inputDexFileName); 179 if (!dexFileFile.exists()) { 180 System.err.println("Can't find the file " + inputDexFileName); 181 System.exit(1); 182 } 183 184 //Read in and parse the dex file 185 DexFile dexFile = new DexFile(dexFileFile, !fixRegisters); 186 187 Deodexerant deodexerant = null; 188 189 190 if (deodexerantHost != null) { 191 if (!dexFile.isOdex()) { 192 System.err.println("-x cannot be used with a normal dex file. Ignoring -x"); 193 } 194 deodexerant = new Deodexerant(dexFile, deodexerantHost, deodexerantPort); 195 } 196 197 if (dexFile.isOdex()) { 198 if (doDump) { 199 System.err.println("-d cannot be used with on odex file. Ignoring -d"); 200 } 201 if (write) { 202 System.err.println("-w cannot be used with an odex file. Ignoring -w"); 203 } 204 if (deodexerant == null) { 205 System.err.println("Warning: You are disassembling an odex file without deodexing it. You"); 206 System.err.println("won't be able to re-assemble the results unless you use deodexerant, and"); 207 System.err.println("the -x option for baksmali"); 208 } 209 } 210 211 if (disassemble) { 212 baksmali.disassembleDexFile(dexFile, deodexerant, outputDirectory, bootClassPath, noParameterRegisters, 213 useLocalsDirective, useSequentialLabels, outputDebugInfo, verboseRegisterInfo); 214 } 215 216 if ((doDump || write) && !dexFile.isOdex()) { 217 try 218 { 219 dump.dump(dexFile, dumpFileName, outputDexFileName, sort); 220 }catch (IOException ex) { 221 System.err.println("Error occured while writing dump file"); 222 ex.printStackTrace(); 223 } 224 } 225 } catch (RuntimeException ex) { 226 System.err.println("\n\nUNEXPECTED TOP-LEVEL EXCEPTION:"); 227 ex.printStackTrace(); 228 System.exit(1); 229 } catch (Throwable ex) { 230 System.err.println("\n\nUNEXPECTED TOP-LEVEL ERROR:"); 231 ex.printStackTrace(); 232 System.exit(1); 233 } 234 } 235 236 /** 237 * Prints the usage message. 238 */ 239 private static void usage() { 240 HelpFormatter formatter = new HelpFormatter(); 241 formatter.printHelp("java -jar baksmali.jar [options] <dex-file>", 242 "disassembles and/or dumps a dex file", options, ""); 243 } 244 245 /** 246 * Prints the version message. 247 */ 248 private static void version() { 249 System.out.println("baksmali " + VERSION + " (http://smali.googlecode.com)"); 250 System.out.println("Copyright (C) 2009 Ben Gruver"); 251 System.out.println("BSD license (http://www.opensource.org/licenses/bsd-license.php)"); 252 System.exit(0); 253 } 254 255 private static void buildOptions() { 256 Option versionOption = OptionBuilder.withLongOpt("version") 257 .withDescription("prints the version then exits") 258 .create("v"); 259 260 Option helpOption = OptionBuilder.withLongOpt("help") 261 .withDescription("prints the help message then exits") 262 .create("?"); 263 264 Option noDisassemblyOption = OptionBuilder.withLongOpt("no-disassembly") 265 .withDescription("suppresses the output of the disassembly") 266 .create("n"); 267 268 Option dumpOption = OptionBuilder.withLongOpt("dump-to") 269 .withDescription("dumps the given dex file into a single annotated dump file named FILE" + 270 " (<dexfile>.dump by default), along with the normal disassembly.") 271 .hasOptionalArg() 272 .withArgName("FILE") 273 .create("d"); 274 275 Option writeDexOption = OptionBuilder.withLongOpt("write-dex") 276 .withDescription("additionally rewrites the input dex file to FILE") 277 .hasArg() 278 .withArgName("FILE") 279 .create("w"); 280 281 Option outputDirOption = OptionBuilder.withLongOpt("output") 282 .withDescription("the directory where the disassembled files will be placed. The default is out") 283 .hasArg() 284 .withArgName("DIR") 285 .create("o"); 286 287 Option sortOption = OptionBuilder.withLongOpt("sort") 288 .withDescription("sort the items in the dex file into a canonical order before dumping/writing") 289 .create("s"); 290 291 Option fixSignedRegisterOption = OptionBuilder.withLongOpt("fix-signed-registers") 292 .withDescription("when dumping or rewriting, fix any registers in the debug info that are encoded as" + 293 " a signed value") 294 .create("f"); 295 296 Option noParameterRegistersOption = OptionBuilder.withLongOpt("no-parameter-registers") 297 .withDescription("use the v<n> syntax instead of the p<n> syntax for registers mapped to method" + 298 " parameters") 299 .create("p"); 300 301 Option deodexerantOption = OptionBuilder.withLongOpt("deodexerant") 302 .withDescription("connect to deodexerant on the specified HOST:PORT, and deodex the input odex" 303 + " file. This option is ignored if the input file is a dex file instead of an odex file") 304 .hasArg() 305 .withArgName("HOST:PORT") 306 .create("x"); 307 308 Option useLocalsOption = OptionBuilder.withLongOpt("use-locals") 309 .withDescription("output the .locals directive with the number of non-parameter registers, rather" + 310 " than the .register directive with the total number of register") 311 .create("l"); 312 313 Option sequentialLabelsOption = OptionBuilder.withLongOpt("sequential-labels") 314 .withDescription("create label names using a sequential numbering scheme per label type, rather than " + 315 "using the bytecode address") 316 .create("q"); 317 318 Option noDebugInfoOption = OptionBuilder.withLongOpt("no-debug-info") 319 .withDescription("don't write out debug info (.local, .param, .line, etc.)") 320 .create("b"); 321 322 Option verboseRegisterInfoOption = OptionBuilder.withLongOpt("verbose-registers") 323 .withDescription("print verbose register type information for each instruction") 324 .create("r"); 325 326 Option classPathOption = OptionBuilder.withLongOpt("bootclasspath") 327 .withDescription("the bootclasspath jars to use, for analysis") 328 .hasOptionalArg() 329 .withArgName("BOOTCLASSPATH") 330 .create("c"); 331 332 options.addOption(versionOption); 333 options.addOption(helpOption); 334 options.addOption(dumpOption); 335 options.addOption(noDisassemblyOption); 336 options.addOption(writeDexOption); 337 options.addOption(outputDirOption); 338 options.addOption(sortOption); 339 options.addOption(fixSignedRegisterOption); 340 options.addOption(noParameterRegistersOption); 341 options.addOption(deodexerantOption); 342 options.addOption(useLocalsOption); 343 options.addOption(sequentialLabelsOption); 344 options.addOption(noDebugInfoOption); 345 options.addOption(verboseRegisterInfoOption); 346 options.addOption(classPathOption); 347 } 348}