Skip to content

Commit

Permalink
Add signature scan for openxr
Browse files Browse the repository at this point in the history
  • Loading branch information
Umbranoxio committed Dec 17, 2023
1 parent c7c406a commit 6f55e00
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 21 deletions.
90 changes: 71 additions & 19 deletions 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;

Expand All @@ -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);

Expand All @@ -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
Expand All @@ -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<ProcessModule>().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<xrGetCurrentInstanceDelegate>(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<xrGetCurrentInstanceDelegate>(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}");
Expand All @@ -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}");
Expand All @@ -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<byte> patternBytes = new List<byte>();
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;
}
}
}
4 changes: 2 additions & 2 deletions ScoreSaber/manifest.json
Expand Up @@ -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",
Expand Down

0 comments on commit 6f55e00

Please sign in to comment.