如何破解.net軟件

.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

  • 把 VerifyLicense 改掉,直接返回一個true。
    • 這個方法我其實用過了,可是發現了一個問題,就是軟件一啓動老是會出現一個nullException,緣由應該是在啓動時軟件檢查是否註冊,而後改過的方法給它返回了個true,但它興致勃勃地去檢查註冊的信息時,沒料到是個空的。
    • 解決辦法就是去修改c:\users<用戶名>\AppData\Local<產品名><文件名><版本號>\user.config文件,把註冊信息寫進去,可是註冊信息仍是要符合解密要求才行。因此我不採用這個方式。
  • 寫一個註冊碼生成器,用對應的私鑰生成符合程序要求的註冊碼,這樣不用改程序。
    • 問題在於,咱們沒有這個公鑰對應的私鑰,沒辦法作註冊信息以後再加密。
    • 解決辦法本身生成一個新的RSA密碼對,而後把程序的公鑰替換了,用對應的私鑰寫註冊機。那麼仍是要改程序了?意義不大,算了不用這個辦法。
  • 改掉Decrypt方法,把解密的過程跳過,讓它支持明文註冊信息,而後就隨個人意輸入了。就用這個辦法了!

方案肯定,如今開始修改程序。加密

第一步:用ildasm來反編譯EXE或是DLL文件到IL源代碼。

ildasm是.net自帶的反編譯IL的工具。我用ildasm打開M.exe文件,看到裏面的命名空間、類名什麼的了,而後選擇菜單裏的「轉儲」,選擇一個空的目錄——注意,會生成一堆文件的,因此要用空的目錄——,確認,IL文件與資源文件就保存到那裏了。spa

因爲咱們只要動一點點代碼,其餘的都不要動的,因此,只須要注意m.il文件就好了。.net

第二步:修改il文件。

用你喜歡的文本編輯器打開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來從新編譯exe文件。

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……

成功!您如今的全部使用限制已被解除。

相關文章
相關標籤/搜索