【注意】このサイトに記載されていることを他人に試すことは「不正アクセス禁止法」に該当する場合があります。詳しくはこちらから

GDBでレジスタを読む CPUの思考を読む技術(第6回/全8回)

黒ネコと学ぶ、GDBを使ったエクスプロイト開発への第一歩

第5回で、スタックは「関数呼び出しの履歴」であり、戻り先情報が積まれる現場だと体感しました。
今回は、そこに"CPU視点"を足します。
この記事のゴールは3つだけです。
・レジスタを数字ではなく意味で読む。
・最重要3レジスタである、RIP/RSP/RBPが説明できる。
・Kali Linuxで、RIPが動く瞬間を、1命令ずつ追って体験する。
※イメージです。

レジスタは、CPUの"メモ帳"であり"現在地表示"

レジスタは、CPUが処理に必要な情報を一時的に置く場所です。
GDBでレジスタを見ると、CPUが今どこで何をしようとしているかが見えます。
 
最重要3レジスタ
・RIP:次に実行する命令の住所(CPUの"次の一手")
・RSP:スタック先頭の住所(作業机の"いちばん上")
・RBP:現在の関数フレームの基準点(机の"目印")
 
クラッシュが"情報"になる理由
・RIPが実行できない場所を指した、などの"結果"
・RIP/RSP/RBPを見ると「何が起きたか」を説明できる
つまりレジスタは「原因」ではなく、現象の結果が反映される観測点なのです。
 
 

レジスタが分かりやすい練習用プログラム

1.RIPの動きが追いやすいプログラムを作成します。
nano gdb01-06.c
 
2.ソース
-----
#include <stdio.h>
 
int add(int x, int y) {
    return x + y;
}
 
int main() {
    int a = 5;
    int b = 7;
    int c = add(a, b);
    printf("Result: %d\n", c);
    return 0;
}
-----
 
3.プログラム入力完了後
「Ctrl」+ o で、プログラムの書き込み
「Ctrl」+ x で、nanoエディター終了です。
 
4.コンパイルします。
gcc -g gdb01-06.c -o gdb01-06
 
 

Kaliで手を動かす①:RIP/RSP/RBPだけを見る

1.GDBを起動します。
gdb ./gdb01-06
 
2.mainで止めます。
break main
run
 
3.まず"現在地"を確認します。
list
 
4.レジスタを最小表示します。
info registers rip rsp rbp
 
5.ここて表示された内容は
・RIP:次に実行する命令の場所(現在地)
・RSP:スタックの先頭(現場)
・RBP:関数フレームの基準点(目印) です。
 
 

Kaliで手を動かす②:RIPを「1命令ずつ」動かす

ここが今回の核心になります。
行単位ではなく、命令単位でCPUを動かすと、RIPが"生きた情報"になります。
 
next/step と ni/si の違い
・next/step:Cコードの「行」単位(人間向け)
・ni(nexti)/si(stepi):CPU命令の「1命令」単位(CPU向け)
 
1.いまのアセンブラの命令列を軽く眺めます。
disassemble
※アセンブラ言語で表示されているため、読めなくてOKです。
「アセンブラの命令が並ぶ」ことを確認するだけです。
 
2.1命令(アセンブラ言語)を進めます。(関数に入らない)
ni
※niは呼び出し先の関数の中には入らず、その関数が終了して戻ってくるまでを1ステップとして実行します。
 
3.進んだら、RIPだけ確認します。(動いたことを体感しましょう)
info registers rip
 
4.これをあと2回繰り返します。
(1回目)
ni
info registers rip
(2回目)
ni
info registers rip
※int c = add(a, b);の実行前にきました。
 
5.add関数呼び出しのところで「中に入る」を体験します。
si
info registers rip
※呼び出し先の関数(add関数)の最初の命令に移動しました。
・"ni":関数呼び出しをまとめて進む傾向。
・"si":関数の中へ入って追える。
※「RIPが動く=CPUが次の命令へ進む」これが体感できれば勝ちです。
 
6.終了します。
continue
quit
 

GDBでレジスタを読む CPUの思考を読む技術のまとめ

レジスタはCPUの「メモ帳」であり、実行中の内部状態を示す最重要の観測点です。
初心者が最初に押さえるべきはRIP/RSP/RBPの3つで、RIPは「次に実行する命令の住所=CPUの次の一手」、RSPは「スタック先頭=現場の起点」、RBPは「関数フレームの基準点=構造の目印」を表します。
GDBで "info registers rip rsp rbp" を確認すると、プログラムがどこにいて、スタックの現場がどこかを説明できるようになります。さらに "ni/si" で1命令ずつ進め、進むたびにRIPを確認すると、CPUが命令を実行して"現在地が更新される"ことを体感できます。
数値の暗記より、止める→見る→少し進めて変化を見る習慣が、クラッシュを情報に変える論理的解析力を育てます。