More fixes
This commit is contained in:
parent
91aa9cc0b8
commit
84cba76ae3
103
deps/premake/libtommath.lua
vendored
103
deps/premake/libtommath.lua
vendored
@ -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)
|
||||
|
@ -1,182 +1,182 @@
|
||||
#include <std_include.hpp>
|
||||
#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<const unsigned char*>(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<unsigned char*>(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<char*>(this->buffer_.data());
|
||||
const auto* input_bytes = reinterpret_cast<const unsigned char*>(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 <std_include.hpp>
|
||||
#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<const unsigned char*>(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<unsigned char*>(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<char*>(this->buffer_.data());
|
||||
const auto* input_bytes = reinterpret_cast<const unsigned char*>(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_;
|
||||
}
|
||||
}
|
||||
|
@ -1,308 +1,308 @@
|
||||
#include <std_include.hpp>
|
||||
#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<char*>(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<char*>(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<char*>(this->buffer_.data()) + this->current_byte_;
|
||||
*length = static_cast<int>(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<int>(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<const char*>(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 <std_include.hpp>
|
||||
#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<char*>(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<char*>(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<char*>(this->buffer_.data()) + this->current_byte_;
|
||||
*length = static_cast<int>(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<int>(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<const char*>(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_;
|
||||
}
|
||||
}
|
||||
|
@ -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<remote_reply> create_message(uint8_t type)
|
||||
{
|
||||
auto reply = std::make_shared<remote_reply>(this, type);
|
||||
return reply;
|
||||
}
|
||||
|
||||
virtual std::shared_ptr<service_reply> create_reply(uint8_t type, uint32_t error = 0 /*Game::bdLobbyErrorCode::BD_NO_ERROR*/)
|
||||
{
|
||||
auto reply = std::make_shared<service_reply>(this, type, error);
|
||||
return reply;
|
||||
}
|
||||
};
|
||||
|
||||
class remote_reply final
|
||||
{
|
||||
public:
|
||||
remote_reply(i_server* server, uint8_t _type) : type_(_type), server_(server) {}
|
||||
|
||||
template <typename BufferType>
|
||||
void send(BufferType* buffer, const bool encrypted)
|
||||
{
|
||||
std::unique_ptr<typed_reply> reply;
|
||||
|
||||
if (encrypted) reply = std::make_unique<encrypted_reply>(this->type_, buffer);
|
||||
else reply = std::make_unique<unencrypted_reply>(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<i_serializable>& object)
|
||||
{
|
||||
this->objects_.push_back(object);
|
||||
}
|
||||
|
||||
void add(i_serializable* object)
|
||||
{
|
||||
this->add(std::shared_ptr<i_serializable>(object));
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t type_;
|
||||
uint32_t error_;
|
||||
remote_reply reply_;
|
||||
|
||||
std::vector<std::shared_ptr<i_serializable>> 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<remote_reply> create_message(uint8_t type)
|
||||
{
|
||||
auto reply = std::make_shared<remote_reply>(this, type);
|
||||
return reply;
|
||||
}
|
||||
|
||||
virtual std::shared_ptr<service_reply> create_reply(uint8_t type,
|
||||
uint32_t error = 0 /*Game::bdLobbyErrorCode::BD_NO_ERROR*/)
|
||||
{
|
||||
auto reply = std::make_shared<service_reply>(this, type, error);
|
||||
return reply;
|
||||
}
|
||||
};
|
||||
|
||||
class remote_reply final
|
||||
{
|
||||
public:
|
||||
remote_reply(i_server* server, uint8_t _type) : type_(_type), server_(server)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename BufferType>
|
||||
void send(BufferType* buffer, const bool encrypted)
|
||||
{
|
||||
std::unique_ptr<typed_reply> reply;
|
||||
|
||||
if (encrypted) reply = std::make_unique<encrypted_reply>(this->type_, buffer);
|
||||
else reply = std::make_unique<unencrypted_reply>(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<i_serializable>& object)
|
||||
{
|
||||
this->objects_.push_back(object);
|
||||
}
|
||||
|
||||
void add(i_serializable* object)
|
||||
{
|
||||
this->add(std::shared_ptr<i_serializable>(object));
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t type_;
|
||||
uint32_t error_;
|
||||
remote_reply reply_;
|
||||
|
||||
std::vector<std::shared_ptr<i_serializable>> objects_;
|
||||
};
|
||||
}
|
||||
|
@ -1,75 +1,75 @@
|
||||
#include <std_include.hpp>
|
||||
#include <utility>
|
||||
#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 <std_include.hpp>
|
||||
#include <utility>
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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<void(*)(unsigned int, unsigned int, unsigned int)>(0x4EFAA0)(id, stringValue, paramcount);
|
||||
return reinterpret_cast<void(*)(unsigned int, unsigned int, unsigned int)>(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<native::scrVmPub_t*>(SELECT_VALUE(0x1BF2580, 0x20B4A80, 0x1F5B080));
|
||||
|
||||
native::scr_instanceFunctions = reinterpret_cast<native::scr_call_t*>( SELECT_VALUE(0x184CDB0, 0x1D4F258,
|
||||
0x1BF59C8));
|
||||
native::scr_globalFunctions = reinterpret_cast<native::scr_call_t*>( SELECT_VALUE(0x186C68C, 0x1D6EB34,
|
||||
0x1C152A4
|
||||
));
|
||||
native::scr_instanceFunctions = reinterpret_cast<native::scr_call_t*>(SELECT_VALUE(0x184CDB0, 0x1D4F258,
|
||||
0x1BF59C8));
|
||||
native::scr_globalFunctions = reinterpret_cast<native::scr_call_t*>(SELECT_VALUE(0x186C68C, 0x1D6EB34,
|
||||
0x1C152A4
|
||||
));
|
||||
|
||||
native::g_script_error_level = reinterpret_cast<int*>(SELECT_VALUE(0x1BEFCFC, 0x20B21FC, 0x1F5B058));
|
||||
native::g_script_error = reinterpret_cast<jmp_buf*>(SELECT_VALUE(0x1BF1D18, 0x20B4218, 0x1F5A818));
|
||||
|
@ -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);
|
||||
|
@ -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<void(std::vector<chaiscript::Boxed_Value>)>&
|
||||
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<chaiscript::Boxed_Value>& arguments) const
|
||||
{
|
||||
return this->context_->get_executer()->call(function, this->get_entity_id(), arguments);
|
||||
}
|
||||
|
||||
void entity::notify(const std::string& event,
|
||||
const std::vector<chaiscript::Boxed_Value>& 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<int>(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<void(std::vector<chaiscript::Boxed_Value>)>&
|
||||
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<chaiscript::Boxed_Value>& arguments) const
|
||||
{
|
||||
return this->context_->get_executer()->call(function, this->get_entity_id(), arguments);
|
||||
}
|
||||
|
||||
void entity::notify(const std::string& event,
|
||||
const std::vector<chaiscript::Boxed_Value>& 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<int>(this->entity_id_)});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>(), "_event_listener_handle");
|
||||
chai->add(chaiscript::constructor<event_listener_handle()>(), "_event_listener_handle");
|
||||
chai->add(chaiscript::constructor<event_listener_handle(const event_listener_handle&)>(),
|
||||
"_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<chaiscript::Boxed_Value> 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<chaiscript::Boxed_Value>& 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<chaiscript::Boxed_Value>& 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>(), "_event_listener_handle");
|
||||
chai->add(chaiscript::constructor<event_listener_handle()>(), "_event_listener_handle");
|
||||
chai->add(chaiscript::constructor<event_listener_handle(const event_listener_handle&)>(),
|
||||
"_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<chaiscript::Boxed_Value> 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<chaiscript::Boxed_Value>& 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<chaiscript::Boxed_Value>& 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<chaiscript::Boxed_Value> 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<chaiscript::Boxed_Value> 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<chaiscript::Boxed_Value> 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<chaiscript::Boxed_Value> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
|
@ -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<chaiscript::Boxed_Value> 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<float>(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<double>(value);
|
||||
value_ptr->type = native::SCRIPT_FLOAT;
|
||||
value_ptr->u.floatValue = static_cast<float>(real_value);
|
||||
}
|
||||
else if (value.get_type_info() == typeid(int))
|
||||
{
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<int>(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<bool>(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<entity>(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<std::string>(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<chaiscript::Boxed_Value>))
|
||||
{
|
||||
float values[3];
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<std::vector<chaiscript::Boxed_Value>>(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<float>(value);
|
||||
}
|
||||
if (value.get_type_info() == typeid(double))
|
||||
{
|
||||
return float(this->context_->get_chai()->boxed_cast<double>(value));
|
||||
}
|
||||
if (value.get_type_info() == typeid(int))
|
||||
{
|
||||
return float(this->context_->get_chai()->boxed_cast<int>(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<chaiscript::Boxed_Value> 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<float>(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<double>(value);
|
||||
value_ptr->type = native::SCRIPT_FLOAT;
|
||||
value_ptr->u.floatValue = static_cast<float>(real_value);
|
||||
}
|
||||
else if (value.get_type_info() == typeid(int))
|
||||
{
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<int>(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<bool>(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<entity>(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<std::string>(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<chaiscript::Boxed_Value>))
|
||||
{
|
||||
float values[3];
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<std::vector<chaiscript::Boxed_Value>
|
||||
>(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<float>(value);
|
||||
}
|
||||
if (value.get_type_info() == typeid(double))
|
||||
{
|
||||
return float(this->context_->get_chai()->boxed_cast<double>(value));
|
||||
}
|
||||
if (value.get_type_info() == typeid(int))
|
||||
{
|
||||
return float(this->context_->get_chai()->boxed_cast<int>(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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>(), "_task_handle");
|
||||
chai->add(chaiscript::constructor<task_handle()>(), "_task_handle");
|
||||
chai->add(chaiscript::constructor<task_handle(const task_handle&)>(), "_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<void()>& callback, const long long milliseconds) -> task_handle
|
||||
{
|
||||
return this->add(callback, milliseconds, true);
|
||||
}), "setTimeout");
|
||||
|
||||
chai->add(chaiscript::fun([this](const std::function<void()>& 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<void()>& 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<void()>& 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>(), "_task_handle");
|
||||
chai->add(chaiscript::constructor<task_handle()>(), "_task_handle");
|
||||
chai->add(chaiscript::constructor<task_handle(const task_handle&)>(), "_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<void()>& callback, const long long milliseconds) -> task_handle
|
||||
{
|
||||
return this->add(callback, milliseconds, true);
|
||||
}), "setTimeout");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[this](const std::function<void()>& 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<void()>& 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<void()>& 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 <typename T>
|
||||
class installer final
|
||||
{
|
||||
static_assert(std::is_base_of<module, T>::value, "Module has invalid base class");
|
||||
|
||||
public:
|
||||
installer()
|
||||
{
|
||||
register_module(std::make_unique<T>());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
static T* get()
|
||||
{
|
||||
for(const auto& module_ : *modules_)
|
||||
{
|
||||
if(typeid(*module_.get()) == typeid(T))
|
||||
{
|
||||
return reinterpret_cast<T*>(module_.get());
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void register_module(std::unique_ptr<module>&& 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<std::unique_ptr<module>>* modules_;
|
||||
|
||||
static void destroy_modules();
|
||||
};
|
||||
|
||||
#define REGISTER_MODULE(name) \
|
||||
namespace \
|
||||
{ \
|
||||
static module_loader::installer<name> $_##name; \
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class installer final
|
||||
{
|
||||
static_assert(std::is_base_of<module, T>::value, "Module has invalid base class");
|
||||
|
||||
public:
|
||||
installer()
|
||||
{
|
||||
register_module(std::make_unique<T>());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static T* get()
|
||||
{
|
||||
for (const auto& module_ : *modules_)
|
||||
{
|
||||
if (typeid(*module_.get()) == typeid(T))
|
||||
{
|
||||
return reinterpret_cast<T*>(module_.get());
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void register_module(std::unique_ptr<module>&& 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<std::unique_ptr<module>>* modules_;
|
||||
|
||||
static void destroy_modules();
|
||||
};
|
||||
|
||||
#define REGISTER_MODULE(name) \
|
||||
namespace \
|
||||
{ \
|
||||
static module_loader::installer<name> $_##name; \
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1,102 +1,102 @@
|
||||
#include <std_include.hpp>
|
||||
#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<std::pair<std::string, int>> scheduler::errors_;
|
||||
utils::concurrent_list<std::function<void()>> scheduler::callbacks_;
|
||||
utils::concurrent_list<std::function<void()>> scheduler::single_callbacks_;
|
||||
|
||||
void scheduler::on_frame(const std::function<void()>& callback)
|
||||
{
|
||||
std::lock_guard _(mutex_);
|
||||
callbacks_.add(callback);
|
||||
}
|
||||
|
||||
void scheduler::once(const std::function<void()>& 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<void(*)()>(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 <std_include.hpp>
|
||||
#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<std::pair<std::string, int>> scheduler::errors_;
|
||||
utils::concurrent_list<std::function<void()>> scheduler::callbacks_;
|
||||
utils::concurrent_list<std::function<void()>> scheduler::single_callbacks_;
|
||||
|
||||
void scheduler::on_frame(const std::function<void()>& callback)
|
||||
{
|
||||
std::lock_guard _(mutex_);
|
||||
callbacks_.add(callback);
|
||||
}
|
||||
|
||||
void scheduler::once(const std::function<void()>& 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<void(*)()>(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);
|
||||
|
@ -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<scripting>()->run_frame();
|
||||
return game::native::G_RunFrame(a1, a2);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ private:
|
||||
|
||||
this->client_utils_.invoke<void>("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};
|
||||
|
@ -1,16 +1,38 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#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 <std_include.hpp>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "interface.hpp"
|
||||
#include "utils/memory.hpp"
|
||||
#include "utils/nt.hpp"
|
||||
#include <minwinbase.h>
|
||||
|
||||
namespace steam
|
||||
{
|
||||
|
@ -1,91 +1,91 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef interface
|
||||
#undef interface
|
||||
#endif
|
||||
|
||||
namespace steam
|
||||
{
|
||||
template <size_t ...>
|
||||
struct argument_size_calculator final : std::integral_constant<size_t, 0>
|
||||
{
|
||||
};
|
||||
|
||||
template <size_t X, size_t ... Xs>
|
||||
struct argument_size_calculator<X, Xs...> final : std::integral_constant<
|
||||
size_t, X + ((argument_size_calculator<Xs...>::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 <typename T, typename... Args>
|
||||
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<sizeof(Args)...>::value;
|
||||
if (passed_argc != method_result.param_size)
|
||||
{
|
||||
throw std::runtime_error("Invalid argument count");
|
||||
}
|
||||
|
||||
return reinterpret_cast<T(__thiscall*)(void*, Args ...)>(method_result.pointer)(
|
||||
this->interface_ptr_, args...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T invoke(const size_t table_entry, Args ... args)
|
||||
{
|
||||
if (!this->interface_ptr_)
|
||||
{
|
||||
throw std::runtime_error("Invalid interface pointer");
|
||||
}
|
||||
|
||||
return reinterpret_cast<T(__thiscall*)(void*, Args ...)>((*this->interface_ptr_)[table_entry])(
|
||||
this->interface_ptr_, args...);
|
||||
}
|
||||
|
||||
private:
|
||||
void*** interface_ptr_;
|
||||
std::unordered_map<std::string, method> 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 <size_t ...>
|
||||
struct argument_size_calculator final : std::integral_constant<size_t, 0>
|
||||
{
|
||||
};
|
||||
|
||||
template <size_t X, size_t ... Xs>
|
||||
struct argument_size_calculator<X, Xs...> final : std::integral_constant<
|
||||
size_t, X + ((argument_size_calculator<Xs...>::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 <typename T, typename... Args>
|
||||
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<sizeof(Args)...>::value;
|
||||
if (passed_argc != method_result.param_size)
|
||||
{
|
||||
throw std::runtime_error("Invalid argument count");
|
||||
}
|
||||
|
||||
return reinterpret_cast<T(__thiscall*)(void*, Args ...)>(method_result.pointer)(
|
||||
this->interface_ptr_, args...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T invoke(const size_t table_entry, Args ... args)
|
||||
{
|
||||
if (!this->interface_ptr_)
|
||||
{
|
||||
throw std::runtime_error("Invalid interface pointer");
|
||||
}
|
||||
|
||||
return reinterpret_cast<T(__thiscall*)(void*, Args ...)>((*this->interface_ptr_)[table_entry])(
|
||||
this->interface_ptr_, args...);
|
||||
}
|
||||
|
||||
private:
|
||||
void*** interface_ptr_;
|
||||
std::unordered_map<std::string, method> 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);
|
||||
};
|
||||
}
|
||||
|
@ -1,234 +1,232 @@
|
||||
#include <std_include.hpp>
|
||||
#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<uint64_t, bool> callbacks::calls_;
|
||||
std::map<uint64_t, callbacks::base*> callbacks::result_handlers_;
|
||||
std::vector<callbacks::result> callbacks::results_;
|
||||
std::vector<callbacks::base*> 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<BYTE*>(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 <std_include.hpp>
|
||||
#include "steam/steam.hpp"
|
||||
|
||||
namespace steam
|
||||
{
|
||||
::utils::nt::module overlay(nullptr);
|
||||
|
||||
uint64_t callbacks::call_id_ = 0;
|
||||
std::recursive_mutex callbacks::mutex_;
|
||||
std::map<uint64_t, bool> callbacks::calls_;
|
||||
std::map<uint64_t, callbacks::base*> callbacks::result_handlers_;
|
||||
std::vector<callbacks::result> callbacks::results_;
|
||||
std::vector<callbacks::base*> 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<BYTE*>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,130 +1,131 @@
|
||||
#pragma once
|
||||
|
||||
namespace utils
|
||||
{
|
||||
template <typename T>
|
||||
class concurrent_list final
|
||||
{
|
||||
public:
|
||||
class element final
|
||||
{
|
||||
public:
|
||||
explicit element(std::recursive_mutex* mutex, std::shared_ptr<T> entry = {}, std::shared_ptr<element> next = {}) :
|
||||
mutex_(mutex),
|
||||
entry_(std::move(entry)),
|
||||
next_(std::move(next))
|
||||
{
|
||||
}
|
||||
|
||||
void remove(const std::shared_ptr<T>& 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<element> get_next() const
|
||||
{
|
||||
std::lock_guard _(*this->mutex_);
|
||||
return this->next_;
|
||||
}
|
||||
|
||||
std::shared_ptr<T> 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<T> entry_;
|
||||
std::shared_ptr<element> 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<T>& 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<T>(object);
|
||||
this->entry_ = std::make_shared<element>(&this->mutex_, object_ptr, this->entry_);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
this->entry_ = {};
|
||||
}
|
||||
|
||||
private:
|
||||
std::recursive_mutex mutex_;
|
||||
std::shared_ptr<element> entry_;
|
||||
};
|
||||
}
|
||||
#pragma once
|
||||
|
||||
namespace utils
|
||||
{
|
||||
template <typename T>
|
||||
class concurrent_list final
|
||||
{
|
||||
public:
|
||||
class element final
|
||||
{
|
||||
public:
|
||||
explicit element(std::recursive_mutex* mutex, std::shared_ptr<T> entry = {},
|
||||
std::shared_ptr<element> next = {}) :
|
||||
mutex_(mutex),
|
||||
entry_(std::move(entry)),
|
||||
next_(std::move(next))
|
||||
{
|
||||
}
|
||||
|
||||
void remove(const std::shared_ptr<T>& 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<element> get_next() const
|
||||
{
|
||||
std::lock_guard _(*this->mutex_);
|
||||
return this->next_;
|
||||
}
|
||||
|
||||
std::shared_ptr<T> 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<T> entry_;
|
||||
std::shared_ptr<element> 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<T>& 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<T>(object);
|
||||
this->entry_ = std::make_shared<element>(&this->mutex_, object_ptr, this->entry_);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
this->entry_ = {};
|
||||
}
|
||||
|
||||
private:
|
||||
std::recursive_mutex mutex_;
|
||||
std::shared_ptr<element> entry_;
|
||||
};
|
||||
}
|
||||
|
@ -1,325 +1,326 @@
|
||||
#include <std_include.hpp>
|
||||
#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<char*>(buffer), length);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void ecc::key::set(const std::string& pub_key_buffer)
|
||||
{
|
||||
this->free();
|
||||
|
||||
if (ecc_ansi_x963_import(reinterpret_cast<const uint8_t*>(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<const uint8_t*>(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<char*>(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<const uint8_t*>(message.data()), message.size(), buffer, &length, nullptr,
|
||||
find_prng("sprng"), key.get());
|
||||
|
||||
return std::string(reinterpret_cast<char*>(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<const uint8_t*>(signature.data()), signature.size(),
|
||||
reinterpret_cast<const uint8_t*>(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<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()),
|
||||
key.size(), 0, &cbc);
|
||||
cbc_encrypt(reinterpret_cast<const uint8_t*>(data.data()),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(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<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()),
|
||||
key.size(), 0, &cbc);
|
||||
cbc_decrypt(reinterpret_cast<const uint8_t*>(data.data()),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(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<const uint8_t*>(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<char*>(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<const uint8_t*>(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<char*>(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<const uint8_t*>(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<char*>(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<const uint8_t*>(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<char*>(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 <std_include.hpp>
|
||||
#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<char*>(buffer), length);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void ecc::key::set(const std::string& pub_key_buffer)
|
||||
{
|
||||
this->free();
|
||||
|
||||
if (ecc_ansi_x963_import(reinterpret_cast<const uint8_t*>(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<const uint8_t*>(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<char*>(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<const uint8_t*>(message.data()), message.size(), buffer, &length, nullptr,
|
||||
find_prng("sprng"), key.get());
|
||||
|
||||
return std::string(reinterpret_cast<char*>(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<const uint8_t*>(signature.data()), signature.size(),
|
||||
reinterpret_cast<const uint8_t*>(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<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()),
|
||||
key.size(), 0, &cbc);
|
||||
cbc_encrypt(reinterpret_cast<const uint8_t*>(data.data()),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(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<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()),
|
||||
key.size(), 0, &cbc);
|
||||
cbc_decrypt(reinterpret_cast<const uint8_t*>(data.data()),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(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<const uint8_t*>(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<char*>(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<const uint8_t*>(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<char*>(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<const uint8_t*>(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<char*>(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<const uint8_t*>(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<char*>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,52 +1,52 @@
|
||||
#include <std_include.hpp>
|
||||
#include "flags.hpp"
|
||||
#include "string.hpp"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
namespace flags
|
||||
{
|
||||
void parse_flags(std::vector<std::string>& 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<std::string> 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 <std_include.hpp>
|
||||
#include "flags.hpp"
|
||||
#include "string.hpp"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
namespace flags
|
||||
{
|
||||
void parse_flags(std::vector<std::string>& 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<std::string> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -1,179 +1,179 @@
|
||||
#include <std_include.hpp>
|
||||
#include "hook.hpp"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
void hook::signature::process()
|
||||
{
|
||||
if (this->signatures_.empty()) return;
|
||||
|
||||
const auto start = reinterpret_cast<char*>(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<void*>(stub), use_jump);
|
||||
}
|
||||
|
||||
hook* hook::initialize(const DWORD place, void* stub, const bool use_jump)
|
||||
{
|
||||
return this->initialize(reinterpret_cast<void*>(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<char*>(this->place_) + 5 + *reinterpret_cast<DWORD*>((static_cast<char*>(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<char*>(this->place_);
|
||||
|
||||
*code = static_cast<char>(this->use_jump_ ? 0xE9 : 0xE8);
|
||||
|
||||
*reinterpret_cast<size_t*>(code + 1) = reinterpret_cast<size_t>(this->stub_) - (reinterpret_cast<size_t>(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<void*>(place), length);
|
||||
}
|
||||
}
|
||||
#include <std_include.hpp>
|
||||
#include "hook.hpp"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
void hook::signature::process()
|
||||
{
|
||||
if (this->signatures_.empty()) return;
|
||||
|
||||
const auto start = reinterpret_cast<char*>(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<void*>(stub), use_jump);
|
||||
}
|
||||
|
||||
hook* hook::initialize(const DWORD place, void* stub, const bool use_jump)
|
||||
{
|
||||
return this->initialize(reinterpret_cast<void*>(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<char*>(this->place_) + 5 + *reinterpret_cast<DWORD*>((static_cast<char*>(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<char*>(this->place_);
|
||||
|
||||
*code = static_cast<char>(this->use_jump_ ? 0xE9 : 0xE8);
|
||||
|
||||
*reinterpret_cast<size_t*>(code + 1) = reinterpret_cast<size_t>(this->stub_) - (reinterpret_cast<size_t>(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<void*>(place), length);
|
||||
}
|
||||
}
|
||||
|
@ -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<void(char*)> callback;
|
||||
};
|
||||
|
||||
signature(void* start, const size_t length) : start_(start), length_(length)
|
||||
{
|
||||
}
|
||||
|
||||
signature(const DWORD start, const size_t length) : signature(reinterpret_cast<void*>(start), length)
|
||||
{
|
||||
}
|
||||
|
||||
signature() : signature(0x400000, 0x800000)
|
||||
{
|
||||
}
|
||||
|
||||
void process();
|
||||
void add(const container& container);
|
||||
|
||||
private:
|
||||
void* start_;
|
||||
size_t length_;
|
||||
std::vector<container> 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<void*>(stub), use_jump)
|
||||
{
|
||||
}
|
||||
|
||||
hook(const DWORD place, void* stub, const bool use_jump = true) : hook(
|
||||
reinterpret_cast<void*>(place), stub, use_jump)
|
||||
{
|
||||
}
|
||||
|
||||
hook(const DWORD place, const DWORD stub, const bool use_jump = true) : hook(
|
||||
reinterpret_cast<void*>(place), reinterpret_cast<void*>(stub), use_jump)
|
||||
{
|
||||
}
|
||||
|
||||
hook(const DWORD place, void (*stub)(), const bool use_jump = true) : hook(
|
||||
reinterpret_cast<void*>(place), reinterpret_cast<void*>(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 <typename T>
|
||||
static void set(void* place, T value)
|
||||
{
|
||||
DWORD old_protect;
|
||||
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect);
|
||||
|
||||
*static_cast<T*>(place) = value;
|
||||
|
||||
VirtualProtect(place, sizeof(T), old_protect, &old_protect);
|
||||
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void set(const DWORD place, T value)
|
||||
{
|
||||
return set<T>(reinterpret_cast<void*>(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<void(char*)> callback;
|
||||
};
|
||||
|
||||
signature(void* start, const size_t length) : start_(start), length_(length)
|
||||
{
|
||||
}
|
||||
|
||||
signature(const DWORD start, const size_t length) : signature(reinterpret_cast<void*>(start), length)
|
||||
{
|
||||
}
|
||||
|
||||
signature() : signature(0x400000, 0x800000)
|
||||
{
|
||||
}
|
||||
|
||||
void process();
|
||||
void add(const container& container);
|
||||
|
||||
private:
|
||||
void* start_;
|
||||
size_t length_;
|
||||
std::vector<container> 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<void*>(stub), use_jump)
|
||||
{
|
||||
}
|
||||
|
||||
hook(const DWORD place, void* stub, const bool use_jump = true) : hook(
|
||||
reinterpret_cast<void*>(place), stub, use_jump)
|
||||
{
|
||||
}
|
||||
|
||||
hook(const DWORD place, const DWORD stub, const bool use_jump = true) : hook(
|
||||
reinterpret_cast<void*>(place), reinterpret_cast<void*>(stub), use_jump)
|
||||
{
|
||||
}
|
||||
|
||||
hook(const DWORD place, void (*stub)(), const bool use_jump = true) : hook(
|
||||
reinterpret_cast<void*>(place), reinterpret_cast<void*>(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 <typename T>
|
||||
static void set(void* place, T value)
|
||||
{
|
||||
DWORD old_protect;
|
||||
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect);
|
||||
|
||||
*static_cast<T*>(place) = value;
|
||||
|
||||
VirtualProtect(place, sizeof(T), old_protect, &old_protect);
|
||||
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void set(const DWORD place, T value)
|
||||
{
|
||||
return set<T>(reinterpret_cast<void*>(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_;
|
||||
};
|
||||
}
|
||||
|
220
src/utils/io.cpp
220
src/utils/io.cpp
@ -1,110 +1,110 @@
|
||||
#include <std_include.hpp>
|
||||
#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<uint32_t>(size));
|
||||
stream.read(const_cast<char*>(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<size_t>(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<std::string> list_files(const std::string& directory)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
|
||||
for (auto& file : std::experimental::filesystem::directory_iterator(directory))
|
||||
{
|
||||
files.push_back(file.path().generic_string());
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
}
|
||||
}
|
||||
#include <std_include.hpp>
|
||||
#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<uint32_t>(size));
|
||||
stream.read(const_cast<char*>(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<size_t>(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<std::string> list_files(const std::string& directory)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
|
||||
for (auto& file : std::experimental::filesystem::directory_iterator(directory))
|
||||
{
|
||||
files.push_back(file.path().generic_string());
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
414
src/utils/nt.cpp
414
src/utils/nt.cpp
@ -1,207 +1,207 @@
|
||||
#include <std_include.hpp>
|
||||
#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<LPCSTR>(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<PIMAGE_NT_HEADERS>(this->get_ptr() + this->get_dos_header()->e_lfanew);
|
||||
}
|
||||
|
||||
PIMAGE_DOS_HEADER module::get_dos_header() const
|
||||
{
|
||||
return reinterpret_cast<PIMAGE_DOS_HEADER>(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<PIMAGE_SECTION_HEADER> module::get_section_headers() const
|
||||
{
|
||||
std::vector<PIMAGE_SECTION_HEADER> 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<std::uint8_t*>(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<void*>(proc_name);
|
||||
if (!target_function) return nullptr;
|
||||
|
||||
auto* header = this->get_optional_header();
|
||||
if (!header) return nullptr;
|
||||
|
||||
auto* import_descriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(this->get_ptr() + header->DataDirectory
|
||||
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
|
||||
while (import_descriptor->Name)
|
||||
{
|
||||
if (!_stricmp(reinterpret_cast<char*>(this->get_ptr() + import_descriptor->Name), module_name.data()))
|
||||
{
|
||||
auto* original_thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->
|
||||
OriginalFirstThunk + this->get_ptr());
|
||||
auto* thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(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<char*>(ordinal_number)) ==
|
||||
target_function)
|
||||
{
|
||||
return reinterpret_cast<void**>(&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<void>("RtlAdjustPrivilege", 19, true, false, &data);
|
||||
ntdll.invoke_pascal<void>("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data);
|
||||
}
|
||||
}
|
||||
}
|
||||
#include <std_include.hpp>
|
||||
#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<LPCSTR>(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<PIMAGE_NT_HEADERS>(this->get_ptr() + this->get_dos_header()->e_lfanew);
|
||||
}
|
||||
|
||||
PIMAGE_DOS_HEADER module::get_dos_header() const
|
||||
{
|
||||
return reinterpret_cast<PIMAGE_DOS_HEADER>(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<PIMAGE_SECTION_HEADER> module::get_section_headers() const
|
||||
{
|
||||
std::vector<PIMAGE_SECTION_HEADER> 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<std::uint8_t*>(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<void*>(proc_name);
|
||||
if (!target_function) return nullptr;
|
||||
|
||||
auto* header = this->get_optional_header();
|
||||
if (!header) return nullptr;
|
||||
|
||||
auto* import_descriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(this->get_ptr() + header->DataDirectory
|
||||
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
|
||||
while (import_descriptor->Name)
|
||||
{
|
||||
if (!_stricmp(reinterpret_cast<char*>(this->get_ptr() + import_descriptor->Name), module_name.data()))
|
||||
{
|
||||
auto* original_thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->
|
||||
OriginalFirstThunk + this->get_ptr());
|
||||
auto* thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(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<char*>(ordinal_number)) ==
|
||||
target_function)
|
||||
{
|
||||
return reinterpret_cast<void**>(&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<void>("RtlAdjustPrivilege", 19, true, false, &data);
|
||||
ntdll.invoke_pascal<void>("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user