migrate to minhook and begin adding crash loop prevention
This commit is contained in:
@@ -103,8 +103,9 @@ Advanced Installer's intuitive and friendly user interface allowed me to quickly
|
||||
|
||||
## Special thanks
|
||||
|
||||
- Wen Jia Liu ([@wj32](https://github.com/wj32)) for his awesome program [Process Hacker](https://github.com/processhacker2/processhacker) which has been absolutely instrumental in the development of wufuc, and also for his [`phnt`](https://github.com/processhacker2/processhacker/tree/master/phnt) headers.
|
||||
- Wen Jia Liu ([@wj32](https://github.com/wj32)) for his awesome program [Process Hacker](https://github.com/processhacker2/processhacker), and also for his [`phnt` headers](https://github.com/processhacker2/processhacker/tree/master/phnt).
|
||||
- Duncan Ogilvie ([@mrexodia](https://github.com/mrexodia)) for his [`patternfind.cpp`](https://github.com/x64dbg/x64dbg/blob/development/src/dbg/patternfind.cpp) algorithm from [x64dbg](https://github.com/x64dbg/x64dbg).
|
||||
- Tsuda Kageyu ([@TsudaKageyu](https://github.com/TsudaKageyu)) for his excellent [minhook](https://github.com/TsudaKageyu/minhook) library.
|
||||
|
||||
[Latest]: https://github.com/zeffy/wufuc/releases/latest
|
||||
[AppVeyor]: https://ci.appveyor.com/project/zeffy/wufuc
|
||||
|
184
inc/minhook/minhook.h
Normal file
184
inc/minhook/minhook.h
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
|
||||
#error MinHook supports only x86 and x64 systems.
|
||||
#endif
|
||||
|
||||
// MinHook Error Codes.
|
||||
typedef enum MH_STATUS
|
||||
{
|
||||
// Unknown error. Should not be returned.
|
||||
MH_UNKNOWN = -1,
|
||||
|
||||
// Successful.
|
||||
MH_OK = 0,
|
||||
|
||||
// MinHook is already initialized.
|
||||
MH_ERROR_ALREADY_INITIALIZED,
|
||||
|
||||
// MinHook is not initialized yet, or already uninitialized.
|
||||
MH_ERROR_NOT_INITIALIZED,
|
||||
|
||||
// The hook for the specified target function is already created.
|
||||
MH_ERROR_ALREADY_CREATED,
|
||||
|
||||
// The hook for the specified target function is not created yet.
|
||||
MH_ERROR_NOT_CREATED,
|
||||
|
||||
// The hook for the specified target function is already enabled.
|
||||
MH_ERROR_ENABLED,
|
||||
|
||||
// The hook for the specified target function is not enabled yet, or already
|
||||
// disabled.
|
||||
MH_ERROR_DISABLED,
|
||||
|
||||
// The specified pointer is invalid. It points the address of non-allocated
|
||||
// and/or non-executable region.
|
||||
MH_ERROR_NOT_EXECUTABLE,
|
||||
|
||||
// The specified target function cannot be hooked.
|
||||
MH_ERROR_UNSUPPORTED_FUNCTION,
|
||||
|
||||
// Failed to allocate memory.
|
||||
MH_ERROR_MEMORY_ALLOC,
|
||||
|
||||
// Failed to change the memory protection.
|
||||
MH_ERROR_MEMORY_PROTECT,
|
||||
|
||||
// The specified module is not loaded.
|
||||
MH_ERROR_MODULE_NOT_FOUND,
|
||||
|
||||
// The specified function is not found.
|
||||
MH_ERROR_FUNCTION_NOT_FOUND
|
||||
}
|
||||
MH_STATUS;
|
||||
|
||||
// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
|
||||
// MH_QueueEnableHook or MH_QueueDisableHook.
|
||||
#define MH_ALL_HOOKS NULL
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Initialize the MinHook library. You must call this function EXACTLY ONCE
|
||||
// at the beginning of your program.
|
||||
MH_STATUS WINAPI MH_Initialize(VOID);
|
||||
|
||||
// Uninitialize the MinHook library. You must call this function EXACTLY
|
||||
// ONCE at the end of your program.
|
||||
MH_STATUS WINAPI MH_Uninitialize(VOID);
|
||||
|
||||
// Creates a Hook for the specified target function, in disabled state.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
|
||||
|
||||
// Creates a Hook for the specified API function, in disabled state.
|
||||
// Parameters:
|
||||
// pszModule [in] A pointer to the loaded module name which contains the
|
||||
// target function.
|
||||
// pszTarget [in] A pointer to the target function name, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHookApi(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
|
||||
|
||||
// Creates a Hook for the specified API function, in disabled state.
|
||||
// Parameters:
|
||||
// pszModule [in] A pointer to the loaded module name which contains the
|
||||
// target function.
|
||||
// pszTarget [in] A pointer to the target function name, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
// ppTarget [out] A pointer to the target function, which will be used
|
||||
// with other functions.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHookApiEx(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
|
||||
|
||||
// Removes an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
|
||||
|
||||
// Enables an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// enabled in one go.
|
||||
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
|
||||
|
||||
// Disables an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// disabled in one go.
|
||||
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
|
||||
|
||||
// Queues to enable an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// queued to be enabled.
|
||||
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
|
||||
|
||||
// Queues to disable an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// queued to be disabled.
|
||||
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
|
||||
|
||||
// Applies all queued changes in one go.
|
||||
MH_STATUS WINAPI MH_ApplyQueued(VOID);
|
||||
|
||||
// Translates the MH_STATUS to its name as a string.
|
||||
const char * WINAPI MH_StatusToString(MH_STATUS status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
BIN
lib/minhook/libMinHook.x64.MT.lib
Normal file
BIN
lib/minhook/libMinHook.x64.MT.lib
Normal file
Binary file not shown.
BIN
lib/minhook/libMinHook.x64.MTd.lib
Normal file
BIN
lib/minhook/libMinHook.x64.MTd.lib
Normal file
Binary file not shown.
BIN
lib/minhook/libMinHook.x86.MT.lib
Normal file
BIN
lib/minhook/libMinHook.x86.MT.lib
Normal file
Binary file not shown.
BIN
lib/minhook/libMinHook.x86.MTd.lib
Normal file
BIN
lib/minhook/libMinHook.x86.MTd.lib
Normal file
Binary file not shown.
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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
337
src/wufuc/context.c
Normal 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
71
src/wufuc/context.h
Normal 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);
|
@@ -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;
|
||||
|
@@ -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, ¶m.hParentMutex, SYNCHRONIZE, FALSE, 0)
|
||||
&& DuplicateHandle(hSrcProcess, pContext->hUnloadEvent, hProcess, ¶m.hUnloadEvent, SYNCHRONIZE, FALSE, 0)
|
||||
&& DuplicateHandle(hSrcProcess, hChildMutex, hProcess, ¶m.hChildMutex, 0, FALSE, DUPLICATE_SAME_ACCESS) ) {
|
||||
|
||||
if ( InjectLibraryAndCreateRemoteThread(hProcess, PIMAGEBASE, ThreadStartCallback, ¶m, 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;
|
||||
}
|
@@ -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);
|
@@ -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;
|
||||
}
|
@@ -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);
|
@@ -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);
|
@@ -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);
|
@@ -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;
|
||||
}
|
||||
|
@@ -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
292
src/wufuc/log.c
Normal 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
6
src/wufuc/log.h
Normal 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
151
src/wufuc/modulehelper.c
Normal 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
15
src/wufuc/modulehelper.h
Normal 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
119
src/wufuc/registryhelper.c
Normal 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;
|
||||
}
|
20
src/wufuc/registryhelper.h
Normal file
20
src/wufuc/registryhelper.h
Normal 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);
|
@@ -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)
|
||||
|
@@ -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
23
src/wufuc/servicehelper.h
Normal 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);
|
@@ -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)
|
||||
|
||||
|
@@ -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));
|
||||
}
|
@@ -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__)
|
@@ -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);
|
||||
}
|
8
src/wufuc/versionhelper.h
Normal file
8
src/wufuc/versionhelper.h
Normal 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
126
src/wufuc/wufuc.c
Normal 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
12
src/wufuc/wufuc.h
Normal 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);
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
Reference in New Issue
Block a user