Отладка гипер­визора Hyper-V

Hyper-V

Ги­пер­визор про­изводс­тва кор­порации Microsoft, как и любая дру­гая прог­рамма, соз­дан людь­ми, а зна­чит, содер­жит опре­делен­ное количес­тво оши­бок. Поиск этих оши­бок — занятие не толь­ко увле­катель­ное, но и полез­ное: во‑пер­вых, Microsoft рас­полага­ет собс­твен­ной прог­раммой Bug Bounty (о ее осо­бен­ностях я рас­ска­жу чуть ниже), а во‑вто­рых… Во‑вто­рых, зна­ния об уяз­вимос­тях и недоку­мен­тирован­ных воз­можнос­тях при­ложе­ний цен­ны сами по себе. В сегод­няшней статье мы рас­смот­рим прин­ципы отладки гипер­визора Hyper-V и раз­берем­ся в его осо­бен­ностях.

Ги­пер­визор ком­пании Microsoft исполь­зует­ся в боль­шом чис­ле ком­понен­тов Windows и, как любой слож­ный про­дукт, не лишен допущен­ных при раз­работ­ке оши­бок. Чис­ло уяз­вимос­тей, най­ден­ных в этом про­дук­те толь­ко в 2020 году, сос­тавило 21.

В 2020 году в Hyper-V была обнаружена 21 уязвимость
В 2020 году в Hyper-V была обна­руже­на 21 уяз­вимость

Для Hyper-V Microsoft пред­лага­ет от­дель­ную прог­рамму баг‑баун­ти, раз­мер вып­лат которой может дос­тигать 250 тысяч дол­ларов. Одна­ко сто­ит упо­мянуть, что Microsoft не работа­ет со стра­нами, которые находят­ся в сан­кци­онном спис­ке США. Рос­сия фор­маль­но при­сутс­тву­ет в этом спис­ке, поэто­му сле­дует про­являть осмотри­тель­ность, ког­да отправ­ляешь информа­цию об уяз­вимос­тях в Microsoft, если ты еще ни разу не получал воз­награж­дение нап­рямую от вен­дора. Луч­ше вос­поль­зовать­ся услу­гами пос­редни­ка, ина­че ты можешь стол­кнуть­ся с тем, что обна­ружен­ная тобою уяз­вимость вдруг одновре­мен­но будет най­дена дру­гой ком­пани­ей или иссле­дова­телем. И неваж­но, что уяз­вимость оста­валась в про­дук­те нес­коль­ко лет (этот вари­ант был про­верен на прак­тике).

Отладка гипер­визора Hyper-V

Что­бы искать уяз­вимос­ти в Hyper-V, нуж­но вла­деть метода­ми отладки это­го гипер­визора. Акту­аль­ные спо­собы отладки и будут темой сегод­няшней статьи. Для этих целей мож­но исполь­зовать эму­лято­ры, под­держи­вающие вло­жен­ную вир­туали­зацию (такие как VMware Workstation или сам Hyper-V), либо обыч­ный компь­ютер или ноут­бук.

Термины

  • Ги­пер­визор — ком­понент Hyper-V, отве­чающий за фун­кци­они­рова­ние под­систе­мы аппа­рат­ной вир­туали­зации про­цес­сора ( hvix64.<wbr />exe — Intel, hvax64.<wbr />exe — AMD, hvaa64.<wbr />exe — ARM). В статье рас­смат­рива­ется гипер­визор для про­цес­соров Intel.
  • Ги­пер­вызов (hypercall) — вызов задан­ной фун­кции в гипер­визоре с помощью инс­трук­ции vmcall\\<wbr />vmmcall\\<wbr />hvc (в зависи­мос­ти от про­изво­дите­ля про­цес­сора);
  • root-раз­дел — Windows Server 2019 с вклю­чен­ным ком­понен­том Hyper-V;
  • гос­тевой раз­дел (вир­туаль­ная машина, ВМ) — опе­раци­онная сис­тема, запущен­ная в сис­теме вир­туали­зации Hyper-V;
  • VMCS (virtual-machine control structure) — струк­тура, опре­деля­ющая логику работы гипер­визора;
  • VMX root — режим, в котором работа­ет гипер­визор;
  • VMX non-root — режим, в котором работа­ет опе­раци­онная сис­тема и обслу­жива­емое ею прик­ладное прог­рам­мное обес­печение;
  • VM exit — переход из VMX non-root в VMX root при выпол­нении инс­трук­ций или усло­вий, задан­ных в VMCS или заложен­ных непос­редс­твен­но в логику работы про­цес­сора.

Отладка через COM-порт

Hyper-V сос­тоит из нес­коль­ких ком­понен­тов, крат­кое опи­сание его струк­туры мож­но най­ти в до­кумен­тации. Для отладки ком­понен­тов Hyper-V ты можешь исполь­зовать WinDbg либо дру­гой отладчик поль­зователь­ско­го режима или режима ядра, одна­ко для под­клю­чения непос­редс­твен­но к гипер­визору необ­ходимо выпол­нить нес­коль­ко допол­нитель­ных шагов, что­бы нас­тро­ить рутовый раз­дел.

Для отладки гипер­визора Microsoft раз­работа­ла спе­циаль­ное рас­ширение WinDbg hvexts.<wbr />dll, которое, к сожале­нию, не вхо­дит в дис­три­бутив и дос­тупно толь­ко пар­тне­рам Microsoft (пос­коль­ку это­му рас­ширению тре­буют­ся сим­волы для модуля гипер­визора, которые Microsoft не пре­дос­тавля­ет). Так­же в катало­ге winxp, находя­щем­ся в пап­ке WinDbg, есть рас­ширение nvkd.<wbr />dll, которое пред­назна­чено для отладки рас­ширений вир­туаль­ного ком­мутато­ра Hyper-V.

Файл справ­ки WinDbg содер­жит опи­сание отладки гипер­визора через COM-порт (отладка Hyper-V через нуль‑модем­ное кабель­ное соеди­нение в фай­ле debugger.<wbr />chm), под­разуме­вающее наличие двух физичес­ких машин. Так­же гипер­визор мож­но отла­дить, если запус­тить его в любом под­держи­ваемом прог­рам­мном обес­печении вир­туали­зации. Далее мы будем исполь­зовать VMware Workstation.

Для начала нуж­но уста­новить Windows Server 2019 в качес­тве гос­тевой ОС и вклю­чить ком­понент Hyper-V. Если нап­рямую под­клю­чить­ся к вир­туаль­ному COM-пор­ту VMware, то при ком­муника­ции пой­дут ошиб­ки обме­на пакетов (слож­но ска­зать, с чем это свя­зано). Исполь­зуй какую‑нибудь бес­плат­ную ути­литу эму­ляции COM-пор­та для ста­били­зации соеди­нения (я уста­новил ути­литу эму­лято­ра COM-пор­та Free Virtual Serial Ports от HHD-software вер­сии 3.32. Пос­ледняя вер­сия 4.12 выда­ет ошиб­ки, ког­да vmdemux пыта­ется открыть COM-порт).

Об­щий порядок дей­ствий таков.

  1. Соз­дай COM-порт для вир­туаль­ной машины VMware (Hardware → Add → Serial port → Use named pipe). Вве­ди \\.\<wbr />pipe\<wbr />com_1.

    Создание COM-порта для виртуальной машины
    Соз­дание COM-пор­та для вир­туаль­ной машины
  2. Для нас­трой­ки отладки вве­ди в коман­дной стро­ке опции отладки гипер­визора:

    bcdedit /hypervisorsettings serial DEBUGPORT:1 BAUDRATE:115200
    bcdedit /set hypervisordebug on

    За­тем нуж­но ввес­ти парамет­ры отладки хос­товой ОС (будет исполь­зован тот же COM-порт):

    bcdedit /set dbgtransport kdhvcom.dll
    bcdedit /dbgsettings serial DEBUGPORT:1 BAUDRATE:115200
    bcdedit /debug on

    До­пол­нитель­но (для отладки заг­рузки гипер­визора — см. соот­ветс­тву­ющий раз­дел статьи):

    Bcdedit /set bootdebug on

    Ни­же при­веден спи­сок модулей отладки, при­сутс­тву­ющих в Windows:

    kdcom.dll
    kdhvcom.dll
    kd1934.dll
    kdhv1394.dll
    kdusb.dll
    kdnet.dll (разные производители сетевых карт — разные модули)
    kd.dll

    В нашем слу­чае мы исполь­зуем kdhvcom.<wbr />dll.

  3. Пе­резаг­рузи Windows Server 2019. Заг­рузка оста­новит­ся и будет ждать под­клю­чения отладчи­ка.

  4. От­крой HHD software Free Virtual Serial Ports, выбери File, затем Create Pipe Port. В поле Pipe name ука­жи то же зна­чение, что было рань­ше запол­нено для вир­туаль­ной машины, —  \\.\<wbr />pipe\<wbr />com_1. Чек­бокс Create pipe дол­жен быть отклю­чен (в про­тив­ном слу­чае будет соз­дан новый име­нован­ный канал, а не выпол­нено под­клю­чение к сущес­тву­юще­му). Наж­ми OK.

    Создание нового порта
    Соз­дание нового пор­та

    Вир­туаль­ный COM-порт нуж­но соз­давать пос­ле запус­ка вир­туаль­ной машины, ина­че ты уви­дишь ошиб­ку, что канал не был соз­дан (VMware соз­дает канал пос­ле запус­ка ВМ).

  5. За­пус­ти ути­литу vmdemux (находит­ся в пап­ке с WinDbg x64) с ука­зани­ем име­ни толь­ко что соз­данно­го COM-пор­та в качес­тве одно­го из парамет­ров:

    vmdemux.exe src com:port=com2,baud=115200

    Ути­лита соз­даст два име­нован­ных канала: Vm0 для гипер­визора и  Vm1 для root-раз­дела.

    Утилита vmdemux создаст два именованных канала
    Ути­лита vmdemux соз­даст два име­нован­ных канала
  6. Ты можешь под­клю­чить WinDbg Preview к каж­дому каналу для тес­тирова­ния:

    WinDBGx.exe k com:port=\.pipeVm1,pipe,reconnect,resets=0 rootраздел
    WinDBGx.exe k com:port=\.pipeVm0,pipe,reconnect,resets=0 гипервизор
    Подключение WinDbg к созданным нами каналам
    Под­клю­чение WinDbg к соз­данным нами каналам
  7. Пос­ле это­го мож­но открыть файл hvix64.exe в IDA PRO, выб­рать WinDbg в качес­тве отладчи­ка и ука­зать в process options → connection string: com:<wbr />port=\\.\<wbr />pipe\<wbr />Vm0,<wbr />pipe,<wbr />resets=0.

  8. Вы­бери Process Attach, наж­ми Same.

  9. От­ладчик оста­новит­ся внут­ри гипер­визора.

    Отладчик остановится внутри гипервизора
    От­ладчик оста­новит­ся внут­ри гипер­визора
  10. По срав­нению с Windows Server 2012 (R2) в акту­аль­ной вер­сии сер­верной вин­ды появил­ся новый модуль — kdstub.<wbr />dll. Ран­ние вер­сии гипер­визора ста­тичес­ки лин­ковались с биб­лиоте­кой отладки и име­ли дос­таточ­но боль­шой раз­мер (2–3 Мбайт), раз­мер текущей вер­сии (10.0.17763.1577) гипер­визора hvix64.<wbr />exe — 1230 Кбайт. В слу­чае сетевой отладки kdstub.<wbr />dll будет заменен под­ходящим отла­доч­ным модулем, нап­ример kd_02_8086.<wbr />dll.

    При сетевой отладке kdstub.dll будет заменен подходящим отладочным модулем
    При сетевой отладке kdstub.dll будет заменен под­ходящим отла­доч­ным модулем

    Во всех под­робнос­тях нас­трой­ка отладки через COM-порт в сре­де Hyper-V опи­сана в статье Саара Ама­ра (@AmarSaar).

Отладка по сети

В Windows Server 2012 и выше появи­лась воз­можность отладки гипер­визора по сети. Так­же эта воз­можность при­сутс­тву­ет во всех вер­сиях Windows 10. Для это­го в хос­товой ОС необ­ходимо выпол­нить коман­ды, что­бы нас­тро­ить парамет­ры отладки гипер­визора:

bcdedit /set hypervisordebug on
bcdedit /hypervisorsettings NET HOSTIP:192.168.2.1 PORT:50000

Ес­ли есть необ­ходимость, для отладки ОС на хос­те нуж­но ука­зать дру­гой порт:

bcdedit /debug yes
bcdedit /dbgsettings net hostip:192.168.2.1 port:50002

Пос­ле выпол­нения команд будет отоб­ражена стро­ка для под­клю­чения. В нас­трой­ках вир­туаль­ной машины VMware нуж­но уста­новить тип адап­тера Host Only, в нас­трой­ках вир­туаль­ной сети (Edit → Virtual Network Editor) нас­тро­ить DHCP для это­го адап­тера и убе­дить­ся, что гос­тевая ОС нор­маль­но получа­ет этот адрес, нап­ример выпол­нив коман­ду ipconfig /<wbr />renew. Опция bcdedit /<wbr />dbgsettings nodhcp поз­воля­ет исполь­зовать IP-адрес опе­раци­онной сис­темы. В этом слу­чае нас­трой­ка DHCP необя­затель­на.

Пос­ле это­го нуж­но запус­тить два экзем­пля­ра IDA PRO, выб­рать тип отладки KernelMode, ука­зать в Process Option → Connection string сле­дующие стро­ки, получен­ные в резуль­тате выпол­нения при­веден­ных выше команд:

net:port=50002,Key=1.2.3.4 — root partition
net:port=50000,Key=5.6.7.8 — hypervisor

Это поз­воля­ет одновре­мен­но отла­живать root-раз­дел и гипер­визор. Сетевая отладка гораз­до про­ще в кон­фигура­ции, дает бо́льшую про­изво­дитель­ность и ста­биль­нее, поэто­му я рекомен­дую исполь­зовать ее там, где это воз­можно. Выпол­нить некото­рые коман­ды WinDbg мож­но даже без наличия сим­волов. Если какие‑то из перечис­ленных ниже команд не будут дос­тупны, прос­то пов­торно заг­рузи сле­дующие рас­ширения WinDbg:

.load kext
.load kdexts
.load exts
.load ext

Здесь:

  • lm — прос­мотр заг­ружен­ных модулей (обыч­но hv и модуль отладки);
  • k — прос­мотр сте­ка;
  • d, e — чте­ние/запись дан­ных по вир­туаль­ных адре­сам;
  • !d, !e — чте­ние/запись дан­ных в физичес­кой памяти;
  • r — отоб­ражение зна­чений регис­тров;
  • !vtop — тран­сля­ция вир­туаль­ных адре­сов в физичес­кие. Спер­ва нуж­но получить содер­жимое регис­тра cr3 и исполь­зовать его как пер­вый параметр. Вир­туаль­ный адрес — вто­рой параметр.

2: kd> !vtop 0x10839d000 0xfffffbb3aa6c3e66
Amd64VtoP: Virt fffffbb3aa6c3e66, pagedir 000000010839d000
Amd64VtoP: PML4E 000000010839dfb8
Amd64VtoP: PDPE 000000010a603670
Amd64VtoP: PDE 000000010a604a98
Amd64VtoP: Large page mapped phys 00000001000c3e66
Virtual address fffffbb3aa6c3e66 translates to physical address 1000c3e66.
!pte2va
!ptov <cr3>

dx — рас­ширение дос­тупно тоже, но с некото­рыми огра­ниче­ниями (из‑за отсутс­твия сим­волов): @$debuggerRootNamespace.<wbr />Debugger.<wbr />State.<wbr />PseudoRegisters.<wbr />General. Exentry — псев­дорегистр, отоб­ража­ющий адрес заг­рузки модуля гипер­визора (hvix64).

Exentry — псевдорегистр, отображающий адрес загрузки модуля гипервизора
Exentry — псев­дорегистр, отоб­ража­ющий адрес заг­рузки модуля гипер­визора

Отладка с использованием встроенных возможностей vmwp.exe

От­ладка вир­туаль­ной машины может быть выпол­нена с исполь­зовани­ем встро­енных воз­можнос­тей про­цес­са vmwp.<wbr />exe (на одну ВМ один экзем­пляр). Эту воз­можность впер­вые упо­мянул на форуме OSR online один из архи­тек­торов Hyper-V Джейк Ошинс (Jake Oshins). Более под­робно опи­сал Рафа­эль Ривера (Rafael Rivera — @WithinRafael) в сво­ем бло­ге. Я обно­вил скрипт Риверы и выложил его на GitHub.

Скрипт так­же может скон­фигури­ровать парамет­ры заг­рузчи­ка гос­тевой ОС при помощи PowerShell direct. Для это­го:

  1. Вык­лючи гос­тевую ОС.

  2. Ука­жи парамет­ры для скрип­та hyperv-dbg-2019.<wbr />ps1.

    Параметры для скрипта hyperv-dbg-2019.ps1
    Па­рамет­ры для скрип­та hyperv-dbg-2019.ps1
  3. За­пус­ти скрипт от име­ни адми­нис­тра­тора (или отклю­чи UAC).

  4. За­пус­ти WinDbg сле­дующей коман­дой:

    WinDBG k net:port=50010,target=127.0.0.1,key=1.2.3.4
  5. Вы­пол­ни коман­ду break (Ctrl-Break), пос­ле которой отладчик оста­новит­ся внут­ри гос­тевой ОС. Теперь мож­но иссле­довать ВМ, исполь­зуя стан­дар­тные коман­ды WinDbg, но в моих экспе­римен­тах интенсив­ная отладка (нап­ример, трас­сиров­ка) нес­коль­ко раз при­води­ла к тому, что все зависа­ло.

Отладка через протокол GDB

VMware Workstation под­держи­вает встро­енный GDB-отладчик. Что­бы его вклю­чить, нуж­но добавить нес­коль­ко строк в кон­фигура­цион­ный файл VMware:

debugStub.listen.guest64 = «TRUE»
debugStub.listen.guest64.remote = «TRUE» — для подключения с других сетевых машин
debugStub.hideBreakpoints = «TRUE»
monitor.debugOnStartGuest64 = «TRUE» остановка сразу же после включения VM

За­тем ты можешь под­клю­чить IDA PRO, «Гид­ру» или Radare2 к акти­виро­ван­ному сер­веру GDB. При­мер отладки через GDB-про­токол будет показан в раз­деле «Заг­рузка гипер­визора».

Отладка эмулятора Windows 10X

Эму­лятор Windows 10X дос­тупен в магази­не Microsoft Store. Этот эму­лятор работа­ет на базе Hyper-V. Сам эму­лятор запус­кает­ся как Hyper-V ВМ, Windows 10X — вло­жен­ная ВМ.

Не­обхо­димо смон­тировать образ flash.<wbr />vhdx (прос­то два раза щел­кнуть мышью на фай­ле), с которым работа­ет эму­лятор и который рас­положен в пап­ке по сле­дующе­му пути:

C:ProgramFilesWindowsAppsMicrosoft.Windows10XEmulatorImage10.0.19578.0Previ_1.0.1.0_x64__8wekyb3d8bbweContent

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

Состояние системы до монтирования
Сос­тояние сис­темы до мон­тирова­ния
Состояние системы после монтирования
Сос­тояние сис­темы пос­ле мон­тирова­ния

Вы­бери том с мет­кой VIRT_EFIESP:

GetVolume | ? {$_.FileSystemLabel eq «VIRT_EFIESP»} | FormatList
mountvol Z: \?Volume{12aef83a6cf24ea1932fb3a586a65308}
bcdedit /store «Z:efiMicrosoftbootBCD» /dbgsettings

Ко­ман­да bcdedit /<wbr />enum <wbr />all /<wbr />v /<wbr />store <wbr />"Z:\<wbr />efi\<wbr />Microsoft\<wbr />boot\<wbr />BCD" покажет опции заг­рузоч­ной записи опе­раци­онной сис­темы эму­лято­ра. Что­бы у нас появи­лась воз­можность отладки гос­тевой ОС, понадо­бит­ся дамп ядра, который мож­но получить с исполь­зовани­ем встро­енных фун­кций эму­лято­ра.

Получение дампа ядра
По­луче­ние дам­па ядра

От­крой Windows device portal — «Отладка». Заг­рузи live kernel dump, а затем открой его в WinDbg и запус­ти скрипт decypher_kdnet_key.<wbr />py. Скрипт най­дет парамет­ры kdnet и закоди­рует в фор­мате Base36.

Использование скрипта decypher_kdnet_key.py
Ис­поль­зование скрип­та decypher_kdnet_key.py

Те­перь запус­ти WinDbg, исполь­зуя коман­ду windbgx.<wbr />exe <wbr />-k <wbr />net:<wbr />port=50005,<wbr />key=2k85xmoorkrbx.<wbr />u7xg1f35gwi4.<wbr />24033ib08wzhs.<wbr />2o8xly2z2ik5y. В резуль­тате ты смо­жешь под­клю­чить­ся к ОС хос­та.

Подключение к хостовой ОС
Под­клю­чение к хос­товой ОС

Отладка Hyper-V c помощью подмененного загрузчика

На эту тему опуб­ликова­ны два иссле­дова­ния: Hyper-V backdoor Дмит­рия Олек­сюка (@d_olex) и Voyager, соз­данный @_xeroxz. Их суть — в замене заг­рузоч­ных фай­лов Windows в целях перех­вата про­цес­са заг­рузки гипер­визора и интегра­ции сво­их управля­ющих модулей. Пол­ноцен­ной отладкой это слож­но наз­вать, но с при­мене­нием это­го метода появ­ляет­ся воз­можность читать и изме­нять память Hyper-V. Под­робнос­ти ты най­дешь на стра­ницах упо­мяну­тых про­ектов.

Заг­рузи пос­леднюю сбор­ку бэк­дора и запус­ти скрипт bootkit_installer.<wbr />ps1 в хос­товой ОС (про­тес­тирова­но в вир­туаль­ной сре­де на Windows Server 2019 внут­ри VMware Workstation). Перезаг­рузим хос­товую ОС и уви­дим сле­дующую кар­тину.

Запуск скрипта bootkit_installer.ps1
За­пуск скрип­та bootkit_installer.ps1

В гос­тевой ОС мы можем запус­тить backdoor_client.<wbr />exe и получить дос­туп к раз­личным струк­турам дан­ных Hyper-V.

Доступ к различным структурам данных Hyper-V на гостевой ОС
Дос­туп к раз­личным струк­турам дан­ных Hyper-V на гос­тевой ОС

Вто­рой про­ект, Voyager, может быть заг­ружен с сай­та GitHacks. Бинар­ников он не содер­жит, поэто­му их необ­ходимо ском­пилиро­вать с помощью Visual Studio для под­ходящей вер­сии Windows. Пос­ле чего запус­тить файл launch.<wbr />bat, который заменит заг­рузоч­ные фай­лы Windows. Пос­ле перезаг­рузки мы уви­дим сле­дующую кар­тину.

Загрузка ОС после применения Voyager
Заг­рузка ОС пос­ле при­мене­ния Voyager

Для про­вер­ки работос­пособ­ности мож­но запус­тить example.<wbr />exe внут­ри гос­тевой ВМ.

Проверка работоспособности Voyager
Про­вер­ка работос­пособ­ности Voyager

На­деюсь, мы уви­дим в будущем боль­ше при­меров для это­го про­екта.

Отладка secure kernel

От­ладку поз­воля­ет выпол­нить модуль EXDi для LiveCloudKd без вклю­чения опции отладки в заг­рузчи­ке гос­тевой ОС. Все под­робнос­ти мож­но узнать в соот­ветс­тву­ющей до­кумен­тации.

Отладка с помощью Radare2

Radare2 — кон­соль­ное средс­тво отладки, под­держи­вающее очень мно­го режимов. Мы рас­смот­рим толь­ко отладку ядра Windows. Бинар­ники мож­но заг­рузить с того же github.com по адре­су https://github.com/radareorg/radare2/releases.

Нез­начитель­но изме­нив исходни­ки, мож­но получить допол­нитель­ную информа­цию о Hyper-V (модифи­циро­ван­ные бинар­ники при­ложе­ны к статье). Для начала рекомен­дую почитать офи­циаль­ные источни­ки, они содер­жат от­личные инс­трук­ции.

До запус­ка необ­ходимо ско­пиро­вать сле­дующие рас­ширения WinDbg x64 в пап­ку с Radare2:

ext.dll
exts.dll
kdexts.dll
kext.dll

Не забудь ука­зать путь к пап­ке с уста­нов­ленным WinDbg x64 в перемен­ной окру­жения _NT_DEBUGGER_EXTENSION_PATH. Вот некото­рые коман­ды для тес­тирова­ния успешнос­ти под­клю­чения:

  • pd — дизас­сем­бли­рова­ние;
  • xq <wbr />@0x<<wbr />address> — отоб­ражение реги­она памяти;
  • v — перек­лючение в режим GUI.

Radare2 может под­клю­чать­ся к ядру Windows в двух режимах: через интерфейс dbgeng.<wbr />dll и с исполь­зовани­ем собс­твен­ного про­токо­ла winkd.

Radare2 и интерфейс dbgeng.dll

Спер­ва необ­ходимо нас­тро­ить гипер­визор в режиме сетевой отладки, как это было опи­сано рань­ше, и запус­тить Radare2 сле­дующим обра­зом:

radare2 d «windbg://-k net:port=50011,key=1.2.3.4″
Запуск Radare2
За­пуск Radare2

Под­клю­чено! Теперь ты можешь выпол­нять стан­дар­тные коман­ды WinDbg, исполь­зуя пре­фикс =!.

Выполнение стандартных команд отладчика
Вы­пол­нение стан­дар­тных команд отладчи­ка

Radare2 и встроенный протокол

Мож­но поп­робовать под­клю­чить­ся к гипер­визору по сети, выпол­нив коман­ду radare2 <wbr />-D <wbr />winkd <wbr />winkd://<wbr />192.<wbr />168.<wbr />174.<wbr />1:<wbr />50011:<wbr />1.<wbr />2.<wbr />3.<wbr />4. Я получил ошиб­ку откры­тия UDP-сокета, хотя netstat показал, что порт открыт. Воз­можно, это ошиб­ка нас­трой­ки на моем стен­де, но испра­вить ее мне не уда­лось. В свя­зи с этим будем исполь­зовать отладку через COM-порт. Для это­го нуж­но нас­тро­ить гипер­визор так, как это было опи­сано рань­ше, запус­тить vmdemux и под­клю­чить Radare2 к име­нован­ному каналу:

radare2 D winkd winkd://\\.\pipe\Vm0

Ис­поль­зуя дан­ные про­токо­ла отладки, мож­но получить допол­нитель­ную информа­цию о заг­ружен­ном модуле Hyper-V.

Получение дополнительной информации о загруженном модуле Hyper-V
По­луче­ние допол­нитель­ной информа­ции о заг­ружен­ном модуле Hyper-V

Иног­да Radare2 не может под­клю­чить­ся к COM-пор­ту и вис­нет. В этом слу­чае нуж­но прос­то спер­ва под­клю­чить­ся обыч­ным WinDbg-отладчи­ком, отклю­чить­ся и под­соеди­нить­ся с помощью Radare2.

Cutter

Cutter — GUI-фрон­тенд для Radare2, обла­дает дос­таточ­но инте­рес­ными отла­доч­ными воз­можнос­тями, но пока что находит­ся в бета‑ста­дии. К тому же Cutter обла­дает встро­енной под­дер­жкой деком­пилято­ра Ghidra, что дела­ет его очень полез­ным. В нас­тоящее вре­мя Cutter под­держи­вает отладку по GDB-про­токо­лу и име­нован­ным каналам WinDbg. Мне уда­лось под­клю­чить­ся к началь­ной ста­дии заг­рузки ОС.

Подключение к начальной стадии загрузки ОС
Под­клю­чение к началь­ной ста­дии заг­рузки ОС

QEMU

QEMU под­держи­вает вло­жен­ную вир­туали­зацию, но без ядер­ного аксе­лера­тора работа­ет очень мед­ленно. Уско­ряющий модуль KVM, под­держи­вающий вло­жен­ную вир­туали­зацию, дос­тупен на плат­форме Linux. Ради инте­реса рекомен­дую пос­мотреть про­ект Debugging secure kernel. Microsoft WHPX и Intel haxm пока что вло­жен­ную вир­туали­зацию не под­держи­вают.

Ghidra + плагин ret-sync

Ты можешь заг­рузить ском­пилиро­ван­ную вер­сию «Гид­ры» с офи­циаль­ного сай­та, а пла­гин ret-sync — с GitHub. Пла­гин поз­воля­ет син­хро­низи­ровать раз­личные отладчи­ки меж­ду собой. Син­хро­низи­ровать будем с WinDbg (хотя мож­но и с GDB).

Для соз­дания про­екта нуж­но выпол­нить сле­дующие дей­ствия:

  1. За­пус­ти «Гид­ру», исполь­зуя ghidraRun.<wbr />bat.

  2. Им­порти­руй пла­гин ret-sync: File → Install extension, наж­ми зеленый плю­сик. Выбери архив ZIP с пла­гином.

    Импорт плагина ret-sync
    Им­порт пла­гина ret-sync
  3. Наж­ми ОK, переза­пус­ти «Гид­ру».

  4. Вы­пол­ни коман­ды File → New project. Non shared project. Ука­жи имя про­екта и пап­ку, в которой будут хра­нить­ся слу­жеб­ные фай­лы.

  5. За­пус­ти CodeBrowser нажати­ем кноп­ки в панели Tool Chest. Ты уви­дишь сооб­щение об уста­нов­ке пла­гина ret-sync.

    Сообщение об установке плагина ret-sync
    Со­обще­ние об уста­нов­ке пла­гина ret-sync
  6. Наж­ми ОK, появит­ся окно с пус­тым про­ектом. Заг­рузи файл hvix64.<wbr />exe, исполь­зуя File → Import file.

    Загрузка файла
    Заг­рузка фай­ла
  7. Наж­ми OK. Файл будет заг­ружен. Пос­ле того как появит­ся зап­рос на выпол­нение ана­лиза, наж­ми Yes.

    Нажми Yes, юзернейм!
    Наж­ми Yes, юзер­нейм!
  8. Вклю­чи фун­кцию Aggressive Instruction Finder.

    Включение Aggressive Instruction Finder
    Вклю­чение Aggressive Instruction Finder
  9. Наж­ми OK. Прог­ресс опе­рации мож­но уви­деть в пра­вом ниж­нем углу окна.

  10. Да­лее появит­ся сооб­щение о том, что файл hvix64.<wbr />pdb отсутс­тву­ет. Прос­то наж­ми OK.

  11. Наж­ми Alt-S для акти­вации пла­гина ret-sync, и ты уви­дишь сле­дующие сооб­щения.

    Сообщения в консоли
    Со­обще­ния в кон­соли
  12. Под­клю­чи WinDbg к Hyper-V (нап­ример, по сети) и заг­рузи рас­ширение ret-sync:

    .load @”C:hv_debuggingsync.dll
    !sync

Ес­ли все прош­ло успешно, ты уви­дишь сооб­щение в кон­соль­ном окне «Гид­ры».

Сообщение в консольном окне «Гидры»
Со­обще­ние в кон­соль­ном окне «Гид­ры»

Ок­но WinDbg будет отоб­ражать выпол­нение команд.

Выполнение команд в окне WinDbg
Вы­пол­нение команд в окне WinDbg

Для про­вер­ки я пос­тавил точ­ку оста­нова на обра­бот­чик гипер­вызова HvPostMessage (F2) и затем запус­тил отладку (F5). Точ­ка оста­нова сра­бота­ла.

Точка останова сработала
Точ­ка оста­нова сра­бота­ла

Ком­бинации кла­виш ret-sync мож­но най­ти на офи­циаль­ной стра­нице Radare2, опции пла­гина ret-sync для WinDbg отоб­ража­ются в кон­соли по коман­де !synchelp.Ты можешь ско­пиро­вать сим­воль­ную информа­цию из IDA PRO в «Гид­ру» с исполь­зовани­ем пла­гина Fake PDB.

Плагин Fake PDB
Пла­гин Fake PDB

Ин­терес­но, что «Гид­ра» во вре­мя ана­лиза hvix64.<wbr />exe (сбор­ка 10.0.17763.1577) наш­ла 4100 фун­кций, в отли­чие от IDA PRO, которая обна­ружи­ла все­го 3687 фун­кций.

Загрузка гипервизора

Вспо­мога­тель­ные ком­понен­ты заг­рузки гипер­визора со вре­менем менялись:

  • hvboot.<wbr />sys — Windows Server 2008, 2008 R2;
  • hvloader.<wbr />exe или  hvloader.<wbr />efi — Windows Server 2012 R2, 2016;
  • hvloader.<wbr />dll — Windows 10, Windows Server 2019.

От­ладка гипер­визора с помощью WinDbg дос­таточ­но удоб­на, но не всег­да воз­можна — нап­ример, ког­да нуж­но отла­дить secure kernel или сре­ду со вклю­чен­ной опци­ей Secure Boot. Поэто­му мы рас­смот­рим заг­рузку гипер­визора при помощи GDB-отладки.

Для это­го нам нуж­но заг­рузить в IDA PRO сле­дующие фай­лы:

  • winload.<wbr />efi (сбор­ка 10.0.17763.1554);
  • hvloader.<wbr />dll (сбор­ка 10.0.17763.1577);
  • hvix64.<wbr />exe (сбор­ка 10.0.17763.1577).

За­тем надо нас­тро­ить для них опции отладки по GDB-про­токо­лу. Для фай­лов hvix64.<wbr />exe и  hvloader.<wbr />dll сим­волы отсутс­тву­ют. Спер­ва мы дол­жны най­ти адре­са заг­рузки winload.<wbr />efi и  hvloader.<wbr />dll с помощью WinDbg, затем отклю­чить WinDbg, вклю­чить Secure Boot и про­дол­жить отладку уже по про­токо­лу GDB.

Для тес­тирова­ния я исполь­зовал Windows Server 2019 c четырь­мя CPU (для заг­рузки количес­тво про­цес­соров не так важ­но, но, как толь­ко заг­рузит­ся гипер­визор GDB, отладчик будет пос­тоян­но перек­лючать­ся меж­ду кон­тек­стом гипер­визора и ядра Windows). Спер­ва заг­рузим winload.<wbr />efi. IDA PRO не показы­вает некото­рые опции отладки, если бинар­ник име­ет тип Windows boot application. Запус­ти свой любимый PE-редак­тор, выбери Optional header → Subsystem и поменяй Windows boot application на Windows GUI.

Для нас­трой­ки отладки необ­ходимо выб­рать Debugger → Select Debugger → GDB, в поле Process Options ука­зать Hostname 127.<wbr />0.<wbr />0.<wbr />1 и port 8864.

Настройка отладки гипервизора
Нас­трой­ка отладки гипер­визора

В гос­тевой ОС был акти­виро­ван режим bootdebug on, поэто­му пос­ле вклю­чения ОС заг­рузка оста­новит­ся в про­цеду­ре winload!DebugService2.

За­пус­ти WinDbg коман­дой WinDBG.<wbr />exe <wbr />-b <wbr />-k <wbr />net:<wbr />port=50002,<wbr />key=1.<wbr />2.<wbr />3.<wbr />4, и ты получишь адрес заг­рузки:

kd> lm
start end module name
00000000`008c4000 00000000`00aa5000 winload (pdb symbols)

Мо­дуль winload.<wbr />efi уже был открыт в IDA PRO, поэто­му выбери Debugger → attach для под­клю­чения к GDB-сер­веру отладки VMware, запус­ти Edit → Segments → Rebase, ука­жи получен­ный ранее адрес winload.<wbr />efi ( 0x008c4000) и наж­ми OK. Теперь дож­дись завер­шения про­цеду­ры и сох­рани базу. Адрес заг­рузки winload.<wbr />efi не изме­нит­ся пос­ле перезаг­рузки, поэто­му опе­рация rebase не пот­ребу­ется. Затем:

  • пос­тавь точ­ку оста­нова на  winload!OslArchHypervisorSetup и про­дол­жи отладку (F9);
  • про­дол­жи отладку в ранее запущен­ном WinDbg (F5).

Фун­кция winload!OslGetHypervisorLaunchType про­веря­ет, была ли уста­нов­лена опция заг­рузки hypervisorlaunchtype (<wbr />0x250000f0).

Опция загрузки hypervisorlaunchtype
Оп­ция заг­рузки hypervisorlaunchtype
Вызов функции HvlpLoadHvLoader
Вы­зов фун­кции HvlpLoadHvLoader

Ес­ли параметр был задан и его зна­чение рав­но 1 (Auto), фун­кция заг­ружа­ет hvloader.<wbr />dll и получа­ет адре­са сле­дующих фун­кций, экспор­тиру­емых биб­лиоте­кой:

  • HvlRescindVsm
  • HvlLaunchHypervisor
  • HvlLoadHypervisor
  • HvlRegisterRuntimeRange
  • HvlUpdateMcUpdateStatus
  • HvlPreloadHypervisor
Получение адресов функций, экспортируемых hvloader.dll
По­луче­ние адре­сов фун­кций, экспор­тиру­емых hvloader.dll

Да­лее выпол­няет­ся фун­кция winload!HvlpLoadHypervisor. Пос­ле вызова CmpFindSkuType выпол­няет­ся hvloader!HvlLoadHypervisor. Для отладки hvloader.<wbr />dll мы дол­жны перек­лючить­ся меж­ду базами. C этой целью был написан скрипт для IDA PRO PatchHvLoader2019.<wbr />py, который покажет базу заг­рузки hvloader (вер­нее, получит ее нап­рямую из базы winload.<wbr />exe) и про­пат­чит фун­кцию hvloader!HvlLoadHypervisor таким обра­зом, что­бы она зацик­лилась (EB FE — jmp rip).

PatchHvLoader2019.py пропатчил hvloader!HvlLoadHypervisor
PatchHvLoader2019.py про­пат­чил hvloader!HvlLoadHypervisor

Скрипт тре­бует руч­ного опре­деле­ния имен в базе IDA PRO: hvloader_image_base и  p_HvlLoadHypervisor. Перемен­ные рас­положе­ны внут­ри фун­кции winload!HvlpLoadHvLoader, это вид­но на сле­дующей иллюс­тра­ции.

Переменные hvloader_image_base и p_HvlLoadHypervisor
Пе­ремен­ные hvloader_image_base и p_HvlLoadHypervisor

Ад­рес hvloader_image_base нуж­но запом­нить. Отклю­чи текущую GDB-сес­сию и заг­рузи hvloader.<wbr />dll в IDA. Под­клю­чись к GDB-сер­веру. CPU дол­жен быть зацик­лен с помощью инс­трук­ции jmp <wbr />rip. Теперь выпол­ни Edit → segments → rebase и вве­ди най­ден­ный адрес hvloader_image_base. Запус­ти RestoreHvLoader2019.<wbr />py. Мож­но отла­живать hvloader.<wbr />dll. Спер­ва hvloader получа­ет все опции заг­рузки Windows и под­готав­лива­ет hvix64.<wbr />exe к отладке, если она была вклю­чена.

Подготовка hvix64.exe к отладке
Под­готов­ка hvix64.exe к отладке

Те­перь у нас есть адрес заг­рузки winload.<wbr />efi и  hvloader.<wbr />dll. Вык­люча­ем ВМ, вклю­чаем опцию SecureBoot (Option → Advanced → UEFI → Enable secure boot). Добавь строч­ку monitor.<wbr />debugOnStartGuest64 <wbr />= <wbr />"TRUE" в кон­фигура­цион­ный файл ВМ (рас­ширение .<wbr />vmx) и запус­ти ВМ. Открой базу winload.<wbr />efi в IDA PRO, под­клю­чись отладчи­ком к GDB-сер­веру VMware, и ты оста­новишь­ся непос­редс­твен­но на началь­ной про­цеду­ре запус­ка вир­туаль­ной опе­раци­онной сис­темы (где‑то на ран­ней ста­дии заг­рузки BIOS).

Начало загрузки BIOS
На­чало заг­рузки BIOS

Наж­ми F9 и подож­ди, пока сно­ва не про­изой­дет оста­нов­ка в про­цеду­ре winload!OslArchHypervisorSetup. Мож­но про­дол­жать отладку, будут выпол­нять­ся Winload.<wbr />efi!BlSiHandleHypervisorLaunchEvent, затем winload!OslArchHypercallSetup и  winload!VlpSetupPhase0. Далее заг­рузчик выпол­няет ини­циали­зацию дис­ков (вклю­чая VHD, если была нас­тро­ена опция заг­рузка с VHD-дис­ка), ини­циали­зацию UEFI ( winload!BlHSTICallProviders), полити­ки целос­тнос­ти кода ( winload!OslInitializeCodeIntegrity), а так­же про­цеду­ры winload!OslFwProtectSecConfigVars, winload!OslpProcessEVStore.

Пе­рехо­дим к  winload!VlpSetupPhase1. Из этой про­цеду­ры вызыва­ется ранее най­ден­ная фун­кция hvloader!p_HvlRescindVsm. Далее winload!OslExecuteTransition сно­ва вызыва­ет winload!VlpSetupLaunchPhase, а  winload!OslArchHypervisorSetup выпол­няет дру­гой блок кода и на этот раз вызыва­ет hvloader.<wbr />dll!p_HvlLaunchHypervisor. В свою оче­редь, Hvloader.<wbr />dll!HvlLaunchHypervisor выпол­няет bootlib!BlGetExecutionEnvironment, bootlib!OslLoadMicrocodeUpdate и затем переда­ет управле­ние заг­ружен­ному гипер­визору.

Передача управления гипервизору
Пе­реда­ча управле­ния гипер­визору

Пос­ле выпол­нения инс­трук­ции mov <wbr />cr3, <wbr />rcx мы видим, что адре­са памяти выше 0x3000 перес­тают быть дос­тупны.

Адреса памяти выше 0x3000 перестают быть доступны
Ад­реса памяти выше 0x3000 перес­тают быть дос­тупны

Од­нако Hvix64.<wbr />exe уже заг­ружен в 64-бит­ное адресное прос­транс­тво. Для дос­тупа к памяти нуж­но вруч­ную соз­дать в IDA PRO область памяти для отладчи­ка (manual memory region).

Создаем в IDA PRO область памяти для отладчика
Соз­даем в IDA PRO область памяти для отладчи­ка

Вы­деля­емая область памяти име­ет сле­дующие началь­ный и конеч­ный адре­са:

Start address: FFFFFB0000000000
End Address: FFFFFCFFFFFFFFFF

В прин­ципе, если отладчик не выда­ет ошиб­ку, мож­но задать рас­ширен­ный диапа­зон ( 0-0xFFFFFFFFFFFFFFFF). Если текущая инс­трук­ция вый­дет за диапа­зон ука­зан­ных адре­сов, то IDA PRO прос­то завис­нет.

Вы­пол­ни пошаго­вую отладку до инс­трук­ции jmp <wbr />rdx, затем скрипт PatchHvix64_2019.<wbr />py. Зак­рой базу hvloader.<wbr />dll, открой hvix64.<wbr />exe и сно­ва под­клю­чись к GDB-сер­веру. Потом для поис­ка адре­са заг­рузки гипер­визора запус­ти RebaseHVGdb2019.<wbr />py, затем — RestoreHvix64_2019.<wbr />py, который воз­вра­щает назад заменен­ные инс­трук­ции. Мы внут­ри hvix64.exe.

hvix64.exe
hvix64.exe

Пос­ле выпол­нения инс­трук­ции vmlaunch мы вер­немся в  hvloader.<wbr />dll, в точ­ку vm_exit, которая была задана в поле vmcs, и заг­рузка ОС про­дол­жится в обыч­ном режиме.

Возврат из hvloader.dll
Воз­врат из hvloader.dll

Ес­ли нуж­но отла­дить hvix64.<wbr />exe с помощью GDB, сде­лай сле­дующее:

  • за­пус­тить VMware в режиме отладки GDB и выпол­нить оста­нов­ку на началь­ной ста­дии заг­рузки BIOS;
  • от­крыть базу дан­ных с  winload.<wbr />efi, под­клю­чить к GDB и пос­тавить точ­ку оста­нова на инс­трук­ции, которая вызыва­ет hvloader!HvlLaunchHypervisor;
  • на­жать F9;
  • за­пус­тить скрипт 1_PatchHvLoader2019.<wbr />py;
  • зак­рыть базу IDA PRO с  winload.<wbr />efi, открыть базу с  hvloader.<wbr />dll и под­клю­чить­ся к GDB;
  • за­пус­тить 2_RestoreHvLoader2019.<wbr />py;
  • соз­дать точ­ку оста­нова на инс­трук­ции, переда­ющей управле­ние гипер­визору ( jmp <wbr />r8);
  • за­пус­тить 3_PatchHvix64_2019.<wbr />py;
  • зак­рыть базу дан­ных с  hvloader.<wbr />dll, открыть базу дан­ных с  hvix64.<wbr />exe и под­клю­чить­ся к GDB-сер­веру;
  • за­пус­тить скрипт 4_RebaseHVGdb2019.<wbr />py;
  • за­пус­тить скрипт 5_RestoreHvix64_2019.<wbr />py.

Пос­ле это­го мож­но отла­живать hvix64.<wbr />exe (в скрип­те забит стар­товый адрес по сме­щению 0x7a). Сле­дует отме­тить, что про­цесс заг­рузки гипер­визора в Windows Server 2012 (и выше) сущес­твен­но отли­чает­ся от Windows Server 2008 R2, где под­готов­ка и запуск гипер­визора про­изво­дит­ся драй­вером hvboot.<wbr />sys, который запус­кает­ся пос­ле заг­рузки ядра Windows. Акти­вация гипер­визора с помощью инс­трук­ции vmlaunch, выпол­ненная в  hvboot.<wbr />sys, и сле­дующий выход из ВМ обра­баты­вает­ся hvix64.<wbr />exe. Более поз­дние вер­сии исполь­зуют hvloader, который запус­кает­ся непос­редс­твен­но из  winload.<wbr />exe.

Поиск символьной информации

С 2018 года мно­гие ком­понен­ты Hyper-V име­ют обще­дос­тупные сим­волы. На момент пуб­ликации толь­ко hvix64.<wbr />exe, hvax64.<wbr />exe и  hvaa64.<wbr />exe с  hvloader.<wbr />dll не име­ли сим­волов. Пос­ледние модули hvloader.<wbr />exe (.<wbr />efi) и  hvloader.<wbr />dll, име­ющие сим­волы, могут быть заг­ружены для модулей, ском­пилиро­ван­ных до мар­та 2018-го (я исполь­зовал сим­волы hvloader.<wbr />dll из Windows 10, сбор­ка 17115, дата сбор­ки — 03.03.2018).

При заг­рузке hvix64.<wbr />exe в IDA PRO мы получа­ем око­ло четырех тысяч фун­кций с име­нами вро­де sub_FFFFF8000XXXXX. Для уско­рения иссле­дова­ния гипер­визора мож­но сна­чала попытать­ся опре­делить некото­рые фун­кции без под­робно­го изу­чения. В пер­вую оче­редь сто­ит исполь­зовать bindiff (или diaphora) для срав­нения фай­лов hvix64, hvloader и  winload, для которых пре­дос­тавля­ется сим­воль­ная информа­ция. Срав­нение показы­вает, что сетевая фун­кция ( e1000), USB, крип­тогра­фия и некото­рые дру­гие фун­кции в точ­ности такие же, как и в  winload.<wbr />exe (в Windows Server 2019 и Windows 10 фун­кции отладки Hyper-V и сетево­го драй­вера были переме­щены в отдель­ные модули, нап­ример bootlib.<wbr />dll). Тот же самый bindiff поз­воля­ет переме­щать име­на сов­пада­ющих фун­кций из одной базы дан­ных в дру­гую. Одна­ко к это­му методу сто­ит отнестись с осто­рож­ностью и не перено­сить сра­зу все пол­ностью сов­павшие фун­кции. По край­ней мере, про­ана­лизи­руй резуль­тат: срав­ни гра­фы сов­павших фун­кций (Ctrl-E).

Да­лее надо опре­делить фун­кции обра­бот­ки пре­рыва­ний и исклю­чений, стан­дар­тные для про­цес­соров архи­тек­туры x86. Облегчит эту задачу неболь­шой скрипт на Python ( ParseIDT.<wbr />py) для пар­синга IDT. Его необ­ходимо запус­кать в IDA PRO, пред­варитель­но под­клю­чив­шись через отла­доч­ный модуль WinDbg к гипер­визору. Если часть ISR не была най­дена, сле­дует про­верить вклад­ку List of problems в IDA PRO, так как IDA может не най­ти эти про­цеду­ры авто­мати­чес­ки.

Да­лее мож­но опре­делить про­цеду­ру выхода VM <wbr />exit, про­читав зна­чения полей VMCS: изу­чи про­цеду­ру запол­нения VMCS в  hvix64.<wbr />exe или же вос­поль­зуйся скрип­том display-vmcs.<wbr />py, который в кон­тек­сте гипер­визора счи­тыва­ет все поля VMCS и выводит их зна­чения. Есть хорошие скрип­ты IDA-Python от Вех­руза Аббасси (Behrooz Abbassi — @rceninja): ia32_msr_decoder.<wbr />py и  IA32_VMX_Helper.<wbr />py. С их помощью мож­но получить сим­воличес­кие име­на полей MSR и  VMCS внут­ри базы дан­ных IDA.

Хо­рошие новос­ти: здесь при­сутс­тву­ют сим­волы hvix64.<wbr />exe, hvax64.<wbr />exe, hvboot.<wbr />sys для Windows Server 2008. Пло­хая новость зак­люча­ется в том, что Windows Server 2008 уже дав­но не обновля­ется и не вклю­чает в себя мно­гих новых фун­кций Hyper-V. Но ты можешь изу­чить базовый механизм работы Hyper-V и реали­зацию гипер­вызовов в срав­нении с Hyper-V TLFS 1.0.

Очень хороший заголо­воч­ный файл hvgdk.<wbr />h, содер­жащий акту­аль­ную информа­цию о Hyper-V (о струк­турах гипер­визора Windows 10 и Windows Server 2019), соз­дал Алекс Ионес­ку (@aionescu).

Утилиты

В пос­ледние годы было раз­работа­но мно­жес­тво полез­ных сис­темных ути­лит. Я не буду опи­сывать ути­литы Sysinternals, потому что они зна­комы всем, кто занима­ется иссле­дова­нием внут­ренне­го устрой­ства Windows. Еще сущес­тву­ет инте­рес­ный набор ути­лит от Пав­ла Йоси­фови­ча (@zodiacon), который известен как один из авто­ров седь­мого изда­ния пер­вой час­ти кни­ги «Внут­реннее устрой­ство Windows». Они похожи на ути­литы Sysinternals, но пос­тавля­ются с откры­тым исходным кодом.

С помощью ETWProvider мож­но пос­мотреть спи­сок ETW-про­вай­деров, исполь­зуемых ком­понен­тами Hyper-V в работа­ющей сис­теме.

Утилита ETWProvider
Ути­лита ETWProvider

С исполь­зовани­ем ути­литы DrvMon мож­но уви­деть вза­имо­дей­ствие ядер­ных ком­понен­тов и ком­понен­тов, запущен­ных в поль­зователь­ском режиме.

Утилита DrvMon
Ути­лита DrvMon

На­бор ути­лит для диаг­ности­рова­ния от Microsoft так­же может быть исполь­зован для получе­ния допол­нитель­ной информа­ции о работе ком­понен­тов Hyper-V. Не менее полез­ны ути­литы для сбо­ра событий ETW:

  • VMLtrace;
  • Fruti;
  • tss_VMLverbosity.<wbr />ps1;
  • V_Tracing_Using_Channels.<wbr />ps1.
VMLtrace и Fruti
VMLtrace и Fruti
tss_VMLverbosity.ps1 и V_Tracing_Using_Channels.ps1
tss_VMLverbosity.ps1 и V_Tracing_Using_Channels.ps1

Гипервызовы

Пос­ледняя вер­сия докумен­та «Hypervisor Top-Level Functional Specification» для Windows Server 2019 — 6.0b — опи­сыва­ет интерфей­сы Hyper-V и внут­реннее устрой­ство некото­рых ком­понен­тов гипер­визора. Каж­дая вир­туаль­ная машина, а так­же непос­редс­твен­но ОС с уста­нов­ленным ком­понен­том Hyper-V пред­став­ляет­ся в виде раз­дела (partition). У каж­дого раз­дела есть свой иден­тифика­тор, который дол­жен быть уни­каль­ным в рам­ках хост‑сер­вера и име­ет 64-бит­ное зна­чение.

Для каж­дого раз­дела при соз­дании зада­ются при­виле­гии (струк­тура HV_PARTITION_PRIVILEGE_MASK), которые и опре­деля­ют воз­можность выпол­нения кон­крет­ных гипер­вызовов. Узнать при­виле­гии мож­но, выпол­нив в root-partition сле­дующий код в ring0:

WinHvGetPartitionId(&PartID);// id раздела
WinHvGetPartitionProperty(PartID,HvPartitionPropertyPrivilegeFlags,&HvProp); // Свойства раздела возвращаются в HvProp

Здесь HvPartitionPropertyPrivilegeFlags — одно из зна­чений перечис­ления HV_PARTITION_PROPERTY_CODE, которы­ми опе­риру­ют фун­кции, экспор­тиру­емые драй­верами winhvr.<wbr />sys и  winhv.<wbr />sys.

HV_STATUS
WinHvGetPartitionProperty(
__in HV_PARTITION_ID PartitionId,
__in HV_PARTITION_PROPERTY_CODE PropertyCode,
__out PHV_PARTITION_PROPERTY PropertyValue
);

Так­же при необ­ходимос­ти эти при­виле­гии мож­но поменять, выз­вав в root-partition сле­дующую фун­кцию:

HV_STATUS
WinHvSetPartitionProperty(
__in HV_PARTITION_ID PartitionId,
__in HV_PARTITION_PROPERTY_CODE PropertyCode,
__in HV_PARTITION_PROPERTY PropertyValue
);

Зна­чение HvPartitionPropertyPrivilegeFlags для раз­дела Windows Server 2019: 002BB9FF00003FFF.

Зна­чение HvPartitionPropertyPrivilegeFlags для гос­тевого раз­дела: 003B80B000002E7F.

В гос­тевой ОС при­виле­гии мож­но получить, помес­тив в  EAX <wbr />0x40000003 и выпол­нив инс­трук­цию CPUID (в докумен­те Hyper-V TLFS 6.0b дана рас­шифров­ка резуль­татов CPUID).

EAX =00002E7F (101110 01111111) биты 31-0 HV_PARTITION_PRIVILEGE_MASK
EBX =003B8030 (111011 10000000 00110000) биты 63-32 HV_PARTITION_PRIVILEGE_MASK
ECX =00000002 (10) — зарезервировано
EDX =00BED7B2 (10111110 11010111 10110010)
Bit 1: Guest debugging support is available
Bit 4: Support for passing hypercall input parameter block via XMM registers is available
Bit 5: Support for a virtual guest idle state is available
Bit 7: Support for querying NUMA distances is available
Bit 8: Support for determining timer frequencies is available
Bit 9: Support for injecting synthetic machine checks is available.
Bit 10: Support for guest crash MSRs is available
Bit 12: Support for NPIEP is available
Bit 14: ExtendedGvaRangesForFlushVirtualAddressListAvailable
Bit 15: Support for returning hypercall output via XMM registers is available
Bit 17: SintPollingModeAvailable
Bit 18: HypercallMsrLockAvailable
Bit 19: Use direct synthetic timers
Bit 20: Support for PAT register available for VSM
Bit 21: Support for bndcfgs register available for VSM
Bit 23: Support for synthetic time unhalted timer available

В гипер­визоре мож­но получить при­виле­гии раз­дела, который выпол­нил опе­рацию, выз­вавшую VM <wbr />exit, если вычис­лить зна­чение gs:<wbr />0. Для это­го нуж­но про­читать зна­чение поля HOST_GS_BASE <wbr />в <wbr />VMCS <wbr />или <wbr />же <wbr />IA32_GS_BASE <wbr />MSR:

WINDBG>rdmsr 0xc0000101
msr[c0000101] = fffffbdb`a68c2000

За­тем сле­дует получить зна­чение, на которое ука­зыва­ет gs:<wbr />83a8, и перей­ти по сме­щению 0xd8.

WINDBG>dc poi(fffffbdb`a68c2000+0x83a8)+d8
ffffe800`000010d8 00003fff 002bb9ff 00000000 ffffe800 .?.+……...
ffffe800`000010e8 00000000 00000000 00216560 ffffe800 ……..`e!…..
ffffe800`000010f8 00000001 00000000 00000000 00000000 …………….
ffffe800`00001108 002342c0 ffffe800 00000000 00000000 .B#………….

В дан­ном слу­чае VM exit был выпол­нен из root-partition. Гипер­визор в каж­дом из раз­делов фор­миру­ет спе­циаль­ную стра­ницу для выпол­нения гипер­вызовов. Ее адрес мож­но получить, про­читав MSR <wbr />0x40000001 (<wbr />HV_X64_MSR_HYPERCALL).

Windows Server 2019 на Windows Server 2019:

kd> rdmsr 0x40000001
msr[40000001] = 00000000`00767000
kd> up 00000000`00767000 L50
kd> up 00000000`00767000 L50
00000000`00767000 0f01c1 vmcall
00000000`00767003 c3 ret
00000000`00767004 8bc8 mov ecx,eax
00000000`00767006 b811000000 mov eax,11h
00000000`0076700b 0f01c1 vmcall
00000000`0076700e c3 ret
00000000`0076700f 488bc1 mov rax,rcx
00000000`00767012 48c7c111000000 mov rcx,11h
00000000`00767019 0f01c1 vmcall
00000000`0076701c c3 ret
00000000`0076701d 8bc8 mov ecx,eax
00000000`0076701f b812000000 mov eax,12h
00000000`00767024 0f01c1 vmcall
00000000`00767027 c3 ret
00000000`00767028 488bc1 mov rax,rcx
00000000`0076702b 48c7c112000000 mov rcx,12h
00000000`00767032 0f01c1 vmcall
00000000`00767035 c3 ret
00000000`00767036 90 nop
00000000`00767037 90 nop

Что­бы иметь воз­можность исполь­зовать экспор­тиру­емые фун­кции winhv.<wbr />sys и  winhvr.<wbr />sys, мож­но либо динами­чес­ки вычис­лять адре­са фун­кций, либо соз­дать lib-файл. Рас­смот­рим вто­рой вари­ант. Для соз­дания def-фай­ла исполь­зуем вывод коман­ды dumpbin:

dumpbin /exports winhv.sys

Windows Server 2016 и новее исполь­зуют драй­вер winhvr.<wbr />sys для root-раз­дела, таким обра­зом def-файл для драй­вера, пред­назна­чен­ного для работы на хост‑сер­вере, необ­ходимо фор­мировать на осно­ве это­го фай­ла. Для сбор­ки 64-бит­ного драй­вера прав­ки вно­сить не нуж­но. Фор­мирова­ние lib-фай­ла выпол­няет­ся сле­дующей коман­дой (для x86):

lib.exe /def:winhv.def /OUT:winhv.lib /machine:x86

Для x64:

lib.exe /def:winhvr.def /OUT:winhvr.lib /machine:x64

Пе­ред выпол­нени­ем команд не забудь запус­тить Visual Studio native tools. Мы можем най­ти таб­лицу гипер­вызовов в фай­ле hvxi64.exe, ис­поль­зуя спе­циаль­ный скрипт. Скрипт соз­дает таб­лицу наподо­бие показан­ной на иллюс­тра­ции ниже.

Пример таблицы, создаваемой скриптом CreatemVmcallHandlersTable2019.py
При­мер таб­лицы, соз­дава­емой скрип­том CreatemVmcallHandlersTable2019.py

Мы можем отоб­разить зна­чения VMCS полей внут­ри hvix64.exe, ис­поль­зуя скрипт display-vmcs.py. Скрипт необ­ходимо запус­тить в IDA PRO для фай­ла hvix64.<wbr />exe при под­клю­чен­ной отла­доч­ной сес­сии к гипер­визору. Скрипт фор­миру­ет и вызыва­ет про­цеду­ру

vmread rax, rax
jmp 3

Он счи­тыва­ет зна­чение регис­тра rax и отоб­ража­ет его в кон­соли IDA PRO. Для срав­нения вот некото­рые зна­чения VMCS.

Нап­ример, ты можешь уви­деть, что гос­тевой раз­дел гипер­визора обра­баты­вает весь поток информа­ции, про­ходя­щей через пор­ты вво­да‑вывода (I/O exiting Unconditional), а для root-раз­дела выпол­няет­ся перех­ват толь­ко некото­рых пор­тов (исполь­зует­ся I/O bitmaps).

WINDBG><wbr />!db <wbr />0x101001000 <wbr />L1300

#101001000 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />03 <wbr />00 <wbr />00 <wbr />00-00 <wbr />00 <wbr />00 <wbr />00 <wbr />10 <wbr />00 <wbr />00 <wbr />00 ...............<wbr />.
#101001010 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />03 <wbr />00 <wbr />00 <wbr />00-00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 ...............<wbr />.
..<wbr />.
#101001080 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00-20 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 ........ ......<wbr />.
..<wbr />.
#101001190 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00-00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />00 <wbr />f1 ...............<wbr />.

Вывод

В статье было опи­сано соз­дание стен­да для иссле­дова­ния Hyper-V, а так­же очень крат­ко опи­саны некото­рые нюан­сы работы гипер­визора. Наде­юсь, эта информа­ция при­годит­ся начина­ющим иссле­дова­телям безопас­ности гипер­визора ком­пании Microsoft.

Понравилась статья? Поделиться с друзьями:
Добавить комментарий