本文宗旨在於提出一種給軟體添加註冊碼的方法。至於所提出的方法是否有效,是否能夠經得起一些逆向高手的破解,還得經過驗證。我只是提出我個人的看法。
一、目標。
目標很明確,就是根據需要註冊軟體的個人資訊,產生註冊碼。並且軟體本身必須可以校正該註冊碼是否有效。並且能夠防止別人逆向算出校正演算法,產生註冊機;能夠防止別人用暴力破解方法,直接修改軟體執行代碼,繞過註冊。
二、方法論述
要做到以上的目標,有兩個方面特別重要。一是,註冊碼產生演算法的選擇;二是,要使軟體具有自身校正機制,防止可執行程式別篡改。下面我們分別論述這兩點。
1. 註冊碼產生演算法的選擇
現在很多軟體都存在註冊機,很大原因是因為軟體本身的註冊碼產生演算法太過於簡單。破解人員很容易從反組譯碼代碼中摳出註冊演算法,並且能夠很容易的還原成C代碼。這些搞破解的算不上大師,但也可以算得上牛人了。我也曾經瞭解過相關的知識,看懂反組譯碼的代碼不難,難的是在大量的彙編代碼中找到彼此的調用關係,並且能夠逆向的寫出對應的代碼;當然有些懶人直接摳出其中的彙編代碼,不用理解詳細的執行過程就能達到破解的目的。
言歸正傳,不管別人多麼NB,他至少要反組譯碼,至少看的是彙編代碼。而如果我們的演算法足夠強大,他們也就玩完了。縱觀如今標準的密碼編譯演算法,無非就是對稱式加密和非對稱式加密。我們也不用去自創演算法了,別做些吃力不討好的事,自己設計的演算法,安全性遠遠比不上現在常用的演算法。我先簡單列舉出常用的演算法,並說明為什麼要選擇我們所要的演算法。
a. 對稱式加密演算法現在流行的有DES,AES兩種,DES演算法廣泛的用在銀行行業,AES出現的比較晚,但是安全性比DES好。所謂的對稱就是只有一個密鑰,加密和解密使用同一個密碼,所以稱為對稱式加密。如果我們用它在產生註冊碼,那麼我們的軟體中必須儲存這個密鑰。不管密鑰在哪裡,總是要存在在一個地方,而我們又沒有辦法去保證這個密鑰的安全性。原因很簡單,破解者只要跟下代碼,就知道我們從哪裡讀出來這個密鑰。
b. 非對稱式加密有RSA,和橢圓曲線等,最流行的是RSA。雖然橢圓曲線效率和安全性比RSA好,但比較複雜,我至今沒看明白原理,呵呵。所謂的非對稱,是因為它有兩個密鑰,一個稱為公開金鑰,一個稱為私密金鑰。公開金鑰是可以對外發布的,而私密金鑰是自己儲存的。用公開金鑰加密,必須用私密金鑰解密,反之,用私密金鑰加密必須用公開金鑰解密。所以,我們知道,我們可以在軟體中儲存公開金鑰的內容,這個是可以公開的(當然,把它隱藏在軟體內部是必要的,總之可以造成破解的難度的事情我們都可以去嘗試)。然後,私密金鑰我們可以自己留著。別人拿不到私密金鑰,根本計算不出註冊碼來。
2. 至此,我們知道我們可以使用RSA演算法了,而且可以保證軟體的安全。至少無法產生註冊機,因為別人沒有私密金鑰。但是具體怎麼做,我們可以按照下面的流程。
a. 註冊碼產生過程:
註冊資訊(包括使用者名稱等資訊)---> RSA私密金鑰加密 ---> 註冊碼。
b. 軟體驗證註冊碼過程:
註冊碼 ---> RSA公開金鑰解密 ---> 註冊資訊。
3. 解決了第一個目標,我們還是很難防止別人直接篡改2進位的可執行檔,從而繞過註冊碼的校正。但是,方法總是有的。為瞭解決這個問題,我想到了一個方法:軟體的自我校正。具體的做法是這樣的:
a. 我們為自身的軟體產生校正值,這裡要使用摘要演算法。最常用的摘要演算法是MD5,相信大家都聽過,這裡也就不再詳述,我們僅僅需要在軟體的執行時,讀取可執行程式(在Windows下,自身的執行檔案是可讀的,但是如果自己要改寫自己,那就沒辦法了)並計算校正值。
b. 接著,我們可以判斷校正值是否正確,如果不正確,我們軟體可以直接自殺。
但是這裡有個問題,我們怎麼在軟體中儲存正確的校正值呢?不可能儲存在檔案或者註冊表中,這樣早晚會被知道的。別人可以直接修改該校正值使之與錯誤的校正值相同,從而騙過軟體的校正。這裡有個方法:迴歸到(第1、2點)中描述的方法。如何迴歸?我們接著說。
4. 儲存軟體的校正值:讓校正值融入註冊碼。我們修改(第2點)的過程如下:
a. 註冊碼產生過程:
註冊資訊(包括使用者名稱等資訊)+ 軟體校正值 ---> RSA私密金鑰加密 ---> 註冊碼。
b. 軟體驗證註冊碼過程:
註冊碼 ---> RSA公開金鑰解密 ---> 註冊資訊 + 軟體校正值。
這樣子,我們就可以這樣判斷軟體是否已經成功註冊。首先根據上面步驟,算出註冊資訊和軟體校正值,然後把這兩者和當前的使用者資訊,和計算出的校正值做比較,如果都匹配,說明軟體已經被成功的註冊。
5. 嘗試破解。
如果你知道了詳細的過程,如何破解該軟體?首先我們知道,已經無法寫出註冊機來了。唯一的辦法是暴利破解,但是暴利破解,軟體又加了自我校正。但是,百密總有一疏,暴利破解還是可以達到的。我們先回顧一下,如果我們按照上述的辦法添加了註冊碼校正。那麼我們的代碼差不多是這麼寫的:
int RSA_Check( char * sn ){
該Function Compute軟體的校正值,根據註冊碼sn解密出校正值和使用者資訊,然後比較,返回是否校正通過。
}
....
在軟體的啟動時,我們調用上述的函數。
if( RSA_Check( sn ) ){ <--------------------------①
在這裡,如果校正失敗,那就直接exit(0)吧,呵呵~
}
但是致命弱點就在上述的①位置。因為①位置的彙編差不多是這樣的:
je xxxxx
....
....
僅僅是一條跳躍陳述式,那麼,破解人員直接將其改成jne或者別的jmp指令就完事了,我們的努力就全廢了。既然如此,我們代碼絕不能寫成這樣,或者我們的方法不該如此簡單。至少,我們可以這麼做:
1. 不要把校正演算法寫成一個統一的介面。
2. 不要僅僅在一個地方做判斷。這點其實很簡單也很有效,如果你願意,你可以在軟體中對效率要求不高的地方多加幾個判斷,這對破解人來說是相當痛苦的,至少他無法同時尋找到所有的關鍵位置。只要有一個地方沒改成功,那麼我們的自我校正就起作用,那麼我們就有權利執行後續的動作了。比如,直接刪掉本身的程式(當然,這裡必須關閉自己,然後調用另一個進程來刪除軟體)等等。
3. 更“賤”的方法是,起一個附加的進程,和主進程互相監視,互相校正。如果校正到對方註冊異常了,那就殺掉對方,幹掉對方的可執行程式。聽起來很賤,但是不是有用,俺也不知道。
4. 如果要防止一個註冊碼到處使用的情況(中國人都是互幫互助的,呵呵),可以在註冊資訊中添加目標機器的資訊,加入到註冊資訊中。
4. 等等的這些方法,就很多了,大家可以自由發揮。
三. 總結
經過上述的論述,我覺得沒有絕對的安全,有時如果你的軟體不想被破解,那麼您就只能詛咒那些不道德的人了。但是我們可以讓他們更加痛苦,至少菜鳥是無法隨隨便便搞破壞的。在中國,寫個軟就開源,免費吧,別指望拿它來養家糊口了。
四. 附件
RSA加解密實現代碼