diff --git a/deps/premake/libtommath.lua b/deps/premake/libtommath.lua index 6b4342b..1e8b277 100644 --- a/deps/premake/libtommath.lua +++ b/deps/premake/libtommath.lua @@ -1,51 +1,52 @@ -libtommath = { - source = path.join(dependencies.basePath, "libtommath"), -} - -function libtommath.import() - links { - "libtommath" - } - - libtommath.includes() -end - -function libtommath.includes() - includedirs { - libtommath.source - } - - defines { - "LTM_DESC", - "__STDC_IEC_559__", - } -end - -function libtommath.project() - project "libtommath" - language "C" - - libtommath.includes() - - files { - path.join(libtommath.source, "*.c"), - } - - defines { - "_LIB" - } - - removedefines { - "_DLL", - "_USRDLL" - } - - linkoptions { - "-IGNORE:4221" - } - - warnings "Off" - kind "StaticLib" -end - -table.insert(dependencies, libtommath) +libtommath = { + source = path.join(dependencies.basePath, "libtommath"), +} + +function libtommath.import() + links { + "libtommath" + } + + libtommath.includes() +end + +function libtommath.includes() + includedirs { + libtommath.source + } + + defines { + "LTM_DESC", + "__STDC_IEC_559__", + "MP_NO_DEV_URANDOM", + } +end + +function libtommath.project() + project "libtommath" + language "C" + + libtommath.includes() + + files { + path.join(libtommath.source, "*.c"), + } + + defines { + "_LIB" + } + + removedefines { + "_DLL", + "_USRDLL" + } + + linkoptions { + "-IGNORE:4221" + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, libtommath) diff --git a/src/game/demonware/bit_buffer.cpp b/src/game/demonware/bit_buffer.cpp index 808b411..50afd64 100644 --- a/src/game/demonware/bit_buffer.cpp +++ b/src/game/demonware/bit_buffer.cpp @@ -1,182 +1,182 @@ -#include -#include "bit_buffer.hpp" - -namespace demonware -{ - bool bit_buffer::read_bytes(const unsigned int bytes, unsigned char* output) - { - return this->read(bytes * 8, output); - } - - bool bit_buffer::read_bool(bool* output) - { - if (!this->read_data_type(1)) - { - return false; - } - - return this->read(1, output); - } - - bool bit_buffer::read_uint32(unsigned int* output) - { - if (!this->read_data_type(8)) - { - return false; - } - - return this->read(32, output); - } - - bool bit_buffer::read_data_type(const char expected) - { - char data_type = 0; - - if (!this->use_data_types_) return true; - if (this->read(5, &data_type)) - { - return (data_type == expected); - } - - return false; - } - - bool bit_buffer::write_bytes(const unsigned int bytes, const char* data) - { - return this->write_bytes(bytes, reinterpret_cast(data)); - } - - bool bit_buffer::write_bytes(unsigned int bytes, const unsigned char* data) - { - return this->write(bytes * 8, data); - } - - bool bit_buffer::write_bool(bool data) - { - if (this->write_data_type(1)) - { - return this->write(1, &data); - } - - return false; - } - - bool bit_buffer::write_int32(int data) - { - if (this->write_data_type(7)) - { - return this->write(32, &data); - } - - return false; - } - - bool bit_buffer::write_uint32(unsigned int data) - { - if (this->write_data_type(8)) - { - return this->write(32, &data); - } - - return false; - } - - bool bit_buffer::write_data_type(char data) - { - if (!this->use_data_types_) - { - return true; - } - - return this->write(5, &data); - } - - bool bit_buffer::read(unsigned int bits, void* output) - { - if (bits == 0) return false; - if ((this->current_bit_ + bits) > (this->buffer_.size() * 8)) return false; - - int cur_byte = this->current_bit_ >> 3; - auto cur_out = 0; - - const char* bytes = this->buffer_.data(); - const auto output_bytes = reinterpret_cast(output); - - while (bits > 0) - { - const int min_bit = (bits < 8) ? bits : 8; - const auto this_byte = bytes[cur_byte++] & 0xFF; - const int remain = this->current_bit_ & 7; - - if ((min_bit + remain) <= 8) - { - output_bytes[cur_out] = BYTE((0xFF >> (8 - min_bit)) & (this_byte >> remain)); - } - else - { - output_bytes[cur_out] = BYTE( - (0xFF >> (8 - min_bit)) & (bytes[cur_byte] << (8 - remain)) | (this_byte >> remain)); - } - - cur_out++; - this->current_bit_ += min_bit; - bits -= min_bit; - } - - return true; - } - - bool bit_buffer::write(const unsigned int bits, const void* data) - { - if (bits == 0) return false; - this->buffer_.resize(this->buffer_.size() + (bits >> 3) + 1); - - int bit = bits; - const auto bytes = const_cast(this->buffer_.data()); - const auto* input_bytes = reinterpret_cast(data); - - while (bit > 0) - { - const int bit_pos = this->current_bit_ & 7; - auto rem_bit = 8 - bit_pos; - const auto this_write = (bit < rem_bit) ? bit : rem_bit; - - const BYTE mask = ((0xFF >> rem_bit) | (0xFF << (bit_pos + this_write))); - const int byte_pos = this->current_bit_ >> 3; - - const BYTE temp_byte = (mask & bytes[byte_pos]); - const BYTE this_bit = ((bits - bit) & 7); - const auto this_byte = (bits - bit) >> 3; - - auto this_data = input_bytes[this_byte]; - - const auto next_byte = (((bits - 1) >> 3) > this_byte) ? input_bytes[this_byte + 1] : 0; - - this_data = BYTE((next_byte << (8 - this_bit)) | (this_data >> this_bit)); - - const BYTE out_byte = (~mask & (this_data << bit_pos) | temp_byte); - bytes[byte_pos] = out_byte; - - this->current_bit_ += this_write; - bit -= this_write; - } - - return true; - } - - void bit_buffer::set_use_data_types(const bool use_data_types) - { - this->use_data_types_ = use_data_types; - } - - unsigned int bit_buffer::size() const - { - return this->current_bit_ / 8 + (this->current_bit_ % 8 ? 1 : 0); - } - - std::string& bit_buffer::get_buffer() - { - this->buffer_.resize(this->size()); - return this->buffer_; - } -} +#include +#include "bit_buffer.hpp" + +namespace demonware +{ + bool bit_buffer::read_bytes(const unsigned int bytes, unsigned char* output) + { + return this->read(bytes * 8, output); + } + + bool bit_buffer::read_bool(bool* output) + { + if (!this->read_data_type(1)) + { + return false; + } + + return this->read(1, output); + } + + bool bit_buffer::read_uint32(unsigned int* output) + { + if (!this->read_data_type(8)) + { + return false; + } + + return this->read(32, output); + } + + bool bit_buffer::read_data_type(const char expected) + { + char data_type = 0; + + if (!this->use_data_types_) return true; + if (this->read(5, &data_type)) + { + return (data_type == expected); + } + + return false; + } + + bool bit_buffer::write_bytes(const unsigned int bytes, const char* data) + { + return this->write_bytes(bytes, reinterpret_cast(data)); + } + + bool bit_buffer::write_bytes(const unsigned int bytes, const unsigned char* data) + { + return this->write(bytes * 8, data); + } + + bool bit_buffer::write_bool(bool data) + { + if (this->write_data_type(1)) + { + return this->write(1, &data); + } + + return false; + } + + bool bit_buffer::write_int32(int data) + { + if (this->write_data_type(7)) + { + return this->write(32, &data); + } + + return false; + } + + bool bit_buffer::write_uint32(unsigned int data) + { + if (this->write_data_type(8)) + { + return this->write(32, &data); + } + + return false; + } + + bool bit_buffer::write_data_type(char data) + { + if (!this->use_data_types_) + { + return true; + } + + return this->write(5, &data); + } + + bool bit_buffer::read(unsigned int bits, void* output) + { + if (bits == 0) return false; + if ((this->current_bit_ + bits) > (this->buffer_.size() * 8)) return false; + + int cur_byte = this->current_bit_ >> 3; + auto cur_out = 0; + + const char* bytes = this->buffer_.data(); + const auto output_bytes = reinterpret_cast(output); + + while (bits > 0) + { + const int min_bit = (bits < 8) ? bits : 8; + const auto this_byte = bytes[cur_byte++] & 0xFF; + const int remain = this->current_bit_ & 7; + + if ((min_bit + remain) <= 8) + { + output_bytes[cur_out] = BYTE((0xFF >> (8 - min_bit)) & (this_byte >> remain)); + } + else + { + output_bytes[cur_out] = BYTE( + (0xFF >> (8 - min_bit)) & (bytes[cur_byte] << (8 - remain)) | (this_byte >> remain)); + } + + cur_out++; + this->current_bit_ += min_bit; + bits -= min_bit; + } + + return true; + } + + bool bit_buffer::write(const unsigned int bits, const void* data) + { + if (bits == 0) return false; + this->buffer_.resize(this->buffer_.size() + (bits >> 3) + 1); + + int bit = bits; + const auto bytes = const_cast(this->buffer_.data()); + const auto* input_bytes = reinterpret_cast(data); + + while (bit > 0) + { + const int bit_pos = this->current_bit_ & 7; + auto rem_bit = 8 - bit_pos; + const auto this_write = (bit < rem_bit) ? bit : rem_bit; + + const BYTE mask = ((0xFF >> rem_bit) | (0xFF << (bit_pos + this_write))); + const int byte_pos = this->current_bit_ >> 3; + + const BYTE temp_byte = (mask & bytes[byte_pos]); + const BYTE this_bit = ((bits - bit) & 7); + const auto this_byte = (bits - bit) >> 3; + + auto this_data = input_bytes[this_byte]; + + const auto next_byte = (((bits - 1) >> 3) > this_byte) ? input_bytes[this_byte + 1] : 0; + + this_data = BYTE((next_byte << (8 - this_bit)) | (this_data >> this_bit)); + + const BYTE out_byte = (~mask & (this_data << bit_pos) | temp_byte); + bytes[byte_pos] = out_byte; + + this->current_bit_ += this_write; + bit -= this_write; + } + + return true; + } + + void bit_buffer::set_use_data_types(const bool use_data_types) + { + this->use_data_types_ = use_data_types; + } + + unsigned int bit_buffer::size() const + { + return this->current_bit_ / 8 + (this->current_bit_ % 8 ? 1 : 0); + } + + std::string& bit_buffer::get_buffer() + { + this->buffer_.resize(this->size()); + return this->buffer_; + } +} diff --git a/src/game/demonware/byte_buffer.cpp b/src/game/demonware/byte_buffer.cpp index 85d9dc3..01de5ea 100644 --- a/src/game/demonware/byte_buffer.cpp +++ b/src/game/demonware/byte_buffer.cpp @@ -1,308 +1,308 @@ -#include -#include "byte_buffer.hpp" - -namespace demonware -{ - bool byte_buffer::read_byte(unsigned char* output) - { - if (!this->read_data_type(3)) return false; - return this->read(1, output); - } - - bool byte_buffer::read_bool(bool* output) - { - if (!this->read_data_type(1)) return false; - return this->read(1, output); - } - - bool byte_buffer::read_int16(short* output) - { - if (!this->read_data_type(5)) return false; - return this->read(2, output); - } - - bool byte_buffer::read_uint16(unsigned short* output) - { - if (!this->read_data_type(6)) return false; - return this->read(2, output); - } - - bool byte_buffer::read_int32(int* output) - { - if (!this->read_data_type(7)) return false; - return this->read(4, output); - } - - bool byte_buffer::read_uint32(unsigned int* output) - { - if (!this->read_data_type(8)) return false; - return this->read(4, output); - } - - bool byte_buffer::read_int64(__int64* output) - { - if (!this->read_data_type(9)) return false; - return this->read(8, output); - } - - bool byte_buffer::read_uint64(unsigned __int64* output) - { - if (!this->read_data_type(10)) return false; - return this->read(8, output); - } - - bool byte_buffer::read_float(float* output) - { - if (!this->read_data_type(13)) return false; - return this->read(4, output); - } - - bool byte_buffer::read_string(std::string* output) - { - char* out_data; - if (this->read_string(&out_data)) - { - output->clear(); - output->append(out_data); - return true; - } - - return false; - } - - bool byte_buffer::read_string(char** output) - { - if (!this->read_data_type(16)) return false; - - *output = const_cast(this->buffer_.data()) + this->current_byte_; - this->current_byte_ += strlen(*output) + 1; - - return true; - } - - bool byte_buffer::read_string(char* output, const int length) - { - if (!this->read_data_type(16)) return false; - - strcpy_s(output, length, const_cast(this->buffer_.data()) + this->current_byte_); - this->current_byte_ += strlen(output) + 1; - - return true; - } - - bool byte_buffer::read_blob(std::string* output) - { - char* out_data; - int length; - if (this->read_blob(&out_data, &length)) - { - output->clear(); - output->append(out_data, length); - return true; - } - - return false; - } - - bool byte_buffer::read_blob(char** output, int* length) - { - if (!this->read_data_type(0x13)) - { - return false; - } - - unsigned int size; - this->read_uint32(&size); - - *output = const_cast(this->buffer_.data()) + this->current_byte_; - *length = static_cast(size); - - this->current_byte_ += size; - - return true; - } - - bool byte_buffer::read_data_type(const char expected) - { - if (!this->use_data_types_) return true; - - char type; - this->read(1, &type); - return type == expected; - } - - bool byte_buffer::read_array_header(const unsigned char expected, unsigned int* element_count, - unsigned int* element_size) - { - if (element_count) *element_count = 0; - if (element_size) *element_size = 0; - - if (!this->read_data_type(expected + 100)) return false; - - uint32_t array_size, el_count; - if (!this->read_uint32(&array_size)) return false; - - this->set_use_data_types(false); - this->read_uint32(&el_count); - this->set_use_data_types(true); - - if (element_count) *element_count = el_count; - if (element_size) *element_size = array_size / el_count; - - return true; - } - - bool byte_buffer::write_byte(char data) - { - this->write_data_type(3); - return this->write(1, &data); - } - - bool byte_buffer::write_bool(bool data) - { - this->write_data_type(1); - return this->write(1, &data); - } - - bool byte_buffer::write_int16(short data) - { - this->write_data_type(5); - return this->write(2, &data); - } - - bool byte_buffer::write_uint16(unsigned short data) - { - this->write_data_type(6); - return this->write(2, &data); - } - - bool byte_buffer::write_int32(int data) - { - this->write_data_type(7); - return this->write(4, &data); - } - - bool byte_buffer::write_uint32(unsigned int data) - { - this->write_data_type(8); - return this->write(4, &data); - } - - bool byte_buffer::write_int64(__int64 data) - { - this->write_data_type(9); - return this->write(8, &data); - } - - bool byte_buffer::write_uint64(unsigned __int64 data) - { - this->write_data_type(10); - return this->write(8, &data); - } - - bool byte_buffer::write_data_type(char data) - { - if (!this->use_data_types_) return true; - return this->write(1, &data); - } - - bool byte_buffer::write_float(float data) - { - this->write_data_type(13); - return this->write(4, &data); - } - - bool byte_buffer::write_string(const std::string& data) - { - return this->write_string(data.data()); - } - - bool byte_buffer::write_string(const char* data) - { - this->write_data_type(16); - return this->write(static_cast(strlen(data)) + 1, data); - } - - bool byte_buffer::write_blob(const std::string& data) - { - return this->write_blob(data.data(), INT(data.size())); - } - - bool byte_buffer::write_blob(const char* data, const int length) - { - this->write_data_type(0x13); - this->write_uint32(length); - - return this->write(length, data); - } - - bool byte_buffer::write_array_header(const unsigned char type, const unsigned int element_count, - const unsigned int element_size) - { - const auto using_types = this->is_using_data_types(); - this->set_use_data_types(false); - - auto result = this->write_byte(type + 100); - - this->set_use_data_types(true); - result &= this->write_uint32(element_count * element_size); - this->set_use_data_types(false); - - result &= this->write_uint32(element_count); - - this->set_use_data_types(using_types); - return result; - } - - bool byte_buffer::read(int bytes, void* output) - { - if (bytes + this->current_byte_ > this->buffer_.size()) return false; - - std::memmove(output, this->buffer_.data() + this->current_byte_, bytes); - this->current_byte_ += bytes; - - return true; - } - - bool byte_buffer::write(const int bytes, const void* data) - { - this->buffer_.append(reinterpret_cast(data), bytes); - this->current_byte_ += bytes; - return true; - } - - bool byte_buffer::write(const std::string& data) - { - return this->write(data.size(), data.data()); - } - - void byte_buffer::set_use_data_types(bool _useDataTypes) - { - this->use_data_types_ = _useDataTypes; - } - - size_t byte_buffer::size() const - { - return this->buffer_.size(); - } - - bool byte_buffer::is_using_data_types() const - { - return use_data_types_; - } - - std::string& byte_buffer::get_buffer() - { - return this->buffer_; - } - - std::string byte_buffer::get_remaining() - { - return std::string(this->buffer_.begin() + this->current_byte_, this->buffer_.end()); - } - - bool byte_buffer::has_more_data() const - { - return this->buffer_.size() > this->current_byte_; - } -} +#include +#include "byte_buffer.hpp" + +namespace demonware +{ + bool byte_buffer::read_byte(unsigned char* output) + { + if (!this->read_data_type(3)) return false; + return this->read(1, output); + } + + bool byte_buffer::read_bool(bool* output) + { + if (!this->read_data_type(1)) return false; + return this->read(1, output); + } + + bool byte_buffer::read_int16(short* output) + { + if (!this->read_data_type(5)) return false; + return this->read(2, output); + } + + bool byte_buffer::read_uint16(unsigned short* output) + { + if (!this->read_data_type(6)) return false; + return this->read(2, output); + } + + bool byte_buffer::read_int32(int* output) + { + if (!this->read_data_type(7)) return false; + return this->read(4, output); + } + + bool byte_buffer::read_uint32(unsigned int* output) + { + if (!this->read_data_type(8)) return false; + return this->read(4, output); + } + + bool byte_buffer::read_int64(__int64* output) + { + if (!this->read_data_type(9)) return false; + return this->read(8, output); + } + + bool byte_buffer::read_uint64(unsigned __int64* output) + { + if (!this->read_data_type(10)) return false; + return this->read(8, output); + } + + bool byte_buffer::read_float(float* output) + { + if (!this->read_data_type(13)) return false; + return this->read(4, output); + } + + bool byte_buffer::read_string(std::string* output) + { + char* out_data; + if (this->read_string(&out_data)) + { + output->clear(); + output->append(out_data); + return true; + } + + return false; + } + + bool byte_buffer::read_string(char** output) + { + if (!this->read_data_type(16)) return false; + + *output = const_cast(this->buffer_.data()) + this->current_byte_; + this->current_byte_ += strlen(*output) + 1; + + return true; + } + + bool byte_buffer::read_string(char* output, const int length) + { + if (!this->read_data_type(16)) return false; + + strcpy_s(output, length, const_cast(this->buffer_.data()) + this->current_byte_); + this->current_byte_ += strlen(output) + 1; + + return true; + } + + bool byte_buffer::read_blob(std::string* output) + { + char* out_data; + int length; + if (this->read_blob(&out_data, &length)) + { + output->clear(); + output->append(out_data, length); + return true; + } + + return false; + } + + bool byte_buffer::read_blob(char** output, int* length) + { + if (!this->read_data_type(0x13)) + { + return false; + } + + unsigned int size; + this->read_uint32(&size); + + *output = const_cast(this->buffer_.data()) + this->current_byte_; + *length = static_cast(size); + + this->current_byte_ += size; + + return true; + } + + bool byte_buffer::read_data_type(const char expected) + { + if (!this->use_data_types_) return true; + + char type; + this->read(1, &type); + return type == expected; + } + + bool byte_buffer::read_array_header(const unsigned char expected, unsigned int* element_count, + unsigned int* element_size) + { + if (element_count) *element_count = 0; + if (element_size) *element_size = 0; + + if (!this->read_data_type(expected + 100)) return false; + + uint32_t array_size, el_count; + if (!this->read_uint32(&array_size)) return false; + + this->set_use_data_types(false); + this->read_uint32(&el_count); + this->set_use_data_types(true); + + if (element_count) *element_count = el_count; + if (element_size) *element_size = array_size / el_count; + + return true; + } + + bool byte_buffer::write_byte(char data) + { + this->write_data_type(3); + return this->write(1, &data); + } + + bool byte_buffer::write_bool(bool data) + { + this->write_data_type(1); + return this->write(1, &data); + } + + bool byte_buffer::write_int16(short data) + { + this->write_data_type(5); + return this->write(2, &data); + } + + bool byte_buffer::write_uint16(unsigned short data) + { + this->write_data_type(6); + return this->write(2, &data); + } + + bool byte_buffer::write_int32(int data) + { + this->write_data_type(7); + return this->write(4, &data); + } + + bool byte_buffer::write_uint32(unsigned int data) + { + this->write_data_type(8); + return this->write(4, &data); + } + + bool byte_buffer::write_int64(__int64 data) + { + this->write_data_type(9); + return this->write(8, &data); + } + + bool byte_buffer::write_uint64(unsigned __int64 data) + { + this->write_data_type(10); + return this->write(8, &data); + } + + bool byte_buffer::write_data_type(char data) + { + if (!this->use_data_types_) return true; + return this->write(1, &data); + } + + bool byte_buffer::write_float(float data) + { + this->write_data_type(13); + return this->write(4, &data); + } + + bool byte_buffer::write_string(const std::string& data) + { + return this->write_string(data.data()); + } + + bool byte_buffer::write_string(const char* data) + { + this->write_data_type(16); + return this->write(static_cast(strlen(data)) + 1, data); + } + + bool byte_buffer::write_blob(const std::string& data) + { + return this->write_blob(data.data(), INT(data.size())); + } + + bool byte_buffer::write_blob(const char* data, const int length) + { + this->write_data_type(0x13); + this->write_uint32(length); + + return this->write(length, data); + } + + bool byte_buffer::write_array_header(const unsigned char type, const unsigned int element_count, + const unsigned int element_size) + { + const auto using_types = this->is_using_data_types(); + this->set_use_data_types(false); + + auto result = this->write_byte(type + 100); + + this->set_use_data_types(true); + result &= this->write_uint32(element_count * element_size); + this->set_use_data_types(false); + + result &= this->write_uint32(element_count); + + this->set_use_data_types(using_types); + return result; + } + + bool byte_buffer::read(const int bytes, void* output) + { + if (bytes + this->current_byte_ > this->buffer_.size()) return false; + + std::memmove(output, this->buffer_.data() + this->current_byte_, bytes); + this->current_byte_ += bytes; + + return true; + } + + bool byte_buffer::write(const int bytes, const void* data) + { + this->buffer_.append(reinterpret_cast(data), bytes); + this->current_byte_ += bytes; + return true; + } + + bool byte_buffer::write(const std::string& data) + { + return this->write(data.size(), data.data()); + } + + void byte_buffer::set_use_data_types(const bool use_data_types) + { + this->use_data_types_ = use_data_types; + } + + size_t byte_buffer::size() const + { + return this->buffer_.size(); + } + + bool byte_buffer::is_using_data_types() const + { + return use_data_types_; + } + + std::string& byte_buffer::get_buffer() + { + return this->buffer_; + } + + std::string byte_buffer::get_remaining() + { + return std::string(this->buffer_.begin() + this->current_byte_, this->buffer_.end()); + } + + bool byte_buffer::has_more_data() const + { + return this->buffer_.size() > this->current_byte_; + } +} diff --git a/src/game/demonware/i_server.hpp b/src/game/demonware/i_server.hpp index c41813b..b2e0b75 100644 --- a/src/game/demonware/i_server.hpp +++ b/src/game/demonware/i_server.hpp @@ -1,182 +1,201 @@ -#pragma once -#include "bit_buffer.hpp" -#include "byte_buffer.hpp" - -namespace demonware -{ - class reply - { - public: - virtual ~reply() = default; - virtual std::string get_data() = 0; - }; - - class raw_reply : public reply - { - public: - raw_reply() = default; - explicit raw_reply(std::string data) : buffer_(std::move(data)) {} - - virtual std::string get_data() override - { - return this->buffer_; - } - - protected: - std::string buffer_; - }; - - class typed_reply : public raw_reply - { - public: - typed_reply(uint8_t _type) : type_(_type) {} - - protected: - uint8_t get_type() const { return this->type_; } - - private: - uint8_t type_; - }; - - class encrypted_reply final : public typed_reply - { - public: - encrypted_reply(const uint8_t type, bit_buffer* bbuffer) : typed_reply(type) - { - this->buffer_.append(bbuffer->get_buffer()); - } - encrypted_reply(const uint8_t type, byte_buffer* bbuffer) : typed_reply(type) - { - this->buffer_.append(bbuffer->get_buffer()); - } - - virtual std::string get_data() override; - }; - - class unencrypted_reply final : public typed_reply - { - public: - unencrypted_reply(uint8_t _type, bit_buffer* bbuffer) : typed_reply(_type) - { - this->buffer_.append(bbuffer->get_buffer()); - } - unencrypted_reply(uint8_t _type, byte_buffer* bbuffer) : typed_reply(_type) - { - this->buffer_.append(bbuffer->get_buffer()); - } - - virtual std::string get_data() override; - }; - - class remote_reply; - class service_reply; - - class i_server - { - public: - virtual ~i_server() = default; - virtual int send(const char* buf, int len) = 0; - virtual int recv(char* buf, int len) = 0; - - virtual void send_reply(reply* reply) = 0; - - virtual std::shared_ptr create_message(uint8_t type) - { - auto reply = std::make_shared(this, type); - return reply; - } - - virtual std::shared_ptr create_reply(uint8_t type, uint32_t error = 0 /*Game::bdLobbyErrorCode::BD_NO_ERROR*/) - { - auto reply = std::make_shared(this, type, error); - return reply; - } - }; - - class remote_reply final - { - public: - remote_reply(i_server* server, uint8_t _type) : type_(_type), server_(server) {} - - template - void send(BufferType* buffer, const bool encrypted) - { - std::unique_ptr reply; - - if (encrypted) reply = std::make_unique(this->type_, buffer); - else reply = std::make_unique(this->type_, buffer); - this->server_->send_reply(reply.get()); - } - - uint8_t get_type() const { return this->type_; } - - private: - uint8_t type_; - i_server* server_; - }; - - class i_serializable - { - public: - virtual ~i_serializable() = default; - virtual void serialize(byte_buffer* /*buffer*/) {} - virtual void deserialize(byte_buffer* /*buffer*/) {} - }; - - class service_reply final - { - public: - service_reply(i_server* _server, uint8_t _type, uint32_t _error) : type_(_type), error_(_error), reply_(_server, 1) {} - - uint64_t send() - { - static uint64_t id = 0x8000000000000001; - const auto transaction_id = ++id; - - byte_buffer buffer; - buffer.write_uint64(transaction_id); - buffer.write_uint32(this->error_); - buffer.write_byte(this->type_); - - if (!this->error_) - { - buffer.write_uint32(uint32_t(this->objects_.size())); - if (!this->objects_.empty()) - { - buffer.write_uint32(uint32_t(this->objects_.size())); - - for (auto& object : this->objects_) - { - object->serialize(&buffer); - } - - this->objects_.clear(); - } - } - else - { - buffer.write_uint64(transaction_id); - } - - this->reply_.send(&buffer, true); - return transaction_id; - } - - void add(const std::shared_ptr& object) - { - this->objects_.push_back(object); - } - - void add(i_serializable* object) - { - this->add(std::shared_ptr(object)); - } - - private: - uint8_t type_; - uint32_t error_; - remote_reply reply_; - - std::vector> objects_; - }; -} +#pragma once +#include "bit_buffer.hpp" +#include "byte_buffer.hpp" + +namespace demonware +{ + class reply + { + public: + virtual ~reply() = default; + virtual std::string get_data() = 0; + }; + + class raw_reply : public reply + { + public: + raw_reply() = default; + + explicit raw_reply(std::string data) : buffer_(std::move(data)) + { + } + + virtual std::string get_data() override + { + return this->buffer_; + } + + protected: + std::string buffer_; + }; + + class typed_reply : public raw_reply + { + public: + typed_reply(uint8_t _type) : type_(_type) + { + } + + protected: + uint8_t get_type() const { return this->type_; } + + private: + uint8_t type_; + }; + + class encrypted_reply final : public typed_reply + { + public: + encrypted_reply(const uint8_t type, bit_buffer* bbuffer) : typed_reply(type) + { + this->buffer_.append(bbuffer->get_buffer()); + } + + encrypted_reply(const uint8_t type, byte_buffer* bbuffer) : typed_reply(type) + { + this->buffer_.append(bbuffer->get_buffer()); + } + + virtual std::string get_data() override; + }; + + class unencrypted_reply final : public typed_reply + { + public: + unencrypted_reply(uint8_t _type, bit_buffer* bbuffer) : typed_reply(_type) + { + this->buffer_.append(bbuffer->get_buffer()); + } + + unencrypted_reply(uint8_t _type, byte_buffer* bbuffer) : typed_reply(_type) + { + this->buffer_.append(bbuffer->get_buffer()); + } + + virtual std::string get_data() override; + }; + + class remote_reply; + class service_reply; + + class i_server + { + public: + virtual ~i_server() = default; + virtual int send(const char* buf, int len) = 0; + virtual int recv(char* buf, int len) = 0; + + virtual void send_reply(reply* reply) = 0; + + virtual std::shared_ptr create_message(uint8_t type) + { + auto reply = std::make_shared(this, type); + return reply; + } + + virtual std::shared_ptr create_reply(uint8_t type, + uint32_t error = 0 /*Game::bdLobbyErrorCode::BD_NO_ERROR*/) + { + auto reply = std::make_shared(this, type, error); + return reply; + } + }; + + class remote_reply final + { + public: + remote_reply(i_server* server, uint8_t _type) : type_(_type), server_(server) + { + } + + template + void send(BufferType* buffer, const bool encrypted) + { + std::unique_ptr reply; + + if (encrypted) reply = std::make_unique(this->type_, buffer); + else reply = std::make_unique(this->type_, buffer); + this->server_->send_reply(reply.get()); + } + + uint8_t get_type() const { return this->type_; } + + private: + uint8_t type_; + i_server* server_; + }; + + class i_serializable + { + public: + virtual ~i_serializable() = default; + + virtual void serialize(byte_buffer* /*buffer*/) + { + } + + virtual void deserialize(byte_buffer* /*buffer*/) + { + } + }; + + class service_reply final + { + public: + service_reply(i_server* _server, uint8_t _type, uint32_t _error) : type_(_type), error_(_error), + reply_(_server, 1) + { + } + + uint64_t send() + { + static uint64_t id = 0x8000000000000001; + const auto transaction_id = ++id; + + byte_buffer buffer; + buffer.write_uint64(transaction_id); + buffer.write_uint32(this->error_); + buffer.write_byte(this->type_); + + if (!this->error_) + { + buffer.write_uint32(uint32_t(this->objects_.size())); + if (!this->objects_.empty()) + { + buffer.write_uint32(uint32_t(this->objects_.size())); + + for (auto& object : this->objects_) + { + object->serialize(&buffer); + } + + this->objects_.clear(); + } + } + else + { + buffer.write_uint64(transaction_id); + } + + this->reply_.send(&buffer, true); + return transaction_id; + } + + void add(const std::shared_ptr& object) + { + this->objects_.push_back(object); + } + + void add(i_serializable* object) + { + this->add(std::shared_ptr(object)); + } + + private: + uint8_t type_; + uint32_t error_; + remote_reply reply_; + + std::vector> objects_; + }; +} diff --git a/src/game/demonware/stun_server.cpp b/src/game/demonware/stun_server.cpp index 6e5595f..6c41819 100644 --- a/src/game/demonware/stun_server.cpp +++ b/src/game/demonware/stun_server.cpp @@ -1,75 +1,75 @@ -#include -#include -#include "module/dw.hpp" -#include "utils/cryptography.hpp" -#include "byte_buffer.hpp" - -namespace demonware -{ - stun_server::stun_server(std::string _name) : name_(std::move(_name)) - { - this->address_ = utils::cryptography::jenkins_one_at_a_time::compute(this->name_); - } - - unsigned long stun_server::get_address() const - { - return this->address_; - } - - void stun_server::ip_discovery(SOCKET s, const sockaddr* to, int tolen) const - { - const uint32_t ip = 0x0100007f; - - byte_buffer buffer; - buffer.set_use_data_types(false); - buffer.write_byte(31); // type - buffer.write_byte(2); // version - buffer.write_byte(0); // version - buffer.write_uint32(ip); // external ip - buffer.write_uint16(3074); // port - - dw::send_datagram_packet(s, buffer.get_buffer(), to, tolen); - } - - void stun_server::nat_discovery(SOCKET s, const sockaddr* to, int tolen) const - { - const uint32_t ip = 0x0100007f; - - byte_buffer buffer; - buffer.set_use_data_types(false); - buffer.write_byte(21); // type - buffer.write_byte(2); // version - buffer.write_byte(0); // version - buffer.write_uint32(ip); // external ip - buffer.write_uint16(3074); // port - buffer.write_uint32(this->get_address()); // server ip - buffer.write_uint16(3074); // server port - - dw::send_datagram_packet(s, buffer.get_buffer(), to, tolen); - } - - int stun_server::send(const SOCKET s, const char* buf, int len, const sockaddr* to, int tolen) const - { - uint8_t type, version, padding; - - byte_buffer buffer(std::string(buf, len)); - buffer.set_use_data_types(false); - buffer.read_byte(&type); - buffer.read_byte(&version); - buffer.read_byte(&padding); - - switch (type) - { - case 30: - this->ip_discovery(s, to, tolen); - break; - case 20: - this->nat_discovery(s, to, tolen); - break; - default: - break; - } - - return len; - } -} +#include +#include +#include "module/dw.hpp" +#include "utils/cryptography.hpp" +#include "byte_buffer.hpp" + +namespace demonware +{ + stun_server::stun_server(std::string _name) : name_(std::move(_name)) + { + this->address_ = utils::cryptography::jenkins_one_at_a_time::compute(this->name_); + } + + unsigned long stun_server::get_address() const + { + return this->address_; + } + + void stun_server::ip_discovery(SOCKET s, const sockaddr* to, const int tolen) const + { + const uint32_t ip = 0x0100007f; + + byte_buffer buffer; + buffer.set_use_data_types(false); + buffer.write_byte(31); // type + buffer.write_byte(2); // version + buffer.write_byte(0); // version + buffer.write_uint32(ip); // external ip + buffer.write_uint16(3074); // port + + dw::send_datagram_packet(s, buffer.get_buffer(), to, tolen); + } + + void stun_server::nat_discovery(SOCKET s, const sockaddr* to, const int tolen) const + { + const uint32_t ip = 0x0100007f; + + byte_buffer buffer; + buffer.set_use_data_types(false); + buffer.write_byte(21); // type + buffer.write_byte(2); // version + buffer.write_byte(0); // version + buffer.write_uint32(ip); // external ip + buffer.write_uint16(3074); // port + buffer.write_uint32(this->get_address()); // server ip + buffer.write_uint16(3074); // server port + + dw::send_datagram_packet(s, buffer.get_buffer(), to, tolen); + } + + int stun_server::send(const SOCKET s, const char* buf, const int len, const sockaddr* to, const int tolen) const + { + uint8_t type, version, padding; + + byte_buffer buffer(std::string(buf, len)); + buffer.set_use_data_types(false); + buffer.read_byte(&type); + buffer.read_byte(&version); + buffer.read_byte(&padding); + + switch (type) + { + case 30: + this->ip_discovery(s, to, tolen); + break; + case 20: + this->nat_discovery(s, to, tolen); + break; + default: + break; + } + + return len; + } +} diff --git a/src/game/demonware/stun_server.hpp b/src/game/demonware/stun_server.hpp index 9a9f0fe..54b40b5 100644 --- a/src/game/demonware/stun_server.hpp +++ b/src/game/demonware/stun_server.hpp @@ -1,21 +1,21 @@ -#pragma once - -namespace demonware -{ - class stun_server final - { - public: - explicit stun_server(std::string name); - - unsigned long get_address() const; - - int send(SOCKET s, const char* buf, int len, const sockaddr* to, int tolen) const; - - private: - std::string name_; - unsigned long address_; - - void ip_discovery(SOCKET s, const sockaddr* to, int tolen) const; - void nat_discovery(SOCKET s, const sockaddr* to, int tolen) const; - }; -} +#pragma once + +namespace demonware +{ + class stun_server final + { + public: + explicit stun_server(std::string name); + + unsigned long get_address() const; + + int send(SOCKET s, const char* buf, int len, const sockaddr* to, int tolen) const; + + private: + std::string name_; + unsigned long address_; + + void ip_discovery(SOCKET s, const sockaddr* to, int tolen) const; + void nat_discovery(SOCKET s, const sockaddr* to, int tolen) const; + }; +} diff --git a/src/game/game.cpp b/src/game/game.cpp index f9caa74..93e1861 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -85,7 +85,7 @@ namespace game void Conbuf_AppendText(const char* message) { - if(is_dedi()) + if (is_dedi()) { conbuf_append_text_dedicated(message); } @@ -247,7 +247,8 @@ namespace game } else { - return reinterpret_cast(0x4EFAA0)(id, stringValue, paramcount); + return reinterpret_cast(0x4EFAA0)( + id, stringValue, paramcount); } } @@ -297,7 +298,7 @@ namespace game launcher::mode get_mode() { - if(mode == launcher::mode::none) + if (mode == launcher::mode::none) { throw std::runtime_error("Launcher mode not valid. Something must be wrong."); } @@ -330,7 +331,8 @@ namespace game native::DB_LoadXAssets = native::DB_LoadXAssets_t(SELECT_VALUE(0x48A8E0, 0x4CD020, 0x44F770)); - native::Dvar_SetFromStringByName = native::Dvar_SetFromStringByName_t(SELECT_VALUE(0x4DD090, 0x5BF740, 0x518DF0)); + native::Dvar_SetFromStringByName = native::Dvar_SetFromStringByName_t( + SELECT_VALUE(0x4DD090, 0x5BF740, 0x518DF0)); native::G_RunFrame = native::G_RunFrame_t(SELECT_VALUE(0x52EAA0, 0x50CB70, 0x48AD60)); @@ -358,11 +360,11 @@ namespace game native::scr_VmPub = reinterpret_cast(SELECT_VALUE(0x1BF2580, 0x20B4A80, 0x1F5B080)); - native::scr_instanceFunctions = reinterpret_cast( SELECT_VALUE(0x184CDB0, 0x1D4F258, - 0x1BF59C8)); - native::scr_globalFunctions = reinterpret_cast( SELECT_VALUE(0x186C68C, 0x1D6EB34, - 0x1C152A4 -)); + native::scr_instanceFunctions = reinterpret_cast(SELECT_VALUE(0x184CDB0, 0x1D4F258, + 0x1BF59C8)); + native::scr_globalFunctions = reinterpret_cast(SELECT_VALUE(0x186C68C, 0x1D6EB34, + 0x1C152A4 + )); native::g_script_error_level = reinterpret_cast(SELECT_VALUE(0x1BEFCFC, 0x20B21FC, 0x1F5B058)); native::g_script_error = reinterpret_cast(SELECT_VALUE(0x1BF1D18, 0x20B4218, 0x1F5A818)); diff --git a/src/game/game.hpp b/src/game/game.hpp index 16c8931..720ca57 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -20,7 +20,7 @@ namespace game typedef void (*DB_LoadXAssets_t)(XZoneInfo* zoneInfo, unsigned int zoneCount, int sync); extern DB_LoadXAssets_t DB_LoadXAssets; - typedef void (*Dvar_SetFromStringByName_t)(const char *dvarName, const char *string); + typedef void (*Dvar_SetFromStringByName_t)(const char* dvarName, const char* string); extern Dvar_SetFromStringByName_t Dvar_SetFromStringByName; typedef int (*G_RunFrame_t)(int, int); diff --git a/src/game/scripting/entity.cpp b/src/game/scripting/entity.cpp index f171676..17e65f7 100644 --- a/src/game/scripting/entity.cpp +++ b/src/game/scripting/entity.cpp @@ -1,134 +1,134 @@ -#include "std_include.hpp" -#include "context.hpp" - -namespace game -{ - namespace scripting - { - entity::entity() : entity(nullptr, 0) - { - } - - entity::entity(const entity& other) : entity(other.context_, other.entity_id_) - { - } - - entity::entity(entity&& other) noexcept - { - if (&other == this) return; - - this->context_ = other.context_; - this->entity_id_ = other.entity_id_; - - other.context_ = nullptr; - other.entity_id_ = 0; - } - - entity::entity(context* context, const unsigned int entity_id) : context_(context), entity_id_(entity_id) - { - this->add(); - } - - entity::~entity() - { - this->release(); - } - - entity& entity::operator=(const entity& other) - { - if (&other != this) - { - this->release(); - - this->context_ = other.context_; - this->entity_id_ = other.entity_id_; - - this->add(); - } - - return *this; - } - - entity& entity::operator=(entity&& other) noexcept - { - if (&other != this) - { - this->release(); - - this->context_ = other.context_; - this->entity_id_ = other.entity_id_; - - other.context_ = nullptr; - other.entity_id_ = 0; - } - - return *this; - } - - event_listener_handle entity::on_notify(const std::string& event, - const std::function)>& - callback, - const bool is_volatile) - const - { - event_listener listener; - listener.event = event; - listener.callback = callback; - listener.entity_id = this->entity_id_; - listener.is_volatile = is_volatile; - - return this->context_->get_event_handler()->add_event_listener(listener); - } - - unsigned int entity::get_entity_id() const - { - return this->entity_id_; - } - - native::scr_entref_t entity::get_entity_reference() const - { - return game::native::Scr_GetEntityIdRef(this->get_entity_id()); - } - - chaiscript::Boxed_Value entity::call(const std::string& function, - const std::vector& arguments) const - { - return this->context_->get_executer()->call(function, this->get_entity_id(), arguments); - } - - void entity::notify(const std::string& event, - const std::vector& arguments) const - { - this->context_->get_executer()->notify(event, this->get_entity_id(), arguments); - } - - void entity::set(const std::string& field, const chaiscript::Boxed_Value& value) const - { - this->context_->get_executer()->set_entity_field(field, this->get_entity_id(), value); - } - - chaiscript::Boxed_Value entity::get(const std::string& field) const - { - return this->context_->get_executer()->get_entity_field(field, this->get_entity_id()); - } - - void entity::add() const - { - if (this->entity_id_) - { - native::VariableValue value{}; - value.type = native::SCRIPT_OBJECT; - value.u.entityId = this->entity_id_; - native::AddRefToValue(&value); - } - } - - void entity::release() const - { - if (this->entity_id_) - { - native::RemoveRefToValue(native::SCRIPT_OBJECT, {static_cast(this->entity_id_)}); - } - } - } -} +#include "std_include.hpp" +#include "context.hpp" + +namespace game +{ + namespace scripting + { + entity::entity() : entity(nullptr, 0) + { + } + + entity::entity(const entity& other) : entity(other.context_, other.entity_id_) + { + } + + entity::entity(entity&& other) noexcept + { + if (&other == this) return; + + this->context_ = other.context_; + this->entity_id_ = other.entity_id_; + + other.context_ = nullptr; + other.entity_id_ = 0; + } + + entity::entity(context* context, const unsigned int entity_id) : context_(context), entity_id_(entity_id) + { + this->add(); + } + + entity::~entity() + { + this->release(); + } + + entity& entity::operator=(const entity& other) + { + if (&other != this) + { + this->release(); + + this->context_ = other.context_; + this->entity_id_ = other.entity_id_; + + this->add(); + } + + return *this; + } + + entity& entity::operator=(entity&& other) noexcept + { + if (&other != this) + { + this->release(); + + this->context_ = other.context_; + this->entity_id_ = other.entity_id_; + + other.context_ = nullptr; + other.entity_id_ = 0; + } + + return *this; + } + + event_listener_handle entity::on_notify(const std::string& event, + const std::function)>& + callback, + const bool is_volatile) + const + { + event_listener listener; + listener.event = event; + listener.callback = callback; + listener.entity_id = this->entity_id_; + listener.is_volatile = is_volatile; + + return this->context_->get_event_handler()->add_event_listener(listener); + } + + unsigned int entity::get_entity_id() const + { + return this->entity_id_; + } + + native::scr_entref_t entity::get_entity_reference() const + { + return game::native::Scr_GetEntityIdRef(this->get_entity_id()); + } + + chaiscript::Boxed_Value entity::call(const std::string& function, + const std::vector& arguments) const + { + return this->context_->get_executer()->call(function, this->get_entity_id(), arguments); + } + + void entity::notify(const std::string& event, + const std::vector& arguments) const + { + this->context_->get_executer()->notify(event, this->get_entity_id(), arguments); + } + + void entity::set(const std::string& field, const chaiscript::Boxed_Value& value) const + { + this->context_->get_executer()->set_entity_field(field, this->get_entity_id(), value); + } + + chaiscript::Boxed_Value entity::get(const std::string& field) const + { + return this->context_->get_executer()->get_entity_field(field, this->get_entity_id()); + } + + void entity::add() const + { + if (this->entity_id_) + { + native::VariableValue value; + value.type = native::SCRIPT_OBJECT; + value.u.entityId = this->entity_id_; + native::AddRefToValue(&value); + } + } + + void entity::release() const + { + if (this->entity_id_) + { + native::RemoveRefToValue(native::SCRIPT_OBJECT, {static_cast(this->entity_id_)}); + } + } + } +} diff --git a/src/game/scripting/event_handler.cpp b/src/game/scripting/event_handler.cpp index df594e6..e9e09b8 100644 --- a/src/game/scripting/event_handler.cpp +++ b/src/game/scripting/event_handler.cpp @@ -1,124 +1,124 @@ -#include "std_include.hpp" -#include "context.hpp" - -namespace game -{ - namespace scripting - { - event_handler::event_handler(context* context) : context_(context) - { - const auto chai = this->context_->get_chai(); - - chai->add(chaiscript::user_type(), "_event_listener_handle"); - chai->add(chaiscript::constructor(), "_event_listener_handle"); - chai->add(chaiscript::constructor(), - "_event_listener_handle"); - - chai->add(chaiscript::fun( - [](event_listener_handle& lhs, const event_listener_handle& rhs) -> event_listener_handle& - { - return lhs = rhs; - }), "="); - - chai->add(chaiscript::fun([this](const event_listener_handle& handle) - { - this->remove(handle); - }), "clear"); - } - - void event_handler::dispatch(event* event) - { - try - { - std::vector arguments; - - for (auto argument : event->arguments) - { - arguments.push_back(this->context_->get_parameters()->load(argument)); - } - - this->dispatch_to_specific_listeners(event, arguments); - this->dispatch_to_generic_listeners(event, arguments); - } - catch (chaiscript::exception::eval_error& e) - { - throw std::runtime_error(e.pretty_print()); - } - } - - void event_handler::dispatch_to_specific_listeners(event* event, - const std::vector& arguments) - { - for (auto listener : this->event_listeners_) - { - if (listener->event == event->name && listener->entity_id == event->entity_id) - { - if (listener->is_volatile) - { - this->event_listeners_.remove(listener); - } - - listener->callback(arguments); - } - } - } - - void event_handler::dispatch_to_generic_listeners(event* event, - const std::vector& arguments) - { - for (auto listener : this->generic_event_listeners_) - { - if (listener->event == event->name) - { - if (listener->is_volatile) - { - this->generic_event_listeners_.remove(listener); - } - - listener->callback(entity(this->context_, event->entity_id), arguments); - } - } - } - - event_listener_handle event_handler::add_event_listener(event_listener listener) - { - listener.id = ++this->current_listener_id_; - this->event_listeners_.add(listener); - return {listener.id}; - } - - event_listener_handle event_handler::add_event_listener(generic_event_listener listener) - { - listener.id = ++this->current_listener_id_; - this->generic_event_listeners_.add(listener); - return {listener.id}; - } - - void event_handler::clear() - { - this->event_listeners_.clear(); - this->generic_event_listeners_.clear(); - } - - void event_handler::remove(const event_listener_handle& handle) - { - for (auto task : this->event_listeners_) - { - if (task->id == handle.id) - { - this->event_listeners_.remove(task); - return; - } - } - - for (auto task : this->generic_event_listeners_) - { - if (task->id == handle.id) - { - this->generic_event_listeners_.remove(task); - return; - } - } - } - } -} +#include "std_include.hpp" +#include "context.hpp" + +namespace game +{ + namespace scripting + { + event_handler::event_handler(context* context) : context_(context) + { + const auto chai = this->context_->get_chai(); + + chai->add(chaiscript::user_type(), "_event_listener_handle"); + chai->add(chaiscript::constructor(), "_event_listener_handle"); + chai->add(chaiscript::constructor(), + "_event_listener_handle"); + + chai->add(chaiscript::fun( + [](event_listener_handle& lhs, const event_listener_handle& rhs) -> event_listener_handle& + { + return lhs = rhs; + }), "="); + + chai->add(chaiscript::fun([this](const event_listener_handle& handle) + { + this->remove(handle); + }), "clear"); + } + + void event_handler::dispatch(event* event) + { + try + { + std::vector arguments; + + for (auto argument : event->arguments) + { + arguments.push_back(this->context_->get_parameters()->load(argument)); + } + + this->dispatch_to_specific_listeners(event, arguments); + this->dispatch_to_generic_listeners(event, arguments); + } + catch (chaiscript::exception::eval_error& e) + { + throw std::runtime_error(e.pretty_print()); + } + } + + void event_handler::dispatch_to_specific_listeners(event* event, + const std::vector& arguments) + { + for (auto listener : this->event_listeners_) + { + if (listener->event == event->name && listener->entity_id == event->entity_id) + { + if (listener->is_volatile) + { + this->event_listeners_.remove(listener); + } + + listener->callback(arguments); + } + } + } + + void event_handler::dispatch_to_generic_listeners(event* event, + const std::vector& arguments) + { + for (auto listener : this->generic_event_listeners_) + { + if (listener->event == event->name) + { + if (listener->is_volatile) + { + this->generic_event_listeners_.remove(listener); + } + + listener->callback(entity(this->context_, event->entity_id), arguments); + } + } + } + + event_listener_handle event_handler::add_event_listener(event_listener listener) + { + listener.id = ++this->current_listener_id_; + this->event_listeners_.add(listener); + return {listener.id}; + } + + event_listener_handle event_handler::add_event_listener(generic_event_listener listener) + { + listener.id = ++this->current_listener_id_; + this->generic_event_listeners_.add(listener); + return {listener.id}; + } + + void event_handler::clear() + { + this->event_listeners_.clear(); + this->generic_event_listeners_.clear(); + } + + void event_handler::remove(const event_listener_handle& handle) + { + for (const auto task : this->event_listeners_) + { + if (task->id == handle.id) + { + this->event_listeners_.remove(task); + return; + } + } + + for (const auto task : this->generic_event_listeners_) + { + if (task->id == handle.id) + { + this->generic_event_listeners_.remove(task); + return; + } + } + } + } +} diff --git a/src/game/scripting/executer.cpp b/src/game/scripting/executer.cpp index 1585547..c57a22e 100644 --- a/src/game/scripting/executer.cpp +++ b/src/game/scripting/executer.cpp @@ -1,172 +1,172 @@ -#include "std_include.hpp" -#include "game/game.hpp" -#include "utils/string.hpp" -#include "functions.hpp" -#include "stack_isolation.hpp" -#include "safe_executer.hpp" -#include "context.hpp" - -namespace game -{ - namespace scripting - { - executer::executer(context* context) : context_(context) - { - } - - int executer::get_field_id(const int classnum, const std::string& field) const - { - const auto field_name = utils::string::to_lower(field); - const auto class_id = native::g_classMap[classnum].id; - const auto field_str = native::SL_GetString(field_name.data(), 1); - const auto _ = gsl::finally([field_str]() - { - native::RemoveRefToValue(native::SCRIPT_STRING, {int(field_str)}); - }); - - const auto offset = native::FindVariable(class_id, field_str); - if (offset) - { - const auto index = 4 * (offset + 0xC800 * (class_id & 1)); - return PINT(SELECT_VALUE(0x1A3BC80, 0x1EFE180, 0x1DC8800))[index]; - } - - return -1; - } - - void executer::set_entity_field(const std::string& field, const unsigned int entity_id, - const chaiscript::Boxed_Value& value) - { - const auto entref = native::Scr_GetEntityIdRef(entity_id); - const int id = get_field_id(entref.raw.classnum, field); - - if (id != -1) - { - stack_isolation _; - this->context_->get_parameters()->push(value); - - native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount; - native::scr_VmPub->inparamcount = 0; - - if (!safe_executer::set_entity_field(entref, id)) - { - throw std::runtime_error("Failed to set value for field '" + field + "'"); - } - } - else - { - this->entity_fields_[entity_id][field] = value; - } - } - - chaiscript::Boxed_Value executer::get_entity_field(const std::string& field, const unsigned int entity_id) - { - const auto entref = native::Scr_GetEntityIdRef(entity_id); - const auto id = this->get_field_id(entref.raw.classnum, field); - - if (id != -1) - { - stack_isolation _; - - native::VariableValue value{}; - if (!safe_executer::get_entity_field(entref, id, &value)) - { - throw std::runtime_error("Failed to get value for field '" + field + "'"); - } - - const auto $ = gsl::finally([value]() - { - native::RemoveRefToValue(value.type, value.u); - }); - - return this->context_->get_parameters()->load(value); - } - else - { - const auto& map = this->entity_fields_[entity_id]; - const auto value = map.find(field); - if (value != map.end()) - { - return value->second; - } - } - - return {}; - } - - void executer::notify(const std::string& event, const unsigned int entity_id, - std::vector arguments) const - { - stack_isolation _; - - std::reverse(arguments.begin(), arguments.end()); - for (auto argument : arguments) - { - this->context_->get_parameters()->push(argument); - } - - const auto event_id = native::SL_GetString(event.data(), 0); - native::Scr_NotifyId(entity_id, event_id, native::scr_VmPub->inparamcount); - } - - chaiscript::Boxed_Value executer::call(const std::string& function, const unsigned int entity_id, - std::vector arguments) const - { - const auto function_index = find_function_index(function, entity_id == 0); - if (function_index < 0) - { - throw std::runtime_error("No function found for name '" + function + "'"); - } - - const auto entity = function_index > 0x1C7 - ? native::Scr_GetEntityIdRef(entity_id) - : native::scr_entref_t{~0u}; - - const auto function_ptr = native::Scr_GetFunc(function_index); - - stack_isolation _; - - std::reverse(arguments.begin(), arguments.end()); - for (const auto& argument : arguments) - { - this->context_->get_parameters()->push(argument); - } - - native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount; - native::scr_VmPub->inparamcount = 0; - - if (!safe_executer::call(function_ptr, entity)) - { - throw std::runtime_error("Error executing function '" + function + "'"); - } - - return this->context_->get_parameters()->get_return_value(); - } - - int executer::find_function_index(const std::string& function, const bool prefer_global) - { - const auto target = utils::string::to_lower(function); - - const auto primary_map = prefer_global - ? &global_function_map - : &instance_function_map; - const auto secondary_map = !prefer_global - ? &global_function_map - : &instance_function_map; - - auto function_entry = primary_map->find(target); - if (function_entry != primary_map->end()) - { - return function_entry->second; - } - - function_entry = secondary_map->find(target); - if (function_entry != secondary_map->end()) - { - return function_entry->second; - } - - return -1; - } - } -} +#include "std_include.hpp" +#include "game/game.hpp" +#include "utils/string.hpp" +#include "functions.hpp" +#include "stack_isolation.hpp" +#include "safe_executer.hpp" +#include "context.hpp" + +namespace game +{ + namespace scripting + { + executer::executer(context* context) : context_(context) + { + } + + int executer::get_field_id(const int classnum, const std::string& field) const + { + const auto field_name = utils::string::to_lower(field); + const auto class_id = native::g_classMap[classnum].id; + const auto field_str = native::SL_GetString(field_name.data(), 1); + const auto _ = gsl::finally([field_str]() + { + native::RemoveRefToValue(native::SCRIPT_STRING, {int(field_str)}); + }); + + const auto offset = native::FindVariable(class_id, field_str); + if (offset) + { + const auto index = 4 * (offset + 0xC800 * (class_id & 1)); + return PINT(SELECT_VALUE(0x1A3BC80, 0x1EFE180, 0x1DC8800))[index]; + } + + return -1; + } + + void executer::set_entity_field(const std::string& field, const unsigned int entity_id, + const chaiscript::Boxed_Value& value) + { + const auto entref = native::Scr_GetEntityIdRef(entity_id); + const int id = get_field_id(entref.raw.classnum, field); + + if (id != -1) + { + stack_isolation _; + this->context_->get_parameters()->push(value); + + native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount; + native::scr_VmPub->inparamcount = 0; + + if (!safe_executer::set_entity_field(entref, id)) + { + throw std::runtime_error("Failed to set value for field '" + field + "'"); + } + } + else + { + this->entity_fields_[entity_id][field] = value; + } + } + + chaiscript::Boxed_Value executer::get_entity_field(const std::string& field, const unsigned int entity_id) + { + const auto entref = native::Scr_GetEntityIdRef(entity_id); + const auto id = this->get_field_id(entref.raw.classnum, field); + + if (id != -1) + { + stack_isolation _; + + native::VariableValue value{}; + if (!safe_executer::get_entity_field(entref, id, &value)) + { + throw std::runtime_error("Failed to get value for field '" + field + "'"); + } + + const auto $ = gsl::finally([value]() + { + native::RemoveRefToValue(value.type, value.u); + }); + + return this->context_->get_parameters()->load(value); + } + else + { + const auto& map = this->entity_fields_[entity_id]; + const auto value = map.find(field); + if (value != map.end()) + { + return value->second; + } + } + + return {}; + } + + void executer::notify(const std::string& event, const unsigned int entity_id, + std::vector arguments) const + { + stack_isolation _; + + std::reverse(arguments.begin(), arguments.end()); + for (auto argument : arguments) + { + this->context_->get_parameters()->push(argument); + } + + const auto event_id = native::SL_GetString(event.data(), 0); + native::Scr_NotifyId(entity_id, event_id, native::scr_VmPub->inparamcount); + } + + chaiscript::Boxed_Value executer::call(const std::string& function, const unsigned int entity_id, + std::vector arguments) const + { + const auto function_index = find_function_index(function, entity_id == 0); + if (function_index < 0) + { + throw std::runtime_error("No function found for name '" + function + "'"); + } + + const auto entity = function_index > 0x1C7 + ? native::Scr_GetEntityIdRef(entity_id) + : native::scr_entref_t{~0u}; + + const auto function_ptr = native::Scr_GetFunc(function_index); + + stack_isolation _; + + std::reverse(arguments.begin(), arguments.end()); + for (const auto& argument : arguments) + { + this->context_->get_parameters()->push(argument); + } + + native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount; + native::scr_VmPub->inparamcount = 0; + + if (!safe_executer::call(function_ptr, entity)) + { + throw std::runtime_error("Error executing function '" + function + "'"); + } + + return this->context_->get_parameters()->get_return_value(); + } + + int executer::find_function_index(const std::string& function, const bool prefer_global) + { + const auto target = utils::string::to_lower(function); + + const auto primary_map = prefer_global + ? &global_function_map + : &instance_function_map; + const auto secondary_map = !prefer_global + ? &global_function_map + : &instance_function_map; + + auto function_entry = primary_map->find(target); + if (function_entry != primary_map->end()) + { + return function_entry->second; + } + + function_entry = secondary_map->find(target); + if (function_entry != secondary_map->end()) + { + return function_entry->second; + } + + return -1; + } + } +} diff --git a/src/game/scripting/functions.hpp b/src/game/scripting/functions.hpp index 281fdce..046fe78 100644 --- a/src/game/scripting/functions.hpp +++ b/src/game/scripting/functions.hpp @@ -1,3 +1,5 @@ +#pragma once + namespace game { namespace scripting diff --git a/src/game/scripting/parameters.cpp b/src/game/scripting/parameters.cpp index 7cb427f..5f55c92 100644 --- a/src/game/scripting/parameters.cpp +++ b/src/game/scripting/parameters.cpp @@ -1,152 +1,153 @@ -#include "std_include.hpp" -#include "context.hpp" - -namespace game -{ - namespace scripting - { - parameters::parameters(context* context) : context_(context) - { - } - - chaiscript::Boxed_Value parameters::load(const native::VariableValue value) const - { - if (value.type == native::SCRIPT_STRING) - { - const std::string string = native::SL_ConvertToString(value.u.stringValue); - return chaiscript::var(string); - } - else if (value.type == native::SCRIPT_FLOAT) - { - return chaiscript::var(value.u.floatValue); - } - else if (value.type == native::SCRIPT_INTEGER) - { - return chaiscript::var(value.u.intValue); - } - else if (value.type == native::SCRIPT_OBJECT) - { - return chaiscript::var(entity(this->context_, value.u.entityId)); - } - else if (value.type == native::SCRIPT_VECTOR) - { - std::vector values; - values.push_back(chaiscript::var(value.u.vectorValue[0])); - values.push_back(chaiscript::var(value.u.vectorValue[1])); - values.push_back(chaiscript::var(value.u.vectorValue[2])); - - return chaiscript::var(values); - } - - return {}; - } - - void parameters::push(const chaiscript::Boxed_Value& value) const - { - if (native::scr_VmPub->outparamcount) - { - native::Scr_ClearOutParams(); - } - - if (native::scr_VmPub->top == native::scr_VmPub->maxstack) - { - throw std::runtime_error("Internal script stack overflow"); - } - - native::VariableValue* value_ptr = ++native::scr_VmPub->top; - ++native::scr_VmPub->inparamcount; - - value_ptr->type = native::SCRIPT_NONE; - value_ptr->u.intValue = 0; - - if (value.get_type_info() == typeid(float)) - { - const auto real_value = this->context_->get_chai()->boxed_cast(value); - value_ptr->type = native::SCRIPT_FLOAT; - value_ptr->u.floatValue = real_value; - } - else if (value.get_type_info() == typeid(double)) - { - const auto real_value = this->context_->get_chai()->boxed_cast(value); - value_ptr->type = native::SCRIPT_FLOAT; - value_ptr->u.floatValue = static_cast(real_value); - } - else if (value.get_type_info() == typeid(int)) - { - const auto real_value = this->context_->get_chai()->boxed_cast(value); - value_ptr->type = native::SCRIPT_INTEGER; - value_ptr->u.intValue = real_value; - } - else if (value.get_type_info() == typeid(bool)) - { - const auto real_value = this->context_->get_chai()->boxed_cast(value); - value_ptr->type = native::SCRIPT_INTEGER; - value_ptr->u.intValue = real_value; - } - else if (value.get_type_info() == typeid(entity)) - { - const auto real_value = this->context_->get_chai()->boxed_cast(value); - value_ptr->type = native::SCRIPT_OBJECT; - value_ptr->u.entityId = real_value.get_entity_id(); - - game::native::AddRefToValue(value_ptr); - } - else if (value.get_type_info() == typeid(std::string)) - { - const auto real_value = this->context_->get_chai()->boxed_cast(value); - value_ptr->type = native::SCRIPT_STRING; - value_ptr->u.stringValue = game::native::SL_GetString(real_value.data(), 0); - } - else if (value.get_type_info() == typeid(std::vector)) - { - float values[3]; - const auto real_value = this->context_->get_chai()->boxed_cast>(value); - if (real_value.size() != 3) - { - throw std::runtime_error("Invalid vector length. Size must be exactly 3"); - } - - const auto unbox_float = [&real_value, this](const size_t index) -> float - { - const auto value = real_value[index]; - if (value.get_type_info() == typeid(float)) - { - return this->context_->get_chai()->boxed_cast(value); - } - if (value.get_type_info() == typeid(double)) - { - return float(this->context_->get_chai()->boxed_cast(value)); - } - if (value.get_type_info() == typeid(int)) - { - return float(this->context_->get_chai()->boxed_cast(value)); - } - - throw std::runtime_error("Vector element at index " + std::to_string(index) + " is not a number"); - }; - - values[0] = unbox_float(0); - values[1] = unbox_float(1); - values[2] = unbox_float(2); - - value_ptr->type = native::SCRIPT_VECTOR; - value_ptr->u.vectorValue = native::Scr_AllocVector(values); - } - else - { - throw std::runtime_error("Unable to unbox value of type '" + value.get_type_info().bare_name() + "'"); - } - } - - chaiscript::Boxed_Value parameters::get_return_value() const - { - if (native::scr_VmPub->inparamcount == 0) return {}; - - native::Scr_ClearOutParams(); - native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount; - native::scr_VmPub->inparamcount = 0; - - return this->load(native::scr_VmPub->top[1 - native::scr_VmPub->outparamcount]); - } - } -} +#include "std_include.hpp" +#include "context.hpp" + +namespace game +{ + namespace scripting + { + parameters::parameters(context* context) : context_(context) + { + } + + chaiscript::Boxed_Value parameters::load(const native::VariableValue value) const + { + if (value.type == native::SCRIPT_STRING) + { + const std::string string = native::SL_ConvertToString(value.u.stringValue); + return chaiscript::var(string); + } + else if (value.type == native::SCRIPT_FLOAT) + { + return chaiscript::var(value.u.floatValue); + } + else if (value.type == native::SCRIPT_INTEGER) + { + return chaiscript::var(value.u.intValue); + } + else if (value.type == native::SCRIPT_OBJECT) + { + return chaiscript::var(entity(this->context_, value.u.entityId)); + } + else if (value.type == native::SCRIPT_VECTOR) + { + std::vector values; + values.push_back(chaiscript::var(value.u.vectorValue[0])); + values.push_back(chaiscript::var(value.u.vectorValue[1])); + values.push_back(chaiscript::var(value.u.vectorValue[2])); + + return chaiscript::var(values); + } + + return {}; + } + + void parameters::push(const chaiscript::Boxed_Value& value) const + { + if (native::scr_VmPub->outparamcount) + { + native::Scr_ClearOutParams(); + } + + if (native::scr_VmPub->top == native::scr_VmPub->maxstack) + { + throw std::runtime_error("Internal script stack overflow"); + } + + native::VariableValue* value_ptr = ++native::scr_VmPub->top; + ++native::scr_VmPub->inparamcount; + + value_ptr->type = native::SCRIPT_NONE; + value_ptr->u.intValue = 0; + + if (value.get_type_info() == typeid(float)) + { + const auto real_value = this->context_->get_chai()->boxed_cast(value); + value_ptr->type = native::SCRIPT_FLOAT; + value_ptr->u.floatValue = real_value; + } + else if (value.get_type_info() == typeid(double)) + { + const auto real_value = this->context_->get_chai()->boxed_cast(value); + value_ptr->type = native::SCRIPT_FLOAT; + value_ptr->u.floatValue = static_cast(real_value); + } + else if (value.get_type_info() == typeid(int)) + { + const auto real_value = this->context_->get_chai()->boxed_cast(value); + value_ptr->type = native::SCRIPT_INTEGER; + value_ptr->u.intValue = real_value; + } + else if (value.get_type_info() == typeid(bool)) + { + const auto real_value = this->context_->get_chai()->boxed_cast(value); + value_ptr->type = native::SCRIPT_INTEGER; + value_ptr->u.intValue = real_value; + } + else if (value.get_type_info() == typeid(entity)) + { + const auto real_value = this->context_->get_chai()->boxed_cast(value); + value_ptr->type = native::SCRIPT_OBJECT; + value_ptr->u.entityId = real_value.get_entity_id(); + + game::native::AddRefToValue(value_ptr); + } + else if (value.get_type_info() == typeid(std::string)) + { + const auto real_value = this->context_->get_chai()->boxed_cast(value); + value_ptr->type = native::SCRIPT_STRING; + value_ptr->u.stringValue = game::native::SL_GetString(real_value.data(), 0); + } + else if (value.get_type_info() == typeid(std::vector)) + { + float values[3]; + const auto real_value = this->context_->get_chai()->boxed_cast + >(value); + if (real_value.size() != 3) + { + throw std::runtime_error("Invalid vector length. Size must be exactly 3"); + } + + const auto unbox_float = [&real_value, this](const size_t index) -> float + { + const auto value = real_value[index]; + if (value.get_type_info() == typeid(float)) + { + return this->context_->get_chai()->boxed_cast(value); + } + if (value.get_type_info() == typeid(double)) + { + return float(this->context_->get_chai()->boxed_cast(value)); + } + if (value.get_type_info() == typeid(int)) + { + return float(this->context_->get_chai()->boxed_cast(value)); + } + + throw std::runtime_error("Vector element at index " + std::to_string(index) + " is not a number"); + }; + + values[0] = unbox_float(0); + values[1] = unbox_float(1); + values[2] = unbox_float(2); + + value_ptr->type = native::SCRIPT_VECTOR; + value_ptr->u.vectorValue = native::Scr_AllocVector(values); + } + else + { + throw std::runtime_error("Unable to unbox value of type '" + value.get_type_info().bare_name() + "'"); + } + } + + chaiscript::Boxed_Value parameters::get_return_value() const + { + if (native::scr_VmPub->inparamcount == 0) return {}; + + native::Scr_ClearOutParams(); + native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount; + native::scr_VmPub->inparamcount = 0; + + return this->load(native::scr_VmPub->top[1 - native::scr_VmPub->outparamcount]); + } + } +} diff --git a/src/game/scripting/scheduler.cpp b/src/game/scripting/scheduler.cpp index 5c1db76..c4aea8f 100644 --- a/src/game/scripting/scheduler.cpp +++ b/src/game/scripting/scheduler.cpp @@ -1,97 +1,99 @@ -#include "std_include.hpp" -#include "context.hpp" - -namespace game -{ - namespace scripting - { - scheduler::scheduler(context* context) : context_(context) - { - const auto chai = this->context_->get_chai(); - - chai->add(chaiscript::user_type(), "_task_handle"); - chai->add(chaiscript::constructor(), "_task_handle"); - chai->add(chaiscript::constructor(), "_task_handle"); - - chai->add(chaiscript::fun([](task_handle& lhs, const task_handle& rhs) -> task_handle& - { - return lhs = rhs; - }), "="); - - chai->add(chaiscript::fun([this](const std::function& callback, const long long milliseconds) -> task_handle - { - return this->add(callback, milliseconds, true); - }), "setTimeout"); - - chai->add(chaiscript::fun([this](const std::function& callback, const long long milliseconds) -> task_handle - { - return this->add(callback, milliseconds, false); - }), "setInterval"); - - const auto clear = [this](const task_handle& handle) - { - this->remove(handle); - }; - - chai->add(chaiscript::fun(clear), "clear"); - chai->add(chaiscript::fun(clear), "clearTimeout"); - chai->add(chaiscript::fun(clear), "clearInterval"); - } - - void scheduler::run_frame() - { - for (auto task : this->tasks_) - { - const auto now = std::chrono::steady_clock::now(); - if ((now - task->last_execution) > task->delay) - { - task->last_execution = now; - if (task->is_volatile) - { - this->tasks_.remove(task); - } - - task->callback(); - } - } - } - - void scheduler::clear() - { - this->tasks_.clear(); - } - - task_handle scheduler::add(const std::function& callback, const long long milliseconds, - const bool is_volatile) - { - return this->add(callback, std::chrono::milliseconds(milliseconds), is_volatile); - } - - task_handle scheduler::add(const std::function& callback, const std::chrono::milliseconds delay, - const bool is_volatile) - { - task task; - task.is_volatile = is_volatile; - task.callback = callback; - task.delay = delay; - task.last_execution = std::chrono::steady_clock::now(); - task.id = ++this->current_task_id_; - - this->tasks_.add(task); - - return { task.id }; - } - - void scheduler::remove(const task_handle& handle) - { - for (auto task : this->tasks_) - { - if(task->id == handle.id) - { - this->tasks_.remove(task); - break; - } - } - } - } -} +#include "std_include.hpp" +#include "context.hpp" + +namespace game +{ + namespace scripting + { + scheduler::scheduler(context* context) : context_(context) + { + const auto chai = this->context_->get_chai(); + + chai->add(chaiscript::user_type(), "_task_handle"); + chai->add(chaiscript::constructor(), "_task_handle"); + chai->add(chaiscript::constructor(), "_task_handle"); + + chai->add(chaiscript::fun([](task_handle& lhs, const task_handle& rhs) -> task_handle& + { + return lhs = rhs; + }), "="); + + chai->add(chaiscript::fun( + [this](const std::function& callback, const long long milliseconds) -> task_handle + { + return this->add(callback, milliseconds, true); + }), "setTimeout"); + + chai->add(chaiscript::fun( + [this](const std::function& callback, const long long milliseconds) -> task_handle + { + return this->add(callback, milliseconds, false); + }), "setInterval"); + + const auto clear = [this](const task_handle& handle) + { + this->remove(handle); + }; + + chai->add(chaiscript::fun(clear), "clear"); + chai->add(chaiscript::fun(clear), "clearTimeout"); + chai->add(chaiscript::fun(clear), "clearInterval"); + } + + void scheduler::run_frame() + { + for (auto task : this->tasks_) + { + const auto now = std::chrono::steady_clock::now(); + if ((now - task->last_execution) > task->delay) + { + task->last_execution = now; + if (task->is_volatile) + { + this->tasks_.remove(task); + } + + task->callback(); + } + } + } + + void scheduler::clear() + { + this->tasks_.clear(); + } + + task_handle scheduler::add(const std::function& callback, const long long milliseconds, + const bool is_volatile) + { + return this->add(callback, std::chrono::milliseconds(milliseconds), is_volatile); + } + + task_handle scheduler::add(const std::function& callback, const std::chrono::milliseconds delay, + const bool is_volatile) + { + task task; + task.is_volatile = is_volatile; + task.callback = callback; + task.delay = delay; + task.last_execution = std::chrono::steady_clock::now(); + task.id = ++this->current_task_id_; + + this->tasks_.add(task); + + return {task.id}; + } + + void scheduler::remove(const task_handle& handle) + { + for (auto task : this->tasks_) + { + if (task->id == handle.id) + { + this->tasks_.remove(task); + break; + } + } + } + } +} diff --git a/src/launcher/html/html_argument.cpp b/src/launcher/html/html_argument.cpp index d169b54..976a4db 100644 --- a/src/launcher/html/html_argument.cpp +++ b/src/launcher/html/html_argument.cpp @@ -43,6 +43,6 @@ int html_argument::get_number() const bool html_argument::get_bool() const { - if(!this->is_bool()) return false; + if (!this->is_bool()) return false; return this->value_->boolVal != FALSE; } diff --git a/src/loader/loader.cpp b/src/loader/loader.cpp index 9d250f4..4d6682a 100644 --- a/src/loader/loader.cpp +++ b/src/loader/loader.cpp @@ -12,7 +12,7 @@ FARPROC loader::load(const utils::nt::module& module) const const auto buffer = binary_loader::load(this->mode_); if (buffer.empty()) return nullptr; - utils::nt::module source(HMODULE(buffer.data())); + const utils::nt::module source(HMODULE(buffer.data())); if (!source) return nullptr; this->load_sections(module, source); @@ -58,8 +58,8 @@ FARPROC loader::load(const utils::nt::module& module) const .get_optional_header()->DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT]; std::memmove(module.get_nt_headers(), source.get_nt_headers(), - sizeof(IMAGE_NT_HEADERS) + (source.get_nt_headers()->FileHeader.NumberOfSections * (sizeof( - IMAGE_SECTION_HEADER)))); + sizeof(IMAGE_NT_HEADERS) + source.get_nt_headers()->FileHeader.NumberOfSections * sizeof( + IMAGE_SECTION_HEADER)); return FARPROC(module.get_ptr() + source.get_relative_entry_point()); } diff --git a/src/loader/module.hpp b/src/loader/module.hpp index 49c344e..a4942a7 100644 --- a/src/loader/module.hpp +++ b/src/loader/module.hpp @@ -1,26 +1,26 @@ -#pragma once - -class module -{ -public: - virtual ~module() - { - } - - virtual void post_start() - { - } - - virtual void post_load() - { - } - - virtual void pre_destroy() - { - } - - virtual void* load_import(const std::string& module, const std::string& function) - { - return nullptr; - } -}; +#pragma once + +class module +{ +public: + virtual ~module() + { + } + + virtual void post_start() + { + } + + virtual void post_load() + { + } + + virtual void pre_destroy() + { + } + + virtual void* load_import(const std::string& module, const std::string& function) + { + return nullptr; + } +}; diff --git a/src/loader/module_loader.cpp b/src/loader/module_loader.cpp index 615d11b..b30c9eb 100644 --- a/src/loader/module_loader.cpp +++ b/src/loader/module_loader.cpp @@ -27,7 +27,7 @@ bool module_loader::post_start() module_->post_start(); } } - catch(premature_shutdown_trigger&) + catch (premature_shutdown_trigger&) { return false; } @@ -75,7 +75,7 @@ void* module_loader::load_import(const std::string& module, const std::string& f for (const auto& module_ : *modules_) { const auto module_function_ptr = module_->load_import(module, function); - if(module_function_ptr) + if (module_function_ptr) { function_ptr = module_function_ptr; } diff --git a/src/loader/module_loader.hpp b/src/loader/module_loader.hpp index 76ec816..f59cadd 100644 --- a/src/loader/module_loader.hpp +++ b/src/loader/module_loader.hpp @@ -1,61 +1,61 @@ -#pragma once -#include "module.hpp" - -class module_loader final -{ -public: - class premature_shutdown_trigger final : public std::exception - { - const char* what() const noexcept override +#pragma once +#include "module.hpp" + +class module_loader final +{ +public: + class premature_shutdown_trigger final : public std::exception + { + const char* what() const noexcept override { return "Premature shutdown requested"; - } - }; - - template - class installer final - { - static_assert(std::is_base_of::value, "Module has invalid base class"); - - public: - installer() - { - register_module(std::make_unique()); - } - }; - - template - static T* get() - { - for(const auto& module_ : *modules_) - { - if(typeid(*module_.get()) == typeid(T)) - { - return reinterpret_cast(module_.get()); - } - } - - return nullptr; - } - - static void register_module(std::unique_ptr&& module); - - static bool post_start(); - static bool post_load(); - static void pre_destroy(); - - static void* load_import(const std::string& module, const std::string& function); - - static void trigger_premature_shutdown(); - -private: - static std::vector>* modules_; - - static void destroy_modules(); -}; - -#define REGISTER_MODULE(name) \ -namespace \ -{ \ - static module_loader::installer $_##name; \ -} + } + }; + + template + class installer final + { + static_assert(std::is_base_of::value, "Module has invalid base class"); + + public: + installer() + { + register_module(std::make_unique()); + } + }; + + template + static T* get() + { + for (const auto& module_ : *modules_) + { + if (typeid(*module_.get()) == typeid(T)) + { + return reinterpret_cast(module_.get()); + } + } + + return nullptr; + } + + static void register_module(std::unique_ptr&& module); + + static bool post_start(); + static bool post_load(); + static void pre_destroy(); + + static void* load_import(const std::string& module, const std::string& function); + + static void trigger_premature_shutdown(); + +private: + static std::vector>* modules_; + + static void destroy_modules(); +}; + +#define REGISTER_MODULE(name) \ +namespace \ +{ \ + static module_loader::installer $_##name; \ +} diff --git a/src/main.cpp b/src/main.cpp index acff003..8eacebb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -105,7 +105,7 @@ int main() auto mode = detect_mode_from_arguments(); if (mode == launcher::mode::none) { - launcher launcher; + const launcher launcher; mode = launcher.run(); if (mode == launcher::mode::none) return 0; } diff --git a/src/module/scheduler.cpp b/src/module/scheduler.cpp index 9a47c52..1c8db69 100644 --- a/src/module/scheduler.cpp +++ b/src/module/scheduler.cpp @@ -1,102 +1,102 @@ -#include -#include "scheduler.hpp" -#include "utils/string.hpp" -#include "game/structs.hpp" -#include "game/game.hpp" -#include "utils/hook.hpp" - -std::mutex scheduler::mutex_; -std::queue> scheduler::errors_; -utils::concurrent_list> scheduler::callbacks_; -utils::concurrent_list> scheduler::single_callbacks_; - -void scheduler::on_frame(const std::function& callback) -{ - std::lock_guard _(mutex_); - callbacks_.add(callback); -} - -void scheduler::once(const std::function& callback) -{ - std::lock_guard _(mutex_); - single_callbacks_.add(callback); -} - -void scheduler::error(const std::string& message, int level) -{ - std::lock_guard _(mutex_); - errors_.emplace(message, level); -} - -void scheduler::frame_stub() -{ - execute(); - reinterpret_cast(SELECT_VALUE(0x458600, 0x556470, 0x4DB070))(); -} - -__declspec(naked) void scheduler::execute() -{ - __asm - { - call execute_error - call execute_safe - retn - } -} - -void scheduler::execute_safe() -{ - for (auto callback : callbacks_) - { - (*callback)(); - } - - for (auto callback : single_callbacks_) - { - single_callbacks_.remove(callback); - (*callback)(); - } -} - -void scheduler::execute_error() -{ - const char* message; - int level; - - if(get_next_error(&message, &level) && message) - { - game::native::Com_Error(level, "%s", message); - } -} - -bool scheduler::get_next_error(const char** error_message, int* error_level) -{ - std::lock_guard _(mutex_); - if(errors_.empty()) - { - *error_message = nullptr; - return false; - } - - const auto error = errors_.front(); - errors_.pop(); - - *error_level = error.second; - *error_message = utils::string::va("%s", error.first.data()); - - return true; -} - -void scheduler::post_load() -{ - utils::hook(SELECT_VALUE(0x44C7DB, 0x55688E, 0x4DB324), frame_stub, HOOK_CALL).install()->quick(); -} - -void scheduler::pre_destroy() -{ - std::lock_guard _(mutex_); - callbacks_.clear(); - single_callbacks_.clear(); -} - -REGISTER_MODULE(scheduler); +#include +#include "scheduler.hpp" +#include "utils/string.hpp" +#include "game/structs.hpp" +#include "game/game.hpp" +#include "utils/hook.hpp" + +std::mutex scheduler::mutex_; +std::queue> scheduler::errors_; +utils::concurrent_list> scheduler::callbacks_; +utils::concurrent_list> scheduler::single_callbacks_; + +void scheduler::on_frame(const std::function& callback) +{ + std::lock_guard _(mutex_); + callbacks_.add(callback); +} + +void scheduler::once(const std::function& callback) +{ + std::lock_guard _(mutex_); + single_callbacks_.add(callback); +} + +void scheduler::error(const std::string& message, int level) +{ + std::lock_guard _(mutex_); + errors_.emplace(message, level); +} + +void scheduler::frame_stub() +{ + execute(); + reinterpret_cast(SELECT_VALUE(0x458600, 0x556470, 0x4DB070))(); +} + +__declspec(naked) void scheduler::execute() +{ + __asm + { + call execute_error + call execute_safe + retn + } +} + +void scheduler::execute_safe() +{ + for (auto callback : callbacks_) + { + (*callback)(); + } + + for (auto callback : single_callbacks_) + { + single_callbacks_.remove(callback); + (*callback)(); + } +} + +void scheduler::execute_error() +{ + const char* message; + int level; + + if (get_next_error(&message, &level) && message) + { + game::native::Com_Error(level, "%s", message); + } +} + +bool scheduler::get_next_error(const char** error_message, int* error_level) +{ + std::lock_guard _(mutex_); + if (errors_.empty()) + { + *error_message = nullptr; + return false; + } + + const auto error = errors_.front(); + errors_.pop(); + + *error_level = error.second; + *error_message = utils::string::va("%s", error.first.data()); + + return true; +} + +void scheduler::post_load() +{ + utils::hook(SELECT_VALUE(0x44C7DB, 0x55688E, 0x4DB324), frame_stub, HOOK_CALL).install()->quick(); +} + +void scheduler::pre_destroy() +{ + std::lock_guard _(mutex_); + callbacks_.clear(); + single_callbacks_.clear(); +} + +REGISTER_MODULE(scheduler); diff --git a/src/module/scripting.cpp b/src/module/scripting.cpp index cb4ffed..49333fa 100644 --- a/src/module/scripting.cpp +++ b/src/module/scripting.cpp @@ -19,7 +19,8 @@ public: ->quick(); utils::hook(SELECT_VALUE(0x4F9706, 0x5772A0, 0x4FAB88), &frame_stub, HOOK_CALL).install()->quick(); - utils::hook(SELECT_VALUE(0x4FFA48, 0x5774AB, 0x4FEFD7), &frame_stub, HOOK_CALL).install()->quick(); // Only relevant one? + utils::hook(SELECT_VALUE(0x4FFA48, 0x5774AB, 0x4FEFD7), &frame_stub, HOOK_CALL).install()->quick(); + // Only relevant one? utils::hook(SELECT_VALUE(0x6109F3, 0x56B637, 0x4EDFF7), &vm_notify_stub, HOOK_CALL).install()->quick(); utils::hook(SELECT_VALUE(0x6128BE, 0x56D541, 0x4EFAF9), &vm_notify_stub, HOOK_CALL).install()->quick(); @@ -149,7 +150,7 @@ private: game::native::VM_Notify(notify_id, type, stack); } - static int frame_stub(int a1, int a2) + static int frame_stub(const int a1, const int a2) { module_loader::get()->run_frame(); return game::native::G_RunFrame(a1, a2); diff --git a/src/module/security.cpp b/src/module/security.cpp index 9b304d2..88b57b4 100644 --- a/src/module/security.cpp +++ b/src/module/security.cpp @@ -8,7 +8,7 @@ class security final : public module public: void post_load() override { - if(game::is_mp()) + if (game::is_mp()) { utils::hook(0x4AECD4, read_p2p_auth_ticket_stub, HOOK_JUMP).install()->quick(); } diff --git a/src/module/steam_proxy.cpp b/src/module/steam_proxy.cpp index 014e60a..a83c6ba 100644 --- a/src/module/steam_proxy.cpp +++ b/src/module/steam_proxy.cpp @@ -133,7 +133,7 @@ private: this->client_utils_.invoke("SetAppIDForCurrentPipe", app_id, false); - utils::nt::module self; + const utils::nt::module self; const auto path = self.get_path(); char our_directory[MAX_PATH] = {0}; diff --git a/src/std_include.cpp b/src/std_include.cpp index a72351b..1e3c599 100644 --- a/src/std_include.cpp +++ b/src/std_include.cpp @@ -1,16 +1,38 @@ -#include - -#pragma comment(linker, "/merge:.data=.cld") -#pragma comment(linker, "/merge:.rdata=.clr") -#pragma comment(linker, "/merge:.cl=.main") -#pragma comment(linker, "/merge:.text=.main") -#pragma comment(linker, "/section:.main,re") -#pragma comment(linker, "/base:0x400000") - -#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") - -#pragma bss_seg(".payload") -char payload_data[BINARY_PAYLOAD_SIZE]; - -#pragma data_seg(".main") -char main_data[200] = {1}; +#include + +#pragma comment(linker, "/merge:.data=.cld") +#pragma comment(linker, "/merge:.rdata=.clr") +#pragma comment(linker, "/merge:.cl=.main") +#pragma comment(linker, "/merge:.text=.main") +#pragma comment(linker, "/section:.main,re") +#pragma comment(linker, "/base:0x400000") + +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") + +#pragma bss_seg(".payload") +char payload_data[BINARY_PAYLOAD_SIZE]; + +#pragma data_seg(".main") +char main_data[200] = {1}; + +extern "C" { +int s_read_arc4random(void*, size_t) +{ + return -1; +} + +int s_read_getrandom(void*, size_t) +{ + return -1; +} + +int s_read_urandom(void*, size_t) +{ + return -1; +} + +int s_read_ltm_rng(void*, size_t) +{ + return -1; +} +} diff --git a/src/steam/interface.cpp b/src/steam/interface.cpp index 5bda637..244cccd 100644 --- a/src/steam/interface.cpp +++ b/src/steam/interface.cpp @@ -2,7 +2,6 @@ #include "interface.hpp" #include "utils/memory.hpp" #include "utils/nt.hpp" -#include namespace steam { diff --git a/src/steam/interface.hpp b/src/steam/interface.hpp index 0752648..1e1ab94 100644 --- a/src/steam/interface.hpp +++ b/src/steam/interface.hpp @@ -1,91 +1,91 @@ -#pragma once - -#ifdef interface -#undef interface -#endif - -namespace steam -{ - template - struct argument_size_calculator final : std::integral_constant - { - }; - - template - struct argument_size_calculator final : std::integral_constant< - size_t, X + ((argument_size_calculator::value + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1))> - { - }; - - class interface final - { - public: - class method final - { - public: - void* pointer = nullptr; - size_t param_size = 0; - }; - - class method_result final - { - public: - std::string name; - size_t param_size = 0; - bool name_found = false; - bool param_size_found = false; - }; - - interface(); - interface(void* interface_ptr); - - operator bool() const; - - template - T invoke(const std::string& method_name, Args ... args) - { - if (!this->interface_ptr_) - { - throw std::runtime_error("Invalid interface pointer"); - } - - const auto method_result = this->find_method(method_name); - if (!method_result.pointer) - { - throw std::runtime_error("Unable to find desired method"); - } - - constexpr size_t passed_argc = argument_size_calculator::value; - if (passed_argc != method_result.param_size) - { - throw std::runtime_error("Invalid argument count"); - } - - return reinterpret_cast(method_result.pointer)( - this->interface_ptr_, args...); - } - - template - T invoke(const size_t table_entry, Args ... args) - { - if (!this->interface_ptr_) - { - throw std::runtime_error("Invalid interface pointer"); - } - - return reinterpret_cast((*this->interface_ptr_)[table_entry])( - this->interface_ptr_, args...); - } - - private: - void*** interface_ptr_; - std::unordered_map methods_; - - method find_method(const std::string& name); - method search_method(const std::string& name); - - method_result analyze_method(const void* method_ptr); - - bool is_rdata(void* pointer); - }; -} +#pragma once + +#ifdef interface +#undef interface +#endif + +namespace steam +{ + template + struct argument_size_calculator final : std::integral_constant + { + }; + + template + struct argument_size_calculator final : std::integral_constant< + size_t, X + ((argument_size_calculator::value + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1))> + { + }; + + class interface final + { + public: + class method final + { + public: + void* pointer = nullptr; + size_t param_size = 0; + }; + + class method_result final + { + public: + std::string name; + size_t param_size = 0; + bool name_found = false; + bool param_size_found = false; + }; + + interface(); + interface(void* interface_ptr); + + operator bool() const; + + template + T invoke(const std::string& method_name, Args ... args) + { + if (!this->interface_ptr_) + { + throw std::runtime_error("Invalid interface pointer"); + } + + const auto method_result = this->find_method(method_name); + if (!method_result.pointer) + { + throw std::runtime_error("Unable to find desired method"); + } + + constexpr size_t passed_argc = argument_size_calculator::value; + if (passed_argc != method_result.param_size) + { + throw std::runtime_error("Invalid argument count"); + } + + return reinterpret_cast(method_result.pointer)( + this->interface_ptr_, args...); + } + + template + T invoke(const size_t table_entry, Args ... args) + { + if (!this->interface_ptr_) + { + throw std::runtime_error("Invalid interface pointer"); + } + + return reinterpret_cast((*this->interface_ptr_)[table_entry])( + this->interface_ptr_, args...); + } + + private: + void*** interface_ptr_; + std::unordered_map methods_; + + method find_method(const std::string& name); + method search_method(const std::string& name); + + method_result analyze_method(const void* method_ptr); + + bool is_rdata(void* pointer); + }; +} diff --git a/src/steam/steam.cpp b/src/steam/steam.cpp index 558ffb6..25fa293 100644 --- a/src/steam/steam.cpp +++ b/src/steam/steam.cpp @@ -1,234 +1,232 @@ -#include -#include "steam/steam.hpp" -#include "module/scheduler.hpp" - -namespace steam -{ - ::utils::nt::module overlay(nullptr); - - uint64_t callbacks::call_id_ = 0; - std::recursive_mutex callbacks::mutex_; - std::map callbacks::calls_; - std::map callbacks::result_handlers_; - std::vector callbacks::results_; - std::vector callbacks::callback_list_; - - uint64_t callbacks::register_call() - { - std::lock_guard _(mutex_); - calls_[++call_id_] = false; - return call_id_; - } - - void callbacks::register_callback(base* handler, const int callback) - { - std::lock_guard _(mutex_); - handler->set_i_callback(callback); - callback_list_.push_back(handler); - } - - void callbacks::register_call_result(const uint64_t call, base* result) - { - std::lock_guard _(mutex_); - result_handlers_[call] = result; - } - - void callbacks::return_call(void* data, const int size, const int type, const uint64_t call) - { - std::lock_guard _(mutex_); - - result result{}; - - result.call = call; - result.data = data; - result.size = size; - result.type = type; - - calls_[call] = true; - - results_.push_back(result); - } - - void callbacks::run_callbacks() - { - std::lock_guard _(mutex_); - - for (const auto& result : results_) - { - if (result_handlers_.find(result.call) != result_handlers_.end()) - { - result_handlers_[result.call]->run(result.data, false, result.call); - } - - for (const auto& callback : callback_list_) - { - if (callback && callback->get_i_callback() == result.type) - { - callback->run(result.data, false, 0); - } - } - - if (result.data) - { - free(result.data); - } - } - - results_.clear(); - } - - std::string get_steam_install_directory() - { - HKEY reg_key; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Valve\\Steam", 0, KEY_QUERY_VALUE, ®_key) == - ERROR_SUCCESS) - { - char path[MAX_PATH] = {0}; - DWORD length = sizeof(path); - RegQueryValueExA(reg_key, "InstallPath", nullptr, nullptr, reinterpret_cast(path), - &length); - RegCloseKey(reg_key); - - std::string steam_path = path; - if (steam_path.back() != '\\' && steam_path.back() != '/') - { - steam_path.push_back('\\'); - } - - return steam_path; - } - - return {}; - } - - extern "C" { - bool SteamAPI_RestartAppIfNecessary() - { - return false; - } - - bool SteamAPI_Init() - { - overlay = ::utils::nt::module("gameoverlayrenderer.dll"); - - if (!overlay) - { - const auto steam_path = get_steam_install_directory(); - if (!steam_path.empty()) - { - overlay = ::utils::nt::module::load(steam_path + "gameoverlayrenderer.dll"); - } - } - - return true; - } - - void SteamAPI_RegisterCallResult(callbacks::base* result, uint64_t call) - { - callbacks::register_call_result(call, result); - } - - void SteamAPI_RegisterCallback(callbacks::base* handler, int callback) - { - callbacks::register_callback(handler, callback); - } - - void SteamAPI_RunCallbacks() - { - callbacks::run_callbacks(); - } - - void SteamAPI_Shutdown() - { - } - - void SteamAPI_UnregisterCallResult() - { - } - - void SteamAPI_UnregisterCallback() - { - } - - - bool SteamGameServer_Init() - { - return true; - } - - void SteamGameServer_RunCallbacks() - { - } - - void SteamGameServer_Shutdown() - { - } - - - friends* SteamFriends() - { - static friends friends; - return &friends; - } - - matchmaking* SteamMatchmaking() - { - static matchmaking matchmaking; - return &matchmaking; - } - - matchmaking_servers* SteamMatchmakingServers() - { - static matchmaking_servers matchmaking_servers; - return &matchmaking_servers; - } - - game_server* SteamGameServer() - { - static game_server game_server; - return &game_server; - } - - master_server_updater* SteamMasterServerUpdater() - { - static master_server_updater master_server_updater; - return &master_server_updater; - } - - networking* SteamNetworking() - { - static networking networking; - return &networking; - } - - remote_storage* SteamRemoteStorage() - { - static remote_storage remote_storage; - return &remote_storage; - } - - user* SteamUser() - { - static user user; - return &user; - } - - utils* SteamUtils() - { - static utils utils; - return &utils; - } - - apps* SteamApps() - { - static apps apps; - return &apps; - } - - user_stats* SteamUserStats() - { - static user_stats user_stats; - return &user_stats; - } - } -} +#include +#include "steam/steam.hpp" + +namespace steam +{ + ::utils::nt::module overlay(nullptr); + + uint64_t callbacks::call_id_ = 0; + std::recursive_mutex callbacks::mutex_; + std::map callbacks::calls_; + std::map callbacks::result_handlers_; + std::vector callbacks::results_; + std::vector callbacks::callback_list_; + + uint64_t callbacks::register_call() + { + std::lock_guard _(mutex_); + calls_[++call_id_] = false; + return call_id_; + } + + void callbacks::register_callback(base* handler, const int callback) + { + std::lock_guard _(mutex_); + handler->set_i_callback(callback); + callback_list_.push_back(handler); + } + + void callbacks::register_call_result(const uint64_t call, base* result) + { + std::lock_guard _(mutex_); + result_handlers_[call] = result; + } + + void callbacks::return_call(void* data, const int size, const int type, const uint64_t call) + { + std::lock_guard _(mutex_); + + result result; + result.call = call; + result.data = data; + result.size = size; + result.type = type; + + calls_[call] = true; + + results_.push_back(result); + } + + void callbacks::run_callbacks() + { + std::lock_guard _(mutex_); + + for (const auto& result : results_) + { + if (result_handlers_.find(result.call) != result_handlers_.end()) + { + result_handlers_[result.call]->run(result.data, false, result.call); + } + + for (const auto& callback : callback_list_) + { + if (callback && callback->get_i_callback() == result.type) + { + callback->run(result.data, false, 0); + } + } + + if (result.data) + { + free(result.data); + } + } + + results_.clear(); + } + + std::string get_steam_install_directory() + { + HKEY reg_key; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Valve\\Steam", 0, KEY_QUERY_VALUE, ®_key) == + ERROR_SUCCESS) + { + char path[MAX_PATH] = {0}; + DWORD length = sizeof(path); + RegQueryValueExA(reg_key, "InstallPath", nullptr, nullptr, reinterpret_cast(path), + &length); + RegCloseKey(reg_key); + + std::string steam_path = path; + if (steam_path.back() != '\\' && steam_path.back() != '/') + { + steam_path.push_back('\\'); + } + + return steam_path; + } + + return {}; + } + + extern "C" { + bool SteamAPI_RestartAppIfNecessary() + { + return false; + } + + bool SteamAPI_Init() + { + overlay = ::utils::nt::module("gameoverlayrenderer.dll"); + + if (!overlay) + { + const auto steam_path = get_steam_install_directory(); + if (!steam_path.empty()) + { + overlay = ::utils::nt::module::load(steam_path + "gameoverlayrenderer.dll"); + } + } + + return true; + } + + void SteamAPI_RegisterCallResult(callbacks::base* result, uint64_t call) + { + callbacks::register_call_result(call, result); + } + + void SteamAPI_RegisterCallback(callbacks::base* handler, int callback) + { + callbacks::register_callback(handler, callback); + } + + void SteamAPI_RunCallbacks() + { + callbacks::run_callbacks(); + } + + void SteamAPI_Shutdown() + { + } + + void SteamAPI_UnregisterCallResult() + { + } + + void SteamAPI_UnregisterCallback() + { + } + + + bool SteamGameServer_Init() + { + return true; + } + + void SteamGameServer_RunCallbacks() + { + } + + void SteamGameServer_Shutdown() + { + } + + + friends* SteamFriends() + { + static friends friends; + return &friends; + } + + matchmaking* SteamMatchmaking() + { + static matchmaking matchmaking; + return &matchmaking; + } + + matchmaking_servers* SteamMatchmakingServers() + { + static matchmaking_servers matchmaking_servers; + return &matchmaking_servers; + } + + game_server* SteamGameServer() + { + static game_server game_server; + return &game_server; + } + + master_server_updater* SteamMasterServerUpdater() + { + static master_server_updater master_server_updater; + return &master_server_updater; + } + + networking* SteamNetworking() + { + static networking networking; + return &networking; + } + + remote_storage* SteamRemoteStorage() + { + static remote_storage remote_storage; + return &remote_storage; + } + + user* SteamUser() + { + static user user; + return &user; + } + + utils* SteamUtils() + { + static utils utils; + return &utils; + } + + apps* SteamApps() + { + static apps apps; + return &apps; + } + + user_stats* SteamUserStats() + { + static user_stats user_stats; + return &user_stats; + } + } +} diff --git a/src/utils/concurrent_list.hpp b/src/utils/concurrent_list.hpp index 63f1e8e..135f20f 100644 --- a/src/utils/concurrent_list.hpp +++ b/src/utils/concurrent_list.hpp @@ -1,130 +1,131 @@ -#pragma once - -namespace utils -{ - template - class concurrent_list final - { - public: - class element final - { - public: - explicit element(std::recursive_mutex* mutex, std::shared_ptr entry = {}, std::shared_ptr next = {}) : - mutex_(mutex), - entry_(std::move(entry)), - next_(std::move(next)) - { - } - - void remove(const std::shared_ptr& element) - { - std::lock_guard _(*this->mutex_); - if (!this->next_) return; - - if (this->next_->entry_.get() == element.get()) - { - this->next_ = this->next_->next_; - } - else - { - this->next_->remove(element); - } - } - - std::shared_ptr get_next() const - { - std::lock_guard _(*this->mutex_); - return this->next_; - } - - std::shared_ptr operator*() const - { - std::lock_guard _(*this->mutex_); - return this->entry_; - } - - element& operator++() - { - std::lock_guard _(*this->mutex_); - *this = this->next_ ? *this->next_ : element(this->mutex_); - return *this; - } - - element operator++(int) - { - std::lock_guard _(*this->mutex_); - auto result = *this; - this->operator++(); - return result; - } - - bool operator==(const element& other) - { - std::lock_guard _(*this->mutex_); - return this->entry_.get() == other.entry_.get(); - } - - bool operator!=(const element& other) - { - std::lock_guard _(*this->mutex_); - return !(*this == other); - } - - private: - std::recursive_mutex* mutex_; - std::shared_ptr entry_; - std::shared_ptr next_; - }; - - element begin() - { - std::lock_guard _(this->mutex_); - return this->entry_ ? *this->entry_ : this->end(); - } - - element end() - { - std::lock_guard _(this->mutex_); - return element(&this->mutex_); - } - - void remove(const element& entry) - { - std::lock_guard _(this->mutex_); - this->remove(*entry); - } - - void remove(const std::shared_ptr& element) - { - std::lock_guard _(this->mutex_); - if (!this->entry_) return; - - if ((**this->entry_).get() == element.get()) - { - this->entry_ = this->entry_->get_next(); - } - else - { - this->entry_->remove(element); - } - } - - void add(const T& object) - { - std::lock_guard _(this->mutex_); - - const auto object_ptr = std::make_shared(object); - this->entry_ = std::make_shared(&this->mutex_, object_ptr, this->entry_); - } - - void clear() - { - std::lock_guard _(this->mutex_); - this->entry_ = {}; - } - - private: - std::recursive_mutex mutex_; - std::shared_ptr entry_; - }; -} +#pragma once + +namespace utils +{ + template + class concurrent_list final + { + public: + class element final + { + public: + explicit element(std::recursive_mutex* mutex, std::shared_ptr entry = {}, + std::shared_ptr next = {}) : + mutex_(mutex), + entry_(std::move(entry)), + next_(std::move(next)) + { + } + + void remove(const std::shared_ptr& element) + { + std::lock_guard _(*this->mutex_); + if (!this->next_) return; + + if (this->next_->entry_.get() == element.get()) + { + this->next_ = this->next_->next_; + } + else + { + this->next_->remove(element); + } + } + + std::shared_ptr get_next() const + { + std::lock_guard _(*this->mutex_); + return this->next_; + } + + std::shared_ptr operator*() const + { + std::lock_guard _(*this->mutex_); + return this->entry_; + } + + element& operator++() + { + std::lock_guard _(*this->mutex_); + *this = this->next_ ? *this->next_ : element(this->mutex_); + return *this; + } + + element operator++(int) + { + std::lock_guard _(*this->mutex_); + auto result = *this; + this->operator++(); + return result; + } + + bool operator==(const element& other) + { + std::lock_guard _(*this->mutex_); + return this->entry_.get() == other.entry_.get(); + } + + bool operator!=(const element& other) + { + std::lock_guard _(*this->mutex_); + return !(*this == other); + } + + private: + std::recursive_mutex* mutex_; + std::shared_ptr entry_; + std::shared_ptr next_; + }; + + element begin() + { + std::lock_guard _(this->mutex_); + return this->entry_ ? *this->entry_ : this->end(); + } + + element end() + { + std::lock_guard _(this->mutex_); + return element(&this->mutex_); + } + + void remove(const element& entry) + { + std::lock_guard _(this->mutex_); + this->remove(*entry); + } + + void remove(const std::shared_ptr& element) + { + std::lock_guard _(this->mutex_); + if (!this->entry_) return; + + if ((**this->entry_).get() == element.get()) + { + this->entry_ = this->entry_->get_next(); + } + else + { + this->entry_->remove(element); + } + } + + void add(const T& object) + { + std::lock_guard _(this->mutex_); + + const auto object_ptr = std::make_shared(object); + this->entry_ = std::make_shared(&this->mutex_, object_ptr, this->entry_); + } + + void clear() + { + std::lock_guard _(this->mutex_); + this->entry_ = {}; + } + + private: + std::recursive_mutex mutex_; + std::shared_ptr entry_; + }; +} diff --git a/src/utils/cryptography.cpp b/src/utils/cryptography.cpp index 583e410..180f8a3 100644 --- a/src/utils/cryptography.cpp +++ b/src/utils/cryptography.cpp @@ -1,325 +1,326 @@ -#include -#include "string.hpp" -#include "cryptography.hpp" - -/// http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/Source/libtomcrypt/doc/libTomCryptDoc.pdf - -namespace utils -{ - namespace cryptography - { - ecc::key::key() - { - ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); - } - - ecc::key::~key() - { - this->free(); - } - - bool ecc::key::is_valid() const - { - return (!memory::is_set(&this->key_storage_, 0, sizeof(this->key_storage_))); - } - - ecc_key* ecc::key::get() - { - return &this->key_storage_; - } - - std::string ecc::key::get_public_key() const - { - uint8_t buffer[512] = {0}; - DWORD length = sizeof(buffer); - - if (ecc_ansi_x963_export(&this->key_storage_, buffer, &length) == CRYPT_OK) - { - return std::string(reinterpret_cast(buffer), length); - } - - return {}; - } - - void ecc::key::set(const std::string& pub_key_buffer) - { - this->free(); - - if (ecc_ansi_x963_import(reinterpret_cast(pub_key_buffer.data()), pub_key_buffer.size(), - &this->key_storage_) != CRYPT_OK) - { - ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); - } - } - - void ecc::key::deserialize(const std::string& key) - { - this->free(); - - if (ecc_import(reinterpret_cast(key.data()), key.size(), &this->key_storage_) != CRYPT_OK) - { - ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); - } - } - - std::string ecc::key::serialize(const int type) const - { - uint8_t buffer[4096] = {0}; - DWORD length = sizeof(buffer); - - if (ecc_export(buffer, &length, type, &this->key_storage_) == CRYPT_OK) - { - return std::string(reinterpret_cast(buffer), length); - } - - return ""; - } - - void ecc::key::free() - { - if (this->is_valid()) - { - ecc_free(&this->key_storage_); - } - - ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); - } - - bool ecc::key::operator==(key& key) const - { - return (this->is_valid() && key.is_valid() && this->serialize(PK_PUBLIC) == key.serialize(PK_PUBLIC)); - } - - ecc::key ecc::generate_key(const int bits) - { - key key; - - ltc_mp = ltm_desc; - register_prng(&sprng_desc); - ecc_make_key(nullptr, find_prng("sprng"), bits / 8, key.get()); - - return key; - } - - std::string ecc::sign_message(key key, const std::string& message) - { - if (!key.is_valid()) return ""; - - uint8_t buffer[512]; - DWORD length = sizeof(buffer); - - ltc_mp = ltm_desc; - register_prng(&sprng_desc); - ecc_sign_hash(reinterpret_cast(message.data()), message.size(), buffer, &length, nullptr, - find_prng("sprng"), key.get()); - - return std::string(reinterpret_cast(buffer), length); - } - - bool ecc::verify_message(key key, const std::string& message, const std::string& signature) - { - if (!key.is_valid()) return false; - - ltc_mp = ltm_desc; - - auto result = 0; - return ( ecc_verify_hash(reinterpret_cast(signature.data()), signature.size(), - reinterpret_cast(message.data()), message.size(), &result, key.get()) == CRYPT_OK && result != 0); - } - - std::string rsa::encrypt(const std::string& data, const std::string& hash, const std::string& key) - { - initialize(); - - const auto prng_id = find_prng("yarrow"); - - rsa_key new_key; - rsa_import(PBYTE(key.data()), key.size(), &new_key); - - prng_state yarrow; - rng_make_prng(128, prng_id, &yarrow, nullptr); - - unsigned char buffer[0x80]; - unsigned long length = sizeof(buffer); - - const auto rsa_result = rsa_encrypt_key( // - PBYTE(data.data()), // - data.size(), // - buffer, // - &length, // - PBYTE(hash.data()), // - hash.size(), // - &yarrow, // - prng_id, // - find_hash("sha1"), // - &new_key); - - rsa_free(&new_key); - - if (rsa_result == CRYPT_OK) - { - return std::string(PCHAR(buffer), length); - } - - return {}; - } - - void rsa::initialize() - { - static auto initialized = false; - if (initialized) return; - initialized = true; - - ltc_mp = ltm_desc; - register_hash(&sha1_desc); - register_prng(&yarrow_desc); - } - - std::string des3::encrypt(const std::string& data, const std::string& iv, const std::string& key) - { - initialize(); - - std::string enc_data; - enc_data.resize(data.size()); - - symmetric_CBC cbc; - const auto des3 = find_cipher("3des"); - - cbc_start(des3, reinterpret_cast(iv.data()), reinterpret_cast(key.data()), - key.size(), 0, &cbc); - cbc_encrypt(reinterpret_cast(data.data()), - reinterpret_cast(const_cast(enc_data.data())), data.size(), &cbc); - cbc_done(&cbc); - - return enc_data; - } - - std::string des3::decrypt(const std::string& data, const std::string& iv, const std::string& key) - { - initialize(); - - std::string dec_data; - dec_data.resize(data.size()); - - symmetric_CBC cbc; - const auto des3 = find_cipher("3des"); - - cbc_start(des3, reinterpret_cast(iv.data()), reinterpret_cast(key.data()), - key.size(), 0, &cbc); - cbc_decrypt(reinterpret_cast(data.data()), - reinterpret_cast(const_cast(dec_data.data())), data.size(), &cbc); - cbc_done(&cbc); - - return dec_data; - } - - void des3::initialize() - { - static auto initialized = false; - if (initialized) return; - initialized = true; - - register_cipher(&des3_desc); - } - - std::string tiger::compute(const std::string& data, const bool hex) - { - return compute(reinterpret_cast(data.data()), data.size(), hex); - } - - std::string tiger::compute(const uint8_t* data, const size_t length, const bool hex) - { - uint8_t buffer[24] = {0}; - - hash_state state; - tiger_init(&state); - tiger_process(&state, data, length); - tiger_done(&state, buffer); - - std::string hash(reinterpret_cast(buffer), sizeof(buffer)); - if (!hex) return hash; - - return string::dump_hex(hash, ""); - } - - std::string sha1::compute(const std::string& data, const bool hex) - { - return compute(reinterpret_cast(data.data()), data.size(), hex); - } - - std::string sha1::compute(const uint8_t* data, size_t length, const bool hex) - { - uint8_t buffer[20] = {0}; - - hash_state state; - sha1_init(&state); - sha1_process(&state, data, length); - sha1_done(&state, buffer); - - std::string hash(reinterpret_cast(buffer), sizeof(buffer)); - if (!hex) return hash; - - return string::dump_hex(hash, ""); - } - - std::string sha256::compute(const std::string& data, bool hex) - { - return compute(reinterpret_cast(data.data()), data.size(), hex); - } - - std::string sha256::compute(const uint8_t* data, size_t length, bool hex) - { - uint8_t buffer[32] = {0}; - - hash_state state; - sha256_init(&state); - sha256_process(&state, data, length); - sha256_done(&state, buffer); - - std::string hash(reinterpret_cast(buffer), sizeof(buffer)); - if (!hex) return hash; - - return string::dump_hex(hash, ""); - } - - std::string sha512::compute(const std::string& data, bool hex) - { - return compute(reinterpret_cast(data.data()), data.size(), hex); - } - - std::string sha512::compute(const uint8_t* data, size_t length, bool hex) - { - uint8_t buffer[64] = {0}; - - hash_state state; - sha512_init(&state); - sha512_process(&state, data, length); - sha512_done(&state, buffer); - - std::string hash(reinterpret_cast(buffer), sizeof(buffer)); - if (!hex) return hash; - - return string::dump_hex(hash, ""); - } - - unsigned int jenkins_one_at_a_time::compute(const std::string& data) - { - return compute(data.data(), data.size()); - } - - unsigned int jenkins_one_at_a_time::compute(const char* key, const size_t len) - { - unsigned int hash, i; - for (hash = i = 0; i < len; ++i) - { - hash += key[i]; - hash += (hash << 10); - hash ^= (hash >> 6); - } - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return hash; - } - } -} +#include +#include "string.hpp" +#include "cryptography.hpp" + +/// http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/Source/libtomcrypt/doc/libTomCryptDoc.pdf + +namespace utils +{ + namespace cryptography + { + ecc::key::key() + { + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + + ecc::key::~key() + { + this->free(); + } + + bool ecc::key::is_valid() const + { + return (!memory::is_set(&this->key_storage_, 0, sizeof(this->key_storage_))); + } + + ecc_key* ecc::key::get() + { + return &this->key_storage_; + } + + std::string ecc::key::get_public_key() const + { + uint8_t buffer[512] = {0}; + DWORD length = sizeof(buffer); + + if (ecc_ansi_x963_export(&this->key_storage_, buffer, &length) == CRYPT_OK) + { + return std::string(reinterpret_cast(buffer), length); + } + + return {}; + } + + void ecc::key::set(const std::string& pub_key_buffer) + { + this->free(); + + if (ecc_ansi_x963_import(reinterpret_cast(pub_key_buffer.data()), pub_key_buffer.size(), + &this->key_storage_) != CRYPT_OK) + { + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + } + + void ecc::key::deserialize(const std::string& key) + { + this->free(); + + if (ecc_import(reinterpret_cast(key.data()), key.size(), &this->key_storage_) != CRYPT_OK) + { + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + } + + std::string ecc::key::serialize(const int type) const + { + uint8_t buffer[4096] = {0}; + DWORD length = sizeof(buffer); + + if (ecc_export(buffer, &length, type, &this->key_storage_) == CRYPT_OK) + { + return std::string(reinterpret_cast(buffer), length); + } + + return ""; + } + + void ecc::key::free() + { + if (this->is_valid()) + { + ecc_free(&this->key_storage_); + } + + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + + bool ecc::key::operator==(key& key) const + { + return (this->is_valid() && key.is_valid() && this->serialize(PK_PUBLIC) == key.serialize(PK_PUBLIC)); + } + + ecc::key ecc::generate_key(const int bits) + { + key key; + + ltc_mp = ltm_desc; + register_prng(&sprng_desc); + ecc_make_key(nullptr, find_prng("sprng"), bits / 8, key.get()); + + return key; + } + + std::string ecc::sign_message(key key, const std::string& message) + { + if (!key.is_valid()) return ""; + + uint8_t buffer[512]; + DWORD length = sizeof(buffer); + + ltc_mp = ltm_desc; + register_prng(&sprng_desc); + ecc_sign_hash(reinterpret_cast(message.data()), message.size(), buffer, &length, nullptr, + find_prng("sprng"), key.get()); + + return std::string(reinterpret_cast(buffer), length); + } + + bool ecc::verify_message(key key, const std::string& message, const std::string& signature) + { + if (!key.is_valid()) return false; + + ltc_mp = ltm_desc; + + auto result = 0; + return (ecc_verify_hash(reinterpret_cast(signature.data()), signature.size(), + reinterpret_cast(message.data()), message.size(), &result, + key.get()) == CRYPT_OK && result != 0); + } + + std::string rsa::encrypt(const std::string& data, const std::string& hash, const std::string& key) + { + initialize(); + + const auto prng_id = find_prng("yarrow"); + + rsa_key new_key; + rsa_import(PBYTE(key.data()), key.size(), &new_key); + + prng_state yarrow; + rng_make_prng(128, prng_id, &yarrow, nullptr); + + unsigned char buffer[0x80]; + unsigned long length = sizeof(buffer); + + const auto rsa_result = rsa_encrypt_key( // + PBYTE(data.data()), // + data.size(), // + buffer, // + &length, // + PBYTE(hash.data()), // + hash.size(), // + &yarrow, // + prng_id, // + find_hash("sha1"), // + &new_key); + + rsa_free(&new_key); + + if (rsa_result == CRYPT_OK) + { + return std::string(PCHAR(buffer), length); + } + + return {}; + } + + void rsa::initialize() + { + static auto initialized = false; + if (initialized) return; + initialized = true; + + ltc_mp = ltm_desc; + register_hash(&sha1_desc); + register_prng(&yarrow_desc); + } + + std::string des3::encrypt(const std::string& data, const std::string& iv, const std::string& key) + { + initialize(); + + std::string enc_data; + enc_data.resize(data.size()); + + symmetric_CBC cbc; + const auto des3 = find_cipher("3des"); + + cbc_start(des3, reinterpret_cast(iv.data()), reinterpret_cast(key.data()), + key.size(), 0, &cbc); + cbc_encrypt(reinterpret_cast(data.data()), + reinterpret_cast(const_cast(enc_data.data())), data.size(), &cbc); + cbc_done(&cbc); + + return enc_data; + } + + std::string des3::decrypt(const std::string& data, const std::string& iv, const std::string& key) + { + initialize(); + + std::string dec_data; + dec_data.resize(data.size()); + + symmetric_CBC cbc; + const auto des3 = find_cipher("3des"); + + cbc_start(des3, reinterpret_cast(iv.data()), reinterpret_cast(key.data()), + key.size(), 0, &cbc); + cbc_decrypt(reinterpret_cast(data.data()), + reinterpret_cast(const_cast(dec_data.data())), data.size(), &cbc); + cbc_done(&cbc); + + return dec_data; + } + + void des3::initialize() + { + static auto initialized = false; + if (initialized) return; + initialized = true; + + register_cipher(&des3_desc); + } + + std::string tiger::compute(const std::string& data, const bool hex) + { + return compute(reinterpret_cast(data.data()), data.size(), hex); + } + + std::string tiger::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[24] = {0}; + + hash_state state; + tiger_init(&state); + tiger_process(&state, data, length); + tiger_done(&state, buffer); + + std::string hash(reinterpret_cast(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string sha1::compute(const std::string& data, const bool hex) + { + return compute(reinterpret_cast(data.data()), data.size(), hex); + } + + std::string sha1::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[20] = {0}; + + hash_state state; + sha1_init(&state); + sha1_process(&state, data, length); + sha1_done(&state, buffer); + + std::string hash(reinterpret_cast(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string sha256::compute(const std::string& data, const bool hex) + { + return compute(reinterpret_cast(data.data()), data.size(), hex); + } + + std::string sha256::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[32] = {0}; + + hash_state state; + sha256_init(&state); + sha256_process(&state, data, length); + sha256_done(&state, buffer); + + std::string hash(reinterpret_cast(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string sha512::compute(const std::string& data, const bool hex) + { + return compute(reinterpret_cast(data.data()), data.size(), hex); + } + + std::string sha512::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[64] = {0}; + + hash_state state; + sha512_init(&state); + sha512_process(&state, data, length); + sha512_done(&state, buffer); + + std::string hash(reinterpret_cast(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + unsigned int jenkins_one_at_a_time::compute(const std::string& data) + { + return compute(data.data(), data.size()); + } + + unsigned int jenkins_one_at_a_time::compute(const char* key, const size_t len) + { + unsigned int hash, i; + for (hash = i = 0; i < len; ++i) + { + hash += key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; + } + } +} diff --git a/src/utils/cryptography.hpp b/src/utils/cryptography.hpp index c938766..7269710 100644 --- a/src/utils/cryptography.hpp +++ b/src/utils/cryptography.hpp @@ -1,96 +1,95 @@ -#pragma once -#include "memory.hpp" - -namespace utils -{ - namespace cryptography - { - class ecc final - { - public: - class key final - { - public: - key(); - ~key(); - - bool is_valid() const; - - ecc_key* get(); - - std::string get_public_key() const; - - void set(const std::string& pub_key_buffer); - - void deserialize(const std::string& key); - - std::string serialize(const int type = PK_PRIVATE) const; - - void free(); - - bool operator==(key& key) const; - - private: - ecc_key key_storage_{}; - }; - - static key generate_key(int bits); - static std::string sign_message(key key, const std::string& message); - static bool verify_message(key key, const std::string& message, const std::string& signature); - }; - - class rsa final - { - public: - static std::string encrypt(const std::string& data, const std::string& hash, const std::string& key); - - private: - static void initialize(); - }; - - class des3 final - { - public: - static std::string encrypt(const std::string& data, const std::string& iv, const std::string& key); - static std::string decrypt(const std::string& data, const std::string& iv, const std::string& key); - - private: - static void initialize(); - }; - - class tiger final - { - public: - static std::string compute(const std::string& data, bool hex = false); - static std::string compute(const uint8_t* data, size_t length, bool hex = false); - }; - - class sha1 final - { - public: - static std::string compute(const std::string& data, bool hex = false); - static std::string compute(const uint8_t* data, size_t length, bool hex = false); - }; - - class sha256 final - { - public: - static std::string compute(const std::string& data, bool hex = false); - static std::string compute(const uint8_t* data, size_t length, bool hex = false); - }; - - class sha512 final - { - public: - static std::string compute(const std::string& data, bool hex = false); - static std::string compute(const uint8_t* data, size_t length, bool hex = false); - }; - - class jenkins_one_at_a_time final - { - public: - static unsigned int compute(const std::string& data); - static unsigned int compute(const char* key, size_t len); - }; - } -} +#pragma once + +namespace utils +{ + namespace cryptography + { + class ecc final + { + public: + class key final + { + public: + key(); + ~key(); + + bool is_valid() const; + + ecc_key* get(); + + std::string get_public_key() const; + + void set(const std::string& pub_key_buffer); + + void deserialize(const std::string& key); + + std::string serialize(int type = PK_PRIVATE) const; + + void free(); + + bool operator==(key& key) const; + + private: + ecc_key key_storage_{}; + }; + + static key generate_key(int bits); + static std::string sign_message(key key, const std::string& message); + static bool verify_message(key key, const std::string& message, const std::string& signature); + }; + + class rsa final + { + public: + static std::string encrypt(const std::string& data, const std::string& hash, const std::string& key); + + private: + static void initialize(); + }; + + class des3 final + { + public: + static std::string encrypt(const std::string& data, const std::string& iv, const std::string& key); + static std::string decrypt(const std::string& data, const std::string& iv, const std::string& key); + + private: + static void initialize(); + }; + + class tiger final + { + public: + static std::string compute(const std::string& data, bool hex = false); + static std::string compute(const uint8_t* data, size_t length, bool hex = false); + }; + + class sha1 final + { + public: + static std::string compute(const std::string& data, bool hex = false); + static std::string compute(const uint8_t* data, size_t length, bool hex = false); + }; + + class sha256 final + { + public: + static std::string compute(const std::string& data, bool hex = false); + static std::string compute(const uint8_t* data, size_t length, bool hex = false); + }; + + class sha512 final + { + public: + static std::string compute(const std::string& data, bool hex = false); + static std::string compute(const uint8_t* data, size_t length, bool hex = false); + }; + + class jenkins_one_at_a_time final + { + public: + static unsigned int compute(const std::string& data); + static unsigned int compute(const char* key, size_t len); + }; + } +} diff --git a/src/utils/flags.cpp b/src/utils/flags.cpp index 3c5a159..972aa21 100644 --- a/src/utils/flags.cpp +++ b/src/utils/flags.cpp @@ -1,52 +1,52 @@ -#include -#include "flags.hpp" -#include "string.hpp" - -namespace utils -{ - namespace flags - { - void parse_flags(std::vector& flags) - { - int num_args; - const auto argv = CommandLineToArgvW(GetCommandLineW(), &num_args); - - flags.clear(); - - if (argv) - { - for (auto i = 0; i < num_args; ++i) - { - std::wstring wide_flag(argv[i]); - if (wide_flag[0] == L'-') - { - flags.emplace_back(wide_flag.begin() + 1, wide_flag.end()); - } - } - - LocalFree(argv); - } - } - - bool has_flag(const std::string& flag) - { - static auto parsed = false; - static std::vector enabled_flags; - - if (!parsed) - { - parse_flags(enabled_flags); - } - - for (const auto& entry : enabled_flags) - { - if (string::to_lower(entry) == string::to_lower(flag)) - { - return true; - } - } - - return false; - } - } -} +#include +#include "flags.hpp" +#include "string.hpp" + +namespace utils +{ + namespace flags + { + void parse_flags(std::vector& flags) + { + int num_args; + const auto argv = CommandLineToArgvW(GetCommandLineW(), &num_args); + + flags.clear(); + + if (argv) + { + for (auto i = 0; i < num_args; ++i) + { + std::wstring wide_flag(argv[i]); + if (wide_flag[0] == L'-') + { + flags.emplace_back(wide_flag.begin() + 1, wide_flag.end()); + } + } + + LocalFree(argv); + } + } + + bool has_flag(const std::string& flag) + { + static auto parsed = false; + static std::vector enabled_flags; + + if (!parsed) + { + parse_flags(enabled_flags); + } + + for (const auto& entry : enabled_flags) + { + if (string::to_lower(entry) == string::to_lower(flag)) + { + return true; + } + } + + return false; + } + } +} diff --git a/src/utils/flags.hpp b/src/utils/flags.hpp index 0a34cd8..994adc3 100644 --- a/src/utils/flags.hpp +++ b/src/utils/flags.hpp @@ -1,10 +1,9 @@ -#pragma once -#include "memory.hpp" - -namespace utils -{ - namespace flags - { - bool has_flag(const std::string& flag); - } -} +#pragma once + +namespace utils +{ + namespace flags + { + bool has_flag(const std::string& flag); + } +} diff --git a/src/utils/hook.cpp b/src/utils/hook.cpp index 5149852..b66d1a6 100644 --- a/src/utils/hook.cpp +++ b/src/utils/hook.cpp @@ -1,179 +1,179 @@ -#include -#include "hook.hpp" - -namespace utils -{ - void hook::signature::process() - { - if (this->signatures_.empty()) return; - - const auto start = reinterpret_cast(this->start_); - - const unsigned int sig_count = this->signatures_.size(); - const auto containers = this->signatures_.data(); - - for (size_t i = 0; i < this->length_; ++i) - { - const auto address = start + i; - - for (unsigned int k = 0; k < sig_count; ++k) - { - const auto container = &containers[k]; - - unsigned int j; - for (j = 0; j < strlen(container->mask); ++j) - { - if (container->mask[j] != '?' && container->signature[j] != address[j]) - { - break; - } - } - - if (j == strlen(container->mask)) - { - container->callback(address); - } - } - } - } - - void hook::signature::add(const container& container) - { - signatures_.push_back(container); - } - - hook::~hook() - { - if (this->initialized_) - { - this->uninstall(); - } - } - - hook* hook::initialize(const DWORD place, void (*stub)(), const bool use_jump) - { - return this->initialize(place, reinterpret_cast(stub), use_jump); - } - - hook* hook::initialize(const DWORD place, void* stub, const bool use_jump) - { - return this->initialize(reinterpret_cast(place), stub, use_jump); - } - - hook* hook::initialize(void* place, void* stub, const bool use_jump) - { - if (this->initialized_) return this; - this->initialized_ = true; - - this->use_jump_ = use_jump; - this->place_ = place; - this->stub_ = stub; - - this->original_ = static_cast(this->place_) + 5 + *reinterpret_cast((static_cast(this-> - place_) + 1)); - - return this; - } - - hook* hook::install(const bool unprotect, const bool keep_unprotected) - { - std::lock_guard _(this->state_mutex_); - - if (!this->initialized_ || this->installed_) - { - return this; - } - - this->installed_ = true; - - if (unprotect) VirtualProtect(this->place_, sizeof(this->buffer_), PAGE_EXECUTE_READWRITE, &this->protection_); - std::memcpy(this->buffer_, this->place_, sizeof(this->buffer_)); - - const auto code = static_cast(this->place_); - - *code = static_cast(this->use_jump_ ? 0xE9 : 0xE8); - - *reinterpret_cast(code + 1) = reinterpret_cast(this->stub_) - (reinterpret_cast(this-> - place_) + 5); - - if (unprotect && !keep_unprotected) - VirtualProtect(this->place_, sizeof(this->buffer_), this->protection_, - &this->protection_); - - FlushInstructionCache(GetCurrentProcess(), this->place_, sizeof(this->buffer_)); - - return this; - } - - void hook::quick() - { - if (this->installed_) - { - this->installed_ = false; - } - } - - bool hook::iat(nt::module module, const std::string& target_module, const std::string& process, void* stub) - { - if (!module.is_valid()) return false; - - auto ptr = module.get_iat_entry(target_module, process); - if (!ptr) return false; - - DWORD protect; - VirtualProtect(ptr, sizeof(*ptr), PAGE_EXECUTE_READWRITE, &protect); - - *ptr = stub; - - VirtualProtect(ptr, sizeof(*ptr), protect, &protect); - return true; - } - - hook* hook::uninstall(const bool unprotect) - { - std::lock_guard _(this->state_mutex_); - - if (!this->initialized_ || !this->installed_) - { - return this; - } - - this->installed_ = false; - - if (unprotect) VirtualProtect(this->place_, sizeof(this->buffer_), PAGE_EXECUTE_READWRITE, &this->protection_); - - std::memcpy(this->place_, this->buffer_, sizeof(this->buffer_)); - - if (unprotect) VirtualProtect(this->place_, sizeof(this->buffer_), this->protection_, &this->protection_); - - FlushInstructionCache(GetCurrentProcess(), this->place_, sizeof(this->buffer_)); - - return this; - } - - void* hook::get_address() const - { - return this->place_; - } - - void* hook::get_original() const - { - return this->original_; - } - - void hook::nop(void* place, const size_t length) - { - DWORD old_protect; - VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); - - memset(place, 0x90, length); - - VirtualProtect(place, length, old_protect, &old_protect); - FlushInstructionCache(GetCurrentProcess(), place, length); - } - - void hook::nop(const DWORD place, const size_t length) - { - nop(reinterpret_cast(place), length); - } -} +#include +#include "hook.hpp" + +namespace utils +{ + void hook::signature::process() + { + if (this->signatures_.empty()) return; + + const auto start = reinterpret_cast(this->start_); + + const unsigned int sig_count = this->signatures_.size(); + const auto containers = this->signatures_.data(); + + for (size_t i = 0; i < this->length_; ++i) + { + const auto address = start + i; + + for (unsigned int k = 0; k < sig_count; ++k) + { + const auto container = &containers[k]; + + unsigned int j; + for (j = 0; j < strlen(container->mask); ++j) + { + if (container->mask[j] != '?' && container->signature[j] != address[j]) + { + break; + } + } + + if (j == strlen(container->mask)) + { + container->callback(address); + } + } + } + } + + void hook::signature::add(const container& container) + { + signatures_.push_back(container); + } + + hook::~hook() + { + if (this->initialized_) + { + this->uninstall(); + } + } + + hook* hook::initialize(const DWORD place, void (*stub)(), const bool use_jump) + { + return this->initialize(place, reinterpret_cast(stub), use_jump); + } + + hook* hook::initialize(const DWORD place, void* stub, const bool use_jump) + { + return this->initialize(reinterpret_cast(place), stub, use_jump); + } + + hook* hook::initialize(void* place, void* stub, const bool use_jump) + { + if (this->initialized_) return this; + this->initialized_ = true; + + this->use_jump_ = use_jump; + this->place_ = place; + this->stub_ = stub; + + this->original_ = static_cast(this->place_) + 5 + *reinterpret_cast((static_cast(this-> + place_) + 1)); + + return this; + } + + hook* hook::install(const bool unprotect, const bool keep_unprotected) + { + std::lock_guard _(this->state_mutex_); + + if (!this->initialized_ || this->installed_) + { + return this; + } + + this->installed_ = true; + + if (unprotect) VirtualProtect(this->place_, sizeof(this->buffer_), PAGE_EXECUTE_READWRITE, &this->protection_); + std::memcpy(this->buffer_, this->place_, sizeof(this->buffer_)); + + const auto code = static_cast(this->place_); + + *code = static_cast(this->use_jump_ ? 0xE9 : 0xE8); + + *reinterpret_cast(code + 1) = reinterpret_cast(this->stub_) - (reinterpret_cast(this-> + place_) + 5); + + if (unprotect && !keep_unprotected) + VirtualProtect(this->place_, sizeof(this->buffer_), this->protection_, + &this->protection_); + + FlushInstructionCache(GetCurrentProcess(), this->place_, sizeof(this->buffer_)); + + return this; + } + + void hook::quick() + { + if (this->installed_) + { + this->installed_ = false; + } + } + + bool hook::iat(const nt::module module, const std::string& target_module, const std::string& process, void* stub) + { + if (!module.is_valid()) return false; + + auto ptr = module.get_iat_entry(target_module, process); + if (!ptr) return false; + + DWORD protect; + VirtualProtect(ptr, sizeof(*ptr), PAGE_EXECUTE_READWRITE, &protect); + + *ptr = stub; + + VirtualProtect(ptr, sizeof(*ptr), protect, &protect); + return true; + } + + hook* hook::uninstall(const bool unprotect) + { + std::lock_guard _(this->state_mutex_); + + if (!this->initialized_ || !this->installed_) + { + return this; + } + + this->installed_ = false; + + if (unprotect) VirtualProtect(this->place_, sizeof(this->buffer_), PAGE_EXECUTE_READWRITE, &this->protection_); + + std::memcpy(this->place_, this->buffer_, sizeof(this->buffer_)); + + if (unprotect) VirtualProtect(this->place_, sizeof(this->buffer_), this->protection_, &this->protection_); + + FlushInstructionCache(GetCurrentProcess(), this->place_, sizeof(this->buffer_)); + + return this; + } + + void* hook::get_address() const + { + return this->place_; + } + + void* hook::get_original() const + { + return this->original_; + } + + void hook::nop(void* place, const size_t length) + { + DWORD old_protect; + VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect); + + memset(place, 0x90, length); + + VirtualProtect(place, length, old_protect, &old_protect); + FlushInstructionCache(GetCurrentProcess(), place, length); + } + + void hook::nop(const DWORD place, const size_t length) + { + nop(reinterpret_cast(place), length); + } +} diff --git a/src/utils/hook.hpp b/src/utils/hook.hpp index f044f76..2702991 100644 --- a/src/utils/hook.hpp +++ b/src/utils/hook.hpp @@ -1,123 +1,123 @@ -#pragma once -#include "nt.hpp" - -#define HOOK_JUMP true -#define HOOK_CALL false - -namespace utils -{ - class hook final - { - public: - class signature final - { - public: - struct container final - { - const char* signature; - const char* mask; - std::function callback; - }; - - signature(void* start, const size_t length) : start_(start), length_(length) - { - } - - signature(const DWORD start, const size_t length) : signature(reinterpret_cast(start), length) - { - } - - signature() : signature(0x400000, 0x800000) - { - } - - void process(); - void add(const container& container); - - private: - void* start_; - size_t length_; - std::vector signatures_; - }; - - hook() : initialized_(false), installed_(false), place_(nullptr), stub_(nullptr), original_(nullptr), - use_jump_(false), protection_(0) - { - ZeroMemory(this->buffer_, sizeof(this->buffer_)); - } - - hook(void* place, void* stub, const bool use_jump = true) : hook() { this->initialize(place, stub, use_jump); } - - hook(void* place, void (*stub)(), const bool use_jump = true) : hook( - place, reinterpret_cast(stub), use_jump) - { - } - - hook(const DWORD place, void* stub, const bool use_jump = true) : hook( - reinterpret_cast(place), stub, use_jump) - { - } - - hook(const DWORD place, const DWORD stub, const bool use_jump = true) : hook( - reinterpret_cast(place), reinterpret_cast(stub), use_jump) - { - } - - hook(const DWORD place, void (*stub)(), const bool use_jump = true) : hook( - reinterpret_cast(place), reinterpret_cast(stub), use_jump) - { - } - - hook(const hook&) = delete; - hook(const hook&&) = delete; - - ~hook(); - - hook* initialize(void* place, void* stub, bool use_jump = true); - hook* initialize(DWORD place, void* stub, bool use_jump = true); - hook* initialize(DWORD place, void (*stub)(), bool use_jump = true); // For lambdas - hook* install(bool unprotect = true, bool keep_unprotected = false); - hook* uninstall(bool unprotect = true); - - void* get_address() const; - void* get_original() const; - void quick(); - - static bool iat(nt::module module, const std::string& target_module, const std::string& process, void* stub); - - static void nop(void* place, size_t length); - static void nop(DWORD place, size_t length); - - template - static void set(void* place, T value) - { - DWORD old_protect; - VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect); - - *static_cast(place) = value; - - VirtualProtect(place, sizeof(T), old_protect, &old_protect); - FlushInstructionCache(GetCurrentProcess(), place, sizeof(T)); - } - - template - static void set(const DWORD place, T value) - { - return set(reinterpret_cast(place), value); - } - - private: - bool initialized_; - bool installed_; - - void* place_; - void* stub_; - void* original_; - char buffer_[5]{}; - bool use_jump_; - - DWORD protection_; - - std::mutex state_mutex_; - }; -} +#pragma once +#include "nt.hpp" + +#define HOOK_JUMP true +#define HOOK_CALL false + +namespace utils +{ + class hook final + { + public: + class signature final + { + public: + struct container final + { + const char* signature; + const char* mask; + std::function callback; + }; + + signature(void* start, const size_t length) : start_(start), length_(length) + { + } + + signature(const DWORD start, const size_t length) : signature(reinterpret_cast(start), length) + { + } + + signature() : signature(0x400000, 0x800000) + { + } + + void process(); + void add(const container& container); + + private: + void* start_; + size_t length_; + std::vector signatures_; + }; + + hook() : initialized_(false), installed_(false), place_(nullptr), stub_(nullptr), original_(nullptr), + use_jump_(false), protection_(0) + { + ZeroMemory(this->buffer_, sizeof(this->buffer_)); + } + + hook(void* place, void* stub, const bool use_jump = true) : hook() { this->initialize(place, stub, use_jump); } + + hook(void* place, void (*stub)(), const bool use_jump = true) : hook( + place, reinterpret_cast(stub), use_jump) + { + } + + hook(const DWORD place, void* stub, const bool use_jump = true) : hook( + reinterpret_cast(place), stub, use_jump) + { + } + + hook(const DWORD place, const DWORD stub, const bool use_jump = true) : hook( + reinterpret_cast(place), reinterpret_cast(stub), use_jump) + { + } + + hook(const DWORD place, void (*stub)(), const bool use_jump = true) : hook( + reinterpret_cast(place), reinterpret_cast(stub), use_jump) + { + } + + hook(const hook&) = delete; + hook(const hook&&) = delete; + + ~hook(); + + hook* initialize(void* place, void* stub, bool use_jump = true); + hook* initialize(DWORD place, void* stub, bool use_jump = true); + hook* initialize(DWORD place, void (*stub)(), bool use_jump = true); // For lambdas + hook* install(bool unprotect = true, bool keep_unprotected = false); + hook* uninstall(bool unprotect = true); + + void* get_address() const; + void* get_original() const; + void quick(); + + static bool iat(nt::module module, const std::string& target_module, const std::string& process, void* stub); + + static void nop(void* place, size_t length); + static void nop(DWORD place, size_t length); + + template + static void set(void* place, T value) + { + DWORD old_protect; + VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect); + + *static_cast(place) = value; + + VirtualProtect(place, sizeof(T), old_protect, &old_protect); + FlushInstructionCache(GetCurrentProcess(), place, sizeof(T)); + } + + template + static void set(const DWORD place, T value) + { + return set(reinterpret_cast(place), value); + } + + private: + bool initialized_; + bool installed_; + + void* place_; + void* stub_; + void* original_; + char buffer_[5]{}; + bool use_jump_; + + DWORD protection_; + + std::mutex state_mutex_; + }; +} diff --git a/src/utils/io.cpp b/src/utils/io.cpp index 6bf5d7a..7c0f7d1 100644 --- a/src/utils/io.cpp +++ b/src/utils/io.cpp @@ -1,110 +1,110 @@ -#include -#include "io.hpp" - -namespace utils -{ - namespace io - { - bool file_exists(const std::string& file) - { - return std::ifstream(file).good(); - } - - bool write_file(const std::string& file, const std::string& data, const bool append) - { - const auto pos = file.find_last_of("/\\"); - if (pos != std::string::npos) - { - create_directory(file.substr(0, pos)); - } - - std::ofstream stream( - file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : std::ofstream::out)); - - if (stream.is_open()) - { - stream.write(data.data(), data.size()); - stream.close(); - return true; - } - - return false; - } - - std::string read_file(const std::string& file) - { - std::string data; - read_file(file, &data); - return data; - } - - bool read_file(const std::string& file, std::string* data) - { - if (!data) return false; - data->clear(); - - if (file_exists(file)) - { - std::ifstream stream(file, std::ios::binary); - if (!stream.is_open()) return false; - - stream.seekg(0, std::ios::end); - const std::streamsize size = stream.tellg(); - stream.seekg(0, std::ios::beg); - - if (size > -1) - { - data->resize(static_cast(size)); - stream.read(const_cast(data->data()), size); - stream.close(); - return true; - } - } - - return false; - } - - size_t file_size(const std::string& file) - { - if (file_exists(file)) - { - std::ifstream stream(file, std::ios::binary); - - if (stream.good()) - { - stream.seekg(0, std::ios::end); - return static_cast(stream.tellg()); - } - } - - return 0; - } - - bool create_directory(const std::string& directory) - { - return std::experimental::filesystem::create_directories(directory); - } - - bool directory_exists(const std::string& directory) - { - return std::experimental::filesystem::is_directory(directory); - } - - bool directory_is_empty(const std::string& directory) - { - return std::experimental::filesystem::is_empty(directory); - } - - std::vector list_files(const std::string& directory) - { - std::vector files; - - for (auto& file : std::experimental::filesystem::directory_iterator(directory)) - { - files.push_back(file.path().generic_string()); - } - - return files; - } - } -} +#include +#include "io.hpp" + +namespace utils +{ + namespace io + { + bool file_exists(const std::string& file) + { + return std::ifstream(file).good(); + } + + bool write_file(const std::string& file, const std::string& data, const bool append) + { + const auto pos = file.find_last_of("/\\"); + if (pos != std::string::npos) + { + create_directory(file.substr(0, pos)); + } + + std::ofstream stream( + file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : std::ofstream::out)); + + if (stream.is_open()) + { + stream.write(data.data(), data.size()); + stream.close(); + return true; + } + + return false; + } + + std::string read_file(const std::string& file) + { + std::string data; + read_file(file, &data); + return data; + } + + bool read_file(const std::string& file, std::string* data) + { + if (!data) return false; + data->clear(); + + if (file_exists(file)) + { + std::ifstream stream(file, std::ios::binary); + if (!stream.is_open()) return false; + + stream.seekg(0, std::ios::end); + const std::streamsize size = stream.tellg(); + stream.seekg(0, std::ios::beg); + + if (size > -1) + { + data->resize(static_cast(size)); + stream.read(const_cast(data->data()), size); + stream.close(); + return true; + } + } + + return false; + } + + size_t file_size(const std::string& file) + { + if (file_exists(file)) + { + std::ifstream stream(file, std::ios::binary); + + if (stream.good()) + { + stream.seekg(0, std::ios::end); + return static_cast(stream.tellg()); + } + } + + return 0; + } + + bool create_directory(const std::string& directory) + { + return std::experimental::filesystem::create_directories(directory); + } + + bool directory_exists(const std::string& directory) + { + return std::experimental::filesystem::is_directory(directory); + } + + bool directory_is_empty(const std::string& directory) + { + return std::experimental::filesystem::is_empty(directory); + } + + std::vector list_files(const std::string& directory) + { + std::vector files; + + for (auto& file : std::experimental::filesystem::directory_iterator(directory)) + { + files.push_back(file.path().generic_string()); + } + + return files; + } + } +} diff --git a/src/utils/nt.cpp b/src/utils/nt.cpp index ebea371..5018af9 100644 --- a/src/utils/nt.cpp +++ b/src/utils/nt.cpp @@ -1,207 +1,207 @@ -#include -#include "nt.hpp" - -namespace utils -{ - namespace nt - { - module module::load(const std::string& name) - { - return module(LoadLibraryA(name.data())); - } - - module module::get_by_address(void* address) - { - HMODULE handle = nullptr; - GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast(address), &handle); - return module(handle); - } - - module::module() - { - this->module_ = GetModuleHandleA(nullptr); - } - - module::module(const std::string& name) - { - this->module_ = GetModuleHandleA(name.data()); - } - - module::module(const HMODULE handle) - { - this->module_ = handle; - } - - bool module::operator==(const module& obj) const - { - return this->module_ == obj.module_; - } - - module::operator bool() const - { - return this->is_valid(); - } - - module::operator HMODULE() const - { - return this->get_handle(); - } - - PIMAGE_NT_HEADERS module::get_nt_headers() const - { - if (!this->is_valid()) return nullptr; - return reinterpret_cast(this->get_ptr() + this->get_dos_header()->e_lfanew); - } - - PIMAGE_DOS_HEADER module::get_dos_header() const - { - return reinterpret_cast(this->get_ptr()); - } - - PIMAGE_OPTIONAL_HEADER module::get_optional_header() const - { - if (!this->is_valid()) return nullptr; - return &this->get_nt_headers()->OptionalHeader; - } - - std::vector module::get_section_headers() const - { - std::vector headers; - - auto nt_headers = this->get_nt_headers(); - auto section = IMAGE_FIRST_SECTION(nt_headers); - - for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i, ++section) - { - if (section) headers.push_back(section); - else OutputDebugStringA("There was an invalid section :O"); - } - - return headers; - } - - std::uint8_t* module::get_ptr() const - { - return reinterpret_cast(this->module_); - } - - void module::unprotect() const - { - if (!this->is_valid()) return; - - DWORD protection; - VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage, PAGE_EXECUTE_READWRITE, - &protection); - } - - size_t module::get_relative_entry_point() const - { - if (!this->is_valid()) return 0; - return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint; - } - - void* module::get_entry_point() const - { - if (!this->is_valid()) return nullptr; - return this->get_ptr() + this->get_relative_entry_point(); - } - - bool module::is_valid() const - { - return this->module_ != nullptr && this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE; - } - - std::string module::get_name() const - { - if (!this->is_valid()) return ""; - - auto path = this->get_path(); - const auto pos = path.find_last_of("/\\"); - if (pos == std::string::npos) return path; - - return path.substr(pos + 1); - } - - std::string module::get_path() const - { - if (!this->is_valid()) return ""; - - char name[MAX_PATH] = {0}; - GetModuleFileNameA(this->module_, name, sizeof name); - - return name; - } - - void module::free() - { - if (this->is_valid()) - { - FreeLibrary(this->module_); - this->module_ = nullptr; - } - } - - HMODULE module::get_handle() const - { - return this->module_; - } - - void** module::get_iat_entry(const std::string& module_name, const std::string& proc_name) const - { - if (!this->is_valid()) return nullptr; - - module other_module(module_name); - if (!other_module.is_valid()) return nullptr; - - const auto target_function = other_module.get_proc(proc_name); - if (!target_function) return nullptr; - - auto* header = this->get_optional_header(); - if (!header) return nullptr; - - auto* import_descriptor = reinterpret_cast(this->get_ptr() + header->DataDirectory - [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); - - while (import_descriptor->Name) - { - if (!_stricmp(reinterpret_cast(this->get_ptr() + import_descriptor->Name), module_name.data())) - { - auto* original_thunk_data = reinterpret_cast(import_descriptor-> - OriginalFirstThunk + this->get_ptr()); - auto* thunk_data = reinterpret_cast(import_descriptor->FirstThunk + this-> - get_ptr()); - - while (original_thunk_data->u1.AddressOfData) - { - const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF; - - if (ordinal_number > 0xFFFF) continue; - - if (GetProcAddress(other_module.module_, reinterpret_cast(ordinal_number)) == - target_function) - { - return reinterpret_cast(&thunk_data->u1.Function); - } - - ++original_thunk_data; - ++thunk_data; - } - - //break; - } - - ++import_descriptor; - } - - return nullptr; - } - - void raise_hard_exception() - { - int data = false; - utils::nt::module ntdll("ntdll.dll"); - ntdll.invoke_pascal("RtlAdjustPrivilege", 19, true, false, &data); - ntdll.invoke_pascal("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data); - } - } -} +#include +#include "nt.hpp" + +namespace utils +{ + namespace nt + { + module module::load(const std::string& name) + { + return module(LoadLibraryA(name.data())); + } + + module module::get_by_address(void* address) + { + HMODULE handle = nullptr; + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast(address), &handle); + return module(handle); + } + + module::module() + { + this->module_ = GetModuleHandleA(nullptr); + } + + module::module(const std::string& name) + { + this->module_ = GetModuleHandleA(name.data()); + } + + module::module(const HMODULE handle) + { + this->module_ = handle; + } + + bool module::operator==(const module& obj) const + { + return this->module_ == obj.module_; + } + + module::operator bool() const + { + return this->is_valid(); + } + + module::operator HMODULE() const + { + return this->get_handle(); + } + + PIMAGE_NT_HEADERS module::get_nt_headers() const + { + if (!this->is_valid()) return nullptr; + return reinterpret_cast(this->get_ptr() + this->get_dos_header()->e_lfanew); + } + + PIMAGE_DOS_HEADER module::get_dos_header() const + { + return reinterpret_cast(this->get_ptr()); + } + + PIMAGE_OPTIONAL_HEADER module::get_optional_header() const + { + if (!this->is_valid()) return nullptr; + return &this->get_nt_headers()->OptionalHeader; + } + + std::vector module::get_section_headers() const + { + std::vector headers; + + auto nt_headers = this->get_nt_headers(); + auto section = IMAGE_FIRST_SECTION(nt_headers); + + for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i, ++section) + { + if (section) headers.push_back(section); + else OutputDebugStringA("There was an invalid section :O"); + } + + return headers; + } + + std::uint8_t* module::get_ptr() const + { + return reinterpret_cast(this->module_); + } + + void module::unprotect() const + { + if (!this->is_valid()) return; + + DWORD protection; + VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage, PAGE_EXECUTE_READWRITE, + &protection); + } + + size_t module::get_relative_entry_point() const + { + if (!this->is_valid()) return 0; + return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint; + } + + void* module::get_entry_point() const + { + if (!this->is_valid()) return nullptr; + return this->get_ptr() + this->get_relative_entry_point(); + } + + bool module::is_valid() const + { + return this->module_ != nullptr && this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE; + } + + std::string module::get_name() const + { + if (!this->is_valid()) return ""; + + auto path = this->get_path(); + const auto pos = path.find_last_of("/\\"); + if (pos == std::string::npos) return path; + + return path.substr(pos + 1); + } + + std::string module::get_path() const + { + if (!this->is_valid()) return ""; + + char name[MAX_PATH] = {0}; + GetModuleFileNameA(this->module_, name, sizeof name); + + return name; + } + + void module::free() + { + if (this->is_valid()) + { + FreeLibrary(this->module_); + this->module_ = nullptr; + } + } + + HMODULE module::get_handle() const + { + return this->module_; + } + + void** module::get_iat_entry(const std::string& module_name, const std::string& proc_name) const + { + if (!this->is_valid()) return nullptr; + + const module other_module(module_name); + if (!other_module.is_valid()) return nullptr; + + const auto target_function = other_module.get_proc(proc_name); + if (!target_function) return nullptr; + + auto* header = this->get_optional_header(); + if (!header) return nullptr; + + auto* import_descriptor = reinterpret_cast(this->get_ptr() + header->DataDirectory + [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + + while (import_descriptor->Name) + { + if (!_stricmp(reinterpret_cast(this->get_ptr() + import_descriptor->Name), module_name.data())) + { + auto* original_thunk_data = reinterpret_cast(import_descriptor-> + OriginalFirstThunk + this->get_ptr()); + auto* thunk_data = reinterpret_cast(import_descriptor->FirstThunk + this-> + get_ptr()); + + while (original_thunk_data->u1.AddressOfData) + { + const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF; + + if (ordinal_number > 0xFFFF) continue; + + if (GetProcAddress(other_module.module_, reinterpret_cast(ordinal_number)) == + target_function) + { + return reinterpret_cast(&thunk_data->u1.Function); + } + + ++original_thunk_data; + ++thunk_data; + } + + //break; + } + + ++import_descriptor; + } + + return nullptr; + } + + void raise_hard_exception() + { + int data = false; + const module ntdll("ntdll.dll"); + ntdll.invoke_pascal("RtlAdjustPrivilege", 19, true, false, &data); + ntdll.invoke_pascal("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data); + } + } +}