まず、コードでセグメンテーション違反が発生していません。代わりに、「Stack Smashing」が表示され、出力コンソールの libc_message の下にスローされます。
*** stack smashing detected ***: _executable-name-with-path_ terminated.
スタック バッファ オーバーフロー バグは、プログラムがスタック上にあるバッファに実際に割り当てられたよりも多くのデータを書き込んだときに発生します。
Stack Smashing Protector (SSP) は、このようなスタック破壊攻撃からアプリケーションを保護するための GCC 拡張機能です。
そして、他の回答で述べたように、あなたの問題はインクリメント(strcat()
関数の最初の引数)で解決されます。から
char line[100]
に
char line[130]; // size of line must be atleast `strlen(line) + strlen(mod) + 1`. Though 130 is not perfect, it is safer
問題がコードのどこに正確にヒットするかを見てみましょう。
そのために、私はあなたのメインの逆アセンブル コードを作成しています。
(gdb) disas main
Dump of assembler code for function main:
0x0804857c <+0>: push %ebp
0x0804857d <+1>: mov %esp,%ebp
0x0804857f <+3>: and $0xfffffff0,%esp
0x08048582 <+6>: sub $0xb0,%esp
0x08048588 <+12>: mov %gs:0x14,%eax
0x0804858e <+18>: mov %eax,0xac(%esp)
..... //Leaving out Code after 0x0804858e till 0x08048671
0x08048671 <+245>: call 0x8048430 <strcat@plt>
0x08048676 <+250>: movl $0x80487d5,0x4(%esp)
.... //Leaving out Code after 0x08048676 till 0x08048704
0x08048704 <+392>: mov 0xac(%esp),%edx
0x0804870b <+399>: xor %gs:0x14,%edx
0x08048712 <+406>: je 0x8048719 <main+413>
0x08048714 <+408>: call 0x8048420 <__stack_chk_fail@plt>
0x08048719 <+413>: leave
0x0804871a <+414>: ret
いつものアセンブリ言語のプロローグに続いて、
Instruction at 0x08048582
: スタックは、メイン関数のストレージ スタック コンテンツを許可するために b0 (10 進数で 176) バイト増加します。
%gs:0x14 は、スタック保護に使用されるランダムなカナリア値を提供します。
Instruction at 0x08048588
: 上記の値を eax レジスタに格納します。
命令0x0804858e
:eax
コンテンツ (カナリア値) は、オフセット 172 で $esp のスタックにプッシュされます
ブレークポイント (1) を に保持します0x0804858e
。
(gdb) break *0x0804858e
Breakpoint 1 at 0x804858e: file program_name.c, line 6.
プログラムを実行します。
(gdb) run
Starting program: /path-to-executable/executable-name
Breakpoint 1, 0x0804858e in main () at program_name.c:6
6 {
プログラムがブレークポイント (1) で一時停止したら、レジスタ 'eax' の内容を出力してランダム カナリア値を取得します。
(gdb) i r eax
eax 0xa3d24300 -1546501376
breakpoint(2) を0x08048671
: call の直前に保持しますstrcat()
。
(gdb) break *0x08048671
Breakpoint 2 at 0x8048671: file program_name.c, line 33.
プログラムの実行を継続してブレークポイントに到達する (2)
(gdb) continue
Continuing.
Breakpoint 2, 0x08048671 in main () at program_name.c:33
strcat()
が呼び出される前に同じであることを確認するために、gdb で次のコマンドを実行して、ランダム カナリア値を保存した 2 番目のトップ スタック コンテンツを出力します。
(gdb) p *(int*)($esp + 172)
$1 = -1546501376
Keep a breakpoint (3) at 0x08048676
: 呼び出しから戻った直後strcat()
(gdb) break *0x08048676
Breakpoint 3 at 0x8048676: file program_name.c, line 36.
プログラムの実行を継続してブレークポイントに到達する (3)
(gdb) continue
Continuing.
Breakpoint 3, main () at program_name.c:36
gdb で次のコマンドを実行してランダム カナリア値を保存した 2 番目のトップ スタック コンテンツを出力し、呼び出しによって破損していないことを確認します。strcat()
(gdb) p *(int*)($esp + 172)
$2 = 1869111673
しかし、呼び出しによって破損していますstrcat()
。見えて同じでは$1
あり$2
ません。ランダム カナリア値が破損したために何が起こるか見てみましょう。
命令0x08048704
: 破損したランダム カナリア値を取得し、「edx」レジスタに格納します。
Instruction at 0x0804870b
: 実際のランダム カナリア値と 'edx' レジスタの内容の xor
Instruction at 0x08048712
: 同一の場合、直接 main の最後にジャンプし、安全に戻ります。この場合、ランダム カナリア値が破損しており、「edx」レジスタの内容が実際のランダム カナリア値と同じではありません。したがって、ジャンプ条件が失敗し、__stack_chk_fail が呼び出され、回答の上部に記載されている libc_message がスローされ、アプリケーションが中止されます。
便利なリンク:
IBM SSP ページ
SSP で興味深い読み物- 注意 pdf。