Using VMProtect on UEFI binaries
As you may or may not know, the latest version of VMProtect (as of writing of this post, 3.7) does not support protection of UEFI binaries at all. When you try to load a UEFI application or a driver, you will be presented with an unsupported subsystem error.
However, VMProtect has supported the protection of Windows kernel mode drivers for quite some time. This means that, with a bit of trickery, you can use it on almost any PE file imaginable, including UEFI binaries.
The trick is extremely simple: just change the subsystem, use VMProtect, and then change it back.
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)fileBase;
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(fileBase + dosHeader->e_lfanew);
ntHeaders->OptionalHeader.Subsystem = targetSubsystem;
Valid values are in the table bellow.
Constant | Value | Description |
---|---|---|
IMAGE_SUBSYSTEM_UNKNOWN | 0 | An unknown subsystem |
IMAGE_SUBSYSTEM_NATIVE | 1 | Device drivers and native Windows processes |
IMAGE_SUBSYSTEM_WINDOWS_GUI | 2 | The Windows graphical user interface (GUI) subsystem |
IMAGE_SUBSYSTEM_WINDOWS_CUI | 3 | The Windows character subsystem |
IMAGE_SUBSYSTEM_OS2_CUI | 5 | The OS/2 character subsystem |
IMAGE_SUBSYSTEM_POSIX_CUI | 7 | The Posix character subsystem |
IMAGE_SUBSYSTEM_NATIVE_WINDOWS | 8 | Native Win9x driver |
IMAGE_SUBSYSTEM_WINDOWS_CE_GUI | 9 | Windows CE |
IMAGE_SUBSYSTEM_EFI_APPLICATION | 10 | An Extensible Firmware Interface (EFI) application |
IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER | 11 | An EFI driver with boot services |
IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER | 12 | An EFI driver with run-time services |
IMAGE_SUBSYSTEM_EFI_ROM | 13 | An EFI ROM image |
IMAGE_SUBSYSTEM_XBOX | 14 | XBOX |
IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION | 16 | Windows boot application |
Keep in mind that only code mutation and virtualization will work. You cannot use file packing, resource protection, memory protection, or anti-debug, as these would cause your binary to have imports from the Windows kernel, which obviously won’t be resolved in a UEFI environment.
If you put in a little more effort, you can even set up Visual Studio post-build scripts (if you are using VS, that is) to automatically run VMProtect.
:: Usage as follows:
:: call "$(SolutionDir)scripts\post_build.bat" "$(TargetDir)$(ProjectName).dll" "$(TargetDir)sakura.efi"
echo Changing subsystem to Windows driver...
call "%~dp0change_subsystem.exe" "%1" 0x1
echo Running VMProtect...
call "C:\Program Files\VMProtect Professional\VMProtect_Con.exe" "%1" "%2" -pf "%~dp0main_config.vmp"
echo Changing subsystem back to EFI application...
call "%~dp0change_subsystem.exe" "%2" 0xA
echo All done
Don’t forget to avoid options that might require adding additional imports into the binary.
<?xml version="1.0" encoding="UTF-8" ?>
<Document Version="2">
<Protection InputFileName="input_file.dll" Options="65736" VMCodeSectionName=".uwu" OutputFileName="sakura_protected.efi">
<Messages />
<Folders />
<Procedures>
</Procedures>
<Objects />
</Protection>
<Script />
</Document>
You can see this setup in action in this video.