3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

旧バージョンUnityでビルド時に脆弱性パッチを自動で当てるやつ(CVE-2025-59489)

Last updated at Posted at 2025-10-04

CVE-2025-59489 Patcher ToolをUnityのプロジェクトフォルダに入れて、ビルド完了後に自動実行するスクリプトを書いてみました。

記事を書くほどでもない気がするのでスクリプトだけ貼っておきます。使用方法等はスクリプト内のコメントを参照してください。(iOS/macは非対応です。)

PostBuildPatcher.cs

/// <summary>
/// ビルド終了後に脆弱性パッチを当てるスクリプト by Yoshi3110
/// 
/// 現在はWindowsPCを使用したWindowsビルドとAndroidビルドにのみ対応しています。
/// なお、Androidのキーストア・キーエイリアスの設定は未検証です。
/// 
/// 
/// ー前準備ー
/// 1.このスクリプト(PostBuildPatcher.cs)をAssets/Editorフォルダにコピーしてください。
/// 2. https://discussions.unity.com/t/cve-2025-59489-patcher-tool/1688032 からツールをダウンロードしてください。
/// 3.プロジェクトのルートフォルダにUnityApplicationPatcherをコピーし、必要に応じてフォルダ名をリネームしてください。
/// (CLIツールのパスが <プロジェクトのルートフォルダ>\UnityApplicationPatcher\UnityApplicationPatcherCLI.exe になっていればOKです。)
/// 
/// 
/// ー注意点ー
/// ・このスクリプトは自己責任で使用してください。
/// ・念のため、最初にビルドしたファイルはパッチが正常に当たっているかを確認してください。
///     UnityApplicationPatcherのGUIツールを使ってパッチを試行し、「パッチをスキップ」と表示されれば成功です。
/// ・Androidビルドを行う場合、バンドルバージョンがPlayerSettingsで設定された数値よりも1大きくなります。
/// 
/// </summary>
using UnityEditor;
using UnityEditor.Callbacks;
using System.Diagnostics;
using System.IO;
using UnityEngine;

public class PostBuildPatcher
{

    // Android用の固定値(未検証です)
    private const string KeystorePath = "";
    private const string KeystorePassword = "";
    private const string KeyAlias = "";
    private const string KeyAliasPassword = "";

    [PostProcessBuild]
    public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
    {
        // Unityプロジェクトのルートパスを取得
        string projectPath = Directory.GetParent(Application.dataPath).FullName;
        string cliPath = Path.Combine(projectPath, "UnityApplicationPatcher", "UnityApplicationPatcherCLI.exe");

        if (!File.Exists(cliPath))
        {
            UnityEngine.Debug.LogError($"[PostBuildProcess] CLI not found: {cliPath}");
            return;
        }

        // ビルド種別ごとに分岐
        if (target == BuildTarget.StandaloneWindows || target == BuildTarget.StandaloneWindows64)
        {
            RunForWindows(cliPath, pathToBuiltProject);
        }
        else if (target == BuildTarget.Android)
        {
            RunForAndroid(cliPath, pathToBuiltProject);
        }
    }

    private static void RunForWindows(string cliPath, string pathToBuiltProject)
    {
        string buildDir = Path.GetDirectoryName(pathToBuiltProject);
        string unityPlayerDll = Path.Combine(buildDir, "UnityPlayer.dll");

        if (!File.Exists(unityPlayerDll))
        {
            UnityEngine.Debug.LogError($"[PostBuildProcess] UnityPlayer.dll not found: {unityPlayerDll}");
            return;
        }

        string arguments = $"-windows -unityPlayerLibrary \"{unityPlayerDll}\"";
        RunCLI(cliPath, arguments);
    }

    private static void RunForAndroid(string cliPath, string pathToBuiltProject)
    {
        // pathToBuiltProject はビルド結果の .apk か .aab ファイルパス
        string extension = Path.GetExtension(pathToBuiltProject).ToLower();
        if (extension != ".apk" && extension != ".aab")
        {
            UnityEngine.Debug.LogWarning($"[PostBuildProcess] Not an APK/AAB: {pathToBuiltProject}");
            return;
        }

        // PlayerSettings からバージョン情報を取得
        int versionCode = PlayerSettings.Android.bundleVersionCode + 1;//バージョンコードを大きくする必要がある
        string versionName = PlayerSettings.bundleVersion;

        // CLI引数構築
        string arguments =
            $"-android " +
            $"-applicationPath \"{pathToBuiltProject}\" " +
            $"-versionCode {versionCode} " +
            $"-versionName \"{versionName}\" ";

        if (KeystorePath != "" && KeystorePassword != "")
        {
            arguments +=
           $"-keystore \"{KeystorePath}\" " +
           $"-keystorePassword \"{KeystorePassword}\" ";
        }

        if (KeyAlias != "" && KeyAliasPassword != "")
        {
            arguments +=
            $"-keyAlias \"{KeyAlias}\" " +
            $"-keyAliasPassword \"{KeyAliasPassword}\" ";
        }
        arguments += $"-verbose";

        bool success = RunCLI(cliPath, arguments);

        if (!success)
            return;
            
        // 出力先ファイルのパス推定 (.patched.apk)
        string patchedPath = Path.ChangeExtension(pathToBuiltProject, ".patched.apk");

        if (!File.Exists(patchedPath))
        {
             UnityEngine.Debug.LogError($"[PostBuildProcess] Patched file not found: {patchedPath}");
            return;
        }

        try
        {
            // 元のAPKを削除
            File.Delete(pathToBuiltProject);

            // Patchedファイルをリネーム
            File.Move(patchedPath, pathToBuiltProject);

             UnityEngine.Debug.Log($"[PostBuildProcess] Replaced original APK with patched version:\n{pathToBuiltProject}");
        }
        catch (System.Exception e)
        {
             UnityEngine.Debug.LogError($"[PostBuildProcess] Failed to replace APK: {e}");
        }
    }
  private static bool RunCLI(string cliPath, string arguments)
    {
        UnityEngine.Debug.Log($"[PostBuildProcess] Run: {cliPath} {arguments}");

        try
        {
            var process = new Process();
            process.StartInfo.FileName = cliPath;
            process.StartInfo.Arguments = arguments;
            process.StartInfo.WorkingDirectory = Path.GetDirectoryName(cliPath);
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.CreateNoWindow = true;
            process.Start();
            process.WaitForExit();

            UnityEngine.Debug.Log($"[PostBuildProcess] Finished with exit code {process.ExitCode}");
            return process.ExitCode == 0;
        }
        catch (System.Exception e)
        {
            UnityEngine.Debug.LogError($"[PostBuildProcess] Failed to run CLI: {e}");
            return false;
        }
    }
}

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?