Singularity is a proof-of-concept for mapping unsigned kernel drivers using a custom UEFI DXE runtime driver.
The usermode mapper (DriverMapper) is a fork of kdmapper that replaces the vulnerable-driver communication layer with a custom UEFI DXE runtime driver (SingularityPkg).
Compatibility
- Tested on Windows 10 Version 22H2 (Build 19045.6466) and Windows 11 Version 25H2 (Build 26200.8037).
Successfully mapping an unsigned kernel driver on Windows 11.
Full walkthrough: https://youtu.be/Tm64grsKTO0
Instead of relying on a vulnerable kernel driver to execute arbitrary code in kernel mode, Singularity uses a UEFI DXE driver that runs in firmware space and hooks the EFI Runtime Service SetVariable.
User Mode (mapper.exe)
|
| NtSetSystemEnvironmentValueEx("Singularity42", MemoryCommand)
v
Windows Kernel (ntoskrnl)
|
| gRT->SetVariable("Singularity42")
v
UEFI Runtime (SingularityDxe.efi)
|
| HookedSetVariable -> RunCommand
v
DriverBuffer (32 MB EfiRuntimeServicesCode pool)
|
| Driver image, allocations, execution
v
Arbitrary kernel-mode code
-
Installation - The DXE driver is loaded at boot (via UEFI shell, DXE driver injection, or boot option). On entry (
DxeDriverEntry), it:- Allocates a 32 MB
EfiRuntimeServicesCodebuffer calledDriverBufferfor hosting mapped drivers - Hooks
gRT->SetVariableby patching the EFI Runtime Services Table, redirecting all calls toHookedSetVariable - Registers event handlers for
SetVirtualAddressMapandExitBootServicesto manage the boot-to-runtime transition
- Allocates a 32 MB
-
SetVariable Hook - The hook checks if the variable name is
"Singularity42". If so, it interprets the payload as aMemoryCommandstructure and passes it toRunCommand. All otherSetVariablecalls are forwarded to the original function. -
Command Operations -
RunCommandsupports these operations:Op Function Description 0 memcpy(dst, src, size)Copies memory between arbitrary addresses 1 AllocatePoolReports DriverBufferaddress back to the caller3 CallStdcall(target)Calls void __stdcall()insideDriverBuffer4 CallFastcall(target)Calls void __fastcall()insideDriverBuffer5 CallDriverEntry(target)Calls a DriverEntry-style function insideDriverBuffer, returns NTSTATUSAll calls are bounds-checked against
DriverBufferto prevent executing arbitrary UEFI addresses. -
Virtual Address Transition - When Windows calls
SetVirtualAddressMap, the DXE driver converts its pointers (oSetVariable,DriverBuffer) usingConvertPointer. AfterExitBootServices, the hook activates fully and begins processing commands.
- Enable
SeSystemEnvironmentPrivilegefor the calling process - Read the target
.sysdriver into memory - Parse PE headers, relocate the image, resolve imports with fallback to
ntoskrnl.exe - Fix the stack cookie (
__security_cookie) - Allocate kernel memory via the DXE driver's operation 1 (reports
DriverBufferaddress) - Write the fixed driver image into
DriverBuffer - Call the driver's entry point via operation 5
- Optionally free the pool after the driver exits
After mapping, ClearMmUnloadedDrivers removes the driver entry from MmUnloadedDrivers via the system handle table, preventing detection by NtQuerySystemInformation.
Mapper.exe [--free] [--PassAllocationPtr] [--copy-header] driver.sys
| Flag | Description |
|---|---|
--free |
Free the allocated pool after the driver's entry point returns |
--PassAllocationPtr |
Pass the allocation address as the first parameter to DriverEntry |
--copy-header |
Keep the PE header intact (default behavior strips it) |
- Visual Studio 2026 (or your preferred version)
- EDK2 properly set up
- NASM assembler (required by EDK2)
-
Clone and set up EDK2:
git clone https://github.com/tianocore/edk2.git cd edk2 git submodule update --init edksetup.bat
-
Copy the
SingularityPkgfolder into the EDK2 workspace root (next toMdePkg,UefiCpuPkg, etc.). -
Build:
build -p SingularityPkg\SingularityPkg.dsc -a X64 -t VS2026 -b RELEASEThe output
SingularityDxe.efiwill be underBuild\SingularityPkg\RELEASE_VS2026\X64\.
Open DriverMapper.slnx in Visual Studio and build the solution.
- A FAT32 formatted USB drive (at least 64 MB)
- Shell.efi from EDK2 (built from
edk2/ShellPkg) or downloaded from a release - The compiled
SingularityDxe.efibinary
-
Format a USB drive as FAT32 and copy the following files to its root:
Shell.efi(renamed tobootx64.efiand placed underEFI\BOOT\so the firmware boots into it automatically)SingularityDxe.efi(placed anywhere on the drive, e.g.SingularityDxe.efi)
Expected layout:
USB drive (FAT32) └── EFI └── BOOT └── bootx64.efi (Shell.efi) └── SingularityDxe.efi -
Boot from the USB drive - Enter your BIOS/UEFI boot menu and select the USB drive. The UEFI Shell will launch.
-
Load the DXE driver - At the UEFI Shell prompt, find the USB drive (typically
fs0:) and run:fs0: load SingularityDxe.efiIf successful, the driver will print its banner, allocate
DriverBuffer, hookSetVariable, and register the virtual address / exit-boot events. -
Exit back to Windows - Once the driver is loaded, find the Windows Boot Manager and run it:
fs0:\EFI\BOOT\bootx64.efi (not this - this is the shell again)Instead, identify the Windows drive (e.g.
fs1:) and run:fs1:\EFI\Microsoft\Boot\bootmgfw.efiWindows will resume normal booting with
SingularityDxe.efinow active in memory. -
Run the mapper - After Windows boots, run
mapper.exeas administrator. It will communicate with the loaded DXE driver through EFI runtime variables to map your unsigned driver.
- If you have Secure Boot enabled, you may need to disable it or sign the DXE driver appropriately.
- The DXE driver persists for the current boot session only. You must re-load it after every reboot.
- You can identify available UEFI file systems at the shell prompt with the
mapcommand. Shell.efican be built from EDK2 (build -p ShellPkg\ShellPkg.dsc -a X64 -t VS2026 -b RELEASE) or obtained from a pre-built EDK2 release.
This project is based on the following projects:
This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
