From d7504e18729dc29b974eb78d411a0dd96149f766 Mon Sep 17 00:00:00 2001 From: zeffy Date: Fri, 9 Feb 2018 03:17:17 -0800 Subject: [PATCH] finish implementing updatepack7 fix (shared process only) --- src/wufuc/callbacks.c | 67 +++++++++++++++++++++++++---------------- src/wufuc/hlpmem.c | 5 ++-- src/wufuc/hlpmisc.c | 70 ++++++++++++++++++++++++++++++++----------- src/wufuc/hlpmisc.h | 18 +++++++---- src/wufuc/hlpsvc.c | 31 ++++++++----------- src/wufuc/hooks.c | 28 ++++++++++++----- 6 files changed, 142 insertions(+), 77 deletions(-) diff --git a/src/wufuc/callbacks.c b/src/wufuc/callbacks.c index d7d59dc..a601cb9 100644 --- a/src/wufuc/callbacks.c +++ b/src/wufuc/callbacks.c @@ -7,11 +7,15 @@ VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer) { - trace(L"Enter service notify callback. (NotifyStatus=%ld ServiceStatus=%ld)", pNotifyBuffer->dwNotificationStatus, pNotifyBuffer->ServiceStatus); + trace(L"Enter service notify callback. (NotifyStatus=%ld ServiceStatus=%ld)", + pNotifyBuffer->dwNotificationStatus, pNotifyBuffer->ServiceStatus); + switch ( pNotifyBuffer->dwNotificationStatus ) { case ERROR_SUCCESS: if ( pNotifyBuffer->ServiceStatus.dwProcessId ) - wufuc_InjectLibrary(pNotifyBuffer->ServiceStatus.dwProcessId, (ContextHandles *)pNotifyBuffer->pContext); + wufuc_InjectLibrary( + pNotifyBuffer->ServiceStatus.dwProcessId, + (ContextHandles *)pNotifyBuffer->pContext); break; case ERROR_SERVICE_MARKED_FOR_DELETE: SetEvent(((ContextHandles *)pNotifyBuffer->pContext)->hUnloadEvent); @@ -25,8 +29,11 @@ DWORD WINAPI ThreadStartCallback(LPVOID pParam) { ContextHandles ctx; SC_HANDLE hSCM; + SC_HANDLE hService; DWORD dwProcessId; - DWORD cbData; + LPQUERY_SERVICE_CONFIGW pServiceConfig; + DWORD dwServiceType; + LPWSTR str; HMODULE hModule; DWORD result; @@ -42,7 +49,7 @@ DWORD WINAPI ThreadStartCallback(LPVOID pParam) // acquire child mutex, should be immediate. if ( WaitForSingleObject(ctx.hChildMutex, 5000) != WAIT_OBJECT_0 ) { - trace(L"Failed to acquire aux mutex within five seconds. (%p)", ctx.hChildMutex); + trace(L"Failed to acquire child mutex within five seconds. (%p)", ctx.hChildMutex); goto close_handles; } @@ -52,31 +59,51 @@ DWORD WINAPI ThreadStartCallback(LPVOID pParam) goto release; } - dwProcessId = HeuristicServiceProcessIdByName(hSCM, L"wuauserv"); + hService = OpenServiceW(hSCM, L"wuauserv", SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG); + dwProcessId = HeuristicServiceProcessId(hSCM, hService); + pServiceConfig = QueryServiceConfigAlloc(hSCM, hService, NULL); + dwServiceType = pServiceConfig->dwServiceType; + free(pServiceConfig); + CloseServiceHandle(hService); CloseServiceHandle(hSCM); + if ( dwProcessId != GetCurrentProcessId() ) { trace(L"Injected into wrong process!", GetCurrentProcessId(), dwProcessId); goto release; } - g_pszWUServiceDll = RegGetValueAlloc(HKEY_LOCAL_MACHINE, - L"SYSTEM\\CurrentControlSet\\services\\wuauserv\\Parameters", - L"ServiceDll", - RRF_RT_REG_SZ, - NULL, - &cbData); - trace(L"Installing hooks..."); + if ( dwServiceType == SERVICE_WIN32_SHARE_PROCESS ) { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + // assume wuaueng.dll hasn't been loaded yet, apply + // RegQueryValueExW hook to fix incompatibility with + // UpdatePack7R2 and other patches that work by + // modifying the Windows Update ServiceDll path in the + // registry. + g_pfnRegQueryValueExW = DetourFindFunction("kernel32.dll", "RegQueryValueExW"); + if ( g_pfnRegQueryValueExW ) + DetourAttach(&(PVOID)g_pfnRegQueryValueExW, RegQueryValueExW_hook); + DetourTransactionCommit(); + } + + // query the ServiceDll path after applying our compat hook so that it + // is correct + str = (LPWSTR)RegQueryValueExAlloc(HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\services\\wuauserv\\Parameters", + L"ServiceDll", NULL, NULL); + g_pszWUServiceDll = ExpandEnvironmentStringsAlloc(str); + free(str); + DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); - // hook LoadLibraryExW g_pfnLoadLibraryExW = DetourFindFunction("kernel32.dll", "LoadLibraryExW"); if ( g_pfnLoadLibraryExW ) DetourAttach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook); - // hook IsDeviceServiceable if ( g_pszWUServiceDll ) { hModule = GetModuleHandleW(g_pszWUServiceDll); if ( hModule ) { @@ -88,19 +115,9 @@ DWORD WINAPI ThreadStartCallback(LPVOID pParam) } else { trace(L"No pattern matched!"); } - } else { - // assume wuaueng.dll hasn't been loaded yet, apply - // RegQueryValueExW hook to fix incompatibility with - // UpdatePack7R2 and other patches that work by - // modifying the Windows Update ServiceDll path in the - // registry. - g_pfnRegQueryValueExW = DetourFindFunction("advapi.dll", "RegQueryValueExW"); - if ( g_pfnRegQueryValueExW ) - DetourAttach(&(PVOID)g_pfnRegQueryValueExW, RegQueryValueExW_hook); } } - DetourTransactionCommit(); // wait for unload event or parent mutex to be abandoned. @@ -112,7 +129,7 @@ DWORD WINAPI ThreadStartCallback(LPVOID pParam) trace(L"Unload condition has been met."); // unhook - if ( g_pfnLoadLibraryExW || g_pfnIsDeviceServiceable || g_pfnRegQueryValueExW) { + if ( g_pfnLoadLibraryExW || g_pfnIsDeviceServiceable || g_pfnRegQueryValueExW ) { trace(L"Removing hooks..."); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); diff --git a/src/wufuc/hlpmem.c b/src/wufuc/hlpmem.c index bd54c5f..ef25a0c 100644 --- a/src/wufuc/hlpmem.c +++ b/src/wufuc/hlpmem.c @@ -138,8 +138,6 @@ bool InjectLibraryAndCreateRemoteThread( goto vfree; } if ( InjectLibrary(hProcess, hModule, &hRemoteModule) ) { - trace(L"Injected library. (%p)", hRemoteModule); - hThread = CreateRemoteThread(hProcess, NULL, 0, @@ -275,7 +273,8 @@ bool wufuc_InjectLibrary(DWORD dwProcessId, ContextHandles *pContext) && DuplicateHandle(hSrcProcess, pContext->hUnloadEvent, hProcess, ¶m.hUnloadEvent, SYNCHRONIZE, FALSE, 0) && DuplicateHandle(hSrcProcess, hChildMutex, hProcess, ¶m.hChildMutex, 0, FALSE, DUPLICATE_SAME_ACCESS) ) { - InjectLibraryAndCreateRemoteThread(hProcess, PIMAGEBASE, ThreadStartCallback, ¶m, sizeof param); + if ( InjectLibraryAndCreateRemoteThread(hProcess, PIMAGEBASE, ThreadStartCallback, ¶m, sizeof param) ) + trace(L"Injected into process. (%lu)", dwProcessId); } else { trace(L"Failed to duplicate context handles! (GetLastError=%lu", GetLastError()); } diff --git a/src/wufuc/hlpmisc.c b/src/wufuc/hlpmisc.c index f85af7a..74f7c88 100644 --- a/src/wufuc/hlpmisc.c +++ b/src/wufuc/hlpmisc.c @@ -2,7 +2,7 @@ #include "hlpmisc.h" #include -bool InitializeMutex(bool InitialOwner, const wchar_t *pMutexName, HANDLE *phMutex) +bool InitializeMutex(bool InitialOwner, LPCWSTR pMutexName, HANDLE *phMutex) { HANDLE hMutex; @@ -21,10 +21,10 @@ bool InitializeMutex(bool InitialOwner, const wchar_t *pMutexName, HANDLE *phMut } bool CreateEventWithStringSecurityDescriptor( - const wchar_t *pStringSecurityDescriptor, + LPCWSTR pStringSecurityDescriptor, bool ManualReset, bool InitialState, - const wchar_t *pName, + LPCWSTR pName, HANDLE *phEvent) { SECURITY_ATTRIBUTES sa = { sizeof sa }; @@ -47,8 +47,8 @@ bool CreateEventWithStringSecurityDescriptor( PVOID RegGetValueAlloc( HKEY hkey, - const wchar_t *pSubKey, - const wchar_t *pValue, + LPCWSTR pSubKey, + LPCWSTR pValue, DWORD dwFlags, LPDWORD pdwType, LPDWORD pcbData) @@ -63,7 +63,45 @@ PVOID RegGetValueAlloc( if ( !result ) return result; if ( RegGetValueW(hkey, pSubKey, pValue, dwFlags, pdwType, result, &cbData) == ERROR_SUCCESS ) { - *pcbData = cbData; + if ( pcbData ) + *pcbData = cbData; + } else { + free(result); + result = NULL; + } + return result; +} + +LPBYTE RegQueryValueExAlloc( + HKEY hKey, + LPCWSTR pSubKey, + LPCWSTR pValueName, + LPDWORD pType, + LPDWORD pcbData) +{ + HKEY hSubKey; + DWORD cbData = 0; + size_t length; + LPBYTE result = NULL; + + if ( pSubKey && *pSubKey ) { + if ( RegOpenKeyW(hKey, pSubKey, &hSubKey) != ERROR_SUCCESS ) + return result; + } else { + hSubKey = hKey; + } + if ( RegQueryValueExW(hSubKey, pValueName, NULL, pType, result, &cbData) != ERROR_SUCCESS ) + return result; + + length = cbData + sizeof(WCHAR); // make sure it is null-terminated + result = malloc(length); + + if ( !result ) return result; + ZeroMemory(result, length); + + if ( RegQueryValueExW(hSubKey, pValueName, NULL, pType, result, &cbData) == ERROR_SUCCESS ) { + if ( pcbData ) + *pcbData = cbData; } else { free(result); result = NULL; @@ -94,20 +132,18 @@ PVOID NtQueryKeyAlloc(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClas return result; } - -bool FileExistsExpandEnvironmentStrings(const wchar_t *path) +LPWSTR ExpandEnvironmentStringsAlloc(LPCWSTR src) { - bool result; - LPWSTR dst; + wchar_t *result; 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 = PathFileExistsW(dst); - free(dst); + buffersize = ExpandEnvironmentStringsW(src, NULL, 0); + result = calloc(buffersize, sizeof *result); + size = ExpandEnvironmentStringsW(src, result, buffersize); + if ( !size || size > buffersize ) { + free(result); + result = NULL; + } return result; } diff --git a/src/wufuc/hlpmisc.h b/src/wufuc/hlpmisc.h index e613823..0061d89 100644 --- a/src/wufuc/hlpmisc.h +++ b/src/wufuc/hlpmisc.h @@ -1,18 +1,24 @@ #pragma once -bool InitializeMutex(bool InitialOwner, const wchar_t *pMutexName, HANDLE *phMutex); +bool InitializeMutex(bool InitialOwner, LPCWSTR pMutexName, HANDLE *phMutex); bool CreateEventWithStringSecurityDescriptor( - const wchar_t *pStringSecurityDescriptor, + LPCWSTR pStringSecurityDescriptor, bool ManualReset, bool InitialState, - const wchar_t *pName, + LPCWSTR pName, HANDLE *phEvent); PVOID RegGetValueAlloc( HKEY hkey, - const wchar_t *pSubKey, - const wchar_t *pValue, + LPCWSTR pSubKey, + LPCWSTR pValue, DWORD dwFlags, LPDWORD pdwType, LPDWORD pcbData); +LPBYTE RegQueryValueExAlloc( + HKEY hKey, + LPCWSTR pSubKey, + LPCWSTR pValueName, + LPDWORD pType, + LPDWORD pcbData); PVOID NtQueryKeyAlloc(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PULONG pResultLength); -bool FileExistsExpandEnvironmentStrings(const wchar_t *path); +LPWSTR ExpandEnvironmentStringsAlloc(LPCWSTR src); diff --git a/src/wufuc/hlpsvc.c b/src/wufuc/hlpsvc.c index 112685f..1eca4f9 100644 --- a/src/wufuc/hlpsvc.c +++ b/src/wufuc/hlpsvc.c @@ -33,7 +33,8 @@ LPQUERY_SERVICE_CONFIGW QueryServiceConfigAlloc( result = malloc(cbBytesNeeded); if ( result ) { if ( QueryServiceConfigW(hService, result, cbBytesNeeded, &cbBytesNeeded) ) { - *pcbBufSize = cbBytesNeeded; + if ( pcbBufSize ) + *pcbBufSize = cbBytesNeeded; } else { free(result); result = NULL; @@ -53,10 +54,8 @@ bool QueryServiceStatusProcessInfoByName( DWORD cbBytesNeeded; hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_STATUS); - if ( !hService ) { - trace(L"Failed to open service %ls! (GetLastError=%ul)", pServiceName, GetLastError()); + if ( !hService ) return result; - } result = !!QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, @@ -119,12 +118,11 @@ DWORD QueryServiceProcessIdByName(SC_HANDLE hSCM, const wchar_t *pServiceName) DWORD HeuristicServiceGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupNameSearch) { wchar_t *pData; - DWORD cbData; DWORD result = 0; DWORD dwProcessId; DWORD cbBufSize; LPQUERY_SERVICE_CONFIGW pServiceConfig; - bool success; + bool success = false; LPWSTR pGroupName; HLOCAL hMem; @@ -133,27 +131,25 @@ DWORD HeuristicServiceGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupNameSe pGroupNameSearch, RRF_RT_REG_MULTI_SZ, NULL, - &cbData); + NULL); if ( !pData ) return result; for ( wchar_t *pName = pData; *pName; pName += wcslen(pName) + 1 ) { dwProcessId = QueryServiceProcessIdByName(hSCM, pName); - trace(L"pName=%ls dwProcessId=%lu", pName, dwProcessId); if ( !dwProcessId ) continue; pServiceConfig = QueryServiceConfigByNameAlloc(hSCM, pName, &cbBufSize); if ( !pServiceConfig ) continue; - success = QueryServiceGroupName(pServiceConfig, &pGroupName, &hMem); - free(pServiceConfig); - if ( !success ) - continue; + if ( pServiceConfig->dwServiceType == SERVICE_WIN32_SHARE_PROCESS + && QueryServiceGroupName(pServiceConfig, &pGroupName, &hMem) ) { - success = !_wcsicmp(pGroupNameSearch, pGroupName); - LocalFree(hMem); + success = !_wcsicmp(pGroupNameSearch, pGroupName); + LocalFree(hMem); + } + free(pServiceConfig); if ( success ) { - trace(L"Found PID: %lu", dwProcessId); result = dwProcessId; break; } @@ -168,13 +164,12 @@ DWORD HeuristicServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService) LPQUERY_SERVICE_CONFIGW pServiceConfig; LPWSTR pGroupName; HLOCAL hMem; - DWORD cbBufSize; result = QueryServiceProcessId(hSCM, hService); if ( result ) return result; - pServiceConfig = QueryServiceConfigAlloc(hSCM, hService, &cbBufSize); + pServiceConfig = QueryServiceConfigAlloc(hSCM, hService, NULL); if ( pServiceConfig ) { switch ( pServiceConfig->dwServiceType ) { case SERVICE_WIN32_OWN_PROCESS: @@ -190,12 +185,12 @@ DWORD HeuristicServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService) if ( QueryServiceGroupName(pServiceConfig, &pGroupName, &hMem) ) { result = HeuristicServiceGroupProcessId(hSCM, pGroupName); LocalFree(hMem); - return result; } break; } free(pServiceConfig); } + return result; } DWORD HeuristicServiceProcessIdByName(SC_HANDLE hSCM, const wchar_t *pServiceName) diff --git a/src/wufuc/hooks.c b/src/wufuc/hooks.c index 6957c4d..8b6aa36 100644 --- a/src/wufuc/hooks.c +++ b/src/wufuc/hooks.c @@ -21,13 +21,19 @@ LSTATUS WINAPI RegQueryValueExW_hook(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpR int pos; LPWSTR fname; const WCHAR realpath[] = L"%systemroot%\\system32\\wuaueng.dll"; + wchar_t *expandedpath; // save original buffer size if ( lpData && lpcbData ) MaximumLength = *lpcbData; result = g_pfnRegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); - if ( result != ERROR_SUCCESS || !MaximumLength || !lpValueName || _wcsicmp(lpValueName, L"ServiceDll") ) + + if ( result != ERROR_SUCCESS + || !MaximumLength + || !lpValueName + || (lpType && *lpType != REG_EXPAND_SZ) + || _wcsicmp(lpValueName, L"ServiceDll") ) return result; pBuffer = (PWCH)lpData; @@ -36,22 +42,28 @@ LSTATUS WINAPI RegQueryValueExW_hook(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpR pkni = NtQueryKeyAlloc((HANDLE)hKey, KeyNameInformation, &ResultLength); if ( !pkni ) return result; - 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 + for ( size_t i = 0; i < NameCount; i++ ) + pkni->Name[i] = towlower(pkni->Name[i]); + + if ( _snwscanf_s(pkni->Name, NameCount, L"\\registry\\machine\\system\\controlset%03d\\services\\wuauserv\\parameters%n", ¤t, &pos) == 1 && pos == NameCount ) { fname = PathFindFileNameW(pBuffer); if ( (!_wcsicmp(fname, L"wuaueng2.dll") // UpdatePack7R2 || !_wcsicmp(fname, L"WuaCpuFix64.dll") // WuaCpuFix - || !_wcsicmp(fname, L"WuaCpuFix.dll")) - && FileExistsExpandEnvironmentStrings(realpath) - && SUCCEEDED(StringCbCopyW(pBuffer, MaximumLength, realpath)) ) { + || !_wcsicmp(fname, L"WuaCpuFix.dll")) ) { - *lpcbData = sizeof realpath; + expandedpath = ExpandEnvironmentStringsAlloc(realpath); + + trace(L"Fixed path to wuauserv ServiceDll: %ls -> %ls", fname, PathFindFileNameW(expandedpath)); + + if ( SUCCEEDED(StringCbCopyW(pBuffer, MaximumLength, expandedpath)) ) + *lpcbData = sizeof realpath; + free(expandedpath); } } free(pkni);