Pythonでつくったプログラムを公開したいとき、WindowsやMacで手軽に実行できるような形で配布したいこともあると思います。
そんなときは Pyinstaller などのパッケージを使って、OSごとにスタンドアローンな実行形式ファイルに変換すると便利です。
この Pyinstaller ですが、素直にマニュアル通りにコンパイル→ビルドしてしまうと、出力した実行形式(Winだと.exeファイル)がアンチウイルスソフトなどによってウイルス判定されてしまう場合があります。
もちろん、この場合は誤検知(false-positive)になるのですが。
しかし、よく使われているセキュリティソフトでこのように誤検知されてしまうと、配布するのが難しくなってしまいます…。
この記事では、そうした誤判定を避ける方法を解説しています。
記事内容の検証環境:
Windows 10 Pro
Python 3.6 (miniconda環境)
Pyinstaller 4.0
Visual Studio C++ 2015 (vcbuildtools)
Visual Studio Code 1.49.0
Pyinstallerによるバイナリの作成概要
Pythonで作成したプログラムを、OSごとにスタンドアローンな実行形式で配布したいとき、Pythonコードをバイナリの実行形式に変換する方法はいくつかあって、代表的なのは以下のようなプロジェクトです。
- Pyinstaller
- py2app
- cx_Freeze
この中でも最も広く使われているのがPyinstallerだと、管理人は勝手に思っています。
開発もaliveで進んでいて、記事時点だと最新安定バージョンは4.0です。
Pyinstallerを使うときの流れは以下の通り。
- pipでpyinstallerをインストール(pip install pyinstaller)
- 実行形式にしたいコードを指定してpyinstallerを実行(pyinstaller myscript.py)
基本はこれだけ。
実際に使用するときはコマンドにオプションを付けたり、specファイルを編集するなどして、ビルドをカスタマイズします。
ちなみに余談ですが、Anaconda環境でライブラリ満載の状態でビルドすると、アホみたいに大きなexeファイルが出来上がります…。あらゆるパッケージが自動で実行ファイルに詰め込まれるためです…。
ウイルスとして誤判定されるとき
Pyinstallerで実行形式(exeファイル)を無事作成できても、新たな問題に直面することとなります。
以下実際のWindowsの画面。
Trojan:Win32/Wacatac.B!ml…?
トロイの木馬…およよよよ…(白目)
Windows10に標準で付属しているWindows セキュリティ「ウイルスと驚異の防止」機能(Microsoft Defender)により、Pyinstallerが出力した実行形式が駆逐されてしまいました…。
たとえ、このようにMicrosoft Defenderで検知されなくても、他の有償セキュリティソフトに誤検知される可能性があります。
原因
調べてみると、どうやらビルド方法に問題があったようです。
Pyinstallerとしてpypiで配布されているパッケージに入っているコンパイル済のブートローダー(Bootloader)を使用して実行形式をビルドすると、アンチウイルスソフトによってfalse-positive(偽陽性)な判定を受ける場合があるとのこと。
ケースとしてはあるあるな事象のようです。
解決策
Pyinstaller公式ドキュメントにある方法に従って、ブートローダーをローカルの環境でビルドし直し、pyinstallerのインストールをやり直します。
以下ではWindowsを前提に書きます。
開発環境がMacでMac向けの実行形式を作る場合も同様なので、ドキュメントをご参照ください。
Chocolateryのインストール
Visual Studio C++のコンパイラを使用してビルドを行う場合は、パッケージ管理ソフトの Chocolatery をインストールしておきます。
あとでChocolateryを使ってビルドツールをインストールするのに使います。
既にChocolateryを導入済み、またはビルドツールにVC++以外を使う場合は次のステップに移動しましょう。
PowerShellを管理者権限で起動します。
PowerShellを管理者権限で起動するには画像のようにWindowsマークを右クリックすると簡単です。
PowerShellが起動したら、Chocolateryの公式サイトにある1行コマンドを実行します。
「2. Install with powershell.exe」にある、Now run the following command:のテキストボックスから1行コマンドをコピーし、PowerShellコンソールに貼り付けそのまま実行します。
このコマンドは念の為ここにも載せておきます。
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
何も問題なければChocolateryのインストールが完了します。
以下の表示があればOKです。
Chocolatery (choco.exe) is now ready.
chocoコマンドでバージョンを表示させて、インストールが上手くいっているか確認しましょう。
choco
失敗するときは、PowerShellが管理者権限で実行されていることを確認してください。
ビルドツールのインストール
今回はVisual Studio C++のコンパイラを使用するので、pythonのvcbuildtoolsパッケージを使用します。
MinGWでもブートローダーをビルドすることは可能なようなので、既に導入済みの方はMinGWでのビルドを検討してもよさそうです。
必ず管理者権限でPowerShellコンソールを起動します。
このとき、conda環境を使っていれば、condaのPowerShellプロンプトを使用するとよいでしょう。
以下のコマンドを実行し、vcbuildtoolsをインストールします。
choco install -y python vcbuildtools
一度conda の環境を切り替えてから、choco installコマンドでvcbuildtoolsのパッケージをインストールしています。
管理者権限で実行しないと失敗する可能性があるので、注意です
さまざまなパッケージがインストールされるので、いくつものコンソールウィンドウが開いたり、ユーザアカウント制御画面で聞かれたりしますが、何も問題がなければ以下のように表示されるはず。
これでビルドツールのインストールが完了しました。
これを使ってブートローダーをビルドしていきます。
Pyinstallerパッケージをclone→ビルド
pyinstallerパッケージをgit clone します。
git clone https://github.com/pyinstaller/pyinstaller
pyinstaller/bootloader に移動し、下記コマンドで waf を実行します。
python ./waf all
ここで、先ほどの手順でビルドツールが適切にインストールされていなければエラーになります。
上手くいけば下記のような表示になり、ブートローダーのビルドが完了します。
Pyinstallerのインストール
pyinstallerのディレクトリに移動し、pythonパッケージをインストールします。
python setup.py install
Pyinstallerの実行
あとは基本通り、pyinstallerを実行するだけ。
pyinstallerが先ほどインストールしたものであることにだけ気をつけましょう(先祖返りに注意)。
まとめ
Pyinstallerで実行ファイルを作成するとそれがマルウェアとみなされて駆逐されてしまう場合の対処法をまとめました。
Pyinstallerのブートローダーを実行環境でコンパイルしてあげることで、上記事象を回避できるということでした。
プログラミングではセキュリティ対策が欠かせませんが、セキュリティソフト対策も重要ということなんですね。