Crypt::verifySignatureBase64 sha256
This commit is contained in:
parent
0a4b9a32f7
commit
07025c6ed7
|
|
@ -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<BYTE> 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<char const*>(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<const char*>(v21), a14);
|
||||
|
||||
Crypt().verifySignatureBase64(message, signatureBase64);
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "Classes.h"
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#include <atlenc.h>
|
||||
|
||||
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);
|
||||
};
|
||||
|
|
@ -93,6 +93,7 @@
|
|||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)Detours\include</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
|
@ -116,6 +117,7 @@
|
|||
<AdditionalIncludeDirectories>$(SolutionDir)Detours\include</AdditionalIncludeDirectories>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
|
@ -176,7 +178,7 @@
|
|||
<ClInclude Include="Classes.h" />
|
||||
<ClInclude Include="Hooks.h" />
|
||||
<ClInclude Include="Util.h" />
|
||||
<ClInclude Include="VerifySignatureBase64.h" />
|
||||
<ClInclude Include="Crypt.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="DebugScriptContext.cpp" />
|
||||
|
|
@ -200,7 +202,7 @@
|
|||
<ClCompile Include="TestHttpGetPost.cpp" />
|
||||
<ClCompile Include="TrustCheck.cpp" />
|
||||
<ClCompile Include="Util.cpp" />
|
||||
<ClCompile Include="VerifySignatureBase64.cpp" />
|
||||
<ClCompile Include="Crypt.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
<ClInclude Include="TrustCheck.h">
|
||||
<Filter>Header Files\Hooks</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VerifySignatureBase64.h">
|
||||
<ClInclude Include="Crypt.h">
|
||||
<Filter>Header Files\Hooks</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MFCCommandLine.h">
|
||||
|
|
@ -89,7 +89,7 @@
|
|||
<ClCompile Include="TrustCheck.cpp">
|
||||
<Filter>Source Files\Hooks</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VerifySignatureBase64.cpp">
|
||||
<ClCompile Include="Crypt.cpp">
|
||||
<Filter>Source Files\Hooks</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MFCCommandLine.cpp">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "pch.h"
|
||||
#include "Util.h"
|
||||
#include <string_view>
|
||||
|
||||
const std::vector<std::string> 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<BYTE> 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<unsigned char> 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;
|
||||
}
|
||||
|
|
@ -12,4 +12,5 @@ public:
|
|||
static std::map<std::string, std::string> parseArgs(std::string args);
|
||||
static bool isASCII(const std::string& s);
|
||||
static std::string toLower(std::string s);
|
||||
static std::vector<BYTE> base64Decode(const std::string_view data);
|
||||
};
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
#include "DebugScriptContext.h"
|
||||
// #include "TestHttpGetPost.h"
|
||||
#include "TrustCheck.h"
|
||||
#include "VerifySignatureBase64.h"
|
||||
#include "Crypt.h"
|
||||
|
||||
#ifdef ARBITERBUILD
|
||||
#include "RCCOutput.h"
|
||||
|
|
|
|||
Loading…
Reference in New Issue