mirror of
https://github.com/revanced/smali.git
synced 2025-05-26 02:52:06 +02:00
Add support for reading a classes.dex file from an apk/jar
git-svn-id: https://smali.googlecode.com/svn/trunk@470 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
parent
4080fe659d
commit
c8d83493d1
@ -33,8 +33,7 @@ import org.jf.dexlib.*;
|
|||||||
import org.jf.dexlib.Item;
|
import org.jf.dexlib.Item;
|
||||||
import org.jf.dexlib.StringDataItem;
|
import org.jf.dexlib.StringDataItem;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.security.DigestException;
|
import java.security.DigestException;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
@ -43,6 +42,9 @@ import java.util.Arrays;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.zip.Adler32;
|
import java.util.zip.Adler32;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
import java.util.zip.ZipException;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <h3>Main use cases</h3>
|
* <h3>Main use cases</h3>
|
||||||
@ -236,8 +238,10 @@ public class DexFile
|
|||||||
/**
|
/**
|
||||||
* Construct a new DexFile instance by reading in the given dex file.
|
* Construct a new DexFile instance by reading in the given dex file.
|
||||||
* @param file The dex file to read in
|
* @param file The dex file to read in
|
||||||
|
* @throws IOException if an IOException occurs
|
||||||
*/
|
*/
|
||||||
public DexFile(String file) {
|
public DexFile(String file)
|
||||||
|
throws IOException {
|
||||||
this(new File(file), true);
|
this(new File(file), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,16 +253,20 @@ public class DexFile
|
|||||||
* @param preserveSignedRegisters If true, keep track of any registers in the debug information
|
* @param preserveSignedRegisters If true, keep track of any registers in the debug information
|
||||||
* that are signed, so they will be written in the same format. See
|
* that are signed, so they will be written in the same format. See
|
||||||
* <code>getPreserveSignedRegisters()</code>
|
* <code>getPreserveSignedRegisters()</code>
|
||||||
|
* @throws IOException if an IOException occurs
|
||||||
*/
|
*/
|
||||||
public DexFile(String file, boolean preserveSignedRegisters) {
|
public DexFile(String file, boolean preserveSignedRegisters)
|
||||||
|
throws IOException {
|
||||||
this(new File(file), preserveSignedRegisters);
|
this(new File(file), preserveSignedRegisters);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new DexFile instance by reading in the given dex file.
|
* Construct a new DexFile instance by reading in the given dex file.
|
||||||
* @param file The dex file to read in
|
* @param file The dex file to read in
|
||||||
|
* @throws IOException if an IOException occurs
|
||||||
*/
|
*/
|
||||||
public DexFile(File file) {
|
public DexFile(File file)
|
||||||
|
throws IOException {
|
||||||
this(file, true);
|
this(file, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,14 +278,54 @@ public class DexFile
|
|||||||
* @param preserveSignedRegisters If true, keep track of any registers in the debug information
|
* @param preserveSignedRegisters If true, keep track of any registers in the debug information
|
||||||
* that are signed, so they will be written in the same format.
|
* that are signed, so they will be written in the same format.
|
||||||
* @see #getPreserveSignedRegisters
|
* @see #getPreserveSignedRegisters
|
||||||
|
* @throws IOException if an IOException occurs
|
||||||
*/
|
*/
|
||||||
public DexFile(File file, boolean preserveSignedRegisters) {
|
public DexFile(File file, boolean preserveSignedRegisters)
|
||||||
|
throws IOException {
|
||||||
this(preserveSignedRegisters);
|
this(preserveSignedRegisters);
|
||||||
|
|
||||||
|
long fileLength;
|
||||||
|
InputStream inputStream;
|
||||||
byte[] magic = FileUtils.readFile(file, 0, 8);
|
byte[] magic = FileUtils.readFile(file, 0, 8);
|
||||||
|
|
||||||
|
//do we have a zip file?
|
||||||
|
if (magic[0] == 0x50 && magic[1] == 0x4B) {
|
||||||
|
ZipFile zipFile = new ZipFile(file);
|
||||||
|
ZipEntry zipEntry = zipFile.getEntry("classes.dex");
|
||||||
|
if (zipEntry == null) {
|
||||||
|
throw new RuntimeException("zip file " + file.getName() + " does not contain a classes.dex file");
|
||||||
|
}
|
||||||
|
fileLength = zipEntry.getSize();
|
||||||
|
if (fileLength < 40) {
|
||||||
|
throw new RuntimeException("The classes.dex file in " + file.getName() + " is too small to be a" +
|
||||||
|
" valid dex file");
|
||||||
|
} else if (fileLength > Integer.MAX_VALUE) {
|
||||||
|
throw new RuntimeException("The classes.dex file in " + file.getName() + " is too large to read in");
|
||||||
|
}
|
||||||
|
inputStream = new BufferedInputStream(zipFile.getInputStream(zipEntry));
|
||||||
|
|
||||||
|
inputStream.mark(8);
|
||||||
|
for (int i=0; i<8; i++) {
|
||||||
|
magic[i] = (byte)inputStream.read();
|
||||||
|
}
|
||||||
|
inputStream.reset();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fileLength = file.length();
|
||||||
|
if (fileLength < 40) {
|
||||||
|
throw new RuntimeException(file.getName() + " is too small to be a valid dex file");
|
||||||
|
}
|
||||||
|
if (fileLength < 40) {
|
||||||
|
throw new RuntimeException(file.getName() + " is too small to be a valid dex file");
|
||||||
|
} else if (fileLength > Integer.MAX_VALUE) {
|
||||||
|
throw new RuntimeException(file.getName() + " is too large to read in");
|
||||||
|
}
|
||||||
|
inputStream = new FileInputStream(file);
|
||||||
|
}
|
||||||
|
|
||||||
byte[] dexMagic, odexMagic;
|
byte[] dexMagic, odexMagic;
|
||||||
|
|
||||||
dexMagic = HeaderItem.MAGIC;
|
dexMagic = org.jf.dexlib.HeaderItem.MAGIC;
|
||||||
odexMagic = OdexHeaderItem.MAGIC;
|
odexMagic = OdexHeaderItem.MAGIC;
|
||||||
|
|
||||||
boolean isDex = true;
|
boolean isDex = true;
|
||||||
@ -294,20 +342,18 @@ public class DexFile
|
|||||||
Input in;
|
Input in;
|
||||||
|
|
||||||
if (isOdex) {
|
if (isOdex) {
|
||||||
byte[] odexHeaderBytes = FileUtils.readFile(file, 0, 40);
|
byte[] odexHeaderBytes = FileUtils.readStream(inputStream, 40);
|
||||||
Input odexHeaderIn = new ByteArrayInput(odexHeaderBytes);
|
Input odexHeaderIn = new ByteArrayInput(odexHeaderBytes);
|
||||||
OdexHeaderItem odexHeader = new OdexHeaderItem(odexHeaderIn);
|
OdexHeaderItem odexHeader = new OdexHeaderItem(odexHeaderIn);
|
||||||
|
|
||||||
in = new ByteArrayInput(FileUtils.readFile(file, odexHeader.dexOffset, odexHeader.dexLength));
|
in = new ByteArrayInput(FileUtils.readStream(inputStream, odexHeader.dexLength));
|
||||||
} else if (isDex) {
|
} else if (isDex) {
|
||||||
in = new ByteArrayInput(FileUtils.readFile(file));
|
in = new ByteArrayInput(FileUtils.readStream(inputStream, (int)fileLength));
|
||||||
} else {
|
} else {
|
||||||
|
StringBuffer sb = new StringBuffer("bad magic value:");
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("bad magic value:");
|
|
||||||
for (int i=0; i<8; i++) {
|
for (int i=0; i<8; i++) {
|
||||||
sb.append(" ");
|
sb.append(" ");
|
||||||
sb.append(magic[i]);
|
sb.append(Hex.u1(magic[i]));
|
||||||
}
|
}
|
||||||
throw new RuntimeException(sb.toString());
|
throw new RuntimeException(sb.toString());
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package org.jf.dexlib.Util;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File I/O utilities.
|
* File I/O utilities.
|
||||||
@ -38,7 +39,8 @@ public final class FileUtils {
|
|||||||
* @param fileName non-null; name of the file to read
|
* @param fileName non-null; name of the file to read
|
||||||
* @return non-null; contents of the file
|
* @return non-null; contents of the file
|
||||||
*/
|
*/
|
||||||
public static byte[] readFile(String fileName) {
|
public static byte[] readFile(String fileName)
|
||||||
|
throws IOException {
|
||||||
File file = new File(fileName);
|
File file = new File(fileName);
|
||||||
return readFile(file);
|
return readFile(file);
|
||||||
}
|
}
|
||||||
@ -50,7 +52,8 @@ public final class FileUtils {
|
|||||||
* @param file non-null; the file to read
|
* @param file non-null; the file to read
|
||||||
* @return non-null; contents of the file
|
* @return non-null; contents of the file
|
||||||
*/
|
*/
|
||||||
public static byte[] readFile(File file) {
|
public static byte[] readFile(File file)
|
||||||
|
throws IOException {
|
||||||
return readFile(file, 0, -1);
|
return readFile(file, 0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +67,8 @@ public final class FileUtils {
|
|||||||
* end of the file
|
* end of the file
|
||||||
* @return non-null; contents of the file
|
* @return non-null; contents of the file
|
||||||
*/
|
*/
|
||||||
public static byte[] readFile(File file, int offset, int length) {
|
public static byte[] readFile(File file, int offset, int length)
|
||||||
|
throws IOException {
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
throw new RuntimeException(file + ": file not found");
|
throw new RuntimeException(file + ": file not found");
|
||||||
}
|
}
|
||||||
@ -91,33 +95,38 @@ public final class FileUtils {
|
|||||||
throw new RuntimeException(file + ": file too short");
|
throw new RuntimeException(file + ": file too short");
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] result = new byte[length];
|
FileInputStream in = new FileInputStream(file);
|
||||||
|
|
||||||
try {
|
int at = offset;
|
||||||
FileInputStream in = new FileInputStream(file);
|
while(at > 0) {
|
||||||
|
long amt = in.skip(at);
|
||||||
int at = offset;
|
if (amt == -1) {
|
||||||
while(at > 0) {
|
throw new RuntimeException(file + ": unexpected EOF");
|
||||||
long amt = in.skip(at);
|
|
||||||
if (amt == -1) {
|
|
||||||
throw new RuntimeException(file + ": unexpected EOF");
|
|
||||||
}
|
|
||||||
at -= amt;
|
|
||||||
}
|
}
|
||||||
|
at -= amt;
|
||||||
while (length > 0) {
|
|
||||||
int amt = in.read(result, at, length);
|
|
||||||
if (amt == -1) {
|
|
||||||
throw new RuntimeException(file + ": unexpected EOF");
|
|
||||||
}
|
|
||||||
at += amt;
|
|
||||||
length -= amt;
|
|
||||||
}
|
|
||||||
in.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new RuntimeException(file + ": trouble reading", ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte[] result = readStream(in, length);
|
||||||
|
|
||||||
|
in.close();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] readStream(InputStream in, int length)
|
||||||
|
throws IOException {
|
||||||
|
byte[] result = new byte[length];
|
||||||
|
int at=0;
|
||||||
|
|
||||||
|
while (length > 0) {
|
||||||
|
int amt = in.read(result, at, length);
|
||||||
|
if (amt == -1) {
|
||||||
|
throw new RuntimeException("unexpected EOF");
|
||||||
|
}
|
||||||
|
at += amt;
|
||||||
|
length -= amt;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user