From 353cfa562e6939699eaeab587a0096360763adcb Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 2 Nov 2020 23:55:59 +0100 Subject: [PATCH] api: begin to separate rundll32 jumps Signed-off-by: Jason A. Donenfeld --- api/adapter.c | 338 +--------------------------------------- api/api.vcxproj | 1 + api/api.vcxproj.filters | 3 + api/rundll32.h | 323 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 333 insertions(+), 332 deletions(-) create mode 100644 api/rundll32.h diff --git a/api/adapter.c b/api/adapter.c index 1014950..0579e8b 100644 --- a/api/adapter.c +++ b/api/adapter.c @@ -1642,212 +1642,6 @@ cleanupDevInfo: return Result; } -#ifdef MAYBE_WOW64 - -typedef struct _PROCESS_STDOUT_STATE -{ - HANDLE Stdout; - WCHAR *Response; - DWORD ResponseCapacity; -} PROCESS_STDOUT_STATE; - -static DWORD WINAPI -ProcessStdout(_Inout_ PROCESS_STDOUT_STATE *State) -{ - for (DWORD Offset = 0, MaxLen = State->ResponseCapacity - 1; Offset < MaxLen;) - { - DWORD SizeRead; - if (!ReadFile(State->Stdout, State->Response + Offset, sizeof(WCHAR) * (MaxLen - Offset), &SizeRead, NULL)) - return ERROR_SUCCESS; - if (SizeRead % sizeof(WCHAR)) - return ERROR_INVALID_DATA; - Offset += SizeRead / sizeof(WCHAR); - State->Response[Offset] = 0; - } - return ERROR_BUFFER_OVERFLOW; -} - -static DWORD WINAPI -ProcessStderr(_In_ HANDLE Stderr) -{ - enum - { - OnNone, - OnLevelStart, - OnLevel, - OnLevelEnd, - OnSpace, - OnMsg - } State = OnNone; - WCHAR Msg[0x200]; - DWORD Count = 0; - WINTUN_LOGGER_LEVEL Level = WINTUN_LOG_INFO; - for (;;) - { - WCHAR Buf[0x200]; - DWORD SizeRead; - if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL)) - return ERROR_SUCCESS; - if (SizeRead % sizeof(WCHAR)) - return ERROR_INVALID_DATA; - SizeRead /= sizeof(WCHAR); - for (DWORD i = 0; i < SizeRead; ++i) - { - WCHAR c = Buf[i]; - if (State == OnNone && c == L'[') - State = OnLevelStart; - else if ( - State == OnLevelStart && ((Level = WINTUN_LOG_INFO, c == L'+') || - (Level = WINTUN_LOG_WARN, c == L'-') || (Level = WINTUN_LOG_ERR, c == L'!'))) - State = OnLevelEnd; - else if (State == OnLevelEnd && c == L']') - State = OnSpace; - else if (State == OnSpace && !iswspace(c) || State == OnMsg && c != L'\r' && c != L'\n') - { - if (Count < _countof(Msg) - 1) - Msg[Count++] = c; - State = OnMsg; - } - else if (State == OnMsg && c == L'\n') - { - Msg[Count] = 0; - Logger(Level, Msg); - State = OnNone; - Count = 0; - } - } - } -} - -static WINTUN_STATUS -ExecuteRunDll32( - _In_z_ const WCHAR *Arguments, - _Out_z_cap_c_(ResponseCapacity) WCHAR *Response, - _In_ DWORD ResponseCapacity) -{ - WCHAR WindowsDirectory[MAX_PATH]; - if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory))) - return LOG_LAST_ERROR(L"Failed to get Windows folder"); - WCHAR RunDll32Path[MAX_PATH]; - if (!PathCombineW(RunDll32Path, WindowsDirectory, L"Sysnative\\rundll32.exe")) - return ERROR_BUFFER_OVERFLOW; - - DWORD Result; - WCHAR RandomTempSubDirectory[MAX_PATH]; - if ((Result = CreateTemporaryDirectory(RandomTempSubDirectory)) != ERROR_SUCCESS) - return LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder"), Result; - WCHAR DllPath[MAX_PATH] = { 0 }; - if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wintun.dll")) - { - Result = ERROR_BUFFER_OVERFLOW; - goto cleanupDirectory; - } - const WCHAR *WintunDllResourceName; - switch (NativeMachine) - { - case IMAGE_FILE_MACHINE_AMD64: - WintunDllResourceName = L"wintun-amd64.dll"; - break; - case IMAGE_FILE_MACHINE_ARM64: - WintunDllResourceName = L"wintun-arm64.dll"; - break; - default: - LOG(WINTUN_LOG_ERR, L"Unsupported platform"); - Result = ERROR_NOT_SUPPORTED; - goto cleanupDirectory; - } - if ((Result = ResourceCopyToFile(DllPath, WintunDllResourceName)) != ERROR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Failed to copy resource"); - goto cleanupDelete; - } - size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1; - WCHAR *CommandLine = HeapAlloc(ModuleHeap, 0, CommandLineLen * sizeof(WCHAR)); - if (!CommandLine) - { - LOG(WINTUN_LOG_ERR, L"Out of memory"); - Result = ERROR_OUTOFMEMORY; - goto cleanupDelete; - } - if (_snwprintf_s(CommandLine, CommandLineLen, _TRUNCATE, L"rundll32 \"%.*s\",%s", MAX_PATH, DllPath, Arguments) == - -1) - { - LOG(WINTUN_LOG_ERR, L"Command line too long"); - Result = ERROR_INVALID_PARAMETER; - goto cleanupDelete; - } - HANDLE StreamRStdout = INVALID_HANDLE_VALUE, StreamRStderr = INVALID_HANDLE_VALUE, - StreamWStdout = INVALID_HANDLE_VALUE, StreamWStderr = INVALID_HANDLE_VALUE; - if (!CreatePipe(&StreamRStdout, &StreamWStdout, &SecurityAttributes, 0) || - !CreatePipe(&StreamRStderr, &StreamWStderr, &SecurityAttributes, 0)) - { - Result = LOG_LAST_ERROR(L"Failed to create pipes"); - goto cleanupPipes; - } - if (!SetHandleInformation(StreamWStdout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) || - !SetHandleInformation(StreamWStderr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) - { - Result = LOG_LAST_ERROR(L"Failed to set handle info"); - goto cleanupPipes; - } - if (ResponseCapacity) - Response[0] = 0; - PROCESS_STDOUT_STATE ProcessStdoutState = { .Stdout = StreamRStdout, - .Response = Response, - .ResponseCapacity = ResponseCapacity }; - HANDLE ThreadStdout = NULL, ThreadStderr = NULL; - if ((ThreadStdout = CreateThread(&SecurityAttributes, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL || - (ThreadStderr = CreateThread(&SecurityAttributes, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL) - { - Result = LOG_LAST_ERROR(L"Failed to spawn readers"); - goto cleanupThreads; - } - STARTUPINFOW si = { .cb = sizeof(STARTUPINFO), - .dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES, - .wShowWindow = SW_HIDE, - .hStdOutput = StreamWStdout, - .hStdError = StreamWStderr }; - PROCESS_INFORMATION pi; - if (!CreateProcessW(RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) - { - Result = LOG_LAST_ERROR(L"Creating process failed"); - goto cleanupThreads; - } - WaitForSingleObject(pi.hProcess, INFINITE); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); -cleanupThreads: - if (ThreadStderr) - { - CloseHandle(StreamWStderr); - StreamWStderr = INVALID_HANDLE_VALUE; - WaitForSingleObject(ThreadStderr, INFINITE); - CloseHandle(ThreadStderr); - } - if (ThreadStdout) - { - CloseHandle(StreamWStdout); - StreamWStdout = INVALID_HANDLE_VALUE; - WaitForSingleObject(ThreadStdout, INFINITE); - if (!GetExitCodeThread(ThreadStdout, &Result)) - Result = LOG_LAST_ERROR(L"Failed to retrieve stdout reader result"); - else if (Result != ERROR_SUCCESS) - LOG_ERROR(L"Failed to read process output", Result); - CloseHandle(ThreadStdout); - } -cleanupPipes: - CloseHandle(StreamRStderr); - CloseHandle(StreamWStderr); - CloseHandle(StreamRStdout); - CloseHandle(StreamWStdout); - HeapFree(ModuleHeap, 0, CommandLine); -cleanupDelete: - DeleteFileW(DllPath); -cleanupDirectory: - RemoveDirectoryW(RandomTempSubDirectory); - return Result; -} - static WINTUN_STATUS GetAdapter(_In_z_ const WCHAR *Pool, _In_ const GUID *CfgInstanceID, _Out_ WINTUN_ADAPTER **Adapter) { @@ -1871,57 +1665,7 @@ cleanupMutex: return Result; } -static WINTUN_STATUS -CreateAdapterNatively( - _In_z_ const WCHAR *Pool, - _In_z_ const WCHAR *Name, - _In_opt_ const GUID *RequestedGUID, - _Out_ WINTUN_ADAPTER **Adapter, - _Inout_ BOOL *RebootRequired) -{ - LOG(WINTUN_LOG_INFO, L"Spawning native process"); - WCHAR RequestedGUIDStr[MAX_GUID_STRING_LEN]; - WCHAR Arguments[15 + WINTUN_MAX_POOL + 3 + MAX_ADAPTER_NAME + 2 + MAX_GUID_STRING_LEN + 1]; - if (_snwprintf_s( - Arguments, - _countof(Arguments), - _TRUNCATE, - RequestedGUID ? L"CreateAdapter \"%s\" \"%s\" %.*s" : L"CreateAdapter \"%s\" \"%s\"", - Pool, - Name, - RequestedGUID ? StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)) : 0, - RequestedGUIDStr) == -1) - return LOG(WINTUN_LOG_ERR, L"Command line too long"), ERROR_INVALID_PARAMETER; - WCHAR Response[8 + 1 + MAX_GUID_STRING_LEN + 1 + 8 + 1]; - DWORD Result = ExecuteRunDll32(Arguments, Response, _countof(Response)); - if (Result != ERROR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Error executing worker process"); - return Result; - } - int Argc; - WCHAR **Argv = CommandLineToArgvW(Response, &Argc); - GUID CfgInstanceID; - if (Argc < 3 || FAILED(CLSIDFromString(Argv[1], &CfgInstanceID))) - { - LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response"); - Result = ERROR_INVALID_PARAMETER; - goto cleanupArgv; - } - Result = wcstoul(Argv[0], NULL, 16); - if (Result == ERROR_SUCCESS && GetAdapter(Pool, &CfgInstanceID, Adapter) != ERROR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Failed to get adapter"); - Result = ERROR_FILE_NOT_FOUND; - } - if (wcstoul(Argv[2], NULL, 16)) - *RebootRequired = TRUE; -cleanupArgv: - LocalFree(Argv); - return Result; -} - -#endif +#include "rundll32.h" WINTUN_STATUS WINAPI WintunCreateAdapter( @@ -1941,7 +1685,7 @@ WintunCreateAdapter( #ifdef MAYBE_WOW64 if (NativeMachine != IMAGE_FILE_PROCESS) { - Result = CreateAdapterNatively(Pool, Name, RequestedGUID, Adapter, RebootRequired); + Result = CreateAdapterViaRundll32(Pool, Name, RequestedGUID, Adapter, RebootRequired); RevertToSelf(); return Result; } @@ -1951,48 +1695,6 @@ WintunCreateAdapter( return Result; } -#ifdef MAYBE_WOW64 - -static WINTUN_STATUS -DeleteAdapterNatively(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Inout_ BOOL *RebootRequired) -{ - LOG(WINTUN_LOG_INFO, L"Spawning native process"); - WCHAR GuidStr[MAX_GUID_STRING_LEN]; - WCHAR Arguments[16 + MAX_GUID_STRING_LEN + 1]; - if (_snwprintf_s( - Arguments, - _countof(Arguments), - _TRUNCATE, - L"DeleteAdapter %d %.*s", - ForceCloseSessions ? 1 : 0, - StringFromGUID2(&Adapter->CfgInstanceID, GuidStr, _countof(GuidStr)), - GuidStr) == -1) - return LOG(WINTUN_LOG_ERR, L"Command line too long"), ERROR_INVALID_PARAMETER; - WCHAR Response[8 + 1 + 8 + 1]; - DWORD Result = ExecuteRunDll32(Arguments, Response, _countof(Response)); - if (Result != ERROR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Error executing worker process"); - return Result; - } - int Argc; - WCHAR **Argv = CommandLineToArgvW(Response, &Argc); - if (Argc < 2) - { - LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response"); - Result = ERROR_INVALID_PARAMETER; - goto cleanupArgv; - } - Result = wcstoul(Argv[0], NULL, 16); - if (wcstoul(Argv[1], NULL, 16)) - *RebootRequired = TRUE; -cleanupArgv: - LocalFree(Argv); - return Result; -} - -#endif - WINTUN_STATUS WINAPI WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired) { @@ -2007,7 +1709,7 @@ WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSess #ifdef MAYBE_WOW64 if (NativeMachine != IMAGE_FILE_PROCESS) { - Result = DeleteAdapterNatively(Adapter, ForceCloseSessions, RebootRequired); + Result = DeleteAdapterViaRundll32(Adapter, ForceCloseSessions, RebootRequired); RevertToSelf(); return Result; } @@ -2046,35 +1748,6 @@ cleanupToken: return Result; } -#ifdef MAYBE_WOW64 - -static WINTUN_STATUS -DeleteDriverNatively() -{ - LOG(WINTUN_LOG_INFO, L"Spawning native process"); - WCHAR Response[8 + 1]; - DWORD Result = ExecuteRunDll32(L"DeleteDriver", Response, _countof(Response)); - if (Result != ERROR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Error executing worker process"); - return Result; - } - int Argc; - WCHAR **Argv = CommandLineToArgvW(Response, &Argc); - if (Argc < 1) - { - LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response"); - Result = ERROR_INVALID_PARAMETER; - goto cleanupArgv; - } - Result = wcstoul(Argv[0], NULL, 16); -cleanupArgv: - LocalFree(Argv); - return Result; -} - -#endif - static WINTUN_STATUS DeleteAllOurAdapters(void) { @@ -2121,17 +1794,18 @@ WintunDeleteDriver(void) if (!ElevateToSystem()) return LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"), ERROR_ACCESS_DENIED; + DWORD Result = ERROR_SUCCESS; + #ifdef MAYBE_WOW64 if (NativeMachine != IMAGE_FILE_PROCESS) { - Result = DeleteDriverNatively(); + Result = DeleteDriverViaRundll32(); RevertToSelf(); return Result; } #endif /* DeleteAllOurAdapters(); */ - DWORD Result = ERROR_SUCCESS; HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex(); if (!DriverInstallationLock) { diff --git a/api/api.vcxproj b/api/api.vcxproj index d864f0c..b50289e 100644 --- a/api/api.vcxproj +++ b/api/api.vcxproj @@ -160,6 +160,7 @@ lib.exe /def:nci.def /out:"$(IntDir)nci.lib" /machine:$(PlatformTarget) /nologo + diff --git a/api/api.vcxproj.filters b/api/api.vcxproj.filters index c1db346..231313c 100644 --- a/api/api.vcxproj.filters +++ b/api/api.vcxproj.filters @@ -58,6 +58,9 @@ Header Files + + Header Files + diff --git a/api/rundll32.h b/api/rundll32.h new file mode 100644 index 0000000..61df869 --- /dev/null +++ b/api/rundll32.h @@ -0,0 +1,323 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018-2020 WireGuard LLC. All Rights Reserved. + */ + +/* TODO: This is currently #include'd in adapter.c. Move into rundll32.c properly. */ + +typedef struct _PROCESS_STDOUT_STATE +{ + HANDLE Stdout; + WCHAR *Response; + DWORD ResponseCapacity; +} PROCESS_STDOUT_STATE; + +static DWORD WINAPI +ProcessStdout(_Inout_ PROCESS_STDOUT_STATE *State) +{ + for (DWORD Offset = 0, MaxLen = State->ResponseCapacity - 1; Offset < MaxLen;) + { + DWORD SizeRead; + if (!ReadFile(State->Stdout, State->Response + Offset, sizeof(WCHAR) * (MaxLen - Offset), &SizeRead, NULL)) + return ERROR_SUCCESS; + if (SizeRead % sizeof(WCHAR)) + return ERROR_INVALID_DATA; + Offset += SizeRead / sizeof(WCHAR); + State->Response[Offset] = 0; + } + return ERROR_BUFFER_OVERFLOW; +} + +static DWORD WINAPI +ProcessStderr(_In_ HANDLE Stderr) +{ + enum + { + OnNone, + OnLevelStart, + OnLevel, + OnLevelEnd, + OnSpace, + OnMsg + } State = OnNone; + WCHAR Msg[0x200]; + DWORD Count = 0; + WINTUN_LOGGER_LEVEL Level = WINTUN_LOG_INFO; + for (;;) + { + WCHAR Buf[0x200]; + DWORD SizeRead; + if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL)) + return ERROR_SUCCESS; + if (SizeRead % sizeof(WCHAR)) + return ERROR_INVALID_DATA; + SizeRead /= sizeof(WCHAR); + for (DWORD i = 0; i < SizeRead; ++i) + { + WCHAR c = Buf[i]; + if (State == OnNone && c == L'[') + State = OnLevelStart; + else if ( + State == OnLevelStart && ((Level = WINTUN_LOG_INFO, c == L'+') || + (Level = WINTUN_LOG_WARN, c == L'-') || (Level = WINTUN_LOG_ERR, c == L'!'))) + State = OnLevelEnd; + else if (State == OnLevelEnd && c == L']') + State = OnSpace; + else if (State == OnSpace && !iswspace(c) || State == OnMsg && c != L'\r' && c != L'\n') + { + if (Count < _countof(Msg) - 1) + Msg[Count++] = c; + State = OnMsg; + } + else if (State == OnMsg && c == L'\n') + { + Msg[Count] = 0; + Logger(Level, Msg); + State = OnNone; + Count = 0; + } + } + } +} + +static WINTUN_STATUS +ExecuteRunDll32( + _In_z_ const WCHAR *Arguments, + _Out_z_cap_c_(ResponseCapacity) WCHAR *Response, + _In_ DWORD ResponseCapacity) +{ + WCHAR WindowsDirectory[MAX_PATH]; + if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory))) + return LOG_LAST_ERROR(L"Failed to get Windows folder"); + WCHAR RunDll32Path[MAX_PATH]; + if (!PathCombineW(RunDll32Path, WindowsDirectory, L"Sysnative\\rundll32.exe")) + return ERROR_BUFFER_OVERFLOW; + + DWORD Result; + WCHAR RandomTempSubDirectory[MAX_PATH]; + if ((Result = CreateTemporaryDirectory(RandomTempSubDirectory)) != ERROR_SUCCESS) + return LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder"), Result; + WCHAR DllPath[MAX_PATH] = { 0 }; + if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wintun.dll")) + { + Result = ERROR_BUFFER_OVERFLOW; + goto cleanupDirectory; + } + const WCHAR *WintunDllResourceName; + switch (NativeMachine) + { + case IMAGE_FILE_MACHINE_AMD64: + WintunDllResourceName = L"wintun-amd64.dll"; + break; + case IMAGE_FILE_MACHINE_ARM64: + WintunDllResourceName = L"wintun-arm64.dll"; + break; + default: + LOG(WINTUN_LOG_ERR, L"Unsupported platform"); + Result = ERROR_NOT_SUPPORTED; + goto cleanupDirectory; + } + if ((Result = ResourceCopyToFile(DllPath, WintunDllResourceName)) != ERROR_SUCCESS) + { + LOG(WINTUN_LOG_ERR, L"Failed to copy resource"); + goto cleanupDelete; + } + size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1; + WCHAR *CommandLine = HeapAlloc(ModuleHeap, 0, CommandLineLen * sizeof(WCHAR)); + if (!CommandLine) + { + LOG(WINTUN_LOG_ERR, L"Out of memory"); + Result = ERROR_OUTOFMEMORY; + goto cleanupDelete; + } + if (_snwprintf_s(CommandLine, CommandLineLen, _TRUNCATE, L"rundll32 \"%.*s\",%s", MAX_PATH, DllPath, Arguments) == + -1) + { + LOG(WINTUN_LOG_ERR, L"Command line too long"); + Result = ERROR_INVALID_PARAMETER; + goto cleanupDelete; + } + HANDLE StreamRStdout = INVALID_HANDLE_VALUE, StreamRStderr = INVALID_HANDLE_VALUE, + StreamWStdout = INVALID_HANDLE_VALUE, StreamWStderr = INVALID_HANDLE_VALUE; + if (!CreatePipe(&StreamRStdout, &StreamWStdout, &SecurityAttributes, 0) || + !CreatePipe(&StreamRStderr, &StreamWStderr, &SecurityAttributes, 0)) + { + Result = LOG_LAST_ERROR(L"Failed to create pipes"); + goto cleanupPipes; + } + if (!SetHandleInformation(StreamWStdout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) || + !SetHandleInformation(StreamWStderr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) + { + Result = LOG_LAST_ERROR(L"Failed to set handle info"); + goto cleanupPipes; + } + if (ResponseCapacity) + Response[0] = 0; + PROCESS_STDOUT_STATE ProcessStdoutState = { .Stdout = StreamRStdout, + .Response = Response, + .ResponseCapacity = ResponseCapacity }; + HANDLE ThreadStdout = NULL, ThreadStderr = NULL; + if ((ThreadStdout = CreateThread(&SecurityAttributes, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL || + (ThreadStderr = CreateThread(&SecurityAttributes, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL) + { + Result = LOG_LAST_ERROR(L"Failed to spawn readers"); + goto cleanupThreads; + } + STARTUPINFOW si = { .cb = sizeof(STARTUPINFO), + .dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES, + .wShowWindow = SW_HIDE, + .hStdOutput = StreamWStdout, + .hStdError = StreamWStderr }; + PROCESS_INFORMATION pi; + if (!CreateProcessW(RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) + { + Result = LOG_LAST_ERROR(L"Creating process failed"); + goto cleanupThreads; + } + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); +cleanupThreads: + if (ThreadStderr) + { + CloseHandle(StreamWStderr); + StreamWStderr = INVALID_HANDLE_VALUE; + WaitForSingleObject(ThreadStderr, INFINITE); + CloseHandle(ThreadStderr); + } + if (ThreadStdout) + { + CloseHandle(StreamWStdout); + StreamWStdout = INVALID_HANDLE_VALUE; + WaitForSingleObject(ThreadStdout, INFINITE); + if (!GetExitCodeThread(ThreadStdout, &Result)) + Result = LOG_LAST_ERROR(L"Failed to retrieve stdout reader result"); + else if (Result != ERROR_SUCCESS) + LOG_ERROR(L"Failed to read process output", Result); + CloseHandle(ThreadStdout); + } +cleanupPipes: + CloseHandle(StreamRStderr); + CloseHandle(StreamWStderr); + CloseHandle(StreamRStdout); + CloseHandle(StreamWStdout); + HeapFree(ModuleHeap, 0, CommandLine); +cleanupDelete: + DeleteFileW(DllPath); +cleanupDirectory: + RemoveDirectoryW(RandomTempSubDirectory); + return Result; +} + +static WINTUN_STATUS +CreateAdapterViaRundll32( + _In_z_ const WCHAR *Pool, + _In_z_ const WCHAR *Name, + _In_opt_ const GUID *RequestedGUID, + _Out_ WINTUN_ADAPTER **Adapter, + _Inout_ BOOL *RebootRequired) +{ + LOG(WINTUN_LOG_INFO, L"Spawning native process"); + WCHAR RequestedGUIDStr[MAX_GUID_STRING_LEN]; + WCHAR Arguments[15 + WINTUN_MAX_POOL + 3 + MAX_ADAPTER_NAME + 2 + MAX_GUID_STRING_LEN + 1]; + if (_snwprintf_s( + Arguments, + _countof(Arguments), + _TRUNCATE, + RequestedGUID ? L"CreateAdapter \"%s\" \"%s\" %.*s" : L"CreateAdapter \"%s\" \"%s\"", + Pool, + Name, + RequestedGUID ? StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)) : 0, + RequestedGUIDStr) == -1) + return LOG(WINTUN_LOG_ERR, L"Command line too long"), ERROR_INVALID_PARAMETER; + WCHAR Response[8 + 1 + MAX_GUID_STRING_LEN + 1 + 8 + 1]; + DWORD Result = ExecuteRunDll32(Arguments, Response, _countof(Response)); + if (Result != ERROR_SUCCESS) + { + LOG(WINTUN_LOG_ERR, L"Error executing worker process"); + return Result; + } + int Argc; + WCHAR **Argv = CommandLineToArgvW(Response, &Argc); + GUID CfgInstanceID; + if (Argc < 3 || FAILED(CLSIDFromString(Argv[1], &CfgInstanceID))) + { + LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response"); + Result = ERROR_INVALID_PARAMETER; + goto cleanupArgv; + } + Result = wcstoul(Argv[0], NULL, 16); + if (Result == ERROR_SUCCESS && GetAdapter(Pool, &CfgInstanceID, Adapter) != ERROR_SUCCESS) + { + LOG(WINTUN_LOG_ERR, L"Failed to get adapter"); + Result = ERROR_FILE_NOT_FOUND; + } + if (wcstoul(Argv[2], NULL, 16)) + *RebootRequired = TRUE; +cleanupArgv: + LocalFree(Argv); + return Result; +} + +static WINTUN_STATUS +DeleteAdapterViaRundll32(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Inout_ BOOL *RebootRequired) +{ + LOG(WINTUN_LOG_INFO, L"Spawning native process"); + WCHAR GuidStr[MAX_GUID_STRING_LEN]; + WCHAR Arguments[16 + MAX_GUID_STRING_LEN + 1]; + if (_snwprintf_s( + Arguments, + _countof(Arguments), + _TRUNCATE, + L"DeleteAdapter %d %.*s", + ForceCloseSessions ? 1 : 0, + StringFromGUID2(&Adapter->CfgInstanceID, GuidStr, _countof(GuidStr)), + GuidStr) == -1) + return LOG(WINTUN_LOG_ERR, L"Command line too long"), ERROR_INVALID_PARAMETER; + WCHAR Response[8 + 1 + 8 + 1]; + DWORD Result = ExecuteRunDll32(Arguments, Response, _countof(Response)); + if (Result != ERROR_SUCCESS) + { + LOG(WINTUN_LOG_ERR, L"Error executing worker process"); + return Result; + } + int Argc; + WCHAR **Argv = CommandLineToArgvW(Response, &Argc); + if (Argc < 2) + { + LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response"); + Result = ERROR_INVALID_PARAMETER; + goto cleanupArgv; + } + Result = wcstoul(Argv[0], NULL, 16); + if (wcstoul(Argv[1], NULL, 16)) + *RebootRequired = TRUE; +cleanupArgv: + LocalFree(Argv); + return Result; +} + +static WINTUN_STATUS +DeleteDriverViaRundll32() +{ + LOG(WINTUN_LOG_INFO, L"Spawning native process"); + WCHAR Response[8 + 1]; + DWORD Result = ExecuteRunDll32(L"DeleteDriver", Response, _countof(Response)); + if (Result != ERROR_SUCCESS) + { + LOG(WINTUN_LOG_ERR, L"Error executing worker process"); + return Result; + } + int Argc; + WCHAR **Argv = CommandLineToArgvW(Response, &Argc); + if (Argc < 1) + { + LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response"); + Result = ERROR_INVALID_PARAMETER; + goto cleanupArgv; + } + Result = wcstoul(Argv[0], NULL, 16); +cleanupArgv: + LocalFree(Argv); + return Result; +} \ No newline at end of file