diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-07-22 07:36:21 +0000 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-08-02 09:43:32 +0000 |
commit | 22e2da002d8ad18b3d3f1286191f03854939f3c4 (patch) | |
tree | ca211b7743fa5e018694f11efb717621a9b13f25 /installer/rundll32.c | |
parent | Use explicit running boolean and use set instead of exchange (diff) | |
download | wintun-22e2da002d8ad18b3d3f1286191f03854939f3c4.tar.xz wintun-22e2da002d8ad18b3d3f1286191f03854939f3c4.zip |
Rewrite installer logic in C
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'installer/rundll32.c')
-rw-r--r-- | installer/rundll32.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/installer/rundll32.c b/installer/rundll32.c new file mode 100644 index 0000000..3a482f1 --- /dev/null +++ b/installer/rundll32.c @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved. + */ + +#include "installation.h" +#include <Windows.h> +#include <tlhelp32.h> +#include <stdio.h> +#include <conio.h> +#include <tchar.h> + +#pragma warning(disable : 4100) /* unreferenced formal parameter */ + +static VOID +ConsoleLogger(_In_ LOGGER_LEVEL Level, _In_ const TCHAR *LogLine) +{ + TCHAR *Template; + switch (Level) + { + case LOG_INFO: + Template = TEXT("[+] %s\n"); + break; + case LOG_WARN: + Template = TEXT("[-] %s\n"); + break; + case LOG_ERR: + Template = TEXT("[!] %s\n"); + break; + default: + return; + } + _ftprintf(stdout, Template, LogLine); +} + +static BOOL ElevateToSystem(VOID) +{ + HANDLE ThreadToken, ProcessSnapshot, WinlogonProcess, WinlogonToken, DuplicatedToken; + PROCESSENTRY32 ProcessEntry = { .dwSize = sizeof(PROCESSENTRY32) }; + BOOL Ret; + DWORD LastError = ERROR_SUCCESS; + TOKEN_PRIVILEGES Privileges = { .PrivilegeCount = 1, .Privileges = { { .Attributes = SE_PRIVILEGE_ENABLED } } }; + CHAR LocalSystemSid[0x400]; + DWORD RequiredBytes = sizeof(LocalSystemSid); + + if (!CreateWellKnownSid(WinLocalSystemSid, NULL, &LocalSystemSid, &RequiredBytes)) + goto cleanup; + struct + { + TOKEN_USER MaybeLocalSystem; + CHAR LargeEnoughForLocalSystem[0x400]; + } TokenUserBuffer; + if (!GetTokenInformation( + GetCurrentProcessToken(), TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes)) + goto cleanup; + if (EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid)) + return TRUE; + if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Privileges.Privileges[0].Luid)) + goto cleanup; + ProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (ProcessSnapshot == INVALID_HANDLE_VALUE) + goto cleanup; + for (Ret = Process32First(ProcessSnapshot, &ProcessEntry); Ret; + LastError = GetLastError(), Ret = Process32Next(ProcessSnapshot, &ProcessEntry)) + { + if (_tcsicmp(ProcessEntry.szExeFile, TEXT("winlogon.exe"))) + continue; + RevertToSelf(); + if (!ImpersonateSelf(SecurityImpersonation)) + continue; + if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &ThreadToken)) + continue; + if (!AdjustTokenPrivileges(ThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL)) + { + LastError = GetLastError(); + CloseHandle(ThreadToken); + continue; + } + CloseHandle(ThreadToken); + + WinlogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessEntry.th32ProcessID); + if (!WinlogonProcess) + continue; + if (!OpenProcessToken(WinlogonProcess, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &WinlogonToken)) + continue; + CloseHandle(WinlogonProcess); + if (!DuplicateToken(WinlogonToken, SecurityImpersonation, &DuplicatedToken)) + { + LastError = GetLastError(); + continue; + } + CloseHandle(WinlogonToken); + 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; +} + +static VOID +RunAsAdministrator(HWND hwnd, TCHAR *Verb, int nCmdShow) +{ + TOKEN_ELEVATION Elevation; + DWORD Required; + if (!GetTokenInformation(GetCurrentProcessToken(), TokenElevation, &Elevation, sizeof(Elevation), &Required)) + return; + if (Elevation.TokenIsElevated) + return; + TCHAR ProcessPath[MAX_PATH], DllPath[MAX_PATH]; + if (!GetModuleFileName(NULL, ProcessPath, _countof(ProcessPath)) || + !GetModuleFileName(ResourceModule, DllPath, _countof(DllPath))) + return; + TCHAR Params[0x1000]; + _stprintf_s(Params, _countof(Params), TEXT("\"%s\",%s"), DllPath, Verb); + ShellExecute(hwnd, TEXT("runas"), ProcessPath, Params, NULL, nCmdShow); + exit(0); +} + +static VOID +Do(BOOL Install, BOOL ShowConsole) +{ + if (ShowConsole) + { + AllocConsole(); + FILE *Stream; + freopen_s(&Stream, "CONOUT$", "w", stdout); + } + SetLogger(ConsoleLogger); + ElevateToSystem(); + Install ? InstallOrUpdate() : Uninstall(); + RevertToSelf(); + _putws(TEXT("\nPress any key to close . . .")); + (VOID) _getch(); +} + +VOID __stdcall InstallWintun(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +{ + RunAsAdministrator(hwnd, TEXT(__FUNCTION__), nCmdShow); + Do(TRUE, !!nCmdShow); +} + +VOID __stdcall UninstallWintun(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +{ + RunAsAdministrator(hwnd, TEXT(__FUNCTION__) , nCmdShow); + Do(FALSE, !!nCmdShow); +}
\ No newline at end of file |