push progress...
This commit is contained in:
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
@@ -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);
|
@@ -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
23
src/wufuc/eventhelper.c
Normal 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
7
src/wufuc/eventhelper.h
Normal 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);
|
@@ -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;
|
||||
|
269
src/wufuc/log.c
269
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 <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));
|
||||
//}
|
||||
|
@@ -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
|
||||
|
@@ -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
41
src/wufuc/mutexhelper.c
Normal 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
4
src/wufuc/mutexhelper.h
Normal 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
391
src/wufuc/ptrlist.c
Normal 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
36
src/wufuc/ptrlist.h
Normal 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);
|
@@ -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);
|
||||
|
@@ -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!");
|
||||
}
|
||||
|
@@ -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);
|
@@ -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" />
|
||||
|
@@ -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">
|
||||
|
Reference in New Issue
Block a user