當前位置: 華文星空 > 知識

電腦軟體(例如 Adobe、Autodesk)為什麽那麽容易被破解?

2019-12-03知識

先說結論:

理論上不存在無法破解的軟體,但並不是說破解軟體比開發容易一萬倍,naive,防破解的目的不是要做一個無法破解的軟體,而是:

讓破解軟體的成本遠大於購買軟體的成本,知名軟體大多都有實力讓軟體破解難度大大加大,但出於市場需求和爭取使用者的角度考慮,會放水!

光說不練假把式,52老司機來給各位簡略表演幾個有代表性的軟體破解,當然,要看懂下面的內容,需要一點點C語言的編程基礎.

我們先來一個最最簡單的軟體破解,假設我們寫了一個軟體,它的註冊手段程式碼如下

#include "stdio.h" #include "string.h" int main () { char Key [ 32 ]; printf ( "請輸入註冊碼:" ); gets ( Key ); if ( strcmp ( Key , "abc123456" ) == 0 ) printf ( "註冊成功" ); else printf ( "註冊失敗" ); }

把他編譯成exe,執行一下

要破解怎麽辦呢?超簡單的,你把這個程式字尾改成txt然後開啟,搜尋註冊碼.然後翻一翻key就找到了

別笑,就算是今天,仍然有一大堆軟體采用這種軟體保護機制,不過這類軟體要不大多不怎麽值錢比如xx管理系統,小算盤之類的,要不就是軟體作者別有用心防君子不防小人.你可能會問了,問題出在那了呢,這類保護機制的問題是,目前大部份的編譯器都會將字串常量直接儲存在可執行檔結構中,所以你要是寫死key,那麽上面這種破解方法幾乎是屢試不爽甚至不需要什麽逆向破解知識就能搞定.

那麽,讓我們進入防破解V2.0時代,為了與時俱進,我們稍微把上面的程式碼改一下

#include "stdio.h" #include "string.h" #include "windows.h" #include "math.h" int main() { char iKey[32]; char Key[32]; char ID[32]; int iID=0xabc1d3f; sprintf(Key,"%x",iID*8+123456); printf("你的機器碼是%x\n",iID); printf("請輸入註冊碼:"); gets(iKey); if (strcmp(Key,iKey)==0) MessageBoxA(0,"註冊成功","",MB_OK); else MessageBoxA(0,"註冊失敗","",MB_OK); }

現在"TXT"破解法已經不頂用了,你看,key找不到了

怎麽樣,這種保護手段是不是熟悉的味道熟悉的配方,這個機器碼可以從網卡MAC,CPU型號,記憶體大小等等等等去生成,當然,key的演算法也可以拉上MD5,SHA等等等等手段來弄而不是簡簡單單的乘一個8再加上123456,總之從機器碼到註冊碼的演算法你能玩出花.

但,這又有什麽卵用呢,開啟ollydbg,對MessageBoxA下斷點(也就是彈窗的函式)

然後輸入一個錯誤的註冊碼,命中斷點,很快,我們來到了判斷註冊碼是否正確的邏輯處理程式碼

你猜猜,要是我們把這個判斷註冊碼是否正確的程式碼給它刪了)(nop指令填充)會怎麽樣

你會發現,握草,不管我輸入什麽,都是註冊成功

那麽問題出在哪了呢,你發現,萬惡之源都始於那個MessageBox函式,正是這個函式,讓我們順藤摸瓜找到了註冊碼判斷程式碼,時至今日,仍然有非常非常大的一部份軟體使用著這個二三十年前就在用的保護手段,每年死於MessageBox被破解的軟體,圍起來可以繞地球三圈.也就是這個保護機制,成就了所謂軟體釋出後十分鐘就被破解的悲慘結局.

這個時候,你痛定思痛,mmp,有內鬼,既然MessageBox不好用,那我不用就是了,於是你把程式碼改成下面這樣

#include "stdio.h" #include "string.h" #include "windows.h" #include "math.h" int main() { char iKey[32]; char Key[32]; char ID[32]; int iID=0xabc1d3f; sprintf(Key,"%x",iID*8+123456); printf("你的機器碼是%x\n",iID); printf("請輸入註冊碼:"); gets(iKey); if (strcmp(Key,iKey)==0) printf("註冊成功"); else exit(0); }

你看,嘖.只要你註冊碼沒輸對,我直接把軟體結束(或者跳到別的地方),看你怎麽辦

可惜,內鬼年年有,"註冊成功"幾個字還是出賣了你,開啟ollydbg,尋找字串參考,然後雙擊

哦豁,完蛋,換湯不換藥,還是給逮住了.

你察覺到這樣一個地方判斷註冊碼實在不靠譜,所以,你改變了策略,把檢查註冊碼的程式碼復制了n遍,或者逐字元檢查註冊碼的準確性,還有人將註冊成功等字樣進行加密或混淆,等到要用的時候再取出來

#include "stdio.h" #include "string.h" #include "windows.h" #include "math.h" int main() { char iKey[32]; char Key[32]; char ID[32]; int iID=0xabc1d3f; sprintf(Key,"%x",iID*8+123456); printf("你的機器碼是%x\n",iID); printf("請輸入註冊碼:"); gets(iKey); if (strcmp(Key,iKey)==0) printf("註冊成功"); else exit(0); if (strcmp(Key,iKey)==0) printf("註冊成功"); else exit(0); if (strcmp(Key,iKey)==0) printf("註冊成功"); else exit(0); if (strcmp(Key,iKey)==0) printf("註冊成功"); else exit(0); if (strcmp(Key,iKey)==0) printf("註冊成功"); else exit(0); if (strcmp(Key,iKey)==0) printf("註冊成功"); else exit(0); if (strcmp(Key,iKey)==0) printf("註冊成功"); else exit(0); if (strcmp(Key,iKey)==0) printf("註冊成功"); else exit(0); }

你放心,不管你復制多少次,要找出來都是時間問題,吃棗是會被破解的.同時只要你要用到明文字串你遲早還是要解密的,這種手段類似於加upx壓縮殼,只需要等待數據解壓完成,所有的東西又都是明文的了。因此比較聰明的做法是,要用時解密,用完後馬上把明文抹掉,這樣說不定能拖延更長的時間。但這仍然也是時間問題。

你開始發現,與其揪出內鬼,不如主動出擊,也就是我們著名的與其解決問題不如解決提出問題的人,終於,你開始對偵錯程式下手了,然後你成功前進演化到防破解V2.5時代.

這個時候,不得不介紹一個老掉牙的但非常有名的函式

IsDebugPresent

你可能有點懵,這個函式是幹啥子用的?,簡單來說,當我們破解一個程式的時候,大部份情況下我們會開啟一個叫偵錯程式的東西來對軟體進行反編譯分析,誒,重點就在這,IsDebugPresent這個函式,就能檢測我們的程式有沒有被一個偵錯程式附加,你想啊,正常情況我們用軟體誰會吃飽撐著附加一個偵錯程式來用,你要是用偵錯程式附加我,你肯定就是想幹壞事.

於是,你開始把程式碼寫成這樣:

#include "stdio.h" #include "string.h" #include "windows.h" #include "math.h" int main() { char iKey[32]; char Key[32]; char ID[32]; int iID=0xabc1d3f; if (IsDebuggerPresent()) { MessageBoxA(NULL,"小樣,就你還破解我的程式,回家喝奶去吧","",MB_OK); return 0; } sprintf(Key,"%x",iID*8+123456); printf("你的機器碼是%x\n",iID); printf("請輸入註冊碼:"); gets(iKey); if (strcmp(Key,iKey)==0) printf("註冊成功"); else exit(0); }

於是,當下次再ollydbg載入偵錯你的程式的時候,就會出現下面的情景

曾經很長一段時間(包括現在),很多軟體或加密殼都會檢查是否有偵錯程式正在偵錯自己,比如tls段會在載入時被執行,如果檢查到自己正在被人偵錯破解,就會設定一個tag讓程式跑到沒啥用的地方去或者直接結束重新,也有利用變形的PE頭讓偵錯程式無法載入,總之手段很多.

可惜這還是沒什麽卵用,比如IsDebugPresent可以透過修改FS寄存器的標誌位來讓它徹底啞火,同樣的手段包括但不限於檢查int 3軟中斷,Raw Call,Query PEB,檢查Debug Privilege和父行程等等等等,都有繞過的方式.

暗樁嘛,只要你插,一個一個拔總是拔的完的

好了,還有啥法子不,放心道高一尺魔高一丈,現在我們來到了現在最流行的,防破解V3.0 VMP時代,

先澄清一下,這裏的VMP並不是VMP殼,它全程叫Virtual Machine Protection,簡單來說,為啥我們破解軟體那麽輕車熟路,還不是因為x86 x64 arm的那堆組譯指令集我們太熟悉了唄.要是我們自己發明一套指令集,然後用這個指令集寫程式並執行在我們自己的虛擬機器上,那麽,破解者一進來,看到的不就是一臉懵逼了麽

可惜的是,VM的執行機制決定了它可能造成幾十倍乃至幾百倍的效能損失,所以,VMP必須用於保護那種關鍵且不是效能瓶頸的程式碼,否者你的軟體跑起來就會像

如果你想了解VM機執行機制,誒,筆者剛好也做了個

那麽,VMP保護機制是完美的麽,當然不是,VMP說白了,也只能做到延長分析時間,你要是把VMP做的足夠復雜,足夠讓一個Cracker醉生夢死了,但是如果這個時間足夠久,你的軟體足夠的值錢讓人有欲望來破解, 他們仍然可以充分地分析你VM機的執行機制,當你的VM機執行機制被摸清了,軟體就離淪陷不遠了.

不過你可以放心,分析VM機執行機理,可比自己寫VM機要頭疼多了,畢竟一個是你需要透過程式碼來揣測別人的思路,而另一個本身是自己的思路轉為程式碼,因此基於這點可以說:

破解軟體比制作軟體簡單,在很多情況下,不存在的!

你可能會問了,為什麽現在市面上那麽多軟體,那麽多遊戲,購買了那麽多聽起來那麽牛逼的保護軟體,結果還是被破解了.而且剛發出來一天就被破解了.

其實很大的問題就出在這個商業保護軟體(比如保護殼)上,因為這類保護殼大多都會被賣給一大票的軟體開發商,有一句話叫樹大招風,就像現在流行的VMP保護機制,之所以能保護,是因為其執行機理破解者不明確,如果你這個軟體就給自己用,而且你這軟體還不怎麽值錢,除非大佬空虛寂寞冷,不然誰會有那閑工夫去分析你的虛擬機器是怎麽跑的,但商業保護殼不同,不論其采用什麽樣的保護機制,只要分析過一遍搞清楚了,幾乎所有使用這類保護機制的軟體都會淪陷,而且在灰色產業上.這種破解甚至還頗有利可圖,只要這個保護機制不更新,一次投入,長期報酬.於是只有說在第一次分析時會花上很長的時間,之後就都只是玩套路了.

因此,購買商業保護殼,其實其保護效果並沒有想象中的那麽強,很可能在灰色產業中形同虛設,甚至一個具有反逆向基礎的碼農自己寫的說不定還更有效果.當然一個軟體是被破解機率高不高,仍然是我之前提到的那句話:防破解不是讓軟體無法破解,而是讓破解軟體的成本遠大於購買軟體的成本

畢竟你說你一個軟體拿來開源都沒人愛用,你還整天琢磨著怎麽才不會被破解,寒摻不老鐵.

那麽你會開始問了,有沒有更給力點的防破解技術?好像之前說的說來說去,無非就是拖延時間,誒,這個我們要擺正心態,不論是加密還是破解,其實說白了最終就是拖延時間,你看那些加密演算法,依據其數學理論,如果要破解,它的計算量就算你把全世界的電腦加起來一塊算,也夠你算三個世界末日了.

不過別擔心,更給力的方法還是有的,你想啊,為什麽我們之前說了那麽多軟體都被破解了,最最關鍵的一個原因,是我們能搞到程式碼,即使這個程式碼已經是經過編譯後的一堆組譯指令,但只要我們有這堆程式碼,遲早我們還是能搞懂這個程式是怎麽回事的,然後我們就可以對癥下藥幹壞事.

這就像給你有一包面粉,而程式就是一個麵包機,你把面粉塞進麵包機做出了麵包,有天你好奇啊,這麵包機咋整咋整就出來一塊麵包了呢,你就動手把麵包機拆了,然後你就知道麵包機是怎麽回事了.

所以有沒有辦法不讓使用者知道我們的程式碼是什麽樣的呢,就像你把面粉交給了麵包師傅做麵包,這個麵包是怎麽做的,你就只能指望看麵包師傅有沒有這個心情告訴你了.

為此,有請早期一個相當流行且普遍的遊戲防破解工具(物理)

你現在可能表情是一臉問號,但我沒和你開玩笑,在2000年時代,大部份的遊戲執行在光碟CD中,但盜版也容易啊,把光碟裏的數據一復制下來,然後就可以復制出一萬張盜版光碟,所以遊戲廠商們就想辦法,想來想去就想到了榔頭

其操作方法很簡單,拿榔頭和釘子,在光碟上釘幾條刮痕出來,造成人工的壞道,然後再將數據燒錄到正確的磁區中,這樣下來雖然程式還是可以正確執行,但是當光頭讀盤讀到這個壞道的時候,就會讀不過去,於是你會發現開啟光碟後,沒有關鍵的檔,這樣你就沒辦法將遊戲或者說程式拷貝出來了,同時還會對壞道的位置做一個標記,遊戲執行時也會檢查這個標記,那麽想要盜版你就也得拿起榔頭在光碟同樣的位置上砸出同樣的刮痕出來,當然,這幾乎是不可能的.

當年這個技術當年又叫防盜環技術,但不管它的名字叫的多高大上,本質上就和榔頭釘釘子如出一轍是同樣的東西,可惜虛擬光驅出現後,同樣有辦法復刻光碟的一切數據(包括壞道),所以,這個技術拿到今天來看並沒有什麽卵用.不過這仍然給了我們足夠的啟發.

現在讓我們進入防破解V3.x時代,之所以不叫V4.0是因為這類技術很早就有並且比VMP保護流行的時間還早的多,而且它可能是最近接理論上不可破解的防破解手段.

我們先聊的是加密狗或者又叫Ukey保護,就是執行軟體你需要插入一個U槽一樣的東西到電腦上,實際上這個Ukey是一個微型電腦,軟體的一些關鍵的演算法和程式碼,都在這個UKey的芯片裏,當我們PC上的軟體執行後,當我們需要執行這類關鍵演算法時,我們會向這個Ukey傳遞數據,然後UKey將結果計算出來,返回給PC的軟體上,這樣就避免了使用者直接能夠逆向取得關鍵的演算法程式碼,破解也就無從談起了.這也就是為什麽到了今天,Ukey保護仍然非常的流行.

可惜,UKey保護仍然有諸多的限制,首先就是帶著一個Ukey賊麻煩,萬一UKey丟了補辦是一個麻煩事,執行軟體插Ukey也是個神煩的事情,同時,UKey的效能決定了它可能不能執行一些過於消耗效能和記憶體空間的程式碼,數據互動也因頻寬和通訊延遲會造成效能損失,所以它和VMP保護機制一樣,同樣不是一個省油的燈,同時開發人員的水平不到位,該保護的程式碼沒保護,保護來沒啥用的程式碼塞了一堆,也會給Cracker帶來機會,而且只要你的軟體夠值錢,你是不是太瞧不起我華強北了

把Ukey拆開來,使用某種"藥水"剝開外層找到內部的芯片並接上已經熔斷的"讀引腳"(有些芯片連這步都省了,直接熱風槍一吹接板讀ROM) 然後再把芯片的程式碼給讀出來

於是,UKey保護也宣布淪陷.

你發現,只要是把實體的東西交到使用者的手上,遲早會出問題,所以,這個Ukey保護現在大部份情況下變成了帶電子證書的網路驗證模式,這類的關鍵程式碼從Ukey轉移到了伺服器上,數據互動透過網路來做.其實這種保護機制和Ukey保護原理是一樣的並沒有什麽本質的區別,但同樣處於網路頻寬也延遲的考慮,同樣具有一定的效能損失和設計缺陷.

需要重點提及的是,這類網路保護的手段必須專門設計以保護程式中的一系列關鍵"功能"程式碼而不是"防破解"程式碼(比如程式碼解密,註冊驗證),因為後者幾乎沒啥卵用仍然能夠將"防破解"的程式碼清除或Dump解密程式碼或偽造本地伺服器實作破解.

所以你指望一堆什麽x盾,x寶一鍵能一勞永逸一鍵保護程式,程式必須經過專業碼農而不是彩筆專門的設計才能起到其應有的保護效果

但現實情況是,處於使用者離線執行和效能延遲瓶頸的考慮,這種網路保護設計的往往都有很大的缺陷,因此,並不是說這東西不好,而是理想很豐滿現實很骨幹,實在無能為力啊.

當然,程式碼保護的手段很多且花樣玩法也很多,本文只是初略介紹幾個比較有代表性的破解和反破解手段.如有興趣

附上自己的引擎,歡迎點star