Add PatchSolution4 for Navicat Modeler 3

This commit is contained in:
Double Sine
2019-09-28 00:49:34 +08:00
parent c8160cb7c5
commit 70f49762cc
13 changed files with 613 additions and 7 deletions
+4
View File
@@ -86,6 +86,10 @@ namespace nkg {
}
}
const char* CapstoneEngine::GetRegisterName(unsigned int reg_id) const noexcept {
return cs_reg_name(Get(), reg_id);
}
[[nodiscard]]
CapstoneDisassembler CapstoneEngine::CreateDisassembler() const {
return CapstoneDisassembler(*this);
+2
View File
@@ -51,6 +51,8 @@ namespace nkg {
void Option(cs_opt_type Type, cs_opt_value Value);
const char* GetRegisterName(unsigned int reg_id) const noexcept;
[[nodiscard]]
CapstoneDisassembler CreateDisassembler() const;
};
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include <Exception.hpp>
#include <keystone/keystone.h>
namespace nkg {
class KeystoneError final : public Exception {
private:
ks_err _ErrorCode;
std::xstring _ErrorString;
public:
KeystoneError(PCTSTR SourceFile, SIZE_T SourceLine, ks_err KeystoneErrorCode, PCTSTR CustomMessage) noexcept :
Exception(SourceFile, SourceLine, CustomMessage),
_ErrorCode(KeystoneErrorCode),
_ErrorString(std::xstring_extension{}, ks_strerror(KeystoneErrorCode), CP_UTF8) {}
[[nodiscard]]
virtual bool HasErrorCode() const noexcept override {
return true;
}
[[nodiscard]]
virtual ULONG_PTR ErrorCode() const noexcept override {
return _ErrorCode;
}
[[nodiscard]]
virtual PCTSTR ErrorString() const noexcept override {
return _ErrorString.c_str();
}
};
}
+44
View File
@@ -0,0 +1,44 @@
#include "KeystoneAssembler.hpp"
#undef NKG_CURRENT_SOURCE_FILE
#undef NKG_CURRENT_SOURCE_LINE
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\KeystoneAssembler.cpp")
#define NKG_CURRENT_SOURCE_LINE() __LINE__
namespace nkg {
KeystoneAssembler::KeystoneAssembler(const KeystoneEngine& Engine) noexcept :
_Engine(Engine) {}
[[nodiscard]]
std::vector<uint8_t> KeystoneAssembler::GenerateMachineCode(const char* AssemblyCode, uint64_t Address) const {
ResourceOwned pbMachineCode(KeystoneMallocTraits{});
size_t cbMachineCode = 0;
size_t InstructionsProcessed = 0;
if (ks_asm(_Engine, AssemblyCode, Address, pbMachineCode.GetAddressOf(), &cbMachineCode, &InstructionsProcessed) != 0) {
throw KeystoneError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), ks_errno(_Engine), TEXT("ks_asm failed."));
}
return std::vector<uint8_t>(pbMachineCode.Get(), pbMachineCode.Get() + cbMachineCode);
}
KeystoneEngine::KeystoneEngine(ks_arch ArchType, ks_mode Mode) {
auto err = ks_open(ArchType, Mode, GetAddressOf());
if (err != KS_ERR_OK) {
throw KeystoneError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, TEXT("ks_open failed."));
}
}
void KeystoneEngine::Option(ks_opt_type Type, ks_opt_value Value) {
auto err = ks_option(Get(), Type, Value);
if (err != KS_ERR_OK) {
throw KeystoneError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, TEXT("ks_option failed."));
}
}
KeystoneAssembler KeystoneEngine::CreateAssembler() const {
return KeystoneAssembler(*this);
}
}
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#include "ExceptionKeystone.hpp"
#include <ResourceOwned.hpp>
#include "ResourceTraitsKeystone.hpp"
#include <vector>
namespace nkg {
class KeystoneEngine;
class KeystoneAssembler {
friend class KeystoneEngine;
private:
const KeystoneEngine& _Engine;
KeystoneAssembler(const KeystoneEngine& Engine) noexcept;
public:
[[nodiscard]]
std::vector<uint8_t> GenerateMachineCode(const char* AssemblyCode, uint64_t Address = 0) const;
};
class KeystoneEngine : private ResourceOwned<KeystoneHandleTraits> {
friend class KeystoneAssembler;
public:
KeystoneEngine(ks_arch ArchType, ks_mode Mode);
void Option(ks_opt_type Type, ks_opt_value Value);
[[nodiscard]]
KeystoneAssembler CreateAssembler() const;
};
}
+150
View File
@@ -0,0 +1,150 @@
#include "PatchSolutions.hpp"
#include <xstring.hpp>
#undef NKG_CURRENT_SOURCE_FILE
#undef NKG_CURRENT_SOURCE_LINE
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\PatchSolution4-amd64.cpp")
#define NKG_CURRENT_SOURCE_LINE() __LINE__
namespace nkg {
PatchSolution4::PatchSolution4(const ImageInterpreter& Image) :
_Image(Image),
_DisassemblyEngine(CS_ARCH_X86, CS_MODE_64),
_AssemblyEngine(KS_ARCH_X86, KS_MODE_64),
_pbPatchMachineCode(nullptr),
_pbPatchNewPublicKey(nullptr) { _DisassemblyEngine.Option(CS_OPT_DETAIL, CS_OPT_ON); }
PatchSolution4::PatchSolution4(const ImageInterpreter* Image) :
_Image(*Image),
_DisassemblyEngine(CS_ARCH_X86, CS_MODE_64),
_AssemblyEngine(KS_ARCH_X86, KS_MODE_64),
_pbPatchMachineCode(nullptr),
_pbPatchNewPublicKey(nullptr) { _DisassemblyEngine.Option(CS_OPT_DETAIL, CS_OPT_ON); }
bool PatchSolution4::FindPatchOffset() noexcept {
try {
_pbPatchMachineCode = _Image.SearchSection<uint8_t*>(".text", [](const uint8_t* p) {
__try {
return
p[0] == 0x48 && p[1] == 0x8d && // prefix of "lea rcx, [rbp+5Fh+var_38]"
p[4] == 0x48 && p[5] == 0x83 && // prefix of "cmp [rbp+5Fh+var_20], 10h"
p[9] == 0x48 && p[10] == 0x0f && p[11] == 0x43 && // prefix of "cmovnb rcx, [rbp+5Fh+var_38]"
p[14] == 0x48 && p[15] == 0x8d && // prefix of "lea rax, [rbp+5Fh+var_58]"
p[18] == 0x48 && p[19] == 0x83 && // prefix of "cmp [rbp+5Fh+var_40], 10h"
p[23] == 0x48 && p[24] == 0x0f && p[25] == 0x43 && // prefix of "cmovnb rax, [rbp+5Fh+var_58]"
p[28] == 0x44 && p[29] == 0x0f && p[30] == 0xb6 && // prefix of "movzx r8d, byte ptr [rax+rdi]"
p[33] == 0x44 && p[34] == 0x02 && // prefix of "add r8b, [rcx+rdi]"
p[37] == 0xba && // prefix of "mov edx, 1"
p[42] == 0x48 && p[43] == 0x8b && // prefix of "mov rcx, rbx"
p[45] == 0xe8; // prefix of "call sub_1806E65F0"
} __except (EXCEPTION_EXECUTE_HANDLER) {
return false;
}
});
auto RegisterIndex = X86_REG_INVALID;
auto Disassembler = _DisassemblyEngine.CreateDisassembler();
Disassembler.SetContext({ _pbPatchMachineCode, 45, _Image.PointerToVa(_pbPatchMachineCode) });
if (Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next()) {
auto lpInsn = Disassembler.GetInstruction();
if (_stricmp(lpInsn->mnemonic, "movzx") == 0 &&
lpInsn->detail->x86.op_count == 2 &&
lpInsn->detail->x86.operands[0].type == X86_OP_REG &&
lpInsn->detail->x86.operands[1].type == X86_OP_MEM &&
lpInsn->detail->x86.operands[1].size == 1 &&
lpInsn->detail->x86.operands[1].mem.scale == 1)
{
RegisterIndex = lpInsn->detail->x86.operands[1].mem.index;
} else {
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Unexpected machine code."));
}
} else {
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Disassemble failed."));
}
if (Disassembler.Next() && Disassembler.Next() && Disassembler.Next()) {
auto lpInsn = Disassembler.GetInstruction();
//
// The previous instruction of "call sub_1806E65F0" should set RCX register.
//
if (_stricmp(lpInsn->mnemonic, "mov") != 0 ||
lpInsn->detail->x86.op_count < 1 ||
lpInsn->detail->x86.operands[0].type != X86_OP_REG ||
lpInsn->detail->x86.operands[0].reg != X86_REG_RCX)
{
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Unexpected machine code."));
}
} else {
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Disassemble failed."));
}
for (size_t i = 0; i < _Image.NumberOfSections(); ++i) {
auto lpSectionHeader = _Image.ImageSectionHeader(i);
if (lpSectionHeader->SizeOfRawData > lpSectionHeader->Misc.VirtualSize) {
auto cbReserved =
lpSectionHeader->SizeOfRawData -
lpSectionHeader->Misc.VirtualSize;
if (cbReserved >= 0x188) {
_pbPatchNewPublicKey = _Image.ImageSectionView<uint8_t*>(lpSectionHeader, lpSectionHeader->Misc.VirtualSize);
auto Assembler = _AssemblyEngine.CreateAssembler();
_NewMachineCode = Assembler.GenerateMachineCode(
std::xstring::format(
TEXT(
"lea rax, qword ptr[0x%.16llx];"
"mov r8b, byte ptr[rax + %hs];"
"mov edx, 1;"
),
_Image.PointerToVa(_pbPatchNewPublicKey),
_DisassemblyEngine.GetRegisterName(RegisterIndex)
).explicit_string().c_str(),
_Image.PointerToVa(_pbPatchMachineCode)
);
// >>>>>>>>>>>> .text:00000001819B02C0 48 8D 4D 27 lea rcx, [rbp + 5Fh + var_38]
// .text:00000001819B02C4 48 83 7D 3F 10 cmp[rbp + 5Fh + var_20], 10h
// 42 BYTES .text:00000001819B02C9 48 0F 43 4D 27 cmovnb rcx, [rbp + 5Fh + var_38]
// .text:00000001819B02CE 48 8D 45 07 lea rax, [rbp + 5Fh + var_58]
// THESE CODE .text:00000001819B02D2 48 83 7D 1F 10 cmp[rbp + 5Fh + var_40], 10h
// WILL BE .text:00000001819B02D7 48 0F 43 45 07 cmovnb rax, [rbp + 5Fh + var_58]
// REPLACED .text:00000001819B02DC 44 0F B6 04 38 movzx r8d, byte ptr[rax + rdi]
// .text:00000001819B02E1 44 02 04 39 add r8b, [rcx + rdi]
// <<<<<<<<<<<< .text:00000001819B02E5 BA 01 00 00 00 mov edx, 1
// .text:00000001819B02EA 48 8B CB mov rcx, rbx
// .text:00000001819B02ED E8 FE 62 D3 FE call sub_1806E65F0
while (_NewMachineCode.size() < 42) {
_NewMachineCode.emplace_back(0x90); // padding with "nop"
}
if (_NewMachineCode.size() != 42) {
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Something unexpected happens."));
}
LOG_SUCCESS(0, "PatchSolution4 ...... Ready to apply");
LOG_HINT(4, "Machine code patch VA = 0x%zx", _Image.PointerToVa(_pbPatchMachineCode));
LOG_HINT(4, "New public key VA = 0x%zx", _Image.PointerToVa(_pbPatchNewPublicKey));
LOG_HINT(4, "New public key offset = 0x%zx", _Image.PointerToFileOffset(_pbPatchNewPublicKey));
return true;
}
}
}
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("No space to store public key."));
} catch (nkg::Exception&) {
_pbPatchMachineCode = nullptr;
_pbPatchNewPublicKey = nullptr;
_NewMachineCode.clear();
LOG_FAILURE(0, "PatchSolution4 ...... Omitted");
return false;
}
}
}
@@ -0,0 +1,72 @@
#include "PatchSolutions.hpp"
#undef NKG_CURRENT_SOURCE_FILE
#undef NKG_CURRENT_SOURCE_LINE
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\PatchSolution4-generic.cpp")
#define NKG_CURRENT_SOURCE_LINE() __LINE__
namespace nkg {
bool PatchSolution4::CheckKey(const RSACipher& Cipher) const noexcept {
auto szPublicKey = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
for (auto pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----", pos)) {
szPublicKey.erase(pos, literal_length("-----BEGIN PUBLIC KEY-----"));
}
for (auto pos = szPublicKey.find("-----END PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----END PUBLIC KEY-----", pos)) {
szPublicKey.erase(pos, literal_length("-----END PUBLIC KEY-----"));
}
for (auto pos = szPublicKey.find("\n"); pos != std::string::npos; pos = szPublicKey.find("\n", pos)) {
szPublicKey.erase(pos, literal_length("\n"));
}
return szPublicKey.length() == 0x188;
}
void PatchSolution4::MakePatch(const RSACipher& Cipher) const {
if (_pbPatchMachineCode == nullptr || _pbPatchNewPublicKey == nullptr || _NewMachineCode.empty()) {
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("PatchSolution4 has not been ready yet."));
}
auto szPublicKey = Cipher.ExportKeyString<RSAKeyType::PublicKey, RSAKeyFormat::PEM>();
for (auto pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----BEGIN PUBLIC KEY-----", pos)) {
szPublicKey.erase(pos, literal_length("-----BEGIN PUBLIC KEY-----"));
}
for (auto pos = szPublicKey.find("-----END PUBLIC KEY-----"); pos != std::string::npos; pos = szPublicKey.find("-----END PUBLIC KEY-----", pos)) {
szPublicKey.erase(pos, literal_length("-----END PUBLIC KEY-----"));
}
for (auto pos = szPublicKey.find("\n"); pos != std::string::npos; pos = szPublicKey.find("\n", pos)) {
szPublicKey.erase(pos, literal_length("\n"));
}
_putts(TEXT("*******************************************************"));
_putts(TEXT("* PatchSolution4 *"));
_putts(TEXT("*******************************************************"));
LOG_HINT(0, "Previous:");
PrintMemory(_pbPatchMachineCode, _NewMachineCode.size(), _Image.ImageBase());
memcpy(_pbPatchMachineCode, _NewMachineCode.data(), _NewMachineCode.size());
LOG_HINT(0, "After:");
PrintMemory(_pbPatchMachineCode, _NewMachineCode.size(), _Image.ImageBase());
_putts(TEXT(""));
LOG_HINT(0, "Previous:");
PrintMemory(_pbPatchNewPublicKey, szPublicKey.size(), _Image.ImageBase());
memcpy(_pbPatchNewPublicKey, szPublicKey.data(), szPublicKey.size());
LOG_HINT(0, "After:");
PrintMemory(_pbPatchNewPublicKey, szPublicKey.size(), _Image.ImageBase());
_putts(TEXT(""));
}
}
+145
View File
@@ -0,0 +1,145 @@
#include "PatchSolutions.hpp"
#include <xstring.hpp>
#undef NKG_CURRENT_SOURCE_FILE
#undef NKG_CURRENT_SOURCE_LINE
#define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\PatchSolution4-i386.cpp")
#define NKG_CURRENT_SOURCE_LINE() __LINE__
namespace nkg {
PatchSolution4::PatchSolution4(const ImageInterpreter& Image) :
_Image(Image),
_DisassemblyEngine(CS_ARCH_X86, CS_MODE_32),
_AssemblyEngine(KS_ARCH_X86, KS_MODE_32),
_pbPatchMachineCode(nullptr),
_pbPatchNewPublicKey(nullptr) { _DisassemblyEngine.Option(CS_OPT_DETAIL, CS_OPT_ON); }
PatchSolution4::PatchSolution4(const ImageInterpreter* Image) :
_Image(*Image),
_DisassemblyEngine(CS_ARCH_X86, CS_MODE_32),
_AssemblyEngine(KS_ARCH_X86, KS_MODE_32),
_pbPatchMachineCode(nullptr),
_pbPatchNewPublicKey(nullptr) { _DisassemblyEngine.Option(CS_OPT_DETAIL, CS_OPT_ON); }
bool PatchSolution4::FindPatchOffset() noexcept {
try {
_pbPatchMachineCode = _Image.SearchSection<uint8_t*>(".text", [](const uint8_t* p) {
__try {
return
p[0] == 0x83 && // prefix of "cmp [ebp+var_30], 10h"
p[4] == 0x8d && // prefix of "lea ecx, [ebp+Dst]"
p[7] == 0x8d && // prefix of "lea eax, [ebp+Memory]"
p[10] == 0x0f && p[11] == 0x43 && // prefix of "cmovnb ecx, [ebp+Dst]"
p[14] == 0x83 && // prefix of "cmp [ebp+var_18], 10h"
p[18] == 0x0f && p[19] == 0x43 && // prefix of "cmovnb eax, [ebp+Memory]"
p[22] == 0x8a && // prefix of "mov dl, [eax+ebx]"
p[25] == 0x02; // prefix of "add dl, [ecx+ebx]"
// p[28]
} __except (EXCEPTION_EXECUTE_HANDLER) {
return false;
}
});
auto RegisterIndex = X86_REG_INVALID;
auto RegisterFinalValue = X86_REG_INVALID;
auto Disassembler = _DisassemblyEngine.CreateDisassembler();
Disassembler.SetContext({ _pbPatchMachineCode, 28, _Image.PointerToVa(_pbPatchMachineCode) });
if (Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next() && Disassembler.Next()) {
auto lpInsn = Disassembler.GetInstruction();
if (_stricmp(lpInsn->mnemonic, "mov") == 0 &&
lpInsn->detail->x86.op_count == 2 &&
lpInsn->detail->x86.operands[0].type == X86_OP_REG &&
lpInsn->detail->x86.operands[1].type == X86_OP_MEM &&
lpInsn->detail->x86.operands[1].size == 1 &&
lpInsn->detail->x86.operands[1].mem.scale == 1)
{
RegisterIndex = lpInsn->detail->x86.operands[1].mem.index;
} else {
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Unexpected machine code."));
}
} else {
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Disassemble failed."));
}
if (Disassembler.Next()) {
auto lpInsn = Disassembler.GetInstruction();
if (_stricmp(lpInsn->mnemonic, "add") == 0 &&
lpInsn->detail->x86.op_count >= 1 &&
lpInsn->detail->x86.operands[0].type == X86_OP_REG &&
lpInsn->detail->x86.operands[0].size == 1)
{
RegisterFinalValue = lpInsn->detail->x86.operands[0].reg;
} else {
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Unexpected machine code."));
}
} else {
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Disassemble failed."));
}
for (size_t i = 0; i < _Image.NumberOfSections(); ++i) {
auto lpSectionHeader = _Image.ImageSectionHeader(i);
if (lpSectionHeader->SizeOfRawData > lpSectionHeader->Misc.VirtualSize) {
auto cbReserved =
lpSectionHeader->SizeOfRawData -
lpSectionHeader->Misc.VirtualSize;
if (cbReserved >= 0x188) {
_pbPatchNewPublicKey = _Image.ImageSectionView<uint8_t*>(lpSectionHeader, lpSectionHeader->Misc.VirtualSize);
auto Assembler = _AssemblyEngine.CreateAssembler();
_NewMachineCode = Assembler.GenerateMachineCode(
std::xstring::format(
TEXT(
"call +5;"
"pop eax;"
"add eax, 0x%.8x;"
"mov %hs, byte ptr [eax + %hs];"
),
_Image.PointerToVa(_pbPatchNewPublicKey) - (_Image.PointerToVa(_pbPatchMachineCode) + 5),
_DisassemblyEngine.GetRegisterName(RegisterFinalValue),
_DisassemblyEngine.GetRegisterName(RegisterIndex)
).explicit_string().c_str()
);
// >>>>>>>>>>>> .text:113FE4A0 83 7D D0 10 cmp [ebp+var_30], 10h
// 28 BYTES .text:113FE4A4 8D 4D BC lea ecx, [ebp+Dst]
// .text:113FE4A7 8D 45 D4 lea eax, [ebp+Memory]
// THESE CODE .text:113FE4AA 0F 43 4D BC cmovnb ecx, [ebp+Dst]
// WILL BE .text:113FE4AE 83 7D E8 10 cmp [ebp+var_18], 10h
// REPLACED .text:113FE4B2 0F 43 45 D4 cmovnb eax, [ebp+Memory]
// .text:113FE4B6 8A 14 18 mov dl, [eax+ebx]
// <<<<<<<<<<<< .text:113FE4B9 02 14 19 add dl, [ecx+ebx]
while (_NewMachineCode.size() < 28) {
_NewMachineCode.emplace_back(0x90); // padding with "nop"
}
if (_NewMachineCode.size() != 28) {
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Something unexpected happens."));
}
LOG_SUCCESS(0, "PatchSolution4 ...... Ready to apply");
LOG_HINT(4, "Machine code patch VA = 0x%zx", _Image.PointerToVa(_pbPatchMachineCode));
LOG_HINT(4, "New public key VA = 0x%zx", _Image.PointerToVa(_pbPatchNewPublicKey));
LOG_HINT(4, "New public key offset = 0x%zx", _Image.PointerToFileOffset(_pbPatchNewPublicKey));
return true;
}
}
}
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("No space to store public key."));
} catch (nkg::Exception&) {
_pbPatchMachineCode = nullptr;
_pbPatchNewPublicKey = nullptr;
_NewMachineCode.clear();
LOG_FAILURE(0, "PatchSolution4 ...... Omitted");
return false;
}
}
}
+33
View File
@@ -2,6 +2,7 @@
#include <RSACipher.hpp>
#include "ImageInterpreter.hpp"
#include "CapstoneDisassembler.hpp"
#include "KeystoneAssembler.hpp"
#include "Misc.hpp"
namespace nkg {
@@ -198,4 +199,36 @@ namespace nkg {
virtual void MakePatch(const RSACipher& Cipher) const override;
};
//
// PatchSolution3 will replace the RSA public key stored in libcc.dll
// For Navicat Data Modeler 3
//
class PatchSolution4 : public PatchSolution {
private:
static const uint8_t KeywordA[0x188];
static const uint8_t KeywordB[0x188];
const ImageInterpreter& _Image;
CapstoneEngine _DisassemblyEngine;
KeystoneEngine _AssemblyEngine;
uint8_t* _pbPatchMachineCode;
uint8_t* _pbPatchNewPublicKey;
std::vector<uint8_t> _NewMachineCode;
public:
PatchSolution4(const ImageInterpreter& Image);
PatchSolution4(const ImageInterpreter* lpImage);
[[nodiscard]]
virtual bool FindPatchOffset() noexcept override;
[[nodiscard]]
virtual bool CheckKey(const RSACipher& Cipher) const noexcept override;
virtual void MakePatch(const RSACipher& Cipher) const override;
};
}
@@ -0,0 +1,33 @@
#pragma once
#include <keystone/keystone.h>
struct KeystoneHandleTraits {
using HandleType = ks_engine*;
static inline const HandleType InvalidValue = nullptr;
[[nodiscard]]
static bool IsValid(const HandleType& Handle) noexcept {
return Handle != InvalidValue;
}
static void Releasor(const HandleType& Handle) noexcept {
ks_close(Handle);
}
};
struct KeystoneMallocTraits {
using HandleType = uint8_t*;
static inline const HandleType InvalidValue = nullptr;
[[nodiscard]]
static bool IsValid(const HandleType& Handle) noexcept {
return Handle != InvalidValue;
}
static void Releasor(const HandleType& Handle) noexcept {
ks_free(Handle);
}
};
+20 -7
View File
@@ -131,7 +131,8 @@ static void LoadKey(
nkg::PatchSolution* pSolution0,
nkg::PatchSolution* pSolution1,
nkg::PatchSolution* pSolution2,
nkg::PatchSolution* pSolution3)
nkg::PatchSolution* pSolution3,
nkg::PatchSolution* pSolution4)
{
if (KeyFilePath.empty() == false) {
LOG_HINT(0, "Import RSA-2048 key from %s", KeyFilePath.c_str());
@@ -141,7 +142,8 @@ static void LoadKey(
if (pSolution0 && !pSolution0->CheckKey(Cipher) ||
pSolution1 && !pSolution1->CheckKey(Cipher) ||
pSolution2 && !pSolution2->CheckKey(Cipher) ||
pSolution3 && !pSolution3->CheckKey(Cipher))
pSolution3 && !pSolution3->CheckKey(Cipher) ||
pSolution4 && !pSolution4->CheckKey(Cipher))
{
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("The RSA private key you provide cannot be used."));
}
@@ -153,7 +155,8 @@ static void LoadKey(
} while (pSolution0 && !pSolution0->CheckKey(Cipher) ||
pSolution1 && !pSolution1->CheckKey(Cipher) ||
pSolution2 && !pSolution2->CheckKey(Cipher) ||
pSolution3 && !pSolution3->CheckKey(Cipher)); // re-generate RSA key if one of 'CheckKey's return false
pSolution3 && !pSolution3->CheckKey(Cipher) ||
pSolution4 && !pSolution4->CheckKey(Cipher)); // re-generate RSA key if one of 'CheckKey's return false
}
LOG_HINT(0, "Your RSA public key:\n%hs", Cipher.ExportKeyString<nkg::RSAKeyType::PublicKey, nkg::RSAKeyFormat::PEM>().c_str());
@@ -207,6 +210,7 @@ int _tmain(int argc, PTSTR argv[]) {
ResourceOwned lpSolution1(CppObjectTraits<nkg::PatchSolution>{});
ResourceOwned lpSolution2(CppObjectTraits<nkg::PatchSolution>{});
ResourceOwned lpSolution3(CppObjectTraits<nkg::PatchSolution>{});
ResourceOwned lpSolution4(CppObjectTraits<nkg::PatchSolution>{});
//
// Open main application
@@ -316,6 +320,7 @@ int _tmain(int argc, PTSTR argv[]) {
lpSolution1.TakeOver(new nkg::PatchSolution1(lpLibccDllInterpreter));
lpSolution2.TakeOver(new nkg::PatchSolution2(lpLibccDllInterpreter));
lpSolution3.TakeOver(new nkg::PatchSolution3(lpLibccDllInterpreter));
lpSolution4.TakeOver(new nkg::PatchSolution4(lpLibccDllInterpreter));
}
//
@@ -338,6 +343,10 @@ int _tmain(int argc, PTSTR argv[]) {
lpSolution3.Release();
}
if (lpSolution4.IsValid() && lpSolution4->FindPatchOffset() == false) {
lpSolution4.Release();
}
_putts(TEXT(""));
//
@@ -345,7 +354,7 @@ int _tmain(int argc, PTSTR argv[]) {
//
SelectPatchSolutions(lpSolution0, lpSolution1, lpSolution2, lpSolution3);
if (lpSolution0.IsValid() == false && lpSolution1.IsValid() == false && lpSolution2.IsValid() == false && lpSolution3.IsValid() == false) {
if (lpSolution0.IsValid() == false && lpSolution1.IsValid() == false && lpSolution2.IsValid() == false && lpSolution3.IsValid() == false && lpSolution4.IsValid() == false) {
throw nkg::Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("No patch applied. Patch abort!"))
.AddHint(TEXT("Are you sure your Navicat has not been patched/modified before?"));
}
@@ -359,14 +368,14 @@ int _tmain(int argc, PTSTR argv[]) {
NavicatBackupDetect(MainExePath);
}
if (lpSolution1.IsValid() || lpSolution2.IsValid() || lpSolution3.IsValid()) {
if (lpSolution1.IsValid() || lpSolution2.IsValid() || lpSolution3.IsValid() || lpSolution4.IsValid()) {
NavicatBackupDetect(LibccDllPath);
}
//
// Loading key
//
LoadKey(Cipher, RsaPrivateKeyPath, lpSolution0, lpSolution1, lpSolution2, lpSolution3);
LoadKey(Cipher, RsaPrivateKeyPath, lpSolution0, lpSolution1, lpSolution2, lpSolution3, lpSolution4);
if (bDryRun == false) {
//
@@ -383,7 +392,7 @@ int _tmain(int argc, PTSTR argv[]) {
NavicatBackupMake(MainExePath);
}
if (lpSolution1.IsValid() || lpSolution2.IsValid() || lpSolution3.IsValid()) {
if (lpSolution1.IsValid() || lpSolution2.IsValid() || lpSolution3.IsValid() || lpSolution4.IsValid()) {
NavicatBackupMake(LibccDllPath);
}
@@ -405,6 +414,10 @@ int _tmain(int argc, PTSTR argv[]) {
if (lpSolution3.IsValid()) {
lpSolution3->MakePatch(Cipher);
}
if (lpSolution4.IsValid()) {
lpSolution4->MakePatch(Cipher);
}
if (RsaPrivateKeyPath.empty()) {
LOG_HINT(
+13
View File
@@ -168,6 +168,7 @@
<ItemGroup>
<ClCompile Include="CapstoneDisassembler.cpp" />
<ClCompile Include="ImageInterpreter.cpp" />
<ClCompile Include="KeystoneAssembler.cpp" />
<ClCompile Include="Misc.cpp" />
<ClCompile Include="PatchSolution0.cpp" />
<ClCompile Include="PatchSolution1.cpp" />
@@ -189,16 +190,28 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="PatchSolution4-amd64.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="PatchSolution4-generic.cpp" />
<ClCompile Include="PatchSolution4-i386.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="_tmain.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="CapstoneDisassembler.hpp" />
<ClInclude Include="ExceptionCapstone.hpp" />
<ClInclude Include="ExceptionKeystone.hpp" />
<ClInclude Include="ImageInterpreter.hpp" />
<ClInclude Include="KeystoneAssembler.hpp" />
<ClInclude Include="Misc.hpp" />
<ClInclude Include="NavicatCrypto.hpp" />
<ClInclude Include="PatchSolutions.hpp" />
<ClInclude Include="ResourceTraitsCapstone.hpp" />
<ClInclude Include="ResourceTraitsKeystone.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
@@ -51,6 +51,18 @@
<ClCompile Include="CapstoneDisassembler.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="PatchSolution4-generic.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="PatchSolution4-amd64.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="KeystoneAssembler.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="PatchSolution4-i386.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="NavicatCrypto.hpp">
@@ -74,5 +86,14 @@
<ClInclude Include="Misc.hpp">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="KeystoneAssembler.hpp">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="ExceptionKeystone.hpp">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="ResourceTraitsKeystone.hpp">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
</Project>