try fix unlocking fps

This commit is contained in:
DismissedLight
2024-07-17 10:19:19 +08:00
parent ad90c6b792
commit 6b03ccdacc
6 changed files with 46 additions and 43 deletions

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace Snap.Hutao.Extension;

View File

@@ -19,19 +19,32 @@ internal static class GameFpsAddress
public static unsafe void UnsafeFindFpsAddress(GameFpsUnlockerContext context, in RequiredRemoteModule remoteModule, in RequiredLocalModule localModule)
{
int offsetToUserAssembly = IndexOfPattern(localModule.UserAssembly.AsSpan());
HutaoException.ThrowIfNot(offsetToUserAssembly >= 0, SH.ServiceGameUnlockerInterestedPatternNotFound);
Span<byte> executableSpan = localModule.Executable.AsSpan();
int offsetToExecutable = 0;
nuint localVirtualAddress = 0;
do
{
int index = IndexOfPattern(executableSpan[offsetToExecutable..]);
if (index < 0)
{
break;
}
nuint rip = localModule.UserAssembly.Address + (uint)offsetToUserAssembly;
rip += 5U;
rip += (nuint)(*(int*)(rip + 2U) + 6);
offsetToExecutable += index;
nuint remoteVirtualAddress = remoteModule.UserAssembly.Address + (rip - localModule.UserAssembly.Address);
nuint rip = localModule.Executable.Address + (uint)offsetToExecutable;
rip += 5U;
rip += (nuint)(*(int*)(rip + 1U) + 5);
nuint ptr = 0;
SpinWait.SpinUntil(() => UnsafeReadProcessMemory(context.AllAccess, remoteVirtualAddress, out ptr) && ptr != 0);
if (*(byte*)rip is ASM_JMP)
{
localVirtualAddress = rip;
break;
}
}
while (true);
nuint localVirtualAddress = ptr - remoteModule.UnityPlayer.Address + localModule.UnityPlayer.Address;
ArgumentOutOfRangeException.ThrowIfZero(localVirtualAddress);
while (*(byte*)localVirtualAddress is ASM_CALL or ASM_JMP)
{
@@ -39,15 +52,15 @@ internal static class GameFpsAddress
}
localVirtualAddress += *(uint*)(localVirtualAddress + 2) + 6;
nuint relativeVirtualAddress = localVirtualAddress - localModule.UnityPlayer.Address;
context.FpsAddress = remoteModule.UnityPlayer.Address + relativeVirtualAddress;
nuint relativeVirtualAddress = localVirtualAddress - localModule.Executable.Address;
context.FpsAddress = remoteModule.Executable.Address + relativeVirtualAddress;
}
private static int IndexOfPattern(in ReadOnlySpan<byte> memory)
private static int IndexOfPattern(in ReadOnlySpan<byte> span)
{
// B9 3C 00 00 00 FF 15
ReadOnlySpan<byte> part = [0xB9, 0x3C, 0x00, 0x00, 0x00, 0xFF, 0x15];
return memory.IndexOf(part);
return span.IndexOf(part);
}
private static unsafe bool UnsafeReadProcessMemory(HANDLE hProcess, nuint baseAddress, out nuint value)

View File

@@ -51,12 +51,9 @@ internal abstract class GameFpsUnlocker : IGameFpsUnlocker
private static RequiredLocalModule LoadRequiredLocalModule(GameFileSystem gameFileSystem)
{
string gameFoler = gameFileSystem.GameDirectory;
string dataFoler = gameFileSystem.DataDirectory;
LOAD_LIBRARY_FLAGS flags = LOAD_LIBRARY_FLAGS.LOAD_LIBRARY_AS_IMAGE_RESOURCE;
HMODULE unityPlayerAddress = LoadLibraryExW(System.IO.Path.Combine(gameFoler, "UnityPlayer.dll"), default, flags);
HMODULE userAssemblyAddress = LoadLibraryExW(System.IO.Path.Combine(dataFoler, "Native", "UserAssembly.dll"), default, flags);
HMODULE executaleAddress = LoadLibraryExW(gameFileSystem.GameFilePath, default, flags);
return new(unityPlayerAddress, userAssemblyAddress);
return new(executaleAddress);
}
}

View File

@@ -42,16 +42,15 @@ internal static class GameProcessModule
private static FindModuleResult UnsafeGetGameModuleInfo(in HANDLE hProcess, out RequiredRemoteModule info)
{
FindModuleResult unityPlayerResult = UnsafeFindModule(hProcess, "UnityPlayer.dll", out Module unityPlayer);
FindModuleResult userAssemblyResult = UnsafeFindModule(hProcess, "UserAssembly.dll", out Module userAssembly);
FindModuleResult result = UnsafeFindModule(hProcess, GameConstants.YuanShenFileName, GameConstants.GenshinImpactFileName, out Module executable);
if (unityPlayerResult is FindModuleResult.Ok && userAssemblyResult is FindModuleResult.Ok)
if (result is FindModuleResult.Ok)
{
info = new(unityPlayer, userAssembly);
info = new(executable);
return FindModuleResult.Ok;
}
if (unityPlayerResult is FindModuleResult.NoModuleFound && userAssemblyResult is FindModuleResult.NoModuleFound)
if (result is FindModuleResult.NoModuleFound)
{
info = default;
return FindModuleResult.NoModuleFound;
@@ -61,7 +60,7 @@ internal static class GameProcessModule
return FindModuleResult.ModuleNotLoaded;
}
private static unsafe FindModuleResult UnsafeFindModule(in HANDLE hProcess, in ReadOnlySpan<char> moduleName, out Module module)
private static unsafe FindModuleResult UnsafeFindModule(in HANDLE hProcess, in ReadOnlySpan<char> moduleName1, in ReadOnlySpan<char> moduleName2, out Module module)
{
HMODULE[] buffer = new HMODULE[128];
if (!K32EnumProcessModules(hProcess, buffer, out uint actualSize))
@@ -86,7 +85,8 @@ internal static class GameProcessModule
fixed (char* lpBaseName = baseName)
{
if (!moduleName.SequenceEqual(MemoryMarshal.CreateReadOnlySpanFromNullTerminated(lpBaseName)))
ReadOnlySpan<char> baseNameSpan = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(lpBaseName);
if (!moduleName1.SequenceEqual(baseNameSpan) || !moduleName2.SequenceEqual(baseNameSpan))
{
continue;
}

View File

@@ -12,30 +12,24 @@ namespace Snap.Hutao.Service.Game.Unlocker;
internal readonly struct RequiredLocalModule : IDisposable
{
public readonly bool HasValue = false;
public readonly Module UnityPlayer;
public readonly Module UserAssembly;
public readonly Module Executable;
private readonly HMODULE hModuleUnityPlayer;
private readonly HMODULE hModuleUserAssembly;
private readonly HMODULE hModuleExecutable;
public RequiredLocalModule(HMODULE unityPlayer, HMODULE userAssembly)
public RequiredLocalModule(HMODULE executable)
{
hModuleUnityPlayer = unityPlayer;
hModuleUserAssembly = userAssembly;
hModuleExecutable = executable;
// Align the pointer
nint unityPlayerMappedView = (nint)(unityPlayer & ~0x3L);
nint userAssemblyMappedView = (nint)(userAssembly & ~0x3L);
nint executableMappedView = (nint)(executable & ~0x3L);
Executable = new((nuint)executableMappedView, GetImageSize(executableMappedView));
HasValue = true;
UnityPlayer = new((nuint)unityPlayerMappedView, GetImageSize(unityPlayerMappedView));
UserAssembly = new((nuint)userAssemblyMappedView, GetImageSize(userAssemblyMappedView));
}
public void Dispose()
{
FreeLibrary(hModuleUnityPlayer);
FreeLibrary(hModuleUserAssembly);
FreeLibrary(hModuleExecutable);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -6,13 +6,11 @@ namespace Snap.Hutao.Service.Game.Unlocker;
internal readonly struct RequiredRemoteModule
{
public readonly bool HasValue = false;
public readonly Module UnityPlayer;
public readonly Module UserAssembly;
public readonly Module Executable;
public RequiredRemoteModule(in Module unityPlayer, in Module userAssembly)
public RequiredRemoteModule(in Module executable)
{
HasValue = true;
UnityPlayer = unityPlayer;
UserAssembly = userAssembly;
Executable = executable;
}
}