Skip to content

Windows - Steam

Steam specific DRM considerations.

Steam (DRM Wrapper)

Failure

This DRM presents is a problem because the game code is encrypted at boot, if you try to modify the game code at that point you'll hit the encrypted data and run into issues.

This is a lightweight form of DRM that encrypts the original binary in-place and decrypts the data at boot. The stub responsible for the decryption is likely written in x86/x64 Assembly.

Resources:

Dangers

Failure

This DRM will deliberately crash the game process after attaching a debugger. It needs to be removed when debugging.

For the purposes of debugging or reverse engineering; Steamless is able to automatically remove this DRM from most games.

Detection

Parse the PE header of the executable in memory. If this DRM is present, there is an IMAGE_SECTION_HEADER with the name .bind.

This holds true for all currently known versions of SteamStub.

Use get_section_names method of min-pe-parser.

Common Workaround(s)

Most loaders use either of the two approaches:

  • DLL Hijack a known DLL and init in one of the library's Init functions e.g. d3d9.CreateDevice.
  • Hook a library's init function (e.g. d3d9.CreateDevice), load Reloaded in the hook, and unhook.

We can't do this in R3, we should assume no knowledge of target game.

What R3 Should Do

Phase 0: Strip Stream Wrapper if Possible with Steamless

We remove Steam DRM Wrapper when possible for interoperability and compatibility purposes.

THE MAIN PURPOSE OF THIS ACTION IS TO ACHIEVE INTEROPERABILITY BETWEEN THE EXISTING GAME SOFTWARE, MOD LOADER AND 3RD PARTY LOADER MODS.

  • Reloaded performs this mainly to allow debugging crashes experienced by end users.
  • Reloaded will never remove SteamWorks API integration. (i.e. steam_api.dll)
  • Reloaded will never include or distribute any emulator for the Steamworks API integration.
  • Reloaded will never promote, encourage or assist with piracy.
  • Reloaded will never assist with bypassing anti-cheats or online protections.

In practice, almost all Steam games will retain their existing copy protection through their integration/use of the SteamWorks API (steam_api.dll).

IMPORTANT: This needs to be communicated in the final software.

  1. Build Steamless with modern .NET (i.e. .NET Core).
  2. Produce native Reloaded Packages (TODO: LINK PENDING) that bundle Steamless as a Tool.
  3. Run Steamless.CLI with --keepbind, --exp.
  4. This is necessary because some games have an edge case.

Phase 1: Strip Stream Wrapper if Possible with Steamless

This is used as a fallback in case Phase 0 fails.

The solution here is to mass hook APIs listed here; and safely unhook after one of the targets has been hit.

This has historically worked well and has only overhead of 3 x86 instructions post unhooking with Reloaded.Hooks.

The preferred workaround for this (currently employed by Reloaded-II and Ultimate-ASI-Loader).

Tricks

Some tricks you can do in order to work around certain limitations

Avoid Forced Reboot

Tip

The SteamWorks API forces games to reboot if they have not been launched via Steam; this can be problematic for DLL Injection.

  1. Set SteamAppID env var.
  2. Hook steam_api.SteamAPI_RestartAppIfNecessary.
  3. Hook steam_api.SteamAPI_IsSteamRunning.

A combination of these has so far been sufficient; usually games' access to Steam Services are unaffected.

This should only be done if DLL Injection is THE ONLY WAY to get the loader running. Currently no known games require this.

This should be avoided if possible, because launching outside of the Steam client leads to Cloud Saves not immediately syncing.