From 07025c6ed71cc3f693b1229ece0b2d2ddd230d54 Mon Sep 17 00:00:00 2001 From: lightbulblighter <59720715+lightbulblighter@users.noreply.github.com> Date: Thu, 2 Jun 2022 00:30:44 -0700 Subject: [PATCH] Crypt::verifySignatureBase64 sha256 --- PolygonClientUtilities/Crypt.cpp | 149 ++++++++++++++++++ PolygonClientUtilities/Crypt.h | 21 +++ .../PolygonClientUtilities.vcxproj | 6 +- .../PolygonClientUtilities.vcxproj.filters | 4 +- PolygonClientUtilities/Util.cpp | 43 +++++ PolygonClientUtilities/Util.h | 1 + .../VerifySignatureBase64.cpp | 22 --- .../VerifySignatureBase64.h | 7 - PolygonClientUtilities/dllmain.cpp | 2 +- 9 files changed, 221 insertions(+), 34 deletions(-) create mode 100644 PolygonClientUtilities/Crypt.cpp create mode 100644 PolygonClientUtilities/Crypt.h delete mode 100644 PolygonClientUtilities/VerifySignatureBase64.cpp delete mode 100644 PolygonClientUtilities/VerifySignatureBase64.h diff --git a/PolygonClientUtilities/Crypt.cpp b/PolygonClientUtilities/Crypt.cpp new file mode 100644 index 0000000..d8ca61d --- /dev/null +++ b/PolygonClientUtilities/Crypt.cpp @@ -0,0 +1,149 @@ +#include "pch.h" +#include "Crypt.h" +#include "Patches.h" +#include "Util.h" + +// Carrot: Notes; +// - The public key should be taken from the attached executable. Find "BgIAAACk" and get 200 characters +// - I didn't test this +// - All the std::runtime_errors here should use RBX::runtime_error but I didn't want to hook it. YOu do it pizza +// - Idk how iffy the base64 decoding is lol + +// Base/rbx/Crypt.cpp + +Crypt::Crypt() +{ + static const char* keyB64 = "BgIAAACkAABSU0ExAAQAAAEAAQBBC9x87ewme1daAWZGJpK3rTepuMbivjpgTyNwu+f7gxpyreKUzQDSpqj+DhT7ni432DY0H4+Zv6MazZFrjeBnS6YnD02fuGkmLb0mg0yO784esDkImtDpqNrmoqPwAe94jr8K8vsxaOeF5b7OfA+lWUcag6Jh0Yb+mZxhFbmvrg=="; + char pbKeyBlob[256]; + int dwBlobLen = 256; + + // http://support.microsoft.com/kb/238187 + if (!CryptAcquireContext(&context, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + { + if (::GetLastError() == NTE_BAD_KEYSET) + { + if (!CryptAcquireContext(&context, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET)) + { + throw std::runtime_error("Error " + std::to_string(GetLastError()) + " during CryptAcquireContext 2\n"); + } + } + else + { + throw std::runtime_error("Error " + std::to_string(GetLastError()) + " during CryptAcquireContext\n"); + } + } + + ATL::Base64Decode(keyB64, strlen(keyB64), (BYTE*)pbKeyBlob, &dwBlobLen); + + if (!CryptImportKey(context, (BYTE*)pbKeyBlob, dwBlobLen, 0, 0, &key)) + { + throw std::runtime_error("Error " + std::to_string(GetLastError()) + " during CryptImportKey"); + } +} + +Crypt::~Crypt() +{ + CryptDestroyKey(key); + CryptReleaseContext(context, 0); +} + +void Crypt::verifySignatureBase64(std::string message, std::string signatureBase64) +{ + // Check for a reasonable signature length before verifying + if (signatureBase64.length() > 4096) + { + throw std::runtime_error(""); + } + + HCRYPTHASH hash; + + if (!CryptCreateHash(context, CALG_SHA_256, NULL, 0, &hash)) + { + throw std::runtime_error(""); + } + + try + { + if (!CryptHashData(hash, (BYTE*)message.c_str(), message.size(), 0)) + { + throw std::runtime_error(""); + } + + // Roblox does stupid stuff. We can just use C++17 features :-) + + std::vector signature = Util::base64Decode(signatureBase64); + + /* + The native cryptography API uses little-endian byte order + while the .NET Framework API uses big-endian byte order. + If you are verifying a signature generated by using a .NET Framework + API (or similar), you must swap the order of signature bytes before + calling the CryptVerifySignature function to verify the signature. + */ + + std::reverse(signature.begin(), signature.end()); + + BYTE* signatureData = new BYTE[signature.size()]; + std::copy(signature.begin(), signature.end(), signatureData); + + if (!CryptVerifySignature(hash, signatureData, signature.size(), key, NULL, 0)) + { + throw std::runtime_error(""); + } + } + catch (...) + { + ::CryptDestroyHash(hash); + throw std::runtime_error(""); + } + + ::CryptDestroyHash(hash); +} + +// End Base/rbx/Crypt.cpp + +Crypt__verifySignatureBase64_t Crypt__verifySignatureBase64 = (Crypt__verifySignatureBase64_t)ADDRESS_CRYPT__VERIFYSIGNATUREBASE64; + +void __fastcall Crypt__verifySignatureBase64_hook(HCRYPTPROV* _this, void*, int a2, BYTE* pbData, int a4, int a5, int a6, DWORD dwDataLen, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15) +{ + std::string message; + std::string signatureBase64; + + // Get message + /* + v18 = pbData; + if ((unsigned int)a8 < 0x10) + { + v18 = (const BYTE*)&pbData; + } + */ + + const BYTE* v18 = pbData; + if ((unsigned int)a8 < 0x10) + { + v18 = (const BYTE*)&pbData; + } + + message = std::string(reinterpret_cast(pbData), dwDataLen); + + // Get signatureBase64 + /* + v21 = (int *)a10; + if ((unsigned int)a15 < 0x10) + { + v21 = &a10; + } + + sub_79EA70(v21, a14, &v30, &dwSigLen); // ATL::Base64Decode + */ + + int* v21 = (int*)a10; + if ((unsigned int)a15 < 0x10) + { + v21 = &a10; + } + + signatureBase64 = std::string(reinterpret_cast(v21), a14); + + Crypt().verifySignatureBase64(message, signatureBase64); +} \ No newline at end of file diff --git a/PolygonClientUtilities/Crypt.h b/PolygonClientUtilities/Crypt.h new file mode 100644 index 0000000..886d74a --- /dev/null +++ b/PolygonClientUtilities/Crypt.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Classes.h" +#include +#include +#include + +typedef void(__thiscall* Crypt__verifySignatureBase64_t)(HCRYPTPROV* _this, int a2, BYTE* pbData, int a4, int a5, int a6, DWORD dwDataLen, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15); +void __fastcall Crypt__verifySignatureBase64_hook(HCRYPTPROV* _this, void*, int a2, BYTE* pbData, int a4, int a5, int a6, DWORD dwDataLen, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15); +extern Crypt__verifySignatureBase64_t Crypt__verifySignatureBase64; + +class Crypt +{ + HCRYPTPROV context; + HCRYPTKEY key; + +public: + Crypt(); + ~Crypt(); + void verifySignatureBase64(std::string message, std::string signatureBase64); +}; \ No newline at end of file diff --git a/PolygonClientUtilities/PolygonClientUtilities.vcxproj b/PolygonClientUtilities/PolygonClientUtilities.vcxproj index c345c27..3b96168 100644 --- a/PolygonClientUtilities/PolygonClientUtilities.vcxproj +++ b/PolygonClientUtilities/PolygonClientUtilities.vcxproj @@ -93,6 +93,7 @@ Use pch.h $(SolutionDir)Detours\include + stdcpp17 Windows @@ -116,6 +117,7 @@ $(SolutionDir)Detours\include Disabled false + stdcpp17 Windows @@ -176,7 +178,7 @@ - + @@ -200,7 +202,7 @@ - + diff --git a/PolygonClientUtilities/PolygonClientUtilities.vcxproj.filters b/PolygonClientUtilities/PolygonClientUtilities.vcxproj.filters index d0e65f5..f7fcf09 100644 --- a/PolygonClientUtilities/PolygonClientUtilities.vcxproj.filters +++ b/PolygonClientUtilities/PolygonClientUtilities.vcxproj.filters @@ -45,7 +45,7 @@ Header Files\Hooks - + Header Files\Hooks @@ -89,7 +89,7 @@ Source Files\Hooks - + Source Files\Hooks diff --git a/PolygonClientUtilities/Util.cpp b/PolygonClientUtilities/Util.cpp index abbf8dc..d2ebc9b 100644 --- a/PolygonClientUtilities/Util.cpp +++ b/PolygonClientUtilities/Util.cpp @@ -1,5 +1,6 @@ #include "pch.h" #include "Util.h" +#include const std::vector Util::allowedHosts { @@ -68,4 +69,46 @@ std::string Util::toLower(std::string s) { std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); }); return s; +} + +// https://stackoverflow.com/a/44562527 +std::vector Util::base64Decode(const std::string_view data) +{ + // table from '+' to 'z' + const uint8_t lookup[] = { + 62, 255, 62, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, + 255, 0, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 255, 255, 255, 255, 63, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 + }; + + static_assert(sizeof(lookup) == 'z' - '+' + 1); + + std::vector out; + int val = 0, valb = -8; + for (uint8_t c : data) + { + if (c < '+' || c > 'z') + { + break; + } + + c -= '+'; + if (lookup[c] >= 64) + { + break; + } + + val = (val << 6) + lookup[c]; + valb += 6; + + if (valb >= 0) + { + out.push_back(char((val >> valb) & 0xFF)); + valb -= 8; + } + } + + return out; } \ No newline at end of file diff --git a/PolygonClientUtilities/Util.h b/PolygonClientUtilities/Util.h index a049e4b..bf1e323 100644 --- a/PolygonClientUtilities/Util.h +++ b/PolygonClientUtilities/Util.h @@ -12,4 +12,5 @@ public: static std::map parseArgs(std::string args); static bool isASCII(const std::string& s); static std::string toLower(std::string s); + static std::vector base64Decode(const std::string_view data); }; \ No newline at end of file diff --git a/PolygonClientUtilities/VerifySignatureBase64.cpp b/PolygonClientUtilities/VerifySignatureBase64.cpp deleted file mode 100644 index 285c821..0000000 --- a/PolygonClientUtilities/VerifySignatureBase64.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "pch.h" -#include "VerifySignatureBase64.h" -#include "Patches.h" - -Crypt__verifySignatureBase64_t Crypt__verifySignatureBase64 = (Crypt__verifySignatureBase64_t)ADDRESS_CRYPT__VERIFYSIGNATUREBASE64; - -void __fastcall Crypt__verifySignatureBase64_hook(HCRYPTPROV* _this, void*, char a2, int a3, int a4, int a5, int a6, int a7, int a8, char a9, int a10, int a11, int a12, int a13, int a14, int a15) -{ - // the actual function signature is (HCRYPTPROV* _this, std::string message, std::string signatureBase64) - // but for some reason it throws a memory access violation when you pass the parameters back into the function, without even modifying them - // each char represents the beginning of new std::string (with the int parameters, that totalls to a length of 24 bytes) - // the signature length is stored in a14 though so we can just use that - - if (a14 > 1024) - { - std::ostringstream error; - error << "Signature too large. " << a14 << " > 1024"; - throw std::runtime_error(error.str()); - } - - Crypt__verifySignatureBase64(_this, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); -} \ No newline at end of file diff --git a/PolygonClientUtilities/VerifySignatureBase64.h b/PolygonClientUtilities/VerifySignatureBase64.h deleted file mode 100644 index 942838d..0000000 --- a/PolygonClientUtilities/VerifySignatureBase64.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "Classes.h" - -typedef void(__thiscall* Crypt__verifySignatureBase64_t)(HCRYPTPROV* _this, char a2, int a3, int a4, int a5, int a6, int a7, int a8, char a9, int a10, int a11, int a12, int a13, int a14, int a15); -void __fastcall Crypt__verifySignatureBase64_hook(HCRYPTPROV* _this, void*, char a2, int a3, int a4, int a5, int a6, int a7, int a8, char a9, int a10, int a11, int a12, int a13, int a14, int a15); -extern Crypt__verifySignatureBase64_t Crypt__verifySignatureBase64; \ No newline at end of file diff --git a/PolygonClientUtilities/dllmain.cpp b/PolygonClientUtilities/dllmain.cpp index 60dfc1d..c3cde91 100644 --- a/PolygonClientUtilities/dllmain.cpp +++ b/PolygonClientUtilities/dllmain.cpp @@ -6,7 +6,7 @@ #include "DebugScriptContext.h" // #include "TestHttpGetPost.h" #include "TrustCheck.h" -#include "VerifySignatureBase64.h" +#include "Crypt.h" #ifdef ARBITERBUILD #include "RCCOutput.h"