バッファオーバーフローを出そうと思って、以下のコードを実行したところ「a」を13文字入力するとプログラムが停止します。
12文字入力すると入力した文字がそのまま出力されますが、何故13文字入力するとプログラムが停止するのでしょうか?
#include <stdio.h> int main(void) { char str[1]; scanf("%s", str); printf("%s", str); return 0; }
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
ベストアンサー
C言語でバッファオーバーフローが発生した場合の動作は未定義です。未定義な動作とは、どのような動作が起きるかはわからないことを意味します。OS、コンパイラ、コンパイル時のオプション、実行時の環境、OSを含む各種設定、等々によって、そのまま正常に動いたり、動作自体が無視されり、エラーになったり、任意のコマンドが実行できたり、等の予測不可能な現象が発生します。12文字では正常っぽい動作で、13文字でエラーになったのは、ただの偶然です。あなたの環境はたまたまそのような動作をするようにコンパイルされていて実行されたに過ぎません。OSを変えたり、コンパイラを変えたり、コンパイル時のオプションを変えたり、実行するタイミングを変えたりしたら、5文字でエラーになるとか、逆に100文字でも出力できるとか、いろいろと変わる可能性があります。「バッファオーバーフローは何文字まで大丈夫か?」という問いには、C言語の規格としては「0文字までは大丈夫だけど、1文字でも溢れたら、何が起きるかは予測は不可能」と答えるしかありません。
それでも、なぜ12文字と13文字で変わるのかを知りたいのであれば、どのような環境でどのようにコンパイルされてどのように動作するのかを細かく分析しないとわかりません。OS(細かいバージョンまでです。Windows 10ではなくWindows 10 Pro, バージョン: 1703, OSビルド: 15063.483と言ったところまで知る必要があります)、コンパイラ(単にVC++とかではなく、こちらもバージョンやアップデートも含めてです)、コンパイル時のオプション(コンパイルそのものへの設定があれば、それも含めて)、実行環境(データ実行防止(DEP)の有無、ウィルススキャンソフトの有無、その他のセキュリティ関係のポリシー)を知る必要があります。コンパイルされたバイナリを逆アセンブラで解析し、スタックへの書き込みをエミュレートしながら、バッファオーバーフロー時にどのようにメモリが変更され、問題があるかないかを見る必要があります。かなり高度な知識が要求されますが、よくあるバッファオーバーフローをついて任意コマンド実行を行う方法(いわゆるバッファオーバーフローに起因する脆弱性というものです)を調べる場合は必須の技術ですので、セキュリティー分野に進みたいのであれば身につけておいて損はありません。
投稿2017/07/17 00:22
総合スコア21735
0
12とかの数字はたまたまです。手元のLinux/64bitのgccでやってみましたが、8まででした。
規格がどうなっているかという話じゃなくて、実際がどうかという話をします。
これは、コンパイラによって異なる部分です。また同じgccでも、32bitのコードを生成するのか64bitのコードを生成するのかによって異なります。
停止の原因は、スタック上の「呼び出し元への戻りアドレス」の破壊でしょう。
mainが呼び出された時点で、スタックトップには、呼び出し元への戻りアドレスが入っています。
呼び出された後に、BPレジスタの値がスタックにPUSHされます。64bitコードだとこれが8バイト。
char str[1];
の1バイトの変数はその直下です。
入力したのが8文字までだと、最後のNULバイトを含めて9文字なので、変数の1バイトと、BPレジスタの値の8バイトの範囲で収まり、呼び出し元への戻りアドレスは無傷です。なので、呼び出し元に戻ることが出来ます。
ただし、呼び出し元へ戻ったあとのBPレジスタは文字列の値で上書きされていますので、呼び出し元が処理続行する場合は、その後の処理がおかしくなる可能性があります(後述)。
入力したのが9文字以上だと、呼び出し元への戻りアドレスを壊してしまいますので、mainからの戻りの時点でおかしなアドレスに戻ろうとして、ほとんどの場合、未割り当てアドレスへのアクセスとなり、セグメンテーション違反の例外になります。
戻りアドレス部分に書き込む値を調整すると、存在するアドレスに戻ることが出来、これがバッファーオーバーフロー攻撃です。
#BPを破壊した場合どうなるか
質問の例のように、mainプログラムで、プログラム終了=プロセス終了の場合は、影響ないようです。
これが、サブルーチンだとすると、呼び出し元で処理が続行できません。
サンプル:
C
1#include <stdio.h> 2 3int sub(void) 4{ 5 char str[1]; 6 scanf("%s", &str); 7 printf("%s", &str); 8 return 0; 9} 10 11int main(void) 12{ 13 printf("Before\n"); 14 sub(); 15 printf("After\n"); 16 return 0; 17} 18~
これだと、1文字の入力で、"After"を表示の後にセグメンテーション違反になりました。0文字入力(入力行の行頭でctrl-D)の場合はstr[0]
にNUL
が入るだけなのでOKです。
投稿2017/07/17 02:07
総合スコア84499
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2017/07/17 00:24