The list dex command should generate an error when used on a non-zip/oat file

This commit is contained in:
Ben Gruver 2016-09-05 10:54:54 -07:00
parent d7d995cc2d
commit fbfe388e40
2 changed files with 86 additions and 50 deletions

View File

@ -35,20 +35,15 @@ import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters; import com.beust.jcommander.Parameters;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.jf.dexlib2.dexbacked.OatFile; import org.jf.dexlib2.DexFileFactory;
import org.jf.dexlib2.dexbacked.raw.HeaderItem;
import org.jf.dexlib2.dexbacked.raw.OdexHeaderItem;
import org.jf.util.jcommander.Command; import org.jf.util.jcommander.Command;
import org.jf.util.jcommander.ExtendedParameter; import org.jf.util.jcommander.ExtendedParameter;
import org.jf.util.jcommander.ExtendedParameters; import org.jf.util.jcommander.ExtendedParameters;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.*; import java.io.File;
import java.util.Collections; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
@Parameters(commandDescription = "Lists the dex files in an apk/oat file.") @Parameters(commandDescription = "Lists the dex files in an apk/oat file.")
@ExtendedParameters( @ExtendedParameters(
@ -85,53 +80,18 @@ public class ListDexCommand extends Command {
if (!file.exists()) { if (!file.exists()) {
System.err.println(String.format("Could not find the file: %s", input)); System.err.println(String.format("Could not find the file: %s", input));
System.exit(-1);
} }
List<String> entries;
try { try {
ZipFile zipFile = new ZipFile(input); entries = DexFileFactory.getAllDexEntries(file);
byte[] magic = new byte[8];
for (ZipEntry zipEntry : Collections.list(zipFile.entries())) {
try {
InputStream inputStream = zipFile.getInputStream(zipEntry);
int totalBytesRead = 0;
while (totalBytesRead < 8) {
int bytesRead = inputStream.read(magic, totalBytesRead, 8 - totalBytesRead);
if (bytesRead == -1) {
break;
}
totalBytesRead += bytesRead;
}
if (totalBytesRead == 8) {
if (HeaderItem.verifyMagic(magic, 0) || OdexHeaderItem.verifyMagic(magic)) {
System.out.println(zipEntry.getName());
}
}
} catch (ZipException ex) {
// ignore and keep looking
continue;
}
}
} catch (ZipException ex) {
// ignore
} catch (IOException ex) { } catch (IOException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
try { for (String entry: entries) {
InputStream inputStream = new BufferedInputStream(new FileInputStream(input)); System.out.println(entry);
OatFile oatFile = OatFile.fromInputStream(inputStream);
for (OatFile.OatDexFile oatDexFile: oatFile.getDexFiles()) {
System.out.println(oatDexFile.filename);
}
} catch (OatFile.NotAnOatFileException ex) {
// just eat it
} catch (IOException ex) {
throw new RuntimeException(ex);
} }
} }
} }

View File

@ -35,6 +35,7 @@ import com.google.common.base.Joiner;
import com.google.common.collect.AbstractIterator; import com.google.common.collect.AbstractIterator;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.jf.dexlib2.dexbacked.DexBackedDexFile; import org.jf.dexlib2.dexbacked.DexBackedDexFile;
import org.jf.dexlib2.dexbacked.DexBackedDexFile.NotADexFile;
import org.jf.dexlib2.dexbacked.DexBackedOdexFile; import org.jf.dexlib2.dexbacked.DexBackedOdexFile;
import org.jf.dexlib2.dexbacked.OatFile; import org.jf.dexlib2.dexbacked.OatFile;
import org.jf.dexlib2.dexbacked.OatFile.NotAnOatFileException; import org.jf.dexlib2.dexbacked.OatFile.NotAnOatFileException;
@ -249,10 +250,10 @@ public final class DexFileFactory {
* *
* @param file The file to open * @param file The file to open
* @param opcodes The set of opcodes to use * @param opcodes The set of opcodes to use
* @return A DexBackedDexFile for the given file * @return An iterable of DexBackedDexFiles
* @throws IOException * @throws IOException
* @throws DexFileNotFoundException If the given file does not exist * @throws DexFileNotFoundException If the given file does not exist
* @throws UnsupportedFileTypeException If the given file is not a dex, odex, zip or oat file * @throws UnsupportedFileTypeException If the given file is not a zip or oat file
*/ */
public static Iterable<? extends DexBackedDexFile> loadAllDexFiles( public static Iterable<? extends DexBackedDexFile> loadAllDexFiles(
@Nonnull File file, @Nonnull final Opcodes opcodes) throws IOException { @Nonnull File file, @Nonnull final Opcodes opcodes) throws IOException {
@ -284,6 +285,8 @@ public final class DexFileFactory {
} catch (IOException ex) { } catch (IOException ex) {
throw new ExceptionWithContext(ex, "Error while reading %s from %s", throw new ExceptionWithContext(ex, "Error while reading %s from %s",
zipEntry.getName(), finalZipFile.getName()); zipEntry.getName(), finalZipFile.getName());
} catch (NotADexFile ex) {
// ignore and continue
} }
} }
} }
@ -331,7 +334,80 @@ public final class DexFileFactory {
} }
throw new UnsupportedFileTypeException("%s is not an apk, dex, odex or oat file.", file.getPath()); throw new UnsupportedFileTypeException("%s is not an apk, dex, odex or oat file.", file.getPath());
}
/**
* Gets all dex entries from an oat/zip file.
*
* For zip files, only entries that match classes[0-9]*.dex will be returned.
*
* @param file The file to get dex entries from
* @return A list of strings contains the dex entry names
* @throws IOException
* @throws DexFileNotFoundException If the given file does not exist
* @throws UnsupportedFileTypeException If the given file is not a zip or oat file
*/
public static List<String> getAllDexEntries(@Nonnull File file) throws IOException {
if (!file.exists()) {
throw new DexFileNotFoundException("%s does not exist", file.getName());
}
List<String> entries = Lists.newArrayList();
Opcodes opcodes = Opcodes.forApi(15);
ZipFile zipFile = null;
try {
zipFile = new ZipFile(file);
} catch (IOException ex) {
// ignore and continue
}
if (zipFile != null) {
Pattern dexPattern = Pattern.compile("classes[0-9]*.dex");
Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
while (zipEntries.hasMoreElements()) {
ZipEntry zipEntry = zipEntries.nextElement();
if (dexPattern.matcher(zipEntry.getName()).matches()) {
try {
loadDexFromZip(zipFile, zipEntry, opcodes);
entries.add(zipEntry.getName());
} catch (IOException ex) {
throw new IOException(String.format("Error while reading %s from %s",
zipEntry.getName(), zipFile.getName()), ex);
}catch (NotADexFile ex) {
// ignore and continue
}
}
}
return entries;
}
InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
try {
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);
}
for (OatDexFile oatDexFile: oatFile.getDexFiles()) {
entries.add(oatDexFile.filename);
}
return entries;
}
} finally {
inputStream.close();
}
throw new UnsupportedFileTypeException("%s is not an apk, oat file.", file.getPath());
} }
/** /**