Pull to refresh

Перенос ОС Windows на другой компьютер средствами ОС Linux

Reading time 9 min
Views 48K
После прочтения статьи «Фривольное клонирование ОС MS Windows XP / Server 2003 своими руками, средствами GNU/Linux» возникло естественное желание дополнить ее в соответствии с реалиями конца 2014 года.

В общем, проблема разворачивания той или иной версии Windows состоит из двух частей — во-первых, нужно скопировать данные разделов с эталонного ПК на новый, и, во-вторых, надо обеспечить загрузку Windows на изменившемся оборудовании.

MBR, таблица разделов и сигнатура диска


Начнем с копирования данных. Какие же данные нам нужно скопировать? Для Windows XP это MBR (446 байт в начале диска, основная таблица разделов и завершающая сигнатура 55AAh), данные о расширенных разделах и собственно данные системного раздела Windows. Для Vista и Windows 7 добавляется еще и 100-мегабайтный системный раздел (GPT не рассматриваем). При этом нужно помнить, что первый раздел в Windows XP по-умолчанию начинается с сектора 63, а в Windows Vista/7 — с сектора 2048. Естественно, все операции мы будем проводить на незапущенной Windows, загрузившись с System Resque CD.

Так вот, не стоит копировать MBR «в лоб», для этого в Linux существует утилита ms-sys, которая записывает загрузчик любой версии Windows от Win95 до Win7 в MBR. Для сохранения и восстановления структуры разделов есть утилита sfdisk.

Например, так:
sfdisk -d /dev/sda > ./parttable.txt (сохраняем структуру разделов)
sfdisk -f /dev/sda < ./parttable.txt (восстанавливаем на другом ПК)
ms-sys -mbr /dev/sda (записываем MBR от Windows XP)


Добавлено:
Для того, чтобы WIndows загрузилась, необходимо также сформировать подпись диска (disk signature). Для этого нужно прочитать содержимое ключа реестра HKLM\SYSTEM\MountedDevices\<\DosDevices\«Имя раздела на диске с двоеточием»>, и выделить первые 8 байт (в шестнадцатеричной записи), например: 4F BE 4F BE. Сделать это на смонтированном в Linux NTFS-томе можно с помощью описанной ниже утилиты reged. Следует учесть, что в reged имя ключа, содержащее слеш, нужно указывать через двойной слеш, например: \\DosDevices\\C:. Затем указанные 8 байт следует записать на диск начиная со смещения 0x01B8 утилитой hexedit. После этого диск готов к загрузке.

Данные разделов NTFS


После копирования MBR и структуры разделов можно копировать собственно данные разделов с помощью partclone. Инструмент partclone позволяет создавать образы разделов ext2/3/4, fat, ntfs, xfs, btrfs, reiserfs и т. д., анализируя внутреннюю структуры ФС и включая в образ только используемые сектора. Создадим на эталонном ПК образ раздела с помощью partclone, размер образа будет равен размеру используемого на томе места.
partclone.ntfs -c -s /dev/sda1 -o <файл образа>

а на целевом компьютере развернем его
partclone.ntfs -r -s <файл образа> -o /dev/sda1

или
partclone.restore -s <файл образа> -o /dev/sda1
К сожалению, внутреннее сжатие в образе не поддерживается.

Возможно также прямое копирование данных с одного устройства на другое с помощью ключа -b:
partclone.ntfs -b -s /dev/sda1 -o /dev/sdb1

Теперь рассмотрим вопрос восстановления данных на раздел размера, меньшего, чем эталонный. Для этого нужно смонтировать partclone-образ и либо скопировать с него файлы на целевой том с сохранением атрибутов, разрешений, hardlink-ов и прочих свойств NTFS, либо уменьшить размер раздела NTFS внутри образа partclone, а уже затем скопировать этот уменьшенный раздел на целевой том командой partclone.ntfs с ключом -b.

Мне не известны инструменты, которыми можно было бы в Linux скопировать файлы и hardlink-и с одного тома NTFS на другой со всеми атрибутами и потоками (если кому-нибудь они известны, прошу в комментарии), так что у нас остается только вариант с уменьшением размера тома. К счастью, существует инструмент imagemount, который экспортирует partclone-образ как блочное устройство nbd и поддерживает монтирование образа в том числе и на запись, при этом изменения сохраняются в отдельном файле (ключ -с). Экспортируем том на запись
modprobe nbd max_part=16
imagemount -w -D -d /dev/nbd0 -f /mnt/images/winxp.img -c ./cow.bin

Теперь изменим размер ФС на томе NTFS. Сначала будет сделан тестовый прогон (ключ -n)
ntfsresize -s <новый размер> -n /dev/nbd0

а затем — реальный:
ntfsresize -s <новый размер> /dev/nbd0

Клонируем раздел:
partclone.ntfs -b -s /dev/nbd0 -o /dev/sda1

А теперь — щепотка пичальки
Imagemount, даже последней версии — 0.3.1, не работает с дисками на запись на архитектуре x86_64 (зависает намертво) и практически не работает на архитектуре i386 (записывает образ с ошибками), поэтому изменение размера раздела на данный момент невозможно. Буду писать в багртекер partclone-utils.

К сожалению, partclone не поддерживает сжатие образов, но эту проблему можно обойти с помощью так любимых в Linux костылей и подпорок. Создадим пустой образ формата qcow2 с виртуальным размером, заведомо превышающим наши потребности (например, 1 Tb). Его реальный объем будет увеличиваться в зависимости от количества данных, которые мы туда запишем.
qemu-img create -f qcow2 <файл образа> 1024G

Смонтируем его как блочное устройство
modprobe nbd max_part=16
qemu-nbd -c /dev/nbd0 <файл образа>

Теперь скопируем на виртуальное устройство файловую систему
partclone.ntfs -b -s /dev/sda1 -o /dev/nbd0

размонтируем устройство и в результате получим файл qcow2 с размером чуть больше, чем размер исходного NTFS-тома. Теперь к файлу можно применить внутреннее сжатие:
qemu-img convert -c <файл образа> <сжатый файл образа>

Легко заметить, что этот способ требует удвоенного места на диске для хранения исходного и сжатого образов, а также дополнительное время на сжатие. Если мы применим еще один костыль, то избавимся и от этих недостатков. После монтирования образа qcow2 (командой qcow-nbd -c /dev/nbd0 <файл образа>) отформатируем его в файловую систему btrfs
mkfs.btrfs /dev/nbd0

а теперь смонтируем со сжатием:
mount -o compress-force=zlib /dev/nbd0 /mnt

и создадим образ файловой системы NTFS
partclone.ntfs -c -s /dev/sda1 -o /mnt/ntfs-image.bin

После этого размонтируем все.

В результате мы получим файл образ со сжатием, в который включены только используемые сектора и который можно смонтировать через imagemount как файловую систему и прочитать его содержимое.

Мне, например, удалось уменьшить размер образа со свежеустановленной Windows XP c 2,7 Gb до 587 Mb. При этом можно смонтировать образ без распаковки и просмотреть файлы внутри.

Гораздо лучше, чем набившие оскомину dd | gzip, не так ли?

Запуск Windows на новом оборудовании


Теперь перед нами стоит вторая задача — сделать так, чтобы установленная на том NTFS Windows смогла запуститься. В случае Windows 7 копируем еще и загрузочный раздел, для Windows Vista — дополнительно делаем (с Windows Vista Live CD) перезапись BCD, чтобы данные в этой области соответствовали серийному номеру жесткого диска, проверяем, чтобы у загрузочного раздела стояла соответствующий флаг boot (можно сделать через parted) и перезагружаемся. После чего с некоторой вероятностью получаем синий экран с надписью 0x0000007B Inaccesseble boot device. В этом случае для Windows XP рекомендуется выставить правильный HAL, но вот незадача, я уже давно не встречал одноядерные ПК без APIC и тем более ACPI, так что наш эталонный образ скорее всего уже содержит правильный многопроцессорный HAL. Поэтому не стоит надеяться, что замена HAL сразу исправит нашу проблему. Скорее всего, причина в том, что Windows не распознала контроллер жесткого диска, и, соответственно, не смогла продолжить с него загрузку.

Допустим, мы не пользовались sysprep при создании эталона (а то получиться неспортивно, потому что sysprep сделает всю работу за нас). Попробуем разобраться, почему ОС Windows не находит контроллер диска на новом оборудовании, несмотря на то, что в случае «чистой» установки она этот контроллер видит. Дело в том, что на завершающем этапе установки Windows отключает (якобы для ускорения загрузки) все драйверы контроллеров дисков, на которых не расположено системных разделов. Получается как с сусликом в фильме «ДМБ»: система его не видит, но он есть.

Включаем IDE-контроллеры: патч MergeIDE

Для Windows XP существует известный патч MergeIDE, который, собственно, и включает в реестре драйверы IDE-устройств обратно, попутно копируя файлы драйверов из driver.cab в \system32\drivers. Проблема в том, что этот патч предназначен для запуска из-под Windows. Попробуем наложить его под Linux вручную. Пусть раздел с Windows XP смонтирован у нас в /mnt, тогда:
cabextract -d /tmp/drivers "/mnt/WINDOWS/system32/Driver Cache/i386/driver.cab"
cd /tmp/drivers
cp atapi.sys intelide.sys pciide.sys pciidex.sys /mnt/WINDOWS/system32/drivers

Для того, чтобы наложить патч MergeIDE.reg на реестр, нужно его отредактировать, убрав переводы строк с помощью символа «\» в последних строках файла, а затем воспользоваться утилитой reged с ключом -I
reged -I /mnt/WINDOWS/system32/config/system HKEY_LOCAL_MACHINE\\SYSTEM ./MergeIDE.reg

Быть может, придется так же исправить ключ CurrentControlSet, который бывает не доступен на незапущенной Windows, на ControlSet001/002.

После этого можно перезагружаться. Надо сказать, в моей практике было несколько случаев, когда запустить образ на другом оборудовании не удавалось ни указанным выше способом, ни с помощью платных инструментов вроде Acronis Universal Restore.

Посмотрев содержимое файла MergeIDE.reg можно увидеть, что вся магия запуска загрузочного драйвера состоит в добавлении записей в две ветви реестра — HKLM\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase и HKLM\SYSTEM\CurrentControlSet\Services.
Ветвь CriticalDeviceDatabase содержит список устройств, необходимых для успешной загрузки системы и задает соответствие между классом устройства и той службой (драйвером), который за нее отвечает, а ветвь Services содержит параметры работы конкретных драйверов. Особенно интересен параметр Start — уровень запуска:
0 — загрузка до старта ядра загрузчиком ОС
1 — загрузка в момент инициализации ядра
2 — загрузка в процессе запуска ОС
3 — загрузка по требованию
4 — не загружать
очевидно, если у нашего драйвера уровень запуска будет отличаться от 0, то соответствующего контроллера в момент загрузки мы не увидим.

MergeIDE.reg оперирует идентификатором класса 4d36e96a-e325-11ce-bfc1-08002be10318 — дисковые контроллеры ATA/ATAPI. Идентификаторы ClassGUID для различных классов устройств известны, их можно найти, например, здесь.
Таким образом можно заставить систему запускать в момент загрузки ядра в память любой драйвер, например, для сетевой карты, если вы загружаетесь через AoE или iSCSI.

Для Windows Vista/7 можно просто пройтись по ветви Services в поисках драйверов, содержащих в названии слово IDE, а потом изменить тип запуска (ключ Start) с «3-отложенный запуск» на «0-загружать в момент загрузки ядра». Для этих ОС есть еще один способ — находим в ветви Services записи msachi и iaStorV (универсальный драйвер AHCI и драйвер AHCI для устройств Intel) и так же изменяем тип запуска с «3» на «0», а потом идем в BIOS и меняем там тип контроллера дисков на AHCI. С Windows XP такой фокус, к сожалению, не прокатит, по причине отсутствия встроенного универсального драйвера AHCI.

Загружаемся с любого IDE или SATA-контроллера: драйвер UniATA

Поэтому обратим внимание на совершенно волшебный драйвер контроллера дисков UniATA от Александра Телятникова aka Alter. Этот драйвер инициализирует любой контроллер, считающий себя IDE- или AHCI-совместимым, а поэтому отлично подходит для наших целей. Порядок установки точно такой же — скопировать файл драйвера, прописаться в CriticalDeviceDatabase и в Services.

wget http://alter.org.ua/ru/soft/win/uni_ata/BusMaster_v45d.tgz
tar -xzvf ./BusMaster_v45d.tgz
cp uniata.sys /mnt/WINDOWS/system32/drivers
cp atactl.exe /mnt/WINDOWS/system32

Теперь интегрируем в образ файл my_uniata_inst.reg следующего содержания

UniATA_Inst.reg
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_8086&dev_2922]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="uniata"

[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\UniATA]
"Type"=dword:00000001
"Start"=dword:00000000
"ErrorControl"=dword:00000000
"Group"="System Bus Extender"
"ImagePath"=hex(2):53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,44,00,52,00,49,00,56,00,45,00,52,00,53,00,5c,00,75,00,6e,00,69,00,61,00,74,00,61,00,2e,00,73,00,79,00,73,00,00,00

[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\UniATA\Parameters\PnpInterface]
"1"=dword:0x00000000
"5"=dword:0x00000000
"SkipRaids"=dword:0x00000001

Здесь ven_8086&dev_2922 — идентификатор установленного SATA-контроллера. Мы также считаем, что CurrentControlSet у нас нет и используем активную ветвь — ControlSet001, номер которой указан в HKLM\SYSTEM\Select\Current.
reged -I /mnt/WINDOWS/system32/config/system HKEY_LOCAL_MACHINE\\SYSTEM ./my_uniata.reg

Если такой способ не срабатывает — можно попробовать более «грязные» методы установки — с помощью файла uniata_w2k.reg из архива с драйверами или по инструкции на сайте разработчика.

Еще пичалька
Как оказалось, UniATA не может инициализировать виртуальный контроллер Intel 8086:2922, который эмулируется QEMU. «Соседний» виртуальный IDE-контроллер инициализируется замечательно. Чей это баг — QEMU или UniATA, не совсем понятно.

Об инструментах


Основной набор утилит можно найти в System Rescue CD. Сюда входят ms-sys, mkfs.btrfs, sfdisk, partclone и reged. Imagemount можно взять из пакета partclone-utils, просто распаковав его в корневую ФС systemresquecd. С пакетом qemu-utils дела обстоят сложнее. Я создавал в отдельном каталоге минимальную установку Debian с помощью debootstrap, затем делал туда chroot и уже потом ставил qemu-utils через apt-get. Перед запуском qemu-nbd нужно не забыть примонтировать /proc, /sys и /dev внутрь chroot'а.

Заключение


Скрытый текст
Купите лучше Acronis Universal Restore
Tags:
Hubs:
+28
Comments 40
Comments Comments 40

Articles