<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Keishin Senzaki</title>
    <description>The latest articles on DEV Community by Keishin Senzaki (@reordo).</description>
    <link>https://dev.to/reordo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4158812%2F38390f13-8b62-4e9f-ac27-269e783ceb05.png</url>
      <title>DEV Community: Keishin Senzaki</title>
      <link>https://dev.to/reordo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/reordo"/>
    <language>en</language>
    <item>
      <title>Booting a VeraCrypt-encrypted Windows VHD through Ventoy</title>
      <dc:creator>Keishin Senzaki</dc:creator>
      <pubDate>Sat, 03 Oct 2026 04:47:53 +0000</pubDate>
      <link>https://dev.to/reordo/booting-a-veracrypt-encrypted-windows-vhd-through-ventoy-317e</link>
      <guid>https://dev.to/reordo/booting-a-veracrypt-encrypted-windows-vhd-through-ventoy-317e</guid>
      <description>&lt;p&gt;I often use Ventoy as a multiboot USB drive: installer ISOs, live systems, recovery tools. Discovering its Windows VHD boot plugin suggested another use for it. Instead of giving every Windows installation its own set of partitions, I could put one in a VHD file, set it up in VirtualBox while another OS was running, and later boot that same installation directly on physical hardware through Ventoy. Replacing a system could then mean preparing a new file instead of repartitioning the drive.&lt;/p&gt;

&lt;p&gt;I also encrypt the systems and data I use with VeraCrypt. I wanted the flexibility of a VHD file and direct hardware boot without giving up system encryption. My first attempt was to boot an ordinary Windows VHD through Ventoy and turn on VeraCrypt system encryption there. The encryption wizard failed in that native-VHD setup. I then encrypted the Windows installation inside its UEFI VirtualBox VM. It booted in the VM, but Ventoy's VHD boot path could no longer start it.&lt;/p&gt;

&lt;p&gt;That led me to build &lt;a href="https://github.com/reordo/EncryptedVhdBoot" rel="noopener noreferrer"&gt;EncryptedVhdBoot&lt;/a&gt;, an experimental x64 UEFI bridge. It authenticates the encrypted volume, decrypts the VHD reads needed before Windows starts, and passes VeraCrypt's standard boot state to &lt;code&gt;veracrypt.sys&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The bridge hooks VHD parser callbacks in &lt;strong&gt;two&lt;/strong&gt; Windows boot applications, with a third hook at the point where Boot Manager starts Winload. The VHD and Microsoft's boot files stay unchanged on disk. Below is how those hooks fit into the boot path.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqhhs8xhht2t3fpyjzwdr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqhhs8xhht2t3fpyjzwdr.png" alt="EncryptedVhdBoot password prompt with masked input during a physical x64 UEFI boot" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The visible password prompt during a physical x64 UEFI boot. The entered characters are masked.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the normal boot paths do not meet
&lt;/h2&gt;

&lt;p&gt;Ventoy's Windows VHD boot image starts a Microsoft Boot Manager that knows how to open VHD files. For an unencrypted Windows VHD, Boot Manager reads the virtual disk, launches &lt;code&gt;winload.efi&lt;/code&gt;, and Windows continues.&lt;/p&gt;

&lt;p&gt;An encrypted VHD creates two separate obstacles. In the tested configuration, VeraCrypt 1.26.29 reports an error when &lt;strong&gt;System &amp;gt; Encrypt System Partition/Drive&lt;/strong&gt; is opened from Windows already running by native VHD boot, so the system has to be encrypted inside the VM. Once it is encrypted, Ventoy can still open the VHD file, but Boot Manager and Winload receive ciphertext from their VHD parsers before the Windows VeraCrypt driver can take over.&lt;/p&gt;

&lt;p&gt;Here is the path the bridge creates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ventoy selects a Windows VHD
  -&amp;gt; EncryptedVhdBoot UEFI application
     -&amp;gt; original Windows Boot Manager
        -&amp;gt; VHD1 read callback: read ciphertext, return plaintext
        -&amp;gt; launch winload.efi
           -&amp;gt; its own VHD1 read callback: return plaintext
           -&amp;gt; Windows kernel and boot-start drivers
              -&amp;gt; veracrypt.sys takes over encrypted disk I/O
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The word &lt;em&gt;own&lt;/em&gt; matters: patching Boot Manager's VHD reader alone is insufficient. &lt;code&gt;winload.efi&lt;/code&gt; has a separate VHD1 parser and continues reading the disk after Boot Manager launches it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intercepting virtual-disk reads
&lt;/h2&gt;

&lt;p&gt;The supported Ventoy input is the official &lt;strong&gt;Win10Based v3.0&lt;/strong&gt; &lt;code&gt;ventoy_vhdboot.img&lt;/code&gt;. Its UEFI boot image contains a specific 64-bit Windows Boot Manager build, version &lt;code&gt;10.0.10240.16384&lt;/code&gt;. Microsoft public symbols and the PE layout let me identify its &lt;code&gt;Vhd1Parser&lt;/code&gt; table. The bridge loads the original Boot Manager, locates the table at RVA &lt;code&gt;0x2CF8&lt;/code&gt;, validates all four original table entries (&lt;code&gt;Open&lt;/code&gt;, &lt;code&gt;Close&lt;/code&gt;, &lt;code&gt;Read&lt;/code&gt;, and &lt;code&gt;Write&lt;/code&gt;) against that build, then replaces the relocated read and write pointers in RAM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;mOriginalVhdRead&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_IO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;mVhd1Parser&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_READ_INDEX&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;mOriginalVhdWrite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_IO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;mVhd1Parser&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_WRITE_INDEX&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="n"&gt;mVhd1Parser&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_READ_INDEX&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UINTN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;EvbVhdReadPassThrough&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;mVhd1Parser&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_WRITE_INDEX&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UINTN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;EvbVhdWritePassThrough&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;MemoryFence&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are the actual callback assignments in &lt;a href="https://github.com/reordo/EncryptedVhdBoot/blob/main/EvbPkg/Application/EvbPreloader/EvbPreloader.c" rel="noopener noreferrer"&gt;EvbPreloader.c&lt;/a&gt;. The original callbacks remain available to the bridge; no VHD routine is copied or permanently rewritten.&lt;/p&gt;

&lt;p&gt;Why work at this level? The VHD parser has already translated file layout into offsets on the &lt;em&gt;virtual disk&lt;/em&gt;. A fixed VHD and a dynamic VHD store their bytes differently in the host file, but the parser presents the same disk-offset view to its callers. That gives the decryption code a useful boundary: it can reason about VeraCrypt sectors without reimplementing Ventoy's VHD file handling.&lt;/p&gt;

&lt;p&gt;The Boot Manager wrapper first calls the saved original &lt;code&gt;VhdRead&lt;/code&gt;. On its first successful read it authenticates the VeraCrypt header, or takes the plain-VHD path if the password is empty. For an encrypted read, &lt;a href="https://github.com/reordo/EncryptedVhdBoot/blob/main/EvbPkg/Application/EvbPreloader/EvbVeraCrypt.c" rel="noopener noreferrer"&gt;EvbVeraCryptDecryptRead&lt;/a&gt; limits the transformation to the encrypted region:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;IntersectStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ByteOffset&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mEncryptedStart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;ByteOffset&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mEncryptedStart&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;IntersectEnd&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ReadEnd&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;mEncryptedEnd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;ReadEnd&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mEncryptedEnd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IntersectStart&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;IntersectEnd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;EFI_SUCCESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An aligned interior can be decrypted in place, using the virtual-disk sector number as the XTS data-unit number. For an unaligned edge, the code rereads the whole sector through the original callback, decrypts it in a scratch buffer, and copies back only the requested span. This preserves bytes outside the encrypted area. Early writes to an encrypted VHD are rejected as write-protected. The bridge does not attempt to implement encrypted writes during the pre-kernel phase. With an empty password, it leaves the ordinary unencrypted-VHD read and write behavior in place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding the second parser
&lt;/h2&gt;

&lt;p&gt;Boot Manager's parser is tied to one validated binary profile. For &lt;code&gt;winload.efi&lt;/code&gt;, a version-only allowlist would be brittle: Windows 10 and 11 ship many builds, and the VHD parser's address moves.&lt;/p&gt;

&lt;p&gt;Instead, the bridge patches Boot Manager's &lt;code&gt;ImgArchEfiStartBootApplication&lt;/code&gt; entry point at RVA &lt;code&gt;0x6B468&lt;/code&gt; after validating its expected 15-byte prologue. The patch redirects control to &lt;code&gt;EvbStartBootApplication&lt;/code&gt;. A trampoline preserves the overwritten instructions and lets that wrapper call the original function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;CopyMem&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;Trampoline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;mBootApplicationHookOriginal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;EVB_BOOT_APP_HOOK_SIZE&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;EvbWriteAbsoluteJump&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;Trampoline&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;EVB_BOOT_APP_HOOK_SIZE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UINTN&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;mBootApplicationHookTarget&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;EVB_BOOT_APP_HOOK_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;EvbWriteAbsoluteJump&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;mBootApplicationHookTarget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UINTN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;EvbStartBootApplication&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The jump uses an indirect RIP-relative x64 encoding that preserves registers. This boundary is reached after Boot Manager has loaded and authenticated the child boot application, but before it starts running.&lt;/p&gt;

&lt;p&gt;At that point, the bridge scans the loaded Winload PE image for a VHD1 parser table. The scanner considers initialized, readable, non-executable sections. Its decisive checks include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;Candidate&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_WRITE_INDEX&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt;
     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Candidate&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_READ_INDEX&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;EVB_VHD_WRAPPER_SIZE&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;EvbMatchesVhdWrapperPair&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Candidate&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_READ_INDEX&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;EvbRangeInSection&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Candidate&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_OPEN_INDEX&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;EvbRangeInSection&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Candidate&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_CLOSE_INDEX&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Match&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;Match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Candidate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The read and write wrappers must have the validated instruction shapes and sit 48 bytes apart; the &lt;code&gt;Open&lt;/code&gt; and &lt;code&gt;Close&lt;/code&gt; targets must be executable. A second candidate makes the result ambiguous, so the scan returns no match.&lt;/p&gt;

&lt;p&gt;Only after finding that unique table does the bridge replace Winload's own callbacks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;mOriginalWinloadVhdRead&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_IO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_READ_INDEX&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;mOriginalWinloadVhdWrite&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_IO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_WRITE_INDEX&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_READ_INDEX&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UINTN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;EvbWinloadVhdRead&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EVB_VHD_WRITE_INDEX&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UINTN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;EvbWinloadVhdWrite&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;MemoryFence&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Winload read wrapper calls its original callback and decrypts the returned sectors. If the encrypted path is active and a suitable parser cannot be identified unambiguously, the child launch is aborted. The bridge does not guess an address or let Winload continue reading ciphertext.&lt;/p&gt;

&lt;p&gt;This is still a compatibility technique, not a promise that every future Windows build will match. The project records the tested versions and the structural checks in its &lt;a href="https://github.com/reordo/EncryptedVhdBoot/blob/main/docs/architecture.md" rel="noopener noreferrer"&gt;architecture notes&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  From password to Windows driver
&lt;/h2&gt;

&lt;p&gt;On the first Boot Manager VHD read, the bridge can use the saved original callback to read the virtual disk's MBR and VeraCrypt system header. It asks for a password and an optional system PIM, then uses VeraCrypt-compatible header and crypto code to authenticate the volume. After header authentication, it checks that decrypting the first encrypted sector produces the expected NTFS signature before allowing the boot to proceed.&lt;/p&gt;

&lt;p&gt;The bridge also prepares VeraCrypt's standard &lt;code&gt;BootArguments&lt;/code&gt; and &lt;code&gt;BOOT_CRYPTO_HEADER&lt;/code&gt; handoff. The relevant part of &lt;a href="https://github.com/reordo/EncryptedVhdBoot/blob/main/EvbPkg/Application/EvbPreloader/EvbVeraCrypt.c" rel="noopener noreferrer"&gt;EvbPrepareBootParams&lt;/a&gt; shows what goes into that handoff:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;CryptoInfoOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UINT16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;OFFSET_OF&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EVB_BOOT_PARAMS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BootCryptoInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;CopyMem&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;BootPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;VcPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;BootPassword&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Flags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UINT32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;Pim&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;CopyMem&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;BootDriveSignature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="n"&gt;Mbr&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;EVB_MBR_SIGNATURE_OFFSET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="k"&gt;sizeof&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;BootDriveSignature&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PIM uses the upper 16 bits of &lt;code&gt;BootArguments.Flags&lt;/code&gt;, matching VeraCrypt-DCS and the Windows driver. The full handoff includes lengths, CRCs, and crypto-header fields; the excerpt highlights the password, disk signature, and PIM. The boot-start &lt;code&gt;veracrypt.sys&lt;/code&gt; driver receives the state it needs when firmware services are gone.&lt;/p&gt;

&lt;p&gt;At &lt;code&gt;ExitBootServices&lt;/code&gt;, the bridge wipes its private expanded-key workspace and partial-sector buffer. It retains the handoff block needed by &lt;code&gt;veracrypt.sys&lt;/code&gt;; the driver later validates, consumes, and burns that block. Once Windows is running, normal encrypted-disk operation belongs to the VeraCrypt driver, not the UEFI bridge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building and using the image
&lt;/h2&gt;

&lt;p&gt;The project builds a replacement &lt;code&gt;ventoy_vhdboot.img&lt;/code&gt; from the verified upstream Win10Based v3.0 image. The original Boot Manager remains in the image; the new UEFI entry point loads it, installs the in-memory hooks, and starts it. The builder also preserves an easy-to-miss detail of the original ISO: its BIOS and UEFI BCD paths share one physical extent. Ventoy patches one path in memory, and the UEFI path must see the same bytes. Making independent BCD copies breaks boot.&lt;/p&gt;

&lt;p&gt;For an encrypted system disk, the tested preparation path is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Windows in an x64 UEFI VirtualBox machine whose system disk is a fixed or dynamic VHD1.&lt;/li&gt;
&lt;li&gt;Complete VeraCrypt system encryption and its pretest &lt;strong&gt;inside the VM&lt;/strong&gt;. On Windows 11, fully remove BitLocker or device encryption first.&lt;/li&gt;
&lt;li&gt;Shut down the VM, keep a recoverable copy of the VHD, and put the VHD on the Ventoy data partition.&lt;/li&gt;
&lt;li&gt;Install the derived vhdboot image and select the VHD from Ventoy in x64 UEFI mode.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For Windows 11, open an elevated Command Prompt inside the VM before enabling VeraCrypt system encryption:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;manage-bde -off C:
manage-bde -status C:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait until &lt;code&gt;manage-bde -status&lt;/code&gt; shows &lt;strong&gt;Conversion Status: Fully Decrypted&lt;/strong&gt; and &lt;strong&gt;Percentage Encrypted: 0.0%&lt;/strong&gt;. &lt;code&gt;Protection Status: Protection Off&lt;/code&gt; alone does not mean decryption has finished.&lt;/p&gt;

&lt;p&gt;The repository's &lt;a href="https://github.com/reordo/EncryptedVhdBoot#readme" rel="noopener noreferrer"&gt;README&lt;/a&gt; has the exact build, install, restore, and preparation commands. An empty password takes the original unencrypted-VHD path, so the same image can still boot ordinary VHDs.&lt;/p&gt;

&lt;p&gt;There is also an optional &lt;code&gt;/ventoy/ventoy_vhdboot.silent&lt;/code&gt; marker file. When it is present beside &lt;code&gt;ventoy_vhdboot.img&lt;/code&gt;, the bridge clears its screen and accepts password and PIM input without showing its own prompts, characters, masking symbols, or status text. This affects only output from the bridge; Ventoy, firmware, and Windows can still display their own interfaces. It is a display option, not a claim of stronger encryption.&lt;/p&gt;

&lt;h2&gt;
  
  
  What has been tested, and what has not
&lt;/h2&gt;

&lt;p&gt;End-to-end boot and driver handoff have been tested with VeraCrypt 1.26.29 on Windows 10 LTSC 2019, 1909, 21H2, and 22H2, and Windows 11 25H2. The tests include fixed and dynamic VHD1 files, default and custom PIM values, and several cipher and PRF combinations. The &lt;a href="https://github.com/reordo/EncryptedVhdBoot#compatibility" rel="noopener noreferrer"&gt;compatibility matrix&lt;/a&gt; gives the exact Winload versions and results.&lt;/p&gt;

&lt;p&gt;The current release requires x64 UEFI with &lt;strong&gt;Secure Boot disabled&lt;/strong&gt; and the specified Ventoy vhdboot image. VHDX, differencing VHDs, Legacy BIOS, arbitrary Boot Manager builds, hidden systems, and rescue workflows are outside the supported scope. The project has &lt;strong&gt;not received an independent security audit&lt;/strong&gt;. Boot tests demonstrate compatibility in the listed setups; they do not certify the security of the bridge.&lt;/p&gt;

&lt;p&gt;The code and detailed design are available in the &lt;a href="https://github.com/reordo/EncryptedVhdBoot" rel="noopener noreferrer"&gt;repository&lt;/a&gt;. I would especially welcome review of the VeraCrypt driver handoff, the Winload parser validation, and the lifetime of sensitive boot state. This is an independent project and is not affiliated with or endorsed by Ventoy, VeraCrypt, or Microsoft.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: This article was drafted with AI assistance. Its technical descriptions were checked against the project's source code and documentation.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>windows</category>
      <category>security</category>
      <category>uefi</category>
    </item>
  </channel>
</rss>
