%n
C でのフォーマット指定子の使用は何ですか?誰かが例で説明できますか?
%n
しまうことが発見されました。printf
たとえば、それにBrainfuckを実装できます。github.com / HexHive
%n
C でのフォーマット指定子の使用は何ですか?誰かが例で説明できますか?
%n
しまうことが発見されました。printf
たとえば、それにBrainfuckを実装できます。github.com / HexHive
回答:
何も印刷されません。引数は、それまでに書き込まれた文字数が格納される、signed intへのポインターでなければなりません。
#include <stdio.h>
int main()
{
int val;
printf("blah %n blah\n", &val);
printf("val = %d\n", val);
return 0;
}
前のコードは次のように出力します。
blah blah
val = 5
int
は常に署名されています。
n format specifies disabled
。どういう理由ですか?
これらの回答のほとんどは何をするか(何も出力%n
せず、これまでに出力された文字数をint
変数に書き込むこと)を説明していますが、これまでのところ、実際に使用方法の例を示した人はいません。ここに1つあります:
int n;
printf("%s: %nFoo\n", "hello", &n);
printf("%*sBar\n", n, "");
印刷されます:
hello: Foo
Bar
フーとバーを揃えて。(%n
この特定の例を使用せずにそれを行うのは簡単です。一般に、最初のprintf
呼び出しを常に中断することができます:
int n = printf("%s: ", "hello");
printf("Foo\n");
printf("%*sBar\n", n, "");
少し追加された利便性が難解なものを使用する価値があるかどうか%n
(そしておそらくエラーを導入するかどうか)は議論の余地があります。
&n
はポインタです(&
アドレス演算子です)。Cは値渡しであり、ポインターprintf
がないとの値を変更できなかったため、ポインターが必要ですn
。フォーマット文字列%*s
での使用は、printf
文字のフィールド幅を使用して%s
指定子(この場合は空の文字列""
)を出力します。基本的な原則の説明は、基本的にこの質問(および回答)の範囲外です。ドキュメントを読むか、SOについて独自の質問をすることをお勧めします。n
printf
printf
私は実際に%n
指定子の実際の使用を多く見たことはありませんが、かなり前からフォーマット文字列攻撃を伴う古い学校のprintfの脆弱性で使用されていたことを覚えています。
このようになった何か
void authorizeUser( char * username, char * password){
...code here setting authorized to false...
printf(username);
if ( authorized ) {
giveControl(username);
}
}
どこ悪意のあるユーザーがフォーマット文字列としてprintf関数に渡されたばかりのパラメータ名を利用しての組み合わせを使用することができ%d
、%c
またはW / Eは、コールスタックを経由して、真の値に許可変数を変更します。
ええ、それは難解な使用ですが、セキュリティホールを回避するためにデーモンを作成するときに知っておくと常に役に立ちますか?:D
%n
未チェックの入力文字列をprintf
フォーマット文字列として使用しないようにするよりも多くの理由があります。
これまでのところ、すべての答えはそれについてです%n
が、誰もが最初にそれを望んでいる理由ではありません。私はそれがsprintf
/snprintf
保存された値は結果の文字列への配列インデックスであるため、結果の文字列を後で分割または変更する必要がある場合に。ただし、このアプリケーションはを使用するとさらに便利にsscanf
なります。特に、scanf
ファミリの関数は処理された文字数ではなくフィールド数を返すためです。
別の本当にハックな使い方は、別の操作の一部として数値を出力すると同時に、無料で疑似log10を取得することです。
%n
、「すべての回答...」については違います。= P
%n
ても、攻撃者に対する脆弱性の危険性はまったくありません。誤って配置された悪名は%n
、フォーマット引数としてフォーマット文字列ではなくメッセージ文字列を渡すという愚かな習慣に本当に属しています。もちろん、この状況%n
が実際に使用されている意図的なフォーマット文字列の一部である場合には決して発生しません。
*p = f();
。%n
ポインタ自体が危険であると見なすのではなく、ポインタが指すオブジェクトに結果を書き込むもう1つの方法であるを「危険」と見なす必要があるのはなぜですか?
先日%n
、問題をうまく解決できる状況に身を置きました。私の以前の回答とは異なり、この場合、私は良い代替案を考案することはできません。
指定したテキストを表示するGUIコントロールがあります。このコントロールは、そのテキストの一部を太字(または斜体、下線など)で表示できます。また、開始文字インデックスと終了文字インデックスを指定することで、どの部分を指定するかを指定できます。
私の場合、コントロールを使用してテキストを生成していますsnprintf
。置換の1つを太字にしたいと思います。この置換の開始インデックスと終了インデックスを見つけることは簡単ではありません。
文字列には複数の置換が含まれ、置換の1つは任意のユーザー指定のテキストです。これは、気になる置換のテキスト検索を実行することは潜在的にあいまいであることを意味します。
フォーマット文字列はローカライズされる場合があり$
、位置フォーマット指定子にPOSIX拡張を使用する場合があります。したがって、元のフォーマット文字列でフォーマット指定子自体を検索することは簡単ではありません。
ローカリゼーションの側面は、フォーマット文字列をへの複数の呼び出しに簡単に分割できないことも意味しsnprintf
ます。
したがって、特定の置換に関するインデックスを見つける最も簡単な方法は、次のようにすることです。
char buf[256];
int start;
int end;
snprintf(buf, sizeof buf,
"blah blah %s %f yada yada %n%s%n yakety yak",
someUserSpecifiedString,
someFloat,
&start, boldString, &end);
control->set_text(buf);
control->set_bold(start, end);
snprintf
ので、snprintf
戻り値をチェックしながら3つは問題なく動作するようです。多分何かのように:int begin = snprintf(..., "blah blah %s %f yada yada", ...);
とint end = snprintf(..., "%s", ...);
、その後、尾:snprintf(..., "blah blah");
。
snprintf
呼び出しの問題は、置換が他のロケールで再配置される可能性があるため、そのように分割できないことです。
%n
。使用する%n
方が他の方法よりも簡単であると私は主張しています。
何も印刷されません。これは%n
、フォーマット文字列に現れる前に印刷された文字数を把握し、それを提供されたintに出力するために使用されます。
#include <stdio.h>
int main(int argc, char* argv[])
{
int resultOfNSpecifier = 0;
_set_printf_count_output(1); /* Required in visual studio */
printf("Some format string%n\n", &resultOfNSpecifier);
printf("Count of chars before the %%n: %d\n", resultOfNSpecifier);
return 0;
}
そのprintf()
関数でこれまでに印刷された文字数の値を格納します。
例:
int a;
printf("Hello World %n \n", &a);
printf("Characters printed so far = %d",a);
このプログラムの出力は
Hello World
Characters printed so far = 12
%nはC99であり、VC ++では機能しません。
%n
C89に存在した。Microsoftはセキュリティ上の理由からデフォルトでMSVCを無効にしているため、MSVCでは機能しません。_set_printf_count_output
有効にするには、最初に呼び出す必要があります。(Merlyn Morgan-Grahamの回答を参照してください。)
printf
K&R、第2版の付録Bの表B-1(変換)に明記されています。(私のコピーの244ページ。)または、ISO C90仕様のセクション7.9.6.1(134ページ)を参照してください。