mirror of
https://github.com/revanced/smali.git
synced 2025-05-02 07:34:28 +02:00
Add "list field offsets" and "list vtables" commands to baksmali
This is a reimplementation of the "DumpFields" and "DumpVtables" entry points that were previously in dexlib2
This commit is contained in:
parent
75cf7e4c64
commit
bccdc809fa
@ -59,6 +59,8 @@ public class ListCommand implements Command {
|
||||
subJc.addCommand("types", new ListTypesCommand(subJc), "type", "t");
|
||||
subJc.addCommand("classes", new ListClassesCommand(subJc), "class", "c");
|
||||
subJc.addCommand("dex", new ListDexCommand(subJc), "d");
|
||||
subJc.addCommand("vtables", new ListVtablesCommand(subJc), "vtable", "v");
|
||||
subJc.addCommand("fieldoffsets", new ListFieldOffsetsCommand(subJc), "fieldoffset", "fo");
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
|
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2016, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.jf.baksmali;
|
||||
|
||||
import com.beust.jcommander.JCommander;
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jf.dexlib2.analysis.ClassPath;
|
||||
import org.jf.dexlib2.analysis.ClassProto;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
||||
import org.jf.dexlib2.iface.ClassDef;
|
||||
import org.jf.dexlib2.iface.DexFile;
|
||||
import org.jf.dexlib2.iface.reference.FieldReference;
|
||||
import org.jf.util.SparseArray;
|
||||
import org.jf.util.jcommander.CommaColonParameterSplitter;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Parameters(commandDescription = "Lists the instance field offsets for classes in a dex file.")
|
||||
public class ListFieldOffsetsCommand extends DexInputCommand {
|
||||
|
||||
@Nonnull private final JCommander jc;
|
||||
|
||||
@Parameter(names = {"-h", "-?", "--help"}, help = true,
|
||||
description = "Show usage information")
|
||||
private boolean help;
|
||||
|
||||
@Parameter(names = {"-a", "--api"},
|
||||
description = "The numeric api level of the file being loaded.")
|
||||
private int apiLevel = 15;
|
||||
|
||||
@Parameter(description = "<file> - A dex/apk/oat/odex file. For apk or oat files that contain multiple dex " +
|
||||
"files, you can specify which dex file to disassemble by appending the name of the dex file with a " +
|
||||
"colon. E.g. \"something.apk:classes2.dex\"")
|
||||
private List<String> inputList = Lists.newArrayList();
|
||||
|
||||
@Parameter(names = {"-b", "--bootclasspath"},
|
||||
description = "A comma/colon separated list of the bootclasspath jar/oat files to include in the " +
|
||||
"classpath when analyzing the dex file. This will override any automatic selection of " +
|
||||
"bootclasspath files that baksmali would otherwise perform. This is analogous to Android's " +
|
||||
"BOOTCLASSPATH environment variable.",
|
||||
splitter = CommaColonParameterSplitter.class)
|
||||
private List<String> bootClassPath = new ArrayList<String>();
|
||||
|
||||
@Parameter(names = {"-c", "--classpath"},
|
||||
description = "A comma/colon separated list of additional jar/oat files to include in the classpath " +
|
||||
"when analyzing the dex file. These will be added to the classpath after any bootclasspath " +
|
||||
"entries.",
|
||||
splitter = CommaColonParameterSplitter.class)
|
||||
private List<String> classPath = new ArrayList<String>();
|
||||
|
||||
@Parameter(names = {"-d", "--classpath-dir"},
|
||||
description = "baksmali will search these directories in order for any classpath entries.")
|
||||
private List<String> classPathDirectories = Lists.newArrayList(".");
|
||||
|
||||
@Parameter(names = "--check-package-private-access",
|
||||
description = "Use the package-private access check when calculating vtable indexes. This should " +
|
||||
"only be needed for 4.2.0 odexes. It was reverted in 4.2.1.")
|
||||
private boolean checkPackagePrivateAccess = false;
|
||||
|
||||
@Parameter(names = "--experimental",
|
||||
description = "Enable experimental opcodes to be disassembled, even if they aren't necessarily " +
|
||||
"supported in the Android runtime yet.")
|
||||
private boolean experimentalOpcodes = false;
|
||||
|
||||
public ListFieldOffsetsCommand(@Nonnull JCommander jc) {
|
||||
this.jc = jc;
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
if (help || inputList == null || inputList.isEmpty()) {
|
||||
jc.usage(jc.getParsedCommand());
|
||||
return;
|
||||
}
|
||||
|
||||
if (inputList.size() > 1) {
|
||||
System.err.println("Too many files specified");
|
||||
jc.usage(jc.getParsedCommand());
|
||||
return;
|
||||
}
|
||||
|
||||
String input = inputList.get(0);
|
||||
DexBackedDexFile dexFile = loadDexFile(input, 15, false);
|
||||
BaksmaliOptions options = getOptions(dexFile);
|
||||
|
||||
try {
|
||||
for (ClassDef classDef: dexFile.getClasses()) {
|
||||
ClassProto classProto = (ClassProto) options.classPath.getClass(classDef);
|
||||
SparseArray<FieldReference> fields = classProto.getInstanceFields();
|
||||
String className = "Class " + classDef.getType() + " : " + fields.size() + " instance fields\n";
|
||||
System.out.write(className.getBytes());
|
||||
for (int i=0;i<fields.size();i++) {
|
||||
String field = fields.keyAt(i) + ":" + fields.valueAt(i).getType() + " " + fields.valueAt(i).getName() + "\n";
|
||||
System.out.write(field.getBytes());
|
||||
}
|
||||
System.out.write("\n".getBytes());
|
||||
}
|
||||
System.out.close();
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private BaksmaliOptions getOptions(DexFile dexFile) {
|
||||
final BaksmaliOptions options = new BaksmaliOptions();
|
||||
|
||||
options.apiLevel = apiLevel;
|
||||
|
||||
try {
|
||||
options.classPath = ClassPath.fromClassPath(classPathDirectories,
|
||||
Iterables.concat(bootClassPath, classPath), dexFile, apiLevel,
|
||||
checkPackagePrivateAccess, experimentalOpcodes);
|
||||
} catch (Exception ex) {
|
||||
System.err.println("Error occurred while loading class path files.");
|
||||
ex.printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
options.experimentalOpcodes = experimentalOpcodes;
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
165
baksmali/src/main/java/org/jf/baksmali/ListVtablesCommand.java
Normal file
165
baksmali/src/main/java/org/jf/baksmali/ListVtablesCommand.java
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2016, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.jf.baksmali;
|
||||
|
||||
import com.beust.jcommander.JCommander;
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jf.dexlib2.analysis.ClassPath;
|
||||
import org.jf.dexlib2.analysis.ClassProto;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
||||
import org.jf.dexlib2.iface.ClassDef;
|
||||
import org.jf.dexlib2.iface.DexFile;
|
||||
import org.jf.dexlib2.iface.Method;
|
||||
import org.jf.util.jcommander.CommaColonParameterSplitter;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Parameters(commandDescription = "Lists the virtual method tables for classes in a dex file.")
|
||||
public class ListVtablesCommand extends DexInputCommand {
|
||||
|
||||
@Nonnull private final JCommander jc;
|
||||
|
||||
@Parameter(names = {"-h", "-?", "--help"}, help = true,
|
||||
description = "Show usage information")
|
||||
private boolean help;
|
||||
|
||||
@Parameter(names = {"-a", "--api"},
|
||||
description = "The numeric api level of the file being loaded.")
|
||||
public int apiLevel = 15;
|
||||
|
||||
@Parameter(description = "<file> - A dex/apk/oat/odex file. For apk or oat files that contain multiple dex " +
|
||||
"files, you can specify which dex file to disassemble by appending the name of the dex file with a " +
|
||||
"colon. E.g. \"something.apk:classes2.dex\"")
|
||||
private List<String> inputList = Lists.newArrayList();
|
||||
|
||||
@Parameter(names = {"-b", "--bootclasspath"},
|
||||
description = "A comma/colon separated list of the bootclasspath jar/oat files to include in the " +
|
||||
"classpath when analyzing the dex file. This will override any automatic selection of " +
|
||||
"bootclasspath files that baksmali would otherwise perform. This is analogous to Android's " +
|
||||
"BOOTCLASSPATH environment variable.",
|
||||
splitter = CommaColonParameterSplitter.class)
|
||||
private List<String> bootClassPath = new ArrayList<String>();
|
||||
|
||||
@Parameter(names = {"-c", "--classpath"},
|
||||
description = "A comma/colon separated list of additional jar/oat files to include in the classpath " +
|
||||
"when analyzing the dex file. These will be added to the classpath after any bootclasspath " +
|
||||
"entries.",
|
||||
splitter = CommaColonParameterSplitter.class)
|
||||
private List<String> classPath = new ArrayList<String>();
|
||||
|
||||
@Parameter(names = {"-d", "--classpath-dir"},
|
||||
description = "baksmali will search these directories in order for any classpath entries.")
|
||||
private List<String> classPathDirectories = Lists.newArrayList(".");
|
||||
|
||||
@Parameter(names = "--check-package-private-access",
|
||||
description = "Use the package-private access check when calculating vtable indexes. This should " +
|
||||
"only be needed for 4.2.0 odexes. It was reverted in 4.2.1.")
|
||||
private boolean checkPackagePrivateAccess = false;
|
||||
|
||||
@Parameter(names = "--experimental",
|
||||
description = "Enable experimental opcodes to be disassembled, even if they aren't necessarily " +
|
||||
"supported in the Android runtime yet.")
|
||||
private boolean experimentalOpcodes = false;
|
||||
|
||||
public ListVtablesCommand(@Nonnull JCommander jc) {
|
||||
this.jc = jc;
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
if (help || inputList == null || inputList.isEmpty()) {
|
||||
jc.usage(jc.getParsedCommand());
|
||||
return;
|
||||
}
|
||||
|
||||
if (inputList.size() > 1) {
|
||||
System.err.println("Too many files specified");
|
||||
jc.usage(jc.getParsedCommand());
|
||||
return;
|
||||
}
|
||||
|
||||
String input = inputList.get(0);
|
||||
DexBackedDexFile dexFile = loadDexFile(input, 15, false);
|
||||
|
||||
BaksmaliOptions options = getOptions(dexFile);
|
||||
if (options == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
for (ClassDef classDef : dexFile.getClasses()) {
|
||||
ClassProto classProto = (ClassProto) options.classPath.getClass(classDef);
|
||||
List<Method> methods = classProto.getVtable();
|
||||
String className = "Class " + classDef.getType() + " extends " + classDef.getSuperclass() + " : " + methods.size() + " methods\n";
|
||||
System.out.write(className.getBytes());
|
||||
for (int i = 0; i < methods.size(); i++) {
|
||||
Method method = methods.get(i);
|
||||
|
||||
String methodString = i + ":" + method.getDefiningClass() + "->" + method.getName() + "(";
|
||||
for (CharSequence parameter : method.getParameterTypes()) {
|
||||
methodString += parameter;
|
||||
}
|
||||
methodString += ")" + method.getReturnType() + "\n";
|
||||
System.out.write(methodString.getBytes());
|
||||
}
|
||||
System.out.write("\n".getBytes());
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected BaksmaliOptions getOptions(DexFile dexFile) {
|
||||
final BaksmaliOptions options = new BaksmaliOptions();
|
||||
|
||||
options.apiLevel = apiLevel;
|
||||
|
||||
try {
|
||||
options.classPath = ClassPath.fromClassPath(classPathDirectories,
|
||||
Iterables.concat(bootClassPath, classPath), dexFile, apiLevel,
|
||||
checkPackagePrivateAccess, experimentalOpcodes);
|
||||
} catch (Exception ex) {
|
||||
System.err.println("Error occurred while loading class path files.");
|
||||
ex.printStackTrace(System.err);
|
||||
return null;
|
||||
}
|
||||
|
||||
options.experimentalOpcodes = experimentalOpcodes;
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
@ -104,7 +104,6 @@ subprojects {
|
||||
antlr_runtime: 'org.antlr:antlr-runtime:3.5.2',
|
||||
antlr: 'org.antlr:antlr:3.5.2',
|
||||
stringtemplate: 'org.antlr:stringtemplate:3.2.1',
|
||||
commons_cli: 'commons-cli:commons-cli:1.2',
|
||||
jflex: 'de.jflex:jflex:1.4.3',
|
||||
jflex_plugin: 'co.tomlee.gradle.plugins:gradle-jflex-plugin:0.0.2',
|
||||
proguard_gradle: 'net.sf.proguard:proguard-gradle:5.2.1',
|
||||
|
@ -49,7 +49,6 @@ dependencies {
|
||||
compile project(':util')
|
||||
compile depends.findbugs
|
||||
compile depends.guava
|
||||
compile depends.commons_cli
|
||||
|
||||
testCompile depends.junit
|
||||
|
||||
|
@ -373,7 +373,7 @@ public class ClassProto implements TypeProto {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Nonnull SparseArray<FieldReference> getInstanceFields() {
|
||||
@Nonnull public SparseArray<FieldReference> getInstanceFields() {
|
||||
if (classPath.isArt()) {
|
||||
return artInstanceFieldsSupplier.get();
|
||||
} else {
|
||||
@ -759,7 +759,7 @@ public class ClassProto implements TypeProto {
|
||||
throw new ExceptionWithContext("Invalid type: %s", type);
|
||||
}
|
||||
|
||||
@Nonnull List<Method> getVtable() {
|
||||
@Nonnull public List<Method> getVtable() {
|
||||
return vtableSupplier.get();
|
||||
}
|
||||
|
||||
|
@ -1,180 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.jf.dexlib2.analysis;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.cli.*;
|
||||
import org.jf.dexlib2.DexFileFactory;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
||||
import org.jf.dexlib2.iface.ClassDef;
|
||||
import org.jf.dexlib2.iface.Field;
|
||||
import org.jf.dexlib2.iface.Method;
|
||||
import org.jf.dexlib2.iface.reference.FieldReference;
|
||||
import org.jf.util.ConsoleUtil;
|
||||
import org.jf.util.SparseArray;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class DumpFields {
|
||||
private static final Options options;
|
||||
|
||||
static {
|
||||
options = new Options();
|
||||
buildOptions();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
CommandLineParser parser = new PosixParser();
|
||||
CommandLine commandLine;
|
||||
|
||||
try {
|
||||
commandLine = parser.parse(options, args);
|
||||
} catch (ParseException ex) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
String[] remainingArgs = commandLine.getArgs();
|
||||
|
||||
Option[] parsedOptions = commandLine.getOptions();
|
||||
ArrayList<String> bootClassPathDirs = Lists.newArrayList();
|
||||
String outFile = "fields.txt";
|
||||
int apiLevel = 15;
|
||||
boolean experimental = false;
|
||||
|
||||
for (int i=0; i<parsedOptions.length; i++) {
|
||||
Option option = parsedOptions[i];
|
||||
String opt = option.getOpt();
|
||||
|
||||
switch (opt.charAt(0)) {
|
||||
case 'd':
|
||||
bootClassPathDirs.add(option.getValue());
|
||||
break;
|
||||
case 'o':
|
||||
outFile = option.getValue();
|
||||
break;
|
||||
case 'a':
|
||||
apiLevel = Integer.parseInt(commandLine.getOptionValue("a"));
|
||||
break;
|
||||
case 'X':
|
||||
experimental = true;
|
||||
break;
|
||||
default:
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
|
||||
if (remainingArgs.length != 1) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
String inputDexFileName = remainingArgs[0];
|
||||
|
||||
File dexFileFile = new File(inputDexFileName);
|
||||
if (!dexFileFile.exists()) {
|
||||
System.err.println("Can't find the file " + inputDexFileName);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
DexBackedDexFile dexFile = DexFileFactory.loadDexFile(dexFileFile, apiLevel, experimental);
|
||||
Iterable<String> bootClassPaths = Splitter.on(":").split("core.jar:ext.jar:framework.jar:android.policy.jar:services.jar");
|
||||
ClassPath classPath = ClassPath.fromClassPath(bootClassPathDirs, bootClassPaths, dexFile, apiLevel, experimental);
|
||||
FileOutputStream outStream = new FileOutputStream(outFile);
|
||||
|
||||
for (ClassDef classDef: dexFile.getClasses()) {
|
||||
ClassProto classProto = (ClassProto) classPath.getClass(classDef);
|
||||
SparseArray<FieldReference> fields = classProto.getInstanceFields();
|
||||
String className = "Class " + classDef.getType() + " : " + fields.size() + " instance fields\n";
|
||||
outStream.write(className.getBytes());
|
||||
for (int i=0;i<fields.size();i++) {
|
||||
String field = fields.keyAt(i) + ":" + fields.valueAt(i).getType() + " " + fields.valueAt(i).getName() + "\n";
|
||||
outStream.write(field.getBytes());
|
||||
}
|
||||
outStream.write("\n".getBytes());
|
||||
}
|
||||
outStream.close();
|
||||
} catch (IOException ex) {
|
||||
System.out.println("IOException thrown when trying to open a dex file or write out vtables: " + ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the usage message.
|
||||
*/
|
||||
private static void usage() {
|
||||
int consoleWidth = ConsoleUtil.getConsoleWidth();
|
||||
if (consoleWidth <= 0) {
|
||||
consoleWidth = 80;
|
||||
}
|
||||
|
||||
System.out.println("java -cp baksmali.jar org.jf.dexlib2.analysis.DumpFields -d path/to/framework/jar/files <dex-file>");
|
||||
}
|
||||
|
||||
private static void buildOptions() {
|
||||
Option classPathDirOption = OptionBuilder.withLongOpt("bootclasspath-dir")
|
||||
.withDescription("the base folder to look for the bootclasspath files in. Defaults to the current " +
|
||||
"directory")
|
||||
.hasArg()
|
||||
.withArgName("DIR")
|
||||
.create("d");
|
||||
|
||||
Option outputFileOption = OptionBuilder.withLongOpt("out-file")
|
||||
.withDescription("output file")
|
||||
.hasArg()
|
||||
.withArgName("FILE")
|
||||
.create("o");
|
||||
|
||||
Option apiLevelOption = OptionBuilder.withLongOpt("api-level")
|
||||
.withDescription("The numeric api-level of the file being disassembled. If not " +
|
||||
"specified, it defaults to 15 (ICS).")
|
||||
.hasArg()
|
||||
.withArgName("API_LEVEL")
|
||||
.create("a");
|
||||
|
||||
Option experimentalOption = OptionBuilder.withLongOpt("experimental")
|
||||
.withDescription("Enable dumping experimental opcodes, that aren't necessarily " +
|
||||
"supported by the android runtime yet.")
|
||||
.create("X");
|
||||
|
||||
options.addOption(classPathDirOption);
|
||||
options.addOption(outputFileOption);
|
||||
options.addOption(apiLevelOption);
|
||||
options.addOption(experimentalOption);
|
||||
}
|
||||
}
|
@ -1,184 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.jf.dexlib2.analysis;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.cli.*;
|
||||
import org.jf.dexlib2.DexFileFactory;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
||||
import org.jf.dexlib2.iface.ClassDef;
|
||||
import org.jf.dexlib2.iface.Method;
|
||||
import org.jf.util.ConsoleUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DumpVtables {
|
||||
private static final Options options;
|
||||
|
||||
static {
|
||||
options = new Options();
|
||||
buildOptions();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
CommandLineParser parser = new PosixParser();
|
||||
CommandLine commandLine;
|
||||
|
||||
try {
|
||||
commandLine = parser.parse(options, args);
|
||||
} catch (ParseException ex) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
String[] remainingArgs = commandLine.getArgs();
|
||||
|
||||
Option[] parsedOptions = commandLine.getOptions();
|
||||
ArrayList<String> bootClassPathDirs = Lists.newArrayList();
|
||||
String outFile = "vtables.txt";
|
||||
int apiLevel = 15;
|
||||
boolean experimental = false;
|
||||
|
||||
for (int i=0; i<parsedOptions.length; i++) {
|
||||
Option option = parsedOptions[i];
|
||||
String opt = option.getOpt();
|
||||
|
||||
switch (opt.charAt(0)) {
|
||||
case 'd':
|
||||
bootClassPathDirs.add(option.getValue());
|
||||
break;
|
||||
case 'o':
|
||||
outFile = option.getValue();
|
||||
break;
|
||||
case 'a':
|
||||
apiLevel = Integer.parseInt(commandLine.getOptionValue("a"));
|
||||
break;
|
||||
case 'X':
|
||||
experimental = true;
|
||||
break;
|
||||
default:
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
|
||||
if (remainingArgs.length != 1) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
String inputDexFileName = remainingArgs[0];
|
||||
|
||||
File dexFileFile = new File(inputDexFileName);
|
||||
if (!dexFileFile.exists()) {
|
||||
System.err.println("Can't find the file " + inputDexFileName);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
DexBackedDexFile dexFile = DexFileFactory.loadDexFile(dexFileFile, apiLevel, experimental);
|
||||
Iterable<String> bootClassPaths = Splitter.on(":").split("core.jar:ext.jar:framework.jar:android.policy.jar:services.jar");
|
||||
ClassPath classPath = ClassPath.fromClassPath(bootClassPathDirs, bootClassPaths, dexFile, apiLevel, experimental);
|
||||
FileOutputStream outStream = new FileOutputStream(outFile);
|
||||
|
||||
for (ClassDef classDef: dexFile.getClasses()) {
|
||||
ClassProto classProto = (ClassProto) classPath.getClass(classDef);
|
||||
List<Method> methods = classProto.getVtable();
|
||||
String className = "Class " + classDef.getType() + " extends " + classDef.getSuperclass() + " : " + methods.size() + " methods\n";
|
||||
outStream.write(className.getBytes());
|
||||
for (int i=0;i<methods.size();i++) {
|
||||
Method method = methods.get(i);
|
||||
|
||||
String methodString = i + ":" + method.getDefiningClass() + "->" + method.getName() + "(";
|
||||
for (CharSequence parameter: method.getParameterTypes()) {
|
||||
methodString += parameter;
|
||||
}
|
||||
methodString += ")" + method.getReturnType() + "\n";
|
||||
outStream.write(methodString.getBytes());
|
||||
}
|
||||
outStream.write("\n".getBytes());
|
||||
}
|
||||
outStream.close();
|
||||
} catch (IOException ex) {
|
||||
System.out.println("IOException thrown when trying to open a dex file or write out vtables: " + ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the usage message.
|
||||
*/
|
||||
private static void usage() {
|
||||
int consoleWidth = ConsoleUtil.getConsoleWidth();
|
||||
if (consoleWidth <= 0) {
|
||||
consoleWidth = 80;
|
||||
}
|
||||
|
||||
System.out.println("java -cp baksmali.jar org.jf.dexlib2.analysis.DumpVtables -d path/to/framework/jar/files <dex-file>");
|
||||
}
|
||||
|
||||
private static void buildOptions() {
|
||||
Option classPathDirOption = OptionBuilder.withLongOpt("bootclasspath-dir")
|
||||
.withDescription("the base folder to look for the bootclasspath files in. Defaults to the current " +
|
||||
"directory")
|
||||
.hasArg()
|
||||
.withArgName("DIR")
|
||||
.create("d");
|
||||
|
||||
Option outputFileOption = OptionBuilder.withLongOpt("out-file")
|
||||
.withDescription("output file")
|
||||
.hasArg()
|
||||
.withArgName("FILE")
|
||||
.create("o");
|
||||
|
||||
Option apiLevelOption = OptionBuilder.withLongOpt("api-level")
|
||||
.withDescription("The numeric api-level of the file being disassembled. If not " +
|
||||
"specified, it defaults to 15 (ICS).")
|
||||
.hasArg()
|
||||
.withArgName("API_LEVEL")
|
||||
.create("a");
|
||||
|
||||
Option experimentalOption = OptionBuilder.withLongOpt("experimental")
|
||||
.withDescription("Enable dumping experimental opcodes, that aren't necessarily " +
|
||||
"supported by the android runtime yet.")
|
||||
.create("X");
|
||||
|
||||
options.addOption(classPathDirOption);
|
||||
options.addOption(outputFileOption);
|
||||
options.addOption(apiLevelOption);
|
||||
options.addOption(experimentalOption);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user