如何获得启用了 EWF 的硬盘驱动器或卷的一致 SHA1(嵌入 Win 7)

本文关键字:SHA1 嵌入 Win 启用 何获得 EWF 硬盘驱动器 | 更新日期: 2023-09-27 17:56:55

问题:即使在 Win 7 Embedded 上启用了 EWF 并使用 Win32 API 的 CreateFile/ReadFile 方法,我也无法获得可重现的文件、卷甚至物理驱动器哈希(例如 SHA1)。看起来(对我来说)ReadFile 正在从 EWF 的 RAM 覆盖层读取,但我需要它来从磁盘获取字节。

背景:我们正在将受监管的硬件+软件产品从Windows XP Embedded(FAT32)更新为Windows 7 Embedded(NTFS)。应用程序代码是用 C#.Net 和 VC++ 编写的。

法规要求是能够验证硬盘上存在的所有文件(包括操作系统文件)是否是提供给监管机构的参考文件的精确副本。监管机构需要能够在硬件设备正常运行(在生产中)时执行此验证,而无需停止设备上运行的应用程序。

XP Embedded的日子里,我们能够在启用EWF时获得一致的文件哈希,并且设备运行,通过解析FAT32文件系统并通过ReadFile(Win 32 API,kernel32.dll读取磁盘簇)。如果我们将文件读取为FileStream,则哈希不一致。

我们的操作系统和应用程序部署为不可变的主磁盘映像。我们使用字节驱动器克隆硬件从主服务器克隆硬盘驱动器。我们还在Linux上通过OSFClone(dd)完成了克隆。

我们正试图在Windows 7 Embedded(x64)中重现这一点(即可验证的文件哈希),这需要操作系统的NTFS分区。

测试环境:

  • 操作系统是 Windows 嵌入式标准 7 EWF 在我们的 RAM 模式下启用卷 (C:, D:)
  • NTFSLastAccessUpdate 已在注册表在系统''控制''
  • 在启用 EWF 之前,所有 Bootstat.dat 文件都已从驱动器中删除,并通过 ewfmgr 提交的更改

以前,为了测试驱动器是否不可变,我做了以下操作:

  • 使用 Win 7e 驱动器启动设备并在进行更改后关闭(启用 EWF)
  • 将Win7e硬盘驱动器插入Kali Linux系统并使用dd | sha1sum获取整个驱动器的哈希
  • 将 Win7e 驱动器重新插入设备并启动,进行更改(启用 EWF),然后再次在 Kali Linux 上重复 dd | sha1sum 步骤(例如dd if=/dev/sda1 |sha1sum),其中/dev/sda1 受 EWF 保护窗口分区。

该测试中不同引导之间的签名匹配。我再次运行上面的测试,但这需要一段时间。[编辑:我现在再次运行测试:EWF 正在工作,Linux 在重新启动 Win7e 驱动器之间为/dev/sda1 返回完全相同的哈希]。NTFSLib 和下面粘贴的测试代码不会重现受 EWF 保护的驱动器的相同签名。

问题:我们已经尝试使用CreateFile/ReadFile方法以及"NtfsLib"(https://github.com/LordMike/NtfsLib)来读取单个文件,卷和''.''PhysicalDriveN,但是在设备重新启动之间我们没有得到可重现的哈希。也就是说,我们每次都会为 Windows 文件(C:''windows''windowsupdate.log)获得不同的 SHA1 哈希;我们每次都会得到不同的 ''.''C: 哈希值,每次都会得到 ''.''PhysicalDrive0 的不同哈希值。

我正在下面粘贴用于计算签名的 C# 代码。我不介意用另一种语言重写东西,比如 C 或 C++,只要我能从硬盘中获取原始字节。请告诉我我在读取原始字节时是否做错了什么。我本身不需要读取和散列单个文件。我可以读取整个磁盘或整个卷并对其进行哈希处理,只要该哈希在设备重新启动之间匹配即可。对整个驱动器或卷进行哈希处理将满足法规要求。对我来说,我从 ReadFile 获得的字节似乎显示了 EWF 对文件系统的看法。

我将不胜感激任何人能给我的任何提示。我一直在阅读有关 ReadFile 的各种帖子,但没有找到有关 EWF 这种行为的任何线索。

我在Windows上以管理员身份运行下面的代码,我的app.manifest设置了requireAdmin。

using System;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using Microsoft.Win32.SafeHandles;

namespace CSharpReadDisk
{
    class DiskReader
    {
        public const uint GenericRead = 0x80000000;
        public const uint FileShareRead = 1;
        public const uint FileShareWrite = 2;
        public const uint OpenExisting = 3;
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        static extern unsafe IntPtr CreateFile(string lpFileName, uint dwDesiredAccess,
          uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
          uint dwFlagsAndAttributes, IntPtr hTemplateFile);
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern unsafe bool ReadFile(IntPtr hFile, void* lpBuffer,
           uint nNumberOfBytesToRead, uint* lpNumberOfBytesRead, IntPtr lpOverlapped);
        [DllImport("kernel32", SetLastError = true)]
        static extern unsafe bool CloseHandle(IntPtr hObject);

        public unsafe IntPtr Open(string filename)
        {
            // open the existing file for reading       
            IntPtr handle = CreateFile(filename, GenericRead, FileShareRead | FileShareWrite, IntPtr.Zero, OpenExisting, 0, IntPtr.Zero);
            return handle;
        }
        public unsafe uint Read(IntPtr handle, byte[] buffer, uint count)
        {
            uint n = 0;
            fixed (byte* p = buffer)
            {
                if (!(ReadFile(handle, p, count, &n, IntPtr.Zero)))
                {
                    return 0;
                }
            }
            return n;
        }
        public unsafe bool Close(IntPtr handle)
        {
            return CloseHandle(handle);
        }
    }
    class Test
    { 
        static void Main(string[] args)
        {
            DiskReader dr = new DiskReader();
            Console.Write("Enter path to drive, volume or file: ");
            string path = Console.ReadLine();
            IntPtr fh = dr.Open(path);
            try
            { 
                SafeFileHandle sfh = new SafeFileHandle(fh, true);
                if (sfh.IsInvalid)
                {
                    Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
                }
                Console.WriteLine("Enter read buffer size (MB): ");
                int bs = Console.Read();
                byte[] lpBuffer = new byte[bs * 1024 * 1024];
                uint bytesRead = 0;
                SHA1Managed sha1 = new SHA1Managed();
                while ((bytesRead = dr.Read(fh, lpBuffer, (uint)lpBuffer.Length)) > 0)
                {
                    sha1.TransformBlock(lpBuffer, 0, (int)bytesRead, null, 0);
                    Console.Write(".");
                }
                sha1.TransformFinalBlock(lpBuffer, 0, (int)bytesRead);
                Console.WriteLine("'nSHA1: {0}", BitConverter.ToString(sha1.Hash));
            }
            catch (Exception e)
            {
                Console.WriteLine("An exception occurred:'n HResult: {0}'n Message: {1}'n InnerException: {2}'n Source: {3}'n TargetSite: {4}'n StackTrace: {5}", 
                    e.HResult, e.Message, e.InnerException, e.Source, e.TargetSite, e.StackTrace);
            }
            dr.Close(fh); // close filehandle

            Console.WriteLine("'nPress any key to exit...");
            Console.ReadKey();
        }
    }
}

如何获得启用了 EWF 的硬盘驱动器或卷的一致 SHA1(嵌入 Win 7)

更新 对于任何感兴趣的人,您实际上可以通过Win32 API中的CreateFile/ReadFile进入EWF下方。必须使用 ''.''PhysicalDriveN 句柄,然后读取与感兴趣的卷对应的特定字节。您可以使用 Win32 API 提供的 SetFilePointer 函数来执行此操作。当然,如果要对整个驱动器进行哈希处理,则无需读取与卷相对应的特定字节。有关此主题的 MSDN 文档不是很清楚,文档不考虑特定的 EWF 用例。

相关文章: