闡述簽名工具這個(gè)概念之前,我先說說它不是什么:
1.它不是用于給程序集加密的工具,它與阻止Reflector或ILSpy對(duì)程序集進(jìn)行反編譯一毛錢關(guān)系都沒有。
2.它很討厭人們把它和加密聯(lián)系在一起。
我再說說它是什么:
1.起個(gè)大名字
sn是strong name的縮寫,正如其名,sn.exe的目的是給程序集起一個(gè)唯一的名字(Hash+name+version+culture),即簽名,保證不會(huì)讓兩個(gè)不同的DLL重名(就跟身份證不能重一樣)
2.讓調(diào)用者識(shí)別被調(diào)用的DLL是否被篡改
這一點(diǎn)是我重點(diǎn)要說的,我們先假設(shè)一個(gè)場(chǎng)景。一個(gè)黑客正在用一個(gè)銀行客戶端程序給一個(gè)賬戶轉(zhuǎn)賬,通過反編譯發(fā)現(xiàn),前端主程序Bank.exe調(diào)用Transfer.dll的TransferMoney方法來進(jìn)行轉(zhuǎn)賬操作。他自然地想到,如果我修改了TransferMoney方法,將金額參數(shù)乘以10,然后重新編譯成Transfer.dll再覆蓋原來的Transfer.dll,他就能成為宇宙首富!
由這個(gè)例子得知,我們亟待解決的安全問題是,讓Bank.exe有能力得知其調(diào)用的Transfer.dll是不是被別人篡改過的。那么我們很自然地會(huì)想到,用信息摘要算法唄~(廢話一下,不同內(nèi)容摘要出來的128位字符串是絕對(duì)不一樣的)
是的!sn起的這個(gè)大名字就是這個(gè)摘要信息,我們可以在Bank.exe的引用信息里存好了我應(yīng)該調(diào)用Transfer.dll的摘要值OriHash,這樣我們就可以在調(diào)用時(shí)先摘要一下當(dāng)前的Transfer.dll得出CurHash,然后比對(duì)一下OriHash和CurHash即可!過程如下圖:

這似乎就是正確答案了,可是...
這樣做有一個(gè)問題,就是關(guān)于你預(yù)先存好的那個(gè)摘要值OriHash。有兩個(gè)方面:
方面1.一旦我正常地更新了Transfer.dll, 那摘要也就變了,也就是說你要通知Bank.exe去更新OriHash。
方面2.由問題1引發(fā)的安全問題。
對(duì)于方面1,我覺得是最主要的原因,一旦Transfer.dll更新了,為了比對(duì)摘要,Bank.exe需要更新OriHash,更新100次Transfer.dll,你就要更新100次OriHash,這個(gè)做法太要命了,當(dāng)然這還只是麻煩層面的問題,更嚴(yán)重的是,我們可以想象到由于頻繁更新OriHash而引發(fā)的安全問題。
對(duì)于方面2,由于你總?cè)ジ翺riHash,這個(gè)環(huán)節(jié)一旦被黑客截獲,你的OriHash就不一定保證是真的了,當(dāng)然我個(gè)人認(rèn)為這個(gè)懷疑有點(diǎn)過頭了,因?yàn)镈LL引用信息一般都是工具自動(dòng)添加的,除非你通過某種網(wǎng)絡(luò)機(jī)制傳輸這個(gè)OriHash到Bank.exe所屬的項(xiàng)目文件(如Bank.csPRoj),此時(shí)OriHash就有了更多的被黑風(fēng)險(xiǎn),這是一個(gè)安全問題!
所以基于以上兩點(diǎn),.Net拿出了非對(duì)稱加密算法這把利劍?。?em>再?gòu)U話一下,非對(duì)稱加密即生成一對(duì)兒鑰匙——私鑰和公鑰,明文被該私鑰加密只能用該公鑰解密,反之亦然,所以私鑰自己要絕對(duì)保密,公鑰可以給任何人)
將OriHash用私鑰加密為CodedHash,并存儲(chǔ)在Transfer.dll中。然后在Bank.exe里一次性存入這個(gè)為了調(diào)用Transfer.dll的公鑰,但一定要意識(shí)到,Transfer.dll里面是絕對(duì)沒有私鑰的,私鑰只包含在myPair.snk文件中,也只有你拿著,并配以荷槍實(shí)彈的保安們誓死保護(hù)不被別人拿走。
那么新的驗(yàn)證流程如下,請(qǐng)結(jié)合下圖:
a.首先Bank.exe里含有公鑰,Transfer.dll里含有CodedHash
b.Bank.exe用公鑰解密CodedHash
c1.若解密成功,就證明這個(gè)CodedHash是用和我公鑰配對(duì)的那個(gè)私鑰加密的。
c11.對(duì)Transfer.dll進(jìn)行摘要得到CurHash,將其和解密的Hash對(duì)比,如果一樣則證明Transfer.dll是安全的,并且是完整的,加載即可。如果不同,則證明這個(gè)Transfer.dll是別人篡改過的,此時(shí)拒絕加載Transfer.dll
c2.若解密失敗,則證明這個(gè)CodedHash是用別的私鑰加密的,也就是黑客弄的,此時(shí)同樣拒絕加載Transfer.dll
如下圖:

這樣的流程解決了之前的兩個(gè)問題,即當(dāng)Transfer.dll正常更新時(shí),不用再把新的Hash傳給Bank.exe了,Bank.exe只需用公鑰去解密CodedHash便可知曉這東西是誰(shuí)發(fā)的,并通過解密了的Hash和實(shí)時(shí)計(jì)算的Transfer.dll的Hash進(jìn)行對(duì)比。這里我們邏輯上有個(gè)假定,那就是Bank.exe里的那個(gè)為了調(diào)用Transfer.dll的那個(gè)公鑰是真的。如果你說這個(gè)被黑了怎么辦,那我只能說,他都能改你這個(gè)Bank.exe里的公鑰信息了,他就想改什么改什么了,你就束手就縛吧。另外如果你說,我們既然之前說怕傳給Bank.exe的OriHash有假,那你為什么不怕傳給Bank.exe的公鑰有假?我只能說,你的邏輯很清晰,的確,我們無(wú)法保證,但我要說的是畢竟公鑰只傳一次,而OriHash有可能需要多次傳輸,風(fēng)險(xiǎn)概率不一樣,如果我們假定Transfer.dll永不改變,也就是說OriHash也只用傳一次,那我可以說你用不用非對(duì)稱加密算法都是一樣的,因?yàn)楸WC第一次給的OriHash是真的和保證第一次給的公鑰是真的,這倆的風(fēng)險(xiǎn)系數(shù)是一樣的。不知道這么說,大家能不能明白我的意思,我也是繞了好久才捋順的。
我們可以再假設(shè)一遍黑客可能進(jìn)行的攻擊方法:(注意前提是黑客不能動(dòng)Bank.exe以及內(nèi)部的PubKey1)
攻擊1:改動(dòng)并覆蓋了我的Transfer.dll,但CodedHash是一模一樣的
這種情況下,對(duì)Transfer.dll摘要的Hash和PubKey1對(duì)CodedHash解密的結(jié)果Hash是不一樣的,成功破案!
攻擊2:改動(dòng)并覆蓋了我的Transfer.dll,黑客自己生成了公鑰私鑰對(duì),并對(duì)Transfer.dll的Hash用私鑰加密成CodedHash.
這種情況下,當(dāng)我們用PubKey1解密CodedHash時(shí),由于公鑰PubKey1和黑客的私鑰不成對(duì),解密時(shí)解不開的,成功破案!
攻擊3:改動(dòng)并覆蓋了我的Transfer.dll,而Transfer.dll根本不是簽名編譯的。
這種情況下,結(jié)果和前面兩個(gè)是一樣的,成功破案!
攻擊4:黑客兄由于拿不著你的私鑰,表示沒有其它攻擊方案了,T_T。
至此,原理總算是說明白了。下面我就介紹如何利用sn.exe來辦這些事兒了。
我很討厭MS把這么多重要的任務(wù)都包裝在了sn.exe里,首先我們有兩個(gè)工程Bank.csproj和Transfer.csproj,我們要做的就是實(shí)現(xiàn)上圖的流程。
1.用sn.exe生成公鑰私鑰對(duì)文件myPair.snk。如下圖:(你要誓死保護(hù)好myPair.snk,因?yàn)槔锩嬗兴借€,且這也是私鑰唯一存在的地方)

2.在Transfer工程中,將myPair.snk的路徑填到AssemblyInfo.cs文件中,如下圖:

3.編譯Transfer工程,生成Transfer.dll。此時(shí),編譯器瞬間完成了對(duì)Transfer.dll的Hash,并用myPair.snk中的私鑰加密了Hash成CodedHash,并將CodedHash存入Transfer.dll中,同時(shí)公鑰信息也存入了Transfer.dll中(注意絕對(duì)沒有私鑰)。
4.在Bank工程中,重新引用Transfer.dll文件,重新編譯Bank.exe,編譯時(shí)編譯器將提取Transfer.dll中的公鑰PubKey1,并將其寫在引用Dll的描述中。當(dāng)我們用反編譯工具查看Bank.exe時(shí),我們可以查看到如下信息:
// Transfer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3d5e0147c186af58
PublicKeyToken即是我們所說的公鑰PubKey1。
5.此時(shí)大功告成,無(wú)論有人用自己的私鑰編譯篡改了的Transfer.dll或者根本就沒有用私鑰簽名編譯,運(yùn)行Bank.exe時(shí)會(huì)拋出如下信息:

這便是最基本的應(yīng)用了,我也是參考了不少文章,其中比較重要的是http://www.windowsdevcenter.com/pub/a/dotnet/2003/04/28/strongnaming.html,該文章還介紹了延遲簽名等機(jī)制,有興趣的朋友可以看看。
在這里再次說明,sn.exe并不能對(duì)程序集加密阻止反編譯,只是讓調(diào)用者知道調(diào)用對(duì)象是不是想要的,僅此而已。
另外,HTTPS也是用的類似的方案來判斷對(duì)方是不是自己人的,只是多了一個(gè)用對(duì)稱加密算法加密數(shù)據(jù)包這一步,其它和這個(gè)都是一樣的。
這是我園子里的第一篇博客,寫得不好歡迎拍磚~
祝大家在園子里一起進(jìn)步!
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注