Как получить согласованный SHA1 жесткого диска или тома с включенным EWF (встроенная Win 7)

Проблема: я не могу получить воспроизводимые хэши файлов, томов или даже физических дисков (например, SHA1) даже с включенным EWF в Win 7 Embedded и использованием методов CreateFile/ReadFile API Win32. Мне кажется, что ReadFile читает из оверлея ОЗУ EWF, но он мне нужен, чтобы получить байты с диска.

Предыстория: Мы обновляем регулируемый аппаратный и программный продукт с Windows XP Embedded (FAT32) до Windows 7 Embedded (NTFS). Код приложения написан на C#.Net и VC++.

Регулирующее требование должно быть в состоянии проверить, что все файлы, включая файлы ОС, присутствующие на жестком диске, являются точными копиями справочных файлов, которые были переданы регулятору. Регулятор должен быть в состоянии выполнить эту проверку, пока аппаратное устройство работает (в производстве), не останавливая приложения, запущенные на устройстве.

Во времена XP Embedded мы могли получать согласованные хэши файлов при включенном EWF и при работающем устройстве, анализируя файловую систему FAT32 и читая дисковые кластеры через ReadFile (Win 32 API, kernel32.dll). Хеши не были согласованы, если мы читаем файл как, скажем, FileStream.

Наша ОС и приложения развернуты в виде неизменяемого образа главного диска. Мы клонируем жесткие диски от мастера, используя байты для аппаратного клонирования байтовых дисков. Мы также сделали клонирование через OSFClone (dd) в Linux.

Мы пытаемся воспроизвести это (то есть проверяемые хэши файлов) в Windows 7 Embedded (x64), для которой требуется раздел NTFS для ОС.

Тестовая среда:

  • ОС Windows Embedded Standard 7 EWF включен в режиме ОЗУ на наших томах (C:, D:)
  • NTFSLastAccessUpdate было установлено на "1" в реестре в папке SYSTEM\Control\
  • Все файлы Bootstat.dat были удалены с диска до включения EWF, а изменения были внесены через ewfmgr.

Ранее, чтобы проверить, является ли диск неизменным, я сделал следующее:

  • Загрузите устройство с приводом Win 7e и ​​выключите его после внесения изменений (EWF включен)
  • Подключите жесткий диск Win7e к системе Kali Linux и используйте dd | sha1sum, чтобы получить хэш всего диска
  • Подключите диск Win7e к устройству и загрузитесь, внесите изменения (EWF включен) и повторите команду dd | Шаг sha1sum снова в Kali Linux (например, dd if=/dev/sda1 | sha1sum), где / dev / sda1 - это защищенный EWF раздел Windows.

В этом тесте подписи совпали между разными ботинками. Я снова запускаю тест выше, но это занимает некоторое время. [Редактировать: я снова запустил тест: EWF работает, и Linux возвращает точно такие же хэши для / dev / sda1 между перезагрузками диска Win7e]. NTFSLib и тестовый код, вставленный ниже, НЕ воспроизводят одинаковые подписи защищенного диска EWF.

Проблема: мы пытались использовать методы CreateFile/ReadFile, а также "NtfsLib" ( https://github.com/LordMike/NtfsLib) для чтения отдельных файлов, тома и \.\PhysicalDriveN, но мы не получаем воспроизводимые хеши между перезагрузка устройства. То есть каждый раз мы получаем разные хэши SHA1 для файла Windows (C:\windows\windowsupdate.log); мы получаем разные хэши для \.\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();
        }
    }
}

1 ответ

Обновление для тех, кто заинтересован, вы можете перейти ниже EWF через CreateFile/ReadFile из Win32 API. Вы должны использовать дескриптор \.\PhysicalDriveN и затем читать определенные байты, которые соответствуют интересующему вас объему. Вы можете сделать это с помощью функции SetFilePointer, также предоставляемой Win32 API. Конечно, если вы хотите хэшировать весь диск, вам не нужно читать определенные байты, которые соответствуют тому. Документы MSDN по этому вопросу не очень ясны, и документы не рассматривают конкретный вариант использования EWF.

Другие вопросы по тегам