Skip to content

Rustbeard86/SteamStubRemover

Repository files navigation

SteamStubRemover

A .NET library for removing Steam DRM stub protection from executables. Supports multiple generations of Steam DRM for both 32-bit and 64-bit executables.

Supported DRM Generations

Generation Architecture Description
Gen1 x86 Legacy protection with basic XOR encryption
Gen2 x86 XorStub with XOR-encoded code sections
Gen2Aes x86 AesStub with AES encryption and XTEA DRM DLL
Gen3 x86, x64 Modern protection with TLS callback support
Gen3Plus x86, x64 Latest variant, most common in modern games

Installation

NuGet Package

dotnet add package SteamStubRemover

Direct DLL Reference

Add a reference to SteamStubRemover.dll in your project:

<ItemGroup>
  <Reference Include="SteamStubRemover">
    <HintPath>path\to\SteamStubRemover.dll</HintPath>
  </Reference>
</ItemGroup>

Quick Start

Basic Usage

using SteamStubRemover;

// Remove DRM stub with default options
bool success = StubRemover.RemoveStub(@"C:\Games\SomeGame\game.exe");

if (success)
{
    Console.WriteLine("DRM stub removed successfully!");
    // Original file backed up as: game.exe.original
    // Cleaned file saved as: game.exe
}

With Result Details

using SteamStubRemover;

var result = StubRemover.RemoveStub(@"C:\Games\SomeGame\game.exe");

if (result.Success)
{
    Console.WriteLine($"Removed {result.Generation} DRM using: {result.PluginName}");
}
else
{
    Console.WriteLine($"Failed: {result.ErrorMessage}");
}

Configuration Options

RemovalOptions

using SteamStubRemover;

var options = new RemovalOptions
{
    // Keep the .bind section in the output file (default: true)
    // Note: Some games require .bind section for IAT references
    KeepBindSection = false,
    
    // Recalculate PE checksum after removal (default: false)
    RecalculateChecksum = true,
    
    // Save decrypted payload data to disk (default: false)
    DumpPayloadToDisk = false,
    
    // Save extracted DRM DLL to disk (default: false)
    DumpDrmDllToDisk = false,
    
    // Zero out the DOS stub data (default: true)
    ZeroDosStubData = true,
    
    // Skip PE section realignment (default: true)
    SkipSectionRealignment = true,
    
    // Enable experimental features (default: false)
    UseExperimentalFeatures = false,
    
    // Enable verbose logging output (default: false)
    VerboseOutput = false,
    
    // Remove certificate table / Security Directory (default: true)
    // Fixes signtool error 0x800700C1 when re-signing cleaned files
    RemoveCertificateTable = true
};

var result = StubRemover.RemoveStub(@"C:\Games\SomeGame\game.exe", options);

Simplified Options

using SteamStubRemover;

// Remove stub with specific options using the simplified overload
bool success = StubRemover.RemoveStub(
    filePath: @"C:\Games\SomeGame\game.exe",
    keepBindSection: false,
    recalculateChecksum: true
);

Logging

Capture Log Messages

using SteamStubRemover;
using SteamStubRemover.Logging;

var result = StubRemover.RemoveStub(
    @"C:\Games\SomeGame\game.exe",
    options: null,
    logHandler: e =>
    {
        string prefix = e.MessageType switch
        {
            LogMessageType.Error => "[ERROR]",
            LogMessageType.Success => "[OK]",
            LogMessageType.Warning => "[WARN]",
            LogMessageType.Debug => "[DEBUG]",
            _ => "[INFO]"
        };
        
        Console.WriteLine($"{prefix} {e.Message}");
    }
);

Log Message Types

Type Description
Information General progress information
Success Operation completed successfully
Warning Non-fatal issues encountered
Error Fatal errors that stop processing
Debug Detailed diagnostic information

Output Files

After successful stub removal:

File Description
game.exe The cleaned executable
game.exe.original Backup of the original protected file
game.exe.payload Decrypted payload (if DumpPayloadToDisk is enabled)
SteamDRMP.dll Extracted DRM module (if DumpDrmDllToDisk is enabled)

Complete Example

using SteamStubRemover;
using SteamStubRemover.Logging;

public class Program
{
    public static int Main(string[] args)
    {
        if (args.Length == 0)
        {
            Console.WriteLine("Usage: StubRemoverTool <file.exe>");
            return 1;
        }

        string filePath = args[0];
        
        if (!File.Exists(filePath))
        {
            Console.WriteLine($"File not found: {filePath}");
            return 1;
        }

        Console.WriteLine($"Processing: {filePath}");
        Console.WriteLine();

        var options = new RemovalOptions
        {
            KeepBindSection = false,
            RecalculateChecksum = true
        };

        var result = StubRemover.RemoveStub(
            filePath,
            options,
            LogMessage
        );

        Console.WriteLine();

        if (result.Success)
        {
            Console.WriteLine($"Successfully removed {result.Generation} DRM with: {result.PluginName}");
            Console.WriteLine($"Original backed up as: {filePath}.original");
            return 0;
        }

        Console.WriteLine($"Failed to remove stub: {result.ErrorMessage}");
        return 1;
    }

    private static void LogMessage(LogMessageEventArgs e)
    {
        ConsoleColor color = e.MessageType switch
        {
            LogMessageType.Error => ConsoleColor.Red,
            LogMessageType.Success => ConsoleColor.Green,
            LogMessageType.Warning => ConsoleColor.Yellow,
            LogMessageType.Debug => ConsoleColor.Gray,
            _ => ConsoleColor.White
        };

        Console.ForegroundColor = color;
        Console.WriteLine(e.Message);
        Console.ResetColor();
    }
}

Error Handling

using SteamStubRemover;

try
{
    var result = StubRemover.RemoveStub(filePath);
    
    if (!result.Success)
    {
        // Check the error message for details
        Console.WriteLine($"Removal failed: {result.ErrorMessage}");
        
        // Common failure reasons:
        // - "No compatible remover found for this file."
        //   The file is not Steam DRM protected or uses an unsupported variant
    }
}
catch (ArgumentException ex)
{
    // Invalid file path provided
    Console.WriteLine($"Invalid argument: {ex.Message}");
}
catch (Exception ex)
{
    // Unexpected error during processing
    Console.WriteLine($"Unexpected error: {ex.Message}");
}

Building from Source

Prerequisites

  • .NET 10 SDK or later
  • PowerShell 7.0 or later (for build script)

Build Commands

# Build NuGet package and DLL
.\build-release.ps1

# Build with CLI tool
.\build-release.ps1 -BuildCli

# Build for specific runtime
.\build-release.ps1 -BuildCli -Runtime win-arm64

Output Structure

release/
  lib/
    SteamStubRemover.dll       # Library assembly
    SteamStubRemover.xml       # XML documentation
  cli/                         # (if -BuildCli specified)
    stubremover.exe            # Single-file CLI tool
  SteamStubRemover.1.0.0.nupkg # NuGet package
  SteamStubRemover.1.0.0.snupkg # Symbol package

API Reference

StubRemover

Static class providing the main entry points for DRM stub removal.

Methods

Method Description
RemoveStub(string, RemovalOptions?, Action<LogMessageEventArgs>?) Removes stub with full options and logging
RemoveStub(string, bool, bool) Simplified removal with basic options

RemovalResult

Record struct returned by RemoveStub.

Property Type Description
Success bool Whether removal succeeded
PluginName string? Name of the plugin that processed the file
Generation string? DRM generation that was detected and removed
ErrorMessage string? Error description if failed

RemovalOptions

Configuration options for the stub removal process.

Property Type Default Description
KeepBindSection bool true Preserve .bind section (some games require this for IAT)
RecalculateChecksum bool false Update PE checksum
DumpPayloadToDisk bool false Save payload data
DumpDrmDllToDisk bool false Save extracted DRM DLL
ZeroDosStubData bool true Clear DOS stub
SkipSectionRealignment bool true Skip realignment
UseExperimentalFeatures bool false Enable experimental
VerboseOutput bool false Verbose logging
RemoveCertificateTable bool true Remove Security Directory (fixes signtool re-signing)

Project Structure

SteamStubRemover/
+-- Core/                         # Core library components
|   +-- Crypto/                   # AES and XOR crypto helpers
|   +-- Events/                   # Log message types and events
|   +-- Extensions/               # FileStream extensions
|   +-- PE32/                     # 32-bit PE file handling
|   +-- PE64/                     # 64-bit PE file handling
|   +-- Services/                 # Logging service
|   +-- RemovalOptions.cs         # Configuration options
|   +-- RemoverPlugin.cs          # Base plugin class
+-- Generations/                  # Shared generation types
|   +-- DrmFlags.cs               # Common DRM flag enums
+-- PortableExecutable/           # Shared PE helpers
|   +-- PeHelpers.cs              # Common marshaling methods
+-- Unpackers/                    # Generation-specific removers
|   +-- Gen1/                     # Legacy (basic XOR)
|   +-- Gen2/                     # XorStub (XOR sections)
|   +-- Gen2Aes/                  # AesStub (AES + XTEA)
|   +-- Gen3/                     # Modern (TLS support)
|   +-- Gen3Plus/                 # Latest variant
+-- StubRemover.cs                # Main entry point

Namespaces

Namespace Contents
SteamStubRemover Main types: StubRemover, RemovalOptions, RemovalResult, RemoverPlugin
SteamStubRemover.Logging LoggingService, LogMessageEventArgs, LogMessageType
SteamStubRemover.PortableExecutable PE file parsing: PeFile32, PeFile64, PeHelpers, NativeApi32, NativeApi64
SteamStubRemover.Cryptography AesHelper, StubCryptoHelper
SteamStubRemover.Extensions FileStreamExtensions
SteamStubRemover.Generations.* Generation-specific remover implementations

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors