Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Game Pass / Xbox App support #10

Closed
gibbed opened this issue Sep 7, 2023 · 6 comments
Closed

Game Pass / Xbox App support #10

gibbed opened this issue Sep 7, 2023 · 6 comments

Comments

@gibbed
Copy link

gibbed commented Sep 7, 2023

I recognize that you're not too keen on Game Pass / Xbox App support due to the limitations of the UWP sandbox.

I did a little experiment.

It turns out that in a Starfield install in the Xbox app, you can rename Starfield.exe. This actually surprised me.

I renamed Starfield.exe to Starfield.real.exe and I wrote a thin wrapper exe to stand-in for Starfield.exe that spawns sfse_loader.exe -altexe Starfield.real.exe from within the UWP sandbox.

It... shockingly, worked. And logs got created just fine.

Documents\My Games\Starfield\SFSE\Logs\skse_loader.txt

SFSE loader: initialize (version = 0.1.0 01070170 2023-09-07 22:13:32, os = 6.2 (9200))
config path = C:\Program Files\WindowsApps\BethesdaSoftworks.ProjectGold_1.7.23.0_x64__3275kfvn8vcwc\Data\SFSE\sfse.ini
launching alternate exe (Starfield.real.exe)
procPath = Starfield.real.exe
launching: Starfield.exe (Starfield.real.exe)
dwSignature = FEEF04BD
dwStrucVersion = 00010000
dwFileVersionMS = 00010007
dwFileVersionLS = 00170000
dwProductVersionMS = 00010007
dwProductVersionLS = 00170000
dwFileFlagsMask = 00000017
dwFileFlags = 00000000
dwFileOS = 00000004
dwFileType = 00000001
dwFileSubtype = 00000000
dwFileDateMS = 00000000
dwFileDateLS = 00000000
productVersionStr = 1.7.23.0
version = 0001000700170000
product name = Starfield
normal exe
dll = C:\Program Files\WindowsApps\BethesdaSoftworks.ProjectGold_1.7.23.0_x64__3275kfvn8vcwc\\sfse_1_7_23.dll
main thread id = 4036
hookBase = 00000247FD7F0000
loadLibraryAAddr = 00007FFBDC1D0C70
getProcAddressAddr = 00007FFBDC1CB650
hook thread complete
launching

Documents\My Games\Starfield\SFSE\Logs\sfse.txt

SFSE runtime: initialize (version = 0.1.0 01070170 2023-09-07 22:13:32, os = 6.2 (9200))
imagebase = 00007FFBAFCF0000
reloc mgr imagebase = 00007FF740D20000
plugin directory = C:\Program Files\WindowsApps\BethesdaSoftworks.ProjectGold_1.7.23.0_x64__3275kfvn8vcwc\Data\SFSE\Plugins\
scanning plugin directory C:\Program Files\WindowsApps\BethesdaSoftworks.ProjectGold_1.7.23.0_x64__3275kfvn8vcwc\Data\SFSE\Plugins\
preinit complete
dispatch message (0) to plugin listeners
no listeners registered
dispatch message (1) to plugin listeners
no listeners registered
init complete

Obviously this will break once build-specific stuff is added to SFSE.

But this does mean sfse_loader.exe can function within the UWP sandbox just fine. So if you're willing to support the UWP build of Starfield or accept contributions of the necessary information, it could happen.

@ianpatt
Copy link
Owner

ianpatt commented Sep 7, 2023

Oh, wow. That's actually the best method I've seen. It does involve a bit of renaming of game content, which is not ideal, but not deal-breaking. If the MS Store launcher is happy to give the magic "can launch this" state to our token and launch a third party process, then we can launch with full control.

Thanks! I will keep this in mind if MS Store support gets added later. It's not going to happen right now, as trying to support two versions at once would suck for development (especially early development where we're just getting the basics going).

For other people reading this, key word to notice:

LATER

@ianpatt ianpatt closed this as completed Sep 7, 2023
@gibbed
Copy link
Author

gibbed commented Sep 7, 2023

Hey, better response than I expected! 👍🏻

Not a huge deal on not initially having support, since it will take time for anything big to happen anyway.

@ianpatt
Copy link
Owner

ianpatt commented Sep 7, 2023

Yeah, the game pass community is doing a really bad job selling themselves right now by making all kinds of ghastly hacks and ignoring messages to take down broken things that would (for example) report the same version number to plugins for both the MS and Steam version.

@gibbed
Copy link
Author

gibbed commented Sep 7, 2023

Yeah, I've been curious about the best way to get SFSE working for Game Pass / Xbox App since I'm playing via that version myself. I've done a bunch of Game Pass / Xbox App modding for other games, was going to check some other things I know that would work but I found the renaming-the-exe first.

@Aemony
Copy link

Aemony commented Sep 24, 2023

Win32 AppX packages do not have the same major restrictions as a proper classic UWP app, which is why a lot of these things are possible. For example the executables are normally protected from reads, but that protection can be removed by simply moving the executable (not copying, as that's not allowed) to another location, which will remove the protection against reading. And at that point you can just copy or move the executable back, and it'll be fully readable for other third-party apps despite its restored location...

Regarding SFSE and the way it works, the main limiter/barrier of entry is that the game need to be launched with the appropriate package identity to start up properly. If Starfield.exe is not launched with a package identity, it restarts itself through gamelaunchhelper.exe to ensure this is the case.

The gamelaunchhelper.exe does things like sets up the expected environment, the package identity, as well as syncs save files with the cloud before finally launching the game executable.

This requirement of going through gamelaunchhelper.exe can be worked around through primarily two different methods:

  1. The previously mentioned method of using a proxy executable, so gamelaunchhelper.exe launches a proxy Starfield.exe which then launches sfse_loader.exe which launches the real renamed game executable. The downside of this approach is that it does not survive game updates and needs to be manually restored after each one of those.

  2. The other alternative is to skip gamelaunchhelper.exe entirely by using one of the debugging tools available that creates a new process in the context of a package app, such as Invoke-CommandInDesktopPackage, with the downside of cloud sync being skipped entirely.

    The below PowerShell script makes use of Invoke-CommandInDesktopPackage to load a skfse_loader.exe stored in the game folder within the context of the packaged app, which allows us to retain the game executable filename and makes it compatible across patches (but again, without cloud sync).

sfse_loader.ps1

# Basic setup:
$AppxName          = "BethesdaSoftworks.ProjectGold"
$ExecutableCustom  = 'sfse_loader.exe' # Leave empty if not using custom executable

# The index of the application that the executable should be launched in the context of
# This will be 0 for most games as they only have a single launch option, but a few games define separate launch
#   options in their appxmanifest.xml files, where the first entry (0) might not correspond to the game/desired context
$AppIndex          = 0

# Setup
$Package           = Get-AppxPackage $AppxName
$PackageFamilyName = $Package.PackageFamilyName
$InstallLocation   = $Package.InstallLocation
$XmlManifest       = Select-Xml -Path "$InstallLocation\appxmanifest.xml" -XPath '/'
$Applications      = $XmlManifest.Node.Package.Applications.Application
$AppId             = if ($null -eq $Applications.Count) { $Applications.Id         } else { $Applications[$AppIndex].Id         }
$Executable        = if ($null -eq $Applications.Count) { $Applications.Executable } else { $Applications[$AppIndex].Executable }
$Command           = if ($null -eq $ExecutableCustom -or [string]::IsNullOrEmpty($ExecutableCustom)) { $Executable } else { $ExecutableCustom }

# Fix executables stored in the install folder
if ((Test-Path $Command -PathType leaf) -eq $false)
{
  if ((Test-Path "$InstallLocation\$Command" -PathType leaf))
  {
    $Command = "$InstallLocation\$Command"
  }
}

# Launch
$params = @{
  AppId             = $AppId
  PackageFamilyName = $PackageFamilyName
  Command           = $Command
}
Invoke-CommandInDesktopPackage @params

Since PowerShell script executions are typically disabled on systems by default, a helper batch file can be used to circumvent that:

sfse_loader.bat

@CD /D "%~dp0"
@powershell.exe -ExecutionPolicy Unrestricted -File  "%~dp0\sfse_loader.ps1"

The main downside of this approach is that as per Microsoft's documentation there's no guarantee being made about the behaviour of the created process, so there might be minor behaviour changes though from my testing I haven't noticed any (probably because AppX Win32 games run with "full trust" privileges anyway).

@ianpatt
Copy link
Owner

ianpatt commented Sep 24, 2023

Thanks, that is a good description of the current restrictions. Including a powershell script and the standard workaround for enabling powershell is probably going to be a death sentence from virus scanners, though. I will look at the implementation of Invoke-CommandInDesktopPackage to see if it can be lifted or reimplemented without setting off alarm bells.

I've also wondered what specifically is breaking IPackageDebugSettings - it works fine for all of the other packaged things on the system, but seems to have exceptions for things delivered through the Xbox section of the store. Haven't done a complete debug session on it yet, but did get pretty deep.

I've also taken a look at gamelaunchhelper's helper dll, but since it's delivered as part of the OS, its implementation can change at any time. That is actually one of the bigger concerns with anything involving the MS store - the things we are doing to launch could break at any time and there's very little we can do about it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants