• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016, Google Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 package org.jf.baksmali;
33 
34 import com.beust.jcommander.JCommander;
35 import com.beust.jcommander.Parameter;
36 import com.beust.jcommander.Parameters;
37 import com.google.common.collect.Lists;
38 import org.jf.util.ConsoleUtil;
39 import org.jf.util.StringWrapper;
40 import org.jf.util.jcommander.*;
41 
42 import javax.annotation.Nonnull;
43 import java.util.List;
44 
45 @Parameters(commandDescription = "Shows usage information")
46 @ExtendedParameters(
47         commandName = "help",
48         commandAliases = "h")
49 public class HelpCommand extends Command {
50 
HelpCommand(@onnull List<JCommander> commandAncestors)51     public HelpCommand(@Nonnull List<JCommander> commandAncestors) {
52         super(commandAncestors);
53     }
54 
55     @Parameter(description = "If specified, show the detailed usage information for the given commands")
56     @ExtendedParameter(argumentNames = "commands")
57     private List<String> commands = Lists.newArrayList();
58 
run()59     public void run() {
60         JCommander parentJc = commandAncestors.get(commandAncestors.size() - 1);
61 
62         if (commands == null || commands.isEmpty()) {
63             System.out.println(new HelpFormatter()
64                     .width(ConsoleUtil.getConsoleWidth())
65                     .format(commandAncestors));
66         } else {
67             boolean printedHelp = false;
68             for (String cmd : commands) {
69                 if (cmd.equals("register-info")) {
70                     printedHelp = true;
71                     String registerInfoHelp = "The --register-info parameter will cause baksmali to generate " +
72                             "comments before and after every instruction containing register type " +
73                             "information about some subset of registers. This parameter accepts a comma-separated list" +
74                             "of values specifying which registers and how much information to include.\n" +
75                             "    ALL: all pre- and post-instruction registers\n" +
76                             "    ALLPRE: all pre-instruction registers\n" +
77                             "    ALLPOST: all post-instruction registers\n" +
78                             "    ARGS: any pre-instruction registers used as arguments to the instruction\n" +
79                             "    DEST: the post-instruction register used as the output of the instruction\n" +
80                             "    MERGE: any pre-instruction register that has been merged from multiple " +
81                             "incoming code paths\n" +
82                             "    FULLMERGE: an extended version of MERGE that also includes a list of all " +
83                             "the register types from incoming code paths that were merged";
84 
85                     Iterable<String> lines = StringWrapper.wrapStringOnBreaks(registerInfoHelp,
86                             ConsoleUtil.getConsoleWidth());
87                     for (String line : lines) {
88                         System.out.println(line);
89                     }
90                 } else if (cmd.equals("input")) {
91                     printedHelp = true;
92                     String registerInfoHelp = "Apks and oat files can contain multiple dex files. In order to " +
93                             "specify a particular dex file, the basic syntax is to treat the apk/oat file as a " +
94                             "directory. For example, to load the \"classes2.dex\" entry from \"app.apk\", you can " +
95                             "use \"app.apk/classes2.dex\".\n" +
96                             "\n" +
97                             "For ease of use, you can also specify a partial path to the dex file to load. For " +
98                             "example, to load a entry named \"/system/framework/framework.jar:classes2.dex\" from " +
99                             "\"framework.oat\", you can use any of the following:\n" +
100                             "\"framework.oat/classes2.dex\"\n" +
101                             "\"framework.oat/framework.jar:classes2.dex\"\n" +
102                             "\"framework.oat/framework/framework.jar:classes2.dex\"\n" +
103                             "\"framework.oat/system/framework/framework.jar:classes2.dex\"\n" +
104                             "\n" +
105                             "In some rare cases, an oat file could have entries that can't be differentiated with " +
106                             "the above syntax. For example \"/blah/blah.dex\" and \"blah/blah.dex\". In this case, " +
107                             "the \"blah.oat/blah/blah.dex\" would match both entries and generate an error. To get " +
108                             "around this, you can add double quotes around the entry name to specify an exact entry " +
109                             "name. E.g. blah.oat/\"/blah/blah.dex\" or blah.oat/\"blah/blah.dex\" respectively.";
110 
111                     Iterable<String> lines = StringWrapper.wrapStringOnBreaks(registerInfoHelp,
112                             ConsoleUtil.getConsoleWidth());
113                     for (String line : lines) {
114                         System.out.println(line);
115                     }
116                 } else if (cmd.equals("classpath")) {
117                     printedHelp = true;
118                     String registerInfoHelp = "When deodexing odex/oat files or when using the --register-info " +
119                             "option, baksmali needs to load all classes from the framework files on the device " +
120                             "in order to fully understand the class hierarchy. There are several options that " +
121                             "control how baksmali finds and loads the classpath entries.\n" +
122                             "\n"+
123                             "L+ devices (ART):\n" +
124                             "When deodexing or disassembling a file from an L+ device using ART, you generally " +
125                             "just need to specify the path to the boot.oat file via the --bootclasspath/-b " +
126                             "parameter. On pre-N devices, the boot.oat file is self-contained and no other files are " +
127                             "needed. In N, boot.oat was split into multiple files. In this case, the other " +
128                             "files should be in the same directory as the boot.oat file, but you still only need to " +
129                             "specify the boot.oat file in the --bootclasspath/-b option. The other files will be " +
130                             "automatically loaded from the same directory.\n" +
131                             "\n" +
132                             "Pre-L devices (dalvik):\n" +
133                             "When deodexing odex files from a pre-L device using dalvik, you " +
134                             "generally just need to specify the path to a directory containing the framework files " +
135                             "from the device via the --classpath-dir/-d option. odex files contain a list of " +
136                             "framework files they depend on and baksmali will search for these dependencies in the " +
137                             "directory that you specify.\n" +
138                             "\n" +
139                             "Dex files don't contain a list of dependencies like odex files, so when disassembling a " +
140                             "dex file using the --register-info option, and using the framework files from a " +
141                             "pre-L device, baksmali will attempt to use a reasonable default list of classpath files " +
142                             "based on the api level set via the -a option. If this default list is incorrect, you " +
143                             "can override the classpath using the --bootclasspath/-b option. This option accepts a " +
144                             "colon separated list of classpath entries. Each entry can be specified in a few " +
145                             "different ways.\n" +
146                             " - A simple filename like \"framework.jar\"\n" +
147                             " - A device path like \"/system/framework/framework.jar\"\n" +
148                             " - A local relative or absolute path like \"/tmp/framework/framework.jar\"\n" +
149                             "When using the first or second formats, you should also specify the directory " +
150                             "containing the framework files via the --classpath-dir/-d option. When using the third " +
151                             "format, this option is not needed.\n" +
152                             "It's worth noting that the second format matches the format used by Android for the " +
153                             "BOOTCLASSPATH environment variable, so you can simply grab the value of that variable " +
154                             "from the device and use it as-is.\n" +
155                             "\n" +
156                             "Examples:\n" +
157                             "  For an M device:\n" +
158                             "    adb pull /system/framework/arm/boot.oat /tmp/boot.oat\n" +
159                             "    baksmali deodex blah.oat -b /tmp/boot.oat\n" +
160                             "  For an N+ device:\n" +
161                             "    adb pull /system/framework/arm /tmp/framework\n" +
162                             "    baksmali deodex blah.oat -b /tmp/framework/boot.oat\n" +
163                             "  For a pre-L device:\n" +
164                             "    adb pull /system/framework /tmp/framework\n" +
165                             "    baksmali deodex blah.odex -d /tmp/framework\n" +
166                             "  Using the BOOTCLASSPATH on a pre-L device:\n" +
167                             "    adb pull /system/framework /tmp/framework\n" +
168                             "    export BOOTCLASSPATH=`adb shell \"echo \\\\$BOOTCLASPATH\"`\n" +
169                             "    baksmali disassemble --register-info ARGS,DEST blah.apk -b $BOOTCLASSPATH -d " +
170                             "/tmp/framework";
171 
172                     Iterable<String> lines = StringWrapper.wrapStringOnBreaks(registerInfoHelp,
173                             ConsoleUtil.getConsoleWidth());
174                     for (String line : lines) {
175                         System.out.println(line);
176                     }
177                 } else {
178                     JCommander command = ExtendedCommands.getSubcommand(parentJc, cmd);
179                     if (command == null) {
180                         System.err.println("No such command: " + cmd);
181                     } else {
182                         printedHelp = true;
183                         System.out.println(new HelpFormatter()
184                                 .width(ConsoleUtil.getConsoleWidth())
185                                 .format(((Command)command.getObjects().get(0)).getCommandHierarchy()));
186                     }
187                 }
188             }
189             if (!printedHelp) {
190                 System.out.println(new HelpFormatter()
191                         .width(ConsoleUtil.getConsoleWidth())
192                         .format(commandAncestors));
193             }
194         }
195     }
196 
197     @Parameters(hidden =  true)
198     @ExtendedParameters(commandName = "hlep")
199     public static class HlepCommand extends HelpCommand {
HlepCommand(@onnull List<JCommander> commandAncestors)200         public HlepCommand(@Nonnull List<JCommander> commandAncestors) {
201             super(commandAncestors);
202         }
203     }
204 }
205