.NET 程式碼混淆工具-JIEJIE.NET

小码编匠發表於2024-10-09

前言

JIEJIE.NET是一款強大的開源.NET程式集混淆工具。它利用深度加密技術和多樣化的混淆策略,有效地保護了.NET軟體的版權和原始碼安全,防止未經授權的訪問和篡改。

專案介紹

JIEJIE.NET是一個用C#開發的開源.NET程式碼加密工具。許多開發人員擔憂其軟體會被破解,版權遭到侵犯,市場上雖有如PreEmptive dotfuscator等工具可用,但在某些特定需求上可能無法完全滿足。

因此JIEJIE.NET應運而生,它能夠對.NET程式集進行深度加密,從而有效地保護軟體版權。尤為值得一提的是,這款工具是完全開源的,可供大家免費使用。

專案功能

1、名稱混淆

重新命名型別和成員:透過變更型別和成員的名稱,增加理解API語義的難度。

2、控制流混淆

混淆控制流:隨機化IL程式碼的控制流,破壞原有的語法結構,使程式碼變得難以解讀。

3、字串加密

加密字串值:蒐集程式集中定義的所有字串值,將其轉換為靜態只讀欄位,並對這些值進行加密處理。

4、資源保護

加密資原始檔:加密並隱藏嵌入式資原始檔(如.resources檔案),使其不易被篡改。

5、分配呼叫棧保護

隱藏分配呼叫棧:調整關鍵字串值的分配呼叫流程,防止駭客利用記憶體分析工具搜尋關鍵資訊。

.NET 程式碼混淆工具-JIEJIE.NET

專案效果

1、加密程式集

JieJie.NET可以收集程式集中定義的所有字串值,將它們轉換為新類中的靜態只讀欄位,並對這些值進行加密處理。這樣就無法直接搜尋字串值,增加了破解的難度。

private string GetLicenseMessage()
{
    return "軟體的許可授權 :" + Environment.UserName;
}

使用JieJie.NET處理後的程式碼

private string GetLicenseMessage()
{
    string text = _0._6 + Environment.UserName;
    return text;
}
//  also create a new class, contains all string value in assembly in random order.
internal static class _0
{
    public static readonly string _0;
    public static readonly string _1;
    public static readonly string _2;
    public static readonly string _3;
    public static readonly string _4;
    public static readonly string _5;
    public static readonly string _6;
    public static readonly string _7;
    public static readonly string _8;
    public static readonly string _9;
    public static readonly string _10;
    public static readonly string _11;
    public static readonly string _12;
    public static readonly string _13;
    public static readonly string _14;
    public static readonly string _15;
    public static readonly string _16;
    public static readonly string _17;
    public static readonly string _18;
    public static readonly string _19;
    public static readonly string _20;
    public static readonly string _21;
​
    static _0()
    {
        byte[] datas = _BytesContainer__._0();
        _11 = GetStringByLong(datas, 151732605047602L);
        _20 = GetStringByLong(datas, 450799767951810L);
        _7 = GetStringByLong(datas, 101155071172227L);
        _4 = GetStringByLong(datas, 47279000500949L);
        _15 = GetStringByLong(datas, 415615395474299L);
        _5 = GetStringByLong(datas, 54975582493063L);
        _2 = GetStringByLong(datas, 17592187197342L);
        _14 = GetStringByLong(datas, 206708198516324L);
        _8 = GetStringByLong(datas, 124244814685054L);
        _21 = GetStringByLong(datas, 459595860893446L);
        _6 = GetStringByLong(datas, 72567769190975L);
        _13 = GetStringByLong(datas, 182518931688172L);
        _18 = GetStringByLong(datas, 433207581847376L);
        _16 = GetStringByLong(datas, 417814419099513L);
        _3 = GetStringByLong(datas, 36283884381871L);
        _1 = GetStringByLong(datas, 9895605165436L);
        _9 = GetStringByLong(datas, 136339442622330L);
        _19 = GetStringByLong(datas, 440904163377248L);
        _17 = GetStringByLong(datas, 426610511995160L);
        _0 = GetStringByLong(datas, 598562L);
        _10 = GetStringByLong(datas, 148434069970387L);
        _12 = GetStringByLong(datas, 158329675868829L);
    }
    private static string GetStringByLong(byte[] datas, long key)
    {
        int num = (int)(key & 0xFFFF) ^ 0xEF83;
        key >>= 16;
        int num2 = (int)(key & 0xFFFFF);
        key >>= 24;
        int num3 = (int)key;
        char[] array = new char[num2];
        int num4 = 0;
        while (num4 < num2)
        {
            int num5 = num4 + num3 << 1;
            array[num4] = (char)(((datas[num5] << 8) + datas[num5 + 1]) ^ num);
            num4++;
            num++;
        }
        return new string(array);
    }
}

2、混淆類成員的順序

當我們寫一個大型類的程式碼時,通常情況下,具有相同目的的欄位或方法會放置得很近。

例如:

private string _RegisterCode = null;
private bool _IsRegisteredFlag = false;
public void SetRegisterCode(string code) { }
public bool IsRegisterdCodeOK(string code) { }
public string GetErrorMessageForRegister();
// 其他成員

當駭客捕獲到某個關鍵成員(例如 _RegisterCode)並分析附近的其他成員時,可能會獲取更多有用的資訊。 但是,JieJie.NET 可以混淆類成員的順序,就像這樣:

private bool _IsRegisteredFlag = false;
// 其他成員
private string _RegisterCode = null;
// 其他成員
public string GetErrorMessageForRegister();
// 其他成員
public bool IsRegisterdCodeOK(string code) { }
// 其他成員
public void SetRegisterCode(string code) { }
// 其他成員

這樣,附近的其他成員可能與某個關鍵成員無關,這可以使破解變得更加困難。

3、隱藏陣列定義

經常在原始碼中定義陣列,例如:

public static byte[] GetBytes()
{
    return new byte[]
    {
        85,
        203,
        85,
        204,
        85,
        255,
        85,
        245,
        85
    };
}

使用 JieJie.NET 後的程式碼

public static byte[] GetBytes()
{
    byte[] array = new byte[18];
    InnerAssemblyHelper20211018.MyInitializeArray(
        array, 
        (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
    return array;
}

這樣處理後,原始陣列的定義被隱藏起來,增加了逆向工程的難度。

4、簡單使用

.NET框架控制檯應用程式。

它支援以下命令列引數:

  • input:[必需,預設引數,輸入.NET程式集檔案的完整路徑,可以是.exe或.dll檔案,目前僅支援.NET Framework 2.0及以上版本]

  • output:[可選,輸出.NET程式集檔案的完整路徑;如果為空,則使用輸入引數的值]

  • snk:[可選,強名稱簽名檔案(.snk)的完整路徑,用於給輸出程式集新增強名稱]

  • switch:[可選,多開關引數,用逗號分隔,也可以在[System.Reflection.ObfuscationAttribute.Feature]中定義。支援:

    • +controlflow:啟用方法體中的控制流混淆。

    • -controlflow:禁用方法體中的控制流混淆。

    • ±strings:啟用/禁用字串值加密。

    • ±resources:啟用/禁用資源資料加密。

    • ±memberorder:啟用/禁用型別中成員列表順序的混淆。

    • ±rename:啟用/禁用型別或成員名稱的重新命名。

    • ±allocationcallstack:啟用/禁用字串值分配呼叫棧的加密。]

  • mapxml:[可選,儲存類/成員舊名稱和新名稱對映資訊的XML格式檔案/目錄名稱。]

  • pause:[可選,在處理完成後暫停控制檯。]

  • debugmode:[可選,允許顯示一些除錯資訊文字。]

  • sdkpath:[可選,設定ildasm.exe所在目錄的完整路徑。]

  • prefixfortyperename:[可選,用於型別名稱重新命名的字首。]

  • prefixformemberrename:[可選,用於型別成員名稱重新命名的字首。]

  • deletetempfile:[可選,在任務完成後刪除模板檔案,預設為false。]

  • merge:[可選,合併到結果檔案的一些.NET程式集檔案。'*'表示合併所有引用的程式集檔案。]

  • .subsystem:[可選,整數值,'2'表示GUI模式的應用程式,'3'表示控制檯模式的應用程式。]

  • .corflags:[可選,整數標誌,'3'表示32位程序無強名稱簽名,'1'表示64位無強名稱,'9'表示32位帶強名稱,'10'表示64位帶強名稱。]

  • [BlazorWebAssembly]:[可選,處理Blazor WebAssembly程式集。]

  • DeadCode:[可選,可以是DisabledNormal(所有方法重新命名,並且沒有任何自定義屬性且從未使用)或All(所有方法重新命名且從未使用)。]

  • RemoveCustomAttributeTypeFullnames:[可選,要移除的自定義屬性型別的完整型別名稱列表。]

示例 1:保護 d:\a.dll 檔案,這將修改dll檔案。

>JIEJIE.NET.exe d:\a.dll

示例 2:分析 d:\a.dll 檔案,並將結果寫入另一個帶有強名稱的dll檔案。啟用控制流混淆,但不加密資源。

>JIEJIE.NET.exe input=d:\a.dll output=d:\publish\a.dll snk=d:\source\company.snk switch=+controlflow,-resources

以上是工具的功能和使用方法。

專案地址

GitHub:https://github.com/dcsoft-yyf/JIEJIE.NET

最後

如果你覺得這篇文章對你有幫助,不妨點個贊支援一下!你的支援是我繼續分享知識的動力。如果有任何疑問或需要進一步的幫助,歡迎隨時留言。

也可以加入微信公眾號[DotNet技術匠] 社群,與其他熱愛技術的同行一起交流心得,共同成長!優秀是一種習慣,歡迎大家留言學習!

相關文章