mirror of
https://github.com/revanced/smali.git
synced 2025-05-23 18:16:23 +02:00
Let baksmali infer the api level when possible
This commit is contained in:
parent
e6f4475c87
commit
077c5c1b91
@ -55,7 +55,7 @@ public abstract class DexInputCommand extends Command {
|
||||
@Parameter(names = {"-a", "--api"},
|
||||
description = "The numeric api level of the file being disassembled.")
|
||||
@ExtendedParameter(argumentNames = "api")
|
||||
public int apiLevel = 15;
|
||||
public int apiLevel = -1;
|
||||
|
||||
@Parameter(description = "A dex/apk/oat/odex file. For apk or oat files that contain multiple dex " +
|
||||
"files, you can specify the specific entry to use as if the apk/oat file was a directory. " +
|
||||
@ -125,6 +125,11 @@ public abstract class DexInputCommand extends Command {
|
||||
dexEntry = input.substring(file.getPath().length() + 1);
|
||||
}
|
||||
|
||||
Opcodes opcodes = null;
|
||||
if (apiLevel != -1) {
|
||||
opcodes = Opcodes.forApi(apiLevel);
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(dexEntry)) {
|
||||
boolean exactMatch = false;
|
||||
if (dexEntry.length() > 2 && dexEntry.charAt(0) == '"' && dexEntry.charAt(dexEntry.length() - 1) == '"') {
|
||||
@ -135,13 +140,13 @@ public abstract class DexInputCommand extends Command {
|
||||
inputEntry = dexEntry;
|
||||
|
||||
try {
|
||||
dexFile = DexFileFactory.loadDexEntry(file, dexEntry, exactMatch, Opcodes.forApi(apiLevel));
|
||||
dexFile = DexFileFactory.loadDexEntry(file, dexEntry, exactMatch, opcodes);
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
dexFile = DexFileFactory.loadDexFile(file, Opcodes.forApi(apiLevel));
|
||||
dexFile = DexFileFactory.loadDexFile(file, opcodes);
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ import java.util.List;
|
||||
public final class DexFileFactory {
|
||||
|
||||
@Nonnull
|
||||
public static DexBackedDexFile loadDexFile(@Nonnull String path, @Nonnull Opcodes opcodes) throws IOException {
|
||||
public static DexBackedDexFile loadDexFile(@Nonnull String path, @Nullable Opcodes opcodes) throws IOException {
|
||||
return loadDexFile(new File(path), opcodes);
|
||||
}
|
||||
|
||||
@ -79,7 +79,7 @@ public final class DexFileFactory {
|
||||
* in a zip file is not a valid dex file
|
||||
*/
|
||||
@Nonnull
|
||||
public static DexBackedDexFile loadDexFile(@Nonnull File file, @Nonnull Opcodes opcodes) throws IOException {
|
||||
public static DexBackedDexFile loadDexFile(@Nonnull File file, @Nullable Opcodes opcodes) throws IOException {
|
||||
if (!file.exists()) {
|
||||
throw new DexFileNotFoundException("%s does not exist", file.getName());
|
||||
}
|
||||
@ -176,7 +176,7 @@ public final class DexFileFactory {
|
||||
* @throws MultipleMatchingDexEntriesException If multiple entries match the given dexEntry
|
||||
*/
|
||||
public static DexBackedDexFile loadDexEntry(@Nonnull File file, @Nonnull String dexEntry,
|
||||
boolean exactMatch, @Nonnull Opcodes opcodes) throws IOException {
|
||||
boolean exactMatch, @Nullable Opcodes opcodes) throws IOException {
|
||||
if (!file.exists()) {
|
||||
throw new DexFileNotFoundException("Container file %s does not exist", file.getName());
|
||||
}
|
||||
@ -456,10 +456,6 @@ public final class DexFileFactory {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull @Override public Opcodes getOpcodes() {
|
||||
return dexFile.getOpcodes();
|
||||
}
|
||||
}
|
||||
|
||||
public static class FilenameVdexProvider implements VdexProvider {
|
||||
|
@ -64,6 +64,11 @@ public class Opcodes {
|
||||
return new Opcodes(NO_VERSION, artVersion);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Opcodes forDexVersion(int dexVersion) {
|
||||
return new Opcodes(VersionMap.mapDexVersionToApi(dexVersion) , NO_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a default Opcodes instance for when the exact Opcodes to use doesn't matter or isn't known
|
||||
*/
|
||||
|
@ -34,6 +34,19 @@ package org.jf.dexlib2;
|
||||
public class VersionMap {
|
||||
public static final int NO_VERSION = -1;
|
||||
|
||||
public static int mapDexVersionToApi(int dexVersion) {
|
||||
if (dexVersion == 35) {
|
||||
return 23;
|
||||
}
|
||||
if (dexVersion == 37) {
|
||||
return 25;
|
||||
}
|
||||
if (dexVersion == 38) {
|
||||
return 27;
|
||||
}
|
||||
throw new RuntimeException("Unsupported dex version " + dexVersion);
|
||||
}
|
||||
|
||||
public static int mapArtVersionToApi(int artVersion) {
|
||||
if (artVersion >= 124) {
|
||||
return 26;
|
||||
|
@ -71,13 +71,20 @@ public class DexBackedDexFile extends BaseDexBuffer implements DexFile {
|
||||
private final int classStartOffset;
|
||||
private final int mapOffset;
|
||||
|
||||
protected DexBackedDexFile(@Nonnull Opcodes opcodes, @Nonnull byte[] buf, int offset, boolean verifyMagic) {
|
||||
protected DexBackedDexFile(@Nullable Opcodes opcodes, @Nonnull byte[] buf, int offset, boolean verifyMagic) {
|
||||
super(buf, offset);
|
||||
|
||||
this.opcodes = opcodes;
|
||||
|
||||
int dexVersion;
|
||||
if (verifyMagic) {
|
||||
DexUtil.verifyDexHeader(buf, offset);
|
||||
dexVersion = DexUtil.verifyDexHeader(buf, offset);
|
||||
} else {
|
||||
dexVersion = HeaderItem.getVersion(buf, offset);
|
||||
}
|
||||
|
||||
if (opcodes == null) {
|
||||
this.opcodes = Opcodes.forDexVersion(dexVersion);
|
||||
} else {
|
||||
this.opcodes = opcodes;
|
||||
}
|
||||
|
||||
stringCount = readSmallUint(HeaderItem.STRING_COUNT_OFFSET);
|
||||
@ -95,20 +102,20 @@ public class DexBackedDexFile extends BaseDexBuffer implements DexFile {
|
||||
mapOffset = readSmallUint(HeaderItem.MAP_OFFSET);
|
||||
}
|
||||
|
||||
public DexBackedDexFile(@Nonnull Opcodes opcodes, @Nonnull BaseDexBuffer buf) {
|
||||
public DexBackedDexFile(@Nullable Opcodes opcodes, @Nonnull BaseDexBuffer buf) {
|
||||
this(opcodes, buf.buf, buf.baseOffset);
|
||||
}
|
||||
|
||||
public DexBackedDexFile(@Nonnull Opcodes opcodes, @Nonnull byte[] buf, int offset) {
|
||||
public DexBackedDexFile(@Nullable Opcodes opcodes, @Nonnull byte[] buf, int offset) {
|
||||
this(opcodes, buf, offset, false);
|
||||
}
|
||||
|
||||
public DexBackedDexFile(@Nonnull Opcodes opcodes, @Nonnull byte[] buf) {
|
||||
public DexBackedDexFile(@Nullable Opcodes opcodes, @Nonnull byte[] buf) {
|
||||
this(opcodes, buf, 0, true);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static DexBackedDexFile fromInputStream(@Nonnull Opcodes opcodes, @Nonnull InputStream is)
|
||||
public static DexBackedDexFile fromInputStream(@Nullable Opcodes opcodes, @Nonnull InputStream is)
|
||||
throws IOException {
|
||||
DexUtil.verifyDexHeader(is);
|
||||
|
||||
|
@ -177,10 +177,6 @@ public class OatFile extends BaseDexBuffer implements MultiDexContainer<OatDexFi
|
||||
return Arrays.asList(bcp.split(":"));
|
||||
}
|
||||
|
||||
@Nonnull @Override public Opcodes getOpcodes() {
|
||||
return opcodes;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<OatDexFile> getDexFiles() {
|
||||
return new AbstractForwardSequentialList<OatDexFile>() {
|
||||
|
@ -58,23 +58,18 @@ import java.util.zip.ZipFile;
|
||||
public class ZipDexContainer implements MultiDexContainer<ZipDexFile> {
|
||||
|
||||
private final File zipFilePath;
|
||||
private final Opcodes opcodes;
|
||||
@Nullable private final Opcodes opcodes;
|
||||
|
||||
/**
|
||||
* Constructs a new ZipDexContainer for the given zip file
|
||||
*
|
||||
* @param zipFilePath The path to the zip file
|
||||
* @param opcodes The Opcodes instance to use when loading dex files from this container
|
||||
*/
|
||||
public ZipDexContainer(@Nonnull File zipFilePath, @Nonnull Opcodes opcodes) {
|
||||
public ZipDexContainer(@Nonnull File zipFilePath, @Nullable Opcodes opcodes) {
|
||||
this.zipFilePath = zipFilePath;
|
||||
this.opcodes = opcodes;
|
||||
}
|
||||
|
||||
@Nonnull @Override public Opcodes getOpcodes() {
|
||||
return opcodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of the names of dex files in this zip file.
|
||||
*
|
||||
@ -147,7 +142,7 @@ public class ZipDexContainer implements MultiDexContainer<ZipDexFile> {
|
||||
|
||||
private final String entryName;
|
||||
|
||||
protected ZipDexFile(@Nonnull Opcodes opcodes, @Nonnull byte[] buf, @Nonnull String entryName) {
|
||||
protected ZipDexFile(@Nullable Opcodes opcodes, @Nonnull byte[] buf, @Nonnull String entryName) {
|
||||
super(opcodes, buf, 0);
|
||||
this.entryName = entryName;
|
||||
}
|
||||
|
@ -31,8 +31,6 @@
|
||||
|
||||
package org.jf.dexlib2.iface;
|
||||
|
||||
import org.jf.dexlib2.Opcodes;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
@ -55,11 +53,6 @@ public interface MultiDexContainer<T extends DexFile> {
|
||||
*/
|
||||
@Nullable T getEntry(@Nonnull String entryName) throws IOException;
|
||||
|
||||
/**
|
||||
* @return the Opcodes instance associated with this MultiDexContainer
|
||||
*/
|
||||
@Nonnull Opcodes getOpcodes();
|
||||
|
||||
/**
|
||||
* This class represents a dex file that is contained in a MultiDexContainer
|
||||
*/
|
||||
|
@ -50,11 +50,12 @@ public class DexUtil {
|
||||
* The inputStream must support mark(), and will be reset to initial position upon exiting the method
|
||||
*
|
||||
* @param inputStream An input stream that is positioned at a dex header
|
||||
* @return The dex version
|
||||
* @throws NotADexFile If the file is not a dex file
|
||||
* @throws InvalidFile If the header appears to be a dex file, but is not valid for some reason
|
||||
* @throws UnsupportedFile If the dex header is valid, but uses unsupported functionality
|
||||
*/
|
||||
public static void verifyDexHeader(@Nonnull InputStream inputStream) throws IOException {
|
||||
public static int verifyDexHeader(@Nonnull InputStream inputStream) throws IOException {
|
||||
if (!inputStream.markSupported()) {
|
||||
throw new IllegalArgumentException("InputStream must support mark");
|
||||
}
|
||||
@ -68,7 +69,7 @@ public class DexUtil {
|
||||
inputStream.reset();
|
||||
}
|
||||
|
||||
verifyDexHeader(partialHeader, 0);
|
||||
return verifyDexHeader(partialHeader, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,11 +77,12 @@ public class DexUtil {
|
||||
*
|
||||
* @param buf A byte array containing at least the first 44 bytes of a dex file
|
||||
* @param offset The offset within the array to the dex header
|
||||
* @return The dex version
|
||||
* @throws NotADexFile If the file is not a dex file
|
||||
* @throws InvalidFile If the header appears to be a dex file, but is not valid for some reason
|
||||
* @throws UnsupportedFile If the dex header is valid, but uses unsupported functionality
|
||||
*/
|
||||
public static void verifyDexHeader(@Nonnull byte[] buf, int offset) {
|
||||
public static int verifyDexHeader(@Nonnull byte[] buf, int offset) {
|
||||
int dexVersion = HeaderItem.getVersion(buf, offset);
|
||||
if (dexVersion == -1) {
|
||||
StringBuilder sb = new StringBuilder("Not a valid dex magic value:");
|
||||
@ -102,6 +104,8 @@ public class DexUtil {
|
||||
if (endian != HeaderItem.LITTLE_ENDIAN_TAG) {
|
||||
throw new InvalidFile(String.format("Invalid endian tag: 0x%x", endian));
|
||||
}
|
||||
|
||||
return dexVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,9 +223,5 @@ public class DexEntryFinderTest {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull @Override public Opcodes getOpcodes() {
|
||||
return Opcodes.getDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user