api: begin to separate rundll32 jumps
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
9a937c7a49
commit
353cfa562e
338
api/adapter.c
338
api/adapter.c
@ -1642,212 +1642,6 @@ cleanupDevInfo:
|
|||||||
return Result;
|
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
|
static WINTUN_STATUS
|
||||||
GetAdapter(_In_z_ const WCHAR *Pool, _In_ const GUID *CfgInstanceID, _Out_ WINTUN_ADAPTER **Adapter)
|
GetAdapter(_In_z_ const WCHAR *Pool, _In_ const GUID *CfgInstanceID, _Out_ WINTUN_ADAPTER **Adapter)
|
||||||
{
|
{
|
||||||
@ -1871,57 +1665,7 @@ cleanupMutex:
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WINTUN_STATUS
|
#include "rundll32.h"
|
||||||
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
|
|
||||||
|
|
||||||
WINTUN_STATUS WINAPI
|
WINTUN_STATUS WINAPI
|
||||||
WintunCreateAdapter(
|
WintunCreateAdapter(
|
||||||
@ -1941,7 +1685,7 @@ WintunCreateAdapter(
|
|||||||
#ifdef MAYBE_WOW64
|
#ifdef MAYBE_WOW64
|
||||||
if (NativeMachine != IMAGE_FILE_PROCESS)
|
if (NativeMachine != IMAGE_FILE_PROCESS)
|
||||||
{
|
{
|
||||||
Result = CreateAdapterNatively(Pool, Name, RequestedGUID, Adapter, RebootRequired);
|
Result = CreateAdapterViaRundll32(Pool, Name, RequestedGUID, Adapter, RebootRequired);
|
||||||
RevertToSelf();
|
RevertToSelf();
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
@ -1951,48 +1695,6 @@ WintunCreateAdapter(
|
|||||||
return Result;
|
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
|
WINTUN_STATUS WINAPI
|
||||||
WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired)
|
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
|
#ifdef MAYBE_WOW64
|
||||||
if (NativeMachine != IMAGE_FILE_PROCESS)
|
if (NativeMachine != IMAGE_FILE_PROCESS)
|
||||||
{
|
{
|
||||||
Result = DeleteAdapterNatively(Adapter, ForceCloseSessions, RebootRequired);
|
Result = DeleteAdapterViaRundll32(Adapter, ForceCloseSessions, RebootRequired);
|
||||||
RevertToSelf();
|
RevertToSelf();
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
@ -2046,35 +1748,6 @@ cleanupToken:
|
|||||||
return Result;
|
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
|
static WINTUN_STATUS
|
||||||
DeleteAllOurAdapters(void)
|
DeleteAllOurAdapters(void)
|
||||||
{
|
{
|
||||||
@ -2121,17 +1794,18 @@ WintunDeleteDriver(void)
|
|||||||
if (!ElevateToSystem())
|
if (!ElevateToSystem())
|
||||||
return LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"), ERROR_ACCESS_DENIED;
|
return LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"), ERROR_ACCESS_DENIED;
|
||||||
|
|
||||||
|
DWORD Result = ERROR_SUCCESS;
|
||||||
|
|
||||||
#ifdef MAYBE_WOW64
|
#ifdef MAYBE_WOW64
|
||||||
if (NativeMachine != IMAGE_FILE_PROCESS)
|
if (NativeMachine != IMAGE_FILE_PROCESS)
|
||||||
{
|
{
|
||||||
Result = DeleteDriverNatively();
|
Result = DeleteDriverViaRundll32();
|
||||||
RevertToSelf();
|
RevertToSelf();
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* DeleteAllOurAdapters(); */
|
/* DeleteAllOurAdapters(); */
|
||||||
DWORD Result = ERROR_SUCCESS;
|
|
||||||
HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex();
|
HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex();
|
||||||
if (!DriverInstallationLock)
|
if (!DriverInstallationLock)
|
||||||
{
|
{
|
||||||
|
@ -160,6 +160,7 @@ lib.exe /def:nci.def /out:"$(IntDir)nci.lib" /machine:$(PlatformTarget) /nologo
|
|||||||
<ClInclude Include="entry.h" />
|
<ClInclude Include="entry.h" />
|
||||||
<ClInclude Include="adapter.h" />
|
<ClInclude Include="adapter.h" />
|
||||||
<ClInclude Include="elevate.h" />
|
<ClInclude Include="elevate.h" />
|
||||||
|
<ClInclude Include="rundll32.h" />
|
||||||
<ClInclude Include="logger.h" />
|
<ClInclude Include="logger.h" />
|
||||||
<ClInclude Include="namespace.h" />
|
<ClInclude Include="namespace.h" />
|
||||||
<ClInclude Include="nci.h" />
|
<ClInclude Include="nci.h" />
|
||||||
|
@ -58,6 +58,9 @@
|
|||||||
<ClInclude Include="entry.h">
|
<ClInclude Include="entry.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="rundll32.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="namespace.c">
|
<ClCompile Include="namespace.c">
|
||||||
|
323
api/rundll32.h
Normal file
323
api/rundll32.h
Normal file
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user