diff --git a/src/wufuc/callbacks.c b/src/wufuc/callbacks.c index a254294..c0dba94 100644 --- a/src/wufuc/callbacks.c +++ b/src/wufuc/callbacks.c @@ -1,54 +1,65 @@ #include "stdafx.h" -#include "context.h" #include "callbacks.h" #include "hooks.h" #include "log.h" #include "modulehelper.h" #include "registryhelper.h" #include "servicehelper.h" +#include "ptrlist.h" #include "wufuc.h" #include VOID CALLBACK cb_service_notify(PSERVICE_NOTIFYW pNotifyBuffer) { + trace(L"enter"); switch ( pNotifyBuffer->dwNotificationStatus ) { case ERROR_SUCCESS: if ( pNotifyBuffer->ServiceStatus.dwProcessId ) wufuc_inject( pNotifyBuffer->ServiceStatus.dwProcessId, (LPTHREAD_START_ROUTINE)cb_start, - (context *)pNotifyBuffer->pContext); + (ptrlist_t *)pNotifyBuffer->pContext); break; case ERROR_SERVICE_MARKED_FOR_DELETE: - SetEvent(((context *)pNotifyBuffer->pContext)->uevent); + SetEvent(ptrlist_at((ptrlist_t *)pNotifyBuffer->pContext, 1, NULL)); break; } if ( pNotifyBuffer->pszServiceNames ) LocalFree((HLOCAL)pNotifyBuffer->pszServiceNames); } -DWORD WINAPI cb_start(context *ctx) +DWORD WINAPI cb_start(HANDLE *pParam) { + HANDLE handles[2]; + HANDLE hCrashMutex; + HANDLE hProceedEvent; SC_HANDLE hSCM; SC_HANDLE hService; DWORD dwProcessId; LPQUERY_SERVICE_CONFIGW pServiceConfig; DWORD dwServiceType; + LPVOID pTarget = NULL; wchar_t *str; HMODULE hModule; - // get mutex and unload event handles from virtual memory - if ( !ctx ) { - trace(L"Context parameter is null!"); + if ( !pParam ) { + trace(L"Parameter argument is null!"); goto unload; } + handles[0] = pParam[0]; // main mutex + handles[1] = pParam[1]; // unload event + hCrashMutex = pParam[2]; // crash mutex + hProceedEvent = pParam[3]; // proceed event + VirtualFree(pParam, 0, MEM_RELEASE); + // acquire child mutex, this should be immediate. - if ( WaitForSingleObject(ctx->handles[ctx->mutex_tag], 5000) != WAIT_OBJECT_0 ) { - trace(L"Failed to acquire child mutex within five seconds. (%p)", ctx->handles[ctx->mutex_tag]); + if ( WaitForSingleObject(hCrashMutex, 5000) != WAIT_OBJECT_0 ) { + trace(L"Failed to acquire child mutex within five seconds. (%p)", hCrashMutex); goto close_handles; } + SetEvent(hProceedEvent); hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); if ( !hSCM ) { @@ -75,11 +86,12 @@ DWORD WINAPI cb_start(context *ctx) // RegQueryValueExW hook to fix incompatibility with // UpdatePack7R2 and other patches that modify the // Windows Update ServiceDll path in the registry. - MH_CreateHookApi(L"kernel32.dll", + trace(L"MH_CreateHookApi RegQueryValueExW=%hs", MH_StatusToString(MH_CreateHookApiEx(L"kernel32.dll", "RegQueryValueExW", RegQueryValueExW_hook, - &(PVOID)g_pfnRegQueryValueExW); - MH_EnableHook(g_pfnRegQueryValueExW); + &(PVOID)g_pfnRegQueryValueExW, + &pTarget))); + trace(L"MH_EnableHook RegQueryValueExW=%hs", MH_StatusToString(MH_EnableHook(pTarget))); } // query the ServiceDll path after applying our compat hook so that it @@ -89,17 +101,18 @@ DWORD WINAPI cb_start(context *ctx) L"ServiceDll", NULL, NULL); if ( !str ) { abort_hook: - MH_RemoveHook(g_pfnRegQueryValueExW); + if ( pTarget ) + trace(L"MH_RemoveHook RegQueryValueExW=%hs", MH_StatusToString(MH_RemoveHook(pTarget))); goto release; } g_pszWUServiceDll = env_expand_strings_alloc(str, NULL); - if ( !g_pszWUServiceDll ) goto abort_hook; free(str); + if ( !g_pszWUServiceDll ) goto abort_hook; - MH_CreateHookApi(L"kernel32.dll", + trace(L"MH_CreateHookApi LoadLibraryExW=%hs", MH_StatusToString(MH_CreateHookApi(L"kernel32.dll", "LoadLibraryExW", LoadLibraryExW_hook, - &(PVOID)g_pfnLoadLibraryExW); + &(PVOID)g_pfnLoadLibraryExW))); if ( GetModuleHandleExW(0, g_pszWUServiceDll, &hModule) || GetModuleHandleExW(0, PathFindFileNameW(g_pszWUServiceDll), &hModule) ) { @@ -109,27 +122,21 @@ abort_hook: FreeLibrary(hModule); } - MH_EnableHook(MH_ALL_HOOKS); + trace(L"MH_EnableHook=%hs", MH_StatusToString(MH_EnableHook(MH_ALL_HOOKS))); // wait for unload event or the main mutex to be released or abandoned, // for example if the user killed rundll32.exe with task manager. - - // we use ctx_wait_any_unsafe here because contexts created by - // ctx_duplicate_context are not initialized by ctx_create, - // and have no critical section to lock, so they are only used to - // hold static handles to send to another process. - ctx_wait_any_unsafe(ctx, false); + WaitForMultipleObjects(_countof(handles), handles, FALSE, INFINITE); trace(L"Unload condition has been met."); - MH_DisableHook(MH_ALL_HOOKS); + trace(L"MH_DisableHook(MH_ALL_HOOKS) LoadLibraryExW=%hs", MH_StatusToString(MH_DisableHook(MH_ALL_HOOKS))); free(g_pszWUServiceDll); release: - ReleaseMutex(ctx->handles[ctx->mutex_tag]); + ReleaseMutex(hCrashMutex); close_handles: - CloseHandle(ctx->handles[ctx->mutex_tag]); - CloseHandle(ctx->mutex); - CloseHandle(ctx->uevent); - VirtualFree(ctx, 0, MEM_RELEASE); + CloseHandle(hCrashMutex); + CloseHandle(handles[0]); + CloseHandle(handles[1]); unload: trace(L"Unloading wufuc and exiting thread."); FreeLibraryAndExitThread(PIMAGEBASE, 0); diff --git a/src/wufuc/callbacks.h b/src/wufuc/callbacks.h index 367c101..63e8ad0 100644 --- a/src/wufuc/callbacks.h +++ b/src/wufuc/callbacks.h @@ -1,4 +1,4 @@ #pragma once VOID CALLBACK cb_service_notify(PSERVICE_NOTIFYW pNotifyBuffer); -DWORD WINAPI cb_start(context *ctx); +DWORD WINAPI cb_start(HANDLE *pParam); diff --git a/src/wufuc/context.c b/src/wufuc/context.c deleted file mode 100644 index cf73e33..0000000 --- a/src/wufuc/context.c +++ /dev/null @@ -1,404 +0,0 @@ -#include "stdafx.h" -#include "context.h" - -#include - -static bool ctxp_remove_handle(context *ctx, DWORD Index) -{ - if ( !ctx || Index > _countof(ctx->handles) || Index > ctx->count ) - return false; - - EnterCriticalSection(&ctx->cs); - for ( DWORD i = Index; i < ctx->count - 1; i++ ) { - ctx->handles[i] = ctx->handles[i + 1]; - ctx->tags[i] = ctx->tags[i + 1]; - } - LeaveCriticalSection(&ctx->cs); - return true; -} - -static bool ctxp_create_new_mutex(bool InitialOwner, - const wchar_t *MutexName, - HANDLE *pMutexHandle) -{ - HANDLE hMutex; - - hMutex = CreateMutexW(NULL, InitialOwner, MutexName); - if ( hMutex ) { - if ( GetLastError() == ERROR_ALREADY_EXISTS ) { - CloseHandle(hMutex); - return false; - } - *pMutexHandle = hMutex; - return true; - } - return false; -} - -static bool ctxp_create_new_mutex_vfmt(bool InitialOwner, - HANDLE *pMutexHandle, - const wchar_t *const NameFormat, - va_list ArgList) -{ - wchar_t *buffer; - int ret; - bool result; - - ret = _vscwprintf(NameFormat, ArgList) + 1; - buffer = calloc(ret, sizeof *buffer); - if ( !buffer ) - return false; - - ret = vswprintf_s(buffer, ret, NameFormat, ArgList); - if ( ret == -1 ) - return false; - - result = ctxp_create_new_mutex(InitialOwner, buffer, pMutexHandle); - free(buffer); - return result; -} - -static bool ctxp_create_event_with_string_security_descriptor( - bool ManualReset, - bool InitialState, - const wchar_t *Name, - const wchar_t *StringSecurityDescriptor, - HANDLE *pEventHandle) -{ - SECURITY_ATTRIBUTES sa = { sizeof sa }; - HANDLE hEvent; - - if ( ConvertStringSecurityDescriptorToSecurityDescriptorW( - StringSecurityDescriptor, - SDDL_REVISION_1, - &sa.lpSecurityDescriptor, - NULL) ) { - - hEvent = CreateEventW(&sa, ManualReset, InitialState, Name); - if ( hEvent ) { - *pEventHandle = hEvent; - return true; - } - } - return false; -} - -static DWORD ctxp_find_handle_index(context *ctx, HANDLE Handle) -{ - DWORD result = -1; - - if ( !ctx || !Handle || Handle == INVALID_HANDLE_VALUE ) - return -1; - - EnterCriticalSection(&ctx->cs); - for ( DWORD i = 0; i < ctx->count; i++ ) { - if ( ctx->handles[i] == Handle ) { - result = i; - break; - } - } - LeaveCriticalSection(&ctx->cs); - return result; -} - -bool ctx_create(context *ctx, - const wchar_t *MutexName, - DWORD MutexTag, - const wchar_t *EventName, - const wchar_t *EventStringSecurityDescriptor, - DWORD EventTag) -{ - bool result = false; - - if ( !ctx ) return false; - - ZeroMemory(ctx, sizeof *ctx); - InitializeCriticalSection(&ctx->cs); - EnterCriticalSection(&ctx->cs); - - if ( ctxp_create_new_mutex(true, MutexName, &ctx->mutex) ) { - ctx->mutex_tag = MutexTag; - ctx->count++; - - result = ctx_add_event(ctx, EventName, EventStringSecurityDescriptor, EventTag, NULL); - if ( !result ) { - ReleaseMutex(ctx->mutex); - ctx_close_and_remove_handle(ctx, ctx->mutex); - } - } - LeaveCriticalSection(&ctx->cs); - return result; -} - -bool ctx_delete(context *ctx) -{ - if ( !ctx || ctx->count > _countof(ctx->handles) ) - return false; - - EnterCriticalSection(&ctx->cs); - while ( ctx->count-- ) { - CloseHandle(ctx->handles[ctx->count]); - ctx->handles[ctx->count] = INVALID_HANDLE_VALUE; - ctx->tags[ctx->count] = -1; - } - LeaveCriticalSection(&ctx->cs); - DeleteCriticalSection(&ctx->cs); - return true; -} - -DWORD ctx_add_handle(context *ctx, HANDLE Handle, DWORD Tag) -{ - DWORD result = -1; - - if ( !ctx || !Handle ) - return -1; - - EnterCriticalSection(&ctx->cs); - result = ctxp_find_handle_index(ctx, Handle); - if ( result != -1 ) { - ctx->tags[result] = Tag; - } else if ( ctx->count < _countof(ctx->handles) ) { - ctx->handles[ctx->count] = Handle; - ctx->tags[ctx->count] = Tag; - - result = ctx->count++; - } - LeaveCriticalSection(&ctx->cs); - return result; -} - -bool ctx_get_tag(context *ctx, HANDLE Handle, DWORD *pTag) -{ - bool result = false; - DWORD index; - - if ( !ctx || !Handle || !pTag ) - return false; - - EnterCriticalSection(&ctx->cs); - index = ctxp_find_handle_index(ctx, Handle); - if ( index != -1 ) { - if ( pTag ) { - *pTag = ctx->tags[index]; - result = true; - } - } - LeaveCriticalSection(&ctx->cs); - return result; -} - -DWORD ctx_add_new_mutex(context *ctx, - bool InitialOwner, - const wchar_t *Name, - DWORD Tag, - HANDLE *pMutexHandle) -{ - HANDLE hMutex; - DWORD result = -1; - - EnterCriticalSection(&ctx->cs); - if ( ctxp_create_new_mutex(InitialOwner, Name, &hMutex) ) { - result = ctx_add_handle(ctx, hMutex, Tag); - if ( result != -1 ) { - if ( pMutexHandle ) - *pMutexHandle = hMutex; - } else { - CloseHandle(hMutex); - } - } - LeaveCriticalSection(&ctx->cs); - return result; -} - -DWORD ctx_add_new_mutex_fmt(context *ctx, - bool InitialOwner, - DWORD Tag, - HANDLE *pMutexHandle, - const wchar_t *const NameFormat, - ...) -{ - HANDLE hMutex; - DWORD result = -1; - va_list arglist; - - EnterCriticalSection(&ctx->cs); - va_start(arglist, NameFormat); - if ( ctxp_create_new_mutex_vfmt(InitialOwner, &hMutex, NameFormat, arglist) ) { - result = ctx_add_handle(ctx, hMutex, Tag); - if ( result != -1 ) { - if ( pMutexHandle ) - *pMutexHandle = hMutex; - } else { - CloseHandle(hMutex); - } - } - va_end(arglist); - LeaveCriticalSection(&ctx->cs); - return result; -} - -DWORD ctx_add_event(context *ctx, - const wchar_t *Name, - const wchar_t *StringSecurityDescriptor, - DWORD Tag, - HANDLE *pEventHandle) -{ - DWORD result = -1; - HANDLE hEvent; - - EnterCriticalSection(&ctx->cs); - if ( ctxp_create_event_with_string_security_descriptor( - true, - false, - Name, - StringSecurityDescriptor, - &hEvent) ) { - result = ctx_add_handle(ctx, hEvent, Tag); - if ( result != -1 ) { - if ( pEventHandle ) - *pEventHandle = hEvent; - } else { - CloseHandle(hEvent); - } - } - LeaveCriticalSection(&ctx->cs); - return result; -} - -DWORD ctx_wait_all_unsafe(context *ctx, - bool Alertable) -{ - return WaitForMultipleObjectsEx(ctx->count, - ctx->handles, - TRUE, - INFINITE, - Alertable); -} - -bool ctx_wait_all(context *ctx, - bool Alertable, - DWORD *pResult) -{ - int ret; - DWORD count; - HANDLE handles[MAXIMUM_WAIT_OBJECTS]; - - EnterCriticalSection(&ctx->cs); - count = ctx->count; - ret = memcpy_s(handles, sizeof(handles), ctx->handles, count * (sizeof *handles)); - LeaveCriticalSection(&ctx->cs); - - if ( ret ) - return false; - - *pResult = WaitForMultipleObjectsEx(count, - handles, - TRUE, - INFINITE, - Alertable); - return true; -} - -DWORD ctx_wait_any_unsafe(context *ctx, - bool Alertable) -{ - return WaitForMultipleObjectsEx(ctx->count, - ctx->handles, - FALSE, - INFINITE, - Alertable); -} - -DWORD ctx_wait_any(context *ctx, - bool Alertable, - DWORD *pResult, - HANDLE *pHandle, - DWORD *pTag) -{ - DWORD count; - HANDLE handles[MAXIMUM_WAIT_OBJECTS]; - DWORD tags[MAXIMUM_WAIT_OBJECTS]; - int ret; - DWORD result; - DWORD index; - - EnterCriticalSection(&ctx->cs); - // make copies of the struct members on the stack before waiting, because - // WaitForMultipleObjects(Ex) doesn't like it when you modify the contents of - // the array it is waiting on. - count = ctx->count; - ret = memcpy_s(handles, sizeof(handles), ctx->handles, count * (sizeof *handles)); - if ( !ret ) - ret = memcpy_s(tags, sizeof(tags), ctx->tags, count * (sizeof *tags)); - LeaveCriticalSection(&ctx->cs); - - if ( ret ) - return -1; - - result = WaitForMultipleObjectsEx(count, handles, FALSE, INFINITE, Alertable); - - if ( result >= WAIT_OBJECT_0 || result < WAIT_OBJECT_0 + count ) - index = result - WAIT_OBJECT_0; - else if ( result >= WAIT_ABANDONED_0 || result < WAIT_ABANDONED_0 + count ) - index = result - WAIT_ABANDONED_0; - - if ( pHandle ) - *pHandle = handles[index]; - if ( pTag ) - *pTag = tags[index]; - - *pResult = result; - return count; -} - -bool ctx_close_and_remove_handle(context *ctx, HANDLE Handle) -{ - bool result = false; - DWORD index; - - EnterCriticalSection(&ctx->cs); - index = ctxp_find_handle_index(ctx, Handle); - result = index != -1 - && CloseHandle(Handle) - && ctxp_remove_handle(ctx, index); - LeaveCriticalSection(&ctx->cs); - return result; -} - -bool ctx_duplicate_context(const context *pSrc, - HANDLE hProcess, - context *pDst, - HANDLE Handle, - DWORD DesiredAccess, - DWORD Tag) -{ - bool result = false; - HANDLE hSrcProcess; - HANDLE hTarget; - DWORD index; - - hSrcProcess = GetCurrentProcess(); - - if ( !DuplicateHandle(hSrcProcess, pSrc->mutex, hProcess, &pDst->mutex, SYNCHRONIZE, FALSE, 0) ) - return false; - pDst->count++; - - if ( !DuplicateHandle(hSrcProcess, pSrc->uevent, hProcess, &pDst->uevent, SYNCHRONIZE, FALSE, 0) ) { -close_mutex: - CloseHandle(pDst->mutex); - pDst->mutex = INVALID_HANDLE_VALUE; - pDst->count = 0; - return false; - } - pDst->count++; - if ( !DuplicateHandle(hSrcProcess, Handle, hProcess, &hTarget, 0, FALSE, DesiredAccess) - || (index = ctx_add_handle(pDst, hTarget, Tag)) == -1 ) { - - CloseHandle(pDst->uevent); - pDst->uevent = INVALID_HANDLE_VALUE; - goto close_mutex; - - } - pDst->mutex_tag = index; - return true; -} diff --git a/src/wufuc/context.h b/src/wufuc/context.h deleted file mode 100644 index a9b0baa..0000000 --- a/src/wufuc/context.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#pragma pack(push, 1) -typedef struct -{ - CRITICAL_SECTION cs; - DWORD count; - union - { - struct - { - HANDLE mutex; - HANDLE uevent; - }; - HANDLE handles[MAXIMUM_WAIT_OBJECTS]; - }; - union - { - struct - { - DWORD mutex_tag; - DWORD uevent_tag; - }; - DWORD tags[MAXIMUM_WAIT_OBJECTS]; - }; -} context; -#pragma pack(pop) - -bool ctx_create(context *ctx, - const wchar_t *MutexName, - DWORD MutexTag, - const wchar_t *EventName, - const wchar_t *EventStringSecurityDescriptor, - DWORD EventTag); -bool ctx_delete(context *ctx); -DWORD ctx_add_handle(context *ctx, HANDLE Handle, DWORD Tag); -bool ctx_get_tag(context *ctx, HANDLE Handle, DWORD *pTag); -DWORD ctx_add_new_mutex(context *ctx, - bool InitialOwner, - const wchar_t *Name, - DWORD Tag, - HANDLE *pMutexHandle); -DWORD ctx_add_new_mutex_fmt(context *ctx, - bool InitialOwner, - DWORD Tag, - HANDLE *pMutexHandle, - const wchar_t *const NameFormat, - ...); -DWORD ctx_add_event(context *ctx, - const wchar_t *Name, - const wchar_t *StringSecurityDescriptor, - DWORD Tag, - HANDLE *pEventHandle); -DWORD ctx_wait_all_unsafe(context *ctx, - bool Alertable); -bool ctx_wait_all(context *ctx, - bool Alertable, - DWORD *pResult); -DWORD ctx_wait_any_unsafe(context *ctx, - bool Alertable); -DWORD ctx_wait_any(context *ctx, - bool Alertable, - DWORD *pResult, - HANDLE *pHandle, - DWORD *pTag); -bool ctx_close_and_remove_handle(context *ctx, HANDLE Handle); -bool ctx_duplicate_context(const context *pSrc, - HANDLE hProcess, - context *pDst, - HANDLE Handle, - DWORD DesiredAccess, - DWORD Tag); \ No newline at end of file diff --git a/src/wufuc/dllmain.c b/src/wufuc/dllmain.c index f6e520e..a29d610 100644 --- a/src/wufuc/dllmain.c +++ b/src/wufuc/dllmain.c @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "log.h" #include @@ -12,6 +13,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: + break; case DLL_PROCESS_DETACH: MH_Uninitialize(); break; diff --git a/src/wufuc/eventhelper.c b/src/wufuc/eventhelper.c new file mode 100644 index 0000000..2c35460 --- /dev/null +++ b/src/wufuc/eventhelper.c @@ -0,0 +1,23 @@ +#include "stdafx.h" +#include "eventhelper.h" + +#include + +HANDLE event_create_with_string_security_descriptor( + bool ManualReset, + bool InitialState, + const wchar_t *Name, + const wchar_t *StringSecurityDescriptor) +{ + SECURITY_ATTRIBUTES sa = { sizeof sa }; + + if ( ConvertStringSecurityDescriptorToSecurityDescriptorW( + StringSecurityDescriptor, + SDDL_REVISION_1, + &sa.lpSecurityDescriptor, + NULL) ) { + + return CreateEventW(&sa, ManualReset, InitialState, Name); + } + return NULL; +} diff --git a/src/wufuc/eventhelper.h b/src/wufuc/eventhelper.h new file mode 100644 index 0000000..da7fbf8 --- /dev/null +++ b/src/wufuc/eventhelper.h @@ -0,0 +1,7 @@ +#pragma once + +HANDLE event_create_with_string_security_descriptor( + bool ManualReset, + bool InitialState, + const wchar_t *Name, + const wchar_t *StringSecurityDescriptor); diff --git a/src/wufuc/hooks.c b/src/wufuc/hooks.c index 1ad17a1..be24b82 100644 --- a/src/wufuc/hooks.c +++ b/src/wufuc/hooks.c @@ -1,8 +1,8 @@ #include "stdafx.h" -#include "context.h" #include "hooks.h" #include "log.h" #include "registryhelper.h" +#include "ptrlist.h" #include "wufuc.h" wchar_t *g_pszWUServiceDll; diff --git a/src/wufuc/log.c b/src/wufuc/log.c index 4088036..54fcecf 100644 --- a/src/wufuc/log.c +++ b/src/wufuc/log.c @@ -1,5 +1,4 @@ #include "stdafx.h" - #include "log.h" void logp_debug_write(const wchar_t *const format, ...) @@ -7,7 +6,7 @@ void logp_debug_write(const wchar_t *const format, ...) DWORD pid; wchar_t exepath[MAX_PATH]; wchar_t *exename; - va_list argptr; + va_list ap; int count; wchar_t *buffer1; wchar_t *buffer2; @@ -19,11 +18,13 @@ void logp_debug_write(const wchar_t *const format, ...) GetModuleFileNameW(NULL, exepath, _countof(exepath)); exename = PathFindFileNameW(exepath); - va_start(argptr, format); - count = _vscwprintf(format, argptr) + 1; + va_start(ap, format); + count = _vscwprintf(format, ap) + 1; + va_end(ap); buffer1 = calloc(count, sizeof *buffer1); - vswprintf_s(buffer1, count, format, argptr); - va_end(argptr); + va_start(ap, format); + vswprintf_s(buffer1, count, format, ap); + va_end(ap); _wstrdate_s(datebuf, _countof(datebuf)); _wstrtime_s(timebuf, _countof(timebuf)); @@ -36,259 +37,3 @@ void logp_debug_write(const wchar_t *const format, ...) OutputDebugStringW(buffer2); free(buffer2); } -#define log_debug_write(format, ...) \ - logp_debug_write(__FUNCTIONW__ L": " format L"\r\n", ##__VA_ARGS__) -#define trace log_debug_write - -//#include "stdafx.h" -//#include "tracing.h" -//#include -// -//wchar_t path[MAX_PATH]; -//wchar_t exepath[MAX_PATH]; -// -//bool tracec(bool condition, const wchar_t *const format, ...) -//{ -// va_list argptr; -// int count; -// wchar_t *buffer; -// -// if ( condition ) { -// va_start(argptr, format); -// -// count = _vscwprintf(format, argptr) + 1; -// buffer = calloc(count, sizeof *buffer); -// vswprintf_s(buffer, count, format, argptr); -// -// va_end(argptr); -// OutputDebugStringW(buffer); -// free(buffer); -// } -// return condition; -//} -//void trace(const wchar_t *const format, ...) -//{ -// va_list argptr; -// int count; -// wchar_t *buffer; -// -// va_start(argptr, format); -// -// count = _vscwprintf(format, argptr) + 1; -// buffer = calloc(count, sizeof *buffer); -// vswprintf_s(buffer, count, format, argptr); -// -// va_end(argptr); -// OutputDebugStringW(buffer); -// free(buffer); -//} -// -//DWORD WINAPI tracing_thread(LPVOID pParam) -//{ -// wchar_t *folder; -// HANDLE file; -// DWORD dwProcessId; -// wchar_t *exename; -// int count; -// -// if ( !*path ) { -// SHGetKnownFolderPath(&FOLDERID_ProgramData, 0, NULL, &folder); -// wcscpy_s(path, _countof(path), folder); -// CoTaskMemFree(folder); -// PathAppendW(path, L"wufuc"); -// CreateDirectoryW(path, NULL); -// PathAppendW(path, L"wufuc.log"); -// } -// if ( !*exepath ) -// GetModuleFileNameW(NULL, exepath, _countof(exepath)); -// -// file = CreateFileW(path, FILE_APPEND_DATA, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); -// itrace(L"CreateFileW=%p", file); -// dwProcessId = GetCurrentProcessId(); -// exename = PathFindFileNameW(exepath); -// -// va_start(argptr, format); -// count = _vscwprintf(format, argptr) + 1; -// buf1 = calloc(count, sizeof *buf1); -// vswprintf_s(buf1, count, format, argptr); -// va_end(argptr); -// -// count = _scwprintf(fmt, datebuf, timebuf, dwProcessId, exename, buf1); -// buf2 = calloc(count + 1, sizeof *buf2); -// swprintf_s(buf2, count + 1, fmt, datebuf, timebuf, dwProcessId, exename, buf1); -// free(buf1); -// itrace(L"WriteFile=%d", WriteFile(file, buf2, count * (sizeof *buf2), &written, NULL)); -// free(buf2); -// itrace(L"FlushFileBuffers=%d", FlushFileBuffers(file)); -// itrace(L"CloseHandle=%d", CloseHandle(file)); -// itrace(L"ReleaseMutex=%d", ReleaseMutex(g_hTracingMutex)); -// -// -// HANDLE hHeap = GetProcessHeap(); -// TCHAR* pchRequest = (TCHAR*)HeapAlloc(hHeap, 0, 512 * sizeof(TCHAR)); -// -// DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0; -// BOOL fSuccess = FALSE; -// HANDLE hPipe = NULL; -// -// // Do some extra error checking since the app will keep running even if this -// // thread fails. -// -// if ( pParam == NULL ) { -// itrace(L"\nERROR - Pipe Server Failure:"); -// itrace(L" InstanceThread got an unexpected NULL value in lpvParam."); -// itrace(L" InstanceThread exitting."); -// if ( pchRequest != NULL ) HeapFree(hHeap, 0, pchRequest); -// return -1; -// } -// -// // Print verbose messages. In production code, this should be for debugging only. -// printf("InstanceThread created, receiving and processing messages.\n"); -// -// // The thread's parameter is a handle to a pipe object instance. -// -// hPipe = (HANDLE)pParam; -// -// // Loop until done reading -// while ( true ) { -// // Read client requests from the pipe. This simplistic code only allows messages -// // up to BUFSIZE characters in length. -// fSuccess = ReadFile( -// hPipe, // handle to pipe -// pchRequest, // buffer to receive data -// 512 * sizeof(TCHAR), // size of buffer -// &cbBytesRead, // number of bytes read -// NULL); // not overlapped I/O -// -// if ( !fSuccess || cbBytesRead == 0 ) { -// if ( GetLastError() == ERROR_BROKEN_PIPE ) { -// itrace(L"InstanceThread: client disconnected."); -// } else { -// itrace(L"InstanceThread ReadFile failed, GLE=%d.", GetLastError()); -// } -// break; -// } -// -// _wstrdate_s(datebuf, _countof(datebuf)); -// _wstrtime_s(timebuf, _countof(timebuf)); -// -// if ( !fSuccess ) { -// itrace(L"InstanceThread WriteFile failed, GLE=%d.", GetLastError()); -// break; -// } -// } -// -// // Flush the pipe to allow the client to read the pipe's contents -// // before disconnecting. Then disconnect the pipe, and close the -// // handle to this pipe instance. -// -// FlushFileBuffers(hPipe); -// DisconnectNamedPipe(hPipe); -// CloseHandle(hPipe); -// -// HeapFree(hHeap, 0, pchRequest); -// -// printf("InstanceThread exitting.\n"); -// return 1; -//} -// -//bool start_tracing(const wchar_t *pipename) -//{ -// HANDLE hPipe; -// HANDLE hPipe = INVALID_HANDLE_VALUE; -// HANDLE hThread = NULL; -// -// while ( true ) { -// hPipe = CreateNamedPipeW(pipename, -// PIPE_ACCESS_INBOUND, 0, PIPE_UNLIMITED_INSTANCES, 512, 0, 512, NULL); -// if ( hPipe == INVALID_HANDLE_VALUE ) { -// itrace(L"CreateNamedPipe failed, GLE=%d.\n"), GetLastError(); -// return false; -// } -// -// if ( ConnectNamedPipe(hPipe, NULL) || -// GetLastError() == ERROR_PIPE_CONNECTED ) { -// itrace(L"Client connected, creating a processing thread."); -// -// // Create a thread for this client. -// hThread = CreateThread( -// NULL, // no security attribute -// 0, // default stack size -// tracing_thread, // thread proc -// (LPVOID)hPipe, // thread parameter -// 0, // not suspended -// NULL); // returns thread ID -// -// if ( hThread == NULL ) { -// itrace(L"CreateThread failed, GLE=%d.\n"), GetLastError(); -// return false; -// } else { -// CloseHandle(hThread); -// } -// } else { -// // The client could not connect, so close the pipe. -// CloseHandle(hPipe); -// } -// } -// return true; -//} -// -//void trace_(const wchar_t *const format, ...) -//{ -// va_list argptr; -// wchar_t *folder; -// wchar_t datebuf[9]; -// wchar_t timebuf[9]; -// HANDLE file; -// DWORD dwProcessId; -// wchar_t *exename; -// int count; -// DWORD written; -// const wchar_t fmt[] = L"%ls %ls [%lu] Exe(%ls) %ls"; -// wchar_t *buf1; -// wchar_t *buf2; -// -// va_start(argptr, format); -// itrace_(format); -// va_end(argptr); -// -// if ( !*path ) { -// SHGetKnownFolderPath(&FOLDERID_ProgramData, 0, NULL, &folder); -// wcscpy_s(path, _countof(path), folder); -// CoTaskMemFree(folder); -// PathAppendW(path, L"wufuc"); -// CreateDirectoryW(path, NULL); -// PathAppendW(path, L"wufuc.log"); -// } -// if ( !*exepath ) -// GetModuleFileNameW(NULL, exepath, _countof(exepath)); -// -// if ( !g_hTracingMutex ) -// g_hTracingMutex = CreateMutexW(NULL, FALSE, L"Global\\6b2f5740-7435-47f7-865c-dbd825292f32"); -// -// itrace(L"WaitForSingleObject=%lu", WaitForSingleObject(g_hTracingMutex, INFINITE)); -// -// _wstrdate_s(datebuf, _countof(datebuf)); -// _wstrtime_s(timebuf, _countof(timebuf)); -// -// file = CreateFileW(path, FILE_APPEND_DATA, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); -// itrace(L"CreateFileW=%p", file); -// dwProcessId = GetCurrentProcessId(); -// exename = PathFindFileNameW(exepath); -// -// va_start(argptr, format); -// count = _vscwprintf(format, argptr) + 1; -// buf1 = calloc(count, sizeof *buf1); -// vswprintf_s(buf1, count, format, argptr); -// va_end(argptr); -// -// count = _scwprintf(fmt, datebuf, timebuf, dwProcessId, exename, buf1); -// buf2 = calloc(count + 1, sizeof *buf2); -// swprintf_s(buf2, count + 1, fmt, datebuf, timebuf, dwProcessId, exename, buf1); -// free(buf1); -// itrace(L"WriteFile=%d", WriteFile(file, buf2, count * (sizeof *buf2), &written, NULL)); -// free(buf2); -// itrace(L"FlushFileBuffers=%d", FlushFileBuffers(file)); -// itrace(L"CloseHandle=%d", CloseHandle(file)); -// itrace(L"ReleaseMutex=%d", ReleaseMutex(g_hTracingMutex)); -//} diff --git a/src/wufuc/log.h b/src/wufuc/log.h index 30397c1..5f1a3f4 100644 --- a/src/wufuc/log.h +++ b/src/wufuc/log.h @@ -2,5 +2,5 @@ void logp_debug_write(const wchar_t *const format, ...); #define log_debug_write(format, ...) \ - logp_debug_write(__FUNCTIONW__ L": " format L"\r\n", ##__VA_ARGS__) + logp_debug_write(__FUNCTIONW__ L"(" _CRT_WIDE(_CRT_STRINGIZE(__LINE__)) L"): " format L"\r\n", ##__VA_ARGS__) #define trace log_debug_write diff --git a/src/wufuc/modulehelper.c b/src/wufuc/modulehelper.c index 577e533..4655e95 100644 --- a/src/wufuc/modulehelper.c +++ b/src/wufuc/modulehelper.c @@ -1,5 +1,6 @@ #include "stdafx.h" #include "modulehelper.h" +#include "log.h" HMODULE mod_get_from_th32_snapshot(HANDLE hSnapshot, const wchar_t *pLibFileName) { @@ -61,7 +62,7 @@ bool mod_inject_and_begin_thread( virt_free: if ( !result && pBaseAddress ) VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE); -resume_process: +resume_process: NtResumeProcess(hProcess); return result; } @@ -148,9 +149,9 @@ bool mod_inject( result = GetExitCodeThread(hThread, (LPDWORD)phRemoteModule) != FALSE; } CloseHandle(hThread); -virt_free: +virt_free: VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE); -resume_process: +resume_process: NtResumeProcess(hProcess); return result; } diff --git a/src/wufuc/mutexhelper.c b/src/wufuc/mutexhelper.c new file mode 100644 index 0000000..6b68b76 --- /dev/null +++ b/src/wufuc/mutexhelper.c @@ -0,0 +1,41 @@ +#include "stdafx.h" +#include "mutexhelper.h" + +#include + +HANDLE mutex_create_new(bool InitialOwner, const wchar_t *MutexName) +{ + HANDLE hMutex; + + hMutex = CreateMutexW(NULL, InitialOwner, MutexName); + if ( hMutex ) { + if ( GetLastError() == ERROR_ALREADY_EXISTS ) { + CloseHandle(hMutex); + return NULL; + } + return hMutex; + } + return NULL; +} + +HANDLE mutex_create_new_fmt(bool InitialOwner, const wchar_t *const NameFormat, ...) +{ + HANDLE result = NULL; + va_list ap; + wchar_t *buffer; + int ret; + + va_start(ap, NameFormat); + ret = _vscwprintf(NameFormat, ap) + 1; + va_end(ap); + buffer = calloc(ret, sizeof *buffer); + if ( buffer ) { + va_start(ap, NameFormat); + ret = vswprintf_s(buffer, ret, NameFormat, ap); + va_end(ap); + if (ret != -1) + result = mutex_create_new(InitialOwner, buffer); + free(buffer); + } + return result; +} diff --git a/src/wufuc/mutexhelper.h b/src/wufuc/mutexhelper.h new file mode 100644 index 0000000..0ca26d4 --- /dev/null +++ b/src/wufuc/mutexhelper.h @@ -0,0 +1,4 @@ +#pragma once + +HANDLE mutex_create_new(bool InitialOwner, const wchar_t *MutexName); +HANDLE mutex_create_new_fmt(bool InitialOwner, const wchar_t *const NameFormat, ...); diff --git a/src/wufuc/ptrlist.c b/src/wufuc/ptrlist.c new file mode 100644 index 0000000..67bfa45 --- /dev/null +++ b/src/wufuc/ptrlist.c @@ -0,0 +1,391 @@ +#include "stdafx.h" +#include "ptrlist.h" + +void ptrlist_lock(ptrlist_t *list) +{ + EnterCriticalSection(&list->criticalSection); +} + +void ptrlist_unlock(ptrlist_t *list) +{ + LeaveCriticalSection(&list->criticalSection); +} + +void *ptrlist_at(ptrlist_t *list, size_t index, uint32_t *pTag) +{ + void *result; + + ptrlist_lock(list); + result = list->values[index]; + if ( pTag ) + *pTag = list->tags[index]; + ptrlist_unlock(list); + return result; +} + +bool ptrlist_create(ptrlist_t *list, size_t capacity, size_t maxCapacity) +{ + bool result = false; + size_t c; + size_t vsize; + size_t tsize; + void *tmp; + + if ( !list || capacity > maxCapacity ) + return result; + + c = capacity ? capacity : + (maxCapacity ? min(maxCapacity, 16) : 16); + vsize = c * (sizeof *list->values); + tsize = c * (sizeof *list->tags); + + InitializeCriticalSection(&list->criticalSection); + ptrlist_lock(list); + + tmp = malloc(vsize + tsize); + if ( tmp ) { + ZeroMemory(tmp, vsize + tsize); + list->values = tmp; + list->tags = (uint32_t *)RtlOffsetToPointer(tmp, vsize); + list->capacity = c; + list->maxCapacity = maxCapacity; + list->count = 0; + result = true; + } + ptrlist_unlock(list); + if ( !result ) + DeleteCriticalSection(&list->criticalSection); + return result; +} + +void ptrlist_destroy(ptrlist_t *list) +{ + if ( !list ) return; + + ptrlist_lock(list); + + free(list->values); + list->values = NULL; + list->tags = NULL; + + list->count = 0; + list->capacity = 0; + list->maxCapacity = 0; + + ptrlist_unlock(list); + DeleteCriticalSection(&list->criticalSection); +} + +size_t ptrlist_index_of(ptrlist_t *list, void *value) +{ + size_t result = -1; + + if ( !list || !value ) + return result; + + ptrlist_lock(list); + for ( size_t i = 0; i < list->count; i++ ) { + if ( list->values[i] == value ) { + result = i; + break; + } + } + ptrlist_unlock(list); + return result; +} + +bool ptrlist_add(ptrlist_t *list, void *value, uint32_t tag) +{ + bool result = false; + size_t newCapacity; + size_t diff; + size_t vsize; + size_t tsize; + void **tmp1; + uint32_t *tmp2; + + if ( !list || !value ) + return result; + + ptrlist_lock(list); + + if ( list->count >= list->capacity ) { + newCapacity = list->count; + if ( list->maxCapacity ) { + diff = list->maxCapacity - list->capacity; + if ( !diff ) + goto leave; + newCapacity += min(diff, 16); + } else { + newCapacity += 16; + } + vsize = newCapacity * (sizeof *list->values); + tsize = newCapacity * (sizeof *list->tags); + + tmp1 = malloc(vsize + tsize); + + if ( !tmp1 ) + goto leave; + + ZeroMemory(tmp1, vsize); + + tmp2 = (uint32_t *)RtlOffsetToPointer(tmp1, vsize); + ZeroMemory(tmp2, tsize); + + if ( memmove_s(tmp1, vsize, list->values, list->count * (sizeof *list->values)) + || memmove_s(tmp2, tsize, list->tags, list->count * (sizeof *list->tags)) ) { + + free(tmp1); + goto leave; + } + list->values = tmp1; + list->tags = tmp2; + list->capacity = newCapacity; + } + list->values[list->count] = value; + list->tags[list->count] = tag; + list->count++; + result = true; +leave: + ptrlist_unlock(list); + return result; +} + +bool ptrlist_add_range(ptrlist_t *list, void **values, uint32_t *tags, size_t count) +{ + bool result = true; + + if ( !list || !values || !count ) + return false; + + ptrlist_lock(list); + if ( list->count + count <= list->maxCapacity ) { + for ( size_t i = 0; result && i < count; i++ ) + result = ptrlist_add(list, values[i], tags ? tags[i] : 0); + } else { + result = false; + } + ptrlist_unlock(list); + return result; +} + +bool ptrlist_remove_at(ptrlist_t *list, size_t index) +{ + bool result = false; + + if ( !list ) return result; + + ptrlist_lock(list); + if ( index <= list->count - 1 ) { + for ( size_t i = index; i < list->count - 1; i++ ) + list->values[i] = list->values[i + 1]; + + list->values[list->count--] = NULL; + result = true; + } + ptrlist_unlock(list); + return result; +} + +bool ptrlist_remove(ptrlist_t *list, void *value) +{ + size_t index; + bool result = false; + + if ( !list || !value ) + return result; + + ptrlist_lock(list); + index = ptrlist_index_of(list, value); + if ( index != -1 ) + result = ptrlist_remove_at(list, index); + ptrlist_unlock(list); + return result; +} + +bool ptrlist_remove_range(ptrlist_t *list, size_t index, size_t count) +{ + bool result = true; + + if ( !list || !count ) + return false; + + ptrlist_lock(list); + if ( index <= list->count - 1 + && index + count <= list->count ) { + + for ( size_t i = 0; result && i < count; i++ ) + result = ptrlist_remove_at(list, index); + } else { + result = false; + } + ptrlist_unlock(list); + return result; +} + +bool ptrlist_clear(ptrlist_t *list) +{ + bool result = false; + + if ( !list ) return result; + + ptrlist_lock(list); + result = ptrlist_remove_range(list, 0, list->count); + ptrlist_unlock(list); + return result; +} + +size_t ptrlist_get_count(ptrlist_t *list) +{ + size_t result = -1; + + if ( !list ) return result; + + ptrlist_lock(list); + result = list->count; + ptrlist_unlock(list); + return result; +} + +size_t ptrlist_get_capacity(ptrlist_t *list) +{ + size_t result = -1; + + if ( !list ) return result; + + ptrlist_lock(list); + result = list->capacity; + ptrlist_unlock(list); + return result; +} + +size_t ptrlist_get_max_capacity(ptrlist_t *list) +{ + size_t result = -1; + + if ( !list ) return result; + + ptrlist_lock(list); + result = list->maxCapacity; + ptrlist_unlock(list); + return result; +} + +bool ptrlist_contains(ptrlist_t *list, void *value) +{ + return ptrlist_index_of(list, value) != -1; +} + +void **ptrlist_copy_values(ptrlist_t *list, size_t *count) +{ + void **result = NULL; + size_t size; + size_t c; + + if ( !list || !count ) + return result; + + ptrlist_lock(list); + c = list->count; + if ( !c ) goto leave; + + size = c * (sizeof *list->values); + result = malloc(c * (sizeof *list->values)); + if ( result ) { + if ( !memcpy_s(result, size, list->values, size) ) { + *count = c; + } else { + free(result); + result = NULL; + } + } +leave: + ptrlist_unlock(list); + return result; +} + +uint32_t *ptrlist_copy_tags(ptrlist_t *list, size_t *count) +{ + uint32_t *result = NULL; + size_t size; + size_t c; + + if ( !list || !count ) + return result; + + ptrlist_lock(list); + c = list->count; + if ( !c ) goto leave; + + size = c * (sizeof *list->tags); + result = malloc(c * (sizeof *list->tags)); + if ( result ) { + if ( !memcpy_s(result, size, list->tags, size) ) { + *count = c; + } else { + free(result); + result = NULL; + } + } +leave: + ptrlist_unlock(list); + return result; +} + +bool ptrlist_copy(ptrlist_t *list, void ***values, uint32_t **tags, size_t *count) +{ + bool result = false; + void **v; + uint32_t *t; + size_t c; + + if ( !values || !tags || !count ) + return result; + + ptrlist_lock(list); + v = ptrlist_copy_values(list, &c); + if ( !v ) goto leave; + + t = ptrlist_copy_tags(list, &c); + if ( !t ) { + free(v); + goto leave; + } + *values = v; + *tags = t; + *count = c; + result = true; +leave: + ptrlist_unlock(list); + return result; +} + +void ptrlist_for_each_stdcall(ptrlist_t *list, void(__stdcall *f)(void *)) +{ + ptrlist_lock(list); + ptrlist_for_stdcall(list, 0, list->count, f); + ptrlist_unlock(list); +} + +void ptrlist_for_stdcall(ptrlist_t *list, size_t index, size_t count, void(__stdcall *f)(void *)) +{ + ptrlist_lock(list); + for ( size_t i = index; i < count; i++ ) + f(list->values[i]); + ptrlist_unlock(list); +} + +void ptrlist_for_each_cdecl(ptrlist_t *list, void(__cdecl *f)(void *)) +{ + ptrlist_lock(list); + ptrlist_for_cdecl(list, 0, list->count, f); + ptrlist_unlock(list); +} + +void ptrlist_for_cdecl(ptrlist_t *list, size_t index, size_t count, void(__cdecl *f)(void *)) +{ + ptrlist_lock(list); + for ( size_t i = index; i < count; i++ ) + f(list->values[i]); + ptrlist_unlock(list); +} diff --git a/src/wufuc/ptrlist.h b/src/wufuc/ptrlist.h new file mode 100644 index 0000000..39f0cc7 --- /dev/null +++ b/src/wufuc/ptrlist.h @@ -0,0 +1,36 @@ +#pragma once + +#pragma pack(push, 1) +typedef struct ptrlist_t_ { + void **values; + uint32_t *tags; + size_t capacity; + size_t maxCapacity; + size_t count; + CRITICAL_SECTION criticalSection; +} ptrlist_t; +#pragma pack(pop) + +void ptrlist_lock(ptrlist_t *list); +void ptrlist_unlock(ptrlist_t *list); +void ptrlist_for_each_stdcall(ptrlist_t *list, void(__stdcall *f)(void *)); +void ptrlist_for_stdcall(ptrlist_t *list, size_t index, size_t count, void(__stdcall *f)(void *)); +void ptrlist_for_each_cdecl(ptrlist_t *list, void(__cdecl *f)(void *)); +void ptrlist_for_cdecl(ptrlist_t *list, size_t index, size_t count, void(__cdecl *f)(void *)); +void *ptrlist_at(ptrlist_t *list, size_t index, uint32_t *pTag); +bool ptrlist_create(ptrlist_t *list, size_t capacity, size_t maxCapacity); +void ptrlist_destroy(ptrlist_t *list); +size_t ptrlist_index_of(ptrlist_t *list, void *value); +bool ptrlist_add(ptrlist_t *list, void *value, uint32_t tag); +bool ptrlist_add_range(ptrlist_t *list, void **values, uint32_t *tags, size_t count); +bool ptrlist_remove_at(ptrlist_t *list, size_t index); +bool ptrlist_remove(ptrlist_t *list, void *value); +bool ptrlist_remove_range(ptrlist_t *list, size_t index, size_t count); +bool ptrlist_clear(ptrlist_t *list); +size_t ptrlist_get_count(ptrlist_t *list); +size_t ptrlist_get_capacity(ptrlist_t *list); +size_t ptrlist_get_max_capacity(ptrlist_t *list); +bool ptrlist_contains(ptrlist_t *list, void *value); +void **ptrlist_copy_values(ptrlist_t *list, size_t *count); +uint32_t *ptrlist_copy_tags(ptrlist_t *list, size_t *count); +bool ptrlist_copy(ptrlist_t *list, void ***values, uint32_t **tags, size_t *count); \ No newline at end of file diff --git a/src/wufuc/rundll32.c b/src/wufuc/rundll32.c index 13496bf..b857e0d 100644 --- a/src/wufuc/rundll32.c +++ b/src/wufuc/rundll32.c @@ -1,15 +1,23 @@ #include "stdafx.h" -#include "context.h" #include "callbacks.h" +#include "eventhelper.h" #include "log.h" #include "modulehelper.h" +#include "mutexhelper.h" +#include "ptrlist.h" #include "registryhelper.h" #include "servicehelper.h" #include "wufuc.h" -void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) +const wchar_t m_szUnloadEventName[] = L"Global\\wufuc_UnloadEvent"; + +void CALLBACK RUNDLL32_StartW(HWND hwnd, + HINSTANCE hinst, + LPWSTR lpszCmdLine, + int nCmdShow) { - context ctx; + ptrlist_t list; + HANDLE hEvent; DWORD dwDesiredAccess; DWORD dwProcessId; bool Unloading = false; @@ -17,21 +25,29 @@ void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, in SC_HANDLE hSCM; SC_HANDLE hService; SERVICE_NOTIFYW NotifyBuffer; - DWORD count; + void **values; + uint32_t *tags; + size_t count; DWORD ret; - HANDLE handle; - DWORD tag; + size_t index; + size_t crashes; - if ( !ctx_create(&ctx, - L"Global\\25020063-b5a7-4227-9fdf-25cb75e8c645", 0, - L"Global\\wufuc_UnloadEvent", L"D:(A;;0x001F0003;;;BA)", 0) ) - return; + if ( !ptrlist_create(&list, 0, MAXIMUM_WAIT_OBJECTS) ) return; + + g_hMainMutex = mutex_create_new(true, + L"Global\\25020063-b5a7-4227-9fdf-25cb75e8c645"); + if ( !g_hMainMutex ) goto destroy_list; + + hEvent = event_create_with_string_security_descriptor( + true, false, m_szUnloadEventName, L"D:(A;;0x001F0003;;;BA)"); + if ( !hEvent ) goto release_mutex; + if ( !ptrlist_add(&list, hEvent, 0) ) goto set_event; dwDesiredAccess = SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG; do { Lagging = false; hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); - if ( !hSCM ) goto delete_ctx; + if ( !hSCM ) goto set_event; hService = OpenServiceW(hSCM, L"wuauserv", dwDesiredAccess); if ( !hService ) goto close_scm; @@ -41,41 +57,59 @@ void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, in dwProcessId = svc_heuristic_process_id(hSCM, hService); if ( dwProcessId ) - wufuc_inject(dwProcessId, (LPTHREAD_START_ROUTINE)cb_start, &ctx); + wufuc_inject(dwProcessId, (LPTHREAD_START_ROUTINE)cb_start, &list); } ZeroMemory(&NotifyBuffer, sizeof NotifyBuffer); NotifyBuffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE; NotifyBuffer.pfnNotifyCallback = (PFN_SC_NOTIFY_CALLBACK)cb_service_notify; - NotifyBuffer.pContext = (PVOID)&ctx; + NotifyBuffer.pContext = (PVOID)&list; while ( !Unloading && !Lagging ) { switch ( NotifyServiceStatusChangeW(hService, SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_RUNNING, &NotifyBuffer) ) { case ERROR_SUCCESS: - count = ctx_wait_any(&ctx, true, &ret, &handle, &tag); - if ( count == -1 ) { - // Wait function failed while making static copy of handles/tags, wtf! + if ( !ptrlist_copy(&list, &values, &tags, &count) ) { Unloading = true; break; - } else if ( ret == WAIT_OBJECT_0 + 1 ) { - trace(L"Unload event was signaled!"); - Unloading = true; - break; - } else if ( (ret >= ERROR_ABANDONED_WAIT_0 || ret < WAIT_ABANDONED_0 + count) ) { - g_ServiceHostCrashCount++; - trace(L"A process that wufuc injected into has crashed %Iu times!!! PID=%lu", - g_ServiceHostCrashCount, tag); + } + ret = WaitForMultipleObjectsEx((DWORD)count, + values, FALSE, INFINITE, TRUE); - ReleaseMutex(handle); // release the abandoned mutex - ctx_close_and_remove_handle(&ctx, handle); - if ( g_ServiceHostCrashCount >= WUFUC_CRASH_THRESHOLD ) { + if ( ret >= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + count ) { + // object signaled + index = ret - WAIT_OBJECT_0; + + if ( index == 0 ) { // Unload event + Unloading = true; + break; + } else { // crash mutex was closed but the process didn't crash + ptrlist_remove(&list, values[index]); + ReleaseMutex(values[index]); + CloseHandle(values[index]); + } + } else if ( ret >= WAIT_ABANDONED_0 && ret < WAIT_ABANDONED_0 + count ) { + // object abandoned + // crash mutex was abandoned, process has most likely crashed. + index = ret - WAIT_ABANDONED_0; + + ptrlist_remove(&list, values[index]); + ReleaseMutex(values[index]); + CloseHandle(values[index]); + + crashes++; + trace(L"A process that wufuc injected into has crashed %Iu time%ls!!! (PID=%lu)", + crashes, crashes != 1 ? L"s" : L"", tags[index]); + + if ( crashes >= SVCHOST_CRASH_THRESHOLD ) { trace(L"Crash threshold has been reached, disabling wufuc until next reboot!"); Unloading = true; } } else if ( ret == WAIT_FAILED ) { - trace(L"Wait failed! GLE=%lu", GetLastError()); + trace(L"WTF - Unexpected result from wait function!!!"); Unloading = true; } + free(values); + free(tags); break; case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING: trace(L"Client lagging!"); @@ -90,15 +124,25 @@ void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, in close_scm: CloseServiceHandle(hSCM); } while ( Lagging ); -delete_ctx: - ctx_delete(&ctx); +set_event: + // signal event in case it is open in any other processes + SetEvent(hEvent); +release_mutex: + ReleaseMutex(g_hMainMutex); +destroy_list: + ptrlist_for_each_stdcall(&list, CloseHandle); + ptrlist_destroy(&list); } -void CALLBACK RUNDLL32_UnloadW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) +void CALLBACK RUNDLL32_UnloadW( + HWND hwnd, + HINSTANCE hinst, + LPWSTR lpszCmdLine, + int nCmdShow) { HANDLE hEvent; - hEvent = OpenEventW(EVENT_MODIFY_STATE, FALSE, L"Global\\wufuc_UnloadEvent"); + hEvent = OpenEventW(EVENT_MODIFY_STATE, FALSE, m_szUnloadEventName); if ( hEvent ) { SetEvent(hEvent); CloseHandle(hEvent); diff --git a/src/wufuc/wufuc.c b/src/wufuc/wufuc.c index 3f0f952..c194d9c 100644 --- a/src/wufuc/wufuc.c +++ b/src/wufuc/wufuc.c @@ -1,38 +1,97 @@ #include "stdafx.h" -#include "context.h" +#include "ptrlist.h" #include "wufuc.h" #include "hooks.h" #include "log.h" #include "modulehelper.h" +#include "mutexhelper.h" #include "patternfind.h" #include "versionhelper.h" #include -size_t g_ServiceHostCrashCount; +HANDLE g_hMainMutex; -bool wufuc_inject(DWORD dwProcessId, - LPTHREAD_START_ROUTINE pfnStart, - context *pContext) +bool close_remote_handle(HANDLE hProcess, HANDLE hObject) { bool result = false; - HANDLE hProcess; - HANDLE hMutex; - context ctx; + DWORD ExitCode; + HANDLE hThread; - if ( !ctx_add_new_mutex_fmt(pContext, - false, - dwProcessId, - &hMutex, - L"Global\\%08x-7132-44a8-be15-56698979d2f3", dwProcessId) ) - return false; + hThread = CreateRemoteThread(hProcess, + NULL, + 0, + (LPTHREAD_START_ROUTINE)CloseHandle, + (LPVOID)hObject, + 0, + NULL); + if ( hThread ) { + if ( WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0 + && GetExitCodeThread(hThread, &ExitCode) ) { + + result = !!ExitCode; + } + CloseHandle(hThread); + } + return result; +} + +bool wufuc_inject(DWORD dwProcessId, + LPTHREAD_START_ROUTINE pStartAddress, + ptrlist_t *list) +{ + bool result = false; + HANDLE hCrashMutex; + HANDLE hProcess; + HANDLE h; + HANDLE hProceedEvent; + HANDLE p[4]; + + hCrashMutex = mutex_create_new_fmt(false, L"Global\\wufuc_CrashMutex*%08x", dwProcessId); + if ( !hCrashMutex ) return result; + if ( !ptrlist_add(list, hCrashMutex, dwProcessId) ) + goto close_mutex; + + hProceedEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + if ( !hProceedEvent ) goto close_mutex; hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); - if ( !hProcess ) return false; + if ( !hProcess ) goto close_pevent; - result = ctx_duplicate_context(pContext, hProcess, &ctx, hMutex, DUPLICATE_SAME_ACCESS, dwProcessId) - && mod_inject_and_begin_thread(hProcess, PIMAGEBASE, pfnStart, &ctx, sizeof ctx); + h = GetCurrentProcess(); + if ( !DuplicateHandle(h, g_hMainMutex, hProcess, &p[0], SYNCHRONIZE, FALSE, 0) ) + goto close_process; + if ( !DuplicateHandle(h, ptrlist_at(list, 0, NULL), hProcess, &p[1], SYNCHRONIZE, FALSE, 0) ) + goto close_p0; + if ( !DuplicateHandle(h, hCrashMutex, hProcess, &p[2], 0, FALSE, DUPLICATE_SAME_ACCESS) ) + goto close_p1; + if ( !DuplicateHandle(h, hProceedEvent, hProcess, &p[3], EVENT_MODIFY_STATE, FALSE, 0) ) + goto close_p2; + + result = mod_inject_and_begin_thread(hProcess, PIMAGEBASE, pStartAddress, p, sizeof p); + + if ( result ) { + // wait for injected thread to signal that it has taken + // ownership of hCrashMutex before proceeding. + result = WaitForSingleObject(hProceedEvent, 5000) != WAIT_TIMEOUT; + } else { + close_remote_handle(hProcess, p[3]); +close_p2: + close_remote_handle(hProcess, p[2]); +close_p1: + close_remote_handle(hProcess, p[1]); +close_p0: + close_remote_handle(hProcess, p[0]); + } +close_process: CloseHandle(hProcess); +close_pevent: + CloseHandle(hProceedEvent); + if ( !result ) { +close_mutex: + ptrlist_remove(list, hCrashMutex); + CloseHandle(hCrashMutex); + } return result; } @@ -50,6 +109,7 @@ bool wufuc_hook(HMODULE hModule) VS_FIXEDFILEINFO *pffi; MODULEINFO modinfo; size_t offset; + LPVOID pTarget; if ( !ver_verify_windows_7_sp1() && !ver_verify_windows_8_1() ) return false; @@ -85,11 +145,11 @@ bool wufuc_hook(HMODULE hModule) trace(L"Failed to allocate version information from hmodule."); break; } - trace(L"Windows Update Agent version: %hu.%hu.%hu.%hu"), + trace(L"Windows Update Agent version: %hu.%hu.%hu.%hu", HIWORD(pffi->dwProductVersionMS), LOWORD(pffi->dwProductVersionMS), HIWORD(pffi->dwProductVersionLS), - LOWORD(pffi->dwProductVersionLS); + LOWORD(pffi->dwProductVersionLS)); // assure wuaueng.dll is at least the minimum supported version tmp = ((ver_verify_windows_7_sp1() && ver_compare_product_version(pffi, 7, 6, 7601, 23714) != -1) @@ -113,10 +173,9 @@ bool wufuc_hook(HMODULE hModule) #endif ); if ( offset != -1 ) { - result = MH_CreateHook( - RtlOffsetToPointer(modinfo.lpBaseOfDll, offset), - IsDeviceServiceable_hook, - NULL) == MH_OK; + pTarget = (LPVOID)RtlOffsetToPointer(modinfo.lpBaseOfDll, offset); + MH_CreateHook(pTarget, IsDeviceServiceable_hook, NULL); + result = (MH_EnableHook(pTarget) == MH_OK); } else { trace(L"Could not locate pattern offset!"); } diff --git a/src/wufuc/wufuc.h b/src/wufuc/wufuc.h index 88cd5f6..3a4c91b 100644 --- a/src/wufuc/wufuc.h +++ b/src/wufuc/wufuc.h @@ -6,11 +6,11 @@ typedef struct WORD wCodePage; } LANGANDCODEPAGE, *PLANGANDCODEPAGE; -#define WUFUC_CRASH_THRESHOLD 3 +#define SVCHOST_CRASH_THRESHOLD 3 -extern size_t g_ServiceHostCrashCount; +extern HANDLE g_hMainMutex; bool wufuc_inject(DWORD dwProcessId, - LPTHREAD_START_ROUTINE pfnStart, - context *pContext); + LPTHREAD_START_ROUTINE pStartAddress, + ptrlist_t *list); bool wufuc_hook(HMODULE hModule); \ No newline at end of file diff --git a/src/wufuc/wufuc.vcxproj b/src/wufuc/wufuc.vcxproj index fcc3c9f..dce5bff 100644 --- a/src/wufuc/wufuc.vcxproj +++ b/src/wufuc/wufuc.vcxproj @@ -20,7 +20,9 @@ - + + + @@ -34,11 +36,13 @@ - + + + diff --git a/src/wufuc/wufuc.vcxproj.filters b/src/wufuc/wufuc.vcxproj.filters index 1c95330..36bb57c 100644 --- a/src/wufuc/wufuc.vcxproj.filters +++ b/src/wufuc/wufuc.vcxproj.filters @@ -30,9 +30,6 @@ Header Files - - Header Files - Header Files @@ -51,6 +48,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + @@ -71,9 +77,6 @@ Source Files - - Source Files - Source Files @@ -92,6 +95,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files +