Refactor code
This commit is contained in:
parent
599ac96c30
commit
28d24ed495
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
*.DS_Store
|
*.DS_Store
|
||||||
|
.vscode/*
|
||||||
bin/*
|
bin/*
|
||||||
43
Makefile
43
Makefile
@ -1,13 +1,13 @@
|
|||||||
CC = g++
|
CC = g++
|
||||||
OPENSSL_INCLUDE_PATH = /usr/local/opt/openssl/include
|
OPENSSL_INCLUDE_PATH = /usr/local/opt/openssl@1.1/include
|
||||||
OPENSSL_LIB_PATH = /usr/local/opt/openssl/lib
|
OPENSSL_LIB_PATH = /usr/local/opt/openssl@1.1/lib
|
||||||
CAPSTONE_INCLUDE_PATH = #/usr/local/Cellar/capstone/4.0.1/include
|
CAPSTONE_INCLUDE_PATH =
|
||||||
CAPSTONE_LIB_PATH = #/usr/local/Cellar/capstone/4.0.1/lib
|
CAPSTONE_LIB_PATH =
|
||||||
KEYSTONE_INCLUDE_PATH = #/usr/local/Cellar/keystone/0.9.1/include
|
KEYSTONE_INCLUDE_PATH =
|
||||||
KEYSTONE_LIB_PATH = #/usr/local/Cellar/keystone/0.9.1/lib
|
KEYSTONE_LIB_PATH =
|
||||||
RAPIDJSON_INCLUDE_PATH = #/usr/local/Cellar/rapidjson/1.1.0/include
|
RAPIDJSON_INCLUDE_PATH =
|
||||||
LIBPLIST_INCLUDE_PATH = #/usr/local/Cellar/libplist/2.0.0_1/include
|
LIBPLIST_INCLUDE_PATH =
|
||||||
LIBPLIST_LIB_PATH = #/usr/local/Cellar/libplist/2.0.0_1/lib
|
LIBPLIST_LIB_PATH =
|
||||||
|
|
||||||
OUTPUT_DIR = ./bin/
|
OUTPUT_DIR = ./bin/
|
||||||
COMMON_DIR = ./common/
|
COMMON_DIR = ./common/
|
||||||
@ -16,10 +16,11 @@ KEYGEN_DIR = ./navicat-keygen/
|
|||||||
|
|
||||||
COMMON_HEADER = \
|
COMMON_HEADER = \
|
||||||
$(COMMON_DIR)Exception.hpp \
|
$(COMMON_DIR)Exception.hpp \
|
||||||
|
$(COMMON_DIR)ExceptionGeneric.hpp \
|
||||||
$(COMMON_DIR)ExceptionOpenssl.hpp \
|
$(COMMON_DIR)ExceptionOpenssl.hpp \
|
||||||
$(COMMON_DIR)ExceptionSystem.hpp \
|
$(COMMON_DIR)ExceptionSystem.hpp \
|
||||||
$(COMMON_DIR)ResourceOwned.hpp \
|
|
||||||
$(COMMON_DIR)ResourceTraitsOpenssl.hpp \
|
$(COMMON_DIR)ResourceTraitsOpenssl.hpp \
|
||||||
|
$(COMMON_DIR)ResourceWrapper.hpp \
|
||||||
$(COMMON_DIR)RSACipher.hpp \
|
$(COMMON_DIR)RSACipher.hpp \
|
||||||
|
|
||||||
PATCHER_HEADER = \
|
PATCHER_HEADER = \
|
||||||
@ -30,15 +31,16 @@ $(PATCHER_DIR)ResourceTraitsKeystone.hpp \
|
|||||||
$(PATCHER_DIR)ResourceTraitsUnix.hpp \
|
$(PATCHER_DIR)ResourceTraitsUnix.hpp \
|
||||||
$(PATCHER_DIR)CapstoneDisassembler.hpp \
|
$(PATCHER_DIR)CapstoneDisassembler.hpp \
|
||||||
$(PATCHER_DIR)KeystoneAssembler.hpp \
|
$(PATCHER_DIR)KeystoneAssembler.hpp \
|
||||||
|
$(PATCHER_DIR)MemoryAccess.hpp \
|
||||||
|
$(PATCHER_DIR)Misc.hpp \
|
||||||
$(PATCHER_DIR)X64ImageInterpreter.hpp \
|
$(PATCHER_DIR)X64ImageInterpreter.hpp \
|
||||||
$(PATCHER_DIR)PatchSolutions.hpp
|
$(PATCHER_DIR)PatchSolutions.hpp
|
||||||
|
|
||||||
PATCHER_SOURCE = \
|
PATCHER_SOURCE = \
|
||||||
$(PATCHER_DIR)CapstoneDisassembler.cpp \
|
$(PATCHER_DIR)CapstoneDisassembler.cpp \
|
||||||
$(PATCHER_DIR)KeystoneAssembler.cpp \
|
$(PATCHER_DIR)KeystoneAssembler.cpp \
|
||||||
|
$(PATCHER_DIR)Misc.cpp \
|
||||||
$(PATCHER_DIR)X64ImageInterpreter.cpp \
|
$(PATCHER_DIR)X64ImageInterpreter.cpp \
|
||||||
$(PATCHER_DIR)HelperIsResolvedTo.cpp \
|
|
||||||
$(PATCHER_DIR)HelperPrintMemory.cpp \
|
|
||||||
$(PATCHER_DIR)PatchSolution0.cpp \
|
$(PATCHER_DIR)PatchSolution0.cpp \
|
||||||
$(PATCHER_DIR)PatchSolution1.cpp \
|
$(PATCHER_DIR)PatchSolution1.cpp \
|
||||||
$(PATCHER_DIR)PatchSolution2.cpp \
|
$(PATCHER_DIR)PatchSolution2.cpp \
|
||||||
@ -47,31 +49,36 @@ $(PATCHER_DIR)main.cpp
|
|||||||
PATCHER_BINARY = $(OUTPUT_DIR)navicat-patcher
|
PATCHER_BINARY = $(OUTPUT_DIR)navicat-patcher
|
||||||
|
|
||||||
KEYGEN_HEADER = \
|
KEYGEN_HEADER = \
|
||||||
$(KEYGEN_DIR)DESCipher.hpp \
|
$(KEYGEN_DIR)Base32.hpp \
|
||||||
$(KEYGEN_DIR)NavicatKeygen.hpp
|
$(KEYGEN_DIR)Base64.hpp \
|
||||||
|
$(KEYGEN_DIR)SerialNumberGenerator.hpp
|
||||||
|
|
||||||
KEYGEN_SOURCE = \
|
KEYGEN_SOURCE = \
|
||||||
$(KEYGEN_DIR)Base64.cpp \
|
$(KEYGEN_DIR)CollectInformation.cpp \
|
||||||
$(KEYGEN_DIR)main.cpp
|
$(KEYGEN_DIR)GenerateLicense.cpp \
|
||||||
|
$(KEYGEN_DIR)main.cpp \
|
||||||
|
$(KEYGEN_DIR)SerialNumberGenerator.cpp
|
||||||
|
|
||||||
KEYGEN_BINARY = $(OUTPUT_DIR)navicat-keygen
|
KEYGEN_BINARY = $(OUTPUT_DIR)navicat-keygen
|
||||||
|
|
||||||
patcher: $(PATCHER_HEADER) $(PATCHER_SOURCE)
|
patcher: $(PATCHER_HEADER) $(PATCHER_SOURCE)
|
||||||
@if [ ! -d $(OUTPUT_DIR) ]; then mkdir -p $(OUTPUT_DIR); fi
|
@if [ ! -d $(OUTPUT_DIR) ]; then mkdir -p $(OUTPUT_DIR); fi
|
||||||
$(CC) -std=c++17 -O2 \
|
$(CC) -std=c++17 -O2 \
|
||||||
|
-I$(COMMON_DIR) \
|
||||||
-I$(OPENSSL_INCLUDE_PATH) -L$(OPENSSL_LIB_PATH) \
|
-I$(OPENSSL_INCLUDE_PATH) -L$(OPENSSL_LIB_PATH) \
|
||||||
$(if $(CAPSTONE_INCLUDE_PATH),-I$(CAPSTONE_INCLUDE_PATH),) $(if $(CAPSTONE_LIB_PATH),-L$(CAPSTONE_LIB_PATH),) \
|
$(if $(CAPSTONE_INCLUDE_PATH),-I$(CAPSTONE_INCLUDE_PATH),) $(if $(CAPSTONE_LIB_PATH),-L$(CAPSTONE_LIB_PATH),) \
|
||||||
$(if $(KEYSTONE_INCLUDE_PATH),-I$(KEYSTONE_INCLUDE_PATH),) $(if $(KEYSTONE_LIB_PATH),-L$(KEYSTONE_LIB_PATH),) \
|
$(if $(KEYSTONE_INCLUDE_PATH),-I$(KEYSTONE_INCLUDE_PATH),) $(if $(KEYSTONE_LIB_PATH),-L$(KEYSTONE_LIB_PATH),) \
|
||||||
$(if $(LIBPLIST_INCLUDE_PATH),-I$(LIBPLIST_INCLUDE_PATH),) $(if $(LIBPLIST_LIB_PATH),-L$(LIBPLIST_LIB_PATH),) \
|
$(if $(LIBPLIST_INCLUDE_PATH),-I$(LIBPLIST_INCLUDE_PATH),) $(if $(LIBPLIST_LIB_PATH),-L$(LIBPLIST_LIB_PATH),) \
|
||||||
-lcrypto -lcapstone -lkeystone -lplist++ $(PATCHER_SOURCE) -o $(PATCHER_BINARY)
|
$(PATCHER_SOURCE) -o $(PATCHER_BINARY) -lcrypto -lcapstone -lkeystone -lplist++
|
||||||
@echo
|
@echo
|
||||||
|
|
||||||
keygen: $(KEYGEM_HEADER) $(KEYGEN_SOURCE)
|
keygen: $(KEYGEM_HEADER) $(KEYGEN_SOURCE)
|
||||||
@if [ ! -d $(OUTPUT_DIR) ]; then mkdir -p $(OUTPUT_DIR); fi
|
@if [ ! -d $(OUTPUT_DIR) ]; then mkdir -p $(OUTPUT_DIR); fi
|
||||||
$(CC) -std=c++17 -O2 \
|
$(CC) -std=c++17 -O2 \
|
||||||
|
-I$(COMMON_DIR) \
|
||||||
-I$(OPENSSL_INCLUDE_PATH) -L$(OPENSSL_LIB_PATH) \
|
-I$(OPENSSL_INCLUDE_PATH) -L$(OPENSSL_LIB_PATH) \
|
||||||
$(if $(RAPIDJSON_INCLUDE_PATH),-I$(RAPIDJSON_INCLUDE_PATH),) \
|
$(if $(RAPIDJSON_INCLUDE_PATH),-I$(RAPIDJSON_INCLUDE_PATH),) \
|
||||||
-lcrypto $(KEYGEN_SOURCE) -o $(KEYGEN_BINARY)
|
$(KEYGEN_SOURCE) -o $(KEYGEN_BINARY) -lcrypto
|
||||||
|
|
||||||
all: patcher keygen
|
all: patcher keygen
|
||||||
@echo 'Done.'
|
@echo 'Done.'
|
||||||
|
|||||||
@ -1,36 +1,101 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stddef.h> // NOLINT
|
#include <stddef.h>
|
||||||
#include <stdint.h> // NOLINT
|
#include <stdint.h>
|
||||||
|
#include <exception>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace nkg {
|
namespace ARL {
|
||||||
|
|
||||||
class Exception {
|
class Exception : public std::exception {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
const char* pvt_File;
|
const char* m_SourceFile;
|
||||||
const char* pvt_Message;
|
const size_t m_SourceLine;
|
||||||
size_t pvt_Line;
|
std::string m_Message;
|
||||||
|
std::vector<std::string> m_Hints;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Exception(const char* File, size_t Line, const char* Message) noexcept :
|
template<typename... __ArgTypes>
|
||||||
pvt_File(File),
|
Exception(const char* SourceFile, size_t SourceLine, const char* Format, __ArgTypes&&... Args) noexcept :
|
||||||
pvt_Message(Message),
|
m_SourceFile(SourceFile),
|
||||||
pvt_Line(Line) {}
|
m_SourceLine(SourceLine)
|
||||||
|
{
|
||||||
|
if constexpr (sizeof...(Args) == 0) {
|
||||||
|
m_Message.assign(Format);
|
||||||
|
} else {
|
||||||
|
int l;
|
||||||
|
|
||||||
[[nodiscard]]
|
l = snprintf(nullptr, 0, Format, std::forward<__ArgTypes>(Args)...);
|
||||||
const char* File() const noexcept {
|
if (l < 0) {
|
||||||
return pvt_File;
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Message.resize(l + 1);
|
||||||
|
|
||||||
|
l = snprintf(m_Message.data(), m_Message.length(), Format, std::forward<__ArgTypes>(Args)...);
|
||||||
|
if (l < 0) {
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (m_Message.back() == '\x00') {
|
||||||
|
m_Message.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
size_t Line() const noexcept {
|
auto ExceptionFile() const noexcept {
|
||||||
return pvt_Line;
|
return m_SourceFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
const char* Message() const noexcept {
|
auto ExceptionLine() const noexcept {
|
||||||
return pvt_Message;
|
return m_SourceLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
auto ExceptionMessage() const noexcept {
|
||||||
|
return m_Message.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __HintType>
|
||||||
|
auto& PushHint(__HintType&& Hint) noexcept { // if an exception is thrown, just suppress and terminate.
|
||||||
|
m_Hints.emplace_back(std::forward<__HintType>(Hint));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... __ArgTypes>
|
||||||
|
auto& PushFormatHint(const char* Format, __ArgTypes&&... Args) noexcept { // if an exception is thrown, just suppress and terminate.
|
||||||
|
int l;
|
||||||
|
std::string s;
|
||||||
|
|
||||||
|
l = snprintf(nullptr, 0, Format, std::forward<__ArgTypes>(Args)...);
|
||||||
|
if (l < 0) {
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
s.resize(l + 1);
|
||||||
|
|
||||||
|
l = snprintf(s.data(), s.length(), Format, std::forward<__ArgTypes>(Args)...);
|
||||||
|
if (l < 0) {
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (s.back() == '\x00') {
|
||||||
|
s.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Hints.emplace_back(std::move(s));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const auto& Hints() const noexcept {
|
||||||
|
return m_Hints;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@ -47,6 +112,12 @@ namespace nkg {
|
|||||||
virtual const char* ErrorString() const noexcept {
|
virtual const char* ErrorString() const noexcept {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
|
virtual const char* what() const noexcept override {
|
||||||
|
return ExceptionMessage();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
28
common/ExceptionGeneric.hpp
Normal file
28
common/ExceptionGeneric.hpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Exception.hpp"
|
||||||
|
|
||||||
|
namespace ARL {
|
||||||
|
|
||||||
|
#pragma push_macro("DECLARE_NEW_EXCEPTION")
|
||||||
|
#undef DECLARE_NEW_EXCEPTION
|
||||||
|
|
||||||
|
#define DECLARE_NEW_EXCEPTION(name) \
|
||||||
|
class name final : public Exception { \
|
||||||
|
public: \
|
||||||
|
template<typename... __ArgTypes> \
|
||||||
|
name(const char* SourceFile, size_t SourceLine, const char* Format, __ArgTypes&&... Args) noexcept : \
|
||||||
|
Exception(SourceFile, SourceLine, Format, std::forward<__ArgTypes>(Args)...) {} \
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_NEW_EXCEPTION(AssertionError);
|
||||||
|
DECLARE_NEW_EXCEPTION(EOFError);
|
||||||
|
DECLARE_NEW_EXCEPTION(IndexError);
|
||||||
|
DECLARE_NEW_EXCEPTION(KeyError);
|
||||||
|
DECLARE_NEW_EXCEPTION(NotImplementedError);
|
||||||
|
DECLARE_NEW_EXCEPTION(OverflowError);
|
||||||
|
DECLARE_NEW_EXCEPTION(ValueError);
|
||||||
|
|
||||||
|
#undef DECLARE_NEW_EXCEPTION
|
||||||
|
#pragma pop_macro("DECLARE_NEW_EXCEPTION")
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,19 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <openssl/err.h>
|
|
||||||
#include "Exception.hpp"
|
#include "Exception.hpp"
|
||||||
|
#include <openssl/err.h>
|
||||||
|
|
||||||
namespace nkg {
|
namespace ARL {
|
||||||
|
|
||||||
class OpensslError final : public Exception {
|
class OpensslError final : public Exception {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
unsigned long pvt_ErrorCode;
|
unsigned long m_ErrorCode;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
OpensslError(const char* File, unsigned Line, unsigned long ErrorCode, const char* Message) noexcept :
|
template<typename... __ArgTypes>
|
||||||
Exception(File, Line, Message),
|
OpensslError(const char* SourceFile, size_t SourceLine, unsigned long ErrorCode, const char* Format, __ArgTypes&&... Args) noexcept :
|
||||||
pvt_ErrorCode(ErrorCode) {}
|
Exception(SourceFile, SourceLine, Format, std::forward<__ArgTypes>(Args)...),
|
||||||
|
m_ErrorCode(ErrorCode) {}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
@ -24,14 +25,18 @@ namespace nkg {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
virtual intptr_t ErrorCode() const noexcept override {
|
virtual intptr_t ErrorCode() const noexcept override {
|
||||||
return pvt_ErrorCode;
|
return m_ErrorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
virtual const char* ErrorString() const noexcept override {
|
virtual const char* ErrorString() const noexcept override {
|
||||||
ERR_load_crypto_strings();
|
static bool loaded = false;
|
||||||
return ERR_reason_error_string(pvt_ErrorCode);
|
if (loaded == false) {
|
||||||
|
ERR_load_crypto_strings();
|
||||||
|
loaded = true;
|
||||||
|
}
|
||||||
|
return ERR_reason_error_string(m_ErrorCode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Exception.hpp"
|
#include "Exception.hpp"
|
||||||
#include <string.h> // NOLINT
|
#include <string.h>
|
||||||
|
|
||||||
namespace nkg {
|
namespace ARL {
|
||||||
|
|
||||||
class SystemError final : public Exception {
|
class SystemError final : public Exception {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
int pvt_ErrorCode;
|
int m_ErrorCode;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SystemError(const char* File, unsigned Line, int ErrorCode, const char* Message) noexcept :
|
template<typename... __ArgTypes>
|
||||||
Exception(File, Line, Message),
|
SystemError(const char* SourceFile, size_t SourceLine, int ErrorCode, const char* Format, __ArgTypes&&... Args) noexcept :
|
||||||
pvt_ErrorCode(ErrorCode) {}
|
Exception(SourceFile, SourceLine, Format, std::forward<__ArgTypes>(Args)...),
|
||||||
|
m_ErrorCode(ErrorCode) {}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
@ -24,14 +25,15 @@ namespace nkg {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
virtual intptr_t ErrorCode() const noexcept override {
|
virtual intptr_t ErrorCode() const noexcept override {
|
||||||
return pvt_ErrorCode;
|
return m_ErrorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
virtual const char* ErrorString() const noexcept override {
|
virtual const char* ErrorString() const noexcept override {
|
||||||
return strerror(pvt_ErrorCode);
|
return strerror(m_ErrorCode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,267 +4,271 @@
|
|||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
#include <openssl/bio.h>
|
#include <openssl/bio.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "Exception.hpp"
|
||||||
#include "ExceptionOpenssl.hpp"
|
#include "ExceptionOpenssl.hpp"
|
||||||
#include "ResourceOwned.hpp"
|
#include "ResourceWrapper.hpp"
|
||||||
#include "ResourceTraitsOpenssl.hpp"
|
#include "ResourceTraitsOpenssl.hpp"
|
||||||
|
|
||||||
enum class RSAKeyType {
|
namespace nkg {
|
||||||
PrivateKey,
|
|
||||||
PublicKey
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class RSAKeyFormat {
|
enum class RSAKeyType {
|
||||||
PEM,
|
PrivateKey,
|
||||||
PKCS1
|
PublicKey
|
||||||
};
|
};
|
||||||
|
|
||||||
class RSACipher {
|
enum class RSAKeyFormat {
|
||||||
private:
|
PEM,
|
||||||
ResourceOwned<OpensslRSATraits> pvt_RsaObj;
|
PKCS1
|
||||||
|
};
|
||||||
|
|
||||||
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
class RSACipher final : private ARL::ResourceWrapper<ARL::ResourceTraits::OpensslRSA> {
|
||||||
static void pvt_WriteRSAToBIO(RSA* lpRSA, BIO* lpBIO) {
|
private:
|
||||||
if constexpr (__Type == RSAKeyType::PrivateKey) {
|
|
||||||
if (PEM_write_bio_RSAPrivateKey(lpBIO, lpRSA, nullptr, nullptr, 0, nullptr, nullptr) == 0) {
|
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
static void _WriteRSAToBIO(RSA* lpRSA, BIO* lpBIO) {
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "PEM_write_bio_RSAPrivateKey failed.");
|
if constexpr (__Type == RSAKeyType::PrivateKey) {
|
||||||
|
if (PEM_write_bio_RSAPrivateKey(lpBIO, lpRSA, nullptr, nullptr, 0, nullptr, nullptr) == 0) {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "PEM_write_bio_RSAPrivateKey failed.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if constexpr (__Format == RSAKeyFormat::PEM) {
|
if constexpr (__Type == RSAKeyType::PublicKey) {
|
||||||
if (PEM_write_bio_RSA_PUBKEY(lpBIO, lpRSA) == 0) {
|
if constexpr (__Format == RSAKeyFormat::PEM) {
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
if (PEM_write_bio_RSA_PUBKEY(lpBIO, lpRSA) == 0) {
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "PEM_write_bio_RSA_PUBKEY failed.");
|
throw ARL::Exception(__FILE__, __LINE__, "PEM_write_bio_RSA_PUBKEY failed.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if constexpr (__Format == RSAKeyFormat::PKCS1) {
|
|
||||||
if (PEM_write_bio_RSAPublicKey(lpBIO, lpRSA) == 0) {
|
if constexpr (__Format == RSAKeyFormat::PKCS1) {
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
if (PEM_write_bio_RSAPublicKey(lpBIO, lpRSA) == 0) {
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "PEM_write_bio_RSAPublicKey failed.");
|
throw ARL::Exception(__FILE__, __LINE__, "PEM_write_bio_RSAPublicKey failed.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
static_assert(__Format == RSAKeyFormat::PEM || __Format == RSAKeyFormat::PKCS1);
|
static_assert(__Format == RSAKeyFormat::PEM || __Format == RSAKeyFormat::PKCS1);
|
||||||
__builtin_unreachable();
|
}
|
||||||
|
|
||||||
|
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 ARL::Exception(__FILE__, __LINE__, "PEM_read_bio_RSAPrivateKey failed.")
|
||||||
|
.PushHint("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 ARL::Exception(__FILE__, __LINE__, "PEM_read_bio_RSA_PUBKEY failed.")
|
||||||
|
.PushHint("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 ARL::Exception(__FILE__, __LINE__, "PEM_read_bio_RSAPublicKey failed.")
|
||||||
|
.PushHint("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() : ARL::ResourceWrapper<ARL::ResourceTraits::OpensslRSA>(RSA_new()) {
|
||||||
|
if (IsValid() == false) {
|
||||||
|
throw ARL::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_new failed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template<RSAKeyType _Type, RSAKeyFormat _Format>
|
[[nodiscard]]
|
||||||
[[nodiscard]]
|
size_t Bits() const {
|
||||||
static RSA* pvt_ReadRSAFromBIO(BIO* lpBIO) {
|
#if (OPENSSL_VERSION_NUMBER & 0xffff0000) == 0x10000000 // openssl 1.0.x
|
||||||
RSA* lpRSA;
|
if (Get()->n == nullptr) {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "RSA modulus has not been set.");
|
||||||
if constexpr (_Type == RSAKeyType::PrivateKey) {
|
} else {
|
||||||
lpRSA = PEM_read_bio_RSAPrivateKey(lpBIO, nullptr, nullptr, nullptr);
|
return BN_num_bits(Get()->n);
|
||||||
if (lpRSA == nullptr) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "PEM_read_bio_RSAPrivateKey failed.");
|
|
||||||
}
|
}
|
||||||
} else {
|
#elif (OPENSSL_VERSION_NUMBER & 0xffff0000) == 0x10100000 // openssl 1.1.x
|
||||||
if constexpr (_Format == RSAKeyFormat::PEM) {
|
return RSA_bits(Get());
|
||||||
lpRSA = PEM_read_bio_RSA_PUBKEY(lpBIO, nullptr, nullptr, nullptr);
|
#else
|
||||||
if (lpRSA == nullptr) {
|
#error "RSACipher.hpp: unexpected OpenSSL version."
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
#endif
|
||||||
throw nkg::Exception(__FILE__, __LINE__, " -> PEM_read_bio_RSA_PUBKEY failed.");
|
}
|
||||||
}
|
|
||||||
} else if constexpr (_Format == RSAKeyFormat::PKCS1) {
|
void GenerateKey(int bits, unsigned int e = RSA_F4) {
|
||||||
lpRSA = PEM_read_bio_RSAPublicKey(lpBIO, nullptr, nullptr, nullptr);
|
ARL::ResourceWrapper bn_e{ ARL::ResourceTraits::OpensslBIGNUM{} };
|
||||||
if (lpRSA == nullptr) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
bn_e.TakeOver(BN_new());
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "PEM_read_bio_RSAPublicKey failed.");
|
if (bn_e.IsValid() == false) {
|
||||||
|
throw ARL::OpensslError(__FILE__, __LINE__, ERR_get_error(), "BN_new failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!BN_set_word(bn_e, e)) {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "BN_set_word failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RSA_generate_key_ex(Get(), bits, bn_e, nullptr)) {
|
||||||
|
throw ARL::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_generate_key_ex failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
||||||
|
void ExportKeyToFile(std::string_view FileName) const {
|
||||||
|
ARL::ResourceWrapper KeyFile{ ARL::ResourceTraits::OpensslBIO{} };
|
||||||
|
|
||||||
|
KeyFile.TakeOver(BIO_new_file(FileName.data(), "w"));
|
||||||
|
if (KeyFile.IsValid() == false) {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "BIO_new_file failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_WriteRSAToBIO<__Type, __Format>(Get(), KeyFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
||||||
|
[[nodiscard]]
|
||||||
|
std::string ExportKeyString() const {
|
||||||
|
ARL::ResourceWrapper TempMemory{ ARL::ResourceTraits::OpensslBIO{} };
|
||||||
|
const char* lpsz = nullptr;
|
||||||
|
|
||||||
|
TempMemory.TakeOver(BIO_new(BIO_s_mem()));
|
||||||
|
if (TempMemory.IsValid() == false) {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "BIO_new failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_WriteRSAToBIO<__Type, __Format>(Get(), TempMemory);
|
||||||
|
|
||||||
|
auto l = BIO_get_mem_data(TempMemory.Get(), &lpsz);
|
||||||
|
|
||||||
|
std::string KeyString(lpsz, l);
|
||||||
|
while (KeyString.back() == '\n' || KeyString.back() == '\r') {
|
||||||
|
KeyString.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
return KeyString;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
||||||
|
void ImportKeyFromFile(std::string_view FileName) {
|
||||||
|
ARL::ResourceWrapper KeyFile{ ARL::ResourceTraits::OpensslBIO{} };
|
||||||
|
|
||||||
|
KeyFile.TakeOver(BIO_new_file(FileName.data(), "r"));
|
||||||
|
if (KeyFile.IsValid() == false) {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "BIO_new_file failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseAndTakeOver(_ReadRSAFromBIO<__Type, __Format>(KeyFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
||||||
|
void ImportKeyString(std::string_view KeyString) {
|
||||||
|
ARL::ResourceWrapper TempMemory{ ARL::ResourceTraits::OpensslBIO{} };
|
||||||
|
|
||||||
|
TempMemory.TakeOver(BIO_new(BIO_s_mem()));
|
||||||
|
if (TempMemory.IsValid() == false) {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "BIO_new failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BIO_puts(TempMemory.Get(), KeyString.data()) <= 0) {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "BIO_puts failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
TakeOver(_ReadRSAFromBIO<__Type, __Format>(TempMemory));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<RSAKeyType __Type = RSAKeyType::PublicKey>
|
||||||
|
size_t Encrypt(const void* lpFrom, size_t cbFrom, void* lpTo, int Padding) const {
|
||||||
|
int BytesWritten;
|
||||||
|
|
||||||
|
if (cbFrom > static_cast<size_t>(INT_MAX)) {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "Length overflowed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (__Type == RSAKeyType::PrivateKey) {
|
||||||
|
BytesWritten = RSA_private_encrypt(
|
||||||
|
static_cast<int>(cbFrom),
|
||||||
|
reinterpret_cast<const unsigned char*>(lpFrom),
|
||||||
|
reinterpret_cast<unsigned char*>(lpTo),
|
||||||
|
Get(),
|
||||||
|
Padding
|
||||||
|
);
|
||||||
|
|
||||||
|
if (BytesWritten == -1) {
|
||||||
|
throw ARL::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_private_encrypt failed.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
static_assert(_Format == RSAKeyFormat::PEM || _Format == RSAKeyFormat::PKCS1);
|
BytesWritten = RSA_public_encrypt(
|
||||||
__builtin_unreachable();
|
static_cast<int>(cbFrom),
|
||||||
|
reinterpret_cast<const unsigned char*>(lpFrom),
|
||||||
|
reinterpret_cast<unsigned char*>(lpTo),
|
||||||
|
Get(),
|
||||||
|
Padding
|
||||||
|
);
|
||||||
|
|
||||||
|
if (BytesWritten == -1) {
|
||||||
|
throw ARL::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_public_encrypt failed.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return BytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
return lpRSA;
|
template<RSAKeyType __Type = RSAKeyType::PrivateKey>
|
||||||
}
|
size_t Decrypt(const void* lpFrom, size_t cbFrom, void* lpTo, int Padding) const {
|
||||||
|
int BytesWritten;
|
||||||
|
|
||||||
public:
|
if (cbFrom > static_cast<size_t>(INT_MAX)) {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "Length overflowed.");
|
||||||
RSACipher() : pvt_RsaObj(OpensslRSATraits{}, RSA_new()) {
|
|
||||||
if (pvt_RsaObj.IsValid() == false) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_new failed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
size_t Bits() const {
|
|
||||||
#if (OPENSSL_VERSION_NUMBER & 0xffff0000) == 0x10000000 // openssl 1.0.x
|
|
||||||
if (pvt_RsaObj->n == nullptr) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "RSA modulus has not been set.");
|
|
||||||
} else {
|
|
||||||
return BN_num_bits(pvt_RsaObj->n);
|
|
||||||
}
|
|
||||||
#elif (OPENSSL_VERSION_NUMBER & 0xffff0000) == 0x10100000 // openssl 1.1.x
|
|
||||||
return RSA_bits(pvt_RsaObj);
|
|
||||||
#else
|
|
||||||
#error "Unexpected openssl version!"
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void GenerateKey(int bits, unsigned int e = RSA_F4) {
|
|
||||||
ResourceOwned bn_e(OpensslBNTraits{}, BN_new());
|
|
||||||
|
|
||||||
if (bn_e.IsValid() == false) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::OpensslError(__FILE__, __LINE__, ERR_get_error(), "BN_new failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!BN_set_word(bn_e, e)) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "BN_set_word failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!RSA_generate_key_ex(pvt_RsaObj, bits, bn_e, nullptr)) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_generate_key_ex failed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
|
||||||
void ExportKeyToFile(const std::string& FileName) const {
|
|
||||||
ResourceOwned BioFile(OpensslBIOTraits{}, BIO_new_file(FileName.c_str(), "w"));
|
|
||||||
|
|
||||||
if (BioFile.IsValid() == false) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "BIO_new_file failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pvt_WriteRSAToBIO<__Type, __Format>(pvt_RsaObj, BioFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
|
||||||
[[nodiscard]]
|
|
||||||
std::string ExportKeyString() const {
|
|
||||||
ResourceOwned BioMemory(OpensslBIOTraits{}, BIO_new(BIO_s_mem()));
|
|
||||||
long StringLength;
|
|
||||||
const char* StringChars = nullptr;
|
|
||||||
|
|
||||||
if (BioMemory.IsValid() == false) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "BIO_new failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pvt_WriteRSAToBIO<__Type, __Format>(pvt_RsaObj, BioMemory);
|
|
||||||
|
|
||||||
StringLength = BIO_get_mem_data(BioMemory, &StringChars);
|
|
||||||
|
|
||||||
return std::string(StringChars, StringLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
|
||||||
void ImportKeyFromFile(const std::string& FileName) {
|
|
||||||
ResourceOwned BioFile(OpensslBIOTraits{}, BIO_new_file(FileName.c_str(), "r"));
|
|
||||||
|
|
||||||
if (BioFile.IsValid() == false) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "BIO_new_file failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pvt_RsaObj.TakeOver(pvt_ReadRSAFromBIO<__Type, __Format>(BioFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<RSAKeyType __Type, RSAKeyFormat __Format>
|
|
||||||
void ImportKeyString(const std::string& KeyString) {
|
|
||||||
ResourceOwned BioMemory(OpensslBIOTraits{}, BIO_new(BIO_s_mem()));
|
|
||||||
RSA* NewRsaObj;
|
|
||||||
|
|
||||||
if (BioMemory.IsValid() == false) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "BIO_new failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BIO_puts(BioMemory, KeyString.c_str()) <= 0) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "BIO_puts failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pvt_RsaObj.TakeOver(pvt_ReadRSAFromBIO<__Type, __Format>(BioMemory));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<RSAKeyType __Type = RSAKeyType::PublicKey>
|
|
||||||
size_t Encrypt(const void* lpFrom, size_t cbFrom, void* lpTo, int Padding) const {
|
|
||||||
int BytesWritten;
|
|
||||||
|
|
||||||
if (cbFrom > INT_MAX) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived lpFrom std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Length overflowed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if constexpr (__Type == RSAKeyType::PrivateKey) {
|
|
||||||
BytesWritten = RSA_private_encrypt(
|
|
||||||
static_cast<int>(cbFrom),
|
|
||||||
reinterpret_cast<const unsigned char*>(lpFrom),
|
|
||||||
reinterpret_cast<unsigned char*>(lpTo),
|
|
||||||
pvt_RsaObj,
|
|
||||||
Padding
|
|
||||||
);
|
|
||||||
|
|
||||||
if (BytesWritten == -1) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived lpFrom std::exception
|
|
||||||
throw nkg::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_private_encrypt failed.");
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
BytesWritten = RSA_public_encrypt(
|
|
||||||
static_cast<int>(cbFrom),
|
|
||||||
reinterpret_cast<const unsigned char*>(lpFrom),
|
|
||||||
reinterpret_cast<unsigned char*>(lpTo),
|
|
||||||
pvt_RsaObj,
|
|
||||||
Padding
|
|
||||||
);
|
|
||||||
|
|
||||||
if (BytesWritten == -1) {
|
if constexpr (__Type == RSAKeyType::PrivateKey) {
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived lpFrom std::exception
|
BytesWritten = RSA_private_decrypt(
|
||||||
throw nkg::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_public_encrypt failed.");
|
static_cast<int>(cbFrom),
|
||||||
|
reinterpret_cast<const unsigned char*>(lpFrom),
|
||||||
|
reinterpret_cast<unsigned char*>(lpTo),
|
||||||
|
Get(),
|
||||||
|
Padding
|
||||||
|
);
|
||||||
|
|
||||||
|
if (BytesWritten == -1) {
|
||||||
|
throw ARL::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_private_decrypt failed.")
|
||||||
|
.PushHint("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 ARL::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_public_decrypt failed.")
|
||||||
|
.PushHint("Are your sure you DO provide a correct public key?");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return BytesWritten;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return BytesWritten;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template<RSAKeyType __Type = RSAKeyType::PrivateKey>
|
|
||||||
size_t Decrypt(const void* lpFrom, int cbFrom, void* lpTo, int Padding) const {
|
|
||||||
int BytesWritten;
|
|
||||||
|
|
||||||
if (cbFrom > INT_MAX) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived lpFrom std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Length overflowed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if constexpr (__Type == RSAKeyType::PrivateKey) {
|
|
||||||
BytesWritten = RSA_private_decrypt(
|
|
||||||
cbFrom,
|
|
||||||
reinterpret_cast<const unsigned char*>(lpFrom),
|
|
||||||
reinterpret_cast<unsigned char*>(lpTo),
|
|
||||||
pvt_RsaObj,
|
|
||||||
Padding
|
|
||||||
);
|
|
||||||
|
|
||||||
if (BytesWritten == -1) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived lpFrom std::exception
|
|
||||||
throw nkg::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_private_decrypt failed.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
BytesWritten = RSA_public_decrypt(
|
|
||||||
cbFrom,
|
|
||||||
reinterpret_cast<const unsigned char*>(lpFrom),
|
|
||||||
reinterpret_cast<unsigned char*>(lpTo),
|
|
||||||
pvt_RsaObj,
|
|
||||||
Padding
|
|
||||||
);
|
|
||||||
|
|
||||||
if (BytesWritten == -1) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived lpFrom std::exception
|
|
||||||
throw nkg::OpensslError(__FILE__, __LINE__, ERR_get_error(), "RSA_public_decrypt failed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return BytesWritten;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,304 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
template<typename __ResourceTraits, typename __LambdaReleasor = void>
|
|
||||||
class ResourceOwned {
|
|
||||||
private:
|
|
||||||
|
|
||||||
using __HandleType = typename __ResourceTraits::HandleType;
|
|
||||||
static_assert(std::is_pod_v<__HandleType>);
|
|
||||||
|
|
||||||
__HandleType pvt_Handle;
|
|
||||||
__LambdaReleasor pvt_Releasor;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
//
|
|
||||||
// Construct from custom releasor.
|
|
||||||
// ``pvt_Handle` will be set to an invalid value.
|
|
||||||
//
|
|
||||||
ResourceOwned(__ResourceTraits, __LambdaReleasor&& Releasor) noexcept :
|
|
||||||
pvt_Handle(__ResourceTraits::InvalidValue),
|
|
||||||
pvt_Releasor(std::forward<__LambdaReleasor>(Releasor)) {}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Construct from handle given and custom releasor.
|
|
||||||
//
|
|
||||||
ResourceOwned(__ResourceTraits, const __HandleType& Handle, __LambdaReleasor&& Releasor) noexcept :
|
|
||||||
pvt_Handle(Handle),
|
|
||||||
pvt_Releasor(std::forward<__LambdaReleasor>(Releasor)) {}
|
|
||||||
|
|
||||||
//
|
|
||||||
// ResourceOwned doesn't allow to copy.
|
|
||||||
// Because it takes `pvt_Handle` exclusively.
|
|
||||||
//
|
|
||||||
ResourceOwned(const ResourceOwned<__ResourceTraits, __LambdaReleasor>& Other) = delete;
|
|
||||||
|
|
||||||
//
|
|
||||||
// ResourceOwned allows to move.
|
|
||||||
//
|
|
||||||
ResourceOwned(ResourceOwned<__ResourceTraits, __LambdaReleasor>&& Other) noexcept :
|
|
||||||
pvt_Handle(Other.pvt_Handle),
|
|
||||||
pvt_Releasor(std::move(Other.pvt_Releasor))
|
|
||||||
{
|
|
||||||
Other.pvt_Handle = __ResourceTraits::InvalidValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// ResourceOwned doesn't allow to copy.
|
|
||||||
// Because it takes `pvt_Handle` exclusively.
|
|
||||||
//
|
|
||||||
ResourceOwned<__ResourceTraits, __LambdaReleasor>&
|
|
||||||
operator=(const ResourceOwned<__ResourceTraits, __LambdaReleasor>& Other) = delete;
|
|
||||||
|
|
||||||
//
|
|
||||||
// ResourceOwned allows to move.
|
|
||||||
//
|
|
||||||
ResourceOwned<__ResourceTraits, __LambdaReleasor>&
|
|
||||||
operator=(ResourceOwned<__ResourceTraits, __LambdaReleasor>&& Other) noexcept {
|
|
||||||
this->pvt_Handle = Other.pvt_Handle;
|
|
||||||
this->pvt_Releasor = std::move(Other.pvt_Releasor);
|
|
||||||
Other.pvt_Handle = __ResourceTraits::InvalidValue;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
operator const __HandleType&() const noexcept { // NOLINT: Allow implicit conversion.
|
|
||||||
return this->pvt_Handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __AsType, bool __IsPointer = std::is_pointer_v<__HandleType>, typename = std::enable_if_t<__IsPointer>>
|
|
||||||
[[nodiscard]]
|
|
||||||
__AsType As() const noexcept {
|
|
||||||
return reinterpret_cast<__AsType>(this->pvt_Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool __IsPointer = std::is_pointer_v<__HandleType>, typename = typename std::enable_if_t<__IsPointer>>
|
|
||||||
[[nodiscard]]
|
|
||||||
__HandleType operator->() const noexcept {
|
|
||||||
return this->pvt_Handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
bool IsValid() const noexcept {
|
|
||||||
return __ResourceTraits::IsValid(this->pvt_Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
const __HandleType& Get() const noexcept {
|
|
||||||
return this->pvt_Handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __ReturnType = __HandleType*>
|
|
||||||
[[nodiscard]]
|
|
||||||
__ReturnType GetAddress() noexcept {
|
|
||||||
return reinterpret_cast<__ReturnType>(&this->pvt_Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TakeOver(const __HandleType& Handle) {
|
|
||||||
if (__ResourceTraits::IsValid(this->pvt_Handle) == true) {
|
|
||||||
this->pvt_Releasor(this->pvt_Handle);
|
|
||||||
}
|
|
||||||
this->pvt_Handle = Handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Discard() noexcept {
|
|
||||||
this->pvt_Handle = __ResourceTraits::InvalidValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
__HandleType Transfer() noexcept {
|
|
||||||
__HandleType t = this->pvt_Handle;
|
|
||||||
this->pvt_Handle = __ResourceTraits::InvalidValue;
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Release() {
|
|
||||||
if (__ResourceTraits::IsValid(this->pvt_Handle)) {
|
|
||||||
this->pvt_Releasor(this->pvt_Handle);
|
|
||||||
this->pvt_Handle = __ResourceTraits::InvalidValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~ResourceOwned() {
|
|
||||||
if (__ResourceTraits::IsValid(this->pvt_Handle)) {
|
|
||||||
this->pvt_Releasor(this->pvt_Handle);
|
|
||||||
this->pvt_Handle = __ResourceTraits::InvalidValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename __ResourceTraits>
|
|
||||||
class ResourceOwned<__ResourceTraits, void> {
|
|
||||||
private:
|
|
||||||
|
|
||||||
using __HandleType = typename __ResourceTraits::HandleType;
|
|
||||||
static_assert(std::is_pod_v<__HandleType>);
|
|
||||||
|
|
||||||
__HandleType pvt_Handle;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
//
|
|
||||||
// Construct from custom releasor.
|
|
||||||
// ``pvt_Handle` will be set to an invalid value.
|
|
||||||
//
|
|
||||||
explicit
|
|
||||||
ResourceOwned(__ResourceTraits) noexcept :
|
|
||||||
pvt_Handle(__ResourceTraits::InvalidValue) {}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Construct from handle given and custom releasor.
|
|
||||||
//
|
|
||||||
ResourceOwned(__ResourceTraits, const __HandleType& Handle) noexcept :
|
|
||||||
pvt_Handle(Handle) {}
|
|
||||||
|
|
||||||
//
|
|
||||||
// ResourceOwned doesn't allow to copy.
|
|
||||||
// Because it takes `pvt_Handle` exclusively.
|
|
||||||
//
|
|
||||||
ResourceOwned(const ResourceOwned<__ResourceTraits, void>& Other) = delete;
|
|
||||||
|
|
||||||
//
|
|
||||||
// ResourceOwned allows to move.
|
|
||||||
//
|
|
||||||
ResourceOwned(ResourceOwned<__ResourceTraits, void>&& Other) noexcept :
|
|
||||||
pvt_Handle(Other.pvt_Handle)
|
|
||||||
{
|
|
||||||
Other.pvt_Handle = __ResourceTraits::InvalidValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// ResourceOwned doesn't allow to copy.
|
|
||||||
// Because it takes `pvt_Handle` exclusively.
|
|
||||||
//
|
|
||||||
ResourceOwned<__ResourceTraits, void>&
|
|
||||||
operator=(const ResourceOwned<__ResourceTraits, void>& Other) = delete;
|
|
||||||
|
|
||||||
//
|
|
||||||
// ResourceOwned allows to move.
|
|
||||||
//
|
|
||||||
ResourceOwned<__ResourceTraits, void>&
|
|
||||||
operator=(ResourceOwned<__ResourceTraits, void>&& Other) noexcept {
|
|
||||||
this->pvt_Handle = Other.pvt_Handle;
|
|
||||||
Other.pvt_Handle = __ResourceTraits::InvalidValue;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
operator const __HandleType&() const noexcept { // NOLINT: Allow implicit conversion.
|
|
||||||
return this->pvt_Handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __AsType, bool __IsPointer = std::is_pointer_v<__HandleType>, typename = typename std::enable_if_t<__IsPointer>>
|
|
||||||
[[nodiscard]]
|
|
||||||
__AsType As() const noexcept {
|
|
||||||
return reinterpret_cast<__AsType>(this->pvt_Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool __IsPointer = std::is_pointer_v<__HandleType>, typename = typename std::enable_if_t<__IsPointer>>
|
|
||||||
[[nodiscard]]
|
|
||||||
__HandleType operator->() const noexcept {
|
|
||||||
return this->pvt_Handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
bool IsValid() const noexcept {
|
|
||||||
return __ResourceTraits::IsValid(this->pvt_Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
const __HandleType& Get() const noexcept {
|
|
||||||
return this->pvt_Handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __ReturnType = __HandleType*>
|
|
||||||
[[nodiscard]]
|
|
||||||
__ReturnType GetAddress() noexcept {
|
|
||||||
return reinterpret_cast<__ReturnType>(&this->pvt_Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TakeOver(const __HandleType& Handle) {
|
|
||||||
if (__ResourceTraits::IsValid(this->pvt_Handle) == true) {
|
|
||||||
__ResourceTraits::Releasor(this->pvt_Handle);
|
|
||||||
}
|
|
||||||
this->pvt_Handle = Handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Discard() noexcept {
|
|
||||||
this->pvt_Handle = __ResourceTraits::InvalidValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
__HandleType Transfer() noexcept {
|
|
||||||
__HandleType t = this->pvt_Handle;
|
|
||||||
this->pvt_Handle = __ResourceTraits::InvalidValue;
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Release() {
|
|
||||||
if (__ResourceTraits::IsValid(this->pvt_Handle)) {
|
|
||||||
__ResourceTraits::Releasor(this->pvt_Handle);
|
|
||||||
this->pvt_Handle = __ResourceTraits::InvalidValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~ResourceOwned() {
|
|
||||||
if (__ResourceTraits::IsValid(this->pvt_Handle)) {
|
|
||||||
__ResourceTraits::Releasor(this->pvt_Handle);
|
|
||||||
this->pvt_Handle = __ResourceTraits::InvalidValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename __ResourceTraits>
|
|
||||||
ResourceOwned(__ResourceTraits) ->
|
|
||||||
ResourceOwned<__ResourceTraits, void>;
|
|
||||||
|
|
||||||
template<typename __ResourceTraits, typename __ArgType>
|
|
||||||
ResourceOwned(__ResourceTraits, __ArgType&&) ->
|
|
||||||
ResourceOwned<
|
|
||||||
__ResourceTraits,
|
|
||||||
std::conditional_t<
|
|
||||||
std::is_same_v<std::remove_cv_t<std::remove_reference_t<__ArgType>>, typename __ResourceTraits::HandleType> == false,
|
|
||||||
std::remove_reference_t<__ArgType>,
|
|
||||||
void
|
|
||||||
>
|
|
||||||
>;
|
|
||||||
|
|
||||||
template<typename __ResourceTraits, typename __LambdaReleasor>
|
|
||||||
ResourceOwned(__ResourceTraits, const typename __ResourceTraits::HandleType&, __LambdaReleasor&&) ->
|
|
||||||
ResourceOwned<__ResourceTraits, std::remove_reference_t<__LambdaReleasor>>;
|
|
||||||
|
|
||||||
template<typename __ClassType>
|
|
||||||
struct CppObjectTraits {
|
|
||||||
using HandleType = __ClassType*;
|
|
||||||
|
|
||||||
static inline const HandleType InvalidValue = nullptr;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
static bool IsValid(const HandleType& Handle) noexcept {
|
|
||||||
return Handle != InvalidValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Releasor(const HandleType& Handle) {
|
|
||||||
delete Handle;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename __ClassType>
|
|
||||||
struct CppDynamicArrayTraits {
|
|
||||||
using HandleType = __ClassType*;
|
|
||||||
|
|
||||||
static inline const HandleType InvalidValue = nullptr;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
static bool IsValid(const HandleType& Handle) noexcept {
|
|
||||||
return Handle != InvalidValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Releasor(const HandleType& Handle) {
|
|
||||||
delete[] Handle;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -2,63 +2,67 @@
|
|||||||
#include <openssl/bio.h>
|
#include <openssl/bio.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
|
|
||||||
struct OpensslBIOTraits {
|
namespace ARL::ResourceTraits {
|
||||||
using HandleType = BIO*;
|
|
||||||
|
|
||||||
static inline const HandleType InvalidValue = nullptr;
|
struct OpensslBIO {
|
||||||
|
using HandleType = BIO*;
|
||||||
|
|
||||||
[[nodiscard]]
|
static inline const HandleType InvalidValue = nullptr;
|
||||||
static bool IsValid(const HandleType& Handle) noexcept {
|
|
||||||
return Handle != InvalidValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Releasor(const HandleType& Handle) noexcept {
|
[[nodiscard]]
|
||||||
BIO_free(Handle);
|
static bool IsValid(const HandleType& Handle) noexcept {
|
||||||
}
|
return Handle != InvalidValue;
|
||||||
};
|
}
|
||||||
|
|
||||||
struct OpensslBIOChainTraits {
|
static void Release(const HandleType& Handle) noexcept {
|
||||||
using HandleType = BIO*;
|
BIO_free(Handle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static inline const HandleType InvalidValue = nullptr;
|
struct OpensslBIOChain {
|
||||||
|
using HandleType = BIO*;
|
||||||
|
|
||||||
[[nodiscard]]
|
static inline const HandleType InvalidValue = nullptr;
|
||||||
static bool IsValid(const HandleType& Handle) noexcept {
|
|
||||||
return Handle != InvalidValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Releasor(const HandleType& Handle) noexcept {
|
[[nodiscard]]
|
||||||
BIO_free_all(Handle);
|
static bool IsValid(const HandleType& Handle) noexcept {
|
||||||
}
|
return Handle != InvalidValue;
|
||||||
};
|
}
|
||||||
|
|
||||||
struct OpensslBNTraits {
|
static void Release(const HandleType& Handle) noexcept {
|
||||||
using HandleType = BIGNUM*;
|
BIO_free_all(Handle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static inline const HandleType InvalidValue = nullptr;
|
struct OpensslBIGNUM {
|
||||||
|
using HandleType = BIGNUM*;
|
||||||
|
|
||||||
[[nodiscard]]
|
static inline const HandleType InvalidValue = nullptr;
|
||||||
static bool IsValid(const HandleType& Handle) noexcept {
|
|
||||||
return Handle != InvalidValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Releasor(const HandleType& Handle) noexcept {
|
[[nodiscard]]
|
||||||
BN_free(Handle);
|
static bool IsValid(const HandleType& Handle) noexcept {
|
||||||
}
|
return Handle != InvalidValue;
|
||||||
};
|
}
|
||||||
|
|
||||||
struct OpensslRSATraits {
|
static void Release(const HandleType& Handle) noexcept {
|
||||||
using HandleType = RSA*;
|
BN_free(Handle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static inline const HandleType InvalidValue = nullptr;
|
struct OpensslRSA {
|
||||||
|
using HandleType = RSA*;
|
||||||
|
|
||||||
[[nodiscard]]
|
static inline const HandleType InvalidValue = nullptr;
|
||||||
static bool IsValid(const HandleType& Handle) noexcept {
|
|
||||||
return Handle != InvalidValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Releasor(const HandleType& Handle) noexcept {
|
[[nodiscard]]
|
||||||
RSA_free(Handle);
|
static bool IsValid(const HandleType& Handle) noexcept {
|
||||||
}
|
return Handle != InvalidValue;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
static void Release(const HandleType& Handle) noexcept {
|
||||||
|
RSA_free(Handle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
375
common/ResourceWrapper.hpp
Normal file
375
common/ResourceWrapper.hpp
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace ARL {
|
||||||
|
|
||||||
|
template<typename __ResourceTraits>
|
||||||
|
class ResourceWrapper {
|
||||||
|
public:
|
||||||
|
|
||||||
|
using HandleType = typename __ResourceTraits::HandleType;
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_trivial_v<HandleType> && std::is_standard_layout_v<HandleType>,
|
||||||
|
"HandleType must be a POD type."
|
||||||
|
);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
HandleType m_Handle;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ResourceWrapper() noexcept :
|
||||||
|
m_Handle(__ResourceTraits::InvalidValue) {}
|
||||||
|
|
||||||
|
ResourceWrapper(const HandleType& Handle) noexcept :
|
||||||
|
m_Handle(Handle) {}
|
||||||
|
|
||||||
|
ResourceWrapper(__ResourceTraits) noexcept :
|
||||||
|
m_Handle(__ResourceTraits::InvalidValue) {}
|
||||||
|
|
||||||
|
ResourceWrapper(__ResourceTraits, const HandleType& Handle) noexcept :
|
||||||
|
m_Handle(Handle) {}
|
||||||
|
|
||||||
|
ResourceWrapper(const ResourceWrapper& Other) = delete;
|
||||||
|
|
||||||
|
ResourceWrapper(ResourceWrapper&& Other) noexcept :
|
||||||
|
m_Handle(std::move(Other.m_Handle))
|
||||||
|
{
|
||||||
|
Other.m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceWrapper& operator=(const ResourceWrapper& Other) = delete;
|
||||||
|
|
||||||
|
ResourceWrapper& operator=(ResourceWrapper&& Other) noexcept {
|
||||||
|
if (this != std::addressof(Other)) {
|
||||||
|
if (IsValid()) {
|
||||||
|
__ResourceTraits::Release(m_Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Handle = std::move(Other.m_Handle);
|
||||||
|
Other.m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
operator HandleType() const noexcept { // NOLINT: Allow implicit conversion.
|
||||||
|
return m_Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __AsType>
|
||||||
|
[[nodiscard]]
|
||||||
|
__AsType As() const noexcept {
|
||||||
|
return reinterpret_cast<__AsType>(m_Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool __Enable = std::is_pointer_v<HandleType>>
|
||||||
|
[[nodiscard]]
|
||||||
|
std::enable_if_t<__Enable, HandleType> operator->() const noexcept {
|
||||||
|
return m_Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool IsValid() const noexcept {
|
||||||
|
return __ResourceTraits::IsValid(m_Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
HandleType Get() const noexcept {
|
||||||
|
return m_Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
HandleType* GetAddressOf() noexcept {
|
||||||
|
return &m_Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __ReturnType>
|
||||||
|
[[nodiscard]]
|
||||||
|
__ReturnType GetAddressOfAs() noexcept {
|
||||||
|
return reinterpret_cast<__ReturnType>(&m_Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TakeOver(const HandleType& Handle) {
|
||||||
|
if (IsValid() == false) {
|
||||||
|
m_Handle = Handle;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("ResourceWrapper is already in use.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Discard() noexcept {
|
||||||
|
m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
HandleType Transfer() noexcept {
|
||||||
|
auto t = m_Handle;
|
||||||
|
m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __ReturnType>
|
||||||
|
[[nodiscard]]
|
||||||
|
__ReturnType TransferAs() noexcept {
|
||||||
|
static_assert(
|
||||||
|
std::is_trivial_v<__ReturnType> && std::is_standard_layout_v<__ReturnType>,
|
||||||
|
"__ReturnType should also be a POD type, just like HandleType."
|
||||||
|
);
|
||||||
|
|
||||||
|
auto t = reinterpret_cast<__ReturnType>(m_Handle);
|
||||||
|
m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Release() {
|
||||||
|
if (IsValid()) {
|
||||||
|
__ResourceTraits::Release(m_Handle);
|
||||||
|
m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReleaseAndTakeOver(const HandleType& Handle) {
|
||||||
|
if (IsValid()) {
|
||||||
|
__ResourceTraits::Release(m_Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Handle = Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
HandleType* ReleaseAndGetAddressOf() {
|
||||||
|
if (IsValid()) {
|
||||||
|
__ResourceTraits::Release(m_Handle);
|
||||||
|
m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetAddressOf();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __ReturnType>
|
||||||
|
__ReturnType ReleaseAndGetAddressOfAs() {
|
||||||
|
if (IsValid()) {
|
||||||
|
__ResourceTraits::Release(m_Handle);
|
||||||
|
m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetAddressOfAs<__ReturnType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
~ResourceWrapper() {
|
||||||
|
Release();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename __ResourceTraits, typename __DeleterType>
|
||||||
|
class ResourceWrapperEx {
|
||||||
|
public:
|
||||||
|
|
||||||
|
using HandleType = typename __ResourceTraits::HandleType;
|
||||||
|
using DeleterType = __DeleterType;
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_trivial_v<HandleType> && std::is_standard_layout_v<HandleType>,
|
||||||
|
"HandleType must be a POD type."
|
||||||
|
);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
HandleType m_Handle;
|
||||||
|
DeleterType m_Deleter;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
template<typename __DeleterArgType>
|
||||||
|
ResourceWrapperEx(__ResourceTraits, __DeleterArgType&& Deleter) noexcept :
|
||||||
|
m_Handle(__ResourceTraits::InvalidValue),
|
||||||
|
m_Deleter(std::forward<__DeleterArgType>(Deleter)) {}
|
||||||
|
|
||||||
|
template<typename __DeleterArgType>
|
||||||
|
ResourceWrapperEx(__ResourceTraits, const HandleType& Handle, __DeleterArgType&& Deleter) noexcept :
|
||||||
|
m_Handle(Handle),
|
||||||
|
m_Deleter(std::forward<__DeleterArgType>(Deleter)) {}
|
||||||
|
|
||||||
|
ResourceWrapperEx(const ResourceWrapperEx& Other) = delete;
|
||||||
|
|
||||||
|
ResourceWrapperEx(ResourceWrapperEx&& Other) noexcept :
|
||||||
|
m_Handle(std::move(Other.m_Handle)),
|
||||||
|
m_Deleter(std::move(Other.m_Deleter))
|
||||||
|
{
|
||||||
|
Other.m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceWrapperEx& operator=(const ResourceWrapperEx& Other) = delete;
|
||||||
|
|
||||||
|
ResourceWrapperEx& operator=(ResourceWrapperEx&& Other) noexcept {
|
||||||
|
if (this != std::addressof(Other)) {
|
||||||
|
if (IsValid()) {
|
||||||
|
m_Deleter(m_Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Handle = std::move(Other.m_Handle);
|
||||||
|
m_Deleter = std::move(Other.m_Deleter);
|
||||||
|
Other.m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
operator HandleType() const noexcept { // NOLINT: Allow implicit conversion.
|
||||||
|
return m_Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __AsType>
|
||||||
|
[[nodiscard]]
|
||||||
|
__AsType As() const noexcept {
|
||||||
|
return reinterpret_cast<__AsType>(m_Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool __Enable = std::is_pointer_v<HandleType>>
|
||||||
|
[[nodiscard]]
|
||||||
|
std::enable_if_t<__Enable, HandleType> operator->() const noexcept {
|
||||||
|
return m_Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool IsValid() const noexcept {
|
||||||
|
return __ResourceTraits::IsValid(m_Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
HandleType Get() const noexcept {
|
||||||
|
return m_Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
HandleType* GetAddressOf() noexcept {
|
||||||
|
return &m_Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __ReturnType>
|
||||||
|
[[nodiscard]]
|
||||||
|
__ReturnType GetAddressOfAs() noexcept {
|
||||||
|
return reinterpret_cast<__ReturnType>(&m_Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TakeOver(const HandleType& Handle) {
|
||||||
|
if (IsValid() == false) {
|
||||||
|
m_Handle = Handle;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("ResourceWrapperEx is already in use.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Discard() noexcept {
|
||||||
|
m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
HandleType Transfer() noexcept {
|
||||||
|
auto t = m_Handle;
|
||||||
|
m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __ReturnType>
|
||||||
|
[[nodiscard]]
|
||||||
|
__ReturnType TransferAs() noexcept {
|
||||||
|
static_assert(std::is_trivial_v<__ReturnType> && std::is_standard_layout_v<__ReturnType>);
|
||||||
|
|
||||||
|
auto t = reinterpret_cast<__ReturnType>(m_Handle);
|
||||||
|
m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Release() {
|
||||||
|
if (IsValid()) {
|
||||||
|
m_Deleter(m_Handle);
|
||||||
|
m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReleaseAndTakeOver(const HandleType& Handle) {
|
||||||
|
if (IsValid()) {
|
||||||
|
__ResourceTraits::Release(m_Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Handle = Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
HandleType* ReleaseAndGetAddressOf() {
|
||||||
|
if (IsValid()) {
|
||||||
|
m_Deleter(m_Handle);
|
||||||
|
m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetAddressOf();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __ReturnType>
|
||||||
|
__ReturnType ReleaseAndGetAddressOfAs() {
|
||||||
|
if (IsValid()) {
|
||||||
|
m_Deleter(m_Handle);
|
||||||
|
m_Handle = __ResourceTraits::InvalidValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetAddressOfAs<__ReturnType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
~ResourceWrapperEx() {
|
||||||
|
Release();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename __ResourceTraits, typename __DeleterArgType>
|
||||||
|
ResourceWrapperEx(__ResourceTraits, __DeleterArgType&& Deleter) ->
|
||||||
|
ResourceWrapperEx<__ResourceTraits, std::remove_reference_t<__DeleterArgType>>;
|
||||||
|
|
||||||
|
template<typename __ResourceTraits, typename __DeleterArgType>
|
||||||
|
ResourceWrapperEx(__ResourceTraits, const typename __ResourceTraits::HandleType& Handle, __DeleterArgType&& Deleter) ->
|
||||||
|
ResourceWrapperEx<__ResourceTraits, std::remove_reference_t<__DeleterArgType>>;
|
||||||
|
|
||||||
|
namespace ResourceTraits {
|
||||||
|
|
||||||
|
template<typename __ClassType>
|
||||||
|
struct CppObject {
|
||||||
|
using HandleType = __ClassType*;
|
||||||
|
|
||||||
|
static inline const HandleType InvalidValue = nullptr;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
static bool IsValid(const HandleType& Handle) noexcept {
|
||||||
|
return Handle != InvalidValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Release(const HandleType& Handle) {
|
||||||
|
delete Handle;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename __ElementType>
|
||||||
|
struct CppArray {
|
||||||
|
using HandleType = __ElementType*;
|
||||||
|
|
||||||
|
static inline const HandleType InvalidValue = nullptr;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
static bool IsValid(const HandleType& Handle) noexcept {
|
||||||
|
return Handle != InvalidValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Release(const HandleType& Handle) {
|
||||||
|
delete[] Handle;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
134
navicat-keygen/Base32.hpp
Normal file
134
navicat-keygen/Base32.hpp
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
inline std::string base32_encode(const void* lpBinary, size_t cbBinary) {
|
||||||
|
static const std::string::value_type Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||||
|
static constexpr std::string::value_type PaddingChar = '=';
|
||||||
|
|
||||||
|
std::string szBase32;
|
||||||
|
|
||||||
|
if (auto pbBinary = reinterpret_cast<const uint8_t*>(lpBinary); cbBinary) {
|
||||||
|
szBase32.reserve((cbBinary * 8 + 4) / 5);
|
||||||
|
|
||||||
|
uint8_t Idx = 0;
|
||||||
|
uint8_t BitsLeft = 8;
|
||||||
|
for (size_t i = 0; i < cbBinary;) {
|
||||||
|
if (BitsLeft < 5) {
|
||||||
|
Idx = pbBinary[i] << (5 - BitsLeft);
|
||||||
|
|
||||||
|
++i;
|
||||||
|
if (i != cbBinary) {
|
||||||
|
Idx |= pbBinary[i] >> (3 + BitsLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
Idx &= 0x1F;
|
||||||
|
BitsLeft += 3;
|
||||||
|
} else {
|
||||||
|
Idx = pbBinary[i] >> (BitsLeft - 5);
|
||||||
|
|
||||||
|
Idx &= 0x1F;
|
||||||
|
BitsLeft -= 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
szBase32.append(1, Alphabet[Idx]);
|
||||||
|
|
||||||
|
if (BitsLeft == 0) {
|
||||||
|
BitsLeft = 8;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (szBase32.length() % 8) {
|
||||||
|
size_t Padding = 8 - szBase32.length() % 8;
|
||||||
|
szBase32.append(Padding, PaddingChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return szBase32;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
inline std::string base32_encode(const std::vector<uint8_t>& Binary) {
|
||||||
|
return base32_encode(Binary.data(), Binary.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
inline std::string base32_encode(const std::initializer_list<uint8_t>& Binary) {
|
||||||
|
return base32_encode(Binary.begin(), Binary.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
inline std::vector<uint8_t> base32_decode(std::string_view szBase32) {
|
||||||
|
static constexpr std::string::value_type PaddingChar = '=';
|
||||||
|
|
||||||
|
std::vector<uint8_t> Binary;
|
||||||
|
|
||||||
|
if (szBase32.length()) {
|
||||||
|
Binary.reserve((szBase32.length() * 5 + 7) / 8);
|
||||||
|
|
||||||
|
uint8_t Byte = 0;
|
||||||
|
uint8_t BitsNeed = 8;
|
||||||
|
for (size_t i = 0; i < szBase32.length(); ++i) {
|
||||||
|
uint8_t Idx;
|
||||||
|
if ('A' <= szBase32[i] && szBase32[i] <= 'Z') {
|
||||||
|
Idx = szBase32[i] - 'A';
|
||||||
|
} else if ('a' <= szBase32[i] && szBase32[i] <= 'z') {
|
||||||
|
Idx = szBase32[i] - 'a';
|
||||||
|
} else if ('2' <= szBase32[i] && szBase32[i] <= '7') {
|
||||||
|
Idx = szBase32[i] - '2' + 26;
|
||||||
|
} else if (szBase32[i] == PaddingChar) {
|
||||||
|
for (size_t j = i + 1; j < szBase32.length(); ++j) {
|
||||||
|
if (szBase32[j] != PaddingChar) {
|
||||||
|
throw std::invalid_argument("base32_decode: invalid padding schema.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
throw std::invalid_argument("base32_decode: non-Base32 character is detected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BitsNeed >= 5) {
|
||||||
|
Byte |= Idx;
|
||||||
|
|
||||||
|
BitsNeed -= 5;
|
||||||
|
Byte <<= BitsNeed;
|
||||||
|
} else {
|
||||||
|
Byte |= Idx >> (5 - BitsNeed);
|
||||||
|
Binary.push_back(Byte);
|
||||||
|
|
||||||
|
BitsNeed += 3;
|
||||||
|
Byte = Idx << BitsNeed;
|
||||||
|
if (BitsNeed > 5) {
|
||||||
|
Byte >>= BitsNeed - 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (BitsNeed) {
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
throw std::invalid_argument("base32_decode: base32 string is corrupted.");
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
if (Byte != 0) {
|
||||||
|
throw std::invalid_argument("base32_decode: base32 string is corrupted.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
case 8:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Binary;
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <openssl/evp.h>
|
|
||||||
#include "../common/Exception.hpp"
|
|
||||||
#include "../common/ResourceOwned.hpp"
|
|
||||||
#include "../common/ResourceTraitsOpenssl.hpp"
|
|
||||||
|
|
||||||
std::string base64_encode(const std::vector<uint8_t>& bindata) {
|
|
||||||
ResourceOwned b64(OpensslBIOTraits{}, BIO_new(BIO_f_base64()));
|
|
||||||
if (b64.IsValid() == false) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "BIO_new failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
|
||||||
|
|
||||||
ResourceOwned mem(OpensslBIOTraits{}, BIO_new(BIO_s_mem()));
|
|
||||||
if (mem.IsValid() == false) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "BIO_new failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
BIO_push(b64, mem);
|
|
||||||
|
|
||||||
if (BIO_write(b64, bindata.data(), bindata.size()) != bindata.size()) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "BIO_write failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BIO_flush(b64) != 1) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "BIO_flush failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* data = nullptr;
|
|
||||||
auto len = BIO_get_mem_data(mem, &data);
|
|
||||||
|
|
||||||
BIO_pop(b64);
|
|
||||||
|
|
||||||
return std::string(data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint8_t> base64_decode(const std::string& ascdata) {
|
|
||||||
ResourceOwned b64(OpensslBIOTraits{}, BIO_new(BIO_f_base64()));
|
|
||||||
if (b64.IsValid() == false) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "BIO_new failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
|
||||||
|
|
||||||
ResourceOwned mem(OpensslBIOTraits{}, BIO_new_mem_buf(ascdata.c_str(), -1));
|
|
||||||
if (mem.IsValid() == false) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "BIO_new failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
BIO_push(b64, mem);
|
|
||||||
|
|
||||||
std::vector<uint8_t> bindata(ascdata.length() / 4 * 3 + 1);
|
|
||||||
bindata.resize(BIO_read(b64, bindata.data(), bindata.size()));
|
|
||||||
|
|
||||||
BIO_pop(b64);
|
|
||||||
|
|
||||||
return bindata;
|
|
||||||
}
|
|
||||||
134
navicat-keygen/Base64.hpp
Normal file
134
navicat-keygen/Base64.hpp
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
inline std::string base64_encode(const void* lpBinary, size_t cbBinary) {
|
||||||
|
static const std::string::value_type Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
static constexpr std::string::value_type PaddingChar = '=';
|
||||||
|
|
||||||
|
std::string szBase64;
|
||||||
|
|
||||||
|
if (auto pbBinary = reinterpret_cast<const uint8_t*>(lpBinary); cbBinary) {
|
||||||
|
szBase64.reserve((cbBinary * 8 + 5) / 6);
|
||||||
|
|
||||||
|
uint8_t Idx = 0;
|
||||||
|
uint8_t BitsLeft = 8;
|
||||||
|
for (size_t i = 0; i < cbBinary;) {
|
||||||
|
if (BitsLeft < 6) {
|
||||||
|
Idx = pbBinary[i] << (6 - BitsLeft);
|
||||||
|
|
||||||
|
++i;
|
||||||
|
if (i != cbBinary) {
|
||||||
|
Idx |= pbBinary[i] >> (2 + BitsLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
Idx &= 0x3F;
|
||||||
|
BitsLeft += 2;
|
||||||
|
} else {
|
||||||
|
Idx = pbBinary[i] >> (BitsLeft - 6);
|
||||||
|
|
||||||
|
Idx &= 0x3F;
|
||||||
|
BitsLeft -= 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
szBase64.append(1, Alphabet[Idx]);
|
||||||
|
|
||||||
|
if (BitsLeft == 0) {
|
||||||
|
BitsLeft = 8;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (szBase64.length() % 4) {
|
||||||
|
size_t Padding = 4 - szBase64.length() % 4;
|
||||||
|
szBase64.append(Padding, PaddingChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return szBase64;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
inline std::string base64_encode(const std::vector<uint8_t>& Binary) {
|
||||||
|
return base64_encode(Binary.data(), Binary.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
inline std::string base64_encode(const std::initializer_list<uint8_t>& Binary) {
|
||||||
|
return base64_encode(Binary.begin(), Binary.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
inline std::vector<uint8_t> base64_decode(std::string_view szBase64) {
|
||||||
|
static constexpr std::string::value_type PaddingChar = '=';
|
||||||
|
|
||||||
|
std::vector<uint8_t> Binary;
|
||||||
|
|
||||||
|
if (szBase64.length()) {
|
||||||
|
Binary.reserve((szBase64.length() * 6 + 7) / 8);
|
||||||
|
|
||||||
|
uint8_t Byte = 0;
|
||||||
|
uint8_t BitsNeed = 8;
|
||||||
|
for (size_t i = 0; i < szBase64.length(); ++i) {
|
||||||
|
uint8_t Idx;
|
||||||
|
if ('A' <= szBase64[i] && szBase64[i] <= 'Z') {
|
||||||
|
Idx = szBase64[i] - 'A';
|
||||||
|
} else if ('a' <= szBase64[i] && szBase64[i] <= 'z') {
|
||||||
|
Idx = szBase64[i] - 'a' + 26;
|
||||||
|
} else if ('0' <= szBase64[i] && szBase64[i] <= '9') {
|
||||||
|
Idx = szBase64[i] - '0' + 26 + 26;
|
||||||
|
} else if (szBase64[i] == '+') {
|
||||||
|
Idx = 26 + 26 + 10;
|
||||||
|
} else if (szBase64[i] == '/') {
|
||||||
|
Idx = 26 + 26 + 10 + 1;
|
||||||
|
} else if (szBase64[i] == PaddingChar) {
|
||||||
|
for (size_t j = i + 1; j < szBase64.length(); ++j) {
|
||||||
|
if (szBase64[j] != PaddingChar) {
|
||||||
|
throw std::invalid_argument("base64_decode: invalid padding schema.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
throw std::invalid_argument("base64_decode: non-Base64 character is detected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BitsNeed >= 6) {
|
||||||
|
Byte |= Idx;
|
||||||
|
|
||||||
|
BitsNeed -= 6;
|
||||||
|
Byte <<= BitsNeed;
|
||||||
|
} else {
|
||||||
|
Byte |= Idx >> (6 - BitsNeed);
|
||||||
|
Binary.push_back(Byte);
|
||||||
|
|
||||||
|
BitsNeed += 2;
|
||||||
|
Byte = Idx << BitsNeed;
|
||||||
|
if (BitsNeed > 6) {
|
||||||
|
Byte >>= BitsNeed - 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (BitsNeed) {
|
||||||
|
case 2:
|
||||||
|
throw std::invalid_argument("base64_decode: base64 string is corrupted.");
|
||||||
|
case 4:
|
||||||
|
case 6:
|
||||||
|
if (Byte != 0) {
|
||||||
|
throw std::invalid_argument("base64_decode: base64 string is corrupted.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
case 8:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Binary;
|
||||||
|
}
|
||||||
|
|
||||||
121
navicat-keygen/CollectInformation.cpp
Normal file
121
navicat-keygen/CollectInformation.cpp
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
#include "SerialNumberGenerator.hpp"
|
||||||
|
#include "ExceptionGeneric.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace nkg {
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
static int ReadInt(int MinVal, int MaxVal, const char* lpszPrompt, const char* lpszErrorMessage) {
|
||||||
|
int val;
|
||||||
|
std::string s;
|
||||||
|
while (true) {
|
||||||
|
std::cout << lpszPrompt;
|
||||||
|
if (!std::getline(std::cin, s)) {
|
||||||
|
throw ARL::EOFError(__FILE__, __LINE__, "Abort.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
val = std::stoi(s, nullptr, 0);
|
||||||
|
if (MinVal <= val && val <= MaxVal) {
|
||||||
|
return val;
|
||||||
|
} else {
|
||||||
|
throw std::invalid_argument("Out of range.");
|
||||||
|
}
|
||||||
|
} catch (std::invalid_argument&) {
|
||||||
|
std::cout << lpszErrorMessage << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
static int ReadInt(int MinVal, int MaxVal, int DefaultVal, const char* lpszPrompt, const char* lpszErrorMessage) {
|
||||||
|
int val;
|
||||||
|
std::string s;
|
||||||
|
while (true) {
|
||||||
|
std::cout << lpszPrompt;
|
||||||
|
if (!std::getline(std::cin, s)) {
|
||||||
|
throw ARL::EOFError(__FILE__, __LINE__, "Abort.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.empty()) {
|
||||||
|
return DefaultVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val = std::stoi(s, nullptr, 0);
|
||||||
|
if (MinVal <= val && val <= MaxVal) {
|
||||||
|
return val;
|
||||||
|
} else {
|
||||||
|
throw std::invalid_argument("Out of range.");
|
||||||
|
}
|
||||||
|
} catch (std::invalid_argument&) {
|
||||||
|
std::cout << lpszErrorMessage << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
SerialNumberGenerator CollectInformationNormal() {
|
||||||
|
SerialNumberGenerator Generator;
|
||||||
|
|
||||||
|
Generator.SetProductSignature(NavicatProductType::Premium);
|
||||||
|
|
||||||
|
std::cout << "[*] Select product language:" << std::endl;
|
||||||
|
std::cout << " 0. English" << std::endl;
|
||||||
|
std::cout << " 1. Simplified Chinese" << std::endl;
|
||||||
|
std::cout << " 2. Traditional Chinese" << std::endl;
|
||||||
|
std::cout << " 3. Japanese" << std::endl;
|
||||||
|
std::cout << " 4. Polish" << std::endl;
|
||||||
|
std::cout << " 5. Spanish" << std::endl;
|
||||||
|
std::cout << " 6. French" << std::endl;
|
||||||
|
std::cout << " 7. German" << std::endl;
|
||||||
|
std::cout << " 8. Korean" << std::endl;
|
||||||
|
std::cout << " 9. Russian" << std::endl;
|
||||||
|
std::cout << " 10. Portuguese" << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
Generator.SetLanguageSignature(
|
||||||
|
static_cast<NavicatLanguage>(ReadInt(0, 10, "(Input index)> ", "Invalid index."))
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << "[*] Input major version number:" << std::endl;
|
||||||
|
Generator.SetVersion(
|
||||||
|
static_cast<uint8_t>(ReadInt(0, 15, 15, "(range: 0 ~ 15, default: 15)> ", "Invalid number."))
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
return Generator;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
SerialNumberGenerator CollectInformationAdvanced() {
|
||||||
|
SerialNumberGenerator Generator;
|
||||||
|
|
||||||
|
std::cout << "[*] Navicat Product Signature:" << std::endl;
|
||||||
|
Generator.SetProductSignature(
|
||||||
|
static_cast<uint8_t>(ReadInt(0x00, 0xff, "(range: 0x00 ~ 0xFF)> ", "Invalid number."))
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << "[*] Navicat Language Signature 0:" << std::endl;
|
||||||
|
auto s1 = static_cast<uint8_t>(ReadInt(0x00, 0xff, "(range: 0x00 ~ 0xFF)> ", "Invalid number."));
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << "[*] Navicat Language Signature 1:" << std::endl;
|
||||||
|
auto s2 = static_cast<uint8_t>(ReadInt(0x00, 0xff, "(range: 0x00 ~ 0xFF)> ", "Invalid number."));
|
||||||
|
|
||||||
|
Generator.SetLanguageSignature(s1, s2);
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << "[*] Input major version number:" << std::endl;
|
||||||
|
Generator.SetVersion(
|
||||||
|
static_cast<uint8_t>(ReadInt(0, 15, 12, "(range: 0 ~ 15, default: 12)> ", "Invalid number."))
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
return Generator;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,41 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <openssl/crypto.h>
|
|
||||||
#include <openssl/des.h>
|
|
||||||
#include <memory.h>
|
|
||||||
|
|
||||||
class DESCipher {
|
|
||||||
private:
|
|
||||||
DES_cblock _Key;
|
|
||||||
DES_key_schedule _Schedule;
|
|
||||||
public:
|
|
||||||
|
|
||||||
DESCipher() noexcept : _Key{}, _Schedule{} {}
|
|
||||||
|
|
||||||
void SetKey(const void* pKey) noexcept {
|
|
||||||
memcpy(&_Key, pKey, sizeof(_Key));
|
|
||||||
DES_set_odd_parity(&_Key);
|
|
||||||
DES_set_key(&_Key, &_Schedule);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clear() noexcept {
|
|
||||||
OPENSSL_cleanse(&_Key, sizeof(_Key));
|
|
||||||
OPENSSL_cleanse(&_Schedule, sizeof(_Schedule));
|
|
||||||
}
|
|
||||||
|
|
||||||
void EncryptBlock(void* lpBuffer) noexcept {
|
|
||||||
DES_cblock block;
|
|
||||||
DES_ecb_encrypt(reinterpret_cast<const_DES_cblock*>(lpBuffer), &block, &_Schedule, DES_ENCRYPT);
|
|
||||||
memcpy(lpBuffer, &block, sizeof(block));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DecryptBlock(void* lpBuffer) noexcept {
|
|
||||||
DES_cblock block;
|
|
||||||
DES_ecb_encrypt(reinterpret_cast<const_DES_cblock*>(lpBuffer), &block, &_Schedule, DES_DECRYPT);
|
|
||||||
memcpy(lpBuffer, &block, sizeof(block));
|
|
||||||
}
|
|
||||||
|
|
||||||
~DESCipher() noexcept {
|
|
||||||
Clear();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
131
navicat-keygen/GenerateLicense.cpp
Normal file
131
navicat-keygen/GenerateLicense.cpp
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
#include "Exception.hpp"
|
||||||
|
#include "ExceptionGeneric.hpp"
|
||||||
|
#include "ResourceWrapper.hpp"
|
||||||
|
#include "ResourceTraitsOpenssl.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>
|
||||||
|
|
||||||
|
namespace nkg {
|
||||||
|
|
||||||
|
void GenerateLicenseText(const RSACipher& Cipher, const SerialNumberGenerator& Generator) {
|
||||||
|
std::string utf8username;
|
||||||
|
std::string utf8organization;
|
||||||
|
|
||||||
|
std::string b64RequestCode;
|
||||||
|
std::vector<uint8_t> RequestCode;
|
||||||
|
std::string utf8RequestInfo;
|
||||||
|
std::string utf8ResponseInfo;
|
||||||
|
std::vector<uint8_t> ResponseCode;
|
||||||
|
std::string b64ResponseCode;
|
||||||
|
|
||||||
|
std::cout << "[*] Your name: ";
|
||||||
|
if (!std::getline(std::cin, utf8username)) {
|
||||||
|
throw ARL::EOFError(__FILE__, __LINE__, "Abort.");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "[*] Your organization: ";
|
||||||
|
if (!std::getline(std::cin, utf8organization)) {
|
||||||
|
throw ARL::EOFError(__FILE__, __LINE__, "Abort.");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::cout << "[*] Input request code in Base64: (Double press ENTER to end)" << std::endl;
|
||||||
|
while (true) {
|
||||||
|
std::string temp;
|
||||||
|
if (!std::getline(std::cin, temp)) {
|
||||||
|
throw ARL::EOFError(__FILE__, __LINE__, "Abort.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temp.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
b64RequestCode.append(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestCode = base64_decode(b64RequestCode);
|
||||||
|
if (RequestCode.size() != 256) {
|
||||||
|
throw ARL::AssertionError(__FILE__, __LINE__, "Broken request code. %zu", RequestCode.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
utf8RequestInfo.resize((Cipher.Bits() + 7) / 8);
|
||||||
|
Cipher.Decrypt(RequestCode.data(), RequestCode.size(), utf8RequestInfo.data(), RSA_PKCS1_PADDING);
|
||||||
|
while (utf8RequestInfo.back() == '\x00') {
|
||||||
|
utf8RequestInfo.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "[*] Request Info:" << std::endl;
|
||||||
|
std::cout << utf8RequestInfo << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
rapidjson::Document json;
|
||||||
|
rapidjson::Value N_Key;
|
||||||
|
rapidjson::Value N_Value;
|
||||||
|
rapidjson::Value O_Key;
|
||||||
|
rapidjson::Value O_Value;
|
||||||
|
rapidjson::Value T_Key;
|
||||||
|
rapidjson::Value T_Value;
|
||||||
|
rapidjson::StringBuffer buffer;
|
||||||
|
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Begin to parse
|
||||||
|
//
|
||||||
|
json.Parse(utf8RequestInfo.c_str());
|
||||||
|
//
|
||||||
|
// Remove "Platform" info
|
||||||
|
//
|
||||||
|
json.RemoveMember("P");
|
||||||
|
//
|
||||||
|
// Set "Name" info
|
||||||
|
//
|
||||||
|
N_Key.SetString("N", 1);
|
||||||
|
N_Value.SetString(utf8username.c_str(), static_cast<rapidjson::SizeType>(utf8username.length()));
|
||||||
|
//
|
||||||
|
// Set "Organization" info
|
||||||
|
//
|
||||||
|
O_Key.SetString("O", 1);
|
||||||
|
O_Value.SetString(utf8organization.c_str(), static_cast<rapidjson::SizeType>(utf8organization.length()));
|
||||||
|
//
|
||||||
|
// Set "Time" info
|
||||||
|
//
|
||||||
|
T_Key.SetString("T", 1);
|
||||||
|
T_Value.SetUint(static_cast<unsigned int>(std::time(nullptr)));
|
||||||
|
//
|
||||||
|
// Add "Name", "Organization" and "Time"
|
||||||
|
//
|
||||||
|
json.AddMember(N_Key, N_Value, json.GetAllocator());
|
||||||
|
json.AddMember(O_Key, O_Value, json.GetAllocator());
|
||||||
|
json.AddMember(T_Key, T_Value, json.GetAllocator());
|
||||||
|
|
||||||
|
json.Accept(writer);
|
||||||
|
if (buffer.GetSize() > 240) {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "Response info is too long.");
|
||||||
|
}
|
||||||
|
|
||||||
|
utf8ResponseInfo.assign(buffer.GetString(), buffer.GetSize());
|
||||||
|
|
||||||
|
std::cout << "[*] Response Info:" << std::endl;
|
||||||
|
std::cout << utf8ResponseInfo << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
ResponseCode.resize((Cipher.Bits() + 7) / 8);
|
||||||
|
Cipher.Encrypt<RSAKeyType::PrivateKey>(utf8ResponseInfo.data(), utf8ResponseInfo.size(), ResponseCode.data(), RSA_PKCS1_PADDING);
|
||||||
|
|
||||||
|
b64ResponseCode = base64_encode(ResponseCode);
|
||||||
|
|
||||||
|
std::cout << "[*] Activation Code:" << std::endl;
|
||||||
|
std::cout << b64ResponseCode << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,195 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <string>
|
|
||||||
#include <random>
|
|
||||||
#include "DESCipher.hpp"
|
|
||||||
|
|
||||||
class NavicatKeygen {
|
|
||||||
public:
|
|
||||||
enum class Language {
|
|
||||||
English,
|
|
||||||
SimplifiedChinese,
|
|
||||||
TraditionalChinese,
|
|
||||||
Japanese,
|
|
||||||
Polish,
|
|
||||||
Spanish,
|
|
||||||
French,
|
|
||||||
German,
|
|
||||||
Korean,
|
|
||||||
Russian,
|
|
||||||
Portuguese
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Product {
|
|
||||||
DataModeler,
|
|
||||||
Premium,
|
|
||||||
MySQL,
|
|
||||||
PostgreSQL,
|
|
||||||
Oracle,
|
|
||||||
SQLServer,
|
|
||||||
SQLite,
|
|
||||||
MariaDB,
|
|
||||||
MongoDB,
|
|
||||||
ReportViewer
|
|
||||||
};
|
|
||||||
private:
|
|
||||||
std::random_device rand_dev;
|
|
||||||
std::default_random_engine rand_eng;
|
|
||||||
std::uniform_int_distribution<int> rand;
|
|
||||||
uint8_t data[10];
|
|
||||||
public:
|
|
||||||
|
|
||||||
NavicatKeygen() : rand_eng(rand_dev()), rand(0, UINT8_MAX), data{} {
|
|
||||||
data[0] = 0x68;
|
|
||||||
data[1] = 0x2A;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetLanguageSignature(Language _language) {
|
|
||||||
switch (_language) {
|
|
||||||
case Language::English:
|
|
||||||
data[5] = 0xAC; // Must be 0xAC for English version.
|
|
||||||
data[6] = 0x88; // Must be 0x88 for English version.
|
|
||||||
break;
|
|
||||||
case Language::SimplifiedChinese:
|
|
||||||
data[5] = 0xCE; // Must be 0xCE for Simplified Chinese version.
|
|
||||||
data[6] = 0x32; // Must be 0x32 for Simplified Chinese version.
|
|
||||||
break;
|
|
||||||
case Language::TraditionalChinese:
|
|
||||||
data[5] = 0xAA; // Must be 0xAA for Traditional Chinese version.
|
|
||||||
data[6] = 0x99; // Must be 0x99 for Traditional Chinese version.
|
|
||||||
break;
|
|
||||||
case Language::Japanese:
|
|
||||||
data[5] = 0xAD; // Must be 0xAD for Japanese version. Discoverer: @dragonflylee
|
|
||||||
data[6] = 0x82; // Must be 0x82 for Japanese version. Discoverer: @dragonflylee
|
|
||||||
break;
|
|
||||||
case Language::Polish:
|
|
||||||
data[5] = 0xBB; // Must be 0xBB for Polish version. Discoverer: @dragonflylee
|
|
||||||
data[6] = 0x55; // Must be 0x55 for Polish version. Discoverer: @dragonflylee
|
|
||||||
break;
|
|
||||||
case Language::Spanish:
|
|
||||||
data[5] = 0xAE; // Must be 0xAE for Spanish version. Discoverer: @dragonflylee
|
|
||||||
data[6] = 0x10; // Must be 0x10 for Spanish version. Discoverer: @dragonflylee
|
|
||||||
break;
|
|
||||||
case Language::French:
|
|
||||||
data[5] = 0xFA; // Must be 0xFA for French version. Discoverer: @Deltafox79
|
|
||||||
data[6] = 0x20; // Must be 0x20 for French version. Discoverer: @Deltafox79
|
|
||||||
break;
|
|
||||||
case Language::German:
|
|
||||||
data[5] = 0xB1; // Must be 0xB1 for German version. Discoverer: @dragonflylee
|
|
||||||
data[6] = 0x60; // Must be 0x60 for German version. Discoverer: @dragonflylee
|
|
||||||
break;
|
|
||||||
case Language::Korean:
|
|
||||||
data[5] = 0xB5; // Must be 0xB5 for Korean version. Discoverer: @dragonflylee
|
|
||||||
data[6] = 0x60; // Must be 0x60 for Korean version. Discoverer: @dragonflylee
|
|
||||||
break;
|
|
||||||
case Language::Russian:
|
|
||||||
data[5] = 0xEE; // Must be 0xB5 for Russian version. Discoverer: @dragonflylee
|
|
||||||
data[6] = 0x16; // Must be 0x60 for Russian version. Discoverer: @dragonflylee
|
|
||||||
break;
|
|
||||||
case Language::Portuguese:
|
|
||||||
data[5] = 0xCD; // Must be 0xCD for Portuguese version. Discoverer: @dragonflylee
|
|
||||||
data[6] = 0x49; // Must be 0x49 for Portuguese version. Discoverer: @dragonflylee
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetLanguageSignature(uint8_t value0, uint8_t value1) {
|
|
||||||
data[5] = value0;
|
|
||||||
data[6] = value1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetProductSignature(Product _product) {
|
|
||||||
switch (_product) {
|
|
||||||
case Product::DataModeler:
|
|
||||||
data[7] = 0x47;
|
|
||||||
break;
|
|
||||||
case Product::Premium:
|
|
||||||
data[7] = 0x65;
|
|
||||||
break;
|
|
||||||
case Product::MySQL:
|
|
||||||
data[7] = 0x68;
|
|
||||||
break;
|
|
||||||
case Product::PostgreSQL:
|
|
||||||
data[7] = 0x6C;
|
|
||||||
break;
|
|
||||||
case Product::Oracle:
|
|
||||||
data[7] = 0x70;
|
|
||||||
break;
|
|
||||||
case Product::SQLServer:
|
|
||||||
data[7] = 0x74;
|
|
||||||
break;
|
|
||||||
case Product::SQLite:
|
|
||||||
data[7] = 0x78;
|
|
||||||
break;
|
|
||||||
case Product::MariaDB:
|
|
||||||
data[7] = 0x7C;
|
|
||||||
break;
|
|
||||||
case Product::MongoDB:
|
|
||||||
data[7] = 0x80;
|
|
||||||
break;
|
|
||||||
case Product::ReportViewer:
|
|
||||||
data[7] = 0xb;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetProductSignature(uint8_t value) {
|
|
||||||
data[7] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetVersion(uint8_t version) {
|
|
||||||
data[8] = version << 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Generate() {
|
|
||||||
static uint8_t DESKey[] = { 0x64, 0xAD, 0xF3, 0x2F, 0xAE, 0xF2, 0x1A, 0x27 };
|
|
||||||
DESCipher cipher;
|
|
||||||
|
|
||||||
data[2] = static_cast<uint8_t>(rand(rand_eng));
|
|
||||||
data[3] = static_cast<uint8_t>(rand(rand_eng));
|
|
||||||
data[4] = static_cast<uint8_t>(rand(rand_eng));
|
|
||||||
data[9] = 0x32;
|
|
||||||
|
|
||||||
cipher.SetKey(&DESKey);
|
|
||||||
cipher.EncryptBlock(data + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GetKey() const {
|
|
||||||
static const char EncodeTable[] = "ABCDEFGH8JKLMN9PQRSTUVWXYZ234567";
|
|
||||||
std::string Key;
|
|
||||||
|
|
||||||
Key.resize(16);
|
|
||||||
|
|
||||||
Key[0] = EncodeTable[data[0] >> 3];
|
|
||||||
Key[1] = EncodeTable[(data[0] & 0x07) << 2 | data[1] >> 6];
|
|
||||||
Key[2] = EncodeTable[data[1] >> 1 & 0x1F];
|
|
||||||
Key[3] = EncodeTable[(data[1] & 0x1) << 4 | data[2] >> 4];
|
|
||||||
Key[4] = EncodeTable[(data[2] & 0xF) << 1 | data[3] >> 7];
|
|
||||||
Key[5] = EncodeTable[data[3] >> 2 & 0x1F];
|
|
||||||
Key[6] = EncodeTable[(data[3] << 3 & 0x1F) | data[4] >> 5];
|
|
||||||
Key[7] = EncodeTable[data[4] & 0x1F];
|
|
||||||
|
|
||||||
Key[8] = EncodeTable[data[5] >> 3];
|
|
||||||
Key[9] = EncodeTable[(data[5] & 0x07) << 2 | data[6] >> 6];
|
|
||||||
Key[10] = EncodeTable[data[6] >> 1 & 0x1F];
|
|
||||||
Key[11] = EncodeTable[(data[6] & 0x1) << 4 | data[7] >> 4];
|
|
||||||
Key[12] = EncodeTable[(data[7] & 0xF) << 1 | data[8] >> 7];
|
|
||||||
Key[13] = EncodeTable[data[8] >> 2 & 0x1F];
|
|
||||||
Key[14] = EncodeTable[(data[8] << 3 & 0x1F) | data[9] >> 5];
|
|
||||||
Key[15] = EncodeTable[data[9] & 0x1F];
|
|
||||||
|
|
||||||
return Key;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GetFormatedKey() const {
|
|
||||||
std::string Key = GetKey();
|
|
||||||
Key.insert(Key.begin() + 4, '-');
|
|
||||||
Key.insert(Key.begin() + 5 + 4, '-');
|
|
||||||
Key.insert(Key.begin() + 10 + 4, '-');
|
|
||||||
return Key;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
183
navicat-keygen/SerialNumberGenerator.cpp
Normal file
183
navicat-keygen/SerialNumberGenerator.cpp
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
#include "SerialNumberGenerator.hpp"
|
||||||
|
#include "Exception.hpp"
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
#include <openssl/des.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "Base32.hpp"
|
||||||
|
|
||||||
|
namespace nkg {
|
||||||
|
|
||||||
|
SerialNumberGenerator::SerialNumberGenerator() noexcept :
|
||||||
|
m_Data{ 0x68 , 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32 } {}
|
||||||
|
|
||||||
|
void SerialNumberGenerator::SetLanguageSignature(NavicatLanguage Language) noexcept {
|
||||||
|
switch (Language) {
|
||||||
|
case NavicatLanguage::English:
|
||||||
|
m_Data[5] = 0xAC; // Must be 0xAC for English version.
|
||||||
|
m_Data[6] = 0x88; // Must be 0x88 for English version.
|
||||||
|
break;
|
||||||
|
case NavicatLanguage::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 NavicatLanguage::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 NavicatLanguage::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 NavicatLanguage::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 NavicatLanguage::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 NavicatLanguage::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 NavicatLanguage::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 NavicatLanguage::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 NavicatLanguage::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 NavicatLanguage::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 SerialNumberGenerator::SetLanguageSignature(uint8_t LanguageSignature0, uint8_t LanguageSignature1) noexcept {
|
||||||
|
m_Data[5] = LanguageSignature0;
|
||||||
|
m_Data[6] = LanguageSignature1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialNumberGenerator::SetProductSignature(NavicatProductType ProductType) noexcept {
|
||||||
|
switch (ProductType) {
|
||||||
|
case NavicatProductType::DataModeler:
|
||||||
|
m_Data[7] = 0x84;
|
||||||
|
break;
|
||||||
|
case NavicatProductType::Premium:
|
||||||
|
m_Data[7] = 0x65;
|
||||||
|
break;
|
||||||
|
case NavicatProductType::MySQL:
|
||||||
|
m_Data[7] = 0x68;
|
||||||
|
break;
|
||||||
|
case NavicatProductType::PostgreSQL:
|
||||||
|
m_Data[7] = 0x6C;
|
||||||
|
break;
|
||||||
|
case NavicatProductType::Oracle:
|
||||||
|
m_Data[7] = 0x70;
|
||||||
|
break;
|
||||||
|
case NavicatProductType::SQLServer:
|
||||||
|
m_Data[7] = 0x74;
|
||||||
|
break;
|
||||||
|
case NavicatProductType::SQLite:
|
||||||
|
m_Data[7] = 0x78;
|
||||||
|
break;
|
||||||
|
case NavicatProductType::MariaDB:
|
||||||
|
m_Data[7] = 0x7C;
|
||||||
|
break;
|
||||||
|
case NavicatProductType::MongoDB:
|
||||||
|
m_Data[7] = 0x80;
|
||||||
|
break;
|
||||||
|
case NavicatProductType::ReportViewer:
|
||||||
|
m_Data[7] = 0x0b;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialNumberGenerator::SetProductSignature(uint8_t ProductSignature) noexcept {
|
||||||
|
m_Data[7] = ProductSignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialNumberGenerator::SetVersion(uint8_t Version) {
|
||||||
|
if (Version < 0x10) {
|
||||||
|
m_Data[8] = static_cast<uint8_t>(Version << 4);
|
||||||
|
} else {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "Invalid version for Navicat.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialNumberGenerator::Generate() {
|
||||||
|
static auto translator = [](char c) {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
//static const char StandardBase32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||||
|
//static const char NavicatBase32[] = "ABCDEFGH8JKLMN9PQRSTUVWXYZ234567";
|
||||||
|
switch (c) {
|
||||||
|
case 'I':
|
||||||
|
return '8';
|
||||||
|
case 'O':
|
||||||
|
return '9';
|
||||||
|
default:
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
//static const char StandardBase32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||||
|
//static const char NavicatBase32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||||
|
return c;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
RAND_bytes(m_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*>(m_Data + 2),
|
||||||
|
reinterpret_cast<const_DES_cblock*>(m_Data + 2),
|
||||||
|
&schedule,
|
||||||
|
DES_ENCRYPT
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
m_SerialNumberShort = base32_encode(m_Data, sizeof(m_Data));
|
||||||
|
std::transform(m_SerialNumberShort.begin(), m_SerialNumberShort.end(), m_SerialNumberShort.begin(), translator);
|
||||||
|
|
||||||
|
m_SerialNumberLong.resize(20);
|
||||||
|
snprintf(m_SerialNumberLong.data(), m_SerialNumberLong.length(),
|
||||||
|
"%.4s-%.4s-%.4s-%.4s",
|
||||||
|
m_SerialNumberShort.c_str() + 0,
|
||||||
|
m_SerialNumberShort.c_str() + 4,
|
||||||
|
m_SerialNumberShort.c_str() + 8,
|
||||||
|
m_SerialNumberShort.c_str() + 12
|
||||||
|
);
|
||||||
|
while (m_SerialNumberLong.back() == '\x00') {
|
||||||
|
m_SerialNumberLong.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const std::string& SerialNumberGenerator::GetSerialNumberShort() const noexcept {
|
||||||
|
return m_SerialNumberShort;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const std::string& SerialNumberGenerator::GetSerialNumberLong() const noexcept {
|
||||||
|
return m_SerialNumberLong;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialNumberGenerator::ShowInConsole() const {
|
||||||
|
std::cout << "[*] Serial number:" << std::endl;
|
||||||
|
std::cout << m_SerialNumberLong << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
65
navicat-keygen/SerialNumberGenerator.hpp
Normal file
65
navicat-keygen/SerialNumberGenerator.hpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
uint8_t m_Data[10];
|
||||||
|
std::string m_SerialNumberShort;
|
||||||
|
std::string m_SerialNumberLong;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
SerialNumberGenerator() noexcept;
|
||||||
|
|
||||||
|
void SetLanguageSignature(NavicatLanguage Language) noexcept;
|
||||||
|
void SetLanguageSignature(uint8_t LanguageSignature0, uint8_t LanguageSignature1) noexcept;
|
||||||
|
|
||||||
|
void SetProductSignature(NavicatProductType ProductType) noexcept;
|
||||||
|
void SetProductSignature(uint8_t ProductSignature) noexcept;
|
||||||
|
|
||||||
|
void SetVersion(uint8_t Version);
|
||||||
|
|
||||||
|
void Generate();
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const std::string& GetSerialNumberShort() const noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const std::string& GetSerialNumberLong() const noexcept;
|
||||||
|
|
||||||
|
void ShowInConsole() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,251 +1,96 @@
|
|||||||
#include <stddef.h> // NOLINT
|
#include <stdio.h>
|
||||||
#include <stdint.h> // NOLINT
|
#include <string.h>
|
||||||
#include <iostream>
|
#include "Exception.hpp"
|
||||||
#include <vector>
|
#include "ExceptionGeneric.hpp"
|
||||||
#include <string>
|
#include "RSACipher.hpp"
|
||||||
|
#include "SerialNumberGenerator.hpp"
|
||||||
|
|
||||||
#include "../common/RSACipher.hpp"
|
namespace nkg {
|
||||||
#include "NavicatKeygen.hpp"
|
using fnCollectInformation = SerialNumberGenerator();
|
||||||
|
|
||||||
#include <rapidjson/document.h>
|
SerialNumberGenerator CollectInformationNormal();
|
||||||
#include <rapidjson/writer.h>
|
SerialNumberGenerator CollectInformationAdvanced();
|
||||||
#include <rapidjson/stringbuffer.h>
|
void GenerateLicenseText(const RSACipher& Cipher, const SerialNumberGenerator& Generator);
|
||||||
|
}
|
||||||
|
|
||||||
template<int min_num, int max_num>
|
static void Welcome() {
|
||||||
bool read_int(int& num, const char* prompt, const char* err_msg) {
|
puts("**********************************************************");
|
||||||
int temp;
|
puts("* Navicat Keygen (macOS) by @DoubleLabyrinth *");
|
||||||
std::string input;
|
puts("* Version: 5.0 *");
|
||||||
|
puts("**********************************************************");
|
||||||
|
puts("");
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
static void Help() {
|
||||||
std::cout << prompt;
|
puts("Usage:");
|
||||||
if (!std::getline(std::cin, input))
|
puts(" navicat-keygen [--adv] <RSA-2048 Private Key File>");
|
||||||
return false;
|
puts("");
|
||||||
|
puts(" [--adv] Enable advance mode.");
|
||||||
|
puts(" This parameter is optional.");
|
||||||
|
puts("");
|
||||||
|
puts(" <RSA-2048 Private Key File> A path to an RSA-2048 private key file.");
|
||||||
|
puts(" This parameter must be specified.");
|
||||||
|
puts("");
|
||||||
|
puts("Example:");
|
||||||
|
puts(" ./navicat-keygen ./RegPrivateKey.pem");
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
int main(int argc, const char* argv[]) {
|
||||||
temp = std::stoi(input, nullptr, 0);
|
Welcome();
|
||||||
if (min_num <= temp && temp <= max_num) {
|
|
||||||
num = temp;
|
if (argc == 2 || argc == 3) {
|
||||||
return true;
|
nkg::fnCollectInformation* lpfnCollectInformation = nullptr;
|
||||||
|
|
||||||
|
if (argc == 3) {
|
||||||
|
if (strcasecmp(argv[1], "--adv") == 0) {
|
||||||
|
lpfnCollectInformation = nkg::CollectInformationAdvanced;
|
||||||
} else {
|
} else {
|
||||||
throw std::invalid_argument(err_msg);
|
Help();
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} else {
|
||||||
std::cout << err_msg << std::endl;
|
lpfnCollectInformation = nkg::CollectInformationNormal;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string base64_encode(const std::vector<uint8_t>& bindata);
|
|
||||||
std::vector<uint8_t> base64_decode(const std::string& ascdata);
|
|
||||||
|
|
||||||
void Help() {
|
|
||||||
std::cout << "***************************************************" << std::endl;
|
|
||||||
std::cout << "* Navicat Keygen by @DoubleLabyrinth *" << std::endl;
|
|
||||||
std::cout << "* Version: 4.0 *" << std::endl;
|
|
||||||
std::cout << "***************************************************" << std::endl;
|
|
||||||
std::cout << std::endl;
|
|
||||||
std::cout << "Usage:" << std::endl;
|
|
||||||
std::cout << " navicat-keygen <RSA-2048 Private Key File>" << std::endl;
|
|
||||||
std::cout << std::endl;
|
|
||||||
std::cout << " <RSA-2048 Private Key File> Path to a PEM-format RSA-2048 private key file." << std::endl;
|
|
||||||
std::cout << " This parameter must be specified." << std::endl;
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
if (argc != 2) {
|
|
||||||
Help();
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
try {
|
try {
|
||||||
std::cout << "***************************************************" << std::endl;
|
nkg::RSACipher Cipher;
|
||||||
std::cout << "* Navicat Keygen by @DoubleLabyrinth *" << std::endl;
|
|
||||||
std::cout << "* Version: 4.0 *" << std::endl;
|
|
||||||
std::cout << "***************************************************" << std::endl;
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
RSACipher RsaCipher;
|
Cipher.ImportKeyFromFile<nkg::RSAKeyType::PrivateKey, nkg::RSAKeyFormat::PEM>(argv[argc - 1]);
|
||||||
|
if (Cipher.Bits() != 2048) {
|
||||||
int select_num;
|
throw ARL::Exception(__FILE__, __LINE__, "RSA key length mismatches.")
|
||||||
|
.PushHint("You must provide an RSA key whose modulus length is 2048 bits.");
|
||||||
NavicatKeygen keygen;
|
|
||||||
std::string username;
|
|
||||||
std::string organization;
|
|
||||||
|
|
||||||
std::string RequestCode_b64;
|
|
||||||
std::vector<uint8_t> RequestCode;
|
|
||||||
char RequestInfo[256] = {};
|
|
||||||
char ResponseInfo[256] = {};
|
|
||||||
std::vector<uint8_t> ResponseCode;
|
|
||||||
std::string ResponseCode_b64;
|
|
||||||
|
|
||||||
rapidjson::Document json;
|
|
||||||
rapidjson::Value N_Key;
|
|
||||||
rapidjson::Value N_Value;
|
|
||||||
rapidjson::Value O_Key;
|
|
||||||
rapidjson::Value O_Value;
|
|
||||||
rapidjson::Value T_Key;
|
|
||||||
rapidjson::Value T_Value;
|
|
||||||
rapidjson::StringBuffer buffer;
|
|
||||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
|
||||||
|
|
||||||
RsaCipher.ImportKeyFromFile<RSAKeyType::PrivateKey, RSAKeyFormat::PEM>(argv[1]);
|
|
||||||
if (RsaCipher.Bits() != 2048) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Not RSA-2048 private key file.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
keygen.SetProductSignature(NavicatKeygen::Product::Premium);
|
auto Generator = lpfnCollectInformation();
|
||||||
|
|
||||||
std::cout
|
Generator.Generate();
|
||||||
<< "Which is your Navicat Premium language?" << std::endl
|
Generator.ShowInConsole();
|
||||||
<< "0. English" << std::endl
|
|
||||||
<< "1. Simplified Chinese" << std::endl
|
|
||||||
<< "2. Traditional Chinese" << std::endl
|
|
||||||
<< "3. Japanese" << std::endl
|
|
||||||
<< "4. Polish" << std::endl
|
|
||||||
<< "5. Spanish" << std::endl
|
|
||||||
<< "6. French" << std::endl
|
|
||||||
<< "7. German" << std::endl
|
|
||||||
<< "8. Korean" << std::endl
|
|
||||||
<< "9. Russian" << std::endl
|
|
||||||
<< "10. Portuguese" << std::endl
|
|
||||||
<< std::endl;
|
|
||||||
if (read_int<0, 10>(select_num, "(Input index)> ", "Invalid index.")) {
|
|
||||||
keygen.SetLanguageSignature(static_cast<NavicatKeygen::Language>(select_num));
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
GenerateLicenseText(Cipher, Generator);
|
||||||
|
|
||||||
if (read_int<0, 15>(select_num, "(Input major version number, range: 0 ~ 15, default: 12)> ", "Invalid number.")) {
|
|
||||||
keygen.SetVersion(static_cast<uint8_t>(select_num));
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Generate snKey
|
|
||||||
//
|
|
||||||
keygen.Generate();
|
|
||||||
std::cout << std::endl;
|
|
||||||
std::cout << "Serial number:" << std::endl;
|
|
||||||
std::cout << keygen.GetFormatedKey() << std::endl;
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Get user name
|
|
||||||
//
|
|
||||||
std::cout << "Your name: ";
|
|
||||||
if (!std::getline(std::cin, username)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Get organization name
|
|
||||||
//
|
|
||||||
std::cout << "Your organization: ";
|
|
||||||
if (!std::getline(std::cin, organization)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Get request code in base64
|
|
||||||
//
|
|
||||||
std::cout << "Input request code (in Base64), input empty line to end:" << std::endl;
|
|
||||||
while (true) {
|
|
||||||
std::string temp;
|
|
||||||
if (!std::getline(std::cin, temp))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (temp.empty())
|
|
||||||
break;
|
|
||||||
|
|
||||||
RequestCode_b64 += temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Get request code in raw bytes
|
|
||||||
//
|
|
||||||
RequestCode = base64_decode(RequestCode_b64);
|
|
||||||
if (RequestCode.size() > ((RsaCipher.Bits() + 7) / 8)) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Request code is too long.");
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Decrypt to get request info
|
|
||||||
//
|
|
||||||
RsaCipher.Decrypt(RequestCode.data(), static_cast<int>(RequestCode.size()), RequestInfo, RSA_PKCS1_PADDING);
|
|
||||||
|
|
||||||
//
|
|
||||||
// print out request info
|
|
||||||
//
|
|
||||||
std::cout << "Request Info:" << std::endl;
|
|
||||||
std::cout << RequestInfo << std::endl;
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Generate response info
|
|
||||||
//
|
|
||||||
json.Parse(RequestInfo);
|
|
||||||
json.RemoveMember("P"); // remove Platform info
|
|
||||||
|
|
||||||
N_Key.SetString("N", 1);
|
|
||||||
N_Value.SetString(username.c_str(), static_cast<rapidjson::SizeType>(username.length()));
|
|
||||||
O_Key.SetString("O", 1);
|
|
||||||
O_Value.SetString(organization.c_str(), static_cast<rapidjson::SizeType>(organization.length()));
|
|
||||||
T_Key.SetString("T", 1);
|
|
||||||
T_Value.SetUint(static_cast<unsigned>(std::time(nullptr)));
|
|
||||||
|
|
||||||
json.AddMember(N_Key, N_Value, json.GetAllocator());
|
|
||||||
json.AddMember(O_Key, O_Value, json.GetAllocator());
|
|
||||||
json.AddMember(T_Key, T_Value, json.GetAllocator());
|
|
||||||
|
|
||||||
json.Accept(writer);
|
|
||||||
|
|
||||||
if (buffer.GetSize() > 240) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Response info is too long.");
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// print out response info
|
|
||||||
//
|
|
||||||
memcpy(ResponseInfo, buffer.GetString(), buffer.GetSize());
|
|
||||||
std::cout << "Response Info:" << std::endl;
|
|
||||||
std::cout << ResponseInfo << std::endl;
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
//
|
|
||||||
// encrypt response info
|
|
||||||
//
|
|
||||||
ResponseCode.resize((RsaCipher.Bits() + 7) / 8);
|
|
||||||
RsaCipher.Encrypt<RSAKeyType::PrivateKey>(ResponseInfo, static_cast<int>(strlen(ResponseInfo)), ResponseCode.data(), RSA_PKCS1_PADDING);
|
|
||||||
|
|
||||||
//
|
|
||||||
// encode encrypted response info in base64 format
|
|
||||||
//
|
|
||||||
ResponseCode_b64 = base64_encode(ResponseCode);
|
|
||||||
|
|
||||||
//
|
|
||||||
// print out activation code
|
|
||||||
//
|
|
||||||
std::cout << "License:" << std::endl;
|
|
||||||
std::cout << ResponseCode_b64 << std::endl;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} catch (nkg::Exception& e) {
|
} catch (ARL::EOFError&) {
|
||||||
std::cout << "[-] " << e.File() << ":" << e.Line() << " ->" << std::endl;
|
return ECANCELED;
|
||||||
std::cout << " " << e.Message() << std::endl;
|
} catch (ARL::Exception& e) {
|
||||||
|
printf("[-] %s:%zu ->\n", e.ExceptionFile(), e.ExceptionLine());
|
||||||
|
printf(" %s\n", e.ExceptionMessage());
|
||||||
|
|
||||||
if (e.HasErrorCode()) {
|
if (e.HasErrorCode()) {
|
||||||
std::cout << " " << e.ErrorString() << std::endl;
|
printf(" %s (0x%zx)\n", e.ErrorString(), e.ErrorCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& Hint : e.Hints()) {
|
||||||
|
printf(" Hints: %s\n", Hint.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
printf("[-] %s\n", e.what());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Help();
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,76 +1,95 @@
|
|||||||
#include "CapstoneDisassembler.hpp"
|
#include "CapstoneDisassembler.hpp"
|
||||||
|
|
||||||
CapstoneDisassembler CapstoneDisassembler::Create(cs_arch ArchType, cs_mode Mode) {
|
namespace nkg {
|
||||||
CapstoneDisassembler NewDisassembler;
|
|
||||||
|
|
||||||
auto err = cs_open(ArchType, Mode, NewDisassembler.pvt_Handle.GetAddress());
|
CapstoneDisassembler::CapstoneDisassembler(const CapstoneEngine& Engine) :
|
||||||
if (err != CS_ERR_OK) {
|
ARL::ResourceWrapper<ARL::ResourceTraits::CapstoneInsn>(cs_malloc(Engine)),
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
m_Engine(Engine),
|
||||||
throw nkg::CapstoneError(__FILE__, __LINE__, err, "cs_open failed.");
|
m_CurrentState{},
|
||||||
|
m_NextState{},
|
||||||
|
m_lpCurrentInsn(nullptr)
|
||||||
|
{
|
||||||
|
if (IsValid() == false) {
|
||||||
|
throw ARL::CapstoneError(__FILE__, __LINE__, cs_errno(Engine), "cs_malloc failed.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NewDisassembler.pvt_Insn.TakeOver(cs_malloc(NewDisassembler.pvt_Handle));
|
CapstoneDisassembler& CapstoneDisassembler::SetContext(const CapstoneContext& Ctx) noexcept {
|
||||||
if (NewDisassembler.pvt_Insn.IsValid() == false) {
|
m_lpCurrentInsn = nullptr;
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::CapstoneError(__FILE__, __LINE__, cs_errno(NewDisassembler.pvt_Handle), "cs_malloc failed.");
|
m_CurrentState.lpMachineCode = nullptr;
|
||||||
|
m_CurrentState.cbMachineCode = 0;
|
||||||
|
m_CurrentState.Address = 0;
|
||||||
|
|
||||||
|
m_NextState = Ctx;
|
||||||
|
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewDisassembler;
|
[[nodiscard]]
|
||||||
}
|
const CapstoneContext& CapstoneDisassembler::GetContext() const noexcept {
|
||||||
|
return m_NextState;
|
||||||
void CapstoneDisassembler::Option(cs_opt_type Type, size_t Value) {
|
|
||||||
auto err = cs_option(pvt_Handle, Type, Value);
|
|
||||||
if (err != CS_ERR_OK) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::CapstoneError(__FILE__, __LINE__, err, "cs_option failed.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pvt_CurrentInsn = nullptr;
|
[[nodiscard]]
|
||||||
|
bool CapstoneDisassembler::Next() noexcept {
|
||||||
|
bool bSucceed;
|
||||||
|
CapstoneContext backup = m_NextState;
|
||||||
|
|
||||||
pvt_Insn.TakeOver(cs_malloc(pvt_Handle));
|
bSucceed = cs_disasm_iter(m_Engine.Get(), reinterpret_cast<const uint8_t**>(&m_NextState.lpMachineCode), &m_NextState.cbMachineCode, &m_NextState.Address, Get());
|
||||||
if (pvt_Insn.IsValid() == false) {
|
if (bSucceed) {
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
if (m_lpCurrentInsn == nullptr) {
|
||||||
throw nkg::CapstoneError(__FILE__, __LINE__, cs_errno(pvt_Handle), "cs_malloc failed.");
|
m_lpCurrentInsn = Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_CurrentState = backup;
|
||||||
|
} else {
|
||||||
|
m_lpCurrentInsn = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bSucceed;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void CapstoneDisassembler::SetContext(uintptr_t lpOpcode, size_t cbOpcode, uint64_t Address) noexcept {
|
[[nodiscard]]
|
||||||
pvt_CurrentCtx.pbOpcode = reinterpret_cast<const uint8_t*>(lpOpcode);
|
const cs_insn* CapstoneDisassembler::GetInstruction() const noexcept {
|
||||||
pvt_CurrentCtx.cbOpcode = cbOpcode;
|
return m_lpCurrentInsn;
|
||||||
pvt_CurrentCtx.Address = Address;
|
|
||||||
pvt_CurrentInsn = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CapstoneDisassembler::SetContext(const void* lpOpcode, size_t cbOpcode, uint64_t Address) noexcept {
|
|
||||||
pvt_CurrentCtx.pbOpcode = reinterpret_cast<const uint8_t*>(lpOpcode);
|
|
||||||
pvt_CurrentCtx.cbOpcode = cbOpcode;
|
|
||||||
pvt_CurrentCtx.Address = Address;
|
|
||||||
pvt_CurrentInsn = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CapstoneDisassembler::Context& CapstoneDisassembler::GetContext() const noexcept {
|
|
||||||
return pvt_CurrentCtx;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cs_insn* CapstoneDisassembler::GetInstruction() const noexcept {
|
|
||||||
return pvt_CurrentInsn;
|
|
||||||
}
|
|
||||||
|
|
||||||
CapstoneDisassembler::Context CapstoneDisassembler::GetInstructionContext() const noexcept {
|
|
||||||
Context CtxOfInsn = {};
|
|
||||||
CtxOfInsn.pbOpcode = pvt_CurrentCtx.pbOpcode - pvt_CurrentInsn->size;
|
|
||||||
CtxOfInsn.cbOpcode = pvt_CurrentCtx.cbOpcode + pvt_CurrentInsn->size;
|
|
||||||
CtxOfInsn.Address = pvt_CurrentCtx.Address - pvt_CurrentInsn->size;
|
|
||||||
return CtxOfInsn;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CapstoneDisassembler::Next() noexcept {
|
|
||||||
bool bSucceed = cs_disasm_iter(pvt_Handle, &pvt_CurrentCtx.pbOpcode, &pvt_CurrentCtx.cbOpcode, &pvt_CurrentCtx.Address, pvt_Insn);
|
|
||||||
if (bSucceed) {
|
|
||||||
if (pvt_CurrentInsn == nullptr) pvt_CurrentInsn = pvt_Insn.Get();
|
|
||||||
} else {
|
|
||||||
pvt_CurrentInsn = nullptr;
|
|
||||||
}
|
}
|
||||||
return bSucceed;
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const CapstoneContext& CapstoneDisassembler::GetInstructionContext() const noexcept {
|
||||||
|
return m_CurrentState;
|
||||||
|
}
|
||||||
|
|
||||||
|
CapstoneEngine::CapstoneEngine(cs_arch ArchType, cs_mode Mode) {
|
||||||
|
auto err = cs_open(ArchType, Mode, GetAddressOf());
|
||||||
|
if (err != CS_ERR_OK) {
|
||||||
|
throw ARL::CapstoneError(__FILE__, __LINE__, err, "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 ARL::CapstoneError(__FILE__, __LINE__, err, "cs_option failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* CapstoneEngine::GetGroupName(unsigned int group_id) const noexcept {
|
||||||
|
return cs_group_name(Get(), group_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* CapstoneEngine::GetInstructionName(unsigned int instruction_id) const noexcept {
|
||||||
|
return cs_insn_name(Get(), instruction_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* CapstoneEngine::GetRegisterName(unsigned int register_id) const noexcept {
|
||||||
|
return cs_reg_name(Get(), register_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
CapstoneDisassembler CapstoneEngine::CreateDisassembler() const {
|
||||||
|
return CapstoneDisassembler(*this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,49 +1,63 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <capstone/capstone.h>
|
#include <capstone/capstone.h>
|
||||||
#include "../common/ResourceOwned.hpp"
|
#include "ExceptionCapstone.hpp"
|
||||||
|
#include "ResourceWrapper.hpp"
|
||||||
#include "ResourceTraitsCapstone.hpp"
|
#include "ResourceTraitsCapstone.hpp"
|
||||||
|
|
||||||
class CapstoneDisassembler {
|
namespace nkg {
|
||||||
public:
|
|
||||||
|
|
||||||
struct Context {
|
struct CapstoneContext {
|
||||||
const uint8_t* pbOpcode;
|
const void* lpMachineCode;
|
||||||
size_t cbOpcode;
|
size_t cbMachineCode;
|
||||||
uint64_t Address;
|
uint64_t Address;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
class CapstoneEngine;
|
||||||
|
|
||||||
ResourceOwned<CapstoneHandleTraits> pvt_Handle;
|
class CapstoneDisassembler : private ARL::ResourceWrapper<ARL::ResourceTraits::CapstoneInsn> {
|
||||||
ResourceOwned<CapstoneInsnTraits> pvt_Insn;
|
friend class CapstoneEngine;
|
||||||
Context pvt_CurrentCtx;
|
private:
|
||||||
cs_insn* pvt_CurrentInsn;
|
|
||||||
|
|
||||||
CapstoneDisassembler() noexcept :
|
const CapstoneEngine& m_Engine;
|
||||||
pvt_Handle(CapstoneHandleTraits{}),
|
CapstoneContext m_CurrentState;
|
||||||
pvt_Insn(CapstoneInsnTraits{}),
|
CapstoneContext m_NextState;
|
||||||
pvt_CurrentCtx{},
|
cs_insn* m_lpCurrentInsn;
|
||||||
pvt_CurrentInsn(nullptr) {}
|
|
||||||
public:
|
|
||||||
|
|
||||||
[[nodiscard]]
|
CapstoneDisassembler(const CapstoneEngine& Engine);
|
||||||
static CapstoneDisassembler Create(cs_arch ArchType, cs_mode Mode);
|
|
||||||
|
|
||||||
void Option(cs_opt_type Type, size_t Value);
|
public:
|
||||||
|
|
||||||
void SetContext(uintptr_t lpOpcode, size_t cbOpcode, uint64_t Address = 0) noexcept ;
|
CapstoneDisassembler& SetContext(const CapstoneContext& Ctx) noexcept;
|
||||||
|
|
||||||
void SetContext(const void* lpOpcode, size_t cbOpcode, uint64_t Address = 0) noexcept;
|
[[nodiscard]]
|
||||||
|
const CapstoneContext& GetContext() const noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
const Context& GetContext() const noexcept;
|
bool Next() noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
const cs_insn* GetInstruction() const noexcept;
|
const cs_insn* GetInstruction() const noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Context GetInstructionContext() const noexcept;
|
const CapstoneContext& GetInstructionContext() const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
[[nodiscard]]
|
class CapstoneEngine : private ARL::ResourceWrapper<ARL::ResourceTraits::CapstoneHandle> {
|
||||||
bool Next() noexcept;
|
friend class CapstoneDisassembler;
|
||||||
};
|
public:
|
||||||
|
|
||||||
|
CapstoneEngine(cs_arch ArchType, cs_mode Mode);
|
||||||
|
|
||||||
|
void Option(cs_opt_type Type, cs_opt_value Value);
|
||||||
|
|
||||||
|
const char* GetGroupName(unsigned int group_id) const noexcept;
|
||||||
|
|
||||||
|
const char* GetInstructionName(unsigned int instruction_id) const noexcept;
|
||||||
|
|
||||||
|
const char* GetRegisterName(unsigned int register_id) const noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
CapstoneDisassembler CreateDisassembler() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -1,19 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../common/Exception.hpp"
|
|
||||||
#include <capstone/capstone.h>
|
#include <capstone/capstone.h>
|
||||||
|
#include "Exception.hpp"
|
||||||
|
|
||||||
namespace nkg {
|
namespace ARL {
|
||||||
|
|
||||||
class CapstoneError final : public Exception {
|
class CapstoneError final : public Exception {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
cs_err pvt_ErrorCode;
|
cs_err m_ErrorCode;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CapstoneError(const char* File, unsigned Line, cs_err ErrorCode, const char* Message) noexcept :
|
template<typename... __ArgTypes>
|
||||||
Exception(File, Line, Message),
|
CapstoneError(const char* SourceFile, size_t SourceLine, cs_err ErrorCode, const char* Format, __ArgTypes&&... Args) noexcept :
|
||||||
pvt_ErrorCode(ErrorCode) {}
|
Exception(SourceFile, SourceLine, Format, std::forward<__ArgTypes>(Args)...),
|
||||||
|
m_ErrorCode(ErrorCode) {}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
@ -24,13 +25,13 @@ namespace nkg {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
virtual intptr_t ErrorCode() const noexcept override {
|
virtual intptr_t ErrorCode() const noexcept override {
|
||||||
return pvt_ErrorCode;
|
return m_ErrorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
virtual const char* ErrorString() const noexcept override {
|
virtual const char* ErrorString() const noexcept override {
|
||||||
return cs_strerror(pvt_ErrorCode);
|
return cs_strerror(m_ErrorCode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../common/Exception.hpp"
|
|
||||||
#include <keystone/keystone.h>
|
#include <keystone/keystone.h>
|
||||||
|
#include "Exception.hpp"
|
||||||
|
|
||||||
namespace nkg {
|
namespace ARL {
|
||||||
|
|
||||||
class KeystoneError final : public Exception {
|
class KeystoneError final : public Exception {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
ks_err pvt_ErrorCode;
|
ks_err m_ErrorCode;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
KeystoneError(const char* File, unsigned Line, ks_err ErrorCode, const char* Message) noexcept :
|
template<typename... __ArgTypes>
|
||||||
Exception(File, Line, Message),
|
KeystoneError(const char* SourceFile, size_t SourceLine, ks_err ErrorCode, const char* Format, __ArgTypes&&... Args) noexcept :
|
||||||
pvt_ErrorCode(ErrorCode) {}
|
Exception(SourceFile, SourceLine, Format, std::forward<__ArgTypes>(Args)...),
|
||||||
|
m_ErrorCode(ErrorCode) {}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
@ -24,13 +25,13 @@ namespace nkg {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
virtual intptr_t ErrorCode() const noexcept override {
|
virtual intptr_t ErrorCode() const noexcept override {
|
||||||
return pvt_ErrorCode;
|
return m_ErrorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
virtual const char* ErrorString() const noexcept override {
|
virtual const char* ErrorString() const noexcept override {
|
||||||
return ks_strerror(pvt_ErrorCode);
|
return ks_strerror(m_ErrorCode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,70 +0,0 @@
|
|||||||
#include <string.h> // NOLINT
|
|
||||||
#include "ExceptionCapstone.hpp"
|
|
||||||
#include "CapstoneDisassembler.hpp"
|
|
||||||
#include "X64ImageInterpreter.hpp"
|
|
||||||
|
|
||||||
namespace nkg {
|
|
||||||
|
|
||||||
bool IsResolvedTo(const X64ImageInterpreter& Image, const void* StubHelperProc, const char *Symbol) {
|
|
||||||
CapstoneDisassembler Disassembler = CapstoneDisassembler::Create(CS_ARCH_X86, CS_MODE_64);
|
|
||||||
|
|
||||||
Disassembler.Option(CS_OPT_DETAIL, CS_OPT_ON);
|
|
||||||
|
|
||||||
// A stub-helper proc must look like:
|
|
||||||
// push xxxxh;
|
|
||||||
// jmp loc_xxxxxxxx
|
|
||||||
// which should be 10 bytes long.
|
|
||||||
Disassembler.SetContext(StubHelperProc, 10);
|
|
||||||
|
|
||||||
if (Disassembler.Next() == false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto insn = Disassembler.GetInstruction();
|
|
||||||
if (strcasecmp(insn->mnemonic, "push") != 0 || insn->detail->x86.operands[0].type != X86_OP_IMM) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto bind_opcode_offset = static_cast<uint32_t>(insn->detail->x86.operands[0].imm);
|
|
||||||
if (Image.CommandOf<LC_DYLD_INFO_ONLY>() == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto bind_opcode_ptr =
|
|
||||||
Image.ImageOffset<uint8_t*>(Image.CommandOf<LC_DYLD_INFO_ONLY>()->lazy_bind_off) +
|
|
||||||
bind_opcode_offset;
|
|
||||||
|
|
||||||
while ((*bind_opcode_ptr & BIND_OPCODE_MASK) != BIND_OPCODE_DONE) {
|
|
||||||
switch (*bind_opcode_ptr & BIND_OPCODE_MASK) {
|
|
||||||
case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: // 0x10
|
|
||||||
case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: // 0x30
|
|
||||||
case BIND_OPCODE_SET_TYPE_IMM: // 0x50
|
|
||||||
case BIND_OPCODE_DO_BIND: // 0x90
|
|
||||||
case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: // 0xB0
|
|
||||||
++bind_opcode_ptr;
|
|
||||||
break;
|
|
||||||
case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: // 0x20
|
|
||||||
case BIND_OPCODE_SET_ADDEND_SLEB: // 0x60
|
|
||||||
case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: // 0x70
|
|
||||||
case BIND_OPCODE_ADD_ADDR_ULEB: // 0x80
|
|
||||||
case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: // 0xA0
|
|
||||||
while (*(++bind_opcode_ptr) & 0x80u);
|
|
||||||
++bind_opcode_ptr;
|
|
||||||
break;
|
|
||||||
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: // 0x40
|
|
||||||
return strcmp(reinterpret_cast<const char *>(bind_opcode_ptr + 1), Symbol) == 0;
|
|
||||||
case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: // 0xC0
|
|
||||||
//
|
|
||||||
// This opcode is too rare to appear,
|
|
||||||
// It is okay to dismiss this opcode
|
|
||||||
//
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
#include <stddef.h> // NOLINT
|
|
||||||
#include <stdint.h> // NOLINT
|
|
||||||
#include <stdio.h> // NOLINT
|
|
||||||
#include <signal.h> // NOLINT
|
|
||||||
#include <setjmp.h> // NOLINT
|
|
||||||
|
|
||||||
static jmp_buf env;
|
|
||||||
|
|
||||||
static void SIGSEGV_Handler(int sig) {
|
|
||||||
siglongjmp(env, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// read byte(s) at address `p` as __Type to `out`
|
|
||||||
// succeed if return true, otherwise return false
|
|
||||||
//
|
|
||||||
template<typename __Type>
|
|
||||||
static inline bool ProbeForRead(const void* p, void* out) {
|
|
||||||
int r = sigsetjmp(env, 1);
|
|
||||||
if (r == 0) {
|
|
||||||
*reinterpret_cast<__Type*>(out) = *reinterpret_cast<const __Type*>(p);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Print memory data in [from, to) at least
|
|
||||||
// If `base` is not nullptr, print address as offset. Otherwise, as absolute address.
|
|
||||||
// NOTICE:
|
|
||||||
// `base` must >= `from`
|
|
||||||
//
|
|
||||||
namespace nkg {
|
|
||||||
|
|
||||||
void PrintMemory(const void *from, const void *to, const void *base) {
|
|
||||||
auto start = reinterpret_cast<const uint8_t *>(from);
|
|
||||||
auto end = reinterpret_cast<const uint8_t *>(to);
|
|
||||||
auto base_ptr = reinterpret_cast<const uint8_t *>(base);
|
|
||||||
|
|
||||||
if (start >= end)
|
|
||||||
return;
|
|
||||||
|
|
||||||
while (reinterpret_cast<uintptr_t>(start) % 16)
|
|
||||||
start--;
|
|
||||||
|
|
||||||
while (reinterpret_cast<uintptr_t>(end) % 16)
|
|
||||||
end++;
|
|
||||||
|
|
||||||
void (*prev_handler)(int) = signal(SIGSEGV, SIGSEGV_Handler);
|
|
||||||
while (start < end) {
|
|
||||||
uint16_t value[16] = {};
|
|
||||||
|
|
||||||
if (base_ptr) {
|
|
||||||
uintptr_t d = start >= base ? start - base_ptr : base_ptr - start;
|
|
||||||
if (start >= base) {
|
|
||||||
printf("+0x%.*zx ", static_cast<int>(2 * sizeof(void *)), d);
|
|
||||||
} else {
|
|
||||||
printf("-0x%.*zx ", static_cast<int>(2 * sizeof(void *)), d);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
printf("0x%.*zx ", static_cast<int>(2 * sizeof(void *)), reinterpret_cast<uintptr_t >(start));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; ++i) {
|
|
||||||
if (start + i < from) {
|
|
||||||
printf(" ");
|
|
||||||
value[i] = 0xfffe;
|
|
||||||
} else if (ProbeForRead<uint8_t>(start + i, value + i)) {
|
|
||||||
printf("%02x ", value[i]);
|
|
||||||
} else {
|
|
||||||
printf("?? ");
|
|
||||||
value[i] = 0xffff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf(" ");
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; ++i) { // NOLINT
|
|
||||||
if (0x20 <= value[i] && value[i] < 0x7f) {
|
|
||||||
printf("%c", value[i]);
|
|
||||||
} else if (value[i] == 0xfffe) {
|
|
||||||
printf(" ");
|
|
||||||
} else {
|
|
||||||
printf(".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
start += 0x10;
|
|
||||||
}
|
|
||||||
signal(SIGSEGV, prev_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,50 +1,40 @@
|
|||||||
#include "KeystoneAssembler.hpp"
|
#include "KeystoneAssembler.hpp"
|
||||||
|
|
||||||
[[nodiscard]]
|
namespace nkg {
|
||||||
KeystoneAssembler KeystoneAssembler::Create(ks_arch ArchType, ks_mode Mode) {
|
|
||||||
KeystoneAssembler NewAssembler;
|
|
||||||
|
|
||||||
auto err = ks_open(ArchType, Mode, NewAssembler.pvt_Engine.GetAddress());
|
KeystoneAssembler::KeystoneAssembler(const KeystoneEngine& Engine) noexcept :
|
||||||
if (err != KS_ERR_OK) {
|
m_Engine(Engine) {}
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::KeystoneError(__FILE__, __LINE__, err, "ks_open failed.");
|
[[nodiscard]]
|
||||||
|
std::vector<uint8_t> KeystoneAssembler::GenerateMachineCode(std::string_view AssemblyCode, uint64_t Address) const {
|
||||||
|
ARL::ResourceWrapper pbMachineCode(ARL::ResourceTraits::KeystoneMalloc{});
|
||||||
|
size_t cbMachineCode = 0;
|
||||||
|
size_t InstructionsProcessed = 0;
|
||||||
|
|
||||||
|
if (ks_asm(m_Engine, AssemblyCode.data(), Address, pbMachineCode.GetAddressOf(), &cbMachineCode, &InstructionsProcessed) != 0) {
|
||||||
|
throw ARL::KeystoneError(__FILE__, __LINE__, ks_errno(m_Engine), "ks_asm failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::vector<uint8_t>(pbMachineCode.Get(), pbMachineCode.Get() + cbMachineCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewAssembler;
|
KeystoneEngine::KeystoneEngine(ks_arch ArchType, ks_mode Mode) {
|
||||||
}
|
auto err = ks_open(ArchType, Mode, GetAddressOf());
|
||||||
|
if (err != KS_ERR_OK) {
|
||||||
void KeystoneAssembler::Option(ks_opt_type Type, size_t Value) {
|
throw ARL::KeystoneError(__FILE__, __LINE__, err, "ks_open failed.");
|
||||||
auto err = ks_option(pvt_Engine, Type, Value);
|
}
|
||||||
if (err != KS_ERR_OK) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::KeystoneError(__FILE__, __LINE__, err, "ks_open failed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
std::vector<uint8_t> KeystoneAssembler::GenerateOpcode(const char *AssemblyCode, uint64_t Address) const {
|
|
||||||
ResourceOwned pbOpcode(KeystoneMallocTraits{});
|
|
||||||
size_t cbOpCode = 0;
|
|
||||||
size_t InstructionsProcessed = 0;
|
|
||||||
|
|
||||||
if (ks_asm(pvt_Engine, AssemblyCode, Address, pbOpcode.GetAddress(), &cbOpCode, &InstructionsProcessed) != 0) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::KeystoneError(__FILE__, __LINE__, ks_errno(pvt_Engine), "ks_asm failed.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::vector<uint8_t>(pbOpcode.Get(), pbOpcode.Get() + cbOpCode);
|
void KeystoneEngine::Option(ks_opt_type Type, ks_opt_value Value) {
|
||||||
}
|
auto err = ks_option(Get(), Type, Value);
|
||||||
|
if (err != KS_ERR_OK) {
|
||||||
[[nodiscard]]
|
throw ARL::KeystoneError(__FILE__, __LINE__, err, "ks_option failed.");
|
||||||
std::vector<uint8_t> KeystoneAssembler::GenerateOpcode(const std::string& AssemblyCode, uint64_t Address) const {
|
}
|
||||||
ResourceOwned pbOpcode(KeystoneMallocTraits{});
|
}
|
||||||
size_t cbOpCode = 0;
|
|
||||||
size_t InstructionsProcessed = 0;
|
KeystoneAssembler KeystoneEngine::CreateAssembler() const {
|
||||||
|
return KeystoneAssembler(*this);
|
||||||
if (ks_asm(pvt_Engine, AssemblyCode.c_str(), Address, pbOpcode.GetAddress(), &cbOpCode, &InstructionsProcessed) != 0) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::KeystoneError(__FILE__, __LINE__, ks_errno(pvt_Engine), "ks_asm failed.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::vector<uint8_t>(pbOpcode.Get(), pbOpcode.Get() + cbOpCode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,28 +1,40 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <keystone/keystone.h>
|
#include "ExceptionKeystone.hpp"
|
||||||
#include "../common/ResourceOwned.hpp"
|
#include "ResourceWrapper.hpp"
|
||||||
#include "ResourceTraitsKeystone.hpp"
|
#include "ResourceTraitsKeystone.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class KeystoneAssembler {
|
namespace nkg {
|
||||||
private:
|
|
||||||
|
|
||||||
ResourceOwned<KeystoneHandleTraits> pvt_Engine;
|
class KeystoneEngine;
|
||||||
|
|
||||||
KeystoneAssembler() noexcept :
|
class KeystoneAssembler {
|
||||||
pvt_Engine(KeystoneHandleTraits{}) {}
|
friend class KeystoneEngine;
|
||||||
public:
|
private:
|
||||||
|
|
||||||
[[nodiscard]]
|
const KeystoneEngine& m_Engine;
|
||||||
static KeystoneAssembler Create(ks_arch ArchType, ks_mode Mode);
|
|
||||||
|
|
||||||
void Option(ks_opt_type Type, size_t Value);
|
KeystoneAssembler(const KeystoneEngine& Engine) noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
public:
|
||||||
std::vector<uint8_t> GenerateOpcode(const char* AssemblyCode, uint64_t Address = 0) const;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
std::vector<uint8_t> GenerateOpcode(const std::string& AssemblyCode, uint64_t Address = 0) const;
|
std::vector<uint8_t> GenerateMachineCode(std::string_view AssemblyCode, uint64_t Address = 0) const;
|
||||||
};
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class KeystoneEngine : private ARL::ResourceWrapper<ARL::ResourceTraits::KeystoneHandle> {
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
151
navicat-patcher/MemoryAccess.hpp
Normal file
151
navicat-patcher/MemoryAccess.hpp
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace ARL {
|
||||||
|
|
||||||
|
template<typename __PtrType1, typename __PtrType2>
|
||||||
|
[[nodiscard]]
|
||||||
|
inline ptrdiff_t AddressDelta(__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>
|
||||||
|
[[nodiscard]]
|
||||||
|
inline __PtrType AddressOffset(__PtrType p, ptrdiff_t 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>
|
||||||
|
[[nodiscard]]
|
||||||
|
inline __ReturnType AddressOffsetWithCast(__PtrType p, ptrdiff_t 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
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __PtrType, typename __BeginPtrType, typename __EndPtrType>
|
||||||
|
[[nodiscard]]
|
||||||
|
inline bool AddressIsInRange(__PtrType p, __BeginPtrType begin, __EndPtrType end) {
|
||||||
|
static_assert(std::is_pointer_v<__PtrType>);
|
||||||
|
static_assert(std::is_pointer_v<__BeginPtrType>);
|
||||||
|
static_assert(std::is_pointer_v<__EndPtrType>);
|
||||||
|
return
|
||||||
|
reinterpret_cast<const volatile char*>(begin) <= reinterpret_cast<const volatile char*>(p) &&
|
||||||
|
reinterpret_cast<const volatile char*>(p) < reinterpret_cast<const volatile char*>(end);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __PtrType, typename __BasePtrType>
|
||||||
|
[[nodiscard]]
|
||||||
|
inline bool AddressIsInRange(__PtrType p, __BasePtrType base, size_t size) {
|
||||||
|
static_assert(std::is_pointer_v<__PtrType>);
|
||||||
|
static_assert(std::is_pointer_v<__BasePtrType>);
|
||||||
|
return AddressIsInRange(p, base, AddressOffset(base, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __PtrType1, typename __PtrType2, typename __BeginPtrType, typename __EndPtrType>
|
||||||
|
[[nodiscard]]
|
||||||
|
inline bool AddressIsInRangeEx(__PtrType1 p1, __PtrType2 p2, __BeginPtrType begin, __EndPtrType end) {
|
||||||
|
static_assert(std::is_pointer_v<__PtrType1>);
|
||||||
|
static_assert(std::is_pointer_v<__PtrType2>);
|
||||||
|
static_assert(std::is_pointer_v<__BeginPtrType>);
|
||||||
|
static_assert(std::is_pointer_v<__EndPtrType>);
|
||||||
|
return
|
||||||
|
reinterpret_cast<const volatile char*>(begin) <= reinterpret_cast<const volatile char*>(p1) &&
|
||||||
|
reinterpret_cast<const volatile char*>(p1) <= reinterpret_cast<const volatile char*>(p2) &&
|
||||||
|
reinterpret_cast<const volatile char*>(p2) <= reinterpret_cast<const volatile char*>(end);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __PtrType, typename __BeginPtrType, typename __EndPtrType>
|
||||||
|
[[nodiscard]]
|
||||||
|
inline bool AddressIsInRangeEx(__PtrType p, size_t s, __BeginPtrType begin, __EndPtrType end) {
|
||||||
|
static_assert(std::is_pointer_v<__PtrType>);
|
||||||
|
static_assert(std::is_pointer_v<__BeginPtrType>);
|
||||||
|
static_assert(std::is_pointer_v<__EndPtrType>);
|
||||||
|
return AddressIsInRange(p, AddressDelta(p, s), begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __PtrType1, typename __PtrType2, typename __BasePtrType>
|
||||||
|
[[nodiscard]]
|
||||||
|
inline bool AddressIsInRangeEx(__PtrType1 p1, __PtrType2 p2, __BasePtrType base, size_t size) {
|
||||||
|
static_assert(std::is_pointer_v<__PtrType1>);
|
||||||
|
static_assert(std::is_pointer_v<__PtrType2>);
|
||||||
|
static_assert(std::is_pointer_v<__BasePtrType>);
|
||||||
|
return AddressIsInRangeEx(p1, p2, base, AddressOffset(base, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __PtrType, typename __BasePtrType>
|
||||||
|
[[nodiscard]]
|
||||||
|
inline bool AddressIsInRangeEx(__PtrType p, size_t s, __BasePtrType base, size_t size) {
|
||||||
|
static_assert(std::is_pointer_v<__PtrType>);
|
||||||
|
static_assert(std::is_pointer_v<__BasePtrType>);
|
||||||
|
return AddressIsInRangeEx(p, AddressOffset(p, s), base, AddressOffset(base, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __ReadType, typename __PtrType>
|
||||||
|
[[nodiscard]]
|
||||||
|
inline __ReadType AddressRead(__PtrType p) noexcept {
|
||||||
|
static_assert(std::is_trivial_v<__ReadType> && std::is_standard_layout_v<__ReadType>);
|
||||||
|
static_assert(std::is_pointer_v<__PtrType>);
|
||||||
|
return *reinterpret_cast<const volatile __ReadType*>(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __ReadType, typename __PtrType>
|
||||||
|
[[nodiscard]]
|
||||||
|
inline __ReadType AddressRead(__PtrType p, ptrdiff_t offset) noexcept {
|
||||||
|
static_assert(std::is_trivial_v<__ReadType> && std::is_standard_layout_v<__ReadType>);
|
||||||
|
static_assert(std::is_pointer_v<__PtrType>);
|
||||||
|
return *reinterpret_cast<const volatile __ReadType*>(
|
||||||
|
reinterpret_cast<const volatile char*>(p) + offset
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __ReadType, typename __PtrType>
|
||||||
|
[[nodiscard]]
|
||||||
|
inline __ReadType AddressRead(__PtrType p, size_t scale, ptrdiff_t index) noexcept {
|
||||||
|
static_assert(std::is_trivial_v<__ReadType> && std::is_standard_layout_v<__ReadType>);
|
||||||
|
static_assert(std::is_pointer_v<__PtrType>);
|
||||||
|
return *reinterpret_cast<const volatile __ReadType*>(
|
||||||
|
reinterpret_cast<const volatile char*>(p) + scale * index
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __WriteType, typename __PtrType>
|
||||||
|
inline void AddressWrite(__PtrType p, const __WriteType& value) noexcept {
|
||||||
|
static_assert(std::is_trivial_v<__WriteType> && std::is_standard_layout_v<__WriteType>);
|
||||||
|
static_assert(std::is_pointer_v<__PtrType>);
|
||||||
|
*reinterpret_cast<volatile __WriteType*>(p) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __WriteType, typename __PtrType>
|
||||||
|
inline void AddressWrite(__PtrType p, ptrdiff_t offset, const __WriteType& value) noexcept {
|
||||||
|
static_assert(std::is_trivial_v<__WriteType> && std::is_standard_layout_v<__WriteType>);
|
||||||
|
static_assert(std::is_pointer_v<__PtrType>);
|
||||||
|
*reinterpret_cast<volatile __WriteType*>(
|
||||||
|
reinterpret_cast<volatile char*>(p) + offset
|
||||||
|
) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __WriteType, typename __PtrType>
|
||||||
|
inline void AddressWrite(__PtrType p, size_t scale, ptrdiff_t index, const __WriteType& value) noexcept {
|
||||||
|
static_assert(std::is_trivial_v<__WriteType> && std::is_standard_layout_v<__WriteType>);
|
||||||
|
static_assert(std::is_pointer_v<__PtrType>);
|
||||||
|
*reinterpret_cast<volatile __WriteType*>(
|
||||||
|
reinterpret_cast<volatile char*>(p) + scale * index
|
||||||
|
) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
159
navicat-patcher/Misc.cpp
Normal file
159
navicat-patcher/Misc.cpp
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
#include "Misc.hpp"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <filesystem>
|
||||||
|
#include "ExceptionSystem.hpp"
|
||||||
|
|
||||||
|
static jmp_buf g_jmbuf;
|
||||||
|
|
||||||
|
static void SIGSEGV_handler(int sig) {
|
||||||
|
siglongjmp(g_jmbuf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// read byte(s) at address `p` as __Type to `out`
|
||||||
|
// succeed if return true, otherwise return false
|
||||||
|
//
|
||||||
|
template<typename __Type>
|
||||||
|
static inline bool probe_for_read(const void* p, void* out) {
|
||||||
|
int r = sigsetjmp(g_jmbuf, 1);
|
||||||
|
if (r == 0) {
|
||||||
|
*reinterpret_cast<__Type*>(out) = *reinterpret_cast<const __Type*>(p);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace nkg::Misc {
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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) {
|
||||||
|
printf("+0x%.*zx ", static_cast<int>(2 * sizeof(void*)), d);
|
||||||
|
} else {
|
||||||
|
printf("-0x%.*zx ", static_cast<int>(2 * sizeof(void*)), d);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("0x%.*zx ", static_cast<int>(2 * sizeof(void*)), reinterpret_cast<uintptr_t>(pbBegin));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; ++i) {
|
||||||
|
if (pbBegin + i < lpMemBegin || pbBegin + i >= lpMemEnd) {
|
||||||
|
printf(" ");
|
||||||
|
Values[i] = 0xfffe;
|
||||||
|
} else if (probe_for_read<uint8_t>(pbBegin + i, Values + i)) {
|
||||||
|
printf("%02x ", Values[i]);
|
||||||
|
} else {
|
||||||
|
printf("?? ");
|
||||||
|
Values[i] = 0xffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(" ");
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; ++i) {
|
||||||
|
if (0x20 <= Values[i] && Values[i] < 0x7f) {
|
||||||
|
printf("%c", Values[i]);
|
||||||
|
} else if (Values[i] == 0xfffe) {
|
||||||
|
printf(" ");
|
||||||
|
} else {
|
||||||
|
printf(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\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);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool FsIsExist(std::string_view szPath) {
|
||||||
|
std::error_code ec;
|
||||||
|
if (std::filesystem::exists(szPath, ec)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (ec) {
|
||||||
|
throw ARL::SystemError(__FILE__, __LINE__, ec.value(), "std::filesystem::exists failed.");
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool FsIsFile(std::string_view szPath) {
|
||||||
|
std::error_code ec;
|
||||||
|
if (std::filesystem::is_regular_file(szPath, ec)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (ec) {
|
||||||
|
throw ARL::SystemError(__FILE__, __LINE__, ec.value(), "std::filesystem::is_regular_file failed.");
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool FsIsDirectory(std::string_view szPath) {
|
||||||
|
std::error_code ec;
|
||||||
|
if (std::filesystem::is_directory(szPath, ec)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (ec) {
|
||||||
|
throw ARL::SystemError(__FILE__, __LINE__, ec.value(), "std::filesystem::is_directory failed.");
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
std::string FsCurrentWorkingDirectory() {
|
||||||
|
std::error_code ec;
|
||||||
|
std::string path = std::filesystem::current_path(ec);
|
||||||
|
if (ec) {
|
||||||
|
throw ARL::SystemError(__FILE__, __LINE__, ec.value(), "std::filesystem::current_path failed.");
|
||||||
|
} else {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
31
navicat-patcher/Misc.hpp
Normal file
31
navicat-patcher/Misc.hpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace nkg::Misc {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Print memory data in [lpMemBegin, lpMemEnd)
|
||||||
|
// If `base` is not nullptr, print address as offset. Otherwise, as absolute address.
|
||||||
|
//
|
||||||
|
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.
|
||||||
|
//
|
||||||
|
void PrintMemory(const void* lpMem, size_t cbMem, const void* lpBase) noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool FsIsExist(std::string_view szPath);
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool FsIsFile(std::string_view szPath);
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool FsIsDirectory(std::string_view szPath);
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
std::string FsCurrentWorkingDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,78 +1,88 @@
|
|||||||
#include "PatchSolutions.hpp"
|
#include "PatchSolutions.hpp"
|
||||||
|
#include "Misc.hpp"
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
|
|
||||||
const char PatchSolution0::Keyword[452] =
|
namespace nkg {
|
||||||
"-----BEGIN PUBLIC KEY-----\x00"
|
|
||||||
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I\x00"
|
|
||||||
"qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv\x00"
|
|
||||||
"a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF\x00"
|
|
||||||
"R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2\x00"
|
|
||||||
"WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt\x00"
|
|
||||||
"YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ\x00"
|
|
||||||
"awIDAQAB\x00"
|
|
||||||
"-----END PUBLIC KEY-----\x00";
|
|
||||||
|
|
||||||
PatchSolution0::PatchSolution0(const X64ImageInterpreter& Image) noexcept :
|
const char PatchSolution0::Keyword[451] =
|
||||||
pvt_Image(Image),
|
"-----BEGIN PUBLIC KEY-----\x00"
|
||||||
pvt_PatchOffset(X64ImageInterpreter::InvalidOffset) {}
|
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I\x00"
|
||||||
|
"qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv\x00"
|
||||||
|
"a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF\x00"
|
||||||
|
"R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2\x00"
|
||||||
|
"WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt\x00"
|
||||||
|
"YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ\x00"
|
||||||
|
"awIDAQAB\x00"
|
||||||
|
"-----END PUBLIC KEY-----";
|
||||||
|
|
||||||
bool PatchSolution0::FindPatchOffset() noexcept {
|
PatchSolution0::PatchSolution0(const X64ImageInterpreter& Image) :
|
||||||
try {
|
m_Image(Image) {}
|
||||||
pvt_PatchOffset = pvt_Image.SearchSectionOffset("__TEXT", "__cstring", [](const uint8_t* p) {
|
|
||||||
return memcmp(p, Keyword, sizeof(Keyword) - 1) == 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
printf("[+] PatchSolution0 ...... Ready to apply.\n");
|
[[nodiscard]]
|
||||||
printf(" Keyword offset = +0x%.8x\n", pvt_PatchOffset);
|
bool PatchSolution0::FindPatchOffset() noexcept {
|
||||||
return true;
|
try {
|
||||||
} catch (...) {
|
auto lpPatch = m_Image.SearchSection("__TEXT", "__cstring", [](const void* base, size_t i, size_t size) {
|
||||||
printf("[-] PatchSolution0 ...... Omitted.\n");
|
if (i + sizeof(Keyword) <= size) {
|
||||||
return false;
|
auto p = ARL::AddressOffset(base, i);
|
||||||
}
|
return memcmp(p, Keyword, sizeof(Keyword) - 1) == 0;
|
||||||
}
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (lpPatch) {
|
||||||
|
m_PatchOffset = m_Image.ConvertPtrToOffset(lpPatch);
|
||||||
|
} else {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "not found.");
|
||||||
|
}
|
||||||
|
|
||||||
bool PatchSolution0::CheckKey(const RSACipher& RsaCipher) const noexcept {
|
printf("[+] PatchSolution0 ...... Ready to apply.\n");
|
||||||
try {
|
printf(" Keyword offset = +0x%.8x\n", m_PatchOffset.value());
|
||||||
if (RsaCipher.Bits() != 2048) {
|
return true;
|
||||||
|
} catch (...) {
|
||||||
|
printf("[-] PatchSolution0 ...... Omitted.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string PublicKeyPEM = RsaCipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
[[nodiscard]]
|
||||||
for (auto& c : PublicKeyPEM) {
|
bool PatchSolution0::CheckKey(const RSACipher& Cipher) const noexcept {
|
||||||
if (c == '\n') c = '\x00';
|
try {
|
||||||
|
return Cipher.Bits() == 2048;
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PublicKeyPEM.length() == sizeof(Keyword) - 1;
|
|
||||||
} catch (...) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PatchSolution0::MakePatch(const RSACipher& Cipher) const {
|
||||||
|
if (m_PatchOffset.has_value()) {
|
||||||
|
std::string szPublicKeyPEM = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
||||||
|
for (auto& c : szPublicKeyPEM) {
|
||||||
|
if (c == '\n') {
|
||||||
|
c = '\x00';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (szPublicKeyPEM.length() < sizeof(Keyword)) {
|
||||||
|
szPublicKeyPEM.push_back('\x00');
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lpPatch = m_Image.ImageOffset(m_PatchOffset.value());
|
||||||
|
|
||||||
|
puts("**************************************************************");
|
||||||
|
puts("* PatchSolution0 *");
|
||||||
|
puts("**************************************************************");
|
||||||
|
|
||||||
|
printf("[*] Previous:\n");
|
||||||
|
Misc::PrintMemory(lpPatch, sizeof(Keyword), m_Image.ImageBase());
|
||||||
|
memcpy(lpPatch, szPublicKeyPEM.data(), sizeof(Keyword));
|
||||||
|
printf("[*] After:\n");
|
||||||
|
Misc::PrintMemory(lpPatch, sizeof(Keyword), m_Image.ImageBase());
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "PatchSolution0: not ready yet.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PatchSolution0::MakePatch(const RSACipher& RsaCipher) const {
|
|
||||||
if (pvt_PatchOffset == X64ImageInterpreter::InvalidOffset) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "PatchSolution0 is not ready.");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string PublicKeyPEM = RsaCipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
|
||||||
for (auto& c : PublicKeyPEM) {
|
|
||||||
if (c == '\n') c = '\x00';
|
|
||||||
}
|
|
||||||
|
|
||||||
auto pbPatch = pvt_Image.ImageOffset<uint8_t*>(pvt_PatchOffset);
|
|
||||||
|
|
||||||
puts("**************************************************************");
|
|
||||||
puts("* PatchSolution0 *");
|
|
||||||
puts("**************************************************************");
|
|
||||||
printf("@+0x%.8x\n", pvt_PatchOffset);
|
|
||||||
|
|
||||||
puts("Previous:");
|
|
||||||
nkg::PrintMemory(pbPatch, pbPatch + sizeof(Keyword), pbPatch);
|
|
||||||
|
|
||||||
memcpy(pbPatch, PublicKeyPEM.data(), PublicKeyPEM.size());
|
|
||||||
|
|
||||||
puts("After:");
|
|
||||||
nkg::PrintMemory(pbPatch, pbPatch + sizeof(Keyword), pbPatch);
|
|
||||||
|
|
||||||
puts("");
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,127 +1,129 @@
|
|||||||
#include "PatchSolutions.hpp"
|
#include "PatchSolutions.hpp"
|
||||||
|
#include "Misc.hpp"
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
|
|
||||||
const uint8_t PatchSolution1::Keyword[0x188] = {
|
namespace nkg {
|
||||||
0xfe, 0xfd, 0xfc, 0xf4, 0xfe, 0xd2, 0xf8, 0xf4, 0xf1, 0xd3, 0xde, 0xc7, 0xdf, 0xd3, 0xd0, 0xfd,
|
|
||||||
0x8a, 0xc3, 0x85, 0xf4, 0xf6, 0xe9, 0xfc, 0xfc, 0xf2, 0xf5, 0xfa, 0xf5, 0xf6, 0xe9, 0x81, 0xfb,
|
|
||||||
0xfe, 0xfd, 0xfc, 0xf4, 0xf4, 0xdf, 0xf2, 0xf9, 0xf2, 0xe5, 0xf0, 0xf7, 0xc0, 0x89, 0xdd, 0xcb,
|
|
||||||
0xf5, 0x87, 0xe6, 0xdd, 0xf4, 0xd9, 0xf8, 0xfb, 0xde, 0xf9, 0xcf, 0xc5, 0x8f, 0x80, 0x80, 0xf3,
|
|
||||||
0xc2, 0xd0, 0xe2, 0x8f, 0xfa, 0x8a, 0xdd, 0xf3, 0xd7, 0xdc, 0x86, 0xdc, 0xf0, 0x81, 0xc0, 0xea,
|
|
||||||
0xd0, 0xd9, 0xf9, 0xd8, 0xda, 0xf2, 0xd0, 0xfd, 0xc3, 0xf6, 0xf3, 0x82, 0xf2, 0x81, 0xef, 0xf2,
|
|
||||||
0xe0, 0xf9, 0xf2, 0xd3, 0x8f, 0xd7, 0xe9, 0xfb, 0xca, 0x86, 0xde, 0xfc, 0xf3, 0xd5, 0xdd, 0xf4,
|
|
||||||
0xc7, 0x80, 0xf7, 0xd5, 0xf2, 0xc1, 0xde, 0xcc, 0xc0, 0xc7, 0xf0, 0xd0, 0xd0, 0xd1, 0xd7, 0xcc,
|
|
||||||
0xd2, 0x81, 0xc1, 0x83, 0xdd, 0xd5, 0x8a, 0x8f, 0x81, 0xe1, 0xf4, 0xd9, 0xf3, 0xd7, 0xca, 0xef,
|
|
||||||
0xf9, 0xdf, 0xe1, 0xee, 0xf0, 0xe9, 0xd1, 0xca, 0xf2, 0xe3, 0xf8, 0xf0, 0x83, 0xde, 0xfb, 0xd7,
|
|
||||||
0xf1, 0xc4, 0xfa, 0x85, 0xf2, 0xdd, 0xdd, 0xfd, 0x85, 0x86, 0xc7, 0xf9, 0xc4, 0xc9, 0xf4, 0xf8,
|
|
||||||
0xd4, 0xd9, 0xe6, 0xd2, 0xf6, 0xc1, 0xc1, 0xf9, 0xe0, 0xe4, 0xf7, 0xe4, 0xfd, 0xf1, 0xf6, 0xfc,
|
|
||||||
0xe1, 0x84, 0xe4, 0xd1, 0xed, 0xfe, 0xdb, 0xe8, 0xdd, 0xe1, 0x85, 0xd0, 0xc5, 0xd2, 0x8a, 0x8e,
|
|
||||||
0xd5, 0xdd, 0xe3, 0xdb, 0xd0, 0xe1, 0xd0, 0xf6, 0xc6, 0xee, 0xe6, 0xf7, 0xda, 0xf1, 0xdb, 0xc9,
|
|
||||||
0x8b, 0xee, 0xcd, 0xdf, 0xff, 0xe8, 0xdd, 0xca, 0x82, 0xdb, 0xf1, 0x82, 0xc3, 0xed, 0xc9, 0xcc,
|
|
||||||
0xc0, 0xf2, 0xd6, 0xdf, 0x83, 0xe9, 0xf3, 0xce, 0xea, 0xfa, 0xdf, 0xf8, 0xd9, 0xff, 0xec, 0x88,
|
|
||||||
0xe4, 0xe4, 0xfd, 0x80, 0xc5, 0xce, 0xfa, 0xd2, 0xf4, 0xd8, 0x84, 0xff, 0xe5, 0xf3, 0xcb, 0xc2,
|
|
||||||
0xfe, 0xc0, 0xc4, 0xfa, 0xde, 0xdd, 0xd5, 0xc9, 0xc5, 0xd5, 0xdf, 0xe3, 0xdd, 0xc1, 0xcb, 0xdd,
|
|
||||||
0xfc, 0xf7, 0x83, 0xf8, 0xda, 0xc1, 0xd4, 0xe3, 0xfe, 0xc2, 0xef, 0xf8, 0xf2, 0xea, 0x8a, 0xd2,
|
|
||||||
0xc7, 0xf2, 0xf0, 0xc2, 0xfb, 0x89, 0xdc, 0xeb, 0xd1, 0xf7, 0xcc, 0xe2, 0xd1, 0xfc, 0xd4, 0xce,
|
|
||||||
0xea, 0xcd, 0xe4, 0x87, 0xe0, 0xcc, 0x8d, 0xf5, 0xc7, 0x85, 0x87, 0xda, 0xcf, 0xde, 0x89, 0xcd,
|
|
||||||
0xe5, 0xfd, 0xe7, 0x83, 0xda, 0xdb, 0xfe, 0xf4, 0x84, 0xec, 0xf6, 0xee, 0xfd, 0xea, 0xf1, 0xf5,
|
|
||||||
0xf5, 0xfc, 0xe6, 0xd0, 0x86, 0xdf, 0xc3, 0xe2, 0xe4, 0xd5, 0xd7, 0xe4, 0xe4, 0xce, 0xd4, 0xce,
|
|
||||||
0x82, 0xda, 0xc7, 0xda, 0x80, 0xcb, 0xee, 0x8c, 0xd0, 0xde, 0xcd, 0xda, 0xdd, 0xcd, 0xcc, 0xeb,
|
|
||||||
0xd2, 0xc3, 0xfc, 0xf2, 0xf6, 0xe9, 0xf8, 0xf8
|
|
||||||
};
|
|
||||||
|
|
||||||
PatchSolution1::PatchSolution1(const X64ImageInterpreter& Image) noexcept :
|
const uint8_t PatchSolution1::Keyword[0x188] = {
|
||||||
pvt_Image(Image),
|
0xfe, 0xfd, 0xfc, 0xf4, 0xfe, 0xd2, 0xf8, 0xf4, 0xf1, 0xd3, 0xde, 0xc7, 0xdf, 0xd3, 0xd0, 0xfd,
|
||||||
pvt_PatchOffset(X64ImageInterpreter::InvalidOffset) {}
|
0x8a, 0xc3, 0x85, 0xf4, 0xf6, 0xe9, 0xfc, 0xfc, 0xf2, 0xf5, 0xfa, 0xf5, 0xf6, 0xe9, 0x81, 0xfb,
|
||||||
|
0xfe, 0xfd, 0xfc, 0xf4, 0xf4, 0xdf, 0xf2, 0xf9, 0xf2, 0xe5, 0xf0, 0xf7, 0xc0, 0x89, 0xdd, 0xcb,
|
||||||
|
0xf5, 0x87, 0xe6, 0xdd, 0xf4, 0xd9, 0xf8, 0xfb, 0xde, 0xf9, 0xcf, 0xc5, 0x8f, 0x80, 0x80, 0xf3,
|
||||||
|
0xc2, 0xd0, 0xe2, 0x8f, 0xfa, 0x8a, 0xdd, 0xf3, 0xd7, 0xdc, 0x86, 0xdc, 0xf0, 0x81, 0xc0, 0xea,
|
||||||
|
0xd0, 0xd9, 0xf9, 0xd8, 0xda, 0xf2, 0xd0, 0xfd, 0xc3, 0xf6, 0xf3, 0x82, 0xf2, 0x81, 0xef, 0xf2,
|
||||||
|
0xe0, 0xf9, 0xf2, 0xd3, 0x8f, 0xd7, 0xe9, 0xfb, 0xca, 0x86, 0xde, 0xfc, 0xf3, 0xd5, 0xdd, 0xf4,
|
||||||
|
0xc7, 0x80, 0xf7, 0xd5, 0xf2, 0xc1, 0xde, 0xcc, 0xc0, 0xc7, 0xf0, 0xd0, 0xd0, 0xd1, 0xd7, 0xcc,
|
||||||
|
0xd2, 0x81, 0xc1, 0x83, 0xdd, 0xd5, 0x8a, 0x8f, 0x81, 0xe1, 0xf4, 0xd9, 0xf3, 0xd7, 0xca, 0xef,
|
||||||
|
0xf9, 0xdf, 0xe1, 0xee, 0xf0, 0xe9, 0xd1, 0xca, 0xf2, 0xe3, 0xf8, 0xf0, 0x83, 0xde, 0xfb, 0xd7,
|
||||||
|
0xf1, 0xc4, 0xfa, 0x85, 0xf2, 0xdd, 0xdd, 0xfd, 0x85, 0x86, 0xc7, 0xf9, 0xc4, 0xc9, 0xf4, 0xf8,
|
||||||
|
0xd4, 0xd9, 0xe6, 0xd2, 0xf6, 0xc1, 0xc1, 0xf9, 0xe0, 0xe4, 0xf7, 0xe4, 0xfd, 0xf1, 0xf6, 0xfc,
|
||||||
|
0xe1, 0x84, 0xe4, 0xd1, 0xed, 0xfe, 0xdb, 0xe8, 0xdd, 0xe1, 0x85, 0xd0, 0xc5, 0xd2, 0x8a, 0x8e,
|
||||||
|
0xd5, 0xdd, 0xe3, 0xdb, 0xd0, 0xe1, 0xd0, 0xf6, 0xc6, 0xee, 0xe6, 0xf7, 0xda, 0xf1, 0xdb, 0xc9,
|
||||||
|
0x8b, 0xee, 0xcd, 0xdf, 0xff, 0xe8, 0xdd, 0xca, 0x82, 0xdb, 0xf1, 0x82, 0xc3, 0xed, 0xc9, 0xcc,
|
||||||
|
0xc0, 0xf2, 0xd6, 0xdf, 0x83, 0xe9, 0xf3, 0xce, 0xea, 0xfa, 0xdf, 0xf8, 0xd9, 0xff, 0xec, 0x88,
|
||||||
|
0xe4, 0xe4, 0xfd, 0x80, 0xc5, 0xce, 0xfa, 0xd2, 0xf4, 0xd8, 0x84, 0xff, 0xe5, 0xf3, 0xcb, 0xc2,
|
||||||
|
0xfe, 0xc0, 0xc4, 0xfa, 0xde, 0xdd, 0xd5, 0xc9, 0xc5, 0xd5, 0xdf, 0xe3, 0xdd, 0xc1, 0xcb, 0xdd,
|
||||||
|
0xfc, 0xf7, 0x83, 0xf8, 0xda, 0xc1, 0xd4, 0xe3, 0xfe, 0xc2, 0xef, 0xf8, 0xf2, 0xea, 0x8a, 0xd2,
|
||||||
|
0xc7, 0xf2, 0xf0, 0xc2, 0xfb, 0x89, 0xdc, 0xeb, 0xd1, 0xf7, 0xcc, 0xe2, 0xd1, 0xfc, 0xd4, 0xce,
|
||||||
|
0xea, 0xcd, 0xe4, 0x87, 0xe0, 0xcc, 0x8d, 0xf5, 0xc7, 0x85, 0x87, 0xda, 0xcf, 0xde, 0x89, 0xcd,
|
||||||
|
0xe5, 0xfd, 0xe7, 0x83, 0xda, 0xdb, 0xfe, 0xf4, 0x84, 0xec, 0xf6, 0xee, 0xfd, 0xea, 0xf1, 0xf5,
|
||||||
|
0xf5, 0xfc, 0xe6, 0xd0, 0x86, 0xdf, 0xc3, 0xe2, 0xe4, 0xd5, 0xd7, 0xe4, 0xe4, 0xce, 0xd4, 0xce,
|
||||||
|
0x82, 0xda, 0xc7, 0xda, 0x80, 0xcb, 0xee, 0x8c, 0xd0, 0xde, 0xcd, 0xda, 0xdd, 0xcd, 0xcc, 0xeb,
|
||||||
|
0xd2, 0xc3, 0xfc, 0xf2, 0xf6, 0xe9, 0xf8, 0xf8
|
||||||
|
};
|
||||||
|
|
||||||
bool PatchSolution1::FindPatchOffset() noexcept {
|
PatchSolution1::PatchSolution1(const X64ImageInterpreter& Image) :
|
||||||
uint8_t* pbPatch = nullptr;
|
m_Image(Image) {}
|
||||||
|
|
||||||
for (size_t i = 0; i < pvt_Image.NumberOfSections(); ++i) {
|
[[nodiscard]]
|
||||||
auto pbSectionView = pvt_Image.SectionView<uint8_t*>(i);
|
bool PatchSolution1::FindPatchOffset() noexcept {
|
||||||
auto cbSectiveView = pvt_Image.ImageSection(i)->size;
|
try {
|
||||||
|
void* lpPatch = nullptr;
|
||||||
|
|
||||||
if (cbSectiveView < sizeof(Keyword)) {
|
for (size_t i = 0; i < m_Image.NumberOfSections(); ++i) {
|
||||||
continue;
|
auto section = m_Image.ImageSection(i);
|
||||||
}
|
if (section->size >= sizeof(Keyword)) {
|
||||||
|
lpPatch = m_Image.SearchSection(section, [](const void* base, size_t i, size_t size) {
|
||||||
|
if (i + sizeof(Keyword) <= size) {
|
||||||
|
return memcmp(ARL::AddressOffset(base, i), Keyword, sizeof(Keyword)) == 0;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
for (size_t j = 0; j < cbSectiveView - sizeof(Keyword); ++j) {
|
if (lpPatch) {
|
||||||
if (memcmp(pbSectionView + j, Keyword, sizeof(Keyword)) == 0) {
|
m_PatchOffset = m_Image.ConvertPtrToOffset(lpPatch);
|
||||||
pbPatch = pbSectionView + j;
|
break;
|
||||||
i = pvt_Image.NumberOfSections();
|
}
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pbPatch == nullptr) {
|
if (lpPatch) {
|
||||||
printf("[-] PatchSolution1 ...... Omitted.\n");
|
printf("[+] PatchSolution1 ...... Ready to apply.\n");
|
||||||
return false;
|
printf(" Keyword offset = +0x%.8x\n", m_PatchOffset.value());
|
||||||
} else {
|
return true;
|
||||||
pvt_PatchOffset = pbPatch - pvt_Image.ImageBase<uint8_t*>();
|
} else {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "not found.");
|
||||||
printf("[+] PatchSolution1 ...... Ready to apply.\n");
|
|
||||||
printf(" Keyword offset = +0x%.8x\n", pvt_PatchOffset);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PatchSolution1::CheckKey(const RSACipher& RsaCipher) const noexcept {
|
|
||||||
try {
|
|
||||||
std::string PublicKeyPEM = RsaCipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
|
||||||
|
|
||||||
PublicKeyPEM.erase(PublicKeyPEM.find("-----BEGIN PUBLIC KEY-----"), 26);
|
|
||||||
PublicKeyPEM.erase(PublicKeyPEM.find("-----END PUBLIC KEY-----"), 24);
|
|
||||||
{
|
|
||||||
std::string::size_type pos = 0;
|
|
||||||
while ((pos = PublicKeyPEM.find('\n', pos)) != std::string::npos) {
|
|
||||||
PublicKeyPEM.erase(pos, 1);
|
|
||||||
}
|
}
|
||||||
}
|
} catch (...) {
|
||||||
|
printf("[-] PatchSolution1 ...... Omitted.\n");
|
||||||
return PublicKeyPEM.length() == sizeof(Keyword);
|
return false;
|
||||||
} catch (...) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PatchSolution1::MakePatch(const RSACipher& RsaCipher) const {
|
|
||||||
if (pvt_PatchOffset == X64ImageInterpreter::InvalidOffset) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "PatchSolution1 is not ready.");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto pbPatch = pvt_Image.ImageOffset<uint8_t*>(pvt_PatchOffset);
|
|
||||||
std::string PublicKeyPEM = RsaCipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
|
||||||
|
|
||||||
PublicKeyPEM.erase(PublicKeyPEM.find("-----BEGIN PUBLIC KEY-----"), 26);
|
|
||||||
PublicKeyPEM.erase(PublicKeyPEM.find("-----END PUBLIC KEY-----"), 24);
|
|
||||||
{
|
|
||||||
std::string::size_type pos = 0;
|
|
||||||
while ((pos = PublicKeyPEM.find('\n', pos)) != std::string::npos) {
|
|
||||||
PublicKeyPEM.erase(pos, 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t key = 8;
|
[[nodiscard]]
|
||||||
for (auto& c : PublicKeyPEM) {
|
bool PatchSolution1::CheckKey(const RSACipher& Cipher) const noexcept {
|
||||||
if (key == 0) key = 8;
|
try {
|
||||||
reinterpret_cast<uint8_t&>(c) ^= 0xbbu - key;
|
return Cipher.Bits() == 2048;
|
||||||
--key;
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
puts("**************************************************************");
|
void PatchSolution1::MakePatch(const RSACipher& Cipher) const {
|
||||||
puts("* PatchSolution1 *");
|
if (m_PatchOffset.has_value()) {
|
||||||
puts("**************************************************************");
|
auto szPublicKeyPEM = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
||||||
printf("@+0x%.8x\n", pvt_PatchOffset);
|
|
||||||
|
|
||||||
puts("Previous:");
|
for (auto pos = szPublicKeyPEM.find("-----BEGIN PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKeyPEM.find("-----BEGIN PUBLIC KEY-----", pos)) {
|
||||||
nkg::PrintMemory(pbPatch, pbPatch + sizeof(Keyword), pbPatch);
|
szPublicKeyPEM.erase(pos, strlen("-----BEGIN PUBLIC KEY-----"));
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(pbPatch, PublicKeyPEM.data(), PublicKeyPEM.length());
|
for (auto pos = szPublicKeyPEM.find("-----END PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKeyPEM.find("-----END PUBLIC KEY-----", pos)) {
|
||||||
|
szPublicKeyPEM.erase(pos, strlen("-----END PUBLIC KEY-----"));
|
||||||
|
}
|
||||||
|
|
||||||
puts("After:");
|
for (auto pos = szPublicKeyPEM.find('\n'); pos != std::string::npos; pos = szPublicKeyPEM.find('\n', pos)) {
|
||||||
nkg::PrintMemory(pbPatch, pbPatch + sizeof(Keyword), pbPatch);
|
szPublicKeyPEM.erase(pos, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0, key = 8; i < szPublicKeyPEM.length(); ++i, --key) {
|
||||||
|
if (key == 0) {
|
||||||
|
key = 8;
|
||||||
|
}
|
||||||
|
szPublicKeyPEM[i] ^= static_cast<char>(0xBB - key);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (szPublicKeyPEM.length() < sizeof(Keyword)) {
|
||||||
|
szPublicKeyPEM.push_back('\x00');
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lpPatch = m_Image.ImageOffset(m_PatchOffset.value());
|
||||||
|
|
||||||
|
puts("**************************************************************");
|
||||||
|
puts("* PatchSolution1 *");
|
||||||
|
puts("**************************************************************");
|
||||||
|
|
||||||
|
printf("[*] Previous:\n");
|
||||||
|
Misc::PrintMemory(lpPatch, sizeof(Keyword), m_Image.ImageBase());
|
||||||
|
memcpy(lpPatch, szPublicKeyPEM.data(), sizeof(Keyword));
|
||||||
|
printf("[*] After:\n");
|
||||||
|
Misc::PrintMemory(lpPatch, sizeof(Keyword), m_Image.ImageBase());
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "PatchSolution1: not ready yet.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
puts("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,254 +1,301 @@
|
|||||||
#include "PatchSolutions.hpp"
|
#include "PatchSolutions.hpp"
|
||||||
#include <memory.h>
|
#include "Misc.hpp"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
const char PatchSolution2::Keyword[1114] =
|
namespace nkg {
|
||||||
"BIjWyoeRR0NBgkqnDZWxCgKCEAw1dqF3DTvOB91ZHwecJYFrdM1KEh"
|
|
||||||
"1yVeRoGqSdLLGZGUlngig3OD5mMzs889IqWqqfHSeHMvzyg1p6UPCY"
|
|
||||||
"nesxa9M2dDUrXHomRHOFHSfsbSXRFwt5GivtnJG9lLJHZ7XWeIQABi"
|
|
||||||
"dKionYD3O6c9tvUAoDosUJAdQ1RaSXTzyETbHTRtnTPeLpO3EedGMs"
|
|
||||||
"v3jG9yPcmmdYkddSeJRwn2raPJmnvdHScHUACw0sUNuosAqPaQbTQN"
|
|
||||||
"PATDzcrnd1Sf8RIbUp4MQJFVJugPLVZbP53Gjtyyniqe5q75kva8Qm"
|
|
||||||
"Hr1uOuXkVppe3cwECaGamupG43L1XfcpRjCMrxRep3s2VlbL01xmfz"
|
|
||||||
"5cIhrj34iVmgZSAmIb8ZxiHPdp1oDMFkbNetZyWegqjAHQQ9eoSOTD"
|
|
||||||
"bERbKEwZ5FLeLsbNAxfqsapB1XBvCavFHualx6bxVxuRQceh4z8kaZ"
|
|
||||||
"iv2pOKbZQSJ2Dx5HEq0bYZ6y6b7sN9IaeDFNQwjzQn1K7k3XlYAPWC"
|
|
||||||
"IvDe8Ln0FUe4yMNmuUhu5RTjxE05hUqtz1HjJvYQ9Es1VA6LflKQ87"
|
|
||||||
"TwIXBNvfrcHaZ72QM4dQtDUyEMrLgMDkJBDM9wqIDps65gSlAz6eHD"
|
|
||||||
"8tYWUttrWose0cH0yykVnqFzPtdRiZyZRfio6lGyK48mIC9z7T6MN3"
|
|
||||||
"a7OaLZHZSwzcpQLcGi7M9q1wXLq4Ms1UvlwntB9FLHc63tHPpG8rhn"
|
|
||||||
"XhZIk4QrSm4GYuEKQVHwku6ulw6wfggVL8FZPhoPCGsrb2rQGurBUL"
|
|
||||||
"3lkVJ6RO9VGHcczDYomXqAJqlt4y9pkQIj9kgwTrxTzEZgMGdYZqsV"
|
|
||||||
"4Bd5JjtrL7u3LA0N2Hq9Xvmmis2jDVhSQoUoGukNIoqng3SBsf0E7b"
|
|
||||||
"4W0S1aZSSOJ90nQHQkQShE9YIMDBbNwIg2ncthwADYqibYUgIvJcK9"
|
|
||||||
"89XHnYmZsdMWtt53lICsXE1vztR5WrQjSw4WXDiB31LXTrvudCB6vw"
|
|
||||||
"kCQa4leutETpKLJ2bYaOYBdoiBFOwvf36YaSuRoY4SP2x1pWOwGFTg"
|
|
||||||
"d90J2uYyCqUa3Q3iX52iigT4EKL2vJKdJ";
|
|
||||||
|
|
||||||
const uint8_t PatchSolution2::FunctionHeader[9] = {
|
const char PatchSolution2::Keyword[1114] =
|
||||||
0x55, // push rbp
|
"BIjWyoeRR0NBgkqnDZWxCgKCEAw1dqF3DTvOB91ZHwecJYFrdM1KEh"
|
||||||
0x48, 0x89, 0xe5, // mov rbp, rsp
|
"1yVeRoGqSdLLGZGUlngig3OD5mMzs889IqWqqfHSeHMvzyg1p6UPCY"
|
||||||
0x41, 0x57, // push r15
|
"nesxa9M2dDUrXHomRHOFHSfsbSXRFwt5GivtnJG9lLJHZ7XWeIQABi"
|
||||||
0x41, 0x56, // push r14
|
"dKionYD3O6c9tvUAoDosUJAdQ1RaSXTzyETbHTRtnTPeLpO3EedGMs"
|
||||||
0x53, // push rbx
|
"v3jG9yPcmmdYkddSeJRwn2raPJmnvdHScHUACw0sUNuosAqPaQbTQN"
|
||||||
};
|
"PATDzcrnd1Sf8RIbUp4MQJFVJugPLVZbP53Gjtyyniqe5q75kva8Qm"
|
||||||
|
"Hr1uOuXkVppe3cwECaGamupG43L1XfcpRjCMrxRep3s2VlbL01xmfz"
|
||||||
|
"5cIhrj34iVmgZSAmIb8ZxiHPdp1oDMFkbNetZyWegqjAHQQ9eoSOTD"
|
||||||
|
"bERbKEwZ5FLeLsbNAxfqsapB1XBvCavFHualx6bxVxuRQceh4z8kaZ"
|
||||||
|
"iv2pOKbZQSJ2Dx5HEq0bYZ6y6b7sN9IaeDFNQwjzQn1K7k3XlYAPWC"
|
||||||
|
"IvDe8Ln0FUe4yMNmuUhu5RTjxE05hUqtz1HjJvYQ9Es1VA6LflKQ87"
|
||||||
|
"TwIXBNvfrcHaZ72QM4dQtDUyEMrLgMDkJBDM9wqIDps65gSlAz6eHD"
|
||||||
|
"8tYWUttrWose0cH0yykVnqFzPtdRiZyZRfio6lGyK48mIC9z7T6MN3"
|
||||||
|
"a7OaLZHZSwzcpQLcGi7M9q1wXLq4Ms1UvlwntB9FLHc63tHPpG8rhn"
|
||||||
|
"XhZIk4QrSm4GYuEKQVHwku6ulw6wfggVL8FZPhoPCGsrb2rQGurBUL"
|
||||||
|
"3lkVJ6RO9VGHcczDYomXqAJqlt4y9pkQIj9kgwTrxTzEZgMGdYZqsV"
|
||||||
|
"4Bd5JjtrL7u3LA0N2Hq9Xvmmis2jDVhSQoUoGukNIoqng3SBsf0E7b"
|
||||||
|
"4W0S1aZSSOJ90nQHQkQShE9YIMDBbNwIg2ncthwADYqibYUgIvJcK9"
|
||||||
|
"89XHnYmZsdMWtt53lICsXE1vztR5WrQjSw4WXDiB31LXTrvudCB6vw"
|
||||||
|
"kCQa4leutETpKLJ2bYaOYBdoiBFOwvf36YaSuRoY4SP2x1pWOwGFTg"
|
||||||
|
"d90J2uYyCqUa3Q3iX52iigT4EKL2vJKdJ";
|
||||||
|
|
||||||
PatchSolution2::PatchSolution2(const X64ImageInterpreter& Image) noexcept :
|
PatchSolution2::PatchSolution2(const X64ImageInterpreter& Image) :
|
||||||
pvt_Image(Image),
|
m_Image(Image),
|
||||||
pvt_Disassembler(CapstoneDisassembler::Create(CS_ARCH_X86, CS_MODE_64)),
|
m_DisassemblerEngine(CS_ARCH_X86, CS_MODE_64),
|
||||||
pvt_Assembler(KeystoneAssembler::Create(KS_ARCH_X86, KS_MODE_64)),
|
m_AssemblerEngine(KS_ARCH_X86, KS_MODE_64)
|
||||||
pvt_FunctionOffset(X64ImageInterpreter::InvalidOffset),
|
{
|
||||||
pvt_KeywordOffset(X64ImageInterpreter::InvalidOffset),
|
m_DisassemblerEngine.Option(CS_OPT_DETAIL, CS_OPT_ON);
|
||||||
pvt_StdStringAppendStubRva(X64ImageInterpreter::InvalidAddress)
|
}
|
||||||
{
|
|
||||||
pvt_Disassembler.Option(CS_OPT_DETAIL, CS_OPT_ON);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PatchSolution2::FindPatchOffset() noexcept {
|
[[nodiscard]]
|
||||||
auto FunctionOffset = X64ImageInterpreter::InvalidOffset;
|
const char* PatchSolution2::TryResolveStubHelper(const void* lpStubHelperProc) const {
|
||||||
auto KeywordOffset = X64ImageInterpreter::InvalidOffset;
|
if (auto dyld_info = m_Image.SpecialLoadCommand<LC_DYLD_INFO_ONLY>(); dyld_info) {
|
||||||
auto StdStringAppendStubRva = X64ImageInterpreter::InvalidAddress;
|
auto Disassembler = m_DisassemblerEngine.CreateDisassembler();
|
||||||
|
|
||||||
try {
|
// A stub-helper proc must look like:
|
||||||
auto Sec__text = pvt_Image.ImageSection("__TEXT", "__text");
|
// push xxxxh;
|
||||||
auto Sec__const = pvt_Image.ImageSection("__TEXT", "__const");
|
// jmp loc_xxxxxxxx
|
||||||
auto Sec__stubs = pvt_Image.ImageSection("__TEXT", "__stubs");
|
// which should be 10 bytes long.
|
||||||
auto SecView__text = pvt_Image.SectionView<uint8_t*>(Sec__text);
|
Disassembler.SetContext({ lpStubHelperProc, 10, 0 });
|
||||||
auto SecView__const = pvt_Image.SectionView<uint8_t*>(Sec__const);
|
|
||||||
auto SecView__stubs = pvt_Image.SectionView<uint8_t*>(Sec__stubs);
|
|
||||||
|
|
||||||
KeywordOffset = pvt_Image.SearchSectionOffset("__TEXT", "__const", [](const uint8_t* p) {
|
if (Disassembler.Next()) {
|
||||||
return memcmp(p, Keyword, sizeof(Keyword)) == 0;
|
auto lpInsn = Disassembler.GetInstruction();
|
||||||
});
|
if (strcasecmp(lpInsn->mnemonic, "push") == 0 && lpInsn->detail->x86.operands[0].type == X86_OP_IMM) {
|
||||||
|
auto pbBindOpcode =
|
||||||
|
m_Image.ImageOffset<const uint8_t*>(dyld_info->lazy_bind_off) +
|
||||||
|
lpInsn->detail->x86.operands[0].imm;
|
||||||
|
|
||||||
auto KeywordRva = pvt_Image.OffsetToRva(KeywordOffset);
|
while ((*pbBindOpcode & BIND_OPCODE_MASK) != BIND_OPCODE_DONE) {
|
||||||
|
switch (*pbBindOpcode & BIND_OPCODE_MASK) {
|
||||||
|
case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: // 0x10
|
||||||
|
case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: // 0x30
|
||||||
|
case BIND_OPCODE_SET_TYPE_IMM: // 0x50
|
||||||
|
case BIND_OPCODE_DO_BIND: // 0x90
|
||||||
|
case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: // 0xB0
|
||||||
|
++pbBindOpcode;
|
||||||
|
break;
|
||||||
|
case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: // 0x20
|
||||||
|
case BIND_OPCODE_SET_ADDEND_SLEB: // 0x60
|
||||||
|
case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: // 0x70
|
||||||
|
case BIND_OPCODE_ADD_ADDR_ULEB: // 0x80
|
||||||
|
case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: // 0xA0
|
||||||
|
while (*(++pbBindOpcode) & 0x80u) {}
|
||||||
|
++pbBindOpcode;
|
||||||
|
break;
|
||||||
|
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: // 0x40
|
||||||
|
return reinterpret_cast<const char *>(pbBindOpcode + 1);
|
||||||
|
case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: // 0xC0
|
||||||
|
//
|
||||||
|
// This opcode is too rare to appear,
|
||||||
|
// It is okay to dismiss this opcode
|
||||||
|
//
|
||||||
|
return nullptr;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto Hint = pvt_Image.SearchSectionOffset("__TEXT", "__text", [Sec__text, SecView__text, KeywordRva](const uint8_t* p) {
|
|
||||||
auto rip = (p - SecView__text) + Sec__text->addr + 4;
|
|
||||||
auto off = *reinterpret_cast<const uint32_t*>(p);
|
|
||||||
return rip + off == KeywordRva;
|
|
||||||
}) - 0xc0;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < 0xc0; ++i) {
|
|
||||||
if (memcmp(pvt_Image.ImageOffset(Hint + i), FunctionHeader, sizeof(FunctionHeader)) == 0) {
|
|
||||||
FunctionOffset = Hint + i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FunctionOffset == X64ImageInterpreter::InvalidOffset) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Not found.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pvt_Disassembler.SetContext(SecView__stubs, Sec__stubs->size, Sec__stubs->addr);
|
|
||||||
while (pvt_Disassembler.Next()) {
|
|
||||||
auto insn = pvt_Disassembler.GetInstruction();
|
|
||||||
|
|
||||||
//
|
|
||||||
// As far as I know, all stub functions have a pattern looking like:
|
|
||||||
// jmp qword ptr [RIP + xxxx]
|
|
||||||
//
|
|
||||||
if (strcasecmp(insn->mnemonic, "jmp") == 0 && insn->detail->x86.operands[0].type == X86_OP_MEM && insn->detail->x86.operands[0].mem.base == X86_REG_RIP) {
|
|
||||||
uint64_t la_symbol_ptr_rva = pvt_Disassembler.GetContext().Address + insn->detail->x86.operands[0].mem.disp;
|
|
||||||
uint32_t la_symbol_ptr_offset = pvt_Image.RvaToOffset(la_symbol_ptr_rva);
|
|
||||||
if (la_symbol_ptr_offset == X64ImageInterpreter::InvalidOffset)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
uint64_t stub_helper_rva = *pvt_Image.ImageOffset<const uint64_t*>(la_symbol_ptr_offset);
|
|
||||||
uint32_t stub_helper_offset = pvt_Image.RvaToOffset(stub_helper_rva);
|
|
||||||
if (stub_helper_offset == X64ImageInterpreter::InvalidOffset)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//
|
|
||||||
// __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKc
|
|
||||||
// is the mangled name of "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::append(char const*)",
|
|
||||||
// which is, as known as, "std::string::append(const char*)"
|
|
||||||
// You can demangle it by c++flit
|
|
||||||
// e.g.
|
|
||||||
// c++filt -_ '__ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKc'
|
|
||||||
//
|
|
||||||
if (nkg::IsResolvedTo(pvt_Image, pvt_Image.ImageOffset(stub_helper_offset), "__ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKc")) {
|
|
||||||
auto StdStringAppendStubOffset = pvt_Disassembler.GetInstructionContext().pbOpcode - pvt_Image.ImageBase<const uint8_t*>();
|
|
||||||
StdStringAppendStubRva = pvt_Image.OffsetToRva(StdStringAppendStubOffset);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
if (StdStringAppendStubRva == X64ImageInterpreter::InvalidAddress) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Not found.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pvt_FunctionOffset = FunctionOffset;
|
|
||||||
pvt_KeywordOffset = KeywordOffset;
|
|
||||||
pvt_StdStringAppendStubRva = StdStringAppendStubRva;
|
|
||||||
|
|
||||||
printf("[+] PatchSolution2 ...... Ready to apply.\n");
|
|
||||||
printf(" Function offset = +0x%.8x\n", pvt_FunctionOffset);
|
|
||||||
printf(" Keyword offset = +0x%.8x\n", pvt_KeywordOffset);
|
|
||||||
printf(" std::string::append(const char*) RVA = 0x%.16llx\n", pvt_StdStringAppendStubRva);
|
|
||||||
return true;
|
|
||||||
} catch (...) {
|
|
||||||
printf("[-] PatchSolution2 ...... Omitted.\n");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
bool PatchSolution2::CheckKey(const RSACipher& RsaCipher) const noexcept {
|
bool PatchSolution2::FindPatchOffset() noexcept {
|
||||||
std::string PublicKeyPEM = RsaCipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
try {
|
||||||
|
std::optional<X64ImageOffset> KeywordOffset;
|
||||||
|
std::optional<X64ImageOffset> FunctionOffset;
|
||||||
|
std::optional<X64ImageAddress> StdStringAppendStubRva;
|
||||||
|
|
||||||
PublicKeyPEM.erase(PublicKeyPEM.find("-----BEGIN PUBLIC KEY-----"), 26);
|
auto section__text = m_Image.ImageSection("__TEXT", "__text");
|
||||||
PublicKeyPEM.erase(PublicKeyPEM.find("-----END PUBLIC KEY-----"), 24);
|
auto section__stubs = m_Image.ImageSection("__TEXT", "__stubs");
|
||||||
{
|
auto sectionview__text = m_Image.ImageSectionView(section__text);
|
||||||
std::string::size_type pos = 0;
|
auto sectionview__stubs = m_Image.ImageSectionView(section__stubs);
|
||||||
while ((pos = PublicKeyPEM.find('\n', pos)) != std::string::npos) {
|
auto Disassembler = m_DisassemblerEngine.CreateDisassembler();
|
||||||
PublicKeyPEM.erase(pos, 1);
|
|
||||||
|
auto p = m_Image.SearchSection("__TEXT", "__const", [](const void* base, size_t i, size_t size) {
|
||||||
|
if (i + sizeof(Keyword) <= size) {
|
||||||
|
return memcmp(ARL::AddressOffset(base, i), Keyword, sizeof(Keyword)) == 0;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (p) {
|
||||||
|
KeywordOffset = m_Image.ConvertPtrToOffset(p);
|
||||||
|
} else {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "Keyword is not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
p = m_Image.SearchSection(section__text, [section__text, KeywordRva = m_Image.ConvertOffsetToRva(KeywordOffset.value())](const void* base, size_t i, size_t size) {
|
||||||
|
if (i + sizeof(uint32_t) <= size) {
|
||||||
|
auto rip = i + section__text->addr + sizeof(uint32_t);
|
||||||
|
auto off = ARL::AddressRead<uint32_t>(ARL::AddressOffset(base, i));
|
||||||
|
return rip + off == KeywordRva;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (p) {
|
||||||
|
p = m_Image.SearchSection(
|
||||||
|
section__text,
|
||||||
|
ARL::AddressDelta(p, sectionview__text) >= 0xc0 ? ARL::AddressDelta(p, sectionview__text) - 0xc0 : 0,
|
||||||
|
[p](const void* base, size_t i, size_t size) {
|
||||||
|
static const uint8_t FunctionHeader[9] = {
|
||||||
|
0x55, // push rbp
|
||||||
|
0x48, 0x89, 0xe5, // mov rbp, rsp
|
||||||
|
0x41, 0x57, // push r15
|
||||||
|
0x41, 0x56, // push r14
|
||||||
|
0x53, // push rbx
|
||||||
|
};
|
||||||
|
if (ARL::AddressOffset(base, i + sizeof(FunctionHeader)) <= p) {
|
||||||
|
return memcmp(ARL::AddressOffset(base, i), FunctionHeader, sizeof(FunctionHeader)) == 0;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (p) {
|
||||||
|
FunctionOffset = m_Image.ConvertPtrToOffset(p);
|
||||||
|
} else {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "Function header is not found.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "Xref of Keyword is not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Disassembler.SetContext({ sectionview__stubs, section__stubs->size, section__stubs->addr });
|
||||||
|
while (Disassembler.Next()) {
|
||||||
|
auto lpInsn = Disassembler.GetInstruction();
|
||||||
|
|
||||||
|
//
|
||||||
|
// As far as I know, all stub functions have a pattern looking like:
|
||||||
|
// jmp qword ptr [RIP + xxxx]
|
||||||
|
//
|
||||||
|
if (strcasecmp(lpInsn->mnemonic, "jmp") == 0 && lpInsn->detail->x86.operands[0].type == X86_OP_MEM && lpInsn->detail->x86.operands[0].mem.base == X86_REG_RIP) {
|
||||||
|
try {
|
||||||
|
X64ImageAddress la_symbol_ptr_rva = Disassembler.GetContext().Address + lpInsn->detail->x86.operands[0].mem.disp;
|
||||||
|
X64ImageOffset la_symbol_ptr_offset = m_Image.ConvertRvaToOffset(la_symbol_ptr_rva);
|
||||||
|
|
||||||
|
X64ImageAddress stub_helper_rva = ARL::AddressRead<uint64_t>(m_Image.ImageBase(), la_symbol_ptr_offset);
|
||||||
|
X64ImageOffset stub_helper_offset = m_Image.ConvertRvaToOffset(stub_helper_rva);
|
||||||
|
|
||||||
|
//
|
||||||
|
// __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKc
|
||||||
|
// is the mangled name of "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::append(char const*)",
|
||||||
|
// which is, as known as, "std::string::append(const char*)"
|
||||||
|
// You can demangle it by c++flit
|
||||||
|
// e.g.
|
||||||
|
// c++filt -_ '__ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKc'
|
||||||
|
//
|
||||||
|
auto lpszSymbolName = TryResolveStubHelper(m_Image.ImageOffset(stub_helper_offset));
|
||||||
|
if (lpszSymbolName && strcmp(lpszSymbolName, "__ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKc") == 0) {
|
||||||
|
StdStringAppendStubRva = Disassembler.GetInstructionContext().Address;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (StdStringAppendStubRva.has_value()) {
|
||||||
|
m_KeywordOffset = KeywordOffset.value();
|
||||||
|
m_FunctionOffset = FunctionOffset.value();
|
||||||
|
m_StdStringAppendStubRva = StdStringAppendStubRva.value();
|
||||||
|
} else {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "std::string::append(const char*) is not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("[+] PatchSolution2 ...... Ready to apply.\n");
|
||||||
|
printf(" Keyword offset = +0x%.8x\n", m_KeywordOffset.value());
|
||||||
|
printf(" CSRegistrationCenter::obtainPublicKey RVA = 0x%.16llx\n", m_Image.ConvertOffsetToRva(m_FunctionOffset.value()));
|
||||||
|
printf(" std::string::append(const char*) RVA = 0x%.16llx\n", m_StdStringAppendStubRva.value());
|
||||||
|
return true;
|
||||||
|
} catch (...) {
|
||||||
|
printf("[-] PatchSolution2 ...... Omitted.\n");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return PublicKeyPEM.length() == 0x188;
|
[[nodiscard]]
|
||||||
}
|
bool PatchSolution2::CheckKey(const RSACipher& Cipher) const noexcept {
|
||||||
|
return Cipher.Bits() == 2048;
|
||||||
void PatchSolution2::MakePatch(const RSACipher& RsaCipher) const {
|
|
||||||
if (pvt_FunctionOffset == X64ImageInterpreter::InvalidOffset ||
|
|
||||||
pvt_KeywordOffset == X64ImageInterpreter::InvalidOffset ||
|
|
||||||
pvt_StdStringAppendStubRva == X64ImageInterpreter::InvalidAddress)
|
|
||||||
{
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "PatchSolution2 is not ready.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
void PatchSolution2::MakePatch(const RSACipher& Cipher) const {
|
||||||
// Prepare public key string
|
if (m_KeywordOffset.has_value() && m_FunctionOffset.has_value() && m_StdStringAppendStubRva.has_value()) {
|
||||||
//
|
//
|
||||||
std::string PublicKeyPEM = RsaCipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
// Prepare public key string
|
||||||
|
//
|
||||||
|
auto szPublicKeyPEM = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
||||||
|
|
||||||
PublicKeyPEM.erase(PublicKeyPEM.find("-----BEGIN PUBLIC KEY-----"), 26);
|
for (auto pos = szPublicKeyPEM.find("-----BEGIN PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKeyPEM.find("-----BEGIN PUBLIC KEY-----", pos)) {
|
||||||
PublicKeyPEM.erase(PublicKeyPEM.find("-----END PUBLIC KEY-----"), 24);
|
szPublicKeyPEM.erase(pos, strlen("-----BEGIN PUBLIC KEY-----"));
|
||||||
{
|
}
|
||||||
std::string::size_type pos = 0;
|
|
||||||
while ((pos = PublicKeyPEM.find('\n', pos)) != std::string::npos) {
|
for (auto pos = szPublicKeyPEM.find("-----END PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKeyPEM.find("-----END PUBLIC KEY-----", pos)) {
|
||||||
PublicKeyPEM.erase(pos, 1);
|
szPublicKeyPEM.erase(pos, strlen("-----END PUBLIC KEY-----"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto pos = szPublicKeyPEM.find('\n'); pos != std::string::npos; pos = szPublicKeyPEM.find('\n', pos)) {
|
||||||
|
szPublicKeyPEM.erase(pos, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Prepare new function opcodes
|
||||||
|
//
|
||||||
|
auto Assembler = m_AssemblerEngine.CreateAssembler();
|
||||||
|
auto MachineCode = Assembler.GenerateMachineCode(
|
||||||
|
[KeywordRva = m_Image.ConvertOffsetToRva(m_KeywordOffset.value()), StdStringAppendStubRva = m_StdStringAppendStubRva.value()]() -> std::string {
|
||||||
|
const char asm_template[] =
|
||||||
|
"push rbp;"
|
||||||
|
"mov rbp, rsp;"
|
||||||
|
|
||||||
|
"xor rax, rax;" // initialize std::string with null
|
||||||
|
"mov qword ptr[rdi], rax;"
|
||||||
|
"mov qword ptr[rdi + 0x8], rax;"
|
||||||
|
"mov qword ptr[rdi + 0x10], rax;"
|
||||||
|
|
||||||
|
"lea rsi, qword ptr[0x%.16llx];" // filled with address to Keyword
|
||||||
|
"call 0x%.16llx;" // filled with address to std::string::append(const char*)
|
||||||
|
|
||||||
|
"leave;"
|
||||||
|
"ret;";
|
||||||
|
std::string asm_string;
|
||||||
|
|
||||||
|
int l = snprintf(nullptr, 0, asm_template, KeywordRva, StdStringAppendStubRva);
|
||||||
|
if (l < 0) {
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
asm_string.resize(l + 1);
|
||||||
|
|
||||||
|
l = snprintf(asm_string.data(), asm_string.length(), asm_template, KeywordRva, StdStringAppendStubRva);
|
||||||
|
if (l < 0) {
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (asm_string.back() == '\x00') {
|
||||||
|
asm_string.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
return asm_string;
|
||||||
|
}().c_str(),
|
||||||
|
m_Image.ConvertOffsetToRva(m_FunctionOffset.value())
|
||||||
|
);
|
||||||
|
|
||||||
|
puts("**************************************************************");
|
||||||
|
puts("* PatchSolution2 *");
|
||||||
|
puts("**************************************************************");
|
||||||
|
|
||||||
|
auto lpKeyword = m_Image.ImageOffset(m_KeywordOffset.value());
|
||||||
|
auto lpFunction = m_Image.ImageOffset(m_FunctionOffset.value());
|
||||||
|
|
||||||
|
printf("[*] Previous:\n");
|
||||||
|
Misc::PrintMemory(lpKeyword, szPublicKeyPEM.length() + 1, m_Image.ImageBase());
|
||||||
|
memcpy(lpKeyword, szPublicKeyPEM.c_str(), szPublicKeyPEM.length() + 1); // with a null-terminator
|
||||||
|
printf("[*] After:\n");
|
||||||
|
Misc::PrintMemory(lpKeyword, szPublicKeyPEM.length() + 1, m_Image.ImageBase());
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("[*] Previous:\n");
|
||||||
|
Misc::PrintMemory(lpFunction, MachineCode.size(), m_Image.ImageBase());
|
||||||
|
memcpy(lpFunction, MachineCode.data(), MachineCode.size());
|
||||||
|
printf("[*] After:\n");
|
||||||
|
Misc::PrintMemory(lpFunction, MachineCode.size(), m_Image.ImageBase());
|
||||||
|
printf("\n");
|
||||||
|
} else {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "PatchSolution2: not ready yet.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Prepare new function opcodes
|
|
||||||
//
|
|
||||||
uint64_t FunctionRVA = pvt_Image.OffsetToRva(pvt_FunctionOffset);
|
|
||||||
uint64_t KeywordRVA = pvt_Image.OffsetToRva(pvt_KeywordOffset);
|
|
||||||
|
|
||||||
char AssemblyCode[512] = {};
|
|
||||||
sprintf(AssemblyCode,
|
|
||||||
"push rbp;"
|
|
||||||
"mov rbp, rsp;"
|
|
||||||
"push r15;"
|
|
||||||
"push r14;"
|
|
||||||
"push rbx;"
|
|
||||||
"sub rsp, 0x48;"
|
|
||||||
|
|
||||||
"mov rbx, rdi;"
|
|
||||||
|
|
||||||
"xor rax, rax;" // initialize std::string with null
|
|
||||||
"mov qword ptr[rsp], rax;"
|
|
||||||
"mov qword ptr[rsp + 0x8], rax;"
|
|
||||||
"mov qword ptr[rsp + 0x10], rax;"
|
|
||||||
|
|
||||||
"lea rdi, qword ptr[rsp];"
|
|
||||||
"lea rsi, qword ptr[0x%.16llx];" // filled with address to Keyword
|
|
||||||
"call 0x%.16llx;" // filled with address to std::string::append(const char*)
|
|
||||||
|
|
||||||
"mov rax, qword ptr[rsp];"
|
|
||||||
"mov qword ptr[rbx], rax;"
|
|
||||||
"mov rax, qword ptr[rsp + 0x8];"
|
|
||||||
"mov qword ptr[rbx + 0x8], rax;"
|
|
||||||
"mov rax, qword ptr[rsp + 0x10];"
|
|
||||||
"mov qword ptr[rbx + 0x10], rax;"
|
|
||||||
|
|
||||||
"mov rax, rbx;"
|
|
||||||
"add rsp, 0x48;"
|
|
||||||
"pop rbx;"
|
|
||||||
"pop r14;"
|
|
||||||
"pop r15;"
|
|
||||||
"pop rbp;"
|
|
||||||
"ret;",
|
|
||||||
KeywordRVA,
|
|
||||||
pvt_StdStringAppendStubRva
|
|
||||||
);
|
|
||||||
|
|
||||||
auto NewFunctionOpcode = pvt_Assembler.GenerateOpcode(AssemblyCode, FunctionRVA);
|
|
||||||
|
|
||||||
auto pbFunctionPatch = pvt_Image.ImageOffset<uint8_t*>(pvt_FunctionOffset);
|
|
||||||
auto pbKeywordPatch = pvt_Image.ImageOffset<uint8_t*>(pvt_KeywordOffset);
|
|
||||||
|
|
||||||
puts("**************************************************************");
|
|
||||||
puts("* PatchSolution2 *");
|
|
||||||
puts("**************************************************************");
|
|
||||||
printf("@+0x%.8x\n", pvt_KeywordOffset);
|
|
||||||
|
|
||||||
puts("Previous:");
|
|
||||||
nkg::PrintMemory(pbKeywordPatch, pbKeywordPatch + sizeof(Keyword) - 1, pbKeywordPatch);
|
|
||||||
|
|
||||||
memcpy(pbKeywordPatch, PublicKeyPEM.c_str(), PublicKeyPEM.length() + 1); // with a null-terminator
|
|
||||||
|
|
||||||
puts("After:");
|
|
||||||
nkg::PrintMemory(pbKeywordPatch, pbKeywordPatch + sizeof(Keyword) - 1, pbKeywordPatch);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
puts("");
|
|
||||||
printf("@+0x%.8x\n", pvt_FunctionOffset);
|
|
||||||
|
|
||||||
puts("Previous:");
|
|
||||||
nkg::PrintMemory(pbFunctionPatch, pbFunctionPatch + NewFunctionOpcode.size(), pbFunctionPatch);
|
|
||||||
|
|
||||||
memcpy(pbFunctionPatch, NewFunctionOpcode.data(), NewFunctionOpcode.size());
|
|
||||||
|
|
||||||
puts("After:");
|
|
||||||
nkg::PrintMemory(pbFunctionPatch, pbFunctionPatch + NewFunctionOpcode.size(), pbFunctionPatch);
|
|
||||||
|
|
||||||
puts("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,114 +1,107 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../common/Exception.hpp"
|
#include "Exception.hpp"
|
||||||
#include "../common/ResourceOwned.hpp"
|
#include "RSACipher.hpp"
|
||||||
#include "../common/RSACipher.hpp"
|
|
||||||
#include "ResourceTraitsUnix.hpp"
|
#include "ResourceTraitsUnix.hpp"
|
||||||
#include "X64ImageInterpreter.hpp"
|
|
||||||
#include "CapstoneDisassembler.hpp"
|
#include "CapstoneDisassembler.hpp"
|
||||||
#include "KeystoneAssembler.hpp"
|
#include "KeystoneAssembler.hpp"
|
||||||
|
#include "X64ImageInterpreter.hpp"
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace nkg {
|
namespace nkg {
|
||||||
//
|
|
||||||
// Print memory data in [from, to) at least
|
class PatchSolution {
|
||||||
// If `base` is not nullptr, print address as offset. Otherwise, as absolute address.
|
public:
|
||||||
// NOTICE:
|
|
||||||
// `base` must >= `from`
|
[[nodiscard]]
|
||||||
//
|
virtual bool FindPatchOffset() noexcept = 0;
|
||||||
void PrintMemory(const void *from, const void *to, const void *base = nullptr);
|
|
||||||
bool IsResolvedTo(const X64ImageInterpreter& Image, const void* StubHelperProc, const char *Symbol);
|
[[nodiscard]]
|
||||||
|
virtual bool CheckKey(const RSACipher& Cipher) const noexcept = 0;
|
||||||
|
|
||||||
|
virtual void MakePatch(const RSACipher& Cipher) const = 0;
|
||||||
|
|
||||||
|
virtual ~PatchSolution() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PatchSolution0 final : public PatchSolution {
|
||||||
|
private:
|
||||||
|
|
||||||
|
static const char Keyword[451];
|
||||||
|
|
||||||
|
const X64ImageInterpreter& m_Image;
|
||||||
|
std::optional<X64ImageOffset> m_PatchOffset;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
PatchSolution0(const X64ImageInterpreter& Image);
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
|
virtual bool FindPatchOffset() noexcept override;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
|
virtual bool CheckKey(const RSACipher& Cipher) const noexcept override;
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
|
virtual void MakePatch(const RSACipher& Cipher) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PatchSolution1 final : public PatchSolution {
|
||||||
|
private:
|
||||||
|
|
||||||
|
static const uint8_t Keyword[0x188];
|
||||||
|
|
||||||
|
const X64ImageInterpreter& m_Image;
|
||||||
|
std::optional<X64ImageOffset> m_PatchOffset;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
PatchSolution1(const X64ImageInterpreter& Image);
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
|
virtual bool FindPatchOffset() noexcept override;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
|
virtual bool CheckKey(const RSACipher& Cipher) const noexcept override;
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
|
virtual void MakePatch(const RSACipher& Cipher) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PatchSolution2 final : public PatchSolution {
|
||||||
|
private:
|
||||||
|
|
||||||
|
static const char Keyword[1114];
|
||||||
|
|
||||||
|
const X64ImageInterpreter& m_Image;
|
||||||
|
CapstoneEngine m_DisassemblerEngine;
|
||||||
|
KeystoneEngine m_AssemblerEngine;
|
||||||
|
|
||||||
|
std::optional<X64ImageOffset> m_KeywordOffset;
|
||||||
|
std::optional<X64ImageOffset> m_FunctionOffset;
|
||||||
|
std::optional<X64ImageAddress> m_StdStringAppendStubRva;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const char* TryResolveStubHelper(const void* lpStubHelperProc) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
PatchSolution2(const X64ImageInterpreter& Image);
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
|
virtual bool FindPatchOffset() noexcept override;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
|
virtual bool CheckKey(const RSACipher& Cipher) const noexcept override;
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
||||||
|
virtual void MakePatch(const RSACipher& Cipher) const override;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class PatchSolution {
|
|
||||||
public:
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
virtual bool FindPatchOffset() noexcept = 0;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
virtual bool CheckKey(const RSACipher& RsaCipher) const noexcept = 0;
|
|
||||||
|
|
||||||
virtual void MakePatch(const RSACipher& RsaCipher) const = 0;
|
|
||||||
|
|
||||||
virtual ~PatchSolution() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PatchSolution0 : public PatchSolution {
|
|
||||||
private:
|
|
||||||
|
|
||||||
static const char Keyword[452];
|
|
||||||
|
|
||||||
const X64ImageInterpreter& pvt_Image;
|
|
||||||
uint32_t pvt_PatchOffset;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
explicit
|
|
||||||
PatchSolution0(const X64ImageInterpreter& Image) noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
|
||||||
virtual bool FindPatchOffset() noexcept override;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
|
||||||
virtual bool CheckKey(const RSACipher& RsaCipher) const noexcept override;
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
|
||||||
virtual void MakePatch(const RSACipher& RsaCipher) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PatchSolution1 : public PatchSolution {
|
|
||||||
private:
|
|
||||||
|
|
||||||
static const uint8_t Keyword[0x188];
|
|
||||||
|
|
||||||
const X64ImageInterpreter& pvt_Image;
|
|
||||||
uint32_t pvt_PatchOffset;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
explicit
|
|
||||||
PatchSolution1(const X64ImageInterpreter& Image) noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
|
||||||
virtual bool FindPatchOffset() noexcept override;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
|
||||||
virtual bool CheckKey(const RSACipher& RsaCipher) const noexcept override;
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
|
||||||
virtual void MakePatch(const RSACipher& RsaCipher) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PatchSolution2 : public PatchSolution {
|
|
||||||
private:
|
|
||||||
|
|
||||||
static const char Keyword[1114];
|
|
||||||
static const uint8_t FunctionHeader[9];
|
|
||||||
|
|
||||||
const X64ImageInterpreter& pvt_Image;
|
|
||||||
CapstoneDisassembler pvt_Disassembler;
|
|
||||||
KeystoneAssembler pvt_Assembler;
|
|
||||||
uint32_t pvt_FunctionOffset;
|
|
||||||
uint32_t pvt_KeywordOffset;
|
|
||||||
uint64_t pvt_StdStringAppendStubRva;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
explicit
|
|
||||||
PatchSolution2(const X64ImageInterpreter& Image) noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
|
||||||
virtual bool FindPatchOffset() noexcept override;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
|
||||||
virtual bool CheckKey(const RSACipher& RsaCipher) const noexcept override;
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE: mark "virtual" explicitly for more readability
|
|
||||||
virtual void MakePatch(const RSACipher& RsaCipher) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|||||||
@ -2,37 +2,39 @@
|
|||||||
#include <capstone/capstone.h>
|
#include <capstone/capstone.h>
|
||||||
#include "ExceptionCapstone.hpp"
|
#include "ExceptionCapstone.hpp"
|
||||||
|
|
||||||
struct CapstoneHandleTraits {
|
namespace ARL::ResourceTraits {
|
||||||
using HandleType = csh;
|
|
||||||
|
|
||||||
static inline const HandleType InvalidValue = 0;
|
struct CapstoneHandle {
|
||||||
|
using HandleType = csh;
|
||||||
|
|
||||||
[[nodiscard]]
|
static inline const HandleType InvalidValue = 0;
|
||||||
static bool IsValid(const HandleType& Handle) noexcept {
|
|
||||||
return Handle != InvalidValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Releasor(HandleType& Handle) {
|
[[nodiscard]]
|
||||||
auto err = cs_close(&Handle);
|
static bool IsValid(const HandleType& Handle) noexcept {
|
||||||
if (err != CS_ERR_OK) {
|
return Handle != InvalidValue;
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::CapstoneError(__FILE__, __LINE__, err, "ks_close failed.");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CapstoneInsnTraits {
|
static void Release(HandleType& Handle) {
|
||||||
using HandleType = cs_insn*;
|
if (auto err = cs_close(&Handle); err != CS_ERR_OK) {
|
||||||
|
throw ARL::CapstoneError(__FILE__, __LINE__, err, "ks_close failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static inline const HandleType InvalidValue = nullptr;
|
struct CapstoneInsn {
|
||||||
|
using HandleType = cs_insn*;
|
||||||
|
|
||||||
[[nodiscard]]
|
static inline const HandleType InvalidValue = nullptr;
|
||||||
static bool IsValid(const HandleType& Handle) noexcept {
|
|
||||||
return Handle != InvalidValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Releasor(const HandleType& Handle) noexcept {
|
[[nodiscard]]
|
||||||
cs_free(Handle, 1);
|
static bool IsValid(const HandleType& Handle) noexcept {
|
||||||
}
|
return Handle != InvalidValue;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
static void Release(const HandleType& Handle) noexcept {
|
||||||
|
cs_free(Handle, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,37 +2,40 @@
|
|||||||
#include <keystone/keystone.h>
|
#include <keystone/keystone.h>
|
||||||
#include "ExceptionKeystone.hpp"
|
#include "ExceptionKeystone.hpp"
|
||||||
|
|
||||||
struct KeystoneHandleTraits {
|
namespace ARL::ResourceTraits {
|
||||||
using HandleType = ks_engine*;
|
|
||||||
|
|
||||||
static inline const HandleType InvalidValue = nullptr;
|
struct KeystoneHandle {
|
||||||
|
using HandleType = ks_engine*;
|
||||||
|
|
||||||
[[nodiscard]]
|
static inline const HandleType InvalidValue = nullptr;
|
||||||
static bool IsValid(const HandleType& Handle) noexcept {
|
|
||||||
return Handle != InvalidValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Releasor(const HandleType& Handle) {
|
[[nodiscard]]
|
||||||
auto err = ks_close(Handle);
|
static bool IsValid(const HandleType& Handle) noexcept {
|
||||||
if (err != KS_ERR_OK) {
|
return Handle != InvalidValue;
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::KeystoneError(__FILE__, __LINE__, err, "ks_close failed.");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct KeystoneMallocTraits {
|
static void Release(const HandleType& Handle) {
|
||||||
using HandleType = uint8_t*;
|
auto err = ks_close(Handle);
|
||||||
|
if (err != KS_ERR_OK) {
|
||||||
|
throw ARL::KeystoneError(__FILE__, __LINE__, err, "ks_close failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static inline const HandleType InvalidValue = nullptr;
|
struct KeystoneMalloc {
|
||||||
|
using HandleType = uint8_t*;
|
||||||
|
|
||||||
[[nodiscard]]
|
static inline const HandleType InvalidValue = nullptr;
|
||||||
static bool IsValid(const HandleType& Handle) noexcept {
|
|
||||||
return Handle != InvalidValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Releasor(const HandleType& Handle) noexcept {
|
[[nodiscard]]
|
||||||
ks_free(Handle);
|
static bool IsValid(const HandleType& Handle) noexcept {
|
||||||
}
|
return Handle != InvalidValue;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
static void Release(const HandleType& Handle) noexcept {
|
||||||
|
ks_free(Handle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,35 +1,38 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <errno.h> // NOLINT
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include "../common/ExceptionSystem.hpp"
|
#include "ExceptionSystem.hpp"
|
||||||
|
|
||||||
struct FileHandleTraits {
|
namespace ARL::ResourceTraits {
|
||||||
using HandleType = int;
|
|
||||||
|
|
||||||
static inline const HandleType InvalidValue = -1;
|
struct FileDescriptor {
|
||||||
|
using HandleType = int;
|
||||||
|
|
||||||
[[nodiscard]]
|
static inline const HandleType InvalidValue = -1;
|
||||||
static bool IsValid(const HandleType& Handle) noexcept {
|
|
||||||
return Handle != InvalidValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Releasor(const HandleType& Handle) {
|
[[nodiscard]]
|
||||||
if (close(Handle) != 0) {
|
static bool IsValid(const HandleType& Handle) noexcept {
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
return Handle != InvalidValue;
|
||||||
throw nkg::SystemError(__FILE__, __LINE__, errno, "close failed.");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MapViewTraits {
|
static void Release(const HandleType& Handle) {
|
||||||
using HandleType = void*;
|
if (close(Handle) != 0) {
|
||||||
|
throw ARL::SystemError(__FILE__, __LINE__, errno, "close failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static inline const HandleType InvalidValue = MAP_FAILED;
|
struct MapView {
|
||||||
|
using HandleType = void*;
|
||||||
|
|
||||||
[[nodiscard]]
|
static inline const HandleType InvalidValue = MAP_FAILED;
|
||||||
static bool IsValid(const HandleType& Handle) noexcept {
|
|
||||||
return Handle != InvalidValue;
|
[[nodiscard]]
|
||||||
}
|
static bool IsValid(const HandleType& Handle) noexcept {
|
||||||
};
|
return Handle != InvalidValue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,131 +1,124 @@
|
|||||||
#include "X64ImageInterpreter.hpp"
|
#include "X64ImageInterpreter.hpp"
|
||||||
|
|
||||||
[[nodiscard]]
|
namespace nkg {
|
||||||
X64ImageInterpreter X64ImageInterpreter::Parse(void* ImageBase) {
|
|
||||||
X64ImageInterpreter NewImage;
|
|
||||||
|
|
||||||
NewImage.pvt_MachHeader = reinterpret_cast<mach_header_64*>(ImageBase);
|
[[nodiscard]]
|
||||||
if (NewImage.pvt_MachHeader->magic != MH_MAGIC_64) {
|
X64ImageInterpreter X64ImageInterpreter::Parse(const void* lpImage, size_t cbImage) {
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
X64ImageInterpreter Interpreter;
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Bad Image");
|
|
||||||
|
Interpreter.m_MachOSize = cbImage;
|
||||||
|
Interpreter.m_MachOHeader = reinterpret_cast<const mach_header_64*>(lpImage);
|
||||||
|
if (Interpreter.m_MachOHeader->magic != MH_MAGIC_64) {
|
||||||
|
throw ARL::AssertionError(__FILE__, __LINE__, "X64ImageInterpreter: bad MachO file: header magic check failure.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cmd_p = ARL::AddressOffsetWithCast<const load_command*>(Interpreter.m_MachOHeader, sizeof(mach_header_64));
|
||||||
|
for (decltype(mach_header_64::ncmds) i = 0; i < Interpreter.m_MachOHeader->ncmds; ++i) {
|
||||||
|
switch (cmd_p->cmd) {
|
||||||
|
case LC_SEGMENT_64: {
|
||||||
|
auto segcmd_p = reinterpret_cast<const segment_command_64*>(cmd_p);
|
||||||
|
auto section_p = ARL::AddressOffsetWithCast<const section_64*>(segcmd_p, sizeof(segment_command_64));
|
||||||
|
|
||||||
|
Interpreter.m_Segments.emplace_back(segcmd_p);
|
||||||
|
|
||||||
|
for (decltype(segment_command_64::nsects) j = 0; j < segcmd_p->nsects; ++j) {
|
||||||
|
Interpreter.m_Sections.emplace_back(§ion_p[j]);
|
||||||
|
Interpreter.m_SectionsAddressMap[section_p[j].addr] = §ion_p[j];
|
||||||
|
Interpreter.m_SectionsOffsetMap[section_p[j].offset] = §ion_p[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LC_DYSYMTAB: {
|
||||||
|
Interpreter.m_SpecialLoadCommands.dysymtab = reinterpret_cast<const dysymtab_command*>(cmd_p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LC_SYMTAB: {
|
||||||
|
Interpreter.m_SpecialLoadCommands.symtab = reinterpret_cast<const symtab_command*>(cmd_p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LC_DYLD_INFO_ONLY: {
|
||||||
|
Interpreter.m_SpecialLoadCommands.dyld_info = reinterpret_cast<const dyld_info_command*>(cmd_p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_p = ARL::AddressOffset(cmd_p, cmd_p->cmdsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Interpreter;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cmd_p = reinterpret_cast<load_command*>(NewImage.pvt_MachHeader + 1);
|
[[nodiscard]]
|
||||||
for (uint32_t i = 0; i < NewImage.pvt_MachHeader->ncmds; ++i) {
|
size_t X64ImageInterpreter::NumberOfSegmentCommands() const noexcept {
|
||||||
switch (cmd_p->cmd) {
|
return m_Segments.size();
|
||||||
case LC_SEGMENT_64: {
|
}
|
||||||
auto segcmd_p = reinterpret_cast<segment_command_64*>(cmd_p);
|
|
||||||
auto section_p = reinterpret_cast<section_64*>(segcmd_p + 1);
|
|
||||||
|
|
||||||
NewImage.pvt_SegmentCommands.emplace_back(segcmd_p);
|
[[nodiscard]]
|
||||||
|
size_t X64ImageInterpreter::NumberOfSections() const noexcept {
|
||||||
|
return m_Sections.size();
|
||||||
|
}
|
||||||
|
|
||||||
for (uint32_t j = 0; j < segcmd_p->nsects; ++j) {
|
[[nodiscard]]
|
||||||
NewImage.pvt_Sections.ByIndex[NewImage.pvt_Sections.ByIndex.size()] = §ion_p[j];
|
const section_64* X64ImageInterpreter::ImageSection(size_t Index) const {
|
||||||
NewImage.pvt_Sections.ByMapAddress[section_p[j].addr] = §ion_p[j];
|
if (Index < m_Sections.size()) {
|
||||||
NewImage.pvt_Sections.ByFileOffset[section_p[j].offset] = §ion_p[j];
|
return m_Sections[Index];
|
||||||
|
} else {
|
||||||
|
throw ARL::IndexError(__FILE__, __LINE__, "X64ImageInterpreter: Index is out of range.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const section_64* X64ImageInterpreter::ImageSection(const char* SegmentName, const char* SectionName) const {
|
||||||
|
for (const auto& segment : m_Segments) {
|
||||||
|
if (strncmp(SegmentName, segment->segname, sizeof(segment->segname)) == 0) {
|
||||||
|
auto section = reinterpret_cast<const section_64*>(segment + 1);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < segment->nsects; ++i) {
|
||||||
|
if (strncmp(SectionName, section[i].sectname, sizeof(section[i].sectname)) == 0) {
|
||||||
|
return §ion[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LC_DYSYMTAB: {
|
|
||||||
NewImage.pvt_DynamicSymbol.SegmentCommand = reinterpret_cast<dysymtab_command*>(cmd_p);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LC_SYMTAB: {
|
|
||||||
NewImage.pvt_Symbol.SegmentCommand = reinterpret_cast<symtab_command*>(cmd_p);
|
|
||||||
NewImage.pvt_Symbol.StringTable = NewImage.ImageOffset<char*>(NewImage.pvt_Symbol.SegmentCommand->stroff);
|
|
||||||
NewImage.pvt_Symbol.SymbolTable = NewImage.ImageOffset<nlist_64*>(NewImage.pvt_Symbol.SegmentCommand->symoff);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LC_DYLD_INFO_ONLY: { // NOLINT
|
|
||||||
NewImage.pvt_DynamicLoaderInfoOnly.SegmentCommand = reinterpret_cast<dyld_info_command*>(cmd_p);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_p = reinterpret_cast<load_command*>(
|
throw ARL::KeyError(__FILE__, __LINE__, "X64ImageInterpreter: section is not found.");
|
||||||
reinterpret_cast<uint8_t*>(cmd_p) + cmd_p->cmdsize
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewImage;
|
[[nodiscard]]
|
||||||
}
|
const section_64* X64ImageInterpreter::ImageSectionFromOffset(X64ImageOffset Offset) const {
|
||||||
|
auto it = m_SectionsOffsetMap.upper_bound(Offset);
|
||||||
[[nodiscard]]
|
if (it != m_SectionsOffsetMap.begin() && (--it, it->first <= Offset && Offset < it->first + it->second->size)) {
|
||||||
size_t X64ImageInterpreter::NumberOfSections() const noexcept {
|
return it->second;
|
||||||
return pvt_Sections.ByIndex.size();
|
} else {
|
||||||
}
|
throw ARL::KeyError(__FILE__, __LINE__, "X64ImageInterpreter: section is not found.");
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
section_64* X64ImageInterpreter::ImageSection(size_t Index) const {
|
|
||||||
auto it = pvt_Sections.ByIndex.find(Index);
|
|
||||||
if (it != pvt_Sections.ByIndex.cend()) {
|
|
||||||
return it->second;
|
|
||||||
} else {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Section is not found.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
section_64* X64ImageInterpreter::ImageSection(const char* SegmentName, const char* SectionName) const {
|
|
||||||
for (auto segcmd_p : pvt_SegmentCommands) {
|
|
||||||
if (strncmp(SegmentName, segcmd_p->segname, sizeof(segcmd_p->segname)) == 0) {
|
|
||||||
auto sec_p = reinterpret_cast<section_64*>(segcmd_p + 1);
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < segcmd_p->nsects; ++i) {
|
|
||||||
if (strncmp(SectionName, sec_p[i].sectname, sizeof(sec_p[i].sectname)) == 0)
|
|
||||||
return &sec_p[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
[[nodiscard]]
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Section is not found.");
|
const section_64* X64ImageInterpreter::ImageSectionFromRva(X64ImageAddress Rva) const {
|
||||||
}
|
auto it = m_SectionsAddressMap.upper_bound(Rva);
|
||||||
|
if (it != m_SectionsAddressMap.begin() && (--it, it->first <= Rva && Rva < it->first + it->second->size)) {
|
||||||
[[nodiscard]]
|
return it->second;
|
||||||
section_64* X64ImageInterpreter::ImageSectionByOffset(uint32_t Offset) const {
|
} else {
|
||||||
for (const auto& it : pvt_Sections.ByFileOffset) {
|
throw ARL::KeyError(__FILE__, __LINE__, "X64ImageInterpreter: section is not found.");
|
||||||
if (it.first <= Offset && Offset < it.first + it.second->size) {
|
|
||||||
return it.second;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
[[nodiscard]]
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Section is not found.");
|
X64ImageAddress X64ImageInterpreter::ConvertOffsetToRva(X64ImageOffset Offset) const {
|
||||||
}
|
auto section = ImageSectionFromOffset(Offset);
|
||||||
|
return section->addr + static_cast<X64ImageAddress>(Offset - section->offset);
|
||||||
[[nodiscard]]
|
}
|
||||||
section_64* X64ImageInterpreter::ImageSectionByRva(uint64_t Rva) const {
|
|
||||||
for (const auto& it : pvt_Sections.ByMapAddress) {
|
[[nodiscard]]
|
||||||
if (it.first <= Rva && Rva < it.first + it.second->size) {
|
X64ImageOffset X64ImageInterpreter::ConvertRvaToOffset(X64ImageAddress Rva) const {
|
||||||
return it.second;
|
auto section = ImageSectionFromRva(Rva);
|
||||||
}
|
return section->offset + static_cast<X64ImageOffset>(Rva - section->addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Section is not found.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
uint64_t X64ImageInterpreter::OffsetToRva(uint32_t Offset) const {
|
|
||||||
auto section = ImageSectionByOffset(Offset);
|
|
||||||
return section->addr + (Offset - section->offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
uint32_t X64ImageInterpreter::RvaToOffset(uint64_t Rva) const {
|
|
||||||
auto section = ImageSectionByRva(Rva);
|
|
||||||
return section->offset + (Rva - section->addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
nlist_64* X64ImageInterpreter::ImageSymbolTable() const noexcept {
|
|
||||||
return pvt_Symbol.SymbolTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,199 +1,222 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string.h> // NOLINT
|
|
||||||
#include <mach-o/loader.h>
|
#include <mach-o/loader.h>
|
||||||
#include <mach-o/nlist.h>
|
#include <mach-o/nlist.h>
|
||||||
|
#include <string.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "../common/Exception.hpp"
|
#include "Exception.hpp"
|
||||||
|
#include "ExceptionGeneric.hpp"
|
||||||
|
#include "MemoryAccess.hpp"
|
||||||
|
|
||||||
class X64ImageInterpreter {
|
namespace nkg {
|
||||||
public:
|
|
||||||
static constexpr uint64_t InvalidAddress = static_cast<uint64_t>(-1);
|
|
||||||
static constexpr uint32_t InvalidOffset = static_cast<uint32_t>(-1);
|
|
||||||
private:
|
|
||||||
|
|
||||||
mach_header_64* pvt_MachHeader;
|
using X64ImageAddress = decltype(section_64::addr);
|
||||||
std::vector<segment_command_64*> pvt_SegmentCommands;
|
using X64ImageOffset = decltype(section_64::offset);
|
||||||
|
|
||||||
struct {
|
class X64ImageInterpreter {
|
||||||
std::map<size_t, section_64*> ByIndex;
|
private:
|
||||||
std::map<uint64_t, section_64*> ByMapAddress;
|
|
||||||
std::map<uint32_t, section_64*> ByFileOffset;
|
|
||||||
} pvt_Sections;
|
|
||||||
|
|
||||||
struct {
|
size_t m_MachOSize;
|
||||||
dysymtab_command* SegmentCommand;
|
const mach_header_64* m_MachOHeader;
|
||||||
} pvt_DynamicSymbol;
|
std::vector<const segment_command_64*> m_Segments;
|
||||||
|
std::vector<const section_64*> m_Sections;
|
||||||
|
std::map<X64ImageAddress, const section_64*> m_SectionsAddressMap;
|
||||||
|
std::map<X64ImageOffset, const section_64*> m_SectionsOffsetMap;
|
||||||
|
struct {
|
||||||
|
const dysymtab_command* dysymtab;
|
||||||
|
const symtab_command* symtab;
|
||||||
|
const dyld_info_command* dyld_info;
|
||||||
|
} m_SpecialLoadCommands;
|
||||||
|
|
||||||
struct {
|
X64ImageInterpreter() :
|
||||||
symtab_command* SegmentCommand;
|
m_MachOSize(0),
|
||||||
char* StringTable;
|
m_MachOHeader(nullptr),
|
||||||
nlist_64* SymbolTable;
|
m_SpecialLoadCommands{} {}
|
||||||
} pvt_Symbol;
|
|
||||||
|
|
||||||
struct {
|
public:
|
||||||
dyld_info_command* SegmentCommand;
|
|
||||||
} pvt_DynamicLoaderInfoOnly;
|
|
||||||
|
|
||||||
X64ImageInterpreter() :
|
[[nodiscard]]
|
||||||
pvt_MachHeader(nullptr),
|
static X64ImageInterpreter Parse(const void* lpImage, size_t cbImage);
|
||||||
pvt_DynamicSymbol{},
|
|
||||||
pvt_Symbol{},
|
|
||||||
pvt_DynamicLoaderInfoOnly{} {}
|
|
||||||
|
|
||||||
public:
|
template<typename __ReturnType = void*>
|
||||||
|
[[nodiscard]]
|
||||||
[[nodiscard]]
|
__ReturnType ImageBase() const noexcept {
|
||||||
static X64ImageInterpreter Parse(void* ImageBase);
|
static_assert(std::is_pointer_v<__ReturnType>);
|
||||||
|
return reinterpret_cast<__ReturnType>(
|
||||||
template<typename __ReturnType = void*>
|
const_cast<mach_header_64*>(m_MachOHeader)
|
||||||
[[nodiscard]]
|
);
|
||||||
__ReturnType ImageBase() const noexcept {
|
|
||||||
static_assert(std::is_pointer_v<__ReturnType>);
|
|
||||||
return reinterpret_cast<__ReturnType>(pvt_MachHeader);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __ReturnType = void*>
|
|
||||||
[[nodiscard]]
|
|
||||||
__ReturnType ImageOffset(size_t Offset) const noexcept {
|
|
||||||
static_assert(std::is_pointer_v<__ReturnType>);
|
|
||||||
return reinterpret_cast<__ReturnType>(
|
|
||||||
reinterpret_cast<uint8_t*>(pvt_MachHeader) + Offset
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned __CommandMacro>
|
|
||||||
[[nodiscard]]
|
|
||||||
auto CommandOf() const noexcept {
|
|
||||||
if constexpr (__CommandMacro == LC_DYSYMTAB) {
|
|
||||||
return pvt_DynamicSymbol.SegmentCommand;
|
|
||||||
} else if constexpr (__CommandMacro == LC_SYMTAB) {
|
|
||||||
return pvt_Symbol.SegmentCommand;
|
|
||||||
} else if constexpr (__CommandMacro == LC_DYLD_INFO_ONLY) { // NOLINT
|
|
||||||
return pvt_DynamicLoaderInfoOnly.SegmentCommand;
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
template<typename __ReturnType = void*>
|
||||||
size_t NumberOfSections() const noexcept;
|
[[nodiscard]]
|
||||||
|
__ReturnType ImageOffset(size_t Offset) const {
|
||||||
[[nodiscard]]
|
if (Offset < m_MachOSize) {
|
||||||
section_64* ImageSection(size_t Index) const;
|
return ARL::AddressOffsetWithCast<__ReturnType>(m_MachOHeader, Offset);
|
||||||
|
} else {
|
||||||
[[nodiscard]]
|
throw ARL::OverflowError(__FILE__, __LINE__, "X64ImageInterpreter: out of range.");
|
||||||
section_64* ImageSection(const char* SegmentName, const char* SectionName) const;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
section_64* ImageSectionByOffset(uint32_t Offset) const;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
section_64* ImageSectionByRva(uint64_t Rva) const;
|
|
||||||
|
|
||||||
template<typename __ReturnType>
|
|
||||||
[[nodiscard]]
|
|
||||||
__ReturnType SectionView(size_t Index) const {
|
|
||||||
auto Section = ImageSection(Index);
|
|
||||||
return ImageOffset<__ReturnType>(Section->offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __ReturnType>
|
|
||||||
[[nodiscard]]
|
|
||||||
__ReturnType SectionView(const char* SegmentName, const char* SectionName) const {
|
|
||||||
auto Section = ImageSection(SegmentName, SectionName);
|
|
||||||
return ImageOffset<__ReturnType>(Section->offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __ReturnType>
|
|
||||||
[[nodiscard]]
|
|
||||||
__ReturnType SectionView(section_64* Section) const {
|
|
||||||
return ImageOffset<__ReturnType>(Section->offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __ReturnType, typename __Hint>
|
|
||||||
[[nodiscard]]
|
|
||||||
__ReturnType SearchSection(size_t Index, __Hint&& Hint) const {
|
|
||||||
return SearchSection<__ReturnType>(ImageSection(Index), std::forward<__Hint>(Hint));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __ReturnType, typename __Hint>
|
|
||||||
[[nodiscard]]
|
|
||||||
__ReturnType SearchSection(const char* SegmentName, const char* SectionName, __Hint&& Hint) const {
|
|
||||||
return SearchSection<__ReturnType>(ImageSection(SegmentName, SectionName), std::forward<__Hint>(Hint));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __ReturnType, typename __Hint>
|
|
||||||
[[nodiscard]]
|
|
||||||
__ReturnType SearchSection(section_64* Section, __Hint&& Hint) const {
|
|
||||||
static_assert(std::is_pointer_v<__ReturnType>);
|
|
||||||
|
|
||||||
auto begin = SectionView<const uint8_t*>(Section);
|
|
||||||
auto end = begin + Section->size;
|
|
||||||
|
|
||||||
for (; begin < end; ++begin) {
|
|
||||||
if (Hint(begin) == true) {
|
|
||||||
return reinterpret_cast<__ReturnType>(const_cast<uint8_t*>(begin));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
[[nodiscard]]
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Data is not found.");
|
size_t ImageSize() const noexcept {
|
||||||
}
|
return m_MachOSize;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename __Hint>
|
[[nodiscard]]
|
||||||
[[nodiscard]]
|
size_t NumberOfSegmentCommands() const noexcept;
|
||||||
uint32_t SearchSectionOffset(size_t Index, __Hint&& Hint) const {
|
|
||||||
return SearchSection<uint8_t*>(Index, std::forward<__Hint>(Hint)) - ImageBase<uint8_t*>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __Hint>
|
[[nodiscard]]
|
||||||
[[nodiscard]]
|
size_t NumberOfSections() const noexcept;
|
||||||
uint32_t SearchSectionOffset(const char* SegmentName, const char* SectionName, __Hint&& Hint) const {
|
|
||||||
return SearchSection<uint8_t*>(SegmentName, SectionName, std::forward<__Hint>(Hint)) - ImageBase<uint8_t*>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __Hint>
|
[[nodiscard]]
|
||||||
[[nodiscard]]
|
const section_64* ImageSection(size_t Index) const;
|
||||||
uint32_t SearchSectionOffset(section_64* Section, __Hint&& Hint) const {
|
|
||||||
return SearchSection<uint8_t*>(Section, std::forward<__Hint>(Hint)) - ImageBase<uint8_t*>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __Hint>
|
[[nodiscard]]
|
||||||
[[nodiscard]]
|
const section_64* ImageSection(const char* SegmentName, const char* SectionName) const;
|
||||||
uint64_t SearchSectionRva(size_t Index, __Hint&& Hint) const {
|
|
||||||
auto Section = ImageSection(Index);
|
|
||||||
auto Offset = SearchSection<uint8_t*>(Section, std::forward<__Hint>(Hint)) - SectionView<uint8_t*>(Section);
|
|
||||||
return Section->addr + Offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __Hint>
|
[[nodiscard]]
|
||||||
[[nodiscard]]
|
const section_64* ImageSectionFromOffset(X64ImageOffset Offset) const;
|
||||||
uint64_t SearchSectionRva(const char* SegmentName, const char* SectionName, __Hint&& Hint) const {
|
|
||||||
auto Section = ImageSection(SegmentName, SectionName);
|
|
||||||
auto Offset = SearchSection<uint8_t*>(Section, std::forward<__Hint>(Hint)) - SectionView<uint8_t*>(Section);
|
|
||||||
return Section->addr + Offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __Hint>
|
[[nodiscard]]
|
||||||
[[nodiscard]]
|
const section_64* ImageSectionFromRva(X64ImageAddress Rva) const;
|
||||||
uint64_t SearchSectionRva(section_64* Section, __Hint&& Hint) const {
|
|
||||||
auto Offset = SearchSection<uint8_t*>(Section, std::forward<__Hint>(Hint)) - SectionView<uint8_t*>(Section);
|
|
||||||
return Section->addr + Offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
uint64_t OffsetToRva(uint32_t Offset) const;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
uint32_t RvaToOffset(uint64_t Address) const;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
template<typename __ReturnType = void*>
|
||||||
nlist_64* ImageSymbolTable() const noexcept;
|
[[nodiscard]]
|
||||||
|
__ReturnType ImageSectionView(const section_64* Section) const noexcept {
|
||||||
|
return ImageOffset<__ReturnType>(Section->offset);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
template<typename __ReturnType = void*>
|
||||||
char* LookupStringTable(size_t Offset) const noexcept {
|
[[nodiscard]]
|
||||||
return pvt_Symbol.StringTable + Offset;
|
__ReturnType ImageSectionView(size_t Index) const {
|
||||||
}
|
return ImageSectionView<__ReturnType>(ImageSection(Index));
|
||||||
};
|
}
|
||||||
|
|
||||||
|
template<typename __ReturnType = void*>
|
||||||
|
[[nodiscard]]
|
||||||
|
__ReturnType ImageSectionView(const char* SegmentName, const char* SectionName) const {
|
||||||
|
return ImageSectionView<__ReturnType>(ImageSection(SegmentName, SectionName));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned __CommandMacro>
|
||||||
|
[[nodiscard]]
|
||||||
|
auto SpecialLoadCommand() const noexcept {
|
||||||
|
if constexpr (__CommandMacro == LC_DYSYMTAB) {
|
||||||
|
return m_SpecialLoadCommands.dysymtab;
|
||||||
|
} else if constexpr (__CommandMacro == LC_SYMTAB) {
|
||||||
|
return m_SpecialLoadCommands.symtab;
|
||||||
|
} else if constexpr (__CommandMacro == LC_DYLD_INFO_ONLY) {
|
||||||
|
return m_SpecialLoadCommands.dyld_info;
|
||||||
|
} else {
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wtautological-compare"
|
||||||
|
constexpr bool always_false = __CommandMacro != __CommandMacro;
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
static_assert(always_false);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __ReturnType = void*, typename __HintType>
|
||||||
|
[[nodiscard]]
|
||||||
|
__ReturnType SearchSection(const section_64* Section, __HintType&& Hint) const {
|
||||||
|
static_assert(std::is_pointer_v<__ReturnType>);
|
||||||
|
|
||||||
|
auto base = ImageSectionView<const uint8_t*>(Section);
|
||||||
|
|
||||||
|
for (decltype(section_64::size) i = 0; i < Section->size; ++i) {
|
||||||
|
if (Hint(base, i, Section->size) == true) {
|
||||||
|
return ARL::AddressOffsetWithCast<__ReturnType>(base, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __ReturnType = void*, typename __HintType>
|
||||||
|
[[nodiscard]]
|
||||||
|
__ReturnType SearchSection(const section_64* Section, size_t Offset, __HintType&& Hint) const {
|
||||||
|
static_assert(std::is_pointer_v<__ReturnType>);
|
||||||
|
|
||||||
|
auto base = ImageSectionView<const uint8_t*>(Section);
|
||||||
|
|
||||||
|
for (decltype(section_64::size) i = Offset; i < Section->size; ++i) {
|
||||||
|
if (Hint(base, i, Section->size) == true) {
|
||||||
|
return ARL::AddressOffsetWithCast<__ReturnType>(base, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __ReturnType = void*, typename __HintType>
|
||||||
|
[[nodiscard]]
|
||||||
|
__ReturnType SearchSection(size_t Index, __HintType&& Hint) const {
|
||||||
|
return SearchSection<__ReturnType>(ImageSection(Index), std::forward<__HintType>(Hint));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __ReturnType = void*, typename __HintType>
|
||||||
|
[[nodiscard]]
|
||||||
|
__ReturnType SearchSection(size_t Index, size_t Offset, __HintType&& Hint) const {
|
||||||
|
return SearchSection<__ReturnType>(ImageSection(Index), Offset, std::forward<__HintType>(Hint));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __ReturnType = void*, typename __HintType>
|
||||||
|
[[nodiscard]]
|
||||||
|
__ReturnType SearchSection(const char* SegmentName, const char* SectionName, __HintType&& Hint) const {
|
||||||
|
return SearchSection<__ReturnType>(ImageSection(SegmentName, SectionName), std::forward<__HintType>(Hint));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __ReturnType = void*, typename __HintType>
|
||||||
|
[[nodiscard]]
|
||||||
|
__ReturnType SearchSection(const char* SegmentName, const char* SectionName, size_t Offset, __HintType&& Hint) const {
|
||||||
|
return SearchSection<__ReturnType>(ImageSection(SegmentName, SectionName), Offset, std::forward<__HintType>(Hint));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
X64ImageAddress ConvertOffsetToRva(X64ImageOffset Offset) const;
|
||||||
|
|
||||||
|
template<typename __ReturnType = void*>
|
||||||
|
[[nodiscard]]
|
||||||
|
__ReturnType ConvertOffsetToPtr(X64ImageOffset Offset) const {
|
||||||
|
return ImageOffset<__ReturnType>(Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
X64ImageOffset ConvertRvaToOffset(X64ImageAddress Address) const;
|
||||||
|
|
||||||
|
template<typename __ReturnType = void*>
|
||||||
|
[[nodiscard]]
|
||||||
|
__ReturnType ConvertRvaToPtr(X64ImageAddress Rva) const {
|
||||||
|
return ConvertOffsetToPtr<__ReturnType>(ConvertRvaToOffset(Rva));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __PtrType>
|
||||||
|
[[nodiscard]]
|
||||||
|
X64ImageAddress ConvertPtrToRva(__PtrType Ptr) const {
|
||||||
|
auto offset = ARL::AddressDelta(Ptr, m_MachOHeader);
|
||||||
|
if (offset < m_MachOSize) {
|
||||||
|
return ConvertOffsetToRva(offset);
|
||||||
|
} else {
|
||||||
|
throw ARL::OverflowError(__FILE__, __LINE__, "X64ImageInterpreter: out of range.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __PtrType>
|
||||||
|
[[nodiscard]]
|
||||||
|
X64ImageAddress ConvertPtrToOffset(__PtrType Ptr) const {
|
||||||
|
auto offset = ARL::AddressDelta(Ptr, m_MachOHeader);
|
||||||
|
if (offset < m_MachOSize) {
|
||||||
|
return offset;
|
||||||
|
} else {
|
||||||
|
throw ARL::OverflowError(__FILE__, __LINE__, "X64ImageInterpreter: out of range.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -4,254 +4,381 @@
|
|||||||
#include <plist/plist++.h>
|
#include <plist/plist++.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "../common/ExceptionSystem.hpp"
|
#include "ExceptionSystem.hpp"
|
||||||
#include "../common/ResourceOwned.hpp"
|
#include "ResourceWrapper.hpp"
|
||||||
#include "ResourceTraitsUnix.hpp"
|
#include "ResourceTraitsUnix.hpp"
|
||||||
#include "PatchSolutions.hpp"
|
#include "PatchSolutions.hpp"
|
||||||
|
#include "Misc.hpp"
|
||||||
|
|
||||||
static void Welcome() {
|
static void Welcome(bool bWait) {
|
||||||
puts("***************************************************");
|
puts("**********************************************************");
|
||||||
puts("* Navicat Patcher by @DoubleLabyrinth *");
|
puts("* Navicat Patcher (macOS) by @DoubleLabyrinth *");
|
||||||
puts("* Version: 4.0 *");
|
puts("* Version: 5.0 *");
|
||||||
puts("***************************************************");
|
puts("**********************************************************");
|
||||||
puts("");
|
puts("");
|
||||||
puts("Press Enter to continue or Ctrl + C to abort.");
|
if (bWait) {
|
||||||
getchar();
|
puts("Press Enter to continue or Ctrl + C to abort.");
|
||||||
|
getchar();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Help() {
|
static void Help() {
|
||||||
puts("***************************************************");
|
|
||||||
puts("* Navicat Patcher by @DoubleLabyrinth *");
|
|
||||||
puts("* Version: 4.0 *");
|
|
||||||
puts("***************************************************");
|
|
||||||
puts("");
|
|
||||||
puts("Usage:");
|
puts("Usage:");
|
||||||
puts(" navicat-patcher <Navicat installation path> [RSA-2048 Private Key File]");
|
puts(" navicat-patcher [--dry-run] <Navicat installation path> [RSA-2048 Private Key File]");
|
||||||
puts("");
|
puts("");
|
||||||
puts(" <Navicat installation path> Path to `Navicat Premium.app`.");
|
puts(" [--dry-run] Run patcher without applying any patches.");
|
||||||
puts(" Example:");
|
puts(" This parameter is optional.");
|
||||||
puts(" /Applications/Navicat\\ Premium.app/");
|
|
||||||
puts(" This parameter must be specified.");
|
|
||||||
puts("");
|
puts("");
|
||||||
puts(" [RSA-2048 Private Key File] Path to a PEM-format RSA-2048 private key file.");
|
puts(" <Navicat installation path> Path to `Navicat Premium.app`.");
|
||||||
puts(" This parameter is optional.");
|
puts(" Example:");
|
||||||
|
puts(" /Applications/Navicat\\ Premium.app/");
|
||||||
|
puts(" This parameter must be specified.");
|
||||||
|
puts("");
|
||||||
|
puts(" [RSA-2048 Private Key File] Path to a PEM-format RSA-2048 private key file.");
|
||||||
|
puts(" This parameter is optional.");
|
||||||
puts("");
|
puts("");
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetNavicatVersion(const char* AppPath) {
|
static bool ParseCommandLine(int argc, char* argv[], bool& bDryrun, std::string& szInstallPath, std::string& szKeyFilePath) {
|
||||||
ResourceOwned hInfoPlist(FileHandleTraits{});
|
if (argc == 2) {
|
||||||
ResourceOwned InfoPlist(CppObjectTraits<PList::Dictionary>{});
|
bDryrun = false;
|
||||||
|
szInstallPath = argv[1];
|
||||||
|
szKeyFilePath.clear();
|
||||||
|
return true;
|
||||||
|
} else if (argc == 3) {
|
||||||
|
if (strcasecmp(argv[1], "--dry-run") == 0) {
|
||||||
|
bDryrun = true;
|
||||||
|
szInstallPath = argv[2];
|
||||||
|
szKeyFilePath.clear();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
bDryrun = false;
|
||||||
|
szInstallPath = argv[1];
|
||||||
|
szKeyFilePath = argv[2];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (argc == 4) {
|
||||||
|
if (strcasecmp(argv[1], "--dry-run") == 0) {
|
||||||
|
bDryrun = true;
|
||||||
|
szInstallPath = argv[2];
|
||||||
|
szKeyFilePath = argv[3];
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string GetNavicatVersion(std::string_view AppPath) {
|
||||||
|
ARL::ResourceWrapper hInfoPlist{ ARL::ResourceTraits::FileDescriptor{} };
|
||||||
|
ARL::ResourceWrapper lpInfoPlist{ ARL::ResourceTraits::CppObject<PList::Dictionary>{} };
|
||||||
|
|
||||||
hInfoPlist.TakeOver(open((std::string(AppPath) + "/Contents/Info.plist").c_str(), O_RDONLY));
|
hInfoPlist.TakeOver(open((std::string(AppPath) + "/Contents/Info.plist").c_str(), O_RDONLY));
|
||||||
if (hInfoPlist.IsValid() == false) {
|
if (hInfoPlist.IsValid() == false) {
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
throw ARL::SystemError(__FILE__, __LINE__, errno, "Failed to open Contents/Info.plist.");
|
||||||
throw nkg::SystemError(__FILE__, __LINE__, errno, "Failed to open Contents/Info.plist.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct stat statInfoPlist = {};
|
struct stat statInfoPlist = {};
|
||||||
if (fstat(hInfoPlist, &statInfoPlist) != 0) {
|
if (fstat(hInfoPlist, &statInfoPlist) != 0) {
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
throw ARL::SystemError(__FILE__, __LINE__, errno, "Failed to get file size of Contents/Info.plist.");
|
||||||
throw nkg::SystemError(__FILE__, __LINE__, errno, "Failed to get file size of Contents/Info.plist.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string contentInfoPlist(statInfoPlist.st_size, '\x00');
|
std::string contentInfoPlist(statInfoPlist.st_size, '\x00');
|
||||||
if (read(hInfoPlist, contentInfoPlist.data(), contentInfoPlist.size()) != contentInfoPlist.size()) {
|
if (read(hInfoPlist, contentInfoPlist.data(), contentInfoPlist.size()) != contentInfoPlist.size()) {
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
throw ARL::SystemError(__FILE__, __LINE__, errno, "Failed to read Contents/Info.plist.");
|
||||||
throw nkg::SystemError(__FILE__, __LINE__, errno, "Failed to read Contents/Info.plist.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InfoPlist.TakeOver(dynamic_cast<PList::Dictionary*>(PList::Structure::FromXml(contentInfoPlist)));
|
lpInfoPlist.TakeOver(dynamic_cast<PList::Dictionary*>(PList::Structure::FromXml(contentInfoPlist)));
|
||||||
if (InfoPlist.IsValid() == false) {
|
if (lpInfoPlist.IsValid() == false) {
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
throw ARL::Exception(__FILE__, __LINE__, "Failed to parse Contents/Info.plist.");
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Failed to parse Contents/Info.plist.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto kv = InfoPlist->Find("CFBundleShortVersionString");
|
auto key_value = lpInfoPlist->Find("CFBundleShortVersionString");
|
||||||
if (kv == InfoPlist->End()) {
|
if (key_value == lpInfoPlist->End()) {
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
throw ARL::Exception(__FILE__, __LINE__, "Cannot find CFBundleShortVersionString in Contents/Info.plist.");
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Cannot find CFBundleShortVersionString in Contents/Info.plist.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kv->second->GetType() == PLIST_STRING) {
|
if (key_value->second->GetType() == PLIST_STRING) {
|
||||||
return dynamic_cast<PList::String*>(kv->second)->GetValue();
|
return dynamic_cast<PList::String*>(key_value->second)->GetValue();
|
||||||
} else {
|
} else {
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
throw ARL::Exception(__FILE__, __LINE__, "Type check failed for CFBundleShortVersionString.");
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "Failed to get Navicat version.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LoadKey(RSACipher& RsaCipher, const char* RsaKeyFileName,
|
static void LoadKey(nkg::RSACipher& Cipher, std::string_view szKeyFileName,
|
||||||
PatchSolution* lpSolution0,
|
nkg::PatchSolution* lpSolution0,
|
||||||
PatchSolution* lpSolution1,
|
nkg::PatchSolution* lpSolution1,
|
||||||
PatchSolution* lpSolution2) {
|
nkg::PatchSolution* lpSolution2) {
|
||||||
if (RsaKeyFileName) {
|
if (szKeyFileName.empty() == false) {
|
||||||
RsaCipher.ImportKeyFromFile<RSAKeyType::PrivateKey, RSAKeyFormat::PEM>(RsaKeyFileName);
|
printf("[*] Import RSA-2048 key from %s\n", szKeyFileName.data());
|
||||||
|
|
||||||
if ((lpSolution0 && !lpSolution0->CheckKey(RsaCipher)) ||
|
Cipher.ImportKeyFromFile<nkg::RSAKeyType::PrivateKey, nkg::RSAKeyFormat::PEM>(szKeyFileName);
|
||||||
(lpSolution1 && !lpSolution1->CheckKey(RsaCipher)) ||
|
|
||||||
(lpSolution2 && !lpSolution2->CheckKey(RsaCipher)))
|
if ((lpSolution0 && lpSolution0->CheckKey(Cipher) == false) ||
|
||||||
|
(lpSolution1 && lpSolution1->CheckKey(Cipher) == false) ||
|
||||||
|
(lpSolution2 && lpSolution2->CheckKey(Cipher) == false))
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
throw ARL::Exception(__FILE__, __LINE__, "The RSA private key you provide cannot be used.");
|
||||||
throw nkg::Exception(__FILE__, __LINE__, "The RSA private key you provide cannot be used.");
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
puts("");
|
|
||||||
puts("[*] Generating new RSA private key, it may take a long time...");
|
puts("[*] Generating new RSA private key, it may take a long time...");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
RsaCipher.GenerateKey(2048);
|
Cipher.GenerateKey(2048);
|
||||||
} while ((lpSolution0 && !lpSolution0->CheckKey(RsaCipher)) ||
|
} while ((lpSolution0 && lpSolution0->CheckKey(Cipher) == false) ||
|
||||||
(lpSolution1 && !lpSolution1->CheckKey(RsaCipher)) ||
|
(lpSolution1 && lpSolution1->CheckKey(Cipher) == false) ||
|
||||||
(lpSolution2 && !lpSolution2->CheckKey(RsaCipher))); // re-generate RSA key if CheckKey return false
|
(lpSolution2 && lpSolution2->CheckKey(Cipher) == false)); // re-generate RSA key if CheckKey return false
|
||||||
|
|
||||||
RsaCipher.ExportKeyToFile<RSAKeyType::PrivateKey, RSAKeyFormat::PEM>("RegPrivateKey.pem");
|
|
||||||
|
|
||||||
puts("[+] New RSA private key has been saved to RegPrivateKey.pem.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PublicKeyPEM = RsaCipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
|
printf("[*] Your RSA private key:\n");
|
||||||
puts("");
|
printf(" %s\n",
|
||||||
puts("[*] Your RSA public key:");
|
[&Cipher]() -> std::string {
|
||||||
puts(PublicKeyPEM.c_str());
|
auto szPrivateKey = Cipher.ExportKeyString<nkg::RSAKeyType::PrivateKey, nkg::RSAKeyFormat::PEM>();
|
||||||
|
for (size_t pos = 0; (pos = szPrivateKey.find('\n', pos)) != std::string::npos; pos += strlen("\n ")) {
|
||||||
|
szPrivateKey.replace(pos, 1, "\n ");
|
||||||
|
}
|
||||||
|
return szPrivateKey;
|
||||||
|
}().c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
printf("[*] Your RSA public key:\n");
|
||||||
|
printf(" %s\n",
|
||||||
|
[&Cipher]() -> std::string {
|
||||||
|
auto szPublicKey = Cipher.ExportKeyString<nkg::RSAKeyType::PublicKey, nkg::RSAKeyFormat::PEM>();
|
||||||
|
for (size_t pos = 0; (pos = szPublicKey.find('\n', pos)) != std::string::npos; pos += strlen("\n ")) {
|
||||||
|
szPublicKey.replace(pos, 1, "\n ");
|
||||||
|
}
|
||||||
|
return szPublicKey;
|
||||||
|
}().c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
if (argc != 2 && argc != 3) {
|
bool bDryrun;
|
||||||
|
std::string szInstallPath;
|
||||||
|
std::string szKeyFilePath;
|
||||||
|
|
||||||
|
if (ParseCommandLine(argc, argv, bDryrun, szInstallPath, szKeyFilePath) == false) {
|
||||||
|
Welcome(false);
|
||||||
Help();
|
Help();
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
Welcome();
|
Welcome(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
RSACipher RsaCipher;
|
if (nkg::Misc::FsIsDirectory(szInstallPath) == false) {
|
||||||
ResourceOwned Solution0(CppObjectTraits<PatchSolution>{});
|
throw ARL::Exception(__FILE__, __LINE__, "Navicat installation path doesn't point to a directory.")
|
||||||
ResourceOwned Solution1(CppObjectTraits<PatchSolution>{});
|
.PushHint("Are you sure the path you specified is correct?")
|
||||||
ResourceOwned Solution2(CppObjectTraits<PatchSolution>{});
|
.PushFormatHint("The path you specified: %s", szInstallPath.c_str());
|
||||||
|
|
||||||
ResourceOwned hMainApp(FileHandleTraits{}, open((std::string(argv[1]) + "/Contents/MacOS/Navicat Premium").c_str(), O_RDWR));
|
|
||||||
if (hMainApp.IsValid() == false) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::SystemError(__FILE__, __LINE__, errno, "open failed.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct stat statMainApp = {};
|
if (szKeyFilePath.empty() == false && nkg::Misc::FsIsFile(szKeyFilePath) == false) {
|
||||||
if (fstat(hMainApp, &statMainApp) != 0) {
|
throw ARL::Exception(__FILE__, __LINE__, "RSA key file path doesn't point to a file.")
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
.PushHint("Are you sure the path you specified is correct?")
|
||||||
throw nkg::SystemError(__FILE__, __LINE__, errno, "fstat failed.");
|
.PushFormatHint("The path you specified: %s", szKeyFilePath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceOwned lpMainApp(MapViewTraits{},
|
while (szInstallPath.back() == '/') {
|
||||||
mmap(nullptr, static_cast<size_t>(statMainApp.st_size), PROT_READ | PROT_WRITE, MAP_SHARED, hMainApp, 0),
|
szInstallPath.pop_back();
|
||||||
[&statMainApp](void* p) { munmap(p, statMainApp.st_size); }
|
|
||||||
);
|
|
||||||
if (lpMainApp.IsValid() == false) {
|
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
|
||||||
throw nkg::SystemError(__FILE__, __LINE__, errno, "mmap failed.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Ver0, Ver1, Ver2;
|
nkg::RSACipher Cipher;
|
||||||
if (sscanf(GetNavicatVersion(argv[1]).c_str(), "%d.%d.%d", &Ver0, &Ver1, &Ver2) != 3) { // NOLINT
|
ARL::ResourceWrapper lpSolution0{ ARL::ResourceTraits::CppObject<nkg::PatchSolution>{} };
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
ARL::ResourceWrapper lpSolution1{ ARL::ResourceTraits::CppObject<nkg::PatchSolution>{} };
|
||||||
throw nkg::SystemError(__FILE__, __LINE__, errno, "Failed to get version of Navicat.");
|
ARL::ResourceWrapper lpSolution2{ ARL::ResourceTraits::CppObject<nkg::PatchSolution>{} };
|
||||||
}
|
|
||||||
|
|
||||||
X64ImageInterpreter MainApp = X64ImageInterpreter::Parse(lpMainApp);
|
std::string main_path;
|
||||||
|
ARL::ResourceWrapper main_fd{ ARL::ResourceTraits::FileDescriptor{} };
|
||||||
|
ARL::ResourceWrapper main_stat{ ARL::ResourceTraits::CppObject<struct stat>{} };
|
||||||
|
ARL::ResourceWrapperEx main_mmap{ ARL::ResourceTraits::MapView{}, [&main_stat](void* p) {
|
||||||
|
if (munmap(p, main_stat->st_size) < 0) {
|
||||||
|
throw ARL::SystemError(__FILE__, __LINE__, errno, "munmap failed.");
|
||||||
|
}
|
||||||
|
} };
|
||||||
|
ARL::ResourceWrapper main_interpreter{ ARL::ResourceTraits::CppObject<nkg::X64ImageInterpreter>{} };
|
||||||
|
|
||||||
printf("[*] Your Navicat version: %d.%d.%d\n", Ver0, Ver1, Ver2);
|
//
|
||||||
printf("\n");
|
// try open "/Contents/MacOS/Navicat Premium"
|
||||||
|
//
|
||||||
Solution0.TakeOver(new PatchSolution0(MainApp));
|
main_path = szInstallPath + "/Contents/MacOS/Navicat Premium";
|
||||||
Solution1.TakeOver(new PatchSolution1(MainApp));
|
main_fd.TakeOver(open(main_path.c_str(), O_RDWR));
|
||||||
Solution2.TakeOver(new PatchSolution2(MainApp));
|
if (main_fd.IsValid()) {
|
||||||
|
printf("[+] Try to open \"%s\" ... Ok!\n", "Contents/MacOS/Navicat Premium");
|
||||||
if (Solution0->FindPatchOffset() == false) {
|
} else {
|
||||||
Solution0.Release();
|
if (errno == ENOENT) {
|
||||||
}
|
printf("[-] Try to open \"%s\" ... Not found!\n", "Contents/MacOS/Navicat Premium");
|
||||||
if (Solution1->FindPatchOffset() == false) {
|
} else {
|
||||||
Solution1.Release();
|
throw ARL::SystemError(__FILE__, __LINE__, errno, "open failed.");
|
||||||
}
|
}
|
||||||
if (Solution2->FindPatchOffset() == false) {
|
|
||||||
Solution2.Release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Begin strategies by different Navicat versions
|
// try map "/Contents/MacOS/Navicat Premium"
|
||||||
//
|
//
|
||||||
if (Ver0 < 12) { // ver < 12.0.0
|
if (main_fd.IsValid()) {
|
||||||
// NOLINTNEXTLINE: allow exceptions that is not derived from std::exception
|
main_stat.TakeOver(new struct stat());
|
||||||
throw nkg::SystemError(__FILE__, __LINE__, errno, "Unsupported version of Navicat.");
|
if (fstat(main_fd, main_stat) != 0) {
|
||||||
} else if (Ver0 == 12 && Ver1 == 0 && Ver2 < 24) { // ver < 12.0.24
|
throw ARL::SystemError(__FILE__, __LINE__, errno, "fstat failed.");
|
||||||
std::string path(argv[1]);
|
|
||||||
while(path.back() == '/') {
|
|
||||||
path.pop_back();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("[*] Your Navicat version is < 12.0.24. So there would be nothing patched.\n");
|
main_mmap.TakeOver(mmap(nullptr, main_stat->st_size, PROT_READ | PROT_WRITE, MAP_SHARED, main_fd, 0));
|
||||||
printf(" Just use `openssl` to generate `RegPrivateKey.pem` and `rpk` file:\n");
|
if (main_mmap.IsValid() == false) {
|
||||||
printf(" openssl genrsa -out RegPrivateKey.pem 2048\n");
|
throw ARL::SystemError(__FILE__, __LINE__, errno, "mmap failed.");
|
||||||
printf(" openssl rsa -in RegPrivateKey.pem -pubout -out rpk\n");
|
|
||||||
printf(" and replace `%s/Contents/Resources/rpk` with the `rpk` file you just generated.\n", path.c_str());
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
} else if (Ver0 == 12 && (Ver1 == 0 || (Ver1 == 1 && Ver2 < 14))) { // 12.0.24 <= ver && ver < 12.1.14
|
|
||||||
// In this case, Solution0 must be applied
|
|
||||||
if (Solution0.IsValid() == false) {
|
|
||||||
puts("[-] Patch abort. None of PatchSolutions will be applied.");
|
|
||||||
puts(" Are you sure your Navicat has not been patched before?");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
} else if (Ver0 == 12 && Ver1 == 1 && Ver2 == 14) { // ver == 12.1.14
|
|
||||||
// In this case, Solution0 and Solution1 must be applied
|
|
||||||
if ((Solution0.IsValid() && Solution1.IsValid()) == false) {
|
|
||||||
puts("[-] Patch abort. None of PatchSolutions will be applied.");
|
|
||||||
puts(" Are you sure your Navicat has not been patched before?");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else { // ver > 12.1.14
|
|
||||||
// In this case, Solution0 and Solution2 must be applied
|
|
||||||
if ((Solution0.IsValid() && Solution2.IsValid()) == false) {
|
|
||||||
puts("[-] Patch abort. None of PatchSolutions will be applied.");
|
|
||||||
puts(" Are you sure your Navicat has not been patched before?");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// End strategies by different Navicat versions
|
|
||||||
//
|
|
||||||
|
|
||||||
LoadKey(RsaCipher, argc == 3 ? argv[2] : nullptr, Solution0, Solution1, Solution2);
|
main_interpreter.TakeOver(
|
||||||
|
new nkg::X64ImageInterpreter(nkg::X64ImageInterpreter::Parse(main_mmap, main_stat->st_size))
|
||||||
|
);
|
||||||
|
|
||||||
if (Solution0.IsValid()) {
|
lpSolution0.TakeOver(
|
||||||
Solution0->MakePatch(RsaCipher);
|
new nkg::PatchSolution0(*main_interpreter.Get())
|
||||||
|
);
|
||||||
|
lpSolution1.TakeOver(
|
||||||
|
new nkg::PatchSolution1(*main_interpreter.Get())
|
||||||
|
);
|
||||||
|
lpSolution2.TakeOver(
|
||||||
|
new nkg::PatchSolution2(*main_interpreter.Get())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (Solution1.IsValid()) {
|
|
||||||
Solution1->MakePatch(RsaCipher);
|
|
||||||
}
|
|
||||||
if (Solution2.IsValid()) {
|
|
||||||
Solution2->MakePatch(RsaCipher);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Solution0.IsValid())
|
|
||||||
puts("[+] PatchSolution0 has been applied.");
|
|
||||||
if (Solution1.IsValid())
|
|
||||||
puts("[+] PatchSolution1 has been applied.");
|
|
||||||
if (Solution2.IsValid())
|
|
||||||
puts("[+] PatchSolution2 has been applied.");
|
|
||||||
|
|
||||||
puts("");
|
puts("");
|
||||||
puts("**************************************************************");
|
|
||||||
puts("* Patch has been done successfully. Have fun and enjoy~~ *");
|
if (lpSolution0.IsValid() && lpSolution0->FindPatchOffset() == false) {
|
||||||
puts("* DO NOT FORGET TO SIGN NAVICAT BY YOUR CERTIFICATE!!! *");
|
lpSolution0.Release();
|
||||||
puts("**************************************************************");
|
}
|
||||||
|
if (lpSolution1.IsValid() && lpSolution1->FindPatchOffset() == false) {
|
||||||
|
lpSolution1.Release();
|
||||||
|
}
|
||||||
|
if (lpSolution2.IsValid() && lpSolution2->FindPatchOffset() == false) {
|
||||||
|
lpSolution2.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (int Ver0, Ver1, Ver2; sscanf(GetNavicatVersion(szInstallPath).c_str(), "%d.%d.%d", &Ver0, &Ver1, &Ver2) == 3) {
|
||||||
|
printf("\n");
|
||||||
|
printf("[*] Your Navicat version: %d.%d.%d\n", Ver0, Ver1, Ver2);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
//
|
||||||
|
// Begin strategies by different Navicat versions
|
||||||
|
//
|
||||||
|
if (Ver0 < 12) { // ver < 12.0.0
|
||||||
|
throw ARL::SystemError(__FILE__, __LINE__, errno, "Unsupported version of Navicat.");
|
||||||
|
} else if (Ver0 == 12 && Ver1 == 0 && Ver2 < 24) { // ver < 12.0.24
|
||||||
|
printf("[*] Your Navicat version is < 12.0.24. So there would be nothing patched.\n");
|
||||||
|
printf(" Just use `openssl` to generate `RegPrivateKey.pem` and `rpk` file:\n");
|
||||||
|
printf(" openssl genrsa -out RegPrivateKey.pem 2048\n");
|
||||||
|
printf(" openssl rsa -in RegPrivateKey.pem -pubout -out rpk\n");
|
||||||
|
printf(" and replace `%s/Contents/Resources/rpk` with the `rpk` file you just generated.\n", szInstallPath.c_str());
|
||||||
|
printf("\n");
|
||||||
|
return 0;
|
||||||
|
} else if (Ver0 == 12 && (Ver1 == 0 || (Ver1 == 1 && Ver2 < 14))) { // 12.0.24 <= ver && ver < 12.1.14
|
||||||
|
// In this case, Solution0 must be applied
|
||||||
|
if (lpSolution0.IsValid() == false) {
|
||||||
|
puts("[-] Patch abort. None of PatchSolutions will be applied.");
|
||||||
|
puts(" Are you sure your Navicat has not been patched/modified before?");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (Ver0 == 12 && Ver1 == 1 && Ver2 == 14) { // ver == 12.1.14
|
||||||
|
// In this case, Solution0 and Solution1 must be applied
|
||||||
|
if ((lpSolution0.IsValid() && lpSolution1.IsValid()) == false) {
|
||||||
|
puts("[-] Patch abort. None of PatchSolutions will be applied.");
|
||||||
|
puts(" Are you sure your Navicat has not been patched/modified before?");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else { // ver > 12.1.14
|
||||||
|
// In this case, Solution0 and Solution2 must be applied
|
||||||
|
if ((lpSolution0.IsValid() && lpSolution2.IsValid()) == false) {
|
||||||
|
puts("[-] Patch abort. None of PatchSolutions will be applied.");
|
||||||
|
puts(" Are you sure your Navicat has not been patched/modified before?");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// End strategies by different Navicat versions
|
||||||
|
//
|
||||||
|
} else {
|
||||||
|
throw ARL::SystemError(__FILE__, __LINE__, errno, "Failed to get version of Navicat.");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Make sure that there is one patch solution at least existing.
|
||||||
|
//
|
||||||
|
if (lpSolution0.IsValid() == false && lpSolution1.IsValid() == false && lpSolution2.IsValid() == false) {
|
||||||
|
throw ARL::Exception(__FILE__, __LINE__, "No patch applied. Patch abort!")
|
||||||
|
.PushHint("Are you sure your Navicat has not been patched/modified before?");
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadKey(Cipher, szKeyFilePath, lpSolution0, lpSolution1, lpSolution2);
|
||||||
|
|
||||||
|
if (bDryrun == false) {
|
||||||
|
//
|
||||||
|
// Save private key if not given
|
||||||
|
//
|
||||||
|
if (szKeyFilePath.empty()) {
|
||||||
|
Cipher.ExportKeyToFile<nkg::RSAKeyType::PrivateKey, nkg::RSAKeyFormat::PEM>("RegPrivateKey.pem");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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 (lpSolution0.IsValid()) {
|
||||||
|
puts("[+] PatchSolution0 has been applied.");
|
||||||
|
}
|
||||||
|
if (lpSolution1.IsValid()) {
|
||||||
|
puts("[+] PatchSolution1 has been applied.");
|
||||||
|
}
|
||||||
|
if (lpSolution2.IsValid()) {
|
||||||
|
puts("[+] PatchSolution2 has been applied.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (szKeyFilePath.empty()) {
|
||||||
|
printf("[*] New RSA-2048 private key has been saved to\n");
|
||||||
|
printf(" %s/RegPrivateKey.pem\n", nkg::Misc::FsCurrentWorkingDirectory().c_str());
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
puts("");
|
||||||
|
puts("**************************************************************");
|
||||||
|
puts("* Patch has been done successfully. Have fun and enjoy~~ *");
|
||||||
|
puts("* DO NOT FORGET TO SIGN NAVICAT BY YOUR CERTIFICATE!!! *");
|
||||||
|
puts("**************************************************************");
|
||||||
|
} else {
|
||||||
|
puts("**************************************************************");
|
||||||
|
puts("* DRY-RUN MODE ENABLE! *");
|
||||||
|
puts("* NO PATCH WILL BE APPLIED! *");
|
||||||
|
puts("**************************************************************");
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} catch (nkg::Exception& e) {
|
} catch (ARL::Exception& e) {
|
||||||
printf("[-] %s:%zu -> \n", e.File(), e.Line());
|
printf("[-] %s:%zu ->\n", e.ExceptionFile(), e.ExceptionLine());
|
||||||
printf(" %s\n", e.Message());
|
printf(" %s\n", e.ExceptionMessage());
|
||||||
|
|
||||||
if (e.HasErrorCode()) {
|
if (e.HasErrorCode()) {
|
||||||
printf(" %s\n", e.ErrorString());
|
printf(" %s (0x%zx)\n", e.ErrorString(), e.ErrorCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& Hint : e.Hints()) {
|
||||||
|
printf(" Hints: %s\n", Hint.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
printf("[-] %s\n", e.what());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user