這是我在做CodePlus軟體的註冊模組時遇到的實際問題,現在還沒有很好的解決。
.Net程式很容易被反編譯出來,也可以通過混淆器來進行一些掩蓋,也可以通過強式名稱來保證不被修改。這真是一個矛與盾的問題。
那麼到底怎麼最大限度的保證軟體不被修改、註冊器不容易被編寫。可能真是一個頭痛的問題。
一般的思路大致是:
一、在註冊機制上採用非對稱式加密結合數位簽章的方法(這個過程較為複雜,也是我目前沒有弄出來的地方,不過我會努力解決這個問題的,也希望得到高手們的指點)
二、一定要強式名稱。關於如何使用強式名稱,這個比較容易:一般的步驟是:
1、在vs.net提供的dos命令視窗裡 用 sn.exe -k 來產生一個鑰匙對。並將之放在項目根目錄下。 如c:\>sn -k c:\YourPrj.snk 然後將YourPrj.snk copy到你的project目錄下。
2、修改AssemblyInfo.cs,
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("..\\..\\YourPrj.snk")]
[assembly: AssemblyKeyName("..\\..\\YourPrj.snk")]
3、rebuild it.這個時候就已經被強式名稱保護了。任何對產生的exe或dll進行的修改(無論是IL,或者二進位),都會導致程式將不再運行。
三、通過混淆器對產生的exe或dll進行混淆。推薦採用http://www.remotesoft.com/salamander/obfuscator/download.html 可以對強式名稱保護下的exe或dll進行混淆再重簽名。也就是說,可以得到混淆和強式名稱的雙重保護。當然,這裡也就會提出一個問題。就是既然remotesoft的obfuscator可以對強式名稱保護下的檔案進行修改(混淆就是大修改了)再重簽到強式名稱,雖然它要求YourPrj.snk要保留在project的根目錄下。但我想進行一下替換,應該也是有可能的。因此,從另一角度來思考,這二種方式其實到最後,對於高手來說,都不會是什麼難以對付的問題。其保護功能也就很有限了。
再說關於非對稱式加密進行註冊驗證機制,由於對rsa演算法的使用還不是太明白,所以一直沒有測試成功。昨天在索克論壇上看到一則東西:
http://www.sorke.com/bbs/Announce/Announce.asp?BoardID=100&ID=6060
裡面講到XC#的驗證代碼是公開的。(這下子明白了,混淆和強式名稱直接都不用了。)但是我在想,要破解xc#的那位朋友,為什麼不把這個驗證代碼去掉,然後再編譯呢?不解了。或者xc#的程式是已經產生好了的,雖然提供部分原始碼,也只是給你看看,而不是讓你有重新編譯的機會吧。那麼,這個裡面強式名稱肯定是用到了的。由於沒有下下來的研究,不是太明白。先把那段有用的代碼copy過來先,這是xc#進行驗證的演算法:
const string RsaKey = "qZj4mbr2CONBW+ABCBddSSDTfKFSzDQc9LltZ3Xzl1UrrE0iwrgQQ/NYNr3h760/JsBb5eTV
+owfTAAdjKzayIEjnTu1W2XMiDSfWfPcDaEpnoG3cWY1BhpTsUz8XxapVSHpRYovaaeA/1SY
fb0h7xbku1M4M9LgGdUwlab+iMc=AQAB";
static bool IsValidPair(string name, string key, string rsaKey)
{
try
{
byte[] b = System.Convert.FromBase64String(key);
using (RSA rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(rsaKey);
RSAPKCS1SignatureDeformatter f = new RSAPKCS1SignatureDeformatter(rsa);
f.SetHashAlgorithm("SHA1");
return (f.VerifySignature(new SHA1Managed().ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(name)), b));
}
}
catch { return false; }
}
再引用那位強人對這段代碼的分析:
我仔細檢查代碼後才發現,檢查的代碼關鍵是RSAPKCS1SignatureDeformatter類,它是System.Security.Cryptography名稱空間中的一個類,專門負責驗證RSA加密簽名的。
RSA就是不對稱式加密的演算法。就是通過私密金鑰加密的只能通過公開金鑰解密。上面的靜態變數RsaKey明顯就是公開金鑰。就是說必須提供他通過帶有私密金鑰的Key產生器產生的驗證碼,才可以使Hash驗證通過。就是說,沒有任何辦法通過公開金鑰獲得驗證碼。
那麼產生註冊碼的辦法沒有用,是否可以通過修改IL代碼的方式破解呢?只要把傳回值直接改成true,那麼無論是不是驗證通過都可以使用了。經過檢查,這個辦法還是不行。
因為這個dll程式不是由XC#主程式自己使用,而是要被vs.net調用的,所以只能註冊為全域程式集。我發現驗證邏輯實現的程式集XHCS.VisualStudio.dll已經被安裝到了GAC中。
大家都知道,安裝到GAC的所有程式集必須要加入強式名稱驗證。如果我修改了dll的內容,那麼這個強式名稱必須被刪除,這個程式集也沒有辦法在GAC中了,導致vs.net無法使用。
好了,現在我想到的是,基於這個代碼,是否可以用在我們自己的系統裡面,那麼,在加密簽名這塊要怎麼來寫,嘗試用:
RSACryptoServiceProvider rsp = new RSACryptoServiceProvider();
rsp.FromXmlString(skey); //這裡讀進了公開金鑰和私密金鑰
bytes=enc.GetBytes(this.rtxtUserGiveSN.Text);
bytes = rsp.SignData(bytes,"sha1");
這樣的代碼來做,但失敗了,還沒有找到原因。說是給對象設定了空值。
再想想,如果有誰對這方面有經驗,希望指導一下。