mirror of
https://github.com/revanced/smali.git
synced 2025-06-12 12:17:37 +02:00
Add the ability to read the dependency information from an odex file, and use those dependencies as the BOOTCLASSPATH by default for odex files
git-svn-id: https://smali.googlecode.com/svn/trunk@679 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
@ -38,6 +38,8 @@ import org.jf.dexlib.Util.SparseArray;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ClassPath {
|
||||
private static ClassPath theClassPath = null;
|
||||
@ -48,21 +50,81 @@ public class ClassPath {
|
||||
//This is only used while initialing the class path. It is set to null after initialization has finished.
|
||||
private LinkedHashMap<String, TempClassInfo> tempClasses;
|
||||
|
||||
public static void InitializeClassPath(String[] classPathDirs, String[] bootClassPath, String dexFilePath,
|
||||
DexFile dexFile) {
|
||||
|
||||
private static final Pattern dalvikCacheOdexPattern = Pattern.compile("@([^@]+)@classes.dex$");
|
||||
|
||||
/**
|
||||
* Initialize the class path using the dependencies from an odex file
|
||||
* @param classPathDirs The directories to search for boot class path files
|
||||
* @param extraBootClassPathEntries any extra entries that should be added after the entries that are read
|
||||
* from the odex file
|
||||
* @param dexFilePath The path of the dex file (used for error reporting purposes only)
|
||||
* @param dexFile The DexFile to load - it must represents an odex file
|
||||
*/
|
||||
public static void InitializeClassPathFromOdex(String[] classPathDirs, String[] extraBootClassPathEntries,
|
||||
String dexFilePath, DexFile dexFile) {
|
||||
if (!dexFile.isOdex()) {
|
||||
throw new ExceptionWithContext("Cannot use InitialiazeClassPathFromOdex with a non-odex DexFile");
|
||||
}
|
||||
|
||||
if (theClassPath != null) {
|
||||
throw new ExceptionWithContext("Cannot initialize ClassPath multiple times");
|
||||
}
|
||||
|
||||
OdexDependencies odexDependencies = dexFile.getOdexDependencies();
|
||||
|
||||
String[] bootClassPath = new String[odexDependencies.getDependencyCount()];
|
||||
for (int i=0; i<bootClassPath.length; i++) {
|
||||
String dependency = odexDependencies.getDependency(i);
|
||||
|
||||
if (dependency.endsWith(".odex")) {
|
||||
int slashIndex = dependency.lastIndexOf("/");
|
||||
|
||||
if (slashIndex != -1) {
|
||||
dependency = dependency.substring(slashIndex+1);
|
||||
}
|
||||
} else if (dependency.endsWith("@classes.dex")) {
|
||||
Matcher m = dalvikCacheOdexPattern.matcher(dependency);
|
||||
|
||||
if (!m.find()) {
|
||||
throw new ExceptionWithContext(String.format("Cannot parse dependency value %s", dependency));
|
||||
}
|
||||
|
||||
dependency = m.group(1);
|
||||
} else {
|
||||
throw new ExceptionWithContext(String.format("Cannot parse dependency value %s", dependency));
|
||||
}
|
||||
|
||||
bootClassPath[i] = dependency;
|
||||
}
|
||||
|
||||
theClassPath = new ClassPath();
|
||||
theClassPath.initClassPath(classPathDirs, bootClassPath, extraBootClassPathEntries, dexFilePath, dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the class path using the given boot class path entries
|
||||
* @param classPathDirs The directories to search for boot class path files
|
||||
* @param bootClassPath A list of the boot class path entries to search for and load
|
||||
* @param dexFilePath The path of the dex file (used for error reporting purposes only)
|
||||
* @param dexFile the DexFile to load
|
||||
*/
|
||||
public static void InitializeClassPath(String[] classPathDirs, String[] bootClassPath,
|
||||
String[] extraBootClassPathEntries, String dexFilePath, DexFile dexFile) {
|
||||
if (theClassPath != null) {
|
||||
throw new ExceptionWithContext("Cannot initialize ClassPath multiple times");
|
||||
}
|
||||
|
||||
theClassPath = new ClassPath();
|
||||
theClassPath.initClassPath(classPathDirs, bootClassPath, dexFilePath, dexFile);
|
||||
theClassPath.initClassPath(classPathDirs, bootClassPath, extraBootClassPathEntries, dexFilePath, dexFile);
|
||||
}
|
||||
|
||||
private ClassPath() {
|
||||
classDefs = new HashMap<String, ClassDef>();
|
||||
}
|
||||
|
||||
private void initClassPath(String[] classPathDirs, String[] bootClassPath, String dexFilePath, DexFile dexFile) {
|
||||
private void initClassPath(String[] classPathDirs, String[] bootClassPath, String[] extraBootClassPathEntries,
|
||||
String dexFilePath, DexFile dexFile) {
|
||||
tempClasses = new LinkedHashMap<String, TempClassInfo>();
|
||||
|
||||
if (bootClassPath != null) {
|
||||
@ -71,6 +133,12 @@ public class ClassPath {
|
||||
}
|
||||
}
|
||||
|
||||
if (extraBootClassPathEntries != null) {
|
||||
for (String bootClassPathEntry: extraBootClassPathEntries) {
|
||||
loadBootClassPath(classPathDirs, bootClassPathEntry);
|
||||
}
|
||||
}
|
||||
|
||||
if (dexFile != null) {
|
||||
loadDexFile(dexFilePath, dexFile);
|
||||
}
|
||||
|
@ -29,7 +29,6 @@
|
||||
package org.jf.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.*;
|
||||
import org.jf.dexlib.*;
|
||||
import org.jf.dexlib.Item;
|
||||
import org.jf.dexlib.StringDataItem;
|
||||
|
||||
@ -37,13 +36,11 @@ import java.io.*;
|
||||
import java.security.DigestException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Collections;
|
||||
import java.util.zip.Adler32;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
/**
|
||||
@ -180,6 +177,7 @@ public class DexFile
|
||||
*/
|
||||
private boolean isOdex = false;
|
||||
|
||||
private OdexDependencies odexDependencies;
|
||||
|
||||
private int dataOffset;
|
||||
private int dataSize;
|
||||
@ -338,7 +336,7 @@ public class DexFile
|
||||
byte[] dexMagic, odexMagic;
|
||||
|
||||
dexMagic = org.jf.dexlib.HeaderItem.MAGIC;
|
||||
odexMagic = OdexHeaderItem.MAGIC;
|
||||
odexMagic = OdexHeader.MAGIC;
|
||||
|
||||
boolean isDex = true;
|
||||
this.isOdex = true;
|
||||
@ -354,9 +352,25 @@ public class DexFile
|
||||
if (isOdex) {
|
||||
byte[] odexHeaderBytes = FileUtils.readStream(inputStream, 40);
|
||||
Input odexHeaderIn = new ByteArrayInput(odexHeaderBytes);
|
||||
OdexHeaderItem odexHeader = new OdexHeaderItem(odexHeaderIn);
|
||||
OdexHeader odexHeader = new OdexHeader(odexHeaderIn);
|
||||
|
||||
int dependencySkip = odexHeader.depsOffset - odexHeader.dexOffset - odexHeader.dexLength;
|
||||
if (dependencySkip < 0) {
|
||||
throw new ExceptionWithContext("Unexpected placement of the odex dependency data");
|
||||
}
|
||||
|
||||
if (odexHeader.dexOffset > 40) {
|
||||
FileUtils.readStream(inputStream, odexHeader.dexOffset - 40);
|
||||
}
|
||||
|
||||
in = new ByteArrayInput(FileUtils.readStream(inputStream, odexHeader.dexLength));
|
||||
|
||||
if (dependencySkip > 0) {
|
||||
FileUtils.readStream(inputStream, dependencySkip);
|
||||
}
|
||||
|
||||
odexDependencies = new OdexDependencies(
|
||||
new ByteArrayInput(FileUtils.readStream(inputStream, odexHeader.depsLength)));
|
||||
} else if (isDex) {
|
||||
in = new ByteArrayInput(FileUtils.readStream(inputStream, (int)fileLength));
|
||||
} else {
|
||||
@ -515,6 +529,14 @@ public class DexFile
|
||||
return this.isOdex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an OdexDependencies object that contains the dependencies for this odex, or null if this
|
||||
* DexFile represents a dex file instead of an odex file
|
||||
*/
|
||||
public OdexDependencies getOdexDependencies() {
|
||||
return odexDependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a boolean value indicating whether items in this dex file should be
|
||||
* written back out "in-place", or whether the normal layout logic should be
|
||||
|
@ -25,7 +25,53 @@
|
||||
* 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class OdexDependencies {
|
||||
public final int modificationTime;
|
||||
public final int crc;
|
||||
public final int dalvikBuild;
|
||||
|
||||
private final String[] dependencies;
|
||||
private final byte[][] dependencyChecksums;
|
||||
|
||||
public OdexDependencies (Input in) {
|
||||
modificationTime = in.readInt();
|
||||
crc = in.readInt();
|
||||
dalvikBuild = in.readInt();
|
||||
|
||||
int dependencyCount = in.readInt();
|
||||
|
||||
dependencies = new String[dependencyCount];
|
||||
dependencyChecksums = new byte[dependencyCount][];
|
||||
|
||||
for (int i=0; i<dependencyCount; i++) {
|
||||
int stringLength = in.readInt();
|
||||
|
||||
try {
|
||||
dependencies[i] = new String(in.readBytes(stringLength), 0, stringLength-1, "US-ASCII");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
dependencyChecksums[i] = in.readBytes(20);
|
||||
}
|
||||
}
|
||||
|
||||
public int getDependencyCount() {
|
||||
return dependencies.length;
|
||||
}
|
||||
|
||||
public String getDependency(int index) {
|
||||
return dependencies[index];
|
||||
}
|
||||
|
||||
public byte[] getDependencyChecksum(int index) {
|
||||
return Arrays.copyOf(dependencyChecksums[index], dependencyChecksums.length);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user