アンチウイルスの魔法の方程式

どんなシステムもベースには独自のアルゴリズムがある。アルゴリズムがなければシステムもない。採用するアルゴリズムの種類はあまり重要ではなく、線形、階層型、決定的、確率型・・・いろいろあるが、どれでもいい。大事なのは、最高の結果を出すために、何らかのルールに従うことだ。

当社製品のアルゴリズムについてよく聞かれるが、特に多いのは、未来の脅威を競合他社よりもうまく検知するうえで、どんなアルゴリズムを使っているのか、という質問だ。

明らかな理由から、当社の魔法の方程式について詳細までお話することはできないが、技術がテーマの今回の記事(これまでの記事で一番専門的な内容のはずだ)では、当社の技術開発室のドアを少しだけ開けて、中の様子を簡単に紹介する。もっと詳しく知りたいという人は、下のコメント欄にどんどん質問を寄せていただきたい。

当社では演繹法によって未知のマルウェアを検知している。全体から入って個々の結論に至るということだ。たとえば、すべてのマルウェアが、x、y、zというアクションを実行するとしよう。あるファイルがx、y、zを実行したとすると、そのファイルに悪意がありそうだ、ということになる。だが、実際はそこまで単純な話ではない。

特定のアクションを実行したからといって、そのオブジェクトをマルウェアだと断定することはできない。結局のところ、どんなコマンドも有益なことを実行するために作成されたのだ

まず、特定のアクションを実行したからといって、そのオブジェクトをマルウェアだと断定することはできない。その最たる例がマスターブートレコード(MBR)へのアクセスだ。このコマンドを使うものがすべてマルウェアというわけではない。平和的な目的でこのコマンドを使うアプリケーションも多いからだ。他のアクションについても同じことが言える。結局のところ、どんなコマンドも「有益な」ことを実行するために作成されたのだ。

つまり、良いものと悪いものを分けるという単純なやり方は、ここでは役に立たない。ただし、無害なプログラムとマルウェアの割合構成を調べるのは効果的だ。当社ではこれをやっている。あるオブジェクトで何が起きているのか、隣のオブジェクトで何が起きているのかを調べ、その結果を分析し、有害/無害の全体的な状況(「味方」の数と「敵」の数)と、その後の処置について、根拠に基づいた決定を下す。

そのために使っているのが、「SR」という慎ましい名前の技術だ。昔、同じような名前の歯磨き粉があったが、間違えないでほしい。当社のSRは「Security Rating(セキュリティ評価)」の略だ。簡単に言うと、SRは多くの枝に分かれた自己学習型の重みづけシステムで、ルールに基づいた評価とエミュレーションのプロセスによって、オブジェクトの本質を正確に見極める。

Kaspersky Labの魔法の方程式:自己学習型の重みづけシステムが、評価とエミュレーションでオブジェクトの本質を見極めるTweet

SRはオブジェクトが生成したイベントの構成と密度、そして表面上の属性(名称、サイズ、場所、圧縮など)を分析する。こうした属性の1つ1つについて、複数のルールを組み合わせて危険度(0~100%)を評価する。最初に作られたルールのセット(今では500以上ある)は、さまざまな系統の80,000種類以上の悪質プログラムを人間の手で調べた結果生まれた。現在はほとんどのルールが自動で作成されており、人間のエキスパートは自己学習型のアルゴリズムを微調整しているだけだ。

テストや管理を簡単にするために、ルールはいくつかのグループに分かれている(「インターネット」「パスワード」「レジストリ」など)。オブジェクトが1つまたは複数のルールに引っかかれば、相応の措置が適用される。

ルールの一番単純な例がこちらだ。

「低レベルAPI “ntdll.dll” 経由でのドライバー読み込み」ルール

API function: NtLoadDriver
Argument 1: *
Argument 2: *
Argument 3…N: *
Assessment: Single operation – 40%, 2-3 operations – 50%, >3 operations – 60%
Harmful: No

「カーネルマシンコード(フック)解析」ルール

API function: CreateFile
Argument 1: Contains ‘ntoskrnl.exe’ entry
Argument 2: *
Argument 3…N: *
Assessment: Single operation – 100%, 2-3 operations – 100%, >3 operations – 100%
Harmful: Yes 

オブジェクトの総合的な危険度は、ルールデータベース全体を使ったチェックで評価された個々の危険度の合計となる。別の言い方をするなら、典型的な人工ニューラルネットワークということだ。たくさんのセンサーから信号を収集して、その質的・数的な特徴を分析し、関連性を調べて危険度を判定する。

こうしてSR技術の活用が2007年に始まった(特許US7530106)。それ以来、当社はこの技術の改良を続けている。お察しのこととは思うが。

当初、一番の問題だったのは、分析対象のファイルが有意でないイベントを大量に生成し、そのせいで、ファイルに悪意があるという誤った結果が出る場合があったことだ。たとえばDelphiアプリケーションを立ち上げると、意味のないイベントが最大500個も生成される。これらはDelphi言語で書かれたアプリケーションすべてに共通の内容で、ファイルの真の意図を読み取れるような情報はまったくない。この「雑音」によってコンピューターのリソースが浪費されるだけでなく、分析がはるかに難しくなってしまう。

プログラムは有意でないイベントを大量に生成することがある。そこで、それを除外する方法を考え出した

そこで、雑音をすべて取り除くフィルターを作成した。通常のルールと違ってブール属性で十分だ。このおかげで、作業は大幅に簡素化され、スピードアップした。結果、ルールにはAPI関数の名称と、その引数のマスクだけが含まれることになった。

たとえば次のような感じだ。

SysAllocString (*,-NULL-,-NULL-)

関数の最初の引数に何らかの意味があり、他の部分はそうでなかった場合、そのイベントは重要でないものと見なされる。

重要でないイベントのフィルタリングルールは、3つの方法で自動生成している。

1つめは、ショウジョウバエ方式だ。開発ツールXを使って、「Hello World」という文字を表示する単純なアプリケーションを準備する。その際には、このツールの一般的なDLLをできる限り使用する。コンパイル済みアプリケーションをエミュレーターで起動して、生成された「ショウジョウバエ的」イベントをすべて「重要でない」フィールドに入力する。

2つめは、パック型ショウジョウバエ方式だ。1つめの方法とよく似ているが、ここではパッカーやプロテクターのふるまいに注目する。このために、アセンブラ言語で書かれたダミーを、さまざまなパッカーやプロテクターとともに処理して、エミュレーターにかける。・・・あとはご推察のとおり、重要でないイベントを除外する。

3つめは統計的な方法だ。安全なファイルと悪意あるファイルの両方を大量に分析し、両タイプのファイルのふるまいで頻繁に確認されるAPI呼び出しを特定する。これは先に挙げた2つを補完する方法であり、ショウジョウバエ的イベントが生成される見込みがまったくない場合に有効だ。この方法の用例としてわかりやすいのは、GUI割り当て関数とメモリ割り当て関数が生成する非重要イベントを特定する場合だろう。

だが、それ(重要でないイベントのフィルタリングルールを自動生成すること)は、一番簡単な課題の1つにすぎなかった。ここからもっと話がおもしろくなる・・・

SRの最初のバージョンは、保護された1台のコンピューター上で動作していたため、実質的に他とのつながりがなかった。これでは全体像を把握できず、どのルールがトリガーされたのかも(それに頻度や正確さも)わからないし、評価をすぐ変更することもできない。まだまだ効果を高める余地があったのだ。

SRのバージョン1は孤立した状態で動作していたが、後続のバージョンはクラウド技術によって強化された

そこで、当社のクラウド技術Kaspersky Security Network(KSN)だ。当時全速力で開発が進められていたKSNには、すでに専門システムであるAstraeaが追加されていた(保護されたコンピューターから送られてくる大量の信号を分析し、マルウェアの世界的状況について合理的な結論を出すシステムだ)。

2009年には、SRの次期バージョンSR2US8640245)をリリースすることができた。SR2はKaspersky Security NetworkAstraeaに統合された。

これで当社はビッグデータを手に入れるとともに、そのデータを掘り下げて分析していくことが可能になった。セキュリティ業界において成功をつかむための魔法のレシピだ!

まとめると、(1)死んだ(効果のない)ルールを削除する、(2)ルールを一時的に無効にする、またはテストする、(3)特殊な係数を使ってルールの評価をほぼリアルタイムで修正する、ことが可能になった。さらに、係数データベースのサイズは信じられないくらいに小さい(キロバイト単位)。このデータベースのアップデートは、2009年当時でさえコンピューターのインターネット接続にほとんど影響しなかった。

Astraeaによって、危険度を計算するための統計フレームワークも広がり、計算には各種エミュレーターの信号だけでなく、KSNに接続されたその他多数のセンサーが発する信号も使われるようになった。また、過去にクラウド(KSN)で下された判定も利用できるため、エミュレーションのプロセスを省くことができる。さらにもう1つ、うれしいボーナスがある。まだデータが少ない(が、それでも怪しい動きをする)未知の「種」を、ストリームから確実に選び出し、人の手で分析できるのだ。

本当に重要なのは、Astraeaがルールを自動的に修正する点だ。人間のエキスパートが必要になるのは、適用される数学モデルの有効性を定期的に評価するときと、それを最適化するときしかない(特許出願US20140096184)。

賢い技術は自分で仕事をかたづける。 #Kaspersky Lab の技術は人間の手を借りず未来の脅威と戦うTweet

グローバルなビッグデータを活用できるようになったことで、昔からの課題を解決する新しいアイデアがただちに浮かんだ。まずは誤検知の問題だ。

当社は、製品で初めて誤検知が見つかったときから、SRを使って誤検知に取り組んできた。だが、誤検知に関して本当の意味で前進があったのは、2011年のことだった。誤検知を一気に削減可能な新機能をいくつか公にしたのだ。

正規ソフトウェアがまったく無害な目的で実行するアクションも多い。たとえば、インストーラーはSystem32フォルダーのファイルを削除する。この動作の評価を自動調整していては、名誉を不当に傷つけることになり、真の悪意を見落としてしまう。一挙両得というわけにはいかないので、妥協が必要だ。そこで、危険度の計算のメカニズムを3つの部分に分けることにした。

1. 先ほど説明した計算:そのふるまいが危険で、発生頻度が高いほど、危険度の評価が高くなる。
2. ある種のホワイトリストルール:具体的な状況やファイルに適用される通常ルールのアクションを、無効化または修正する。
3. 正規アプリケーションの検知ルール:正規アプリケーションの典型的なふるまいが見られる場合は危険度を下げ、場合によっては安全という評価を下す。

例:

「レジストリキー “autorun”の作成」ルール 

API function: Registry: establishing the meaning of the parameter (RegSetValueEx)
Argument 1: Contains entry
‘RegistryMachineSoftwareClasses*shellexContextMenuHandlersNotepad++’
Argument 2: *
Argument 3…N: *
Evaluation: Single operation – 1%, 2-3 operations – 1%, >3 operations – 1%
Harmfulness: None

この例では明らかにレジストリキーにアクセスされていることがわかるが、これは単にNotepad++がDLLを渡しているだけだ。ルールの引数はFalseを削除するが、メインのルールは一定であり、このキーを変更しようとする別の試行があると、意図されたとおりに動作する。

2011年には、さらに別の便利な機能を導入した(我々は無駄な時間を過ごすことなどない)。

先ほど触れたように、SRではルール同士が連携せずに動作していた。そのため、ファイルを読み込むファイルをディスクに保存 – Autorunキーに追加、といった複雑な相互依存性を調べることができなかった。だが、そのような相互依存性を追跡できれば、個々のイベントの危険度を合計しただけの評価よりも正確な評価が可能になるかもしれない。そこでSR2では、イベントの相関付けを可能にして、未知のマルウェアをさらに正確に検知することを目指した。

我々はこれを2つの方法で行った。

未来の脅威と有利に戦うためには、イベントの分析だけでなく、イベントの関連付けが欠かせない

1つめの方法として、ルールのグループか個別のルールかをORANDで決定するビットマスクを作成した。主な記述は、ふるまいの分類のビット索引だ。元々、ふるまいの詳細に基づいてマルウェアをクラスタ化するために考えられたものだが、同様のアプローチを危険度評価の改良にも適用できる。実際に、マスクを使うことで(RULE76 or RULE151)や(RULE270 or RULE540)といった関数を実装できる。こうしたマスクの良いところは、コンパクトさと動作の速さだ。柔軟性に欠けるのが難点だが。

2つめの方法は、SRの計算の後に全体分析を実施する特別なスクリプトの開発だ(特許US8607349)。このスクリプトは、個別に開始することも、ルールがトリガーされたときに開始することもできる。以前トリガーされたルールやルールのグループに関する統計が蓄積されたデータベースに、各スクリプトがアクセスできる。その結果、次の3つが可能になった。(1)サブプログラムの条件付け、計算、循環、有効化といった複雑なロジックを使用する、(2)ニューラルネットワークを最大限に活用する、(3)スクリプトを使用して、より正確なSR評価だけでなく、後続のスクリプトに適用可能な新しい情報を得る。

たとえば、10個のルールを分析した結果、最初のスクリプトが「アプリケーションが他のプログラムのパスワードを取得しようとしている」と判断したとする。2番目のスクリプトは「アプリケーションが何かをインターネットに送信する」と判断した。一方、3番目のスクリプトは「アプリケーションがパスワードに興味を示し、かつ何かをインターネットに送信した場合、危険度の評価が+100%となる」と判断する。

さらに、スクリプトはどんなルールとでも使用でき、最後のルールが何らかのアルゴリズムのトリガー的なものになる。

以下がスクリプトの例だ。

VarS : string;begin
if copy(ExtractFilePath(APIArg[1]), 2, 100)=’:’ then begin
AddSR(20);
s := LowerCase(ExtractFileExt(APIArg[1]));if S = ‘.exe’ then AddSR(40);
if S = ‘.com’ then AddSR(50);
if S = ‘.pif’ then AddSR(60);
if S = ‘.zip’ then AddSR(-20);
end;
end.

この例では、スクリプトがファイル作成の動作を評価している。ファイルがディスクのルートで作成されたことが確認されると、SRでの危険度評価は20%となる。さらに、ファイルの拡張子に応じて、「+」か「-」の符号で評価が追加される。

この例から、スクリプトの主な利点がよくわかる。さまざまチェックの結果に基づいて個々のSR危険度を割り当てることで、関数の引数について複合的な評価を実行できることだ。また、危険度評価を上げるチェックもあれば、下げるチェックもあるため、複合的なチェックと複合的な分析が可能となり、検知ミスのさらなる抑制を見込める。

ここからは少し未来の話を・・・

当社はすでに2015年版の個人向け製品ラインを世に送り出し始めている。長きにわたって考え抜いた末、ローカルのSRを廃止して、危険度の計算をすべてクラウドに移すことにした。

このアプローチは、多くの利点をただちにもたらす。分析の質を落とすことなく、コンピューターで必要とされるリソースを減らせるのだ。処理はすべてクラウドで実行されるのだから。判定の配信の遅れについては、埋め合わせできるだろう。・・・実際のところ遅れはほとんどない。1,000分の1秒にも満たない時間なので、特別なソフトウェア以外にはわからないだろう。ユーザーの皆さんも気づかないはずだ。

これでおわかりいただけたと思う。Coca-Colaのような「秘密の」魔法の方程式を、6,000文字程度で簡単に説明した。だが、もちろんこれは氷山の一角だ。この技術を詳しく説明しようとしたら、数日はかかるだろう。とにかく、もっと詳しく知りたい人は下のコメント欄で知らせてほしい。

@e_kaspersky のブログで一番技術的な内容の記事。一読の価値ありTweet

 

コメントを読む 0
コメントを書く