Skip to content

Commit

Permalink
Backport alternative class reading method for invalid class CRCs
Browse files Browse the repository at this point in the history
  • Loading branch information
win32kbase committed Jan 2, 2022
1 parent c8a3cf8 commit 52bc600
Showing 1 changed file with 37 additions and 8 deletions.
45 changes: 37 additions & 8 deletions src/main/java/me/coley/recaf/workspace/JarResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.nio.file.Path;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

Expand Down Expand Up @@ -34,21 +35,49 @@ protected Map<String, byte[]> loadClasses() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
EntryLoader loader = getEntryLoader();
ZipInputStream zis = new ZipInputStream(new FileInputStream(getPath().toFile()));
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
// verify entries are classes and valid files
// - skip intentional garbage / zip file abnormalities
if (shouldSkip(entry.getName()))
continue;
if (loader.isValidClassEntry(entry)) {

try {
ZipInputStream zis = new ZipInputStream(new FileInputStream(getPath().toFile()));
ZipEntry entry;

while ((entry = zis.getNextEntry()) != null) {
// verify entries are classes and valid files
// - skip intentional garbage / zip file abnormalities
if (shouldSkip(entry.getName()))
continue;
if (!loader.isValidClassEntry(entry))
continue;

out.reset();
byte[] in = IOUtil.toByteArray(zis, out, buffer);

// There is no possible way a "class" under 30 bytes is valid
if (in.length < 30)
continue;

loader.onClass(entry.getName(), in);
}
} catch (ZipException e) {
if (e.getMessage().contains("invalid entry CRC")) {
// "ZipFile"/"JarFile" reads the entire ZIP file structure before letting us do any entry parsing.
// This may not always be ideal, but this way has one major bonus. It totally ignores CRC validity.
// It also ignores a few other zip entry values.
// Since somebody can intentionally write bogus data there to crash "ZipInputStream" this way works.
ZipFile zf = new ZipFile(getPath().toString());
Enumeration<? extends ZipEntry> entries = zf.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();

if (shouldSkip(entry.getName()))
continue;
if (!loader.isValidClassEntry(entry))
continue;

InputStream zis = zf.getInputStream(entry);
byte[] in = IOUtil.toByteArray(zis);
loader.onClass(entry.getName(), in);
}
}
}
loader.finishClasses();
return loader.getClasses();
Expand Down

0 comments on commit 52bc600

Please # to comment.