リー先生の手法は、間接ジャンプ命令のアドレスと、その飛び先アドレスと、分岐予測機構と同様に、その命令に至る直前の何個かの条件分岐命令の条件成立、不成立のヒストリをシグネチャとして用いる。プログラムが正常に動作している状態で、プログラム中の全ての間接ジャンプ命令に対して出現したシグネチャを学習して記憶しておき、アタックが発生しうる通常の稼動状態で、この記憶したシグネチャと異なるシグネチャが出て来たら、プログラムが書き換えられたと判断する。

アタックが無くても動作状態によっては学習していないシグネチャが出て来る誤検出と、アタックがあっても、運悪く学習したのと同じシグネチャになり検出漏れになるという可能性も皆無ではないが、これは、泥棒の侵入を完全にシャットアウトする防犯システムがないのと同じで、セキュリティーは高まるが、完璧ではないと考えておく必要がある。

原理は良いとして、何個くらいのシグネチャを学習する必要があるのかが問題であるが、SPECマークのプログラムを調査した結果では最大でも3万個程度で良いという。間接ジャンプ命令が出てくるたびに3万個の学習したシグネチャのどれかと一致するかという比較を、まともにやろうとすると大変であるので、ブルームフィルタ(Bloom Filter)という手法を使う。

ブルームフィルタは、端的に言うと、シグネチャをハッシュ関数を通してビット数を圧縮し、それをインデックスとしてメモリをアクセスする。メモリは、最初はゼロクリアして置き、学習時には、出て来たシグネチャに対してアクセスされたメモリに"1"を書き込む。そして稼動時には、メモリを読んで"1"であれば学習したシグネチャ、"0"であれば未知のシグネチャと判断する。ハッシュを使っているので、ここでも誤検出の可能性があるが、最大でも3万個のシグネチャの記憶に対して128Kとか256Kのアドレスがあれば、元々完璧な判別が可能という性質のものではないので、実用上問題はない。

これで、3万個のシグネチャを総当りで比較するという作業は、ブルームフィルタのメモリをアクセスするという作業に簡略化されたが、リー先生は、更に分岐予測機構を利用することを提案している。分岐予測機構は過去の成功した分岐先をだけを記憶しているので、分岐予測が成功した場合には、その分岐先アドレスは書き換えられてはいない。従って、ブルームフィルタを読むのは分岐予測が失敗した場合だけで良い。

今のプロセサでは、分岐予測が外れると、予測機構は「私のミスでした。メモリに書いてあるプログラム様が言われるのが正しいです」と引き下がってしまうが、悪意をもってプログラムの書き換えが発生する環境では、「待てよ、もしかしたら私のミスではなく、プログラムの方が書き換えられてるんじゃないの」と考えて、ブルームフィルタ様にどちらが正しいかお伺いを立てるというやり方にするわけである。

異常な分岐検出の概念図

命令が書き換えられないように保護されている環境では、これでデータ書き換えに起因する殆どの異常動作を防ぐことができそうであるが、命令の書き換えが可能、あるいは、データを命令として実行できる環境では、メモリの読み書きを行うロード/ストア命令に対しても同様な異常動作の監視を行う必要がある。しかし、こちらの実現方法については、まだ、研究中とのことであった。

技術的には非常におもしろい方法であるが、プログラムごとにシグネチャを記憶したブルームフィルタのパターンを作る必要があり、実行するプロセスがスイッチするたびにシグネチャテーブルを入れ替える必要がでる。256Kbitのブルームフィルタの場合は32KBの情報で、VMの切り替え程度の情報量であるので、やってできないほどのデータ量ではない。

しかし、ソフトごとのシグネチャを各ユーザが個別に作るのは現実的にはないので、プログラムのバイナリと一緒に提供される必要がある。そのためには、同一のバイナリが使えるCPU間ではブルームフィルタのメモリ容量やハッシュ関数が同じでないと困るなどの問題が考えられ、実用的に普及させるには更に多くの課題がありそうである。