UNIX/gdb

基本

コンパイル

# gcc -g <ソース>
※ -g で追加デバッグ情報の出力が可能になる(gdb の listでソースが表示可能になる)

オブジェクトファイルの情報を表示する

# objdump -M intel -D <プログラム>
※ -M intel でシンタックスをIntel形式にする。

オブジェクトファイルのシンボルを表示する

# nm <プログラム>

coreファイルの解析

# file <coreファイル名>
※ coreファイルの出力プログラムを確認
# gdb <プログラム名> <コアファイル名>
※ プログラムが異常終了した直後の状態が再現される。
(gdb) bt
#0  0x00007f079fe8b6a7 in _IO_default_xsputn_internal () from /lib64/libc.so.6
#1  0x00007f079fe5f190 in vfprintf () from /lib64/libc.so.6
#2  0x00007f079fe80609 in vsprintf () from /lib64/libc.so.6
#3  0x00007f079fe662b8 in sprintf () from /lib64/libc.so.6
#4  0x0000000000400667 in GetMngFile (mngfile=0x600ae0) at test.c:27
#5  0x00000000004005bb in main () at test.c:12

(gdb) f 4
#4  0x0000000000400667 in GetMngFile (mngfile=0x600ae0) at test.c:27
27          sprintf(mngfile[i],"%s_%s",file,DATA);
(gdb) print i
$1 = 27
(gdb) print file
$2 = "abc", '\000' <repeats 124 times>
(gdb) f 5
#5  0x00000000004005bb in main () at test.c:12
12        GetMngFile(mngfile);
(gdb) p mngfile
$3 = {"abc_TEST", '\000' <repeats 41 times>, "abc_TEST", '\000' <repeats 41 times>}

レジスタ

レジスタ名称説明
axアミュレータ大抵の場合はCPUがマシン命令を実行する際の一時変数として用いられる
cxカウンタ
dxデータレジスタ
bxベースレジスタ
spスタックポインタメモリ上の場所を示す32bitのアドレスを格納
bpベースポインタ
siソースインデックスデータ読み込み参照元
diデスティネーションインデックスデータ書き出し先
ipプロセッサによって実行されようとしている現在の命令を格納
flags比較演算、メモリのセグメント化に用いられる複数フラグから構成


 

コマンド

list(l)

ソースプログラムを表示する

disassemble

disassemble <関数名>

関数の逆アセンブル結果を表示
(シンタックスIntel形式で出力した例)

(gdb) disassemble main
〜省略
  0x00000000004004d5 <+17>:    mov    edi,0x4005e8
  0x00000000004004e3 <+31>:    cmp    DWORD PTR [rbp-0x4],0x4 ※1
  0x00000000004004e7 <+35>:    jle    0x4004d5 <main+17>    ※2
  0x00000000004004e9 <+37>:    mov    eax,0x0         ※3
※1 rbpレジスタから4を減算した値をアドレスとして用い、そのアドレスから開始している4バイトの値と数値の4を比較
※2 比較対象の値が4以下の場合は 4004d5 に移行する
※3 そうでない場合は、jle命令の次の命令を実行する

set disassembly-flavor intel

関数の逆アセンブルのシンタックスをIntel形式にする。
命令語 <操作対象>, <参照元>

break(b)

break { <関数名> | ステップ }

指定した関数直前で実行を止める

watch(w)

watch 変数

指定した変数の値が変更されたら停止する

info(i)

info registers [レジスタ](i r [レジスタ])

レジスタの内容を表示

info break

設定したbreakポイントの表示

info watchpoints

設定したwatchポイントの表示

x/

x/[表示数]{表現方法}[グループ単位] 値

引数の値を様々な形式で表示する。デフォルトは16進数、4バイトを1グループ表示。x/1xw

表現方法説明表現方法説明
o8進数cASCIIコード
x16進数s全体の文字列
u10進数i逆アセンブル?
t2進数
グループ単位バイト数グループ単位バイト数
b1bytew4byte
h2byteg8byte

print(p)

print[/書式] {変数 または 計算式} 

引数で指定した計算式の結果を 一時変数に格納する。書式は x/ で使用する表現方法の値を利用する

(gdb) print 0x7fffffffe48c - 0x7fffffffe470
$2 = 28

step(s)

ステップイン。次の処理まで進む(関数の中に入る)

next(n)

next

ステップアウト。次の処理まで進む(関数の中はスキップ)

next insutruction

eipが指定している命令を読み込み、それを実行し、次の命令を格納されているアドレスを差すようにeipの値を進める

continue(c)

breakポイントで停止したプログラムを再開させる。

frame(f)

frame <フレーム名>

関数フレームの移動

backtrace(bt)[full]

呼び出している関数のネスト状態を確認。fullを付与するとローカル変数の情報も表示する

 

サンプル

バッファオーバーラン

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h>

int check_authentication(char *password) { 
    int auth_flag = 0; 
    char password_buffer[16];
    memset(password_buffer, 0x00, sizeof(password_buffer));
    strcpy(password_buffer, password);
    if(strcmp(password_buffer, "pass") == 0) {
        auth_flag = 1;
    }
    return auth_flag;
}

int main(int argc, char *argv[]) { 
    if(argc < 2) {
        printf("使用方法: %s <パスワード>\n", argv[0]); 
        exit(0);
    }
    if(check_authentication(argv[1])) {
        printf("OK。\n"); 
    } else { 
        printf("NG。\n");     
    }
}

デバッグ

[root@cent6 kita]# gdb ./a.out
(gdb) b 8
Breakpoint 1 at 0x400637: file test.c, line 8.
(gdb) b 9
Breakpoint 2 at 0x40064d: file test.c, line 9.
(gdb) b 13
Breakpoint 3 at 0x40067c: file test.c, line 13.
(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Starting program: /root/kita/a.out AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Breakpoint 1, check_authentication (password=0x7fffffffe804 'A' <repeats 37 times>) at test.c:8
8 memset(password_buffer, 0x00, sizeof(password_buffer));
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.149.el6.x86_64
(gdb) x/8xw password_buffer
0x7fffffffe480: 0xffffe5c0 0x00007fff 0x00400745 0x00000000 初期化されてない
0x7fffffffe490: 0xf7a58ba0 0x00007fff 0x00400700 0x00000000
(gdb) c
Continuing.
Breakpoint 2, check_authentication (password=0x7fffffffe804 'A' <repeats 37 times>) at test.c:9
9 strcpy(password_buffer, password);
(gdb) x/8xw password_buffer
0x7fffffffe480: 0x00000000 0x00000000 0x00000000 0x00000000 16byte分初期化
0x7fffffffe490: 0xf7a58ba0 0x00007fff 0x00400700 0x00000000
(gdb) x/x &auth_flag
0x7fffffffe49c: 0x00000000 auth_flag のアドレス位置を確認
(gdb) print 0x7fffffffe49c - 0x7fffffffe480
$1 = 28 auth_flag は password_buffer の 28byte後にある
(gdb) c
Continuing.
Breakpoint 3, check_authentication (password=0x7fffffffe804 'A' <repeats 37 times>) at test.c:13
13 return auth_flag;
(gdb) x/16xw password_buffer
0x7fffffffe480: 0x41414141 0x41414141 0x41414141 0x41414141
0x7fffffffe490: 0x41414141 0x41414141 0x41414141 0x41414141 auth_flag のアドレス部分まで上書きされてる
0x7fffffffe4a0: 0x41414141 0x00000041 0x004006cf 0x00000000 38byte分 A(0x41) がコピーされている
0x7fffffffe4b0: 0xffffe5a8 0x00007fff 0x00000000 0x00000002
(gdb) x/x &auth_flag
0x7fffffffe49c: 0x41414141 auth_flagの参照先も書き換えられている(本来は0のままを想定)
(gdb) c
Continuing.
OK。 0 以外の場合は、OKとしてる為、パスワードが通ってしまう
Program received signal SIGSEGV, Segmentation fault. バッファオーバーランによりクラッシュ
main (argc=Cannot access memory at address 0x414141413d
) at test.c:26
26 }


トップ   編集 凍結解除 差分 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2015-04-29 (水) 12:10:30 (2012d)