Browse files

Refactor how classpath loading works

  • Loading branch information...
JesusFreke committed Sep 18, 2016
1 parent 4c77ad7 commit 31ad2bc1002784161b318627f32b4df8bcb862e0
@@ -34,14 +34,19 @@
import com.beust.jcommander.Parameter;
import org.jf.dexlib2.analysis.ClassPath;
import org.jf.dexlib2.analysis.ClassPathResolver;
import org.jf.dexlib2.dexbacked.OatFile.OatDexFile;
import org.jf.dexlib2.iface.DexFile;
import org.jf.util.jcommander.ColonParameterSplitter;
import org.jf.util.jcommander.ExtendedParameter;
import javax.annotation.Nonnull;
import java.util.List;
import static org.jf.dexlib2.analysis.ClassPath.NOT_ART;
public class AnalysisArguments {
@Parameter(names = {"-a", "--api"},
description = "The numeric api level of the file being disassembled.")
@@ -68,7 +73,7 @@
description = "A directory to search for classpath files. This option can be used multiple times to " +
"specify multiple directories to search. They will be searched in the order they are provided.")
@ExtendedParameter(argumentNames = "dir")
public List<String> classPathDirectories = Lists.newArrayList(".");
public List<String> classPathDirectories = null;
public static class CheckPackagePrivateArgument {
@Parameter(names = {"--check-package-private-access", "--package-private", "--checkpp", "--pp"},
@@ -77,9 +82,37 @@
public boolean checkPackagePrivateAccess = false;
public ClassPath loadClassPathForDexFile(@Nonnull DexFile dexFile, boolean checkPackagePrivateAccess)
throws IOException {
return ClassPath.loadClassPath(classPathDirectories, bootClassPath, classPath, dexFile, apiLevel,
ClassPathResolver resolver;
List<String> filteredClassPathDirectories = Lists.newArrayList();
if (classPathDirectories != null) {
for (String dir: classPathDirectories) {
File file = new File(dir);
if (!file.exists()) {
System.err.println(String.format("Warning: directory %s does not exist. Ignoring.", dir));
} else if (!file.isDirectory()) {
System.err.println(String.format("Warning: %s is not a directory. Ignoring.", dir));
} else {
if (bootClassPath == null) {
// TODO: we should be able to get the api from the Opcodes object associated with the dexFile..
// except that the oat version -> api mapping doesn't fully work yet
resolver = new ClassPathResolver(filteredClassPathDirectories, classPath, dexFile, apiLevel);
} else {
resolver = new ClassPathResolver(filteredClassPathDirectories, bootClassPath, classPath, dexFile);
int oatVersion = NOT_ART;
if (dexFile instanceof OatDexFile) {
oatVersion = ((OatDexFile)dexFile).getOatFile().getOatVersion();
return new ClassPath(resolver.getResolvedClassProviders(), checkPackagePrivateAccess, oatVersion);
@@ -108,6 +108,67 @@ public void run() {
"around this, you can add double quotes around the entry name to specify an exact entry " +
"name. E.g. blah.oat/\"/blah/blah.dex\" or blah.oat/\"blah/blah.dex\" respectively.";
Iterable<String> lines = StringWrapper.wrapStringOnBreaks(registerInfoHelp,
for (String line : lines) {
} else if (cmd.equals("classpath")) {
printedHelp = true;
String registerInfoHelp = "When deodexing odex/oat files or when using the --register-info " +
"option, baksmali needs to load all classes from the framework files on the device " +
"in order to fully understand the class hierarchy. There are several options that " +
"control how baksmali finds and loads the classpath entries.\n" +
"L+ devices (ART):\n" +
"When deodexing or disassembling a file from an L+ device using ART, you generally " +
"just need to specify the path to the boot.oat file via the --bootclasspath/-b " +
"parameter. On pre-N devices, the boot.oat file is self-contained and no other files are " +
"needed. In N, boot.oat was split into multiple files. In this case, the other " +
"files should be in the same directory as the boot.oat file, but you still only need to " +
"specify the boot.oat file in the --bootclasspath/-b option. The other files will be " +
"automatically loaded from the same directory.\n" +
"\n" +
"Pre-L devices (dalvik):\n" +
"When deodexing odex files from a pre-L device using dalvik, you " +
"generally just need to specify the path to a directory containing the framework files " +
"from the device via the --classpath-dir/-d option. odex files contain a list of " +
"framework files they depend on and baksmali will search for these dependencies in the " +
"directory that you specify.\n" +
"\n" +
"Dex files don't contain a list of dependencies like odex files, so when disassembling a " +
"dex file using the --register-info option, and using the framework files from a " +
"pre-L device, baksmali will attempt to use a reasonable default list of classpath files " +
"based on the api level set via the -a option. If this default list is incorrect, you " +
"can override the classpath using the --bootclasspath/-b option. This option accepts a " +
"colon separated list of classpath entries. Each entry can be specified in a few " +
"different ways.\n" +
" - A simple filename like \"framework.jar\"\n" +
" - A device path like \"/system/framework/framework.jar\"\n" +
" - A local relative or absolute path like \"/tmp/framework/framework.jar\"\n" +
"When using the first or second formats, you should also specify the directory " +
"containing the framework files via the --classpath-dir/-d option. When using the third " +
"format, this option is not needed.\n" +
"It's worth noting that the second format matches the format used by Android for the " +
"BOOTCLASSPATH environment variable, so you can simply grab the value of that variable " +
"from the device and use it as-is.\n" +
"\n" +
"Examples:\n" +
" For an M device:\n" +
" adb pull /system/framework/arm/boot.oat /tmp/boot.oat\n" +
" baksmali deodex blah.oat -b /tmp/boot.oat\n" +
" For an N+ device:\n" +
" adb pull /system/framework/arm /tmp/framework\n" +
" baksmali deodex blah.oat -b /tmp/framework/boot.oat\n" +
" For a pre-L device:\n" +
" adb pull /system/framework /tmp/framework\n" +
" baksmali deodex blah.odex -d /tmp/framework\n" +
" Using the BOOTCLASSPATH on a pre-L device:\n" +
" adb pull /system/framework /tmp/framework\n" +
" export BOOTCLASSPATH=`adb shell \"echo \\\\$BOOTCLASPATH\"`\n" +
" baksmali disassemble --register-info ARGS,DEST blah.apk -b $BOOTCLASSPATH -d " +
Iterable<String> lines = StringWrapper.wrapStringOnBreaks(registerInfoHelp,
for (String line : lines) {
@@ -36,6 +36,9 @@
import com.beust.jcommander.Parameters;
import org.jf.dexlib2.DexFileFactory;
import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
import org.jf.dexlib2.iface.MultiDexContainer;
import org.jf.util.jcommander.Command;
import org.jf.util.jcommander.ExtendedParameter;
import org.jf.util.jcommander.ExtendedParameters;
@@ -85,7 +88,9 @@ public ListDexCommand(@Nonnull List<JCommander> commandAncestors) {
List<String> entries;
try {
entries = DexFileFactory.getAllDexEntries(file);
MultiDexContainer<? extends DexBackedDexFile> container =
DexFileFactory.loadDexContainer(file, Opcodes.forApi(15));
entries = container.getDexEntryNames();
} catch (IOException ex) {
throw new RuntimeException(ex);
Oops, something went wrong.

0 comments on commit 31ad2bc

Please sign in to comment.