淺談共享軟體如何不被暴力蹂躪

共享軟體是目前世界上軟體業比較熱門的話題,國內更是如此。成千上萬的程式師以極大的熱情投入到這個領域來,都憧憬著用辛勤的勞動獲得豐厚 的回報;但,實際並非如此,絕大多數的人都鎩羽而歸。值得注意的是:除了軟體設計和技術上的原因外,最大的原因就是共享軟體被破解(Crack)了……

面對破解

一個做共享軟體的作者,面對的是已經形成團夥的眾多破解高手,國內的什麼CCG、BCG,國外的eGis、King、Core、TNT、DAMN和TMG,皆為水準一流的破解組織。全球盜版軟體不少於80%都是由他們的破解的,技術實力連大軟體公司都不可小視。

看到這裡,你是否已經灰心了?別怕,雖然目前我們理論上無法完全避免被破解,但如果能夠有效地拖延被破解的時間,並充分打擊破解者的自信心,是可以讓破解者無法忍受這種折磨從而最終放棄的。

破解,通常的做法有兩種——暴力破解(爆破)和寫註冊機。筆者就自己積累的經驗來依次講解每種破解方法的原理和應對方法,某些關鍵的常式講解 (Delphi代碼),使用C++和VB的朋友可以自己稍微修改一下。希望這能對一些新手有些幫助,能夠更有效地保護自己的勞動成果。
認識暴力破解

暴力破解簡稱「爆破」,這是破解手段中最常見的,也是最簡單的破解方法。該法最適合於對付沒有CRC校驗的軟體,破解新手樂於採用。

大凡共享軟體,驗證是否註冊大多採用if條件陳述式來進行判斷,即使你採用了什麼RSA或ECC等強力加密演算法,也免不了使用if條件陳述式。這裡就是共享軟體最為危險的地方,也是爆破新手孜孜不倦所尋求的目標。
例如,你的註冊函數類似如下:

利用RSA進行註冊碼的數位簽章驗證

if RSAVerify MD5 Key  MD5 Code  e n  then
ShowMessage '註冊成功!' 
else
ShowMessage '註冊失敗!' 

這裡Key是用戶輸入的註冊碼,是由你發送給註冊使用者的,Code是根據使用者輸入的用戶名自動計算出來的註冊碼,e是RSA演算法的公匙,而n是RSA演算法的模數。

第一次過招

上例註冊函數即使使用了強勁的RSA演算法進行註冊碼驗證,但依然很容易被破解,我們只要把這裡修改為:

將邏輯判斷改為否

if not RSAVerify MD5 Key  MD5 Code  e n  then
ShowMessage '註冊成功!' 
else
ShowMessage '註冊失敗!' 

這時戲劇性的結果會產生:隨便輸入任何註冊碼都可以註冊通過,相反輸入正確的註冊碼卻無法通過註冊。

要破解這樣的軟體就必須先反彙編或者跟蹤你的程式,找到判斷註冊碼的cmp、test等彙編指令後的關鍵跳轉指令處,通常是je、jz之類的彙編指令,把它們修改為jne或jnz即可,這樣常常只需要修改一個位元組就可以完美破解了。

目前大部分共享軟體都是用以上方法進行判斷,這也是為什麼網上被破解的軟體鋪天蓋地的主要原因。因為這樣破解實在是太簡單了……

第二次過招

其實只要把軟體的關鍵代碼嵌入到註冊碼或者註冊檔中就可以充分防止破解。

最簡單的方法就是把關鍵代碼(你的軟體功能限制部分最關鍵而且最簡單的一個函數)做成一個小DLL(動態連結程式庫),用強力對稱演算法加密(密匙可以是主程 序某一固定不變的部分或殼的特徵Hash值)後生成一個註冊檔(License檔,這格式只有你知道),或者Base64編碼後生成一個註冊表檔, 用戶可以按兩下導入註冊表內。

校驗流程如下:已註冊用戶驗證註冊碼時,先驗證有沒有檔,沒有檔則自然受限制的功能無法使用。如果有 註冊檔,解密後即生成一個小臨時檔。如果主程序被脫殼或者被修改(爆破),自然Hash值密碼不符,解密出來的肯定都是垃圾碼,沒有一點用處。只有沒 有被修改的主程序才能正確地解碼,而且當然
只有解密正確的檔才是一個真正的DLL檔,才能被GetProcAddress函數找到欲調用的關鍵函數位址。這樣只有已註冊用戶才可以享受到你的軟體的全部功能了。如此一來,Cracker破解你的軟體就變得很困難了。

首先,他如果沒有註冊檔,即使他把主程序脫殼了,由於受限制的部分和註冊檔是關聯的,他也根本無法修補完整。

第二,即使他得到了你的註冊檔,由於是加密檔,他也無法直接利用,這樣就逼迫他去拆解你的演算法,這可是他們最不願意碰到的事情啊!如果到了這一步,只有真正對加密演算法有研究的Cracker高手才會繼續破解下去。

第三,你是可以用些小技巧來使他的破解工作更加繁鎖。這裡我推薦大家使用DSA公開密匙加密演算法,它和RSA一樣,可以進行數位簽章(RSA還可以加 密,DSA則只能進行數位簽章)。這裡選用它的原因就是它有一項非常實用的特性:亂數填充機制。即DSA每次簽名都要使用一個亂數K,正因為有這 個K的存在,即使是相同的用戶名和機器識別字,由DSA加密過的每份註冊檔都不會相同。這對Cracker拆解你的註冊檔來說是一個極大的障礙。

第四,即使他得到瞭解密後的DLL檔,他也需要大幅度地修改主程序或者把你的DLL部分的關鍵代碼拆出來添到主可執行檔中。這就看他對PE檔案格式 理解得如何了。即使這樣,如果你的程式中有大量的Hash校驗和死機代碼,你就耐心等著我們可愛的Cracker同志吐血吧……:)

最後還要記住:用完這個DLL暫存檔案後立即從記憶體中卸載此DLL並刪掉,而且注意在解密之前探測一下,系統中有沒有FileMon這個威脅極大的探測器:

探測FileMon

function DetectFileMon Boolean
begin
if CreateFile PChar '\\.\FILEVXD' 
GENERIC_READ or GENERIC_WRI
TE
FILE_SHARE_READ or FILE_SHAR
E_WRITE
nil
OPEN_EXISTING
FILE_ATTRIBUTE_NORMAL
0 <> INVALID_HANDLE_VALUE then
Result = True //如果有,就關機!
else
Result = False
end

當然,你可以保護得更好一些:可以不採用臨時DLL,而把解密後的關鍵代碼用WriteProcessMemory這個API函數寫入到主可執行檔自 己進程被提交(Committed)的記憶體頁面的指定位置去。這樣由於磁片上沒有解密後的暫存檔案,破解更加困難。事實上,目前世界上最強勁的專業保護 軟 件Amadillo就是用的這種方法。而且這種方法可以充分防止被調試器Dump。但實現起來比較困難,尤其是在WinNT 5以後的作業系統中。
由於這種方法將註冊檔和受限制代碼惟一關聯,爆破手拿到你的軟體也只有乾瞪眼。建議大家都給共享軟體加上功能限制,這樣比時間和次數限制更加安全。

留言

本月最夯

偷用電腦,怎知?事件檢視器全記錄!(開機時間、啟動項時間...)