我也跟著搞了搞,下面把感受和過程貼下。
我選了妹子打傘的那一張,首先就是OCR識別01,在linux下用的tesseract-ocr,具體使用方法在這篇文章裡提到了,很詳細,不過稍微有些舊,具體配置過程參見裡面提到的官方文檔。
提前說一下,偶用tesseract-ocr識別的並不足夠準確==!(看STAGE1裡面人家用的是漢王搞的,我後來就沒有再試,直接用的人家搞下來的01繼續了下一步。。)我是這麼做的。
首先在google code上下載了tesseract-ocr源碼,按文檔解決好依賴,然後配置安裝。接著下載語言套件,在列表裡可以看到一個Math/Equation的,不是因為要識別數字就下載這個包,我們只要eng的就可以。然後解壓到tessdata下,如果你有自己的安裝目錄,要export一下tessdata的副檔案夾(如果找不到訓練集,tesseract也會提示你設一下),不然的話就放在/user/local/share/tessdata下。最新的tesseract已經支援不少圖片格式了,因此沒必要在convert格式。
執行tesseract 1.png 1.out -l eng。結果只有一點點亂七八糟的東西,一點意義也沒有。。為了提高識別準確度,可以把每一行截個圖,逐行處理。甚至可以用PS,總之提高圖片裡數位對比跟清晰度,然後再給tesseract識別。
這回好多了,不過發現結果裡面有好多字母,我們明明只需要數位,沒必要讓它把字母也包進來,況且還是錯的。。可以給tesseract加個配置項digits,這樣它就只會識別數字了,執行tesseract 1.png 1.out -l eng digits,結果裡有一些94.。。再縮小範圍,讓tesseract只識別01. 不過預設檔案沒有這個配置項,我們可以手工寫一個。
在/usr/local/share/tessdata/configs裡,sudo cp digits binarys,然後修改一下binarys,使其只識別01. binarys最終內容如下:tessedit_char_whitelist 01
現在執行tesseract 1.png 1.out -l eng binarys,結果已經好很多了。不過苦B之處在於,這個結果總歸是不可信的,你還得一個一個去比對tesseract是不是識別對了。
總結,OCR識別有意義的文字,對準確度要求並不高。但是識別二進位碼要求就相當高了,錯一個都沒的進行下一步==!
接下來就是把識別的文本的二進位碼轉化成一些有意義的東西。在(上)中,可以看到作者對每行幾個,一共幾行,總數是不是8的倍數等都統計了一遍,要想出這些二進位碼到底是什麼感覺是最最難的一步,得有足夠的想象力。妹子打傘的這個還好說,直接寫成二進位檔案就是下一步的結果,紅衣端莊全身照的那個,作者最後說搞出來一段二進位碼是重複的,並且最後一次重複還有點雜訊,然後作者就直接扣出那一段分析,不管其它的了,總覺得不夠完美啊,恩。。果然還是這一步最難了。
下面把文本二進位碼寫成二進位檔案的代碼貼下,需要說明的是,這段代碼不通用,因為我預設的二進位碼總數是8的倍數(太爛了,好久不寫cpp)。
#include<fstream>#include<iostream>using namespace std;int main(){ ifstream infile; infile.open("binary"); if(infile){ cout<<"open success!"<<endl; ofstream outfile; outfile.open("binaryout",ofstream::out); if(!outfile){ cout<<"open write file failure"<<endl; return 0; }else{ cout<<"open outfile success!"<<endl; } char in,out,tmp; int count=0; int totalInterator = 0; out=0; while(true){ cout<<"totalInterator:"<<totalInterator<<endl; totalInterator++; in = infile.get(); if(!infile.good()){ break; } if(in==10){ continue; } tmp = ((in-'0')<<(7-count)); out = out | tmp; count++; if(count==8){ count=0; outfile.put(out); outfile.flush(); out=0; } } outfile.flush(); outfile.close(); infile.close(); cout<<"done"<<endl; }else{ cout<<"open error!"<<endl; } return 0;}
在(上)中,作者反覆提到了big-endian,little-endian,但是這裡其實是用不到這個概念的==!不信你看他最後結論是不是都是big-endian正確?big-endian,little-endian分別是一個數儲存的時候以高位地址結尾和以低位地址結尾, 但是單位是位元組,因此又稱作高位元組序和低位元組序。一個ASCII碼本來就是一個位元組,因此也無所謂高位元組序,低位元組序了。作者的意思可能是一個位元組正著存還是反著存,這個我覺得除非是解人家加密的密碼,否則沒有這個考慮的必要。
寫出來的二進位檔案,要分析它的屬性,就需要看檔案的頭幾個位元組,類型一般是前三位元組。我從網上搜來一點類型,展示一下。
SWF (swf):"435753"或者“465753" JPEG (jpg):"FFD8FF" PNG (png):"89504E47" GIF (gif):"47494638" TIFF (tif):"49492A00" Bitmap (bmp):"424D" CAD (dwg):"41433130" XML (xml):"3C3F786D6C" HTML (html):"68746D6C3E")); Word/Excel (xls.or.doc):"D0CF11E0" Access (mdb):"5374616E64617264204A" ZIP Archive (zip):"504B0304" RAR Archive (rar):"52617221" Wave (wav):"57415645" AVI (avi):"41564920" Real Media (rm):"2E524D46" MPEG (mpg):"000001BA"或者"000001B3" Quicktime (mov):"6D6F6F76" Windows Media (asf):"3026B2758E66CF11"
由於linux不是靠副檔名識別檔案類型的,所以gnome一下就認出了這是gz,不然我們就自己搜然後用對應的軟體開啟好了。
給二進位檔案(我的叫binaryout)加上副檔名gz,命令列解壓下:gunzip binaryout.gz。或者保留著源壓縮包,gunzip -c binaryout.gz > binaryout
不加副檔名,gunzip預設是不給你解壓的,除非加上參數-f。
然後華麗的class檔案就出來了~cafe babe有木有~
你可以這麼看二進位檔案:vim binaryout -b以二進位方式察看,然後在vim裡面轉換成十六進位,看的方便點: %!xxd .有一篇文章講的就是這個。
直接運行找不到類是正常的,因為Java 要求檔案的類名要和程式裡的類名統一的,即主程式類名是A,那麼這個編譯後的class檔案命名為A.class。我們搞成這種形式就能運行了。在(上)中,java拋出的錯誤直接提示了類名是i。我的並沒有這個提示,只說找不到類。其實都到這步了,哪用管這麼多,直接jd反編譯,看結果。不貼代碼了,(中)裡面62樓有寫的,那就是完整代碼。
然後或者你把binaryout改名成i.class,或者你乾脆把代碼copy到你的eclipse裡運行一下,URL結果就出來了。
其實這段java代碼也挺好玩,這段雜亂的字串是怎麼組織起來成為URL的?
我們通過以下代碼來看每次訪問的index
#include<stdio.h>int main(){ int arr[42]; int x,i; for(i=0;i<42;i++){ arr[i]=0; } for(i=0;i<50;i++){ x = i * 6 % 41; printf("%d",x); if(arr[x]==0){ arr[x]=1; }else{ printf("collision!"); } printf("\n"); } return 0;}
輸出結果發現,前41個根本沒有衝突,接下來才會發生衝突。而www.i.u-tokyo.ac.jp/fun/hikari-loveletter,這段URL長度正好是41!因此只要對URL每個字元換到新的位置,就是w-aurlwtcniewo./-t.kjhltiypioe.o/kvru.fae這段混亂的字元了。
東京大學這麼用心,給跪了。。情報,和服,妹子,詩跟音樂,這海報牛大了。