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.Parameter; 35 import com.google.common.collect.ImmutableList; 36 import com.google.common.collect.Lists; 37 import org.jf.dexlib2.analysis.ClassPath; 38 import org.jf.dexlib2.analysis.ClassPathResolver; 39 import org.jf.dexlib2.dexbacked.OatFile.OatDexFile; 40 import org.jf.dexlib2.iface.DexFile; 41 import org.jf.util.jcommander.ColonParameterSplitter; 42 import org.jf.util.jcommander.ExtendedParameter; 43 44 import javax.annotation.Nonnull; 45 import java.io.File; 46 import java.io.IOException; 47 import java.util.List; 48 49 import static org.jf.dexlib2.analysis.ClassPath.NOT_ART; 50 51 public class AnalysisArguments { 52 @Parameter(names = {"-b", "--bootclasspath", "--bcp"}, 53 description = "A colon separated list of the files to include in the bootclasspath when analyzing the " + 54 "dex file. If not specified, baksmali will attempt to choose an " + 55 "appropriate default. When analyzing oat files, this can simply be the path to the device's " + 56 "boot.oat file. A single empty string can be used to specify that an empty bootclasspath should " + 57 "be used. (e.g. --bootclasspath \"\") See baksmali help classpath for more information.", 58 splitter = ColonParameterSplitter.class) 59 @ExtendedParameter(argumentNames = "classpath") 60 public List<String> bootClassPath = null; 61 62 @Parameter(names = {"-c", "--classpath", "--cp"}, 63 description = "A colon separated list of additional files to include in the classpath when analyzing the " + 64 "dex file. These will be added to the classpath after any bootclasspath entries.", 65 splitter = ColonParameterSplitter.class) 66 @ExtendedParameter(argumentNames = "classpath") 67 public List<String> classPath = Lists.newArrayList(); 68 69 @Parameter(names = {"-d", "--classpath-dir", "--cpd", "--dir"}, 70 description = "A directory to search for classpath files. This option can be used multiple times to " + 71 "specify multiple directories to search. They will be searched in the order they are provided.") 72 @ExtendedParameter(argumentNames = "dir") 73 public List<String> classPathDirectories = null; 74 75 public static class CheckPackagePrivateArgument { 76 @Parameter(names = {"--check-package-private-access", "--package-private", "--checkpp", "--pp"}, 77 description = "Use the package-private access check when calculating vtable indexes. This is enabled " + 78 "by default for oat files. For odex files, this is only needed for odexes from 4.2.0. It " + 79 "was reverted in 4.2.1.") 80 public boolean checkPackagePrivateAccess = false; 81 } 82 83 @Nonnull loadClassPathForDexFile(@onnull File dexFileDir, @Nonnull DexFile dexFile, boolean checkPackagePrivateAccess)84 public ClassPath loadClassPathForDexFile(@Nonnull File dexFileDir, @Nonnull DexFile dexFile, 85 boolean checkPackagePrivateAccess) throws IOException { 86 return loadClassPathForDexFile(dexFileDir, dexFile, checkPackagePrivateAccess, NOT_ART); 87 } 88 89 @Nonnull loadClassPathForDexFile(@onnull File dexFileDir, @Nonnull DexFile dexFile, boolean checkPackagePrivateAccess, int oatVersion)90 public ClassPath loadClassPathForDexFile(@Nonnull File dexFileDir, @Nonnull DexFile dexFile, 91 boolean checkPackagePrivateAccess, int oatVersion) 92 throws IOException { 93 ClassPathResolver resolver; 94 95 // By default, oatVersion should be NOT_ART, and we'll automatically set it if dexFile is an oat file. In some 96 // cases the caller may choose to override the oat version, in which case we should use the given oat version 97 // regardless of the actual version of the oat file 98 if (oatVersion == NOT_ART) { 99 if (dexFile instanceof OatDexFile) { 100 checkPackagePrivateAccess = true; 101 oatVersion = ((OatDexFile)dexFile).getContainer().getOatVersion(); 102 } 103 } else { 104 // this should always be true for ART 105 checkPackagePrivateAccess = true; 106 } 107 108 if (classPathDirectories == null || classPathDirectories.size() == 0) { 109 classPathDirectories = Lists.newArrayList(dexFileDir.getPath()); 110 } 111 112 List<String> filteredClassPathDirectories = Lists.newArrayList(); 113 if (classPathDirectories != null) { 114 for (String dir: classPathDirectories) { 115 File file = new File(dir); 116 if (!file.exists()) { 117 System.err.println(String.format("Warning: directory %s does not exist. Ignoring.", dir)); 118 } else if (!file.isDirectory()) { 119 System.err.println(String.format("Warning: %s is not a directory. Ignoring.", dir)); 120 } else { 121 filteredClassPathDirectories.add(dir); 122 } 123 } 124 } 125 126 if (bootClassPath == null) { 127 // TODO: we should be able to get the api from the Opcodes object associated with the dexFile.. 128 // except that the oat version -> api mapping doesn't fully work yet 129 resolver = new ClassPathResolver(filteredClassPathDirectories, classPath, dexFile); 130 } else if (bootClassPath.size() == 1 && bootClassPath.get(0).length() == 0) { 131 // --bootclasspath "" is a special case, denoting that no bootclasspath should be used 132 resolver = new ClassPathResolver( 133 ImmutableList.<String>of(), ImmutableList.<String>of(), classPath, dexFile); 134 } else { 135 resolver = new ClassPathResolver(filteredClassPathDirectories, bootClassPath, classPath, dexFile); 136 } 137 138 if (oatVersion == 0 && dexFile instanceof OatDexFile) { 139 oatVersion = ((OatDexFile)dexFile).getContainer().getOatVersion(); 140 } 141 return new ClassPath(resolver.getResolvedClassProviders(), checkPackagePrivateAccess, oatVersion); 142 } 143 } 144