チュートリアル

ロウハンマーの再現

ロウハンマーは、メモリの特定の行を繰り返しアクセスすることで隣接行のビットが1から0へフリップする現象です(メモリセルの電荷漏洩によるもので、True Cellモデルでは1→0方向のみ)。フリップは対象ビットの上下の同じ桁のセルが両方とも0(放電状態)の場合にのみ発生します。攻撃者は、自分がアクセス可能なメモリ領域を繰り返し読み書きするだけで、アクセス権のない隣接行のデータを破壊できます。

このチュートリアルでは、単純PC環境上でロウハンマーを再現する具体的な手順を説明します。ロウハンマーの仕様詳細はアーキテクチャを参照してください。

有効化の手順

ロウハンマーシミュレーションはデフォルトで無効です。以下の手順で有効化します。

  1. CPUが停止していることを確認します(Start/Stopボタンが「▶」の状態)。
  2. ロウハンマートグルボタンをクリックして有効化します。

ロウハンマートグルボタンはCPU実行中は操作できません。必ずCPUを停止してから切り替えてください。

有効化すると、メモリエディタ上でフリップしやすいビット位置(行ごとに複数)がストライプ表示でハイライトされます。対象ニブル(16進数1桁)の幅を4等分し、フリップ対象のビット位置に対応するストライプを色分けして表示します(左からビット3→ビット0の順、ビット位置ごとに赤・橙・黄緑・緑)。これにより、どのアドレスのどのビットがフリップ対象かを事前に確認できます。

基本: ビットフリップの発生

最もシンプルなロウハンマーの再現方法です。特定のメモリ行を繰り返し読み取る無限ループを実行し、隣接行にビットフリップが発生することを確認します。

ハンマリングプログラム

以下のプログラムは、アドレス0xFD00(行0x7E)を繰り返し読み取る無限ループです。

アドレス命令説明
0x01000x21LXI H, 0xFD00HLレジスタにアドレス0xFD00を設定
0x01010x00
0x01020xFD
0x01030x7EMOV A, MHLが指すアドレス(0xFD00)から読み取り
0x01040xC3JMP 0x0103MOV A, Mに戻る(無限ループ)
0x01050x03
0x01060x01

このプログラムの核心は、MOV A, MJMPのたった2命令のループです。LXI Hはループの前にHLレジスタを初期化するだけで、1回だけ実行されます。

メモリとレジスタの設定

  1. CPUを停止します。
  2. メモリエディタで、アドレス0x0100以降に上記の7バイトを入力します。
    • メモリエディタでGキーを押し、0100と入力してEnterでジャンプします。
    • Enterキーで編集モードに入り、各バイトの値を入力します。
  3. フリップ対象のメモリに1を含む値を書き込みます(True Cellモデルでは1→0方向のみフリップするため、対象ビットが1でないとフリップが観測できません。また、上下の同じ桁のセルが0である必要があります)。
    • アドレス0xFA000xFFを書き込みます(行0x7Dのフリップ対象バイト)。
    • アドレス0xFE000xFFを書き込みます(行0x7Fのフリップ対象バイト)。
  4. レジスタエディタで、PCレジスタに0x0100を設定します。
  5. ロウハンマートグルボタンをクリックして有効化します。

実行と確認

  1. Start/Stopボタンをクリックしてプログラムを実行します。
  2. しばらく待ちます。

    デフォルトでは256回のアクセスでビットフリップが発生します。

  3. CPUを停止し、メモリエディタで以下のアドレスを確認します。
    アドレス行番号確認内容
    0xFA00行0x7D行0x7Eの上方向の隣接行。事前に設定した0xFFから0xDFに変化します(ビット5が1→0にクリア)。
    0xFE00行0x7F行0x7Eの下方向の隣接行。事前に設定した0xFFから0xFEに変化します(ビット0が1→0にクリア)。

フリップ対象のバイトオフセットとビット位置は、行ごとに複数が予め固定値として決められています。同じ行なら毎回同じビットが対象になります。対象ビットが1で、かつ上下の同じ桁のセルが両方とも0の場合のみクリアされます。何度起動し直しても同じ結果になります。

動作の仕組み

このプログラムが動作する仕組みを整理します。

ループ1回あたりのメモリアクセスは以下の通りです。

アクセスアドレス原因
10x0103行0x00MOV A, M 命令のフェッチ
20xFD00行0x7EMOV A, M の実行(攻撃対象)
30x0104行0x00JMP 命令のフェッチ
40x0105行0x00JMPオペランド(下位バイト)のフェッチ
50x0106行0x00JMPオペランド(上位バイト)のフェッチ

ループ1回あたり、行0x7Eへのアクセスにより行0x7Dと行0x7Fのカウンタがそれぞれ1増加し、行0x00へのアクセスにより行0x01のカウンタが4増加します(行0x00は端の行のため上方向の隣接行なし。実際のDRAMでは行のアクティベーションが隣接行に電気的干渉を与えるため、アクセスされた行自体ではなく隣接行のカウンタが増加します)。

プログラム自体の命令フェッチにより行0x01のカウンタも増加するため、行0x7D・行0x7Fよりも先に行0x01の閾値に到達します。ただし、行0x01側の変化はこのチュートリアルの観測対象外であり、プログラムの動作にも影響しません。

応用: ページテーブルエントリへの攻撃

攻撃の概要

ロウハンマーのセキュリティ上の脅威は、メモリ保護機構を破壊できる点にあります。ここでは、ロウハンマーによってページテーブルエントリ(PTE)のValidビットを1から0にクリアし、ページフォルトを発生させるシナリオを再現します。

シナリオは以下の通りです。

  1. ページテーブルを行0x7Fに配置する(アドレス0xFE00〜)
  2. ページ0のPTEにValid=1を設定する(アドレス0xFE00のビット0が1)
  3. 隣接する行0x7Eを繰り返し読み取る
  4. ビットフリップにより、ページ0のPTEのValidビットが1から0にクリアされる
  5. その後、ページ0にアクセスするとページフォルトが発生する
メモリレイアウト:
  行 0x00: 0x0000-0x01FF  ← ハンマリングプログラム配置(アドレス 0x0100)
  ...
  行 0x7D: 0xFA00-0xFBFF  ← 上方向のフリップ先
  行 0x7E: 0xFC00-0xFDFF  ← ハンマリング対象(アドレス 0xFD00 を繰り返し読み取り)
  行 0x7F: 0xFE00-0xFFFF  ← ページテーブル配置(下方向のフリップ先)

フリップ対象のバイトオフセットとビット位置は行ごとに複数が予め固定されています。行0x7Fではオフセット0・ビット0がフリップ対象の一つとして含まれているため、アドレス0xFE00のビット0(PTEのValidビット)が1から0にクリアされます。

メモリとレジスタの設定

1. ページテーブルの配置

メモリエディタで以下の値を設定します。これはページテーブルのうち、このチュートリアルで使用するエントリです。

アドレス説明
0xFE000x01ページ0のPTEフラグ(Valid=1)
0xFE010x00ページ0の物理ページ番号(0x00)
0xFE020x01ページ1のPTEフラグ(Valid=1)
0xFE030x01ページ1の物理ページ番号(0x01)

ページ0(0x0000〜0x00FF)とページ1(0x0100〜0x01FF)を物理アドレスと同じアドレスにマッピング(恒等写像)しています。

PTEの構造についてはアーキテクチャ: PTEフラグを参照してください。各PTEは2バイトで、下位バイトがフラグ(ビット0=Valid)、上位バイトが物理ページ番号です。

2. ハンマリングプログラムの配置

基本チュートリアルと同じプログラムを0x0100に配置します。

アドレス命令
0x01000x21LXI H, 0xFD00
0x01010x00
0x01020xFD
0x01030x7EMOV A, M
0x01040xC3JMP 0x0103
0x01050x03
0x01060x01

3. レジスタの設定

レジスタ説明
PC0x0100プログラムの先頭アドレス
PTBR0xFE00ページテーブルの先頭アドレス

この段階ではMMUは無効のままにしておきます。ハンマリング中はMMUを使用しません。

実行と確認

  1. ロウハンマートグルボタンをクリックして有効化します。
  2. Start/Stopボタンをクリックしてプログラムを実行します。
  3. しばらく待ちます。

    行0x7Eへのアクセスにより隣接する行0x7Fのカウンタが蓄積され、閾値に達すると行0x7F内の予め決められた位置のビットが1から0へクリアされます。

  4. CPUを停止します。
  5. メモリエディタでアドレス0xFE00を確認します。

    行0x7Fではオフセット0・ビット0がフリップ対象の一つとして含まれているため、アドレス0xFE00のビット0(Validビット)が1から0にクリアされ、値が0x01から0x00に変化します。これによりPTEが無効化されます。

ページフォルトの発生

破壊されたPTEを使ってページフォルトが発生することを確認します。

1. 確認用プログラムの配置

メモリエディタで以下のプログラムを0x0110に追加します。このプログラムはアドレス0x0000(ページ0)から読み取りを行います。

アドレス命令説明
0x01100x3ALDA 0x0000アドレス0x0000(ページ0)から読み取り
0x01110x00
0x01120x00
0x01130x76HLTCPU停止

2. MMUの有効化と実行

  1. レジスタエディタでPCに0x0110を設定します。
  2. MMUトグルボタンをクリックしてMMUを有効化します。
  3. Start/Stopボタンをクリックして実行します。

3. 結果

LDA 0x0000が仮想アドレス0x0000(ページ0)にアクセスしようとしますが、PTEのValidビットが0であるため、ページフォルト例外が発生します。

レジスタエディタでPFAR(ページフォルトアドレスレジスタ)に0x0000が設定されていることを確認できます。

ページフォルトの仕組みについてはアーキテクチャ: ページフォルトを参照してください。

この例では、ベクタテーブルを設定していないため、ページフォルトハンドラへのジャンプは行われません(未定義の動作になります)。ページフォルト処理の完全な再現については、別途ベクタテーブルとハンドラの設定が必要です。