steady progress

This commit is contained in:
zeffy
2017-12-30 00:25:56 -08:00
parent c6d1def339
commit b63312c294
15 changed files with 573 additions and 436 deletions

View File

@@ -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"

View File

@@ -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);
} }

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

View File

@@ -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)
{
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);
} }
result = !!QueryServiceStatusEx(hService,
SC_STATUS_PROCESS_INFO,
(LPBYTE)pServiceStatus,
sizeof *pServiceStatus,
&cbBytesNeeded);
CloseServiceHandle(hService);
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;
}

View File

@@ -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);

View File

@@ -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", &current, &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;
} }

View File

@@ -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);

View File

@@ -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;

View File

@@ -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"

View File

@@ -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;

View File

@@ -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>

Binary file not shown.

View File

@@ -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