new hybrid method (improved group heuristic method + NotifyServiceStatusChange API)
This commit is contained in:
@@ -5,66 +5,23 @@
|
||||
#include "hlpmem.h"
|
||||
#include "hlpsvc.h"
|
||||
|
||||
bool DuplicateContextHandles(HANDLE hSrcProcess, ContextHandles *pSrcContext, HANDLE hAuxiliaryMutex, HANDLE hTargetProcess, ContextHandles *pTargetContext)
|
||||
{
|
||||
return
|
||||
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);
|
||||
}
|
||||
|
||||
VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer)
|
||||
{
|
||||
HANDLE hProcess;
|
||||
wchar_t MutexName[44];
|
||||
HANDLE hAuxiliaryMutex;
|
||||
ContextHandles TargetContext;
|
||||
|
||||
trace(L"Enter service notify callback. (NotifyStatus=%ld ServiceStatus=%ld)", pNotifyBuffer->dwNotificationStatus, pNotifyBuffer->ServiceStatus);
|
||||
switch ( pNotifyBuffer->dwNotificationStatus ) {
|
||||
case ERROR_SUCCESS:
|
||||
if ( !pNotifyBuffer->ServiceStatus.dwProcessId
|
||||
|| swprintf_s(MutexName, _countof(MutexName),
|
||||
L"Global\\%08x-7132-44a8-be15-56698979d2f3",
|
||||
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);
|
||||
if ( pNotifyBuffer->ServiceStatus.dwProcessId )
|
||||
wufuc_InjectLibrary(pNotifyBuffer->ServiceStatus.dwProcessId, (ContextHandles *)pNotifyBuffer->pContext);
|
||||
break;
|
||||
case ERROR_SERVICE_MARKED_FOR_DELETE:
|
||||
SetEvent((HANDLE)pNotifyBuffer->pContext);
|
||||
SetEvent(((ContextHandles *)pNotifyBuffer->pContext)->hUnloadEvent);
|
||||
break;
|
||||
}
|
||||
if ( pNotifyBuffer->pszServiceNames )
|
||||
LocalFree((HLOCAL)pNotifyBuffer->pszServiceNames);
|
||||
}
|
||||
|
||||
DWORD WINAPI StartAddress(LPVOID pParam)
|
||||
DWORD WINAPI ThreadStartCallback(LPVOID pParam)
|
||||
{
|
||||
ContextHandles ctx;
|
||||
SC_HANDLE hSCM;
|
||||
@@ -80,12 +37,12 @@ DWORD WINAPI StartAddress(LPVOID pParam)
|
||||
}
|
||||
ctx = *(ContextHandles *)pParam;
|
||||
if ( !VirtualFree(pParam, 0, MEM_RELEASE) )
|
||||
trace(L"Failed to free context parameter. pParam=%p GetLastError=%lu",
|
||||
trace(L"Failed to free context parameter. (%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);
|
||||
if ( WaitForSingleObject(ctx.hChildMutex, 5000) != WAIT_OBJECT_0 ) {
|
||||
trace(L"Failed to acquire aux mutex within five seconds. (%p)", ctx.hChildMutex);
|
||||
goto close_handles;
|
||||
}
|
||||
|
||||
@@ -95,15 +52,13 @@ DWORD WINAPI StartAddress(LPVOID pParam)
|
||||
goto release;
|
||||
}
|
||||
|
||||
dwProcessId = QueryServiceProcessId(hSCM, L"wuauserv");
|
||||
dwProcessId = HeuristicServiceProcessIdByName(hSCM, L"wuauserv");
|
||||
CloseServiceHandle(hSCM);
|
||||
if ( dwProcessId != GetCurrentProcessId() ) {
|
||||
trace(L"Injected into wrong process! CurrentProcessId=%lu wuauserv ProcessId=%lu",
|
||||
GetCurrentProcessId, dwProcessId);
|
||||
trace(L"Injected into wrong process!", GetCurrentProcessId(), dwProcessId);
|
||||
goto release;
|
||||
}
|
||||
|
||||
// hook IsDeviceServiceable
|
||||
g_pszWUServiceDll = RegGetValueAlloc(HKEY_LOCAL_MACHINE,
|
||||
L"SYSTEM\\CurrentControlSet\\services\\wuauserv\\Parameters",
|
||||
L"ServiceDll",
|
||||
@@ -111,6 +66,8 @@ DWORD WINAPI StartAddress(LPVOID pParam)
|
||||
NULL,
|
||||
&cbData);
|
||||
|
||||
trace(L"Installing hooks...");
|
||||
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
|
||||
@@ -119,16 +76,32 @@ DWORD WINAPI StartAddress(LPVOID pParam)
|
||||
if ( g_pfnLoadLibraryExW )
|
||||
DetourAttach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook);
|
||||
|
||||
// hook IsDeviceServiceable
|
||||
if ( g_pszWUServiceDll ) {
|
||||
hModule = GetModuleHandleW(g_pszWUServiceDll);
|
||||
if ( hModule && FindIsDeviceServiceablePtr(hModule,
|
||||
&(PVOID)g_pfnIsDeviceServiceable) ) {
|
||||
|
||||
if ( hModule ) {
|
||||
if ( FindIDSFunctionPointer(hModule, &(PVOID)g_pfnIsDeviceServiceable) ) {
|
||||
trace(L"Matched pattern for %ls!IsDeviceServiceable. (%p)",
|
||||
PathFindFileNameW(g_pszWUServiceDll),
|
||||
g_pfnIsDeviceServiceable);
|
||||
DetourAttach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook);
|
||||
} 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();
|
||||
|
||||
}
|
||||
|
||||
DetourTransactionCommit();
|
||||
|
||||
// wait for unload event or parent mutex to be abandoned.
|
||||
// for example if the user killed rundll32.exe with task manager.
|
||||
@@ -136,30 +109,34 @@ DWORD WINAPI StartAddress(LPVOID pParam)
|
||||
// which point it becomes abandoned again.
|
||||
result = WaitForMultipleObjects(_countof(ctx.handles), ctx.handles, FALSE, INFINITE);
|
||||
|
||||
trace(L"Unloading!");
|
||||
trace(L"Unload condition has been met.");
|
||||
|
||||
// unhook
|
||||
if ( g_pfnLoadLibraryExW || g_pfnIsDeviceServiceable ) {
|
||||
if ( g_pfnLoadLibraryExW || g_pfnIsDeviceServiceable || g_pfnRegQueryValueExW) {
|
||||
trace(L"Removing hooks...");
|
||||
trace(L"DetourTransactionBegin %lu", DetourTransactionBegin());
|
||||
trace(L"DetourUpdateThread %lu", DetourUpdateThread(GetCurrentThread()));
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
|
||||
if ( g_pfnLoadLibraryExW )
|
||||
trace(L"DetourDetach LoadLibraryExW %lu", DetourDetach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook));
|
||||
DetourDetach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook);
|
||||
|
||||
if ( g_pfnIsDeviceServiceable )
|
||||
trace(L"DetourDetach IsDeviceServiceable %lu", DetourDetach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook));
|
||||
DetourDetach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook);
|
||||
|
||||
trace(L"DetourTransactionCommit %lu", DetourTransactionCommit());
|
||||
if ( g_pfnRegQueryValueExW )
|
||||
DetourDetach(&(PVOID)g_pfnRegQueryValueExW, RegQueryValueExW_hook);
|
||||
|
||||
DetourTransactionCommit();
|
||||
}
|
||||
free(g_pszWUServiceDll);
|
||||
|
||||
release:
|
||||
ReleaseMutex(ctx.hAuxiliaryMutex);
|
||||
ReleaseMutex(ctx.hChildMutex);
|
||||
close_handles:
|
||||
CloseHandle(ctx.hAuxiliaryMutex);
|
||||
CloseHandle(ctx.hMainMutex);
|
||||
CloseHandle(ctx.hChildMutex);
|
||||
CloseHandle(ctx.hParentMutex);
|
||||
CloseHandle(ctx.hUnloadEvent);
|
||||
unload:
|
||||
trace(L"Freeing library and exiting main thread.");
|
||||
FreeLibraryAndExitThread(PIMAGEBASE, 0);
|
||||
}
|
@@ -1,25 +1,4 @@
|
||||
#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);
|
||||
DWORD WINAPI ThreadStartCallback(LPVOID pParam);
|
||||
|
@@ -6,7 +6,6 @@ BOOL APIENTRY DllMain(HMODULE hModule,
|
||||
{
|
||||
switch ( ul_reason_for_call ) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
|
@@ -1,10 +1,11 @@
|
||||
#include "stdafx.h"
|
||||
#include "hlpmisc.h"
|
||||
#include "hlpmem.h"
|
||||
#include "hlpver.h"
|
||||
#include "hooks.h"
|
||||
#include <sddl.h>
|
||||
#include "callbacks.h"
|
||||
|
||||
bool FindIsDeviceServiceablePtr(HMODULE hModule, PVOID *ppfnIsDeviceServiceable)
|
||||
bool FindIDSFunctionPointer(HMODULE hModule, PVOID *ppfnIsDeviceServiceable)
|
||||
{
|
||||
bool result = false;
|
||||
bool is_win7 = false;
|
||||
@@ -21,14 +22,12 @@ bool FindIsDeviceServiceablePtr(HMODULE hModule, PVOID *ppfnIsDeviceServiceable)
|
||||
MODULEINFO modinfo;
|
||||
size_t offset;
|
||||
|
||||
is_win7 = IsWindowsVersion(6, 1, 1);
|
||||
if ( !is_win7 ) {
|
||||
is_win81 = IsWindowsVersion(6, 3, 0);
|
||||
if ( !is_win81 ) {
|
||||
if ( !((is_win7 = IsWindowsVersion(6, 1, 1))
|
||||
|| (is_win81 = IsWindowsVersion(6, 3, 0))) ) {
|
||||
|
||||
trace(L"Unsupported operating system.");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
ptl = GetVersionInfoFromHModuleAlloc(hModule, L"\\VarFileInfo\\Translation", &cbtl);
|
||||
if ( !ptl ) {
|
||||
@@ -54,7 +53,7 @@ bool FindIsDeviceServiceablePtr(HMODULE hModule, PVOID *ppfnIsDeviceServiceable)
|
||||
// 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);
|
||||
trace(L"Module internal name does not match. (%ls)", pInternalName);
|
||||
free(pInternalName);
|
||||
if ( tmp )
|
||||
continue;
|
||||
@@ -66,8 +65,8 @@ bool FindIsDeviceServiceablePtr(HMODULE hModule, PVOID *ppfnIsDeviceServiceable)
|
||||
}
|
||||
|
||||
// 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));
|
||||
tmp = ((is_win7 && ProductVersionCompare(pffi, 7, 6, 7601, 23714) != -1)
|
||||
|| (is_win81 && ProductVersionCompare(pffi, 7, 9, 9600, 18621) != -1));
|
||||
free(pffi);
|
||||
if ( !tmp ) {
|
||||
trace(L"Module does not meet the minimum supported version.");
|
||||
@@ -89,10 +88,7 @@ bool FindIsDeviceServiceablePtr(HMODULE hModule, PVOID *ppfnIsDeviceServiceable)
|
||||
);
|
||||
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;
|
||||
}
|
||||
@@ -128,10 +124,9 @@ bool InjectLibraryAndCreateRemoteThread(
|
||||
|
||||
Status = NtSuspendProcess(hProcess);
|
||||
if ( !NT_SUCCESS(Status) ) return result;
|
||||
trace(L"Suspended process. hProcess=%p", hProcess);
|
||||
|
||||
if ( pParam ) {
|
||||
// this gets freed by pStartAddress
|
||||
// this will be VirtualFree()'d by the function at pStartAddress
|
||||
pBaseAddress = VirtualAllocEx(hProcess,
|
||||
NULL,
|
||||
cbParam,
|
||||
@@ -143,7 +138,7 @@ bool InjectLibraryAndCreateRemoteThread(
|
||||
goto vfree;
|
||||
}
|
||||
if ( InjectLibrary(hProcess, hModule, &hRemoteModule) ) {
|
||||
trace(L"Injected library. hRemoteModule=%p", hRemoteModule);
|
||||
trace(L"Injected library. (%p)", hRemoteModule);
|
||||
|
||||
hThread = CreateRemoteThread(hProcess,
|
||||
NULL,
|
||||
@@ -154,7 +149,6 @@ bool InjectLibraryAndCreateRemoteThread(
|
||||
NULL);
|
||||
|
||||
if ( hThread ) {
|
||||
trace(L"Created remote thread. hThread=%p", hThread);
|
||||
CloseHandle(hThread);
|
||||
result = true;
|
||||
}
|
||||
@@ -173,9 +167,6 @@ bool InjectLibrary(HANDLE hProcess, HMODULE hModule, HMODULE *phRemoteModule)
|
||||
|
||||
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,
|
||||
@@ -200,13 +191,11 @@ bool InjectLibraryByFilename(
|
||||
|
||||
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 resume;
|
||||
trace(L"Created TH32 module snapshot. dwProcessId=%lu", dwProcessId);
|
||||
|
||||
*phRemoteModule = GetRemoteHModuleFromTh32ModuleSnapshot(hSnapshot,
|
||||
pLibFilename);
|
||||
@@ -224,13 +213,9 @@ bool InjectLibraryByFilename(
|
||||
PAGE_READWRITE);
|
||||
|
||||
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 vfree;
|
||||
trace(L"Wrote to process memory. hProcess=%p pBaseAddress=%p pLibFileName=%.*ls nSize=%Iu",
|
||||
hProcess, pBaseAddress, cchLibFilename, pLibFilename, nSize);
|
||||
|
||||
hThread = CreateRemoteThread(hProcess,
|
||||
NULL,
|
||||
@@ -240,10 +225,8 @@ bool InjectLibraryByFilename(
|
||||
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);
|
||||
@@ -253,13 +236,51 @@ bool InjectLibraryByFilename(
|
||||
pLibFilename);
|
||||
|
||||
CloseHandle(hSnapshot);
|
||||
result = !!*phRemoteModule;
|
||||
result = *phRemoteModule != NULL;
|
||||
}
|
||||
} else {
|
||||
result = !!GetExitCodeThread(hThread, (LPDWORD)phRemoteModule);
|
||||
result = GetExitCodeThread(hThread, (LPDWORD)phRemoteModule) != FALSE;
|
||||
}
|
||||
CloseHandle(hThread);
|
||||
vfree: VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE);
|
||||
resume: NtResumeProcess(hProcess);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool wufuc_InjectLibrary(DWORD dwProcessId, ContextHandles *pContext)
|
||||
{
|
||||
bool result = false;
|
||||
HANDLE hProcess;
|
||||
wchar_t MutexName[44];
|
||||
HANDLE hChildMutex;
|
||||
HANDLE hSrcProcess;
|
||||
ContextHandles param = { 0 };
|
||||
|
||||
if ( swprintf_s(MutexName, _countof(MutexName), L"Global\\%08x-7132-44a8-be15-56698979d2f3", dwProcessId) == -1 ) {
|
||||
trace(L"Failed to print mutex name to string! (%lu)", dwProcessId);
|
||||
return result;
|
||||
}
|
||||
if ( !InitializeMutex(false, MutexName, &hChildMutex) ) {
|
||||
return result;
|
||||
}
|
||||
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
|
||||
|
||||
if ( !hProcess ) {
|
||||
trace(L"Failed to open target process! (GetLastError=%lu)", GetLastError());
|
||||
goto close_mutex;
|
||||
};
|
||||
hSrcProcess = GetCurrentProcess();
|
||||
|
||||
if ( DuplicateHandle(hSrcProcess, pContext->hParentMutex, hProcess, ¶m.hParentMutex, SYNCHRONIZE, FALSE, 0)
|
||||
&& 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);
|
||||
} else {
|
||||
trace(L"Failed to duplicate context handles! (GetLastError=%lu", GetLastError());
|
||||
}
|
||||
CloseHandle(hProcess);
|
||||
close_mutex:
|
||||
CloseHandle(hChildMutex);
|
||||
return result;
|
||||
}
|
||||
|
@@ -1,12 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct
|
||||
{
|
||||
HANDLE hChildMutex;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
HANDLE hParentMutex;
|
||||
HANDLE hUnloadEvent;
|
||||
} DUMMYSTRUCTNAME;
|
||||
struct
|
||||
{
|
||||
HANDLE hMainMutex;
|
||||
HANDLE hUnloadEvent;
|
||||
} u;
|
||||
HANDLE handles[2];
|
||||
};
|
||||
} ContextHandles;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD wLanguage;
|
||||
WORD wCodePage;
|
||||
} LANGANDCODEPAGE, *PLANGANDCODEPAGE;
|
||||
|
||||
bool FindIsDeviceServiceablePtr(HMODULE hModule, PVOID *ppfnIsDeviceServiceable);
|
||||
bool FindIDSFunctionPointer(HMODULE hModule, PVOID *ppfnIsDeviceServiceable);
|
||||
HANDLE GetRemoteHModuleFromTh32ModuleSnapshot(HANDLE hSnapshot, const wchar_t *pLibFileName);
|
||||
bool InjectLibraryAndCreateRemoteThread(
|
||||
HANDLE hProcess,
|
||||
@@ -20,3 +41,4 @@ bool InjectLibraryByFilename(
|
||||
const wchar_t *pLibFilename,
|
||||
size_t cchLibFilename,
|
||||
HMODULE *phRemoteModule);
|
||||
bool wufuc_InjectLibrary(DWORD dwProcessId, ContextHandles *pContext);
|
||||
|
@@ -14,6 +14,8 @@ bool InitializeMutex(bool InitialOwner, const wchar_t *pMutexName, HANDLE *phMut
|
||||
}
|
||||
*phMutex = hMutex;
|
||||
return true;
|
||||
} else {
|
||||
trace(L"Failed to create mutex: %ls (GetLastError=%ld)", pMutexName, GetLastError());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -68,3 +70,44 @@ PVOID RegGetValueAlloc(
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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 = PathFileExistsW(dst);
|
||||
free(dst);
|
||||
return result;
|
||||
}
|
||||
|
@@ -14,3 +14,5 @@ PVOID RegGetValueAlloc(
|
||||
DWORD dwFlags,
|
||||
LPDWORD pdwType,
|
||||
LPDWORD pcbData);
|
||||
PVOID NtQueryKeyAlloc(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PULONG pResultLength);
|
||||
bool FileExistsExpandEnvironmentStrings(const wchar_t *path);
|
||||
|
@@ -8,12 +8,25 @@ LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(
|
||||
LPDWORD pcbBufSize)
|
||||
{
|
||||
SC_HANDLE hService;
|
||||
DWORD cbBytesNeeded;
|
||||
LPQUERY_SERVICE_CONFIGW result = NULL;
|
||||
|
||||
hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_CONFIG);
|
||||
if ( !hService ) return result;
|
||||
|
||||
result = QueryServiceConfigAlloc(hSCM, hService, pcbBufSize);
|
||||
|
||||
CloseServiceHandle(hService);
|
||||
return result;
|
||||
}
|
||||
|
||||
LPQUERY_SERVICE_CONFIGW QueryServiceConfigAlloc(
|
||||
SC_HANDLE hSCM,
|
||||
SC_HANDLE hService,
|
||||
LPDWORD pcbBufSize)
|
||||
{
|
||||
DWORD cbBytesNeeded;
|
||||
LPQUERY_SERVICE_CONFIGW result = NULL;
|
||||
|
||||
if ( !QueryServiceConfigW(hService, NULL, 0, &cbBytesNeeded)
|
||||
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
|
||||
|
||||
@@ -27,7 +40,6 @@ LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseServiceHandle(hService);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -55,7 +67,7 @@ bool QueryServiceStatusProcessInfoByName(
|
||||
return result;
|
||||
}
|
||||
|
||||
bool QueryServiceGroupName(const LPQUERY_SERVICE_CONFIGW pServiceConfig, wchar_t *pGroupName, size_t nSize)
|
||||
bool QueryServiceGroupName(const LPQUERY_SERVICE_CONFIGW pServiceConfig, LPWSTR *pGroupName, HLOCAL *hMem)
|
||||
{
|
||||
bool result = false;
|
||||
int NumArgs;
|
||||
@@ -66,16 +78,36 @@ bool QueryServiceGroupName(const LPQUERY_SERVICE_CONFIGW pServiceConfig, wchar_t
|
||||
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]);
|
||||
if ( !_wcsicmp(argv[i], L"-k") ) {
|
||||
*pGroupName = argv[++i];
|
||||
*hMem = (HLOCAL)argv;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
LocalFree((HLOCAL)argv);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD QueryServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService)
|
||||
{
|
||||
DWORD result = 0;
|
||||
SERVICE_STATUS_PROCESS ServiceStatus;
|
||||
DWORD cbBytesNeeded;
|
||||
|
||||
if ( QueryServiceStatusEx(hService,
|
||||
SC_STATUS_PROCESS_INFO,
|
||||
(LPBYTE)&ServiceStatus,
|
||||
sizeof ServiceStatus,
|
||||
&cbBytesNeeded) ) {
|
||||
|
||||
result = ServiceStatus.dwProcessId;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DWORD QueryServiceProcessId(SC_HANDLE hSCM, const wchar_t *pServiceName)
|
||||
DWORD QueryServiceProcessIdByName(SC_HANDLE hSCM, const wchar_t *pServiceName)
|
||||
{
|
||||
SERVICE_STATUS_PROCESS ServiceStatusProcess;
|
||||
|
||||
@@ -84,31 +116,44 @@ DWORD QueryServiceProcessId(SC_HANDLE hSCM, const wchar_t *pServiceName)
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD InferSvchostGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupName)
|
||||
DWORD HeuristicServiceGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupNameSearch)
|
||||
{
|
||||
DWORD result = 0;
|
||||
DWORD cbData;
|
||||
wchar_t *pData;
|
||||
DWORD cbData;
|
||||
DWORD result = 0;
|
||||
DWORD dwProcessId;
|
||||
DWORD cbBufSize;
|
||||
LPQUERY_SERVICE_CONFIGW pServiceConfig;
|
||||
bool success;
|
||||
WCHAR GroupName[256];
|
||||
LPWSTR pGroupName;
|
||||
HLOCAL hMem;
|
||||
|
||||
pData = RegGetValueAlloc(HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost",
|
||||
pGroupNameSearch,
|
||||
RRF_RT_REG_MULTI_SZ,
|
||||
NULL,
|
||||
&cbData);
|
||||
|
||||
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);
|
||||
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, GroupName, _countof(GroupName));
|
||||
|
||||
success = QueryServiceGroupName(pServiceConfig, &pGroupName, &hMem);
|
||||
free(pServiceConfig);
|
||||
if ( success && !_wcsicmp(pGroupName, GroupName) ) {
|
||||
trace(L"found PID for group %ls: %lu", pGroupName, dwProcessId);
|
||||
if ( !success )
|
||||
continue;
|
||||
|
||||
success = !_wcsicmp(pGroupNameSearch, pGroupName);
|
||||
LocalFree(hMem);
|
||||
if ( success ) {
|
||||
trace(L"Found PID: %lu", dwProcessId);
|
||||
result = dwProcessId;
|
||||
break;
|
||||
}
|
||||
@@ -116,3 +161,51 @@ DWORD InferSvchostGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupName)
|
||||
free(pData);
|
||||
return result;
|
||||
}
|
||||
|
||||
DWORD HeuristicServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService)
|
||||
{
|
||||
DWORD result = 0;
|
||||
LPQUERY_SERVICE_CONFIGW pServiceConfig;
|
||||
LPWSTR pGroupName;
|
||||
HLOCAL hMem;
|
||||
DWORD cbBufSize;
|
||||
|
||||
result = QueryServiceProcessId(hSCM, hService);
|
||||
if ( result )
|
||||
return result;
|
||||
|
||||
pServiceConfig = QueryServiceConfigAlloc(hSCM, hService, &cbBufSize);
|
||||
if ( pServiceConfig ) {
|
||||
switch ( pServiceConfig->dwServiceType ) {
|
||||
case SERVICE_WIN32_OWN_PROCESS:
|
||||
// if the service isn't already running there's no
|
||||
// way to accurately guess the PID when it is set to
|
||||
// run in its own process. returns 0
|
||||
break;
|
||||
case SERVICE_WIN32_SHARE_PROCESS:
|
||||
// when the service is configured to run in a shared
|
||||
// process, it is possible to "guess" which svchost.exe
|
||||
// it will eventually be loaded into by finding other
|
||||
// services in the same group that are already running.
|
||||
if ( QueryServiceGroupName(pServiceConfig, &pGroupName, &hMem) ) {
|
||||
result = HeuristicServiceGroupProcessId(hSCM, pGroupName);
|
||||
LocalFree(hMem);
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
free(pServiceConfig);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD HeuristicServiceProcessIdByName(SC_HANDLE hSCM, const wchar_t *pServiceName)
|
||||
{
|
||||
DWORD result = 0;
|
||||
SC_HANDLE hService;
|
||||
|
||||
hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
|
||||
result = HeuristicServiceProcessId(hSCM, hService);
|
||||
CloseServiceHandle(hService);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
@@ -4,10 +4,17 @@ LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(
|
||||
SC_HANDLE hSCM,
|
||||
const wchar_t *pServiceName,
|
||||
LPDWORD pcbBufSize);
|
||||
LPQUERY_SERVICE_CONFIGW QueryServiceConfigAlloc(
|
||||
SC_HANDLE hSCM,
|
||||
SC_HANDLE hService,
|
||||
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);
|
||||
DWORD QueryServiceProcessId(SC_HANDLE hSCM, const wchar_t *pServiceName);
|
||||
DWORD InferSvchostGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupName);
|
||||
bool QueryServiceGroupName(const LPQUERY_SERVICE_CONFIGW pServiceConfig, LPWSTR *pGroupName, HLOCAL *hMem);
|
||||
DWORD QueryServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService);
|
||||
DWORD QueryServiceProcessIdByName(SC_HANDLE hSCM, const wchar_t *pServiceName);
|
||||
DWORD HeuristicServiceGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupName);
|
||||
DWORD HeuristicServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService);
|
||||
DWORD HeuristicServiceProcessIdByName(SC_HANDLE hSCM, const wchar_t *pServiceName);
|
@@ -1,7 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "hlpver.h"
|
||||
|
||||
int FileInfoVerCompare(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wBuild, WORD wRev)
|
||||
int ProductVersionCompare(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wBuild, WORD wRev)
|
||||
{
|
||||
if ( HIWORD(pffi->dwProductVersionMS) < wMajor ) return -1;
|
||||
if ( HIWORD(pffi->dwProductVersionMS) > wMajor ) return 1;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
int FileInfoVerCompare(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wBuild, WORD wRev);
|
||||
int ProductVersionCompare(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wBuild, WORD wRev);
|
||||
bool GetVersionInfoFromHModule(HMODULE hModule, LPCWSTR pszSubBlock, LPVOID pData, PUINT pcbData);
|
||||
LPVOID GetVersionInfoFromHModuleAlloc(HMODULE hModule, LPCWSTR pszSubBlock, PUINT pcbData);
|
||||
bool IsWindowsVersion(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor);
|
||||
|
@@ -1,13 +1,62 @@
|
||||
#include "stdafx.h"
|
||||
#include "hooks.h"
|
||||
#include "hlpmem.h"
|
||||
#include "hlpmisc.h"
|
||||
#include "hlpsvc.h"
|
||||
#include "hlpmem.h"
|
||||
|
||||
LPWSTR g_pszWUServiceDll;
|
||||
|
||||
LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceable;
|
||||
LPFN_REGQUERYVALUEEXW g_pfnRegQueryValueExW;
|
||||
LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW;
|
||||
LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceable;
|
||||
|
||||
LSTATUS WINAPI RegQueryValueExW_hook(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
|
||||
{
|
||||
PWCH pBuffer;
|
||||
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";
|
||||
|
||||
// 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") )
|
||||
return result;
|
||||
|
||||
pBuffer = (PWCH)lpData;
|
||||
|
||||
// get name of registry key being queried
|
||||
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
|
||||
&& 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)) ) {
|
||||
|
||||
*lpcbData = sizeof realpath;
|
||||
}
|
||||
}
|
||||
free(pkni);
|
||||
return result;
|
||||
}
|
||||
|
||||
HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags)
|
||||
{
|
||||
@@ -15,21 +64,29 @@ 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 (%p)", lpFileName, result);
|
||||
|
||||
if ( g_pszWUServiceDll
|
||||
&& !_wcsicmp(lpFileName, g_pszWUServiceDll)
|
||||
&& FindIsDeviceServiceablePtr(result, &(PVOID)g_pfnIsDeviceServiceable) ) {
|
||||
&& !_wcsicmp(lpFileName, g_pszWUServiceDll) ) {
|
||||
|
||||
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());
|
||||
if ( FindIDSFunctionPointer(result, &(PVOID)g_pfnIsDeviceServiceable) ) {
|
||||
trace(L"Matched pattern for %ls!IsDeviceServiceable. (%p)",
|
||||
PathFindFileNameW(lpFileName),
|
||||
g_pfnIsDeviceServiceable);
|
||||
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
DetourAttach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook);
|
||||
DetourTransactionCommit();
|
||||
} else if ( !g_pfnIsDeviceServiceable ) {
|
||||
trace(L"No pattern matched!");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL WINAPI IsDeviceServiceable_hook(void)
|
||||
{
|
||||
trace(L"Entered stub function.");
|
||||
return TRUE;
|
||||
}
|
||||
|
@@ -1,13 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
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 LPWSTR g_pszWUServiceDll;
|
||||
|
||||
extern LPFN_REGQUERYVALUEEXW g_pfnRegQueryValueExW;
|
||||
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);
|
||||
|
@@ -1,11 +1,14 @@
|
||||
#include "stdafx.h"
|
||||
#include "callbacks.h"
|
||||
#include "hlpmisc.h"
|
||||
|
||||
#include "hlpmem.h"
|
||||
#include "hlpsvc.h"
|
||||
|
||||
void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
|
||||
{
|
||||
ContextHandles ctx;
|
||||
DWORD dwDesiredAccess;
|
||||
DWORD dwProcessId;
|
||||
bool Unloading = false;
|
||||
bool Lagging;
|
||||
SC_HANDLE hSCM;
|
||||
@@ -14,7 +17,7 @@ void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, in
|
||||
|
||||
if ( !InitializeMutex(true,
|
||||
L"Global\\25020063-b5a7-4227-9fdf-25cb75e8c645",
|
||||
&ctx.hMainMutex) ) {
|
||||
&ctx.hParentMutex) ) {
|
||||
|
||||
trace(L"Failed to initialize main mutex. (GetLastError=%ul)", GetLastError());
|
||||
return;
|
||||
@@ -28,6 +31,7 @@ void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, in
|
||||
trace(L"Failed to create unload event. (GetLastError=%ul)", GetLastError());
|
||||
goto close_mutex;
|
||||
}
|
||||
dwDesiredAccess = SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG;
|
||||
do {
|
||||
Lagging = false;
|
||||
hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
|
||||
@@ -36,12 +40,18 @@ void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, in
|
||||
goto close_event;
|
||||
}
|
||||
|
||||
hService = OpenServiceW(hSCM, L"wuauserv", SERVICE_QUERY_STATUS);
|
||||
hService = OpenServiceW(hSCM, L"wuauserv", dwDesiredAccess);
|
||||
if ( !hService ) {
|
||||
trace(L"Failed to open service. (GetLastError=%ul)", GetLastError());
|
||||
goto close_scm;
|
||||
}
|
||||
if ( (dwDesiredAccess & SERVICE_QUERY_CONFIG) == SERVICE_QUERY_CONFIG ) {
|
||||
dwDesiredAccess &= ~SERVICE_QUERY_CONFIG;
|
||||
|
||||
dwProcessId = HeuristicServiceProcessId(hSCM, hService);
|
||||
if ( dwProcessId )
|
||||
wufuc_InjectLibrary(dwProcessId, &ctx);
|
||||
}
|
||||
ZeroMemory(&NotifyBuffer, sizeof NotifyBuffer);
|
||||
NotifyBuffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
|
||||
NotifyBuffer.pfnNotifyCallback = ServiceNotifyCallback;
|
||||
@@ -68,8 +78,8 @@ close_scm: CloseServiceHandle(hSCM);
|
||||
close_event:
|
||||
CloseHandle(ctx.hUnloadEvent);
|
||||
close_mutex:
|
||||
ReleaseMutex(ctx.hMainMutex);
|
||||
CloseHandle(ctx.hMainMutex);
|
||||
ReleaseMutex(ctx.hParentMutex);
|
||||
CloseHandle(ctx.hParentMutex);
|
||||
}
|
||||
|
||||
void CALLBACK RUNDLL32_UnloadW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
|
||||
|
Reference in New Issue
Block a user