mirror of
https://github.com/DoubleLabyrinth/navicat-keygen.git
synced 2019-12-02 05:10:56 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2e9ad3b39 | ||
|
|
f701a80b8f | ||
|
|
ec41feca91 | ||
|
|
c36f44dd1b | ||
|
|
70f49762cc | ||
|
|
c8160cb7c5 | ||
|
|
c173b0ff50 | ||
|
|
028c90b794 | ||
|
|
aac8ffd367 | ||
|
|
953da17799 | ||
|
|
33d75ddb12 | ||
|
|
0f9e750a31 |
@@ -4,7 +4,7 @@
|
||||
|
||||
This repository will tell you how Navicat offline activation works.
|
||||
|
||||
Previous code is archived in [`windows-archived`](https://github.com/DoubleLabyrinth/navicat-keygen/tree/windows-archived) branch for the reason that previos code contains 3rd binary libraries and it gets quite big :-(.
|
||||
Previous code is archived in [`windows-archived`](https://github.com/DoubleLabyrinth/navicat-keygen/tree/windows-archived) branch for the reason that previous code contains 3rd binary libraries and it gets quite big :-(
|
||||
|
||||
When you git-clone this repo, please add `--single-branch` flag so that archived branch won't be cloned to your computer, which saves your time and disk.
|
||||
|
||||
|
||||
@@ -12,5 +12,6 @@ export WINEDLLPATH="$navicat_root/$WINEDIR/lib/wine"
|
||||
export WINELOADER="$navicat_root/$WINEDIR/bin/wine64"
|
||||
export WINESERVER="$navicat_root/$WINEDIR/bin/wineserver"
|
||||
export WINEPREFIX="$HOME/.navicat64"
|
||||
export WINEDEBUG=-all # suppress all wine debug info
|
||||
|
||||
exec "${WINELOADER:-wine}" "navicat-keygen.exe" "-text" "RegPrivateKey.pem"
|
||||
|
||||
@@ -12,6 +12,7 @@ export WINEDLLPATH="$navicat_root/$WINEDIR/lib/wine"
|
||||
export WINELOADER="$navicat_root/$WINEDIR/bin/wine64"
|
||||
export WINESERVER="$navicat_root/$WINEDIR/bin/wineserver"
|
||||
export WINEPREFIX="$HOME/.navicat64"
|
||||
export WINEDEBUG=-all # suppress all wine debug info
|
||||
|
||||
# 将斜线替换为反斜线
|
||||
navicat_root_back_slash=${navicat_root//\//\\}
|
||||
|
||||
+1
-1
@@ -102,7 +102,7 @@ namespace std {
|
||||
|
||||
xstring(xstring_extension, const char* lpstr, DWORD CodePage = CP_ACP) {
|
||||
if (CodePage == CP_ACP || CodePage == GetACP()) {
|
||||
assign(str);
|
||||
assign(lpstr);
|
||||
} else {
|
||||
std::wstring wstr;
|
||||
|
||||
|
||||
+12
-12
@@ -210,18 +210,18 @@
|
||||
|
||||
4. __data[7]__ is Navicat product ID. (Thanks @dragonflylee and @Deltafox79)
|
||||
|
||||
|Product Name |Enterprise|Standard|Educational|Essentials|
|
||||
|---------------------|:--------:|:------:|:---------:|:--------:|
|
||||
|Navicat Report Viewer|0x0B | | | |
|
||||
|Navicat Data Modeler | |0x47 |0x4A | |
|
||||
|Navicat Premium |0x65 | |0x66 |0x67 |
|
||||
|Navicat MySQL |0x68 |0x69 |0x6A |0x6B |
|
||||
|Navicat PostgreSQL |0x6C |0x6D |0x6E |0x6F |
|
||||
|Navicat Oracle |0x70 |0x71 |0x72 |0x73 |
|
||||
|Navicat SQL Server |0x74 |0x75 |0x76 |0x77 |
|
||||
|Navicat SQLite |0x78 |0x79 |0x7A |0x7B |
|
||||
|Navicat MariaDB |0x7C |0x7D |0x7E |0x7F |
|
||||
|Navicat MongoDB |0x80 |0x81 |0x82 | |
|
||||
|Product Name |Enterprise|Standard|Educational|Essentials|
|
||||
|----------------------|:--------:|:------:|:---------:|:--------:|
|
||||
|Navicat Report Viewer |0x0B | | | |
|
||||
|Navicat Data Modeler 3| |0x84 |0x85 | |
|
||||
|Navicat Premium |0x65 | |0x66 |0x67 |
|
||||
|Navicat MySQL |0x68 |0x69 |0x6A |0x6B |
|
||||
|Navicat PostgreSQL |0x6C |0x6D |0x6E |0x6F |
|
||||
|Navicat Oracle |0x70 |0x71 |0x72 |0x73 |
|
||||
|Navicat SQL Server |0x74 |0x75 |0x76 |0x77 |
|
||||
|Navicat SQLite |0x78 |0x79 |0x7A |0x7B |
|
||||
|Navicat MariaDB |0x7C |0x7D |0x7E |0x7F |
|
||||
|Navicat MongoDB |0x80 |0x81 |0x82 | |
|
||||
|
||||
5. High 4 bits of __data[8]__ represents __major version number__.
|
||||
|
||||
|
||||
@@ -210,18 +210,18 @@
|
||||
|
||||
4. __data[7]__ 是Navicat产品ID。(感谢 @dragonflylee 和 @Deltafox79提供的数据)
|
||||
|
||||
|产品名 |Enterprise|Standard|Educational|Essentials|
|
||||
|---------------------|:--------:|:------:|:---------:|:--------:|
|
||||
|Navicat Report Viewer|0x0B | | | |
|
||||
|Navicat Data Modeler | |0x47 |0x4A | |
|
||||
|Navicat Premium |0x65 | |0x66 |0x67 |
|
||||
|Navicat MySQL |0x68 |0x69 |0x6A |0x6B |
|
||||
|Navicat PostgreSQL |0x6C |0x6D |0x6E |0x6F |
|
||||
|Navicat Oracle |0x70 |0x71 |0x72 |0x73 |
|
||||
|Navicat SQL Server |0x74 |0x75 |0x76 |0x77 |
|
||||
|Navicat SQLite |0x78 |0x79 |0x7A |0x7B |
|
||||
|Navicat MariaDB |0x7C |0x7D |0x7E |0x7F |
|
||||
|Navicat MongoDB |0x80 |0x81 |0x82 | |
|
||||
|产品名 |Enterprise|Standard|Educational|Essentials|
|
||||
|----------------------|:--------:|:------:|:---------:|:--------:|
|
||||
|Navicat Report Viewer |0x0B | | | |
|
||||
|Navicat Data Modeler 3| |0x84 |0x85 | |
|
||||
|Navicat Premium |0x65 | |0x66 |0x67 |
|
||||
|Navicat MySQL |0x68 |0x69 |0x6A |0x6B |
|
||||
|Navicat PostgreSQL |0x6C |0x6D |0x6E |0x6F |
|
||||
|Navicat Oracle |0x70 |0x71 |0x72 |0x73 |
|
||||
|Navicat SQL Server |0x74 |0x75 |0x76 |0x77 |
|
||||
|Navicat SQLite |0x78 |0x79 |0x7A |0x7B |
|
||||
|Navicat MariaDB |0x7C |0x7D |0x7E |0x7F |
|
||||
|Navicat MongoDB |0x80 |0x81 |0x82 | |
|
||||
|
||||
5. __data[8]__ 的高4位代表 __版本号__。低4位未知,但可以用来延长激活期限,可取的值有`0000`和`0001`。
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
* `capstone[x86]:x64-windows-static`
|
||||
* `capstone[x86]:x86-windows-static`
|
||||
* `keystone:x64-windows-static`
|
||||
* `keystone:x86-windows-static`
|
||||
* `openssl-windows:x64-windows-static`
|
||||
* `openssl-windows:x86-windows-static`
|
||||
* `rapidjson:x64-windows-static`
|
||||
@@ -22,6 +24,8 @@
|
||||
```console
|
||||
$ vcpkg install capstone[x86]:x64-windows-static
|
||||
$ vcpkg install capstone[x86]:x86-windows-static
|
||||
$ vcpkg install keystone:x64-windows-static
|
||||
$ vcpkg install keystone:x86-windows-static
|
||||
$ vcpkg install openssl-windows:x64-windows-static
|
||||
$ vcpkg install openssl-windows:x86-windows-static
|
||||
$ vcpkg install rapidjson:x64-windows-static
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
* `capstone[x86]:x64-windows-static`
|
||||
* `capstone[x86]:x86-windows-static`
|
||||
* `keystone:x64-windows-static`
|
||||
* `keystone:x86-windows-static`
|
||||
* `openssl-windows:x64-windows-static`
|
||||
* `openssl-windows:x86-windows-static`
|
||||
* `rapidjson:x64-windows-static`
|
||||
@@ -18,6 +20,8 @@
|
||||
```console
|
||||
$ vcpkg install capstone[x86]:x64-windows-static
|
||||
$ vcpkg install capstone[x86]:x86-windows-static
|
||||
$ vcpkg install keystone:x64-windows-static
|
||||
$ vcpkg install keystone:x86-windows-static
|
||||
$ vcpkg install openssl-windows:x64-windows-static
|
||||
$ vcpkg install openssl-windows:x86-windows-static
|
||||
$ vcpkg install rapidjson:x64-windows-static
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
1. Switch to the path you extracted the installation package. Run Navicat, for initialization:
|
||||
|
||||
```console
|
||||
$ cd ~/navicat121_premium_en_x64 && \
|
||||
./start_navicat
|
||||
$ cd ~/navicat121_premium_en_x64
|
||||
$ ./start_navicat
|
||||
```
|
||||
|
||||
When running for the first time, you will be prompted with the following two windows, click "Cancel" to:
|
||||
@@ -30,17 +30,17 @@
|
||||
> The 64-bit executable file is downloaded here. If you use 32-bit, please download the corresponding version.
|
||||
|
||||
```console
|
||||
$ curl -O -L https://github.com/DoubleLabyrinth/navicat-keygen/releases/latest/download/navicat-keygen-for-x64.zip && \
|
||||
unzip navicat-keygen-for-x64.zip
|
||||
$ curl -O -L https://github.com/DoubleLabyrinth/navicat-keygen/releases/latest/download/navicat-keygen-for-x64.zip
|
||||
$ unzip navicat-keygen-for-x64.zip
|
||||
```
|
||||
|
||||
3. Download `navicat-pacther.sh` and `navicat-keygen.sh`:
|
||||
|
||||
```console
|
||||
$ curl -O -L https://raw.githubusercontent.com/DoubleLabyrinth/navicat-keygen/windows/bash/navicat-patcher.sh && \
|
||||
chmod +x navicat-patcher.sh && \
|
||||
curl -O -L https://raw.githubusercontent.com/DoubleLabyrinth/navicat-keygen/windows/bash/navicat-keygen.sh && \
|
||||
chmod +x navicat-keygen.sh
|
||||
$ curl -O -L https://raw.githubusercontent.com/DoubleLabyrinth/navicat-keygen/windows/bash/navicat-patcher.sh
|
||||
$ chmod +x navicat-patcher.sh
|
||||
$ curl -O -L https://raw.githubusercontent.com/DoubleLabyrinth/navicat-keygen/windows/bash/navicat-keygen.sh
|
||||
$ chmod +x navicat-keygen.sh
|
||||
```
|
||||
|
||||
4. Use `navicat-patcher.exe` to replace __Navicat Activation Public Key__ that is stored in `navicat.exe` or `libcc.dll`.
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
1. 切换到解压安装包的路径,本示例解压到了 `家目录`,运行Navicat,使其初始化环境:
|
||||
|
||||
```console
|
||||
$ cd ~/navicat121_premium_en_x64 && \
|
||||
./start_navicat
|
||||
$ cd ~/navicat121_premium_en_x64
|
||||
$ ./start_navicat
|
||||
```
|
||||
|
||||
首次启动时,会提示如下两个窗口,点击“Cancel”即可:
|
||||
@@ -28,17 +28,17 @@
|
||||
> 此处下载的是64位的可执行文件,若您使用32位,请下载对应版本
|
||||
|
||||
```console
|
||||
$ curl -O -L https://github.com/DoubleLabyrinth/navicat-keygen/releases/latest/download/navicat-keygen-for-x64.zip && \
|
||||
unzip navicat-keygen-for-x64.zip
|
||||
$ curl -O -L https://github.com/DoubleLabyrinth/navicat-keygen/releases/latest/download/navicat-keygen-for-x64.zip
|
||||
$ unzip navicat-keygen-for-x64.zip
|
||||
```
|
||||
|
||||
3. 下载 `navicat-pacther.sh` 和 `navicat-keygen.sh`:
|
||||
|
||||
```console
|
||||
$ curl -O -L https://raw.githubusercontent.com/DoubleLabyrinth/navicat-keygen/windows/bash/navicat-patcher.sh && \
|
||||
chmod +x navicat-patcher.sh && \
|
||||
curl -O -L https://raw.githubusercontent.com/DoubleLabyrinth/navicat-keygen/windows/bash/navicat-keygen.sh && \
|
||||
chmod +x navicat-keygen.sh
|
||||
$ curl -O -L https://raw.githubusercontent.com/DoubleLabyrinth/navicat-keygen/windows/bash/navicat-patcher.sh
|
||||
$ chmod +x navicat-patcher.sh
|
||||
$ curl -O -L https://raw.githubusercontent.com/DoubleLabyrinth/navicat-keygen/windows/bash/navicat-keygen.sh
|
||||
$ chmod +x navicat-keygen.sh
|
||||
```
|
||||
|
||||
4. 使用 `navicat-patcher.exe` 替换掉 `navicat.exe` 和 `libcc.dll` 里的Navicat激活公钥。
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace nkg {
|
||||
void SerialNumberGenerator::SetProductSignature(NavicatProductType ProductType) noexcept {
|
||||
switch (ProductType) {
|
||||
case NavicatProductType::DataModeler:
|
||||
_Data[7] = 0x47;
|
||||
_Data[7] = 0x84;
|
||||
break;
|
||||
case NavicatProductType::Premium:
|
||||
_Data[7] = 0x65;
|
||||
|
||||
@@ -79,13 +79,17 @@ namespace nkg {
|
||||
}
|
||||
}
|
||||
|
||||
void CapstoneEngine::Option(cs_opt_type Type, size_t Value) {
|
||||
void CapstoneEngine::Option(cs_opt_type Type, cs_opt_value Value) {
|
||||
auto err = cs_option(Get(), Type, Value);
|
||||
if (err != CS_ERR_OK) {
|
||||
throw CapstoneError(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), err, TEXT("cs_option failed."));
|
||||
}
|
||||
}
|
||||
|
||||
const char* CapstoneEngine::GetRegisterName(unsigned int reg_id) const noexcept {
|
||||
return cs_reg_name(Get(), reg_id);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
CapstoneDisassembler CapstoneEngine::CreateDisassembler() const {
|
||||
return CapstoneDisassembler(*this);
|
||||
|
||||
@@ -49,7 +49,9 @@ namespace nkg {
|
||||
|
||||
CapstoneEngine(cs_arch ArchType, cs_mode Mode);
|
||||
|
||||
void Option(cs_opt_type Type, size_t Value);
|
||||
void Option(cs_opt_type Type, cs_opt_value Value);
|
||||
|
||||
const char* GetRegisterName(unsigned int reg_id) const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
CapstoneDisassembler CreateDisassembler() const;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -64,8 +64,8 @@ namespace nkg {
|
||||
NewImage._SectionNameTable[SectionName] = i;
|
||||
}
|
||||
|
||||
NewImage._SectionAddressTable[NewImage._SectionHeaderTable[i].VirtualAddress] = i;
|
||||
NewImage._SectionOffsetTable[NewImage._SectionHeaderTable[i].PointerToRawData] = i;
|
||||
NewImage._SectionRvaTable[NewImage._SectionHeaderTable[i].VirtualAddress] = i;
|
||||
NewImage._SectionFileOffsetTable[NewImage._SectionHeaderTable[i].PointerToRawData] = i;
|
||||
}
|
||||
|
||||
if (!DisableRelocationParsing && NewImage._NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0) {
|
||||
@@ -86,14 +86,14 @@ namespace nkg {
|
||||
case IMAGE_REL_BASED_HIGH:
|
||||
case IMAGE_REL_BASED_LOW:
|
||||
case IMAGE_REL_BASED_HIGHADJ:
|
||||
NewImage._RelocationAddressTable[Rva + (RelocItems[i] & 0x0fff)] = 2;
|
||||
NewImage._RelocationRvaTable[Rva + (RelocItems[i] & 0x0fff)] = 2;
|
||||
break;
|
||||
case IMAGE_REL_BASED_HIGHLOW:
|
||||
NewImage._RelocationAddressTable[Rva + (RelocItems[i] & 0x0fff)] = 4;
|
||||
NewImage._RelocationRvaTable[Rva + (RelocItems[i] & 0x0fff)] = 4;
|
||||
break;
|
||||
#if defined(IMAGE_REL_BASED_DIR64)
|
||||
case IMAGE_REL_BASED_DIR64:
|
||||
NewImage._RelocationAddressTable[Rva + (RelocItems[i] & 0x0fff)] = 8;
|
||||
NewImage._RelocationRvaTable[Rva + (RelocItems[i] & 0x0fff)] = 8;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
@@ -179,7 +179,16 @@ namespace nkg {
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeader(PCSTR lpszSectionName) const {
|
||||
PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeader(size_t Idx) const {
|
||||
if (Idx < _NtHeaders->FileHeader.NumberOfSections) {
|
||||
return _SectionHeaderTable + Idx;
|
||||
} else {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Idx is out of range."));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeaderByName(PCSTR lpszSectionName) const {
|
||||
uint64_t NameValue = 0;
|
||||
|
||||
for (int i = 0; i < sizeof(NameValue) && lpszSectionName[i]; ++i)
|
||||
@@ -196,9 +205,9 @@ namespace nkg {
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeader(uintptr_t Rva) const {
|
||||
auto it = _SectionAddressTable.upper_bound(Rva);
|
||||
if (it != _SectionAddressTable.begin()) {
|
||||
PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeaderByRva(uintptr_t Rva) const {
|
||||
auto it = _SectionRvaTable.upper_bound(Rva);
|
||||
if (it != _SectionRvaTable.begin()) {
|
||||
--it;
|
||||
}
|
||||
|
||||
@@ -215,15 +224,14 @@ namespace nkg {
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t ImageInterpreter::RvaToFileOffset(uintptr_t Rva) const {
|
||||
auto SectionHeader = ImageSectionHeader(Rva);
|
||||
return SectionHeader->PointerToRawData + (Rva - static_cast<uintptr_t>(SectionHeader->VirtualAddress));
|
||||
PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeaderByVa(uintptr_t Va) const {
|
||||
return ImageSectionHeaderByRva(Va - _NtHeaders->OptionalHeader.ImageBase);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t ImageInterpreter::FileOffsetToRva(uintptr_t FileOffset) const {
|
||||
auto it = _SectionOffsetTable.upper_bound(FileOffset);
|
||||
if (it != _SectionOffsetTable.begin()) {
|
||||
PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeaderByFileOffset(uintptr_t FileOffset) const {
|
||||
auto it = _SectionFileOffsetTable.upper_bound(FileOffset);
|
||||
if (it != _SectionFileOffsetTable.begin()) {
|
||||
--it;
|
||||
}
|
||||
|
||||
@@ -232,23 +240,65 @@ namespace nkg {
|
||||
uintptr_t SectionFileOffsetEnd = SectionFileOffsetBegin + SectionHeader->SizeOfRawData;
|
||||
|
||||
if (SectionFileOffsetBegin <= FileOffset && FileOffset < SectionFileOffsetEnd) {
|
||||
return SectionHeader->VirtualAddress + (FileOffset - SectionHeader->PointerToRawData);
|
||||
return SectionHeader;
|
||||
} else {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Target section header is not found."))
|
||||
.AddHint(std::xstring::format(TEXT("FileOffset = 0x%zx"), FileOffset));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t ImageInterpreter::RvaToVa(uintptr_t Rva) const noexcept {
|
||||
return Rva + _NtHeaders->OptionalHeader.ImageBase;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t ImageInterpreter::RvaToFileOffset(uintptr_t Rva) const {
|
||||
auto SectionHeader = ImageSectionHeaderByRva(Rva);
|
||||
return SectionHeader->PointerToRawData + (Rva - static_cast<uintptr_t>(SectionHeader->VirtualAddress));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t ImageInterpreter::FileOffsetToRva(uintptr_t FileOffset) const {
|
||||
auto SectionHeader = ImageSectionHeaderByFileOffset(FileOffset);
|
||||
return SectionHeader->VirtualAddress + (FileOffset - SectionHeader->PointerToRawData);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t ImageInterpreter::FileOffsetToVa(uintptr_t FileOffset) const {
|
||||
return FileOffsetToRva(FileOffset) + _NtHeaders->OptionalHeader.ImageBase;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t ImageInterpreter::VaToRva(uintptr_t Va) const noexcept {
|
||||
return Va - _NtHeaders->OptionalHeader.ImageBase;
|
||||
}
|
||||
[[nodiscard]]
|
||||
uintptr_t ImageInterpreter::VaToFileOffset(uintptr_t Va) const {
|
||||
return ImageSectionHeaderByVa(Va)->PointerToRawData;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool ImageInterpreter::IsRvaRangeInRelocTable(uintptr_t Rva, size_t Size) const {
|
||||
auto it = _RelocationAddressTable.upper_bound(Rva);
|
||||
if (it != _RelocationAddressTable.begin()) {
|
||||
auto it = _RelocationRvaTable.upper_bound(Rva);
|
||||
if (it != _RelocationRvaTable.begin()) {
|
||||
--it;
|
||||
}
|
||||
|
||||
return it->first <= Rva && Rva < it->first + it->second;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool ImageInterpreter::IsVaRangeInRelocTable(uintptr_t Va, size_t Size) const {
|
||||
return IsRvaRangeInRelocTable(VaToRva(Va), Size);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool ImageInterpreter::IsFileOffsetRangeInRelocTable(uintptr_t FileOffset, size_t Size) const {
|
||||
return IsRvaRangeInRelocTable(FileOffsetToRva(FileOffset), Size);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
DWORD ImageInterpreter::ImageFileMajorVersion() const {
|
||||
if (_VsFixedFileInfo) {
|
||||
return _VsFixedFileInfo->dwFileVersionMS;
|
||||
@@ -257,6 +307,7 @@ namespace nkg {
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
DWORD ImageInterpreter::ImageFileMinorVersion() const {
|
||||
if (_VsFixedFileInfo) {
|
||||
return _VsFixedFileInfo->dwFileVersionLS;
|
||||
@@ -265,6 +316,7 @@ namespace nkg {
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
DWORD ImageInterpreter::ImageProductMajorVersion() const {
|
||||
if (_VsFixedFileInfo) {
|
||||
return _VsFixedFileInfo->dwProductVersionMS;
|
||||
@@ -273,6 +325,7 @@ namespace nkg {
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
DWORD ImageInterpreter::ImageProductMinorVersion() const {
|
||||
if (_VsFixedFileInfo) {
|
||||
return _VsFixedFileInfo->dwProductVersionLS;
|
||||
@@ -280,5 +333,10 @@ namespace nkg {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Image does not have version info."));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
size_t ImageInterpreter::NumberOfSections() const noexcept {
|
||||
return _NtHeaders->FileHeader.NumberOfSections;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace nkg {
|
||||
PIMAGE_NT_HEADERS _NtHeaders;
|
||||
PIMAGE_SECTION_HEADER _SectionHeaderTable;
|
||||
std::map<uint64_t, size_t> _SectionNameTable;
|
||||
std::map<uintptr_t, size_t> _SectionAddressTable;
|
||||
std::map<uintptr_t, size_t> _SectionOffsetTable;
|
||||
std::map<uintptr_t, size_t> _RelocationAddressTable;
|
||||
std::map<uintptr_t, size_t> _SectionRvaTable;
|
||||
std::map<uintptr_t, size_t> _SectionFileOffsetTable;
|
||||
std::map<uintptr_t, size_t> _RelocationRvaTable;
|
||||
VS_FIXEDFILEINFO* _VsFixedFileInfo;
|
||||
|
||||
ImageInterpreter();
|
||||
@@ -57,33 +57,48 @@ namespace nkg {
|
||||
PIMAGE_SECTION_HEADER ImageSectionTable() const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageSectionHeader(PCSTR lpszSectionName) const;
|
||||
PIMAGE_SECTION_HEADER ImageSectionHeader(size_t Idx) const;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageSectionHeader(uintptr_t Rva) const;
|
||||
PIMAGE_SECTION_HEADER ImageSectionHeaderByName(PCSTR lpszSectionName) const;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageSectionHeaderByRva(uintptr_t Rva) const;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageSectionHeaderByVa(uintptr_t Va) const;
|
||||
|
||||
[[nodiscard]]
|
||||
PIMAGE_SECTION_HEADER ImageSectionHeaderByFileOffset(uintptr_t FileOffset) const;
|
||||
|
||||
template<typename __PtrType = PVOID>
|
||||
[[nodiscard]]
|
||||
__PtrType ImageSectionView(PCSTR lpszSectionName, size_t Offset = 0) const {
|
||||
return ImageOffset<__PtrType>(ImageSectionHeader(lpszSectionName)->PointerToRawData + Offset);
|
||||
}
|
||||
|
||||
template<typename __PtrType = PVOID>
|
||||
[[nodiscard]]
|
||||
__PtrType ImageSectionView(PIMAGE_SECTION_HEADER SectionHeader, size_t Offset = 0) const {
|
||||
__PtrType ImageSectionView(PIMAGE_SECTION_HEADER SectionHeader, size_t Offset = 0) const noexcept {
|
||||
return ImageOffset<__PtrType>(SectionHeader->PointerToRawData + Offset);
|
||||
}
|
||||
|
||||
template<typename __ReturnType, typename __Hint>
|
||||
template<typename __PtrType = PVOID>
|
||||
[[nodiscard]]
|
||||
__ReturnType SearchSection(PCSTR lpszSectionName, __Hint&& Hint) const {
|
||||
return SearchSection<__ReturnType>(ImageSectionHeader(lpszSectionName), std::forward<__Hint>(Hint));
|
||||
__PtrType ImageSectionViewByName(PCSTR lpszSectionName, size_t Offset = 0) const {
|
||||
return ImageOffset<__PtrType>(ImageSectionHeaderByName(lpszSectionName)->PointerToRawData + Offset);
|
||||
}
|
||||
|
||||
template<typename __ReturnType, typename __Hint>
|
||||
template<typename __PtrType = PVOID>
|
||||
[[nodiscard]]
|
||||
__ReturnType SearchSection(PCSTR lpszSectionName, size_t Offset, __Hint&& Hint) const {
|
||||
return SearchSection<__ReturnType>(ImageSectionHeader(lpszSectionName), Offset, std::forward<__Hint>(Hint));
|
||||
__PtrType ImageSectionViewByRva(uintptr_t Rva, size_t Offset = 0) const {
|
||||
return ImageOffset<__PtrType>(ImageSectionHeaderByRva(Rva)->PointerToRawData + Offset);
|
||||
}
|
||||
|
||||
template<typename __PtrType = PVOID>
|
||||
[[nodiscard]]
|
||||
__PtrType ImageSectionViewByVa(uintptr_t Va, size_t Offset = 0) const {
|
||||
return ImageOffset<__PtrType>(ImageSectionHeaderByVa(Va)->PointerToRawData + Offset);
|
||||
}
|
||||
|
||||
template<typename __PtrType = PVOID>
|
||||
[[nodiscard]]
|
||||
__PtrType ImageSectionViewByFileOffset(uintptr_t FileOffset, size_t Offset = 0) const {
|
||||
return ImageOffset<__PtrType>(ImageSectionHeaderByFileOffset(FileOffset)->PointerToRawData + Offset);
|
||||
}
|
||||
|
||||
template<typename __ReturnType, typename __Hint>
|
||||
@@ -120,11 +135,23 @@ namespace nkg {
|
||||
throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Data is not found."));
|
||||
}
|
||||
|
||||
template<typename __ReturnType, typename __Hint>
|
||||
[[nodiscard]]
|
||||
uintptr_t RvaToFileOffset(uintptr_t Rva) const;
|
||||
__ReturnType SearchSection(PCSTR lpszSectionName, __Hint&& Hint) const {
|
||||
return SearchSection<__ReturnType>(ImageSectionHeaderByName(lpszSectionName), std::forward<__Hint>(Hint));
|
||||
}
|
||||
|
||||
template<typename __ReturnType, typename __Hint>
|
||||
[[nodiscard]]
|
||||
__ReturnType SearchSection(PCSTR lpszSectionName, size_t Offset, __Hint&& Hint) const {
|
||||
return SearchSection<__ReturnType>(ImageSectionHeaderByName(lpszSectionName), Offset, std::forward<__Hint>(Hint));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t FileOffsetToRva(uintptr_t FileOffset) const;
|
||||
uintptr_t RvaToVa(uintptr_t Rva) const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t RvaToFileOffset(uintptr_t Rva) const;
|
||||
|
||||
template<typename __PtrType = PVOID>
|
||||
[[nodiscard]]
|
||||
@@ -133,12 +160,11 @@ namespace nkg {
|
||||
return ImageOffset<__PtrType>(RvaToFileOffset(Rva));
|
||||
}
|
||||
|
||||
template<typename __PtrType>
|
||||
[[nodiscard]]
|
||||
uintptr_t PointerToRva(__PtrType Ptr) const {
|
||||
static_assert(std::is_pointer_v<__PtrType>);
|
||||
return FileOffsetToRva(reinterpret_cast<const volatile char*>(Ptr) - reinterpret_cast<const volatile char*>(_DosHeader));
|
||||
}
|
||||
uintptr_t FileOffsetToRva(uintptr_t FileOffset) const;
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t FileOffsetToVa(uintptr_t FileOffset) const;
|
||||
|
||||
template<typename __PtrType>
|
||||
[[nodiscard]]
|
||||
@@ -146,6 +172,18 @@ namespace nkg {
|
||||
return ImageOffset<__PtrType>(FileOffset);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t VaToRva(uintptr_t Va) const noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
uintptr_t VaToFileOffset(uintptr_t Va) const;
|
||||
|
||||
template<typename __PtrType>
|
||||
[[nodiscard]]
|
||||
__PtrType VaToPointer(uintptr_t Va) const noexcept {
|
||||
return RvaToPointer<__PtrType>(VaToRva(Va));
|
||||
}
|
||||
|
||||
template<typename __PtrType>
|
||||
[[nodiscard]]
|
||||
uintptr_t PointerToFileOffset(__PtrType Ptr) const noexcept {
|
||||
@@ -153,9 +191,33 @@ namespace nkg {
|
||||
return reinterpret_cast<const volatile char*>(Ptr) - reinterpret_cast<const volatile char*>(_DosHeader);
|
||||
}
|
||||
|
||||
template<typename __PtrType>
|
||||
[[nodiscard]]
|
||||
uintptr_t PointerToRva(__PtrType Ptr) const {
|
||||
return FileOffsetToRva(PointerToFileOffset(Ptr));
|
||||
}
|
||||
|
||||
template<typename __PtrType>
|
||||
[[nodiscard]]
|
||||
uintptr_t PointerToVa(__PtrType Ptr) const {
|
||||
return FileOffsetToVa(PointerToFileOffset(Ptr));
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool IsRvaRangeInRelocTable(uintptr_t Rva, size_t Size) const;
|
||||
|
||||
[[nodiscard]]
|
||||
bool IsVaRangeInRelocTable(uintptr_t Va, size_t Size) const;
|
||||
|
||||
[[nodiscard]]
|
||||
bool IsFileOffsetRangeInRelocTable(uintptr_t FileOffset, size_t Size) const;
|
||||
|
||||
template<typename __PtrType>
|
||||
[[nodiscard]]
|
||||
bool IsFileOffsetRangeInRelocTable(__PtrType Ptr, size_t Size) const {
|
||||
return IsRvaRangeInRelocTable(PointerToRva(Ptr), Size);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
DWORD ImageFileMajorVersion() const;
|
||||
|
||||
@@ -167,6 +229,9 @@ namespace nkg {
|
||||
|
||||
[[nodiscard]]
|
||||
DWORD ImageProductMinorVersion() const;
|
||||
|
||||
[[nodiscard]]
|
||||
size_t NumberOfSections() const noexcept;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -55,8 +55,8 @@ namespace nkg {
|
||||
[[nodiscard]]
|
||||
bool PatchSolution1::FindPatchOffset() noexcept {
|
||||
try {
|
||||
PIMAGE_SECTION_HEADER SectionHeader_text = _Image.ImageSectionHeader(".text");
|
||||
PIMAGE_SECTION_HEADER SectionHeader_rdata = _Image.ImageSectionHeader(".rdata");
|
||||
PIMAGE_SECTION_HEADER SectionHeader_text = _Image.ImageSectionHeaderByName(".text");
|
||||
PIMAGE_SECTION_HEADER SectionHeader_rdata = _Image.ImageSectionHeaderByName(".rdata");
|
||||
const uint8_t* pbPatch[_countof(_PatchOffset)] = {};
|
||||
|
||||
pbPatch[0] = _Image.SearchSection<const uint8_t*>(SectionHeader_rdata, [](const uint8_t* p) {
|
||||
|
||||
@@ -429,7 +429,7 @@ print('};')
|
||||
[[nodiscard]]
|
||||
bool PatchSolution2::FindPatchOffset() noexcept {
|
||||
try {
|
||||
auto SectionHeader_text = _Image.ImageSectionHeader(".text");
|
||||
auto SectionHeader_text = _Image.ImageSectionHeaderByName(".text");
|
||||
auto SectionView_text = _Image.ImageSectionView<const uint8_t*>(SectionHeader_text);
|
||||
const uint8_t* lpPatch[_countof(_PatchOffset)] = {};
|
||||
|
||||
|
||||
@@ -437,7 +437,7 @@ print('};')
|
||||
bool PatchSolution2::FindPatchOffset() noexcept {
|
||||
|
||||
try {
|
||||
auto SectionHeader_text = _Image.ImageSectionHeader(".text");
|
||||
auto SectionHeader_text = _Image.ImageSectionHeaderByName(".text");
|
||||
auto SectionView_text = _Image.ImageSectionView<const uint8_t*>(SectionHeader_text);
|
||||
const uint8_t* lpPatch[_countof(_PatchOffset)] = {};
|
||||
|
||||
|
||||
@@ -323,7 +323,7 @@ namespace nkg {
|
||||
}
|
||||
|
||||
size_t PublicKeyReadCursor = 0;
|
||||
auto SectionHeader_rdata = _Image.ImageSectionHeader(".rdata");
|
||||
auto SectionHeader_rdata = _Image.ImageSectionHeaderByName(".rdata");
|
||||
auto SectionView_rdata = _Image.ImageSectionView(SectionHeader_rdata);
|
||||
|
||||
for (size_t i = 0; i < _countof(_Patch); PublicKeyReadCursor += Keyword[i].Size, ++i) {
|
||||
|
||||
@@ -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(""));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
static void Welcome() {
|
||||
_putts(TEXT("***************************************************"));
|
||||
_putts(TEXT("* Navicat Patcher by @DoubleLabyrinth *"));
|
||||
_putts(TEXT("* Version: 4.0 *"));
|
||||
_putts(TEXT("* Version: 4.1 *"));
|
||||
_putts(TEXT("***************************************************"));
|
||||
_putts(TEXT(""));
|
||||
_putts(TEXT("Press Enter to continue or Ctrl + C to abort."));
|
||||
@@ -29,7 +29,7 @@ static void Welcome() {
|
||||
static void Help() {
|
||||
_putts(TEXT("***************************************************"));
|
||||
_putts(TEXT("* Navicat Patcher by @DoubleLabyrinth *"));
|
||||
_putts(TEXT("* Version: 4.0 *"));
|
||||
_putts(TEXT("* Version: 4.1 *"));
|
||||
_putts(TEXT("***************************************************"));
|
||||
_putts(TEXT(""));
|
||||
_putts(TEXT("Usage:"));
|
||||
@@ -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(
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user