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;
}
}
}