常見電子書格式及其反編譯思路分析第2/3頁
更新時間:2008年07月17日 23:41:04 作者:
本文僅僅從技術(shù)角度討論電子書反編譯問題,請勿將之用于侵犯版權(quán)等等非法目的,或損害他人利益。如果您對此感到失望,請勿繼續(xù)閱讀。
2.2.2.1 Web Compiler 1.67
這種格式的電子書,因?yàn)槠渲谱鞴ぞ咴趪鴥?nèi)出現(xiàn)得比較早,而且有非常徹底的漢化解密版,所以曾經(jīng)比較流行,E書時空提供的很多電子書都是這種格式。不過也正因?yàn)樗牧餍?,?dǎo)致想反編譯它的人也多,引出了各種反編譯工具,所以現(xiàn)在用的人似乎已經(jīng)不多了。
反編譯工具里,收費(fèi)的就不去說它了,國內(nèi)RMH和Fbilo還聯(lián)合推出過免費(fèi)的unwebcompiler,并且提供全套的Delphi源代碼,有需要的到google或百度搜索一下unwebcompiler就有了。不過可能國內(nèi)大多數(shù)軟件網(wǎng)站的管理員都不是開發(fā)人員出身,對源代碼不感興趣,所以收藏的都是212 KB的EXE,有源代碼的不多,需要仔細(xì)找一下。
在unwebcompiler的源代碼里,RMH和Fbilo對Web Compiler 1.67生成的電子書的文件格式進(jìn)行了詳細(xì)描述,在這里我就不做無聊的重復(fù),有興趣就自己去看吧。我做的UnEBook也使用了他們提供的源代碼,實(shí)現(xiàn)對Web Compiler 1.67生成的電子書的批量反編譯,不過被我將代碼從Delphi改成了C,似乎長度縮短了一些(原代碼中有一段在字符串和十六進(jìn)制數(shù)之間轉(zhuǎn)換來、轉(zhuǎn)換去,看起來比較怪異,被我省了),不過LHA解壓縮部分改起來實(shí)在太麻煩,我直接在網(wǎng)上找了一段現(xiàn)成的C代碼來用。
2.2.2.2 Caislabs eBook Pack Express 1.6
這個電子書制作工具也出過漢化版,所以在國內(nèi)也有一定影響,不過這種影響似乎還沒有大到足以使反編譯工具滿天飛的程度,嘿嘿……
在分析這種格式的電子書的時候,我沒有使用任何反匯編工具,用UltraEdit32和系統(tǒng)監(jiān)視工具就猜出來了:
文件標(biāo)識:以十六進(jìn)制串 00 F8 03 00 結(jié)尾。這個似乎是一種慣例,差不多所有EXE格式的電子書都有自己特殊的文件結(jié)尾。
目錄塊起始地址指針:0003F81C
目錄塊中目錄項(xiàng)結(jié)構(gòu):以0字符結(jié)尾的文件名+4字節(jié)起始地址,文件名起始字節(jié)為FF則目錄塊結(jié)束。
如果文件存放在子目錄里,則文件名首字符:02=../,01:第一個00變成/,直到遇到02。
文件內(nèi)容實(shí)際起始地址:目錄項(xiàng)里的4字節(jié)起始地址+9
文件內(nèi)容長度:目錄項(xiàng)里4字節(jié)起始地址所指內(nèi)容,DWORD。
在分析出目錄結(jié)構(gòu)后,我曾經(jīng)想通過調(diào)試工具,分析文件加密算法,再反編譯出具體的文件內(nèi)容,但是很快我就發(fā)現(xiàn)那樣干太累了,實(shí)在是得不償失。
不過在經(jīng)過幾次嘗試后,我還是找到了一個偷懶的辦法:
通過安裝hook的方法,往電子書的進(jìn)程空間注入一個DLL。
在這個DLL里,用Windows標(biāo)準(zhǔn)的API函數(shù)URLDownloadToFile,就可以下載到指定的文件。文件的URL可以按前面說的方法,從目錄項(xiàng)得到相對路徑,再加上一個固定前綴("file://Z:\\com_caislabs_ebk\\")構(gòu)成絕對路徑。
UnEbook在批量反編譯這種格式的電子書的時候,就是按照上面的分析結(jié)果實(shí)現(xiàn)的。
不過到了更高版本的Caislabs eBook Pack Express的時候,似乎Caislabs公司也開始意識到文件內(nèi)容保護(hù)的重要性,因此不僅對文件內(nèi)容采用更強(qiáng)的加密算法,杜絕了可以用URLDownloadToFile下載的漏洞,連目錄塊的加密強(qiáng)度都強(qiáng)到足夠使我不想去分析了。幸好這個時候我已經(jīng)有了更好的反編譯思路--與具體文件格式無關(guān)的,專門針對使用IE內(nèi)核的電子書的通用反編譯思想。
2.2.2.3 通用反編譯思路
在分析過幾種電子書格式后,我開始領(lǐng)悟到一個真理:電子書內(nèi)部文件結(jié)構(gòu)的變化是無窮的,而我的時間和精力是有限的;把有限的時間和精力投入到對抗無窮的變數(shù)中去,早晚會有累死的一天。
有此認(rèn)識后,我開始思考有沒有什么通用的方法,可以解決大部分電子書的反編譯問題(我還沒有幼稚到相信這世上會有萬能藥的程度)。按照慣例(不可救藥的職業(yè)?。?,第一步當(dāng)然是市場調(diào)查、產(chǎn)品定位,結(jié)論是目前大多數(shù)電子書都是基于IE內(nèi)核的,但是根據(jù)我在開發(fā)MyReader時對IE內(nèi)核的了解,這里面明顯存在一個誤區(qū):微軟以控件的形式提供IE內(nèi)核,其目的就是希望通過控件接口的開放性、方便性,吸引更多的人加入微軟的標(biāo)準(zhǔn)陣營,如果想在此基礎(chǔ)上添加加密、保護(hù)等等內(nèi)容,恐怕與微軟的初衷不合(我說的是當(dāng)時,以后微軟改主意了也說不定)。因此我相信IE內(nèi)核一定有后門可走!經(jīng)過一番努力,果然沒有令我失望。
1、基本原理
針對IE內(nèi)核電子書的通用破解技術(shù)實(shí)現(xiàn)起來可能需要一些技術(shù)和技巧,但是原理卻很簡單,幾句話就可以說清楚:不論電子書在存儲的時候如何對內(nèi)容進(jìn)行加密,在將內(nèi)容傳遞給IE內(nèi)核進(jìn)行顯示的時候,一定要將內(nèi)容轉(zhuǎn)換成IE內(nèi)核能夠識別的標(biāo)準(zhǔn)格式--HTML格式。而IE內(nèi)核為了便于顯示、刷新,在對HTML代碼進(jìn)行解析后,并不是立刻就把這些HTML代碼拋棄,而是在內(nèi)存里保存了一份備份。因此只要將這份備份從IE內(nèi)核里搞出來,就得到了解碼后的內(nèi)容,也就是反編譯想得到的內(nèi)容。
至于網(wǎng)頁中的其它內(nèi)容,包括圖片、css、js、Flash文件等,就更簡單了:模擬IE內(nèi)核,直接找電子書要就好。如果電子書分辨不出請求是來自IE內(nèi)核還是來自其它地方,自然會乖乖把我們需要的東西雙手奉上!
雖然反編譯的原理幾句話就可以說清,但是要加以實(shí)現(xiàn),還需要經(jīng)過艱苦的探索和試驗(yàn),我自己就經(jīng)過了長期的努力,IE內(nèi)核的源代碼都翻來覆去看了好幾遍(吹的,別當(dāng)真!)。而我思想的發(fā)展也大概經(jīng)歷了兩個階段:第一個階段是在得到某份傳說中的源代碼(沒錯,就是那份展開后近700MB,被國內(nèi)主流媒體形容為噱頭、無足輕重、充滿無聊垃圾的東西)之前,完全立足于微軟公開的IE內(nèi)核接口。當(dāng)時我考慮將電子書內(nèi)容按照HTML、圖像等分類,分別解決獲取問題。第二個階段是在得到那份源代碼之后,我突然發(fā)現(xiàn)其實(shí)對于所有文件,我都可以直接找電子書要,只要假裝是IE內(nèi)核在要就行了。
由于某些東西比較敏感,因此下面敘述的主要是我第一個階段的想法,其中有些屬于基礎(chǔ)性的東西。第二個階段的實(shí)現(xiàn)恕我不便奉告。
2、獲取HTML源代碼的方法
從IE內(nèi)核獲取HTML源代碼的方法不僅我一個人在想,從國內(nèi)到國外,從CSDN(CSDN的VC/MFC區(qū)有一個欄目專門討論IE內(nèi)核編程)到MSDN,早就有很多人討論過了,歸納起來,一般認(rèn)為可以通過下列步驟實(shí)現(xiàn):
不管是通過鼠標(biāo)點(diǎn)擊也好,通過EnumChildWindow也好,總之先找到IE內(nèi)核的顯示窗口,也就是電子書顯示網(wǎng)頁內(nèi)容的那個窗口。
通過這個窗口的句柄(HWND),取得這個窗口對應(yīng)的IE內(nèi)核文檔接口IHTMLDocument2的接口指針。取得的方法目前認(rèn)為有兩種,我個人認(rèn)為這兩種需要結(jié)合使用,否則總有一些電子書會搞不定:一個是通過MSAA,一個是通過WM_HTML_GETOBJECT消息。至于具體的實(shí)現(xiàn)代碼,在CSDN上都快被討論爛了,因此此處從略,有需要的自己到CSDN上找。不過這兩種方法都對平臺有要求:XP下是完全沒有問題,2000下可能需要裝IE 6,98/Me/NT就不要想了。
在得到IHTMLDocument2接口指針后,按照這個接口提供的標(biāo)準(zhǔn)方法,即可獲得文檔的HTML代碼。具體實(shí)現(xiàn)代碼見CSDN中的例子。
除了上面這種方法外,我自己還嘗試過一種方法:使用MIME Filter。
對于搞過網(wǎng)頁在線翻譯、網(wǎng)頁內(nèi)容過濾的人來說,MIME Filter可是吃飯的本錢,它的作用和實(shí)現(xiàn)機(jī)理應(yīng)該早就爛熟于心,但是對于其它人來說,可能還不是很熟,所以這里簡單介紹一下:為了便于對IE內(nèi)核的功能進(jìn)行擴(kuò)展,微軟規(guī)定在IE內(nèi)核顯示某種標(biāo)準(zhǔn)格式(HTML、TEXT等)的內(nèi)容之前,會先將要顯示的內(nèi)容傳遞給這種格式的過濾器,即MIME Filter,由它先對內(nèi)容進(jìn)行預(yù)處理(如將英文翻譯成中文,將下流文字替換成星號等),然后再顯示。
按照這個原理,如果實(shí)現(xiàn)一個針對HTML格式的MIME Filter,即可攔截到最原汁原味的HTML代碼。可惜,經(jīng)過我的嘗試,這招對IE本身是靈的,對某些電子書也有效,但是對另一些無效。再加上使用IHTMLDocument2接口指針的方法要比這種方法簡單得多,也可靠得多,所以后來在我開發(fā)的反編譯工具KillEBook、IECracker和CtrlN里就沒有使用這種方法。不過這種方法也有一個好處:與平臺無關(guān),我在98/Me/2000/XP下都試過,當(dāng)然都是在虛擬機(jī)下試的啦。
MIME Filter的作用機(jī)理、實(shí)現(xiàn)方法在MSDN里有詳細(xì)說明,并提供了詳細(xì)的實(shí)例代碼,有需要的可以到MSDN上搜“MIME Filter”。
3、獲取圖像的方法
與HTML代碼相似,IE內(nèi)核對圖像的處理也有一個“下載->解碼->顯示”的過程??紤]到顯示代碼的抽象性,原來各種各樣的圖像格式,包括JPG、GIF、PNG、TIFF等,在解碼后都被統(tǒng)一表示成位圖格式,而原有格式數(shù)據(jù)在解碼后即被從內(nèi)存中釋放,只在IE的cache中留有文件備份。如果指定不允許保存本地cache,則連這個備份都沒有。在IE中通過右鍵菜單選“圖片另存為...”的時候,其實(shí)就是將cache中的文件備份拷貝一份出來,如果cache中已經(jīng)沒有備份,就只能保存內(nèi)存中的位圖(*.bmp)了。現(xiàn)在明白為什么有些圖片明明是jpg格式,但是用IE卻只能保存為“無標(biāo)題.bmp”了吧?
因此,獲取圖像文件要比獲取HTML文件難得多。而且在MSDN里說得很清楚,用IHTMLDocument2接口只能得到圖像的鏈接,用MIME Filter也不能搞到網(wǎng)頁里的圖像數(shù)據(jù),因此需要另想辦法。我想過、試過的包括:
先將圖像復(fù)制到剪貼板,再從剪貼板里獲取圖像數(shù)據(jù),然后根據(jù)圖像文件擴(kuò)展名(可以從圖像元素的URL里解析),編碼成原始圖像格式,包括jpg、png、gif、tiff等。這個方法實(shí)現(xiàn)比較簡單,到MSDN KB里搜索Q293125,拷貝圖像到剪貼板的現(xiàn)成源代碼就有了,圖像編碼的源代碼則可以參考cximage,這個也是google一下就有的。不過這個方法遠(yuǎn)非完美無缺:a). 對于png、gif等允許帶透明背景的格式,用這種方法處理后就不透明了。b). gif動畫處理后就動不起來了,只能顯示其中的某一幀。c). 對于jpg這樣的有損壓縮格式來說,每壓縮一次就損失一次,多壓縮幾次可能就沒法看了。d). 在電子書里,可以通過標(biāo)準(zhǔn)的Windows API函數(shù),使剪貼板失效。
將IE內(nèi)核導(dǎo)航到圖片,然后通過IViewObject接口獲取圖片的拷貝。這個方法與上面的方法基本相同,不過不通過剪貼板,可以防止因?yàn)榧糍N板被封鎖而搞不到圖像。
使用IE圖像解碼插件。IE內(nèi)核在下載到某種格式的圖像文件后,會調(diào)用對應(yīng)的解碼器,對圖像進(jìn)行解碼(類似于MIME Filter)。為了便于擴(kuò)充,解碼器是做成插件形式的。如果自己做一個圖像解碼器插件,對解碼請求進(jìn)行攔截,即可獲得解碼前的原始圖像格式數(shù)據(jù)。解碼器的接口、實(shí)現(xiàn)方法在微軟公開文檔中沒有任何蛛絲馬跡,但是在那份傳說中的源代碼里,不僅有詳細(xì)的接口規(guī)范,而且有好幾個內(nèi)嵌圖像解碼器的實(shí)現(xiàn)代碼,可供借鑒。奇怪的是,雖然在MSDN中找不到,但是我在google上搜的時候,卻發(fā)現(xiàn)有一個日本人在自己的個人網(wǎng)站上,早就給出了詳細(xì)的圖像解碼器插件實(shí)現(xiàn)方法,一步一步說得很清楚,而且落款時間是2002年12月!看來這份源代碼的泄漏時間可能比想象的要早。當(dāng)然這個日本人也可能本來就在微軟工作,或與微軟有合作關(guān)系,可以光明正大地查看解碼器源代碼也說不定。
4、通用反編譯器的實(shí)現(xiàn)
在解決了HTML、頁面元素等的獲取方法后,通用反編譯器KillEBook的實(shí)現(xiàn)就很簡單了,其算法可以描述如下:
打開電子書。
定位電子書的顯示窗口。
獲取當(dāng)前顯示頁面的HTML代碼。
解析頁面HTML代碼,得到其中的所有鏈接。
獲取頁面上的所有元素內(nèi)容,包括圖片等。
引導(dǎo)IE內(nèi)核依次加載HTML鏈接頁面。
重復(fù)步驟3~6,直到所有頁面及其中的元素都已獲取到。
5、進(jìn)一步討論
在完成KillEBook后,我發(fā)現(xiàn)其實(shí)對它擴(kuò)展一下,就可以成為一種新的離線瀏覽器,解決傳統(tǒng)離線瀏覽器(Offline Explorer Pro、Webzip等)面臨的一個問題:傳統(tǒng)離線瀏覽器多半與IE內(nèi)核沒什么瓜葛,因此在抓靜態(tài)網(wǎng)頁的時候都沒有什么問題,但是在抓用session維持的動態(tài)網(wǎng)頁時,都有點(diǎn)問題,更不用說抓需要PKI證書驗(yàn)證的HTTPS網(wǎng)站。
因此我考慮可以實(shí)現(xiàn)這樣一個離線瀏覽器:
提供一個地址欄供用戶輸入起始URL。
內(nèi)嵌一個微軟web browser控件(IE內(nèi)核),供用戶交互,包括在網(wǎng)頁上輸入用戶名/密碼、從IE證書庫中選擇證書。
用戶登錄成功、進(jìn)入需要開始抓取的網(wǎng)頁后,設(shè)定遞歸深度、URL過濾條件,點(diǎn)“開始”按鈕開始抓取。
離線瀏覽器自動引導(dǎo)web browser進(jìn)入每個頁面,每進(jìn)入一個頁面,都通過web browser控件獲取客戶端HTML源代碼及頁面元素,包括圖片、css、js、flash等。
采用這種方法實(shí)現(xiàn)的離線瀏覽器,由于使用web browser控件,因此可以維持客戶端session,抓取到動態(tài)網(wǎng)頁。雖然網(wǎng)頁抓取下來就成了靜態(tài)的,但是對離線瀏覽來說應(yīng)該不成問題,對付收費(fèi)的網(wǎng)上教育等網(wǎng)站正好合適。
2.3 HLP格式
這種格式出現(xiàn)得比較早,在16位Windows(Windows 95以前的各Windows版本)下曾是標(biāo)準(zhǔn)的幫助文件格式,因此大概也算是Windows下出現(xiàn)得最早的電子書格式之一了。
由于這種格式比較流行,國外研究的也比較多,不過公開源代碼的我似乎只見過一個HELPDECO v2.1。這個軟件是一個控制臺程序,因此有人做了一個GUI外殼DuffOS對它進(jìn)行封裝。國內(nèi)有人對HELPDECO進(jìn)行過漢化,到漢化新世紀(jì)搜索一下就可以找到,包括全部源代碼。
在UnEBook中使用了HELPDECO的源代碼,實(shí)現(xiàn)對HLP文件的批量反編譯。不過從我使用的情況看,原版HELPDECO有一個小小的不足:反編譯出來的RTF文件沒有指定字符集。這對英文RTF來說沒有任何影響,但是對中文RTF來說,其影響足夠強(qiáng)到使您打開RTF后看到的是一堆亂碼。它的修正方法有兩個:
用文本編輯器打開反編譯出來的RTF文件,手工指定中文字符集。這個是一種比較累的方法。
修改HELPDECO源代碼,加上字符集修正,這個是一勞永逸的辦法。但是不知道為什么,在漢化新世紀(jì)推出的漢化版上,我看到的還是原版的HELPDECO。看來漢化者只是用它反編譯過英文HLP,沒有反編譯過中文HLP。
另外這份源代碼還有一個不知道算不算是嚴(yán)重的問題:變量沒有統(tǒng)一初始化、釋放,因此不僅在程序退出的時候,VC++會報(bào)告有內(nèi)存漏洞,而且就象當(dāng)年的DOS內(nèi)核一樣,幾乎沒有可重入性。我曾經(jīng)試圖修復(fù)這個bug,但是在經(jīng)過一個下午的奮斗后,有兩處泄漏死活找不到。最后我還是決定向DuffOS學(xué)習(xí):將HELPDECO代碼封裝成一個獨(dú)立的DLL,每反編譯一個HLP文件,都動態(tài)加載、釋放一次DLL。這樣一方面可以利用Windows本身的DLL管理機(jī)制,彌補(bǔ)HELPDECO產(chǎn)生的內(nèi)存漏洞,一方面解決不可重入問題。收費(fèi)的“耶書制造”軟件提供的HLP反編譯功能也是用DLL文件實(shí)現(xiàn)的,因此我嚴(yán)重懷疑它的作者可能也曾遇到過相同的煩惱,嘿嘿嘿……
相關(guān)文章
linux Shell學(xué)習(xí)筆記最后一節(jié),溫故與知新
linux Shell學(xué)習(xí)筆記最后一節(jié),這節(jié)是對前面章節(jié)的小結(jié),學(xué)習(xí)shell編程的朋友可以參考下。2010-12-12Verilog語言數(shù)據(jù)類型基礎(chǔ)教程
這篇文章主要為大家介紹了Verilog語言數(shù)據(jù)類型基礎(chǔ)教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04在InstallShield中引用WINSOCK 的示例代碼
在InstallShield中引用WINSOCK 的示例代碼...2007-03-03