This commit is contained in:
zeffy
2018-05-17 08:52:53 -07:00
parent 35760a2546
commit e6da8ec18b
71 changed files with 902 additions and 2536 deletions

7
FAQ.md
View File

@@ -15,12 +15,7 @@ These must be used from an elevated command line prompt.
## How to restore Windows Update to its default configuration
Windows Update by default is configured to run as `SERVICE_WIN32_SHARE_PROCESS`, which means it shares a single `svchost.exe` process with several other Windows services.
It can also be configured as `SERVICE_WIN32_OWN_PROCESS`, which means it runs in its own process, which doesn't start until Windows Update does.
Normally, either of these configurations is supported.
However, if you have used another third-party solution for the CPU fix (such as UpdatePack7R2 or WuaCpuFix) either knowingly or unknowingly, wufuc will not function correctly if Windows Update is configured as `SERVICE_WIN32_OWN_PROCESS`.
If you have used another third-party solution for the CPU fix (such as UpdatePack7R2 or WuaCpuFix) either knowingly or unknowingly, wufuc may not function correctly.
You have two ways to work around this limitation, either:

View File

@@ -41,13 +41,6 @@ Some people with older Intel and AMD processors are also affected! I've received
- [AMD FX-8350](https://github.com/zeffy/wufuc/issues/32)
- [AMD Turion 64 Mobile Technology ML-34](https://github.com/zeffy/wufuc/issues/80)
## Bad Microsoft!
If you are interested, you can read my original write-up on discovering the CPU check [here](https://github.com/zeffy/wufuc/tree/old-kb4012218-19).
The tl;dr version is basically, inside a system file named `wuaueng.dll`, there are two functions responsible for the CPU check: `IsDeviceServiceable(void)` and `IsCPUSupported(void)`.
`IsDeviceServiceable` simply calls `IsCPUSupported` once, and then re-uses the result that it receives on subsequent calls.
## Features
- Enables Windows Update on PCs with unsupported processors.
@@ -57,34 +50,36 @@ The tl;dr version is basically, inside a system file named `wuaueng.dll`, there
- Byte pattern-based patching, which means it will usually keep working even after new updates come out.
- No dependencies.
## Frequently Asked Questions
## How wufuc works
See [FAQ.md](https://github.com/zeffy/wufuc/blob/master/FAQ.md).
The tl;dr version is basically:
## How it works
* Inside a system file called `wuaueng.dll`, there are two functions responsible for the CPU check: `IsDeviceServiceable` and `IsCPUSupported`.
* `IsDeviceServiceable` simply calls `IsCPUSupported` once, and then saves the result and re-uses it on subsequent calls.
* I take advantage of this behavior in wufuc by patching the saved result so that it is always `TRUE`, or supported.
This is a basic run-down of what wufuc does when you install it:
If you would like more information, you can read my original write-up on discovering the CPU check [here](https://github.com/zeffy/wufuc/tree/old-kb4012218-19).
- The installer registers a scheduled task that automatically starts wufuc on system boot/user log on.
- Depending on how the Windows Update service is configured to run, wufuc will:
* **Shared process**: inject itself into the service host process that Windows Update will run in when it starts.
* **Own process**: wait for the Windows Update service to start and then inject into it.
- Once injected, wufuc will hook some functions where appropriate:
* `LoadLibraryExW` hook will automatically hook the `IsDeviceServiceable()` function inside `wuaueng.dll` when it is loaded.
* `RegQueryValueExW` hook is necessary to provide compatibility with [UpdatePack7R2](../../issues/100). This hook not applied when `wuauserv` is configured to run in its own process.
## Building
To build wufuc from source, you need to download and install the following:
1. [Visual Studio 2017](https://www.visualstudio.com/).
2. [Windows Driver Kit (WDK)](https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk).
3. (Optional, for MSI packages) [Advanced Installer](https://www.advancedinstaller.com/).
## Sponsors
### [Advanced Installer](https://www.advancedinstaller.com/)
The installer packages are created with Advanced Installer using an [open source license](http://www.advancedinstaller.com/free-license.html).
The installer packages are created with Advanced Installer using an [open source license](https://www.advancedinstaller.com/free-license.html).
Advanced Installer's intuitive and friendly user interface allowed me to quickly create a feature complete installer with minimal effort. Check it out!
## Special thanks
- Wen Jia Liu ([@wj32](https://github.com/wj32)) for his awesome program [Process Hacker](https://github.com/processhacker2/processhacker), and also for his [phnt headers](https://github.com/processhacker2/processhacker/tree/master/phnt).
- Duncan Ogilvie ([@mrexodia](https://github.com/mrexodia)) for [x64dbg](https://github.com/x64dbg/x64dbg), its [`patternfind.cpp`](https://github.com/x64dbg/x64dbg/blob/development/src/dbg/patternfind.cpp) algorithm, and its issue template which I adapted for this project.
- Tsuda Kageyu ([@TsudaKageyu](https://github.com/TsudaKageyu)) for his excellent [minhook](https://github.com/TsudaKageyu/minhook) library.
- [**@wj32**](https://github.com/wj32) for his awesome program [Process Hacker](https://github.com/processhacker2/processhacker), and also for his [phnt headers](https://github.com/processhacker2/processhacker/tree/master/phnt).
- [**@mrexodia**](https://github.com/mrexodia) for [x64dbg](https://github.com/x64dbg/x64dbg), its [`patternfind.cpp`](https://github.com/x64dbg/x64dbg/blob/development/src/dbg/patternfind.cpp) algorithm, and its issue template which I adapted for this project.
[Latest]: https://github.com/zeffy/wufuc/releases/latest
[AppVeyor]: https://ci.appveyor.com/project/zeffy/wufuc

View File

@@ -22,9 +22,9 @@ before_build:
set "BUILD_ZIPFILE=%APPVEYOR_BUILD_FOLDER%\%APPVEYOR_PROJECT_NAME%_v%BUILD_COMMIT_VERSION%-%PLATFORM%.zip"
after_build:
- cmd: >-
copy /Y "COPYING" "src\wufuc_setup_bat\COPYING.txt"
copy /Y "COPYING" "src\setup_bat\COPYING.txt"
cd "%APPVEYOR_BUILD_FOLDER%\src\wufuc_setup_bat"
cd "%APPVEYOR_BUILD_FOLDER%\src\setup_bat"
echo v%BUILD_COMMIT_VERSION%>version.txt
@@ -32,9 +32,9 @@ after_build:
for /R %%i in (*.bat) do unix2dos "%%i"
7z a "%BUILD_ZIPFILE%" "..\wufuc_setup_bat"
7z a "%BUILD_ZIPFILE%" "..\setup_bat"
7z rn "%BUILD_ZIPFILE%" "wufuc_setup_bat" "%APPVEYOR_PROJECT_NAME%"
7z rn "%BUILD_ZIPFILE%" "setup_bat" "%APPVEYOR_PROJECT_NAME%"
7z d "%BUILD_ZIPFILE%" "%APPVEYOR_PROJECT_NAME%\.gitignore"
artifacts:

View File

@@ -1,81 +0,0 @@
MinHook - The Minimalistic API Hooking Library for x64/x86
Copyright (C) 2009-2017 Tsuda Kageyu.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================================================
Portions of this software are Copyright (c) 2008-2009, Vyacheslav Patkov.
================================================================================
Hacker Disassembler Engine 32 C
Copyright (c) 2008-2009, Vyacheslav Patkov.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------------------
Hacker Disassembler Engine 64 C
Copyright (c) 2008-2009, Vyacheslav Patkov.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,184 +0,0 @@
/*
* MinHook - The Minimalistic API Hooking Library for x64/x86
* Copyright (C) 2009-2017 Tsuda Kageyu.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
#error MinHook supports only x86 and x64 systems.
#endif
// MinHook Error Codes.
typedef enum MH_STATUS
{
// Unknown error. Should not be returned.
MH_UNKNOWN = -1,
// Successful.
MH_OK = 0,
// MinHook is already initialized.
MH_ERROR_ALREADY_INITIALIZED,
// MinHook is not initialized yet, or already uninitialized.
MH_ERROR_NOT_INITIALIZED,
// The hook for the specified target function is already created.
MH_ERROR_ALREADY_CREATED,
// The hook for the specified target function is not created yet.
MH_ERROR_NOT_CREATED,
// The hook for the specified target function is already enabled.
MH_ERROR_ENABLED,
// The hook for the specified target function is not enabled yet, or already
// disabled.
MH_ERROR_DISABLED,
// The specified pointer is invalid. It points the address of non-allocated
// and/or non-executable region.
MH_ERROR_NOT_EXECUTABLE,
// The specified target function cannot be hooked.
MH_ERROR_UNSUPPORTED_FUNCTION,
// Failed to allocate memory.
MH_ERROR_MEMORY_ALLOC,
// Failed to change the memory protection.
MH_ERROR_MEMORY_PROTECT,
// The specified module is not loaded.
MH_ERROR_MODULE_NOT_FOUND,
// The specified function is not found.
MH_ERROR_FUNCTION_NOT_FOUND
}
MH_STATUS;
// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
// MH_QueueEnableHook or MH_QueueDisableHook.
#define MH_ALL_HOOKS NULL
#ifdef __cplusplus
extern "C" {
#endif
// Initialize the MinHook library. You must call this function EXACTLY ONCE
// at the beginning of your program.
MH_STATUS WINAPI MH_Initialize(VOID);
// Uninitialize the MinHook library. You must call this function EXACTLY
// ONCE at the end of your program.
MH_STATUS WINAPI MH_Uninitialize(VOID);
// Creates a Hook for the specified target function, in disabled state.
// Parameters:
// pTarget [in] A pointer to the target function, which will be
// overridden by the detour function.
// pDetour [in] A pointer to the detour function, which will override
// the target function.
// ppOriginal [out] A pointer to the trampoline function, which will be
// used to call the original target function.
// This parameter can be NULL.
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
// Creates a Hook for the specified API function, in disabled state.
// Parameters:
// pszModule [in] A pointer to the loaded module name which contains the
// target function.
// pszTarget [in] A pointer to the target function name, which will be
// overridden by the detour function.
// pDetour [in] A pointer to the detour function, which will override
// the target function.
// ppOriginal [out] A pointer to the trampoline function, which will be
// used to call the original target function.
// This parameter can be NULL.
MH_STATUS WINAPI MH_CreateHookApi(
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
// Creates a Hook for the specified API function, in disabled state.
// Parameters:
// pszModule [in] A pointer to the loaded module name which contains the
// target function.
// pszTarget [in] A pointer to the target function name, which will be
// overridden by the detour function.
// pDetour [in] A pointer to the detour function, which will override
// the target function.
// ppOriginal [out] A pointer to the trampoline function, which will be
// used to call the original target function.
// This parameter can be NULL.
// ppTarget [out] A pointer to the target function, which will be used
// with other functions.
// This parameter can be NULL.
MH_STATUS WINAPI MH_CreateHookApiEx(
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
// Removes an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
// Enables an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// enabled in one go.
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
// Disables an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// disabled in one go.
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
// Queues to enable an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// queued to be enabled.
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
// Queues to disable an already created hook.
// Parameters:
// pTarget [in] A pointer to the target function.
// If this parameter is MH_ALL_HOOKS, all created hooks are
// queued to be disabled.
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
// Applies all queued changes in one go.
MH_STATUS WINAPI MH_ApplyQueued(VOID);
// Translates the MH_STATUS to its name as a string.
const char * WINAPI MH_StatusToString(MH_STATUS status);
#ifdef __cplusplus
}
#endif

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,81 +0,0 @@
MinHook - The Minimalistic API Hooking Library for x64/x86
Copyright (C) 2009-2017 Tsuda Kageyu.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================================================
Portions of this software are Copyright (c) 2008-2009, Vyacheslav Patkov.
================================================================================
Hacker Disassembler Engine 32 C
Copyright (c) 2008-2009, Vyacheslav Patkov.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------------------
Hacker Disassembler Engine 64 C
Copyright (c) 2008-2009, Vyacheslav Patkov.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -46,6 +46,8 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<GenerateManifest>false</GenerateManifest>
<OutDir>$(ProjectDir)bin\$(Configuration)\$(PlatformShortName)\</OutDir>
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
@@ -93,7 +95,7 @@
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
</Link>
<PostBuildEvent>
<Command>copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup\"</Command>
<Command>copy /Y "$(TargetPath)" "$(SolutionDir)setup_ai\"</Command>
<Message>Copy release binaries to the setup staging directory</Message>
</PostBuildEvent>
</ItemDefinitionGroup>

View File

@@ -5,10 +5,7 @@
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiPropsComponent">
<ROW Property="AI_BITMAP_DISPLAY_MODE" Value="0"/>
<ROW Property="AI_CLEAN_RESOURCES_DISABLE_UPGRADE" Value="1"/>
<ROW Property="AI_CLEAN_RESOURCES_UNINSTALL" Value="1"/>
<ROW Property="AI_CLEAN_RESOURCES_USER_PROMPT_BASIC_UI" Value="1"/>
<ROW Property="AI_CLEAN_RESOURCES_USER_PROMPT_FULL_UI" Value="1"/>
<ROW Property="AI_ThemeStyle" Value="aero" MsiKey="AI_ThemeStyle"/>
<ROW Property="ALLUSERS" Value="1"/>
<ROW Property="ARPCOMMENTS" Value="Enables Windows Update on PCs with unsupported processors." ValueLocId="*"/>
@@ -21,10 +18,10 @@
<ROW Property="AiPreventAutoPin" Value="System.AppUserModel.ExcludeFromShowInNewInstall"/>
<ROW Property="MSIFASTINSTALL" MultiBuildValue="x64Build:6#x86Build:6"/>
<ROW Property="Manufacturer" Value="zeffy"/>
<ROW Property="ProductCode" Value="1027:{84169AC2-619B-4E39-ABAC-D97D0CCE52AA} 1028:{3242799A-EABC-4846-9FB2-9157464AC6B2} 1031:{15845A1D-9531-4B6B-B56E-93E56652876D} 1033:{02D77154-1789-4037-8157-4F9B400D184E} 1035:{2AB75127-0A1D-46C3-9939-7E1BEF4101F8} 1036:{E0275036-3F2B-44F3-BCDB-78C55071F41B} 1038:{66A9F4FC-8DB1-45AE-98A5-469F14DC2867} 1040:{A037A274-187E-4231-9857-17075F270D01} 1041:{8E027F22-470D-4800-B135-3661E11F1B2D} 1042:{0C7CB276-E4EB-4D99-BC4D-E362BD4AEA46} 1043:{DDD233EB-262F-42B5-BB37-61366CCB3AB7} 1045:{1008FE13-9C80-4061-BAF1-AFEFA3C322BE} 1046:{2C6C0A74-CDEE-4495-858D-EE570F1B14F0} 1049:{D86825C0-4294-441C-B200-3C7B1314FF10} 1060:{D475BE6D-DB4D-4783-8396-F96186694C6E} 2052:{BA2561A6-D217-400D-A2B0-A0AA07222A94} 2070:{3C2F9949-F866-45C9-BE0E-0D046934E2CF} 3082:{AB82F7D2-24EF-47C9-9978-A69CE1BE56B0} " Type="16"/>
<ROW Property="ProductCode" Value="1027:{8788C792-140E-41E9-B875-685F557ACEE6} 1028:{C3A9DFE3-DBAB-47BA-ABAD-804D54F0FBF4} 1031:{85F838D1-6E19-4D99-BEE8-3A46A6D52813} 1033:{F011FFEE-01E3-495E-80CA-10A640C55031} 1035:{03787122-8FC5-4BF2-B447-372148E7E0CD} 1036:{C83296AB-0CC4-4954-A218-3F76BE31C530} 1038:{8D87BFD2-FE05-4506-A1D8-62EE821DB623} 1040:{C48A5EF8-8DB1-4D08-B468-683879C807E3} 1041:{5CCB0BE8-E87D-4D8C-BD5F-B5A6E1CDDB4A} 1042:{2AE0CA07-01C9-4B29-A880-E52CE19EB157} 1043:{28C34648-07BD-463C-A61E-AE47525AF2D2} 1045:{F7E7320E-9EBF-44C5-97E7-E8FEB7A47613} 1046:{393B1C36-514F-4722-A577-408055568261} 1049:{13DAE24C-D5C2-443E-8105-8B3FE24C9370} 1060:{836B7413-1503-4164-9D21-87C28468AD61} 2052:{880E51E8-4243-42F4-BAA3-B32785746291} 2070:{E76212D9-7C99-4C47-9004-3F32D658D6A6} 3082:{CFE6B8E7-9D52-488C-BEA6-A7EE3306B20C} " Type="16"/>
<ROW Property="ProductLanguage" Value="1033"/>
<ROW Property="ProductName" Value="wufuc"/>
<ROW Property="ProductVersion" Value="1.0.0.191" Type="32" TargetFile="wufuc64.dll"/>
<ROW Property="ProductVersion" Value="1.0.1.0" Type="32" TargetFile="wufuc64.dll"/>
<ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND"/>
<ROW Property="UpgradeCode" Value="{4C52972C-251E-4D1B-AD09-EAA765719DCC}"/>
<ROW Property="WindowsType9X" MultiBuildValue="x64Build:Windows 9x/ME#x86Build:Windows 9x/ME" ValueLocId="-"/>
@@ -43,36 +40,30 @@
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiDirsComponent">
<ROW Directory="APPDIR" Directory_Parent="TARGETDIR" DefaultDir="APPDIR:." IsPseudoRoot="1"/>
<ROW Directory="CommonAppDataFolder" Directory_Parent="TARGETDIR" DefaultDir="COMMON~1|CommonAppDataFolder" IsPseudoRoot="1"/>
<ROW Directory="SHORTCUTDIR" Directory_Parent="TARGETDIR" DefaultDir="SHORTC~1|SHORTCUTDIR" IsPseudoRoot="1"/>
<ROW Directory="TARGETDIR" DefaultDir="SourceDir"/>
<ROW Directory="Troubleshooting_1_Dir" Directory_Parent="APPDIR" DefaultDir="TROUBL~1|Troubleshooting"/>
<ROW Directory="Troubleshooting_Dir" Directory_Parent="SHORTCUTDIR" DefaultDir="TROUBL~1|Troubleshooting"/>
<ROW Directory="Troubleshooting_Dir" Directory_Parent="SHORTCUTDIR" DefaultDir="HELPAN~1|Help and Support"/>
<ROW Directory="X64FeatureItems_Dir" Directory_Parent="APPDIR" DefaultDir=".:X64FEA~1|X64FeatureItems"/>
<ROW Directory="X86FeatureItems_Dir" Directory_Parent="APPDIR" DefaultDir=".:X86FEA~1|X86FeatureItems"/>
<ROW Directory="wufuc_Dir" Directory_Parent="CommonAppDataFolder" DefaultDir="wufuc"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent">
<ROW Component="COPYING" ComponentId="{6CA1ECA7-4C30-4BD0-A5E8-6B3E5BCBE31D}" Directory_="APPDIR" Attributes="0" KeyPath="COPYING" Type="0"/>
<ROW Component="ProductInformation" ComponentId="{75030EAB-5C17-4F84-B529-28003271CA3F}" Directory_="APPDIR" Attributes="4" KeyPath="Version"/>
<ROW Component="Restore_wuauserv.reg" ComponentId="{ED9F90C5-1984-48DE-B109-4AF6F12A2E8F}" Directory_="Troubleshooting_1_Dir" Attributes="0" KeyPath="Restore_wuauserv.reg" Type="0"/>
<ROW Component="SHORTCUTDIR" ComponentId="{910396A4-AFDD-4E57-BF00-2FDD4108AC61}" Directory_="SHORTCUTDIR" Attributes="0"/>
<ROW Component="Troubleshooting" ComponentId="{D4F7163C-0FD7-4862-BF97-F1693236500C}" Directory_="Troubleshooting_Dir" Attributes="0"/>
<ROW Component="X64FeatureItems" ComponentId="{0E189A37-1F40-4756-ACB9-6511067D5B47}" Directory_="X64FeatureItems_Dir" Attributes="0"/>
<ROW Component="X86FeatureItems" ComponentId="{CBB84726-9EC3-4570-9012-37BA98719022}" Directory_="X86FeatureItems_Dir" Attributes="0"/>
<ROW Component="wufuc" ComponentId="{331CB0F5-F6E7-4712-9F97-3609A0D5AFE6}" Directory_="wufuc_Dir" Attributes="0"/>
<ROW Component="wufuc32.dll" ComponentId="{7FBEF396-DCBC-4838-A4EB-336F74A836C7}" Directory_="APPDIR" Attributes="0" KeyPath="wufuc32.dll"/>
<ROW Component="wufuc64.dll" ComponentId="{0407D471-998A-4FD3-BC2D-72EE56FBEEF4}" Directory_="APPDIR" Attributes="256" KeyPath="wufuc64.dll"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent">
<ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="COPYING ProductInformation Restore_wuauserv.reg SHORTCUTDIR Troubleshooting wufuc"/>
<ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="COPYING ProductInformation SHORTCUTDIR Troubleshooting"/>
<ROW Feature="X64Feature" Feature_Parent="MainFeature" Title="X64Feature" Display="0" Level="1" Directory_="APPDIR" Attributes="0" Components="X64FeatureItems wufuc64.dll" Builds="x64Build"/>
<ROW Feature="X86Feature" Feature_Parent="MainFeature" Title="X86Feature" Display="0" Level="1" Directory_="APPDIR" Attributes="0" Components="X86FeatureItems wufuc32.dll" Builds="x86Build"/>
<ATTRIBUTE name="CurrentFeature" value="MainFeature"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent">
<ROW File="COPYING" Component_="COPYING" FileName="COPYING.txt" Attributes="0" SourcePath="..\..\COPYING" SelfReg="false" NextFile="Restore_wuauserv.reg"/>
<ROW File="Restore_wuauserv.reg" Component_="Restore_wuauserv.reg" FileName="RESTOR~1.REG|Restore_wuauserv.reg" Attributes="0" SourcePath="..\wufuc_setup_bat\Troubleshooting\Restore_wuauserv.reg" SelfReg="false"/>
<ROW File="COPYING" Component_="COPYING" FileName="COPYING.txt" Attributes="0" SourcePath="..\..\COPYING" SelfReg="false"/>
<ROW File="wufuc32.dll" Component_="wufuc32.dll" FileName="wufuc32.dll" Attributes="0" SourcePath="wufuc32.dll" SelfReg="false" NextFile="wufuc64.dll"/>
<ROW File="wufuc64.dll" Component_="wufuc64.dll" FileName="wufuc64.dll" Attributes="0" SourcePath="wufuc64.dll" SelfReg="false" NextFile="COPYING"/>
</COMPONENT>
@@ -80,10 +71,6 @@
<ROW MsiShortcutProperty="Uninstallwufuc1" Shortcut_="Uninstallwufuc" PropertyKey="[AiPreventAutoPin]" PropVariantValue="1"/>
<ROW MsiShortcutProperty="License1" Shortcut_="License" PropertyKey="[AiPreventAutoPin]" PropVariantValue="1"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.AiRemoveFileComponent">
<ROW RemoveFile="log" Condition="(AI_CLEAN_RESOURCES_UNINSTALL = &quot;1&quot;) AND (NOT UPGRADINGPRODUCTCODE)" Options="1"/>
<ROW RemoveFile="_" Condition="(AI_CLEAN_RESOURCES_UNINSTALL = &quot;1&quot;) AND (NOT UPGRADINGPRODUCTCODE)" Options="0"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.BootstrOptComponent">
<ROW BootstrOptKey="GlobalOptions" DownloadFolder="[AppDataFolder][|Manufacturer]\[|ProductName]\prerequisites" Options="2"/>
</COMPONENT>
@@ -128,11 +115,6 @@
<ROW Fragment="WelcomeDlg.aip" Path="&lt;AI_THEMES&gt;classic\fragments\WelcomeDlg.aip"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiActionTextComponent">
<ROW Action="AI_AiRemoveFilesCommit" Description="Executing file removal operations" DescriptionLocId="ActionText.Description.AI_AiRemoveFilesCommit" Template="Executing file removal: [1]" TemplateLocId="ActionText.Template.AI_AiRemoveFilesCommit"/>
<ROW Action="AI_AiRemoveFilesDeferred_Permanent" Description="Preparing files for removal" DescriptionLocId="ActionText.Description.AI_AiRemoveFilesDeferred_Permanent" Template="Preparing file: [1]" TemplateLocId="ActionText.Template.AI_AiRemoveFilesDeferred_Permanent"/>
<ROW Action="AI_AiRemoveFilesDeferred_Undoable" Description="Preparing files for removal" DescriptionLocId="ActionText.Description.AI_AiRemoveFilesDeferred_Undoable" Template="Preparing file: [1]" TemplateLocId="ActionText.Template.AI_AiRemoveFilesDeferred_Undoable"/>
<ROW Action="AI_AiRemoveFilesImmediate" Description="Preparing files for removal" DescriptionLocId="ActionText.Description.AI_AiRemoveFilesImmediate" Template="Preparing file: [1]" TemplateLocId="ActionText.Template.AI_AiRemoveFilesImmediate"/>
<ROW Action="AI_AiRemoveFilesRollback" Description="Restoring removed files" DescriptionLocId="ActionText.Description.AI_AiRemoveFilesRollback" Template="Restoring file: [1]" TemplateLocId="ActionText.Template.AI_AiRemoveFilesRollback"/>
<ROW Action="AI_XmlCommit" Description="Committing XML file configurations." DescriptionLocId="ActionText.Description.AI_XmlCommit" Template="Committing XML file configurations." TemplateLocId="ActionText.Template.AI_XmlCommit"/>
<ROW Action="AI_XmlConfig" Description="Executing XML file configurations" DescriptionLocId="ActionText.Description.AI_XmlConfig" Template="Configuring XML file: &quot;[1]&quot;" TemplateLocId="ActionText.Template.AI_XmlConfig"/>
<ROW Action="AI_XmlInstall" Description="Generating actions to configure XML files" DescriptionLocId="ActionText.Description.AI_XmlInstall"/>
@@ -143,7 +125,6 @@
<COMPONENT cid="caphyon.advinst.msicomp.MsiBinaryComponent">
<ROW Name="AdvancedInstallerHelper.dll" SourcePath="AdvancedInstallerHelper.dll"/>
<ROW Name="Prereq.dll" SourcePath="&lt;AI_CUSTACTS&gt;Prereq.dll"/>
<ROW Name="ResourceCleaner.dll" SourcePath="&lt;AI_CUSTACTS&gt;ResourceCleaner.dll"/>
<ROW Name="ShortcutFlags.dll" SourcePath="&lt;AI_CUSTACTS&gt;ShortcutFlags.dll"/>
<ROW Name="aicustact.dll" SourcePath="&lt;AI_CUSTACTS&gt;aicustact.dll"/>
<ROW Name="viewer.exe" SourcePath="&lt;AI_CUSTACTS&gt;viewer.exe"/>
@@ -187,14 +168,8 @@
<ROW Directory_="X86FeatureItems_Dir" Component_="X86FeatureItems" ManualDelete="false"/>
<ROW Directory_="X64FeatureItems_Dir" Component_="X64FeatureItems" ManualDelete="false"/>
<ROW Directory_="Troubleshooting_Dir" Component_="Troubleshooting" ManualDelete="false"/>
<ROW Directory_="wufuc_Dir" Component_="wufuc" ManualDelete="true"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiCustActComponent">
<ROW Action="AI_AiRemoveFilesCommit" Type="11777" Source="ResourceCleaner.dll" Target="OnAiRemoveFilesCommit" WithoutSeq="true"/>
<ROW Action="AI_AiRemoveFilesDeferred_Permanent" Type="11265" Source="ResourceCleaner.dll" Target="OnAiRemoveFilesPermanent" WithoutSeq="true"/>
<ROW Action="AI_AiRemoveFilesDeferred_Undoable" Type="11265" Source="ResourceCleaner.dll" Target="OnAiRemoveFilesUndoable" WithoutSeq="true"/>
<ROW Action="AI_AiRemoveFilesImmediate" Type="1" Source="ResourceCleaner.dll" Target="OnAiRemoveFilesImmediate"/>
<ROW Action="AI_AiRemoveFilesRollback" Type="11521" Source="ResourceCleaner.dll" Target="OnAiUndoRemoveFiles"/>
<ROW Action="AI_AppSearchEx" Type="1" Source="Prereq.dll" Target="DoAppSearchEx"/>
<ROW Action="AI_ApplyShortcutFlags" Type="3073" Source="ShortcutFlags.dll" Target="UpdateShortcutFlags" WithoutSeq="true"/>
<ROW Action="AI_BACKUP_AI_SETUPEXEPATH" Type="51" Source="AI_SETUPEXEPATH_ORIGINAL" Target="[AI_SETUPEXEPATH]"/>
@@ -211,7 +186,6 @@
<ROW Action="AI_PinToStartScreen" Type="1025" Source="ShortcutFlags.dll" Target="PinToStartScreen" WithoutSeq="true"/>
<ROW Action="AI_PinToTaskbar" Type="1025" Source="ShortcutFlags.dll" Target="PinToTaskbar" WithoutSeq="true"/>
<ROW Action="AI_PrepareShortcutFlags" Type="1" Source="ShortcutFlags.dll" Target="PrepareActionData"/>
<ROW Action="AI_PromptUserBasicUI" Type="1" Source="ResourceCleaner.dll" Target="OnPromptUserBasicUI"/>
<ROW Action="AI_RESTORE_AI_SETUPEXEPATH" Type="51" Source="AI_SETUPEXEPATH" Target="[AI_SETUPEXEPATH_ORIGINAL]"/>
<ROW Action="AI_RESTORE_LOCATION" Type="65" Source="aicustact.dll" Target="RestoreLocation"/>
<ROW Action="AI_ResolveKnownFolders" Type="1" Source="aicustact.dll" Target="AI_ResolveKnownFolders"/>
@@ -235,24 +209,26 @@
<ROW Action="SET_APPDIR" Type="307" Source="APPDIR" Target="[ProgramFilesFolder][Manufacturer]\[ProductName]" MultiBuildTarget="x64Build:[ProgramFiles64Folder]\[ProductName]#x86Build:[ProgramFilesFolder]\[ProductName]"/>
<ROW Action="SET_SHORTCUTDIR" Type="307" Source="SHORTCUTDIR" Target="[ProgramMenuFolder][ProductName]"/>
<ROW Action="SET_TARGETDIR_TO_APPDIR" Type="51" Source="TARGETDIR" Target="[APPDIR]"/>
<ROW Action="SetRebootProperty" Type="51" Source="REBOOT" Target="Force"/>
<ROW Action="StartWindowsUpdateService" Type="3073" Source="aicustact.dll" Target="StartWinService" Options="1" AdditionalSeq="AI_DATA_SETTER_3"/>
<ROW Action="StopWindowsUpdateService" Type="3073" Source="aicustact.dll" Target="StopWinService" Options="1" AdditionalSeq="AI_DATA_SETTER_2"/>
<ROW Action="StopWindowsUpdateService" Type="3137" Source="aicustact.dll" Target="StopWinService" Options="1" AdditionalSeq="AI_DATA_SETTER_2"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiIconsComponent">
<ROW Name="msiexec.exe" SourcePath="..\..\..\..\..\..\..\Windows\System32\msiexec.exe" Index="0"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiIniFileComponent">
<ROW IniFile="ServiceDll" FileName="RESTOR~1.REG|Restore_wuauserv.reg" DirProperty="APPDIR" Section="HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\wuauserv\Parameters" Key="&quot;ServiceDll&quot;" Value="hex(2):25,00,73,00,79,00,73,00,74,00,65,00,6d,00,72,00,6f,00,6f,\" Action="0" Component_="ProductInformation"/>
<ROW IniFile="URL" FileName="Donate.url" DirProperty="SHORTCUTDIR" Section="InternetShortcut" Key="URL" Value="https://github.com/zeffy/wufuc/blob/master/DONATE.md" Action="0" Component_="SHORTCUTDIR"/>
<ROW IniFile="URL_2" FileName="Readme.url" DirProperty="SHORTCUTDIR" Section="InternetShortcut" Key="URL" Value="https://github.com/zeffy/wufuc/blob/master/README.md" Action="0" Component_="SHORTCUTDIR"/>
<ROW IniFile="URL_6" FileName="LATEST~1.URL|Latest Release.url" DirProperty="SHORTCUTDIR" Section="InternetShortcut" Key="URL" Value="https://github.com/zeffy/wufuc/releases/latest" Action="0" Component_="SHORTCUTDIR"/>
<ROW IniFile="URL_7" FileName="REPORT~1.URL|Report an Issue.url" DirProperty="Troubleshooting_Dir" Section="InternetShortcut" Key="URL" Value="https://github.com/zeffy/wufuc/issues" Action="0" Component_="SHORTCUTDIR"/>
<ROW IniFile="URL_2" FileName="Readme.url" DirProperty="SHORTCUTDIR" Section="InternetShortcut" Key="URL" Value="https://github.com/zeffy/wufuc" Action="0" Component_="SHORTCUTDIR"/>
<ROW IniFile="URL_6" FileName="LATEST~1.URL|Latest release.url" DirProperty="SHORTCUTDIR" Section="InternetShortcut" Key="URL" Value="https://github.com/zeffy/wufuc/releases/latest" Action="0" Component_="SHORTCUTDIR"/>
<ROW IniFile="URL_7" FileName="REPORT~1.URL|Report an issue.url" DirProperty="Troubleshooting_Dir" Section="InternetShortcut" Key="URL" Value="https://github.com/zeffy/wufuc/issues" Action="0" Component_="SHORTCUTDIR"/>
<ROW IniFile="URL_8" FileName="FAQ.url" DirProperty="Troubleshooting_Dir" Section="InternetShortcut" Key="URL" Value="https://github.com/zeffy/wufuc/blob/master/FAQ.md" Action="0" Component_="SHORTCUTDIR"/>
<ROW IniFile="WorkingDirectory" FileName="Donate.url" DirProperty="SHORTCUTDIR" Section="InternetShortcut" Key="WorkingDirectory" Value="[SHORTCUTDIR]" Action="0" Component_="SHORTCUTDIR"/>
<ROW IniFile="WorkingDirectory_2" FileName="Readme.url" DirProperty="SHORTCUTDIR" Section="InternetShortcut" Key="WorkingDirectory" Value="[SHORTCUTDIR]" Action="0" Component_="SHORTCUTDIR"/>
<ROW IniFile="WorkingDirectory_6" FileName="LATEST~1.URL|Latest Release.url" DirProperty="SHORTCUTDIR" Section="InternetShortcut" Key="WorkingDirectory" Value="[SHORTCUTDIR]" Action="0" Component_="SHORTCUTDIR"/>
<ROW IniFile="WorkingDirectory_7" FileName="REPORT~1.URL|Report an Issue.url" DirProperty="Troubleshooting_Dir" Section="InternetShortcut" Key="WorkingDirectory" Value="[Troubleshooting_Dir]" Action="0" Component_="SHORTCUTDIR"/>
<ROW IniFile="WorkingDirectory_6" FileName="LATEST~1.URL|Latest release.url" DirProperty="SHORTCUTDIR" Section="InternetShortcut" Key="WorkingDirectory" Value="[SHORTCUTDIR]" Action="0" Component_="SHORTCUTDIR"/>
<ROW IniFile="WorkingDirectory_7" FileName="REPORT~1.URL|Report an issue.url" DirProperty="Troubleshooting_Dir" Section="InternetShortcut" Key="WorkingDirectory" Value="[Troubleshooting_Dir]" Action="0" Component_="SHORTCUTDIR"/>
<ROW IniFile="WorkingDirectory_8" FileName="FAQ.url" DirProperty="Troubleshooting_Dir" Section="InternetShortcut" Key="WorkingDirectory" Value="[Troubleshooting_Dir]" Action="0" Component_="SHORTCUTDIR"/>
<ROW IniFile="c00730079007300740065006d0033003200" FileName="RESTOR~1.REG|Restore_wuauserv.reg" DirProperty="APPDIR" Section="HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\wuauserv\Parameters" Key="00,74,00,25,00,5c,00,73,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,\" Value="00,74,00,25,00,5c,00,73,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,\" Action="0" Component_="ProductInformation"/>
<ROW IniFile="e0067002e0064006c006c000000" FileName="RESTOR~1.REG|Restore_wuauserv.reg" DirProperty="APPDIR" Section="HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\wuauserv\Parameters" Key="77,00,75,00,61,00,75,00,65,00,6e,00,67,00,2e,00,64,00,6c,00,6c,00,00,00" Value="77,00,75,00,61,00,75,00,65,00,6e,00,67,00,2e,00,64,00,6c,00,6c,00,00,00" Action="0" Component_="ProductInformation"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiInstExSeqComponent">
<ROW Action="AI_DOWNGRADE" Condition="AI_NEWERPRODUCTFOUND AND (UILevel &lt;&gt; 5)" Sequence="210"/>
@@ -277,12 +253,8 @@
<ROW Action="RunScheduledTask" Condition="( ( NOT Installed ) OR ( Installed AND REMOVE &lt;&gt; &quot;ALL&quot; AND AI_INSTALL_MODE &lt;&gt; &quot;Remove&quot; ) )" Sequence="5827"/>
<ROW Action="RunSFCScan" Sequence="3603"/>
<ROW Action="AI_AppSearchEx" Sequence="101"/>
<ROW Action="SetRebootProperty" Condition="NONDEFAULT_SERVICEDLL" Sequence="201"/>
<ROW Action="StartWindowsUpdateService" Condition="( ( NOT Installed ) OR ( Installed AND REMOVE &lt;&gt; &quot;ALL&quot; AND AI_INSTALL_MODE &lt;&gt; &quot;Remove&quot; ) )" Sequence="6402"/>
<ROW Action="AI_DATA_SETTER_3" Condition="( ( NOT Installed ) OR ( Installed AND REMOVE &lt;&gt; &quot;ALL&quot; AND AI_INSTALL_MODE &lt;&gt; &quot;Remove&quot; ) )" Sequence="6401"/>
<ROW Action="AI_AiRemoveFilesImmediate" Sequence="3499"/>
<ROW Action="AI_AiRemoveFilesRollback" Sequence="3099"/>
<ROW Action="AI_PromptUserBasicUI" Condition="((REMOVE = &quot;ALL&quot;) AND (NOT UPGRADINGPRODUCTCODE))" Sequence="2501"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiInstallUISequenceComponent">
<ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=&quot;&quot;" Sequence="749"/>
@@ -307,13 +279,9 @@
<ROW Registry="Path" Root="-1" Key="Software\[ProductName]" Name="Path" Value="[APPDIR]" Component_="ProductInformation"/>
<ROW Registry="Version" Root="-1" Key="Software\[ProductName]" Name="Version" Value="[ProductVersion]" Component_="ProductInformation"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiRemoveFileComponent">
<ROW FileKey="_" Component_="ProductInformation" DirProperty="wufuc_Dir" InstallMode="2"/>
<ROW FileKey="log" Component_="ProductInformation" FileName="*.log" DirProperty="wufuc_Dir" InstallMode="2"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiShortsComponent">
<ROW Shortcut="License" Directory_="SHORTCUTDIR" Name="License" Component_="COPYING" Target="[#COPYING]" Hotkey="0" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>
<ROW Shortcut="Openwufuclogfile" Directory_="Troubleshooting_Dir" Name="OPENWU~1|Open wufuc log file" Component_="SHORTCUTDIR" Target="[CommonAppDataFolder]wufuc\wufuc.log" Hotkey="0" IconIndex="0" ShowCmd="1"/>
<ROW Shortcut="Openwufuclogfile" Directory_="Troubleshooting_Dir" Name="OPENWU~1|Open wufuc log file" Component_="SHORTCUTDIR" Target="[CommonAppDataFolder]wufuc\wufuc.1.log" Hotkey="0" IconIndex="0" ShowCmd="1"/>
<ROW Shortcut="Uninstallwufuc" Directory_="SHORTCUTDIR" Name="UNINST~2|Uninstall [|ProductName]" Component_="ProductInformation" Target="[SystemFolder]msiexec.exe" Arguments="/x [ProductCode]" Hotkey="0" Icon_="msiexec.exe" IconIndex="0" ShowCmd="1" CustomFlags="1"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiThemeComponent">

View File

@@ -0,0 +1,5 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,11
[InternetShortcut]
URL=https://github.com/zeffy/wufuc/blob/master/DONATE.md
IDList=

View File

@@ -0,0 +1,5 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,11
[InternetShortcut]
URL=https://github.com/zeffy/wufuc/releases/latest
IDList=

View File

@@ -0,0 +1,5 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,11
[InternetShortcut]
URL=https://github.com/zeffy/wufuc
IDList=

View File

@@ -5,12 +5,6 @@ VisualStudioVersion = 15.0.27130.2036
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wufuc", "wufuc\wufuc.vcxproj", "{00F96695-CE41-4C2F-A344-6219DFB4F887}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "wufuc_setup_bat", "wufuc_setup_bat", "{97E33D3C-9AA1-4B84-803A-1A6AE2C6F361}"
ProjectSection(SolutionItems) = preProject
wufuc_setup_bat\install_wufuc.bat = wufuc_setup_bat\install_wufuc.bat
wufuc_setup_bat\uninstall_wufuc.bat = wufuc_setup_bat\uninstall_wufuc.bat
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AdvancedInstallerHelper", "AdvancedInstallerHelper\AdvancedInstallerHelper.vcxproj", "{12498D61-02AF-4C13-925D-E130EEDE2543}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Repository Items", "Repository Items", "{E7EDB493-4D31-4646-8537-C515613689A6}"

121
src/wufuc/asprintf.c Normal file
View File

@@ -0,0 +1,121 @@
#include "stdafx.h"
#include "asprintf.h"
#include <locale.h>
int asprintf(char **strp, char const *const fmt, ...)
{
va_list ap;
int result;
va_start(ap, fmt);
result = vasprintf(strp, fmt, ap);
va_end(ap);
return result;
}
int vasprintf(char **strp, char const *const fmt, va_list ap)
{
return vasprintf_l(strp, fmt, _get_current_locale(), ap);
}
int asprintf_l(char **strp, char const *const fmt, _locale_t locale, ...)
{
va_list ap;
int result;
va_start(ap, locale);
result = vasprintf_l(strp, fmt, locale, ap);
va_end(ap);
return result;
}
int vasprintf_l(char **strp, char const *const fmt, _locale_t locale, va_list ap)
{
va_list copy;
int result;
char *str;
int ret;
va_copy(copy, ap);
result = _vscprintf(fmt, copy);
va_end(copy);
if ( result == -1 )
return result;
str = calloc(result + 1, sizeof *str);
if ( !str )
return -1;
va_copy(copy, ap);
ret = _vsprintf_s_l(str, result + 1, fmt, locale, copy);
va_end(copy);
if ( ret == -1 ) {
free(str);
return -1;
}
*strp = str;
return result;
}
int aswprintf(wchar_t **strp, wchar_t const *const fmt, ...)
{
va_list ap;
int result;
va_start(ap, fmt);
result = vaswprintf(strp, fmt, ap);
va_end(ap);
return result;
}
int vaswprintf(wchar_t **strp, wchar_t const *const fmt, va_list ap)
{
return vaswprintf_l(strp, fmt, _get_current_locale(), ap);
}
int aswprintf_l(wchar_t **strp, wchar_t const *const fmt, _locale_t locale, ...)
{
va_list ap;
int result;
va_start(ap, locale);
result = vaswprintf_l(strp, fmt, locale, ap);
va_end(ap);
return result;
}
int vaswprintf_l(wchar_t **strp, wchar_t const *const fmt, _locale_t locale, va_list ap)
{
va_list copy;
int result;
wchar_t *str;
int ret;
va_copy(copy, ap);
result = _vscwprintf_l(fmt, locale, copy);
va_end(copy);
if ( result == -1 )
return result;
str = calloc(result + 1, sizeof *str);
if ( !str )
return -1;
va_copy(copy, ap);
ret = _vswprintf_s_l(str, result + 1, fmt, locale, copy);
va_end(copy);
if ( ret == -1 ) {
free(str);
return -1;
}
*strp = str;
return result;
}

17
src/wufuc/asprintf.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
int asprintf(char **strp, char const *const fmt, ...);
int vasprintf(char **strp, char const *const fmt, va_list ap);
int asprintf_l(char **strp, char const *const fmt, _locale_t locale, ...);
int vasprintf_l(char **strp, char const *const fmt, _locale_t locale, va_list ap);
int aswprintf(wchar_t **strp, wchar_t const *const fmt, ...);
int vaswprintf(wchar_t **strp, wchar_t const *const fmt, va_list ap);
int aswprintf_l(wchar_t **strp, wchar_t const *const fmt, _locale_t locale, ...);
int vaswprintf_l(wchar_t **strp, wchar_t const *const fmt, _locale_t locale, va_list ap);

View File

@@ -1,165 +0,0 @@
#include "stdafx.h"
#include "callbacks.h"
#include "hooks.h"
#include "log.h"
#include "modulehelper.h"
#include "registryhelper.h"
#include "servicehelper.h"
#include "versionhelper.h"
#include "ptrlist.h"
#include "wufuc.h"
#include <VersionHelpers.h>
#include <minhook.h>
VOID CALLBACK service_notify_callback(PSERVICE_NOTIFYW pNotifyBuffer)
{
switch ( pNotifyBuffer->dwNotificationStatus ) {
case ERROR_SUCCESS:
if ( pNotifyBuffer->ServiceStatus.dwProcessId )
wufuc_inject(
pNotifyBuffer->ServiceStatus.dwProcessId,
(LPTHREAD_START_ROUTINE)thread_start_callback,
(ptrlist_t *)pNotifyBuffer->pContext);
break;
case ERROR_SERVICE_MARKED_FOR_DELETE:
SetEvent(ptrlist_at((ptrlist_t *)pNotifyBuffer->pContext, 0, NULL));
break;
}
if ( pNotifyBuffer->pszServiceNames )
LocalFree((HLOCAL)pNotifyBuffer->pszServiceNames);
}
DWORD WINAPI thread_start_callback(HANDLE *pParam)
{
HANDLE handles[2];
HANDLE hCrashMutex;
HANDLE hProceedEvent;
SC_HANDLE hSCM;
SC_HANDLE hService;
DWORD dwProcessId;
LPQUERY_SERVICE_CONFIGW pServiceConfig;
DWORD dwServiceType;
const wchar_t szKernel32Dll[] = L"kernel32.dll";
const wchar_t szKernelBaseDll[] = L"kernelbase.dll";
const wchar_t *pszModule;
MH_STATUS status;
int tmp;
LPVOID pv1 = NULL;
LPVOID pv2 = NULL;
wchar_t *str;
HMODULE hModule;
if ( !pParam ) {
log_error(L"Parameter argument is null!");
goto unload;
}
handles[0] = pParam[0]; // main mutex
handles[1] = pParam[1]; // unload event
hCrashMutex = pParam[2]; // crash mutex
hProceedEvent = pParam[3]; // proceed event
if ( !VirtualFree(pParam, 0, MEM_RELEASE) )
log_warning(L"VirtualFree failed! (lpAddress=%p, GLE=%lu)", pParam, GetLastError());
// acquire child mutex, this should be immediate.
if ( WaitForSingleObject(hCrashMutex, 5000) != WAIT_OBJECT_0 ) {
log_error(L"Failed to acquire crash mutex within five seconds. (%p)", hCrashMutex);
goto close_handles;
}
SetEvent(hProceedEvent);
CloseHandle(hProceedEvent);
hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
if ( !hSCM ) {
log_error(L"Failed to open SCM. (GetLastError=%lu)", GetLastError());
goto release;
}
hService = OpenServiceW(hSCM, L"wuauserv", SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
dwProcessId = svc_heuristic_process_id(hSCM, hService);
pServiceConfig = svc_query_config_alloc(hSCM, hService, NULL);
dwServiceType = pServiceConfig->dwServiceType;
tmp = _wcsicmp(pServiceConfig->lpBinaryPathName, GetCommandLineW());
free(pServiceConfig);
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
if ( tmp || dwProcessId != GetCurrentProcessId() ) {
log_error(L"Injected into wrong process!");
goto release;
}
if ( !ver_verify_version_info(6, 1, 0) && !ver_verify_version_info(6, 3, 0) ) {
log_error(L"Unsupported operating system!");
goto release;
}
if ( dwServiceType == SERVICE_WIN32_SHARE_PROCESS ) {
// assume wuaueng.dll hasn't been loaded yet, apply
// RegQueryValueExW hook to fix incompatibility with
// UpdatePack7R2 and other patches that modify the
// Windows Update ServiceDll path in the registry.
pszModule = IsWindows8OrGreater()
? szKernelBaseDll
: szKernel32Dll;
status = MH_CreateHookApiEx(pszModule,
"RegQueryValueExW",
RegQueryValueExW_hook,
&(PVOID)g_pfnRegQueryValueExW,
&pv1);
if ( status == MH_OK ) {
status = MH_EnableHook(pv1);
if ( status == MH_OK )
log_info(L"Hooked RegQueryValueExW! (Module=%ls, Address=%p)", pszModule, pv1);
else log_error(L"Failed to enable RegQueryValueExW hook! (Status=%hs)", MH_StatusToString(status));
} else log_error(L"Failed to create RegQueryValueExW hook! (Status=%hs)", MH_StatusToString(status));
}
// query the ServiceDll path after applying our compat hook so that it
// is consistent
str = (wchar_t *)reg_query_value_alloc(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\services\\wuauserv\\Parameters",
L"ServiceDll", NULL, NULL);
if ( !str ) {
abort_hook:
if ( pv1 )
MH_RemoveHook(pv1);
goto release;
}
g_pszWUServiceDll = env_expand_strings_alloc(str, NULL);
free(str);
if ( !g_pszWUServiceDll ) goto abort_hook;
status = MH_CreateHookApiEx(szKernelBaseDll,
"LoadLibraryExW",
LoadLibraryExW_hook,
&(PVOID)g_pfnLoadLibraryExW,
&pv2);
if ( status == MH_OK ) {
status = MH_EnableHook(pv2);
if ( status == MH_OK )
log_info(L"Hooked LoadLibraryExW! (Module=%ls, Address=%p)", szKernelBaseDll, pv2);
else log_error(L"Failed to enable LoadLibraryExW hook! (Status=%hs)", MH_StatusToString(status));
} else log_error(L"Failed to create LoadLibraryExW hook! (Status=%hs)", MH_StatusToString(status));
if ( GetModuleHandleExW(0, g_pszWUServiceDll, &hModule)
|| GetModuleHandleExW(0, PathFindFileNameW(g_pszWUServiceDll), &hModule) ) {
// hook IsDeviceServiceable if wuaueng.dll is already loaded
wufuc_patch(hModule);
FreeLibrary(hModule);
}
// wait for unload event or the main mutex to be released or abandoned,
// for example if the user killed rundll32.exe with task manager.
WaitForMultipleObjects(_countof(handles), handles, FALSE, INFINITE);
log_info(L"Unload condition has been met.");
MH_DisableHook(MH_ALL_HOOKS);
free(g_pszWUServiceDll);
release:
ReleaseMutex(hCrashMutex);
close_handles:
CloseHandle(hCrashMutex);
CloseHandle(handles[0]);
CloseHandle(handles[1]);
unload:
log_info(L"Unloading wufuc and exiting thread.");
FreeLibraryAndExitThread(PIMAGEBASE, 0);
}

View File

@@ -1,4 +0,0 @@
#pragma once
VOID CALLBACK service_notify_callback(PSERVICE_NOTIFYW pNotifyBuffer);
DWORD WINAPI thread_start_callback(HANDLE *pParam);

View File

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

View File

@@ -1,23 +0,0 @@
#include "stdafx.h"
#include "eventhelper.h"
#include <sddl.h>
HANDLE event_create_with_string_security_descriptor(
bool ManualReset,
bool InitialState,
const wchar_t *Name,
const wchar_t *StringSecurityDescriptor)
{
SECURITY_ATTRIBUTES sa = { sizeof sa };
if ( ConvertStringSecurityDescriptorToSecurityDescriptorW(
StringSecurityDescriptor,
SDDL_REVISION_1,
&sa.lpSecurityDescriptor,
NULL) ) {
return CreateEventW(&sa, ManualReset, InitialState, Name);
}
return NULL;
}

View File

@@ -1,7 +0,0 @@
#pragma once
HANDLE event_create_with_string_security_descriptor(
bool ManualReset,
bool InitialState,
const wchar_t *Name,
const wchar_t *StringSecurityDescriptor);

54
src/wufuc/helpers.c Normal file
View File

@@ -0,0 +1,54 @@
#include "stdafx.h"
#include "helpers.h"
#include <sddl.h>
HANDLE CreateEventWithStringSecurityDescriptor(
LPCWSTR lpStringSecurityDescriptor,
BOOL bManualReset,
BOOL bInitialState,
LPCWSTR lpName)
{
SECURITY_ATTRIBUTES sa = { sizeof sa };
if ( ConvertStringSecurityDescriptorToSecurityDescriptorW(
lpStringSecurityDescriptor,
SDDL_REVISION_1,
&sa.lpSecurityDescriptor,
NULL) ) {
return CreateEventW(&sa, bManualReset, bInitialState, lpName);
}
return NULL;
}
HANDLE CreateNewMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName)
{
HANDLE result;
result = CreateMutexW(lpMutexAttributes, bInitialOwner, lpName);
if ( result ) {
if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
CloseHandle(result);
return NULL;
}
return result;
}
return NULL;
}
BOOL VerifyVersionInfoHelper(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
{
DWORDLONG dwlConditionMask = 0;
OSVERSIONINFOEXW osvi = { sizeof osvi };
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);
}

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

@@ -0,0 +1,11 @@
#pragma once
HANDLE CreateNewMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName);
HANDLE CreateEventWithStringSecurityDescriptor(
LPCWSTR lpStringSecurityDescriptor,
BOOL bManualReset,
BOOL bInitialState,
LPCWSTR lpName);
BOOL VerifyVersionInfoHelper(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor);

View File

@@ -1,93 +0,0 @@
#include "stdafx.h"
#include "hooks.h"
#include "log.h"
#include "registryhelper.h"
#include "ptrlist.h"
#include "wufuc.h"
wchar_t *g_pszWUServiceDll;
LPFN_REGQUERYVALUEEXW g_pfnRegQueryValueExW;
LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW;
LSTATUS WINAPI RegQueryValueExW_hook(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
{
wchar_t *pBuffer;
DWORD MaximumLength = 0;
LSTATUS result;
ULONG ResultLength;
PKEY_NAME_INFORMATION pkni;
size_t NameCount;
unsigned int current;
int pos;
wchar_t *fname;
const wchar_t realpath[] = L"%systemroot%\\system32\\wuaueng.dll";
wchar_t *expandedpath;
DWORD cchLength;
// save original buffer size
if ( lpData && lpcbData )
MaximumLength = *lpcbData;
result = g_pfnRegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
if ( result != ERROR_SUCCESS
|| !MaximumLength
|| !lpValueName
|| (lpType && *lpType != REG_EXPAND_SZ)
|| _wcsicmp(lpValueName, L"ServiceDll") )
return result;
pBuffer = (wchar_t *)lpData;
// get name of registry key being queried
pkni = reg_query_key_alloc((HANDLE)hKey, KeyNameInformation, &ResultLength);
if ( !pkni )
return result;
NameCount = pkni->NameLength / sizeof *pkni->Name;
// change key name to lower-case because there is no case-insensitive version of _snwscanf_s
for ( size_t i = 0; i < NameCount; i++ )
pkni->Name[i] = towlower(pkni->Name[i]);
if ( _snwscanf_s(pkni->Name, NameCount, L"\\registry\\machine\\system\\controlset%03u\\services\\wuauserv\\parameters%n", &current, &pos) == 1
&& pos == NameCount ) {
fname = PathFindFileNameW(pBuffer);
if ( (!_wcsicmp(fname, L"wuaueng2.dll") // UpdatePack7R2
|| !_wcsicmp(fname, L"WuaCpuFix64.dll") // WuaCpuFix
|| !_wcsicmp(fname, L"WuaCpuFix.dll")) ) {
expandedpath = env_expand_strings_alloc(realpath, &cchLength);
if ( expandedpath ) {
if ( PathFileExistsW(expandedpath)
&& SUCCEEDED(StringCbCopyW(pBuffer, MaximumLength, expandedpath)) ) {
*lpcbData = cchLength * (sizeof *expandedpath);
log_info(L"Fixed path to Windows Update service library.");
}
free(expandedpath);
}
}
}
free(pkni);
return result;
}
HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags)
{
HMODULE result;
result = g_pfnLoadLibraryExW(lpFileName, hFile, dwFlags);
if ( !result ) return result;
log_debug(L"Loaded library: %ls (%p)", lpFileName, result);
if ( dwFlags == LOAD_WITH_ALTERED_SEARCH_PATH
&& g_pszWUServiceDll
&& (!_wcsicmp(lpFileName, g_pszWUServiceDll)
|| !_wcsicmp(lpFileName, PathFindFileNameW(g_pszWUServiceDll))) ) {
wufuc_patch(result);
}
return result;
}

View File

@@ -1,16 +0,0 @@
#pragma once
typedef LSTATUS(WINAPI *LPFN_REGQUERYVALUEEXW)(HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD);
typedef HMODULE(WINAPI *LPFN_LOADLIBRARYEXW)(LPCWSTR, HANDLE, DWORD);
extern wchar_t *g_pszWUServiceDll;
extern LPFN_REGQUERYVALUEEXW g_pfnRegQueryValueExW;
extern LPFN_LOADLIBRARYEXW g_pfnLoadLibraryExW;
extern PVOID g_ptRegQueryValueExW;
extern PVOID g_ptLoadLibraryExW;
LSTATUS WINAPI RegQueryValueExW_hook(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
HMODULE WINAPI LoadLibraryExW_hook(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags);

View File

@@ -1,162 +0,0 @@
#include "stdafx.h"
#include "log.h"
#include <ShlObj.h>
static HANDLE m_hFile = INVALID_HANDLE_VALUE;
static DWORD m_dwProcessId;
static wchar_t m_szExeFilePath[MAX_PATH];
static wchar_t *m_pszExeName;
BOOL CALLBACK init_once_callback(
PINIT_ONCE InitOnce,
PVOID *Parameter,
PVOID *lpContext)
{
BOOL result;
HRESULT hr;
wchar_t *pszPath;
wchar_t szFilePath[MAX_PATH];
int ret;
m_dwProcessId = GetCurrentProcessId();
if ( !GetModuleFileNameW(NULL, m_szExeFilePath, _countof(m_szExeFilePath)) ) {
log_debug(L"GetModuleFileNameW failed! (GLE=%lu)", GetLastError());
return FALSE;
}
m_pszExeName = PathFindFileNameW(m_szExeFilePath);
hr = SHGetKnownFolderPath(&FOLDERID_ProgramData, 0, NULL, &pszPath);
if ( hr != S_OK ) {
log_debug(L"SHGetKnownFolderPath failed! (HRESULT=0x%08X)", hr);
return FALSE;
}
ret = wcscpy_s(szFilePath, _countof(szFilePath), pszPath);
CoTaskMemFree(pszPath);
if ( ret ) {
log_debug(L"wcscpy_s failed! (Return value=%d)", ret);
return FALSE;
}
if ( !PathAppendW(szFilePath, L"wufuc") ) {
append_fail:
log_debug(L"PathAppendW failed!");
return FALSE;
}
if ( !CreateDirectoryW(szFilePath, NULL)
&& GetLastError() != ERROR_ALREADY_EXISTS ) {
log_debug(L"CreateDirectoryW failed! (GLE=%lu)", GetLastError());
return FALSE;
}
if ( !PathAppendW(szFilePath, L"wufuc.1.log") )
goto append_fail;
m_hFile = CreateFileW(szFilePath,
FILE_APPEND_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
result = m_hFile != INVALID_HANDLE_VALUE;
if ( !result )
log_debug(L"CreateFileW failed! (GLE=%lu)", GetLastError());
return result;
}
void log_debug_(const wchar_t *const format, ...)
{
va_list ap;
wchar_t *buf;
int ret;
int count;
va_start(ap, format);
count = _vscwprintf(format, ap);
va_end(ap);
if ( count == -1 ) return;
buf = calloc(count + 1, sizeof *buf);
if ( !buf ) return;
va_start(ap, format);
ret = vswprintf_s(buf, count + 1, format, ap);
va_end(ap);
if ( ret != -1 )
OutputDebugStringW(buf);
free(buf);
}
void log_trace_(const wchar_t *const format, ...)
{
static INIT_ONCE InitOnce = INIT_ONCE_STATIC_INIT;
BOOL bStatus;
wchar_t datebuf[9];
wchar_t timebuf[9];
va_list ap;
const wchar_t fmt[] = L"%ls %ls [%ls:%lu] %ls";
int count;
wchar_t *buf1;
int ret;
wchar_t *buf2;
int size;
char *buf3;
DWORD written;
bStatus = InitOnceExecuteOnce(&InitOnce, init_once_callback, NULL, NULL);
if ( _wstrdate_s(datebuf, _countof(datebuf))
|| _wstrtime_s(timebuf, _countof(timebuf)) )
return;
va_start(ap, format);
ret = _vscwprintf(format, ap);
va_end(ap);
if ( ret == -1 ) return;
count = ret + 1;
buf1 = calloc(count, sizeof *buf1);
if ( !buf1 ) return;
va_start(ap, format);
ret = vswprintf_s(buf1, count, format, ap);
va_end(ap);
if ( ret == -1 ) goto free_buf1;
ret = _scwprintf(fmt, datebuf, timebuf, m_pszExeName, m_dwProcessId, buf1);
if ( ret == -1 ) goto free_buf1;
count = ret + 1;
buf2 = calloc(count, sizeof *buf2);
if ( !buf2 ) goto free_buf1;
ret = swprintf_s(buf2, count, fmt, datebuf, timebuf, m_pszExeName, m_dwProcessId, buf1);
if ( ret == -1 ) goto free_buf2;
if ( bStatus ) {
size = WideCharToMultiByte(CP_UTF8, 0, buf2, ret, NULL, 0, NULL, NULL);
if ( !size ) goto fallback;
buf3 = malloc(size);
if ( !buf3 ) goto fallback;
ret = WideCharToMultiByte(CP_UTF8, 0, buf2, ret, buf3, size, NULL, NULL)
&& WriteFile(m_hFile, buf3, size, &written, NULL);
free(buf3);
if ( !ret ) goto fallback;
} else {
fallback:
OutputDebugStringW(buf2);
}
free_buf2:
free(buf2);
free_buf1:
free(buf1);
}
void log_close(void)
{
if ( m_hFile != INVALID_HANDLE_VALUE )
CloseHandle(m_hFile);
}

View File

@@ -1,10 +0,0 @@
#pragma once
void log_debug_(const wchar_t *const format, ...);
void log_trace_(const wchar_t *const format, ...);
void log_close(void);
#define log_debug(format, ...) log_debug_(__FUNCTIONW__ L"(" _CRT_WIDE(_CRT_STRINGIZE(__LINE__)) L"): [DEBUG] " format L"\r\n", ##__VA_ARGS__)
#define log_info(format, ...) log_trace_(__FUNCTIONW__ L"(" _CRT_WIDE(_CRT_STRINGIZE(__LINE__)) L"): [INFO] " format L"\r\n", ##__VA_ARGS__)
#define log_warning(format, ...) log_trace_(__FUNCTIONW__ L"(" _CRT_WIDE(_CRT_STRINGIZE(__LINE__)) L"): [WARNING] " format L"\r\n", ##__VA_ARGS__)
#define log_error(format, ...) log_trace_(__FUNCTIONW__ L"(" _CRT_WIDE(_CRT_STRINGIZE(__LINE__)) L"): [ERROR] " format L"\r\n", ##__VA_ARGS__)

99
src/wufuc/logger.c Normal file
View File

@@ -0,0 +1,99 @@
#include "stdafx.h"
#include "logger.h"
#include "utf8.h"
#include <ShlObj.h>
static WCHAR s_szExeFilePath[MAX_PATH];
static LPWSTR s_pszExeFileName;
static HANDLE s_hFile = INVALID_HANDLE_VALUE;
static BOOL CALLBACK init_once_callback(
PINIT_ONCE InitOnce,
PVOID *Parameter,
PVOID *lpContext)
{
PWSTR pszPath;
LPWSTR folder;
int count;
LPWSTR file;
if ( !GetModuleFileNameW(NULL, s_szExeFilePath, _countof(s_szExeFilePath)) )
return FALSE;
s_pszExeFileName = PathFindFileNameW(s_szExeFilePath);
if ( FAILED(SHGetKnownFolderPath(&FOLDERID_ProgramData, KF_FLAG_DEFAULT, NULL, &pszPath)) )
return FALSE;
count = aswprintf(&folder, L"%ls\\wufuc", pszPath);
CoTaskMemFree(pszPath);
if ( count == -1 )
return FALSE;
if ( (CreateDirectoryW(folder, NULL) || GetLastError() == ERROR_ALREADY_EXISTS)
&& aswprintf(&file, L"%ls\\wufuc.1.log", folder) != -1 ) {
s_hFile = CreateFileW(file,
FILE_APPEND_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
free(file);
}
free(folder);
return s_hFile != INVALID_HANDLE_VALUE;
}
void log_debug_(const wchar_t *const format, ...)
{
va_list ap;
int count;
wchar_t *buffer;
va_start(ap, format);
count = vaswprintf(&buffer, format, ap);
va_end(ap);
if ( count != -1 )
OutputDebugStringW(buffer);
free(buffer);
}
void log_trace_(const wchar_t *const format, ...)
{
static INIT_ONCE InitOnce = INIT_ONCE_STATIC_INIT;
BOOL status;
wchar_t datebuf[9];
wchar_t timebuf[9];
va_list ap;
int count;
wchar_t *buf1;
wchar_t *buf2;
status = InitOnceExecuteOnce(&InitOnce, init_once_callback, NULL, NULL);
if ( _wstrdate_s(datebuf, _countof(datebuf))
|| _wstrtime_s(timebuf, _countof(timebuf)) )
return;
va_start(ap, format);
count = vaswprintf(&buf1, format, ap);
va_end(ap);
if ( count == -1 ) return;
count = aswprintf(&buf2, L"%ls %ls [%ls:%lu] %ls", datebuf, timebuf, s_pszExeFileName, GetCurrentProcessId(), buf1);
free(buf1);
if ( count == -1 ) return;
if ( !status || !UTF8WriteFile(s_hFile, buf2) )
OutputDebugStringW(buf2);
free(buf2);
}
void log_close(void)
{
if ( s_hFile != INVALID_HANDLE_VALUE )
CloseHandle(s_hFile);
}

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

@@ -0,0 +1,11 @@
#pragma once
void log_debug_(const wchar_t *const format, ...);
void log_trace_(const wchar_t *const format, ...);
void log_close(void);
#define log_debug(format, ...) log_debug_(L"[DEBUG] " __FUNCTIONW__ L"(" _CRT_WIDE(_CRT_STRINGIZE(__LINE__)) L"): " format L"\r\n", ##__VA_ARGS__)
#define log_info(format, ...) log_trace_(L"[INFO] " __FUNCTIONW__ L"(" _CRT_WIDE(_CRT_STRINGIZE(__LINE__)) L"): " format L"\r\n", ##__VA_ARGS__)
#define log_warning(format, ...) log_trace_(L"[WARNING] " __FUNCTIONW__ L"(" _CRT_WIDE(_CRT_STRINGIZE(__LINE__)) L"): " format L"\r\n", ##__VA_ARGS__)
#define log_error(format, ...) log_trace_(L"[ERROR] " __FUNCTIONW__ L"(" _CRT_WIDE(_CRT_STRINGIZE(__LINE__)) L"): " format L"\r\n", ##__VA_ARGS__)
#define log_gle(format, ...) log_trace_(L"[ERROR] " __FUNCTIONW__ L"(" _CRT_WIDE(_CRT_STRINGIZE(__LINE__)) L"): " format L" (LastError=%lu)\r\n", ##__VA_ARGS__, GetLastError())

8
src/wufuc/memory.c Normal file
View File

@@ -0,0 +1,8 @@
#include "stdafx.h"
#include "stdafx.h"
#include "memory.h"
BOOL WriteProcessMemoryBOOL(HANDLE hProcess, LPBOOL lpBaseAddress, BOOL bValue)
{
return WriteProcessMemory(hProcess, lpBaseAddress, &bValue, sizeof bValue, NULL);
}

3
src/wufuc/memory.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
BOOL WriteProcessMemoryBOOL(HANDLE hProcess, LPBOOL lpBaseAddress, BOOL bValue);

View File

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

View File

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

24
src/wufuc/modules.c Normal file
View File

@@ -0,0 +1,24 @@
#include "stdafx.h"
#include "modules.h"
HMODULE Toolhelp32GetModuleHandle(DWORD th32ProcessID, LPCWSTR lpModuleName)
{
HANDLE Snapshot;
MODULEENTRY32W me = { sizeof me };
HMODULE result = NULL;
Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, th32ProcessID);
if ( !Snapshot ) return NULL;
if ( Module32FirstW(Snapshot, &me) ) {
do {
if ( !_wcsicmp(me.szExePath, lpModuleName) ) {
result = me.hModule;
break;
}
} while ( Module32NextW(Snapshot, &me) );
}
CloseHandle(Snapshot);
return result;
}

3
src/wufuc/modules.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
HMODULE Toolhelp32GetModuleHandle(DWORD th32ProcessID, LPCWSTR lpModuleName);

View File

@@ -1,41 +0,0 @@
#include "stdafx.h"
#include "mutexhelper.h"
#include <sddl.h>
HANDLE mutex_create_new(bool InitialOwner, const wchar_t *MutexName)
{
HANDLE hMutex;
hMutex = CreateMutexW(NULL, InitialOwner, MutexName);
if ( hMutex ) {
if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
CloseHandle(hMutex);
return NULL;
}
return hMutex;
}
return NULL;
}
HANDLE mutex_create_new_fmt(bool InitialOwner, const wchar_t *const NameFormat, ...)
{
HANDLE result = NULL;
va_list ap;
wchar_t *buffer;
int ret;
va_start(ap, NameFormat);
ret = _vscwprintf(NameFormat, ap) + 1;
va_end(ap);
buffer = calloc(ret, sizeof *buffer);
if ( buffer ) {
va_start(ap, NameFormat);
ret = vswprintf_s(buffer, ret, NameFormat, ap);
va_end(ap);
if (ret != -1)
result = mutex_create_new(InitialOwner, buffer);
free(buffer);
}
return result;
}

View File

@@ -1,4 +0,0 @@
#pragma once
HANDLE mutex_create_new(bool InitialOwner, const wchar_t *MutexName);
HANDLE mutex_create_new_fmt(bool InitialOwner, const wchar_t *const NameFormat, ...);

View File

@@ -1,403 +0,0 @@
#include "stdafx.h"
#include "ptrlist.h"
void ptrlist_lock(ptrlist_t *list)
{
EnterCriticalSection(&list->criticalSection);
}
void ptrlist_unlock(ptrlist_t *list)
{
LeaveCriticalSection(&list->criticalSection);
}
void *ptrlist_at(ptrlist_t *list, size_t index, uint32_t *pTag)
{
void *result;
ptrlist_lock(list);
result = list->values[index];
if ( pTag )
*pTag = list->tags[index];
ptrlist_unlock(list);
return result;
}
bool ptrlist_create(ptrlist_t *list, size_t capacity, size_t maxCapacity)
{
bool result = false;
size_t c;
size_t vsize;
size_t tsize;
void *tmp;
if ( !list || capacity > maxCapacity )
return result;
c = capacity ? capacity :
(maxCapacity ? min(maxCapacity, 16) : 16);
vsize = c * (sizeof *list->values);
tsize = c * (sizeof *list->tags);
InitializeCriticalSection(&list->criticalSection);
ptrlist_lock(list);
tmp = malloc(vsize + tsize);
if ( tmp ) {
ZeroMemory(tmp, vsize + tsize);
list->values = tmp;
list->tags = OffsetToPointer(tmp, vsize);
list->capacity = c;
list->maxCapacity = maxCapacity;
list->count = 0;
result = true;
}
ptrlist_unlock(list);
if ( !result )
DeleteCriticalSection(&list->criticalSection);
return result;
}
void ptrlist_destroy(ptrlist_t *list)
{
if ( !list ) return;
ptrlist_lock(list);
free(list->values);
list->values = NULL;
list->tags = NULL;
list->count = 0;
list->capacity = 0;
list->maxCapacity = 0;
ptrlist_unlock(list);
DeleteCriticalSection(&list->criticalSection);
}
size_t ptrlist_index_of(ptrlist_t *list, void *value)
{
size_t result = -1;
if ( !list || !value )
return result;
ptrlist_lock(list);
for ( size_t i = 0; i < list->count; i++ ) {
if ( list->values[i] == value ) {
result = i;
break;
}
}
ptrlist_unlock(list);
return result;
}
bool ptrlist_add(ptrlist_t *list, void *value, uint32_t tag)
{
bool result = false;
size_t newCapacity;
size_t diff;
size_t vsize;
size_t tsize;
void **tmp1;
uint32_t *tmp2;
if ( !list || !value )
return result;
ptrlist_lock(list);
if ( list->count >= list->capacity ) {
newCapacity = list->count;
if ( list->maxCapacity ) {
diff = list->maxCapacity - list->capacity;
if ( !diff )
goto leave;
newCapacity += min(diff, 16);
} else {
newCapacity += 16;
}
vsize = newCapacity * (sizeof *list->values);
tsize = newCapacity * (sizeof *list->tags);
tmp1 = malloc(vsize + tsize);
if ( !tmp1 )
goto leave;
ZeroMemory(tmp1, vsize);
tmp2 = OffsetToPointer(tmp1, vsize);
ZeroMemory(tmp2, tsize);
if ( memmove_s(tmp1, vsize, list->values, list->count * (sizeof *list->values))
|| memmove_s(tmp2, tsize, list->tags, list->count * (sizeof *list->tags)) ) {
free(tmp1);
goto leave;
}
list->values = tmp1;
list->tags = tmp2;
list->capacity = newCapacity;
}
list->values[list->count] = value;
list->tags[list->count] = tag;
list->count++;
result = true;
leave:
ptrlist_unlock(list);
return result;
}
bool ptrlist_add_range(ptrlist_t *list, void **values, uint32_t *tags, size_t count)
{
bool result = true;
if ( !list || !values || !count )
return false;
ptrlist_lock(list);
if ( list->count + count <= list->maxCapacity ) {
for ( size_t i = 0; result && i < count; i++ )
result = ptrlist_add(list, values[i], tags ? tags[i] : 0);
} else {
result = false;
}
ptrlist_unlock(list);
return result;
}
bool ptrlist_remove_at(ptrlist_t *list, size_t index)
{
bool result = false;
if ( !list ) return result;
ptrlist_lock(list);
if ( index <= list->count - 1 ) {
for ( size_t i = index; i < list->count - 1; i++ )
list->values[i] = list->values[i + 1];
list->values[list->count--] = NULL;
result = true;
}
ptrlist_unlock(list);
return result;
}
bool ptrlist_remove(ptrlist_t *list, void *value)
{
size_t index;
bool result = false;
if ( !list || !value )
return result;
ptrlist_lock(list);
index = ptrlist_index_of(list, value);
if ( index != -1 )
result = ptrlist_remove_at(list, index);
ptrlist_unlock(list);
return result;
}
bool ptrlist_remove_range(ptrlist_t *list, size_t index, size_t count)
{
bool result = true;
if ( !list || !count )
return false;
ptrlist_lock(list);
if ( index <= list->count - 1
&& index + count <= list->count ) {
for ( size_t i = 0; result && i < count; i++ )
result = ptrlist_remove_at(list, index);
} else {
result = false;
}
ptrlist_unlock(list);
return result;
}
bool ptrlist_clear(ptrlist_t *list)
{
bool result = false;
if ( !list ) return result;
ptrlist_lock(list);
result = ptrlist_remove_range(list, 0, list->count);
ptrlist_unlock(list);
return result;
}
size_t ptrlist_get_count(ptrlist_t *list)
{
size_t result = -1;
if ( !list ) return result;
ptrlist_lock(list);
result = list->count;
ptrlist_unlock(list);
return result;
}
size_t ptrlist_get_capacity(ptrlist_t *list)
{
size_t result = -1;
if ( !list ) return result;
ptrlist_lock(list);
result = list->capacity;
ptrlist_unlock(list);
return result;
}
size_t ptrlist_get_max_capacity(ptrlist_t *list)
{
size_t result = -1;
if ( !list ) return result;
ptrlist_lock(list);
result = list->maxCapacity;
ptrlist_unlock(list);
return result;
}
bool ptrlist_contains(ptrlist_t *list, void *value)
{
return ptrlist_index_of(list, value) != -1;
}
void **ptrlist_copy_values(ptrlist_t *list, size_t *count)
{
void **result = NULL;
size_t size;
size_t c;
if ( !list || !count )
return result;
ptrlist_lock(list);
c = list->count;
if ( !c ) goto leave;
size = c * (sizeof *list->values);
result = malloc(c * (sizeof *list->values));
if ( result ) {
if ( !memcpy_s(result, size, list->values, size) ) {
*count = c;
} else {
free(result);
result = NULL;
}
}
leave:
ptrlist_unlock(list);
return result;
}
uint32_t *ptrlist_copy_tags(ptrlist_t *list, size_t *count)
{
uint32_t *result = NULL;
size_t size;
size_t c;
if ( !list || !count )
return result;
ptrlist_lock(list);
c = list->count;
if ( !c ) goto leave;
size = c * (sizeof *list->tags);
result = malloc(c * (sizeof *list->tags));
if ( result ) {
if ( !memcpy_s(result, size, list->tags, size) ) {
*count = c;
} else {
free(result);
result = NULL;
}
}
leave:
ptrlist_unlock(list);
return result;
}
bool ptrlist_copy(ptrlist_t *list, void ***values, uint32_t **tags, size_t *count)
{
bool result = false;
void **v;
uint32_t *t;
size_t c;
if ( !values || !tags || !count )
return result;
ptrlist_lock(list);
v = ptrlist_copy_values(list, &c);
if ( !v ) goto leave;
t = ptrlist_copy_tags(list, &c);
if ( !t ) {
free(v);
goto leave;
}
*values = v;
*tags = t;
*count = c;
result = true;
leave:
ptrlist_unlock(list);
return result;
}
void ptrlist_for(ptrlist_t *list, size_t index, size_t count, void(__cdecl *f)(void *))
{
if ( !list || !f ) return;
ptrlist_lock(list);
if ( index + count <= list->count ) {
for ( size_t i = index; i < count; i++ )
f(list->values[i]);
}
ptrlist_unlock(list);
}
void ptrlist_for_each(ptrlist_t *list, void(__cdecl *f)(void *))
{
if ( !list || !f ) return;
ptrlist_lock(list);
ptrlist_for(list, 0, list->count, f);
ptrlist_unlock(list);
}
void ptrlist_for_stdcall(ptrlist_t *list, size_t index, size_t count, void(__stdcall *f)(void *))
{
if ( !list || !f ) return;
ptrlist_lock(list);
if ( index + count <= list->count ) {
for ( size_t i = index; i < count; i++ )
f(list->values[i]);
}
ptrlist_unlock(list);
}
void ptrlist_for_each_stdcall(ptrlist_t *list, void(__stdcall *f)(void *))
{
if ( !list || !f ) return;
ptrlist_lock(list);
ptrlist_for_stdcall(list, 0, list->count, f);
ptrlist_unlock(list);
}

View File

@@ -1,37 +0,0 @@
#pragma once
#pragma pack(push, 1)
typedef struct ptrlist_t_
{
void **values;
uint32_t *tags;
size_t capacity;
size_t maxCapacity;
size_t count;
CRITICAL_SECTION criticalSection;
} ptrlist_t;
#pragma pack(pop)
void ptrlist_lock(ptrlist_t *list);
void ptrlist_unlock(ptrlist_t *list);
void *ptrlist_at(ptrlist_t *list, size_t index, uint32_t *pTag);
bool ptrlist_create(ptrlist_t *list, size_t capacity, size_t maxCapacity);
void ptrlist_destroy(ptrlist_t *list);
size_t ptrlist_index_of(ptrlist_t *list, void *value);
bool ptrlist_add(ptrlist_t *list, void *value, uint32_t tag);
bool ptrlist_add_range(ptrlist_t *list, void **values, uint32_t *tags, size_t count);
bool ptrlist_remove_at(ptrlist_t *list, size_t index);
bool ptrlist_remove(ptrlist_t *list, void *value);
bool ptrlist_remove_range(ptrlist_t *list, size_t index, size_t count);
bool ptrlist_clear(ptrlist_t *list);
size_t ptrlist_get_count(ptrlist_t *list);
size_t ptrlist_get_capacity(ptrlist_t *list);
size_t ptrlist_get_max_capacity(ptrlist_t *list);
bool ptrlist_contains(ptrlist_t *list, void *value);
void **ptrlist_copy_values(ptrlist_t *list, size_t *count);
uint32_t *ptrlist_copy_tags(ptrlist_t *list, size_t *count);
bool ptrlist_copy(ptrlist_t *list, void ***values, uint32_t **tags, size_t *count);
void ptrlist_for(ptrlist_t *list, size_t index, size_t count, void(__cdecl *f)(void *));
void ptrlist_for_each(ptrlist_t *list, void(__cdecl *f)(void *));
void ptrlist_for_stdcall(ptrlist_t *list, size_t index, size_t count, void(__stdcall *f)(void *));
void ptrlist_for_each_stdcall(ptrlist_t *list, void(__stdcall *f)(void *));

22
src/wufuc/registry.c Normal file
View File

@@ -0,0 +1,22 @@
#include "stdafx.h"
#include "registry.h"
DWORD RegGetValueAlloc(PVOID *ppvData, HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpValueName, DWORD dwFlags, LPDWORD pdwType)
{
DWORD result;
PVOID pvData;
if ( RegGetValueW(hKey, lpSubKey, lpValueName, dwFlags, pdwType, NULL, &result) != ERROR_SUCCESS )
return 0;
pvData = malloc(result);
if ( !pvData ) return 0;
if ( RegGetValueW(hKey, lpSubKey, lpValueName, dwFlags, pdwType, pvData, &result) == ERROR_SUCCESS ) {
*ppvData = pvData;
} else {
free(pvData);
return 0;
}
return result;
}

3
src/wufuc/registry.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
DWORD RegGetValueAlloc(PVOID *ppvData, HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpValueName, DWORD dwFlags, LPDWORD pdwType);

View File

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

View File

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

View File

@@ -8,11 +8,11 @@
#define BUILD_VERSION_COMMA 1,0,1,0
#endif
#define S_(x) #x
#define S(x) S_(x)
#define STRINGIZE_(x) #x
#define STRINGIZE(x) STRINGIZE_(x)
#ifdef X64
#ifdef _WIN64
#define FILENAME "wufuc64.dll"
#elif defined(X86)
#else
#define FILENAME "wufuc32.dll"
#endif

Binary file not shown.

View File

@@ -1,84 +0,0 @@
#include "stdafx.h"
#include "resourcehelper.h"
#include "log.h"
void *res_get_version_info(HMODULE hModule)
{
HRSRC hResInfo;
DWORD dwSize;
HGLOBAL hResData;
LPVOID pRes;
void *result;
hResInfo = FindResourceW(hModule,
MAKEINTRESOURCEW(VS_VERSION_INFO),
MAKEINTRESOURCEW(RT_VERSION));
if ( !hResInfo ) return NULL;
dwSize = SizeofResource(hModule, hResInfo);
if ( !dwSize ) return NULL;
hResData = LoadResource(hModule, hResInfo);
if ( !hResData ) return NULL;
pRes = LockResource(hResData);
if ( !pRes ) return NULL;
result = malloc(dwSize);
if ( !result ) return NULL;
if ( memcpy_s(result, dwSize, pRes, dwSize) ) {
free(result);
result = NULL;
}
return result;
}
wchar_t *res_query_string_file_info(const void *pBlock,
LANGANDCODEPAGE lcp,
const wchar_t *pszStringName,
size_t *pcchLength)
{
const wchar_t fmt[] = L"\\StringFileInfo\\%04x%04x\\%ls";
int ret;
int count;
wchar_t *pszSubBlock;
wchar_t *result = NULL;
UINT uLen;
ret = _scwprintf(fmt, lcp.wLanguage, lcp.wCodePage, pszStringName);
if ( ret == -1 ) return NULL;
count = ret + 1;
pszSubBlock = calloc(count, sizeof *pszSubBlock);
if ( !pszSubBlock ) return NULL;
ret = swprintf_s(pszSubBlock, count, fmt, lcp.wLanguage, lcp.wCodePage, pszStringName);
if ( ret != -1
&& VerQueryValueW(pBlock, pszSubBlock, &(LPVOID)result, &uLen)
&& pcchLength )
*pcchLength = uLen;
free(pszSubBlock);
return result;
}
PLANGANDCODEPAGE res_query_var_file_info(const void *pBlock, size_t *pCount)
{
PLANGANDCODEPAGE result = NULL;
UINT uLen;
if ( VerQueryValueW(pBlock, L"\\VarFileInfo\\Translation", &(LPVOID)result, &uLen) )
*pCount = uLen / (sizeof *result);
return result;
}
VS_FIXEDFILEINFO *res_query_fixed_file_info(const void *pBlock)
{
VS_FIXEDFILEINFO *result;
UINT uLen;
if ( VerQueryValueW(pBlock, L"\\", &(LPVOID)result, &uLen) )
return result;
return NULL;
}

View File

@@ -1,18 +0,0 @@
#pragma once
typedef struct
{
WORD wLanguage;
WORD wCodePage;
} LANGANDCODEPAGE, *PLANGANDCODEPAGE;
void *res_get_version_info(HMODULE hModule);
wchar_t *res_query_string_file_info(const void *pBlock,
LANGANDCODEPAGE lcp,
const wchar_t *pszStringName,
size_t *pcchLength);
PLANGANDCODEPAGE res_query_var_file_info(const void *pBlock, size_t *pcbData);
VS_FIXEDFILEINFO *res_query_fixed_file_info(const void *pBlock);

View File

@@ -1,148 +1,261 @@
#include "stdafx.h"
#include "callbacks.h"
#include "eventhelper.h"
#include "log.h"
#include "modulehelper.h"
#include "mutexhelper.h"
#include "ptrlist.h"
#include "registryhelper.h"
#include "servicehelper.h"
#include "wufuc.h"
#include "memory.h"
#include "modules.h"
#include "patternfind.h"
#include "registry.h"
#include "helpers.h"
#include "versioninfo.h"
const wchar_t m_szUnloadEventName[] = L"Global\\wufuc_UnloadEvent";
static BOOL s_bWindowsSevenSP1;
static BOOL s_bWindowsEightPointOne;
void CALLBACK RUNDLL32_StartW(HWND hwnd,
HINSTANCE hinst,
LPWSTR lpszCmdLine,
int nCmdShow)
static LPVOID ResolveAndTranslatePtr(LPVOID lpSrcImageBase, size_t Offset, LPVOID lpDstImageBase)
{
ptrlist_t list;
HANDLE hEvent;
DWORD dwDesiredAccess;
LPVOID p = OffsetToPointer(lpSrcImageBase, Offset);
#ifdef _WIN64
return OffsetToPointer(lpDstImageBase, PointerToOffset(lpSrcImageBase, OffsetToPointer(p, sizeof(uint32_t) + *(uint32_t *)p)));
#else
return *(LPVOID *)p;
#endif
}
static VOID CALLBACK ServiceNotifyCallback(PVOID pParameter)
{
PSERVICE_NOTIFY pNotifyBuffer = pParameter;
DWORD dwProcessId = pNotifyBuffer->ServiceStatus.dwProcessId;
const DWORD dwDesiredAccess = PROCESS_SUSPEND_RESUME | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE;
LPWSTR fname;
HANDLE hProcess;
NTSTATUS Status;
LPWSTR lpwstrFilename;
LPVOID lpData;
PLANGANDCODEPAGE lpTranslate;
LPWSTR lpInternalName;
VS_FIXEDFILEINFO *lpffi;
const char *pattern;
size_t off1;
size_t off2;
HMODULE hModule;
MODULEINFO modinfo;
LPVOID lpBuffer;
SIZE_T NumberOfBytesRead;
size_t offset;
LPVOID lpAddress;
BOOL bValue;
switch ( pNotifyBuffer->dwNotificationStatus ) {
case ERROR_SUCCESS:
if ( !RegGetValueAlloc(&lpwstrFilename,
HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\services\\wuauserv\\Parameters",
L"ServiceDll",
RRF_RT_REG_SZ,
NULL) ) {
log_gle(L"Failed to get wuauserv ServiceDll value!");
break;
}
if ( !GetFileVersionInfoExAlloc(FILE_VER_GET_NEUTRAL, TRUE, lpwstrFilename, &lpData) ) {
log_gle(L"Failed to get file version information: lpwstrFilename=%ls", lpwstrFilename);
goto free_lpwstrFilename;
}
if ( !VerQueryTranslations(lpData, &lpTranslate) ) {
log_gle(L"Failed to get resource translations: pBlock=%p", lpData);
goto free_lpData;
}
if ( !VerQueryString(lpData, lpTranslate[0], L"InternalName", &lpInternalName) ) {
log_gle(L"Failed to get InternalName resource string: wLanguage=%04x wCodePage=%04x pBlock=%p",
lpTranslate[0].wLanguage, lpTranslate[0].wCodePage, lpData);
goto free_lpData;
}
if ( _wcsicmp(lpInternalName, L"wuaueng.dll") ) {
log_error(L"InternalName mismatch: lpInternalName=%ls", lpInternalName);
goto free_lpData;
}
if ( !VerQueryFileInfo(lpData, &lpffi) ) {
log_gle(L"Failed to get resource file info: pBlock=%p", lpData);
goto free_lpData;
}
#ifdef _WIN64
if ( (s_bWindowsSevenSP1 && vercmp(lpffi->dwProductVersionMS, lpffi->dwProductVersionLS, 7, 6, 7601, 23714) != -1)
|| (s_bWindowsEightPointOne && vercmp(lpffi->dwProductVersionMS, lpffi->dwProductVersionLS, 7, 9, 9600, 18621) != -1) ) {
// all x64
pattern = "FFF3 4883EC?? 33DB 391D???????? 7508 8B05????????";
off1 = 0xa;
off2 = 0x12;
} else goto free_lpData;
#else
if ( s_bWindowsSevenSP1 && vercmp(lpffi->dwProductVersionMS, lpffi->dwProductVersionLS, 7, 6, 7601, 23714) != -1 ) {
// windows 7 x86
pattern = "833D????????00 743E E8???????? A3????????";
off1 = 0x2;
off2 = 0xf;
} else if ( s_bWindowsEightPointOne && vercmp(lpffi->dwProductVersionMS, lpffi->dwProductVersionLS, 7, 9, 9600, 18621) != -1 ) {
// windows 8.1 x86
pattern = "8BFF 51 833D????????00 7507 A1????????";
off1 = 0x5;
off2 = 0xd;
} else goto free_lpData;
#endif
fname = PathFindFileNameW(lpwstrFilename);
log_info(L"Supported version of %ls: %hu.%hu.%hu.%hu",
fname,
HIWORD(lpffi->dwProductVersionMS), LOWORD(lpffi->dwProductVersionMS),
HIWORD(lpffi->dwProductVersionLS), LOWORD(lpffi->dwProductVersionLS));
hProcess = OpenProcess(dwDesiredAccess, FALSE, dwProcessId);
if ( !hProcess ) {
log_gle(L"Failed to open target process: dwProcessId=%lu", dwProcessId);
goto free_lpData;
}
Status = NtSuspendProcess(hProcess);
if ( Status != STATUS_SUCCESS ) {
log_error(L"Failed to suspend target process: hProcess=%p (Status=%ld)", hProcess, Status);
goto close_hProcess;
}
hModule = Toolhelp32GetModuleHandle(dwProcessId, lpwstrFilename);
if ( !hModule ) {
log_gle(L"Failed to find target module in Toolhelp32 snapshot: th32ProcessId=%lu lpModuleName=%ls",
dwProcessId, lpwstrFilename);
goto resume_hProcess;
}
if ( !GetModuleInformation(hProcess, hModule, &modinfo, sizeof modinfo) ) {
log_error(L"Failed to get target module information: hProcess=%p hModule=%p", hProcess, hModule);
goto resume_hProcess;
}
lpBuffer = malloc(modinfo.SizeOfImage);
if ( !lpBuffer ) {
log_error(L"Failed to allocate memory for lpBuffer!");
goto resume_hProcess;
}
if ( !ReadProcessMemory(hProcess, modinfo.lpBaseOfDll, lpBuffer, modinfo.SizeOfImage, &NumberOfBytesRead) ) {
log_gle(L"Failed to read target process memory: hProcess=%p lpBaseAddress=%p nSize=%lu",
hProcess, modinfo.lpBaseOfDll, modinfo.SizeOfImage);
goto free_lpBuffer;
}
offset = patternfind(lpBuffer, NumberOfBytesRead, pattern);
if ( offset == -1 ) {
log_error(L"Failed to find IsDeviceServiceable pattern!");
goto free_lpBuffer;
}
log_info(L"Found IsDeviceServiceable function offset: %ls+0x%Ix", fname, offset);
lpAddress = ResolveAndTranslatePtr(lpBuffer, offset + off1, modinfo.lpBaseOfDll);
bValue = FALSE;
if ( WriteProcessMemory(hProcess, lpAddress, &bValue, sizeof bValue, NULL) )
log_info(L"Successfully wrote value to target process: lpAddress=%p", lpAddress);
else
log_gle(L"Failed to write value to target process: lpAddress=%p!", lpAddress);
lpAddress = ResolveAndTranslatePtr(lpBuffer, offset + off2, modinfo.lpBaseOfDll);
bValue = TRUE;
if ( WriteProcessMemory(hProcess, lpAddress, &bValue, sizeof bValue, NULL) )
log_info(L"Successfully wrote value to target process: lpAddress=%p", lpAddress);
else
log_gle(L"Failed to patch flag in target process at address %p!", lpAddress);
free_lpBuffer:
free(lpBuffer);
resume_hProcess:
NtResumeProcess(hProcess);
close_hProcess:
CloseHandle(hProcess);
free_lpData:
free(lpData);
free_lpwstrFilename:
free(lpwstrFilename);
break;
case ERROR_SERVICE_MARKED_FOR_DELETE:
*(bool *)pNotifyBuffer->pContext = true;
break;
}
if ( pNotifyBuffer->pszServiceNames )
LocalFree((HLOCAL)pNotifyBuffer->pszServiceNames);
}
void CALLBACK RUNDLL32_StartW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
{
HANDLE hMutex;
HANDLE hUnloadEvent;
bool Lagging;
SC_HANDLE hSCM;
SC_HANDLE hService;
DWORD dwProcessId;
SERVICE_NOTIFYW NotifyBuffer;
bool Unloading = false;
DWORD e;
void **values;
uint32_t *tags;
size_t count;
DWORD r;
size_t index;
size_t crashes = 0;
bool Suspending = false;
DWORD Error;
g_hMainMutex = mutex_create_new(true,
L"Global\\25020063-b5a7-4227-9fdf-25cb75e8c645");
if ( !g_hMainMutex ) return;
if ( !ptrlist_create(&list, 0, MAXIMUM_WAIT_OBJECTS) ) goto release_mutex;
hEvent = event_create_with_string_security_descriptor(
true, false, m_szUnloadEventName, L"D:(A;;0x001F0003;;;BA)");
if ( !hEvent ) goto destroy_list;
if ( !ptrlist_add(&list, hEvent, 0) ) goto set_event;
dwDesiredAccess = SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG;
hMutex = CreateNewMutex(NULL, TRUE, L"Global\\25020063-b5a7-4227-9fdf-25cb75e8c645");
if ( !hMutex ) {
log_error(L"Failed to create instance mutex!");
return;
}
hUnloadEvent = CreateEventWithStringSecurityDescriptor(L"D:(A;;0x001F0003;;;BA)",
TRUE, FALSE, L"Global\\wufuc_UnloadEvent");
if ( !hUnloadEvent ) {
log_gle(L"Failed to create unload event!");
goto release_mutex;
}
s_bWindowsSevenSP1 = VerifyVersionInfoHelper(6, 1, 1);
if ( !s_bWindowsSevenSP1 ) {
s_bWindowsEightPointOne = VerifyVersionInfoHelper(6, 3, 0);
if ( !s_bWindowsEightPointOne ) {
log_error(L"Unsupported operating system!");
goto close_event;
}
}
do {
Lagging = false;
hSCM = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
if ( !hSCM ) goto set_event;
if ( !hSCM ) break;
hService = OpenServiceW(hSCM, L"wuauserv", dwDesiredAccess);
if ( !hService ) goto close_scm;
if ( (dwDesiredAccess & SERVICE_QUERY_CONFIG) == SERVICE_QUERY_CONFIG ) {
dwDesiredAccess &= ~SERVICE_QUERY_CONFIG;
dwProcessId = svc_heuristic_process_id(hSCM, hService);
if ( dwProcessId )
wufuc_inject(dwProcessId, (LPTHREAD_START_ROUTINE)thread_start_callback, &list);
hService = OpenServiceW(hSCM, L"wuauserv", SERVICE_QUERY_STATUS);
if ( !hService ) {
CloseServiceHandle(hSCM);
break;
}
ZeroMemory(&NotifyBuffer, sizeof NotifyBuffer);
NotifyBuffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
NotifyBuffer.pfnNotifyCallback = (PFN_SC_NOTIFY_CALLBACK)service_notify_callback;
NotifyBuffer.pContext = (PVOID)&list;
while ( !Unloading && !Lagging ) {
e = NotifyServiceStatusChangeW(hService,
NotifyBuffer.pfnNotifyCallback = ServiceNotifyCallback;
NotifyBuffer.pContext = &Lagging;
while ( true ) {
Error = NotifyServiceStatusChangeW(hService,
SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_RUNNING,
&NotifyBuffer);
switch ( e ) {
switch ( Error ) {
case ERROR_SUCCESS:
do {
if ( !ptrlist_copy(&list, &values, &tags, &count) ) {
Unloading = true;
break;
Error = WaitForSingleObjectEx(hUnloadEvent, INFINITE, TRUE);
switch ( Error ) {
case WAIT_OBJECT_0:
log_info(L"Unload event signaled!");
goto exit_loop;
case WAIT_FAILED:
log_error(L"WaitForSingleObjectEx failed! Error=%lu", Error);
goto exit_loop;
}
r = WaitForMultipleObjectsEx((DWORD)count,
values, FALSE, INFINITE, TRUE);
if ( r >= WAIT_OBJECT_0 && r < WAIT_OBJECT_0 + count ) {
// object signaled
index = r - WAIT_OBJECT_0;
if ( !index ) {
// Unload event
Unloading = true;
} else {
// crash mutex was released cleanly
ptrlist_remove(&list, values[index]);
ReleaseMutex(values[index]);
CloseHandle(values[index]);
}
} else if ( r >= WAIT_ABANDONED_0 && r < WAIT_ABANDONED_0 + count ) {
// object abandoned
// crash mutex was abandoned, process has most likely crashed.
index = r - WAIT_ABANDONED_0;
ptrlist_remove(&list, values[index]);
ReleaseMutex(values[index]);
CloseHandle(values[index]);
crashes++;
log_warning(L"A process wufuc injected into has crashed %Iu time%ls! (ProcessId=%lu)",
crashes, crashes != 1 ? L"s" : L"", tags[index]);
if ( crashes >= SVCHOST_CRASH_THRESHOLD ) {
log_error(L"Crash threshold has been reached, disabling wufuc until next reboot!");
Unloading = true;
Suspending = true;
}
} else if ( r == WAIT_FAILED ) {
log_error(L"Wait function failed!");
Unloading = true;
}
free(values);
free(tags);
} while ( r != WAIT_IO_COMPLETION && !Unloading );
} while ( Error != WAIT_IO_COMPLETION );
break;
case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING:
log_warning(L"Client lagging!");
log_warning(L"The service notification client is lagging too far behind the current state of services in the machine.");
Lagging = true;
break;
goto exit_loop;
case ERROR_SERVICE_MARKED_FOR_DELETE:
log_warning(L"The specified service has been marked for deletion.");
Lagging = true;
goto exit_loop;
default:
log_error(L"NotifyServiceStatusChange failed! (Return value=%lu)", e);
Unloading = true;
break;
log_error(L"NotifyServiceStatusChange failed! Error=%lu", Error);
goto exit_loop;
}
}
exit_loop:
CloseServiceHandle(hService);
close_scm:
CloseServiceHandle(hSCM);
} while ( Lagging );
set_event:
// signal event in case it is open in any other processes
SetEvent(hEvent);
destroy_list:
ptrlist_for_each_stdcall(&list, CloseHandle);
ptrlist_destroy(&list);
if ( Suspending )
NtSuspendProcess(NtCurrentProcess());
close_event:
CloseHandle(hUnloadEvent);
release_mutex:
ReleaseMutex(g_hMainMutex);
CloseHandle(g_hMainMutex);
ReleaseMutex(hMutex);
CloseHandle(hMutex);
}
void CALLBACK RUNDLL32_UnloadW(
@@ -153,7 +266,7 @@ void CALLBACK RUNDLL32_UnloadW(
{
HANDLE hEvent;
hEvent = OpenEventW(EVENT_MODIFY_STATE, FALSE, m_szUnloadEventName);
hEvent = OpenEventW(EVENT_MODIFY_STATE, FALSE, L"Global\\wufuc_UnloadEvent");
if ( hEvent ) {
SetEvent(hEvent);
CloseHandle(hEvent);

View File

@@ -1,209 +0,0 @@
#include "stdafx.h"
#include "servicehelper.h"
#include "registryhelper.h"
LPQUERY_SERVICE_CONFIGW svc_query_config_by_name_alloc(
SC_HANDLE hSCM,
const wchar_t *pServiceName,
LPDWORD pcbBufSize)
{
SC_HANDLE hService;
LPQUERY_SERVICE_CONFIGW result = NULL;
hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_CONFIG);
if ( !hService ) return result;
result = svc_query_config_alloc(hSCM, hService, pcbBufSize);
CloseServiceHandle(hService);
return result;
}
LPQUERY_SERVICE_CONFIGW svc_query_config_alloc(
SC_HANDLE hSCM,
SC_HANDLE hService,
LPDWORD pcbBufSize)
{
DWORD cbBytesNeeded;
LPQUERY_SERVICE_CONFIGW result = NULL;
if ( !QueryServiceConfigW(hService, NULL, 0, &cbBytesNeeded)
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
result = malloc(cbBytesNeeded);
if ( result ) {
if ( QueryServiceConfigW(hService, result, cbBytesNeeded, &cbBytesNeeded) ) {
if ( pcbBufSize )
*pcbBufSize = cbBytesNeeded;
} else {
free(result);
result = NULL;
}
}
}
return result;
}
bool svc_query_process_info_by_name(
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 )
return result;
result = !!QueryServiceStatusEx(hService,
SC_STATUS_PROCESS_INFO,
(LPBYTE)pServiceStatus,
sizeof *pServiceStatus,
&cbBytesNeeded);
CloseServiceHandle(hService);
return result;
}
bool svc_query_group_name(
const LPQUERY_SERVICE_CONFIGW pServiceConfig,
wchar_t **pGroupName,
HLOCAL *hMem)
{
bool result = false;
int NumArgs;
wchar_t **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") ) {
*pGroupName = argv[++i];
*hMem = (HLOCAL)argv;
return true;
}
}
}
LocalFree((HLOCAL)argv);
}
return false;
}
DWORD svc_query_process_id(SC_HANDLE hSCM, SC_HANDLE hService)
{
DWORD result = 0;
SERVICE_STATUS_PROCESS ServiceStatus;
DWORD cbBytesNeeded;
if ( QueryServiceStatusEx(hService,
SC_STATUS_PROCESS_INFO,
(LPBYTE)&ServiceStatus,
sizeof ServiceStatus,
&cbBytesNeeded) ) {
result = ServiceStatus.dwProcessId;
}
return result;
}
DWORD svc_query_process_id_by_name(SC_HANDLE hSCM, const wchar_t *pServiceName)
{
SERVICE_STATUS_PROCESS ServiceStatusProcess;
if ( svc_query_process_info_by_name(hSCM, pServiceName, &ServiceStatusProcess) )
return ServiceStatusProcess.dwProcessId;
return 0;
}
DWORD svc_heuristic_group_process_id(SC_HANDLE hSCM, const wchar_t *pGroupNameSearch)
{
wchar_t *pData;
DWORD result = 0;
DWORD dwProcessId;
DWORD cbBufSize;
LPQUERY_SERVICE_CONFIGW pServiceConfig;
bool success = false;
wchar_t *pGroupName;
HLOCAL hMem;
pData = reg_get_value_alloc(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost",
pGroupNameSearch,
RRF_RT_REG_MULTI_SZ,
NULL,
NULL);
if ( !pData ) return result;
for ( wchar_t *pName = pData; *pName; pName += wcslen(pName) + 1 ) {
dwProcessId = svc_query_process_id_by_name(hSCM, pName);
if ( !dwProcessId ) continue;
pServiceConfig = svc_query_config_by_name_alloc(hSCM, pName, &cbBufSize);
if ( !pServiceConfig ) continue;
if ( pServiceConfig->dwServiceType == SERVICE_WIN32_SHARE_PROCESS
&& svc_query_group_name(pServiceConfig, &pGroupName, &hMem) ) {
success = !_wcsicmp(pGroupNameSearch, pGroupName);
LocalFree(hMem);
}
free(pServiceConfig);
if ( success ) {
result = dwProcessId;
break;
}
}
free(pData);
return result;
}
DWORD svc_heuristic_process_id(SC_HANDLE hSCM, SC_HANDLE hService)
{
DWORD result = 0;
LPQUERY_SERVICE_CONFIGW pServiceConfig;
wchar_t *pGroupName;
HLOCAL hMem;
result = svc_query_process_id(hSCM, hService);
if ( result )
return result;
pServiceConfig = svc_query_config_alloc(hSCM, hService, NULL);
if ( pServiceConfig ) {
switch ( pServiceConfig->dwServiceType ) {
case SERVICE_WIN32_OWN_PROCESS:
// if the service isn't already running there's no
// way to accurately guess the PID when it is set to
// run in its own process. returns 0
break;
case SERVICE_WIN32_SHARE_PROCESS:
// when the service is configured to run in a shared
// process, it is possible to "guess" which svchost.exe
// it will eventually be loaded into by finding other
// services in the same group that are already running.
if ( svc_query_group_name(pServiceConfig, &pGroupName, &hMem) ) {
result = svc_heuristic_group_process_id(hSCM, pGroupName);
LocalFree(hMem);
}
break;
}
free(pServiceConfig);
}
return result;
}
DWORD svc_heuristic_process_id_by_name(SC_HANDLE hSCM, const wchar_t *pServiceName)
{
DWORD result = 0;
SC_HANDLE hService;
hService = OpenServiceW(hSCM, pServiceName, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
result = svc_heuristic_process_id(hSCM, hService);
CloseServiceHandle(hService);
return result;
}

View File

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

View File

@@ -11,15 +11,12 @@
#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 <time.h>
#include <share.h>
#include <strsafe.h>
#include <shellapi.h>
@@ -27,6 +24,10 @@
#include <Psapi.h>
#include <TlHelp32.h>
#include "asprintf.h"
#include "logger.h"
extern IMAGE_DOS_HEADER __ImageBase;
#define PIMAGEBASE ((HMODULE)&__ImageBase)
#define OffsetToPointer(Base, Offset) ((void *)(((uint8_t *)(Base)) + ((ptrdiff_t)(Offset))))
#define PointerToOffset(Base, Pointer) ((ptrdiff_t)(((uint8_t *)(Pointer)) - ((uint8_t *)(Base))))

26
src/wufuc/utf8.c Normal file
View File

@@ -0,0 +1,26 @@
#include "stdafx.h"
#include "utf8.h"
DWORD UTF8WriteFile(HANDLE hFile, LPCWSTR lpWideCharStr)
{
int cchWideChar;
int size;
char *buffer;
DWORD NumberOfBytesWritten = 0;
cchWideChar = lstrlenW(lpWideCharStr);
size = WideCharToMultiByte(CP_UTF8, 0, lpWideCharStr, cchWideChar, NULL, 0, NULL, NULL);
if ( !size )
return 0;
buffer = malloc(size);
if ( !buffer )
return 0;
if ( WideCharToMultiByte(CP_UTF8, 0, lpWideCharStr, cchWideChar, buffer, size, NULL, NULL) )
WriteFile(hFile, buffer, size, &NumberOfBytesWritten, NULL);
free(buffer);
return NumberOfBytesWritten;
}

3
src/wufuc/utf8.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
DWORD UTF8WriteFile(HANDLE hFile, LPCWSTR lpWideCharStr);

View File

@@ -1,33 +0,0 @@
#include "stdafx.h"
#include "versionhelper.h"
int ver_compare_product_version(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wBuild, WORD wRev)
{
if ( HIWORD(pffi->dwProductVersionMS) < wMajor ) return -1;
if ( HIWORD(pffi->dwProductVersionMS) > wMajor ) return 1;
if ( 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 ver_verify_version_info(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
{
DWORDLONG dwlConditionMask = 0;
OSVERSIONINFOEXW osvi = { sizeof osvi };
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;
}

View File

@@ -1,4 +0,0 @@
#pragma once
int ver_compare_product_version(VS_FIXEDFILEINFO *pffi, WORD wMajor, WORD wMinor, WORD wBuild, WORD wRev);
bool ver_verify_version_info(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor);

130
src/wufuc/versioninfo.c Normal file
View File

@@ -0,0 +1,130 @@
#include "stdafx.h"
#include "versioninfo.h"
DWORD GetModuleVersionInfo(HMODULE hModule, LPVOID *lplpData)
{
HRSRC hResInfo;
DWORD result;
HGLOBAL hResData;
LPVOID pRes;
LPVOID lpData;
hResInfo = FindResourceW(hModule,
MAKEINTRESOURCEW(VS_VERSION_INFO),
MAKEINTRESOURCEW(RT_VERSION));
if ( !hResInfo ) return 0;
result = SizeofResource(hModule, hResInfo);
if ( !result ) return 0;
hResData = LoadResource(hModule, hResInfo);
if ( !hResData ) return 0;
pRes = LockResource(hResData);
if ( !pRes ) return 0;
lpData = malloc(result);
if ( !lpData ) return 0;
if ( !memcpy_s(lpData, result, pRes, result) ) {
*lplpData = lpData;
} else {
free(lpData);
return 0;
}
return result;
}
DWORD GetFileVersionInfoExAlloc(DWORD dwFlags, BOOL bPrefetched, LPCWSTR lpwstrFilename, LPVOID *lplpData)
{
DWORD result;
DWORD dwHandle;
LPVOID lpData;
result = GetFileVersionInfoSizeExW(dwFlags,
lpwstrFilename,
&dwHandle);
if ( !result ) return 0;
lpData = malloc(result);
if ( !lpData ) return 0;
if ( GetFileVersionInfoExW(bPrefetched ? (dwFlags | FILE_VER_GET_PREFETCHED) : dwFlags,
lpwstrFilename,
dwHandle,
result,
lpData) ) {
*lplpData = lpData;
} else {
free(lpData);
return 0;
}
return result;
}
UINT VerQueryString(LPCVOID pBlock, LANGANDCODEPAGE LangCodePage, LPCWSTR lpName, LPWSTR *lplpString)
{
LPWSTR pszSubBlock;
LPVOID lpBuffer;
UINT result = 0;
if ( aswprintf(&pszSubBlock,
L"\\StringFileInfo\\%04x%04x\\%ls",
LangCodePage.wLanguage,
LangCodePage.wCodePage,
lpName) == -1 )
return 0;
if ( VerQueryValueW(pBlock, pszSubBlock, &lpBuffer, &result) )
*lplpString = (LPWSTR)lpBuffer;
free(pszSubBlock);
return result;
}
UINT VerQueryTranslations(LPCVOID pBlock, PLANGANDCODEPAGE *lplpTranslate)
{
PLANGANDCODEPAGE lpTranslate;
UINT uLen;
if ( VerQueryValueW(pBlock, L"\\VarFileInfo\\Translation", &(LPVOID)lpTranslate, &uLen) ) {
*lplpTranslate = lpTranslate;
return uLen / (sizeof *lpTranslate);
}
return 0;
}
UINT VerQueryFileInfo(LPCVOID pBlock, VS_FIXEDFILEINFO **lplpffi)
{
VS_FIXEDFILEINFO *lpffi;
UINT result;
if ( VerQueryValueW(pBlock, L"\\", &(LPVOID)lpffi, &result) ) {
*lplpffi = lpffi;
return result;
}
return 0;
}
int vercmp(DWORD dwMS, DWORD dwLS, WORD wMajor, WORD wMinor, WORD wBuild, WORD wRev)
{
WORD w;
w = HIWORD(dwMS);
if ( w < wMajor ) return -1;
if ( w > wMajor ) return 1;
w = LOWORD(dwMS);
if ( w < wMinor ) return -1;
if ( w > wMinor ) return 1;
w = HIWORD(dwLS);
if ( w < wBuild ) return -1;
if ( w > wBuild ) return 1;
w = LOWORD(dwLS);
if ( w < wRev ) return -1;
if ( w > wRev ) return 1;
return 0;
}

19
src/wufuc/versioninfo.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
typedef struct
{
WORD wLanguage;
WORD wCodePage;
} LANGANDCODEPAGE, *PLANGANDCODEPAGE;
DWORD GetModuleVersionInfo(HMODULE hModule, LPVOID *lplpData);
DWORD GetFileVersionInfoExAlloc(DWORD dwFlags, BOOL bPrefetched, LPCWSTR lpwstrFilename, LPVOID *lplpData);
UINT VerQueryString(LPCVOID pBlock, LANGANDCODEPAGE LangCodePage, LPCWSTR lpName, LPWSTR *lplpString);
UINT VerQueryTranslations(LPCVOID pBlock, PLANGANDCODEPAGE *lplpTranslate);
UINT VerQueryFileInfo(LPCVOID pBlock, VS_FIXEDFILEINFO **lplpffi);
int vercmp(DWORD dwMS, DWORD dwLS, WORD wMajor, WORD wMinor, WORD wBuild, WORD wRev);

View File

@@ -1,222 +0,0 @@
#include "stdafx.h"
#include "ptrlist.h"
#include "wufuc.h"
#include "hooks.h"
#include "log.h"
#include "modulehelper.h"
#include "mutexhelper.h"
#include "patternfind.h"
#include "resourcehelper.h"
#include "versionhelper.h"
#include <minhook.h>
HANDLE g_hMainMutex;
static bool close_remote_handle(HANDLE hProcess, HANDLE hObject)
{
bool result = false;
DWORD ExitCode;
HANDLE hThread;
hThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)CloseHandle,
(LPVOID)hObject,
0,
NULL);
if ( hThread ) {
if ( WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0
&& GetExitCodeThread(hThread, &ExitCode) ) {
result = !!ExitCode;
}
CloseHandle(hThread);
}
return result;
}
bool wufuc_inject(DWORD dwProcessId,
LPTHREAD_START_ROUTINE pStartAddress,
ptrlist_t *list)
{
bool result = false;
HANDLE hCrashMutex;
HANDLE hProcess;
HANDLE h;
HANDLE hProceedEvent;
HANDLE p[4];
hCrashMutex = mutex_create_new_fmt(false, L"Global\\wufuc_CrashMutex*%08x", dwProcessId);
if ( !hCrashMutex ) return result;
if ( !ptrlist_add(list, hCrashMutex, dwProcessId) )
goto close_mutex;
hProceedEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
if ( !hProceedEvent ) goto close_mutex;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if ( !hProcess ) goto close_pevent;
h = GetCurrentProcess();
if ( !DuplicateHandle(h, g_hMainMutex, hProcess, &p[0], SYNCHRONIZE, FALSE, 0) )
goto close_process;
if ( !DuplicateHandle(h, ptrlist_at(list, 0, NULL), hProcess, &p[1], SYNCHRONIZE, FALSE, 0) )
goto close_p0;
if ( !DuplicateHandle(h, hCrashMutex, hProcess, &p[2], 0, FALSE, DUPLICATE_SAME_ACCESS) )
goto close_p1;
if ( !DuplicateHandle(h, hProceedEvent, hProcess, &p[3], EVENT_MODIFY_STATE, FALSE, 0) )
goto close_p2;
result = mod_inject_and_begin_thread(hProcess, PIMAGEBASE, pStartAddress, p, sizeof p);
if ( result ) {
// wait for injected thread to signal that it has taken
// ownership of hCrashMutex before proceeding.
result = WaitForSingleObject(hProceedEvent, 5000) != WAIT_TIMEOUT;
} else {
close_remote_handle(hProcess, p[3]);
close_p2:
close_remote_handle(hProcess, p[2]);
close_p1:
close_remote_handle(hProcess, p[1]);
close_p0:
close_remote_handle(hProcess, p[0]);
}
close_process:
CloseHandle(hProcess);
close_pevent:
CloseHandle(hProceedEvent);
if ( !result ) {
close_mutex:
ptrlist_remove(list, hCrashMutex);
CloseHandle(hCrashMutex);
}
if ( result )
log_info(L"Successfully injected into process! (ProcessId=%lu)", dwProcessId);
else
log_warning(L"Failed to inject into process! (ProcessId=%lu)", dwProcessId);
return result;
}
static bool wufuc_get_patch_info(VS_FIXEDFILEINFO *pffi, PATCHINFO *ppi)
{
#ifdef _WIN64
if ( ver_verify_version_info(6, 1, 1) && ver_compare_product_version(pffi, 7, 6, 7601, 23714) != -1
|| ver_verify_version_info(6, 3, 0) && ver_compare_product_version(pffi, 7, 9, 9600, 18621) != -1 ) {
ppi->pattern = "FFF3 4883EC?? 33DB 391D???????? 7508 8B05????????";
ppi->off1 = 0xa;
ppi->off2 = 0x12;
return true;
}
#elif _WIN32
if ( ver_verify_version_info(6, 1, 1)
&& ver_compare_product_version(pffi, 7, 6, 7601, 23714) != -1 ) {
ppi->pattern = "833D????????00 743E E8???????? A3????????";
ppi->off1 = 0x2;
ppi->off2 = 0xf;
return true;
} else if ( ver_verify_version_info(6, 3, 0)
&& ver_compare_product_version(pffi, 7, 9, 9600, 18621) != -1 ) {
ppi->pattern = "8BFF 51 833D????????00 7507 A1????????";
ppi->off1 = 0x5;
ppi->off2 = 0xd;
return true;
}
#endif
return false;
}
static bool wufuc_get_patch_ptrs(const PATCHINFO *ppi, uintptr_t pfn, PBOOL *ppval1, PBOOL *ppval2)
{
#ifdef _WIN64
*ppval1 = (PBOOL)(pfn + ppi->off1 + sizeof(uint32_t) + *(uint32_t *)(pfn + ppi->off1));
*ppval2 = (PBOOL)(pfn + ppi->off2 + sizeof(uint32_t) + *(uint32_t *)(pfn + ppi->off2));
return true;
#elif _WIN32
*ppval1 = (PBOOL)(*(uintptr_t *)(pfn + ppi->off1));
*ppval2 = (PBOOL)(*(uintptr_t *)(pfn + ppi->off2));
return true;
#else
return false;
#endif
}
void wufuc_patch(HMODULE hModule)
{
void *pBlock;
PATCHINFO pi;
size_t count;
PLANGANDCODEPAGE plcp;
wchar_t *pInternalName;
VS_FIXEDFILEINFO *pffi;
MODULEINFO modinfo;
size_t offset;
void *pfn;
DWORD fOldProtect;
PBOOL pval1;
PBOOL pval2;
pBlock = res_get_version_info(hModule);
if ( !pBlock ) return;
plcp = res_query_var_file_info(pBlock, &count);
if ( !plcp ) goto free_pBlock;
for ( size_t i = 0; i < count; i++ ) {
pInternalName = res_query_string_file_info(pBlock, plcp[i], L"InternalName", NULL);
if ( pInternalName && !_wcsicmp(pInternalName, L"wuaueng.dll") )
goto cont_patch;
}
goto free_pBlock;
cont_patch:
pffi = res_query_fixed_file_info(pBlock);
if ( !pffi ) goto free_pBlock;
if ( !wufuc_get_patch_info(pffi, &pi) ) {
log_warning(L"Unsupported Windows Update Agent version: %hu.%hu.%hu.%hu",
HIWORD(pffi->dwProductVersionMS),
LOWORD(pffi->dwProductVersionMS),
HIWORD(pffi->dwProductVersionLS),
LOWORD(pffi->dwProductVersionLS));
goto free_pBlock;
}
log_info(L"Supported Windows Update Agent version: %hu.%hu.%hu.%hu",
HIWORD(pffi->dwProductVersionMS),
LOWORD(pffi->dwProductVersionMS),
HIWORD(pffi->dwProductVersionLS),
LOWORD(pffi->dwProductVersionLS));
if ( !GetModuleInformation(GetCurrentProcess(), hModule, &modinfo, sizeof modinfo) ) {
log_error(L"GetModuleInformation failed! (hModule=%p, GLE=%lu)", hModule, GetLastError());
goto free_pBlock;
}
offset = patternfind(modinfo.lpBaseOfDll, modinfo.SizeOfImage, pi.pattern);
if ( offset == -1 ) {
log_info(L"Couldn't match IsDeviceServiceable function!");
goto free_pBlock;
}
pfn = OffsetToPointer(modinfo.lpBaseOfDll, offset);
log_info(L"Matched %ls!IsDeviceServiceable function! (Offset=%IX, Address=%p)",
PathFindFileNameW(g_pszWUServiceDll), offset, pfn);
if ( wufuc_get_patch_ptrs(&pi, (uintptr_t)pfn, &pval1, &pval2) ) {
if ( *pval1 && VirtualProtect(pval1, sizeof *pval1, PAGE_READWRITE, &fOldProtect) ) {
*pval1 = FALSE;
VirtualProtect(pval1, sizeof *pval1, fOldProtect, &fOldProtect);
log_info(L"Patched variable! (Address=%p)", pval1);
}
if ( !*pval2 && VirtualProtect(pval2, sizeof *pval2, PAGE_READWRITE, &fOldProtect) ) {
*pval2 = TRUE;
VirtualProtect(pval2, sizeof *pval2, fOldProtect, &fOldProtect);
log_info(L"Patched variable! (Address=%p)", pval2);
}
}
free_pBlock:
free(pBlock);
}

View File

@@ -1,16 +0,0 @@
#pragma once
typedef struct _PATCHINFO
{
const char *pattern;
size_t off1;
size_t off2;
} PATCHINFO;
#define SVCHOST_CRASH_THRESHOLD 3
extern HANDLE g_hMainMutex;
bool wufuc_inject(DWORD dwProcessId,
LPTHREAD_START_ROUTINE pStartAddress,
ptrlist_t *list);
void wufuc_patch(HMODULE hModule);

View File

@@ -19,36 +19,27 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="callbacks.h" />
<ClInclude Include="eventhelper.h" />
<ClInclude Include="mutexhelper.h" />
<ClInclude Include="ptrlist.h" />
<ClInclude Include="log.h" />
<ClInclude Include="modulehelper.h" />
<ClInclude Include="registryhelper.h" />
<ClInclude Include="resourcehelper.h" />
<ClInclude Include="servicehelper.h" />
<ClInclude Include="versionhelper.h" />
<ClInclude Include="hooks.h" />
<ClInclude Include="asprintf.h" />
<ClInclude Include="logger.h" />
<ClInclude Include="memory.h" />
<ClInclude Include="modules.h" />
<ClInclude Include="registry.h" />
<ClInclude Include="helpers.h" />
<ClInclude Include="utf8.h" />
<ClInclude Include="versioninfo.h" />
<ClInclude Include="verify.h" />
<ClInclude Include="patternfind.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="wufuc.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="callbacks.c" />
<ClCompile Include="asprintf.c" />
<ClCompile Include="dllmain.c" />
<ClCompile Include="eventhelper.c" />
<ClCompile Include="ptrlist.c" />
<ClCompile Include="modulehelper.c" />
<ClCompile Include="registryhelper.c" />
<ClCompile Include="resourcehelper.c" />
<ClCompile Include="servicehelper.c" />
<ClCompile Include="mutexhelper.c" />
<ClCompile Include="versionhelper.c" />
<ClCompile Include="hooks.c" />
<ClCompile Include="log.c" />
<ClCompile Include="logger.c" />
<ClCompile Include="memory.c" />
<ClCompile Include="modules.c" />
<ClCompile Include="patternfind.c" />
<ClCompile Include="registry.c" />
<ClCompile Include="stdafx.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
@@ -56,7 +47,9 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="rundll32.c" />
<ClCompile Include="wufuc.c" />
<ClCompile Include="helpers.c" />
<ClCompile Include="utf8.c" />
<ClCompile Include="versioninfo.c" />
</ItemGroup>
<ItemGroup>
<None Include="exports.def" />
@@ -125,8 +118,8 @@
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
<GenerateManifest>false</GenerateManifest>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\minhook;$(LibraryPath)</LibraryPath>
<IncludePath>$(SolutionDir)..\inc\phnt;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\x86;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
@@ -134,8 +127,8 @@
<IntDir>$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
<GenerateManifest>false</GenerateManifest>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\minhook;$(LibraryPath)</LibraryPath>
<IncludePath>$(SolutionDir)..\inc\phnt;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\x64;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
@@ -143,8 +136,8 @@
<IntDir>$(ProjectDir)obj\$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
<GenerateManifest>false</GenerateManifest>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\minhook;$(LibraryPath)</LibraryPath>
<IncludePath>$(SolutionDir)..\inc\phnt;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\x86;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
@@ -152,8 +145,8 @@
<IntDir>$(ProjectDir)obj\$(Configuration)\$(PlatformShortName)\</IntDir>
<TargetName>$(ProjectName)$(PlatformArchitecture)</TargetName>
<GenerateManifest>false</GenerateManifest>
<IncludePath>$(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\minhook;$(LibraryPath)</LibraryPath>
<IncludePath>$(SolutionDir)..\inc\phnt;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\lib\x64;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
@@ -172,11 +165,9 @@
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
<EntryPointSymbol>
</EntryPointSymbol>
<AdditionalDependencies>version.lib;Shlwapi.lib;libMinHook.x86.MTd.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
<AdditionalDependencies>version.lib;Shlwapi.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>X86;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<ResourceCompile />
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@@ -195,11 +186,9 @@
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
<EntryPointSymbol>
</EntryPointSymbol>
<AdditionalDependencies>version.lib;Shlwapi.lib;libMinHook.x64.MTd.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
<AdditionalDependencies>version.lib;Shlwapi.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>X64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<ResourceCompile />
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
@@ -226,15 +215,13 @@
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
<EntryPointSymbol>
</EntryPointSymbol>
<AdditionalDependencies>version.lib;Shlwapi.lib;libMinHook.x86.MT.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
<AdditionalDependencies>version.lib;Shlwapi.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
<SetChecksum>true</SetChecksum>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>X86;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<ResourceCompile />
<PostBuildEvent>
<Command>copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup_bat\"
copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup\"</Command>
<Command>copy /Y "$(TargetPath)" "$(SolutionDir)setup_bat\"
copy /Y "$(TargetPath)" "$(SolutionDir)setup_ai\"</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy release binaries to the setup staging directories</Message>
@@ -263,15 +250,13 @@ copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup\"</Command>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
<AdditionalDependencies>version.lib;Shlwapi.lib;libMinHook.x64.MT.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
<AdditionalDependencies>version.lib;Shlwapi.lib;%(AdditionalDependencies);ntdll.lib</AdditionalDependencies>
<SetChecksum>true</SetChecksum>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>X64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
<ResourceCompile />
<PostBuildEvent>
<Command>copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup_bat\"
copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup\"</Command>
<Command>copy /Y "$(TargetPath)" "$(SolutionDir)setup_bat\"
copy /Y "$(TargetPath)" "$(SolutionDir)setup_ai\"</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy release binaries to the setup staging directories</Message>

View File

@@ -15,12 +15,6 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="callbacks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="hooks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -30,47 +24,38 @@
<ClInclude Include="patternfind.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="versionhelper.h">
<ClInclude Include="asprintf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="servicehelper.h">
<ClInclude Include="versioninfo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="registryhelper.h">
<ClInclude Include="verify.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="wufuc.h">
<ClInclude Include="registry.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="modulehelper.h">
<ClInclude Include="modules.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="log.h">
<ClInclude Include="logger.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ptrlist.h">
<ClInclude Include="utf8.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="eventhelper.h">
<ClInclude Include="memory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mutexhelper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resourcehelper.h">
<ClInclude Include="helpers.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="rundll32.c">
<Filter>Source Files</Filter>
</ClCompile>
@@ -80,34 +65,28 @@
<ClCompile Include="patternfind.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="servicehelper.c">
<ClCompile Include="asprintf.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="versionhelper.c">
<ClCompile Include="versioninfo.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="registryhelper.c">
<ClCompile Include="modules.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wufuc.c">
<ClCompile Include="registry.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="log.c">
<ClCompile Include="logger.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="modulehelper.c">
<ClCompile Include="utf8.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ptrlist.c">
<ClCompile Include="memory.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mutexhelper.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="eventhelper.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="resourcehelper.c">
<ClCompile Include="helpers.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
@@ -116,7 +95,7 @@
<Filter>Source Files</Filter>
</None>
<None Include="resource.h">
<Filter>Header Files</Filter>
<Filter>Resource Files</Filter>
</None>
</ItemGroup>
<ItemGroup>