質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

2回答

521閲覧

【C言語】scanfでは何文字まで入力可能?

退会済みユーザー

退会済みユーザー

総合スコア0

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

1クリップ

投稿2017/07/16 23:42

バッファオーバーフローを出そうと思って、以下のコードを実行したところ「a」を13文字入力するとプログラムが停止します。
12文字入力すると入力した文字がそのまま出力されますが、何故13文字入力するとプログラムが停止するのでしょうか?

#include <stdio.h> int main(void) { char str[1]; scanf("%s", str); printf("%s", str); return 0; }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答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

raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/07/17 00:24

とてもご丁寧がご説明ありがとうございます! 勉強になります!
guest

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

otn

総合スコア84498

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/07/17 02:10

ご回答ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問