Skip to content

Commit

Permalink
update for game version 4.8.0
Browse files Browse the repository at this point in the history
  • Loading branch information
34736384 committed Jul 16, 2024
1 parent 20fb63a commit ad45bdf
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 45 deletions.
2 changes: 1 addition & 1 deletion unlockfps_nc/AboutForm.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 1 addition & 20 deletions unlockfps_nc/Service/IpcService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public void Start(int processId, IntPtr pFpsValue)
}

var stubWndProc = Native.GetProcAddress(_stubModule, "WndProc");
var targetWindow = GetWindowFromProcessId(processId);
var targetWindow = ProcessUtils.GetWindowFromProcessId(processId);
var threadId = Native.GetWindowThreadProcessId(targetWindow, out uint _);

_wndHook = Native.SetWindowsHookEx(3, stubWndProc, _stubModule, threadId);
Expand Down Expand Up @@ -144,25 +144,6 @@ private string GetUnlockerStubPath()
return filePath;
}

private IntPtr GetWindowFromProcessId(int processId)
{
IntPtr windowHandle = IntPtr.Zero;

Native.EnumWindows((hWnd, lParam) =>
{
Native.GetWindowThreadProcessId(hWnd, out uint pid);
if (pid == processId)
{
windowHandle = hWnd;
return false;
}

return true;
}, IntPtr.Zero);

return windowHandle;
}

public void Dispose()
{
Stop();
Expand Down
51 changes: 47 additions & 4 deletions unlockfps_nc/Service/ProcessService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
Expand Down Expand Up @@ -161,8 +162,7 @@ private async Task Worker()

Native.CloseHandle(pi.hThread);

if (!await UpdateRemoteModules())
return;
SpinWait.SpinUntil(() => ProcessUtils.GetWindowFromProcessId(_gamePid) != IntPtr.Zero);

if (!SetupData())
return;
Expand Down Expand Up @@ -251,12 +251,22 @@ private unsafe bool SetupData()

if (!pUnityPlayer || !pUserAssembly)
{
if (!File.Exists(unityPlayerPath) && !File.Exists(userAssemblyPath))
{
if (SetupDataEx())
return true;
goto BAD_PATTERN;
}

MessageBox.Show(
@"Failed to load UnityPlayer.dll or UserAssembly.dll",
@"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}

if (!UpdateRemoteModules())
return false;

var dosHeader = Marshal.PtrToStructure<IMAGE_DOS_HEADER>(pUnityPlayer);
var ntHeader = Marshal.PtrToStructure<IMAGE_NT_HEADERS>((IntPtr)(pUnityPlayer.BaseAddress.ToInt64() + dosHeader.e_lfanew));

Expand Down Expand Up @@ -326,7 +336,40 @@ private unsafe bool SetupData()
return false;
}

private async Task<bool> UpdateRemoteModules()
private unsafe bool SetupDataEx()
{
var gameName = Path.GetFileNameWithoutExtension(_config.GamePath);
var remoteExe = ProcessUtils.GetModuleBase(_gameHandle, $"{gameName}.exe");
if (remoteExe == IntPtr.Zero)
return false;

using ModuleGuard pGenshinImpact = Native.LoadLibraryEx(_config.GamePath, IntPtr.Zero, 32);
if (!pGenshinImpact)
return false;

var vaResults = ProcessUtils.PatternScanAllOccurrences(pGenshinImpact, "B9 3C 00 00 00 E8");
if (vaResults.Count == 0)
return false;

var localVa = (byte*)vaResults
.Select(x => x + 5)
.Select(x => x + *(int*)(x + 1) + 5)
.FirstOrDefault(x => *(byte*)x == 0xE9);

if (localVa == null)
return false;

while (localVa[0] == 0xE8 || localVa[0] == 0xE9)
localVa += *(int*)(localVa + 1) + 5;

localVa += *(int*)(localVa + 2) + 6;
var rva = localVa - pGenshinImpact.BaseAddress.ToInt64();
_pFpsValue = (IntPtr)(remoteExe + rva);

return true;
}

private bool UpdateRemoteModules()
{
int retries = 0;

Expand All @@ -341,7 +384,7 @@ private async Task<bool> UpdateRemoteModules()
if (retries > 10)
break;

await Task.Delay(2000, _cts.Token);
Task.Delay(2000, _cts.Token).Wait();
retries++;
}

Expand Down
4 changes: 2 additions & 2 deletions unlockfps_nc/SetupForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ private void BtnBrowse_Click(object sender, EventArgs e)
return;
}

var unityPlayer = Path.Combine(directory, "UnityPlayer.dll");
if (!File.Exists(unityPlayer))
var dataDir = Path.Combine(directory, $"{fileName}_Data");
if (!Directory.Exists(dataDir))
{
MessageBox.Show(@"That's not the right place", @"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
Expand Down
9 changes: 9 additions & 0 deletions unlockfps_nc/Utility/Native.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,15 @@ public static bool IsWine()

return ver != 0;
}

public static uint GetModuleImageSize(IntPtr lpBaseAddress)
{
var dosHeader = Marshal.PtrToStructure<IMAGE_DOS_HEADER>(lpBaseAddress);
var ntHeader = Marshal.PtrToStructure<IMAGE_NT_HEADERS>(lpBaseAddress + dosHeader.e_lfanew);

return ntHeader.OptionalHeader.SizeOfImage;
}

}

internal class ModuleGuard(IntPtr module) : IDisposable
Expand Down
103 changes: 85 additions & 18 deletions unlockfps_nc/Utility/ProcessUtils.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;
Expand Down Expand Up @@ -30,6 +31,25 @@ public static string GetProcessPathFromPid(uint pid, out IntPtr processHandle)
return sb.ToString();
}

public static IntPtr GetWindowFromProcessId(int processId)
{
IntPtr windowHandle = IntPtr.Zero;

Native.EnumWindows((hWnd, lParam) =>
{
Native.GetWindowThreadProcessId(hWnd, out uint pid);
if (pid == processId)
{
windowHandle = hWnd;
return false;
}

return true;
}, IntPtr.Zero);

return windowHandle;
}

public static bool InjectDlls(IntPtr processHandle, List<string> dllPaths)
{
#if !RELEASEMIN
Expand Down Expand Up @@ -71,23 +91,11 @@ public static bool InjectDlls(IntPtr processHandle, List<string> dllPaths)

public static unsafe IntPtr PatternScan(IntPtr module, string signature)
{
var tokens = signature.Split(' ');
var patternBytes = tokens
.Select(x => x == "?" ? (byte)0xFF : Convert.ToByte(x, 16))
.ToArray();
var maskBytes = tokens
.Select(x => x == "?")
.ToArray();

var dosHeader = Marshal.PtrToStructure<IMAGE_DOS_HEADER>(module);
var ntHeader = Marshal.PtrToStructure<IMAGE_NT_HEADERS>((IntPtr)(module.ToInt64() + dosHeader.e_lfanew));
var (patternBytes, maskBytes) = ParseSignature(signature);

var sizeOfImage = ntHeader.OptionalHeader.SizeOfImage;
var sizeOfImage = Native.GetModuleImageSize(module);
var scanBytes = (byte*)module;

var s = patternBytes.Length;
var d = patternBytes;

if (Native.IsWine())
{
/*
Expand All @@ -98,23 +106,82 @@ public static unsafe IntPtr PatternScan(IntPtr module, string signature)
Native.VirtualProtect(module, sizeOfImage, MemoryProtection.EXECUTE_READWRITE, out _);
}

for (var i = 0U; i < sizeOfImage - s; i++)
var span = new ReadOnlySpan<byte>(scanBytes, (int)sizeOfImage);
var offset = PatternScan(span, patternBytes, maskBytes);

if (offset != -1)
return (IntPtr)(module.ToInt64() + offset);


return IntPtr.Zero;
}

public static unsafe List<IntPtr> PatternScanAllOccurrences(IntPtr module, string signature)
{
var (patternBytes, maskBytes) = ParseSignature(signature);

var sizeOfImage = Native.GetModuleImageSize(module);
var scanBytes = (byte*)module;

if (Native.IsWine())
Native.VirtualProtect(module, sizeOfImage, MemoryProtection.EXECUTE_READWRITE, out _);

var span = new ReadOnlySpan<byte>(scanBytes, (int)sizeOfImage);
var offsets = new List<IntPtr>();

var totalProcessed = 0L;
while (true)
{
var offset = PatternScan(span, patternBytes, maskBytes);
if (offset == -1)
break;

offsets.Add((IntPtr)(module.ToInt64() + offset + totalProcessed));

var processedOffset = offset + patternBytes.Length;
totalProcessed += processedOffset;

span = span.Slice((int)processedOffset);
}

return offsets;
}

public static long PatternScan(ReadOnlySpan<byte> data, byte[] patternBytes, bool[] maskBytes)
{
var s = patternBytes.Length;
var d = patternBytes;

for (var i = 0; i < data.Length - s; i++)
{
var found = true;
for (var j = 0; j < s; j++)
{
if (d[j] != scanBytes[i + j] && !maskBytes[j])
if (d[j] != data[i + j] && !maskBytes[j])
{
found = false;
break;
}
}

if (found)
return (IntPtr)(module.ToInt64() + i);
return i;
}

return IntPtr.Zero;
return -1;
}

private static (byte[], bool[]) ParseSignature(string signature)
{
var tokens = signature.Split(' ');
var patternBytes = tokens
.Select(x => x == "?" ? (byte)0xFF : Convert.ToByte(x, 16))
.ToArray();
var maskBytes = tokens
.Select(x => x == "?")
.ToArray();

return (patternBytes, maskBytes);
}

public static IntPtr GetModuleBase(IntPtr hProcess, string moduleName)
Expand Down

0 comments on commit ad45bdf

Please sign in to comment.