Compare commits
No commits in common. "v1.7" and "windows" have entirely different histories.
68
.github/workflows/build.yml
vendored
Normal file
68
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
name: navicat-keygen builds
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
navicat-keygen-x86:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
shell: pwsh
|
||||
run: |
|
||||
pushd .
|
||||
cd ${env:VCPKG_INSTALLATION_ROOT}
|
||||
git pull
|
||||
vcpkg install openssl:x86-windows-static
|
||||
vcpkg install unicorn:x86-windows-static
|
||||
vcpkg install fmt:x86-windows-static
|
||||
vcpkg install rapidjson:x86-windows-static
|
||||
vcpkg install keystone:x86-windows-static
|
||||
popd
|
||||
|
||||
- name: Clone source
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.1
|
||||
|
||||
- name: Build project
|
||||
run: |
|
||||
vcpkg integrate install
|
||||
msbuild navicat-keygen.sln /p:Configuration=Release /p:Platform=x86
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: navicat-keygen-x86.zip
|
||||
path: bin/x86-Release/*.exe
|
||||
|
||||
navicat-keygen-x64:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pushd .
|
||||
cd ${env:VCPKG_INSTALLATION_ROOT}
|
||||
git pull
|
||||
vcpkg install openssl:x64-windows-static
|
||||
vcpkg install unicorn:x64-windows-static
|
||||
vcpkg install fmt:x64-windows-static
|
||||
vcpkg install rapidjson:x64-windows-static
|
||||
vcpkg install keystone:x64-windows-static
|
||||
popd
|
||||
|
||||
- name: Clone source
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.1
|
||||
|
||||
- name: Build project
|
||||
run: |
|
||||
vcpkg integrate install
|
||||
msbuild navicat-keygen.sln /p:Configuration=Release /p:Platform=x64
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: navicat-keygen-x64.zip
|
||||
path: bin/x64-Release/*.exe
|
||||
291
.gitignore
vendored
291
.gitignore
vendored
@ -1,289 +1,4 @@
|
||||
## 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
|
||||
.vscode/
|
||||
bin/
|
||||
obj/
|
||||
|
||||
304
README.md
304
README.md
@ -1,301 +1,35 @@
|
||||
# Navicat Keygen
|
||||
# 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__
|
||||
Previous previous code is archived in [`windows-archived`](https://notabug.org/doublesine/navicat-keygen/src/windows-archived) branch for the reason that previous previous code contains 3rd binary libraries and it gets quite big :-(
|
||||
|
||||
It is a __RSA-2048__ public key that Navicat used to encrypt or decrypt offline activation information.
|
||||
Previous code is archived in [`windows-archived2`](https://notabug.org/doublesine/navicat-keygen/src/windows-archived2) branch for the reason that Navicat has come to version 16.x.x which I think should be a milestone and I decide to obsolete previous code and rewrite new one.
|
||||
|
||||
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:
|
||||
When you git-clone this repo, please add `--single-branch` flag so that archived branches won't be cloned to your computer, which saves your time and disk.
|
||||
|
||||
> -----BEGIN PUBLIC KEY-----
|
||||
> MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
|
||||
> qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
|
||||
> a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
|
||||
> R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
|
||||
> WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
|
||||
> YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
|
||||
> awIDAQAB
|
||||
> -----END PUBLIC KEY-----
|
||||
```console
|
||||
$ git clone -b windows --single-branch https://notabug.org/doublesine/navicat-keygen.git
|
||||
```
|
||||
|
||||
If you have the corresponding private key, please tell me. I would be very appreciated for your generous.
|
||||
## 1. How does it work?
|
||||
|
||||
__NOTICE:__
|
||||
see [here](doc/how-does-it-work.md). (WATING TO BE UPDATED)
|
||||
|
||||
Start from __Navicat Premium 12.0.25__, Navicat do not load this public key from resource in `navicat.exe`. Actually the public key is stored in `libcc.dll` and encrypted. And to avoid being replaced easily, the public key is split into 5 parts:
|
||||
## 2. How to build?
|
||||
|
||||
The content below is discovered from `libcc.dll` of Navicat Premium x64 12.0.25 Simplified Chinese version. SHA256 value is `607e0a84c75966b00f3d12fa833e91d159e4f51ac51b6ba66f98d0c3cbefdce0`. I do not guaranteed that __offset__ value is absolutely correct in other versions. But __char string__ and __immediate values__ is highly possible to be found.
|
||||
see [here](doc/how-to-build.md).
|
||||
|
||||
1. At file offset `+ 0x1A12090` in `libcc.dll`, stored as __char string__:
|
||||
## 3. How to use?
|
||||
|
||||
> "D75125B70767B94145B47C1CB3C0755E
|
||||
> 7CCB8825C5DCE0C58ACF944E08280140
|
||||
> 9A02472FAFFD1CD77864BB821AE36766
|
||||
> FEEDE6A24F12662954168BFA314BD950
|
||||
> 32B9D82445355ED7BC0B880887D650F5"
|
||||
see [here](doc/how-to-use.md).
|
||||
|
||||
2. At file offset `+ 0x59D799` in `libcc.dll`, stored as __immediate value__ in a instruction:
|
||||
## 4. Contributor
|
||||
|
||||
> 0xFE 0xEA 0xBC 0x01
|
||||
* Deltafox79
|
||||
|
||||
In decimal: `29158142`
|
||||
* dragonflylee
|
||||
|
||||
3. At file offset `+ 0x1A11DA0` in `libcc.dll`, stored as __char string__:
|
||||
|
||||
> "E1CED09B9C2186BF71A70C0FE2F1E0AE
|
||||
> F3BD6B75277AAB20DFAF3D110F75912B
|
||||
> FB63AC50EC4C48689D1502715243A79F
|
||||
> 39FF2DE2BF15CE438FF885745ED54573
|
||||
> 850E8A9F40EE2FF505EB7476F95ADB78
|
||||
> 3B28CA374FAC4632892AB82FB3BF4715
|
||||
> FCFE6E82D03731FC3762B6AAC3DF1C3B
|
||||
> C646FE9CD3C62663A97EE72DB932A301
|
||||
> 312B4A7633100C8CC357262C39A2B3A6
|
||||
> 4B224F5276D5EDBDF0804DC3AC4B8351
|
||||
> 62BB1969EAEBADC43D2511D6E0239287
|
||||
> 81B167A48273B953378D3D2080CC0677
|
||||
> 7E8A2364F0234B81064C5C739A8DA28D
|
||||
> C5889072BF37685CBC94C2D31D0179AD
|
||||
> 86D8E3AA8090D4F0B281BE37E0143746
|
||||
> E6049CCC06899401264FA471C016A96C
|
||||
> 79815B55BBC26B43052609D9D175FBCD
|
||||
> E455392F10E51EC162F51CF732E6BB39
|
||||
> 1F56BBFD8D957DF3D4C55B71CEFD54B1
|
||||
> 9C16D458757373E698D7E693A8FC3981
|
||||
> 5A8BF03BA05EA8C8778D38F9873D62B4
|
||||
> 460F41ACF997C30E7C3AF025FA171B5F
|
||||
> 5AD4D6B15E95C27F6B35AD61875E5505
|
||||
> 449B4E"
|
||||
|
||||
4. At file offset `+ 0x59D77F` in `libcc.dll`, stored as __immediate value__ in a instruction:
|
||||
|
||||
> 0x59 0x08 0x01 0x00 (in decimal )
|
||||
|
||||
In decimal: `67673`
|
||||
|
||||
5. At file offset `+ 0x1A11D8C` in `libcc.dll`, stored as __char string__:
|
||||
|
||||
> "92933"
|
||||
|
||||
Then output encrypted public key with format `"%s%d%s%d%s"`, the order is the same as it list:
|
||||
|
||||
> D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7BC0B880887D650F529158142E1CED09B9C2186BF71A70C0FE2F1E0AEF3BD6B75277AAB20DFAF3D110F75912BFB63AC50EC4C48689D1502715243A79F39FF2DE2BF15CE438FF885745ED54573850E8A9F40EE2FF505EB7476F95ADB783B28CA374FAC4632892AB82FB3BF4715FCFE6E82D03731FC3762B6AAC3DF1C3BC646FE9CD3C62663A97EE72DB932A301312B4A7633100C8CC357262C39A2B3A64B224F5276D5EDBDF0804DC3AC4B835162BB1969EAEBADC43D2511D6E023928781B167A48273B953378D3D2080CC06777E8A2364F0234B81064C5C739A8DA28DC5889072BF37685CBC94C2D31D0179AD86D8E3AA8090D4F0B281BE37E0143746E6049CCC06899401264FA471C016A96C79815B55BBC26B43052609D9D175FBCDE455392F10E51EC162F51CF732E6BB391F56BBFD8D957DF3D4C55B71CEFD54B19C16D458757373E698D7E693A8FC39815A8BF03BA05EA8C8778D38F9873D62B4460F41ACF997C30E7C3AF025FA171B5F5AD4D6B15E95C27F6B35AD61875E5505449B4E6767392933
|
||||
|
||||
This encrypted public key can be decrypted by my another repo: [how-does-navicat-encrypt-password](https://github.com/DoubleLabyrinth/how-does-navicat-encrypt-password), while the key used is `b'23970790'`
|
||||
|
||||
Example:
|
||||
|
||||
```cmd
|
||||
E:\GitHub>git clone https://github.com/DoubleLabyrinth/how-does-navicat-encrypt-password.git
|
||||
...
|
||||
E:\GitHub>cd how-does-navicat-encrypt-password\python3
|
||||
E:\GitHub\how-does-navicat-encrypt-password\python3>python
|
||||
Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> from NavicatCrypto import *
|
||||
>>> cipher = Navicat11Crypto(b'23970790')
|
||||
>>> print(cipher.DecryptString('D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7BC0B880887D650F529158142E1CED09B9C2186BF71A70C0FE2F1E0AEF3BD6B75277AAB20DFAF3D110F75912BFB63AC50EC4C48689D1502715243A79F39FF2DE2BF15CE438FF885745ED54573850E8A9F40EE2FF505EB7476F95ADB783B28CA374FAC4632892AB82FB3BF4715FCFE6E82D03731FC3762B6AAC3DF1C3BC646FE9CD3C62663A97EE72DB932A301312B4A7633100C8CC357262C39A2B3A64B224F5276D5EDBDF0804DC3AC4B835162BB1969EAEBADC43D2511D6E023928781B167A48273B953378D3D2080CC06777E8A2364F0234B81064C5C739A8DA28DC5889072BF37685CBC94C2D31D0179AD86D8E3AA8090D4F0B281BE37E0143746E6049CCC06899401264FA471C016A96C79815B55BBC26B43052609D9D175FBCDE455392F10E51EC162F51CF732E6BB391F56BBFD8D957DF3D4C55B71CEFD54B19C16D458757373E698D7E693A8FC39815A8BF03BA05EA8C8778D38F9873D62B4460F41ACF997C30E7C3AF025FA171B5F5AD4D6B15E95C27F6B35AD61875E5505449B4E6767392933'))
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
|
||||
qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
|
||||
a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
|
||||
R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
|
||||
WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
|
||||
YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
|
||||
awIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
```
|
||||
|
||||
* __Request Code__
|
||||
|
||||
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__.
|
||||
|
||||
* __Offline Activation Request Information__
|
||||
|
||||
It is just a JSON-style ASCII string which contains 3 items. Respectively they are `"K"`, `"DI"` and `"P"`, which represent __snKey__, __DeviceIdentifier__ (related with your machine), __Platform__ (Appropriately speaking, it should be OS Type).
|
||||
|
||||
Like:
|
||||
> {"K": "xxxxxxxxxxxxxxxx", "DI": "yyyyyyyyyyyyy", "P": "WIN8"}
|
||||
|
||||
* __Activation Code__
|
||||
|
||||
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).
|
||||
|
||||
* __Offline Activation Response Information__
|
||||
|
||||
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`'.
|
||||
|
||||
`"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).
|
||||
|
||||
`"T"` can be omitted.
|
||||
|
||||
* __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 __data[10]__ to represent the 10-bytes-long data.
|
||||
|
||||
1. __data[0]__ and __data[1]__ must be `0x68` and `0x2A` respectively.
|
||||
|
||||
_`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.`_
|
||||
|
||||
| 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 |
|
||||
|
||||
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.
|
||||
|
||||
## 4. How to use
|
||||
1. Build patcher and keygen in Release configuration or download the latest release.
|
||||
|
||||
2. Replace __Navicat Activation Public Key__ in `navicat.exe` or `libcc.dll`.
|
||||
Example:
|
||||
|
||||
* For Navicat Premium version < 12.0.25
|
||||
```bash
|
||||
E:\GitHub\navicat-keygen\x64\Release>navicat-patcher.exe "D:\Program Files\PremiumSoft\Navicat Premium 12"
|
||||
D:\Program Files\PremiumSoft\Navicat Premium 12\navicat.exe has been backed up.
|
||||
Public key has been replaced.
|
||||
Success!
|
||||
```
|
||||
|
||||
* For Navicat Premium version >= 12.0.25
|
||||
```bash
|
||||
E:\GitHub\navicat-keygen\x64\Release>navicat-patcher.exe "D:\Program Files\PremiumSoft\Navicat Premium 12"
|
||||
D:\Program Files\PremiumSoft\Navicat Premium 12\libcc.dll has been backed up.
|
||||
Public key has been replaced.
|
||||
Success!
|
||||
```
|
||||
You may wait for a few seconds or even longer, because patcher is search for a appropriate RSA key. Finally you will get `RegPrivateKey.pem` file at current directory.
|
||||
|
||||
If you do not want to search, use `RegPrivateKey.pem` in my latest release, then:
|
||||
```bash
|
||||
E:\GitHub\navicat-keygen\x64\Release>navicat-patcher.exe "D:\Program Files\PremiumSoft\Navicat Premium 12" RegPrivateKey.pem
|
||||
D:\Program Files\PremiumSoft\Navicat Premium 12\libcc.dll has been backed up.
|
||||
Public key has been replaced.
|
||||
Success!
|
||||
```
|
||||
|
||||
3. Then in console:
|
||||
|
||||
```bash
|
||||
E:\GitHub\navicat-keygen\x64\Release>navicat-keygen.exe RegPrivateKey.pem
|
||||
|
||||
```
|
||||
|
||||
You will get a __snKey__ and be asked to input your name and organization.
|
||||
Just input and then you will be asked to input the request code. Now __DO NOT CLOSE KEYGEN__.
|
||||
|
||||
4. Disconnect network and open Navicat Premium, find and click `Registration`. Then input `Registration Key` by snKey that keygen gave. Then click `Activate`.
|
||||
|
||||
5. Generally online activation will failed and Navicat will ask you do `Manual Activation`, just choose it.
|
||||
|
||||
6. Copy your request code and paste it in keygen. Input empty line to tell keygen that your input ends.
|
||||
|
||||
7. Then you will get activation code which looks like a Base64 string. Just copy it and paste it in Navicat `Manual Activation` window, then click Activate. If nothing is wrong, activation should be done successfully.
|
||||
* zenuo
|
||||
|
||||
34
README.zh-CN.md
Normal file
34
README.zh-CN.md
Normal file
@ -0,0 +1,34 @@
|
||||
# navicat-keygen for windows
|
||||
|
||||
这份repo将会告诉你Navicat是怎么完成离线激活的。
|
||||
|
||||
第一次归档的代码位于 [`windows-archived`](https://notabug.org/doublesine/navicat-keygen/src/windows-archived) 分支。归档原因:包含第三方二进制库,项目过大。
|
||||
|
||||
第二次归档的代码位于 [`windows-archived2`](https://notabug.org/doublesine/navicat-keygen/src/windows-archived2) 分支。归档原因:Navicat进入16.x.x版本,本项目打算进行重构。
|
||||
|
||||
当你clone该仓库的时候,请使用 `--single-branch` 选项,以此避免clone到已被归档的分支、以及节省你的时间和磁盘空间。
|
||||
|
||||
```console
|
||||
$ git clone -b windows --single-branch https://notabug.org/doublesine/navicat-keygen.git
|
||||
```
|
||||
|
||||
## 1. 注册机是怎么工作的?
|
||||
|
||||
见[这里](doc/how-does-it-work.zh-CN.md)。
|
||||
|
||||
## 2. 如何编译?
|
||||
|
||||
见[这里](doc/how-to-build.zh-CN.md)。
|
||||
|
||||
## 3. 如何使用这个注册机?
|
||||
|
||||
见[这里](doc/how-to-use.zh-CN.md)。
|
||||
|
||||
## 4. 贡献者
|
||||
|
||||
* Deltafox79
|
||||
|
||||
* dragonflylee
|
||||
|
||||
* zenuo
|
||||
|
||||
49
common/common.vcxitems
Normal file
49
common/common.vcxitems
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<MSBuildAllProjects Condition="'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' < '16.0'">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
<HasSharedItems>true</HasSharedItems>
|
||||
<ItemsProjectGuid>{6d81a756-475a-4093-919e-3e9217f662ca}</ItemsProjectGuid>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ProjectCapability Include="SourceItemsFromImports" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)cp_converter.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)exception.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)exceptions\index_exception.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)exceptions\key_exception.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)exceptions\win32_exception.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)exceptions\not_implemented_exception.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)exceptions\operation_canceled_exception.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)exceptions\overflow_exception.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\keystone\keystone_handle.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\openssl\bignum.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\openssl\bio.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\openssl\bio_chain.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\openssl\decoder_ctx.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\openssl\encoder_ctx.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\openssl\evp_cipher_ctx.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\openssl\evp_pkey.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\openssl\evp_pkey_ctx.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\openssl\rsa.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\unicorn\unicorn_handle.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\win32\map_view_ptr.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\cxx_dynamic_array_traits.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\cxx_object_traits.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\win32\file_handle.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\win32\generic_handle.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_traits\win32\local_alloc.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)resource_wrapper.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)rsa_cipher.hpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)exceptions\win32_exception.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)rsa_cipher.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
6
common/common.vcxitems.user
Normal file
6
common/common.vcxitems.user
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ShowAllFiles>true</ShowAllFiles>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
79
common/cp_converter.hpp
Normal file
79
common/cp_converter.hpp
Normal file
@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <windows.h>
|
||||
#include "exceptions/win32_exception.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\common\\cp_converter.hpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
template<int from_cp, int to_cp>
|
||||
struct cp_converter {
|
||||
static std::string convert(std::string_view from_string) {
|
||||
if constexpr (from_cp == to_cp) {
|
||||
return from_string;
|
||||
} else {
|
||||
if (from_cp == CP_ACP && GetACP() == to_cp) {
|
||||
return from_string;
|
||||
} else {
|
||||
return cp_converter<-1, to_cp>::convert(cp_converter<from_cp, -1>::convert(from_string));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<int from_cp>
|
||||
struct cp_converter<from_cp, -1> {
|
||||
static std::wstring convert(std::string_view from_string) {
|
||||
int len;
|
||||
|
||||
len = MultiByteToWideChar(from_cp, 0, from_string.data(), -1, NULL, 0);
|
||||
if (len <= 0) {
|
||||
throw ::nkg::exceptions::win32_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), u8"MultiByteToWideChar failed.");
|
||||
}
|
||||
|
||||
std::wstring to_string(len, 0);
|
||||
|
||||
len = MultiByteToWideChar(from_cp, 0, from_string.data(), -1, to_string.data(), len);
|
||||
if (len <= 0) {
|
||||
throw ::nkg::exceptions::win32_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), u8"MultiByteToWideChar failed.");
|
||||
}
|
||||
|
||||
while (to_string.length() > 0 && to_string.back() == 0) {
|
||||
to_string.pop_back();
|
||||
}
|
||||
|
||||
return to_string;
|
||||
}
|
||||
};
|
||||
|
||||
template<int to_cp>
|
||||
struct cp_converter<-1, to_cp> {
|
||||
static std::string convert(std::wstring_view from_string) {
|
||||
int len;
|
||||
|
||||
len = WideCharToMultiByte(to_cp, 0, from_string.data(), -1, NULL, 0, NULL, NULL);
|
||||
if (len <= 0) {
|
||||
throw ::nkg::exceptions::win32_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), u8"WideCharToMultiByte failed.");
|
||||
}
|
||||
|
||||
std::string to_string(len, 0);
|
||||
|
||||
len = WideCharToMultiByte(to_cp, 0, from_string.data(), -1, to_string.data(), len, NULL, NULL);
|
||||
if (len <= 0) {
|
||||
throw ::nkg::exceptions::win32_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), u8"WideCharToMultiByte failed.");
|
||||
}
|
||||
|
||||
while (to_string.length() > 0 && to_string.back() == 0) {
|
||||
to_string.pop_back();
|
||||
}
|
||||
|
||||
return to_string;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
86
common/exception.hpp
Normal file
86
common/exception.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class exception : public std::exception {
|
||||
private:
|
||||
int m_source_line;
|
||||
std::string m_source_file;
|
||||
std::string m_custom_message;
|
||||
std::vector<std::string> m_hints;
|
||||
|
||||
public:
|
||||
[[noreturn]]
|
||||
static void trap_then_terminate() {
|
||||
#if _MSC_VER
|
||||
__debugbreak();
|
||||
#elif defined(__GNUC__) || defined(__GNUG__) || defined(__clang__)
|
||||
__builtin_trap();
|
||||
|
||||
#else
|
||||
#error "exception.hpp: unknown compiler is detected."
|
||||
#endif
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
exception(std::string_view file, int line, std::string_view message) noexcept :
|
||||
std::exception(), // don't pass `char*` to `std::exception`, because it is not documented in c++ standard.
|
||||
m_source_line(line),
|
||||
m_source_file(file),
|
||||
m_custom_message(message) {}
|
||||
|
||||
[[nodiscard]]
|
||||
int source_line() const noexcept {
|
||||
return m_source_line;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const std::string& source_file() const noexcept {
|
||||
return m_source_file;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const std::string& custom_message() const noexcept {
|
||||
return m_custom_message;
|
||||
}
|
||||
|
||||
exception& push_hint(std::string_view hint) noexcept {
|
||||
m_hints.emplace_back(hint);
|
||||
return *this;
|
||||
}
|
||||
|
||||
exception& pop_hint() noexcept {
|
||||
m_hints.pop_back();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& hints() const noexcept {
|
||||
return m_hints;
|
||||
}
|
||||
|
||||
virtual const char* what() const noexcept override {
|
||||
return m_custom_message.c_str();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool error_code_exists() const noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual intptr_t error_code() const noexcept {
|
||||
trap_then_terminate();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual const std::string& error_string() const noexcept {
|
||||
trap_then_terminate();
|
||||
}
|
||||
|
||||
virtual ~exception() = default;
|
||||
};
|
||||
|
||||
}
|
||||
10
common/exceptions/index_exception.hpp
Normal file
10
common/exceptions/index_exception.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include "../exception.hpp"
|
||||
|
||||
namespace nkg::exceptions {
|
||||
|
||||
class index_exception : public ::nkg::exception {
|
||||
using ::nkg::exception::exception;
|
||||
};
|
||||
|
||||
}
|
||||
10
common/exceptions/key_exception.hpp
Normal file
10
common/exceptions/key_exception.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include "../exception.hpp"
|
||||
|
||||
namespace nkg::exceptions {
|
||||
|
||||
class key_exception : public ::nkg::exception {
|
||||
using ::nkg::exception::exception;
|
||||
};
|
||||
|
||||
}
|
||||
10
common/exceptions/not_implemented_exception.hpp
Normal file
10
common/exceptions/not_implemented_exception.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include "../exception.hpp"
|
||||
|
||||
namespace nkg::exceptions {
|
||||
|
||||
class not_implemented_exception : public ::nkg::exception {
|
||||
using ::nkg::exception::exception;
|
||||
};
|
||||
|
||||
}
|
||||
10
common/exceptions/operation_canceled_exception.hpp
Normal file
10
common/exceptions/operation_canceled_exception.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include "../exception.hpp"
|
||||
|
||||
namespace nkg::exceptions {
|
||||
|
||||
class operation_canceled_exception : public ::nkg::exception {
|
||||
using ::nkg::exception::exception;
|
||||
};
|
||||
|
||||
}
|
||||
10
common/exceptions/overflow_exception.hpp
Normal file
10
common/exceptions/overflow_exception.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include "../exception.hpp"
|
||||
|
||||
namespace nkg::exceptions {
|
||||
|
||||
class overflow_exception : public ::nkg::exception {
|
||||
using ::nkg::exception::exception;
|
||||
};
|
||||
|
||||
}
|
||||
30
common/exceptions/win32_exception.cpp
Normal file
30
common/exceptions/win32_exception.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include "win32_exception.hpp"
|
||||
#include "../resource_wrapper.hpp"
|
||||
#include "../resource_traits/win32/local_alloc.hpp"
|
||||
#include "../cp_converter.hpp"
|
||||
|
||||
namespace nkg::exceptions {
|
||||
|
||||
win32_exception::win32_exception(std::string_view file, int line, error_code_t win32_error_code, std::string_view message) noexcept :
|
||||
::nkg::exception(file, line, message)
|
||||
{
|
||||
m_error_code = win32_error_code;
|
||||
|
||||
::nkg::resource_wrapper error_string{ ::nkg::resource_traits::win32::local_alloc{} };
|
||||
FormatMessageW(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
||||
NULL,
|
||||
win32_error_code,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
error_string.template unsafe_addressof<wchar_t>(),
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
if (error_string.is_valid()) {
|
||||
m_error_string = ::nkg::cp_converter<-1, CP_UTF8>::convert(error_string.template as<wchar_t*>());
|
||||
} else {
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
35
common/exceptions/win32_exception.hpp
Normal file
35
common/exceptions/win32_exception.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include "../exception.hpp"
|
||||
#include <windows.h>
|
||||
|
||||
namespace nkg::exceptions {
|
||||
|
||||
class win32_exception final : public ::nkg::exception {
|
||||
public:
|
||||
using error_code_t = decltype(GetLastError());
|
||||
|
||||
private:
|
||||
error_code_t m_error_code;
|
||||
std::string m_error_string;
|
||||
|
||||
public:
|
||||
|
||||
win32_exception(std::string_view file, int line, error_code_t win32_error_code, std::string_view message) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool error_code_exists() const noexcept override {
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual intptr_t error_code() const noexcept override {
|
||||
return m_error_code;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual const std::string& error_string() const noexcept override {
|
||||
return m_error_string;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
21
common/resource_traits/cxx_dynamic_array_traits.hpp
Normal file
21
common/resource_traits/cxx_dynamic_array_traits.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
namespace nkg::resource_traits {
|
||||
|
||||
template<typename element_t>
|
||||
struct cxx_dynamic_array_traits {
|
||||
using handle_t = element_t*;
|
||||
|
||||
static constexpr handle_t invalid_value = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) {
|
||||
delete[] handle;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
21
common/resource_traits/cxx_object_traits.hpp
Normal file
21
common/resource_traits/cxx_object_traits.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
namespace nkg::resource_traits {
|
||||
|
||||
template<typename object_t>
|
||||
struct cxx_object_traits {
|
||||
using handle_t = object_t*;
|
||||
|
||||
static constexpr handle_t invalid_value = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) {
|
||||
delete handle;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
35
common/resource_traits/keystone/keystone_handle.hpp
Normal file
35
common/resource_traits/keystone/keystone_handle.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include <keystone/keystone.h>
|
||||
|
||||
namespace nkg::resource_traits::keystone {
|
||||
|
||||
struct keystone_handle {
|
||||
using handle_t = ks_engine*;
|
||||
|
||||
static constexpr handle_t invalid_value = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) {
|
||||
ks_close(handle);
|
||||
}
|
||||
};
|
||||
|
||||
struct keystone_alloc {
|
||||
using handle_t = unsigned char*;
|
||||
|
||||
static constexpr handle_t invalid_value = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) noexcept {
|
||||
ks_free(handle);
|
||||
}
|
||||
};
|
||||
}
|
||||
21
common/resource_traits/openssl/bignum.hpp
Normal file
21
common/resource_traits/openssl/bignum.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <openssl/bn.h>
|
||||
|
||||
namespace nkg::resource_traits::openssl {
|
||||
|
||||
struct bignum {
|
||||
using handle_t = BIGNUM*;
|
||||
|
||||
static constexpr handle_t invalid_value = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) noexcept {
|
||||
BN_free(handle);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
21
common/resource_traits/openssl/bio.hpp
Normal file
21
common/resource_traits/openssl/bio.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <openssl/bio.h>
|
||||
|
||||
namespace nkg::resource_traits::openssl {
|
||||
|
||||
struct bio {
|
||||
using handle_t = BIO*;
|
||||
|
||||
static constexpr handle_t invalid_value = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) noexcept {
|
||||
BIO_free(handle);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
21
common/resource_traits/openssl/bio_chain.hpp
Normal file
21
common/resource_traits/openssl/bio_chain.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <openssl/bio.h>
|
||||
|
||||
namespace nkg::resource_traits::openssl {
|
||||
|
||||
struct bio_chain {
|
||||
using handle_t = BIO*;
|
||||
|
||||
static constexpr handle_t invalid_value = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) noexcept {
|
||||
BIO_free_all(handle);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
21
common/resource_traits/openssl/decoder_ctx.hpp
Normal file
21
common/resource_traits/openssl/decoder_ctx.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <openssl/decoder.h>
|
||||
|
||||
namespace nkg::resource_traits::openssl {
|
||||
|
||||
struct decoder_ctx {
|
||||
using handle_t = OSSL_DECODER_CTX*;
|
||||
|
||||
static constexpr handle_t invalid_value = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) noexcept {
|
||||
OSSL_DECODER_CTX_free(handle);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
21
common/resource_traits/openssl/encoder_ctx.hpp
Normal file
21
common/resource_traits/openssl/encoder_ctx.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <openssl/encoder.h>
|
||||
|
||||
namespace nkg::resource_traits::openssl {
|
||||
|
||||
struct encoder_ctx {
|
||||
using handle_t = OSSL_ENCODER_CTX*;
|
||||
|
||||
static constexpr handle_t invalid_value = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) noexcept {
|
||||
OSSL_ENCODER_CTX_free(handle);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
21
common/resource_traits/openssl/evp_cipher_ctx.hpp
Normal file
21
common/resource_traits/openssl/evp_cipher_ctx.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <openssl/evp.h>
|
||||
|
||||
namespace nkg::resource_traits::openssl {
|
||||
|
||||
struct evp_cipher_ctx {
|
||||
using handle_t = EVP_CIPHER_CTX*;
|
||||
|
||||
static constexpr handle_t invalid_value = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) noexcept {
|
||||
EVP_CIPHER_CTX_free(handle);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
21
common/resource_traits/openssl/evp_pkey.hpp
Normal file
21
common/resource_traits/openssl/evp_pkey.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <openssl/evp.h>
|
||||
|
||||
namespace nkg::resource_traits::openssl {
|
||||
|
||||
struct evp_pkey {
|
||||
using handle_t = EVP_PKEY*;
|
||||
|
||||
static constexpr handle_t invalid_value = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) noexcept {
|
||||
EVP_PKEY_free(handle);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
21
common/resource_traits/openssl/evp_pkey_ctx.hpp
Normal file
21
common/resource_traits/openssl/evp_pkey_ctx.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <openssl/evp.h>
|
||||
|
||||
namespace nkg::resource_traits::openssl {
|
||||
|
||||
struct evp_pkey_ctx {
|
||||
using handle_t = EVP_PKEY_CTX*;
|
||||
|
||||
static constexpr handle_t invalid_value = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) noexcept {
|
||||
EVP_PKEY_CTX_free(handle);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
21
common/resource_traits/openssl/rsa.hpp
Normal file
21
common/resource_traits/openssl/rsa.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
namespace nkg::resource_traits::openssl {
|
||||
|
||||
struct rsa {
|
||||
using handle_t = RSA*;
|
||||
|
||||
static constexpr handle_t invalid_value = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) noexcept {
|
||||
RSA_free(handle);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
21
common/resource_traits/unicorn/unicorn_handle.hpp
Normal file
21
common/resource_traits/unicorn/unicorn_handle.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <unicorn/unicorn.h>
|
||||
|
||||
namespace nkg::resource_traits::unicorn {
|
||||
|
||||
struct unicorn_handle {
|
||||
using handle_t = uc_engine*;
|
||||
|
||||
static constexpr handle_t invalid_value = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) {
|
||||
uc_close(handle);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
21
common/resource_traits/win32/file_handle.hpp
Normal file
21
common/resource_traits/win32/file_handle.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
|
||||
namespace nkg::resource_traits::win32 {
|
||||
|
||||
struct file_handle {
|
||||
using handle_t = HANDLE;
|
||||
|
||||
static inline const handle_t invalid_value = INVALID_HANDLE_VALUE;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) {
|
||||
CloseHandle(handle);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
21
common/resource_traits/win32/generic_handle.hpp
Normal file
21
common/resource_traits/win32/generic_handle.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
|
||||
namespace nkg::resource_traits::win32 {
|
||||
|
||||
struct generic_handle {
|
||||
using handle_t = HANDLE;
|
||||
|
||||
static constexpr handle_t invalid_value = NULL;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) {
|
||||
CloseHandle(handle);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
21
common/resource_traits/win32/local_alloc.hpp
Normal file
21
common/resource_traits/win32/local_alloc.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
|
||||
namespace nkg::resource_traits::win32 {
|
||||
|
||||
struct local_alloc {
|
||||
using handle_t = HLOCAL;
|
||||
|
||||
static constexpr handle_t invalid_value = NULL;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t handle) {
|
||||
LocalFree(handle);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
21
common/resource_traits/win32/map_view_ptr.hpp
Normal file
21
common/resource_traits/win32/map_view_ptr.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
|
||||
namespace nkg::resource_traits::win32 {
|
||||
|
||||
struct map_view_ptr {
|
||||
using handle_t = PVOID;
|
||||
|
||||
static constexpr handle_t invalid_value = NULL;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool is_valid(const handle_t& handle) noexcept {
|
||||
return handle != invalid_value;
|
||||
}
|
||||
|
||||
static void release(const handle_t& handle) {
|
||||
UnmapViewOfFile(handle);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
245
common/resource_wrapper.hpp
Normal file
245
common/resource_wrapper.hpp
Normal file
@ -0,0 +1,245 @@
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace nkg {
|
||||
|
||||
template<typename resource_traits_t, typename releaser_t = void>
|
||||
class resource_wrapper {
|
||||
public:
|
||||
using handle_t = typename resource_traits_t::handle_t;
|
||||
static_assert(std::is_trivial_v<handle_t> && std::is_standard_layout_v<handle_t>, "`resource_wrapper` requires a handle with POD type.");
|
||||
|
||||
private:
|
||||
handle_t m_handle;
|
||||
releaser_t m_releaser;
|
||||
|
||||
public:
|
||||
template<typename releaser_arg_t>
|
||||
resource_wrapper(releaser_arg_t&& releaser) noexcept :
|
||||
m_handle(resource_traits_t::invalid_value),
|
||||
m_releaser(std::forward<releaser_arg_t>(releaser)) {}
|
||||
|
||||
template<typename releaser_arg_t>
|
||||
resource_wrapper(const handle_t& handle, releaser_arg_t&& releaser) noexcept :
|
||||
m_handle(handle),
|
||||
m_releaser(std::forward<releaser_arg_t>(releaser)) {}
|
||||
|
||||
template<typename releaser_arg_t>
|
||||
resource_wrapper(resource_traits_t, releaser_arg_t&& releaser) noexcept :
|
||||
m_handle(resource_traits_t::invalid_value),
|
||||
m_releaser(std::forward<releaser_arg_t>(releaser)) {}
|
||||
|
||||
template<typename releaser_arg_t>
|
||||
resource_wrapper(resource_traits_t, const handle_t& handle, releaser_arg_t&& releaser) noexcept :
|
||||
m_handle(handle),
|
||||
m_releaser(std::forward<releaser_t>(releaser)) {}
|
||||
|
||||
//
|
||||
// `resource_wrapper` does not allow copy-construct
|
||||
//
|
||||
resource_wrapper(const resource_wrapper& other) = delete;
|
||||
|
||||
//
|
||||
// `resource_wrapper` allows move-construct.
|
||||
//
|
||||
resource_wrapper(resource_wrapper&& other) noexcept :
|
||||
m_handle(other.m_handle),
|
||||
m_releaser(std::move(other.m_releaser))
|
||||
{
|
||||
other.m_handle = resource_traits_t::invalid_value;
|
||||
}
|
||||
|
||||
//
|
||||
// `resource_wrapper` does not allow to copy.
|
||||
//
|
||||
resource_wrapper& operator=(const resource_wrapper& other) = delete;
|
||||
|
||||
//
|
||||
// `resource_wrapper` allows to move.
|
||||
//
|
||||
resource_wrapper& operator=(resource_wrapper&& other) noexcept {
|
||||
if (this != std::addressof(other)) {
|
||||
m_handle = other.m_handle;
|
||||
m_releaser = std::move(other.m_releaser);
|
||||
other.m_handle = resource_traits_t::invalid_value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename ptr_t = handle_t, std::enable_if_t<std::is_pointer_v<handle_t>, ptr_t> = nullptr>
|
||||
[[nodiscard]]
|
||||
ptr_t operator->() const noexcept {
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
template<typename as_t>
|
||||
[[nodiscard]]
|
||||
as_t as() const noexcept {
|
||||
return reinterpret_cast<as_t>(m_handle);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool is_valid() const noexcept {
|
||||
return resource_traits_t::is_valid(m_handle);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const handle_t& get() const noexcept {
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
template<typename as_t = handle_t>
|
||||
[[nodiscard]]
|
||||
as_t* unsafe_addressof() noexcept {
|
||||
return reinterpret_cast<as_t*>(std::addressof(m_handle));
|
||||
}
|
||||
|
||||
void set(const handle_t& handle) {
|
||||
if (is_valid()) {
|
||||
m_releaser(m_handle);
|
||||
}
|
||||
m_handle = handle;
|
||||
}
|
||||
|
||||
void discard() noexcept {
|
||||
m_handle = resource_traits_t::invalid_value;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
handle_t transfer() noexcept {
|
||||
handle_t t = m_handle;
|
||||
m_handle = resource_traits_t::invalid_value;
|
||||
return t;
|
||||
}
|
||||
|
||||
void release() {
|
||||
if (is_valid()) {
|
||||
m_releaser(m_handle);
|
||||
m_handle = resource_traits_t::invalid_value;
|
||||
}
|
||||
}
|
||||
|
||||
~resource_wrapper() {
|
||||
release();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename resource_traits_t>
|
||||
class resource_wrapper<resource_traits_t, void> {
|
||||
public:
|
||||
using handle_t = typename resource_traits_t::handle_t;
|
||||
static_assert(std::is_trivial_v<handle_t>&& std::is_standard_layout_v<handle_t>, "`resource_wrapper` requires a handle with POD type.");
|
||||
|
||||
private:
|
||||
handle_t m_handle;
|
||||
|
||||
public:
|
||||
resource_wrapper() noexcept :
|
||||
m_handle(resource_traits_t::invalid_value) {}
|
||||
|
||||
resource_wrapper(const handle_t& handle) noexcept :
|
||||
m_handle(handle) {}
|
||||
|
||||
resource_wrapper(resource_traits_t) noexcept :
|
||||
m_handle(resource_traits_t::invalid_value) {}
|
||||
|
||||
resource_wrapper(resource_traits_t, const handle_t& handle) noexcept :
|
||||
m_handle(handle) {}
|
||||
|
||||
resource_wrapper(const resource_wrapper& other) = delete;
|
||||
|
||||
resource_wrapper(resource_wrapper&& other) noexcept :
|
||||
m_handle(other.m_handle)
|
||||
{
|
||||
other.m_handle = resource_traits_t::invalid_value;
|
||||
}
|
||||
|
||||
resource_wrapper& operator=(const resource_wrapper& other) = delete;
|
||||
|
||||
resource_wrapper& operator=(resource_wrapper&& other) noexcept {
|
||||
if (this != std::addressof(other)) {
|
||||
m_handle = other.m_handle;
|
||||
other.m_handle = resource_traits_t::invalid_value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename ptr_t = handle_t, std::enable_if_t<std::is_pointer_v<handle_t>, ptr_t> = nullptr>
|
||||
[[nodiscard]]
|
||||
ptr_t operator->() const noexcept {
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
template<typename as_t>
|
||||
[[nodiscard]]
|
||||
as_t as() const noexcept {
|
||||
return reinterpret_cast<as_t>(m_handle);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool is_valid() const noexcept {
|
||||
return resource_traits_t::is_valid(m_handle);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const handle_t& get() const noexcept {
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
template<typename as_t = handle_t>
|
||||
[[nodiscard]]
|
||||
as_t* unsafe_addressof() noexcept {
|
||||
return reinterpret_cast<as_t*>(std::addressof(m_handle));
|
||||
}
|
||||
|
||||
void set(const handle_t& handle) {
|
||||
if (is_valid()) {
|
||||
resource_traits_t::release(m_handle);
|
||||
}
|
||||
m_handle = handle;
|
||||
}
|
||||
|
||||
void discard() noexcept {
|
||||
m_handle = resource_traits_t::invalid_value;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
handle_t transfer() noexcept {
|
||||
handle_t t = m_handle;
|
||||
m_handle = resource_traits_t::invalid_value;
|
||||
return t;
|
||||
}
|
||||
|
||||
void release() {
|
||||
if (is_valid()) {
|
||||
resource_traits_t::release(m_handle);
|
||||
m_handle = resource_traits_t::invalid_value;
|
||||
}
|
||||
}
|
||||
|
||||
~resource_wrapper() {
|
||||
release();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename resource_traits_t>
|
||||
resource_wrapper(resource_traits_t) ->
|
||||
resource_wrapper<resource_traits_t, void>;
|
||||
|
||||
template<typename resource_traits_t, typename arg_t>
|
||||
resource_wrapper(resource_traits_t, arg_t&&) ->
|
||||
resource_wrapper<
|
||||
resource_traits_t,
|
||||
std::conditional_t<
|
||||
std::is_same_v<std::remove_cv_t<std::remove_reference_t<arg_t>>, typename resource_traits_t::handle_t> == false,
|
||||
std::remove_reference_t<arg_t>,
|
||||
void
|
||||
>
|
||||
>;
|
||||
|
||||
template<typename resource_traits_t, typename releaser_t, typename handle_t = typename resource_traits_t::handle_t>
|
||||
resource_wrapper(resource_traits_t, const handle_t&, releaser_t&&) ->
|
||||
resource_wrapper<resource_traits_t, std::remove_reference_t<releaser_t>>;
|
||||
|
||||
}
|
||||
625
common/rsa_cipher.cpp
Normal file
625
common/rsa_cipher.cpp
Normal file
@ -0,0 +1,625 @@
|
||||
#include "rsa_cipher.hpp"
|
||||
#include <mutex>
|
||||
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/bio.h>
|
||||
|
||||
#include "resource_traits/openssl/bio.hpp"
|
||||
#include "resource_traits/openssl/bignum.hpp"
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER & 0xf0000000) == 0x30000000 // for openssl 3.x.x
|
||||
#include <openssl/encoder.h>
|
||||
#include <openssl/decoder.h>
|
||||
#include "resource_traits/openssl/encoder_ctx.hpp"
|
||||
#include "resource_traits/openssl/decoder_ctx.hpp"
|
||||
#endif
|
||||
|
||||
#include "cp_converter.hpp"
|
||||
|
||||
#include "exceptions/overflow_exception.hpp"
|
||||
|
||||
#pragma comment(lib, "libcrypto")
|
||||
#pragma comment(lib, "crypt32") // required by libcrypto.lib
|
||||
#pragma comment(lib, "ws2_32") // required by libcrypto.lib
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\common\\rsa_cipher.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER & 0xf0000000) < 0x30000000 // for openssl < 3.0.0
|
||||
RSA* rsa_cipher::_read_private_key_from_bio(BIO* p_bio) {
|
||||
resource_wrapper new_rsa
|
||||
{ resource_traits::openssl::rsa{}, PEM_read_bio_RSAPrivateKey(p_bio, nullptr, nullptr, nullptr) };
|
||||
|
||||
if (new_rsa.is_valid()) {
|
||||
return new_rsa.transfer();
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"PEM_read_bio_RSAPrivateKey failed.")
|
||||
.push_hint(u8"Are you sure that you DO provide a valid RSA private key file?");
|
||||
}
|
||||
}
|
||||
|
||||
RSA* rsa_cipher::_read_public_key_pem_from_bio(BIO* p_bio) {
|
||||
resource_wrapper new_rsa
|
||||
{ resource_traits::openssl::rsa{}, PEM_read_bio_RSA_PUBKEY(p_bio, nullptr, nullptr, nullptr) };
|
||||
|
||||
if (new_rsa.is_valid()) {
|
||||
return new_rsa.transfer();
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"PEM_read_bio_RSA_PUBKEY failed.")
|
||||
.push_hint(u8"Are you sure that you DO provide a valid RSA public key file with PEM format?");
|
||||
}
|
||||
}
|
||||
|
||||
RSA* rsa_cipher::_read_public_key_pkcs1_from_bio(BIO* p_bio) {
|
||||
resource_wrapper new_rsa
|
||||
{ resource_traits::openssl::rsa{}, PEM_read_bio_RSAPublicKey(p_bio, nullptr, nullptr, nullptr) };
|
||||
|
||||
if (new_rsa.is_valid()) {
|
||||
return new_rsa.transfer();
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"PEM_read_bio_RSAPublicKey failed.")
|
||||
.push_hint(u8"Are you sure that you DO provide a valid RSA public key file with PKCS1 format?");
|
||||
}
|
||||
}
|
||||
|
||||
void rsa_cipher::_write_private_key_to_bio(RSA* p_rsa, BIO* p_bio) {
|
||||
auto r = PEM_write_bio_RSAPrivateKey(p_bio, p_rsa, nullptr, nullptr, 0, nullptr, nullptr);
|
||||
if (r == 0) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"PEM_write_bio_RSAPrivateKey failed.");
|
||||
};
|
||||
}
|
||||
|
||||
void rsa_cipher::_write_public_key_pem_to_bio(RSA* p_rsa, BIO* p_bio) {
|
||||
auto r = PEM_write_bio_RSA_PUBKEY(p_bio, p_rsa);
|
||||
if (r == 0) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"PEM_write_bio_RSA_PUBKEY failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void rsa_cipher::_write_public_key_pkcs1_to_bio(RSA* p_rsa, BIO* p_bio) {
|
||||
auto r = PEM_write_bio_RSAPublicKey(p_bio, p_rsa);
|
||||
if (r == 0) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"PEM_write_bio_RSAPublicKey failed.");
|
||||
}
|
||||
}
|
||||
#elif (OPENSSL_VERSION_NUMBER & 0xf0000000) == 0x30000000 // for openssl 3.x.x
|
||||
[[nodiscard]]
|
||||
EVP_PKEY* rsa_cipher::_read_private_key_from_bio(BIO* p_bio) {
|
||||
resource_wrapper new_rsa{ resource_traits::openssl::evp_pkey{} };
|
||||
|
||||
resource_wrapper decoder_context
|
||||
{ resource_traits::openssl::decoder_ctx{}, OSSL_DECODER_CTX_new_for_pkey(new_rsa.unsafe_addressof(), "PEM", "pkcs1", "RSA", OSSL_KEYMGMT_SELECT_PRIVATE_KEY, nullptr, nullptr) };
|
||||
|
||||
if (!decoder_context.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"OSSL_DECODER_CTX_new_for_pkey failed.");
|
||||
}
|
||||
|
||||
if (!OSSL_DECODER_from_bio(decoder_context.get(), p_bio)) { // 1 on success, 0 on failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"OSSL_DECODER_from_bio failed.");
|
||||
}
|
||||
|
||||
return new_rsa.transfer();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
EVP_PKEY* rsa_cipher::_read_public_key_pem_from_bio(BIO* p_bio) {
|
||||
resource_wrapper new_rsa{ resource_traits::openssl::evp_pkey{} };
|
||||
|
||||
resource_wrapper decoder_context
|
||||
{ resource_traits::openssl::decoder_ctx{}, OSSL_DECODER_CTX_new_for_pkey(new_rsa.unsafe_addressof(), "PEM", "SubjectPublicKeyInfo", "RSA", OSSL_KEYMGMT_SELECT_PUBLIC_KEY, nullptr, nullptr) };
|
||||
|
||||
if (!decoder_context.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"OSSL_DECODER_CTX_new_for_pkey failed.");
|
||||
}
|
||||
|
||||
if (!OSSL_DECODER_from_bio(decoder_context.get(), p_bio)) { // 1 on success, 0 on failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"OSSL_DECODER_from_bio failed.");
|
||||
}
|
||||
|
||||
return new_rsa.transfer();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
EVP_PKEY* rsa_cipher::_read_public_key_pkcs1_from_bio(BIO* p_bio) {
|
||||
resource_wrapper new_rsa{ resource_traits::openssl::evp_pkey{} };
|
||||
|
||||
resource_wrapper decoder_context
|
||||
{ resource_traits::openssl::decoder_ctx{}, OSSL_DECODER_CTX_new_for_pkey(new_rsa.unsafe_addressof(), "PEM", "pkcs1", "RSA", OSSL_KEYMGMT_SELECT_PUBLIC_KEY, nullptr, nullptr) };
|
||||
|
||||
if (!decoder_context.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"OSSL_DECODER_CTX_new_for_pkey failed.");
|
||||
}
|
||||
|
||||
if (!OSSL_DECODER_from_bio(decoder_context.get(), p_bio)) { // 1 on success, 0 on failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"OSSL_DECODER_from_bio failed.");
|
||||
}
|
||||
|
||||
return new_rsa.transfer();
|
||||
}
|
||||
|
||||
void rsa_cipher::_write_private_key_to_bio(EVP_PKEY* p_rsa, BIO* p_bio) {
|
||||
resource_wrapper encoder_context
|
||||
{ resource_traits::openssl::encoder_ctx{}, OSSL_ENCODER_CTX_new_for_pkey(p_rsa, OSSL_KEYMGMT_SELECT_PRIVATE_KEY, "PEM", "pkcs1", nullptr) };
|
||||
|
||||
if (!encoder_context.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"OSSL_ENCODER_CTX_new_for_pkey failed.");
|
||||
}
|
||||
|
||||
if (!OSSL_ENCODER_to_bio(encoder_context.get(), p_bio)) { // 1 on success, 0 on failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"OSSL_ENCODER_to_bio failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void rsa_cipher::_write_public_key_pem_to_bio(EVP_PKEY* p_rsa, BIO* p_bio) {
|
||||
resource_wrapper encoder_context
|
||||
{ resource_traits::openssl::encoder_ctx{}, OSSL_ENCODER_CTX_new_for_pkey(p_rsa, OSSL_KEYMGMT_SELECT_PUBLIC_KEY, "PEM", "SubjectPublicKeyInfo", nullptr) };
|
||||
|
||||
if (!encoder_context.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"OSSL_ENCODER_CTX_new_for_pkey failed.");
|
||||
}
|
||||
|
||||
if (!OSSL_ENCODER_to_bio(encoder_context.get(), p_bio)) { // 1 on success, 0 on failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"OSSL_ENCODER_to_bio failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void rsa_cipher::_write_public_key_pkcs1_to_bio(EVP_PKEY* p_rsa, BIO* p_bio) {
|
||||
resource_wrapper encoder_context
|
||||
{ resource_traits::openssl::encoder_ctx{}, OSSL_ENCODER_CTX_new_for_pkey(p_rsa, OSSL_KEYMGMT_SELECT_PUBLIC_KEY, "PEM", "pkcs1", nullptr) };
|
||||
|
||||
if (!encoder_context.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"OSSL_ENCODER_CTX_new_for_pkey failed.");
|
||||
}
|
||||
|
||||
if (!OSSL_ENCODER_to_bio(encoder_context.get(), p_bio)) { // 1 on success, 0 on failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"OSSL_ENCODER_to_bio failed.");
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error "rsa_cipher.cpp: Unexpected OpenSSL version."
|
||||
#endif
|
||||
|
||||
rsa_cipher::rsa_cipher() = default;
|
||||
|
||||
[[nodiscard]]
|
||||
size_t rsa_cipher::bits() const {
|
||||
if (m_rsa.get()) {
|
||||
#if (OPENSSL_VERSION_NUMBER & 0xfff00000) == 0x10000000 // openssl 1.0.x
|
||||
return BN_num_bits(m_rsa->n);
|
||||
#elif (OPENSSL_VERSION_NUMBER & 0xfff00000) == 0x10100000 // openssl 1.1.x
|
||||
return RSA_bits(m_rsa.get());
|
||||
#elif (OPENSSL_VERSION_NUMBER & 0xf0000000) == 0x30000000 // openssl 3.x.x
|
||||
return EVP_PKEY_get_bits(m_rsa.get());
|
||||
#else
|
||||
#error "rsa_cipher.cpp: uexpected OpenSSL version"
|
||||
#endif
|
||||
} else {
|
||||
throw no_key_assigned_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"RSA key has not been assigned yet.");
|
||||
}
|
||||
}
|
||||
|
||||
void rsa_cipher::generate_key(int bits, unsigned int e) {
|
||||
resource_wrapper bn_e{ resource_traits::openssl::bignum{}, BN_new() };
|
||||
|
||||
if (bn_e.is_valid() == false) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ERR_get_error(), u8"BN_new failed.");
|
||||
}
|
||||
|
||||
if (BN_set_word(bn_e.get(), e) == 0) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BN_set_word failed.");
|
||||
}
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER & 0xf0000000) < 0x30000000 // for openssl < 3.0.0
|
||||
resource_wrapper new_rsa{ resource_traits::openssl::rsa{}, RSA_new() };
|
||||
if (!new_rsa.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ERR_get_error(), u8"RSA_new failed.");
|
||||
}
|
||||
|
||||
if (RSA_generate_key_ex(new_rsa.get(), bits, bn_e.get(), nullptr) == 0) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ERR_get_error(), u8"RSA_generate_key_ex failed.");
|
||||
}
|
||||
|
||||
m_rsa = std::move(new_rsa);
|
||||
#elif (OPENSSL_VERSION_NUMBER & 0xf0000000) == 0x30000000 // for openssl 3.x.x
|
||||
resource_wrapper evp_pkey_context{ resource_traits::openssl::evp_pkey_ctx{}, EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr) };
|
||||
if (!evp_pkey_context.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_CTX_new_id failed.");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_keygen_init(evp_pkey_context.get()) <= 0) { // 1 for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_keygen_init failed.");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_rsa_keygen_bits(evp_pkey_context.get(), bits) <= 0) { // return a positive value for success and 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_CTX_set_rsa_keygen_bits failed.");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set1_rsa_keygen_pubexp(evp_pkey_context.get(), bn_e.get()) <= 0) { // return a positive value for success and 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_CTX_set1_rsa_keygen_pubexp failed.");
|
||||
}
|
||||
|
||||
resource_wrapper new_rsa{ resource_traits::openssl::evp_pkey{} };
|
||||
|
||||
if (EVP_PKEY_keygen(evp_pkey_context.get(), new_rsa.unsafe_addressof()) <= 0) { // 1 for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_keygen failed.");
|
||||
}
|
||||
|
||||
m_rsa = std::move(new_rsa);
|
||||
#else
|
||||
#error "rsa_cipher.cpp: Unexpected OpenSSL version."
|
||||
#endif
|
||||
}
|
||||
|
||||
void rsa_cipher::export_private_key_file(std::wstring_view file_path) const {
|
||||
resource_wrapper bio_file
|
||||
{ resource_traits::openssl::bio{}, BIO_new_file(cp_converter<-1, CP_UTF8>::convert(file_path).c_str(), "w")};
|
||||
|
||||
if (bio_file.is_valid()) {
|
||||
_write_private_key_to_bio(m_rsa.get(), bio_file.get());
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new_file failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void rsa_cipher::export_private_key_file(const std::filesystem::path& file_path) const {
|
||||
export_private_key_file(static_cast<std::wstring_view>(file_path.native()));
|
||||
}
|
||||
|
||||
void rsa_cipher::export_public_key_file_pem(std::wstring_view file_path) const {
|
||||
resource_wrapper bio_file
|
||||
{ resource_traits::openssl::bio{}, BIO_new_file(cp_converter<-1, CP_UTF8>::convert(file_path).c_str(), "w")};
|
||||
|
||||
if (bio_file.is_valid()) {
|
||||
_write_public_key_pem_to_bio(m_rsa.get(), bio_file.get());
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new_file failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void rsa_cipher::export_public_key_file_pem(const std::filesystem::path& file_path) const {
|
||||
export_public_key_file_pem(static_cast<std::wstring_view>(file_path.native()));
|
||||
}
|
||||
|
||||
void rsa_cipher::export_public_key_file_pkcs1(std::wstring_view file_path) const {
|
||||
resource_wrapper bio_file
|
||||
{ resource_traits::openssl::bio{}, BIO_new_file(cp_converter<-1, CP_UTF8>::convert(file_path).c_str(), "w")};
|
||||
|
||||
if (bio_file.is_valid()) {
|
||||
_write_public_key_pkcs1_to_bio(m_rsa.get(), bio_file.get());
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new_file failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void rsa_cipher::export_public_key_file_pkcs1(const std::filesystem::path& file_path) const {
|
||||
export_public_key_file_pkcs1(static_cast<std::wstring_view>(file_path.native()));
|
||||
}
|
||||
|
||||
void rsa_cipher::import_private_key_file(std::wstring_view file_path) {
|
||||
resource_wrapper bio_file
|
||||
{ resource_traits::openssl::bio{}, BIO_new_file(cp_converter<-1, CP_UTF8>::convert(file_path).c_str(), "r") };
|
||||
|
||||
if (bio_file.is_valid()) {
|
||||
m_rsa.set(_read_private_key_from_bio(bio_file.get()));
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new_file failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void rsa_cipher::import_private_key_file(const std::filesystem::path& file_path) {
|
||||
import_private_key_file(static_cast<std::wstring_view>(file_path.native()));
|
||||
}
|
||||
|
||||
void rsa_cipher::import_public_key_file_pem(std::wstring_view file_path) {
|
||||
resource_wrapper bio_file
|
||||
{ resource_traits::openssl::bio{}, BIO_new_file(cp_converter<-1, CP_UTF8>::convert(file_path).c_str(), "r") };
|
||||
|
||||
if (bio_file.is_valid()) {
|
||||
m_rsa.set(_read_public_key_pem_from_bio(bio_file.get()));
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new_file failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void rsa_cipher::import_public_key_file_pem(const std::filesystem::path& file_path) {
|
||||
import_public_key_file_pem(static_cast<std::wstring_view>(file_path.native()));
|
||||
}
|
||||
|
||||
void rsa_cipher::import_public_key_file_pkcs1(std::wstring_view file_path) {
|
||||
resource_wrapper bio_file
|
||||
{ resource_traits::openssl::bio{}, BIO_new_file(cp_converter<-1, CP_UTF8>::convert(file_path).c_str(), "r") };
|
||||
|
||||
if (bio_file.is_valid()) {
|
||||
m_rsa.set(_read_public_key_pkcs1_from_bio(bio_file.get()));
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new_file failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void rsa_cipher::import_public_key_file_pkcs1(const std::filesystem::path& file_path) {
|
||||
import_public_key_file_pkcs1(static_cast<std::wstring_view>(file_path.native()));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::string rsa_cipher::export_private_key_string() const {
|
||||
resource_wrapper bio_memory{ resource_traits::openssl::bio{}, BIO_new(BIO_s_mem()) };
|
||||
|
||||
if (bio_memory.is_valid()) {
|
||||
_write_private_key_to_bio(m_rsa.get(), bio_memory.get());
|
||||
|
||||
const char* pch = nullptr;
|
||||
long lch = BIO_get_mem_data(bio_memory.get(), &pch);
|
||||
|
||||
return std::string(pch, lch);
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::string rsa_cipher::export_public_key_string_pem() const {
|
||||
resource_wrapper bio_memory{ resource_traits::openssl::bio{}, BIO_new(BIO_s_mem()) };
|
||||
|
||||
if (bio_memory.is_valid()) {
|
||||
_write_public_key_pem_to_bio(m_rsa.get(), bio_memory.get());
|
||||
|
||||
const char* pch = nullptr;
|
||||
long lch = BIO_get_mem_data(bio_memory.get(), &pch);
|
||||
|
||||
return std::string(pch, lch);
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::string rsa_cipher::export_public_key_string_pkcs1() const {
|
||||
resource_wrapper bio_memory{ resource_traits::openssl::bio{}, BIO_new(BIO_s_mem()) };
|
||||
|
||||
if (bio_memory.is_valid()) {
|
||||
_write_public_key_pkcs1_to_bio(m_rsa.get(), bio_memory.get());
|
||||
|
||||
const char* pch = nullptr;
|
||||
long lch = BIO_get_mem_data(bio_memory.get(), &pch);
|
||||
|
||||
return std::string(pch, lch);
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void rsa_cipher::import_private_key_string(std::string_view key_string) {
|
||||
resource_wrapper bio_memory{ resource_traits::openssl::bio{}, BIO_new(BIO_s_mem()) };
|
||||
|
||||
if (bio_memory.is_valid() == false) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
|
||||
}
|
||||
|
||||
if (BIO_puts(bio_memory.get(), key_string.data()) <= 0) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_puts failed.");
|
||||
}
|
||||
|
||||
m_rsa.set(_read_private_key_from_bio(bio_memory.get()));
|
||||
}
|
||||
|
||||
void rsa_cipher::import_public_key_string_pem(std::string_view key_string) {
|
||||
resource_wrapper bio_memory{ resource_traits::openssl::bio{}, BIO_new(BIO_s_mem()) };
|
||||
|
||||
if (bio_memory.is_valid() == false) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
|
||||
}
|
||||
|
||||
if (BIO_puts(bio_memory.get(), key_string.data()) <= 0) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_puts failed.");
|
||||
}
|
||||
|
||||
m_rsa.set(_read_public_key_pem_from_bio(bio_memory.get()));
|
||||
}
|
||||
|
||||
void rsa_cipher::import_public_key_string_pkcs1(std::string_view key_string) {
|
||||
resource_wrapper bio_memory{ resource_traits::openssl::bio{}, BIO_new(BIO_s_mem()) };
|
||||
|
||||
if (bio_memory.is_valid() == false) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
|
||||
}
|
||||
|
||||
if (BIO_puts(bio_memory.get(), key_string.data()) <= 0) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_puts failed.");
|
||||
}
|
||||
|
||||
m_rsa.set(_read_public_key_pkcs1_from_bio(bio_memory.get()));
|
||||
}
|
||||
|
||||
size_t rsa_cipher::public_encrypt(const void* plaintext, size_t plaintext_size, void* ciphertext, int padding) const {
|
||||
#if (OPENSSL_VERSION_NUMBER & 0xf0000000) < 0x30000000 // for openssl < 3.0.0
|
||||
if (plaintext_size <= INT_MAX) {
|
||||
int bytes_written =
|
||||
RSA_public_encrypt(static_cast<int>(plaintext_size), reinterpret_cast<const unsigned char*>(plaintext), reinterpret_cast<unsigned char*>(ciphertext), m_rsa.get(), padding);
|
||||
|
||||
if (bytes_written != -1) {
|
||||
return bytes_written;
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ERR_get_error(), u8"RSA_public_encrypt failed.");
|
||||
}
|
||||
} else {
|
||||
throw exceptions::overflow_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"plaintext_size > INT_MAX");
|
||||
}
|
||||
#elif (OPENSSL_VERSION_NUMBER & 0xf0000000) == 0x30000000 // for openssl 3.x.x
|
||||
resource_wrapper evp_pkey_context{ resource_traits::openssl::evp_pkey_ctx{}, EVP_PKEY_CTX_new(m_rsa.get(), nullptr) };
|
||||
if (!evp_pkey_context.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_CTX_new failed.");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_encrypt_init(evp_pkey_context.get()) <= 0) { // return 1 for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_encrypt_init failed.");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(evp_pkey_context.get(), padding) <= 0) { // return a positive value for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_CTX_set_rsa_padding failed.");
|
||||
}
|
||||
|
||||
size_t ciphertext_size = 0;
|
||||
if (EVP_PKEY_encrypt(evp_pkey_context.get(), nullptr, &ciphertext_size, reinterpret_cast<const unsigned char*>(plaintext), plaintext_size) <= 0) { // return 1 for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_encrypt failed.");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_encrypt(evp_pkey_context.get(), reinterpret_cast<unsigned char*>(ciphertext), &ciphertext_size, reinterpret_cast<const unsigned char*>(plaintext), plaintext_size) <= 0) { // return 1 for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_encrypt failed.");
|
||||
}
|
||||
|
||||
return ciphertext_size;
|
||||
#else
|
||||
#error "rsa_cipher.cpp: Unexpected OpenSSL version."
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t rsa_cipher::private_encrypt(const void* plaintext, size_t plaintext_size, void* ciphertext, int padding) const {
|
||||
#if (OPENSSL_VERSION_NUMBER & 0xf0000000) < 0x30000000 // for openssl < 3.0.0
|
||||
if (plaintext_size <= INT_MAX) {
|
||||
int bytes_written =
|
||||
RSA_private_encrypt(static_cast<int>(plaintext_size), reinterpret_cast<const unsigned char*>(plaintext), reinterpret_cast<unsigned char*>(ciphertext), m_rsa.get(), padding);
|
||||
|
||||
if (bytes_written != -1) {
|
||||
return bytes_written;
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ERR_get_error(), u8"RSA_public_encrypt failed.");
|
||||
}
|
||||
} else {
|
||||
throw exceptions::overflow_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"plaintext_size > INT_MAX");
|
||||
}
|
||||
#elif (OPENSSL_VERSION_NUMBER & 0xf0000000) == 0x30000000 // for openssl 3.x.x
|
||||
resource_wrapper evp_pkey_context{ resource_traits::openssl::evp_pkey_ctx{}, EVP_PKEY_CTX_new(m_rsa.get(), nullptr) };
|
||||
if (!evp_pkey_context.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_CTX_new failed.");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_sign_init(evp_pkey_context.get()) <= 0) { // return 1 for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_sign_init failed.");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(evp_pkey_context.get(), padding) <= 0) { // return a positive value for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_CTX_set_rsa_padding failed.");
|
||||
}
|
||||
|
||||
size_t ciphertext_size = 0;
|
||||
if (EVP_PKEY_sign(evp_pkey_context.get(), nullptr, &ciphertext_size, reinterpret_cast<const unsigned char*>(plaintext), plaintext_size) <= 0) { // return 1 for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_sign failed.");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_sign(evp_pkey_context.get(), reinterpret_cast<unsigned char*>(ciphertext), &ciphertext_size, reinterpret_cast<const unsigned char*>(plaintext), plaintext_size) <= 0) { // return 1 for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_sign failed.");
|
||||
}
|
||||
|
||||
return ciphertext_size;
|
||||
#else
|
||||
#error "rsa_cipher.cpp: Unexpected OpenSSL version."
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t rsa_cipher::public_decrypt(const void* ciphertext, size_t ciphertext_size, void* plaintext, int padding) const {
|
||||
#if (OPENSSL_VERSION_NUMBER & 0xf0000000) < 0x30000000 // for openssl < 3.0.0
|
||||
if (ciphertext_size <= INT_MAX) {
|
||||
int bytes_written =
|
||||
RSA_public_decrypt(static_cast<int>(ciphertext_size), reinterpret_cast<const unsigned char*>(ciphertext), reinterpret_cast<unsigned char*>(plaintext), m_rsa.get(), padding);
|
||||
|
||||
if (bytes_written != -1) {
|
||||
return bytes_written;
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ERR_get_error(), u8"RSA_public_decrypt failed.")
|
||||
.push_hint(u8"Are your sure you DO provide a correct public key?");
|
||||
}
|
||||
} else {
|
||||
throw exceptions::overflow_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"ciphertext_size > INT_MAX");
|
||||
}
|
||||
#elif (OPENSSL_VERSION_NUMBER & 0xf0000000) == 0x30000000 // for openssl 3.x.x
|
||||
resource_wrapper evp_pkey_context{ resource_traits::openssl::evp_pkey_ctx{}, EVP_PKEY_CTX_new(m_rsa.get(), nullptr) };
|
||||
if (!evp_pkey_context.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_CTX_new failed.");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_verify_recover_init(evp_pkey_context.get())) { // return 1 for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_verify_recover_init failed.");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(evp_pkey_context.get(), padding) <= 0) { // return a positive value for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_CTX_set_rsa_padding failed.");
|
||||
}
|
||||
|
||||
size_t plaintext_size = 0;
|
||||
if (EVP_PKEY_verify_recover(evp_pkey_context.get(), nullptr, &plaintext_size, reinterpret_cast<const unsigned char*>(ciphertext), ciphertext_size) <= 0) { // return 1 for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_verify_recover failed.")
|
||||
.push_hint(u8"Are your sure you DO provide a correct public key?");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_verify_recover(evp_pkey_context.get(), reinterpret_cast<unsigned char*>(plaintext), &plaintext_size, reinterpret_cast<const unsigned char*>(ciphertext), ciphertext_size) <= 0) { // return 1 for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_verify_recover failed.");
|
||||
}
|
||||
|
||||
return plaintext_size;
|
||||
#else
|
||||
#error "rsa_cipher.cpp: Unexpected OpenSSL version."
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t rsa_cipher::private_decrypt(const void* ciphertext, size_t ciphertext_size, void* plaintext, int padding) const {
|
||||
#if (OPENSSL_VERSION_NUMBER & 0xf0000000) < 0x30000000 // for openssl < 3.0.0
|
||||
if (ciphertext_size <= INT_MAX) {
|
||||
int bytes_written =
|
||||
RSA_private_decrypt(static_cast<int>(ciphertext_size), reinterpret_cast<const unsigned char*>(ciphertext), reinterpret_cast<unsigned char*>(plaintext), m_rsa.get(), padding);
|
||||
|
||||
if (bytes_written != -1) {
|
||||
return bytes_written;
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ERR_get_error(), u8"RSA_public_decrypt failed.")
|
||||
.push_hint(u8"Are your sure you DO provide a correct private key?");
|
||||
}
|
||||
} else {
|
||||
throw exceptions::overflow_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"ciphertext_size > INT_MAX");
|
||||
}
|
||||
#elif (OPENSSL_VERSION_NUMBER & 0xf0000000) == 0x30000000 // for openssl 3.x.x
|
||||
resource_wrapper evp_pkey_context{ resource_traits::openssl::evp_pkey_ctx{}, EVP_PKEY_CTX_new(m_rsa.get(), nullptr) };
|
||||
if (!evp_pkey_context.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_CTX_new failed.");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_decrypt_init(evp_pkey_context.get()) <= 0) { // return 1 for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_decrypt_init failed.");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(evp_pkey_context.get(), padding) <= 0) { // return a positive value for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_CTX_set_rsa_padding failed.");
|
||||
}
|
||||
|
||||
size_t plaintext_size = 0;
|
||||
if (EVP_PKEY_decrypt(evp_pkey_context.get(), nullptr, &plaintext_size, reinterpret_cast<const unsigned char*>(ciphertext), ciphertext_size) <= 0) { // return 1 for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_decrypt failed.")
|
||||
.push_hint(u8"Are your sure you DO provide a correct private key?");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_decrypt(evp_pkey_context.get(), reinterpret_cast<unsigned char*>(plaintext), &plaintext_size, reinterpret_cast<const unsigned char*>(ciphertext), ciphertext_size) <= 0) { // return 1 for success, 0 or a negative value for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_PKEY_decrypt failed.");
|
||||
}
|
||||
|
||||
return plaintext_size;
|
||||
#else
|
||||
#error "rsa_cipher.cpp: Unexpected OpenSSL version."
|
||||
#endif
|
||||
}
|
||||
|
||||
rsa_cipher::backend_error::backend_error(std::string_view file, int line, std::string_view message) noexcept:
|
||||
::nkg::exception::exception(file, line, message), m_error_code(0) {}
|
||||
|
||||
rsa_cipher::backend_error::backend_error(std::string_view file, int line, error_code_t openssl_errno, std::string_view message) noexcept:
|
||||
::nkg::exception::exception(file, line, message), m_error_code(openssl_errno)
|
||||
{
|
||||
static std::once_flag onceflag_load_crypto_strings;
|
||||
std::call_once(onceflag_load_crypto_strings, []() { ERR_load_crypto_strings(); });
|
||||
|
||||
m_error_string = ERR_reason_error_string(m_error_code);
|
||||
}
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
161
common/rsa_cipher.hpp
Normal file
161
common/rsa_cipher.hpp
Normal file
@ -0,0 +1,161 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include "resource_wrapper.hpp"
|
||||
#if (OPENSSL_VERSION_NUMBER & 0xf0000000) < 0x30000000 // for openssl < 3.0.0
|
||||
#include "resource_traits/openssl/rsa.hpp"
|
||||
#elif (OPENSSL_VERSION_NUMBER & 0xf0000000) == 0x30000000 // for openssl 3.x.x
|
||||
#include "resource_traits/openssl/evp_pkey_ctx.hpp"
|
||||
#include "resource_traits/openssl/evp_pkey.hpp"
|
||||
#else
|
||||
#error "rsa_cipher.hpp: Unexpected OpenSSL version."
|
||||
#endif
|
||||
|
||||
#include "exception.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\common\\rsa_cipher.hpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class rsa_cipher {
|
||||
public:
|
||||
class backend_error;
|
||||
class no_key_assigned_error;
|
||||
|
||||
private:
|
||||
#if (OPENSSL_VERSION_NUMBER & 0xf0000000) < 0x30000000 // for openssl < 3.0.0
|
||||
resource_wrapper<resource_traits::openssl::rsa> m_rsa;
|
||||
|
||||
[[nodiscard]]
|
||||
static RSA* _read_private_key_from_bio(BIO* p_bio);
|
||||
|
||||
[[nodiscard]]
|
||||
static RSA* _read_public_key_pem_from_bio(BIO* p_bio);
|
||||
|
||||
[[nodiscard]]
|
||||
static RSA* _read_public_key_pkcs1_from_bio(BIO* p_bio);
|
||||
|
||||
static void _write_private_key_to_bio(RSA* p_rsa, BIO* p_bio);
|
||||
|
||||
static void _write_public_key_pem_to_bio(RSA* p_rsa, BIO* p_bio);
|
||||
|
||||
static void _write_public_key_pkcs1_to_bio(RSA* p_rsa, BIO* p_bio);
|
||||
#elif (OPENSSL_VERSION_NUMBER & 0xf0000000) == 0x30000000 // for openssl 3.x.x
|
||||
resource_wrapper<resource_traits::openssl::evp_pkey> m_rsa;
|
||||
|
||||
[[nodiscard]]
|
||||
static EVP_PKEY* _read_private_key_from_bio(BIO* p_bio);
|
||||
|
||||
[[nodiscard]]
|
||||
static EVP_PKEY* _read_public_key_pem_from_bio(BIO* p_bio);
|
||||
|
||||
[[nodiscard]]
|
||||
static EVP_PKEY* _read_public_key_pkcs1_from_bio(BIO* p_bio);
|
||||
|
||||
static void _write_private_key_to_bio(EVP_PKEY* p_rsa, BIO* p_bio);
|
||||
|
||||
static void _write_public_key_pem_to_bio(EVP_PKEY* p_rsa, BIO* p_bio);
|
||||
|
||||
static void _write_public_key_pkcs1_to_bio(EVP_PKEY* p_rsa, BIO* p_bio);
|
||||
#else
|
||||
#error "rsa_cipher.hpp: Unexpected OpenSSL version."
|
||||
#endif
|
||||
|
||||
public:
|
||||
rsa_cipher();
|
||||
|
||||
[[nodiscard]]
|
||||
size_t bits() const;
|
||||
|
||||
void generate_key(int bits, unsigned int e = RSA_F4);
|
||||
|
||||
void export_private_key_file(std::wstring_view file_path) const;
|
||||
|
||||
void export_private_key_file(const std::filesystem::path& file_path) const;
|
||||
|
||||
void export_public_key_file_pem(std::wstring_view file_path) const;
|
||||
|
||||
void export_public_key_file_pem(const std::filesystem::path& file_path) const;
|
||||
|
||||
void export_public_key_file_pkcs1(std::wstring_view file_path) const;
|
||||
|
||||
void export_public_key_file_pkcs1(const std::filesystem::path& file_path) const;
|
||||
|
||||
void import_private_key_file(std::wstring_view file_path);
|
||||
|
||||
void import_private_key_file(const std::filesystem::path& file_path);
|
||||
|
||||
void import_public_key_file_pem(std::wstring_view file_path);
|
||||
|
||||
void import_public_key_file_pem(const std::filesystem::path& file_path);
|
||||
|
||||
void import_public_key_file_pkcs1(std::wstring_view file_path);
|
||||
|
||||
void import_public_key_file_pkcs1(const std::filesystem::path& file_path);
|
||||
|
||||
[[nodiscard]]
|
||||
std::string export_private_key_string() const;
|
||||
|
||||
[[nodiscard]]
|
||||
std::string export_public_key_string_pem() const;
|
||||
|
||||
[[nodiscard]]
|
||||
std::string export_public_key_string_pkcs1() const;
|
||||
|
||||
void import_private_key_string(std::string_view key_string);
|
||||
|
||||
void import_public_key_string_pem(std::string_view key_string);
|
||||
|
||||
void import_public_key_string_pkcs1(std::string_view key_string);
|
||||
|
||||
size_t public_encrypt(const void* plaintext, size_t plaintext_size, void* ciphertext, int padding) const;
|
||||
|
||||
size_t private_encrypt(const void* plaintext, size_t plaintext_size, void* ciphertext, int padding) const;
|
||||
|
||||
size_t public_decrypt(const void* ciphertext, size_t ciphertext_size, void* plaintext, int padding) const;
|
||||
|
||||
size_t private_decrypt(const void* ciphertext, size_t ciphertext_size, void* plaintext, int padding) const;
|
||||
};
|
||||
|
||||
class rsa_cipher::backend_error : public ::nkg::exception {
|
||||
public:
|
||||
using error_code_t = decltype(ERR_get_error());
|
||||
|
||||
private:
|
||||
error_code_t m_error_code;
|
||||
std::string m_error_string;
|
||||
|
||||
public:
|
||||
backend_error(std::string_view file, int line, std::string_view message) noexcept;
|
||||
|
||||
backend_error(std::string_view file, int line, error_code_t openssl_errno, std::string_view message) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool error_code_exists() const noexcept override {
|
||||
return m_error_code != 0;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual intptr_t error_code() const noexcept override {
|
||||
if (error_code_exists()) { return m_error_code; } else { trap_then_terminate(); }
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual const std::string& error_string() const noexcept override {
|
||||
if (error_code_exists()) { return m_error_string; } else { trap_then_terminate(); }
|
||||
}
|
||||
};
|
||||
|
||||
class rsa_cipher::no_key_assigned_error : public ::nkg::exception {
|
||||
using ::nkg::exception::exception;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
284
doc/how-does-it-work.md
Normal file
284
doc/how-does-it-work.md
Normal file
@ -0,0 +1,284 @@
|
||||
# Navicat Keygen - How does it work?
|
||||
|
||||
[中文版](how-does-it-work.zh-CN.md)
|
||||
|
||||
## 1. Keyword Explanation.
|
||||
|
||||
* __Navicat Activation Public Key__
|
||||
|
||||
It is a __RSA-2048__ public key that Navicat used to encrypt or decrypt offline activation information.
|
||||
|
||||
It is stored in __navicat.exe__ as a kind of resource called __RCData__. The resource name is `"ACTIVATIONPUBKEY"`. You can see it by a software called [___Resource Hacker___](http://www.angusj.com/resourcehacker/). The public key is
|
||||
|
||||
```
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
|
||||
qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
|
||||
a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
|
||||
R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
|
||||
WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
|
||||
YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
|
||||
awIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
```
|
||||
|
||||
If you have the corresponding private key, you can tell me. I would be very appreciated for your generous.
|
||||
|
||||
__NOTICE:__
|
||||
|
||||
Start from __Navicat Premium 12.0.25__, Navicat do not load this public key from resource in `navicat.exe`. Instead, the public key is stored in `libcc.dll` and has been encrypted. To avoid being replaced easily, the public key is split into 5 parts:
|
||||
|
||||
The following content is discovered from `libcc.dll` of __Navicat Premium x64 12.0.25 Simplified Chinese version__. The SHA256 value of `libcc.dll` is `607e0a84c75966b00f3d12fa833e91d159e4f51ac51b6ba66f98d0c3cbefdce0`.
|
||||
|
||||
I __DO NOT__ guarantee that offset values are absolutely correct in other versions. But __char strings__ and __immediate values__ are highly possible to be found.
|
||||
|
||||
1. At file offset `+0x01A12090` in `libcc.dll`, stored as __char string__:
|
||||
|
||||
```
|
||||
"D75125B70767B94145B47C1CB3C0755E
|
||||
7CCB8825C5DCE0C58ACF944E08280140
|
||||
9A02472FAFFD1CD77864BB821AE36766
|
||||
FEEDE6A24F12662954168BFA314BD950
|
||||
32B9D82445355ED7BC0B880887D650F5"
|
||||
```
|
||||
|
||||
2. At file offset `+0x0059D799` in `libcc.dll`, stored as __immediate value__ in a instruction:
|
||||
|
||||
```
|
||||
0xFE 0xEA 0xBC 0x01
|
||||
```
|
||||
|
||||
In decimal: `29158142`
|
||||
|
||||
3. At file offset `+0x01A11DA0` in `libcc.dll`, stored as __char string__:
|
||||
|
||||
```
|
||||
"E1CED09B9C2186BF71A70C0FE2F1E0AE
|
||||
F3BD6B75277AAB20DFAF3D110F75912B
|
||||
FB63AC50EC4C48689D1502715243A79F
|
||||
39FF2DE2BF15CE438FF885745ED54573
|
||||
850E8A9F40EE2FF505EB7476F95ADB78
|
||||
3B28CA374FAC4632892AB82FB3BF4715
|
||||
FCFE6E82D03731FC3762B6AAC3DF1C3B
|
||||
C646FE9CD3C62663A97EE72DB932A301
|
||||
312B4A7633100C8CC357262C39A2B3A6
|
||||
4B224F5276D5EDBDF0804DC3AC4B8351
|
||||
62BB1969EAEBADC43D2511D6E0239287
|
||||
81B167A48273B953378D3D2080CC0677
|
||||
7E8A2364F0234B81064C5C739A8DA28D
|
||||
C5889072BF37685CBC94C2D31D0179AD
|
||||
86D8E3AA8090D4F0B281BE37E0143746
|
||||
E6049CCC06899401264FA471C016A96C
|
||||
79815B55BBC26B43052609D9D175FBCD
|
||||
E455392F10E51EC162F51CF732E6BB39
|
||||
1F56BBFD8D957DF3D4C55B71CEFD54B1
|
||||
9C16D458757373E698D7E693A8FC3981
|
||||
5A8BF03BA05EA8C8778D38F9873D62B4
|
||||
460F41ACF997C30E7C3AF025FA171B5F
|
||||
5AD4D6B15E95C27F6B35AD61875E5505
|
||||
449B4E"
|
||||
```
|
||||
|
||||
4. At file offset `+0x0059D77F` in `libcc.dll`, stored as __immediate value__ in a instruction:
|
||||
|
||||
```
|
||||
0x59 0x08 0x01 0x00
|
||||
```
|
||||
|
||||
In decimal: `67673`
|
||||
|
||||
5. At file offset `+ 0x1A11D8C` in `libcc.dll`, stored as __char string__:
|
||||
|
||||
```
|
||||
"92933"
|
||||
```
|
||||
|
||||
Then output encrypted public key with format `"%s%d%s%d%s"`. The order is the same as it lists:
|
||||
|
||||
```
|
||||
D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7BC0B880887D650F529158142E1CED09B9C2186BF71A70C0FE2F1E0AEF3BD6B75277AAB20DFAF3D110F75912BFB63AC50EC4C48689D1502715243A79F39FF2DE2BF15CE438FF885745ED54573850E8A9F40EE2FF505EB7476F95ADB783B28CA374FAC4632892AB82FB3BF4715FCFE6E82D03731FC3762B6AAC3DF1C3BC646FE9CD3C62663A97EE72DB932A301312B4A7633100C8CC357262C39A2B3A64B224F5276D5EDBDF0804DC3AC4B835162BB1969EAEBADC43D2511D6E023928781B167A48273B953378D3D2080CC06777E8A2364F0234B81064C5C739A8DA28DC5889072BF37685CBC94C2D31D0179AD86D8E3AA8090D4F0B281BE37E0143746E6049CCC06899401264FA471C016A96C79815B55BBC26B43052609D9D175FBCDE455392F10E51EC162F51CF732E6BB391F56BBFD8D957DF3D4C55B71CEFD54B19C16D458757373E698D7E693A8FC39815A8BF03BA05EA8C8778D38F9873D62B4460F41ACF997C30E7C3AF025FA171B5F5AD4D6B15E95C27F6B35AD61875E5505449B4E6767392933
|
||||
```
|
||||
|
||||
This encrypted public key can be decrypted by my another repo: [how-does-navicat-encrypt-password](https://github.com/DoubleLabyrinth/how-does-navicat-encrypt-password), while the key used is `b'23970790'`.
|
||||
|
||||
Example:
|
||||
|
||||
```cmd
|
||||
E:\GitHub>git clone https://github.com/DoubleLabyrinth/how-does-navicat-encrypt-password.git
|
||||
...
|
||||
E:\GitHub>cd how-does-navicat-encrypt-password\python3
|
||||
E:\GitHub\how-does-navicat-encrypt-password\python3>python
|
||||
Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> from NavicatCrypto import *
|
||||
>>> cipher = Navicat11Crypto(b'23970790')
|
||||
>>> print(cipher.DecryptString('D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7BC0B880887D650F529158142E1CED09B9C2186BF71A70C0FE2F1E0AEF3BD6B75277AAB20DFAF3D110F75912BFB63AC50EC4C48689D1502715243A79F39FF2DE2BF15CE438FF885745ED54573850E8A9F40EE2FF505EB7476F95ADB783B28CA374FAC4632892AB82FB3BF4715FCFE6E82D03731FC3762B6AAC3DF1C3BC646FE9CD3C62663A97EE72DB932A301312B4A7633100C8CC357262C39A2B3A64B224F5276D5EDBDF0804DC3AC4B835162BB1969EAEBADC43D2511D6E023928781B167A48273B953378D3D2080CC06777E8A2364F0234B81064C5C739A8DA28DC5889072BF37685CBC94C2D31D0179AD86D8E3AA8090D4F0B281BE37E0143746E6049CCC06899401264FA471C016A96C79815B55BBC26B43052609D9D175FBCDE455392F10E51EC162F51CF732E6BB391F56BBFD8D957DF3D4C55B71CEFD54B19C16D458757373E698D7E693A8FC39815A8BF03BA05EA8C8778D38F9873D62B4460F41ACF997C30E7C3AF025FA171B5F5AD4D6B15E95C27F6B35AD61875E5505449B4E6767392933'))
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
|
||||
qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
|
||||
a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
|
||||
R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
|
||||
WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
|
||||
YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
|
||||
awIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
```
|
||||
|
||||
__NOTICE:__
|
||||
|
||||
Start from __Navicat Premium 12.1.11__, Navicat do not load the public key through the method I talked before. Of course, the public key is still stored in `libcc.dll`. When Navicat starts, it encrypts the public key by an 8-bytes-long XOR key and stores the ciphertext in static area. When verifing __Activation Code__, Navicat will regenerate the 8-bytes-long XOR key and decrypts the ciphertext in static area to get the public key.
|
||||
|
||||
In `libcc.dll`, x64 version, you can find some instructions that looks like:
|
||||
|
||||
```asm
|
||||
xor eax, 'M'
|
||||
mov byte_xxxxxx, al
|
||||
...
|
||||
xor eax, 'I'
|
||||
mov byte_xxxxxx, al
|
||||
...
|
||||
xor eax, 'I'
|
||||
mov byte_xxxxxx, al
|
||||
...
|
||||
xor eax, 'B'
|
||||
mov byte_xxxxxx, al
|
||||
...
|
||||
xor eax, 'I'
|
||||
mov byte_xxxxxx, al
|
||||
...
|
||||
xor eax, 'j'
|
||||
mov byte_xxxxxx, al
|
||||
...
|
||||
...
|
||||
```
|
||||
|
||||
* __Request Code__
|
||||
|
||||
It is a Base64 string that represents 256-bytes-long data, while the 256-bytes-long data is the cipher text of __Offline Activation Request Information__ encrypted by __Navicat Activation Public Key__.
|
||||
|
||||
* __Offline Activation Request Information__
|
||||
|
||||
It is just a JSON-style ASCII string which contains 3 items. They are `"K"`, `"DI"` and `"P"` respectively, which represent __snKey__, __DeviceIdentifier__ (related with your machine), __Platform__ (OS Type).
|
||||
|
||||
Like
|
||||
|
||||
```
|
||||
{"K": "xxxxxxxxxxxxxxxx", "DI": "yyyyyyyyyyyyy", "P": "WIN8"}
|
||||
```
|
||||
|
||||
* __Activation Code__
|
||||
|
||||
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 the official activation private key and we have to replace it in `navicat.exe` and `libcc.dll`.
|
||||
|
||||
* __Offline Activation Response Information__
|
||||
|
||||
Just like __Offline Activation Request Information__, it is also a JSON-style ASCII string. But it contains 5 items. They are `"K"`, `"N"`, `"O"`, `"T"` and `"DI"` respectively.
|
||||
|
||||
`"K"` and `"DI"` has the same meaning that is mentioned in __Offline Activation Request Information__ and must be the same with the corresponding items in __Offline Activation Request Information__.
|
||||
|
||||
`"N"`, `"O"`, `"T"` represent __Name__, __Organization__, __Timestamp__ respectively. __Name__ and __Organization__ are UTF-8 strings and the type of __Timestamp__ can be string or integer. (Thanks for discoveries from @Wizr, issue #10)
|
||||
|
||||
`"T"` can be omitted.
|
||||
|
||||
* __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 product language signatures.
|
||||
|
||||
| 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 3| |0x84 |0x85 | |
|
||||
|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 `uint8_t data[10]` is ready, Navicat uses __DES__ with __ECB mode__ to encrypt the last 8 bytes of `uint8_t data[10]` 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 use Base32 to encode `uint8_t data[10]` whose encode table is
|
||||
|
||||
```cpp
|
||||
char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
```
|
||||
|
||||
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, if need, `"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.
|
||||
|
||||
282
doc/how-does-it-work.zh-CN.md
Normal file
282
doc/how-does-it-work.zh-CN.md
Normal file
@ -0,0 +1,282 @@
|
||||
# Navicat Keygen - 注册机是怎么工作的?
|
||||
|
||||
## 1. 关键词解释.
|
||||
|
||||
* __Navicat激活公钥__
|
||||
|
||||
这是一个2048位的RSA公钥,Navicat使用这个公钥来完成相关激活信息的加密和解密。
|
||||
|
||||
这个公钥被作为 __RCData__ 类型的资源储存在 __navicat.exe__ 当中。资源名为`"ACTIVATIONPUBKEY"`。你可以使用一个叫[Resource Hacker](http://www.angusj.com/resourcehacker/)的软件来查看它。这个公钥的具体内容为:
|
||||
|
||||
```
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
|
||||
qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
|
||||
a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
|
||||
R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
|
||||
WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
|
||||
YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
|
||||
awIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
```
|
||||
|
||||
如果您有相应的私钥并乐意公开的话欢迎联系我,我将非常感谢您的慷慨。
|
||||
|
||||
__注意:__
|
||||
|
||||
从 __Navicat Premium 12.0.25__ 开始,Navicat不再从`navicat.exe`的资源中加载私钥。事实上,公钥转为从`libcc.dll`中加载,并且已经被加密。与此同时,为了防止被轻松地替换,加密的公钥被分到5个地方储存:
|
||||
|
||||
以下内容是从 __Navicat Premium x64 12.0.25 简体中文版__ 的`libcc.dll`中发现的,`libcc.dll`的SHA256值为`607e0a84c75966b00f3d12fa833e91d159e4f51ac51b6ba66f98d0c3cbefdce0`。我不保证在Navicat的其他版本中相关偏移量和下述的相同,但相关的 __字符串__ 以及 __立即数__ 是很可能找得到的。
|
||||
|
||||
1. 在`libcc.dll`中,文件偏移量`+0x01A12090`的地方,储存了加密公钥的第一部分,以 __字符串__ 的形式储存:
|
||||
|
||||
```
|
||||
"D75125B70767B94145B47C1CB3C0755E
|
||||
7CCB8825C5DCE0C58ACF944E08280140
|
||||
9A02472FAFFD1CD77864BB821AE36766
|
||||
FEEDE6A24F12662954168BFA314BD950
|
||||
32B9D82445355ED7BC0B880887D650F5"
|
||||
```
|
||||
|
||||
2. 在`libcc.dll`中,文件偏移量`+0x0059D799`的地方,储存了加密公钥的第二部分,以 __立即数__ 的形式储存在一条指令中:
|
||||
|
||||
```
|
||||
0xFE 0xEA 0xBC 0x01
|
||||
```
|
||||
|
||||
相应的十进制值为: `29158142`
|
||||
|
||||
3. 在`libcc.dll`中,文件偏移量`+0x01A11DA0`的地方,储存了加密公钥的第三部分,以 __字符串__ 的形式储存:
|
||||
|
||||
```
|
||||
"E1CED09B9C2186BF71A70C0FE2F1E0AE
|
||||
F3BD6B75277AAB20DFAF3D110F75912B
|
||||
FB63AC50EC4C48689D1502715243A79F
|
||||
39FF2DE2BF15CE438FF885745ED54573
|
||||
850E8A9F40EE2FF505EB7476F95ADB78
|
||||
3B28CA374FAC4632892AB82FB3BF4715
|
||||
FCFE6E82D03731FC3762B6AAC3DF1C3B
|
||||
C646FE9CD3C62663A97EE72DB932A301
|
||||
312B4A7633100C8CC357262C39A2B3A6
|
||||
4B224F5276D5EDBDF0804DC3AC4B8351
|
||||
62BB1969EAEBADC43D2511D6E0239287
|
||||
81B167A48273B953378D3D2080CC0677
|
||||
7E8A2364F0234B81064C5C739A8DA28D
|
||||
C5889072BF37685CBC94C2D31D0179AD
|
||||
86D8E3AA8090D4F0B281BE37E0143746
|
||||
E6049CCC06899401264FA471C016A96C
|
||||
79815B55BBC26B43052609D9D175FBCD
|
||||
E455392F10E51EC162F51CF732E6BB39
|
||||
1F56BBFD8D957DF3D4C55B71CEFD54B1
|
||||
9C16D458757373E698D7E693A8FC3981
|
||||
5A8BF03BA05EA8C8778D38F9873D62B4
|
||||
460F41ACF997C30E7C3AF025FA171B5F
|
||||
5AD4D6B15E95C27F6B35AD61875E5505
|
||||
449B4E"
|
||||
```
|
||||
|
||||
4. 在`libcc.dll`中,文件偏移量`+0x0059D77F`的地方,储存了加密公钥的第四部分,以 __立即数__ 的形式储存在一条指令中:
|
||||
|
||||
```
|
||||
0x59 0x08 0x01 0x00
|
||||
```
|
||||
|
||||
相应的十进制值为: `67673`
|
||||
|
||||
5. 在`libcc.dll`中,文件偏移量`+0x01A11D8C`的地方,储存了加密公钥的第五部分,以 __字符串__ 的形式储存:
|
||||
|
||||
```
|
||||
"92933"
|
||||
```
|
||||
|
||||
这五部分按照`"%s%d%s%d%s"`的形式输出则为加密的公钥,顺序和上述的顺序相同,具体的输出为:
|
||||
|
||||
```
|
||||
|
||||
D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7BC0B880887D650F529158142E1CED09B9C2186BF71A70C0FE2F1E0AEF3BD6B75277AAB20DFAF3D110F75912BFB63AC50EC4C48689D1502715243A79F39FF2DE2BF15CE438FF885745ED54573850E8A9F40EE2FF505EB7476F95ADB783B28CA374FAC4632892AB82FB3BF4715FCFE6E82D03731FC3762B6AAC3DF1C3BC646FE9CD3C62663A97EE72DB932A301312B4A7633100C8CC357262C39A2B3A64B224F5276D5EDBDF0804DC3AC4B835162BB1969EAEBADC43D2511D6E023928781B167A48273B953378D3D2080CC06777E8A2364F0234B81064C5C739A8DA28DC5889072BF37685CBC94C2D31D0179AD86D8E3AA8090D4F0B281BE37E0143746E6049CCC06899401264FA471C016A96C79815B55BBC26B43052609D9D175FBCDE455392F10E51EC162F51CF732E6BB391F56BBFD8D957DF3D4C55B71CEFD54B19C16D458757373E698D7E693A8FC39815A8BF03BA05EA8C8778D38F9873D62B4460F41ACF997C30E7C3AF025FA171B5F5AD4D6B15E95C27F6B35AD61875E5505449B4E6767392933
|
||||
|
||||
```
|
||||
|
||||
这个加密的公钥可以用我的另外一个repo([how-does-navicat-encrypt-password](https://github.com/DoubleLabyrinth/how-does-navicat-encrypt-password))解密,其中密钥为`b'23970790'`。
|
||||
|
||||
例如:
|
||||
|
||||
```cmd
|
||||
E:\GitHub>git clone https://github.com/DoubleLabyrinth/how-does-navicat-encrypt-password.git
|
||||
...
|
||||
E:\GitHub>cd how-does-navicat-encrypt-password\python3
|
||||
E:\GitHub\how-does-navicat-encrypt-password\python3>python
|
||||
Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> from NavicatCrypto import *
|
||||
>>> cipher = Navicat11Crypto(b'23970790')
|
||||
>>> print(cipher.DecryptString('D75125B70767B94145B47C1CB3C0755E7CCB8825C5DCE0C58ACF944E082801409A02472FAFFD1CD77864BB821AE36766FEEDE6A24F12662954168BFA314BD95032B9D82445355ED7BC0B880887D650F529158142E1CED09B9C2186BF71A70C0FE2F1E0AEF3BD6B75277AAB20DFAF3D110F75912BFB63AC50EC4C48689D1502715243A79F39FF2DE2BF15CE438FF885745ED54573850E8A9F40EE2FF505EB7476F95ADB783B28CA374FAC4632892AB82FB3BF4715FCFE6E82D03731FC3762B6AAC3DF1C3BC646FE9CD3C62663A97EE72DB932A301312B4A7633100C8CC357262C39A2B3A64B224F5276D5EDBDF0804DC3AC4B835162BB1969EAEBADC43D2511D6E023928781B167A48273B953378D3D2080CC06777E8A2364F0234B81064C5C739A8DA28DC5889072BF37685CBC94C2D31D0179AD86D8E3AA8090D4F0B281BE37E0143746E6049CCC06899401264FA471C016A96C79815B55BBC26B43052609D9D175FBCDE455392F10E51EC162F51CF732E6BB391F56BBFD8D957DF3D4C55B71CEFD54B19C16D458757373E698D7E693A8FC39815A8BF03BA05EA8C8778D38F9873D62B4460F41ACF997C30E7C3AF025FA171B5F5AD4D6B15E95C27F6B35AD61875E5505449B4E6767392933'))
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I
|
||||
qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv
|
||||
a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF
|
||||
R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2
|
||||
WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt
|
||||
YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ
|
||||
awIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
```
|
||||
|
||||
__注意:__
|
||||
|
||||
从 __Navicat Premium 12.1.11__ 开始,Navicat不再用上面说的方法加载密钥。当然密钥还是储存在`libcc.dll`文件中。当Navicat启动时,它会用8字节长的XOR密钥来加密公钥,并储存到一个静态数据区中。当验证 __激活码__ 时,Navicat会重新生成一样的8字节XOR密钥,并解密在静态储存区中的密文,从而获取公钥。
|
||||
|
||||
在`libcc.dll`,x64版本中,你会看到如下的几条指令:
|
||||
|
||||
```asm
|
||||
xor eax, 'M'
|
||||
mov byte_xxxxxx, al
|
||||
...
|
||||
xor eax, 'I'
|
||||
mov byte_xxxxxx, al
|
||||
...
|
||||
xor eax, 'I'
|
||||
mov byte_xxxxxx, al
|
||||
...
|
||||
xor eax, 'B'
|
||||
mov byte_xxxxxx, al
|
||||
...
|
||||
xor eax, 'I'
|
||||
mov byte_xxxxxx, al
|
||||
...
|
||||
xor eax, 'j'
|
||||
mov byte_xxxxxx, al
|
||||
...
|
||||
...
|
||||
```
|
||||
|
||||
* __请求码__
|
||||
|
||||
这是一个Base64编码的字符串,代表的是长度为256字节的数据。这256字节的数据是 __离线激活信息__ 用 __Navicat激活公钥__ 加密的密文。
|
||||
|
||||
* __离线激活请求信息__
|
||||
|
||||
这是一个JSON风格的字符串。它包含了3个Key:`"K"`、`"DI"`和`"P"`,分别代表 __序列号__、__设备识别码__(与你的电脑硬件信息相关)和 __平台__ (其实就是操作系统类型)。
|
||||
|
||||
例如:
|
||||
|
||||
```
|
||||
{"K": "xxxxxxxxxxxxxxxx", "DI": "yyyyyyyyyyyyy", "P": "WIN8"}
|
||||
```
|
||||
|
||||
* __激活码__
|
||||
|
||||
这是一个Base64编码的字符串,代表的是长度为256字节的数据。这256字节的数据是 __离线激活回复信息__ 用 __Navicat激活私钥__ 加密的密文。目前我们不知道官方的 __Navicat激活私钥__,所以我们得替换掉软件里的公钥。
|
||||
|
||||
* __离线激活回复信息__
|
||||
|
||||
和 __离线激活请求信息__ 一样,它也是一个JSON风格的字符串。但是它包含5个Key,分别为`"K"`、`"N"`、`"O"`、`"T"` 和 `"DI"`.
|
||||
|
||||
`"K"` 和 `"DI"` 的意义与 __离线激活请求信息__ 中的相同,且Value必须与 __离线激活请求信息__ 中的相同。
|
||||
|
||||
`"N"`、`"O"`、`"T"` 分别代表 __注册名__、__组织__、__授权时间__。
|
||||
|
||||
__注册名__ 和 __组织__ 的值类型为UTF-8编码的字符串。__授权时间__ 的值类型可以为字符串或整数(感谢@Wizr在issue #10中的报告)。
|
||||
|
||||
`"T"` 可以被省略。
|
||||
|
||||
* __序列号__
|
||||
|
||||
这是一个被分为了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 3| |0x84 |0x85 | |
|
||||
|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
|
||||
unsigned char DESKey = { 0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27 };
|
||||
```
|
||||
|
||||
之后使用Base32编码 __data[10]__,其中编码表改为:
|
||||
|
||||
```cpp
|
||||
char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
```
|
||||
|
||||
编码之后你应该会得到一个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软件中填入 __激活码__ 即可完成离线激活。
|
||||
|
||||
60
doc/how-to-build.md
Normal file
60
doc/how-to-build.md
Normal file
@ -0,0 +1,60 @@
|
||||
# navicat-keygen for windows - How to build?
|
||||
|
||||
[中文版](how-to-build.zh-CN.md)
|
||||
|
||||
## 1. Prerequisites
|
||||
|
||||
1. Please make sure that you have __Visual Studio 2022__ or the higher. Because this is a VS2022 project.
|
||||
|
||||
2. Please make sure you have installed `vcpkg` and the following libraries:
|
||||
|
||||
* `fmt:x64-windows-static`
|
||||
* `fmt:x86-windows-static`
|
||||
* `openssl:x64-windows-static`
|
||||
* `openssl:x86-windows-static`
|
||||
* `rapidjson:x64-windows-static`
|
||||
* `rapidjson:x86-windows-static`
|
||||
* `keystone:x64-windows-static`
|
||||
* `keystone:x86-windows-static`
|
||||
* `unicorn:x64-windows-static`
|
||||
* `unicorn:x86-windows-static`
|
||||
|
||||
is installed.
|
||||
|
||||
You can install them by:
|
||||
|
||||
```console
|
||||
$ vcpkg install fmt:x64-windows-static
|
||||
$ vcpkg install fmt:x86-windows-static
|
||||
$ vcpkg install openssl:x64-windows-static
|
||||
$ vcpkg install openssl:x86-windows-static
|
||||
$ vcpkg install rapidjson:x64-windows-static
|
||||
$ vcpkg install rapidjson:x86-windows-static
|
||||
$ vcpkg install keystone:x64-windows-static
|
||||
$ vcpkg install keystone:x86-windows-static
|
||||
$ vcpkg install unicorn:x64-windows-static
|
||||
$ vcpkg install unicorn:x86-windows-static
|
||||
```
|
||||
|
||||
3. Your `vcpkg` has been integrated into your __Visual Studio__, which means you have run
|
||||
|
||||
```console
|
||||
$ vcpkg integrate install
|
||||
```
|
||||
|
||||
successfully.
|
||||
|
||||
## 2. Build
|
||||
|
||||
1. Open this project in __Visual Studio__.
|
||||
|
||||
2. Select `Release` configuration.
|
||||
|
||||
3. Select `Win32` to build keygen/patcher for 32-bits Navicat.
|
||||
|
||||
Or select `x64` to build keygen/patcher for 64-bits Navicat.
|
||||
|
||||
4. Select __Build > Build Solution__.
|
||||
|
||||
You will see executable files in `bin/` directory.
|
||||
|
||||
54
doc/how-to-build.zh-CN.md
Normal file
54
doc/how-to-build.zh-CN.md
Normal file
@ -0,0 +1,54 @@
|
||||
# navicat-keygen for windows - 如何编译?
|
||||
|
||||
## 1. 前提条件
|
||||
|
||||
1. 请确保你有 __Visual Studio 2022__ 或者更高版本。因为这是一个VS2022项目。
|
||||
|
||||
2. 请确保你安装了 `vcpkg` 以及下面几个库:
|
||||
|
||||
* `fmt:x64-windows-static`
|
||||
* `fmt:x86-windows-static`
|
||||
* `openssl:x64-windows-static`
|
||||
* `openssl:x86-windows-static`
|
||||
* `rapidjson:x64-windows-static`
|
||||
* `rapidjson:x86-windows-static`
|
||||
* `keystone:x64-windows-static`
|
||||
* `keystone:x86-windows-static`
|
||||
* `unicorn:x64-windows-static`
|
||||
* `unicorn:x86-windows-static`
|
||||
|
||||
你可以通过下面的命令来安装它们:
|
||||
|
||||
```console
|
||||
$ vcpkg install fmt:x64-windows-static
|
||||
$ vcpkg install fmt:x86-windows-static
|
||||
$ vcpkg install openssl:x64-windows-static
|
||||
$ vcpkg install openssl:x86-windows-static
|
||||
$ vcpkg install rapidjson:x64-windows-static
|
||||
$ vcpkg install rapidjson:x86-windows-static
|
||||
$ vcpkg install keystone:x64-windows-static
|
||||
$ vcpkg install keystone:x86-windows-static
|
||||
$ vcpkg install unicorn:x64-windows-static
|
||||
$ vcpkg install unicorn:x86-windows-static
|
||||
```
|
||||
|
||||
3. 你的 `vcpkg` 已经和你的 __Visual Studio__ 集成了,即你曾成功运行了:
|
||||
|
||||
```console
|
||||
$ vcpkg integrate install
|
||||
```
|
||||
|
||||
## 2. 编译
|
||||
|
||||
1. 在 __Visual Studio__ 打开这个项目。
|
||||
|
||||
2. 选择 `Release` 配置。
|
||||
|
||||
3. 选择 `Win32` 来生成供32位Navicat使用的keygen/patcher。
|
||||
|
||||
或者选择 `x64` 来生成供64位Navicat使用的keygen/patcher。
|
||||
|
||||
4. 选择 __生成 > 生成解决方案__。
|
||||
|
||||
生成完成后,你会在 `bin/` 文件夹下看到编译后的keygen/patcher。
|
||||
|
||||
196
doc/how-to-use.md
Normal file
196
doc/how-to-use.md
Normal file
@ -0,0 +1,196 @@
|
||||
# navicat-keygen for windows - How to use?
|
||||
|
||||
[中文版](how-to-use.windows.zh-CN.md)
|
||||
|
||||
1. Use `navicat-patcher.exe` to replace __Navicat Activation Public Key__ that is stored in `libcc.dll`.
|
||||
|
||||
```
|
||||
navicat-patcher.exe [-dry-run] <Navicat Install Path> [RSA-2048 PEM File Path]
|
||||
```
|
||||
|
||||
* `[-dry-run]` Run patcher without applying any patches.
|
||||
|
||||
__This parameter is optional.__
|
||||
|
||||
* `<Navicat Install Path>`: The full path to Navicat installation folder.
|
||||
|
||||
__This parameter must be specified.__
|
||||
|
||||
* `[RSA-2048 PEM File Path]`: The full path or relative path to a RSA-2048 private key file.
|
||||
|
||||
__This parameter is optional.__ If not specified, `navicat-patcher.exe` will generate a new RSA-2048 private key file `RegPrivateKey.pem` at current directory.
|
||||
|
||||
__Example: (in cmd.exe)__
|
||||
|
||||
```
|
||||
navicat-patcher.exe "C:\Program Files\PremiumSoft\Navicat Premium 16"
|
||||
```
|
||||
|
||||
It has been tested on __Navicat Premium 16.0.7 English version__. The following is an example of output.
|
||||
|
||||
```
|
||||
***************************************************
|
||||
* navicat-patcher by @DoubleLabyrinth *
|
||||
* version: 16.0.7.0 *
|
||||
***************************************************
|
||||
|
||||
[+] Try to open libcc.dll ... OK!
|
||||
|
||||
[*] patch_solution_since<16, 0, 7, 0>: m_va_CSRegistrationInfoFetcher_WIN_vtable = 0x00000001837759f0
|
||||
[*] patch_solution_since<16, 0, 7, 0>: m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey = 0x0000000181fa52d0
|
||||
[*] patch_solution_since<16, 0, 7, 0>: m_va_iat_entry_malloc = 0x0000000183439bd0
|
||||
[+] patch_solution_since<16, 0, 7, 0>: official encoded key is found.
|
||||
|
||||
[*] Generating new RSA private key, it may take a long time...
|
||||
[*] Your RSA private key:
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEAvxaFFjTE6hi80nhjgfFMM3yPer122OIWIbbumFIuAOcCF6D3
|
||||
PnRHBdP9IqB99K6Nv6vKK3Jf0Y+dc5ETrg0l0AHYq+dTFTiWusHuRMx6xFjWzO96
|
||||
7mFmJq6P28dUucKnr6yG1TQeZaq+mHh2DNEnNEYgV7cLVT1unUmMOL/PBh/eCcaJ
|
||||
8hQNTQafQQknzCnAKC89v33y+rKInJNy9B+zSB0BGCz+eS8MKf6zc78JMSOnF2uj
|
||||
NK+QEwaYw8lAbJve1F+rCQS0mbm0QvHhZYZrblVHI5l/8LkX5qBtKw7duUhXHxmO
|
||||
fQieF23bBk9HDp5uQUGsdbKX6ZWitn/h926xyQIDAQABAoIBAQCHXxDRdni5zuSV
|
||||
xivYdnUhVHDg5zA23ZQINmw5BJ8KjJzy2FnPqNhXzKJb0Y7ptG8/BhinRtOSxkcp
|
||||
A/IJL89F2MkCn1JAimJd091UZ/fg+X7SmCVikyWm6auIa2IeZ0QcNAEhMVcHdzqn
|
||||
EU+wLMu1QKjQ+x/QN0ERtHTeDyQ+lUNB+bvAjx3LHN9Zh8weVBHHtwDoyyZDdJPw
|
||||
NWgpgcW+uYzlT66uh7LPPaRsEZgAkPIkhzZnwmugXdhlWxtYHKTEfe5gCqubQICc
|
||||
I/x1yBP1EZFm6qBQD4/49775ZbXwxgaWvBXG+Aah9x8JYtVUS4MgrAiC4a8NQqFp
|
||||
nwKVjUIBAoGBAOWsj9GGb2KYbfLzJNRrSxhs4TUBfpHteKSm2pL92NAbIOjssNhL
|
||||
hLY3gBFX2RnYmoGD6YT84JNykuAictgAd5GwvLIbaVF9l7MQn8APRbe2CzQ+/494
|
||||
9hpn33MZOBNd3I+a5+2qoFbXI04loyYDJkkeOqbwZzJjs7k9HmZMNwY5AoGBANT9
|
||||
tRFWFDvA0pPgGoHhzlsAUAmrbSfCPkhrRXpE9fgl3VnV+NRtjCf9NhJt0uaIokZ5
|
||||
oSf+jClcwU8N4EvGxMBaCHTqBzgc4dLPWpMAhPoMjjv1Oyug2iBcuTasHVP+Jdgq
|
||||
CaNzpXOuq4upaaNrq+QMsI6O9wA/zWhWPmnYQYgRAoGAUk56471noU+65zvXUQB6
|
||||
UvCB7Hrynt0ZRPg+kDrEPh/atV5NKdY2Yw6UqKJwvOBwzkU1pGDzIiQHGqd9vIa+
|
||||
Usmhdbp5DakSeitU9IEEnQdyEHEbKJFSsLfUzeyVuesDJbt/rh5dg4Fpt5GpW+/5
|
||||
Am8A2d6BPP+Z4qJSiJp7hZECgYEAy64TCZEXqEytE1yr/KjDfaK+54BX0j2e8gIj
|
||||
XtmznqoXE2Hboslfzp4Gp3j+xhbDmEGYK3bw8l0RP1g1tkFOxeNTUvq6DJ8SFVbV
|
||||
dt54S+bV3eCVxRL9hRUmyXGuWjQgXKdWsEhXYFkZE2Xe77h3mI3KCYoOCt74v146
|
||||
MV3szQECgYEAozTO7Wuum+VMKIY35hmHMjUiYmLl3EXWwMBT2VSsk8Siu0XoH0yd
|
||||
KoxsLDUBMS8sWKCZhFwU+Fx8UZjfo+xE3H4UTyVsw5EDpB9gSud928gNADwxTKor
|
||||
3s4jnUzb4XRQ0qN2jXzdNuqXNV1ozeqajbM2oSZqbSnWSs5g6DpIs1Q=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
||||
[*] patch_solution_since<16, 0, 7, 0>: Patch has been done.
|
||||
[*] New RSA-2048 private key has been saved to
|
||||
C:\Users\DoubleSine\source\repos\navicat-keygen\bin\x64-Release\RegPrivateKey.pem
|
||||
|
||||
|
||||
*******************************************************
|
||||
* PATCH HAS BEEN DONE SUCCESSFULLY! *
|
||||
* HAVE FUN AND ENJOY~ *
|
||||
*******************************************************
|
||||
```
|
||||
|
||||
2. Then use `navicat-keygen.exe` to generate __snKey__ and __Activation Code__
|
||||
|
||||
```
|
||||
navicat-keygen.exe <-bin|-text> [-adv] <RSA-2048 Private Key File>
|
||||
```
|
||||
|
||||
* `<-bin|-text>`: Must be `-bin` or `-text`.
|
||||
|
||||
If `-bin` is specified, `navicat-keygen.exe` will finally generate `license_file`. It is used for Navicat old activation method only.
|
||||
|
||||
If `-text` is specified, `navicat-keygen.exe` will finally generate a Base64-style string which is __Activation Code__. It is used for Navicat new activation method.
|
||||
|
||||
__This parameter must be specified.__
|
||||
|
||||
* `[-adv]`: Enable advanced mode.
|
||||
|
||||
__This parameter is optional.__ If specified, `navicat-keygen.exe` will ask you input Navicat product ID number, language signature numbers. It is for future use generally.
|
||||
|
||||
* `<RSA-2048 Private Key File>`: The full path or relative path to an RSA-2048 private key file. The private key must be in PEM format.
|
||||
|
||||
__This parameter must be specified.__
|
||||
|
||||
__Example: (in cmd.exe)__
|
||||
|
||||
```console
|
||||
navicat-keygen.exe -text .\RegPrivateKey.pem
|
||||
```
|
||||
|
||||
You will be asked to select Navicat product, language and input major version number. After that an randomly generated __snKey__ will be given.
|
||||
|
||||
```
|
||||
***************************************************
|
||||
* navicat-keygen by @DoubleLabyrinth *
|
||||
* version: 16.0.7.0 *
|
||||
***************************************************
|
||||
|
||||
[*] Select Navicat product:
|
||||
0. DataModeler
|
||||
1. Premium
|
||||
2. MySQL
|
||||
3. PostgreSQL
|
||||
4. Oracle
|
||||
5. SQLServer
|
||||
6. SQLite
|
||||
7. MariaDB
|
||||
8. MongoDB
|
||||
9. ReportViewer
|
||||
|
||||
(Input index)> 1
|
||||
|
||||
[*] Select product 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)> 0
|
||||
|
||||
[*] Input major version number:
|
||||
(range: 11 ~ 16, default: 16)> 16
|
||||
|
||||
[*] Serial number:
|
||||
NAVL-GFKA-T5SR-ZFTK
|
||||
|
||||
[*] Your name:
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
```
|
||||
[*] Your name: Double Sine
|
||||
[*] Your organization: PremiumSoft CyberTech Ltd.
|
||||
|
||||
[*] Input request code (in Base64), input empty line to end:
|
||||
```
|
||||
|
||||
After that, you will be asked to input the request code. Now __DO NOT CLOSE KEYGEN__.
|
||||
|
||||
3. __Disconnect your network__ and open Navicat. Find and click `Registration`. Fill `Registration Key` by __snKey__ that the keygen gave and click `Activate`.
|
||||
|
||||
4. Generally online activation will failed and Navicat will ask you do `Manual Activation`, just choose it.
|
||||
|
||||
5. Copy your request code and paste it in the keygen. Input empty line to tell the keygen that your input ends.
|
||||
|
||||
```
|
||||
[*] Your name: Double Sine
|
||||
[*] Your organization: PremiumSoft CyberTech Ltd.
|
||||
|
||||
[*] Input request code (in Base64), input empty line to end:
|
||||
CpgnfbIJGmAcxCuo/pAb8EeoS0audZn2NNemg6c3NPK/dWgb343IZQrFwoBZY6lpxE4Fq1BoNmCM75P03XpiXQ+hErcvFWk6iQPDCk/d4msf/AoprIqAMpXFoFLkeP0G93UIIEeBsUej8SrxdDgQDM585iPok5fUW+fTDCD1VICr7DBdL3c/69IxeIgiOQSuImdIQiM3/EOfDiFbAJL9vHW5LxFT8jj+8RPXehwPTBphpInmGdzxVZUZJwAGlXt7orrRbzafdeBjz6MnTajTcJP3SS2dBCiR33UScnyxYGEXdzv7+QLScTmCvI7gqg3Z8DMhroKMoHmy1AvC16FKVw==
|
||||
|
||||
[*] Request Info:
|
||||
{"K":"NAVLGFKAT5SRZFTK", "DI":"7D48FCBD093C778879A1", "P":"WIN"}
|
||||
|
||||
[*] Response Info:
|
||||
{"K":"NAVLGFKAT5SRZFTK","DI":"7D48FCBD093C778879A1","N":"Double Sine","O":"PremiumSoft CyberTech Ltd.","T":1644387294}
|
||||
|
||||
[*] Activation Code:
|
||||
vwLGmQIWg/DtzHMcaKCDHAjTcBNbTo2VmNllphUSUMgGjgvL6v82ue+GqXB6M/qn48Rj4D4Joqqisr6UwMSclNmQxOQz4RftEpLtG6KBjDo4LM71qn9R/jWoZV5EoHPQkX5gzhO/D7GammrRGn2MV+zI6dJ4c4SBFNnNyjAeEqNzinrQwjB7lUVTlpHEe/SMrdCsGliPZQ/X+5ASbEsq3D8PZsjysJv98MIJrZvdTdznrRe8JzYP+8sbIPQMIX1UDmdyDpbpSl45N92OhO4htz1kFjUEfnrwY0GMOhdYHv/PfMI7RiQzkRyY7pLvX7muJ4dkA+CmMmwew3gy3MWjig==
|
||||
```
|
||||
|
||||
6. Finally, you will get __Activation Code__ which looks like a Base64 string. Just copy it and paste it in Navicat `Manual Activation` window, then click `Activate`. If nothing wrong, activation should be done successfully.
|
||||
|
||||
194
doc/how-to-use.zh-CN.md
Normal file
194
doc/how-to-use.zh-CN.md
Normal file
@ -0,0 +1,194 @@
|
||||
# navicat-keygen for windows - 如何使用这个注册机?
|
||||
|
||||
1. 使用`navicat-patcher.exe`替换掉`navicat.exe`和`libcc.dll`里的Navicat激活公钥。
|
||||
|
||||
```
|
||||
navicat-patcher.exe [-dry-run] <Navicat Install Path> [RSA-2048 PEM File Path]
|
||||
```
|
||||
|
||||
* `[-dry-run]`: 运行patcher但不对Navicat程序做任何修改。
|
||||
|
||||
__这个参数是可选的。__
|
||||
|
||||
* `<Navicat Install Path>`: Navicat的完整安装路径。
|
||||
|
||||
__这个参数必须指定。__
|
||||
|
||||
* `[RSA-2048 PEM File Path]`: RSA-2048私钥文件的完整路径或相对路径。
|
||||
|
||||
__这个参数是可选的。__ 如果未指定,`navicat-patcher.exe`将会在当前目录生成一个新的RSA-2048私钥文件。
|
||||
|
||||
__例如:(在cmd.exe中)__
|
||||
|
||||
```
|
||||
navicat-patcher.exe "C:\Program Files\PremiumSoft\Navicat Premium 16"
|
||||
```
|
||||
|
||||
__Navicat Premium 16.0.7 英文版__ 已通过测试。下面将是一份样例输出:
|
||||
|
||||
```
|
||||
***************************************************
|
||||
* navicat-patcher by @DoubleLabyrinth *
|
||||
* version: 16.0.7.0 *
|
||||
***************************************************
|
||||
|
||||
[+] Try to open libcc.dll ... OK!
|
||||
|
||||
[*] patch_solution_since<16, 0, 7, 0>: m_va_CSRegistrationInfoFetcher_WIN_vtable = 0x00000001837759f0
|
||||
[*] patch_solution_since<16, 0, 7, 0>: m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey = 0x0000000181fa52d0
|
||||
[*] patch_solution_since<16, 0, 7, 0>: m_va_iat_entry_malloc = 0x0000000183439bd0
|
||||
[+] patch_solution_since<16, 0, 7, 0>: official encoded key is found.
|
||||
|
||||
[*] Generating new RSA private key, it may take a long time...
|
||||
[*] Your RSA private key:
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEAvxaFFjTE6hi80nhjgfFMM3yPer122OIWIbbumFIuAOcCF6D3
|
||||
PnRHBdP9IqB99K6Nv6vKK3Jf0Y+dc5ETrg0l0AHYq+dTFTiWusHuRMx6xFjWzO96
|
||||
7mFmJq6P28dUucKnr6yG1TQeZaq+mHh2DNEnNEYgV7cLVT1unUmMOL/PBh/eCcaJ
|
||||
8hQNTQafQQknzCnAKC89v33y+rKInJNy9B+zSB0BGCz+eS8MKf6zc78JMSOnF2uj
|
||||
NK+QEwaYw8lAbJve1F+rCQS0mbm0QvHhZYZrblVHI5l/8LkX5qBtKw7duUhXHxmO
|
||||
fQieF23bBk9HDp5uQUGsdbKX6ZWitn/h926xyQIDAQABAoIBAQCHXxDRdni5zuSV
|
||||
xivYdnUhVHDg5zA23ZQINmw5BJ8KjJzy2FnPqNhXzKJb0Y7ptG8/BhinRtOSxkcp
|
||||
A/IJL89F2MkCn1JAimJd091UZ/fg+X7SmCVikyWm6auIa2IeZ0QcNAEhMVcHdzqn
|
||||
EU+wLMu1QKjQ+x/QN0ERtHTeDyQ+lUNB+bvAjx3LHN9Zh8weVBHHtwDoyyZDdJPw
|
||||
NWgpgcW+uYzlT66uh7LPPaRsEZgAkPIkhzZnwmugXdhlWxtYHKTEfe5gCqubQICc
|
||||
I/x1yBP1EZFm6qBQD4/49775ZbXwxgaWvBXG+Aah9x8JYtVUS4MgrAiC4a8NQqFp
|
||||
nwKVjUIBAoGBAOWsj9GGb2KYbfLzJNRrSxhs4TUBfpHteKSm2pL92NAbIOjssNhL
|
||||
hLY3gBFX2RnYmoGD6YT84JNykuAictgAd5GwvLIbaVF9l7MQn8APRbe2CzQ+/494
|
||||
9hpn33MZOBNd3I+a5+2qoFbXI04loyYDJkkeOqbwZzJjs7k9HmZMNwY5AoGBANT9
|
||||
tRFWFDvA0pPgGoHhzlsAUAmrbSfCPkhrRXpE9fgl3VnV+NRtjCf9NhJt0uaIokZ5
|
||||
oSf+jClcwU8N4EvGxMBaCHTqBzgc4dLPWpMAhPoMjjv1Oyug2iBcuTasHVP+Jdgq
|
||||
CaNzpXOuq4upaaNrq+QMsI6O9wA/zWhWPmnYQYgRAoGAUk56471noU+65zvXUQB6
|
||||
UvCB7Hrynt0ZRPg+kDrEPh/atV5NKdY2Yw6UqKJwvOBwzkU1pGDzIiQHGqd9vIa+
|
||||
Usmhdbp5DakSeitU9IEEnQdyEHEbKJFSsLfUzeyVuesDJbt/rh5dg4Fpt5GpW+/5
|
||||
Am8A2d6BPP+Z4qJSiJp7hZECgYEAy64TCZEXqEytE1yr/KjDfaK+54BX0j2e8gIj
|
||||
XtmznqoXE2Hboslfzp4Gp3j+xhbDmEGYK3bw8l0RP1g1tkFOxeNTUvq6DJ8SFVbV
|
||||
dt54S+bV3eCVxRL9hRUmyXGuWjQgXKdWsEhXYFkZE2Xe77h3mI3KCYoOCt74v146
|
||||
MV3szQECgYEAozTO7Wuum+VMKIY35hmHMjUiYmLl3EXWwMBT2VSsk8Siu0XoH0yd
|
||||
KoxsLDUBMS8sWKCZhFwU+Fx8UZjfo+xE3H4UTyVsw5EDpB9gSud928gNADwxTKor
|
||||
3s4jnUzb4XRQ0qN2jXzdNuqXNV1ozeqajbM2oSZqbSnWSs5g6DpIs1Q=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
||||
[*] patch_solution_since<16, 0, 7, 0>: Patch has been done.
|
||||
[*] New RSA-2048 private key has been saved to
|
||||
C:\Users\DoubleSine\source\repos\navicat-keygen\bin\x64-Release\RegPrivateKey.pem
|
||||
|
||||
|
||||
*******************************************************
|
||||
* PATCH HAS BEEN DONE SUCCESSFULLY! *
|
||||
* HAVE FUN AND ENJOY~ *
|
||||
*******************************************************
|
||||
```
|
||||
|
||||
2. 接下来使用`navicat-keygen.exe`来生成序列号和激活码
|
||||
|
||||
```
|
||||
navicat-keygen.exe <-bin|-text> [-adv] <RSA-2048 Private Key File>
|
||||
```
|
||||
|
||||
* `<-bin|-text>`: 必须是`-bin`或`-text`。
|
||||
|
||||
如果指定了`-bin`,`navicat-keygen.exe`最终将生成`license_file`文件。这个选项是给Navicat旧激活方式使用的。
|
||||
|
||||
如果指定了`-text`,`navicat-keygen.exe`最终将生成Base64样式的激活码。这个选项是给Navicat新激活方式使用的。
|
||||
|
||||
__这个参数必须指定。__
|
||||
|
||||
* `[-adv]`: 开启高级模式。
|
||||
|
||||
__这个参数是可选的。__ 如果指定了这个参数,`navicat-keygen.exe`将会要求你手工填写产品ID号、语言标识号。这个选项一般是给以后用的。
|
||||
|
||||
* `<RSA-2048 Private Key File>`: RSA-2048私钥文件的完整路径或相对路径。私钥必须是PEM格式的。
|
||||
|
||||
__这个参数必须指定。__
|
||||
|
||||
__例如:(在cmd.exe中)__
|
||||
|
||||
```console
|
||||
navicat-keygen.exe -text .\RegPrivateKey.pem
|
||||
```
|
||||
|
||||
你会被要求选择Navicat产品类别、语言以及输入主版本号。之后会随机生成一个序列号。
|
||||
|
||||
```
|
||||
***************************************************
|
||||
* navicat-keygen by @DoubleLabyrinth *
|
||||
* version: 16.0.7.0 *
|
||||
***************************************************
|
||||
|
||||
[*] Select Navicat product:
|
||||
0. DataModeler
|
||||
1. Premium
|
||||
2. MySQL
|
||||
3. PostgreSQL
|
||||
4. Oracle
|
||||
5. SQLServer
|
||||
6. SQLite
|
||||
7. MariaDB
|
||||
8. MongoDB
|
||||
9. ReportViewer
|
||||
|
||||
(Input index)> 1
|
||||
|
||||
[*] Select product 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)> 0
|
||||
|
||||
[*] Input major version number:
|
||||
(range: 11 ~ 16, default: 16)> 16
|
||||
|
||||
[*] Serial number:
|
||||
NAVL-GFKA-T5SR-ZFTK
|
||||
|
||||
[*] Your name:
|
||||
```
|
||||
|
||||
你可以使用这个序列号暂时激活Navicat。
|
||||
|
||||
接下来你会被要求输入`用户名`和`组织名`;请随便填写,但不要太长。
|
||||
|
||||
```
|
||||
[*] Your name: Double Sine
|
||||
[*] Your organization: PremiumSoft CyberTech Ltd.
|
||||
|
||||
[*] Input request code (in Base64), input empty line to end:
|
||||
```
|
||||
|
||||
之后你会被要求填入请求码。注意 __不要关闭命令行__.
|
||||
|
||||
3. __断开网络__ 并打开Navicat。找到`注册`窗口,并填入keygen给你的序列号。然后点击`激活`按钮。
|
||||
|
||||
4. 一般来说在线激活肯定会失败,这时候Navicat会询问你是否`手动激活`,直接选吧。
|
||||
|
||||
5. 在`手动激活`窗口你会得到一个请求码,复制它并把它粘贴到keygen里。最后别忘了连按至少两下回车结束输入。
|
||||
|
||||
```
|
||||
[*] Your name: Double Sine
|
||||
[*] Your organization: PremiumSoft CyberTech Ltd.
|
||||
|
||||
[*] Input request code (in Base64), input empty line to end:
|
||||
CpgnfbIJGmAcxCuo/pAb8EeoS0audZn2NNemg6c3NPK/dWgb343IZQrFwoBZY6lpxE4Fq1BoNmCM75P03XpiXQ+hErcvFWk6iQPDCk/d4msf/AoprIqAMpXFoFLkeP0G93UIIEeBsUej8SrxdDgQDM585iPok5fUW+fTDCD1VICr7DBdL3c/69IxeIgiOQSuImdIQiM3/EOfDiFbAJL9vHW5LxFT8jj+8RPXehwPTBphpInmGdzxVZUZJwAGlXt7orrRbzafdeBjz6MnTajTcJP3SS2dBCiR33UScnyxYGEXdzv7+QLScTmCvI7gqg3Z8DMhroKMoHmy1AvC16FKVw==
|
||||
|
||||
[*] Request Info:
|
||||
{"K":"NAVLGFKAT5SRZFTK", "DI":"7D48FCBD093C778879A1", "P":"WIN"}
|
||||
|
||||
[*] Response Info:
|
||||
{"K":"NAVLGFKAT5SRZFTK","DI":"7D48FCBD093C778879A1","N":"Double Sine","O":"PremiumSoft CyberTech Ltd.","T":1644387294}
|
||||
|
||||
[*] Activation Code:
|
||||
vwLGmQIWg/DtzHMcaKCDHAjTcBNbTo2VmNllphUSUMgGjgvL6v82ue+GqXB6M/qn48Rj4D4Joqqisr6UwMSclNmQxOQz4RftEpLtG6KBjDo4LM71qn9R/jWoZV5EoHPQkX5gzhO/D7GammrRGn2MV+zI6dJ4c4SBFNnNyjAeEqNzinrQwjB7lUVTlpHEe/SMrdCsGliPZQ/X+5ASbEsq3D8PZsjysJv98MIJrZvdTdznrRe8JzYP+8sbIPQMIX1UDmdyDpbpSl45N92OhO4htz1kFjUEfnrwY0GMOhdYHv/PfMI7RiQzkRyY7pLvX7muJ4dkA+CmMmwew3gy3MWjig==
|
||||
```
|
||||
|
||||
6. 如果不出意外,你会得到一个看似用Base64编码的激活码。直接复制它,并把它粘贴到Navicat的`手动激活`窗口,最后点`激活`按钮。如果没什么意外的话应该能成功激活。
|
||||
|
||||
@ -1,13 +1,20 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.32112.339
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "navicat-keygen", "navicat-keygen\navicat-keygen.vcxproj", "{CB49F054-83AB-4C16-B73B-33D7DF696E16}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "navicat-keygen", "navicat-keygen\navicat-keygen.vcxproj", "{6D262AF4-5DAC-4F0C-B3D6-23C9CBEA9756}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "navicat-patcher", "navicat-patcher\navicat-patcher.vcxproj", "{30BE8CAB-6137-4441-9F64-599D0A6EEA0C}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "navicat-patcher", "navicat-patcher\navicat-patcher.vcxproj", "{1B6920EB-E6ED-465F-9600-B5F816752375}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common\common.vcxitems", "{6D81A756-475A-4093-919E-3E9217F662CA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
||||
common\common.vcxitems*{1b6920eb-e6ed-465f-9600-b5f816752375}*SharedItemsImports = 4
|
||||
common\common.vcxitems*{6d262af4-5dac-4f0c-b3d6-23c9cbea9756}*SharedItemsImports = 4
|
||||
common\common.vcxitems*{6d81a756-475a-4093-919e-3e9217f662ca}*SharedItemsImports = 9
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
@ -15,24 +22,27 @@ Global
|
||||
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
|
||||
{6D262AF4-5DAC-4F0C-B3D6-23C9CBEA9756}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6D262AF4-5DAC-4F0C-B3D6-23C9CBEA9756}.Debug|x64.Build.0 = Debug|x64
|
||||
{6D262AF4-5DAC-4F0C-B3D6-23C9CBEA9756}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{6D262AF4-5DAC-4F0C-B3D6-23C9CBEA9756}.Debug|x86.Build.0 = Debug|Win32
|
||||
{6D262AF4-5DAC-4F0C-B3D6-23C9CBEA9756}.Release|x64.ActiveCfg = Release|x64
|
||||
{6D262AF4-5DAC-4F0C-B3D6-23C9CBEA9756}.Release|x64.Build.0 = Release|x64
|
||||
{6D262AF4-5DAC-4F0C-B3D6-23C9CBEA9756}.Release|x86.ActiveCfg = Release|Win32
|
||||
{6D262AF4-5DAC-4F0C-B3D6-23C9CBEA9756}.Release|x86.Build.0 = Release|Win32
|
||||
{1B6920EB-E6ED-465F-9600-B5F816752375}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1B6920EB-E6ED-465F-9600-B5F816752375}.Debug|x64.Build.0 = Debug|x64
|
||||
{1B6920EB-E6ED-465F-9600-B5F816752375}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{1B6920EB-E6ED-465F-9600-B5F816752375}.Debug|x86.Build.0 = Debug|Win32
|
||||
{1B6920EB-E6ED-465F-9600-B5F816752375}.Release|x64.ActiveCfg = Release|x64
|
||||
{1B6920EB-E6ED-465F-9600-B5F816752375}.Release|x64.Build.0 = Release|x64
|
||||
{1B6920EB-E6ED-465F-9600-B5F816752375}.Release|x86.ActiveCfg = Release|Win32
|
||||
{1B6920EB-E6ED-465F-9600-B5F816752375}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {9382E280-F6E3-48E2-B3EF-1DB5BFF83DAE}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
133
navicat-keygen/CollectInformation.cpp
Normal file
133
navicat-keygen/CollectInformation.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#include "navicat_serial_generator.hpp"
|
||||
#include <iostream>
|
||||
#include "exceptions/operation_canceled_exception.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-keygen\\CollectInformation.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
[[nodiscard]]
|
||||
static int read_int(int min_val, int max_val, std::wstring_view prompt, std::wstring_view error_msg) {
|
||||
int val;
|
||||
|
||||
for (std::wstring s;;) {
|
||||
std::wcout << prompt;
|
||||
if (!std::getline(std::wcin, s)) {
|
||||
throw exceptions::operation_canceled_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Operation is canceled by user.");
|
||||
}
|
||||
|
||||
if (s.empty())
|
||||
continue;
|
||||
|
||||
try {
|
||||
val = std::stoi(s, nullptr, 0);
|
||||
if (min_val <= val && val <= max_val) {
|
||||
return val;
|
||||
} else {
|
||||
throw std::invalid_argument(u8"");
|
||||
}
|
||||
} catch (std::invalid_argument&) {
|
||||
std::wcout << error_msg << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
static int read_int(int min_val, int max_val, int default_val, std::wstring_view prompt, std::wstring_view error_msg) {
|
||||
int val;
|
||||
|
||||
for (std::wstring s;;) {
|
||||
std::wcout << prompt;
|
||||
if (!std::getline(std::wcin, s)) {
|
||||
throw exceptions::operation_canceled_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Operation is canceled by user.");
|
||||
}
|
||||
|
||||
if (s.empty()) {
|
||||
return default_val;
|
||||
}
|
||||
|
||||
try {
|
||||
val = std::stoi(s, nullptr, 0);
|
||||
if (min_val <= val && val <= max_val) {
|
||||
return val;
|
||||
} else {
|
||||
throw std::invalid_argument(u8"");
|
||||
}
|
||||
} catch (std::invalid_argument&) {
|
||||
std::wcout << error_msg << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
navicat_serial_generator CollectInformationNormal() {
|
||||
navicat_serial_generator sn_generator;
|
||||
|
||||
std::wcout << L"[*] Select Navicat product:" << std::endl;
|
||||
std::wcout << L" 0. DataModeler" << std::endl;
|
||||
std::wcout << L" 1. Premium" << std::endl;
|
||||
std::wcout << L" 2. MySQL" << std::endl;
|
||||
std::wcout << L" 3. PostgreSQL" << std::endl;
|
||||
std::wcout << L" 4. Oracle" << std::endl;
|
||||
std::wcout << L" 5. SQLServer" << std::endl;
|
||||
std::wcout << L" 6. SQLite" << std::endl;
|
||||
std::wcout << L" 7. MariaDB" << std::endl;
|
||||
std::wcout << L" 8. MongoDB" << std::endl;
|
||||
std::wcout << L" 9. ReportViewer" << std::endl;
|
||||
std::wcout << L" 10. ChartsCreator" << std::endl;
|
||||
std::wcout << L" 11. ChartsViewer" << std::endl;
|
||||
std::wcout << std::endl;
|
||||
sn_generator.set_software_type(static_cast<navicat_software_type>(read_int(0, 11, L"(Input index)> ", L"Invalid index.")));
|
||||
std::wcout << std::endl;
|
||||
|
||||
std::wcout << L"[*] Select product language:" << std::endl;
|
||||
std::wcout << L" 0. English" << std::endl;
|
||||
std::wcout << L" 1. Simplified Chinese" << std::endl;
|
||||
std::wcout << L" 2. Traditional Chinese" << std::endl;
|
||||
std::wcout << L" 3. Japanese" << std::endl;
|
||||
std::wcout << L" 4. Polish" << std::endl;
|
||||
std::wcout << L" 5. Spanish" << std::endl;
|
||||
std::wcout << L" 6. French" << std::endl;
|
||||
std::wcout << L" 7. German" << std::endl;
|
||||
std::wcout << L" 8. Korean" << std::endl;
|
||||
std::wcout << L" 9. Russian" << std::endl;
|
||||
std::wcout << L" 10. Portuguese" << std::endl;
|
||||
std::wcout << std::endl;
|
||||
sn_generator.set_software_language(static_cast<navicat_software_language>(read_int(0, 10, L"(Input index)> ", L"Invalid index.")));
|
||||
std::wcout << std::endl;
|
||||
|
||||
std::wcout << L"[*] Input major version number:" << std::endl;
|
||||
sn_generator.set_software_version(read_int(1, 16, 16, L"(range: 1 ~ 16, default: 16)> ", L"Invalid number."));
|
||||
std::wcout << std::endl;
|
||||
|
||||
return sn_generator;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
navicat_serial_generator CollectInformationAdvanced() {
|
||||
navicat_serial_generator sn_generator;
|
||||
|
||||
std::wcout << L"[*] Navicat Product Signature:" << std::endl;
|
||||
sn_generator.set_software_type(static_cast<std::uint8_t>(read_int(0x00, 0xff, L"(range: 0x00 ~ 0xFF)> ", L"Invalid number.")));
|
||||
std::wcout << std::endl;
|
||||
|
||||
std::wcout << L"[*] Navicat Language Signature 0:" << std::endl;
|
||||
auto s1 = static_cast<std::uint8_t>(read_int(0x00, 0xff, L"(range: 0x00 ~ 0xFF)> ", L"Invalid number."));
|
||||
std::wcout << std::endl;
|
||||
|
||||
std::wcout << L"[*] Navicat Language Signature 1:" << std::endl;
|
||||
auto s2 = static_cast<std::uint8_t>(read_int(0x00, 0xff, L"(range: 0x00 ~ 0xFF)> ", L"Invalid number."));
|
||||
sn_generator.set_software_language(s1, s2);
|
||||
std::wcout << std::endl;
|
||||
|
||||
std::wcout << L"[*] Input major version number:" << std::endl;
|
||||
sn_generator.set_software_version(read_int(1, 16, 16, L"(range: 1 ~ 16, default: 16)> ", L"Invalid number."));
|
||||
std::wcout << std::endl;
|
||||
|
||||
return sn_generator;
|
||||
}
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
237
navicat-keygen/GenerateLicense.cpp
Normal file
237
navicat-keygen/GenerateLicense.cpp
Normal file
@ -0,0 +1,237 @@
|
||||
#include "exception.hpp"
|
||||
#include "exceptions/operation_canceled_exception.hpp"
|
||||
#include "exceptions/win32_exception.hpp"
|
||||
|
||||
#include "resource_wrapper.hpp"
|
||||
#include "resource_traits/win32/file_handle.hpp"
|
||||
|
||||
#include "cp_converter.hpp"
|
||||
#include "base64_rfc4648.hpp"
|
||||
#include "navicat_serial_generator.hpp"
|
||||
#include "rsa_cipher.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/writer.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-keygen\\GenerateLicense.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
void GenerateLicenseText(const rsa_cipher& cipher, const navicat_serial_generator& sn_generator) {
|
||||
std::wstring username;
|
||||
std::wstring organization;
|
||||
std::string u8_username;
|
||||
std::string u8_organization;
|
||||
|
||||
std::wstring b64_request_code;
|
||||
std::vector<std::uint8_t> request_code;
|
||||
std::string u8_request_info;
|
||||
std::string u8_response_info;
|
||||
std::vector<std::uint8_t> response_code;
|
||||
std::wstring b64_response_code;
|
||||
|
||||
std::wcout << L"[*] Your name: ";
|
||||
if (!std::getline(std::wcin, username)) {
|
||||
throw exceptions::operation_canceled_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Operation is canceled by user.");
|
||||
} else {
|
||||
u8_username = cp_converter<-1, CP_UTF8>::convert(username);
|
||||
}
|
||||
|
||||
std::wcout << L"[*] Your organization: ";
|
||||
if (!std::getline(std::wcin, organization)) {
|
||||
throw exceptions::operation_canceled_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Operation is canceled by user.");
|
||||
} else {
|
||||
u8_organization = cp_converter<-1, CP_UTF8>::convert(organization);
|
||||
}
|
||||
|
||||
std::wcout << std::endl;
|
||||
std::wcout << L"[*] Input request code in Base64: (Input empty line to end)" << std::endl;
|
||||
while (true) {
|
||||
std::wstring s;
|
||||
if (!std::getline(std::wcin, s)) {
|
||||
throw exceptions::operation_canceled_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Operation is canceled by user.");
|
||||
}
|
||||
|
||||
if (s.empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
b64_request_code.append(s);
|
||||
}
|
||||
|
||||
if (b64_request_code.empty()) {
|
||||
throw exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Nothing inputs, abort!");
|
||||
}
|
||||
|
||||
request_code = base64_rfc4648::decode(cp_converter<-1, CP_UTF8>::convert(b64_request_code));
|
||||
|
||||
u8_request_info.resize((cipher.bits() + 7) / 8);
|
||||
u8_request_info.resize(cipher.private_decrypt(request_code.data(), request_code.size(), u8_request_info.data(), RSA_PKCS1_PADDING));
|
||||
while (u8_request_info.back() == '\x00') {
|
||||
u8_request_info.pop_back();
|
||||
}
|
||||
|
||||
std::wcout << L"[*] Request Info:" << std::endl;
|
||||
std::wcout << cp_converter<CP_UTF8, -1>::convert(u8_request_info) << std::endl;
|
||||
std::wcout << std::endl;
|
||||
|
||||
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);
|
||||
|
||||
//
|
||||
// begin to parse
|
||||
//
|
||||
json.Parse(u8_request_info.c_str());
|
||||
|
||||
//
|
||||
// remove "Platform" info
|
||||
//
|
||||
json.RemoveMember(u8"P");
|
||||
|
||||
//
|
||||
// set "Name" info
|
||||
//
|
||||
N_Key.SetString(u8"N", 1);
|
||||
N_Value.SetString(u8_username.c_str(), static_cast<rapidjson::SizeType>(u8_username.length()));
|
||||
|
||||
//
|
||||
// set "Organization" info
|
||||
//
|
||||
O_Key.SetString(u8"O", 1);
|
||||
O_Value.SetString(u8_organization.c_str(), static_cast<rapidjson::SizeType>(u8_organization.length()));
|
||||
|
||||
//
|
||||
// set "Time" info
|
||||
//
|
||||
T_Key.SetString(u8"T", 1);
|
||||
T_Value.SetUint(static_cast<unsigned int>(std::time(nullptr)));
|
||||
|
||||
//
|
||||
// add "Name", "Organization" and "Time"
|
||||
//
|
||||
json.AddMember(N_Key, N_Value, json.GetAllocator());
|
||||
json.AddMember(O_Key, O_Value, json.GetAllocator());
|
||||
json.AddMember(T_Key, T_Value, json.GetAllocator());
|
||||
|
||||
//
|
||||
// flush
|
||||
//
|
||||
json.Accept(writer);
|
||||
|
||||
if (buffer.GetSize() > 240) {
|
||||
throw exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Response Info is too long.");
|
||||
}
|
||||
|
||||
u8_response_info.assign(buffer.GetString(), buffer.GetSize());
|
||||
|
||||
std::wcout << L"[*] Response Info:" << std::endl;
|
||||
std::wcout << cp_converter<CP_UTF8, -1>::convert(u8_response_info) << std::endl;
|
||||
std::wcout << std::endl;
|
||||
|
||||
response_code.resize((cipher.bits() + 7) / 8);
|
||||
response_code.resize(cipher.private_encrypt(u8_response_info.data(), u8_response_info.size(), response_code.data(), RSA_PKCS1_PADDING));
|
||||
b64_response_code = cp_converter<CP_UTF8, -1>::convert(base64_rfc4648::encode(response_code));
|
||||
|
||||
std::wcout << L"[*] Activation Code:" << std::endl;
|
||||
std::wcout << b64_response_code << std::endl;
|
||||
std::wcout << std::endl;
|
||||
}
|
||||
|
||||
void GenerateLicenseBinary(const rsa_cipher& cipher, const navicat_serial_generator& sn_generator) {
|
||||
std::string utf8SerialNumber = sn_generator.serial_number();
|
||||
|
||||
std::wstring username;
|
||||
std::wstring organization;
|
||||
std::string u8_username;
|
||||
std::string u8_organization;
|
||||
|
||||
std::string u8_response_info;
|
||||
std::vector<std::uint8_t> response_code;
|
||||
|
||||
std::wcout << L"[*] Your name: ";
|
||||
if (!std::getline(std::wcin, username)) {
|
||||
throw exceptions::operation_canceled_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Operation is canceled by user.");
|
||||
} else {
|
||||
u8_username = cp_converter<-1, CP_UTF8>::convert(username);
|
||||
}
|
||||
|
||||
std::wcout << L"[*] Your organization: ";
|
||||
if (!std::getline(std::wcin, organization)) {
|
||||
throw exceptions::operation_canceled_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Operation is canceled by user.");
|
||||
} else {
|
||||
u8_organization = cp_converter<-1, CP_UTF8>::convert(organization);
|
||||
}
|
||||
|
||||
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::Value K_Key;
|
||||
rapidjson::Value K_Value;
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||
|
||||
json.Parse("{}");
|
||||
K_Key.SetString("K", 1);
|
||||
K_Value.SetString(utf8SerialNumber.c_str(), static_cast<rapidjson::SizeType>(utf8SerialNumber.length()));
|
||||
N_Key.SetString("N", 1);
|
||||
N_Value.SetString(u8_username.c_str(), static_cast<rapidjson::SizeType>(u8_username.length()));
|
||||
O_Key.SetString("O", 1);
|
||||
O_Value.SetString(u8_organization.c_str(), static_cast<rapidjson::SizeType>(u8_organization.length()));
|
||||
T_Key.SetString("T", 1);
|
||||
T_Value.SetUint(static_cast<unsigned int>(std::time(nullptr)));
|
||||
|
||||
json.AddMember(K_Key, K_Value, json.GetAllocator());
|
||||
json.AddMember(N_Key, N_Value, json.GetAllocator());
|
||||
json.AddMember(O_Key, O_Value, json.GetAllocator());
|
||||
json.AddMember(T_Key, T_Value, json.GetAllocator());
|
||||
|
||||
//
|
||||
// flush
|
||||
//
|
||||
json.Accept(writer);
|
||||
|
||||
if (buffer.GetSize() > 240) {
|
||||
throw exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Response Info is too long.");
|
||||
}
|
||||
|
||||
u8_response_info.assign(buffer.GetString(), buffer.GetSize());
|
||||
|
||||
std::wcout << L"[*] Response Info:" << std::endl;
|
||||
std::wcout << cp_converter<CP_UTF8, -1>::convert(u8_response_info) << std::endl;
|
||||
std::wcout << std::endl;
|
||||
|
||||
response_code.resize((cipher.bits() + 7) / 8);
|
||||
response_code.resize(cipher.private_encrypt(u8_response_info.data(), u8_response_info.size(), response_code.data(), RSA_PKCS1_PADDING));
|
||||
|
||||
resource_wrapper license_file{ resource_traits::win32::file_handle{}, CreateFileW(L"license_file", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) };
|
||||
if (license_file.is_valid() == false) {
|
||||
throw exceptions::win32_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), u8"CreateFileW failed.");
|
||||
}
|
||||
|
||||
if (DWORD _; WriteFile(license_file.get(), response_code.data(), static_cast<DWORD>(response_code.size()), &_, NULL) == FALSE) {
|
||||
throw exceptions::win32_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), u8"WriteFile failed.");
|
||||
}
|
||||
|
||||
std::wcout << L"[+] license_file has been generated." << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
@ -1,387 +0,0 @@
|
||||
#include <tchar.h>
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/des.h>
|
||||
|
||||
// OpenSSL precompiled lib, download from https://www.npcglib.org/~stathis/blog/precompiled-openssl/, MSVC2015 version
|
||||
// direct link https://www.npcglib.org/~stathis/downloads/openssl-1.1.0f-vs2015.7z
|
||||
// x86: "D:\openssl-1.1.0f-vs2015\include" has been add to include path. (modify it at project properties if necessary)
|
||||
// "D:\openssl-1.1.0f-vs2015\lib" has been add to library path. (modify it at project properties if necessary)
|
||||
// x64: "D:\openssl-1.1.0f-vs2015\include64" has been add to include path. (modify it at project properties if necessary)
|
||||
// "D:\openssl-1.1.0f-vs2015\lib64" has been add to library path. (modify it at project properties if necessary)
|
||||
#ifdef _DEBUG
|
||||
#pragma comment(lib, "libcryptoMTd.lib")
|
||||
#else
|
||||
#pragma comment(lib, "libcryptoMT.lib")
|
||||
#endif
|
||||
#pragma comment(lib, "WS2_32.lib") // some symbol are used in OpenSSL static lib
|
||||
#pragma comment(lib, "Crypt32.lib") // some symbol are used in OpenSSL static lib
|
||||
|
||||
#define NAVICAT_12
|
||||
|
||||
enum NavicatLanguage {
|
||||
English,
|
||||
SimplifiedChinese,
|
||||
TraditionalChinese,
|
||||
Japanese,
|
||||
Polish,
|
||||
Spanish,
|
||||
French,
|
||||
German,
|
||||
Korean,
|
||||
Russian,
|
||||
Portuguese
|
||||
};
|
||||
|
||||
void GenerateSnKey(char(&SnKey)[16], NavicatLanguage _language) {
|
||||
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();
|
||||
|
||||
switch (_language) {
|
||||
case English:
|
||||
temp_SnKey[5] = 0xAC; // Must be 0xAC for English version.
|
||||
temp_SnKey[6] = 0x88; // Must be 0x88 for English version.
|
||||
break;
|
||||
case SimplifiedChinese:
|
||||
temp_SnKey[5] = 0xCE; // Must be 0xCE for Simplified Chinese version.
|
||||
temp_SnKey[6] = 0x32; // Must be 0x32 for Simplified Chinese version.
|
||||
break;
|
||||
case TraditionalChinese:
|
||||
temp_SnKey[5] = 0xAA; // Must be 0xAA for Traditional Chinese version.
|
||||
temp_SnKey[6] = 0x99; // Must be 0x99 for Traditional Chinese version.
|
||||
break;
|
||||
case Japanese:
|
||||
temp_SnKey[5] = 0xAD; // Must be 0xAD for Japanese version. Discoverer: @dragonflylee
|
||||
temp_SnKey[6] = 0x82; // Must be 0x82 for Japanese version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case Polish:
|
||||
temp_SnKey[5] = 0xBB; // Must be 0xBB for Polish version. Discoverer: @dragonflylee
|
||||
temp_SnKey[6] = 0x55; // Must be 0x55 for Polish version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case Spanish:
|
||||
temp_SnKey[5] = 0xAE; // Must be 0xAE for Spanish version. Discoverer: @dragonflylee
|
||||
temp_SnKey[6] = 0x10; // Must be 0x10 for Spanish version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case French:
|
||||
temp_SnKey[5] = 0xFA; // Must be 0xFA for French version. Discoverer: @Deltafox79
|
||||
temp_SnKey[6] = 0x20; // Must be 0x20 for French version. Discoverer: @Deltafox79
|
||||
break;
|
||||
case German:
|
||||
temp_SnKey[5] = 0xB1; // Must be 0xB1 for German version. Discoverer: @dragonflylee
|
||||
temp_SnKey[6] = 0x60; // Must be 0x60 for German version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case Korean:
|
||||
temp_SnKey[5] = 0xB5; // Must be 0xB5 for Korean version. Discoverer: @dragonflylee
|
||||
temp_SnKey[6] = 0x60; // Must be 0x60 for Korean version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case Russian:
|
||||
temp_SnKey[5] = 0xEE; // Must be 0xB5 for Russian version. Discoverer: @dragonflylee
|
||||
temp_SnKey[6] = 0x16; // Must be 0x60 for Russian version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case Portuguese:
|
||||
temp_SnKey[5] = 0xCD; // Must be 0xCD for Portuguese version. Discoverer: @dragonflylee
|
||||
temp_SnKey[6] = 0x49; // Must be 0x49 for Portuguese version. Discoverer: @dragonflylee
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#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.
|
||||
#else
|
||||
#error "Navicat version is not specified."
|
||||
#endif
|
||||
temp_SnKey[9] = 0x32; // 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.
|
||||
// Must not be 0x00. 0x01-0xFA is ok.
|
||||
|
||||
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* DeviceIdentifier) {
|
||||
|
||||
char LicenseJson[2048 / 8] = { };
|
||||
#if defined(NAVICAT_12)
|
||||
sprintf_s(LicenseJson, "{\"K\":\"%.16s\", \"N\":\"%s\", \"O\":\"%s\", \"DI\":\"%s\"}", SnKey, Name, Organization, DeviceIdentifier);
|
||||
#elif defined(NAVICAT_11)
|
||||
sprintf_s(LicenseJson, "{\"K\":\"%.16s\", \"N\":\"%s\", \"O\":\"%s\"}", SnKey, Name, Organization);
|
||||
#else
|
||||
#error "Navicat version is not specified."
|
||||
#endif
|
||||
unsigned char EncryptedLicenseData[2048 / 8] = { };
|
||||
if (RSA_private_encrypt(static_cast<int>(strlen(LicenseJson)),
|
||||
reinterpret_cast<uint8_t*>(LicenseJson),
|
||||
EncryptedLicenseData,
|
||||
RSAPrivateKey,
|
||||
RSA_PKCS1_PADDING) == -1) {
|
||||
_tprintf_s(TEXT("Failed to encrypt license data.\r\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#if defined(NAVICAT_12)
|
||||
DWORD LicenseStringLength = 1024;
|
||||
TCHAR LicenseString[1024] = { };
|
||||
if (!CryptBinaryToString(EncryptedLicenseData, sizeof(EncryptedLicenseData), 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) {
|
||||
_tprintf_s(TEXT("Failed to create \"license_file\".\r\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!WriteFile(hLicenseFile, EncryptedLicenseData, sizeof(EncryptedLicenseData), nullptr, nullptr)) {
|
||||
_tprintf_s(TEXT("Failed to write \"license_file\".\r\n"));
|
||||
CloseHandle(hLicenseFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CloseHandle(hLicenseFile);
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
RSA* ReadRSAPrivateKeyFromFile(LPCTSTR filename) {
|
||||
#ifdef UNICODE
|
||||
int req_size = WideCharToMultiByte(CP_ACP, 0, filename, -1, nullptr, 0, nullptr, nullptr);
|
||||
if (req_size == 0) {
|
||||
_tprintf_s(TEXT("Failed to convert wchar* to char*. CODE: 0x%08x @[ReadRSAPrivateKeyFromFile -> WideCharToMultiByte]\r\n"), GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
char* temp_filename = new char[req_size]();
|
||||
WideCharToMultiByte(CP_ACP, 0, filename, -1, temp_filename, req_size, nullptr, nullptr);
|
||||
|
||||
BIO* b = BIO_new(BIO_s_file());
|
||||
if (b == nullptr) {
|
||||
_tprintf_s(TEXT("Failed to create BIO object. CODE: 0x%08x @[ReadRSAPrivateKeyFromFile -> BIO_new]\r\n"), ERR_get_error());
|
||||
delete[] temp_filename;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (1 != BIO_read_filename(b, temp_filename)) {
|
||||
_tprintf_s(TEXT("Failed to set target file of BIO. CODE: 0x%08x @[ReadRSAPrivateKeyFromFile -> BIO_read_filename]\r\n"), ERR_get_error());
|
||||
|
||||
BIO_free_all(b);
|
||||
delete[] temp_filename;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
delete[] temp_filename;
|
||||
#else
|
||||
BIO* b = BIO_new(BIO_s_file());
|
||||
if (b == nullptr) {
|
||||
_tprintf_s(TEXT("Failed to create BIO object. CODE: 0x%08x @[ReadRSAPrivateKeyFromFile -> BIO_new]\r\n"), ERR_get_error());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (1 != BIO_read_filename(b, filename)) {
|
||||
_tprintf_s(TEXT("Failed to set target file of BIO. CODE: 0x%08x @[ReadRSAPrivateKeyFromFile -> BIO_read_filename]\r\n"), ERR_get_error());
|
||||
|
||||
BIO_free_all(b);
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
RSA* ret = PEM_read_bio_RSAPrivateKey(b, nullptr, nullptr, nullptr);
|
||||
if (ret == nullptr) {
|
||||
_tprintf_s(TEXT("Failed to read RSA private key. CODE: 0x%08x @[ReadRSAPrivateKeyFromFile -> PEM_read_bio_RSAPrivateKey]\r\n"), ERR_get_error());
|
||||
|
||||
BIO_free_all(b);
|
||||
return nullptr;
|
||||
} else {
|
||||
BIO_free_all(b);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
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 0;
|
||||
}
|
||||
|
||||
srand(static_cast<unsigned int>(time(nullptr)));
|
||||
|
||||
RSA* PrivateKey = ReadRSAPrivateKeyFromFile(argv[1]);
|
||||
if (PrivateKey == nullptr)
|
||||
return 0;
|
||||
|
||||
std::cout
|
||||
<< "Which is your Navicat 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;
|
||||
|
||||
int LanguageIndex = -1;
|
||||
while (true) {
|
||||
std::cout << "(input index)>";
|
||||
|
||||
std::string temp;
|
||||
if (!std::getline(std::cin, temp)) {
|
||||
RSA_free(PrivateKey);
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
LanguageIndex = std::stoi(temp);
|
||||
if (LanguageIndex < 0 || LanguageIndex > 10)
|
||||
throw std::invalid_argument("Invalid index");
|
||||
break;
|
||||
} catch (...) {
|
||||
std::cout << "Invalid index." << std::endl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
char SnKey[16] = { };
|
||||
GenerateSnKey(SnKey, static_cast<NavicatLanguage>(LanguageIndex));
|
||||
|
||||
std::string strName;
|
||||
std::string strOrganization;
|
||||
_tprintf_s(TEXT("Your name: "));
|
||||
std::getline(std::cin, strName);
|
||||
_tprintf_s(TEXT("Your organization: "));
|
||||
std::getline(std::cin, strOrganization);
|
||||
|
||||
#if defined(NAVICAT_12)
|
||||
std::string RequestCode;
|
||||
_tprintf_s(TEXT("Input request code (in Base64), empty line to return:\r\n"));
|
||||
while (true) {
|
||||
std::string temp;
|
||||
std::getline(std::cin, temp);
|
||||
if (temp.empty())
|
||||
break;
|
||||
|
||||
RequestCode += temp;
|
||||
}
|
||||
|
||||
BYTE EncryptedRequestData[1024] = { };
|
||||
DWORD EncryptedRequestDataLength = sizeof(EncryptedRequestData);
|
||||
if (!CryptStringToBinaryA(RequestCode.c_str(), NULL, CRYPT_STRING_BASE64, EncryptedRequestData, &EncryptedRequestDataLength, NULL, NULL)) {
|
||||
_tprintf_s(TEXT("Failed to decode Base64 string. CODE: 0x%08x\r\n"), GetLastError());
|
||||
RSA_free(PrivateKey);
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
char RequestData[1024] = { };
|
||||
if (RSA_private_decrypt(EncryptedRequestDataLength,
|
||||
EncryptedRequestData,
|
||||
reinterpret_cast<BYTE*>(RequestData),
|
||||
PrivateKey, RSA_PKCS1_PADDING) == -1) {
|
||||
_tprintf_s(TEXT("Failed to decrypt request code.\r\n"));
|
||||
RSA_free(PrivateKey);
|
||||
return -2;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
std::cout << "-----------Begin Request Code Data---------------" << std::endl;
|
||||
std::cout << RequestData << std::endl;
|
||||
std::cout << "-----------End Request Code Data---------------" << std::endl;
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
std::string strDeviceIdentifier;
|
||||
for (int i = 0, length = static_cast<int>(strlen(RequestData)) - 4; i < length; ++i) {
|
||||
if (RequestData[i] == '"' &&
|
||||
RequestData[i + 1] == 'D' &&
|
||||
RequestData[i + 2] == 'I' &&
|
||||
RequestData[i + 3] == '"') {
|
||||
|
||||
char temp[256] = { };
|
||||
int x = i + 4, j = 0;
|
||||
while (RequestData[x] != '"' && x < length)
|
||||
x++;
|
||||
x++;
|
||||
while (RequestData[x] != '"' && j < 256) {
|
||||
temp[j++] = RequestData[x];
|
||||
x++;
|
||||
}
|
||||
strDeviceIdentifier += temp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (strDeviceIdentifier.empty()) {
|
||||
_tprintf_s(TEXT("Not a valid request code.\r\n"));
|
||||
RSA_free(PrivateKey);
|
||||
return -3;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
GenerateLicense(PrivateKey, SnKey, strName.c_str(), strOrganization.c_str(), strDeviceIdentifier.c_str());
|
||||
#elif defined(NAVICAT_11)
|
||||
GenerateLicense(PrivateKey, SnKey, strName.c_str(), strOrganization.c_str(), nullptr);
|
||||
#else
|
||||
#error "Navicat version is not specified."
|
||||
#endif
|
||||
|
||||
RSA_free(PrivateKey);
|
||||
return 0;
|
||||
}
|
||||
120
navicat-keygen/base32_rfc4648.cpp
Normal file
120
navicat-keygen/base32_rfc4648.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
#include "base32_rfc4648.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-keygen\\base32_rfc4648.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
char base32_rfc4648::symbol(alphabet_index_t idx) {
|
||||
return alphabet[idx];
|
||||
}
|
||||
|
||||
base32_rfc4648::alphabet_index_t base32_rfc4648::reverse_symbol(char c) {
|
||||
if ('A' <= c && c <= 'Z') {
|
||||
return c - 'A';
|
||||
} else if ('2' <= c && c <= '7') {
|
||||
return c - '2' + 26;
|
||||
} else {
|
||||
throw decoding_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Non-base32 digit is found");
|
||||
}
|
||||
}
|
||||
|
||||
std::string base32_rfc4648::encode(const std::vector<uint8_t>& data) {
|
||||
return encode(data.data(), data.size());
|
||||
}
|
||||
|
||||
std::string base32_rfc4648::encode(const void* data_ptr, size_t data_size) {
|
||||
std::string retval;
|
||||
|
||||
if (data_size) {
|
||||
retval.reserve((data_size * 8 + 4) / 5);
|
||||
|
||||
auto p = reinterpret_cast<const uint8_t*>(data_ptr);
|
||||
alphabet_index_t left_bits = 0;
|
||||
alphabet_index_t bit_buffer = 0;
|
||||
for (size_t i = 0; i < data_size; ++i) {
|
||||
bit_buffer = (bit_buffer << 8) | p[i];
|
||||
left_bits += 8;
|
||||
|
||||
while (left_bits >= 5) {
|
||||
alphabet_index_t idx = (bit_buffer >> (left_bits - 5)) & 0x1f;
|
||||
retval.push_back(symbol(idx));
|
||||
left_bits -= 5;
|
||||
}
|
||||
}
|
||||
|
||||
if (left_bits > 0) {
|
||||
alphabet_index_t idx = (bit_buffer << (5 - left_bits)) & 0x1f;
|
||||
retval.push_back(symbol(idx));
|
||||
}
|
||||
|
||||
switch (data_size % 5) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
retval.append(6, padding_character);
|
||||
break;
|
||||
case 2:
|
||||
retval.append(4, padding_character);
|
||||
break;
|
||||
case 3:
|
||||
retval.append(3, padding_character);
|
||||
break;
|
||||
case 4:
|
||||
retval.append(1, padding_character);
|
||||
break;
|
||||
default:
|
||||
__assume(false);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> base32_rfc4648::decode(std::string_view b32_string) {
|
||||
if (b32_string.length() % 8 == 0) {
|
||||
std::vector<uint8_t> retval;
|
||||
|
||||
size_t count_of_padding = std::distance(b32_string.crbegin(), std::find_if_not(b32_string.crbegin(), b32_string.crend(), [](char c) -> bool { return c == padding_character; }));
|
||||
switch (count_of_padding) {
|
||||
case 1:
|
||||
retval.reserve(b32_string.length() / 8 * 5 - (5 - 4));
|
||||
break;
|
||||
case 3:
|
||||
retval.reserve(b32_string.length() / 8 * 5 - (5 - 3));
|
||||
break;
|
||||
case 4:
|
||||
retval.reserve(b32_string.length() / 8 * 5 - (5 - 2));
|
||||
break;
|
||||
case 6:
|
||||
retval.reserve(b32_string.length() / 8 * 5 - (5 - 1));
|
||||
break;
|
||||
default:
|
||||
throw decoding_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Incorrect padding");
|
||||
}
|
||||
|
||||
size_t count_of_encoded = b32_string.length() - count_of_padding;
|
||||
|
||||
alphabet_index_t left_bits = 0;
|
||||
alphabet_index_t bit_buffer = 0;
|
||||
for (size_t i = 0; i < count_of_encoded; ++i) {
|
||||
bit_buffer = (bit_buffer << 5) | reverse_symbol(b32_string[i]);
|
||||
left_bits += 5;
|
||||
|
||||
while (left_bits >= 8) {
|
||||
auto val = static_cast<uint8_t>((bit_buffer >> (left_bits - 8)) & 0xff);
|
||||
retval.push_back(val);
|
||||
left_bits -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
} else {
|
||||
throw decoding_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Incorrect padding");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
39
navicat-keygen/base32_rfc4648.hpp
Normal file
39
navicat-keygen/base32_rfc4648.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include "exception.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-keygen\\base32_rfc4648.hpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
struct base32_rfc4648 {
|
||||
using alphabet_index_t = size_t;
|
||||
|
||||
static constexpr const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
static constexpr const char padding_character = '=';
|
||||
|
||||
class decoding_error : public ::nkg::exception {
|
||||
public:
|
||||
decoding_error(std::string_view file, int line, std::string_view message) noexcept :
|
||||
::nkg::exception(file, line, message) {}
|
||||
};
|
||||
|
||||
static char symbol(alphabet_index_t idx);
|
||||
|
||||
static alphabet_index_t reverse_symbol(char c);
|
||||
|
||||
static std::string encode(const std::vector<uint8_t>& data);
|
||||
|
||||
static std::string encode(const void* data_ptr, size_t data_size);
|
||||
|
||||
static std::vector<uint8_t> decode(std::string_view b32_string);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
103
navicat-keygen/base64_rfc4648.cpp
Normal file
103
navicat-keygen/base64_rfc4648.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include "base64_rfc4648.hpp"
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "resource_wrapper.hpp"
|
||||
#include "resource_traits/openssl/bio.hpp"
|
||||
#include "resource_traits/openssl/bio_chain.hpp"
|
||||
|
||||
#pragma comment(lib, "libcrypto")
|
||||
#pragma comment(lib, "crypt32") // required by libcrypto.lib
|
||||
#pragma comment(lib, "ws2_32") // required by libcrypto.lib
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-keygen\\base64_rfc4648.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
std::string base64_rfc4648::encode(const std::vector<std::uint8_t>& data) {
|
||||
resource_wrapper bio_b64{ resource_traits::openssl::bio_chain{}, BIO_new(BIO_f_base64()) };
|
||||
if (bio_b64.is_valid() == false) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
|
||||
}
|
||||
|
||||
BIO_set_flags(bio_b64.get(), BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
resource_wrapper bio_memory{ resource_traits::openssl::bio{}, BIO_new(BIO_s_mem()) };
|
||||
if (bio_memory.is_valid() == false) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
|
||||
}
|
||||
|
||||
BIO_push(bio_b64.get(), bio_memory.get());
|
||||
|
||||
for (size_t written_size = 0, left_size = data.size(); left_size != 0;) {
|
||||
int size_to_write = static_cast<int>(std::min(left_size, static_cast<size_t>(INT_MAX)));
|
||||
|
||||
int r = BIO_write(bio_b64.get(), data.data() + written_size, size_to_write);
|
||||
if (r > 0) {
|
||||
written_size += r;
|
||||
left_size -= r;
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_write failed.");
|
||||
}
|
||||
}
|
||||
|
||||
BIO_flush(bio_b64.get());
|
||||
|
||||
const char* pch = nullptr;
|
||||
long lch = BIO_get_mem_data(bio_memory.get(), &pch);
|
||||
|
||||
bio_memory.discard(); // the bio_chain `bio_b64` will free it
|
||||
|
||||
return std::string(pch, lch);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> base64_rfc4648::decode(std::string_view b64_string) {
|
||||
resource_wrapper bio_b64{ resource_traits::openssl::bio_chain{}, BIO_new(BIO_f_base64()) };
|
||||
if (bio_b64.is_valid() == false) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
|
||||
}
|
||||
|
||||
BIO_set_flags(bio_b64.get(), BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
resource_wrapper bio_memory{ resource_traits::openssl::bio{}, BIO_new(BIO_s_mem()) };
|
||||
if (bio_memory.is_valid() == false) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_new failed.");
|
||||
}
|
||||
|
||||
BIO_push(bio_b64.get(), bio_memory.get());
|
||||
|
||||
for (size_t written_length = 0, left_length = b64_string.length(); left_length != 0;) {
|
||||
int length_to_write = static_cast<int>(std::min(left_length, static_cast<size_t>(INT_MAX)));
|
||||
|
||||
int r = BIO_write(bio_memory.get(), b64_string.data() + written_length, length_to_write);
|
||||
if (r > 0) {
|
||||
written_length += r;
|
||||
left_length -= r;
|
||||
} else {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"BIO_write failed.");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> retval;
|
||||
retval.reserve(b64_string.length() * 3 / 4 + 1);
|
||||
|
||||
for (uint8_t buf[256];;) {
|
||||
auto len = BIO_read(bio_b64.get(), buf, sizeof(buf));
|
||||
if (len > 0) {
|
||||
retval.insert(retval.end(), buf, buf + len);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bio_memory.discard(); // the bio_chain `bio_b64` will free it
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
20
navicat-keygen/base64_rfc4648.hpp
Normal file
20
navicat-keygen/base64_rfc4648.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "exception.hpp"
|
||||
|
||||
namespace nkg {
|
||||
|
||||
struct base64_rfc4648 {
|
||||
|
||||
class backend_error : public ::nkg::exception {
|
||||
public:
|
||||
backend_error(std::string_view file, int line, std::string_view message) noexcept :
|
||||
::nkg::exception(file, line, message) {}
|
||||
};
|
||||
|
||||
static std::string encode(const std::vector<std::uint8_t>& data);
|
||||
static std::vector<uint8_t> decode(std::string_view str_b64);
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
@ -19,35 +19,36 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{CB49F054-83AB-4C16-B73B-33D7DF696E16}</ProjectGuid>
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{6d262af4-5dac-4f0c-b3d6-23c9cbea9756}</ProjectGuid>
|
||||
<RootNamespace>navicatkeygen</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0</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_xp</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
@ -55,6 +56,7 @@
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
<Import Project="..\common\common.vcxitems" 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" />
|
||||
@ -71,47 +73,44 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>D:\openssl-1.1.0f-vs2015\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>D:\openssl-1.1.0f-vs2015\lib;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>D:\openssl-1.1.0f-vs2015\include64;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>D:\openssl-1.1.0f-vs2015\lib64;$(LibraryPath)</LibraryPath>
|
||||
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\obj\$(PlatformTarget)-$(Configuration)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>D:\openssl-1.1.0f-vs2015\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>D:\openssl-1.1.0f-vs2015\lib;$(LibraryPath)</LibraryPath>
|
||||
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\obj\$(PlatformTarget)-$(Configuration)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\obj\$(PlatformTarget)-$(Configuration)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>D:\openssl-1.1.0f-vs2015\include64;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>D:\openssl-1.1.0f-vs2015\lib64;$(LibraryPath)</LibraryPath>
|
||||
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\obj\$(PlatformTarget)-$(Configuration)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" />
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<VcpkgUseStatic>true</VcpkgUseStatic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<VcpkgUseStatic>true</VcpkgUseStatic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<VcpkgUseStatic>true</VcpkgUseStatic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<VcpkgUseStatic>true</VcpkgUseStatic>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<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>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -122,13 +121,12 @@
|
||||
<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>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -138,16 +136,29 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<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>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -158,7 +169,17 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="_tmain.cpp" />
|
||||
<ClCompile Include="base32_rfc4648.cpp" />
|
||||
<ClCompile Include="base64_rfc4648.cpp" />
|
||||
<ClCompile Include="CollectInformation.cpp" />
|
||||
<ClCompile Include="GenerateLicense.cpp" />
|
||||
<ClCompile Include="navicat_serial_generator.cpp" />
|
||||
<ClCompile Include="wmain.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="base32_rfc4648.hpp" />
|
||||
<ClInclude Include="base64_rfc4648.hpp" />
|
||||
<ClInclude Include="navicat_serial_generator.hpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
@ -3,11 +3,11 @@
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;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>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
@ -15,8 +15,34 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="_tmain.cpp">
|
||||
<ClCompile Include="wmain.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base64_rfc4648.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="navicat_serial_generator.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CollectInformation.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GenerateLicense.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base32_rfc4648.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="base64_rfc4648.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="navicat_serial_generator.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="base32_rfc4648.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
6
navicat-keygen/navicat-keygen.vcxproj.user
Normal file
6
navicat-keygen/navicat-keygen.vcxproj.user
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ShowAllFiles>true</ShowAllFiles>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
196
navicat-keygen/navicat_serial_generator.cpp
Normal file
196
navicat-keygen/navicat_serial_generator.cpp
Normal file
@ -0,0 +1,196 @@
|
||||
#include "navicat_serial_generator.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
#if (OPENSSL_VERSION_NUMBER & 0xf0000000) == 0x30000000 // for openssl 3.x.x
|
||||
#include <openssl/provider.h>
|
||||
#endif
|
||||
|
||||
#include "resource_wrapper.hpp"
|
||||
#include "resource_traits/openssl/evp_cipher_ctx.hpp"
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include "base32_rfc4648.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-keygen\\navicat_serial_generator.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
char navicat_serial_generator::_replace_confusing_chars(char c) noexcept {
|
||||
if (c == 'I') {
|
||||
return '8';
|
||||
} else if (c == 'O') {
|
||||
return '9';
|
||||
} else {
|
||||
return c;
|
||||
}
|
||||
};
|
||||
|
||||
navicat_serial_generator::navicat_serial_generator() noexcept :
|
||||
m_data{ 0x68 , 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32 }, m_des_key{} {}
|
||||
|
||||
void navicat_serial_generator::set_software_language(navicat_software_language lang) noexcept {
|
||||
switch (lang) {
|
||||
case navicat_software_language::English:
|
||||
m_data[5] = 0xAC; // Must be 0xAC for English version.
|
||||
m_data[6] = 0x88; // Must be 0x88 for English version.
|
||||
break;
|
||||
case navicat_software_language::SimplifiedChinese:
|
||||
m_data[5] = 0xCE; // Must be 0xCE for Simplified Chinese version.
|
||||
m_data[6] = 0x32; // Must be 0x32 for Simplified Chinese version.
|
||||
break;
|
||||
case navicat_software_language::TraditionalChinese:
|
||||
m_data[5] = 0xAA; // Must be 0xAA for Traditional Chinese version.
|
||||
m_data[6] = 0x99; // Must be 0x99 for Traditional Chinese version.
|
||||
break;
|
||||
case navicat_software_language::Japanese:
|
||||
m_data[5] = 0xAD; // Must be 0xAD for Japanese version. Discoverer: @dragonflylee
|
||||
m_data[6] = 0x82; // Must be 0x82 for Japanese version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case navicat_software_language::Polish:
|
||||
m_data[5] = 0xBB; // Must be 0xBB for Polish version. Discoverer: @dragonflylee
|
||||
m_data[6] = 0x55; // Must be 0x55 for Polish version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case navicat_software_language::Spanish:
|
||||
m_data[5] = 0xAE; // Must be 0xAE for Spanish version. Discoverer: @dragonflylee
|
||||
m_data[6] = 0x10; // Must be 0x10 for Spanish version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case navicat_software_language::French:
|
||||
m_data[5] = 0xFA; // Must be 0xFA for French version. Discoverer: @Deltafox79
|
||||
m_data[6] = 0x20; // Must be 0x20 for French version. Discoverer: @Deltafox79
|
||||
break;
|
||||
case navicat_software_language::German:
|
||||
m_data[5] = 0xB1; // Must be 0xB1 for German version. Discoverer: @dragonflylee
|
||||
m_data[6] = 0x60; // Must be 0x60 for German version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case navicat_software_language::Korean:
|
||||
m_data[5] = 0xB5; // Must be 0xB5 for Korean version. Discoverer: @dragonflylee
|
||||
m_data[6] = 0x60; // Must be 0x60 for Korean version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case navicat_software_language::Russian:
|
||||
m_data[5] = 0xEE; // Must be 0xB5 for Russian version. Discoverer: @dragonflylee
|
||||
m_data[6] = 0x16; // Must be 0x60 for Russian version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case navicat_software_language::Portuguese:
|
||||
m_data[5] = 0xCD; // Must be 0xCD for Portuguese version. Discoverer: @dragonflylee
|
||||
m_data[6] = 0x49; // Must be 0x49 for Portuguese version. Discoverer: @dragonflylee
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void navicat_serial_generator::set_software_language(uint8_t lang_sig0, uint8_t lang_sig1) noexcept {
|
||||
m_data[5] = lang_sig0;
|
||||
m_data[6] = lang_sig1;
|
||||
}
|
||||
|
||||
void navicat_serial_generator::set_software_type(navicat_software_type software_type) noexcept {
|
||||
switch (software_type) {
|
||||
case navicat_software_type::DataModeler:
|
||||
m_data[7] = 0x84;
|
||||
break;
|
||||
case navicat_software_type::Premium:
|
||||
m_data[7] = 0x65;
|
||||
break;
|
||||
case navicat_software_type::MySQL:
|
||||
m_data[7] = 0x68;
|
||||
break;
|
||||
case navicat_software_type::PostgreSQL:
|
||||
m_data[7] = 0x6C;
|
||||
break;
|
||||
case navicat_software_type::Oracle:
|
||||
m_data[7] = 0x70;
|
||||
break;
|
||||
case navicat_software_type::SQLServer:
|
||||
m_data[7] = 0x74;
|
||||
break;
|
||||
case navicat_software_type::SQLite:
|
||||
m_data[7] = 0x78;
|
||||
break;
|
||||
case navicat_software_type::MariaDB:
|
||||
m_data[7] = 0x7C;
|
||||
break;
|
||||
case navicat_software_type::MongoDB:
|
||||
m_data[7] = 0x80;
|
||||
break;
|
||||
case navicat_software_type::ReportViewer:
|
||||
m_data[7] = 0xb;
|
||||
break;
|
||||
case navicat_software_type::ChartsCreator:
|
||||
m_data[7] = 0x86;
|
||||
break;
|
||||
case navicat_software_type::ChartsViewer:
|
||||
m_data[7] = 0x88;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void navicat_serial_generator::set_software_type(uint8_t software_type_sig) noexcept {
|
||||
m_data[7] = software_type_sig;
|
||||
}
|
||||
|
||||
void navicat_serial_generator::set_software_version(int ver) {
|
||||
if (1 <= ver && ver < 16) {
|
||||
static_assert(sizeof(m_des_key) == sizeof(s_des_key0));
|
||||
|
||||
m_data[8] = static_cast<std::uint8_t>((ver << 4) | (m_data[8] & 0x0f));
|
||||
memcpy(m_des_key, s_des_key0, sizeof(s_des_key0));
|
||||
} else if (16 <= ver && ver < 32) {
|
||||
static_assert(sizeof(m_des_key) == sizeof(s_des_key1));
|
||||
|
||||
m_data[8] = static_cast<std::uint8_t>(((ver - 16) << 4) | (m_data[8] & 0x0f));
|
||||
memcpy(m_des_key, s_des_key1, sizeof(s_des_key1));
|
||||
} else {
|
||||
throw version_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Invalid navicat version.");
|
||||
}
|
||||
}
|
||||
|
||||
void navicat_serial_generator::generate() {
|
||||
RAND_bytes(m_data + 2, 3);
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER & 0xf0000000) == 0x30000000 // for openssl 3.x.x
|
||||
if (!OSSL_PROVIDER_available(nullptr, "legacy")) {
|
||||
if (OSSL_PROVIDER_load(nullptr, "legacy") == nullptr) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"OSSL_PROVIDER_load failed.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
resource_wrapper evp_cipher_context{ resource_traits::openssl::evp_cipher_ctx{}, EVP_CIPHER_CTX_new() };
|
||||
if (!evp_cipher_context.is_valid()) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_CIPHER_CTX_new failed.");
|
||||
}
|
||||
|
||||
if (EVP_EncryptInit(evp_cipher_context.get(), EVP_des_ecb(), m_des_key, nullptr) <= 0) { // return 1 for success and 0 for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_EncryptInit failed.");
|
||||
}
|
||||
|
||||
if (int _; EVP_EncryptUpdate(evp_cipher_context.get(), m_data + 2, &_, m_data + 2, 8) <= 0) { // return 1 for success and 0 for failure
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"EVP_EncryptUpdate failed.");
|
||||
}
|
||||
|
||||
m_serial_number = base32_rfc4648::encode(m_data, sizeof(m_data));
|
||||
std::transform(m_serial_number.begin(), m_serial_number.end(), m_serial_number.begin(), _replace_confusing_chars);
|
||||
|
||||
std::string_view sn = m_serial_number;
|
||||
m_serial_number_formatted = fmt::format("{}-{}-{}-{}", sn.substr(0, 4), sn.substr(4, 4), sn.substr(8, 4), sn.substr(12, 4));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const std::string& navicat_serial_generator::serial_number() const noexcept {
|
||||
return m_serial_number;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const std::string& navicat_serial_generator::serial_number_formatted() const noexcept {
|
||||
return m_serial_number_formatted;
|
||||
}
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
82
navicat-keygen/navicat_serial_generator.hpp
Normal file
82
navicat-keygen/navicat_serial_generator.hpp
Normal file
@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "exception.hpp"
|
||||
|
||||
namespace nkg {
|
||||
|
||||
enum class navicat_software_language {
|
||||
English,
|
||||
SimplifiedChinese,
|
||||
TraditionalChinese,
|
||||
Japanese,
|
||||
Polish,
|
||||
Spanish,
|
||||
French,
|
||||
German,
|
||||
Korean,
|
||||
Russian,
|
||||
Portuguese
|
||||
};
|
||||
|
||||
enum class navicat_software_type {
|
||||
DataModeler,
|
||||
Premium,
|
||||
MySQL,
|
||||
PostgreSQL,
|
||||
Oracle,
|
||||
SQLServer,
|
||||
SQLite,
|
||||
MariaDB,
|
||||
MongoDB,
|
||||
ReportViewer,
|
||||
ChartsCreator,
|
||||
ChartsViewer
|
||||
};
|
||||
|
||||
class navicat_serial_generator {
|
||||
public:
|
||||
class version_error;
|
||||
class backend_error;
|
||||
|
||||
private:
|
||||
static inline const uint8_t s_des_key0[8] = {0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27};
|
||||
static inline const uint8_t s_des_key1[8] = {0xE9, 0x7F, 0xB0, 0x60, 0x77, 0x45, 0x90, 0xAE};
|
||||
|
||||
uint8_t m_data[10];
|
||||
uint8_t m_des_key[8];
|
||||
std::string m_serial_number;
|
||||
std::string m_serial_number_formatted;
|
||||
|
||||
static char _replace_confusing_chars(char c) noexcept;
|
||||
|
||||
public:
|
||||
navicat_serial_generator() noexcept;
|
||||
|
||||
void set_software_language(navicat_software_language lang) noexcept;
|
||||
void set_software_language(uint8_t lang_sig0, uint8_t lang_sig1) noexcept;
|
||||
|
||||
void set_software_type(navicat_software_type software_type) noexcept;
|
||||
void set_software_type(uint8_t software_type_sig) noexcept;
|
||||
|
||||
void set_software_version(int Version);
|
||||
|
||||
void generate();
|
||||
|
||||
[[nodiscard]]
|
||||
const std::string& serial_number() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
const std::string& serial_number_formatted() const noexcept;
|
||||
};
|
||||
|
||||
class navicat_serial_generator::version_error : public ::nkg::exception {
|
||||
using ::nkg::exception::exception;
|
||||
};
|
||||
|
||||
class navicat_serial_generator::backend_error : public ::nkg::exception {
|
||||
using ::nkg::exception::exception;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
121
navicat-keygen/wmain.cpp
Normal file
121
navicat-keygen/wmain.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
#include <stdio.h>
|
||||
#include <functional>
|
||||
|
||||
#include "exception.hpp"
|
||||
#include "exceptions/operation_canceled_exception.hpp"
|
||||
|
||||
#include "cp_converter.hpp"
|
||||
#include "base64_rfc4648.hpp"
|
||||
#include "navicat_serial_generator.hpp"
|
||||
#include "rsa_cipher.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-keygen\\wmain.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
using fnCollectInformation = std::function<navicat_serial_generator()>;
|
||||
using fnGenerateLicense = std::function<void(const rsa_cipher& cipher, const navicat_serial_generator& generator)>;
|
||||
|
||||
navicat_serial_generator CollectInformationNormal();
|
||||
navicat_serial_generator CollectInformationAdvanced();
|
||||
void GenerateLicenseText(const rsa_cipher& cipher, const navicat_serial_generator& sn_generator);
|
||||
void GenerateLicenseBinary(const rsa_cipher& cipher, const navicat_serial_generator& sn_generator);
|
||||
}
|
||||
|
||||
static void welcome() {
|
||||
_putws(L"***************************************************");
|
||||
_putws(L"* navicat-keygen by @DoubleLabyrinth *");
|
||||
_putws(L"* version: 16.0.7.0-2 *");
|
||||
_putws(L"***************************************************");
|
||||
_putws(L"");
|
||||
}
|
||||
|
||||
static void help() {
|
||||
_putws(L"Usage:");
|
||||
_putws(L" navicat-keygen.exe <-bin|-text> [-adv] <RSA-2048 Private Key File>");
|
||||
_putws(L"");
|
||||
_putws(L" <-bin|-text> Specify \"-bin\" to generate \"license_file\" used by Navicat 11.");
|
||||
_putws(L" Specify \"-text\" to generate base64-encoded activation code.");
|
||||
_putws(L" This parameter is mandatory.");
|
||||
_putws(L"");
|
||||
_putws(L" [-adv] Enable advance mode.");
|
||||
_putws(L" This parameter is optional.");
|
||||
_putws(L"");
|
||||
_putws(L" <RSA-2048 Private Key File> A path to an RSA-2048 private key file.");
|
||||
_putws(L" This parameter is mandatory.");
|
||||
_putws(L"");
|
||||
_putws(L"Example:");
|
||||
_putws(L" navicat-keygen.exe -text .\\RegPrivateKey.pem");
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t* argv[]) {
|
||||
welcome();
|
||||
|
||||
if (argc == 3 || argc == 4) {
|
||||
nkg::fnCollectInformation lpfnCollectInformation;
|
||||
nkg::fnGenerateLicense lpfnGenerateLicense;
|
||||
|
||||
if (_wcsicmp(argv[1], L"-bin") == 0) {
|
||||
lpfnGenerateLicense = nkg::GenerateLicenseBinary;
|
||||
} else if (_wcsicmp(argv[1], L"-text") == 0) {
|
||||
lpfnGenerateLicense = nkg::GenerateLicenseText;
|
||||
} else {
|
||||
help();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argc == 3) {
|
||||
lpfnCollectInformation = nkg::CollectInformationNormal;
|
||||
} else if (argc == 4 && _wcsicmp(argv[2], L"-adv") == 0) {
|
||||
lpfnCollectInformation = nkg::CollectInformationAdvanced;
|
||||
} else {
|
||||
help();
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
nkg::rsa_cipher cipher;
|
||||
|
||||
cipher.import_private_key_file(nkg::cp_converter<-1, CP_UTF8>::convert(argv[argc - 1]));
|
||||
if (cipher.bits() != 2048) {
|
||||
throw nkg::exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"RSA key length != 2048 bits.")
|
||||
.push_hint(u8"You must provide an RSA key whose modulus length is 2048 bits.");
|
||||
}
|
||||
|
||||
auto sn_generator = lpfnCollectInformation();
|
||||
sn_generator.generate();
|
||||
|
||||
_putws(L"[*] Serial number:");
|
||||
_putws(nkg::cp_converter<CP_UTF8, -1>::convert(sn_generator.serial_number_formatted()).c_str());
|
||||
_putws(L"");
|
||||
|
||||
lpfnGenerateLicense(cipher, sn_generator);
|
||||
|
||||
return 0;
|
||||
} catch (nkg::exceptions::operation_canceled_exception&) {
|
||||
return -1;
|
||||
} catch (nkg::exception& e) {
|
||||
wprintf_s(L"[-] %s:%d ->\n", nkg::cp_converter<CP_UTF8, -1>::convert(e.source_file()).c_str(), e.source_line());
|
||||
wprintf_s(L" %s\n", nkg::cp_converter<CP_UTF8, -1>::convert(e.custom_message()).c_str());
|
||||
|
||||
if (e.error_code_exists()) {
|
||||
wprintf_s(L" %s (0x%zx)\n", nkg::cp_converter<CP_UTF8, -1>::convert(e.error_string()).c_str(), e.error_code());
|
||||
}
|
||||
|
||||
for (auto& hint : e.hints()) {
|
||||
wprintf_s(L" Hints: %s\n", nkg::cp_converter<CP_UTF8, -1>::convert(hint).c_str());
|
||||
}
|
||||
|
||||
return -1;
|
||||
} catch (std::exception& e) {
|
||||
wprintf_s(L"[-] %s\n", nkg::cp_converter<CP_UTF8, -1>::convert(e.what()).c_str());
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
help();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
@ -1,12 +0,0 @@
|
||||
// to avoid "AES_KEY" definaition conflict
|
||||
#include "NavicatCrypto/NavicatCrypto.hpp"
|
||||
|
||||
namespace patcher {
|
||||
|
||||
std::string EncryptPublicKey(const char* public_key, size_t len) {
|
||||
Navicat11Crypto cipher("23970790", 8);
|
||||
auto&& temp = cipher.EncryptString(public_key, len);
|
||||
return std::string(temp.begin(), temp.end());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,291 +0,0 @@
|
||||
#pragma once
|
||||
#include "aes.h"
|
||||
#include "blowfish.h"
|
||||
#include "SHA1.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class Navicat11Crypto {
|
||||
protected:
|
||||
BLOWFISH_KEY BlowfishKey;
|
||||
|
||||
void BytesToHex(const void* src, size_t len, char* dst) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
char h = reinterpret_cast<const uint8_t*>(src)[i] >> 4;
|
||||
char l = reinterpret_cast<const uint8_t*>(src)[i] & 0x0F;
|
||||
|
||||
h += h >= 10 ? 'A' - 10 : '0';
|
||||
l += l >= 10 ? 'A' - 10 : '0';
|
||||
dst[2 * i] = h;
|
||||
dst[2 * i + 1] = l;
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckHex(const char* src, size_t len) {
|
||||
if (len % 2 != 0)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < len; i += 2) {
|
||||
char h = src[i];
|
||||
char l = src[i + 1];
|
||||
|
||||
if (src[i] < '0' || src[i] > 'F')
|
||||
return false;
|
||||
if (src[i] < 'A' && src[i] > '9')
|
||||
return false;
|
||||
if (src[i + 1] < '0' || src[i + 1] > 'F')
|
||||
return false;
|
||||
if (src[i + 1] < 'A' && src[i + 1] > '9')
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HexToBytes(const char* src, size_t len, void* dst) {
|
||||
for (size_t i = 0; i < len; i += 2) {
|
||||
uint8_t h = src[i];
|
||||
uint8_t l = src[i + 1];
|
||||
|
||||
h -= h > '9' ? 'A' - 10 : '0';
|
||||
l -= l > '9' ? 'A' - 10 : '0';
|
||||
|
||||
reinterpret_cast<uint8_t*>(dst)[i / 2] = (h << 4 )^ l;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Navicat11Crypto() {
|
||||
const uint8_t DefaultKey[8] = {
|
||||
'3', 'D', 'C', '5', 'C', 'A', '3', '9'
|
||||
};
|
||||
SHA1_DIGEST KeyHash;
|
||||
accelc_SHA1(DefaultKey, sizeof(DefaultKey), &KeyHash);
|
||||
accelc_Blowfish_set_key(KeyHash.byte, sizeof(KeyHash), &BlowfishKey);
|
||||
}
|
||||
|
||||
Navicat11Crypto(const void* srcBytes, size_t srclen) {
|
||||
if (srclen == 0)
|
||||
srclen = BLOWFISH_MIN_KEY_LENGTH;
|
||||
if (srclen > BLOWFISH_MAX_KEY_LENGTH)
|
||||
srclen = BLOWFISH_MAX_KEY_LENGTH;
|
||||
SHA1_DIGEST KeyHash;
|
||||
accelc_SHA1(srcBytes, srclen, &KeyHash);
|
||||
accelc_Blowfish_set_key(KeyHash.byte, sizeof(KeyHash), &BlowfishKey);
|
||||
}
|
||||
|
||||
std::vector<char> EncryptString(const void* srcBytes, size_t srclen) {
|
||||
std::vector<char> ret;
|
||||
if (srclen == 0)
|
||||
return ret;
|
||||
|
||||
ret.resize(srclen * 2 + 1);
|
||||
ret[srclen * 2] = 0;
|
||||
|
||||
uint8_t CV[BLOWFISH_BLOCK_SIZE] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
accelc_Blowfish_encrypt(CV, &BlowfishKey, BLOWFISH_BIG_ENDIAN);
|
||||
|
||||
const uint64_t* blocks = reinterpret_cast<const uint64_t*>(srcBytes);
|
||||
size_t blocks_len = srclen / BLOWFISH_BLOCK_SIZE;
|
||||
for (size_t i = 0; i < blocks_len; ++i) {
|
||||
union {
|
||||
uint8_t byte[8];
|
||||
uint64_t qword;
|
||||
} temp;
|
||||
|
||||
temp.qword = blocks[i];
|
||||
temp.qword ^= *reinterpret_cast<uint64_t*>(CV);
|
||||
accelc_Blowfish_encrypt(temp.byte, &BlowfishKey, BLOWFISH_BIG_ENDIAN);
|
||||
*reinterpret_cast<uint64_t*>(CV) ^= temp.qword;
|
||||
|
||||
BytesToHex(temp.byte, 8, ret.data() + 16 * i);
|
||||
}
|
||||
|
||||
if (srclen % BLOWFISH_BLOCK_SIZE) {
|
||||
accelc_Blowfish_encrypt(CV, &BlowfishKey, BLOWFISH_BIG_ENDIAN);
|
||||
for (size_t i = 0; i < srclen % BLOWFISH_BLOCK_SIZE; ++i)
|
||||
CV[i] ^= reinterpret_cast<const uint8_t*>(blocks + blocks_len)[i];
|
||||
BytesToHex(CV, srclen % BLOWFISH_BLOCK_SIZE, ret.data() + 16 * blocks_len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> DecryptString(const char* srchex, size_t srclen) {
|
||||
std::vector<uint8_t> ret;
|
||||
if (CheckHex(srchex, srclen) == false)
|
||||
return ret;
|
||||
|
||||
ret.resize(srclen / 2);
|
||||
uint8_t CV[BLOWFISH_BLOCK_SIZE] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
accelc_Blowfish_encrypt(CV, &BlowfishKey, BLOWFISH_BIG_ENDIAN);
|
||||
|
||||
const char (*blocks)[16] = reinterpret_cast<const char (*)[16]>(srchex);
|
||||
size_t blocks_len = srclen / 16;
|
||||
for (size_t i = 0; i < blocks_len; ++i) {
|
||||
union {
|
||||
uint8_t byte[8];
|
||||
uint64_t qword;
|
||||
} temp, temp2;
|
||||
|
||||
HexToBytes(blocks[i], 16, temp.byte);
|
||||
std::memcpy(temp2.byte, temp.byte, 8);
|
||||
accelc_Blowfish_decrypt(temp.byte, &BlowfishKey, BLOWFISH_BIG_ENDIAN);
|
||||
temp.qword ^= *reinterpret_cast<uint64_t*>(CV);
|
||||
*reinterpret_cast<uint64_t*>(ret.data() + 8 * i) = temp.qword;
|
||||
*reinterpret_cast<uint64_t*>(CV) ^= temp2.qword;
|
||||
}
|
||||
|
||||
if (srclen % 16) {
|
||||
union {
|
||||
uint8_t byte[8];
|
||||
uint64_t qword;
|
||||
} temp = { };
|
||||
HexToBytes(blocks[blocks_len], srclen % 16, temp.byte);
|
||||
|
||||
accelc_Blowfish_encrypt(CV, &BlowfishKey, BLOWFISH_BIG_ENDIAN);
|
||||
for (size_t i = 0; i < (srclen % 16) / 2; ++i)
|
||||
ret[blocks_len * 8 + i] = temp.byte[i] ^ CV[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class Navicat12Crypto : public Navicat11Crypto {
|
||||
protected:
|
||||
AES_KEY AES128Key;
|
||||
public:
|
||||
|
||||
Navicat12Crypto() : Navicat11Crypto() {
|
||||
uint8_t DefaultKey[16] = {
|
||||
'l', 'i', 'b', 'c', 'c', 'k', 'e', 'y',
|
||||
'l', 'i', 'b', 'c', 'c', 'k', 'e', 'y'
|
||||
};
|
||||
accelc_AES128_set_key(DefaultKey, &AES128Key);
|
||||
}
|
||||
|
||||
Navicat12Crypto(const void* srcBytes, size_t srclen) :
|
||||
Navicat11Crypto(srcBytes, srclen) {
|
||||
|
||||
uint8_t DefaultKey[16] = {
|
||||
'l', 'i', 'b', 'c', 'c', 'k', 'e', 'y',
|
||||
'l', 'i', 'b', 'c', 'c', 'k', 'e', 'y'
|
||||
};
|
||||
accelc_AES128_set_key(DefaultKey, &AES128Key);
|
||||
}
|
||||
|
||||
std::vector<char> EncryptString(const void* srcBytes, size_t srclen) {
|
||||
std::vector<char> ret;
|
||||
if (srclen == 0)
|
||||
return ret;
|
||||
|
||||
ret.resize((srclen / AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE * 2);
|
||||
union {
|
||||
uint8_t byte[AES_BLOCK_SIZE];
|
||||
uint64_t qword[2];
|
||||
} CV = {
|
||||
'l', 'i', 'b', 'c', 'c', 'i', 'v', ' ',
|
||||
'l', 'i', 'b', 'c', 'c', 'i', 'v', ' '
|
||||
};
|
||||
|
||||
const uint8_t (*blocks)[AES_BLOCK_SIZE] = reinterpret_cast<const uint8_t (*)[AES_BLOCK_SIZE]>(srcBytes);
|
||||
size_t blocks_len = srclen / AES_BLOCK_SIZE;
|
||||
for (size_t i = 0; i < blocks_len; ++i) {
|
||||
union {
|
||||
uint8_t byte[AES_BLOCK_SIZE];
|
||||
uint64_t qword[2];
|
||||
} temp;
|
||||
|
||||
std::memcpy(temp.byte, blocks[i], AES_BLOCK_SIZE);
|
||||
temp.qword[0] ^= CV.qword[0];
|
||||
temp.qword[1] ^= CV.qword[1];
|
||||
accelc_AES128_encrypt(temp.byte, &AES128Key);
|
||||
BytesToHex(temp.byte, AES_BLOCK_SIZE, ret.data() + 2 * AES_BLOCK_SIZE * i);
|
||||
CV.qword[0] = temp.qword[0];
|
||||
CV.qword[1] = temp.qword[1];
|
||||
}
|
||||
|
||||
uint8_t padding = AES_BLOCK_SIZE - srclen % AES_BLOCK_SIZE;
|
||||
union {
|
||||
uint8_t byte[AES_BLOCK_SIZE];
|
||||
uint64_t qword[2];
|
||||
} temp;
|
||||
|
||||
std::memcpy(temp.byte, blocks[blocks_len], srclen % AES_BLOCK_SIZE);
|
||||
for (size_t i = srclen % AES_BLOCK_SIZE; i < AES_BLOCK_SIZE; ++i)
|
||||
temp.byte[i] = padding;
|
||||
|
||||
temp.qword[0] ^= CV.qword[0];
|
||||
temp.qword[1] ^= CV.qword[1];
|
||||
accelc_AES128_encrypt(temp.byte, &AES128Key);
|
||||
BytesToHex(temp.byte, AES_BLOCK_SIZE, ret.data() + 2 * AES_BLOCK_SIZE * blocks_len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> DecryptString(const char* srchex, size_t srclen) {
|
||||
std::vector<uint8_t> ret;
|
||||
if (srclen % (2 * AES_BLOCK_SIZE) != 0 || CheckHex(srchex, srclen) == false)
|
||||
return ret;
|
||||
|
||||
ret.reserve(srclen / 2);
|
||||
ret.resize(srclen / 2 - AES_BLOCK_SIZE);
|
||||
union {
|
||||
uint8_t byte[AES_BLOCK_SIZE];
|
||||
uint64_t qword[2];
|
||||
} CV = {
|
||||
'l', 'i', 'b', 'c', 'c', 'i', 'v', ' ',
|
||||
'l', 'i', 'b', 'c', 'c', 'i', 'v', ' '
|
||||
};
|
||||
|
||||
const char (*blocks)[2 * AES_BLOCK_SIZE] = reinterpret_cast<const char(*)[2 * AES_BLOCK_SIZE]>(srchex);
|
||||
size_t blocks_len = srclen / (2 * AES_BLOCK_SIZE);
|
||||
for (size_t i = 0; i < blocks_len; ++i) {
|
||||
union {
|
||||
uint8_t byte[AES_BLOCK_SIZE];
|
||||
uint64_t qword[2];
|
||||
} temp, NextVector;
|
||||
|
||||
HexToBytes(blocks[i], 2 * AES_BLOCK_SIZE, temp.byte);
|
||||
std::memcpy(NextVector.byte, temp.byte, AES_BLOCK_SIZE);
|
||||
accelc_AES128_decrypt(temp.byte, &AES128Key);
|
||||
temp.qword[0] ^= CV.qword[0];
|
||||
temp.qword[1] ^= CV.qword[1];
|
||||
|
||||
std::memcpy(ret.data() + AES_BLOCK_SIZE * i, temp.byte, AES_BLOCK_SIZE);
|
||||
std::memcpy(CV.byte, NextVector.byte, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
union {
|
||||
uint8_t byte[AES_BLOCK_SIZE];
|
||||
uint64_t qword[2];
|
||||
} temp;
|
||||
HexToBytes(blocks[blocks_len], 2 * AES_BLOCK_SIZE, temp.byte);
|
||||
accelc_AES128_decrypt(temp.byte, &AES128Key);
|
||||
temp.qword[0] ^= CV.qword[0];
|
||||
temp.qword[1] ^= CV.qword[1];
|
||||
|
||||
if (temp.byte[AES_BLOCK_SIZE - 1] > AES_BLOCK_SIZE) {
|
||||
ret.clear();
|
||||
return ret;
|
||||
} else {
|
||||
uint8_t padding = temp.byte[AES_BLOCK_SIZE - 1];
|
||||
for (int i = AES_BLOCK_SIZE - padding; i < AES_BLOCK_SIZE; ++i)
|
||||
if (temp.byte[i] != padding) {
|
||||
ret.clear();
|
||||
return ret;
|
||||
}
|
||||
for (int i = 0; i < (AES_BLOCK_SIZE - padding); ++i)
|
||||
ret.emplace_back(temp.byte[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
@ -1,438 +0,0 @@
|
||||
#include "aes.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#else
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
extern const uint32_t accelc_aes_rcon[11];
|
||||
|
||||
extern const uint8_t accelc_aes_SBox[256];
|
||||
extern const uint8_t accelc_aes_InverseSBox[256];
|
||||
|
||||
extern const uint8_t accelc_aes_GF2p8_Mul_0x02[256];
|
||||
extern const uint8_t accelc_aes_GF2p8_Mul_0x03[256];
|
||||
extern const uint8_t accelc_aes_GF2p8_Mul_0x09[256];
|
||||
extern const uint8_t accelc_aes_GF2p8_Mul_0x0B[256];
|
||||
extern const uint8_t accelc_aes_GF2p8_Mul_0x0D[256];
|
||||
extern const uint8_t accelc_aes_GF2p8_Mul_0x0E[256];
|
||||
|
||||
#define Swap(X, Y, Temp) \
|
||||
Temp = X; \
|
||||
X = Y; \
|
||||
Y = Temp;
|
||||
|
||||
void accelc_AES128_encrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey) {
|
||||
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[0];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[1];
|
||||
|
||||
uint8_t ShiftTemp = 0;
|
||||
for (int i = 1; i < 10; ++i) {
|
||||
|
||||
for (int j = 0; j < 16; ++j)
|
||||
srcBytes[j] = accelc_aes_SBox[srcBytes[j]];
|
||||
|
||||
//Shift rows starts;
|
||||
//Shift the second row;
|
||||
Swap(srcBytes[1], srcBytes[5], ShiftTemp)
|
||||
Swap(srcBytes[5], srcBytes[9], ShiftTemp)
|
||||
Swap(srcBytes[9], srcBytes[13], ShiftTemp)
|
||||
//Shift the third row;
|
||||
Swap(srcBytes[2], srcBytes[10], ShiftTemp)
|
||||
Swap(srcBytes[6], srcBytes[14], ShiftTemp)
|
||||
//Shift the fourth row;
|
||||
Swap(srcBytes[3], srcBytes[15], ShiftTemp)
|
||||
Swap(srcBytes[15], srcBytes[11], ShiftTemp)
|
||||
Swap(srcBytes[11], srcBytes[7], ShiftTemp)
|
||||
//Shift rows ends;
|
||||
|
||||
|
||||
for (int j = 0; j < 16; j += 4) {
|
||||
uint8_t temp[4];
|
||||
*(uint32_t*)temp = ((uint32_t*)srcBytes)[j / 4];
|
||||
|
||||
srcBytes[j] = (uint8_t)(accelc_aes_GF2p8_Mul_0x02[temp[0]] ^ accelc_aes_GF2p8_Mul_0x03[temp[1]] ^ temp[2] ^ temp[3]);
|
||||
srcBytes[j + 1] = (uint8_t)(temp[0] ^ accelc_aes_GF2p8_Mul_0x02[temp[1]] ^ accelc_aes_GF2p8_Mul_0x03[temp[2]] ^ temp[3]);
|
||||
srcBytes[j + 2] = (uint8_t)(temp[0] ^ temp[1] ^ accelc_aes_GF2p8_Mul_0x02[temp[2]] ^ accelc_aes_GF2p8_Mul_0x03[temp[3]]);
|
||||
srcBytes[j + 3] = (uint8_t)(accelc_aes_GF2p8_Mul_0x03[temp[0]] ^ temp[1] ^ temp[2] ^ accelc_aes_GF2p8_Mul_0x02[temp[3]]);
|
||||
}
|
||||
|
||||
((uint64_t*)(srcBytes))[0] ^= srcKey->qword[i * 2];
|
||||
((uint64_t*)(srcBytes))[1] ^= srcKey->qword[i * 2 + 1];
|
||||
}
|
||||
|
||||
for (int j = 0; j < 16; ++j)
|
||||
srcBytes[j] = accelc_aes_SBox[srcBytes[j]];
|
||||
|
||||
//Shift rows starts;
|
||||
//Shift the second row;
|
||||
Swap(srcBytes[1], srcBytes[5], ShiftTemp)
|
||||
Swap(srcBytes[5], srcBytes[9], ShiftTemp)
|
||||
Swap(srcBytes[9], srcBytes[13], ShiftTemp)
|
||||
//Shift the third row;
|
||||
Swap(srcBytes[2], srcBytes[10], ShiftTemp)
|
||||
Swap(srcBytes[6], srcBytes[14], ShiftTemp)
|
||||
//Shift the fourth row;
|
||||
Swap(srcBytes[3], srcBytes[15], ShiftTemp)
|
||||
Swap(srcBytes[15], srcBytes[11], ShiftTemp)
|
||||
Swap(srcBytes[11], srcBytes[7], ShiftTemp)
|
||||
//Shift rows ends;
|
||||
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[20];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[21];
|
||||
}
|
||||
|
||||
void accelc_AES128_decrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey) {
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[20];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[21];
|
||||
|
||||
uint8_t ShiftTemp = 0;
|
||||
|
||||
for (int i = 9; i > 0; --i) {
|
||||
//Inverse Shift rows starts;
|
||||
//Inverse shift the second row;
|
||||
Swap(srcBytes[13], srcBytes[9], ShiftTemp)
|
||||
Swap(srcBytes[9], srcBytes[5], ShiftTemp)
|
||||
Swap(srcBytes[5], srcBytes[1], ShiftTemp)
|
||||
//Inverse shift the third row;
|
||||
Swap(srcBytes[14], srcBytes[6], ShiftTemp)
|
||||
Swap(srcBytes[10], srcBytes[2], ShiftTemp)
|
||||
//Inverse shift the fourth row;
|
||||
Swap(srcBytes[3], srcBytes[7], ShiftTemp)
|
||||
Swap(srcBytes[7], srcBytes[11], ShiftTemp)
|
||||
Swap(srcBytes[11], srcBytes[15], ShiftTemp)
|
||||
|
||||
for (int j = 0; j < 16; ++j)
|
||||
srcBytes[j] = accelc_aes_InverseSBox[srcBytes[j]];
|
||||
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[i * 2];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[i * 2 + 1];
|
||||
|
||||
for (int j = 0; j < 16; j += 4) {
|
||||
uint8_t temp[4];
|
||||
*(uint32_t*)temp = ((uint32_t*)srcBytes)[j / 4];
|
||||
srcBytes[j] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0E[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[2]] ^ accelc_aes_GF2p8_Mul_0x09[temp[3]]);
|
||||
srcBytes[j + 1] = (uint8_t)(accelc_aes_GF2p8_Mul_0x09[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[3]]);
|
||||
srcBytes[j + 2] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0D[temp[0]] ^ accelc_aes_GF2p8_Mul_0x09[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[3]]);
|
||||
srcBytes[j + 3] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0B[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[1]] ^ accelc_aes_GF2p8_Mul_0x09[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[3]]);
|
||||
}
|
||||
}
|
||||
|
||||
//Inverse Shift rows starts;
|
||||
//Inverse shift the second row;
|
||||
Swap(srcBytes[13], srcBytes[9], ShiftTemp)
|
||||
Swap(srcBytes[9], srcBytes[5], ShiftTemp)
|
||||
Swap(srcBytes[5], srcBytes[1], ShiftTemp)
|
||||
//Inverse shift the third row;
|
||||
Swap(srcBytes[14], srcBytes[6], ShiftTemp)
|
||||
Swap(srcBytes[10], srcBytes[2], ShiftTemp)
|
||||
//Inverse shift the fourth row;
|
||||
Swap(srcBytes[3], srcBytes[7], ShiftTemp)
|
||||
Swap(srcBytes[7], srcBytes[11], ShiftTemp)
|
||||
Swap(srcBytes[11], srcBytes[15], ShiftTemp)
|
||||
|
||||
for (int j = 0; j < 16; ++j)
|
||||
srcBytes[j] = accelc_aes_InverseSBox[srcBytes[j]];
|
||||
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[0];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[1];
|
||||
}
|
||||
|
||||
void accelc_AES128_set_key(const uint8_t srcUserKey[16], AES_KEY* dstKey) {
|
||||
dstKey->qword[0] = ((const uint64_t*)srcUserKey)[0];
|
||||
dstKey->qword[1] = ((const uint64_t*)srcUserKey)[1];
|
||||
|
||||
for (int i = 4; i < 44; ++i) {
|
||||
uint32_t temp = dstKey->dword[i - 1];
|
||||
if (i % 4 == 0) {
|
||||
temp = _rotr(temp, 8);
|
||||
((uint8_t*)&temp)[0] = accelc_aes_SBox[((uint8_t*)&temp)[0]];
|
||||
((uint8_t*)&temp)[1] = accelc_aes_SBox[((uint8_t*)&temp)[1]];
|
||||
((uint8_t*)&temp)[2] = accelc_aes_SBox[((uint8_t*)&temp)[2]];
|
||||
((uint8_t*)&temp)[3] = accelc_aes_SBox[((uint8_t*)&temp)[3]];
|
||||
temp ^= accelc_aes_rcon[i / 4];
|
||||
}
|
||||
dstKey->dword[i] = dstKey->dword[i - 4] ^ temp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void accelc_AES192_encrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey) {
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[0];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[1];
|
||||
|
||||
uint8_t ShiftTemp = 0;
|
||||
for (int i = 1; i < 12; ++i) {
|
||||
|
||||
for (int j = 0; j < 16; ++j)
|
||||
srcBytes[j] = accelc_aes_SBox[srcBytes[j]];
|
||||
|
||||
//Shift rows starts;
|
||||
//Shift the second row;
|
||||
Swap(srcBytes[1], srcBytes[5], ShiftTemp)
|
||||
Swap(srcBytes[5], srcBytes[9], ShiftTemp)
|
||||
Swap(srcBytes[9], srcBytes[13], ShiftTemp)
|
||||
//Shift the third row;
|
||||
Swap(srcBytes[2], srcBytes[10], ShiftTemp)
|
||||
Swap(srcBytes[6], srcBytes[14], ShiftTemp)
|
||||
//Shift the fourth row;
|
||||
Swap(srcBytes[3], srcBytes[15], ShiftTemp)
|
||||
Swap(srcBytes[15], srcBytes[11], ShiftTemp)
|
||||
Swap(srcBytes[11], srcBytes[7], ShiftTemp)
|
||||
//Shift rows ends;
|
||||
|
||||
for (int j = 0; j < 16; j += 4) {
|
||||
uint8_t temp[4];
|
||||
*(uint32_t*)temp = ((uint32_t*)srcBytes)[j / 4];
|
||||
|
||||
srcBytes[j] = (uint8_t)(accelc_aes_GF2p8_Mul_0x02[temp[0]] ^ accelc_aes_GF2p8_Mul_0x03[temp[1]] ^ temp[2] ^ temp[3]);
|
||||
srcBytes[j + 1] = (uint8_t)(temp[0] ^ accelc_aes_GF2p8_Mul_0x02[temp[1]] ^ accelc_aes_GF2p8_Mul_0x03[temp[2]] ^ temp[3]);
|
||||
srcBytes[j + 2] = (uint8_t)(temp[0] ^ temp[1] ^ accelc_aes_GF2p8_Mul_0x02[temp[2]] ^ accelc_aes_GF2p8_Mul_0x03[temp[3]]);
|
||||
srcBytes[j + 3] = (uint8_t)(accelc_aes_GF2p8_Mul_0x03[temp[0]] ^ temp[1] ^ temp[2] ^ accelc_aes_GF2p8_Mul_0x02[temp[3]]);
|
||||
}
|
||||
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[i * 2];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[i * 2 + 1];
|
||||
}
|
||||
|
||||
for (int j = 0; j < 16; ++j)
|
||||
srcBytes[j] = accelc_aes_SBox[srcBytes[j]];
|
||||
|
||||
//Shift rows starts;
|
||||
//Shift the second row;
|
||||
Swap(srcBytes[1], srcBytes[5], ShiftTemp) //Swap is a MACRO, no need to add ';'.
|
||||
Swap(srcBytes[5], srcBytes[9], ShiftTemp)
|
||||
Swap(srcBytes[9], srcBytes[13], ShiftTemp)
|
||||
//Shift the third row;
|
||||
Swap(srcBytes[2], srcBytes[10], ShiftTemp)
|
||||
Swap(srcBytes[6], srcBytes[14], ShiftTemp)
|
||||
//Shift the fourth row;
|
||||
Swap(srcBytes[3], srcBytes[15], ShiftTemp)
|
||||
Swap(srcBytes[15], srcBytes[11], ShiftTemp)
|
||||
Swap(srcBytes[11], srcBytes[7], ShiftTemp)
|
||||
//Shift rows ends;
|
||||
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[24];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[25];
|
||||
}
|
||||
|
||||
void accelc_AES192_decrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey) {
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[24];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[25];
|
||||
|
||||
uint8_t ShiftTemp = 0;
|
||||
|
||||
for (int i = 11; i > 0; --i) {
|
||||
//Inverse Shift rows starts;
|
||||
//Inverse shift the second row;
|
||||
Swap(srcBytes[13], srcBytes[9], ShiftTemp)
|
||||
Swap(srcBytes[9], srcBytes[5], ShiftTemp)
|
||||
Swap(srcBytes[5], srcBytes[1], ShiftTemp)
|
||||
//Inverse shift the third row;
|
||||
Swap(srcBytes[14], srcBytes[6], ShiftTemp)
|
||||
Swap(srcBytes[10], srcBytes[2], ShiftTemp)
|
||||
//Inverse shift the fourth row;
|
||||
Swap(srcBytes[3], srcBytes[7], ShiftTemp)
|
||||
Swap(srcBytes[7], srcBytes[11], ShiftTemp)
|
||||
Swap(srcBytes[11], srcBytes[15], ShiftTemp)
|
||||
|
||||
for (int j = 0; j < 16; ++j)
|
||||
srcBytes[j] = accelc_aes_InverseSBox[srcBytes[j]];
|
||||
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[i * 2];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[i * 2 + 1];
|
||||
|
||||
for (int j = 0; j < 16; j += 4) {
|
||||
uint8_t temp[4];
|
||||
*(uint32_t*)temp = ((uint32_t*)srcBytes)[j / 4];
|
||||
srcBytes[j] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0E[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[2]] ^ accelc_aes_GF2p8_Mul_0x09[temp[3]]);
|
||||
srcBytes[j + 1] = (uint8_t)(accelc_aes_GF2p8_Mul_0x09[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[3]]);
|
||||
srcBytes[j + 2] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0D[temp[0]] ^ accelc_aes_GF2p8_Mul_0x09[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[3]]);
|
||||
srcBytes[j + 3] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0B[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[1]] ^ accelc_aes_GF2p8_Mul_0x09[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[3]]);
|
||||
}
|
||||
}
|
||||
|
||||
//Inverse Shift rows starts;
|
||||
//Inverse shift the second row;
|
||||
Swap(srcBytes[13], srcBytes[9], ShiftTemp)
|
||||
Swap(srcBytes[9], srcBytes[5], ShiftTemp)
|
||||
Swap(srcBytes[5], srcBytes[1], ShiftTemp)
|
||||
//Inverse shift the third row;
|
||||
Swap(srcBytes[14], srcBytes[6], ShiftTemp)
|
||||
Swap(srcBytes[10], srcBytes[2], ShiftTemp)
|
||||
//Inverse shift the fourth row;
|
||||
Swap(srcBytes[3], srcBytes[7], ShiftTemp)
|
||||
Swap(srcBytes[7], srcBytes[11], ShiftTemp)
|
||||
Swap(srcBytes[11], srcBytes[15], ShiftTemp)
|
||||
|
||||
for (uint8_t j = 0; j < 16; ++j)
|
||||
srcBytes[j] = accelc_aes_InverseSBox[srcBytes[j]];
|
||||
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[0];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[1];
|
||||
}
|
||||
|
||||
void accelc_AES192_set_key(const uint8_t srcUserKey[24], AES_KEY* dstKey) {
|
||||
dstKey->qword[0] = ((const uint64_t*)srcUserKey)[0];
|
||||
dstKey->qword[1] = ((const uint64_t*)srcUserKey)[1];
|
||||
dstKey->qword[2] = ((const uint64_t*)srcUserKey)[2];
|
||||
|
||||
for (int i = 6; i < 52; ++i) {
|
||||
uint32_t temp = dstKey->dword[i - 1];
|
||||
if (i % 6 == 0) {
|
||||
temp = _rotr(temp, 8);
|
||||
((uint8_t*)&temp)[0] = accelc_aes_SBox[((uint8_t*)&temp)[0]];
|
||||
((uint8_t*)&temp)[1] = accelc_aes_SBox[((uint8_t*)&temp)[1]];
|
||||
((uint8_t*)&temp)[2] = accelc_aes_SBox[((uint8_t*)&temp)[2]];
|
||||
((uint8_t*)&temp)[3] = accelc_aes_SBox[((uint8_t*)&temp)[3]];
|
||||
temp ^= accelc_aes_rcon[i / 6];
|
||||
}
|
||||
dstKey->dword[i] = dstKey->dword[i - 6] ^ temp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void accelc_AES256_encrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey) {
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[0];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[1];
|
||||
|
||||
uint8_t ShiftTemp = 0;
|
||||
for (int i = 1; i < 14; ++i) {
|
||||
|
||||
for (int j = 0; j < 16; ++j)
|
||||
srcBytes[j] = accelc_aes_SBox[srcBytes[j]];
|
||||
|
||||
//Shift rows starts;
|
||||
//Shift the second row;
|
||||
Swap(srcBytes[1], srcBytes[5], ShiftTemp)
|
||||
Swap(srcBytes[5], srcBytes[9], ShiftTemp)
|
||||
Swap(srcBytes[9], srcBytes[13], ShiftTemp)
|
||||
//Shift the third row;
|
||||
Swap(srcBytes[2], srcBytes[10], ShiftTemp)
|
||||
Swap(srcBytes[6], srcBytes[14], ShiftTemp)
|
||||
//Shift the fourth row;
|
||||
Swap(srcBytes[3], srcBytes[15], ShiftTemp)
|
||||
Swap(srcBytes[15], srcBytes[11], ShiftTemp)
|
||||
Swap(srcBytes[11], srcBytes[7], ShiftTemp)
|
||||
//Shift rows ends;
|
||||
|
||||
for (int j = 0; j < 16; j += 4) {
|
||||
uint8_t temp[4];
|
||||
*(uint32_t*)temp = ((uint32_t*)srcBytes)[j / 4];
|
||||
|
||||
srcBytes[j] = (uint8_t)(accelc_aes_GF2p8_Mul_0x02[temp[0]] ^ accelc_aes_GF2p8_Mul_0x03[temp[1]] ^ temp[2] ^ temp[3]);
|
||||
srcBytes[j + 1] = (uint8_t)(temp[0] ^ accelc_aes_GF2p8_Mul_0x02[temp[1]] ^ accelc_aes_GF2p8_Mul_0x03[temp[2]] ^ temp[3]);
|
||||
srcBytes[j + 2] = (uint8_t)(temp[0] ^ temp[1] ^ accelc_aes_GF2p8_Mul_0x02[temp[2]] ^ accelc_aes_GF2p8_Mul_0x03[temp[3]]);
|
||||
srcBytes[j + 3] = (uint8_t)(accelc_aes_GF2p8_Mul_0x03[temp[0]] ^ temp[1] ^ temp[2] ^ accelc_aes_GF2p8_Mul_0x02[temp[3]]);
|
||||
}
|
||||
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[i * 2];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[i * 2 + 1];
|
||||
}
|
||||
|
||||
for (int j = 0; j < 16; ++j)
|
||||
srcBytes[j] = accelc_aes_SBox[srcBytes[j]];
|
||||
|
||||
//Shift rows starts;
|
||||
//Shift the second row;
|
||||
Swap(srcBytes[1], srcBytes[5], ShiftTemp)
|
||||
Swap(srcBytes[5], srcBytes[9], ShiftTemp)
|
||||
Swap(srcBytes[9], srcBytes[13], ShiftTemp)
|
||||
//Shift the third row;
|
||||
Swap(srcBytes[2], srcBytes[10], ShiftTemp)
|
||||
Swap(srcBytes[6], srcBytes[14], ShiftTemp)
|
||||
//Shift the fourth row;
|
||||
Swap(srcBytes[3], srcBytes[15], ShiftTemp)
|
||||
Swap(srcBytes[15], srcBytes[11], ShiftTemp)
|
||||
Swap(srcBytes[11], srcBytes[7], ShiftTemp)
|
||||
//Shift rows ends;
|
||||
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[28];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[29];
|
||||
}
|
||||
|
||||
void accelc_AES256_decrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey) {
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[28];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[29];
|
||||
|
||||
uint8_t ShiftTemp = 0;
|
||||
for (int i = 13; i > 0; --i) {
|
||||
//Inverse Shift rows starts;
|
||||
//Inverse shift the second row;
|
||||
Swap(srcBytes[13], srcBytes[9], ShiftTemp)
|
||||
Swap(srcBytes[9], srcBytes[5], ShiftTemp)
|
||||
Swap(srcBytes[5], srcBytes[1], ShiftTemp)
|
||||
//Inverse shift the third row;
|
||||
Swap(srcBytes[14], srcBytes[6], ShiftTemp)
|
||||
Swap(srcBytes[10], srcBytes[2], ShiftTemp)
|
||||
//Inverse shift the fourth row;
|
||||
Swap(srcBytes[3], srcBytes[7], ShiftTemp)
|
||||
Swap(srcBytes[7], srcBytes[11], ShiftTemp)
|
||||
Swap(srcBytes[11], srcBytes[15], ShiftTemp)
|
||||
|
||||
for (int j = 0; j < 16; ++j)
|
||||
srcBytes[j] = accelc_aes_InverseSBox[srcBytes[j]];
|
||||
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[i * 2];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[i * 2 + 1];
|
||||
|
||||
for (int j = 0; j < 16; j += 4) {
|
||||
uint8_t temp[4];
|
||||
*(uint32_t*)temp = ((uint32_t*)srcBytes)[j / 4];
|
||||
|
||||
srcBytes[j] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0E[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[2]] ^ accelc_aes_GF2p8_Mul_0x09[temp[3]]);
|
||||
srcBytes[j + 1] = (uint8_t)(accelc_aes_GF2p8_Mul_0x09[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[3]]);
|
||||
srcBytes[j + 2] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0D[temp[0]] ^ accelc_aes_GF2p8_Mul_0x09[temp[1]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0B[temp[3]]);
|
||||
srcBytes[j + 3] = (uint8_t)(accelc_aes_GF2p8_Mul_0x0B[temp[0]] ^ accelc_aes_GF2p8_Mul_0x0D[temp[1]] ^ accelc_aes_GF2p8_Mul_0x09[temp[2]] ^ accelc_aes_GF2p8_Mul_0x0E[temp[3]]);
|
||||
}
|
||||
}
|
||||
|
||||
//Inverse Shift rows starts;
|
||||
//Inverse shift the second row;
|
||||
Swap(srcBytes[13], srcBytes[9], ShiftTemp)
|
||||
Swap(srcBytes[9], srcBytes[5], ShiftTemp)
|
||||
Swap(srcBytes[5], srcBytes[1], ShiftTemp)
|
||||
//Inverse shift the third row;
|
||||
Swap(srcBytes[14], srcBytes[6], ShiftTemp)
|
||||
Swap(srcBytes[10], srcBytes[2], ShiftTemp)
|
||||
//Inverse shift the fourth row;
|
||||
Swap(srcBytes[3], srcBytes[7], ShiftTemp)
|
||||
Swap(srcBytes[7], srcBytes[11], ShiftTemp)
|
||||
Swap(srcBytes[11], srcBytes[15], ShiftTemp)
|
||||
|
||||
for (int j = 0; j < 16; ++j)
|
||||
srcBytes[j] = accelc_aes_InverseSBox[srcBytes[j]];
|
||||
|
||||
((uint64_t*)srcBytes)[0] ^= srcKey->qword[0];
|
||||
((uint64_t*)srcBytes)[1] ^= srcKey->qword[1];
|
||||
}
|
||||
|
||||
void accelc_AES256_set_key(const uint8_t srcUserKey[32], AES_KEY* dstKey) {
|
||||
dstKey->qword[0] = ((const uint64_t*)srcUserKey)[0];
|
||||
dstKey->qword[1] = ((const uint64_t*)srcUserKey)[1];
|
||||
dstKey->qword[2] = ((const uint64_t*)srcUserKey)[2];
|
||||
dstKey->qword[3] = ((const uint64_t*)srcUserKey)[3];
|
||||
|
||||
for (int i = 8; i < 60; ++i) {
|
||||
uint32_t temp = dstKey->dword[i - 1];
|
||||
if (i % 8 == 0) {
|
||||
temp = _rotr(temp, 8);
|
||||
((uint8_t*)&temp)[0] = accelc_aes_SBox[((uint8_t*)&temp)[0]];
|
||||
((uint8_t*)&temp)[1] = accelc_aes_SBox[((uint8_t*)&temp)[1]];
|
||||
((uint8_t*)&temp)[2] = accelc_aes_SBox[((uint8_t*)&temp)[2]];
|
||||
((uint8_t*)&temp)[3] = accelc_aes_SBox[((uint8_t*)&temp)[3]];
|
||||
temp ^= accelc_aes_rcon[i / 8];
|
||||
}
|
||||
if (i % 8 == 4) {
|
||||
((uint8_t*)&temp)[0] = accelc_aes_SBox[((uint8_t*)&temp)[0]];
|
||||
((uint8_t*)&temp)[1] = accelc_aes_SBox[((uint8_t*)&temp)[1]];
|
||||
((uint8_t*)&temp)[2] = accelc_aes_SBox[((uint8_t*)&temp)[2]];
|
||||
((uint8_t*)&temp)[3] = accelc_aes_SBox[((uint8_t*)&temp)[3]];
|
||||
}
|
||||
dstKey->dword[i] = dstKey->dword[i - 8] ^ temp;
|
||||
}
|
||||
}
|
||||
@ -1,82 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define AES_BLOCK_SIZE 16
|
||||
#define AES128_USERKEY_LENGTH 16
|
||||
#define AES192_USERKEY_LENGTH 24
|
||||
#define AES256_USERKEY_LENGTH 32
|
||||
|
||||
typedef struct _AES_KEY {
|
||||
union {
|
||||
uint8_t byte[240];
|
||||
uint16_t word[120];
|
||||
uint32_t dword[60];
|
||||
uint64_t qword[30];
|
||||
};
|
||||
} AES_KEY;
|
||||
|
||||
//
|
||||
// encrypt
|
||||
//
|
||||
void accelc_AES128_encrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
|
||||
void accelc_AES192_encrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
|
||||
void accelc_AES256_encrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
|
||||
|
||||
//
|
||||
// dncrypt
|
||||
//
|
||||
void accelc_AES128_decrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
|
||||
void accelc_AES192_decrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
|
||||
void accelc_AES256_decrypt(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
|
||||
|
||||
//
|
||||
// set_key
|
||||
//
|
||||
void accelc_AES128_set_key(const uint8_t srcUserKey[AES128_USERKEY_LENGTH], AES_KEY* dstKey);
|
||||
void accelc_AES192_set_key(const uint8_t srcUserKey[AES192_USERKEY_LENGTH], AES_KEY* dstKey);
|
||||
void accelc_AES256_set_key(const uint8_t srcUserKey[AES256_USERKEY_LENGTH], AES_KEY* dstKey);
|
||||
|
||||
//
|
||||
// encrypt_aesni
|
||||
//
|
||||
void accelc_AES128_encrypt_aesni(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
|
||||
void accelc_AES192_encrypt_aesni(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
|
||||
void accelc_AES256_encrypt_aesni(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
|
||||
|
||||
//
|
||||
// decrypt_aesni
|
||||
//
|
||||
void accelc_AES128_decrypt_aesni(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
|
||||
void accelc_AES192_decrypt_aesni(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
|
||||
void accelc_AES256_decrypt_aesni(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcKey);
|
||||
|
||||
//
|
||||
// decrypt_aesni_fast
|
||||
//
|
||||
void accelc_AES128_decrypt_aesni_fast(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcInverseKey);
|
||||
void accelc_AES192_decrypt_aesni_fast(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcInverseKey);
|
||||
void accelc_AES256_decrypt_aesni_fast(uint8_t srcBytes[AES_BLOCK_SIZE], const AES_KEY* srcInverseKey);
|
||||
|
||||
//
|
||||
// set_key_aesni
|
||||
//
|
||||
void accelc_AES128_set_key_aesni(const uint8_t srcUserKey[AES128_USERKEY_LENGTH], AES_KEY* dstKey);
|
||||
void accelc_AES192_set_key_aesni(const uint8_t srcUserKey[AES128_USERKEY_LENGTH], AES_KEY* dstKey);
|
||||
void accelc_AES256_set_key_aesni(const uint8_t srcUserKey[AES256_USERKEY_LENGTH], AES_KEY* dstKey);
|
||||
|
||||
//
|
||||
// set_invkey_aesni
|
||||
//
|
||||
void accelc_AES128_set_invkey_aesni(const AES_KEY* __restrict srcKey, AES_KEY* __restrict dstInverseKey);
|
||||
void accelc_AES192_set_invkey_aesni(const AES_KEY* __restrict srcKey, AES_KEY* __restrict dstInverseKey);
|
||||
void accelc_AES256_set_invkey_aesni(const AES_KEY* __restrict srcKey, AES_KEY* __restrict dstInverseKey);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1,157 +0,0 @@
|
||||
#include <stdint.h>
|
||||
|
||||
const uint8_t accelc_aes_SBox[256] = {
|
||||
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
|
||||
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
|
||||
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
|
||||
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
|
||||
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
|
||||
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
|
||||
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
|
||||
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
|
||||
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
|
||||
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
|
||||
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
|
||||
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
|
||||
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
|
||||
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
|
||||
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
|
||||
};
|
||||
|
||||
const uint32_t accelc_aes_rcon[11] = {
|
||||
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
|
||||
};
|
||||
|
||||
const uint8_t accelc_aes_GF2p8_Mul_0x02[256] = {
|
||||
0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E,
|
||||
0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E,
|
||||
0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5A, 0x5C, 0x5E,
|
||||
0x60, 0x62, 0x64, 0x66, 0x68, 0x6A, 0x6C, 0x6E, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7A, 0x7C, 0x7E,
|
||||
0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9A, 0x9C, 0x9E,
|
||||
0xA0, 0xA2, 0xA4, 0xA6, 0xA8, 0xAA, 0xAC, 0xAE, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC, 0xBE,
|
||||
0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, 0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
|
||||
0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE, 0xF0, 0xF2, 0xF4, 0xF6, 0xF8, 0xFA, 0xFC, 0xFE,
|
||||
0x1B, 0x19, 0x1F, 0x1D, 0x13, 0x11, 0x17, 0x15, 0x0B, 0x09, 0x0F, 0x0D, 0x03, 0x01, 0x07, 0x05,
|
||||
0x3B, 0x39, 0x3F, 0x3D, 0x33, 0x31, 0x37, 0x35, 0x2B, 0x29, 0x2F, 0x2D, 0x23, 0x21, 0x27, 0x25,
|
||||
0x5B, 0x59, 0x5F, 0x5D, 0x53, 0x51, 0x57, 0x55, 0x4B, 0x49, 0x4F, 0x4D, 0x43, 0x41, 0x47, 0x45,
|
||||
0x7B, 0x79, 0x7F, 0x7D, 0x73, 0x71, 0x77, 0x75, 0x6B, 0x69, 0x6F, 0x6D, 0x63, 0x61, 0x67, 0x65,
|
||||
0x9B, 0x99, 0x9F, 0x9D, 0x93, 0x91, 0x97, 0x95, 0x8B, 0x89, 0x8F, 0x8D, 0x83, 0x81, 0x87, 0x85,
|
||||
0xBB, 0xB9, 0xBF, 0xBD, 0xB3, 0xB1, 0xB7, 0xB5, 0xAB, 0xA9, 0xAF, 0xAD, 0xA3, 0xA1, 0xA7, 0xA5,
|
||||
0xDB, 0xD9, 0xDF, 0xDD, 0xD3, 0xD1, 0xD7, 0xD5, 0xCB, 0xC9, 0xCF, 0xCD, 0xC3, 0xC1, 0xC7, 0xC5,
|
||||
0xFB, 0xF9, 0xFF, 0xFD, 0xF3, 0xF1, 0xF7, 0xF5, 0xEB, 0xE9, 0xEF, 0xED, 0xE3, 0xE1, 0xE7, 0xE5
|
||||
};
|
||||
|
||||
const uint8_t accelc_aes_GF2p8_Mul_0x03[256] = {
|
||||
0x00, 0x03, 0x06, 0x05, 0x0C, 0x0F, 0x0A, 0x09, 0x18, 0x1B, 0x1E, 0x1D, 0x14, 0x17, 0x12, 0x11,
|
||||
0x30, 0x33, 0x36, 0x35, 0x3C, 0x3F, 0x3A, 0x39, 0x28, 0x2B, 0x2E, 0x2D, 0x24, 0x27, 0x22, 0x21,
|
||||
0x60, 0x63, 0x66, 0x65, 0x6C, 0x6F, 0x6A, 0x69, 0x78, 0x7B, 0x7E, 0x7D, 0x74, 0x77, 0x72, 0x71,
|
||||
0x50, 0x53, 0x56, 0x55, 0x5C, 0x5F, 0x5A, 0x59, 0x48, 0x4B, 0x4E, 0x4D, 0x44, 0x47, 0x42, 0x41,
|
||||
0xC0, 0xC3, 0xC6, 0xC5, 0xCC, 0xCF, 0xCA, 0xC9, 0xD8, 0xDB, 0xDE, 0xDD, 0xD4, 0xD7, 0xD2, 0xD1,
|
||||
0xF0, 0xF3, 0xF6, 0xF5, 0xFC, 0xFF, 0xFA, 0xF9, 0xE8, 0xEB, 0xEE, 0xED, 0xE4, 0xE7, 0xE2, 0xE1,
|
||||
0xA0, 0xA3, 0xA6, 0xA5, 0xAC, 0xAF, 0xAA, 0xA9, 0xB8, 0xBB, 0xBE, 0xBD, 0xB4, 0xB7, 0xB2, 0xB1,
|
||||
0x90, 0x93, 0x96, 0x95, 0x9C, 0x9F, 0x9A, 0x99, 0x88, 0x8B, 0x8E, 0x8D, 0x84, 0x87, 0x82, 0x81,
|
||||
0x9B, 0x98, 0x9D, 0x9E, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8F, 0x8C, 0x89, 0x8A,
|
||||
0xAB, 0xA8, 0xAD, 0xAE, 0xA7, 0xA4, 0xA1, 0xA2, 0xB3, 0xB0, 0xB5, 0xB6, 0xBF, 0xBC, 0xB9, 0xBA,
|
||||
0xFB, 0xF8, 0xFD, 0xFE, 0xF7, 0xF4, 0xF1, 0xF2, 0xE3, 0xE0, 0xE5, 0xE6, 0xEF, 0xEC, 0xE9, 0xEA,
|
||||
0xCB, 0xC8, 0xCD, 0xCE, 0xC7, 0xC4, 0xC1, 0xC2, 0xD3, 0xD0, 0xD5, 0xD6, 0xDF, 0xDC, 0xD9, 0xDA,
|
||||
0x5B, 0x58, 0x5D, 0x5E, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4F, 0x4C, 0x49, 0x4A,
|
||||
0x6B, 0x68, 0x6D, 0x6E, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7F, 0x7C, 0x79, 0x7A,
|
||||
0x3B, 0x38, 0x3D, 0x3E, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2F, 0x2C, 0x29, 0x2A,
|
||||
0x0B, 0x08, 0x0D, 0x0E, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1F, 0x1C, 0x19, 0x1A
|
||||
};
|
||||
|
||||
const uint8_t accelc_aes_InverseSBox[256] = {
|
||||
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
|
||||
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
|
||||
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
|
||||
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
|
||||
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
|
||||
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
|
||||
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
|
||||
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
|
||||
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
|
||||
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
|
||||
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
|
||||
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
|
||||
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
|
||||
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
|
||||
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
|
||||
};
|
||||
|
||||
const uint8_t accelc_aes_GF2p8_Mul_0x09[256] = {
|
||||
0x00, 0x09, 0x12, 0x1B, 0x24, 0x2D, 0x36, 0x3F, 0x48, 0x41, 0x5A, 0x53, 0x6C, 0x65, 0x7E, 0x77,
|
||||
0x90, 0x99, 0x82, 0x8B, 0xB4, 0xBD, 0xA6, 0xAF, 0xD8, 0xD1, 0xCA, 0xC3, 0xFC, 0xF5, 0xEE, 0xE7,
|
||||
0x3B, 0x32, 0x29, 0x20, 0x1F, 0x16, 0x0D, 0x04, 0x73, 0x7A, 0x61, 0x68, 0x57, 0x5E, 0x45, 0x4C,
|
||||
0xAB, 0xA2, 0xB9, 0xB0, 0x8F, 0x86, 0x9D, 0x94, 0xE3, 0xEA, 0xF1, 0xF8, 0xC7, 0xCE, 0xD5, 0xDC,
|
||||
0x76, 0x7F, 0x64, 0x6D, 0x52, 0x5B, 0x40, 0x49, 0x3E, 0x37, 0x2C, 0x25, 0x1A, 0x13, 0x08, 0x01,
|
||||
0xE6, 0xEF, 0xF4, 0xFD, 0xC2, 0xCB, 0xD0, 0xD9, 0xAE, 0xA7, 0xBC, 0xB5, 0x8A, 0x83, 0x98, 0x91,
|
||||
0x4D, 0x44, 0x5F, 0x56, 0x69, 0x60, 0x7B, 0x72, 0x05, 0x0C, 0x17, 0x1E, 0x21, 0x28, 0x33, 0x3A,
|
||||
0xDD, 0xD4, 0xCF, 0xC6, 0xF9, 0xF0, 0xEB, 0xE2, 0x95, 0x9C, 0x87, 0x8E, 0xB1, 0xB8, 0xA3, 0xAA,
|
||||
0xEC, 0xE5, 0xFE, 0xF7, 0xC8, 0xC1, 0xDA, 0xD3, 0xA4, 0xAD, 0xB6, 0xBF, 0x80, 0x89, 0x92, 0x9B,
|
||||
0x7C, 0x75, 0x6E, 0x67, 0x58, 0x51, 0x4A, 0x43, 0x34, 0x3D, 0x26, 0x2F, 0x10, 0x19, 0x02, 0x0B,
|
||||
0xD7, 0xDE, 0xC5, 0xCC, 0xF3, 0xFA, 0xE1, 0xE8, 0x9F, 0x96, 0x8D, 0x84, 0xBB, 0xB2, 0xA9, 0xA0,
|
||||
0x47, 0x4E, 0x55, 0x5C, 0x63, 0x6A, 0x71, 0x78, 0x0F, 0x06, 0x1D, 0x14, 0x2B, 0x22, 0x39, 0x30,
|
||||
0x9A, 0x93, 0x88, 0x81, 0xBE, 0xB7, 0xAC, 0xA5, 0xD2, 0xDB, 0xC0, 0xC9, 0xF6, 0xFF, 0xE4, 0xED,
|
||||
0x0A, 0x03, 0x18, 0x11, 0x2E, 0x27, 0x3C, 0x35, 0x42, 0x4B, 0x50, 0x59, 0x66, 0x6F, 0x74, 0x7D,
|
||||
0xA1, 0xA8, 0xB3, 0xBA, 0x85, 0x8C, 0x97, 0x9E, 0xE9, 0xE0, 0xFB, 0xF2, 0xCD, 0xC4, 0xDF, 0xD6,
|
||||
0x31, 0x38, 0x23, 0x2A, 0x15, 0x1C, 0x07, 0x0E, 0x79, 0x70, 0x6B, 0x62, 0x5D, 0x54, 0x4F, 0x46
|
||||
};
|
||||
|
||||
const uint8_t accelc_aes_GF2p8_Mul_0x0B[256] = {
|
||||
0x00, 0x0B, 0x16, 0x1D, 0x2C, 0x27, 0x3A, 0x31, 0x58, 0x53, 0x4E, 0x45, 0x74, 0x7F, 0x62, 0x69,
|
||||
0xB0, 0xBB, 0xA6, 0xAD, 0x9C, 0x97, 0x8A, 0x81, 0xE8, 0xE3, 0xFE, 0xF5, 0xC4, 0xCF, 0xD2, 0xD9,
|
||||
0x7B, 0x70, 0x6D, 0x66, 0x57, 0x5C, 0x41, 0x4A, 0x23, 0x28, 0x35, 0x3E, 0x0F, 0x04, 0x19, 0x12,
|
||||
0xCB, 0xC0, 0xDD, 0xD6, 0xE7, 0xEC, 0xF1, 0xFA, 0x93, 0x98, 0x85, 0x8E, 0xBF, 0xB4, 0xA9, 0xA2,
|
||||
0xF6, 0xFD, 0xE0, 0xEB, 0xDA, 0xD1, 0xCC, 0xC7, 0xAE, 0xA5, 0xB8, 0xB3, 0x82, 0x89, 0x94, 0x9F,
|
||||
0x46, 0x4D, 0x50, 0x5B, 0x6A, 0x61, 0x7C, 0x77, 0x1E, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2F,
|
||||
0x8D, 0x86, 0x9B, 0x90, 0xA1, 0xAA, 0xB7, 0xBC, 0xD5, 0xDE, 0xC3, 0xC8, 0xF9, 0xF2, 0xEF, 0xE4,
|
||||
0x3D, 0x36, 0x2B, 0x20, 0x11, 0x1A, 0x07, 0x0C, 0x65, 0x6E, 0x73, 0x78, 0x49, 0x42, 0x5F, 0x54,
|
||||
0xF7, 0xFC, 0xE1, 0xEA, 0xDB, 0xD0, 0xCD, 0xC6, 0xAF, 0xA4, 0xB9, 0xB2, 0x83, 0x88, 0x95, 0x9E,
|
||||
0x47, 0x4C, 0x51, 0x5A, 0x6B, 0x60, 0x7D, 0x76, 0x1F, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2E,
|
||||
0x8C, 0x87, 0x9A, 0x91, 0xA0, 0xAB, 0xB6, 0xBD, 0xD4, 0xDF, 0xC2, 0xC9, 0xF8, 0xF3, 0xEE, 0xE5,
|
||||
0x3C, 0x37, 0x2A, 0x21, 0x10, 0x1B, 0x06, 0x0D, 0x64, 0x6F, 0x72, 0x79, 0x48, 0x43, 0x5E, 0x55,
|
||||
0x01, 0x0A, 0x17, 0x1C, 0x2D, 0x26, 0x3B, 0x30, 0x59, 0x52, 0x4F, 0x44, 0x75, 0x7E, 0x63, 0x68,
|
||||
0xB1, 0xBA, 0xA7, 0xAC, 0x9D, 0x96, 0x8B, 0x80, 0xE9, 0xE2, 0xFF, 0xF4, 0xC5, 0xCE, 0xD3, 0xD8,
|
||||
0x7A, 0x71, 0x6C, 0x67, 0x56, 0x5D, 0x40, 0x4B, 0x22, 0x29, 0x34, 0x3F, 0x0E, 0x05, 0x18, 0x13,
|
||||
0xCA, 0xC1, 0xDC, 0xD7, 0xE6, 0xED, 0xF0, 0xFB, 0x92, 0x99, 0x84, 0x8F, 0xBE, 0xB5, 0xA8, 0xA3
|
||||
};
|
||||
|
||||
const uint8_t accelc_aes_GF2p8_Mul_0x0D[256] = {
|
||||
0x00, 0x0D, 0x1A, 0x17, 0x34, 0x39, 0x2E, 0x23, 0x68, 0x65, 0x72, 0x7F, 0x5C, 0x51, 0x46, 0x4B,
|
||||
0xD0, 0xDD, 0xCA, 0xC7, 0xE4, 0xE9, 0xFE, 0xF3, 0xB8, 0xB5, 0xA2, 0xAF, 0x8C, 0x81, 0x96, 0x9B,
|
||||
0xBB, 0xB6, 0xA1, 0xAC, 0x8F, 0x82, 0x95, 0x98, 0xD3, 0xDE, 0xC9, 0xC4, 0xE7, 0xEA, 0xFD, 0xF0,
|
||||
0x6B, 0x66, 0x71, 0x7C, 0x5F, 0x52, 0x45, 0x48, 0x03, 0x0E, 0x19, 0x14, 0x37, 0x3A, 0x2D, 0x20,
|
||||
0x6D, 0x60, 0x77, 0x7A, 0x59, 0x54, 0x43, 0x4E, 0x05, 0x08, 0x1F, 0x12, 0x31, 0x3C, 0x2B, 0x26,
|
||||
0xBD, 0xB0, 0xA7, 0xAA, 0x89, 0x84, 0x93, 0x9E, 0xD5, 0xD8, 0xCF, 0xC2, 0xE1, 0xEC, 0xFB, 0xF6,
|
||||
0xD6, 0xDB, 0xCC, 0xC1, 0xE2, 0xEF, 0xF8, 0xF5, 0xBE, 0xB3, 0xA4, 0xA9, 0x8A, 0x87, 0x90, 0x9D,
|
||||
0x06, 0x0B, 0x1C, 0x11, 0x32, 0x3F, 0x28, 0x25, 0x6E, 0x63, 0x74, 0x79, 0x5A, 0x57, 0x40, 0x4D,
|
||||
0xDA, 0xD7, 0xC0, 0xCD, 0xEE, 0xE3, 0xF4, 0xF9, 0xB2, 0xBF, 0xA8, 0xA5, 0x86, 0x8B, 0x9C, 0x91,
|
||||
0x0A, 0x07, 0x10, 0x1D, 0x3E, 0x33, 0x24, 0x29, 0x62, 0x6F, 0x78, 0x75, 0x56, 0x5B, 0x4C, 0x41,
|
||||
0x61, 0x6C, 0x7B, 0x76, 0x55, 0x58, 0x4F, 0x42, 0x09, 0x04, 0x13, 0x1E, 0x3D, 0x30, 0x27, 0x2A,
|
||||
0xB1, 0xBC, 0xAB, 0xA6, 0x85, 0x88, 0x9F, 0x92, 0xD9, 0xD4, 0xC3, 0xCE, 0xED, 0xE0, 0xF7, 0xFA,
|
||||
0xB7, 0xBA, 0xAD, 0xA0, 0x83, 0x8E, 0x99, 0x94, 0xDF, 0xD2, 0xC5, 0xC8, 0xEB, 0xE6, 0xF1, 0xFC,
|
||||
0x67, 0x6A, 0x7D, 0x70, 0x53, 0x5E, 0x49, 0x44, 0x0F, 0x02, 0x15, 0x18, 0x3B, 0x36, 0x21, 0x2C,
|
||||
0x0C, 0x01, 0x16, 0x1B, 0x38, 0x35, 0x22, 0x2F, 0x64, 0x69, 0x7E, 0x73, 0x50, 0x5D, 0x4A, 0x47,
|
||||
0xDC, 0xD1, 0xC6, 0xCB, 0xE8, 0xE5, 0xF2, 0xFF, 0xB4, 0xB9, 0xAE, 0xA3, 0x80, 0x8D, 0x9A, 0x97
|
||||
};
|
||||
|
||||
const uint8_t accelc_aes_GF2p8_Mul_0x0E[256] = {
|
||||
0x00, 0x0E, 0x1C, 0x12, 0x38, 0x36, 0x24, 0x2A, 0x70, 0x7E, 0x6C, 0x62, 0x48, 0x46, 0x54, 0x5A,
|
||||
0xE0, 0xEE, 0xFC, 0xF2, 0xD8, 0xD6, 0xC4, 0xCA, 0x90, 0x9E, 0x8C, 0x82, 0xA8, 0xA6, 0xB4, 0xBA,
|
||||
0xDB, 0xD5, 0xC7, 0xC9, 0xE3, 0xED, 0xFF, 0xF1, 0xAB, 0xA5, 0xB7, 0xB9, 0x93, 0x9D, 0x8F, 0x81,
|
||||
0x3B, 0x35, 0x27, 0x29, 0x03, 0x0D, 0x1F, 0x11, 0x4B, 0x45, 0x57, 0x59, 0x73, 0x7D, 0x6F, 0x61,
|
||||
0xAD, 0xA3, 0xB1, 0xBF, 0x95, 0x9B, 0x89, 0x87, 0xDD, 0xD3, 0xC1, 0xCF, 0xE5, 0xEB, 0xF9, 0xF7,
|
||||
0x4D, 0x43, 0x51, 0x5F, 0x75, 0x7B, 0x69, 0x67, 0x3D, 0x33, 0x21, 0x2F, 0x05, 0x0B, 0x19, 0x17,
|
||||
0x76, 0x78, 0x6A, 0x64, 0x4E, 0x40, 0x52, 0x5C, 0x06, 0x08, 0x1A, 0x14, 0x3E, 0x30, 0x22, 0x2C,
|
||||
0x96, 0x98, 0x8A, 0x84, 0xAE, 0xA0, 0xB2, 0xBC, 0xE6, 0xE8, 0xFA, 0xF4, 0xDE, 0xD0, 0xC2, 0xCC,
|
||||
0x41, 0x4F, 0x5D, 0x53, 0x79, 0x77, 0x65, 0x6B, 0x31, 0x3F, 0x2D, 0x23, 0x09, 0x07, 0x15, 0x1B,
|
||||
0xA1, 0xAF, 0xBD, 0xB3, 0x99, 0x97, 0x85, 0x8B, 0xD1, 0xDF, 0xCD, 0xC3, 0xE9, 0xE7, 0xF5, 0xFB,
|
||||
0x9A, 0x94, 0x86, 0x88, 0xA2, 0xAC, 0xBE, 0xB0, 0xEA, 0xE4, 0xF6, 0xF8, 0xD2, 0xDC, 0xCE, 0xC0,
|
||||
0x7A, 0x74, 0x66, 0x68, 0x42, 0x4C, 0x5E, 0x50, 0x0A, 0x04, 0x16, 0x18, 0x32, 0x3C, 0x2E, 0x20,
|
||||
0xEC, 0xE2, 0xF0, 0xFE, 0xD4, 0xDA, 0xC8, 0xC6, 0x9C, 0x92, 0x80, 0x8E, 0xA4, 0xAA, 0xB8, 0xB6,
|
||||
0x0C, 0x02, 0x10, 0x1E, 0x34, 0x3A, 0x28, 0x26, 0x7C, 0x72, 0x60, 0x6E, 0x44, 0x4A, 0x58, 0x56,
|
||||
0x37, 0x39, 0x2B, 0x25, 0x0F, 0x01, 0x13, 0x1D, 0x47, 0x49, 0x5B, 0x55, 0x7F, 0x71, 0x63, 0x6D,
|
||||
0xD7, 0xD9, 0xCB, 0xC5, 0xEF, 0xE1, 0xF3, 0xFD, 0xA7, 0xA9, 0xBB, 0xB5, 0x9F, 0x91, 0x83, 0x8D
|
||||
};
|
||||
@ -1,281 +0,0 @@
|
||||
#include "blowfish.h"
|
||||
#include <memory.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#define _bswap _byteswap_ulong
|
||||
#elif defined(__GNUC__)
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
const uint32_t accelc_Blowfish_Original_PBox[18] = {
|
||||
0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0,
|
||||
0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
|
||||
0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, 0x9216D5D9, 0x8979FB1B
|
||||
};
|
||||
|
||||
const uint32_t accelc_Blowfish_Original_SBox[4][256] = {
|
||||
{
|
||||
0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E,
|
||||
0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E,
|
||||
0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A,
|
||||
0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032,
|
||||
0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0,
|
||||
0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE,
|
||||
0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7,
|
||||
0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09,
|
||||
0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,
|
||||
0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573,
|
||||
0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8,
|
||||
0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C,
|
||||
0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9,
|
||||
0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF,
|
||||
0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915,
|
||||
0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A
|
||||
},
|
||||
|
||||
{
|
||||
0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E,
|
||||
0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1,
|
||||
0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD,
|
||||
0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331,
|
||||
0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87,
|
||||
0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD,
|
||||
0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3,
|
||||
0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960,
|
||||
0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,
|
||||
0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E,
|
||||
0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281,
|
||||
0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73,
|
||||
0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250,
|
||||
0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061,
|
||||
0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC,
|
||||
0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7
|
||||
},
|
||||
|
||||
{
|
||||
0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840,
|
||||
0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB,
|
||||
0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B,
|
||||
0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B,
|
||||
0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC,
|
||||
0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115,
|
||||
0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E,
|
||||
0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B,
|
||||
0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,
|
||||
0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE,
|
||||
0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61,
|
||||
0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C,
|
||||
0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169,
|
||||
0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62,
|
||||
0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC,
|
||||
0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0
|
||||
},
|
||||
|
||||
{
|
||||
0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4,
|
||||
0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22,
|
||||
0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59,
|
||||
0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C,
|
||||
0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD,
|
||||
0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F,
|
||||
0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166,
|
||||
0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47,
|
||||
0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,
|
||||
0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7,
|
||||
0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525,
|
||||
0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E,
|
||||
0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299,
|
||||
0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A,
|
||||
0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060,
|
||||
0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6
|
||||
}
|
||||
};
|
||||
|
||||
#define f_transform(_x, _S) ((((_S)[0][(_x)[3]] + (_S)[1][(_x)[2]]) ^ (_S)[2][(_x)[1]]) + (_S)[3][(_x)[0]])
|
||||
|
||||
void accelc_Blowfish_encrypt(uint8_t srcBytes[8],
|
||||
const BLOWFISH_KEY* srcKey,
|
||||
int Endian) {
|
||||
uint32_t* const L = (uint32_t*)srcBytes;
|
||||
uint32_t* const R = (uint32_t*)(srcBytes + 4);
|
||||
|
||||
if (Endian == BLOWFISH_BIG_ENDIAN) {
|
||||
*L = _bswap(*L);
|
||||
*R = _bswap(*R);
|
||||
}
|
||||
|
||||
*L ^= srcKey->SubKey[0];
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
|
||||
*R ^= srcKey->SubKey[1];
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
|
||||
*L ^= srcKey->SubKey[2];
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
|
||||
*R ^= srcKey->SubKey[3];
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
|
||||
*L ^= srcKey->SubKey[4];
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
|
||||
*R ^= srcKey->SubKey[5];
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
|
||||
*L ^= srcKey->SubKey[6];
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
|
||||
*R ^= srcKey->SubKey[7];
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
|
||||
*L ^= srcKey->SubKey[8];
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
|
||||
*R ^= srcKey->SubKey[9];
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
|
||||
*L ^= srcKey->SubKey[10];
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
|
||||
*R ^= srcKey->SubKey[11];
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
|
||||
*L ^= srcKey->SubKey[12];
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
|
||||
*R ^= srcKey->SubKey[13];
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
|
||||
*L ^= srcKey->SubKey[14];
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
|
||||
*R ^= srcKey->SubKey[15];
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
|
||||
*L ^= srcKey->SubKey[16];
|
||||
*R ^= srcKey->SubKey[17];
|
||||
|
||||
uint32_t temp = *R;
|
||||
*R = *L;
|
||||
*L = temp;
|
||||
|
||||
if (Endian == BLOWFISH_BIG_ENDIAN) {
|
||||
*L = _bswap(*L);
|
||||
*R = _bswap(*R);
|
||||
}
|
||||
}
|
||||
|
||||
void accelc_Blowfish_decrypt(uint8_t srcBytes[8],
|
||||
const BLOWFISH_KEY* srcKey,
|
||||
int Endian) {
|
||||
uint32_t* const L = (uint32_t*)srcBytes;
|
||||
uint32_t* const R = (uint32_t*)(srcBytes + 4);
|
||||
|
||||
if (Endian == BLOWFISH_BIG_ENDIAN) {
|
||||
*L = _bswap(*L);
|
||||
*R = _bswap(*R);
|
||||
}
|
||||
|
||||
uint32_t temp = *R;
|
||||
*R = *L;
|
||||
*L = temp;
|
||||
|
||||
*L ^= srcKey->SubKey[16];
|
||||
*R ^= srcKey->SubKey[17];
|
||||
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
*R ^= srcKey->SubKey[15];
|
||||
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
*L ^= srcKey->SubKey[14];
|
||||
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
*R ^= srcKey->SubKey[13];
|
||||
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
*L ^= srcKey->SubKey[12];
|
||||
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
*R ^= srcKey->SubKey[11];
|
||||
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
*L ^= srcKey->SubKey[10];
|
||||
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
*R ^= srcKey->SubKey[9];
|
||||
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
*L ^= srcKey->SubKey[8];
|
||||
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
*R ^= srcKey->SubKey[7];
|
||||
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
*L ^= srcKey->SubKey[6];
|
||||
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
*R ^= srcKey->SubKey[5];
|
||||
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
*L ^= srcKey->SubKey[4];
|
||||
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
*R ^= srcKey->SubKey[3];
|
||||
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
*L ^= srcKey->SubKey[2];
|
||||
|
||||
*L ^= f_transform(srcBytes + 4, srcKey->SBox);
|
||||
*R ^= srcKey->SubKey[1];
|
||||
|
||||
*R ^= f_transform(srcBytes, srcKey->SBox);
|
||||
*L ^= srcKey->SubKey[0];
|
||||
|
||||
if (Endian == BLOWFISH_BIG_ENDIAN) {
|
||||
*L = _bswap(*L);
|
||||
*R = _bswap(*R);
|
||||
}
|
||||
}
|
||||
|
||||
int accelc_Blowfish_set_key(const uint8_t srcUserKey[], uint8_t UserKeyLength,
|
||||
BLOWFISH_KEY* dstKey) {
|
||||
if (UserKeyLength == 0)
|
||||
return STATUS_BLOWFISH_INVALID_KEY_LENGTH;
|
||||
if (UserKeyLength > BLOWFISH_MAX_KEY_LENGTH)
|
||||
return STATUS_BLOWFISH_KEY_TOO_LONG;
|
||||
|
||||
memcpy(dstKey->SubKey, accelc_Blowfish_Original_PBox, sizeof(accelc_Blowfish_Original_PBox));
|
||||
memcpy(dstKey->SBox, accelc_Blowfish_Original_SBox, sizeof(accelc_Blowfish_Original_SBox));
|
||||
|
||||
for (int i = 0; i < 18; ++i) {
|
||||
uint32_t temp = 0;
|
||||
|
||||
temp <<= 8;
|
||||
temp |= srcUserKey[(i * 4) % UserKeyLength];
|
||||
|
||||
temp <<= 8;
|
||||
temp |= srcUserKey[(i * 4 + 1) % UserKeyLength];
|
||||
|
||||
temp <<= 8;
|
||||
temp |= srcUserKey[(i * 4 + 2) % UserKeyLength];
|
||||
|
||||
temp <<= 8;
|
||||
temp |= srcUserKey[(i * 4 + 3) % UserKeyLength];
|
||||
|
||||
dstKey->SubKey[i] ^= temp;
|
||||
}
|
||||
|
||||
uint8_t temp[8] = { 0 };
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
accelc_Blowfish_encrypt(temp, dstKey, BLOWFISH_LITTLE_ENDIAN);
|
||||
((uint64_t*)dstKey->SubKey)[i] = *(uint64_t*)temp;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 512; ++i) {
|
||||
accelc_Blowfish_encrypt(temp, dstKey, BLOWFISH_LITTLE_ENDIAN);
|
||||
((uint64_t*)dstKey->SBox)[i] = *(uint64_t*)temp;
|
||||
}
|
||||
|
||||
return STATUS_BLOWFISH_SUCCESS;
|
||||
}
|
||||
@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define STATUS_BLOWFISH_SUCCESS 0
|
||||
#define STATUS_BLOWFISH_INVALID_KEY_LENGTH (-1)
|
||||
#define STATUS_BLOWFISH_KEY_TOO_LONG (-2)
|
||||
|
||||
#define BLOWFISH_LITTLE_ENDIAN 0
|
||||
#define BLOWFISH_BIG_ENDIAN 1
|
||||
|
||||
#define BLOWFISH_MIN_KEY_LENGTH 1
|
||||
#define BLOWFISH_MAX_KEY_LENGTH 56
|
||||
|
||||
#define BLOWFISH_BLOCK_SIZE 8
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct _BLOWFISH_KEY {
|
||||
uint32_t SubKey[18];
|
||||
uint32_t SBox[4][256];
|
||||
} BLOWFISH_KEY;
|
||||
|
||||
void accelc_Blowfish_encrypt(uint8_t srcBytes[8],
|
||||
const BLOWFISH_KEY* srcKey,
|
||||
int Endian);
|
||||
|
||||
void accelc_Blowfish_decrypt(uint8_t srcBytes[8],
|
||||
const BLOWFISH_KEY* srcKey,
|
||||
int Endian);
|
||||
|
||||
int accelc_Blowfish_set_key(const uint8_t srcUserKey[], uint8_t UserKeyLength,
|
||||
BLOWFISH_KEY* dstKey);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@ -1,120 +0,0 @@
|
||||
#include "sha1.h"
|
||||
#include <memory.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#define _bswap _byteswap_ulong
|
||||
#define _bswap64 _byteswap_uint64
|
||||
#elif defined(__GNUC__)
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
#define SHA1_BLOCKSIZE 64
|
||||
|
||||
void accelc_SHA1_init(SHA1_BUFFER* HashBuffer) {
|
||||
HashBuffer->dword[0] = 0x67452301;
|
||||
HashBuffer->dword[1] = 0xEFCDAB89;
|
||||
HashBuffer->dword[2] = 0x98BADCFE;
|
||||
HashBuffer->dword[3] = 0x10325476;
|
||||
HashBuffer->dword[4] = 0xC3D2E1F0;
|
||||
}
|
||||
|
||||
void accelc_SHA1_update(const void* __restrict srcBytes, size_t srcBytesLength,
|
||||
SHA1_BUFFER* __restrict HashBuffer) {
|
||||
uint32_t Buffer[80] = { 0 };
|
||||
uint32_t a, b, c, d, e;
|
||||
const uint32_t (*MessageBlock)[16] = srcBytes;
|
||||
|
||||
size_t RoundsOfMainCycle = srcBytesLength / SHA1_BLOCKSIZE;
|
||||
for (size_t i = 0; i < RoundsOfMainCycle; ++i) {
|
||||
|
||||
for (int j = 0; j < 16; ++j)
|
||||
Buffer[j] = _bswap(MessageBlock[i][j]);
|
||||
|
||||
for (int j = 16; j < 80; ++j) {
|
||||
uint32_t temp = Buffer[j - 3] ^ Buffer[j - 8] ^ Buffer[j - 14] ^ Buffer[j - 16];
|
||||
Buffer[j] = _rotl(temp, 1);
|
||||
}
|
||||
a = HashBuffer->dword[0];
|
||||
b = HashBuffer->dword[1];
|
||||
c = HashBuffer->dword[2];
|
||||
d = HashBuffer->dword[3];
|
||||
e = HashBuffer->dword[4];
|
||||
|
||||
for (int j = 0; j < 20; ++j) {
|
||||
uint32_t T = _rotl(a, 5);
|
||||
T += ((b & c) ^ (~b & d)) + e + 0x5A827999 + Buffer[j];
|
||||
e = d;
|
||||
d = c;
|
||||
c = _rotl(b, 30);
|
||||
b = a;
|
||||
a = T;
|
||||
}
|
||||
for (int j = 20; j < 40; ++j) {
|
||||
uint32_t T = _rotl(a, 5);
|
||||
T += (b ^ c ^ d) + e + 0x6ED9EBA1 + Buffer[j];
|
||||
e = d;
|
||||
d = c;
|
||||
c = _rotl(b, 30);
|
||||
b = a;
|
||||
a = T;
|
||||
}
|
||||
for (int j = 40; j < 60; ++j) {
|
||||
uint32_t T = _rotl(a, 5);
|
||||
T += ((b & c) ^ (b & d) ^ (c & d)) + e + 0x8F1BBCDC + Buffer[j];
|
||||
e = d;
|
||||
d = c;
|
||||
c = _rotl(b, 30);
|
||||
b = a;
|
||||
a = T;
|
||||
}
|
||||
for (int j = 60; j < 80; ++j) {
|
||||
uint32_t T = _rotl(a, 5);
|
||||
T += (b ^ c ^ d) + e + 0xCA62C1D6 + Buffer[j];
|
||||
e = d;
|
||||
d = c;
|
||||
c = _rotl(b, 30);
|
||||
b = a;
|
||||
a = T;
|
||||
}
|
||||
HashBuffer->dword[0] += a;
|
||||
HashBuffer->dword[1] += b;
|
||||
HashBuffer->dword[2] += c;
|
||||
HashBuffer->dword[3] += d;
|
||||
HashBuffer->dword[4] += e;
|
||||
}
|
||||
}
|
||||
|
||||
void accelc_SHA1_final(const void* __restrict LeftBytes, size_t LeftBytesLength, uint64_t TotalBytesLength,
|
||||
const SHA1_BUFFER* HashBuffer, SHA1_DIGEST* Hash) {
|
||||
if (HashBuffer != Hash)
|
||||
memcpy(Hash, HashBuffer, sizeof(SHA1_BUFFER));
|
||||
|
||||
if (LeftBytesLength >= SHA1_BLOCKSIZE) {
|
||||
accelc_SHA1_update(LeftBytes, LeftBytesLength, Hash);
|
||||
LeftBytes = (const uint8_t*)LeftBytes + (LeftBytesLength / SHA1_BLOCKSIZE) * SHA1_BLOCKSIZE;
|
||||
LeftBytesLength %= SHA1_BLOCKSIZE;
|
||||
}
|
||||
|
||||
uint8_t Extra[128] = { 0 };
|
||||
for (size_t i = 0; i < LeftBytesLength; ++i)
|
||||
Extra[i] = ((const uint8_t*)LeftBytes)[i];
|
||||
|
||||
Extra[LeftBytesLength] = 0x80;
|
||||
*(uint64_t*)(Extra + (LeftBytesLength >= 64 - 8 ? 128 - 8 : 64 - 8)) = _bswap64(TotalBytesLength * 8);
|
||||
|
||||
accelc_SHA1_update(Extra, LeftBytesLength >= 56 ? 128 : 64, Hash);
|
||||
|
||||
Hash->dword[0] = _bswap(Hash->dword[0]);
|
||||
Hash->dword[1] = _bswap(Hash->dword[1]);
|
||||
Hash->dword[2] = _bswap(Hash->dword[2]);
|
||||
Hash->dword[3] = _bswap(Hash->dword[3]);
|
||||
Hash->dword[4] = _bswap(Hash->dword[4]);
|
||||
}
|
||||
|
||||
void accelc_SHA1(const void* __restrict srcBytes, size_t srclen,
|
||||
SHA1_DIGEST* __restrict Hash) {
|
||||
accelc_SHA1_init(Hash);
|
||||
accelc_SHA1_update(srcBytes, srclen, Hash);
|
||||
accelc_SHA1_final((uint8_t*)srcBytes + (srclen / SHA1_BLOCKSIZE) * SHA1_BLOCKSIZE, srclen % SHA1_BLOCKSIZE, srclen, Hash, Hash);
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct _SHA1_DIGEST {
|
||||
union {
|
||||
uint8_t byte[20];
|
||||
uint32_t dword[5];
|
||||
};
|
||||
} SHA1_DIGEST, SHA1_BUFFER;
|
||||
|
||||
void accelc_SHA1_init(SHA1_BUFFER* HashBuffer);
|
||||
|
||||
void accelc_SHA1_update(const void* __restrict srcBytes, size_t srcBytesLength,
|
||||
SHA1_BUFFER* __restrict HashBuffer);
|
||||
|
||||
void accelc_SHA1_final(const void* __restrict LeftBytes, size_t LeftBytesLength, uint64_t TotalBytesLength,
|
||||
const SHA1_BUFFER* HashBuffer, SHA1_DIGEST* Hash);
|
||||
|
||||
void accelc_SHA1(const void* __restrict srcBytes, size_t srclen,
|
||||
SHA1_DIGEST* __restrict Hash);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@ -1,59 +0,0 @@
|
||||
#include "def.hpp"
|
||||
|
||||
// Solution0 is for navicat premium of which the version < 12.0.25
|
||||
namespace patcher::Solution0 {
|
||||
|
||||
BOOL Do(LPCTSTR navicat_exe_path, LPCTSTR prepared_key_file) {
|
||||
if (!BackupFile(navicat_exe_path))
|
||||
return FALSE;
|
||||
|
||||
RSA* PrivateKey = nullptr;
|
||||
if (prepared_key_file == nullptr) {
|
||||
PrivateKey = GenerateRSAKey();
|
||||
if (PrivateKey == nullptr)
|
||||
return FALSE;
|
||||
|
||||
if (!WriteRSAPrivateKeyToFile(TEXT("RegPrivateKey.pem"), PrivateKey)) {
|
||||
RSA_free(PrivateKey);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
PrivateKey = ReadRSAPrivateKeyFromFile(prepared_key_file);
|
||||
if (PrivateKey == nullptr)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
char* pem_pubkey = GetPEMText(PrivateKey);
|
||||
if (pem_pubkey == nullptr)
|
||||
return FALSE;
|
||||
|
||||
RSA_free(PrivateKey); // we do not need it anymore
|
||||
|
||||
HANDLE hUpdater = BeginUpdateResource(navicat_exe_path, FALSE);
|
||||
if (hUpdater == NULL) {
|
||||
_tprintf_s(TEXT("Cannot modify navicat.exe. CODE: 0x%08x @[patcher::Solution0::Do -> BeginUpdateResource]\r\n"), GetLastError());
|
||||
|
||||
delete[] pem_pubkey;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!UpdateResource(hUpdater,
|
||||
RT_RCDATA,
|
||||
TEXT("ACTIVATIONPUBKEY"),
|
||||
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
|
||||
pem_pubkey, strlen(pem_pubkey))) {
|
||||
_tprintf_s(TEXT("Cannot replace public key. CODE: 0x%08x @[patcher::Solution0::Do -> UpdateResource]\r\n"), GetLastError());
|
||||
|
||||
EndUpdateResource(hUpdater, TRUE);
|
||||
delete[] pem_pubkey;
|
||||
return FALSE;
|
||||
} else {
|
||||
_tprintf_s(TEXT("@[patcher::Solution0::Do]: Public key has been replaced by:\r\n%hs"), pem_pubkey);
|
||||
|
||||
EndUpdateResource(hUpdater, FALSE);
|
||||
delete[] pem_pubkey;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,436 +0,0 @@
|
||||
#include "def.hpp"
|
||||
|
||||
// Solution1 is for navicat premium of which the version = 12.0.25
|
||||
namespace patcher::Solution1 {
|
||||
|
||||
static BOOL CheckRSAKeyIsAppropriate(RSA* PrivateKey) {
|
||||
char* pem_pubkey = GetPEMText(PrivateKey);
|
||||
if (pem_pubkey == nullptr)
|
||||
return FALSE;
|
||||
|
||||
std::string encrypted_pem_text = EncryptPublicKey(pem_pubkey, strlen(pem_pubkey));
|
||||
delete[] pem_pubkey;
|
||||
|
||||
if (encrypted_pem_text[160] > '9' || encrypted_pem_text[160] < '1')
|
||||
return FALSE;
|
||||
for (int i = 1; i < 8; ++i)
|
||||
if (encrypted_pem_text[160 + i] > '9' || encrypted_pem_text[160 + i] < '0')
|
||||
return FALSE;
|
||||
|
||||
if (encrypted_pem_text[910] > '9' || encrypted_pem_text[910] < '1')
|
||||
return FALSE;
|
||||
for (int i = 1; i < 5; ++i)
|
||||
if (encrypted_pem_text[910 + i] > '9' || encrypted_pem_text[910 + i] < '0')
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static RSA* GenerateAppropriateRSAKey() {
|
||||
while (true) {
|
||||
RSA* Key = GenerateRSAKey();
|
||||
if (Key == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if (CheckRSAKeyIsAppropriate(Key)) {
|
||||
return Key;
|
||||
} else {
|
||||
RSA_free(Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL FindPatchOffset(LPCTSTR libcc_dll_path, DWORD Offset[5]) {
|
||||
Offset[0] = 0;
|
||||
Offset[1] = 0;
|
||||
Offset[2] = 0;
|
||||
Offset[3] = 0;
|
||||
Offset[4] = 0;
|
||||
|
||||
HANDLE h_libcc = CreateFile(libcc_dll_path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (h_libcc == INVALID_HANDLE_VALUE) {
|
||||
_tprintf_s(TEXT("Failed to open libcc.dll. CODE: 0x%08x @[FindPatchOffset -> CreateFile]\r\n"), GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// DWORD is enough, you know libcc.dll cannot be larger than 4GB
|
||||
DWORD libcc_size = GetFileSize(h_libcc, nullptr);
|
||||
HANDLE h_libcc_map = CreateFileMapping(h_libcc, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
if (h_libcc_map == NULL) {
|
||||
_tprintf_s(TEXT("Failed to create mapping for libcc.dll. CODE: 0x%08x @[FindPatchOffset -> CreateFileMapping]\r\n"), GetLastError());
|
||||
CloseHandle(h_libcc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const uint8_t* libcc = reinterpret_cast<const uint8_t*>(MapViewOfFile(h_libcc_map, FILE_MAP_READ, 0, 0, 0));
|
||||
if (libcc == nullptr) {
|
||||
_tprintf_s(TEXT("Failed to map libcc.dll. CODE: 0x%08x @[FindPatchOffset -> MapViewOfFile]\r\n"), GetLastError());
|
||||
CloseHandle(h_libcc_map);
|
||||
CloseHandle(h_libcc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const IMAGE_DOS_HEADER* libcc_dos_header = reinterpret_cast<const IMAGE_DOS_HEADER*>(libcc);
|
||||
|
||||
// check dos signature
|
||||
if (libcc_dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
_tprintf_s(TEXT("libcc.dll does not have a valid DOS header. @[FindPatchOffset]\r\n"));
|
||||
UnmapViewOfFile(libcc);
|
||||
CloseHandle(h_libcc_map);
|
||||
CloseHandle(h_libcc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const IMAGE_NT_HEADERS* libcc_nt_header = reinterpret_cast<const IMAGE_NT_HEADERS*>(libcc + libcc_dos_header->e_lfanew);
|
||||
|
||||
// check nt signature
|
||||
if (libcc_nt_header->Signature != IMAGE_NT_SIGNATURE) {
|
||||
_tprintf_s(TEXT("libcc.dll does not have a valid NT header. @[FindPatchOffset]\r\n"));
|
||||
UnmapViewOfFile(libcc);
|
||||
CloseHandle(h_libcc_map);
|
||||
CloseHandle(h_libcc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// check if a dll
|
||||
if ((libcc_nt_header->FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) {
|
||||
_tprintf_s(TEXT("libcc.dll is not a DLL file. @[FindPatchOffset]\r\n"));
|
||||
UnmapViewOfFile(libcc);
|
||||
CloseHandle(h_libcc_map);
|
||||
CloseHandle(h_libcc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// check if 32-bits or 64-bits
|
||||
#if defined(_M_X64)
|
||||
if (libcc_nt_header->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 || libcc_nt_header->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
||||
_tprintf_s(TEXT("libcc.dll is not a 64-bits DLL file. @[FindPatchOffset]\r\n"));
|
||||
#elif defined(_M_IX86)
|
||||
if (libcc_nt_header->FileHeader.Machine != IMAGE_FILE_MACHINE_I386 || libcc_nt_header->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||||
#else
|
||||
#error "unknown arch"
|
||||
#endif
|
||||
_tprintf_s(TEXT("libcc.dll is not a 32-bits DLL file. @[FindPatchOffset]\r\n"));
|
||||
UnmapViewOfFile(libcc);
|
||||
CloseHandle(h_libcc_map);
|
||||
CloseHandle(h_libcc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WORD section_num = libcc_nt_header->FileHeader.NumberOfSections;
|
||||
const IMAGE_SECTION_HEADER* libcc_section_headers = reinterpret_cast<const IMAGE_SECTION_HEADER*>(
|
||||
libcc + libcc_dos_header->e_lfanew + sizeof(libcc_nt_header->Signature) + sizeof(libcc_nt_header->FileHeader) + libcc_nt_header->FileHeader.SizeOfOptionalHeader
|
||||
);
|
||||
|
||||
const IMAGE_SECTION_HEADER* rdata_section = nullptr;
|
||||
for (WORD i = 0; i < section_num; ++i) {
|
||||
if (*reinterpret_cast<const uint64_t*>(libcc_section_headers[i].Name) == 0x61746164722e) { // b'\x00\x00atadr.'
|
||||
rdata_section = libcc_section_headers + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rdata_section == nullptr) {
|
||||
_tprintf_s(TEXT(".rdata section is not found. @[FindPatchOffset]\r\n"));
|
||||
UnmapViewOfFile(libcc);
|
||||
CloseHandle(h_libcc_map);
|
||||
CloseHandle(h_libcc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const IMAGE_SECTION_HEADER* text_section = nullptr;
|
||||
for (WORD i = 0; i < section_num; ++i) {
|
||||
if (*reinterpret_cast<const uint64_t*>(libcc_section_headers[i].Name) == 0x747865742e) { // b'\x00\x00\x00txet.'
|
||||
text_section = libcc_section_headers + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (text_section == nullptr) {
|
||||
_tprintf_s(TEXT(".text section is not found. @[FindPatchOffset]\r\n"));
|
||||
UnmapViewOfFile(libcc);
|
||||
CloseHandle(h_libcc_map);
|
||||
CloseHandle(h_libcc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// search offset[0]
|
||||
{
|
||||
const uint8_t keyword[] = "D75125B70767B94145B47C1CB3C0755E";
|
||||
const uint8_t* start = libcc + rdata_section->PointerToRawData;
|
||||
DWORD section_size = rdata_section->SizeOfRawData;
|
||||
for (DWORD i = 0; i < section_size; ++i) {
|
||||
if (start[i] == keyword[0]) {
|
||||
bool found = true;
|
||||
for (DWORD j = 1; j < sizeof(keyword) - 1; ++j)
|
||||
if (start[i + j] != keyword[j]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
if (found) {
|
||||
Offset[0] = rdata_section->PointerToRawData + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// search offset[2]
|
||||
{
|
||||
const uint8_t keyword[] = "E1CED09B9C2186BF71A70C0FE2F1E0AE";
|
||||
const uint8_t* start = libcc + rdata_section->PointerToRawData;
|
||||
DWORD section_size = rdata_section->SizeOfRawData;
|
||||
for (DWORD i = 0; i < section_size; ++i) {
|
||||
if (start[i] == keyword[0]) {
|
||||
bool found = true;
|
||||
for (DWORD j = 1; j < sizeof(keyword) - 1; ++j)
|
||||
if (start[i + j] != keyword[j]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
if (found) {
|
||||
Offset[2] = rdata_section->PointerToRawData + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// search offset[4]
|
||||
{
|
||||
const uint8_t keyword[] = "92933";
|
||||
const uint8_t* start = libcc + rdata_section->PointerToRawData;
|
||||
DWORD section_size = rdata_section->SizeOfRawData;
|
||||
for (DWORD i = 0; i < section_size; ++i) {
|
||||
if (start[i] == keyword[0]) {
|
||||
bool found = true;
|
||||
for (DWORD j = 1; j < sizeof(keyword) - 1; ++j)
|
||||
if (start[i + j] != keyword[j]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
if (found) {
|
||||
Offset[4] = rdata_section->PointerToRawData + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// search offset[1]
|
||||
{
|
||||
const uint8_t keyword[] = { 0xfe, 0xea, 0xbc, 0x01 };
|
||||
const uint8_t* start = libcc + text_section->PointerToRawData;
|
||||
DWORD section_size = text_section->SizeOfRawData;
|
||||
for (DWORD i = 0; i < section_size; ++i) {
|
||||
if (start[i] == keyword[0]) {
|
||||
bool found = true;
|
||||
for (DWORD j = 1; j < sizeof(keyword); ++j)
|
||||
if (start[i + j] != keyword[j]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
if (found) {
|
||||
Offset[1] = text_section->PointerToRawData + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// search offset[3]
|
||||
{
|
||||
const uint8_t keyword[] = { 0x59, 0x08, 0x01, 0x00 };
|
||||
const uint8_t* start = libcc + text_section->PointerToRawData;
|
||||
DWORD section_size = text_section->SizeOfRawData;
|
||||
for (DWORD i = 0; i < section_size; ++i) {
|
||||
if (start[i] == keyword[0]) {
|
||||
bool found = true;
|
||||
for (DWORD j = 1; j < sizeof(keyword); ++j)
|
||||
if (start[i + j] != keyword[j]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
if (found) {
|
||||
Offset[3] = text_section->PointerToRawData + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UnmapViewOfFile(libcc);
|
||||
CloseHandle(h_libcc_map);
|
||||
CloseHandle(h_libcc);
|
||||
|
||||
if (Offset[0] == 0 || Offset[1] == 0 || Offset[2] == 0 || Offset[3] == 0 || Offset[4] == 0) {
|
||||
_tprintf_s(TEXT("Failed to find all patch offset. Is libcc.dll from official? Or you've patched?\r\n"));
|
||||
return FALSE;
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL Do(LPCTSTR libcc_dll_path, LPCTSTR prepared_key_file) {
|
||||
// uint8_t expected_hash[SHA256_DIGEST_LENGTH] = {
|
||||
// 0x60, 0x7e, 0x0a, 0x84, 0xc7, 0x59, 0x66, 0xb0,
|
||||
// 0x0f, 0x3d, 0x12, 0xfa, 0x83, 0x3e, 0x91, 0xd1,
|
||||
// 0x59, 0xe4, 0xf5, 0x1a, 0xc5, 0x1b, 0x6b, 0xa6,
|
||||
// 0x6f, 0x98, 0xd0, 0xc3, 0xcb, 0xef, 0xdc, 0xe0
|
||||
// };
|
||||
//
|
||||
// if (!Check_libcc_Hash(libcc_dll_path, expected_hash))
|
||||
// return FALSE;
|
||||
|
||||
DWORD Patch_Offset[5];
|
||||
if (!FindPatchOffset(libcc_dll_path, Patch_Offset))
|
||||
return FALSE;
|
||||
|
||||
|
||||
|
||||
if (!BackupFile(libcc_dll_path))
|
||||
return FALSE;
|
||||
|
||||
RSA* PrivateKey = nullptr;
|
||||
if (prepared_key_file != nullptr) {
|
||||
PrivateKey = ReadRSAPrivateKeyFromFile(prepared_key_file);
|
||||
if (PrivateKey == nullptr)
|
||||
return FALSE;
|
||||
|
||||
if (!CheckRSAKeyIsAppropriate(PrivateKey)) {
|
||||
_tprintf_s(TEXT("The key is not appropriate to use. @[patcher::Solution1::Do -> CheckRSAKeyIsAppropriate]\r\n"));
|
||||
RSA_free(PrivateKey);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
} else {
|
||||
PrivateKey = GenerateAppropriateRSAKey();
|
||||
if (PrivateKey == nullptr)
|
||||
return FALSE;
|
||||
|
||||
if (!WriteRSAPrivateKeyToFile(TEXT("RegPrivateKey.pem"), PrivateKey)) {
|
||||
RSA_free(PrivateKey);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
char* pem_pubkey = GetPEMText(PrivateKey);
|
||||
if (pem_pubkey == nullptr)
|
||||
return FALSE;
|
||||
|
||||
std::string encrypted_pem_pubkey = EncryptPublicKey(pem_pubkey, strlen(pem_pubkey));
|
||||
|
||||
delete[] pem_pubkey; // we do not need it anymore
|
||||
RSA_free(PrivateKey); // we do not need it anymore
|
||||
|
||||
// split encrypted_pem_pubkey to 5 part: |160 chars|8 chars|742 chars|5 chars|5 chars|
|
||||
// | |
|
||||
// \ / \ /
|
||||
// imm1 imm3
|
||||
std::string encrypted_pem_pubkey0(encrypted_pem_pubkey.begin(), encrypted_pem_pubkey.begin() + 160);
|
||||
std::string encrypted_pem_pubkey1(encrypted_pem_pubkey.begin() + 160, encrypted_pem_pubkey.begin() + 160 + 8);
|
||||
std::string encrypted_pem_pubkey2(encrypted_pem_pubkey.begin() + 160 + 8, encrypted_pem_pubkey.begin() + 160 + 8 + 742);
|
||||
std::string encrypted_pem_pubkey3(encrypted_pem_pubkey.begin() + 160 + 8 + 742, encrypted_pem_pubkey.begin() + 160 + 8 + 742 + 5);
|
||||
std::string encrypted_pem_pubkey4(encrypted_pem_pubkey.begin() + 160 + 8 + 742 + 5, encrypted_pem_pubkey.end());
|
||||
|
||||
uint32_t imm1 = std::stoul(encrypted_pem_pubkey1.c_str());
|
||||
uint32_t imm3 = std::stoul(encrypted_pem_pubkey3.c_str());
|
||||
|
||||
HANDLE hFile = CreateFile(libcc_dll_path, GENERIC_WRITE, NULL, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
_tprintf_s(TEXT("Failed to open libcc.dll. CODE: 0x%08x @[patcher::Solution1::Do -> CreateFile]\r\n"), GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Start from win8, lpNumberOfBytesWritten parameter in WriteFile can be null if lpOverlapped is null.
|
||||
// But win7 is not. lpNumberOfBytesWritten cannot be null if lpOverlapped is null.
|
||||
// However MSDN does not mention that.
|
||||
DWORD WrittenBytes;
|
||||
|
||||
// start patch 0
|
||||
_tprintf_s(TEXT("\r\nStart to do patch 0......\r\n"));
|
||||
if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, Patch_Offset[0], nullptr, FILE_BEGIN)) {
|
||||
_tprintf_s(TEXT("Failed to set file pointer. CODE: 0x%08x @[patcher::Solution1::Do -> SetFilePointer]\r\n"), GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_tprintf_s(TEXT("At offset +0x%08x, write:\r\n\"%hs\"\r\n"), Patch_Offset[0], encrypted_pem_pubkey0.c_str());
|
||||
if (FALSE == WriteFile(hFile, encrypted_pem_pubkey0.c_str(), encrypted_pem_pubkey0.length(), &WrittenBytes, nullptr)) {
|
||||
_tprintf_s(TEXT("Failed to write patch 0. CODE: 0x%08x @[patcher::Solution1::Do -> WriteFile]\r\n"), GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_tprintf_s(TEXT("patch 0 done.....\r\n"));
|
||||
|
||||
// start patch 1
|
||||
_tprintf_s(TEXT("\r\nStart to do patch 1.....\r\n"));
|
||||
if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, Patch_Offset[1], nullptr, FILE_BEGIN)) {
|
||||
_tprintf_s(TEXT("Failed to set file pointer. CODE: 0x%08x @[patcher::Solution1::Do -> SetFilePointer]\r\n"), GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_tprintf_s(TEXT("At offset +0x%08x, write immediate value %d (type: uint32_t)\r\n"), Patch_Offset[1], imm1);
|
||||
if (FALSE == WriteFile(hFile, &imm1, sizeof(imm1), &WrittenBytes, nullptr)) {
|
||||
_tprintf_s(TEXT("Failed to write patch 1. CODE: 0x%08x @[patcher::Solution1::Do -> WriteFile]\r\n"), GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_tprintf_s(TEXT("patch 1 done.....\r\n"));
|
||||
|
||||
// start patch 2
|
||||
_tprintf_s(TEXT("\r\nStart to do patch 2.....\r\n"));
|
||||
if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, Patch_Offset[2], nullptr, FILE_BEGIN)) {
|
||||
_tprintf_s(TEXT("Failed to set file pointer. CODE: 0x%08x @[patcher::Solution1::Do -> SetFilePointer]\r\n"), GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_tprintf_s(TEXT("At offset +0x%08x, write:\r\n\"%hs\"\r\n"), Patch_Offset[2], encrypted_pem_pubkey2.c_str());
|
||||
if (FALSE == WriteFile(hFile, encrypted_pem_pubkey2.c_str(), encrypted_pem_pubkey2.length(), &WrittenBytes, nullptr)) {
|
||||
_tprintf_s(TEXT("Failed to write patch 2. CODE: 0x%08x @[patcher::Solution1::Do -> WriteFile]\r\n"), GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_tprintf_s(TEXT("patch 2 done.....\r\n"));
|
||||
|
||||
// start patch 3
|
||||
_tprintf_s(TEXT("\r\nStart to do patch 3.....\r\n"));
|
||||
if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, Patch_Offset[3], nullptr, FILE_BEGIN)) {
|
||||
_tprintf_s(TEXT("Failed to set file pointer. CODE: 0x%08x @[patcher::Solution1::Do -> SetFilePointer]\r\n"), GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_tprintf_s(TEXT("At offset +0x%08x, write immediate value %d (type: uint32_t)\r\n"), Patch_Offset[3], imm3);
|
||||
if (FALSE == WriteFile(hFile, &imm3, sizeof(imm3), &WrittenBytes, nullptr)) {
|
||||
_tprintf_s(TEXT("Failed to write patch 3. CODE: 0x%08x @[patcher::Solution1::Do -> WriteFile]\r\n"), GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_tprintf_s(TEXT("patch 3 done.....\r\n"));
|
||||
|
||||
// start patch 4
|
||||
_tprintf_s(TEXT("\r\nStart to do patch 4.....\r\n"));
|
||||
if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, Patch_Offset[4], nullptr, FILE_BEGIN)) {
|
||||
_tprintf_s(TEXT("Failed to set file pointer. CODE: 0x%08x @[patcher::Solution1::Do -> SetFilePointer]\r\n"), GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_tprintf_s(TEXT("At offset +0x%08x, write:\r\n\"%hs\"\r\n"), Patch_Offset[4], encrypted_pem_pubkey4.c_str());
|
||||
if (FALSE == WriteFile(hFile, encrypted_pem_pubkey4.c_str(), encrypted_pem_pubkey4.length(), &WrittenBytes, nullptr)) {
|
||||
_tprintf_s(TEXT("Failed to write patch 4. CODE: 0x%08x @[patcher::Solution1::Do -> WriteFile]\r\n"), GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_tprintf_s(TEXT("patch 4 done.....\r\n\r\n"));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
#include "def.hpp"
|
||||
|
||||
namespace std {
|
||||
#ifdef UNICODE
|
||||
typedef wstring Tstring;
|
||||
#else
|
||||
typedef string Tstring;
|
||||
#endif
|
||||
}
|
||||
|
||||
int _tmain(int argc, TCHAR* argv[]) {
|
||||
if (argc != 2 && argc != 3) {
|
||||
_tprintf_s(TEXT("Usage:\r\n"));
|
||||
_tprintf_s(TEXT(" navicat-patcher.exe <Navicat installation path> [RSA-2048 PEM file]\r\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
{ // check path validity
|
||||
DWORD attr = GetFileAttributes(argv[1]);
|
||||
if (attr == INVALID_FILE_ATTRIBUTES) {
|
||||
_tprintf_s(TEXT("Failed to get installation path attribute. CODE: 0x%08x @[GetFileAttributes]\r\n"), GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
||||
_tprintf_s(TEXT("Error: Path is not a directory.\r\n"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::Tstring navicat_exe_path(argv[1]);
|
||||
if (navicat_exe_path.back() != TEXT('/') && navicat_exe_path.back() != TEXT('\\'))
|
||||
navicat_exe_path.push_back(TEXT('\\'));
|
||||
navicat_exe_path += TEXT("navicat.exe");
|
||||
|
||||
std::Tstring libcc_dll_path(argv[1]);
|
||||
if (libcc_dll_path.back() != TEXT('/') && libcc_dll_path.back() != TEXT('\\'))
|
||||
libcc_dll_path.push_back(TEXT('\\'));
|
||||
libcc_dll_path += TEXT("libcc.dll");
|
||||
|
||||
DWORD NavicatMajorVersion;
|
||||
DWORD NavicatMinorVersion;
|
||||
if (!patcher::GetNavicatVerion(navicat_exe_path.c_str(), &NavicatMajorVersion, &NavicatMinorVersion))
|
||||
return 0;
|
||||
|
||||
BOOL status;
|
||||
if (NavicatMajorVersion <= 0x000C0000 && NavicatMinorVersion < 0x00190000) { // for navicat ver < 12.0.25
|
||||
status = patcher::Solution0::Do(navicat_exe_path.c_str());
|
||||
} else if (NavicatMajorVersion == 0x000C0000 && NavicatMinorVersion <= 0x001C0000) { // for navicat ver <= 12.0.28
|
||||
status = patcher::Solution1::Do(libcc_dll_path.c_str(), argc == 3 ? argv[2] : nullptr);
|
||||
} else {
|
||||
_tprintf_s(TEXT("Warning: Unknown version detected, still continue? [y/n] "));
|
||||
TCHAR selection = _gettchar();
|
||||
if (selection == 'Y' || selection == 'y')
|
||||
status = patcher::Solution1::Do(libcc_dll_path.c_str(), argc == 3 ? argv[2] : nullptr);
|
||||
}
|
||||
|
||||
_tprintf_s(TEXT("%s\r\n"), status == TRUE ? TEXT("Success!") : TEXT("Failed!"));
|
||||
return 0;
|
||||
}
|
||||
200
navicat-patcher/amd64_emulator.cpp
Normal file
200
navicat-patcher/amd64_emulator.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include "amd64_emulator.hpp"
|
||||
#include "exceptions/key_exception.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-patcher\\amd64_emulator.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
void amd64_emulator::_unicorn_hookcode_cb_stub(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
|
||||
auto hook_stub_ctx = reinterpret_cast<hook_stub_context_t*>(user_data);
|
||||
hook_stub_ctx->self->m_unicorn_hook_cbs_hookcode[hook_stub_ctx->unicorn_hook_handle](address, size);
|
||||
}
|
||||
|
||||
void amd64_emulator::_unicorn_hookmem_cb_stub(uc_engine* uc, uc_mem_type type, uint64_t address, int size, int64_t value, void* user_data) {
|
||||
auto hook_stub_ctx = reinterpret_cast<hook_stub_context_t*>(user_data);
|
||||
hook_stub_ctx->self->m_unicorn_hook_cbs_hookmem[hook_stub_ctx->unicorn_hook_handle](type, address, static_cast<unsigned int>(size), value);
|
||||
}
|
||||
|
||||
bool amd64_emulator::_unicorn_eventmem_cb_stub(uc_engine* uc, uc_mem_type type, uint64_t address, int size, int64_t value, void* user_data) {
|
||||
auto hook_stub_ctx = reinterpret_cast<hook_stub_context_t*>(user_data);
|
||||
return hook_stub_ctx->self->m_unicorn_hook_cbs_eventmem[hook_stub_ctx->unicorn_hook_handle](type, address, static_cast<unsigned int>(size), value);
|
||||
}
|
||||
|
||||
amd64_emulator::amd64_emulator() {
|
||||
auto err = uc_open(UC_ARCH_X86, UC_MODE_64, m_unicorn_engine.unsafe_addressof());
|
||||
if (err != UC_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_open failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void amd64_emulator::reg_read(int regid, void* value) {
|
||||
auto err = uc_reg_read(m_unicorn_engine.get(), regid, value);
|
||||
if (err != UC_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_reg_read failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void amd64_emulator::reg_write(int regid, const void* value) {
|
||||
auto err = uc_reg_write(m_unicorn_engine.get(), regid, value);
|
||||
if (err != UC_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_reg_write failed.");
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t amd64_emulator::msr_read(uint32_t rid) {
|
||||
uc_x86_msr msr;
|
||||
msr.rid = rid;
|
||||
|
||||
auto err = uc_reg_read(m_unicorn_engine.get(), UC_X86_REG_MSR, &msr);
|
||||
if (err != UC_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_reg_write failed.");
|
||||
}
|
||||
|
||||
return msr.value;
|
||||
}
|
||||
|
||||
void amd64_emulator::msr_write(uint32_t rid, uint64_t value) {
|
||||
uc_x86_msr msr;
|
||||
msr.rid = rid;
|
||||
msr.value = value;
|
||||
|
||||
auto err = uc_reg_write(m_unicorn_engine.get(), UC_X86_REG_MSR, &msr);
|
||||
if (err != UC_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_reg_write failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void amd64_emulator::mem_map(uint64_t address, size_t size, uint32_t perms) {
|
||||
auto err = uc_mem_map(m_unicorn_engine.get(), address, size, perms);
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_map failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void amd64_emulator::mem_unmap(uint64_t address, size_t size) {
|
||||
auto err = uc_mem_unmap(m_unicorn_engine.get(), address, size);
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_unmap failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void amd64_emulator::mem_read(uint64_t address, void* buf, size_t size) {
|
||||
auto err = uc_mem_read(m_unicorn_engine.get(), address, buf, size);
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_read failed.");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> amd64_emulator::mem_read(uint64_t address, size_t size) {
|
||||
std::vector<uint8_t> ret_buf(size);
|
||||
|
||||
auto err = uc_mem_read(m_unicorn_engine.get(), address, ret_buf.data(), ret_buf.size());
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_read failed.");
|
||||
}
|
||||
|
||||
return ret_buf;
|
||||
}
|
||||
|
||||
void amd64_emulator::mem_write(uint64_t address, const void* buf, size_t size) {
|
||||
auto err = uc_mem_write(m_unicorn_engine.get(), address, buf, size);
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_write failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void amd64_emulator::mem_write(uint64_t address, const std::vector<uint8_t>& buf) {
|
||||
mem_write(address, buf.data(), buf.size());
|
||||
}
|
||||
|
||||
void amd64_emulator::hook_del(uc_hook hook_handle) {
|
||||
auto iter_of_hook_stub_ctxs = m_unicorn_hook_stub_ctxs.find(hook_handle);
|
||||
if (iter_of_hook_stub_ctxs == m_unicorn_hook_stub_ctxs.end()) {
|
||||
throw exceptions::key_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Target hook is not found.");
|
||||
}
|
||||
|
||||
auto iter_of_hook_cbs_hookcode = m_unicorn_hook_cbs_hookcode.find(hook_handle);
|
||||
if (iter_of_hook_cbs_hookcode != m_unicorn_hook_cbs_hookcode.end()) {
|
||||
auto err = uc_hook_del(m_unicorn_engine.get(), hook_handle);
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"hook_del failed.");
|
||||
}
|
||||
|
||||
m_unicorn_hook_cbs_hookcode.erase(iter_of_hook_cbs_hookcode);
|
||||
m_unicorn_hook_stub_ctxs.erase(iter_of_hook_stub_ctxs);
|
||||
return;
|
||||
}
|
||||
|
||||
auto iter_of_hook_cbs_hookmem = m_unicorn_hook_cbs_hookmem.find(hook_handle);
|
||||
if (iter_of_hook_cbs_hookmem != m_unicorn_hook_cbs_hookmem.end()) {
|
||||
auto err = uc_hook_del(m_unicorn_engine.get(), hook_handle);
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"hook_del failed.");
|
||||
}
|
||||
|
||||
m_unicorn_hook_cbs_hookmem.erase(iter_of_hook_cbs_hookmem);
|
||||
m_unicorn_hook_stub_ctxs.erase(iter_of_hook_stub_ctxs);
|
||||
return;
|
||||
}
|
||||
|
||||
auto iter_of_hook_cbs_eventmem = m_unicorn_hook_cbs_eventmem.find(hook_handle);
|
||||
if (iter_of_hook_cbs_eventmem != m_unicorn_hook_cbs_eventmem.end()) {
|
||||
auto err = uc_hook_del(m_unicorn_engine.get(), hook_handle);
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"hook_del failed.");
|
||||
}
|
||||
|
||||
m_unicorn_hook_cbs_eventmem.erase(iter_of_hook_cbs_eventmem);
|
||||
m_unicorn_hook_stub_ctxs.erase(iter_of_hook_stub_ctxs);
|
||||
return;
|
||||
}
|
||||
|
||||
__assume(false);
|
||||
}
|
||||
|
||||
void amd64_emulator::emu_start(uint64_t begin_address, uint64_t end_address, uint64_t timeout, size_t count) {
|
||||
auto err = uc_emu_start(m_unicorn_engine.get(), begin_address, end_address, timeout, count);
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"emu_start failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void amd64_emulator::emu_stop() {
|
||||
auto err = uc_emu_stop(m_unicorn_engine.get());
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_emu_stop failed.");
|
||||
}
|
||||
}
|
||||
|
||||
//void amd64_emulator::create_gdt_entry(uint64_t gdt_entry_address, uint32_t base, uint32_t limit, uint8_t access_byte, uint8_t flags) {
|
||||
// struct {
|
||||
// uint16_t limit0;
|
||||
// uint16_t base0;
|
||||
// uint8_t base1;
|
||||
// uint8_t access_byte;
|
||||
// uint8_t limit1 : 4;
|
||||
// uint8_t flags : 4;
|
||||
// uint8_t base2;
|
||||
// } segment_descriptor;
|
||||
|
||||
// static_assert(sizeof(segment_descriptor) == 8);
|
||||
|
||||
// segment_descriptor.limit0 = limit & 0xffff;
|
||||
// segment_descriptor.base0 = base & 0xffff;
|
||||
// segment_descriptor.base1 = (base >> 16) & 0xff;
|
||||
// segment_descriptor.access_byte = access_byte;
|
||||
// segment_descriptor.limit1 = (limit >> 16) & 0xf;
|
||||
// segment_descriptor.flags = flags & 0xf;
|
||||
// segment_descriptor.base2 = (base >> 24) & 0xff;
|
||||
|
||||
// auto err = uc_mem_write(m_unicorn_engine.get(), gdt_entry_address, &segment_descriptor, sizeof(segment_descriptor));
|
||||
// if (err != UC_ERR_OK) {
|
||||
// throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_write failed.");
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
159
navicat-patcher/amd64_emulator.hpp
Normal file
159
navicat-patcher/amd64_emulator.hpp
Normal file
@ -0,0 +1,159 @@
|
||||
#pragma once
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <unicorn/unicorn.h>
|
||||
|
||||
#include <any>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
|
||||
#include "resource_wrapper.hpp"
|
||||
#include "resource_traits/unicorn/unicorn_handle.hpp"
|
||||
|
||||
#include "exception.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-patcher\\amd64_emulator.hpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class amd64_emulator {
|
||||
public:
|
||||
class backend_error : public ::nkg::exception {
|
||||
public:
|
||||
using error_code_t = uc_err;
|
||||
|
||||
private:
|
||||
error_code_t m_error_code;
|
||||
std::string m_error_string;
|
||||
|
||||
public:
|
||||
backend_error(std::string_view file, int line, error_code_t unicorn_err, std::string_view message) noexcept :
|
||||
::nkg::exception(file, line, message), m_error_code(unicorn_err), m_error_string(uc_strerror(unicorn_err)) {}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool error_code_exists() const noexcept override {
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual intptr_t error_code() const noexcept override {
|
||||
return m_error_code;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual const std::string& error_string() const noexcept override {
|
||||
return m_error_string;
|
||||
}
|
||||
};
|
||||
|
||||
using hookcode_cb_t = void(uint64_t address, size_t size);
|
||||
using hookmem_cb_t = void(uc_mem_type type, uint64_t address, size_t size, int64_t value);
|
||||
using eventmem_cb_t = bool(uc_mem_type type, uint64_t address, size_t size, int64_t value);
|
||||
|
||||
private:
|
||||
struct hook_stub_context_t {
|
||||
amd64_emulator* self;
|
||||
uc_hook unicorn_hook_handle;
|
||||
};
|
||||
|
||||
resource_wrapper<resource_traits::unicorn::unicorn_handle> m_unicorn_engine;
|
||||
std::unordered_map<std::string, std::any> m_unicorn_user_ctx;
|
||||
|
||||
std::unordered_map<uc_hook, std::unique_ptr<hook_stub_context_t>> m_unicorn_hook_stub_ctxs;
|
||||
|
||||
std::unordered_map<uc_hook, std::function<hookcode_cb_t>> m_unicorn_hook_cbs_hookcode;
|
||||
std::unordered_map<uc_hook, std::function<hookmem_cb_t>> m_unicorn_hook_cbs_hookmem;
|
||||
std::unordered_map<uc_hook, std::function<eventmem_cb_t>> m_unicorn_hook_cbs_eventmem;
|
||||
|
||||
static void _unicorn_hookcode_cb_stub(uc_engine* uc, uint64_t address, uint32_t size, void* user_data);
|
||||
static void _unicorn_hookmem_cb_stub(uc_engine* uc, uc_mem_type type, uint64_t address, int size, int64_t value, void* user_data);
|
||||
static bool _unicorn_eventmem_cb_stub(uc_engine* uc, uc_mem_type type, uint64_t address, int size, int64_t value, void* user_data);
|
||||
|
||||
public:
|
||||
amd64_emulator();
|
||||
|
||||
void reg_read(int regid, void* buf);
|
||||
|
||||
void reg_write(int regid, const void* buf);
|
||||
|
||||
uint64_t msr_read(uint32_t rid);
|
||||
|
||||
void msr_write(uint32_t rid, uint64_t value);
|
||||
|
||||
void mem_map(uint64_t address, size_t size, uint32_t perms);
|
||||
|
||||
void mem_unmap(uint64_t address, size_t size);
|
||||
|
||||
void mem_read(uint64_t address, void* buf, size_t size);
|
||||
|
||||
std::vector<uint8_t> mem_read(uint64_t address, size_t size);
|
||||
|
||||
void mem_write(uint64_t address, const void* buf, size_t size);
|
||||
|
||||
void mem_write(uint64_t address, const std::vector<uint8_t>& buf);
|
||||
|
||||
template<int hook_type, typename callable_t>
|
||||
uc_hook hook_add(callable_t&& hook_callback, uint64_t begin_address = 1, uint64_t end_address = 0) {
|
||||
uc_err err;
|
||||
|
||||
auto hook_stub_ctx = std::make_unique<hook_stub_context_t>();
|
||||
hook_stub_ctx->self = this;
|
||||
hook_stub_ctx->unicorn_hook_handle = 0;
|
||||
|
||||
if constexpr (hook_type == UC_HOOK_CODE) {
|
||||
err = uc_hook_add(m_unicorn_engine.get(), &hook_stub_ctx->unicorn_hook_handle, hook_type, _unicorn_hookcode_cb_stub, hook_stub_ctx.get(), begin_address, end_address);
|
||||
if (err != UC_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_hook_add failed.");
|
||||
}
|
||||
|
||||
m_unicorn_hook_cbs_hookcode.emplace(std::make_pair(hook_stub_ctx->unicorn_hook_handle, std::forward<callable_t>(hook_callback)));
|
||||
} else if constexpr ((hook_type & ~UC_HOOK_MEM_VALID) == 0) {
|
||||
err = uc_hook_add(m_unicorn_engine.get(), &hook_stub_ctx->unicorn_hook_handle, hook_type, _unicorn_hookmem_cb_stub, hook_stub_ctx.get(), begin_address, end_address);
|
||||
if (err != UC_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_hook_add failed.");
|
||||
}
|
||||
|
||||
m_unicorn_hook_cbs_hookmem.emplace(std::make_pair(hook_stub_ctx->unicorn_hook_handle, std::forward<callable_t>(hook_callback)));
|
||||
} else if constexpr ((hook_type & ~UC_HOOK_MEM_UNMAPPED) == 0) {
|
||||
err = uc_hook_add(m_unicorn_engine.get(), &hook_stub_ctx->unicorn_hook_handle, hook_type, _unicorn_eventmem_cb_stub, hook_stub_ctx.get(), begin_address, end_address);
|
||||
if (err != UC_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_hook_add failed.");
|
||||
}
|
||||
|
||||
m_unicorn_hook_cbs_eventmem.emplace(std::make_pair(hook_stub_ctx->unicorn_hook_handle, std::forward<callable_t>(hook_callback)));
|
||||
} else {
|
||||
static_assert(
|
||||
hook_type == UC_HOOK_CODE ||
|
||||
(hook_type & ~UC_HOOK_MEM_VALID) == 0 ||
|
||||
(hook_type & ~UC_HOOK_MEM_UNMAPPED) == 0, "Unsupported hook type.");
|
||||
}
|
||||
|
||||
return m_unicorn_hook_stub_ctxs.emplace(std::make_pair(hook_stub_ctx->unicorn_hook_handle, std::move(hook_stub_ctx))).first->first;
|
||||
}
|
||||
|
||||
void hook_del(uc_hook hook_handle);
|
||||
|
||||
void emu_start(uint64_t begin_address, uint64_t end_address = 0, uint64_t timeout = 0, size_t count = 0);
|
||||
|
||||
void emu_stop();
|
||||
|
||||
// void create_gdt_entry(uint64_t gdt_entry_address, uint32_t base, uint32_t limit, uint8_t access_byte, uint8_t flags);
|
||||
|
||||
template<typename val_t>
|
||||
void context_set(const std::string& name, val_t&& value) {
|
||||
m_unicorn_user_ctx[name] = std::forward<val_t>(value);
|
||||
}
|
||||
|
||||
template<typename val_t>
|
||||
val_t context_get(const std::string& name) {
|
||||
return std::any_cast<val_t>(m_unicorn_user_ctx[name]);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
@ -1,249 +0,0 @@
|
||||
#include "def.hpp"
|
||||
|
||||
namespace patcher {
|
||||
|
||||
BOOL BackupFile(LPCTSTR file_path) {
|
||||
size_t file_path_len = _tcslen(file_path);
|
||||
|
||||
TCHAR* backup_file_path = new TCHAR[file_path_len + 16]();
|
||||
_stprintf_s(backup_file_path, file_path_len + 16, TEXT("%s%s"), file_path, TEXT(".backup"));
|
||||
|
||||
if (!CopyFile(file_path, backup_file_path, TRUE)) {
|
||||
switch (GetLastError()) {
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
_tprintf_s(TEXT("@[BackupFile]: Cannot find %s.\r\n"), file_path);
|
||||
break;
|
||||
case ERROR_FILE_EXISTS:
|
||||
_tprintf_s(TEXT("@[BackupFile]: Backup file already exists.\r\n"));
|
||||
break;
|
||||
case ERROR_ACCESS_DENIED:
|
||||
_tprintf_s(TEXT("@[BackupFile]: Access denied, please run as administrator.\r\n"));
|
||||
break;
|
||||
default:
|
||||
_tprintf_s(TEXT("Unknown error. CODE: 0x%08x @[BackupFile -> CopyFile]\r\n"), GetLastError());
|
||||
}
|
||||
delete[] backup_file_path;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_tprintf_s(TEXT("@[BackupFile]: %s has been backed up.\r\n"), file_path);
|
||||
delete[] backup_file_path;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
RSA* GenerateRSAKey(int bits) {
|
||||
RSA* ret = RSA_generate_key(bits, RSA_F4, nullptr, nullptr);
|
||||
if (ret == nullptr) {
|
||||
_tprintf_s(TEXT("Failed to generate RSA key. CODE: 0x%08x @[GenerateRSAKey -> RSA_generate_key]\r\n"), ERR_get_error());
|
||||
return nullptr;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL WriteRSAPrivateKeyToFile(LPCTSTR filename, RSA* PrivateKey) {
|
||||
#ifdef UNICODE
|
||||
int req_size = WideCharToMultiByte(CP_ACP, 0, filename, -1, nullptr, 0, nullptr, nullptr);
|
||||
if (req_size == 0) {
|
||||
_tprintf_s(TEXT("Failed to convert wchar* to char*. CODE: 0x%08x @[WriteRSAPrivateKeyToFile -> WideCharToMultiByte]\r\n"), GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
char* temp_filename = new char[req_size]();
|
||||
WideCharToMultiByte(CP_ACP, 0, filename, -1, temp_filename, req_size, nullptr, nullptr);
|
||||
|
||||
BIO* b = BIO_new(BIO_s_file());
|
||||
if (b == nullptr) {
|
||||
_tprintf_s(TEXT("Failed to create BIO object. CODE: 0x%08x @[WriteRSAPrivateKeyToFile -> BIO_new]\r\n"), ERR_get_error());
|
||||
delete[] temp_filename;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (1 != BIO_write_filename(b, temp_filename)) {
|
||||
_tprintf_s(TEXT("Failed to set target file of BIO. CODE: 0x%08x @[WriteRSAPrivateKeyToFile -> BIO_write_filename]\r\n"), ERR_get_error());
|
||||
|
||||
BIO_free_all(b);
|
||||
delete[] temp_filename;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
delete[] temp_filename;
|
||||
#else
|
||||
BIO* b = BIO_new(BIO_s_file());
|
||||
if (b == nullptr) {
|
||||
_tprintf_s(TEXT("Failed to create BIO object. CODE: 0x%08x @[WriteRSAPrivateKeyToFile -> BIO_new]\r\n"), ERR_get_error());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (1 != BIO_write_filename(b, filename)) {
|
||||
_tprintf_s(TEXT("Failed to set target file of BIO. CODE: 0x%08x @[WriteRSAPrivateKeyToFile -> BIO_write_filename]\r\n"), ERR_get_error());
|
||||
|
||||
BIO_free_all(b);
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
if (1 != PEM_write_bio_RSAPrivateKey(b, PrivateKey, nullptr, nullptr, 0, nullptr, nullptr)) {
|
||||
_tprintf_s(TEXT("Failed to write RSA private key. CODE: 0x%08x @[WriteRSAPrivateKeyToFile -> PEM_write_bio_RSAPrivateKey]\r\n"), ERR_get_error());
|
||||
|
||||
BIO_free_all(b);
|
||||
return FALSE;
|
||||
} else {
|
||||
BIO_free_all(b);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
RSA* ReadRSAPrivateKeyFromFile(LPCTSTR filename) {
|
||||
#ifdef UNICODE
|
||||
int req_size = WideCharToMultiByte(CP_ACP, 0, filename, -1, nullptr, 0, nullptr, nullptr);
|
||||
if (req_size == 0) {
|
||||
_tprintf_s(TEXT("Failed to convert wchar* to char*. CODE: 0x%08x @[ReadRSAPrivateKeyFromFile -> WideCharToMultiByte]\r\n"), GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
char* temp_filename = new char[req_size]();
|
||||
WideCharToMultiByte(CP_ACP, 0, filename, -1, temp_filename, req_size, nullptr, nullptr);
|
||||
|
||||
BIO* b = BIO_new(BIO_s_file());
|
||||
if (b == nullptr) {
|
||||
_tprintf_s(TEXT("Failed to create BIO object. CODE: 0x%08x @[ReadRSAPrivateKeyFromFile -> BIO_new]\r\n"), ERR_get_error());
|
||||
delete[] temp_filename;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (1 != BIO_read_filename(b, temp_filename)) {
|
||||
_tprintf_s(TEXT("Failed to set target file of BIO. CODE: 0x%08x @[ReadRSAPrivateKeyFromFile -> BIO_read_filename]\r\n"), ERR_get_error());
|
||||
|
||||
BIO_free_all(b);
|
||||
delete[] temp_filename;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
delete[] temp_filename;
|
||||
#else
|
||||
BIO* b = BIO_new(BIO_s_file());
|
||||
if (b == nullptr) {
|
||||
_tprintf_s(TEXT("Failed to create BIO object. CODE: 0x%08x @[ReadRSAPrivateKeyFromFile -> BIO_new]\r\n"), ERR_get_error());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (1 != BIO_read_filename(b, filename)) {
|
||||
_tprintf_s(TEXT("Failed to set target file of BIO. CODE: 0x%08x @[ReadRSAPrivateKeyFromFile -> BIO_read_filename]\r\n"), ERR_get_error());
|
||||
|
||||
BIO_free_all(b);
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
RSA* ret = PEM_read_bio_RSAPrivateKey(b, nullptr, nullptr, nullptr);
|
||||
if (ret == nullptr) {
|
||||
_tprintf_s(TEXT("Failed to read RSA private key. CODE: 0x%08x @[ReadRSAPrivateKeyFromFile -> PEM_read_bio_RSAPrivateKey]\r\n"), ERR_get_error());
|
||||
|
||||
BIO_free_all(b);
|
||||
return nullptr;
|
||||
} else {
|
||||
BIO_free_all(b);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL GetNavicatVerion(LPCTSTR exe_path, DWORD* major_ver, DWORD* minor_ver) {
|
||||
DWORD FileVersionInfoSize = GetFileVersionInfoSize(exe_path, nullptr);
|
||||
if (FileVersionInfoSize == 0) {
|
||||
_tprintf_s(TEXT("Failed to get navicat.exe verion info. CODE: 0x%08x @[GetNavicatVerion -> GetFileVersionInfoSize]\r\n"), GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
LPVOID buf = new unsigned char[FileVersionInfoSize]();
|
||||
if (FALSE == GetFileVersionInfo(exe_path, 0, FileVersionInfoSize, buf)) {
|
||||
_tprintf_s(TEXT("Failed to get navicat.exe verion info. CODE: 0x%08x @[GetNavicatVerion -> GetFileVersionInfo]\r\n"), GetLastError());
|
||||
delete[] buf;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LPVOID info_ptr;
|
||||
UINT info_len;
|
||||
if (FALSE == VerQueryValue(buf, TEXT("\\"), &info_ptr, &info_len)) {
|
||||
_tprintf_s(TEXT("Failed to get navicat.exe verion info. CODE: 0x%08x @[GetNavicatVerion -> VerQueryValue]\r\n"), GetLastError());
|
||||
delete[] buf;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*major_ver = static_cast<VS_FIXEDFILEINFO*>(info_ptr)->dwFileVersionMS;
|
||||
*minor_ver = static_cast<VS_FIXEDFILEINFO*>(info_ptr)->dwFileVersionLS;
|
||||
delete[] buf;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Check_libcc_Hash(LPCTSTR libcc_dll_path, const uint8_t expected_hash[SHA256_DIGEST_LENGTH]) {
|
||||
HANDLE hFile = CreateFile(libcc_dll_path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
_tprintf_s(TEXT("Failed to open libcc.dll. CODE: 0x%08x @[Check_libcc_Hash -> CreateFile]\r\n"), GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LARGE_INTEGER FileSize;
|
||||
if (FALSE == GetFileSizeEx(hFile, &FileSize)) {
|
||||
_tprintf_s(TEXT("Failed to get libcc.dll size. CODE: 0x%08x @[Check_libcc_Hash -> GetFileSizeEx]\r\n"), GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HANDLE hFileMap = CreateFileMapping(hFile, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
if (hFileMap == NULL) {
|
||||
_tprintf_s(TEXT("Failed to create mapping for libcc.dll. CODE: 0x%08x @[Check_libcc_Hash -> CreateFileMapping]\r\n"), GetLastError());
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const uint8_t* libcc_data = reinterpret_cast<const uint8_t*>(MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0));
|
||||
if (libcc_data == nullptr) {
|
||||
_tprintf_s(TEXT("Failed to map libcc.dll. CODE: 0x%08x @[Check_libcc_Hash -> MapViewOfFile]\r\n"), GetLastError());
|
||||
CloseHandle(hFileMap);
|
||||
CloseHandle(hFile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
uint8_t real_hash[SHA256_DIGEST_LENGTH] = { };
|
||||
|
||||
SHA256(libcc_data, FileSize.LowPart, real_hash);
|
||||
UnmapViewOfFile(libcc_data);
|
||||
CloseHandle(hFileMap);
|
||||
CloseHandle(hFile);
|
||||
|
||||
if (memcmp(expected_hash, real_hash, SHA256_DIGEST_LENGTH) != 0) {
|
||||
_tprintf_s(TEXT("ERROR: SHA256 do not match.\r\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
char* GetPEMText(RSA* PrivateKey) {
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
if (bio == nullptr) {
|
||||
_tprintf_s(TEXT("Cannot create BIO object. CODE: 0x%08x @[GetPEMText -> BIO_new]\r\n"), ERR_get_error());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (1 != PEM_write_bio_RSA_PUBKEY(bio, PrivateKey)) {
|
||||
_tprintf_s(TEXT("Cannot write RSA-2048 public key. CODE: 0x%08x @[GetPEMText -> PEM_write_bio_RSA_PUBKEY]\r\n"), ERR_get_error());
|
||||
BIO_free_all(bio);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char* pem_data_ptr;
|
||||
int pem_data_len = BIO_get_mem_data(bio, &pem_data_ptr);
|
||||
|
||||
char* ret = new char[pem_data_len + 256]();
|
||||
for (int i = 0, j = 0; i < pem_data_len; ++i, ++j) {
|
||||
if (pem_data_ptr[i] == '\n') {
|
||||
ret[j++] = '\r';
|
||||
ret[j] = pem_data_ptr[i];
|
||||
} else {
|
||||
ret[j] = pem_data_ptr[i];
|
||||
}
|
||||
}
|
||||
|
||||
BIO_free_all(bio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
#pragma once
|
||||
#include <tchar.h>
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
// OpenSSL precompiled lib, download from https://www.npcglib.org/~stathis/blog/precompiled-openssl/, MSVC2015 version
|
||||
// direct link https://www.npcglib.org/~stathis/downloads/openssl-1.1.0f-vs2015.7z
|
||||
// x86: "D:\openssl-1.1.0f-vs2015\include" has been add to include path. (modify it at project properties if necessary)
|
||||
// "D:\openssl-1.1.0f-vs2015\lib" has been add to library path. (modify it at project properties if necessary)
|
||||
// x64: "D:\openssl-1.1.0f-vs2015\include64" has been add to include path. (modify it at project properties if necessary)
|
||||
// "D:\openssl-1.1.0f-vs2015\lib64" has been add to library path. (modify it at project properties if necessary)
|
||||
#ifdef _DEBUG
|
||||
#pragma comment(lib, "libcryptoMTd.lib")
|
||||
#else
|
||||
#pragma comment(lib, "libcryptoMT.lib")
|
||||
#endif
|
||||
#pragma comment(lib, "WS2_32.lib") // some symbol are used in OpenSSL static lib
|
||||
#pragma comment(lib, "Crypt32.lib") // some symbol are used in OpenSSL static lib
|
||||
#pragma comment(lib, "version.lib") // GetFileVersionInfoSize, GetFileVersionInfo, VerQueryValue are in this lib
|
||||
|
||||
namespace patcher {
|
||||
|
||||
BOOL BackupFile(LPCTSTR file_path);
|
||||
|
||||
RSA* GenerateRSAKey(int bits = 2048);
|
||||
|
||||
BOOL WriteRSAPrivateKeyToFile(LPCTSTR filename, RSA* PrivateKey);
|
||||
RSA* ReadRSAPrivateKeyFromFile(LPCTSTR filename);
|
||||
|
||||
BOOL GetNavicatVerion(LPCTSTR exe_path, DWORD* major_ver, DWORD* minor_ver);
|
||||
|
||||
std::string EncryptPublicKey(const char* public_key, size_t len);
|
||||
|
||||
BOOL Check_libcc_Hash(LPCTSTR libcc_dll_path, const uint8_t expected_hash[SHA256_DIGEST_LENGTH]);
|
||||
|
||||
char* GetPEMText(RSA* PrivateKey);
|
||||
|
||||
namespace Solution0 {
|
||||
BOOL Do(LPCTSTR navicat_exe_path, LPCTSTR prepared_key_file = nullptr);
|
||||
}
|
||||
|
||||
namespace Solution1 {
|
||||
BOOL Do(LPCTSTR libcc_dll_path, LPCTSTR prepared_key_file = nullptr);
|
||||
}
|
||||
|
||||
}
|
||||
160
navicat-patcher/i386_emulator.cpp
Normal file
160
navicat-patcher/i386_emulator.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include "i386_emulator.hpp"
|
||||
#include "exceptions/key_exception.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-patcher\\i386_emulator.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
void i386_emulator::_unicorn_hookcode_cb_stub(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
|
||||
auto hook_stub_ctx =
|
||||
reinterpret_cast<hook_stub_context_t*>(user_data);
|
||||
|
||||
auto& hook_callback =
|
||||
std::any_cast<std::function<hookcode_cb_t>&>(hook_stub_ctx->self->m_unicorn_hook_callbacks[hook_stub_ctx->unicorn_hook_handle]);
|
||||
|
||||
hook_callback(static_cast<uint32_t>(address), size);
|
||||
}
|
||||
|
||||
void i386_emulator::_unicorn_hookmem_cb_stub(uc_engine* uc, uc_mem_type type, uint64_t address, int size, int64_t value, void* user_data) {
|
||||
auto hook_stub_ctx =
|
||||
reinterpret_cast<hook_stub_context_t*>(user_data);
|
||||
|
||||
auto& hook_callback =
|
||||
std::any_cast<std::function<hookmem_cb_t>&>(hook_stub_ctx->self->m_unicorn_hook_callbacks[hook_stub_ctx->unicorn_hook_handle]);
|
||||
|
||||
hook_callback(type, static_cast<uint32_t>(address), static_cast<unsigned int>(size), static_cast<int32_t>(value));
|
||||
}
|
||||
|
||||
bool i386_emulator::_unicorn_eventmem_cb_stub(uc_engine* uc, uc_mem_type type, uint64_t address, int size, int64_t value, void* user_data) {
|
||||
auto hook_stub_ctx =
|
||||
reinterpret_cast<hook_stub_context_t*>(user_data);
|
||||
|
||||
auto& hook_callback =
|
||||
std::any_cast<std::function<eventmem_cb_t>&>(hook_stub_ctx->self->m_unicorn_hook_callbacks[hook_stub_ctx->unicorn_hook_handle]);
|
||||
|
||||
return hook_callback(type, static_cast<uint32_t>(address), static_cast<unsigned int>(size), static_cast<int32_t>(value));
|
||||
}
|
||||
|
||||
i386_emulator::i386_emulator() {
|
||||
auto err = uc_open(UC_ARCH_X86, UC_MODE_32, m_unicorn_engine.unsafe_addressof());
|
||||
if (err != UC_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_open failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void i386_emulator::reg_read(int regid, void* value) {
|
||||
auto err = uc_reg_read(m_unicorn_engine.get(), regid, value);
|
||||
if (err != UC_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_reg_read failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void i386_emulator::reg_write(int regid, const void* value) {
|
||||
auto err = uc_reg_write(m_unicorn_engine.get(), regid, value);
|
||||
if (err != UC_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_reg_write failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void i386_emulator::mem_map(uint32_t address, size_t size, uint32_t perms) {
|
||||
auto err = uc_mem_map(m_unicorn_engine.get(), address, size, perms);
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_map failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void i386_emulator::mem_unmap(uint32_t address, size_t size) {
|
||||
auto err = uc_mem_unmap(m_unicorn_engine.get(), address, size);
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_unmap failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void i386_emulator::mem_read(uint32_t address, void* buf, size_t size) {
|
||||
auto err = uc_mem_read(m_unicorn_engine.get(), address, buf, size);
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_read failed.");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> i386_emulator::mem_read(uint32_t address, size_t size) {
|
||||
std::vector<uint8_t> ret_buf(size);
|
||||
|
||||
auto err = uc_mem_read(m_unicorn_engine.get(), address, ret_buf.data(), ret_buf.size());
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_read failed.");
|
||||
}
|
||||
|
||||
return ret_buf;
|
||||
}
|
||||
|
||||
void i386_emulator::mem_write(uint32_t address, const void* buf, size_t size) {
|
||||
auto err = uc_mem_write(m_unicorn_engine.get(), address, buf, size);
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_mem_write failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void i386_emulator::mem_write(uint32_t address, const std::vector<uint8_t>& buf) {
|
||||
mem_write(address, buf.data(), buf.size());
|
||||
}
|
||||
|
||||
void i386_emulator::hook_del(uc_hook hook_handle) {
|
||||
auto iter_of_hook_stub_ctxs = m_unicorn_hook_stub_ctxs.find(hook_handle);
|
||||
if (iter_of_hook_stub_ctxs == m_unicorn_hook_stub_ctxs.end()) {
|
||||
throw exceptions::key_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Target hook is not found.");
|
||||
}
|
||||
|
||||
auto iter_of_hook_callbacks = m_unicorn_hook_callbacks.find(hook_handle);
|
||||
if (iter_of_hook_callbacks != m_unicorn_hook_callbacks.end()) {
|
||||
auto err = uc_hook_del(m_unicorn_engine.get(), hook_handle);
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"hook_del failed.");
|
||||
}
|
||||
|
||||
m_unicorn_hook_callbacks.erase(iter_of_hook_callbacks);
|
||||
m_unicorn_hook_stub_ctxs.erase(iter_of_hook_stub_ctxs);
|
||||
return;
|
||||
}
|
||||
|
||||
__assume(false);
|
||||
}
|
||||
|
||||
void i386_emulator::create_gdt_entry(uint32_t gdt_entry_address, uint32_t base, uint32_t limit, uint8_t access_byte, uint8_t flags) {
|
||||
struct {
|
||||
uint64_t limit0 : 16;
|
||||
uint64_t base0 : 24;
|
||||
uint64_t access_byte : 8;
|
||||
uint64_t limit1 : 4;
|
||||
uint64_t flags : 4;
|
||||
uint64_t base1 : 8;
|
||||
} gdt_entry;
|
||||
|
||||
gdt_entry.limit0 = limit & 0xffff;
|
||||
gdt_entry.base0 = base & 0xffffff;
|
||||
gdt_entry.access_byte = access_byte;
|
||||
gdt_entry.flags = flags & 0xf;
|
||||
gdt_entry.base1 = (base & 0xff000000) >> 24;
|
||||
|
||||
mem_write(gdt_entry_address, &gdt_entry, sizeof(gdt_entry));
|
||||
}
|
||||
|
||||
void i386_emulator::emu_start(uint32_t begin_address, uint32_t end_address, uint64_t timeout, size_t count) {
|
||||
auto err = uc_emu_start(m_unicorn_engine.get(), begin_address, end_address, timeout, count);
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"emu_start failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void i386_emulator::emu_stop() {
|
||||
auto err = uc_emu_stop(m_unicorn_engine.get());
|
||||
if (err) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_emu_stop failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
152
navicat-patcher/i386_emulator.hpp
Normal file
152
navicat-patcher/i386_emulator.hpp
Normal file
@ -0,0 +1,152 @@
|
||||
#pragma once
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <unicorn/unicorn.h>
|
||||
|
||||
#include <any>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
|
||||
#include "resource_wrapper.hpp"
|
||||
#include "resource_traits/unicorn/unicorn_handle.hpp"
|
||||
|
||||
#include "exception.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-patcher\\i386_emulator.hpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class i386_emulator {
|
||||
public:
|
||||
class backend_error : public ::nkg::exception {
|
||||
public:
|
||||
using error_code_t = uc_err;
|
||||
|
||||
private:
|
||||
error_code_t m_error_code;
|
||||
std::string m_error_string;
|
||||
|
||||
public:
|
||||
backend_error(std::string_view file, int line, error_code_t unicorn_err, std::string_view message) noexcept :
|
||||
::nkg::exception(file, line, message), m_error_code(unicorn_err), m_error_string(uc_strerror(unicorn_err)) {}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool error_code_exists() const noexcept override {
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual intptr_t error_code() const noexcept override {
|
||||
return m_error_code;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual const std::string& error_string() const noexcept override {
|
||||
return m_error_string;
|
||||
}
|
||||
};
|
||||
|
||||
using hookcode_cb_t = void(uint32_t address, size_t size);
|
||||
using hookmem_cb_t = void(uc_mem_type type, uint32_t address, size_t size, int32_t value);
|
||||
using eventmem_cb_t = bool(uc_mem_type type, uint32_t address, size_t size, int32_t value);
|
||||
|
||||
private:
|
||||
struct hook_stub_context_t {
|
||||
i386_emulator* self;
|
||||
uc_hook unicorn_hook_handle;
|
||||
};
|
||||
|
||||
resource_wrapper<resource_traits::unicorn::unicorn_handle> m_unicorn_engine;
|
||||
std::unordered_map<std::string, std::any> m_unicorn_user_ctx;
|
||||
|
||||
std::unordered_map<uc_hook, std::unique_ptr<hook_stub_context_t>> m_unicorn_hook_stub_ctxs;
|
||||
std::unordered_map<uc_hook, std::any> m_unicorn_hook_callbacks;
|
||||
|
||||
static void _unicorn_hookcode_cb_stub(uc_engine* uc, uint64_t address, uint32_t size, void* user_data);
|
||||
static void _unicorn_hookmem_cb_stub(uc_engine* uc, uc_mem_type type, uint64_t address, int size, int64_t value, void* user_data);
|
||||
static bool _unicorn_eventmem_cb_stub(uc_engine* uc, uc_mem_type type, uint64_t address, int size, int64_t value, void* user_data);
|
||||
|
||||
public:
|
||||
i386_emulator();
|
||||
|
||||
void reg_read(int regid, void* value);
|
||||
|
||||
void reg_write(int regid, const void* value);
|
||||
|
||||
void mem_map(uint32_t address, size_t size, uint32_t perms);
|
||||
|
||||
void mem_unmap(uint32_t address, size_t size);
|
||||
|
||||
void mem_read(uint32_t address, void* buf, size_t size);
|
||||
|
||||
std::vector<uint8_t> mem_read(uint32_t address, size_t size);
|
||||
|
||||
void mem_write(uint32_t address, const void* buf, size_t size);
|
||||
|
||||
void mem_write(uint32_t address, const std::vector<uint8_t>& buf);
|
||||
|
||||
template<int hook_type, typename callable_t>
|
||||
uc_hook hook_add(callable_t&& hook_callback, uint32_t begin_address = 1, uint32_t end_address = 0) {
|
||||
uc_err err;
|
||||
|
||||
auto hook_stub_ctx = std::make_unique<hook_stub_context_t>();
|
||||
hook_stub_ctx->self = this;
|
||||
hook_stub_ctx->unicorn_hook_handle = 0;
|
||||
|
||||
if constexpr (hook_type == UC_HOOK_CODE) {
|
||||
err = uc_hook_add(m_unicorn_engine.get(), &hook_stub_ctx->unicorn_hook_handle, hook_type, _unicorn_hookcode_cb_stub, hook_stub_ctx.get(), begin_address, end_address);
|
||||
if (err != UC_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_hook_add failed.");
|
||||
}
|
||||
|
||||
m_unicorn_hook_callbacks.emplace(std::make_pair(hook_stub_ctx->unicorn_hook_handle, std::function<hookcode_cb_t>{ std::forward<callable_t>(hook_callback) }));
|
||||
} else if constexpr ((hook_type & ~UC_HOOK_MEM_VALID) == 0) {
|
||||
err = uc_hook_add(m_unicorn_engine.get(), &hook_stub_ctx->unicorn_hook_handle, hook_type, _unicorn_hookmem_cb_stub, hook_stub_ctx.get(), begin_address, end_address);
|
||||
if (err != UC_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_hook_add failed.");
|
||||
}
|
||||
|
||||
m_unicorn_hook_callbacks.emplace(std::make_pair(hook_stub_ctx->unicorn_hook_handle, std::function<hookmem_cb_t>{ std::forward<callable_t>(hook_callback) }));
|
||||
} else if constexpr ((hook_type & ~UC_HOOK_MEM_UNMAPPED) == 0) {
|
||||
err = uc_hook_add(m_unicorn_engine.get(), &hook_stub_ctx->unicorn_hook_handle, hook_type, _unicorn_eventmem_cb_stub, hook_stub_ctx.get(), begin_address, end_address);
|
||||
if (err != UC_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"uc_hook_add failed.");
|
||||
}
|
||||
|
||||
m_unicorn_hook_callbacks.emplace(std::make_pair(hook_stub_ctx->unicorn_hook_handle, std::function<eventmem_cb_t>{ std::forward<callable_t>(hook_callback) }));
|
||||
} else {
|
||||
static_assert(
|
||||
hook_type == UC_HOOK_CODE ||
|
||||
(hook_type & ~UC_HOOK_MEM_VALID) == 0 ||
|
||||
(hook_type & ~UC_HOOK_MEM_UNMAPPED) == 0, "Unsupported hook type.");
|
||||
}
|
||||
|
||||
return m_unicorn_hook_stub_ctxs.emplace(std::make_pair(hook_stub_ctx->unicorn_hook_handle, std::move(hook_stub_ctx))).first->first;
|
||||
}
|
||||
|
||||
void hook_del(uc_hook hook_handle);
|
||||
|
||||
void create_gdt_entry(uint32_t gdt_entry_address, uint32_t base, uint32_t limit, uint8_t access_byte, uint8_t flags);
|
||||
|
||||
void emu_start(uint32_t begin_address, uint32_t end_address = 0, uint64_t timeout = 0, size_t count = 0);
|
||||
|
||||
void emu_stop();
|
||||
|
||||
template<typename val_t>
|
||||
void context_set(const std::string& name, val_t&& value) {
|
||||
m_unicorn_user_ctx[name] = std::forward<val_t>(value);
|
||||
}
|
||||
|
||||
template<typename val_t>
|
||||
val_t context_get(const std::string& name) {
|
||||
return std::any_cast<val_t>(m_unicorn_user_ctx[name]);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
302
navicat-patcher/image_interpreter.cpp
Normal file
302
navicat-patcher/image_interpreter.cpp
Normal file
@ -0,0 +1,302 @@
|
||||
#include "image_interpreter.hpp"
|
||||
#include <fmt/format.h>
|
||||
#include "exceptions/index_exception.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-patcher\\image_interpreter.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
image_interpreter::image_interpreter() :
|
||||
m_dos_header(nullptr),
|
||||
m_nt_headers(nullptr),
|
||||
m_section_header_table(nullptr),
|
||||
m_vs_fixed_file_info(nullptr) {}
|
||||
|
||||
[[nodiscard]]
|
||||
image_interpreter image_interpreter::parse(void* image_base, bool parse_relocation) {
|
||||
image_interpreter new_image;
|
||||
|
||||
new_image.m_dos_header = reinterpret_cast<PIMAGE_DOS_HEADER>(image_base);
|
||||
if (new_image.m_dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Invalid image: DOS signature check failure")
|
||||
.push_hint(u8"Are you sure you DO provide a valid WinPE file?");
|
||||
}
|
||||
|
||||
new_image.m_nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS>(reinterpret_cast<uint8_t*>(image_base) + new_image.m_dos_header->e_lfanew);
|
||||
if (new_image.m_nt_headers->Signature != IMAGE_NT_SIGNATURE) {
|
||||
throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Invalid image: NT signature check failure")
|
||||
.push_hint(u8"Are you sure you DO provide a valid WinPE file?");
|
||||
}
|
||||
|
||||
#if defined(_M_AMD64)
|
||||
if (new_image.m_nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
||||
throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Invalid image: optional header magic check failure")
|
||||
.push_hint(u8"Are you sure you DO provide a valid 64-bits WinPE file?");
|
||||
}
|
||||
if (new_image.m_nt_headers->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) {
|
||||
throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Invalid image: machine check failure")
|
||||
.push_hint(u8"Are you sure you DO provide a valid 64-bits WinPE file?");
|
||||
}
|
||||
#elif defined(_M_IX86)
|
||||
if (new_image.m_nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||||
throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Invalid Image. (Optional header magic check failure)")
|
||||
.push_hint(u8"Are you sure you DO provide a valid 32-bits WinPE file?");
|
||||
}
|
||||
if (new_image.m_nt_headers->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) {
|
||||
throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Invalid Image. (Machine check failure)")
|
||||
.push_hint(u8"Are you sure you DO provide a valid 32-bits WinPE file?");
|
||||
}
|
||||
#else
|
||||
#error "image_interpreter.cpp: unsupported architecture."
|
||||
#endif
|
||||
|
||||
new_image.m_section_header_table =
|
||||
reinterpret_cast<PIMAGE_SECTION_HEADER>(reinterpret_cast<char*>(&new_image.m_nt_headers->OptionalHeader) + new_image.m_nt_headers->FileHeader.SizeOfOptionalHeader);
|
||||
|
||||
for (WORD i = 0; i < new_image.m_nt_headers->FileHeader.NumberOfSections; ++i) {
|
||||
auto section_name = make_section_name(new_image.m_section_header_table[i].Name);
|
||||
|
||||
if (new_image.m_section_header_name_lookup_table.find(section_name) == new_image.m_section_header_name_lookup_table.end()) {
|
||||
new_image.m_section_header_name_lookup_table[section_name] = &new_image.m_section_header_table[i];
|
||||
}
|
||||
|
||||
new_image.m_section_header_rva_lookup_table[new_image.m_section_header_table[i].VirtualAddress] = &new_image.m_section_header_table[i];
|
||||
new_image.m_section_header_fo_lookup_table[new_image.m_section_header_table[i].PointerToRawData] = &new_image.m_section_header_table[i];
|
||||
}
|
||||
|
||||
if (parse_relocation && new_image.m_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0) {
|
||||
auto relocation_table =
|
||||
new_image.convert_rva_to_ptr<PIMAGE_BASE_RELOCATION>(new_image.m_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
|
||||
|
||||
while (relocation_table->VirtualAddress != 0) {
|
||||
rva_t rva = relocation_table->VirtualAddress;
|
||||
auto reloc_items = reinterpret_cast<WORD*>(relocation_table + 1);
|
||||
auto reloc_items_count = (relocation_table->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
|
||||
|
||||
for (DWORD i = 0; i < reloc_items_count; ++i) {
|
||||
auto reloc_type = reloc_items[i] >> 12;
|
||||
|
||||
switch (reloc_type) {
|
||||
case IMAGE_REL_BASED_ABSOLUTE:
|
||||
break;
|
||||
case IMAGE_REL_BASED_HIGH:
|
||||
case IMAGE_REL_BASED_LOW:
|
||||
case IMAGE_REL_BASED_HIGHADJ:
|
||||
new_image.m_relocation_rva_lookup_table[rva + (reloc_items[i] & 0x0fff)] = 2;
|
||||
break;
|
||||
case IMAGE_REL_BASED_HIGHLOW:
|
||||
new_image.m_relocation_rva_lookup_table[rva + (reloc_items[i] & 0x0fff)] = 4;
|
||||
break;
|
||||
#if defined(IMAGE_REL_BASED_DIR64)
|
||||
case IMAGE_REL_BASED_DIR64:
|
||||
new_image.m_relocation_rva_lookup_table[rva + (reloc_items[i] & 0x0fff)] = 8;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
relocation_table = reinterpret_cast<PIMAGE_BASE_RELOCATION>(&reloc_items[reloc_items_count]);
|
||||
}
|
||||
}
|
||||
|
||||
if (new_image.m_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) {
|
||||
rva_t import_rva = new_image.m_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
|
||||
|
||||
auto import_descriptors = new_image.convert_rva_to_ptr<PIMAGE_IMPORT_DESCRIPTOR>(import_rva);
|
||||
for (size_t i = 0; import_descriptors[i].OriginalFirstThunk != 0; ++i) {
|
||||
auto import_lookup_table = new_image.convert_rva_to_ptr<PIMAGE_THUNK_DATA>(import_descriptors[i].OriginalFirstThunk);
|
||||
rva_t import_address_table_rva = import_descriptors[i].FirstThunk;
|
||||
|
||||
for (size_t j = 0; import_lookup_table[j].u1.Ordinal != 0; ++j) {
|
||||
new_image.m_iat_rva_lookup_table[import_address_table_rva + j * sizeof(IMAGE_THUNK_DATA)] = std::make_pair(&import_descriptors[i], &import_lookup_table[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (new_image.m_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress) {
|
||||
rva_t resource_rva = new_image.m_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
|
||||
|
||||
auto res_type_directory = new_image.convert_rva_to_ptr<PIMAGE_RESOURCE_DIRECTORY>(resource_rva);
|
||||
auto res_type_name_entries = reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY_ENTRY>(res_type_directory + 1);
|
||||
auto res_type_id_entries = res_type_name_entries + res_type_directory->NumberOfNamedEntries;
|
||||
|
||||
for (WORD i = 0; i < res_type_directory->NumberOfIdEntries && new_image.m_vs_fixed_file_info == nullptr; ++i) {
|
||||
if (res_type_id_entries[i].Id == reinterpret_cast<uintptr_t>(RT_VERSION) && res_type_id_entries[i].DataIsDirectory) {
|
||||
auto res_name_directory = new_image.convert_rva_to_ptr<PIMAGE_RESOURCE_DIRECTORY>(resource_rva + res_type_id_entries[i].OffsetToDirectory);
|
||||
auto res_name_name_entries = reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY_ENTRY>(res_name_directory + 1);
|
||||
auto res_name_id_entries = res_name_name_entries + res_name_directory->NumberOfNamedEntries;
|
||||
|
||||
for (WORD j = 0; j < res_name_directory->NumberOfIdEntries && new_image.m_vs_fixed_file_info == nullptr; ++j) {
|
||||
if (res_name_id_entries[j].Id == VS_VERSION_INFO && res_name_id_entries[j].DataIsDirectory) {
|
||||
auto res_lang_directory = new_image.convert_rva_to_ptr<PIMAGE_RESOURCE_DIRECTORY>(resource_rva + res_name_id_entries[j].OffsetToDirectory);
|
||||
auto res_lang_name_entries = reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY_ENTRY>(res_lang_directory + 1);
|
||||
auto res_lang_id_entries = res_lang_name_entries + res_lang_directory->NumberOfNamedEntries;
|
||||
|
||||
for (WORD k = 0; k < res_lang_directory->NumberOfIdEntries && new_image.m_vs_fixed_file_info == nullptr; ++k) {
|
||||
constexpr WORD neutral_lang_id = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
|
||||
constexpr WORD english_lang_id = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
|
||||
|
||||
if ((res_lang_id_entries[k].Id == neutral_lang_id || res_lang_id_entries[k].Id == english_lang_id) && !res_lang_id_entries[k].DataIsDirectory) {
|
||||
auto res_data_entry = new_image.convert_rva_to_ptr<PIMAGE_RESOURCE_DATA_ENTRY>(resource_rva + res_lang_id_entries[k].OffsetToData);
|
||||
|
||||
auto vs_version_info = new_image.convert_rva_to_ptr<PBYTE>(res_data_entry->OffsetToData);
|
||||
auto vs_version_info_key = reinterpret_cast<PWSTR>(vs_version_info + 6); // vs_version_info->szKey
|
||||
if (_wcsicmp(vs_version_info_key, L"VS_VERSION_INFO") == 0) {
|
||||
auto p = reinterpret_cast<PBYTE>(vs_version_info_key + _countof(L"VS_VERSION_INFO"));
|
||||
while (new_image.convert_ptr_to_rva(p) % sizeof(DWORD)) {
|
||||
++p;
|
||||
}
|
||||
|
||||
auto vs_fixed_file_info = reinterpret_cast<VS_FIXEDFILEINFO*>(p);
|
||||
|
||||
if (vs_fixed_file_info->dwSignature == VS_FFI_SIGNATURE) {
|
||||
new_image.m_vs_fixed_file_info = vs_fixed_file_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new_image;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_DOS_HEADER image_interpreter::image_dos_header() const noexcept {
|
||||
return m_dos_header;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_NT_HEADERS image_interpreter::image_nt_headers() const noexcept {
|
||||
return m_nt_headers;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER image_interpreter::image_section_header_table() const noexcept {
|
||||
return m_section_header_table;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER image_interpreter::image_section_header(size_t n) const {
|
||||
if (n < m_nt_headers->FileHeader.NumberOfSections) {
|
||||
return m_section_header_table + n;
|
||||
} else {
|
||||
throw exceptions::index_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Section index is out of range.");
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER image_interpreter::image_section_header(std::string_view section_name) const {
|
||||
if (section_name.length() <= 8) {
|
||||
std::array<BYTE, 8> name{};
|
||||
|
||||
std::copy(section_name.begin(), section_name.end(), name.begin());
|
||||
|
||||
auto it = m_section_header_name_lookup_table.find(name);
|
||||
if (it != m_section_header_name_lookup_table.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
throw exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format(u8"Target section header is not found: section_name = {}", section_name));
|
||||
}
|
||||
} else {
|
||||
throw exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Target section header is not found: section_name is too long.");
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER image_interpreter::image_section_header_from_rva(rva_t rva) const {
|
||||
auto it = m_section_header_rva_lookup_table.upper_bound(rva);
|
||||
if (it != m_section_header_rva_lookup_table.begin()) {
|
||||
--it;
|
||||
}
|
||||
|
||||
rva_t section_rva_begin = it->second->VirtualAddress;
|
||||
rva_t section_rva_end = section_rva_begin + it->second->Misc.VirtualSize;
|
||||
|
||||
if (section_rva_begin <= rva && rva < section_rva_end) {
|
||||
return it->second;
|
||||
} else {
|
||||
throw exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Target section header is not found.")
|
||||
.push_hint(fmt::format("rva = 0x{:x}", rva));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER image_interpreter::image_section_header_from_va(va_t va) const {
|
||||
return image_section_header_from_rva(static_cast<rva_t>(va - m_nt_headers->OptionalHeader.ImageBase));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER image_interpreter::image_section_header_from_fo(fo_t file_offset) const {
|
||||
auto it = m_section_header_fo_lookup_table.upper_bound(file_offset);
|
||||
if (it != m_section_header_fo_lookup_table.begin()) {
|
||||
--it;
|
||||
}
|
||||
|
||||
uintptr_t section_fo_begin = it->second->PointerToRawData;
|
||||
uintptr_t section_fo_end = section_fo_begin + it->second->SizeOfRawData;
|
||||
|
||||
if (section_fo_begin <= file_offset && file_offset < section_fo_end) {
|
||||
return it->second;
|
||||
} else {
|
||||
throw exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Target section header is not found.")
|
||||
.push_hint(fmt::format(u8"file_offset = 0x{:x}", file_offset));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
image_interpreter::va_t image_interpreter::convert_rva_to_va(rva_t rva) const noexcept {
|
||||
return rva + m_nt_headers->OptionalHeader.ImageBase;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
image_interpreter::fo_t image_interpreter::convert_rva_to_fo(rva_t rva) const {
|
||||
auto section_header = image_section_header_from_rva(rva);
|
||||
return section_header->PointerToRawData + (rva - static_cast<uintptr_t>(section_header->VirtualAddress));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
image_interpreter::rva_t image_interpreter::convert_fo_to_rva(fo_t file_offset) const {
|
||||
auto section_header = image_section_header_from_fo(file_offset);
|
||||
return section_header->VirtualAddress + (file_offset - section_header->PointerToRawData);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
image_interpreter::va_t image_interpreter::convert_fo_to_va(fo_t file_offset) const {
|
||||
return convert_fo_to_rva(file_offset) + m_nt_headers->OptionalHeader.ImageBase;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
image_interpreter::rva_t image_interpreter::convert_va_to_rva(va_t va) const noexcept {
|
||||
return va - m_nt_headers->OptionalHeader.ImageBase;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
image_interpreter::fo_t image_interpreter::convert_va_to_fo(va_t va) const {
|
||||
return image_section_header_from_va(va)->PointerToRawData;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
size_t image_interpreter::number_of_sections() const noexcept {
|
||||
return m_nt_headers->FileHeader.NumberOfSections;
|
||||
}
|
||||
|
||||
PIMAGE_IMPORT_DESCRIPTOR image_interpreter::import_descriptor_from_rva(rva_t rva) {
|
||||
auto it = m_iat_rva_lookup_table.find(rva);
|
||||
return it != m_iat_rva_lookup_table.end() ? it->second.first : nullptr;
|
||||
}
|
||||
|
||||
PIMAGE_THUNK_DATA image_interpreter::import_lookup_entry_from_rva(rva_t rva) {
|
||||
auto it = m_iat_rva_lookup_table.find(rva);
|
||||
return it != m_iat_rva_lookup_table.end() ? it->second.second : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
202
navicat-patcher/image_interpreter.hpp
Normal file
202
navicat-patcher/image_interpreter.hpp
Normal file
@ -0,0 +1,202 @@
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <windows.h>
|
||||
|
||||
#include "exception.hpp"
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class image_interpreter {
|
||||
public:
|
||||
using va_t = uintptr_t;
|
||||
using rva_t = uintptr_t;
|
||||
using fo_t = uintptr_t;
|
||||
|
||||
private:
|
||||
PIMAGE_DOS_HEADER m_dos_header;
|
||||
PIMAGE_NT_HEADERS m_nt_headers;
|
||||
PIMAGE_SECTION_HEADER m_section_header_table;
|
||||
|
||||
std::map<std::array<BYTE, 8>, PIMAGE_SECTION_HEADER> m_section_header_name_lookup_table;
|
||||
std::map<rva_t, PIMAGE_SECTION_HEADER> m_section_header_rva_lookup_table;
|
||||
std::map<fo_t, PIMAGE_SECTION_HEADER> m_section_header_fo_lookup_table;
|
||||
|
||||
std::map<rva_t, size_t> m_relocation_rva_lookup_table;
|
||||
|
||||
std::map<rva_t, std::pair<PIMAGE_IMPORT_DESCRIPTOR, PIMAGE_THUNK_DATA>> m_iat_rva_lookup_table;
|
||||
|
||||
VS_FIXEDFILEINFO* m_vs_fixed_file_info;
|
||||
|
||||
image_interpreter();
|
||||
|
||||
static std::array<BYTE, 8> make_section_name(const BYTE (&name)[8]) {
|
||||
std::array<BYTE, 8> retval;
|
||||
std::copy(std::begin(name), std::end(name), retval.begin());
|
||||
return retval;
|
||||
}
|
||||
|
||||
public:
|
||||
class parse_error : public ::nkg::exception {
|
||||
public:
|
||||
parse_error(std::string_view file, int line, std::string_view message) noexcept :
|
||||
::nkg::exception(file, line, message) {}
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
static image_interpreter parse(void* image_base, bool parse_relocation);
|
||||
|
||||
template<typename ptr_t = void*>
|
||||
[[nodiscard]]
|
||||
ptr_t image_base() const noexcept {
|
||||
static_assert(std::is_pointer_v<ptr_t>);
|
||||
return reinterpret_cast<ptr_t>(m_dos_header);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_DOS_HEADER image_dos_header() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_NT_HEADERS image_nt_headers() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER image_section_header_table() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER image_section_header(size_t n) const;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER image_section_header(std::string_view name) const;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER image_section_header_from_rva(rva_t rva) const;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER image_section_header_from_va(va_t va) const;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER image_section_header_from_fo(fo_t file_offset) const;
|
||||
|
||||
[[nodiscard]]
|
||||
va_t convert_rva_to_va(rva_t rva) const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
fo_t convert_rva_to_fo(rva_t rva) const;
|
||||
|
||||
template<typename ptr_t = void*>
|
||||
[[nodiscard]]
|
||||
ptr_t convert_rva_to_ptr(rva_t rva) const {
|
||||
static_assert(std::is_pointer_v<ptr_t>);
|
||||
return convert_fo_to_ptr<ptr_t>(convert_rva_to_fo(rva));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
rva_t convert_fo_to_rva(fo_t file_offset) const;
|
||||
|
||||
[[nodiscard]]
|
||||
va_t convert_fo_to_va(fo_t file_offset) const;
|
||||
|
||||
template<typename ptr_t>
|
||||
[[nodiscard]]
|
||||
ptr_t convert_fo_to_ptr(fo_t file_offset) const noexcept {
|
||||
static_assert(std::is_pointer_v<ptr_t>);
|
||||
return reinterpret_cast<ptr_t>(image_base<char*>() + file_offset);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
rva_t convert_va_to_rva(va_t va) const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
fo_t convert_va_to_fo(va_t va) const;
|
||||
|
||||
template<typename ptr_t>
|
||||
[[nodiscard]]
|
||||
ptr_t convert_va_to_ptr(va_t va) const noexcept {
|
||||
return convert_rva_to_ptr<ptr_t>(convert_va_to_rva(va));
|
||||
}
|
||||
|
||||
template<typename ptr_t>
|
||||
[[nodiscard]]
|
||||
fo_t convert_ptr_to_fo(ptr_t ptr) const noexcept {
|
||||
static_assert(std::is_pointer_v<ptr_t>);
|
||||
return reinterpret_cast<const volatile char*>(ptr) - image_base<const volatile char*>();
|
||||
}
|
||||
|
||||
template<typename ptr_t>
|
||||
[[nodiscard]]
|
||||
rva_t convert_ptr_to_rva(ptr_t ptr) const {
|
||||
return convert_fo_to_rva(convert_ptr_to_fo(ptr));
|
||||
}
|
||||
|
||||
template<typename ptr_t>
|
||||
[[nodiscard]]
|
||||
va_t convert_ptr_to_va(ptr_t ptr) const {
|
||||
return convert_fo_to_va(convert_ptr_to_fo(ptr));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
size_t number_of_sections() const noexcept;
|
||||
|
||||
template<typename ptr_t = void*>
|
||||
[[nodiscard]]
|
||||
ptr_t image_section_view(size_t n, size_t offset = 0) const {
|
||||
static_assert(std::is_pointer_v<ptr_t>);
|
||||
return reinterpret_cast<ptr_t>(image_base<char*>() + image_section_header(n)->PointerToRawData + offset);
|
||||
}
|
||||
|
||||
template<typename ptr_t = void*>
|
||||
[[nodiscard]]
|
||||
ptr_t image_section_view(std::string_view section_name, size_t offset = 0) const {
|
||||
static_assert(std::is_pointer_v<ptr_t>);
|
||||
return reinterpret_cast<ptr_t>(image_base<char*>() + image_section_header(section_name)->PointerToRawData + offset);
|
||||
}
|
||||
|
||||
template<typename ptr_t, typename pred_func_t>
|
||||
[[nodiscard]]
|
||||
ptr_t search_section(size_t n, pred_func_t&& pred_func) const {
|
||||
static_assert(std::is_pointer_v<ptr_t>);
|
||||
|
||||
auto section_header = image_section_header(n);
|
||||
|
||||
auto begin = image_base<const uint8_t*>() + section_header->PointerToRawData;
|
||||
auto end = begin + section_header->Misc.VirtualSize;
|
||||
|
||||
for (; begin < end; ++begin) {
|
||||
if (pred_func(begin, end - begin)) {
|
||||
return reinterpret_cast<ptr_t>(const_cast<uint8_t*>(begin));
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename ptr_t, typename pred_func_t>
|
||||
[[nodiscard]]
|
||||
ptr_t search_section(std::string_view section_name, pred_func_t&& pred_func) const {
|
||||
static_assert(std::is_pointer_v<ptr_t>);
|
||||
|
||||
auto section_header = image_section_header(section_name);
|
||||
|
||||
auto begin = image_base<const uint8_t*>() + section_header->PointerToRawData;
|
||||
auto end = begin + section_header->Misc.VirtualSize;
|
||||
|
||||
for (; begin < end; ++begin) {
|
||||
if (pred_func(begin, end - begin)) {
|
||||
return reinterpret_cast<ptr_t>(const_cast<uint8_t*>(begin));
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PIMAGE_IMPORT_DESCRIPTOR import_descriptor_from_rva(rva_t rva);
|
||||
|
||||
PIMAGE_THUNK_DATA import_lookup_entry_from_rva(rva_t rva);
|
||||
|
||||
auto& relocation_distribute() {
|
||||
return m_relocation_rva_lookup_table;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
38
navicat-patcher/keystone_assembler.cpp
Normal file
38
navicat-patcher/keystone_assembler.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include "keystone_assembler.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-patcher\\keystone_assembler.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
keystone_assembler::keystone_assembler(ks_arch architecture, ks_mode mode) {
|
||||
auto err = ks_open(architecture, mode, m_keystone_engine.unsafe_addressof());
|
||||
if (err != KS_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"ks_open failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void keystone_assembler::option(ks_opt_type option_type, size_t option_value) {
|
||||
auto err = ks_option(m_keystone_engine.get(), option_type, option_value);
|
||||
if (err != KS_ERR_OK) {
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"ks_option failed.");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> keystone_assembler::assemble(std::string_view asm_string, uint64_t asm_address) const {
|
||||
resource_wrapper machine_code{ resource_traits::keystone::keystone_alloc{} };
|
||||
size_t machine_code_size = 0;
|
||||
size_t stat_count = 0;
|
||||
|
||||
if (ks_asm(m_keystone_engine.get(), asm_string.data(), asm_address, machine_code.unsafe_addressof(), &machine_code_size, &stat_count) < 0) {
|
||||
auto err = ks_errno(m_keystone_engine.get());
|
||||
throw backend_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, u8"ks_option failed.");
|
||||
}
|
||||
|
||||
return std::vector<uint8_t>(machine_code.get(), machine_code.get() + machine_code_size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
54
navicat-patcher/keystone_assembler.hpp
Normal file
54
navicat-patcher/keystone_assembler.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <keystone/keystone.h>
|
||||
|
||||
#include "resource_wrapper.hpp"
|
||||
#include "resource_traits/keystone/keystone_handle.hpp"
|
||||
|
||||
#include "exception.hpp"
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class keystone_assembler {
|
||||
public:
|
||||
class backend_error : public ::nkg::exception {
|
||||
public:
|
||||
using error_code_t = ks_err;
|
||||
|
||||
private:
|
||||
error_code_t m_error_code;
|
||||
std::string m_error_string;
|
||||
|
||||
public:
|
||||
backend_error(std::string_view file, int line, error_code_t keystone_err, std::string_view message) noexcept :
|
||||
::nkg::exception(file, line, message), m_error_code(keystone_err), m_error_string(ks_strerror(keystone_err)) {}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool error_code_exists() const noexcept override {
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual intptr_t error_code() const noexcept override {
|
||||
return m_error_code;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual const std::string& error_string() const noexcept override {
|
||||
return m_error_string;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
resource_wrapper<resource_traits::keystone::keystone_handle> m_keystone_engine;
|
||||
|
||||
public:
|
||||
keystone_assembler(ks_arch architecture, ks_mode mode);
|
||||
|
||||
void option(ks_opt_type option_type, size_t option_value);
|
||||
|
||||
std::vector<uint8_t> assemble(std::string_view asm_string, uint64_t asm_address = 0) const;
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
@ -19,35 +19,36 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{30BE8CAB-6137-4441-9F64-599D0A6EEA0C}</ProjectGuid>
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{1b6920eb-e6ed-465f-9600-b5f816752375}</ProjectGuid>
|
||||
<RootNamespace>navicatpatcher</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0</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_xp</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
@ -55,6 +56,7 @@
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
<Import Project="..\common\common.vcxitems" 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" />
|
||||
@ -71,50 +73,44 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>D:\openssl-1.1.0f-vs2015\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>D:\openssl-1.1.0f-vs2015\lib;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>D:\openssl-1.1.0f-vs2015\include64;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>D:\openssl-1.1.0f-vs2015\lib64;$(LibraryPath)</LibraryPath>
|
||||
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\obj\$(PlatformTarget)-$(Configuration)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>D:\openssl-1.1.0f-vs2015\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>D:\openssl-1.1.0f-vs2015\lib;$(LibraryPath)</LibraryPath>
|
||||
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\obj\$(PlatformTarget)-$(Configuration)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\obj\$(PlatformTarget)-$(Configuration)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>D:\openssl-1.1.0f-vs2015\include64;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>D:\openssl-1.1.0f-vs2015\lib64;$(LibraryPath)</LibraryPath>
|
||||
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\obj\$(PlatformTarget)-$(Configuration)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<VcpkgUseStatic>true</VcpkgUseStatic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<VcpkgUseStatic>true</VcpkgUseStatic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<VcpkgUseStatic>true</VcpkgUseStatic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<VcpkgUseStatic>true</VcpkgUseStatic>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<AdditionalOptions>/std:c++latest</AdditionalOptions>
|
||||
</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>
|
||||
<AdditionalOptions>/std:c++latest</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@ -124,15 +120,13 @@
|
||||
<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>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<AdditionalOptions>/std:c++latest</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@ -141,18 +135,30 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<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>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<AdditionalOptions>/std:c++latest</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@ -162,22 +168,41 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="common.cpp" />
|
||||
<ClCompile Include="EncryptPublicKey.cpp" />
|
||||
<ClCompile Include="NavicatCrypto\aes.c" />
|
||||
<ClCompile Include="NavicatCrypto\aes_constant.c" />
|
||||
<ClCompile Include="NavicatCrypto\blowfish.c" />
|
||||
<ClCompile Include="NavicatCrypto\sha1.c" />
|
||||
<ClCompile Include="Solution0.cpp" />
|
||||
<ClCompile Include="Solution1.cpp" />
|
||||
<ClCompile Include="_tmain.cpp" />
|
||||
<ClCompile Include="i386_emulator.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="image_interpreter.cpp" />
|
||||
<ClCompile Include="keystone_assembler.cpp" />
|
||||
<ClCompile Include="patch_solution_since_16.0.7.0.amd64.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="amd64_emulator.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="patch_solution_since_16.0.7.0.generic.cpp" />
|
||||
<ClCompile Include="patch_solution_since_16.0.7.0.i386.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="wmain.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="def.hpp" />
|
||||
<ClInclude Include="NavicatCrypto\aes.h" />
|
||||
<ClInclude Include="NavicatCrypto\blowfish.h" />
|
||||
<ClInclude Include="NavicatCrypto\NavicatCrypto.hpp" />
|
||||
<ClInclude Include="NavicatCrypto\sha1.h" />
|
||||
<ClInclude Include="i386_emulator.hpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="keystone_assembler.hpp" />
|
||||
<ClInclude Include="patch_solution.hpp" />
|
||||
<ClInclude Include="image_interpreter.hpp" />
|
||||
<ClInclude Include="patch_solution_since.hpp" />
|
||||
<ClInclude Include="patch_solution_since_16.0.7.0.hpp" />
|
||||
<ClInclude Include="amd64_emulator.hpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
@ -3,11 +3,11 @@
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;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>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
@ -15,48 +15,51 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="_tmain.cpp">
|
||||
<ClCompile Include="wmain.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NavicatCrypto\aes.c">
|
||||
<ClCompile Include="image_interpreter.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NavicatCrypto\aes_constant.c">
|
||||
<ClCompile Include="patch_solution_since_16.0.7.0.amd64.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NavicatCrypto\blowfish.c">
|
||||
<ClCompile Include="amd64_emulator.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NavicatCrypto\sha1.c">
|
||||
<ClCompile Include="keystone_assembler.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="EncryptPublicKey.cpp">
|
||||
<ClCompile Include="patch_solution_since_16.0.7.0.generic.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Solution0.cpp">
|
||||
<ClCompile Include="i386_emulator.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="common.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Solution1.cpp">
|
||||
<ClCompile Include="patch_solution_since_16.0.7.0.i386.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="NavicatCrypto\aes.h">
|
||||
<ClInclude Include="patch_solution.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NavicatCrypto\blowfish.h">
|
||||
<ClInclude Include="patch_solution_since_16.0.7.0.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NavicatCrypto\NavicatCrypto.hpp">
|
||||
<ClInclude Include="patch_solution_since.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NavicatCrypto\sha1.h">
|
||||
<ClInclude Include="image_interpreter.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="def.hpp">
|
||||
<ClInclude Include="amd64_emulator.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="keystone_assembler.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="i386_emulator.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
||||
6
navicat-patcher/navicat-patcher.vcxproj.user
Normal file
6
navicat-patcher/navicat-patcher.vcxproj.user
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ShowAllFiles>true</ShowAllFiles>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
19
navicat-patcher/patch_solution.hpp
Normal file
19
navicat-patcher/patch_solution.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "rsa_cipher.hpp"
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class patch_solution {
|
||||
public:
|
||||
[[nodiscard]]
|
||||
virtual bool find_patch() = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool check_rsa_privkey(const rsa_cipher& cipher) = 0;
|
||||
|
||||
virtual void make_patch(const rsa_cipher& cipher) = 0;
|
||||
|
||||
virtual ~patch_solution() = default;
|
||||
};
|
||||
|
||||
}
|
||||
9
navicat-patcher/patch_solution_since.hpp
Normal file
9
navicat-patcher/patch_solution_since.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "patch_solution.hpp"
|
||||
|
||||
namespace nkg {
|
||||
|
||||
template<int major_ver0, int major_ver1, int minor_ver0, int minor_ver1>
|
||||
class patch_solution_since;
|
||||
|
||||
}
|
||||
591
navicat-patcher/patch_solution_since_16.0.7.0.amd64.cpp
Normal file
591
navicat-patcher/patch_solution_since_16.0.7.0.amd64.cpp
Normal file
@ -0,0 +1,591 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include "amd64_emulator.hpp"
|
||||
#include "keystone_assembler.hpp"
|
||||
#include "patch_solution_since_16.0.7.0.hpp"
|
||||
#include <algorithm>
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace nkg {
|
||||
|
||||
patch_solution_since<16, 0, 7, 0>::patch_solution_since(image_interpreter& libcc_interpreter) :
|
||||
m_libcc_interpreter(libcc_interpreter),
|
||||
m_va_CSRegistrationInfoFetcher_WIN_vtable(0),
|
||||
m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey(0),
|
||||
m_va_iat_entry_malloc(0) {}
|
||||
|
||||
bool patch_solution_since<16, 0, 7, 0>::find_patch() {
|
||||
auto CSRegistrationInfoFetcher_WIN_type_descriptor_name =
|
||||
m_libcc_interpreter.search_section<const uint8_t*>(
|
||||
".data",
|
||||
[](const uint8_t* p, size_t s) {
|
||||
if (s < sizeof(".?AVCSRegistrationInfoFetcher_WIN@@")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strcmp(reinterpret_cast<const char*>(p), ".?AVCSRegistrationInfoFetcher_WIN@@") == 0;
|
||||
}
|
||||
);
|
||||
|
||||
if (CSRegistrationInfoFetcher_WIN_type_descriptor_name == nullptr) {
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: RTTI info for CSRegistrationInfoFetcher_WIN is not found. (failure label 0)\n");
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_rtti_type_descriptor = CSRegistrationInfoFetcher_WIN_type_descriptor_name - 0x10;
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_rtti_type_descriptor_rva = m_libcc_interpreter.convert_ptr_to_rva(CSRegistrationInfoFetcher_WIN_rtti_type_descriptor);
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_pTypeDescriptor =
|
||||
m_libcc_interpreter.search_section<const uint8_t*>(
|
||||
".rdata",
|
||||
[this, CSRegistrationInfoFetcher_WIN_rtti_type_descriptor_rva](const uint8_t* p, size_t s) {
|
||||
if (reinterpret_cast<uintptr_t>(p) % sizeof(uint32_t) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s < sizeof(uint32_t)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*reinterpret_cast<const uint32_t*>(p) != CSRegistrationInfoFetcher_WIN_rtti_type_descriptor_rva) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s < sizeof(uint32_t) * 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto maybe_CSRegistrationInfoFetcher_WIN_rtti_class_hierarchy_descriptor_rva = reinterpret_cast<const uint32_t*>(p)[1];
|
||||
|
||||
try {
|
||||
return memcmp(m_libcc_interpreter.image_section_header_from_rva(maybe_CSRegistrationInfoFetcher_WIN_rtti_class_hierarchy_descriptor_rva)->Name, ".rdata\x00\x00", 8) == 0;
|
||||
} catch (nkg::exception&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_pTypeDescriptor == nullptr) {
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: RTTI info for CSRegistrationInfoFetcher_WIN is not found. (failure label 1)\n");
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator = CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_pTypeDescriptor - 0xC;
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_va = m_libcc_interpreter.convert_ptr_to_va(CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator);
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_vtable_before =
|
||||
m_libcc_interpreter.search_section<const uint8_t*>(
|
||||
".rdata",
|
||||
[CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_va](const uint8_t* p, size_t s) {
|
||||
if (reinterpret_cast<uintptr_t>(p) % sizeof(uint64_t) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s < sizeof(uint64_t)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return *reinterpret_cast<const uint64_t*>(p) == CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_va;
|
||||
}
|
||||
);
|
||||
|
||||
if (CSRegistrationInfoFetcher_WIN_vtable_before == nullptr) {
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: Vftable for CSRegistrationInfoFetcher_WIN is not found.\n");
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_vtable =
|
||||
reinterpret_cast<const image_interpreter::va_t*>(CSRegistrationInfoFetcher_WIN_vtable_before + sizeof(image_interpreter::va_t));
|
||||
|
||||
m_va_CSRegistrationInfoFetcher_WIN_vtable = m_libcc_interpreter.convert_ptr_to_va(CSRegistrationInfoFetcher_WIN_vtable);
|
||||
m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey = CSRegistrationInfoFetcher_WIN_vtable[6];
|
||||
wprintf(L"[*] patch_solution_since<16, 0, 7, 0>: m_va_CSRegistrationInfoFetcher_WIN_vtable = 0x%016llx\n", m_va_CSRegistrationInfoFetcher_WIN_vtable);
|
||||
wprintf(L"[*] patch_solution_since<16, 0, 7, 0>: m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey = 0x%016llx\n", m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey);
|
||||
|
||||
amd64_emulator x64_emulator;
|
||||
|
||||
x64_emulator.context_set("heap_base", uint64_t{ 0x00007fff00000000 });
|
||||
x64_emulator.context_set("heap_size", size_t{ 0x1000 * 32 });
|
||||
x64_emulator.context_set("heap_records", std::map<uint64_t, uint64_t>{});
|
||||
|
||||
x64_emulator.context_set("stack_base", uint64_t{ 0x00007fffffff0000 });
|
||||
x64_emulator.context_set("stack_size", size_t{ 0x1000 * 32 });
|
||||
x64_emulator.context_set("stack_top", uint64_t{ x64_emulator.context_get<uint64_t>("stack_base") - x64_emulator.context_get<size_t>("stack_size") });
|
||||
|
||||
x64_emulator.context_set("dead_area_base", uint64_t{ 0xfffffffffffff000 });
|
||||
x64_emulator.context_set("dead_area_size", size_t{ 0x1000 });
|
||||
|
||||
x64_emulator.context_set("iat_base", uint64_t{ m_libcc_interpreter.convert_rva_to_va(m_libcc_interpreter.image_nt_headers()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) });
|
||||
x64_emulator.context_set("iat_size", size_t{ m_libcc_interpreter.image_nt_headers()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size });
|
||||
|
||||
x64_emulator.context_set("external_api_stub_area_base", uint64_t{ 0xffff800000000000 });
|
||||
x64_emulator.context_set("external_api_stub_area_size", size_t{ (x64_emulator.context_get<size_t>("iat_size") / 8 + 0xfff) / 0x1000 * 0x1000 });
|
||||
|
||||
x64_emulator.context_set("external_api_impl", std::map<std::string, uint64_t>{});
|
||||
x64_emulator.context_set("external_api_impl_area_base", uint64_t{ 0xffff900000000000 });
|
||||
x64_emulator.context_set("external_api_impl_area_size", size_t{ 0 });
|
||||
|
||||
x64_emulator.context_set("gs_base", uint64_t{ 0xffffa00000000000 });
|
||||
x64_emulator.context_set("gs_size", size_t{ 0x1000 });
|
||||
|
||||
x64_emulator.context_set("start_address", static_cast<uint64_t>(m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey));
|
||||
x64_emulator.context_set("dead_address", x64_emulator.context_get<uint64_t>("dead_area_base"));
|
||||
|
||||
// allocate heap
|
||||
x64_emulator.mem_map(x64_emulator.context_get<uint64_t>("heap_base"), x64_emulator.context_get<size_t>("heap_size"), UC_PROT_READ | UC_PROT_WRITE);
|
||||
|
||||
// allocate stack
|
||||
x64_emulator.mem_map(x64_emulator.context_get<uint64_t>("stack_top"), x64_emulator.context_get<size_t>("stack_size"), UC_PROT_READ | UC_PROT_WRITE);
|
||||
|
||||
// allocate dead area
|
||||
x64_emulator.mem_map(x64_emulator.context_get<uint64_t>("dead_area_base"), x64_emulator.context_get<size_t>("dead_area_size"), UC_PROT_READ | UC_PROT_EXEC);
|
||||
|
||||
// allocate and hook read access to IAT
|
||||
{
|
||||
auto iat_base = x64_emulator.context_get<uint64_t>("iat_base");
|
||||
auto iat_size = x64_emulator.context_get<size_t>("iat_size");
|
||||
auto external_api_stub_area_base = x64_emulator.context_get<uint64_t>("external_api_stub_area_base");
|
||||
|
||||
auto iat_page_base = iat_base / 0x1000 * 0x1000;
|
||||
auto iat_page_count = (iat_base - iat_page_base + iat_size + 0xfff) / 0x1000;
|
||||
|
||||
x64_emulator.mem_map(iat_page_base, iat_page_count * 0x1000, UC_PROT_READ);
|
||||
|
||||
x64_emulator.hook_add<UC_HOOK_MEM_READ>(
|
||||
[this, &x64_emulator, iat_base, external_api_stub_area_base](uc_mem_type type, uint64_t address, size_t size, int64_t value) {
|
||||
auto rva = m_libcc_interpreter.convert_va_to_rva(address);
|
||||
auto import_lookup_entry = m_libcc_interpreter.import_lookup_entry_from_rva(rva);
|
||||
|
||||
if (import_lookup_entry && !IMAGE_SNAP_BY_ORDINAL(import_lookup_entry->u1.Ordinal)) {
|
||||
auto import_by_name_entry = m_libcc_interpreter.convert_rva_to_ptr<PIMAGE_IMPORT_BY_NAME>(import_lookup_entry->u1.AddressOfData);
|
||||
if (strcmp(import_by_name_entry->Name, "memcpy") == 0) {
|
||||
uint64_t impl_address = x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl")["memcpy"];
|
||||
x64_emulator.mem_write(address, &impl_address, sizeof(impl_address));
|
||||
} else if (strcmp(import_by_name_entry->Name, "memcmp") == 0) {
|
||||
uint64_t impl_address = x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl")["memcmp"];
|
||||
x64_emulator.mem_write(address, &impl_address, sizeof(impl_address));
|
||||
} else {
|
||||
uint64_t stub_address = external_api_stub_area_base + (address - iat_base) / sizeof(IMAGE_THUNK_DATA);
|
||||
x64_emulator.mem_write(address, &stub_address, sizeof(stub_address));
|
||||
}
|
||||
} else {
|
||||
x64_emulator.emu_stop();
|
||||
}
|
||||
},
|
||||
iat_base,
|
||||
iat_base + iat_size - 1
|
||||
);
|
||||
}
|
||||
|
||||
// allocate and setup external api stub area
|
||||
{
|
||||
auto external_api_stub_area_base = x64_emulator.context_get<uint64_t>("external_api_stub_area_base");
|
||||
auto external_api_stub_area_size = x64_emulator.context_get<size_t>("external_api_stub_area_size");
|
||||
|
||||
x64_emulator.mem_map(external_api_stub_area_base, external_api_stub_area_size, UC_PROT_READ | UC_PROT_EXEC);
|
||||
x64_emulator.mem_write(external_api_stub_area_base, std::vector<uint8_t>(external_api_stub_area_size, 0xc3)); // c3 -> ret
|
||||
|
||||
x64_emulator.hook_add<UC_HOOK_CODE>(
|
||||
[this, &x64_emulator, external_api_stub_area_base](uint64_t address, size_t size) {
|
||||
auto iat_base = x64_emulator.context_get<uint64_t>("iat_base");
|
||||
auto from_va = iat_base + (address - external_api_stub_area_base) * sizeof(IMAGE_THUNK_DATA);
|
||||
auto from_rva = m_libcc_interpreter.convert_va_to_rva(from_va);
|
||||
|
||||
auto import_lookup_entry = m_libcc_interpreter.import_lookup_entry_from_rva(from_rva);
|
||||
if (import_lookup_entry && !IMAGE_SNAP_BY_ORDINAL(import_lookup_entry->u1.Ordinal)) {
|
||||
auto import_by_name_entry = m_libcc_interpreter.convert_rva_to_ptr<PIMAGE_IMPORT_BY_NAME>(import_lookup_entry->u1.AddressOfData);
|
||||
if (strcmp(import_by_name_entry->Name, "malloc") == 0) {
|
||||
m_va_iat_entry_malloc = from_va;
|
||||
|
||||
uint64_t alloc_size;
|
||||
x64_emulator.reg_read(UC_X86_REG_RCX, &alloc_size);
|
||||
|
||||
auto& heap_records = x64_emulator.context_get<std::map<uint64_t, uint64_t>&>("heap_records");
|
||||
|
||||
auto predecessor_chunk =
|
||||
std::adjacent_find(
|
||||
heap_records.begin(),
|
||||
heap_records.end(),
|
||||
[alloc_size](const auto& chunk0, const auto& chunk1) { return chunk1.first - (chunk0.first + chunk0.second) >= alloc_size; }
|
||||
);
|
||||
|
||||
uint64_t alloc_p;
|
||||
if (predecessor_chunk != heap_records.end()) {
|
||||
alloc_p = predecessor_chunk->first + predecessor_chunk->second;
|
||||
} else {
|
||||
auto heap_base = x64_emulator.context_get<uint64_t>("heap_base");
|
||||
auto heap_size = x64_emulator.context_get<uint64_t>("heap_size");
|
||||
|
||||
auto free_space_base = heap_records.size() > 0 ? heap_records.rbegin()->first + heap_records.rbegin()->second : heap_base;
|
||||
auto free_space_size = heap_base + heap_size - free_space_base;
|
||||
|
||||
if (free_space_size < alloc_size) {
|
||||
auto heap_expand_base = heap_base + heap_size;
|
||||
auto heap_expand_size = (alloc_size - free_space_size + 0xfff) / 0x1000 * 0x1000;
|
||||
x64_emulator.mem_map(heap_expand_base, heap_expand_size, UC_PROT_READ | UC_PROT_WRITE);
|
||||
}
|
||||
|
||||
alloc_p = free_space_base;
|
||||
}
|
||||
|
||||
heap_records[alloc_p] = alloc_size;
|
||||
|
||||
x64_emulator.reg_write(UC_X86_REG_RAX, &alloc_p);
|
||||
} else if (strcmp(import_by_name_entry->Name, "free") == 0) {
|
||||
uint64_t alloc_p;
|
||||
x64_emulator.reg_read(UC_X86_REG_RCX, &alloc_p);
|
||||
|
||||
auto& heap_records = x64_emulator.context_get<std::map<uint64_t, uint64_t>&>("heap_records");
|
||||
|
||||
auto chunk = heap_records.find(alloc_p);
|
||||
if (chunk != heap_records.end()) {
|
||||
heap_records.erase(chunk);
|
||||
} else {
|
||||
x64_emulator.emu_stop();
|
||||
}
|
||||
} else {
|
||||
x64_emulator.emu_stop();
|
||||
}
|
||||
} else {
|
||||
x64_emulator.emu_stop();
|
||||
}
|
||||
},
|
||||
external_api_stub_area_base,
|
||||
external_api_stub_area_base + external_api_stub_area_size - 1
|
||||
);
|
||||
}
|
||||
|
||||
// allocate and setup external api impl area
|
||||
{
|
||||
keystone_assembler x64_assembler{ KS_ARCH_X86, KS_MODE_64 };
|
||||
|
||||
std::map<std::string, std::vector<uint8_t>> machine_code_list =
|
||||
{
|
||||
std::make_pair(
|
||||
"memcpy",
|
||||
x64_assembler.assemble(
|
||||
"push rdi;"
|
||||
"push rsi;"
|
||||
"mov rdi, rcx;"
|
||||
"mov rsi, rdx;"
|
||||
"mov rcx, r8;"
|
||||
"rep movs byte ptr [rdi], byte ptr [rsi];"
|
||||
"pop rsi;"
|
||||
"pop rdi;"
|
||||
"ret;"
|
||||
)
|
||||
),
|
||||
std::make_pair(
|
||||
"memcmp",
|
||||
x64_assembler.assemble(
|
||||
" push rdi;"
|
||||
" push rsi;"
|
||||
" mov rsi, rcx;"
|
||||
" mov rdi, rdx;"
|
||||
" mov rcx, r8;"
|
||||
" cmp rcx, rcx;"
|
||||
" repe cmps byte ptr [rsi], byte ptr [rdi];"
|
||||
" jz cmp_eq;"
|
||||
"cmp_not_eq:"
|
||||
" movsx eax, byte ptr [rsi - 1];"
|
||||
" movsx ecx, byte ptr [rdi - 1];"
|
||||
" sub eax, ecx;"
|
||||
" jmp final;"
|
||||
"cmp_eq:"
|
||||
" xor eax, eax;"
|
||||
"final:"
|
||||
" pop rsi;"
|
||||
" pop rdi;"
|
||||
" ret;"
|
||||
)
|
||||
),
|
||||
std::make_pair(
|
||||
"memmove",
|
||||
x64_assembler.assemble(
|
||||
" push rdi;"
|
||||
" push rsi;"
|
||||
" cmp rdx, rcx;"
|
||||
" jb reverse_copy;"
|
||||
"copy:"
|
||||
" mov rdi, rcx;"
|
||||
" mov rsi, rdx;"
|
||||
" mov rcx, r8;"
|
||||
" rep movsb byte ptr[rdi], byte ptr[rsi];"
|
||||
" jmp final;"
|
||||
"reverse_copy:"
|
||||
" std;"
|
||||
" lea rdi, qword ptr[rcx + r8 - 1];"
|
||||
" lea rsi, qword ptr[rdx + r8 - 1];"
|
||||
" mov rcx, r8;"
|
||||
" rep movsb byte ptr[rdi], byte ptr[rsi];"
|
||||
" cld;"
|
||||
"final:"
|
||||
" pop rsi;"
|
||||
" pop rdi;"
|
||||
" ret;"
|
||||
)
|
||||
)
|
||||
};
|
||||
|
||||
auto& external_api_impl = x64_emulator.context_get<std::map<std::string, uint64_t>&>("external_api_impl");
|
||||
auto& external_api_impl_area_base = x64_emulator.context_get<uint64_t&>("external_api_impl_area_base");
|
||||
auto& external_api_impl_area_size = x64_emulator.context_get<size_t&>("external_api_impl_area_size");
|
||||
|
||||
auto p = external_api_impl_area_base;
|
||||
for (const auto& name_code_pair : machine_code_list) {
|
||||
external_api_impl[name_code_pair.first] = p;
|
||||
p = (p + name_code_pair.second.size() + 0xf) / 0x10 * 0x10;
|
||||
}
|
||||
|
||||
external_api_impl_area_size = (p + 0xfff) / 0x1000 * 0x1000 - external_api_impl_area_base;
|
||||
|
||||
x64_emulator.mem_map(external_api_impl_area_base, external_api_impl_area_size, UC_PROT_READ | UC_PROT_EXEC);
|
||||
for (const auto& name_code_pair : machine_code_list) {
|
||||
x64_emulator.mem_write(external_api_impl[name_code_pair.first], name_code_pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
// allocate and hook access to gs area
|
||||
x64_emulator.mem_map(x64_emulator.context_get<uint64_t>("gs_base"), x64_emulator.context_get<size_t>("gs_size"), UC_PROT_READ | UC_PROT_WRITE);
|
||||
x64_emulator.msr_write(0xC0000101, x64_emulator.context_get<uint64_t>("gs_base")); // set gs base address
|
||||
|
||||
x64_emulator.hook_add<UC_HOOK_MEM_READ>(
|
||||
[this, &x64_emulator](uc_mem_type access, uint64_t address, size_t size, int64_t value) {
|
||||
auto gs_base = x64_emulator.context_get<uint64_t>("gs_base");
|
||||
switch (address - gs_base) {
|
||||
case 0x10: // qword ptr gs:[0x10] -> Stack Limit / Ceiling of stack (low address)
|
||||
{
|
||||
uint64_t val = x64_emulator.context_get<uint64_t>("stack_top");
|
||||
x64_emulator.mem_write(address, &val, size);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
x64_emulator.emu_stop();
|
||||
break;
|
||||
}
|
||||
},
|
||||
x64_emulator.context_get<uint64_t>("gs_base"),
|
||||
x64_emulator.context_get<uint64_t>("gs_base") + x64_emulator.context_get<size_t>("gs_size") - 1
|
||||
);
|
||||
|
||||
// x64_emulator.hook_add<UC_HOOK_CODE>([](uint64_t address, size_t size) { wprintf_s(L"code_trace, address = 0x%016zx\n", address); });
|
||||
|
||||
x64_emulator.hook_add<UC_HOOK_MEM_UNMAPPED>(
|
||||
[this, &x64_emulator](uc_mem_type access, uint64_t address, size_t size, int64_t value) -> bool {
|
||||
try {
|
||||
auto fault_section = m_libcc_interpreter.image_section_header_from_va(address);
|
||||
|
||||
auto page_base = address / 0x1000 * 0x1000;
|
||||
auto page_size = 0x1000;
|
||||
uint32_t page_perms = UC_PROT_NONE;
|
||||
|
||||
if (fault_section->Characteristics & IMAGE_SCN_MEM_READ) {
|
||||
page_perms |= UC_PROT_READ;
|
||||
}
|
||||
if (fault_section->Characteristics & IMAGE_SCN_MEM_WRITE) {
|
||||
page_perms |= UC_PROT_WRITE;
|
||||
}
|
||||
if (fault_section->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
|
||||
page_perms |= UC_PROT_EXEC;
|
||||
}
|
||||
|
||||
x64_emulator.mem_map(page_base, page_size, page_perms);
|
||||
x64_emulator.mem_write(page_base, m_libcc_interpreter.convert_va_to_ptr<const void*>(page_base), page_size);
|
||||
|
||||
return true;
|
||||
} catch (::nkg::exception&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// set rbp, rsp
|
||||
uint64_t init_rbp = x64_emulator.context_get<uint64_t>("stack_base") - x64_emulator.context_get<size_t>("stack_size") / 4;
|
||||
uint64_t init_rsp = x64_emulator.context_get<uint64_t>("stack_base") - x64_emulator.context_get<size_t>("stack_size") / 2;
|
||||
|
||||
x64_emulator.reg_write(UC_X86_REG_RBP, &init_rbp);
|
||||
x64_emulator.reg_write(UC_X86_REG_RSP, &init_rsp);
|
||||
|
||||
// set return address
|
||||
auto retaddr = x64_emulator.context_get<uint64_t>("dead_address");
|
||||
x64_emulator.mem_write(init_rsp, &retaddr, sizeof(retaddr));
|
||||
|
||||
// set argument registers
|
||||
uint64_t init_rcx = 0; // `this` pointer of CSRegistrationInfoFetcher_WIN, but we don't need it for now.
|
||||
uint64_t init_rdx = init_rsp + 0x40; // a pointer to stack memory which stores return value
|
||||
x64_emulator.reg_write(UC_X86_REG_RCX, &init_rcx);
|
||||
x64_emulator.reg_write(UC_X86_REG_RDX, &init_rdx);
|
||||
|
||||
//
|
||||
// start emulate
|
||||
//
|
||||
try {
|
||||
x64_emulator.emu_start(x64_emulator.context_get<uint64_t>("start_address"), x64_emulator.context_get<uint64_t>("dead_address"));
|
||||
} catch (nkg::exception&) {
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: Code emulation failed.\n");
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
wprintf_s(L"[*] patch_solution_since<16, 0, 7, 0>: m_va_iat_entry_malloc = 0x%016llx\n", m_va_iat_entry_malloc);
|
||||
|
||||
//
|
||||
// get result
|
||||
//
|
||||
// on AMD64 platform, `std::string` has follow memory layout:
|
||||
// ------------------------------
|
||||
// | offset | size |
|
||||
// ------------------------------
|
||||
// | +0 | 0x10 | `char[16]: a small string buffer` OR `char*: a large string buffer pointer`
|
||||
// ------------------------------
|
||||
// | +0x10 | 0x8 | size_t: string length
|
||||
// ------------------------------
|
||||
// | +0x18 | 0x8 | size_t: capacity
|
||||
// ------------------------------
|
||||
//
|
||||
uint64_t encoded_key_length;
|
||||
x64_emulator.mem_read(init_rdx + 0x10, &encoded_key_length, sizeof(encoded_key_length));
|
||||
if (encoded_key_length != official_encoded_key.length()) {
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: unexpected encoded key length(%llu).\n", encoded_key_length);
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t encoded_key_ptr;
|
||||
x64_emulator.mem_read(init_rdx, &encoded_key_ptr, sizeof(encoded_key_ptr));
|
||||
|
||||
auto encoded_key = x64_emulator.mem_read(encoded_key_ptr, encoded_key_length);
|
||||
if (memcmp(encoded_key.data(), official_encoded_key.data(), encoded_key.size()) == 0) {
|
||||
wprintf_s(L"[+] patch_solution_since<16, 0, 7, 0>: official encoded key is found.\n");
|
||||
return true;
|
||||
} else {
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: official encoded key is not found.\n");
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool patch_solution_since<16, 0, 7, 0>::check_rsa_privkey(const rsa_cipher& cipher) {
|
||||
return true; // no requirements
|
||||
}
|
||||
|
||||
void patch_solution_since<16, 0, 7, 0>::make_patch(const rsa_cipher& cipher) {
|
||||
auto encoded_key = _build_encoded_key(cipher);
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey =
|
||||
m_libcc_interpreter.convert_va_to_ptr<uint8_t*>(m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey);
|
||||
|
||||
std::vector<std::string> patch_code_chunks;
|
||||
patch_code_chunks.emplace_back("push rdi;");
|
||||
patch_code_chunks.emplace_back("push rsi;");
|
||||
patch_code_chunks.emplace_back("push rbx;");
|
||||
patch_code_chunks.emplace_back("push rbp;");
|
||||
patch_code_chunks.emplace_back("mov rbp, rsp;");
|
||||
patch_code_chunks.emplace_back("mov rbx, rdx;");
|
||||
patch_code_chunks.emplace_back("sub rsp, 0x20;");
|
||||
patch_code_chunks.emplace_back(fmt::format("mov rcx, {:#x};", encoded_key.length() + 1));
|
||||
patch_code_chunks.emplace_back(fmt::format("call qword ptr [{:#016x}];", m_va_iat_entry_malloc));
|
||||
patch_code_chunks.emplace_back("add rsp, 0x20;");
|
||||
{
|
||||
std::vector<uint64_t> push_values((encoded_key.length() + 1 + 7) / 8, 0);
|
||||
memcpy(push_values.data(), encoded_key.data(), encoded_key.length());
|
||||
|
||||
std::for_each(
|
||||
push_values.crbegin(),
|
||||
push_values.crend(),
|
||||
[&patch_code_chunks](uint64_t x) {
|
||||
patch_code_chunks.emplace_back(fmt::format("mov rdx, {:#016x};", x));
|
||||
patch_code_chunks.emplace_back("push rdx;");
|
||||
}
|
||||
);
|
||||
}
|
||||
patch_code_chunks.emplace_back("mov rdi, rax;");
|
||||
patch_code_chunks.emplace_back("mov rsi, rsp;");
|
||||
patch_code_chunks.emplace_back(fmt::format("mov rcx, {:#x};", encoded_key.length() + 1));
|
||||
patch_code_chunks.emplace_back("rep movs byte ptr [rdi], byte ptr [rsi];");
|
||||
patch_code_chunks.emplace_back("mov qword ptr [rbx], rax;");
|
||||
patch_code_chunks.emplace_back(fmt::format("mov qword ptr [rbx + 0x10], {:#x};", encoded_key.length()));
|
||||
patch_code_chunks.emplace_back(fmt::format("mov qword ptr [rbx + 0x18], {:#x};", encoded_key.length() + 1));
|
||||
patch_code_chunks.emplace_back("mov rax, rbx;");
|
||||
patch_code_chunks.emplace_back("leave;");
|
||||
patch_code_chunks.emplace_back("pop rbx;");
|
||||
patch_code_chunks.emplace_back("pop rsi;");
|
||||
patch_code_chunks.emplace_back("pop rdi;");
|
||||
patch_code_chunks.emplace_back("ret;");
|
||||
|
||||
//auto patch_code = keystone_assembler{ KS_ARCH_X86, KS_MODE_64 }
|
||||
// .assemble(
|
||||
// fmt::format(
|
||||
// " push rdi;"
|
||||
// " push rsi;"
|
||||
// " push rbx;"
|
||||
// " mov rbx, rdx;"
|
||||
// "allocate_string_buf:"
|
||||
// " mov rcx, {encoded_key_length:#x} + 1;"
|
||||
// " sub rsp, 0x20;"
|
||||
// " call qword ptr [{m_va_iat_entry_malloc:#x}];"
|
||||
// " add rsp, 0x20;"
|
||||
// "write_our_own_key_to_string_buf:"
|
||||
// " mov rdi, rax;"
|
||||
// " lea rsi, qword ptr [end_of_code + rip];"
|
||||
// " mov rcx, 0x188;"
|
||||
// " rep movs byte ptr [rdi], byte ptr [rsi];"
|
||||
// " mov byte ptr [rdi], 0;"
|
||||
// "craft_std_string:"
|
||||
// " mov qword ptr [rbx], rax;"
|
||||
// " mov qword ptr [rbx + 0x10], {encoded_key_length:#x};"
|
||||
// " mov qword ptr [rbx + 0x18], {encoded_key_length:#x} + 1;"
|
||||
// "final:"
|
||||
// " mov rax, rbx;"
|
||||
// " pop rbx;"
|
||||
// " pop rsi;"
|
||||
// " pop rdi;"
|
||||
// " ret;"
|
||||
// "end_of_code:",
|
||||
// fmt::arg("encoded_key_length", encoded_key.length()),
|
||||
// fmt::arg("m_va_iat_entry_malloc", m_va_iat_entry_malloc)
|
||||
// ),
|
||||
// m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey
|
||||
// );
|
||||
|
||||
std::vector<uint8_t> assembled_patch_code;
|
||||
{
|
||||
keystone_assembler x86_assembler{ KS_ARCH_X86, KS_MODE_64 };
|
||||
|
||||
auto current_va = m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey;
|
||||
auto next_reloc = m_libcc_interpreter.relocation_distribute().lower_bound(m_libcc_interpreter.convert_va_to_rva(current_va));
|
||||
for (const auto& patch_code_chunk : patch_code_chunks) {
|
||||
auto assembled_patch_code_chunk = x86_assembler.assemble(patch_code_chunk, current_va);
|
||||
|
||||
while (true) {
|
||||
auto next_reloc_va = m_libcc_interpreter.convert_rva_to_va(next_reloc->first);
|
||||
auto next_reloc_size = next_reloc->second;
|
||||
|
||||
if (current_va + assembled_patch_code_chunk.size() + 2 <= next_reloc_va) { // 2 -> size of machine code "jmp rel8"
|
||||
assembled_patch_code.insert(assembled_patch_code.end(), assembled_patch_code_chunk.begin(), assembled_patch_code_chunk.end());
|
||||
current_va += assembled_patch_code_chunk.size();
|
||||
break;
|
||||
} else if (current_va + 2 <= next_reloc_va) {
|
||||
auto next_va = next_reloc_va + next_reloc_size;
|
||||
auto assembled_jmp = x86_assembler.assemble(fmt::format("jmp {:#016x};", next_va), current_va);
|
||||
auto assembled_padding = std::vector<uint8_t>(next_va - (current_va + assembled_jmp.size()), 0xcc); // 0xcc -> int3
|
||||
assembled_patch_code.insert(assembled_patch_code.end(), assembled_jmp.begin(), assembled_jmp.end());
|
||||
assembled_patch_code.insert(assembled_patch_code.end(), assembled_padding.begin(), assembled_padding.end());
|
||||
current_va = next_va;
|
||||
++next_reloc;
|
||||
} else {
|
||||
__assume(false); // impossible to reach here
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey, assembled_patch_code.data(), assembled_patch_code.size());
|
||||
wprintf_s(L"[*] patch_solution_since<16, 0, 7, 0>: Patch has been done.\n");
|
||||
}
|
||||
|
||||
}
|
||||
16
navicat-patcher/patch_solution_since_16.0.7.0.generic.cpp
Normal file
16
navicat-patcher/patch_solution_since_16.0.7.0.generic.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include "patch_solution_since_16.0.7.0.hpp"
|
||||
#include <regex>
|
||||
|
||||
namespace nkg {
|
||||
|
||||
std::string patch_solution_since<16, 0, 7, 0>::_build_encoded_key(const rsa_cipher& cipher) {
|
||||
auto encoded_key = cipher.export_public_key_string_pem();
|
||||
|
||||
encoded_key = std::regex_replace(encoded_key, std::regex("-----BEGIN PUBLIC KEY-----"), "");
|
||||
encoded_key = std::regex_replace(encoded_key, std::regex("-----END PUBLIC KEY-----"), "");
|
||||
encoded_key = std::regex_replace(encoded_key, std::regex("\n"), "");
|
||||
|
||||
return encoded_key;
|
||||
}
|
||||
|
||||
}
|
||||
35
navicat-patcher/patch_solution_since_16.0.7.0.hpp
Normal file
35
navicat-patcher/patch_solution_since_16.0.7.0.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include "patch_solution_since.hpp"
|
||||
#include "image_interpreter.hpp"
|
||||
#include <any>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace nkg {
|
||||
|
||||
template<>
|
||||
class patch_solution_since<16, 0, 7, 0> final : public patch_solution {
|
||||
private:
|
||||
static inline std::string_view official_encoded_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889IqdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginva5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOFR0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmtYyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQawIDAQAB";
|
||||
|
||||
image_interpreter& m_libcc_interpreter;
|
||||
image_interpreter::va_t m_va_CSRegistrationInfoFetcher_WIN_vtable;
|
||||
image_interpreter::va_t m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey;
|
||||
image_interpreter::va_t m_va_iat_entry_malloc;
|
||||
|
||||
std::string _build_encoded_key(const rsa_cipher& cipher);
|
||||
|
||||
public:
|
||||
patch_solution_since(image_interpreter& libcc_interpreter);
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool find_patch() override;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool check_rsa_privkey(const rsa_cipher& cipher) override;
|
||||
|
||||
virtual void make_patch(const rsa_cipher& cipher) override;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
629
navicat-patcher/patch_solution_since_16.0.7.0.i386.cpp
Normal file
629
navicat-patcher/patch_solution_since_16.0.7.0.i386.cpp
Normal file
@ -0,0 +1,629 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include "i386_emulator.hpp"
|
||||
#include "keystone_assembler.hpp"
|
||||
#include "patch_solution_since_16.0.7.0.hpp"
|
||||
#include <algorithm>
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace nkg {
|
||||
|
||||
patch_solution_since<16, 0, 7, 0>::patch_solution_since(image_interpreter& libcc_interpreter) :
|
||||
m_libcc_interpreter(libcc_interpreter),
|
||||
m_va_CSRegistrationInfoFetcher_WIN_vtable(0),
|
||||
m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey(0),
|
||||
m_va_iat_entry_malloc(0) {}
|
||||
|
||||
bool patch_solution_since<16, 0, 7, 0>::find_patch() {
|
||||
auto CSRegistrationInfoFetcher_WIN_type_descriptor_name =
|
||||
m_libcc_interpreter.search_section<const uint8_t*>(
|
||||
".data",
|
||||
[](const uint8_t* p, size_t s) {
|
||||
if (s < sizeof(".?AVCSRegistrationInfoFetcher_WIN@@")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strcmp(reinterpret_cast<const char*>(p), ".?AVCSRegistrationInfoFetcher_WIN@@") == 0;
|
||||
}
|
||||
);
|
||||
|
||||
if (CSRegistrationInfoFetcher_WIN_type_descriptor_name == nullptr) {
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: RTTI info for CSRegistrationInfoFetcher_WIN is not found. (failure label 0)\n");
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_rtti_type_descriptor = CSRegistrationInfoFetcher_WIN_type_descriptor_name - 0x8;
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_rtti_type_descriptor_va = m_libcc_interpreter.convert_ptr_to_va(CSRegistrationInfoFetcher_WIN_rtti_type_descriptor);
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_pTypeDescriptor =
|
||||
m_libcc_interpreter.search_section<const uint8_t*>(
|
||||
".rdata",
|
||||
[this, CSRegistrationInfoFetcher_WIN_rtti_type_descriptor_va](const uint8_t* p, size_t s) {
|
||||
if (reinterpret_cast<uintptr_t>(p) % sizeof(uint32_t) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s < sizeof(uint32_t)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*reinterpret_cast<const uint32_t*>(p) != CSRegistrationInfoFetcher_WIN_rtti_type_descriptor_va) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s < sizeof(uint32_t) * 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto maybe_CSRegistrationInfoFetcher_WIN_rtti_class_hierarchy_descriptor_va = reinterpret_cast<const uint32_t*>(p)[1];
|
||||
|
||||
try {
|
||||
return memcmp(m_libcc_interpreter.image_section_header_from_va(maybe_CSRegistrationInfoFetcher_WIN_rtti_class_hierarchy_descriptor_va)->Name, ".rdata\x00\x00", 8) == 0;
|
||||
} catch (nkg::exception&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_pTypeDescriptor == nullptr) {
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: RTTI info for CSRegistrationInfoFetcher_WIN is not found. (failure label 1)\n");
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator = CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_pTypeDescriptor - 0xC;
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_va = m_libcc_interpreter.convert_ptr_to_va(CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator);
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_vtable_before =
|
||||
m_libcc_interpreter.search_section<const uint8_t*>(
|
||||
".rdata",
|
||||
[CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_va](const uint8_t* p, size_t s) {
|
||||
if (reinterpret_cast<uintptr_t>(p) % sizeof(uint32_t) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s < sizeof(uint32_t)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return *reinterpret_cast<const uint32_t*>(p) == CSRegistrationInfoFetcher_WIN_rtti_complete_object_locator_va;
|
||||
}
|
||||
);
|
||||
|
||||
if (CSRegistrationInfoFetcher_WIN_vtable_before == nullptr) {
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: Vftable for CSRegistrationInfoFetcher_WIN is not found.\n");
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_vtable =
|
||||
reinterpret_cast<const uint32_t*>(CSRegistrationInfoFetcher_WIN_vtable_before + sizeof(uint32_t));
|
||||
|
||||
m_va_CSRegistrationInfoFetcher_WIN_vtable = m_libcc_interpreter.convert_ptr_to_va(CSRegistrationInfoFetcher_WIN_vtable);
|
||||
m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey = CSRegistrationInfoFetcher_WIN_vtable[6];
|
||||
wprintf(L"[*] patch_solution_since<16, 0, 7, 0>: m_va_CSRegistrationInfoFetcher_WIN_vtable = 0x%08x\n", m_va_CSRegistrationInfoFetcher_WIN_vtable);
|
||||
wprintf(L"[*] patch_solution_since<16, 0, 7, 0>: m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey = 0x%08x\n", m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey);
|
||||
|
||||
|
||||
i386_emulator x86_emulator;
|
||||
|
||||
x86_emulator.context_set("heap_base", uint32_t{ 0x7f000000 });
|
||||
x86_emulator.context_set("heap_size", size_t{ 0x1000 * 32 });
|
||||
x86_emulator.context_set("heap_records", std::map<uint32_t, uint32_t>{});
|
||||
|
||||
x86_emulator.context_set("stack_base", uint32_t{ 0x7fff0000 });
|
||||
x86_emulator.context_set("stack_size", size_t{ 0x1000 * 32 });
|
||||
x86_emulator.context_set("stack_top", uint32_t{ x86_emulator.context_get<uint32_t>("stack_base") - x86_emulator.context_get<size_t>("stack_size") });
|
||||
|
||||
x86_emulator.context_set("r0_to_r3_stub_area_base", uint32_t{ 0xffffe000 });
|
||||
x86_emulator.context_set("r0_to_r3_stub_area_size", size_t{ 0x1000 });
|
||||
|
||||
x86_emulator.context_set("dead_area_base", uint32_t{ 0xfffff000 });
|
||||
x86_emulator.context_set("dead_area_size", size_t{ 0x1000 });
|
||||
|
||||
x86_emulator.context_set("iat_base", uint32_t{ m_libcc_interpreter.convert_rva_to_va(m_libcc_interpreter.image_nt_headers()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) });
|
||||
x86_emulator.context_set("iat_size", size_t{ m_libcc_interpreter.image_nt_headers()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size });
|
||||
|
||||
x86_emulator.context_set("external_api_stub_area_base", uint32_t{ 0x80000000 });
|
||||
x86_emulator.context_set("external_api_stub_area_size", size_t{ (x86_emulator.context_get<size_t>("iat_size") / 8 + 0xfff) / 0x1000 * 0x1000 });
|
||||
|
||||
x86_emulator.context_set("external_api_impl", std::map<std::string, uint32_t>{});
|
||||
x86_emulator.context_set("external_api_impl_area_base", uint32_t{ 0x90000000 });
|
||||
x86_emulator.context_set("external_api_impl_area_size", size_t{ 0 });
|
||||
|
||||
x86_emulator.context_set("gdt_base", uint32_t{ 0xffff0000 });
|
||||
x86_emulator.context_set("gdt_size", size_t{ 0x1000 });
|
||||
|
||||
x86_emulator.context_set("fs_base", uint32_t{ 0xa0000000 });
|
||||
x86_emulator.context_set("fs_size", size_t{ 0x1000 });
|
||||
|
||||
x86_emulator.context_set("start_address", static_cast<uint32_t>(m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey));
|
||||
x86_emulator.context_set("dead_address", x86_emulator.context_get<uint32_t>("dead_area_base"));
|
||||
|
||||
// allocate heap
|
||||
x86_emulator.mem_map(x86_emulator.context_get<uint32_t>("heap_base"), x86_emulator.context_get<size_t>("heap_size"), UC_PROT_READ | UC_PROT_WRITE);
|
||||
|
||||
// allocate stack
|
||||
x86_emulator.mem_map(x86_emulator.context_get<uint32_t>("stack_top"), x86_emulator.context_get<size_t>("stack_size"), UC_PROT_READ | UC_PROT_WRITE);
|
||||
|
||||
// allocate r0_to_r3_stub area
|
||||
x86_emulator.mem_map(x86_emulator.context_get<uint32_t>("r0_to_r3_stub_area_base"), x86_emulator.context_get<size_t>("r0_to_r3_stub_area_size"), UC_PROT_READ | UC_PROT_EXEC);
|
||||
x86_emulator.mem_write(x86_emulator.context_get<uint32_t>("r0_to_r3_stub_area_base"), keystone_assembler{ KS_ARCH_X86, KS_MODE_32 }.assemble("iretd;"));
|
||||
|
||||
// allocate dead area
|
||||
x86_emulator.mem_map(x86_emulator.context_get<uint32_t>("dead_area_base"), x86_emulator.context_get<size_t>("dead_area_size"), UC_PROT_READ | UC_PROT_EXEC);
|
||||
|
||||
// allocate and hook read access to IAT
|
||||
{
|
||||
auto iat_base = x86_emulator.context_get<uint32_t>("iat_base");
|
||||
auto iat_size = x86_emulator.context_get<size_t>("iat_size");
|
||||
auto external_api_stub_area_base = x86_emulator.context_get<uint32_t>("external_api_stub_area_base");
|
||||
|
||||
auto iat_page_base = iat_base / 0x1000 * 0x1000;
|
||||
auto iat_page_count = (iat_base - iat_page_base + iat_size + 0xfff) / 0x1000;
|
||||
|
||||
x86_emulator.mem_map(iat_page_base, iat_page_count * 0x1000, UC_PROT_READ);
|
||||
|
||||
x86_emulator.hook_add<UC_HOOK_MEM_READ>(
|
||||
[this, &x86_emulator, iat_base, external_api_stub_area_base](uc_mem_type type, uint32_t address, size_t size, int32_t value) {
|
||||
auto rva = m_libcc_interpreter.convert_va_to_rva(address);
|
||||
auto import_lookup_entry = m_libcc_interpreter.import_lookup_entry_from_rva(rva);
|
||||
|
||||
if (import_lookup_entry && !IMAGE_SNAP_BY_ORDINAL(import_lookup_entry->u1.Ordinal)) {
|
||||
auto import_by_name_entry = m_libcc_interpreter.convert_rva_to_ptr<PIMAGE_IMPORT_BY_NAME>(import_lookup_entry->u1.AddressOfData);
|
||||
if (strcmp(import_by_name_entry->Name, "memcpy") == 0) {
|
||||
uint32_t impl_address = x86_emulator.context_get<std::map<std::string, uint32_t>&>("external_api_impl")["memcpy"];
|
||||
x86_emulator.mem_write(address, &impl_address, sizeof(impl_address));
|
||||
} else {
|
||||
uint32_t stub_address = external_api_stub_area_base + (address - iat_base) / sizeof(IMAGE_THUNK_DATA);
|
||||
x86_emulator.mem_write(address, &stub_address, sizeof(stub_address));
|
||||
}
|
||||
} else {
|
||||
x86_emulator.emu_stop();
|
||||
}
|
||||
},
|
||||
iat_base,
|
||||
iat_base + iat_size - 1
|
||||
);
|
||||
}
|
||||
|
||||
// allocate and setup external api stub area
|
||||
{
|
||||
auto external_api_stub_area_base = x86_emulator.context_get<uint32_t>("external_api_stub_area_base");
|
||||
auto external_api_stub_area_size = x86_emulator.context_get<size_t>("external_api_stub_area_size");
|
||||
|
||||
x86_emulator.mem_map(external_api_stub_area_base, external_api_stub_area_size, UC_PROT_READ | UC_PROT_EXEC);
|
||||
x86_emulator.mem_write(external_api_stub_area_base, std::vector<uint8_t>(external_api_stub_area_size, 0xc3)); // c3 -> ret
|
||||
|
||||
x86_emulator.hook_add<UC_HOOK_CODE>(
|
||||
[this, &x86_emulator, external_api_stub_area_base](uint32_t address, size_t size) {
|
||||
auto iat_base = x86_emulator.context_get<uint32_t>("iat_base");
|
||||
auto from_va = iat_base + (address - external_api_stub_area_base) * sizeof(IMAGE_THUNK_DATA);
|
||||
auto from_rva = m_libcc_interpreter.convert_va_to_rva(from_va);
|
||||
|
||||
auto import_lookup_entry = m_libcc_interpreter.import_lookup_entry_from_rva(from_rva);
|
||||
if (import_lookup_entry && !IMAGE_SNAP_BY_ORDINAL(import_lookup_entry->u1.Ordinal)) {
|
||||
auto import_by_name_entry = m_libcc_interpreter.convert_rva_to_ptr<PIMAGE_IMPORT_BY_NAME>(import_lookup_entry->u1.AddressOfData);
|
||||
if (strcmp(import_by_name_entry->Name, "malloc") == 0) {
|
||||
m_va_iat_entry_malloc = from_va;
|
||||
|
||||
uint32_t esp;
|
||||
x86_emulator.reg_read(UC_X86_REG_ESP, &esp);
|
||||
|
||||
uint32_t alloc_size;
|
||||
x86_emulator.mem_read(esp + 4, &alloc_size, sizeof(alloc_size));
|
||||
|
||||
auto& heap_records = x86_emulator.context_get<std::map<uint32_t, uint32_t>&>("heap_records");
|
||||
|
||||
auto predecessor_chunk =
|
||||
std::adjacent_find(
|
||||
heap_records.begin(),
|
||||
heap_records.end(),
|
||||
[alloc_size](const auto& chunk0, const auto& chunk1) { return chunk1.first - (chunk0.first + chunk0.second) >= alloc_size; }
|
||||
);
|
||||
|
||||
uint32_t alloc_p;
|
||||
if (predecessor_chunk != heap_records.end()) {
|
||||
alloc_p = predecessor_chunk->first + predecessor_chunk->second;
|
||||
} else {
|
||||
auto heap_base = x86_emulator.context_get<uint32_t>("heap_base");
|
||||
auto heap_size = x86_emulator.context_get<uint32_t>("heap_size");
|
||||
|
||||
auto free_space_base = heap_records.size() > 0 ? heap_records.rbegin()->first + heap_records.rbegin()->second : heap_base;
|
||||
auto free_space_size = heap_base + heap_size - free_space_base;
|
||||
|
||||
if (free_space_size < alloc_size) {
|
||||
auto heap_expand_base = heap_base + heap_size;
|
||||
auto heap_expand_size = (alloc_size - free_space_size + 0xfff) / 0x1000 * 0x1000;
|
||||
x86_emulator.mem_map(heap_expand_base, heap_expand_size, UC_PROT_READ | UC_PROT_WRITE);
|
||||
}
|
||||
|
||||
alloc_p = free_space_base;
|
||||
}
|
||||
|
||||
heap_records[alloc_p] = alloc_size;
|
||||
|
||||
x86_emulator.reg_write(UC_X86_REG_EAX, &alloc_p);
|
||||
} else if (strcmp(import_by_name_entry->Name, "free") == 0) {
|
||||
uint32_t esp;
|
||||
x86_emulator.reg_read(UC_X86_REG_ESP, &esp);
|
||||
|
||||
uint32_t alloc_p;
|
||||
x86_emulator.mem_read(esp + 4, &alloc_p, sizeof(alloc_p));
|
||||
|
||||
auto& heap_records = x86_emulator.context_get<std::map<uint32_t, uint32_t>&>("heap_records");
|
||||
|
||||
auto chunk = heap_records.find(alloc_p);
|
||||
if (chunk != heap_records.end()) {
|
||||
heap_records.erase(chunk);
|
||||
} else {
|
||||
x86_emulator.emu_stop();
|
||||
}
|
||||
} else {
|
||||
x86_emulator.emu_stop();
|
||||
}
|
||||
} else {
|
||||
x86_emulator.emu_stop();
|
||||
}
|
||||
},
|
||||
external_api_stub_area_base,
|
||||
external_api_stub_area_base + external_api_stub_area_size - 1
|
||||
);
|
||||
}
|
||||
|
||||
// allocate and setup external api impl area
|
||||
{
|
||||
keystone_assembler x86_assembler{ KS_ARCH_X86, KS_MODE_32 };
|
||||
|
||||
std::map<std::string, std::vector<uint8_t>> machine_code_list =
|
||||
{
|
||||
std::make_pair(
|
||||
"memcpy",
|
||||
x86_assembler.assemble(
|
||||
"push edi;"
|
||||
"push esi;"
|
||||
"mov eax, dword ptr [esp + 0x8 + 0x4];"
|
||||
"mov edi, eax;"
|
||||
"mov esi, dword ptr [esp + 0x8 + 0x8];"
|
||||
"mov ecx, dword ptr [esp + 0x8 + 0xc];"
|
||||
"rep movs byte ptr [edi], byte ptr [esi];"
|
||||
"pop esi;"
|
||||
"pop edi;"
|
||||
"ret;"
|
||||
)
|
||||
)
|
||||
};
|
||||
|
||||
auto& external_api_impl = x86_emulator.context_get<std::map<std::string, uint32_t>&>("external_api_impl");
|
||||
auto& external_api_impl_area_base = x86_emulator.context_get<uint32_t&>("external_api_impl_area_base");
|
||||
auto& external_api_impl_area_size = x86_emulator.context_get<size_t&>("external_api_impl_area_size");
|
||||
|
||||
auto p = external_api_impl_area_base;
|
||||
for (const auto& name_code_pair : machine_code_list) {
|
||||
external_api_impl[name_code_pair.first] = p;
|
||||
p = (p + name_code_pair.second.size() + 0xf) / 0x10 * 0x10;
|
||||
}
|
||||
|
||||
external_api_impl_area_size = (p + 0xfff) / 0x1000 * 0x1000 - external_api_impl_area_base;
|
||||
|
||||
x86_emulator.mem_map(external_api_impl_area_base, external_api_impl_area_size, UC_PROT_READ | UC_PROT_EXEC);
|
||||
for (const auto& name_code_pair : machine_code_list) {
|
||||
x86_emulator.mem_write(external_api_impl[name_code_pair.first], name_code_pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
// allocate and setup GDT, segment registers
|
||||
{
|
||||
auto gdt_base = x86_emulator.context_get<uint32_t>("gdt_base");
|
||||
auto gdt_size = x86_emulator.context_get<size_t>("gdt_size");
|
||||
x86_emulator.mem_map(gdt_base, gdt_size, UC_PROT_READ | UC_PROT_WRITE);
|
||||
|
||||
x86_emulator.create_gdt_entry(gdt_base, 0, 0, 0, 0); // null segment descriptor
|
||||
// -------------------------------------------------------- access_byte
|
||||
// 0x80 -> present bit
|
||||
// (0 << 5) -> DPL is set to 0
|
||||
// 0x10 -> code/data segment
|
||||
// 0x08 -> executable segment
|
||||
// !(0x4) -> not conforming code segment
|
||||
// 0x02 -> code segment is readable
|
||||
// !(0x01) -> accessed bit, this bit is managed by CPU
|
||||
// -------------------------------------------------------- flags
|
||||
// 0x08 -> 4k granularity
|
||||
// 0x04 -> 32-bit protected mode segment
|
||||
// !(0x01) -> AVL bit is not used
|
||||
x86_emulator.create_gdt_entry(gdt_base + 1 * 0x8, 0x00000000, 0xfffff, 0x80 | (0 << 5) | 0x10 | 0x08 | !(0x04) | 0x02 | !(0x01), 0x08 | 0x04 | !(0x01)); // kernel code segment
|
||||
// -------------------------------------------------------- access_byte
|
||||
// 0x80 -> present bit
|
||||
// (0 << 5) -> DPL is set to 0
|
||||
// 0x10 -> code/data segment
|
||||
// !(0x08) -> data segment
|
||||
// !(0x4) -> segment grows up
|
||||
// 0x02 -> data segment is writable
|
||||
// !(0x01) -> accessed bit, this bit is managed by CPU
|
||||
// -------------------------------------------------------- flags
|
||||
// 0x08 -> 4k granularity
|
||||
// 0x04 -> 32-bit protected mode segment
|
||||
// !(0x01) -> AVL bit is not used
|
||||
x86_emulator.create_gdt_entry(gdt_base + 2 * 0x8, 0x00000000, 0xfffff, 0x80 | (0 << 5) | 0x10 | !(0x08) | !(0x04) | 0x02 | !(0x01), 0x08 | 0x04 | !(0x01)); // kernel data segment
|
||||
// -------------------------------------------------------- access_byte
|
||||
// 0x80 -> present bit
|
||||
// (3 << 5) -> DPL is set to 3
|
||||
// 0x10 -> code/data segment
|
||||
// 0x08 -> executable segment
|
||||
// !(0x4) -> not conforming code segment
|
||||
// 0x02 -> code segment is readable
|
||||
// !(0x01) -> accessed bit, this bit is managed by CPU
|
||||
// -------------------------------------------------------- flags
|
||||
// 0x08 -> 4k granularity
|
||||
// 0x04 -> 32-bit protected mode segment
|
||||
// !(0x01) -> AVL bit is not used
|
||||
x86_emulator.create_gdt_entry(gdt_base + 3 * 0x8, 0x00000000, 0xfffff, 0x80 | (3 << 5) | 0x10 | 0x08 | !(0x04) | 0x02 | !(0x01), 0x08 | 0x04 | !(0x01)); // user code segment
|
||||
// -------------------------------------------------------- access_byte
|
||||
// 0x80 -> present bit
|
||||
// (3 << 5) -> DPL is set to 3
|
||||
// 0x10 -> code/data segment
|
||||
// !(0x08) -> data segment
|
||||
// !(0x4) -> segment grows up
|
||||
// 0x02 -> data segment is writable
|
||||
// !(0x01) -> accessed bit, this bit is managed by CPU
|
||||
// -------------------------------------------------------- flags
|
||||
// 0x08 -> 4k granularity
|
||||
// 0x04 -> 32-bit protected mode segment
|
||||
// !(0x01) -> AVL bit is not used
|
||||
x86_emulator.create_gdt_entry(gdt_base + 4 * 0x8, 0x00000000, 0xfffff, 0x80 | (3 << 5) | 0x10 | !(0x08) | !(0x04) | 0x02 | !(0x01), 0x08 | 0x04 | !(0x01)); // user data segment
|
||||
// -------------------------------------------------------- access_byte
|
||||
// 0x80 -> present bit
|
||||
// (3 << 5) -> DPL is set to 3
|
||||
// 0x10 -> code/data segment
|
||||
// !(0x08) -> data segment
|
||||
// !(0x4) -> segment grows up
|
||||
// 0x02 -> data segment is writable
|
||||
// !(0x01) -> accessed bit, this bit is managed by CPU
|
||||
// -------------------------------------------------------- flags
|
||||
// !(0x08) -> 1-byte granularity
|
||||
// 0x04 -> 32-bit protected mode segment
|
||||
// !(0x01) -> AVL bit is not used
|
||||
auto fs_base = x86_emulator.context_get<uint32_t>("fs_base");
|
||||
auto fs_size = x86_emulator.context_get<size_t>("fs_size");
|
||||
x86_emulator.create_gdt_entry(gdt_base + 7 * 0x8, fs_base, fs_size - 1, 0x80 | (3 << 5) | 0x10 | !(0x08) | !(0x04) | 0x02 | !(0x01), !(0x08) | 0x04 | !(0x01)); // user fs segment
|
||||
|
||||
uc_x86_mmr gdtr = {};
|
||||
gdtr.base = gdt_base;
|
||||
gdtr.limit = gdt_base + gdt_size - 1;
|
||||
x86_emulator.reg_write(UC_X86_REG_GDTR, &gdtr);
|
||||
|
||||
uint16_t cs, ds, es, fs, gs, ss;
|
||||
cs = (1 << 3) | (0 << 2) | (0); // use kernel code segmet
|
||||
ss = (2 << 3) | (0 << 2) | (0); // use kernel data segmet
|
||||
ds = es = (4 << 3) | (0 << 2) | (3); // use user data segment
|
||||
fs = (7 << 3) | (0 << 2) | (3); // use user fs segment
|
||||
gs = 0; // not used
|
||||
|
||||
uint32_t eflags;
|
||||
x86_emulator.reg_read(UC_X86_REG_EFLAGS, &eflags);
|
||||
x86_emulator.reg_write(UC_X86_REG_CS, &cs);
|
||||
x86_emulator.reg_write(UC_X86_REG_SS, &ss);
|
||||
x86_emulator.reg_write(UC_X86_REG_DS, &ds);
|
||||
x86_emulator.reg_write(UC_X86_REG_ES, &es);
|
||||
x86_emulator.reg_write(UC_X86_REG_FS, &fs);
|
||||
x86_emulator.reg_write(UC_X86_REG_GS, &gs);
|
||||
|
||||
}
|
||||
|
||||
// allocate and hook access to fs area
|
||||
{
|
||||
auto fs_base = x86_emulator.context_get<uint32_t>("fs_base");
|
||||
auto fs_size = x86_emulator.context_get<size_t>("fs_size");
|
||||
x86_emulator.mem_map(fs_base, fs_size, UC_PROT_READ | UC_PROT_WRITE);
|
||||
|
||||
x86_emulator.hook_add<UC_HOOK_MEM_READ>(
|
||||
[this, &x86_emulator, fs_base](uc_mem_type access, uint32_t address, size_t size, int64_t value) {
|
||||
switch (address - fs_base) {
|
||||
case 0:
|
||||
if (size == 4) {
|
||||
// Current Structured Exception Handling (SEH) frame, leave it NULL
|
||||
} else {
|
||||
x86_emulator.emu_stop();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
x86_emulator.emu_stop();
|
||||
break;
|
||||
}
|
||||
},
|
||||
fs_base,
|
||||
fs_base + fs_size - 1
|
||||
);
|
||||
}
|
||||
|
||||
// x86_emulator.hook_add<UC_HOOK_CODE>([](uint32_t address, uint32_t size) { wprintf_s(L"code_trace, address = 0x%08x\n", address); });
|
||||
|
||||
x86_emulator.hook_add<UC_HOOK_MEM_UNMAPPED>(
|
||||
[this, &x86_emulator](uc_mem_type access, uint32_t address, size_t size, int64_t value) -> bool {
|
||||
try {
|
||||
auto fault_section = m_libcc_interpreter.image_section_header_from_va(address);
|
||||
|
||||
auto page_base = address / 0x1000 * 0x1000;
|
||||
auto page_size = 0x1000;
|
||||
uint32_t page_perms = UC_PROT_NONE;
|
||||
|
||||
if (fault_section->Characteristics & IMAGE_SCN_MEM_READ) {
|
||||
page_perms |= UC_PROT_READ;
|
||||
}
|
||||
if (fault_section->Characteristics & IMAGE_SCN_MEM_WRITE) {
|
||||
page_perms |= UC_PROT_WRITE;
|
||||
}
|
||||
if (fault_section->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
|
||||
page_perms |= UC_PROT_EXEC;
|
||||
}
|
||||
|
||||
x86_emulator.mem_map(page_base, page_size, page_perms);
|
||||
x86_emulator.mem_write(page_base, m_libcc_interpreter.convert_va_to_ptr<const void*>(page_base), page_size);
|
||||
|
||||
return true;
|
||||
} catch (::nkg::exception&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// set ebp, esp
|
||||
uint32_t init_ebp = x86_emulator.context_get<uint32_t>("stack_base") - x86_emulator.context_get<size_t>("stack_size") / 4;
|
||||
uint32_t init_esp = x86_emulator.context_get<uint32_t>("stack_base") - x86_emulator.context_get<size_t>("stack_size") / 2;
|
||||
|
||||
x86_emulator.reg_write(UC_X86_REG_EBP, &init_ebp);
|
||||
x86_emulator.reg_write(UC_X86_REG_ESP, &init_esp);
|
||||
|
||||
// setup iretd context
|
||||
uint32_t ring3_eip = x86_emulator.context_get<uint32_t>("start_address");
|
||||
uint32_t ring3_cs = (3 << 3) | (0 << 2) | (3); // use user code segment
|
||||
uint32_t ring3_eflags; x86_emulator.reg_read(UC_X86_REG_EFLAGS, &ring3_eflags);
|
||||
uint32_t ring3_esp = init_esp + 5 * 4;
|
||||
uint32_t ring3_ss = (4 << 3) | (0 << 2) | (3); // use user data segment
|
||||
x86_emulator.mem_write(init_esp, &ring3_eip, sizeof(ring3_eip));
|
||||
x86_emulator.mem_write(init_esp + 0x4, &ring3_cs, sizeof(ring3_cs));
|
||||
x86_emulator.mem_write(init_esp + 0x8, &ring3_eflags, sizeof(ring3_eflags));
|
||||
x86_emulator.mem_write(init_esp + 0xc, &ring3_esp, sizeof(ring3_esp));
|
||||
x86_emulator.mem_write(init_esp + 0x10, &ring3_ss, sizeof(ring3_ss));
|
||||
|
||||
// set ring3 retaddr
|
||||
uint32_t ring3_retaddr = x86_emulator.context_get<uint32_t>("dead_address");
|
||||
x86_emulator.mem_write(ring3_esp, &ring3_retaddr, sizeof(ring3_retaddr));
|
||||
|
||||
// set argument registers
|
||||
uint32_t init_ecx = 0; // `this` pointer of CSRegistrationInfoFetcher_WIN, but we don't need it for now.
|
||||
uint32_t retval_addr = ring3_esp + 0x40; // a pointer to stack memory which stores return value
|
||||
x86_emulator.reg_write(UC_X86_REG_ECX, &init_ecx);
|
||||
x86_emulator.mem_write(ring3_esp + 4, &retval_addr, sizeof(retval_addr)); // write to dword ptr [ring3_esp + 4]
|
||||
|
||||
//
|
||||
// start emulate
|
||||
//
|
||||
try {
|
||||
x86_emulator.emu_start(x86_emulator.context_get<uint32_t>("r0_to_r3_stub_area_base"), x86_emulator.context_get<uint32_t>("dead_address"));
|
||||
} catch (nkg::exception&) {
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: Code emulation failed.\n");
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
wprintf_s(L"[*] patch_solution_since<16, 0, 7, 0>: m_va_iat_entry_malloc = 0x%08x\n", m_va_iat_entry_malloc);
|
||||
|
||||
//
|
||||
// get result
|
||||
//
|
||||
// on I386 platform, `std::string` has follow memory layout:
|
||||
// ------------------------------
|
||||
// | offset | size |
|
||||
// ------------------------------
|
||||
// | +0 | 0x10 | `char[16]: a small string buffer` OR `char*: a large string buffer pointer`
|
||||
// ------------------------------
|
||||
// | +0x10 | 0x4 | size_t: string length
|
||||
// ------------------------------
|
||||
// | +0x14 | 0x4 | size_t: capacity
|
||||
// ------------------------------
|
||||
//
|
||||
uint32_t encoded_key_length;
|
||||
x86_emulator.mem_read(retval_addr + 0x10, &encoded_key_length, sizeof(encoded_key_length));
|
||||
if (encoded_key_length != official_encoded_key.length()) {
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: Unexpected encoded key length(%u).\n", encoded_key_length);
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t encoded_key_ptr;
|
||||
x86_emulator.mem_read(retval_addr, &encoded_key_ptr, sizeof(encoded_key_ptr));
|
||||
|
||||
auto encoded_key = x86_emulator.mem_read(encoded_key_ptr, encoded_key_length);
|
||||
if (memcmp(encoded_key.data(), official_encoded_key.data(), encoded_key.size()) == 0) {
|
||||
wprintf_s(L"[+] patch_solution_since<16, 0, 7, 0>: Official encoded key is found.\n");
|
||||
return true;
|
||||
} else {
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: Official encoded key is not found.\n");
|
||||
wprintf_s(L"[-] patch_solution_since<16, 0, 7, 0>: This patch solution will be suppressed.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool patch_solution_since<16, 0, 7, 0>::check_rsa_privkey(const rsa_cipher& cipher) {
|
||||
return true; // no requirements
|
||||
}
|
||||
|
||||
void patch_solution_since<16, 0, 7, 0>::make_patch(const rsa_cipher& cipher) {
|
||||
auto encoded_key = _build_encoded_key(cipher);
|
||||
|
||||
auto CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey =
|
||||
m_libcc_interpreter.convert_va_to_ptr<uint8_t*>(m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey);
|
||||
|
||||
std::vector<std::string> patch_code_chunks;
|
||||
patch_code_chunks.emplace_back("push edi;");
|
||||
patch_code_chunks.emplace_back("push esi;");
|
||||
patch_code_chunks.emplace_back("push ebx;");
|
||||
patch_code_chunks.emplace_back("push ebp;");
|
||||
patch_code_chunks.emplace_back("mov ebp, esp;");
|
||||
patch_code_chunks.emplace_back("call label; label: pop ebx; sub ebx, label;"); // ebx <- relocation shift value
|
||||
patch_code_chunks.emplace_back(fmt::format("mov eax, {:#08x};", m_va_iat_entry_malloc));
|
||||
patch_code_chunks.emplace_back("add eax, ebx;");
|
||||
patch_code_chunks.emplace_back("mov eax, dword ptr [eax];"); // eax <- address of `malloc`
|
||||
patch_code_chunks.emplace_back(fmt::format("push {:#x};", encoded_key.length() + 1));
|
||||
patch_code_chunks.emplace_back("call eax;");
|
||||
patch_code_chunks.emplace_back("add esp, 0x4;");
|
||||
{
|
||||
std::vector<uint32_t> push_values((encoded_key.length() + 1 + 3) / 4, 0);
|
||||
memcpy(push_values.data(), encoded_key.data(), encoded_key.length());
|
||||
std::for_each(push_values.crbegin(), push_values.crend(), [&patch_code_chunks](uint32_t x) { patch_code_chunks.emplace_back(fmt::format("push {:#08x};", x)); });
|
||||
}
|
||||
patch_code_chunks.emplace_back("mov edi, eax;");
|
||||
patch_code_chunks.emplace_back("mov esi, esp;");
|
||||
patch_code_chunks.emplace_back(fmt::format("mov ecx, {:#x};", encoded_key.length() + 1));
|
||||
patch_code_chunks.emplace_back("rep movs byte ptr [edi], byte ptr [esi];");
|
||||
patch_code_chunks.emplace_back("mov edx, dword ptr [ebp + 0x14];");
|
||||
patch_code_chunks.emplace_back("mov dword ptr [edx], eax;");
|
||||
patch_code_chunks.emplace_back(fmt::format("mov dword ptr [edx + 0x10], {:#x};", encoded_key.length()));
|
||||
patch_code_chunks.emplace_back(fmt::format("mov dword ptr [edx + 0x14], {:#x};", encoded_key.length() + 1));
|
||||
patch_code_chunks.emplace_back("mov eax, edx;");
|
||||
patch_code_chunks.emplace_back("leave;");
|
||||
patch_code_chunks.emplace_back("pop ebx;");
|
||||
patch_code_chunks.emplace_back("pop esi;");
|
||||
patch_code_chunks.emplace_back("pop edi;");
|
||||
patch_code_chunks.emplace_back("ret 4;");
|
||||
|
||||
std::vector<uint8_t> assembled_patch_code;
|
||||
{
|
||||
keystone_assembler x86_assembler{ KS_ARCH_X86, KS_MODE_32 };
|
||||
|
||||
auto current_va = m_va_CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey;
|
||||
auto next_reloc = m_libcc_interpreter.relocation_distribute().lower_bound(m_libcc_interpreter.convert_va_to_rva(current_va));
|
||||
for (const auto& patch_code_chunk : patch_code_chunks) {
|
||||
auto assembled_patch_code_chunk = x86_assembler.assemble(patch_code_chunk, current_va);
|
||||
|
||||
while (true) {
|
||||
auto next_reloc_va = m_libcc_interpreter.convert_rva_to_va(next_reloc->first);
|
||||
auto next_reloc_size = next_reloc->second;
|
||||
|
||||
if (current_va + assembled_patch_code_chunk.size() + 2 <= next_reloc_va) { // 2 -> size of machine code "jmp rel8"
|
||||
assembled_patch_code.insert(assembled_patch_code.end(), assembled_patch_code_chunk.begin(), assembled_patch_code_chunk.end());
|
||||
current_va += assembled_patch_code_chunk.size();
|
||||
break;
|
||||
} else if (current_va + 2 <= next_reloc_va) {
|
||||
auto next_va = next_reloc_va + next_reloc_size;
|
||||
auto assembled_jmp = x86_assembler.assemble(fmt::format("jmp {:#08x};", next_va), current_va);
|
||||
auto assembled_padding = std::vector<uint8_t>(next_va - (current_va + assembled_jmp.size()), 0xcc); // 0xcc -> int3
|
||||
assembled_patch_code.insert(assembled_patch_code.end(), assembled_jmp.begin(), assembled_jmp.end());
|
||||
assembled_patch_code.insert(assembled_patch_code.end(), assembled_padding.begin(), assembled_padding.end());
|
||||
current_va = next_va;
|
||||
++next_reloc;
|
||||
} else {
|
||||
__assume(false); // impossible to reach here
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(CSRegistrationInfoFetcher_WIN_GenerateRegistrationKey, assembled_patch_code.data(), assembled_patch_code.size());
|
||||
wprintf_s(L"[*] patch_solution_since<16, 0, 7, 0>: Patch has been done.\n");
|
||||
}
|
||||
|
||||
}
|
||||
295
navicat-patcher/wmain.cpp
Normal file
295
navicat-patcher/wmain.cpp
Normal file
@ -0,0 +1,295 @@
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <fmt/format.h>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
|
||||
#include "cp_converter.hpp"
|
||||
|
||||
#include "resource_wrapper.hpp"
|
||||
#include "resource_traits/cxx_object_traits.hpp"
|
||||
#include "resource_traits/win32/file_handle.hpp"
|
||||
#include "resource_traits/win32/generic_handle.hpp"
|
||||
#include "resource_traits/win32/map_view_ptr.hpp"
|
||||
|
||||
#include "rsa_cipher.hpp"
|
||||
#include "image_interpreter.hpp"
|
||||
#include "patch_solution.hpp"
|
||||
#include "patch_solution_since_16.0.7.0.hpp"
|
||||
|
||||
#include "exception.hpp"
|
||||
#include "exceptions/operation_canceled_exception.hpp"
|
||||
#include "exceptions/win32_exception.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-patcher\\wmain.cpp"
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
void welcome() {
|
||||
_putws(L"***************************************************");
|
||||
_putws(L"* navicat-patcher by @DoubleLabyrinth *");
|
||||
_putws(L"* version: 16.0.7.0-2 *");
|
||||
_putws(L"***************************************************");
|
||||
_putws(L"");
|
||||
}
|
||||
|
||||
|
||||
void help() {
|
||||
_putws(L"Usage:");
|
||||
_putws(L" navicat-patcher.exe [-dry-run] <Navicat Install Path> [RSA-2048 PEM File Path]");
|
||||
_putws(L"");
|
||||
_putws(L" [-dry-run] Run patcher without applying any patches.");
|
||||
_putws(L" This parameter is optional.");
|
||||
_putws(L"");
|
||||
_putws(L" <Navicat Install Path> Path to a directory where Navicat is installed.");
|
||||
_putws(L" This parameter is mandatory.");
|
||||
_putws(L"");
|
||||
_putws(L" [RSA-2048 PEM File Path] Path to an RSA-2048 private key file.");
|
||||
_putws(L" If not specified, an RSA-2048 private key file");
|
||||
_putws(L" named \"RegPrivateKey.pem\" will be generated.");
|
||||
_putws(L" This parameter is optional.");
|
||||
_putws(L"");
|
||||
_putws(L"Example:");
|
||||
_putws(L" navicat-patcher.exe \"C:\\Program Files\\PremiumSoft\\Navicat Premium 12\"");
|
||||
_putws(L"");
|
||||
}
|
||||
|
||||
bool parse_cmdline(int argc, wchar_t* argv[], bool& dry_run, std::filesystem::path& navicat_install_path, std::filesystem::path& rsa_privkey_filepath) {
|
||||
if (argc == 2) {
|
||||
dry_run = false;
|
||||
navicat_install_path = argv[1];
|
||||
rsa_privkey_filepath.clear();
|
||||
return true;
|
||||
} else if (argc == 3) {
|
||||
if (_wcsicmp(argv[1], L"-dry-run") == 0) {
|
||||
dry_run = true;
|
||||
navicat_install_path = argv[2];
|
||||
rsa_privkey_filepath.clear();
|
||||
return true;
|
||||
} else {
|
||||
dry_run = false;
|
||||
navicat_install_path = argv[1];
|
||||
rsa_privkey_filepath = argv[2];
|
||||
return true;
|
||||
}
|
||||
} else if (argc == 4) {
|
||||
if (_wcsicmp(argv[1], L"-dry-run") == 0) {
|
||||
dry_run = true;
|
||||
navicat_install_path = argv[2];
|
||||
rsa_privkey_filepath = argv[3];
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void select_patch_solutions
|
||||
(nkg::resource_wrapper<nkg::resource_traits::cxx_object_traits<nkg::patch_solution>>& solution0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void load_rsa_privkey(nkg::rsa_cipher& cipher, std::filesystem::path& rsa_privkey_filepath, nkg::patch_solution* solution0) {
|
||||
if (!rsa_privkey_filepath.empty()) {
|
||||
wprintf_s(L"[*] Import RSA-2048 private key from\n");
|
||||
wprintf_s(L" %s\n", rsa_privkey_filepath.native().c_str());
|
||||
|
||||
cipher.import_private_key_file(rsa_privkey_filepath);
|
||||
|
||||
if (solution0 && !solution0->check_rsa_privkey(cipher)) {
|
||||
throw nkg::exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"The RSA private key you provide cannot be used.");
|
||||
}
|
||||
} else {
|
||||
wprintf_s(L"[*] Generating new RSA private key, it may take a long time...\n");
|
||||
|
||||
do {
|
||||
cipher.generate_key(2048);
|
||||
} while (solution0 && !solution0->check_rsa_privkey(cipher)); // re-generate RSA key if one of `check_rsa_privkey` returns false
|
||||
}
|
||||
|
||||
wprintf_s(L"[*] Your RSA private key:\n%s\n", nkg::cp_converter<CP_UTF8, -1>::convert(cipher.export_private_key_string()).c_str());
|
||||
}
|
||||
|
||||
template<typename... args_t>
|
||||
bool all_patch_solutions_are_suppressed(args_t&&... args) {
|
||||
return (!args.is_valid() && ...);
|
||||
}
|
||||
|
||||
void detect_backup(const std::filesystem::path& file_path) {
|
||||
std::filesystem::path backup_path = file_path.native() + L".bak";
|
||||
if (std::filesystem::is_regular_file(backup_path)) {
|
||||
while (true) {
|
||||
wprintf_s(L"[*] Previous backup %s is detected. Delete? (y/n)", backup_path.native().c_str());
|
||||
|
||||
auto select = getwchar();
|
||||
while (select != L'\n' && getwchar() != L'\n') {}
|
||||
|
||||
if (select == L'Y' || select == L'y') {
|
||||
std::filesystem::remove(backup_path);
|
||||
break;
|
||||
} else if (select == TEXT('N') || select == TEXT('n')) {
|
||||
throw nkg::exceptions::operation_canceled_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Backup file still exists. Patch abort!");
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void make_backup(const std::filesystem::path& file_path) {
|
||||
std::filesystem::path backup_path = file_path.native() + L".bak";
|
||||
if (std::filesystem::exists(backup_path)) {
|
||||
throw nkg::exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Previous backup is detected.")
|
||||
.push_hint(fmt::format(u8"Please delete {} and try again.", nkg::cp_converter<-1, CP_UTF8>::convert(backup_path.native())));
|
||||
} else {
|
||||
std::filesystem::copy_file(file_path, backup_path);
|
||||
}
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t* argv[]) {
|
||||
welcome();
|
||||
|
||||
bool dry_run = false;
|
||||
std::filesystem::path navicat_install_path;
|
||||
std::filesystem::path rsa_privkey_filepath;
|
||||
|
||||
if (parse_cmdline(argc, argv, dry_run, navicat_install_path, rsa_privkey_filepath)) {
|
||||
try {
|
||||
if (!std::filesystem::is_directory(navicat_install_path)) {
|
||||
throw nkg::exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Navicat install path doesn't point to a directory.")
|
||||
.push_hint(u8"Are you sure the path you specified is correct?")
|
||||
.push_hint(fmt::format(u8"The path you specified: {}", nkg::cp_converter<-1, CP_UTF8>::convert(navicat_install_path.native())));
|
||||
}
|
||||
|
||||
if (!rsa_privkey_filepath.empty() && !std::filesystem::is_regular_file(rsa_privkey_filepath)) {
|
||||
throw nkg::exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"RSA key file path doesn't point to a file.")
|
||||
.push_hint(u8"Are you sure the path you specified is correct?")
|
||||
.push_hint(fmt::format(u8"The path you specified: {}", nkg::cp_converter<-1, CP_UTF8>::convert(rsa_privkey_filepath.native())));
|
||||
}
|
||||
|
||||
nkg::rsa_cipher cipher;
|
||||
|
||||
std::filesystem::path libcc_filepath = navicat_install_path / "libcc.dll";
|
||||
nkg::resource_wrapper libcc_handle{ nkg::resource_traits::win32::file_handle{} };
|
||||
nkg::resource_wrapper libcc_map_handle{ nkg::resource_traits::win32::generic_handle{} };
|
||||
nkg::resource_wrapper libcc_map_view{ nkg::resource_traits::win32::map_view_ptr{} };
|
||||
std::optional<nkg::image_interpreter> libcc_interpreter;
|
||||
|
||||
nkg::resource_wrapper solution0{ nkg::resource_traits::cxx_object_traits<nkg::patch_solution>{} };
|
||||
|
||||
// open libcc.dll
|
||||
libcc_handle.set(CreateFileW(libcc_filepath.native().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL));
|
||||
if (libcc_handle.is_valid()) {
|
||||
wprintf_s(L"[+] Try to open libcc.dll ... OK!\n");
|
||||
} else {
|
||||
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
||||
wprintf_s(L"[-] Try to open libcc.dll ... NOT FOUND!\n");
|
||||
} else {
|
||||
throw nkg::exceptions::win32_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), u8"Failed to open libcc.dll");
|
||||
}
|
||||
}
|
||||
|
||||
if (libcc_handle.is_valid()) {
|
||||
libcc_map_handle.set(CreateFileMapping(libcc_handle.get(), NULL, PAGE_READWRITE, 0, 0, NULL));
|
||||
if (!libcc_map_handle.is_valid()) {
|
||||
throw nkg::exceptions::win32_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), u8"CreateFileMapping failed.");
|
||||
}
|
||||
|
||||
libcc_map_view.set(MapViewOfFile(libcc_map_handle.get(), FILE_MAP_ALL_ACCESS, 0, 0, 0));
|
||||
if (!libcc_map_view.is_valid()) {
|
||||
throw nkg::exceptions::win32_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), u8"MapViewOfFile failed.");
|
||||
}
|
||||
|
||||
libcc_interpreter = nkg::image_interpreter::parse(libcc_map_view.get(), true);
|
||||
|
||||
solution0.set(new nkg::patch_solution_since<16, 0, 7, 0>(libcc_interpreter.value()));
|
||||
}
|
||||
|
||||
_putws(L"");
|
||||
|
||||
// find patch and decide which solution will be applied
|
||||
if (solution0.is_valid()) {
|
||||
auto patch_found = solution0->find_patch();
|
||||
_putws(L"");
|
||||
|
||||
if (!patch_found) {
|
||||
solution0.release();
|
||||
}
|
||||
}
|
||||
|
||||
select_patch_solutions(solution0);
|
||||
|
||||
if (all_patch_solutions_are_suppressed(solution0)) {
|
||||
throw nkg::exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"All patch solutions are suppressed. Patch abort!")
|
||||
.push_hint(u8"Are you sure your navicat has not been patched/modified before?");
|
||||
}
|
||||
|
||||
// load key
|
||||
load_rsa_privkey(cipher, rsa_privkey_filepath, solution0.get());
|
||||
|
||||
// apply patch solutions
|
||||
if (dry_run) {
|
||||
_putws(L"*******************************************************");
|
||||
_putws(L"* DRY-RUN MODE ENABLE! *");
|
||||
_putws(L"* NO PATCH WILL BE APPLIED! *");
|
||||
_putws(L"*******************************************************");
|
||||
} else {
|
||||
// save private key if not given
|
||||
if (rsa_privkey_filepath.empty()) {
|
||||
cipher.export_private_key_file(u8"RegPrivateKey.pem");
|
||||
}
|
||||
|
||||
// detecting backups
|
||||
if (solution0.is_valid()) {
|
||||
detect_backup(libcc_filepath);
|
||||
}
|
||||
|
||||
// make backup
|
||||
if (solution0.is_valid()) {
|
||||
make_backup(libcc_filepath);
|
||||
}
|
||||
|
||||
// make patch
|
||||
// no way to go back from here :-)
|
||||
if (solution0.is_valid()) {
|
||||
solution0->make_patch(cipher);
|
||||
}
|
||||
|
||||
// print new key file path
|
||||
if (rsa_privkey_filepath.empty()) {
|
||||
wprintf_s(L"[*] New RSA-2048 private key has been saved to\n");
|
||||
wprintf_s(L" %s\n", (std::filesystem::current_path() / L"RegPrivateKey.pem").c_str());
|
||||
wprintf_s(L"\n");
|
||||
}
|
||||
|
||||
_putws(L"");
|
||||
_putws(L"*******************************************************");
|
||||
_putws(L"* PATCH HAS BEEN DONE SUCCESSFULLY! *");
|
||||
_putws(L"* HAVE FUN AND ENJOY~ *");
|
||||
_putws(L"*******************************************************");
|
||||
}
|
||||
|
||||
return 0;
|
||||
} catch (nkg::exception& e) {
|
||||
wprintf_s(L"[-] %s:%d ->\n", nkg::cp_converter<CP_UTF8, -1>::convert(e.source_file()).c_str(), e.source_line());
|
||||
wprintf_s(L" %s\n", nkg::cp_converter<CP_UTF8, -1>::convert(e.custom_message()).c_str());
|
||||
if (e.error_code_exists()) {
|
||||
wprintf_s(L" %s (0x%zx)\n", nkg::cp_converter<CP_UTF8, -1>::convert(e.error_string()).c_str(), e.error_code());
|
||||
}
|
||||
|
||||
for (auto& hint : e.hints()) {
|
||||
wprintf_s(L" HINT: %s\n", nkg::cp_converter<CP_UTF8, -1>::convert(hint).c_str());
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
help();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
Loading…
Reference in New Issue
Block a user