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