From f359800ce5a65508b07068821653c5146ef917e6 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Mon, 9 Sep 2019 21:24:20 +0200 Subject: [PATCH] Added a constexpr string obfuscator --- CMakeLists.txt | 1 + src/misc/strobf.h | 144 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 src/misc/strobf.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d42ec1..77ff713 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,7 @@ set(HEADER_FILES src/misc/hex.h src/misc/advanced_mutex.h src/misc/memtracker.h + src/misc/strobf.h src/log/translation.h src/log/LogUtils.h diff --git a/src/misc/strobf.h b/src/misc/strobf.h new file mode 100644 index 0000000..afdeee3 --- /dev/null +++ b/src/misc/strobf.h @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include + +namespace str_obf { + namespace internal { + template + struct message { + /* helper to access the types */ + static constexpr auto _size = size; + using _char_t = char_t; + using _key_t = key_t; + + /* memory */ + std::array buffer{0}; + key_t key{}; + + /* some memory access helpers */ + std::string_view string_view() const noexcept { return {this->buffer.begin(), this->length}; } + std::string string() const { return {this->buffer.begin(), this->length}; } + const char* c_str() const noexcept { return &this->buffer[0]; } + }; + + constexpr auto time_seed() noexcept { + std::uint64_t shifted = 0; + + for( const auto c : __TIME__ ) + { + shifted <<= 8; + shifted |= c; + } + + return shifted; + } + + constexpr uint64_t string_hash(const char* str, int h = 0) noexcept { + return !str[h] ? 5381 : (string_hash(str, h + 1) * 33) ^ str[h]; + } + + constexpr std::uint32_t rng32_next(std::uint64_t& state, const std::uint32_t& inc) noexcept { + std::uint64_t oldstate = state; + // Advance internal state + state = oldstate * 6364136223846793005ULL + (inc | 1UL); + // Calculate output function (XSH RR), uses old state for max ILP + std::uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u; + std::uint32_t rot = oldstate >> 59u; + return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); + } + } + + template + constexpr inline void crypt(char_t* begin, size_t length, const key_t& key) noexcept { + static_assert(sizeof(char_t) == 1, "Currently only 8 bit supported"); + if(length == 0) return; + + auto kbegin = std::begin(key); + auto kend = std::end(key); + if(kbegin == kend) return; + + auto it = kbegin; + while(length-- > 0) { + if(it == kend) + it = kbegin; + + *begin ^= *it; + + it++; + begin++; + } + } + + template + constexpr inline internal::message encode(const char_t(&message)[message_size], const key_t& key) noexcept { + internal::message result{}; + result.key = key; + + { + auto bit = result.buffer.begin(); + auto mit = message; + + size_t index = message_size; + while(index-- > 0) + *bit++ = *mit++; + } + + crypt(result.buffer.data(), message_size, key); + return result; + } + + template + inline std::string decode(const internal::message& message) { + std::string result{}; + result.resize(message_size); + + memcpy(result.data(), message.buffer.begin(), message_size); + crypt(result.data(), message_size, message.key); + + return result; + } + + constexpr inline std::array generate_key(const char* _str_seed, unsigned int line) noexcept { + std::uint64_t rng_seed = internal::time_seed() ^ internal::string_hash(_str_seed, 0) ^ line; + std::uint64_t rng_base = rng_seed; + + std::array result{}; + for(auto& it : result) + it = (internal::rng32_next(rng_base, rng_seed) >> 16UL) & 0xFFUL; + return result; + } + + template + struct decode_helper { + const message& encoded; + std::array buffer{0}; + bool decoded = false; /* a trivial check which (if this only gets used once) the compiler could evaluate */ + +#ifndef WIN32 /* else if you call string_view() or string() it wound inline this method */ + __attribute__((always_inline)) +#endif + const char* c_str() noexcept { + if(!this->decoded) { + memcpy(this->buffer.data(), this->encoded.buffer.begin(), message::_size); + crypt((typename message::_char_t*) this->buffer.data(), message::_size, this->encoded.key); + buffer[message::_size] = 0; /* append the null terminator at the end */ + this->decoded = true; /* let the compiler combine buffer[message::_size] and this->decoded = true; */ + } + + return &this->buffer[0]; + } + + inline std::string_view string_view() noexcept { + return {this->c_str(), message::_size}; + } + + inline std::string string() { return {this->c_str(), message::_size}; } + }; +} + +#define strobf_define(variable_name, string) \ +constexpr const auto variable_name = ::str_obf::encode(string, str_obf::generate_key(__FILE__ __TIME__, __LINE__)) + +#define strobf_val(variable_name) (str_obf::decode_helper{_hello_world}) \ No newline at end of file