見出し画像

Steamで配信したゲームがウイルス検知された話

Dungeon Antiquaというゲームを2024/10/10にSteamでリリースしまして、その後も不具合修正や要望の多かった機能の追加などアップデートを重ねていたのですが、あるタイミングでのアップデートにより突然ゲームがウイルス検知されるという事案が発生し、そこから地獄を見ました。

もしかして今後同じ目に遭う人がいるかもしれないので、体験記としてまとめておきます。

問題発生〜暫定対応まで

  1. 12/6アップデート以降、ウイルス検知発生のXのポストなどを見かけるようになる。調べるとPyInstallerでexe化したファイルにはありがちなことらしい(詳しくは次項)。とりあえず連絡が取れた方にウイルス検知からの除外設定を個別にお願いしたり、Steamにお知らせを掲示したりした。

  2. 12/11早朝、Steamサポートから「あなたのゲームがウイルスであるという報告が複数寄せられたため、販売を停止した。対策をとらない場合ストアから削除することになる」という連絡が来た。

  3. しばらくネットで探せる限りの情報を拾っては対策を試みたりしたが(詳しくは後述)解決方法がわからず、やむを得ずサポートに「ウイルス検知前のバージョンに戻す。またウイルス検知ソフトのメーカーに対してソフトがウイルスの検知判定を外してもらうよう連絡した」と申告して、12/18に12/6アップデート前バージョンでの販売再開を許可してもらった。

  4. とりあえず最悪の展開(ストアから削除)は免れたが、このままでは一生アプデできなくなる。特に年明けにはゲームのプレイエリアを拡張する大型アップデートを計画していたためこのままというわけにはいかない。

(12/23 10:52追記補足)
Windowsには標準でWindows Defenderが入っていますが、本件に関しては「Windows Defenderでは検知されなかったが、Norton等を入れているユーザーさんの環境で誤検知された」という事案になります。

Steamに掲載したお知らせ。みんな見ていたかは知らない。

なぜウイルス検知されたのか?

Dungeon AntiquaはPyxelというレトロゲームエンジンで制作しています。
そのPyxelは名前が示唆するとおりプログラム言語としては「Python」を用いており、実行ファイルの生成にはPyInstallerを使っています(PyxelのCLIでラッピングしているのでなんとなく使っていると気づきませんが)。

前述の通り、PyInstallerで生成したファイルがウイルス(トロイの木馬)検知されるのは「あるある」なようです。
なぜそんなことになるのか? 私は素人なので、以下ChatGPTさんによる理由の解説です。

1.自己展開型実行ファイル
PyInstallerで生成された実行ファイルは、内部にバイトコードやライブラリを含み、それを実行時に展開・実行します。
この挙動がマルウェアやウイルスの自己展開型プログラムと似ているため、セキュリティソフトが疑わしい動作とみなすことがあります。
2.コードの暗号化・難読化
一部のPyInstallerオプションでは、バイトコードを暗号化または難読化します。
これがマルウェアが自身のコードを隠蔽する手法と酷似しているため、誤検知が発生しやすくなります。
3.一時ファイル展開
実行時に一時ファイルを生成してコードを実行する挙動が、マルウェアの典型的な動作と一致することがあります。
4.悪用事例
PyInstallerは便利なツールであるがゆえに、悪意のあるPythonスクリプトをスタンドアロン実行ファイル化する目的でも使用されることがあります。
このため、PyInstaller製の実行ファイル自体が警戒されやすい傾向にあります。

ChatGPT 4oさま

対策と試行錯誤

ではどうやってこの誤検知を防ぐか、ですが、いろいろな情報があり、どれも試すか検討はしました。

ちなみに前段として、私のWindows PCにはアンチウイルスソフトは何も入れていなかったのですが、この検証のためにNortonを購入する羽目になりました。

bootloaderを自前でビルドする

ブートローダー(bootloader)とは、スタンドアロン実行ファイルの起動部分を担っており、Pythonのバイトコードや依存ライブラリをロード・展開してスクリプトを実行する役割を持っているプログラムです。

これを「自前でビルドする」がなぜ対策になるかというと、デフォルトのブートローダーは多くのアンチウイルスソフトウェアに「既知の脅威」としてシグネチャが登録されている(ウイルスっぽい形状として認識されている)のに対して、自前でビルドするとビルドする環境に依存して生成されるバイナリの形が変わるので、アンチウイルスソフトウェアに登録されているのグネチャとマッチしづらくなるということのようです。

この方法が有効だった、という情報は多かったので真っ先に試しましたが、私の場合はダメでした。

アンチウイルスソフトへ申請する

「オイコラ誤検知じゃボケェ!しっかり精査しろや!」とウイルス検知ソフト様にお願い奉るという方法ですね。

受理してもらえれば確実に解決はするでしょうが、果たしてこの申請をどの程度真摯に拾ってもらえるのか、またどのくらいの時間がかかるのかはこちらから見ると完全にブラックボックスです。

なので申請はしたものの、1日でも早く解決したいのに確実性もスピード感もわからない(そもそも連絡来るのかもわからない)ものをただただ待ってはいられないわけで・・

PyInstallerやPythonのバージョンを最新に保つ

こういうことはお約束的に、AIさんがアドバイスしてきたり何がしかの記事に書いてあったりするわけですが、私の場合はむしろウイルス検知前にPythonの実行環境を入れ直したりした経緯がたまたまあったので、「ということはダウングレードすればとりあえず誤検知回避できるかも?!」と思って試しました。

もちろん無駄でした。

コードサイニング証明書を導入する

Windowsの実行プログラムをネット上などからダウンロードしたときに「このアプリは不明な発行元です」みたいな警告を見たことがありませんか?

コードサイニング証明書は、ソフトウェアの提供元が「信頼できる発行元によって作成され、改ざんされていないことを保証する」もので、発行機関に申請して取得した組織だけが保有するコードサイニング証明書を生成済みのexeファイルに付加することでデジタル証明された状態となります。

たしかに、「これは株式会社xxの製品です」と高らかに謳っているウイルス汚染ソフトというのは考えづらいので、ウイルス検知ソフトも除外条件として設けている可能性は高そうに思えます。

調べてみると、比較的安いタイプ(発行元によって価格が異なったり、OV証明書とEV証明書という2段階の信頼度があったりする)でも3年間で18万円などの費用がかかるようで、少し躊躇しました。

ただそれでも、これで解決するなら永遠に解決しないよりマシですし、今後他のソフトウェアを開発する上でも信頼度を上げることができます。
というわけで買いました。

・・が!

これは単に私の調査不足だったのですが、発行元サイトのFAQに「早ければ申請後数営業日で発行できる」とあったのでそれならばと購入に踏み切ったところ、これが誤読でして、「事前審査」と「本審査と発行の手続き」があり、前者が数営業日で終わるというだけの話でした。
事前審査が終わった段階で担当者の方に聞いたら、「早くて3週間、長いケースだと2ヶ月くらいかかりますね」と言われてしまい絶望しました。

ソースコードから怪しそうな処理を見つけて変更する

この時点で私の怒りとストレスはピークに達し、日中庭に出てはうろうろと歩き回り、呪詛の言葉を呟き木札を噛むなどしていましたが(嘘)、冷静に考えてこれまでPyxelで作ったプログラムが全てウイルス検知されたわけではないので、結局はプログラムの中身次第でもあるということになります。

つまり誤検知とはいえ、どこかしら「Dungeon Antiqua」にトロイの木馬に近い振る舞いがあるということで。
改めてトロイの木馬の挙動の特徴を調べたところ、以下のものがあるようです。

  • 情報窃取: ユーザーのパスワード、クレジットカード情報、個人情報を収集。

  • バックドアの作成: 攻撃者が遠隔でコンピュータを制御できるようにする。

  • システムへの損害: ファイルの削除、システムの破壊などを行う。

  • スパムの送信: コンピュータをスパム送信に利用する。

  • マルウェアの配布: 他のウイルスやランサムウェアをインストールする。

心当たりがあるとしたら「ファイルの削除、システムの破壊などを行う」でしょうか。
Dungeon AntiquaはRPGなのでプレイヤーのセーブデータをPC内に保存しますが、そのセーブデータを消去する機能というのもゲーム内にあり、具体的にはセーブデータのローカルファイルを `os.remove()` で削除していました。

Pythonのosライブラリはその名の通り、os標準のファイル操作機能などを多く有しており、もしかすると危険とみなされる要素あるかもなぁ、と感じたので、`os.remove()` はダミーファイルで上書きする=標準のopen()関数を使用した処理に変更し、またセーブデータのパス取得にも`os.path` を使っていたので、osライブラリを排除するためにpathlibライブラリを使ったコードに切り替えたりしました。

結論、私の場合これが効きました。

一度ウイルス認定されたファイルが拒否されつづける問題

しかし問題は終わらない。

対策実施済みの「dungeon-antiqua.exe」を個別にスキャンすると、「問題は検出されませんでした」と表示されるようになったのですが、このファイルをDropboxとかにアップしてまたダウンロードしようとすると「権限がありません」といったエラーが出て、ダウンロードが強制的に拒否されるのです。

Steamにアップしたとしてもこうなります。

こんなん見ても大半の人は「??」となるに違いないSteamのエラー

どうやら、ウイルス検知ソフトは「ウイルス(と奴が信じているもの)」の発生元のURLやファイル名なども記憶しており、中身が変わってもそこからのダウンロードを拒否するようになっているようなのです。

試しにPyxelの「Hello world」みたいなスカスカのプログラムを「dungeon-antiqua.exe」という名前に変更して、同じURLからダウンロードすると拒否されました。

真に恐れるべきは有能な敵ではなく無能な味方である、とはこのことか。
仕方ないので実行ファイル名を「dungeon-antiqua-v2.exe」に変更しました。

ゲームの起動ファイルはSteam上で設定/変更できるのですが、リアルタイムに全プレイヤーの環境に反映されるわけではないので、どうしてもタイミングによっては「起動ファイルがありません」とかいう無様すぎるエラーが出てしまったりします。

事前にSteamサポートに相談したところ「うん、起動ファイルは設定で変えられるよ。でもプレイヤーに混乱を招くかもしれないから、あんまりやるべきじゃないね」みたいな回答が返ってきてしまったのですが、んなこたぁこっちも知ってんだよ。

で、泣く泣くまたストアページに訳の分からないアップデートの注意書きを入れて対処することにしました。

Steamに掲載したお知らせ2、これもみんな見ていたかは知らない。

そして最後に念のためもう一度、と思ってサーバーにアップしてダウンロードをテストしたところ、また既知の脅威扱いでブロック発生。

なんでやねん。。。
ともう何度目とも知れない絶望を味わいかけたのですが、ここまでの何十回ものテストにより、どうやらウイルス検知ソフトはファイルの外観面でも類似判定的なものをしているらしいことがわかってきていたので「もしかしたらアイコンちょっと変えたら通るんじゃ?」と閃き、アイコンのファイルを左右反転させるという謎すぎる対処を行ったところ、ようやくブロックが止まりました。ばんざい!!

これが悪いタイプの妖精(N○rton氏談)


これは良いタイプの妖精(N○rton氏談)

おわりに

本当に酷い目にあいました。
これまでの制作のどの断面よりもこの問題が一番(精神的にも)キツかったです。

しかし人が精魂込めて作った制作物を「ウイルスだ」と勝手に判定して販売・流通を妨害してしまうって、アンチウイルスソフトってなかなかな権力の持ち主ですよねえ。

痴漢冤罪にあった人の気持ちがちょっとだけわかる気がしちゃいました。(まぁそれは深刻度がさすがに全然違うか・・)

それでは良き年末年始を!

いいなと思ったら応援しよう!