Как создать MBR-загрузчик с помощью программы EasyBCD
Как создать MBR-загрузчик Windows с нуля? Не восстановить его, не пересоздать, а именно создать с нуля – выделить дисковое пространство под загрузочный раздел, сформировать таковой со всеми необходимыми атрибутами, внедрить файлы загрузчика, сделать запись о загрузке Windows. Необходимость в этом возникает, как правило, когда Windows установлена на одном жёстком диске, а её загрузочный раздел находится на другом диске. И этот другой диск с загрузчиком необходимо либо извлечь, либо переразметить. В этой статье будем воссоединять Windows и её загрузчик – разместим их обоих на одном жёстком диске, с которого и будет загружаться компьютер. А поможет нам в этом деле программа EasyBCD.
Но программа EasyBCD – не единственный инструмент, который будет участвовать в нашей операции. Нам также потребуются возможности системного управления дисками. Его можно запустить в меню Win+X (в Win8.1 и Win10) или через поиск в меню «Пуск», введя название утилиты – diskmgmt.msc.
Итак, имеем обозначенную выше ситуацию – Windows установлена на одном диске, значащемся как диск 0, а её загрузочный MBR-раздел «Зарезервировано системой» размещается на другом диске, диске 1.
Как их объединить на одном диске – диске 0? У задачи есть несколько путей решения. Один – это клонирование загрузочного раздела на диск 0 и внесение записи о загрузке Windows в клонированный загрузчик. Для этой операции потребуется программа, умеющая клонировать разделы. При этом если не работать с командной строкой, то всё равно потребуется участие программ типа EasyBCD для внесения записи о загрузке системы в новый загрузчик. Другой путь – создание раздела загрузчика с нуля с использованием системного управления дисками и возможностей той же программы EasyBCD. Этим путём мы и пойдём.
1. Создание активного раздела для загрузчика
В управлении дисками создадим загрузочный раздел за счёт небольшого пространства, отобранного у раздела Windows. Кликаем раздел С, выбираем в контекстном меню «Сжать том».
В графе указания размера сжимаемого пространства указываем 350 Мб. Кликаем «Сжать».
На образовавшемся пустом месте в контекстном меню выбираем «Создать простой том».
В приветственном окне мастера и на этапе указания размера создаваемого раздела просто жмём «Далее».
На этапе назначения буквы диска тоже просто жмём «Далее». Загрузочному разделу обычно не назначается буква, но при его создании вручную она нам будет нужна. Потом мы её уберём. В качестве метки тома можем указать стандартное название раздела MBR-загрузчика – «Зарезервировано системой».
Раздел на 350 Мб создан. Теперь нам нужно сделать его активным. В контекстном меню на нём выбираем «Сделать раздел активным».
Важно: на MBR-диске может быть только один активный раздел. Если на диске есть уже другой активный раздел, его нужно сделать неактивным. И только потом в управлении дисками станет доступной возможность сделать активным новосозданный раздел.
И вот итог: у нас после раздела С появился активный раздел «Зарезервировано системой».
Теперь нужно на этом разделе создать файлы загрузчика.
2. Создание MBR-загрузчика
Создавать файлы MBR-загрузчика Windows будем с помощью упомянутой программы EasyBCD. Она бесплатная, скачать её можно на официальном сайте: https://neosmart.net/EasyBCD/
Устанавливаем и запускаем программу. Идём в раздел «Установка BCD». В графе «Создание загрузочного внешнего носителя» из выпадающего списка выбираем наш созданный раздел на 350 Мб. В нашем случае это раздел с буквой D.
Затем жмём «Установить BCD». На запрос программы, хотим ли мы загрузить новый файл BCD можем нажать «Да».
Но может быть и так, что EasyBCD не сможет автоматически загрузить для редактирования новый файл BCD. И в её интерфейсе останется файл BCD текущего системного загрузчика. Лучше перестраховаться и вручную загрузить файл BCD нового загрузчика. В меню программы «Файл» выбираем «Выбрать BCD». Жмём «Ок» в окошке предупреждения, что мы загружаем внешний файл BCD.
В окне открывшегося проводника вручную прописываем в адресной строке путь к файлу BCD по типу:
D:\Boot
Где вместо буквы D вам нужно подставить свою букву нового загрузочного раздела. Жмём Enter в адресной строке, в открывшемся пути выбираем файл BCD и открываем его.
Как видим в разделе EasyBCD «Текущее меню», в нашем новом загрузчике нет ни единой записи о загрузке Windows.
Исправим это. Идём в раздел «Добавить запись». И добавляем нашу Windows: в графе «Имя» указываем имя системы, в графе «Диск» указываем раздел, где стоит система. И жмём кнопку-плюсик. По этому же принципу добавляем другие Windows, если их на диске имеется несколько.
Далее можем зайти в раздел «Редактировать меню загрузки» и выбрать для меню загрузчика русский язык. Это нужно, чтобы среда восстановления была на русском. Если в загрузчик добавлялись несколько Windows, в этом разделе можем настроить меню загрузки – установить таймаут автовыбора системы, установить порядок систем в списке и т.п. По итогу настроек жмём «Сохранить».
Вот, собственно, и всё.
3. Удаление буквы загрузочного раздела
Буква нового загрузочного раздела сыграла свою роль, будучи указателем при создании файлов MBR-загрузчика в программе EasyBCD. И теперь она не нужна. Идём снова в управление дисками, на новом загрузочном разделе в контекстном меню выбираем изменение буквы.
И удаляем букву.
На этом всё: можем перезагружаться, выставлять в BIOS загрузку с диска с новым загрузчиком и тестировать запуск Windows.
Сборка и запуск загрузчика
Перед началом статьи хочу сказать, что еще больше полезной и нужной информации вы найдете в нашем Telegram-канале. Подпишитесь, мне будет очень приятно.
Если вы так же любопытны, как я, вы наверняка задумывались о том, как работают операционные системы. Здесь я расскажу о некоторых исследованиях и экспериментах, которые я провёл, чтобы лучше понять, как работают вычислительные и операционные системы. После прочтения вы создадите свою загрузочную программу, которая будет работать в любом приложении виртуальных машин, например в Virtual Box.
Эта статья не предназначена для того, чтобы объяснить работу загрузчика во всей его сложности. Этот пример — отправная точка для x86 архитектуры. Для понимания этой статьи требуется базовое знание микропроцессоров и программирования.
Простыми словами загрузчик — это часть программы, загружаемая в рабочую память компьютера после загрузки.
После нажатия кнопки Пуск компьютеру предстоит многое сделать. Запускается и выполняет свою работу прошивка, называемая BIOS (базовая система ввода-вывода). После этого BIOS передаёт управление загрузчику, установленному на любом доступном носителе: USB, жёстком диске, CD и т.д. BIOS последовательно просматривает все носители, проверяя уникальную подпись, которую также называют записью загрузки. Когда она найдена и загружена в память компьютера, начинает работать процессор. Если быть более точным, эта запись располагается по адресу 0x7C00. Сохраните его, он нужен для написания загрузчика.
Как упоминалось выше, в процессе инициализации BIOS ищет в первом секторе загрузочного устройства уникальную подпись. Её значение равно 0xAA55 и должно находиться в последних двух байтах первого сектора. И хотя все 512 байт доступны в главной загрузочной записи, мы не можем использовать их все: мы должны вычесть схему и подпись таблицы раздела диска и подпись. Останется только 440 байт. Маловато. Но вы можете решить эту проблему, написав код для загрузки данных из других секторов в памяти.
- BIOS загружает компьютеры и их периферийные устройства.
- BIOS ищет загрузочные устройства.
- Когда BIOS находит подпись 0xAA55 в MBR, он загружает этот сектор в память в позицию 0x7C00 и передаёт управление этой точке входа, то есть начинает выполнение инструкций с точки в памяти 0x7C00.
Код загрузчика на ассемблере:
Ассемблер необходимо скомпилировать в машинный код. Обратите внимание, что 512 в шестнадцатеричной системе — это 0x200, а последние два байта — 0x55 и 0xAA. Он инвертирован по сравнению с кодом ассемблера выше, что связано с системой порядка хранения, называемой порядком следования байтов. Например, в big-endian системе два байта, требуемых для шестнадцатеричного числа 0x55AA, будут храниться как 0x55AA (если 55 хранится по адресу 0x1FE, AA будет храниться 0x1FF). В little-endian системе это число будет храниться как 0xAA55 (AA по адресу 0x1FE, 55 в 0x1FF).
Машинный код после компиляции NASM
Я объясню этот код построчно в случае если вам не знаком ассемблер:
1. Если укажем целевой режим процессора, директива BITS укажет, где NASM следует сгенерировать код, предназначенный для работы на процессоре, поддерживающем 16-битный, 32-битный или 64-битный режим. Синтаксис — BITS XX, где XX это 16, 32 или 64.
2. Если укажем адрес начала программы в бинарном файла, директива ORG укажет начальный адрес, по которому NASM будет считать начало программы при её загрузке в память. Когда этот код переводится в машинный, компилятор и компоновщик определяют и организуют все структуры данных, необходимые программе. Для этой цели будет использован начальный адрес.
3. Это просто ярлык. Когда он определён в коде, то ссылается на позицию в памяти, которую вы можете указать. Он используется вместе с командами условного перехода для контроля потока приложения.
После разбора четвёртой строки нам необходимо описать концепцию регистров:
Регистр процессора — блок ячеек памяти, образующий сверхбыструю оперативную память (СОЗУ) внутри процессора. Используется самим процессором и большей частью недоступен программисту: например, при выборке из памяти очередной команды она помещается в регистр команд, к которому программист обратиться не может. Википедия
4. Назначение данных с помощью инструкции MOV, которая используется для перемещения данных. В данном случае мы перемещаем значение адреса в памяти ярлыка сообщения в регистр SI, который укажет на текст “Hey! This code is my boot loader operating”. На картинке ниже видим, что при переводе в машинный код этот текст хранится в позиции 0x7C10.
5. Мы будем использовать видеосервисы BIOS для отображения текста на экране, поэтому сейчас мы настраиваем отображение по своему желанию. Сервис перемещает байт 0x0E в регистр AH.
6. Ещё одна ссылка на метку, позволяющая управлять потоком выполнения. Позднее мы используем её для создания цикла.
7. Эта инструкция загружает байт из операнда-источника в регистр AL. Вспомните четвёртую строку, где регистру SI была задана позиция текстового адреса. Теперь эта инструкция получает символ, хранящийся в ячейке памяти 0x7C10. Важно заметить, что она ведёт себя как массив, и мы указываем на первую позицию, содержащую символ ‘H’, как видно на рисунке ниже. Этот текст будет представлен итеративно по вертикали, и каждый символ будет задаваться каждый раз. Кроме того, второй символ не был представлен снимком, извлечённым из программы IDA. 0x65 в ASCII отображает символ ‘e’:
8. Выполнение логической операции OR между (AL | AL) на первый взгляд кажется бессмысленным, однако это не так. Нам нужно проверить, равен ли результат этой операции нулю, основываясь на логическом булевом значении. После этой операции результат будет, например, [1 | 1 = 1] или [0 | 0 = 0].
9. Переход к метке остановки (строка 12), если результат последней операции OR равен нулю. В первый момент значение AL равно [0x48 = ‘H’] , основываясь на последней инструкции LODSB, помните строку 7? Значит, код не перейдёт к метке остановки в первый раз. Почему так? (0x48 OR 0x48) = 0x48, следовательно он переходит к следующей инструкции на следующей строке. Важно заметить, что инструкция JZ связана не только с инструкцией OR. Существует другой регистр, FLAGS, который наблюдается в процессе операций перехода, то есть результат операции OR хранится в этом регистре FLAG и наблюдается инструкцией JZ.
10. Вызывая прерывание BIOS, инструкция INT 0x10 отображает значение AL на экране. Вспомните строку 5, мы задали значение AH байтом 0x0E. Это комбинация для представления значения AL на экране.
11. Переход к метке loop, которая без всяких условий похожа на инструкцию GOTO в языках высокого уровня.
12. Мы снова на строке 7, LODSB перехватывает контроль. После того, как байт будет перемещён из адреса в памяти в регистр AL, регистр SI инкрементируется. Во второй раз он указывает на адрес 0x7C11 = [0x65 ‘e’], затем на экране отображается символ ‘e’. Этот цикл будет выполняться до тех пор, пока не достигнет адреса 0x7C3B = [0x00 0], и, когда JZ снова выполнится в строке 9, поток будет доведён до метки остановки.
13. Здесь мы заканчиваем наше путешествие. Выполнение останавливают инструкции CLI и HLT.
14. На строке 17 вы видите инструкцию, которая заполняет оставшиеся 510 байтов нулями после чего добавляет подпись загрузочной записи 0xAA55.
Убедитесь, что компилятор NASM и эмулятор виртуальной машины QEMU установлены на ваш компьютер. Воспользуйтесь предпочтительным менеджер зависимостей или скачайте их из интернета.
Для Linux наберите в терминале:
sudo apt-get install nasm qemu
На Mac OS можно использовать homebrew:
brew install nasm qemu
После этого вам нужно создать файл с кодом сборки, представленным в коде загрузчика выше. Давайте назовём этот файл boot.asm и затем запустим команду NASM:
nasm -f bin boot.asm -o boot.bin
Будет создан двоичный файл, который нужно запустить на виртуальной машине. Давайте запустим на QEMU: