Java通过读取前几个字节读取实际文件类型(取证)

3
你好,我需要一种使用Java读取任何文件的前四个字节的方法。
为什么要读取前四个字节?因为它是实际文件类型的取证指纹(文件扩展名不可靠,因为它可以被伪造)。
现在,使用以下Java代码读取文件将读取文件“content”,我认为它会跳过文件头信息……?我无法获取“魔术数字”(前四个字节),因此无法确认给定样本的真实文件类型。
参考链接:http://en.wikipedia.org/wiki/File_carving
byte[] buffer = new byte[4];
InputStream is = new FileInputStream("somwhere.in.the.dark");
if (is.read(buffer) != buffer.length) { 
    // do something 
}
is.close();

读取文件的前 4 个字节

请提供建议?


这就是如何读取文件的前4个字节。对于大多数文件,没有"头文件"和"内容"之分,"magic cookie" 是主要内容的一部分。如果文件较短,则可能只读取少于4个字节。哪些功能不起作用?你看到了什么行为,超出了你的预期吗?实际的文件名是“somwhere”还是“somewhere”? - Andrew Janke
1
你可以使用 https://tika.apache.org/,而不是自己去做这件事。 - blank
如果有人上传了一个exe文件,但将其重命名为xls,Tika能检测到吗? - user3761555
谢谢 Blank。我测试了 Tika。简单的 API 调用 metadata.getProperty("Content-Type") 给了我我需要的一切! - user3761555
3个回答

4
如Blank所建议的,https://tika.apache.org
以下是代码 - 在此示例中,"test3_iamexe.txt"是一个可执行文件,文件扩展名被攻击者重命名为"txt"。
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.mime.MediaType;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.sax.BodyContentHandler;
import org.apache.tika.parser.AbstractParser;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.sax.XHTMLContentHandler;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Set;
import org.apache.tika.metadata.Property;

public class TestTika {

    public static void main(String[] args) {
        File file = null;
    InputStream stream = null;
        String contentType = null;

        try
        {
            file = new File("C:\\tmp\\test3_iamexe.txt");
            stream = new FileInputStream(file);

            AutoDetectParser parser = new AutoDetectParser();
            BodyContentHandler handler = new BodyContentHandler();
            Metadata metadata = new Metadata();

            try {
                // This step here is a little expensive
                parser.parse(stream, handler, metadata);
            } finally {
                stream.close();
            }

            // metadata is a HashMap, you can loop over it see what you need. Alternatively, I think Content-Type is what you need
            contentType = metadata.get("Content-Type");

        } catch(...)
        {
            // handle it
        }

        return;
    }
}

实际上,您不需要使用解析器来获取MIME类型,使用Tika默认设置的简短版本即可:Tika tika = new Tika(); String mimeType = tika.detect(new File("C:\\tmp\\test3_iamexe.txt")); - m1ld

2

我认为你可以使用:

IOUtils.toByteArray(InputStream is) 

看这里:IOUtils.toByteArray用于将InputStream转换为byteArray,然后获取前4个字节。

1
使用java.nio.file API实现此功能,具体而言,请编写自己的FileTypeDetector。
我恰好在我的一个项目中正在做这件事:

https://github.com/fge/java7-fs-more/tree/topic/filetypedetector

通过这个,我能够使用Files.probeContentType()并返回文件的确切类型作为MIME字符串。

请参见测试文件


现在,它是如何工作的:

  • 您编写自己的FileTypeDetector实现(这里提供了检测PNG文件的示例);
  • 如果检测器无法确定类型,则使其返回null
  • 您将实现注册到META-INF/services/java.nio.file.spi.FileTypeDetector中(请参见此处);
  • 测试它...
  • 并使用Files.probeContentType()

Files.probeContentType() 是垃圾... 完全不跨平台,请参见https://dev59.com/rmct5IYBdhLWcg3wCJB-等。 - blank
@blank 很抱歉,但如果你这样说的话,说明你根本不理解它是如何工作的。请查看我的实现和测试文件! - fge
1
在过去的几个月中,我们在Solaris上遇到了一些文件类型返回null的问题,这是有问题的。但是在jdk8中可能已经修复了。 - blank
@user3761555,你可以编写一个可靠地检测多种文件类型的程序(例如,在一个探测器中检测txt和csv,在另一个探测器中检测xls和xlsx等)。JDK提供的实现并不好,因为它仅依赖于文件扩展名,而这些扩展名往往是误导性的。 - fge
顺便说一下:如果 in.read(buf) 返回少于 PNG_HEADER_SIZE 字节,你的PNG检测器将会失败,这是根据文档可能发生的。 - xehpuk
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接