fix Crypt::verifySignatureBase64

This commit is contained in:
lightbulblighter 2022-06-04 03:25:12 -07:00
parent aef1543021
commit 394a916e49
No known key found for this signature in database
GPG Key ID: 0B2452F9DE0E2D01
3 changed files with 30 additions and 45 deletions

View File

@ -1,43 +1,35 @@
// CARROT WAS HERE
#include "pch.h" #include "pch.h"
#include "Crypt.h" #include "Crypt.h"
#include "Patches.h" #include "Patches.h"
#include "Util.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() Crypt::Crypt()
{ {
static const char* keyB64 = "BgIAAACkAABSU0ExAAQAAAEAAQBBC9x87ewme1daAWZGJpK3rTepuMbivjpgTyNwu+f7gxpyreKUzQDSpqj+DhT7ni432DY0H4+Zv6MazZFrjeBnS6YnD02fuGkmLb0mg0yO784esDkImtDpqNrmoqPwAe94jr8K8vsxaOeF5b7OfA+lWUcag6Jh0Yb+mZxhFbmvrg=="; if (!CryptAcquireContext(&context, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
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 (::GetLastError() == NTE_BAD_KEYSET)
{ {
if (!CryptAcquireContext(&context, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET)) if (!CryptAcquireContext(&context, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET))
{ {
throw std::runtime_error("Error " + std::to_string(GetLastError()) + " during CryptAcquireContext 2\n"); throw std::runtime_error("Error during CryptAcquireContext 2\n");
} }
} }
else else
{ {
throw std::runtime_error("Error " + std::to_string(GetLastError()) + " during CryptAcquireContext\n"); throw std::runtime_error("Error during CryptAcquireContext\n");
} }
} }
ATL::Base64Decode(keyB64, strlen(keyB64), (BYTE*)pbKeyBlob, &dwBlobLen); std::vector<BYTE> publicKey = Util::base64Decode(Util::publicKey);
BYTE* blob = new BYTE[publicKey.size()];
if (!CryptImportKey(context, (BYTE*)pbKeyBlob, dwBlobLen, 0, 0, &key)) std::copy(publicKey.begin(), publicKey.end(), blob);
if (!CryptImportKey(context, blob, publicKey.size(), 0, 0, &key))
{ {
throw std::runtime_error("Error " + std::to_string(GetLastError()) + " during CryptImportKey"); throw std::runtime_error("Error during CryptImportKey");
} }
} }
@ -69,15 +61,14 @@ void Crypt::verifySignatureBase64(std::string message, std::string signatureBase
throw std::runtime_error(""); throw std::runtime_error("");
} }
// Roblox does stupid stuff. We can just use C++17 features :-)
std::vector<BYTE> signature = Util::base64Decode(signatureBase64); std::vector<BYTE> signature = Util::base64Decode(signatureBase64);
/* /*
The native cryptography API uses little-endian byte order The native cryptography API uses little-endian byte order
while the .NET Framework API uses big-endian byte order. while OpenSSL 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 If you are verifying a signature generated by using a OpenSSL API
(or similar), you must swap the order of signature bytes before
calling the CryptVerifySignature function to verify the signature. calling the CryptVerifySignature function to verify the signature.
*/ */
@ -100,24 +91,21 @@ void Crypt::verifySignatureBase64(std::string message, std::string signatureBase
::CryptDestroyHash(hash); ::CryptDestroyHash(hash);
} }
// End Base/rbx/Crypt.cpp
Crypt__verifySignatureBase64_t Crypt__verifySignatureBase64 = (Crypt__verifySignatureBase64_t)ADDRESS_CRYPT__VERIFYSIGNATUREBASE64; Crypt__verifySignatureBase64_t Crypt__verifySignatureBase64 = (Crypt__verifySignatureBase64_t)ADDRESS_CRYPT__VERIFYSIGNATUREBASE64;
// Crypt::verifySignatureBase64(std::string message, std::string signatureBase64)
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) 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)
{ {
/*
Ideally, we would be able to just use the function signature as-is.
However, it causes inexplicable crashes. Thus, we must reconstruct
the strings by hand given the manual parameters.
*/
std::string message; std::string message;
std::string signatureBase64; std::string signatureBase64;
// Get message // Get message
/*
v18 = pbData;
if ((unsigned int)a8 < 0x10)
{
v18 = (const BYTE*)&pbData;
}
*/
const BYTE* v18 = pbData; const BYTE* v18 = pbData;
if ((unsigned int)a8 < 0x10) if ((unsigned int)a8 < 0x10)
{ {
@ -127,16 +115,6 @@ void __fastcall Crypt__verifySignatureBase64_hook(HCRYPTPROV* _this, void*, int
message = std::string(reinterpret_cast<char const*>(pbData), dwDataLen); message = std::string(reinterpret_cast<char const*>(pbData), dwDataLen);
// Get signatureBase64 // Get signatureBase64
/*
v21 = (int *)a10;
if ((unsigned int)a15 < 0x10)
{
v21 = &a10;
}
sub_79EA70(v21, a14, &v30, &dwSigLen); // ATL::Base64Decode
*/
int* v21 = (int*)a10; int* v21 = (int*)a10;
if ((unsigned int)a15 < 0x10) if ((unsigned int)a15 < 0x10)
{ {
@ -145,5 +123,6 @@ void __fastcall Crypt__verifySignatureBase64_hook(HCRYPTPROV* _this, void*, int
signatureBase64 = std::string(reinterpret_cast<const char*>(v21), a14); signatureBase64 = std::string(reinterpret_cast<const char*>(v21), a14);
// Verify the signature
Crypt().verifySignatureBase64(message, signatureBase64); Crypt().verifySignatureBase64(message, signatureBase64);
} }

View File

@ -2,6 +2,11 @@
#include "Util.h" #include "Util.h"
#include <string_view> #include <string_view>
const std::string Util::publicKey = "BgIAAACkAABSU0ExAAQAAAEAAQABmKy9m0NxBRoXTuQPZU8BeM"
"fwBisHcYBy93KSlQB3emeiW/pEMj9YWn2k7JkHiqcjuH+XE5PW"
"K+q9s8oLQsnXTdTYa2l+1BhypP5jefgq0ZHITTIMBfE7rTI39p"
"pzs0ayXKINQMIsBzXaJm25v5gP+vlz4cupJPq+jy9De+kcyw==";
const std::vector<std::string> Util::allowedHosts const std::vector<std::string> Util::allowedHosts
{ {
"polygon.pizzaboxer.xyz", "polygon.pizzaboxer.xyz",

View File

@ -5,6 +5,7 @@
class Util class Util
{ {
public: public:
static const std::string publicKey;
static const std::vector<std::string> allowedHosts; static const std::vector<std::string> allowedHosts;
static const std::vector<std::string> allowedSchemes; static const std::vector<std::string> allowedSchemes;
static const std::vector<std::string> allowedEmbeddedSchemes; static const std::vector<std::string> allowedEmbeddedSchemes;