简体   繁体   English

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

[英]How to get consistent SHA1 of Hard Drive or Volume that has EWF enabled (Win 7 embedded)

Problem: I am unable to get reproducible file, volume or even physical drive hashes (eg SHA1) even with EWF enabled on Win 7 Embedded and using Win32 API's CreateFile/ReadFile methods. 问题:即使在Win 7 Embedded上启用了EWF并使用Win32 API的CreateFile / ReadFile方法,我也无法获得可重现的文件,卷甚至物理驱动器哈希(例如SHA1)。 It appears (to me) that ReadFile is reading from the EWF's RAM overlay but I need it to get me the bytes from the disk. 在我看来,ReadFile正在从EWF的RAM覆盖层读取数据,但是我需要它来从磁盘获取字节。

Background: We are updating a regulated hardware+software product from Windows XP Embedded (FAT32) to Windows 7 Embedded (NTFS). 背景信息:我们正在将受管制的硬件和软件产品从Windows XP Embedded(FAT32)更新为Windows 7 Embedded(NTFS)。 The application code is written in C#.Net and VC++. 应用程序代码是用C#.Net和VC ++编写的。

A regulatory requirement is to be able to verify that all files, including OS files, present on the hard disk are exact copies of the reference files that were given to the regulator. 监管要求是能够验证硬盘上存在的所有文件,包括OS文件,都是提供给监管机构的参考文件的精确副本。 The regulator needs to be able to perform this verification while the hardware device is functional (in production) without stopping the applications running on the device. 调节器需要能够在硬件设备正常运行(生产中)时执行此验证,而无需停止设备上运行的应用程序。

In the XP Embedded days, we were able to get consistent file hashes when EWF was enabled, and with the device operational, by parsing the FAT32 file system and reading disk clusters via ReadFile (Win 32 API, kernel32.dll). 在XP Embedded时代,通过解析FAT32文件系统并通过ReadFile(Win 32 API,kernel32.dll)读取磁盘群集,可以在启用EWF并使设备运行时获得一致的文件哈希。 The hashes were not consistent if we read the file as, say, a FileStream. 如果我们将文件读取为FileStream,则哈希值不一致。

Our OS and applications are deployed as an immutable master disk image. 我们的操作系统和应用程序被部署为不可变的主磁盘映像。 We clone the hard drives from a master using a byte for byte drive clone hardware. 我们使用字节作为字节驱动器克隆硬件从主机克隆硬盘驱动器。 We have also done the cloning via OSFClone (dd) on Linux. 我们还通过Linux上的OSFClone(dd)进行了克隆。

We are trying to reproduce this (ie verifiable file hashes) in Windows 7 Embedded (x64) which requires an NTFS partition for the OS. 我们正在尝试在Windows 7 Embedded(x64)中重现此文件(即可验证的文件散列),该文件需要OS的NTFS分区。

Test Environment: 测试环境:

  • OS is Windows Embedded Standard 7 EWF is enabled in RAM mode on our volumes (C:, D:) 操作系统为Windows Embedded Standard 7 EWF在我们的卷(C :, D :)上以RAM模式启用
  • NTFSLastAccessUpdate has been set to "1" in the registry under SYSTEM\\Control\\ NTFSLastAccessUpdate已在SYSTEM \\ Control \\下的注册表中设置为“ 1”
  • All Bootstat.dat files were deleted from the drive prior to enabling EWF and the changes committed via ewfmgr 在启用EWF和通过ewfmgr提交的更改之前,已从驱动器中删除了所有Bootstat.dat文件。

Previously, to test whether the drive is immutable, I've done the following: 以前,为了测试驱动器是否不可变,我已经完成了以下操作:

  • Boot a device with the Win 7e drive and shutdown after making changes (EWF enabled) 引导带有Win 7e驱动器的设备并进行更改后关闭(启用EWF)
  • Plug the Win7e hard drive in a Kali Linux system and use dd | 将Win7e硬盘驱动器插入Kali Linux系统并使用dd | sha1sum to get the hash of the entire drive sha1sum获取整个驱动器的哈希
  • Plug back the Win7e drive in the device and boot, make changes (EWF enabled) and repeat the dd | 将Win7e驱动器插回设备并启动,进行更改(启用EWF),然后重复dd | dd。 sha1sum step on Kali Linux again (eg dd if=/dev/sda1 | sha1sum) where /dev/sda1 is an EWF protected Windows partition. sha1sum再次在Kali Linux上运行(例如dd if = / dev / sda1 | sha1sum),其中/ dev / sda1是受EWF保护的Windows分区。

The signatures matched in that test between different boots. 在该测试中,不同启动之间的签名匹配。 I'm running the test above again but it takes a while. 我再次在上面进行测试,但需要一段时间。 [Edit: I have run the test again now: the EWF is working and Linux returns exact same hashes for /dev/sda1 between reboots of the Win7e drive]. [编辑:我现在再次运行测试:EWF正在工作,并且Linux在Win7e驱动器的重新引导之间为/ dev / sda1返回完全相同的哈希值]。 NTFSLib and the test code pasted below do NOT reproduce same signatures of the EWF protected drive. NTFSLib和下面粘贴的测试代码不会复制受EWF保护的驱动器的相同签名。

Problem: We've tried using CreateFile / ReadFile methods as well as an "NtfsLib" ( https://github.com/LordMike/NtfsLib ) to read individual files, volume and \\.\\PhysicalDriveN but we are not getting reproducible hashes between reboots of the device. 问题:我们尝试使用CreateFile / ReadFile方法以及“ NtfsLib”( https://github.com/LordMike/NtfsLib )来读取单个文件,卷和\\。\\ PhysicalDriveN,但我们之间没有得到可复制的哈希重新启动设备。 That is, we get a different SHA1 hashes for a Windows file (C:\\windows\\windowsupdate.log) every time; 也就是说,我们每次都为Windows文件(C:\\ windows \\ windowsupdate.log)获得不同的SHA1哈希值; we get different hashes for \\.\\C: everytime, and we get different hashes for \\.\\PhysicalDrive0 every time. 我们每次都为\\。\\ C获得不同的哈希,并且每次都为\\。\\ PhysicalDrive0获得不同的哈希。

I'm pasting the C# code below that I'm using to calculate signatures. 我在下面粘贴了用于计算签名的C#代码。 I don't mind re-writing the thing in another language, say C or C++, as long as I can get raw bytes from the hard disk. 只要我可以从硬盘上获取原始字节,我都不介意用另一种语言(例如C或C ++)来重写它。 Please tell me if I'm doing something wrong in reading raw bytes. 请告诉我在读取原始字节时是否做错了什么。 I do not need to read and hash individual files per se. 我本身不需要读取和散列单个文件。 I can read the entire disk or an entire volume and hash it as long as that hash matches between reboots of the device. 我可以读取整个磁盘或整个卷并对其进行哈希处理,只要该哈希值在设备重新引导之间匹配时即可。 Hashing the entire drive or the volume would satisfy the regulatory requirement. 散列整个驱动器或卷将满足法规要求。 To me, it seems that the bytes I get from ReadFile show EWF's view of the filesystem. 在我看来,我从ReadFile中获得的字节似乎显示了EWF对文件系统的看法。

I would appreciate any hints anyone can give me. 任何人都可以给我的提示,我将不胜感激。 I've been reading various posts about ReadFile but did not find any clues to this behavior with EWF. 我一直在阅读有关ReadFile的各种文章,但没有发现有关EWF这种行为的任何线索。

I am running the code below as an Admin on Windows and my app.manifest has the requireAdmin thing set. 我在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();
        }
    }
}

Update for anyone who is interested, you can actually go below EWF via CreateFile/ReadFile from Win32 API. 如果有兴趣的人进行更新,则实际上可以通过Win32 API中的CreateFile / ReadFile进入EWF以下。 You must use the \\.\\PhysicalDriveN handle and then read specific bytes that correspond to the volume you are interested in. You can do that by using the SetFilePointer function also provided by the Win32 API. 您必须使用\\。\\ PhysicalDriveN句柄,然后读取与您感兴趣的卷相对应的特定字节。您可以通过使用Win32 API也提供的SetFilePointer函数来做到这一点。 Of course, if you wanted to hash the entire drive, you won't need to read specific bytes that correspond to the volume. 当然,如果要散列整个驱动器,则无需读取与该卷相对应的特定字节。 MSDN docs on this subject are not very clear and the docs do not consider the specific EWF use case. 关于此主题的MSDN文档不是很清楚,文档未考虑特定的EWF用例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM