吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7808|回复: 64
上一主题 下一主题
收起左侧

[原创] Navicat for Sqlite 17.3.2 英文版 一字节替换RSA公钥

  [复制链接]
跳转到指定楼层
楼主
go4399 发表于 2025-8-29 22:12 回帖奖励

Navicat 17 破解教程中,iwolf大佬详细分析了 Navicat Premium 17.1.3 的破解过程。分析发现,程序所使用的 RSA 公钥以碎片化的方式分散在 libcc.dll 的 .rdata 区段中,在运行时动态拼接而成。该教程采用 Hook 技术,拦截公钥拼接函数,将原始公钥替换为自定义的公钥,从而实现离线激活。
想到论坛中有一个RSA一字节替换工具,既然公钥是以碎片形式存储的,是否可以修改这些碎片中的单个字节,实现更简洁的破解。

0. 使用的工具

x64dbg、Python、PatchRSA、010 editor

1. 找到原始RSA公钥

x64dbg打开navicat.exe,内存布局发现libcc.dll尚未加载。监视内存布局并按几次F9运行,直到libcc.dll被加载。(第一次使用x64dbg,用得不对请指正)


根据 iwolf 大佬的提示,可以通过搜索 call r8 对应的字节码,定位到调用公钥拼接函数的位置。在libcc.dll上右键单击,选择“在反汇编中转到”,进入CPU(反汇编)窗口;再次右键,选择“搜索”→“当前模块”→“匹配特征”。

在“搜索匹配特征”窗口中,使用十六进制搜索模式查找字节序列41 FF D0 90 48 8B D0 48 8B CF,该字节序列对应以下汇编指令。

call r8
nop
mov rdx,rax
mov rcx,rdi

搜索后得到如下结果:


结果不多,使用 Ctrl+A 全选,按F2设置断点。
返回 CPU(反汇编)窗口,按几次 F9 运行,程序很快便到达目标断点。再按 F8 单步执行,此时寄存器 rax 所指向的内容即为拼接后的 RSA 公钥。

2. 一字节替换RSA公钥

通过AI辅助生成以下Python脚本,从PEM格式的RSA公钥中提取参数n和e。需要pip install cryptography

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa

# PEM 格式的公钥(替换为你自己的)
pem_data = """-----BEGIN PUBLIC KEY-----
MIIBIjAN……QawIDAQAB
-----END PUBLIC KEY-----"""

# 编码为 bytes
pem_data = pem_data.encode('utf-8')

# 加载公钥
public_key = serialization.load_pem_public_key(pem_data)

# 确保是 RSA 公钥
if isinstance(public_key, rsa.RSAPublicKey):
    numbers = public_key.public_numbers()
    n = numbers.n
    e = numbers.e

    print("n (modulus) in hex:")
    print(hex(n))
    print("\ne (public exponent) in hex:")
    print(hex(e))
else:
    print("Not an RSA public key")

打开 PatchRSA 工具,填入获取的 RSA 参数 ne ,点击“计算”按钮,即可得到经单字节修改后的 ndpq 参数。


通过AI辅助生成以下Python脚本,将 nedpq这些参数重新组装成PEM格式的RSA公钥和私钥。

from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
import os

# RSA 参数(请替换为你自己的值)
n = int("xxxx", 16)  # 十六进制字符串
e = int("10001", 16) # e = 65537
d = int("xxxx", 16)
p = int("xxxx", 16)
q = int("xxxx", 16)

# 验证RSA参数
print("Validating RSA parameters...")

# 1. 检查 p * q == n
if p * q != n:
    raise ValueError(f"p * q ≠ n\np*q = {p * q}\nn   = {n}")

# 2. 检查 e 和 d 是否互为模逆
phi = (p - 1) * (q - 1)
if (e * d) % phi != 1:
    raise ValueError(f"e * d ≢ 1 mod φ(n)\n(e*d) % phi = {(e*d) % phi}")

# 3. 计算 CRT 参数
dmp1 = d % (p - 1)
dmq1 = d % (q - 1)
try:
    iqmp = pow(q, -1, p)  # q⁻¹ mod p
except ValueError:
    raise ValueError("q has no inverse mod p (gcd(q,p) ≠ 1?)")

# 构造密钥
try:
    private_numbers = rsa.RSAPrivateNumbers(
        p=p,
        q=q,
        d=d,
        dmp1=dmp1,
        dmq1=dmq1,
        iqmp=iqmp,
        public_numbers=rsa.RSAPublicNumbers(e=e, n=n)
    )

    private_key = private_numbers.private_key()
    print("Successfully constructed private key!")

    # 导出 PEM
    pem_private = private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption()
    )

    pem_public = private_key.public_key().public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo
    )

    print("\nPrivate Key (PEM):")
    print(pem_private.decode())

    print("\nPublic Key (PEM):")
    print(pem_public.decode())

except Exception as ex:
    print("Failed to create private key:", str(ex))

对比原始公钥与替换后的公钥可以发现,仅需将字符“Q”修改为“T”即可完成公钥替换。
原始公钥MIIBI……QawIDAQAB
替换公钥MIIBI……TawIDAQAB

3. 找到RSA公钥的可修改位置

回到x64dbg,按Ctrl+F2重新运行,按几次F9 运行,回到第一次命中的目标断点。这一次,按 F7 单步进入 RSA 公钥的拼装函数,跟踪其执行流程。


进入公钥拼装函数后,便可看到分散的公钥碎片。公钥碎片可能在区段中、可能是立即数、也可能是差值,等等。

F8 单步运行,直到公钥拼接到QawIDAQAB这个位置。

看到这里7FFCC01B29AC储存着Qa,正是我们要替换的地方。
在内存窗口中转到7FFCC01B29AC,记下Qa前后的字符。
关闭x64dbg。010 Editor打开libcc.dll,Hex Bytes搜索51 61 00 00,刚好找到唯一的位置,修改51为54,保存。(51 61即是Qa,改成54,即是Q改成T
再次打开x64dbg,回到第一次命中的目标断点。检查返回的RSA公钥,修改正确。

4. 离线激活

许可证密钥参考Navicat 17 破解教程XX XX v12.0.23.0 破解教程x86,x64通用,手动破解,不要补丁,无病毒
手工凑出68 2A 00 00 00 AC 88 78 10 FF  这10个字节,上述参考中对字节意义有详细解释。对后8个字节00 00 00 AC 88 78 10 FF进行DES加密(ECB模式,无填充,密钥为 “E9 7F B0 60 77 45 90 AE”),加密得到68 2A 19 59 16 1B D1 76 0F B9,手工BASE32编码得到NAVBSWIWDPIXMD5Z。断网离线激活不再赘述。注意ToolsFx不支持RSA参数是小素数因子,离线激活用到的RSA加解密需要其他工具计算。


以上仅作技术交流,最后支持使用正版软件。

参考

https://www.52pojie.cn/thread-2052969-1-1.html
https://www.52pojie.cn/thread-2008824-1-1.html
https://www.52pojie.cn/thread-688820-1-1.html

免费评分

参与人数 20吾爱币 +19 热心值 +17 收起 理由
gml857 + 1 + 1 我很赞同!
5210LYX + 1 + 1 我很赞同!
whereismy + 1 谢谢@Thanks!
banma98 + 1 谢谢@Thanks!
clove613 + 1 我很赞同!
yzdong + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
iwolf + 1 + 1 我很赞同!
myaly1008 + 1 + 1 谢谢@Thanks!
Courser + 1 + 1 用心讨论,共获提升!
tzxinqing + 2 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
wx96wx + 1 谢谢@Thanks!
pedoc + 1 + 1 谢谢@Thanks!
星空迷徒 + 1 谢谢@Thanks!
helian147 + 2 + 1 谢谢@Thanks!
slzslz + 1 + 1 我很赞同!
蚯蚓翔龙 + 1 + 1 用心讨论,共获提升!
ScriptXoX + 1 + 1 谢谢分享
congcongzhidao + 1 + 1 我很赞同!
vLove0 + 1 + 1 谢谢@Thanks!
3yu3 + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
smile1110 发表于 2025-8-29 23:06
算假key没劲,我已研发出算真key。

免费评分

参与人数 5吾爱币 +6 热心值 +5 收起 理由
clcms + 1 + 1 我很赞同!
tzxinqing + 1 + 1 牛逼
小朋友呢 + 2 + 1 用心讨论,共获提升!
lml0126 + 1 + 1 希望展开一批算号
congcongzhidao + 1 + 1 我很赞同!

查看全部评分

推荐
pedoc 发表于 2025-9-1 21:52
sdieedu 发表于 2025-9-1 19:28
靠你了  github放一下

应该是不让放成品的,放点核心代码

Program.cs

using System.Numerics;
using System.Security.Cryptography;
using System.Text;
using HarmonyLib;
using Newtonsoft.Json;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;

namespace NavicatKeygen2025;

// Thanks to
// [Navicat for Sqlite 17.3.2 英文版 一字节替换RSA公钥](https://www.52pojie.cn/thread-2056733-1-1.html)
// [Navicat 17 破解教程](https://www.52pojie.cn/thread-2052969-1-1.html)
// [XX XX v12.0.23.0 破解教程x86,x64通用,手动破解,不要补丁,无病毒](https://www.52pojie.cn/thread-688820-1-1.html)

class Program
{
    private static string RawPublicKeyOneLine =
        "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889IqdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginva5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOFR0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmtYyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQawIDAQAB";

    private static string RawPublicKey = """
                                         -----BEGIN PUBLIC KEY-----
                                         MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
                                         qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
                                         a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
                                         R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
                                         WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
                                         YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
                                         awIDAQAB
                                         -----END PUBLIC KEY-----
                                         """;

    private static string NewPublicKey = """
                                         -----BEGIN PUBLIC KEY-----
                                         MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
                                         qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
                                         a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
                                         R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
                                         WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
                                         YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuT
                                         awIDAQAB
                                         -----END PUBLIC KEY-----
                                         """;

    private static string NewPrivateKey = """
                                          -----BEGIN PRIVATE KEY-----
                                          MIIEOwIBADANBgkqhkiG9w0BAQEFAASCBCUwggQhAgEAAoIBAQDDV2oXdKQJoACY
                                          zOzzz0ip1b0zZ0h2HeMb3I9yYueYmIakEXgT1UdIwZ7yg8DLaQkOZ023gFwTKC+y
                                          wR+CKe9rm3mObfnZQCgOixQmRNcZCGkBYwXh8GYGk7cR50bras6yowGCZJ0DLEJI
                                          8FEkg4VHRCBkVtGdTR+uPfh+JWaBiIu5lICYhuzxnGIc92nWgPi1Sm+wVyLhAm1g
                                          2M2cZTZY8fqu8KEaXUhEqvEy2ouJ6Wy9qNSPKuA4Lo2bKZgy9k0RHeG0US0vV5Bs
                                          LJN8Oa1jJDVa3g63XaXF/TBUhHmZwY3tcJclEc4UdJ/WDNdZptFK+a3WeuXuxbpy
                                          PGWO65NrAgMBAAECggEAGUMDa950AGawp4nEgOrW1zEvfLo9qNW/YWBGEHyvrFLH
                                          JZNAmj8ob842AY0kVg09iBt0kAO0JPe++k07B3NhrjIt6XOvvdVAoNFi2YImpinQ
                                          vc49cDTH8uT4IFw2QnfrV1gpsQlaTPupnLjjw/dxK8mEEP8i4BdVm3CtzMj0/LvI
                                          K4z+Nzgu5WRpuc9JIaIOY6OtJAoePVr0+80uBoZ1v/S9uZucWSkwYbM+iSz71C8x
                                          5swsAjCw3R/1DCFvTOdCL0qHbB3txjkj95PqPdRv4S4Xdo37MK0M+YKBHyaPnGnJ
                                          ffJuH8NRsaw6wzCvDlI5bLrNytxbt0erw6EQPq6L4QICAf0Cgf9iPxOpOCY+LUQy
                                          soI9Q4mjX+5/ctBzvIxgfwZClVPJ+zwsSyzNHlEeDeRPuXaXl+hjyVTbCLsiR4Me
                                          DaQ3aBPTiw1bP9y3s6F5e8O4t37KtELlCRCJxt1PQLyj6YG4SdYaeTaTDuTY22pD
                                          3fWChYr0EChu0aNDi+GpnWhbnB1s56FOwGDdj84uE04DgPZcy63fdGZx1lLs5I2E
                                          s3P8LN56MEXAGHU9CjNvfLOm56E2xuCv3DSWdyLQT75rNZyEQYjVz6hWqpZ5Ydr+
                                          lCf6E/Sggt776OSyuutD5G7QevU8u+DH5CHFMLASVdCj/GZGPMPLLZtUO8yqYnDi
                                          cd2T04cCAgExAoH/UP9t5zJKnTJWqnFvXLDktdPuXha7ct+84AV5lMVmCfzeVCo6
                                          KnXXLK8JTw05j6uGxVYEZnyhQ5avq8RVYfSle9+FSHizMKSg+PYnm490sgvBpvA9
                                          OUnBxYg6vexSrSv6n2LVspIx6/OhfYht04jj0WnM2+hr8NFPX7ZNhlGEFPg2jiWe
                                          9quLsYLq64qUElc95x8hIrMvNO0NG52TfxFC7nwD1WaUqZlSZJTrzCvlRrLaJUKn
                                          /HEGO7Wy6NKPUp5xAM2uHJ2RZ0tc8EwXVV7EbNzYl9kfS5c9RYD8N1dX/hVrMYGM
                                          sfT9BHDJjZkWfMu2JDlaeSzABK0aIib8JdbbAgIAyw==
                                          -----END PRIVATE KEY-----
                                          """;

    static void Main(string[] args)
    {
        RSAParameterGenerator.PatchBouncyCastleRSAValid();

        //var formatted = RawPublicKey.formatPublicKeyPem();

        var navicatVersion = 17;

        //重置试用(可选)
        // Patcher.ResetTrial(navicatVersion);

        if (AdminChecker.IsRunAsAdmin())
        {
            Console.WriteLine("----------------------------开始patch流程----------------------------");
            Patcher.PatchHosts();
            Patcher.Patch(navicatVersion);
        }
        else
        {
            Console.WriteLine("请以管理员身份运行此程序以应用补丁");
        }

        Console.WriteLine("----------------------------开始离线激活流程----------------------------");
        var sn = GenerateKey(navicatVersion, "en");
        var chunks = sn
            .ToCharArray()
            .Select((x, i) => new { x, i })
            .GroupBy(p => p.i / 4, p => p.x)
            .Select(chunk => new string(chunk.ToArray()));
        var formattedSn = string.Join("-", chunks);

        //拿到原公钥的n和e
        //var (n, e) = ExtractModulusAndExponentFromPublicKeyV2(RawPublicKey);
        // n = "10001";
        // e = "C3576A1774A409A00098CCECF3CF48A9D5BD336748761DE31BDC8F7262E7989886A4117813D54748C19EF283C0CB69090E674DB7805C13282FB2C11F8229EF6B9B798E6DF9D940280E8B142644D7190869016305E1F0660693B711E746EB6ACEB2A30182649D032C4248F0512483854744206456D19D4D1FAE3DF87E256681888BB994809886ECF19C621CF769D680F8B54A6FB05722E1026D60D8CD9C653658F1FAAEF0A11A5D4844AAF132DA8B89E96CBDA8D48F2AE0382E8D9B299832F64D111DE1B4512D2F57906C2C937C39AD6324355ADE0EB75DA5C5FD3054847999C18DED70972511CE14749FD60CD759A6D14AF9ADD67AE5EEC5BA723C658EEB906B";

        //借助PatchRSA工具,生成新的n e d p q(1 byte patch),然后恢复成PEM格式的公私钥
        // var hexN =
        //     "C3576A1774A409A00098CCECF3CF48A9D5BD336748761DE31BDC8F7262E7989886A4117813D54748C19EF283C0CB69090E674DB7805C13282FB2C11F8229EF6B9B798E6DF9D940280E8B142644D7190869016305E1F0660693B711E746EB6ACEB2A30182649D032C4248F0512483854744206456D19D4D1FAE3DF87E256681888BB994809886ECF19C621CF769D680F8B54A6FB05722E1026D60D8CD9C653658F1FAAEF0A11A5D4844AAF132DA8B89E96CBDA8D48F2AE0382E8D9B299832F64D111DE1B4512D2F57906C2C937C39AD6324355ADE0EB75DA5C5FD3054847999C18DED70972511CE14749FD60CD759A6D14AF9ADD67AE5EEC5BA723C658EEB936B";
        // var e = 0x10001;
        // var hexD =
        //     "1943036BDE740066B0A789C480EAD6D7312F7CBA3DA8D5BF616046107CAFAC52C72593409A3F286FCE36018D24560D3D881B749003B424F7BEFA4D3B077361AE322DE973AFBDD540A0D162D98226A629D0BDCE3D7034C7F2E4F8205C364277EB575829B1095A4CFBA99CB8E3C3F7712BC98410FF22E017559B70ADCCC8F4FCBBC82B8CFE37382EE56469B9CF4921A20E63A3AD240A1E3D5AF4FBCD2E068675BFF4BDB99B9C59293061B33E892CFBD42F31E6CC2C0230B0DD1FF50C216F4CE7422F4A876C1DEDC63923F793EA3DD46FE12E17768DFB30AD0CF982811F268F9C69C97DF26E1FC351B1AC3AC330AF0E52396CBACDCADC5BB747ABC3A1103EAE8BE1";
        // var hexP = "1FD";
        // var hexQ =
        //     "623F13A938263E2D4432B2823D4389A35FEE7F72D073BC8C607F06429553C9FB3C2C4B2CCD1E511E0DE44FB9769797E863C954DB08BB2247831E0DA4376813D38B0D5B3FDCB7B3A1797BC3B8B77ECAB442E5091089C6DD4F40BCA3E981B849D61A7936930EE4D8DB6A43DDF582858AF410286ED1A3438BE1A99D685B9C1D6CE7A14EC060DD8FCE2E134E0380F65CCBADDF746671D652ECE48D84B373FC2CDE7A3045C018753D0A336F7CB3A6E7A136C6E0AFDC34967722D04FBE6B359C844188D5CFA856AA967961DAFE9427FA13F4A082DEFBE8E4B2BAEB43E46ED07AF53CBBE0C7E421C530B01255D0A3FC66463CC3CB2D9B543BCCAA6270E271DD93D387";
        //
        // var newRSAParameters = RSAParameterGenerator.GenerateRSAParameters(hexN, e, hexD, hexP, hexQ);
        // var rsa = newRSAParameters.toPemPair();
        // Console.WriteLine("private key pem:");
        // Console.WriteLine(rsa.privateKeyPem);
        // Console.WriteLine("public key pem:");
        // Console.WriteLine(rsa.publicKeyPem);

        // var e = CryptByRSAToBase64("1");
        // var r = DecryptByRSAFromBase64(e); //加密

        Console.WriteLine("SN: " + formattedSn);

        Console.WriteLine("Request Code:");
        var requestCode = Console.ReadLine();
        var reqContent = DecryptByRSAFromBase64(requestCode);
        Console.WriteLine("请求明文:" + reqContent);
        var req = JsonConvert.DeserializeObject<LicenseRequest>(reqContent);
        var resp = req.toResponse();
        var respContent = String.Format("{{\"K\":\"{0}\", \"DI\":\"{1}\", \"N\":\"{2}\", \"O\":\"{3}\", \"T\":{4}}}",
            resp.K, resp.DI, resp.N, resp.O, resp.T);
        Console.WriteLine("响应明文:" + respContent);
        var respCode = CryptByRSAToBase64(respContent);
        Console.WriteLine("Activation Code:");
        Console.WriteLine(respCode);

        Console.WriteLine("按任意键退出...");
        Console.ReadKey();
    }

    private static String GenerateKey(int version, string language)
    {
        if (version < 17) throw new ArgumentException("Version must be 17 or higher");

        var random = new Random();
        var snBytes = new byte[10];
        //固定 h*
        snBytes[0] = 0x68;
        snBytes[1] = 0x2a;

        //随机 或 固定
        snBytes[2] = (byte)random.Next(0, 256);
        snBytes[3] = (byte)random.Next(0, 256);
        snBytes[4] = (byte)random.Next(0, 256);
        // snBytes[2] = 0;
        // snBytes[3] = 0;
        // snBytes[4] = 0;

        //语言
        if (language == "en") //英文
        {
            snBytes[5] = 0xAC;
            snBytes[6] = 0x88;
        }
        else if (language == "cn") //简体中文
        {
            snBytes[5] = 0xCE;
            snBytes[6] = 0x32;
        }
        else
        {
            throw new ArgumentException("Unsupported language");
        }

        // 固定 Premium
        snBytes[7] = 0x65;
        //snBytes[7] = 0x78; //SQLite 0x78

        //版本
        snBytes[8] = (byte)(0x10 + (17 - version));

        //固定 FF
        snBytes[9] = 0xFF;

        if (version >= 17)
        {
            //15 以下 0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27
            //17版本的key
            byte[] desKey = [0xE9, 0x7F, 0xB0, 0x60, 0x77, 0x45, 0x90, 0xAE];
            var encrypt = DesEncrypt(snBytes[2..], desKey);
            var target = new byte[10];
            target[0] = 0x68;
            target[1] = 0x2a;
            Array.Copy(encrypt, 0, target, 2, 8);
            return Base32.Encode(target);
        }
        else
        {
            throw new ArgumentException("Unsupported version");
        }

        throw new NotImplementedException("Version not implemented");
    }

    private static byte[] DesEncrypt(byte[] data, byte[] key)
    {
        using DESCryptoServiceProvider des = new DESCryptoServiceProvider();
        des.Key = key;
        des.Mode = System.Security.Cryptography.CipherMode.ECB;
        des.Padding = System.Security.Cryptography.PaddingMode.PKCS7;

        using var encryptor = des.CreateEncryptor();
        return encryptor.TransformFinalBlock(data, 0, data.Length);
    }

    private static (byte[] n, byte[] e) ExtractModulusAndExponentFromPublicKey(string publicKeyPem)
    {
        using var rsa = RSA.Create();
        rsa.ImportFromPem(publicKeyPem);

        var parameters = rsa.ExportParameters(false);
        return (parameters.Modulus, parameters.Exponent);
    }

    private static (string hexN, string hexE) ExtractModulusAndExponentFromPublicKeyV2(string publicKeyPem)
    {
        using var rsa = RSA.Create();
        rsa.ImportFromPem(publicKeyPem);

        var parameters = rsa.ExportParameters(false);
        return (Convert.ToHexString(parameters.Modulus), Convert.ToHexString(parameters.Exponent));
    }

    private static byte[] DecryptByRSA(byte[] data)
    {
        // 读取私钥
        RsaPrivateCrtKeyParameters priKey;
        using (var reader = new System.IO.StringReader(NewPrivateKey))
            priKey = ((RsaPrivateCrtKeyParameters)new PemReader(reader).ReadObject());

        var decryptEngine = new Pkcs1Encoding(new RsaEngine());
        decryptEngine.Init(false, priKey);

        var decrypted = decryptEngine.ProcessBlock(data, 0, data.Length);
        return decrypted;
    }

    private static byte[] CryptByRSA(byte[] data)
    {
        // 读取私钥
        RsaPrivateCrtKeyParameters priKey;
        using (var reader = new System.IO.StringReader(NewPrivateKey))
            priKey = ((RsaPrivateCrtKeyParameters)new PemReader(reader).ReadObject());

        // 使用 PKCS1Padding 的 RSA 引擎
        var encryptEngine = new Pkcs1Encoding(new RsaEngine());
        encryptEngine.Init(true, priKey);

        // 加密
        var cipher = encryptEngine.ProcessBlock(data, 0, data.Length);
        return cipher;
    }

    private static string DecryptByRSAFromBase64(string base64Data)
    {
        var r = DecryptByRSA(Convert.FromBase64String(base64Data));
        var content = Encoding.UTF8.GetString(r);
        return content;
    }

    private static string CryptByRSAToBase64(string data)
    {
        var r = CryptByRSA(Encoding.UTF8.GetBytes(data));
        return Convert.ToBase64String(r);
    }
}

Patcher.cs

using Microsoft.Win32;

namespace NavicatKeygen2025;

public class Patcher
{
    private static string GetInstallLocation(int version) =>
        $"C:\\Program Files\\PremiumSoft\\Navicat Premium {version}";

    private static Dictionary<string, long> LibccPatchLocations = new Dictionary<string, long>()
    {
        { "1.1.0", 0x61005C4 }
    };

    public static void Patch(int navicatVersion)
    {
        PatchLibcc(navicatVersion);
    }

    public static void PatchHosts()
    {
        var hostsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System),
            @"drivers\etc\hosts");
        RemoveReadonly(hostsPath);
        var hostsContent = File.ReadAllLines(hostsPath);
        foreach (var line in hostsContent)
        {
            if (line.Contains("activate.navicat.com"))
            {
                Console.WriteLine("hosts文件已存在激活屏蔽记录");
                return;
            }
        }

        using (var sw = File.AppendText(hostsPath))
        {
            sw.WriteLine();
            sw.WriteLine("# navicat");
            sw.WriteLine("127.0.0.1 activate.navicat.com");
            sw.Flush();
        }

        Console.WriteLine("hosts文件激活屏蔽记录添加完成");
    }

    public static void PatchLibcc(int navicatVersion)
    {
        Console.WriteLine($"正在尝试 patch navicat-v{navicatVersion} libcc");
        //MI..IB..
        byte[] firstPattern = [0x4D, 0x49, 0x00, 0x00, 0x49, 0x42, 0x00, 0x00];
        var libccPath = Path.Combine(GetInstallLocation(navicatVersion), "libcc.dll");
        RemoveReadonly(libccPath);

        var libccBytes = File.ReadAllBytes(libccPath);
        var publicKeyStartLocation = GetPositionAfterMatch(libccBytes, firstPattern);
        if (publicKeyStartLocation <= 0)
        {
            Console.WriteLine("未找到公钥起始位置");
            return;
        }

        publicKeyStartLocation -= firstPattern.Length;
        //Console.WriteLine("PublicKey Location: 0x" + publicKeyStartLocation.ToString("X"));
        //Qa..
        byte[] secondPattern = [0x51, 0x61, 0x00, 0x00];
        var publicKeyPatchLocation = GetPositionAfterMatch(libccBytes, secondPattern, publicKeyStartLocation);
        if (publicKeyPatchLocation <= 0)
        {
            Console.WriteLine("未找到公钥Patch位置");
            return;
        }

        publicKeyPatchLocation -= secondPattern.Length;

        if (publicKeyPatchLocation - publicKeyStartLocation > 0x100)
        {
            Console.WriteLine(
                $"找到距离公钥起始位置(0x{publicKeyStartLocation.ToString("X")})超出距离的特征点(0x{publicKeyPatchLocation.ToString("X")}),可能已被patch过");
            return;
        }

        libccBytes[publicKeyPatchLocation] = 0x54; // Q -> T
        File.WriteAllBytes(libccPath, libccBytes);
        Console.WriteLine("libcc处理完成");
    }

    private static void RemoveReadonly(string filePath)
    {
        FileAttributes attributo = File.GetAttributes(filePath);
        if ((attributo & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
        {
            File.SetAttributes(filePath, attributo ^ FileAttributes.ReadOnly);
        }
    }

    static int GetPositionAfterMatch(byte[] data, byte[] pattern, int offset = 0)
    {
        for (int i = 0 + offset; i < (data.Length - pattern.Length); i++)
        {
            bool match = true;
            for (int k = 0; k < pattern.Length; k++)
            {
                if (data[i + k] != pattern[k])
                {
                    match = false;
                    break;
                }
            }

            if (match)
            {
                return i + pattern.Length;
            }
        }

        return -1;
    }

    public static void ResetTrial(int navicatVersion)
    {
        string dn = "Info";
        string dn2 = "ShellFolder";
        string rp = @"Software\Classes\CLSID";

        // 1. 删除固定路径的注册表键
        string[] navicatKeys =
        {
            @$"Software\PremiumSoft\NavicatPremium\Registration{navicatVersion}XCS",
            @$"Software\PremiumSoft\NavicatPremium\Registration{navicatVersion}XEN",
            @"Software\PremiumSoft\NavicatPremium\Update",
            @"Software\PremiumSoft\NavicatCommon"
        };

        foreach (var key in navicatKeys)
        {
            try
            {
                Registry.CurrentUser.DeleteSubKeyTree(key, throwOnMissingSubKey: false);
                Console.WriteLine($"Deleted: {key}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to delete {key}: {ex.Message}");
            }
        }

        Console.WriteLine("finding.....");

        using (var clsidRoot = Registry.CurrentUser.OpenSubKey(rp, writable: true))
        {
            if (clsidRoot != null)
            {
                foreach (var subKeyName in clsidRoot.GetSubKeyNames())
                {
                    try
                    {
                        using (var subKey = clsidRoot.OpenSubKey(subKeyName, writable: true))
                        {
                            if (subKey == null) continue;

                            // 检查 Info 或 ShellFolder
                            if (Array.Exists(subKey.GetSubKeyNames(),
                                    n => string.Equals(n, dn, StringComparison.OrdinalIgnoreCase)) ||
                                Array.Exists(subKey.GetSubKeyNames(),
                                    n => string.Equals(n, dn2, StringComparison.OrdinalIgnoreCase)))
                            {
                                Console.WriteLine($"deleting: {rp}\\{subKey.ToString()}");
                                clsidRoot.DeleteSubKeyTree(subKeyName, throwOnMissingSubKey: false);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Failed to process {subKeyName}: {ex.Message}");
                    }
                }
            }
        }

        Console.WriteLine("reset navicat trial done!");
    }
}

免费评分

参与人数 4吾爱币 +6 热心值 +4 收起 理由
潛行 + 1 + 1 感谢您的宝贵建议,我们会努力争取做得更好!
3yu3 + 3 + 1 谢谢@Thanks!
go4399 + 1 + 1 我很赞同!
email123 + 1 + 1 谢谢@Thanks!

查看全部评分

3#
m_h 发表于 2025-8-29 23:19
注意ToolsFx不支持RSA参数是小素数因子,离线激活用到的RSA加解密需要其他工具计算。 推荐个工具啊。!!!
4#
6302638 发表于 2025-8-30 00:03
有人研究出了真key!!!
怎么做到的啊?!!@smile1110

点评

无敌是多么寂寞  详情 回复 发表于 2025-8-30 01:18
5#
蚯蚓翔龙 发表于 2025-8-30 00:58
一字节替换有点意思
6#
smile1110 发表于 2025-8-30 01:18
6302638 发表于 2025-8-30 00:03
有人研究出了真key!!!
怎么做到的啊?!!@smile1110

无敌是多么寂寞
7#
lml0126 发表于 2025-8-30 06:12
smile1110 发表于 2025-8-29 23:06
算假key没劲,我已研发出算真key。

牛,多少位的RSA能逆出真key来?
8#
开创者 发表于 2025-8-30 08:23

是的,一旦公布,就失效。不公布,永远都可以用。
9#
duokebei 发表于 2025-8-30 10:03
厉害厉害,博主真的无敌
10#
sdieedu 发表于 2025-8-30 17:51
smile1110 发表于 2025-8-29 23:06
算假key没劲,我已研发出算真key。

搞个网页给真key吧,呵呵

点评

比你能想到的还有厉害一百倍  详情 回复 发表于 2025-8-31 02:05
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-2-15 20:44

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表