diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.github/README.md b/.github/README.md new file mode 100644 index 0000000..fd1860e --- /dev/null +++ b/.github/README.md @@ -0,0 +1,17 @@ +# Windows-Game-Patches + +[![MSBuild](https://github.com/illusion0001/Windows-Game-Patches/actions/workflows/msbuild.yml/badge.svg?branch=main)](https://github.com/illusion0001/Windows-Game-Patches/actions/workflows/msbuild.yml) + +[Latest Release](/../../../../illusion0001/Windows-Game-Patches/releases/latest) + +# Patches + +- **Bright Memory: Infinite** + - Disable TAA + - Disable Sharpness + +# Credits +- [Lyall](https://github.com/Lyall) for Project Template. +- [Ultimate ASI Loader](https://github.com/ThirteenAG/Ultimate-ASI-Loader) for ASI loading. +- [inipp](https://github.com/mcmtroffaes/inipp) for ini reading. +- [length-disassembler](https://github.com/Nomade040/length-disassembler) for length disassembly. diff --git a/.github/workflows/msbuild.yml b/.github/workflows/msbuild.yml new file mode 100644 index 0000000..baff2a0 --- /dev/null +++ b/.github/workflows/msbuild.yml @@ -0,0 +1,102 @@ +name: MSBuild + +on: + push: + paths-ignore: + - "**/*.md" + - '**/*.txt' + pull_request: + paths-ignore: + - "**/*.md" + - '**/*.txt' + workflow_dispatch: + +concurrency: + group: ${{ github.ref && github.event_name }} + cancel-in-progress: true + +env: + SOLUTION_FILE_PATH: .\Windows-Game-Patches.sln + BUILD_CONFIGURATION: Release + +permissions: + contents: write + +jobs: + build: + runs-on: windows-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: recursive + fetch-depth: 0 + + - name: Add MSBuild to PATH + uses: microsoft/setup-msbuild@main + + - name: Setup environment variables + run: | + $cmdOutput = Split-Path -Path $pwd -Leaf + echo "project_name=$cmdOutput" >> $Env:GITHUB_ENV + echo "commit_ver=1.0.$(git rev-list HEAD --count)" >> $Env:GITHUB_ENV + + - name: Build + run: | + msbuild /m /p:Configuration=${{ env.BUILD_CONFIGURATION }} /p:Platform=x64 ${{ env.SOLUTION_FILE_PATH }} + echo "zip_name=${{ env.project_name }}-${{ env.commit_ver }}" >> $Env:GITHUB_ENV + + - name: Generate Filehash + run: | + $AlgorithmType = "SHA512" + $folderPath = ".\${{ env.BUILD_CONFIGURATION }}\" + $files = Get-ChildItem "$folderPath" -Filter "*.asi" + foreach ($file in $files) { + $hash = Get-FileHash -Algorithm $AlgorithmType -Path $file.FullName | Format-List + $hash | Out-File -Encoding utf8 -FilePath "$folderPath\$($file.BaseName).$AlgorithmType" + $hash | Out-File -Append -Encoding utf8 -FilePath "$folderPath\AllHash.$AlgorithmType" + echo $hash + } + + curl -fLOS https://github.com/ThirteenAG/Ultimate-ASI-Loader/releases/download/x64-latest/version.zip + Expand-Archive -Path version.zip -DestinationPath ".\${{ env.BUILD_CONFIGURATION }}\" + $hash = Get-FileHash -Algorithm $AlgorithmType -Path ".\${{ env.BUILD_CONFIGURATION }}\version.dll" | Format-List + $hash | Out-File -Encoding utf8 -FilePath ".\${{ env.BUILD_CONFIGURATION }}\version.$AlgorithmType" + $hash | Out-File -Append -Encoding utf8 -FilePath ".\${{ env.BUILD_CONFIGURATION }}\AllHash.$AlgorithmType" + echo $hash + $compress = @{ + Path = ".\${{ env.BUILD_CONFIGURATION }}\*.asi", ".\${{ env.BUILD_CONFIGURATION }}\*.dll", ".\${{ env.BUILD_CONFIGURATION }}\*.$AlgorithmType" + CompressionLevel = "NoCompression" + DestinationPath = ".\${{ env.zip_name }}.zip" + } + Compress-Archive @compress + + $hashMarkdown = @' +
+ Plugin Hashes (Click to Expand) + + ```yaml + {0} + ``` + +
+ '@ -f (Get-Content "$folderPath\AllHash.$AlgorithmType" | Out-String) + $hashMarkdown | Out-File -Encoding utf8 -FilePath hash.md + Get-Content hash.md + + - name: Upload Artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ env.zip_name }} + path: | + ${{ env.BUILD_CONFIGURATION }}/*.asi + ${{ env.BUILD_CONFIGURATION }}/*.SHA512 + + - name: Create Release + if: | + github.event_name == 'workflow_dispatch' && + github.repository == 'illusion0001/Windows-Game-Patches' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh release create ${{ env.commit_ver }} ${{ env.ZIP_NAME }}.zip --target ${{ GITHUB.SHA }} -t "${{ env.commit_ver }}" -F hash.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8182614 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# Visual Studio +/**/.vs +/**/Debug +/**/Release diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..81d05ae --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "external/inipp"] + path = external/inipp + url = https://github.com/mcmtroffaes/inipp.git +[submodule "external/length-disassembler"] + path = external/length-disassembler + url = https://github.com/Nomade040/length-disassembler.git diff --git a/BrightMemoryInfinite.NoTAA/BrightMemoryInfinite.NoTAA.sln b/BrightMemoryInfinite.NoTAA/BrightMemoryInfinite.NoTAA.sln new file mode 100644 index 0000000..132ef01 --- /dev/null +++ b/BrightMemoryInfinite.NoTAA/BrightMemoryInfinite.NoTAA.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33424.131 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BrightMemoryInfinite.NoTAA", "BrightMemoryInfinite.NoTAA.vcxproj", "{AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Debug|x64.ActiveCfg = Debug|x64 + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Debug|x64.Build.0 = Debug|x64 + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Debug|x86.ActiveCfg = Debug|Win32 + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Debug|x86.Build.0 = Debug|Win32 + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Release|x64.ActiveCfg = Release|x64 + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Release|x64.Build.0 = Release|x64 + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Release|x86.ActiveCfg = Release|Win32 + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {CDD207AD-54BC-44A9-933A-5DFEDBD97F44} + EndGlobalSection +EndGlobal diff --git a/BrightMemoryInfinite.NoTAA/BrightMemoryInfinite.NoTAA.vcxproj b/BrightMemoryInfinite.NoTAA/BrightMemoryInfinite.NoTAA.vcxproj new file mode 100644 index 0000000..eb84aff --- /dev/null +++ b/BrightMemoryInfinite.NoTAA/BrightMemoryInfinite.NoTAA.vcxproj @@ -0,0 +1,179 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {ab7a871d-2a06-48c6-863f-b8a0fe8f8e0b} + BrightMemoryInfiniteNoTAA + 10.0.22000.0 + + + + DynamicLibrary + true + ClangCL + Unicode + + + DynamicLibrary + false + ClangCL + true + Unicode + + + DynamicLibrary + true + ClangCL + Unicode + + + DynamicLibrary + false + ClangCL + true + Unicode + + + + + + + + + + + + + + + + + + + + + \..\include\;$(IncludePath) + .asi + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + + + \..\include\;$(IncludePath) + .asi + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + + + .asi + + + .asi + + + + Level3 + true + UNICODE;_CRT_SECURE_NO_WARNINGS;_USRDLL + true + Use + pch.h + + + Windows + true + false + + + + + Level3 + true + true + true + UNICODE;_CRT_SECURE_NO_WARNINGS;_USRDLL + true + Use + pch.h + + + Windows + true + true + true + false + + + + + Level3 + true + UNICODE;_CRT_SECURE_NO_WARNINGS;_USRDLL + true + NotUsing + pch.h + ..\include\;..\external\;%(AdditionalIncludeDirectories) + Default + + + + + Windows + true + false + + + + + Level3 + true + true + true + UNICODE;_CRT_SECURE_NO_WARNINGS;_USRDLL + true + NotUsing + pch.h + ..\include\;..\external\;%(AdditionalIncludeDirectories) + Default + + + + + Windows + true + true + true + false + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BrightMemoryInfinite.NoTAA/BrightMemoryInfinite.NoTAA.vcxproj.filters b/BrightMemoryInfinite.NoTAA/BrightMemoryInfinite.NoTAA.vcxproj.filters new file mode 100644 index 0000000..4222594 --- /dev/null +++ b/BrightMemoryInfinite.NoTAA/BrightMemoryInfinite.NoTAA.vcxproj.filters @@ -0,0 +1,32 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/BrightMemoryInfinite.NoTAA/BrightMemoryInfinite.NoTAA.vcxproj.user b/BrightMemoryInfinite.NoTAA/BrightMemoryInfinite.NoTAA.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/BrightMemoryInfinite.NoTAA/BrightMemoryInfinite.NoTAA.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/BrightMemoryInfinite.NoTAA/dllmain.cpp b/BrightMemoryInfinite.NoTAA/dllmain.cpp new file mode 100644 index 0000000..3880ded --- /dev/null +++ b/BrightMemoryInfinite.NoTAA/dllmain.cpp @@ -0,0 +1,161 @@ +#include "stdafx.h" +#include "helper.hpp" + +using namespace std; + +HMODULE baseModule = GetModuleHandle(NULL); + +#define GAME_NAME "BrightMemoryInfinite" +#define xstr(s) str(s) +#define str(s) #s + +inipp::Ini ini; +FILE* fp_log; +time_t sec; + +#define LOG(fmt,...) \ +{ \ + time(&sec); \ + fprintf(fp_log, "%s: %.24s " fmt "\n", __FUNCTION__, ctime(&sec), __VA_ARGS__); \ +} + +// INI Variables +bool bDisableTAA; +bool bDisableSharpness; + +void LoggingInit(void) +{ + const char* log_path = GAME_NAME ".log"; + time(&sec); + fp_log = fopen(log_path, "w"); + if (fp_log != NULL) + { + LOG("Log file opened at %s", log_path); + } + else + { + MessageBox(0, L"Failed to open log file.", (wchar_t*)GAME_NAME, MB_ICONWARNING); + } +} + +void ReadConfig(void) +{ + string sExePath; + string sExeName; + string sGameName; + // Get game name and exe path + LPWSTR exePath = new WCHAR[_MAX_PATH]; + GetModuleFileNameW(baseModule, exePath, _MAX_PATH); + wstring exePathWString(exePath); + sExePath = string(exePathWString.begin(), exePathWString.end()); + wstring wsGameName = Memory::GetVersionProductName(); + sExeName = sExePath.substr(sExePath.find_last_of("/\\") + 1); + sGameName = string(wsGameName.begin(), wsGameName.end()); + + LOG("Game Name: %s", sGameName.c_str()); + LOG("Game Path: %s", sExePath.c_str()); + + // Initialize config + // UE4 games use launchers so config path is relative to launcher + std::string config_path = GAME_NAME ".ini"; + std::ifstream iniFile(config_path); + if (!iniFile) + { + // no ini, lets generate one. + LOG("Failed to load config file."); + string ini_defaults = "[Settings]\n" + str(bDisableTAA)" = true\n" + str(bDisableSharpness)" = true\n"; + std::ofstream iniFile(config_path); + iniFile << ini_defaults; + bDisableTAA = true; + bDisableSharpness = true; + LOG("Created default config file."); + } + else + { + ini.parse(iniFile); + inipp::get_value(ini.sections["Settings"], str(bDisableTAA), bDisableTAA); + inipp::get_value(ini.sections["Settings"], str(bDisableSharpness), bDisableSharpness); + } + + // Log config parse + LOG("%s: %s (%i)", str(bDisableTAA), bDisableTAA ? "true" : "false", bDisableTAA); + LOG("%s: %s (%i)", str(bDisableSharpness), bDisableSharpness ? "true" : "false", bDisableSharpness); +} + +void ShowPatchInfo(uint32_t Patch_Length, size_t Patch_Size, uint64_t Patch_Addr, const char* Patch_Name) +{ + LOG("Patch Name: %s", Patch_Name); + LOG("Hook length: %u bytes", Patch_Length); + LOG("Patch length: %llu bytes", Patch_Size); + LOG("Hook address: 0x%016llx", Patch_Addr); +} + +void DisableTAA(void) +{ + uint8_t* DisableTAAResult = Memory::PatternScan(baseModule, "8B 04 8E 83 F8 ?? 77 ?? 89 83 ?? ?? ?? ??"); + if (DisableTAAResult) + { + const char xor_eax_eax[] = { '\x31', '\xc0', '\x90' }; + uint64_t DisableTAAAddress = ((uintptr_t)DisableTAAResult); + uint32_t DisableTAALength = Memory::GetHookLength((char*)DisableTAAAddress, 14); + Memory::PatchBytes((uintptr_t)DisableTAAAddress, xor_eax_eax, sizeof(xor_eax_eax)); + ShowPatchInfo(DisableTAALength, sizeof(xor_eax_eax), (uintptr_t)DisableTAAAddress, str(bDisableTAA)); + } + else + { + LOG("Pattern scan failed."); + } +} + +void DisableSharpness(void) +{ + uint8_t* DisableSharpnessResult = Memory::PatternScan(baseModule, "F3 44 0F 10 40 04 44 0F 2F C6 73 ?? 45 0F 57 C0 EB ??"); + if (DisableSharpnessResult) + { + const char xor_xmm8[] = { '\x45', '\x0F', '\x57', '\xC0', '\x90', '\x90' }; + uint64_t DisableSharpnessAddress = ((uintptr_t)DisableSharpnessResult); + uint32_t DisableSharpnessLength = Memory::GetHookLength((char*)DisableSharpnessAddress, 18); + Memory::PatchBytes((uintptr_t)DisableSharpnessAddress, xor_xmm8, sizeof(xor_xmm8)); + ShowPatchInfo(DisableSharpnessLength, sizeof(xor_xmm8), (uintptr_t)DisableSharpnessAddress, str(bDisableSharpness)); + } + else + { + LOG("Pattern scan failed."); + } +} + +DWORD __stdcall Main(void*) +{ + bDisableTAA = false; + bDisableSharpness = false; + LoggingInit(); + ReadConfig(); + if (bDisableTAA) + DisableTAA(); + if (bDisableSharpness) + DisableSharpness(); + LOG("Shutting down " str(fp_log) " file handle."); + fclose(fp_log); + return true; +} + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + { + CreateThread(NULL, 0, Main, 0, NULL, 0); + } + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} diff --git a/BrightMemoryInfinite.NoTAA/stdafx.cpp b/BrightMemoryInfinite.NoTAA/stdafx.cpp new file mode 100644 index 0000000..fd4f341 --- /dev/null +++ b/BrightMemoryInfinite.NoTAA/stdafx.cpp @@ -0,0 +1 @@ +#include "stdafx.h" diff --git a/Windows-Game-Patches.sln b/Windows-Game-Patches.sln new file mode 100644 index 0000000..79c4e63 --- /dev/null +++ b/Windows-Game-Patches.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33424.131 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BrightMemoryInfinite.NoTAA", "BrightMemoryInfinite.NoTAA\BrightMemoryInfinite.NoTAA.vcxproj", "{AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Debug|x64.ActiveCfg = Debug|x64 + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Debug|x64.Build.0 = Debug|x64 + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Debug|x86.ActiveCfg = Debug|Win32 + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Debug|x86.Build.0 = Debug|Win32 + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Release|x64.ActiveCfg = Release|x64 + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Release|x64.Build.0 = Release|x64 + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Release|x86.ActiveCfg = Release|Win32 + {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B182B24E-F786-4017-940D-5B814AFEE867} + EndGlobalSection +EndGlobal diff --git a/Windows-Game-Patches.vcxproj b/Windows-Game-Patches.vcxproj new file mode 100644 index 0000000..f52028a --- /dev/null +++ b/Windows-Game-Patches.vcxproj @@ -0,0 +1,134 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {42d74197-0533-448e-ba7a-e60ab40a2e81} + WindowsGamePatches + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + \ No newline at end of file diff --git a/Windows-Game-Patches.vcxproj.filters b/Windows-Game-Patches.vcxproj.filters new file mode 100644 index 0000000..a8a6563 --- /dev/null +++ b/Windows-Game-Patches.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + \ No newline at end of file diff --git a/Windows-Game-Patches.vcxproj.user b/Windows-Game-Patches.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/Windows-Game-Patches.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/external/inipp b/external/inipp new file mode 160000 index 0000000..c61e699 --- /dev/null +++ b/external/inipp @@ -0,0 +1 @@ +Subproject commit c61e699682d3f1091209c2179f1d03f5fc593327 diff --git a/external/length-disassembler b/external/length-disassembler new file mode 160000 index 0000000..e8b3454 --- /dev/null +++ b/external/length-disassembler @@ -0,0 +1 @@ +Subproject commit e8b3454604a09779f7e622279739e73b171a9c67 diff --git a/include/helper.hpp b/include/helper.hpp new file mode 100644 index 0000000..5841491 --- /dev/null +++ b/include/helper.hpp @@ -0,0 +1,242 @@ +#include "stdafx.h" +#include + +using namespace std; + +// TODO: Find out where this came from +namespace Memory +{ + template + void Write(uintptr_t* writeAddress, T value) + { + DWORD oldProtect; + VirtualProtect((LPVOID)(writeAddress), sizeof(T), PAGE_EXECUTE_WRITECOPY, &oldProtect); + *(reinterpret_cast(writeAddress)) = value; + VirtualProtect((LPVOID)(writeAddress), sizeof(T), oldProtect, &oldProtect); + } + + void PatchBytes(uintptr_t address, const char* pattern, unsigned int numBytes) + { + DWORD oldProtect; + VirtualProtect((LPVOID)address, numBytes, PAGE_EXECUTE_READWRITE, &oldProtect); + memcpy((LPVOID)address, pattern, numBytes); + VirtualProtect((LPVOID)address, numBytes, oldProtect, &oldProtect); + } + + void ReadBytes(const uintptr_t address, void* const buffer, const SIZE_T size) + { + memcpy(buffer, reinterpret_cast(address), size); + } + + uintptr_t ReadMultiLevelPointer(uintptr_t base, const std::vector& offsets) + { + MEMORY_BASIC_INFORMATION mbi; + for (auto& offset : offsets) + { + if (!VirtualQuery(reinterpret_cast(base), &mbi, sizeof(MEMORY_BASIC_INFORMATION)) || mbi.Protect & (PAGE_NOACCESS | PAGE_GUARD)) + return 0; + + base = *reinterpret_cast(base) + offset; + } + + return base; + } + + int GetHookLength(char* src, int minLen) + { + int lengthHook = 0; + const int size = 15; + char buffer[size]; + + memcpy(buffer, src, size); + + // must be >= 14 + while (lengthHook <= minLen) + lengthHook += ldisasm(&buffer[lengthHook], true); + + return lengthHook; + } + + bool DetourFunction32(void* src, void* dst, int len) + { + if (len < 5) return false; + + DWORD curProtection; + VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &curProtection); + + memset(src, 0x90, len); + + uintptr_t relativeAddress = ((uintptr_t)dst - (uintptr_t)src) - 5; + + *(BYTE*)src = 0xE9; + *(uintptr_t*)((uintptr_t)src + 1) = relativeAddress; + + DWORD temp; + VirtualProtect(src, len, curProtection, &temp); + + return true; + } + + void* DetourFunction64(void* pSource, void* pDestination, int dwLen) + { + DWORD MinLen = 14; + + if (dwLen < MinLen) return NULL; + + BYTE stub[] = { + 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [$+6] + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ptr + }; + + void* pTrampoline = VirtualAlloc(0, dwLen + sizeof(stub), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + + DWORD dwOld = 0; + VirtualProtect(pSource, dwLen, PAGE_EXECUTE_READWRITE, &dwOld); + + DWORD64 retto = (DWORD64)pSource + dwLen; + + // trampoline + memcpy(stub + 6, &retto, 8); + memcpy((void*)((DWORD_PTR)pTrampoline), pSource, dwLen); + memcpy((void*)((DWORD_PTR)pTrampoline + dwLen), stub, sizeof(stub)); + + // orig + memcpy(stub + 6, &pDestination, 8); + memcpy(pSource, stub, sizeof(stub)); + + for (int i = MinLen; i < dwLen; i++) + { + *(BYTE*)((DWORD_PTR)pSource + i) = 0x90; + } + + VirtualProtect(pSource, dwLen, dwOld, &dwOld); + return (void*)((DWORD_PTR)pTrampoline); + } + + static HMODULE GetThisDllHandle() + { + MEMORY_BASIC_INFORMATION info; + size_t len = VirtualQueryEx(GetCurrentProcess(), (void*)GetThisDllHandle, &info, sizeof(info)); + assert(len == sizeof(info)); + return len ? (HMODULE)info.AllocationBase : NULL; + } + + // CSGOSimple's pattern scan + // https://github.com/OneshotGH/CSGOSimple-master/blob/master/CSGOSimple/helpers/utils.cpp + std::uint8_t* PatternScan(void* module, const char* signature) + { + static auto pattern_to_byte = [](const char* pattern) { + auto bytes = std::vector{}; + auto start = const_cast(pattern); + auto end = const_cast(pattern) + strlen(pattern); + + for (auto current = start; current < end; ++current) { + if (*current == '?') { + ++current; + if (*current == '?') + ++current; + bytes.push_back(-1); + } + else { + bytes.push_back(strtoul(current, ¤t, 16)); + } + } + return bytes; + }; + + auto dosHeader = (PIMAGE_DOS_HEADER)module; + auto ntHeaders = (PIMAGE_NT_HEADERS)((std::uint8_t*)module + dosHeader->e_lfanew); + + auto sizeOfImage = ntHeaders->OptionalHeader.SizeOfImage; + auto patternBytes = pattern_to_byte(signature); + auto scanBytes = reinterpret_cast(module); + + auto s = patternBytes.size(); + auto d = patternBytes.data(); + + for (auto i = 0ul; i < sizeOfImage - s; ++i) { + bool found = true; + for (auto j = 0ul; j < s; ++j) { + if (scanBytes[i + j] != d[j] && d[j] != -1) { + found = false; + break; + } + } + if (found) { + return &scanBytes[i]; + } + } + return nullptr; + } + + std::string GetVersionString() + { + auto hInst = GetModuleHandle(NULL); + auto hResInfo = FindResourceW(hInst, MAKEINTRESOURCE(1), RT_VERSION); + if (!hResInfo) return {}; + auto dwSize = SizeofResource(hInst, hResInfo); + if (!dwSize) return {}; + auto hResData = LoadResource(hInst, hResInfo); + char* pRes = static_cast(LockResource(hResData)); + if (!pRes) return {}; + + std::vector ResCopy(pRes, pRes + dwSize); + + VS_FIXEDFILEINFO* pvFileInfo; + UINT uiFileInfoLen; + + if (!VerQueryValueA(ResCopy.data(), "\\", reinterpret_cast(&pvFileInfo), &uiFileInfoLen)) + return "(unknown)"; + + char buf[25]; + int len = sprintf(buf, "%hu.%hu.%hu.%hu", + HIWORD(pvFileInfo->dwFileVersionMS), + LOWORD(pvFileInfo->dwFileVersionMS), + HIWORD(pvFileInfo->dwFileVersionLS), + LOWORD(pvFileInfo->dwFileVersionLS) + ); + + return std::string(buf, len); + } + + vector string_to_ints(const string& s, char delimiter) { + vector tokens; + string token; + istringstream tokenStream(s); + while (getline(tokenStream, token, delimiter)) { + tokens.push_back(stoi(token)); + } + return tokens; + } + + + std::wstring GetVersionProductName() + { + struct LANGCODEPAGE { + WORD wLang; + WORD wCode; + } *lpTranslate; + + UINT cbTranslate; + + HMODULE baseModule = GetModuleHandle(NULL); + + auto exePath = new WCHAR[_MAX_PATH]; + GetModuleFileName(baseModule, exePath, _MAX_PATH); + auto size = GetFileVersionInfoSize(exePath, NULL); + std::vector buffer(size); + GetFileVersionInfo(exePath, NULL, size, buffer.data()); + VerQueryValue(buffer.data(), L"VarFileInfo\\Translation", (LPVOID*)&lpTranslate, &cbTranslate); + + if (cbTranslate < sizeof(LANGCODEPAGE)) { + return L""; + } + + wchar_t query[512]; + _snwprintf(query, sizeof(query), L"\\StringFileInfo\\%04x%04x\\ProductName", lpTranslate[0].wLang, lpTranslate[0].wCode); + wchar_t const* p; + UINT n_chars; + VerQueryValue(buffer.data(), query, (LPVOID*)&p, &n_chars); + return std::wstring(p, p + n_chars); + } +} diff --git a/include/stdafx.h b/include/stdafx.h new file mode 100644 index 0000000..5fbfdb9 --- /dev/null +++ b/include/stdafx.h @@ -0,0 +1,19 @@ +#pragma once +#pragma comment(lib,"Version.lib") + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inipp/inipp/inipp.h" +#include "length-disassembler/headerOnly/ldisasm.h"