From 6f55e00ed48a39c430b7b358d81f4c036a48707a Mon Sep 17 00:00:00 2001 From: Umbranox Date: Mon, 18 Dec 2023 09:37:49 +1100 Subject: [PATCH] Add signature scan for openxr --- ScoreSaber/Core/Utils/OpenXRManager.cs | 90 ++++++++++++++++++++------ ScoreSaber/manifest.json | 4 +- 2 files changed, 73 insertions(+), 21 deletions(-) diff --git a/ScoreSaber/Core/Utils/OpenXRManager.cs b/ScoreSaber/Core/Utils/OpenXRManager.cs index 957ddce..9081359 100644 --- a/ScoreSaber/Core/Utils/OpenXRManager.cs +++ b/ScoreSaber/Core/Utils/OpenXRManager.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; using System.Runtime.InteropServices; using System.Text; @@ -9,6 +12,9 @@ internal static unsafe class OpenXRManager { [DllImport("kernel32", CharSet = CharSet.Auto)] private static extern IntPtr GetModuleHandle(string lpModuleName); + [DllImport("kernel32.dll")] + public static extern bool ReadProcessMemory(IntPtr hProcess, ulong lpBaseAddress, byte[] lpBuffer, int dwSize, int lpNumberOfBytesRead = 0); + [DllImport("openxr_loader", EntryPoint = "xrGetSystemProperties", CallingConvention = CallingConvention.Cdecl)] private static extern ulong GetSystemProperties(long* instance, ulong systemId, XrSystemProperties* properties); @@ -28,13 +34,13 @@ internal static unsafe class OpenXRManager { // XrSystemProperties structure https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSystemProperties.html private struct XrSystemProperties { - public ulong type; // 64 bit - public void* next; // 64 bit - public ulong systemId; // 64 bit - public int vendorId; // 32 bit - public fixed byte systemName[XR_MAX_SYSTEM_NAME_SIZE]; - public XrSystemGraphicsProperties graphicsProperties; - public XrSystemTrackingProperties trackingProperties; + public ulong type; // 64 bit + public void* next; // 64 bit + public ulong systemId; // 64 bit + public int vendorId; // 32 bit + public fixed byte systemName[XR_MAX_SYSTEM_NAME_SIZE]; + public XrSystemGraphicsProperties graphicsProperties; + public XrSystemTrackingProperties trackingProperties; }; // XrSystemGraphicsProperties structure https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSystemGraphicsProperties.html @@ -61,37 +67,46 @@ private struct XrSystemGetInfo { private const int XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY = 1; // https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrStructureType.html - private const int XR_TYPE_SYSTEM_GET_INFO = 4; + private const int XR_TYPE_SYSTEM_GET_INFO = 4; private const int XR_TYPE_SYSTEM_PROPERTIES = 5; - private const int XR_MAX_SYSTEM_NAME_SIZE = 256; + private const int XR_MAX_SYSTEM_NAME_SIZE = 256; internal static string hmdName = null; + internal const string xrGetCurrentInstancePattern = "48 83 EC 28 65 48 8B 04 25 ? ? ? ? 8B 0D ? ? ? ? BA ? ? ? ? 48 8B 0C C8 8B 04 0A 39 05 ? ? ? ? 7F 0C 48 8D 05 ? ? ? ? 48 83 C4 28 C3 48 8D 0D ? ? ? ?"; + internal static void Initialize() { hmdName = AttemptGetHmd(); } private static string AttemptGetHmd() { try { - var openXRLoaderBaseAddress = GetModuleHandle("openxr_loader"); + var currentProcess = Process.GetCurrentProcess(); + var openXRLoaderModule = currentProcess.Modules.Cast().FirstOrDefault(module => module.ModuleName == "openxr_loader.dll"); - if (openXRLoaderBaseAddress == IntPtr.Zero) { + if (openXRLoaderModule == null) { throw new Exception("openxr_loader not found"); } // Get our xrInstance - var xrGetCurrentInstance = Marshal.GetDelegateForFunctionPointer(openXRLoaderBaseAddress + 0x39480); - var xrCurrentInstance = new IntPtr(*(long*)xrGetCurrentInstance()); - var xrInstance = (long*)*(ulong*)new IntPtr((byte*)xrCurrentInstance.ToPointer() + 8); + var xrGetCurrentInstanceOffset = PatternScan(Process.GetCurrentProcess(), openXRLoaderModule, xrGetCurrentInstancePattern); + + if (xrGetCurrentInstanceOffset == IntPtr.Zero) { + throw new Exception("xrGetCurrentInstance not found"); + } + + var xrGetCurrentInstance = Marshal.GetDelegateForFunctionPointer(xrGetCurrentInstanceOffset); + var xrCurrentInstance = new IntPtr(*(long*)xrGetCurrentInstance()); + var xrInstance = (long*)*(ulong*)new IntPtr((byte*)xrCurrentInstance.ToPointer() + 8); // Get our systemId var info = new XrSystemGetInfo { - type = XR_TYPE_SYSTEM_GET_INFO, + type = XR_TYPE_SYSTEM_GET_INFO, formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY }; - ulong systemId = 0; - var getSystemResult = GetSystem(xrInstance, &info, &systemId); + ulong systemId = 0; + var getSystemResult = GetSystem(xrInstance, &info, &systemId); if (getSystemResult != 0) { Plugin.Log.Info($"Failed to get system from OpenXR {getSystemResult}"); @@ -101,7 +116,7 @@ private struct XrSystemGetInfo { // Get our system properties XrSystemProperties properties; properties.type = XR_TYPE_SYSTEM_PROPERTIES; - var result = GetSystemProperties(xrInstance, systemId, &properties); + var result = GetSystemProperties(xrInstance, systemId, &properties); if (result != 0) { Plugin.Log.Info($"Failed to get system properties from OpenXR {result}"); @@ -117,12 +132,49 @@ private struct XrSystemGetInfo { systemNameStrBuilder.Append(((char)properties.systemName[charIndex])); } - return systemNameStrBuilder.ToString(); } catch (Exception ex) { Plugin.Log.Info($"Failed to get hmd from OpenXR {ex}"); return null; } } + + + static IntPtr PatternScan(Process process, ProcessModule module, string pattern) { + + byte[] moduleBuffer = new byte[module.ModuleMemorySize]; + var success = ReadProcessMemory(process.Handle, (ulong)module.BaseAddress, moduleBuffer, module.ModuleMemorySize); + + if (!success) { + throw new Exception("Failed to read process memory"); + } + + // Convert the input pattern string into a list of bytes + List patternBytes = new List(); + foreach (var b in pattern.Split(' ')) { + // Treat '?' as a wildcard (0x0) and convert other hex values to bytes + patternBytes.Add(b == "?" ? (byte)0x0 : Convert.ToByte(b, 16)); + } + + for (int i = 0; i < moduleBuffer.Length - patternBytes.Count + 1; i++) { + // Flag indicating whether the pattern is matched at the current position + bool isPatternMatch = true; + + for (int j = 0; j < patternBytes.Count; j++) { + if (patternBytes[j] != 0x0 && patternBytes[j] != moduleBuffer[i + j]) { + // If the bytes don't match, set the flag to false and break out of the loop + isPatternMatch = false; + break; + } + } + + // If the pattern is fully matched, return the address of the match + if (isPatternMatch) { + return IntPtr.Add(module.BaseAddress, i); + } + } + + return IntPtr.Zero; + } } } \ No newline at end of file diff --git a/ScoreSaber/manifest.json b/ScoreSaber/manifest.json index 789f4a2..2517599 100644 --- a/ScoreSaber/manifest.json +++ b/ScoreSaber/manifest.json @@ -2,11 +2,11 @@ "$schema": "https://raw.githubusercontent.com/nike4613/ModSaber-MetadataFileSchema/master/Schema.json", "author": "Umbranox", "description": "Allows you to upload scores to an online leaderboard, earn PP from ranked maps and compare scores with others.", - "gameVersion": "1.33.0", + "gameVersion": "1.34.2", "icon": "ScoreSaber.logo.png", "id": "ScoreSaber", "name": "ScoreSaber", - "version": "3.3.2", + "version": "3.3.3", "dependsOn": { "BSIPA": "^4.1.6", "BeatSaberMarkupLanguage": "^1.8.0",