34 Commits
Author SHA1 Message Date
Double Sine 599ac96c30 Make compatible with openssl@1.1 2019-11-22 13:21:12 +08:00
Double Sine e61b0f9e8e Override rapidjson include path if specified 2019-08-28 15:33:28 +08:00
Double Sine a69805e470 Remove assert 2019-08-28 11:57:54 +08:00
Double Sine f1394f6aeb fix a typo 2019-08-28 11:55:49 +08:00
Double Sine 6272f56d01 Override include/lib path if specified 2019-08-28 11:03:17 +08:00
Double Sine ea583e9797 Add '--single-branch' option to make git-clone faster 2019-07-30 01:51:24 +08:00
Double Sine 316314f9bb Refactor code + Add support for 12.1.24 2019-07-30 01:30:16 +08:00
Double SineandGitHub c05f755957 Merge pull request #245 from cvno/mac
Fix undefined template error
2019-03-02 01:24:37 +08:00
cvnoandGitHub e37e72e2fa FIX undefined template error
FIX Exception.hpp:46:23: error: implicit instantiation of undefined template
2019-03-01 13:44:11 +08:00
Double Sine e4c55e0fa0 Remove navicat-activate-server 2019-02-08 12:26:45 +08:00
Double Sine b32aa80331 Fix typo 2019-02-08 12:25:39 +08:00
Double Sine 0d0c2a2ba7 Fix output format mistake 2019-02-08 12:21:35 +08:00
Double Sine e6964a1da3 Update readme 2019-02-08 12:20:31 +08:00
Double Sine ddf0ff7443 Add version message 2019-02-08 11:13:21 +08:00
Double Sine 8e74008d01 Update Makefile 2019-02-08 02:34:38 +08:00
Double Sine dd6d0713e6 Refactor code + Add support for 12.1.15 2019-02-08 02:23:00 +08:00
Double SineandGitHub e4e433ec94 Merge pull request #198 from bringtree/mac
fix bug
2018-12-20 14:39:47 +08:00
黄培松andGitHub bcce475faa fix bugs
```bash
g++ -std=c++11 -O2 -I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib -lcrypto ./navicat-patcher/Helper.cpp ./navicat-patcher/main.cpp ./navicat-patcher/Solution0.cpp ./navicat-patcher/Solution1.cpp -o ./bin/navicat-patcher
g++ -std=c++11 -O2 -I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib -lcrypto ./navicat-keygen/Helper.cpp ./navicat-keygen/main.cpp -o ./bin/navicat-keygen
./navicat-keygen/Helper.cpp:47:13: error: use of undeclared identifier 'assert'
            assert(bits_collected < 6);
            ^
./navicat-keygen/Helper.cpp:51:9: error: use of undeclared identifier 'assert'
        assert(outpos >= (retval.size() - 2));
        ^
./navicat-keygen/Helper.cpp:52:9: error: use of undeclared identifier 'assert'
        assert(outpos <= retval.size());
```
2018-12-20 14:31:57 +08:00
Double Sine 88ccb398a0 Refactor code 2018-12-19 18:00:46 +08:00
Double SineandGitHub 7e0705dd9d Merge pull request #96 from lxiaoxiang/update-readme
update readme
2018-09-11 14:17:43 +08:00
luoxiaoxiang.bj 193ae6bdfa update readme 2018-07-03 17:41:19 +08:00
Double Sine 23508443c4 Add Chinese README 2018-06-24 12:18:28 +08:00
Double Sine cae2eb95ff Update README.md 2018-06-24 12:16:29 +08:00
Double Sine 9f1f661752 Add supplement about code sign 2018-04-16 20:08:21 +08:00
Double Sine ee22a9ed24 Support Navicat 12.0.24 2018-04-15 20:06:05 +08:00
Double Sine 50fbcc52c3 Update readme 2018-03-17 16:52:03 +08:00
Double Sine 96cf594fe0 Add language selection. 2018-03-17 16:47:56 +08:00
Double Sine d24a420ce5 Support for multiple language. 2018-02-07 18:07:38 +08:00
Double Sine 41b319332a Support for Navicat 12 French version. 2018-02-07 10:29:05 +08:00
Double Sine 0ca18231b5 Update README.md for some adjustment. 2018-01-13 00:30:46 +08:00
Double Sine 1ec9c0cea9 Update README.md for better description. 2018-01-13 00:20:27 +08:00
Double Sine 83e43f5178 Update code for better customization. 2018-01-13 00:19:31 +08:00
Double Sine fc82c87597 remove old branch file 2017-12-11 20:37:18 +08:00
Double Sine 5e9a98c71d start mac branch 2017-12-11 20:31:50 +08:00
41 changed files with 4195 additions and 1202 deletions
+2 -289
View File
@@ -1,289 +1,2 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Typescript v1 declaration files
typings/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
MailDataReciever/Renci.SshNet.dll
*.DS_Store
bin/*
+233
View File
@@ -0,0 +1,233 @@
# Navicat Keygen - How does it work?
[中文版 How does it work?](HOW_DOES_IT_WORK.zh-CN.md)
## 1. Keyword Explanation.
* __Navicat Activation Public Key__
It is an __RSA-2048__ public key that Navicat used to encrypt or decrypt offline activation information.
It is stored in
```
Navicat Premium.app/Contents/Resources/rpk
```
You can see it by any kind of text editor. The content is:
```
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
awIDAQAB
-----END PUBLIC KEY-----
```
If you have the corresponding private key, please tell me. I would be very appreciated for your generous.
__NOTICE:__
Start from __Navicat Premuim 12.0.24 for Mac__, the public key is no longer stored in
```
Navicat Premium.app/Contents/Resources/rpk
```
Instead, the public key is stored in Navicat executable file
```
Navicat Premium.app/Contents/MacOS/Navicat Premium
```
in plaintext. You can see it by searching string `"-----BEGIN PUBLIC KEY----- "`.
__NOTICE:__
Start from __Navicat Premium 12.1.14 for Mac__, the public key is still stored in the executable file in plaintext.
However, it does not load the key from the plaintext. Instead, it loads the key from a piece of ciphertext which is 0x188 bytes long. The ciphertext is
```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
};
```
The ciphertext is encrypted by XOR encryption where XOR key is
```
\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba
```
* __Request Code__
It is a Base64 string that represents 256-bytes-long data, while the 256-bytes-long data is the ciphertext of __Offline Activation Request Information__ encrypted by __Navicat Activation Public Key__.
* __Offline Activation Request Information__
It is just a JSON-style UTF-8 string which contains 3 items. Respectively they are `"K"`, `"DI"` and `"P"`, which represent __snKey__, __DeviceIdentifier__, __Platform__.
Example:
```
{ "K": "xxxxxxxxxxxxxxxx", "P": "Mac 10.13", "DI": "xxxxxxxxxxxxxxxxxxxx" }
```
* __Activation Code__
It is a Base64 string that represents 256-bytes-long data, while the 256-bytes-long data is the ciphertext of __Offline Activation Response Information__ encrypted by __Navicat Activation Private Key__ which, so far, we don't know.
* __Offline Activation Response Information__
Just like __Offline Activation Request Information__, it is also a JSON-style UTF-8 string. But it contains 5 items. Respectively they are `"K"`, `"N"`, `"O"`, `"T"`, '`DI`'.
`"K"` and `"DI"` has the same meaning mentioned in __Offline Activation Request Information__ and must be same with the corresponding items in __Offline Activation Request Information__.
`"N"`, `"O"`, `"T"` represent __Name__, __Organization__, __Time__ respectively. __Name__ and __Organization__ are string and the type of __Time__ can be string or integer (Thanks for discoveries from @Wizr, issue #10).
Differ from Navicat Windows version, `"T"` is mandatory and must have -1 ~ +4 days difference from current time.
Example:
```
{
"DI" : "xxxxxxxxxxxxxxxxxxxx",
"T" : "1515770827.925012",
"K" : "xxxxxxxxxxxxxxxx",
"N" : "DoubleLabyrinth",
"O" : "Shadow"
}
```
* __snKey__
It is a 4-block-long string, while every block is 4-chars-long.
__snKey__ is generated by 10-bytes-long data. In order to explain it easily, I use __uint8_t data[10]__ to represent the 10-bytes-long data.
1. __data[0]__ and __data[1]__ must be `0x68` and `0x2A` respectively.
These two bytes are Naivcat signature number.
2. __data[2]__, __data[3]__ and __data[4]__ can be any byte. Just set them whatever you want.
3. __data[5]__ and __data[6]__ are related with your Navicat product language.
| Language | data[5] | data[6] | Discoverer |
|------------|-----------|-----------|-----------------|
| 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]__ is Navicat product ID. (Thanks @dragonflylee and @Deltafox79)
|Product Name |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. High 4 bits of __data[8]__ represents __major version number__.
Low 4 bits is unknown, but we can use it to delay activation deadline. Possible values are `0000` or `0001`.
__Example:__
For __Navicat 12 x64__: High 4 bits must be `1100`, which is the binary of number `12`.
For __Navicat 11 x64__: High 4 bits must be `1011`, which is the binary of number `11`.
6. __data[9]__ is unknown, but you can set it by `0xFD`, `0xFC` or `0xFB` if you want to use __not-for-resale license__.
According to symbol information in __Navicat 12 for Mac x64__ version:
* `0xFB` is __Not-For-Resale-30-days__ license.
* `0xFC` is __Not-For-Resale-90-days__ license.
* `0xFD` is __Not-For-Resale-365-days__ license.
* `0xFE` is __Not-For-Resale__ license.
* `0xFF` is __Site__ license.
After that. Navicat use __DES__ with __ECB mode__ to encrypt the last 8 bytes which are from __data[2]__ to __data[9]__.
The DES key is:
```cpp
const uint8_t DESKey = { 0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27 };
```
Then use Base32 to encode `uint8_t data[10]` whose encode table is
```cpp
// Thanks for discoveries from @Wizr, issue #10
char EncodeTable[] = "ABCDEFGH8JKLMN9PQRSTUVWXYZ234567";
```
After encoding, you will get a 16-char-long string starting with `"NAV"`.
Finally, divide the 16-char-long string to four 4-chars-long blocks and join them with `"-"` then you will get __snKey__.
## 2. Activation Process
1. Check whether __snKey__ that user inputs is valid.
2. After user clicks `Activate`, Navicat will start online activation first. If fails, user can choose offline activation.
3. Navicat will use the __snKey__ that user inputs and some information collected from user's machine to generate __Offline Activation Request Information__. Then Navicat will encrypt it by __Navicat Activation Public Key__ and return a Base64-encoded string as __Request Code__.
4. In legal way, the __Request Code__ should be sent to Navicat official activation server by a Internet-accessible computer. And Navicat official activation server will return a legal __Activation Code__.
But now, we use keygen to play the official activation server's role.
1. According to the __Request Code__, get `"DI"` value and `"K"` value.
2. Fill __Offline Activation Response Information__ with `"K"` value, name, organization name, `"DI"` value and `"T"` value.
3. Encrypt __Offline Activation Response Information__ by __Navicat Activation Private Key__ and you will get 256-byte-long data.
4. Encode the 256-byte-long data by Base64. The result is __Activation Code__.
5. After user input __Activation Code__, offline activation is done successfully.
+230
View File
@@ -0,0 +1,230 @@
# 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软件中填入 __激活码__ 即可完成离线激活。
+89
View File
@@ -0,0 +1,89 @@
CC = g++
OPENSSL_INCLUDE_PATH = /usr/local/opt/openssl/include
OPENSSL_LIB_PATH = /usr/local/opt/openssl/lib
CAPSTONE_INCLUDE_PATH = #/usr/local/Cellar/capstone/4.0.1/include
CAPSTONE_LIB_PATH = #/usr/local/Cellar/capstone/4.0.1/lib
KEYSTONE_INCLUDE_PATH = #/usr/local/Cellar/keystone/0.9.1/include
KEYSTONE_LIB_PATH = #/usr/local/Cellar/keystone/0.9.1/lib
RAPIDJSON_INCLUDE_PATH = #/usr/local/Cellar/rapidjson/1.1.0/include
LIBPLIST_INCLUDE_PATH = #/usr/local/Cellar/libplist/2.0.0_1/include
LIBPLIST_LIB_PATH = #/usr/local/Cellar/libplist/2.0.0_1/lib
OUTPUT_DIR = ./bin/
COMMON_DIR = ./common/
PATCHER_DIR = ./navicat-patcher/
KEYGEN_DIR = ./navicat-keygen/
COMMON_HEADER = \
$(COMMON_DIR)Exception.hpp \
$(COMMON_DIR)ExceptionOpenssl.hpp \
$(COMMON_DIR)ExceptionSystem.hpp \
$(COMMON_DIR)ResourceOwned.hpp \
$(COMMON_DIR)ResourceTraitsOpenssl.hpp \
$(COMMON_DIR)RSACipher.hpp \
PATCHER_HEADER = \
$(PATCHER_DIR)ExceptionCapstone.hpp \
$(PATCHER_DIR)ExceptionKeystone.hpp \
$(PATCHER_DIR)ResourceTraitsCapstone.hpp \
$(PATCHER_DIR)ResourceTraitsKeystone.hpp \
$(PATCHER_DIR)ResourceTraitsUnix.hpp \
$(PATCHER_DIR)CapstoneDisassembler.hpp \
$(PATCHER_DIR)KeystoneAssembler.hpp \
$(PATCHER_DIR)X64ImageInterpreter.hpp \
$(PATCHER_DIR)PatchSolutions.hpp
PATCHER_SOURCE = \
$(PATCHER_DIR)CapstoneDisassembler.cpp \
$(PATCHER_DIR)KeystoneAssembler.cpp \
$(PATCHER_DIR)X64ImageInterpreter.cpp \
$(PATCHER_DIR)HelperIsResolvedTo.cpp \
$(PATCHER_DIR)HelperPrintMemory.cpp \
$(PATCHER_DIR)PatchSolution0.cpp \
$(PATCHER_DIR)PatchSolution1.cpp \
$(PATCHER_DIR)PatchSolution2.cpp \
$(PATCHER_DIR)main.cpp
PATCHER_BINARY = $(OUTPUT_DIR)navicat-patcher
KEYGEN_HEADER = \
$(KEYGEN_DIR)DESCipher.hpp \
$(KEYGEN_DIR)NavicatKeygen.hpp
KEYGEN_SOURCE = \
$(KEYGEN_DIR)Base64.cpp \
$(KEYGEN_DIR)main.cpp
KEYGEN_BINARY = $(OUTPUT_DIR)navicat-keygen
patcher: $(PATCHER_HEADER) $(PATCHER_SOURCE)
@if [ ! -d $(OUTPUT_DIR) ]; then mkdir -p $(OUTPUT_DIR); fi
$(CC) -std=c++17 -O2 \
-I$(OPENSSL_INCLUDE_PATH) -L$(OPENSSL_LIB_PATH) \
$(if $(CAPSTONE_INCLUDE_PATH),-I$(CAPSTONE_INCLUDE_PATH),) $(if $(CAPSTONE_LIB_PATH),-L$(CAPSTONE_LIB_PATH),) \
$(if $(KEYSTONE_INCLUDE_PATH),-I$(KEYSTONE_INCLUDE_PATH),) $(if $(KEYSTONE_LIB_PATH),-L$(KEYSTONE_LIB_PATH),) \
$(if $(LIBPLIST_INCLUDE_PATH),-I$(LIBPLIST_INCLUDE_PATH),) $(if $(LIBPLIST_LIB_PATH),-L$(LIBPLIST_LIB_PATH),) \
-lcrypto -lcapstone -lkeystone -lplist++ $(PATCHER_SOURCE) -o $(PATCHER_BINARY)
@echo
keygen: $(KEYGEM_HEADER) $(KEYGEN_SOURCE)
@if [ ! -d $(OUTPUT_DIR) ]; then mkdir -p $(OUTPUT_DIR); fi
$(CC) -std=c++17 -O2 \
-I$(OPENSSL_INCLUDE_PATH) -L$(OPENSSL_LIB_PATH) \
$(if $(RAPIDJSON_INCLUDE_PATH),-I$(RAPIDJSON_INCLUDE_PATH),) \
-lcrypto $(KEYGEN_SOURCE) -o $(KEYGEN_BINARY)
all: patcher keygen
@echo 'Done.'
.PHONY: all
clean:
ifeq ($(wildcard $(PATCHER_BINARY)), $(PATCHER_BINARY))
rm $(PATCHER_BINARY)
endif
ifeq ($(wildcard $(KEYGEN_BINARY)), $(KEYGEN_BINARY))
rm $(KEYGEN_BINARY)
endif
+294 -131
View File
@@ -1,156 +1,319 @@
# Navicat Keygen
This repository will tell you how Navicat offline activation works.
[中文版README](README.zh-CN.md)
## 1. Keyword Explanation.
This repository will tell you how Navicat offline activation works.
* __Navicat Activation Public Key__
[How does it work?](HOW_DOES_IT_WORK.md)
It is a __RSA-2048__ public key that Navicat used to encrypt or decrypt offline activation information.
__NOTICE: This keygen only supports Navicat Premium.__
It is stored in __navicat.exe__ as a kind of resource called __RCData__. The resource name is `"ActivationPubKey"`. You can see it by a kind of software [___Resource Hacker___](http://www.angusj.com/resourcehacker/). The concrete content is:
## 1. How to build
> -----BEGIN PUBLIC KEY-----
> MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
> qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
> a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
> R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
> WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
> YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
> awIDAQAB
> -----END PUBLIC KEY-----
* Before you build keygen, you should make sure you have following libs:
```
openssl
capstone
keystone
rapidjson
libplist
```
You can install them by
```shell
$ brew install openssl
$ brew install capstone
$ brew install keystone
$ brew install rapidjson
$ brew install libplist
```
* Clone `mac` branch and build keygen and patcher:
```shell
$ git clone -b mac --single-branch https://github.com/DoubleLabyrinth/navicat-keygen.git
$ cd navicat-keygen
$ make all
```
You will see two executable files in `bin/` directory:
```shell
$ ls bin/
navicat-keygen navicat-patcher
```
## 2. How to Use
1. Build keygen and patcher.
2. Backup all of your saved database connection configurations (with password).
3. Remove all connections, if have, that Navicat saved in `Keychain Access.app`.
You can find them by search with keyword `navicat` in `Keychain Access.app`.
4. Use `navicat-patcher` to replace __Navicat Activation Public Key__.
```
Usage:
navicat-patcher <Navicat installation path> [RSA-2048 Private Key File]
<Navicat installation path> Path to `Navicat Premium.app`.
Example:
/Applications/Navicat\ Premium.app/
This parameter must be specified.
[RSA-2048 Private Key File] Path to a PEM-format RSA-2048 private key file.
This parameter is optional.
```
* `<Navicat installation path>`: The path to `Navicat Premium.app`.
__This parameter must be specified.__
* `[RSA-2048 PrivateKey(PEM file)]`: The path to an RSA-2048 private key file.
__This parameter is optional.__
If not specified, `navicat-patcher` will generate a new RSA-2048 private key file `RegPrivateKey.pem` at current directory.
__Example:__
```console
$ ./navicat-patcher /Applications/Navicat\ Premium.app/
```
It has been tested on __Navicat Premium 12.1.24 For Mac Simplified Chinese__ version.
The following is an example of output:
```console
$ ./navicat-patcher /Applications/Navicat\ Premium.app/
***************************************************
* Navicat Patcher by @DoubleLabyrinth *
* Version: 4.0 *
***************************************************
Press Enter to continue or Ctrl + C to abort.
[*] Your Navicat version: 12.1.24
[+] PatchSolution0 ...... Ready to apply.
Keyword offset = +0x024a7db8
[-] PatchSolution1 ...... Omitted.
[+] PatchSolution2 ...... Ready to apply.
Function offset = +0x00ec9868
Keyword offset = +0x0263fd60
std::string::append(const char*) RVA = 0x000000010214b726
[*] Generating new RSA private key, it may take a long time...
[+] New RSA private key has been saved to RegPrivateKey.pem.
[*] Your RSA public key:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA030QIDXRx372bGrne9kp
uuAqpxaxJX0x6LVaOf8+Uan2SQnFH8frnuMDRg5PjdBnFWEJGqZmRD1fNkLOhhCE
iFZWxrDgJcuEBrv5VlduQ4hlYIulcf6qilBZUaaX9Kb3R7+H8ClMb00HwLc/Iht5
bd9krhU3CT3g2ZG00GxVhEF4a/zZMDjeuQvTUeeubIeriT/2YC+w/tKfGbqWvjC6
wkbjXGbVICSiKzhzztS4BHbtQMl8v6doMhFVd/PEDNFQrbkEr3kbk/oD8AccL8iz
aV17UHt4VW2fR8tMyTvcuhTaUtWmt/tL6Z1RzCqH+KvTv8GpH8qFcty89YXja7dL
kQIDAQAB
-----END PUBLIC KEY-----
**************************************************************
* PatchSolution0 *
**************************************************************
@+0x024a7db8
Previous:
-0x0000000000000008 2d 2d 2d 2d 2d 42 45 47 -----BEG
+0x0000000000000008 49 4e 20 50 55 42 4c 49 43 20 4b 45 59 2d 2d 2d IN PUBLIC KEY---
+0x0000000000000018 2d 2d 00 4d 49 49 42 49 6a 41 4e 42 67 6b 71 68 --.MIIBIjANBgkqh
+0x0000000000000028 6b 69 47 39 77 30 42 41 51 45 46 41 41 4f 43 41 kiG9w0BAQEFAAOCA
...
...
...
After:
-0x0000000000000008 2d 2d 2d 2d 2d 42 45 47 -----BEG
+0x0000000000000008 49 4e 20 50 55 42 4c 49 43 20 4b 45 59 2d 2d 2d IN PUBLIC KEY---
+0x0000000000000018 2d 2d 00 4d 49 49 42 49 6a 41 4e 42 67 6b 71 68 --.MIIBIjANBgkqh
+0x0000000000000028 6b 69 47 39 77 30 42 41 51 45 46 41 41 4f 43 41 kiG9w0BAQEFAAOCA
...
...
...
**************************************************************
* PatchSolution2 *
**************************************************************
@+0x0263fd60
Previous:
+0x0000000000000000 42 49 6a 57 79 6f 65 52 52 30 4e 42 67 6b 71 6e BIjWyoeRR0NBgkqn
+0x0000000000000010 44 5a 57 78 43 67 4b 43 45 41 77 31 64 71 46 33 DZWxCgKCEAw1dqF3
+0x0000000000000020 44 54 76 4f 42 39 31 5a 48 77 65 63 4a 59 46 72 DTvOB91ZHwecJYFr
+0x0000000000000030 64 4d 31 4b 45 68 31 79 56 65 52 6f 47 71 53 64 dM1KEh1yVeRoGqSd
+0x0000000000000040 4c 4c 47 5a 47 55 6c 6e 67 69 67 33 4f 44 35 6d LLGZGUlngig3OD5m
...
...
...
@+0x00ec9868
Previous:
-0x0000000000000008 55 48 89 e5 41 57 41 56 UH..AWAV
+0x0000000000000008 53 48 83 ec 38 49 89 fe c6 45 e5 01 31 c0 88 45 SH..8I...E..1..E
+0x0000000000000018 e6 88 45 e7 48 8d 35 c5 70 61 01 48 8d 5d b0 48 ..E.H.5.pa.H.].H
+0x0000000000000028 89 df e8 49 d9 ff ff 48 8d 35 ef ed 60 01 48 89 ...I...H.5..`.H.
+0x0000000000000038 df e8 80 1e 28 01 e8 3f f4 00 00 88 45 e5 e8 b7 ....(..?....E...
+0x0000000000000048 f4 00 00 88 45 e6 e8 2f f5 00 00 88 45 e7 f6 45 ....E../....E..E
After:
-0x0000000000000008 55 48 89 e5 41 57 41 56 UH..AWAV
+0x0000000000000008 53 48 83 ec 48 48 89 fb 48 31 c0 48 89 04 24 48 SH..HH..H1.H..$H
+0x0000000000000018 89 44 24 08 48 89 44 24 10 48 8d 3c 24 48 8d 35 .D$.H.D$.H.<$H.5
+0x0000000000000028 cc 64 77 01 e8 8d 1e 28 01 48 8b 04 24 48 89 03 .dw....(.H..$H..
+0x0000000000000038 48 8b 44 24 08 48 89 43 08 48 8b 44 24 10 48 89 H.D$.H.C.H.D$.H.
+0x0000000000000048 43 10 48 89 d8 48 83 c4 48 5b 41 5e 41 5f 5d c3 C.H..H..H[A^A_].
[+] PatchSolution0 has been applied.
[+] PatchSolution2 has been applied.
**************************************************************
* Patch has been done successfully. Have fun and enjoy~~ *
* DO NOT FORGET TO SIGN NAVICAT BY YOUR CERTIFICATE!!! *
**************************************************************
```
* __FOR Navicat Premium version < 12.0.24 ONLY:__
`navicat-patcher` will abort and won't apply any patch.
You should use openssl to generate `RegPrivateKey.pem` and `rpk` file.
```console
$ openssl genrsa -out RegPrivateKey.pem 2048
$ openssl rsa -in RegPrivateKey.pem -pubout -out rpk
```
Then replace
```
/Applications/Navicat Premium.app/Contents/Resources/rpk
```
by `rpk` you just generated.
5. __Generate a self-signed code-sign certificate and always trust it.__
__Then use `codesign` to re-sign `Navicat Premium.app`.__
```console
$ codesign -f -s "Your self-signed code-sign certificate name" <path to Navicat Premium.app>
```
__NOTICE:__
"Your self-signed code-sign certificate name" is the name of your certificate in `Keychain Access.app`, not path.
__Example:__
```console
$ codesign -f -s "foobar" /Applications/Navicat\ Premium.app/
```
6. Then use `navicat-keygen` to generate __snKey__ and __Activation Code__.
```
Usage:
navicat-keygen <RSA-2048 Private Key File>
<RSA-2048 Private Key File> Path to a PEM-format RSA-2048 private key file.
This parameter must be specified.
```
* `<RSA-2048 Private Key File>`: Path to a PEM-format RSA-2048 private key file.
__This parameter must be specified.__
__Example:__
```console
$ ./navicat-keygen ./RegPrivateKey.pem
```
You will be asked to select Navicat language and give major version number. After that an randomly generated __snKey__ will be given.
```console
$ ./navicat-keygen ./RegPrivateKey.pem
***************************************************
* Navicat Keygen by @DoubleLabyrinth *
* Version: 4.0 *
***************************************************
Which is your Navicat Premium language?
0. English
1. Simplified Chinese
2. Traditional Chinese
3. Japanese
4. Polish
5. Spanish
6. French
7. German
8. Korean
9. Russian
10. Portuguese
If you have the corresponding private key, please tell me. I would be very appreciated for your generous.
(Input index)> 1
* __Request Code__
(Input major version number, range: 0 ~ 15, default: 12)> 12
It is a Base64 string that represents 256-bytes-long data, while the 256-bytes-long data is the cipher text of the __offline activation information__ encrypted by __Navicat Activation Public Key__.
Serial number:
NAVG-Z5H9-NK2L-MAZJ
* __Offline Activation Request Information__
Your name:
```
It is just a JSON-style ASCII string which contains 3 items. Respectively they are `"K"`, `"DI"` and `"P"`, which represent __snKey__, __checksum__ (related with your machine and OS), __Platform__ (Appropriately speaking, it should be OS Type).
You can use this __snKey__ to activate your Navicat preliminarily.
Then you will be asked to input `Your name` and `Your organization`. Just set them whatever you want, but not too long.
Like:
> {"K": "xxxxxxxxxxxxxxxx", "DI": "yyyyyyyyyyyyy", "P": "WIN8"}
```console
Your name: DoubleLabyrinth
Your organization: DoubleLabyrinth
Input request code (in Base64), input empty line to end:
```
After that, you will be asked to input request code. Now __DO NOT CLOSE KEYGEN__.
* __Activation Code__
7. __Disconnect your network__ and open Navicat Premium.
It is a Base64 string that represents 256-bytes-long data, while the 256-bytes-long data is the cipher text of the __offline activation response information__ encrypted by __Navicat Activation Private Key__ (so far, we don't know official activation private key).
Find and click `Registration`.
Fill license key by __Serial number__ that the keygen gave and click `Activate`.
* __Offline Activation Response Information__
8. Generally online activation will fail and Navicat will ask you do `Manual Activation`, just choose it.
Just like __Offline Activation Request Information__, it is also a JSON-style ASCII string. But it contains 5 items. Respectively they are `"K"`, `"N"`, `"O"`, `"T"`, '`DI`'.
9. Copy your request code and paste it in the keygen. Input empty line to tell the keygen that your input ends.
`"K"` and `"DI"` has the same meaning mentioned in __Offline Activation Request Information__ and must be same with the corresponding items in __Offline Activation Request Information__.
```console
Your name: DoubleLabyrinth
Your organization: DoubleLabyrinth
`"N"`, `"O"`, `"T"` represent __Name__, __Organization__, __Time__ respectively. __Name__ and __Organization__ are string and the type of __Time__ is unknown.
Input request code (in Base64), input empty line to end:
Nuk6pouXNhuGnqb2rBbxpDOiCFxhdJF4/gteYA/UZFUwqmhhphn3PAErvlxCtbUCf9Lzw02gfIFog3gmTB1C5JzPdeE5uuD6SAvhlQ7ZVOmdA66dvt6mDDpuf78cGio1Rpkd0D/6dLzgHnFJJPOfPtlIT5ZOLDiWkiSJm8d83+ckMBoMtcvpXCiwDIGb1KfVZwsgLojyrrO5OzakIzd2xQ8r3mEmbVbMl/zD0S5fO4agxEOp2WvpmM1cqom9Egll7kgcQG8A0z1Abqo1PrVBjjOsb/v8wy5V/469G6/uDT4AkZQSz8m/TX9ZQlZE3QBlzrJ+sTEkpMVhw3h3u6l4JQ==
`"T"` can be omitted.
Request Info:
{"K":"NAVGZ5H9NK2LMAZJ", "DI":"NGVlZjdjOTViMzYyMWI0", "P":"MAC"}
* __snKey__
Response Info:
{"K":"NAVGZ5H9NK2LMAZJ","DI":"NGVlZjdjOTViMzYyMWI0","N":"DoubleLabyrinth","O":"DoubleLabyrinth","T":1564415636}
It is a 4-block-long string, while every block is 4-chars-long.
License:
Vd4QUzEw6DPNpJLYVKV6ZNDny0gsZWCXbKyrf2nF27iTM35YUBouXEcAB/Vy355V2z++7iXe/coKmV4kNZbywlBchI5ts7gOHnhXWzBYQ3yKsBYKob/7sxaiw7CXCmhM4mPLMzrp5okewCWjBjb51keZ4SA3F6j8HGIVYiZW3CAZtkjxs9uUoXvVIJr+Gt83TgU+sqiC4oSplokopAql2zWPieA9KuhPoCKiGLMvuQwv0wWWPc2HorY0AHAetsyZ8MN4utZ2ylQ9z/ZojwX1KViyh3xxnjWF7xXJljIdBA4tCi4QDqDLvTuICfUV7VeKzOUY+ZKCO0xGxkTe1HVwog==
```
__snKey__ is generated by 10-bytes-long data. In order to explain it easily, I use __data[10]__ to represent the 10-bytes-long data.
10. Finally, you will get __Activation Code__ which looks like a Base64 string.
1. __data[0]__ and __data[1]__ must be `0x68` and `0x2A` respectively.
Just copy it and paste it in Navicat `Manual Activation` window, then click `Activate`.
If nothing wrong, activation should be done successfully.
_`May change when Navicat product changes. Uncertain yet.`_
2. __data[2]__, __data[3]__ and __data[4]__ can be any byte. Just set them whatever you want.
_`May change when Navicat product changes. Uncertain yet. But it's very possible right.`_
3. __data[5]__ and __data[6]__ are related with your Navicat product language. It depends.
~~_`May change when Navicat product changes. Uncertain yet.`_~~
_`Must change when Navicat product changes. Confirmed yet.`_
For __Navicat 12 x64 Simplified Chinese version__: They must be `0xCE` and `0x32` respectively.
For __Navicat 12 x64 Traditional Chinese version__: They must be `0xAA` and `0x99` respectively.
For __Navicat 11 x64 Simplified Chinese version__: They must be `0xCE` and `0x32` respectively.
According to __Navicat 12 for Mac x64__ version, what IDA 7.0 indicates is that this two bytes are product signature.
4. __data[7]__ represents whether it is __commercial license__ or __non-commercial license__.
For __Navicat 12 x64__: `0x65` is __commercial license__, `0x66` is __non-commercial license__.
For __Navicat 11 x64__: `0x15` is __commercial license__, `0x16` is __non-commercial license__.
_`May change when Navicat product changes. Uncertain yet.`_
_`Must change when version change.`_
According to __Navicat 12 for Mac x64__ version, what IDA 7.0 indicates is that commercial license is __Enterprise License__ and non-commercial license is __Educational License__.
5. High 4 bits of __data[8]__ represents __version number__. Low 4 bits is unknown, but we can use it to delay activation deadline. Possible value is `0000` or `0001`.
For __Navicat 12 x64__: High 4 bits must be `1100`, which is the binary of number `12`.
For __Navicat 11 x64__: High 4 bits must be `1011`, which is the binary of number `11`.
_`Must change when version change. Confirmed by Navicat 12 for Mac x64 with IDA Pro 7.0`_
6. __data[9]__ is unknown, but you can set it `0xFD` or `0xFC` or `0xFB` if you want to use __not-for-resale license__.
_`May change when Navicat product changes. Uncertain yet.`_
According to __Navicat 12 for Mac x64__ version, what IDA 7.0 indicates is that:
* `0xFB` is __Not-For-Resale-30-days__ license.
* `0xFC` is __Not-For-Resale-90-days__ license.
* `0xFD` is __Not-For-Resale-365-days__ license.
* `0xFE` is __Not-For-Resale__ license.
* `0xFF` is __Site__ license.
-----------------
After that. Navicat use __DES__ with __ECB mode__ to encrypt the last 8 bytes which are from __data[2]__ to __data[9]__.
The DES key is:
```cpp
unsigned char DESKey = { 0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27 };
```
Then encode the 10-bytes-long data: __(Use Base32 encode if you just want a conclusion.)__
1. Regard __data[10]__ as a 80-bits-long data.
If __data[10]__ starts with `0x68` and `0x2A`, so the 80-bits-long data is `01011000 00101010......`
2. Divide the 80-bits-long data as 16 5-bits-long blocks.
If __data[10]__ starts with `0x68` and `0x2A`, so the 80-bits-long data is `01011`, `00000`, `10101`, `0....`, ...
3. So the value every block is less than 32. Map them by a encode-table:
```cpp
char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
```
Then you will get a 16-char-long string.
If __data[10]__ starts with `0x68` and `0x2A`, so after encoded, it should starts with `"N"`, `"A"`, `"V"`.
4. Divide the 16-char-long string to four 4-chars-long blocks, Then you get __snKey__.
## 3. Activation Process
1. Check whether __sn_Key__ that user inputs is legal.
2. After user clicks `Activate`, Navicat will start online activation first. If fails, user can choose offline activation.
3. Navicat will use the __snKey__ that user inputs and some information collected from user's machine to generate __Offline Activation Request Information__, then encrypt it by __Navicat Activation Public Key__ and return Base64-encoded string as __Request Code__.
4. In legal way, the __Request Code__ should be sent to Navicat official activation server by a Internet-accessible computer. And Navicat official activation server will return a legal __Activation Code__.
But now, we use keygen to play the official activation server's role.
1. According to the __Request Code__, Get `"DI"` value and `"K"` value.
2. Fill __Offline Activation Response Information__ with `"K"` value, name, organization name and `"DI"` value.
3. Encrypt __Offline Activation Response Information__ by __Navicat Activation Private Key__ and you will get 256-byte-long data.
4. Encode 256-byte-long data by Base64. The result is __Activation Code__.
5. Input __Activation Code__, then offline activation is done.
+310
View File
@@ -0,0 +1,310 @@
# Navicat Keygen
这份repo将会告诉你Navicat是怎么完成离线激活的。
[注册机是怎么工作的?](HOW_DOES_IT_WORK.zh-CN.md)
## 1. 如何编译
* 在编译之前,你应该确保你有如下几个库:
```
openssl
capstone
keystone
rapidjson
libplist
```
如果你有`brew`的话,你可以通过
```
$ brew install openssl
$ brew install capstone
$ brew install keystone
$ brew install rapidjson
$ brew install libplist
```
来完成它们的安装。
* Clone `mac` 分支,并编译keygen和patcher
```bash
$ git clone -b mac --single-branch https://github.com/DoubleLabyrinth/navicat-keygen.git
$ cd navicat-keygen
$ make all
```
编译完成后你会在 `bin/` 文件夹下看到两个可执行文件:
```bash
$ ls bin/
navicat-keygen navicat-patcher
```
## 2. 如何使用这个Keygen
1. 编译好keygen和patcher。
2. 备份好Navicat中所有已保存的数据库连接(包括密码)。
3. 移除所有Navicat在 `Keychain Access.app` (即钥匙链)中保存的连接,如果有的话。
你可以通过在 `Keychain Access.app` 中搜索关键词 `navicat` 来找到它们。
4. 使用`navicat-patcher`替换掉公钥:
```
Usage:
navicat-patcher <Navicat installation path> [RSA-2048 Private Key File]
<Navicat installation path> Path to `Navicat Premium.app`.
Example:
/Applications/Navicat\ Premium.app/
This parameter must be specified.
[RSA-2048 Private Key File] Path to a PEM-format RSA-2048 private key file.
This parameter is optional.
```
* `<Navicat installation path>`: `Navicat Premium.app` 的路径。
__这个参数必须指定。__
* `[RSA-2048 PrivateKey(PEM file)]`: PEM格式的RSA-2048私钥文件路径。
__这个参数是可选的。__
如果没有指定,`navicat-patcher`将会在当前目录下生成一个新的RSA-2048私钥文件`RegPrivateKey.pem`。
__例如:__
```console
$ ./navicat-patcher /Applications/Navicat\ Premium.app/
```
__Navicat Premium For Mac 12.1.24 简体中文版__ 已通过测试。下面将是一份样例输出:
```console
$ ./navicat-patcher /Applications/Navicat\ Premium.app/
***************************************************
* Navicat Patcher by @DoubleLabyrinth *
* Version: 4.0 *
***************************************************
Press Enter to continue or Ctrl + C to abort.
[*] Your Navicat version: 12.1.24
[+] PatchSolution0 ...... Ready to apply.
Keyword offset = +0x024a7db8
[-] PatchSolution1 ...... Omitted.
[+] PatchSolution2 ...... Ready to apply.
Function offset = +0x00ec9868
Keyword offset = +0x0263fd60
std::string::append(const char*) RVA = 0x000000010214b726
[*] Generating new RSA private key, it may take a long time...
[+] New RSA private key has been saved to RegPrivateKey.pem.
[*] Your RSA public key:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA030QIDXRx372bGrne9kp
uuAqpxaxJX0x6LVaOf8+Uan2SQnFH8frnuMDRg5PjdBnFWEJGqZmRD1fNkLOhhCE
iFZWxrDgJcuEBrv5VlduQ4hlYIulcf6qilBZUaaX9Kb3R7+H8ClMb00HwLc/Iht5
bd9krhU3CT3g2ZG00GxVhEF4a/zZMDjeuQvTUeeubIeriT/2YC+w/tKfGbqWvjC6
wkbjXGbVICSiKzhzztS4BHbtQMl8v6doMhFVd/PEDNFQrbkEr3kbk/oD8AccL8iz
aV17UHt4VW2fR8tMyTvcuhTaUtWmt/tL6Z1RzCqH+KvTv8GpH8qFcty89YXja7dL
kQIDAQAB
-----END PUBLIC KEY-----
**************************************************************
* PatchSolution0 *
**************************************************************
@+0x024a7db8
Previous:
-0x0000000000000008 2d 2d 2d 2d 2d 42 45 47 -----BEG
+0x0000000000000008 49 4e 20 50 55 42 4c 49 43 20 4b 45 59 2d 2d 2d IN PUBLIC KEY---
+0x0000000000000018 2d 2d 00 4d 49 49 42 49 6a 41 4e 42 67 6b 71 68 --.MIIBIjANBgkqh
+0x0000000000000028 6b 69 47 39 77 30 42 41 51 45 46 41 41 4f 43 41 kiG9w0BAQEFAAOCA
...
...
...
After:
-0x0000000000000008 2d 2d 2d 2d 2d 42 45 47 -----BEG
+0x0000000000000008 49 4e 20 50 55 42 4c 49 43 20 4b 45 59 2d 2d 2d IN PUBLIC KEY---
+0x0000000000000018 2d 2d 00 4d 49 49 42 49 6a 41 4e 42 67 6b 71 68 --.MIIBIjANBgkqh
+0x0000000000000028 6b 69 47 39 77 30 42 41 51 45 46 41 41 4f 43 41 kiG9w0BAQEFAAOCA
...
...
...
**************************************************************
* PatchSolution2 *
**************************************************************
@+0x0263fd60
Previous:
+0x0000000000000000 42 49 6a 57 79 6f 65 52 52 30 4e 42 67 6b 71 6e BIjWyoeRR0NBgkqn
+0x0000000000000010 44 5a 57 78 43 67 4b 43 45 41 77 31 64 71 46 33 DZWxCgKCEAw1dqF3
+0x0000000000000020 44 54 76 4f 42 39 31 5a 48 77 65 63 4a 59 46 72 DTvOB91ZHwecJYFr
+0x0000000000000030 64 4d 31 4b 45 68 31 79 56 65 52 6f 47 71 53 64 dM1KEh1yVeRoGqSd
+0x0000000000000040 4c 4c 47 5a 47 55 6c 6e 67 69 67 33 4f 44 35 6d LLGZGUlngig3OD5m
...
...
...
@+0x00ec9868
Previous:
-0x0000000000000008 55 48 89 e5 41 57 41 56 UH..AWAV
+0x0000000000000008 53 48 83 ec 38 49 89 fe c6 45 e5 01 31 c0 88 45 SH..8I...E..1..E
+0x0000000000000018 e6 88 45 e7 48 8d 35 c5 70 61 01 48 8d 5d b0 48 ..E.H.5.pa.H.].H
+0x0000000000000028 89 df e8 49 d9 ff ff 48 8d 35 ef ed 60 01 48 89 ...I...H.5..`.H.
+0x0000000000000038 df e8 80 1e 28 01 e8 3f f4 00 00 88 45 e5 e8 b7 ....(..?....E...
+0x0000000000000048 f4 00 00 88 45 e6 e8 2f f5 00 00 88 45 e7 f6 45 ....E../....E..E
After:
-0x0000000000000008 55 48 89 e5 41 57 41 56 UH..AWAV
+0x0000000000000008 53 48 83 ec 48 48 89 fb 48 31 c0 48 89 04 24 48 SH..HH..H1.H..$H
+0x0000000000000018 89 44 24 08 48 89 44 24 10 48 8d 3c 24 48 8d 35 .D$.H.D$.H.<$H.5
+0x0000000000000028 cc 64 77 01 e8 8d 1e 28 01 48 8b 04 24 48 89 03 .dw....(.H..$H..
+0x0000000000000038 48 8b 44 24 08 48 89 43 08 48 8b 44 24 10 48 89 H.D$.H.C.H.D$.H.
+0x0000000000000048 43 10 48 89 d8 48 83 c4 48 5b 41 5e 41 5f 5d c3 C.H..H..H[A^A_].
[+] PatchSolution0 has been applied.
[+] PatchSolution2 has been applied.
**************************************************************
* Patch has been done successfully. Have fun and enjoy~~ *
* DO NOT FORGET TO SIGN NAVICAT BY YOUR CERTIFICATE!!! *
**************************************************************
```
* __仅对 Navicat Premium 版本 < 12.0.24 的说明:__
如果你的Navicat版本小于12.0.24,那么`navicat-patcher`将会终止并且不会修改目标文件。
你必须使用openssl生成`RegPrivateKey.pem`和`rpk`文件:
```console
$ openssl genrsa -out RegPrivateKey.pem 2048
$ openssl rsa -in RegPrivateKey.pem -pubout -out rpk
```
接着用刚生成的`rpk`文件替换
```
/Applications/Navicat Premium.app/Contents/Resources/rpk
```
5. __生成一份自签名的代码证书,并总是信任该证书。这一步非常重要。__
__然后用`codesign`对`Navicat Premium.app`重签名。__
```console
$ codesign -f -s "Your self-signed code-sign certificate name" <path to Navicat Premium.app>
```
__注意:__
"Your self-signed code-sign certificate name"是你证书的名字,不是路径。
__例如:__
```console
$ codesign -f -s "foobar" /Applications/Navicat\ Premium.app/
```
6. 接下来使用`navicat-keygen`来生成 __序列号__ 和 __激活码__。
```
Usage:
navicat-keygen <RSA-2048 Private Key File>
<RSA-2048 Private Key File> Path to a PEM-format RSA-2048 private key file.
This parameter must be specified.
```
* `<RSA-2048 Private Key File>`: PEM格式的RSA-2048私钥文件路径。
__这个参数必须指定。__
__例如:__
```console
$ ./navicat-keygen ./RegPrivateKey.pem
```
你会被要求选择Navicat的语言以及输入主版本号。之后会随机生成一个 __序列号__。
```console
$ ./navicat-keygen ./RegPrivateKey.pem
***************************************************
* Navicat Keygen by @DoubleLabyrinth *
* Version: 4.0 *
***************************************************
Which is your Navicat Premium language?
0. English
1. Simplified Chinese
2. Traditional Chinese
3. Japanese
4. Polish
5. Spanish
6. French
7. German
8. Korean
9. Russian
10. Portuguese
(Input index)> 1
(Input major version number, range: 0 ~ 15, default: 12)> 12
Serial number:
NAVG-Z5H9-NK2L-MAZJ
Your name:
```
你可以使用这个 __序列号__ 暂时激活Navicat。
接下来你会被要求输入`用户名`和`组织名`;请随便填写,但不要太长。
```console
Your name: DoubleLabyrinth
Your organization: DoubleLabyrinth
Input request code (in Base64), input empty line to end:
```
之后你会被要求填入请求码。注意 __不要关闭注册机__。
7. __断开网络__ 并打开Navicat。
找到`注册`窗口,填入注册机给你的序列号。然后点击`激活`按钮。
8. 一般来说在线激活肯定会失败,这时候Navicat会询问你是否`手动激活`,直接选吧。
9. 在`手动激活`窗口你会得到一个请求码,复制它并把它粘贴到keygen里。最后别忘了连按至少两下回车结束输入。
```console
Your name: DoubleLabyrinth
Your organization: DoubleLabyrinth
Input request code (in Base64), input empty line to end:
Nuk6pouXNhuGnqb2rBbxpDOiCFxhdJF4/gteYA/UZFUwqmhhphn3PAErvlxCtbUCf9Lzw02gfIFog3gmTB1C5JzPdeE5uuD6SAvhlQ7ZVOmdA66dvt6mDDpuf78cGio1Rpkd0D/6dLzgHnFJJPOfPtlIT5ZOLDiWkiSJm8d83+ckMBoMtcvpXCiwDIGb1KfVZwsgLojyrrO5OzakIzd2xQ8r3mEmbVbMl/zD0S5fO4agxEOp2WvpmM1cqom9Egll7kgcQG8A0z1Abqo1PrVBjjOsb/v8wy5V/469G6/uDT4AkZQSz8m/TX9ZQlZE3QBlzrJ+sTEkpMVhw3h3u6l4JQ==
Request Info:
{"K":"NAVGZ5H9NK2LMAZJ", "DI":"NGVlZjdjOTViMzYyMWI0", "P":"MAC"}
Response Info:
{"K":"NAVGZ5H9NK2LMAZJ","DI":"NGVlZjdjOTViMzYyMWI0","N":"DoubleLabyrinth","O":"DoubleLabyrinth","T":1564415636}
License:
Vd4QUzEw6DPNpJLYVKV6ZNDny0gsZWCXbKyrf2nF27iTM35YUBouXEcAB/Vy355V2z++7iXe/coKmV4kNZbywlBchI5ts7gOHnhXWzBYQ3yKsBYKob/7sxaiw7CXCmhM4mPLMzrp5okewCWjBjb51keZ4SA3F6j8HGIVYiZW3CAZtkjxs9uUoXvVIJr+Gt83TgU+sqiC4oSplokopAql2zWPieA9KuhPoCKiGLMvuQwv0wWWPc2HorY0AHAetsyZ8MN4utZ2ylQ9z/ZojwX1KViyh3xxnjWF7xXJljIdBA4tCi4QDqDLvTuICfUV7VeKzOUY+ZKCO0xGxkTe1HVwog==
```
10. 如果不出意外,你会得到一个看似用Base64编码的激活码。
直接复制它,并把它粘贴到Navicat的`手动激活`窗口,最后点`激活`按钮。
如果没什么意外的话应该能成功激活。
+53
View File
@@ -0,0 +1,53 @@
#pragma once
#include <stddef.h> // NOLINT
#include <stdint.h> // NOLINT
namespace nkg {
class Exception {
private:
const char* pvt_File;
const char* pvt_Message;
size_t pvt_Line;
public:
Exception(const char* File, size_t Line, const char* Message) noexcept :
pvt_File(File),
pvt_Message(Message),
pvt_Line(Line) {}
[[nodiscard]]
const char* File() const noexcept {
return pvt_File;
}
[[nodiscard]]
size_t Line() const noexcept {
return pvt_Line;
}
[[nodiscard]]
const char* Message() const noexcept {
return pvt_Message;
}
[[nodiscard]]
virtual bool HasErrorCode() const noexcept {
return false;
}
[[nodiscard]]
virtual intptr_t ErrorCode() const noexcept {
return 0;
}
[[nodiscard]]
virtual const char* ErrorString() const noexcept {
return nullptr;
}
};
}
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include <openssl/err.h>
#include "Exception.hpp"
namespace nkg {
class OpensslError final : public Exception {
private:
unsigned long pvt_ErrorCode;
public:
OpensslError(const char* File, unsigned Line, unsigned long ErrorCode, const char* Message) noexcept :
Exception(File, Line, Message),
pvt_ErrorCode(ErrorCode) {}
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual bool HasErrorCode() const noexcept override {
return true;
}
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual intptr_t ErrorCode() const noexcept override {
return pvt_ErrorCode;
}
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual const char* ErrorString() const noexcept override {
ERR_load_crypto_strings();
return ERR_reason_error_string(pvt_ErrorCode);
}
};
}
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include "Exception.hpp"
#include <string.h> // NOLINT
namespace nkg {
class SystemError final : public Exception {
private:
int pvt_ErrorCode;
public:
SystemError(const char* File, unsigned Line, int ErrorCode, const char* Message) noexcept :
Exception(File, Line, Message),
pvt_ErrorCode(ErrorCode) {}
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual bool HasErrorCode() const noexcept override {
return true;
}
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual intptr_t ErrorCode() const noexcept override {
return pvt_ErrorCode;
}
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual const char* ErrorString() const noexcept override {
return strerror(pvt_ErrorCode);
}
};
}
+270
View File
@@ -0,0 +1,270 @@
#pragma once
#include <openssl/opensslv.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/rsa.h>
#include <string>
#include "ExceptionOpenssl.hpp"
#include "ResourceOwned.hpp"
#include "ResourceTraitsOpenssl.hpp"
enum class RSAKeyType {
PrivateKey,
PublicKey
};
enum class RSAKeyFormat {
PEM,
PKCS1
};
class RSACipher {
private:
ResourceOwned<OpensslRSATraits> pvt_RsaObj;
template<RSAKeyType __Type, RSAKeyFormat __Format>
static void pvt_WriteRSAToBIO(RSA* lpRSA, BIO* lpBIO) {
if constexpr (__Type == RSAKeyType::PrivateKey) {
if (PEM_write_bio_RSAPrivateKey(lpBIO, lpRSA, nullptr, nullptr, 0, nullptr, nullptr) == 0) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "PEM_write_bio_RSAPrivateKey failed.");
}
} else {
if constexpr (__Format == RSAKeyFormat::PEM) {
if (PEM_write_bio_RSA_PUBKEY(lpBIO, lpRSA) == 0) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "PEM_write_bio_RSA_PUBKEY failed.");
}
} else if constexpr (__Format == RSAKeyFormat::PKCS1) {
if (PEM_write_bio_RSAPublicKey(lpBIO, lpRSA) == 0) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "PEM_write_bio_RSAPublicKey failed.");
}
} else {
static_assert(__Format == RSAKeyFormat::PEM || __Format == RSAKeyFormat::PKCS1);
__builtin_unreachable();
}
}
}
template<RSAKeyType _Type, RSAKeyFormat _Format>
[[nodiscard]]
static RSA* pvt_ReadRSAFromBIO(BIO* lpBIO) {
RSA* lpRSA;
if constexpr (_Type == RSAKeyType::PrivateKey) {
lpRSA = PEM_read_bio_RSAPrivateKey(lpBIO, nullptr, nullptr, nullptr);
if (lpRSA == nullptr) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "PEM_read_bio_RSAPrivateKey failed.");
}
} else {
if constexpr (_Format == RSAKeyFormat::PEM) {
lpRSA = PEM_read_bio_RSA_PUBKEY(lpBIO, nullptr, nullptr, nullptr);
if (lpRSA == nullptr) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, " -> PEM_read_bio_RSA_PUBKEY failed.");
}
} else if constexpr (_Format == RSAKeyFormat::PKCS1) {
lpRSA = PEM_read_bio_RSAPublicKey(lpBIO, nullptr, nullptr, nullptr);
if (lpRSA == nullptr) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "PEM_read_bio_RSAPublicKey failed.");
}
} else {
static_assert(_Format == RSAKeyFormat::PEM || _Format == RSAKeyFormat::PKCS1);
__builtin_unreachable();
}
}
return lpRSA;
}
public:
RSACipher() : pvt_RsaObj(OpensslRSATraits{}, RSA_new()) {
if (pvt_RsaObj.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_new failed.");
}
}
[[nodiscard]]
size_t Bits() const {
#if (OPENSSL_VERSION_NUMBER & 0xffff0000) == 0x10000000 // openssl 1.0.x
if (pvt_RsaObj->n == nullptr) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "RSA modulus has not been set.");
} else {
return BN_num_bits(pvt_RsaObj->n);
}
#elif (OPENSSL_VERSION_NUMBER & 0xffff0000) == 0x10100000 // openssl 1.1.x
return RSA_bits(pvt_RsaObj);
#else
#error "Unexpected openssl version!"
#endif
}
void GenerateKey(int bits, unsigned int e = RSA_F4) {
ResourceOwned bn_e(OpensslBNTraits{}, BN_new());
if (bn_e.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::OpensslError(__FILE__, __LINE__, ERR_get_error(), "BN_new failed.");
}
if (!BN_set_word(bn_e, e)) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "BN_set_word failed.");
}
if (!RSA_generate_key_ex(pvt_RsaObj, bits, bn_e, nullptr)) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_generate_key_ex failed.");
}
}
template<RSAKeyType __Type, RSAKeyFormat __Format>
void ExportKeyToFile(const std::string& FileName) const {
ResourceOwned BioFile(OpensslBIOTraits{}, BIO_new_file(FileName.c_str(), "w"));
if (BioFile.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "BIO_new_file failed.");
}
pvt_WriteRSAToBIO<__Type, __Format>(pvt_RsaObj, BioFile);
}
template<RSAKeyType __Type, RSAKeyFormat __Format>
[[nodiscard]]
std::string ExportKeyString() const {
ResourceOwned BioMemory(OpensslBIOTraits{}, BIO_new(BIO_s_mem()));
long StringLength;
const char* StringChars = nullptr;
if (BioMemory.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "BIO_new failed.");
}
pvt_WriteRSAToBIO<__Type, __Format>(pvt_RsaObj, BioMemory);
StringLength = BIO_get_mem_data(BioMemory, &StringChars);
return std::string(StringChars, StringLength);
}
template<RSAKeyType __Type, RSAKeyFormat __Format>
void ImportKeyFromFile(const std::string& FileName) {
ResourceOwned BioFile(OpensslBIOTraits{}, BIO_new_file(FileName.c_str(), "r"));
if (BioFile.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "BIO_new_file failed.");
}
pvt_RsaObj.TakeOver(pvt_ReadRSAFromBIO<__Type, __Format>(BioFile));
}
template<RSAKeyType __Type, RSAKeyFormat __Format>
void ImportKeyString(const std::string& KeyString) {
ResourceOwned BioMemory(OpensslBIOTraits{}, BIO_new(BIO_s_mem()));
RSA* NewRsaObj;
if (BioMemory.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "BIO_new failed.");
}
if (BIO_puts(BioMemory, KeyString.c_str()) <= 0) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "BIO_puts failed.");
}
pvt_RsaObj.TakeOver(pvt_ReadRSAFromBIO<__Type, __Format>(BioMemory));
}
template<RSAKeyType __Type = RSAKeyType::PublicKey>
size_t Encrypt(const void* lpFrom, size_t cbFrom, void* lpTo, int Padding) const {
int BytesWritten;
if (cbFrom > INT_MAX) {
// NOLINTNEXTLINE: allow exceptions that is not derived lpFrom std::exception
throw nkg::Exception(__FILE__, __LINE__, "Length overflowed.");
}
if constexpr (__Type == RSAKeyType::PrivateKey) {
BytesWritten = RSA_private_encrypt(
static_cast<int>(cbFrom),
reinterpret_cast<const unsigned char*>(lpFrom),
reinterpret_cast<unsigned char*>(lpTo),
pvt_RsaObj,
Padding
);
if (BytesWritten == -1) {
// NOLINTNEXTLINE: allow exceptions that is not derived lpFrom std::exception
throw nkg::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_private_encrypt failed.");
}
} else {
BytesWritten = RSA_public_encrypt(
static_cast<int>(cbFrom),
reinterpret_cast<const unsigned char*>(lpFrom),
reinterpret_cast<unsigned char*>(lpTo),
pvt_RsaObj,
Padding
);
if (BytesWritten == -1) {
// NOLINTNEXTLINE: allow exceptions that is not derived lpFrom std::exception
throw nkg::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_public_encrypt failed.");
}
}
return BytesWritten;
}
template<RSAKeyType __Type = RSAKeyType::PrivateKey>
size_t Decrypt(const void* lpFrom, int cbFrom, void* lpTo, int Padding) const {
int BytesWritten;
if (cbFrom > INT_MAX) {
// NOLINTNEXTLINE: allow exceptions that is not derived lpFrom std::exception
throw nkg::Exception(__FILE__, __LINE__, "Length overflowed.");
}
if constexpr (__Type == RSAKeyType::PrivateKey) {
BytesWritten = RSA_private_decrypt(
cbFrom,
reinterpret_cast<const unsigned char*>(lpFrom),
reinterpret_cast<unsigned char*>(lpTo),
pvt_RsaObj,
Padding
);
if (BytesWritten == -1) {
// NOLINTNEXTLINE: allow exceptions that is not derived lpFrom std::exception
throw nkg::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_private_decrypt failed.");
}
} else {
BytesWritten = RSA_public_decrypt(
cbFrom,
reinterpret_cast<const unsigned char*>(lpFrom),
reinterpret_cast<unsigned char*>(lpTo),
pvt_RsaObj,
Padding
);
if (BytesWritten == -1) {
// NOLINTNEXTLINE: allow exceptions that is not derived lpFrom std::exception
throw nkg::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_public_decrypt failed.");
}
}
return BytesWritten;
}
};
+304
View File
@@ -0,0 +1,304 @@
#pragma once
#include <type_traits>
#include <utility>
template<typename __ResourceTraits, typename __LambdaReleasor = void>
class ResourceOwned {
private:
using __HandleType = typename __ResourceTraits::HandleType;
static_assert(std::is_pod_v<__HandleType>);
__HandleType pvt_Handle;
__LambdaReleasor pvt_Releasor;
public:
//
// Construct from custom releasor.
// ``pvt_Handle` will be set to an invalid value.
//
ResourceOwned(__ResourceTraits, __LambdaReleasor&& Releasor) noexcept :
pvt_Handle(__ResourceTraits::InvalidValue),
pvt_Releasor(std::forward<__LambdaReleasor>(Releasor)) {}
//
// Construct from handle given and custom releasor.
//
ResourceOwned(__ResourceTraits, const __HandleType& Handle, __LambdaReleasor&& Releasor) noexcept :
pvt_Handle(Handle),
pvt_Releasor(std::forward<__LambdaReleasor>(Releasor)) {}
//
// ResourceOwned doesn't allow to copy.
// Because it takes `pvt_Handle` exclusively.
//
ResourceOwned(const ResourceOwned<__ResourceTraits, __LambdaReleasor>& Other) = delete;
//
// ResourceOwned allows to move.
//
ResourceOwned(ResourceOwned<__ResourceTraits, __LambdaReleasor>&& Other) noexcept :
pvt_Handle(Other.pvt_Handle),
pvt_Releasor(std::move(Other.pvt_Releasor))
{
Other.pvt_Handle = __ResourceTraits::InvalidValue;
}
//
// ResourceOwned doesn't allow to copy.
// Because it takes `pvt_Handle` exclusively.
//
ResourceOwned<__ResourceTraits, __LambdaReleasor>&
operator=(const ResourceOwned<__ResourceTraits, __LambdaReleasor>& Other) = delete;
//
// ResourceOwned allows to move.
//
ResourceOwned<__ResourceTraits, __LambdaReleasor>&
operator=(ResourceOwned<__ResourceTraits, __LambdaReleasor>&& Other) noexcept {
this->pvt_Handle = Other.pvt_Handle;
this->pvt_Releasor = std::move(Other.pvt_Releasor);
Other.pvt_Handle = __ResourceTraits::InvalidValue;
return *this;
}
[[nodiscard]]
operator const __HandleType&() const noexcept { // NOLINT: Allow implicit conversion.
return this->pvt_Handle;
}
template<typename __AsType, bool __IsPointer = std::is_pointer_v<__HandleType>, typename = std::enable_if_t<__IsPointer>>
[[nodiscard]]
__AsType As() const noexcept {
return reinterpret_cast<__AsType>(this->pvt_Handle);
}
template<bool __IsPointer = std::is_pointer_v<__HandleType>, typename = typename std::enable_if_t<__IsPointer>>
[[nodiscard]]
__HandleType operator->() const noexcept {
return this->pvt_Handle;
}
[[nodiscard]]
bool IsValid() const noexcept {
return __ResourceTraits::IsValid(this->pvt_Handle);
}
[[nodiscard]]
const __HandleType& Get() const noexcept {
return this->pvt_Handle;
}
template<typename __ReturnType = __HandleType*>
[[nodiscard]]
__ReturnType GetAddress() noexcept {
return reinterpret_cast<__ReturnType>(&this->pvt_Handle);
}
void TakeOver(const __HandleType& Handle) {
if (__ResourceTraits::IsValid(this->pvt_Handle) == true) {
this->pvt_Releasor(this->pvt_Handle);
}
this->pvt_Handle = Handle;
}
void Discard() noexcept {
this->pvt_Handle = __ResourceTraits::InvalidValue;
}
[[nodiscard]]
__HandleType Transfer() noexcept {
__HandleType t = this->pvt_Handle;
this->pvt_Handle = __ResourceTraits::InvalidValue;
return t;
}
void Release() {
if (__ResourceTraits::IsValid(this->pvt_Handle)) {
this->pvt_Releasor(this->pvt_Handle);
this->pvt_Handle = __ResourceTraits::InvalidValue;
}
}
~ResourceOwned() {
if (__ResourceTraits::IsValid(this->pvt_Handle)) {
this->pvt_Releasor(this->pvt_Handle);
this->pvt_Handle = __ResourceTraits::InvalidValue;
}
}
};
template<typename __ResourceTraits>
class ResourceOwned<__ResourceTraits, void> {
private:
using __HandleType = typename __ResourceTraits::HandleType;
static_assert(std::is_pod_v<__HandleType>);
__HandleType pvt_Handle;
public:
//
// Construct from custom releasor.
// ``pvt_Handle` will be set to an invalid value.
//
explicit
ResourceOwned(__ResourceTraits) noexcept :
pvt_Handle(__ResourceTraits::InvalidValue) {}
//
// Construct from handle given and custom releasor.
//
ResourceOwned(__ResourceTraits, const __HandleType& Handle) noexcept :
pvt_Handle(Handle) {}
//
// ResourceOwned doesn't allow to copy.
// Because it takes `pvt_Handle` exclusively.
//
ResourceOwned(const ResourceOwned<__ResourceTraits, void>& Other) = delete;
//
// ResourceOwned allows to move.
//
ResourceOwned(ResourceOwned<__ResourceTraits, void>&& Other) noexcept :
pvt_Handle(Other.pvt_Handle)
{
Other.pvt_Handle = __ResourceTraits::InvalidValue;
}
//
// ResourceOwned doesn't allow to copy.
// Because it takes `pvt_Handle` exclusively.
//
ResourceOwned<__ResourceTraits, void>&
operator=(const ResourceOwned<__ResourceTraits, void>& Other) = delete;
//
// ResourceOwned allows to move.
//
ResourceOwned<__ResourceTraits, void>&
operator=(ResourceOwned<__ResourceTraits, void>&& Other) noexcept {
this->pvt_Handle = Other.pvt_Handle;
Other.pvt_Handle = __ResourceTraits::InvalidValue;
return *this;
}
[[nodiscard]]
operator const __HandleType&() const noexcept { // NOLINT: Allow implicit conversion.
return this->pvt_Handle;
}
template<typename __AsType, bool __IsPointer = std::is_pointer_v<__HandleType>, typename = typename std::enable_if_t<__IsPointer>>
[[nodiscard]]
__AsType As() const noexcept {
return reinterpret_cast<__AsType>(this->pvt_Handle);
}
template<bool __IsPointer = std::is_pointer_v<__HandleType>, typename = typename std::enable_if_t<__IsPointer>>
[[nodiscard]]
__HandleType operator->() const noexcept {
return this->pvt_Handle;
}
[[nodiscard]]
bool IsValid() const noexcept {
return __ResourceTraits::IsValid(this->pvt_Handle);
}
[[nodiscard]]
const __HandleType& Get() const noexcept {
return this->pvt_Handle;
}
template<typename __ReturnType = __HandleType*>
[[nodiscard]]
__ReturnType GetAddress() noexcept {
return reinterpret_cast<__ReturnType>(&this->pvt_Handle);
}
void TakeOver(const __HandleType& Handle) {
if (__ResourceTraits::IsValid(this->pvt_Handle) == true) {
__ResourceTraits::Releasor(this->pvt_Handle);
}
this->pvt_Handle = Handle;
}
void Discard() noexcept {
this->pvt_Handle = __ResourceTraits::InvalidValue;
}
[[nodiscard]]
__HandleType Transfer() noexcept {
__HandleType t = this->pvt_Handle;
this->pvt_Handle = __ResourceTraits::InvalidValue;
return t;
}
void Release() {
if (__ResourceTraits::IsValid(this->pvt_Handle)) {
__ResourceTraits::Releasor(this->pvt_Handle);
this->pvt_Handle = __ResourceTraits::InvalidValue;
}
}
~ResourceOwned() {
if (__ResourceTraits::IsValid(this->pvt_Handle)) {
__ResourceTraits::Releasor(this->pvt_Handle);
this->pvt_Handle = __ResourceTraits::InvalidValue;
}
}
};
template<typename __ResourceTraits>
ResourceOwned(__ResourceTraits) ->
ResourceOwned<__ResourceTraits, void>;
template<typename __ResourceTraits, typename __ArgType>
ResourceOwned(__ResourceTraits, __ArgType&&) ->
ResourceOwned<
__ResourceTraits,
std::conditional_t<
std::is_same_v<std::remove_cv_t<std::remove_reference_t<__ArgType>>, typename __ResourceTraits::HandleType> == false,
std::remove_reference_t<__ArgType>,
void
>
>;
template<typename __ResourceTraits, typename __LambdaReleasor>
ResourceOwned(__ResourceTraits, const typename __ResourceTraits::HandleType&, __LambdaReleasor&&) ->
ResourceOwned<__ResourceTraits, std::remove_reference_t<__LambdaReleasor>>;
template<typename __ClassType>
struct CppObjectTraits {
using HandleType = __ClassType*;
static inline const HandleType InvalidValue = nullptr;
[[nodiscard]]
static bool IsValid(const HandleType& Handle) noexcept {
return Handle != InvalidValue;
}
static void Releasor(const HandleType& Handle) {
delete Handle;
}
};
template<typename __ClassType>
struct CppDynamicArrayTraits {
using HandleType = __ClassType*;
static inline const HandleType InvalidValue = nullptr;
[[nodiscard]]
static bool IsValid(const HandleType& Handle) noexcept {
return Handle != InvalidValue;
}
static void Releasor(const HandleType& Handle) {
delete[] Handle;
}
};
+64
View File
@@ -0,0 +1,64 @@
#pragma once
#include <openssl/bio.h>
#include <openssl/rsa.h>
struct OpensslBIOTraits {
using HandleType = BIO*;
static inline const HandleType InvalidValue = nullptr;
[[nodiscard]]
static bool IsValid(const HandleType& Handle) noexcept {
return Handle != InvalidValue;
}
static void Releasor(const HandleType& Handle) noexcept {
BIO_free(Handle);
}
};
struct OpensslBIOChainTraits {
using HandleType = BIO*;
static inline const HandleType InvalidValue = nullptr;
[[nodiscard]]
static bool IsValid(const HandleType& Handle) noexcept {
return Handle != InvalidValue;
}
static void Releasor(const HandleType& Handle) noexcept {
BIO_free_all(Handle);
}
};
struct OpensslBNTraits {
using HandleType = BIGNUM*;
static inline const HandleType InvalidValue = nullptr;
[[nodiscard]]
static bool IsValid(const HandleType& Handle) noexcept {
return Handle != InvalidValue;
}
static void Releasor(const HandleType& Handle) noexcept {
BN_free(Handle);
}
};
struct OpensslRSATraits {
using HandleType = RSA*;
static inline const HandleType InvalidValue = nullptr;
[[nodiscard]]
static bool IsValid(const HandleType& Handle) noexcept {
return Handle != InvalidValue;
}
static void Releasor(const HandleType& Handle) noexcept {
RSA_free(Handle);
}
};
-38
View File
@@ -1,38 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "navicat-keygen", "navicat-keygen\navicat-keygen.vcxproj", "{CB49F054-83AB-4C16-B73B-33D7DF696E16}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "navicat-patcher", "navicat-patcher\navicat-patcher.vcxproj", "{30BE8CAB-6137-4441-9F64-599D0A6EEA0C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CB49F054-83AB-4C16-B73B-33D7DF696E16}.Debug|x64.ActiveCfg = Debug|x64
{CB49F054-83AB-4C16-B73B-33D7DF696E16}.Debug|x64.Build.0 = Debug|x64
{CB49F054-83AB-4C16-B73B-33D7DF696E16}.Debug|x86.ActiveCfg = Debug|Win32
{CB49F054-83AB-4C16-B73B-33D7DF696E16}.Debug|x86.Build.0 = Debug|Win32
{CB49F054-83AB-4C16-B73B-33D7DF696E16}.Release|x64.ActiveCfg = Release|x64
{CB49F054-83AB-4C16-B73B-33D7DF696E16}.Release|x64.Build.0 = Release|x64
{CB49F054-83AB-4C16-B73B-33D7DF696E16}.Release|x86.ActiveCfg = Release|Win32
{CB49F054-83AB-4C16-B73B-33D7DF696E16}.Release|x86.Build.0 = Release|Win32
{30BE8CAB-6137-4441-9F64-599D0A6EEA0C}.Debug|x64.ActiveCfg = Debug|x64
{30BE8CAB-6137-4441-9F64-599D0A6EEA0C}.Debug|x64.Build.0 = Debug|x64
{30BE8CAB-6137-4441-9F64-599D0A6EEA0C}.Debug|x86.ActiveCfg = Debug|Win32
{30BE8CAB-6137-4441-9F64-599D0A6EEA0C}.Debug|x86.Build.0 = Debug|Win32
{30BE8CAB-6137-4441-9F64-599D0A6EEA0C}.Release|x64.ActiveCfg = Release|x64
{30BE8CAB-6137-4441-9F64-599D0A6EEA0C}.Release|x64.Build.0 = Release|x64
{30BE8CAB-6137-4441-9F64-599D0A6EEA0C}.Release|x86.ActiveCfg = Release|Win32
{30BE8CAB-6137-4441-9F64-599D0A6EEA0C}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
+66
View File
@@ -0,0 +1,66 @@
#include <vector>
#include <string>
#include <openssl/evp.h>
#include "../common/Exception.hpp"
#include "../common/ResourceOwned.hpp"
#include "../common/ResourceTraitsOpenssl.hpp"
std::string base64_encode(const std::vector<uint8_t>& bindata) {
ResourceOwned b64(OpensslBIOTraits{}, BIO_new(BIO_f_base64()));
if (b64.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "BIO_new failed.");
}
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
ResourceOwned mem(OpensslBIOTraits{}, BIO_new(BIO_s_mem()));
if (mem.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "BIO_new failed.");
}
BIO_push(b64, mem);
if (BIO_write(b64, bindata.data(), bindata.size()) != bindata.size()) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "BIO_write failed.");
}
if (BIO_flush(b64) != 1) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "BIO_flush failed.");
}
const char* data = nullptr;
auto len = BIO_get_mem_data(mem, &data);
BIO_pop(b64);
return std::string(data, len);
}
std::vector<uint8_t> base64_decode(const std::string& ascdata) {
ResourceOwned b64(OpensslBIOTraits{}, BIO_new(BIO_f_base64()));
if (b64.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "BIO_new failed.");
}
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
ResourceOwned mem(OpensslBIOTraits{}, BIO_new_mem_buf(ascdata.c_str(), -1));
if (mem.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "BIO_new failed.");
}
BIO_push(b64, mem);
std::vector<uint8_t> bindata(ascdata.length() / 4 * 3 + 1);
bindata.resize(BIO_read(b64, bindata.data(), bindata.size()));
BIO_pop(b64);
return bindata;
}
+41
View File
@@ -0,0 +1,41 @@
#pragma once
#include <openssl/crypto.h>
#include <openssl/des.h>
#include <memory.h>
class DESCipher {
private:
DES_cblock _Key;
DES_key_schedule _Schedule;
public:
DESCipher() noexcept : _Key{}, _Schedule{} {}
void SetKey(const void* pKey) noexcept {
memcpy(&_Key, pKey, sizeof(_Key));
DES_set_odd_parity(&_Key);
DES_set_key(&_Key, &_Schedule);
}
void Clear() noexcept {
OPENSSL_cleanse(&_Key, sizeof(_Key));
OPENSSL_cleanse(&_Schedule, sizeof(_Schedule));
}
void EncryptBlock(void* lpBuffer) noexcept {
DES_cblock block;
DES_ecb_encrypt(reinterpret_cast<const_DES_cblock*>(lpBuffer), &block, &_Schedule, DES_ENCRYPT);
memcpy(lpBuffer, &block, sizeof(block));
}
void DecryptBlock(void* lpBuffer) noexcept {
DES_cblock block;
DES_ecb_encrypt(reinterpret_cast<const_DES_cblock*>(lpBuffer), &block, &_Schedule, DES_DECRYPT);
memcpy(lpBuffer, &block, sizeof(block));
}
~DESCipher() noexcept {
Clear();
}
};
+195
View File
@@ -0,0 +1,195 @@
#pragma once
#include <string>
#include <random>
#include "DESCipher.hpp"
class NavicatKeygen {
public:
enum class Language {
English,
SimplifiedChinese,
TraditionalChinese,
Japanese,
Polish,
Spanish,
French,
German,
Korean,
Russian,
Portuguese
};
enum class Product {
DataModeler,
Premium,
MySQL,
PostgreSQL,
Oracle,
SQLServer,
SQLite,
MariaDB,
MongoDB,
ReportViewer
};
private:
std::random_device rand_dev;
std::default_random_engine rand_eng;
std::uniform_int_distribution<int> rand;
uint8_t data[10];
public:
NavicatKeygen() : rand_eng(rand_dev()), rand(0, UINT8_MAX), data{} {
data[0] = 0x68;
data[1] = 0x2A;
}
void SetLanguageSignature(Language _language) {
switch (_language) {
case Language::English:
data[5] = 0xAC; // Must be 0xAC for English version.
data[6] = 0x88; // Must be 0x88 for English version.
break;
case Language::SimplifiedChinese:
data[5] = 0xCE; // Must be 0xCE for Simplified Chinese version.
data[6] = 0x32; // Must be 0x32 for Simplified Chinese version.
break;
case Language::TraditionalChinese:
data[5] = 0xAA; // Must be 0xAA for Traditional Chinese version.
data[6] = 0x99; // Must be 0x99 for Traditional Chinese version.
break;
case Language::Japanese:
data[5] = 0xAD; // Must be 0xAD for Japanese version. Discoverer: @dragonflylee
data[6] = 0x82; // Must be 0x82 for Japanese version. Discoverer: @dragonflylee
break;
case Language::Polish:
data[5] = 0xBB; // Must be 0xBB for Polish version. Discoverer: @dragonflylee
data[6] = 0x55; // Must be 0x55 for Polish version. Discoverer: @dragonflylee
break;
case Language::Spanish:
data[5] = 0xAE; // Must be 0xAE for Spanish version. Discoverer: @dragonflylee
data[6] = 0x10; // Must be 0x10 for Spanish version. Discoverer: @dragonflylee
break;
case Language::French:
data[5] = 0xFA; // Must be 0xFA for French version. Discoverer: @Deltafox79
data[6] = 0x20; // Must be 0x20 for French version. Discoverer: @Deltafox79
break;
case Language::German:
data[5] = 0xB1; // Must be 0xB1 for German version. Discoverer: @dragonflylee
data[6] = 0x60; // Must be 0x60 for German version. Discoverer: @dragonflylee
break;
case Language::Korean:
data[5] = 0xB5; // Must be 0xB5 for Korean version. Discoverer: @dragonflylee
data[6] = 0x60; // Must be 0x60 for Korean version. Discoverer: @dragonflylee
break;
case Language::Russian:
data[5] = 0xEE; // Must be 0xB5 for Russian version. Discoverer: @dragonflylee
data[6] = 0x16; // Must be 0x60 for Russian version. Discoverer: @dragonflylee
break;
case Language::Portuguese:
data[5] = 0xCD; // Must be 0xCD for Portuguese version. Discoverer: @dragonflylee
data[6] = 0x49; // Must be 0x49 for Portuguese version. Discoverer: @dragonflylee
break;
default:
break;
}
}
void SetLanguageSignature(uint8_t value0, uint8_t value1) {
data[5] = value0;
data[6] = value1;
}
void SetProductSignature(Product _product) {
switch (_product) {
case Product::DataModeler:
data[7] = 0x47;
break;
case Product::Premium:
data[7] = 0x65;
break;
case Product::MySQL:
data[7] = 0x68;
break;
case Product::PostgreSQL:
data[7] = 0x6C;
break;
case Product::Oracle:
data[7] = 0x70;
break;
case Product::SQLServer:
data[7] = 0x74;
break;
case Product::SQLite:
data[7] = 0x78;
break;
case Product::MariaDB:
data[7] = 0x7C;
break;
case Product::MongoDB:
data[7] = 0x80;
break;
case Product::ReportViewer:
data[7] = 0xb;
default:
break;
}
}
void SetProductSignature(uint8_t value) {
data[7] = value;
}
void SetVersion(uint8_t version) {
data[8] = version << 4;
}
void Generate() {
static uint8_t DESKey[] = { 0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27 };
DESCipher cipher;
data[2] = static_cast<uint8_t>(rand(rand_eng));
data[3] = static_cast<uint8_t>(rand(rand_eng));
data[4] = static_cast<uint8_t>(rand(rand_eng));
data[9] = 0x32;
cipher.SetKey(&DESKey);
cipher.EncryptBlock(data + 2);
}
std::string GetKey() const {
static const char EncodeTable[] = "ABCDEFGH8JKLMN9PQRSTUVWXYZ234567";
std::string Key;
Key.resize(16);
Key[0] = EncodeTable[data[0] >> 3];
Key[1] = EncodeTable[(data[0] & 0x07) << 2 | data[1] >> 6];
Key[2] = EncodeTable[data[1] >> 1 & 0x1F];
Key[3] = EncodeTable[(data[1] & 0x1) << 4 | data[2] >> 4];
Key[4] = EncodeTable[(data[2] & 0xF) << 1 | data[3] >> 7];
Key[5] = EncodeTable[data[3] >> 2 & 0x1F];
Key[6] = EncodeTable[(data[3] << 3 & 0x1F) | data[4] >> 5];
Key[7] = EncodeTable[data[4] & 0x1F];
Key[8] = EncodeTable[data[5] >> 3];
Key[9] = EncodeTable[(data[5] & 0x07) << 2 | data[6] >> 6];
Key[10] = EncodeTable[data[6] >> 1 & 0x1F];
Key[11] = EncodeTable[(data[6] & 0x1) << 4 | data[7] >> 4];
Key[12] = EncodeTable[(data[7] & 0xF) << 1 | data[8] >> 7];
Key[13] = EncodeTable[data[8] >> 2 & 0x1F];
Key[14] = EncodeTable[(data[8] << 3 & 0x1F) | data[9] >> 5];
Key[15] = EncodeTable[data[9] & 0x1F];
return Key;
}
std::string GetFormatedKey() const {
std::string Key = GetKey();
Key.insert(Key.begin() + 4, '-');
Key.insert(Key.begin() + 5 + 4, '-');
Key.insert(Key.begin() + 10 + 4, '-');
return Key;
}
};
-271
View File
@@ -1,271 +0,0 @@
#include <tchar.h>
#include <windows.h>
#include <wincrypt.h>
#ifndef UNICODE
#include <stdio.h>
#endif
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/des.h>
#pragma comment(lib, "Crypt32.lib")
#pragma comment(lib, "libcrypto.lib")
#define NAVICAT_12
void GenerateSnKey(char(&SnKey)[16]) {
static char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
static DES_cblock DESKey = { 0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27 };
BYTE temp_snKey[10] = { 0x68, 0x2a }; // must start with 0x68, 0x2a
temp_snKey[2] = rand();
temp_snKey[3] = rand();
temp_snKey[4] = rand();
temp_snKey[5] = 0xCE; // Must be 0xCE for Simplified Chinese version.
// Must be 0xAA for Traditional Chinese version.
temp_snKey[6] = 0x32; // Must be 0x32 for Simplified Chinese version.
// Must be 0x99 for Traditional Chinese version.
#if defined(NAVICAT_12)
temp_snKey[7] = 0x65; // 0x65 - commercial, 0x66 - non-commercial
temp_snKey[8] = 0xC0; // High 4-bits = version number. Low 4-bits doesn't know, but can be used to delay activation time.
#elif defined(NAVICAT_11)
temp_snKey[7] = 0x15; // 0x15 - commercial, 0x16 - non-commercial
temp_snKey[8] = 0xB0; // High 4-bits = version number. Low 4-bits doesn't know, but can be used to delay activation time.
#endif
temp_snKey[9] = 0x70; // 0xfd, 0xfc, 0xfb if you want to use not-for-resale license.
DES_key_schedule schedule;
DES_set_key_unchecked(&DESKey, &schedule);
DES_cblock enc_temp_snKey;
DES_ecb_encrypt(reinterpret_cast<const_DES_cblock*>(temp_snKey + 2), &enc_temp_snKey, &schedule, DES_ENCRYPT);
memmove_s(temp_snKey + 2, sizeof(enc_temp_snKey), enc_temp_snKey, sizeof(enc_temp_snKey));
SnKey[0] = EncodeTable[temp_snKey[0] >> 3];
SnKey[1] = EncodeTable[(temp_snKey[0] & 0x07) << 2 | temp_snKey[1] >> 6];
SnKey[2] = EncodeTable[temp_snKey[1] >> 1 & 0x1F];
SnKey[3] = EncodeTable[(temp_snKey[1] & 0x1) << 4 | temp_snKey[2] >> 4];
SnKey[4] = EncodeTable[(temp_snKey[2] & 0xF) << 1 | temp_snKey[3] >> 7];
SnKey[5] = EncodeTable[temp_snKey[3] >> 2 & 0x1F];
SnKey[6] = EncodeTable[temp_snKey[3] << 3 & 0x1F | temp_snKey[4] >> 5];
SnKey[7] = EncodeTable[temp_snKey[4] & 0x1F];
SnKey[8] = EncodeTable[temp_snKey[5] >> 3];
SnKey[9] = EncodeTable[(temp_snKey[5] & 0x07) << 2 | temp_snKey[6] >> 6];
SnKey[10] = EncodeTable[temp_snKey[6] >> 1 & 0x1F];
SnKey[11] = EncodeTable[(temp_snKey[6] & 0x1) << 4 | temp_snKey[7] >> 4];
SnKey[12] = EncodeTable[(temp_snKey[7] & 0xF) << 1 | temp_snKey[8] >> 7];
SnKey[13] = EncodeTable[temp_snKey[8] >> 2 & 0x1F];
SnKey[14] = EncodeTable[temp_snKey[8] << 3 & 0x1F | temp_snKey[9] >> 5];
SnKey[15] = EncodeTable[temp_snKey[9] & 0x1F];
_tprintf_s(TEXT("\r\n"));
_tprintf_s(TEXT("SnKey:\r\n"));
_tprintf_s(TEXT("%.4hs-%.4hs-%.4hs-%.4hs\r\n"), SnKey, SnKey + 4, SnKey + 8, SnKey + 12);
_tprintf_s(TEXT("\r\n"));
}
BOOL GenerateLicense(RSA* RSAPrivateKey,
const char* SnKey,
const char* Name,
const char* Organization,
const char* DI) {
char LicenseJson[2048 / 8] = { };
#if defined(NAVICAT_12)
sprintf_s(LicenseJson, "{\"K\":\"%.16s\", \"N\":\"%s\", \"O\":\"%s\", \"DI\":\"%s\"}", SnKey, Name, Organization, DI);
#elif defined(NAVICAT_11)
sprintf_s(LicenseJson, "{\"K\":\"%.16s\", \"N\":\"%s\", \"O\":\"%s\"}", SnKey, Name, Organization);
#endif
unsigned char License[2048 / 8] = { };
RSA_private_encrypt(strlen(LicenseJson),
reinterpret_cast<uint8_t*>(LicenseJson),
License,
RSAPrivateKey,
RSA_PKCS1_PADDING);
#if defined(NAVICAT_12)
DWORD LicenseStringLength = 1024;
TCHAR LicenseString[1024] = { };
if (!CryptBinaryToString(License, sizeof(License), CRYPT_STRING_BASE64, LicenseString, &LicenseStringLength)) {
_tprintf_s(TEXT("Cannot get Base64 string. CODE: 0x%08x\r\n"), GetLastError());
return FALSE;
}
_tprintf_s(TEXT("License:\r\n%s"), LicenseString);
return TRUE;
#elif defined(NAVICAT_11)
HANDLE hLicenseFile = CreateFile(TEXT("license_file"), GENERIC_ALL, NULL, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hLicenseFile == NULL)
return FALSE;
if (!WriteFile(hLicenseFile, License, sizeof(License), nullptr, nullptr)) {
CloseHandle(hLicenseFile);
return FALSE;
}
CloseHandle(hLicenseFile);
return TRUE;
#endif
}
int _tmain(int argc, TCHAR* argv[]) {
if (argc != 2) {
_tprintf_s(TEXT("Usage:\r\n"));
_tprintf_s(TEXT(" navicat-keygen.exe <RSA-2048 PrivateKey(PEM file)>\r\n"));
return -1;
}
srand(time(nullptr));
#ifdef UNICODE
char pem_file_path[256] = { };
sprintf_s(pem_file_path, "%S", argv[1]);
#else
char* pem_file_path = argv[1];
#endif
RSA* PrivateKey = nullptr;
BIO* PrivateKeyFile = BIO_new(BIO_s_file());
BIO_read_filename(PrivateKeyFile, pem_file_path);
PrivateKey = PEM_read_bio_RSAPrivateKey(PrivateKeyFile, nullptr, nullptr, nullptr);
BIO_free_all(PrivateKeyFile);
if (PrivateKey == nullptr) {
_tprintf_s(TEXT("Failed to load private key.\r\n"));
return -2;
}
TCHAR tName[64] = { };
TCHAR tOrganization[64] = { };
{
DWORD ReadCount;
_tprintf_s(TEXT("Your name: "));
ReadConsole(GetStdHandle(STD_INPUT_HANDLE), tName, 64, &ReadCount, nullptr);
tName[ReadCount - 2] = 0;
tName[ReadCount - 1] = 0;
_tprintf_s(TEXT("Your organization: "));
ReadConsole(GetStdHandle(STD_INPUT_HANDLE), tOrganization, 64, &ReadCount, nullptr);
tOrganization[ReadCount - 2] = 0;
tOrganization[ReadCount - 1] = 0;
}
#ifdef UNICODE
char Name[64] = { };
char Organization[64] = { };
if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
tName, _tcslen(tName),
Name, 64,
NULL,
NULL) == 0) {
_tprintf_s(TEXT("Failed to convert name to UTF-8. CODE: 0x%08x\r\n"), GetLastError());
RSA_free(PrivateKey);
return GetLastError();
}
if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
tOrganization, _tcslen(tOrganization),
Organization, 64,
NULL,
NULL) == 0) {
_tprintf_s(TEXT("Failed to convert name to UTF-8. CODE: 0x%08x\r\n"), GetLastError());
RSA_free(PrivateKey);
return GetLastError();
}
#else
char* Name = tName;
char* Organization = tOrganization;
#endif
char SnKey[16] = { };
GenerateSnKey(SnKey);
TCHAR Base64String[1024] = { };
_tprintf_s(TEXT("Input request code (in Base64), empty line to return:\r\n"));
for (TCHAR* cur = Base64String; cur < Base64String + 1024;) {
DWORD ReadCount;
if (!ReadConsole(GetStdHandle(STD_INPUT_HANDLE), cur, Base64String + 1024 - cur, &ReadCount, NULL))
break;
cur += ReadCount;
#ifdef UNICODE
if (*reinterpret_cast<uint32_t*>(cur - 4) == '\r\0\n\0')
break;
#else
if (*reinterpret_cast<uint32_t*>(cur - 4) == '\r\n\r\n')
break;
#endif
}
Base64String[1024 - 1] = NULL;
BYTE enc_request_code[1024] = { };
DWORD enc_request_code_length = 1024;
if (!CryptStringToBinary(Base64String, NULL, CRYPT_STRING_BASE64, enc_request_code, &enc_request_code_length, NULL, NULL)) {
_tprintf_s(TEXT("Failed to decode Base64 string. CODE: 0x%08x\r\n"), GetLastError());
RSA_free(PrivateKey);
return GetLastError();
}
char request_code[1024] = { };
if (!RSA_private_decrypt(enc_request_code_length,
enc_request_code,
reinterpret_cast<BYTE*>(request_code),
PrivateKey, RSA_PKCS1_PADDING)) {
_tprintf_s(TEXT("Failed to decrypt request code.\r\n"));
RSA_free(PrivateKey);
return -3;
}
#ifdef _DEBUG
#ifdef UNICODE
_tprintf_s(TEXT("%S\r\n"), request_code);
#else
_tprintf_s(TEXT("%s\r\n"), request_code);
#endif
#endif
//--------------------------------------------------------------------
if (strlen(request_code) >= 256) {
_tprintf_s(TEXT("Not a valid request code.\r\n"));
RSA_free(PrivateKey);
return -4;
}
char* DI_ptr = request_code;
for (; DI_ptr < request_code + 256; DI_ptr++) {
if (*reinterpret_cast<uint32_t*>(DI_ptr) == '"ID"') {
DI_ptr += 4;
while (*DI_ptr++ != '"');
break;
}
}
if (DI_ptr >= request_code + 256) {
_tprintf_s(TEXT("Not a valid request code.\r\n"));
RSA_free(PrivateKey);
return -5;
}
for (char* ptr = DI_ptr; ptr < request_code + 256; ptr++) {
if (*ptr == '"') {
*ptr = 0;
break;
}
}
//-------------------------------------------------------------------
GenerateLicense(PrivateKey, SnKey, Name, Organization, DI_ptr);
RSA_free(PrivateKey);
return 0;
}
+251
View File
@@ -0,0 +1,251 @@
#include <stddef.h> // NOLINT
#include <stdint.h> // NOLINT
#include <iostream>
#include <vector>
#include <string>
#include "../common/RSACipher.hpp"
#include "NavicatKeygen.hpp"
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
template<int min_num, int max_num>
bool read_int(int& num, const char* prompt, const char* err_msg) {
int temp;
std::string input;
while (true) {
std::cout << prompt;
if (!std::getline(std::cin, input))
return false;
try {
temp = std::stoi(input, nullptr, 0);
if (min_num <= temp && temp <= max_num) {
num = temp;
return true;
} else {
throw std::invalid_argument(err_msg);
}
} catch (...) {
std::cout << err_msg << std::endl;
}
}
}
std::string base64_encode(const std::vector<uint8_t>& bindata);
std::vector<uint8_t> base64_decode(const std::string& ascdata);
void Help() {
std::cout << "***************************************************" << std::endl;
std::cout << "* Navicat Keygen by @DoubleLabyrinth *" << std::endl;
std::cout << "* Version: 4.0 *" << std::endl;
std::cout << "***************************************************" << std::endl;
std::cout << std::endl;
std::cout << "Usage:" << std::endl;
std::cout << " navicat-keygen <RSA-2048 Private Key File>" << std::endl;
std::cout << std::endl;
std::cout << " <RSA-2048 Private Key File> Path to a PEM-format RSA-2048 private key file." << std::endl;
std::cout << " This parameter must be specified." << std::endl;
std::cout << std::endl;
}
int main(int argc, char* argv[]) {
if (argc != 2) {
Help();
return -1;
} else {
try {
std::cout << "***************************************************" << std::endl;
std::cout << "* Navicat Keygen by @DoubleLabyrinth *" << std::endl;
std::cout << "* Version: 4.0 *" << std::endl;
std::cout << "***************************************************" << std::endl;
std::cout << std::endl;
RSACipher RsaCipher;
int select_num;
NavicatKeygen keygen;
std::string username;
std::string organization;
std::string RequestCode_b64;
std::vector<uint8_t> RequestCode;
char RequestInfo[256] = {};
char ResponseInfo[256] = {};
std::vector<uint8_t> ResponseCode;
std::string ResponseCode_b64;
rapidjson::Document json;
rapidjson::Value N_Key;
rapidjson::Value N_Value;
rapidjson::Value O_Key;
rapidjson::Value O_Value;
rapidjson::Value T_Key;
rapidjson::Value T_Value;
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
RsaCipher.ImportKeyFromFile<RSAKeyType::PrivateKey, RSAKeyFormat::PEM>(argv[1]);
if (RsaCipher.Bits() != 2048) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "Not RSA-2048 private key file.");
}
keygen.SetProductSignature(NavicatKeygen::Product::Premium);
std::cout
<< "Which is your Navicat Premium language?" << std::endl
<< "0. English" << std::endl
<< "1. Simplified Chinese" << std::endl
<< "2. Traditional Chinese" << std::endl
<< "3. Japanese" << std::endl
<< "4. Polish" << std::endl
<< "5. Spanish" << std::endl
<< "6. French" << std::endl
<< "7. German" << std::endl
<< "8. Korean" << std::endl
<< "9. Russian" << std::endl
<< "10. Portuguese" << std::endl
<< std::endl;
if (read_int<0, 10>(select_num, "(Input index)> ", "Invalid index.")) {
keygen.SetLanguageSignature(static_cast<NavicatKeygen::Language>(select_num));
} else {
return -1;
}
std::cout << std::endl;
if (read_int<0, 15>(select_num, "(Input major version number, range: 0 ~ 15, default: 12)> ", "Invalid number.")) {
keygen.SetVersion(static_cast<uint8_t>(select_num));
} else {
return -1;
}
//
// Generate snKey
//
keygen.Generate();
std::cout << std::endl;
std::cout << "Serial number:" << std::endl;
std::cout << keygen.GetFormatedKey() << std::endl;
std::cout << std::endl;
//
// Get user name
//
std::cout << "Your name: ";
if (!std::getline(std::cin, username)) {
return -1;
}
//
// Get organization name
//
std::cout << "Your organization: ";
if (!std::getline(std::cin, organization)) {
return -1;
}
std::cout << std::endl;
//
// Get request code in base64
//
std::cout << "Input request code (in Base64), input empty line to end:" << std::endl;
while (true) {
std::string temp;
if (!std::getline(std::cin, temp))
return 0;
if (temp.empty())
break;
RequestCode_b64 += temp;
}
//
// Get request code in raw bytes
//
RequestCode = base64_decode(RequestCode_b64);
if (RequestCode.size() > ((RsaCipher.Bits() + 7) / 8)) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "Request code is too long.");
}
//
// Decrypt to get request info
//
RsaCipher.Decrypt(RequestCode.data(), static_cast<int>(RequestCode.size()), RequestInfo, RSA_PKCS1_PADDING);
//
// print out request info
//
std::cout << "Request Info:" << std::endl;
std::cout << RequestInfo << std::endl;
std::cout << std::endl;
//
// Generate response info
//
json.Parse(RequestInfo);
json.RemoveMember("P"); // remove Platform info
N_Key.SetString("N", 1);
N_Value.SetString(username.c_str(), static_cast<rapidjson::SizeType>(username.length()));
O_Key.SetString("O", 1);
O_Value.SetString(organization.c_str(), static_cast<rapidjson::SizeType>(organization.length()));
T_Key.SetString("T", 1);
T_Value.SetUint(static_cast<unsigned>(std::time(nullptr)));
json.AddMember(N_Key, N_Value, json.GetAllocator());
json.AddMember(O_Key, O_Value, json.GetAllocator());
json.AddMember(T_Key, T_Value, json.GetAllocator());
json.Accept(writer);
if (buffer.GetSize() > 240) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "Response info is too long.");
}
//
// print out response info
//
memcpy(ResponseInfo, buffer.GetString(), buffer.GetSize());
std::cout << "Response Info:" << std::endl;
std::cout << ResponseInfo << std::endl;
std::cout << std::endl;
//
// encrypt response info
//
ResponseCode.resize((RsaCipher.Bits() + 7) / 8);
RsaCipher.Encrypt<RSAKeyType::PrivateKey>(ResponseInfo, static_cast<int>(strlen(ResponseInfo)), ResponseCode.data(), RSA_PKCS1_PADDING);
//
// encode encrypted response info in base64 format
//
ResponseCode_b64 = base64_encode(ResponseCode);
//
// print out activation code
//
std::cout << "License:" << std::endl;
std::cout << ResponseCode_b64 << std::endl;
return 0;
} catch (nkg::Exception& e) {
std::cout << "[-] " << e.File() << ":" << e.Line() << " ->" << std::endl;
std::cout << " " << e.Message() << std::endl;
if (e.HasErrorCode()) {
std::cout << " " << e.ErrorString() << std::endl;
}
return -1;
}
}
}
-162
View File
@@ -1,162 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{CB49F054-83AB-4C16-B73B-33D7DF696E16}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>navicatkeygen</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>D:\OpenSSL-Win64\include;$(IncludePath)</IncludePath>
<LibraryPath>D:\OpenSSL-Win64\lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>D:\OpenSSL-Win64\include;$(IncludePath)</IncludePath>
<LibraryPath>D:\OpenSSL-Win64\lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="_tmain.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="_tmain.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
</Project>
+76
View File
@@ -0,0 +1,76 @@
#include "CapstoneDisassembler.hpp"
CapstoneDisassembler CapstoneDisassembler::Create(cs_arch ArchType, cs_mode Mode) {
CapstoneDisassembler NewDisassembler;
auto err = cs_open(ArchType, Mode, NewDisassembler.pvt_Handle.GetAddress());
if (err != CS_ERR_OK) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::CapstoneError(__FILE__, __LINE__, err, "cs_open failed.");
}
NewDisassembler.pvt_Insn.TakeOver(cs_malloc(NewDisassembler.pvt_Handle));
if (NewDisassembler.pvt_Insn.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::CapstoneError(__FILE__, __LINE__, cs_errno(NewDisassembler.pvt_Handle), "cs_malloc failed.");
}
return NewDisassembler;
}
void CapstoneDisassembler::Option(cs_opt_type Type, size_t Value) {
auto err = cs_option(pvt_Handle, Type, Value);
if (err != CS_ERR_OK) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::CapstoneError(__FILE__, __LINE__, err, "cs_option failed.");
}
pvt_CurrentInsn = nullptr;
pvt_Insn.TakeOver(cs_malloc(pvt_Handle));
if (pvt_Insn.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::CapstoneError(__FILE__, __LINE__, cs_errno(pvt_Handle), "cs_malloc failed.");
}
}
void CapstoneDisassembler::SetContext(uintptr_t lpOpcode, size_t cbOpcode, uint64_t Address) noexcept {
pvt_CurrentCtx.pbOpcode = reinterpret_cast<const uint8_t*>(lpOpcode);
pvt_CurrentCtx.cbOpcode = cbOpcode;
pvt_CurrentCtx.Address = Address;
pvt_CurrentInsn = nullptr;
}
void CapstoneDisassembler::SetContext(const void* lpOpcode, size_t cbOpcode, uint64_t Address) noexcept {
pvt_CurrentCtx.pbOpcode = reinterpret_cast<const uint8_t*>(lpOpcode);
pvt_CurrentCtx.cbOpcode = cbOpcode;
pvt_CurrentCtx.Address = Address;
pvt_CurrentInsn = nullptr;
}
const CapstoneDisassembler::Context& CapstoneDisassembler::GetContext() const noexcept {
return pvt_CurrentCtx;
}
const cs_insn* CapstoneDisassembler::GetInstruction() const noexcept {
return pvt_CurrentInsn;
}
CapstoneDisassembler::Context CapstoneDisassembler::GetInstructionContext() const noexcept {
Context CtxOfInsn = {};
CtxOfInsn.pbOpcode = pvt_CurrentCtx.pbOpcode - pvt_CurrentInsn->size;
CtxOfInsn.cbOpcode = pvt_CurrentCtx.cbOpcode + pvt_CurrentInsn->size;
CtxOfInsn.Address = pvt_CurrentCtx.Address - pvt_CurrentInsn->size;
return CtxOfInsn;
}
bool CapstoneDisassembler::Next() noexcept {
bool bSucceed = cs_disasm_iter(pvt_Handle, &pvt_CurrentCtx.pbOpcode, &pvt_CurrentCtx.cbOpcode, &pvt_CurrentCtx.Address, pvt_Insn);
if (bSucceed) {
if (pvt_CurrentInsn == nullptr) pvt_CurrentInsn = pvt_Insn.Get();
} else {
pvt_CurrentInsn = nullptr;
}
return bSucceed;
}
+49
View File
@@ -0,0 +1,49 @@
#pragma once
#include <capstone/capstone.h>
#include "../common/ResourceOwned.hpp"
#include "ResourceTraitsCapstone.hpp"
class CapstoneDisassembler {
public:
struct Context {
const uint8_t* pbOpcode;
size_t cbOpcode;
uint64_t Address;
};
private:
ResourceOwned<CapstoneHandleTraits> pvt_Handle;
ResourceOwned<CapstoneInsnTraits> pvt_Insn;
Context pvt_CurrentCtx;
cs_insn* pvt_CurrentInsn;
CapstoneDisassembler() noexcept :
pvt_Handle(CapstoneHandleTraits{}),
pvt_Insn(CapstoneInsnTraits{}),
pvt_CurrentCtx{},
pvt_CurrentInsn(nullptr) {}
public:
[[nodiscard]]
static CapstoneDisassembler Create(cs_arch ArchType, cs_mode Mode);
void Option(cs_opt_type Type, size_t Value);
void SetContext(uintptr_t lpOpcode, size_t cbOpcode, uint64_t Address = 0) noexcept ;
void SetContext(const void* lpOpcode, size_t cbOpcode, uint64_t Address = 0) noexcept;
[[nodiscard]]
const Context& GetContext() const noexcept;
[[nodiscard]]
const cs_insn* GetInstruction() const noexcept;
[[nodiscard]]
Context GetInstructionContext() const noexcept;
[[nodiscard]]
bool Next() noexcept;
};
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include "../common/Exception.hpp"
#include <capstone/capstone.h>
namespace nkg {
class CapstoneError final : public Exception {
private:
cs_err pvt_ErrorCode;
public:
CapstoneError(const char* File, unsigned Line, cs_err ErrorCode, const char* Message) noexcept :
Exception(File, Line, Message),
pvt_ErrorCode(ErrorCode) {}
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual bool HasErrorCode() const noexcept override {
return true;
}
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual intptr_t ErrorCode() const noexcept override {
return pvt_ErrorCode;
}
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual const char* ErrorString() const noexcept override {
return cs_strerror(pvt_ErrorCode);
}
};
}
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include "../common/Exception.hpp"
#include <keystone/keystone.h>
namespace nkg {
class KeystoneError final : public Exception {
private:
ks_err pvt_ErrorCode;
public:
KeystoneError(const char* File, unsigned Line, ks_err ErrorCode, const char* Message) noexcept :
Exception(File, Line, Message),
pvt_ErrorCode(ErrorCode) {}
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual bool HasErrorCode() const noexcept override {
return true;
}
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual intptr_t ErrorCode() const noexcept override {
return pvt_ErrorCode;
}
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual const char* ErrorString() const noexcept override {
return ks_strerror(pvt_ErrorCode);
}
};
}
+70
View File
@@ -0,0 +1,70 @@
#include <string.h> // NOLINT
#include "ExceptionCapstone.hpp"
#include "CapstoneDisassembler.hpp"
#include "X64ImageInterpreter.hpp"
namespace nkg {
bool IsResolvedTo(const X64ImageInterpreter& Image, const void* StubHelperProc, const char *Symbol) {
CapstoneDisassembler Disassembler = CapstoneDisassembler::Create(CS_ARCH_X86, CS_MODE_64);
Disassembler.Option(CS_OPT_DETAIL, CS_OPT_ON);
// A stub-helper proc must look like:
// push xxxxh;
// jmp loc_xxxxxxxx
// which should be 10 bytes long.
Disassembler.SetContext(StubHelperProc, 10);
if (Disassembler.Next() == false) {
return false;
}
auto insn = Disassembler.GetInstruction();
if (strcasecmp(insn->mnemonic, "push") != 0 || insn->detail->x86.operands[0].type != X86_OP_IMM) {
return false;
}
auto bind_opcode_offset = static_cast<uint32_t>(insn->detail->x86.operands[0].imm);
if (Image.CommandOf<LC_DYLD_INFO_ONLY>() == nullptr) {
return false;
}
auto bind_opcode_ptr =
Image.ImageOffset<uint8_t*>(Image.CommandOf<LC_DYLD_INFO_ONLY>()->lazy_bind_off) +
bind_opcode_offset;
while ((*bind_opcode_ptr & BIND_OPCODE_MASK) != BIND_OPCODE_DONE) {
switch (*bind_opcode_ptr & BIND_OPCODE_MASK) {
case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: // 0x10
case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: // 0x30
case BIND_OPCODE_SET_TYPE_IMM: // 0x50
case BIND_OPCODE_DO_BIND: // 0x90
case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: // 0xB0
++bind_opcode_ptr;
break;
case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: // 0x20
case BIND_OPCODE_SET_ADDEND_SLEB: // 0x60
case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: // 0x70
case BIND_OPCODE_ADD_ADDR_ULEB: // 0x80
case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: // 0xA0
while (*(++bind_opcode_ptr) & 0x80u);
++bind_opcode_ptr;
break;
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: // 0x40
return strcmp(reinterpret_cast<const char *>(bind_opcode_ptr + 1), Symbol) == 0;
case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: // 0xC0
//
// This opcode is too rare to appear,
// It is okay to dismiss this opcode
//
return false;
default:
return false;
}
}
return false;
}
}
+96
View File
@@ -0,0 +1,96 @@
#include <stddef.h> // NOLINT
#include <stdint.h> // NOLINT
#include <stdio.h> // NOLINT
#include <signal.h> // NOLINT
#include <setjmp.h> // NOLINT
static jmp_buf env;
static void SIGSEGV_Handler(int sig) {
siglongjmp(env, 1);
}
//
// read byte(s) at address `p` as __Type to `out`
// succeed if return true, otherwise return false
//
template<typename __Type>
static inline bool ProbeForRead(const void* p, void* out) {
int r = sigsetjmp(env, 1);
if (r == 0) {
*reinterpret_cast<__Type*>(out) = *reinterpret_cast<const __Type*>(p);
return true;
} else {
return false;
}
}
//
// Print memory data in [from, to) at least
// If `base` is not nullptr, print address as offset. Otherwise, as absolute address.
// NOTICE:
// `base` must >= `from`
//
namespace nkg {
void PrintMemory(const void *from, const void *to, const void *base) {
auto start = reinterpret_cast<const uint8_t *>(from);
auto end = reinterpret_cast<const uint8_t *>(to);
auto base_ptr = reinterpret_cast<const uint8_t *>(base);
if (start >= end)
return;
while (reinterpret_cast<uintptr_t>(start) % 16)
start--;
while (reinterpret_cast<uintptr_t>(end) % 16)
end++;
void (*prev_handler)(int) = signal(SIGSEGV, SIGSEGV_Handler);
while (start < end) {
uint16_t value[16] = {};
if (base_ptr) {
uintptr_t d = start >= base ? start - base_ptr : base_ptr - start;
if (start >= base) {
printf("+0x%.*zx ", static_cast<int>(2 * sizeof(void *)), d);
} else {
printf("-0x%.*zx ", static_cast<int>(2 * sizeof(void *)), d);
}
} else {
printf("0x%.*zx ", static_cast<int>(2 * sizeof(void *)), reinterpret_cast<uintptr_t >(start));
}
for (int i = 0; i < 16; ++i) {
if (start + i < from) {
printf(" ");
value[i] = 0xfffe;
} else if (ProbeForRead<uint8_t>(start + i, value + i)) {
printf("%02x ", value[i]);
} else {
printf("?? ");
value[i] = 0xffff;
}
}
printf(" ");
for (int i = 0; i < 16; ++i) { // NOLINT
if (0x20 <= value[i] && value[i] < 0x7f) {
printf("%c", value[i]);
} else if (value[i] == 0xfffe) {
printf(" ");
} else {
printf(".");
}
}
printf("\n");
start += 0x10;
}
signal(SIGSEGV, prev_handler);
}
}
+50
View File
@@ -0,0 +1,50 @@
#include "KeystoneAssembler.hpp"
[[nodiscard]]
KeystoneAssembler KeystoneAssembler::Create(ks_arch ArchType, ks_mode Mode) {
KeystoneAssembler NewAssembler;
auto err = ks_open(ArchType, Mode, NewAssembler.pvt_Engine.GetAddress());
if (err != KS_ERR_OK) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::KeystoneError(__FILE__, __LINE__, err, "ks_open failed.");
}
return NewAssembler;
}
void KeystoneAssembler::Option(ks_opt_type Type, size_t Value) {
auto err = ks_option(pvt_Engine, Type, Value);
if (err != KS_ERR_OK) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::KeystoneError(__FILE__, __LINE__, err, "ks_open failed.");
}
}
[[nodiscard]]
std::vector<uint8_t> KeystoneAssembler::GenerateOpcode(const char *AssemblyCode, uint64_t Address) const {
ResourceOwned pbOpcode(KeystoneMallocTraits{});
size_t cbOpCode = 0;
size_t InstructionsProcessed = 0;
if (ks_asm(pvt_Engine, AssemblyCode, Address, pbOpcode.GetAddress(), &cbOpCode, &InstructionsProcessed) != 0) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::KeystoneError(__FILE__, __LINE__, ks_errno(pvt_Engine), "ks_asm failed.");
}
return std::vector<uint8_t>(pbOpcode.Get(), pbOpcode.Get() + cbOpCode);
}
[[nodiscard]]
std::vector<uint8_t> KeystoneAssembler::GenerateOpcode(const std::string& AssemblyCode, uint64_t Address) const {
ResourceOwned pbOpcode(KeystoneMallocTraits{});
size_t cbOpCode = 0;
size_t InstructionsProcessed = 0;
if (ks_asm(pvt_Engine, AssemblyCode.c_str(), Address, pbOpcode.GetAddress(), &cbOpCode, &InstructionsProcessed) != 0) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::KeystoneError(__FILE__, __LINE__, ks_errno(pvt_Engine), "ks_asm failed.");
}
return std::vector<uint8_t>(pbOpcode.Get(), pbOpcode.Get() + cbOpCode);
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <keystone/keystone.h>
#include "../common/ResourceOwned.hpp"
#include "ResourceTraitsKeystone.hpp"
#include <vector>
#include <string>
class KeystoneAssembler {
private:
ResourceOwned<KeystoneHandleTraits> pvt_Engine;
KeystoneAssembler() noexcept :
pvt_Engine(KeystoneHandleTraits{}) {}
public:
[[nodiscard]]
static KeystoneAssembler Create(ks_arch ArchType, ks_mode Mode);
void Option(ks_opt_type Type, size_t Value);
[[nodiscard]]
std::vector<uint8_t> GenerateOpcode(const char* AssemblyCode, uint64_t Address = 0) const;
[[nodiscard]]
std::vector<uint8_t> GenerateOpcode(const std::string& AssemblyCode, uint64_t Address = 0) const;
};
+78
View File
@@ -0,0 +1,78 @@
#include "PatchSolutions.hpp"
#include <memory.h>
const char PatchSolution0::Keyword[452] =
"-----BEGIN PUBLIC KEY-----\x00"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I\x00"
"qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv\x00"
"a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF\x00"
"R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2\x00"
"WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt\x00"
"YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ\x00"
"awIDAQAB\x00"
"-----END PUBLIC KEY-----\x00";
PatchSolution0::PatchSolution0(const X64ImageInterpreter& Image) noexcept :
pvt_Image(Image),
pvt_PatchOffset(X64ImageInterpreter::InvalidOffset) {}
bool PatchSolution0::FindPatchOffset() noexcept {
try {
pvt_PatchOffset = pvt_Image.SearchSectionOffset("__TEXT", "__cstring", [](const uint8_t* p) {
return memcmp(p, Keyword, sizeof(Keyword) - 1) == 0;
});
printf("[+] PatchSolution0 ...... Ready to apply.\n");
printf(" Keyword offset = +0x%.8x\n", pvt_PatchOffset);
return true;
} catch (...) {
printf("[-] PatchSolution0 ...... Omitted.\n");
return false;
}
}
bool PatchSolution0::CheckKey(const RSACipher& RsaCipher) const noexcept {
try {
if (RsaCipher.Bits() != 2048) {
return false;
}
std::string PublicKeyPEM = RsaCipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
for (auto& c : PublicKeyPEM) {
if (c == '\n') c = '\x00';
}
return PublicKeyPEM.length() == sizeof(Keyword) - 1;
} catch (...) {
return false;
}
}
void PatchSolution0::MakePatch(const RSACipher& RsaCipher) const {
if (pvt_PatchOffset == X64ImageInterpreter::InvalidOffset) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "PatchSolution0 is not ready.");
}
std::string PublicKeyPEM = RsaCipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
for (auto& c : PublicKeyPEM) {
if (c == '\n') c = '\x00';
}
auto pbPatch = pvt_Image.ImageOffset<uint8_t*>(pvt_PatchOffset);
puts("**************************************************************");
puts("* PatchSolution0 *");
puts("**************************************************************");
printf("@+0x%.8x\n", pvt_PatchOffset);
puts("Previous:");
nkg::PrintMemory(pbPatch, pbPatch + sizeof(Keyword), pbPatch);
memcpy(pbPatch, PublicKeyPEM.data(), PublicKeyPEM.size());
puts("After:");
nkg::PrintMemory(pbPatch, pbPatch + sizeof(Keyword), pbPatch);
puts("");
}
+127
View File
@@ -0,0 +1,127 @@
#include "PatchSolutions.hpp"
#include <memory.h>
const uint8_t PatchSolution1::Keyword[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
};
PatchSolution1::PatchSolution1(const X64ImageInterpreter& Image) noexcept :
pvt_Image(Image),
pvt_PatchOffset(X64ImageInterpreter::InvalidOffset) {}
bool PatchSolution1::FindPatchOffset() noexcept {
uint8_t* pbPatch = nullptr;
for (size_t i = 0; i < pvt_Image.NumberOfSections(); ++i) {
auto pbSectionView = pvt_Image.SectionView<uint8_t*>(i);
auto cbSectiveView = pvt_Image.ImageSection(i)->size;
if (cbSectiveView < sizeof(Keyword)) {
continue;
}
for (size_t j = 0; j < cbSectiveView - sizeof(Keyword); ++j) {
if (memcmp(pbSectionView + j, Keyword, sizeof(Keyword)) == 0) {
pbPatch = pbSectionView + j;
i = pvt_Image.NumberOfSections();
break;
}
}
}
if (pbPatch == nullptr) {
printf("[-] PatchSolution1 ...... Omitted.\n");
return false;
} else {
pvt_PatchOffset = pbPatch - pvt_Image.ImageBase<uint8_t*>();
printf("[+] PatchSolution1 ...... Ready to apply.\n");
printf(" Keyword offset = +0x%.8x\n", pvt_PatchOffset);
return true;
}
}
bool PatchSolution1::CheckKey(const RSACipher& RsaCipher) const noexcept {
try {
std::string PublicKeyPEM = RsaCipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
PublicKeyPEM.erase(PublicKeyPEM.find("-----BEGIN PUBLIC KEY-----"), 26);
PublicKeyPEM.erase(PublicKeyPEM.find("-----END PUBLIC KEY-----"), 24);
{
std::string::size_type pos = 0;
while ((pos = PublicKeyPEM.find('\n', pos)) != std::string::npos) {
PublicKeyPEM.erase(pos, 1);
}
}
return PublicKeyPEM.length() == sizeof(Keyword);
} catch (...) {
return false;
}
}
void PatchSolution1::MakePatch(const RSACipher& RsaCipher) const {
if (pvt_PatchOffset == X64ImageInterpreter::InvalidOffset) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "PatchSolution1 is not ready.");
}
auto pbPatch = pvt_Image.ImageOffset<uint8_t*>(pvt_PatchOffset);
std::string PublicKeyPEM = RsaCipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
PublicKeyPEM.erase(PublicKeyPEM.find("-----BEGIN PUBLIC KEY-----"), 26);
PublicKeyPEM.erase(PublicKeyPEM.find("-----END PUBLIC KEY-----"), 24);
{
std::string::size_type pos = 0;
while ((pos = PublicKeyPEM.find('\n', pos)) != std::string::npos) {
PublicKeyPEM.erase(pos, 1);
}
}
uint8_t key = 8;
for (auto& c : PublicKeyPEM) {
if (key == 0) key = 8;
reinterpret_cast<uint8_t&>(c) ^= 0xbbu - key;
--key;
}
puts("**************************************************************");
puts("* PatchSolution1 *");
puts("**************************************************************");
printf("@+0x%.8x\n", pvt_PatchOffset);
puts("Previous:");
nkg::PrintMemory(pbPatch, pbPatch + sizeof(Keyword), pbPatch);
memcpy(pbPatch, PublicKeyPEM.data(), PublicKeyPEM.length());
puts("After:");
nkg::PrintMemory(pbPatch, pbPatch + sizeof(Keyword), pbPatch);
puts("");
}
+254
View File
@@ -0,0 +1,254 @@
#include "PatchSolutions.hpp"
#include <memory.h>
const char PatchSolution2::Keyword[1114] =
"BIjWyoeRR0NBgkqnDZWxCgKCEAw1dqF3DTvOB91ZHwecJYFrdM1KEh"
"1yVeRoGqSdLLGZGUlngig3OD5mMzs889IqWqqfHSeHMvzyg1p6UPCY"
"nesxa9M2dDUrXHomRHOFHSfsbSXRFwt5GivtnJG9lLJHZ7XWeIQABi"
"dKionYD3O6c9tvUAoDosUJAdQ1RaSXTzyETbHTRtnTPeLpO3EedGMs"
"v3jG9yPcmmdYkddSeJRwn2raPJmnvdHScHUACw0sUNuosAqPaQbTQN"
"PATDzcrnd1Sf8RIbUp4MQJFVJugPLVZbP53Gjtyyniqe5q75kva8Qm"
"Hr1uOuXkVppe3cwECaGamupG43L1XfcpRjCMrxRep3s2VlbL01xmfz"
"5cIhrj34iVmgZSAmIb8ZxiHPdp1oDMFkbNetZyWegqjAHQQ9eoSOTD"
"bERbKEwZ5FLeLsbNAxfqsapB1XBvCavFHualx6bxVxuRQceh4z8kaZ"
"iv2pOKbZQSJ2Dx5HEq0bYZ6y6b7sN9IaeDFNQwjzQn1K7k3XlYAPWC"
"IvDe8Ln0FUe4yMNmuUhu5RTjxE05hUqtz1HjJvYQ9Es1VA6LflKQ87"
"TwIXBNvfrcHaZ72QM4dQtDUyEMrLgMDkJBDM9wqIDps65gSlAz6eHD"
"8tYWUttrWose0cH0yykVnqFzPtdRiZyZRfio6lGyK48mIC9z7T6MN3"
"a7OaLZHZSwzcpQLcGi7M9q1wXLq4Ms1UvlwntB9FLHc63tHPpG8rhn"
"XhZIk4QrSm4GYuEKQVHwku6ulw6wfggVL8FZPhoPCGsrb2rQGurBUL"
"3lkVJ6RO9VGHcczDYomXqAJqlt4y9pkQIj9kgwTrxTzEZgMGdYZqsV"
"4Bd5JjtrL7u3LA0N2Hq9Xvmmis2jDVhSQoUoGukNIoqng3SBsf0E7b"
"4W0S1aZSSOJ90nQHQkQShE9YIMDBbNwIg2ncthwADYqibYUgIvJcK9"
"89XHnYmZsdMWtt53lICsXE1vztR5WrQjSw4WXDiB31LXTrvudCB6vw"
"kCQa4leutETpKLJ2bYaOYBdoiBFOwvf36YaSuRoY4SP2x1pWOwGFTg"
"d90J2uYyCqUa3Q3iX52iigT4EKL2vJKdJ";
const uint8_t PatchSolution2::FunctionHeader[9] = {
0x55, // push rbp
0x48, 0x89, 0xe5, // mov rbp, rsp
0x41, 0x57, // push r15
0x41, 0x56, // push r14
0x53, // push rbx
};
PatchSolution2::PatchSolution2(const X64ImageInterpreter& Image) noexcept :
pvt_Image(Image),
pvt_Disassembler(CapstoneDisassembler::Create(CS_ARCH_X86, CS_MODE_64)),
pvt_Assembler(KeystoneAssembler::Create(KS_ARCH_X86, KS_MODE_64)),
pvt_FunctionOffset(X64ImageInterpreter::InvalidOffset),
pvt_KeywordOffset(X64ImageInterpreter::InvalidOffset),
pvt_StdStringAppendStubRva(X64ImageInterpreter::InvalidAddress)
{
pvt_Disassembler.Option(CS_OPT_DETAIL, CS_OPT_ON);
}
bool PatchSolution2::FindPatchOffset() noexcept {
auto FunctionOffset = X64ImageInterpreter::InvalidOffset;
auto KeywordOffset = X64ImageInterpreter::InvalidOffset;
auto StdStringAppendStubRva = X64ImageInterpreter::InvalidAddress;
try {
auto Sec__text = pvt_Image.ImageSection("__TEXT", "__text");
auto Sec__const = pvt_Image.ImageSection("__TEXT", "__const");
auto Sec__stubs = pvt_Image.ImageSection("__TEXT", "__stubs");
auto SecView__text = pvt_Image.SectionView<uint8_t*>(Sec__text);
auto SecView__const = pvt_Image.SectionView<uint8_t*>(Sec__const);
auto SecView__stubs = pvt_Image.SectionView<uint8_t*>(Sec__stubs);
KeywordOffset = pvt_Image.SearchSectionOffset("__TEXT", "__const", [](const uint8_t* p) {
return memcmp(p, Keyword, sizeof(Keyword)) == 0;
});
auto KeywordRva = pvt_Image.OffsetToRva(KeywordOffset);
auto Hint = pvt_Image.SearchSectionOffset("__TEXT", "__text", [Sec__text, SecView__text, KeywordRva](const uint8_t* p) {
auto rip = (p - SecView__text) + Sec__text->addr + 4;
auto off = *reinterpret_cast<const uint32_t*>(p);
return rip + off == KeywordRva;
}) - 0xc0;
for (uint32_t i = 0; i < 0xc0; ++i) {
if (memcmp(pvt_Image.ImageOffset(Hint + i), FunctionHeader, sizeof(FunctionHeader)) == 0) {
FunctionOffset = Hint + i;
break;
}
}
if (FunctionOffset == X64ImageInterpreter::InvalidOffset) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "Not found.");
}
pvt_Disassembler.SetContext(SecView__stubs, Sec__stubs->size, Sec__stubs->addr);
while (pvt_Disassembler.Next()) {
auto insn = pvt_Disassembler.GetInstruction();
//
// As far as I know, all stub functions have a pattern looking like:
// jmp qword ptr [RIP + xxxx]
//
if (strcasecmp(insn->mnemonic, "jmp") == 0 && insn->detail->x86.operands[0].type == X86_OP_MEM && insn->detail->x86.operands[0].mem.base == X86_REG_RIP) {
uint64_t la_symbol_ptr_rva = pvt_Disassembler.GetContext().Address + insn->detail->x86.operands[0].mem.disp;
uint32_t la_symbol_ptr_offset = pvt_Image.RvaToOffset(la_symbol_ptr_rva);
if (la_symbol_ptr_offset == X64ImageInterpreter::InvalidOffset)
continue;
uint64_t stub_helper_rva = *pvt_Image.ImageOffset<const uint64_t*>(la_symbol_ptr_offset);
uint32_t stub_helper_offset = pvt_Image.RvaToOffset(stub_helper_rva);
if (stub_helper_offset == X64ImageInterpreter::InvalidOffset)
continue;
//
// __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKc
// is the mangled name of "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::append(char const*)",
// which is, as known as, "std::string::append(const char*)"
// You can demangle it by c++flit
// e.g.
// c++filt -_ '__ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKc'
//
if (nkg::IsResolvedTo(pvt_Image, pvt_Image.ImageOffset(stub_helper_offset), "__ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKc")) {
auto StdStringAppendStubOffset = pvt_Disassembler.GetInstructionContext().pbOpcode - pvt_Image.ImageBase<const uint8_t*>();
StdStringAppendStubRva = pvt_Image.OffsetToRva(StdStringAppendStubOffset);
break;
}
}
}
if (StdStringAppendStubRva == X64ImageInterpreter::InvalidAddress) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "Not found.");
}
pvt_FunctionOffset = FunctionOffset;
pvt_KeywordOffset = KeywordOffset;
pvt_StdStringAppendStubRva = StdStringAppendStubRva;
printf("[+] PatchSolution2 ...... Ready to apply.\n");
printf(" Function offset = +0x%.8x\n", pvt_FunctionOffset);
printf(" Keyword offset = +0x%.8x\n", pvt_KeywordOffset);
printf(" std::string::append(const char*) RVA = 0x%.16llx\n", pvt_StdStringAppendStubRva);
return true;
} catch (...) {
printf("[-] PatchSolution2 ...... Omitted.\n");
return false;
}
}
[[nodiscard]]
bool PatchSolution2::CheckKey(const RSACipher& RsaCipher) const noexcept {
std::string PublicKeyPEM = RsaCipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
PublicKeyPEM.erase(PublicKeyPEM.find("-----BEGIN PUBLIC KEY-----"), 26);
PublicKeyPEM.erase(PublicKeyPEM.find("-----END PUBLIC KEY-----"), 24);
{
std::string::size_type pos = 0;
while ((pos = PublicKeyPEM.find('\n', pos)) != std::string::npos) {
PublicKeyPEM.erase(pos, 1);
}
}
return PublicKeyPEM.length() == 0x188;
}
void PatchSolution2::MakePatch(const RSACipher& RsaCipher) const {
if (pvt_FunctionOffset == X64ImageInterpreter::InvalidOffset ||
pvt_KeywordOffset == X64ImageInterpreter::InvalidOffset ||
pvt_StdStringAppendStubRva == X64ImageInterpreter::InvalidAddress)
{
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "PatchSolution2 is not ready.");
}
//
// Prepare public key string
//
std::string PublicKeyPEM = RsaCipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
PublicKeyPEM.erase(PublicKeyPEM.find("-----BEGIN PUBLIC KEY-----"), 26);
PublicKeyPEM.erase(PublicKeyPEM.find("-----END PUBLIC KEY-----"), 24);
{
std::string::size_type pos = 0;
while ((pos = PublicKeyPEM.find('\n', pos)) != std::string::npos) {
PublicKeyPEM.erase(pos, 1);
}
}
//
// Prepare new function opcodes
//
uint64_t FunctionRVA = pvt_Image.OffsetToRva(pvt_FunctionOffset);
uint64_t KeywordRVA = pvt_Image.OffsetToRva(pvt_KeywordOffset);
char AssemblyCode[512] = {};
sprintf(AssemblyCode,
"push rbp;"
"mov rbp, rsp;"
"push r15;"
"push r14;"
"push rbx;"
"sub rsp, 0x48;"
"mov rbx, rdi;"
"xor rax, rax;" // initialize std::string with null
"mov qword ptr[rsp], rax;"
"mov qword ptr[rsp + 0x8], rax;"
"mov qword ptr[rsp + 0x10], rax;"
"lea rdi, qword ptr[rsp];"
"lea rsi, qword ptr[0x%.16llx];" // filled with address to Keyword
"call 0x%.16llx;" // filled with address to std::string::append(const char*)
"mov rax, qword ptr[rsp];"
"mov qword ptr[rbx], rax;"
"mov rax, qword ptr[rsp + 0x8];"
"mov qword ptr[rbx + 0x8], rax;"
"mov rax, qword ptr[rsp + 0x10];"
"mov qword ptr[rbx + 0x10], rax;"
"mov rax, rbx;"
"add rsp, 0x48;"
"pop rbx;"
"pop r14;"
"pop r15;"
"pop rbp;"
"ret;",
KeywordRVA,
pvt_StdStringAppendStubRva
);
auto NewFunctionOpcode = pvt_Assembler.GenerateOpcode(AssemblyCode, FunctionRVA);
auto pbFunctionPatch = pvt_Image.ImageOffset<uint8_t*>(pvt_FunctionOffset);
auto pbKeywordPatch = pvt_Image.ImageOffset<uint8_t*>(pvt_KeywordOffset);
puts("**************************************************************");
puts("* PatchSolution2 *");
puts("**************************************************************");
printf("@+0x%.8x\n", pvt_KeywordOffset);
puts("Previous:");
nkg::PrintMemory(pbKeywordPatch, pbKeywordPatch + sizeof(Keyword) - 1, pbKeywordPatch);
memcpy(pbKeywordPatch, PublicKeyPEM.c_str(), PublicKeyPEM.length() + 1); // with a null-terminator
puts("After:");
nkg::PrintMemory(pbKeywordPatch, pbKeywordPatch + sizeof(Keyword) - 1, pbKeywordPatch);
puts("");
printf("@+0x%.8x\n", pvt_FunctionOffset);
puts("Previous:");
nkg::PrintMemory(pbFunctionPatch, pbFunctionPatch + NewFunctionOpcode.size(), pbFunctionPatch);
memcpy(pbFunctionPatch, NewFunctionOpcode.data(), NewFunctionOpcode.size());
puts("After:");
nkg::PrintMemory(pbFunctionPatch, pbFunctionPatch + NewFunctionOpcode.size(), pbFunctionPatch);
puts("");
}
+114
View File
@@ -0,0 +1,114 @@
#pragma once
#include "../common/Exception.hpp"
#include "../common/ResourceOwned.hpp"
#include "../common/RSACipher.hpp"
#include "ResourceTraitsUnix.hpp"
#include "X64ImageInterpreter.hpp"
#include "CapstoneDisassembler.hpp"
#include "KeystoneAssembler.hpp"
namespace nkg {
//
// Print memory data in [from, to) at least
// If `base` is not nullptr, print address as offset. Otherwise, as absolute address.
// NOTICE:
// `base` must >= `from`
//
void PrintMemory(const void *from, const void *to, const void *base = nullptr);
bool IsResolvedTo(const X64ImageInterpreter& Image, const void* StubHelperProc, const char *Symbol);
}
class PatchSolution {
public:
[[nodiscard]]
virtual bool FindPatchOffset() noexcept = 0;
[[nodiscard]]
virtual bool CheckKey(const RSACipher& RsaCipher) const noexcept = 0;
virtual void MakePatch(const RSACipher& RsaCipher) const = 0;
virtual ~PatchSolution() = default;
};
class PatchSolution0 : public PatchSolution {
private:
static const char Keyword[452];
const X64ImageInterpreter& pvt_Image;
uint32_t pvt_PatchOffset;
public:
explicit
PatchSolution0(const X64ImageInterpreter& Image) noexcept;
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual bool FindPatchOffset() noexcept override;
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual bool CheckKey(const RSACipher& RsaCipher) const noexcept override;
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual void MakePatch(const RSACipher& RsaCipher) const override;
};
class PatchSolution1 : public PatchSolution {
private:
static const uint8_t Keyword[0x188];
const X64ImageInterpreter& pvt_Image;
uint32_t pvt_PatchOffset;
public:
explicit
PatchSolution1(const X64ImageInterpreter& Image) noexcept;
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual bool FindPatchOffset() noexcept override;
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual bool CheckKey(const RSACipher& RsaCipher) const noexcept override;
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual void MakePatch(const RSACipher& RsaCipher) const override;
};
class PatchSolution2 : public PatchSolution {
private:
static const char Keyword[1114];
static const uint8_t FunctionHeader[9];
const X64ImageInterpreter& pvt_Image;
CapstoneDisassembler pvt_Disassembler;
KeystoneAssembler pvt_Assembler;
uint32_t pvt_FunctionOffset;
uint32_t pvt_KeywordOffset;
uint64_t pvt_StdStringAppendStubRva;
public:
explicit
PatchSolution2(const X64ImageInterpreter& Image) noexcept;
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual bool FindPatchOffset() noexcept override;
[[nodiscard]]
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual bool CheckKey(const RSACipher& RsaCipher) const noexcept override;
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
virtual void MakePatch(const RSACipher& RsaCipher) const override;
};
@@ -0,0 +1,38 @@
#pragma once
#include <capstone/capstone.h>
#include "ExceptionCapstone.hpp"
struct CapstoneHandleTraits {
using HandleType = csh;
static inline const HandleType InvalidValue = 0;
[[nodiscard]]
static bool IsValid(const HandleType& Handle) noexcept {
return Handle != InvalidValue;
}
static void Releasor(HandleType& Handle) {
auto err = cs_close(&Handle);
if (err != CS_ERR_OK) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::CapstoneError(__FILE__, __LINE__, err, "ks_close failed.");
}
}
};
struct CapstoneInsnTraits {
using HandleType = cs_insn*;
static inline const HandleType InvalidValue = nullptr;
[[nodiscard]]
static bool IsValid(const HandleType& Handle) noexcept {
return Handle != InvalidValue;
}
static void Releasor(const HandleType& Handle) noexcept {
cs_free(Handle, 1);
}
};
@@ -0,0 +1,38 @@
#pragma once
#include <keystone/keystone.h>
#include "ExceptionKeystone.hpp"
struct KeystoneHandleTraits {
using HandleType = ks_engine*;
static inline const HandleType InvalidValue = nullptr;
[[nodiscard]]
static bool IsValid(const HandleType& Handle) noexcept {
return Handle != InvalidValue;
}
static void Releasor(const HandleType& Handle) {
auto err = ks_close(Handle);
if (err != KS_ERR_OK) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::KeystoneError(__FILE__, __LINE__, err, "ks_close failed.");
}
}
};
struct KeystoneMallocTraits {
using HandleType = uint8_t*;
static inline const HandleType InvalidValue = nullptr;
[[nodiscard]]
static bool IsValid(const HandleType& Handle) noexcept {
return Handle != InvalidValue;
}
static void Releasor(const HandleType& Handle) noexcept {
ks_free(Handle);
}
};
+35
View File
@@ -0,0 +1,35 @@
#pragma once
#include <errno.h> // NOLINT
#include <unistd.h>
#include <sys/mman.h>
#include "../common/ExceptionSystem.hpp"
struct FileHandleTraits {
using HandleType = int;
static inline const HandleType InvalidValue = -1;
[[nodiscard]]
static bool IsValid(const HandleType& Handle) noexcept {
return Handle != InvalidValue;
}
static void Releasor(const HandleType& Handle) {
if (close(Handle) != 0) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::SystemError(__FILE__, __LINE__, errno, "close failed.");
}
}
};
struct MapViewTraits {
using HandleType = void*;
static inline const HandleType InvalidValue = MAP_FAILED;
[[nodiscard]]
static bool IsValid(const HandleType& Handle) noexcept {
return Handle != InvalidValue;
}
};
+131
View File
@@ -0,0 +1,131 @@
#include "X64ImageInterpreter.hpp"
[[nodiscard]]
X64ImageInterpreter X64ImageInterpreter::Parse(void* ImageBase) {
X64ImageInterpreter NewImage;
NewImage.pvt_MachHeader = reinterpret_cast<mach_header_64*>(ImageBase);
if (NewImage.pvt_MachHeader->magic != MH_MAGIC_64) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "Bad Image");
}
auto cmd_p = reinterpret_cast<load_command*>(NewImage.pvt_MachHeader + 1);
for (uint32_t i = 0; i < NewImage.pvt_MachHeader->ncmds; ++i) {
switch (cmd_p->cmd) {
case LC_SEGMENT_64: {
auto segcmd_p = reinterpret_cast<segment_command_64*>(cmd_p);
auto section_p = reinterpret_cast<section_64*>(segcmd_p + 1);
NewImage.pvt_SegmentCommands.emplace_back(segcmd_p);
for (uint32_t j = 0; j < segcmd_p->nsects; ++j) {
NewImage.pvt_Sections.ByIndex[NewImage.pvt_Sections.ByIndex.size()] = &section_p[j];
NewImage.pvt_Sections.ByMapAddress[section_p[j].addr] = &section_p[j];
NewImage.pvt_Sections.ByFileOffset[section_p[j].offset] = &section_p[j];
}
break;
}
case LC_DYSYMTAB: {
NewImage.pvt_DynamicSymbol.SegmentCommand = reinterpret_cast<dysymtab_command*>(cmd_p);
break;
}
case LC_SYMTAB: {
NewImage.pvt_Symbol.SegmentCommand = reinterpret_cast<symtab_command*>(cmd_p);
NewImage.pvt_Symbol.StringTable = NewImage.ImageOffset<char*>(NewImage.pvt_Symbol.SegmentCommand->stroff);
NewImage.pvt_Symbol.SymbolTable = NewImage.ImageOffset<nlist_64*>(NewImage.pvt_Symbol.SegmentCommand->symoff);
break;
}
case LC_DYLD_INFO_ONLY: { // NOLINT
NewImage.pvt_DynamicLoaderInfoOnly.SegmentCommand = reinterpret_cast<dyld_info_command*>(cmd_p);
}
default:
break;
}
cmd_p = reinterpret_cast<load_command*>(
reinterpret_cast<uint8_t*>(cmd_p) + cmd_p->cmdsize
);
}
return NewImage;
}
[[nodiscard]]
size_t X64ImageInterpreter::NumberOfSections() const noexcept {
return pvt_Sections.ByIndex.size();
}
[[nodiscard]]
section_64* X64ImageInterpreter::ImageSection(size_t Index) const {
auto it = pvt_Sections.ByIndex.find(Index);
if (it != pvt_Sections.ByIndex.cend()) {
return it->second;
} else {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "Section is not found.");
}
}
[[nodiscard]]
section_64* X64ImageInterpreter::ImageSection(const char* SegmentName, const char* SectionName) const {
for (auto segcmd_p : pvt_SegmentCommands) {
if (strncmp(SegmentName, segcmd_p->segname, sizeof(segcmd_p->segname)) == 0) {
auto sec_p = reinterpret_cast<section_64*>(segcmd_p + 1);
for (uint32_t i = 0; i < segcmd_p->nsects; ++i) {
if (strncmp(SectionName, sec_p[i].sectname, sizeof(sec_p[i].sectname)) == 0)
return &sec_p[i];
}
break;
}
}
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "Section is not found.");
}
[[nodiscard]]
section_64* X64ImageInterpreter::ImageSectionByOffset(uint32_t Offset) const {
for (const auto& it : pvt_Sections.ByFileOffset) {
if (it.first <= Offset && Offset < it.first + it.second->size) {
return it.second;
}
}
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "Section is not found.");
}
[[nodiscard]]
section_64* X64ImageInterpreter::ImageSectionByRva(uint64_t Rva) const {
for (const auto& it : pvt_Sections.ByMapAddress) {
if (it.first <= Rva && Rva < it.first + it.second->size) {
return it.second;
}
}
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "Section is not found.");
}
[[nodiscard]]
uint64_t X64ImageInterpreter::OffsetToRva(uint32_t Offset) const {
auto section = ImageSectionByOffset(Offset);
return section->addr + (Offset - section->offset);
}
[[nodiscard]]
uint32_t X64ImageInterpreter::RvaToOffset(uint64_t Rva) const {
auto section = ImageSectionByRva(Rva);
return section->offset + (Rva - section->addr);
}
[[nodiscard]]
nlist_64* X64ImageInterpreter::ImageSymbolTable() const noexcept {
return pvt_Symbol.SymbolTable;
}
+199
View File
@@ -0,0 +1,199 @@
#pragma once
#include <string.h> // NOLINT
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <vector>
#include <map>
#include "../common/Exception.hpp"
class X64ImageInterpreter {
public:
static constexpr uint64_t InvalidAddress = static_cast<uint64_t>(-1);
static constexpr uint32_t InvalidOffset = static_cast<uint32_t>(-1);
private:
mach_header_64* pvt_MachHeader;
std::vector<segment_command_64*> pvt_SegmentCommands;
struct {
std::map<size_t, section_64*> ByIndex;
std::map<uint64_t, section_64*> ByMapAddress;
std::map<uint32_t, section_64*> ByFileOffset;
} pvt_Sections;
struct {
dysymtab_command* SegmentCommand;
} pvt_DynamicSymbol;
struct {
symtab_command* SegmentCommand;
char* StringTable;
nlist_64* SymbolTable;
} pvt_Symbol;
struct {
dyld_info_command* SegmentCommand;
} pvt_DynamicLoaderInfoOnly;
X64ImageInterpreter() :
pvt_MachHeader(nullptr),
pvt_DynamicSymbol{},
pvt_Symbol{},
pvt_DynamicLoaderInfoOnly{} {}
public:
[[nodiscard]]
static X64ImageInterpreter Parse(void* ImageBase);
template<typename __ReturnType = void*>
[[nodiscard]]
__ReturnType ImageBase() const noexcept {
static_assert(std::is_pointer_v<__ReturnType>);
return reinterpret_cast<__ReturnType>(pvt_MachHeader);
}
template<typename __ReturnType = void*>
[[nodiscard]]
__ReturnType ImageOffset(size_t Offset) const noexcept {
static_assert(std::is_pointer_v<__ReturnType>);
return reinterpret_cast<__ReturnType>(
reinterpret_cast<uint8_t*>(pvt_MachHeader) + Offset
);
}
template<unsigned __CommandMacro>
[[nodiscard]]
auto CommandOf() const noexcept {
if constexpr (__CommandMacro == LC_DYSYMTAB) {
return pvt_DynamicSymbol.SegmentCommand;
} else if constexpr (__CommandMacro == LC_SYMTAB) {
return pvt_Symbol.SegmentCommand;
} else if constexpr (__CommandMacro == LC_DYLD_INFO_ONLY) { // NOLINT
return pvt_DynamicLoaderInfoOnly.SegmentCommand;
} else {
return nullptr;
}
}
[[nodiscard]]
size_t NumberOfSections() const noexcept;
[[nodiscard]]
section_64* ImageSection(size_t Index) const;
[[nodiscard]]
section_64* ImageSection(const char* SegmentName, const char* SectionName) const;
[[nodiscard]]
section_64* ImageSectionByOffset(uint32_t Offset) const;
[[nodiscard]]
section_64* ImageSectionByRva(uint64_t Rva) const;
template<typename __ReturnType>
[[nodiscard]]
__ReturnType SectionView(size_t Index) const {
auto Section = ImageSection(Index);
return ImageOffset<__ReturnType>(Section->offset);
}
template<typename __ReturnType>
[[nodiscard]]
__ReturnType SectionView(const char* SegmentName, const char* SectionName) const {
auto Section = ImageSection(SegmentName, SectionName);
return ImageOffset<__ReturnType>(Section->offset);
}
template<typename __ReturnType>
[[nodiscard]]
__ReturnType SectionView(section_64* Section) const {
return ImageOffset<__ReturnType>(Section->offset);
}
template<typename __ReturnType, typename __Hint>
[[nodiscard]]
__ReturnType SearchSection(size_t Index, __Hint&& Hint) const {
return SearchSection<__ReturnType>(ImageSection(Index), std::forward<__Hint>(Hint));
}
template<typename __ReturnType, typename __Hint>
[[nodiscard]]
__ReturnType SearchSection(const char* SegmentName, const char* SectionName, __Hint&& Hint) const {
return SearchSection<__ReturnType>(ImageSection(SegmentName, SectionName), std::forward<__Hint>(Hint));
}
template<typename __ReturnType, typename __Hint>
[[nodiscard]]
__ReturnType SearchSection(section_64* Section, __Hint&& Hint) const {
static_assert(std::is_pointer_v<__ReturnType>);
auto begin = SectionView<const uint8_t*>(Section);
auto end = begin + Section->size;
for (; begin < end; ++begin) {
if (Hint(begin) == true) {
return reinterpret_cast<__ReturnType>(const_cast<uint8_t*>(begin));
}
}
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "Data is not found.");
}
template<typename __Hint>
[[nodiscard]]
uint32_t SearchSectionOffset(size_t Index, __Hint&& Hint) const {
return SearchSection<uint8_t*>(Index, std::forward<__Hint>(Hint)) - ImageBase<uint8_t*>();
}
template<typename __Hint>
[[nodiscard]]
uint32_t SearchSectionOffset(const char* SegmentName, const char* SectionName, __Hint&& Hint) const {
return SearchSection<uint8_t*>(SegmentName, SectionName, std::forward<__Hint>(Hint)) - ImageBase<uint8_t*>();
}
template<typename __Hint>
[[nodiscard]]
uint32_t SearchSectionOffset(section_64* Section, __Hint&& Hint) const {
return SearchSection<uint8_t*>(Section, std::forward<__Hint>(Hint)) - ImageBase<uint8_t*>();
}
template<typename __Hint>
[[nodiscard]]
uint64_t SearchSectionRva(size_t Index, __Hint&& Hint) const {
auto Section = ImageSection(Index);
auto Offset = SearchSection<uint8_t*>(Section, std::forward<__Hint>(Hint)) - SectionView<uint8_t*>(Section);
return Section->addr + Offset;
}
template<typename __Hint>
[[nodiscard]]
uint64_t SearchSectionRva(const char* SegmentName, const char* SectionName, __Hint&& Hint) const {
auto Section = ImageSection(SegmentName, SectionName);
auto Offset = SearchSection<uint8_t*>(Section, std::forward<__Hint>(Hint)) - SectionView<uint8_t*>(Section);
return Section->addr + Offset;
}
template<typename __Hint>
[[nodiscard]]
uint64_t SearchSectionRva(section_64* Section, __Hint&& Hint) const {
auto Offset = SearchSection<uint8_t*>(Section, std::forward<__Hint>(Hint)) - SectionView<uint8_t*>(Section);
return Section->addr + Offset;
}
[[nodiscard]]
uint64_t OffsetToRva(uint32_t Offset) const;
[[nodiscard]]
uint32_t RvaToOffset(uint64_t Address) const;
[[nodiscard]]
nlist_64* ImageSymbolTable() const noexcept;
[[nodiscard]]
char* LookupStringTable(size_t Offset) const noexcept {
return pvt_Symbol.StringTable + Offset;
}
};
-105
View File
@@ -1,105 +0,0 @@
#include <tchar.h>
#include <windows.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#pragma comment(lib, "libcrypto.lib")
BOOL BackupNavicat(PTSTR NavicatFileName) {
TCHAR new_NavicatFileName[1024] = { };
if (NavicatFileName == nullptr)
NavicatFileName = TEXT("navicat.exe");
_stprintf_s(new_NavicatFileName, TEXT("%s%s"), NavicatFileName, TEXT(".backup"));
if (!CopyFile(NavicatFileName, new_NavicatFileName, TRUE)) {
switch (GetLastError()) {
case ERROR_FILE_NOT_FOUND:
_tprintf_s(TEXT("Cannot find %s.\r\n"), NavicatFileName);
break;
case ERROR_FILE_EXISTS:
_tprintf_s(TEXT("Backup file already exists.\r\n"));
break;
default:
_tprintf_s(TEXT("Unknown error. CODE: 0x%08x.\r\n"), GetLastError());
}
return FALSE;
}
_tprintf_s(TEXT("%s has been backed up.\r\n"), NavicatFileName);
return TRUE;
}
BOOL ReplaceNavicatPublicKey(HANDLE resUpdater, void* pemPublicKey, size_t length) {
return UpdateResource(resUpdater,
RT_RCDATA,
TEXT("ActivationPubKey"),
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
pemPublicKey, length);
}
RSA* GeneratePrivateKey() {
RSA* PrivateKey = RSA_generate_key(2048, RSA_F4, nullptr, nullptr);
BIO* PrivateKeyFile = BIO_new(BIO_s_file());
BIO_write_filename(PrivateKeyFile, "RegPrivateKey.pem");
PEM_write_bio_RSAPrivateKey(PrivateKeyFile, PrivateKey, nullptr, nullptr, 0, nullptr, nullptr);
BIO_free_all(PrivateKeyFile);
return PrivateKey;
}
int _tmain(int argc, TCHAR* argv[]) {
if (argc != 2 && argc != 3) {
_tprintf_s(TEXT("Usage:\r\n"));
_tprintf_s(TEXT(" navicat-patcher.exe <navicat.exe path>\r\n"));
return 0;
}
if (BackupNavicat(argv[1]) == FALSE)
return GetLastError();
RSA* PrivateKey = GeneratePrivateKey();
HANDLE hUpdater = BeginUpdateResource(argv[1], FALSE);
if (hUpdater == NULL) {
_tprintf_s(TEXT("Cannot open file. CODE: 0x%08x\r\n"), GetLastError());
RSA_free(PrivateKey);
return GetLastError();
}
char pemPublicKey[1024] = { };
{
char temp_buf[1024] = { };
BIO* BIO_pemPublicKey = BIO_new(BIO_s_mem());
PEM_write_bio_RSA_PUBKEY(BIO_pemPublicKey, PrivateKey);
BIO_read(BIO_pemPublicKey, temp_buf, 1024);
BIO_free_all(BIO_pemPublicKey);
char* pemPublicKey_ptr = pemPublicKey;
for (size_t i = 0; i < 1024; ++i) {
if (temp_buf[i] == '\n')
*(pemPublicKey_ptr++) = '\r';
if (temp_buf[i] == 0)
break;
*(pemPublicKey_ptr++) = temp_buf[i];
}
}
if (ReplaceNavicatPublicKey(hUpdater, pemPublicKey, strlen(pemPublicKey)) == FALSE) {
_tprintf_s(TEXT("Cannot replace public key. CODE: 0x%08x\r\n"), GetLastError());
EndUpdateResource(hUpdater, TRUE);
return GetLastError();
} else {
_tprintf_s(TEXT("Public key has been replaced.\r\n"));
EndUpdateResource(hUpdater, FALSE);
}
_tprintf_s(TEXT("Success!.\r\n"));
RSA_free(PrivateKey);
return 0;
}
+259
View File
@@ -0,0 +1,259 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <plist/plist++.h>
#include <string>
#include "../common/ExceptionSystem.hpp"
#include "../common/ResourceOwned.hpp"
#include "ResourceTraitsUnix.hpp"
#include "PatchSolutions.hpp"
static void Welcome() {
puts("***************************************************");
puts("* Navicat Patcher by @DoubleLabyrinth *");
puts("* Version: 4.0 *");
puts("***************************************************");
puts("");
puts("Press Enter to continue or Ctrl + C to abort.");
getchar();
}
static void Help() {
puts("***************************************************");
puts("* Navicat Patcher by @DoubleLabyrinth *");
puts("* Version: 4.0 *");
puts("***************************************************");
puts("");
puts("Usage:");
puts(" navicat-patcher <Navicat installation path> [RSA-2048 Private Key File]");
puts("");
puts(" <Navicat installation path> Path to `Navicat Premium.app`.");
puts(" Example:");
puts(" /Applications/Navicat\\ Premium.app/");
puts(" This parameter must be specified.");
puts("");
puts(" [RSA-2048 Private Key File] Path to a PEM-format RSA-2048 private key file.");
puts(" This parameter is optional.");
puts("");
}
static std::string GetNavicatVersion(const char* AppPath) {
ResourceOwned hInfoPlist(FileHandleTraits{});
ResourceOwned InfoPlist(CppObjectTraits<PList::Dictionary>{});
hInfoPlist.TakeOver(open((std::string(AppPath) + "/Contents/Info.plist").c_str(), O_RDONLY));
if (hInfoPlist.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::SystemError(__FILE__, __LINE__, errno, "Failed to open Contents/Info.plist.");
}
struct stat statInfoPlist = {};
if (fstat(hInfoPlist, &statInfoPlist) != 0) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::SystemError(__FILE__, __LINE__, errno, "Failed to get file size of Contents/Info.plist.");
}
std::string contentInfoPlist(statInfoPlist.st_size, '\x00');
if (read(hInfoPlist, contentInfoPlist.data(), contentInfoPlist.size()) != contentInfoPlist.size()) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::SystemError(__FILE__, __LINE__, errno, "Failed to read Contents/Info.plist.");
}
InfoPlist.TakeOver(dynamic_cast<PList::Dictionary*>(PList::Structure::FromXml(contentInfoPlist)));
if (InfoPlist.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "Failed to parse Contents/Info.plist.");
}
auto kv = InfoPlist->Find("CFBundleShortVersionString");
if (kv == InfoPlist->End()) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "Cannot find CFBundleShortVersionString in Contents/Info.plist.");
}
if (kv->second->GetType() == PLIST_STRING) {
return dynamic_cast<PList::String*>(kv->second)->GetValue();
} else {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "Failed to get Navicat version.");
}
}
static void LoadKey(RSACipher& RsaCipher, const char* RsaKeyFileName,
PatchSolution* lpSolution0,
PatchSolution* lpSolution1,
PatchSolution* lpSolution2) {
if (RsaKeyFileName) {
RsaCipher.ImportKeyFromFile<RSAKeyType::PrivateKey, RSAKeyFormat::PEM>(RsaKeyFileName);
if ((lpSolution0 && !lpSolution0->CheckKey(RsaCipher)) ||
(lpSolution1 && !lpSolution1->CheckKey(RsaCipher)) ||
(lpSolution2 && !lpSolution2->CheckKey(RsaCipher)))
{
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::Exception(__FILE__, __LINE__, "The RSA private key you provide cannot be used.");
}
} else {
puts("");
puts("[*] Generating new RSA private key, it may take a long time...");
do {
RsaCipher.GenerateKey(2048);
} while ((lpSolution0 && !lpSolution0->CheckKey(RsaCipher)) ||
(lpSolution1 && !lpSolution1->CheckKey(RsaCipher)) ||
(lpSolution2 && !lpSolution2->CheckKey(RsaCipher))); // re-generate RSA key if CheckKey return false
RsaCipher.ExportKeyToFile<RSAKeyType::PrivateKey, RSAKeyFormat::PEM>("RegPrivateKey.pem");
puts("[+] New RSA private key has been saved to RegPrivateKey.pem.");
}
std::string PublicKeyPEM = RsaCipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
puts("");
puts("[*] Your RSA public key:");
puts(PublicKeyPEM.c_str());
}
int main(int argc, char* argv[]) {
if (argc != 2 && argc != 3) {
Help();
return -1;
} else {
Welcome();
try {
RSACipher RsaCipher;
ResourceOwned Solution0(CppObjectTraits<PatchSolution>{});
ResourceOwned Solution1(CppObjectTraits<PatchSolution>{});
ResourceOwned Solution2(CppObjectTraits<PatchSolution>{});
ResourceOwned hMainApp(FileHandleTraits{}, open((std::string(argv[1]) + "/Contents/MacOS/Navicat Premium").c_str(), O_RDWR));
if (hMainApp.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::SystemError(__FILE__, __LINE__, errno, "open failed.");
}
struct stat statMainApp = {};
if (fstat(hMainApp, &statMainApp) != 0) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::SystemError(__FILE__, __LINE__, errno, "fstat failed.");
}
ResourceOwned lpMainApp(MapViewTraits{},
mmap(nullptr, static_cast<size_t>(statMainApp.st_size), PROT_READ | PROT_WRITE, MAP_SHARED, hMainApp, 0),
[&statMainApp](void* p) { munmap(p, statMainApp.st_size); }
);
if (lpMainApp.IsValid() == false) {
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::SystemError(__FILE__, __LINE__, errno, "mmap failed.");
}
int Ver0, Ver1, Ver2;
if (sscanf(GetNavicatVersion(argv[1]).c_str(), "%d.%d.%d", &Ver0, &Ver1, &Ver2) != 3) { // NOLINT
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::SystemError(__FILE__, __LINE__, errno, "Failed to get version of Navicat.");
}
X64ImageInterpreter MainApp = X64ImageInterpreter::Parse(lpMainApp);
printf("[*] Your Navicat version: %d.%d.%d\n", Ver0, Ver1, Ver2);
printf("\n");
Solution0.TakeOver(new PatchSolution0(MainApp));
Solution1.TakeOver(new PatchSolution1(MainApp));
Solution2.TakeOver(new PatchSolution2(MainApp));
if (Solution0->FindPatchOffset() == false) {
Solution0.Release();
}
if (Solution1->FindPatchOffset() == false) {
Solution1.Release();
}
if (Solution2->FindPatchOffset() == false) {
Solution2.Release();
}
//
// Begin strategies by different Navicat versions
//
if (Ver0 < 12) { // ver < 12.0.0
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
throw nkg::SystemError(__FILE__, __LINE__, errno, "Unsupported version of Navicat.");
} else if (Ver0 == 12 && Ver1 == 0 && Ver2 < 24) { // ver < 12.0.24
std::string path(argv[1]);
while(path.back() == '/') {
path.pop_back();
}
printf("[*] Your Navicat version is < 12.0.24. So there would be nothing patched.\n");
printf(" Just use `openssl` to generate `RegPrivateKey.pem` and `rpk` file:\n");
printf(" openssl genrsa -out RegPrivateKey.pem 2048\n");
printf(" openssl rsa -in RegPrivateKey.pem -pubout -out rpk\n");
printf(" and replace `%s/Contents/Resources/rpk` with the `rpk` file you just generated.\n", path.c_str());
printf("\n");
return 0;
} else if (Ver0 == 12 && (Ver1 == 0 || (Ver1 == 1 && Ver2 < 14))) { // 12.0.24 <= ver && ver < 12.1.14
// In this case, Solution0 must be applied
if (Solution0.IsValid() == false) {
puts("[-] Patch abort. None of PatchSolutions will be applied.");
puts(" Are you sure your Navicat has not been patched before?");
return -1;
}
} else if (Ver0 == 12 && Ver1 == 1 && Ver2 == 14) { // ver == 12.1.14
// In this case, Solution0 and Solution1 must be applied
if ((Solution0.IsValid() && Solution1.IsValid()) == false) {
puts("[-] Patch abort. None of PatchSolutions will be applied.");
puts(" Are you sure your Navicat has not been patched before?");
return -1;
}
} else { // ver > 12.1.14
// In this case, Solution0 and Solution2 must be applied
if ((Solution0.IsValid() && Solution2.IsValid()) == false) {
puts("[-] Patch abort. None of PatchSolutions will be applied.");
puts(" Are you sure your Navicat has not been patched before?");
return -1;
}
}
//
// End strategies by different Navicat versions
//
LoadKey(RsaCipher, argc == 3 ? argv[2] : nullptr, Solution0, Solution1, Solution2);
if (Solution0.IsValid()) {
Solution0->MakePatch(RsaCipher);
}
if (Solution1.IsValid()) {
Solution1->MakePatch(RsaCipher);
}
if (Solution2.IsValid()) {
Solution2->MakePatch(RsaCipher);
}
if (Solution0.IsValid())
puts("[+] PatchSolution0 has been applied.");
if (Solution1.IsValid())
puts("[+] PatchSolution1 has been applied.");
if (Solution2.IsValid())
puts("[+] PatchSolution2 has been applied.");
puts("");
puts("**************************************************************");
puts("* Patch has been done successfully. Have fun and enjoy~~ *");
puts("* DO NOT FORGET TO SIGN NAVICAT BY YOUR CERTIFICATE!!! *");
puts("**************************************************************");
return 0;
} catch (nkg::Exception& e) {
printf("[-] %s:%zu -> \n", e.File(), e.Line());
printf(" %s\n", e.Message());
if (e.HasErrorCode()) {
printf(" %s\n", e.ErrorString());
}
return -1;
}
}
}
-162
View File
@@ -1,162 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{30BE8CAB-6137-4441-9F64-599D0A6EEA0C}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>navicatpatcher</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>D:\OpenSSL-Win64\include;$(IncludePath)</IncludePath>
<LibraryPath>D:\OpenSSL-Win64\lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>D:\OpenSSL-Win64\include;$(IncludePath)</IncludePath>
<LibraryPath>D:\OpenSSL-Win64\lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="_tmain.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="_tmain.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
</Project>