読者です 読者をやめる 読者になる 読者になる

Python SyntaxError Programming を解析してみた


id:TAKESAKO の 「Python SyntaxError Programming」が凄いです.

http://developer.cybozu.co.jp/takesako/2010/05/python-syntaxer.html

#!/usr/bin/python
_=-~-~(()>[]);_,__=_*_,_**_-~-~_;___='%'+`SyntaxError`[_];exec''+___*(__+~-~_)%(_*_^-~__,_*_-~__,~__*__/~_,~-~_*~_,_-__^~-~_*_,-~-~__,~-_*_,_/_^~_*~_,_-~-~_*_,_-~-~_*_,_|~-~_*~_,_+__+__/_,__,~_&_*_,__+_|_*_,_-__^~-~_*_,__^~-_*_,_|~-~_*~_,~-~_*~_,-~__,-~-~__)

これで,
「Hello, Python!」
と表示されます.
凄すぎてどうなってるのか全然わかりません><


で,頑張って解析してみました.

まずは,文ごとに分ける

; で一行にされているので,まずは改行して見やすくしてみます.

_=-~-~(()>[]);
_,__=_*_,_**_-~-~_;
___='%'+`SyntaxError`[_];
exec''+___*(__+~-~_)%(_*_^-~__,_*_-~__,~__*__/~_,~-~_*~_,_-__^~-~_*_,-~-~__,~-_*_,_/_^~_*~_,_-~-~_*_,_-~-~_*_,_|~-~_*~_,_+__+__/_,__,~_&_*_,__+_|_*_,_-__^~-~_*_,__^~-_*_,_|~-~_*~_,~-~_*~_,-~__,-~-~__)


まったく見やすくならないですね!! やりましたね!!

まずは1行目を解析してみる

_=-~-~(()>[]);


まず,_ に代入をしているのはわかります.
なので右辺を解析してみます.

-~-~(()>[]);


まずは,- も ~ も演算子なので確固のついている () > [] が先に処理されます.
で,空のタプルと空のリストを比較しています.

iPython で実行してみると

>>> () > []
True

となります.


ちなみに

>>> () < []
False
>>> () == []
False
>>> () is []
False
>>> () in []
False

という結果になります.
これは Python の決め事で,昔の Guido は何でも比較出来るのが正しいと考えてたみたいです.
(Python3.0 では比較出来ないみたいです.)


で,話しを戻すと

-~-~True;

になっているわけですね.


で,~ 記号でビット反転されています.
ビット反転が良くわからなかったのですが,
http://ja.wikipedia.org/wiki/2%E3%81%AE%E8%A3%9C%E6%95%B0
ここを id:nishiohirokazu に教えてもらってわかりました!!


で,True の数値表現は 1 なので

>>> int(True)
1
>>> ~1
-2
>>> --2
2
>>> ~2
-3
>>> --3
3

と,言う事で _ に 3 を代入している事がわかりました.

2行目を解析してみる

こうなってくると,2行目が見えてきました.

_,__=_*_,_**_-~-~_;


また代入をしているのですが,「,」 が両辺にあるので多項代入だとわかります.
で,右辺をまずはさきほど求めた 3 でおきかえてみます.

_,__=3*3,3**3-~-~3;

になります.

_,__=3*3,3**3-~-~3;

計算すると

_,__=9,32;

になります.

これで,この時点でそれぞれ変数に
_ = 9
__ = 32

が,入っている事がわかります.

3行目を解析してみる

___='%'+`SyntaxError`[_];


まずは代入なので右辺を見ていきます.
で,判明している _ に 9 を入れてみます.

___='%'+`SyntaxError`[9];


で,バッククートは括れば評価結果を取得できるので SyntaxError を評価すると
(これも Python3.0 では repr 関数に置きかわりました)

>>> `SyntaxError`
"<type 'exceptions.SyntaxError'>"

と,文字列を取得できます.

___='%'+"<type 'exceptions.SyntaxError'>"[9];

で,その文字列の配列の9要素目なので
「c」が取得できます.

___='%'+'c';
___='%c';

で,結果として
___ = '%c'
が入っている事になります.

4行目を解析してみる

exec''+___*(__+~-~_)%(_*_^-~__,_*_-~__,~__*__/~_,~-~_*~_,_-__^~-~_*_,-~-~__,~-_*_,_/_^~_*~_,_-~-~_*_,_-~-~_*_,_|~-~_*~_,_+__+__/_,__,~_&_*_,__+_|_*_,_-__^~-~_*_,__^~-_*_,_|~-~_*~_,~-~_*~_,-~__,-~-~__)

ここまでで,
_ = 9
__ = 32
___ = '%c'
が判明しているので,すべて置き換えてみます.

exec''+%c*(32+~-~9)%(9*9^-~32,9*9-~32,~32*32/~9,~-~9*~9,9-32^~-~9*9,-~-~32,~-9*9,9/9^~9*~9,9-~-~9*9,9-~-~9*9,9|~-~9*~9,9+32+32/9,32,~9&9*9,32+9|9*9,9-32^~-~9*9,32^~-9*9,9|~-~9*~9,~-~9*~9,-~32,-~-~32)

あとは計算してみると……

exec''+'%c'*(21)%(112,114,105,110,116,34,72,101,108,108,111,44,32,80,121,116,104,111,110,33,34)

となります.

で,

exec''+'%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c'%(112,114,105,110,116,34,72,101,108,108,111,44,32,80,121,116,104,111,110,33,34)

と,文字コードから文字列を作りだしていて……

exec''+'print"Hello, Python!"'


となっていて
「Hello, Python!」
と表示されます.


以上,解析結果としては,id:TAKESAKO が変態すぐるという事がわかりました><