diff options
author | 2020-10-16 13:30:51 +0200 | |
---|---|---|
committer | 2020-10-30 16:51:00 +0100 | |
commit | 9a16d4e3cc6fb51bdf791beb2a6c8c3eda7b265d (patch) | |
tree | d2ed66d6e0270b6082ef73372ab15cf719c878ad | |
parent | api: redirect log to stderr in rundll32 invocations (diff) | |
download | wintun-9a16d4e3cc6fb51bdf791beb2a6c8c3eda7b265d.tar.xz wintun-9a16d4e3cc6fb51bdf791beb2a6c8c3eda7b265d.zip |
api: build the bridge from WoW64 to native in
SetupAPI fails to create a device in WoW64 processes. x86 (and arm)
wintun.dll pack the amd64 and arm64 wintun.dll now, and use rundll32 to
create a native process to do the job where required.
Signed-off-by: Simon Rozman <simon@rozman.si>
-rw-r--r-- | api/adapter.c | 164 | ||||
-rw-r--r-- | api/api.vcxproj | 6 | ||||
-rw-r--r-- | api/resources.rc | 7 |
3 files changed, 166 insertions, 11 deletions
diff --git a/api/adapter.c b/api/adapter.c index 7f2824a..57d7ce4 100644 --- a/api/adapter.c +++ b/api/adapter.c @@ -9,8 +9,20 @@ #define WAIT_FOR_REGISTRY_TIMEOUT 10000 /* ms */ #define MAX_POOL_DEVICE_TYPE (MAX_POOL + 8) /* Should accommodate a pool name with " Tunnel" appended */ +#if defined(_M_IX86) +# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_I386 +#elif defined(_M_AMD64) +# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_AMD64 +#elif defined(_M_ARM) +# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARMNT +#elif defined(_M_ARM64) +# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARM64 +#else +# error Unsupported architecture +#endif static _locale_t Locale; +static USHORT NativeMachine = IMAGE_FILE_PROCESS; WINTUN_STATUS AdapterGetDrvInfoDetail( @@ -324,6 +336,22 @@ void AdapterInit() { Locale = _wcreate_locale(LC_ALL, L""); + +#if defined(_M_IX86) || defined(_M_ARM) + typedef BOOL(WINAPI * IsWow64Process2_t)( + _In_ HANDLE hProcess, _Out_ USHORT * pProcessMachine, _Out_opt_ USHORT * pNativeMachine); + HANDLE Kernel32; + IsWow64Process2_t IsWow64Process2; + USHORT ProcessMachine; + if ((Kernel32 = GetModuleHandleW(L"kernel32.dll")) == NULL || + (IsWow64Process2 = (IsWow64Process2_t)GetProcAddress(Kernel32, "IsWow64Process2")) == NULL || + !IsWow64Process2(GetCurrentProcess(), &ProcessMachine, &NativeMachine)) + { + BOOL IsWoW64; + NativeMachine = + IsWow64Process(GetCurrentProcess(), &IsWoW64) && IsWoW64 ? IMAGE_FILE_MACHINE_AMD64 : IMAGE_FILE_PROCESS; + } +#endif } void @@ -1203,15 +1231,9 @@ cleanupMutex: return Result; } -WINTUN_STATUS WINAPI -WintunCreateAdapter( - _In_z_count_c_(MAX_POOL) const WCHAR *Pool, - _In_z_count_c_(MAX_ADAPTER_NAME) const WCHAR *Name, - _In_opt_ const GUID *RequestedGUID, - _Out_ WINTUN_ADAPTER **Adapter, - _Inout_ BOOL *RebootRequired) +static WINTUN_STATUS +CreateTemporaryDirectory(_Out_cap_c_(MAX_PATH) WCHAR *RandomTempSubDirectory) { -#if defined(HAVE_EV) || defined(HAVE_WHQL) WCHAR WindowsDirectory[MAX_PATH]; if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory))) return LOG_LAST_ERROR(L"Failed to get Windows folder"); @@ -1219,19 +1241,121 @@ WintunCreateAdapter( if (!PathCombineW(WindowsTempDirectory, WindowsDirectory, L"Temp")) return ERROR_BUFFER_OVERFLOW; UCHAR RandomBytes[32] = { 0 }; -# pragma warning(suppress : 6387) +#pragma warning(suppress : 6387) if (!RtlGenRandom(RandomBytes, sizeof(RandomBytes))) return LOG_LAST_ERROR(L"Failed to generate random"); WCHAR RandomSubDirectory[sizeof(RandomBytes) * 2 + 1]; for (int i = 0; i < sizeof(RandomBytes); ++i) swprintf_s(&RandomSubDirectory[i * 2], 3, L"%02x", RandomBytes[i]); - WCHAR RandomTempSubDirectory[MAX_PATH]; if (!PathCombineW(RandomTempSubDirectory, WindowsTempDirectory, RandomSubDirectory)) return ERROR_BUFFER_OVERFLOW; if (!CreateDirectoryW(RandomTempSubDirectory, SecurityAttributes)) return LOG_LAST_ERROR(L"Failed to create temporary folder"); + return ERROR_SUCCESS; +} + +#if defined(_M_IX86) || defined(_M_ARM) + +static WINTUN_STATUS +ExecuteRunDll32(_In_z_ const WCHAR *Arguments) +{ + 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; + } + if ((Result = ResourceCopyToFile( + DllPath, NativeMachine == IMAGE_FILE_MACHINE_ARM64 ? L"wintun-arm64.dll" : L"wintun-amd64.dll")) != + ERROR_SUCCESS) + { + LOG(WINTUN_LOG_ERR, L"Failed to copy resource"); + goto cleanupDelete; + } + HANDLE Heap = GetProcessHeap(); + size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1; + WCHAR *CommandLine = HeapAlloc(Heap, 0, CommandLineLen * sizeof(WCHAR)); + if (!CommandLine) + { + LOG(WINTUN_LOG_ERR, L"Out of memory"); + Result = ERROR_OUTOFMEMORY; + goto cleanupDelete; + } + _snwprintf_s(CommandLine, CommandLineLen, _TRUNCATE, L"rundll32 \"%.*s\",%s", MAX_PATH, DllPath, Arguments); + /* TODO: Create stdio pipes to intercept logged messages. */ + STARTUPINFOW si = { .cb = sizeof(STARTUPINFO), .dwFlags = STARTF_USESHOWWINDOW, .wShowWindow = SW_HIDE }; + PROCESS_INFORMATION pi; + if (!CreateProcessW(RunDll32Path, CommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + { + Result = LOG_LAST_ERROR(L"Creating process failed"); + goto cleanupCommandLine; + } + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); +cleanupCommandLine: + HeapFree(Heap, 0, CommandLine); +cleanupDelete: + DeleteFileW(DllPath); +cleanupDirectory: + RemoveDirectoryW(RandomTempSubDirectory); + return Result; +} + +#endif +WINTUN_STATUS WINAPI +WintunCreateAdapter( + _In_z_count_c_(MAX_POOL) const WCHAR *Pool, + _In_z_count_c_(MAX_ADAPTER_NAME) const WCHAR *Name, + _In_opt_ const GUID *RequestedGUID, + _Out_ WINTUN_ADAPTER **Adapter, + _Inout_ BOOL *RebootRequired) +{ +#if defined(_M_IX86) || defined(_M_ARM) + if (NativeMachine != IMAGE_FILE_PROCESS) + { + LOG(WINTUN_LOG_INFO, L"Spawning native process for the job"); + WCHAR RequestedGUIDStr[MAX_GUID_STRING_LEN]; + WCHAR Arguments[15 + MAX_POOL + 3 + MAX_ADAPTER_NAME + 2 + MAX_GUID_STRING_LEN + 1]; + _snwprintf_s( + Arguments, + _countof(Arguments), + _TRUNCATE, + RequestedGUID ? L"CreateAdapter \"%.*s\" \"%.*s\" %.*s" : L"CreateAdapter \"%.*s\" \"%.*s\"", + MAX_POOL, + Pool, + MAX_ADAPTER_NAME, + Name, + RequestedGUID ? StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr)) : 0, + RequestedGUIDStr); + DWORD Result = ExecuteRunDll32(Arguments); + if (Result != ERROR_SUCCESS) + { + LOG(WINTUN_LOG_ERR, L"Error executing worker process"); + return Result; + } + return WintunGetAdapter(Pool, Name, Adapter); + } +#endif + +#if defined(HAVE_EV) || defined(HAVE_WHQL) DWORD Result = ERROR_SUCCESS; + WCHAR RandomTempSubDirectory[MAX_PATH]; + if ((Result = CreateTemporaryDirectory(RandomTempSubDirectory)) != ERROR_SUCCESS) + return LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder"), Result; + WCHAR CatPath[MAX_PATH] = { 0 }; WCHAR SysPath[MAX_PATH] = { 0 }; WCHAR InfPath[MAX_PATH] = { 0 }; @@ -1278,6 +1402,26 @@ cleanupDirectory: WINTUN_STATUS WINAPI WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _Inout_ BOOL *RebootRequired) { +#if defined(_M_IX86) || defined(_M_ARM) + if (NativeMachine != IMAGE_FILE_PROCESS) + { + LOG(WINTUN_LOG_INFO, L"Spawning native process for the job"); + WCHAR GuidStr[MAX_GUID_STRING_LEN]; + WCHAR Arguments[14 + MAX_GUID_STRING_LEN + 1]; + _snwprintf_s( + Arguments, + _countof(Arguments), + _TRUNCATE, + L"DeleteAdapter %.*s", + StringFromGUID2(&Adapter->CfgInstanceID, GuidStr, _countof(GuidStr)), + GuidStr); + DWORD Result = ExecuteRunDll32(Arguments); + if (Result != ERROR_SUCCESS) + LOG(WINTUN_LOG_ERR, L"Error executing worker process"); + return Result; + } +#endif + HDEVINFO DevInfo; SP_DEVINFO_DATA DevInfoData; DWORD Result = GetDevInfoData(&Adapter->CfgInstanceID, &DevInfo, &DevInfoData); diff --git a/api/api.vcxproj b/api/api.vcxproj index 71cfd66..eb5c7eb 100644 --- a/api/api.vcxproj +++ b/api/api.vcxproj @@ -149,9 +149,13 @@ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> </ClCompile> <ResourceCompile> - <AdditionalIncludeDirectories>..\$(Configuration)\$(WintunPlatform);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\$(Configuration)\$(WintunPlatform);..\$(Configuration);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions Condition="'$(Platform)'=='Win32' Or '$(Platform)'=='x64' Or '$(Configuration)|$(Platform)'=='Debug|ARM64'">HAVE_EV;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions Condition="Exists('$(OutDir)whql\')">HAVE_WHQL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Platform)'=='Win32'">_M_IX86=600;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Platform)'=='x64'">_M_AMD64=100;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Platform)'=='ARM'">_M_ARM=7;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Platform)'=='ARM64'">_M_ARM64=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ResourceCompile> <Link> <AdditionalDependencies>Bcrypt.lib;Cfgmgr32.lib;Crypt32.lib;Iphlpapi.lib;newdev.lib;ntdll.lib;Setupapi.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> diff --git a/api/resources.rc b/api/resources.rc index efcd47b..e2abe18 100644 --- a/api/resources.rc +++ b/api/resources.rc @@ -18,6 +18,13 @@ wintun-whql.inf RCDATA "whql\\wintun.inf" wintun-whql.sys RCDATA "whql\\wintun.sys" #endif +#if defined(_M_IX86) +wintun-amd64.dll RCDATA "amd64\\wintun.dll" +#endif +#if defined(_M_IX86) || defined(_M_ARM) +wintun-arm64.dll RCDATA "arm64\\wintun.dll" +#endif + #define STRINGIZE(x) #x #define EXPAND(x) STRINGIZE(x) |