GDB
使用するときはGDB単体ではなくExploit用に拡張されたPEDAを使う。 インストール
$ apt install gdb
チートシート
Options
-q: version情報などをプリントしない。
-p PID: プロセスにアタッチ。./a &してpsで取得するなど。 Commands
ブレークポイント系
b,break: ブレークポイント追加。
b: 現在のアドレスに追加
b (アドレス/関数名/ファイル名:アドレス)
b *func: func+0
b *func+10
b *0x55555555487b
d: ブレークポイント削除。
d 1: 1番目のブレークポイントを削除。
disable (breakpointの番号)
enable (breakpointの番号)
ignore (breakpointの番号) (無効化する回数)
n,next: ソースにおけるステップオーバー
s,step: ソースにおけるステップイン
ni,nexti: 機械語におけるステップオーバー
si,stepi: 機械語におけるステップイン
c,continue: 次のbreakpointに飛ぶ
c 100: そのbreakpointは100回ignoreする。
i b,info break: breakpointの状態
ignore (breakpoint_number) (count): 回数無視。
レジスタ系
p (レジスタ名): レジスタの値を表示
i r,info registers: 全てのレジスタの値を表示
set (レジスタ名)=(値)
set $rax=1
メモリ系
i proc map, info proc mappings: メモリ配置の確認
watch (メモリアドレス): 書き換え検知
rw (メモリアドレス): 読み取り検知
aw (メモリアドレス): 書き換え/読み取り検知
x: メモリダンプ
x/(表示する数)(メモリサイズ)(表示フォーマット) (表示するメモリの先頭アドレス)
table:メモリサイズ
b 1byte BYTE
h 2bytes HALFWORD
w 4bytes WORD
g 8bytes GIANTWORD
table:表示フォーマット
s 文字列
i 命令
x 16進数
x/16wx $ebp: EBPから16ワードを16進数で表示。
アドレスを指定しないと前回xを実行して表示されたアドレスの続きのアドレスに対して実行される。
文字列を出力したいときはbが良いっぽい?
関数実行後にポインタの値を見たければx/8bs (関数の引数に与えられたアドレス)とすればよい。
プログラム実行系
r,run: プログラムの実行。
r [コマンドライン引数]
入力待機はCtrl + Zで退避できる
start [コマンドライン引数]: エントリポイントでbreakpointを差し込んだ状態で実行と同じ(多分)。b *mainが使えない場合に使う。
set args (コマンドライン引数)
shell COMMAND: シェルコマンドを実行できる。
j (アドレス/関数名): ジャンプ。
アセンブル系
disas,disassemble: 逆アセンブル。
disas (関数名)
disas (開始アドレス) (終了アドレス)
set disassembly-flavor intel/att: Intel記法かAT&T記法か。defaultはAT&T。gdbinitに常にintelになるよう記述できる。
bt,backtrace: どのような関数を経ているか
q,quit: GDBの終了。
画面の見方
[ebp+0x8]はebpのアドレスに0x8足したアドレスを表す
今どの関数にいるか?最後にin 関数名()と書いてある。
https://gyazo.com/c84c6b4194698c42bf5c02b2508f075c
EFLAGSは赤がフラグが立っていて(1)緑が立っていない(0)ことを示す。
https://gyazo.com/56a2b2797fac1a9bc235bb4c28503176
GCCでコンパイル時に-gオプションをつけるとデバッグ情報が負荷される。 disas mainが出来ないときはstartしてエントリポイントのアドレス調べてmain関数のアドレスを計算してブレークポイントを設定する。
rで使った引数が記録されてしまっている(show argsで確認可能)から、set argsを実行することでリセットする。
ゼロフラグ切り替えset $eflags^=(1<<6)。キャストがおかしいと怒られることがある。
set {int}0x83040 = 4