应该是不让放成品的,放点核心代码
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!");
}
}