第 2 节
作者:雨来不躲      更新:2022-08-10 08:35      字数:5269
  赡芄诖蠖嗍砑镜墓芾碓倍疾皇强⑷嗽背錾恚栽创氩桓行巳ぃ允詹氐亩际?12 KB的EXE,有源代码的不多,需要仔细找一下。
  在unwebpiler的源代码里,RMH和Fbilo对Web piler 1。67生成的电子书的文件格式进行了详细描述,在这里我就不做无聊的重复,有兴趣就自己去看吧。我做的UnEBook也使用了他们提供的源代码,实现对Web piler 1。67生成的电子书的批量反编译,不过被我将代码从Delphi改成了C,似乎长度缩短了一些(原代码中有一段在字符串和十六进制数之间转换来、转换去,看起来比较怪异,被我省了),不过LHA解压缩部分改起来实在太麻烦,我直接在网上找了一段现成的C代码来用。
  2。2。2。2 Caislabs eBook Pack Express 1。6
  这个电子书制作工具也出过汉化版,所以在国内也有一定影响,不过这种影响似乎还没有大到足以使反编译工具满天飞的程度,嘿嘿……
  在分析这种格式的电子书的时候,我没有使用任何反汇编工具,用UltraEdit32和系统监视工具就猜出来了:
  文件标识:以十六进制串 00 F8 03 00 结尾。这个似乎是一种惯例,差不多所有EXE格式的电子书都有自己特殊的文件结尾。
  目录块起始地址指针:0003F81C
  目录块中目录项结构:以0字符结尾的文件名+4字节起始地址,文件名起始字节为FF则目录块结束。
  如果文件存放在子目录里,则文件名首字符:02=。。/,01:第一个00变成/,直到遇到02。
  文件内容实际起始地址:目录项里的4字节起始地址+9
  文件内容长度:目录项里4字节起始地址所指内容,DWORD。
  在分析出目录结构后,我曾经想通过调试工具,分析文件加密算法,再反编译出具体的文件内容,但是很快我就发现那样干太累了,实在是得不偿失。
  不过在经过几次尝试后,我还是找到了一个偷懒的办法:
  通过安装hook的方法,往电子书的进程空间注入一个DLL。
  在这个DLL里,用Windows标准的API函数URLDownloadToFile,就可以下载到指定的文件。文件的URL可以按前面说的方法,从目录项得到相对路径,再加上一个固定前缀(〃file://Z:_caislabs_ebk”)构成绝对路径。
  UnEbook在批量反编译这种格式的电子书的时候,就是按照上面的分析结果实现的。
  不过到了更高版本的Caislabs eBook Pack Express的时候,似乎Caislabs公司也开始意识到文件内容保护的重要性,因此不仅对文件内容采用更强的加密算法,杜绝了可以用URLDownloadToFile下载的漏洞,连目录块的加密强度都强到足够使我不想去分析了。幸好这个时候我已经有了更好的反编译思路--与具体文件格式无关的,专门针对使用IE内核的电子书的通用反编译思想。
  2。2。2。3 通用反编译思路
  在分析过几种电子书格式后,我开始领悟到一个真理:电子书内部文件结构的变化是无穷的,而我的时间和精力是有限的;把有限的时间和精力投入到对抗无穷的变数中去,早晚会有累死的一天。
  有此认识后,我开始思考有没有什么通用的方法,可以解决大部分电子书的反编译问题(我还没有幼稚到相信这世上会有万能药的程度)。按照惯例(不可救药的职业病),第一步当然是市场调查、产品定位,结论是目前大多数电子书都是基于IE内核的,但是根据我在开发MyReader时对IE内核的了解,这里面明显存在一个误区:微软以控件的形式提供IE内核,其目的就是希望通过控件接口的开放性、方便性,吸引更多的人加入微软的标准阵营,如果想在此基础上添加加密、保护等等内容,恐怕与微软的初衷不合(我说的是当时,以后微软改主意了也说不定)。因此我相信IE内核一定有后门可走!经过一番努力,果然没有令我失望。
  1、基本原理
  针对IE内核电子书的通用破解技术实现起来可能需要一些技术和技巧,但是原理却很简单,几句话就可以说清楚:不论电子书在存储的时候如何对内容进行加密,在将内容传递给IE内核进行显示的时候,一定要将内容转换成IE内核能够识别的标准格式--HTML格式。而IE内核为了便于显示、刷新,在对HTML代码进行解析后,并不是立刻就把这些HTML代码抛弃,而是在内存里保存了一份备份。因此只要将这份备份从IE内核里搞出来,就得到了解码后的内容,也就是反编译想得到的内容。
  至于网页中的其它内容,包括图片、css、js、Flash文件等,就更简单了:模拟IE内核,直接找电子书要就好。如果电子书分辨不出请求是来自IE内核还是来自其它地方,自然会乖乖把我们需要的东西双手奉上!
  虽然反编译的原理几句话就可以说清,但是要加以实现,还需要经过艰苦的探索和试验,我自己就经过了长期的努力,IE内核的源代码都翻来覆去看了好几遍(吹的,别当真!)。而我思想的发展也大概经历了两个阶段:第一个阶段是在得到某份传说中的源代码(没错,就是那份展开后近700MB,被国内主流媒体形容为噱头、无足轻重、充满无聊垃圾的东西)之前,完全立足于微软公开的IE内核接口。当时我考虑将电子书内容按照HTML、图像等分类,分别解决获取问题。第二个阶段是在得到那份源代码之后,我突然发现其实对于所有文件,我都可以直接找电子书要,只要假装是IE内核在要就行了。
  由于某些东西比较敏感,因此下面叙述的主要是我第一个阶段的想法,其中有些属于基础性的东西。第二个阶段的实现恕我不便奉告。
  2、获取HTML源代码的方法
  从IE内核获取HTML源代码的方法不仅我一个人在想,从国内到国外,从CSDN(CSDN的VC/MFC区有一个栏目专门讨论IE内核编程)到MSDN,早就有很多人讨论过了,归纳起来,一般认为可以通过下列步骤实现:
  不管是通过鼠标点击也好,通过EnumChildWindow也好,总之先找到IE内核的显示窗口,也就是电子书显示网页内容的那个窗口。
  通过这个窗口的句柄(HWND),取得这个窗口对应的IE内核文档接口IHTMLDocument2的接口指针。取得的方法目前认为有两种,我个人认为这两种需要结合使用,否则总有一些电子书会搞不定:一个是通过MSAA,一个是通过WM_HTML_GETOBJECT消息。至于具体的实现代码,在CSDN上都快被讨论烂了,因此此处从略,有需要的自己到CSDN上找。不过这两种方法都对平台有要求:XP下是完全没有问题,2000下可能需要装IE 6,98/Me/NT就不要想了。
  在得到IHTMLDocument2接口指针后,按照这个接口提供的标准方法,即可获得文档的HTML代码。具体实现代码见CSDN中的例子。
  除了上面这种方法外,我自己还尝试过一种方法:使用MIME Filter。
  对于搞过网页在线翻译、网页内容过滤的人来说,MIME Filter可是吃饭的本钱,它的作用和实现机理应该早就烂熟于心,但是对于其它人来说,可能还不是很熟,所以这里简单介绍一下:为了便于对IE内核的功能进行扩展,微软规定在IE内核显示某种标准格式(HTML、TEXT等)的内容之前,会先将要显示的内容传递给这种格式的过滤器,即MIME Filter,由它先对内容进行预处理(如将英文翻译成中文,将下流文字替换成星号等),然后再显示。
  按照这个原理,如果实现一个针对HTML格式的MIME Filter,即可拦截到最原汁原味的HTML代码。可惜,经过我的尝试,这招对IE本身是灵的,对某些电子书也有效,但是对另一些无效。再加上使用IHTMLDocument2接口指针的方法要比这种方法简单得多,也可靠得多,所以后来在我开发的反编译工具KillEBook、IECracker和CtrlN里就没有使用这种方法。不过这种方法也有一个好处:与平台无关,我在98/Me/2000/XP下都试过,当然都是在虚拟机下试的啦。
  MIME Filter的作用机理、实现方法在MSDN里有详细说明,并提供了详细的实例代码,有需要的可以到MSDN上搜“MIME Filter”。
  3、获取图像的方法
  与HTML代码相似,IE内核对图像的处理也有一个“下载…》解码…》显示”的过程。考虑到显示代码的抽象性,原来各种各样的图像格式,包括JPG、GIF、PNG、TIFF等,在解码后都被统一表示成位图格式,而原有格式数据在解码后即被从内存中释放,只在IE的cache中留有文件备份。如果指定不允许保存本地cache,则连这个备份都没有。在IE中通过右键菜单选“图片另存为。。。”的时候,其实就是将cache中的文件备份拷贝一份出来,如果cache中已经没有备份,就只能保存内存中的位图(*。bmp)了。现在明白为什么有些图片明明是jpg格式,但是用IE却只能保存为“无标题。bmp”了吧?
  因此,获取图像文件要比获取HTML文件难得多。而且在MSDN里说得很清楚,用IHTMLDocument2接口只能得到图像的链接,用MIME Filter也不能搞到网页里的图像数据,因此需要另想办法。我想过、试过的包括:
  先将图像复制到剪贴板,再从剪贴板里获取图像数据,然后根据图像文件扩展名(可以从图像元素的URL里解析),编码成原始图像格式,包括jpg、png、gif、tiff等。这个方法实现比较简单,到MSDN KB里搜索Q293125,拷贝图像到剪贴板的现成源代码就有了,图像编码的源代码则可以参考cximage,这个也是google一下就有的。不过这个方法远非完美无缺:a)。 对于png、gif等允许带透明背景的格式,用这种方法处理后就不透明了。b)。 gif动画处理后就动不起来了,只能显示其中的某一帧。c)。 对于jpg这样的有损压缩格式来说,每压缩一次就损失一次,多压缩几次可能就没法看了。d)。 在电子书里,可以通过标准的Windows API函数,使剪贴板失效。
  将IE内核导航到图片,然后通过IViewObject接口获取图片的拷贝。这个方法与上面的方法基本相同,不过不通过剪贴板,可以防止因为剪贴板被封锁而搞不到图像。
  使用IE图像解码插件。IE内核在下载到某种格式的图像文件后,会调用对应的解码器,对图像进行解码(类似于MIME Filter)。为了便于扩充,解码器是做成插件形式的。如果自己做一个图像解码器插件,对解码请求进行拦截,即可获得解码前的原始图像格式数据。解码器的接口、实现方法在微软公开文档中没有任何蛛丝马迹,但是在那份传说中的源代码里,不仅有详细的接口规范,而且有好几个内嵌图像解码器的实现代码,可供借鉴。奇怪的是,虽然在MSDN中找不到,但是我在google上搜的时候,却发现有一个日本人在自己的个人网站上,早就给出了详细的图像解码器插件实现方法,一步一步说得很清楚,而且落款时间是2002年12月!看来这份源代码的泄漏时间可能比想象的要早。当然这个日本人也可能本来就在微软工作,或与微软有合作关系,可以光明正大地查看解码器源代码也说不定。
  4、通用反编译器的实现
  在解决了HTML、页面元素等的获取方法后,通用反编译器KillEBook的实现就很简单了,其算法可以描述如下:
  打开电子书。
  定位电子书的显示窗口。
  获取当前显示页面的HTML代码。
  解析页面HTML代码,得到其中的所有链接。
  获取页面上的所有元素内容,包括图片等。
  引导IE内核依次加载HTML链接页面。
  重复步骤3~6,直到所有页面及其中的元素都已获取到。
  5、进一步讨论
  在完成KillEBook后,我发现其实对它扩展一下,就可以成为一种新的离线浏览器,解决传统离线浏览器(Offline Explorer Pro、Webzip等)面临的一个问题:传统离线浏览器多半与IE内核没什么瓜葛,因此在抓静态网页的时候都没有什么问题,但是在抓用session维持的动态网页时,都有点问题,更不用说抓需要PKI证书验证的HTTPS网站。
  因此我考虑可以实现这样一个离线浏览器:
  提供一个地址栏供用户输入起始URL。
  内嵌一个微软web browser控件(IE内核),供用户交互,包括在网页上输入用户名/密码、从IE证书库中选择证书。
  用户登录成功、进入需要开始抓取的网页后,设定递归深度、URL过滤条件,点“开始”按钮开始抓取。
  离线浏览器自动引导web browser进入每个页面,每进入一个页面,都通过web browser控件获取客户端HTML源代码及页面元素,包括图片、css、js、flash等。
  采用这种方法实现的离线浏览器,由于