.net sdk中有很多很強大的工具,能夠輕易完成對.net程序的破解,只要你懂得一點IL語言就行。如今以一個 M 軟件爲例,介紹整個破解過程。json
我以"M"來稱呼這個軟件。首先,要搞明白M的註冊原理。M是經過輸入註冊碼來完成註冊的,爲了破解它,要先搞明白它註冊的原理,這就必須用反譯工具來分析它。c#
我用的反編譯工具是.net reflactor,能夠用它打開.net的可執行文件,看到C#源代碼。打開以後,通過一番尋找,發現的註冊窗口的事件處理過程所在,而後一直找到了它的註冊校驗程序。以下:編輯器
MarkdownPad2.Licensing.LicenseEngine.VerifyLicense(String, String) : Boolean public bool VerifyLicense(string licenseKey, string email) { if (string.IsNullOrEmpty(licenseKey) || string.IsNullOrEmpty(email)) { return false; } try { this.License = this.Decrypt(licenseKey); this.LicenseProcessed = true; } catch (Exception exception3) { ... return false; } if (((this.License == null) || (this.License.Email == null)) || (this.License.Product == null)) { return false; } bool flag = this.License.Email.Equals(email, StringComparison.OrdinalIgnoreCase); bool flag2 = this.License.Product == "MarkdownPad2"; return (flag && flag2); }
在窗口中輸入的email和key都被送到這裏,其中Key經過Decrypt方法進行解密,直接生成了一個License對象,這個對象的定義以下:ide
namespace MarkdownPad2.Licensing { using System; using System.Runtime.CompilerServices; public class License { public DateTime CreationDate { get; set; } public string Email { get; set; } public int LicenseTypeId { get; set; } public string Name { get; set; } public string Product { get; set; } } }
看來就是註冊信息的內存對象了。那麼,再看看生成這個對象的那個Decrypt方法:工具
private License Decrypt(string payload) { RSA rSA = CryptoKey.FromPublicKey( "-----BEGIN PUBLIC KEY-----\nMIIB...pQIDAQAB\n-----END PUBLIC KEY-----", "2QJmLPD5ktxIrFkr") .GetRSA(); byte[] msg = Convert.FromBase64String(payload); byte[] bytes = rSA.PublicDecrypt(msg, RSA.Padding.PKCS1); string str = Encoding.Default.GetString(bytes); IRestResponse response = new RestResponse { Content = str }; License license = new JsonDeserializer().Deserialize<License>(response); rSA.Dispose(); return license; }
研究一下就能明白,這個程序就是經過一個指定公鑰的rsa解密器,對傳入的Base64字符進行解密,解密以後的內容是一個Json格式的文本符串,這個文本串直接反序列化就是License對象了。ui
破解的辦法有下列幾個:this
方案肯定,如今開始修改程序。加密
ildasm是.net自帶的反編譯IL的工具。我用ildasm打開M.exe文件,看到裏面的命名空間、類名什麼的了,而後選擇菜單裏的「轉儲」,選擇一個空的目錄——注意,會生成一堆文件的,因此要用空的目錄——,確認,IL文件與資源文件就保存到那裏了。spa
因爲咱們只要動一點點代碼,其餘的都不要動的,因此,只須要注意m.il文件就好了。.net
用你喜歡的文本編輯器打開m.il文件,找到咱們打算要修改的Decrypt方法,哇,這個在C#裏只有幾行方法,在IL裏好長呀!
再回來看看這個方法的c#版:
private License Decrypt(string payload) { RSA rSA = CryptoKey.FromPublicKey( "-----BEGIN PUBLIC KEY-----\nMIIB...pQIDAQAB\n-----END PUBLIC KEY-----", "2QJmLPD5ktxIrFkr") .GetRSA(); byte[] msg = Convert.FromBase64String(payload); byte[] bytes = rSA.PublicDecrypt(msg, RSA.Padding.PKCS1); string str = Encoding.Default.GetString(bytes); IRestResponse response = new RestResponse { Content = str }; License license = new JsonDeserializer().Deserialize<License>(response); rSA.Dispose(); return license; }
咱們要把它改成這樣:
private License Decrypt(string payload) { IRestResponse response = new RestResponse { Content = payload }; JsonDeserializer deserializer = new JsonDeserializer(); return deserializer.Deserialize<License>(response); }
如今,硬起頭皮,看看IL代碼,發現並不太難,好比提及頭這段:
.locals init ( class [ManagedOpenSsl]OpenSSL.Crypto.CryptoKey V_0, class [ManagedOpenSsl]OpenSSL.Crypto.RSA V_1, uint8[] V_2, uint8[] V_3, string V_4, class [RestSharp]RestSharp.IRestResponse V_5, class [RestSharp]RestSharp.Deserializers.JsonDeserializer V_6, class MarkdownPad2.Licensing.License V_7)
這就是局部變量的定義啦,它們按位置編號,從0開始。
而後對着c#看,就是幾個ldXXX指令(ldstr:壓棧字串常量;ldloc:壓棧局部變量,ldarg:壓棧本方法參數)準備參數,一個call調用方法,若有返回值,就用stloc保存到第N號變量裏。
IL_0000: ldstr "-----BEGIN PUBLIC KEY-----\nMI...QAB\n-----END PUBLIC KEY-----" IL_0005: ldstr "2QJmLPD5ktxIrFkr" IL_000a: call class [ManagedOpenSsl]OpenSSL.Crypto.CryptoKey [ManagedOpenSsl]OpenSSL.Crypto.CryptoKey::FromPublicKey(string, string) IL_000f: stloc.0
看懂了吧?後面的也都同樣。咱們一直找到new RestResponse的地方,
IL_0034: newobj instance void [RestSharp]RestSharp.RestResponse::.ctor() IL_0039: stloc.s V_5 //new 的返回值賦值給V_5局部變量。 IL_003b: ldloc.s V_5 //第0個參數是this指針。 IL_003d: ldloc.s V_4 //set方法的參數,如今取的是V_4,也就是str局部變量 IL_003f: callvirt instance void [RestSharp]RestSharp.IRestResponse::set_Content(string)
咱們只須要把 IL_003d: ldloc.s V_4
改成 IL_003d: ldarg.1
,就把payload參數直接給了response.Content了。
IL_0034: newobj instance void [RestSharp]RestSharp.RestResponse::.ctor() IL_0039: stloc.s V_5 IL_003b: ldloc.s V_5 IL_003d: ldarg.1 IL_003f: callvirt instance void [RestSharp]RestSharp.IRestResponse::set_Content(string)
前面的RSA解密代碼若是不刪除,它們會對將放進來的明文進行解密,會引發異常,咱們就把它們都註釋了吧!也就是初始化局部變量以後到IL_0034以前的代碼都所有刪除。而最後還有一個RSA.dispose(),它對應的IL代碼以下,也一併刪除:
IL_0056: ldloc.1 IL_0057: callvirt instance void [ManagedOpenSsl]OpenSSL.Core.Base::Dispose()
還有,因爲有4個局部變量沒有被使用,因此也要在init裏把它們刪除,否則會形成程序運行時的堆棧出錯。
最後檢查程序裏的變量引用序號是否是須要調整。最後的程序是這樣:
.method private hidebysig instance class MarkdownPad2.Licensing.License Decrypt(string payload) cil managed { // 代碼大小 95 (0x5f) .maxstack 3 .locals init ( class [RestSharp]RestSharp.IRestResponse V_5, class [RestSharp]RestSharp.Deserializers.JsonDeserializer V_6, class MarkdownPad2.Licensing.License V_7) IL_0034: newobj instance void [RestSharp]RestSharp.RestResponse::.ctor() IL_0039: stloc.s V_5 IL_003b: ldloc.s V_5 IL_003d: ldarg.1 IL_003f: callvirt instance void [RestSharp]RestSharp.IRestResponse::set_Content(string) IL_0044: newobj instance void [RestSharp]RestSharp.Deserializers.JsonDeserializer::.ctor() IL_0049: stloc.s V_6 IL_004b: ldloc.s V_6 IL_004d: ldloc.s V_5 IL_004f: callvirt instance !!0 [RestSharp]RestSharp.Deserializers.JsonDeserializer::Deserialize<class MarkdownPad2.Licensing.License>(class [RestSharp]RestSharp.IRestResponse) IL_0054: stloc.s V_7 IL_005c: ldloc.s V_7 IL_005e: ret } // end of method LicenseEngine::Decrypt
ilasm是一個.net sdk裏的命令行工具,用來編譯il文件。在命令行裏執行下面的命令,M.exe就被從新生成了:
ilasm /exe /resource=M.res /output=M.exe M.il
注意,M.exe裏的程序還有不少圖片之類的資源,在反編譯時,這些資源文件也會被抽出來放到這裏,全部的資源都會在m.res文件裏描述。在從新編譯時,只須要如上面例子裏的那樣/resource=M.res就好了。
好,把破解過的M.exe放回到原來的目錄裏,替換原版的程序,而後執行之。
選擇註冊,在註冊碼框裏輸入json格式的明文:
{"CreationDate":"2014-12-11T06:06:54.0068849Z", "Email":"***@qq.com", "LicenseTypeId":1,"Name":"myname", "Product":"Msoftware"}
這個JSON數據是根據License對象的成員而編寫的。如今咱們知道這個字串會被直接反序列化爲一個妥妥的License對象。
一按OK……
成功!您如今的全部使用限制已被解除。