値の調整

'%%%dc' % ((value - 1) % 256 + 1)としないといけない。

まず%cについて。 %d%xを使うと、偶然それに対応する引数の値が大きかった場合、出力させたい文字数より多い文字数が出力されるため。

$-1$ / $+1$の調整について。これは$0$を作らないため。 $\mathrm{value} = 0$のとき(python等の常に非負を返すmodであれば)$(\mathrm{value} - 1) \bmod = 255$となり全体で$256$となる。 %0cのようになってしまうと、これは別の意味(空白でなくて0埋め)のflagと解釈されてしまう。そうでなくても最低$1$文字出力される。

$ cat a.c
#include <stdio.h>
int main(void) {
    int c, d;
    printf("%0c%n", 65, &c);
    printf("%6d%n", 1000000007, &d);
    printf("\nc = %d\nd = %d\n", c, d);
    printf("%012d\n", 123);
    return 0;
}

$ gcc a.c

$ ./a.out
A1000000007
c = 1
d = 10
000000000123

golf

書き込みの際はshort writeを使うと便利であるが、%hhnは長くなるので注意。 以下は$4$byte書き込みたい時の比較。

  • 12345678123456791234567a1234567b%123c%12$hhn%123c%13$hhn%123c%14$hhn%123c%15$hhn
  • 123456781234567a%12345c%12$hn%12345c%13$hn
  • 12345678%123456789c%12$n

payloadの生成のためのコードも(関数化しない場合は)同様に長くなる。

順序

%hn%hhnを併用するとき、%hnを先に使い%hhnは後にするとよい。 %hnは$\bmod 65536$だが%hhnは$256$なので、逆にするとひとつ前の書き込み結果のみからの調整ができない。