diff --git a/appveyor.yml b/appveyor.yml index 3451df3..54520db 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,6 +28,8 @@ after_build: cd "%APPVEYOR_BUILD_FOLDER%\wufuc_setup_bat" + echo %BUILD_COMMIT_VERSION% >version.txt + for /R %%i in (*.txt) do unix2dos "%%i" for /R %%i in (*.bat) do unix2dos "%%i" diff --git a/wufuc/callbacks.c b/wufuc/callbacks.c index 663e3da..73972e3 100644 --- a/wufuc/callbacks.c +++ b/wufuc/callbacks.c @@ -3,12 +3,59 @@ #include "hooks.h" #include "helpers.h" +bool DuplicateContextHandles(HANDLE hSrcProcess, ContextHandles *pSrcContext, HANDLE hAuxiliaryMutex, HANDLE hTargetProcess, ContextHandles *pTargetContext) +{ + if ( DuplicateHandle(hSrcProcess, pSrcContext->hMainMutex, + hTargetProcess, &pTargetContext->hMainMutex, SYNCHRONIZE, FALSE, 0) + + && DuplicateHandle(hSrcProcess, pSrcContext->hUnloadEvent, + hTargetProcess, &pTargetContext->hUnloadEvent, SYNCHRONIZE, FALSE, 0) + + && DuplicateHandle(hSrcProcess, hAuxiliaryMutex, + hTargetProcess, &pTargetContext->hAuxiliaryMutex, 0, FALSE, DUPLICATE_SAME_ACCESS) ) { + + return true; + } + return false; +} + VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer) { + HANDLE hProcess; + wchar_t MutexName[37]; + HANDLE hAuxiliaryMutex; + ContextHandles TargetContext; + switch ( pNotifyBuffer->dwNotificationStatus ) { case ERROR_SUCCESS: - if ( pNotifyBuffer->ServiceStatus.dwProcessId ) - InjectSelfAndCreateRemoteThread(pNotifyBuffer->ServiceStatus.dwProcessId, &StartAddress, (HANDLE)pNotifyBuffer->pContext, SYNCHRONIZE); + if ( !pNotifyBuffer->ServiceStatus.dwProcessId + || swprintf_s(MutexName, _countof(MutexName), L"Global\\wufuc_AuxiliaryMutex*%08X", pNotifyBuffer->ServiceStatus.dwProcessId) == -1 + || !InitializeMutex(false, MutexName, &hAuxiliaryMutex) ) + break; + + hProcess = OpenProcess(PROCESS_ALL_ACCESS, + FALSE, + pNotifyBuffer->ServiceStatus.dwProcessId); + if ( !hProcess ) { + trace(L"Failed to open target process! (GetLastError=%lu)", GetLastError()); + break; + }; + + if ( !DuplicateContextHandles(GetCurrentProcess(), pNotifyBuffer->pContext, hAuxiliaryMutex, hProcess, &TargetContext) ) { + trace(L"Failed to duplicate handles into target process." + L"%p %p %p (GetLastError=%lu)", + TargetContext.hMainMutex, + TargetContext.hUnloadEvent, + TargetContext.hAuxiliaryMutex, + GetLastError()); + break; + }; + InjectLibraryAndCreateRemoteThread( + hProcess, + PIMAGEBASE, + StartAddress, + &TargetContext, + sizeof TargetContext); break; case ERROR_SERVICE_MARKED_FOR_DELETE: SetEvent((HANDLE)pNotifyBuffer->pContext); @@ -20,65 +67,100 @@ VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer) DWORD WINAPI StartAddress(LPVOID pParam) { + ContextHandles ctx; SC_HANDLE hSCM; - DWORD cbBufSize; - LPQUERY_SERVICE_CONFIGW pServiceConfig; - DWORD dwServiceType; - int result; + DWORD dwProcessId; DWORD cbData; - LPWSTR pServiceDll; HMODULE hModule; + DWORD result; + + // get mutex and unload event handles from virtual memory + if ( !pParam ) { + trace(L"Context parameter is null!"); + goto unload; + } + ctx = *(ContextHandles *)pParam; + if ( !VirtualFree(pParam, 0, MEM_RELEASE) ) + trace(L"Failed to free context parameter. pParam=%p GetLastError=%lu", + pParam, GetLastError()); + + // acquire child mutex, should be immediate. + if ( WaitForSingleObject(ctx.hAuxiliaryMutex, 5000) != WAIT_OBJECT_0 ) { + trace(L"Failed to acquire aux mutex within five seconds. hAuxiliaryMutex=%p", ctx.hAuxiliaryMutex); + goto close_handles; + } hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); - if ( !hSCM ) goto cleanup; + if ( !hSCM ) { + trace(L"Failed to open SCM. (GetLastError=%ul)", GetLastError()); + goto release; + } - pServiceConfig = QueryServiceConfigByNameAlloc(hSCM, L"wuauserv", &cbBufSize); + dwProcessId = QueryServiceProcessId(hSCM, L"wuauserv"); CloseServiceHandle(hSCM); - if ( !pServiceConfig ) goto cleanup; + if ( dwProcessId != GetCurrentProcessId() ) { + trace(L"Injected into wrong process! CurrentProcessId=%lu wuauserv ProcessId=%lu", + GetCurrentProcessId, dwProcessId); + goto release; + } - //dwServiceType = pServiceConfig->dwServiceType; - result = _wcsicmp(pServiceConfig->lpBinaryPathName, GetCommandLineW()); - free(pServiceConfig); - if ( result ) goto cleanup; + // hook IsDeviceServiceable + g_pszWUServiceDll = RegGetValueAlloc(HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\services\\wuauserv\\Parameters", + L"ServiceDll", + RRF_RT_REG_SZ, + NULL, + &cbData); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); - // hook apis if configured as shared service - /* if ( dwServiceType == SERVICE_WIN32_SHARE_PROCESS ) { - g_pfnLoadLibraryExW = DetourFindFunction("kernel32.dll", "LoadLibraryExW"); + // hook LoadLibraryExW + g_pfnLoadLibraryExW = DetourFindFunction("kernel32.dll", "LoadLibraryExW"); + if ( g_pfnLoadLibraryExW ) DetourAttach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook); - g_pfnRegQueryValueExW = DetourFindFunction("kernel32.dll", "RegQueryValueExW"); - DetourAttach(&(PVOID)g_pfnRegQueryValueExW, RegQueryValueExW_hook); - }*/ + if ( g_pszWUServiceDll ) { + hModule = GetModuleHandleW(g_pszWUServiceDll); + if ( hModule && FindIsDeviceServiceablePtr(hModule, + &(PVOID)g_pfnIsDeviceServiceable) ) { - // hook IsDeviceServiceable if wuaueng.dll is already loaded - pServiceDll = RegGetValueAlloc(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\services\\wuauserv\\Parameters", L"ServiceDll", RRF_RT_REG_SZ, NULL, &cbData); - if ( pServiceDll ) { - hModule = GetModuleHandleW(pServiceDll); - if ( hModule && FindIsDeviceServiceablePtr(pServiceDll, hModule, &(PVOID)g_pfnIsDeviceServiceable) ) DetourAttach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook); - - free(pServiceDll); + } } DetourTransactionCommit(); - // wait for unload event - WaitForSingleObject((HANDLE)pParam, INFINITE); - // unhook functions - trace(L"DetourTransactionBegin result=%d", DetourTransactionBegin()); - trace(L"DetourUpdateThread result=%d", DetourUpdateThread(GetCurrentThread())); - //if ( g_pfnLoadLibraryExW ) - // trace(L"DetourDetach LoadLibraryExW_hook result=%d", DetourDetach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook)); - //if ( g_pfnRegQueryValueExW ) - // trace(L"DetourDetach RegQueryValueExW_hook result=%d", DetourDetach(&(PVOID)g_pfnRegQueryValueExW, RegQueryValueExW_hook)); - if ( g_pfnIsDeviceServiceable ) - trace(L"DetourDetach IsDeviceServiceable_hook result=%d", DetourDetach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook)); - trace(L"DetourTransactionCommit result=%d", DetourTransactionCommit()); + // wait for unload event or parent mutex to be abandoned. + // for example if the user killed rundll32.exe with task manager. + // intentionally leave parent mutex open until this thread ends, at + // which point it becomes abandoned again. + result = WaitForMultipleObjects(_countof(ctx.handles), ctx.handles, FALSE, INFINITE); -cleanup: - CloseHandle((HANDLE)pParam); + trace(L"Unloading!"); + + // unhook + if ( g_pfnLoadLibraryExW || g_pfnIsDeviceServiceable ) { + trace(L"Removing hooks..."); + trace(L"DetourTransactionBegin %lu", DetourTransactionBegin()); + trace(L"DetourUpdateThread %lu", DetourUpdateThread(GetCurrentThread())); + + if ( g_pfnLoadLibraryExW ) + trace(L"DetourDetach LoadLibraryExW %lu", DetourDetach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook)); + + if ( g_pfnIsDeviceServiceable ) + trace(L"DetourDetach IsDeviceServiceable %lu", DetourDetach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook)); + + trace(L"DetourTransactionCommit %lu", DetourTransactionCommit()); + } + free(g_pszWUServiceDll); + +release: + ReleaseMutex(ctx.hAuxiliaryMutex); +close_handles: + CloseHandle(ctx.hAuxiliaryMutex); + CloseHandle(ctx.hMainMutex); + CloseHandle(ctx.hUnloadEvent); +unload: FreeLibraryAndExitThread(PIMAGEBASE, 0); } \ No newline at end of file diff --git a/wufuc/callbacks.h b/wufuc/callbacks.h index 244008e..ce8013d 100644 --- a/wufuc/callbacks.h +++ b/wufuc/callbacks.h @@ -1,4 +1,25 @@ #pragma once +#pragma pack(push, 1) +typedef struct +{ + HANDLE hAuxiliaryMutex; + union + { + struct + { + HANDLE hMainMutex; + HANDLE hUnloadEvent; + } DUMMYSTRUCTNAME; + struct + { + HANDLE hMainMutex; + HANDLE hUnloadEvent; + } u; + HANDLE handles[2]; + }; +} ContextHandles; +#pragma pack(pop) + VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer); DWORD WINAPI StartAddress(LPVOID pParam); diff --git a/wufuc/dllmain.c b/wufuc/dllmain.c index 09f5e54..209d8e1 100644 --- a/wufuc/dllmain.c +++ b/wufuc/dllmain.c @@ -7,7 +7,9 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv break; case DLL_PROCESS_DETACH: break; - default: + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: break; } return TRUE; diff --git a/wufuc/exports.def b/wufuc/exports.def index 73ff4cb..66441e4 100644 --- a/wufuc/exports.def +++ b/wufuc/exports.def @@ -1,5 +1,5 @@ LIBRARY EXPORTS - RUNDLL32_StartW @3 - RUNDLL32_UnloadW @4 - RUNDLL32_DeleteFileW @5 + RUNDLL32_StartW @1 + RUNDLL32_UnloadW @2 + RUNDLL32_DeleteFileW @3 diff --git a/wufuc/helpers.c b/wufuc/helpers.c index 5625416..fc6928a 100644 --- a/wufuc/helpers.c +++ b/wufuc/helpers.c @@ -3,59 +3,47 @@ #include "hooks.h" #include -bool CreateExclusiveMutex(const wchar_t *name, HANDLE *pmutex) +bool InitializeMutex(bool InitialOwner, const wchar_t *pMutexName, HANDLE *phMutex) { - HANDLE mutex; + HANDLE hMutex; - mutex = CreateMutexW(NULL, TRUE, name); - if ( mutex ) { + hMutex = CreateMutexW(NULL, InitialOwner, pMutexName); + if ( hMutex ) { if ( GetLastError() == ERROR_ALREADY_EXISTS ) { - CloseHandle(mutex); + CloseHandle(hMutex); return false; } - *pmutex = mutex; + *phMutex = hMutex; return true; } return false; } -bool CreateEventWithStringSecurityDescriptor(const wchar_t *descriptor, bool manualreset, bool initialstate, const wchar_t *name, HANDLE *pevent) +bool CreateEventWithStringSecurityDescriptor( + const wchar_t *pStringSecurityDescriptor, + bool ManualReset, + bool InitialState, + const wchar_t *pName, + HANDLE *phEvent) { SECURITY_ATTRIBUTES sa = { sizeof sa }; HANDLE event; - if ( ConvertStringSecurityDescriptorToSecurityDescriptorW(descriptor, SDDL_REVISION_1, &sa.lpSecurityDescriptor, NULL) ) { - event = CreateEventW(&sa, manualreset, initialstate, name); + if ( ConvertStringSecurityDescriptorToSecurityDescriptorW( + pStringSecurityDescriptor, + SDDL_REVISION_1, + &sa.lpSecurityDescriptor, + NULL) ) { + + event = CreateEventW(&sa, ManualReset, InitialState, pName); if ( event ) { - *pevent = event; + *phEvent = event; return true; } } return false; } -bool FileExists(const wchar_t *path) -{ - return GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES; -} - -bool FileExistsExpandEnvironmentStrings(const wchar_t *path) -{ - bool result; - LPWSTR dst; - DWORD buffersize; - DWORD size; - - buffersize = ExpandEnvironmentStringsW(path, NULL, 0); - dst = calloc(buffersize, sizeof *dst); - size = ExpandEnvironmentStringsW(path, dst, buffersize); - if ( !size || size > buffersize ) - return false; - result = FileExists(dst); - free(dst); - return result; -} - int FileInfoVerCompare(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wBuild, WORD wRev) { if ( HIWORD(pffi->dwProductVersionMS) < wMajor ) return -1; @@ -69,140 +57,267 @@ int FileInfoVerCompare(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wB return 0; } -bool FindIsDeviceServiceablePtr(const wchar_t *pFilename, HMODULE hModule, PVOID *ppfnIsDeviceServiceable) +bool GetVersionInfoFromHModule(HMODULE hModule, LPCWSTR pszSubBlock, LPVOID pData, PUINT pcbData) { bool result = false; - DWORD dwLen; - LPVOID pBlock; - PLANGANDCODEPAGE ptl; - UINT cb; - wchar_t SubBlock[38]; - wchar_t *pInternalName; + UINT cbData; + HRSRC hResInfo; + DWORD dwSize; + HGLOBAL hResData; + LPVOID pRes; + LPVOID pCopy; + LPVOID pBuffer; UINT uLen; - VS_FIXEDFILEINFO *pffi; - bool is_win7 = false; - bool is_win81 = false; - size_t n; - char szModule[MAX_PATH]; - LPFN_ISDEVICESERVICEABLE pfnIsDeviceServiceable = NULL; - MODULEINFO modinfo; - const char *pattern; - size_t offset; - dwLen = GetFileVersionInfoSizeW(pFilename, NULL); - if ( !dwLen ) return result; + if ( !pcbData ) return result; + cbData = *pcbData; - pBlock = malloc(dwLen); - if ( !pBlock ) return result; + hResInfo = FindResourceW(hModule, + MAKEINTRESOURCEW(VS_VERSION_INFO), + RT_VERSION); + if ( !hResInfo ) return result; - if ( !GetFileVersionInfoW(pFilename, 0, dwLen, pBlock) - || !VerQueryValueW(pBlock, L"\\VarFileInfo\\Translation", (LPVOID *)&ptl, &cb) ) + dwSize = SizeofResource(hModule, hResInfo); + if ( !dwSize ) return result; + + hResData = LoadResource(hModule, hResInfo); + if ( !hResData ) return result; + + pRes = LockResource(hResData); + if ( !pRes ) return result; + + pCopy = malloc(dwSize); + if ( !pCopy + || memcpy_s(pCopy, dwSize, pRes, dwSize) + || !VerQueryValueW(pCopy, pszSubBlock, &pBuffer, &uLen) ) goto cleanup; - is_win7 = IsWindowsVersion(6, 1, 1); + if ( !_wcsnicmp(pszSubBlock, L"\\StringFileInfo\\", 16) ) + *pcbData = uLen * sizeof(wchar_t); + else + *pcbData = uLen; - if ( !is_win7 ) - is_win81 = IsWindowsVersion(6, 3, 0); - - for ( size_t i = 0; i < (cb / sizeof *ptl); i++ ) { - swprintf_s(SubBlock, _countof(SubBlock), L"\\StringFileInfo\\%04x%04x\\InternalName", - ptl[i].wLanguage, - ptl[i].wCodePage); - - // identify wuaueng.dll by its resource data - if ( !VerQueryValueW(pBlock, SubBlock, (LPVOID *)&pInternalName, &uLen) - || _wcsicmp(pInternalName, L"wuaueng.dll") - || !VerQueryValueW(pBlock, L"\\", (LPVOID *)&pffi, &uLen) ) - continue; - - // assure wuaueng.dll is at least the minimum supported version - if ( (is_win7 && FileInfoVerCompare(pffi, 7, 6, 7601, 23714) != -1) - || (is_win81 && FileInfoVerCompare(pffi, 7, 9, 9600, 18621) != -1) ) { - - // convert pFilename to multibyte string because DetourFindFunction doesn't take wide string - // try resolving with detours helper function first (needs dbghelp.dll and an internet connection) - //if ( !wcstombs_s(&n, szModule, _countof(szModule), pFilename, _TRUNCATE) ) - // pfnIsDeviceServiceable = DetourFindFunction(PathFindFileNameA(szModule), "IsDeviceServiceable"); - - // fall back to byte pattern search if the above method fails - if ( !pfnIsDeviceServiceable - && K32GetModuleInformation(GetCurrentProcess(), hModule, &modinfo, sizeof modinfo) ) { -#ifdef _WIN64 - pattern = "FFF3 4883EC?? 33DB 391D???????? 7508 8B05????????"; -#else - if ( is_win7 ) - pattern = "833D????????00 743E E8???????? A3????????"; - else // if we've reached this point we can assume win 8.1 without checking is_win81 again - pattern = "8BFF 51 833D????????00 7507 A1????????"; -#endif - offset = patternfind(modinfo.lpBaseOfDll, modinfo.SizeOfImage, pattern); - if ( offset != -1 ) - pfnIsDeviceServiceable = (LPFN_ISDEVICESERVICEABLE)((uint8_t *)modinfo.lpBaseOfDll + offset); - } - - if ( pfnIsDeviceServiceable ) { - trace(L"Found IsDeviceServiceable address: %p", pfnIsDeviceServiceable); - *ppfnIsDeviceServiceable = pfnIsDeviceServiceable; - result = true; - } - break; - } + if ( !pData ) { + result = true; + goto cleanup; } + if ( cbData < *pcbData + || memcpy_s(pData, cbData, pBuffer, *pcbData) ) + goto cleanup; + + result = true; cleanup: - free(pBlock); + free(pCopy); return result; } -bool GetRemoteHModuleFromTh32ModuleSnapshot(HANDLE hSnapshot, const wchar_t *pLibFileName, HMODULE *phRemoteModule) +LPVOID GetVersionInfoFromHModuleAlloc(HMODULE hModule, LPCWSTR pszSubBlock, PUINT pcbData) +{ + UINT cbData = 0; + LPVOID result = NULL; + + if ( !GetVersionInfoFromHModule(hModule, pszSubBlock, NULL, &cbData) ) + return result; + + result = malloc(cbData); + if ( !result ) return result; + + if ( GetVersionInfoFromHModule(hModule, pszSubBlock, result, &cbData) ) { + *pcbData = cbData; + } else { + free(result); + result = NULL; + } + return result; +} + +bool FindIsDeviceServiceablePtr(HMODULE hModule, PVOID *ppfnIsDeviceServiceable) +{ + bool result = false; + bool is_win7 = false; + bool is_win81 = false; + PLANGANDCODEPAGE ptl; + HANDLE hProcess; + int tmp; + UINT cbtl; + wchar_t SubBlock[38]; + UINT cbInternalName; + wchar_t *pInternalName; + UINT cbffi; + VS_FIXEDFILEINFO *pffi; + MODULEINFO modinfo; + size_t offset; + + is_win7 = IsWindowsVersion(6, 1, 1); + if ( !is_win7 ) { + is_win81 = IsWindowsVersion(6, 3, 0); + if ( !is_win81 ) { + trace(L"Unsupported operating system. is_win7=%ls is_win81=%ls", + is_win7 ? L"true" : L"false", + is_win81 ? L"true" : L"false"); + return result; + } + } + + ptl = GetVersionInfoFromHModuleAlloc(hModule, L"\\VarFileInfo\\Translation", &cbtl); + if ( !ptl ) { + trace(L"Failed to allocate version translation information from hmodule."); + return result; + } + hProcess = GetCurrentProcess(); + + for ( size_t i = 0, count = (cbtl / sizeof *ptl); i < count; i++ ) { + if ( swprintf_s(SubBlock, + _countof(SubBlock), + L"\\StringFileInfo\\%04x%04x\\InternalName", + ptl[i].wLanguage, + ptl[i].wCodePage) == -1 ) + continue; + + pInternalName = GetVersionInfoFromHModuleAlloc(hModule, SubBlock, &cbInternalName); + if ( !pInternalName ) { + trace(L"Failed to allocate version internal name from hmodule."); + continue; + } + + // identify wuaueng.dll by its resource data + tmp = _wcsicmp(pInternalName, L"wuaueng.dll"); + if ( tmp ) + trace(L"Module internal name does not match. pInternalName=%ls cbInternalName=%lu", pInternalName, cbInternalName); + free(pInternalName); + if ( tmp ) + continue; + + pffi = GetVersionInfoFromHModuleAlloc(hModule, L"\\", &cbffi); + if ( !pffi ) { + trace(L"Failed to allocate version information from hmodule."); + continue; + } + + // assure wuaueng.dll is at least the minimum supported version + tmp = ((is_win7 && FileInfoVerCompare(pffi, 7, 6, 7601, 23714) != -1) + || (is_win81 && FileInfoVerCompare(pffi, 7, 9, 9600, 18621) != -1)); + free(pffi); + if ( !tmp ) { + trace(L"Module does not meet the minimum supported version."); + continue; + } + + if ( !GetModuleInformation(hProcess, hModule, &modinfo, sizeof modinfo) ) + break; + + offset = patternfind(modinfo.lpBaseOfDll, + modinfo.SizeOfImage, +#ifdef _WIN64 + "FFF3 4883EC?? 33DB 391D???????? 7508 8B05????????" +#else + is_win7 + ? "833D????????00 743E E8???????? A3????????" + : "8BFF 51 833D????????00 7507 A1????????" +#endif + ); + if ( offset != -1 ) { + *ppfnIsDeviceServiceable = (PVOID)((uint8_t *)modinfo.lpBaseOfDll + offset); + trace(L"Found IsDeviceServiceable address: %p", *ppfnIsDeviceServiceable); + result = true; + } else { + trace(L"IsDeviceServiceable function pattern not found."); + } + break; + } + free(ptl); + return result; +} + +HANDLE GetRemoteHModuleFromTh32ModuleSnapshot(HANDLE hSnapshot, const wchar_t *pLibFileName) { MODULEENTRY32W me = { sizeof me }; if ( !Module32FirstW(hSnapshot, &me) ) - return false; + return NULL; do { - if ( !_wcsicmp(me.szExePath, pLibFileName) ) { - *phRemoteModule = me.hModule; - return true; - } + if ( !_wcsicmp(me.szExePath, pLibFileName) ) + return me.hModule; } while ( Module32NextW(hSnapshot, &me) ); - return false; + return NULL; } -bool InjectSelfAndCreateRemoteThread(DWORD dwProcessId, LPTHREAD_START_ROUTINE pStartAddress, HANDLE SourceHandle, DWORD dwDesiredAccess) +bool InjectLibraryAndCreateRemoteThread( + HANDLE hProcess, + HMODULE hModule, + LPTHREAD_START_ROUTINE pStartAddress, + const void *pParam, + size_t cbParam) { bool result = false; - HANDLE hProcess; NTSTATUS Status; - HMODULE hRemoteModule; - LPTHREAD_START_ROUTINE pfnTargetStartAddress; - HANDLE TargetHandle = NULL; + LPVOID pBaseAddress = NULL; + SIZE_T cb; + HMODULE hRemoteModule = NULL; HANDLE hThread; - hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); - if ( !hProcess ) return result; - Status = NtSuspendProcess(hProcess); + if ( !NT_SUCCESS(Status) ) return result; + trace(L"Suspended process. hProcess=%p", hProcess); - if ( !NT_SUCCESS(Status) ) goto cleanup; + if ( pParam ) { + // this gets freed by pStartAddress + pBaseAddress = VirtualAllocEx(hProcess, + NULL, + cbParam, + MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE); + if ( !pBaseAddress ) goto resume; - if ( InjectLibraryByLocalHModule(hProcess, PIMAGEBASE, &hRemoteModule) - && (!SourceHandle || DuplicateHandle(GetCurrentProcess(), SourceHandle, hProcess, &TargetHandle, dwDesiredAccess, FALSE, 0)) ) { + if ( !WriteProcessMemory(hProcess, pBaseAddress, pParam, cbParam, &cb) ) + goto vfree; + } + if ( InjectLibrary(hProcess, hModule, &hRemoteModule) ) { + trace(L"Injected library. hRemoteModule=%p", hRemoteModule); - // get pointer to StartAddress in remote process - pfnTargetStartAddress = (LPTHREAD_START_ROUTINE)((uint8_t *)hRemoteModule + ((uint8_t *)pStartAddress - (uint8_t *)PIMAGEBASE)); + hThread = CreateRemoteThread(hProcess, + NULL, + 0, + (LPTHREAD_START_ROUTINE)((uint8_t *)hRemoteModule + ((uint8_t *)pStartAddress - (uint8_t *)hModule)), + pBaseAddress, + 0, + NULL); - hThread = CreateRemoteThread(hProcess, NULL, 0, pfnTargetStartAddress, (LPVOID)TargetHandle, 0, NULL); if ( hThread ) { + trace(L"Created remote thread. hThread=%p", hThread); CloseHandle(hThread); result = true; } } - NtResumeProcess(hProcess); -cleanup: - CloseHandle(hProcess); +vfree: + if ( !result && pBaseAddress ) + VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE); +resume: NtResumeProcess(hProcess); return result; } -bool InjectLibraryByFileName(HANDLE hProcess, const wchar_t *pLibFileName, size_t cchLibFileName, HMODULE *phRemoteModule) +bool InjectLibrary(HANDLE hProcess, HMODULE hModule, HMODULE *phRemoteModule) +{ + WCHAR Filename[MAX_PATH]; + DWORD nLength; + + nLength = GetModuleFileNameW(hModule, Filename, _countof(Filename)); + if ( nLength ) { + trace(L"Got module filename for local module. " + L"hModule=%p Filename=%ls nLength=%lu", + hModule, Filename, nLength); + return InjectLibraryByFilename(hProcess, + Filename, + nLength, + phRemoteModule); + } + return false; +} + +bool InjectLibraryByFilename( + HANDLE hProcess, + const wchar_t *pLibFilename, + size_t cchLibFilename, + HMODULE *phRemoteModule) { bool result = false; DWORD dwProcessId; @@ -214,59 +329,69 @@ bool InjectLibraryByFileName(HANDLE hProcess, const wchar_t *pLibFileName, size_ Status = NtSuspendProcess(hProcess); if ( !NT_SUCCESS(Status) ) return result; + trace(L"Suspended process. hProcess=%p", hProcess); dwProcessId = GetProcessId(hProcess); hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId); - if ( !hSnapshot ) goto L1; + if ( !hSnapshot ) goto resume; + trace(L"Created TH32 module snapshot. dwProcessId=%lu", dwProcessId); + + *phRemoteModule = GetRemoteHModuleFromTh32ModuleSnapshot(hSnapshot, + pLibFilename); - result = GetRemoteHModuleFromTh32ModuleSnapshot(hSnapshot, pLibFileName, phRemoteModule); CloseHandle(hSnapshot); - // already injected... returns false but sets *phRemoteModule - if ( result ) goto L1; + // already injected... still sets *phRemoteModule + if ( *phRemoteModule ) goto resume; - nSize = (cchLibFileName + 1) * sizeof *pLibFileName; - pBaseAddress = VirtualAllocEx(hProcess, NULL, nSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + nSize = (cchLibFilename + 1) * sizeof *pLibFilename; + pBaseAddress = VirtualAllocEx(hProcess, + NULL, + nSize, + MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE); - if ( !pBaseAddress ) goto L1; + if ( !pBaseAddress ) goto resume; + trace(L"Allocated virtual memory in process. hProcess=%p pBaseAddress=%p nSize=%Iu", + hProcess, pBaseAddress, nSize); - if ( !WriteProcessMemory(hProcess, pBaseAddress, pLibFileName, nSize, NULL) ) - goto L2; + if ( !WriteProcessMemory(hProcess, pBaseAddress, pLibFilename, nSize, NULL) ) + goto vfree; + trace(L"Wrote to process memory. hProcess=%p pBaseAddress=%p pLibFileName=%.*ls nSize=%Iu", + hProcess, pBaseAddress, cchLibFilename, pLibFilename, nSize); - hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, pBaseAddress, 0, NULL); - if ( !hThread ) goto L2; + hThread = CreateRemoteThread(hProcess, + NULL, + 0, + (LPTHREAD_START_ROUTINE)LoadLibraryW, + pBaseAddress, + 0, + NULL); + if ( !hThread ) goto vfree; + trace(L"Created remote thread. hThread=%p", hThread); WaitForSingleObject(hThread, INFINITE); + trace(L"Created thread finished running. hThread=%p", hThread); if ( sizeof *phRemoteModule > sizeof(DWORD) ) { hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId); if ( hSnapshot ) { - result = GetRemoteHModuleFromTh32ModuleSnapshot(hSnapshot, pLibFileName, phRemoteModule); + *phRemoteModule = GetRemoteHModuleFromTh32ModuleSnapshot( + hSnapshot, + pLibFilename); + CloseHandle(hSnapshot); } } else { result = !!GetExitCodeThread(hThread, (LPDWORD)phRemoteModule); } CloseHandle(hThread); -L2: VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE); -L1: NtResumeProcess(hProcess); +vfree: VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE); +resume: NtResumeProcess(hProcess); return result; } -bool InjectLibraryByLocalHModule(HANDLE hProcess, HMODULE hModule, HMODULE *phRemoteModule) -{ - WCHAR Filename[MAX_PATH]; - DWORD nLength; - - nLength = GetModuleFileNameW(hModule, Filename, _countof(Filename)); - - if ( nLength ) - return InjectLibraryByFileName(hProcess, Filename, nLength, phRemoteModule); - - return false; -} - bool IsWindowsVersion(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor) { OSVERSIONINFOEXW osvi = { sizeof osvi }; @@ -280,33 +405,18 @@ bool IsWindowsVersion(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackM osvi.dwMinorVersion = wMinorVersion; osvi.wServicePackMajor = wServicePackMajor; - return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE; + return VerifyVersionInfoW(&osvi, + VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, + dwlConditionMask) != FALSE; } -PVOID NtQueryKeyAlloc(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PULONG pResultLength) -{ - NTSTATUS Status; - ULONG ResultLength; - PVOID result = NULL; - - Status = NtQueryKey(KeyHandle, KeyInformationClass, NULL, 0, &ResultLength); - if ( Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL ) - return result; - - result = malloc(ResultLength); - if ( !result ) return result; - - Status = NtQueryKey(KeyHandle, KeyInformationClass, result, ResultLength, &ResultLength); - if ( NT_SUCCESS(Status) ) { - *pResultLength = ResultLength; - } else { - free(result); - result = NULL; - } - return result; -} - -PVOID RegGetValueAlloc(HKEY hkey, const wchar_t *pSubKey, const wchar_t *pValue, DWORD dwFlags, LPDWORD pdwType, LPDWORD pcbData) +PVOID RegGetValueAlloc( + HKEY hkey, + const wchar_t *pSubKey, + const wchar_t *pValue, + DWORD dwFlags, + LPDWORD pdwType, + LPDWORD pcbData) { DWORD cbData = 0; PVOID result = NULL; @@ -326,7 +436,10 @@ PVOID RegGetValueAlloc(HKEY hkey, const wchar_t *pSubKey, const wchar_t *pValue, return result; } -LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(SC_HANDLE hSCM, const wchar_t *pServiceName, LPDWORD pcbBufSize) +LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc( + SC_HANDLE hSCM, + const wchar_t *pServiceName, + LPDWORD pcbBufSize) { SC_HANDLE hService; DWORD cbBytesNeeded; @@ -352,37 +465,27 @@ LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(SC_HANDLE hSCM, const wcha return result; } -bool QueryServiceStatusProcessInfoByName(SC_HANDLE hSCM, const wchar_t *pServiceName, LPSERVICE_STATUS_PROCESS pServiceStatus) +bool QueryServiceStatusProcessInfoByName( + SC_HANDLE hSCM, + const wchar_t *pServiceName, + LPSERVICE_STATUS_PROCESS pServiceStatus) { bool result = false; SC_HANDLE hService; DWORD cbBytesNeeded; hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_STATUS); - if ( !hService ) return result; - - result = !!QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)pServiceStatus, sizeof *pServiceStatus, &cbBytesNeeded); - CloseServiceHandle(hService); - return result; -} - -bool QueryServiceGroupName(const LPQUERY_SERVICE_CONFIGW pServiceConfig, wchar_t *pGroupName, size_t nSize) -{ - bool result = false; - int NumArgs; - LPWSTR *argv; - - argv = CommandLineToArgvW(pServiceConfig->lpBinaryPathName, &NumArgs); - if ( argv ) { - if ( !_wcsicmp(PathFindFileNameW(argv[0]), L"svchost.exe") ) { - - for ( int i = 1; (i + 1) < NumArgs; i++ ) { - if ( !_wcsicmp(argv[i], L"-k") ) - return !wcscpy_s(pGroupName, nSize, argv[++i]); - } - } - LocalFree((HLOCAL)argv); + if ( !hService ) { + trace(L"Failed to open service %ls! (GetLastError=%ul)", pServiceName, GetLastError()); + return result; } + + result = !!QueryServiceStatusEx(hService, + SC_STATUS_PROCESS_INFO, + (LPBYTE)pServiceStatus, + sizeof *pServiceStatus, + &cbBytesNeeded); + CloseServiceHandle(hService); return result; } @@ -394,36 +497,3 @@ DWORD QueryServiceProcessId(SC_HANDLE hSCM, const wchar_t *pServiceName) return ServiceStatusProcess.dwProcessId; return 0; } - -DWORD InferSvchostGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupName) -{ - DWORD result = 0; - DWORD cbData; - wchar_t *pData; - DWORD dwProcessId; - DWORD cbBufSize; - LPQUERY_SERVICE_CONFIGW pServiceConfig; - bool success; - WCHAR GroupName[256]; - - pData = RegGetValueAlloc(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost", pGroupName, RRF_RT_REG_MULTI_SZ, NULL, &cbData); - if ( !pData ) return result; - - for ( wchar_t *pName = pData; *pName; pName += wcslen(pName) + 1 ) { - dwProcessId = QueryServiceProcessId(hSCM, pName); - trace(L"pName=%ls dwProcessId=%lu", pName, dwProcessId); - if ( !dwProcessId ) continue; - - pServiceConfig = QueryServiceConfigByNameAlloc(hSCM, pName, &cbBufSize); - if ( !pServiceConfig ) continue; - success = QueryServiceGroupName(pServiceConfig, GroupName, _countof(GroupName)); - free(pServiceConfig); - if ( success && !_wcsicmp(pGroupName, GroupName) ) { - trace(L"found PID for group %ls: %lu", pGroupName, dwProcessId); - result = dwProcessId; - break; - } - } - free(pData); - return result; -} \ No newline at end of file diff --git a/wufuc/helpers.h b/wufuc/helpers.h index aec62fe..ac68049 100644 --- a/wufuc/helpers.h +++ b/wufuc/helpers.h @@ -1,25 +1,49 @@ #pragma once -bool CreateExclusiveMutex(const wchar_t *name, HANDLE *pmutex); -bool CreateEventWithStringSecurityDescriptor(const wchar_t *descriptor, bool manualreset, bool initialstate, const wchar_t *name, HANDLE *pevent); +typedef struct +{ + WORD wLanguage; + WORD wCodePage; +} LANGANDCODEPAGE, *PLANGANDCODEPAGE; -bool FileExists(const wchar_t *path); -bool FileExistsExpandEnvironmentStrings(const wchar_t *path); +bool InitializeMutex(bool InitialOwner, const wchar_t *pMutexName, HANDLE *phMutex); +bool CreateEventWithStringSecurityDescriptor( + const wchar_t *pStringSecurityDescriptor, + bool ManualReset, + bool InitialState, + const wchar_t *pName, + HANDLE *phEvent); int FileInfoVerCompare(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wBuild, WORD wRev); -size_t FindArgument(const wchar_t **argv, size_t argc, const wchar_t *val); - -bool FindIsDeviceServiceablePtr(const wchar_t *pFilename, HMODULE hModule, PVOID *ppfnIsDeviceServiceable); -bool GetRemoteHModuleFromTh32ModuleSnapshot(HANDLE hSnapshot, const wchar_t *pLibFileName, HMODULE *phRemoteModule); -bool InjectSelfAndCreateRemoteThread(DWORD dwProcessId, LPTHREAD_START_ROUTINE pStartAddress, HANDLE SourceHandle, DWORD dwDesiredAccess); -bool InjectLibraryByFileName(HANDLE hProcess, const wchar_t *pLibFileName, size_t nLength, HMODULE *phRemoteModule); -bool InjectLibraryByLocalHModule(HANDLE hProcess, HMODULE hModule, HMODULE *phRemoteModule); +bool GetVersionInfoFromHModule(HMODULE hModule, LPCWSTR pszSubBlock, LPVOID pData, PUINT pcbData); +LPVOID GetVersionInfoFromHModuleAlloc(HMODULE hModule, LPCWSTR pszSubBlock, PUINT pcbData); +bool FindIsDeviceServiceablePtr(HMODULE hModule, PVOID *ppfnIsDeviceServiceable); +HANDLE GetRemoteHModuleFromTh32ModuleSnapshot(HANDLE hSnapshot, const wchar_t *pLibFileName); +bool InjectLibraryAndCreateRemoteThread( + HANDLE hProcess, + HMODULE hModule, + LPTHREAD_START_ROUTINE pStartAddress, + const void *pParam, + size_t cbParam); +bool InjectLibrary(HANDLE hProcess, HMODULE hModule, HMODULE *phRemoteModule); +bool InjectLibraryByFilename( + HANDLE hProcess, + const wchar_t *pLibFilename, + size_t cchLibFilename, + HMODULE *phRemoteModule); bool IsWindowsVersion(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor); - -PVOID NtQueryKeyAlloc(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PULONG pResultLength); -PVOID RegGetValueAlloc(HKEY hkey, const wchar_t *pSubKey, const wchar_t *pValue, DWORD dwFlags, LPDWORD pdwType, LPDWORD pcbData); -LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(SC_HANDLE hSCM, const wchar_t *pServiceName, LPDWORD pcbBufSize); -bool QueryServiceStatusProcessInfoByName(SC_HANDLE hSCM, const wchar_t *pServiceName, LPSERVICE_STATUS_PROCESS pServiceStatus); - -bool QueryServiceGroupName(const LPQUERY_SERVICE_CONFIGW pServiceConfig, wchar_t *pGroupName, size_t nSize); +PVOID RegGetValueAlloc( + HKEY hkey, + const wchar_t *pSubKey, + const wchar_t *pValue, + DWORD dwFlags, + LPDWORD pdwType, + LPDWORD pcbData); +LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc( + SC_HANDLE hSCM, + const wchar_t *pServiceName, + LPDWORD pcbBufSize); +bool QueryServiceStatusProcessInfoByName( + SC_HANDLE hSCM, + const wchar_t *pServiceName, + LPSERVICE_STATUS_PROCESS pServiceStatus); DWORD QueryServiceProcessId(SC_HANDLE hSCM, const wchar_t *pServiceName); -DWORD InferSvchostGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupName); diff --git a/wufuc/hooks.c b/wufuc/hooks.c index c25d142..c9cc23f 100644 --- a/wufuc/hooks.c +++ b/wufuc/hooks.c @@ -2,71 +2,10 @@ #include "hooks.h" #include "helpers.h" -LPFN_REGQUERYVALUEEXW g_pfnRegQueryValueExW; -LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW; +LPWSTR g_pszWUServiceDll; + LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceable; - -LSTATUS WINAPI RegQueryValueExW_hook(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) -{ - PWCH pBuffer = NULL; - DWORD MaximumLength = 0; - LSTATUS result; - ULONG ResultLength; - PKEY_NAME_INFORMATION pkni; - size_t NameCount; - int current; - int pos; - LPWSTR fname; - const WCHAR realpath[] = L"%systemroot%\\system32\\wuaueng.dll"; - - trace(L""); - - // save original buffer size - if ( lpData && lpcbData ) - MaximumLength = *lpcbData; - trace(L""); - - result = g_pfnRegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); - - if ( result != ERROR_SUCCESS || !MaximumLength || !lpValueName || _wcsicmp(lpValueName, L"ServiceDll") ) - return result; - trace(L""); - - pBuffer = (wchar_t *)lpData; - trace(L""); - - // get name of registry key being queried - pkni = NtQueryKeyAlloc((HANDLE)hKey, KeyNameInformation, &ResultLength); - trace(L""); - if ( !pkni ) - return result; - trace(L""); - - NameCount = pkni->NameLength / sizeof *pkni->Name; - // change key name to lower-case because there is no case-insensitive version of _snwscanf_s - if ( !_wcslwr_s(pkni->Name, NameCount) - && _snwscanf_s(pkni->Name, NameCount, L"\\registry\\machine\\system\\controlset%03d\\services\\wuauserv\\parameters%n", ¤t, &pos) == 1 - && pos == NameCount ) { - - trace(L"key=%.*ls", NameCount, pkni->Name); - - fname = PathFindFileNameW(pBuffer); - - trace(L"fname=%ls", fname); - - if ( (!_wcsicmp(fname, L"wuaueng2.dll") // UpdatePack7R2 - || !_wcsicmp(fname, L"WuaCpuFix64.dll") // WuaCpuFix 64-bit - || !_wcsicmp(fname, L"WuaCpuFix.dll")) - && FileExistsExpandEnvironmentStrings(realpath) - && SUCCEEDED(StringCbCopyW(pBuffer, MaximumLength, realpath)) ) { - trace(L""); - - *lpcbData = sizeof realpath; - } - } - free(pkni); - return result; -} +LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW; HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags) { @@ -74,13 +13,16 @@ HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFla result = g_pfnLoadLibraryExW(lpFileName, hFile, dwFlags); if ( !result ) return result; + trace(L"Loaded library. lpFileName=%ls result=%p", lpFileName, result); - trace(L"Loaded library: %ls", lpFileName); - if ( FindIsDeviceServiceablePtr(lpFileName, result, (PVOID *)&g_pfnIsDeviceServiceable) ) { - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - DetourAttach((PVOID *)&g_pfnIsDeviceServiceable, IsDeviceServiceable_hook); - DetourTransactionCommit(); + if ( g_pszWUServiceDll + && !_wcsicmp(lpFileName, g_pszWUServiceDll) + && FindIsDeviceServiceablePtr(result, &(PVOID)g_pfnIsDeviceServiceable) ) { + + trace(L"DetourTransactionBegin=%lu", DetourTransactionBegin()); + trace(L"DetourUpdateThread=%lu", DetourUpdateThread(GetCurrentThread())); + trace(L"DetourAttach=%lu", DetourAttach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook)); + trace(L"DetourTransactionCommit=%lu", DetourTransactionCommit()); } return result; } diff --git a/wufuc/hooks.h b/wufuc/hooks.h index 5bd780a..05f494d 100644 --- a/wufuc/hooks.h +++ b/wufuc/hooks.h @@ -1,19 +1,13 @@ #pragma once -typedef struct -{ - WORD wLanguage; - WORD wCodePage; -} LANGANDCODEPAGE, *PLANGANDCODEPAGE; -typedef LSTATUS(WINAPI *LPFN_REGQUERYVALUEEXW)(HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD); typedef HMODULE(WINAPI *LPFN_LOADLIBRARYEXW)(LPCWSTR, HANDLE, DWORD); typedef BOOL(WINAPI *LPFN_ISDEVICESERVICEABLE)(void); -extern LPFN_REGQUERYVALUEEXW g_pfnRegQueryValueExW; +extern LPWSTR g_pszWUServiceDll; + extern LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW; extern LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceable; -LSTATUS WINAPI RegQueryValueExW_hook(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData); HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags); BOOL WINAPI IsDeviceServiceable_hook(void); diff --git a/wufuc/rundll32.c b/wufuc/rundll32.c index 04d156b..6b81f0b 100644 --- a/wufuc/rundll32.c +++ b/wufuc/rundll32.c @@ -2,66 +2,57 @@ #include "callbacks.h" #include "helpers.h" + + void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { - HANDLE hMutex; - HANDLE hEvent; - DWORD cbBufSize; - LPQUERY_SERVICE_CONFIGW pServiceConfig; - wchar_t GroupName[256]; - DWORD dwProcessId; + ContextHandles ctx; bool Unloading = false; bool Lagging; SC_HANDLE hSCM; SC_HANDLE hService; SERVICE_NOTIFYW NotifyBuffer; - if ( !CreateExclusiveMutex(L"Global\\{25020063-B5A7-4227-9FDF-25CB75E8C645}", &hMutex) ) + if ( !InitializeMutex(true, + L"Global\\{25020063-B5A7-4227-9FDF-25CB75E8C645}", + &ctx.hMainMutex) ) { + + trace(L"Failed to initialize main mutex. (GetLastError=%ul)", GetLastError()); return; + }; + if ( !CreateEventWithStringSecurityDescriptor(L"D:(A;;0x001F0003;;;BA)", + true, + false, + L"Global\\wufuc_UnloadEvent", + &ctx.hUnloadEvent) ) { - if ( !CreateEventWithStringSecurityDescriptor(L"D:(A;;0x001F0003;;;BA)", true, false, L"Global\\wufuc_UnloadEvent", &hEvent) ) - goto L1; - - //hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); - //if ( hSCM ) { - // trace(L"hSCM=%p", hSCM); - // pServiceConfig = QueryServiceConfigByNameAlloc(hSCM, L"wuauserv", &cbBufSize); - // trace(L"pServiceConfig=%p", pServiceConfig); - // if ( pServiceConfig ) { - // // inject into existing service host process if wuauserv is configured as shared process - // trace(L"pServiceConfig->dwServiceType=%lu", pServiceConfig->dwServiceType); - // if ( pServiceConfig->dwServiceType == SERVICE_WIN32_SHARE_PROCESS - // && QueryServiceGroupName(pServiceConfig, GroupName, _countof(GroupName)) ) { - // trace(L"GroupName=%ls", GroupName); - - // dwProcessId = InferSvchostGroupProcessId(hSCM, GroupName); - // trace(L"dwProcessId=%lu", dwProcessId); - // if ( dwProcessId ) - // InjectSelfAndCreateRemoteThread(dwProcessId, StartAddress, hEvent, SYNCHRONIZE); - // } - // free(pServiceConfig); - // } - // CloseServiceHandle(hSCM); - //} - + trace(L"Failed to create unload event. (GetLastError=%ul)", GetLastError()); + goto close_mutex; + } do { Lagging = false; hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); - if ( !hSCM ) goto L2; + if ( !hSCM ) { + trace(L"Failed to open SCM. (GetLastError=%ul)", GetLastError()); + goto close_event; + } hService = OpenServiceW(hSCM, L"wuauserv", SERVICE_QUERY_STATUS); - if ( !hService ) goto L3; + if ( !hService ) { + trace(L"Failed to open service. (GetLastError=%ul)", GetLastError()); + goto close_scm; + } ZeroMemory(&NotifyBuffer, sizeof NotifyBuffer); NotifyBuffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE; NotifyBuffer.pfnNotifyCallback = ServiceNotifyCallback; - NotifyBuffer.pContext = (PVOID)hEvent; + NotifyBuffer.pContext = (PVOID)&ctx; while ( !Unloading && !Lagging ) { switch ( NotifyServiceStatusChangeW(hService, SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_RUNNING, &NotifyBuffer) ) { case ERROR_SUCCESS: - Unloading = WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == WAIT_OBJECT_0; + Unloading = WaitForSingleObjectEx(ctx.hUnloadEvent, INFINITE, TRUE) == WAIT_OBJECT_0; break; case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING: trace(L"Client lagging!"); @@ -73,11 +64,13 @@ void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, in } } CloseServiceHandle(hService); -L3: CloseServiceHandle(hSCM); +close_scm: CloseServiceHandle(hSCM); } while ( Lagging ); -L2: CloseHandle(hEvent); -L1: ReleaseMutex(hMutex); - CloseHandle(hMutex); +close_event: + CloseHandle(ctx.hUnloadEvent); +close_mutex: + ReleaseMutex(ctx.hMainMutex); + CloseHandle(ctx.hMainMutex); } void CALLBACK RUNDLL32_UnloadW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) @@ -91,7 +84,11 @@ void CALLBACK RUNDLL32_UnloadW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, i } } -void CALLBACK RUNDLL32_DeleteFileW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) +void CALLBACK RUNDLL32_DeleteFileW( + HWND hwnd, + HINSTANCE hinst, + LPWSTR lpszCmdLine, + int nCmdShow) { int argc; LPWSTR *argv; diff --git a/wufuc/stdafx.h b/wufuc/stdafx.h index 879c6f1..602239c 100644 --- a/wufuc/stdafx.h +++ b/wufuc/stdafx.h @@ -4,16 +4,21 @@ #include #include + #include #include +#include + #include #include -#include + #include -#include -#include #include #include + +#include +#include + #include #include "patternfind.h" diff --git a/wufuc/tracing.c b/wufuc/tracing.c index 6e34dcd..0a9bf67 100644 --- a/wufuc/tracing.c +++ b/wufuc/tracing.c @@ -1,8 +1,6 @@ #include "stdafx.h" #include "tracing.h" -static FILE *steam; - void trace_(const wchar_t *const format, ...) { va_list argptr; diff --git a/wufuc/wufuc.vcxproj b/wufuc/wufuc.vcxproj index 08179af..bc10126 100644 --- a/wufuc/wufuc.vcxproj +++ b/wufuc/wufuc.vcxproj @@ -155,7 +155,7 @@ exports.def - ntdll.lib;version.lib;Shlwapi.lib;detours.X86.MTd.lib;%(AdditionalDependencies) + version.lib;Shlwapi.lib;detours.X86.MTd.lib;%(AdditionalDependencies);ntdll.lib X86;%(PreprocessorDefinitions) @@ -177,7 +177,7 @@ exports.def - ntdll.lib;version.lib;Shlwapi.lib;detours.X64.MTd.lib;%(AdditionalDependencies) + version.lib;Shlwapi.lib;detours.X64.MTd.lib;%(AdditionalDependencies);ntdll.lib X64;%(PreprocessorDefinitions) @@ -207,7 +207,7 @@ exports.def - ntdll.lib;version.lib;Shlwapi.lib;detours.X86.MT.lib;%(AdditionalDependencies) + version.lib;Shlwapi.lib;detours.X86.MT.lib;%(AdditionalDependencies);ntdll.lib true @@ -236,7 +236,7 @@ true false exports.def - ntdll.lib;version.lib;Shlwapi.lib;detours.X64.MT.lib;%(AdditionalDependencies) + version.lib;Shlwapi.lib;detours.X64.MT.lib;%(AdditionalDependencies);ntdll.lib true diff --git a/wufuc_setup_bat/Restore_wuauserv.reg b/wufuc_setup_bat/Restore_wuauserv.reg new file mode 100644 index 0000000..eb1c973 Binary files /dev/null and b/wufuc_setup_bat/Restore_wuauserv.reg differ diff --git a/wufuc_setup_bat/install_wufuc.bat b/wufuc_setup_bat/install_wufuc.bat index c89aa2f..0888685 100644 --- a/wufuc_setup_bat/install_wufuc.bat +++ b/wufuc_setup_bat/install_wufuc.bat @@ -14,7 +14,8 @@ :: You should have received a copy of the GNU General Public License :: along with this program. If not, see . - +set /p wufuc_version=<"%~dp0version.txt" +title wufuc v%wufuc_version% Setup echo Copyright ^(C^) 2017 zeffy echo This program comes with ABSOLUTELY NO WARRANTY. echo This is free software, and you are welcome to redistribute it @@ -78,7 +79,6 @@ echo in which case, you will need to make an exception and restore it. goto :die :xml_exists -for /f "tokens=*" %%i in ('wmic /output:stdout datafile where "name='%wufuc_dll_fullpath:\=\\%'" get Version /value ^| find "="') do set "%%i" set "wufuc_xml=%~dp0wufuc_ScheduledTask.xml" if exist "%wufuc_xml%" goto :check_winver @@ -86,7 +86,7 @@ echo ERROR - Could not find %wufuc_xml%! echo. echo This most likely means you didn't extract all the files from the archive. echo. -echo Please extract all the files from wufuc_v%Version%.zip to a permanent +echo Please extract all the files from wufuc_v%wufuc_version%.zip to a permanent echo location like C:\Program Files\wufuc and try again. goto :die @@ -112,6 +112,7 @@ goto :die :check_mode set "wufuc_task=wufuc.{72EEE38B-9997-42BD-85D3-2DD96DA17307}" +set "space= " if "%UNINSTALL%"=="1" goto :confirm_uninstall @@ -125,7 +126,7 @@ echo systems with Intel Kaby Lake, AMD Ryzen, or other unsupported processors. echo. echo Please be absolutely sure you really need wufuc before proceeding. echo. -set /p CONTINUE_INSTALL=Enter 'Y' if you want to install wufuc %Version%: +set /p CONTINUE_INSTALL=Enter 'Y' if you want to install wufuc %wufuc_version%:%space% if /I "%CONTINUE_INSTALL%"=="Y" goto :install goto :cancel @@ -135,7 +136,6 @@ net start Schedule schtasks /Create /XML "%wufuc_xml%" /TN "%wufuc_task%" /F schtasks /Change /TN "%wufuc_task%" /TR "'%systemroot%\System32\rundll32.exe' """%wufuc_dll_fullpath%""",RUNDLL32_Start" schtasks /Change /TN "%wufuc_task%" /ENABLE -rundll32 "%wufuc_dll_fullpath%",RUNDLL32_Unload net stop wuauserv schtasks /Run /TN "%wufuc_task%" @@ -150,7 +150,7 @@ goto :confirm_restart :confirm_uninstall if "%UNATTENDED%"=="1" goto :uninstall_stub echo. -set /p CONTINUE_UNINSTALL=Enter 'Y' if you want to uninstall wufuc: +set /p CONTINUE_UNINSTALL=Enter 'Y' if you want to uninstall wufuc:%space% if /I "%CONTINUE_UNINSTALL%"=="Y" goto :uninstall_stub goto :cancel @@ -187,7 +187,7 @@ goto :confirm_restart if "%NORESTART%"=="1" goto :die if "%UNATTENDED%"=="1" goto :restart echo. -set /p CONTINUE_RESTART=Enter 'Y' if you would like to restart now: +set /p CONTINUE_RESTART=Enter 'Y' if you would like to restart now:%space% if /I "%CONTINUE_RESTART%"=="Y" goto :restart goto :die :restart