More fixes

This commit is contained in:
momo5502 2019-09-24 11:46:47 +02:00
parent 91aa9cc0b8
commit 84cba76ae3
37 changed files with 3327 additions and 3280 deletions

View File

@ -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)

View File

@ -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_;
}
}

View File

@ -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_;
}
}

View File

@ -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_;
};
}

View File

@ -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;
}
}

View File

@ -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;
};
}

View File

@ -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));

View File

@ -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);

View File

@ -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_)});
}
}
}
}

View File

@ -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;
}
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -1,3 +1,5 @@
#pragma once
namespace game
{
namespace scripting

View File

@ -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]);
}
}
}

View File

@ -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;
}
}
}
}
}

View File

@ -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;
}

View File

@ -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());
}

View File

@ -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;
}
};

View File

@ -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;
}

View File

@ -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; \
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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();
}

View File

@ -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};

View File

@ -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;
}
}

View File

@ -2,7 +2,6 @@
#include "interface.hpp"
#include "utils/memory.hpp"
#include "utils/nt.hpp"
#include <minwinbase.h>
namespace steam
{

View File

@ -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);
};
}

View File

@ -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, &reg_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, &reg_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;
}
}
}

View File

@ -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_;
};
}

View File

@ -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;
}
}
}

View File

@ -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);
};
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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_;
};
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}