push progress...

This commit is contained in:
zeffy
2018-03-08 01:50:37 -08:00
parent ca3b98e454
commit bf47ab665c
20 changed files with 740 additions and 840 deletions

View File

@@ -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 <minhook.h>
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);

View File

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

View File

@@ -1,404 +0,0 @@
#include "stdafx.h"
#include "context.h"
#include <sddl.h>
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;
}

View File

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

View File

@@ -1,4 +1,5 @@
#include "stdafx.h"
#include "log.h"
#include <minhook.h>
@@ -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;

23
src/wufuc/eventhelper.c Normal file
View File

@@ -0,0 +1,23 @@
#include "stdafx.h"
#include "eventhelper.h"
#include <sddl.h>
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;
}

7
src/wufuc/eventhelper.h Normal file
View File

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

View File

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

View File

@@ -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 <Shlobj.h>
//
//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));
//}

View File

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

View File

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

41
src/wufuc/mutexhelper.c Normal file
View File

@@ -0,0 +1,41 @@
#include "stdafx.h"
#include "mutexhelper.h"
#include <sddl.h>
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;
}

4
src/wufuc/mutexhelper.h Normal file
View File

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

391
src/wufuc/ptrlist.c Normal file
View File

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

36
src/wufuc/ptrlist.h Normal file
View File

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

View File

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

View File

@@ -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 <minhook.h>
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!");
}

View File

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

View File

@@ -20,7 +20,9 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="callbacks.h" />
<ClInclude Include="context.h" />
<ClInclude Include="eventhelper.h" />
<ClInclude Include="mutexhelper.h" />
<ClInclude Include="ptrlist.h" />
<ClInclude Include="log.h" />
<ClInclude Include="modulehelper.h" />
<ClInclude Include="registryhelper.h" />
@@ -34,11 +36,13 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="callbacks.c" />
<ClCompile Include="context.c" />
<ClCompile Include="dllmain.c" />
<ClCompile Include="eventhelper.c" />
<ClCompile Include="ptrlist.c" />
<ClCompile Include="modulehelper.c" />
<ClCompile Include="registryhelper.c" />
<ClCompile Include="servicehelper.c" />
<ClCompile Include="mutexhelper.c" />
<ClCompile Include="versionhelper.c" />
<ClCompile Include="hooks.c" />
<ClCompile Include="log.c" />

View File

@@ -30,9 +30,6 @@
<ClInclude Include="patternfind.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="context.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="versionhelper.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -51,6 +48,15 @@
<ClInclude Include="log.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ptrlist.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="eventhelper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mutexhelper.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="callbacks.c">
@@ -71,9 +77,6 @@
<ClCompile Include="patternfind.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="context.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="servicehelper.c">
<Filter>Source Files</Filter>
</ClCompile>
@@ -92,6 +95,15 @@
<ClCompile Include="modulehelper.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ptrlist.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mutexhelper.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="eventhelper.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="wufuc.rc">