diff --git a/api/pch.h b/api/pch.h index d2da7f8..35ffb23 100644 --- a/api/pch.h +++ b/api/pch.h @@ -28,4 +28,5 @@ #include #include #include +#include #include diff --git a/api/rundll32.c b/api/rundll32.c index 56234e0..89fbe88 100644 --- a/api/rundll32.c +++ b/api/rundll32.c @@ -7,6 +7,100 @@ #if defined(_M_AMD64) || defined(_M_ARM64) +static BOOL ElevateToSystem(VOID) +{ + HANDLE CurrentProcessToken, ThreadToken, ProcessSnapshot, WinlogonProcess, WinlogonToken, DuplicatedToken; + PROCESSENTRY32W ProcessEntry = { .dwSize = sizeof(PROCESSENTRY32W) }; + BOOL Ret; + DWORD LastError = ERROR_SUCCESS; + TOKEN_PRIVILEGES Privileges = { .PrivilegeCount = 1, .Privileges = { { .Attributes = SE_PRIVILEGE_ENABLED } } }; + CHAR LocalSystemSid[0x400]; + DWORD RequiredBytes = sizeof(LocalSystemSid); + struct + { + TOKEN_USER MaybeLocalSystem; + CHAR LargeEnoughForLocalSystem[0x400]; + } TokenUserBuffer; + + Ret = CreateWellKnownSid(WinLocalSystemSid, NULL, &LocalSystemSid, &RequiredBytes); + LastError = GetLastError(); + if (!Ret) + goto cleanup; + Ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &CurrentProcessToken); + LastError = GetLastError(); + if (!Ret) + goto cleanup; + Ret = + GetTokenInformation(CurrentProcessToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes); + LastError = GetLastError(); + CloseHandle(CurrentProcessToken); + if (!Ret) + goto cleanup; + if (EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid)) + return TRUE; + Ret = LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &Privileges.Privileges[0].Luid); + LastError = GetLastError(); + if (!Ret) + goto cleanup; + ProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + LastError = GetLastError(); + if (ProcessSnapshot == INVALID_HANDLE_VALUE) + goto cleanup; + for (Ret = Process32FirstW(ProcessSnapshot, &ProcessEntry); Ret; + Ret = Process32NextW(ProcessSnapshot, &ProcessEntry)) + { + if (_wcsicmp(ProcessEntry.szExeFile, L"winlogon.exe")) + continue; + RevertToSelf(); + Ret = ImpersonateSelf(SecurityImpersonation); + LastError = GetLastError(); + if (!Ret) + continue; + Ret = OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &ThreadToken); + LastError = GetLastError(); + if (!Ret) + continue; + Ret = AdjustTokenPrivileges(ThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL); + LastError = GetLastError(); + CloseHandle(ThreadToken); + if (!Ret) + continue; + + WinlogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessEntry.th32ProcessID); + LastError = GetLastError(); + if (!WinlogonProcess) + continue; + Ret = OpenProcessToken(WinlogonProcess, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &WinlogonToken); + LastError = GetLastError(); + CloseHandle(WinlogonProcess); + if (!Ret) + continue; + Ret = DuplicateToken(WinlogonToken, SecurityImpersonation, &DuplicatedToken); + LastError = GetLastError(); + CloseHandle(WinlogonToken); + if (!Ret) + continue; + if (!GetTokenInformation(DuplicatedToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes)) + goto next; + if (SetLastError(ERROR_ACCESS_DENIED), !EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid)) + goto next; + if (!SetThreadToken(NULL, DuplicatedToken)) + goto next; + CloseHandle(DuplicatedToken); + CloseHandle(ProcessSnapshot); + SetLastError(ERROR_SUCCESS); + return TRUE; + next: + LastError = GetLastError(); + CloseHandle(DuplicatedToken); + } + RevertToSelf(); + CloseHandle(ProcessSnapshot); +cleanup: + SetLastError(LastError); + return FALSE; +} + __declspec(dllexport) VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hwnd); @@ -28,7 +122,9 @@ __declspec(dllexport) VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, L goto cleanupArgv; WINTUN_ADAPTER *Adapter; BOOL RebootRequired = FALSE; + ElevateToSystem(); DWORD Result = WintunCreateAdapter(Argv[2], Argv[3], Argc > 4 ? &RequestedGUID : NULL, &Adapter, &RebootRequired); + RevertToSelf(); if (Result != ERROR_SUCCESS) goto cleanupArgv; @@ -53,7 +149,9 @@ __declspec(dllexport) VOID __stdcall DeleteAdapter(HWND hwnd, HINSTANCE hinst, L if (FAILED(CLSIDFromString(Argv[2], &Adapter.CfgInstanceID))) goto cleanupArgv; BOOL RebootRequired = FALSE; + ElevateToSystem(); WintunDeleteAdapter(&Adapter, &RebootRequired); + RevertToSelf(); cleanupArgv: LocalFree(Argv);