Ломаем BIOS: включение поддержки виртуализации VT-x на нетбуке Acer Aspire One

в 21:44, , рубрики: diy или сделай сам, virtualbox, виртуализация, Нетбуки, операционные системы, метки: , ,

В данной статье мы расскажем вам пошагово о том, как допилить напильником свой нетбук или ноутбук, в котором по какому-то недоразумению выключен и залочен в таком состоянии бит 2 в MSR 0x3A — попросту говоря, у вас есть в процессоре поддержка виртуализации, но она заблокирована биосом.

ПРЕДУПРЕЖДЕНИЕ: всё, описанное в этой статье, рассчитано на то, что вы знаете, что делаете. Всё на свой страх и риск! Если не уверены — не пытайтесь повторить это дома.

Итак, в чем же проблема?

Проблема, которую мы будем решать, для конечного пользователя компьютера выглядит так: При использовании гипервизора второго типа (например, VirtualBox)

  • вы не можете запускать виртуалки с более, чем одним процессором
  • вы не можете запускать 64-битные гостевые операционные системы внутри 32-битной хост ОС.

Вот такое сообщение вы можете видеть при попытке запуска виртуалки с числом процессоров, большим чем 1:
image

Аналогичное сообщение об ошибке вы также получаете, если собираетесь запускать 64-битную виртуальную машину (например, Debian amd64) с 32-разнядной хост ОС, например WinXP.

Можно ли вылечить это?

На этот вопрос можно ответить, проверив некоторые биты в некоторых словах состояния процессора. Самый простой способ убедиться, что в вашем случае проблема лечится — это посмотреть на то, что показывает программа SecurAble. В моем случае это выглядело так:
image

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

Биос на нетбуке Acer Aspire производства Insyde, настройки его очень скудны и по F2 естественно мы не можем зайти в программу редактирования настроек БИОСа и включить виртуализацию там. Это было бы слишком просто.

Поэтому, мы будем дизассемблировать БИОС и менять его код, чтобы у нас бит был выставлен в 1. Если готовы, то читаем далее.

Что нужно знать до начала работы

Итак, некоторая техническая информация — чтобы понимать, что мы делаем и зачем.

Современные процессоры, по крайней мере многие из них, имеют поддержку виртуализации. За нее отвечает бит №5 в слове ECX при вызове команды CPUID с параметром EAX=01H. Именно этот способ проверки — единственно верный, поскольку, как показывает практика, сайт Intel врет, например, для моего процессора Intel Atom N570. По этой ссылке написано:

Intel® Virtualization Technology (VT-x) 	No

Однако мы-то знаем, что это неправда. Для тех, кто на «ты» с программированием на ассемблере, не составит труда выяснить это, написав нечто вроде

MOV EAX, 1
CPUID

и проверив потом 5-й бит регистра ECX.
Мне же было лень этим заниматься, поэтому я скачал опенсорсовую программу CPUID Explorer, запустил ее и посмотрел результат. К слову, CPU-Z тут непригодна — она дает результат слишком «юзер френдли» — нам же нужно было узнать точное значение бита. Вот как это выглядело в моем случае:
image
В кружочек обведен интересующий нас бит VMX. Он выставлен в 1, он есть, несмотря на то, что говорит нам сайт Intel.
Документация по командам процессора на стр. 215 говорит нам про команду CPUID, что
Bit #5 VMX Virtual Machine Extensions. A value of 1 indicates that the processor supports this technology

Но это еще не все. Чтобы гипервизоры второго типа смогли пользоваться командами поддержки виртуализации (VMX), необходимо явным образом разрешить эти инструкции в MSR (специальном регистре процессора) номер 0x3A. Вот что говорит нам документация по этому регистру на стр. 237:
регистр 3Ah: IA32_FEATURE_CONTROL
Бит 0: lock bit — если он выставлен, то дальнейшие модификации этого регистра не допускаются, до следующей перезагрузки.
Бит 1: VMX в SMX — safer mode extensions. Работа функций виртуализации в SMX допускается только тогда, когда процессор поддерживает SMX — это указывается в соседнем слева, 6-м бите в ECX при вызове команды CPUID.01H — на картинке выше этот бит равен нулю, наш процессор Atm N570 не поддерживает SMX — поэтому и в MSR 0x3A бит №1 должен быть нулевым.
Бит 2: VMX не в SMX — это, собственно, и есть бит, отвечающий за поддержку виртуализации. Он соответствует обведенному в кружочек биту в CPUID и именно он должен быть выставлен в 1.

Как проверить содержимое MSR 0x3A

Чтобы убедиться, что мы все про наш компьютер поняли верно, нужно посмотреть, что на самом деле у нас хранится в MSR 0x3A. Для этого я использовал пакет msr-tools в Debian (реальном, не виртуальном. В виртуальном результат неверный). Вот так вы сможете проверить значение этого бита:
— ребутаемся в Debian, потом:

# apt-get install msr-tools
# modprobe msr
# rdmsr 0x3A
9

Девять!!! Девять это 00001001. Как видим, наш BIOS использует недокументированный бит №3 в специальном слове регистра 0x3A — по документации, этот бит Reserved. Но это не суть. Суть в том, что у нас включен lock bit и выключен наш VMX бит №2 — так что все верно, программа SecurAble не врет и у нас действительно поддержка виртуализации отключена на уровне BIOS, хотя и поддерживается процессором.

Будем это править.

Почему эту проблему нужно решать

Дело в том, что при отключенной поддержке виртуализации (VMX) в процессорном слове 0x3A ваши виртуальные машины в VirtualBox работают в режиме паравиртуализации. Они, не имея возможности перевести гипервизор в VMX Root и виртуальную машину в VMX Non-root operation, вынуждены делать трансляцию процессорных инструкций НА ЛЕТУ. Проблему представляют 17 инструкций процессора, которые не «VM-safe», т.е. они используют единственные на весь компьютер регистры или блоки данных (таблицы) в процессоре. Эти команды: SGDT, SIDT, SLDT, SMSW, PUSHF/POPF, LAR, LSL, VERR/VERW, CALL, JMP, INT n, INTO, RET, STR и даже банальная MOV! Все эти инструкции изменяются на лету, чтобы виртуальная машина выполнила их в безопасном для системы виде. Подробнее про эту проблему описано тут (англ.). Из-за этого страдает быстродействие виртуальной машины.

Что нам потребуется

Для этой задачи нам потребуются следующие вещи:

  • оригинальный BIOS для нашего нетбука с сайта производителя.
  • IDA
  • phoenixtool210.zip (гугл знает, где скачать)
  • HHD Hex Editor Neo или любой другой HEX Editor
  • FAR Manager :)
  • nasm — для дизассемблирования
  • Знание о том, как залить BIOS аварийным способом

Для начала, очень важно знать, что если что-то пойдет не так, то как восстановить компьютер. Для моего ноутбука с биосом InsydeH20 существует недокументированная процедура восстановления биоса:

  • отформатить USB HDD в FAT16 с партицией мегов на 100 (FAT32 не понимает)
  • залить туда один файл со сжатым биосом (ZE6.fd в моем случае)
  • выключить ноут, потом вынуть все USB устройства и аккумулятор
  • вынуть шнур питания
  • подключить USB HDD
  • нажать и удерживать Esc+Fn
  • воткнуть питание и через 5 сек нажать кнопку включения питания
  • отпустить кнопки клавиатуры

И вуаля, материнская плата сама (как — загадка) выкачает с USB HDD новый биос и прошьет его за 1 минуту, потом ноут ребутнется.

Я проверил этот способ, залив таким образом стандартный биос с сайта производителя (другой версии, чем стоял у меня до этого) — действительно, работает, версия биоса обновилась.
Таким же способом я решил в итоге заливать в систему и прохаченный биос.

Итак, начинаем:
Распаковываем биос из SFX-архива, скачанного с сайта производителя. Сам иос будет иметь имя файла что-то вроде ZE6.fd и иметь размер 2 мегабайта ровно.
Далее нам необходимо распаковать БИОС, поскольку он сжат. Для этого используется программа PhoenixTool.exe. В первое поле в ее окошке мы указываем этот сжатый биос, и программа сама его декомпиляет на, в моем случае, целых 609 исходных файлов, имеющих имена в формате GUID.ext. Часть из этих файлов — конфигурационные, а часть — двоичные, но все с расширением ROM. Некоторые двоичные файлы содержат программы со стандартным виндовским PE заголовком.

Наша задача — среди этих 609 файлов найти файл, содержащий нужную нам инструкцию

WRMSR

оказалось, что искать команду MOV EAX, 3AH перед командой WRMSR бессмысленно — в моем биосе WRMSR оформлена как отдельная функция и принимает параметры через стек. Поэтому я делал это так (мне показалось то проще, чам в IDA): установил на Linux пакет nasm, который включает в себя ndisasm. Потом дизассемблировал все файлы *.ROM командой

ndisasm -b 32 file.rom > file.asm

И потом простым поиском нашел команду wrmsr в них — таких файлов оказалось 29. Потом пришлось каждый из ни загружать в IDA и искать там нужный код, который лочит регистр 3AH.

Такой код нашелся только в одном файле с именем 62D171CB-78CD-4480-8678-C6A2A797A8DE.MOD, и выглядел этот код так (после некоторой моей работы по переименованию функций в более понятные, и добавлении пары комментов):

LOCK_VMX        proc near            

                push    esi
                push    3Ah
                call    ReadMSR
                pop     ecx
                mov     ecx, eax
                xor     esi, esi
                and     ecx, 1
                or      ecx, esi
                pop     esi
                jnz     short exitprc    ; if(ReadMSR() & 1) goto exitprc;
                push    edx
                or      eax, 1          ; Set lock bit (bit #0)
                push    eax
                push    3Ah
                call    WriteMSR
                add     esp, 0Ch

exitprc:                      
                retn
LOCK_VMX        endp

По определению, код, который лочит регистр, делает это один раз. Потому это самое удачное место для того, чтобы сделать наш хак: меняем цифру 1 на цифру 5 в инструкции:

or      eax, 1

Это приведет к тому, что одновременно с выставлением lock bit мы выставляем бит VMX (бит #2). Заметим тут, что мы не имеем права выставлять бит #1, поскольку набор инструкций SMX у нас в процессоре не поддерживается (это говорит CPUID.1H:ECX bit 6.

Менять будем не совсем в файле *.ROM, а в оплетке *.MOD, которая содержит этот файл. Для этого нужно в программе PhoenixTool.exe, которая у нас уже открыта и биос в нее уже загружен, нажать на кнопку Structure, и инайти ветку с нашим именем файла:
image
Нажимаем кнопку Extract, получаем файл *.MOD (который состоит из заголовка + тела файла *.ROM), и правим наш бит именно в этом файле MOD. Смотрим в IDA, какой двоичный код соответствует окрестности инструкции, которую мы меняем, и в HEX редакторе открываем файл, ищем это место в коде, и меняем всего 1 байт с 01 на 05. Сохраняем модифицированный файл *.MOD. Потом в PhoenixTool нажимаем Replace, выбираем модифицированный MOD, и нажимаем Exit. Всё. Программа сама пересобрала биос и упаковала его для нас, при этом назвала его тем же именем, что и было (старый файл сохранен с расширением OLD).

Всё. Теперь заливаем единственный файл с новым биосом на USB HDD (можно и на USB флешку), и выполняем описанную выше процедуру аварийного восстановления биоса. Она прошьет комп этом новым биосом и всё будет готово.

Вот как теперь выглядит вывод программы SecurAble:
image

Теперь VirtualBox запускает виртуалки с 4 ядрами (а не с одним, как было раньше). Теперь я из-под своей основной 32-разряной операционной системы могу запускать 64-битные операционки в виртуалках.
И, что самое главное, теперь виртуалки на самом деле виртуализованные (гипервизор использует инструкции VMX), а не паравиртуализованные.

P.S. В биосах других производителей (не Insyde) есть возможность править не сам BIOS, а только его настройки, извлекаемые программой SYMCMOS.EXE. Там процесс такой же, за исключением того, что в дизассемблированном биосе находится номер настройки, которая используется для запрещения или разрешения VMX, и потом эта настройка правится непосредственно в CMOS биоса. В моем же биосе таких настроек нет, или программа symcmos их не находит, поэтому такой путь допиливания напильником не подходит в моем случае. Путь непосредственного хака биоса выглядит надежнее: мы таким образом просто игнорируем какие бы то ни было настройки биоса, просто выставляем бит VMX и лочим регистр 0x3A после этого.

Счастье есть :) Спасибо, что дочитали до конца.

Автор: danx

  1. Flat Earth:

    Спасибо, очень интересная и поучительная статья.
    Хочу опробовать это на своем Lenovo G560.

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js