Most Overlooked Obfuscation

もっとも見逃されていた難読化

受賞者:Yusuke Endoh

引用元:https://www.ioccc.org/2015/endoh2/prog.c

審査員・作者による説明:https://www.ioccc.org/2015/endoh2/hint.html

動作

catコマンドで見ると、ただのHello, world!に見える。

$ cat prog.c
int main(){ printf("Hello, world!\n"); }

しかしコンパイル・実行すると、元のプログラムが表示される。

$ gcc -w -o prog prog.c

$ ./prog
int main(){ printf("Hello, world!\n"); }

$ ./prog | diff -s - prog.c
Files - and prog.c are identical

デモ動画。

図:作者によるデモ動画(引用元:https://www.youtube.com/watch?v=QZkRw2bik9Q

解説

バックスペース文字を悪用したQuine。 プログラムを20文字程度ずつに分割し、20文字書いたらバックスペースで20文字戻る、というのを繰り返すコードになっている。 実際には、コード中にバックスペース文字が出現したらコンパイルが通らないので、文字列リテラルでバックスペースを包む必要がある。 20文字程度ごとに文字列リテラルが割り込んでくるという制約で書くことになるので多少面倒くさい。 バックスペース文字を難読化に使うアイデアは[[2011/fredriksson]]でも少し登場していた。

アンダースコアを出力した後、バックスペースで戻り、文字を出力すると、タイプライタの時代では下線付き文字となっていた。 これを重ね打ちという。 同じ文字を重ね打ちすることで太字にするハックもあった。 これらのハックは今でもlessのようなページャに実装されており、prog.cをlessで見ると強調・下線付き文字になる(端末にもよる)。

プログラムの構造を見たいときは、次のように、バックスペースの列の前にカーソルを下に移動させるエスケープシーケンスを入れるとよい。

$ clear && ruby -e 'puts File.read("prog.c").gsub(/\x08+/) { "\e[B" + $& }'
int main(){ printf("");{char*p,s[999]="i
                   nt main(){ printf(~~)
                   ;{char*p,s[999]=~%s
                   ~,*q=s,c;for(p=62**~
                   ~+q;q<s+435;c=q-s>*~s
                   ~||c>8?*p++=c-35?*~}
                   ~<c?34:c:92:0,p[*~
                   ~]=0)c=*q++;*p=2+*~
                   ~;printf(s+62**~
                   ~,s);}return(*~#0
                    _
                    H
                    H_
                     e
                     e_
                      l
                      l_
                       l
                       l_
                        o
                        o_
                         ,
                         ,_

                           _
                           w
                           w_
                            o
                            o_
                             r
                             r_
                              l
                              l_
                               d
                               d_
                                !
                                !#n~); }
                   ",*q=s,c;for(p=62**"
                   "+q;q<s+435;c=q-s>*"s
                   "||c>8?*p++=c-35?*"}
                   "<c?34:c:92:0,p[*"
                   "]=0)c=*q++;*p=2+*"
                   ";printf(s+62**"
                   ",s);}return(*"\0
                    _
                    H
                    H_
                     e
                     e_
                      l
                      l_
                       l
                       l_
                        o
                        o_
                         ,
                         ,_

                           _
                           w
                           w_
                            o
                            o_
                             r
                             r_
                              l
                              l_
                               d
                               d_
                                !
                                !\n"); }