VirusTotalのAPIを利用して複数のファイルを一括でスキャンする処理をbashで書く

# ファイルを複数のアンチウィルス製品でチェックするのに VirusTotalは便利だけれど、複数ファイルを手作業で検査するのはめんどくさい……

出所が不明なファイルの安全性を確認するのに VirusTotal を使うのは普通の作業だと思いますし、また一般向けにリリースするバイナリを複数のアンチウィルス製品で事前にチェックする場合にも大変便利です。VirusTotal はオンラインのサービスにブラウザからアップロードするだけで60種類以上のウィルス対策ソフトで検査した結果が一覧で見れるのですから、これはとても便利です。
https://www.virustotal.com/ja/

VirusTotal自体は2012年にGoogleの傘下となりましたから、サービス自体は信頼してよいはずです。(ただし社外秘とか、関係者外秘のファイルをこういうところにアップロードしてはだめなことは言うまでもありませんね）

しかし検査したいファイルがたくさんあると、これを手作業で検査するのはイヤですよね。ブラウザでファイルを一つづつ指定してチマチマやるのは絶対にめんどくさい。そんなときに VirusTotal API を利用すると、手作業でチマチマやらずに済みます。
https://www.virustotal.com/ja/documentation/public-api/

そこで、ここでは bash のスクリプトで、VirusTotal API を利用してファイルを一括でスキャンしてもらう処理を書いてみることにします。

# まずは仕様の確認から
まずはファイルスキャンに関するAPIの仕様を確認してみましょう。
https://www.virustotal.com/ja/documentation/public-api/#scanning-files

するとAPI経由でのスキャンは、ファイルサイズが 32MB までに制限されている旨が記載されています。Web UI からのスキャン時のファイルサイズでは 64MB までOKのようですから、API経由のほうが上限が小さいことに注意します。

そして curl を利用した例が出ています。これをベースにして bash から呼んでやればよさげです。ただしこのときに API_KEY を付与してリクエストする必要があります。

では、API KEY について調べてみると……ここらへんのページにいろいろ説明がありますので、ここでは省略します。

http://www.morihi-soc.net/?p=600
http://blog.daruyanagi.jp/entry/2014/10/24/025219

また、実際に API KEY を取得してみると、API の利用は１分間あたり４回、などの制限値が明示されていました。

そこでとりあえず１分４回の制限範囲でファイルをバッチ処理的に VirusTotal に投げるようにスクリプトを作ってみます。


なお、現在の実装では１日あたりの上限値の超過チェックを行っていないので、あまりに大量すぎるファイルを食わせると、どこかで破たんします。今回の実装は、せいぜい数十個程度のファイルを一括で投げたい場合に利用するのに向いています。

# 実装

必要最低限の実装としては、こんな感じ。curl と jq を使っていますので、これをインストールしておく必要があります。

jq が無い場合は "jq ." の部分を抜けばOKです。jq は json の整形のみに使っていますから、整形する必要がなければ不要です。

API Key は実際に取得したものを記載して利用する必要があります。

```bash:virusscan.sh
#!/bin/bash

VT_API_KEY=[APIKEYをココに書く]
SLEEP_WAIT=15

while read filename
do
  time_start=$( date +%s )
  curl -F "file=@${filename}" -F apikey=${VT_API_KEY} https://www.virustotal.com/vtapi/v2/file/scan  | tee --append virusscan.json
  time_end=$( date +%s )

  # 15秒おきにスキャン対象のファイルをアップロードしたいけれど、
  # 直前のアップロードに掛かった時間は差っ引いてウェイトを入れるようにする
  next_wait=$(( SLEEP_WAIT + time_start - time_end ))
  (for waitcount in $( seq ${next_wait} ) ; do echo -n "." ; sleep 1 ; done ; echo "") > /dev/stderr
done
```

動作確認は Bash on Windows の Ubuntu 14.04 LTS で行っています。この理由は、私が検査したかったファイルが Windows 向けのバイナリだったからです。ただし curl と jq さえあれば、どの環境でも動くはずです。

また実行結果はホームディレクトリの virusscan.json に追記していきます。(Windowsのホームディレクトリでは無い点に注意が必要）

そしてこの処理で行えるのはあくまでファイルを VirusTotal に投げるだけの処理です。実行結果は別途取得せねばなりません。

実行結果を別途取得する処理は追々実装することにします。

# 使用方法

```ls *.exe | virusscan.sh``` のように、検査対象のファイル一覧を標準入力から渡せばOKです。


# 実行結果

virusscan.json にファイルごとに以下のような形式で実行結果が追記されていきます。ただしこの形式は jq でフォーマットを整形しています。jq を用いない場合は改行無しでサーバから帰って来た結果がそのまま出力されますので、可読性があまりよろしくないのです。なお、この処理ではあくまでキューに投げ込んでいるだけですから、実際の結果を見たいならは、現時点ではとりあえず permalink の URL でブラウザで閲覧するなどの作業が必要です。

```json
{
  "verbose_msg": "Scan request successfully queued, come back later for the report",
  "md5": "2531a013011a08936c2a8b7e7f0e8123",
  "permalink": "https://www.virustotal.com/file/24998e534d79c7803cf62a0105235dc319401c8857e4ab1a0a0094987fec72ae/analysi
s/1492482984/",
  "sha256": "24998e534d79c7803cf62a0105235dc319401c8857e4ab1a0a0094987fec72ae",
  "response_code": 1,
  "resource": "24998e534d79c7803cf62a0105235dc319401c8857e4ab1a0a0094987fec72ae",
  "sha1": "3eba96724d20f8f1dcd059fbac70df810fb79954",
  "scan_id": "24998e534d79c7803cf62a0105235dc319401c8857e4ab1a0a0094987fec72ae-1492482984"
}
```