messyなkitchenなブログ

ただひたすらに散らかった台所や人生やその他を晒す。

MENU

PyInstaller で実行ファイルを作ったら Symantec に叱られる件

Python スクリプトを PyInstaller を使って実行ファイル化したら Symantec に叱られた。
これを解決するまでをメモしておく。

ことの始まり

Python スクリプトで作成したツールを他の Windows PC でも使用したい、という要求が発生しました。

対象の PC に Python 実行環境が入っていなくても、実行ファイル化すれば簡単に解決しそうです。(←このときはまだ、"かんたん"だと思っていました・・・ )

調べてみるといくつかの方法が見つかり、その中から PyInstaller を使用してみることにしました。

実行ファイル化は、たとえば次のようなコマンドを叩きます。

> %localappdata%\Programs\Python\Python37-32\Scripts\pyinstaller.exe SampleApp.py --onefile --noconsole 

これで、スクリプトファイル SampleApp.py から、実行ファイル SampleApp.exe への実行ファイル化はできました。
だがしかし、めでたしめでたし、とはならず・・・

起こった問題

実行ファイル化は成功するのですが、ウイルス対策ソフトである Symantec が「怪しいヤツ、発見、はっけん!!」とか騒ぎ、「けしからん!」と叱られ、生まれたばかりの実行ファイルが抹消されるという悲劇が起こりました。

いろいろ足掻いてみる

Symantec の暴挙をどうにか回避できないか、試してみました。

  • 単一ファイル化 (--onefile) をしないと、消されない。
  • デバッグ情報を一部付与する (--debug=bootloader) と、消されない。
  • PyInstaller のバージョンを下げる (> pip install pyinstaller==3.4) と、消されない。

どうやら、PyInstaller に含まれる bootloader に対して、Symantec が騒ぎ立てる様子でした。

PyInstaller の bootloader をリビルドする

もう少し調べると、PyInstaller にはビルド済みの bootloader が含まれているようです。
Windows の場合は run.exe, run_d.exe, runw.exe, runw_d.exe がそれぞれ 32bit版、64bit版。

つまり、これらをビルドし直したらバイナリが変化するので、もしかしたらウイルスだと判断されなくなるのではないか?ということです。

ソースコードを入手する。ここ

解凍し、bootloader フォルダへ移動する。

ビルド実行する。

> python ./waf distclean all

ビルドが成功すると run.exe, run_d.exe, runw.exe, runw_d.exe が生成される。

上記 4ファイルを Python37-32\Lib\site-packages\PyInstaller\bootloader\Windows-32bit\ へコピーする。

ことの終わり

上記の手順で bootloader のバイナリを差し替え、再び実行ファイル化を試しました。

...

...

... 実行ファイル化、成功。Symantec も騒がない!!

生成された実行ファイルの起動も、期待する動作も問題ありませんでした。

過去にどのような経緯があってウイルスだと検出されるようになったのかまでは調べませんでしたが、これで Python スクリプトの実行ファイル化は大丈夫そうです。

tips

tips 1: ビルド時のエラー対策

bootloader のビルドには、Cコンパイラが必要です。
コンパイラの環境によっては、ビルド時の warning がエラーとして扱われてしまって、ビルドが停止します。

これを回避するために、wscript ファイルを修正します。

-Werror を削除。

ctx.env.append_value('CFLAGS', ['-Wall',
# この行をコメントアウト            '-Werror',
                                '-Wno-error=unused-variable',
                                '-Wno-error=unused-function'])

tips 2: Cコンパイラの導入

自分の環境に Cコンパイラが入っていなかったため、予めフリーのものをインストールしました。

今回は MINGW 32bit のオフラインインストールを実施。

パッケージをダウンロードする。

パッケージを解凍してできた mingw32c:\ へ配置する。

環境変数を設定する。

> set mingw_home=c:\mingw32
> path=%path%;%mingw_home%\bin