Remove all old solutions
This commit is contained in:
parent
44d33cac08
commit
84b20b3b0e
@ -1,142 +0,0 @@
|
|||||||
#include "def.hpp"
|
|
||||||
|
|
||||||
// The following APIs are in version.lib
|
|
||||||
// GetFileVersionInfoSize
|
|
||||||
// GetFileVersionInfo
|
|
||||||
// VerQueryValue
|
|
||||||
// #pragma comment(lib, "version.lib")
|
|
||||||
|
|
||||||
namespace Patcher {
|
|
||||||
|
|
||||||
const char Solution0::Keyword[461] =
|
|
||||||
"-----BEGIN PUBLIC KEY-----\r\n"
|
|
||||||
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I\r\n"
|
|
||||||
"qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv\r\n"
|
|
||||||
"a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF\r\n"
|
|
||||||
"R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2\r\n"
|
|
||||||
"WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt\r\n"
|
|
||||||
"YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ\r\n"
|
|
||||||
"awIDAQAB\r\n"
|
|
||||||
"-----END PUBLIC KEY-----\r\n";
|
|
||||||
|
|
||||||
bool Solution0::FindPatchOffset() noexcept {
|
|
||||||
bool bFound = false;
|
|
||||||
|
|
||||||
PIMAGE_SECTION_HEADER pResourceSection =
|
|
||||||
Helper::ImageSectionHeader(pTargetFile->GetView<uint8_t>(), ".rsrc");
|
|
||||||
|
|
||||||
if (pResourceSection == nullptr)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint8_t* pResourceSectionData =
|
|
||||||
pTargetFile->GetView<uint8_t>() + pResourceSection->PointerToRawData;
|
|
||||||
|
|
||||||
for (DWORD i = 0; i < pResourceSection->SizeOfRawData; ++i) {
|
|
||||||
if (memcmp(pResourceSectionData + i, Keyword, KeywordLength) == 0) {
|
|
||||||
PatchOffset = pResourceSection->PointerToRawData + i;
|
|
||||||
bFound = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bFound)
|
|
||||||
_tprintf_s(TEXT("MESSAGE: [Solution0] Keyword has been found: offset = +0x%08lx.\n"), PatchOffset);
|
|
||||||
return bFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Solution0::MakePatch(RSACipher* cipher) const {
|
|
||||||
uint8_t* lpTargetFileView = pTargetFile->GetView<uint8_t>();
|
|
||||||
std::string RSAPublicKeyPEM;
|
|
||||||
|
|
||||||
RSAPublicKeyPEM =
|
|
||||||
cipher->ExportKeyString<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
|
|
||||||
if (RSAPublicKeyPEM.empty()) {
|
|
||||||
REPORT_ERROR("ERROR: cipher->ExportKeyString failed.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// lambda function, replace '\n' to '\r\n'
|
|
||||||
[](std::string& str, const std::string& OldSub, const std::string& NewSub) {
|
|
||||||
std::string::size_type pos = 0;
|
|
||||||
std::string::size_type srclen = OldSub.size();
|
|
||||||
std::string::size_type dstlen = NewSub.size();
|
|
||||||
|
|
||||||
while ((pos = str.find(OldSub, pos)) != std::string::npos) {
|
|
||||||
str.replace(pos, srclen, NewSub);
|
|
||||||
pos += dstlen;
|
|
||||||
}
|
|
||||||
} (RSAPublicKeyPEM, "\n", "\r\n");
|
|
||||||
|
|
||||||
if (RSAPublicKeyPEM.length() != KeywordLength) {
|
|
||||||
REPORT_ERROR("ERROR: Public key length does not match.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRINT_MESSAGE("//");
|
|
||||||
PRINT_MESSAGE("// Begin Solution0");
|
|
||||||
PRINT_MESSAGE("//");
|
|
||||||
_tprintf_s(TEXT("@+0x%08X\nPrevious:\n"), PatchOffset);
|
|
||||||
Helper::PrintMemory(lpTargetFileView + PatchOffset,
|
|
||||||
lpTargetFileView + PatchOffset + KeywordLength,
|
|
||||||
lpTargetFileView);
|
|
||||||
|
|
||||||
memcpy(lpTargetFileView + PatchOffset, RSAPublicKeyPEM.c_str(), KeywordLength);
|
|
||||||
|
|
||||||
PRINT_MESSAGE("After:");
|
|
||||||
Helper::PrintMemory(lpTargetFileView + PatchOffset,
|
|
||||||
lpTargetFileView + PatchOffset + KeywordLength,
|
|
||||||
lpTargetFileView);
|
|
||||||
PRINT_MESSAGE("");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DWORD Solution0::GetMainAppVersion(LPDWORD lpMajorVer, LPDWORD lpMinorVer) {
|
|
||||||
// BOOL bSuccess = FALSE;
|
|
||||||
// DWORD dwLastError = ERROR_SUCCESS;
|
|
||||||
// std::Tstring TargetFileFullName = InstallationPath + MainAppName;
|
|
||||||
//
|
|
||||||
// DWORD dwSize = 0;
|
|
||||||
// PVOID lpData = NULL;
|
|
||||||
// VS_FIXEDFILEINFO* lpVersionInfo = NULL;
|
|
||||||
// UINT VersionInfoSize = 0;
|
|
||||||
//
|
|
||||||
// dwSize = GetFileVersionInfoSize(TargetFileFullName.c_str(),
|
|
||||||
// &dwSize); // MSDN doesn't say it can be NULL.
|
|
||||||
// // so I use dwSize to receive this deprecated value
|
|
||||||
// if (dwSize == 0) {
|
|
||||||
// dwLastError = GetLastError();
|
|
||||||
// REPORT_ERROR_WITH_CODE("ERROR: GetFileVersionInfoSize failed.", dwLastError);
|
|
||||||
// goto ON_Solution0_GetMainAppVersion_ERROR;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// lpData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
|
|
||||||
// if (lpData == nullptr) {
|
|
||||||
// dwLastError = GetLastError();
|
|
||||||
// REPORT_ERROR_WITH_CODE("ERROR: HeapAlloc failed.", dwLastError);
|
|
||||||
// goto ON_Solution0_GetMainAppVersion_ERROR;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (!GetFileVersionInfo(TargetFileFullName.c_str(), NULL, dwSize, lpData)) {
|
|
||||||
// dwLastError = GetLastError();
|
|
||||||
// REPORT_ERROR_WITH_CODE("ERROR: GetFileVersionInfo failed.", dwLastError);
|
|
||||||
// goto ON_Solution0_GetMainAppVersion_ERROR;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (!VerQueryValue(lpData, TEXT("\\"), reinterpret_cast<LPVOID*>(&lpVersionInfo), &VersionInfoSize)) {
|
|
||||||
// dwLastError = GetLastError();
|
|
||||||
// REPORT_ERROR_WITH_CODE("ERROR: VerQueryValue failed.", dwLastError);
|
|
||||||
// goto ON_Solution0_GetMainAppVersion_ERROR;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// *lpMajorVer = lpVersionInfo->dwProductVersionMS;
|
|
||||||
// *lpMinorVer = lpVersionInfo->dwProductVersionLS;
|
|
||||||
//
|
|
||||||
// bSuccess = TRUE;
|
|
||||||
// ON_Solution0_GetMainAppVersion_ERROR:
|
|
||||||
// if (lpData)
|
|
||||||
// HeapFree(GetProcessHeap(), NULL, lpData);
|
|
||||||
// return bSuccess;
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,311 +0,0 @@
|
|||||||
#include "def.hpp"
|
|
||||||
|
|
||||||
namespace Patcher {
|
|
||||||
|
|
||||||
const char* Solution1::Keywords[5] = {
|
|
||||||
"D75125B70767B94145B47C1CB3C0755E"
|
|
||||||
"7CCB8825C5DCE0C58ACF944E08280140"
|
|
||||||
"9A02472FAFFD1CD77864BB821AE36766"
|
|
||||||
"FEEDE6A24F12662954168BFA314BD950"
|
|
||||||
"32B9D82445355ED7BC0B880887D650F5",
|
|
||||||
|
|
||||||
"\xfe\xea\xbc\x01",
|
|
||||||
|
|
||||||
"E1CED09B9C2186BF71A70C0FE2F1E0AE"
|
|
||||||
"F3BD6B75277AAB20DFAF3D110F75912B"
|
|
||||||
"FB63AC50EC4C48689D1502715243A79F"
|
|
||||||
"39FF2DE2BF15CE438FF885745ED54573"
|
|
||||||
"850E8A9F40EE2FF505EB7476F95ADB78"
|
|
||||||
"3B28CA374FAC4632892AB82FB3BF4715"
|
|
||||||
"FCFE6E82D03731FC3762B6AAC3DF1C3B"
|
|
||||||
"C646FE9CD3C62663A97EE72DB932A301"
|
|
||||||
"312B4A7633100C8CC357262C39A2B3A6"
|
|
||||||
"4B224F5276D5EDBDF0804DC3AC4B8351"
|
|
||||||
"62BB1969EAEBADC43D2511D6E0239287"
|
|
||||||
"81B167A48273B953378D3D2080CC0677"
|
|
||||||
"7E8A2364F0234B81064C5C739A8DA28D"
|
|
||||||
"C5889072BF37685CBC94C2D31D0179AD"
|
|
||||||
"86D8E3AA8090D4F0B281BE37E0143746"
|
|
||||||
"E6049CCC06899401264FA471C016A96C"
|
|
||||||
"79815B55BBC26B43052609D9D175FBCD"
|
|
||||||
"E455392F10E51EC162F51CF732E6BB39"
|
|
||||||
"1F56BBFD8D957DF3D4C55B71CEFD54B1"
|
|
||||||
"9C16D458757373E698D7E693A8FC3981"
|
|
||||||
"5A8BF03BA05EA8C8778D38F9873D62B4"
|
|
||||||
"460F41ACF997C30E7C3AF025FA171B5F"
|
|
||||||
"5AD4D6B15E95C27F6B35AD61875E5505"
|
|
||||||
"449B4E",
|
|
||||||
|
|
||||||
"\x59\x08\x01\x00",
|
|
||||||
|
|
||||||
"92933"
|
|
||||||
};
|
|
||||||
|
|
||||||
const int Solution1::KeywordsLength[5] = {
|
|
||||||
160,
|
|
||||||
4,
|
|
||||||
742,
|
|
||||||
4,
|
|
||||||
5
|
|
||||||
};
|
|
||||||
|
|
||||||
bool Solution1::CheckKey(RSACipher* cipher) const noexcept {
|
|
||||||
BOOL bOk = FALSE;
|
|
||||||
std::string RSAPublicKeyPEM;
|
|
||||||
|
|
||||||
RSAPublicKeyPEM =
|
|
||||||
cipher->ExportKeyString<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
|
|
||||||
if (RSAPublicKeyPEM.empty()) {
|
|
||||||
REPORT_ERROR("ERROR: cipher->ExportKeyString failed.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
[](std::string& str, const std::string& OldSub, const std::string& NewSub) {
|
|
||||||
std::string::size_type pos = 0;
|
|
||||||
std::string::size_type srclen = OldSub.size();
|
|
||||||
std::string::size_type dstlen = NewSub.size();
|
|
||||||
|
|
||||||
while ((pos = str.find(OldSub, pos)) != std::string::npos) {
|
|
||||||
str.replace(pos, srclen, NewSub);
|
|
||||||
pos += dstlen;
|
|
||||||
}
|
|
||||||
} (RSAPublicKeyPEM, "\n", "\r\n"); // replace '\n' to '\r\n'
|
|
||||||
|
|
||||||
std::string encrypted_pem_text = Helper::EncryptPublicKey(RSAPublicKeyPEM);
|
|
||||||
|
|
||||||
if (encrypted_pem_text[160] > '9' || encrypted_pem_text[160] < '1')
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (int i = 1; i < 8; ++i)
|
|
||||||
if (encrypted_pem_text[160 + i] > '9' || encrypted_pem_text[160 + i] < '0')
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (encrypted_pem_text[910] > '9' || encrypted_pem_text[910] < '1')
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (int i = 1; i < 5; ++i)
|
|
||||||
if (encrypted_pem_text[910 + i] > '9' || encrypted_pem_text[910 + i] < '0')
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Solution1::FindPatchOffset() noexcept {
|
|
||||||
PIMAGE_SECTION_HEADER textSection = nullptr;
|
|
||||||
PIMAGE_SECTION_HEADER rdataSection = nullptr;
|
|
||||||
|
|
||||||
uint8_t* pTargetFileView = pTargetFile->GetView<uint8_t>();
|
|
||||||
off_t Offsets[5] = { -1, -1, -1, -1, -1 };
|
|
||||||
|
|
||||||
textSection = Helper::ImageSectionHeader(pTargetFileView, ".text");
|
|
||||||
if (textSection == nullptr) {
|
|
||||||
// REPORT_ERROR("ERROR: Cannot find .text section.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
rdataSection = Helper::ImageSectionHeader(pTargetFileView, ".rdata");
|
|
||||||
if (textSection == nullptr) {
|
|
||||||
// REPORT_ERROR("ERROR: Cannot find .rdata section.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------
|
|
||||||
// try to search Keywords[0]
|
|
||||||
// -------------------------
|
|
||||||
for (DWORD i = 0; i < rdataSection->SizeOfRawData; ++i) {
|
|
||||||
if (memcmp(pTargetFileView + rdataSection->PointerToRawData + i, Keywords[0], KeywordsLength[0]) == 0) {
|
|
||||||
Offsets[0] = rdataSection->PointerToRawData + i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Offsets[0] == -1) {
|
|
||||||
// REPORT_ERROR("ERROR: Cannot find Keywords[0].");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------
|
|
||||||
// try to search Keywords[2]
|
|
||||||
// -------------------------
|
|
||||||
for (DWORD i = 0; i < rdataSection->SizeOfRawData; ++i) {
|
|
||||||
if (memcmp(pTargetFileView + rdataSection->PointerToRawData + i, Keywords[2], KeywordsLength[2]) == 0) {
|
|
||||||
Offsets[2] = rdataSection->PointerToRawData + i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Offsets[2] == -1) {
|
|
||||||
// REPORT_ERROR("ERROR: Cannot find Keywords[2].");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------
|
|
||||||
// try to search Keywords[4]
|
|
||||||
// -------------------------
|
|
||||||
for (DWORD i = 0; i < rdataSection->SizeOfRawData; ++i) {
|
|
||||||
if (memcmp((uint8_t*)pTargetFileView + rdataSection->PointerToRawData + i, Keywords[4], KeywordsLength[4]) == 0) {
|
|
||||||
Offsets[4] = rdataSection->PointerToRawData + i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Offsets[4] == -1) {
|
|
||||||
// REPORT_ERROR("ERROR: Cannot find Keywords[4].");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------
|
|
||||||
// try to search Keywords[1] and Keywords[3]
|
|
||||||
// -------------------------
|
|
||||||
for (DWORD i = 0; i < textSection->SizeOfRawData; ++i) {
|
|
||||||
if (memcmp(pTargetFileView + textSection->PointerToRawData + i, Keywords[1], KeywordsLength[1]) == 0) {
|
|
||||||
|
|
||||||
// Keywords[3] must be close to Keywords[1]
|
|
||||||
for (DWORD j = i - 64; j < i + 64; ++j) {
|
|
||||||
if (memcmp(pTargetFileView + textSection->PointerToRawData + j, Keywords[3], KeywordsLength[3]) == 0) {
|
|
||||||
Offsets[1] = textSection->PointerToRawData + i;
|
|
||||||
Offsets[3] = textSection->PointerToRawData + j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Offsets[1] and Offsets[3] are set synchronously
|
|
||||||
// so check Offsets[1] is enough
|
|
||||||
if (Offsets[1] != -1)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Offsets[1] == -1) {
|
|
||||||
// REPORT_ERROR("ERROR: Cannot find Keywords[1] and Keywords[3].");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PatchOffsets[0] = Offsets[0];
|
|
||||||
PatchOffsets[1] = Offsets[1];
|
|
||||||
PatchOffsets[2] = Offsets[2];
|
|
||||||
PatchOffsets[3] = Offsets[3];
|
|
||||||
PatchOffsets[4] = Offsets[4];
|
|
||||||
_tprintf_s(TEXT("MESSAGE: [Solution1] Keywords[0] has been found: offset = +0x%08lx.\n"), PatchOffsets[0]);
|
|
||||||
_tprintf_s(TEXT("MESSAGE: [Solution1] Keywords[1] has been found: offset = +0x%08lx.\n"), PatchOffsets[1]);
|
|
||||||
_tprintf_s(TEXT("MESSAGE: [Solution1] Keywords[2] has been found: offset = +0x%08lx.\n"), PatchOffsets[2]);
|
|
||||||
_tprintf_s(TEXT("MESSAGE: [Solution1] Keywords[3] has been found: offset = +0x%08lx.\n"), PatchOffsets[3]);
|
|
||||||
_tprintf_s(TEXT("MESSAGE: [Solution1] Keywords[4] has been found: offset = +0x%08lx.\n"), PatchOffsets[4]);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Solution1::MakePatch(RSACipher* cipher) const {
|
|
||||||
std::string RSAPublicKeyPEM;
|
|
||||||
std::string encrypted_pem_pubkey;
|
|
||||||
uint8_t* pTargetFileView = pTargetFile->GetView<uint8_t>();
|
|
||||||
|
|
||||||
RSAPublicKeyPEM = cipher->ExportKeyString<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
|
|
||||||
if (RSAPublicKeyPEM.empty()) {
|
|
||||||
REPORT_ERROR("ERROR: cipher->ExportKeyString failed.");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
[](std::string& str, const std::string& OldSub, const std::string& NewSub) {
|
|
||||||
std::string::size_type pos = 0;
|
|
||||||
std::string::size_type srclen = OldSub.size();
|
|
||||||
std::string::size_type dstlen = NewSub.size();
|
|
||||||
|
|
||||||
while ((pos = str.find(OldSub, pos)) != std::string::npos) {
|
|
||||||
str.replace(pos, srclen, NewSub);
|
|
||||||
pos += dstlen;
|
|
||||||
}
|
|
||||||
} (RSAPublicKeyPEM, "\n", "\r\n"); // replace '\n' to '\r\n'
|
|
||||||
|
|
||||||
encrypted_pem_pubkey = Helper::EncryptPublicKey(RSAPublicKeyPEM);
|
|
||||||
|
|
||||||
// split encrypted_pem_pubkey to 5 part: |160 chars|8 chars|742 chars|5 chars|5 chars|
|
|
||||||
// | |
|
|
||||||
// \ / \ /
|
|
||||||
// imm1 imm3
|
|
||||||
std::string encrypted_pem_pubkey0(encrypted_pem_pubkey.begin(), encrypted_pem_pubkey.begin() + 160);
|
|
||||||
std::string encrypted_pem_pubkey1(encrypted_pem_pubkey.begin() + 160, encrypted_pem_pubkey.begin() + 160 + 8);
|
|
||||||
std::string encrypted_pem_pubkey2(encrypted_pem_pubkey.begin() + 160 + 8, encrypted_pem_pubkey.begin() + 160 + 8 + 742);
|
|
||||||
std::string encrypted_pem_pubkey3(encrypted_pem_pubkey.begin() + 160 + 8 + 742, encrypted_pem_pubkey.begin() + 160 + 8 + 742 + 5);
|
|
||||||
std::string encrypted_pem_pubkey4(encrypted_pem_pubkey.begin() + 160 + 8 + 742 + 5, encrypted_pem_pubkey.end());
|
|
||||||
uint32_t imm1 = std::stoul(encrypted_pem_pubkey1.c_str());
|
|
||||||
uint32_t imm3 = std::stoul(encrypted_pem_pubkey3.c_str());
|
|
||||||
|
|
||||||
PRINT_MESSAGE("//");
|
|
||||||
PRINT_MESSAGE("// Begin Solution1");
|
|
||||||
PRINT_MESSAGE("//");
|
|
||||||
|
|
||||||
// ----------------------------------
|
|
||||||
// process PatchOffsets[0]
|
|
||||||
// ----------------------------------
|
|
||||||
_tprintf_s(TEXT("@+0x%08X\nPrevious:\n"), PatchOffsets[0]);
|
|
||||||
Helper::PrintMemory(pTargetFileView + PatchOffsets[0],
|
|
||||||
pTargetFileView + PatchOffsets[0] + KeywordsLength[0],
|
|
||||||
pTargetFileView);
|
|
||||||
memcpy(pTargetFileView + PatchOffsets[0], encrypted_pem_pubkey0.c_str(), KeywordsLength[0]);
|
|
||||||
PRINT_MESSAGE("After:");
|
|
||||||
Helper::PrintMemory(pTargetFileView + PatchOffsets[0],
|
|
||||||
pTargetFileView + PatchOffsets[0] + KeywordsLength[0],
|
|
||||||
pTargetFileView);
|
|
||||||
PRINT_MESSAGE("");
|
|
||||||
|
|
||||||
// ----------------------------------
|
|
||||||
// process PatchOffsets[1]
|
|
||||||
// ----------------------------------
|
|
||||||
_tprintf_s(TEXT("@+0x%08X\nPrevious:\n"), PatchOffsets[1]);
|
|
||||||
Helper::PrintMemory(pTargetFileView + PatchOffsets[1],
|
|
||||||
pTargetFileView + PatchOffsets[1] + KeywordsLength[1],
|
|
||||||
pTargetFileView);
|
|
||||||
memcpy(pTargetFileView + PatchOffsets[1], &imm1, KeywordsLength[1]);
|
|
||||||
PRINT_MESSAGE("After:");
|
|
||||||
Helper::PrintMemory(pTargetFileView + PatchOffsets[1],
|
|
||||||
pTargetFileView + PatchOffsets[1] + KeywordsLength[1],
|
|
||||||
pTargetFileView);
|
|
||||||
PRINT_MESSAGE("");
|
|
||||||
|
|
||||||
// ----------------------------------
|
|
||||||
// process PatchOffsets[2]
|
|
||||||
// ----------------------------------
|
|
||||||
_tprintf_s(TEXT("@+0x%08X\nPrevious:\n"), PatchOffsets[2]);
|
|
||||||
Helper::PrintMemory(pTargetFileView + PatchOffsets[2],
|
|
||||||
pTargetFileView + PatchOffsets[2] + KeywordsLength[2],
|
|
||||||
pTargetFileView);
|
|
||||||
memcpy(pTargetFileView + PatchOffsets[2], encrypted_pem_pubkey2.c_str(), KeywordsLength[2]);
|
|
||||||
PRINT_MESSAGE("After:");
|
|
||||||
Helper::PrintMemory(pTargetFileView + PatchOffsets[2],
|
|
||||||
pTargetFileView + PatchOffsets[2] + KeywordsLength[2],
|
|
||||||
pTargetFileView);
|
|
||||||
PRINT_MESSAGE("");
|
|
||||||
|
|
||||||
// ----------------------------------
|
|
||||||
// process PatchOffsets[3]
|
|
||||||
// ----------------------------------
|
|
||||||
_tprintf_s(TEXT("@+0x%08X\nPrevious:\n"), PatchOffsets[3]);
|
|
||||||
Helper::PrintMemory(pTargetFileView + PatchOffsets[3],
|
|
||||||
pTargetFileView + PatchOffsets[3] + KeywordsLength[3],
|
|
||||||
pTargetFileView);
|
|
||||||
memcpy(pTargetFileView + PatchOffsets[3], &imm3, KeywordsLength[3]);
|
|
||||||
PRINT_MESSAGE("After:");
|
|
||||||
Helper::PrintMemory(pTargetFileView + PatchOffsets[3],
|
|
||||||
pTargetFileView + PatchOffsets[3] + KeywordsLength[3],
|
|
||||||
pTargetFileView);
|
|
||||||
PRINT_MESSAGE("");
|
|
||||||
|
|
||||||
// ----------------------------------
|
|
||||||
// process PatchOffsets[4]
|
|
||||||
// ----------------------------------
|
|
||||||
_tprintf_s(TEXT("@+0x%08X\nPrevious:\n"), PatchOffsets[4]);
|
|
||||||
Helper::PrintMemory(pTargetFileView + PatchOffsets[4],
|
|
||||||
pTargetFileView + PatchOffsets[4] + KeywordsLength[4],
|
|
||||||
pTargetFileView);
|
|
||||||
memcpy(pTargetFileView + PatchOffsets[4], encrypted_pem_pubkey4.c_str(), KeywordsLength[4]);
|
|
||||||
PRINT_MESSAGE("After:");
|
|
||||||
Helper::PrintMemory(pTargetFileView + PatchOffsets[4],
|
|
||||||
pTargetFileView + PatchOffsets[4] + KeywordsLength[4],
|
|
||||||
pTargetFileView);
|
|
||||||
PRINT_MESSAGE("");
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,253 +0,0 @@
|
|||||||
#include "def.hpp"
|
|
||||||
|
|
||||||
namespace Patcher {
|
|
||||||
|
|
||||||
const char Solution2::KeywordsMeta[KeywordsCount + 1] =
|
|
||||||
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw1dqF3SkCaAAmMzs889I"
|
|
||||||
"qdW9M2dIdh3jG9yPcmLnmJiGpBF4E9VHSMGe8oPAy2kJDmdNt4BcEygvssEfginv"
|
|
||||||
"a5t5jm352UAoDosUJkTXGQhpAWMF4fBmBpO3EedG62rOsqMBgmSdAyxCSPBRJIOF"
|
|
||||||
"R0QgZFbRnU0frj34fiVmgYiLuZSAmIbs8ZxiHPdp1oD4tUpvsFci4QJtYNjNnGU2"
|
|
||||||
"WPH6rvChGl1IRKrxMtqLielsvajUjyrgOC6NmymYMvZNER3htFEtL1eQbCyTfDmt"
|
|
||||||
"YyQ1Wt4Ot12lxf0wVIR5mcGN7XCXJRHOFHSf1gzXWabRSvmt1nrl7sW6cjxljuuQ"
|
|
||||||
"awIDAQAB";
|
|
||||||
|
|
||||||
uint8_t Solution2::Keywords[KeywordsCount][5];
|
|
||||||
|
|
||||||
#if defined(_M_X64)
|
|
||||||
|
|
||||||
void Solution2::BuildKeywords() noexcept {
|
|
||||||
for (size_t i = 0; i < KeywordsCount; ++i) {
|
|
||||||
Keywords[i][0] = 0x83; // Keywords[i] = asm('xor eax, KeywordsMeta[i]') +
|
|
||||||
Keywords[i][1] = 0xf0;
|
|
||||||
Keywords[i][2] = KeywordsMeta[i];
|
|
||||||
Keywords[i][3] = 0x88; // asm_prefix('mov byte ptr ds:xxxxxxxxxxxxxxxx, al')
|
|
||||||
Keywords[i][4] = 0x05;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Solution2::FindPatchOffset() noexcept {
|
|
||||||
PIMAGE_SECTION_HEADER textSection = nullptr;
|
|
||||||
uint8_t* pTargetFileView = pTargetFile->GetView<uint8_t>();
|
|
||||||
uint8_t* ptextSectionData = nullptr;
|
|
||||||
off_t Offsets[KeywordsCount];
|
|
||||||
memset(Offsets, -1, sizeof(Offsets));
|
|
||||||
|
|
||||||
textSection = Helper::ImageSectionHeader(pTargetFileView, ".text");
|
|
||||||
if (textSection == nullptr)
|
|
||||||
return false;
|
|
||||||
ptextSectionData = pTargetFileView + textSection->PointerToRawData;
|
|
||||||
|
|
||||||
BuildKeywords();
|
|
||||||
|
|
||||||
// Find offsets
|
|
||||||
{
|
|
||||||
size_t FirstKeywordCounter = 0;
|
|
||||||
uint32_t Hints[9];
|
|
||||||
DWORD PossibleRangeStart = 0xffffffff;
|
|
||||||
DWORD PossibleRangeEnd;
|
|
||||||
for (DWORD i = 0; i < textSection->SizeOfRawData; ++i) {
|
|
||||||
if (memcmp(ptextSectionData + i, Keywords[0], sizeof(Keywords[0])) == 0) {
|
|
||||||
Hints[FirstKeywordCounter++] =
|
|
||||||
*reinterpret_cast<uint32_t*>(ptextSectionData + i + sizeof(Keywords[0])) +
|
|
||||||
i + sizeof(Keywords[0]) + sizeof(uint32_t);
|
|
||||||
if (i < PossibleRangeStart)
|
|
||||||
PossibleRangeStart = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PossibleRangeStart -= 0x1000;
|
|
||||||
PossibleRangeEnd = PossibleRangeStart + 0x100000;
|
|
||||||
|
|
||||||
// Keywords[0] should occur 9 times.
|
|
||||||
// Because there's only 9 'M' chars in `KeywordsMeta`.
|
|
||||||
if (FirstKeywordCounter != 9)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Helper::QuickSort(Hints, 0, _countof(Hints));
|
|
||||||
|
|
||||||
// assert
|
|
||||||
// if not satisfied, refuse to patch
|
|
||||||
if (Hints[8] - Hints[0] != 0x18360F8F8 - 0x18360F7D0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < KeywordsCount; ++i) {
|
|
||||||
if (Offsets[i] != -1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (DWORD j = PossibleRangeStart; j < PossibleRangeEnd; ++j) {
|
|
||||||
if (memcmp(ptextSectionData + j, Keywords[i], sizeof(Keywords[i])) == 0) {
|
|
||||||
off_t index =
|
|
||||||
*reinterpret_cast<uint32_t*>(ptextSectionData + j + sizeof(Keywords[i])) +
|
|
||||||
j + sizeof(Keywords[i]) + sizeof(uint32_t) - Hints[0];
|
|
||||||
|
|
||||||
if (0 <= index && index < KeywordsCount && KeywordsMeta[index] == KeywordsMeta[i]) {
|
|
||||||
Offsets[index] = textSection->PointerToRawData + j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if not found, refuse to patch
|
|
||||||
if (Offsets[i] == -1)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static_assert(sizeof(PatchOffsets) == sizeof(Offsets), "static_assert failure!");
|
|
||||||
memcpy(PatchOffsets, Offsets, sizeof(PatchOffsets));
|
|
||||||
|
|
||||||
for (size_t i = 0; i < KeywordsCount; ++i)
|
|
||||||
_tprintf_s(TEXT("MESSAGE: [Solution2] Keywords[%zu] has been found: offset = +0x%08lx.\n"),
|
|
||||||
i, PatchOffsets[i]);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
void Solution2::BuildKeywords() noexcept {
|
|
||||||
for (size_t i = 0; i < KeywordsCount; ++i) {
|
|
||||||
switch (i % 3) {
|
|
||||||
case 0:
|
|
||||||
Keywords[i][0] = 0x83; // Keywords[i] = asm('xor edx, KeywordsMeta[i]') +
|
|
||||||
Keywords[i][1] = 0xf2;
|
|
||||||
Keywords[i][2] = KeywordsMeta[i];
|
|
||||||
Keywords[i][3] = 0x88; // asm_prefix('mov byte ptr ds:xxxxxxxx, dl')
|
|
||||||
Keywords[i][4] = 0x15;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
Keywords[i][0] = 0x83; // Keywords[i] = asm('xor eax, KeywordsMeta[i]') +
|
|
||||||
Keywords[i][1] = 0xf0;
|
|
||||||
Keywords[i][2] = KeywordsMeta[i];
|
|
||||||
Keywords[i][3] = 0xa2; // asm_prefix('mov byte ptr ds:xxxxxxxx, al')
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Keywords[i][0] = 0x83; // Keywords[i] = asm('xor ecx, KeywordsMeta[i]') +
|
|
||||||
Keywords[i][1] = 0xf1;
|
|
||||||
Keywords[i][2] = KeywordsMeta[i];
|
|
||||||
Keywords[i][3] = 0x88; // asm_prefix('mov byte ptr ds:xxxxxxxx, cl')
|
|
||||||
Keywords[i][4] = 0x0D;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Solution2::FindPatchOffset() noexcept {
|
|
||||||
PIMAGE_SECTION_HEADER textSection = nullptr;
|
|
||||||
uint8_t* pTargetFileView = pTargetFile->GetView<uint8_t>();
|
|
||||||
uint8_t* ptextSectionData = nullptr;
|
|
||||||
off_t Offsets[KeywordsCount];
|
|
||||||
memset(Offsets, -1, sizeof(Offsets));
|
|
||||||
|
|
||||||
textSection = Helper::ImageSectionHeader(pTargetFileView, ".text");
|
|
||||||
if (textSection == nullptr)
|
|
||||||
return false;
|
|
||||||
ptextSectionData = pTargetFileView + textSection->PointerToRawData;
|
|
||||||
|
|
||||||
BuildKeywords();
|
|
||||||
|
|
||||||
// Find offsets
|
|
||||||
{
|
|
||||||
size_t FirstKeywordCounter = 0;
|
|
||||||
uint32_t Hints[3];
|
|
||||||
DWORD PossibleRangeStart = 0xffffffff;
|
|
||||||
DWORD PossibleRangeEnd;
|
|
||||||
for (DWORD i = 0; i < textSection->SizeOfRawData; ++i) {
|
|
||||||
if (memcmp(ptextSectionData + i, Keywords[0], sizeof(Keywords[0])) == 0) {
|
|
||||||
Hints[FirstKeywordCounter++] =
|
|
||||||
*reinterpret_cast<uint32_t*>(ptextSectionData + i + sizeof(Keywords[0]));
|
|
||||||
if (i < PossibleRangeStart)
|
|
||||||
PossibleRangeStart = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PossibleRangeStart -= 0x1000;
|
|
||||||
PossibleRangeEnd = PossibleRangeStart + 0x100000;
|
|
||||||
|
|
||||||
// Keywords[0] should occur 3 times.
|
|
||||||
if (FirstKeywordCounter != 3)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Helper::QuickSort(Hints, 0, _countof(Hints));
|
|
||||||
|
|
||||||
// assert
|
|
||||||
// if not satisfied, refuse to patch
|
|
||||||
if (Hints[2] - Hints[0] != 0x127382BE - 0x12738210)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < KeywordsCount; ++i) {
|
|
||||||
uint8_t CurrentKeyword[9];
|
|
||||||
size_t CurrentKeywordSize = i % 3 == 1 ? 4 : 5;
|
|
||||||
memcpy(CurrentKeyword, Keywords[i], CurrentKeywordSize);
|
|
||||||
*reinterpret_cast<uint32_t*>(CurrentKeyword + CurrentKeywordSize) = Hints[0] + i;
|
|
||||||
CurrentKeywordSize += sizeof(uint32_t);
|
|
||||||
|
|
||||||
for (DWORD j = PossibleRangeStart; j < PossibleRangeEnd; ++j) {
|
|
||||||
if (memcmp(ptextSectionData + j, CurrentKeyword, CurrentKeywordSize) == 0) {
|
|
||||||
Offsets[i] = textSection->PointerToRawData + j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if not found, refuse to patch
|
|
||||||
if (Offsets[i] == -1)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static_assert(sizeof(PatchOffsets) == sizeof(Offsets), "static_assert failure!");
|
|
||||||
memcpy(PatchOffsets, Offsets, sizeof(PatchOffsets));
|
|
||||||
|
|
||||||
for (size_t i = 0; i < KeywordsCount; ++i)
|
|
||||||
_tprintf_s(TEXT("MESSAGE: [Solution2] Keywords[%zu] has been found: offset = +0x%08lx.\n"),
|
|
||||||
i, PatchOffsets[i]);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool Solution2::MakePatch(RSACipher* cipher) const {
|
|
||||||
std::string RSAPublicKeyPEM;
|
|
||||||
uint8_t* pTargetFileView = pTargetFile->GetView<uint8_t>();
|
|
||||||
|
|
||||||
RSAPublicKeyPEM = cipher->ExportKeyString<RSACipher::KeyType::PublicKey, RSACipher::KeyFormat::PEM>();
|
|
||||||
if (RSAPublicKeyPEM.empty()) {
|
|
||||||
REPORT_ERROR("ERROR: cipher->ExportKeyString failed.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RSAPublicKeyPEM.erase(RSAPublicKeyPEM.find("-----BEGIN PUBLIC KEY-----"), 26);
|
|
||||||
RSAPublicKeyPEM.erase(RSAPublicKeyPEM.find("-----END PUBLIC KEY-----"), 24);
|
|
||||||
{
|
|
||||||
std::string::size_type pos = 0;
|
|
||||||
while ((pos = RSAPublicKeyPEM.find("\n", pos)) != std::string::npos) {
|
|
||||||
RSAPublicKeyPEM.erase(pos, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RSAPublicKeyPEM.length() != KeywordsCount) {
|
|
||||||
REPORT_ERROR("ERROR: Public key length does not match.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRINT_MESSAGE("//");
|
|
||||||
PRINT_MESSAGE("// Begin Solution2");
|
|
||||||
PRINT_MESSAGE("//");
|
|
||||||
for (size_t i = 0; i < KeywordsCount; ++i) {
|
|
||||||
_tprintf_s(TEXT("@+0x%08X: %02X %02X %02X --> "),
|
|
||||||
PatchOffsets[i],
|
|
||||||
pTargetFileView[PatchOffsets[i]],
|
|
||||||
pTargetFileView[PatchOffsets[i] + 1],
|
|
||||||
pTargetFileView[PatchOffsets[i] + 2]);
|
|
||||||
pTargetFileView[PatchOffsets[i] + 2] = RSAPublicKeyPEM[i];
|
|
||||||
_tprintf_s(TEXT("%02X %02X %02X\n"),
|
|
||||||
pTargetFileView[PatchOffsets[i]],
|
|
||||||
pTargetFileView[PatchOffsets[i] + 1],
|
|
||||||
pTargetFileView[PatchOffsets[i] + 2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
PRINT_MESSAGE("");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -183,95 +183,4 @@ namespace Patcher {
|
|||||||
virtual ~Solution() {}
|
virtual ~Solution() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Solution0 will replace the RSA public key stored in main application.
|
|
||||||
class Solution0 : public Solution {
|
|
||||||
private:
|
|
||||||
static const char Keyword[461];
|
|
||||||
static constexpr int KeywordLength = 460;
|
|
||||||
|
|
||||||
FileMapper* pTargetFile;
|
|
||||||
off_t PatchOffset;
|
|
||||||
public:
|
|
||||||
|
|
||||||
Solution0() noexcept :
|
|
||||||
pTargetFile(nullptr),
|
|
||||||
PatchOffset(-1) {}
|
|
||||||
|
|
||||||
virtual void SetFile(FileMapper* pMainApp) noexcept override {
|
|
||||||
pTargetFile = pMainApp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Solution0 does not have any requirements for an RSA-2048 key
|
|
||||||
virtual bool CheckKey(RSACipher* cipher) const noexcept override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true if found, other return false
|
|
||||||
virtual bool FindPatchOffset() noexcept override;
|
|
||||||
|
|
||||||
// Make a patch based on an RSA private key given
|
|
||||||
// Return true if success, otherwise return false
|
|
||||||
virtual bool MakePatch(RSACipher* cipher) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Solution0 will replace the RSA public key stored in libcc.dll
|
|
||||||
class Solution1 : public Solution {
|
|
||||||
private:
|
|
||||||
static const char* Keywords[5];
|
|
||||||
static const int KeywordsLength[5];
|
|
||||||
|
|
||||||
FileMapper* pTargetFile;
|
|
||||||
off_t PatchOffsets[5];
|
|
||||||
public:
|
|
||||||
Solution1() :
|
|
||||||
pTargetFile(nullptr),
|
|
||||||
PatchOffsets{ -1, -1, -1, -1, -1 } {}
|
|
||||||
|
|
||||||
virtual void SetFile(FileMapper* pLibccFile) noexcept override {
|
|
||||||
pTargetFile = pLibccFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Solution1 has some requirements for an RSA-2048 key
|
|
||||||
virtual bool CheckKey(RSACipher* cipher) const noexcept override;
|
|
||||||
|
|
||||||
// Return true if found, otherwise return false
|
|
||||||
virtual bool FindPatchOffset() noexcept override;
|
|
||||||
|
|
||||||
// Make a patch based on an RSA private key given
|
|
||||||
// Return true if success, otherwise return false
|
|
||||||
virtual bool MakePatch(RSACipher* cipher) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Solution2 : public Solution {
|
|
||||||
private:
|
|
||||||
static constexpr size_t KeywordsCount = 0x188;
|
|
||||||
static const char KeywordsMeta[KeywordsCount + 1];
|
|
||||||
static uint8_t Keywords[KeywordsCount][5];
|
|
||||||
|
|
||||||
FileMapper* pTargetFile;
|
|
||||||
off_t PatchOffsets[KeywordsCount];
|
|
||||||
|
|
||||||
void BuildKeywords() noexcept;
|
|
||||||
public:
|
|
||||||
Solution2() :
|
|
||||||
pTargetFile(nullptr) {
|
|
||||||
memset(PatchOffsets, -1, sizeof(PatchOffsets));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void SetFile(FileMapper* pLibccFile) noexcept override {
|
|
||||||
pTargetFile = pLibccFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Solution2 has no requirements for an RSA-2048 key
|
|
||||||
virtual bool CheckKey(RSACipher* cipher) const noexcept override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true if found, otherwise return false
|
|
||||||
virtual bool FindPatchOffset() noexcept override;
|
|
||||||
|
|
||||||
// Make a patch based on an RSA private key given
|
|
||||||
// Return true if success, otherwise return false
|
|
||||||
virtual bool MakePatch(RSACipher* cipher) const override;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user