這是一張圖,這也是一個 python script

Posted by TJ Wei on 星期六, 1月 19, 2013 with 1 comment
2013-01-21 更新:
這是最新的圖:
目前 face6.gif 能在 window/linux/mac/cygwin 中當成 python script 執行。
而且還有一個特異功能,讓在 windows 中的執行結果和 linux/mac/cygwin 略有差異。
除了
python face6.gif
外 ,執行
ruby -x face6.gif
perl -x face6.gif 
java -jar face6.gif
也會被當成相對應的語言執行,只是印出 Python rocks 的字串。

當成 .html 打開(比方更改副檔名),會用  javascript  印出 Python rocks,並且連到本頁。
rar x face6.gif 則會解出一些 symlinks,代表著上列可能的用法。
當然,這還是一個完整的 gif 檔案。
如果你用 unzip -v 來查看 face6.gif,除了 java 的檔案外,還會看到 __main__.py,如果你檢查 __main__.py,就會發現這個  __main__.py 沒有被執行到,因為 python 不喜歡 .zip 有 comment。

以無法為有法,以無限為有限,以無用為有用。
原理:
CPython 讀取原始檔的時候,基本上是一行一行讀的,碰到 \x00,後面的東西都會忽略(C 語言的劣根性)。
所以適當的安插 \x00,並且妥善處理 \n \r 即可。
但為什麼 mac 和 linux 會有差異?
因為 buffer 的大小不同, Linux 是每 8k 讀取, mac 則是 每 1k, windows 每行則約 0.5k。所以要適當的插入 \x00。
另外 windows 讀到 \x1a 時,檔案會直接結束,這裡也要另外處理。

如果光是要讓圖片可以被 python 執行,上面說的方法太麻煩。
其實只要把 .egg檔(有 __main__.py 的 .zip) 放到圖片後面即可。
如果這個 .zip 剛好也是個 .jar,那麼就能變成 image/python/java 三合一。
適當的位置放入 <html>...</html>,就可以當成  .html 來看。這時就能四合一。
不過這時就無法再插入 ruby, perl 的程式碼了。
mac 的 ruby 還好辦,因為碰到 \x00,後面的東西就會忽略。但 perl 及 linux 上的 ruby 似乎只能放在後面。
java 也只吃放在最後的 .jar。
還好, .zip 允許加入 comment,而且是以純文字的方式放在檔案最後,因此,我們把 #!perl 和 #!ruby 放到 .jar 的註解中即可。
問題是,如此一來, python 就不會把這樣的檔案當成 .egg了。所以還是用回我的方式,利用 .gif 的檔案結構,把整個檔案變成一個很大的 .py 檔。


原文:
相信不少人知道可以把 .rar 或是 .7z 藏在一張圖片裡面。但有沒有可能讓一個圖片檔,同時也是一個可執行的 python script 呢?
如果允許 python -x 參數的話,似乎可能性就大了點(至少 netpbm 可以)。
但在不用 -x 的參數的情形下,是否也能辦到呢?
特別是 gif, jpg, png 這類檔案中,幾乎無可避免一定有一些非 ascii 的字元,從 python source code 中會發現這些東西在第一步就會被擋下。這些檔又有固定的檔頭,也沒辦法偷偷在前面塞 #。
真的沒辦法嗎?
答案在這張圖中。


http://www.flickr.com/photos/theklan/1361277704/ CC-SA授權
(更新:上面這張圖已經可以在 *NIX 系統如 linux, osx, cygwin 的 python 2.7.3 跑,下載後直接 python face4.gif 即可。 windows 仍不行。底下的連結和說明是歷史遺跡)

如果你跟我一樣,是用 64bit ubuntu 12.10,然後有裝  python 2.7.3 的話, 可以到這裡下載上面的圖。然後 python face2.gif 執行這個 gif 檔試試看,它會一些字,而假如你有 pygame 的話,會跑出俄羅斯方塊。用一般的看圖軟體,也能夠正常的看這個圖。

更新:( 附帶說明一下,這是完全的 .py 檔案,不是 .egg/.zip。 後來才發現其實 python 會把 .zip 當成是 .egg 來跑,所以如最前面所說的,要把壓縮檔藏在圖片後面是很簡單的。所以只要把 .egg 藏在圖片後面就好了,而且 windows 也能用,所以我發現的方法完全沒有實用價值。 )
windows 版的 python 機制不太一樣,目前還不確定這個方法能不能用。

mac/cygwin 版本只是一些參數上的差異,花點時間是可以調整到同時能在 mac 及 ubunutu 上用的。
(更新,最上面的圖已經弄成在 mac  和 linux 都可用。)

更新: 示範影片
Categories: