migrate to minhook and begin adding crash loop prevention

This commit is contained in:
zeffy
2018-03-01 14:49:11 -08:00
parent d2b0bae9e5
commit 6f2b140060
37 changed files with 1562 additions and 1045 deletions

View File

@@ -1,52 +1,36 @@
#include "stdafx.h"
#include "callbacks.h"
#include "hlpmem.h"
#include "hlpmisc.h"
#include "hlpsvc.h"
#include "hooks.h"
VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer)
#include "context.h"
#include "callbacks.h"
#include "hooks.h"
#include "log.h"
#include "modulehelper.h"
#include "registryhelper.h"
#include "servicehelper.h"
#include "wufuc.h"
#include <minhook.h>
VOID CALLBACK cb_service_notify(PSERVICE_NOTIFYW pNotifyBuffer)
{
switch ( pNotifyBuffer->dwNotificationStatus ) {
case ERROR_SUCCESS:
if ( pNotifyBuffer->ServiceStatus.dwProcessId )
wufuc_InjectLibrary(
wufuc_inject(
pNotifyBuffer->ServiceStatus.dwProcessId,
(ContextHandles *)pNotifyBuffer->pContext);
(LPTHREAD_START_ROUTINE)cb_start,
(context *)pNotifyBuffer->pContext);
break;
case ERROR_SERVICE_MARKED_FOR_DELETE:
SetEvent(((ContextHandles *)pNotifyBuffer->pContext)->hUnloadEvent);
SetEvent(((context *)pNotifyBuffer->pContext)->uevent);
break;
}
if ( pNotifyBuffer->pszServiceNames )
LocalFree((HLOCAL)pNotifyBuffer->pszServiceNames);
}
DWORD WINAPI PipeLoopThreadCallback(LPVOID pParam)
DWORD WINAPI cb_start(context *ctx)
{
HANDLE hPipe = (HANDLE)pParam;
BOOL fSuccess;
wchar_t chBuf[512];
while (true) {
// Read from the pipe.
fSuccess = ReadFile(
hPipe, // pipe handle
chBuf, // buffer to receive reply
BUFSIZE * sizeof(wchar_t), // size of buffer
&cbRead, // number of bytes read
NULL); // not overlapped
if ( !fSuccess && GetLastError() != ERROR_MORE_DATA )
break;;
_tprintf(TEXT("\"%s\"\n"), chBuf);
}
}
DWORD WINAPI StartThreadCallback(LPVOID pParam)
{
ContextHandles ctx;
SC_HANDLE hSCM;
SC_HANDLE hService;
DWORD dwProcessId;
@@ -54,22 +38,17 @@ DWORD WINAPI StartThreadCallback(LPVOID pParam)
DWORD dwServiceType;
wchar_t *str;
HMODULE hModule;
wchar_t Filename[MAX_PATH];
DWORD result;
// get mutex and unload event handles from virtual memory
if ( !pParam ) {
if ( !ctx ) {
trace(L"Context parameter is null!");
goto unload;
}
ctx = *(ContextHandles *)pParam;
if ( !VirtualFree(pParam, 0, MEM_RELEASE) )
trace(L"Failed to free context parameter. (%p, GetLastError=%lu)",
pParam, GetLastError());
// acquire child mutex, should be immediate.
if ( WaitForSingleObject(ctx.hChildMutex, 5000) != WAIT_OBJECT_0 ) {
trace(L"Failed to acquire child mutex within five seconds. (%p)", ctx.hChildMutex);
// 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]);
goto close_handles;
}
@@ -79,112 +58,78 @@ DWORD WINAPI StartThreadCallback(LPVOID pParam)
goto release;
}
hService = OpenServiceW(hSCM, L"wuauserv", SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
dwProcessId = HeuristicServiceProcessId(hSCM, hService);
pServiceConfig = QueryServiceConfigAlloc(hSCM, hService, NULL);
hService = OpenServiceW(hSCM, L"wuauserv",
SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
dwProcessId = svc_heuristic_process_id(hSCM, hService);
pServiceConfig = svc_query_config_alloc(hSCM, hService, NULL);
dwServiceType = pServiceConfig->dwServiceType;
free(pServiceConfig);
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
if ( dwProcessId != GetCurrentProcessId() ) {
trace(L"Injected into wrong process!", GetCurrentProcessId(), dwProcessId);
trace(L"Injected into wrong process!");
goto release;
}
trace(L"Installing hooks...");
if ( dwServiceType == SERVICE_WIN32_SHARE_PROCESS ) {
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
// assume wuaueng.dll hasn't been loaded yet, apply
// RegQueryValueExW hook to fix incompatibility with
// UpdatePack7R2 and other patches that work by
// modifying the Windows Update ServiceDll path in the
// registry.
g_pfnRegQueryValueExW = DetourFindFunction("kernel32.dll", "RegQueryValueExW");
if ( g_pfnRegQueryValueExW )
DetourAttach(&(PVOID)g_pfnRegQueryValueExW, RegQueryValueExW_hook);
DetourTransactionCommit();
// UpdatePack7R2 and other patches that modify the
// Windows Update ServiceDll path in the registry.
MH_CreateHookApi(L"kernel32.dll",
"RegQueryValueExW",
RegQueryValueExW_hook,
&(PVOID)g_pfnRegQueryValueExW);
MH_EnableHook(g_pfnRegQueryValueExW);
}
// query the ServiceDll path after applying our compat hook so that it
// is correct
str = (wchar_t *)RegQueryValueExAlloc(HKEY_LOCAL_MACHINE,
str = (wchar_t *)reg_query_value_alloc(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\services\\wuauserv\\Parameters",
L"ServiceDll", NULL, NULL);
g_pszWUServiceDll = ExpandEnvironmentStringsAlloc(str, NULL);
g_pszWUServiceDll = env_expand_strings_alloc(str, NULL);
free(str);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
MH_CreateHookApi(L"kernel32.dll",
"LoadLibraryExW",
LoadLibraryExW_hook,
&(PVOID)g_pfnLoadLibraryExW);
g_pfnLoadLibraryExW = DetourFindFunction("kernel32.dll", "LoadLibraryExW");
if ( g_pfnLoadLibraryExW )
DetourAttach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook);
if ( g_pszWUServiceDll
&& (GetModuleHandleExW(0, g_pszWUServiceDll, &hModule)
|| GetModuleHandleExW(0, PathFindFileNameW(g_pszWUServiceDll), &hModule))) {
if ( g_pszWUServiceDll ) {
if ( GetModuleHandleExW(0, g_pszWUServiceDll, &hModule) ) {
if ( FindIDSFunctionAddress(hModule, &(PVOID)g_pfnIsDeviceServiceable) ) {
trace(L"Matched pattern for %ls!IsDeviceServiceable. (%p)",
PathFindFileNameW(g_pszWUServiceDll),
g_pfnIsDeviceServiceable);
DetourAttach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook);
} else {
trace(L"No pattern matched!");
}
FreeLibrary(hModule);
}
// hook IsDeviceServiceable if wuaueng.dll is already loaded
wufuc_hook(hModule);
FreeLibrary(hModule);
}
DetourTransactionCommit();
MH_EnableHook(MH_ALL_HOOKS);
// wait for unload event or parent mutex to be abandoned.
// for example if the user killed rundll32.exe with task manager.
// intentionally leave parent mutex open until this thread ends, at
// which point it becomes abandoned again.
result = WaitForMultipleObjects(_countof(ctx.handles), ctx.handles, FALSE, INFINITE);
result = WaitForMultipleObjects(_countof(ctx->handles), ctx->handles, FALSE, INFINITE);
trace(L"Unload condition has been met.");
// unhook
if ( g_pfnLoadLibraryExW || g_pfnIsDeviceServiceable || g_pfnRegQueryValueExW ) {
trace(L"Removing hooks...");
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
if ( g_pfnLoadLibraryExW )
DetourDetach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook);
// check to see if the last known address of IsDeviceServiceable
// is still in the address space of wuaueng.dll before
// attempting to unhook the function.
if ( g_pfnIsDeviceServiceable
&& GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(LPWSTR)g_pfnIsDeviceServiceableLastKnown, &hModule) ) {
if ( GetModuleFileNameW(hModule, Filename, _countof(Filename))
&& (!_wcsicmp(Filename, g_pszWUServiceDll)
|| !_wcsicmp(Filename, PathFindFileNameW(g_pszWUServiceDll))) )
DetourDetach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook);
FreeLibrary(hModule);
}
if ( g_pfnRegQueryValueExW )
DetourDetach(&(PVOID)g_pfnRegQueryValueExW, RegQueryValueExW_hook);
DetourTransactionCommit();
switch ( result ) {
case ERROR_ABANDONED_WAIT_0:
ReleaseMutex(ctx->mutex);
break;
}
free(g_pszWUServiceDll);
MH_DisableHook(MH_ALL_HOOKS);
free(g_pszWUServiceDll);
release:
ReleaseMutex(ctx.hChildMutex);
ReleaseMutex(ctx->handles[ctx->mutex_tag]);
close_handles:
CloseHandle(ctx.hChildMutex);
CloseHandle(ctx.hUnloadEvent);
CloseHandle(ctx.hParentMutex);
if ( g_hTracingMutex )
CloseHandle(g_hTracingMutex);
CloseHandle(ctx->handles[ctx->mutex_tag]);
CloseHandle(ctx->mutex);
CloseHandle(ctx->uevent);
VirtualFree(ctx, 0, MEM_RELEASE);
unload:
trace(L"Freeing library and exiting main thread.");
trace(L"Freeing library and exiting thread.");
FreeLibraryAndExitThread(PIMAGEBASE, 0);
}

View File

@@ -1,4 +1,4 @@
#pragma once
VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer);
DWORD WINAPI ThreadStartCallback(LPVOID pParam);
VOID CALLBACK cb_service_notify(PSERVICE_NOTIFYW pNotifyBuffer);
DWORD WINAPI cb_start(context *ctx);

337
src/wufuc/context.c Normal file
View File

@@ -0,0 +1,337 @@
#include "stdafx.h"
#include "context.h"
#include <sddl.h>
static bool ctxp_remove_handle(context *ctx, unsigned Index)
{
if ( !ctx || Index > _countof(ctx->handles) || Index > ctx->count )
return false;
EnterCriticalSection(&ctx->cs);
for ( unsigned 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 unsigned ctxp_find_handle_index(context *ctx, HANDLE Handle)
{
unsigned result = -1;
if ( !ctx || !Handle || Handle == INVALID_HANDLE_VALUE )
return -1;
EnterCriticalSection(&ctx->cs);
for ( unsigned 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,
unsigned MutexTag,
const wchar_t *EventName,
const wchar_t *EventStringSecurityDescriptor,
unsigned 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;
}
unsigned ctx_add_handle(context *ctx, HANDLE Handle, unsigned Tag)
{
unsigned 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, unsigned *pTag)
{
bool result = false;
unsigned 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;
}
unsigned ctx_add_new_mutex(context *ctx,
bool InitialOwner,
const wchar_t *Name,
unsigned Tag,
HANDLE *pMutexHandle)
{
HANDLE hMutex;
unsigned 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;
}
unsigned ctx_add_new_mutex_fmt(context *ctx,
bool InitialOwner,
unsigned Tag,
HANDLE *pMutexHandle,
const wchar_t *const NameFormat,
...)
{
HANDLE hMutex;
unsigned 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;
}
unsigned ctx_add_event(context *ctx,
const wchar_t *Name,
const wchar_t *StringSecurityDescriptor,
unsigned Tag,
HANDLE *pEventHandle)
{
unsigned 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;
}
bool ctx_wait(context *ctx, bool WaitAll, bool Alertable, DWORD *pResult)
{
int ret;
unsigned 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 ) {
*pResult = WaitForMultipleObjectsEx(count,
handles,
WaitAll,
INFINITE,
Alertable);
return true;
}
return false;
}
bool ctx_close_and_remove_handle(context *ctx,
HANDLE Handle)
{
bool result = false;
unsigned 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,
unsigned Tag)
{
bool result = false;
HANDLE hSrcProcess;
HANDLE hTarget;
size_t index;
hSrcProcess = GetCurrentProcess();
if ( !DuplicateHandle(hSrcProcess, pSrc->mutex, hProcess, &pDst->mutex, SYNCHRONIZE, FALSE, 0) )
return false;
if ( !DuplicateHandle(hSrcProcess, pSrc->uevent, hProcess, &pDst->uevent, SYNCHRONIZE, FALSE, 0) ) {
close_mutex:
CloseHandle(pDst->mutex);
pDst->mutex = INVALID_HANDLE_VALUE;
return false;
}
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->tags[0] = index;
return true;
}

71
src/wufuc/context.h Normal file
View File

@@ -0,0 +1,71 @@
#pragma once
#pragma pack(push, 1)
typedef struct
{
CRITICAL_SECTION cs;
unsigned count;
union
{
struct
{
HANDLE mutex;
HANDLE uevent;
};
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
};
union
{
struct
{
unsigned mutex_tag;
unsigned uevent_tag;
};
unsigned tags[MAXIMUM_WAIT_OBJECTS];
};
} context;
#pragma pack(pop)
bool ctx_create(context *ctx,
const wchar_t *MutexName,
unsigned MutexTag,
const wchar_t *EventName,
const wchar_t *EventStringSecurityDescriptor,
unsigned EventTag);
bool ctx_delete(context *ctx);
unsigned ctx_add_handle(context *ctx, HANDLE Handle, unsigned Tag);
bool ctx_get_tag(context *ctx, HANDLE Handle, unsigned *pTag);
unsigned ctx_add_new_mutex(context *ctx,
bool InitialOwner,
const wchar_t *Name,
unsigned Tag,
HANDLE *pMutexHandle);
unsigned ctx_add_new_mutex_fmt(context *ctx,
bool InitialOwner,
unsigned Tag,
HANDLE *pMutexHandle,
const wchar_t *const NameFormat,
...);
unsigned ctx_add_event(context *ctx,
const wchar_t *Name,
const wchar_t *StringSecurityDescriptor,
unsigned Tag,
HANDLE *pEventHandle);
bool ctx_wait(context *ctx, bool WaitAll, bool Alertable, DWORD *pResult);
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,
unsigned Tag);

View File

@@ -1,4 +1,5 @@
#include "stdafx.h"
#include <minhook.h>
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
@@ -6,9 +7,12 @@ BOOL APIENTRY DllMain(HMODULE hModule,
{
switch ( ul_reason_for_call ) {
case DLL_PROCESS_ATTACH:
MH_Initialize();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
MH_Uninitialize();
break;
}
return TRUE;

View File

@@ -1,291 +0,0 @@
#include "stdafx.h"
#include "callbacks.h"
#include "hlpmem.h"
#include "hlpmisc.h"
#include "hlpver.h"
#include "hooks.h"
bool FindIDSFunctionAddress(HMODULE hModule, PVOID *ppfnIsDeviceServiceable)
{
bool result = false;
bool is_win7 = false;
bool is_win81 = false;
PLANGANDCODEPAGE ptl;
HANDLE hProcess;
int tmp;
UINT cbtl;
wchar_t SubBlock[38];
UINT cbInternalName;
wchar_t *pInternalName;
UINT cbffi;
VS_FIXEDFILEINFO *pffi;
MODULEINFO modinfo;
size_t offset;
if ( !((is_win7 = IsWindowsVersion(6, 1, 1))
|| (is_win81 = IsWindowsVersion(6, 3, 0))) ) {
trace(L"Unsupported operating system.");
return result;
}
ptl = GetVersionInfoFromHModuleAlloc(hModule, L"\\VarFileInfo\\Translation", &cbtl);
if ( !ptl ) {
trace(L"Failed to allocate version translation information from hmodule.");
return result;
}
hProcess = GetCurrentProcess();
for ( size_t i = 0, count = (cbtl / sizeof *ptl); i < count; i++ ) {
if ( swprintf_s(SubBlock,
_countof(SubBlock),
L"\\StringFileInfo\\%04x%04x\\InternalName",
ptl[i].wLanguage,
ptl[i].wCodePage) == -1 )
continue;
pInternalName = GetVersionInfoFromHModuleAlloc(hModule, SubBlock, &cbInternalName);
if ( !pInternalName ) {
trace(L"Failed to allocate version internal name from hmodule.");
continue;
}
// identify wuaueng.dll by its resource data
tmp = _wcsicmp(pInternalName, L"wuaueng.dll");
if ( tmp )
trace(L"Module internal name does not match. (%ls)", pInternalName);
free(pInternalName);
if ( tmp )
continue;
pffi = GetVersionInfoFromHModuleAlloc(hModule, L"\\", &cbffi);
if ( !pffi ) {
trace(L"Failed to allocate version information from hmodule.");
break;
}
trace(L"Windows Update Agent version: %hu.%hu.%hu.%hu",
HIWORD(pffi->dwProductVersionMS),
LOWORD(pffi->dwProductVersionMS),
HIWORD(pffi->dwProductVersionLS),
LOWORD(pffi->dwProductVersionLS));
// assure wuaueng.dll is at least the minimum supported version
tmp = ((is_win7 && ProductVersionCompare(pffi, 7, 6, 7601, 23714) != -1)
|| (is_win81 && ProductVersionCompare(pffi, 7, 9, 9600, 18621) != -1));
free(pffi);
if ( !tmp ) {
trace(L"Windows Update Agent does not meet the minimum supported version.");
break;
}
if ( !GetModuleInformation(hProcess, hModule, &modinfo, sizeof modinfo) )
break;
offset = patternfind(modinfo.lpBaseOfDll, modinfo.SizeOfImage,
#ifdef _WIN64
"FFF3 4883EC?? 33DB 391D???????? 7508 8B05????????"
#else
is_win7
? "833D????????00 743E E8???????? A3????????"
: "8BFF 51 833D????????00 7507 A1????????"
#endif
);
if ( offset != -1 ) {
g_pfnIsDeviceServiceableLastKnown = (PVOID)((uint8_t *)modinfo.lpBaseOfDll + offset);
*ppfnIsDeviceServiceable = g_pfnIsDeviceServiceableLastKnown;
result = true;
}
break;
}
free(ptl);
return result;
}
HANDLE GetRemoteHModuleFromTh32ModuleSnapshot(HANDLE hSnapshot, const wchar_t *pLibFileName)
{
MODULEENTRY32W me = { sizeof me };
if ( !Module32FirstW(hSnapshot, &me) )
return NULL;
do {
if ( !_wcsicmp(me.szExePath, pLibFileName) )
return me.hModule;
} while ( Module32NextW(hSnapshot, &me) );
return NULL;
}
bool InjectLibraryAndCreateRemoteThread(
HANDLE hProcess,
HMODULE hModule,
LPTHREAD_START_ROUTINE pStartAddress,
const void *pParam,
size_t cbParam)
{
bool result = false;
NTSTATUS Status;
LPVOID pBaseAddress = NULL;
SIZE_T cb;
HMODULE hRemoteModule = NULL;
HANDLE hThread;
Status = NtSuspendProcess(hProcess);
if ( !NT_SUCCESS(Status) ) return result;
if ( pParam ) {
// this will be VirtualFree()'d by the function at pStartAddress
pBaseAddress = VirtualAllocEx(hProcess,
NULL,
cbParam,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
if ( !pBaseAddress ) goto resume;
if ( !WriteProcessMemory(hProcess, pBaseAddress, pParam, cbParam, &cb) )
goto vfree;
}
if ( InjectLibrary(hProcess, hModule, &hRemoteModule) ) {
hThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)((uint8_t *)hRemoteModule + ((uint8_t *)pStartAddress - (uint8_t *)hModule)),
pBaseAddress,
0,
NULL);
if ( hThread ) {
CloseHandle(hThread);
result = true;
}
}
vfree:
if ( !result && pBaseAddress )
VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE);
resume: NtResumeProcess(hProcess);
return result;
}
bool InjectLibrary(HANDLE hProcess, HMODULE hModule, HMODULE *phRemoteModule)
{
WCHAR Filename[MAX_PATH];
DWORD nLength;
nLength = GetModuleFileNameW(hModule, Filename, _countof(Filename));
if ( nLength ) {
return InjectLibraryByFilename(hProcess,
Filename,
nLength,
phRemoteModule);
}
return false;
}
bool InjectLibraryByFilename(
HANDLE hProcess,
const wchar_t *pLibFilename,
size_t cchLibFilename,
HMODULE *phRemoteModule)
{
bool result = false;
DWORD dwProcessId;
NTSTATUS Status;
HANDLE hSnapshot;
SIZE_T nSize;
LPVOID pBaseAddress;
HANDLE hThread;
Status = NtSuspendProcess(hProcess);
if ( !NT_SUCCESS(Status) ) return result;
dwProcessId = GetProcessId(hProcess);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
if ( !hSnapshot ) goto resume;
*phRemoteModule = GetRemoteHModuleFromTh32ModuleSnapshot(hSnapshot,
pLibFilename);
CloseHandle(hSnapshot);
// already injected... still sets *phRemoteModule
if ( *phRemoteModule ) goto resume;
nSize = (cchLibFilename + 1) * sizeof *pLibFilename;
pBaseAddress = VirtualAllocEx(hProcess,
NULL,
nSize,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
if ( !pBaseAddress ) goto resume;
if ( !WriteProcessMemory(hProcess, pBaseAddress, pLibFilename, nSize, NULL) )
goto vfree;
hThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)LoadLibraryW,
pBaseAddress,
0,
NULL);
if ( !hThread ) goto vfree;
WaitForSingleObject(hThread, INFINITE);
if ( sizeof *phRemoteModule > sizeof(DWORD) ) {
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
if ( hSnapshot ) {
*phRemoteModule = GetRemoteHModuleFromTh32ModuleSnapshot(
hSnapshot,
pLibFilename);
CloseHandle(hSnapshot);
result = *phRemoteModule != NULL;
}
} else {
result = GetExitCodeThread(hThread, (LPDWORD)phRemoteModule) != FALSE;
}
CloseHandle(hThread);
vfree: VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE);
resume: NtResumeProcess(hProcess);
return result;
}
bool wufuc_InjectLibrary(DWORD dwProcessId, ContextHandles *pContext)
{
bool result = false;
HANDLE hProcess;
wchar_t MutexName[44];
HANDLE hChildMutex;
HANDLE hSrcProcess;
ContextHandles param = { 0 };
if ( swprintf_s(MutexName, _countof(MutexName),
L"Global\\%08x-7132-44a8-be15-56698979d2f3", dwProcessId) == -1 ) {
trace(L"Failed to print mutex name to string! (%lu)", dwProcessId);
return result;
}
if ( !InitializeMutex(false, MutexName, &hChildMutex) ) {
return result;
}
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if ( !hProcess ) {
trace(L"Failed to open target process! (GetLastError=%lu)", GetLastError());
goto close_mutex;
};
hSrcProcess = GetCurrentProcess();
if ( DuplicateHandle(hSrcProcess, pContext->hParentMutex, hProcess, &param.hParentMutex, SYNCHRONIZE, FALSE, 0)
&& DuplicateHandle(hSrcProcess, pContext->hUnloadEvent, hProcess, &param.hUnloadEvent, SYNCHRONIZE, FALSE, 0)
&& DuplicateHandle(hSrcProcess, hChildMutex, hProcess, &param.hChildMutex, 0, FALSE, DUPLICATE_SAME_ACCESS) ) {
if ( InjectLibraryAndCreateRemoteThread(hProcess, PIMAGEBASE, ThreadStartCallback, &param, sizeof param) )
trace(L"Injected into process. (%lu)", dwProcessId);
} else {
trace(L"Failed to duplicate context handles! (GetLastError=%lu", GetLastError());
}
CloseHandle(hProcess);
close_mutex:
CloseHandle(hChildMutex);
return result;
}

View File

@@ -1,44 +0,0 @@
#pragma once
#pragma pack(push, 1)
typedef struct
{
HANDLE hChildMutex;
union
{
struct
{
HANDLE hParentMutex;
HANDLE hUnloadEvent;
} DUMMYSTRUCTNAME;
struct
{
HANDLE hMainMutex;
HANDLE hUnloadEvent;
} u;
HANDLE handles[2];
};
} ContextHandles;
#pragma pack(pop)
typedef struct
{
WORD wLanguage;
WORD wCodePage;
} LANGANDCODEPAGE, *PLANGANDCODEPAGE;
bool FindIDSFunctionAddress(HMODULE hModule, PVOID *ppfnIsDeviceServiceable);
HANDLE GetRemoteHModuleFromTh32ModuleSnapshot(HANDLE hSnapshot, const wchar_t *pLibFileName);
bool InjectLibraryAndCreateRemoteThread(
HANDLE hProcess,
HMODULE hModule,
LPTHREAD_START_ROUTINE pStartAddress,
const void *pParam,
size_t cbParam);
bool InjectLibrary(HANDLE hProcess, HMODULE hModule, HMODULE *phRemoteModule);
bool InjectLibraryByFilename(
HANDLE hProcess,
const wchar_t *pLibFilename,
size_t cchLibFilename,
HMODULE *phRemoteModule);
bool wufuc_InjectLibrary(DWORD dwProcessId, ContextHandles *pContext);

View File

@@ -1,155 +0,0 @@
#include "stdafx.h"
#include "hlpmisc.h"
#include <sddl.h>
bool InitializeMutex(bool InitialOwner, const wchar_t *pMutexName, HANDLE *phMutex)
{
HANDLE hMutex;
hMutex = CreateMutexW(NULL, InitialOwner, pMutexName);
if ( hMutex ) {
if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
CloseHandle(hMutex);
return false;
}
*phMutex = hMutex;
return true;
} else {
trace(L"Failed to create mutex: %ls (GetLastError=%ld)",
pMutexName, GetLastError());
}
return false;
}
bool CreateEventWithStringSecurityDescriptor(
const wchar_t *pStringSecurityDescriptor,
bool ManualReset,
bool InitialState,
const wchar_t *pName,
HANDLE *phEvent)
{
SECURITY_ATTRIBUTES sa = { sizeof sa };
HANDLE event;
if ( ConvertStringSecurityDescriptorToSecurityDescriptorW(
pStringSecurityDescriptor,
SDDL_REVISION_1,
&sa.lpSecurityDescriptor,
NULL) ) {
event = CreateEventW(&sa, ManualReset, InitialState, pName);
if ( event ) {
*phEvent = event;
return true;
}
}
return false;
}
PVOID RegGetValueAlloc(
HKEY hkey,
const wchar_t *pSubKey,
const wchar_t *pValue,
DWORD dwFlags,
LPDWORD pdwType,
LPDWORD pcbData)
{
DWORD cbData = 0;
PVOID result = NULL;
if ( RegGetValueW(hkey, pSubKey, pValue, dwFlags, pdwType, NULL, &cbData) != ERROR_SUCCESS )
return result;
result = malloc(cbData);
if ( !result ) return result;
if ( RegGetValueW(hkey, pSubKey, pValue, dwFlags, pdwType, result, &cbData) == ERROR_SUCCESS ) {
if ( pcbData )
*pcbData = cbData;
} else {
free(result);
result = NULL;
}
return result;
}
LPBYTE RegQueryValueExAlloc(
HKEY hKey,
const wchar_t *pSubKey,
const wchar_t *pValueName,
LPDWORD pType,
LPDWORD pcbData)
{
HKEY hSubKey;
DWORD cbData = 0;
size_t length;
LPBYTE result = NULL;
if ( pSubKey && *pSubKey ) {
if ( RegOpenKeyW(hKey, pSubKey, &hSubKey) != ERROR_SUCCESS )
return result;
} else {
hSubKey = hKey;
}
if ( RegQueryValueExW(hSubKey, pValueName, NULL, pType, result, &cbData) != ERROR_SUCCESS )
return result;
length = cbData + (sizeof UNICODE_NULL * 2);
result = malloc(length);
if ( !result ) return result;
ZeroMemory(result, length);
if ( RegQueryValueExW(hSubKey, pValueName, NULL, pType, result, &cbData) == ERROR_SUCCESS ) {
if ( pcbData )
*pcbData = cbData;
} else {
free(result);
result = NULL;
}
return result;
}
PVOID NtQueryKeyAlloc(
HANDLE KeyHandle,
KEY_INFORMATION_CLASS KeyInformationClass,
PULONG pResultLength)
{
NTSTATUS Status;
ULONG ResultLength;
PVOID result = NULL;
Status = NtQueryKey(KeyHandle, KeyInformationClass, NULL, 0, &ResultLength);
if ( Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL )
return result;
result = malloc(ResultLength);
if ( !result ) return result;
Status = NtQueryKey(KeyHandle, KeyInformationClass, result, ResultLength, &ResultLength);
if ( NT_SUCCESS(Status) ) {
*pResultLength = ResultLength;
} else {
free(result);
result = NULL;
}
return result;
}
wchar_t *ExpandEnvironmentStringsAlloc(const wchar_t *src, LPDWORD pcchLength)
{
wchar_t *result;
DWORD buffersize;
DWORD size;
buffersize = ExpandEnvironmentStringsW(src, NULL, 0);
result = calloc(buffersize, sizeof *result);
size = ExpandEnvironmentStringsW(src, result, buffersize);
if ( !size || size > buffersize ) {
free(result);
result = NULL;
} else if ( pcchLength ) {
*pcchLength = buffersize;
}
return result;
}

View File

@@ -1,27 +0,0 @@
#pragma once
bool InitializeMutex(bool InitialOwner, const wchar_t *pMutexName, HANDLE *phMutex);
bool CreateEventWithStringSecurityDescriptor(
const wchar_t *pStringSecurityDescriptor,
bool ManualReset,
bool InitialState,
const wchar_t *pName,
HANDLE *phEvent);
PVOID RegGetValueAlloc(
HKEY hkey,
const wchar_t *pSubKey,
const wchar_t *pValue,
DWORD dwFlags,
LPDWORD pdwType,
LPDWORD pcbData);
LPBYTE RegQueryValueExAlloc(
HKEY hKey,
const wchar_t *pSubKey,
const wchar_t *pValueName,
LPDWORD pType,
LPDWORD pcbData);
PVOID NtQueryKeyAlloc(
HANDLE KeyHandle,
KEY_INFORMATION_CLASS KeyInformationClass,
PULONG pResultLength);
wchar_t *ExpandEnvironmentStringsAlloc(const wchar_t *src, LPDWORD pcchLength);

View File

@@ -1,23 +0,0 @@
#pragma once
LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(
SC_HANDLE hSCM,
const wchar_t *pServiceName,
LPDWORD pcbBufSize);
LPQUERY_SERVICE_CONFIGW QueryServiceConfigAlloc(
SC_HANDLE hSCM,
SC_HANDLE hService,
LPDWORD pcbBufSize);
bool QueryServiceStatusProcessInfoByName(
SC_HANDLE hSCM,
const wchar_t *pServiceName,
LPSERVICE_STATUS_PROCESS pServiceStatus);
bool QueryServiceGroupName(
const LPQUERY_SERVICE_CONFIGW pServiceConfig,
wchar_t **pGroupName,
HLOCAL *hMem);
DWORD QueryServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService);
DWORD QueryServiceProcessIdByName(SC_HANDLE hSCM, const wchar_t *pServiceName);
DWORD HeuristicServiceGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupName);
DWORD HeuristicServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService);
DWORD HeuristicServiceProcessIdByName(SC_HANDLE hSCM, const wchar_t *pServiceName);

View File

@@ -1,6 +0,0 @@
#pragma once
int ProductVersionCompare(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wBuild, WORD wRev);
bool GetVersionInfoFromHModule(HMODULE hModule, const wchar_t *pszSubBlock, LPVOID pData, PUINT pcbData);
LPVOID GetVersionInfoFromHModuleAlloc(HMODULE hModule, const wchar_t *pszSubBlock, PUINT pcbData);
bool IsWindowsVersion(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor);

View File

@@ -1,14 +1,16 @@
#include "stdafx.h"
#include "hlpmem.h"
#include "hlpmisc.h"
#include "hooks.h"
#include "log.h"
#include "registryhelper.h"
#include "context.h"
#include "wufuc.h"
wchar_t *g_pszWUServiceDll;
LPFN_REGQUERYVALUEEXW g_pfnRegQueryValueExW;
LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW;
LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceable;
LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceableLastKnown;
LSTATUS WINAPI RegQueryValueExW_hook(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
{
@@ -38,10 +40,10 @@ LSTATUS WINAPI RegQueryValueExW_hook(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpR
|| _wcsicmp(lpValueName, L"ServiceDll") )
return result;
pBuffer = (PWCH)lpData;
pBuffer = (wchar_t *)lpData;
// get name of registry key being queried
pkni = NtQueryKeyAlloc((HANDLE)hKey, KeyNameInformation, &ResultLength);
pkni = reg_query_key_alloc((HANDLE)hKey, KeyNameInformation, &ResultLength);
if ( !pkni )
return result;
NameCount = pkni->NameLength / sizeof *pkni->Name;
@@ -59,7 +61,7 @@ LSTATUS WINAPI RegQueryValueExW_hook(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpR
|| !_wcsicmp(fname, L"WuaCpuFix64.dll") // WuaCpuFix
|| !_wcsicmp(fname, L"WuaCpuFix.dll")) ) {
expandedpath = ExpandEnvironmentStringsAlloc(realpath, &cchLength);
expandedpath = env_expand_strings_alloc(realpath, &cchLength);
if ( expandedpath ) {
if ( PathFileExistsW(expandedpath)
&& SUCCEEDED(StringCbCopyW(pBuffer, MaximumLength, expandedpath)) ) {
@@ -87,18 +89,7 @@ HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFla
&& (!_wcsicmp(lpFileName, g_pszWUServiceDll)
|| !_wcsicmp(lpFileName, PathFindFileNameW(g_pszWUServiceDll))) ) {
if ( FindIDSFunctionAddress(result, &(PVOID)g_pfnIsDeviceServiceable) ) {
trace(L"Matched pattern for %ls!IsDeviceServiceable. (%p)",
PathFindFileNameW(lpFileName),
g_pfnIsDeviceServiceable);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook);
DetourTransactionCommit();
} else if ( !g_pfnIsDeviceServiceable ) {
trace(L"No pattern matched!");
}
wufuc_hook(result);
}
return result;
}

View File

@@ -10,7 +10,10 @@ extern wchar_t *g_pszWUServiceDll;
extern LPFN_REGQUERYVALUEEXW g_pfnRegQueryValueExW;
extern LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW;
extern LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceable;
extern LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceableLastKnown;
extern PVOID g_ptRegQueryValueExW;
extern PVOID g_ptLoadLibraryExW;
extern PVOID g_ptIsDeviceServiceable;
LSTATUS WINAPI RegQueryValueExW_hook(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags);

292
src/wufuc/log.c Normal file
View File

@@ -0,0 +1,292 @@
#include "stdafx.h"
#include "log.h"
void logp_debug_write(const wchar_t *const format, ...)
{
DWORD pid;
wchar_t exepath[MAX_PATH];
wchar_t *exename;
va_list argptr;
int count;
wchar_t *buffer1;
wchar_t *buffer2;
wchar_t datebuf[9];
wchar_t timebuf[9];
const wchar_t fmt[] = L"%ls %ls [%ls:%lu] %ls";
pid = GetCurrentProcessId();
GetModuleFileNameW(NULL, exepath, _countof(exepath));
exename = PathFindFileNameW(exepath);
va_start(argptr, format);
count = _vscwprintf(format, argptr) + 1;
buffer1 = calloc(count, sizeof *buffer1);
vswprintf_s(buffer1, count, format, argptr);
va_end(argptr);
_wstrdate_s(datebuf, _countof(datebuf));
_wstrtime_s(timebuf, _countof(timebuf));
count = _scwprintf(fmt, datebuf, timebuf, exename, pid, buffer1) + 1;
buffer2 = calloc(count, sizeof *buffer2);
swprintf_s(buffer1, count, fmt, datebuf, timebuf, exename, pid, buffer1);
free(buffer1);
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));
//}

6
src/wufuc/log.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
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__)
#define trace log_debug_write

151
src/wufuc/modulehelper.c Normal file
View File

@@ -0,0 +1,151 @@
#include "stdafx.h"
#include "modulehelper.h"
HMODULE mod_get_from_th32_snapshot(HANDLE hSnapshot, const wchar_t *pLibFileName)
{
MODULEENTRY32W me = { sizeof me };
if ( !Module32FirstW(hSnapshot, &me) )
return NULL;
do {
if ( !_wcsicmp(me.szExePath, pLibFileName) )
return me.hModule;
} while ( Module32NextW(hSnapshot, &me) );
return NULL;
}
bool mod_inject_and_begin_thread(
HANDLE hProcess,
HMODULE hModule,
LPTHREAD_START_ROUTINE pStartAddress,
const void *pParam,
size_t cbParam)
{
bool result = false;
NTSTATUS Status;
LPVOID pBaseAddress = NULL;
SIZE_T cb;
HMODULE hRemoteModule = NULL;
HANDLE hThread;
Status = NtSuspendProcess(hProcess);
if ( !NT_SUCCESS(Status) ) return result;
if ( pParam ) {
// this will be VirtualFree()'d by the function at pStartAddress
pBaseAddress = VirtualAllocEx(hProcess,
NULL,
cbParam,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
if ( !pBaseAddress ) goto resume;
if ( !WriteProcessMemory(hProcess, pBaseAddress, pParam, cbParam, &cb) )
goto vfree;
}
if ( mod_inject_by_hmodule(hProcess, hModule, &hRemoteModule) ) {
hThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)((uint8_t *)hRemoteModule + ((uint8_t *)pStartAddress - (uint8_t *)hModule)),
pBaseAddress,
0,
NULL);
if ( hThread ) {
CloseHandle(hThread);
result = true;
}
}
vfree:
if ( !result && pBaseAddress )
VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE);
resume: NtResumeProcess(hProcess);
return result;
}
bool mod_inject_by_hmodule(HANDLE hProcess, HMODULE hModule, HMODULE *phRemoteModule)
{
WCHAR Filename[MAX_PATH];
DWORD nLength;
nLength = GetModuleFileNameW(hModule, Filename, _countof(Filename));
if ( nLength ) {
return mod_inject(hProcess,
Filename,
nLength,
phRemoteModule);
}
return false;
}
bool mod_inject(
HANDLE hProcess,
const wchar_t *pLibFilename,
size_t cchLibFilename,
HMODULE *phRemoteModule)
{
bool result = false;
DWORD dwProcessId;
NTSTATUS Status;
HANDLE hSnapshot;
SIZE_T nSize;
LPVOID pBaseAddress;
HANDLE hThread;
Status = NtSuspendProcess(hProcess);
if ( !NT_SUCCESS(Status) ) return result;
dwProcessId = GetProcessId(hProcess);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
if ( !hSnapshot ) goto resume;
*phRemoteModule = mod_get_from_th32_snapshot(hSnapshot,
pLibFilename);
CloseHandle(hSnapshot);
// already injected... still sets *phRemoteModule
if ( *phRemoteModule ) goto resume;
nSize = (cchLibFilename + 1) * sizeof *pLibFilename;
pBaseAddress = VirtualAllocEx(hProcess,
NULL,
nSize,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
if ( !pBaseAddress ) goto resume;
if ( !WriteProcessMemory(hProcess, pBaseAddress, pLibFilename, nSize, NULL) )
goto vfree;
hThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)LoadLibraryW,
pBaseAddress,
0,
NULL);
if ( !hThread ) goto vfree;
WaitForSingleObject(hThread, INFINITE);
if ( sizeof *phRemoteModule > sizeof(DWORD) ) {
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
if ( hSnapshot ) {
*phRemoteModule = mod_get_from_th32_snapshot(
hSnapshot,
pLibFilename);
CloseHandle(hSnapshot);
result = *phRemoteModule != NULL;
}
} else {
result = GetExitCodeThread(hThread, (LPDWORD)phRemoteModule) != FALSE;
}
CloseHandle(hThread);
vfree: VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE);
resume: NtResumeProcess(hProcess);
return result;
}

15
src/wufuc/modulehelper.h Normal file
View File

@@ -0,0 +1,15 @@
#pragma once
HMODULE mod_get_from_th32_snapshot(HANDLE hSnapshot, const wchar_t *pLibFileName);
bool mod_inject_and_begin_thread(
HANDLE hProcess,
HMODULE hModule,
LPTHREAD_START_ROUTINE pStartAddress,
const void *pParam,
size_t cbParam);
bool mod_inject_by_hmodule(HANDLE hProcess, HMODULE hModule, HMODULE *phRemoteModule);
bool mod_inject(
HANDLE hProcess,
const wchar_t *pLibFilename,
size_t cchLibFilename,
HMODULE *phRemoteModule);

119
src/wufuc/registryhelper.c Normal file
View File

@@ -0,0 +1,119 @@
#include "stdafx.h"
#include "registryhelper.h"
#include <sddl.h>
PVOID reg_get_value_alloc(
HKEY hKey,
const wchar_t *SubKey,
const wchar_t *Value,
DWORD dwFlags,
LPDWORD pdwType,
LPDWORD pcbData)
{
DWORD cbData = 0;
PVOID result = NULL;
if ( RegGetValueW(hKey, SubKey, Value, dwFlags, pdwType, NULL, &cbData) != ERROR_SUCCESS )
return result;
result = malloc(cbData);
if ( !result ) return result;
if ( RegGetValueW(hKey, SubKey, Value, dwFlags, pdwType, result, &cbData) == ERROR_SUCCESS ) {
if ( pcbData )
*pcbData = cbData;
} else {
free(result);
result = NULL;
}
return result;
}
LPBYTE reg_query_value_alloc(
HKEY hKey,
const wchar_t *SubKey,
const wchar_t *Value,
LPDWORD pdwType,
LPDWORD pcbData)
{
HKEY hSubKey;
DWORD cbData = 0;
DWORD dwType;
LPBYTE result = NULL;
if ( SubKey && *SubKey ) {
if ( RegOpenKeyW(hKey, SubKey, &hSubKey) != ERROR_SUCCESS )
return result;
} else {
hSubKey = hKey;
}
if ( RegQueryValueExW(hSubKey, Value, NULL, &dwType, result, &cbData) != ERROR_SUCCESS )
return result;
switch ( dwType ) {
case REG_SZ:
case REG_EXPAND_SZ:
cbData += sizeof UNICODE_NULL;
break;
case REG_MULTI_SZ:
cbData += (sizeof UNICODE_NULL) * 2;
break;
}
result = malloc(cbData);
if ( !result ) return result;
ZeroMemory(result, cbData);
if ( RegQueryValueExW(hSubKey, Value, NULL, pdwType, result, &cbData) == ERROR_SUCCESS ) {
if ( pcbData )
*pcbData = cbData;
} else {
free(result);
result = NULL;
}
return result;
}
PVOID reg_query_key_alloc(
HANDLE KeyHandle,
KEY_INFORMATION_CLASS KeyInformationClass,
PULONG pResultLength)
{
NTSTATUS Status;
ULONG ResultLength;
PVOID result = NULL;
Status = NtQueryKey(KeyHandle, KeyInformationClass, NULL, 0, &ResultLength);
if ( Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL )
return result;
result = malloc(ResultLength);
if ( !result ) return result;
Status = NtQueryKey(KeyHandle, KeyInformationClass, result, ResultLength, &ResultLength);
if ( NT_SUCCESS(Status) ) {
*pResultLength = ResultLength;
} else {
free(result);
result = NULL;
}
return result;
}
wchar_t *env_expand_strings_alloc(const wchar_t *src, LPDWORD pcchLength)
{
wchar_t *result;
DWORD buffersize;
DWORD size;
buffersize = ExpandEnvironmentStringsW(src, NULL, 0);
result = calloc(buffersize, sizeof *result);
size = ExpandEnvironmentStringsW(src, result, buffersize);
if ( !size || size > buffersize ) {
free(result);
result = NULL;
} else if ( pcchLength ) {
*pcchLength = buffersize;
}
return result;
}

View File

@@ -0,0 +1,20 @@
#pragma once
PVOID reg_get_value_alloc(
HKEY hkey,
const wchar_t *pSubKey,
const wchar_t *pValue,
DWORD dwFlags,
LPDWORD pdwType,
LPDWORD pcbData);
LPBYTE reg_query_value_alloc(
HKEY hKey,
const wchar_t *pSubKey,
const wchar_t *pValueName,
LPDWORD pType,
LPDWORD pcbData);
PVOID reg_query_key_alloc(
HANDLE KeyHandle,
KEY_INFORMATION_CLASS KeyInformationClass,
PULONG pResultLength);
wchar_t *env_expand_strings_alloc(const wchar_t *src, LPDWORD pcchLength);

View File

@@ -1,12 +1,15 @@
#include "stdafx.h"
#include "context.h"
#include "callbacks.h"
#include "hlpmem.h"
#include "hlpmisc.h"
#include "hlpsvc.h"
#include "modulehelper.h"
#include "registryhelper.h"
#include "servicehelper.h"
#include "log.h"
#include "wufuc.h"
void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
{
ContextHandles ctx;
context ctx;
DWORD dwDesiredAccess;
DWORD dwProcessId;
bool Unloading = false;
@@ -15,55 +18,37 @@ void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, in
SC_HANDLE hService;
SERVICE_NOTIFYW NotifyBuffer;
if ( !InitializeMutex(true,
L"Global\\25020063-b5a7-4227-9fdf-25cb75e8c645",
&ctx.hParentMutex) )
if ( !ctx_create(&ctx,
L"Global\\25020063-b5a7-4227-9fdf-25cb75e8c645", 0,
L"Global\\wufuc_UnloadEvent", L"D:(A;;0x001F0003;;;BA)", 0) )
return;
if ( !start_traing() )
itrace(L"Could not create tracing pipe!");
return;
if ( !CreateEventWithStringSecurityDescriptor(L"D:(A;;0x001F0003;;;BA)",
true,
false,
L"Global\\wufuc_UnloadEvent",
&ctx.hUnloadEvent) ) {
trace(L"Failed to create unload event. (GetLastError=%lu)", GetLastError());
goto close_mutex;
}
dwDesiredAccess = SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG;
do {
Lagging = false;
hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
if ( !hSCM ) {
trace(L"Failed to open SCM. (GetLastError=%lu)", GetLastError());
goto close_event;
}
if ( !hSCM ) goto delete_ctx;
hService = OpenServiceW(hSCM, L"wuauserv", dwDesiredAccess);
if ( !hService ) {
trace(L"Failed to open service. (GetLastError=%lu)", GetLastError());
goto close_scm;
}
if ( !hService ) goto close_scm;
if ( (dwDesiredAccess & SERVICE_QUERY_CONFIG) == SERVICE_QUERY_CONFIG ) {
dwDesiredAccess &= ~SERVICE_QUERY_CONFIG;
dwProcessId = HeuristicServiceProcessId(hSCM, hService);
dwProcessId = svc_heuristic_process_id(hSCM, hService);
if ( dwProcessId )
wufuc_InjectLibrary(dwProcessId, &ctx);
wufuc_inject(dwProcessId, (LPTHREAD_START_ROUTINE)cb_start, &ctx);
}
ZeroMemory(&NotifyBuffer, sizeof NotifyBuffer);
NotifyBuffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
NotifyBuffer.pfnNotifyCallback = ServiceNotifyCallback;
NotifyBuffer.pfnNotifyCallback = cb_service_notify;
NotifyBuffer.pContext = (PVOID)&ctx;
while ( !Unloading && !Lagging ) {
switch ( NotifyServiceStatusChangeW(hService,
SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_RUNNING,
&NotifyBuffer) ) {
case ERROR_SUCCESS:
Unloading = WaitForSingleObjectEx(ctx.hUnloadEvent, INFINITE, TRUE) == WAIT_OBJECT_0;
Unloading = WaitForSingleObjectEx(ctx.uevent, INFINITE, TRUE) == WAIT_OBJECT_0;
break;
case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING:
trace(L"Client lagging!");
@@ -75,15 +60,11 @@ void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, in
}
}
CloseServiceHandle(hService);
close_scm: CloseServiceHandle(hSCM);
close_scm:
CloseServiceHandle(hSCM);
} while ( Lagging );
close_event:
CloseHandle(ctx.hUnloadEvent);
close_mutex:
ReleaseMutex(ctx.hParentMutex);
if ( g_hTracingMutex )
CloseHandle(g_hTracingMutex);
CloseHandle(ctx.hParentMutex);
delete_ctx:
ctx_delete(&ctx);
}
void CALLBACK RUNDLL32_UnloadW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)

View File

@@ -1,8 +1,8 @@
#include "stdafx.h"
#include "hlpmisc.h"
#include "hlpsvc.h"
#include "servicehelper.h"
#include "registryhelper.h"
LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(
LPQUERY_SERVICE_CONFIGW svc_query_config_by_name_alloc(
SC_HANDLE hSCM,
const wchar_t *pServiceName,
LPDWORD pcbBufSize)
@@ -13,13 +13,13 @@ LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(
hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_CONFIG);
if ( !hService ) return result;
result = QueryServiceConfigAlloc(hSCM, hService, pcbBufSize);
result = svc_query_config_alloc(hSCM, hService, pcbBufSize);
CloseServiceHandle(hService);
return result;
}
LPQUERY_SERVICE_CONFIGW QueryServiceConfigAlloc(
LPQUERY_SERVICE_CONFIGW svc_query_config_alloc(
SC_HANDLE hSCM,
SC_HANDLE hService,
LPDWORD pcbBufSize)
@@ -44,7 +44,7 @@ LPQUERY_SERVICE_CONFIGW QueryServiceConfigAlloc(
return result;
}
bool QueryServiceStatusProcessInfoByName(
bool svc_query_process_info_by_name(
SC_HANDLE hSCM,
const wchar_t *pServiceName,
LPSERVICE_STATUS_PROCESS pServiceStatus)
@@ -66,7 +66,7 @@ bool QueryServiceStatusProcessInfoByName(
return result;
}
bool QueryServiceGroupName(
bool svc_query_group_name(
const LPQUERY_SERVICE_CONFIGW pServiceConfig,
wchar_t **pGroupName,
HLOCAL *hMem)
@@ -92,7 +92,7 @@ bool QueryServiceGroupName(
return false;
}
DWORD QueryServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService)
DWORD svc_query_process_id(SC_HANDLE hSCM, SC_HANDLE hService)
{
DWORD result = 0;
SERVICE_STATUS_PROCESS ServiceStatus;
@@ -109,16 +109,16 @@ DWORD QueryServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService)
return result;
}
DWORD QueryServiceProcessIdByName(SC_HANDLE hSCM, const wchar_t *pServiceName)
DWORD svc_query_process_id_by_name(SC_HANDLE hSCM, const wchar_t *pServiceName)
{
SERVICE_STATUS_PROCESS ServiceStatusProcess;
if ( QueryServiceStatusProcessInfoByName(hSCM, pServiceName, &ServiceStatusProcess) )
if ( svc_query_process_info_by_name(hSCM, pServiceName, &ServiceStatusProcess) )
return ServiceStatusProcess.dwProcessId;
return 0;
}
DWORD HeuristicServiceGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupNameSearch)
DWORD svc_heuristic_group_process_id(SC_HANDLE hSCM, const wchar_t *pGroupNameSearch)
{
wchar_t *pData;
DWORD result = 0;
@@ -129,7 +129,7 @@ DWORD HeuristicServiceGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupNameSe
wchar_t *pGroupName;
HLOCAL hMem;
pData = RegGetValueAlloc(HKEY_LOCAL_MACHINE,
pData = reg_get_value_alloc(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost",
pGroupNameSearch,
RRF_RT_REG_MULTI_SZ,
@@ -139,14 +139,14 @@ DWORD HeuristicServiceGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupNameSe
if ( !pData ) return result;
for ( wchar_t *pName = pData; *pName; pName += wcslen(pName) + 1 ) {
dwProcessId = QueryServiceProcessIdByName(hSCM, pName);
dwProcessId = svc_query_process_id_by_name(hSCM, pName);
if ( !dwProcessId ) continue;
pServiceConfig = QueryServiceConfigByNameAlloc(hSCM, pName, &cbBufSize);
pServiceConfig = svc_query_config_by_name_alloc(hSCM, pName, &cbBufSize);
if ( !pServiceConfig ) continue;
if ( pServiceConfig->dwServiceType == SERVICE_WIN32_SHARE_PROCESS
&& QueryServiceGroupName(pServiceConfig, &pGroupName, &hMem) ) {
&& svc_query_group_name(pServiceConfig, &pGroupName, &hMem) ) {
success = !_wcsicmp(pGroupNameSearch, pGroupName);
LocalFree(hMem);
@@ -161,18 +161,18 @@ DWORD HeuristicServiceGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupNameSe
return result;
}
DWORD HeuristicServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService)
DWORD svc_heuristic_process_id(SC_HANDLE hSCM, SC_HANDLE hService)
{
DWORD result = 0;
LPQUERY_SERVICE_CONFIGW pServiceConfig;
wchar_t *pGroupName;
HLOCAL hMem;
result = QueryServiceProcessId(hSCM, hService);
result = svc_query_process_id(hSCM, hService);
if ( result )
return result;
pServiceConfig = QueryServiceConfigAlloc(hSCM, hService, NULL);
pServiceConfig = svc_query_config_alloc(hSCM, hService, NULL);
if ( pServiceConfig ) {
switch ( pServiceConfig->dwServiceType ) {
case SERVICE_WIN32_OWN_PROCESS:
@@ -185,8 +185,8 @@ DWORD HeuristicServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService)
// process, it is possible to "guess" which svchost.exe
// it will eventually be loaded into by finding other
// services in the same group that are already running.
if ( QueryServiceGroupName(pServiceConfig, &pGroupName, &hMem) ) {
result = HeuristicServiceGroupProcessId(hSCM, pGroupName);
if ( svc_query_group_name(pServiceConfig, &pGroupName, &hMem) ) {
result = svc_heuristic_group_process_id(hSCM, pGroupName);
LocalFree(hMem);
}
break;
@@ -196,13 +196,13 @@ DWORD HeuristicServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService)
return result;
}
DWORD HeuristicServiceProcessIdByName(SC_HANDLE hSCM, const wchar_t *pServiceName)
DWORD svc_heuristic_process_id_by_name(SC_HANDLE hSCM, const wchar_t *pServiceName)
{
DWORD result = 0;
SC_HANDLE hService;
hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
result = HeuristicServiceProcessId(hSCM, hService);
result = svc_heuristic_process_id(hSCM, hService);
CloseServiceHandle(hService);
return result;

23
src/wufuc/servicehelper.h Normal file
View File

@@ -0,0 +1,23 @@
#pragma once
LPQUERY_SERVICE_CONFIGW svc_query_config_by_name_alloc(
SC_HANDLE hSCM,
const wchar_t *pServiceName,
LPDWORD pcbBufSize);
LPQUERY_SERVICE_CONFIGW svc_query_config_alloc(
SC_HANDLE hSCM,
SC_HANDLE hService,
LPDWORD pcbBufSize);
bool svc_query_process_info_by_name(
SC_HANDLE hSCM,
const wchar_t *pServiceName,
LPSERVICE_STATUS_PROCESS pServiceStatus);
bool svc_query_group_name(
const LPQUERY_SERVICE_CONFIGW pServiceConfig,
wchar_t **pGroupName,
HLOCAL *hMem);
DWORD svc_query_process_id(SC_HANDLE hSCM, SC_HANDLE hService);
DWORD svc_query_process_id_by_name(SC_HANDLE hSCM, const wchar_t *pServiceName);
DWORD svc_heuristic_group_process_id(SC_HANDLE hSCM, const wchar_t *pGroupName);
DWORD svc_heuristic_process_id(SC_HANDLE hSCM, SC_HANDLE hService);
DWORD svc_heuristic_process_id_by_name(SC_HANDLE hSCM, const wchar_t *pServiceName);

View File

@@ -27,10 +27,6 @@
#include <Psapi.h>
#include <TlHelp32.h>
#include <detours.h>
#include "patternfind.h"
#include "tracing.h"
extern IMAGE_DOS_HEADER __ImageBase;
#define PIMAGEBASE ((HMODULE)&__ImageBase)

View File

@@ -1,234 +0,0 @@
#include "stdafx.h"
#include "tracing.h"
#include <Shlobj.h>
void itrace_(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);
}
HANDLE g_hTracingMutex;
wchar_t path[MAX_PATH];
wchar_t exepath[MAX_PATH];
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

@@ -1,15 +0,0 @@
#pragma once
#include <phnt_windows.h>
extern HANDLE g_hTracingMutex;
void itrace_(const wchar_t *const format, ...);
void trace_(const wchar_t *const format, ...);
#define STRINGIZEW_(x) L#x
#define STRINGIZEW(x) STRINGIZEW_(x)
#define LINEWSTR STRINGIZEW(__LINE__)
#define itrace(format, ...) itrace_(__FILEW__ L":" LINEWSTR L"(" __FUNCTIONW__ L"): " format L"\r\n", ##__VA_ARGS__)
#define trace(format, ...) trace_(__FILEW__ L":" LINEWSTR L"(" __FUNCTIONW__ L"): " format L"\r\n", ##__VA_ARGS__)

View File

@@ -1,7 +1,7 @@
#include "stdafx.h"
#include "hlpver.h"
#include "versionhelper.h"
int ProductVersionCompare(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wBuild, WORD wRev)
int ver_compare_product_version(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wBuild, WORD wRev)
{
if ( HIWORD(pffi->dwProductVersionMS) < wMajor ) return -1;
if ( HIWORD(pffi->dwProductVersionMS) > wMajor ) return 1;
@@ -14,7 +14,7 @@ int ProductVersionCompare(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD
return 0;
}
bool GetVersionInfoFromHModule(HMODULE hModule, const wchar_t *pszSubBlock, LPVOID pData, PUINT pcbData)
bool ver_get_version_info_from_hmodule(HMODULE hModule, const wchar_t *pszSubBlock, LPVOID pData, PUINT pcbData)
{
bool result = false;
UINT cbData;
@@ -44,8 +44,9 @@ bool GetVersionInfoFromHModule(HMODULE hModule, const wchar_t *pszSubBlock, LPVO
if ( !pRes ) return result;
pCopy = malloc(dwSize);
if ( !pCopy
|| memcpy_s(pCopy, dwSize, pRes, dwSize)
if ( !pCopy ) return result;
if ( memcpy_s(pCopy, dwSize, pRes, dwSize)
|| !VerQueryValueW(pCopy, pszSubBlock, &pBuffer, &uLen) )
goto cleanup;
@@ -68,18 +69,18 @@ cleanup:
return result;
}
LPVOID GetVersionInfoFromHModuleAlloc(HMODULE hModule, const wchar_t *pszSubBlock, PUINT pcbData)
LPVOID ver_get_version_info_from_hmodule_alloc(HMODULE hModule, const wchar_t *pszSubBlock, PUINT pcbData)
{
UINT cbData = 0;
LPVOID result = NULL;
if ( !GetVersionInfoFromHModule(hModule, pszSubBlock, NULL, &cbData) )
if ( !ver_get_version_info_from_hmodule(hModule, pszSubBlock, NULL, &cbData) )
return result;
result = malloc(cbData);
if ( !result ) return result;
if ( GetVersionInfoFromHModule(hModule, pszSubBlock, result, &cbData) ) {
if ( ver_get_version_info_from_hmodule(hModule, pszSubBlock, result, &cbData) ) {
*pcbData = cbData;
} else {
free(result);
@@ -88,7 +89,7 @@ LPVOID GetVersionInfoFromHModuleAlloc(HMODULE hModule, const wchar_t *pszSubBloc
return result;
}
bool IsWindowsVersion(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
bool ver_verify_version_info(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
{
OSVERSIONINFOEXW osvi = { sizeof osvi };
@@ -105,3 +106,13 @@ bool IsWindowsVersion(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackM
VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR,
dwlConditionMask) != FALSE;
}
bool ver_verify_windows_7_sp1(void)
{
return ver_verify_version_info(6, 1, 1);
}
bool ver_verify_windows_8_1(void)
{
return ver_verify_version_info(6, 3, 0);
}

View File

@@ -0,0 +1,8 @@
#pragma once
int ver_compare_product_version(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wBuild, WORD wRev);
bool ver_get_version_info_from_hmodule(HMODULE hModule, const wchar_t *pszSubBlock, LPVOID pData, PUINT pcbData);
LPVOID ver_get_version_info_from_hmodule_alloc(HMODULE hModule, const wchar_t *pszSubBlock, PUINT pcbData);
bool ver_verify_version_info(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor);
bool ver_verify_windows_7_sp1(void);
bool ver_verify_windows_8_1(void);

126
src/wufuc/wufuc.c Normal file
View File

@@ -0,0 +1,126 @@
#include "stdafx.h"
#include "context.h"
#include "wufuc.h"
#include "modulehelper.h"
#include "versionhelper.h"
#include "hooks.h"
#include "log.h"
#include "patternfind.h"
#include <minhook.h>
bool wufuc_inject(DWORD dwProcessId,
LPTHREAD_START_ROUTINE pfnStart,
context *pContext)
{
bool result = false;
HANDLE hProcess;
HANDLE hMutex;
context ctx;
if ( !ctx_add_new_mutex_fmt(pContext,
false,
dwProcessId,
&hMutex,
L"Global\\%08x-7132-44a8-be15-56698979d2f3", dwProcessId) )
return false;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if ( !hProcess ) return false;
result = ctx_duplicate_context(pContext, hProcess, &ctx, hMutex, DUPLICATE_SAME_ACCESS, dwProcessId)
&& mod_inject_and_begin_thread(hProcess, PIMAGEBASE, pfnStart, &ctx, sizeof ctx);
CloseHandle(hProcess);
return result;
}
bool wufuc_hook(HMODULE hModule)
{
bool result = false;
PLANGANDCODEPAGE ptl;
HANDLE hProcess;
int tmp;
UINT cbtl;
wchar_t SubBlock[38];
UINT cbInternalName;
wchar_t *pInternalName;
UINT cbffi;
VS_FIXEDFILEINFO *pffi;
MODULEINFO modinfo;
size_t offset;
if ( !ver_verify_windows_7_sp1() && !ver_verify_windows_8_1() )
return false;
ptl = ver_get_version_info_from_hmodule_alloc(hModule, L"\\VarFileInfo\\Translation", &cbtl);
if ( !ptl ) {
trace(L"Failed to allocate version translation information from hmodule.");
return false;
}
hProcess = GetCurrentProcess();
for ( size_t i = 0, count = (cbtl / sizeof *ptl); i < count; i++ ) {
if ( swprintf_s(SubBlock,
_countof(SubBlock),
L"\\StringFileInfo\\%04x%04x\\InternalName",
ptl[i].wLanguage,
ptl[i].wCodePage) == -1 )
continue;
pInternalName = ver_get_version_info_from_hmodule_alloc(hModule, SubBlock, &cbInternalName);
if ( !pInternalName ) {
trace(L"Failed to allocate version internal name from hmodule.");
continue;
}
// identify wuaueng.dll by its resource data
if ( !_wcsicmp(pInternalName, L"wuaueng.dll") ) {
pffi = ver_get_version_info_from_hmodule_alloc(hModule, L"\\", &cbffi);
if ( !pffi ) {
trace(L"Failed to allocate version information from hmodule.");
break;
}
trace(L"Windows Update Agent version: %hu.%hu.%hu.%hu"),
HIWORD(pffi->dwProductVersionMS),
LOWORD(pffi->dwProductVersionMS),
HIWORD(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)
|| (ver_verify_windows_8_1() && ver_compare_product_version(pffi, 7, 9, 9600, 18621) != -1));
free(pffi);
if ( !tmp ) {
trace(L"Windows Update Agent does not meet the minimum supported version.");
break;
}
if ( !GetModuleInformation(hProcess, hModule, &modinfo, sizeof modinfo) ) {
trace(L"Failed to get module information (%p)", hModule);
break;
}
offset = patternfind(modinfo.lpBaseOfDll, modinfo.SizeOfImage,
#ifdef _WIN64
"FFF3 4883EC?? 33DB 391D???????? 7508 8B05????????"
#else
ver_verify_windows_7_sp1()
? "833D????????00 743E E8???????? A3????????"
: "8BFF 51 833D????????00 7507 A1????????"
#endif
);
if ( offset == -1 ) {
trace(L"Could not locate pattern offset!");
break;
} else {
result = MH_CreateHook((PVOID)((uint8_t *)modinfo.lpBaseOfDll + offset),
IsDeviceServiceable_hook,
NULL) == MH_OK;
}
break;
} else trace(L"Module internal name does not match. (%ls)", pInternalName);
free(pInternalName);
}
free(ptl);
return result;
}

12
src/wufuc/wufuc.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
typedef struct
{
WORD wLanguage;
WORD wCodePage;
} LANGANDCODEPAGE, *PLANGANDCODEPAGE;
bool wufuc_inject(DWORD dwProcessId,
LPTHREAD_START_ROUTINE pfnStart,
context *pContext);
bool wufuc_hook(HMODULE hModule);

View File

@@ -20,24 +20,28 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="callbacks.h" />
<ClInclude Include="hlpmem.h" />
<ClInclude Include="hlpmisc.h" />
<ClInclude Include="hlpsvc.h" />
<ClInclude Include="hlpver.h" />
<ClInclude Include="context.h" />
<ClInclude Include="log.h" />
<ClInclude Include="modulehelper.h" />
<ClInclude Include="registryhelper.h" />
<ClInclude Include="servicehelper.h" />
<ClInclude Include="versionhelper.h" />
<ClInclude Include="hooks.h" />
<ClInclude Include="patternfind.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="tracing.h" />
<ClInclude Include="wufuc.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="callbacks.c" />
<ClCompile Include="context.c" />
<ClCompile Include="dllmain.c" />
<ClCompile Include="hlpmem.c" />
<ClCompile Include="hlpmisc.c" />
<ClCompile Include="hlpsvc.c" />
<ClCompile Include="hlpver.c" />
<ClCompile Include="modulehelper.c" />
<ClCompile Include="registryhelper.c" />
<ClCompile Include="servicehelper.c" />
<ClCompile Include="versionhelper.c" />
<ClCompile Include="hooks.c" />
<ClCompile Include="log.c" />
<ClCompile Include="patternfind.c" />
<ClCompile Include="stdafx.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
@@ -46,7 +50,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="rundll32.c" />
<ClCompile Include="tracing.c" />
<ClCompile Include="wufuc.c" />
</ItemGroup>
<ItemGroup>
<None Include="exports.def" />
@@ -115,8 +119,8 @@
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
<GenerateManifest>false</GenerateManifest>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\detours;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\detours;$(LibraryPath)</LibraryPath>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\minhook;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
@@ -124,26 +128,26 @@
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
<GenerateManifest>false</GenerateManifest>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\detours;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\detours;$(LibraryPath)</LibraryPath>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\minhook;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)bin\$(Configuration)\$(PlatformShortName)\</OutDir>
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
<IntDir>$(ProjectDir)obj\$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
<GenerateManifest>false</GenerateManifest>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\detours;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\detours;$(LibraryPath)</LibraryPath>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\minhook;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)bin\$(Configuration)\$(PlatformShortName)\</OutDir>
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
<IntDir>$(ProjectDir)obj\$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
<GenerateManifest>false</GenerateManifest>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\detours;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\detours;$(LibraryPath)</LibraryPath>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\minhook;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
@@ -162,7 +166,7 @@
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
<EntryPointSymbol>
</EntryPointSymbol>
<AdditionalDependencies>version.lib;Shlwapi.lib;detours.X86.MTd.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
<AdditionalDependencies>version.lib;Shlwapi.lib;libMinHook.x86.MTd.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>X86;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -185,7 +189,7 @@
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
<EntryPointSymbol>
</EntryPointSymbol>
<AdditionalDependencies>version.lib;Shlwapi.lib;detours.X64.MTd.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
<AdditionalDependencies>version.lib;Shlwapi.lib;libMinHook.x64.MTd.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>X64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -216,7 +220,7 @@
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
<EntryPointSymbol>
</EntryPointSymbol>
<AdditionalDependencies>version.lib;Shlwapi.lib;detours.X86.MT.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
<AdditionalDependencies>version.lib;Shlwapi.lib;libMinHook.x86.MT.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
<SetChecksum>true</SetChecksum>
</Link>
<ResourceCompile>
@@ -253,7 +257,7 @@ copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup\"</Command>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
<AdditionalDependencies>version.lib;Shlwapi.lib;detours.X64.MT.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
<AdditionalDependencies>version.lib;Shlwapi.lib;libMinHook.x64.MT.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
<SetChecksum>true</SetChecksum>
</Link>
<ResourceCompile>

View File

@@ -21,9 +21,6 @@
<ClInclude Include="hooks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="tracing.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -33,16 +30,25 @@
<ClInclude Include="patternfind.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="hlpmem.h">
<ClInclude Include="context.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="hlpmisc.h">
<ClInclude Include="versionhelper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="hlpsvc.h">
<ClInclude Include="servicehelper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="hlpver.h">
<ClInclude Include="registryhelper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="wufuc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="modulehelper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="log.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
@@ -56,9 +62,6 @@
<ClCompile Include="hooks.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="tracing.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="rundll32.c">
<Filter>Source Files</Filter>
</ClCompile>
@@ -68,16 +71,25 @@
<ClCompile Include="patternfind.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hlpsvc.c">
<ClCompile Include="context.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hlpmem.c">
<ClCompile Include="servicehelper.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hlpver.c">
<ClCompile Include="versionhelper.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hlpmisc.c">
<ClCompile Include="registryhelper.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wufuc.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="log.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="modulehelper.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>