| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.jf.baksmali; |
| |
| import org.apache.commons.cli.*; |
| import org.jf.dexlib.DexFile; |
| import org.jf.dexlib.Util.Deodexerant; |
| |
| import java.io.File; |
| import java.io.InputStream; |
| import java.io.IOException; |
| import java.util.Properties; |
| |
| public class main { |
| |
| public static final String VERSION; |
| |
| private static final Options options; |
| |
| static { |
| options = new Options(); |
| buildOptions(); |
| |
| InputStream templateStream = baksmali.class.getClassLoader().getResourceAsStream("baksmali.properties"); |
| Properties properties = new Properties(); |
| String version = "(unknown)"; |
| try { |
| properties.load(templateStream); |
| version = properties.getProperty("application.version"); |
| } catch (IOException ex) { |
| } |
| VERSION = version; |
| } |
| |
| /** |
| * This class is uninstantiable. |
| */ |
| private main() { |
| } |
| |
| /** |
| * Run! |
| */ |
| public static void main(String[] args) { |
| CommandLineParser parser = new PosixParser(); |
| CommandLine commandLine; |
| |
| try { |
| commandLine = parser.parse(options, args); |
| } catch (ParseException ex) { |
| usage(); |
| return; |
| } |
| |
| boolean disassemble = true; |
| boolean doDump = false; |
| boolean write = false; |
| boolean sort = false; |
| boolean fixRegisters = false; |
| boolean noParameterRegisters = false; |
| boolean useLocalsDirective = false; |
| boolean useIndexedLabels = false; |
| boolean outputDebugInfo = true; |
| |
| |
| String outputDirectory = "out"; |
| String dumpFileName = null; |
| String outputDexFileName = null; |
| String inputDexFileName = null; |
| String deodexerantHost = null; |
| int deodexerantPort = 0; |
| |
| String[] remainingArgs = commandLine.getArgs(); |
| |
| if (commandLine.hasOption("v")) { |
| version(); |
| return; |
| } |
| |
| if (commandLine.hasOption("?")) { |
| usage(); |
| return; |
| } |
| |
| if (remainingArgs.length != 1) { |
| usage(); |
| return; |
| } |
| |
| inputDexFileName = remainingArgs[0]; |
| |
| if (commandLine.hasOption("n")) { |
| disassemble = false; |
| } |
| |
| if (commandLine.hasOption("d")) { |
| doDump = true; |
| dumpFileName = commandLine.getOptionValue("d", inputDexFileName + ".dump"); |
| } |
| |
| if (commandLine.hasOption("w")) { |
| write = true; |
| outputDexFileName = commandLine.getOptionValue("w"); |
| } |
| |
| if (commandLine.hasOption("o")) { |
| outputDirectory = commandLine.getOptionValue("o"); |
| } |
| |
| if (commandLine.hasOption("s")) { |
| sort = true; |
| } |
| |
| if (commandLine.hasOption("f")) { |
| fixRegisters = true; |
| } |
| |
| if (commandLine.hasOption("p")) { |
| noParameterRegisters = true; |
| } |
| |
| if (commandLine.hasOption("l")) { |
| useLocalsDirective = true; |
| } |
| |
| if (commandLine.hasOption("i")) { |
| useIndexedLabels = true; |
| } |
| |
| if (commandLine.hasOption("b")) { |
| outputDebugInfo = false; |
| } |
| |
| if (commandLine.hasOption("x")) { |
| String deodexerantAddress = commandLine.getOptionValue("x"); |
| String[] parts = deodexerantAddress.split(":"); |
| if (parts.length != 2) { |
| System.err.println("Invalid deodexerant address. Expecting :<port> or <host>:<port>"); |
| System.exit(1); |
| } |
| |
| deodexerantHost = parts[0]; |
| if (deodexerantHost.length() == 0) { |
| deodexerantHost = "localhost"; |
| } |
| try { |
| deodexerantPort = Integer.parseInt(parts[1]); |
| } catch (NumberFormatException ex) { |
| System.err.println("Invalid port \"" + deodexerantPort + "\" for deodexerant address"); |
| System.exit(1); |
| } |
| } |
| |
| try { |
| File dexFileFile = new File(inputDexFileName); |
| if (!dexFileFile.exists()) { |
| System.err.println("Can't find the file " + inputDexFileName); |
| System.exit(1); |
| } |
| |
| //Read in and parse the dex file |
| DexFile dexFile = new DexFile(dexFileFile, !fixRegisters); |
| |
| Deodexerant deodexerant = null; |
| |
| |
| if (deodexerantHost != null) { |
| if (!dexFile.isOdex()) { |
| System.err.println("-x cannot be used with a normal dex file. Ignoring -x"); |
| } |
| deodexerant = new Deodexerant(dexFile, deodexerantHost, deodexerantPort); |
| } |
| |
| if (dexFile.isOdex()) { |
| if (doDump) { |
| System.err.println("-d cannot be used with on odex file. Ignoring -d"); |
| } |
| if (write) { |
| System.err.println("-w cannot be used with an odex file. Ignoring -w"); |
| } |
| } |
| |
| if (disassemble) { |
| baksmali.disassembleDexFile(dexFile, deodexerant, outputDirectory, noParameterRegisters, |
| useLocalsDirective, useIndexedLabels, outputDebugInfo); |
| } |
| |
| if ((doDump || write) && !dexFile.isOdex()) { |
| try |
| { |
| dump.dump(dexFile, dumpFileName, outputDexFileName, sort); |
| }catch (IOException ex) { |
| System.err.println("Error occured while writing dump file"); |
| ex.printStackTrace(); |
| } |
| } |
| } catch (RuntimeException ex) { |
| System.err.println("\n\nUNEXPECTED TOP-LEVEL EXCEPTION:"); |
| ex.printStackTrace(); |
| System.exit(1); |
| } catch (Throwable ex) { |
| System.err.println("\n\nUNEXPECTED TOP-LEVEL ERROR:"); |
| ex.printStackTrace(); |
| System.exit(1); |
| } |
| } |
| |
| /** |
| * Prints the usage message. |
| */ |
| private static void usage() { |
| HelpFormatter formatter = new HelpFormatter(); |
| formatter.printHelp("java -jar baksmali.jar [options] <dex-file>", |
| "disassembles and/or dumps a dex file", options, ""); |
| } |
| |
| /** |
| * Prints the version message. |
| */ |
| private static void version() { |
| System.out.println("baksmali " + VERSION + " (http://smali.googlecode.com)"); |
| System.out.println("Copyright (C) 2009 Ben Gruver"); |
| System.out.println("BSD license (http://www.opensource.org/licenses/bsd-license.php)"); |
| System.exit(0); |
| } |
| |
| private static void buildOptions() { |
| Option versionOption = OptionBuilder.withLongOpt("version") |
| .withDescription("prints the version then exits") |
| .create("v"); |
| |
| Option helpOption = OptionBuilder.withLongOpt("help") |
| .withDescription("prints the help message then exits") |
| .create("?"); |
| |
| Option noDisassemblyOption = OptionBuilder.withLongOpt("no-disassembly") |
| .withDescription("suppresses the output of the disassembly") |
| .create("n"); |
| |
| Option dumpOption = OptionBuilder.withLongOpt("dump-to") |
| .withDescription("dumps the given dex file into a single annotated dump file named FILE" + |
| " (<dexfile>.dump by default), along with the normal disassembly.") |
| .hasOptionalArg() |
| .withArgName("FILE") |
| .create("d"); |
| |
| Option writeDexOption = OptionBuilder.withLongOpt("write-dex") |
| .withDescription("additionally rewrites the input dex file to FILE") |
| .hasArg() |
| .withArgName("FILE") |
| .create("w"); |
| |
| Option outputDirOption = OptionBuilder.withLongOpt("output") |
| .withDescription("the directory where the disassembled files will be placed. The default is out") |
| .hasArg() |
| .withArgName("DIR") |
| .create("o"); |
| |
| Option sortOption = OptionBuilder.withLongOpt("sort") |
| .withDescription("sort the items in the dex file into a canonical order before dumping/writing") |
| .create("s"); |
| |
| Option fixSignedRegisterOption = OptionBuilder.withLongOpt("fix-signed-registers") |
| .withDescription("when dumping or rewriting, fix any registers in the debug info that are encoded as" + |
| " a signed value") |
| .create("f"); |
| |
| Option noParameterRegistersOption = OptionBuilder.withLongOpt("no-parameter-registers") |
| .withDescription("use the v<n> syntax instead of the p<n> syntax for registers mapped to method" + |
| " parameters") |
| .create("p"); |
| |
| Option deodexerantOption = OptionBuilder.withLongOpt("deodexerant") |
| .withDescription("connect to deodexerant on the specified HOST:PORT, and deodex the input odex" |
| + " file. This option is ignored if the input file is a dex file instead of an odex file") |
| .hasArg() |
| .withArgName("HOST:PORT") |
| .create("x"); |
| |
| Option useLocalsOption = OptionBuilder.withLongOpt("use-locals") |
| .withDescription("output the .locals directive with the number of non-parameter registers, rather" + |
| " than the .register directive with the total number of register") |
| .create("l"); |
| |
| Option indexedLabelsOption = OptionBuilder.withLongOpt("indexed-labels") |
| .withDescription("create label names using a per-method/per-label-type auto-index as the suffix, " + |
| " rather than the bytecode offset") |
| .create("i"); |
| |
| Option noDebugInfoOption = OptionBuilder.withLongOpt("no-debug-info") |
| .withDescription("don't write out debug info (.local, .param, .line, etc.)") |
| .create("b"); |
| |
| options.addOption(versionOption); |
| options.addOption(helpOption); |
| options.addOption(dumpOption); |
| options.addOption(noDisassemblyOption); |
| options.addOption(writeDexOption); |
| options.addOption(outputDirOption); |
| options.addOption(sortOption); |
| options.addOption(fixSignedRegisterOption); |
| options.addOption(noParameterRegistersOption); |
| options.addOption(deodexerantOption); |
| options.addOption(useLocalsOption); |
| options.addOption(indexedLabelsOption); |
| options.addOption(noDebugInfoOption); |
| } |
| } |