fix: prevent collisions in method ids for java-input

This commit is contained in:
Skylot
2021-08-13 15:43:57 +01:00
parent 7c0671c81b
commit 55bb20cf29
9 changed files with 51 additions and 31 deletions
@@ -21,22 +21,22 @@ import jadx.api.plugins.utils.ZipSecurity;
public class JavaFileLoader {
private static final Logger LOG = LoggerFactory.getLogger(JavaFileLoader.class);
public static final int MAX_MAGIC_SIZE = 4;
public static final byte[] JAVA_CLASS_FILE_MAGIC = { (byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE };
public static final byte[] ZIP_FILE_MAGIC = { 0x50, 0x4B, 0x03, 0x04 };
private static final int MAX_MAGIC_SIZE = 4;
private static final byte[] JAVA_CLASS_FILE_MAGIC = { (byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE };
private static final byte[] ZIP_FILE_MAGIC = { 0x50, 0x4B, 0x03, 0x04 };
private static int classUniqId = 1;
private int classUniqId = 1;
public static List<JavaClassReader> collectFiles(List<Path> inputFiles) {
public List<JavaClassReader> collectFiles(List<Path> inputFiles) {
return inputFiles.stream()
.map(Path::toFile)
.map(JavaFileLoader::loadFromFile)
.map(this::loadFromFile)
.filter(list -> !list.isEmpty())
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
private static List<JavaClassReader> loadFromFile(File file) {
private List<JavaClassReader> loadFromFile(File file) {
try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) {
return loadReader(file, inputStream, file.getAbsolutePath());
} catch (Exception e) {
@@ -45,7 +45,7 @@ public class JavaFileLoader {
}
}
private static List<JavaClassReader> loadReader(File file, InputStream in, String inputFileName) throws IOException {
private List<JavaClassReader> loadReader(File file, InputStream in, String inputFileName) throws IOException {
byte[] magic = new byte[MAX_MAGIC_SIZE];
if (in.read(magic) != magic.length) {
return Collections.emptyList();
@@ -61,7 +61,7 @@ public class JavaFileLoader {
return Collections.emptyList();
}
private static List<JavaClassReader> collectFromZip(File file) {
private List<JavaClassReader> collectFromZip(File file) {
List<JavaClassReader> result = new ArrayList<>();
try {
ZipSecurity.readZipEntries(file, (entry, in) -> {
@@ -94,7 +94,7 @@ public class JavaFileLoader {
int estimateSize = prefix.length + in.available();
ByteArrayOutputStream out = new ByteArrayOutputStream(estimateSize);
out.write(prefix);
byte[] buffer = new byte[0xFFFF];
byte[] buffer = new byte[8 * 1024];
while (true) {
int len = in.read(buffer);
if (len == -1) {
@@ -105,11 +105,7 @@ public class JavaFileLoader {
return out.toByteArray();
}
private static int getNextUniqId() {
classUniqId++;
if (classUniqId >= 0xFFFF) {
classUniqId = 1;
}
return classUniqId;
private int getNextUniqId() {
return classUniqId++;
}
}
@@ -22,7 +22,7 @@ public class JavaInputPlugin implements JadxInputPlugin {
@Override
public ILoadResult loadFiles(List<Path> inputFiles) {
List<JavaClassReader> readers = JavaFileLoader.collectFiles(inputFiles);
List<JavaClassReader> readers = new JavaFileLoader().collectFiles(inputFiles);
if (readers.isEmpty()) {
return EmptyLoadResult.INSTANCE;
}
@@ -78,7 +78,7 @@ public class ConstPoolReader {
int descIdx = data.readU2();
JavaMethodRef mthRef = new JavaMethodRef();
mthRef.initUniqId(clsReader, clsIdx, nameIdx, descIdx);
mthRef.initUniqId(clsReader, idx, true);
mthRef.setParentClassType(getClass(clsIdx));
mthRef.setName(getUtf8(nameIdx));
mthRef.setDescr(getUtf8(descIdx));
@@ -94,7 +94,7 @@ public class JavaClassData implements IClassData {
methodRef.setParentClassType(classType);
JavaMethodData method = new JavaMethodData(this, methodRef);
for (int i = 0; i < methodsCount; i++) {
parseMethod(reader, method, clsIdx);
parseMethod(reader, method, i);
mthConsumer.accept(method);
}
}
@@ -112,7 +112,7 @@ public class JavaClassData implements IClassData {
field.setAttributes(attributes);
}
private void parseMethod(DataReader reader, JavaMethodData method, int clsIdx) {
private void parseMethod(DataReader reader, JavaMethodData method, int id) {
int accessFlags = reader.readU2();
int nameIdx = reader.readU2();
int descriptorIdx = reader.readU2();
@@ -120,7 +120,7 @@ public class JavaClassData implements IClassData {
JavaMethodRef methodRef = method.getMethodRef();
methodRef.reset();
methodRef.initUniqId(clsReader, clsIdx, nameIdx, descriptorIdx);
methodRef.initUniqId(clsReader, id, false);
methodRef.setName(constPoolReader.getUtf8(nameIdx));
methodRef.setDescr(constPoolReader.getUtf8(descriptorIdx));
@@ -16,9 +16,15 @@ public class JavaMethodRef extends JavaMethodProto implements IMethodRef {
return uniqId;
}
public void initUniqId(JavaClassReader clsReader, int clsIdx, int nameIdx, int descIdx) {
// TODO: check for id overlap
this.uniqId = (clsReader.getId() & 0xFFF) << 20 | (clsIdx & 0xFF) << 12 | (nameIdx & 0xFF) << 4 | descIdx & 0xF;
public void initUniqId(JavaClassReader clsReader, int id, boolean fromConstPool) {
int readerId = clsReader.getId();
if (readerId > 0xFFFF || id > 0x7FFF) {
// loaded more than 65535 classes or more than 32767 methods in this class -> disable caching
this.uniqId = 0;
} else {
int source = fromConstPool ? 0 : 0x8000;
this.uniqId = (readerId & 0xFFFF) << 16 | source | id & 0x7FFF;
}
}
@Override