這篇文章的標(biāo)題所提出的問題的答案是“不可能”。至少對(duì)我來說是不可能的。借助適當(dāng)?shù)墓ぞ,我們可以反編譯任何SWF文件。所以,不要將重要的信息置于SWF文件中。SWF文件中不要包含個(gè)人的帳號(hào)或者密碼。
我將簡(jiǎn)要的論述“保護(hù)”技術(shù)的歷史,和他們是如何失敗的,接著我將說明我們能盡的最大努力。中國(guó)古語有云,“規(guī)則只能防君子,不能仿小人”。
公開的文件格式
在討論之前,我們先要知道,SWF的文件格式是公開的。公開的文件格式,意味著SWF文件并不是只能由Flash生成。其他公司也能制作可以在SWF播放器上播放的SWF文件。公開的文件格式意味著從什么位置獲取什么信息是眾所周知的,也就意味著每個(gè)字節(jié)都是眾所周知的。因此,如果我有時(shí)間來一個(gè)字節(jié)一個(gè)字節(jié)的檢查SWF文件,我可以了解所有的細(xì)節(jié)。
當(dāng)然,對(duì)于一個(gè)2M大小的SWF文件,我沒有時(shí)間來逐個(gè)字節(jié)的檢查。因此,我就借助軟件來完成這個(gè)工作。如果軟件遇到問題,我會(huì)暫時(shí)接管這個(gè)工作,檢查發(fā)生問題的字節(jié)。修正它,然后繼續(xù)。所以,沒有什么東西能夠掩藏的住,其限制只是我的時(shí)間和我的耐性。如果反編譯一個(gè)SWF文件的酬勞是數(shù)百美元的話,我想我會(huì)花上數(shù)年時(shí)間來逐個(gè)字節(jié)的讀取它。
好了,以下是反編譯和保護(hù)技術(shù)之間的戰(zhàn)爭(zhēng)歷史。
防止被導(dǎo)入
伴隨著Flash的出現(xiàn),Macromedia提供給開發(fā)者一個(gè)“防止導(dǎo)入的口令保護(hù)”功能。如果你給SWF文件加上導(dǎo)入口令的話,這個(gè)SWF文件就不能被導(dǎo)入了(知道倒入密碼除外)。SWF文件不加保護(hù)的話,其中的矢量圖形可以被導(dǎo)入到fla文件中。這種保護(hù)沒有什么用處,僅僅是假想的安全。
試想一下,你的SWF被用戶的播放器來播放的,你不可能利用用戶的播放器來保護(hù)你的SWF文件。因此,它是如何來保護(hù)SWF文件的呢?很簡(jiǎn)單,這種保護(hù)存在于你所買的Flash開發(fā)工具中。Flash開發(fā)工具不能導(dǎo)入有(導(dǎo)入)密碼的SWF文件。沒關(guān)系,對(duì)吧?我可以用十六進(jìn)制編輯打開那個(gè)SWF文件,刪除保護(hù)密碼,從而也就移除了保護(hù)功能。
如此簡(jiǎn)單,所以忘記導(dǎo)入保護(hù)功能吧。
轉(zhuǎn)換成放映機(jī)文件并且壓縮
如果我將它轉(zhuǎn)化成exe格式的放映機(jī)文件,還可以被反編譯嗎?答案:是的,SWF文件仍然存在其中。借助軟件可以很容易的將SWF文件從exe文件中釋放出來。壓縮可以使SWF文件不能被十六進(jìn)制編輯器讀取,壓縮是一種保護(hù)措施嗎?壓縮算法類似于zip算法,很容易被破解。
FLASM AND THE P-CODE
在flash5的時(shí)代,出現(xiàn)了兩種流行的工具,免費(fèi)的“Flasm”和商業(yè)的“ASV 2.0”。Flasm就是“Flash asm”,它將SWF中的字節(jié)碼解釋成可理解的簡(jiǎn)短代碼(p-codes)。比如“a=3”顯示為"push 'a', 3", "setVariable";SWF中的字節(jié)碼是:"96 08 00 00 61 00 07 03 00 00 00 1D"。如果想學(xué)習(xí)“SWF格式結(jié)構(gòu)”的話,這是個(gè)非常有價(jià)值的工具。
程序員喜歡用高級(jí)語言(比如:C、C++)來開發(fā)軟件,但是當(dāng)講求效率的時(shí)候,他們會(huì)在其中混合使用低級(jí)的匯編語言。因此,有時(shí)候開發(fā)者會(huì)利用Flasm編寫低級(jí)別的p-codes來增加效率。所以,F(xiàn)lasm編輯SWF中的actionscript是強(qiáng)有力的。你可以參考例子,了解如何利用這種技術(shù)來優(yōu)化3D代碼,但是懷有惡意的用戶能夠“編輯”SWF文件,SWF中的任何保護(hù)措施都可以不費(fèi)力的移除。我們不需要知道密碼就可以移除保護(hù)措施。
這兒有個(gè)通用、知名的技術(shù)來保護(hù)我們的影片不被偷竊并在其它的范圍內(nèi)顯示。我們編輯腳本來檢查_url屬性,如果_url不是我們(合法)的范圍,就使功能失效并顯示一條“You are thief”的消息。可是,借助Flasm可以很容易刪除這條腳本語句。不需要1分鐘便可以破解這種保護(hù)措施。
ACTIONSCRIPT VIEWER AND "void (a)<=b>"c" || 0(!1 && !0)"
ASV(ActionScript Viewer)能夠從SWF中提取出角色,例如::聲音、形狀和位圖等都可以被竊取。
它同樣可以提取actionscript字節(jié)碼,ASV 2嘗試將p-codes匹配成高級(jí)別的actionscript。當(dāng)遇到"push 'a', 3", "setVariable";時(shí)顯示"a=3"這樣的等同于actionscript的語言。然而我們能夠創(chuàng)造沒有任何模式來匹配的代碼,從而破壞ASV的解析。利用Flasm,可以容易的編寫不同于標(biāo)準(zhǔn)模式的代碼,從而使ASV不能進(jìn)行匹配工作。擾亂ASV 2工作的一句有名的代碼是“;”,這是一條jung代碼。它不做任何事,但是能搞亂ASV 2的工作。
但是,當(dāng)保護(hù)腳本眾所周知時(shí),ASV的作者(Burakk)當(dāng)然不會(huì)放過它。這種保護(hù)技術(shù)對(duì)于ASV 3來說就失效了。
飛速發(fā)展的反編譯工具
之后是MX時(shí)代的到來,許多反編譯工具的出現(xiàn),加快了Flash厄運(yùn)的速度。
現(xiàn)行版本的ASV 4除了顯示得到匹配的actionscript代碼,得不到匹配的代碼以p-codes形式顯示。如果解釋成p-codes發(fā)生問題,將顯示SWF中的字節(jié)碼。它同樣能夠顯示代碼在SWF文件中所處的偏移量,這意味著它不會(huì)失效。你不可能擾亂它的工作,因?yàn),至少它能顯示SWF文件中的“字節(jié)碼”。
更甚的是,F(xiàn)lash MX2004提供通過JavaScript API來生成”fla”文件。那使它能夠建立發(fā)布成SWF格式的fla文件。此刻,所有的東西都在那邊了。
更不用說聲音、形狀和位圖了,偷竊者不喜歡這些東西,因?yàn)樗鼈兲兹菀兹〉昧恕M蹈`者喜歡切的actionscript,因?yàn)槠渲须[藏著密碼,因?yàn)槠渲杏凶柚勾擞捌2シ诺哪_本代碼,
如果ASV只能將腳本反編譯成字節(jié)碼,那么它對(duì)于大多數(shù)偷竊者是沒有用處的。因此很多人進(jìn)他們的最大努力來阻止ASV 4將腳本反編譯成actionscript或者p-codes。實(shí)際上,對(duì)于大多數(shù)反編譯者來說,腳本得不到匹配,反編譯工具就無用了。
這是曾經(jīng)用過的一些技術(shù),當(dāng)它們?cè)谝蛱鼐W(wǎng)上發(fā)布并且被反編譯組織揭示之后,每種技術(shù)的保護(hù)效果最終都會(huì)變得非常薄弱和氣數(shù)將盡。
依據(jù)數(shù)據(jù)尺寸(句子)分塊反編譯
大多數(shù)之所以能夠成功的迷惑或者破壞反編譯器,原因在于播放器和反編譯器的不同行為。播放器逐個(gè)的執(zhí)行字節(jié)碼,就像現(xiàn)實(shí)世界中的讀書一樣,一個(gè)單詞,接著下一個(gè)單詞。然而反編譯器通常將字節(jié)鏈分成有意義的片斷,猶如現(xiàn)實(shí)世界中的讀書一樣,一個(gè)句子,接著下一個(gè)句子。
反編譯器的行為如此簡(jiǎn)單的原因在于大多數(shù)的p-code都是遵循數(shù)據(jù)大小規(guī)律的。對(duì)于字節(jié)碼("96 08 00 00 61 00 07 03 00 00 00 1D"),反編譯器遇到代表"push"操作的0x96時(shí)會(huì)想“push什么呢”?下個(gè)字節(jié)(0x0008)指示的內(nèi)容:接下去8個(gè)字節(jié)中的內(nèi)容壓入堆棧,即把("00 61 00 07 03 00 00 00")壓入堆棧。所以,通常反編譯器依據(jù)數(shù)據(jù)大小將簡(jiǎn)短的片斷切成一塊一塊的,這樣便會(huì)解釋成“push something”。因此,("96 08 00 00 61 00 07 03 00 00 00")就成為一個(gè)句子。下一個(gè)字節(jié)是下一個(gè)句子的開始,就是代表"setVariable"的0x1D。這樣8個(gè)字節(jié)的"something",將被更進(jìn)一步解釋成一個(gè)字符串“a”和一個(gè)數(shù)字“3”。
讓我們來看一下字節(jié)碼:("99 02 00 05 00 96")。0x99意味著分支(或者跳轉(zhuǎn)),在哪里分支呢?接下去的是(0002),因此數(shù)據(jù)存儲(chǔ)在機(jī)下去的兩個(gè)字節(jié)中,將它在下面兩個(gè)字節(jié)處截?cái)。總之,我們知?99 02 00 05 00"是個(gè)句子。接下去的是0x96,代表下個(gè)句子的開始。
再看第三個(gè)例子,字節(jié)碼:("88 08 00 03 00 63 00 62 00 61 00 96 07 00")。0x88代表定義常數(shù),定義的常數(shù)內(nèi)容是什么呢?后續(xù)字節(jié)(0008),表明常數(shù)內(nèi)容存儲(chǔ)在后繼的8個(gè)字節(jié)中。所以,句子就是:("88 08 00 03 00 63 00 62 00 61 00")。代表下個(gè)句子開始的("96 07 00 ...),意味著將7個(gè)字節(jié)的數(shù)據(jù)壓入堆棧。
因此,字節(jié)碼砍成單獨(dú)的句子。每個(gè)句子由命令和數(shù)據(jù)組成,并且以命令打頭。因此,每個(gè)句子都是一個(gè)基本的單元。理論上來說,對(duì)于這種方法沒有什么錯(cuò)誤。
使播放器從句子中間開始讀數(shù)據(jù)
讓我們開始討論“是播放器從句子中間讀數(shù)據(jù)”的破壞反編譯器的技術(shù)。
首先,我舉一個(gè)現(xiàn)實(shí)世界的例子: John says good morning. Mary says thank you.
現(xiàn)在生成SWF文件: skip 9 words Tom says John says good morning. skip 3 words back 7 wordsMary says thank you.
如果逐個(gè)字讀的話,結(jié)果和原來一樣,然而反編譯器按句子來讀取,自然發(fā)生錯(cuò)誤。第一,它知道Tom說了什么,但語法不對(duì),匯報(bào)出錯(cuò);第二,它沒有看到第二個(gè)“skip”命令,因?yàn)樗幱诰渥又虚g;第三,當(dāng)它被迫退回7個(gè)字后,感到迷惑,認(rèn)為應(yīng)該從“Tom said”開始執(zhí)行整個(gè)句子;第四,這個(gè)錯(cuò)誤使它在第二行和第三行之間陷入無限循環(huán)之中。
總之,我們?cè)黾恿恕癟om said”這句垃圾代碼,并提供整個(gè)句子長(zhǎng)度的錯(cuò)誤數(shù)據(jù)大小信息。這個(gè)錯(cuò)誤的長(zhǎng)度覆蓋了“skip”命令。
來看個(gè)真實(shí)的例子,請(qǐng)注意,這些技術(shù)需要操作字節(jié)碼,純actionscript不能夠?qū)崿F(xiàn)。
例1 :
向前跳轉(zhuǎn)的包含無效尺寸數(shù)據(jù)的死代碼。 push True branchifTrue label2 constants ''label2:push 'a',3setVariable
你仔細(xì)看的話,會(huì)發(fā)現(xiàn)"constants ''"這行是垃圾代碼,它不可能被執(zhí)行到。然而,理論上,當(dāng)?shù)诙械慕Y(jié)果為"not True"時(shí),它將被執(zhí)行。因此,反編譯器嘗試對(duì)它進(jìn)行反編譯。
讓我們來增大"0x88 - constants"后面的"sentence size",從而包括知道腳本結(jié)尾的所有字節(jié)。你知道,反編譯器將把字節(jié)碼砍成像這樣的3個(gè)句子: push True branchifTrue label2 constants label2: push 'a',3 setVariable
如果你試圖反編譯此SWF文件,根據(jù)我前面提到的4個(gè)錯(cuò)誤,一些反編譯器將碰壁。仍舊有些反編譯器幸存,但只是顯示:"if(false){};"。ASV 3也不能顯示此腳本,但是ASV 4能夠顯示。為了破解這個(gè)SWF,我們移除死代碼"constant xxxx", (0x88和隨后兩個(gè)字節(jié)),然后所有的東西都得到反編譯。
這兒是zip格式的文件,將詳細(xì)解釋怎樣制作這樣的受保護(hù)文件。
例2:
先后跳轉(zhuǎn)的包含無效尺寸數(shù)據(jù)的死代碼。
push 'b' label1: push 'a',3 setVariable branch label2 branch label1
label2:push 'b'是句垃圾代碼,我們將修改它,用來使ASV 4碰壁。讓我們來修改push 'b'的"length of sentence"。修改"0x96"后面的2個(gè)字節(jié)的數(shù)據(jù),使句子的長(zhǎng)度增長(zhǎng)到分支Label1之前。這樣,反編譯器將把字節(jié)碼作為3個(gè)句子:
push label1: push 'a',3 setVariable branch label2 branch label1 label2:
現(xiàn)在,反編譯器不知道將把什么壓入堆棧,同樣它將在第一個(gè)句子和第二個(gè)句子之間形成死循環(huán)。這種技術(shù)將使大部分反編譯器碰壁。Flasm、ASV 4同樣也無效。為了破解這個(gè)SWF,我們手工刪除"push b" (0x96和后隨的2個(gè)字節(jié)),這樣所有的東西都可反編譯了。
當(dāng)這個(gè)技術(shù)流傳后,burakk將修改ASV 4,使它能正確處理死循環(huán)。這樣下個(gè)版本的ASV就可對(duì)付這種技術(shù)了。
這兒是zip格式的文件,將詳細(xì)解釋怎樣制作這樣的受保護(hù)文件
出處:CSDN
責(zé)任編輯:qhwa
上一頁(yè) 下一頁(yè) 如何防止SWF文件被反編譯 [2]
◎進(jìn)入論壇Flash專欄版塊參加討論
|