Unbreakable Serial Number Scheme
前幾天蕭易玄提及,他寫的共享軟體 Ram Disk Utility ,已經被 Mac 上一個很有名的序號大全(骷髏頭)給蒐羅進去。雖然發生這種事有點遺憾,但我想這也沒那麼糟,畢竟這代表 RDU 已經被國際注意到,而且大家真的會想要去用,也算是一種肯定。
是不是有某些奧客把他買來的序號流傳出去呢?如果是這樣那就還好。你可以比對出這奧客當初購買的基本資料或信用卡等,看是列入黑名單或者和找他算帳。但根據蕭易玄表示,骷髏頭出現的並非是他曾經發過的任何序號,因此我們可以推論,這是那些 cracker 自行產生的序號。在這種狀況下,我們沒辦法找出是誰散佈的序號,因為我們客戶資料庫裡壓根沒有這組序號的主人資料。因此,一個好的序號機制必須防止 cracker 破解出運算規律並且自行產生任意的序號。
難道那些 cracker 有通靈之術,能猜到序號的運算規律?當然並非如此。我花了點時間來看看 RDU 的序號機制。因為這是一個 REALbasic Application,增加了反組譯的難度,不過大概也只花兩個小時,就找出了問題所在。問題在於 RDU 的序號機制和許多軟體一樣,採用的是傳統的檢驗手法:
- 首先軟體裡面包含一個自己設計的秘密方法,經過許多複雜的步驟可以把註冊資訊轉換成序號,我們暫且把這個方法叫做 GenerateSN()。
- 當使用者輸入註冊資訊時,計算 S = GenerateSN(Name, Oranization, …)。
- 如果使用者輸入的序號 UserInputSN 和 S 相同,就視作輸入正確。
看出問題了嗎?就算 GenerateSN() 設計得多複雜、多難懂、用猜的根本不可能猜出來,只要 cracker 提供一些假資料,在第二步的時候 cracker 就可以得到正確的序號 S 了。所以這種檢驗方法的弱點在於「為了檢查序號是否正確,軟體裡面就內建了序號產生器」。
那麼,這樣如何呢?從登入系統得來的靈感(一般登入系統都不會直接比對密碼的明文,而是會比對 hash 過的密碼),如果我們也比對序號的 hash 呢?
- 首先軟體裡面包含一個單向(One-Way Function)函數 Hash(),以及一個 GenerateHashedSN(),可以給定註冊資訊(Name, Organization, …)計算出 Hash 過後的序號。
- 當使用者輸入註冊資訊時,計算 H = GenerateHashedSN(Name, Oranization, …)。
- 如果 Hash(UserInputSN) 和 H 相同,就視作輸入正確。
看起來很不錯。問題是你要怎麼設計 Hash() 和 GenerateHashedSN()?一個最簡單的想法是 GenerateHashedSN(x) = Hash(GenerateSN(x))。但是這樣一來等於是先算出了正確的序號再把它 Hash 過。如此一來還是產生了正確的序號!我們必須規定 GenerateHashedSN() 在計算的過程中不可以計算出真正的序號。因此要設計這套方法就變得很困難了。
其實用抽象化的角度來看,要防止別人產生序號,可以利用數位簽章(請參閱這篇關於公開金鑰系統的文章)的特性:
- 每個人都可以迅速地為任何他想要的文件產生簽名。
- 每個人都可以迅速地確定任何一個簽名,是不是某個簽名者對於某個特定文件所產生的。
- 沒有辦法(在合理時間內)幫其他人為他們沒有簽過的文件產生簽名。
有了這些特性,我們可以如此設計軟體序號的機制:使用者輸入序號時,用 public verification key 檢查 UserInputSN 是不是註冊資料的簽章即可。密碼學上很多這類的演算法可以用,舉個實際用 RSA 簽章的流程實例:
- 首先軟體裡面包含一個 public verification key: VK,而成對的 private signing key: SK 妥善地收藏在開發者的極機密電腦裡。
- 開發者計算序號的方式是 RSA(Hash(Name, Organization, …), SK)。
- 當使用者輸入序號的時候,軟體檢查 RSA(UserInputSN, VK) 和 Hash(Name, Organization, …) 是否相同。(因為 RSA 的特性是加密解密方法一樣,只是 key 不一樣。也就是說 RSA(RSA(m, SK), VK) = m)
這樣就可以保證別人很難偽造序號了。
已經有別人做好這些事情提供 framework 了,叫做 Aquatic Prime。
不過注意這篇文章標題並不是「無敵的軟體保護機制」,這篇文章講到的方法只有做到「很難讓人偽造序號」。序號本身無法破解並不是代表這軟體就無法破解了,破解的方法很多,把你軟體裡面的 Verification Key 抽換掉、直接更改 binary 機械碼、甚至像 Aquatic Prime 這種 open source 的 framework 更簡單,你自己編譯一個改過的版本替換掉就好。不過「無法偽造序號」代表了一個基本的意義:那些盜版散播的難度會變高。例如你要改 binary ,那麼軟體每一次更新的時候你都得重新改一次,很麻煩。而且現在盜版大家也越來越有安全觀念,既然別人可以修改註冊機制,那為什麼不能放進木馬之類的東西?網路上來路不明的破解檔最好不要用,去軟體網站抓正版然後輸入盜版序號才是正確(?)的方法啊!不能偽造序號,也就等於提高盜版者的風險。
(這篇文章考慮了很久才寫出來,裡面已經盡量避免對破解的部份說明太清楚。但是軟體保護這種東西本來就得知道攻擊手法才能了解原理。當然是希望大家都用正版,如此一來軟體也不用保護了……)
“可以列入 “骷髏頭” 也算是有名了…
只要想想連大公司的軟體也到處走了
---Brent. 1/12, 2008小軟體又如何呢 ?
我有Email 給你…有空看一下吧….”