キーロガーというよりも、むしろプロセスの隠蔽方法や、ロギングする データの取得方法についてのあれやこれやといったことをまとめようかなと思いこのページを作りました。ちなみにこの文章は、あくまでまとめのページであ り、プログラムなどの解説は含んでないので、ご了承ください。
例えば、キーボードの入力を取得するAPIは多々ありますが、自らの プログラム(もしくはWindow)が、フォーカスを失っている状態でも、キーボードの入力を取得してくれるようにするためにはどうすればよいでしょう。 もっともシンプルな方法はキーボード入力取得のAPIを使用することです。
SHORT GetAsyncKeyState(
int vKey
);
このAPIは、自らのプログラムのフォーカスの有無にかかわらずに、 正確にキーを取得してくれます。このAPIを利用することによって、もっともシンプルなキーロガーを作成することが可能です。
上記のプログラムは、「test.txt」というファイルに、キー ボードのログを保存します。ただし、このプログラムにはいくつもの欠点があります。まず、必ずしも正確にキーボードの入力を取得してくれるわけではないと いう点です。これは、GetAsyncKeyStateの仕組みです。if分岐で0x8000との論理積を評価した場合、 GetAsyncKeyState はこのAPIが呼び出されたまさにその瞬間にキー入力があったかどうかを判定することになります。プログラムの中でwhileループのsleep時間は 100m/sです。つまり0.1秒であり、その0.1秒の間にキーが押されて離された場合、GetAsyncKeyStateはそのキー入力を取得するこ とができなくなります。あくまでもGetAsyncKeyStateが呼び出された瞬間にキーが押されているのかどうかの判定なので、 GetAsyncKeyState が呼び出されていない時(例えばsleepのウェイト中など)にキー入力があった場合は、そのキーを取得することができません。
それを解決するために、GetAsyncKeyStateとのif分 岐での論理積に0x0001を設定します。つまり上記のプログラムのGetAsyncKeyStateの0x8000の部分を
if(GetAsyncKeyState('A') & 0x0001){ fputc('A', fp), fflush(fp); }
と変更します。0x8000を指定すると、APIが呼び出された瞬間 のキーの状態を監視しますが、0x0001を指定すると、呼び出されるまでに入力されたキーの状態を取得してくれます。これによって正確にキーボードの入 力を監視、取得することができます。ただし、もちろん場合によっては瞬間のキーの状態が欲しいときもありますので、0x8000と0x0001を場合に よって使い分けることが必要になるでしょう。
GetAsyncKeyStateについての詳細は、MSDN のGetAsyncKeyStateを 参照してください。
GetAsyncKeyStateはなかなか強力なAPIですが、グ ローバルに(フォーカスを失った状態で)キーを取得するためのもうひとつの方法として、フックを使うやり方があります。ローカルフックでは、自らのプログ ラムをフォーカスを失えば、キーを取得することはできなくなりますが、グローバルフックならば取得することが可能です。しかし、グローバルフックを利用す る場合、DLLを作成しなければなりません。
グローバルフックとは、すべてのプロセスへ任意のDLLを注入させる 仕組みです。つまり、フックを利用したキーロガーとは、全プロセスへ注入させた任意のDLLがキーボードの入力を取得して、自分のプロセスへメッセージと してそのキー情報を送信してもらうことで、キーボードのロギングを実現しています。ここではフックに関しての詳細は説明しませんので興味があるならば調べ てください。
以下のグローバルフックを利用したキーロガーのソースコードです。
../src/klogger02.cpp
../src/keyhook.h
../src/keydll.cpp
ま ず、keydll.cppとkeyhook.hをコンパイルしてDLLを作成したあと、その作成時に生成されたLIBファイルを klogger02.cppのプロジェクト に追加してコンパイルします。グローバルフックは強力なシステムであり、キーボードの他に、プログラム間で送受信されるメッセージやその他あらゆる情報を 取得することができます。2000/XPではハードウェアレベルでのキーログも取得することができ(取得してもあまり意味がないですが)まさに最高のシス テムですが、故に危険です。例えばVC++に付属しているツールでspy++というものがあります。これはまさにグローバルフックを利用して、様々なメッ セージを監視しているわけです。
かなり万能なグローバルフックですが、グローバルフックでも取得でき
ない代表的な情報に、クリップボードのログがあります。クリップボードのログはフックでは取得することができませんが、クリップボードには、それ相応の
APIが用意されています。それらを使うと、クリップボードを常に監視することができ、さらに、クリップボードの変更時に、そのデータを取得することが可
能となります。以下にクリップボード取得を行うDLLを示します。
上 記のプログラムはDLLとして作られていますが、もちろん通常のEXEファイルでもクリップボードロギングの作成を行うことはできます。上記のプログラム は、常 駐プログラム隠蔽テクニックで紹介したプログラムです。
プ ロセス隠蔽については、方法はいくつかあります。例えばDLLのインジェクションについて私が書いたものが常 駐プログラム隠蔽テクニックです。このテクニックを利用すれば、任意の プログラム(DLL)を、別の(任意の)プロセスへ注入し、自らのプログラムを終了させることで、プロセスの隠蔽を行っています。この方法は 2000/XPでしか利用できないテクニックですが、十分に面白いHackingだと思います。
逆にWindows9x系では、以下のプログラムを使うことによっ て、プロセスの隠蔽を行えます。これはサービスプロセスとしてプログラムを登録することであり、これによってプロセス隠蔽を行っています。
HMODULE hKernel32 = GetModuleHandle(_T("kernel32"));
typedef DWORD (WINAPI *REGISTERSERVICEPROCESS)(DWORD, DWORD);
REGISTERSERVICEPROCESS RSProcess = (REGISTERSERVICEPROCESS)
GetProcAddress(hKernel32, "RegisterServiceProcess");
if( ! RSProcess )
return(-1);
RSProcess(NULL, 1);
上記のプログラムは、kernel32.dllから RegisterServiceProcessを探し出し、それを利用することによって、サービスプロセスへの登録を行っています。 RegisterServiceProcessについてはMSDN のRegisterServiceProcessを参照してください。
Windows9x系では比較的容易にプロセスの隠蔽が可能です。で は2000/XPでのプロセスの隠蔽方法で、DLLを使用しない方法を紹介します。これはDLLインジェクションと似たようなものなのですが、DLLでは なく関数自体を別の(任意の)プロセスへ注入してみようということです。
./keyLoggerTH.cpp
./keyLoggerTH.cpp(exeファイル)
上記のプログラムでは、DLLではなく関数をプロセスへ注入すること により、プロセスの隠蔽を実現しています。ちなみにWin9x系でプログラムが実行された場合、サービスプロセスへ登録して隠蔽をはかろうとしています が、この部分は未実装なので、このプログラムは9x系では正常に動作しません。
任意のコードを別のプロセスへ注入する方法に関してはThree Ways to Inject Your Code into Another Processが とても参考になります。ぜひ読んでみてください。
以 上が私が、キーロガーやプロセス隠蔽に関して調べたことです。この文章に関して、間違いや指摘や意見などなどがありましたら こ こにメールください。
終わり。