GUID On runtime

This commit is contained in:
Louvenarde 2024-02-03 00:31:03 +01:00
parent 0d222e30cf
commit 67bd07949d
6 changed files with 164 additions and 110 deletions

View File

@ -873,11 +873,6 @@ namespace Assets
void IXModel::ConvertPlayerModelFromSingleplayerToMultiplayer(Game::XModel* model, Utils::Memory::Allocator& allocator)
{
if (model->name == "body_airport_com_a"s)
{
printf("");
}
std::string requiredBonesForHumanoid[] = {
"j_spinelower",
"j_spineupper",

View File

@ -19,10 +19,11 @@ namespace Components
std::vector<std::uint64_t> Auth::BannedUids =
{
0xf4d2c30b712ac6e3,
// No longer necessary
/* 0xf4d2c30b712ac6e3,
0xf7e33c4081337fa3,
0x6f5597f103cc50e9,
0xecd542eee54ffccf,
0xecd542eee54ffccf,*/
};
bool Auth::HasAccessToReservedSlot;
@ -45,7 +46,7 @@ namespace Components
if (mseconds < 0) mseconds = 0;
}
Localization::Set("MPUI_SECURITY_INCREASE_MESSAGE", Utils::String::VA("Increasing security level from %d to %d (est. %s)",GetSecurityLevel(), TokenContainer.targetLevel, Utils::String::FormatTimeSpan(static_cast<int>(mseconds)).data()));
Localization::Set("MPUI_SECURITY_INCREASE_MESSAGE", Utils::String::VA("Increasing security level from %d to %d (est. %s)", GetSecurityLevel(), TokenContainer.targetLevel, Utils::String::FormatTimeSpan(static_cast<int>(mseconds)).data()));
}
else if (TokenContainer.thread.joinable())
{
@ -53,7 +54,7 @@ namespace Components
TokenContainer.generating = false;
StoreKey();
Logger::Debug("Security level is {}",GetSecurityLevel());
Logger::Debug("Security level is {}", GetSecurityLevel());
Command::Execute("closemenu security_increase_popmenu", false);
if (!TokenContainer.cancel)
@ -212,7 +213,7 @@ namespace Components
SteamID guid;
guid.bits = xuid;
if (Bans::IsBanned({guid, address.getIP()}))
if (Bans::IsBanned({ guid, address.getIP() }))
{
Logger::PrintFail2Ban("Failed connect attempt from IP address: {}\n", Network::AdrToString(address));
Network::Send(address, "error\nEXE_ERR_BANNED_PERM");
@ -304,10 +305,10 @@ namespace Components
xor eax, eax
jmp safeContinue
noAccess:
mov eax, dword ptr [edx + 0x10]
noAccess :
mov eax, dword ptr[edx + 0x10]
safeContinue:
safeContinue :
// Game code skipped by hook
add esp, 0xC
@ -342,6 +343,8 @@ namespace Components
void Auth::StoreKey()
{
// We write the key as a decoy I suppose - it's really no longer needed
// TODO Remove this part
if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled() && GuidKey.isValid())
{
Proto::Auth::Certificate cert;
@ -366,6 +369,15 @@ namespace Components
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) return;
if (!force && GuidKey.isValid()) return;
// We no longer read the key from disk
// While having obvious advantages to palliate the fact that some users are not playing on Steam,
// it is creating a lot of issues because GUID files get packaged with the game when people share it
// and it makes it harder for server owners to identify players uniquely
// Note that we could store it in Appdata, but then it would be dissociated from the rest of player files,
// so for now we're doing something else: the key is generated uniquely from the machine's characteristics
// It is not (necessarily) stored and therefore, not loaded, so it could make it harder to evade bans without
// using a custom client that would need regeneration at each update.
#if false
Proto::Auth::Certificate cert;
if (cert.ParseFromString(::Utils::IO::ReadFile("players/guid.dat")))
{
@ -379,10 +391,9 @@ namespace Components
}
if (!GuidKey.isValid())
{
#endif
Auth::GenerateKey();
}
}
}
uint32_t Auth::GetSecurityLevel()
{

View File

@ -463,7 +463,7 @@ namespace Components
void Download::Reply(mg_connection* connection, const std::string& contentType, const std::string& data)
{
const auto formatted = std::format("Content-Type: {}\r\n", contentType);
const auto formatted = std::format("Content-Type: {}\r\nAccess-Control-Allow-Origin: *\r\n", contentType);
mg_http_reply(connection, 200, formatted.c_str(), "%s", data.c_str());
}

View File

@ -56,6 +56,9 @@
#include <dwmapi.h>
#pragma comment (lib, "dwmapi.lib")
#include <iphlpapi.h>
#pragma comment (lib, "iphlpapi.lib")
// Ignore the warnings
#pragma warning(push)
#pragma warning(disable: 4100)

View File

@ -8,10 +8,80 @@ namespace Utils
{
void Initialize()
{
DES3::Initialize();
Rand::Initialize();
}
std::string GetEntropy()
{
DWORD volumeID;
if (GetVolumeInformationA("C:\\",
NULL,
NULL,
&volumeID,
NULL,
NULL,
NULL,
NULL
))
{
// Drive info
return std::to_string(volumeID);
}
else
{
// Resort to mac address
unsigned long outBufLen = 0;
DWORD dwResult = GetAdaptersInfo(NULL, &outBufLen);
if (dwResult == ERROR_BUFFER_OVERFLOW) // This is what we're expecting
{
// Now allocate a structure of the required size.
PIP_ADAPTER_INFO pIpAdapterInfo = reinterpret_cast<PIP_ADAPTER_INFO>(malloc(outBufLen));
dwResult = GetAdaptersInfo(pIpAdapterInfo, &outBufLen);
if (dwResult == ERROR_SUCCESS)
{
while (pIpAdapterInfo)
{
switch (pIpAdapterInfo->Type)
{
default:
pIpAdapterInfo = pIpAdapterInfo->Next;
continue;
case IF_TYPE_IEEE80211:
case MIB_IF_TYPE_ETHERNET:
{
std::string macAddress{};
for (size_t i = 0; i < ARRAYSIZE(pIpAdapterInfo->Address); i++)
{
macAddress += std::to_string(pIpAdapterInfo->Address[i]);
}
free(pIpAdapterInfo);
return macAddress;
}
}
}
}
else
{
// :(
// Continue to fallback
}
// Free before going next because clearly this is not working
free(pIpAdapterInfo);
}
else
{
// No MAC, no C: drive? Come on
}
// ultimate fallback
return std::to_string(Rand::GenerateInt());
}
}
#pragma region Rand
prng_state Rand::State;
@ -51,8 +121,29 @@ namespace Utils
Key key;
ltc_mp = ltm_desc;
register_prng(&sprng_desc);
ecc_make_key(nullptr, find_prng("sprng"), bits / 8, key.getKeyPtr());
int descriptorIndex = register_prng(&chacha20_prng_desc);
// allocate state
{
prng_state* state = new prng_state();
chacha20_prng_start(state);
const auto entropy = Cryptography::GetEntropy();
chacha20_prng_add_entropy(reinterpret_cast<const unsigned char*>(entropy.data()), entropy.size(), state);
chacha20_prng_ready(state);
const auto result = ecc_make_key(state, descriptorIndex, bits / 8, key.getKeyPtr());
if (result != CRYPT_OK)
{
Components::Logger::PrintError(Game::conChannel_t::CON_CHANNEL_ERROR, "There was an issue generating your unique player ID! Please contact support");
}
// Deallocate state
delete state;
}
return key;
}
@ -139,45 +230,6 @@ namespace Utils
#pragma endregion
#pragma region DES3
void DES3::Initialize()
{
register_cipher(&des3_desc);
}
std::string DES3::Encrypt(const std::string& text, const std::string& iv, const std::string& key)
{
std::string encData;
encData.resize(text.size());
symmetric_CBC cbc;
const auto des3 = find_cipher("3des");
cbc_start(des3, reinterpret_cast<const std::uint8_t*>(iv.data()), reinterpret_cast<const std::uint8_t*>(key.data()), static_cast<int>(key.size()), 0, &cbc);
cbc_encrypt(reinterpret_cast<const std::uint8_t*>(text.data()), reinterpret_cast<uint8_t*>(encData.data()), text.size(), &cbc);
cbc_done(&cbc);
return encData;
}
std::string DES3::Decrpyt(const std::string& data, const std::string& iv, const std::string& key)
{
std::string decData;
decData.resize(data.size());
symmetric_CBC cbc;
const auto des3 = find_cipher("3des");
cbc_start(des3, reinterpret_cast<const std::uint8_t*>(iv.data()), reinterpret_cast<const std::uint8_t*>(key.data()), static_cast<int>(key.size()), 0, &cbc);
cbc_decrypt(reinterpret_cast<const std::uint8_t*>(data.data()), reinterpret_cast<std::uint8_t*>(decData.data()), data.size(), &cbc);
cbc_done(&cbc);
return decData;
}
#pragma endregion
#pragma region Tiger
std::string Tiger::Compute(const std::string& data, bool hex)

View File

@ -5,6 +5,7 @@ namespace Utils
namespace Cryptography
{
void Initialize();
std::string GetEntropy();
class Token
{
@ -327,14 +328,6 @@ namespace Utils
static bool VerifyMessage(Key key, const std::string& message, const std::string& signature);
};
class DES3
{
public:
static void Initialize();
static std::string Encrypt(const std::string& text, const std::string& iv, const std::string& key);
static std::string Decrpyt(const std::string& text, const std::string& iv, const std::string& key);
};
class Tiger
{
public: