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
|
## 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).
|
- 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
|
[Latest]: https://github.com/zeffy/wufuc/releases/latest
|
||||||
[AppVeyor]: https://ci.appveyor.com/project/zeffy/wufuc
|
[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 "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 ) {
|
switch ( pNotifyBuffer->dwNotificationStatus ) {
|
||||||
case ERROR_SUCCESS:
|
case ERROR_SUCCESS:
|
||||||
if ( pNotifyBuffer->ServiceStatus.dwProcessId )
|
if ( pNotifyBuffer->ServiceStatus.dwProcessId )
|
||||||
wufuc_InjectLibrary(
|
wufuc_inject(
|
||||||
pNotifyBuffer->ServiceStatus.dwProcessId,
|
pNotifyBuffer->ServiceStatus.dwProcessId,
|
||||||
(ContextHandles *)pNotifyBuffer->pContext);
|
(LPTHREAD_START_ROUTINE)cb_start,
|
||||||
|
(context *)pNotifyBuffer->pContext);
|
||||||
break;
|
break;
|
||||||
case ERROR_SERVICE_MARKED_FOR_DELETE:
|
case ERROR_SERVICE_MARKED_FOR_DELETE:
|
||||||
SetEvent(((ContextHandles *)pNotifyBuffer->pContext)->hUnloadEvent);
|
SetEvent(((context *)pNotifyBuffer->pContext)->uevent);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ( pNotifyBuffer->pszServiceNames )
|
if ( pNotifyBuffer->pszServiceNames )
|
||||||
LocalFree((HLOCAL)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 hSCM;
|
||||||
SC_HANDLE hService;
|
SC_HANDLE hService;
|
||||||
DWORD dwProcessId;
|
DWORD dwProcessId;
|
||||||
@@ -54,22 +38,17 @@ DWORD WINAPI StartThreadCallback(LPVOID pParam)
|
|||||||
DWORD dwServiceType;
|
DWORD dwServiceType;
|
||||||
wchar_t *str;
|
wchar_t *str;
|
||||||
HMODULE hModule;
|
HMODULE hModule;
|
||||||
wchar_t Filename[MAX_PATH];
|
|
||||||
DWORD result;
|
DWORD result;
|
||||||
|
|
||||||
// get mutex and unload event handles from virtual memory
|
// get mutex and unload event handles from virtual memory
|
||||||
if ( !pParam ) {
|
if ( !ctx ) {
|
||||||
trace(L"Context parameter is null!");
|
trace(L"Context parameter is null!");
|
||||||
goto unload;
|
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.
|
// acquire child mutex, this should be immediate.
|
||||||
if ( WaitForSingleObject(ctx.hChildMutex, 5000) != WAIT_OBJECT_0 ) {
|
if ( WaitForSingleObject(ctx->handles[ctx->mutex_tag], 5000) != WAIT_OBJECT_0 ) {
|
||||||
trace(L"Failed to acquire child mutex within five seconds. (%p)", ctx.hChildMutex);
|
trace(L"Failed to acquire child mutex within five seconds. (%p)", ctx->handles[ctx->mutex_tag]);
|
||||||
goto close_handles;
|
goto close_handles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,112 +58,78 @@ DWORD WINAPI StartThreadCallback(LPVOID pParam)
|
|||||||
goto release;
|
goto release;
|
||||||
}
|
}
|
||||||
|
|
||||||
hService = OpenServiceW(hSCM, L"wuauserv", SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
|
hService = OpenServiceW(hSCM, L"wuauserv",
|
||||||
dwProcessId = HeuristicServiceProcessId(hSCM, hService);
|
SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
|
||||||
pServiceConfig = QueryServiceConfigAlloc(hSCM, hService, NULL);
|
dwProcessId = svc_heuristic_process_id(hSCM, hService);
|
||||||
|
pServiceConfig = svc_query_config_alloc(hSCM, hService, NULL);
|
||||||
dwServiceType = pServiceConfig->dwServiceType;
|
dwServiceType = pServiceConfig->dwServiceType;
|
||||||
free(pServiceConfig);
|
free(pServiceConfig);
|
||||||
CloseServiceHandle(hService);
|
CloseServiceHandle(hService);
|
||||||
CloseServiceHandle(hSCM);
|
CloseServiceHandle(hSCM);
|
||||||
|
|
||||||
if ( dwProcessId != GetCurrentProcessId() ) {
|
if ( dwProcessId != GetCurrentProcessId() ) {
|
||||||
trace(L"Injected into wrong process!", GetCurrentProcessId(), dwProcessId);
|
trace(L"Injected into wrong process!");
|
||||||
goto release;
|
goto release;
|
||||||
}
|
}
|
||||||
|
|
||||||
trace(L"Installing hooks...");
|
|
||||||
|
|
||||||
if ( dwServiceType == SERVICE_WIN32_SHARE_PROCESS ) {
|
if ( dwServiceType == SERVICE_WIN32_SHARE_PROCESS ) {
|
||||||
DetourTransactionBegin();
|
|
||||||
DetourUpdateThread(GetCurrentThread());
|
|
||||||
|
|
||||||
// assume wuaueng.dll hasn't been loaded yet, apply
|
// assume wuaueng.dll hasn't been loaded yet, apply
|
||||||
// RegQueryValueExW hook to fix incompatibility with
|
// RegQueryValueExW hook to fix incompatibility with
|
||||||
// UpdatePack7R2 and other patches that work by
|
// UpdatePack7R2 and other patches that modify the
|
||||||
// modifying the Windows Update ServiceDll path in the
|
// Windows Update ServiceDll path in the registry.
|
||||||
// registry.
|
MH_CreateHookApi(L"kernel32.dll",
|
||||||
g_pfnRegQueryValueExW = DetourFindFunction("kernel32.dll", "RegQueryValueExW");
|
"RegQueryValueExW",
|
||||||
if ( g_pfnRegQueryValueExW )
|
RegQueryValueExW_hook,
|
||||||
DetourAttach(&(PVOID)g_pfnRegQueryValueExW, RegQueryValueExW_hook);
|
&(PVOID)g_pfnRegQueryValueExW);
|
||||||
DetourTransactionCommit();
|
MH_EnableHook(g_pfnRegQueryValueExW);
|
||||||
}
|
}
|
||||||
|
|
||||||
// query the ServiceDll path after applying our compat hook so that it
|
// query the ServiceDll path after applying our compat hook so that it
|
||||||
// is correct
|
// 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"SYSTEM\\CurrentControlSet\\services\\wuauserv\\Parameters",
|
||||||
L"ServiceDll", NULL, NULL);
|
L"ServiceDll", NULL, NULL);
|
||||||
g_pszWUServiceDll = ExpandEnvironmentStringsAlloc(str, NULL);
|
g_pszWUServiceDll = env_expand_strings_alloc(str, NULL);
|
||||||
free(str);
|
free(str);
|
||||||
|
|
||||||
DetourTransactionBegin();
|
MH_CreateHookApi(L"kernel32.dll",
|
||||||
DetourUpdateThread(GetCurrentThread());
|
"LoadLibraryExW",
|
||||||
|
LoadLibraryExW_hook,
|
||||||
|
&(PVOID)g_pfnLoadLibraryExW);
|
||||||
|
|
||||||
g_pfnLoadLibraryExW = DetourFindFunction("kernel32.dll", "LoadLibraryExW");
|
if ( g_pszWUServiceDll
|
||||||
if ( g_pfnLoadLibraryExW )
|
&& (GetModuleHandleExW(0, g_pszWUServiceDll, &hModule)
|
||||||
DetourAttach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook);
|
|| GetModuleHandleExW(0, PathFindFileNameW(g_pszWUServiceDll), &hModule))) {
|
||||||
|
|
||||||
if ( g_pszWUServiceDll ) {
|
// hook IsDeviceServiceable if wuaueng.dll is already loaded
|
||||||
if ( GetModuleHandleExW(0, g_pszWUServiceDll, &hModule) ) {
|
wufuc_hook(hModule);
|
||||||
if ( FindIDSFunctionAddress(hModule, &(PVOID)g_pfnIsDeviceServiceable) ) {
|
FreeLibrary(hModule);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
DetourTransactionCommit();
|
MH_EnableHook(MH_ALL_HOOKS);
|
||||||
|
|
||||||
// wait for unload event or parent mutex to be abandoned.
|
// wait for unload event or parent mutex to be abandoned.
|
||||||
// for example if the user killed rundll32.exe with task manager.
|
// for example if the user killed rundll32.exe with task manager.
|
||||||
// intentionally leave parent mutex open until this thread ends, at
|
result = WaitForMultipleObjects(_countof(ctx->handles), ctx->handles, FALSE, INFINITE);
|
||||||
// which point it becomes abandoned again.
|
|
||||||
result = WaitForMultipleObjects(_countof(ctx.handles), ctx.handles, FALSE, INFINITE);
|
|
||||||
trace(L"Unload condition has been met.");
|
trace(L"Unload condition has been met.");
|
||||||
|
|
||||||
// unhook
|
switch ( result ) {
|
||||||
if ( g_pfnLoadLibraryExW || g_pfnIsDeviceServiceable || g_pfnRegQueryValueExW ) {
|
case ERROR_ABANDONED_WAIT_0:
|
||||||
trace(L"Removing hooks...");
|
ReleaseMutex(ctx->mutex);
|
||||||
DetourTransactionBegin();
|
break;
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
free(g_pszWUServiceDll);
|
|
||||||
|
|
||||||
|
MH_DisableHook(MH_ALL_HOOKS);
|
||||||
|
free(g_pszWUServiceDll);
|
||||||
release:
|
release:
|
||||||
ReleaseMutex(ctx.hChildMutex);
|
ReleaseMutex(ctx->handles[ctx->mutex_tag]);
|
||||||
close_handles:
|
close_handles:
|
||||||
CloseHandle(ctx.hChildMutex);
|
CloseHandle(ctx->handles[ctx->mutex_tag]);
|
||||||
CloseHandle(ctx.hUnloadEvent);
|
CloseHandle(ctx->mutex);
|
||||||
CloseHandle(ctx.hParentMutex);
|
CloseHandle(ctx->uevent);
|
||||||
if ( g_hTracingMutex )
|
VirtualFree(ctx, 0, MEM_RELEASE);
|
||||||
CloseHandle(g_hTracingMutex);
|
|
||||||
unload:
|
unload:
|
||||||
trace(L"Freeing library and exiting main thread.");
|
trace(L"Freeing library and exiting thread.");
|
||||||
FreeLibraryAndExitThread(PIMAGEBASE, 0);
|
FreeLibraryAndExitThread(PIMAGEBASE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer);
|
VOID CALLBACK cb_service_notify(PSERVICE_NOTIFYW pNotifyBuffer);
|
||||||
DWORD WINAPI ThreadStartCallback(LPVOID pParam);
|
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 "stdafx.h"
|
||||||
|
#include <minhook.h>
|
||||||
|
|
||||||
BOOL APIENTRY DllMain(HMODULE hModule,
|
BOOL APIENTRY DllMain(HMODULE hModule,
|
||||||
DWORD ul_reason_for_call,
|
DWORD ul_reason_for_call,
|
||||||
@@ -6,9 +7,12 @@ BOOL APIENTRY DllMain(HMODULE hModule,
|
|||||||
{
|
{
|
||||||
switch ( ul_reason_for_call ) {
|
switch ( ul_reason_for_call ) {
|
||||||
case DLL_PROCESS_ATTACH:
|
case DLL_PROCESS_ATTACH:
|
||||||
|
MH_Initialize();
|
||||||
|
break;
|
||||||
case DLL_THREAD_ATTACH:
|
case DLL_THREAD_ATTACH:
|
||||||
case DLL_THREAD_DETACH:
|
case DLL_THREAD_DETACH:
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
|
MH_Uninitialize();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return TRUE;
|
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 "stdafx.h"
|
||||||
#include "hlpmem.h"
|
|
||||||
#include "hlpmisc.h"
|
|
||||||
#include "hooks.h"
|
#include "hooks.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "registryhelper.h"
|
||||||
|
#include "context.h"
|
||||||
|
#include "wufuc.h"
|
||||||
|
|
||||||
wchar_t *g_pszWUServiceDll;
|
wchar_t *g_pszWUServiceDll;
|
||||||
|
|
||||||
LPFN_REGQUERYVALUEEXW g_pfnRegQueryValueExW;
|
LPFN_REGQUERYVALUEEXW g_pfnRegQueryValueExW;
|
||||||
LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW;
|
LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW;
|
||||||
LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceable;
|
LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceable;
|
||||||
LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceableLastKnown;
|
|
||||||
|
|
||||||
LSTATUS WINAPI RegQueryValueExW_hook(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
|
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") )
|
|| _wcsicmp(lpValueName, L"ServiceDll") )
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
pBuffer = (PWCH)lpData;
|
pBuffer = (wchar_t *)lpData;
|
||||||
|
|
||||||
// get name of registry key being queried
|
// get name of registry key being queried
|
||||||
pkni = NtQueryKeyAlloc((HANDLE)hKey, KeyNameInformation, &ResultLength);
|
pkni = reg_query_key_alloc((HANDLE)hKey, KeyNameInformation, &ResultLength);
|
||||||
if ( !pkni )
|
if ( !pkni )
|
||||||
return result;
|
return result;
|
||||||
NameCount = pkni->NameLength / sizeof *pkni->Name;
|
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"WuaCpuFix64.dll") // WuaCpuFix
|
||||||
|| !_wcsicmp(fname, L"WuaCpuFix.dll")) ) {
|
|| !_wcsicmp(fname, L"WuaCpuFix.dll")) ) {
|
||||||
|
|
||||||
expandedpath = ExpandEnvironmentStringsAlloc(realpath, &cchLength);
|
expandedpath = env_expand_strings_alloc(realpath, &cchLength);
|
||||||
if ( expandedpath ) {
|
if ( expandedpath ) {
|
||||||
if ( PathFileExistsW(expandedpath)
|
if ( PathFileExistsW(expandedpath)
|
||||||
&& SUCCEEDED(StringCbCopyW(pBuffer, MaximumLength, 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, g_pszWUServiceDll)
|
||||||
|| !_wcsicmp(lpFileName, PathFindFileNameW(g_pszWUServiceDll))) ) {
|
|| !_wcsicmp(lpFileName, PathFindFileNameW(g_pszWUServiceDll))) ) {
|
||||||
|
|
||||||
if ( FindIDSFunctionAddress(result, &(PVOID)g_pfnIsDeviceServiceable) ) {
|
wufuc_hook(result);
|
||||||
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!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,10 @@ extern wchar_t *g_pszWUServiceDll;
|
|||||||
extern LPFN_REGQUERYVALUEEXW g_pfnRegQueryValueExW;
|
extern LPFN_REGQUERYVALUEEXW g_pfnRegQueryValueExW;
|
||||||
extern LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW;
|
extern LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW;
|
||||||
extern LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceable;
|
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);
|
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);
|
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 "stdafx.h"
|
||||||
|
#include "context.h"
|
||||||
#include "callbacks.h"
|
#include "callbacks.h"
|
||||||
#include "hlpmem.h"
|
#include "modulehelper.h"
|
||||||
#include "hlpmisc.h"
|
#include "registryhelper.h"
|
||||||
#include "hlpsvc.h"
|
#include "servicehelper.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "wufuc.h"
|
||||||
|
|
||||||
void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
|
void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
|
||||||
{
|
{
|
||||||
ContextHandles ctx;
|
context ctx;
|
||||||
DWORD dwDesiredAccess;
|
DWORD dwDesiredAccess;
|
||||||
DWORD dwProcessId;
|
DWORD dwProcessId;
|
||||||
bool Unloading = false;
|
bool Unloading = false;
|
||||||
@@ -15,55 +18,37 @@ void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, in
|
|||||||
SC_HANDLE hService;
|
SC_HANDLE hService;
|
||||||
SERVICE_NOTIFYW NotifyBuffer;
|
SERVICE_NOTIFYW NotifyBuffer;
|
||||||
|
|
||||||
if ( !InitializeMutex(true,
|
if ( !ctx_create(&ctx,
|
||||||
L"Global\\25020063-b5a7-4227-9fdf-25cb75e8c645",
|
L"Global\\25020063-b5a7-4227-9fdf-25cb75e8c645", 0,
|
||||||
&ctx.hParentMutex) )
|
L"Global\\wufuc_UnloadEvent", L"D:(A;;0x001F0003;;;BA)", 0) )
|
||||||
return;
|
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;
|
dwDesiredAccess = SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG;
|
||||||
do {
|
do {
|
||||||
Lagging = false;
|
Lagging = false;
|
||||||
hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
|
hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
|
||||||
if ( !hSCM ) {
|
if ( !hSCM ) goto delete_ctx;
|
||||||
trace(L"Failed to open SCM. (GetLastError=%lu)", GetLastError());
|
|
||||||
goto close_event;
|
|
||||||
}
|
|
||||||
|
|
||||||
hService = OpenServiceW(hSCM, L"wuauserv", dwDesiredAccess);
|
hService = OpenServiceW(hSCM, L"wuauserv", dwDesiredAccess);
|
||||||
if ( !hService ) {
|
if ( !hService ) goto close_scm;
|
||||||
trace(L"Failed to open service. (GetLastError=%lu)", GetLastError());
|
|
||||||
goto close_scm;
|
|
||||||
}
|
|
||||||
if ( (dwDesiredAccess & SERVICE_QUERY_CONFIG) == SERVICE_QUERY_CONFIG ) {
|
if ( (dwDesiredAccess & SERVICE_QUERY_CONFIG) == SERVICE_QUERY_CONFIG ) {
|
||||||
dwDesiredAccess &= ~SERVICE_QUERY_CONFIG;
|
dwDesiredAccess &= ~SERVICE_QUERY_CONFIG;
|
||||||
|
|
||||||
dwProcessId = HeuristicServiceProcessId(hSCM, hService);
|
dwProcessId = svc_heuristic_process_id(hSCM, hService);
|
||||||
if ( dwProcessId )
|
if ( dwProcessId )
|
||||||
wufuc_InjectLibrary(dwProcessId, &ctx);
|
wufuc_inject(dwProcessId, (LPTHREAD_START_ROUTINE)cb_start, &ctx);
|
||||||
}
|
}
|
||||||
ZeroMemory(&NotifyBuffer, sizeof NotifyBuffer);
|
ZeroMemory(&NotifyBuffer, sizeof NotifyBuffer);
|
||||||
NotifyBuffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
|
NotifyBuffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
|
||||||
NotifyBuffer.pfnNotifyCallback = ServiceNotifyCallback;
|
NotifyBuffer.pfnNotifyCallback = cb_service_notify;
|
||||||
NotifyBuffer.pContext = (PVOID)&ctx;
|
NotifyBuffer.pContext = (PVOID)&ctx;
|
||||||
while ( !Unloading && !Lagging ) {
|
while ( !Unloading && !Lagging ) {
|
||||||
switch ( NotifyServiceStatusChangeW(hService,
|
switch ( NotifyServiceStatusChangeW(hService,
|
||||||
SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_RUNNING,
|
SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_RUNNING,
|
||||||
&NotifyBuffer) ) {
|
&NotifyBuffer) ) {
|
||||||
case ERROR_SUCCESS:
|
case ERROR_SUCCESS:
|
||||||
Unloading = WaitForSingleObjectEx(ctx.hUnloadEvent, INFINITE, TRUE) == WAIT_OBJECT_0;
|
Unloading = WaitForSingleObjectEx(ctx.uevent, INFINITE, TRUE) == WAIT_OBJECT_0;
|
||||||
break;
|
break;
|
||||||
case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING:
|
case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING:
|
||||||
trace(L"Client lagging!");
|
trace(L"Client lagging!");
|
||||||
@@ -75,15 +60,11 @@ void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
CloseServiceHandle(hService);
|
CloseServiceHandle(hService);
|
||||||
close_scm: CloseServiceHandle(hSCM);
|
close_scm:
|
||||||
|
CloseServiceHandle(hSCM);
|
||||||
} while ( Lagging );
|
} while ( Lagging );
|
||||||
close_event:
|
delete_ctx:
|
||||||
CloseHandle(ctx.hUnloadEvent);
|
ctx_delete(&ctx);
|
||||||
close_mutex:
|
|
||||||
ReleaseMutex(ctx.hParentMutex);
|
|
||||||
if ( g_hTracingMutex )
|
|
||||||
CloseHandle(g_hTracingMutex);
|
|
||||||
CloseHandle(ctx.hParentMutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CALLBACK RUNDLL32_UnloadW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
|
void CALLBACK RUNDLL32_UnloadW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "hlpmisc.h"
|
#include "servicehelper.h"
|
||||||
#include "hlpsvc.h"
|
#include "registryhelper.h"
|
||||||
|
|
||||||
LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(
|
LPQUERY_SERVICE_CONFIGW svc_query_config_by_name_alloc(
|
||||||
SC_HANDLE hSCM,
|
SC_HANDLE hSCM,
|
||||||
const wchar_t *pServiceName,
|
const wchar_t *pServiceName,
|
||||||
LPDWORD pcbBufSize)
|
LPDWORD pcbBufSize)
|
||||||
@@ -13,13 +13,13 @@ LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(
|
|||||||
hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_CONFIG);
|
hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_CONFIG);
|
||||||
if ( !hService ) return result;
|
if ( !hService ) return result;
|
||||||
|
|
||||||
result = QueryServiceConfigAlloc(hSCM, hService, pcbBufSize);
|
result = svc_query_config_alloc(hSCM, hService, pcbBufSize);
|
||||||
|
|
||||||
CloseServiceHandle(hService);
|
CloseServiceHandle(hService);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
LPQUERY_SERVICE_CONFIGW QueryServiceConfigAlloc(
|
LPQUERY_SERVICE_CONFIGW svc_query_config_alloc(
|
||||||
SC_HANDLE hSCM,
|
SC_HANDLE hSCM,
|
||||||
SC_HANDLE hService,
|
SC_HANDLE hService,
|
||||||
LPDWORD pcbBufSize)
|
LPDWORD pcbBufSize)
|
||||||
@@ -44,7 +44,7 @@ LPQUERY_SERVICE_CONFIGW QueryServiceConfigAlloc(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QueryServiceStatusProcessInfoByName(
|
bool svc_query_process_info_by_name(
|
||||||
SC_HANDLE hSCM,
|
SC_HANDLE hSCM,
|
||||||
const wchar_t *pServiceName,
|
const wchar_t *pServiceName,
|
||||||
LPSERVICE_STATUS_PROCESS pServiceStatus)
|
LPSERVICE_STATUS_PROCESS pServiceStatus)
|
||||||
@@ -66,7 +66,7 @@ bool QueryServiceStatusProcessInfoByName(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QueryServiceGroupName(
|
bool svc_query_group_name(
|
||||||
const LPQUERY_SERVICE_CONFIGW pServiceConfig,
|
const LPQUERY_SERVICE_CONFIGW pServiceConfig,
|
||||||
wchar_t **pGroupName,
|
wchar_t **pGroupName,
|
||||||
HLOCAL *hMem)
|
HLOCAL *hMem)
|
||||||
@@ -92,7 +92,7 @@ bool QueryServiceGroupName(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD QueryServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService)
|
DWORD svc_query_process_id(SC_HANDLE hSCM, SC_HANDLE hService)
|
||||||
{
|
{
|
||||||
DWORD result = 0;
|
DWORD result = 0;
|
||||||
SERVICE_STATUS_PROCESS ServiceStatus;
|
SERVICE_STATUS_PROCESS ServiceStatus;
|
||||||
@@ -109,16 +109,16 @@ DWORD QueryServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService)
|
|||||||
return result;
|
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;
|
SERVICE_STATUS_PROCESS ServiceStatusProcess;
|
||||||
|
|
||||||
if ( QueryServiceStatusProcessInfoByName(hSCM, pServiceName, &ServiceStatusProcess) )
|
if ( svc_query_process_info_by_name(hSCM, pServiceName, &ServiceStatusProcess) )
|
||||||
return ServiceStatusProcess.dwProcessId;
|
return ServiceStatusProcess.dwProcessId;
|
||||||
return 0;
|
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;
|
wchar_t *pData;
|
||||||
DWORD result = 0;
|
DWORD result = 0;
|
||||||
@@ -129,7 +129,7 @@ DWORD HeuristicServiceGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupNameSe
|
|||||||
wchar_t *pGroupName;
|
wchar_t *pGroupName;
|
||||||
HLOCAL hMem;
|
HLOCAL hMem;
|
||||||
|
|
||||||
pData = RegGetValueAlloc(HKEY_LOCAL_MACHINE,
|
pData = reg_get_value_alloc(HKEY_LOCAL_MACHINE,
|
||||||
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost",
|
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost",
|
||||||
pGroupNameSearch,
|
pGroupNameSearch,
|
||||||
RRF_RT_REG_MULTI_SZ,
|
RRF_RT_REG_MULTI_SZ,
|
||||||
@@ -139,14 +139,14 @@ DWORD HeuristicServiceGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupNameSe
|
|||||||
if ( !pData ) return result;
|
if ( !pData ) return result;
|
||||||
|
|
||||||
for ( wchar_t *pName = pData; *pName; pName += wcslen(pName) + 1 ) {
|
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;
|
if ( !dwProcessId ) continue;
|
||||||
|
|
||||||
pServiceConfig = QueryServiceConfigByNameAlloc(hSCM, pName, &cbBufSize);
|
pServiceConfig = svc_query_config_by_name_alloc(hSCM, pName, &cbBufSize);
|
||||||
if ( !pServiceConfig ) continue;
|
if ( !pServiceConfig ) continue;
|
||||||
|
|
||||||
if ( pServiceConfig->dwServiceType == SERVICE_WIN32_SHARE_PROCESS
|
if ( pServiceConfig->dwServiceType == SERVICE_WIN32_SHARE_PROCESS
|
||||||
&& QueryServiceGroupName(pServiceConfig, &pGroupName, &hMem) ) {
|
&& svc_query_group_name(pServiceConfig, &pGroupName, &hMem) ) {
|
||||||
|
|
||||||
success = !_wcsicmp(pGroupNameSearch, pGroupName);
|
success = !_wcsicmp(pGroupNameSearch, pGroupName);
|
||||||
LocalFree(hMem);
|
LocalFree(hMem);
|
||||||
@@ -161,18 +161,18 @@ DWORD HeuristicServiceGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupNameSe
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD HeuristicServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService)
|
DWORD svc_heuristic_process_id(SC_HANDLE hSCM, SC_HANDLE hService)
|
||||||
{
|
{
|
||||||
DWORD result = 0;
|
DWORD result = 0;
|
||||||
LPQUERY_SERVICE_CONFIGW pServiceConfig;
|
LPQUERY_SERVICE_CONFIGW pServiceConfig;
|
||||||
wchar_t *pGroupName;
|
wchar_t *pGroupName;
|
||||||
HLOCAL hMem;
|
HLOCAL hMem;
|
||||||
|
|
||||||
result = QueryServiceProcessId(hSCM, hService);
|
result = svc_query_process_id(hSCM, hService);
|
||||||
if ( result )
|
if ( result )
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
pServiceConfig = QueryServiceConfigAlloc(hSCM, hService, NULL);
|
pServiceConfig = svc_query_config_alloc(hSCM, hService, NULL);
|
||||||
if ( pServiceConfig ) {
|
if ( pServiceConfig ) {
|
||||||
switch ( pServiceConfig->dwServiceType ) {
|
switch ( pServiceConfig->dwServiceType ) {
|
||||||
case SERVICE_WIN32_OWN_PROCESS:
|
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
|
// process, it is possible to "guess" which svchost.exe
|
||||||
// it will eventually be loaded into by finding other
|
// it will eventually be loaded into by finding other
|
||||||
// services in the same group that are already running.
|
// services in the same group that are already running.
|
||||||
if ( QueryServiceGroupName(pServiceConfig, &pGroupName, &hMem) ) {
|
if ( svc_query_group_name(pServiceConfig, &pGroupName, &hMem) ) {
|
||||||
result = HeuristicServiceGroupProcessId(hSCM, pGroupName);
|
result = svc_heuristic_group_process_id(hSCM, pGroupName);
|
||||||
LocalFree(hMem);
|
LocalFree(hMem);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -196,13 +196,13 @@ DWORD HeuristicServiceProcessId(SC_HANDLE hSCM, SC_HANDLE hService)
|
|||||||
return result;
|
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;
|
DWORD result = 0;
|
||||||
SC_HANDLE hService;
|
SC_HANDLE hService;
|
||||||
|
|
||||||
hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
|
hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
|
||||||
result = HeuristicServiceProcessId(hSCM, hService);
|
result = svc_heuristic_process_id(hSCM, hService);
|
||||||
CloseServiceHandle(hService);
|
CloseServiceHandle(hService);
|
||||||
return result;
|
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 <Psapi.h>
|
||||||
#include <TlHelp32.h>
|
#include <TlHelp32.h>
|
||||||
|
|
||||||
#include <detours.h>
|
|
||||||
#include "patternfind.h"
|
|
||||||
#include "tracing.h"
|
|
||||||
|
|
||||||
extern IMAGE_DOS_HEADER __ImageBase;
|
extern IMAGE_DOS_HEADER __ImageBase;
|
||||||
#define PIMAGEBASE ((HMODULE)&__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 "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;
|
||||||
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;
|
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;
|
bool result = false;
|
||||||
UINT cbData;
|
UINT cbData;
|
||||||
@@ -44,8 +44,9 @@ bool GetVersionInfoFromHModule(HMODULE hModule, const wchar_t *pszSubBlock, LPVO
|
|||||||
if ( !pRes ) return result;
|
if ( !pRes ) return result;
|
||||||
|
|
||||||
pCopy = malloc(dwSize);
|
pCopy = malloc(dwSize);
|
||||||
if ( !pCopy
|
if ( !pCopy ) return result;
|
||||||
|| memcpy_s(pCopy, dwSize, pRes, dwSize)
|
|
||||||
|
if ( memcpy_s(pCopy, dwSize, pRes, dwSize)
|
||||||
|| !VerQueryValueW(pCopy, pszSubBlock, &pBuffer, &uLen) )
|
|| !VerQueryValueW(pCopy, pszSubBlock, &pBuffer, &uLen) )
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@@ -68,18 +69,18 @@ cleanup:
|
|||||||
return result;
|
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;
|
UINT cbData = 0;
|
||||||
LPVOID result = NULL;
|
LPVOID result = NULL;
|
||||||
|
|
||||||
if ( !GetVersionInfoFromHModule(hModule, pszSubBlock, NULL, &cbData) )
|
if ( !ver_get_version_info_from_hmodule(hModule, pszSubBlock, NULL, &cbData) )
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
result = malloc(cbData);
|
result = malloc(cbData);
|
||||||
if ( !result ) return result;
|
if ( !result ) return result;
|
||||||
|
|
||||||
if ( GetVersionInfoFromHModule(hModule, pszSubBlock, result, &cbData) ) {
|
if ( ver_get_version_info_from_hmodule(hModule, pszSubBlock, result, &cbData) ) {
|
||||||
*pcbData = cbData;
|
*pcbData = cbData;
|
||||||
} else {
|
} else {
|
||||||
free(result);
|
free(result);
|
||||||
@@ -88,7 +89,7 @@ LPVOID GetVersionInfoFromHModuleAlloc(HMODULE hModule, const wchar_t *pszSubBloc
|
|||||||
return result;
|
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 };
|
OSVERSIONINFOEXW osvi = { sizeof osvi };
|
||||||
|
|
||||||
@@ -105,3 +106,13 @@ bool IsWindowsVersion(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackM
|
|||||||
VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR,
|
VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR,
|
||||||
dwlConditionMask) != FALSE;
|
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>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="callbacks.h" />
|
<ClInclude Include="callbacks.h" />
|
||||||
<ClInclude Include="hlpmem.h" />
|
<ClInclude Include="context.h" />
|
||||||
<ClInclude Include="hlpmisc.h" />
|
<ClInclude Include="log.h" />
|
||||||
<ClInclude Include="hlpsvc.h" />
|
<ClInclude Include="modulehelper.h" />
|
||||||
<ClInclude Include="hlpver.h" />
|
<ClInclude Include="registryhelper.h" />
|
||||||
|
<ClInclude Include="servicehelper.h" />
|
||||||
|
<ClInclude Include="versionhelper.h" />
|
||||||
<ClInclude Include="hooks.h" />
|
<ClInclude Include="hooks.h" />
|
||||||
<ClInclude Include="patternfind.h" />
|
<ClInclude Include="patternfind.h" />
|
||||||
<ClInclude Include="stdafx.h" />
|
<ClInclude Include="stdafx.h" />
|
||||||
<ClInclude Include="targetver.h" />
|
<ClInclude Include="targetver.h" />
|
||||||
<ClInclude Include="tracing.h" />
|
<ClInclude Include="wufuc.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="callbacks.c" />
|
<ClCompile Include="callbacks.c" />
|
||||||
|
<ClCompile Include="context.c" />
|
||||||
<ClCompile Include="dllmain.c" />
|
<ClCompile Include="dllmain.c" />
|
||||||
<ClCompile Include="hlpmem.c" />
|
<ClCompile Include="modulehelper.c" />
|
||||||
<ClCompile Include="hlpmisc.c" />
|
<ClCompile Include="registryhelper.c" />
|
||||||
<ClCompile Include="hlpsvc.c" />
|
<ClCompile Include="servicehelper.c" />
|
||||||
<ClCompile Include="hlpver.c" />
|
<ClCompile Include="versionhelper.c" />
|
||||||
<ClCompile Include="hooks.c" />
|
<ClCompile Include="hooks.c" />
|
||||||
|
<ClCompile Include="log.c" />
|
||||||
<ClCompile Include="patternfind.c" />
|
<ClCompile Include="patternfind.c" />
|
||||||
<ClCompile Include="stdafx.c">
|
<ClCompile Include="stdafx.c">
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||||
@@ -46,7 +50,7 @@
|
|||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="rundll32.c" />
|
<ClCompile Include="rundll32.c" />
|
||||||
<ClCompile Include="tracing.c" />
|
<ClCompile Include="wufuc.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="exports.def" />
|
<None Include="exports.def" />
|
||||||
@@ -115,8 +119,8 @@
|
|||||||
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
|
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
|
||||||
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
|
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
|
||||||
<GenerateManifest>false</GenerateManifest>
|
<GenerateManifest>false</GenerateManifest>
|
||||||
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\detours;$(IncludePath)</IncludePath>
|
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath)</IncludePath>
|
||||||
<LibraryPath>$(SolutionDir)..\lib\detours;$(LibraryPath)</LibraryPath>
|
<LibraryPath>$(SolutionDir)..\lib\minhook;$(LibraryPath)</LibraryPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<LinkIncremental>true</LinkIncremental>
|
<LinkIncremental>true</LinkIncremental>
|
||||||
@@ -124,26 +128,26 @@
|
|||||||
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
|
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
|
||||||
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
|
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
|
||||||
<GenerateManifest>false</GenerateManifest>
|
<GenerateManifest>false</GenerateManifest>
|
||||||
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\detours;$(IncludePath)</IncludePath>
|
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath)</IncludePath>
|
||||||
<LibraryPath>$(SolutionDir)..\lib\detours;$(LibraryPath)</LibraryPath>
|
<LibraryPath>$(SolutionDir)..\lib\minhook;$(LibraryPath)</LibraryPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<LinkIncremental>false</LinkIncremental>
|
<LinkIncremental>false</LinkIncremental>
|
||||||
<OutDir>$(ProjectDir)bin\$(Configuration)\$(PlatformShortName)\</OutDir>
|
<OutDir>$(ProjectDir)bin\$(Configuration)\$(PlatformShortName)\</OutDir>
|
||||||
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
|
<IntDir>$(ProjectDir)obj\$(Configuration)\$(PlatformShortName)\</IntDir>
|
||||||
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
|
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
|
||||||
<GenerateManifest>false</GenerateManifest>
|
<GenerateManifest>false</GenerateManifest>
|
||||||
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\detours;$(IncludePath)</IncludePath>
|
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath)</IncludePath>
|
||||||
<LibraryPath>$(SolutionDir)..\lib\detours;$(LibraryPath)</LibraryPath>
|
<LibraryPath>$(SolutionDir)..\lib\minhook;$(LibraryPath)</LibraryPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<LinkIncremental>false</LinkIncremental>
|
<LinkIncremental>false</LinkIncremental>
|
||||||
<OutDir>$(ProjectDir)bin\$(Configuration)\$(PlatformShortName)\</OutDir>
|
<OutDir>$(ProjectDir)bin\$(Configuration)\$(PlatformShortName)\</OutDir>
|
||||||
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
|
<IntDir>$(ProjectDir)obj\$(Configuration)\$(PlatformShortName)\</IntDir>
|
||||||
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
|
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
|
||||||
<GenerateManifest>false</GenerateManifest>
|
<GenerateManifest>false</GenerateManifest>
|
||||||
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\detours;$(IncludePath)</IncludePath>
|
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath)</IncludePath>
|
||||||
<LibraryPath>$(SolutionDir)..\lib\detours;$(LibraryPath)</LibraryPath>
|
<LibraryPath>$(SolutionDir)..\lib\minhook;$(LibraryPath)</LibraryPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
@@ -162,7 +166,7 @@
|
|||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
||||||
<EntryPointSymbol>
|
<EntryPointSymbol>
|
||||||
</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>
|
</Link>
|
||||||
<ResourceCompile>
|
<ResourceCompile>
|
||||||
<PreprocessorDefinitions>X86;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>X86;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
@@ -185,7 +189,7 @@
|
|||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
||||||
<EntryPointSymbol>
|
<EntryPointSymbol>
|
||||||
</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>
|
</Link>
|
||||||
<ResourceCompile>
|
<ResourceCompile>
|
||||||
<PreprocessorDefinitions>X64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>X64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
@@ -216,7 +220,7 @@
|
|||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
||||||
<EntryPointSymbol>
|
<EntryPointSymbol>
|
||||||
</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>
|
<SetChecksum>true</SetChecksum>
|
||||||
</Link>
|
</Link>
|
||||||
<ResourceCompile>
|
<ResourceCompile>
|
||||||
@@ -253,7 +257,7 @@ copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup\"</Command>
|
|||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
<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>
|
<SetChecksum>true</SetChecksum>
|
||||||
</Link>
|
</Link>
|
||||||
<ResourceCompile>
|
<ResourceCompile>
|
||||||
|
@@ -21,9 +21,6 @@
|
|||||||
<ClInclude Include="hooks.h">
|
<ClInclude Include="hooks.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="tracing.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="targetver.h">
|
<ClInclude Include="targetver.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -33,16 +30,25 @@
|
|||||||
<ClInclude Include="patternfind.h">
|
<ClInclude Include="patternfind.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="hlpmem.h">
|
<ClInclude Include="context.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="hlpmisc.h">
|
<ClInclude Include="versionhelper.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="hlpsvc.h">
|
<ClInclude Include="servicehelper.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</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>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -56,9 +62,6 @@
|
|||||||
<ClCompile Include="hooks.c">
|
<ClCompile Include="hooks.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="tracing.c">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="rundll32.c">
|
<ClCompile Include="rundll32.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -68,16 +71,25 @@
|
|||||||
<ClCompile Include="patternfind.c">
|
<ClCompile Include="patternfind.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="hlpsvc.c">
|
<ClCompile Include="context.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="hlpmem.c">
|
<ClCompile Include="servicehelper.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="hlpver.c">
|
<ClCompile Include="versionhelper.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</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>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
Reference in New Issue
Block a user