diff --git a/FAQ.md b/FAQ.md index 6c1d0cc..5d7c703 100644 --- a/FAQ.md +++ b/FAQ.md @@ -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: diff --git a/README.md b/README.md index 93cda4c..96be7b5 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/appveyor.yml b/appveyor.yml index e4587c4..fc92120 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -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: diff --git a/inc/minhook/minhook.LICENSE.txt b/inc/minhook/minhook.LICENSE.txt deleted file mode 100644 index 74dea27..0000000 --- a/inc/minhook/minhook.LICENSE.txt +++ /dev/null @@ -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. diff --git a/inc/minhook/minhook.h b/inc/minhook/minhook.h deleted file mode 100644 index 9f62e33..0000000 --- a/inc/minhook/minhook.h +++ /dev/null @@ -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 - diff --git a/lib/minhook/libMinHook.x64.MT.lib b/lib/minhook/libMinHook.x64.MT.lib deleted file mode 100644 index 9bed8ad..0000000 Binary files a/lib/minhook/libMinHook.x64.MT.lib and /dev/null differ diff --git a/lib/minhook/libMinHook.x64.MTd.lib b/lib/minhook/libMinHook.x64.MTd.lib deleted file mode 100644 index 7ce78df..0000000 Binary files a/lib/minhook/libMinHook.x64.MTd.lib and /dev/null differ diff --git a/lib/minhook/libMinHook.x86.MT.lib b/lib/minhook/libMinHook.x86.MT.lib deleted file mode 100644 index 8a9d7f3..0000000 Binary files a/lib/minhook/libMinHook.x86.MT.lib and /dev/null differ diff --git a/lib/minhook/libMinHook.x86.MTd.lib b/lib/minhook/libMinHook.x86.MTd.lib deleted file mode 100644 index 36c32ba..0000000 Binary files a/lib/minhook/libMinHook.x86.MTd.lib and /dev/null differ diff --git a/lib/minhook/minhook.LICENSE.txt b/lib/minhook/minhook.LICENSE.txt deleted file mode 100644 index 74dea27..0000000 --- a/lib/minhook/minhook.LICENSE.txt +++ /dev/null @@ -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. diff --git a/src/AdvancedInstallerHelper/AdvancedInstallerHelper.vcxproj b/src/AdvancedInstallerHelper/AdvancedInstallerHelper.vcxproj index b49d9e0..31be887 100644 --- a/src/AdvancedInstallerHelper/AdvancedInstallerHelper.vcxproj +++ b/src/AdvancedInstallerHelper/AdvancedInstallerHelper.vcxproj @@ -46,6 +46,8 @@ true false + $(ProjectDir)bin\$(Configuration)\$(PlatformShortName)\ + $(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\ false @@ -93,7 +95,7 @@ exports.def - copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup\" + copy /Y "$(TargetPath)" "$(SolutionDir)setup_ai\" Copy release binaries to the setup staging directory diff --git a/src/wufuc_setup/.gitignore b/src/setup_ai/.gitignore similarity index 100% rename from src/wufuc_setup/.gitignore rename to src/setup_ai/.gitignore diff --git a/src/wufuc_setup/LICENSE.rtf b/src/setup_ai/LICENSE.rtf similarity index 100% rename from src/wufuc_setup/LICENSE.rtf rename to src/setup_ai/LICENSE.rtf diff --git a/src/wufuc_setup/wufuc_setup.aip b/src/setup_ai/wufuc_setup.aip similarity index 87% rename from src/wufuc_setup/wufuc_setup.aip rename to src/setup_ai/wufuc_setup.aip index 54783b6..efa6a50 100644 --- a/src/wufuc_setup/wufuc_setup.aip +++ b/src/setup_ai/wufuc_setup.aip @@ -5,10 +5,7 @@ - - - @@ -21,10 +18,10 @@ - + - + @@ -43,36 +40,30 @@ - - - + - - - - + - - + @@ -80,10 +71,6 @@ - - - - @@ -128,11 +115,6 @@ - - - - - @@ -143,7 +125,6 @@ - @@ -187,14 +168,8 @@ - - - - - - @@ -211,7 +186,6 @@ - @@ -235,24 +209,26 @@ - - + + - - - + + + - - + + + + @@ -277,12 +253,8 @@ - - - - @@ -307,13 +279,9 @@ - - - - - + diff --git a/src/wufuc_setup_bat/.gitignore b/src/setup_bat/.gitignore similarity index 100% rename from src/wufuc_setup_bat/.gitignore rename to src/setup_bat/.gitignore diff --git a/src/wufuc_setup_bat/COPYING.txt b/src/setup_bat/COPYING.txt similarity index 100% rename from src/wufuc_setup_bat/COPYING.txt rename to src/setup_bat/COPYING.txt diff --git a/src/setup_bat/Help and Support/Donate.url b/src/setup_bat/Help and Support/Donate.url new file mode 100644 index 0000000..2df8855 --- /dev/null +++ b/src/setup_bat/Help and Support/Donate.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +URL=https://github.com/zeffy/wufuc/blob/master/DONATE.md +IDList= diff --git a/src/setup_bat/Help and Support/Latest release.url b/src/setup_bat/Help and Support/Latest release.url new file mode 100644 index 0000000..c33e468 --- /dev/null +++ b/src/setup_bat/Help and Support/Latest release.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +URL=https://github.com/zeffy/wufuc/releases/latest +IDList= diff --git a/src/wufuc_setup_bat/Troubleshooting/Restore_wuauserv.reg b/src/setup_bat/Help and Support/Restore_wuauserv.reg similarity index 79% rename from src/wufuc_setup_bat/Troubleshooting/Restore_wuauserv.reg rename to src/setup_bat/Help and Support/Restore_wuauserv.reg index 4a2cca4..eb1c973 100644 Binary files a/src/wufuc_setup_bat/Troubleshooting/Restore_wuauserv.reg and b/src/setup_bat/Help and Support/Restore_wuauserv.reg differ diff --git a/src/setup_bat/Help and Support/wufuc on GitHub.url b/src/setup_bat/Help and Support/wufuc on GitHub.url new file mode 100644 index 0000000..65a1ec9 --- /dev/null +++ b/src/setup_bat/Help and Support/wufuc on GitHub.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +URL=https://github.com/zeffy/wufuc +IDList= diff --git a/src/wufuc_setup_bat/install_wufuc.bat b/src/setup_bat/install_wufuc.bat similarity index 100% rename from src/wufuc_setup_bat/install_wufuc.bat rename to src/setup_bat/install_wufuc.bat diff --git a/src/wufuc_setup_bat/uninstall_wufuc.bat b/src/setup_bat/uninstall_wufuc.bat similarity index 100% rename from src/wufuc_setup_bat/uninstall_wufuc.bat rename to src/setup_bat/uninstall_wufuc.bat diff --git a/src/wufuc_setup_bat/wufuc_ScheduledTask.xml b/src/setup_bat/wufuc_ScheduledTask.xml similarity index 100% rename from src/wufuc_setup_bat/wufuc_ScheduledTask.xml rename to src/setup_bat/wufuc_ScheduledTask.xml diff --git a/src/wufuc.sln b/src/wufuc.sln index 9c68b81..47a1e3c 100644 --- a/src/wufuc.sln +++ b/src/wufuc.sln @@ -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}" diff --git a/src/wufuc/asprintf.c b/src/wufuc/asprintf.c new file mode 100644 index 0000000..9d379c9 --- /dev/null +++ b/src/wufuc/asprintf.c @@ -0,0 +1,121 @@ +#include "stdafx.h" +#include "asprintf.h" +#include + +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; +} diff --git a/src/wufuc/asprintf.h b/src/wufuc/asprintf.h new file mode 100644 index 0000000..aee31d5 --- /dev/null +++ b/src/wufuc/asprintf.h @@ -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); diff --git a/src/wufuc/callbacks.c b/src/wufuc/callbacks.c deleted file mode 100644 index 0230edc..0000000 --- a/src/wufuc/callbacks.c +++ /dev/null @@ -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 -#include - -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); -} - diff --git a/src/wufuc/callbacks.h b/src/wufuc/callbacks.h deleted file mode 100644 index 973f943..0000000 --- a/src/wufuc/callbacks.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -VOID CALLBACK service_notify_callback(PSERVICE_NOTIFYW pNotifyBuffer); -DWORD WINAPI thread_start_callback(HANDLE *pParam); diff --git a/src/wufuc/dllmain.c b/src/wufuc/dllmain.c index 710c094..141b3a0 100644 --- a/src/wufuc/dllmain.c +++ b/src/wufuc/dllmain.c @@ -1,7 +1,4 @@ #include "stdafx.h" -#include "log.h" - -#include 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; diff --git a/src/wufuc/eventhelper.c b/src/wufuc/eventhelper.c deleted file mode 100644 index 2c35460..0000000 --- a/src/wufuc/eventhelper.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "stdafx.h" -#include "eventhelper.h" - -#include - -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; -} diff --git a/src/wufuc/eventhelper.h b/src/wufuc/eventhelper.h deleted file mode 100644 index da7fbf8..0000000 --- a/src/wufuc/eventhelper.h +++ /dev/null @@ -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); diff --git a/src/wufuc/helpers.c b/src/wufuc/helpers.c new file mode 100644 index 0000000..a464776 --- /dev/null +++ b/src/wufuc/helpers.c @@ -0,0 +1,54 @@ +#include "stdafx.h" +#include "helpers.h" +#include + +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); +} diff --git a/src/wufuc/helpers.h b/src/wufuc/helpers.h new file mode 100644 index 0000000..21ec83a --- /dev/null +++ b/src/wufuc/helpers.h @@ -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); diff --git a/src/wufuc/hooks.c b/src/wufuc/hooks.c deleted file mode 100644 index b036b35..0000000 --- a/src/wufuc/hooks.c +++ /dev/null @@ -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", ¤t, &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; -} diff --git a/src/wufuc/hooks.h b/src/wufuc/hooks.h deleted file mode 100644 index 7161e30..0000000 --- a/src/wufuc/hooks.h +++ /dev/null @@ -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); diff --git a/src/wufuc/log.c b/src/wufuc/log.c deleted file mode 100644 index b397702..0000000 --- a/src/wufuc/log.c +++ /dev/null @@ -1,162 +0,0 @@ -#include "stdafx.h" -#include "log.h" - -#include - -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); -} diff --git a/src/wufuc/log.h b/src/wufuc/log.h deleted file mode 100644 index f2f54c1..0000000 --- a/src/wufuc/log.h +++ /dev/null @@ -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__) diff --git a/src/wufuc/logger.c b/src/wufuc/logger.c new file mode 100644 index 0000000..475550e --- /dev/null +++ b/src/wufuc/logger.c @@ -0,0 +1,99 @@ +#include "stdafx.h" +#include "logger.h" +#include "utf8.h" +#include + +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); +} diff --git a/src/wufuc/logger.h b/src/wufuc/logger.h new file mode 100644 index 0000000..6c83297 --- /dev/null +++ b/src/wufuc/logger.h @@ -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()) diff --git a/src/wufuc/memory.c b/src/wufuc/memory.c new file mode 100644 index 0000000..2e69090 --- /dev/null +++ b/src/wufuc/memory.c @@ -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); +} \ No newline at end of file diff --git a/src/wufuc/memory.h b/src/wufuc/memory.h new file mode 100644 index 0000000..4065250 --- /dev/null +++ b/src/wufuc/memory.h @@ -0,0 +1,3 @@ +#pragma once + +BOOL WriteProcessMemoryBOOL(HANDLE hProcess, LPBOOL lpBaseAddress, BOOL bValue); diff --git a/src/wufuc/modulehelper.c b/src/wufuc/modulehelper.c deleted file mode 100644 index c48df35..0000000 --- a/src/wufuc/modulehelper.c +++ /dev/null @@ -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; -} diff --git a/src/wufuc/modulehelper.h b/src/wufuc/modulehelper.h deleted file mode 100644 index 2e88a78..0000000 --- a/src/wufuc/modulehelper.h +++ /dev/null @@ -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); diff --git a/src/wufuc/modules.c b/src/wufuc/modules.c new file mode 100644 index 0000000..de97d31 --- /dev/null +++ b/src/wufuc/modules.c @@ -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; +} diff --git a/src/wufuc/modules.h b/src/wufuc/modules.h new file mode 100644 index 0000000..ff6e252 --- /dev/null +++ b/src/wufuc/modules.h @@ -0,0 +1,3 @@ +#pragma once + +HMODULE Toolhelp32GetModuleHandle(DWORD th32ProcessID, LPCWSTR lpModuleName); diff --git a/src/wufuc/mutexhelper.c b/src/wufuc/mutexhelper.c deleted file mode 100644 index 6b68b76..0000000 --- a/src/wufuc/mutexhelper.c +++ /dev/null @@ -1,41 +0,0 @@ -#include "stdafx.h" -#include "mutexhelper.h" - -#include - -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; -} diff --git a/src/wufuc/mutexhelper.h b/src/wufuc/mutexhelper.h deleted file mode 100644 index 0ca26d4..0000000 --- a/src/wufuc/mutexhelper.h +++ /dev/null @@ -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, ...); diff --git a/src/wufuc/ptrlist.c b/src/wufuc/ptrlist.c deleted file mode 100644 index 09bb85a..0000000 --- a/src/wufuc/ptrlist.c +++ /dev/null @@ -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); -} diff --git a/src/wufuc/ptrlist.h b/src/wufuc/ptrlist.h deleted file mode 100644 index e14034c..0000000 --- a/src/wufuc/ptrlist.h +++ /dev/null @@ -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 *)); diff --git a/src/wufuc/registry.c b/src/wufuc/registry.c new file mode 100644 index 0000000..8113b0a --- /dev/null +++ b/src/wufuc/registry.c @@ -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; +} diff --git a/src/wufuc/registry.h b/src/wufuc/registry.h new file mode 100644 index 0000000..b2a4075 --- /dev/null +++ b/src/wufuc/registry.h @@ -0,0 +1,3 @@ +#pragma once + +DWORD RegGetValueAlloc(PVOID *ppvData, HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpValueName, DWORD dwFlags, LPDWORD pdwType); diff --git a/src/wufuc/registryhelper.c b/src/wufuc/registryhelper.c deleted file mode 100644 index 9975c18..0000000 --- a/src/wufuc/registryhelper.c +++ /dev/null @@ -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; -} diff --git a/src/wufuc/registryhelper.h b/src/wufuc/registryhelper.h deleted file mode 100644 index b452053..0000000 --- a/src/wufuc/registryhelper.h +++ /dev/null @@ -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); diff --git a/src/wufuc/resource.h b/src/wufuc/resource.h index a8ce4af..f161183 100644 --- a/src/wufuc/resource.h +++ b/src/wufuc/resource.h @@ -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 diff --git a/src/wufuc/resource.rc b/src/wufuc/resource.rc index 3591d7c..172a828 100644 Binary files a/src/wufuc/resource.rc and b/src/wufuc/resource.rc differ diff --git a/src/wufuc/resourcehelper.c b/src/wufuc/resourcehelper.c deleted file mode 100644 index 537b733..0000000 --- a/src/wufuc/resourcehelper.c +++ /dev/null @@ -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; -} diff --git a/src/wufuc/resourcehelper.h b/src/wufuc/resourcehelper.h deleted file mode 100644 index 8710339..0000000 --- a/src/wufuc/resourcehelper.h +++ /dev/null @@ -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); diff --git a/src/wufuc/rundll32.c b/src/wufuc/rundll32.c index ebd7596..cf1c646 100644 --- a/src/wufuc/rundll32.c +++ b/src/wufuc/rundll32.c @@ -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); diff --git a/src/wufuc/servicehelper.c b/src/wufuc/servicehelper.c deleted file mode 100644 index 0e94113..0000000 --- a/src/wufuc/servicehelper.c +++ /dev/null @@ -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; - -} diff --git a/src/wufuc/servicehelper.h b/src/wufuc/servicehelper.h deleted file mode 100644 index 7342705..0000000 --- a/src/wufuc/servicehelper.h +++ /dev/null @@ -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); diff --git a/src/wufuc/stdafx.h b/src/wufuc/stdafx.h index 4052852..8ae9b6f 100644 --- a/src/wufuc/stdafx.h +++ b/src/wufuc/stdafx.h @@ -11,15 +11,12 @@ #include #include - - // TODO: reference additional headers your program requires here #include #include #include #include #include -#include #include #include @@ -27,6 +24,10 @@ #include #include +#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)))) diff --git a/src/wufuc/utf8.c b/src/wufuc/utf8.c new file mode 100644 index 0000000..26632c1 --- /dev/null +++ b/src/wufuc/utf8.c @@ -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; +} diff --git a/src/wufuc/utf8.h b/src/wufuc/utf8.h new file mode 100644 index 0000000..415f47f --- /dev/null +++ b/src/wufuc/utf8.h @@ -0,0 +1,3 @@ +#pragma once + +DWORD UTF8WriteFile(HANDLE hFile, LPCWSTR lpWideCharStr); \ No newline at end of file diff --git a/src/wufuc/versionhelper.c b/src/wufuc/versionhelper.c deleted file mode 100644 index 86fe01e..0000000 --- a/src/wufuc/versionhelper.c +++ /dev/null @@ -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; -} diff --git a/src/wufuc/versionhelper.h b/src/wufuc/versionhelper.h deleted file mode 100644 index 11b1226..0000000 --- a/src/wufuc/versionhelper.h +++ /dev/null @@ -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); diff --git a/src/wufuc/versioninfo.c b/src/wufuc/versioninfo.c new file mode 100644 index 0000000..cda1cc5 --- /dev/null +++ b/src/wufuc/versioninfo.c @@ -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; +} diff --git a/src/wufuc/versioninfo.h b/src/wufuc/versioninfo.h new file mode 100644 index 0000000..b8105bf --- /dev/null +++ b/src/wufuc/versioninfo.h @@ -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); diff --git a/src/wufuc/wufuc.c b/src/wufuc/wufuc.c deleted file mode 100644 index c28d3ab..0000000 --- a/src/wufuc/wufuc.c +++ /dev/null @@ -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 - -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); -} diff --git a/src/wufuc/wufuc.h b/src/wufuc/wufuc.h deleted file mode 100644 index 8c51863..0000000 --- a/src/wufuc/wufuc.h +++ /dev/null @@ -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); diff --git a/src/wufuc/wufuc.vcxproj b/src/wufuc/wufuc.vcxproj index 0b0095e..0327c27 100644 --- a/src/wufuc/wufuc.vcxproj +++ b/src/wufuc/wufuc.vcxproj @@ -19,36 +19,27 @@ - - - - - - - - - - - + + + + + + + + + - - + - - - - - - - - - - + + + + Create Create @@ -56,7 +47,9 @@ Create - + + + @@ -125,8 +118,8 @@ $(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\ $(ProjectName)$(PlatformArchitecture) false - $(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath) - $(SolutionDir)..\lib\minhook;$(LibraryPath) + $(SolutionDir)..\inc\phnt;$(IncludePath) + $(SolutionDir)..\lib\x86;$(LibraryPath) true @@ -134,8 +127,8 @@ $(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(PlatformShortName)\ $(ProjectName)$(PlatformArchitecture) false - $(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath) - $(SolutionDir)..\lib\minhook;$(LibraryPath) + $(SolutionDir)..\inc\phnt;$(IncludePath) + $(SolutionDir)..\lib\x64;$(LibraryPath) false @@ -143,8 +136,8 @@ $(ProjectDir)obj\$(Configuration)\$(PlatformShortName)\ $(ProjectName)$(PlatformArchitecture) false - $(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath) - $(SolutionDir)..\lib\minhook;$(LibraryPath) + $(SolutionDir)..\inc\phnt;$(IncludePath) + $(SolutionDir)..\lib\x86;$(LibraryPath) false @@ -152,8 +145,8 @@ $(ProjectDir)obj\$(Configuration)\$(PlatformShortName)\ $(ProjectName)$(PlatformArchitecture) false - $(SolutionDir)..\inc\phnt;$(SolutionDir)..\inc\minhook;$(IncludePath) - $(SolutionDir)..\lib\minhook;$(LibraryPath) + $(SolutionDir)..\inc\phnt;$(IncludePath) + $(SolutionDir)..\lib\x64;$(LibraryPath) @@ -172,11 +165,9 @@ exports.def - version.lib;Shlwapi.lib;libMinHook.x86.MTd.lib;%(AdditionalDependencies);ntdll.lib + version.lib;Shlwapi.lib;%(AdditionalDependencies);ntdll.lib - - X86;%(PreprocessorDefinitions) - + @@ -195,11 +186,9 @@ exports.def - version.lib;Shlwapi.lib;libMinHook.x64.MTd.lib;%(AdditionalDependencies);ntdll.lib + version.lib;Shlwapi.lib;%(AdditionalDependencies);ntdll.lib - - X64;%(PreprocessorDefinitions) - + @@ -226,15 +215,13 @@ exports.def - version.lib;Shlwapi.lib;libMinHook.x86.MT.lib;%(AdditionalDependencies);ntdll.lib + version.lib;Shlwapi.lib;%(AdditionalDependencies);ntdll.lib true - - X86;%(PreprocessorDefinitions) - + - copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup_bat\" -copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup\" + copy /Y "$(TargetPath)" "$(SolutionDir)setup_bat\" +copy /Y "$(TargetPath)" "$(SolutionDir)setup_ai\" Copy release binaries to the setup staging directories @@ -263,15 +250,13 @@ copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup\" true false exports.def - version.lib;Shlwapi.lib;libMinHook.x64.MT.lib;%(AdditionalDependencies);ntdll.lib + version.lib;Shlwapi.lib;%(AdditionalDependencies);ntdll.lib true - - X64;%(PreprocessorDefinitions) - + - copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup_bat\" -copy /Y "$(TargetPath)" "$(SolutionDir)wufuc_setup\" + copy /Y "$(TargetPath)" "$(SolutionDir)setup_bat\" +copy /Y "$(TargetPath)" "$(SolutionDir)setup_ai\" Copy release binaries to the setup staging directories diff --git a/src/wufuc/wufuc.vcxproj.filters b/src/wufuc/wufuc.vcxproj.filters index 6e347bc..c468ff1 100644 --- a/src/wufuc/wufuc.vcxproj.filters +++ b/src/wufuc/wufuc.vcxproj.filters @@ -15,12 +15,6 @@ - - Header Files - - - Header Files - Header Files @@ -30,47 +24,38 @@ Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - - Header Files - - + Header Files - - Source Files - Source Files - - Source Files - Source Files @@ -80,34 +65,28 @@ Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - - Source Files - - - Source Files - - + Source Files @@ -116,7 +95,7 @@ Source Files - Header Files + Resource Files