move source files to src folder, some code updates..

This commit is contained in:
zeffy
2018-02-05 13:50:11 -08:00
parent 0dd4b0488b
commit f1dc539aba
50 changed files with 413 additions and 364 deletions

165
src/wufuc/callbacks.c Normal file
View File

@@ -0,0 +1,165 @@
#include "stdafx.h"
#include "callbacks.h"
#include "hooks.h"
#include "hlpmisc.h"
#include "hlpmem.h"
#include "hlpsvc.h"
bool DuplicateContextHandles(HANDLE hSrcProcess, ContextHandles *pSrcContext, HANDLE hAuxiliaryMutex, HANDLE hTargetProcess, ContextHandles *pTargetContext)
{
return
DuplicateHandle(hSrcProcess, pSrcContext->hMainMutex,
hTargetProcess, &pTargetContext->hMainMutex, SYNCHRONIZE, FALSE, 0)
&& DuplicateHandle(hSrcProcess, pSrcContext->hUnloadEvent,
hTargetProcess, &pTargetContext->hUnloadEvent, SYNCHRONIZE, FALSE, 0)
&& DuplicateHandle(hSrcProcess, hAuxiliaryMutex,
hTargetProcess, &pTargetContext->hAuxiliaryMutex, 0, FALSE, DUPLICATE_SAME_ACCESS);
}
VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer)
{
HANDLE hProcess;
wchar_t MutexName[44];
HANDLE hAuxiliaryMutex;
ContextHandles TargetContext;
switch ( pNotifyBuffer->dwNotificationStatus ) {
case ERROR_SUCCESS:
if ( !pNotifyBuffer->ServiceStatus.dwProcessId
|| swprintf_s(MutexName, _countof(MutexName),
L"Global\\%08x-7132-44a8-be15-56698979d2f3",
pNotifyBuffer->ServiceStatus.dwProcessId) == -1
|| !InitializeMutex(false, MutexName, &hAuxiliaryMutex) )
break;
hProcess = OpenProcess(PROCESS_ALL_ACCESS,
FALSE,
pNotifyBuffer->ServiceStatus.dwProcessId);
if ( !hProcess ) {
trace(L"Failed to open target process! (GetLastError=%lu)", GetLastError());
break;
};
if ( !DuplicateContextHandles(GetCurrentProcess(), pNotifyBuffer->pContext, hAuxiliaryMutex, hProcess, &TargetContext) ) {
trace(L"Failed to duplicate handles into target process."
L"%p %p %p (GetLastError=%lu)",
TargetContext.hMainMutex,
TargetContext.hUnloadEvent,
TargetContext.hAuxiliaryMutex,
GetLastError());
break;
};
InjectLibraryAndCreateRemoteThread(
hProcess,
PIMAGEBASE,
StartAddress,
&TargetContext,
sizeof TargetContext);
break;
case ERROR_SERVICE_MARKED_FOR_DELETE:
SetEvent((HANDLE)pNotifyBuffer->pContext);
break;
}
if ( pNotifyBuffer->pszServiceNames )
LocalFree((HLOCAL)pNotifyBuffer->pszServiceNames);
}
DWORD WINAPI StartAddress(LPVOID pParam)
{
ContextHandles ctx;
SC_HANDLE hSCM;
DWORD dwProcessId;
DWORD cbData;
HMODULE hModule;
DWORD result;
// get mutex and unload event handles from virtual memory
if ( !pParam ) {
trace(L"Context parameter is null!");
goto unload;
}
ctx = *(ContextHandles *)pParam;
if ( !VirtualFree(pParam, 0, MEM_RELEASE) )
trace(L"Failed to free context parameter. pParam=%p GetLastError=%lu",
pParam, GetLastError());
// acquire child mutex, should be immediate.
if ( WaitForSingleObject(ctx.hAuxiliaryMutex, 5000) != WAIT_OBJECT_0 ) {
trace(L"Failed to acquire aux mutex within five seconds. hAuxiliaryMutex=%p", ctx.hAuxiliaryMutex);
goto close_handles;
}
hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
if ( !hSCM ) {
trace(L"Failed to open SCM. (GetLastError=%ul)", GetLastError());
goto release;
}
dwProcessId = QueryServiceProcessId(hSCM, L"wuauserv");
CloseServiceHandle(hSCM);
if ( dwProcessId != GetCurrentProcessId() ) {
trace(L"Injected into wrong process! CurrentProcessId=%lu wuauserv ProcessId=%lu",
GetCurrentProcessId, dwProcessId);
goto release;
}
// hook IsDeviceServiceable
g_pszWUServiceDll = RegGetValueAlloc(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\services\\wuauserv\\Parameters",
L"ServiceDll",
RRF_RT_REG_SZ,
NULL,
&cbData);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
// hook LoadLibraryExW
g_pfnLoadLibraryExW = DetourFindFunction("kernel32.dll", "LoadLibraryExW");
if ( g_pfnLoadLibraryExW )
DetourAttach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook);
if ( g_pszWUServiceDll ) {
hModule = GetModuleHandleW(g_pszWUServiceDll);
if ( hModule && FindIsDeviceServiceablePtr(hModule,
&(PVOID)g_pfnIsDeviceServiceable) ) {
DetourAttach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook);
}
}
DetourTransactionCommit();
// wait for unload event or parent mutex to be abandoned.
// for example if the user killed rundll32.exe with task manager.
// intentionally leave parent mutex open until this thread ends, at
// which point it becomes abandoned again.
result = WaitForMultipleObjects(_countof(ctx.handles), ctx.handles, FALSE, INFINITE);
trace(L"Unloading!");
// unhook
if ( g_pfnLoadLibraryExW || g_pfnIsDeviceServiceable ) {
trace(L"Removing hooks...");
trace(L"DetourTransactionBegin %lu", DetourTransactionBegin());
trace(L"DetourUpdateThread %lu", DetourUpdateThread(GetCurrentThread()));
if ( g_pfnLoadLibraryExW )
trace(L"DetourDetach LoadLibraryExW %lu", DetourDetach(&(PVOID)g_pfnLoadLibraryExW, LoadLibraryExW_hook));
if ( g_pfnIsDeviceServiceable )
trace(L"DetourDetach IsDeviceServiceable %lu", DetourDetach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook));
trace(L"DetourTransactionCommit %lu", DetourTransactionCommit());
}
free(g_pszWUServiceDll);
release:
ReleaseMutex(ctx.hAuxiliaryMutex);
close_handles:
CloseHandle(ctx.hAuxiliaryMutex);
CloseHandle(ctx.hMainMutex);
CloseHandle(ctx.hUnloadEvent);
unload:
FreeLibraryAndExitThread(PIMAGEBASE, 0);
}

25
src/wufuc/callbacks.h Normal file
View File

@@ -0,0 +1,25 @@
#pragma once
#pragma pack(push, 1)
typedef struct
{
HANDLE hAuxiliaryMutex;
union
{
struct
{
HANDLE hMainMutex;
HANDLE hUnloadEvent;
} DUMMYSTRUCTNAME;
struct
{
HANDLE hMainMutex;
HANDLE hUnloadEvent;
} u;
HANDLE handles[2];
};
} ContextHandles;
#pragma pack(pop)
VOID CALLBACK ServiceNotifyCallback(PSERVICE_NOTIFYW pNotifyBuffer);
DWORD WINAPI StartAddress(LPVOID pParam);

16
src/wufuc/dllmain.c Normal file
View File

@@ -0,0 +1,16 @@
#include "stdafx.h"
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch ( ul_reason_for_call ) {
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

5
src/wufuc/exports.def Normal file
View File

@@ -0,0 +1,5 @@
LIBRARY
EXPORTS
RUNDLL32_StartW @1
RUNDLL32_UnloadW @2
RUNDLL32_DeleteFileW @3

265
src/wufuc/hlpmem.c Normal file
View File

@@ -0,0 +1,265 @@
#include "stdafx.h"
#include "hlpmem.h"
#include "hlpver.h"
#include "hooks.h"
#include <sddl.h>
bool FindIsDeviceServiceablePtr(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;
is_win7 = IsWindowsVersion(6, 1, 1);
if ( !is_win7 ) {
is_win81 = IsWindowsVersion(6, 3, 0);
if ( !is_win81 ) {
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. pInternalName=%ls cbInternalName=%lu", pInternalName, cbInternalName);
free(pInternalName);
if ( tmp )
continue;
pffi = GetVersionInfoFromHModuleAlloc(hModule, L"\\", &cbffi);
if ( !pffi ) {
trace(L"Failed to allocate version information from hmodule.");
continue;
}
// assure wuaueng.dll is at least the minimum supported version
tmp = ((is_win7 && FileInfoVerCompare(pffi, 7, 6, 7601, 23714) != -1)
|| (is_win81 && FileInfoVerCompare(pffi, 7, 9, 9600, 18621) != -1));
free(pffi);
if ( !tmp ) {
trace(L"Module does not meet the minimum supported version.");
continue;
}
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 ) {
*ppfnIsDeviceServiceable = (PVOID)((uint8_t *)modinfo.lpBaseOfDll + offset);
trace(L"Found IsDeviceServiceable address: %p", *ppfnIsDeviceServiceable);
result = true;
} else {
trace(L"IsDeviceServiceable function pattern not found.");
}
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;
trace(L"Suspended process. hProcess=%p", hProcess);
if ( pParam ) {
// this gets freed by 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) ) {
trace(L"Injected library. hRemoteModule=%p", hRemoteModule);
hThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)((uint8_t *)hRemoteModule + ((uint8_t *)pStartAddress - (uint8_t *)hModule)),
pBaseAddress,
0,
NULL);
if ( hThread ) {
trace(L"Created remote thread. hThread=%p", 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 ) {
trace(L"Got module filename for local module. "
L"hModule=%p Filename=%ls nLength=%lu",
hModule, Filename, 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;
trace(L"Suspended process. hProcess=%p", hProcess);
dwProcessId = GetProcessId(hProcess);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
if ( !hSnapshot ) goto resume;
trace(L"Created TH32 module snapshot. dwProcessId=%lu", dwProcessId);
*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;
trace(L"Allocated virtual memory in process. hProcess=%p pBaseAddress=%p nSize=%Iu",
hProcess, pBaseAddress, nSize);
if ( !WriteProcessMemory(hProcess, pBaseAddress, pLibFilename, nSize, NULL) )
goto vfree;
trace(L"Wrote to process memory. hProcess=%p pBaseAddress=%p pLibFileName=%.*ls nSize=%Iu",
hProcess, pBaseAddress, cchLibFilename, pLibFilename, nSize);
hThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)LoadLibraryW,
pBaseAddress,
0,
NULL);
if ( !hThread ) goto vfree;
trace(L"Created remote thread. hThread=%p", hThread);
WaitForSingleObject(hThread, INFINITE);
trace(L"Created thread finished running. hThread=%p", hThread);
if ( sizeof *phRemoteModule > sizeof(DWORD) ) {
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
if ( hSnapshot ) {
*phRemoteModule = GetRemoteHModuleFromTh32ModuleSnapshot(
hSnapshot,
pLibFilename);
CloseHandle(hSnapshot);
result = !!*phRemoteModule;
}
} else {
result = !!GetExitCodeThread(hThread, (LPDWORD)phRemoteModule);
}
CloseHandle(hThread);
vfree: VirtualFreeEx(hProcess, pBaseAddress, 0, MEM_RELEASE);
resume: NtResumeProcess(hProcess);
return result;
}

22
src/wufuc/hlpmem.h Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
typedef struct
{
WORD wLanguage;
WORD wCodePage;
} LANGANDCODEPAGE, *PLANGANDCODEPAGE;
bool FindIsDeviceServiceablePtr(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);

70
src/wufuc/hlpmisc.c Normal file
View File

@@ -0,0 +1,70 @@
#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;
}
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 ) {
*pcbData = cbData;
} else {
free(result);
result = NULL;
}
return result;
}

16
src/wufuc/hlpmisc.h Normal file
View File

@@ -0,0 +1,16 @@
#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);

118
src/wufuc/hlpsvc.c Normal file
View File

@@ -0,0 +1,118 @@
#include "stdafx.h"
#include "hlpmisc.h"
#include "hlpsvc.h"
LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(
SC_HANDLE hSCM,
const wchar_t *pServiceName,
LPDWORD pcbBufSize)
{
SC_HANDLE hService;
DWORD cbBytesNeeded;
LPQUERY_SERVICE_CONFIGW result = NULL;
hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_CONFIG);
if ( !hService ) return result;
if ( !QueryServiceConfigW(hService, NULL, 0, &cbBytesNeeded)
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
result = malloc(cbBytesNeeded);
if ( result ) {
if ( QueryServiceConfigW(hService, result, cbBytesNeeded, &cbBytesNeeded) ) {
*pcbBufSize = cbBytesNeeded;
} else {
free(result);
result = NULL;
}
}
}
CloseServiceHandle(hService);
return result;
}
bool QueryServiceStatusProcessInfoByName(
SC_HANDLE hSCM,
const wchar_t *pServiceName,
LPSERVICE_STATUS_PROCESS pServiceStatus)
{
bool result = false;
SC_HANDLE hService;
DWORD cbBytesNeeded;
hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_STATUS);
if ( !hService ) {
trace(L"Failed to open service %ls! (GetLastError=%ul)", pServiceName, GetLastError());
return result;
}
result = !!QueryServiceStatusEx(hService,
SC_STATUS_PROCESS_INFO,
(LPBYTE)pServiceStatus,
sizeof *pServiceStatus,
&cbBytesNeeded);
CloseServiceHandle(hService);
return result;
}
bool QueryServiceGroupName(const LPQUERY_SERVICE_CONFIGW pServiceConfig, wchar_t *pGroupName, size_t nSize)
{
bool result = false;
int NumArgs;
LPWSTR *argv;
argv = CommandLineToArgvW(pServiceConfig->lpBinaryPathName, &NumArgs);
if ( argv ) {
if ( !_wcsicmp(PathFindFileNameW(argv[0]), L"svchost.exe") ) {
for ( int i = 1; (i + 1) < NumArgs; i++ ) {
if ( !_wcsicmp(argv[i], L"-k") )
return !wcscpy_s(pGroupName, nSize, argv[++i]);
}
}
LocalFree((HLOCAL)argv);
}
return result;
}
DWORD QueryServiceProcessId(SC_HANDLE hSCM, const wchar_t *pServiceName)
{
SERVICE_STATUS_PROCESS ServiceStatusProcess;
if ( QueryServiceStatusProcessInfoByName(hSCM, pServiceName, &ServiceStatusProcess) )
return ServiceStatusProcess.dwProcessId;
return 0;
}
DWORD InferSvchostGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupName)
{
DWORD result = 0;
DWORD cbData;
wchar_t *pData;
DWORD dwProcessId;
DWORD cbBufSize;
LPQUERY_SERVICE_CONFIGW pServiceConfig;
bool success;
WCHAR GroupName[256];
pData = RegGetValueAlloc(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost", pGroupName, RRF_RT_REG_MULTI_SZ, NULL, &cbData);
if ( !pData ) return result;
for ( wchar_t *pName = pData; *pName; pName += wcslen(pName) + 1 ) {
dwProcessId = QueryServiceProcessId(hSCM, pName);
trace(L"pName=%ls dwProcessId=%lu", pName, dwProcessId);
if ( !dwProcessId ) continue;
pServiceConfig = QueryServiceConfigByNameAlloc(hSCM, pName, &cbBufSize);
if ( !pServiceConfig ) continue;
success = QueryServiceGroupName(pServiceConfig, GroupName, _countof(GroupName));
free(pServiceConfig);
if ( success && !_wcsicmp(pGroupName, GroupName) ) {
trace(L"found PID for group %ls: %lu", pGroupName, dwProcessId);
result = dwProcessId;
break;
}
}
free(pData);
return result;
}

13
src/wufuc/hlpsvc.h Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
LPQUERY_SERVICE_CONFIGW QueryServiceConfigByNameAlloc(
SC_HANDLE hSCM,
const wchar_t *pServiceName,
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, size_t nSize);
DWORD QueryServiceProcessId(SC_HANDLE hSCM, const wchar_t *pServiceName);
DWORD InferSvchostGroupProcessId(SC_HANDLE hSCM, const wchar_t *pGroupName);

107
src/wufuc/hlpver.c Normal file
View File

@@ -0,0 +1,107 @@
#include "stdafx.h"
#include "hlpver.h"
int FileInfoVerCompare(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 ( LOWORD(pffi->dwProductVersionMS) < wMinor ) return -1;
if ( LOWORD(pffi->dwProductVersionMS) > wMinor ) return 1;
if ( HIWORD(pffi->dwProductVersionLS) < wBuild ) return -1;
if ( HIWORD(pffi->dwProductVersionLS) > wBuild ) return 1;
if ( LOWORD(pffi->dwProductVersionLS) < wRev ) return -1;
if ( LOWORD(pffi->dwProductVersionLS) > wRev ) return 1;
return 0;
}
bool GetVersionInfoFromHModule(HMODULE hModule, LPCWSTR pszSubBlock, LPVOID pData, PUINT pcbData)
{
bool result = false;
UINT cbData;
HRSRC hResInfo;
DWORD dwSize;
HGLOBAL hResData;
LPVOID pRes;
LPVOID pCopy;
LPVOID pBuffer;
UINT uLen;
if ( !pcbData ) return result;
cbData = *pcbData;
hResInfo = FindResourceW(hModule,
MAKEINTRESOURCEW(VS_VERSION_INFO),
RT_VERSION);
if ( !hResInfo ) return result;
dwSize = SizeofResource(hModule, hResInfo);
if ( !dwSize ) return result;
hResData = LoadResource(hModule, hResInfo);
if ( !hResData ) return result;
pRes = LockResource(hResData);
if ( !pRes ) return result;
pCopy = malloc(dwSize);
if ( !pCopy
|| memcpy_s(pCopy, dwSize, pRes, dwSize)
|| !VerQueryValueW(pCopy, pszSubBlock, &pBuffer, &uLen) )
goto cleanup;
if ( !_wcsnicmp(pszSubBlock, L"\\StringFileInfo\\", 16) )
*pcbData = uLen * sizeof(wchar_t);
else
*pcbData = uLen;
if ( !pData ) {
result = true;
goto cleanup;
}
if ( cbData < *pcbData
|| memcpy_s(pData, cbData, pBuffer, *pcbData) )
goto cleanup;
result = true;
cleanup:
free(pCopy);
return result;
}
LPVOID GetVersionInfoFromHModuleAlloc(HMODULE hModule, LPCWSTR pszSubBlock, PUINT pcbData)
{
UINT cbData = 0;
LPVOID result = NULL;
if ( !GetVersionInfoFromHModule(hModule, pszSubBlock, NULL, &cbData) )
return result;
result = malloc(cbData);
if ( !result ) return result;
if ( GetVersionInfoFromHModule(hModule, pszSubBlock, result, &cbData) ) {
*pcbData = cbData;
} else {
free(result);
result = NULL;
}
return result;
}
bool IsWindowsVersion(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
{
OSVERSIONINFOEXW osvi = { sizeof osvi };
DWORDLONG dwlConditionMask = 0;
VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_EQUAL);
VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_EQUAL);
VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
osvi.dwMajorVersion = wMajorVersion;
osvi.dwMinorVersion = wMinorVersion;
osvi.wServicePackMajor = wServicePackMajor;
return VerifyVersionInfoW(&osvi,
VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR,
dwlConditionMask) != FALSE;
}

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

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

35
src/wufuc/hooks.c Normal file
View File

@@ -0,0 +1,35 @@
#include "stdafx.h"
#include "hooks.h"
#include "hlpmem.h"
#include "hlpmisc.h"
#include "hlpsvc.h"
LPWSTR g_pszWUServiceDll;
LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceable;
LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW;
HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags)
{
HMODULE result;
result = g_pfnLoadLibraryExW(lpFileName, hFile, dwFlags);
if ( !result ) return result;
trace(L"Loaded library. lpFileName=%ls result=%p", lpFileName, result);
if ( g_pszWUServiceDll
&& !_wcsicmp(lpFileName, g_pszWUServiceDll)
&& FindIsDeviceServiceablePtr(result, &(PVOID)g_pfnIsDeviceServiceable) ) {
trace(L"DetourTransactionBegin=%lu", DetourTransactionBegin());
trace(L"DetourUpdateThread=%lu", DetourUpdateThread(GetCurrentThread()));
trace(L"DetourAttach=%lu", DetourAttach(&(PVOID)g_pfnIsDeviceServiceable, IsDeviceServiceable_hook));
trace(L"DetourTransactionCommit=%lu", DetourTransactionCommit());
}
return result;
}
BOOL WINAPI IsDeviceServiceable_hook(void)
{
return TRUE;
}

13
src/wufuc/hooks.h Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
typedef HMODULE(WINAPI *LPFN_LOADLIBRARYEXW)(LPCWSTR, HANDLE, DWORD);
typedef BOOL(WINAPI *LPFN_ISDEVICESERVICEABLE)(void);
extern LPWSTR g_pszWUServiceDll;
extern LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW;
extern LPFN_ISDEVICESERVICEABLE g_pfnIsDeviceServiceable;
HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags);
BOOL WINAPI IsDeviceServiceable_hook(void);

View File

@@ -0,0 +1,11 @@
Based on mrexodia's patternfind code originally written in C++
Licensed under Lesser GNU Public License 3.0
https://bitbucket.org/mrexodia/patternfind
Changes made:
- Ported to C, removed dependency on C++ type vector<T>
- Uses stdint.h type uint8_t instead of unsigned char (for readability)
- Renamed patternfind overloads to patternfind, patternfind_bytes, patternfind_pbyte
- Added VirtualProtect calls to patternwrite function to prevent access violation exceptions

View File

@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

181
src/wufuc/patternfind.c Normal file
View File

@@ -0,0 +1,181 @@
#include "stdafx.h"
#include "patternfind.h"
static inline bool isHex(char ch)
{
return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f');
}
static inline int hexchtoint(char ch)
{
if ( ch >= '0' && ch <= '9' )
return ch - '0';
else if ( ch >= 'A' && ch <= 'F' )
return ch - 'A' + 10;
else if ( ch >= 'a' && ch <= 'f' )
return ch - 'a' + 10;
return -1;
}
static inline size_t formathexpattern(const char *patterntext, char *formattext, size_t formattextsize)
{
size_t len = strlen(patterntext);
size_t result = 0;
for ( size_t i = 0; i < len; i++ ) {
if ( patterntext[i] == '?' || hexchtoint(patterntext[i]) != -1 ) {
if ( formattext && result + 1 < formattextsize )
formattext[result] = patterntext[i];
result++;
}
}
if ( result % 2 ) { //not a multiple of 2
if ( formattext && result + 1 < formattextsize )
formattext[result] = '?';
result++;
}
if ( formattext ) {
if ( result <= formattextsize )
formattext[result] = '\0';
else
formattext[0] = '\0';
}
return result;
}
bool patterntransform(const char *patterntext, PatternByte *pattern, size_t patternsize)
{
memset(pattern, 0, patternsize * (sizeof *pattern));
size_t len = formathexpattern(patterntext, NULL, 0);
if ( !len || len / 2 > patternsize )
return false;
size_t size = len + 1;
char *formattext = malloc(size);
formathexpattern(patterntext, formattext, size);
PatternByte newByte;
for ( size_t i = 0, j = 0, k = 0; i < len && k <= patternsize; i++ ) {
if ( formattext[i] == '?' ) { //wildcard
newByte.nibble[j].wildcard = true; //match anything
} else { //hex
newByte.nibble[j].wildcard = false;
newByte.nibble[j].data = hexchtoint(formattext[i]) & 0xF;
}
j++;
if ( j == 2 ) { //two nibbles = one byte
j = 0;
pattern[k++] = newByte;
}
}
free(formattext);
return true;
}
static inline bool patternmatchbyte(uint8_t byte, const PatternByte pbyte)
{
int matched = 0;
uint8_t n1 = (byte >> 4) & 0xF;
if ( pbyte.nibble[0].wildcard )
matched++;
else if ( pbyte.nibble[0].data == n1 )
matched++;
uint8_t n2 = byte & 0xF;
if ( pbyte.nibble[1].wildcard )
matched++;
else if ( pbyte.nibble[1].data == n2 )
matched++;
return (matched == 2);
}
size_t patternfind(uint8_t *data, size_t datasize, const char *pattern)
{
size_t searchpatternsize = formathexpattern(pattern, NULL, 0) / 2;
PatternByte *searchpattern = calloc(searchpatternsize, sizeof(PatternByte));
size_t result = -1;
if ( patterntransform(pattern, searchpattern, searchpatternsize) )
result = patternfind_pbyte(data, datasize, searchpattern, searchpatternsize);
free(searchpattern);
return result;
}
__declspec(noinline)
size_t patternfind_bytes(uint8_t *data, size_t datasize, const uint8_t *pattern, size_t patternsize)
{
if ( patternsize > datasize )
patternsize = datasize;
for ( size_t i = 0, pos = 0; i < datasize; i++ ) {
if ( data[i] == pattern[pos] ) {
pos++;
if ( pos == patternsize )
return i - patternsize + 1;
} else if ( pos > 0 ) {
i -= pos;
pos = 0; //reset current pattern position
}
}
return -1;
}
static inline void patternwritebyte(uint8_t *byte, const PatternByte pbyte)
{
uint8_t n1 = (*byte >> 4) & 0xF;
uint8_t n2 = *byte & 0xF;
if ( !pbyte.nibble[0].wildcard )
n1 = pbyte.nibble[0].data;
if ( !pbyte.nibble[1].wildcard )
n2 = pbyte.nibble[1].data;
*byte = ((n1 << 4) & 0xF0) | (n2 & 0xF);
}
void patternwrite(uint8_t *data, size_t datasize, const char *pattern)
{
size_t writepatternsize = formathexpattern(pattern, NULL, 0) / 2;
PatternByte *writepattern = calloc(writepatternsize, sizeof(PatternByte));
if ( patterntransform(pattern, writepattern, writepatternsize) ) {
DWORD OldProtect;
BOOL result = VirtualProtect(data, writepatternsize, PAGE_READWRITE, &OldProtect);
if ( writepatternsize > datasize )
writepatternsize = datasize;
for ( size_t i = 0; i < writepatternsize; i++ )
patternwritebyte(&data[i], writepattern[i]);
result = VirtualProtect(data, writepatternsize, OldProtect, &OldProtect);
}
free(writepattern);
}
bool patternsnr(uint8_t *data, size_t datasize, const char *searchpattern, const char *replacepattern)
{
size_t found = patternfind(data, datasize, searchpattern);
if ( found == -1 )
return false;
patternwrite(data + found, found - datasize, replacepattern);
return true;
}
__declspec(noinline)
size_t patternfind_pbyte(uint8_t *data, size_t datasize, const PatternByte *pattern, size_t searchpatternsize)
{
for ( size_t i = 0, pos = 0; i < datasize; i++ ) { //search for the pattern
if ( patternmatchbyte(data[i], pattern[pos]) ) { //check if our pattern matches the current byte
pos++;
if ( pos == searchpatternsize ) //everything matched
return i - searchpatternsize + 1;
} else if ( pos > 0 ) { //fix by Computer_Angel
i -= pos;
pos = 0; //reset current pattern position
}
}
return -1;
}

55
src/wufuc/patternfind.h Normal file
View File

@@ -0,0 +1,55 @@
#pragma once
typedef struct
{
struct
{
uint8_t data;
bool wildcard;
} nibble[2];
} PatternByte;
//returns: offset to data when found, -1 when not found
size_t patternfind(
uint8_t *data, //data
size_t datasize, //size of data
const char *pattern //pattern to search
);
//returns: offset to data when found, -1 when not found
size_t patternfind_bytes(
uint8_t *data, //data
size_t datasize, //size of data
const uint8_t *pattern, //bytes to search
size_t patternsize //size of bytes to search
);
//returns: nothing
void patternwrite(
uint8_t *data, //data
size_t datasize, //size of data
const char *pattern //pattern to write
);
//returns: true on success, false on failure
bool patternsnr(
uint8_t *data, //data
size_t datasize, //size of data
const char *searchpattern, //pattern to search
const char *replacepattern //pattern to write
);
//returns: true on success, false on failure
bool patterntransform(
const char *patterntext, //pattern string
PatternByte *pattern, //pattern to feed to patternfind
size_t patternsize //size of pattern
);
//returns: offset to data when found, -1 when not found
size_t patternfind_pbyte(
uint8_t *data, //data
size_t datasize, //size of data
const PatternByte *pattern, //pattern to search
size_t searchpatternsize //size of pattern to search
);

102
src/wufuc/rundll32.c Normal file
View File

@@ -0,0 +1,102 @@
#include "stdafx.h"
#include "callbacks.h"
#include "hlpmisc.h"
void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
{
ContextHandles ctx;
bool Unloading = false;
bool Lagging;
SC_HANDLE hSCM;
SC_HANDLE hService;
SERVICE_NOTIFYW NotifyBuffer;
if ( !InitializeMutex(true,
L"Global\\25020063-b5a7-4227-9fdf-25cb75e8c645",
&ctx.hMainMutex) ) {
trace(L"Failed to initialize main mutex. (GetLastError=%ul)", GetLastError());
return;
};
if ( !CreateEventWithStringSecurityDescriptor(L"D:(A;;0x001F0003;;;BA)",
true,
false,
L"Global\\wufuc_UnloadEvent",
&ctx.hUnloadEvent) ) {
trace(L"Failed to create unload event. (GetLastError=%ul)", GetLastError());
goto close_mutex;
}
do {
Lagging = false;
hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
if ( !hSCM ) {
trace(L"Failed to open SCM. (GetLastError=%ul)", GetLastError());
goto close_event;
}
hService = OpenServiceW(hSCM, L"wuauserv", SERVICE_QUERY_STATUS);
if ( !hService ) {
trace(L"Failed to open service. (GetLastError=%ul)", GetLastError());
goto close_scm;
}
ZeroMemory(&NotifyBuffer, sizeof NotifyBuffer);
NotifyBuffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
NotifyBuffer.pfnNotifyCallback = ServiceNotifyCallback;
NotifyBuffer.pContext = (PVOID)&ctx;
while ( !Unloading && !Lagging ) {
switch ( NotifyServiceStatusChangeW(hService,
SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_RUNNING,
&NotifyBuffer) ) {
case ERROR_SUCCESS:
Unloading = WaitForSingleObjectEx(ctx.hUnloadEvent, INFINITE, TRUE) == WAIT_OBJECT_0;
break;
case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING:
trace(L"Client lagging!");
Lagging = true;
break;
default:
Unloading = true;
break;
}
}
CloseServiceHandle(hService);
close_scm: CloseServiceHandle(hSCM);
} while ( Lagging );
close_event:
CloseHandle(ctx.hUnloadEvent);
close_mutex:
ReleaseMutex(ctx.hMainMutex);
CloseHandle(ctx.hMainMutex);
}
void CALLBACK RUNDLL32_UnloadW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
{
HANDLE hEvent;
hEvent = OpenEventW(EVENT_MODIFY_STATE, FALSE, L"Global\\wufuc_UnloadEvent");
if ( hEvent ) {
SetEvent(hEvent);
CloseHandle(hEvent);
}
}
void CALLBACK RUNDLL32_DeleteFileW(
HWND hwnd,
HINSTANCE hinst,
LPWSTR lpszCmdLine,
int nCmdShow)
{
int argc;
LPWSTR *argv;
argv = CommandLineToArgvW(lpszCmdLine, &argc);
if ( argv ) {
if ( !DeleteFileW(argv[0]) && GetLastError() == ERROR_ACCESS_DENIED )
MoveFileExW(argv[0], NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
LocalFree((HLOCAL)argv);
}
}

11
src/wufuc/rundll32.h Normal file
View File

@@ -0,0 +1,11 @@
#pragma once
#ifdef UNICODE
#define RUNDLL32_Start RUNDLL32_StartW
#define RUNDLL32_Unload RUNDLL32_UnloadW
#define RUNDLL32_DeleteFile RUNDLL32_DeleteFileW
#else
#define RUNDLL32_Start RUNDLL32_StartA
#define RUNDLL32_Unload RUNDLL32_UnloadA
#define RUNDLL32_DeleteFile RUNDLL32_DeleteFileA
#endif // !UNICODE

7
src/wufuc/stdafx.c Normal file
View File

@@ -0,0 +1,7 @@
// stdafx.c : source file that includes just the standard includes
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

34
src/wufuc/stdafx.h Normal file
View File

@@ -0,0 +1,34 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
// Windows Header Files:
#include <phnt_windows.h>
#include <phnt.h>
// TODO: reference additional headers your program requires here
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <strsafe.h>
#include <shellapi.h>
#include <Shlwapi.h>
#include <Psapi.h>
#include <TlHelp32.h>
#include <detours.h>
#include "patternfind.h"
#include "tracing.h"
extern IMAGE_DOS_HEADER __ImageBase;
#define PIMAGEBASE ((HMODULE)&__ImageBase)

9
src/wufuc/targetver.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#define _WIN32_WINNT _WIN32_WINNT_WIN7
#include <SDKDDKVer.h>

19
src/wufuc/tracing.c Normal file
View File

@@ -0,0 +1,19 @@
#include "stdafx.h"
#include "tracing.h"
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);
}

14
src/wufuc/tracing.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include <phnt_windows.h>
extern IMAGE_DOS_HEADER __ImageBase;
#define HMODULE_THISCOMPONENT ((HMODULE)&__ImageBase);
void trace_(const wchar_t *const format, ...);
#define STRINGIZEW_(x) L#x
#define STRINGIZEW(x) STRINGIZEW_(x)
#define LINEWSTR STRINGIZEW(__LINE__)
#define trace(format, ...) trace_(__FILEW__ L":" LINEWSTR L"(" __FUNCTIONW__ L"): " format L"\n", ##__VA_ARGS__)

BIN
src/wufuc/wufuc.rc Normal file

Binary file not shown.

17
src/wufuc/wufuc.rch Normal file
View File

@@ -0,0 +1,17 @@
#ifndef WUFUC_RCH_INCLUDED
#define WUFUC_RCH_INCLUDED
#pragma once
#ifndef BUILD_COMMIT_VERSION
#define BUILD_COMMIT_VERSION 0.9.999.0
#endif
#ifndef BUILD_VERSION_COMMA
#define BUILD_VERSION_COMMA 0,9,999,0
#endif
#define STRINGIZE_(x) #x
#define STRINGIZE(x) STRINGIZE_(x)
#ifdef X64
#define WUFUC_DLL "wufuc64.dll"
#elif defined(X86)
#define WUFUC_DLL "wufuc32.dll"
#endif
#endif

273
src/wufuc/wufuc.vcxproj Normal file
View File

@@ -0,0 +1,273 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="callbacks.h" />
<ClInclude Include="hlpmem.h" />
<ClInclude Include="hlpmisc.h" />
<ClInclude Include="hlpsvc.h" />
<ClInclude Include="hlpver.h" />
<ClInclude Include="hooks.h" />
<ClInclude Include="patternfind.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="tracing.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="callbacks.c" />
<ClCompile Include="dllmain.c" />
<ClCompile Include="hlpmem.c" />
<ClCompile Include="hlpmisc.c" />
<ClCompile Include="hlpsvc.c" />
<ClCompile Include="hlpver.c" />
<ClCompile Include="hooks.c" />
<ClCompile Include="patternfind.c" />
<ClCompile Include="stdafx.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="rundll32.c" />
<ClCompile Include="tracing.c" />
</ItemGroup>
<ItemGroup>
<None Include="exports.def" />
<None Include="wufuc.rch">
<FileType>Document</FileType>
</None>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="wufuc.rc" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{00F96695-CE41-4C2F-A344-6219DFB4F887}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>wufuc</RootNamespace>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(ProjectDir)bin\$(Configuration)\$(PlatformShortName)\</OutDir>
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
<GenerateManifest>false</GenerateManifest>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\detours;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\detours;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(ProjectDir)bin\$(Configuration)\$(PlatformShortName)\</OutDir>
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
<GenerateManifest>false</GenerateManifest>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\detours;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\detours;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)bin\$(Configuration)\$(PlatformShortName)\</OutDir>
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
<GenerateManifest>false</GenerateManifest>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\detours;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\detours;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)bin\$(Configuration)\$(PlatformShortName)\</OutDir>
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
<GenerateManifest>false</GenerateManifest>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\detours;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\detours;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;WUFUC_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
<SDLCheck>true</SDLCheck>
<PrecompiledHeader>Use</PrecompiledHeader>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
<EntryPointSymbol>
</EntryPointSymbol>
<AdditionalDependencies>version.lib;Shlwapi.lib;detours.X86.MTd.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>X86;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;WUFUC_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
<SDLCheck>true</SDLCheck>
<PrecompiledHeader>Use</PrecompiledHeader>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
<EntryPointSymbol>
</EntryPointSymbol>
<AdditionalDependencies>version.lib;Shlwapi.lib;detours.X64.MTd.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>X64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;WUFUC_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
<SDLCheck>true</SDLCheck>
<PrecompiledHeader>Use</PrecompiledHeader>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DebugInformationFormat>None</DebugInformationFormat>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<ResourceCompile Condition="'$(APPVEYOR)'=='True'">
<PreprocessorDefinitions>BUILD_COMMIT_VERSION=$(BUILD_COMMIT_VERSION);BUILD_VERSION_COMMA=$(BUILD_VERSION_COMMA);$(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
<EntryPointSymbol>
</EntryPointSymbol>
<AdditionalDependencies>version.lib;Shlwapi.lib;detours.X86.MT.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
<SetChecksum>true</SetChecksum>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>X86;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<PostBuildEvent>
<Command>copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup_bat\"
copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup\"</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy release binaries to the setup staging directories</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;WUFUC_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<CompileAs>CompileAsC</CompileAs>
<PrecompiledHeader>Use</PrecompiledHeader>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DebugInformationFormat>None</DebugInformationFormat>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<ResourceCompile Condition="'$(APPVEYOR)'=='True'">
<PreprocessorDefinitions>BUILD_COMMIT_VERSION=$(BUILD_COMMIT_VERSION);BUILD_VERSION_COMMA=$(BUILD_VERSION_COMMA);$(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
<AdditionalDependencies>version.lib;Shlwapi.lib;detours.X64.MT.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
<SetChecksum>true</SetChecksum>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>X64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<PostBuildEvent>
<Command>copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup_bat\"
copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup\"</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy release binaries to the setup staging directories</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{629a1242-73f5-4282-a218-7b8d7d761cc6}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{e54f7242-67a6-4c85-bf48-0f7a6095b613}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{acf0da3d-e3e4-4fc8-aaf8-8d0558e6414c}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="callbacks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="hooks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="tracing.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="patternfind.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="hlpmem.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="hlpmisc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="hlpsvc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="hlpver.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="callbacks.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="dllmain.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hooks.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="tracing.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="rundll32.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="stdafx.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="patternfind.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hlpsvc.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hlpmem.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hlpver.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hlpmisc.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="wufuc.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="wufuc.rch">
<Filter>Resource Files</Filter>
</None>
<None Include="exports.def">
<Filter>Source Files</Filter>
</None>
</ItemGroup>
</Project>