diff options
Diffstat (limited to 'api/rundll32.c')
-rw-r--r-- | api/rundll32.c | 321 |
1 files changed, 63 insertions, 258 deletions
diff --git a/api/rundll32.c b/api/rundll32.c index 37d4387..6bdc7c9 100644 --- a/api/rundll32.c +++ b/api/rundll32.c @@ -15,134 +15,6 @@ #include <objbase.h> #include <assert.h> -#ifdef ACCEPT_WOW64 - -# define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) - -static DWORD -WriteFormatted(_In_ DWORD StdHandle, _In_z_ LPCWSTR Template, ...) -{ - LPWSTR FormattedMessage = NULL; - DWORD Size; - va_list Arguments; - va_start(Arguments, Template); - DWORD Len = FormatMessageW( - FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, - Template, - 0, - 0, - (VOID *)&FormattedMessage, - 0, - &Arguments); - if (SUCCEEDED(DWordMult(Len, sizeof(*FormattedMessage), &Size))) - WriteFile(GetStdHandle(StdHandle), FormattedMessage, Size, &Size, NULL); - else - Size = 0; - LocalFree(FormattedMessage); - va_end(Arguments); - return Size / sizeof(*FormattedMessage); -} - -static VOID CALLBACK -ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine) -{ - LPCWSTR Template; - switch (Level) - { - case WINTUN_LOG_INFO: - Template = L"[+] %1\n"; - break; - case WINTUN_LOG_WARN: - Template = L"[-] %1\n"; - break; - case WINTUN_LOG_ERR: - Template = L"[!] %1\n"; - break; - default: - return; - } - WriteFormatted(STD_ERROR_HANDLE, Template, LogLine); -} - -VOID __stdcall CreateAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) -{ -# pragma EXPORT - - int Argc; - LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); - WintunSetLogger(ConsoleLogger); - - if (Argc < 4) - goto cleanup; - if (wcslen(Argv[2]) >= WINTUN_MAX_POOL) - goto cleanup; - if (wcslen(Argv[3]) >= MAX_ADAPTER_NAME) - goto cleanup; - GUID RequestedGUID; - if (Argc > 4 && FAILED(CLSIDFromString(Argv[4], &RequestedGUID))) - goto cleanup; - - BOOL RebootRequired; - WINTUN_ADAPTER *Adapter = WintunCreateAdapter(Argv[2], Argv[3], Argc > 4 ? &RequestedGUID : NULL, &RebootRequired); - DWORD LastError = Adapter ? ERROR_SUCCESS : GetLastError(); - WriteFormatted( - STD_OUTPUT_HANDLE, L"%1!X! %2!s! %3!X!", LastError, Adapter ? Adapter->DevInstanceID : L"\"\"", RebootRequired); - if (Adapter) - WintunFreeAdapter(Adapter); - -cleanup: - LocalFree(Argv); -} - -VOID __stdcall DeleteAdapter(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) -{ -# pragma EXPORT - - int Argc; - LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); - WintunSetLogger(ConsoleLogger); - - if (Argc < 4) - goto cleanup; - - DWORD LastError; - BOOL RebootRequired = FALSE; - WINTUN_ADAPTER *Adapter = AdapterOpenFromDevInstanceId(Argv[2], Argv[3]); - if (!Adapter) - { - LastError = GetLastError(); - goto write; - } - BOOL ForceCloseSessions = wcstoul(Argv[4], NULL, 10); - LastError = WintunDeleteAdapter(Adapter, ForceCloseSessions, &RebootRequired) ? ERROR_SUCCESS : GetLastError(); - WintunFreeAdapter(Adapter); -write: - WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired); - -cleanup: - LocalFree(Argv); -} - -VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) -{ -# pragma EXPORT - - int Argc; - LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); - WintunSetLogger(ConsoleLogger); - - if (Argc < 2) - goto cleanup; - - BOOL RebootRequired; - DWORD LastError = WintunDeletePoolDriver(Argv[2], &RebootRequired) ? ERROR_SUCCESS : GetLastError(); - WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", LastError, RebootRequired); - -cleanup: - LocalFree(Argv); -} -#endif - #ifdef MAYBE_WOW64 _Return_type_success_(return != FALSE) @@ -265,52 +137,23 @@ ProcessStdout(_Inout_ PROCESS_STDOUT_STATE *State) 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; + WCHAR Msg[0x200], Buf[0x220], LevelRune; + DWORD64 Timestamp; + DWORD SizeRead; + WINTUN_LOGGER_LEVEL Level; for (;;) { - WCHAR Buf[0x200]; - DWORD SizeRead; - if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL)) + if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL) || !SizeRead) return ERROR_SUCCESS; if (SizeRead % sizeof(*Buf)) return ERROR_INVALID_DATA; - SizeRead /= sizeof(*Buf); - 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; - LoggerLog(Level, NULL, Msg); - State = OnNone; - Count = 0; - } - } + Msg[0] = Buf[SizeRead / sizeof(*Buf) - 1] = L'\0'; + if (swscanf_s(Buf, L"[%c %I64u] %[^\n]", &LevelRune, 1, &Timestamp, Msg, (DWORD)_countof(Msg)) != 3 || !Msg[0]) + return ERROR_INVALID_DATA; + if (!((Level = WINTUN_LOG_INFO, LevelRune == L'+') || (Level = WINTUN_LOG_WARN, LevelRune == L'-') || + (Level = WINTUN_LOG_ERR, LevelRune == L'!'))) + return ERROR_INVALID_DATA; + Logger(Level, Timestamp, Msg); } } @@ -343,7 +186,7 @@ ExecuteRunDll32( return FALSE; } WCHAR DllPath[MAX_PATH] = { 0 }; - if (!PathCombineW(DllPath, RandomTempSubDirectory, L"wintun.dll")) + if (!PathCombineW(DllPath, RandomTempSubDirectory, L"setupapihost.dll")) { LastError = ERROR_BUFFER_OVERFLOW; goto cleanupDirectory; @@ -352,10 +195,10 @@ ExecuteRunDll32( switch (NativeMachine) { case IMAGE_FILE_MACHINE_AMD64: - WintunDllResourceName = L"wintun-amd64.dll"; + WintunDllResourceName = L"setupapihost-amd64.dll"; break; case IMAGE_FILE_MACHINE_ARM64: - WintunDllResourceName = L"wintun-arm64.dll"; + WintunDllResourceName = L"setupapihost-arm64.dll"; break; default: LOG(WINTUN_LOG_ERR, L"Unsupported platform 0x%x", NativeMachine); @@ -444,9 +287,9 @@ cleanupThreads: WaitForSingleObject(ThreadStdout, INFINITE); DWORD ThreadResult; if (!GetExitCodeThread(ThreadStdout, &ThreadResult)) - LOG_LAST_ERROR(L"Failed to retrieve stdout reader result"); + LastError = LOG_LAST_ERROR(L"Failed to retrieve stdout reader result"); else if (ThreadResult != ERROR_SUCCESS) - LOG_ERROR(LastError, L"Failed to read process output"); + LastError = LOG_ERROR(ThreadResult, L"Failed to read process output"); CloseHandle(ThreadStdout); } cleanupPipes: @@ -462,132 +305,94 @@ cleanupDirectory: return RET_ERROR(TRUE, LastError); } -_Use_decl_annotations_ -WINTUN_ADAPTER * -CreateAdapterViaRundll32(LPCWSTR Pool, LPCWSTR Name, const GUID *RequestedGUID, BOOL *RebootRequired) +static _Return_type_success_(return != FALSE) +BOOL +InvokeClassInstaller(_In_ LPCWSTR Action, _In_ LPCWSTR Function, _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) { - LOG(WINTUN_LOG_INFO, L"Spawning native process"); - LPWSTR Arguments = NULL; - if (RequestedGUID) + LOG(WINTUN_LOG_INFO, L"Spawning native process to %s instance", Action); + + WCHAR InstanceId[MAX_INSTANCE_ID]; + DWORD RequiredChars = _countof(InstanceId); + if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredChars, &RequiredChars)) { - WCHAR RequestedGUIDStr[MAX_GUID_STRING_LEN]; - if (StringFromGUID2(RequestedGUID, RequestedGUIDStr, _countof(RequestedGUIDStr))) - Arguments = ArgvToCommandLineW(3, Pool, Name, RequestedGUIDStr); + LOG_LAST_ERROR(L"Failed to get adapter instance ID"); + return FALSE; } - else - Arguments = ArgvToCommandLineW(2, Pool, Name); + LPWSTR Arguments = ArgvToCommandLineW(1, InstanceId); if (!Arguments) { - LOG(WINTUN_LOG_ERR, L"Command line too long"); - SetLastError(ERROR_INVALID_PARAMETER); - return NULL; + SetLastError(LOG_ERROR(ERROR_INVALID_PARAMETER, L"Command line too long")); + return FALSE; } - WINTUN_ADAPTER *Adapter = NULL; DWORD LastError; - WCHAR Response[8 + 1 + MAX_GUID_STRING_LEN + 1 + 8 + 1]; - if (!ExecuteRunDll32(L"CreateAdapter", Arguments, Response, _countof(Response))) + WCHAR Response[8 + 1]; + if (!ExecuteRunDll32(Function, Arguments, Response, _countof(Response))) { - LastError = GetLastError(); - LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments); + LastError = LOG_LAST_ERROR(L"Error executing worker process: %s", Arguments); goto cleanupArguments; } int Argc; LPWSTR *Argv = CommandLineToArgvW(Response, &Argc); - if (Argc < 3) + if (Argc < 1) { - LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response); - LastError = ERROR_INVALID_PARAMETER; + LastError = LOG_ERROR(ERROR_INVALID_PARAMETER, L"Incomplete response: %s", Response); goto cleanupArgv; } LastError = wcstoul(Argv[0], NULL, 16); - if (LastError == ERROR_SUCCESS && (Adapter = AdapterOpenFromDevInstanceId(Pool, Argv[1])) == NULL) - { - LOG(WINTUN_LOG_ERR, L"Failed to get adapter %s", Argv[1]); - LastError = ERROR_FILE_NOT_FOUND; - } - if (wcstoul(Argv[2], NULL, 16)) - *RebootRequired = TRUE; cleanupArgv: LocalFree(Argv); cleanupArguments: Free(Arguments); - SetLastError(LastError); - return Adapter; + return RET_ERROR(TRUE, LastError); } _Use_decl_annotations_ BOOL -DeleteAdapterViaRundll32(const WINTUN_ADAPTER *Adapter, BOOL ForceCloseSessions, BOOL *RebootRequired) +RemoveInstanceViaRundll32(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData) { - LOG(WINTUN_LOG_INFO, L"Spawning native process"); - LPWSTR Arguments = ArgvToCommandLineW(3, Adapter->Pool, Adapter->DevInstanceID, ForceCloseSessions ? L"1" : L"0"); - if (!Arguments) - { - LOG(WINTUN_LOG_ERR, L"Command line too long"); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - WCHAR Response[8 + 1 + 8 + 1]; - DWORD LastError; - if (!ExecuteRunDll32(L"DeleteAdapter", Arguments, Response, _countof(Response))) - { - LastError = GetLastError(); - LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments); - goto cleanupArguments; - } - int Argc; - LPWSTR *Argv = CommandLineToArgvW(Response, &Argc); - if (Argc < 2) - { - LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response); - LastError = ERROR_INVALID_PARAMETER; - goto cleanupArgv; - } - LastError = wcstoul(Argv[0], NULL, 16); - if (wcstoul(Argv[1], NULL, 16)) - *RebootRequired = TRUE; -cleanupArgv: - LocalFree(Argv); -cleanupArguments: - Free(Arguments); - return RET_ERROR(TRUE, LastError); + return InvokeClassInstaller(L"remove", L"RemoveInstance", DevInfo, DevInfoData); } _Use_decl_annotations_ BOOL -DeletePoolDriverViaRundll32(LPCWSTR Pool, BOOL *RebootRequired) +EnableInstanceViaRundll32(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData) { - LOG(WINTUN_LOG_INFO, L"Spawning native process"); - LPWSTR Arguments = ArgvToCommandLineW(1, Pool); - if (!Arguments) - { - LOG(WINTUN_LOG_ERR, L"Command line too long"); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - WCHAR Response[8 + 1 + 8 + 1]; + return InvokeClassInstaller(L"enable", L"EnableInstance", DevInfo, DevInfoData); +} + +_Use_decl_annotations_ +BOOL +DisableInstanceViaRundll32(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData) +{ + return InvokeClassInstaller(L"disable", L"DisableInstance", DevInfo, DevInfoData); +} + +_Use_decl_annotations_ +BOOL +CreateInstanceWin7ViaRundll32(LPWSTR InstanceId) +{ + LOG(WINTUN_LOG_INFO, L"Spawning native process to create instance"); + DWORD LastError; - if (!ExecuteRunDll32(L"DeletePoolDriver", Arguments, Response, _countof(Response))) + WCHAR Response[MAX_INSTANCE_ID + 1]; + if (!ExecuteRunDll32(L"CreateInstanceWin7", L"", Response, _countof(Response))) { - LastError = GetLastError(); - LOG(WINTUN_LOG_ERR, L"Error executing worker process: %s", Arguments); - goto cleanupArguments; + LastError = LOG_LAST_ERROR(L"Error executing worker process"); + goto cleanup; } int Argc; LPWSTR *Argv = CommandLineToArgvW(Response, &Argc); if (Argc < 2) { - LOG(WINTUN_LOG_ERR, L"Incomplete response: %s", Response); - LastError = ERROR_INVALID_PARAMETER; + LastError = LOG_ERROR(ERROR_INVALID_PARAMETER, L"Incomplete response: %s", Response); goto cleanupArgv; } LastError = wcstoul(Argv[0], NULL, 16); - if (wcstoul(Argv[1], NULL, 16)) - *RebootRequired = TRUE; + if (LastError == ERROR_SUCCESS) + wcsncpy_s(InstanceId, MAX_INSTANCE_ID, Argv[1], _TRUNCATE); cleanupArgv: LocalFree(Argv); -cleanupArguments: - Free(Arguments); +cleanup: return RET_ERROR(TRUE, LastError); } #endif |