我也跟着搞了搞,下面把感受和过程贴下。
我选了妹子打伞的那一张,首先就是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这段混乱的字符了。
东京大学这么用心,给跪了。。情报,和服,妹子,诗跟音乐,这海报牛大了。