aboutsummaryrefslogtreecommitdiffstats
path: root/api/rundll32.c
diff options
context:
space:
mode:
authorSimon Rozman <simon@rozman.si>2020-10-15 14:54:21 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2020-10-30 16:51:00 +0100
commit369801cdfa1f41b3bc8bf6e1bafead8301278568 (patch)
treec45563d959627c849ae827eec88264598c204450 /api/rundll32.c
parentapi: move documentation to .h and discontinue on static functions (diff)
downloadwintun-369801cdfa1f41b3bc8bf6e1bafead8301278568.tar.xz
wintun-369801cdfa1f41b3bc8bf6e1bafead8301278568.zip
api: elevate rundll32 calls to SYSTEM
I need this for debugging. In production environment, WoW64 clients will already call rundll32 elevated to SYSTEM. Signed-off-by: Simon Rozman <simon@rozman.si>
Diffstat (limited to 'api/rundll32.c')
-rw-r--r--api/rundll32.c98
1 files changed, 98 insertions, 0 deletions
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);