steady progress
This commit is contained in:
@@ -28,6 +28,8 @@ after_build:
|
|||||||
|
|
||||||
cd "%APPVEYOR_BUILD_FOLDER%\wufuc_setup_bat"
|
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 (*.txt) do unix2dos "%%i"
|
||||||
|
|
||||||
for /R %%i in (*.bat) do unix2dos "%%i"
|
for /R %%i in (*.bat) do unix2dos "%%i"
|
||||||
|
@@ -3,12 +3,59 @@
|
|||||||
#include "hooks.h"
|
#include "hooks.h"
|
||||||
#include "helpers.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)
|
VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer)
|
||||||
{
|
{
|
||||||
|
HANDLE hProcess;
|
||||||
|
wchar_t MutexName[37];
|
||||||
|
HANDLE hAuxiliaryMutex;
|
||||||
|
ContextHandles TargetContext;
|
||||||
|
|
||||||
switch ( pNotifyBuffer->dwNotificationStatus ) {
|
switch ( pNotifyBuffer->dwNotificationStatus ) {
|
||||||
case ERROR_SUCCESS:
|
case ERROR_SUCCESS:
|
||||||
if ( pNotifyBuffer->ServiceStatus.dwProcessId )
|
if ( !pNotifyBuffer->ServiceStatus.dwProcessId
|
||||||
InjectSelfAndCreateRemoteThread(pNotifyBuffer->ServiceStatus.dwProcessId, &StartAddress, (HANDLE)pNotifyBuffer->pContext, SYNCHRONIZE);
|
|| 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;
|
break;
|
||||||
case ERROR_SERVICE_MARKED_FOR_DELETE:
|
case ERROR_SERVICE_MARKED_FOR_DELETE:
|
||||||
SetEvent((HANDLE)pNotifyBuffer->pContext);
|
SetEvent((HANDLE)pNotifyBuffer->pContext);
|
||||||
@@ -20,65 +67,100 @@ VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer)
|
|||||||
|
|
||||||
DWORD WINAPI StartAddress(LPVOID pParam)
|
DWORD WINAPI StartAddress(LPVOID pParam)
|
||||||
{
|
{
|
||||||
|
ContextHandles ctx;
|
||||||
SC_HANDLE hSCM;
|
SC_HANDLE hSCM;
|
||||||
DWORD cbBufSize;
|
DWORD dwProcessId;
|
||||||
LPQUERY_SERVICE_CONFIGW pServiceConfig;
|
|
||||||
DWORD dwServiceType;
|
|
||||||
int result;
|
|
||||||
DWORD cbData;
|
DWORD cbData;
|
||||||
LPWSTR pServiceDll;
|
|
||||||
HMODULE hModule;
|
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);
|
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);
|
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;
|
// hook IsDeviceServiceable
|
||||||
result = _wcsicmp(pServiceConfig->lpBinaryPathName, GetCommandLineW());
|
g_pszWUServiceDll = RegGetValueAlloc(HKEY_LOCAL_MACHINE,
|
||||||
free(pServiceConfig);
|
L"SYSTEM\\CurrentControlSet\\services\\wuauserv\\Parameters",
|
||||||
if ( result ) goto cleanup;
|
L"ServiceDll",
|
||||||
|
RRF_RT_REG_SZ,
|
||||||
|
NULL,
|
||||||
|
&cbData);
|
||||||
|
|
||||||
DetourTransactionBegin();
|
DetourTransactionBegin();
|
||||||
DetourUpdateThread(GetCurrentThread());
|
DetourUpdateThread(GetCurrentThread());
|
||||||
|
|
||||||
// hook apis if configured as shared service
|
// hook LoadLibraryExW
|
||||||
/* if ( dwServiceType == SERVICE_WIN32_SHARE_PROCESS ) {
|
|
||||||
g_pfnLoadLibraryExW = DetourFindFunction("kernel32.dll", "LoadLibraryExW");
|
g_pfnLoadLibraryExW = DetourFindFunction("kernel32.dll", "LoadLibraryExW");
|
||||||
|
if ( g_pfnLoadLibraryExW )
|
||||||
DetourAttach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook);
|
DetourAttach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook);
|
||||||
|
|
||||||
g_pfnRegQueryValueExW = DetourFindFunction("kernel32.dll", "RegQueryValueExW");
|
if ( g_pszWUServiceDll ) {
|
||||||
DetourAttach(&(PVOID)g_pfnRegQueryValueExW, RegQueryValueExW_hook);
|
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);
|
DetourAttach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook);
|
||||||
|
}
|
||||||
free(pServiceDll);
|
|
||||||
}
|
}
|
||||||
DetourTransactionCommit();
|
DetourTransactionCommit();
|
||||||
|
|
||||||
// wait for unload event
|
|
||||||
WaitForSingleObject((HANDLE)pParam, INFINITE);
|
|
||||||
|
|
||||||
// unhook functions
|
// wait for unload event or parent mutex to be abandoned.
|
||||||
trace(L"DetourTransactionBegin result=%d", DetourTransactionBegin());
|
// for example if the user killed rundll32.exe with task manager.
|
||||||
trace(L"DetourUpdateThread result=%d", DetourUpdateThread(GetCurrentThread()));
|
// intentionally leave parent mutex open until this thread ends, at
|
||||||
//if ( g_pfnLoadLibraryExW )
|
// which point it becomes abandoned again.
|
||||||
// trace(L"DetourDetach LoadLibraryExW_hook result=%d", DetourDetach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook));
|
result = WaitForMultipleObjects(_countof(ctx.handles), ctx.handles, FALSE, INFINITE);
|
||||||
//if ( g_pfnRegQueryValueExW )
|
|
||||||
// trace(L"DetourDetach RegQueryValueExW_hook result=%d", DetourDetach(&(PVOID)g_pfnRegQueryValueExW, RegQueryValueExW_hook));
|
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 )
|
if ( g_pfnIsDeviceServiceable )
|
||||||
trace(L"DetourDetach IsDeviceServiceable_hook result=%d", DetourDetach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook));
|
trace(L"DetourDetach IsDeviceServiceable %lu", DetourDetach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook));
|
||||||
trace(L"DetourTransactionCommit result=%d", DetourTransactionCommit());
|
|
||||||
|
|
||||||
cleanup:
|
trace(L"DetourTransactionCommit %lu", DetourTransactionCommit());
|
||||||
CloseHandle((HANDLE)pParam);
|
}
|
||||||
|
free(g_pszWUServiceDll);
|
||||||
|
|
||||||
|
release:
|
||||||
|
ReleaseMutex(ctx.hAuxiliaryMutex);
|
||||||
|
close_handles:
|
||||||
|
CloseHandle(ctx.hAuxiliaryMutex);
|
||||||
|
CloseHandle(ctx.hMainMutex);
|
||||||
|
CloseHandle(ctx.hUnloadEvent);
|
||||||
|
unload:
|
||||||
FreeLibraryAndExitThread(PIMAGEBASE, 0);
|
FreeLibraryAndExitThread(PIMAGEBASE, 0);
|
||||||
}
|
}
|
@@ -1,4 +1,25 @@
|
|||||||
#pragma once
|
#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);
|
VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer);
|
||||||
DWORD WINAPI StartAddress(LPVOID pParam);
|
DWORD WINAPI StartAddress(LPVOID pParam);
|
||||||
|
@@ -7,7 +7,9 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
|
|||||||
break;
|
break;
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
break;
|
break;
|
||||||
default:
|
case DLL_THREAD_ATTACH:
|
||||||
|
break;
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
LIBRARY
|
LIBRARY
|
||||||
EXPORTS
|
EXPORTS
|
||||||
RUNDLL32_StartW @3
|
RUNDLL32_StartW @1
|
||||||
RUNDLL32_UnloadW @4
|
RUNDLL32_UnloadW @2
|
||||||
RUNDLL32_DeleteFileW @5
|
RUNDLL32_DeleteFileW @3
|
||||||
|
538
wufuc/helpers.c
538
wufuc/helpers.c
@@ -3,59 +3,47 @@
|
|||||||
#include "hooks.h"
|
#include "hooks.h"
|
||||||
#include <sddl.h>
|
#include <sddl.h>
|
||||||
|
|
||||||
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);
|
hMutex = CreateMutexW(NULL, InitialOwner, pMutexName);
|
||||||
if ( mutex ) {
|
if ( hMutex ) {
|
||||||
if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
|
if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
|
||||||
CloseHandle(mutex);
|
CloseHandle(hMutex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*pmutex = mutex;
|
*phMutex = hMutex;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
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 };
|
SECURITY_ATTRIBUTES sa = { sizeof sa };
|
||||||
HANDLE event;
|
HANDLE event;
|
||||||
|
|
||||||
if ( ConvertStringSecurityDescriptorToSecurityDescriptorW(descriptor, SDDL_REVISION_1, &sa.lpSecurityDescriptor, NULL) ) {
|
if ( ConvertStringSecurityDescriptorToSecurityDescriptorW(
|
||||||
event = CreateEventW(&sa, manualreset, initialstate, name);
|
pStringSecurityDescriptor,
|
||||||
|
SDDL_REVISION_1,
|
||||||
|
&sa.lpSecurityDescriptor,
|
||||||
|
NULL) ) {
|
||||||
|
|
||||||
|
event = CreateEventW(&sa, ManualReset, InitialState, pName);
|
||||||
if ( event ) {
|
if ( event ) {
|
||||||
*pevent = event;
|
*phEvent = event;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
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)
|
int FileInfoVerCompare(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;
|
||||||
@@ -69,140 +57,267 @@ int FileInfoVerCompare(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wB
|
|||||||
return 0;
|
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;
|
bool result = false;
|
||||||
DWORD dwLen;
|
UINT cbData;
|
||||||
LPVOID pBlock;
|
HRSRC hResInfo;
|
||||||
PLANGANDCODEPAGE ptl;
|
DWORD dwSize;
|
||||||
UINT cb;
|
HGLOBAL hResData;
|
||||||
wchar_t SubBlock[38];
|
LPVOID pRes;
|
||||||
wchar_t *pInternalName;
|
LPVOID pCopy;
|
||||||
|
LPVOID pBuffer;
|
||||||
UINT uLen;
|
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 ( !pcbData ) return result;
|
||||||
if ( !dwLen ) return result;
|
cbData = *pcbData;
|
||||||
|
|
||||||
pBlock = malloc(dwLen);
|
hResInfo = FindResourceW(hModule,
|
||||||
if ( !pBlock ) return result;
|
MAKEINTRESOURCEW(VS_VERSION_INFO),
|
||||||
|
RT_VERSION);
|
||||||
|
if ( !hResInfo ) return result;
|
||||||
|
|
||||||
if ( !GetFileVersionInfoW(pFilename, 0, dwLen, pBlock)
|
dwSize = SizeofResource(hModule, hResInfo);
|
||||||
|| !VerQueryValueW(pBlock, L"\\VarFileInfo\\Translation", (LPVOID *)&ptl, &cb) )
|
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;
|
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 )
|
if ( !pData ) {
|
||||||
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;
|
result = true;
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
break;
|
if ( cbData < *pcbData
|
||||||
}
|
|| memcpy_s(pData, cbData, pBuffer, *pcbData) )
|
||||||
}
|
goto cleanup;
|
||||||
|
|
||||||
|
result = true;
|
||||||
cleanup:
|
cleanup:
|
||||||
free(pBlock);
|
free(pCopy);
|
||||||
return result;
|
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 };
|
MODULEENTRY32W me = { sizeof me };
|
||||||
if ( !Module32FirstW(hSnapshot, &me) )
|
if ( !Module32FirstW(hSnapshot, &me) )
|
||||||
return false;
|
return NULL;
|
||||||
do {
|
do {
|
||||||
if ( !_wcsicmp(me.szExePath, pLibFileName) ) {
|
if ( !_wcsicmp(me.szExePath, pLibFileName) )
|
||||||
*phRemoteModule = me.hModule;
|
return me.hModule;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} while ( Module32NextW(hSnapshot, &me) );
|
} 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;
|
bool result = false;
|
||||||
HANDLE hProcess;
|
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
HMODULE hRemoteModule;
|
LPVOID pBaseAddress = NULL;
|
||||||
LPTHREAD_START_ROUTINE pfnTargetStartAddress;
|
SIZE_T cb;
|
||||||
HANDLE TargetHandle = NULL;
|
HMODULE hRemoteModule = NULL;
|
||||||
HANDLE hThread;
|
HANDLE hThread;
|
||||||
|
|
||||||
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
|
|
||||||
if ( !hProcess ) return result;
|
|
||||||
|
|
||||||
Status = NtSuspendProcess(hProcess);
|
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)
|
if ( !WriteProcessMemory(hProcess, pBaseAddress, pParam, cbParam, &cb) )
|
||||||
&& (!SourceHandle || DuplicateHandle(GetCurrentProcess(), SourceHandle, hProcess, &TargetHandle, dwDesiredAccess, FALSE, 0)) ) {
|
goto vfree;
|
||||||
|
}
|
||||||
|
if ( InjectLibrary(hProcess, hModule, &hRemoteModule) ) {
|
||||||
|
trace(L"Injected library. hRemoteModule=%p", hRemoteModule);
|
||||||
|
|
||||||
// get pointer to StartAddress in remote process
|
hThread = CreateRemoteThread(hProcess,
|
||||||
pfnTargetStartAddress = (LPTHREAD_START_ROUTINE)((uint8_t *)hRemoteModule + ((uint8_t *)pStartAddress - (uint8_t *)PIMAGEBASE));
|
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 ) {
|
if ( hThread ) {
|
||||||
|
trace(L"Created remote thread. hThread=%p", hThread);
|
||||||
CloseHandle(hThread);
|
CloseHandle(hThread);
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NtResumeProcess(hProcess);
|
vfree:
|
||||||
cleanup:
|
if ( !result && pBaseAddress )
|
||||||
CloseHandle(hProcess);
|
VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE);
|
||||||
|
resume: NtResumeProcess(hProcess);
|
||||||
return result;
|
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;
|
bool result = false;
|
||||||
DWORD dwProcessId;
|
DWORD dwProcessId;
|
||||||
@@ -214,59 +329,69 @@ bool InjectLibraryByFileName(HANDLE hProcess, const wchar_t *pLibFileName, size_
|
|||||||
|
|
||||||
Status = NtSuspendProcess(hProcess);
|
Status = NtSuspendProcess(hProcess);
|
||||||
if ( !NT_SUCCESS(Status) ) return result;
|
if ( !NT_SUCCESS(Status) ) return result;
|
||||||
|
trace(L"Suspended process. hProcess=%p", hProcess);
|
||||||
|
|
||||||
dwProcessId = GetProcessId(hProcess);
|
dwProcessId = GetProcessId(hProcess);
|
||||||
|
|
||||||
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
|
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);
|
CloseHandle(hSnapshot);
|
||||||
|
|
||||||
// already injected... returns false but sets *phRemoteModule
|
// already injected... still sets *phRemoteModule
|
||||||
if ( result ) goto L1;
|
if ( *phRemoteModule ) goto resume;
|
||||||
|
|
||||||
nSize = (cchLibFileName + 1) * sizeof *pLibFileName;
|
nSize = (cchLibFilename + 1) * sizeof *pLibFilename;
|
||||||
pBaseAddress = VirtualAllocEx(hProcess, NULL, nSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
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) )
|
if ( !WriteProcessMemory(hProcess, pBaseAddress, pLibFilename, nSize, NULL) )
|
||||||
goto L2;
|
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);
|
hThread = CreateRemoteThread(hProcess,
|
||||||
if ( !hThread ) goto L2;
|
NULL,
|
||||||
|
0,
|
||||||
|
(LPTHREAD_START_ROUTINE)LoadLibraryW,
|
||||||
|
pBaseAddress,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
if ( !hThread ) goto vfree;
|
||||||
|
trace(L"Created remote thread. hThread=%p", hThread);
|
||||||
|
|
||||||
WaitForSingleObject(hThread, INFINITE);
|
WaitForSingleObject(hThread, INFINITE);
|
||||||
|
trace(L"Created thread finished running. hThread=%p", hThread);
|
||||||
|
|
||||||
if ( sizeof *phRemoteModule > sizeof(DWORD) ) {
|
if ( sizeof *phRemoteModule > sizeof(DWORD) ) {
|
||||||
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
|
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
|
||||||
if ( hSnapshot ) {
|
if ( hSnapshot ) {
|
||||||
result = GetRemoteHModuleFromTh32ModuleSnapshot(hSnapshot, pLibFileName, phRemoteModule);
|
*phRemoteModule = GetRemoteHModuleFromTh32ModuleSnapshot(
|
||||||
|
hSnapshot,
|
||||||
|
pLibFilename);
|
||||||
|
|
||||||
CloseHandle(hSnapshot);
|
CloseHandle(hSnapshot);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = !!GetExitCodeThread(hThread, (LPDWORD)phRemoteModule);
|
result = !!GetExitCodeThread(hThread, (LPDWORD)phRemoteModule);
|
||||||
}
|
}
|
||||||
CloseHandle(hThread);
|
CloseHandle(hThread);
|
||||||
L2: VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE);
|
vfree: VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE);
|
||||||
L1: NtResumeProcess(hProcess);
|
resume: NtResumeProcess(hProcess);
|
||||||
return result;
|
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)
|
bool IsWindowsVersion(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
|
||||||
{
|
{
|
||||||
OSVERSIONINFOEXW osvi = { sizeof osvi };
|
OSVERSIONINFOEXW osvi = { sizeof osvi };
|
||||||
@@ -280,33 +405,18 @@ bool IsWindowsVersion(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackM
|
|||||||
osvi.dwMinorVersion = wMinorVersion;
|
osvi.dwMinorVersion = wMinorVersion;
|
||||||
osvi.wServicePackMajor = wServicePackMajor;
|
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)
|
PVOID RegGetValueAlloc(
|
||||||
{
|
HKEY hkey,
|
||||||
NTSTATUS Status;
|
const wchar_t *pSubKey,
|
||||||
ULONG ResultLength;
|
const wchar_t *pValue,
|
||||||
PVOID result = NULL;
|
DWORD dwFlags,
|
||||||
|
LPDWORD pdwType,
|
||||||
Status = NtQueryKey(KeyHandle, KeyInformationClass, NULL, 0, &ResultLength);
|
LPDWORD pcbData)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
DWORD cbData = 0;
|
DWORD cbData = 0;
|
||||||
PVOID result = NULL;
|
PVOID result = NULL;
|
||||||
@@ -326,7 +436,10 @@ PVOID RegGetValueAlloc(HKEY hkey, const wchar_t *pSubKey, const wchar_t *pValue,
|
|||||||
return result;
|
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;
|
SC_HANDLE hService;
|
||||||
DWORD cbBytesNeeded;
|
DWORD cbBytesNeeded;
|
||||||
@@ -352,37 +465,27 @@ LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(SC_HANDLE hSCM, const wcha
|
|||||||
return result;
|
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;
|
bool result = false;
|
||||||
SC_HANDLE hService;
|
SC_HANDLE hService;
|
||||||
DWORD cbBytesNeeded;
|
DWORD cbBytesNeeded;
|
||||||
|
|
||||||
hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_STATUS);
|
hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_STATUS);
|
||||||
if ( !hService ) return result;
|
if ( !hService ) {
|
||||||
|
trace(L"Failed to open service %ls! (GetLastError=%ul)", pServiceName, GetLastError());
|
||||||
result = !!QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)pServiceStatus, sizeof *pServiceStatus, &cbBytesNeeded);
|
|
||||||
CloseServiceHandle(hService);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QueryServiceGroupName(const LPQUERY_SERVICE_CONFIGW pServiceConfig, wchar_t *pGroupName, size_t nSize)
|
result = !!QueryServiceStatusEx(hService,
|
||||||
{
|
SC_STATUS_PROCESS_INFO,
|
||||||
bool result = false;
|
(LPBYTE)pServiceStatus,
|
||||||
int NumArgs;
|
sizeof *pServiceStatus,
|
||||||
LPWSTR *argv;
|
&cbBytesNeeded);
|
||||||
|
CloseServiceHandle(hService);
|
||||||
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);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,36 +497,3 @@ DWORD QueryServiceProcessId(SC_HANDLE hSCM, const wchar_t *pServiceName)
|
|||||||
return ServiceStatusProcess.dwProcessId;
|
return ServiceStatusProcess.dwProcessId;
|
||||||
return 0;
|
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;
|
|
||||||
}
|
|
@@ -1,25 +1,49 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
bool CreateExclusiveMutex(const wchar_t *name, HANDLE *pmutex);
|
typedef struct
|
||||||
bool CreateEventWithStringSecurityDescriptor(const wchar_t *descriptor, bool manualreset, bool initialstate, const wchar_t *name, HANDLE *pevent);
|
{
|
||||||
|
WORD wLanguage;
|
||||||
|
WORD wCodePage;
|
||||||
|
} LANGANDCODEPAGE, *PLANGANDCODEPAGE;
|
||||||
|
|
||||||
bool FileExists(const wchar_t *path);
|
bool InitializeMutex(bool InitialOwner, const wchar_t *pMutexName, HANDLE *phMutex);
|
||||||
bool FileExistsExpandEnvironmentStrings(const wchar_t *path);
|
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);
|
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 GetVersionInfoFromHModule(HMODULE hModule, LPCWSTR pszSubBlock, LPVOID pData, PUINT pcbData);
|
||||||
|
LPVOID GetVersionInfoFromHModuleAlloc(HMODULE hModule, LPCWSTR pszSubBlock, PUINT pcbData);
|
||||||
bool FindIsDeviceServiceablePtr(const wchar_t *pFilename, HMODULE hModule, PVOID *ppfnIsDeviceServiceable);
|
bool FindIsDeviceServiceablePtr(HMODULE hModule, PVOID *ppfnIsDeviceServiceable);
|
||||||
bool GetRemoteHModuleFromTh32ModuleSnapshot(HANDLE hSnapshot, const wchar_t *pLibFileName, HMODULE *phRemoteModule);
|
HANDLE GetRemoteHModuleFromTh32ModuleSnapshot(HANDLE hSnapshot, const wchar_t *pLibFileName);
|
||||||
bool InjectSelfAndCreateRemoteThread(DWORD dwProcessId, LPTHREAD_START_ROUTINE pStartAddress, HANDLE SourceHandle, DWORD dwDesiredAccess);
|
bool InjectLibraryAndCreateRemoteThread(
|
||||||
bool InjectLibraryByFileName(HANDLE hProcess, const wchar_t *pLibFileName, size_t nLength, HMODULE *phRemoteModule);
|
HANDLE hProcess,
|
||||||
bool InjectLibraryByLocalHModule(HANDLE hProcess, HMODULE hModule, HMODULE *phRemoteModule);
|
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);
|
bool IsWindowsVersion(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor);
|
||||||
|
PVOID RegGetValueAlloc(
|
||||||
PVOID NtQueryKeyAlloc(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PULONG pResultLength);
|
HKEY hkey,
|
||||||
PVOID RegGetValueAlloc(HKEY hkey, const wchar_t *pSubKey, const wchar_t *pValue, DWORD dwFlags, LPDWORD pdwType, LPDWORD pcbData);
|
const wchar_t *pSubKey,
|
||||||
LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(SC_HANDLE hSCM, const wchar_t *pServiceName, LPDWORD pcbBufSize);
|
const wchar_t *pValue,
|
||||||
bool QueryServiceStatusProcessInfoByName(SC_HANDLE hSCM, const wchar_t *pServiceName, LPSERVICE_STATUS_PROCESS pServiceStatus);
|
DWORD dwFlags,
|
||||||
|
LPDWORD pdwType,
|
||||||
bool QueryServiceGroupName(const LPQUERY_SERVICE_CONFIGW pServiceConfig, wchar_t *pGroupName, size_t nSize);
|
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 QueryServiceProcessId(SC_HANDLE hSCM, const wchar_t *pServiceName);
|
||||||
DWORD InferSvchostGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupName);
|
|
||||||
|
@@ -2,71 +2,10 @@
|
|||||||
#include "hooks.h"
|
#include "hooks.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
LPFN_REGQUERYVALUEEXW g_pfnRegQueryValueExW;
|
LPWSTR g_pszWUServiceDll;
|
||||||
LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW;
|
|
||||||
LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceable;
|
LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceable;
|
||||||
|
LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags)
|
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);
|
result = g_pfnLoadLibraryExW(lpFileName, hFile, dwFlags);
|
||||||
if ( !result ) return result;
|
if ( !result ) return result;
|
||||||
|
trace(L"Loaded library. lpFileName=%ls result=%p", lpFileName, result);
|
||||||
|
|
||||||
trace(L"Loaded library: %ls", lpFileName);
|
if ( g_pszWUServiceDll
|
||||||
if ( FindIsDeviceServiceablePtr(lpFileName, result, (PVOID *)&g_pfnIsDeviceServiceable) ) {
|
&& !_wcsicmp(lpFileName, g_pszWUServiceDll)
|
||||||
DetourTransactionBegin();
|
&& FindIsDeviceServiceablePtr(result, &(PVOID)g_pfnIsDeviceServiceable) ) {
|
||||||
DetourUpdateThread(GetCurrentThread());
|
|
||||||
DetourAttach((PVOID *)&g_pfnIsDeviceServiceable, IsDeviceServiceable_hook);
|
trace(L"DetourTransactionBegin=%lu", DetourTransactionBegin());
|
||||||
DetourTransactionCommit();
|
trace(L"DetourUpdateThread=%lu", DetourUpdateThread(GetCurrentThread()));
|
||||||
|
trace(L"DetourAttach=%lu", DetourAttach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook));
|
||||||
|
trace(L"DetourTransactionCommit=%lu", DetourTransactionCommit());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@@ -1,19 +1,13 @@
|
|||||||
#pragma once
|
#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 HMODULE(WINAPI *LPFN_LOADLIBRARYEXW)(LPCWSTR, HANDLE, DWORD);
|
||||||
typedef BOOL(WINAPI *LPFN_ISDEVICESERVICEABLE)(void);
|
typedef BOOL(WINAPI *LPFN_ISDEVICESERVICEABLE)(void);
|
||||||
|
|
||||||
extern LPFN_REGQUERYVALUEEXW g_pfnRegQueryValueExW;
|
extern LPWSTR g_pszWUServiceDll;
|
||||||
|
|
||||||
extern LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW;
|
extern LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW;
|
||||||
extern LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceable;
|
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);
|
HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags);
|
||||||
BOOL WINAPI IsDeviceServiceable_hook(void);
|
BOOL WINAPI IsDeviceServiceable_hook(void);
|
||||||
|
@@ -2,66 +2,57 @@
|
|||||||
#include "callbacks.h"
|
#include "callbacks.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
|
void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
|
||||||
{
|
{
|
||||||
HANDLE hMutex;
|
ContextHandles ctx;
|
||||||
HANDLE hEvent;
|
|
||||||
DWORD cbBufSize;
|
|
||||||
LPQUERY_SERVICE_CONFIGW pServiceConfig;
|
|
||||||
wchar_t GroupName[256];
|
|
||||||
DWORD dwProcessId;
|
|
||||||
bool Unloading = false;
|
bool Unloading = false;
|
||||||
bool Lagging;
|
bool Lagging;
|
||||||
SC_HANDLE hSCM;
|
SC_HANDLE hSCM;
|
||||||
SC_HANDLE hService;
|
SC_HANDLE hService;
|
||||||
SERVICE_NOTIFYW NotifyBuffer;
|
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;
|
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) )
|
trace(L"Failed to create unload event. (GetLastError=%ul)", GetLastError());
|
||||||
goto L1;
|
goto close_mutex;
|
||||||
|
}
|
||||||
//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);
|
|
||||||
//}
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
Lagging = false;
|
Lagging = false;
|
||||||
hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
|
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);
|
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);
|
ZeroMemory(&NotifyBuffer, sizeof NotifyBuffer);
|
||||||
NotifyBuffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
|
NotifyBuffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
|
||||||
NotifyBuffer.pfnNotifyCallback = ServiceNotifyCallback;
|
NotifyBuffer.pfnNotifyCallback = ServiceNotifyCallback;
|
||||||
NotifyBuffer.pContext = (PVOID)hEvent;
|
NotifyBuffer.pContext = (PVOID)&ctx;
|
||||||
while ( !Unloading && !Lagging ) {
|
while ( !Unloading && !Lagging ) {
|
||||||
switch ( NotifyServiceStatusChangeW(hService,
|
switch ( NotifyServiceStatusChangeW(hService,
|
||||||
SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_RUNNING,
|
SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_RUNNING,
|
||||||
&NotifyBuffer) ) {
|
&NotifyBuffer) ) {
|
||||||
case ERROR_SUCCESS:
|
case ERROR_SUCCESS:
|
||||||
Unloading = WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == WAIT_OBJECT_0;
|
Unloading = WaitForSingleObjectEx(ctx.hUnloadEvent, INFINITE, TRUE) == WAIT_OBJECT_0;
|
||||||
break;
|
break;
|
||||||
case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING:
|
case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING:
|
||||||
trace(L"Client lagging!");
|
trace(L"Client lagging!");
|
||||||
@@ -73,11 +64,13 @@ void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
CloseServiceHandle(hService);
|
CloseServiceHandle(hService);
|
||||||
L3: CloseServiceHandle(hSCM);
|
close_scm: CloseServiceHandle(hSCM);
|
||||||
} while ( Lagging );
|
} while ( Lagging );
|
||||||
L2: CloseHandle(hEvent);
|
close_event:
|
||||||
L1: ReleaseMutex(hMutex);
|
CloseHandle(ctx.hUnloadEvent);
|
||||||
CloseHandle(hMutex);
|
close_mutex:
|
||||||
|
ReleaseMutex(ctx.hMainMutex);
|
||||||
|
CloseHandle(ctx.hMainMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CALLBACK RUNDLL32_UnloadW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
|
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;
|
int argc;
|
||||||
LPWSTR *argv;
|
LPWSTR *argv;
|
||||||
|
@@ -4,16 +4,21 @@
|
|||||||
|
|
||||||
#include <phnt_windows.h>
|
#include <phnt_windows.h>
|
||||||
#include <phnt.h>
|
#include <phnt.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#include <strsafe.h>
|
#include <strsafe.h>
|
||||||
#include <Psapi.h>
|
|
||||||
#include <TlHelp32.h>
|
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
#include <Shlwapi.h>
|
#include <Shlwapi.h>
|
||||||
|
|
||||||
|
#include <Psapi.h>
|
||||||
|
#include <TlHelp32.h>
|
||||||
|
|
||||||
#include <detours.h>
|
#include <detours.h>
|
||||||
|
|
||||||
#include "patternfind.h"
|
#include "patternfind.h"
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "tracing.h"
|
#include "tracing.h"
|
||||||
|
|
||||||
static FILE *steam;
|
|
||||||
|
|
||||||
void trace_(const wchar_t *const format, ...)
|
void trace_(const wchar_t *const format, ...)
|
||||||
{
|
{
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
|
@@ -155,7 +155,7 @@
|
|||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
||||||
<EntryPointSymbol>
|
<EntryPointSymbol>
|
||||||
</EntryPointSymbol>
|
</EntryPointSymbol>
|
||||||
<AdditionalDependencies>ntdll.lib;version.lib;Shlwapi.lib;detours.X86.MTd.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>version.lib;Shlwapi.lib;detours.X86.MTd.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
<ResourceCompile>
|
<ResourceCompile>
|
||||||
<PreprocessorDefinitions>X86;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>X86;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
@@ -177,7 +177,7 @@
|
|||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
||||||
<EntryPointSymbol>
|
<EntryPointSymbol>
|
||||||
</EntryPointSymbol>
|
</EntryPointSymbol>
|
||||||
<AdditionalDependencies>ntdll.lib;version.lib;Shlwapi.lib;detours.X64.MTd.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>version.lib;Shlwapi.lib;detours.X64.MTd.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
<ResourceCompile>
|
<ResourceCompile>
|
||||||
<PreprocessorDefinitions>X64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>X64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
@@ -207,7 +207,7 @@
|
|||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
||||||
<EntryPointSymbol>
|
<EntryPointSymbol>
|
||||||
</EntryPointSymbol>
|
</EntryPointSymbol>
|
||||||
<AdditionalDependencies>ntdll.lib;version.lib;Shlwapi.lib;detours.X86.MT.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>version.lib;Shlwapi.lib;detours.X86.MT.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
|
||||||
<SetChecksum>true</SetChecksum>
|
<SetChecksum>true</SetChecksum>
|
||||||
</Link>
|
</Link>
|
||||||
<ResourceCompile>
|
<ResourceCompile>
|
||||||
@@ -236,7 +236,7 @@
|
|||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
||||||
<AdditionalDependencies>ntdll.lib;version.lib;Shlwapi.lib;detours.X64.MT.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>version.lib;Shlwapi.lib;detours.X64.MT.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
|
||||||
<SetChecksum>true</SetChecksum>
|
<SetChecksum>true</SetChecksum>
|
||||||
</Link>
|
</Link>
|
||||||
<ResourceCompile>
|
<ResourceCompile>
|
||||||
|
BIN
wufuc_setup_bat/Restore_wuauserv.reg
Normal file
BIN
wufuc_setup_bat/Restore_wuauserv.reg
Normal file
Binary file not shown.
@@ -14,7 +14,8 @@
|
|||||||
:: You should have received a copy of the GNU General Public License
|
:: You should have received a copy of the GNU General Public License
|
||||||
:: along with this program. If not, see <http://www.gnu.org/licenses/>.
|
:: along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
set /p wufuc_version=<"%~dp0version.txt"
|
||||||
|
title wufuc v%wufuc_version% Setup
|
||||||
echo Copyright ^(C^) 2017 zeffy
|
echo Copyright ^(C^) 2017 zeffy
|
||||||
echo This program comes with ABSOLUTELY NO WARRANTY.
|
echo This program comes with ABSOLUTELY NO WARRANTY.
|
||||||
echo This is free software, and you are welcome to redistribute it
|
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
|
goto :die
|
||||||
|
|
||||||
:xml_exists
|
: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"
|
set "wufuc_xml=%~dp0wufuc_ScheduledTask.xml"
|
||||||
if exist "%wufuc_xml%" goto :check_winver
|
if exist "%wufuc_xml%" goto :check_winver
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ echo ERROR - Could not find %wufuc_xml%!
|
|||||||
echo.
|
echo.
|
||||||
echo This most likely means you didn't extract all the files from the archive.
|
echo This most likely means you didn't extract all the files from the archive.
|
||||||
echo.
|
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.
|
echo location like C:\Program Files\wufuc and try again.
|
||||||
goto :die
|
goto :die
|
||||||
|
|
||||||
@@ -112,6 +112,7 @@ goto :die
|
|||||||
|
|
||||||
:check_mode
|
:check_mode
|
||||||
set "wufuc_task=wufuc.{72EEE38B-9997-42BD-85D3-2DD96DA17307}"
|
set "wufuc_task=wufuc.{72EEE38B-9997-42BD-85D3-2DD96DA17307}"
|
||||||
|
set "space= "
|
||||||
|
|
||||||
if "%UNINSTALL%"=="1" goto :confirm_uninstall
|
if "%UNINSTALL%"=="1" goto :confirm_uninstall
|
||||||
|
|
||||||
@@ -125,7 +126,7 @@ echo systems with Intel Kaby Lake, AMD Ryzen, or other unsupported processors.
|
|||||||
echo.
|
echo.
|
||||||
echo Please be absolutely sure you really need wufuc before proceeding.
|
echo Please be absolutely sure you really need wufuc before proceeding.
|
||||||
echo.
|
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
|
if /I "%CONTINUE_INSTALL%"=="Y" goto :install
|
||||||
goto :cancel
|
goto :cancel
|
||||||
|
|
||||||
@@ -135,7 +136,6 @@ net start Schedule
|
|||||||
schtasks /Create /XML "%wufuc_xml%" /TN "%wufuc_task%" /F
|
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%" /TR "'%systemroot%\System32\rundll32.exe' """%wufuc_dll_fullpath%""",RUNDLL32_Start"
|
||||||
schtasks /Change /TN "%wufuc_task%" /ENABLE
|
schtasks /Change /TN "%wufuc_task%" /ENABLE
|
||||||
rundll32 "%wufuc_dll_fullpath%",RUNDLL32_Unload
|
|
||||||
net stop wuauserv
|
net stop wuauserv
|
||||||
schtasks /Run /TN "%wufuc_task%"
|
schtasks /Run /TN "%wufuc_task%"
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ goto :confirm_restart
|
|||||||
:confirm_uninstall
|
:confirm_uninstall
|
||||||
if "%UNATTENDED%"=="1" goto :uninstall_stub
|
if "%UNATTENDED%"=="1" goto :uninstall_stub
|
||||||
echo.
|
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
|
if /I "%CONTINUE_UNINSTALL%"=="Y" goto :uninstall_stub
|
||||||
goto :cancel
|
goto :cancel
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ goto :confirm_restart
|
|||||||
if "%NORESTART%"=="1" goto :die
|
if "%NORESTART%"=="1" goto :die
|
||||||
if "%UNATTENDED%"=="1" goto :restart
|
if "%UNATTENDED%"=="1" goto :restart
|
||||||
echo.
|
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
|
if /I "%CONTINUE_RESTART%"=="Y" goto :restart
|
||||||
goto :die
|
goto :die
|
||||||
:restart
|
:restart
|
||||||
|
Reference in New Issue
Block a user