diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f7c3058..9e4c47b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing guidelines -**English** | [Community translations](https://github.com/zeffy/wufuc/wiki) +This document is also available in [简体中文], [繁体中文], [русский], [Español] and [more...](https://github.com/zeffy/wufuc/wiki) ## Reporting an issue [![](https://isitmaintained.com/badge/resolution/zeffy/wufuc.svg)](https://isitmaintained.com/project/zeffy/wufuc) @@ -20,3 +20,8 @@ - Issues that don't have the information requested above (when applicable) will be closed immediately and the poster directed to the contributing guidelines. - Issues that go a week without a response from original poster are subject to closure at my discretion. + +[简体中文]: https://github.com/zeffy/wufuc/wiki/CONTRIBUTING-(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87) +[繁体中文]: https://github.com/zeffy/wufuc/wiki/CONTRIBUTING-(%E7%B9%81%E9%AB%94%E4%B8%AD%E6%96%87) +[русский]: https://github.com/zeffy/wufuc/wiki/CONTRIBUTING-(%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9) +[Español]: https://github.com/zeffy/wufuc/wiki/CONTRIBUTING-(Espa%C3%B1ol) diff --git a/README.md b/README.md index e67b194..b17b120 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ # wufuc -[![Donate Bitcoin](https://cdn.rawgit.com/zeffy/wufuc/badges/bitcoin.svg)](https://admin.gear.mycelium.com/gateways/3554/orders/new) [![AppVeyor Builds](https://img.shields.io/appveyor/ci/zeffy/wufuc.svg?logo=appveyor&style=flat-square)](https://ci.appveyor.com/project/zeffy/wufuc) [![Chat on Telegram](https://cdn.rawgit.com/zeffy/wufuc/badges/telegram.svg)](https://t.me/joinchat/HEo6LUvV_83O92WzbYXLeQ) [![All Releases](https://img.shields.io/github/downloads/zeffy/wufuc/total.svg?style=flat-square)](https://github.com/zeffy/wufuc/releases/latest) +[![Donate Bitcoin](https://cdn.rawgit.com/zeffy/wufuc/badges/bitcoin.svg)](https://admin.gear.mycelium.com/gateways/3554/orders/new) [![AppVeyor Builds](https://img.shields.io/appveyor/ci/zeffy/wufuc.svg?logo=appveyor&style=flat-square)][AppVeyor] [![Chat on Telegram](https://cdn.rawgit.com/zeffy/wufuc/badges/telegram.svg)](https://t.me/joinchat/HEo6LUvV_83O92WzbYXLeQ) [![All Releases](https://img.shields.io/github/downloads/zeffy/wufuc/total.svg?style=flat-square)][Latest] -**English** | [Community translations](https://github.com/zeffy/wufuc/wiki) +This document is also available in [简体中文], [繁体中文], [русский], [Español] and [more...](https://github.com/zeffy/wufuc/wiki) Disables the "Unsupported Hardware" message in Windows Update, and allows you to continue installing updates on Windows 7 and 8.1 systems with Intel Kaby Lake, AMD Ryzen, or other unsupported processors. ## Downloads -**[Latest stable build](https://github.com/zeffy/wufuc/releases/latest) - Most people will want this version.** +**[Latest stable build][Latest] - Most people will want this version.** -[Unstable builds](https://ci.appveyor.com/project/zeffy/wufuc) - Probably contains bugs; do not report issues with these builds. +[Unstable builds][AppVeyor] - Probably contains bugs; do not report issues with these builds. ## Donate @@ -96,12 +96,19 @@ There was a fundamental issue with the method I tried using in this version that ## Sponsors -### [Advanced Installer](http://www.advancedinstaller.com/) +### [Advanced Installer](https://www.advancedinstaller.com/) The installer packages are created with Advanced Installer using an [open source license](http://www.advancedinstaller.com/free-license.html). -Advanced Installer's intuitive and friendly user interface allowed me to quickly create a feature complete installer with minimal effort. [Check it out!](http://www.advancedinstaller.com/) +Advanced Installer's intuitive and friendly user interface allowed me to quickly create a feature complete installer with minimal effort. Check it out! ## Special thanks - Wen Jia Liu ([@wj32](https://github.com/wj32)) for his awesome program [Process Hacker](https://github.com/processhacker2/processhacker) which has been absolutely instrumental in the development of wufuc, and also for his [`phnt`](https://github.com/processhacker2/processhacker/tree/master/phnt) headers. - Duncan Ogilvie ([@mrexodia](https://github.com/mrexodia)) for his [`patternfind.cpp`](https://github.com/x64dbg/x64dbg/blob/development/src/dbg/patternfind.cpp) algorithm from [x64dbg](https://github.com/x64dbg/x64dbg). + +[Latest]: https://github.com/zeffy/wufuc/releases/latest +[AppVeyor]: https://ci.appveyor.com/project/zeffy/wufuc +[简体中文]: https://github.com/zeffy/wufuc/wiki/README-(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87) +[繁体中文]: https://github.com/zeffy/wufuc/wiki/README-(%E7%B9%81%E9%AB%94%E4%B8%AD%E6%96%87) +[русский]: https://github.com/zeffy/wufuc/wiki/README-(%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9) +[Español]: https://github.com/zeffy/wufuc/wiki/README-(Espa%C3%B1ol) \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 95d05e7..3451df3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.0.0.{build} +version: 0.9.999.{build} branches: only: - master diff --git a/wufuc/callbacks.c b/wufuc/callbacks.c index 9d29ae0..663e3da 100644 --- a/wufuc/callbacks.c +++ b/wufuc/callbacks.c @@ -1,17 +1,14 @@ #include "stdafx.h" #include "callbacks.h" +#include "hooks.h" #include "helpers.h" -#include VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer) { - HMODULE hModule; - switch ( pNotifyBuffer->dwNotificationStatus ) { case ERROR_SUCCESS: - if ( inject_self_into_process(pNotifyBuffer->ServiceStatus.dwProcessId, &hModule) ) { - - } + if ( pNotifyBuffer->ServiceStatus.dwProcessId ) + InjectSelfAndCreateRemoteThread(pNotifyBuffer->ServiceStatus.dwProcessId, &StartAddress, (HANDLE)pNotifyBuffer->pContext, SYNCHRONIZE); break; case ERROR_SERVICE_MARKED_FOR_DELETE: SetEvent((HANDLE)pNotifyBuffer->pContext); @@ -20,3 +17,68 @@ VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer) if ( pNotifyBuffer->pszServiceNames ) LocalFree((HLOCAL)pNotifyBuffer->pszServiceNames); } + +DWORD WINAPI StartAddress(LPVOID pParam) +{ + SC_HANDLE hSCM; + DWORD cbBufSize; + LPQUERY_SERVICE_CONFIGW pServiceConfig; + DWORD dwServiceType; + int result; + DWORD cbData; + LPWSTR pServiceDll; + HMODULE hModule; + + hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); + if ( !hSCM ) goto cleanup; + + pServiceConfig = QueryServiceConfigByNameAlloc(hSCM, L"wuauserv", &cbBufSize); + CloseServiceHandle(hSCM); + if ( !pServiceConfig ) goto cleanup; + + //dwServiceType = pServiceConfig->dwServiceType; + result = _wcsicmp(pServiceConfig->lpBinaryPathName, GetCommandLineW()); + free(pServiceConfig); + if ( result ) goto cleanup; + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + // hook apis if configured as shared service + /* if ( dwServiceType == SERVICE_WIN32_SHARE_PROCESS ) { + g_pfnLoadLibraryExW = DetourFindFunction("kernel32.dll", "LoadLibraryExW"); + DetourAttach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook); + + g_pfnRegQueryValueExW = DetourFindFunction("kernel32.dll", "RegQueryValueExW"); + DetourAttach(&(PVOID)g_pfnRegQueryValueExW, RegQueryValueExW_hook); + }*/ + + // hook IsDeviceServiceable if wuaueng.dll is already loaded + pServiceDll = RegGetValueAlloc(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\services\\wuauserv\\Parameters", L"ServiceDll", RRF_RT_REG_SZ, NULL, &cbData); + if ( pServiceDll ) { + hModule = GetModuleHandleW(pServiceDll); + if ( hModule && FindIsDeviceServiceablePtr(pServiceDll, hModule, &(PVOID)g_pfnIsDeviceServiceable) ) + DetourAttach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook); + + free(pServiceDll); + } + DetourTransactionCommit(); + + // wait for unload event + WaitForSingleObject((HANDLE)pParam, INFINITE); + + // unhook functions + trace(L"DetourTransactionBegin result=%d", DetourTransactionBegin()); + trace(L"DetourUpdateThread result=%d", DetourUpdateThread(GetCurrentThread())); + //if ( g_pfnLoadLibraryExW ) + // trace(L"DetourDetach LoadLibraryExW_hook result=%d", DetourDetach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook)); + //if ( g_pfnRegQueryValueExW ) + // trace(L"DetourDetach RegQueryValueExW_hook result=%d", DetourDetach(&(PVOID)g_pfnRegQueryValueExW, RegQueryValueExW_hook)); + if ( g_pfnIsDeviceServiceable ) + trace(L"DetourDetach IsDeviceServiceable_hook result=%d", DetourDetach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook)); + trace(L"DetourTransactionCommit result=%d", DetourTransactionCommit()); + +cleanup: + CloseHandle((HANDLE)pParam); + FreeLibraryAndExitThread(PIMAGEBASE, 0); +} \ No newline at end of file diff --git a/wufuc/callbacks.h b/wufuc/callbacks.h index 39c40f7..244008e 100644 --- a/wufuc/callbacks.h +++ b/wufuc/callbacks.h @@ -1,3 +1,4 @@ #pragma once VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer); +DWORD WINAPI StartAddress(LPVOID pParam); diff --git a/wufuc/dllmain.c b/wufuc/dllmain.c index 06ee1d6..09f5e54 100644 --- a/wufuc/dllmain.c +++ b/wufuc/dllmain.c @@ -4,7 +4,6 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv { switch ( ul_reason_for_call ) { case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hModule); break; case DLL_PROCESS_DETACH: break; diff --git a/wufuc/exports.def b/wufuc/exports.def index 288118e..73ff4cb 100644 --- a/wufuc/exports.def +++ b/wufuc/exports.def @@ -2,4 +2,4 @@ LIBRARY EXPORTS RUNDLL32_StartW @3 RUNDLL32_UnloadW @4 - RUNDLL32_DeleteFileW @5 \ No newline at end of file + RUNDLL32_DeleteFileW @5 diff --git a/wufuc/helpers.c b/wufuc/helpers.c index dc6beb5..5625416 100644 --- a/wufuc/helpers.c +++ b/wufuc/helpers.c @@ -1,8 +1,9 @@ #include "stdafx.h" #include "helpers.h" +#include "hooks.h" #include -bool create_exclusive_mutex(const wchar_t *name, HANDLE *pmutex) +bool CreateExclusiveMutex(const wchar_t *name, HANDLE *pmutex) { HANDLE mutex; @@ -18,7 +19,7 @@ bool create_exclusive_mutex(const wchar_t *name, HANDLE *pmutex) return false; } -bool create_event_with_security_descriptor(const wchar_t *descriptor, bool manualreset, bool initialstate, const wchar_t *name, HANDLE *pevent) +bool CreateEventWithStringSecurityDescriptor(const wchar_t *descriptor, bool manualreset, bool initialstate, const wchar_t *name, HANDLE *pevent) { SECURITY_ATTRIBUTES sa = { sizeof sa }; HANDLE event; @@ -33,109 +34,29 @@ bool create_event_with_security_descriptor(const wchar_t *descriptor, bool manua return false; } -bool inject_self_into_process(DWORD dwProcessId, HMODULE *phModule) -{ - wchar_t szFilename[MAX_PATH]; - DWORD nLength; - - nLength = GetModuleFileNameW(PIMAGEBASE, szFilename, _countof(szFilename)); - - if ( nLength ) - return inject_dll_into_process(dwProcessId, szFilename, nLength, phModule); - - return false; -} - -bool inject_dll_into_process(DWORD dwProcessId, const wchar_t *pszFilename, size_t nLength, HMODULE *phModule) -{ - bool result = false; - HANDLE hProcess; - NTSTATUS Status; - LPVOID pBaseAddress; - HANDLE hThread; - HANDLE hModule = NULL; - - hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); - if ( !hProcess ) return result; - - Status = NtSuspendProcess(hProcess); - if ( !NT_SUCCESS(Status) ) goto L1; - - pBaseAddress = VirtualAllocEx(hProcess, NULL, nLength + (sizeof *pszFilename), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - if ( !pBaseAddress ) goto L2; - - if ( WriteProcessMemory(hProcess, pBaseAddress, pszFilename, nLength, NULL) - && (hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, pBaseAddress, 0, NULL)) ) { - - WaitForSingleObject(hThread, INFINITE); - if ( sizeof(DWORD) < sizeof hModule ) { - - } else { - GetExitCodeThread(hThread, (LPDWORD)&hModule); - } - if ( hModule ) { - result = true; - *phModule = hModule; - } - CloseHandle(hThread); - } - VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE); -L2: NtResumeProcess(hProcess); -L1: CloseHandle(hProcess); - return result; -} - -const wchar_t *path_find_fname(const wchar_t *path) -{ - const wchar_t *pwc = NULL; - if ( path ) - pwc = (const wchar_t *)wcsrchr(path, L'\\'); - - return (pwc && *(++pwc)) ? pwc : path; -} - -bool path_change_fname(const wchar_t *srcpath, const wchar_t *fname, wchar_t *dstpath, size_t size) -{ - bool result; - wchar_t drive[_MAX_DRIVE]; - wchar_t dir[_MAX_DIR]; - - result = !_wsplitpath_s(srcpath, drive, _countof(drive), dir, _countof(dir), NULL, 0, NULL, 0); - if ( result ) - result = !_wmakepath_s(dstpath, size, drive, dir, fname, NULL); - return result; -} - -bool path_file_exists(const wchar_t *path) +bool FileExists(const wchar_t *path) { return GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES; } -bool path_expand_file_exists(const wchar_t *path) +bool FileExistsExpandEnvironmentStrings(const wchar_t *path) { bool result; - wchar_t *dst; + LPWSTR dst; DWORD buffersize; DWORD size; - dst = NULL; - size = 0; - do { - if ( size ) { - if ( dst ) - free(dst); - dst = calloc(size, sizeof *dst); - } - buffersize = size; - size = ExpandEnvironmentStringsW(path, dst, buffersize); - } while ( buffersize < size ); - - result = path_file_exists(dst); + 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 ffi_ver_compare(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; @@ -148,16 +69,361 @@ int ffi_ver_compare(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wBuil return 0; } -size_t find_argv_option(const wchar_t **argv, size_t argc, const wchar_t *option) +bool FindIsDeviceServiceablePtr(const wchar_t *pFilename, HMODULE hModule, PVOID *ppfnIsDeviceServiceable) { - size_t index = -1; + bool result = false; + DWORD dwLen; + LPVOID pBlock; + PLANGANDCODEPAGE ptl; + UINT cb; + wchar_t SubBlock[38]; + wchar_t *pInternalName; + 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; - for ( size_t i = 1; i < argc; i++ ) { - if ( !_wcsicmp(argv[i], option) ) - index = i; + dwLen = GetFileVersionInfoSizeW(pFilename, NULL); + if ( !dwLen ) return result; + + pBlock = malloc(dwLen); + if ( !pBlock ) return result; + + if ( !GetFileVersionInfoW(pFilename, 0, dwLen, pBlock) + || !VerQueryValueW(pBlock, L"\\VarFileInfo\\Translation", (LPVOID *)&ptl, &cb) ) + goto cleanup; + + is_win7 = IsWindowsVersion(6, 1, 1); + + if ( !is_win7 ) + is_win81 = IsWindowsVersion(6, 3, 0); + + for ( size_t i = 0; i < (cb / sizeof *ptl); i++ ) { + swprintf_s(SubBlock, _countof(SubBlock), L"\\StringFileInfo\\%04x%04x\\InternalName", + ptl[i].wLanguage, + ptl[i].wCodePage); + + // identify wuaueng.dll by its resource data + if ( !VerQueryValueW(pBlock, SubBlock, (LPVOID *)&pInternalName, &uLen) + || _wcsicmp(pInternalName, L"wuaueng.dll") + || !VerQueryValueW(pBlock, L"\\", (LPVOID *)&pffi, &uLen) ) + continue; + + // assure wuaueng.dll is at least the minimum supported version + if ( (is_win7 && FileInfoVerCompare(pffi, 7, 6, 7601, 23714) != -1) + || (is_win81 && FileInfoVerCompare(pffi, 7, 9, 9600, 18621) != -1) ) { + + // convert pFilename to multibyte string because DetourFindFunction doesn't take wide string + // try resolving with detours helper function first (needs dbghelp.dll and an internet connection) + //if ( !wcstombs_s(&n, szModule, _countof(szModule), pFilename, _TRUNCATE) ) + // pfnIsDeviceServiceable = DetourFindFunction(PathFindFileNameA(szModule), "IsDeviceServiceable"); + + // fall back to byte pattern search if the above method fails + if ( !pfnIsDeviceServiceable + && K32GetModuleInformation(GetCurrentProcess(), hModule, &modinfo, sizeof modinfo) ) { +#ifdef _WIN64 + pattern = "FFF3 4883EC?? 33DB 391D???????? 7508 8B05????????"; +#else + if ( is_win7 ) + pattern = "833D????????00 743E E8???????? A3????????"; + else // if we've reached this point we can assume win 8.1 without checking is_win81 again + pattern = "8BFF 51 833D????????00 7507 A1????????"; +#endif + offset = patternfind(modinfo.lpBaseOfDll, modinfo.SizeOfImage, pattern); + if ( offset != -1 ) + pfnIsDeviceServiceable = (LPFN_ISDEVICESERVICEABLE)((uint8_t *)modinfo.lpBaseOfDll + offset); + } + + if ( pfnIsDeviceServiceable ) { + trace(L"Found IsDeviceServiceable address: %p", pfnIsDeviceServiceable); + *ppfnIsDeviceServiceable = pfnIsDeviceServiceable; + result = true; + } + break; + } } - if ( index == -1 ) - return index; - - return ++index < argc ? index : -1; +cleanup: + free(pBlock); + return result; } + +bool GetRemoteHModuleFromTh32ModuleSnapshot(HANDLE hSnapshot, const wchar_t *pLibFileName, HMODULE *phRemoteModule) +{ + MODULEENTRY32W me = { sizeof me }; + if ( !Module32FirstW(hSnapshot, &me) ) + return false; + do { + if ( !_wcsicmp(me.szExePath, pLibFileName) ) { + *phRemoteModule = me.hModule; + return true; + } + } while ( Module32NextW(hSnapshot, &me) ); + return false; +} + +bool InjectSelfAndCreateRemoteThread(DWORD dwProcessId, LPTHREAD_START_ROUTINE pStartAddress, HANDLE SourceHandle, DWORD dwDesiredAccess) +{ + bool result = false; + HANDLE hProcess; + NTSTATUS Status; + HMODULE hRemoteModule; + LPTHREAD_START_ROUTINE pfnTargetStartAddress; + HANDLE TargetHandle = NULL; + HANDLE hThread; + + hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); + if ( !hProcess ) return result; + + Status = NtSuspendProcess(hProcess); + + if ( !NT_SUCCESS(Status) ) goto cleanup; + + if ( InjectLibraryByLocalHModule(hProcess, PIMAGEBASE, &hRemoteModule) + && (!SourceHandle || DuplicateHandle(GetCurrentProcess(), SourceHandle, hProcess, &TargetHandle, dwDesiredAccess, FALSE, 0)) ) { + + // get pointer to StartAddress in remote process + pfnTargetStartAddress = (LPTHREAD_START_ROUTINE)((uint8_t *)hRemoteModule + ((uint8_t *)pStartAddress - (uint8_t *)PIMAGEBASE)); + + hThread = CreateRemoteThread(hProcess, NULL, 0, pfnTargetStartAddress, (LPVOID)TargetHandle, 0, NULL); + if ( hThread ) { + CloseHandle(hThread); + result = true; + } + } + NtResumeProcess(hProcess); +cleanup: + CloseHandle(hProcess); + return result; +} + +bool InjectLibraryByFileName(HANDLE hProcess, const wchar_t *pLibFileName, size_t cchLibFileName, HMODULE *phRemoteModule) +{ + bool result = false; + DWORD dwProcessId; + NTSTATUS Status; + HANDLE hSnapshot; + SIZE_T nSize; + LPVOID pBaseAddress; + HANDLE hThread; + + Status = NtSuspendProcess(hProcess); + if ( !NT_SUCCESS(Status) ) return result; + + dwProcessId = GetProcessId(hProcess); + + hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId); + if ( !hSnapshot ) goto L1; + + result = GetRemoteHModuleFromTh32ModuleSnapshot(hSnapshot, pLibFileName, phRemoteModule); + CloseHandle(hSnapshot); + + // already injected... returns false but sets *phRemoteModule + if ( result ) goto L1; + + nSize = (cchLibFileName + 1) * sizeof *pLibFileName; + pBaseAddress = VirtualAllocEx(hProcess, NULL, nSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + + if ( !pBaseAddress ) goto L1; + + if ( !WriteProcessMemory(hProcess, pBaseAddress, pLibFileName, nSize, NULL) ) + goto L2; + + hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, pBaseAddress, 0, NULL); + if ( !hThread ) goto L2; + + WaitForSingleObject(hThread, INFINITE); + + if ( sizeof *phRemoteModule > sizeof(DWORD) ) { + hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId); + if ( hSnapshot ) { + result = GetRemoteHModuleFromTh32ModuleSnapshot(hSnapshot, pLibFileName, phRemoteModule); + CloseHandle(hSnapshot); + } + } else { + result = !!GetExitCodeThread(hThread, (LPDWORD)phRemoteModule); + } + CloseHandle(hThread); +L2: VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE); +L1: NtResumeProcess(hProcess); + return result; +} + +bool InjectLibraryByLocalHModule(HANDLE hProcess, HMODULE hModule, HMODULE *phRemoteModule) +{ + WCHAR Filename[MAX_PATH]; + DWORD nLength; + + nLength = GetModuleFileNameW(hModule, Filename, _countof(Filename)); + + if ( nLength ) + return InjectLibraryByFileName(hProcess, Filename, nLength, phRemoteModule); + + return false; +} + +bool IsWindowsVersion(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor) +{ + OSVERSIONINFOEXW osvi = { sizeof osvi }; + + DWORDLONG dwlConditionMask = 0; + VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_EQUAL); + VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_EQUAL); + VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + + osvi.dwMajorVersion = wMajorVersion; + osvi.dwMinorVersion = wMinorVersion; + osvi.wServicePackMajor = wServicePackMajor; + + return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE; +} + +PVOID NtQueryKeyAlloc(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PULONG pResultLength) +{ + NTSTATUS Status; + ULONG ResultLength; + PVOID result = NULL; + + Status = NtQueryKey(KeyHandle, KeyInformationClass, NULL, 0, &ResultLength); + if ( Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL ) + return result; + + result = malloc(ResultLength); + if ( !result ) return result; + + Status = NtQueryKey(KeyHandle, KeyInformationClass, result, ResultLength, &ResultLength); + if ( NT_SUCCESS(Status) ) { + *pResultLength = ResultLength; + } else { + free(result); + result = NULL; + } + return result; +} + +PVOID RegGetValueAlloc(HKEY hkey, const wchar_t *pSubKey, const wchar_t *pValue, DWORD dwFlags, LPDWORD pdwType, LPDWORD pcbData) +{ + DWORD cbData = 0; + PVOID result = NULL; + + if ( RegGetValueW(hkey, pSubKey, pValue, dwFlags, pdwType, NULL, &cbData) != ERROR_SUCCESS ) + return result; + + result = malloc(cbData); + if ( !result ) return result; + + if ( RegGetValueW(hkey, pSubKey, pValue, dwFlags, pdwType, result, &cbData) == ERROR_SUCCESS ) { + *pcbData = cbData; + } else { + free(result); + result = NULL; + } + return result; +} + +LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(SC_HANDLE hSCM, const wchar_t *pServiceName, LPDWORD pcbBufSize) +{ + SC_HANDLE hService; + DWORD cbBytesNeeded; + LPQUERY_SERVICE_CONFIGW result = NULL; + + hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_CONFIG); + if ( !hService ) return result; + + if ( !QueryServiceConfigW(hService, NULL, 0, &cbBytesNeeded) + && GetLastError() == ERROR_INSUFFICIENT_BUFFER ) { + + result = malloc(cbBytesNeeded); + if ( result ) { + if ( QueryServiceConfigW(hService, result, cbBytesNeeded, &cbBytesNeeded) ) { + *pcbBufSize = cbBytesNeeded; + } else { + free(result); + result = NULL; + } + } + } + CloseServiceHandle(hService); + return result; +} + +bool QueryServiceStatusProcessInfoByName(SC_HANDLE hSCM, const wchar_t *pServiceName, LPSERVICE_STATUS_PROCESS pServiceStatus) +{ + bool result = false; + SC_HANDLE hService; + DWORD cbBytesNeeded; + + hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_STATUS); + if ( !hService ) return result; + + result = !!QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)pServiceStatus, sizeof *pServiceStatus, &cbBytesNeeded); + CloseServiceHandle(hService); + return result; +} + +bool QueryServiceGroupName(const LPQUERY_SERVICE_CONFIGW pServiceConfig, wchar_t *pGroupName, size_t nSize) +{ + bool result = false; + int NumArgs; + LPWSTR *argv; + + argv = CommandLineToArgvW(pServiceConfig->lpBinaryPathName, &NumArgs); + if ( argv ) { + if ( !_wcsicmp(PathFindFileNameW(argv[0]), L"svchost.exe") ) { + + for ( int i = 1; (i + 1) < NumArgs; i++ ) { + if ( !_wcsicmp(argv[i], L"-k") ) + return !wcscpy_s(pGroupName, nSize, argv[++i]); + } + } + LocalFree((HLOCAL)argv); + } + return result; +} + +DWORD QueryServiceProcessId(SC_HANDLE hSCM, const wchar_t *pServiceName) +{ + SERVICE_STATUS_PROCESS ServiceStatusProcess; + + if ( QueryServiceStatusProcessInfoByName(hSCM, pServiceName, &ServiceStatusProcess) ) + return ServiceStatusProcess.dwProcessId; + return 0; +} + +DWORD InferSvchostGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupName) +{ + DWORD result = 0; + DWORD cbData; + wchar_t *pData; + DWORD dwProcessId; + DWORD cbBufSize; + LPQUERY_SERVICE_CONFIGW pServiceConfig; + bool success; + WCHAR GroupName[256]; + + pData = RegGetValueAlloc(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost", pGroupName, RRF_RT_REG_MULTI_SZ, NULL, &cbData); + if ( !pData ) return result; + + for ( wchar_t *pName = pData; *pName; pName += wcslen(pName) + 1 ) { + dwProcessId = QueryServiceProcessId(hSCM, pName); + trace(L"pName=%ls dwProcessId=%lu", pName, dwProcessId); + if ( !dwProcessId ) continue; + + pServiceConfig = QueryServiceConfigByNameAlloc(hSCM, pName, &cbBufSize); + if ( !pServiceConfig ) continue; + success = QueryServiceGroupName(pServiceConfig, GroupName, _countof(GroupName)); + free(pServiceConfig); + if ( success && !_wcsicmp(pGroupName, GroupName) ) { + trace(L"found PID for group %ls: %lu", pGroupName, dwProcessId); + result = dwProcessId; + break; + } + } + free(pData); + return result; +} \ No newline at end of file diff --git a/wufuc/helpers.h b/wufuc/helpers.h index 8d51e94..aec62fe 100644 --- a/wufuc/helpers.h +++ b/wufuc/helpers.h @@ -1,13 +1,25 @@ #pragma once -bool create_exclusive_mutex(const wchar_t *name, HANDLE *pmutex); -bool create_event_with_security_descriptor(const wchar_t *descriptor, bool manualreset, bool initialstate, const wchar_t *name, HANDLE *pevent); +bool CreateExclusiveMutex(const wchar_t *name, HANDLE *pmutex); +bool CreateEventWithStringSecurityDescriptor(const wchar_t *descriptor, bool manualreset, bool initialstate, const wchar_t *name, HANDLE *pevent); -bool inject_self_into_process(DWORD dwProcessId, HMODULE *phModule); -bool inject_dll_into_process(DWORD dwProcessId, const wchar_t *pszFilename, size_t nLength, HMODULE *phModule); +bool FileExists(const wchar_t *path); +bool FileExistsExpandEnvironmentStrings(const wchar_t *path); +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); -const wchar_t *path_find_fname(const wchar_t *path); -bool path_change_fname(const wchar_t *srcpath, const wchar_t *fname, wchar_t *dstpath, size_t size); -bool path_file_exists(const wchar_t *path); -bool path_expand_file_exists(const wchar_t *path); -int ffi_ver_compare(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wBuild, WORD wRev); \ No newline at end of file +bool FindIsDeviceServiceablePtr(const wchar_t *pFilename, HMODULE hModule, PVOID *ppfnIsDeviceServiceable); +bool GetRemoteHModuleFromTh32ModuleSnapshot(HANDLE hSnapshot, const wchar_t *pLibFileName, HMODULE *phRemoteModule); +bool InjectSelfAndCreateRemoteThread(DWORD dwProcessId, LPTHREAD_START_ROUTINE pStartAddress, HANDLE SourceHandle, DWORD dwDesiredAccess); +bool InjectLibraryByFileName(HANDLE hProcess, const wchar_t *pLibFileName, size_t nLength, HMODULE *phRemoteModule); +bool InjectLibraryByLocalHModule(HANDLE hProcess, HMODULE hModule, HMODULE *phRemoteModule); +bool IsWindowsVersion(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor); + +PVOID NtQueryKeyAlloc(HANDLE KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, PULONG pResultLength); +PVOID RegGetValueAlloc(HKEY hkey, const wchar_t *pSubKey, const wchar_t *pValue, DWORD dwFlags, LPDWORD pdwType, LPDWORD pcbData); +LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(SC_HANDLE hSCM, const wchar_t *pServiceName, LPDWORD pcbBufSize); +bool QueryServiceStatusProcessInfoByName(SC_HANDLE hSCM, const wchar_t *pServiceName, LPSERVICE_STATUS_PROCESS pServiceStatus); + +bool QueryServiceGroupName(const LPQUERY_SERVICE_CONFIGW pServiceConfig, wchar_t *pGroupName, size_t nSize); +DWORD QueryServiceProcessId(SC_HANDLE hSCM, const wchar_t *pServiceName); +DWORD InferSvchostGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupName); diff --git a/wufuc/hooks.c b/wufuc/hooks.c index a0989bc..c25d142 100644 --- a/wufuc/hooks.c +++ b/wufuc/hooks.c @@ -1,141 +1,88 @@ #include "stdafx.h" #include "hooks.h" -#include "patchwua.h" #include "helpers.h" -#include - 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 = NULL; + DWORD MaximumLength = 0; LSTATUS result; - DWORD cbData; - NTSTATUS Status; ULONG ResultLength; PKEY_NAME_INFORMATION pkni; - size_t BufferCount; + size_t NameCount; int current; int pos; - wchar_t *tmp; - size_t MaxCount; - size_t cbLength; + LPWSTR fname; + const WCHAR realpath[] = L"%systemroot%\\system32\\wuaueng.dll"; - if ( (lpData && lpcbData) - && (lpValueName && !_wcsicmp(lpValueName, L"ServiceDll")) ) { + trace(L""); - // store original lpData buffer size - cbData = *lpcbData; + // save original buffer size + if ( lpData && lpcbData ) + MaximumLength = *lpcbData; + trace(L""); - // this way the dll path is guaranteed to be null-terminated - result = RegGetValueW(hKey, NULL, lpValueName, RRF_RT_REG_EXPAND_SZ | RRF_NOEXPAND, lpType, lpData, lpcbData); - if ( result != ERROR_SUCCESS ) - goto L1; + result = g_pfnRegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); - pkni = NULL; - ResultLength = 0; - do { - if ( ResultLength ) { - if ( pkni ) - free(pkni); - pkni = malloc(ResultLength); - } - Status = NtQueryKey((HANDLE)hKey, KeyNameInformation, pkni, ResultLength, &ResultLength); - } while ( Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL ); - if ( !NT_SUCCESS(Status) ) - goto L2; + if ( result != ERROR_SUCCESS || !MaximumLength || !lpValueName || _wcsicmp(lpValueName, L"ServiceDll") ) + return result; + trace(L""); - BufferCount = pkni->NameLength / sizeof(wchar_t); - // change key name to lower-case because there is no case-insensitive version of _snwscanf_s - if ( !_wcslwr_s(pkni->Name, BufferCount) && _snwscanf_s(pkni->Name, BufferCount, - L"\\registry\\machine\\system\\controlset%03d\\services\\wuauserv\\parameters%n", ¤t, &pos) == 1 - && pos == BufferCount ) { + pBuffer = (wchar_t *)lpData; + trace(L""); - const wchar_t *fname = path_find_fname((wchar_t *)lpData); + // get name of registry key being queried + pkni = NtQueryKeyAlloc((HANDLE)hKey, KeyNameInformation, &ResultLength); + trace(L""); + if ( !pkni ) + return result; + trace(L""); - if ( !_wcsicmp(fname, L"wuaueng2.dll") // UpdatePack7R2 - || !_wcsicmp(fname, L"WuaCpuFix64.dll") // WuaCpuFix - || !_wcsicmp(fname, L"WuaCpuFix.dll") ) { + 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 ) { - MaxCount = cbData / sizeof(wchar_t); - tmp = malloc(cbData); - path_change_fname((wchar_t *)lpData, L"wuaueng.dll", tmp, MaxCount); - if ( path_expand_file_exists(tmp) - && !wcscpy_s((wchar_t *)lpData, MaxCount, tmp) - && SUCCEEDED(StringCbLengthW((PNZWCH)lpData, cbData, &cbLength)) ) { + trace(L"key=%.*ls", NameCount, pkni->Name); - *lpcbData = (DWORD)(cbLength + (sizeof UNICODE_NULL)); - } - free(tmp); - } + 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; } -L2: free(pkni); - } else { - // handle normally - result = g_pfnRegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); } -L1: return result; + free(pkni); + return result; } HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags) { HMODULE result; - DWORD dwLen; - LPVOID pBlock; - PLANGANDCODEPAGE ptl; - UINT cb; - wchar_t lpSubBlock[38]; - wchar_t *lpszInternalName; - UINT uLen; - VS_FIXEDFILEINFO *pffi; - wchar_t path[MAX_PATH]; - const wchar_t *fname; - MODULEINFO modinfo; result = g_pfnLoadLibraryExW(lpFileName, hFile, dwFlags); - if ( !result ) { - trace(L"Failed to load library: %ls (error code=%08X)", lpFileName, GetLastError()); - goto L1; - } + if ( !result ) return result; trace(L"Loaded library: %ls", lpFileName); - dwLen = GetFileVersionInfoSizeW(lpFileName, NULL); - if ( !dwLen ) - goto L1; - - pBlock = malloc(dwLen); - - if ( !GetFileVersionInfoW(lpFileName, 0, dwLen, pBlock) - || !VerQueryValueW(pBlock, L"\\VarFileInfo\\Translation", (LPVOID *)&ptl, &cb) ) - goto L2; - - for ( size_t i = 0; i < (cb / sizeof(LANGANDCODEPAGE)); i++ ) { - swprintf_s(lpSubBlock, _countof(lpSubBlock), - L"\\StringFileInfo\\%04x%04x\\InternalName", - ptl[i].wLanguage, - ptl[i].wCodePage); - - if ( VerQueryValueW(pBlock, lpSubBlock, (LPVOID *)&lpszInternalName, &uLen) - && !_wcsicmp(lpszInternalName, L"wuaueng.dll") ) { - - VerQueryValueW(pBlock, L"\\", (LPVOID *)&pffi, &uLen); - GetModuleFileNameW(result, path, _countof(path)); - fname = path_find_fname(path); - - if ( (/*verify_win7() &&*/ ffi_ver_compare(pffi, 7, 6, 7601, 23714) != -1) - || (/*verify_win81() &&*/ ffi_ver_compare(pffi, 7, 9, 9600, 18621) != -1) ) { - - if ( GetModuleInformation(GetCurrentProcess(), result, &modinfo, sizeof(MODULEINFO)) ) { - if ( !patch_wua(modinfo.lpBaseOfDll, modinfo.SizeOfImage, fname) ) - trace(L"Failed to patch %ls!", fname); - } - } - break; - } + if ( FindIsDeviceServiceablePtr(lpFileName, result, (PVOID *)&g_pfnIsDeviceServiceable) ) { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + DetourAttach((PVOID *)&g_pfnIsDeviceServiceable, IsDeviceServiceable_hook); + DetourTransactionCommit(); } -L2: free(pBlock); -L1: return result; + return result; } BOOL WINAPI IsDeviceServiceable_hook(void) diff --git a/wufuc/hooks.h b/wufuc/hooks.h index 485cb83..5bd780a 100644 --- a/wufuc/hooks.h +++ b/wufuc/hooks.h @@ -1,6 +1,6 @@ #pragma once -typedef struct tagLANGANDCODEPAGE +typedef struct { WORD wLanguage; WORD wCodePage; @@ -8,9 +8,12 @@ typedef struct tagLANGANDCODEPAGE typedef LSTATUS(WINAPI *LPFN_REGQUERYVALUEEXW)(HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD); typedef HMODULE(WINAPI *LPFN_LOADLIBRARYEXW)(LPCWSTR, HANDLE, DWORD); +typedef BOOL(WINAPI *LPFN_ISDEVICESERVICEABLE)(void); extern LPFN_REGQUERYVALUEEXW g_pfnRegQueryValueExW; extern LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW; +extern LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceable; LSTATUS WINAPI RegQueryValueExW_hook(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData); HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags); +BOOL WINAPI IsDeviceServiceable_hook(void); diff --git a/wufuc/patchwua.c b/wufuc/patchwua.c deleted file mode 100644 index 13f156b..0000000 --- a/wufuc/patchwua.c +++ /dev/null @@ -1,69 +0,0 @@ -#include "stdafx.h" -#include "patchwua.h" - -#ifdef _M_AMD64 -static const PatchSet X64PatchSet = { "FFF3 4883EC?? 33DB 391D???????? 7508 8B05????????", 0xA, 0x12 }; -#elif defined(_M_IX86) -static const PatchSet Win7X86PatchSet = { "833D????????00 743E E8???????? A3????????", 0x2, 0xF }; -static const PatchSet Win81X86PatchSet = { "8BFF 51 833D????????00 7507 A1????????", 0x5, 0xD }; -#endif - -bool calculate_pointers(uintptr_t lpfn, const PatchSet *ps, LPBOOL *ppba, LPBOOL *ppbb) -{ -#ifdef _M_AMD64 - *ppba = (LPBOOL)(lpfn + ps->Offset1 + sizeof(uint32_t) + *(uint32_t *)(lpfn + ps->Offset1)); - *ppbb = (LPBOOL)(lpfn + ps->Offset2 + sizeof(uint32_t) + *(uint32_t *)(lpfn + ps->Offset2)); - return true; -#elif defined(_M_IX86) - *ppba = (LPBOOL)(*(uintptr_t *)(lpfn + ps->Offset1)); - *ppbb = (LPBOOL)(*(uintptr_t *)(lpfn + ps->Offset2)); - return true; -#endif - return false; -} - -bool patch_wua(void *lpBaseOfDll, size_t SizeOfImage, const wchar_t *fname) -{ - bool result = false; - - const PatchSet *pps = NULL; -#ifdef _M_AMD64 - pps = &X64PatchSet; -#elif defined(_M_IX86) - if ( 1/*verify_win7()*/ ) - pps = &Win7X86PatchSet; - else if ( 1/*verify_win81()*/ ) - pps = &Win81X86PatchSet; - else - goto L1; -#endif - size_t offset = patternfind(lpBaseOfDll, SizeOfImage, pps->Pattern); - if ( offset == -1 ) { - trace(L"No pattern match! (couldn't patch)"); - goto L1; - } - uintptr_t ptr = (uintptr_t)lpBaseOfDll + offset; - - LPBOOL pba, pbb; - if ( calculate_pointers((uintptr_t)ptr, pps, &pba, &pbb) ) { - DWORD flOldProtect; - if ( *pba == TRUE ) { - if ( VirtualProtect(pba, sizeof *pba, PAGE_READWRITE, &flOldProtect) ) { - *pba = FALSE; - trace(L"Patched value #1 at %ls!%p: %08X", fname, pba, *pba); - if ( !VirtualProtect(pba, sizeof *pba, flOldProtect, &flOldProtect) ) - trace(L"Failed to restore memory region permissions at %ls!%p (error code=%08X)", fname, pba, GetLastError()); - } else trace(L"Failed to change memory region permissions at %ls!%p (error code=%08X)", fname, pba, GetLastError()); - } - if ( *pbb == FALSE ) { - if ( VirtualProtect(pbb, sizeof *pbb, PAGE_READWRITE, &flOldProtect) ) { - *pbb = TRUE; - trace(L"Patched value #2 at %ls!%p: %08X", fname, pbb, *pbb); - if ( !VirtualProtect(pbb, sizeof *pbb, flOldProtect, &flOldProtect) ) - trace(L"Failed to restore memory region permissions at %ls!%p: (error code=%08X)", fname, pbb, GetLastError()); - } else trace(L"Failed to change memory region permissions at %ls!%p (error code=%08X)", fname, pbb, GetLastError()); - } - result = !*pba && *pbb; - } -L1: return result; -} diff --git a/wufuc/patchwua.h b/wufuc/patchwua.h deleted file mode 100644 index 2741ffe..0000000 --- a/wufuc/patchwua.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -typedef struct tagPatchSet -{ - const char *Pattern; - const size_t Offset1; - const size_t Offset2; -} PatchSet; - -bool calculate_pointers(uintptr_t lpfn, const PatchSet *ps, LPBOOL *ppba, LPBOOL *ppbb); -bool patch_wua(void *lpBaseOfDll, size_t SizeOfImage, const wchar_t *fname); diff --git a/wufuc/patternfind.c b/wufuc/patternfind.c index 48baf42..a1ad4fe 100644 --- a/wufuc/patternfind.c +++ b/wufuc/patternfind.c @@ -94,7 +94,6 @@ static inline bool patternmatchbyte(uint8_t byte, const PatternByte pbyte) return (matched == 2); } -__declspec(noinline) size_t patternfind(uint8_t *data, size_t datasize, const char *pattern) { size_t searchpatternsize = formathexpattern(pattern, NULL, 0) / 2; diff --git a/wufuc/patternfind.h b/wufuc/patternfind.h index e29240f..ee990c6 100644 --- a/wufuc/patternfind.h +++ b/wufuc/patternfind.h @@ -2,7 +2,7 @@ typedef struct { - struct PatternNibble + struct { uint8_t data; bool wildcard; diff --git a/wufuc/rundll32.c b/wufuc/rundll32.c index 5670cbe..04d156b 100644 --- a/wufuc/rundll32.c +++ b/wufuc/rundll32.c @@ -6,19 +6,44 @@ void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, in { HANDLE hMutex; HANDLE hEvent; - bool Unloading; + DWORD cbBufSize; + LPQUERY_SERVICE_CONFIGW pServiceConfig; + wchar_t GroupName[256]; + DWORD dwProcessId; + bool Unloading = false; bool Lagging; SC_HANDLE hSCM; SC_HANDLE hService; SERVICE_NOTIFYW NotifyBuffer; - if ( !create_exclusive_mutex(L"Global\\{25020063-B5A7-4227-9FDF-25CB75E8C645}", &hMutex) ) + if ( !CreateExclusiveMutex(L"Global\\{25020063-B5A7-4227-9FDF-25CB75E8C645}", &hMutex) ) return; - if ( !create_event_with_security_descriptor(L"D:(A;;0x001F0003;;;BA)", true, false, L"Global\\wufuc_UnloadEvent", &hEvent) ) + if ( !CreateEventWithStringSecurityDescriptor(L"D:(A;;0x001F0003;;;BA)", true, false, L"Global\\wufuc_UnloadEvent", &hEvent) ) goto L1; - Unloading = false; + //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 { Lagging = false; hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); @@ -57,12 +82,12 @@ L1: ReleaseMutex(hMutex); void CALLBACK RUNDLL32_UnloadW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { - HANDLE event; + HANDLE hEvent; - event = OpenEventW(EVENT_MODIFY_STATE, FALSE, L"Global\\wufuc_UnloadEvent"); - if ( event ) { - SetEvent(event); - CloseHandle(event); + hEvent = OpenEventW(EVENT_MODIFY_STATE, FALSE, L"Global\\wufuc_UnloadEvent"); + if ( hEvent ) { + SetEvent(hEvent); + CloseHandle(hEvent); } } diff --git a/wufuc/stdafx.h b/wufuc/stdafx.h index 85ea5eb..879c6f1 100644 --- a/wufuc/stdafx.h +++ b/wufuc/stdafx.h @@ -7,9 +7,13 @@ #include #include #include +#include #include #include +#include +#include #include +#include #include #include "patternfind.h" diff --git a/wufuc/tracing.c b/wufuc/tracing.c index f174b49..6e34dcd 100644 --- a/wufuc/tracing.c +++ b/wufuc/tracing.c @@ -1,13 +1,20 @@ #include "stdafx.h" #include "tracing.h" +static FILE *steam; + void trace_(const wchar_t *const format, ...) { va_list argptr; + int count; + wchar_t *buffer; + va_start(argptr, format); - int count = _vscwprintf(format, argptr) + 1; - wchar_t *buffer = calloc(count, sizeof(wchar_t)); + + count = _vscwprintf(format, argptr) + 1; + buffer = calloc(count, sizeof *buffer); vswprintf_s(buffer, count, format, argptr); + va_end(argptr); OutputDebugStringW(buffer); free(buffer); diff --git a/wufuc/wufuc.rch b/wufuc/wufuc.rch index 48ba6c2..b90a63e 100644 --- a/wufuc/wufuc.rch +++ b/wufuc/wufuc.rch @@ -2,10 +2,10 @@ #define WUFUC_RCH_INCLUDED #pragma once #ifndef BUILD_COMMIT_VERSION -#define BUILD_COMMIT_VERSION 1.0.0.0 +#define BUILD_COMMIT_VERSION 0.9.999.0 #endif #ifndef BUILD_VERSION_COMMA -#define BUILD_VERSION_COMMA 1,0,0,0 +#define BUILD_VERSION_COMMA 0,9,999,0 #endif #define STRINGIZE_(x) #x #define STRINGIZE(x) STRINGIZE_(x) diff --git a/wufuc/wufuc.vcxproj b/wufuc/wufuc.vcxproj index 65a9ff2..08179af 100644 --- a/wufuc/wufuc.vcxproj +++ b/wufuc/wufuc.vcxproj @@ -26,7 +26,6 @@ - @@ -42,7 +41,6 @@ - @@ -157,7 +155,7 @@ exports.def - ntdll.lib;version.lib;detours.X86.MTd.lib;%(AdditionalDependencies) + ntdll.lib;version.lib;Shlwapi.lib;detours.X86.MTd.lib;%(AdditionalDependencies) X86;%(PreprocessorDefinitions) @@ -179,7 +177,7 @@ exports.def - ntdll.lib;version.lib;detours.X64.MTd.lib;%(AdditionalDependencies) + ntdll.lib;version.lib;Shlwapi.lib;detours.X64.MTd.lib;%(AdditionalDependencies) X64;%(PreprocessorDefinitions) @@ -209,7 +207,7 @@ exports.def - ntdll.lib;version.lib;detours.X86.MT.lib;%(AdditionalDependencies) + ntdll.lib;version.lib;Shlwapi.lib;detours.X86.MT.lib;%(AdditionalDependencies) true @@ -238,7 +236,7 @@ true false exports.def - ntdll.lib;version.lib;detours.X64.MT.lib;%(AdditionalDependencies) + ntdll.lib;version.lib;Shlwapi.lib;detours.X64.MT.lib;%(AdditionalDependencies) true diff --git a/wufuc/wufuc.vcxproj.filters b/wufuc/wufuc.vcxproj.filters index cf73c20..ac2a207 100644 --- a/wufuc/wufuc.vcxproj.filters +++ b/wufuc/wufuc.vcxproj.filters @@ -15,9 +15,6 @@ - - Header Files - Header Files @@ -41,9 +38,6 @@ - - Source Files - Source Files diff --git a/wufuc_setup_bat/install_wufuc.bat b/wufuc_setup_bat/install_wufuc.bat index 6d3bd26..c89aa2f 100644 --- a/wufuc_setup_bat/install_wufuc.bat +++ b/wufuc_setup_bat/install_wufuc.bat @@ -61,7 +61,7 @@ set "wufuc_dll=wufuc64.dll" :dll_exists set "wufuc_dll_fullpath=%~dp0%wufuc_dll%" -if exist "%wufuc_dll_fullpath%" goto :check_winver +if exist "%wufuc_dll_fullpath%" goto :xml_exists echo ERROR - Could not find %wufuc_dll_fullpath%! echo. @@ -77,6 +77,19 @@ echo This error could also mean that your anti-virus deleted or quarantined %wuf echo in which case, you will need to make an exception and restore it. goto :die +:xml_exists +for /f "tokens=*" %%i in ('wmic /output:stdout datafile where "name='%wufuc_dll_fullpath:\=\\%'" get Version /value ^| find "="') do set "%%i" +set "wufuc_xml=%~dp0wufuc_ScheduledTask.xml" +if exist "%wufuc_xml%" goto :check_winver + +echo ERROR - Could not find %wufuc_xml%! +echo. +echo This most likely means you didn't extract all the files from the archive. +echo. +echo Please extract all the files from wufuc_v%Version%.zip to a permanent +echo location like C:\Program Files\wufuc and try again. +goto :die + :check_winver ver | findstr " 6\.1\." >nul && ( echo Detected supported operating system: Windows 7 %WINDOWS_ARCHITECTURE% @@ -98,8 +111,7 @@ echo. goto :die :check_mode -set "regkey=HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\svchost.exe" -set "wufuc_dll_target=%systemfolder%\%wufuc_dll%" +set "wufuc_task=wufuc.{72EEE38B-9997-42BD-85D3-2DD96DA17307}" if "%UNINSTALL%"=="1" goto :confirm_uninstall @@ -113,19 +125,24 @@ echo systems with Intel Kaby Lake, AMD Ryzen, or other unsupported processors. echo. echo Please be absolutely sure you really need wufuc before proceeding. echo. -for /f "tokens=*" %%i in ('wmic /output:stdout datafile where "name='%wufuc_dll_fullpath:\=\\%'" get Version /value ^| find "="') do set "%%i" -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 %Version%: if /I "%CONTINUE_INSTALL%"=="Y" goto :install goto :cancel :install call :uninstall -copy /Y "%wufuc_dll_fullpath%" "%wufuc_dll_target%" && ( - reg add "%regkey%" /v VerifierDlls /t REG_SZ /d "%wufuc_dll%" /f - reg add "%regkey%" /v GlobalFlag /t REG_DWORD /d 0x00000100 /f -) +net start Schedule +schtasks /Create /XML "%wufuc_xml%" /TN "%wufuc_task%" /F +schtasks /Change /TN "%wufuc_task%" /TR "'%systemroot%\System32\rundll32.exe' """%wufuc_dll_fullpath%""",RUNDLL32_Start" +schtasks /Change /TN "%wufuc_task%" /ENABLE +rundll32 "%wufuc_dll_fullpath%",RUNDLL32_Unload +net stop wuauserv +schtasks /Run /TN "%wufuc_task%" + +timeout /nobreak /t 3 >nul +net start wuauserv echo. -echo You will need to restart your PC to finish installing wufuc. +echo You may need to restart your PC to finish installing wufuc. goto :confirm_restart :: END INSTALL MODE /////////////////////////////////////////////////////////// @@ -133,26 +150,27 @@ goto :confirm_restart :confirm_uninstall if "%UNATTENDED%"=="1" goto :uninstall_stub echo. -set /p CONTINUE_UNINSTALL=Enter 'Y' if you want to uninstall wufuc: +set /p CONTINUE_UNINSTALL=Enter 'Y' if you want to uninstall wufuc: if /I "%CONTINUE_UNINSTALL%"=="Y" goto :uninstall_stub goto :cancel :uninstall_stub call :uninstall -echo You will need to restart your PC to finish uninstalling wufuc. +echo You may need to restart your PC to finish uninstalling wufuc. goto :confirm_restart :uninstall :: restore wuaueng.dll if it was modified by 0.1-0.5 sfc /SCANFILE="%systemfolder%\wuaueng.dll" - :: remove traces of wufuc 0.6-0.7 - set "wufuc_task=wufuc.{72EEE38B-9997-42BD-85D3-2DD96DA17307}" + :: remove traces of wufuc 0.6-0.7, 0.9.999+ schtasks /Query /TN "%wufuc_task%" >nul 2>&1 && ( schtasks /Delete /TN "%wufuc_task%" /F ) - rundll32 "%wufuc_dll_fullpath%",RUNDLL32_LegacyUnload + rundll32 "%wufuc_dll_fullpath%",RUNDLL32_Unload - :: remove traces of wufuc >=0.8 + :: remove traces of wufuc 0.8.x + set "regkey=HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\svchost.exe" + set "wufuc_dll_target=%systemfolder%\%wufuc_dll%" reg query "%regkey%" >nul 2>&1 || goto :delete_target reg delete "%regkey%" /f || goto :skip_delete :delete_target @@ -169,7 +187,7 @@ goto :confirm_restart if "%NORESTART%"=="1" goto :die if "%UNATTENDED%"=="1" goto :restart echo. -set /p CONTINUE_RESTART=Enter 'Y' if you would like to restart now: +set /p CONTINUE_RESTART=Enter 'Y' if you would like to restart now: if /I "%CONTINUE_RESTART%"=="Y" goto :restart goto :die :restart diff --git a/wufuc_setup_bat/wufuc_ScheduledTask.xml b/wufuc_setup_bat/wufuc_ScheduledTask.xml new file mode 100644 index 0000000..7770bd4 Binary files /dev/null and b/wufuc_setup_bat/wufuc_ScheduledTask.xml differ