Skip to content

Instantly share code, notes, and snippets.

@asdf913
Last active January 18, 2025 15:07
Show Gist options
  • Save asdf913/aefc815914c11c625c418e7d56674828 to your computer and use it in GitHub Desktop.
Save asdf913/aefc815914c11c625c418e7d56674828 to your computer and use it in GitHub Desktop.
List of allowed "org.apache.pdfbox.util.filetypedetector.FileType" and test if a given file is accepted by "org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject.createFromByteArray(org.apache.pdfbox.pdmodel.PDDocument,byte[],java.lang.String)" method
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.FieldOrMethod;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.FieldInstruction;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.IF_ACMPEQ;
import org.apache.bcel.generic.IF_ACMPNE;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.InvokeInstruction;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.Type;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.function.FailableFunction;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
public class PDImageXObjectTest {
public static void main(final String[] args)
throws NoSuchMethodException, IOException, IllegalAccessException, InvocationTargetException {
//
final Entry<Method, Collection<Object>> entry = getPDImageXObjectCreateFromByteArrayDetectFileTypeMethodAndAllowedFileTypes();
//
System.out.println(entry);
//
// (public static org.apache.pdfbox.util.filetypedetector.FileType
// org.apache.pdfbox.util.filetypedetector.FileTypeDetector.detectFileType(byte[]),[JPEG,
// PNG, TIFF, BMP, GIF])
//
if (args != null && args.length > 0 && entry != null) {
//
final File file = new File(args[0]);
//
System.out.println();
//
final Object object = entry.getKey().invoke(null, Files.readAllBytes(file.toPath()));
//
System.out.println(object);
//
System.out.println(entry.getValue().contains(object));
//
} // if
//
}
private static Entry<Method, Collection<Object>> getPDImageXObjectCreateFromByteArrayDetectFileTypeMethodAndAllowedFileTypes()
throws IOException, NoSuchMethodException, IllegalAccessException {
//
Class<?> clz = PDImageXObject.class;
//
Collection<Object> allowedFileType = null;
//
MutablePair<Method, Collection<Object>> entry = null;
//
try (final InputStream is = getResourceAsStream(clz,
String.format("/%1$s.class", StringUtils.replace(getName(clz), ".", "/")))) {
//
// org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject.createFromByteArray(org.apache.pdfbox.pdmodel.PDDocument,byte[],java.lang.String)
//
final org.apache.bcel.classfile.Method m = getMethod(
parse(testAndApply(Objects::nonNull, is, x -> new ClassParser(x, null), null)),
getDeclaredMethod(clz, "createFromByteArray", PDDocument.class, byte[].class, String.class));
//
final Instruction[] ins = getInstructions(
getInstructionList(testAndApply(Objects::nonNull, m, x -> new MethodGen(x, null, null), null)));
//
final ConstantPool cp = getConstantPool(m);
//
final ConstantPoolGen cpg = new ConstantPoolGen(cp);
//
Instruction in = null;
//
INVOKESTATIC invokestatic = null;
//
Object object = null;
//
Type[] argumentTypes = null;
//
List<Field> fs = null;
//
int size = 0;
//
for (int i = 0; i < length(ins); i++) {
//
if ((in = ArrayUtils.get(ins, i)) instanceof INVOKESTATIC temp && invokestatic == null) {
//
if (length((argumentTypes = getArgumentTypes(invokestatic = temp, cpg))) == 1) {
//
if ((entry = ObjectUtils.getIfNull(entry, MutablePair::new)) != null) {
//
entry.setLeft(getDeclaredMethod(clz = forName(getClassName(invokestatic, cpg)),
getMethodName(invokestatic, cpg),
forName(getClassName(ArrayUtils.get(argumentTypes, 0)))));
//
} // if
//
} // if
//
} else if (i > 0 && ArrayUtils.get(ins, i - 1) instanceof GETSTATIC getstatic
&& Boolean.logicalOr(in instanceof IF_ACMPNE, in instanceof IF_ACMPEQ)) {
//
if ((size = IterableUtils.size(fs = toList(
filter(Arrays.stream(getDeclaredFields(forName(getClassName(getstatic.getFieldType(cpg))))),
f -> Objects.equals(getName(f), getFieldName(getstatic, cpg)))))) > 1) {
//
throw new IllegalStateException();
//
} else if (size == 1) {
//
if (!contains(allowedFileType = ObjectUtils.getIfNull(allowedFileType, ArrayList::new),
object = FieldUtils.readStaticField(IterableUtils.get(fs, 0)))) {
//
add(allowedFileType, object);
//
} // if
//
} // if
//
} // if
//
} // for
//
} // try
//
if ((entry = ObjectUtils.getIfNull(entry, MutablePair::new)) != null) {
//
entry.setValue(allowedFileType);
//
} // if
//
return entry;
//
}
private static ConstantPool getConstantPool(final FieldOrMethod instance) {
return instance != null ? instance.getConstantPool() : null;
}
private static String getFieldName(final FieldInstruction instance, final ConstantPoolGen cpg) {
return instance != null ? instance.getFieldName(cpg) : null;
}
private static String getClassName(final Type instance) {
return instance != null ? instance.getClassName() : null;
}
private static String getMethodName(final InvokeInstruction instance, final ConstantPoolGen cpg) {
return instance != null ? instance.getMethodName(cpg) : null;
}
private static String getClassName(final InvokeInstruction instance, final ConstantPoolGen cpg) {
return instance != null ? instance.getClassName(cpg) : null;
}
private static Type[] getArgumentTypes(final InvokeInstruction instance, final ConstantPoolGen cpg) {
return instance != null ? instance.getArgumentTypes(cpg) : null;
}
private static InstructionList getInstructionList(final MethodGen instance) {
return instance != null ? instance.getInstructionList() : null;
}
private static org.apache.bcel.classfile.Method getMethod(final JavaClass instance,
final java.lang.reflect.Method m) {
return instance != null ? instance.getMethod(m) : null;
}
private static <E> void add(final Collection<E> items, final E item) {
if (items != null) {
items.add(item);
}
}
private static boolean contains(final Collection<?> items, final Object item) {
return items != null && items.contains(item);
}
private static Instruction[] getInstructions(final InstructionList instance) {
return instance != null ? instance.getInstructions() : null;
}
private static JavaClass parse(final ClassParser instance) throws IOException {
return instance != null ? instance.parse() : null;
}
private static <T> List<T> toList(final Stream<T> instance) {
return instance != null ? instance.toList() : null;
}
private static <T> Stream<T> filter(final Stream<T> instance, final Predicate<? super T> predicate) {
//
return instance != null && (predicate != null || Proxy.isProxyClass(getClass(instance)))
? instance.filter(predicate)
: null;
//
}
private static Class<?> getClass(final Object instance) {
return instance != null ? instance.getClass() : null;
}
private static Class<?> forName(final String className) {
try {
return StringUtils.isNotBlank(className) ? Class.forName(className) : null;
} catch (final ClassNotFoundException e) {
return null;
}
}
private static int length(final Object[] instance) {
return instance != null ? instance.length : 0;
}
private static <T, R, E extends Throwable> R testAndApply(final Predicate<T> predicate, final T value,
final FailableFunction<T, R, E> functionTrue, final FailableFunction<T, R, E> functionFalse) throws E {
return test(predicate, value) ? apply(functionTrue, value) : apply(functionFalse, value);
}
private static <T, R, E extends Throwable> R apply(final FailableFunction<T, R, E> instance, final T value)
throws E {
return instance != null ? instance.apply(value) : null;
}
private static final <T> boolean test(final Predicate<T> instance, final T value) {
return instance != null && instance.test(value);
}
private static Field[] getDeclaredFields(final Class<?> instance) {
return instance != null ? instance.getDeclaredFields() : null;
}
private static Method getDeclaredMethod(final Class<?> instance, final String name,
final Class<?>... parameterTypes) throws NoSuchMethodException {
return instance != null ? instance.getDeclaredMethod(name, parameterTypes) : null;
}
private static String getName(final Class<?> instance) {
return instance != null ? instance.getName() : null;
}
private static String getName(final Member instance) {
return instance != null ? instance.getName() : null;
}
private static InputStream getResourceAsStream(final Class<?> instance, final String name) {
return instance != null && name != null ? instance.getResourceAsStream(name) : null;
}
}
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.bcel/bcel -->
<dependency>
<groupId>org.apache.bcel</groupId>
<artifactId>bcel</artifactId>
<version>6.10.0</version>
</dependency>
<!--https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.3</version>
</dependency>
</dependencies>
@asdf913
Copy link
Author

asdf913 commented Jan 18, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment