在NhibernateProfiler破解這個系列的第一篇里我們描述了NhibernateProfiler的破解思路,同時也對這個思路進行了驗證。本來准備第二篇就寫這個工具的,但最終中間還是插了二篇關於附加到進程工具的介紹與實現。現在我們就回來把這個工具給完成了,也為這個系列做個完結 。
在第一篇里我們描述的那種方法叫做暴破,也就是暴力破解,理論上跟出注冊算法,是更好的選擇,但NhibernateProfiler使用的是許可認證技術,采用的是RSA非對稱公鑰加密(RSACryptoServiceProvider),也就是說在你不知道公鑰或私鑰中的任何一個的情況下,知道了算法也是白搭,事實上RSA非對稱公鑰加密的算法本來就是公開的。關於RSA加密,網上的資料很多,各位可自行百度或GOOGLE,在這里就不詳述了,使用許可認證技術的軟件基本上只有暴破一種方法,暴破雖然較跟出算法更容易一些,但缺點也是很明顯的,就是破解的目標每出來一個新版本都要重新破解一次,而跟出算法,就不會出這樣的問題,無論他出多少版本,只要他的注冊算法不變,寫個注冊機,就可以無限制的使用,所以為了在一定程度上彌補暴破的這種缺陷,我們來寫一個自動破解工具,這樣就可以在作者沒有改動我們修改的那塊代碼的情況下,實現多次破解 。
遵循我們一向的習慣,介紹前,先看看這個破解工具實現后的 樣子。
如果你不想打開解決方案,調試運行的話(源碼在根目錄下的src文件平里),附錄的根目錄的Build文件夾里有一個編譯好的程序 NHProfilerCracker.exe , 雙擊打開就可以運行了。
可以看到有個去除升級的選項框,選中的話,NHibernateProfiler的自動升級部分也會被清除,如果不選的話,破解后的NHibernateProfiler就還可以繼續升級,不過如果保留升級的話有個問題,就是他升級一次,你就要再使用工具破解一次,而且不保證他每次升級后,這個破解工具都還有效。所以這個你們可以自行選擇,不過建議,至少保存一個去升級的版本,以備各種不測
OKAY,點擊中間那個大按鈕 會彈出文件選擇對話框,選中,附錄里 target文件夾里 NHProf.exe ,這個是我下的最新的V2.0 build 2150 的版本,寫第一篇時還是build 2148 。 如圖所示
點擊打開。 這時候如果彈出
則說明破解已經完成了,這時候我們再到target文件夾里去看看,會發現多了兩個文件,一個NHProf_bak.exe 還有一個是HibernatingRhinos.Profiler.Client.Host_bak.dll 。這是兩個被修改文件的備份,如果發現破解不行了,可以把這兩個文件替換回去 。
OKAY,這個很簡單,沒什么好介紹的,下面就開始講這個東西是怎么實現的,不過在講實現之前,還得再回顧一下,第一篇里分析出來的結果 。
在第一篇里,我們分析出來,驗證許可有效是由HibernatingRhinos.Profiler.Client.Host.dll 里 Rhino.Licensing命名空間的AbstractLicenseValidator類的IsLicenseValid這個方法完成的,所以我們只要讓這個方法永遠返回TRUE就可以實現無論如何驗證都有效了,另外我們也分析出來,只要在這個方法里改掉三個地方,就可以保證它永遠返回TRUE了,其中第一處為
throw new LicenseExpiredException("Expiration Date: " + this.ExpirationDate);
對應的是IL代碼是
IL_0085: /* 72 | (70)0021CC */ ldstr "Expiration Date: " IL_008a: /* 02 | */ ldarg.0 IL_008b: /* 28 | (06)0001AD */ call instance valuetype [mscorlib]System.DateTime Rhino.Licensing.AbstractLicenseValidator::get_ExpirationDate() IL_0090: /* 8C | (01)000038 */ box [mscorlib]System.DateTime IL_0095: /* 28 | (0A)000140 */ call string [mscorlib]System.String::Concat(object,object) IL_009a: /* 73 | (06)000207 */ newobj instance void Rhino.Licensing.LicenseExpiredException::.ctor(string) IL_009f: /* 7A | */ throw
提出來上面紅字的部分
72 700021CC
02
28 060001AD
8C 01000038
28 0A000140
73 06000207
7A
變成實際順序(還記得那個大端小端嗎,不記得可以翻翻第一篇里的描述)
72 CC210070
02
28 AD010006
8C 38000001
28 4001000A
73 07020006
7A
然后在文件(這段HEX所在的文件,這里是 HibernatingRhinos.Profiler.Client.Host.dll )里搜索上面的HEX。找到后,把他們全部清0,這樣就可以實現第一處的更改了,剩下的兩處原理也是一樣的。
OAKY,上面就是第一篇里分析出來的結果,有了這些,這個工具就容易實現了,其實我們的工具就是把上面的工作自動化了而已,自動搜索HEX,然后自動把這段HEX清0。下面我們就來用這個第一處的修改來作為例子說明一下這個工具是怎么寫的,修改其它地方的代碼你們可以自己去實現或者看源代碼里的實現,原理都是一樣的 。
代碼不是很麻煩,直接上代碼 。
string filePath = rootPath + "\\HibernatingRhinos.Profiler.Client.Host.dll" ; // 將要修改的文件讀到文件流里。 FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite) ; // 再將文件流寫到一個byte[] byte[] buffer = new byte[stream.Length]; stream.Read(buffer, 0, (int)stream.Length); // Rhino.Licensing命名空間里的AbstractLicenseValidator類的 IsLicenseValid 方法 // 里的throw .... /*********************************** 72 700021CC => CC210070 02 28 060001AD => AD010006 8C 01000038 => 38000001 28 0A000140 => 4001000A 73 06000207 => 07020006 7A ***********************************/ byte[] sinCode = new byte[] { 0x72, 0xCC, 0x21, 0x00, 0x70, 0X02, 0x28, 0xAD, 0x01, 0x00, 0x06, 0x8C, 0x38, 0x00, 0x00, 0x01, 0x28, 0x40, 0x01, 0x00, 0x0A, 0x73, 0x07, 0x02, 0x00, 0x06, 0x7A }; // 找到位置 這個方法在源文件里有,可以自己看一看不麻煩。 int startPos = this.findFirstPos(buffer, 0, sinCode); if (startPos > 0) { // 全部清0 for (int i = 0; i < sinCode.Length; i++) { stream.Seek(startPos + i, SeekOrigin.Begin); stream.WriteByte(0x00); } }
這段代碼並不是很難,不詳細解釋了, 看看注釋應該就明白了。 :)
從上面我們可以看出,只要作者不對我們改的這幾個方法進行變動的話,這個工具就是一直可以使用的,不過如果變動了這幾個地方,這個工具也就不能用了 :)