bigly changes (see description)
- use LdrRegisterDllNotification instead of LoadLibraryExW for patching ** LoadLibraryExW is currently still hooked for the UpdatePack7 compatibility fix, I'm looking into other alternatives - more robust error checking - refactored a lot of code to be more reusable - header guards - better logging framework - tighter permissions on the unload event - probably other stuff I forgot about
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -254,3 +254,6 @@ paket-files/
|
|||||||
# Advanced Installer
|
# Advanced Installer
|
||||||
**/*-cache/
|
**/*-cache/
|
||||||
**/*-SetupFiles/
|
**/*-SetupFiles/
|
||||||
|
|
||||||
|
# Other
|
||||||
|
setup-batch/*.dll
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
version: 0.7.2.{build}
|
version: 0.7.2.{build}
|
||||||
skip_commits:
|
skip_commits:
|
||||||
files:
|
files:
|
||||||
- README.md
|
- **/*.md
|
||||||
- CONTRIBUTING.md
|
- **/*.aip
|
||||||
image: Visual Studio 2017
|
image: Visual Studio 2017
|
||||||
configuration: Release
|
configuration: Release
|
||||||
platform:
|
platform:
|
||||||
|
106
wufuc/callbacks.c
Normal file
106
wufuc/callbacks.c
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#include "callbacks.h"
|
||||||
|
|
||||||
|
#include "service.h"
|
||||||
|
#include "iathook.h"
|
||||||
|
#include "hooks.h"
|
||||||
|
#include "patchwua.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "ntdllhelper.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define WIN32_NO_STATUS
|
||||||
|
#include <windows.h>
|
||||||
|
#undef WIN32_NO_STATUS
|
||||||
|
|
||||||
|
#include <winternl.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <Psapi.h>
|
||||||
|
#include <sddl.h>
|
||||||
|
|
||||||
|
DWORD WINAPI ThreadProcCallback(LPVOID lpParam) {
|
||||||
|
TCHAR lpServiceCommandLine[0x8000];
|
||||||
|
GetServiceCommandLine(NULL, _T("wuauserv"), lpServiceCommandLine, _countof(lpServiceCommandLine));
|
||||||
|
if ( _tcsicmp(GetCommandLine(), lpServiceCommandLine) )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
SECURITY_ATTRIBUTES sa = { 0 };
|
||||||
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||||
|
sa.bInheritHandle = FALSE;
|
||||||
|
if ( !ConvertStringSecurityDescriptorToSecurityDescriptor(_T("D:(A;;0x001F0003;;;BA)"), SDDL_REVISION_1, &sa.lpSecurityDescriptor, NULL) ) {
|
||||||
|
trace(_T("Failed to convert string security descriptor to security descriptor (error code=%08X)"), GetLastError());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE hEvent = CreateEvent(&sa, TRUE, FALSE, _T("Global\\wufuc_UnloadEvent"));
|
||||||
|
if ( hEvent ) {
|
||||||
|
iat_hook(GetModuleHandle(NULL), "LoadLibraryExW", (LPVOID)&fpLoadLibraryExW, LoadLibraryExW_hook);
|
||||||
|
|
||||||
|
PVOID cookie;
|
||||||
|
NTSTATUS status;
|
||||||
|
if ( TryLdrRegisterDllNotification(0, (PLDR_DLL_NOTIFICATION_FUNCTION)LdrDllNotificationCallback, NULL, &cookie, &status) ) {
|
||||||
|
if ( NT_SUCCESS(status) ) {
|
||||||
|
trace(_T("Registered LdrDllNotificationCallback (status code=%d)"), status);
|
||||||
|
HMODULE hm = GetModuleHandleW(GetWindowsUpdateServiceDllW());
|
||||||
|
if ( hm ) {
|
||||||
|
MODULEINFO modinfo;
|
||||||
|
if ( GetModuleInformation(GetCurrentProcess(), hm, &modinfo, sizeof(MODULEINFO)) )
|
||||||
|
PatchWUA((void *)modinfo.lpBaseOfDll, (size_t)modinfo.SizeOfImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitForSingleObject(hEvent, INFINITE);
|
||||||
|
trace(_T("Unload event was set"));
|
||||||
|
|
||||||
|
if ( cookie ) {
|
||||||
|
if ( TryLdrUnregisterDllNotification(cookie, &status) ) {
|
||||||
|
if ( NT_SUCCESS(status) )
|
||||||
|
trace(_T("Unregistered LdrDllNotificationCallback (status code=%d)"), status);
|
||||||
|
else
|
||||||
|
trace(_T("Failed to unregister LdrDllNotificationCallback (status code=%d)"), status);
|
||||||
|
} else
|
||||||
|
trace(_T("Failed to get LdrUnregisterDllNotification proc address"));
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
trace(_T("Failed to register LdrDllNotificationCallback (status code=%d)"), status);
|
||||||
|
} else
|
||||||
|
trace(_T("Failed to get LdrRegisterDllNotification proc address"));
|
||||||
|
|
||||||
|
iat_hook(GetModuleHandle(NULL), "LoadLibraryExW", NULL, fpLoadLibraryExW);
|
||||||
|
CloseHandle(hEvent);
|
||||||
|
} else {
|
||||||
|
trace(_T("Failed to create unload event (error code=%08X)"), GetLastError());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
trace(_T("Bye bye!"));
|
||||||
|
FreeLibraryAndExitThread((HMODULE)lpParam, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID CALLBACK LdrDllNotificationCallback(ULONG NotificationReason, PCLDR_DLL_NOTIFICATION_DATA NotificationData, PVOID Context) {
|
||||||
|
switch ( NotificationReason ) {
|
||||||
|
case LDR_DLL_NOTIFICATION_REASON_LOADED:
|
||||||
|
{
|
||||||
|
LDR_DLL_LOADED_NOTIFICATION_DATA data = NotificationData->Loaded;
|
||||||
|
|
||||||
|
trace(_T("Loaded library: %wZ"), data.FullDllName);
|
||||||
|
|
||||||
|
wchar_t buffer[MAX_PATH];
|
||||||
|
wcscpy_s(buffer, _countof(buffer), (wchar_t *)GetWindowsUpdateServiceDllW());
|
||||||
|
ApplyUpdatePack7R2ShimIfNeeded(buffer, _countof(buffer), buffer, _countof(buffer));
|
||||||
|
|
||||||
|
if ( !_wcsnicmp((wchar_t *)data.FullDllName->Buffer, buffer, (size_t)data.FullDllName->Length) )
|
||||||
|
PatchWUA(data.DllBase, data.SizeOfImage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case LDR_DLL_NOTIFICATION_REASON_UNLOADED:
|
||||||
|
{
|
||||||
|
LDR_DLL_UNLOADED_NOTIFICATION_DATA data = NotificationData->Unloaded;
|
||||||
|
|
||||||
|
trace(_T("Unloaded library: %wZ"), data.FullDllName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
11
wufuc/callbacks.h
Normal file
11
wufuc/callbacks.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef CALLBACKS_H
|
||||||
|
#define CALLBACKS_H
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ntdllhelper.h"
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
DWORD WINAPI ThreadProcCallback(LPVOID lpParam);
|
||||||
|
VOID CALLBACK LdrDllNotificationCallback(ULONG NotificationReason, PCLDR_DLL_NOTIFICATION_DATA NotificationData, PVOID Context);
|
||||||
|
#endif
|
@@ -1,23 +1,25 @@
|
|||||||
#include <Windows.h>
|
#include "callbacks.h"
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "hooks.h"
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||||
switch (ul_reason_for_call) {
|
switch ( ul_reason_for_call ) {
|
||||||
case DLL_PROCESS_ATTACH:
|
case DLL_PROCESS_ATTACH:
|
||||||
{
|
{
|
||||||
if (!IsOperatingSystemSupported() || IsWow64())
|
if ( !IsOperatingSystemSupported() || IsWow64() )
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
DisableThreadLibraryCalls(hModule);
|
DisableThreadLibraryCalls(hModule);
|
||||||
HANDLE hThread = CreateThread(NULL, 0, NewThreadProc, NULL, 0, NULL);
|
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProcCallback, (LPVOID)hModule, 0, NULL);
|
||||||
CloseHandle(hThread);
|
CloseHandle(hThread);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
logging_free();
|
if ( !lpReserved )
|
||||||
|
FreeNTDLL();
|
||||||
|
FreeLogging();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@@ -1,3 +0,0 @@
|
|||||||
EXPORTS
|
|
||||||
Rundll32Entry
|
|
||||||
Rundll32Unload
|
|
@@ -1,26 +1,16 @@
|
|||||||
#include <Windows.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <tchar.h>
|
|
||||||
#include <TlHelp32.h>
|
|
||||||
#include <Psapi.h>
|
|
||||||
|
|
||||||
#include "logging.h"
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
static BOOL m_checkedIsWindows7 = FALSE;
|
#include "logging.h"
|
||||||
static BOOL m_isWindows7 = FALSE;
|
|
||||||
static BOOL m_checkedIsWindows8Point1 = FALSE;
|
|
||||||
static BOOL m_isWindows8Point1 = FALSE;
|
|
||||||
|
|
||||||
static ISWOW64PROCESS fpIsWow64Process = NULL;
|
#include <stdint.h>
|
||||||
static BOOL m_checkedIsWow64 = FALSE;
|
|
||||||
static BOOL m_isWow64 = FALSE;
|
|
||||||
|
|
||||||
static TCHAR m_emod_basename[MAX_PATH];
|
#include <Windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <Psapi.h>
|
||||||
|
#include <TlHelp32.h>
|
||||||
|
|
||||||
BOOL CompareWindowsVersion(BYTE Operator, DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor, DWORD dwTypeMask) {
|
static BOOL CompareWindowsVersion(BYTE Operator, DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor, DWORD dwTypeMask) {
|
||||||
OSVERSIONINFOEX osvi;
|
OSVERSIONINFOEX osvi = { 0 };
|
||||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
|
|
||||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
||||||
osvi.dwMajorVersion = dwMajorVersion;
|
osvi.dwMajorVersion = dwMajorVersion;
|
||||||
osvi.dwMinorVersion = dwMinorVersion;
|
osvi.dwMinorVersion = dwMinorVersion;
|
||||||
@@ -37,7 +27,10 @@ BOOL CompareWindowsVersion(BYTE Operator, DWORD dwMajorVersion, DWORD dwMinorVer
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOL IsWindows7(void) {
|
BOOL IsWindows7(void) {
|
||||||
if (!m_checkedIsWindows7) {
|
static BOOL m_checkedIsWindows7 = FALSE;
|
||||||
|
static BOOL m_isWindows7 = FALSE;
|
||||||
|
|
||||||
|
if ( !m_checkedIsWindows7 ) {
|
||||||
m_isWindows7 = CompareWindowsVersion(VER_EQUAL, 6, 1, 0, 0, VER_MAJORVERSION | VER_MINORVERSION);
|
m_isWindows7 = CompareWindowsVersion(VER_EQUAL, 6, 1, 0, 0, VER_MAJORVERSION | VER_MINORVERSION);
|
||||||
m_checkedIsWindows7 = TRUE;
|
m_checkedIsWindows7 = TRUE;
|
||||||
}
|
}
|
||||||
@@ -45,7 +38,10 @@ BOOL IsWindows7(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOL IsWindows8Point1(void) {
|
BOOL IsWindows8Point1(void) {
|
||||||
if (!m_checkedIsWindows8Point1) {
|
static BOOL m_checkedIsWindows8Point1 = FALSE;
|
||||||
|
static BOOL m_isWindows8Point1 = FALSE;
|
||||||
|
|
||||||
|
if ( !m_checkedIsWindows8Point1 ) {
|
||||||
m_isWindows8Point1 = CompareWindowsVersion(VER_EQUAL, 6, 3, 0, 0, VER_MAJORVERSION | VER_MINORVERSION);
|
m_isWindows8Point1 = CompareWindowsVersion(VER_EQUAL, 6, 3, 0, 0, VER_MAJORVERSION | VER_MINORVERSION);
|
||||||
m_checkedIsWindows8Point1 = TRUE;
|
m_checkedIsWindows8Point1 = TRUE;
|
||||||
}
|
}
|
||||||
@@ -61,56 +57,60 @@ BOOL IsOperatingSystemSupported(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOL IsWow64(void) {
|
BOOL IsWow64(void) {
|
||||||
if (!m_checkedIsWow64) {
|
static BOOL m_checkedIsWow64 = FALSE;
|
||||||
if (!fpIsWow64Process)
|
static BOOL m_isWow64 = FALSE;
|
||||||
|
static ISWOW64PROCESS fpIsWow64Process = NULL;
|
||||||
|
|
||||||
|
if ( !m_checkedIsWow64 ) {
|
||||||
|
if ( !fpIsWow64Process )
|
||||||
fpIsWow64Process = (ISWOW64PROCESS)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "IsWow64Process");
|
fpIsWow64Process = (ISWOW64PROCESS)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "IsWow64Process");
|
||||||
|
|
||||||
if (fpIsWow64Process && fpIsWow64Process(GetCurrentProcess(), &m_isWow64))
|
if ( fpIsWow64Process && fpIsWow64Process(GetCurrentProcess(), &m_isWow64) )
|
||||||
m_checkedIsWow64 = TRUE;
|
m_checkedIsWow64 = TRUE;
|
||||||
}
|
}
|
||||||
return m_isWow64;
|
return m_isWow64;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID suspend_other_threads(DWORD dwProcessId, DWORD dwThreadId, HANDLE *lphThreads, SIZE_T dwSize, SIZE_T *lpcb) {
|
void suspend_other_threads(LPHANDLE lphThreads, size_t *lpcb) {
|
||||||
|
DWORD dwProcessId = GetCurrentProcessId();
|
||||||
|
DWORD dwThreadId = GetCurrentThreadId();
|
||||||
|
|
||||||
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
||||||
THREADENTRY32 te;
|
THREADENTRY32 te = { 0 };
|
||||||
ZeroMemory(&te, sizeof(THREADENTRY32));
|
|
||||||
te.dwSize = sizeof(te);
|
te.dwSize = sizeof(te);
|
||||||
Thread32First(hSnap, &te);
|
Thread32First(hSnap, &te);
|
||||||
|
|
||||||
SIZE_T count = 0;
|
size_t count = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (te.th32OwnerProcessID != dwProcessId || te.th32ThreadID == dwThreadId)
|
if ( te.th32OwnerProcessID != dwProcessId || te.th32ThreadID == dwThreadId )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
lphThreads[count] = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID);
|
lphThreads[count] = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID);
|
||||||
SuspendThread(lphThreads[count]);
|
SuspendThread(lphThreads[count]);
|
||||||
count++;
|
count++;
|
||||||
} while (count < dwSize && Thread32Next(hSnap, &te));
|
} while ( count < *lpcb && Thread32Next(hSnap, &te) );
|
||||||
CloseHandle(hSnap);
|
CloseHandle(hSnap);
|
||||||
|
|
||||||
*lpcb = count;
|
*lpcb = count;
|
||||||
trace(L"Suspended %d other threads", count);
|
trace(_T("Suspended %d other threads"), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID resume_and_close_threads(LPHANDLE lphThreads, SIZE_T cb) {
|
void resume_and_close_threads(LPHANDLE lphThreads, size_t cb) {
|
||||||
for (SIZE_T i = 0; i < cb; i++) {
|
for ( size_t i = 0; i < cb; i++ ) {
|
||||||
ResumeThread(lphThreads[i]);
|
ResumeThread(lphThreads[i]);
|
||||||
CloseHandle(lphThreads[i]);
|
CloseHandle(lphThreads[i]);
|
||||||
}
|
}
|
||||||
trace(L"Resumed %d threads", cb);
|
trace(_T("Resumed %d threads"), cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_cpuid_brand(char *brand) {
|
void get_cpuid_brand(char *brand) {
|
||||||
int info[4];
|
int info[4];
|
||||||
__cpuidex(info, 0x80000000, 0);
|
__cpuidex(info, 0x80000000, 0);
|
||||||
if (info[0] < 0x80000004) {
|
if ( info[0] < 0x80000004 ) {
|
||||||
brand[0] = '\0';
|
brand[0] = '\0';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint32_t *char_as_int = (uint32_t *)brand;
|
uint32_t *char_as_int = (uint32_t *)brand;
|
||||||
for (int op = 0x80000002; op <= 0x80000004; op++) {
|
for ( int op = 0x80000002; op <= 0x80000004; op++ ) {
|
||||||
__cpuidex(info, op, 0);
|
__cpuidex(info, op, 0);
|
||||||
*(char_as_int++) = info[0];
|
*(char_as_int++) = info[0];
|
||||||
*(char_as_int++) = info[1];
|
*(char_as_int++) = info[1];
|
||||||
|
@@ -1,20 +1,21 @@
|
|||||||
|
#ifndef HELPERS_H
|
||||||
|
#define HELPERS_H
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
|
#include <Windows.h>
|
||||||
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
|
|
||||||
|
|
||||||
typedef BOOL(WINAPI *ISWOW64PROCESS)(HANDLE, PBOOL);
|
typedef BOOL(WINAPI *ISWOW64PROCESS)(HANDLE, PBOOL);
|
||||||
|
|
||||||
BOOL CompareWindowsVersion(BYTE Operator, DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor, DWORD dwTypeMask);
|
|
||||||
BOOL IsWindows7(void);
|
BOOL IsWindows7(void);
|
||||||
BOOL IsWindows8Point1(void);
|
BOOL IsWindows8Point1(void);
|
||||||
BOOL IsOperatingSystemSupported(void);
|
BOOL IsOperatingSystemSupported(void);
|
||||||
BOOL IsWow64(void);
|
BOOL IsWow64(void);
|
||||||
|
|
||||||
VOID suspend_other_threads(DWORD dwProcessId, DWORD dwThreadId, HANDLE *lphThreads, SIZE_T dwSize, SIZE_T *lpcb);
|
void suspend_other_threads(LPHANDLE lphThreads, size_t *lpcb);
|
||||||
VOID resume_and_close_threads(LPHANDLE lphThreads, SIZE_T dwSize);
|
void resume_and_close_threads(LPHANDLE lphThreads, size_t cb);
|
||||||
|
|
||||||
void get_cpuid_brand(char *brand);
|
void get_cpuid_brand(char *brand);
|
||||||
|
|
||||||
#define STRINGIZE_(x) #x
|
#define STRINGIZE_(x) #x
|
||||||
#define STRINGIZE(x) STRINGIZE_(x)
|
#define STRINGIZE(x) STRINGIZE_(x)
|
||||||
|
#endif
|
||||||
|
239
wufuc/hooks.c
239
wufuc/hooks.c
@@ -1,192 +1,67 @@
|
|||||||
#include <Windows.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <tchar.h>
|
|
||||||
#include <Psapi.h>
|
|
||||||
#include <sddl.h>
|
|
||||||
|
|
||||||
#include "helpers.h"
|
|
||||||
#include "logging.h"
|
|
||||||
#include "service.h"
|
|
||||||
#include "iathook.h"
|
|
||||||
#include "patternfind.h"
|
|
||||||
#include "hooks.h"
|
#include "hooks.h"
|
||||||
|
|
||||||
|
#include "service.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
//#include "ntdllhelper.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
//#define WIN32_NO_STATUS
|
||||||
|
#include <Windows.h>
|
||||||
|
//#undef WIN32_NO_STATUS
|
||||||
|
|
||||||
|
//#include <winternl.h>
|
||||||
|
//#include <ntstatus.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <Psapi.h>
|
||||||
|
|
||||||
|
//REGQUERYVALUEEXW fpRegQueryValueExW = NULL;
|
||||||
LOADLIBRARYEXW fpLoadLibraryExW = NULL;
|
LOADLIBRARYEXW fpLoadLibraryExW = NULL;
|
||||||
LOADLIBRARYEXA fpLoadLibraryExA = NULL;
|
|
||||||
|
|
||||||
DWORD WINAPI NewThreadProc(LPVOID lpParam) {
|
//LRESULT WINAPI RegQueryValueExW_hook(HKEY hKey, LPCTSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) {
|
||||||
SC_HANDLE hSCManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT);
|
// static NTQUERYKEY fpNtQueryKey = NULL;
|
||||||
|
//
|
||||||
|
// DWORD cbData = *lpcbData;
|
||||||
|
//
|
||||||
|
// LRESULT result = fpRegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
|
||||||
|
// if ( !result && lpData && !_wcsicmp((const wchar_t *)lpValueName, L"ServiceDll") ) {
|
||||||
|
// if ( InitNTDLL() ) {
|
||||||
|
// if ( !fpNtQueryKey )
|
||||||
|
// fpNtQueryKey = (NTQUERYKEY)GetProcAddress(g_hNTDLL, "NtQueryKey");
|
||||||
|
//
|
||||||
|
// if ( fpNtQueryKey ) {
|
||||||
|
// ULONG ResultLength;
|
||||||
|
// NTSTATUS status = fpNtQueryKey((HANDLE)hKey, KeyNameInformation, NULL, 0, &ResultLength);
|
||||||
|
// if ( status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL ) {
|
||||||
|
// PVOID buffer = malloc(ResultLength);
|
||||||
|
// if ( NT_SUCCESS(fpNtQueryKey((HANDLE)hKey, KeyNameInformation, buffer, ResultLength, &ResultLength))
|
||||||
|
// && !_wcsnicmp(buffer, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\services\\wuauserv", (size_t)ResultLength) ) {
|
||||||
|
//
|
||||||
|
// wchar_t path[MAX_PATH], newpath[MAX_PATH];
|
||||||
|
// wcsncpy_s(path, _countof(path), (wchar_t *)lpData, (rsize_t)*lpcbData);
|
||||||
|
//
|
||||||
|
// if ( ApplyUpdatePack7R2ShimIfNeeded(path, _countof(path), newpath, _countof(newpath)) ) {
|
||||||
|
// trace(_T("UpdatePack7R2 shim: \"%ls\" -> \"%ls\""), path, newpath);
|
||||||
|
// wcscpy_s((wchar_t *)lpData, (rsize_t)cbData, newpath);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// free(buffer);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return result;
|
||||||
|
//}
|
||||||
|
|
||||||
TCHAR lpBinaryPathName[0x8000];
|
HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags) {
|
||||||
get_svcpath(hSCManager, _T("wuauserv"), lpBinaryPathName, _countof(lpBinaryPathName));
|
wchar_t buffer[MAX_PATH];
|
||||||
CloseServiceHandle(hSCManager);
|
|
||||||
|
|
||||||
if (_tcsicmp(GetCommandLine(), lpBinaryPathName))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
SECURITY_ATTRIBUTES sa = { 0 };
|
|
||||||
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
||||||
ConvertStringSecurityDescriptorToSecurityDescriptor(_T("D:PAI(A;;FA;;;BA)"), SDDL_REVISION_1, &sa.lpSecurityDescriptor, NULL);
|
|
||||||
sa.bInheritHandle = FALSE;
|
|
||||||
|
|
||||||
HANDLE hEvent = CreateEvent(&sa, TRUE, FALSE, _T("Global\\wufuc_UnloadEvent"));
|
|
||||||
if (!hEvent)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
DWORD dwProcessId = GetCurrentProcessId();
|
|
||||||
DWORD dwThreadId = GetCurrentThreadId();
|
|
||||||
HANDLE lphThreads[0x1000];
|
|
||||||
SIZE_T count;
|
|
||||||
|
|
||||||
suspend_other_threads(dwProcessId, dwThreadId, lphThreads, _countof(lphThreads), &count);
|
|
||||||
|
|
||||||
HMODULE hm = GetModuleHandle(NULL);
|
|
||||||
iat_hook(hm, "LoadLibraryExA", (LPVOID)&fpLoadLibraryExA, LoadLibraryExA_hook);
|
|
||||||
iat_hook(hm, "LoadLibraryExW", (LPVOID)&fpLoadLibraryExW, LoadLibraryExW_hook);
|
|
||||||
|
|
||||||
HMODULE hwu = GetModuleHandle(get_wuauservdll());
|
|
||||||
if (hwu && PatchWUA(hwu))
|
|
||||||
trace(L"Successfully patched previously loaded WUA module!");
|
|
||||||
|
|
||||||
resume_and_close_threads(lphThreads, count);
|
|
||||||
|
|
||||||
WaitForSingleObject(hEvent, INFINITE);
|
|
||||||
trace(L"Unloading...");
|
|
||||||
|
|
||||||
suspend_other_threads(dwProcessId, dwThreadId, lphThreads, _countof(lphThreads), &count);
|
|
||||||
|
|
||||||
iat_hook(hm, "LoadLibraryExA", NULL, fpLoadLibraryExA);
|
|
||||||
iat_hook(hm, "LoadLibraryExW", NULL, fpLoadLibraryExW);
|
|
||||||
|
|
||||||
resume_and_close_threads(lphThreads, count);
|
|
||||||
|
|
||||||
trace(L"Bye bye!");
|
|
||||||
CloseHandle(hEvent);
|
|
||||||
FreeLibraryAndExitThread(HINST_THISCOMPONENT, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
HMODULE WINAPI LoadLibraryExA_hook(
|
|
||||||
_In_ LPCSTR lpFileName,
|
|
||||||
_Reserved_ HANDLE hFile,
|
|
||||||
_In_ DWORD dwFlags
|
|
||||||
) {
|
|
||||||
CHAR buffer[MAX_PATH];
|
|
||||||
strcpy_s(buffer, _countof(buffer), lpFileName);
|
|
||||||
|
|
||||||
BOOL isWUA = !_stricmp(buffer, get_wuauservdllA());
|
|
||||||
if (isWUA) {
|
|
||||||
CHAR drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
|
|
||||||
_splitpath_s(buffer, drive, _countof(drive), dir, _countof(dir), fname, _countof(fname), ext, _countof(ext));
|
|
||||||
|
|
||||||
if (!_stricmp(fname, "wuaueng2")) {
|
|
||||||
CHAR newpath[MAX_PATH];
|
|
||||||
_makepath_s(newpath, _countof(buffer), drive, dir, "wuaueng", ext);
|
|
||||||
|
|
||||||
if (GetFileAttributesA(newpath) != INVALID_FILE_ATTRIBUTES) {
|
|
||||||
strcpy_s(buffer, _countof(buffer), newpath);
|
|
||||||
trace(L"UpdatePack7R2 compatibility fix: redirecting %S -> %S", lpFileName, buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HMODULE result = fpLoadLibraryExA(buffer, hFile, dwFlags);
|
|
||||||
trace(L"Loaded library: %S", buffer);
|
|
||||||
|
|
||||||
if (isWUA)
|
|
||||||
PatchWUA(result);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
HMODULE WINAPI LoadLibraryExW_hook(
|
|
||||||
_In_ LPCWSTR lpFileName,
|
|
||||||
_Reserved_ HANDLE hFile,
|
|
||||||
_In_ DWORD dwFlags
|
|
||||||
) {
|
|
||||||
WCHAR buffer[MAX_PATH];
|
|
||||||
wcscpy_s(buffer, _countof(buffer), lpFileName);
|
wcscpy_s(buffer, _countof(buffer), lpFileName);
|
||||||
|
|
||||||
BOOL isWUA = !_wcsicmp(buffer, get_wuauservdllW());
|
if ( !_wcsicmp(buffer, GetWindowsUpdateServiceDllW())
|
||||||
if (isWUA) {
|
&& ApplyUpdatePack7R2ShimIfNeeded(buffer, _countof(buffer), buffer, _countof(buffer)) ) {
|
||||||
WCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
|
trace(_T("UpdatePack7R2 shim: %ls -> %ls"), lpFileName, buffer);
|
||||||
_wsplitpath_s(buffer, drive, _countof(drive), dir, _countof(dir), fname, _countof(fname), ext, _countof(ext));
|
|
||||||
|
|
||||||
if (!_wcsicmp(fname, L"wuaueng2")) {
|
|
||||||
WCHAR newpath[MAX_PATH];
|
|
||||||
_wmakepath_s(newpath, _countof(buffer), drive, dir, L"wuaueng", ext);
|
|
||||||
|
|
||||||
if (GetFileAttributesW(newpath) != INVALID_FILE_ATTRIBUTES) {
|
|
||||||
wcscpy_s(buffer, _countof(buffer), newpath);
|
|
||||||
trace(L"UpdatePack7R2 compatibility fix: redirecting %s -> %s", lpFileName, buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HMODULE result = fpLoadLibraryExW(buffer, hFile, dwFlags);
|
return fpLoadLibraryExW((LPWSTR)buffer, hFile, dwFlags);
|
||||||
trace(L"Loaded library: %s", buffer);
|
|
||||||
|
|
||||||
if (isWUA)
|
|
||||||
PatchWUA(result);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL PatchWUA(HMODULE hModule) {
|
|
||||||
LPSTR pattern;
|
|
||||||
SIZE_T offset00, offset01;
|
|
||||||
#ifdef _AMD64_
|
|
||||||
pattern = "FFF3 4883EC?? 33DB 391D???????? 7508 8B05????????";
|
|
||||||
offset00 = 10;
|
|
||||||
offset01 = 18;
|
|
||||||
#elif defined(_X86_)
|
|
||||||
if (IsWindows7()) {
|
|
||||||
pattern = "833D????????00 743E E8???????? A3????????";
|
|
||||||
offset00 = 2;
|
|
||||||
offset01 = 15;
|
|
||||||
} else if (IsWindows8Point1()) {
|
|
||||||
pattern = "8BFF 51 833D????????00 7507 A1????????";
|
|
||||||
offset00 = 5;
|
|
||||||
offset01 = 13;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MODULEINFO modinfo;
|
|
||||||
GetModuleInformation(GetCurrentProcess(), hModule, &modinfo, sizeof(MODULEINFO));
|
|
||||||
|
|
||||||
LPBYTE ptr = patternfind(modinfo.lpBaseOfDll, modinfo.SizeOfImage, 0, pattern);
|
|
||||||
if (!ptr) {
|
|
||||||
trace(L"No pattern match!");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
trace(L"wuaueng!IsDeviceServiceable VA: %p", ptr);
|
|
||||||
BOOL result = FALSE;
|
|
||||||
LPBOOL lpbFirstRun, lpbIsCPUSupportedResult;
|
|
||||||
#ifdef _AMD64_
|
|
||||||
lpbFirstRun = (LPBOOL)(ptr + offset00 + sizeof(uint32_t) + *(uint32_t *)(ptr + offset00));
|
|
||||||
lpbIsCPUSupportedResult = (LPBOOL)(ptr + offset01 + sizeof(uint32_t) + *(uint32_t *)(ptr + offset01));
|
|
||||||
#elif defined(_X86_)
|
|
||||||
lpbFirstRun = (LPBOOL)(*(uintptr_t *)(ptr + offset00));
|
|
||||||
lpbIsCPUSupportedResult = (LPBOOL)(*(uintptr_t *)(ptr + offset01));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DWORD flNewProtect = PAGE_READWRITE;
|
|
||||||
DWORD flOldProtect;
|
|
||||||
if (*lpbFirstRun) {
|
|
||||||
VirtualProtect(lpbFirstRun, sizeof(BOOL), flNewProtect, &flOldProtect);
|
|
||||||
*lpbFirstRun = FALSE;
|
|
||||||
VirtualProtect(lpbFirstRun, sizeof(BOOL), flOldProtect, &flNewProtect);
|
|
||||||
trace(L"Patched boolean value #1: %p = %08x", lpbFirstRun, *lpbFirstRun);
|
|
||||||
result = TRUE;
|
|
||||||
}
|
|
||||||
if (!*lpbIsCPUSupportedResult) {
|
|
||||||
VirtualProtect(lpbIsCPUSupportedResult, sizeof(BOOL), flNewProtect, &flOldProtect);
|
|
||||||
*lpbIsCPUSupportedResult = TRUE;
|
|
||||||
VirtualProtect(lpbIsCPUSupportedResult, sizeof(BOOL), flOldProtect, &flNewProtect);
|
|
||||||
trace(L"Patched boolean value #2: %p = %08x", lpbIsCPUSupportedResult, *lpbIsCPUSupportedResult);
|
|
||||||
result = TRUE;
|
|
||||||
}
|
|
||||||
if (result)
|
|
||||||
trace(L"Successfully patched WUA module!");
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
@@ -1,23 +1,33 @@
|
|||||||
|
#ifndef HOOKS_H
|
||||||
|
#define HOOKS_H
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
typedef HMODULE(WINAPI *LOADLIBRARYEXA)(LPCSTR, HANDLE, DWORD);
|
//#define WIN32_NO_STATUS
|
||||||
|
#include <Windows.h>
|
||||||
|
//#undef WIN32_NO_STATUS
|
||||||
|
|
||||||
|
//typedef enum _KEY_INFORMATION_CLASS {
|
||||||
|
// KeyBasicInformation = 0,
|
||||||
|
// KeyNodeInformation = 1,
|
||||||
|
// KeyFullInformation = 2,
|
||||||
|
// KeyNameInformation = 3,
|
||||||
|
// KeyCachedInformation = 4,
|
||||||
|
// KeyFlagsInformation = 5,
|
||||||
|
// KeyVirtualizationInformation = 6,
|
||||||
|
// KeyHandleTagsInformation = 7,
|
||||||
|
// MaxKeyInfoClass = 8
|
||||||
|
//} KEY_INFORMATION_CLASS;
|
||||||
|
//
|
||||||
|
//typedef NTSTATUS(NTAPI *NTQUERYKEY)(HANDLE, KEY_INFORMATION_CLASS, PVOID, ULONG, PULONG);
|
||||||
|
//
|
||||||
|
//typedef LRESULT(WINAPI *REGQUERYVALUEEXW)(HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD);
|
||||||
typedef HMODULE(WINAPI *LOADLIBRARYEXW)(LPCWSTR, HANDLE, DWORD);
|
typedef HMODULE(WINAPI *LOADLIBRARYEXW)(LPCWSTR, HANDLE, DWORD);
|
||||||
|
|
||||||
|
//extern REGQUERYVALUEEXW fpRegQueryValueExW;
|
||||||
extern LOADLIBRARYEXW fpLoadLibraryExW;
|
extern LOADLIBRARYEXW fpLoadLibraryExW;
|
||||||
extern LOADLIBRARYEXA fpLoadLibraryExA;
|
|
||||||
|
|
||||||
DWORD WINAPI NewThreadProc(LPVOID lpParam);
|
LRESULT WINAPI RegQueryValueExW_hook(HKEY hKey, LPCTSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
|
||||||
|
|
||||||
HMODULE WINAPI LoadLibraryExA_hook(
|
HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags);
|
||||||
_In_ LPCSTR lpFileName,
|
|
||||||
_Reserved_ HANDLE hFile,
|
|
||||||
_In_ DWORD dwFlags
|
|
||||||
);
|
|
||||||
|
|
||||||
HMODULE WINAPI LoadLibraryExW_hook(
|
#endif
|
||||||
_In_ LPCWSTR lpFileName,
|
|
||||||
_Reserved_ HANDLE hFile,
|
|
||||||
_In_ DWORD dwFlags
|
|
||||||
);
|
|
||||||
|
|
||||||
BOOL PatchWUA(HMODULE hModule);
|
|
||||||
|
@@ -1,39 +1,41 @@
|
|||||||
#include <Windows.h>
|
|
||||||
|
|
||||||
#include "logging.h"
|
|
||||||
#include "iathook.h"
|
#include "iathook.h"
|
||||||
|
|
||||||
VOID iat_hook(HMODULE hModule, LPCSTR lpFuncName, LPVOID *lpOldAddress, LPVOID lpNewAddress) {
|
#include "logging.h"
|
||||||
LPVOID *lpAddress = iat_find(hModule, lpFuncName);
|
|
||||||
if (!lpAddress || *lpAddress == lpNewAddress)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!hModule)
|
#include <Windows.h>
|
||||||
hModule = GetModuleHandle(NULL);
|
#include <tchar.h>
|
||||||
|
|
||||||
trace(L"Modified import address: hmod=%p, import=%S, old addr=%p, new addr=%p", hModule, lpFuncName, *lpAddress, lpNewAddress);
|
|
||||||
|
|
||||||
DWORD flOldProtect;
|
|
||||||
DWORD flNewProtect = PAGE_READWRITE;
|
|
||||||
VirtualProtect(lpAddress, sizeof(LPVOID), flNewProtect, &flOldProtect);
|
|
||||||
if (lpOldAddress)
|
|
||||||
*lpOldAddress = *lpAddress;
|
|
||||||
*lpAddress = lpNewAddress;
|
|
||||||
VirtualProtect(lpAddress, sizeof(LPVOID), flOldProtect, &flNewProtect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static LPVOID *iat_find(HMODULE hModule, LPCSTR lpFunctionName) {
|
static LPVOID *iat_find(HMODULE hModule, LPCSTR lpFunctionName) {
|
||||||
uintptr_t hm = (uintptr_t)hModule;
|
uintptr_t hm = (uintptr_t)hModule;
|
||||||
|
|
||||||
for (PIMAGE_IMPORT_DESCRIPTOR iid = (PIMAGE_IMPORT_DESCRIPTOR)(hm + ((PIMAGE_NT_HEADERS)(hm + ((PIMAGE_DOS_HEADER)hm)->e_lfanew))
|
for ( PIMAGE_IMPORT_DESCRIPTOR iid = (PIMAGE_IMPORT_DESCRIPTOR)(hm + ((PIMAGE_NT_HEADERS)(hm + ((PIMAGE_DOS_HEADER)hm)->e_lfanew))
|
||||||
->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); iid->Name; iid++) {
|
->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); iid->Name; iid++ ) {
|
||||||
|
|
||||||
LPVOID *pp;
|
LPVOID *pp;
|
||||||
for (SIZE_T i = 0; *(pp = i + (LPVOID *)(hm + iid->FirstThunk)); i++) {
|
for ( size_t i = 0; *(pp = i + (LPVOID *)(hm + iid->FirstThunk)); i++ ) {
|
||||||
LPSTR fn = (LPSTR)(hm + *(i + (SIZE_T *)(hm + iid->OriginalFirstThunk)) + 2);
|
LPSTR fn = (LPSTR)(hm + *(i + (PSIZE_T)(hm + iid->OriginalFirstThunk)) + 2);
|
||||||
if (!((uintptr_t)fn & IMAGE_ORDINAL_FLAG) && !_stricmp(lpFunctionName, fn))
|
if ( !((uintptr_t)fn & IMAGE_ORDINAL_FLAG) && !_stricmp((const char *)lpFunctionName, (char *)fn) )
|
||||||
return pp;
|
return pp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void iat_hook(HMODULE hModule, LPCSTR lpFuncName, LPVOID *lpOldAddress, LPVOID lpNewAddress) {
|
||||||
|
LPVOID *lpAddress = iat_find(hModule, lpFuncName);
|
||||||
|
if ( !lpAddress || *lpAddress == lpNewAddress )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( !hModule )
|
||||||
|
hModule = GetModuleHandle(NULL);
|
||||||
|
|
||||||
|
trace(_T("Modified IAT: hModule=%p, Name=%hs, OldAddress=%p, NewAddress=%p"), hModule, lpFuncName, *lpAddress, lpNewAddress);
|
||||||
|
|
||||||
|
DWORD flOldProtect;
|
||||||
|
DWORD flNewProtect = PAGE_READWRITE;
|
||||||
|
VirtualProtect(lpAddress, sizeof(LPVOID), flNewProtect, &flOldProtect);
|
||||||
|
if ( lpOldAddress )
|
||||||
|
*lpOldAddress = *lpAddress;
|
||||||
|
*lpAddress = lpNewAddress;
|
||||||
|
VirtualProtect(lpAddress, sizeof(LPVOID), flOldProtect, &flNewProtect);
|
||||||
|
}
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
|
#ifndef IATHOOK_H
|
||||||
|
#define IATHOOK_H
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
VOID iat_hook(HMODULE hModule, LPCSTR lpFuncName, LPVOID *lpOldAddress, LPVOID lpNewAddress);
|
#include <Windows.h>
|
||||||
|
|
||||||
static LPVOID *iat_find(HMODULE hModule, LPCSTR lpFunctionName);
|
void iat_hook(HMODULE hModule, LPCSTR lpFuncName, LPVOID *lpOldAddress, LPVOID lpNewAddress);
|
||||||
|
#endif
|
||||||
|
@@ -1,53 +1,59 @@
|
|||||||
#include <Windows.h>
|
#include "logging.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
#include <Psapi.h>
|
#include <Psapi.h>
|
||||||
|
|
||||||
#include "helpers.h"
|
|
||||||
#include "logging.h"
|
|
||||||
|
|
||||||
static FILE *fp;
|
static FILE *fp;
|
||||||
static BOOL logging_enabled = FALSE;
|
static BOOL logging_enabled = FALSE;
|
||||||
|
|
||||||
BOOL logging_init(void) {
|
BOOL InitLogging(void) {
|
||||||
if (fp)
|
if ( fp )
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
WCHAR filename[MAX_PATH];
|
TCHAR filename[MAX_PATH];
|
||||||
GetModuleFileNameW(HINST_THISCOMPONENT, filename, _countof(filename));
|
GetModuleFileName(HINST_THISCOMPONENT, filename, _countof(filename));
|
||||||
WCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME];
|
|
||||||
_wsplitpath_s(filename, drive, _countof(drive), dir, _countof(dir), fname, _countof(fname), NULL, 0);
|
|
||||||
|
|
||||||
WCHAR basename[MAX_PATH];
|
TCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME];
|
||||||
|
_tsplitpath_s(filename, drive, _countof(drive), dir, _countof(dir), fname, _countof(fname), NULL, 0);
|
||||||
|
|
||||||
|
TCHAR basename[MAX_PATH];
|
||||||
GetModuleBaseNameW(GetCurrentProcess(), NULL, basename, _countof(basename));
|
GetModuleBaseNameW(GetCurrentProcess(), NULL, basename, _countof(basename));
|
||||||
wcscat_s(fname, _countof(fname), L".");
|
_tcscat_s(fname, _countof(fname), _T("."));
|
||||||
wcscat_s(fname, _countof(fname), basename);
|
_tcscat_s(fname, _countof(fname), basename);
|
||||||
_wmakepath_s(filename, _countof(filename), drive, dir, fname, L".log");
|
_tmakepath_s(filename, _countof(filename), drive, dir, fname, _T(".log"));
|
||||||
|
|
||||||
HANDLE hFile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
HANDLE hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
LARGE_INTEGER size;
|
LARGE_INTEGER size;
|
||||||
GetFileSizeEx(hFile, &size);
|
GetFileSizeEx(hFile, &size);
|
||||||
CloseHandle(hFile);
|
CloseHandle(hFile);
|
||||||
fp = _wfsopen(filename, size.QuadPart < (1 << 20) ? L"at" : L"wt", _SH_DENYWR);
|
fp = _tfsopen(filename, size.QuadPart < (1 << 20) ? _T("at") : _T("wt"), _SH_DENYWR);
|
||||||
return (fp != NULL);
|
return (fp != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID trace_(LPCWSTR format, ...) {
|
void trace_(LPCTSTR format, ...) {
|
||||||
if (logging_init()) {
|
static DWORD dwProcessId = 0;
|
||||||
WCHAR datebuf[9], timebuf[9];
|
|
||||||
_wstrdate_s(datebuf, _countof(datebuf));
|
if ( InitLogging() ) {
|
||||||
_wstrtime_s(timebuf, _countof(timebuf));
|
if ( !dwProcessId )
|
||||||
fwprintf_s(fp, L"%s %s [%d] ", datebuf, timebuf, GetCurrentProcessId());
|
dwProcessId = GetCurrentProcessId();
|
||||||
|
|
||||||
|
TCHAR datebuf[9], timebuf[9];
|
||||||
|
_tstrdate_s(datebuf, _countof(datebuf));
|
||||||
|
_tstrtime_s(timebuf, _countof(timebuf));
|
||||||
|
_ftprintf_s(fp, _T("%s %s [%d] "), datebuf, timebuf, dwProcessId);
|
||||||
|
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
va_start(argptr, format);
|
va_start(argptr, format);
|
||||||
vfwprintf_s(fp, format, argptr);
|
_vftprintf_s(fp, format, argptr);
|
||||||
va_end(argptr);
|
va_end(argptr);
|
||||||
fflush(fp);
|
fflush(fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL logging_free(void) {
|
BOOL FreeLogging(void) {
|
||||||
return fp && !fclose(fp);
|
return fp && !fclose(fp);
|
||||||
}
|
}
|
||||||
|
@@ -1,13 +1,20 @@
|
|||||||
|
#ifndef LOGGING_H
|
||||||
|
#define LOGGING_H
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
BOOL logging_init(void);
|
#include <Windows.h>
|
||||||
VOID trace_(LPCWSTR format, ...);
|
#include <tchar.h>
|
||||||
BOOL logging_free(void);
|
|
||||||
|
extern IMAGE_DOS_HEADER __ImageBase;
|
||||||
|
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
|
||||||
|
|
||||||
|
BOOL InitLogging(void);
|
||||||
|
void trace_(LPCTSTR format, ...);
|
||||||
|
BOOL FreeLogging(void);
|
||||||
|
|
||||||
#define STRINGIZE_(x) #x
|
#define STRINGIZE_(x) #x
|
||||||
#define STRINGIZE(x) STRINGIZE_(x)
|
#define STRINGIZE(x) STRINGIZE_(x)
|
||||||
|
|
||||||
#define STRINGIZEW_(x) L#x
|
#define __LINESTR__ STRINGIZE(__LINE__)
|
||||||
#define STRINGIZEW(x) STRINGIZEW_(x)
|
#define trace(format, ...) trace_(_T(__FILE__) _T(":") _T(__LINESTR__) _T("(") _T(__FUNCTION__) _T("): ") format _T("\n"), ##__VA_ARGS__)
|
||||||
#define __LINEWSTR__ STRINGIZEW(__LINE__)
|
#endif
|
||||||
#define trace(format, ...) trace_(__FILEW__ L":" __LINEWSTR__ L"(" __FUNCTIONW__ L"): " format L"\n", ##__VA_ARGS__)
|
|
||||||
|
56
wufuc/ntdllhelper.c
Normal file
56
wufuc/ntdllhelper.c
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#include "ntdllhelper.h"
|
||||||
|
|
||||||
|
#define WIN32_NO_STATUS
|
||||||
|
#include <windows.h>
|
||||||
|
#undef WIN32_NO_STATUS
|
||||||
|
|
||||||
|
#include <winternl.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
|
||||||
|
HMODULE g_hNTDLL = NULL;
|
||||||
|
|
||||||
|
BOOL InitNTDLL(void) {
|
||||||
|
if ( !g_hNTDLL )
|
||||||
|
g_hNTDLL = LoadLibrary(_T("ntdll"));
|
||||||
|
return (g_hNTDLL != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL FreeNTDLL(void) {
|
||||||
|
if ( g_hNTDLL ) {
|
||||||
|
BOOL result = FreeLibrary(g_hNTDLL);
|
||||||
|
if ( result )
|
||||||
|
g_hNTDLL = NULL;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL TryLdrRegisterDllNotification(ULONG Flags, PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction, PVOID Context, PVOID *Cookie, NTSTATUS *result) {
|
||||||
|
static LDRREGISTERDLLNOTIFICATION fpLdrRegisterDllNotification = NULL;
|
||||||
|
|
||||||
|
if ( InitNTDLL() ) {
|
||||||
|
if ( !fpLdrRegisterDllNotification )
|
||||||
|
fpLdrRegisterDllNotification = (LDRREGISTERDLLNOTIFICATION)GetProcAddress(g_hNTDLL, "LdrRegisterDllNotification");
|
||||||
|
|
||||||
|
if ( fpLdrRegisterDllNotification ) {
|
||||||
|
*result = fpLdrRegisterDllNotification(Flags, NotificationFunction, Context, Cookie);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL TryLdrUnregisterDllNotification(PVOID Cookie, NTSTATUS *result) {
|
||||||
|
static LDRUNREGISTERDLLNOTIFICATION fpLdrUnregisterDllNotification = NULL;
|
||||||
|
|
||||||
|
if ( InitNTDLL() ) {
|
||||||
|
if ( !fpLdrUnregisterDllNotification )
|
||||||
|
fpLdrUnregisterDllNotification = (LDRUNREGISTERDLLNOTIFICATION)GetProcAddress(g_hNTDLL, "LdrUnregisterDllNotification");
|
||||||
|
|
||||||
|
if ( fpLdrUnregisterDllNotification ) {
|
||||||
|
*result = fpLdrUnregisterDllNotification(Cookie);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
49
wufuc/ntdllhelper.h
Normal file
49
wufuc/ntdllhelper.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#ifndef NTDLLHELPER_H
|
||||||
|
#define NTDLLHELPER_H
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WIN32_NO_STATUS
|
||||||
|
#include <windows.h>
|
||||||
|
#undef WIN32_NO_STATUS
|
||||||
|
|
||||||
|
#include <winternl.h>
|
||||||
|
|
||||||
|
typedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA {
|
||||||
|
ULONG Flags;
|
||||||
|
PUNICODE_STRING FullDllName;
|
||||||
|
PUNICODE_STRING BaseDllName;
|
||||||
|
PVOID DllBase;
|
||||||
|
ULONG SizeOfImage;
|
||||||
|
} LDR_DLL_LOADED_NOTIFICATION_DATA, *PLDR_DLL_LOADED_NOTIFICATION_DATA;
|
||||||
|
|
||||||
|
typedef struct _LDR_DLL_UNLOADED_NOTIFICATION_DATA {
|
||||||
|
ULONG Flags;
|
||||||
|
PCUNICODE_STRING FullDllName;
|
||||||
|
PCUNICODE_STRING BaseDllName;
|
||||||
|
PVOID DllBase;
|
||||||
|
ULONG SizeOfImage;
|
||||||
|
} LDR_DLL_UNLOADED_NOTIFICATION_DATA, *PLDR_DLL_UNLOADED_NOTIFICATION_DATA;
|
||||||
|
|
||||||
|
typedef union _LDR_DLL_NOTIFICATION_DATA {
|
||||||
|
LDR_DLL_LOADED_NOTIFICATION_DATA Loaded;
|
||||||
|
LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded;
|
||||||
|
} LDR_DLL_NOTIFICATION_DATA, *PLDR_DLL_NOTIFICATION_DATA;
|
||||||
|
typedef const LDR_DLL_NOTIFICATION_DATA *PCLDR_DLL_NOTIFICATION_DATA;
|
||||||
|
|
||||||
|
typedef VOID(CALLBACK *PLDR_DLL_NOTIFICATION_FUNCTION)(ULONG, PCLDR_DLL_NOTIFICATION_DATA, PVOID);
|
||||||
|
|
||||||
|
#define LDR_DLL_NOTIFICATION_REASON_LOADED 1
|
||||||
|
#define LDR_DLL_NOTIFICATION_REASON_UNLOADED 2
|
||||||
|
|
||||||
|
typedef NTSTATUS(NTAPI *LDRREGISTERDLLNOTIFICATION)(ULONG, PLDR_DLL_NOTIFICATION_FUNCTION, PVOID, PVOID *);
|
||||||
|
typedef NTSTATUS(NTAPI *LDRUNREGISTERDLLNOTIFICATION)(PVOID);
|
||||||
|
|
||||||
|
extern HMODULE g_hNTDLL;
|
||||||
|
|
||||||
|
BOOL InitNTDLL(void);
|
||||||
|
|
||||||
|
BOOL FreeNTDLL(void);
|
||||||
|
|
||||||
|
BOOL TryLdrRegisterDllNotification(ULONG Flags, PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction, PVOID Context, PVOID *Cookie, NTSTATUS *result);
|
||||||
|
BOOL TryLdrUnregisterDllNotification(PVOID Cookie, NTSTATUS *result);
|
||||||
|
#endif
|
68
wufuc/patchwua.c
Normal file
68
wufuc/patchwua.c
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#include "patchwua.h"
|
||||||
|
|
||||||
|
#include "patternfind.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <Psapi.h>
|
||||||
|
|
||||||
|
|
||||||
|
BOOL PatchWUA(void *lpBaseOfDll, size_t SizeOfImage) {
|
||||||
|
char *pattern;
|
||||||
|
size_t offset00, offset01;
|
||||||
|
#ifdef _AMD64_
|
||||||
|
pattern = "FFF3 4883EC?? 33DB 391D???????? 7508 8B05????????";
|
||||||
|
offset00 = 10;
|
||||||
|
offset01 = 18;
|
||||||
|
#elif defined(_X86_)
|
||||||
|
if ( IsWindows7() ) {
|
||||||
|
pattern = "833D????????00 743E E8???????? A3????????";
|
||||||
|
offset00 = 2;
|
||||||
|
offset01 = 15;
|
||||||
|
} else if ( IsWindows8Point1() ) {
|
||||||
|
pattern = "8BFF 51 833D????????00 7507 A1????????";
|
||||||
|
offset00 = 5;
|
||||||
|
offset01 = 13;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned char *ptr = patternfind(lpBaseOfDll, SizeOfImage, 0, pattern);
|
||||||
|
if ( !ptr ) {
|
||||||
|
trace(_T("No pattern match!"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
trace(_T("wuaueng!IsDeviceServiceable VA: %p"), ptr);
|
||||||
|
BOOL result = FALSE;
|
||||||
|
LPBOOL lpbFirstRun, lpbIsCPUSupportedResult;
|
||||||
|
#ifdef _AMD64_
|
||||||
|
lpbFirstRun = (LPBOOL)(ptr + offset00 + sizeof(uint32_t) + *(uint32_t *)(ptr + offset00));
|
||||||
|
lpbIsCPUSupportedResult = (LPBOOL)(ptr + offset01 + sizeof(uint32_t) + *(uint32_t *)(ptr + offset01));
|
||||||
|
#elif defined(_X86_)
|
||||||
|
lpbFirstRun = (LPBOOL)(*(uintptr_t *)(ptr + offset00));
|
||||||
|
lpbIsCPUSupportedResult = (LPBOOL)(*(uintptr_t *)(ptr + offset01));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DWORD flNewProtect = PAGE_READWRITE;
|
||||||
|
DWORD flOldProtect;
|
||||||
|
if ( *lpbFirstRun ) {
|
||||||
|
VirtualProtect(lpbFirstRun, sizeof(BOOL), flNewProtect, &flOldProtect);
|
||||||
|
*lpbFirstRun = FALSE;
|
||||||
|
VirtualProtect(lpbFirstRun, sizeof(BOOL), flOldProtect, &flNewProtect);
|
||||||
|
trace(_T("Patched boolean value #1: %p = %s"), lpbFirstRun, *lpbFirstRun ? L"TRUE" : L"FALSE");
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
if ( !*lpbIsCPUSupportedResult ) {
|
||||||
|
VirtualProtect(lpbIsCPUSupportedResult, sizeof(BOOL), flNewProtect, &flOldProtect);
|
||||||
|
*lpbIsCPUSupportedResult = TRUE;
|
||||||
|
VirtualProtect(lpbIsCPUSupportedResult, sizeof(BOOL), flOldProtect, &flNewProtect);
|
||||||
|
trace(_T("Patched boolean value #2: %p = %s"), lpbIsCPUSupportedResult, *lpbIsCPUSupportedResult ? L"TRUE" : L"FALSE");
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
if ( result )
|
||||||
|
trace(_T("Successfully patched WUA module!"));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
8
wufuc/patchwua.h
Normal file
8
wufuc/patchwua.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef PATCHWUA_H
|
||||||
|
#define PATCHWUA_H
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
BOOL PatchWUA(void *lpBaseOfDll, size_t SizeOfImage);
|
||||||
|
#endif
|
@@ -1,30 +1,31 @@
|
|||||||
#include <Windows.h>
|
|
||||||
#include "patternfind.h"
|
#include "patternfind.h"
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
/* Ported to C from x64dbg's patternfind.cpp:
|
/* Ported to C from x64dbg's patternfind.cpp:
|
||||||
* https://github.com/x64dbg/x64dbg/blob/development/src/dbg/patternfind.cpp
|
* https://github.com/x64dbg/x64dbg/blob/development/src/dbg/patternfind.cpp
|
||||||
* x64dbg license (GPL-3.0):
|
* x64dbg license (GPL-3.0):
|
||||||
* https://github.com/x64dbg/x64dbg/blob/development/LICENSE
|
* https://github.com/x64dbg/x64dbg/blob/development/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int hexchtoint(CHAR c) {
|
static int hexchtoint(char c) {
|
||||||
int result = -1;
|
int result = -1;
|
||||||
if (c >= '0' && c <= '9')
|
if ( c >= '0' && c <= '9' )
|
||||||
result = c - '0';
|
result = c - '0';
|
||||||
else if (c >= 'A' && c <= 'F')
|
else if ( c >= 'A' && c <= 'F' )
|
||||||
result = c - 'A' + 10;
|
result = c - 'A' + 10;
|
||||||
else if (c >= 'a' && c <= 'f')
|
else if ( c >= 'a' && c <= 'f' )
|
||||||
result = c - 'a' + 10;
|
result = c - 'a' + 10;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
SIZE_T formathexpattern(LPCSTR patterntext, LPSTR formattext, SIZE_T formattextsize) {
|
static size_t formathexpattern(const char *patterntext, char *formattext, size_t formattextsize) {
|
||||||
SIZE_T len = strlen(patterntext);
|
size_t len = strlen(patterntext);
|
||||||
SIZE_T result = 0;
|
size_t result = 0;
|
||||||
for (SIZE_T i = 0; i < len && (!formattext || result < formattextsize); i++) {
|
for ( size_t i = 0; i < len && (!formattext || result < formattextsize); i++ ) {
|
||||||
if (patterntext[i] == '?' || hexchtoint(patterntext[i]) != -1) {
|
if ( patterntext[i] == '?' || hexchtoint(patterntext[i]) != -1 ) {
|
||||||
if (formattext)
|
if ( formattext )
|
||||||
formattext[result] = patterntext[i];
|
formattext[result] = patterntext[i];
|
||||||
|
|
||||||
result++;
|
result++;
|
||||||
@@ -33,21 +34,21 @@ SIZE_T formathexpattern(LPCSTR patterntext, LPSTR formattext, SIZE_T formattexts
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL patterntransform(LPCSTR patterntext, LPPATTERNBYTE pattern, SIZE_T *patternsize) {
|
static BOOL patterntransform(const char *patterntext, LPPATTERNBYTE pattern, size_t *patternsize) {
|
||||||
SIZE_T cb = formathexpattern(patterntext, NULL, 0);
|
size_t cb = formathexpattern(patterntext, NULL, 0);
|
||||||
if (!cb || cb > *patternsize)
|
if ( !cb || cb > *patternsize )
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
LPSTR formattext = calloc(cb, sizeof(CHAR));
|
char *formattext = calloc(cb, sizeof(char));
|
||||||
cb = formathexpattern(patterntext, formattext, cb);
|
cb = formathexpattern(patterntext, formattext, cb);
|
||||||
|
|
||||||
if (cb % 2)
|
if ( cb % 2 )
|
||||||
formattext[cb++] = '?';
|
formattext[cb++] = '?';
|
||||||
|
|
||||||
formattext[cb] = '\0';
|
formattext[cb] = '\0';
|
||||||
|
|
||||||
for (SIZE_T i = 0, j = 0, k = 0; i < cb; i++, j ^= 1, k = (i - j) >> 1) {
|
for ( size_t i = 0, j = 0, k = 0; i < cb; i++, j ^= 1, k = (i - j) >> 1 ) {
|
||||||
if (formattext[i] == '?')
|
if ( formattext[i] == '?' )
|
||||||
pattern[k].nibble[j].wildcard = TRUE;
|
pattern[k].nibble[j].wildcard = TRUE;
|
||||||
else {
|
else {
|
||||||
pattern[k].nibble[j].wildcard = FALSE;
|
pattern[k].nibble[j].wildcard = FALSE;
|
||||||
@@ -59,21 +60,61 @@ BOOL patterntransform(LPCSTR patterntext, LPPATTERNBYTE pattern, SIZE_T *pattern
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
LPBYTE patternfind(LPBYTE data, SIZE_T datasize, SIZE_T startindex, LPCSTR pattern) {
|
static void patternwritebyte(unsigned char *byte, LPPATTERNBYTE pbyte) {
|
||||||
LPBYTE result = NULL;
|
unsigned char n1 = (*byte >> 4) & 0xf;
|
||||||
SIZE_T searchpatternsize = strlen(pattern);
|
unsigned char 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL patternwrite(unsigned char *data, size_t datasize, const char *pattern) {
|
||||||
|
size_t writepatternsize = strlen(pattern);
|
||||||
|
if ( writepatternsize > datasize )
|
||||||
|
writepatternsize = datasize;
|
||||||
|
|
||||||
|
BOOL result = FALSE;
|
||||||
|
LPPATTERNBYTE writepattern = calloc(writepatternsize, sizeof(PATTERNBYTE));
|
||||||
|
if ( patterntransform(pattern, writepattern, &writepatternsize) ) {
|
||||||
|
DWORD flNewProtect = PAGE_READWRITE;
|
||||||
|
DWORD flOldProtect;
|
||||||
|
|
||||||
|
if ( result = VirtualProtect(data, writepatternsize, flNewProtect, &flOldProtect) ) {
|
||||||
|
for ( size_t i = 0; i < writepatternsize; i++ ) {
|
||||||
|
BYTE n1 = (data[i] >> 4) & 0xf;
|
||||||
|
BYTE n2 = data[i] & 0xf;
|
||||||
|
if ( !writepattern[i].nibble[0].wildcard )
|
||||||
|
n1 = writepattern[i].nibble[0].data;
|
||||||
|
|
||||||
|
if ( !writepattern[i].nibble[1].wildcard )
|
||||||
|
n2 = writepattern[i].nibble[1].data;
|
||||||
|
data[i] = ((n1 << 4) & 0xf0) | (n2 & 0xf);
|
||||||
|
result = VirtualProtect(data, writepatternsize, flOldProtect, &flNewProtect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(writepattern);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *patternfind(unsigned char *data, size_t datasize, size_t startindex, const char *pattern) {
|
||||||
|
unsigned char *result = NULL;
|
||||||
|
size_t searchpatternsize = strlen(pattern);
|
||||||
LPPATTERNBYTE searchpattern = calloc(searchpatternsize, sizeof(PATTERNBYTE));
|
LPPATTERNBYTE searchpattern = calloc(searchpatternsize, sizeof(PATTERNBYTE));
|
||||||
|
|
||||||
if (patterntransform(pattern, searchpattern, &searchpatternsize)) {
|
if ( patterntransform(pattern, searchpattern, &searchpatternsize) ) {
|
||||||
for (SIZE_T i = startindex, j = 0; i < datasize; i++) { //search for the pattern
|
for ( size_t i = startindex, j = 0; i < datasize; i++ ) { //search for the pattern
|
||||||
if ((searchpattern[j].nibble[0].wildcard || searchpattern[j].nibble[0].data == ((data[i] >> 4) & 0xf))
|
if ( (searchpattern[j].nibble[0].wildcard || searchpattern[j].nibble[0].data == ((data[i] >> 4) & 0xf))
|
||||||
&& (searchpattern[j].nibble[1].wildcard || searchpattern[j].nibble[1].data == (data[i] & 0xf))) { //check if our pattern matches the current byte
|
&& (searchpattern[j].nibble[1].wildcard || searchpattern[j].nibble[1].data == (data[i] & 0xf)) ) { //check if our pattern matches the current byte
|
||||||
|
|
||||||
if (++j == searchpatternsize) { //everything matched
|
if ( ++j == searchpatternsize ) { //everything matched
|
||||||
result = data + (i - searchpatternsize + 1);
|
result = data + (i - searchpatternsize + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (j > 0) { //fix by Computer_Angel
|
} else if ( j > 0 ) { //fix by Computer_Angel
|
||||||
i -= j;
|
i -= j;
|
||||||
j = 0; //reset current pattern position
|
j = 0; //reset current pattern position
|
||||||
}
|
}
|
||||||
@@ -83,51 +124,9 @@ LPBYTE patternfind(LPBYTE data, SIZE_T datasize, SIZE_T startindex, LPCSTR patte
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID patternwritebyte(LPBYTE byte, LPPATTERNBYTE pbyte) {
|
unsigned char *patternsnr(unsigned char *data, size_t datasize, size_t startindex, const char *searchpattern, const char *replacepattern) {
|
||||||
BYTE n1 = (*byte >> 4) & 0xf;
|
unsigned char *result = patternfind(data, datasize, startindex, searchpattern);
|
||||||
BYTE n2 = *byte & 0xf;
|
if ( !result )
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL patternwrite(LPBYTE data, SIZE_T datasize, LPCSTR pattern) {
|
|
||||||
|
|
||||||
SIZE_T writepatternsize = strlen(pattern);
|
|
||||||
if (writepatternsize > datasize)
|
|
||||||
writepatternsize = datasize;
|
|
||||||
|
|
||||||
BOOL result = FALSE;
|
|
||||||
LPPATTERNBYTE writepattern = calloc(writepatternsize, sizeof(PATTERNBYTE));
|
|
||||||
if (patterntransform(pattern, writepattern, &writepatternsize)) {
|
|
||||||
DWORD flNewProtect = PAGE_READWRITE;
|
|
||||||
DWORD flOldProtect;
|
|
||||||
|
|
||||||
if (VirtualProtect(data, writepatternsize, flNewProtect, &flOldProtect)) {
|
|
||||||
for (size_t i = 0; i < writepatternsize; i++) {
|
|
||||||
BYTE n1 = (data[i] >> 4) & 0xf;
|
|
||||||
BYTE n2 = data[i] & 0xf;
|
|
||||||
if (!writepattern[i].nibble[0].wildcard)
|
|
||||||
n1 = writepattern[i].nibble[0].data;
|
|
||||||
|
|
||||||
if (!writepattern[i].nibble[1].wildcard)
|
|
||||||
n2 = writepattern[i].nibble[1].data;
|
|
||||||
data[i] = ((n1 << 4) & 0xf0) | (n2 & 0xf);
|
|
||||||
|
|
||||||
}
|
|
||||||
result = VirtualProtect(data, writepatternsize, flOldProtect, &flNewProtect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(writepattern);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPBYTE patternsnr(LPBYTE data, SIZE_T datasize, SIZE_T startindex, LPCSTR searchpattern, LPCSTR replacepattern) {
|
|
||||||
LPBYTE result = patternfind(data, datasize, startindex, searchpattern);
|
|
||||||
if (result == NULL)
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
patternwrite(result, datasize, replacepattern);
|
patternwrite(result, datasize, replacepattern);
|
||||||
|
@@ -1,16 +1,16 @@
|
|||||||
|
#ifndef PATTERNFIND_H
|
||||||
|
#define PATTERNFIND_H
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
typedef struct _PATTERNBYTE {
|
typedef struct _PATTERNBYTE {
|
||||||
struct _PATTERNNIBBLE {
|
struct _PATTERNNIBBLE {
|
||||||
BYTE data;
|
unsigned char data;
|
||||||
BOOL wildcard;
|
BOOL wildcard;
|
||||||
} nibble[2];
|
} nibble[2];
|
||||||
} PATTERNBYTE, *PPATTERNBYTE, *LPPATTERNBYTE;
|
} PATTERNBYTE, *PPATTERNBYTE, *LPPATTERNBYTE;
|
||||||
|
|
||||||
int hexchtoint(CHAR ch);
|
unsigned char *patternfind(unsigned char *data, size_t datasize, size_t startindex, const char *pattern);
|
||||||
SIZE_T formathexpattern(LPCSTR patterntext, LPSTR formattext, SIZE_T formattextsize);
|
unsigned char *patternsnr(unsigned char *data, size_t datasize, size_t startindex, const char *searchpattern, const char *replacepattern);
|
||||||
BOOL patterntransform(LPCSTR patterntext, LPPATTERNBYTE pattern, SIZE_T *patternsize);
|
#endif
|
||||||
LPBYTE patternfind(LPBYTE data, SIZE_T datasize, SIZE_T startindex, LPCSTR pattern);
|
|
||||||
VOID patternwritebyte(LPBYTE byte, LPPATTERNBYTE pbyte);
|
|
||||||
BOOL patternwrite(LPBYTE data, SIZE_T datasize, LPCSTR pattern);
|
|
||||||
LPBYTE patternsnr(LPBYTE data, SIZE_T datasize, SIZE_T startindex, LPCSTR searchpattern, LPCSTR replacepattern);
|
|
||||||
|
@@ -1,87 +1,84 @@
|
|||||||
#include <Windows.h>
|
#include "service.h"
|
||||||
#include <TlHelp32.h>
|
|
||||||
#include <tchar.h>
|
|
||||||
#include <VersionHelpers.h>
|
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "service.h"
|
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <TlHelp32.h>
|
||||||
|
#include <VersionHelpers.h>
|
||||||
|
|
||||||
|
__declspec(dllexport)
|
||||||
void CALLBACK Rundll32Entry(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) {
|
void CALLBACK Rundll32Entry(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) {
|
||||||
HANDLE hEvent = OpenEvent(SYNCHRONIZE, FALSE, _T("Global\\wufuc_UnloadEvent"));
|
HANDLE hEvent = OpenEvent(SYNCHRONIZE, FALSE, _T("Global\\wufuc_UnloadEvent"));
|
||||||
if (hEvent) {
|
if ( hEvent ) {
|
||||||
CloseHandle(hEvent);
|
CloseHandle(hEvent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LPWSTR osname;
|
wchar_t *osname;
|
||||||
if (IsWindows7()) {
|
if ( IsWindows7() ) {
|
||||||
if (IsWindowsServer())
|
if ( IsWindowsServer() )
|
||||||
osname = L"Windows Server 2008 R2";
|
osname = _T("Windows Server 2008 R2");
|
||||||
else
|
else
|
||||||
osname = L"Windows 7";
|
osname = _T("Windows 7");
|
||||||
} else if (IsWindows8Point1()) {
|
} else if ( IsWindows8Point1() ) {
|
||||||
if (IsWindowsServer())
|
if ( IsWindowsServer() )
|
||||||
osname = L"Windows Server 2012 R2";
|
osname = _T("Windows Server 2012 R2");
|
||||||
else
|
else
|
||||||
osname = L"Windows 8.1";
|
osname = _T("Windows 8.1");
|
||||||
}
|
}
|
||||||
trace(L"Operating System: %s %d-bit", osname, sizeof(uintptr_t) * 8);
|
trace(_T("Operating System: %s %d-bit"), osname, sizeof(uintptr_t) * 8);
|
||||||
|
|
||||||
char brand[0x31];
|
char brand[0x31];
|
||||||
get_cpuid_brand(brand);
|
get_cpuid_brand(brand);
|
||||||
SIZE_T i = 0;
|
size_t i = 0;
|
||||||
while (i < _countof(brand) && isspace(*(brand + i)))
|
while ( i < _countof(brand) && isspace(brand[i]) )
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
trace(L"Processor: %S", brand + i);
|
trace(_T("Processor: %hs"), brand + i);
|
||||||
|
|
||||||
SC_HANDLE hSCManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT);
|
SC_HANDLE hSCManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT);
|
||||||
if (!hSCManager)
|
if ( !hSCManager )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TCHAR lpGroupName[256];
|
TCHAR lpGroupName[256];
|
||||||
DWORD dwProcessId;
|
DWORD dwProcessId;
|
||||||
BOOL result = get_svcpid(hSCManager, _T("wuauserv"), &dwProcessId);
|
BOOL result = GetServiceProcessId(hSCManager, _T("wuauserv"), &dwProcessId);
|
||||||
if (!result && get_svcgname(hSCManager, _T("wuauserv"), lpGroupName, _countof(lpGroupName)))
|
if ( !result && GetServiceGroupName(hSCManager, _T("wuauserv"), lpGroupName, _countof(lpGroupName)) )
|
||||||
result = get_svcgpid(hSCManager, lpGroupName, &dwProcessId);
|
result = GetServiceGroupProcessId(hSCManager, lpGroupName, &dwProcessId);
|
||||||
|
|
||||||
CloseServiceHandle(hSCManager);
|
CloseServiceHandle(hSCManager);
|
||||||
if (!result)
|
if ( !result )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
|
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
|
||||||
if (!hProcess)
|
if ( !hProcess )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TCHAR lpLibFileName[MAX_PATH];
|
TCHAR lpLibFileName[MAX_PATH];
|
||||||
GetModuleFileName(HINST_THISCOMPONENT, lpLibFileName, _countof(lpLibFileName));
|
GetModuleFileName(HINST_THISCOMPONENT, lpLibFileName, _countof(lpLibFileName));
|
||||||
SIZE_T size = (_tcslen(lpLibFileName) + 1) * sizeof(TCHAR);
|
SIZE_T size = (SIZE_T)((_tcslen(lpLibFileName) + 1) * sizeof(TCHAR));
|
||||||
|
|
||||||
LPVOID lpBaseAddress = VirtualAllocEx(hProcess, NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
LPVOID lpBaseAddress = VirtualAllocEx(hProcess, NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||||
if (lpBaseAddress && WriteProcessMemory(hProcess, lpBaseAddress, lpLibFileName, size, NULL)) {
|
|
||||||
|
if ( lpBaseAddress && WriteProcessMemory(hProcess, lpBaseAddress, lpLibFileName, size, NULL) ) {
|
||||||
HANDLE hThread = CreateRemoteThread(
|
HANDLE hThread = CreateRemoteThread(
|
||||||
hProcess,
|
hProcess, NULL, 0,
|
||||||
NULL,
|
(LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), STRINGIZE(LoadLibrary)),
|
||||||
0,
|
lpBaseAddress, 0, NULL
|
||||||
(LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(_T("kernel32.dll")),
|
|
||||||
STRINGIZE(LoadLibrary)),
|
|
||||||
lpBaseAddress,
|
|
||||||
0,
|
|
||||||
NULL
|
|
||||||
);
|
);
|
||||||
WaitForSingleObject(hThread, INFINITE);
|
WaitForSingleObject(hThread, INFINITE);
|
||||||
trace(L"Injected into process: %d", dwProcessId);
|
trace(_T("Injected into process: %d"), dwProcessId);
|
||||||
CloseHandle(hThread);
|
CloseHandle(hThread);
|
||||||
}
|
}
|
||||||
VirtualFreeEx(hProcess, lpBaseAddress, 0, MEM_RELEASE);
|
VirtualFreeEx(hProcess, lpBaseAddress, 0, MEM_RELEASE);
|
||||||
CloseHandle(hProcess);
|
CloseHandle(hProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__declspec(dllexport)
|
||||||
void CALLBACK Rundll32Unload(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) {
|
void CALLBACK Rundll32Unload(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) {
|
||||||
HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, _T("Global\\wufuc_UnloadEvent"));
|
HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, _T("Global\\wufuc_UnloadEvent"));
|
||||||
if (hEvent) {
|
if ( hEvent ) {
|
||||||
trace(L"Setting unload event...");
|
trace(_T("Setting unload event..."));
|
||||||
SetEvent(hEvent);
|
SetEvent(hEvent);
|
||||||
CloseHandle(hEvent);
|
CloseHandle(hEvent);
|
||||||
}
|
}
|
||||||
|
203
wufuc/service.c
203
wufuc/service.c
@@ -1,98 +1,120 @@
|
|||||||
#include <windows.h>
|
#include "service.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "shellapihelper.h"
|
#include "shellapihelper.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "service.h"
|
|
||||||
|
|
||||||
static CHAR wuauservdllA[MAX_PATH];
|
static BOOL OpenServiceParametersKey(LPCWSTR lpSubKey, PHKEY phkResult) {
|
||||||
static WCHAR wuauservdllW[MAX_PATH];
|
|
||||||
|
|
||||||
BOOL get_svcdllA(LPCSTR lpServiceName, LPSTR lpServiceDll, DWORD dwSize) {
|
|
||||||
CHAR lpSubKey[257];
|
|
||||||
sprintf_s(lpSubKey, _countof(lpSubKey), "SYSTEM\\CurrentControlSet\\services\\%s\\Parameters", lpServiceName);
|
|
||||||
DWORD cb = dwSize;
|
|
||||||
if (RegGetValueA(HKEY_LOCAL_MACHINE, lpSubKey, "ServiceDll", RRF_RT_REG_SZ, NULL, lpServiceDll, &cb))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
trace(L"Service \"%S\" DLL path: %S", lpServiceName, lpServiceDll);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL get_svcdllW(LPCWSTR lpServiceName, LPWSTR lpServiceDll, DWORD dwSize) {
|
|
||||||
WCHAR lpSubKey[257];
|
|
||||||
swprintf_s(lpSubKey, _countof(lpSubKey), L"SYSTEM\\CurrentControlSet\\services\\%s\\Parameters", lpServiceName);
|
|
||||||
DWORD cb = dwSize;
|
|
||||||
if (RegGetValueW(HKEY_LOCAL_MACHINE, lpSubKey, L"ServiceDll", RRF_RT_REG_SZ, NULL, lpServiceDll, &cb))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
trace(L"Service \"%s\" DLL path: %s", lpServiceName, lpServiceDll);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPSTR get_wuauservdllA(void) {
|
|
||||||
if (!*wuauservdllA)
|
|
||||||
get_svcdllA("wuauserv", wuauservdllA, _countof(wuauservdllA));
|
|
||||||
|
|
||||||
return wuauservdllA;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPWSTR get_wuauservdllW(void) {
|
|
||||||
if (!*wuauservdllW)
|
|
||||||
get_svcdllW(L"wuauserv", wuauservdllW, _countof(wuauservdllW));
|
|
||||||
|
|
||||||
return wuauservdllW;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL get_svcpid(SC_HANDLE hSCManager, LPCTSTR lpServiceName, DWORD *lpdwProcessId) {
|
|
||||||
SC_HANDLE hService = OpenService(hSCManager, lpServiceName, SERVICE_QUERY_STATUS);
|
|
||||||
if (!hService)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
SERVICE_STATUS_PROCESS lpBuffer;
|
|
||||||
DWORD cbBytesNeeded;
|
|
||||||
BOOL result = FALSE;
|
BOOL result = FALSE;
|
||||||
if (QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&lpBuffer, sizeof(lpBuffer), &cbBytesNeeded)
|
HKEY hKey, hSubKey;
|
||||||
&& lpBuffer.dwProcessId) {
|
if ( !RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\services", 0, KEY_READ, &hKey)
|
||||||
|
&& !RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ, &hSubKey)
|
||||||
|
&& !RegOpenKeyExW(hSubKey, L"Parameters", 0, KEY_READ, phkResult) ) {
|
||||||
|
|
||||||
*lpdwProcessId = lpBuffer.dwProcessId;
|
result = TRUE;
|
||||||
#ifdef _UNICODE
|
}
|
||||||
trace(L"Service \"%s\" process ID: %d", lpServiceName, *lpdwProcessId);
|
if ( hKey )
|
||||||
#else
|
RegCloseKey(hKey);
|
||||||
trace(L"Service \"%S\" process ID: %d", lpServiceName, *lpdwProcessId);
|
|
||||||
#endif
|
if ( hSubKey )
|
||||||
|
RegCloseKey(hSubKey);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL FindServiceDllW(LPCWSTR lpServiceName, LPWSTR lpServiceDll, DWORD dwSize) {
|
||||||
|
BOOL result = FALSE;
|
||||||
|
HKEY hKey;
|
||||||
|
if ( OpenServiceParametersKey(lpServiceName, &hKey) ) {
|
||||||
|
DWORD cb = dwSize;
|
||||||
|
if ( !RegGetValueW(hKey, NULL, L"ServiceDll", RRF_RT_REG_SZ, NULL, lpServiceDll, &cb) ) {
|
||||||
|
trace(_T("Service \"%s\" DLL path: %ls"), lpServiceName, lpServiceDll);
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
LPWSTR GetWindowsUpdateServiceDllW(void) {
|
||||||
|
static WCHAR path[MAX_PATH];
|
||||||
|
|
||||||
|
if ( !path[0] ) {
|
||||||
|
if ( !FindServiceDllW(L"wuauserv", path, _countof(path)) )
|
||||||
|
path[0] = L'\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL ApplyUpdatePack7R2ShimIfNeeded(const wchar_t *path, size_t pathsize, wchar_t *newpath, size_t newpathsize) {
|
||||||
|
wchar_t drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
|
||||||
|
_wsplitpath_s(path, drive, _countof(drive), dir, _countof(dir), fname, _countof(fname), ext, _countof(ext));
|
||||||
|
if ( !_wcsicmp(fname, L"wuaueng2") ) {
|
||||||
|
_wmakepath_s(newpath, newpathsize, drive, dir, L"wuaueng", ext);
|
||||||
|
return GetFileAttributesW(newpath) != INVALID_FILE_ATTRIBUTES;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL GetServiceProcessId(SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPDWORD lpdwProcessId) {
|
||||||
|
BOOL result = FALSE;
|
||||||
|
BOOL selfclose = !hSCManager;
|
||||||
|
if ( selfclose && !(hSCManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT)) )
|
||||||
|
return result;
|
||||||
|
|
||||||
|
SC_HANDLE hService = OpenService(hSCManager, lpServiceName, SERVICE_QUERY_STATUS);
|
||||||
|
|
||||||
|
if ( selfclose )
|
||||||
|
CloseServiceHandle(hSCManager);
|
||||||
|
|
||||||
|
if ( !hService )
|
||||||
|
return result;
|
||||||
|
|
||||||
|
SERVICE_STATUS_PROCESS buffer;
|
||||||
|
DWORD cb;
|
||||||
|
if ( QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&buffer, sizeof(buffer), &cb)
|
||||||
|
&& buffer.dwProcessId ) {
|
||||||
|
|
||||||
|
*lpdwProcessId = buffer.dwProcessId;
|
||||||
|
trace(_T("Service \"%s\" process ID: %d"), lpServiceName, *lpdwProcessId);
|
||||||
result = TRUE;
|
result = TRUE;
|
||||||
}
|
}
|
||||||
CloseServiceHandle(hService);
|
CloseServiceHandle(hService);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL get_svcgname(SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPTSTR lpGroupName, SIZE_T dwSize) {
|
BOOL GetServiceGroupName(SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPTSTR lpGroupName, SIZE_T dwSize) {
|
||||||
|
BOOL result = FALSE;
|
||||||
|
BOOL selfclose = !hSCManager;
|
||||||
|
if ( selfclose && !(hSCManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT)) )
|
||||||
|
return result;
|
||||||
|
|
||||||
TCHAR lpBinaryPathName[0x8000];
|
TCHAR lpBinaryPathName[0x8000];
|
||||||
if (!get_svcpath(hSCManager, lpServiceName, lpBinaryPathName, _countof(lpBinaryPathName)))
|
if ( !GetServiceCommandLine(hSCManager, lpServiceName, lpBinaryPathName, _countof(lpBinaryPathName)) )
|
||||||
return FALSE;
|
return result;
|
||||||
|
|
||||||
|
if ( selfclose )
|
||||||
|
CloseServiceHandle(hSCManager);
|
||||||
|
|
||||||
int numArgs;
|
int numArgs;
|
||||||
LPWSTR *argv = CommandLineToArgv(lpBinaryPathName, &numArgs);
|
LPWSTR *argv = CommandLineToArgv(lpBinaryPathName, &numArgs);
|
||||||
if (numArgs < 3)
|
if ( numArgs < 3 )
|
||||||
return FALSE;
|
return result;
|
||||||
|
|
||||||
TCHAR fname[_MAX_FNAME];
|
TCHAR fname[_MAX_FNAME];
|
||||||
_tsplitpath_s(argv[0], NULL, 0, NULL, 0, fname, _countof(fname), NULL, 0);
|
_tsplitpath_s(argv[0], NULL, 0, NULL, 0, fname, _countof(fname), NULL, 0);
|
||||||
|
|
||||||
BOOL result = FALSE;
|
if ( !_tcsicmp(fname, _T("svchost")) ) {
|
||||||
if (!_tcsicmp(fname, _T("svchost"))) {
|
|
||||||
LPWSTR *p = argv;
|
LPWSTR *p = argv;
|
||||||
for (int i = 1; i < numArgs; i++) {
|
for ( int i = 1; i < numArgs; i++ ) {
|
||||||
if (!_tcsicmp(*(p++), _T("-k")) && !_tcscpy_s(lpGroupName, dwSize, *p)) {
|
if ( !_tcsicmp(*(p++), _T("-k")) && !_tcscpy_s(lpGroupName, dwSize, *p) ) {
|
||||||
result = TRUE;
|
result = TRUE;
|
||||||
#ifdef _UNICODE
|
trace(_T("Service \"%s\" group name: %s"), lpServiceName, lpGroupName);
|
||||||
trace(L"Service \"%s\" group name: %s", lpServiceName, lpGroupName);
|
|
||||||
#else
|
|
||||||
trace(L"Service \"%S\" group name: %S", lpServiceName, lpGroupName);
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,16 +122,22 @@ BOOL get_svcgname(SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPTSTR lpGroupNam
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL get_svcpath(SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPTSTR lpBinaryPathName, SIZE_T dwSize) {
|
BOOL GetServiceCommandLine(SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPTSTR lpBinaryPathName, SIZE_T dwSize) {
|
||||||
|
BOOL result = FALSE;
|
||||||
|
if ( !hSCManager && !(hSCManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT)) )
|
||||||
|
return result;
|
||||||
|
|
||||||
HANDLE hService = OpenService(hSCManager, lpServiceName, SERVICE_QUERY_CONFIG);
|
HANDLE hService = OpenService(hSCManager, lpServiceName, SERVICE_QUERY_CONFIG);
|
||||||
if (!hService)
|
if ( !hService )
|
||||||
return FALSE;
|
return result;
|
||||||
|
|
||||||
DWORD cbBytesNeeded;
|
DWORD cbBytesNeeded;
|
||||||
BOOL result = FALSE;
|
if ( !QueryServiceConfig(hService, NULL, 0, &cbBytesNeeded)
|
||||||
if (!QueryServiceConfig(hService, NULL, 0, &cbBytesNeeded) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
|
||||||
|
|
||||||
LPQUERY_SERVICE_CONFIG sc = malloc(cbBytesNeeded);
|
LPQUERY_SERVICE_CONFIG sc = malloc(cbBytesNeeded);
|
||||||
if (QueryServiceConfig(hService, sc, cbBytesNeeded, &cbBytesNeeded) && !_tcscpy_s(lpBinaryPathName, dwSize, sc->lpBinaryPathName))
|
if ( QueryServiceConfig(hService, sc, cbBytesNeeded, &cbBytesNeeded)
|
||||||
|
&& !_tcscpy_s(lpBinaryPathName, dwSize, sc->lpBinaryPathName) )
|
||||||
result = TRUE;
|
result = TRUE;
|
||||||
free(sc);
|
free(sc);
|
||||||
}
|
}
|
||||||
@@ -117,29 +145,32 @@ BOOL get_svcpath(SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPTSTR lpBinaryPat
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL get_svcgpid(SC_HANDLE hSCManager, LPTSTR lpServiceGroupName, DWORD *lpdwProcessId) {
|
BOOL GetServiceGroupProcessId(SC_HANDLE hSCManager, LPTSTR lpServiceGroupName, LPDWORD lpdwProcessId) {
|
||||||
|
BOOL result = FALSE;
|
||||||
|
BOOL selfclose = !hSCManager;
|
||||||
|
if ( selfclose && !(hSCManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT)) )
|
||||||
|
return result;
|
||||||
|
|
||||||
DWORD uBytes = 1 << 20;
|
DWORD uBytes = 1 << 20;
|
||||||
LPBYTE pvData = malloc(uBytes);
|
LPBYTE pvData = malloc(uBytes);
|
||||||
RegGetValue(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost"),
|
RegGetValue(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost"),
|
||||||
lpServiceGroupName, RRF_RT_REG_MULTI_SZ, NULL, pvData, &uBytes);
|
lpServiceGroupName, RRF_RT_REG_MULTI_SZ, NULL, pvData, &uBytes);
|
||||||
|
|
||||||
BOOL result = FALSE;
|
for ( LPTSTR p = (LPTSTR)pvData; *p; p += _tcslen(p) + 1 ) {
|
||||||
for (LPTSTR p = (LPTSTR)pvData; *p; p += _tcslen(p) + 1) {
|
|
||||||
DWORD dwProcessId;
|
DWORD dwProcessId;
|
||||||
TCHAR group[256];
|
TCHAR group[256];
|
||||||
if (get_svcpid(hSCManager, p, &dwProcessId)
|
if ( GetServiceProcessId(hSCManager, p, &dwProcessId)
|
||||||
&& (get_svcgname(hSCManager, p, group, _countof(group)) && !_tcsicmp(group, lpServiceGroupName))) {
|
&& (GetServiceGroupName(hSCManager, p, group, _countof(group))
|
||||||
|
&& !_tcsicmp(group, lpServiceGroupName)) ) {
|
||||||
|
|
||||||
*lpdwProcessId = dwProcessId;
|
*lpdwProcessId = dwProcessId;
|
||||||
result = TRUE;
|
result = TRUE;
|
||||||
#ifdef _UNICODE
|
trace(_T("Service group \"%s\" process ID: %d"), lpServiceGroupName, *lpdwProcessId);
|
||||||
trace(L"Service group \"%s\" process ID: %d", lpServiceGroupName, *lpdwProcessId);
|
|
||||||
#else
|
|
||||||
trace(L"Service group \"%S\" process ID: %d", lpServiceGroupName, *lpdwProcessId);
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(pvData);
|
free(pvData);
|
||||||
|
if ( selfclose )
|
||||||
|
CloseServiceHandle(hSCManager);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@@ -1,18 +1,14 @@
|
|||||||
|
#ifndef SERVICE_H
|
||||||
|
#define SERVICE_H
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
BOOL get_svcdllA(LPCSTR lpServiceName, LPSTR lpServiceDll, DWORD dwSize);
|
#include <Windows.h>
|
||||||
BOOL get_svcdllW(LPCWSTR lpServiceName, LPWSTR lpServiceDll, DWORD dwSize);
|
|
||||||
BOOL get_svcpid(SC_HANDLE hSCManager, LPCTSTR lpServiceName, DWORD *lpdwProcessId);
|
|
||||||
BOOL get_svcgname(SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPTSTR lpGroupName, SIZE_T dwSize);
|
|
||||||
BOOL get_svcpath(SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPTSTR lpBinaryPathName, SIZE_T dwSize);
|
|
||||||
BOOL get_svcgpid(SC_HANDLE hSCManager, LPTSTR lpServiceGroupName, DWORD *lpdwProcessId);
|
|
||||||
LPSTR get_wuauservdllA(void);
|
|
||||||
LPWSTR get_wuauservdllW(void);
|
|
||||||
|
|
||||||
#ifdef UNICODE
|
BOOL FindServiceDllW(LPCWSTR lpServiceName, LPWSTR lpServiceDll, DWORD nCount);
|
||||||
#define get_svcdll get_svcdllW
|
LPWSTR GetWindowsUpdateServiceDllW(void);
|
||||||
#define get_wuauservdll get_wuauservdllW
|
BOOL ApplyUpdatePack7R2ShimIfNeeded(const wchar_t *path, size_t pathsize, wchar_t *newpath, size_t newpathsize);
|
||||||
#else
|
BOOL GetServiceProcessId(SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPDWORD lpdwProcessId);
|
||||||
#define get_svcdll get_svcdllA
|
BOOL GetServiceGroupName(SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPTSTR lpGroupName, SIZE_T dwSize);
|
||||||
#define get_wuauservdll get_wuauservdllA
|
BOOL GetServiceCommandLine(SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPTSTR lpBinaryPathName, SIZE_T dwSize);
|
||||||
|
BOOL GetServiceGroupProcessId(SC_HANDLE hSCManager, LPTSTR lpServiceGroupName, LPDWORD lpdwProcessId);
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1,7 +1,10 @@
|
|||||||
|
#ifndef SHELLAPIHELPER_H
|
||||||
|
#define SHELLAPIHELPER_H
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef UNICODE
|
#ifdef UNICODE
|
||||||
#define CommandLineToArgv CommandLineToArgvW
|
#define CommandLineToArgv CommandLineToArgvW
|
||||||
#else
|
#else
|
||||||
#define CommandLineToArgv CommandLineToArgvA
|
#define CommandLineToArgv CommandLineToArgvA
|
||||||
#endif // !UNICODE
|
#endif
|
||||||
|
#endif
|
||||||
|
@@ -107,7 +107,6 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
|
||||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
@@ -120,7 +119,6 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
|
||||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
@@ -140,7 +138,6 @@
|
|||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
|
||||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
@@ -165,7 +162,6 @@
|
|||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
|
||||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
@@ -175,22 +171,25 @@
|
|||||||
</PostBuildEvent>
|
</PostBuildEvent>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="callbacks.c" />
|
||||||
<ClCompile Include="hooks.c" />
|
<ClCompile Include="hooks.c" />
|
||||||
<ClCompile Include="dllmain.c" />
|
<ClCompile Include="dllmain.c" />
|
||||||
<ClCompile Include="iathook.c" />
|
<ClCompile Include="iathook.c" />
|
||||||
<ClCompile Include="logging.c" />
|
<ClCompile Include="logging.c" />
|
||||||
|
<ClCompile Include="ntdllhelper.c" />
|
||||||
|
<ClCompile Include="patchwua.c" />
|
||||||
<ClCompile Include="patternfind.c" />
|
<ClCompile Include="patternfind.c" />
|
||||||
<ClCompile Include="rundll32.c" />
|
<ClCompile Include="rundll32.c" />
|
||||||
<ClCompile Include="service.c" />
|
<ClCompile Include="service.c" />
|
||||||
<ClCompile Include="helpers.c" />
|
<ClCompile Include="helpers.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="exports.def" />
|
<ClInclude Include="callbacks.h" />
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="hooks.h" />
|
<ClInclude Include="hooks.h" />
|
||||||
<ClInclude Include="iathook.h" />
|
<ClInclude Include="iathook.h" />
|
||||||
<ClInclude Include="logging.h" />
|
<ClInclude Include="logging.h" />
|
||||||
|
<ClInclude Include="ntdllhelper.h" />
|
||||||
|
<ClInclude Include="patchwua.h" />
|
||||||
<ClInclude Include="patternfind.h" />
|
<ClInclude Include="patternfind.h" />
|
||||||
<ClInclude Include="service.h" />
|
<ClInclude Include="service.h" />
|
||||||
<ClInclude Include="shellapihelper.h" />
|
<ClInclude Include="shellapihelper.h" />
|
||||||
|
31
wufuc/wufuc.vcxproj.filters
Normal file
31
wufuc/wufuc.vcxproj.filters
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="hooks.c" />
|
||||||
|
<ClCompile Include="dllmain.c" />
|
||||||
|
<ClCompile Include="iathook.c" />
|
||||||
|
<ClCompile Include="logging.c" />
|
||||||
|
<ClCompile Include="patternfind.c" />
|
||||||
|
<ClCompile Include="rundll32.c" />
|
||||||
|
<ClCompile Include="service.c" />
|
||||||
|
<ClCompile Include="helpers.c" />
|
||||||
|
<ClCompile Include="callbacks.c" />
|
||||||
|
<ClCompile Include="patchwua.c" />
|
||||||
|
<ClCompile Include="ntdllhelper.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="hooks.h" />
|
||||||
|
<ClInclude Include="iathook.h" />
|
||||||
|
<ClInclude Include="logging.h" />
|
||||||
|
<ClInclude Include="patternfind.h" />
|
||||||
|
<ClInclude Include="service.h" />
|
||||||
|
<ClInclude Include="shellapihelper.h" />
|
||||||
|
<ClInclude Include="helpers.h" />
|
||||||
|
<ClInclude Include="callbacks.h" />
|
||||||
|
<ClInclude Include="patchwua.h" />
|
||||||
|
<ClInclude Include="ntdllhelper.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="wufuc.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
@@ -2,9 +2,10 @@
|
|||||||
#include <Msiquery.h>
|
#include <Msiquery.h>
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
|
|
||||||
|
__declspec(dllexport)
|
||||||
UINT __stdcall AIHelper_SetUnloadEvent(MSIHANDLE hInstall) {
|
UINT __stdcall AIHelper_SetUnloadEvent(MSIHANDLE hInstall) {
|
||||||
HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, _T("Global\\wufuc_UnloadEvent"));
|
HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, _T("Global\\wufuc_UnloadEvent"));
|
||||||
if (hEvent) {
|
if ( hEvent ) {
|
||||||
SetEvent(hEvent);
|
SetEvent(hEvent);
|
||||||
CloseHandle(hEvent);
|
CloseHandle(hEvent);
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||||
switch (ul_reason_for_call) {
|
switch ( ul_reason_for_call ) {
|
||||||
case DLL_PROCESS_ATTACH:
|
case DLL_PROCESS_ATTACH:
|
||||||
break;
|
break;
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
|
@@ -1,2 +0,0 @@
|
|||||||
EXPORTS
|
|
||||||
AIHelper_SetUnloadEvent
|
|
@@ -111,7 +111,6 @@
|
|||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<AdditionalDependencies>Msi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>Msi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
@@ -123,7 +122,6 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
@@ -135,7 +133,6 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
@@ -153,16 +150,12 @@
|
|||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<AdditionalDependencies>Msi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>Msi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="aihelper.c" />
|
<ClCompile Include="aihelper.c" />
|
||||||
<ClCompile Include="dllmain.c" />
|
<ClCompile Include="dllmain.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<None Include="exports.def" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
Reference in New Issue
Block a user