From 8920228819d4cd1cb016ba577b9c65a0cd798fd4 Mon Sep 17 00:00:00 2001 From: Ben Gruver Date: Mon, 13 Jul 2015 21:39:28 -0700 Subject: [PATCH] Add oat support in DexFileFactory --- .../java/org/jf/baksmali/baksmaliOptions.java | 3 +- .../src/main/java/org/jf/baksmali/main.java | 37 +++++- .../java/org/jf/dexlib2/DexFileFactory.java | 110 ++++++++++++++---- .../org/jf/dexlib2/analysis/ClassPath.java | 20 +++- .../jf/dexlib2/dexbacked/BaseDexBuffer.java | 19 ++- .../jf/dexlib2/dexbacked/BaseDexReader.java | 39 ++++--- .../dexlib2/dexbacked/DexBackedDexFile.java | 8 +- .../dexlib2/dexbacked/DexBackedOdexFile.java | 5 +- .../org/jf/dexlib2/dexbacked/OatFile.java | 10 +- .../jf/dexlib2/dexbacked/raw/RawDexFile.java | 3 +- 10 files changed, 201 insertions(+), 53 deletions(-) diff --git a/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java b/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java index b6cc1571..24bf0b96 100644 --- a/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java +++ b/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java @@ -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 bootClassPathDirs = Lists.newArrayList(); public List bootClassPathEntries = Lists.newArrayList(); diff --git a/baksmali/src/main/java/org/jf/baksmali/main.java b/baksmali/src/main/java/org/jf/baksmali/main.java index 71598fa6..e11dc205 100644 --- a/baksmali/src/main/java/org/jf/baksmali/main.java +++ b/baksmali/src/main/java/org/jf/baksmali/main.java @@ -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"); } } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java b/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java index fb433bb3..60488ba2 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java @@ -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 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; + } + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java index bd9cfb1b..4185da82 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java @@ -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 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 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 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, diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexBuffer.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexBuffer.java index 7d06bff7..9cf49294 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexBuffer.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexBuffer.java @@ -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; + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java index 96645b8c..13c0a7b0 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java @@ -49,7 +49,7 @@ public class BaseDexReader { 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 { } } - offset = end; + offset = end - dexBuf.baseOffset; return result; } @@ -93,7 +93,7 @@ public class BaseDexReader { } 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 { } } - offset = end; + offset = end - dexBuf.baseOffset; return result; } @@ -150,7 +150,7 @@ public class BaseDexReader { * @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 { } } - 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 { } } - offset = end; + offset = end - dexBuf.baseOffset; } public int readSmallUint() { @@ -285,7 +285,7 @@ public class BaseDexReader { 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 { 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 { 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 { 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 { 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 { 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; } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java index 1774096e..638fd855 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java @@ -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 getClasses() { diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedOdexFile.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedOdexFile.java index 1aa9c1eb..12f19db0 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedOdexFile.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedOdexFile.java @@ -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 getDependencies() { final int dexOffset = OdexHeaderItem.getDexOffset(odexBuf); final int dependencyOffset = OdexHeaderItem.getDependenciesOffset(odexBuf) - dexOffset; diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/OatFile.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/OatFile.java index 88ef08c7..b5250d0d 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/OatFile.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/OatFile.java @@ -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 { diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/RawDexFile.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/RawDexFile.java index 1fac80bb..204a29d8 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/RawDexFile.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/RawDexFile.java @@ -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()); } }