Files
native_invoker_v2/src/detail/rage.hpp
2025-11-18 20:07:29 +01:00

235 lines
8.5 KiB
C++

#pragma once
#include <cstdint>
namespace fxn::rage
{
namespace sysObfuscatedTypes
{
std::uint32_t obfuscatedRandom()
{
static std::uint32_t next = 0xCB536E6A;
next = next * 214013 + 2531011;
return next;
}
}
template<typename T, bool TMutate = true>
class sysObfuscated
{
public:
sysObfuscated()
{
static_assert((sizeof(T) & 3) == 0, "Size of T must be a multiple of 4");
Init();
}
sysObfuscated(const sysObfuscated<T, TMutate>& rhs)
{
Init();
Set(rhs.Get());
}
public:
template<bool TMutateOther>
sysObfuscated(const sysObfuscated<T, TMutateOther>& rhs)
{
Init();
Set(rhs.Get());
}
explicit sysObfuscated(const T& data)
{
Init();
Set(data);
}
~sysObfuscated() {}
public:
T Get() const;
void Set(const T& data);
operator T() const { return Get(); }
public:
template<bool TMutateOther> bool operator==(const sysObfuscated<T, TMutateOther>& rhs) const { return Get() == rhs.Get(); }
template<bool TMutateOther> bool operator!=(const sysObfuscated<T, TMutateOther>& rhs) const { return Get() != rhs.Get(); }
template<bool TMutateOther> bool operator<(const sysObfuscated<T, TMutateOther>& rhs) const { return Get() < rhs.Get(); }
template<bool TMutateOther> bool operator<=(const sysObfuscated<T, TMutateOther>& rhs) const { return Get() <= rhs.Get(); }
template<bool TMutateOther> bool operator>(const sysObfuscated<T, TMutateOther>& rhs) const { return Get() > rhs.Get(); }
template<bool TMutateOther> bool operator>=(const sysObfuscated<T, TMutateOther>& rhs) const { return Get() >= rhs.Get(); }
public:
template<bool TMutateOther> sysObfuscated<T, TMutate>& operator=(const sysObfuscated<T, TMutateOther>& rhs) { Set(rhs.Get()); return *this; }
sysObfuscated<T, TMutate>& operator=(const T& data) { Set(data); return *this; }
public:
template<bool TMutateOther> sysObfuscated<T, TMutate>& operator+=(const sysObfuscated<T, TMutateOther>& rhs) { Set(Get()+rhs.Get()); return *this; }
sysObfuscated<T, TMutate>& operator+=(const T& data) { Set(Get()+data); return *this; }
template<bool TMutateOther> sysObfuscated<T, TMutate>& operator-=(const sysObfuscated<T, TMutateOther>& rhs) { Set(Get()-rhs.Get()); return *this; }
sysObfuscated<T, TMutate>& operator-=(const T& data) { Set(Get()-data); return *this; }
template<bool TMutateOther> sysObfuscated<T, TMutate>& operator*=(const sysObfuscated<T, TMutateOther>& rhs) { Set(Get()*rhs.Get()); return *this; }
sysObfuscated<T, TMutate>& operator*=(const T& data) { Set(Get()*data); return *this; }
template<bool TMutateOther> sysObfuscated<T, TMutate>& operator/=(const sysObfuscated<T, TMutateOther>& rhs) { Set(Get()/rhs.Get()); return *this; }
sysObfuscated<T, TMutate>& operator/=(const T& data) { Set(Get()/data); return *this; }
private:
void Init();
mutable std::uint32_t m_data[(TMutate ? sizeof(T)*2 : sizeof(T)) / sizeof(std::uint32_t)];
mutable std::uint32_t m_xor;
mutable std::uint32_t m_mutate;
};
template<class T, bool TMutate> __forceinline void sysObfuscated<T, TMutate>::Init()
{
m_xor = sysObfuscatedTypes::obfuscatedRandom();
if(TMutate)
{
m_mutate = sysObfuscatedTypes::obfuscatedRandom();
}
}
template<class T, bool TMutate> __forceinline T sysObfuscated<T, TMutate>::Get() const
{
std::uint32_t xorVal = m_xor ^ (std::uint32_t)(size_t)this;
std::uint32_t ret[sizeof(T)/sizeof(std::uint32_t)];
std::uint32_t* src = const_cast<std::uint32_t*>(&m_data[0]);
std::uint32_t* dest = (std::uint32_t*)&ret;
for(size_t i=0; i<sizeof(T)/4; ++i)
{
if(TMutate)
{
// Extract valid data from two words of storage
std::uint32_t a = *src & m_mutate;
std::uint32_t b = src[sizeof(T)/4] & (~m_mutate);
// Apply entropy in the unused bits: Just flip the two u16's in the std::uint32_t. We can't do a
// huge amount more without knowledge of the mutation mask.
std::uint32_t entropyA = ((*src & (~m_mutate)) << 16) | ((*src & (~m_mutate)) >> 16);
std::uint32_t entropyB = ((src[sizeof(T)/4] & m_mutate) << 16) | ((src[sizeof(T)/4] & m_mutate) >> 16);
*src = (*src & m_mutate) | entropyA;
src[sizeof(T)/4] = (src[sizeof(T)/4] & (~m_mutate)) | entropyB;
*dest++ = a | b;
++src;
}
else
{
*dest++ = *src++ ^ xorVal;
}
}
// Call Set() to reset the xor and mutate keys on every call to Get()
if(TMutate)
{
const_cast<sysObfuscated<T, TMutate>*>(this)->Set(*(T*)&ret);
}
return *(T*)&ret;
}
template<class T, bool TMutate> __forceinline void sysObfuscated<T, TMutate>::Set(const T& data)
{
// Reset xor and mutate keys
Init();
std::uint32_t xorVal = m_xor ^ (std::uint32_t)(size_t)this;
std::uint32_t* src = (std::uint32_t*)&data;
std::uint32_t* dest = &m_data[0];
for(size_t i=0; i<sizeof(T)/4; ++i)
{
if(TMutate)
{
std::uint32_t a = *src & m_mutate;
std::uint32_t b = *src & (~m_mutate);
++src;
*dest = a;
dest[sizeof(T)/4] = b;
++dest;
}
else
{
*dest++ = *src++ ^ xorVal;
}
}
}
template <typename _T>
class scrCommandHash
{
private:
static const int ToplevelSize = 256;
static const int PerBucket = 7;
struct Bucket
{
sysObfuscated<Bucket *, false> obf_Next;
_T Data[PerBucket];
sysObfuscated<std::uint32_t, false> obf_Count;
sysObfuscated<std::uint64_t, false> obf_Hashes[PerBucket];
std::uint64_t plainText_Hashes[PerBucket];
};
public:
void RegistrationComplete(bool val)
{
m_bRegistrationComplete = val;
}
void Init()
{
m_Occupancy = 0;
m_bRegistrationComplete = false;
for (int i=0; i<ToplevelSize; i++)
m_Buckets[i] = NULL;
}
void Kill()
{
for (int i=0; i<ToplevelSize; i++) {
Bucket *b = m_Buckets[i];
while (b) {
char *old = (char*) b;
b = b->obf_Next.Get();
delete[] old;
}
m_Buckets[i] = NULL;
}
m_Occupancy = 0;
}
void Insert(std::uint64_t hashcode,_T cmd)
{
Bucket * b = m_Buckets[hashcode & (ToplevelSize-1)];
// If this chain is empty, or the first bucket is full, allocate and patch in a new bucket
if (!b || b->obf_Count.Get() == PerBucket) {
Bucket *nb = (Bucket*) new char[sizeof(Bucket)];
nb->obf_Next.Set(m_Buckets[hashcode & (ToplevelSize-1)]);
nb->obf_Count.Set(0);
b = m_Buckets[hashcode & (ToplevelSize-1)] = nb;
}
b->obf_Hashes[b->obf_Count.Get()].Set(hashcode);
b->plainText_Hashes[b->obf_Count.Get()] = 0; //hashcode;
b->Data[b->obf_Count] = cmd;
b->obf_Count.Set(b->obf_Count.Get()+1); //inc count
}
_T Lookup(std::uint64_t hashcode)
{
Bucket *b = m_Buckets[hashcode & (ToplevelSize-1)];
while (b) {
for (std::uint32_t i=0; i<b->obf_Count.Get(); i++)
if (b->obf_Hashes[i].Get() == hashcode)
return b->Data[i];
b = b->obf_Next.Get();
}
return 0;
}
private:
Bucket* m_Buckets[ToplevelSize];
int m_Occupancy;
bool m_bRegistrationComplete;
};
}