直接读取DD镜像用FileStream即可,需绕过文件系统幻觉、按扇区对齐读取;E01镜像必须用LibEwfSharp解析;提取文件推荐DiscUtils;大镜像须流式处理避免OOM。

直接读取 DD 镜像:用 FileStream 就够了,但得绕开“文件系统”幻觉
DD 镜像本质是原始字节流,没有元数据、不带校验、不加密。C# 里最直接的方式就是把它当普通二进制文件打开——FileStream 完全胜任,不需要第三方库。
常见错误是试图用 Directory.GetFiles 或 DriveInfo 去“枚举镜像里的文件”,这行不通:镜像不是挂载状态,它只是个大文件。你得自己解析分区表(如 MBR/GPT)和文件系统(如 NTFS/FAT32)结构。
- 用
FileStream时务必指定FileAccess.Read和FileShare.Read,避免被其他进程锁死 - 别用
StreamReader或TextReader——它们会按编码解码,破坏原始扇区数据 - 读扇区推荐按 512 字节或 4096 字节对齐(
stream.Position = sectorNum * 512),否则容易错位
E01 镜像必须用专用库:原生 C# 不支持 EWF 格式
EnCase E01 是压缩+校验+分卷的专有格式,C# 运行时完全不认识它。试图用 FileStream 直接读会得到乱码或校验失败,因为头部是 EWF 自定义结构,后面还可能是 zlib/LZ77 压缩块。
目前唯一稳定可用的方案是绑定 libewf 的 C# 封装:LibEwfSharp(NuGet 可搜到)。它通过 P/Invoke 调用原生 libewf,能正确解压、验证、跳转扇区。
- 安装后初始化要用
EwfImage.Open(),不是File.OpenRead() - 分卷 E01(
image.E01,image.E02…)必须把所有文件放在同一目录,Open()会自动识别并拼接 - 若遇到
LibEwfException: Unsupported segment file format,大概率是 E01 版本太新(v2/v3),确认LibEwfSharp是否基于较新版 libewf 编译
读取扇区后怎么定位文件?别硬写 NTFS 解析器
拿到某个扇区的原始字节(比如从偏移 0x100000 开始读 512 字节),不等于你就“看到文件”。NTFS 的 $MFT、FAT32 的 FAT 表、目录项都藏在特定 LBA 位置,且受簇大小、对齐方式影响。
真要提取文件内容,强烈建议复用成熟解析库,而不是手撕结构体:
-
DiscUtils(NuGet)支持读取 DD/E01(需配合LibEwfSharp提供的流)中的 NTFS/FAT/ext2,能直接获取DirectoryInfo和FileInfo对象 - 用
DiscUtils.Ntfs.NtfsFileSystem构造时传入的是Stream(来自FileStream或EwfImage.GetStream()),不是路径字符串 - 注意
DiscUtils默认不处理未分配簇或 $LogFile,如需恢复已删除文件,得额外调用NtfsFileSystem.GetDeletedFiles()
性能与内存陷阱:大镜像别一次性加载
一个 500GB 的 DD 镜像,用 File.ReadAllBytes() 会直接 OOM;E01 即使压缩率高,解压流也得边读边解,不能缓存全量。
所有操作必须基于流式处理(Stream),尤其涉及搜索、哈希、特征扫描时:
- 计算镜像 MD5?用
HashAlgorithm.ComputeHash(stream),别先ToArray() - 扫描 ASCII 字符串(如关键词)?用
Span<byte></byte>+ 滑动窗口,每次只读几 MB 到内存 - DiscUtils 的
NtfsFileSystem内部会缓存部分元数据,但不会加载整个 $MFT 到 RAM——前提是构造时传的是可 seek 的Stream(EwfImage.GetStream()满足)
最易被忽略的一点:E01 的时间戳和硬件信息存在段头里,不在文件系统内。如果做时间线分析,得先用 EwfImage.GetSegment(0).GetHeader() 提取 acquiry_date,而不是只看 $STANDARD_INFORMATION。










