Compare commits
No commits in common. "windows" and "windows-archived2" have entirely different histories.
windows
...
windows-ar
68
.github/workflows/build.yml
vendored
68
.github/workflows/build.yml
vendored
@ -1,68 +0,0 @@
|
||||
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
|
||||
17
README.md
17
README.md
@ -1,22 +1,20 @@
|
||||
# navicat-keygen
|
||||
# Navicat Keygen
|
||||
|
||||
[中文版README](README.zh-CN.md)
|
||||
|
||||
This repository will tell you how Navicat offline activation works.
|
||||
|
||||
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 :-(
|
||||
Previous code is archived in [`windows-archived`](https://github.com/DoubleLabyrinth/navicat-keygen/tree/windows-archived) branch for the reason that previous code contains 3rd binary libraries and it gets quite big :-(
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
When you git-clone this repo, please add `--single-branch` flag so that archived branch won't be cloned to your computer, which saves your time and disk.
|
||||
|
||||
```console
|
||||
$ git clone -b windows --single-branch https://notabug.org/doublesine/navicat-keygen.git
|
||||
$ git clone -b windows --single-branch https://github.com/DoubleLabyrinth/navicat-keygen.git
|
||||
```
|
||||
|
||||
## 1. How does it work?
|
||||
|
||||
see [here](doc/how-does-it-work.md). (WATING TO BE UPDATED)
|
||||
see [here](doc/how-does-it-work.md)
|
||||
|
||||
## 2. How to build?
|
||||
|
||||
@ -24,7 +22,9 @@ see [here](doc/how-to-build.md).
|
||||
|
||||
## 3. How to use?
|
||||
|
||||
see [here](doc/how-to-use.md).
|
||||
For Windows users, see [here](doc/how-to-use.windows.md).
|
||||
|
||||
For Linux users, see [here](doc/how-to-use.linux.md).
|
||||
|
||||
## 4. Contributor
|
||||
|
||||
@ -33,3 +33,4 @@ see [here](doc/how-to-use.md).
|
||||
* dragonflylee
|
||||
|
||||
* zenuo
|
||||
|
||||
|
||||
@ -1,15 +1,13 @@
|
||||
# navicat-keygen for windows
|
||||
# Navicat Keygen
|
||||
|
||||
这份repo将会告诉你Navicat是怎么完成离线激活的。
|
||||
|
||||
第一次归档的代码位于 [`windows-archived`](https://notabug.org/doublesine/navicat-keygen/src/windows-archived) 分支。归档原因:包含第三方二进制库,项目过大。
|
||||
由于历史代码包含第三方二进制库,且大小较大,故决定将该项目的历史代码归档到 [`windows-archived`](https://github.com/DoubleLabyrinth/navicat-keygen/tree/windows-archived) 分支。
|
||||
|
||||
第二次归档的代码位于 [`windows-archived2`](https://notabug.org/doublesine/navicat-keygen/src/windows-archived2) 分支。归档原因:Navicat进入16.x.x版本,本项目打算进行重构。
|
||||
|
||||
当你clone该仓库的时候,请使用 `--single-branch` 选项,以此避免clone到已被归档的分支、以及节省你的时间和磁盘空间。
|
||||
当你clone该仓库的时候,请使用 `--single-branch` 选项,以此避免clone到 `windows-archived` 分支,并且还可以节省你的时间和磁盘空间。
|
||||
|
||||
```console
|
||||
$ git clone -b windows --single-branch https://notabug.org/doublesine/navicat-keygen.git
|
||||
$ git clone -b windows --single-branch https://github.com/DoubleLabyrinth/navicat-keygen.git
|
||||
```
|
||||
|
||||
## 1. 注册机是怎么工作的?
|
||||
@ -22,7 +20,9 @@ $ git clone -b windows --single-branch https://notabug.org/doublesine/navicat-ke
|
||||
|
||||
## 3. 如何使用这个注册机?
|
||||
|
||||
见[这里](doc/how-to-use.zh-CN.md)。
|
||||
针对 Windows 用户,请见[这里](doc/how-to-use.windows.zh-CN.md)。
|
||||
|
||||
针对 Linux 用户,请见[这里](doc/how-to-use.linux.zh-CN.md)。
|
||||
|
||||
## 4. 贡献者
|
||||
|
||||
|
||||
17
bash/navicat-keygen.sh
Normal file
17
bash/navicat-keygen.sh
Normal file
@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cd `dirname "$0"`
|
||||
navicat_root=`pwd`
|
||||
|
||||
# Wine environment variables
|
||||
WINEDIR="wine"
|
||||
export LANG="en_US.UTF-8"
|
||||
export PATH="$navicat_root/$WINEDIR/bin":"$navicat_root":"$navicat_root/$WINEDIR/drive_c/windows":"$PATH"
|
||||
export LD_LIBRARY_PATH="$navicat_root/$WINEDIR/lib":"$navicat_root/lib":"$LD_LIBRARY_PATH"
|
||||
export WINEDLLPATH="$navicat_root/$WINEDIR/lib/wine"
|
||||
export WINELOADER="$navicat_root/$WINEDIR/bin/wine64"
|
||||
export WINESERVER="$navicat_root/$WINEDIR/bin/wineserver"
|
||||
export WINEPREFIX="$HOME/.navicat64"
|
||||
export WINEDEBUG=-all # suppress all wine debug info
|
||||
|
||||
exec "${WINELOADER:-wine}" "navicat-keygen.exe" "-text" "RegPrivateKey.pem"
|
||||
27
bash/navicat-patcher.sh
Normal file
27
bash/navicat-patcher.sh
Normal file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cd `dirname "$0"`
|
||||
navicat_root=`pwd`
|
||||
|
||||
# Wine environment variables
|
||||
WINEDIR="wine"
|
||||
export LANG="en_US.UTF-8"
|
||||
export PATH="$navicat_root/$WINEDIR/bin":"$navicat_root":"$navicat_root/$WINEDIR/drive_c/windows":"$PATH"
|
||||
export LD_LIBRARY_PATH="$navicat_root/$WINEDIR/lib":"$navicat_root/lib":"$LD_LIBRARY_PATH"
|
||||
export WINEDLLPATH="$navicat_root/$WINEDIR/lib/wine"
|
||||
export WINELOADER="$navicat_root/$WINEDIR/bin/wine64"
|
||||
export WINESERVER="$navicat_root/$WINEDIR/bin/wineserver"
|
||||
export WINEPREFIX="$HOME/.navicat64"
|
||||
export WINEDEBUG=-all # suppress all wine debug info
|
||||
|
||||
# 将斜线替换为反斜线
|
||||
navicat_root_back_slash=${navicat_root//\//\\}
|
||||
# 前缀
|
||||
prefix='Z:\'
|
||||
# 后缀
|
||||
suffix='\Navicat'
|
||||
# wine环境中的navicat路径
|
||||
navicat_path="$prefix$navicat_root_back_slash$suffix"
|
||||
|
||||
# wine执行navicat-patcher.exe
|
||||
exec "${WINELOADER:-wine}" "navicat-patcher.exe" "$navicat_path"
|
||||
66
common/Exception.hpp
Normal file
66
common/Exception.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
#include "xstring.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class Exception {
|
||||
private:
|
||||
|
||||
PCTSTR _SourceFile;
|
||||
SIZE_T _SourceLine;
|
||||
PCTSTR _Message;
|
||||
std::vector<std::xstring> _Hints;
|
||||
|
||||
public:
|
||||
|
||||
Exception(PCTSTR SourceFile, SIZE_T SourceLine, PCTSTR CustomMessage) noexcept :
|
||||
_SourceFile(SourceFile),
|
||||
_SourceLine(SourceLine),
|
||||
_Message(CustomMessage) {}
|
||||
|
||||
[[nodiscard]]
|
||||
auto File() const noexcept {
|
||||
return _SourceFile;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
auto Line() const noexcept {
|
||||
return _SourceLine;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
auto Message() const noexcept {
|
||||
return _Message;
|
||||
}
|
||||
|
||||
auto& AddHint(const std::xstring& Hint) {
|
||||
_Hints.emplace_back(Hint);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const auto& Hints() const noexcept {
|
||||
return _Hints;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool HasErrorCode() const noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual ULONG_PTR ErrorCode() const noexcept {
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual PCTSTR ErrorString() const noexcept {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual ~Exception() = default;
|
||||
};
|
||||
|
||||
}
|
||||
44
common/ExceptionOpenssl.hpp
Normal file
44
common/ExceptionOpenssl.hpp
Normal file
@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
#include "Exception.hpp"
|
||||
#include <openssl/err.h>
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class OpensslError final : public Exception {
|
||||
private:
|
||||
|
||||
unsigned long _ErrorCode;
|
||||
std::xstring _ErrorString;
|
||||
|
||||
public:
|
||||
|
||||
OpensslError(PCTSTR SourceFile, SIZE_T SourceLine, unsigned long OpensslErrorCode, PCTSTR CustomMessage) noexcept :
|
||||
Exception(SourceFile, SourceLine, CustomMessage),
|
||||
_ErrorCode(OpensslErrorCode)
|
||||
{
|
||||
static bool CryptoStringsLoaded = false;
|
||||
if (CryptoStringsLoaded == false) {
|
||||
ERR_load_crypto_strings();
|
||||
CryptoStringsLoaded = true;
|
||||
}
|
||||
|
||||
_ErrorString = std::xstring(std::xstring_extension{}, ERR_reason_error_string(_ErrorCode), CP_UTF8);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool HasErrorCode() const noexcept override {
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual ULONG_PTR ErrorCode() const noexcept override {
|
||||
return _ErrorCode;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual PCTSTR ErrorString() const noexcept override {
|
||||
return _ErrorString.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
28
common/ExceptionUser.hpp
Normal file
28
common/ExceptionUser.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "Exception.hpp"
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class UserAbortionError final : public Exception {
|
||||
public:
|
||||
|
||||
UserAbortionError(PCTSTR SourceFile, SIZE_T SourceLine, PCTSTR CustomMessage) noexcept :
|
||||
Exception(SourceFile, SourceLine, CustomMessage) {}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool HasErrorCode() const noexcept override {
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual ULONG_PTR ErrorCode() const noexcept override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual PCTSTR ErrorString() const noexcept override {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
49
common/ExceptionWin32.hpp
Normal file
49
common/ExceptionWin32.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
#include "Exception.hpp"
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class Win32Error final : public Exception {
|
||||
private:
|
||||
|
||||
DWORD _ErrorCode;
|
||||
std::xstring _ErrorString;
|
||||
|
||||
public:
|
||||
|
||||
Win32Error(PCTSTR SourceFile, SIZE_T SourceLine, DWORD Win32ErrorCode, PCTSTR CustomMessage) noexcept :
|
||||
Exception(SourceFile, SourceLine, CustomMessage),
|
||||
_ErrorCode(Win32ErrorCode)
|
||||
{
|
||||
PTSTR Text = NULL;
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
||||
NULL,
|
||||
Win32ErrorCode,
|
||||
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
|
||||
reinterpret_cast<PTSTR>(&Text),
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
if (Text) {
|
||||
_ErrorString = Text;
|
||||
LocalFree(Text);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool HasErrorCode() const noexcept override {
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual ULONG_PTR ErrorCode() const noexcept override {
|
||||
return _ErrorCode;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual PCTSTR ErrorString() const noexcept override {
|
||||
return _ErrorString.c_str();
|
||||
}
|
||||
};
|
||||
}
|
||||
270
common/RSACipher.hpp
Normal file
270
common/RSACipher.hpp
Normal file
@ -0,0 +1,270 @@
|
||||
#pragma once
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include "Exception.hpp"
|
||||
#include "ExceptionOpenssl.hpp"
|
||||
#include "ResourceOwned.hpp"
|
||||
#include "ResourceTraitsOpenssl.hpp"
|
||||
|
||||
#pragma comment(lib, "crypt32") // required by libcrypto.lib
|
||||
#pragma comment(lib, "ws2_32") // required by libcrypto.lib
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\common\\RSACipher.hpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
enum class RSAKeyType {
|
||||
PrivateKey,
|
||||
PublicKey
|
||||
};
|
||||
|
||||
enum class RSAKeyFormat {
|
||||
PEM,
|
||||
PKCS1
|
||||
};
|
||||
|
||||
class RSACipher final : private ResourceOwned<OpensslRSATraits> {
|
||||
private:
|
||||
|
||||
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
||||
static void _WriteRSAToBIO(RSA* lpRSA, BIO* lpBIO) {
|
||||
if constexpr (__Type == RSAKeyType::PrivateKey) {
|
||||
if (PEM_write_bio_RSAPrivateKey(lpBIO, lpRSA, nullptr, nullptr, 0, nullptr, nullptr) == 0) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("PEM_write_bio_RSAPrivateKey failed."));
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (__Type == RSAKeyType::PublicKey) {
|
||||
if constexpr (__Format == RSAKeyFormat::PEM) {
|
||||
if (PEM_write_bio_RSA_PUBKEY(lpBIO, lpRSA) == 0) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("PEM_write_bio_RSA_PUBKEY failed."));
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (__Format == RSAKeyFormat::PKCS1) {
|
||||
if (PEM_write_bio_RSAPublicKey(lpBIO, lpRSA) == 0) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("PEM_write_bio_RSAPublicKey failed."));
|
||||
}
|
||||
}
|
||||
|
||||
static_assert(__Format == RSAKeyFormat::PEM || __Format == RSAKeyFormat::PKCS1);
|
||||
}
|
||||
|
||||
static_assert(__Type == RSAKeyType::PrivateKey || __Type == RSAKeyType::PublicKey);
|
||||
}
|
||||
|
||||
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
||||
[[nodiscard]]
|
||||
static RSA* _ReadRSAFromBIO(BIO* lpBIO) {
|
||||
RSA* lpRSA;
|
||||
|
||||
if constexpr (__Type == RSAKeyType::PrivateKey) {
|
||||
lpRSA = PEM_read_bio_RSAPrivateKey(lpBIO, nullptr, nullptr, nullptr);
|
||||
if (lpRSA == nullptr) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("PEM_read_bio_RSAPrivateKey failed."))
|
||||
.AddHint(TEXT("Are you sure that you DO provide a valid RSA private key file?"));
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (__Type == RSAKeyType::PublicKey) {
|
||||
if constexpr (__Format == RSAKeyFormat::PEM) {
|
||||
lpRSA = PEM_read_bio_RSA_PUBKEY(lpBIO, nullptr, nullptr, nullptr);
|
||||
if (lpRSA == nullptr) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("PEM_read_bio_RSA_PUBKEY failed."))
|
||||
.AddHint(TEXT("Are you sure that you DO provide a valid RSA public key file with PEM format?"));
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (__Format == RSAKeyFormat::PKCS1) {
|
||||
lpRSA = PEM_read_bio_RSAPublicKey(lpBIO, nullptr, nullptr, nullptr);
|
||||
if (lpRSA == nullptr) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("PEM_read_bio_RSAPublicKey failed."))
|
||||
.AddHint(TEXT("Are you sure that you DO provide a valid RSA public key file with PKCS1 format?"));
|
||||
}
|
||||
}
|
||||
|
||||
static_assert(__Format == RSAKeyFormat::PEM || __Format == RSAKeyFormat::PKCS1);
|
||||
}
|
||||
|
||||
static_assert(__Type == RSAKeyType::PrivateKey || __Type == RSAKeyType::PublicKey);
|
||||
|
||||
return lpRSA;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
RSACipher() : ResourceOwned<OpensslRSATraits>(RSA_new()) {
|
||||
if (IsValid() == false) {
|
||||
throw OpensslError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ERR_get_error(), TEXT("RSA_new failed."));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
size_t Bits() const {
|
||||
#if (OPENSSL_VERSION_NUMBER & 0xffff0000) == 0x10000000 // openssl 1.0.x
|
||||
if (Get()->n == nullptr) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("RSA modulus has not been set."));
|
||||
} else {
|
||||
return BN_num_bits(Get()->n);
|
||||
}
|
||||
#elif (OPENSSL_VERSION_NUMBER & 0xffff0000) == 0x10100000 // openssl 1.1.x
|
||||
return RSA_bits(Get());
|
||||
#else
|
||||
#error "RSACipher.hpp: unexpected OpenSSL version."
|
||||
#endif
|
||||
}
|
||||
|
||||
void GenerateKey(int bits, unsigned int e = RSA_F4) {
|
||||
ResourceOwned<OpensslBNTraits> bn_e(BN_new());
|
||||
|
||||
if (bn_e.IsValid() == false) {
|
||||
throw OpensslError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ERR_get_error(), TEXT("BN_new failed."));
|
||||
}
|
||||
|
||||
if (!BN_set_word(bn_e, e)) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("BN_set_word failed."));
|
||||
}
|
||||
|
||||
if (!RSA_generate_key_ex(Get(), bits, bn_e, nullptr)) {
|
||||
throw OpensslError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ERR_get_error(), TEXT("RSA_generate_key_ex failed."));
|
||||
}
|
||||
}
|
||||
|
||||
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
||||
void ExportKeyToFile(const std::xstring& FileName) const {
|
||||
ResourceOwned<OpensslBIOTraits> BioFile(BIO_new_file(FileName.explicit_string(CP_UTF8).c_str(), "w"));
|
||||
|
||||
if (BioFile.IsValid() == false) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("BIO_new_file failed."));
|
||||
}
|
||||
|
||||
_WriteRSAToBIO<__Type, __Format>(Get(), BioFile);
|
||||
}
|
||||
|
||||
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
||||
[[nodiscard]]
|
||||
std::string ExportKeyString() const {
|
||||
ResourceOwned<OpensslBIOTraits> BioMemory(BIO_new(BIO_s_mem()));
|
||||
long StringLength;
|
||||
const char* StringChars = nullptr;
|
||||
|
||||
if (BioMemory.IsValid() == false) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("BIO_new failed."));
|
||||
}
|
||||
|
||||
_WriteRSAToBIO<__Type, __Format>(Get(), BioMemory);
|
||||
|
||||
StringLength = BIO_get_mem_data(BioMemory.Get(), &StringChars);
|
||||
|
||||
return std::string(StringChars, StringLength);
|
||||
}
|
||||
|
||||
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
||||
void ImportKeyFromFile(const std::xstring& FileName) {
|
||||
ResourceOwned<OpensslBIOTraits> BioFile(BIO_new_file(FileName.explicit_string(CP_UTF8).c_str(), "r"));
|
||||
|
||||
if (BioFile.IsValid() == false) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("BIO_new_file failed."));
|
||||
}
|
||||
|
||||
TakeOver(_ReadRSAFromBIO<__Type, __Format>(BioFile));
|
||||
}
|
||||
|
||||
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
||||
void ImportKeyString(const std::string& KeyString) {
|
||||
ResourceOwned<OpensslBIOTraits> BioMemory(BIO_new(BIO_s_mem()));
|
||||
|
||||
if (BioMemory.IsValid() == false) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("BIO_new failed."));
|
||||
}
|
||||
|
||||
if (BIO_puts(BioMemory.Get(), KeyString.c_str()) <= 0) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("BIO_puts failed."));
|
||||
}
|
||||
|
||||
TakeOver(_ReadRSAFromBIO<__Type, __Format>(BioMemory));
|
||||
}
|
||||
|
||||
template<RSAKeyType __Type = RSAKeyType::PublicKey>
|
||||
size_t Encrypt(const void* lpFrom, size_t cbFrom, void* lpTo, int Padding) const {
|
||||
int BytesWritten;
|
||||
|
||||
if (cbFrom > INT_MAX) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Length overflowed."));
|
||||
}
|
||||
|
||||
if constexpr (__Type == RSAKeyType::PrivateKey) {
|
||||
BytesWritten = RSA_private_encrypt(
|
||||
static_cast<int>(cbFrom),
|
||||
reinterpret_cast<const unsigned char*>(lpFrom),
|
||||
reinterpret_cast<unsigned char*>(lpTo),
|
||||
Get(),
|
||||
Padding
|
||||
);
|
||||
|
||||
if (BytesWritten == -1) {
|
||||
throw OpensslError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ERR_get_error(), TEXT("RSA_private_encrypt failed."));
|
||||
}
|
||||
} else {
|
||||
BytesWritten = RSA_public_encrypt(
|
||||
static_cast<int>(cbFrom),
|
||||
reinterpret_cast<const unsigned char*>(lpFrom),
|
||||
reinterpret_cast<unsigned char*>(lpTo),
|
||||
Get(),
|
||||
Padding
|
||||
);
|
||||
|
||||
if (BytesWritten == -1) {
|
||||
throw OpensslError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ERR_get_error(), TEXT("RSA_public_encrypt failed."));
|
||||
}
|
||||
}
|
||||
|
||||
return BytesWritten;
|
||||
}
|
||||
|
||||
template<RSAKeyType __Type = RSAKeyType::PrivateKey>
|
||||
size_t Decrypt(const void* lpFrom, size_t cbFrom, void* lpTo, int Padding) const {
|
||||
int BytesWritten;
|
||||
|
||||
if (cbFrom > INT_MAX) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Length overflowed."));
|
||||
}
|
||||
|
||||
if constexpr (__Type == RSAKeyType::PrivateKey) {
|
||||
BytesWritten = RSA_private_decrypt(
|
||||
static_cast<int>(cbFrom),
|
||||
reinterpret_cast<const unsigned char*>(lpFrom),
|
||||
reinterpret_cast<unsigned char*>(lpTo),
|
||||
Get(),
|
||||
Padding
|
||||
);
|
||||
|
||||
if (BytesWritten == -1) {
|
||||
throw OpensslError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ERR_get_error(), TEXT("RSA_private_decrypt failed."))
|
||||
.AddHint(TEXT("Are your sure you DO provide a correct private key?"));
|
||||
}
|
||||
} else {
|
||||
BytesWritten = RSA_public_decrypt(
|
||||
static_cast<int>(cbFrom),
|
||||
reinterpret_cast<const unsigned char*>(lpFrom),
|
||||
reinterpret_cast<unsigned char*>(lpTo),
|
||||
Get(),
|
||||
Padding
|
||||
);
|
||||
|
||||
if (BytesWritten == -1) {
|
||||
throw OpensslError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ERR_get_error(), TEXT("RSA_public_decrypt failed."))
|
||||
.AddHint(TEXT("Are your sure you DO provide a correct public key?"));
|
||||
}
|
||||
}
|
||||
|
||||
return BytesWritten;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
313
common/ResourceOwned.hpp
Normal file
313
common/ResourceOwned.hpp
Normal file
@ -0,0 +1,313 @@
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
template<typename __ResourceTraits, typename __LambdaReleasor = void>
|
||||
class ResourceOwned {
|
||||
private:
|
||||
|
||||
using __HandleType = typename __ResourceTraits::HandleType;
|
||||
static_assert(std::is_pod_v<__HandleType>);
|
||||
|
||||
__HandleType _Handle;
|
||||
__LambdaReleasor _Releasor;
|
||||
|
||||
public:
|
||||
|
||||
ResourceOwned(__LambdaReleasor&& Releasor) noexcept :
|
||||
_Handle(__ResourceTraits::InvalidValue),
|
||||
_Releasor(std::forward<__LambdaReleasor>(Releasor)) {}
|
||||
|
||||
ResourceOwned(const __HandleType& Handle, __LambdaReleasor&& Releasor) noexcept :
|
||||
_Handle(Handle),
|
||||
_Releasor(std::forward<__LambdaReleasor>(Releasor)) {}
|
||||
|
||||
//
|
||||
// Construct from custom releasor.
|
||||
// `_Handle` will be set to an invalid value.
|
||||
//
|
||||
ResourceOwned(__ResourceTraits, __LambdaReleasor&& Releasor) noexcept :
|
||||
_Handle(__ResourceTraits::InvalidValue),
|
||||
_Releasor(std::forward<__LambdaReleasor>(Releasor)) {}
|
||||
|
||||
//
|
||||
// Construct from handle given and custom releasor.
|
||||
//
|
||||
ResourceOwned(__ResourceTraits, const __HandleType& Handle, __LambdaReleasor&& Releasor) noexcept :
|
||||
_Handle(Handle),
|
||||
_Releasor(std::forward<__LambdaReleasor>(Releasor)) {}
|
||||
|
||||
//
|
||||
// ResourceOwned doesn't allow to copy.
|
||||
// Because it takes `_Handle` exclusively.
|
||||
//
|
||||
ResourceOwned(const ResourceOwned<__ResourceTraits, __LambdaReleasor>& Other) = delete;
|
||||
|
||||
//
|
||||
// ResourceOwned allows to move.
|
||||
//
|
||||
ResourceOwned(ResourceOwned<__ResourceTraits, __LambdaReleasor>&& Other) noexcept :
|
||||
_Handle(Other._Handle),
|
||||
_Releasor(std::move(Other._Releasor))
|
||||
{
|
||||
Other._Handle = __ResourceTraits::InvalidValue;
|
||||
}
|
||||
|
||||
//
|
||||
// ResourceOwned doesn't allow to copy.
|
||||
// Because it takes `_Handle` exclusively.
|
||||
//
|
||||
ResourceOwned<__ResourceTraits, __LambdaReleasor>& operator=(const ResourceOwned<__ResourceTraits, __LambdaReleasor>& Other) = delete;
|
||||
|
||||
//
|
||||
// ResourceOwned allows to move.
|
||||
//
|
||||
ResourceOwned<__ResourceTraits, __LambdaReleasor>& operator=(ResourceOwned<__ResourceTraits, __LambdaReleasor>&& Other) noexcept {
|
||||
_Handle = Other._Handle;
|
||||
_Releasor = std::move(Other._Releasor);
|
||||
Other._Handle = __ResourceTraits::InvalidValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
operator const __HandleType&() const noexcept { // NOLINT: Allow implicit conversion.
|
||||
return _Handle;
|
||||
}
|
||||
|
||||
template<typename __AsType, bool __IsPointer = std::is_pointer_v<__HandleType>, typename = std::enable_if_t<__IsPointer>>
|
||||
[[nodiscard]]
|
||||
__AsType As() const noexcept {
|
||||
return reinterpret_cast<__AsType>(_Handle);
|
||||
}
|
||||
|
||||
template<bool __IsPointer = std::is_pointer_v<__HandleType>, typename = typename std::enable_if_t<__IsPointer>>
|
||||
[[nodiscard]]
|
||||
__HandleType operator->() const noexcept {
|
||||
return _Handle;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool IsValid() const noexcept {
|
||||
return __ResourceTraits::IsValid(_Handle);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const __HandleType& Get() const noexcept {
|
||||
return _Handle;
|
||||
}
|
||||
|
||||
template<typename __ReturnType = __HandleType*>
|
||||
[[nodiscard]]
|
||||
__ReturnType GetAddressOf() noexcept {
|
||||
return reinterpret_cast<__ReturnType>(&_Handle);
|
||||
}
|
||||
|
||||
void TakeOver(const __HandleType& Handle) {
|
||||
if (__ResourceTraits::IsValid(_Handle) == true) {
|
||||
_Releasor(_Handle);
|
||||
}
|
||||
_Handle = Handle;
|
||||
}
|
||||
|
||||
void Discard() noexcept {
|
||||
_Handle = __ResourceTraits::InvalidValue;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
__HandleType Transfer() noexcept {
|
||||
__HandleType t = _Handle;
|
||||
_Handle = __ResourceTraits::InvalidValue;
|
||||
return t;
|
||||
}
|
||||
|
||||
void Release() {
|
||||
if (__ResourceTraits::IsValid(_Handle)) {
|
||||
_Releasor(_Handle);
|
||||
_Handle = __ResourceTraits::InvalidValue;
|
||||
}
|
||||
}
|
||||
|
||||
~ResourceOwned() {
|
||||
if (__ResourceTraits::IsValid(_Handle)) {
|
||||
_Releasor(_Handle);
|
||||
_Handle = __ResourceTraits::InvalidValue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename __ResourceTraits>
|
||||
class ResourceOwned<__ResourceTraits, void> {
|
||||
private:
|
||||
|
||||
using __HandleType = typename __ResourceTraits::HandleType;
|
||||
static_assert(std::is_pod_v<__HandleType>);
|
||||
|
||||
__HandleType _Handle;
|
||||
|
||||
public:
|
||||
|
||||
ResourceOwned() noexcept :
|
||||
_Handle(__ResourceTraits::InvalidValue) {}
|
||||
|
||||
ResourceOwned(const __HandleType& Handle) noexcept :
|
||||
_Handle(Handle) {}
|
||||
|
||||
//
|
||||
// Construct from custom releasor.
|
||||
// `_Handle` will be set to an invalid value.
|
||||
//
|
||||
explicit ResourceOwned(__ResourceTraits) noexcept :
|
||||
_Handle(__ResourceTraits::InvalidValue) {}
|
||||
|
||||
//
|
||||
// Construct from handle given and custom releasor.
|
||||
//
|
||||
ResourceOwned(__ResourceTraits, const __HandleType& Handle) noexcept :
|
||||
_Handle(Handle) {}
|
||||
|
||||
//
|
||||
// ResourceOwned doesn't allow to copy.
|
||||
// Because it takes `_Handle` exclusively.
|
||||
//
|
||||
ResourceOwned(const ResourceOwned<__ResourceTraits, void>& Other) = delete;
|
||||
|
||||
//
|
||||
// ResourceOwned allows to move.
|
||||
//
|
||||
ResourceOwned(ResourceOwned<__ResourceTraits, void>&& Other) noexcept :
|
||||
_Handle(Other._Handle) {
|
||||
Other._Handle = __ResourceTraits::InvalidValue;
|
||||
}
|
||||
|
||||
//
|
||||
// ResourceOwned doesn't allow to copy.
|
||||
// Because it takes `_Handle` exclusively.
|
||||
//
|
||||
ResourceOwned<__ResourceTraits, void>& operator=(const ResourceOwned<__ResourceTraits, void>& Other) = delete;
|
||||
|
||||
//
|
||||
// ResourceOwned allows to move.
|
||||
//
|
||||
ResourceOwned<__ResourceTraits, void>& operator=(ResourceOwned<__ResourceTraits, void>&& Other) noexcept {
|
||||
_Handle = Other._Handle;
|
||||
Other._Handle = __ResourceTraits::InvalidValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
operator const __HandleType&() const noexcept { // NOLINT: Allow implicit conversion.
|
||||
return _Handle;
|
||||
}
|
||||
|
||||
template<typename __AsType, bool __IsPointer = std::is_pointer_v<__HandleType>, typename = typename std::enable_if_t<__IsPointer>>
|
||||
[[nodiscard]]
|
||||
__AsType As() const noexcept {
|
||||
return reinterpret_cast<__AsType>(_Handle);
|
||||
}
|
||||
|
||||
template<bool __IsPointer = std::is_pointer_v<__HandleType>, typename = typename std::enable_if_t<__IsPointer>>
|
||||
[[nodiscard]]
|
||||
__HandleType operator->() const noexcept {
|
||||
return _Handle;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool IsValid() const noexcept {
|
||||
return __ResourceTraits::IsValid(_Handle);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const __HandleType& Get() const noexcept {
|
||||
return _Handle;
|
||||
}
|
||||
|
||||
template<typename __ReturnType = __HandleType*>
|
||||
[[nodiscard]]
|
||||
__ReturnType GetAddressOf() noexcept {
|
||||
return reinterpret_cast<__ReturnType>(&_Handle);
|
||||
}
|
||||
|
||||
void TakeOver(const __HandleType& Handle) {
|
||||
if (__ResourceTraits::IsValid(_Handle) == true) {
|
||||
__ResourceTraits::Releasor(_Handle);
|
||||
}
|
||||
_Handle = Handle;
|
||||
}
|
||||
|
||||
void Discard() noexcept {
|
||||
_Handle = __ResourceTraits::InvalidValue;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
__HandleType Transfer() noexcept {
|
||||
__HandleType t = _Handle;
|
||||
_Handle = __ResourceTraits::InvalidValue;
|
||||
return t;
|
||||
}
|
||||
|
||||
void Release() {
|
||||
if (__ResourceTraits::IsValid(_Handle)) {
|
||||
__ResourceTraits::Releasor(_Handle);
|
||||
_Handle = __ResourceTraits::InvalidValue;
|
||||
}
|
||||
}
|
||||
|
||||
~ResourceOwned() {
|
||||
if (__ResourceTraits::IsValid(_Handle)) {
|
||||
__ResourceTraits::Releasor(_Handle);
|
||||
_Handle = __ResourceTraits::InvalidValue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename __ResourceTraits>
|
||||
ResourceOwned(__ResourceTraits) ->
|
||||
ResourceOwned<__ResourceTraits, void>;
|
||||
|
||||
template<typename __ResourceTraits, typename __ArgType>
|
||||
ResourceOwned(__ResourceTraits, __ArgType&&) ->
|
||||
ResourceOwned<
|
||||
__ResourceTraits,
|
||||
std::conditional_t<
|
||||
std::is_same_v<std::remove_cv_t<std::remove_reference_t<__ArgType>>, typename __ResourceTraits::HandleType> == false,
|
||||
std::remove_reference_t<__ArgType>,
|
||||
void
|
||||
>
|
||||
>;
|
||||
|
||||
template<typename __ResourceTraits, typename __LambdaReleasor>
|
||||
ResourceOwned(__ResourceTraits, const typename __ResourceTraits::HandleType&, __LambdaReleasor&&) ->
|
||||
ResourceOwned<__ResourceTraits, std::remove_reference_t<__LambdaReleasor>>;
|
||||
|
||||
template<typename __ClassType>
|
||||
struct CppObjectTraits {
|
||||
using HandleType = __ClassType*;
|
||||
|
||||
static inline const HandleType InvalidValue = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool IsValid(const HandleType& Handle) noexcept {
|
||||
return Handle != InvalidValue;
|
||||
}
|
||||
|
||||
static void Releasor(const HandleType& Handle) {
|
||||
delete Handle;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename __ClassType>
|
||||
struct CppDynamicArrayTraits {
|
||||
using HandleType = __ClassType*;
|
||||
|
||||
static inline const HandleType InvalidValue = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool IsValid(const HandleType& Handle) noexcept {
|
||||
return Handle != InvalidValue;
|
||||
}
|
||||
|
||||
static void Releasor(const HandleType& Handle) {
|
||||
delete[] Handle;
|
||||
}
|
||||
};
|
||||
|
||||
64
common/ResourceTraitsOpenssl.hpp
Normal file
64
common/ResourceTraitsOpenssl.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
struct OpensslBIOTraits {
|
||||
using HandleType = BIO*;
|
||||
|
||||
static inline const HandleType InvalidValue = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool IsValid(const HandleType& Handle) noexcept {
|
||||
return Handle != InvalidValue;
|
||||
}
|
||||
|
||||
static void Releasor(const HandleType& Handle) noexcept {
|
||||
BIO_free(Handle);
|
||||
}
|
||||
};
|
||||
|
||||
struct OpensslBIOChainTraits {
|
||||
using HandleType = BIO*;
|
||||
|
||||
static inline const HandleType InvalidValue = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool IsValid(const HandleType& Handle) noexcept {
|
||||
return Handle != InvalidValue;
|
||||
}
|
||||
|
||||
static void Releasor(const HandleType& Handle) noexcept {
|
||||
BIO_free_all(Handle);
|
||||
}
|
||||
};
|
||||
|
||||
struct OpensslBNTraits {
|
||||
using HandleType = BIGNUM*;
|
||||
|
||||
static inline const HandleType InvalidValue = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool IsValid(const HandleType& Handle) noexcept {
|
||||
return Handle != InvalidValue;
|
||||
}
|
||||
|
||||
static void Releasor(const HandleType& Handle) noexcept {
|
||||
BN_free(Handle);
|
||||
}
|
||||
};
|
||||
|
||||
struct OpensslRSATraits {
|
||||
using HandleType = RSA*;
|
||||
|
||||
static inline const HandleType InvalidValue = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool IsValid(const HandleType& Handle) noexcept {
|
||||
return Handle != InvalidValue;
|
||||
}
|
||||
|
||||
static void Releasor(const HandleType& Handle) noexcept {
|
||||
RSA_free(Handle);
|
||||
}
|
||||
};
|
||||
|
||||
47
common/ResourceTraitsWin32.hpp
Normal file
47
common/ResourceTraitsWin32.hpp
Normal file
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
|
||||
struct GenericHandleTraits {
|
||||
using HandleType = HANDLE;
|
||||
|
||||
static inline const HandleType InvalidValue = NULL;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool IsValid(const HandleType& Handle) noexcept {
|
||||
return Handle != InvalidValue;
|
||||
}
|
||||
|
||||
static void Releasor(const HandleType& Handle) noexcept {
|
||||
CloseHandle(Handle);
|
||||
}
|
||||
};
|
||||
|
||||
struct FileHandleTraits {
|
||||
using HandleType = HANDLE;
|
||||
|
||||
static inline const HandleType InvalidValue = INVALID_HANDLE_VALUE;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool IsValid(const HandleType& Handle) noexcept {
|
||||
return Handle != InvalidValue;
|
||||
}
|
||||
|
||||
static void Releasor(const HandleType& Handle) noexcept {
|
||||
CloseHandle(Handle);
|
||||
}
|
||||
};
|
||||
|
||||
struct MapViewHandleTraits {
|
||||
using HandleType = PVOID;
|
||||
|
||||
static inline const HandleType InvalidValue = NULL;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool IsValid(const HandleType& Handle) noexcept {
|
||||
return Handle != InvalidValue;
|
||||
}
|
||||
|
||||
static void Releasor(const HandleType& Handle) noexcept {
|
||||
UnmapViewOfFile(Handle);
|
||||
}
|
||||
};
|
||||
9
common/bytearray.hpp
Normal file
9
common/bytearray.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
namespace std {
|
||||
|
||||
using bytearray = vector<uint8_t>;
|
||||
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
<?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>
|
||||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
<HasSharedItems>true</HasSharedItems>
|
||||
<ItemsProjectGuid>{6d81a756-475a-4093-919e-3e9217f662ca}</ItemsProjectGuid>
|
||||
<ItemsProjectGuid>{290c5d5e-52d2-4fef-909f-27fd95ae0af9}</ItemsProjectGuid>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
@ -14,36 +14,15 @@
|
||||
<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" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)bytearray.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)Exception.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ExceptionOpenssl.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ExceptionUser.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ExceptionWin32.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ResourceOwned.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ResourceTraitsOpenssl.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ResourceTraitsWin32.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)RSACipher.hpp" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)xstring.hpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@ -1,79 +0,0 @@
|
||||
#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
|
||||
@ -1,86 +0,0 @@
|
||||
#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;
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
#include "../exception.hpp"
|
||||
|
||||
namespace nkg::exceptions {
|
||||
|
||||
class index_exception : public ::nkg::exception {
|
||||
using ::nkg::exception::exception;
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
#include "../exception.hpp"
|
||||
|
||||
namespace nkg::exceptions {
|
||||
|
||||
class key_exception : public ::nkg::exception {
|
||||
using ::nkg::exception::exception;
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
#include "../exception.hpp"
|
||||
|
||||
namespace nkg::exceptions {
|
||||
|
||||
class not_implemented_exception : public ::nkg::exception {
|
||||
using ::nkg::exception::exception;
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
#include "../exception.hpp"
|
||||
|
||||
namespace nkg::exceptions {
|
||||
|
||||
class operation_canceled_exception : public ::nkg::exception {
|
||||
using ::nkg::exception::exception;
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
#include "../exception.hpp"
|
||||
|
||||
namespace nkg::exceptions {
|
||||
|
||||
class overflow_exception : public ::nkg::exception {
|
||||
using ::nkg::exception::exception;
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
#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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,245 +0,0 @@
|
||||
#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>>;
|
||||
|
||||
}
|
||||
@ -1,625 +0,0 @@
|
||||
#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
|
||||
@ -1,161 +0,0 @@
|
||||
#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
|
||||
288
common/xstring.hpp
Normal file
288
common/xstring.hpp
Normal file
@ -0,0 +1,288 @@
|
||||
#pragma once
|
||||
#include <tchar.h>
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
#include <system_error>
|
||||
|
||||
namespace std {
|
||||
|
||||
struct xstring_extension {};
|
||||
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
class xstring final : public wstring {
|
||||
public:
|
||||
|
||||
using wstring::wstring;
|
||||
using wstring::operator=;
|
||||
|
||||
xstring(const wstring& wstr) : wstring(wstr) {}
|
||||
|
||||
xstring(wstring&& wstr) : wstring(std::move(wstr)) {}
|
||||
|
||||
xstring(xstring_extension, const string& str, DWORD CodePage = CP_ACP) {
|
||||
auto len = MultiByteToWideChar(CodePage, 0, str.c_str(), -1, NULL, 0);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
resize(static_cast<size_t>(len) - 1);
|
||||
|
||||
len = MultiByteToWideChar(CodePage, 0, str.c_str(), -1, data(), len);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
}
|
||||
|
||||
xstring(xstring_extension, const char* lpstr, DWORD CodePage = CP_ACP) {
|
||||
auto len = MultiByteToWideChar(CodePage, 0, lpstr, -1, NULL, 0);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
resize(static_cast<size_t>(len) - 1);
|
||||
|
||||
len = MultiByteToWideChar(CodePage, 0, lpstr, -1, data(), len);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
}
|
||||
#else
|
||||
class xstring final : public string {
|
||||
public:
|
||||
|
||||
using string::string;
|
||||
using string::operator=;
|
||||
|
||||
xstring(const string& str) : string(str) {}
|
||||
|
||||
xstring(string&& str) : string(std::move(str)) {}
|
||||
|
||||
xstring(xstring_extension, const string& str, DWORD CodePage = CP_ACP) {
|
||||
if (CodePage == CP_ACP || CodePage == GetACP()) {
|
||||
assign(str);
|
||||
} else {
|
||||
std::wstring wstr;
|
||||
|
||||
auto len = MultiByteToWideChar(CodePage, 0, str.c_str(), -1, NULL, 0);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
wstr.resize(len - 1);
|
||||
|
||||
len = MultiByteToWideChar(CodePage, 0, str.c_str(), -1, wstr.data(), len);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
resize(len - 1);
|
||||
|
||||
len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, data(), len, NULL, NULL);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xstring(xstring_extension, const char* lpstr, DWORD CodePage = CP_ACP) {
|
||||
if (CodePage == CP_ACP || CodePage == GetACP()) {
|
||||
assign(lpstr);
|
||||
} else {
|
||||
std::wstring wstr;
|
||||
|
||||
auto len = MultiByteToWideChar(CodePage, 0, lpstr, -1, NULL, 0);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
wstr.resize(len - 1);
|
||||
|
||||
len = MultiByteToWideChar(CodePage, 0, lpstr, -1, wstr.data(), len);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
resize(len - 1);
|
||||
|
||||
len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, data(), len, NULL, NULL);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xstring(xstring_extension, const wstring& wstr) {
|
||||
auto len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
resize(len - 1);
|
||||
|
||||
len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, data(), len, NULL, NULL);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
}
|
||||
|
||||
xstring(xstring_extension, const wchar_t* lpwstr) {
|
||||
auto len = WideCharToMultiByte(CP_ACP, 0, lpwstr, -1, NULL, 0, NULL, NULL);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
resize(len - 1);
|
||||
|
||||
len = WideCharToMultiByte(CP_ACP, 0, lpwstr, -1, data(), len, NULL, NULL);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string explicit_string(DWORD CodePage = CP_ACP) const {
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
std::string str;
|
||||
|
||||
auto len = WideCharToMultiByte(CodePage, 0, c_str(), -1, NULL, 0, NULL, NULL);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
str.resize(static_cast<size_t>(len) - 1);
|
||||
|
||||
len = WideCharToMultiByte(CodePage, 0, c_str(), -1, str.data(), len, NULL, NULL);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
return str;
|
||||
#else
|
||||
if (CodePage == CP_ACP || CodePage == GetACP()) {
|
||||
return *this;
|
||||
} else {
|
||||
std::string str;
|
||||
std::wstring wstr;
|
||||
|
||||
auto len = MultiByteToWideChar(CP_ACP, 0, c_str(), -1, NULL, 0);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
wstr.resize(len - 1);
|
||||
|
||||
len = MultiByteToWideChar(CP_ACP, 0, c_str(), -1, wstr.data(), len);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
len = WideCharToMultiByte(CodePage, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
str.resize(len - 1);
|
||||
|
||||
len = WideCharToMultiByte(CodePage, 0, wstr.c_str(), -1, str.data(), len, NULL, NULL);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::wstring explicit_wstring() const {
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
return *this;
|
||||
#else
|
||||
std::wstring wstr;
|
||||
|
||||
auto len = MultiByteToWideChar(CP_ACP, 0, c_str(), -1, NULL, 0);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
wstr.resize(len - 1);
|
||||
|
||||
len = MultiByteToWideChar(CP_ACP, 0, c_str(), -1, wstr.data(), len);
|
||||
if (len == 0) {
|
||||
auto err = GetLastError();
|
||||
throw std::system_error(err, std::system_category());
|
||||
}
|
||||
|
||||
return wstr;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename... __Ts>
|
||||
static xstring format(const xstring& Format, __Ts&&... Args) {
|
||||
xstring s;
|
||||
|
||||
auto len = _sctprintf(Format.c_str(), std::forward<__Ts>(Args)...);
|
||||
if (len == -1) {
|
||||
throw std::invalid_argument("_sctprintf failed.");
|
||||
}
|
||||
|
||||
s.resize(len);
|
||||
|
||||
_sntprintf_s(s.data(), s.length() + 1, _TRUNCATE, Format.c_str(), std::forward<__Ts>(Args)...);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
template<typename... __Ts>
|
||||
static xstring format(PCTSTR lpszFormat, __Ts&& ... Args) {
|
||||
xstring s;
|
||||
|
||||
auto len = _sctprintf(lpszFormat, std::forward<__Ts>(Args)...);
|
||||
if (len == -1) {
|
||||
throw std::invalid_argument("_sctprintf failed.");
|
||||
}
|
||||
|
||||
s.resize(len);
|
||||
|
||||
_sntprintf_s(s.data(), s.length() + 1, _TRUNCATE, lpszFormat, std::forward<__Ts>(Args)...);
|
||||
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,39 +1,35 @@
|
||||
# navicat-keygen for windows - How to build?
|
||||
# Navicat Keygen - 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.
|
||||
1. Please make sure that you have __Visual Studio 2019__ or the higher. Because this is a VS2019 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`
|
||||
* `capstone[x86]:x64-windows-static`
|
||||
* `capstone[x86]:x86-windows-static`
|
||||
* `keystone:x64-windows-static`
|
||||
* `keystone:x86-windows-static`
|
||||
* `unicorn:x64-windows-static`
|
||||
* `unicorn:x86-windows-static`
|
||||
* `openssl-windows:x64-windows-static`
|
||||
* `openssl-windows:x86-windows-static`
|
||||
* `rapidjson:x64-windows-static`
|
||||
* `rapidjson: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 capstone[x86]:x64-windows-static
|
||||
$ vcpkg install capstone[x86]: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
|
||||
$ vcpkg install openssl-windows:x64-windows-static
|
||||
$ vcpkg install openssl-windows:x86-windows-static
|
||||
$ vcpkg install rapidjson:x64-windows-static
|
||||
$ vcpkg install rapidjson:x86-windows-static
|
||||
```
|
||||
|
||||
3. Your `vcpkg` has been integrated into your __Visual Studio__, which means you have run
|
||||
|
||||
@ -1,35 +1,31 @@
|
||||
# navicat-keygen for windows - 如何编译?
|
||||
# Navicat Keygen - 如何编译?
|
||||
|
||||
## 1. 前提条件
|
||||
|
||||
1. 请确保你有 __Visual Studio 2022__ 或者更高版本。因为这是一个VS2022项目。
|
||||
1. 请确保你有 __Visual Studio 2019__ 或者更高版本。因为这是一个VS2019项目。
|
||||
|
||||
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`
|
||||
* `capstone[x86]:x64-windows-static`
|
||||
* `capstone[x86]:x86-windows-static`
|
||||
* `keystone:x64-windows-static`
|
||||
* `keystone:x86-windows-static`
|
||||
* `unicorn:x64-windows-static`
|
||||
* `unicorn:x86-windows-static`
|
||||
* `openssl-windows:x64-windows-static`
|
||||
* `openssl-windows:x86-windows-static`
|
||||
* `rapidjson:x64-windows-static`
|
||||
* `rapidjson: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 capstone[x86]:x64-windows-static
|
||||
$ vcpkg install capstone[x86]: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
|
||||
$ vcpkg install openssl-windows:x64-windows-static
|
||||
$ vcpkg install openssl-windows:x86-windows-static
|
||||
$ vcpkg install rapidjson:x64-windows-static
|
||||
$ vcpkg install rapidjson:x86-windows-static
|
||||
```
|
||||
|
||||
3. 你的 `vcpkg` 已经和你的 __Visual Studio__ 集成了,即你曾成功运行了:
|
||||
|
||||
257
doc/how-to-use.linux.md
Normal file
257
doc/how-to-use.linux.md
Normal file
@ -0,0 +1,257 @@
|
||||
# Navicat Keygen - How to use? (Linux)
|
||||
|
||||
[中文版](how-to-use.linux.zh-CN.md)
|
||||
|
||||
* Maintainer(s): zenuo, DoubleLabyrinth
|
||||
|
||||
---
|
||||
|
||||
> You can download [Screen recoding](image/Screen_recording.mp4) for references.
|
||||
|
||||
1. Switch to the path you extracted the installation package. Run Navicat, for initialization:
|
||||
|
||||
```console
|
||||
$ cd ~/navicat121_premium_en_x64
|
||||
$ ./start_navicat
|
||||
```
|
||||
|
||||
When running for the first time, you will be prompted with the following two windows, click "Cancel" to:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Until the `Registration` window appears, select `Trial`, close Navicat after loading is complete, and execute `Step 2`:
|
||||
|
||||

|
||||
|
||||
2. Download the latest release [from here](https://github.com/DoubleLabyrinth/navicat-keygen/releases), and extract:
|
||||
|
||||
> The 64-bit executable file is downloaded here. If you use 32-bit, please download the corresponding version.
|
||||
|
||||
```console
|
||||
$ curl -O -L https://github.com/DoubleLabyrinth/navicat-keygen/releases/latest/download/navicat-keygen-for-x64.zip
|
||||
$ unzip navicat-keygen-for-x64.zip
|
||||
```
|
||||
|
||||
3. Download `navicat-pacther.sh` and `navicat-keygen.sh`:
|
||||
|
||||
```console
|
||||
$ curl -O -L https://raw.githubusercontent.com/DoubleLabyrinth/navicat-keygen/windows/bash/navicat-patcher.sh
|
||||
$ chmod +x navicat-patcher.sh
|
||||
$ curl -O -L https://raw.githubusercontent.com/DoubleLabyrinth/navicat-keygen/windows/bash/navicat-keygen.sh
|
||||
$ chmod +x navicat-keygen.sh
|
||||
```
|
||||
|
||||
4. Use `navicat-patcher.exe` to replace __Navicat Activation Public Key__ that is stored in `navicat.exe` or `libcc.dll`.
|
||||
|
||||
> Please turn off `Navicat` when performing this step.
|
||||
|
||||
```console
|
||||
$ ./navicat-patcher.sh
|
||||
```
|
||||
|
||||
It has been tested on __Navicat Premium 12.1.22 Simplified Chinese version__. The following is an example of output:
|
||||
|
||||
```
|
||||
***************************************************
|
||||
* Navicat Patcher by @DoubleLabyrinth *
|
||||
* Version: 4.0 *
|
||||
***************************************************
|
||||
|
||||
Press Enter to continue or Ctrl + C to abort.
|
||||
|
||||
[+] Try to open Navicat.exe ... Ok!
|
||||
[+] Try to open libcc.dll ... Ok!
|
||||
|
||||
[+] PatchSolution0 ...... Ready to apply
|
||||
[*] Patch offset = +0x029bccd8
|
||||
[+] PatchSolution1 ...... Ready to apply
|
||||
[*] [0] Patch offset = +0x02206c00
|
||||
[*] [1] Patch offset = +0x0074c489
|
||||
[*] [2] Patch offset = +0x02206910
|
||||
[*] [3] Patch offset = +0x0074c46f
|
||||
[*] [4] Patch offset = +0x02206904
|
||||
[-] PatchSolution2 ...... Omitted
|
||||
[+] PatchSolution3 ...... Ready to apply
|
||||
[*] [ 0] Instruction RVA = 0x016539c8, Patch Offset = +0x023e64d4
|
||||
[*] [ 1] Instruction RVA = 0x01653a1f, Patch Offset = +0x01652e23
|
||||
[*] [ 2] Instruction RVA = 0x01653a25, Patch Offset = +0x01652e28
|
||||
[*] [ 3] Instruction RVA = 0x01653a8c, Patch Offset = +0x01652e8e
|
||||
...
|
||||
...
|
||||
...
|
||||
[*] [108] Instruction RVA = 0x016604e1, Patch Offset = +0x023e66d8
|
||||
[*] [109] Instruction RVA = 0x01660518, Patch Offset = +0x0165f91c
|
||||
[*] [110] Instruction RVA = 0x0166051e, Patch Offset = +0x0165f921
|
||||
|
||||
[*] PatchSolution0 is suppressed in order to keep digital signature valid.
|
||||
|
||||
[*] Generating new RSA private key, it may take a long time...
|
||||
[*] Your RSA public key:
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1hV66HgU4LrKXWW6O7bK
|
||||
AN6ZTr5W+Mq8ClTQ+Pc+BdhLu6rww55kVq7OXKGpvx0G4eTafYMGrrBETgDSTaMq
|
||||
Bx+8bZbGBWh2LtNfqU+xUrpHHBSz0ByBc3iTEzzthJl+Fzf8suDX2lWYIc/Ym/eW
|
||||
YtxdJ7xOzLb68z4N0zVmA0jFX2FOm75DRYgKqy4SGixapfucL9dVaWVLTUdbrVdj
|
||||
4LX78t4t5ykbYoThrat4yuLvj/BxLaQ6ivKD+ScfHdtCoY+NA5jmBoUfBq3Q1SXB
|
||||
iNaoXctbi0/H3MiPu0cRojryAocooF89yFm5/mNnzWGAYPr6DvBI8CDTZmjaQ4oC
|
||||
aQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
|
||||
*******************************************************
|
||||
* PatchSolution1 *
|
||||
*******************************************************
|
||||
[*] Previous:
|
||||
+0x0000000002206c00 44 37 35 31 32 35 42 37 30 37 36 37 42 39 34 31 D75125B70767B941
|
||||
+0x0000000002206c10 34 35 42 34 37 43 31 43 42 33 43 30 37 35 35 45 45B47C1CB3C0755E
|
||||
+0x0000000002206c20 37 43 43 42 38 38 32 35 43 35 44 43 45 30 43 35 7CCB8825C5DCE0C5
|
||||
...
|
||||
...
|
||||
[*] After:
|
||||
+0x0000000002206c00 33 43 32 39 30 39 35 38 33 34 38 41 42 43 35 39 3C290958348ABC59
|
||||
+0x0000000002206c10 36 44 39 30 43 45 45 38 31 36 42 36 39 38 34 44 6D90CEE816B6984D
|
||||
+0x0000000002206c20 35 32 35 34 37 45 30 32 34 31 42 36 42 43 31 41 52547E0241B6BC1A
|
||||
...
|
||||
...
|
||||
|
||||
[*] Previous:
|
||||
+0x000000000074c480 fe ea bc 01 ....
|
||||
[*] After:
|
||||
+0x000000000074c480 08 00 00 00 ....
|
||||
|
||||
[*] Previous:
|
||||
+0x0000000002206910 45 31 43 45 44 30 39 42 39 43 32 31 38 36 42 46 E1CED09B9C2186BF
|
||||
+0x0000000002206920 37 31 41 37 30 43 30 46 45 32 46 31 45 30 41 45 71A70C0FE2F1E0AE
|
||||
+0x0000000002206930 46 33 42 44 36 42 37 35 32 37 37 41 41 42 32 30 F3BD6B75277AAB20
|
||||
...
|
||||
...
|
||||
[*] After:
|
||||
+0x0000000002206910 41 33 39 42 41 36 43 34 31 36 33 32 35 30 46 45 A39BA6C4163250FE
|
||||
+0x0000000002206920 42 32 41 39 31 41 34 32 46 44 42 46 30 41 32 31 B2A91A42FDBF0A21
|
||||
+0x0000000002206930 33 34 46 34 36 44 43 45 34 30 42 46 41 42 33 35 34F46DCE40BFAB35
|
||||
...
|
||||
...
|
||||
|
||||
[*] Previous:
|
||||
+0x000000000074c460 59 Y
|
||||
+0x000000000074c470 08 01 00 ...
|
||||
[*] After:
|
||||
+0x000000000074c460 06 .
|
||||
+0x000000000074c470 00 00 00 ...
|
||||
|
||||
[*] Previous:
|
||||
+0x0000000002206900 39 32 39 33 33 92933
|
||||
[*] After:
|
||||
+0x0000000002206900 42 34 34 33 38 B4438
|
||||
|
||||
*******************************************************
|
||||
* PatchSolution3 *
|
||||
*******************************************************
|
||||
[*] +023e64d4: 4d 49 49 ---> 4d 49 49
|
||||
[*] +01652e23: 42 49 ---> 42 49
|
||||
[*] +01652e28: 6a ---> 6a
|
||||
...
|
||||
...
|
||||
...
|
||||
[*] +023e66d8: 77 49 44 41 ---> 51 49 44 41
|
||||
[*] +0165f91c: 51 41 ---> 51 41
|
||||
[*] +0165f921: 42 ---> 42
|
||||
|
||||
[*] New RSA-2048 private key has been saved to
|
||||
C:\Users\DoubleSine\github.com\navicat-keygen\bin\x64-Release\RegPrivateKey.pem
|
||||
|
||||
*******************************************************
|
||||
* PATCH HAS BEEN DONE SUCCESSFULLY! *
|
||||
* HAVE FUN AND ENJOY~ *
|
||||
*******************************************************
|
||||
```
|
||||
|
||||
5. Then use `navicat-keygen.exe` to generate __snKey__ and __Activation Code__
|
||||
|
||||
```console
|
||||
$ ./navicat-keygen.sh
|
||||
```
|
||||
|
||||
You will be asked to select Navicat product, language and input major version number. After that an randomly generated __snKey__ will be given.
|
||||
|
||||
```
|
||||
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)> 1
|
||||
|
||||
(Input major version number, range: 0 ~ 15, default: 12)> 12
|
||||
|
||||
Serial number:
|
||||
NAVO-2ORP-IN5A-GQEE
|
||||
|
||||
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: DoubleLabyrinth
|
||||
Your organization: DoubleLabyrinth
|
||||
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__.
|
||||
|
||||
6. __Set up__ a invalid proxy. Find and click `Registration`. Fill `Registration Key` by __snKey__ that the keygen gave and click `Activate`.
|
||||
|
||||
7. Online activation will failed and Navicat will ask you do `Manual Activation`, just choose it.
|
||||
|
||||
8. Copy your request code and paste it in the keygen. Input empty line to tell the keygen that your input ends.
|
||||
|
||||
```
|
||||
Your name: DoubleLabyrinth
|
||||
Your organization: DoubleLabyrinth
|
||||
|
||||
Input request code (in Base64), input empty line to end:
|
||||
t2U+0yfE2FfnbjyhCXa0lglZOHu9Ntc3qyGiPbR6xb1QoU63/9BVfdaCq0blwVycXPyT/Vqw5joIKdM5oCRR/afCPM7iRcyhQMAnvqwc+AOKCqayVV+SqKLvtR/AbREI12w++PQ6Ewfs4A8PgB8OJ9G0jKt6Q/iJRblqi2WWw9mwy+YHcYYh3UAfygTnyj/xl+MzRymbY0lkus+6LPtpDecVsFFhM7F32Ee1QPwISko7bAkHOtkt+joPfYDdn9PDGZ4HEmeLvH6UqZCXkzgaAfynB7cQZFEkId8FsW2NGkbpM7wB2Hi3fNFgOIjutTprixTdbpFKn4w6gGc28ve23A==
|
||||
|
||||
Request Info:
|
||||
{"K":"NAVO2ORPIN5AGQEE", "DI":"R91j6WyMhxHznAKSxxxx", "P":"WIN"}
|
||||
|
||||
Response Info:
|
||||
{"K":"NAVO2ORPIN5AGQEE","DI":"R91j6WyMhxHznAKSxxxx","N":"DoubleLabyrinth","O":"DoubleLabyrinth","T":1547826060}
|
||||
|
||||
License:
|
||||
lRF18o+ZhBphyN0U5kFLHtAAGGXuvhqOcxNuvAk4dJcGeR0ISuw74mQvAfdNjv0T
|
||||
I5NZFzqIJvrzM0XeR88q+3kmZkECuxwwWHP3zzDPhPiylcTV4DoGZ1tfoViUSYQc
|
||||
LgXG0Fl7koZeP61YOKQ8GfX+Xk2ZTM64bYaF7NlhonM+GQUJCCF2JThmrP921t2p
|
||||
b/E5pV6fLOYMM13881ZQcQcltMNVDZn4lzgzKRFFxCQFaTl6fJMHZdYVmICQTHtI
|
||||
sNaym0zduc8/cv34mgJ+7NseXmsEPCdjrZ59wgfPsLhZLXqtfxi5hGWw4NMa3Sb2
|
||||
UI8dzqFzRp/hSDEM0mEqiA==
|
||||
```
|
||||
|
||||
9. 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. Don't forget to close the proxy that we just set up.
|
||||
|
||||
255
doc/how-to-use.linux.zh-CN.md
Normal file
255
doc/how-to-use.linux.zh-CN.md
Normal file
@ -0,0 +1,255 @@
|
||||
# Navicat Keygen - 如何使用这个注册机? (Linux)
|
||||
|
||||
* 维护者:zenuo, DoubleLabyrinth
|
||||
|
||||
---
|
||||
|
||||
> 可下载[录屏文件](image/Screen_recording.mp4)参考
|
||||
|
||||
1. 切换到解压安装包的路径,本示例解压到了 `家目录`,运行Navicat,使其初始化环境:
|
||||
|
||||
```console
|
||||
$ cd ~/navicat121_premium_en_x64
|
||||
$ ./start_navicat
|
||||
```
|
||||
|
||||
首次启动时,会提示如下两个窗口,点击“Cancel”即可:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
直至出现 `Registration` 窗口,选择 `Trial`,待加载完成后关闭Navicat,执行 `步骤2`:
|
||||
|
||||

|
||||
|
||||
2. [从这里](https://github.com/DoubleLabyrinth/navicat-keygen/releases)下载最新的release,并且解压:
|
||||
|
||||
> 此处下载的是64位的可执行文件,若您使用32位,请下载对应版本
|
||||
|
||||
```console
|
||||
$ curl -O -L https://github.com/DoubleLabyrinth/navicat-keygen/releases/latest/download/navicat-keygen-for-x64.zip
|
||||
$ unzip navicat-keygen-for-x64.zip
|
||||
```
|
||||
|
||||
3. 下载 `navicat-pacther.sh` 和 `navicat-keygen.sh`:
|
||||
|
||||
```console
|
||||
$ curl -O -L https://raw.githubusercontent.com/DoubleLabyrinth/navicat-keygen/windows/bash/navicat-patcher.sh
|
||||
$ chmod +x navicat-patcher.sh
|
||||
$ curl -O -L https://raw.githubusercontent.com/DoubleLabyrinth/navicat-keygen/windows/bash/navicat-keygen.sh
|
||||
$ chmod +x navicat-keygen.sh
|
||||
```
|
||||
|
||||
4. 使用 `navicat-patcher.exe` 替换掉 `navicat.exe` 和 `libcc.dll` 里的Navicat激活公钥。
|
||||
|
||||
> 执行此步骤时,请将Navicat关闭
|
||||
|
||||
```console
|
||||
$ ./navicat-patcher.sh
|
||||
```
|
||||
|
||||
__Navicat Premium 12.1.22 简体中文版已通过测试__。下面将是一份样例输出:
|
||||
|
||||
```
|
||||
***************************************************
|
||||
* Navicat Patcher by @DoubleLabyrinth *
|
||||
* Version: 4.0 *
|
||||
***************************************************
|
||||
|
||||
Press Enter to continue or Ctrl + C to abort.
|
||||
|
||||
[+] Try to open Navicat.exe ... Ok!
|
||||
[+] Try to open libcc.dll ... Ok!
|
||||
|
||||
[+] PatchSolution0 ...... Ready to apply
|
||||
[*] Patch offset = +0x029bccd8
|
||||
[+] PatchSolution1 ...... Ready to apply
|
||||
[*] [0] Patch offset = +0x02206c00
|
||||
[*] [1] Patch offset = +0x0074c489
|
||||
[*] [2] Patch offset = +0x02206910
|
||||
[*] [3] Patch offset = +0x0074c46f
|
||||
[*] [4] Patch offset = +0x02206904
|
||||
[-] PatchSolution2 ...... Omitted
|
||||
[+] PatchSolution3 ...... Ready to apply
|
||||
[*] [ 0] Instruction RVA = 0x016539c8, Patch Offset = +0x023e64d4
|
||||
[*] [ 1] Instruction RVA = 0x01653a1f, Patch Offset = +0x01652e23
|
||||
[*] [ 2] Instruction RVA = 0x01653a25, Patch Offset = +0x01652e28
|
||||
[*] [ 3] Instruction RVA = 0x01653a8c, Patch Offset = +0x01652e8e
|
||||
...
|
||||
...
|
||||
...
|
||||
[*] [108] Instruction RVA = 0x016604e1, Patch Offset = +0x023e66d8
|
||||
[*] [109] Instruction RVA = 0x01660518, Patch Offset = +0x0165f91c
|
||||
[*] [110] Instruction RVA = 0x0166051e, Patch Offset = +0x0165f921
|
||||
|
||||
[*] PatchSolution0 is suppressed in order to keep digital signature valid.
|
||||
|
||||
[*] Generating new RSA private key, it may take a long time...
|
||||
[*] Your RSA public key:
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1hV66HgU4LrKXWW6O7bK
|
||||
AN6ZTr5W+Mq8ClTQ+Pc+BdhLu6rww55kVq7OXKGpvx0G4eTafYMGrrBETgDSTaMq
|
||||
Bx+8bZbGBWh2LtNfqU+xUrpHHBSz0ByBc3iTEzzthJl+Fzf8suDX2lWYIc/Ym/eW
|
||||
YtxdJ7xOzLb68z4N0zVmA0jFX2FOm75DRYgKqy4SGixapfucL9dVaWVLTUdbrVdj
|
||||
4LX78t4t5ykbYoThrat4yuLvj/BxLaQ6ivKD+ScfHdtCoY+NA5jmBoUfBq3Q1SXB
|
||||
iNaoXctbi0/H3MiPu0cRojryAocooF89yFm5/mNnzWGAYPr6DvBI8CDTZmjaQ4oC
|
||||
aQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
|
||||
*******************************************************
|
||||
* PatchSolution1 *
|
||||
*******************************************************
|
||||
[*] Previous:
|
||||
+0x0000000002206c00 44 37 35 31 32 35 42 37 30 37 36 37 42 39 34 31 D75125B70767B941
|
||||
+0x0000000002206c10 34 35 42 34 37 43 31 43 42 33 43 30 37 35 35 45 45B47C1CB3C0755E
|
||||
+0x0000000002206c20 37 43 43 42 38 38 32 35 43 35 44 43 45 30 43 35 7CCB8825C5DCE0C5
|
||||
...
|
||||
...
|
||||
[*] After:
|
||||
+0x0000000002206c00 33 43 32 39 30 39 35 38 33 34 38 41 42 43 35 39 3C290958348ABC59
|
||||
+0x0000000002206c10 36 44 39 30 43 45 45 38 31 36 42 36 39 38 34 44 6D90CEE816B6984D
|
||||
+0x0000000002206c20 35 32 35 34 37 45 30 32 34 31 42 36 42 43 31 41 52547E0241B6BC1A
|
||||
...
|
||||
...
|
||||
|
||||
[*] Previous:
|
||||
+0x000000000074c480 fe ea bc 01 ....
|
||||
[*] After:
|
||||
+0x000000000074c480 08 00 00 00 ....
|
||||
|
||||
[*] Previous:
|
||||
+0x0000000002206910 45 31 43 45 44 30 39 42 39 43 32 31 38 36 42 46 E1CED09B9C2186BF
|
||||
+0x0000000002206920 37 31 41 37 30 43 30 46 45 32 46 31 45 30 41 45 71A70C0FE2F1E0AE
|
||||
+0x0000000002206930 46 33 42 44 36 42 37 35 32 37 37 41 41 42 32 30 F3BD6B75277AAB20
|
||||
...
|
||||
...
|
||||
[*] After:
|
||||
+0x0000000002206910 41 33 39 42 41 36 43 34 31 36 33 32 35 30 46 45 A39BA6C4163250FE
|
||||
+0x0000000002206920 42 32 41 39 31 41 34 32 46 44 42 46 30 41 32 31 B2A91A42FDBF0A21
|
||||
+0x0000000002206930 33 34 46 34 36 44 43 45 34 30 42 46 41 42 33 35 34F46DCE40BFAB35
|
||||
...
|
||||
...
|
||||
|
||||
[*] Previous:
|
||||
+0x000000000074c460 59 Y
|
||||
+0x000000000074c470 08 01 00 ...
|
||||
[*] After:
|
||||
+0x000000000074c460 06 .
|
||||
+0x000000000074c470 00 00 00 ...
|
||||
|
||||
[*] Previous:
|
||||
+0x0000000002206900 39 32 39 33 33 92933
|
||||
[*] After:
|
||||
+0x0000000002206900 42 34 34 33 38 B4438
|
||||
|
||||
*******************************************************
|
||||
* PatchSolution3 *
|
||||
*******************************************************
|
||||
[*] +023e64d4: 4d 49 49 ---> 4d 49 49
|
||||
[*] +01652e23: 42 49 ---> 42 49
|
||||
[*] +01652e28: 6a ---> 6a
|
||||
...
|
||||
...
|
||||
...
|
||||
[*] +023e66d8: 77 49 44 41 ---> 51 49 44 41
|
||||
[*] +0165f91c: 51 41 ---> 51 41
|
||||
[*] +0165f921: 42 ---> 42
|
||||
|
||||
[*] New RSA-2048 private key has been saved to
|
||||
C:\Users\DoubleSine\github.com\navicat-keygen\bin\x64-Release\RegPrivateKey.pem
|
||||
|
||||
*******************************************************
|
||||
* PATCH HAS BEEN DONE SUCCESSFULLY! *
|
||||
* HAVE FUN AND ENJOY~ *
|
||||
*******************************************************
|
||||
```
|
||||
|
||||
5. 接下来使用`navicat-keygen.exe`来生成序列号和激活码
|
||||
|
||||
```console
|
||||
$ ./navicat-keygen.sh
|
||||
```
|
||||
|
||||
你会被要求选择Navicat产品类别、语言以及输入主版本号。之后会随机生成一个序列号。
|
||||
|
||||
```
|
||||
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)> 1
|
||||
|
||||
(Input major version number, range: 0 ~ 15, default: 12)> 12
|
||||
|
||||
Serial number:
|
||||
NAVO-2ORP-IN5A-GQEE
|
||||
|
||||
Your name:
|
||||
```
|
||||
|
||||
你可以使用这个序列号暂时激活Navicat。
|
||||
|
||||
接下来你会被要求输入`用户名`和`组织名`;请随便填写,但不要太长。
|
||||
|
||||
```
|
||||
Your name: DoubleLabyrinth
|
||||
Your organization: DoubleLabyrinth
|
||||
Input request code (in Base64), input empty line to end:
|
||||
```
|
||||
|
||||
之后你会被要求填入请求码。注意 __不要关闭命令行__.
|
||||
|
||||
6. 配置一个不存在的`代理`。找到`注册`窗口,并填入keygen给你的序列号。然后点击`激活`按钮。
|
||||
|
||||
7. 在线激活失败,这时候Navicat会询问你是否`手动激活`,直接选吧。
|
||||
|
||||
8. 在`手动激活`窗口你会得到一个请求码,复制它并把它粘贴到keygen里。最后别忘了连按至少两下回车结束输入。
|
||||
|
||||
```
|
||||
Your name: DoubleLabyrinth
|
||||
Your organization: DoubleLabyrinth
|
||||
|
||||
Input request code (in Base64), input empty line to end:
|
||||
t2U+0yfE2FfnbjyhCXa0lglZOHu9Ntc3qyGiPbR6xb1QoU63/9BVfdaCq0blwVycXPyT/Vqw5joIKdM5oCRR/afCPM7iRcyhQMAnvqwc+AOKCqayVV+SqKLvtR/AbREI12w++PQ6Ewfs4A8PgB8OJ9G0jKt6Q/iJRblqi2WWw9mwy+YHcYYh3UAfygTnyj/xl+MzRymbY0lkus+6LPtpDecVsFFhM7F32Ee1QPwISko7bAkHOtkt+joPfYDdn9PDGZ4HEmeLvH6UqZCXkzgaAfynB7cQZFEkId8FsW2NGkbpM7wB2Hi3fNFgOIjutTprixTdbpFKn4w6gGc28ve23A==
|
||||
|
||||
Request Info:
|
||||
{"K":"NAVO2ORPIN5AGQEE", "DI":"R91j6WyMhxHznAKSxxxx", "P":"WIN"}
|
||||
|
||||
Response Info:
|
||||
{"K":"NAVO2ORPIN5AGQEE","DI":"R91j6WyMhxHznAKSxxxx","N":"DoubleLabyrinth","O":"DoubleLabyrinth","T":1547826060}
|
||||
|
||||
License:
|
||||
lRF18o+ZhBphyN0U5kFLHtAAGGXuvhqOcxNuvAk4dJcGeR0ISuw74mQvAfdNjv0T
|
||||
I5NZFzqIJvrzM0XeR88q+3kmZkECuxwwWHP3zzDPhPiylcTV4DoGZ1tfoViUSYQc
|
||||
LgXG0Fl7koZeP61YOKQ8GfX+Xk2ZTM64bYaF7NlhonM+GQUJCCF2JThmrP921t2p
|
||||
b/E5pV6fLOYMM13881ZQcQcltMNVDZn4lzgzKRFFxCQFaTl6fJMHZdYVmICQTHtI
|
||||
sNaym0zduc8/cv34mgJ+7NseXmsEPCdjrZ59wgfPsLhZLXqtfxi5hGWw4NMa3Sb2
|
||||
UI8dzqFzRp/hSDEM0mEqiA==
|
||||
```
|
||||
|
||||
9. 如果不出意外,你会得到一个看似用Base64编码的激活码。直接复制它,并把它粘贴到Navicat的`手动激活`窗口,最后点`激活`按钮。如果没什么意外的话应该能成功激活。别忘了关闭我们刚刚设置的不存在的代理哦。
|
||||
|
||||
@ -1,196 +0,0 @@
|
||||
# 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.
|
||||
|
||||
256
doc/how-to-use.windows.md
Normal file
256
doc/how-to-use.windows.md
Normal file
@ -0,0 +1,256 @@
|
||||
# Navicat Keygen - How to use? (Windows)
|
||||
|
||||
[中文版](how-to-use.windows.zh-CN.md)
|
||||
|
||||
1. Download the latest release [from here](https://github.com/DoubleLabyrinth/navicat-keygen/releases).
|
||||
|
||||
2. Use `navicat-patcher.exe` to replace __Navicat Activation Public Key__ that is stored in `navicat.exe` or `libcc.dll`.
|
||||
|
||||
```
|
||||
navicat-patcher.exe [-dry-run] <Navicat Installation Path> [RSA-2048 PEM File Path]
|
||||
```
|
||||
|
||||
* `[-dry-run]` Run patcher without applying any patches.
|
||||
|
||||
__This parameter is optional.__
|
||||
|
||||
* `<Navicat Installation 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 12"
|
||||
```
|
||||
|
||||
It has been tested on __Navicat Premium 12.1.22 Simplified Chinese version__. The following is an example of output.
|
||||
|
||||
```
|
||||
***************************************************
|
||||
* Navicat Patcher by @DoubleLabyrinth *
|
||||
* Version: 4.0 *
|
||||
***************************************************
|
||||
|
||||
Press Enter to continue or Ctrl + C to abort.
|
||||
|
||||
[+] Try to open Navicat.exe ... Ok!
|
||||
[+] Try to open libcc.dll ... Ok!
|
||||
|
||||
[+] PatchSolution0 ...... Ready to apply
|
||||
[*] Patch offset = +0x029bccd8
|
||||
[+] PatchSolution1 ...... Ready to apply
|
||||
[*] [0] Patch offset = +0x02206c00
|
||||
[*] [1] Patch offset = +0x0074c489
|
||||
[*] [2] Patch offset = +0x02206910
|
||||
[*] [3] Patch offset = +0x0074c46f
|
||||
[*] [4] Patch offset = +0x02206904
|
||||
[-] PatchSolution2 ...... Omitted
|
||||
[+] PatchSolution3 ...... Ready to apply
|
||||
[*] [ 0] Instruction RVA = 0x016539c8, Patch Offset = +0x023e64d4
|
||||
[*] [ 1] Instruction RVA = 0x01653a1f, Patch Offset = +0x01652e23
|
||||
[*] [ 2] Instruction RVA = 0x01653a25, Patch Offset = +0x01652e28
|
||||
[*] [ 3] Instruction RVA = 0x01653a8c, Patch Offset = +0x01652e8e
|
||||
...
|
||||
...
|
||||
...
|
||||
[*] [108] Instruction RVA = 0x016604e1, Patch Offset = +0x023e66d8
|
||||
[*] [109] Instruction RVA = 0x01660518, Patch Offset = +0x0165f91c
|
||||
[*] [110] Instruction RVA = 0x0166051e, Patch Offset = +0x0165f921
|
||||
|
||||
[*] PatchSolution0 is suppressed in order to keep digital signature valid.
|
||||
|
||||
[*] Generating new RSA private key, it may take a long time...
|
||||
[*] Your RSA public key:
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1hV66HgU4LrKXWW6O7bK
|
||||
AN6ZTr5W+Mq8ClTQ+Pc+BdhLu6rww55kVq7OXKGpvx0G4eTafYMGrrBETgDSTaMq
|
||||
Bx+8bZbGBWh2LtNfqU+xUrpHHBSz0ByBc3iTEzzthJl+Fzf8suDX2lWYIc/Ym/eW
|
||||
YtxdJ7xOzLb68z4N0zVmA0jFX2FOm75DRYgKqy4SGixapfucL9dVaWVLTUdbrVdj
|
||||
4LX78t4t5ykbYoThrat4yuLvj/BxLaQ6ivKD+ScfHdtCoY+NA5jmBoUfBq3Q1SXB
|
||||
iNaoXctbi0/H3MiPu0cRojryAocooF89yFm5/mNnzWGAYPr6DvBI8CDTZmjaQ4oC
|
||||
aQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
|
||||
*******************************************************
|
||||
* PatchSolution1 *
|
||||
*******************************************************
|
||||
[*] Previous:
|
||||
+0x0000000002206c00 44 37 35 31 32 35 42 37 30 37 36 37 42 39 34 31 D75125B70767B941
|
||||
+0x0000000002206c10 34 35 42 34 37 43 31 43 42 33 43 30 37 35 35 45 45B47C1CB3C0755E
|
||||
+0x0000000002206c20 37 43 43 42 38 38 32 35 43 35 44 43 45 30 43 35 7CCB8825C5DCE0C5
|
||||
...
|
||||
...
|
||||
[*] After:
|
||||
+0x0000000002206c00 33 43 32 39 30 39 35 38 33 34 38 41 42 43 35 39 3C290958348ABC59
|
||||
+0x0000000002206c10 36 44 39 30 43 45 45 38 31 36 42 36 39 38 34 44 6D90CEE816B6984D
|
||||
+0x0000000002206c20 35 32 35 34 37 45 30 32 34 31 42 36 42 43 31 41 52547E0241B6BC1A
|
||||
...
|
||||
...
|
||||
|
||||
[*] Previous:
|
||||
+0x000000000074c480 fe ea bc 01 ....
|
||||
[*] After:
|
||||
+0x000000000074c480 08 00 00 00 ....
|
||||
|
||||
[*] Previous:
|
||||
+0x0000000002206910 45 31 43 45 44 30 39 42 39 43 32 31 38 36 42 46 E1CED09B9C2186BF
|
||||
+0x0000000002206920 37 31 41 37 30 43 30 46 45 32 46 31 45 30 41 45 71A70C0FE2F1E0AE
|
||||
+0x0000000002206930 46 33 42 44 36 42 37 35 32 37 37 41 41 42 32 30 F3BD6B75277AAB20
|
||||
...
|
||||
...
|
||||
[*] After:
|
||||
+0x0000000002206910 41 33 39 42 41 36 43 34 31 36 33 32 35 30 46 45 A39BA6C4163250FE
|
||||
+0x0000000002206920 42 32 41 39 31 41 34 32 46 44 42 46 30 41 32 31 B2A91A42FDBF0A21
|
||||
+0x0000000002206930 33 34 46 34 36 44 43 45 34 30 42 46 41 42 33 35 34F46DCE40BFAB35
|
||||
...
|
||||
...
|
||||
|
||||
[*] Previous:
|
||||
+0x000000000074c460 59 Y
|
||||
+0x000000000074c470 08 01 00 ...
|
||||
[*] After:
|
||||
+0x000000000074c460 06 .
|
||||
+0x000000000074c470 00 00 00 ...
|
||||
|
||||
[*] Previous:
|
||||
+0x0000000002206900 39 32 39 33 33 92933
|
||||
[*] After:
|
||||
+0x0000000002206900 42 34 34 33 38 B4438
|
||||
|
||||
*******************************************************
|
||||
* PatchSolution3 *
|
||||
*******************************************************
|
||||
[*] +023e64d4: 4d 49 49 ---> 4d 49 49
|
||||
[*] +01652e23: 42 49 ---> 42 49
|
||||
[*] +01652e28: 6a ---> 6a
|
||||
...
|
||||
...
|
||||
...
|
||||
[*] +023e66d8: 77 49 44 41 ---> 51 49 44 41
|
||||
[*] +0165f91c: 51 41 ---> 51 41
|
||||
[*] +0165f921: 42 ---> 42
|
||||
|
||||
[*] New RSA-2048 private key has been saved to
|
||||
C:\Users\DoubleSine\github.com\navicat-keygen\bin\x64-Release\RegPrivateKey.pem
|
||||
|
||||
*******************************************************
|
||||
* PATCH HAS BEEN DONE SUCCESSFULLY! *
|
||||
* HAVE FUN AND ENJOY~ *
|
||||
*******************************************************
|
||||
```
|
||||
|
||||
3. Then use `navicat-keygen.exe` to generate __snKey__ and __Activation Code__
|
||||
|
||||
```
|
||||
navicat-keygen.exe <-bin|-text> [-adv] <RSA-2048 PrivateKey(PEM 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 PrivateKey(PEM file)>`: The full path or relative path to a RSA-2048 private key file.
|
||||
|
||||
__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.
|
||||
|
||||
```
|
||||
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)> 1
|
||||
|
||||
(Input major version number, range: 0 ~ 15, default: 12)> 12
|
||||
|
||||
Serial number:
|
||||
NAVO-2ORP-IN5A-GQEE
|
||||
|
||||
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: DoubleLabyrinth
|
||||
Your organization: DoubleLabyrinth
|
||||
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__.
|
||||
|
||||
4. __Disconnect your network__ and open Navicat. Find and click `Registration`. Fill `Registration Key` by __snKey__ that the keygen gave and 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 the keygen. Input empty line to tell the keygen that your input ends.
|
||||
|
||||
```
|
||||
Your name: DoubleLabyrinth
|
||||
Your organization: DoubleLabyrinth
|
||||
|
||||
Input request code (in Base64), input empty line to end:
|
||||
t2U+0yfE2FfnbjyhCXa0lglZOHu9Ntc3qyGiPbR6xb1QoU63/9BVfdaCq0blwVycXPyT/Vqw5joIKdM5oCRR/afCPM7iRcyhQMAnvqwc+AOKCqayVV+SqKLvtR/AbREI12w++PQ6Ewfs4A8PgB8OJ9G0jKt6Q/iJRblqi2WWw9mwy+YHcYYh3UAfygTnyj/xl+MzRymbY0lkus+6LPtpDecVsFFhM7F32Ee1QPwISko7bAkHOtkt+joPfYDdn9PDGZ4HEmeLvH6UqZCXkzgaAfynB7cQZFEkId8FsW2NGkbpM7wB2Hi3fNFgOIjutTprixTdbpFKn4w6gGc28ve23A==
|
||||
|
||||
Request Info:
|
||||
{"K":"NAVO2ORPIN5AGQEE", "DI":"R91j6WyMhxHznAKSxxxx", "P":"WIN"}
|
||||
|
||||
Response Info:
|
||||
{"K":"NAVO2ORPIN5AGQEE","DI":"R91j6WyMhxHznAKSxxxx","N":"DoubleLabyrinth","O":"DoubleLabyrinth","T":1547826060}
|
||||
|
||||
License:
|
||||
lRF18o+ZhBphyN0U5kFLHtAAGGXuvhqOcxNuvAk4dJcGeR0ISuw74mQvAfdNjv0T
|
||||
I5NZFzqIJvrzM0XeR88q+3kmZkECuxwwWHP3zzDPhPiylcTV4DoGZ1tfoViUSYQc
|
||||
LgXG0Fl7koZeP61YOKQ8GfX+Xk2ZTM64bYaF7NlhonM+GQUJCCF2JThmrP921t2p
|
||||
b/E5pV6fLOYMM13881ZQcQcltMNVDZn4lzgzKRFFxCQFaTl6fJMHZdYVmICQTHtI
|
||||
sNaym0zduc8/cv34mgJ+7NseXmsEPCdjrZ59wgfPsLhZLXqtfxi5hGWw4NMa3Sb2
|
||||
UI8dzqFzRp/hSDEM0mEqiA==
|
||||
```
|
||||
|
||||
7. 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.
|
||||
|
||||
254
doc/how-to-use.windows.zh-CN.md
Normal file
254
doc/how-to-use.windows.zh-CN.md
Normal file
@ -0,0 +1,254 @@
|
||||
# Navicat Keygen - 如何使用这个注册机? (Windows)
|
||||
|
||||
1. [从这里](https://github.com/DoubleLabyrinth/navicat-keygen/releases)下载最新的release。
|
||||
|
||||
2. 使用`navicat-patcher.exe`替换掉`navicat.exe`和`libcc.dll`里的Navicat激活公钥。
|
||||
|
||||
```
|
||||
navicat-patcher.exe [-dry-run] <Navicat Installation Path> [RSA-2048 PEM File Path]
|
||||
```
|
||||
|
||||
* `[-dry-run]`: 运行patcher但不对Navicat程序做任何修改。
|
||||
|
||||
__这个参数是可选的。__
|
||||
|
||||
* `<Navicat Installation 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 12"
|
||||
```
|
||||
|
||||
__Navicat Premium 12.1.22 简体中文版已通过测试__。下面将是一份样例输出:
|
||||
|
||||
```
|
||||
***************************************************
|
||||
* Navicat Patcher by @DoubleLabyrinth *
|
||||
* Version: 4.0 *
|
||||
***************************************************
|
||||
|
||||
Press Enter to continue or Ctrl + C to abort.
|
||||
|
||||
[+] Try to open Navicat.exe ... Ok!
|
||||
[+] Try to open libcc.dll ... Ok!
|
||||
|
||||
[+] PatchSolution0 ...... Ready to apply
|
||||
[*] Patch offset = +0x029bccd8
|
||||
[+] PatchSolution1 ...... Ready to apply
|
||||
[*] [0] Patch offset = +0x02206c00
|
||||
[*] [1] Patch offset = +0x0074c489
|
||||
[*] [2] Patch offset = +0x02206910
|
||||
[*] [3] Patch offset = +0x0074c46f
|
||||
[*] [4] Patch offset = +0x02206904
|
||||
[-] PatchSolution2 ...... Omitted
|
||||
[+] PatchSolution3 ...... Ready to apply
|
||||
[*] [ 0] Instruction RVA = 0x016539c8, Patch Offset = +0x023e64d4
|
||||
[*] [ 1] Instruction RVA = 0x01653a1f, Patch Offset = +0x01652e23
|
||||
[*] [ 2] Instruction RVA = 0x01653a25, Patch Offset = +0x01652e28
|
||||
[*] [ 3] Instruction RVA = 0x01653a8c, Patch Offset = +0x01652e8e
|
||||
...
|
||||
...
|
||||
...
|
||||
[*] [108] Instruction RVA = 0x016604e1, Patch Offset = +0x023e66d8
|
||||
[*] [109] Instruction RVA = 0x01660518, Patch Offset = +0x0165f91c
|
||||
[*] [110] Instruction RVA = 0x0166051e, Patch Offset = +0x0165f921
|
||||
|
||||
[*] PatchSolution0 is suppressed in order to keep digital signature valid.
|
||||
|
||||
[*] Generating new RSA private key, it may take a long time...
|
||||
[*] Your RSA public key:
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1hV66HgU4LrKXWW6O7bK
|
||||
AN6ZTr5W+Mq8ClTQ+Pc+BdhLu6rww55kVq7OXKGpvx0G4eTafYMGrrBETgDSTaMq
|
||||
Bx+8bZbGBWh2LtNfqU+xUrpHHBSz0ByBc3iTEzzthJl+Fzf8suDX2lWYIc/Ym/eW
|
||||
YtxdJ7xOzLb68z4N0zVmA0jFX2FOm75DRYgKqy4SGixapfucL9dVaWVLTUdbrVdj
|
||||
4LX78t4t5ykbYoThrat4yuLvj/BxLaQ6ivKD+ScfHdtCoY+NA5jmBoUfBq3Q1SXB
|
||||
iNaoXctbi0/H3MiPu0cRojryAocooF89yFm5/mNnzWGAYPr6DvBI8CDTZmjaQ4oC
|
||||
aQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
|
||||
*******************************************************
|
||||
* PatchSolution1 *
|
||||
*******************************************************
|
||||
[*] Previous:
|
||||
+0x0000000002206c00 44 37 35 31 32 35 42 37 30 37 36 37 42 39 34 31 D75125B70767B941
|
||||
+0x0000000002206c10 34 35 42 34 37 43 31 43 42 33 43 30 37 35 35 45 45B47C1CB3C0755E
|
||||
+0x0000000002206c20 37 43 43 42 38 38 32 35 43 35 44 43 45 30 43 35 7CCB8825C5DCE0C5
|
||||
...
|
||||
...
|
||||
[*] After:
|
||||
+0x0000000002206c00 33 43 32 39 30 39 35 38 33 34 38 41 42 43 35 39 3C290958348ABC59
|
||||
+0x0000000002206c10 36 44 39 30 43 45 45 38 31 36 42 36 39 38 34 44 6D90CEE816B6984D
|
||||
+0x0000000002206c20 35 32 35 34 37 45 30 32 34 31 42 36 42 43 31 41 52547E0241B6BC1A
|
||||
...
|
||||
...
|
||||
|
||||
[*] Previous:
|
||||
+0x000000000074c480 fe ea bc 01 ....
|
||||
[*] After:
|
||||
+0x000000000074c480 08 00 00 00 ....
|
||||
|
||||
[*] Previous:
|
||||
+0x0000000002206910 45 31 43 45 44 30 39 42 39 43 32 31 38 36 42 46 E1CED09B9C2186BF
|
||||
+0x0000000002206920 37 31 41 37 30 43 30 46 45 32 46 31 45 30 41 45 71A70C0FE2F1E0AE
|
||||
+0x0000000002206930 46 33 42 44 36 42 37 35 32 37 37 41 41 42 32 30 F3BD6B75277AAB20
|
||||
...
|
||||
...
|
||||
[*] After:
|
||||
+0x0000000002206910 41 33 39 42 41 36 43 34 31 36 33 32 35 30 46 45 A39BA6C4163250FE
|
||||
+0x0000000002206920 42 32 41 39 31 41 34 32 46 44 42 46 30 41 32 31 B2A91A42FDBF0A21
|
||||
+0x0000000002206930 33 34 46 34 36 44 43 45 34 30 42 46 41 42 33 35 34F46DCE40BFAB35
|
||||
...
|
||||
...
|
||||
|
||||
[*] Previous:
|
||||
+0x000000000074c460 59 Y
|
||||
+0x000000000074c470 08 01 00 ...
|
||||
[*] After:
|
||||
+0x000000000074c460 06 .
|
||||
+0x000000000074c470 00 00 00 ...
|
||||
|
||||
[*] Previous:
|
||||
+0x0000000002206900 39 32 39 33 33 92933
|
||||
[*] After:
|
||||
+0x0000000002206900 42 34 34 33 38 B4438
|
||||
|
||||
*******************************************************
|
||||
* PatchSolution3 *
|
||||
*******************************************************
|
||||
[*] +023e64d4: 4d 49 49 ---> 4d 49 49
|
||||
[*] +01652e23: 42 49 ---> 42 49
|
||||
[*] +01652e28: 6a ---> 6a
|
||||
...
|
||||
...
|
||||
...
|
||||
[*] +023e66d8: 77 49 44 41 ---> 51 49 44 41
|
||||
[*] +0165f91c: 51 41 ---> 51 41
|
||||
[*] +0165f921: 42 ---> 42
|
||||
|
||||
[*] New RSA-2048 private key has been saved to
|
||||
C:\Users\DoubleSine\github.com\navicat-keygen\bin\x64-Release\RegPrivateKey.pem
|
||||
|
||||
*******************************************************
|
||||
* PATCH HAS BEEN DONE SUCCESSFULLY! *
|
||||
* HAVE FUN AND ENJOY~ *
|
||||
*******************************************************
|
||||
```
|
||||
|
||||
3. 接下来使用`navicat-keygen.exe`来生成序列号和激活码
|
||||
|
||||
```
|
||||
navicat-keygen.exe <-bin|-text> [-adv] <RSA-2048 PrivateKey(PEM 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 PrivateKey(PEM file)>`: RSA-2048私钥文件的完整路径或相对路径。
|
||||
|
||||
__这个参数必须指定。__
|
||||
|
||||
__例如:(在cmd.exe中)__
|
||||
|
||||
```console
|
||||
navicat-keygen.exe -text .\RegPrivateKey.pem
|
||||
```
|
||||
|
||||
你会被要求选择Navicat产品类别、语言以及输入主版本号。之后会随机生成一个序列号。
|
||||
|
||||
```
|
||||
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)> 1
|
||||
|
||||
(Input major version number, range: 0 ~ 15, default: 12)> 12
|
||||
|
||||
Serial number:
|
||||
NAVO-2ORP-IN5A-GQEE
|
||||
|
||||
Your name:
|
||||
```
|
||||
|
||||
你可以使用这个序列号暂时激活Navicat。
|
||||
|
||||
接下来你会被要求输入`用户名`和`组织名`;请随便填写,但不要太长。
|
||||
|
||||
```
|
||||
Your name: DoubleLabyrinth
|
||||
Your organization: DoubleLabyrinth
|
||||
Input request code (in Base64), input empty line to end:
|
||||
```
|
||||
|
||||
之后你会被要求填入请求码。注意 __不要关闭命令行__.
|
||||
|
||||
4. __断开网络__ 并打开Navicat。找到`注册`窗口,并填入keygen给你的序列号。然后点击`激活`按钮。
|
||||
|
||||
5. 一般来说在线激活肯定会失败,这时候Navicat会询问你是否`手动激活`,直接选吧。
|
||||
|
||||
6. 在`手动激活`窗口你会得到一个请求码,复制它并把它粘贴到keygen里。最后别忘了连按至少两下回车结束输入。
|
||||
|
||||
```
|
||||
Your name: DoubleLabyrinth
|
||||
Your organization: DoubleLabyrinth
|
||||
|
||||
Input request code (in Base64), input empty line to end:
|
||||
t2U+0yfE2FfnbjyhCXa0lglZOHu9Ntc3qyGiPbR6xb1QoU63/9BVfdaCq0blwVycXPyT/Vqw5joIKdM5oCRR/afCPM7iRcyhQMAnvqwc+AOKCqayVV+SqKLvtR/AbREI12w++PQ6Ewfs4A8PgB8OJ9G0jKt6Q/iJRblqi2WWw9mwy+YHcYYh3UAfygTnyj/xl+MzRymbY0lkus+6LPtpDecVsFFhM7F32Ee1QPwISko7bAkHOtkt+joPfYDdn9PDGZ4HEmeLvH6UqZCXkzgaAfynB7cQZFEkId8FsW2NGkbpM7wB2Hi3fNFgOIjutTprixTdbpFKn4w6gGc28ve23A==
|
||||
|
||||
Request Info:
|
||||
{"K":"NAVO2ORPIN5AGQEE", "DI":"R91j6WyMhxHznAKSxxxx", "P":"WIN"}
|
||||
|
||||
Response Info:
|
||||
{"K":"NAVO2ORPIN5AGQEE","DI":"R91j6WyMhxHznAKSxxxx","N":"DoubleLabyrinth","O":"DoubleLabyrinth","T":1547826060}
|
||||
|
||||
License:
|
||||
lRF18o+ZhBphyN0U5kFLHtAAGGXuvhqOcxNuvAk4dJcGeR0ISuw74mQvAfdNjv0T
|
||||
I5NZFzqIJvrzM0XeR88q+3kmZkECuxwwWHP3zzDPhPiylcTV4DoGZ1tfoViUSYQc
|
||||
LgXG0Fl7koZeP61YOKQ8GfX+Xk2ZTM64bYaF7NlhonM+GQUJCCF2JThmrP921t2p
|
||||
b/E5pV6fLOYMM13881ZQcQcltMNVDZn4lzgzKRFFxCQFaTl6fJMHZdYVmICQTHtI
|
||||
sNaym0zduc8/cv34mgJ+7NseXmsEPCdjrZ59wgfPsLhZLXqtfxi5hGWw4NMa3Sb2
|
||||
UI8dzqFzRp/hSDEM0mEqiA==
|
||||
```
|
||||
|
||||
4. 如果不出意外,你会得到一个看似用Base64编码的激活码。直接复制它,并把它粘贴到Navicat的`手动激活`窗口,最后点`激活`按钮。如果没什么意外的话应该能成功激活。
|
||||
|
||||
@ -1,194 +0,0 @@
|
||||
# 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的`手动激活`窗口,最后点`激活`按钮。如果没什么意外的话应该能成功激活。
|
||||
|
||||
BIN
doc/image/Screen_recording.mp4
Normal file
BIN
doc/image/Screen_recording.mp4
Normal file
Binary file not shown.
BIN
doc/image/Screenshot_2019-04-30_12-31-33.png
Normal file
BIN
doc/image/Screenshot_2019-04-30_12-31-33.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
doc/image/Screenshot_2019-04-30_12-31-52.png
Normal file
BIN
doc/image/Screenshot_2019-04-30_12-31-52.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
doc/image/Screenshot_2019-04-30_12-32-43.png
Normal file
BIN
doc/image/Screenshot_2019-04-30_12-32-43.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@ -1,19 +1,19 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.32112.339
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29215.179
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "navicat-keygen", "navicat-keygen\navicat-keygen.vcxproj", "{6D262AF4-5DAC-4F0C-B3D6-23C9CBEA9756}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "navicat-keygen", "navicat-keygen\navicat-keygen.vcxproj", "{BA201764-EECF-4DA8-BCAD-7CFBA301FC9C}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "navicat-patcher", "navicat-patcher\navicat-patcher.vcxproj", "{1B6920EB-E6ED-465F-9600-B5F816752375}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "navicat-patcher", "navicat-patcher\navicat-patcher.vcxproj", "{7EE03EF3-D58D-4B53-913D-4A4DC8A29E34}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common\common.vcxitems", "{6D81A756-475A-4093-919E-3E9217F662CA}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common\common.vcxitems", "{290C5D5E-52D2-4FEF-909F-27FD95AE0AF9}"
|
||||
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
|
||||
common\common.vcxitems*{290c5d5e-52d2-4fef-909f-27fd95ae0af9}*SharedItemsImports = 9
|
||||
common\common.vcxitems*{7ee03ef3-d58d-4b53-913d-4a4dc8a29e34}*SharedItemsImports = 4
|
||||
common\common.vcxitems*{ba201764-eecf-4da8-bcad-7cfba301fc9c}*SharedItemsImports = 4
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@ -22,27 +22,27 @@ Global
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{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
|
||||
{BA201764-EECF-4DA8-BCAD-7CFBA301FC9C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BA201764-EECF-4DA8-BCAD-7CFBA301FC9C}.Debug|x64.Build.0 = Debug|x64
|
||||
{BA201764-EECF-4DA8-BCAD-7CFBA301FC9C}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{BA201764-EECF-4DA8-BCAD-7CFBA301FC9C}.Debug|x86.Build.0 = Debug|Win32
|
||||
{BA201764-EECF-4DA8-BCAD-7CFBA301FC9C}.Release|x64.ActiveCfg = Release|x64
|
||||
{BA201764-EECF-4DA8-BCAD-7CFBA301FC9C}.Release|x64.Build.0 = Release|x64
|
||||
{BA201764-EECF-4DA8-BCAD-7CFBA301FC9C}.Release|x86.ActiveCfg = Release|Win32
|
||||
{BA201764-EECF-4DA8-BCAD-7CFBA301FC9C}.Release|x86.Build.0 = Release|Win32
|
||||
{7EE03EF3-D58D-4B53-913D-4A4DC8A29E34}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{7EE03EF3-D58D-4B53-913D-4A4DC8A29E34}.Debug|x64.Build.0 = Debug|x64
|
||||
{7EE03EF3-D58D-4B53-913D-4A4DC8A29E34}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{7EE03EF3-D58D-4B53-913D-4A4DC8A29E34}.Debug|x86.Build.0 = Debug|Win32
|
||||
{7EE03EF3-D58D-4B53-913D-4A4DC8A29E34}.Release|x64.ActiveCfg = Release|x64
|
||||
{7EE03EF3-D58D-4B53-913D-4A4DC8A29E34}.Release|x64.Build.0 = Release|x64
|
||||
{7EE03EF3-D58D-4B53-913D-4A4DC8A29E34}.Release|x86.ActiveCfg = Release|Win32
|
||||
{7EE03EF3-D58D-4B53-913D-4A4DC8A29E34}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {9382E280-F6E3-48E2-B3EF-1DB5BFF83DAE}
|
||||
SolutionGuid = {CB1D6B65-6AEA-44E4-8698-0AEBDBC63CD2}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
92
navicat-keygen/Base64.hpp
Normal file
92
navicat-keygen/Base64.hpp
Normal file
@ -0,0 +1,92 @@
|
||||
#pragma once
|
||||
#include <Exception.hpp>
|
||||
#include <ExceptionWin32.hpp>
|
||||
#include <xstring.hpp>
|
||||
#include <bytearray.hpp>
|
||||
#include <wincrypt.h>
|
||||
|
||||
#pragma comment(lib, "Crypt32")
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-keygen\\Base64.hpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
std::xstring Base64Encode(const std::bytearray& Bytes) {
|
||||
if (Bytes.empty()) {
|
||||
return std::xstring();
|
||||
} else {
|
||||
DWORD cchBase64String = 0;
|
||||
std::xstring Base64String;
|
||||
|
||||
auto bResult = CryptBinaryToString(
|
||||
Bytes.data(),
|
||||
static_cast<DWORD>(Bytes.size()),
|
||||
CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF,
|
||||
NULL,
|
||||
&cchBase64String
|
||||
);
|
||||
if (bResult == FALSE) {
|
||||
throw Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("CryptBinaryToString failed."));
|
||||
}
|
||||
|
||||
Base64String.resize(cchBase64String - 1);
|
||||
|
||||
bResult = CryptBinaryToString(
|
||||
Bytes.data(),
|
||||
static_cast<DWORD>(Bytes.size()),
|
||||
CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF,
|
||||
Base64String.data(),
|
||||
&cchBase64String
|
||||
);
|
||||
if (bResult == FALSE) {
|
||||
throw Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("CryptBinaryToString failed."));
|
||||
}
|
||||
|
||||
return Base64String;
|
||||
}
|
||||
}
|
||||
|
||||
std::bytearray Base64Decode(const std::xstring& Base64String) {
|
||||
if (Base64String.empty()) {
|
||||
return std::bytearray();
|
||||
} else {
|
||||
DWORD cbBytes = 0;
|
||||
std::bytearray Bytes;
|
||||
|
||||
auto bResult = CryptStringToBinary(
|
||||
Base64String.c_str(),
|
||||
NULL,
|
||||
CRYPT_STRING_BASE64,
|
||||
NULL,
|
||||
&cbBytes,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
if (bResult == FALSE) {
|
||||
throw Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("CryptStringToBinary failed."))
|
||||
.AddHint(TEXT("Are you sure it is a Base64 string?"));
|
||||
}
|
||||
|
||||
Bytes.resize(cbBytes);
|
||||
|
||||
bResult = CryptStringToBinary(
|
||||
Base64String.c_str(),
|
||||
NULL,
|
||||
CRYPT_STRING_BASE64,
|
||||
Bytes.data(),
|
||||
&cbBytes,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (bResult == FALSE) {
|
||||
throw Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("CryptStringToBinary failed."));
|
||||
}
|
||||
|
||||
return Bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,20 +1,34 @@
|
||||
#include "navicat_serial_generator.hpp"
|
||||
#include "SerialNumberGenerator.hpp"
|
||||
#include <ExceptionUser.hpp>
|
||||
#include <iostream>
|
||||
#include "exceptions/operation_canceled_exception.hpp"
|
||||
|
||||
#define NKG_CURRENT_SOURCE_FILE() u8".\\navicat-keygen\\CollectInformation.cpp"
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-keygen\\CollectInformation.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace std {
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
static auto& xcin = wcin;
|
||||
static auto& xcout = wcout;
|
||||
static auto& xcerr = wcerr;
|
||||
#else
|
||||
static auto& xcin = cin;
|
||||
static auto& xcout = cout;
|
||||
static auto& xcerr = cerr;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace nkg {
|
||||
|
||||
[[nodiscard]]
|
||||
static int read_int(int min_val, int max_val, std::wstring_view prompt, std::wstring_view error_msg) {
|
||||
static int ReadInt(int MinVal, int MaxVal, PCTSTR lpszPrompt, PCTSTR lpszErrorMessage) {
|
||||
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.");
|
||||
std::xstring s;
|
||||
while (true) {
|
||||
std::xcout << lpszPrompt;
|
||||
if (!std::getline(std::xcin, s)) {
|
||||
throw UserAbortionError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Abort."));
|
||||
}
|
||||
|
||||
if (s.empty())
|
||||
@ -22,112 +36,117 @@ namespace nkg {
|
||||
|
||||
try {
|
||||
val = std::stoi(s, nullptr, 0);
|
||||
if (min_val <= val && val <= max_val) {
|
||||
if (MinVal <= val && val <= MaxVal) {
|
||||
return val;
|
||||
} else {
|
||||
throw std::invalid_argument(u8"");
|
||||
throw std::invalid_argument("");
|
||||
}
|
||||
} catch (std::invalid_argument&) {
|
||||
std::wcout << error_msg << std::endl;
|
||||
std::xcout << lpszErrorMessage << 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) {
|
||||
static int ReadInt(int MinVal, int MaxVal, int DefaultVal, PCTSTR lpszPrompt, PCTSTR lpszErrorMessage) {
|
||||
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.");
|
||||
std::xstring s;
|
||||
while (true) {
|
||||
std::xcout << lpszPrompt;
|
||||
if (!std::getline(std::xcin, s)) {
|
||||
throw UserAbortionError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Abort."));
|
||||
}
|
||||
|
||||
if (s.empty()) {
|
||||
return default_val;
|
||||
return DefaultVal;
|
||||
}
|
||||
|
||||
try {
|
||||
val = std::stoi(s, nullptr, 0);
|
||||
if (min_val <= val && val <= max_val) {
|
||||
if (MinVal <= val && val <= MaxVal) {
|
||||
return val;
|
||||
} else {
|
||||
throw std::invalid_argument(u8"");
|
||||
throw std::invalid_argument("");
|
||||
}
|
||||
} catch (std::invalid_argument&) {
|
||||
std::wcout << error_msg << std::endl;
|
||||
std::xcout << lpszErrorMessage << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
navicat_serial_generator CollectInformationNormal() {
|
||||
navicat_serial_generator sn_generator;
|
||||
SerialNumberGenerator CollectInformationNormal() {
|
||||
SerialNumberGenerator 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::xcout << TEXT("[*] Select Navicat product:") << std::endl;
|
||||
std::xcout << TEXT(" 0. DataModeler") << std::endl;
|
||||
std::xcout << TEXT(" 1. Premium") << std::endl;
|
||||
std::xcout << TEXT(" 2. MySQL") << std::endl;
|
||||
std::xcout << TEXT(" 3. PostgreSQL") << std::endl;
|
||||
std::xcout << TEXT(" 4. Oracle") << std::endl;
|
||||
std::xcout << TEXT(" 5. SQLServer") << std::endl;
|
||||
std::xcout << TEXT(" 6. SQLite") << std::endl;
|
||||
std::xcout << TEXT(" 7. MariaDB") << std::endl;
|
||||
std::xcout << TEXT(" 8. MongoDB") << std::endl;
|
||||
std::xcout << TEXT(" 9. ReportViewer") << std::endl;
|
||||
std::xcout << std::endl;
|
||||
Generator.SetProductSignature(
|
||||
static_cast<NavicatProductType>(ReadInt(0, 9, TEXT("(Input index)> "), TEXT("Invalid index.")))
|
||||
);
|
||||
|
||||
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::xcout << std::endl;
|
||||
std::xcout << TEXT("[*] Select product language:") << std::endl;
|
||||
std::xcout << TEXT(" 0. English") << std::endl;
|
||||
std::xcout << TEXT(" 1. Simplified Chinese") << std::endl;
|
||||
std::xcout << TEXT(" 2. Traditional Chinese") << std::endl;
|
||||
std::xcout << TEXT(" 3. Japanese") << std::endl;
|
||||
std::xcout << TEXT(" 4. Polish") << std::endl;
|
||||
std::xcout << TEXT(" 5. Spanish") << std::endl;
|
||||
std::xcout << TEXT(" 6. French") << std::endl;
|
||||
std::xcout << TEXT(" 7. German") << std::endl;
|
||||
std::xcout << TEXT(" 8. Korean") << std::endl;
|
||||
std::xcout << TEXT(" 9. Russian") << std::endl;
|
||||
std::xcout << TEXT(" 10. Portuguese") << std::endl;
|
||||
std::xcout << std::endl;
|
||||
Generator.SetLanguageSignature(
|
||||
static_cast<NavicatLanguage>(ReadInt(0, 10, TEXT("(Input index)> "), TEXT("Invalid index.")))
|
||||
);
|
||||
|
||||
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;
|
||||
std::xcout << std::endl;
|
||||
std::xcout << TEXT("[*] Input major version number:") << std::endl;
|
||||
Generator.SetVersion(
|
||||
static_cast<BYTE>(ReadInt(0, 15, 12, TEXT("(range: 0 ~ 15, default: 12)> "), TEXT("Invalid number.")))
|
||||
);
|
||||
|
||||
return sn_generator;
|
||||
std::xcout << std::endl;
|
||||
return Generator;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
navicat_serial_generator CollectInformationAdvanced() {
|
||||
navicat_serial_generator sn_generator;
|
||||
SerialNumberGenerator CollectInformationAdvanced() {
|
||||
SerialNumberGenerator 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::xcout << TEXT("[*] Navicat Product Signature:") << std::endl;
|
||||
Generator.SetProductSignature(
|
||||
static_cast<BYTE>(ReadInt(0x00, 0xff, TEXT("(range: 0x00 ~ 0xFF)> "), TEXT("Invalid number.")))
|
||||
);
|
||||
|
||||
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::xcout << std::endl;
|
||||
std::xcout << TEXT("[*] Navicat Language Signature 0:") << std::endl;
|
||||
auto s1 = static_cast<BYTE>(ReadInt(0x00, 0xff, TEXT("(range: 0x00 ~ 0xFF)> "), TEXT("Invalid number.")));
|
||||
std::xcout << std::endl;
|
||||
std::xcout << TEXT("[*] Navicat Language Signature 1:") << std::endl;
|
||||
auto s2 = static_cast<BYTE>(ReadInt(0x00, 0xff, TEXT("(range: 0x00 ~ 0xFF)> "), TEXT("Invalid number.")));
|
||||
Generator.SetLanguageSignature(s1, s2);
|
||||
|
||||
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::xcout << std::endl;
|
||||
std::xcout << TEXT("[*] Input major version number:") << std::endl;
|
||||
Generator.SetVersion(
|
||||
static_cast<BYTE>(ReadInt(0, 15, 12, TEXT("(range: 0 ~ 15, default: 12)> "), TEXT("Invalid number.")))
|
||||
);
|
||||
|
||||
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;
|
||||
std::xcout << std::endl;
|
||||
return Generator;
|
||||
}
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
|
||||
@ -1,84 +1,90 @@
|
||||
#include "exception.hpp"
|
||||
#include "exceptions/operation_canceled_exception.hpp"
|
||||
#include "exceptions/win32_exception.hpp"
|
||||
#include <ExceptionUser.hpp>
|
||||
#include <ResourceOwned.hpp>
|
||||
#include <ResourceTraitsWin32.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 <xstring.hpp>
|
||||
#include <bytearray.hpp>
|
||||
#include <RSACipher.hpp>
|
||||
#include "Base64.hpp"
|
||||
#include "SerialNumberGenerator.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"
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-keygen\\GenerateLicense.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace std {
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
static auto & xcin = wcin;
|
||||
static auto& xcout = wcout;
|
||||
static auto& xcerr = wcerr;
|
||||
#else
|
||||
static auto& xcin = cin;
|
||||
static auto& xcout = cout;
|
||||
static auto& xcerr = cerr;
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
void GenerateLicenseText(const RSACipher& Cipher, const SerialNumberGenerator& Generator) {
|
||||
std::xstring username;
|
||||
std::xstring organization;
|
||||
std::string utf8username;
|
||||
std::string utf8organization;
|
||||
|
||||
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::xstring b64RequestCode;
|
||||
std::bytearray RequestCode;
|
||||
std::string utf8RequestInfo;
|
||||
std::string utf8ResponseInfo;
|
||||
std::bytearray ResponseCode;
|
||||
std::xstring b64ResponseCode;
|
||||
|
||||
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.");
|
||||
std::xcout << TEXT("[*] Your name: ");
|
||||
if (!std::getline(std::xcin, username)) {
|
||||
throw UserAbortionError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Abort."));
|
||||
} else {
|
||||
u8_username = cp_converter<-1, CP_UTF8>::convert(username);
|
||||
utf8username = username.explicit_string(CP_UTF8);
|
||||
}
|
||||
|
||||
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.");
|
||||
std::xcout << TEXT("[*] Your organization: ");
|
||||
if (!std::getline(std::xcin, organization)) {
|
||||
throw UserAbortionError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Abort."));
|
||||
} else {
|
||||
u8_organization = cp_converter<-1, CP_UTF8>::convert(organization);
|
||||
utf8organization = organization.explicit_string(CP_UTF8);
|
||||
}
|
||||
|
||||
std::wcout << std::endl;
|
||||
std::wcout << L"[*] Input request code in Base64: (Input empty line to end)" << std::endl;
|
||||
std::xcout << TEXT("[*] 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.");
|
||||
std::xstring temp;
|
||||
if (!std::getline(std::xcin, temp)) {
|
||||
throw UserAbortionError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Abort."));
|
||||
}
|
||||
|
||||
if (s.empty()) {
|
||||
if (temp.empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
b64_request_code.append(s);
|
||||
b64RequestCode.append(temp);
|
||||
}
|
||||
|
||||
if (b64_request_code.empty()) {
|
||||
throw exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), u8"Nothing inputs, abort!");
|
||||
RequestCode = Base64Decode(b64RequestCode);
|
||||
|
||||
utf8RequestInfo.resize((Cipher.Bits() + 7) / 8);
|
||||
Cipher.Decrypt(RequestCode.data(), RequestCode.size(), utf8RequestInfo.data(), RSA_PKCS1_PADDING);
|
||||
while (utf8RequestInfo.back() == '\x00') {
|
||||
utf8RequestInfo.pop_back();
|
||||
}
|
||||
|
||||
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;
|
||||
std::xcout << TEXT("[*] Request Info:") << std::endl;
|
||||
std::xcout << std::xstring(std::xstring_extension{}, utf8RequestInfo, CP_UTF8) << std::endl;
|
||||
std::xcout << std::endl;
|
||||
|
||||
rapidjson::Document json;
|
||||
rapidjson::Value N_Key;
|
||||
@ -91,87 +97,80 @@ namespace nkg {
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||
|
||||
//
|
||||
// begin to parse
|
||||
// Begin to parse
|
||||
//
|
||||
json.Parse(u8_request_info.c_str());
|
||||
|
||||
json.Parse(utf8RequestInfo.c_str());
|
||||
//
|
||||
// remove "Platform" info
|
||||
// Remove "Platform" info
|
||||
//
|
||||
json.RemoveMember(u8"P");
|
||||
|
||||
json.RemoveMember("P");
|
||||
//
|
||||
// set "Name" info
|
||||
// Set "Name" info
|
||||
//
|
||||
N_Key.SetString(u8"N", 1);
|
||||
N_Value.SetString(u8_username.c_str(), static_cast<rapidjson::SizeType>(u8_username.length()));
|
||||
|
||||
N_Key.SetString("N", 1);
|
||||
N_Value.SetString(utf8username.c_str(), static_cast<rapidjson::SizeType>(utf8username.length()));
|
||||
//
|
||||
// set "Organization" info
|
||||
// Set "Organization" info
|
||||
//
|
||||
O_Key.SetString(u8"O", 1);
|
||||
O_Value.SetString(u8_organization.c_str(), static_cast<rapidjson::SizeType>(u8_organization.length()));
|
||||
|
||||
O_Key.SetString("O", 1);
|
||||
O_Value.SetString(utf8organization.c_str(), static_cast<rapidjson::SizeType>(utf8organization.length()));
|
||||
//
|
||||
// set "Time" info
|
||||
// Set "Time" info
|
||||
//
|
||||
T_Key.SetString(u8"T", 1);
|
||||
T_Key.SetString("T", 1);
|
||||
T_Value.SetUint(static_cast<unsigned int>(std::time(nullptr)));
|
||||
|
||||
//
|
||||
// add "Name", "Organization" and "Time"
|
||||
// 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.");
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Response info is too long."));
|
||||
}
|
||||
|
||||
u8_response_info.assign(buffer.GetString(), buffer.GetSize());
|
||||
utf8ResponseInfo.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;
|
||||
std::xcout << TEXT("[*] Response Info:") << std::endl;
|
||||
std::xcout << std::xstring(std::xstring_extension{}, utf8ResponseInfo, CP_UTF8) << std::endl;
|
||||
std::xcout << 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));
|
||||
ResponseCode.resize((Cipher.Bits() + 7) / 8);
|
||||
Cipher.Encrypt<RSAKeyType::PrivateKey>(utf8ResponseInfo.data(), utf8ResponseInfo.size(), ResponseCode.data(), RSA_PKCS1_PADDING);
|
||||
b64ResponseCode = Base64Encode(ResponseCode);
|
||||
|
||||
std::wcout << L"[*] Activation Code:" << std::endl;
|
||||
std::wcout << b64_response_code << std::endl;
|
||||
std::wcout << std::endl;
|
||||
std::xcout << TEXT("[*] Activation Code:") << std::endl;
|
||||
std::xcout << b64ResponseCode << std::endl;
|
||||
std::xcout << std::endl;
|
||||
}
|
||||
|
||||
void GenerateLicenseBinary(const rsa_cipher& cipher, const navicat_serial_generator& sn_generator) {
|
||||
std::string utf8SerialNumber = sn_generator.serial_number();
|
||||
void GenerateLicenseBinary(const RSACipher& Cipher, const SerialNumberGenerator& Generator) {
|
||||
ResourceOwned hLicenseFile(FileHandleTraits{});
|
||||
|
||||
std::wstring username;
|
||||
std::wstring organization;
|
||||
std::string u8_username;
|
||||
std::string u8_organization;
|
||||
std::string utf8SerialNumber = Generator.GetSerialNumberShort().explicit_string(CP_UTF8);
|
||||
|
||||
std::string u8_response_info;
|
||||
std::vector<std::uint8_t> response_code;
|
||||
std::xstring username;
|
||||
std::xstring organization;
|
||||
std::string utf8username;
|
||||
std::string utf8organization;
|
||||
|
||||
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.");
|
||||
std::string utf8ResponseInfo;
|
||||
std::bytearray ResponseCode;
|
||||
|
||||
std::xcout << TEXT("[*] Your name: ");
|
||||
if (!std::getline(std::xcin, username)) {
|
||||
throw UserAbortionError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Abort."));
|
||||
} else {
|
||||
u8_username = cp_converter<-1, CP_UTF8>::convert(username);
|
||||
utf8username = username.explicit_string(CP_UTF8);
|
||||
}
|
||||
|
||||
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.");
|
||||
std::xcout << TEXT("[*] Your organization: ");
|
||||
if (!std::getline(std::xcin, organization)) {
|
||||
throw UserAbortionError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Abort."));
|
||||
} else {
|
||||
u8_organization = cp_converter<-1, CP_UTF8>::convert(organization);
|
||||
utf8organization = organization.explicit_string(CP_UTF8);
|
||||
}
|
||||
|
||||
rapidjson::Document json;
|
||||
@ -190,9 +189,9 @@ namespace nkg {
|
||||
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()));
|
||||
N_Value.SetString(utf8username.c_str(), static_cast<rapidjson::SizeType>(utf8username.length()));
|
||||
O_Key.SetString("O", 1);
|
||||
O_Value.SetString(u8_organization.c_str(), static_cast<rapidjson::SizeType>(u8_organization.length()));
|
||||
O_Value.SetString(utf8organization.c_str(), static_cast<rapidjson::SizeType>(utf8organization.length()));
|
||||
T_Key.SetString("T", 1);
|
||||
T_Value.SetUint(static_cast<unsigned int>(std::time(nullptr)));
|
||||
|
||||
@ -201,37 +200,42 @@ namespace nkg {
|
||||
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.");
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Response info is too long."));
|
||||
}
|
||||
|
||||
u8_response_info.assign(buffer.GetString(), buffer.GetSize());
|
||||
utf8ResponseInfo.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;
|
||||
std::xcout << TEXT("[*] Response Info:") << std::endl;
|
||||
std::xcout << std::xstring(std::xstring_extension{}, utf8ResponseInfo, CP_UTF8) << std::endl;
|
||||
std::xcout << 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));
|
||||
ResponseCode.resize((Cipher.Bits() + 7) / 8);
|
||||
Cipher.Encrypt<RSAKeyType::PrivateKey>(utf8ResponseInfo.data(), utf8ResponseInfo.size(), ResponseCode.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.");
|
||||
hLicenseFile.TakeOver(
|
||||
CreateFile(
|
||||
TEXT("license_file"),
|
||||
GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL
|
||||
)
|
||||
);
|
||||
if (hLicenseFile.IsValid() == false) {
|
||||
throw Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("CreateFile 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.");
|
||||
DWORD NumberOfBytesWritten;
|
||||
if (!WriteFile(hLicenseFile, ResponseCode.data(), static_cast<DWORD>(ResponseCode.size()), &NumberOfBytesWritten, NULL)) {
|
||||
throw Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("WriteFile failed."));
|
||||
}
|
||||
|
||||
std::wcout << L"[+] license_file has been generated." << std::endl;
|
||||
}
|
||||
std::xcout << TEXT("[+] license_file has been generated.") << std::endl;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
|
||||
195
navicat-keygen/SerialNumberGenerator.cpp
Normal file
195
navicat-keygen/SerialNumberGenerator.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
#include "SerialNumberGenerator.hpp"
|
||||
#include <Exception.hpp>
|
||||
#include <openssl/des.h>
|
||||
#include <NTSecAPI.h>
|
||||
#include <iostream>
|
||||
|
||||
#pragma comment(lib, "Advapi32")
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-keygen\\NavicatKeygen.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace std {
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
static auto & xcin = wcin;
|
||||
static auto& xcout = wcout;
|
||||
static auto& xcerr = wcerr;
|
||||
#else
|
||||
static auto& xcin = cin;
|
||||
static auto& xcout = cout;
|
||||
static auto& xcerr = cerr;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace nkg {
|
||||
|
||||
SerialNumberGenerator::SerialNumberGenerator() noexcept :
|
||||
_Data{ 0x68 , 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32 } {}
|
||||
|
||||
void SerialNumberGenerator::SetLanguageSignature(NavicatLanguage Language) noexcept {
|
||||
switch (Language) {
|
||||
case NavicatLanguage::English:
|
||||
_Data[5] = 0xAC; // Must be 0xAC for English version.
|
||||
_Data[6] = 0x88; // Must be 0x88 for English version.
|
||||
break;
|
||||
case NavicatLanguage::SimplifiedChinese:
|
||||
_Data[5] = 0xCE; // Must be 0xCE for Simplified Chinese version.
|
||||
_Data[6] = 0x32; // Must be 0x32 for Simplified Chinese version.
|
||||
break;
|
||||
case NavicatLanguage::TraditionalChinese:
|
||||
_Data[5] = 0xAA; // Must be 0xAA for Traditional Chinese version.
|
||||
_Data[6] = 0x99; // Must be 0x99 for Traditional Chinese version.
|
||||
break;
|
||||
case NavicatLanguage::Japanese:
|
||||
_Data[5] = 0xAD; // Must be 0xAD for Japanese version. Discoverer: @dragonflylee
|
||||
_Data[6] = 0x82; // Must be 0x82 for Japanese version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case NavicatLanguage::Polish:
|
||||
_Data[5] = 0xBB; // Must be 0xBB for Polish version. Discoverer: @dragonflylee
|
||||
_Data[6] = 0x55; // Must be 0x55 for Polish version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case NavicatLanguage::Spanish:
|
||||
_Data[5] = 0xAE; // Must be 0xAE for Spanish version. Discoverer: @dragonflylee
|
||||
_Data[6] = 0x10; // Must be 0x10 for Spanish version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case NavicatLanguage::French:
|
||||
_Data[5] = 0xFA; // Must be 0xFA for French version. Discoverer: @Deltafox79
|
||||
_Data[6] = 0x20; // Must be 0x20 for French version. Discoverer: @Deltafox79
|
||||
break;
|
||||
case NavicatLanguage::German:
|
||||
_Data[5] = 0xB1; // Must be 0xB1 for German version. Discoverer: @dragonflylee
|
||||
_Data[6] = 0x60; // Must be 0x60 for German version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case NavicatLanguage::Korean:
|
||||
_Data[5] = 0xB5; // Must be 0xB5 for Korean version. Discoverer: @dragonflylee
|
||||
_Data[6] = 0x60; // Must be 0x60 for Korean version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case NavicatLanguage::Russian:
|
||||
_Data[5] = 0xEE; // Must be 0xB5 for Russian version. Discoverer: @dragonflylee
|
||||
_Data[6] = 0x16; // Must be 0x60 for Russian version. Discoverer: @dragonflylee
|
||||
break;
|
||||
case NavicatLanguage::Portuguese:
|
||||
_Data[5] = 0xCD; // Must be 0xCD for Portuguese version. Discoverer: @dragonflylee
|
||||
_Data[6] = 0x49; // Must be 0x49 for Portuguese version. Discoverer: @dragonflylee
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SerialNumberGenerator::SetLanguageSignature(BYTE LanguageSignature0, BYTE LanguageSignature1) noexcept {
|
||||
_Data[5] = LanguageSignature0;
|
||||
_Data[6] = LanguageSignature1;
|
||||
}
|
||||
|
||||
void SerialNumberGenerator::SetProductSignature(NavicatProductType ProductType) noexcept {
|
||||
switch (ProductType) {
|
||||
case NavicatProductType::DataModeler:
|
||||
_Data[7] = 0x84;
|
||||
break;
|
||||
case NavicatProductType::Premium:
|
||||
_Data[7] = 0x65;
|
||||
break;
|
||||
case NavicatProductType::MySQL:
|
||||
_Data[7] = 0x68;
|
||||
break;
|
||||
case NavicatProductType::PostgreSQL:
|
||||
_Data[7] = 0x6C;
|
||||
break;
|
||||
case NavicatProductType::Oracle:
|
||||
_Data[7] = 0x70;
|
||||
break;
|
||||
case NavicatProductType::SQLServer:
|
||||
_Data[7] = 0x74;
|
||||
break;
|
||||
case NavicatProductType::SQLite:
|
||||
_Data[7] = 0x78;
|
||||
break;
|
||||
case NavicatProductType::MariaDB:
|
||||
_Data[7] = 0x7C;
|
||||
break;
|
||||
case NavicatProductType::MongoDB:
|
||||
_Data[7] = 0x80;
|
||||
break;
|
||||
case NavicatProductType::ReportViewer:
|
||||
_Data[7] = 0xb;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SerialNumberGenerator::SetProductSignature(BYTE ProductSignature) noexcept {
|
||||
_Data[7] = ProductSignature;
|
||||
}
|
||||
|
||||
void SerialNumberGenerator::SetVersion(BYTE Version) {
|
||||
if (Version < 0x10) {
|
||||
_Data[8] = static_cast<BYTE>(Version << 4);
|
||||
} else {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Invalid version for Navicat."));
|
||||
}
|
||||
}
|
||||
|
||||
void SerialNumberGenerator::Generate() {
|
||||
static const TCHAR EncodeTable[] = TEXT("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567");
|
||||
|
||||
RtlGenRandom(_Data + 2, 3);
|
||||
|
||||
const_DES_cblock key = { 0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27 };
|
||||
DES_key_schedule schedule;
|
||||
DES_set_key_unchecked(&key, &schedule);
|
||||
DES_ecb_encrypt(
|
||||
reinterpret_cast<const_DES_cblock*>(_Data + 2),
|
||||
reinterpret_cast<const_DES_cblock*>(_Data + 2),
|
||||
&schedule,
|
||||
DES_ENCRYPT
|
||||
);
|
||||
|
||||
_SerialNumberShort.resize(16);
|
||||
|
||||
_SerialNumberShort[0] = EncodeTable[_Data[0] >> 3];
|
||||
_SerialNumberShort[1] = EncodeTable[(_Data[0] & 0x07) << 2 | _Data[1] >> 6];
|
||||
_SerialNumberShort[2] = EncodeTable[_Data[1] >> 1 & 0x1F];
|
||||
_SerialNumberShort[3] = EncodeTable[(_Data[1] & 0x1) << 4 | _Data[2] >> 4];
|
||||
_SerialNumberShort[4] = EncodeTable[(_Data[2] & 0xF) << 1 | _Data[3] >> 7];
|
||||
_SerialNumberShort[5] = EncodeTable[_Data[3] >> 2 & 0x1F];
|
||||
_SerialNumberShort[6] = EncodeTable[_Data[3] << 3 & 0x1F | _Data[4] >> 5];
|
||||
_SerialNumberShort[7] = EncodeTable[_Data[4] & 0x1F];
|
||||
|
||||
_SerialNumberShort[8] = EncodeTable[_Data[5] >> 3];
|
||||
_SerialNumberShort[9] = EncodeTable[(_Data[5] & 0x07) << 2 | _Data[6] >> 6];
|
||||
_SerialNumberShort[10] = EncodeTable[_Data[6] >> 1 & 0x1F];
|
||||
_SerialNumberShort[11] = EncodeTable[(_Data[6] & 0x1) << 4 | _Data[7] >> 4];
|
||||
_SerialNumberShort[12] = EncodeTable[(_Data[7] & 0xF) << 1 | _Data[8] >> 7];
|
||||
_SerialNumberShort[13] = EncodeTable[_Data[8] >> 2 & 0x1F];
|
||||
_SerialNumberShort[14] = EncodeTable[_Data[8] << 3 & 0x1F | _Data[9] >> 5];
|
||||
_SerialNumberShort[15] = EncodeTable[_Data[9] & 0x1F];
|
||||
|
||||
_SerialNumberLong = std::xstring::format(
|
||||
TEXT("%.4s-%.4s-%.4s-%.4s"),
|
||||
_SerialNumberShort.c_str() + 0,
|
||||
_SerialNumberShort.c_str() + 4,
|
||||
_SerialNumberShort.c_str() + 8,
|
||||
_SerialNumberShort.c_str() + 12
|
||||
);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const std::xstring& SerialNumberGenerator::GetSerialNumberShort() const noexcept {
|
||||
return _SerialNumberShort;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const std::xstring& SerialNumberGenerator::GetSerialNumberLong() const noexcept {
|
||||
return _SerialNumberLong;
|
||||
}
|
||||
|
||||
void SerialNumberGenerator::ShowInConsole() const {
|
||||
std::xcout << TEXT("[*] Serial number:") << std::endl;
|
||||
std::xcout << _SerialNumberLong << std::endl;
|
||||
std::xcout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
64
navicat-keygen/SerialNumberGenerator.hpp
Normal file
64
navicat-keygen/SerialNumberGenerator.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <xstring.hpp>
|
||||
|
||||
namespace nkg {
|
||||
|
||||
enum class NavicatLanguage {
|
||||
English,
|
||||
SimplifiedChinese,
|
||||
TraditionalChinese,
|
||||
Japanese,
|
||||
Polish,
|
||||
Spanish,
|
||||
French,
|
||||
German,
|
||||
Korean,
|
||||
Russian,
|
||||
Portuguese
|
||||
};
|
||||
|
||||
enum class NavicatProductType {
|
||||
DataModeler,
|
||||
Premium,
|
||||
MySQL,
|
||||
PostgreSQL,
|
||||
Oracle,
|
||||
SQLServer,
|
||||
SQLite,
|
||||
MariaDB,
|
||||
MongoDB,
|
||||
ReportViewer
|
||||
};
|
||||
|
||||
class SerialNumberGenerator {
|
||||
private:
|
||||
|
||||
BYTE _Data[10];
|
||||
std::xstring _SerialNumberShort;
|
||||
std::xstring _SerialNumberLong;
|
||||
|
||||
public:
|
||||
|
||||
SerialNumberGenerator() noexcept;
|
||||
|
||||
void SetLanguageSignature(NavicatLanguage Language) noexcept;
|
||||
void SetLanguageSignature(BYTE LanguageSignature0, BYTE LanguageSignature1) noexcept;
|
||||
|
||||
void SetProductSignature(NavicatProductType ProductType) noexcept;
|
||||
void SetProductSignature(BYTE ProductSignature) noexcept;
|
||||
|
||||
void SetVersion(BYTE Version);
|
||||
|
||||
void Generate();
|
||||
|
||||
[[nodiscard]]
|
||||
const std::xstring& GetSerialNumberShort() const noexcept;
|
||||
[[nodiscard]]
|
||||
const std::xstring& GetSerialNumberLong() const noexcept;
|
||||
|
||||
void ShowInConsole() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
117
navicat-keygen/_tmain.cpp
Normal file
117
navicat-keygen/_tmain.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
#include <tchar.h>
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <Exception.hpp>
|
||||
#include <ExceptionUser.hpp>
|
||||
#include <RSACipher.hpp>
|
||||
#include "SerialNumberGenerator.hpp"
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-keygen\\_tmain.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
using fnCollectInformation = SerialNumberGenerator();
|
||||
using fnGenerateLicense = void(const RSACipher& Cipher, const SerialNumberGenerator& Generator);
|
||||
|
||||
SerialNumberGenerator CollectInformationNormal();
|
||||
SerialNumberGenerator CollectInformationAdvanced();
|
||||
void GenerateLicenseText(const RSACipher& Cipher, const SerialNumberGenerator& Generator);
|
||||
void GenerateLicenseBinary(const RSACipher& Cipher, const SerialNumberGenerator& Generator);
|
||||
}
|
||||
|
||||
static void Welcome() {
|
||||
_putts(TEXT("***************************************************"));
|
||||
_putts(TEXT("* Navicat Keygen by @DoubleLabyrinth *"));
|
||||
_putts(TEXT("* Version: 4.0 *"));
|
||||
_putts(TEXT("***************************************************"));
|
||||
_putts(TEXT(""));
|
||||
}
|
||||
|
||||
static void Help() {
|
||||
_putts(TEXT("Usage:"));
|
||||
_putts(TEXT(" navicat-keygen.exe <-bin|-text> [-adv] <RSA-2048 Private Key File>"));
|
||||
_putts(TEXT(""));
|
||||
_putts(TEXT(" <-bin|-text> Specify \"-bin\" to generate \"license_file\" used by Navicat 11."));
|
||||
_putts(TEXT(" Specify \"-text\" to generate base64-encoded activation code."));
|
||||
_putts(TEXT(" This parameter must be specified."));
|
||||
_putts(TEXT(""));
|
||||
_putts(TEXT(" [-adv] Enable advance mode."));
|
||||
_putts(TEXT(" This parameter is optional."));
|
||||
_putts(TEXT(""));
|
||||
_putts(TEXT(" <RSA-2048 Private Key File> A path to an RSA-2048 private key file."));
|
||||
_putts(TEXT(" This parameter must be specified."));
|
||||
_putts(TEXT(""));
|
||||
_putts(TEXT("Example:"));
|
||||
_putts(TEXT(" navicat-keygen.exe -text .\\RegPrivateKey.pem"));
|
||||
}
|
||||
|
||||
int _tmain(int argc, PTSTR argv[]) {
|
||||
Welcome();
|
||||
|
||||
if (argc == 3 || argc == 4) {
|
||||
nkg::fnCollectInformation* lpfnCollectInformation = nullptr;
|
||||
nkg::fnGenerateLicense* lpfnGenerateLicense = nullptr;
|
||||
|
||||
if (_tcsicmp(argv[1], TEXT("-bin")) == 0) {
|
||||
lpfnGenerateLicense = nkg::GenerateLicenseBinary;
|
||||
} else if (_tcsicmp(argv[1], TEXT("-text")) == 0) {
|
||||
lpfnGenerateLicense = nkg::GenerateLicenseText;
|
||||
} else {
|
||||
Help();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argc == 4) {
|
||||
if (_tcsicmp(argv[2], TEXT("-adv")) == 0) {
|
||||
lpfnCollectInformation = nkg::CollectInformationAdvanced;
|
||||
} else {
|
||||
Help();
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
lpfnCollectInformation = nkg::CollectInformationNormal;
|
||||
}
|
||||
|
||||
try {
|
||||
nkg::RSACipher Cipher;
|
||||
|
||||
Cipher.ImportKeyFromFile<nkg::RSAKeyType::PrivateKey, nkg::RSAKeyFormat::PEM>(argv[argc - 1]);
|
||||
if (Cipher.Bits() != 2048) {
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("RSA key length mismatches."))
|
||||
.AddHint(TEXT("You must provide an RSA key whose modulus length is 2048 bits."));
|
||||
}
|
||||
|
||||
auto Generator = lpfnCollectInformation();
|
||||
|
||||
Generator.Generate();
|
||||
Generator.ShowInConsole();
|
||||
|
||||
lpfnGenerateLicense(Cipher, Generator);
|
||||
|
||||
return 0;
|
||||
} catch (nkg::UserAbortionError&) {
|
||||
return -1;
|
||||
} catch (nkg::Exception& e) {
|
||||
_tprintf_s(TEXT("[-] %s:%zu ->\n"), e.File(), e.Line());
|
||||
_tprintf_s(TEXT(" %s\n"), e.Message());
|
||||
|
||||
if (e.HasErrorCode()) {
|
||||
_tprintf_s(TEXT(" %s (0x%zx)\n"), e.ErrorString(), e.ErrorCode());
|
||||
}
|
||||
|
||||
for (auto& Hint : e.Hints()) {
|
||||
_tprintf_s(TEXT(" Hints: %s\n"), Hint.c_str());
|
||||
}
|
||||
|
||||
return -1;
|
||||
} catch (std::exception& e) {
|
||||
_tprintf_s(TEXT("[-] %hs\n"), e.what());
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
Help();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -1,120 +0,0 @@
|
||||
#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
|
||||
@ -1,39 +0,0 @@
|
||||
#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
|
||||
@ -1,103 +0,0 @@
|
||||
#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
|
||||
@ -1,20 +0,0 @@
|
||||
#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);
|
||||
};
|
||||
|
||||
}
|
||||
@ -20,37 +20,43 @@
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{BA201764-EECF-4DA8-BCAD-7CFBA301FC9C}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{6d262af4-5dac-4f0c-b3d6-23c9cbea9756}</ProjectGuid>
|
||||
<RootNamespace>navicatkeygen</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
|
||||
<VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<SpectreMitigation>false</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<SpectreMitigation>false</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<SpectreMitigation>false</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<SpectreMitigation>false</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
@ -73,40 +79,28 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\obj\$(PlatformTarget)-$(Configuration)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)\obj\$(PlatformTarget)-$(Configuration)\$(ProjectName)\</IntDir>
|
||||
<OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(Platform)-$(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>
|
||||
<OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<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>
|
||||
<OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
@ -118,9 +112,25 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<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|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
@ -136,23 +146,10 @@
|
||||
<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>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
@ -169,17 +166,14 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<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" />
|
||||
<ClCompile Include="SerialNumberGenerator.cpp" />
|
||||
<ClCompile Include="_tmain.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="base32_rfc4648.hpp" />
|
||||
<ClInclude Include="base64_rfc4648.hpp" />
|
||||
<ClInclude Include="navicat_serial_generator.hpp" />
|
||||
<ClInclude Include="Base64.hpp" />
|
||||
<ClInclude Include="SerialNumberGenerator.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;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
@ -15,13 +15,10 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="wmain.cpp">
|
||||
<ClCompile Include="_tmain.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base64_rfc4648.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="navicat_serial_generator.cpp">
|
||||
<ClCompile Include="SerialNumberGenerator.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CollectInformation.cpp">
|
||||
@ -30,18 +27,12 @@
|
||||
<ClCompile Include="GenerateLicense.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base32_rfc4648.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="base64_rfc4648.hpp">
|
||||
<ClInclude Include="Base64.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="navicat_serial_generator.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="base32_rfc4648.hpp">
|
||||
<ClInclude Include="SerialNumberGenerator.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
||||
@ -1,196 +0,0 @@
|
||||
#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
|
||||
@ -1,82 +0,0 @@
|
||||
#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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -1,121 +0,0 @@
|
||||
#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
|
||||
98
navicat-patcher/CapstoneDisassembler.cpp
Normal file
98
navicat-patcher/CapstoneDisassembler.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
#include "CapstoneDisassembler.hpp"
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\CapstoneDisassembler.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
CapstoneDisassembler::CapstoneDisassembler(const CapstoneEngine& Engine) :
|
||||
ResourceOwned<CapstoneInsnTraits>(cs_malloc(Engine)),
|
||||
_Engine(Engine),
|
||||
_CurrentState{},
|
||||
_NextState{},
|
||||
_lpCurrentInsn(nullptr)
|
||||
{
|
||||
if (IsValid() == false) {
|
||||
throw CapstoneError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), cs_errno(Engine), TEXT("cs_malloc failed."));
|
||||
}
|
||||
}
|
||||
|
||||
CapstoneDisassembler::CapstoneDisassembler(CapstoneDisassembler&& Other) noexcept :
|
||||
ResourceOwned<CapstoneInsnTraits>(static_cast<ResourceOwned<CapstoneInsnTraits>&&>(Other)),
|
||||
_Engine(Other._Engine),
|
||||
_CurrentState(Other._CurrentState),
|
||||
_NextState(Other._NextState),
|
||||
_lpCurrentInsn(Other._lpCurrentInsn) {}
|
||||
|
||||
CapstoneDisassembler& CapstoneDisassembler::SetContext(const CapstoneContext& Ctx) noexcept {
|
||||
_lpCurrentInsn = nullptr;
|
||||
|
||||
_CurrentState.lpMachineCode = nullptr;
|
||||
_CurrentState.cbMachineCode = 0;
|
||||
_CurrentState.Address = 0;
|
||||
|
||||
_NextState = Ctx;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const CapstoneContext& CapstoneDisassembler::GetContext() const noexcept {
|
||||
return _NextState;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool CapstoneDisassembler::Next() noexcept {
|
||||
bool bSucceed;
|
||||
CapstoneContext backup = _NextState;
|
||||
|
||||
bSucceed = cs_disasm_iter(_Engine.Get(), reinterpret_cast<const uint8_t**>(&_NextState.lpMachineCode), &_NextState.cbMachineCode, &_NextState.Address, Get());
|
||||
if (bSucceed) {
|
||||
if (_lpCurrentInsn == nullptr) {
|
||||
_lpCurrentInsn = Get();
|
||||
}
|
||||
|
||||
_CurrentState = backup;
|
||||
} else {
|
||||
_lpCurrentInsn = nullptr;
|
||||
}
|
||||
|
||||
return bSucceed;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const cs_insn* CapstoneDisassembler::GetInstruction() const noexcept {
|
||||
return _lpCurrentInsn;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const CapstoneContext& CapstoneDisassembler::GetInstructionContext() const noexcept {
|
||||
return _CurrentState;
|
||||
}
|
||||
|
||||
CapstoneEngine::CapstoneEngine(cs_arch ArchType, cs_mode Mode) {
|
||||
auto err = cs_open(ArchType, Mode, GetAddressOf());
|
||||
if (err != CS_ERR_OK) {
|
||||
throw CapstoneError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, TEXT("cs_open failed."));
|
||||
}
|
||||
}
|
||||
|
||||
void CapstoneEngine::Option(cs_opt_type Type, cs_opt_value Value) {
|
||||
auto err = cs_option(Get(), Type, Value);
|
||||
if (err != CS_ERR_OK) {
|
||||
throw CapstoneError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, TEXT("cs_option failed."));
|
||||
}
|
||||
}
|
||||
|
||||
const char* CapstoneEngine::GetRegisterName(unsigned int reg_id) const noexcept {
|
||||
return cs_reg_name(Get(), reg_id);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
CapstoneDisassembler CapstoneEngine::CreateDisassembler() const {
|
||||
return CapstoneDisassembler(*this);
|
||||
}
|
||||
}
|
||||
|
||||
61
navicat-patcher/CapstoneDisassembler.hpp
Normal file
61
navicat-patcher/CapstoneDisassembler.hpp
Normal file
@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
#include "ExceptionCapstone.hpp"
|
||||
#include <ResourceOwned.hpp>
|
||||
#include "ResourceTraitsCapstone.hpp"
|
||||
|
||||
namespace nkg {
|
||||
|
||||
struct CapstoneContext {
|
||||
const void* lpMachineCode;
|
||||
size_t cbMachineCode;
|
||||
uint64_t Address;
|
||||
};
|
||||
|
||||
class CapstoneEngine;
|
||||
|
||||
class CapstoneDisassembler : private ResourceOwned<CapstoneInsnTraits> {
|
||||
friend class CapstoneEngine;
|
||||
private:
|
||||
|
||||
const CapstoneEngine& _Engine;
|
||||
CapstoneContext _CurrentState;
|
||||
CapstoneContext _NextState;
|
||||
cs_insn* _lpCurrentInsn;
|
||||
|
||||
CapstoneDisassembler(const CapstoneEngine& Engine);
|
||||
|
||||
public:
|
||||
|
||||
CapstoneDisassembler(CapstoneDisassembler&& Other) noexcept;
|
||||
|
||||
CapstoneDisassembler& SetContext(const CapstoneContext& Ctx) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
const CapstoneContext& GetContext() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
bool Next() noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
const cs_insn* GetInstruction() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
const CapstoneContext& GetInstructionContext() const noexcept;
|
||||
};
|
||||
|
||||
class CapstoneEngine : private ResourceOwned<CapstoneHandleTraits> {
|
||||
friend class CapstoneDisassembler;
|
||||
public:
|
||||
|
||||
CapstoneEngine(cs_arch ArchType, cs_mode Mode);
|
||||
|
||||
void Option(cs_opt_type Type, cs_opt_value Value);
|
||||
|
||||
const char* GetRegisterName(unsigned int reg_id) const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
CapstoneDisassembler CreateDisassembler() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
36
navicat-patcher/ExceptionCapstone.hpp
Normal file
36
navicat-patcher/ExceptionCapstone.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include <Exception.hpp>
|
||||
#include <capstone/capstone.h>
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class CapstoneError final : public Exception {
|
||||
private:
|
||||
|
||||
cs_err _ErrorCode;
|
||||
std::xstring _ErrorString;
|
||||
|
||||
public:
|
||||
|
||||
CapstoneError(PCTSTR SourceFile, SIZE_T SourceLine, cs_err CapstoneErrorCode, PCTSTR CustomMessage) noexcept :
|
||||
Exception(SourceFile, SourceLine, CustomMessage),
|
||||
_ErrorCode(CapstoneErrorCode),
|
||||
_ErrorString(std::xstring_extension{}, cs_strerror(CapstoneErrorCode), CP_UTF8) {}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool HasErrorCode() const noexcept override {
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual ULONG_PTR ErrorCode() const noexcept override {
|
||||
return _ErrorCode;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual PCTSTR ErrorString() const noexcept override {
|
||||
return _ErrorString.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
37
navicat-patcher/ExceptionKeystone.hpp
Normal file
37
navicat-patcher/ExceptionKeystone.hpp
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#include <Exception.hpp>
|
||||
#include <keystone/keystone.h>
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class KeystoneError final : public Exception {
|
||||
private:
|
||||
|
||||
ks_err _ErrorCode;
|
||||
std::xstring _ErrorString;
|
||||
|
||||
public:
|
||||
|
||||
KeystoneError(PCTSTR SourceFile, SIZE_T SourceLine, ks_err KeystoneErrorCode, PCTSTR CustomMessage) noexcept :
|
||||
Exception(SourceFile, SourceLine, CustomMessage),
|
||||
_ErrorCode(KeystoneErrorCode),
|
||||
_ErrorString(std::xstring_extension{}, ks_strerror(KeystoneErrorCode), CP_UTF8) {}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool HasErrorCode() const noexcept override {
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual ULONG_PTR ErrorCode() const noexcept override {
|
||||
return _ErrorCode;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual PCTSTR ErrorString() const noexcept override {
|
||||
return _ErrorString.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
342
navicat-patcher/ImageInterpreter.cpp
Normal file
342
navicat-patcher/ImageInterpreter.cpp
Normal file
@ -0,0 +1,342 @@
|
||||
#include "ImageInterpreter.hpp"
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\ImageInterpreter.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
ImageInterpreter::ImageInterpreter() :
|
||||
_DosHeader(nullptr),
|
||||
_NtHeaders(nullptr),
|
||||
_SectionHeaderTable(nullptr),
|
||||
_VsFixedFileInfo(nullptr) {}
|
||||
|
||||
[[nodiscard]]
|
||||
ImageInterpreter ImageInterpreter::ParseImage(PVOID ImageBase, bool DisableRelocationParsing) {
|
||||
ImageInterpreter NewImage;
|
||||
|
||||
NewImage._DosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(ImageBase);
|
||||
if (NewImage._DosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Invalid Image. (DOS signature check failure)"))
|
||||
.AddHint(TEXT("Are you sure you DO provide a valid WinPE file?"));
|
||||
}
|
||||
|
||||
NewImage._NtHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(
|
||||
reinterpret_cast<uint8_t*>(ImageBase) + NewImage._DosHeader->e_lfanew
|
||||
);
|
||||
if (NewImage._NtHeaders->Signature != IMAGE_NT_SIGNATURE) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Invalid Image. (NT signature check failure)"))
|
||||
.AddHint(TEXT("Are you sure you DO provide a valid WinPE file?"));
|
||||
}
|
||||
|
||||
#if defined(_M_AMD64)
|
||||
if (NewImage._NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Invalid Image. (Optional header magic check failure)"))
|
||||
.AddHint(TEXT("Are you sure you DO provide a valid 64-bits WinPE file?"));
|
||||
}
|
||||
if (NewImage._NtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Invalid Image. (Machine check failure)"))
|
||||
.AddHint(TEXT("Are you sure you DO provide a valid 64-bits WinPE file?"));
|
||||
}
|
||||
#elif defined(_M_IX86)
|
||||
if (NewImage._NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Invalid Image. (Optional header magic check failure)"))
|
||||
.AddHint(TEXT("Are you sure you DO provide a valid 32-bits WinPE file?"));
|
||||
}
|
||||
if (NewImage._NtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Invalid Image. (Machine check failure)"))
|
||||
.AddHint(TEXT("Are you sure you DO provide a valid 32-bits WinPE file?"));
|
||||
}
|
||||
#else
|
||||
#error "Unsupported architecture."
|
||||
#endif
|
||||
|
||||
NewImage._SectionHeaderTable = reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
||||
reinterpret_cast<char*>(&NewImage._NtHeaders->OptionalHeader) + NewImage._NtHeaders->FileHeader.SizeOfOptionalHeader
|
||||
);
|
||||
|
||||
for (WORD i = 0; i < NewImage._NtHeaders->FileHeader.NumberOfSections; ++i) {
|
||||
uint64_t SectionName = *reinterpret_cast<uint64_t*>(NewImage._SectionHeaderTable[i].Name);
|
||||
|
||||
if (NewImage._SectionNameTable.find(SectionName) == NewImage._SectionNameTable.end()) {
|
||||
NewImage._SectionNameTable[SectionName] = i;
|
||||
}
|
||||
|
||||
NewImage._SectionRvaTable[NewImage._SectionHeaderTable[i].VirtualAddress] = i;
|
||||
NewImage._SectionFileOffsetTable[NewImage._SectionHeaderTable[i].PointerToRawData] = i;
|
||||
}
|
||||
|
||||
if (!DisableRelocationParsing && NewImage._NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0) {
|
||||
auto RelocTableRva = NewImage._NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
|
||||
auto RelocTable = NewImage.RvaToPointer<PIMAGE_BASE_RELOCATION>(RelocTableRva);
|
||||
|
||||
while (RelocTable->VirtualAddress != 0) {
|
||||
uintptr_t Rva = RelocTable->VirtualAddress;
|
||||
PWORD RelocItems = reinterpret_cast<PWORD>(RelocTable + 1);
|
||||
DWORD RelocItemsCount = (RelocTable->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
|
||||
|
||||
for (DWORD i = 0; i < RelocItemsCount; ++i) {
|
||||
auto RelocType = RelocItems[i] >> 12;
|
||||
|
||||
switch (RelocType) {
|
||||
case IMAGE_REL_BASED_ABSOLUTE:
|
||||
break;
|
||||
case IMAGE_REL_BASED_HIGH:
|
||||
case IMAGE_REL_BASED_LOW:
|
||||
case IMAGE_REL_BASED_HIGHADJ:
|
||||
NewImage._RelocationRvaTable[Rva + (RelocItems[i] & 0x0fff)] = 2;
|
||||
break;
|
||||
case IMAGE_REL_BASED_HIGHLOW:
|
||||
NewImage._RelocationRvaTable[Rva + (RelocItems[i] & 0x0fff)] = 4;
|
||||
break;
|
||||
#if defined(IMAGE_REL_BASED_DIR64)
|
||||
case IMAGE_REL_BASED_DIR64:
|
||||
NewImage._RelocationRvaTable[Rva + (RelocItems[i] & 0x0fff)] = 8;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RelocTable = reinterpret_cast<PIMAGE_BASE_RELOCATION>(&RelocItems[RelocItemsCount]);
|
||||
}
|
||||
}
|
||||
|
||||
if (NewImage._NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress) {
|
||||
uintptr_t ResourceRva = NewImage._NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
|
||||
|
||||
auto ResourceTypeTable =
|
||||
NewImage.RvaToPointer<PIMAGE_RESOURCE_DIRECTORY>(ResourceRva);
|
||||
auto ResourceTypeNameEntries =
|
||||
reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY_ENTRY>(ResourceTypeTable + 1);
|
||||
auto ResourceTypeIdEntries =
|
||||
ResourceTypeNameEntries + ResourceTypeTable->NumberOfNamedEntries;
|
||||
bool VS_FII_Ok = false;
|
||||
|
||||
for (WORD i = 0; i < ResourceTypeTable->NumberOfIdEntries && !VS_FII_Ok; ++i) {
|
||||
if (ResourceTypeIdEntries[i].Id == reinterpret_cast<uintptr_t>(RT_VERSION) && ResourceTypeIdEntries[i].DataIsDirectory) {
|
||||
auto ResourceNameTable =
|
||||
NewImage.RvaToPointer<PIMAGE_RESOURCE_DIRECTORY>(ResourceRva + ResourceTypeIdEntries[i].OffsetToDirectory);
|
||||
auto ResourceNameNameEntries =
|
||||
reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY_ENTRY>(ResourceNameTable + 1);
|
||||
auto ResourceNameIdEntries =
|
||||
ResourceNameNameEntries + ResourceNameTable->NumberOfNamedEntries;
|
||||
|
||||
for (WORD j = 0; j < ResourceNameTable->NumberOfIdEntries && !VS_FII_Ok; ++j) {
|
||||
if (ResourceNameIdEntries[j].Id == VS_VERSION_INFO && ResourceNameIdEntries[j].DataIsDirectory) {
|
||||
auto ResourceLangTable =
|
||||
NewImage.RvaToPointer<PIMAGE_RESOURCE_DIRECTORY>(ResourceRva + ResourceNameIdEntries[j].OffsetToDirectory);
|
||||
auto ResourceLangNameEntries =
|
||||
reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY_ENTRY>(ResourceLangTable + 1);
|
||||
auto ResourceLangIdEntries =
|
||||
ResourceLangNameEntries + ResourceLangTable->NumberOfNamedEntries;
|
||||
|
||||
for (WORD k = 0; k < ResourceLangTable->NumberOfIdEntries && !VS_FII_Ok; ++k) {
|
||||
if (ResourceLangIdEntries[k].Id == MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) && !ResourceLangIdEntries[k].DataIsDirectory) {
|
||||
auto ResourceDataEntry =
|
||||
NewImage.RvaToPointer<PIMAGE_RESOURCE_DATA_ENTRY>(ResourceRva + ResourceLangIdEntries[k].OffsetToData);
|
||||
|
||||
auto VsVersionInfo = NewImage.RvaToPointer<PBYTE>(ResourceDataEntry->OffsetToData);
|
||||
auto VsVersionInfoszKey = reinterpret_cast<PWSTR>(VsVersionInfo + 6);
|
||||
if (_wcsicmp(VsVersionInfoszKey, L"VS_VERSION_INFO") == 0) {
|
||||
auto p = reinterpret_cast<PBYTE>(VsVersionInfoszKey + _countof(L"VS_VERSION_INFO"));
|
||||
while (NewImage.PointerToRva(p) % sizeof(DWORD)) {
|
||||
++p;
|
||||
}
|
||||
|
||||
if (reinterpret_cast<VS_FIXEDFILEINFO*>(p)->dwSignature == VS_FFI_SIGNATURE) {
|
||||
NewImage._VsFixedFileInfo = reinterpret_cast<VS_FIXEDFILEINFO*>(p);
|
||||
VS_FII_Ok = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NewImage;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_DOS_HEADER ImageInterpreter::ImageDosHeader() const noexcept {
|
||||
return _DosHeader;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_NT_HEADERS ImageInterpreter::ImageNtHeaders() const noexcept {
|
||||
return _NtHeaders;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionTable() const noexcept {
|
||||
return _SectionHeaderTable;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeader(size_t Idx) const {
|
||||
if (Idx < _NtHeaders->FileHeader.NumberOfSections) {
|
||||
return _SectionHeaderTable + Idx;
|
||||
} else {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Idx is out of range."));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeaderByName(PCSTR lpszSectionName) const {
|
||||
uint64_t NameValue = 0;
|
||||
|
||||
for (int i = 0; i < sizeof(NameValue) && lpszSectionName[i]; ++i)
|
||||
reinterpret_cast<PSTR>(&NameValue)[i] = lpszSectionName[i];
|
||||
|
||||
auto it = _SectionNameTable.find(NameValue);
|
||||
|
||||
if (it == _SectionNameTable.end()) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Target section header is not found."))
|
||||
.AddHint(std::xstring::format(TEXT("lpszSectionName = %s"), lpszSectionName));
|
||||
}
|
||||
|
||||
return &_SectionHeaderTable[it->second];
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeaderByRva(uintptr_t Rva) const {
|
||||
auto it = _SectionRvaTable.upper_bound(Rva);
|
||||
if (it != _SectionRvaTable.begin()) {
|
||||
--it;
|
||||
}
|
||||
|
||||
auto SectionHeader = &_SectionHeaderTable[it->second];
|
||||
uintptr_t SectionRvaBegin = SectionHeader->VirtualAddress;
|
||||
uintptr_t SectionRvaEnd = SectionRvaBegin + SectionHeader->Misc.VirtualSize;
|
||||
|
||||
if (SectionRvaBegin <= Rva && Rva < SectionRvaEnd) {
|
||||
return SectionHeader;
|
||||
} else {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Target section header is not found."))
|
||||
.AddHint(std::xstring::format(TEXT("Rva = 0x%zx"), Rva));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeaderByVa(uintptr_t Va) const {
|
||||
return ImageSectionHeaderByRva(Va - _NtHeaders->OptionalHeader.ImageBase);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeaderByFileOffset(uintptr_t FileOffset) const {
|
||||
auto it = _SectionFileOffsetTable.upper_bound(FileOffset);
|
||||
if (it != _SectionFileOffsetTable.begin()) {
|
||||
--it;
|
||||
}
|
||||
|
||||
auto SectionHeader = &_SectionHeaderTable[it->second];
|
||||
uintptr_t SectionFileOffsetBegin = SectionHeader->PointerToRawData;
|
||||
uintptr_t SectionFileOffsetEnd = SectionFileOffsetBegin + SectionHeader->SizeOfRawData;
|
||||
|
||||
if (SectionFileOffsetBegin <= FileOffset && FileOffset < SectionFileOffsetEnd) {
|
||||
return SectionHeader;
|
||||
} else {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Target section header is not found."))
|
||||
.AddHint(std::xstring::format(TEXT("FileOffset = 0x%zx"), FileOffset));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t ImageInterpreter::RvaToVa(uintptr_t Rva) const noexcept {
|
||||
return Rva + _NtHeaders->OptionalHeader.ImageBase;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t ImageInterpreter::RvaToFileOffset(uintptr_t Rva) const {
|
||||
auto SectionHeader = ImageSectionHeaderByRva(Rva);
|
||||
return SectionHeader->PointerToRawData + (Rva - static_cast<uintptr_t>(SectionHeader->VirtualAddress));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t ImageInterpreter::FileOffsetToRva(uintptr_t FileOffset) const {
|
||||
auto SectionHeader = ImageSectionHeaderByFileOffset(FileOffset);
|
||||
return SectionHeader->VirtualAddress + (FileOffset - SectionHeader->PointerToRawData);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t ImageInterpreter::FileOffsetToVa(uintptr_t FileOffset) const {
|
||||
return FileOffsetToRva(FileOffset) + _NtHeaders->OptionalHeader.ImageBase;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t ImageInterpreter::VaToRva(uintptr_t Va) const noexcept {
|
||||
return Va - _NtHeaders->OptionalHeader.ImageBase;
|
||||
}
|
||||
[[nodiscard]]
|
||||
uintptr_t ImageInterpreter::VaToFileOffset(uintptr_t Va) const {
|
||||
return ImageSectionHeaderByVa(Va)->PointerToRawData;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool ImageInterpreter::IsRvaRangeInRelocTable(uintptr_t Rva, size_t Size) const {
|
||||
auto it = _RelocationRvaTable.upper_bound(Rva);
|
||||
if (it != _RelocationRvaTable.begin()) {
|
||||
--it;
|
||||
}
|
||||
|
||||
return it->first <= Rva && Rva < it->first + it->second;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool ImageInterpreter::IsVaRangeInRelocTable(uintptr_t Va, size_t Size) const {
|
||||
return IsRvaRangeInRelocTable(VaToRva(Va), Size);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool ImageInterpreter::IsFileOffsetRangeInRelocTable(uintptr_t FileOffset, size_t Size) const {
|
||||
return IsRvaRangeInRelocTable(FileOffsetToRva(FileOffset), Size);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
DWORD ImageInterpreter::ImageFileMajorVersion() const {
|
||||
if (_VsFixedFileInfo) {
|
||||
return _VsFixedFileInfo->dwFileVersionMS;
|
||||
} else {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Image does not have version info."));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
DWORD ImageInterpreter::ImageFileMinorVersion() const {
|
||||
if (_VsFixedFileInfo) {
|
||||
return _VsFixedFileInfo->dwFileVersionLS;
|
||||
} else {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Image does not have version info."));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
DWORD ImageInterpreter::ImageProductMajorVersion() const {
|
||||
if (_VsFixedFileInfo) {
|
||||
return _VsFixedFileInfo->dwProductVersionMS;
|
||||
} else {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Image does not have version info."));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
DWORD ImageInterpreter::ImageProductMinorVersion() const {
|
||||
if (_VsFixedFileInfo) {
|
||||
return _VsFixedFileInfo->dwProductVersionLS;
|
||||
} else {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Image does not have version info."));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
size_t ImageInterpreter::NumberOfSections() const noexcept {
|
||||
return _NtHeaders->FileHeader.NumberOfSections;
|
||||
}
|
||||
}
|
||||
|
||||
238
navicat-patcher/ImageInterpreter.hpp
Normal file
238
navicat-patcher/ImageInterpreter.hpp
Normal file
@ -0,0 +1,238 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <Exception.hpp>
|
||||
#include <windows.h>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\ImageInterpreter.hpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class ImageInterpreter {
|
||||
private:
|
||||
|
||||
PIMAGE_DOS_HEADER _DosHeader;
|
||||
PIMAGE_NT_HEADERS _NtHeaders;
|
||||
PIMAGE_SECTION_HEADER _SectionHeaderTable;
|
||||
std::map<uint64_t, size_t> _SectionNameTable;
|
||||
std::map<uintptr_t, size_t> _SectionRvaTable;
|
||||
std::map<uintptr_t, size_t> _SectionFileOffsetTable;
|
||||
std::map<uintptr_t, size_t> _RelocationRvaTable;
|
||||
VS_FIXEDFILEINFO* _VsFixedFileInfo;
|
||||
|
||||
ImageInterpreter();
|
||||
|
||||
public:
|
||||
|
||||
[[nodiscard]]
|
||||
static ImageInterpreter ParseImage(PVOID PtrToImageBase, bool DisableRelocationParsing = false);
|
||||
|
||||
template<typename __PtrType = PVOID>
|
||||
[[nodiscard]]
|
||||
__PtrType ImageBase() const noexcept {
|
||||
static_assert(std::is_pointer_v<__PtrType>);
|
||||
return reinterpret_cast<__PtrType>(_DosHeader);
|
||||
}
|
||||
|
||||
template<typename __PtrType = PVOID>
|
||||
[[nodiscard]]
|
||||
__PtrType ImageOffset(size_t Offset) const noexcept {
|
||||
static_assert(std::is_pointer_v<__PtrType>);
|
||||
return reinterpret_cast<__PtrType>(reinterpret_cast<char*>(_DosHeader) + Offset);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_DOS_HEADER ImageDosHeader() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_NT_HEADERS ImageNtHeaders() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageSectionTable() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageSectionHeader(size_t Idx) const;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageSectionHeaderByName(PCSTR lpszSectionName) const;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageSectionHeaderByRva(uintptr_t Rva) const;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageSectionHeaderByVa(uintptr_t Va) const;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageSectionHeaderByFileOffset(uintptr_t FileOffset) const;
|
||||
|
||||
template<typename __PtrType = PVOID>
|
||||
[[nodiscard]]
|
||||
__PtrType ImageSectionView(PIMAGE_SECTION_HEADER SectionHeader, size_t Offset = 0) const noexcept {
|
||||
return ImageOffset<__PtrType>(SectionHeader->PointerToRawData + Offset);
|
||||
}
|
||||
|
||||
template<typename __PtrType = PVOID>
|
||||
[[nodiscard]]
|
||||
__PtrType ImageSectionViewByName(PCSTR lpszSectionName, size_t Offset = 0) const {
|
||||
return ImageOffset<__PtrType>(ImageSectionHeaderByName(lpszSectionName)->PointerToRawData + Offset);
|
||||
}
|
||||
|
||||
template<typename __PtrType = PVOID>
|
||||
[[nodiscard]]
|
||||
__PtrType ImageSectionViewByRva(uintptr_t Rva, size_t Offset = 0) const {
|
||||
return ImageOffset<__PtrType>(ImageSectionHeaderByRva(Rva)->PointerToRawData + Offset);
|
||||
}
|
||||
|
||||
template<typename __PtrType = PVOID>
|
||||
[[nodiscard]]
|
||||
__PtrType ImageSectionViewByVa(uintptr_t Va, size_t Offset = 0) const {
|
||||
return ImageOffset<__PtrType>(ImageSectionHeaderByVa(Va)->PointerToRawData + Offset);
|
||||
}
|
||||
|
||||
template<typename __PtrType = PVOID>
|
||||
[[nodiscard]]
|
||||
__PtrType ImageSectionViewByFileOffset(uintptr_t FileOffset, size_t Offset = 0) const {
|
||||
return ImageOffset<__PtrType>(ImageSectionHeaderByFileOffset(FileOffset)->PointerToRawData + Offset);
|
||||
}
|
||||
|
||||
template<typename __ReturnType, typename __Hint>
|
||||
[[nodiscard]]
|
||||
__ReturnType SearchSection(PIMAGE_SECTION_HEADER SectionHeader, __Hint&& Hint) const {
|
||||
static_assert(std::is_pointer_v<__ReturnType>);
|
||||
|
||||
auto begin = ImageSectionView<const uint8_t*>(SectionHeader);
|
||||
auto end = begin + SectionHeader->Misc.VirtualSize;
|
||||
|
||||
for (; begin < end; ++begin) {
|
||||
if (Hint(begin) == true) {
|
||||
return reinterpret_cast<__ReturnType>(const_cast<uint8_t*>(begin));
|
||||
}
|
||||
}
|
||||
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Data is not found."));
|
||||
}
|
||||
|
||||
template<typename __ReturnType, typename __Hint>
|
||||
[[nodiscard]]
|
||||
__ReturnType SearchSection(PIMAGE_SECTION_HEADER SectionHeader, size_t Offset, __Hint&& Hint) const {
|
||||
static_assert(std::is_pointer_v<__ReturnType>);
|
||||
|
||||
auto begin = ImageSectionView<const uint8_t*>(SectionHeader) + Offset;
|
||||
auto end = begin + SectionHeader->Misc.VirtualSize;
|
||||
|
||||
for (; begin < end; ++begin) {
|
||||
if (Hint(begin) == true) {
|
||||
return reinterpret_cast<__ReturnType>(const_cast<uint8_t*>(begin));
|
||||
}
|
||||
}
|
||||
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Data is not found."));
|
||||
}
|
||||
|
||||
template<typename __ReturnType, typename __Hint>
|
||||
[[nodiscard]]
|
||||
__ReturnType SearchSection(PCSTR lpszSectionName, __Hint&& Hint) const {
|
||||
return SearchSection<__ReturnType>(ImageSectionHeaderByName(lpszSectionName), std::forward<__Hint>(Hint));
|
||||
}
|
||||
|
||||
template<typename __ReturnType, typename __Hint>
|
||||
[[nodiscard]]
|
||||
__ReturnType SearchSection(PCSTR lpszSectionName, size_t Offset, __Hint&& Hint) const {
|
||||
return SearchSection<__ReturnType>(ImageSectionHeaderByName(lpszSectionName), Offset, std::forward<__Hint>(Hint));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t RvaToVa(uintptr_t Rva) const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t RvaToFileOffset(uintptr_t Rva) const;
|
||||
|
||||
template<typename __PtrType = PVOID>
|
||||
[[nodiscard]]
|
||||
__PtrType RvaToPointer(uintptr_t Rva) const {
|
||||
static_assert(std::is_pointer_v<__PtrType>);
|
||||
return ImageOffset<__PtrType>(RvaToFileOffset(Rva));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t FileOffsetToRva(uintptr_t FileOffset) const;
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t FileOffsetToVa(uintptr_t FileOffset) const;
|
||||
|
||||
template<typename __PtrType>
|
||||
[[nodiscard]]
|
||||
__PtrType FileOffsetToPointer(uintptr_t FileOffset) const noexcept {
|
||||
return ImageOffset<__PtrType>(FileOffset);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t VaToRva(uintptr_t Va) const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t VaToFileOffset(uintptr_t Va) const;
|
||||
|
||||
template<typename __PtrType>
|
||||
[[nodiscard]]
|
||||
__PtrType VaToPointer(uintptr_t Va) const noexcept {
|
||||
return RvaToPointer<__PtrType>(VaToRva(Va));
|
||||
}
|
||||
|
||||
template<typename __PtrType>
|
||||
[[nodiscard]]
|
||||
uintptr_t PointerToFileOffset(__PtrType Ptr) const noexcept {
|
||||
static_assert(std::is_pointer_v<__PtrType>);
|
||||
return reinterpret_cast<const volatile char*>(Ptr) - reinterpret_cast<const volatile char*>(_DosHeader);
|
||||
}
|
||||
|
||||
template<typename __PtrType>
|
||||
[[nodiscard]]
|
||||
uintptr_t PointerToRva(__PtrType Ptr) const {
|
||||
return FileOffsetToRva(PointerToFileOffset(Ptr));
|
||||
}
|
||||
|
||||
template<typename __PtrType>
|
||||
[[nodiscard]]
|
||||
uintptr_t PointerToVa(__PtrType Ptr) const {
|
||||
return FileOffsetToVa(PointerToFileOffset(Ptr));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool IsRvaRangeInRelocTable(uintptr_t Rva, size_t Size) const;
|
||||
|
||||
[[nodiscard]]
|
||||
bool IsVaRangeInRelocTable(uintptr_t Va, size_t Size) const;
|
||||
|
||||
[[nodiscard]]
|
||||
bool IsFileOffsetRangeInRelocTable(uintptr_t FileOffset, size_t Size) const;
|
||||
|
||||
template<typename __PtrType>
|
||||
[[nodiscard]]
|
||||
bool IsFileOffsetRangeInRelocTable(__PtrType Ptr, size_t Size) const {
|
||||
return IsRvaRangeInRelocTable(PointerToRva(Ptr), Size);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
DWORD ImageFileMajorVersion() const;
|
||||
|
||||
[[nodiscard]]
|
||||
DWORD ImageFileMinorVersion() const;
|
||||
|
||||
[[nodiscard]]
|
||||
DWORD ImageProductMajorVersion() const;
|
||||
|
||||
[[nodiscard]]
|
||||
DWORD ImageProductMinorVersion() const;
|
||||
|
||||
[[nodiscard]]
|
||||
size_t NumberOfSections() const noexcept;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
44
navicat-patcher/KeystoneAssembler.cpp
Normal file
44
navicat-patcher/KeystoneAssembler.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "KeystoneAssembler.hpp"
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\KeystoneAssembler.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
KeystoneAssembler::KeystoneAssembler(const KeystoneEngine& Engine) noexcept :
|
||||
_Engine(Engine) {}
|
||||
|
||||
[[nodiscard]]
|
||||
std::vector<uint8_t> KeystoneAssembler::GenerateMachineCode(const char* AssemblyCode, uint64_t Address) const {
|
||||
ResourceOwned pbMachineCode(KeystoneMallocTraits{});
|
||||
size_t cbMachineCode = 0;
|
||||
size_t InstructionsProcessed = 0;
|
||||
|
||||
if (ks_asm(_Engine, AssemblyCode, Address, pbMachineCode.GetAddressOf(), &cbMachineCode, &InstructionsProcessed) != 0) {
|
||||
throw KeystoneError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ks_errno(_Engine), TEXT("ks_asm failed."));
|
||||
}
|
||||
|
||||
return std::vector<uint8_t>(pbMachineCode.Get(), pbMachineCode.Get() + cbMachineCode);
|
||||
}
|
||||
|
||||
KeystoneEngine::KeystoneEngine(ks_arch ArchType, ks_mode Mode) {
|
||||
auto err = ks_open(ArchType, Mode, GetAddressOf());
|
||||
if (err != KS_ERR_OK) {
|
||||
throw KeystoneError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, TEXT("ks_open failed."));
|
||||
}
|
||||
}
|
||||
|
||||
void KeystoneEngine::Option(ks_opt_type Type, ks_opt_value Value) {
|
||||
auto err = ks_option(Get(), Type, Value);
|
||||
if (err != KS_ERR_OK) {
|
||||
throw KeystoneError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, TEXT("ks_option failed."));
|
||||
}
|
||||
}
|
||||
|
||||
KeystoneAssembler KeystoneEngine::CreateAssembler() const {
|
||||
return KeystoneAssembler(*this);
|
||||
}
|
||||
}
|
||||
|
||||
39
navicat-patcher/KeystoneAssembler.hpp
Normal file
39
navicat-patcher/KeystoneAssembler.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include "ExceptionKeystone.hpp"
|
||||
#include <ResourceOwned.hpp>
|
||||
#include "ResourceTraitsKeystone.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class KeystoneEngine;
|
||||
|
||||
class KeystoneAssembler {
|
||||
friend class KeystoneEngine;
|
||||
private:
|
||||
|
||||
const KeystoneEngine& _Engine;
|
||||
|
||||
KeystoneAssembler(const KeystoneEngine& Engine) noexcept;
|
||||
|
||||
public:
|
||||
|
||||
[[nodiscard]]
|
||||
std::vector<uint8_t> GenerateMachineCode(const char* AssemblyCode, uint64_t Address = 0) const;
|
||||
|
||||
};
|
||||
|
||||
class KeystoneEngine : private ResourceOwned<KeystoneHandleTraits> {
|
||||
friend class KeystoneAssembler;
|
||||
public:
|
||||
|
||||
KeystoneEngine(ks_arch ArchType, ks_mode Mode);
|
||||
|
||||
void Option(ks_opt_type Type, ks_opt_value Value);
|
||||
|
||||
[[nodiscard]]
|
||||
KeystoneAssembler CreateAssembler() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
176
navicat-patcher/Misc.cpp
Normal file
176
navicat-patcher/Misc.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <tchar.h>
|
||||
#include <windows.h>
|
||||
#include <ExceptionWin32.hpp>
|
||||
#include <xstring.hpp>
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\Misc.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
template<typename __Type>
|
||||
static inline bool ProbeForRead(const void* p, void* out) {
|
||||
__try {
|
||||
*reinterpret_cast<__Type*>(out) = *reinterpret_cast<const __Type*>(p);
|
||||
return true;
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Print memory data in [lpMemBegin, lpMemEnd)
|
||||
// If `base` is not nullptr, print address as offset. Otherwise, as absolute address.
|
||||
// NOTICE:
|
||||
// `base` must >= `from`
|
||||
//
|
||||
void PrintMemory(const void* lpMemBegin, const void* lpMemEnd, const void* lpBase) noexcept {
|
||||
auto pbBegin = reinterpret_cast<const uint8_t*>(lpMemBegin);
|
||||
auto pbEnd = reinterpret_cast<const uint8_t*>(lpMemEnd);
|
||||
auto pbBase = reinterpret_cast<const uint8_t*>(lpBase);
|
||||
|
||||
if (pbBegin >= pbEnd)
|
||||
return;
|
||||
|
||||
while (reinterpret_cast<uintptr_t>(pbBegin) % 16)
|
||||
pbBegin--;
|
||||
|
||||
while (reinterpret_cast<uintptr_t>(pbEnd) % 16)
|
||||
pbEnd++;
|
||||
|
||||
while (pbBegin < pbEnd) {
|
||||
uint16_t Values[16] = {};
|
||||
|
||||
if (pbBase) {
|
||||
uintptr_t d = pbBegin >= lpBase ? pbBegin - pbBase : pbBase - pbBegin;
|
||||
if (pbBegin >= lpBase) {
|
||||
_tprintf_s(TEXT("+0x%.*zx "), static_cast<int>(2 * sizeof(void*)), d);
|
||||
} else {
|
||||
_tprintf_s(TEXT("-0x%.*zx "), static_cast<int>(2 * sizeof(void*)), d);
|
||||
}
|
||||
} else {
|
||||
_tprintf_s(TEXT("0x%.*zx "), static_cast<int>(2 * sizeof(void*)), reinterpret_cast<uintptr_t>(pbBegin));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (pbBegin + i < lpMemBegin || pbBegin + i >= lpMemEnd) {
|
||||
_tprintf_s(TEXT(" "));
|
||||
Values[i] = 0xfffe;
|
||||
} else if (ProbeForRead<uint8_t>(pbBegin + i, Values + i)) {
|
||||
_tprintf_s(TEXT("%02x "), Values[i]);
|
||||
} else {
|
||||
_tprintf_s(TEXT("?? "));
|
||||
Values[i] = 0xffff;
|
||||
}
|
||||
}
|
||||
|
||||
_tprintf_s(TEXT(" "));
|
||||
|
||||
for (int i = 0; i < 16; ++i) { // NOLINT
|
||||
if (0x20 <= Values[i] && Values[i] < 0x7f) {
|
||||
_tprintf_s(TEXT("%c"), Values[i]);
|
||||
} else if (Values[i] == 0xfffe) {
|
||||
_tprintf_s(TEXT(" "));
|
||||
} else {
|
||||
_tprintf_s(TEXT("."));
|
||||
}
|
||||
}
|
||||
|
||||
_tprintf_s(TEXT("\n"));
|
||||
|
||||
pbBegin += 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Print memory data in [lpMem, lpMem + cbMem)
|
||||
// If `base` is not nullptr, print address as offset. Otherwise, as absolute address.
|
||||
// NOTICE:
|
||||
// `base` must >= `from`
|
||||
//
|
||||
void PrintMemory(const void* lpMem, size_t cbMem, const void* lpBase) noexcept {
|
||||
PrintMemory(lpMem, reinterpret_cast<const uint8_t*>(lpMem) + cbMem, lpBase);
|
||||
}
|
||||
|
||||
void PrintBytes(const void* lpMemBegin, const void* lpMemEnd) noexcept {
|
||||
auto pbMemBegin = reinterpret_cast<const uint8_t*>(lpMemBegin);
|
||||
auto pbMemEnd = reinterpret_cast<const uint8_t*>(lpMemEnd);
|
||||
|
||||
if (pbMemBegin < pbMemEnd) {
|
||||
uint8_t v;
|
||||
|
||||
if (ProbeForRead<uint8_t>(pbMemBegin, &v)) {
|
||||
_tprintf_s(TEXT("%.2x"), v);
|
||||
} else {
|
||||
_tprintf_s(TEXT("??"));
|
||||
}
|
||||
|
||||
++pbMemBegin;
|
||||
}
|
||||
|
||||
while (pbMemBegin < pbMemEnd) {
|
||||
uint8_t v;
|
||||
|
||||
if (ProbeForRead<uint8_t>(pbMemBegin, &v)) {
|
||||
_tprintf_s(TEXT(" %.2x"), v);
|
||||
} else {
|
||||
_tprintf_s(TEXT(" ??"));
|
||||
}
|
||||
|
||||
++pbMemBegin;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintBytes(const void* lpMem, size_t cbMem) noexcept {
|
||||
PrintBytes(lpMem, reinterpret_cast<const char*>(lpMem) + cbMem);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool IsValidDirectoryPath(PCTSTR lpszDirectoryPath) noexcept {
|
||||
DWORD Attribute = GetFileAttributes(lpszDirectoryPath);
|
||||
return Attribute != INVALID_FILE_ATTRIBUTES && (Attribute & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool IsValidFilePath(PCTSTR lpszFilePath) noexcept {
|
||||
DWORD Attribute = GetFileAttributes(lpszFilePath);
|
||||
return Attribute != INVALID_FILE_ATTRIBUTES && (Attribute & FILE_ATTRIBUTE_DIRECTORY) == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool IsWineEnvironment() noexcept {
|
||||
static bool Checked = false;
|
||||
static bool IsWineEnv = false;
|
||||
|
||||
if (Checked == false) {
|
||||
auto hNtdll = GetModuleHandle(TEXT("ntdll.dll"));
|
||||
IsWineEnv = hNtdll && GetProcAddress(hNtdll, "wine_get_version") != nullptr;
|
||||
Checked = true;
|
||||
}
|
||||
|
||||
return IsWineEnv;
|
||||
}
|
||||
|
||||
std::xstring GetCurrentWorkingDirectory() {
|
||||
std::xstring CurrentDirectory;
|
||||
|
||||
auto s = ::GetCurrentDirectory(0, NULL);
|
||||
if (s == 0) {
|
||||
throw Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("GetCurrentDirectory failed"));
|
||||
}
|
||||
|
||||
CurrentDirectory.resize(static_cast<size_t>(s) - 1);
|
||||
|
||||
s = ::GetCurrentDirectory(s, CurrentDirectory.data());
|
||||
if (s == 0) {
|
||||
throw Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("GetCurrentDirectory failed"));
|
||||
}
|
||||
|
||||
return CurrentDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
74
navicat-patcher/Misc.hpp
Normal file
74
navicat-patcher/Misc.hpp
Normal file
@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
#include <tchar.h>
|
||||
#include <windows.h>
|
||||
#include <type_traits>
|
||||
#include <xstring.hpp>
|
||||
|
||||
#define LOG_SUCCESS(tab, fmt, ...) tab ? _tprintf_s(TEXT("%*c[+] " fmt "\n"), tab, ' ', __VA_ARGS__) : _tprintf_s(TEXT("[+] " fmt "\n"), __VA_ARGS__)
|
||||
#define LOG_FAILURE(tab, fmt, ...) tab ? _tprintf_s(TEXT("%*c[-] " fmt "\n"), tab, ' ', __VA_ARGS__) : _tprintf_s(TEXT("[-] " fmt "\n"), __VA_ARGS__)
|
||||
#define LOG_HINT(tab, fmt, ...) tab ? _tprintf_s(TEXT("%*c[*] " fmt "\n"), tab, ' ', __VA_ARGS__) : _tprintf_s(TEXT("[*] " fmt "\n"), __VA_ARGS__)
|
||||
#define LOG_SELECT(tab, fmt, ...) tab ? _tprintf_s(TEXT("%*c[?] " fmt " "), tab, ' ', __VA_ARGS__) : _tprintf_s(TEXT("[?] " fmt " "), __VA_ARGS__)
|
||||
|
||||
namespace nkg {
|
||||
|
||||
template<size_t __Len>
|
||||
constexpr size_t literal_length(const char (&)[__Len]) noexcept {
|
||||
return __Len - 1;
|
||||
}
|
||||
|
||||
template<typename __PtrType1, typename __PtrType2>
|
||||
constexpr auto address_delta(__PtrType1 p1, __PtrType2 p2) noexcept {
|
||||
static_assert(std::is_pointer_v<__PtrType1>);
|
||||
static_assert(std::is_pointer_v<__PtrType2>);
|
||||
return reinterpret_cast<const volatile char*>(p1) - reinterpret_cast<const volatile char*>(p2);
|
||||
}
|
||||
|
||||
template<typename __PtrType>
|
||||
constexpr __PtrType address_offset(__PtrType p, decltype(static_cast<char*>(nullptr) - static_cast<char*>(nullptr)) offset) noexcept {
|
||||
static_assert(std::is_pointer_v<__PtrType>);
|
||||
return reinterpret_cast<__PtrType>(
|
||||
const_cast<char*>(reinterpret_cast<const volatile char*>(p)) + offset
|
||||
);
|
||||
}
|
||||
|
||||
template<typename __ReturnType, typename __PtrType>
|
||||
constexpr __ReturnType address_offset_cast(__PtrType p, decltype(static_cast<char*>(nullptr) - static_cast<char*>(nullptr)) offset) noexcept {
|
||||
static_assert(std::is_pointer_v<__ReturnType>);
|
||||
static_assert(std::is_pointer_v<__PtrType>);
|
||||
return reinterpret_cast<__ReturnType>(
|
||||
const_cast<char*>(reinterpret_cast<const volatile char*>(p)) + offset
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Print memory data in [lpMemBegin, lpMemEnd)
|
||||
// If `base` is not nullptr, print address as offset. Otherwise, as absolute address.
|
||||
// NOTICE:
|
||||
// `base` must >= `from`
|
||||
//
|
||||
void PrintMemory(const void* lpMemBegin, const void* lpMemEnd, const void* lpBase) noexcept;
|
||||
|
||||
//
|
||||
// Print memory data in [lpMem, lpMem + cbMem)
|
||||
// If `base` is not nullptr, print address as offset. Otherwise, as absolute address.
|
||||
// NOTICE:
|
||||
// `base` must >= `from`
|
||||
//
|
||||
void PrintMemory(const void* lpMem, size_t cbMem, const void* lpBase) noexcept;
|
||||
|
||||
void PrintBytes(const void* lpMemBegin, const void* lpMemEnd) noexcept;
|
||||
void PrintBytes(const void* lpMem, size_t cbMem) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
bool IsValidDirectoryPath(PCTSTR lpszDirectoryPath) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
bool IsValidFilePath(PCTSTR lpszFilePath) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
bool IsWineEnvironment() noexcept;
|
||||
|
||||
std::xstring GetCurrentWorkingDirectory();
|
||||
}
|
||||
|
||||
217
navicat-patcher/NavicatCrypto.hpp
Normal file
217
navicat-patcher/NavicatCrypto.hpp
Normal file
@ -0,0 +1,217 @@
|
||||
#pragma once
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/blowfish.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
class Navicat11Crypto {
|
||||
protected:
|
||||
using BlockType = uint8_t[BF_BLOCK];
|
||||
|
||||
BF_KEY _BlowfishKey;
|
||||
|
||||
template<bool __UpperCase = true>
|
||||
static void _BytesToHex(const void* src, size_t len, char* dst) noexcept {
|
||||
auto pb_src = reinterpret_cast<const uint8_t*>(src);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
char h = pb_src[i] >> 4;
|
||||
char l = pb_src[i] & 0x0F;
|
||||
|
||||
if constexpr (__UpperCase) {
|
||||
h += h >= 10 ? 'A' - 10 : '0';
|
||||
l += l >= 10 ? 'A' - 10 : '0';
|
||||
} else {
|
||||
h += h >= 10 ? 'a' - 10 : '0';
|
||||
l += l >= 10 ? 'a' - 10 : '0';
|
||||
}
|
||||
|
||||
dst[2 * i] = h;
|
||||
dst[2 * i + 1] = l;
|
||||
}
|
||||
}
|
||||
|
||||
static void _HexToBytes(const char* src, size_t len, void* dst) {
|
||||
auto pb_dst = reinterpret_cast<uint8_t*>(dst);
|
||||
for (size_t i = 0; i < len; i += 2) {
|
||||
uint8_t h = src[i];
|
||||
uint8_t l = src[i + 1];
|
||||
|
||||
if ('0' <= h && h <= '9') {
|
||||
h -= '0';
|
||||
} else if ('A' <= h && h <= 'F') {
|
||||
h -= 'A';
|
||||
} else if ('a' <= h && h <= 'f') {
|
||||
h -= 'a';
|
||||
} else {
|
||||
throw std::invalid_argument("Non-hex character detected.");
|
||||
}
|
||||
|
||||
if ('0' <= l && l <= '9') {
|
||||
l -= '0';
|
||||
} else if ('A' <= l && l <= 'F') {
|
||||
l -= 'A';
|
||||
} else if ('a' <= l && l <= 'f') {
|
||||
l -= 'a';
|
||||
} else {
|
||||
throw std::invalid_argument("Non-hex character detected.");
|
||||
}
|
||||
|
||||
pb_dst[i / 2] = (h << 4) ^ l;
|
||||
}
|
||||
}
|
||||
|
||||
static void _XorBlock(BlockType& a, const BlockType& b) noexcept {
|
||||
reinterpret_cast<uint64_t&>(a) ^= reinterpret_cast<const uint64_t&>(b);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::string _EncryptString(const void* lpPlaintext, size_t cbPlaintext) const {
|
||||
std::string Ciphertext;
|
||||
|
||||
if (cbPlaintext) {
|
||||
Ciphertext.resize(2 * cbPlaintext);
|
||||
|
||||
alignas(sizeof(BlockType)) BlockType CV = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
alignas(sizeof(BlockType)) BlockType Block;
|
||||
auto lpPlaintextBlock = reinterpret_cast<const uint8_t*>(lpPlaintext);
|
||||
auto lpCiphertextHexBlock = Ciphertext.data();
|
||||
auto BlockCount = cbPlaintext / BF_BLOCK;
|
||||
|
||||
BF_ecb_encrypt(CV, CV, &_BlowfishKey, BF_ENCRYPT);
|
||||
|
||||
for (size_t i = 0; i < BlockCount; ++i, lpPlaintextBlock += sizeof(BlockType), lpCiphertextHexBlock += 2 * sizeof(BlockType)) {
|
||||
memcpy(Block, lpPlaintextBlock, sizeof(BlockType));
|
||||
|
||||
_XorBlock(Block, CV);
|
||||
BF_ecb_encrypt(Block, Block, &_BlowfishKey, BF_ENCRYPT);
|
||||
_XorBlock(CV, Block);
|
||||
|
||||
_BytesToHex(Block, sizeof(Block), lpCiphertextHexBlock);
|
||||
}
|
||||
|
||||
auto LeftByteCount = cbPlaintext % sizeof(BlockType);
|
||||
if (LeftByteCount) {
|
||||
BF_ecb_encrypt(CV, CV, &_BlowfishKey, BF_ENCRYPT);
|
||||
|
||||
for (size_t i = 0; i < LeftByteCount; ++i) {
|
||||
CV[i] ^= lpPlaintextBlock[i];
|
||||
}
|
||||
|
||||
_BytesToHex(CV, LeftByteCount, lpCiphertextHexBlock);
|
||||
}
|
||||
}
|
||||
|
||||
return Ciphertext;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::string _DecryptString(const char* lpCiphertext, size_t cbCiphertext) const {
|
||||
std::string Plaintext;
|
||||
|
||||
if (cbCiphertext) {
|
||||
if (cbCiphertext % 2) {
|
||||
throw std::invalid_argument("Ciphertext is not a hex string.");
|
||||
}
|
||||
|
||||
Plaintext.resize(cbCiphertext / 2);
|
||||
|
||||
alignas(sizeof(BlockType)) BlockType CV = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
alignas(sizeof(BlockType)) BlockType Block;
|
||||
auto lpPlaintextBlock = Plaintext.data();
|
||||
auto lpCiphertextHexBlock = lpCiphertext;
|
||||
auto BlockCount = cbCiphertext / (2 * sizeof(BlockType));
|
||||
|
||||
BF_ecb_encrypt(CV, CV, &_BlowfishKey, BF_ENCRYPT);
|
||||
|
||||
for (size_t i = 0; i < BlockCount; ++i, lpPlaintextBlock += sizeof(BlockType), lpCiphertextHexBlock += 2 * sizeof(BlockType)) {
|
||||
alignas(sizeof(BlockType)) BlockType CiphertextBlock;
|
||||
|
||||
_HexToBytes(lpCiphertextHexBlock, 2 * sizeof(BlockType), CiphertextBlock);
|
||||
memcpy(Block, CiphertextBlock, sizeof(BlockType));
|
||||
|
||||
BF_ecb_encrypt(Block, Block, &_BlowfishKey, BF_DECRYPT);
|
||||
_XorBlock(Block, CV);
|
||||
_XorBlock(CV, CiphertextBlock);
|
||||
|
||||
memcpy(lpPlaintextBlock, Block, sizeof(BlockType));
|
||||
}
|
||||
|
||||
auto LeftHexCount = cbCiphertext % (2 * sizeof(BlockType));
|
||||
if (LeftHexCount) {
|
||||
_HexToBytes(lpCiphertextHexBlock, LeftHexCount, Block);
|
||||
|
||||
BF_ecb_encrypt(CV, CV, &_BlowfishKey, BF_ENCRYPT);
|
||||
|
||||
for (size_t i = 0; i < LeftHexCount / 2; ++i) {
|
||||
lpPlaintextBlock[i] = Block[i] ^ CV[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Plaintext;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Navicat11Crypto() noexcept {
|
||||
static const uint8_t PresetKey[SHA_DIGEST_LENGTH] = {
|
||||
0x42, 0xCE, 0xB2, 0x71, 0xA5, 0xE4, 0x58, 0xB7,
|
||||
0x4A, 0xEA, 0x93, 0x94, 0x79, 0x22, 0x35, 0x43,
|
||||
0x91, 0x87, 0x33, 0x40
|
||||
};
|
||||
|
||||
BF_set_key(&_BlowfishKey, sizeof(PresetKey), PresetKey);
|
||||
}
|
||||
|
||||
Navicat11Crypto(const void* lpUserKey, size_t cbUserKey) noexcept {
|
||||
SetKey(lpUserKey, cbUserKey);
|
||||
}
|
||||
|
||||
Navicat11Crypto(const std::initializer_list<uint8_t>& UserKey) noexcept {
|
||||
SetKey(UserKey);
|
||||
}
|
||||
|
||||
void SetKey(const void* lpUserKey, size_t cbUserKey) noexcept {
|
||||
uint8_t MessageDigest[SHA_DIGEST_LENGTH];
|
||||
|
||||
BF_set_key(
|
||||
&_BlowfishKey,
|
||||
sizeof(MessageDigest),
|
||||
SHA1(reinterpret_cast<const uint8_t*>(lpUserKey), cbUserKey, MessageDigest)
|
||||
);
|
||||
|
||||
OPENSSL_cleanse(MessageDigest, SHA_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
void SetKey(const std::initializer_list<uint8_t>& UserKey) noexcept {
|
||||
uint8_t MessageDigest[SHA_DIGEST_LENGTH];
|
||||
|
||||
BF_set_key(
|
||||
&_BlowfishKey,
|
||||
sizeof(MessageDigest),
|
||||
SHA1(UserKey.begin(), UserKey.size(), MessageDigest)
|
||||
);
|
||||
|
||||
OPENSSL_cleanse(MessageDigest, SHA_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::string EncryptString(const std::string& Plaintext) const {
|
||||
return _EncryptString(Plaintext.c_str(), Plaintext.length());
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::string DecryptString(const std::string& Ciphertext) const {
|
||||
return _DecryptString(Ciphertext.c_str(), Ciphertext.length());
|
||||
}
|
||||
|
||||
void Clear() noexcept {
|
||||
OPENSSL_cleanse(&_BlowfishKey, sizeof(_BlowfishKey));
|
||||
}
|
||||
|
||||
~Navicat11Crypto() noexcept {
|
||||
Clear();
|
||||
}
|
||||
};
|
||||
|
||||
82
navicat-patcher/PatchSolution0.cpp
Normal file
82
navicat-patcher/PatchSolution0.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
#include "PatchSolutions.hpp"
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\PatchSolution0.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
const char PatchSolution0::Keyword[461] =
|
||||
"-----BEGIN PUBLIC KEY-----\r\n"
|
||||
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I\r\n"
|
||||
"qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv\r\n"
|
||||
"a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF\r\n"
|
||||
"R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2\r\n"
|
||||
"WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt\r\n"
|
||||
"YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ\r\n"
|
||||
"awIDAQAB\r\n"
|
||||
"-----END PUBLIC KEY-----\r\n";
|
||||
|
||||
[[nodiscard]]
|
||||
bool PatchSolution0::FindPatchOffset() noexcept {
|
||||
try {
|
||||
_PatchOffset = _Image.PointerToFileOffset(
|
||||
_Image.SearchSection<uint8_t*>(".rsrc", [](const uint8_t* p) {
|
||||
__try {
|
||||
return memcmp(p, Keyword, literal_length(Keyword)) == 0;
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
LOG_SUCCESS(0, "PatchSolution0 ...... Ready to apply");
|
||||
LOG_HINT(4, "Patch offset = +0x%.8zx", _PatchOffset);
|
||||
|
||||
return true;
|
||||
} catch (nkg::Exception&) {
|
||||
_PatchOffset = InvalidOffset;
|
||||
|
||||
LOG_FAILURE(0, "PatchSolution0 ...... Omitted");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool PatchSolution0::CheckKey(const RSACipher& Cipher) const noexcept {
|
||||
auto szPublicKey = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
||||
for (auto i = szPublicKey.find("\n"); i != std::string::npos; i = szPublicKey.find("\n", i + 2)) {
|
||||
szPublicKey.replace(i, 1, "\r\n");
|
||||
}
|
||||
|
||||
return szPublicKey.length() == literal_length(Keyword);
|
||||
}
|
||||
|
||||
void PatchSolution0::MakePatch(const RSACipher& Cipher) const {
|
||||
if (_PatchOffset == InvalidOffset) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("PatchSolution0 has not been ready yet."));
|
||||
}
|
||||
|
||||
auto szPublicKey = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
||||
for (auto i = szPublicKey.find("\n"); i != std::string::npos; i = szPublicKey.find("\n", i + 2)) {
|
||||
szPublicKey.replace(i, 1, "\r\n");
|
||||
}
|
||||
|
||||
_putts(TEXT("*******************************************************"));
|
||||
_putts(TEXT("* PatchSolution0 *"));
|
||||
_putts(TEXT("*******************************************************"));
|
||||
|
||||
LOG_HINT(0, "Previous:");
|
||||
PrintMemory(_Image.ImageOffset(_PatchOffset), literal_length(Keyword), _Image.ImageBase());
|
||||
|
||||
memcpy(_Image.ImageOffset(_PatchOffset), szPublicKey.c_str(), literal_length(Keyword));
|
||||
|
||||
LOG_HINT(0, "After:");
|
||||
PrintMemory(_Image.ImageOffset(_PatchOffset), literal_length(Keyword), _Image.ImageBase());
|
||||
|
||||
_putts(TEXT(""));
|
||||
}
|
||||
}
|
||||
|
||||
308
navicat-patcher/PatchSolution1.cpp
Normal file
308
navicat-patcher/PatchSolution1.cpp
Normal file
@ -0,0 +1,308 @@
|
||||
#include "PatchSolutions.hpp"
|
||||
#include "NavicatCrypto.hpp"
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\PatchSolution1.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
static Navicat11Crypto g_NavicatCipher = Navicat11Crypto("23970790", 8);
|
||||
|
||||
const char PatchSolution1::Keyword0[160 + 1] =
|
||||
"D75125B70767B94145B47C1CB3C0755E"
|
||||
"7CCB8825C5DCE0C58ACF944E08280140"
|
||||
"9A02472FAFFD1CD77864BB821AE36766"
|
||||
"FEEDE6A24F12662954168BFA314BD950"
|
||||
"32B9D82445355ED7BC0B880887D650F5";
|
||||
|
||||
const char PatchSolution1::Keyword1[4 + 1] =
|
||||
"\xfe\xea\xbc\x01";
|
||||
|
||||
const char PatchSolution1::Keyword2[742 + 1] =
|
||||
"E1CED09B9C2186BF71A70C0FE2F1E0AE"
|
||||
"F3BD6B75277AAB20DFAF3D110F75912B"
|
||||
"FB63AC50EC4C48689D1502715243A79F"
|
||||
"39FF2DE2BF15CE438FF885745ED54573"
|
||||
"850E8A9F40EE2FF505EB7476F95ADB78"
|
||||
"3B28CA374FAC4632892AB82FB3BF4715"
|
||||
"FCFE6E82D03731FC3762B6AAC3DF1C3B"
|
||||
"C646FE9CD3C62663A97EE72DB932A301"
|
||||
"312B4A7633100C8CC357262C39A2B3A6"
|
||||
"4B224F5276D5EDBDF0804DC3AC4B8351"
|
||||
"62BB1969EAEBADC43D2511D6E0239287"
|
||||
"81B167A48273B953378D3D2080CC0677"
|
||||
"7E8A2364F0234B81064C5C739A8DA28D"
|
||||
"C5889072BF37685CBC94C2D31D0179AD"
|
||||
"86D8E3AA8090D4F0B281BE37E0143746"
|
||||
"E6049CCC06899401264FA471C016A96C"
|
||||
"79815B55BBC26B43052609D9D175FBCD"
|
||||
"E455392F10E51EC162F51CF732E6BB39"
|
||||
"1F56BBFD8D957DF3D4C55B71CEFD54B1"
|
||||
"9C16D458757373E698D7E693A8FC3981"
|
||||
"5A8BF03BA05EA8C8778D38F9873D62B4"
|
||||
"460F41ACF997C30E7C3AF025FA171B5F"
|
||||
"5AD4D6B15E95C27F6B35AD61875E5505"
|
||||
"449B4E";
|
||||
|
||||
const char PatchSolution1::Keyword3[4 + 1] =
|
||||
"\x59\x08\x01\x00";
|
||||
|
||||
const char PatchSolution1::Keyword4[5 + 1] =
|
||||
"92933";
|
||||
|
||||
[[nodiscard]]
|
||||
bool PatchSolution1::FindPatchOffset() noexcept {
|
||||
try {
|
||||
PIMAGE_SECTION_HEADER SectionHeader_text = _Image.ImageSectionHeaderByName(".text");
|
||||
PIMAGE_SECTION_HEADER SectionHeader_rdata = _Image.ImageSectionHeaderByName(".rdata");
|
||||
const uint8_t* pbPatch[_countof(_PatchOffset)] = {};
|
||||
|
||||
pbPatch[0] = _Image.SearchSection<const uint8_t*>(SectionHeader_rdata, [](const uint8_t* p) {
|
||||
__try {
|
||||
return memcmp(p, Keyword0, sizeof(Keyword0)) == 0;
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
pbPatch[2] = _Image.SearchSection<const uint8_t*>(SectionHeader_rdata, [](const uint8_t* p) {
|
||||
__try {
|
||||
return memcmp(p, Keyword2, sizeof(Keyword2)) == 0;
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
pbPatch[4] = _Image.SearchSection<const uint8_t*>(SectionHeader_rdata, [](const uint8_t* p) {
|
||||
__try {
|
||||
return memcmp(p, Keyword4, sizeof(Keyword4)) == 0;
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
pbPatch[1] = _Image.SearchSection<const uint8_t*>(SectionHeader_text, [&pbPatch](const uint8_t* p) {
|
||||
__try {
|
||||
if (memcmp(p, Keyword1, literal_length(Keyword1)) == 0) {
|
||||
// Keyword3 must be close to Keyword1
|
||||
for (auto j = p - 64; j < p + 64; ++j) {
|
||||
if (memcmp(j, Keyword3, literal_length(Keyword3)) == 0) {
|
||||
pbPatch[3] = j;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
for (size_t i = 0; i < _countof(_PatchOffset); ++i) {
|
||||
_PatchOffset[i] = _Image.PointerToFileOffset(pbPatch[i]);
|
||||
}
|
||||
|
||||
_PatchSize[0] = literal_length(Keyword0);
|
||||
while (pbPatch[0][_PatchSize[0] + 1] == 0 && _PatchSize[0] < literal_length(Keyword0) + literal_length("29158142") - 1) {
|
||||
++_PatchSize[0];
|
||||
}
|
||||
|
||||
_PatchSize[1] = sizeof(uint32_t);
|
||||
|
||||
_PatchSize[2] = literal_length(Keyword2);
|
||||
while (pbPatch[2][_PatchSize[2] + 1] == 0 && _PatchSize[2] < literal_length(Keyword2) + literal_length("67673") - 1) {
|
||||
++_PatchSize[2];
|
||||
}
|
||||
|
||||
_PatchSize[3] = sizeof(uint32_t);
|
||||
|
||||
_PatchSize[4] = literal_length(Keyword4);
|
||||
|
||||
LOG_SUCCESS(0, "PatchSolution1 ...... Ready to apply");
|
||||
LOG_HINT(4, "[0] Patch offset = +0x%.8zx", _PatchOffset[0]);
|
||||
LOG_HINT(4, "[1] Patch offset = +0x%.8zx", _PatchOffset[1]);
|
||||
LOG_HINT(4, "[2] Patch offset = +0x%.8zx", _PatchOffset[2]);
|
||||
LOG_HINT(4, "[3] Patch offset = +0x%.8zx", _PatchOffset[3]);
|
||||
LOG_HINT(4, "[4] Patch offset = +0x%.8zx", _PatchOffset[4]);
|
||||
|
||||
return true;
|
||||
} catch (nkg::Exception&) {
|
||||
for (size_t i = 0; i < _countof(_PatchOffset); ++i) {
|
||||
_PatchOffset[i] = InvalidOffset;
|
||||
_PatchSize[i] = 0;
|
||||
}
|
||||
|
||||
LOG_FAILURE(0, "PatchSolution1 ...... Omitted");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool PatchSolution1::CheckKey(const RSACipher& Cipher) const noexcept {
|
||||
if (_PatchSize[0] && _PatchSize[1] && _PatchSize[2] && _PatchSize[3] && _PatchSize[4]) {
|
||||
auto szPublicKey = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
||||
for (auto i = szPublicKey.find("\n"); i != std::string::npos; i = szPublicKey.find("\n", i + 2)) {
|
||||
szPublicKey.replace(i, 1, "\r\n");
|
||||
}
|
||||
|
||||
auto szPublicKeyEncrypted = g_NavicatCipher.EncryptString(szPublicKey);
|
||||
|
||||
if (szPublicKeyEncrypted.length() != 920) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// we require the chars in [p1, p2) of szPublicKeyEncrypted must be number chars
|
||||
size_t p1, p2;
|
||||
|
||||
p1 = _PatchSize[0];
|
||||
p2 = literal_length(Keyword0) + literal_length("29158142");
|
||||
|
||||
if (('1' <= szPublicKeyEncrypted[p1] && szPublicKeyEncrypted[p1] <= '9') == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = p1 + 1; i < p2; ++i) {
|
||||
if (('0' <= szPublicKeyEncrypted[i] && szPublicKeyEncrypted[i] <= '9') == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// we require the chars in [p1, p2) of szPublicKeyEncrypted must be number chars
|
||||
|
||||
p1 = literal_length(Keyword0) + literal_length("29158142") + _PatchSize[2];
|
||||
p2 = literal_length(Keyword0) + literal_length("29158142") + literal_length(Keyword2) + literal_length("67673");
|
||||
|
||||
if (('1' <= szPublicKeyEncrypted[p1] && szPublicKeyEncrypted[p1] <= '9') == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = p1 + 1; i < p2; ++i) {
|
||||
if (('0' <= szPublicKeyEncrypted[i] && szPublicKeyEncrypted[i] <= '9') == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void PatchSolution1::MakePatch(const RSACipher& Cipher) const {
|
||||
if (_PatchSize[0] && _PatchSize[1] && _PatchSize[2] && _PatchSize[3] && _PatchSize[4]) {
|
||||
auto szPublicKey = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
||||
for (auto i = szPublicKey.find("\n"); i != std::string::npos; i = szPublicKey.find("\n", i + 2)) {
|
||||
szPublicKey.replace(i, 1, "\r\n");
|
||||
}
|
||||
|
||||
auto szPublicKeyEncrypted = g_NavicatCipher.EncryptString(szPublicKey);
|
||||
|
||||
//
|
||||
// p0 p1 p2 p3 p4 p5
|
||||
// Original encrypted public key layout: |160 chars|8 chars|742 chars|5 chars|5 chars|
|
||||
// | |
|
||||
// V V
|
||||
// ImmValue1 ImmValue3
|
||||
size_t p0, p1, p2, p3, p4, p5;
|
||||
p0 = 0;
|
||||
p1 = _PatchSize[0];
|
||||
p2 = literal_length(Keyword0) + literal_length("29158142");
|
||||
p3 = literal_length(Keyword0) + literal_length("29158142") + _PatchSize[2];
|
||||
p4 = literal_length(Keyword0) + literal_length("29158142") + literal_length(Keyword2) + literal_length("67673");
|
||||
p5 = literal_length(Keyword0) + literal_length("29158142") + literal_length(Keyword2) + literal_length("67673") + literal_length(Keyword4);
|
||||
|
||||
if (szPublicKeyEncrypted.length() != 920) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("szPublicKeyEncrypted.length() != 920"));
|
||||
}
|
||||
|
||||
std::string EncryptedPEM0(szPublicKeyEncrypted.begin() + p0, szPublicKeyEncrypted.begin() + p1);
|
||||
std::string EncryptedPEM1(szPublicKeyEncrypted.begin() + p1, szPublicKeyEncrypted.begin() + p2);
|
||||
std::string EncryptedPEM2(szPublicKeyEncrypted.begin() + p2, szPublicKeyEncrypted.begin() + p3);
|
||||
std::string EncryptedPEM3(szPublicKeyEncrypted.begin() + p3, szPublicKeyEncrypted.begin() + p4);
|
||||
std::string EncryptedPEM4(szPublicKeyEncrypted.begin() + p4, szPublicKeyEncrypted.begin() + p5);
|
||||
uint32_t ImmValue1 = std::stoul(EncryptedPEM1.c_str());
|
||||
uint32_t ImmValue3 = std::stoul(EncryptedPEM3.c_str());
|
||||
|
||||
uint8_t* pbPatch[_countof(_PatchOffset)] = {};
|
||||
for (size_t i = 0; i < _countof(_PatchOffset); ++i) {
|
||||
pbPatch[i] = _Image.FileOffsetToPointer<uint8_t*>(_PatchOffset[i]);
|
||||
}
|
||||
|
||||
_putts(TEXT("*******************************************************"));
|
||||
_putts(TEXT("* PatchSolution1 *"));
|
||||
_putts(TEXT("*******************************************************"));
|
||||
|
||||
// ----------------------------------
|
||||
// process PatchOffsets[0]
|
||||
// ----------------------------------
|
||||
LOG_HINT(0, "Previous:");
|
||||
PrintMemory(pbPatch[0], _PatchSize[0], _Image.ImageBase());
|
||||
|
||||
memcpy(pbPatch[0], EncryptedPEM0.data(), _PatchSize[0]);
|
||||
|
||||
LOG_HINT(0, "After:");
|
||||
PrintMemory(pbPatch[0], _PatchSize[0], _Image.ImageBase());
|
||||
|
||||
_putts(TEXT(""));
|
||||
|
||||
// ----------------------------------
|
||||
// process PatchOffsets[1]
|
||||
// ----------------------------------
|
||||
LOG_HINT(0, "Previous:");
|
||||
PrintMemory(pbPatch[1], _PatchSize[1], _Image.ImageBase());
|
||||
|
||||
memcpy(pbPatch[1], &ImmValue1, _PatchSize[1]);
|
||||
|
||||
LOG_HINT(0, "After:");
|
||||
PrintMemory(pbPatch[1], _PatchSize[1], _Image.ImageBase());
|
||||
|
||||
_putts(TEXT(""));
|
||||
|
||||
// ----------------------------------
|
||||
// process PatchOffsets[2]
|
||||
// ----------------------------------
|
||||
LOG_HINT(0, "Previous:");
|
||||
PrintMemory(pbPatch[2], _PatchSize[2], _Image.ImageBase());
|
||||
|
||||
memcpy(pbPatch[2], EncryptedPEM2.data(), _PatchSize[2]);
|
||||
|
||||
LOG_HINT(0, "After:");
|
||||
PrintMemory(pbPatch[2], _PatchSize[2], _Image.ImageBase());
|
||||
|
||||
_putts(TEXT(""));
|
||||
|
||||
// ----------------------------------
|
||||
// process PatchOffsets[3]
|
||||
// ----------------------------------
|
||||
LOG_HINT(0, "Previous:");
|
||||
PrintMemory(pbPatch[3], _PatchSize[3], _Image.ImageBase());
|
||||
|
||||
memcpy(pbPatch[3], &ImmValue3, _PatchSize[3]);
|
||||
|
||||
LOG_HINT(0, "After:");
|
||||
PrintMemory(pbPatch[3], _PatchSize[3], _Image.ImageBase());
|
||||
|
||||
_putts(TEXT(""));
|
||||
|
||||
// ----------------------------------
|
||||
// process PatchOffsets[4]
|
||||
// ----------------------------------
|
||||
LOG_HINT(0, "Previous:");
|
||||
PrintMemory(pbPatch[4], _PatchSize[4], _Image.ImageBase());
|
||||
|
||||
memcpy(pbPatch[4], EncryptedPEM4.data(), _PatchSize[4]);
|
||||
|
||||
LOG_HINT(0, "After:");
|
||||
PrintMemory(pbPatch[4], _PatchSize[4], _Image.ImageBase());
|
||||
|
||||
_putts(TEXT(""));
|
||||
} else {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("PatchSolution1 has not been ready yet."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
511
navicat-patcher/PatchSolution2-amd64.cpp
Normal file
511
navicat-patcher/PatchSolution2-amd64.cpp
Normal file
@ -0,0 +1,511 @@
|
||||
#include "PatchSolutions.hpp"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\PatchSolution2-amd64.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
/*
|
||||
Keyword[0x188][5] is generated by the following python script:
|
||||
|
||||
-----Begin Python3 Script-----
|
||||
meta = \
|
||||
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I" \
|
||||
"qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv" \
|
||||
"a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF" \
|
||||
"R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2" \
|
||||
"WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt" \
|
||||
"YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ" \
|
||||
"awIDAQAB"
|
||||
|
||||
print('const uint8_t PatchSolution2::Keyword[0x188][5] = {')
|
||||
for i in range(0, len(meta)):
|
||||
i1 = '0x83, 0xf0, 0x%.2x' % ord(meta[i]) # asm('xor eax, meta[i]')
|
||||
i2 = '0x88, 0x05' # asm_prefix('mov byte ptr ds:xxxxxxxxxxxxxxxx, al')
|
||||
print(' { %s, %s }' % (i1, i2), end = ',\n' if i != len(meta) - 1 else '\n')
|
||||
print('};')
|
||||
-----End Python3 Script-----
|
||||
|
||||
*/
|
||||
const uint8_t PatchSolution2::Keyword[0x188][5] = {
|
||||
{ 0x83, 0xf0, 0x4d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x49, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x49, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x42, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x49, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4e, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x42, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x67, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6b, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x71, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x68, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6b, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x69, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x47, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x39, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x77, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x30, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x42, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x51, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x45, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x46, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4f, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x43, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x51, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x38, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x49, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x49, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x42, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x43, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x67, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4b, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x43, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x51, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x45, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x77, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x31, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x64, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x71, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x46, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x33, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x53, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6b, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x43, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x61, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x7a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x73, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x38, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x38, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x39, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x49, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x71, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x64, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x57, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x39, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x32, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x64, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x49, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x64, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x68, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x33, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x47, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x39, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x79, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x50, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x63, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4c, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6e, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x69, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x47, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x70, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x42, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x46, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x34, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x45, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x39, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x56, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x48, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x53, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x47, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x65, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x38, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6f, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x50, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x79, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x32, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6b, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x44, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x64, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4e, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x74, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x34, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x42, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x63, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x45, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x79, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x67, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x76, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x73, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x73, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x45, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x66, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x67, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x69, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6e, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x76, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x61, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x35, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x74, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x35, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x33, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x35, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x32, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x55, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6f, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x44, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6f, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x73, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x55, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6b, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x54, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x58, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x47, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x51, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x68, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x70, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x57, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x46, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x34, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x66, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x42, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x42, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x70, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4f, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x33, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x45, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x65, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x64, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x47, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x36, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x32, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x72, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4f, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x73, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x71, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x42, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x67, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x53, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x64, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x79, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x78, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x43, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x53, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x50, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x42, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x52, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x49, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4f, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x46, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x52, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x30, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x51, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x67, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x5a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x46, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x62, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x52, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6e, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x55, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x30, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x66, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x72, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x33, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x34, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x66, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x69, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x56, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x67, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x59, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x69, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4c, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x75, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x5a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x53, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x49, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x62, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x73, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x38, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x5a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x78, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x69, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x48, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x50, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x64, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x70, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x31, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6f, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x44, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x34, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x74, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x55, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x70, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x76, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x73, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x46, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x63, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x69, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x34, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x51, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x74, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x59, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4e, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4e, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6e, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x47, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x55, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x32, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x57, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x50, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x48, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x36, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x72, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x76, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x43, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x68, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x47, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6c, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x31, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x49, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x52, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4b, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x72, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x78, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x74, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x71, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4c, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x69, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x65, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6c, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x73, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x76, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x61, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x55, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x79, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x72, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x67, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4f, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x43, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x36, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4e, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x79, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x59, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x76, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x5a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4e, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x45, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x52, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x33, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x68, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x74, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x46, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x45, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x74, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4c, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x31, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x65, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x51, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x62, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x43, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x79, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x54, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x66, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x44, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x74, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x59, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x79, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x51, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x31, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x57, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x74, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x34, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4f, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x74, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x31, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x32, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6c, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x78, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x66, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x30, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x77, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x56, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x49, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x52, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x35, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x63, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x47, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4e, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x37, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x58, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x43, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x58, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x52, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x48, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x4f, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x46, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x48, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x53, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x66, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x31, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x67, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x7a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x58, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x57, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x61, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x62, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x52, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x53, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x76, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6d, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x74, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x31, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6e, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x72, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6c, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x37, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x73, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x57, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x36, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x63, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x78, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6c, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x6a, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x75, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x75, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x51, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x61, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x77, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x49, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x44, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x51, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x41, 0x88, 0x05 },
|
||||
{ 0x83, 0xf0, 0x42, 0x88, 0x05 }
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
bool PatchSolution2::FindPatchOffset() noexcept {
|
||||
try {
|
||||
auto SectionHeader_text = _Image.ImageSectionHeaderByName(".text");
|
||||
auto SectionView_text = _Image.ImageSectionView<const uint8_t*>(SectionHeader_text);
|
||||
const uint8_t* lpPatch[_countof(_PatchOffset)] = {};
|
||||
|
||||
std::vector<size_t> Hints;
|
||||
DWORD PossibleRangeStart = 0xffffffff;
|
||||
DWORD PossibleRangeEnd;
|
||||
|
||||
for (DWORD i = 0; i < SectionHeader_text->SizeOfRawData; ++i) {
|
||||
if (memcmp(SectionView_text + i, Keyword[0], sizeof(Keyword[0])) == 0) {
|
||||
size_t RRip = i + sizeof(Keyword[0]) + sizeof(uint32_t);
|
||||
size_t RRipOffset = *reinterpret_cast<const uint32_t*>(SectionView_text + i + sizeof(Keyword[0]));
|
||||
|
||||
Hints.emplace_back(RRip + RRipOffset);
|
||||
|
||||
if (i < PossibleRangeStart) {
|
||||
PossibleRangeStart = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PossibleRangeStart -= 0x1000;
|
||||
PossibleRangeEnd = PossibleRangeStart + 0x100000;
|
||||
|
||||
// Keywords[0] should occur 9 times.
|
||||
// Because there's only 9 'M' chars in `KeywordMeta`.
|
||||
if (Hints.size() != 9) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Hints.size() != 9"));
|
||||
}
|
||||
|
||||
std::sort(Hints.begin(), Hints.end());
|
||||
|
||||
// assert
|
||||
// if not satisfied, refuse to patch
|
||||
if (Hints.back() - Hints.front() != 0x18360F8F8 - 0x18360F7D0) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Hints.back() - Hints.front() != 0x18360F8F8 - 0x18360F7D0"));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _countof(_PatchOffset); ++i) {
|
||||
for (DWORD j = PossibleRangeStart; j < PossibleRangeEnd; ++j) {
|
||||
if (memcmp(SectionView_text + j, Keyword[i], sizeof(Keyword[i])) == 0) {
|
||||
size_t RRip = j + sizeof(Keyword[i]) + sizeof(uint32_t);
|
||||
size_t RRipOffset = *reinterpret_cast<const uint32_t*>(SectionView_text + j + sizeof(Keyword[i]));
|
||||
size_t Index = RRip + RRipOffset - Hints.front();
|
||||
|
||||
if (Index == i) {
|
||||
lpPatch[i] = SectionView_text + j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if not found, refuse to patch
|
||||
if (lpPatch[i] == nullptr) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("A patch point is missing."));
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _countof(_PatchOffset); ++i) {
|
||||
_PatchOffset[i] = _Image.PointerToFileOffset(lpPatch[i]);
|
||||
}
|
||||
|
||||
LOG_SUCCESS(0, "PatchSolution2 ...... Ready to apply");
|
||||
for (size_t i = 0; i < _countof(_PatchOffset); i += 4) {
|
||||
static_assert(sizeof(_countof(_PatchOffset)) % 4 == 0);
|
||||
LOG_HINT(4, "Patch offset[%zu ... %zu] = 0x%.8zx, 0x%.8zx, 0x%.8zx, 0x%.8zx", i, i + 3, _PatchOffset[i], _PatchOffset[i + 1], _PatchOffset[i + 2], _PatchOffset[i + 3]);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (nkg::Exception&) {
|
||||
for (size_t i = 0; i < _countof(_PatchOffset); ++i) {
|
||||
_PatchOffset[i] = InvalidOffset;
|
||||
}
|
||||
|
||||
LOG_FAILURE(0, "PatchSolution2 ...... Omitted");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
92
navicat-patcher/PatchSolution2-generic.cpp
Normal file
92
navicat-patcher/PatchSolution2-generic.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
#include "PatchSolutions.hpp"
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\PatchSolution2-generic.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
const char PatchSolution2::KeywordMeta[0x188 + 1] =
|
||||
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I"
|
||||
"qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv"
|
||||
"a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF"
|
||||
"R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2"
|
||||
"WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt"
|
||||
"YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ"
|
||||
"awIDAQAB";
|
||||
|
||||
[[nodiscard]]
|
||||
bool PatchSolution2::CheckKey(const RSACipher& Cipher) const noexcept {
|
||||
auto szPublicKey = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
||||
|
||||
for (auto pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("-----BEGIN PUBLIC KEY-----"));
|
||||
}
|
||||
|
||||
for (auto pos = szPublicKey.find("-----END PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----END PUBLIC KEY-----", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("-----END PUBLIC KEY-----"));
|
||||
}
|
||||
|
||||
for (auto pos = szPublicKey.find("\n"); pos != std::string::npos; pos = szPublicKey.find("\n", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("\n"));
|
||||
}
|
||||
|
||||
return szPublicKey.length() == literal_length(KeywordMeta);
|
||||
}
|
||||
|
||||
void PatchSolution2::MakePatch(const RSACipher& Cipher) const {
|
||||
for (size_t i = 0; i < _countof(_PatchOffset); ++i) {
|
||||
if (_PatchOffset[i] == InvalidOffset) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("PatchSolution2 has not been ready yet."));
|
||||
}
|
||||
}
|
||||
|
||||
auto pbImage = _Image.ImageBase<uint8_t*>();
|
||||
auto szPublicKey = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
||||
|
||||
for (auto pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("-----BEGIN PUBLIC KEY-----"));
|
||||
}
|
||||
|
||||
for (auto pos = szPublicKey.find("-----END PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----END PUBLIC KEY-----", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("-----END PUBLIC KEY-----"));
|
||||
}
|
||||
|
||||
for (auto pos = szPublicKey.find("\n"); pos != std::string::npos; pos = szPublicKey.find("\n", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("\n"));
|
||||
}
|
||||
|
||||
if (szPublicKey.length() != literal_length(KeywordMeta)) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("szPublicKey.length() != literal_length(KeywordMeta)"));
|
||||
}
|
||||
|
||||
_putts(TEXT("*******************************************************"));
|
||||
_putts(TEXT("* PatchSolution2 *"));
|
||||
_putts(TEXT("*******************************************************"));
|
||||
|
||||
for (size_t i = 0; i < _countof(_PatchOffset); i += 2) {
|
||||
static_assert(_countof(_PatchOffset) % 2 == 0);
|
||||
LOG_HINT(0, "+0x%.8zx: %.2x %.2x %.2x -> %.2x %.2x %.2x | +0x%.8zx: %.2x %.2x %.2x -> %.2x %.2x %.2x",
|
||||
_PatchOffset[i],
|
||||
pbImage[_PatchOffset[i]],
|
||||
pbImage[_PatchOffset[i] + 1],
|
||||
pbImage[_PatchOffset[i] + 2],
|
||||
pbImage[_PatchOffset[i]],
|
||||
pbImage[_PatchOffset[i] + 1],
|
||||
szPublicKey[i],
|
||||
_PatchOffset[i + 1],
|
||||
pbImage[_PatchOffset[i + 1]],
|
||||
pbImage[_PatchOffset[i + 1] + 1],
|
||||
pbImage[_PatchOffset[i + 1] + 2],
|
||||
pbImage[_PatchOffset[i + 1]],
|
||||
pbImage[_PatchOffset[i + 1] + 1],
|
||||
szPublicKey[i + 1]
|
||||
);
|
||||
|
||||
pbImage[_PatchOffset[i] + 2] = szPublicKey[i];
|
||||
pbImage[_PatchOffset[i + 1] + 2] = szPublicKey[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
517
navicat-patcher/PatchSolution2-i386.cpp
Normal file
517
navicat-patcher/PatchSolution2-i386.cpp
Normal file
@ -0,0 +1,517 @@
|
||||
#include "PatchSolutions.hpp"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\PatchSolution2-i386.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
/*
|
||||
Keyword[0x188][5] is generated by the following python script:
|
||||
|
||||
-----Begin Python3 Script-----
|
||||
meta = \
|
||||
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I" \
|
||||
"qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv" \
|
||||
"a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF" \
|
||||
"R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2" \
|
||||
"WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt" \
|
||||
"YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ" \
|
||||
"awIDAQAB"
|
||||
|
||||
print('const uint8_t PatchSolution2::Keywords[0x188][5] = {')
|
||||
for i in range(0, len(meta)):
|
||||
if i % 3 == 0:
|
||||
i1 = '0x83, 0xf2, 0x%.2x' % ord(meta[i]) # asm('xor edx, meta[i]')
|
||||
i2 = '0x88, 0x15' # asm_prefix('mov byte ptr ds:xxxxxxxx, dl')
|
||||
elif i % 3 == 1:
|
||||
i1 = '0x83, 0xf0, 0x%.2x' % ord(meta[i]) # asm('xor eax, meta[i]')
|
||||
i2 = '0xa2' # asm_prefix('mov byte ptr ds:xxxxxxxx, al')
|
||||
else:
|
||||
i1 = '0x83, 0xf1, 0x%.2x' % ord(meta[i]) # asm('xor ecx, meta[i]')
|
||||
i2 = '0x88, 0x0d' # asm_prefix('mov byte ptr ds:xxxxxxxx, cl')
|
||||
print(' { %s, %s }' % (i1, i2), end=',\n' if i != len(meta) - 1 else '\n')
|
||||
print('};')
|
||||
-----End Python3 Script-----
|
||||
|
||||
*/
|
||||
const uint8_t PatchSolution2::Keyword[0x188][5] = {
|
||||
{ 0x83, 0xf2, 0x4d, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x49, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x49, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x42, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x49, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x6a, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x41, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x4e, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x42, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x67, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6b, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x71, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x68, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6b, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x69, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x47, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x39, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x77, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x30, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x42, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x41, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x51, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x45, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x46, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x41, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x41, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x4f, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x43, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x41, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x51, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x38, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x41, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x4d, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x49, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x49, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x42, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x43, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x67, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x4b, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x43, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x41, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x51, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x45, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x41, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x77, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x31, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x64, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x71, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x46, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x33, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x53, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x6b, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x43, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x61, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x41, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x41, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x6d, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x4d, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x7a, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x73, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x38, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x38, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x39, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x49, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x71, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x64, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x57, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x39, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x4d, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x32, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x64, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x49, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x64, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x68, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x33, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x6a, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x47, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x39, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x79, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x50, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x63, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x6d, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x4c, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x6e, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x6d, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x4a, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x69, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x47, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x70, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x42, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x46, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x34, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x45, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x39, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x56, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x48, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x53, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x4d, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x47, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x65, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x38, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x6f, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x50, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x41, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x79, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x32, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6b, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x4a, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x44, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6d, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x64, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x4e, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x74, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x34, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x42, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x63, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x45, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x79, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x67, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x76, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x73, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x73, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x45, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x66, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x67, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x69, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x6e, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x76, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x61, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x35, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x74, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x35, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x6a, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6d, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x33, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x35, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x32, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x55, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x41, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6f, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x44, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x6f, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x73, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x55, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x4a, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6b, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x54, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x58, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x47, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x51, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x68, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x70, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x41, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x57, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x4d, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x46, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x34, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x66, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x42, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x6d, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x42, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x70, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x4f, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x33, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x45, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x65, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x64, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x47, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x36, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x32, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x72, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x4f, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x73, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x71, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x4d, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x42, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x67, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x6d, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x53, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x64, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x41, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x79, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x78, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x43, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x53, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x50, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x42, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x52, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x4a, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x49, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x4f, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x46, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x52, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x30, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x51, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x67, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x5a, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x46, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x62, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x52, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x6e, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x55, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x30, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x66, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x72, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6a, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x33, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x34, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x66, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x69, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x56, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6d, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x67, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x59, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x69, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x4c, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x75, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x5a, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x53, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x41, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6d, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x49, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x62, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x73, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x38, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x5a, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x78, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x69, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x48, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x50, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x64, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x70, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x31, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x6f, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x44, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x34, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x74, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x55, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x70, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x76, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x73, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x46, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x63, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x69, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x34, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x51, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x4a, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x74, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x59, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x4e, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6a, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x4e, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x6e, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x47, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x55, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x32, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x57, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x50, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x48, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x36, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x72, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x76, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x43, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x68, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x47, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6c, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x31, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x49, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x52, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x4b, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x72, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x78, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x4d, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x74, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x71, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x4c, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x69, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x65, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x6c, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x73, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x76, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x61, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x6a, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x55, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x6a, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x79, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x72, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x67, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x4f, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x43, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x36, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x4e, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6d, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x79, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x6d, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x59, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x4d, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x76, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x5a, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x4e, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x45, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x52, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x33, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x68, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x74, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x46, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x45, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x74, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x4c, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x31, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x65, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x51, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x62, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x43, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x79, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x54, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x66, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x44, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x6d, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x74, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x59, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x79, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x51, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x31, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x57, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x74, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x34, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x4f, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x74, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x31, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x32, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6c, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x78, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x66, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x30, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x77, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x56, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x49, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x52, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x35, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6d, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x63, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x47, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x4e, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x37, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x58, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x43, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x58, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x4a, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x52, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x48, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x4f, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x46, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x48, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x53, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x66, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x31, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x67, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x7a, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x58, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x57, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x61, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x62, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x52, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x53, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x76, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x6d, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x74, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x31, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x6e, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x72, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x6c, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x37, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x73, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x57, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x36, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x63, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x6a, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x78, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x6c, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x6a, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x75, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x75, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x51, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x61, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x77, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x49, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x44, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x41, 0xa2 },
|
||||
{ 0x83, 0xf1, 0x51, 0x88, 0x0d },
|
||||
{ 0x83, 0xf2, 0x41, 0x88, 0x15 },
|
||||
{ 0x83, 0xf0, 0x42, 0xa2 }
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
bool PatchSolution2::FindPatchOffset() noexcept {
|
||||
|
||||
try {
|
||||
auto SectionHeader_text = _Image.ImageSectionHeaderByName(".text");
|
||||
auto SectionView_text = _Image.ImageSectionView<const uint8_t*>(SectionHeader_text);
|
||||
const uint8_t* lpPatch[_countof(_PatchOffset)] = {};
|
||||
|
||||
std::vector<size_t> Hints;
|
||||
DWORD PossibleRangeStart = 0xffffffff;
|
||||
DWORD PossibleRangeEnd;
|
||||
|
||||
for (DWORD i = 0; i < SectionHeader_text->SizeOfRawData; ++i) {
|
||||
if (memcmp(SectionView_text + i, Keyword[0], sizeof(Keyword[0])) == 0) {
|
||||
Hints.emplace_back(
|
||||
*reinterpret_cast<const uint32_t*>(SectionView_text + i + sizeof(Keyword[0]))
|
||||
);
|
||||
|
||||
if (i < PossibleRangeStart) {
|
||||
PossibleRangeStart = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PossibleRangeStart -= 0x1000;
|
||||
PossibleRangeEnd = PossibleRangeStart + 0x100000;
|
||||
|
||||
// Keywords[0] should occur 3 times.
|
||||
if (Hints.size() != 3) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Hints.size() != 3"));
|
||||
}
|
||||
|
||||
std::sort(Hints.begin(), Hints.end());
|
||||
|
||||
if (Hints.back() - Hints.front() != 0x127382BE - 0x12738210) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Hints.back() - Hints.front() != 0x127382BE - 0x12738210"));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _countof(_PatchOffset); ++i) {
|
||||
uint8_t CurrentKeyword[9];
|
||||
size_t CurrentKeywordSize = i % 3 == 1 ? 4 : 5;
|
||||
|
||||
memcpy(CurrentKeyword, Keyword[i], CurrentKeywordSize);
|
||||
*reinterpret_cast<uint32_t*>(CurrentKeyword + CurrentKeywordSize) = Hints[0] + i;
|
||||
CurrentKeywordSize += sizeof(uint32_t);
|
||||
|
||||
for (DWORD j = PossibleRangeStart; j < PossibleRangeEnd; ++j) {
|
||||
if (memcmp(SectionView_text + j, CurrentKeyword, CurrentKeywordSize) == 0) {
|
||||
lpPatch[i] = SectionView_text + j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if not found, refuse to patch
|
||||
if (lpPatch[i] == nullptr) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("A patch point is missing."));
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _countof(_PatchOffset); ++i) {
|
||||
_PatchOffset[i] = _Image.PointerToFileOffset(lpPatch[i]);
|
||||
}
|
||||
|
||||
LOG_SUCCESS(0, "PatchSolution2 ...... Ready to apply");
|
||||
for (size_t i = 0; i < _countof(_PatchOffset); i += 4) {
|
||||
static_assert(sizeof(_countof(_PatchOffset)) % 4 == 0);
|
||||
LOG_HINT(4, "Patch offset[%zu ... %zu] = 0x%.8zx, 0x%.8zx, 0x%.8zx, 0x%.8zx", i, i + 3, _PatchOffset[i], _PatchOffset[i + 1], _PatchOffset[i + 2], _PatchOffset[i + 3]);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (nkg::Exception&) {
|
||||
for (size_t i = 0; i < _countof(_PatchOffset); ++i) {
|
||||
_PatchOffset[i] = InvalidOffset;
|
||||
}
|
||||
|
||||
LOG_FAILURE(0, "PatchSolution2 ...... Omitted");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
231
navicat-patcher/PatchSolution3-amd64.cpp
Normal file
231
navicat-patcher/PatchSolution3-amd64.cpp
Normal file
@ -0,0 +1,231 @@
|
||||
#include "PatchSolutions.hpp"
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\PatchSolution3-amd64.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
PatchSolution3::PatchSolution3(const ImageInterpreter& Image) :
|
||||
_Image(Image),
|
||||
_Engine(CS_ARCH_X86, CS_MODE_64),
|
||||
_Patch{}
|
||||
{
|
||||
_Engine.Option(CS_OPT_DETAIL, CS_OPT_ON);
|
||||
}
|
||||
|
||||
PatchSolution3::PatchSolution3(const ImageInterpreter* lpImage) :
|
||||
_Image(*lpImage),
|
||||
_Engine(CS_ARCH_X86, CS_MODE_64),
|
||||
_Patch{}
|
||||
{
|
||||
_Engine.Option(CS_OPT_DETAIL, CS_OPT_ON);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool PatchSolution3::CheckIfMatchPattern(const cs_insn* lpInsn) const noexcept {
|
||||
// the instruction we're interested in has one of the following patterns:
|
||||
// 1. mov PTR [MEM], IMM (IMM must consist of printable chars) // for IMM_DATA
|
||||
// 2. lea REG, PTR [MEM] (MEM must point to a non-empty printable string) // for STRING_DATA
|
||||
|
||||
if (_stricmp(lpInsn->mnemonic, "mov") == 0) {
|
||||
if (lpInsn->detail->x86.operands[1].type != X86_OP_IMM) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto pbImmValue = lpInsn->bytes + lpInsn->detail->x86.encoding.imm_offset;
|
||||
auto cbImmValue = lpInsn->detail->x86.encoding.imm_size;
|
||||
|
||||
return IsPrintable(pbImmValue, cbImmValue);
|
||||
} else if (_stricmp(lpInsn->mnemonic, "lea") == 0) {
|
||||
// as far as I know, all strings are loaded by "lea REG, QWORD PTR [RIP + disp]"
|
||||
// so operands[1] must look like "[RIP + disp]"
|
||||
if (lpInsn->detail->x86.operands[1].mem.base != X86_REG_RIP) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// scale must 1, otherwise pattern mismatches
|
||||
if (lpInsn->detail->x86.operands[1].mem.scale != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto StringRva = static_cast<uintptr_t>(
|
||||
lpInsn->address + lpInsn->size + // Next RIP
|
||||
lpInsn->detail->x86.operands[1].mem.disp
|
||||
);
|
||||
|
||||
try {
|
||||
auto StringPtr = _Image.RvaToPointer<const char*>(StringRva);
|
||||
auto StringLength = strlen(StringPtr);
|
||||
|
||||
// StringPtr must have at least one char
|
||||
// every char in StringPtr must be printable, otherwise pattern mismatches
|
||||
return StringLength && IsPrintable(StringPtr, StringLength);
|
||||
} catch (nkg::Exception&) {
|
||||
// If not found, pattern mismatches
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool PatchSolution3::CheckIfFound(const cs_insn* lpInsn, size_t KeywordIdx) const noexcept {
|
||||
// the instruction we're interested in has one of the following patterns:
|
||||
// 1. mov PTR [MEM], IMM (IMM must consist of printable chars) // for IMM_DATA
|
||||
// 2. lea REG, PTR [MEM] (MEM must point to a non-empty printable string) // for STRING_DATA
|
||||
|
||||
auto& op_count = lpInsn->detail->x86.op_count;
|
||||
auto& operands = lpInsn->detail->x86.operands;
|
||||
|
||||
if (op_count != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Keyword[KeywordIdx].Type == IMM_DATA && operands[1].type == X86_OP_IMM) {
|
||||
static_assert(sizeof(operands[1].imm) == sizeof(Keyword[KeywordIdx].Value));
|
||||
return
|
||||
operands[1].imm == *reinterpret_cast<const int64_t*>(Keyword[KeywordIdx].Value) &&
|
||||
lpInsn->detail->x86.encoding.imm_size == Keyword[KeywordIdx].Size;
|
||||
} else if (Keyword[KeywordIdx].Type == STRING_DATA && operands[1].type == X86_OP_MEM) {
|
||||
auto StringRva = static_cast<uintptr_t>(
|
||||
lpInsn->address + lpInsn->size + // Next RIP
|
||||
operands[1].mem.disp
|
||||
);
|
||||
|
||||
try {
|
||||
auto StringPtr = _Image.RvaToPointer<const char*>(StringRva);
|
||||
return
|
||||
strncmp(StringPtr, reinterpret_cast<const char*>(Keyword[KeywordIdx].Value), Keyword[KeywordIdx].Size) == 0 &&
|
||||
StringPtr[Keyword[KeywordIdx].Size] == '\x00';
|
||||
} catch (nkg::Exception&) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PatchSolution3::PatchInfo PatchSolution3::CreatePatchPoint(const void* lpOpcode, const cs_insn* lpInsn, size_t KeywordIdx) const noexcept {
|
||||
PatchInfo NewPatch;
|
||||
|
||||
NewPatch.OpcodeRva = lpInsn->address;
|
||||
NewPatch.lpOpcode = const_cast<void*>(lpOpcode);
|
||||
|
||||
if (lpInsn->detail->x86.operands[1].type == X86_OP_MEM) {
|
||||
auto StringRva = static_cast<uintptr_t>(
|
||||
lpInsn->address + lpInsn->size + // Next RIP
|
||||
lpInsn->detail->x86.operands[1].mem.disp
|
||||
);
|
||||
|
||||
NewPatch.lpOriginalString = _Image.RvaToPointer<char*>(StringRva);
|
||||
|
||||
if (Keyword[KeywordIdx].NotRecommendedToModify) {
|
||||
NewPatch.lpPatch = address_offset(NewPatch.lpOpcode, lpInsn->detail->x86.encoding.disp_offset);
|
||||
NewPatch.cbPatch = lpInsn->detail->x86.encoding.disp_size;
|
||||
} else {
|
||||
NewPatch.lpPatch = reinterpret_cast<uint8_t*>(NewPatch.lpOriginalString);
|
||||
NewPatch.cbPatch = Keyword[KeywordIdx].Size;
|
||||
}
|
||||
} else { // X86_OP_IMM
|
||||
NewPatch.lpPatch = address_offset(NewPatch.lpOpcode, lpInsn->detail->x86.encoding.imm_offset);
|
||||
NewPatch.cbPatch = lpInsn->detail->x86.encoding.imm_size;
|
||||
NewPatch.lpOriginalString = nullptr;
|
||||
}
|
||||
|
||||
NewPatch.lpReplaceString = nullptr;
|
||||
|
||||
return NewPatch;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool PatchSolution3::FindPatchOffset() noexcept {
|
||||
try {
|
||||
static const uint8_t HeaderOfTargetFunction[] = {
|
||||
0x40, 0x55, // push rbp
|
||||
0x48, 0x8D, 0xAC, 0x24, 0x70, 0xBC, 0xFF, 0xFF, // lea rbp, [rsp-4390h]
|
||||
0xB8, 0x90, 0x44, 0x00, 0x00 // mov eax, 4490h
|
||||
};
|
||||
|
||||
PatchInfo Patch[_countof(_Patch)] = {};
|
||||
|
||||
const uint8_t* lpTargetFunction = nullptr;
|
||||
auto lptargetFunctionHint = _Image.SearchSection<const uint8_t*>(".text", [&lpTargetFunction](const uint8_t* p) {
|
||||
__try {
|
||||
if (*reinterpret_cast<const uint32_t*>(p) == 0x6b67424e) {
|
||||
auto i = p - 0x250;
|
||||
for (; i < p; ++i) {
|
||||
if (memcmp(i, HeaderOfTargetFunction, sizeof(HeaderOfTargetFunction)) == 0) {
|
||||
lpTargetFunction = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
size_t KeywordIndex = 0;
|
||||
CapstoneDisassembler Disassembler = _Engine.CreateDisassembler();
|
||||
|
||||
Disassembler.SetContext(CapstoneContext{ lpTargetFunction, 0xcd03, _Image.PointerToRva(lpTargetFunction) });
|
||||
|
||||
while (Disassembler.Next()) {
|
||||
auto lpInsn = Disassembler.GetInstruction();
|
||||
|
||||
if (lpInsn->mnemonic[0] == 'j' || lpInsn->mnemonic[0] == 'J') {
|
||||
auto JumpedBranch = GetJumpedBranch(Disassembler.GetContext(), lpInsn);
|
||||
|
||||
if (_stricmp(lpInsn->mnemonic, "jmp") == 0) {
|
||||
Disassembler.SetContext(JumpedBranch);
|
||||
} else {
|
||||
Disassembler.SetContext(SelectBranch(Disassembler.GetContext(), JumpedBranch, KeywordIndex));
|
||||
}
|
||||
} else if (_stricmp(lpInsn->mnemonic, "ret") == 0) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Reach end of function."));
|
||||
} else {
|
||||
if (CheckIfMatchPattern(lpInsn) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CheckIfFound(lpInsn, KeywordIndex) == false) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Missing a patch."));
|
||||
}
|
||||
|
||||
Patch[KeywordIndex] = CreatePatchPoint(Disassembler.GetInstructionContext().lpMachineCode, lpInsn, KeywordIndex);
|
||||
|
||||
++KeywordIndex;
|
||||
}
|
||||
|
||||
if (KeywordIndex == _countof(Patch)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (KeywordIndex != _countof(Patch)) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Some patches are not found."));
|
||||
}
|
||||
|
||||
LOG_SUCCESS(0, "PatchSolution3 ...... Ready to apply");
|
||||
for (size_t i = 0; i < _countof(Patch); ++i) {
|
||||
_Patch[i] = Patch[i];
|
||||
LOG_HINT(4, "[%3zu] Instruction RVA = 0x%.8llx, Patch Offset = +0x%.8zx", i, _Patch[i].OpcodeRva, address_delta(_Patch[i].lpPatch, _Image.ImageBase()));
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (nkg::Exception&) {
|
||||
memset(_Patch, 0, sizeof(_Patch));
|
||||
|
||||
LOG_FAILURE(0, "PatchSolution3 ...... Omitted");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
424
navicat-patcher/PatchSolution3-generic.cpp
Normal file
424
navicat-patcher/PatchSolution3-generic.cpp
Normal file
@ -0,0 +1,424 @@
|
||||
#include "PatchSolutions.hpp"
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\PatchSolution3-generic.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
const PatchSolution3::KeywordInfo PatchSolution3::Keyword[111] = {
|
||||
{ { 0x4d, 0x49, 0x49 }, 3, STRING_DATA, false },
|
||||
{ { 0x42, 0x49 }, 2, IMM_DATA, false },
|
||||
{ { 0x6a }, 1, IMM_DATA, false },
|
||||
{ { 0x41 }, 1, IMM_DATA, false },
|
||||
{ { 0x4e, 0x42, 0x67, 0x6b }, 4, IMM_DATA, false },
|
||||
{ { 0x71 }, 1, IMM_DATA, false },
|
||||
{ { 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77 }, 6, STRING_DATA, false },
|
||||
{ { 0x30 }, 1, STRING_DATA, true },
|
||||
{ { 0x42 }, 1, IMM_DATA, false },
|
||||
{ { 0x41 }, 1, IMM_DATA, false },
|
||||
{ { 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43 }, 7, STRING_DATA, false },
|
||||
{ { 0x41, 0x51, 0x38, 0x41, 0x4d, 0x49 }, 6, STRING_DATA, false },
|
||||
{ { 0x49, 0x42 }, 2, STRING_DATA, false },
|
||||
{ { 0x43, 0x67, 0x4b, 0x43 }, 4, IMM_DATA, false },
|
||||
{ { 0x41, 0x51 }, 2, STRING_DATA, false },
|
||||
{ { 0x45, 0x41, 0x77, 0x31 }, 4, IMM_DATA, false },
|
||||
{ { 0x64, 0x71, 0x46, 0x33 }, 4, IMM_DATA, false },
|
||||
{ { 0x53 }, 1, STRING_DATA, true },
|
||||
{ { 0x6b, 0x43, 0x61, 0x41, 0x41, 0x6d }, 6, STRING_DATA, false },
|
||||
{ { 0x4d, 0x7a, 0x73, 0x38 }, 4, IMM_DATA, false },
|
||||
{ { 0x38, 0x39, 0x49, 0x71 }, 4, IMM_DATA, false },
|
||||
{ { 0x64 }, 1, IMM_DATA, false },
|
||||
{ { 0x57 }, 1, IMM_DATA, false },
|
||||
{ { 0x39, 0x4d, 0x32, 0x64 }, 4, IMM_DATA, false },
|
||||
{ { 0x49, 0x64, 0x68 }, 3, STRING_DATA, false },
|
||||
{ { 0x33, 0x6a }, 2, IMM_DATA, false },
|
||||
{ { 0x47, 0x39, 0x79, 0x50 }, 4, IMM_DATA, false },
|
||||
{ { 0x63, 0x6d }, 2, IMM_DATA, false },
|
||||
{ { 0x4c }, 1, IMM_DATA, false },
|
||||
{ { 0x6e, 0x6d, 0x4a }, 3, STRING_DATA, false },
|
||||
{ { 0x69, 0x47, 0x70, 0x42, 0x46, 0x34, 0x45 }, 7, STRING_DATA, false },
|
||||
{ { 0x39, 0x56, 0x48, 0x53, 0x4d, 0x47 }, 6, STRING_DATA, false },
|
||||
{ { 0x65, 0x38, 0x6f, 0x50, 0x41, 0x79, 0x32, 0x6b }, 8, STRING_DATA, false },
|
||||
{ { 0x4a, 0x44 }, 2, STRING_DATA, false },
|
||||
{ { 0x6d, 0x64 }, 2, IMM_DATA, false },
|
||||
{ { 0x4e, 0x74, 0x34 }, 3, STRING_DATA, false },
|
||||
{ { 0x42, 0x63, 0x45, 0x79, 0x67, 0x76 }, 6, STRING_DATA, false },
|
||||
{ { 0x73, 0x73, 0x45, 0x66, 0x67, 0x69 }, 6, STRING_DATA, false },
|
||||
{ { 0x6e, 0x76, 0x61, 0x35, 0x74 }, 5, STRING_DATA, false },
|
||||
{ { 0x35, 0x6a, 0x6d, 0x33, 0x35, 0x32 }, 6, STRING_DATA, false },
|
||||
{ { 0x55, 0x41 }, 2, IMM_DATA, false },
|
||||
{ { 0x6f, 0x44, 0x6f, 0x73 }, 4, IMM_DATA, false },
|
||||
{ { 0x55, 0x4a }, 2, IMM_DATA, false },
|
||||
{ { 0x6b, 0x54, 0x58, 0x47, 0x51 }, 5, STRING_DATA, false },
|
||||
{ { 0x68, 0x70, 0x41, 0x57, 0x4d, 0x46 }, 6, STRING_DATA, false },
|
||||
{ { 0x34, 0x66, 0x42, 0x6d, 0x42 }, 5, STRING_DATA, false },
|
||||
{ { 0x70, 0x4f, 0x33, 0x45 }, 4, IMM_DATA, false },
|
||||
{ { 0x65, 0x64 }, 2, IMM_DATA, false },
|
||||
{ { 0x47 }, 1, IMM_DATA, false },
|
||||
{ { 0x36, 0x32, 0x72, 0x4f, 0x73, 0x71 }, 6, STRING_DATA, false },
|
||||
{ { 0x4d }, 1, IMM_DATA, false },
|
||||
{ { 0x42, 0x67, 0x6d, 0x53 }, 4, STRING_DATA, false },
|
||||
{ { 0x64 }, 1, IMM_DATA, false },
|
||||
{ { 0x41, 0x79, 0x78, 0x43, 0x53 }, 5, STRING_DATA, false },
|
||||
{ { 0x50 }, 1, IMM_DATA, false },
|
||||
{ { 0x42, 0x52, 0x4a, 0x49, 0x4f }, 5, STRING_DATA, false },
|
||||
{ { 0x46, 0x52, 0x30, 0x51, 0x67, 0x5a, 0x46, 0x62 }, 8, STRING_DATA, false },
|
||||
{ { 0x52 }, 1, IMM_DATA, false },
|
||||
{ { 0x6e, 0x55, 0x30, 0x66 }, 4, STRING_DATA, false },
|
||||
{ { 0x72, 0x6a, 0x33, 0x34 }, 4, IMM_DATA, false },
|
||||
{ { 0x66 }, 1, STRING_DATA, true },
|
||||
{ { 0x69, 0x56, 0x6d, 0x67 }, 4, IMM_DATA, false },
|
||||
{ { 0x59, 0x69, 0x4c, 0x75 }, 4, STRING_DATA, false },
|
||||
{ { 0x5a, 0x53, 0x41, 0x6d }, 4, IMM_DATA, false },
|
||||
{ { 0x49, 0x62 }, 2, IMM_DATA, false },
|
||||
{ { 0x73 }, 1, IMM_DATA, false },
|
||||
{ { 0x38, 0x5a, 0x78, 0x69 }, 4, IMM_DATA, false },
|
||||
{ { 0x48 }, 1, IMM_DATA, false },
|
||||
{ { 0x50, 0x64, 0x70, 0x31 }, 4, IMM_DATA, false },
|
||||
{ { 0x6f, 0x44 }, 2, IMM_DATA, false },
|
||||
{ { 0x34 }, 1, IMM_DATA, false },
|
||||
{ { 0x74, 0x55, 0x70, 0x76, 0x73, 0x46 }, 6, STRING_DATA, false },
|
||||
{ { 0x63, 0x69, 0x34, 0x51, 0x4a, 0x74 }, 6, STRING_DATA, false },
|
||||
{ { 0x59, 0x4e, 0x6a, 0x4e, 0x6e, 0x47, 0x55 }, 7, STRING_DATA, false },
|
||||
{ { 0x32, 0x57, 0x50, 0x48 }, 4, STRING_DATA, false },
|
||||
{ { 0x36, 0x72, 0x76, 0x43, 0x68, 0x47, 0x6c }, 7, STRING_DATA, false },
|
||||
{ { 0x31, 0x49, 0x52, 0x4b, 0x72, 0x78, 0x4d, 0x74 }, 8, STRING_DATA, false },
|
||||
{ { 0x71, 0x4c, 0x69, 0x65, 0x6c }, 5, STRING_DATA, false },
|
||||
{ { 0x73, 0x76, 0x61, 0x6a, 0x55, 0x6a, 0x79, 0x72 }, 8, STRING_DATA, false },
|
||||
{ { 0x67 }, 1, STRING_DATA, true },
|
||||
{ { 0x4f, 0x43, 0x36, 0x4e, 0x6d, 0x79, 0x6d, 0x59 }, 8, STRING_DATA, false },
|
||||
{ { 0x4d }, 1, IMM_DATA, false },
|
||||
{ { 0x76, 0x5a, 0x4e }, 3, STRING_DATA, false },
|
||||
{ { 0x45, 0x52, 0x33, 0x68, 0x74 }, 5, STRING_DATA, false },
|
||||
{ { 0x46 }, 1, IMM_DATA, false },
|
||||
{ { 0x45, 0x74, 0x4c, 0x31 }, 4, STRING_DATA, false },
|
||||
{ { 0x65, 0x51, 0x62, 0x43, 0x79 }, 5, STRING_DATA, false },
|
||||
{ { 0x54, 0x66, 0x44, 0x6d, 0x74, 0x59, 0x79, 0x51 }, 8, STRING_DATA, false },
|
||||
{ { 0x31, 0x57, 0x74, 0x34 }, 4, STRING_DATA, false },
|
||||
{ { 0x4f }, 1, IMM_DATA, false },
|
||||
{ { 0x74, 0x31, 0x32, 0x6c, 0x78, 0x66 }, 6, STRING_DATA, false },
|
||||
{ { 0x30 }, 1, IMM_DATA, false },
|
||||
{ { 0x77, 0x56, 0x49, 0x52, 0x35 }, 5, STRING_DATA, false },
|
||||
{ { 0x6d }, 1, IMM_DATA, false },
|
||||
{ { 0x63, 0x47, 0x4e, 0x37 }, 4, STRING_DATA, false },
|
||||
{ { 0x58, 0x43, 0x58, 0x4a }, 4, STRING_DATA, false },
|
||||
{ { 0x52, 0x48, 0x4f, 0x46 }, 4, IMM_DATA, false },
|
||||
{ { 0x48, 0x53 }, 2, IMM_DATA, false },
|
||||
{ { 0x66 }, 1, IMM_DATA, false },
|
||||
{ { 0x31, 0x67, 0x7a, 0x58, 0x57 }, 5, STRING_DATA, false },
|
||||
{ { 0x61 }, 1, IMM_DATA, false },
|
||||
{ { 0x62 }, 1, IMM_DATA, false },
|
||||
{ { 0x52, 0x53 }, 2, STRING_DATA, false },
|
||||
{ { 0x76, 0x6d, 0x74, 0x31, 0x6e }, 5, STRING_DATA, false },
|
||||
{ { 0x72, 0x6c }, 2, STRING_DATA, true },
|
||||
{ { 0x37, 0x73, 0x57 }, 3, STRING_DATA, false },
|
||||
{ { 0x36, 0x63, 0x6a }, 3, STRING_DATA, false },
|
||||
{ { 0x78, 0x6c, 0x6a, 0x75, 0x75, 0x51, 0x61 }, 7, STRING_DATA, false },
|
||||
{ { 0x77, 0x49, 0x44, 0x41 }, 4, STRING_DATA, false },
|
||||
{ { 0x51, 0x41 }, 2, IMM_DATA, false },
|
||||
{ { 0x42 }, 1, IMM_DATA, false }
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
bool PatchSolution3::IsPrintable(const void* p, size_t s) noexcept {
|
||||
auto pb = reinterpret_cast<const uint8_t*>(p);
|
||||
for (size_t i = 0; i < s; ++i) {
|
||||
if (isprint(pb[i]) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
CapstoneContext PatchSolution3::GetJumpedBranch(const CapstoneContext& NotJumpedBranch, const cs_insn* lpJxxInsn) const {
|
||||
CapstoneContext JumpedBranch;
|
||||
|
||||
JumpedBranch.lpMachineCode = _Image.RvaToPointer<const void*>(
|
||||
static_cast<uintptr_t>(lpJxxInsn->detail->x86.operands[0].imm)
|
||||
);
|
||||
|
||||
JumpedBranch.cbMachineCode = NotJumpedBranch.cbMachineCode - (
|
||||
reinterpret_cast<const uint8_t*>(JumpedBranch.lpMachineCode) -
|
||||
reinterpret_cast<const uint8_t*>(NotJumpedBranch.lpMachineCode)
|
||||
);
|
||||
|
||||
JumpedBranch.Address = lpJxxInsn->detail->x86.operands[0].imm;
|
||||
|
||||
return JumpedBranch;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
CapstoneContext PatchSolution3::SelectBranch(const CapstoneContext& NotJumpedBranch, const CapstoneContext& JumpedBranch, size_t KeywordIdx) const {
|
||||
CapstoneContext A = NotJumpedBranch;
|
||||
CapstoneContext B = JumpedBranch;
|
||||
int WeightA = 0;
|
||||
int WeightB = 0;
|
||||
auto Disassembler = _Engine.CreateDisassembler();
|
||||
|
||||
while (true) {
|
||||
int WeightAPrev = WeightA;
|
||||
int WeightBPrev = WeightB;
|
||||
|
||||
//
|
||||
// process NotJumpedBranch
|
||||
//
|
||||
Disassembler.SetContext(A);
|
||||
while (Disassembler.Next()) {
|
||||
auto lpInsn = Disassembler.GetInstruction();
|
||||
|
||||
//
|
||||
// For all x86 mnemonics, only 'jcc' or 'jmp' starts with 'j' or 'J'.
|
||||
// So it should be a new branch if we meet them.
|
||||
//
|
||||
if (lpInsn->mnemonic[0] == 'j' || lpInsn->mnemonic[0] == 'J') {
|
||||
auto JumpedBranch = GetJumpedBranch(Disassembler.GetContext(), lpInsn);
|
||||
|
||||
if (_stricmp(lpInsn->mnemonic, "jmp") == 0) {
|
||||
Disassembler.SetContext(JumpedBranch);
|
||||
} else {
|
||||
try {
|
||||
Disassembler.SetContext(SelectBranch(Disassembler.GetContext(), JumpedBranch, KeywordIdx));
|
||||
} catch (nkg::Exception&) {
|
||||
// If exception occurs, give up NotJumpedBranch
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (_stricmp(lpInsn->mnemonic, "ret") == 0) {
|
||||
return JumpedBranch;
|
||||
} else {
|
||||
if (CheckIfMatchPattern(lpInsn) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// if match pattern, but keyword doesn't match,
|
||||
// NotJumpedBranch must not be what we want
|
||||
//
|
||||
if (CheckIfFound(lpInsn, KeywordIdx) == false) {
|
||||
return JumpedBranch;
|
||||
}
|
||||
|
||||
//
|
||||
// If keyword is succeeded to match
|
||||
// Add WeightA and stop processing NotJumpedBranch
|
||||
//
|
||||
++WeightA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
A = Disassembler.GetContext();
|
||||
|
||||
//
|
||||
// process JumpedBranch
|
||||
//
|
||||
Disassembler.SetContext(B);
|
||||
while (Disassembler.Next()) {
|
||||
auto lpInsn = Disassembler.GetInstruction();
|
||||
|
||||
//
|
||||
// For all x86 mnemonics, only 'jcc' or 'jmp' starts with 'j' or 'J'.
|
||||
// So it should be a new branch if we meet them.
|
||||
//
|
||||
if (lpInsn->mnemonic[0] == 'j' || lpInsn->mnemonic[0] == 'J') {
|
||||
auto JumpedBranch = GetJumpedBranch(Disassembler.GetContext(), lpInsn);
|
||||
|
||||
if (_stricmp(lpInsn->mnemonic, "jmp") == 0) {
|
||||
Disassembler.SetContext(JumpedBranch);
|
||||
} else {
|
||||
try {
|
||||
Disassembler.SetContext(SelectBranch(Disassembler.GetContext(), JumpedBranch, KeywordIdx));
|
||||
} catch (nkg::Exception&) {
|
||||
// If exception occurs, give up JumpedBranch
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (_stricmp(lpInsn->mnemonic, "ret") == 0) {
|
||||
return NotJumpedBranch;
|
||||
} else {
|
||||
if (CheckIfMatchPattern(lpInsn) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// if match pattern, but keyword doesn't match,
|
||||
// JumpedBranch must not be what we want
|
||||
//
|
||||
if (CheckIfFound(lpInsn, KeywordIdx) == false) {
|
||||
return NotJumpedBranch;
|
||||
}
|
||||
|
||||
//
|
||||
// If keyword is succeeded to match
|
||||
// Add WeightB and stop processing JumpedBranch
|
||||
//
|
||||
++WeightB;
|
||||
break;
|
||||
}
|
||||
}
|
||||
B = Disassembler.GetContext();
|
||||
|
||||
//
|
||||
// If this happens, it means neither of two branch is our target
|
||||
if (WeightAPrev == WeightA && WeightBPrev == WeightB) {
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Branch is not selected."));
|
||||
}
|
||||
|
||||
if (WeightA != WeightB)
|
||||
return WeightA > WeightB ? NotJumpedBranch : JumpedBranch;
|
||||
else
|
||||
++KeywordIdx;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool PatchSolution3::CheckKey(const RSACipher& Cipher) const noexcept {
|
||||
//
|
||||
// Brute-force search, cchString should be 1 or 2
|
||||
//
|
||||
auto SearchString = [](const void* lpRange, size_t cbRange, const char* lpString, size_t cchString) -> const char* {
|
||||
const char* p = reinterpret_cast<const char*>(lpRange);
|
||||
|
||||
for (size_t i = 0; i < cbRange; ++i) {
|
||||
if (p[i] == lpString[0]) {
|
||||
bool match = true;
|
||||
|
||||
__try {
|
||||
for (size_t j = 1; j < cchString; ++j) {
|
||||
if (p[i + j] != lpString[j]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
match = false;
|
||||
}
|
||||
|
||||
if (match && p[i + cchString] == '\x00')
|
||||
return address_offset_cast<const char*>(lpRange, i);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
auto szPublicKey = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
||||
|
||||
for (auto pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("-----BEGIN PUBLIC KEY-----"));
|
||||
}
|
||||
|
||||
for (auto pos = szPublicKey.find("-----END PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----END PUBLIC KEY-----", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("-----END PUBLIC KEY-----"));
|
||||
}
|
||||
|
||||
for (auto pos = szPublicKey.find("\n"); pos != std::string::npos; pos = szPublicKey.find("\n", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("\n"));
|
||||
}
|
||||
|
||||
if (szPublicKey.length() != 0x188) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t PublicKeyReadCursor = 0;
|
||||
auto SectionHeader_rdata = _Image.ImageSectionHeaderByName(".rdata");
|
||||
auto SectionView_rdata = _Image.ImageSectionView(SectionHeader_rdata);
|
||||
|
||||
for (size_t i = 0; i < _countof(_Patch); PublicKeyReadCursor += Keyword[i].Size, ++i) {
|
||||
if (Keyword[i].NotRecommendedToModify) {
|
||||
_Patch[i].lpReplaceString = nullptr;
|
||||
|
||||
const char* lpReplaceString = nullptr;
|
||||
const void* lpSearchRange = _Patch[i].lpOriginalString;
|
||||
size_t cbSearchRange = SectionHeader_rdata->SizeOfRawData - address_delta(_Patch[i].lpOriginalString, SectionView_rdata);
|
||||
|
||||
for (size_t offset = 0;;) {
|
||||
lpReplaceString = SearchString(
|
||||
address_offset(lpSearchRange, offset),
|
||||
cbSearchRange - offset,
|
||||
szPublicKey.c_str() + PublicKeyReadCursor,
|
||||
Keyword[i].Size
|
||||
);
|
||||
|
||||
if (lpReplaceString == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_Image.IsRvaRangeInRelocTable(_Image.PointerToRva(lpReplaceString), Keyword[i].Size + 1)) {
|
||||
//
|
||||
// Damn it!
|
||||
// ReplaceString will be modified during relocation
|
||||
// We have to find another one
|
||||
//
|
||||
++offset;
|
||||
} else {
|
||||
//
|
||||
// ReplaceString won't be modified during relocation
|
||||
// which can be used to act as a part of public key string
|
||||
//
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_Patch[i].lpReplaceString = const_cast<char*>(lpReplaceString);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PatchSolution3::MakePatch(const RSACipher& Cipher) const {
|
||||
for (size_t i = 0; i < _countof(_Patch); ++i) {
|
||||
if (_Patch[i].lpPatch == nullptr) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("PatchSolution3 has not been ready yet."));
|
||||
}
|
||||
}
|
||||
|
||||
auto szPublicKey = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
||||
|
||||
for (auto pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("-----BEGIN PUBLIC KEY-----"));
|
||||
}
|
||||
|
||||
for (auto pos = szPublicKey.find("-----END PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----END PUBLIC KEY-----", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("-----END PUBLIC KEY-----"));
|
||||
}
|
||||
|
||||
for (auto pos = szPublicKey.find("\n"); pos != std::string::npos; pos = szPublicKey.find("\n", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("\n"));
|
||||
}
|
||||
|
||||
_putts(TEXT("*******************************************************"));
|
||||
_putts(TEXT("* PatchSolution3 *"));
|
||||
_putts(TEXT("*******************************************************"));
|
||||
|
||||
size_t readptr = 0;
|
||||
for (size_t i = 0; i < _countof(_Patch); readptr += Keyword[i].Size, ++i) {
|
||||
_tprintf_s(TEXT("[*] +%.8zx: "), address_delta(_Patch[i].lpPatch, _Image.ImageBase()));
|
||||
|
||||
PrintBytes(_Patch[i].lpPatch, _Patch[i].cbPatch);
|
||||
_tprintf_s(TEXT(" ---> "));
|
||||
|
||||
if (Keyword[i].NotRecommendedToModify) {
|
||||
auto offset = _Patch[i].lpReplaceString - _Patch[i].lpOriginalString;
|
||||
uint64_t disp = 0;
|
||||
|
||||
memcpy(&disp, _Patch[i].lpPatch, _Patch[i].cbPatch);
|
||||
disp += offset;
|
||||
|
||||
memcpy(_Patch[i].lpPatch, &disp, _Patch[i].cbPatch);
|
||||
} else {
|
||||
memcpy(_Patch[i].lpPatch, szPublicKey.c_str() + readptr, Keyword[i].Size);
|
||||
}
|
||||
|
||||
PrintBytes(_Patch[i].lpPatch, _Patch[i].cbPatch);
|
||||
_tprintf_s(TEXT("\n"));
|
||||
}
|
||||
|
||||
_putts(TEXT(""));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
247
navicat-patcher/PatchSolution3-i386.cpp
Normal file
247
navicat-patcher/PatchSolution3-i386.cpp
Normal file
@ -0,0 +1,247 @@
|
||||
#include "PatchSolutions.hpp"
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\PatchSolution3-i386.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
PatchSolution3::PatchSolution3(const ImageInterpreter& Image) :
|
||||
_Image(Image),
|
||||
_Engine(CS_ARCH_X86, CS_MODE_32),
|
||||
_Patch{}
|
||||
{
|
||||
_Engine.Option(CS_OPT_DETAIL, CS_OPT_ON);
|
||||
}
|
||||
|
||||
PatchSolution3::PatchSolution3(const ImageInterpreter* lpImage) :
|
||||
_Image(*lpImage),
|
||||
_Engine(CS_ARCH_X86, CS_MODE_32),
|
||||
_Patch{}
|
||||
{
|
||||
_Engine.Option(CS_OPT_DETAIL, CS_OPT_ON);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool PatchSolution3::CheckIfMatchPattern(const cs_insn* lpInsn) const noexcept {
|
||||
// the instruction we're interested in has one of the following patterns:
|
||||
// 1. mov PTR [MEM], IMM (IMM must consist of printable chars) // for KeywordType::IMM_DATA
|
||||
// except pattern "mov [ebp - 0x4], IMM"
|
||||
// 2. push IMM (IMM must consist of printable chars) // for KeywordType::IMM_DATA
|
||||
// 3. push offset MEM (MEM must point to a non-empty printable string) // for KeywordType::STRING_DATA
|
||||
//
|
||||
|
||||
if (_stricmp(lpInsn->mnemonic, "mov") == 0) {
|
||||
// filter the case "mov [ebp - 0x4], IMM"
|
||||
// because IMM may consist of printable chars in that case, which will mislead us.
|
||||
//
|
||||
// Here I use "> -0x30" to intensify condition, instead of "== -0x4"
|
||||
if (lpInsn->detail->x86.operands[0].type == X86_OP_MEM &&
|
||||
lpInsn->detail->x86.operands[0].mem.base == X86_REG_EBP &&
|
||||
lpInsn->detail->x86.operands[0].mem.disp > -0x30)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lpInsn->detail->x86.operands[1].type != X86_OP_IMM) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto pbImmValue = lpInsn->bytes + lpInsn->detail->x86.encoding.imm_offset;
|
||||
auto cbImmValue = lpInsn->detail->x86.encoding.imm_size;
|
||||
|
||||
// each bytes of imm must be printable;
|
||||
return IsPrintable(pbImmValue, cbImmValue);
|
||||
} else if (_stricmp(lpInsn->mnemonic, "push") == 0) {
|
||||
if (lpInsn->detail->x86.operands[0].type != X86_OP_IMM) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test if match pattern 2
|
||||
auto pbImmValue = lpInsn->bytes + lpInsn->detail->x86.encoding.imm_offset;
|
||||
auto cbImmValue = lpInsn->detail->x86.encoding.imm_size;
|
||||
if (IsPrintable(pbImmValue, cbImmValue)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// test if match pattern 3
|
||||
auto StringRva = static_cast<uintptr_t>(
|
||||
lpInsn->detail->x86.operands[0].imm - _Image.ImageNtHeaders()->OptionalHeader.ImageBase
|
||||
);
|
||||
|
||||
try {
|
||||
auto StringPtr = _Image.RvaToPointer<const char*>(StringRva);
|
||||
auto StringLength = strlen(StringPtr);
|
||||
|
||||
// StringPtr must have at least one char
|
||||
// every char in StringPtr must be printable, otherwise pattern mismatches
|
||||
return StringLength && IsPrintable(StringPtr, StringLength);
|
||||
} catch (nkg::Exception&) {
|
||||
// If not found, pattern mismatches
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool PatchSolution3::CheckIfFound(const cs_insn* lpInsn, size_t KeywordIdx) const noexcept {
|
||||
// the instruction we're interested in has one of the following patterns:
|
||||
// 1. mov PTR [MEM], IMM (IMM must consist of printable chars) // for KeywordType::IMM_DATA
|
||||
// except pattern "mov [ebp - 0x4], IMM"
|
||||
// 2. push IMM (IMM must consist of printable chars) // for KeywordType::IMM_DATA
|
||||
// 3. push offset MEM (MEM must point to a non-empty printable string) // for KeywordType::STRING_DATA
|
||||
//
|
||||
|
||||
auto& op_count = lpInsn->detail->x86.op_count;
|
||||
auto& operands = lpInsn->detail->x86.operands;
|
||||
|
||||
if (op_count < 1 || operands[op_count - 1].type != X86_OP_IMM) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Keyword[KeywordIdx].Type == IMM_DATA) {
|
||||
static_assert(sizeof(operands[op_count - 1].imm) == sizeof(Keyword[KeywordIdx].Value));
|
||||
return
|
||||
operands[op_count - 1].imm == *reinterpret_cast<const int64_t*>(Keyword[KeywordIdx].Value) &&
|
||||
lpInsn->detail->x86.encoding.imm_size == Keyword[KeywordIdx].Size;
|
||||
} else if (Keyword[KeywordIdx].Type == STRING_DATA) {
|
||||
auto StringRva = static_cast<uintptr_t>(
|
||||
operands[op_count - 1].imm - _Image.ImageNtHeaders()->OptionalHeader.ImageBase
|
||||
);
|
||||
|
||||
try {
|
||||
auto StringPtr = _Image.RvaToPointer<const char*>(StringRva);
|
||||
return
|
||||
strncmp(StringPtr, reinterpret_cast<const char*>(Keyword[KeywordIdx].Value), Keyword[KeywordIdx].Size) == 0 &&
|
||||
StringPtr[Keyword[KeywordIdx].Size] == '\x00';
|
||||
} catch (nkg::Exception&) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PatchSolution3::PatchInfo PatchSolution3::CreatePatchPoint(const void* lpOpcode, const cs_insn* lpInsn, size_t KeywordIdx) const noexcept {
|
||||
PatchInfo NewPatch;
|
||||
|
||||
NewPatch.OpcodeRva = lpInsn->address;
|
||||
NewPatch.lpOpcode = const_cast<void*>(lpOpcode);
|
||||
|
||||
if (Keyword[KeywordIdx].Type == IMM_DATA) {
|
||||
NewPatch.lpPatch = address_offset(NewPatch.lpOpcode, lpInsn->detail->x86.encoding.imm_offset);
|
||||
NewPatch.cbPatch = lpInsn->detail->x86.encoding.imm_size;
|
||||
NewPatch.lpOriginalString = nullptr;
|
||||
} else {
|
||||
auto StringRva = static_cast<uintptr_t>(
|
||||
lpInsn->detail->x86.operands[0].imm - _Image.ImageNtHeaders()->OptionalHeader.ImageBase
|
||||
);
|
||||
|
||||
NewPatch.lpOriginalString = _Image.RvaToPointer<char*>(StringRva);
|
||||
|
||||
if (Keyword[KeywordIdx].NotRecommendedToModify) {
|
||||
NewPatch.lpPatch = address_offset(NewPatch.lpOpcode, lpInsn->detail->x86.encoding.imm_offset);
|
||||
NewPatch.cbPatch = lpInsn->detail->x86.encoding.imm_size;
|
||||
} else {
|
||||
NewPatch.lpPatch = reinterpret_cast<uint8_t*>(NewPatch.lpOriginalString);
|
||||
NewPatch.cbPatch = Keyword[KeywordIdx].Size;
|
||||
}
|
||||
}
|
||||
|
||||
NewPatch.lpReplaceString = nullptr;
|
||||
|
||||
return NewPatch;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool PatchSolution3::FindPatchOffset() noexcept {
|
||||
try {
|
||||
static const uint8_t HeaderOfTargetFunction[] = {
|
||||
0x55, // push ebp
|
||||
0x8B, 0xEC, // mov ebp, esp
|
||||
0x6A, 0xFF // push 0xffffffff
|
||||
};
|
||||
|
||||
PatchInfo Patch[_countof(_Patch)] = {};
|
||||
|
||||
const uint8_t* lpTargetFunction = nullptr;
|
||||
auto lptargetFunctionHint = _Image.SearchSection<const uint8_t*>(".text", [&lpTargetFunction](const uint8_t* p) {
|
||||
__try {
|
||||
if (*reinterpret_cast<const uint32_t*>(p) == 0x6b67424e) {
|
||||
auto i = p - 0x1B0;
|
||||
for (; i < p; ++i) {
|
||||
if (memcmp(i, HeaderOfTargetFunction, sizeof(HeaderOfTargetFunction)) == 0) {
|
||||
lpTargetFunction = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
size_t KeywordIndex = 0;
|
||||
CapstoneDisassembler Disassembler = _Engine.CreateDisassembler();
|
||||
|
||||
Disassembler.SetContext(CapstoneContext{ lpTargetFunction, 0x9014, _Image.PointerToRva(lpTargetFunction) });
|
||||
|
||||
while (Disassembler.Next()) {
|
||||
auto lpInsn = Disassembler.GetInstruction();
|
||||
|
||||
if (lpInsn->mnemonic[0] == 'j' || lpInsn->mnemonic[0] == 'J') {
|
||||
auto JumpedBranch = GetJumpedBranch(Disassembler.GetContext(), lpInsn);
|
||||
|
||||
if (_stricmp(lpInsn->mnemonic, "jmp") == 0) {
|
||||
Disassembler.SetContext(JumpedBranch);
|
||||
} else {
|
||||
Disassembler.SetContext(SelectBranch(Disassembler.GetContext(), JumpedBranch, KeywordIndex));
|
||||
}
|
||||
} else if (_stricmp(lpInsn->mnemonic, "ret") == 0) {
|
||||
return false;
|
||||
} else {
|
||||
if (CheckIfMatchPattern(lpInsn) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CheckIfFound(lpInsn, KeywordIndex) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Patch[KeywordIndex] = CreatePatchPoint(Disassembler.GetInstructionContext().lpMachineCode, lpInsn, KeywordIndex);
|
||||
|
||||
++KeywordIndex;
|
||||
}
|
||||
|
||||
if (KeywordIndex == _countof(Patch)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (KeywordIndex != _countof(Patch)) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Some patches are not found."));
|
||||
}
|
||||
|
||||
LOG_SUCCESS(0, "PatchSolution3 ...... Ready to apply");
|
||||
for (size_t i = 0; i < _countof(Patch); ++i) {
|
||||
_Patch[i] = Patch[i];
|
||||
LOG_HINT(4, "[%3zu] Instruction RVA = 0x%.8llx, Patch Offset = +0x%.8zx", i, _Patch[i].OpcodeRva, address_delta(_Patch[i].lpPatch, _Image.ImageBase()));
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (nkg::Exception&) {
|
||||
memset(_Patch, 0, sizeof(_Patch));
|
||||
|
||||
LOG_FAILURE(0, "PatchSolution3 ...... Omitted");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
150
navicat-patcher/PatchSolution4-amd64.cpp
Normal file
150
navicat-patcher/PatchSolution4-amd64.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
#include "PatchSolutions.hpp"
|
||||
#include <xstring.hpp>
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\PatchSolution4-amd64.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
PatchSolution4::PatchSolution4(const ImageInterpreter& Image) :
|
||||
_Image(Image),
|
||||
_DisassemblyEngine(CS_ARCH_X86, CS_MODE_64),
|
||||
_AssemblyEngine(KS_ARCH_X86, KS_MODE_64),
|
||||
_pbPatchMachineCode(nullptr),
|
||||
_pbPatchNewPublicKey(nullptr) { _DisassemblyEngine.Option(CS_OPT_DETAIL, CS_OPT_ON); }
|
||||
|
||||
PatchSolution4::PatchSolution4(const ImageInterpreter* Image) :
|
||||
_Image(*Image),
|
||||
_DisassemblyEngine(CS_ARCH_X86, CS_MODE_64),
|
||||
_AssemblyEngine(KS_ARCH_X86, KS_MODE_64),
|
||||
_pbPatchMachineCode(nullptr),
|
||||
_pbPatchNewPublicKey(nullptr) { _DisassemblyEngine.Option(CS_OPT_DETAIL, CS_OPT_ON); }
|
||||
|
||||
bool PatchSolution4::FindPatchOffset() noexcept {
|
||||
try {
|
||||
_pbPatchMachineCode = _Image.SearchSection<uint8_t*>(".text", [](const uint8_t* p) {
|
||||
__try {
|
||||
return
|
||||
p[0] == 0x48 && p[1] == 0x8d && // prefix of "lea rcx, [rbp+5Fh+var_38]"
|
||||
p[4] == 0x48 && p[5] == 0x83 && // prefix of "cmp [rbp+5Fh+var_20], 10h"
|
||||
p[9] == 0x48 && p[10] == 0x0f && p[11] == 0x43 && // prefix of "cmovnb rcx, [rbp+5Fh+var_38]"
|
||||
p[14] == 0x48 && p[15] == 0x8d && // prefix of "lea rax, [rbp+5Fh+var_58]"
|
||||
p[18] == 0x48 && p[19] == 0x83 && // prefix of "cmp [rbp+5Fh+var_40], 10h"
|
||||
p[23] == 0x48 && p[24] == 0x0f && p[25] == 0x43 && // prefix of "cmovnb rax, [rbp+5Fh+var_58]"
|
||||
p[28] == 0x44 && p[29] == 0x0f && p[30] == 0xb6 && // prefix of "movzx r8d, byte ptr [rax+rdi]"
|
||||
p[33] == 0x44 && p[34] == 0x02 && // prefix of "add r8b, [rcx+rdi]"
|
||||
p[37] == 0xba && // prefix of "mov edx, 1"
|
||||
p[42] == 0x48 && p[43] == 0x8b && // prefix of "mov rcx, rbx"
|
||||
p[45] == 0xe8; // prefix of "call sub_1806E65F0"
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
auto RegisterIndex = X86_REG_INVALID;
|
||||
auto Disassembler = _DisassemblyEngine.CreateDisassembler();
|
||||
Disassembler.SetContext({ _pbPatchMachineCode, 45, _Image.PointerToVa(_pbPatchMachineCode) });
|
||||
|
||||
if (Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next()) {
|
||||
auto lpInsn = Disassembler.GetInstruction();
|
||||
if (_stricmp(lpInsn->mnemonic, "movzx") == 0 &&
|
||||
lpInsn->detail->x86.op_count == 2 &&
|
||||
lpInsn->detail->x86.operands[0].type == X86_OP_REG &&
|
||||
lpInsn->detail->x86.operands[1].type == X86_OP_MEM &&
|
||||
lpInsn->detail->x86.operands[1].size == 1 &&
|
||||
lpInsn->detail->x86.operands[1].mem.scale == 1)
|
||||
{
|
||||
RegisterIndex = lpInsn->detail->x86.operands[1].mem.index;
|
||||
} else {
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Unexpected machine code."));
|
||||
}
|
||||
} else {
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Disassemble failed."));
|
||||
}
|
||||
|
||||
if (Disassembler.Next() && Disassembler.Next() && Disassembler.Next()) {
|
||||
auto lpInsn = Disassembler.GetInstruction();
|
||||
|
||||
//
|
||||
// The previous instruction of "call sub_1806E65F0" should set RCX register.
|
||||
//
|
||||
if (_stricmp(lpInsn->mnemonic, "mov") != 0 ||
|
||||
lpInsn->detail->x86.op_count < 1 ||
|
||||
lpInsn->detail->x86.operands[0].type != X86_OP_REG ||
|
||||
lpInsn->detail->x86.operands[0].reg != X86_REG_RCX)
|
||||
{
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Unexpected machine code."));
|
||||
}
|
||||
} else {
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Disassemble failed."));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _Image.NumberOfSections(); ++i) {
|
||||
auto lpSectionHeader = _Image.ImageSectionHeader(i);
|
||||
if (lpSectionHeader->SizeOfRawData > lpSectionHeader->Misc.VirtualSize) {
|
||||
auto cbReserved =
|
||||
lpSectionHeader->SizeOfRawData -
|
||||
lpSectionHeader->Misc.VirtualSize;
|
||||
|
||||
if (cbReserved >= 0x188) {
|
||||
_pbPatchNewPublicKey = _Image.ImageSectionView<uint8_t*>(lpSectionHeader, lpSectionHeader->Misc.VirtualSize);
|
||||
|
||||
auto Assembler = _AssemblyEngine.CreateAssembler();
|
||||
_NewMachineCode = Assembler.GenerateMachineCode(
|
||||
std::xstring::format(
|
||||
TEXT(
|
||||
"lea rax, qword ptr[0x%.16llx];"
|
||||
"mov r8b, byte ptr[rax + %hs];"
|
||||
"mov edx, 1;"
|
||||
),
|
||||
_Image.PointerToVa(_pbPatchNewPublicKey),
|
||||
_DisassemblyEngine.GetRegisterName(RegisterIndex)
|
||||
).explicit_string().c_str(),
|
||||
_Image.PointerToVa(_pbPatchMachineCode)
|
||||
);
|
||||
|
||||
// >>>>>>>>>>>> .text:00000001819B02C0 48 8D 4D 27 lea rcx, [rbp + 5Fh + var_38]
|
||||
// .text:00000001819B02C4 48 83 7D 3F 10 cmp[rbp + 5Fh + var_20], 10h
|
||||
// 42 BYTES .text:00000001819B02C9 48 0F 43 4D 27 cmovnb rcx, [rbp + 5Fh + var_38]
|
||||
// .text:00000001819B02CE 48 8D 45 07 lea rax, [rbp + 5Fh + var_58]
|
||||
// THESE CODE .text:00000001819B02D2 48 83 7D 1F 10 cmp[rbp + 5Fh + var_40], 10h
|
||||
// WILL BE .text:00000001819B02D7 48 0F 43 45 07 cmovnb rax, [rbp + 5Fh + var_58]
|
||||
// REPLACED .text:00000001819B02DC 44 0F B6 04 38 movzx r8d, byte ptr[rax + rdi]
|
||||
// .text:00000001819B02E1 44 02 04 39 add r8b, [rcx + rdi]
|
||||
// <<<<<<<<<<<< .text:00000001819B02E5 BA 01 00 00 00 mov edx, 1
|
||||
// .text:00000001819B02EA 48 8B CB mov rcx, rbx
|
||||
// .text:00000001819B02ED E8 FE 62 D3 FE call sub_1806E65F0
|
||||
while (_NewMachineCode.size() < 42) {
|
||||
_NewMachineCode.emplace_back(0x90); // padding with "nop"
|
||||
}
|
||||
|
||||
if (_NewMachineCode.size() != 42) {
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Something unexpected happens."));
|
||||
}
|
||||
|
||||
LOG_SUCCESS(0, "PatchSolution4 ...... Ready to apply");
|
||||
LOG_HINT(4, "Machine code patch VA = 0x%zx", _Image.PointerToVa(_pbPatchMachineCode));
|
||||
LOG_HINT(4, "New public key VA = 0x%zx", _Image.PointerToVa(_pbPatchNewPublicKey));
|
||||
LOG_HINT(4, "New public key offset = 0x%zx", _Image.PointerToFileOffset(_pbPatchNewPublicKey));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("No space to store public key."));
|
||||
} catch (nkg::Exception&) {
|
||||
_pbPatchMachineCode = nullptr;
|
||||
_pbPatchNewPublicKey = nullptr;
|
||||
_NewMachineCode.clear();
|
||||
|
||||
LOG_FAILURE(0, "PatchSolution4 ...... Omitted");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
72
navicat-patcher/PatchSolution4-generic.cpp
Normal file
72
navicat-patcher/PatchSolution4-generic.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
#include "PatchSolutions.hpp"
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\PatchSolution4-generic.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
bool PatchSolution4::CheckKey(const RSACipher& Cipher) const noexcept {
|
||||
auto szPublicKey = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
||||
|
||||
for (auto pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("-----BEGIN PUBLIC KEY-----"));
|
||||
}
|
||||
|
||||
for (auto pos = szPublicKey.find("-----END PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----END PUBLIC KEY-----", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("-----END PUBLIC KEY-----"));
|
||||
}
|
||||
|
||||
for (auto pos = szPublicKey.find("\n"); pos != std::string::npos; pos = szPublicKey.find("\n", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("\n"));
|
||||
}
|
||||
|
||||
return szPublicKey.length() == 0x188;
|
||||
}
|
||||
|
||||
void PatchSolution4::MakePatch(const RSACipher& Cipher) const {
|
||||
if (_pbPatchMachineCode == nullptr || _pbPatchNewPublicKey == nullptr || _NewMachineCode.empty()) {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("PatchSolution4 has not been ready yet."));
|
||||
}
|
||||
|
||||
auto szPublicKey = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
||||
|
||||
for (auto pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("-----BEGIN PUBLIC KEY-----"));
|
||||
}
|
||||
|
||||
for (auto pos = szPublicKey.find("-----END PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----END PUBLIC KEY-----", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("-----END PUBLIC KEY-----"));
|
||||
}
|
||||
|
||||
for (auto pos = szPublicKey.find("\n"); pos != std::string::npos; pos = szPublicKey.find("\n", pos)) {
|
||||
szPublicKey.erase(pos, literal_length("\n"));
|
||||
}
|
||||
|
||||
_putts(TEXT("*******************************************************"));
|
||||
_putts(TEXT("* PatchSolution4 *"));
|
||||
_putts(TEXT("*******************************************************"));
|
||||
|
||||
LOG_HINT(0, "Previous:");
|
||||
PrintMemory(_pbPatchMachineCode, _NewMachineCode.size(), _Image.ImageBase());
|
||||
|
||||
memcpy(_pbPatchMachineCode, _NewMachineCode.data(), _NewMachineCode.size());
|
||||
|
||||
LOG_HINT(0, "After:");
|
||||
PrintMemory(_pbPatchMachineCode, _NewMachineCode.size(), _Image.ImageBase());
|
||||
|
||||
_putts(TEXT(""));
|
||||
|
||||
LOG_HINT(0, "Previous:");
|
||||
PrintMemory(_pbPatchNewPublicKey, szPublicKey.size(), _Image.ImageBase());
|
||||
|
||||
memcpy(_pbPatchNewPublicKey, szPublicKey.data(), szPublicKey.size());
|
||||
|
||||
LOG_HINT(0, "After:");
|
||||
PrintMemory(_pbPatchNewPublicKey, szPublicKey.size(), _Image.ImageBase());
|
||||
|
||||
_putts(TEXT(""));
|
||||
}
|
||||
}
|
||||
|
||||
145
navicat-patcher/PatchSolution4-i386.cpp
Normal file
145
navicat-patcher/PatchSolution4-i386.cpp
Normal file
@ -0,0 +1,145 @@
|
||||
#include "PatchSolutions.hpp"
|
||||
#include <xstring.hpp>
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\PatchSolution4-i386.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
namespace nkg {
|
||||
|
||||
PatchSolution4::PatchSolution4(const ImageInterpreter& Image) :
|
||||
_Image(Image),
|
||||
_DisassemblyEngine(CS_ARCH_X86, CS_MODE_32),
|
||||
_AssemblyEngine(KS_ARCH_X86, KS_MODE_32),
|
||||
_pbPatchMachineCode(nullptr),
|
||||
_pbPatchNewPublicKey(nullptr) { _DisassemblyEngine.Option(CS_OPT_DETAIL, CS_OPT_ON); }
|
||||
|
||||
PatchSolution4::PatchSolution4(const ImageInterpreter* Image) :
|
||||
_Image(*Image),
|
||||
_DisassemblyEngine(CS_ARCH_X86, CS_MODE_32),
|
||||
_AssemblyEngine(KS_ARCH_X86, KS_MODE_32),
|
||||
_pbPatchMachineCode(nullptr),
|
||||
_pbPatchNewPublicKey(nullptr) { _DisassemblyEngine.Option(CS_OPT_DETAIL, CS_OPT_ON); }
|
||||
|
||||
bool PatchSolution4::FindPatchOffset() noexcept {
|
||||
try {
|
||||
_pbPatchMachineCode = _Image.SearchSection<uint8_t*>(".text", [](const uint8_t* p) {
|
||||
__try {
|
||||
return
|
||||
p[0] == 0x83 && // prefix of "cmp [ebp+var_30], 10h"
|
||||
p[4] == 0x8d && // prefix of "lea ecx, [ebp+Dst]"
|
||||
p[7] == 0x8d && // prefix of "lea eax, [ebp+Memory]"
|
||||
p[10] == 0x0f && p[11] == 0x43 && // prefix of "cmovnb ecx, [ebp+Dst]"
|
||||
p[14] == 0x83 && // prefix of "cmp [ebp+var_18], 10h"
|
||||
p[18] == 0x0f && p[19] == 0x43 && // prefix of "cmovnb eax, [ebp+Memory]"
|
||||
p[22] == 0x8a && // prefix of "mov dl, [eax+ebx]"
|
||||
p[25] == 0x02; // prefix of "add dl, [ecx+ebx]"
|
||||
// p[28]
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
auto RegisterIndex = X86_REG_INVALID;
|
||||
auto RegisterFinalValue = X86_REG_INVALID;
|
||||
auto Disassembler = _DisassemblyEngine.CreateDisassembler();
|
||||
Disassembler.SetContext({ _pbPatchMachineCode, 28, _Image.PointerToVa(_pbPatchMachineCode) });
|
||||
|
||||
if (Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next()) {
|
||||
auto lpInsn = Disassembler.GetInstruction();
|
||||
if (_stricmp(lpInsn->mnemonic, "mov") == 0 &&
|
||||
lpInsn->detail->x86.op_count == 2 &&
|
||||
lpInsn->detail->x86.operands[0].type == X86_OP_REG &&
|
||||
lpInsn->detail->x86.operands[1].type == X86_OP_MEM &&
|
||||
lpInsn->detail->x86.operands[1].size == 1 &&
|
||||
lpInsn->detail->x86.operands[1].mem.scale == 1)
|
||||
{
|
||||
RegisterIndex = lpInsn->detail->x86.operands[1].mem.index;
|
||||
} else {
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Unexpected machine code."));
|
||||
}
|
||||
} else {
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Disassemble failed."));
|
||||
}
|
||||
|
||||
if (Disassembler.Next()) {
|
||||
auto lpInsn = Disassembler.GetInstruction();
|
||||
if (_stricmp(lpInsn->mnemonic, "add") == 0 &&
|
||||
lpInsn->detail->x86.op_count >= 1 &&
|
||||
lpInsn->detail->x86.operands[0].type == X86_OP_REG &&
|
||||
lpInsn->detail->x86.operands[0].size == 1)
|
||||
{
|
||||
RegisterFinalValue = lpInsn->detail->x86.operands[0].reg;
|
||||
} else {
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Unexpected machine code."));
|
||||
}
|
||||
} else {
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Disassemble failed."));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _Image.NumberOfSections(); ++i) {
|
||||
auto lpSectionHeader = _Image.ImageSectionHeader(i);
|
||||
if (lpSectionHeader->SizeOfRawData > lpSectionHeader->Misc.VirtualSize) {
|
||||
auto cbReserved =
|
||||
lpSectionHeader->SizeOfRawData -
|
||||
lpSectionHeader->Misc.VirtualSize;
|
||||
|
||||
if (cbReserved >= 0x188) {
|
||||
_pbPatchNewPublicKey = _Image.ImageSectionView<uint8_t*>(lpSectionHeader, lpSectionHeader->Misc.VirtualSize);
|
||||
|
||||
auto Assembler = _AssemblyEngine.CreateAssembler();
|
||||
_NewMachineCode = Assembler.GenerateMachineCode(
|
||||
std::xstring::format(
|
||||
TEXT(
|
||||
"call +5;"
|
||||
"pop eax;"
|
||||
"add eax, 0x%.8x;"
|
||||
"mov %hs, byte ptr [eax + %hs];"
|
||||
),
|
||||
_Image.PointerToVa(_pbPatchNewPublicKey) - (_Image.PointerToVa(_pbPatchMachineCode) + 5),
|
||||
_DisassemblyEngine.GetRegisterName(RegisterFinalValue),
|
||||
_DisassemblyEngine.GetRegisterName(RegisterIndex)
|
||||
).explicit_string().c_str()
|
||||
);
|
||||
|
||||
// >>>>>>>>>>>> .text:113FE4A0 83 7D D0 10 cmp [ebp+var_30], 10h
|
||||
// 28 BYTES .text:113FE4A4 8D 4D BC lea ecx, [ebp+Dst]
|
||||
// .text:113FE4A7 8D 45 D4 lea eax, [ebp+Memory]
|
||||
// THESE CODE .text:113FE4AA 0F 43 4D BC cmovnb ecx, [ebp+Dst]
|
||||
// WILL BE .text:113FE4AE 83 7D E8 10 cmp [ebp+var_18], 10h
|
||||
// REPLACED .text:113FE4B2 0F 43 45 D4 cmovnb eax, [ebp+Memory]
|
||||
// .text:113FE4B6 8A 14 18 mov dl, [eax+ebx]
|
||||
// <<<<<<<<<<<< .text:113FE4B9 02 14 19 add dl, [ecx+ebx]
|
||||
while (_NewMachineCode.size() < 28) {
|
||||
_NewMachineCode.emplace_back(0x90); // padding with "nop"
|
||||
}
|
||||
|
||||
if (_NewMachineCode.size() != 28) {
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Something unexpected happens."));
|
||||
}
|
||||
|
||||
LOG_SUCCESS(0, "PatchSolution4 ...... Ready to apply");
|
||||
LOG_HINT(4, "Machine code patch VA = 0x%zx", _Image.PointerToVa(_pbPatchMachineCode));
|
||||
LOG_HINT(4, "New public key VA = 0x%zx", _Image.PointerToVa(_pbPatchNewPublicKey));
|
||||
LOG_HINT(4, "New public key offset = 0x%zx", _Image.PointerToFileOffset(_pbPatchNewPublicKey));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("No space to store public key."));
|
||||
} catch (nkg::Exception&) {
|
||||
_pbPatchMachineCode = nullptr;
|
||||
_pbPatchNewPublicKey = nullptr;
|
||||
_NewMachineCode.clear();
|
||||
|
||||
LOG_FAILURE(0, "PatchSolution4 ...... Omitted");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
234
navicat-patcher/PatchSolutions.hpp
Normal file
234
navicat-patcher/PatchSolutions.hpp
Normal file
@ -0,0 +1,234 @@
|
||||
#pragma once
|
||||
#include <RSACipher.hpp>
|
||||
#include "ImageInterpreter.hpp"
|
||||
#include "CapstoneDisassembler.hpp"
|
||||
#include "KeystoneAssembler.hpp"
|
||||
#include "Misc.hpp"
|
||||
|
||||
namespace nkg {
|
||||
|
||||
class PatchSolution {
|
||||
protected:
|
||||
|
||||
static constexpr size_t InvalidOffset = -1;
|
||||
|
||||
public:
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool FindPatchOffset() noexcept = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool CheckKey(const RSACipher& Cipher) const noexcept = 0;
|
||||
|
||||
virtual void MakePatch(const RSACipher& Cipher) const = 0;
|
||||
|
||||
virtual ~PatchSolution() = default;
|
||||
};
|
||||
|
||||
//
|
||||
// PatchSolution0 will replace the RSA public key stored in navicat.exe
|
||||
//
|
||||
class PatchSolution0 final : public PatchSolution {
|
||||
private:
|
||||
|
||||
static const char Keyword[461];
|
||||
|
||||
const ImageInterpreter& _Image;
|
||||
size_t _PatchOffset;
|
||||
|
||||
public:
|
||||
|
||||
PatchSolution0(const ImageInterpreter& Image) noexcept :
|
||||
_Image(Image),
|
||||
_PatchOffset(InvalidOffset) {}
|
||||
|
||||
PatchSolution0(const ImageInterpreter* lpImage) noexcept :
|
||||
_Image(*lpImage),
|
||||
_PatchOffset(InvalidOffset) {}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool FindPatchOffset() noexcept override;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool CheckKey(const RSACipher& Cipher) const noexcept override;
|
||||
|
||||
virtual void MakePatch(const RSACipher& Cipher) const override;
|
||||
};
|
||||
|
||||
//
|
||||
// PatchSolution1 will replace the RSA public key stored in libcc.dll
|
||||
//
|
||||
class PatchSolution1 final : public PatchSolution {
|
||||
private:
|
||||
|
||||
static const char Keyword0[160 + 1];
|
||||
static const char Keyword1[4 + 1];
|
||||
static const char Keyword2[742 + 1];
|
||||
static const char Keyword3[4 + 1];
|
||||
static const char Keyword4[5 + 1];
|
||||
|
||||
const ImageInterpreter& _Image;
|
||||
size_t _PatchOffset[5];
|
||||
size_t _PatchSize[5];
|
||||
|
||||
public:
|
||||
|
||||
PatchSolution1(const ImageInterpreter& Image) noexcept :
|
||||
_Image(Image),
|
||||
_PatchOffset{ InvalidOffset , InvalidOffset , InvalidOffset , InvalidOffset , InvalidOffset },
|
||||
_PatchSize{} {}
|
||||
|
||||
PatchSolution1(const ImageInterpreter* lpImage) noexcept :
|
||||
_Image(*lpImage),
|
||||
_PatchOffset{ InvalidOffset , InvalidOffset , InvalidOffset , InvalidOffset , InvalidOffset },
|
||||
_PatchSize{} {}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool FindPatchOffset() noexcept override;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool CheckKey(const RSACipher& Cipher) const noexcept override;
|
||||
|
||||
virtual void MakePatch(const RSACipher& Cipher) const override;
|
||||
};
|
||||
|
||||
//
|
||||
// PatchSolution2 will replace the RSA public key stored in libcc.dll
|
||||
//
|
||||
class PatchSolution2 final : public PatchSolution {
|
||||
private:
|
||||
|
||||
static const char KeywordMeta[0x188 + 1];
|
||||
static const uint8_t Keyword[0x188][5];
|
||||
|
||||
const ImageInterpreter& _Image;
|
||||
size_t _PatchOffset[0x188];
|
||||
|
||||
public:
|
||||
|
||||
PatchSolution2(const ImageInterpreter& Image) noexcept :
|
||||
_Image(Image),
|
||||
_PatchOffset{}
|
||||
{
|
||||
for (size_t i = 0; i < _countof(_PatchOffset); ++i) {
|
||||
_PatchOffset[i] = InvalidOffset;
|
||||
}
|
||||
}
|
||||
|
||||
PatchSolution2(const ImageInterpreter* lpImage) noexcept :
|
||||
_Image(*lpImage),
|
||||
_PatchOffset{}
|
||||
{
|
||||
for (size_t i = 0; i < _countof(_PatchOffset); ++i) {
|
||||
_PatchOffset[i] = InvalidOffset;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool FindPatchOffset() noexcept override;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool CheckKey(const RSACipher& Cipher) const noexcept override;
|
||||
|
||||
virtual void MakePatch(const RSACipher& Cipher) const override;
|
||||
};
|
||||
|
||||
//
|
||||
// PatchSolution3 will replace the RSA public key stored in libcc.dll
|
||||
//
|
||||
class PatchSolution3 final : public PatchSolution {
|
||||
private:
|
||||
|
||||
using KeywordValueType = uint8_t[8];
|
||||
|
||||
using KeywordSizeType = size_t;
|
||||
|
||||
enum KeywordTypeEnum { IMM_DATA, STRING_DATA };
|
||||
|
||||
struct KeywordInfo {
|
||||
KeywordValueType Value;
|
||||
KeywordSizeType Size;
|
||||
KeywordTypeEnum Type;
|
||||
bool NotRecommendedToModify;
|
||||
};
|
||||
|
||||
struct PatchInfo {
|
||||
uint64_t OpcodeRva;
|
||||
void* lpOpcode;
|
||||
void* lpPatch;
|
||||
size_t cbPatch;
|
||||
char* lpOriginalString;
|
||||
char* lpReplaceString;
|
||||
};
|
||||
|
||||
static const KeywordInfo Keyword[111];
|
||||
|
||||
const ImageInterpreter& _Image;
|
||||
CapstoneEngine _Engine;
|
||||
mutable PatchInfo _Patch[111];
|
||||
|
||||
[[nodiscard]]
|
||||
static bool IsPrintable(const void* p, size_t s) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
bool CheckIfMatchPattern(const cs_insn* lpInsn) const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
bool CheckIfFound(const cs_insn* lpInsn, size_t KeywordIdx) const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
PatchInfo CreatePatchPoint(const void* lpOpcode, const cs_insn* lpInsn, size_t KeywordIdx) const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
CapstoneContext GetJumpedBranch(const CapstoneContext& Bifurcation, const cs_insn* lpJxxInsn) const;
|
||||
|
||||
[[nodiscard]]
|
||||
CapstoneContext SelectBranch(const CapstoneContext& NotJumpedBranch, const CapstoneContext& JumpedBranch, size_t KeywordIdx) const;
|
||||
|
||||
public:
|
||||
|
||||
PatchSolution3(const ImageInterpreter& Image);
|
||||
|
||||
PatchSolution3(const ImageInterpreter* lpImage);
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool FindPatchOffset() noexcept override;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool CheckKey(const RSACipher& Cipher) const noexcept override;
|
||||
|
||||
virtual void MakePatch(const RSACipher& Cipher) const override;
|
||||
};
|
||||
|
||||
//
|
||||
// PatchSolution3 will replace the RSA public key stored in libcc.dll
|
||||
// For Navicat Data Modeler 3
|
||||
//
|
||||
class PatchSolution4 : public PatchSolution {
|
||||
private:
|
||||
|
||||
static const uint8_t KeywordA[0x188];
|
||||
static const uint8_t KeywordB[0x188];
|
||||
|
||||
const ImageInterpreter& _Image;
|
||||
CapstoneEngine _DisassemblyEngine;
|
||||
KeystoneEngine _AssemblyEngine;
|
||||
uint8_t* _pbPatchMachineCode;
|
||||
uint8_t* _pbPatchNewPublicKey;
|
||||
std::vector<uint8_t> _NewMachineCode;
|
||||
|
||||
public:
|
||||
|
||||
PatchSolution4(const ImageInterpreter& Image);
|
||||
|
||||
PatchSolution4(const ImageInterpreter* lpImage);
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool FindPatchOffset() noexcept override;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool CheckKey(const RSACipher& Cipher) const noexcept override;
|
||||
|
||||
virtual void MakePatch(const RSACipher& Cipher) const override;
|
||||
};
|
||||
}
|
||||
33
navicat-patcher/ResourceTraitsCapstone.hpp
Normal file
33
navicat-patcher/ResourceTraitsCapstone.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include <capstone/capstone.h>
|
||||
|
||||
struct CapstoneHandleTraits {
|
||||
using HandleType = csh;
|
||||
|
||||
static inline const HandleType InvalidValue = NULL;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool IsValid(const HandleType& Handle) noexcept {
|
||||
return Handle != InvalidValue;
|
||||
}
|
||||
|
||||
static void Releasor(HandleType& Handle) noexcept {
|
||||
cs_close(&Handle);
|
||||
}
|
||||
};
|
||||
|
||||
struct CapstoneInsnTraits {
|
||||
using HandleType = cs_insn*;
|
||||
|
||||
static inline const HandleType InvalidValue = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool IsValid(const HandleType& Handle) noexcept {
|
||||
return Handle != InvalidValue;
|
||||
}
|
||||
|
||||
static void Releasor(const HandleType& Handle) noexcept {
|
||||
cs_free(Handle, 1);
|
||||
}
|
||||
};
|
||||
|
||||
33
navicat-patcher/ResourceTraitsKeystone.hpp
Normal file
33
navicat-patcher/ResourceTraitsKeystone.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include <keystone/keystone.h>
|
||||
|
||||
struct KeystoneHandleTraits {
|
||||
using HandleType = ks_engine*;
|
||||
|
||||
static inline const HandleType InvalidValue = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool IsValid(const HandleType& Handle) noexcept {
|
||||
return Handle != InvalidValue;
|
||||
}
|
||||
|
||||
static void Releasor(const HandleType& Handle) noexcept {
|
||||
ks_close(Handle);
|
||||
}
|
||||
};
|
||||
|
||||
struct KeystoneMallocTraits {
|
||||
using HandleType = uint8_t*;
|
||||
|
||||
static inline const HandleType InvalidValue = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool IsValid(const HandleType& Handle) noexcept {
|
||||
return Handle != InvalidValue;
|
||||
}
|
||||
|
||||
static void Releasor(const HandleType& Handle) noexcept {
|
||||
ks_free(Handle);
|
||||
}
|
||||
};
|
||||
|
||||
459
navicat-patcher/_tmain.cpp
Normal file
459
navicat-patcher/_tmain.cpp
Normal file
@ -0,0 +1,459 @@
|
||||
#include <tchar.h>
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <Exception.hpp>
|
||||
#include <ExceptionWin32.hpp>
|
||||
#include <ResourceOwned.hpp>
|
||||
#include <ResourceTraitsWin32.hpp>
|
||||
#include "ImageInterpreter.hpp"
|
||||
#include "PatchSolutions.hpp"
|
||||
#include "Misc.hpp"
|
||||
|
||||
#undef NKG_CURRENT_SOURCE_FILE
|
||||
#undef NKG_CURRENT_SOURCE_LINE
|
||||
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\_tmain.cpp")
|
||||
#define NKG_CURRENT_SOURCE_LINE() __LINE__
|
||||
|
||||
static void Welcome() {
|
||||
_putts(TEXT("***************************************************"));
|
||||
_putts(TEXT("* Navicat Patcher by @DoubleLabyrinth *"));
|
||||
_putts(TEXT("* Version: 4.1 *"));
|
||||
_putts(TEXT("***************************************************"));
|
||||
_putts(TEXT(""));
|
||||
_putts(TEXT("Press Enter to continue or Ctrl + C to abort."));
|
||||
auto c = _gettchar();
|
||||
while (c != TEXT('\n') && _gettchar() != TEXT('\n')) {}
|
||||
}
|
||||
|
||||
static void Help() {
|
||||
_putts(TEXT("***************************************************"));
|
||||
_putts(TEXT("* Navicat Patcher by @DoubleLabyrinth *"));
|
||||
_putts(TEXT("* Version: 4.1 *"));
|
||||
_putts(TEXT("***************************************************"));
|
||||
_putts(TEXT(""));
|
||||
_putts(TEXT("Usage:"));
|
||||
_putts(TEXT(" navicat-patcher.exe [-dry-run] <Navicat Installation Path> [RSA-2048 PEM File Path]"));
|
||||
_putts(TEXT(""));
|
||||
_putts(TEXT(" [-dry-run] Run patcher without applying any patches."));
|
||||
_putts(TEXT(" This parameter is optional."));
|
||||
_putts(TEXT(""));
|
||||
_putts(TEXT(" <Navicat Installation Path> The folder path where Navicat is installed."));
|
||||
_putts(TEXT(" This parameter must be specified."));
|
||||
_putts(TEXT(""));
|
||||
_putts(TEXT(" [RSA-2048 PEM File Path] The path to an RSA-2048 private key file."));
|
||||
_putts(TEXT(" This parameter is optional."));
|
||||
_putts(TEXT(" If not specified, an RSA-2048 private key file"));
|
||||
_putts(TEXT(" named \"RegPrivateKey.pem\" will be generated."));
|
||||
_putts(TEXT(""));
|
||||
_putts(TEXT("Example:"));
|
||||
_putts(TEXT(" navicat-patcher.exe \"C:\\Program Files\\PremiumSoft\\Navicat Premium 12\""));
|
||||
}
|
||||
|
||||
static bool ParseCommandLine(int argc, PTSTR argv[], bool& bDryRun, std::xstring& NavInstallPath, std::xstring& RsaPrivateKeyPath) {
|
||||
if (argc == 2) {
|
||||
bDryRun = false;
|
||||
NavInstallPath = argv[1];
|
||||
RsaPrivateKeyPath.clear();
|
||||
return true;
|
||||
} else if (argc == 3) {
|
||||
if (_tcsicmp(argv[1], TEXT("-dry-run")) == 0) {
|
||||
bDryRun = true;
|
||||
NavInstallPath = argv[2];
|
||||
RsaPrivateKeyPath.clear();
|
||||
return true;
|
||||
} else {
|
||||
bDryRun = false;
|
||||
NavInstallPath = argv[1];
|
||||
RsaPrivateKeyPath = argv[2];
|
||||
return true;
|
||||
}
|
||||
} else if (argc == 4) {
|
||||
if (_tcsicmp(argv[1], TEXT("-dry-run")) == 0) {
|
||||
bDryRun = true;
|
||||
NavInstallPath = argv[2];
|
||||
RsaPrivateKeyPath = argv[3];
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void SelectPatchSolutions(
|
||||
ResourceOwned<CppObjectTraits<nkg::PatchSolution>>& lpSolution0,
|
||||
ResourceOwned<CppObjectTraits<nkg::PatchSolution>>& lpSolution1,
|
||||
ResourceOwned<CppObjectTraits<nkg::PatchSolution>>& lpSolution2,
|
||||
ResourceOwned<CppObjectTraits<nkg::PatchSolution>>& lpSolution3)
|
||||
{
|
||||
// if RSA public is detected in libcc.dll, don't patch main application to keep digital signature valid.
|
||||
if ((lpSolution1.IsValid() || lpSolution2.IsValid() || lpSolution3.IsValid()) && lpSolution0.IsValid()) {
|
||||
LOG_HINT(0, "PatchSolution0 is suppressed in order to keep digital signature valid.");
|
||||
lpSolution0.Release();
|
||||
}
|
||||
}
|
||||
|
||||
static void NavicatBackupDetect(const std::xstring& FilePath) {
|
||||
if (std::xstring BackupPath = FilePath + TEXT(".backup"); nkg::IsValidFilePath(BackupPath.c_str()) == true) {
|
||||
while (true) {
|
||||
LOG_SELECT(0, "Previous backup %s detected. Delete? (y/n)", BackupPath.c_str());
|
||||
|
||||
auto select = _gettchar();
|
||||
while (select != TEXT('\n') && _gettchar() != TEXT('\n')) {}
|
||||
if (select == TEXT('Y') || select == TEXT('y')) {
|
||||
if (!DeleteFile(BackupPath.c_str())) {
|
||||
throw nkg::Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("Failed to delete backup file."));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (select == TEXT('N') || select == TEXT('n')) {
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Backup file still existed. Patch abort!"));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
_putts(TEXT(""));
|
||||
}
|
||||
}
|
||||
|
||||
static void NavicatBackupMake(const std::xstring& FilePath) {
|
||||
std::xstring BackupPath = FilePath + TEXT(".backup");
|
||||
if (CopyFile(FilePath.c_str(), BackupPath.c_str(), TRUE) == FALSE) {
|
||||
throw nkg::Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("CopyFile failed."));
|
||||
}
|
||||
}
|
||||
|
||||
static void LoadKey(
|
||||
nkg::RSACipher& Cipher, const std::xstring& KeyFilePath,
|
||||
nkg::PatchSolution* pSolution0,
|
||||
nkg::PatchSolution* pSolution1,
|
||||
nkg::PatchSolution* pSolution2,
|
||||
nkg::PatchSolution* pSolution3,
|
||||
nkg::PatchSolution* pSolution4)
|
||||
{
|
||||
if (KeyFilePath.empty() == false) {
|
||||
LOG_HINT(0, "Import RSA-2048 key from %s", KeyFilePath.c_str());
|
||||
|
||||
Cipher.ImportKeyFromFile<nkg::RSAKeyType::PrivateKey, nkg::RSAKeyFormat::PEM>(KeyFilePath);
|
||||
|
||||
if (pSolution0 && !pSolution0->CheckKey(Cipher) ||
|
||||
pSolution1 && !pSolution1->CheckKey(Cipher) ||
|
||||
pSolution2 && !pSolution2->CheckKey(Cipher) ||
|
||||
pSolution3 && !pSolution3->CheckKey(Cipher) ||
|
||||
pSolution4 && !pSolution4->CheckKey(Cipher))
|
||||
{
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("The RSA private key you provide cannot be used."));
|
||||
}
|
||||
} else {
|
||||
LOG_HINT(0, "Generating new RSA private key, it may take a long time...");
|
||||
|
||||
do {
|
||||
Cipher.GenerateKey(2048);
|
||||
} while (pSolution0 && !pSolution0->CheckKey(Cipher) ||
|
||||
pSolution1 && !pSolution1->CheckKey(Cipher) ||
|
||||
pSolution2 && !pSolution2->CheckKey(Cipher) ||
|
||||
pSolution3 && !pSolution3->CheckKey(Cipher) ||
|
||||
pSolution4 && !pSolution4->CheckKey(Cipher)); // re-generate RSA key if one of 'CheckKey's return false
|
||||
}
|
||||
|
||||
LOG_HINT(0, "Your RSA public key:\n%hs", Cipher.ExportKeyString<nkg::RSAKeyType::PublicKey, nkg::RSAKeyFormat::PEM>().c_str());
|
||||
}
|
||||
|
||||
int _tmain(int argc, PTSTR argv[]) {
|
||||
bool bDryRun;
|
||||
std::xstring NavInstallPath;
|
||||
std::xstring RsaPrivateKeyPath;
|
||||
|
||||
if (ParseCommandLine(argc, argv, bDryRun, NavInstallPath, RsaPrivateKeyPath) == false) {
|
||||
Help();
|
||||
return -1;
|
||||
} else {
|
||||
Welcome();
|
||||
|
||||
try {
|
||||
if (nkg::IsValidDirectoryPath(NavInstallPath.c_str()) == false) {
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Navicat installation path doesn't point to a directory."))
|
||||
.AddHint(TEXT("Are you sure the path you specified is correct?"))
|
||||
.AddHint(std::xstring::format(TEXT("The path you specified: %s"), NavInstallPath.c_str()));
|
||||
}
|
||||
|
||||
if (RsaPrivateKeyPath.empty() == false && nkg::IsValidFilePath(RsaPrivateKeyPath.c_str()) == false) {
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("RSA key file path doesn't point to a file."))
|
||||
.AddHint(TEXT("Are you sure the path you specified is correct?"))
|
||||
.AddHint(std::xstring::format(TEXT("The path you specified: %s"), RsaPrivateKeyPath.c_str()));
|
||||
}
|
||||
|
||||
while (NavInstallPath.back() == TEXT('\\') || NavInstallPath.back() == TEXT('/')) {
|
||||
NavInstallPath.pop_back();
|
||||
}
|
||||
|
||||
NavInstallPath.push_back(nkg::IsWineEnvironment() ? TEXT('/') : TEXT('\\'));
|
||||
|
||||
nkg::RSACipher Cipher;
|
||||
|
||||
std::xstring MainExePath;
|
||||
ResourceOwned hMainExe(FileHandleTraits{});
|
||||
ResourceOwned hMainExeMapping(GenericHandleTraits{});
|
||||
ResourceOwned lpMainExeMapping(MapViewHandleTraits{});
|
||||
ResourceOwned lpMainExeInterpreter(CppObjectTraits<nkg::ImageInterpreter>{});
|
||||
|
||||
std::xstring LibccDllPath;
|
||||
ResourceOwned hLibccDll(FileHandleTraits{});
|
||||
ResourceOwned hLibccDllMapping(GenericHandleTraits{});
|
||||
ResourceOwned lpLibccDllMapping(MapViewHandleTraits{});
|
||||
ResourceOwned lpLibccDllInterpreter(CppObjectTraits<nkg::ImageInterpreter>{});
|
||||
|
||||
ResourceOwned lpSolution0(CppObjectTraits<nkg::PatchSolution>{});
|
||||
ResourceOwned lpSolution1(CppObjectTraits<nkg::PatchSolution>{});
|
||||
ResourceOwned lpSolution2(CppObjectTraits<nkg::PatchSolution>{});
|
||||
ResourceOwned lpSolution3(CppObjectTraits<nkg::PatchSolution>{});
|
||||
ResourceOwned lpSolution4(CppObjectTraits<nkg::PatchSolution>{});
|
||||
|
||||
//
|
||||
// Open main application
|
||||
//
|
||||
do {
|
||||
MainExePath = NavInstallPath + TEXT("Navicat.exe");
|
||||
hMainExe.TakeOver(
|
||||
CreateFile(MainExePath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)
|
||||
);
|
||||
if (hMainExe.IsValid()) {
|
||||
LOG_SUCCESS(0, "Try to open Navicat.exe ... Ok!");
|
||||
break;
|
||||
} else if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
||||
LOG_FAILURE(0, "Try to open Navicat.exe ... Not found!");
|
||||
} else {
|
||||
throw nkg::Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("Failed to open Navicat.exe"));
|
||||
}
|
||||
|
||||
MainExePath = NavInstallPath + TEXT("Modeler.exe");
|
||||
hMainExe.TakeOver(
|
||||
CreateFile(MainExePath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)
|
||||
);
|
||||
if (hMainExe.IsValid()) {
|
||||
LOG_SUCCESS(0, "Try to open Modeler.exe ... Ok!");
|
||||
break;
|
||||
} else if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
||||
LOG_FAILURE(0, "Try to open Modeler.exe ... Not found!");
|
||||
} else {
|
||||
throw nkg::Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("Failed to open Modeler.exe"));
|
||||
}
|
||||
|
||||
MainExePath = NavInstallPath + TEXT("Rviewer.exe");
|
||||
hMainExe.TakeOver(
|
||||
CreateFile(MainExePath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)
|
||||
);
|
||||
if (hMainExe.IsValid()) {
|
||||
LOG_SUCCESS(0, "Try to open Rviewer.exe ... Ok!");
|
||||
break;
|
||||
} else if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
||||
LOG_FAILURE(0, "Try to open Rviewer.exe ... Not found!");
|
||||
} else {
|
||||
throw nkg::Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("Failed to open Rviewer.exe"));
|
||||
}
|
||||
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Main application is not found."))
|
||||
.AddHint(TEXT("Are you sure you specified a valid Navicat installation path?"))
|
||||
.AddHint(std::xstring::format(TEXT("The path you specified: %s"), NavInstallPath.c_str()));
|
||||
} while (false);
|
||||
|
||||
//
|
||||
// Open libcc.dll, if have
|
||||
//
|
||||
do {
|
||||
LibccDllPath = NavInstallPath + TEXT("libcc.dll");
|
||||
hLibccDll.TakeOver(
|
||||
CreateFile(LibccDllPath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)
|
||||
);
|
||||
if (hLibccDll.IsValid()) {
|
||||
LOG_SUCCESS(0, "Try to open libcc.dll ... Ok!");
|
||||
break;
|
||||
} else if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
||||
LOG_FAILURE(0, "Try to open libcc.dll ... Not found!");
|
||||
} else {
|
||||
throw nkg::Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("Failed to open libcc.dll"));
|
||||
}
|
||||
} while (false);
|
||||
|
||||
_putts(TEXT(""));
|
||||
|
||||
//
|
||||
// Map main application
|
||||
//
|
||||
hMainExeMapping.TakeOver(CreateFileMapping(hMainExe, NULL, PAGE_READWRITE, 0, 0, NULL));
|
||||
if (hMainExeMapping.IsValid() == false) {
|
||||
throw nkg::Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("CreateFileMapping failed."));
|
||||
}
|
||||
|
||||
lpMainExeMapping.TakeOver(MapViewOfFile(hMainExeMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0));
|
||||
if (hMainExeMapping.IsValid() == false) {
|
||||
throw nkg::Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("MapViewOfFile failed."));
|
||||
}
|
||||
|
||||
lpMainExeInterpreter.TakeOver(
|
||||
new nkg::ImageInterpreter(nkg::ImageInterpreter::ParseImage(lpMainExeMapping))
|
||||
);
|
||||
|
||||
lpSolution0.TakeOver(new nkg::PatchSolution0(lpMainExeInterpreter));
|
||||
|
||||
//
|
||||
// Map libcc.dll, if have
|
||||
//
|
||||
if (hLibccDll.IsValid()) {
|
||||
hLibccDllMapping.TakeOver(CreateFileMapping(hLibccDll, NULL, PAGE_READWRITE, 0, 0, NULL));
|
||||
if (hMainExeMapping.IsValid() == false) {
|
||||
throw nkg::Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("CreateFileMapping failed."));
|
||||
}
|
||||
|
||||
lpLibccDllMapping.TakeOver(MapViewOfFile(hLibccDllMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0));
|
||||
if (hMainExeMapping.IsValid() == false) {
|
||||
throw nkg::Win32Error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), GetLastError(), TEXT("MapViewOfFile failed."));
|
||||
}
|
||||
|
||||
lpLibccDllInterpreter.TakeOver(
|
||||
new nkg::ImageInterpreter(nkg::ImageInterpreter::ParseImage(lpLibccDllMapping))
|
||||
);
|
||||
|
||||
lpSolution1.TakeOver(new nkg::PatchSolution1(lpLibccDllInterpreter));
|
||||
lpSolution2.TakeOver(new nkg::PatchSolution2(lpLibccDllInterpreter));
|
||||
lpSolution3.TakeOver(new nkg::PatchSolution3(lpLibccDllInterpreter));
|
||||
lpSolution4.TakeOver(new nkg::PatchSolution4(lpLibccDllInterpreter));
|
||||
}
|
||||
|
||||
//
|
||||
// Finding patch offsets
|
||||
//
|
||||
|
||||
if (lpSolution0->FindPatchOffset() == false) {
|
||||
lpSolution0.Release();
|
||||
}
|
||||
|
||||
if (lpSolution1.IsValid() && lpSolution1->FindPatchOffset() == false) {
|
||||
lpSolution1.Release();
|
||||
}
|
||||
|
||||
if (lpSolution2.IsValid() && lpSolution2->FindPatchOffset() == false) {
|
||||
lpSolution2.Release();
|
||||
}
|
||||
|
||||
if (lpSolution3.IsValid() && lpSolution3->FindPatchOffset() == false) {
|
||||
lpSolution3.Release();
|
||||
}
|
||||
|
||||
if (lpSolution4.IsValid() && lpSolution4->FindPatchOffset() == false) {
|
||||
lpSolution4.Release();
|
||||
}
|
||||
|
||||
_putts(TEXT(""));
|
||||
|
||||
//
|
||||
// decide which solutions will be applied
|
||||
//
|
||||
SelectPatchSolutions(lpSolution0, lpSolution1, lpSolution2, lpSolution3);
|
||||
|
||||
if (lpSolution0.IsValid() == false && lpSolution1.IsValid() == false && lpSolution2.IsValid() == false && lpSolution3.IsValid() == false && lpSolution4.IsValid() == false) {
|
||||
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("No patch applied. Patch abort!"))
|
||||
.AddHint(TEXT("Are you sure your Navicat has not been patched/modified before?"));
|
||||
}
|
||||
|
||||
_putts(TEXT(""));
|
||||
|
||||
//
|
||||
// detecting backups
|
||||
//
|
||||
if (lpSolution0.IsValid()) {
|
||||
NavicatBackupDetect(MainExePath);
|
||||
}
|
||||
|
||||
if (lpSolution1.IsValid() || lpSolution2.IsValid() || lpSolution3.IsValid() || lpSolution4.IsValid()) {
|
||||
NavicatBackupDetect(LibccDllPath);
|
||||
}
|
||||
|
||||
//
|
||||
// Loading key
|
||||
//
|
||||
LoadKey(Cipher, RsaPrivateKeyPath, lpSolution0, lpSolution1, lpSolution2, lpSolution3, lpSolution4);
|
||||
|
||||
if (bDryRun == false) {
|
||||
//
|
||||
// Saving private key if not given
|
||||
//
|
||||
if (RsaPrivateKeyPath.empty()) {
|
||||
Cipher.ExportKeyToFile<nkg::RSAKeyType::PrivateKey, nkg::RSAKeyFormat::PEM>(std::xstring{ std::xstring_extension{}, "RegPrivateKey.pem" });
|
||||
}
|
||||
|
||||
//
|
||||
// Making backups
|
||||
//
|
||||
if (lpSolution0.IsValid()) {
|
||||
NavicatBackupMake(MainExePath);
|
||||
}
|
||||
|
||||
if (lpSolution1.IsValid() || lpSolution2.IsValid() || lpSolution3.IsValid() || lpSolution4.IsValid()) {
|
||||
NavicatBackupMake(LibccDllPath);
|
||||
}
|
||||
|
||||
//
|
||||
// Making patch. No way to go back here :-)
|
||||
//
|
||||
if (lpSolution0.IsValid()) {
|
||||
lpSolution0->MakePatch(Cipher);
|
||||
}
|
||||
|
||||
if (lpSolution1.IsValid()) {
|
||||
lpSolution1->MakePatch(Cipher);
|
||||
}
|
||||
|
||||
if (lpSolution2.IsValid()) {
|
||||
lpSolution2->MakePatch(Cipher);
|
||||
}
|
||||
|
||||
if (lpSolution3.IsValid()) {
|
||||
lpSolution3->MakePatch(Cipher);
|
||||
}
|
||||
|
||||
if (lpSolution4.IsValid()) {
|
||||
lpSolution4->MakePatch(Cipher);
|
||||
}
|
||||
|
||||
if (RsaPrivateKeyPath.empty()) {
|
||||
LOG_HINT(
|
||||
0,
|
||||
"New RSA-2048 private key has been saved to\n%s%cRegPrivateKey.pem",
|
||||
nkg::GetCurrentWorkingDirectory().c_str(),
|
||||
nkg::IsWineEnvironment() ? TEXT('/') : TEXT('\\')
|
||||
);
|
||||
|
||||
_putts(TEXT(""));
|
||||
}
|
||||
|
||||
_putts(TEXT("*******************************************************"));
|
||||
_putts(TEXT("* PATCH HAS BEEN DONE SUCCESSFULLY! *"));
|
||||
_putts(TEXT("* HAVE FUN AND ENJOY~ *"));
|
||||
_putts(TEXT("*******************************************************"));
|
||||
} else {
|
||||
_putts(TEXT("*******************************************************"));
|
||||
_putts(TEXT("* DRY-RUN MODE ENABLE! *"));
|
||||
_putts(TEXT("* NO PATCH WILL BE APPLIED! *"));
|
||||
_putts(TEXT("*******************************************************"));
|
||||
}
|
||||
|
||||
return 0;
|
||||
} catch (nkg::Exception& e) {
|
||||
LOG_FAILURE(0, "%s:%zu ->", e.File(), e.Line());
|
||||
LOG_FAILURE(4, "%s", e.Message());
|
||||
if (e.HasErrorCode()) {
|
||||
LOG_HINT(4, "%s (0x%zx)", e.ErrorString(), e.ErrorCode());
|
||||
}
|
||||
|
||||
for (auto& Hint : e.Hints()) {
|
||||
LOG_HINT(4, "Hint: %s", Hint.c_str());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,200 +0,0 @@
|
||||
#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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user