mirror of
https://github.com/k1tbyte/Wand-Enhancer.git
synced 2026-08-28 17:01:04 +00:00
feat: add support for DevTools hotkey, fix patching logic
This commit is contained in:
+4
-1
@@ -134,4 +134,7 @@ dist
|
||||
./WeModPatcher/bin/
|
||||
./AsarSharp/obj/
|
||||
./AsarSharp/bin/
|
||||
.idea
|
||||
.idea
|
||||
packages
|
||||
*/bin/
|
||||
*/obj/
|
||||
@@ -16,35 +16,8 @@ namespace WeModPatcher.Core
|
||||
{
|
||||
public class Patcher
|
||||
{
|
||||
private class PatchEntry
|
||||
{
|
||||
public Regex Target { get; set; }
|
||||
public string Patch { get; set; }
|
||||
public bool Applied { get; set; }
|
||||
public bool SingleMatch { get; set; } = true;
|
||||
public bool DynamicFieldResolve { get; set; }
|
||||
}
|
||||
|
||||
private static readonly Dictionary<EPatchType, PatchEntry> Patches = new Dictionary<EPatchType, PatchEntry>()
|
||||
{
|
||||
{
|
||||
EPatchType.ActivatePro,
|
||||
new PatchEntry
|
||||
{
|
||||
DynamicFieldResolve = true,
|
||||
Target = new Regex(@"getUserAccount\(\)\{.*?return\s+this\.#\w+\.fetch\(\{.*?\}\)\}", RegexOptions.Singleline),
|
||||
Patch = "getUserAccount(){return this.#<fetch_field_name>.fetch({endpoint:\"/v3/account\",method:\"GET\",name:\"/v3/account\",collectMetrics:0}).then(response=>{response.subscription={period:\"yearly\",state:\"active\"};response.flags=78;return response;})}"
|
||||
}
|
||||
},
|
||||
{
|
||||
EPatchType.DisableUpdates,
|
||||
new PatchEntry
|
||||
{
|
||||
Target = new Regex(@"registerHandler\(""ACTION_CHECK_FOR_UPDATE"".*?\)\)\)\)", RegexOptions.Singleline),
|
||||
Patch = "registerHandler(\"ACTION_CHECK_FOR_UPDATE\",(e=>expectUpdateFeedUrl(e,(e=>null)))"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private readonly WeModConfig _weModConfig;
|
||||
private readonly Action<string, ELogType> _logger;
|
||||
@@ -52,7 +25,6 @@ namespace WeModPatcher.Core
|
||||
private readonly string _asarPath;
|
||||
private readonly string _backupPath;
|
||||
private readonly string _unpackedPath;
|
||||
private int _sumOfPatches = 0;
|
||||
|
||||
public Patcher(WeModConfig weModConfig, Action<string, ELogType> logger, PatchConfig config)
|
||||
{
|
||||
@@ -65,49 +37,46 @@ namespace WeModPatcher.Core
|
||||
_backupPath = Path.Combine(weModConfig.RootDirectory, "resources", "app.asar.backup");
|
||||
}
|
||||
|
||||
private static string GetFetchFieldName(string targetFunction)
|
||||
{
|
||||
var fetchMatch = Regex.Match(targetFunction, @"return\s+this\.#(\w+)\.fetch");
|
||||
return fetchMatch.Success ? fetchMatch.Groups[1].Value : null;
|
||||
}
|
||||
|
||||
private void ApplyJsPatch(string fileName, string js, PatchEntry patch, EPatchType patchType)
|
||||
private string ApplyJsPatch(string fileName, string js, PatcherConfig.PatchEntry patch, EPatchType patchType)
|
||||
{
|
||||
if (patch.Applied)
|
||||
{
|
||||
return;
|
||||
return js;
|
||||
}
|
||||
|
||||
var matches = patch.Target.Matches(js);
|
||||
if (matches.Count == 0)
|
||||
{
|
||||
return;
|
||||
return js;
|
||||
}
|
||||
|
||||
var prefix = $"[PATCHER] [{patchType} -> {patch.Name}]";
|
||||
|
||||
if(matches.Count > 1 && patch.SingleMatch)
|
||||
{
|
||||
throw new Exception(
|
||||
$"[PATCHER] [{patchType}] Patch failed. Multiple target functions found. Looks like the version is not supported");
|
||||
$"{prefix} Patch failed. Multiple target functions found. Looks like the version is not supported");
|
||||
}
|
||||
|
||||
if (patch.DynamicFieldResolve)
|
||||
if (patch.Resolver != null)
|
||||
{
|
||||
string fetchFieldName = GetFetchFieldName(matches[0].Value);
|
||||
if (string.IsNullOrEmpty(fetchFieldName))
|
||||
string resolvedField = patch.Resolver.Handler(matches[0].Value);
|
||||
if (string.IsNullOrEmpty(resolvedField))
|
||||
{
|
||||
throw new Exception($"[PATCHER] [{patchType}] Fetch field name not found");
|
||||
throw new Exception($"{prefix} Resolver failed to find field name");
|
||||
}
|
||||
|
||||
patch.Patch = patch.Patch.Replace("<fetch_field_name>", fetchFieldName);
|
||||
patch.Patch = patch.Patch.Replace(patch.Resolver.Placeholder, resolvedField);
|
||||
}
|
||||
|
||||
_logger($"[PATCHER] [{patchType}] Found target function in: " + Path.GetFileName(fileName), ELogType.Info);
|
||||
|
||||
_logger($"{prefix} Found target function in: " + Path.GetFileName(fileName), ELogType.Info);
|
||||
|
||||
File.WriteAllText(fileName, patch.Target.Replace(js, patch.Patch));
|
||||
_logger($"[PATCHER] [{patchType}] Patch applied", ELogType.Success);
|
||||
string newJs = patch.Target.Replace(js, patch.Patch);
|
||||
File.WriteAllText(fileName, newJs);
|
||||
_logger($"{prefix} Patch applied", ELogType.Success);
|
||||
patch.Applied = true;
|
||||
_sumOfPatches -= (int)patchType;
|
||||
|
||||
return newJs;
|
||||
}
|
||||
|
||||
private void PatchAsar()
|
||||
@@ -121,21 +90,42 @@ namespace WeModPatcher.Core
|
||||
throw new Exception("[PATCHER] No app bundle found");
|
||||
}
|
||||
|
||||
var requestedPatches = _config.PatchTypes.ToList();
|
||||
requestedPatches.ForEach(patch => _sumOfPatches += (int)patch);
|
||||
// Track patches that still need to be completed
|
||||
var remainingPatches = new HashSet<EPatchType>(_config.PatchTypes);
|
||||
var patcherConfig = PatcherConfig.GetInstance();
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (_sumOfPatches <= 0)
|
||||
if (remainingPatches.Count == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
string data = File.ReadAllText(item);
|
||||
foreach (var entry in requestedPatches)
|
||||
|
||||
// Iterate over a copy of the list so we can modify the HashSet
|
||||
foreach (var entry in remainingPatches.ToList())
|
||||
{
|
||||
ApplyJsPatch(item, data, Patches[entry], entry);
|
||||
var entries = patcherConfig[entry];
|
||||
foreach (var patchEntry in entries)
|
||||
{
|
||||
// Update data in memory so subsequent patches in the same file work on latest content
|
||||
data = ApplyJsPatch(item, data, patchEntry, entry);
|
||||
}
|
||||
|
||||
// Check if all entries for this patch type are applied
|
||||
if (entries.All(x => x.Applied))
|
||||
{
|
||||
remainingPatches.Remove(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(remainingPatches.Count > 0)
|
||||
{
|
||||
var failedPatches = string.Join(", ", remainingPatches.Select(p => p.ToString()));
|
||||
throw new Exception($"[PATCHER] Failed to apply patches: {failedPatches}. The version may not be supported.");
|
||||
}
|
||||
}
|
||||
|
||||
private void AttachProxyDll()
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using WeModPatcher.Models;
|
||||
|
||||
namespace WeModPatcher.Core
|
||||
{
|
||||
public static class PatcherConfig
|
||||
{
|
||||
public class ResolveContext
|
||||
{
|
||||
public string Placeholder { get; set; }
|
||||
public Func<string, string> Handler { get; set; }
|
||||
}
|
||||
|
||||
public class PatchEntry
|
||||
{
|
||||
public Regex Target { get; set; }
|
||||
public string Patch { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool Applied { get; set; }
|
||||
public bool SingleMatch { get; set; } = true;
|
||||
public ResolveContext Resolver { get; set; }
|
||||
}
|
||||
|
||||
public static Dictionary<EPatchType, PatchEntry[]> GetInstance()
|
||||
{
|
||||
return new Dictionary<EPatchType, PatchEntry[]>()
|
||||
{
|
||||
{
|
||||
EPatchType.ActivatePro,
|
||||
new[]
|
||||
{
|
||||
new PatchEntry
|
||||
{
|
||||
Resolver = new ResolveContext
|
||||
{
|
||||
Handler = (targetFunction) =>
|
||||
{
|
||||
var fetchMatch = Regex.Match(targetFunction, @"return\s+this\.#(\w+)\.fetch");
|
||||
return fetchMatch.Success ? fetchMatch.Groups[1].Value : null;
|
||||
},
|
||||
Placeholder = "<service_name>"
|
||||
},
|
||||
Name = "getUserAccount",
|
||||
Target = new Regex(@"getUserAccount\(\)\{.*?return\s+this\.#\w+\.fetch\(\{.*?\}\)\}",
|
||||
RegexOptions.Singleline),
|
||||
Patch =
|
||||
"getUserAccount(){return this.#<service_name>.fetch({endpoint:\"/v3/account\",method:\"GET\",name:\"/v3/account\",collectMetrics:0}).then(response=>{response.subscription={period:\"yearly\",state:\"active\"};return response;})}"
|
||||
},
|
||||
new PatchEntry
|
||||
{
|
||||
Resolver = new ResolveContext
|
||||
{
|
||||
Handler = (targetFunction) =>
|
||||
{
|
||||
var match = Regex.Match(targetFunction, @"return\s+this\.#(\w+)\.post");
|
||||
return match.Success ? match.Groups[1].Value : null;
|
||||
},
|
||||
Placeholder = "<service_name>"
|
||||
},
|
||||
Name = "setAccountWandBrandExperience",
|
||||
Target = new Regex(
|
||||
@"setAccountWandBrandExperience\(\){.*?return\s+this\.#\w+\.post\(""/v3/account/brand_experience_wand""\)}",
|
||||
RegexOptions.Singleline),
|
||||
Patch =
|
||||
"setAccountWandBrandExperience(){return this.#<service_name>.post(\"/v3/account/brand_experience_wand\").then(response=>{response.subscription={period:\"yearly\",state:\"active\"};return response;})}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
EPatchType.DisableUpdates,
|
||||
new[]
|
||||
{
|
||||
new PatchEntry
|
||||
{
|
||||
Target = new Regex(@"registerHandler\(""ACTION_CHECK_FOR_UPDATE"".*?\)\)\)\)",
|
||||
RegexOptions.Singleline),
|
||||
Patch = "registerHandler(\"ACTION_CHECK_FOR_UPDATE\",(e=>expectUpdateFeedUrl(e,(e=>null)))"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
EPatchType.DevToolsOnF12,
|
||||
new[]
|
||||
{
|
||||
new PatchEntry
|
||||
{
|
||||
Resolver = new ResolveContext
|
||||
{
|
||||
Handler = (matchContent) => {
|
||||
var match = Regex.Match(matchContent, @"this\.#(\w+)\(""ACTION_OPEN_DEV_TOOLS""\)");
|
||||
return match.Success ? match.Groups[1].Value : null;
|
||||
},
|
||||
Placeholder = "<dispatch_method>"
|
||||
},
|
||||
Target = new Regex(@"document\.addEventListener\(""keydown"",\s*\((?<arg>\w+)\s*=>\s*\{[^}]*?""ACTION_OPEN_DEV_TOOLS""[^}]*?\}\)\)", RegexOptions.Singleline),
|
||||
Patch = "document.addEventListener(\"keydown\",(${arg}=>{\"F12\"!==${arg}.key||this.#<dispatch_method>(\"ACTION_OPEN_DEV_TOOLS\")}))"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,8 @@ namespace WeModPatcher.Models
|
||||
{
|
||||
ActivatePro = 1,
|
||||
DisableUpdates = 2,
|
||||
DisableTelemetry = 4
|
||||
DisableTelemetry = 4,
|
||||
DevToolsOnF12 = 8
|
||||
}
|
||||
|
||||
public sealed class PatchConfig
|
||||
|
||||
@@ -54,6 +54,12 @@
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
||||
<Button
|
||||
Margin="0 0 5 0"
|
||||
Width="25" Height="25" Padding="5.5"
|
||||
Style="{StaticResource IconButton}"
|
||||
Tag="{StaticResource CogIcon}"
|
||||
/>
|
||||
<Button
|
||||
Margin="9 0 15 0"
|
||||
Tag="{StaticResource CloseIcon}"
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
<CheckBox Grid.Row="0" x:Name="ActivateProBox" HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
IsChecked="True" />
|
||||
|
||||
<TextBlock Grid.Row="1" VerticalAlignment="Center" Text="Disable telemetry" />
|
||||
<CheckBox Grid.Row="1" x:Name="DisableTelemetryBox" HorizontalAlignment="Right" VerticalAlignment="Center" />
|
||||
<TextBlock Grid.Row="1" VerticalAlignment="Center" Text="DevTools on F12" />
|
||||
<CheckBox Grid.Row="1" x:Name="DevToolsHotkeyBox" HorizontalAlignment="Right" VerticalAlignment="Center" />
|
||||
|
||||
<TextBlock Grid.Row="2" VerticalAlignment="Center" Text="Disable updates" />
|
||||
<CheckBox Grid.Row="2" x:Name="DisableUpdateBox" HorizontalAlignment="Right" VerticalAlignment="Center" />
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace WeModPatcher.View.Popups
|
||||
private void OnPatchButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (ActivateProBox.IsChecked != true && DisableUpdateBox.IsChecked != true &&
|
||||
DisableTelemetryBox.IsChecked != true)
|
||||
DevToolsHotkeyBox.IsChecked != true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -36,6 +36,11 @@ namespace WeModPatcher.View.Popups
|
||||
result.Add(EPatchType.DisableUpdates);
|
||||
}
|
||||
|
||||
if (DevToolsHotkeyBox.IsChecked == true)
|
||||
{
|
||||
result.Add(EPatchType.DevToolsOnF12);
|
||||
}
|
||||
|
||||
_onApply(new PatchConfig
|
||||
{
|
||||
PatchTypes = result,
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
<Compile Include="Converters\BaseBooleanConverter.cs" />
|
||||
<Compile Include="Converters\ToVisibilityConverter.cs" />
|
||||
<Compile Include="Core\Patcher.cs" />
|
||||
<Compile Include="Core\PatcherConfig.cs" />
|
||||
<Compile Include="Models\WeModConfig.cs" />
|
||||
<Compile Include="Models\PatchConfig.cs" />
|
||||
<Compile Include="Models\Signature.cs" />
|
||||
|
||||
Reference in New Issue
Block a user