mirror of
https://github.com/revanced/smali.git
synced 2025-05-07 18:04:32 +02:00
Add oat support in DexFileFactory
This commit is contained in:
parent
3ff884b1c3
commit
8920228819
@ -36,6 +36,7 @@ import org.jf.dexlib2.analysis.ClassPath;
|
||||
import org.jf.dexlib2.analysis.InlineMethodResolver;
|
||||
import org.jf.dexlib2.util.SyntheticAccessorResolver;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@ -54,7 +55,7 @@ public class baksmaliOptions {
|
||||
|
||||
public int apiLevel = 15;
|
||||
public String outputDirectory = "out";
|
||||
public String dexEntry = "classes.dex";
|
||||
@Nullable public String dexEntry = null;
|
||||
public List<String> bootClassPathDirs = Lists.newArrayList();
|
||||
|
||||
public List<String> bootClassPathEntries = Lists.newArrayList();
|
||||
|
@ -31,9 +31,11 @@ package org.jf.baksmali;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.cli.*;
|
||||
import org.jf.dexlib2.DexFileFactory;
|
||||
import org.jf.dexlib2.DexFileFactory.MultipleDexFilesException;
|
||||
import org.jf.dexlib2.analysis.InlineMethodResolver;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedOdexFile;
|
||||
import org.jf.dexlib2.dexbacked.OatFile.OatDexFile;
|
||||
import org.jf.util.ConsoleUtil;
|
||||
import org.jf.util.SmaliHelpFormatter;
|
||||
|
||||
@ -256,10 +258,20 @@ public class main {
|
||||
}
|
||||
|
||||
//Read in and parse the dex file
|
||||
DexBackedDexFile dexFile = DexFileFactory.loadDexFile(dexFileFile, options.dexEntry,
|
||||
options.apiLevel, options.experimental);
|
||||
DexBackedDexFile dexFile = null;
|
||||
try {
|
||||
dexFile = DexFileFactory.loadDexFile(dexFileFile, options.dexEntry, options.apiLevel, options.experimental);
|
||||
} catch (MultipleDexFilesException ex) {
|
||||
System.err.println(String.format("%s contains multiple dex files. You must specify which one to " +
|
||||
"disassemble with the -e option", dexFileFile.getName()));
|
||||
System.err.println("Valid entries include:");
|
||||
for (OatDexFile oatDexFile: ex.oatFile.getDexFiles()) {
|
||||
System.err.println(oatDexFile.filename);
|
||||
}
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if (dexFile.isOdexFile()) {
|
||||
if (dexFile.hasOdexOpcodes()) {
|
||||
if (!options.deodex) {
|
||||
System.err.println("Warning: You are disassembling an odex file without deodexing it. You");
|
||||
System.err.println("won't be able to re-assemble the results unless you deodex it with the -x");
|
||||
@ -547,8 +559,7 @@ public class main {
|
||||
"/system/framework/services.jar",
|
||||
"/system/framework/apache-xml.jar",
|
||||
"/system/framework/filterfw.jar");
|
||||
|
||||
} else {
|
||||
} else if (apiLevel < 21) {
|
||||
// this is correct as of api 17/4.2.2
|
||||
return Lists.newArrayList(
|
||||
"/system/framework/core.jar",
|
||||
@ -561,6 +572,22 @@ public class main {
|
||||
"/system/framework/android.policy.jar",
|
||||
"/system/framework/services.jar",
|
||||
"/system/framework/apache-xml.jar");
|
||||
} else { // api >= 21
|
||||
// TODO: verify, add new ones?
|
||||
return Lists.newArrayList(
|
||||
"/system/framework/core-libart.jar",
|
||||
"/system/framework/conscrypt.jar",
|
||||
"/system/framework/okhttp.jar",
|
||||
"/system/framework/core-junit.jar",
|
||||
"/system/framework/bouncycastle.jar",
|
||||
"/system/framework/ext.jar",
|
||||
"/system/framework/framework.jar",
|
||||
"/system/framework/telephony-common.jar",
|
||||
"/system/framework/voip-common.jar",
|
||||
"/system/framework/ims-common.jar",
|
||||
"/system/framework/mms-common.jar",
|
||||
"/system/framework/android.policy.jar",
|
||||
"/system/framework/apache-xml.jar");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,51 +31,56 @@
|
||||
|
||||
package org.jf.dexlib2;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedOdexFile;
|
||||
import org.jf.dexlib2.dexbacked.OatFile;
|
||||
import org.jf.dexlib2.dexbacked.OatFile.NotAnOatFileException;
|
||||
import org.jf.dexlib2.dexbacked.OatFile.OatDexFile;
|
||||
import org.jf.dexlib2.iface.DexFile;
|
||||
import org.jf.dexlib2.writer.pool.DexPool;
|
||||
import org.jf.util.ExceptionWithContext;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public final class DexFileFactory {
|
||||
@Nonnull
|
||||
public static DexBackedDexFile loadDexFile(String path, int api)
|
||||
throws IOException {
|
||||
public static DexBackedDexFile loadDexFile(@Nonnull String path, int api) throws IOException {
|
||||
return loadDexFile(path, api, false);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static DexBackedDexFile loadDexFile(String path, int api, boolean experimental)
|
||||
public static DexBackedDexFile loadDexFile(@Nonnull String path, int api, boolean experimental)
|
||||
throws IOException {
|
||||
return loadDexFile(new File(path), "classes.dex", Opcodes.forApi(api, experimental));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static DexBackedDexFile loadDexFile(File dexFile, int api) throws IOException {
|
||||
public static DexBackedDexFile loadDexFile(@Nonnull File dexFile, int api) throws IOException {
|
||||
return loadDexFile(dexFile, api, false);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static DexBackedDexFile loadDexFile(File dexFile, int api, boolean experimental)
|
||||
public static DexBackedDexFile loadDexFile(@Nonnull File dexFile, int api, boolean experimental)
|
||||
throws IOException {
|
||||
return loadDexFile(dexFile, "classes.dex", Opcodes.forApi(api, experimental));
|
||||
return loadDexFile(dexFile, null, Opcodes.forApi(api, experimental));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static DexBackedDexFile loadDexFile(File dexFile, String dexEntry, int api,
|
||||
public static DexBackedDexFile loadDexFile(@Nonnull File dexFile, @Nullable String dexEntry, int api,
|
||||
boolean experimental) throws IOException {
|
||||
return loadDexFile(dexFile, dexEntry, Opcodes.forApi(api, experimental));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static DexBackedDexFile loadDexFile(File dexFile, String dexEntry,
|
||||
@Nonnull Opcodes opcodes) throws IOException {
|
||||
public static DexBackedDexFile loadDexFile(@Nonnull File dexFile, @Nullable String dexEntry,
|
||||
@Nonnull Opcodes opcodes) throws IOException {
|
||||
ZipFile zipFile = null;
|
||||
boolean isZipFile = false;
|
||||
try {
|
||||
@ -83,16 +88,18 @@ public final class DexFileFactory {
|
||||
// if we get here, it's safe to assume we have a zip file
|
||||
isZipFile = true;
|
||||
|
||||
ZipEntry zipEntry = zipFile.getEntry(dexEntry);
|
||||
String zipEntryName = MoreObjects.firstNonNull(dexEntry, "classes.dex");
|
||||
ZipEntry zipEntry = zipFile.getEntry(zipEntryName);
|
||||
if (zipEntry == null) {
|
||||
throw new NoClassesDexException("zip file %s does not contain a classes.dex file", dexFile.getName());
|
||||
throw new DexFileNotFound("zip file %s does not contain a %s file", dexFile.getName(), zipEntryName);
|
||||
}
|
||||
long fileLength = zipEntry.getSize();
|
||||
if (fileLength < 40) {
|
||||
throw new ExceptionWithContext(
|
||||
"The " + dexEntry + " file in %s is too small to be a valid dex file", dexFile.getName());
|
||||
throw new ExceptionWithContext("The %s file in %s is too small to be a valid dex file",
|
||||
zipEntryName, dexFile.getName());
|
||||
} else if (fileLength > Integer.MAX_VALUE) {
|
||||
throw new ExceptionWithContext("The " + dexEntry + " file in %s is too large to read in", dexFile.getName());
|
||||
throw new ExceptionWithContext("The %s file in %s is too large to read in",
|
||||
zipEntryName, dexFile.getName());
|
||||
}
|
||||
byte[] dexBytes = new byte[(int)fileLength];
|
||||
ByteStreams.readFully(zipFile.getInputStream(zipEntry), dexBytes);
|
||||
@ -127,30 +134,93 @@ public final class DexFileFactory {
|
||||
} catch (DexBackedOdexFile.NotAnOdexFile ex) {
|
||||
// just eat it
|
||||
}
|
||||
|
||||
OatFile oatFile = null;
|
||||
try {
|
||||
oatFile = OatFile.fromInputStream(inputStream);
|
||||
} catch (NotAnOatFileException ex) {
|
||||
// just eat it
|
||||
}
|
||||
|
||||
if (oatFile != null) {
|
||||
if (oatFile.isSupportedVersion() == OatFile.UNSUPPORTED) {
|
||||
throw new UnsupportedOatVersionException(oatFile);
|
||||
}
|
||||
|
||||
List<OatDexFile> oatDexFiles = oatFile.getDexFiles();
|
||||
|
||||
if (oatDexFiles.size() == 0) {
|
||||
throw new DexFileNotFound("Oat file %s contains no dex files", dexFile.getName());
|
||||
}
|
||||
|
||||
if (dexEntry == null) {
|
||||
if (oatDexFiles.size() > 1) {
|
||||
throw new MultipleDexFilesException(oatFile);
|
||||
}
|
||||
return oatDexFiles.get(0);
|
||||
} else {
|
||||
// first check for an exact match
|
||||
for (OatDexFile oatDexFile : oatFile.getDexFiles()) {
|
||||
if (oatDexFile.filename.equals(dexEntry)) {
|
||||
return oatDexFile;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dexEntry.contains("/")) {
|
||||
for (OatDexFile oatDexFile : oatFile.getDexFiles()) {
|
||||
File oatEntryFile = new File(oatDexFile.filename);
|
||||
if (oatEntryFile.getName().equals(dexEntry)) {
|
||||
return oatDexFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new DexFileNotFound("oat file %s does not contain a dex file named %s",
|
||||
dexFile.getName(), dexEntry);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
inputStream.close();
|
||||
}
|
||||
|
||||
throw new ExceptionWithContext("%s is not an apk, dex file or odex file.", dexFile.getPath());
|
||||
throw new ExceptionWithContext("%s is not an apk, dex, odex or oat file.", dexFile.getPath());
|
||||
}
|
||||
|
||||
public static void writeDexFile(String path, DexFile dexFile) throws IOException {
|
||||
public static void writeDexFile(@Nonnull String path, @Nonnull DexFile dexFile) throws IOException {
|
||||
DexPool.writeTo(path, dexFile);
|
||||
}
|
||||
|
||||
private DexFileFactory() {}
|
||||
|
||||
public static class NoClassesDexException extends ExceptionWithContext {
|
||||
public NoClassesDexException(Throwable cause) {
|
||||
public static class DexFileNotFound extends ExceptionWithContext {
|
||||
public DexFileNotFound(@Nullable Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public NoClassesDexException(Throwable cause, String message, Object... formatArgs) {
|
||||
public DexFileNotFound(@Nullable Throwable cause, @Nullable String message, Object... formatArgs) {
|
||||
super(cause, message, formatArgs);
|
||||
}
|
||||
|
||||
public NoClassesDexException(String message, Object... formatArgs) {
|
||||
public DexFileNotFound(@Nullable String message, Object... formatArgs) {
|
||||
super(message, formatArgs);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MultipleDexFilesException extends ExceptionWithContext {
|
||||
@Nonnull public final OatFile oatFile;
|
||||
|
||||
public MultipleDexFilesException(@Nonnull OatFile oatFile) {
|
||||
super("Oat file has multiple dex files.");
|
||||
this.oatFile = oatFile;
|
||||
}
|
||||
}
|
||||
|
||||
public static class UnsupportedOatVersionException extends ExceptionWithContext {
|
||||
@Nonnull public final OatFile oatFile;
|
||||
|
||||
public UnsupportedOatVersionException(@Nonnull OatFile oatFile) {
|
||||
super("Unsupported oat version: %d", oatFile.getOatVersion());
|
||||
this.oatFile = oatFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.jf.dexlib2.DexFileFactory;
|
||||
import org.jf.dexlib2.DexFileFactory.DexFileNotFound;
|
||||
import org.jf.dexlib2.analysis.reflection.ReflectionClassDef;
|
||||
import org.jf.dexlib2.iface.ClassDef;
|
||||
import org.jf.dexlib2.iface.DexFile;
|
||||
@ -58,6 +59,7 @@ public class ClassPath {
|
||||
@Nonnull private final TypeProto unknownClass;
|
||||
@Nonnull private HashMap<String, ClassDef> availableClasses = Maps.newHashMap();
|
||||
private boolean checkPackagePrivateAccess;
|
||||
public boolean isArt;
|
||||
|
||||
/**
|
||||
* Creates a new ClassPath instance that can load classes from the given dex files
|
||||
@ -82,15 +84,29 @@ public class ClassPath {
|
||||
* Creates a new ClassPath instance that can load classes from the given dex files
|
||||
*
|
||||
* @param classPath An iterable of DexFile objects. When loading a class, these dex files will be searched in order
|
||||
* @param checkPackagePrivateAccess Whether checkPackagePrivateAccess is needed, enabled for ONLY early API 17 by default
|
||||
* @param checkPackagePrivateAccess Whether checkPackagePrivateAccess is needed, enabled for ONLY early API 17 by
|
||||
* default
|
||||
*/
|
||||
public ClassPath(@Nonnull Iterable<DexFile> classPath, boolean checkPackagePrivateAccess) {
|
||||
this(classPath, checkPackagePrivateAccess, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ClassPath instance that can load classes from the given dex files
|
||||
*
|
||||
* @param classPath An iterable of DexFile objects. When loading a class, these dex files will be searched in order
|
||||
* @param checkPackagePrivateAccess Whether checkPackagePrivateAccess is needed, enabled for ONLY early API 17 by
|
||||
* default
|
||||
* @param isArt Whether this is ClassPath is for ART
|
||||
*/
|
||||
public ClassPath(@Nonnull Iterable < DexFile > classPath, boolean checkPackagePrivateAccess, boolean isArt) {
|
||||
// add fallbacks for certain special classes that must be present
|
||||
Iterable<DexFile> dexFiles = Iterables.concat(classPath, Lists.newArrayList(getBasicClasses()));
|
||||
|
||||
unknownClass = new UnknownClassProto(this);
|
||||
loadedClasses.put(unknownClass.getType(), unknownClass);
|
||||
this.checkPackagePrivateAccess = checkPackagePrivateAccess;
|
||||
this.isArt = isArt;
|
||||
|
||||
loadPrimitiveType("Z");
|
||||
loadPrimitiveType("B");
|
||||
@ -223,7 +239,7 @@ public class ClassPath {
|
||||
} else {
|
||||
try {
|
||||
return DexFileFactory.loadDexFile(file, api, experimental);
|
||||
} catch (DexFileFactory.NoClassesDexException ex) {
|
||||
} catch (DexFileNotFound ex) {
|
||||
// ignore and continue
|
||||
} catch (Exception ex) {
|
||||
throw ExceptionWithContext.withContext(ex,
|
||||
|
@ -37,13 +37,19 @@ import javax.annotation.Nonnull;
|
||||
|
||||
public class BaseDexBuffer {
|
||||
@Nonnull /* package private */ final byte[] buf;
|
||||
/* package private */ final int baseOffset;
|
||||
|
||||
public BaseDexBuffer(@Nonnull byte[] buf) {
|
||||
this(buf, 0);
|
||||
}
|
||||
public BaseDexBuffer(@Nonnull byte[] buf, int offset) {
|
||||
this.buf = buf;
|
||||
this.baseOffset = offset;
|
||||
}
|
||||
|
||||
public int readSmallUint(int offset) {
|
||||
byte[] buf = this.buf;
|
||||
offset += baseOffset;
|
||||
int result = (buf[offset] & 0xff) |
|
||||
((buf[offset+1] & 0xff) << 8) |
|
||||
((buf[offset+2] & 0xff) << 16) |
|
||||
@ -56,6 +62,7 @@ public class BaseDexBuffer {
|
||||
|
||||
public int readOptionalUint(int offset) {
|
||||
byte[] buf = this.buf;
|
||||
offset += baseOffset;
|
||||
int result = (buf[offset] & 0xff) |
|
||||
((buf[offset+1] & 0xff) << 8) |
|
||||
((buf[offset+2] & 0xff) << 16) |
|
||||
@ -68,16 +75,18 @@ public class BaseDexBuffer {
|
||||
|
||||
public int readUshort(int offset) {
|
||||
byte[] buf = this.buf;
|
||||
offset += baseOffset;
|
||||
return (buf[offset] & 0xff) |
|
||||
((buf[offset+1] & 0xff) << 8);
|
||||
}
|
||||
|
||||
public int readUbyte(int offset) {
|
||||
return buf[offset] & 0xff;
|
||||
return buf[offset + baseOffset] & 0xff;
|
||||
}
|
||||
|
||||
public long readLong(int offset) {
|
||||
byte[] buf = this.buf;
|
||||
offset += baseOffset;
|
||||
return (buf[offset] & 0xff) |
|
||||
((buf[offset+1] & 0xff) << 8) |
|
||||
((buf[offset+2] & 0xff) << 16) |
|
||||
@ -90,6 +99,7 @@ public class BaseDexBuffer {
|
||||
|
||||
public int readInt(int offset) {
|
||||
byte[] buf = this.buf;
|
||||
offset += baseOffset;
|
||||
return (buf[offset] & 0xff) |
|
||||
((buf[offset+1] & 0xff) << 8) |
|
||||
((buf[offset+2] & 0xff) << 16) |
|
||||
@ -98,12 +108,13 @@ public class BaseDexBuffer {
|
||||
|
||||
public int readShort(int offset) {
|
||||
byte[] buf = this.buf;
|
||||
offset += baseOffset;
|
||||
return (buf[offset] & 0xff) |
|
||||
(buf[offset+1] << 8);
|
||||
}
|
||||
|
||||
public int readByte(int offset) {
|
||||
return buf[offset];
|
||||
return buf[baseOffset + offset];
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@ -115,4 +126,8 @@ public class BaseDexBuffer {
|
||||
protected byte[] getBuf() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
protected int getBaseOffset() {
|
||||
return baseOffset;
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
||||
public void setOffset(int offset) { this.offset = offset; }
|
||||
|
||||
public int readSleb128() {
|
||||
int end = offset;
|
||||
int end = dexBuf.baseOffset + offset;
|
||||
int currentByteValue;
|
||||
int result;
|
||||
byte[] buf = dexBuf.buf;
|
||||
@ -84,7 +84,7 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
||||
}
|
||||
}
|
||||
|
||||
offset = end;
|
||||
offset = end - dexBuf.baseOffset;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
||||
}
|
||||
|
||||
private int readUleb128(boolean allowLarge) {
|
||||
int end = offset;
|
||||
int end = dexBuf.baseOffset + offset;
|
||||
int currentByteValue;
|
||||
int result;
|
||||
byte[] buf = dexBuf.buf;
|
||||
@ -129,7 +129,7 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
||||
}
|
||||
}
|
||||
|
||||
offset = end;
|
||||
offset = end - dexBuf.baseOffset;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -150,7 +150,7 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
||||
* @return The unsigned value, reinterpreted as a signed int
|
||||
*/
|
||||
public int readBigUleb128() {
|
||||
int end = offset;
|
||||
int end = dexBuf.baseOffset + offset;
|
||||
int currentByteValue;
|
||||
int result;
|
||||
byte[] buf = dexBuf.buf;
|
||||
@ -179,12 +179,12 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
||||
}
|
||||
}
|
||||
|
||||
offset = end;
|
||||
offset = end - dexBuf.baseOffset;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void skipUleb128() {
|
||||
int end = offset;
|
||||
int end = dexBuf.baseOffset + offset;
|
||||
byte currentByteValue;
|
||||
byte[] buf = dexBuf.buf;
|
||||
|
||||
@ -206,7 +206,7 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
||||
}
|
||||
}
|
||||
|
||||
offset = end;
|
||||
offset = end - dexBuf.baseOffset;
|
||||
}
|
||||
|
||||
public int readSmallUint() {
|
||||
@ -285,7 +285,7 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
||||
public int readByte(int offset) { return dexBuf.readByte(offset); }
|
||||
|
||||
public int readSizedInt(int bytes) {
|
||||
int o = offset;
|
||||
int o = dexBuf.baseOffset + offset;
|
||||
byte[] buf = dexBuf.buf;
|
||||
|
||||
int result;
|
||||
@ -311,12 +311,12 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
||||
default:
|
||||
throw new ExceptionWithContext("Invalid size %d for sized int at offset 0x%x", bytes, offset);
|
||||
}
|
||||
offset = o + bytes;
|
||||
offset = o + bytes - dexBuf.baseOffset;
|
||||
return result;
|
||||
}
|
||||
|
||||
public int readSizedSmallUint(int bytes) {
|
||||
int o = offset;
|
||||
int o = dexBuf.baseOffset + offset;
|
||||
byte[] buf = dexBuf.buf;
|
||||
|
||||
int result = 0;
|
||||
@ -341,12 +341,12 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
||||
default:
|
||||
throw new ExceptionWithContext("Invalid size %d for sized uint at offset 0x%x", bytes, offset);
|
||||
}
|
||||
offset = o + bytes;
|
||||
offset = o + bytes - dexBuf.baseOffset;
|
||||
return result;
|
||||
}
|
||||
|
||||
public int readSizedRightExtendedInt(int bytes) {
|
||||
int o = offset;
|
||||
int o = dexBuf.baseOffset + offset;
|
||||
byte[] buf = dexBuf.buf;
|
||||
|
||||
int result;
|
||||
@ -373,12 +373,12 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
||||
throw new ExceptionWithContext(
|
||||
"Invalid size %d for sized, right extended int at offset 0x%x", bytes, offset);
|
||||
}
|
||||
offset = o + bytes;
|
||||
offset = o + bytes - dexBuf.baseOffset;
|
||||
return result;
|
||||
}
|
||||
|
||||
public long readSizedRightExtendedLong(int bytes) {
|
||||
int o = offset;
|
||||
int o = dexBuf.baseOffset + offset;
|
||||
byte[] buf = dexBuf.buf;
|
||||
|
||||
long result;
|
||||
@ -439,12 +439,12 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
||||
throw new ExceptionWithContext(
|
||||
"Invalid size %d for sized, right extended long at offset 0x%x", bytes, offset);
|
||||
}
|
||||
offset = o + bytes;
|
||||
offset = o + bytes - dexBuf.baseOffset;
|
||||
return result;
|
||||
}
|
||||
|
||||
public long readSizedLong(int bytes) {
|
||||
int o = offset;
|
||||
int o = dexBuf.baseOffset + offset;
|
||||
byte[] buf = dexBuf.buf;
|
||||
|
||||
long result;
|
||||
@ -505,13 +505,14 @@ public class BaseDexReader<T extends BaseDexBuffer> {
|
||||
throw new ExceptionWithContext("Invalid size %d for sized long at offset 0x%x", bytes, offset);
|
||||
}
|
||||
|
||||
offset = o + bytes;
|
||||
offset = o + bytes - dexBuf.baseOffset;
|
||||
return result;
|
||||
}
|
||||
|
||||
public String readString(int utf16Length) {
|
||||
int[] ret = new int[1];
|
||||
String value = Utf8Utils.utf8BytesWithUtf16LengthToString(dexBuf.buf, offset, utf16Length, ret);
|
||||
String value = Utf8Utils.utf8BytesWithUtf16LengthToString(
|
||||
dexBuf.buf, dexBuf.baseOffset + offset, utf16Length, ret);
|
||||
offset += ret[0];
|
||||
return value;
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ public class DexBackedDexFile extends BaseDexBuffer implements DexFile {
|
||||
private final int classStartOffset;
|
||||
|
||||
private DexBackedDexFile(Opcodes opcodes, @Nonnull byte[] buf, int offset, boolean verifyMagic) {
|
||||
super(buf);
|
||||
super(buf, offset);
|
||||
|
||||
this.opcodes = opcodes;
|
||||
|
||||
@ -121,10 +121,16 @@ public class DexBackedDexFile extends BaseDexBuffer implements DexFile {
|
||||
return opcodes;
|
||||
}
|
||||
|
||||
// Will only be true for a dalvik-style odex file
|
||||
public boolean isOdexFile() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Will be true for both a dalvik-style odex file, and an art-style odex file embedded in an oat file
|
||||
public boolean hasOdexOpcodes() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Set<? extends DexBackedClassDef> getClasses() {
|
||||
|
@ -33,7 +33,6 @@ package org.jf.dexlib2.dexbacked;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import org.jf.dexlib2.Opcodes;
|
||||
import org.jf.dexlib2.dexbacked.raw.HeaderItem;
|
||||
import org.jf.dexlib2.dexbacked.raw.OdexHeaderItem;
|
||||
import org.jf.dexlib2.dexbacked.util.VariableSizeList;
|
||||
|
||||
@ -61,6 +60,10 @@ public class DexBackedOdexFile extends DexBackedDexFile {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean hasOdexOpcodes() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<String> getDependencies() {
|
||||
final int dexOffset = OdexHeaderItem.getDexOffset(odexBuf);
|
||||
final int dependencyOffset = OdexHeaderItem.getDependenciesOffset(odexBuf) - dexOffset;
|
||||
|
@ -124,8 +124,12 @@ public class OatFile extends BaseDexBuffer {
|
||||
return new OatFile(buf);
|
||||
}
|
||||
|
||||
public int getOatVersion() {
|
||||
return oatHeader.getVersion();
|
||||
}
|
||||
|
||||
public int isSupportedVersion() {
|
||||
int version = oatHeader.getVersion();
|
||||
int version = getOatVersion();
|
||||
if (version < MIN_OAT_VERSION) {
|
||||
return UNSUPPORTED;
|
||||
}
|
||||
@ -187,6 +191,10 @@ public class OatFile extends BaseDexBuffer {
|
||||
super(opcodes, OatFile.this.buf, offset);
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
@Override public boolean hasOdexOpcodes() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class OatHeader {
|
||||
|
@ -59,7 +59,7 @@ public class RawDexFile extends DexBackedDexFile {
|
||||
|
||||
@Nonnull
|
||||
public byte[] readByteRange(int start, int length) {
|
||||
return Arrays.copyOfRange(getBuf(), start, start+length);
|
||||
return Arrays.copyOfRange(getBuf(), getBaseOffset() + start, getBaseOffset() + start + length);
|
||||
}
|
||||
|
||||
public int getMapOffset() {
|
||||
@ -94,6 +94,7 @@ public class RawDexFile extends DexBackedDexFile {
|
||||
}
|
||||
|
||||
public void writeAnnotations(@Nonnull Writer out, @Nonnull AnnotatedBytes annotatedBytes) throws IOException {
|
||||
// TODO: need to pass in the offset
|
||||
annotatedBytes.writeAnnotations(out, getBuf());
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user