Journal

Uvnitř HV2: introspekce paměti začíná překladem adres.

HV2 je privátní interposer zaváděný při startu uvnitř existující virtualizační vrstvy. Článek odděluje mechanismus, který ve zděděné implementaci skutečně existuje, od zpevnění, kompatibility a měření, jež ještě zbývají, aniž by zveřejnil detaily potřebné k replikaci.

Interpozice hypervizoruVM exityDvouúrovňový překladKyberbezpečnostní výzkum

HV2 zkoumá, co lze měřit z vrstvy pod hostovaným operačním systémem. Nejde o zveřejnění hotového operačního nástroje. Jde o dokumentaci privátní laboratorní platformy, která využívá existující virtualizační hranici k řízené introspekci paměti a stavu provádění.

Výchozí kód obsahuje fungující mechanismus i zděděné předpoklady. Článek proto záměrně rozlišuje tři kategorie: co je ve zdroji implementované, co je požadované zpevnění a co zatím nemá reprezentativní měření. Nezveřejňujeme zdrojový kód, instrukční sekvence, bajtové signatury, posuny struktur, interní detaily konkrétních sestavení, instalační cesty ani postupy k obcházení ochran.

Nástroj uvnitř OS pozoruje systém, kterému zároveň musí věřit.

Nástroje v uživatelském režimu omezují hranice procesů a kontroly oprávnění. Nástroje v režimu jádra vidí podstatně víc, pořád ale sdílejí model důvěry, pravidla aktualizací a prostor kompromitace stejného operačního systému. HV2 posouvá pozorovací bod pod tuto vrstvu.

Pozice výzkumuCo typicky vidíHlavní omezení
Uživatelský režimVeřejná API, procesově dostupnou paměť a stav viditelný debuggeru.Handly, kontroly oprávnění, anti-debug logika a manipulace v uživatelském režimu.
Režim jádraStruktury OS, tabulky stránek a paměť dostupnou ovladači.Stále leží uvnitř stejné hranice důvěry a může podléhat skrývání na úrovni jádra.
Virtualizační vrstvaStav hosta, vnořený překlad, fyzické podložení paměti a kontext VM exitu.Složitější start, ladění, validace a kompatibilita mezi verzemi.

HV2 je úzký interposer, ne náhradní hypervizor.

Návrh stojí na zachování běžného chování platformy. HV2 rozpoznává jen úzkou řídicí cestu; nesouvisející VM exity předává původní obsluze. Privátní značka slouží ke směrování a omezuje náhodné zachycení. Neprokazuje ale identitu ani oprávnění volajícího. Současný model důvěry proto počítá s jediným vlastníkem v řízené laboratoři.

Tohle rozlišení je důležité i obecně. Rozpoznat formát zprávy není totéž jako autorizovat jejího autora. Zpevnění protokolu musí později přidat verzi, délku rámce, maximální velikost přenosu, kontrolovanou aritmetiku, politiku oprávnění a ověření, že je celý rámec skutečně namapovaný.

VM exit je hardwarově definované předání řízení.

Procesor při relevantní události čistě předá řízení z provádění hosta do virtualizační vrstvy. HV2 tento přechod používá jako kontrolovaný přenos příkazů. V kontextu hypervizoru může číst stav hosta a metadata překladu, ke kterým uživatelský režim nemá autoritativní přístup.

Každý zachycený exit projde třemi kroky. Nejprve se klasifikuje, zda vůbec patří do cesty HV2. Potom backend načte právě ten stav, který operace potřebuje: ukazatel instrukce hosta, kořen adresního prostoru, kontext registrů, metadata exitu a kořen vnořeného překladu. Nakonec se zapíše stavový kód, posune provádění hosta a obnoví běh bez narušení nesouvisejícího stavu.

# Cílový control flow, nikoli privátní implementace.
function on_vmexit(raw_context):
  exit = backend.read_exit(raw_context)

  if not is_recognized_command(exit, raw_context):
    return original_handler(raw_context)

  frame = backend.read_command_frame(raw_context)
  status = validate_authorize_dispatch(frame)

  backend.write_return(raw_context, status)
  backend.advance_guest_ip(raw_context)
  return resume_guest

Čtení paměti je dvoustupňový problém překladu adres.

Slovní spojení „přečíst paměť“ skrývá většinu práce. Virtuální adresa hosta se nejprve přeloží přes jeho tabulky stránek na fyzickou adresu hosta. Ta se potom přeloží přes druhou úroveň na skutečné fyzické podložení. Až potom může vzniknout dočasné mapování dostupné hypervizoru.

Korektní výsledek musí zachovat, ve které fázi překlad selhal. Nulová adresa sama neřekne, zda chyběl záznam PTE hosta, položka vnořeného překladu, mapování konkrétního procesoru nebo zda byl neplatný vstup. Pro forenzní použití je původ překladu součástí dat, ne detail pouze pro ladění.

FázeVstupVýstup nebo chyba
Průchod tabulkami hostaKořen adresního prostoru + virtuální adresaFyzická adresa hosta, velikost stránky, oprávnění nebo přesná chybějící úroveň.
Vnořený průchodVnořený kořen + fyzická adresa hostaSkutečné fyzické podložení nebo chyba druhé úrovně.
Dočasné mapováníFyzická stránka + slot procesoruKrátkodobé virtuální mapování pro přesně omezenou operaci.

Zděděné rozhraní má šest operací; rozhoduje jejich kontrakt.

Názvy níže jsou bezpečné publikační štítky, ne identifikátory ze zdrojového kódu. Malý inventář se audituje snáz, ale samotný počet privilegované rozhraní nezabezpečí.

Publikační názevVýznamNejdůležitější invariant
INIT_MAPPřipraví dočasný stav mapování na aktuálním procesoru.Inicializace musí proběhnout na každém podporovaném logickém procesoru.
QUERY_ROOTVrátí kořen aktuálního adresního prostoru hosta.Výsledek musí nést kontext, ke kterému patří.
TRANSLATE_VAProvede průchod virtuálními tabulkami stránek hosta.Rozlišit standardní a velké stránky i přesnou chybu úrovně.
READ_GPAČte fyzický rozsah hosta po vnořeném překladu.Omezená délka, oprávnění a dělení bezpečné vůči hranicím stránek.
WRITE_GPAZapisuje do fyzického podložení paměti hosta.Explicitní oprávnění a chybová cesta, která při nejistotě odmítne operaci.
COPY_VAKopíruje mezi dvěma explicitními kořeny adresních prostorů.Kontrolovaná aritmetika a hranice na obou stranách.

Podstatné jsou invarianty, ne privátní instrukce.

Kompaktní rámec pořád potřebuje obálku.

Zděděná unie příkazů je malá, ale současná cesta důvěřuje vstupu volajícího více, než by mělo zpevněné rozhraní. Verze, délka celého rámce, maximální přenos, kontrolovaná aritmetika rozsahů a ověření všech hranic patří před zpracování příkazu.

# Cílový kontrakt, ne privátní source code.
struct CommandFrame {
  version: ProtocolVersion
  frame_bytes: BoundedLength
  operation: Operation
  rights: CapabilityMask
  source: AddressDescriptor
  destination: AddressDescriptor
  transfer_bytes: BoundedLength
  status: HV2Status
}

validate(frame):
  require complete_frame_is_mapped(frame)
  require supported(frame.version, frame.operation)
  require frame.transfer_bytes <= policy.max_transfer
  require checked_address_ranges(frame)
  require authorize(frame.rights, frame.operation)

Obsluha VM exitu musí být konzervativní.

Interposer obslouží pouze exit, který umí jednoznačně klasifikovat a ověřit. Současný kód správně posílá nesouvisející exity původní cestou. Zpevněná verze musí navíc oddělit rozpoznání příkazu od autorizace a vracet explicitní stav pro neznámou operaci.

Mapování vázané na procesor vyžaduje inicializaci celé topologie.

Klientská knihovna připíná jedno vlákno postupně na všechny skupiny procesorů, aby každý logický procesor získal vlastní dočasné položky mapování. Audit odhalil dvě konkrétní potřeby: afinitu je nutné obnovit na každé chybové cestě a výběr mapovacího slotu ověřit proti moderním identifikátorům topologie.

function initialize_all_processors():
  original_affinity = current_thread_affinity()

  try:
    for cpu in enumerated_logical_processors():
      require pin_current_thread(cpu)
      require mapping_slot_is_valid(cpu)
      require hv2_call(INIT_MAP) == OK
    return OK
  finally:
    restore_affinity(original_affinity)

Překlad virtuální adresy hosta je průchod tabulkami, ne vyhledání v mapě.

Zděděný průchod obsahuje větve pro standardní i velké stránky. Cílový kontrakt navíc musí kontrolovat kanoničnost adresy, příznak přítomnosti, rezervované bity, požadovaná oprávnění a fyzickou šířku použitou při skládání výsledku.

function translate_guest_virtual(root, va):
  require canonical(va)
  idx = split_virtual_address(va)

  pml4e = read_entry(root, idx.pml4)
  if not pml4e.present: return PML4E_NOT_PRESENT

  pdpte = read_entry(pml4e.page, idx.pdpt)
  if not pdpte.present: return PDPTE_NOT_PRESENT
  if pdpte.large and entry_is_valid(pdpte):
    return pdpte.base + idx.offset_1g

  pde = read_entry(pdpte.page, idx.pd)
  if not pde.present: return PDE_NOT_PRESENT
  if pde.large and entry_is_valid(pde):
    return pde.base + idx.offset_2m

  pte = read_entry(pde.page, idx.pt)
  if not pte.present: return PTE_NOT_PRESENT
  require entry_is_valid_for_access(pte)
  return GPA(pte.base + idx.offset_4k)

Fyzická adresa hosta stále potřebuje vnořený překlad.

Fyzická adresa hosta není konečná adresa v paměti stroje. Každá vnořená úroveň potřebuje stejnou disciplínu pro přítomnost položky, velké stránky, fyzickou šířku a oprávnění jako průchod tabulkami hosta. Až výsledná fyzická stránka stroje se vloží do mapovacího slotu příslušného procesoru a místní překladová cache se zneplatní.

Kopírovací smyčka musí respektovat hranice obou stran.

Reálný rozsah přechází přes hranice stránek. Implementace správně omezuje každou iteraci podle zbývajících bajtů ve zdrojové i cílové stránce. To ale samo neomezuje celkovou délku požadavku. Maximální velikost přenosu a kontrola přetečení patří do vstupního kontraktu ještě před smyčku.

function copy_guest_range(src_root, src_va, dst_root, dst_va, size):
  require size <= policy.max_transfer
  require ranges_do_not_overflow(src_va, dst_va, size)

  while size > 0:
    src = translate_and_map(src_root, src_va, READ)
    dst = translate_and_map(dst_root, dst_va, WRITE)

    chunk = min(
      bytes_left_in_page(src_va),
      bytes_left_in_page(dst_va),
      size
    )

    copy_bytes(dst, src, chunk)
    src_va += chunk
    dst_va += chunk
    size -= chunk

  return OK

Shoda backendů musí být testovaným kontraktem.

HV2 obsahuje dvě zděděné větve pro dvě zásadně odlišné rodiny virtualizace x64. Označujeme je [Architecture-A] a [Architecture-B]. Zamýšlená sémantika příkazů je společná, ale část zpracování a paměťové logiky je duplicitní. Oprava v jedné větvi se proto nemusí objevit ve druhé. Bezprostředním řešením je společná sada sémantických testů; dlouhodobým společná implementační vrstva.

Taxonomie chyb má cenu jen při úplném předávání výsledku.

Zděděný kód definuje detailní stavové kódy, některé překladové cesty ale stále zredukují chybu na nulovou adresu nebo vrátí úspěch kolem neplatného výsledku. Výzkumné rozhraní potřebuje typovaný výsledek a stejné předávání chyb na obou backendech.

Proč je HV2 užitečné pro kyberbezpečnostní výzkum.

Mnoho moderních útoků manipuluje s tím, co operační systém dokáže pravdivě vykázat. Nezávislý pozorovací bod proto sám o sobě není detekcí, ale představuje cennou kontrolní rovinu. Použití zůstává omezené na autorizovanou laboratoř.

Diferenciální forenzní analýza paměti.

Stejná deklarovaná oblast se načte kolektorem uvnitř hosta a přes HV2. Každý výsledek nese původ adresního prostoru i překladu. Rozdíly mohou odhalit skrývání, odpojené objekty, zastaralé struktury nebo chybu akvizice; experiment nesmí automaticky prohlásit každý rozdíl za malware.

Validace ochrany koncových bodů.

Izolovaný host dostane předem definovanou a autorizovanou změnu paměti. Výzkumník zaznamená změnu viditelnou z nižší vrstvy i telemetrii obranného nástroje. Výsledkem je hranice pokrytí, ne tvrzení, že jedna zmeškaná událost poráží celý produkt.

Rootkit a malware analýza.

V kontrolních bodech se porovnají objekty vykázané hostem, dosažitelnost přes tabulky stránek a fyzické pozůstatky. HV2 poskytuje nezávislou cestu akvizice; interpretace chování pořád patří analytickému postupu.

Experimenty s exploity jádra.

Během autorizovaného výzkumu lze zachytit mapování, cílové oblasti a stav v okolí pádu před událostí i po ní. Analýza výsledného stavu potom méně závisí na hostu, který už může být nestabilní.

Interakce s bezpečnostními politikami virtualizace.

Kontrolovaná matice politik při startu, integrity paměti a izolačních režimů ukáže aktivaci, viditelnost a časování. Cílem je mapa kompatibility a hranic důvěry, nikoli návod k obejití ochrany.

Co audit zdrojového kódu skutečně prokázal.

OblastZjištěníStav tvrzení
InterpoziceNesouvisející exity se předávají původní obsluze.Implementované ve zděděné cestě.
PřekladExistuje průchod tabulkami hosta i vnořený průchod včetně velkých stránek.Implementované; negativní testy a testy oprávnění chybějí.
Stav procesoruKlient inicializuje mapování po logických procesorech.Implementované; obnova po časném selhání a předpoklady o topologii potřebují zpevnění.
Kopírování přes hranice stránekIterace se dělí podle zdrojové a cílové stránky.Implementované; celkový limit požadavku je samostatný požadavek.
BackendyExistují dvě rodiny x64 se společným záměrem.Implementované, ale shoda není doložena společnými testy.
VýkonRepozitář neobsahuje reprezentativní běh benchmarku.Žádná tvrzení o latenci, propustnosti ani stabilitě.

Pět lekcí z HV2 platí pro každé privilegované rozhraní.

1. Výchozím chováním interposeru je předání původní cestě.

Vrstva má obsloužit jen provoz, který umí klasifikovat a ověřit. Neznámý exit, operace, verze nebo stav potřebuje explicitní cestu, nikdy náhodný průchod další větví.

2. Výsledek překladu potřebuje dohledatelný původ.

Konečná adresa nestačí. Ukládejte kořen hosta, velikost stránky, generaci vnořeného kořene, oprávnění a fázi chyby, aby šlo odlišit pozorovaná data od chyby akvizice.

3. Hranice stránky je součást kontraktu API.

Mapovat jednu stránku a kopírovat libovolný rozsah jsou dvě různé operace. Úplnost rámce, kontrolovaná aritmetika, dělení po stránkách a celkový limit řeší různé třídy selhání.

4. Stav vázaný na procesor mění topologii v podmínku korektnosti.

Inicializace, obnova afinity, šířka identifikátoru, skupiny procesorů a migrace vláken potřebují testy na strojích, které platforma tvrdí, že podporuje.

5. Oddělujte implementované, plánované a změřené.

Zdrojový kód může prokázat existenci cesty. Nemůže prokázat aktuální kompatibilitu, přijatelnou latenci nejpomalejších případů ani dlouhodobou stabilitu. K tomu jsou potřeba reprodukovatelné výsledky testů.

HV2 se musí testovat jako platforma, ne ukázat jako jeden trik.

Repozitář definuje směr validace, nikoli hotovou sadu důkazů. Důvěryhodný program vede od offline analýzy kompatibility přes ověření startovacího řetězce a korektnosti příkazů až k nepříznivým případům překladu, zátěžovým testům a interakci s bezpečnostními funkcemi.

  • Negativní testy rámce: zkrácení, neznámá verze, neplatná operace, přetečení a překročení limitu přenosu.
  • Testy topologie: skupiny procesorů, maximální identifikátor, migrace, časné selhání a obnova afinity.
  • Testy obou průchodů tabulkami: chybějící úrovně, velké stránky, rezervované bity, oprávnění a hraniční fyzické šířky.
  • Testy rozsahů: hranice zdrojové a cílové stránky, přetečení adresy a částečné selhání.
  • Shoda backendů: stejný korpus požadavků, stavů a vynucených chyb na obou architekturách.
  • Benchmarky: rozdělení latence, propustnost, spolehlivost startu a dlouhodobá zátěž, ne jedno nejlepší číslo.

Tento článek dokumentuje výzkum, ne nasazení.

Nízkoúrovňový výzkum hypervizoru má přirozeně dvojí využití. Text proto poskytuje expertům architekturu, invarianty, auditní zjištění a obranné experimenty, ale ne cestu k replikaci. Vynecháváme přesné signatury, posuny, konstanty, obnovu stavu backendu, spouštěcí sekvence, cílová sestavení a instalační postup.

Další milník je menší křehkost a skutečné měření.

Zděděná implementace dokládá mechanismus a odkryla své předpoklady. Sama o sobě neprokazuje kompatibilitu se současnými verzemi ani připravenost k produkčnímu provozu. Další fáze se soustředí na zjišťování prostředí za běhu, zpevnění protokolu, společné testy backendů, bezpečnější práci s kompatibilitou a měřicí instrumentaci.

Výzkumná hodnota HV2 není v tom, že umí přesunout bajty. Je v tom, že nutí přesně pojmenovat, odkud adresa pochází, na kterém procesoru mapování existuje, která fáze překladu selhala a co systém skutečně změřil. Právě tato disciplína odděluje platformu od dema, které náhodou fungovalo na jedné snadné adrese.

Zpět do JournaluVýzkum, systémy a technické poznámky.

Řešíte nízkoúrovňový výzkum?

Rádi se podíváme na problém, hranice i bezpečný způsob ověření.

Kontaktovat Gloryck