231 lines
11 KiB
Markdown
231 lines
11 KiB
Markdown
# Navicat keygen - 注册机是怎么工作的?
|
||
|
||
## 1. 关键词解释.
|
||
|
||
* __Navicat激活公钥__
|
||
|
||
这是一个2048位的RSA公钥,Navicat使用这个公钥来完成相关激活信息的加密和解密。
|
||
|
||
这个公钥储存在
|
||
|
||
```
|
||
Navicat Premium.app/Contents/Resources/rpk
|
||
```
|
||
|
||
中,你可以用任何一种文本编辑器打开并查看它。这个公钥的具体内容为:
|
||
|
||
```
|
||
-----BEGIN PUBLIC KEY-----
|
||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
|
||
qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
|
||
a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
|
||
R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
|
||
WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
|
||
YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
|
||
awIDAQAB
|
||
-----END PUBLIC KEY-----
|
||
```
|
||
|
||
如果您有相应的私钥并乐意公开的话欢迎联系我,我将非常感谢您的慷慨。
|
||
|
||
__注意:__
|
||
|
||
从 __Navicat Premium for Mac 12.0.24__ 开始,公钥不再存储在
|
||
|
||
```
|
||
Navicat Premium.app/Contents/Resources/rpk
|
||
```
|
||
|
||
中。事实上,公钥放在了Navicat的二进制执行文件
|
||
|
||
```
|
||
Navicat Premium.app/Contents/MacOS/Navicat Premium
|
||
```
|
||
|
||
中,你可以通过搜索`"-----BEGIN PUBLIC KEY-----"`来找到它。
|
||
|
||
__注意:__
|
||
|
||
从 __Navicat Premium for Mac 12.1.14__ 开始,公钥仍然以明文的方式储存在二进制可执行文件中。
|
||
|
||
但是Navicat并不从这个明文中加载公钥。事实上,密钥是从一段0x188字节长的密文中加载的。密文为:
|
||
|
||
```c
|
||
const uint8_t ciphertext[0x188] = {
|
||
0xfe, 0xfd, 0xfc, 0xf4, 0xfe, 0xd2, 0xf8, 0xf4, 0xf1, 0xd3, 0xde, 0xc7, 0xdf, 0xd3, 0xd0, 0xfd,
|
||
0x8a, 0xc3, 0x85, 0xf4, 0xf6, 0xe9, 0xfc, 0xfc, 0xf2, 0xf5, 0xfa, 0xf5, 0xf6, 0xe9, 0x81, 0xfb,
|
||
0xfe, 0xfd, 0xfc, 0xf4, 0xf4, 0xdf, 0xf2, 0xf9, 0xf2, 0xe5, 0xf0, 0xf7, 0xc0, 0x89, 0xdd, 0xcb,
|
||
0xf5, 0x87, 0xe6, 0xdd, 0xf4, 0xd9, 0xf8, 0xfb, 0xde, 0xf9, 0xcf, 0xc5, 0x8f, 0x80, 0x80, 0xf3,
|
||
0xc2, 0xd0, 0xe2, 0x8f, 0xfa, 0x8a, 0xdd, 0xf3, 0xd7, 0xdc, 0x86, 0xdc, 0xf0, 0x81, 0xc0, 0xea,
|
||
0xd0, 0xd9, 0xf9, 0xd8, 0xda, 0xf2, 0xd0, 0xfd, 0xc3, 0xf6, 0xf3, 0x82, 0xf2, 0x81, 0xef, 0xf2,
|
||
0xe0, 0xf9, 0xf2, 0xd3, 0x8f, 0xd7, 0xe9, 0xfb, 0xca, 0x86, 0xde, 0xfc, 0xf3, 0xd5, 0xdd, 0xf4,
|
||
0xc7, 0x80, 0xf7, 0xd5, 0xf2, 0xc1, 0xde, 0xcc, 0xc0, 0xc7, 0xf0, 0xd0, 0xd0, 0xd1, 0xd7, 0xcc,
|
||
0xd2, 0x81, 0xc1, 0x83, 0xdd, 0xd5, 0x8a, 0x8f, 0x81, 0xe1, 0xf4, 0xd9, 0xf3, 0xd7, 0xca, 0xef,
|
||
0xf9, 0xdf, 0xe1, 0xee, 0xf0, 0xe9, 0xd1, 0xca, 0xf2, 0xe3, 0xf8, 0xf0, 0x83, 0xde, 0xfb, 0xd7,
|
||
0xf1, 0xc4, 0xfa, 0x85, 0xf2, 0xdd, 0xdd, 0xfd, 0x85, 0x86, 0xc7, 0xf9, 0xc4, 0xc9, 0xf4, 0xf8,
|
||
0xd4, 0xd9, 0xe6, 0xd2, 0xf6, 0xc1, 0xc1, 0xf9, 0xe0, 0xe4, 0xf7, 0xe4, 0xfd, 0xf1, 0xf6, 0xfc,
|
||
0xe1, 0x84, 0xe4, 0xd1, 0xed, 0xfe, 0xdb, 0xe8, 0xdd, 0xe1, 0x85, 0xd0, 0xc5, 0xd2, 0x8a, 0x8e,
|
||
0xd5, 0xdd, 0xe3, 0xdb, 0xd0, 0xe1, 0xd0, 0xf6, 0xc6, 0xee, 0xe6, 0xf7, 0xda, 0xf1, 0xdb, 0xc9,
|
||
0x8b, 0xee, 0xcd, 0xdf, 0xff, 0xe8, 0xdd, 0xca, 0x82, 0xdb, 0xf1, 0x82, 0xc3, 0xed, 0xc9, 0xcc,
|
||
0xc0, 0xf2, 0xd6, 0xdf, 0x83, 0xe9, 0xf3, 0xce, 0xea, 0xfa, 0xdf, 0xf8, 0xd9, 0xff, 0xec, 0x88,
|
||
0xe4, 0xe4, 0xfd, 0x80, 0xc5, 0xce, 0xfa, 0xd2, 0xf4, 0xd8, 0x84, 0xff, 0xe5, 0xf3, 0xcb, 0xc2,
|
||
0xfe, 0xc0, 0xc4, 0xfa, 0xde, 0xdd, 0xd5, 0xc9, 0xc5, 0xd5, 0xdf, 0xe3, 0xdd, 0xc1, 0xcb, 0xdd,
|
||
0xfc, 0xf7, 0x83, 0xf8, 0xda, 0xc1, 0xd4, 0xe3, 0xfe, 0xc2, 0xef, 0xf8, 0xf2, 0xea, 0x8a, 0xd2,
|
||
0xc7, 0xf2, 0xf0, 0xc2, 0xfb, 0x89, 0xdc, 0xeb, 0xd1, 0xf7, 0xcc, 0xe2, 0xd1, 0xfc, 0xd4, 0xce,
|
||
0xea, 0xcd, 0xe4, 0x87, 0xe0, 0xcc, 0x8d, 0xf5, 0xc7, 0x85, 0x87, 0xda, 0xcf, 0xde, 0x89, 0xcd,
|
||
0xe5, 0xfd, 0xe7, 0x83, 0xda, 0xdb, 0xfe, 0xf4, 0x84, 0xec, 0xf6, 0xee, 0xfd, 0xea, 0xf1, 0xf5,
|
||
0xf5, 0xfc, 0xe6, 0xd0, 0x86, 0xdf, 0xc3, 0xe2, 0xe4, 0xd5, 0xd7, 0xe4, 0xe4, 0xce, 0xd4, 0xce,
|
||
0x82, 0xda, 0xc7, 0xda, 0x80, 0xcb, 0xee, 0x8c, 0xd0, 0xde, 0xcd, 0xda, 0xdd, 0xcd, 0xcc, 0xeb,
|
||
0xd2, 0xc3, 0xfc, 0xf2, 0xf6, 0xe9, 0xf8, 0xf8
|
||
};
|
||
```
|
||
|
||
这个密文是采用XOR加密得来,XOR密钥为
|
||
|
||
```
|
||
\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba
|
||
```
|
||
|
||
* __请求码__
|
||
|
||
这是一个Base64编码的字符串,代表的是长度为256字节的数据。这256字节的数据是 __离线激活信息__ 用 __Navicat激活公钥__ 加密的密文。
|
||
|
||
* __离线激活请求信息__
|
||
|
||
这是一个JSON风格的UTF-8字符串。它包含了3个Key:`"K"`、`"DI"`和`"P"`,分别代表 __序列号__、__设备识别码__(与你的电脑硬件信息相关)和 __平台__ (其实就是操作系统类型)。
|
||
|
||
例如:
|
||
|
||
```
|
||
{ "K": "xxxxxxxxxxxxxxxx", "P": "Mac 10.13", "DI": "xxxxxxxxxxxxxxxxxxxx" }
|
||
```
|
||
|
||
* __激活码__
|
||
|
||
这是一个Base64编码的字符串,代表的是长度为256字节的数据。这256字节的数据是 __离线激活回复信息__ 用 __Navicat激活私钥__ 加密的密文。目前我们不知道官方的 __Navicat激活私钥__,所以我们得替换掉软件里的公钥。
|
||
|
||
* __离线激活回复信息__
|
||
|
||
和 __离线激活请求信息__ 一样,它也是一个JSON风格的UTF-8字符串。但是它包含5个Key,分别为`"K"`、`"N"`、`"O"`、`"T"` 和 `"DI"`.
|
||
|
||
`"K"` 和 `"DI"` 的意义与 __离线激活请求信息__ 中的相同,且Value必须与 __离线激活请求信息__ 中的相同。
|
||
|
||
`"N"`、`"O"`、`"T"` 分别代表 __注册名__、__组织__、__授权时间__。
|
||
|
||
__注册名__ 和 __组织__ 的值类型为UTF-8编码的字符串。__授权时间__ 的值类型可以为字符串或整数(感谢@Wizr在issue #10中的报告)。
|
||
|
||
和Windows版本Navicat不同的是,`"T"` 项不可以省略,并且和当前时间的差距必须在-1 ~ +4天之内。
|
||
|
||
例如:
|
||
|
||
```
|
||
{
|
||
"DI" : "xxxxxxxxxxxxxxxxxxxx",
|
||
"T" : "1515770827.925012",
|
||
"K" : "xxxxxxxxxxxxxxxx",
|
||
"N" : "DoubleLabyrinth",
|
||
"O" : "Shadow"
|
||
}
|
||
```
|
||
|
||
* __序列号__
|
||
|
||
这是一个被分为了4个部分的字符串,其中每个部分都是4个字符长。
|
||
|
||
__序列号__ 是通过10个字节的数据来生成的。为了表达方便,我用 __uint8_t data[10]__ 来表示这10个字节。
|
||
|
||
1. __data[0]__ 和 __data[1]__ 必须分别为 `0x68` 和 `0x2A`。
|
||
|
||
这两个字节为Navicat的标志数。
|
||
|
||
2. __data[2]__、__data[3]__ 和 __data[4]__ 可以是任意字节,你想设成什么都行。
|
||
|
||
3. __data[5]__ 和 __data[6]__ 是Navicat的语言标志,值如下:
|
||
|
||
| 语言类型 | data[5] | data[6] | 发现者 |
|
||
|------------|:---------:|:---------:|-----------------|
|
||
| English | 0xAC | 0x88 | |
|
||
| 简体中文 | 0xCE | 0x32 | |
|
||
| 繁體中文 | 0xAA | 0x99 | |
|
||
| 日本語 | 0xAD | 0x82 | @dragonflylee |
|
||
| Polski | 0xBB | 0x55 | @dragonflylee |
|
||
| Español | 0xAE | 0x10 | @dragonflylee |
|
||
| Français | 0xFA | 0x20 | @Deltafox79 |
|
||
| Deutsch | 0xB1 | 0x60 | @dragonflylee |
|
||
| 한국어 | 0xB5 | 0x60 | @dragonflylee |
|
||
| Русский | 0xEE | 0x16 | @dragonflylee |
|
||
| Português | 0xCD | 0x49 | @dragonflylee |
|
||
|
||
4. __data[7]__ 是Navicat产品ID。(感谢 @dragonflylee 和 @Deltafox79提供的数据)
|
||
|
||
|产品名 |Enterprise|Standard|Educational|Essentials|
|
||
|---------------------|:--------:|:------:|:---------:|:--------:|
|
||
|Navicat Report Viewer|0x0B | | | |
|
||
|Navicat Data Modeler | |0x47 |0x4A | |
|
||
|Navicat Premium |0x65 | |0x66 |0x67 |
|
||
|Navicat MySQL |0x68 |0x69 |0x6A |0x6B |
|
||
|Navicat PostgreSQL |0x6C |0x6D |0x6E |0x6F |
|
||
|Navicat Oracle |0x70 |0x71 |0x72 |0x73 |
|
||
|Navicat SQL Server |0x74 |0x75 |0x76 |0x77 |
|
||
|Navicat SQLite |0x78 |0x79 |0x7A |0x7B |
|
||
|Navicat MariaDB |0x7C |0x7D |0x7E |0x7F |
|
||
|Navicat MongoDB |0x80 |0x81 |0x82 | |
|
||
|
||
5. __data[8]__ 的高4位代表 __版本号__。低4位未知,但可以用来延长激活期限,可取的值有`0000`和`0001`。
|
||
|
||
例如:
|
||
|
||
对于 __Navicat 12__: 高4位必须是`1100`,为`12`的二进制形式。
|
||
对于 __Navicat 11__: 高4位必须是`1011`,为`11`的二进制形式。
|
||
|
||
6. __data[9]__ 目前暂未知,但如果你想要 __not-for-resale license__ 的话可以设成`0xFD`、`0xFC`或`0xFB`。
|
||
|
||
根据 __Navicat 12 for Mac x64__ 版本残留的符号信息可知:
|
||
|
||
* `0xFB`是 __Not-For-Resale-30-days__ license.
|
||
* `0xFC`是 __Not-For-Resale-90-days__ license.
|
||
* `0xFD`是 __Not-For-Resale-365-days__ license.
|
||
* `0xFE`是 __Not-For-Resale__ license.
|
||
* `0xFF`是 __Site__ license.
|
||
|
||
之后Navicat使用 __ECB__ 模式的 __DES__ 算法来加密 __data[10]__ 的后8字节,也就是 __data[2]__ 到 __data[9]__ 的部分。
|
||
|
||
相应的DES密钥为:
|
||
|
||
```cpp
|
||
const uint8_t DESKey = { 0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27 };
|
||
```
|
||
|
||
之后使用Base32编码 __data[10]__,其中编码表改为:
|
||
|
||
```cpp
|
||
// Thanks for discoveries from @Wizr, issue #10
|
||
char EncodeTable[] = "ABCDEFGH8JKLMN9PQRSTUVWXYZ234567";
|
||
```
|
||
|
||
编码之后你应该会得到一个16字节长的字符串,并且以"NAV"打头。
|
||
|
||
将16字节的字符串分成4个4字节的小块,然后用`"-"`连接就可以得到 __序列号__。
|
||
|
||
## 2. 激活过程
|
||
|
||
1. 检查用户输入的 __序列号__ 是否合法。
|
||
|
||
2. 在用户点击了`激活`按钮之后,Navicat会先尝试在线激活。如果失败,用户可以选择离线激活。
|
||
|
||
3. Navicat会使用用户输入的 __序列号__ 以及从用户电脑收集来的信息生成 __离线激活请求信息__,然后用 __Navicat激活公钥__ 加密,并将密文用Base64编码,最后得到 __请求码__。
|
||
|
||
4. 正常流程下,__请求码__ 应该通过可联网的电脑发送给Navicat的官方激活服务器。之后Navicat的官方激活服务器会返回一个合法的 __激活码__。
|
||
|
||
但现在我们使用注册机来扮演官方激活服务器的角色,只是Navicat软件里的激活公钥得换成自己的公钥:
|
||
|
||
1. 根据 __请求码__, 获得`"DI"`值和`"K"`值。
|
||
|
||
2. 用`"K"`值、用户名、组织名和`"DI"`值填写 __离线激活回复信息__。
|
||
|
||
3. 用自己的2048位RSA私钥加密 __离线激活回复信息__,你将会得到256字节的密文。
|
||
|
||
4. 用Base64编码这256字节的密文,就可以得到 __激活码__。
|
||
|
||
5. 在Navicat软件中填入 __激活码__ 即可完成离线激活。
|