diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2020-11-02 23:55:59 +0100 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2020-11-03 02:25:20 +0100 |
commit | 353cfa562e6939699eaeab587a0096360763adcb (patch) | |
tree | 5c31abbff73be15c0cd8c0de98808d5dc4b08abf /api/adapter.c | |
parent | example: rewrite and replace api's debug rundll32 functionality (diff) | |
download | wintun-353cfa562e6939699eaeab587a0096360763adcb.tar.xz wintun-353cfa562e6939699eaeab587a0096360763adcb.zip |
api: begin to separate rundll32 jumps
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'api/adapter.c')
-rw-r--r-- | api/adapter.c | 338 |
1 files changed, 6 insertions, 332 deletions
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) { |