diff --git a/.github/workflows/patcher.yml b/.github/workflows/patcher.yml index 71effe885..60ad19a41 100644 --- a/.github/workflows/patcher.yml +++ b/.github/workflows/patcher.yml @@ -8,25 +8,32 @@ on: branches: [ "v*", "master" ] paths: [ "patcher/**/*" ] +env: + DOTNET_VERSION: 8.x + jobs: build: name: Build Patcher - runs-on: windows-latest + runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - with: - persist-credentials: false - - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@v2 + - name: Setup .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} - name: Build Patcher - run: msbuild.exe patcher\HitmanPatcher.sln -t:Build -p:Configuration=Release -p:Platform=x64 -m + run: | + export DOTNET_NOLOGO=true + export DOTNET_CLI_TELEMETRY_OPTOUT=true + cd patcher + dotnet publish HitmanPatcher/HitmanPatcher.csproj -c Release -p DebugType=none -o Publish/Windows - - name: Upload Patcher Artifacts + - name: Upload patcher-windows uses: actions/upload-artifact@v4 with: name: patcher-windows - path: patcher/bin/x64/Release/PeacockPatcher.exe + path: patcher/Publish/Windows/ILRepack diff --git a/patcher/AOBScanner.cs b/patcher/HitmanPatcher.Core/AOBScanner.cs similarity index 92% rename from patcher/AOBScanner.cs rename to patcher/HitmanPatcher.Core/AOBScanner.cs index bbe396230..3047f8e57 100644 --- a/patcher/AOBScanner.cs +++ b/patcher/HitmanPatcher.Core/AOBScanner.cs @@ -68,6 +68,15 @@ public static bool TryGetHitmanVersionByScanning(Process process, tasks => tasks.Select(task => task.Result) .Where(x => x != null)); + + Task> getDynresEnablePatches = + Task.Factory.ContinueWhenAll(new Task[] + { + findDynresEnable(exeData), + }, + tasks => + tasks.Select(task => task.Result) + .Where(x => x != null)); Task>[] alltasks = @@ -76,11 +85,13 @@ public static bool TryGetHitmanVersionByScanning(Process process, getProtocolPatches, getDynresForceofflinePatches }; // ReSharper disable once CoVariantArrayConversion - Task.WaitAll(alltasks); + Task.WaitAll([..alltasks, getDynresEnablePatches]); bench.Stop(); - Console.WriteLine(bench.Elapsed.ToString()); - +#if DEBUG + Compositions.Logger.log(bench.Elapsed.ToString()); +#endif + // error out if any task does not have exactly 1 result if (alltasks.Any(task => task.Result.Count() != 1)) { @@ -94,7 +105,8 @@ public static bool TryGetHitmanVersionByScanning(Process process, Note("AuthHeader2", getAuthheadPatches.Result.First()[1]); Note("ConfigDomain", getConfigdomainPatches.Result.First()[0]); Note("Protocol", getProtocolPatches.Result.First()[0]); - Note("DynamicResources", getDynresForceofflinePatches.Result.First()[0]); + Note("DynamicResources->ForceOffline", getDynresForceofflinePatches.Result.First()[0]); + Note("DynamicResources->Enable", getDynresEnablePatches.Result.FirstOrDefault()?[0]); #endif result = new HitmanVersion() @@ -104,7 +116,9 @@ public static bool TryGetHitmanVersionByScanning(Process process, configdomain = getConfigdomainPatches.Result.First(), protocol = getProtocolPatches.Result.First(), dynres_noforceoffline = - getDynresForceofflinePatches.Result.First() + getDynresForceofflinePatches.Result.First(), + dynres_enable = + getDynresEnablePatches.Result.FirstOrDefault() ?? [] }; return true; @@ -115,7 +129,14 @@ public static bool TryGetHitmanVersionByScanning(Process process, #if DEBUG private static void Note(string name, Patch patch) { - MainForm.GetInstance().log($"{name}: {patch.offset:X} {BitConverter.ToString(patch.original).Replace("-", string.Empty)} {BitConverter.ToString(patch.patch).Replace("-", string.Empty)}"); + if (patch == null) + { + Compositions.Logger.log($"{name}: n/a"); + + return; + } + + Compositions.Logger.log($"{name}: {patch.offset:X} {BitConverter.ToString(patch.original).Replace("-", string.Empty)} {BitConverter.ToString(patch.patch).Replace("-", string.Empty)}"); } #endif @@ -526,6 +547,31 @@ private static Task findDynresForceoffline(byte[] data) #endregion + #region dynres_enable + + private static Task findDynresEnable(byte[] data) + { + return Task.Factory.ContinueWhenAll(new[] + { + Task.Factory.StartNew(() => findPattern(data, 0x4, "ba502e23f1488d0d")) // 3.210 + .ContinueWith(task => + task.Result.Select(addr => addr + 0x22 + BitConverter.ToInt32(data, addr + 0x1A)).ToArray()), + }, tasks => + { + IEnumerable offsets = + tasks.SelectMany(task => task.Result); + if (offsets.Count() != 1) + return null; + return new[] + { + new Patch(offsets.First(), "01", "00", + MemProtection.PAGE_EXECUTE_READWRITE) + }; + }); + } + + #endregion + private static int[] findPattern(byte[] data, byte alignment, string pattern) { diff --git a/patcher/HitmanPatcher.Core/Compositions.cs b/patcher/HitmanPatcher.Core/Compositions.cs new file mode 100644 index 000000000..aec7e09fa --- /dev/null +++ b/patcher/HitmanPatcher.Core/Compositions.cs @@ -0,0 +1,9 @@ +namespace HitmanPatcher +{ + public static class Compositions + { + public static bool HasAdmin { get; set; } + + public static ILoggingProvider Logger { get; set; } + } +} diff --git a/patcher/HitmanPatcher.Core/HitmanPatcher.Core.csproj b/patcher/HitmanPatcher.Core/HitmanPatcher.Core.csproj new file mode 100644 index 000000000..bfd65fbf1 --- /dev/null +++ b/patcher/HitmanPatcher.Core/HitmanPatcher.Core.csproj @@ -0,0 +1,23 @@ + + + net46 + enable + disable + + x64 + true + + HitmanPatcher + PeacockPatcher.Core + + latest + + + + TRACE;PLATFORM_STEAM;PLATFORM_EPIC;PLATFORM_GOG;PLATFORM_SCARLETT + + + + TRACE;PLATFORM_STEAM;PLATFORM_EPIC + + diff --git a/patcher/HitmanVersion.cs b/patcher/HitmanPatcher.Core/HitmanVersion.cs similarity index 98% rename from patcher/HitmanVersion.cs rename to patcher/HitmanPatcher.Core/HitmanVersion.cs index 24ac7dc77..55b6a4a75 100644 --- a/patcher/HitmanVersion.cs +++ b/patcher/HitmanPatcher.Core/HitmanVersion.cs @@ -34,7 +34,7 @@ public Patch(int offset, string original, string patch, MemProtection defaultPro public class HitmanVersion { - public Patch[] certpin, authheader, configdomain, protocol, dynres_noforceoffline; + public Patch[] certpin, authheader, configdomain, protocol, dynres_noforceoffline, dynres_enable; private static Dictionary timestampMap = new Dictionary(); diff --git a/patcher/MemoryPatcher.cs b/patcher/HitmanPatcher.Core/MemoryPatcher.cs similarity index 97% rename from patcher/MemoryPatcher.cs rename to patcher/HitmanPatcher.Core/MemoryPatcher.cs index 668556b30..94debb928 100644 --- a/patcher/MemoryPatcher.cs +++ b/patcher/HitmanPatcher.Core/MemoryPatcher.cs @@ -69,7 +69,7 @@ public static void PatchAllProcesses(ILoggingProvider logger, Options patchOptio } catch (Win32Exception ex) { - if (ex.NativeErrorCode == 5 && !Program.HasAdmin) + if (ex.NativeErrorCode == 5 && !Compositions.HasAdmin) { logger.log(String.Format("Access denied, try running the patcher as admin.")); process.Dispose(); @@ -184,6 +184,10 @@ public static bool Patch(Process process, Options patchOptions) { patches.AddRange(v.protocol); } + if (patchOptions.EnableDynamicResources) + { + patches.AddRange(v.dynres_enable); + } if (patchOptions.DisableForceOfflineOnFailedDynamicResources) { patches.AddRange(v.dynres_noforceoffline); @@ -275,6 +279,7 @@ public struct Options public bool SetCustomConfigDomain; public string CustomConfigDomain; public bool UseHttp; + public bool EnableDynamicResources; public bool DisableForceOfflineOnFailedDynamicResources; } diff --git a/patcher/PatchDefinitions/v1_12.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v1_12.cs similarity index 100% rename from patcher/PatchDefinitions/v1_12.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v1_12.cs diff --git a/patcher/PatchDefinitions/v1_15.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v1_15.cs similarity index 100% rename from patcher/PatchDefinitions/v1_15.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v1_15.cs diff --git a/patcher/PatchDefinitions/v1_16.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v1_16.cs similarity index 100% rename from patcher/PatchDefinitions/v1_16.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v1_16.cs diff --git a/patcher/PatchDefinitions/v2_13.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v2_13.cs similarity index 100% rename from patcher/PatchDefinitions/v2_13.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v2_13.cs diff --git a/patcher/PatchDefinitions/v2_71.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v2_71.cs similarity index 100% rename from patcher/PatchDefinitions/v2_71.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v2_71.cs diff --git a/patcher/PatchDefinitions/v2_72.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v2_72.cs similarity index 100% rename from patcher/PatchDefinitions/v2_72.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v2_72.cs diff --git a/patcher/PatchDefinitions/v3_10.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v3_10.cs similarity index 100% rename from patcher/PatchDefinitions/v3_10.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v3_10.cs diff --git a/patcher/PatchDefinitions/v3_100.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v3_100.cs similarity index 100% rename from patcher/PatchDefinitions/v3_100.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v3_100.cs diff --git a/patcher/PatchDefinitions/v3_11.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v3_11.cs similarity index 100% rename from patcher/PatchDefinitions/v3_11.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v3_11.cs diff --git a/patcher/PatchDefinitions/v3_110.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v3_110.cs similarity index 100% rename from patcher/PatchDefinitions/v3_110.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v3_110.cs diff --git a/patcher/PatchDefinitions/v3_120.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v3_120.cs similarity index 100% rename from patcher/PatchDefinitions/v3_120.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v3_120.cs diff --git a/patcher/PatchDefinitions/v3_20.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v3_20.cs similarity index 100% rename from patcher/PatchDefinitions/v3_20.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v3_20.cs diff --git a/patcher/PatchDefinitions/v3_30.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v3_30.cs similarity index 100% rename from patcher/PatchDefinitions/v3_30.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v3_30.cs diff --git a/patcher/PatchDefinitions/v3_40.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v3_40.cs similarity index 100% rename from patcher/PatchDefinitions/v3_40.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v3_40.cs diff --git a/patcher/PatchDefinitions/v3_50.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v3_50.cs similarity index 100% rename from patcher/PatchDefinitions/v3_50.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v3_50.cs diff --git a/patcher/PatchDefinitions/v3_70.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/v3_70.cs similarity index 100% rename from patcher/PatchDefinitions/v3_70.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/v3_70.cs diff --git a/patcher/PatchDefinitions/vScpc.cs b/patcher/HitmanPatcher.Core/PatchDefinitions/vScpc.cs similarity index 100% rename from patcher/PatchDefinitions/vScpc.cs rename to patcher/HitmanPatcher.Core/PatchDefinitions/vScpc.cs diff --git a/patcher/Pinvoke.cs b/patcher/HitmanPatcher.Core/Pinvoke.cs similarity index 100% rename from patcher/Pinvoke.cs rename to patcher/HitmanPatcher.Core/Pinvoke.cs diff --git a/patcher/Settings.cs b/patcher/HitmanPatcher.Core/Settings.cs similarity index 98% rename from patcher/Settings.cs rename to patcher/HitmanPatcher.Core/Settings.cs index eb7cabece..aff154ede 100644 --- a/patcher/Settings.cs +++ b/patcher/HitmanPatcher.Core/Settings.cs @@ -22,6 +22,7 @@ public Settings() DisableCertPinning = true, AlwaysSendAuthHeader = true, SetCustomConfigDomain = true, + EnableDynamicResources = true, DisableForceOfflineOnFailedDynamicResources = true, }; darkModeEnabled = false; diff --git a/patcher/HitmanPatcher.csproj b/patcher/HitmanPatcher.csproj deleted file mode 100644 index c2914cd5e..000000000 --- a/patcher/HitmanPatcher.csproj +++ /dev/null @@ -1,177 +0,0 @@ - - - - - - - - Debug - x64 - {0487D44B-B3E1-4A6E-91E0-47016C391A20} - WinExe - Properties - HitmanPatcher - PeacockPatcher - v4.6 - 512 - - True - False - False - False - False - None.None.None.Increment - None.None.None.Increment - 8 - - - - true - bin\x64\Debug\ - DEBUG;TRACE;PLATFORM_STEAM;PLATFORM_EPIC;PLATFORM_GOG;PLATFORM_SCARLETT - full - x64 - prompt - MinimumRecommendedRules.ruleset - true - - - - bin\x64\Release\ - TRACE;PLATFORM_STEAM;PLATFORM_EPIC - true - pdbonly - x64 - prompt - MinimumRecommendedRules.ruleset - true - - - - patcher.ico - - - - - - - - - - - - - - - - - - - True - True - CliLocale.resx - - - Form - - - MainForm.cs - - - - - Form - - - OptionsForm.cs - - - - - - - - - - - - - - - - - - - - - - Form - - - TrayOptionsForm.cs - - - ResXFileCodeGenerator - CliLocale.Designer.cs - - - MainForm.cs - Designer - - - OptionsForm.cs - Designer - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - True - - - TrayOptionsForm.Designer.cs - - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - - - - - - - - - diff --git a/patcher/HitmanPatcher.sln b/patcher/HitmanPatcher.sln index 1d06a1846..1672d72f8 100644 --- a/patcher/HitmanPatcher.sln +++ b/patcher/HitmanPatcher.sln @@ -3,18 +3,24 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HitmanPatcher", "HitmanPatcher.csproj", "{0487D44B-B3E1-4A6E-91E0-47016C391A20}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HitmanPatcher", "HitmanPatcher\HitmanPatcher.csproj", "{0487D44B-B3E1-4A6E-91E0-47016C391A20}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HitmanPatcher.Core", "HitmanPatcher.Core\HitmanPatcher.Core.csproj", "{596AFD4B-5BB1-4FE0-9C2A-12809C186AF4}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 + Release|Any CPU = Release|Any CPU + Debug|Any CPU = Debug|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0487D44B-B3E1-4A6E-91E0-47016C391A20}.Debug|x64.ActiveCfg = Debug|x64 - {0487D44B-B3E1-4A6E-91E0-47016C391A20}.Debug|x64.Build.0 = Debug|x64 - {0487D44B-B3E1-4A6E-91E0-47016C391A20}.Release|x64.ActiveCfg = Release|x64 - {0487D44B-B3E1-4A6E-91E0-47016C391A20}.Release|x64.Build.0 = Release|x64 + {0487D44B-B3E1-4A6E-91E0-47016C391A20}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0487D44B-B3E1-4A6E-91E0-47016C391A20}.Release|Any CPU.Build.0 = Release|Any CPU + {0487D44B-B3E1-4A6E-91E0-47016C391A20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0487D44B-B3E1-4A6E-91E0-47016C391A20}.Debug|Any CPU.Build.0 = Debug|Any CPU + {596AFD4B-5BB1-4FE0-9C2A-12809C186AF4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {596AFD4B-5BB1-4FE0-9C2A-12809C186AF4}.Release|Any CPU.Build.0 = Release|Any CPU + {596AFD4B-5BB1-4FE0-9C2A-12809C186AF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {596AFD4B-5BB1-4FE0-9C2A-12809C186AF4}.Debug|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/patcher/App.config b/patcher/HitmanPatcher/App.config similarity index 94% rename from patcher/App.config rename to patcher/HitmanPatcher/App.config index fcf2f62a0..d572e7498 100644 --- a/patcher/App.config +++ b/patcher/HitmanPatcher/App.config @@ -1,7 +1,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - ..\Novikov_standard.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Novikov_error.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Novikov_success.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - diff --git a/patcher/Properties/Settings.Designer.cs b/patcher/Properties/Settings.Designer.cs deleted file mode 100644 index eeee566bd..000000000 --- a/patcher/Properties/Settings.Designer.cs +++ /dev/null @@ -1,26 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace HitmanPatcher.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - } -} diff --git a/patcher/Properties/Settings.settings b/patcher/Properties/Settings.settings deleted file mode 100644 index 39645652a..000000000 --- a/patcher/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - -