finish implementing updatepack7 fix (shared process only)

This commit is contained in:
zeffy
2018-02-09 03:17:17 -08:00
parent 3a04fb2a74
commit d7504e1872
6 changed files with 142 additions and 77 deletions

View File

@@ -7,11 +7,15 @@
VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer) 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 ) { switch ( pNotifyBuffer->dwNotificationStatus ) {
case ERROR_SUCCESS: case ERROR_SUCCESS:
if ( pNotifyBuffer->ServiceStatus.dwProcessId ) if ( pNotifyBuffer->ServiceStatus.dwProcessId )
wufuc_InjectLibrary(pNotifyBuffer->ServiceStatus.dwProcessId, (ContextHandles *)pNotifyBuffer->pContext); wufuc_InjectLibrary(
pNotifyBuffer->ServiceStatus.dwProcessId,
(ContextHandles *)pNotifyBuffer->pContext);
break; break;
case ERROR_SERVICE_MARKED_FOR_DELETE: case ERROR_SERVICE_MARKED_FOR_DELETE:
SetEvent(((ContextHandles *)pNotifyBuffer->pContext)->hUnloadEvent); SetEvent(((ContextHandles *)pNotifyBuffer->pContext)->hUnloadEvent);
@@ -25,8 +29,11 @@ DWORD WINAPI ThreadStartCallback(LPVOID pParam)
{ {
ContextHandles ctx; ContextHandles ctx;
SC_HANDLE hSCM; SC_HANDLE hSCM;
SC_HANDLE hService;
DWORD dwProcessId; DWORD dwProcessId;
DWORD cbData; LPQUERY_SERVICE_CONFIGW pServiceConfig;
DWORD dwServiceType;
LPWSTR str;
HMODULE hModule; HMODULE hModule;
DWORD result; DWORD result;
@@ -42,7 +49,7 @@ DWORD WINAPI ThreadStartCallback(LPVOID pParam)
// acquire child mutex, should be immediate. // acquire child mutex, should be immediate.
if ( WaitForSingleObject(ctx.hChildMutex, 5000) != WAIT_OBJECT_0 ) { 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; goto close_handles;
} }
@@ -52,31 +59,51 @@ DWORD WINAPI ThreadStartCallback(LPVOID pParam)
goto release; 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); CloseServiceHandle(hSCM);
if ( dwProcessId != GetCurrentProcessId() ) { if ( dwProcessId != GetCurrentProcessId() ) {
trace(L"Injected into wrong process!", GetCurrentProcessId(), dwProcessId); trace(L"Injected into wrong process!", GetCurrentProcessId(), dwProcessId);
goto release; 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..."); 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(); DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread()); DetourUpdateThread(GetCurrentThread());
// hook LoadLibraryExW
g_pfnLoadLibraryExW = DetourFindFunction("kernel32.dll", "LoadLibraryExW"); g_pfnLoadLibraryExW = DetourFindFunction("kernel32.dll", "LoadLibraryExW");
if ( g_pfnLoadLibraryExW ) if ( g_pfnLoadLibraryExW )
DetourAttach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook); DetourAttach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook);
// hook IsDeviceServiceable
if ( g_pszWUServiceDll ) { if ( g_pszWUServiceDll ) {
hModule = GetModuleHandleW(g_pszWUServiceDll); hModule = GetModuleHandleW(g_pszWUServiceDll);
if ( hModule ) { if ( hModule ) {
@@ -88,19 +115,9 @@ DWORD WINAPI ThreadStartCallback(LPVOID pParam)
} else { } else {
trace(L"No pattern matched!"); 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(); DetourTransactionCommit();
// wait for unload event or parent mutex to be abandoned. // 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."); trace(L"Unload condition has been met.");
// unhook // unhook
if ( g_pfnLoadLibraryExW || g_pfnIsDeviceServiceable || g_pfnRegQueryValueExW) { if ( g_pfnLoadLibraryExW || g_pfnIsDeviceServiceable || g_pfnRegQueryValueExW ) {
trace(L"Removing hooks..."); trace(L"Removing hooks...");
DetourTransactionBegin(); DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread()); DetourUpdateThread(GetCurrentThread());

View File

@@ -138,8 +138,6 @@ bool InjectLibraryAndCreateRemoteThread(
goto vfree; goto vfree;
} }
if ( InjectLibrary(hProcess, hModule, &hRemoteModule) ) { if ( InjectLibrary(hProcess, hModule, &hRemoteModule) ) {
trace(L"Injected library. (%p)", hRemoteModule);
hThread = CreateRemoteThread(hProcess, hThread = CreateRemoteThread(hProcess,
NULL, NULL,
0, 0,
@@ -275,7 +273,8 @@ bool wufuc_InjectLibrary(DWORD dwProcessId, ContextHandles *pContext)
&& DuplicateHandle(hSrcProcess, pContext->hUnloadEvent, hProcess, &param.hUnloadEvent, SYNCHRONIZE, FALSE, 0) && DuplicateHandle(hSrcProcess, pContext->hUnloadEvent, hProcess, &param.hUnloadEvent, SYNCHRONIZE, FALSE, 0)
&& DuplicateHandle(hSrcProcess, hChildMutex, hProcess, &param.hChildMutex, 0, FALSE, DUPLICATE_SAME_ACCESS) ) { && DuplicateHandle(hSrcProcess, hChildMutex, hProcess, &param.hChildMutex, 0, FALSE, DUPLICATE_SAME_ACCESS) ) {
InjectLibraryAndCreateRemoteThread(hProcess, PIMAGEBASE, ThreadStartCallback, &param, sizeof param); if ( InjectLibraryAndCreateRemoteThread(hProcess, PIMAGEBASE, ThreadStartCallback, &param, sizeof param) )
trace(L"Injected into process. (%lu)", dwProcessId);
} else { } else {
trace(L"Failed to duplicate context handles! (GetLastError=%lu", GetLastError()); trace(L"Failed to duplicate context handles! (GetLastError=%lu", GetLastError());
} }

View File

@@ -2,7 +2,7 @@
#include "hlpmisc.h" #include "hlpmisc.h"
#include <sddl.h> #include <sddl.h>
bool InitializeMutex(bool InitialOwner, const wchar_t *pMutexName, HANDLE *phMutex) bool InitializeMutex(bool InitialOwner, LPCWSTR pMutexName, HANDLE *phMutex)
{ {
HANDLE hMutex; HANDLE hMutex;
@@ -21,10 +21,10 @@ bool InitializeMutex(bool InitialOwner, const wchar_t *pMutexName, HANDLE *phMut
} }
bool CreateEventWithStringSecurityDescriptor( bool CreateEventWithStringSecurityDescriptor(
const wchar_t *pStringSecurityDescriptor, LPCWSTR pStringSecurityDescriptor,
bool ManualReset, bool ManualReset,
bool InitialState, bool InitialState,
const wchar_t *pName, LPCWSTR pName,
HANDLE *phEvent) HANDLE *phEvent)
{ {
SECURITY_ATTRIBUTES sa = { sizeof sa }; SECURITY_ATTRIBUTES sa = { sizeof sa };
@@ -47,8 +47,8 @@ bool CreateEventWithStringSecurityDescriptor(
PVOID RegGetValueAlloc( PVOID RegGetValueAlloc(
HKEY hkey, HKEY hkey,
const wchar_t *pSubKey, LPCWSTR pSubKey,
const wchar_t *pValue, LPCWSTR pValue,
DWORD dwFlags, DWORD dwFlags,
LPDWORD pdwType, LPDWORD pdwType,
LPDWORD pcbData) LPDWORD pcbData)
@@ -63,6 +63,44 @@ PVOID RegGetValueAlloc(
if ( !result ) return result; if ( !result ) return result;
if ( RegGetValueW(hkey, pSubKey, pValue, dwFlags, pdwType, result, &cbData) == ERROR_SUCCESS ) { if ( RegGetValueW(hkey, pSubKey, pValue, dwFlags, pdwType, result, &cbData) == ERROR_SUCCESS ) {
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; *pcbData = cbData;
} else { } else {
free(result); free(result);
@@ -94,20 +132,18 @@ PVOID NtQueryKeyAlloc(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClas
return result; return result;
} }
LPWSTR ExpandEnvironmentStringsAlloc(LPCWSTR src)
bool FileExistsExpandEnvironmentStrings(const wchar_t *path)
{ {
bool result; wchar_t *result;
LPWSTR dst;
DWORD buffersize; DWORD buffersize;
DWORD size; DWORD size;
buffersize = ExpandEnvironmentStringsW(path, NULL, 0); buffersize = ExpandEnvironmentStringsW(src, NULL, 0);
dst = calloc(buffersize, sizeof *dst); result = calloc(buffersize, sizeof *result);
size = ExpandEnvironmentStringsW(path, dst, buffersize); size = ExpandEnvironmentStringsW(src, result, buffersize);
if ( !size || size > buffersize ) if ( !size || size > buffersize ) {
return false; free(result);
result = PathFileExistsW(dst); result = NULL;
free(dst); }
return result; return result;
} }

View File

@@ -1,18 +1,24 @@
#pragma once #pragma once
bool InitializeMutex(bool InitialOwner, const wchar_t *pMutexName, HANDLE *phMutex); bool InitializeMutex(bool InitialOwner, LPCWSTR pMutexName, HANDLE *phMutex);
bool CreateEventWithStringSecurityDescriptor( bool CreateEventWithStringSecurityDescriptor(
const wchar_t *pStringSecurityDescriptor, LPCWSTR pStringSecurityDescriptor,
bool ManualReset, bool ManualReset,
bool InitialState, bool InitialState,
const wchar_t *pName, LPCWSTR pName,
HANDLE *phEvent); HANDLE *phEvent);
PVOID RegGetValueAlloc( PVOID RegGetValueAlloc(
HKEY hkey, HKEY hkey,
const wchar_t *pSubKey, LPCWSTR pSubKey,
const wchar_t *pValue, LPCWSTR pValue,
DWORD dwFlags, DWORD dwFlags,
LPDWORD pdwType, LPDWORD pdwType,
LPDWORD pcbData); LPDWORD pcbData);
LPBYTE RegQueryValueExAlloc(
HKEY hKey,
LPCWSTR pSubKey,
LPCWSTR pValueName,
LPDWORD pType,
LPDWORD pcbData);
PVOID NtQueryKeyAlloc(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PULONG pResultLength); PVOID NtQueryKeyAlloc(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PULONG pResultLength);
bool FileExistsExpandEnvironmentStrings(const wchar_t *path); LPWSTR ExpandEnvironmentStringsAlloc(LPCWSTR src);

View File

@@ -33,6 +33,7 @@ LPQUERY_SERVICE_CONFIGW QueryServiceConfigAlloc(
result = malloc(cbBytesNeeded); result = malloc(cbBytesNeeded);
if ( result ) { if ( result ) {
if ( QueryServiceConfigW(hService, result, cbBytesNeeded, &cbBytesNeeded) ) { if ( QueryServiceConfigW(hService, result, cbBytesNeeded, &cbBytesNeeded) ) {
if ( pcbBufSize )
*pcbBufSize = cbBytesNeeded; *pcbBufSize = cbBytesNeeded;
} else { } else {
free(result); free(result);
@@ -53,10 +54,8 @@ bool QueryServiceStatusProcessInfoByName(
DWORD cbBytesNeeded; DWORD cbBytesNeeded;
hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_STATUS); hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_STATUS);
if ( !hService ) { if ( !hService )
trace(L"Failed to open service %ls! (GetLastError=%ul)", pServiceName, GetLastError());
return result; return result;
}
result = !!QueryServiceStatusEx(hService, result = !!QueryServiceStatusEx(hService,
SC_STATUS_PROCESS_INFO, 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) DWORD HeuristicServiceGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupNameSearch)
{ {
wchar_t *pData; wchar_t *pData;
DWORD cbData;
DWORD result = 0; DWORD result = 0;
DWORD dwProcessId; DWORD dwProcessId;
DWORD cbBufSize; DWORD cbBufSize;
LPQUERY_SERVICE_CONFIGW pServiceConfig; LPQUERY_SERVICE_CONFIGW pServiceConfig;
bool success; bool success = false;
LPWSTR pGroupName; LPWSTR pGroupName;
HLOCAL hMem; HLOCAL hMem;
@@ -133,27 +131,25 @@ DWORD HeuristicServiceGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupNameSe
pGroupNameSearch, pGroupNameSearch,
RRF_RT_REG_MULTI_SZ, RRF_RT_REG_MULTI_SZ,
NULL, NULL,
&cbData); NULL);
if ( !pData ) return result; if ( !pData ) return result;
for ( wchar_t *pName = pData; *pName; pName += wcslen(pName) + 1 ) { for ( wchar_t *pName = pData; *pName; pName += wcslen(pName) + 1 ) {
dwProcessId = QueryServiceProcessIdByName(hSCM, pName); dwProcessId = QueryServiceProcessIdByName(hSCM, pName);
trace(L"pName=%ls dwProcessId=%lu", pName, dwProcessId);
if ( !dwProcessId ) continue; if ( !dwProcessId ) continue;
pServiceConfig = QueryServiceConfigByNameAlloc(hSCM, pName, &cbBufSize); pServiceConfig = QueryServiceConfigByNameAlloc(hSCM, pName, &cbBufSize);
if ( !pServiceConfig ) continue; if ( !pServiceConfig ) continue;
success = QueryServiceGroupName(pServiceConfig, &pGroupName, &hMem); if ( pServiceConfig->dwServiceType == SERVICE_WIN32_SHARE_PROCESS
free(pServiceConfig); && QueryServiceGroupName(pServiceConfig, &pGroupName, &hMem) ) {
if ( !success )
continue;
success = !_wcsicmp(pGroupNameSearch, pGroupName); success = !_wcsicmp(pGroupNameSearch, pGroupName);
LocalFree(hMem); LocalFree(hMem);
}
free(pServiceConfig);
if ( success ) { if ( success ) {
trace(L"Found PID: %lu", dwProcessId);
result = dwProcessId; result = dwProcessId;
break; break;
} }
@@ -168,13 +164,12 @@ DWORD HeuristicServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService)
LPQUERY_SERVICE_CONFIGW pServiceConfig; LPQUERY_SERVICE_CONFIGW pServiceConfig;
LPWSTR pGroupName; LPWSTR pGroupName;
HLOCAL hMem; HLOCAL hMem;
DWORD cbBufSize;
result = QueryServiceProcessId(hSCM, hService); result = QueryServiceProcessId(hSCM, hService);
if ( result ) if ( result )
return result; return result;
pServiceConfig = QueryServiceConfigAlloc(hSCM, hService, &cbBufSize); pServiceConfig = QueryServiceConfigAlloc(hSCM, hService, NULL);
if ( pServiceConfig ) { if ( pServiceConfig ) {
switch ( pServiceConfig->dwServiceType ) { switch ( pServiceConfig->dwServiceType ) {
case SERVICE_WIN32_OWN_PROCESS: case SERVICE_WIN32_OWN_PROCESS:
@@ -190,12 +185,12 @@ DWORD HeuristicServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService)
if ( QueryServiceGroupName(pServiceConfig, &pGroupName, &hMem) ) { if ( QueryServiceGroupName(pServiceConfig, &pGroupName, &hMem) ) {
result = HeuristicServiceGroupProcessId(hSCM, pGroupName); result = HeuristicServiceGroupProcessId(hSCM, pGroupName);
LocalFree(hMem); LocalFree(hMem);
return result;
} }
break; break;
} }
free(pServiceConfig); free(pServiceConfig);
} }
return result;
} }
DWORD HeuristicServiceProcessIdByName(SC_HANDLE hSCM, const wchar_t *pServiceName) DWORD HeuristicServiceProcessIdByName(SC_HANDLE hSCM, const wchar_t *pServiceName)

View File

@@ -21,13 +21,19 @@ LSTATUS WINAPI RegQueryValueExW_hook(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpR
int pos; int pos;
LPWSTR fname; LPWSTR fname;
const WCHAR realpath[] = L"%systemroot%\\system32\\wuaueng.dll"; const WCHAR realpath[] = L"%systemroot%\\system32\\wuaueng.dll";
wchar_t *expandedpath;
// save original buffer size // save original buffer size
if ( lpData && lpcbData ) if ( lpData && lpcbData )
MaximumLength = *lpcbData; MaximumLength = *lpcbData;
result = g_pfnRegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, 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; return result;
pBuffer = (PWCH)lpData; pBuffer = (PWCH)lpData;
@@ -36,22 +42,28 @@ LSTATUS WINAPI RegQueryValueExW_hook(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpR
pkni = NtQueryKeyAlloc((HANDLE)hKey, KeyNameInformation, &ResultLength); pkni = NtQueryKeyAlloc((HANDLE)hKey, KeyNameInformation, &ResultLength);
if ( !pkni ) if ( !pkni )
return result; return result;
NameCount = pkni->NameLength / sizeof *pkni->Name; NameCount = pkni->NameLength / sizeof *pkni->Name;
// change key name to lower-case because there is no case-insensitive version of _snwscanf_s // change key name to lower-case because there is no case-insensitive version of _snwscanf_s
if ( !_wcslwr_s(pkni->Name, NameCount) for ( size_t i = 0; i < NameCount; i++ )
&& _snwscanf_s(pkni->Name, NameCount, L"\\registry\\machine\\system\\controlset%03d\\services\\wuauserv\\parameters%n", &current, &pos) == 1 pkni->Name[i] = towlower(pkni->Name[i]);
if ( _snwscanf_s(pkni->Name, NameCount, L"\\registry\\machine\\system\\controlset%03d\\services\\wuauserv\\parameters%n", &current, &pos) == 1
&& pos == NameCount ) { && pos == NameCount ) {
fname = PathFindFileNameW(pBuffer); fname = PathFindFileNameW(pBuffer);
if ( (!_wcsicmp(fname, L"wuaueng2.dll") // UpdatePack7R2 if ( (!_wcsicmp(fname, L"wuaueng2.dll") // UpdatePack7R2
|| !_wcsicmp(fname, L"WuaCpuFix64.dll") // WuaCpuFix || !_wcsicmp(fname, L"WuaCpuFix64.dll") // WuaCpuFix
|| !_wcsicmp(fname, L"WuaCpuFix.dll")) || !_wcsicmp(fname, L"WuaCpuFix.dll")) ) {
&& FileExistsExpandEnvironmentStrings(realpath)
&& SUCCEEDED(StringCbCopyW(pBuffer, MaximumLength, 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; *lpcbData = sizeof realpath;
free(expandedpath);
} }
} }
free(pkni); free(pkni);