LinuxでRAMの中身を読み取る方法――LiMEを使ったメモリダンプの実践ガイド
本記事では、コンピュータのRAM(メインメモリ)に格納されたデータを読み出す方法を、実際の手順とともに詳しく解説します。
RAM(Random Access Memory)は、あらゆるコンピュータシステムに不可欠な部品であり、システムが処理を実行するために必要なデータを一時的に保存する役割を担っています。ただし、RAMの内容は揮発性(ボラタイル)であるため、通常はシャットダウンとともに失われてしまいます。
RAMの内容を保存する手段のひとつが「RAMダンプ」です。これは、RAM上のデータをハードディスクなどのストレージデバイスへコピーするプロセスを指します。取得したRAMダンプを解析することで、ダンプ取得時点におけるシステムの状態について、貴重な知見を得ることができます。
この記事では、RAMの内容を読み取る手順を解説するとともに、RAMダンプとは何か、そしてシステム解析にどのように役立つのかを説明します。さらに、RAMダンプの取得方法と、得られたデータの解析方法についてもステップバイステップで紹介していきます。
なぜRAMのデータを読み取るのか?
ディスクからデータを読み込む操作には慣れている方も多いでしょう。しかし、最も重要な情報が格納されているRAMから直接データを読み出せることはご存じでしょうか。
開発者の視点で言えば、空間計算量(スペースコンプレキシティ)を調査し、RAMの内部を掘り下げて「何が起きているのか」を理解することにつながります。
RAMへのアクセスと読み取りは、さまざまな場面で役立ちます。代表的なユースケースのひとつが、コンピュータシステムのトラブルシューティングや障害診断です。RAMの内容を調べることで、特定の時点におけるシステムの状態を把握できます。
たとえば、コンピュータが突然クラッシュした場合、RAMの内容を調査すればクラッシュの原因を特定できる可能性があります。
もうひとつの重要なユースケースがフォレンジック(デジタル鑑識)分析です。不正行為の証拠を探してシステムを調査する際、RAMの内容を確認することで、そのマシン上で行われていた活動の手がかりを得られます。
たとえば、セキュリティ専門家はRAM解析を通じて、特定のプロセスが稼働していたかどうかを判定したり、最近アクセスされたファイルを特定したりできます。
また、ソフトウェア開発者や研究者にとっても有用です。RAM上のデータを分析することで、開発者は自作ソフトウェアのパフォーマンスを把握し、潜在的な問題やボトルネックを発見できます。研究者はマルウェアの挙動の研究や、新しいセキュリティツール・技術の開発にRAM解析を活用できます。
このように、RAMの読み取りはトラブルシューティング、フォレンジック分析、ソフトウェア開発、研究のいずれの場面でも、コンピュータシステムの内部動作を理解するための強力な手段となります。
具体的な手順に入る前に、まず用語を簡単に整理しておきましょう。当たり前の知識に思えるかもしれませんが、このガイドを読み進めるうえで必要になる概念なので、復習として確認しておく価値があります。
RAMとは物理的なハードウェアデバイスです。ほかにもCPU、ハードディスクといった物理コンポーネントが存在します。
その上に載っているのがオペレーティングシステム(OS)です。OSは常に「カーネル」と呼ばれる部分を通じてハードウェアと対話します。カーネルはOSソフトウェアの中核を担う、最も重要な要素のひとつです。
ユーザーの視点で考えると、私たちはまずOSにログインし、そのうえでアプリケーションの実行を中心とした作業を行います。
カーネルとは何か?
カーネルとは、OSの根幹をなす部分であり、私たちが裏側で実行するプログラムを通じて、ユーザーからの指示を受け付ける役割を果たします。
計算処理そのものはすべてCPU(中央演算処理装置)が担当します。しかし、CPUのサービスをどのように利用しようとも、データ・命令・コード・プログラムは必ずRAM(ランダムアクセスメモリ)を経由します。
つまり、ある時点で私たちがデータに対して行った処理の結果は、すべてメモリ上に存在することになります。プログラマがデータ構造を構築する場合も、そのデータはすべてRAM上に置かれます。
したがって、RAMに直接アクセスすれば、データ構造がどのように生成され、どのように配置されているのか、空間計算量がどう機能しているのかを目で見て確認できるのです。
たとえばChromeのようなWebブラウザを例に考えてみましょう。アプリケーションにセキュリティ上の脆弱性が生じているかもしれません。その場合、最も効果的な調査方法は、RAMにアクセスしてデータがどのように扱われているかを確認することです。
Chrome(または任意のブラウザ)でgmail.comのような安全なサイトを開いたとしましょう。Gmailに入力したユーザー名やパスワードなどの情報は、インターネット経由でGoogleのサーバーへ送信されます。このデータは完全に暗号化されているため、パスワードを解読するのは困難です。
しかし、パスワードを入力する段階では、キーボードのついたコンピュータを使用していますよね。入力後、なんらかのプログラムがデータを暗号化してインターネットへ送信します。ということは、最初の段階では、あなたのデータはRAM上に存在していたことになります。
まず、パスワードは平文のデータとしてRAM上に置かれます。その後、プログラムがそれを暗号化してネットワークへ送るのです。もしRAMにアクセスできれば、パスワードが暗号化されているかどうかを確認できます。しかも、このプロセスは非常にシンプルです。
具体例で仕組みを見てみましょう。「a」という変数があり、「9」というデータが代入されているとします。プログラムを実行すると、このデータはRAMにロードされます。プログラムが終了すると、RAM上のデータは消えるはずですが、実際に確かめた人は少ないのではないでしょうか。少し調査すれば、これを証明できます。
では、メモリの最上部にロードされたデータが、アプリケーション終了後もRAMに残っているかどうかは、どうやって確認すればよいのでしょうか。
実は、RAM上のこれらの内容は間もなく消去されます。そこで登場するのが「RAMダンプ」です。RAMダンプとは、RAM全体を丸ごとキャプチャするプロセスのこと。データセットが初めてRAMにロードされたときの実際の姿をそのまま記録できます。次に、メモリからデータをキャプチャ(抽出)する方法を学びましょう。
これを実現するには、なんらかのソフトウェアが必要です。このツールの目的は、メモリの奥深くまで入り込み、格納されているすべてのデータを取り出すことにあります。
LiMEとは何か?
LiME(Linux Memory Extractor)は、Linuxからメモリを抽出するための強力なソフトウェアです。このソフトウェアは「ドライバ」とも呼ばれ、別名「モジュール」とも呼ばれます。RAMがデバイスである以上、その内容を読み取るにはデバイスにアクセスするためのドライバが必要だからです。
LiMEはドライバの一種です。Linuxに精通している方ならご存じのとおり、ドライバを機能させるには、カーネルの助けを借りてそのドライバをロードする必要があります。
Linuxの文脈では、ドライバは「モジュール」とも呼ばれます。つまりLiMEはLinuxカーネルモジュールであり、いわゆる「ローダブルカーネルモジュール(LKM)」として、OSに組み込んで使用できます。
背景の説明はここまでにして、実際にRAMの内容を抽出する手順を見ていきましょう。以下、ハンズオン形式でステップごとに進めます。
セットアップとインストール
必要なのはLiMEドライバだけです。このモジュールはGitHubからダウンロードできます:https://github.com/gursimarsm/LiME
まずLinuxシステムを起動してください(筆者はRed Hat Enterprise Linuxを使用しています)。free -hコマンドを実行すると、使用中のRAM容量、空き容量などの詳細を確認できます。
※free -mコマンドの出力例
RAMにアクセスするには、カーネルが追加のモジュールをロードできる環境が必要です。今回使うモジュール名はLiMEです。そのためにインストールするのが「kernel-devel」と「kernel-headers」という2つのパッケージです。この2つがあれば、LiMEモジュールを使った以降の作業が可能になります。
パッケージをインストールするには、yumが設定済みである必要があります。yumとは、Red Hat系Linuxでソフトウェアをインストールするためのコマンドです。設定方法については付録を参照してください。
※インストール作業の様子
続いて、もうひとつ準備が必要です。ドライバをGitHubからダウンロードするため、Gitが未導入ならインストールしましょう。次のコマンドでインストールできます:yum install git。あわせてアカウントの設定も済ませておきましょう。
# git config --global user.name "Your Name"
# git config --global user.email "you@example.com"
先ほど紹介したリポジトリは、ローダブルカーネルモジュール(LKM)です。これを使えば、Linux OS全体のメモリを取得できます。AndroidもLinuxベースなので、Androidデバイスにも応用可能です。
モジュールは次のコマンドでダウンロードできます:
# git clone https://github.com/gursimarsm/LiME
ダウンロード後、ソフトウェアのディレクトリへ移動します。複数のフォルダがありますが、メインのコードを実行するには「src」ディレクトリへ移動してください。
このディレクトリにはC言語で書かれた複数のプログラムが含まれています。ファイルを利用するにはコンパイルが必要です。そのためにmakeコマンドを使用します。あわせて必要なものをインストールしておきましょう:
# yum install make
# yum install gcc
/LiME/src/ ディレクトリ内でmakeコマンドを実行すると、コード全体がコンパイルされます。
ここでエラーが出た場合は、最新版のLiMEに含まれる「orc metadata generate」という新機能が原因かもしれません。この機能を使うには、LiME関連パッケージのelfutils-libelf-develを追加でインストールする必要があります。yumで次のようにインストールできます:
※elfutils-libelf-develのインストール方法
インストールが完了したら、再度makeコマンドを実行します。GCCコンパイラがコード全体をコンパイルし、最終的に「カーネルオブジェクトファイル(.ko)」というオブジェクトファイルが1つ生成されます。これがLiMEの最終モジュールです。
※makeコマンドの出力例
このファイルは同じディレクトリ内にあります。lsコマンドで確認してみてください。
モジュールの使い方
このモジュールを組み込むことで、カーネルはRAM全体をキャプチャ(読み取り)できるようになります。通常はRAM全体を一括で読み取ることはできませんが、LiMEモジュールのおかげでそれが可能になります。
LiMEモジュールの詳細を知りたい場合は、modinfoコマンドを使いましょう。modinfo limeのように入力すると、ファイルの場所などの詳細情報が表示され、追加パラメータを持つモジュール(ドライバ)の一覧も確認できます。各パラメータにはそれぞれ利点があります。
※modinfoコマンドの出力例
ここでは、特に重要な2つのパラメータ「path」と「format」を使用します。
pathは、RAM全体を読み取った際にデータを保存するファイルの指定です。作成したい出力先ファイルを、ここで指定します。
もうひとつのformatは、RAMデータを読み取る形式の指定です。今回はRAMのデータをそのままの形で読み取りたいので、RAM上のデータ(主にバイナリ)をバイナリ形式のまま、生(raw)の状態でキャプチャします。
つまり、formatはrawとし、pathで指定したファイルに保存するわけです。
それでは、いよいよRAMからデータを読み取るメインコマンドを実行しましょう。
デモンストレーション
このデモでは、ChromeでGmailアカウントのパスワードを入力してみます。これにより、RAMからデータをキャプチャする方法と、パスワードが暗号化されているかどうかの両方を確認できます。
この2点を検証するには、コマンドプロンプトに移動し、データがまだRAM上に残っているかをチェックします。モジュールをロードするには、insmodコマンドを使用します。このコマンドでモジュールを挿入(insert)できます。
モジュールのフルパスをコピーし、insmodコマンドに続けて貼り付けましょう。
※insmodコマンドの実行例
このモジュールはカーネルの助けを借りてロードされ、RAMから全データのキャプチャを開始し、たとえばmyram.dataのようなファイルに保存します。
メモリダンプ(RAMダンプ)全体がこのファイルに書き込まれ、キャプチャ形式はraw形式となります。
2つのパラメータ(pathとformat)を指定してコマンドを実行すると、その瞬間にRAM上のデータがすべてキャプチャされ、指定したファイルに保存されます。この処理には通常数秒かかります。所要時間はCPU速度とRAM上のデータ量によります。
※コマンド実行例
データの読み方
これでmyram.dataファイルが作成され、RAMの全データがこのファイルに保存されました。raw形式でキャプチャしたため、データはバイナリになっています。このファイルを直接読もうとしても、人間には読めません。headコマンドで先頭10行程度を読んでみても、意味のある表示にはなりません。
※headコマンドの出力例
catコマンドを使えば全データを読み取れますが、やはり表示されるのはバイナリ形式のままです。そこで、パイプ機能を使ってこのコマンドをstringsという新しいコマンドと組み合わせます:
※パイプを使ったコマンド例
stringsは、データを人間が読める通常のテキスト形式に変換してくれるコマンドです。
※strings適用後の出力例
表示は延々と続きます。中断するにはCtrl+Cを押してください。
現時点では、全データを見てもピンとこないかもしれません。ここで、RAM上に「mywebpasswordgmail」というパスワードのデータがあることが分かっています。このデータが本当に存在するか確認するため、さらにパイプをつなげてgrepコマンドを組み合わせましょう。grepはデータを絞り込む(フィルタリングする)のに役立ちます。
cat /myram.data | strings | grep mywebpasswordgmail
こうすると、全データの中からこの文字列を検索します。データがテキストに変換され、該当する文字列が見つかった行をgrepが拾い上げ、結果を表示してくれます。
このシンプルな例から分かるように、キーボードで入力したものはすべてRAMに流れ込みます。パスワードであろうと、閲覧中のセキュアなサイトの情報であろうと、データはRAM上に存在します。どんなプログラムを実行しても関係ありません。キーボードから入力したものはすべてRAMにロードされ、抽出可能です。これこそがメモリダンプなのです。
LiMEには、ほかにも多くの強力な機能があります。今の例では、操作を行っているシステム自身から直接データをキャプチャしましたが、LiMEはリアルタイムでデータをキャプチャし、ネットワーク経由で別のコンピュータへ送信することもできます。
これはどういうことでしょうか。たとえば、誰かがWebサイトを開いて何かを入力しているとします。その入力内容全体が、リアルタイムでもう一台のコンピュータへ送信されるイメージです。
ここで話しているのはキーロガーではなく、あくまでRAMの話です。任意のプログラムが動作しているとき、データベースはデータを保存し、プログラムはハードディスクの別の場所からデータを読み込んでいます。RAM上で起きているすべてのことを、システムがリアルタイムでキャプチャし、ネットワーク経由で他のコンピュータへ送れるのです。
まとめ
本記事は以上です。楽しんで読んでいただき、何か新しいことを学べたなら嬉しいです。
筆者はLinkedInでのご意見や議論も歓迎しています。ダイレクトメッセージでお気軽にご連絡ください。
記事を気に入っていただけたら、GitHubでスターを付けたり、LinkedInで関連スキルの推薦(エンドースメント)をしていただければ、執筆のモチベーションにつながります。
それでは次回の記事まで、ご安全に! 学び続けましょう。
-
macOSの「リカバリサーバーに接続できませんでした」エラーを解決する4つの方法
macOS MojaveやCatalinaのアップデート中に「リカバリサーバーに接続できませんでした(The Recovery server could not be contacted)」というエラーに遭遇していませんか?このエラーは、インターネット接続の不具合、日付と時刻の同期ズレ、あるいはMacがAppleのサーバーに正常に接続できない場合などに発生します。 Macでこのエラーが繰り返し表示される場合、本記事で紹介する対処法を試してみてください。その前に、まずはこのエラーが発生する原因について詳しく見ていきましょう。 「リカバリサーバーに接続できませんでした」エラーとは? このエラー
-
macOSでBlu-rayディスクを再生する方法|VLCを使った設定手順を解説
テクノロジー企業には、特定の技術に対して意外な「盲点」があるものです。Appleの場合、その盲点こそがBlu-ray(ブルーレイ)です。Appleは物理ディスクを時代遅れで無意味なものとみなしており、Blu-rayというフォーマットを真剣に受け止めたことがありません。実際、macOSは初期状態ではBlu-rayディスクを再生できない仕様になっています。そのため、MacでBlu-rayを視聴するには、サードパーティ製のソフトウェアを導入する必要があります。幸い、優れたオープンソースの選択肢がいくつか存在します。本ガイドでは、無料動画プレーヤーとして常に高い評価を得ているVLCを使用します。Elm