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 9cf49294..eeb28227 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexBuffer.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexBuffer.java @@ -97,6 +97,23 @@ public class BaseDexBuffer { (((long)buf[offset+7]) << 56); } + public int readLongAsSmallUint(int offset) { + byte[] buf = this.buf; + offset += baseOffset; + long result = (buf[offset] & 0xff) | + ((buf[offset+1] & 0xff) << 8) | + ((buf[offset+2] & 0xff) << 16) | + ((buf[offset+3] & 0xffL) << 24) | + ((buf[offset+4] & 0xffL) << 32) | + ((buf[offset+5] & 0xffL) << 40) | + ((buf[offset+6] & 0xffL) << 48) | + (((long)buf[offset+7]) << 56); + if (result < 0 || result > Integer.MAX_VALUE) { + throw new ExceptionWithContext("Encountered out-of-range ulong at offset 0x%x", offset); + } + return (int)result; + } + public int readInt(int offset) { byte[] buf = this.buf; offset += baseOffset; 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 bf55f934..dbeb67ce 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/OatFile.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/OatFile.java @@ -49,7 +49,7 @@ import java.util.List; public class OatFile extends BaseDexBuffer { private static final byte[] ELF_MAGIC = new byte[] { 0x7f, 'E', 'L', 'F' }; private static final byte[] OAT_MAGIC = new byte[] { 'o', 'a', 't', '\n' }; - private static final int ELF_HEADER_SIZE = 52; + private static final int MIN_ELF_HEADER_SIZE = 52; // These are the "known working" versions that I have manually inspected the source for. // Later version may or may not work, depending on what changed. @@ -60,18 +60,27 @@ public class OatFile extends BaseDexBuffer { public static final int SUPPORTED = 1; public static final int UNKNOWN = 2; + private final boolean is64bit; @Nonnull private final OatHeader oatHeader; @Nonnull private final Opcodes opcodes; public OatFile(@Nonnull byte[] buf) { super(buf); - if (buf.length < ELF_HEADER_SIZE) { + if (buf.length < MIN_ELF_HEADER_SIZE) { throw new NotAnOatFileException(); } verifyMagic(buf); + if (buf[4] == 1) { + is64bit = false; + } else if (buf[4] == 2) { + is64bit = true; + } else { + throw new InvalidOatFileException(String.format("Invalid word-size value: %x", buf[5])); + } + OatHeader oatHeader = null; SymbolTable symbolTable = getSymbolTable(); for (Symbol symbol: symbolTable.getSymbols()) { @@ -258,9 +267,18 @@ public class OatFile extends BaseDexBuffer { @Nonnull private List getSections() { - final int offset = readSmallUint(32); - final int entrySize = readUshort(46); - final int entryCount = readUshort(48); + final int offset; + final int entrySize; + final int entryCount; + if (is64bit) { + offset = readLongAsSmallUint(40); + entrySize = readUshort(58); + entryCount = readUshort(60); + } else { + offset = readSmallUint(32); + entrySize = readUshort(46); + entryCount = readUshort(48); + } if (offset + (entrySize * entryCount) > buf.length) { throw new InvalidOatFileException("The ELF section headers extend past the end of the file"); @@ -271,7 +289,11 @@ public class OatFile extends BaseDexBuffer { if (index < 0 || index >= entryCount) { throw new IndexOutOfBoundsException(); } - return new SectionHeader(offset + (index * entrySize)); + if (is64bit) { + return new SectionHeader64Bit(offset + (index * entrySize)); + } else { + return new SectionHeader32Bit(offset + (index * entrySize)); + } } @Override public int size() { @@ -304,43 +326,35 @@ public class OatFile extends BaseDexBuffer { } } - private class SectionHeader { - private final int offset; - + private abstract class SectionHeader { + protected final int offset; public static final int TYPE_DYNAMIC_SYMBOL_TABLE = 11; + public SectionHeader(int offset) { this.offset = offset; } + @Nonnull public String getName() { return getSectionNameStringTable().getString(readSmallUint(offset)); } + public int getType() { return readInt(offset + 4); } + public abstract long getAddress(); + public abstract int getOffset(); + public abstract int getSize(); + public abstract int getLink(); + public abstract int getEntrySize(); + } - public SectionHeader(int offset) { - this.offset = offset; - } + private class SectionHeader32Bit extends SectionHeader { + public SectionHeader32Bit(int offset) { super(offset); } + @Override public long getAddress() { return readInt(offset + 12) & 0xFFFFFFFFL; } + @Override public int getOffset() { return readSmallUint(offset + 16); } + @Override public int getSize() { return readSmallUint(offset + 20); } + @Override public int getLink() { return readSmallUint(offset + 24); } + @Override public int getEntrySize() { return readSmallUint(offset + 36); } + } - @Nonnull - public String getName() { - return getSectionNameStringTable().getString(readSmallUint(offset)); - } - - public int getType() { - return readInt(offset + 4); - } - - public long getAddress() { - return readInt(offset + 12) & 0xFFFFFFFFL; - } - - public int getOffset() { - return readSmallUint(offset + 16); - } - - public int getSize() { - return readSmallUint(offset + 20); - } - - public int getLink() { - return readSmallUint(offset + 24); - } - - public int getEntrySize() { - return readSmallUint(offset + 36); - } + private class SectionHeader64Bit extends SectionHeader { + public SectionHeader64Bit(int offset) { super(offset); } + @Override public long getAddress() { return readLong(offset + 16); } + @Override public int getOffset() { return readLongAsSmallUint(offset + 24); } + @Override public int getSize() { return readLongAsSmallUint(offset + 32); } + @Override public int getLink() { return readSmallUint(offset + 40); } + @Override public int getEntrySize() { return readLongAsSmallUint(offset + 56); } } class SymbolTable { @@ -371,7 +385,11 @@ public class OatFile extends BaseDexBuffer { if (index < 0 || index >= entryCount) { throw new IndexOutOfBoundsException(); } - return new Symbol(offset + index * entrySize); + if (is64bit) { + return new Symbol64(offset + index * entrySize); + } else { + return new Symbol32(offset + index * entrySize); + } } @Override public int size() { @@ -380,29 +398,13 @@ public class OatFile extends BaseDexBuffer { }; } - public class Symbol { - private final int offset; - - public Symbol(int offset) { - this.offset = offset; - } - - @Nonnull - public String getName() { - return stringTable.getString(readSmallUint(offset)); - } - - public int getValue() { - return readSmallUint(offset + 4); - } - - public int getSize() { - return readSmallUint(offset + 8); - } - - public int getSectionIndex() { - return readUshort(offset + 14); - } + public abstract class Symbol { + protected final int offset; + public Symbol(int offset) { this.offset = offset; } + @Nonnull public abstract String getName(); + public abstract long getValue(); + public abstract int getSize(); + public abstract int getSectionIndex(); public int getFileOffset() { SectionHeader sectionHeader; @@ -427,6 +429,26 @@ public class OatFile extends BaseDexBuffer { return (int)fileOffset; } } + + public class Symbol32 extends Symbol { + public Symbol32(int offset) { super(offset); } + + @Nonnull + public String getName() { return stringTable.getString(readSmallUint(offset)); } + public long getValue() { return readSmallUint(offset + 4); } + public int getSize() { return readSmallUint(offset + 8); } + public int getSectionIndex() { return readUshort(offset + 14); } + } + + public class Symbol64 extends Symbol { + public Symbol64(int offset) { super(offset); } + + @Nonnull + public String getName() { return stringTable.getString(readSmallUint(offset)); } + public long getValue() { return readLong(offset + 8); } + public int getSize() { return readLongAsSmallUint(offset + 16); } + public int getSectionIndex() { return readUshort(offset + 6); } + } } private class StringTable {