2

フォーマットされたI/O関数が、提供された引数よりも多くの引数を予期している場合に、フォーマット文字列攻撃が発生することを私は知っています。

Cでは、

メモリ位置を読み取るための1つの例:

printf("%x"); // this prints a memory address location in the stack

メモリ位置を上書きする別の例:

printf("Overwritten%n"); //this prints the number of chars in "Overwritten"

私の質問は:なぜこれが両方の場合に起こるのですか?対応する値を指定せずにフォーマットされた文字列に%xしかないのに、メモリにアドレスが出力されるのはなぜですか?そして、そのアドレスは正確には何ですか?私はそれが起こることを知っています、しかし実際に何が起こっているのですか?

上書きについても同様です。

4

4 に答える 4

4

発生するのは未定義の動作です。Printf は、対応する値がないことを知りません。呼び出しの 2 番目のパラメーター (提供していない) にアクセスし、ランダムなメモリ値にアクセスしようとします。

の場合"overwritten%n"、%n は、%n を呼び出すまでに書き込まれた文字数をメモリに保存します。正しいアドレスを渡さずに if を呼び出すと、ランダムな場所に何かが書き込まれ、メモリが破損する危険があります。

于 2012-10-05T11:28:20.063 に答える
2

C が「高水準アセンブラー」と名付けられていることを考えると、その答えはそのコンパイラー構造にあります。printfすべての引数が実際に提供されたかどうかをチェックすることなく、可変数の引数を受け入れる関数です。そのため、関数がコンパイラ レベルでどのように引数を受け入れるかに応じて、次のシナリオが可能です。

まず、printf に渡された文字列が解析され、内部関数が呼び出され、2 番目のケースでは文字列 'Overwritten' が出力されます (最初のケースでは、フォーマットされた文字列の最初の記号は '%' です)。これはパラメータを意味します)。次に、パラメーターが出力されるように要求されると、対応する生データ出力ルーチンが呼び出され、次に何をスタックに配置するかを引数に指定します (オフセットはコンパイル時に計算されます)。の場合、%x引数はなく、印刷される変更されていない文字列は空であり、割り当てられていないため、スタック内の次の 32 ビット値は現在の戻りアドレスであり、EXE の読み込み時に OS によって生成されたものです。時間、実際に経由してスタックに入れますcall printf_hex_address組み立て説明書。この攻撃は、処理プログラムが実際にメモリ内に永続的であり、スワップされない場合、このアドレスはプログラムのアドレス空間内の書き込み可能なメモリ位置であるという事実に基づいているようです。「上書きされた」長さが表示される理由は、文字列の実際の長さが渡されるように設計された内部文字列操作ルーチンによって説明できます。

于 2012-10-05T11:31:56.903 に答える
1

あなたに役立つかもしれません:
あなたはWindowsで作業していると思います。厳密なチェックは行われません。
Linuxでも同じことを試しましたが、警告が表示されました。

int main(){
printf("%x");
printf("上書き%n");
}


$ gcc test.c
test.c: 関数 'main' 内:
test.c:4: 警告: フォーマットの引数が少なすぎますtest.c
:5: 警告: フォーマットの引数が少なすぎます

于 2012-10-05T11:28:50.693 に答える
1

これはprintf、プログラマーの意図がわからないためです。フォーマット文字列にフォーマット識別子がある場合、適切な引数をフォーマットします。

printf("%x");

追加の引数が必要です (通常はレジスタまたはスタックに格納されます)。プログラマーはこの呼び出しでコンパイラーに追加の引数を提供するように指示しなかったため、printfその時点で引数を見つけることが期待される場所に格納されているものはすべて出力されます。

最適化の理由から、コンパイラは通常、次の関数を呼び出す前にレジスタをクリアしません。

于 2012-10-05T11:29:54.200 に答える