Add DW emulator
This commit is contained in:
parent
fc30cb2f4f
commit
1764ff9699
@ -18,7 +18,7 @@ namespace demonware
|
||||
return this->read(1, output);
|
||||
}
|
||||
|
||||
bool bit_buffer::read_u_int32(unsigned int* output)
|
||||
bool bit_buffer::read_uint32(unsigned int* output)
|
||||
{
|
||||
if (!this->read_data_type(8))
|
||||
{
|
||||
|
@ -13,7 +13,7 @@ namespace demonware
|
||||
|
||||
bool read_bytes(unsigned int bytes, unsigned char* output);
|
||||
bool read_bool(bool* output);
|
||||
bool read_u_int32(unsigned int* output);
|
||||
bool read_uint32(unsigned int* output);
|
||||
bool read_data_type(char expected);
|
||||
|
||||
bool write_bytes(unsigned int bytes, const char* data);
|
||||
|
@ -122,7 +122,7 @@ namespace demonware
|
||||
return true;
|
||||
}
|
||||
|
||||
bool byte_buffer::read_data_type(char expected)
|
||||
bool byte_buffer::read_data_type(const char expected)
|
||||
{
|
||||
if (!this->use_data_types_) return true;
|
||||
|
||||
@ -295,4 +295,14 @@ namespace demonware
|
||||
{
|
||||
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_;
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,9 @@ namespace demonware
|
||||
bool is_using_data_types() const;
|
||||
|
||||
std::string& get_buffer();
|
||||
std::string get_remaining();
|
||||
|
||||
bool has_more_data() const;
|
||||
|
||||
private:
|
||||
std::string buffer_;
|
||||
|
@ -17,7 +17,7 @@ namespace demonware
|
||||
i_service(const i_service&) = delete;
|
||||
i_service& operator=(const i_service&) = delete;
|
||||
|
||||
typedef std::function<void(i_server*, byte_buffer*)> Callback;
|
||||
typedef std::function<void(i_server*, byte_buffer*)> callback;
|
||||
|
||||
virtual uint16_t getType() = 0;
|
||||
|
||||
@ -42,7 +42,16 @@ namespace demonware
|
||||
}
|
||||
|
||||
protected:
|
||||
std::map<uint8_t, Callback> callbacks{};
|
||||
std::map<uint8_t, callback> callbacks{};
|
||||
|
||||
template<typename Class, typename T, typename... Args>
|
||||
void register_service(const uint8_t type, T(Class::*callback)(Args ...) const)
|
||||
{
|
||||
this->callbacks[type] = [this, callback](Args... args) -> T
|
||||
{
|
||||
return (reinterpret_cast<Class*>(this)->*callback)(args...);
|
||||
};
|
||||
}
|
||||
|
||||
template<typename Class, typename T, typename... Args>
|
||||
void register_service(const uint8_t type, T(Class::*callback)(Args ...))
|
||||
@ -62,7 +71,7 @@ namespace demonware
|
||||
};
|
||||
|
||||
template<uint16_t Type>
|
||||
class i_generic_service final : public i_service
|
||||
class i_generic_service : public i_service
|
||||
{
|
||||
public:
|
||||
uint16_t getType() override { return Type; }
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include <std_include.hpp>
|
||||
#include "service_server.hpp"
|
||||
#include "module/dw.hpp"
|
||||
#include "utils/cryptography.hpp"
|
||||
|
||||
namespace demonware
|
||||
@ -41,7 +41,9 @@ namespace demonware
|
||||
result.write_int32(seed);
|
||||
|
||||
const auto iv = utils::cryptography::tiger::compute(std::string(reinterpret_cast<char*>(&seed), 4));
|
||||
//result.write(utils::cryptography::des3::encrypt(data, iv, Components::DemonWare::GetKey(true)));
|
||||
|
||||
const std::string key(reinterpret_cast<char*>(dw::get_key(true)), 24);
|
||||
result.write(utils::cryptography::des3::encrypt(data, iv, key));
|
||||
|
||||
return result.get_buffer();
|
||||
}
|
||||
@ -62,7 +64,6 @@ namespace demonware
|
||||
std::lock_guard<std::recursive_mutex> _(this->mutex_);
|
||||
|
||||
this->incoming_queue_.push(std::string(buf, len));
|
||||
//this->parsePacket(Utils::String(buf, len));
|
||||
|
||||
return len;
|
||||
}
|
||||
@ -100,7 +101,7 @@ namespace demonware
|
||||
}
|
||||
}
|
||||
|
||||
void service_server::call_handler(uint8_t type, const std::string& data)
|
||||
void service_server::call_handler(const uint8_t type, const std::string& data)
|
||||
{
|
||||
if (this->services_.find(type) != this->services_.end())
|
||||
{
|
||||
@ -117,7 +118,7 @@ namespace demonware
|
||||
if (!this->incoming_queue_.empty())
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
const std::string packet = this->incoming_queue_.front();
|
||||
const auto packet = this->incoming_queue_.front();
|
||||
this->incoming_queue_.pop();
|
||||
|
||||
this->parse_packet(packet);
|
||||
@ -131,7 +132,7 @@ namespace demonware
|
||||
|
||||
try
|
||||
{
|
||||
while (!packet.empty())
|
||||
while (buffer.has_more_data())
|
||||
{
|
||||
int size;
|
||||
buffer.read_int32(&size);
|
||||
@ -170,7 +171,10 @@ namespace demonware
|
||||
p_buffer.read_int32(&iv);
|
||||
|
||||
auto iv_hash = utils::cryptography::tiger::compute(std::string(reinterpret_cast<char*>(&iv), 4));
|
||||
//pBuffer.get_buffer() = utils::cryptography::des3::decrypt(pBuffer.get_buffer(), iv_hash, Components::DemonWare::GetKey(false));
|
||||
|
||||
const std::string key(reinterpret_cast<char*>(dw::get_key(false)), 24);
|
||||
p_buffer = byte_buffer{ utils::cryptography::des3::decrypt(p_buffer.get_remaining(), iv_hash, key) };
|
||||
p_buffer.set_use_data_types(false);
|
||||
|
||||
int checksum;
|
||||
p_buffer.read_int32(&checksum);
|
||||
@ -181,7 +185,7 @@ namespace demonware
|
||||
printf("DW: Handling message of type %d (encrypted: %d)\n", type, enc);
|
||||
|
||||
this->reply_sent_ = false;
|
||||
this->call_handler(type, p_buffer.get_buffer());
|
||||
this->call_handler(type, p_buffer.get_remaining());
|
||||
|
||||
if (!this->reply_sent_ && type != 7)
|
||||
{
|
||||
|
29
src/game/demonware/services/bdDML.cpp
Normal file
29
src/game/demonware/services/bdDML.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
#include <std_include.hpp>
|
||||
#include "bdDML.hpp"
|
||||
#include "../data_types.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdDML::bdDML()
|
||||
{
|
||||
this->register_service(2, &bdDML::get_user_raw_data);
|
||||
}
|
||||
|
||||
void bdDML::get_user_raw_data(i_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
auto result = new bdDMLRawData;
|
||||
result->country_code = "US";
|
||||
result->country_code = "'Murica";
|
||||
result->region = "New York";
|
||||
result->city = "New York";
|
||||
result->latitude = 0;
|
||||
result->longitude = 0;
|
||||
|
||||
result->asn = 0x2119;
|
||||
result->timezone = "+01:00";
|
||||
|
||||
auto reply = server->create_reply(this->get_sub_type());
|
||||
reply->add(result);
|
||||
reply->send();
|
||||
}
|
||||
}
|
14
src/game/demonware/services/bdDML.hpp
Normal file
14
src/game/demonware/services/bdDML.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "../i_service.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdDML final : public i_generic_service<27>
|
||||
{
|
||||
public:
|
||||
bdDML();
|
||||
|
||||
private:
|
||||
void get_user_raw_data(i_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
26
src/game/demonware/services/bdLSGHello.cpp
Normal file
26
src/game/demonware/services/bdLSGHello.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include <std_include.hpp>
|
||||
#include "bdLSGHello.hpp"
|
||||
#include "module/dw.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
void bdLSGHello::call_service(i_server* server, const std::string& data)
|
||||
{
|
||||
bit_buffer buffer(data);
|
||||
|
||||
bool more_data;
|
||||
buffer.set_use_data_types(false);
|
||||
buffer.read_bool(&more_data);
|
||||
buffer.set_use_data_types(true);
|
||||
|
||||
uint32_t seed, title_id;
|
||||
buffer.read_uint32(&title_id);
|
||||
buffer.read_uint32(&seed);
|
||||
|
||||
uint8_t ticket[128];
|
||||
buffer.read_bytes(sizeof(ticket), ticket);
|
||||
|
||||
dw::set_key(true, ticket);
|
||||
dw::set_key(false, ticket);
|
||||
}
|
||||
}
|
11
src/game/demonware/services/bdLSGHello.hpp
Normal file
11
src/game/demonware/services/bdLSGHello.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "../i_service.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdLSGHello final : public i_generic_service<7>
|
||||
{
|
||||
public:
|
||||
void call_service(i_server* server, const std::string& data) override;
|
||||
};
|
||||
}
|
60
src/game/demonware/services/bdSteamAuth.cpp
Normal file
60
src/game/demonware/services/bdSteamAuth.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include <std_include.hpp>
|
||||
#include "bdSteamAuth.hpp"
|
||||
#include "game/structs.hpp"
|
||||
#include "steam/steam.hpp"
|
||||
#include "utils/cryptography.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
void bdSteamAuth::call_service(i_server* server, const std::string& data)
|
||||
{
|
||||
bit_buffer buffer(data);
|
||||
|
||||
bool more_data;
|
||||
buffer.set_use_data_types(false);
|
||||
buffer.read_bool(&more_data);
|
||||
buffer.set_use_data_types(true);
|
||||
|
||||
uint32_t seed, title_id, ticket_size;
|
||||
buffer.read_uint32(&seed);
|
||||
buffer.read_uint32(&title_id);
|
||||
buffer.read_uint32(&ticket_size);
|
||||
|
||||
uint8_t ticket[1024];
|
||||
buffer.read_bytes(std::min(ticket_size, static_cast<uint32_t>(sizeof(ticket))), ticket);
|
||||
|
||||
game::native::bdAuthTicket auth_ticket{};
|
||||
std::memset(&auth_ticket, 0xA, sizeof auth_ticket);
|
||||
|
||||
auth_ticket.m_magicNumber = 0x0EFBDADDE;
|
||||
auth_ticket.m_type = 0;
|
||||
auth_ticket.m_titleID = title_id;
|
||||
auth_ticket.m_userID = steam::SteamUser()->GetSteamID().bits;
|
||||
|
||||
auto key = utils::cryptography::tiger::compute("Open-IW5");
|
||||
|
||||
strcpy_s(auth_ticket.m_username, "Open-IW5 User");
|
||||
std::memcpy(auth_ticket.m_sessionKey, key.data(), 24);
|
||||
auth_ticket.m_timeIssued = static_cast<uint32_t>(time(nullptr));
|
||||
|
||||
uint8_t lsg_ticket[128];
|
||||
ZeroMemory(&lsg_ticket, sizeof lsg_ticket);
|
||||
std::memcpy(lsg_ticket, key.data(), 24);
|
||||
|
||||
const auto iv = utils::cryptography::tiger::compute(std::string(reinterpret_cast<char*>(&seed), 4));
|
||||
|
||||
const std::string enc_key (reinterpret_cast<char*>(&ticket[32]), 24);
|
||||
auto enc_ticket = utils::cryptography::des3::encrypt(std::string(reinterpret_cast<char*>(&auth_ticket), sizeof(auth_ticket)), iv,enc_key );
|
||||
|
||||
bit_buffer response;
|
||||
response.set_use_data_types(false);
|
||||
response.write_bool(false);
|
||||
response.write_uint32(700);
|
||||
response.write_uint32(seed);
|
||||
response.write_bytes(enc_ticket.size(), enc_ticket.data());
|
||||
response.write_bytes(sizeof(lsg_ticket), lsg_ticket);
|
||||
|
||||
auto reply = server->create_message(29);
|
||||
reply->send(&response, false);
|
||||
}
|
||||
}
|
11
src/game/demonware/services/bdSteamAuth.hpp
Normal file
11
src/game/demonware/services/bdSteamAuth.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "../i_service.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdSteamAuth final : public i_generic_service<28>
|
||||
{
|
||||
public:
|
||||
void call_service(i_server* server, const std::string& data) override;
|
||||
};
|
||||
}
|
266
src/game/demonware/services/bdStorage.cpp
Normal file
266
src/game/demonware/services/bdStorage.cpp
Normal file
@ -0,0 +1,266 @@
|
||||
#include <std_include.hpp>
|
||||
#include "bdStorage.hpp"
|
||||
#include "../data_types.hpp"
|
||||
#include "utils/cryptography.hpp"
|
||||
#include "utils/nt.hpp"
|
||||
#include "utils/io.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdStorage::bdStorage()
|
||||
{
|
||||
this->register_service(1, &bdStorage::set_legacy_user_file);
|
||||
this->register_service(3, &bdStorage::get_legacy_user_file);
|
||||
this->register_service(5, &bdStorage::list_legacy_user_files);
|
||||
this->register_service(6, &bdStorage::list_publisher_files);
|
||||
this->register_service(7, &bdStorage::get_publisher_file);
|
||||
this->register_service(10, &bdStorage::set_user_file);
|
||||
this->register_service(11, &bdStorage::delete_user_file);
|
||||
this->register_service(12, &bdStorage::get_user_file);
|
||||
|
||||
this->map_publisher_resource("heatmap\\.raw", DW_HEATMAP);
|
||||
this->map_publisher_resource("motd-.*\\.txt", DW_MOTD);
|
||||
this->map_publisher_resource("online_mp\\.img", DW_IMG);
|
||||
this->map_publisher_resource("online_[Tt][Uu][0-9]+_mp_.+\\.wad", DW_WAD);
|
||||
this->map_publisher_resource("playlists(_.+)?\\.aggr", DW_PLAYLIST);
|
||||
this->map_publisher_resource("social_[Tt][Uu][0-9]+\\.cfg", DW_CONFIG);
|
||||
this->map_publisher_resource("iotd-.*\\.txt", DW_IOTD_TXT);
|
||||
this->map_publisher_resource("iotd-.*\\.jpg", DW_IOTD_IMG);
|
||||
}
|
||||
|
||||
void bdStorage::map_publisher_resource(const std::string& expression, const INT id)
|
||||
{
|
||||
const auto res = FindResource(::utils::nt::module(), MAKEINTRESOURCE(id), RT_RCDATA);
|
||||
if (!res) return;
|
||||
|
||||
const auto handle = LoadResource(nullptr, res);
|
||||
if (!handle) return;
|
||||
|
||||
std::string data(LPSTR(LockResource(handle)), SizeofResource(nullptr, res));
|
||||
|
||||
publisher_resources_.emplace_back(std::regex{expression}, data);
|
||||
}
|
||||
|
||||
bool bdStorage::load_publisher_resource(const std::string& name, std::string& buffer)
|
||||
{
|
||||
for(const auto& resource : this->publisher_resources_)
|
||||
{
|
||||
if (std::regex_match(name, resource.first))
|
||||
{
|
||||
buffer = resource.second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
printf("DW: Missing publisher file: %s\n", name.data());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string bdStorage::get_user_file_path(const std::string& name)
|
||||
{
|
||||
return "players2/user/" + name;
|
||||
}
|
||||
|
||||
void bdStorage::set_legacy_user_file(i_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
bool priv;
|
||||
std::string filename, data;
|
||||
|
||||
buffer->read_string(&filename);
|
||||
buffer->read_bool(&priv);
|
||||
buffer->read_blob(&data);
|
||||
|
||||
printf("DW: Storing user file: %s\n", filename.data());
|
||||
|
||||
const auto path = get_user_file_path(filename);
|
||||
utils::io::write_file(path, data);
|
||||
|
||||
auto info = new bdFileInfo;
|
||||
|
||||
info->file_id = *reinterpret_cast<const uint64_t*>(utils::cryptography::sha1::compute(filename).data());
|
||||
info->filename = filename;
|
||||
info->create_time = uint32_t(time(nullptr));
|
||||
info->modified_time = info->create_time;
|
||||
info->file_size = uint32_t(data.size());
|
||||
info->owner_id = 0;
|
||||
info->priv = priv;
|
||||
|
||||
auto reply = server->create_reply(this->get_sub_type());
|
||||
reply->add(info);
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStorage::get_legacy_user_file(i_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
std::string filename, data;
|
||||
buffer->read_string(&filename);
|
||||
|
||||
printf("DW: Loading user file: %s\n", filename.data());
|
||||
|
||||
const auto path = get_user_file_path(filename);
|
||||
if(utils::io::read_file(path, &data))
|
||||
{
|
||||
auto reply = server->create_reply(this->get_sub_type());
|
||||
reply->add(new bdFileData(data));
|
||||
reply->send();
|
||||
}
|
||||
else
|
||||
{
|
||||
server->create_reply(this->get_sub_type(), game::native::BD_NO_FILE)->send();
|
||||
}
|
||||
}
|
||||
|
||||
void bdStorage::list_legacy_user_files(i_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
uint64_t unk;
|
||||
uint32_t date;
|
||||
uint16_t num_results, offset;
|
||||
std::string filename, data;
|
||||
|
||||
buffer->read_uint64(&unk);
|
||||
buffer->read_uint32(&date);
|
||||
buffer->read_uint16(&num_results);
|
||||
buffer->read_uint16(&offset);
|
||||
buffer->read_string(&filename);
|
||||
|
||||
auto reply = server->create_reply(this->get_sub_type());
|
||||
|
||||
const auto path = get_user_file_path(filename);
|
||||
if(utils::io::read_file(path, &data))
|
||||
{
|
||||
auto* info = new bdFileInfo;
|
||||
|
||||
info->file_id = *reinterpret_cast<const uint64_t*>(utils::cryptography::sha1::compute(filename).data());
|
||||
info->filename = filename;
|
||||
info->create_time = 0;
|
||||
info->modified_time = info->create_time;
|
||||
info->file_size = uint32_t(data.size());
|
||||
info->owner_id = 0;
|
||||
info->priv = false;
|
||||
|
||||
reply->add(info);
|
||||
}
|
||||
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStorage::list_publisher_files(i_server* server, byte_buffer* buffer)
|
||||
{
|
||||
uint32_t date;
|
||||
uint16_t num_results, offset;
|
||||
std::string filename, data;
|
||||
|
||||
buffer->read_uint32(&date);
|
||||
buffer->read_uint16(&num_results);
|
||||
buffer->read_uint16(&offset);
|
||||
buffer->read_string(&filename);
|
||||
|
||||
auto reply = server->create_reply(this->get_sub_type());
|
||||
|
||||
if (this->load_publisher_resource(filename, data))
|
||||
{
|
||||
auto* info = new bdFileInfo;
|
||||
|
||||
info->file_id = *reinterpret_cast<const uint64_t*>(utils::cryptography::sha1::compute(filename).data());
|
||||
info->filename = filename;
|
||||
info->create_time = 0;
|
||||
info->modified_time = info->create_time;
|
||||
info->file_size = uint32_t(data.size());
|
||||
info->owner_id = 0;
|
||||
info->priv = false;
|
||||
|
||||
reply->add(info);
|
||||
}
|
||||
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStorage::get_publisher_file(i_server* server, byte_buffer* buffer)
|
||||
{
|
||||
std::string filename;
|
||||
buffer->read_string(&filename);
|
||||
|
||||
printf("DW: Loading publisher file: %s\n", filename.data());
|
||||
|
||||
std::string data;
|
||||
if (this->load_publisher_resource(filename, data))
|
||||
{
|
||||
auto reply = server->create_reply(this->get_sub_type());
|
||||
reply->add(new bdFileData(data));
|
||||
reply->send();
|
||||
}
|
||||
else
|
||||
{
|
||||
server->create_reply(this->get_sub_type(), game::native::BD_NO_FILE)->send();
|
||||
}
|
||||
}
|
||||
|
||||
void bdStorage::delete_user_file(i_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
uint64_t owner;
|
||||
std::string game, filename;
|
||||
|
||||
buffer->read_string(&game);
|
||||
buffer->read_string(&filename);
|
||||
buffer->read_uint64(&owner);
|
||||
|
||||
// Really remove the file?
|
||||
|
||||
auto reply = server->create_reply(this->get_sub_type());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStorage::set_user_file(i_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
bool priv;
|
||||
uint64_t owner;
|
||||
std::string game, filename, data;
|
||||
|
||||
buffer->read_string(&game);
|
||||
buffer->read_string(&filename);
|
||||
buffer->read_bool(&priv);
|
||||
buffer->read_blob(&data);
|
||||
buffer->read_uint64(&owner);
|
||||
|
||||
const auto path = get_user_file_path(filename);
|
||||
utils::io::write_file(path, data);
|
||||
|
||||
auto info = new bdFileInfo;
|
||||
|
||||
info->file_id = *reinterpret_cast<const uint64_t*>(utils::cryptography::sha1::compute(filename).data());
|
||||
info->filename = filename;
|
||||
info->create_time = uint32_t(time(nullptr));
|
||||
info->modified_time = info->create_time;
|
||||
info->file_size = uint32_t(data.size());
|
||||
info->owner_id = owner;
|
||||
info->priv = priv;
|
||||
|
||||
auto reply = server->create_reply(this->get_sub_type());
|
||||
reply->add(info);
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStorage::get_user_file(i_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
uint64_t owner;
|
||||
std::string game, filename, platform, data;
|
||||
|
||||
buffer->read_string(&game);
|
||||
buffer->read_string(&filename);
|
||||
buffer->read_uint64(&owner);
|
||||
buffer->read_string(&platform);
|
||||
|
||||
const auto path = get_user_file_path(filename);
|
||||
if(utils::io::read_file(path, &data))
|
||||
{
|
||||
auto reply = server->create_reply(this->get_sub_type());
|
||||
reply->add(new bdFileData(data));
|
||||
reply->send();
|
||||
}
|
||||
else
|
||||
{
|
||||
server->create_reply(this->get_sub_type(), game::native::BD_NO_FILE)->send();
|
||||
}
|
||||
}
|
||||
}
|
28
src/game/demonware/services/bdStorage.hpp
Normal file
28
src/game/demonware/services/bdStorage.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "../i_service.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdStorage final : public i_generic_service<10>
|
||||
{
|
||||
public:
|
||||
bdStorage();
|
||||
|
||||
private:
|
||||
std::vector<std::pair<std::regex, std::string>> publisher_resources_;
|
||||
|
||||
void set_legacy_user_file(i_server* server, byte_buffer* buffer) const;
|
||||
void get_legacy_user_file(i_server* server, byte_buffer* buffer) const;
|
||||
void list_legacy_user_files(i_server* server, byte_buffer* buffer) const;
|
||||
void list_publisher_files(i_server* server, byte_buffer* buffer);
|
||||
void get_publisher_file(i_server* server, byte_buffer* buffer);
|
||||
void delete_user_file(i_server* server, byte_buffer* buffer) const;
|
||||
void set_user_file(i_server* server, byte_buffer* buffer) const;
|
||||
void get_user_file(i_server* server, byte_buffer* buffer) const;
|
||||
|
||||
void map_publisher_resource(const std::string& expression, INT id);
|
||||
bool load_publisher_resource(const std::string& name, std::string& buffer);
|
||||
|
||||
static std::string get_user_file_path(const std::string& name);
|
||||
};
|
||||
}
|
21
src/game/demonware/services/bdTitleUtilities.cpp
Normal file
21
src/game/demonware/services/bdTitleUtilities.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include <std_include.hpp>
|
||||
#include "bdTitleUtilities.hpp"
|
||||
#include "../data_types.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdTitleUtilities::bdTitleUtilities()
|
||||
{
|
||||
this->register_service(6, &bdTitleUtilities::get_server_time);
|
||||
}
|
||||
|
||||
void bdTitleUtilities::get_server_time(i_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
const auto time_result = new bdTimeStamp;
|
||||
time_result->unix_time = uint32_t(time(nullptr));
|
||||
|
||||
auto reply = server->create_reply(this->get_sub_type());
|
||||
reply->add(time_result);
|
||||
reply->send();
|
||||
}
|
||||
}
|
14
src/game/demonware/services/bdTitleUtilities.hpp
Normal file
14
src/game/demonware/services/bdTitleUtilities.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "../i_service.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdTitleUtilities final : public i_generic_service<12>
|
||||
{
|
||||
public:
|
||||
bdTitleUtilities();
|
||||
|
||||
private:
|
||||
void get_server_time(i_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#include <std_include.hpp>
|
||||
#include <utility>
|
||||
#include "stun_server.hpp"
|
||||
#include "module/dw.hpp"
|
||||
#include "utils/cryptography.hpp"
|
||||
#include "byte_buffer.hpp"
|
||||
|
||||
@ -28,7 +28,7 @@ namespace demonware
|
||||
buffer.write_uint32(ip); // external ip
|
||||
buffer.write_uint16(3074); // port
|
||||
|
||||
//Components::DemonWare::SendDatagramPacket(s, buffer, to, tolen);
|
||||
dw::send_datagram_packet(s, buffer.get_buffer(), to, tolen);
|
||||
}
|
||||
|
||||
void stun_server::nat_discovery(SOCKET s, const sockaddr* to, int tolen) const
|
||||
@ -45,7 +45,7 @@ namespace demonware
|
||||
buffer.write_uint32(this->get_address()); // server ip
|
||||
buffer.write_uint16(3074); // server port
|
||||
|
||||
//Components::DemonWare::SendDatagramPacket(s, buffer, to, tolen);
|
||||
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
|
||||
|
@ -4,6 +4,346 @@ namespace game
|
||||
{
|
||||
namespace native
|
||||
{
|
||||
enum bdLobbyErrorCode : uint32_t
|
||||
{
|
||||
BD_NO_ERROR = 0x0,
|
||||
BD_TOO_MANY_TASKS = 0x1,
|
||||
BD_NOT_CONNECTED = 0x2,
|
||||
BD_SEND_FAILED = 0x3,
|
||||
BD_HANDLE_TASK_FAILED = 0x4,
|
||||
BD_START_TASK_FAILED = 0x5,
|
||||
BD_RESULT_EXCEEDS_BUFFER_SIZE = 0x64,
|
||||
BD_ACCESS_DENIED = 0x65,
|
||||
BD_EXCEPTION_IN_DB = 0x66,
|
||||
BD_MALFORMED_TASK_HEADER = 0x67,
|
||||
BD_INVALID_ROW = 0x68,
|
||||
BD_EMPTY_ARG_LIST = 0x69,
|
||||
BD_PARAM_PARSE_ERROR = 0x6A,
|
||||
BD_PARAM_MISMATCHED_TYPE = 0x6B,
|
||||
BD_SERVICE_NOT_AVAILABLE = 0x6C,
|
||||
BD_CONNECTION_RESET = 0x6D,
|
||||
BD_INVALID_USER_ID = 0x6E,
|
||||
BD_LOBBY_PROTOCOL_VERSION_FAILURE = 0x6F,
|
||||
BD_LOBBY_INTERNAL_FAILURE = 0x70,
|
||||
BD_LOBBY_PROTOCOL_ERROR = 0x71,
|
||||
BD_LOBBY_FAILED_TO_DECODE_UTF8 = 0x72,
|
||||
BD_LOBBY_ASCII_EXPECTED = 0x73,
|
||||
BD_ASYNCHRONOUS_ERROR = 0xC8,
|
||||
BD_STREAMING_COMPLETE = 0xC9,
|
||||
BD_MEMBER_NO_PROPOSAL = 0x12C,
|
||||
BD_TEAMNAME_ALREADY_EXISTS = 0x12D,
|
||||
BD_MAX_TEAM_MEMBERSHIPS_LIMITED = 0x12E,
|
||||
BD_MAX_TEAM_OWNERSHIPS_LIMITED = 0x12F,
|
||||
BD_NOT_A_TEAM_MEMBER = 0x130,
|
||||
BD_INVALID_TEAM_ID = 0x131,
|
||||
BD_INVALID_TEAM_NAME = 0x132,
|
||||
BD_NOT_A_TEAM_OWNER = 0x133,
|
||||
BD_NOT_AN_ADMIN_OR_OWNER = 0x134,
|
||||
BD_MEMBER_PROPOSAL_EXISTS = 0x135,
|
||||
BD_MEMBER_EXISTS = 0x136,
|
||||
BD_TEAM_FULL = 0x137,
|
||||
BD_VULGAR_TEAM_NAME = 0x138,
|
||||
BD_TEAM_USERID_BANNED = 0x139,
|
||||
BD_TEAM_EMPTY = 0x13A,
|
||||
BD_INVALID_TEAM_PROFILE_QUERY_ID = 0x13B,
|
||||
BD_TEAMNAME_TOO_SHORT = 0x13C,
|
||||
BD_UNIQUE_PROFILE_DATA_EXISTS_ALREADY = 0x13D,
|
||||
BD_INVALID_LEADERBOARD_ID = 0x190,
|
||||
BD_INVALID_STATS_SET = 0x191,
|
||||
BD_EMPTY_STATS_SET_IGNORED = 0x193,
|
||||
BD_NO_DIRECT_ACCESS_TO_ARBITRATED_LBS = 0x194,
|
||||
BD_STATS_WRITE_PERMISSION_DENIED = 0x195,
|
||||
BD_STATS_WRITE_TYPE_DATA_TYPE_MISMATCH = 0x196,
|
||||
BD_NO_STATS_FOR_USER = 0x197,
|
||||
BD_INVALID_ACCESS_TO_UNRANKED_LB = 0x198,
|
||||
BD_INVALID_EXTERNAL_TITLE_ID = 0x199,
|
||||
BD_DIFFERENT_LEADERBOARD_SCHEMAS = 0x19A,
|
||||
BD_TOO_MANY_LEADERBOARDS_REQUESTED = 0x19B,
|
||||
BD_ENTITLEMENTS_ERROR = 0x19C,
|
||||
BD_ENTITLEMENTS_INVALID_TITLEID = 0x19D,
|
||||
BD_ENTITLEMENTS_INVALID_LEADERBOARDID = 0x19E,
|
||||
BD_ENTITLEMENTS_INVALID_GET_MODE_FOR_TITLE = 0x19F,
|
||||
BD_ENTITLEMENTS_URL_CONNECTION_ERROR = 0x1A0,
|
||||
BD_ENTITLEMENTS_CONFIG_ERROR = 0x1A1,
|
||||
BD_ENTITLEMENTS_NAMED_PARENT_ERROR = 0x1A2,
|
||||
BD_ENTITLEMENTS_NAMED_KEY_ERROR = 0x1A3,
|
||||
BD_TOO_MANY_ENTITY_IDS_REQUESTED = 0x1A4,
|
||||
BD_STATS_READ_FAILED = 0x1A5,
|
||||
BD_INVALID_TITLE_ID = 0x1F4,
|
||||
BD_MESSAGING_INVALID_MAIL_ID = 0x258,
|
||||
BD_SELF_BLOCK_NOT_ALLOWED = 0x259,
|
||||
BD_GLOBAL_MESSAGE_ACCESS_DENIED = 0x25A,
|
||||
BD_GLOBAL_MESSAGES_USER_LIMIT_EXCEEDED = 0x25B,
|
||||
BD_MESSAGING_SENDER_DOES_NOT_EXIST = 0x25C,
|
||||
BD_AUTH_NO_ERROR = 0x2BC,
|
||||
BD_AUTH_BAD_REQUEST = 0x2BD,
|
||||
BD_AUTH_SERVER_CONFIG_ERROR = 0x2BE,
|
||||
BD_AUTH_BAD_TITLE_ID = 0x2BF,
|
||||
BD_AUTH_BAD_ACCOUNT = 0x2C0,
|
||||
BD_AUTH_ILLEGAL_OPERATION = 0x2C1,
|
||||
BD_AUTH_INCORRECT_LICENSE_CODE = 0x2C2,
|
||||
BD_AUTH_CREATE_USERNAME_EXISTS = 0x2C3,
|
||||
BD_AUTH_CREATE_USERNAME_ILLEGAL = 0x2C4,
|
||||
BD_AUTH_CREATE_USERNAME_VULGAR = 0x2C5,
|
||||
BD_AUTH_CREATE_MAX_ACC_EXCEEDED = 0x2C6,
|
||||
BD_AUTH_MIGRATE_NOT_SUPPORTED = 0x2C7,
|
||||
BD_AUTH_TITLE_DISABLED = 0x2C8,
|
||||
BD_AUTH_ACCOUNT_EXPIRED = 0x2C9,
|
||||
BD_AUTH_ACCOUNT_LOCKED = 0x2CA,
|
||||
BD_AUTH_UNKNOWN_ERROR = 0x2CB,
|
||||
BD_AUTH_INCORRECT_PASSWORD = 0x2CC,
|
||||
BD_AUTH_IP_NOT_IN_ALLOWED_RANGE = 0x2CD,
|
||||
BD_AUTH_WII_TOKEN_VERIFICATION_FAILED = 0x2CE,
|
||||
BD_AUTH_WII_AUTHENTICATION_FAILED = 0x2CF,
|
||||
BD_AUTH_IP_KEY_LIMIT_REACHED = 0x2D0,
|
||||
BD_AUTH_INVALID_GSPID = 0x2D1,
|
||||
BD_AUTH_INVALID_IP_RANGE_ID = 0x2D2,
|
||||
BD_AUTH_3DS_TOKEN_VERIFICATION_FAILED = 0x2D1,
|
||||
BD_AUTH_3DS_AUTHENTICATION_FAILED = 0x2D2,
|
||||
BD_AUTH_STEAM_APP_ID_MISMATCH = 0x2D3,
|
||||
BD_AUTH_ABACCOUNTS_APP_ID_MISMATCH = 0x2D4,
|
||||
BD_AUTH_CODO_USERNAME_NOT_SET = 0x2D5,
|
||||
BD_AUTH_WIIU_TOKEN_VERIFICATION_FAILED = 0x2D6,
|
||||
BD_AUTH_WIIU_AUTHENTICATION_FAILED = 0x2D7,
|
||||
BD_AUTH_CODO_USERNAME_NOT_BASE64 = 0x2D8,
|
||||
BD_AUTH_CODO_USERNAME_NOT_UTF8 = 0x2D9,
|
||||
BD_AUTH_TENCENT_TICKET_EXPIRED = 0x2DA,
|
||||
BD_AUTH_PS3_SERVICE_ID_MISMATCH = 0x2DB,
|
||||
BD_AUTH_CODOID_NOT_WHITELISTED = 0x2DC,
|
||||
BD_AUTH_PLATFORM_TOKEN_ERROR = 0x2DD,
|
||||
BD_AUTH_JSON_FORMAT_ERROR = 0x2DE,
|
||||
BD_AUTH_REPLY_CONTENT_ERROR = 0x2DF,
|
||||
BD_AUTH_THIRD_PARTY_TOKEN_EXPIRED = 0x2E0,
|
||||
BD_AUTH_CONTINUING = 0x2E1,
|
||||
BD_AUTH_PLATFORM_DEVICE_ID_ERROR = 0x2E4,
|
||||
BD_NO_PROFILE_INFO_EXISTS = 0x320,
|
||||
BD_FRIENDSHIP_NOT_REQUSTED = 0x384,
|
||||
BD_NOT_A_FRIEND = 0x385,
|
||||
BD_SELF_FRIENDSHIP_NOT_ALLOWED = 0x387,
|
||||
BD_FRIENDSHIP_EXISTS = 0x388,
|
||||
BD_PENDING_FRIENDSHIP_EXISTS = 0x389,
|
||||
BD_USERID_BANNED = 0x38A,
|
||||
BD_FRIENDS_FULL = 0x38C,
|
||||
BD_FRIENDS_NO_RICH_PRESENCE = 0x38D,
|
||||
BD_RICH_PRESENCE_TOO_LARGE = 0x38E,
|
||||
BD_NO_FILE = 0x3E8,
|
||||
BD_PERMISSION_DENIED = 0x3E9,
|
||||
BD_FILESIZE_LIMIT_EXCEEDED = 0x3EA,
|
||||
BD_FILENAME_MAX_LENGTH_EXCEEDED = 0x3EB,
|
||||
BD_EXTERNAL_STORAGE_SERVICE_ERROR = 0x3EC,
|
||||
BD_CHANNEL_DOES_NOT_EXIST = 0x44D,
|
||||
BD_CHANNEL_ALREADY_SUBSCRIBED = 0x44E,
|
||||
BD_CHANNEL_NOT_SUBSCRIBED = 0x44F,
|
||||
BD_CHANNEL_FULL = 0x450,
|
||||
BD_CHANNEL_SUBSCRIPTIONS_FULL = 0x451,
|
||||
BD_CHANNEL_NO_SELF_WHISPERING = 0x452,
|
||||
BD_CHANNEL_ADMIN_REQUIRED = 0x453,
|
||||
BD_CHANNEL_TARGET_NOT_SUBSCRIBED = 0x454,
|
||||
BD_CHANNEL_REQUIRES_PASSWORD = 0x455,
|
||||
BD_CHANNEL_TARGET_IS_SELF = 0x456,
|
||||
BD_CHANNEL_PUBLIC_BAN_NOT_ALLOWED = 0x457,
|
||||
BD_CHANNEL_USER_BANNED = 0x458,
|
||||
BD_CHANNEL_PUBLIC_PASSWORD_NOT_ALLOWED = 0x459,
|
||||
BD_CHANNEL_PUBLIC_KICK_NOT_ALLOWED = 0x45A,
|
||||
BD_CHANNEL_MUTED = 0x45B,
|
||||
BD_EVENT_DESC_TRUNCATED = 0x4B0,
|
||||
BD_CONTENT_UNLOCK_UNKNOWN_ERROR = 0x514,
|
||||
BD_UNLOCK_KEY_INVALID = 0x515,
|
||||
BD_UNLOCK_KEY_ALREADY_USED_UP = 0x516,
|
||||
BD_SHARED_UNLOCK_LIMIT_REACHED = 0x517,
|
||||
BD_DIFFERENT_HARDWARE_ID = 0x518,
|
||||
BD_INVALID_CONTENT_OWNER = 0x519,
|
||||
BD_CONTENT_UNLOCK_INVALID_USER = 0x51A,
|
||||
BD_CONTENT_UNLOCK_INVALID_CATEGORY = 0x51B,
|
||||
BD_KEY_ARCHIVE_INVALID_WRITE_TYPE = 0x5DC,
|
||||
BD_KEY_ARCHIVE_EXCEEDED_MAX_IDS_PER_REQUEST = 0x5DD,
|
||||
BD_BANDWIDTH_TEST_TRY_AGAIN = 0x712,
|
||||
BD_BANDWIDTH_TEST_STILL_IN_PROGRESS = 0x713,
|
||||
BD_BANDWIDTH_TEST_NOT_PROGRESS = 0x714,
|
||||
BD_BANDWIDTH_TEST_SOCKET_ERROR = 0x715,
|
||||
BD_INVALID_SESSION_NONCE = 0x76D,
|
||||
BD_ARBITRATION_FAILURE = 0x76F,
|
||||
BD_ARBITRATION_USER_NOT_REGISTERED = 0x771,
|
||||
BD_ARBITRATION_NOT_CONFIGURED = 0x772,
|
||||
BD_CONTENTSTREAMING_FILE_NOT_AVAILABLE = 0x7D0,
|
||||
BD_CONTENTSTREAMING_STORAGE_SPACE_EXCEEDED = 0x7D1,
|
||||
BD_CONTENTSTREAMING_NUM_FILES_EXCEEDED = 0x7D2,
|
||||
BD_CONTENTSTREAMING_UPLOAD_BANDWIDTH_EXCEEDED = 0x7D3,
|
||||
BD_CONTENTSTREAMING_FILENAME_MAX_LENGTH_EXCEEDED = 0x7D4,
|
||||
BD_CONTENTSTREAMING_MAX_THUMB_DATA_SIZE_EXCEEDED = 0x7D5,
|
||||
BD_CONTENTSTREAMING_DOWNLOAD_BANDWIDTH_EXCEEDED = 0x7D6,
|
||||
BD_CONTENTSTREAMING_NOT_ENOUGH_DOWNLOAD_BUFFER_SPACE = 0x7D7,
|
||||
BD_CONTENTSTREAMING_SERVER_NOT_CONFIGURED = 0x7D8,
|
||||
BD_CONTENTSTREAMING_INVALID_APPLE_RECEIPT = 0x7DA,
|
||||
BD_CONTENTSTREAMING_APPLE_STORE_NOT_AVAILABLE = 0x7DB,
|
||||
BD_CONTENTSTREAMING_APPLE_RECEIPT_FILENAME_MISMATCH = 0x7DC,
|
||||
BD_CONTENTSTREAMING_HTTP_ERROR = 0x7E4,
|
||||
BD_CONTENTSTREAMING_FAILED_TO_START_HTTP = 0x7E5,
|
||||
BD_CONTENTSTREAMING_LOCALE_INVALID = 0x7E6,
|
||||
BD_CONTENTSTREAMING_LOCALE_MISSING = 0x7E7,
|
||||
BD_VOTERANK_ERROR_EMPTY_RATING_SUBMISSION = 0x7EE,
|
||||
BD_VOTERANK_ERROR_MAX_VOTES_EXCEEDED = 0x7EF,
|
||||
BD_VOTERANK_ERROR_INVALID_RATING = 0x7F0,
|
||||
BD_MAX_NUM_TAGS_EXCEEDED = 0x82A,
|
||||
BD_TAGGED_COLLECTION_DOES_NOT_EXIST = 0x82B,
|
||||
BD_EMPTY_TAG_ARRAY = 0x82C,
|
||||
BD_INVALID_QUERY_ID = 0x834,
|
||||
BD_NO_ENTRY_TO_UPDATE = 0x835,
|
||||
BD_SESSION_INVITE_EXISTS = 0x836,
|
||||
BD_INVALID_SESSION_ID = 0x837,
|
||||
BD_ATTACHMENT_TOO_LARGE = 0x838,
|
||||
BD_INVALID_GROUP_ID = 0xAF0,
|
||||
BD_MAIL_INVALID_MAIL_ID_ERROR = 0xB55,
|
||||
BD_UCD_SERVICE_ERROR = 0xC80,
|
||||
BD_UCD_SERVICE_DISABLED = 0xC81,
|
||||
BD_UCD_UNINTIALIZED_ERROR = 0xC82,
|
||||
BD_UCD_ACCOUNT_ALREADY_REGISTERED = 0xC83,
|
||||
BD_UCD_ACCOUNT_NOT_REGISTERED = 0xC84,
|
||||
BD_UCD_AUTH_ATTEMPT_FAILED = 0xC85,
|
||||
BD_UCD_ACCOUNT_LINKING_ERROR = 0xC86,
|
||||
BD_UCD_ENCRYPTION_ERROR = 0xC87,
|
||||
BD_UCD_ACCOUNT_DATA_INVALID = 0xC88,
|
||||
BD_UCD_ACCOUNT_DATA_INVALID_FIRSTNAME = 0xC89,
|
||||
BD_UCD_ACCOUNT_DATA_INVALID_LASTNAME = 0xC8A,
|
||||
BD_UCD_ACCOUNT_DATA_INVALID_DOB = 0xC8B,
|
||||
BD_UCD_ACCOUNT_DATA_INVALID_EMAIL = 0xC8C,
|
||||
BD_UCD_ACCOUNT_DATA_INVALID_COUNTRY = 0xC8D,
|
||||
BD_UCD_ACCOUNT_DATA_INVALID_POSTCODE = 0xC8E,
|
||||
BD_UCD_ACCOUNT_DATA_INVALID_PASSWORD = 0xC8F,
|
||||
BD_UCD_ACCOUNT_NAME_ALREADY_RESISTERED = 0xC94,
|
||||
BD_UCD_ACCOUNT_EMAIL_ALREADY_RESISTERED = 0xC95,
|
||||
BD_UCD_GUEST_ACCOUNT_AUTH_CONFLICT = 0xC96,
|
||||
BD_TWITCH_SERVICE_ERROR = 0xC1D,
|
||||
BD_TWITCH_ACCOUNT_ALREADY_LINKED = 0xC1E,
|
||||
BD_TWITCH_NO_LINKED_ACCOUNT = 0xC1F,
|
||||
BD_YOUTUBE_SERVICE_ERROR = 0xCE5,
|
||||
BD_YOUTUBE_SERVICE_COMMUNICATION_ERROR = 0xCE6,
|
||||
BD_YOUTUBE_USER_DENIED_AUTHORIZATION = 0xCE7,
|
||||
BD_YOUTUBE_AUTH_MAX_TIME_EXCEEDED = 0xCE8,
|
||||
BD_YOUTUBE_USER_UNAUTHORIZED = 0xCE9,
|
||||
BD_YOUTUBE_UPLOAD_MAX_TIME_EXCEEDED = 0xCEA,
|
||||
BD_YOUTUBE_DUPLICATE_UPLOAD = 0xCEB,
|
||||
BD_YOUTUBE_FAILED_UPLOAD = 0xCEC,
|
||||
BD_YOUTUBE_ACCOUNT_ALREADY_REGISTERED = 0xCED,
|
||||
BD_YOUTUBE_ACCOUNT_NOT_REGISTERED = 0xCEE,
|
||||
BD_YOUTUBE_CONTENT_SERVER_ERROR = 0xCEF,
|
||||
BD_YOUTUBE_UPLOAD_DOES_NOT_EXIST = 0xCF0,
|
||||
BD_YOUTUBE_NO_LINKED_ACCOUNT = 0xCF1,
|
||||
BD_YOUTUBE_DEVELOPER_TAGS_INVALID = 0xCF2,
|
||||
BD_TWITTER_AUTH_ATTEMPT_FAILED = 0xDAD,
|
||||
BD_TWITTER_AUTH_TOKEN_INVALID = 0xDAE,
|
||||
BD_TWITTER_UPDATE_LIMIT_REACHED = 0xDAF,
|
||||
BD_TWITTER_UNAVAILABLE = 0xDB0,
|
||||
BD_TWITTER_ERROR = 0xDB1,
|
||||
BD_TWITTER_TIMED_OUT = 0xDB2,
|
||||
BD_TWITTER_DISABLED_FOR_USER = 0xDB3,
|
||||
BD_TWITTER_ACCOUNT_AMBIGUOUS = 0xDB4,
|
||||
BD_TWITTER_MAXIMUM_ACCOUNTS_REACHED = 0xDB5,
|
||||
BD_TWITTER_ACCOUNT_NOT_REGISTERED = 0xDB6,
|
||||
BD_TWITTER_DUPLICATE_STATUS = 0xDB7,
|
||||
BD_TWITTER_ACCOUNT_ALREADY_REGISTERED = 0xE1C,
|
||||
BD_FACEBOOK_AUTH_ATTEMPT_FAILED = 0xE11,
|
||||
BD_FACEBOOK_AUTH_TOKEN_INVALID = 0xE12,
|
||||
BD_FACEBOOK_PHOTO_DOES_NOT_EXIST = 0xE13,
|
||||
BD_FACEBOOK_PHOTO_INVALID = 0xE14,
|
||||
BD_FACEBOOK_PHOTO_ALBUM_FULL = 0xE15,
|
||||
BD_FACEBOOK_UNAVAILABLE = 0xE16,
|
||||
BD_FACEBOOK_ERROR = 0xE17,
|
||||
BD_FACEBOOK_TIMED_OUT = 0xE18,
|
||||
BD_FACEBOOK_DISABLED_FOR_USER = 0xE19,
|
||||
BD_FACEBOOK_ACCOUNT_AMBIGUOUS = 0xE1A,
|
||||
BD_FACEBOOK_MAXIMUM_ACCOUNTS_REACHED = 0xE1B,
|
||||
BD_FACEBOOK_INVALID_NUM_PICTURES_REQUESTED = 0xE1C,
|
||||
BD_FACEBOOK_VIDEO_DOES_NOT_EXIST = 0xE1D,
|
||||
BD_FACEBOOK_ACCOUNT_ALREADY_REGISTERED = 0xE1E,
|
||||
BD_APNS_INVALID_PAYLOAD = 0xE74,
|
||||
BD_APNS_INVALID_TOKEN_LENGTH_ERROR = 0xE76,
|
||||
BD_MAX_CONSOLEID_LENGTH_EXCEEDED = 0xEE1,
|
||||
BD_MAX_WHITELIST_LENGTH_EXCEEDED = 0xEE2,
|
||||
BD_USERGROUP_NAME_ALREADY_EXISTS = 0x1770,
|
||||
BD_INVALID_USERGROUP_ID = 0x1771,
|
||||
BD_USER_ALREADY_IN_USERGROUP = 0x1772,
|
||||
BD_USER_NOT_IN_USERGROUP = 0x1773,
|
||||
BD_INVALID_USERGROUP_MEMBER_TYPE = 0x1774,
|
||||
BD_TOO_MANY_MEMBERS_REQUESTED = 0x1775,
|
||||
BD_USERGROUP_NAME_TOO_SHORT = 0x1776,
|
||||
BD_RICH_PRESENCE_DATA_TOO_LARGE = 0x1A90,
|
||||
BD_RICH_PRESENCE_TOO_MANY_USERS = 0x1A91,
|
||||
BD_PRESENCE_DATA_TOO_LARGE = 0x283C,
|
||||
BD_PRESENCE_TOO_MANY_USERS = 0x283D,
|
||||
BD_USER_LOGGED_IN_OTHER_TITLE = 0x283E,
|
||||
BD_USER_NOT_LOGGED_IN = 0x283F,
|
||||
BD_SUBSCRIPTION_TOO_MANY_USERS = 0x1B58,
|
||||
BD_SUBSCRIPTION_TICKET_PARSE_ERROR = 0x1B59,
|
||||
BD_CODO_ID_INVALID_DATA = 0x1BBC,
|
||||
BD_INVALID_MESSAGE_FORMAT = 0x1BBD,
|
||||
BD_TLOG_TOO_MANY_MESSAGES = 0x1BBE,
|
||||
BD_CODO_ID_NOT_IN_WHITELIST = 0x1BBF,
|
||||
BD_TLOG_MESSAGE_TRANSFORMATION_ERROR = 0x1BC0,
|
||||
BD_REWARDS_NOT_ENABLED = 0x1BC1,
|
||||
BD_MARKETPLACE_ERROR = 0x1F40,
|
||||
BD_MARKETPLACE_RESOURCE_NOT_FOUND = 0x1F41,
|
||||
BD_MARKETPLACE_INVALID_CURRENCY = 0x1F42,
|
||||
BD_MARKETPLACE_INVALID_PARAMETER = 0x1F43,
|
||||
BD_MARKETPLACE_RESOURCE_CONFLICT = 0x1F44,
|
||||
BD_MARKETPLACE_STORAGE_ERROR = 0x1F45,
|
||||
BD_MARKETPLACE_INTEGRITY_ERROR = 0x1F46,
|
||||
BD_MARKETPLACE_INSUFFICIENT_FUNDS_ERROR = 0x1F47,
|
||||
BD_MARKETPLACE_MMP_SERVICE_ERROR = 0x1F48,
|
||||
BD_MARKETPLACE_PRECONDITION_REQUIRED = 0x1F49,
|
||||
BD_MARKETPLACE_ITEM_MULTIPLE_PURCHASE_ERROR = 0x1F4A,
|
||||
BD_MARKETPLACE_MISSING_REQUIRED_ENTITLEMENT = 0x1F4B,
|
||||
BD_MARKETPLACE_VALIDATION_ERROR = 0x1F4C,
|
||||
BD_MARKETPLACE_TENCENT_PAYMENT_ERROR = 0x1F4D,
|
||||
BD_MARKETPLACE_SKU_NOT_COUPON_ENABLED_ERROR = 0x1F4E,
|
||||
BD_LEAGUE_INVALID_TEAM_SIZE = 0x1FA4,
|
||||
BD_LEAGUE_INVALID_TEAM = 0x1FA5,
|
||||
BD_LEAGUE_INVALID_SUBDIVISION = 0x1FA6,
|
||||
BD_LEAGUE_INVALID_LEAGUE = 0x1FA7,
|
||||
BD_LEAGUE_TOO_MANY_RESULTS_REQUESTED = 0x1FA8,
|
||||
BD_LEAGUE_METADATA_TOO_LARGE = 0x1FA9,
|
||||
BD_LEAGUE_TEAM_ICON_TOO_LARGE = 0x1FAA,
|
||||
BD_LEAGUE_TEAM_NAME_TOO_LONG = 0x1FAB,
|
||||
BD_LEAGUE_ARRAY_SIZE_MISMATCH = 0x1FAC,
|
||||
BD_LEAGUE_SUBDIVISION_MISMATCH = 0x2008,
|
||||
BD_LEAGUE_INVALID_WRITE_TYPE = 0x2009,
|
||||
BD_LEAGUE_INVALID_STATS_DATA = 0x200A,
|
||||
BD_LEAGUE_SUBDIVISION_UNRANKED = 0x200B,
|
||||
BD_LEAGUE_CROSS_TEAM_STATS_WRITE_PREVENTED = 0x200C,
|
||||
BD_LEAGUE_INVALID_STATS_SEASON = 0x200D,
|
||||
BD_COMMERCE_ERROR = 0x206C,
|
||||
BD_COMMERCE_RESOURCE_NOT_FOUND = 0x206D,
|
||||
BD_COMMERCE_STORAGE_INVALID_PARAMETER = 0x206E,
|
||||
BD_COMMERCE_APPLICATION_INVALID_PARAMETER = 0x206F,
|
||||
BD_COMMERCE_RESOURCE_CONFLICT = 0x2070,
|
||||
BD_COMMERCE_STORAGE_ERROR = 0x2071,
|
||||
BD_COMMERCE_INTEGRITY_ERROR = 0x2072,
|
||||
BD_COMMERCE_MMP_SERVICE_ERROR = 0x2073,
|
||||
BD_COMMERCE_PERMISSION_DENIED = 0x2074,
|
||||
BD_COMMERCE_INSUFFICIENT_FUNDS_ERROR = 0x2075,
|
||||
BD_COMMERCE_UNKNOWN_CURRENCY = 0x2076,
|
||||
BD_COMMERCE_INVALID_RECEIPT = 0x2077,
|
||||
BD_COMMERCE_RECEIPT_USED = 0x2078,
|
||||
BD_COMMERCE_TRANSACTION_ALREADY_APPLIED = 0x2079,
|
||||
BD_COMMERCE_INVALID_CURRENCY_TYPE = 0x207A,
|
||||
BD_CONNECTION_COUNTER_ERROR = 0x20D0,
|
||||
BD_LINKED_ACCOUNTS_INVALID_CONTEXT = 0x2198,
|
||||
BD_LINKED_ACCOUNTS_INVALID_PLATFORM = 0x2199,
|
||||
BD_LINKED_ACCOUNTS_LINKED_ACCOUNTS_FETCH_ERROR = 0x219A,
|
||||
BD_LINKED_ACCOUNTS_INVALID_ACCOUNT = 0x219B,
|
||||
BD_GMSG_INVALID_CATEGORY_ID = 0x27D8,
|
||||
BD_GMSG_CATEGORY_MEMBERSHIPS_LIMIT = 0x27D9,
|
||||
BD_GMSG_NONMEMBER_POST_DISALLOWED = 0x27DA,
|
||||
BD_GMSG_CATEGORY_DISALLOWS_CLIENT_TYPE = 0x27DB,
|
||||
BD_GMSG_PAYLOAD_TOO_BIG = 0x27DC,
|
||||
BD_GMSG_MEMBER_POST_DISALLOWED = 0x27DD,
|
||||
BD_GMSG_OVERLOADED = 0x27DE,
|
||||
BD_GMSG_USER_PERCATEGORY_POST_RATE_EXCEEDED = 0x27DF,
|
||||
BD_GMSG_USER_GLOBAL_POST_RATE_EXCEEDED = 0x27E0,
|
||||
BD_GMSG_GROUP_POST_RATE_EXCEEDED = 0x27E1,
|
||||
BD_MAX_ERROR_CODE = 0x27E2,
|
||||
};
|
||||
|
||||
enum bdNATType : uint8_t
|
||||
{
|
||||
BD_NAT_UNKNOWN = 0x0,
|
||||
@ -11,5 +351,22 @@ namespace game
|
||||
BD_NAT_MODERATE = 0x2,
|
||||
BD_NAT_STRICT = 0x3,
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct bdAuthTicket
|
||||
{
|
||||
unsigned int m_magicNumber;
|
||||
char m_type;
|
||||
unsigned int m_titleID;
|
||||
unsigned int m_timeIssued;
|
||||
unsigned int m_timeExpires;
|
||||
unsigned __int64 m_licenseID;
|
||||
unsigned __int64 m_userID;
|
||||
char m_username[64];
|
||||
char m_sessionKey[24];
|
||||
char m_usingHashMagicNumber[3];
|
||||
char m_hash[4];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,410 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "dw.hpp"
|
||||
#include "utils/hook.hpp"
|
||||
#include "game/game.hpp"
|
||||
#include "utils/nt.hpp"
|
||||
#include "utils/cryptography.hpp"
|
||||
|
||||
class dw final : public module
|
||||
#include "game/demonware/services/bdLSGHello.hpp" // 7
|
||||
#include "game/demonware/services/bdStorage.hpp" // 10
|
||||
#include "game/demonware/services/bdTitleUtilities.hpp" // 12
|
||||
#include "game/demonware/services/bdDML.hpp" // 27
|
||||
#include "game/demonware/services/bdSteamAuth.hpp" // 28
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
public:
|
||||
dw()
|
||||
namespace io
|
||||
{
|
||||
// TODO Patch DW
|
||||
int __stdcall send_to(const SOCKET s, const char* buf, const int len, const int flags, const sockaddr* to,
|
||||
const int tolen)
|
||||
{
|
||||
if (tolen == sizeof(sockaddr_in))
|
||||
{
|
||||
const auto in_addr = reinterpret_cast<const sockaddr_in*>(to);
|
||||
const auto server = dw::find_stun_server_by_address(in_addr->sin_addr.s_addr);
|
||||
if (server) return server->send(s, buf, len, to, tolen);
|
||||
}
|
||||
|
||||
void post_load() override
|
||||
return sendto(s, buf, len, flags, to, tolen);
|
||||
}
|
||||
|
||||
int __stdcall recv_from(const SOCKET s, char* buf, const int len, const int flags, sockaddr* from, int* fromlen)
|
||||
{
|
||||
auto res = dw::recv_datagam_packet(s, buf, len, from, fromlen);
|
||||
if (res != 0) return res;
|
||||
|
||||
res = recvfrom(s, buf, len, flags, from, fromlen);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int __stdcall send(const SOCKET s, const char* buf, const int len, const int flags)
|
||||
{
|
||||
auto server = dw::find_server_by_socket(s);
|
||||
if (server) return server->send(buf, len);
|
||||
|
||||
return ::send(s, buf, len, flags);
|
||||
}
|
||||
|
||||
int __stdcall recv(const SOCKET s, char* buf, const int len, const int flags)
|
||||
{
|
||||
auto server = dw::find_server_by_socket(s);
|
||||
if (server)
|
||||
{
|
||||
const auto blocking = dw::is_blocking_socket(s, TCP_BLOCKING);
|
||||
|
||||
int result;
|
||||
do
|
||||
{
|
||||
result = server->recv(buf, len);
|
||||
if (blocking && result < 0) std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
while (blocking && result < 0);
|
||||
|
||||
if (!blocking && result < 0)
|
||||
{
|
||||
WSASetLastError(WSAEWOULDBLOCK);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return ::recv(s, buf, len, flags);
|
||||
}
|
||||
|
||||
int __stdcall connect(const SOCKET s, const sockaddr* addr, const int len)
|
||||
{
|
||||
if (len == sizeof(sockaddr_in))
|
||||
{
|
||||
const auto* in_addr = reinterpret_cast<const sockaddr_in*>(addr);
|
||||
if (dw::link_socket(s, in_addr->sin_addr.s_addr)) return 0;
|
||||
}
|
||||
|
||||
return ::connect(s, addr, len);
|
||||
}
|
||||
|
||||
int __stdcall close_socket(const SOCKET s)
|
||||
{
|
||||
dw::remove_blocking_socket(s);
|
||||
dw::unlink_socket(s);
|
||||
return closesocket(s);
|
||||
}
|
||||
|
||||
int __stdcall ioctl_socket(const SOCKET s, const long cmd, u_long* argp)
|
||||
{
|
||||
if (static_cast<unsigned long>(cmd) == (FIONBIO))
|
||||
{
|
||||
dw::set_blocking_socket(s, *argp == 0);
|
||||
}
|
||||
|
||||
return ioctlsocket(s, cmd, argp);
|
||||
}
|
||||
|
||||
hostent* __stdcall get_host_by_name(char* name)
|
||||
{
|
||||
static std::mutex mutex;
|
||||
std::lock_guard<std::mutex> _(mutex);
|
||||
|
||||
unsigned long addr = 0;
|
||||
const auto server = dw::find_server_by_name(name);
|
||||
if (server) addr = server->get_address();
|
||||
|
||||
const auto stun_server = dw::find_stun_server_by_name(name);
|
||||
if (stun_server) addr = stun_server->get_address();
|
||||
|
||||
if (server || stun_server)
|
||||
{
|
||||
static in_addr address;
|
||||
address.s_addr = addr;
|
||||
|
||||
static in_addr* addr_list[2];
|
||||
addr_list[0] = &address;
|
||||
addr_list[1] = nullptr;
|
||||
|
||||
static hostent host;
|
||||
host.h_name = name;
|
||||
host.h_aliases = nullptr;
|
||||
host.h_addrtype = AF_INET;
|
||||
host.h_length = sizeof(in_addr);
|
||||
host.h_addr_list = reinterpret_cast<char **>(addr_list);
|
||||
|
||||
return &host;
|
||||
}
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4996)
|
||||
|
||||
// ReSharper disable once CppDeprecatedEntity
|
||||
return gethostbyname(name);
|
||||
|
||||
#pragma warning(pop)
|
||||
}
|
||||
|
||||
bool register_hook(const std::string& process, void* stub)
|
||||
{
|
||||
const utils::nt::module main;
|
||||
|
||||
auto result = false;
|
||||
result = result || utils::hook::iat(main, "wsock32.dll", process, stub);
|
||||
result = result || utils::hook::iat(main, "WS2_32.dll", process, stub);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bool dw::terminate_;
|
||||
std::thread dw::message_thread_;
|
||||
std::recursive_mutex dw::server_mutex_;
|
||||
std::map<SOCKET, bool> dw::blocking_sockets_;
|
||||
std::map<SOCKET, std::shared_ptr<service_server>> dw::socket_links_;
|
||||
std::map<unsigned long, std::shared_ptr<service_server>> dw::servers_;
|
||||
std::map<unsigned long, std::shared_ptr<stun_server>> dw::stun_servers_;
|
||||
std::map<SOCKET, std::queue<std::pair<std::string, std::string>>> dw::datagram_packets_;
|
||||
|
||||
uint8_t dw::encryption_key_[24];
|
||||
uint8_t dw::decryption_key_[24];
|
||||
|
||||
std::shared_ptr<service_server> dw::find_server_by_name(const std::string& name)
|
||||
{
|
||||
std::lock_guard _(server_mutex_);
|
||||
return find_server_by_address(utils::cryptography::jenkins_one_at_a_time::compute(name));
|
||||
}
|
||||
|
||||
std::shared_ptr<service_server> dw::find_server_by_address(const unsigned long address)
|
||||
{
|
||||
std::lock_guard _(server_mutex_);
|
||||
|
||||
const auto server = servers_.find(address);
|
||||
if (server != servers_.end())
|
||||
{
|
||||
return server->second;
|
||||
}
|
||||
|
||||
return std::shared_ptr<service_server>();
|
||||
}
|
||||
|
||||
std::shared_ptr<stun_server> dw::find_stun_server_by_name(const std::string& name)
|
||||
{
|
||||
std::lock_guard _(server_mutex_);
|
||||
return find_stun_server_by_address(utils::cryptography::jenkins_one_at_a_time::compute(name));
|
||||
}
|
||||
|
||||
std::shared_ptr<stun_server> dw::find_stun_server_by_address(const unsigned long address)
|
||||
{
|
||||
std::lock_guard _(server_mutex_);
|
||||
|
||||
const auto server = stun_servers_.find(address);
|
||||
if (server != stun_servers_.end())
|
||||
{
|
||||
return server->second;
|
||||
}
|
||||
|
||||
return std::shared_ptr<stun_server>();
|
||||
}
|
||||
|
||||
std::shared_ptr<service_server> dw::find_server_by_socket(const SOCKET s)
|
||||
{
|
||||
std::lock_guard _(server_mutex_);
|
||||
|
||||
const auto server = socket_links_.find(s);
|
||||
if (server != socket_links_.end())
|
||||
{
|
||||
return server->second;
|
||||
}
|
||||
|
||||
return std::shared_ptr<service_server>();
|
||||
}
|
||||
|
||||
bool dw::link_socket(const SOCKET s, const unsigned long address)
|
||||
{
|
||||
std::lock_guard _(server_mutex_);
|
||||
|
||||
const auto server = find_server_by_address(address);
|
||||
if (!server) return false;
|
||||
|
||||
socket_links_[s] = server;
|
||||
return true;
|
||||
}
|
||||
|
||||
void dw::unlink_socket(const SOCKET sock)
|
||||
{
|
||||
std::lock_guard _(server_mutex_);
|
||||
|
||||
const auto server = socket_links_.find(sock);
|
||||
if (server != socket_links_.end())
|
||||
{
|
||||
socket_links_.erase(server);
|
||||
}
|
||||
|
||||
const auto dgram_packets = datagram_packets_.find(sock);
|
||||
if (dgram_packets != datagram_packets_.end())
|
||||
{
|
||||
datagram_packets_.erase(dgram_packets);
|
||||
}
|
||||
}
|
||||
|
||||
int dw::recv_datagam_packet(const SOCKET s, char* buf, const int len, sockaddr* from, int* fromlen)
|
||||
{
|
||||
std::unique_lock lock(server_mutex_);
|
||||
|
||||
auto queue = datagram_packets_.find(s);
|
||||
if (queue != datagram_packets_.end())
|
||||
{
|
||||
const bool blocking = is_blocking_socket(s, UDP_BLOCKING);
|
||||
|
||||
lock.unlock();
|
||||
while (blocking && queue->second.empty())
|
||||
{
|
||||
std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
lock.lock();
|
||||
|
||||
if (!queue->second.empty())
|
||||
{
|
||||
auto packet = queue->second.front();
|
||||
queue->second.pop();
|
||||
|
||||
*fromlen = INT(packet.first.size());
|
||||
std::memcpy(from, packet.first.data(), *fromlen);
|
||||
|
||||
const int size = std::min(len, INT(packet.second.size()));
|
||||
std::memcpy(buf, packet.second.data(), size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
WSASetLastError(WSAEWOULDBLOCK);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dw::send_datagram_packet(const SOCKET s, const std::string& data, const sockaddr* to, const int tolen)
|
||||
{
|
||||
std::lock_guard _(server_mutex_);
|
||||
datagram_packets_[s].push({std::string(LPSTR(to), tolen), data});
|
||||
}
|
||||
|
||||
bool dw::is_blocking_socket(const SOCKET s, const bool def)
|
||||
{
|
||||
std::lock_guard _(server_mutex_);
|
||||
|
||||
if (blocking_sockets_.find(s) != blocking_sockets_.end())
|
||||
{
|
||||
return blocking_sockets_[s];
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
void dw::remove_blocking_socket(const SOCKET s)
|
||||
{
|
||||
std::lock_guard _(server_mutex_);
|
||||
|
||||
const auto entry = blocking_sockets_.find(s);
|
||||
if (entry != blocking_sockets_.end())
|
||||
{
|
||||
blocking_sockets_.erase(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void dw::set_blocking_socket(const SOCKET s, const bool blocking)
|
||||
{
|
||||
std::lock_guard _(server_mutex_);
|
||||
blocking_sockets_[s] = blocking;
|
||||
}
|
||||
|
||||
uint8_t* dw::get_key(const bool encrypt)
|
||||
{
|
||||
return encrypt ? encryption_key_ : decryption_key_;
|
||||
}
|
||||
|
||||
void dw::set_key(const bool encrypt, uint8_t* key)
|
||||
{
|
||||
static_assert(sizeof encryption_key_ == sizeof decryption_key_);
|
||||
std::memcpy(encrypt ? encryption_key_ : decryption_key_, key, sizeof encryption_key_);
|
||||
}
|
||||
|
||||
void dw::server_thread()
|
||||
{
|
||||
terminate_ = false;
|
||||
while (!terminate_)
|
||||
{
|
||||
std::unique_lock lock(server_mutex_);
|
||||
|
||||
for (auto& server : servers_)
|
||||
{
|
||||
server.second->run_frame();
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
|
||||
std::this_thread::sleep_for(50ms);
|
||||
}
|
||||
}
|
||||
|
||||
void dw::pre_destroy()
|
||||
{
|
||||
std::lock_guard _(server_mutex_);
|
||||
|
||||
terminate_ = true;
|
||||
if (message_thread_.joinable())
|
||||
{
|
||||
message_thread_.join();
|
||||
}
|
||||
|
||||
servers_.clear();
|
||||
stun_servers_.clear();
|
||||
socket_links_.clear();
|
||||
blocking_sockets_.clear();
|
||||
datagram_packets_.clear();
|
||||
}
|
||||
|
||||
dw::dw()
|
||||
{
|
||||
register_stun_server("mw3-stun.us.demonware.net");
|
||||
register_stun_server("mw3-stun.eu.demonware.net");
|
||||
register_stun_server("stun.jp.demonware.net");
|
||||
register_stun_server("stun.au.demonware.net");
|
||||
register_stun_server("stun.eu.demonware.net");
|
||||
register_stun_server("stun.us.demonware.net");
|
||||
|
||||
auto lsg_server = register_server("mw3-pc-lobby.prod.demonware.net");
|
||||
auto auth_server = register_server("mw3-pc-auth.prod.demonware.net");
|
||||
|
||||
auth_server->register_service<bdSteamAuth>();
|
||||
|
||||
lsg_server->register_service<bdLSGHello>();
|
||||
lsg_server->register_service<bdStorage>();
|
||||
lsg_server->register_service<bdTitleUtilities>();
|
||||
lsg_server->register_service<bdDML>();
|
||||
/*lsg_server->register_service<bdMatchMaking>();
|
||||
lsg_server->register_service<bdBandwidthTest>();
|
||||
lsg_server->register_service<bdGroup>();
|
||||
lsg_server->register_service<bdAnticheat>();
|
||||
lsg_server->register_service<bdRelayService>();*/
|
||||
}
|
||||
|
||||
void dw::post_load()
|
||||
{
|
||||
message_thread_ = std::thread(server_thread);
|
||||
|
||||
io::register_hook("send", io::send);
|
||||
io::register_hook("recv", io::recv);
|
||||
io::register_hook("sendto", io::send_to);
|
||||
io::register_hook("recvfrom", io::recv_from);
|
||||
io::register_hook("connect", io::connect);
|
||||
io::register_hook("closesocket", io::close_socket);
|
||||
io::register_hook("ioctlsocket", io::ioctl_socket);
|
||||
io::register_hook("gethostbyname", io::get_host_by_name);
|
||||
|
||||
utils::hook(SELECT_VALUE(0x6F40A0, 0x6EE1C0, 0x611310), bd_logger_stub, HOOK_JUMP).install()->quick();
|
||||
}
|
||||
|
||||
private:
|
||||
static void bd_logger_stub(int /*type*/, const char* const /*channelName*/, const char*, const char* const /*file*/,
|
||||
void dw::bd_logger_stub(int /*type*/, const char* const /*channelName*/, const char*, const char* const /*file*/,
|
||||
const char* const function, const unsigned int /*line*/, const char* const msg, ...)
|
||||
{
|
||||
char buffer[2048];
|
||||
@ -30,6 +417,6 @@ private:
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_MODULE(dw)
|
||||
}
|
||||
|
75
src/module/dw.hpp
Normal file
75
src/module/dw.hpp
Normal file
@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "game/demonware/stun_server.hpp"
|
||||
#include "game/demonware/service_server.hpp"
|
||||
|
||||
#define TCP_BLOCKING true
|
||||
#define UDP_BLOCKING false
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class dw final : public module
|
||||
{
|
||||
public:
|
||||
dw();
|
||||
|
||||
void post_load() override;
|
||||
void pre_destroy() override;
|
||||
|
||||
template <typename... Args>
|
||||
static std::shared_ptr<service_server> register_server(Args ... args)
|
||||
{
|
||||
std::lock_guard _(server_mutex_);
|
||||
auto server = std::make_shared<service_server>(args...);
|
||||
servers_[server->get_address()] = server;
|
||||
return server;
|
||||
}
|
||||
|
||||
static std::shared_ptr<stun_server> register_stun_server(std::string name)
|
||||
{
|
||||
std::lock_guard _(server_mutex_);
|
||||
auto server = std::make_shared<stun_server>(name);
|
||||
stun_servers_[server->get_address()] = server;
|
||||
return server;
|
||||
}
|
||||
|
||||
static int recv_datagam_packet(SOCKET s, char* buf, int len, sockaddr* from, int* fromlen);
|
||||
static void send_datagram_packet(SOCKET s, const std::string& data, const sockaddr* to, int tolen);
|
||||
|
||||
static bool is_blocking_socket(SOCKET s, bool def);
|
||||
static void remove_blocking_socket(SOCKET s);
|
||||
static void set_blocking_socket(SOCKET s, bool blocking);
|
||||
|
||||
static std::shared_ptr<stun_server> find_stun_server_by_name(const std::string& name);
|
||||
static std::shared_ptr<stun_server> find_stun_server_by_address(unsigned long address);
|
||||
|
||||
static std::shared_ptr<service_server> find_server_by_name(const std::string& name);
|
||||
static std::shared_ptr<service_server> find_server_by_address(unsigned long address);
|
||||
static std::shared_ptr<service_server> find_server_by_socket(SOCKET s);
|
||||
static bool link_socket(SOCKET sock, unsigned long address);
|
||||
static void unlink_socket(SOCKET sock);
|
||||
|
||||
static void set_key(bool encrypt, uint8_t* key);
|
||||
static uint8_t* get_key(bool encrypt);
|
||||
|
||||
private:
|
||||
static bool terminate_;
|
||||
static std::thread message_thread_;
|
||||
static std::recursive_mutex server_mutex_;
|
||||
|
||||
static uint8_t encryption_key_[24];
|
||||
static uint8_t decryption_key_[24];
|
||||
|
||||
static std::map<SOCKET, bool> blocking_sockets_;
|
||||
static std::map<SOCKET, std::shared_ptr<service_server>> socket_links_;
|
||||
static std::map<unsigned long, std::shared_ptr<service_server>> servers_;
|
||||
static std::map<unsigned long, std::shared_ptr<stun_server>> stun_servers_;
|
||||
static std::map<SOCKET, std::queue<std::pair<std::string, std::string>>> datagram_packets_;
|
||||
|
||||
static void server_thread();
|
||||
|
||||
static void bd_logger_stub(int /*type*/, const char* const /*channelName*/, const char*,
|
||||
const char* const /*file*/,
|
||||
const char* const function, const unsigned int /*line*/, const char* const msg, ...);
|
||||
};
|
||||
}
|
@ -4,3 +4,12 @@
|
||||
#define IMAGE_MP 301
|
||||
#define BINARY_SP 302
|
||||
#define BINARY_MP 303
|
||||
|
||||
#define DW_HEATMAP 304
|
||||
#define DW_MOTD 305
|
||||
#define DW_IMG 306
|
||||
#define DW_WAD 307
|
||||
#define DW_PLAYLIST 308
|
||||
#define DW_CONFIG 309
|
||||
#define DW_IOTD_TXT 310
|
||||
#define DW_IOTD_IMG 311
|
||||
|
@ -92,6 +92,15 @@ IMAGE_MP BITMAP "resources/multiplayer.bmp"
|
||||
BINARY_SP RCDATA "resources/iw5sp.exe.diff"
|
||||
BINARY_MP RCDATA "resources/iw5mp.exe.diff"
|
||||
|
||||
DW_HEATMAP RCDATA "resources/dw/heatmap.raw"
|
||||
DW_MOTD RCDATA "resources/dw/motd-english.txt"
|
||||
DW_IMG RCDATA "resources/dw/online_mp.img"
|
||||
DW_WAD RCDATA "resources/dw/online_tu14_mp_english.wad"
|
||||
DW_PLAYLIST RCDATA "resources/dw/playlists.aggr"
|
||||
DW_CONFIG RCDATA "resources/dw/social_tu1.cfg"
|
||||
DW_IOTD_TXT RCDATA "resources/dw/iotd-english.txt"
|
||||
DW_IOTD_IMG RCDATA "resources/dw/iotd-english.jpg"
|
||||
|
||||
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
BIN
src/resources/dw/heatmap.raw
Normal file
BIN
src/resources/dw/heatmap.raw
Normal file
Binary file not shown.
BIN
src/resources/dw/iotd-english.jpg
Normal file
BIN
src/resources/dw/iotd-english.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
1
src/resources/dw/iotd-english.txt
Normal file
1
src/resources/dw/iotd-english.txt
Normal file
@ -0,0 +1 @@
|
||||
Blub
|
1
src/resources/dw/motd-english.txt
Normal file
1
src/resources/dw/motd-english.txt
Normal file
@ -0,0 +1 @@
|
||||
Welcome to Open-IW5
|
BIN
src/resources/dw/online_mp.img
Normal file
BIN
src/resources/dw/online_mp.img
Normal file
Binary file not shown.
BIN
src/resources/dw/online_tu14_mp_english.wad
Normal file
BIN
src/resources/dw/online_tu14_mp_english.wad
Normal file
Binary file not shown.
BIN
src/resources/dw/playlists.aggr
Normal file
BIN
src/resources/dw/playlists.aggr
Normal file
Binary file not shown.
55
src/resources/dw/social_tu1.cfg
Normal file
55
src/resources/dw/social_tu1.cfg
Normal file
@ -0,0 +1,55 @@
|
||||
// DW Delay values
|
||||
set facebook_active 0
|
||||
set facebook_friends_active 0
|
||||
set facebook_upload_video_active 0
|
||||
set facebook_upload_photo_active 0
|
||||
set facebook_delay 750
|
||||
set facebook_max_retry_time 30000
|
||||
set facebook_retry_step 1000
|
||||
set facebook_friends_max_retry_time 30000
|
||||
set facebook_friends_retry_step 1000
|
||||
|
||||
set entitlements_active 0
|
||||
set entitlements_delay 500
|
||||
set entitlements_config_file_max_retry_time 30000
|
||||
set entitlements_config_file_retry_step 1000
|
||||
set entitlements_key_archive_max_retry_time 30000
|
||||
set entitlements_key_archive_retry_step 1000
|
||||
|
||||
set userGroup_active 1
|
||||
set elite_clan_active 0
|
||||
|
||||
set cl_enableDedicatedServerBrowser 1
|
||||
|
||||
set dw_presence_active 0
|
||||
set dw_presence_put_delay 5000
|
||||
set dw_presence_put_rate 30000
|
||||
set dw_presence_get_delay 5000
|
||||
set dw_presence_get_rate 60000
|
||||
|
||||
#ifdef MP
|
||||
set onlinevault_active 1
|
||||
set onlinevault_maxslots_sub0 10
|
||||
set onlinevault_maxslots_sub1 10
|
||||
set onlinevault_maxslots_sub2 10
|
||||
set onlinevault_maxtime_sub0 30
|
||||
set onlinevault_maxtime_sub1 30
|
||||
set onlinevault_maxtime_sub2 60
|
||||
#endif // #ifdef MP
|
||||
|
||||
set past_title_data_active 0
|
||||
|
||||
set pm_gamesetup_mode_altmodes 1
|
||||
set pm_gamesetup_mode_altmodes_dropzone 1
|
||||
set pm_gamesetup_mode_altmodes_teamjug 1
|
||||
set pm_gamesetup_mode_altmodes_jug 1
|
||||
set pm_gamesetup_mode_altmodes_gungame 1
|
||||
set pm_gamesetup_mode_altmodes_infected 1
|
||||
set pm_gamesetup_mode_altmodes_oneinthechamber 1
|
||||
|
||||
set pm_gamesetup_options_createdefaultclass 1
|
||||
set pm_gamesetup_options_customclassrestrictions 1
|
||||
|
||||
set prestige_shop_active 1
|
||||
|
||||
set theater_active 1
|
@ -13,6 +13,7 @@
|
||||
#include <objidl.h>
|
||||
#include <gdiplus.h>
|
||||
#include <WinSock2.h>
|
||||
#include <Ws2tcpip.h>
|
||||
#include <corecrt_io.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
@ -29,6 +30,7 @@
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <regex>
|
||||
#include <thread>
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
@ -40,6 +42,8 @@
|
||||
#include <tomcrypt.h>
|
||||
|
||||
#pragma comment (lib, "gdiplus.lib")
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
|
||||
#pragma warning(pop)
|
||||
#pragma warning(disable: 4100)
|
||||
|
||||
|
@ -1,8 +1,11 @@
|
||||
#include <std_include.hpp>
|
||||
#include "steam/steam.hpp"
|
||||
#include "module/dw.hpp"
|
||||
|
||||
namespace steam
|
||||
{
|
||||
std::string auth_ticket;
|
||||
|
||||
int user::GetHSteamUser()
|
||||
{
|
||||
return NULL;
|
||||
@ -107,7 +110,12 @@ namespace steam
|
||||
unsigned __int64 user::RequestEncryptedAppTicket(void* pUserData, int cbUserData)
|
||||
{
|
||||
// Generate the authentication ticket
|
||||
//Components::DemonWare::GenerateAuthTicket(std::string(reinterpret_cast<char*>(pUserData), cbUserData));
|
||||
const auto id = this->GetSteamID();
|
||||
|
||||
auth_ticket = "Open-IW5";
|
||||
auth_ticket.resize(32);
|
||||
auth_ticket.append(reinterpret_cast<char*>(pUserData), cbUserData);
|
||||
auth_ticket.append(reinterpret_cast<const char*>(&id.bits), sizeof(id.bits));
|
||||
|
||||
// Create the call response
|
||||
const auto result = callbacks::register_call();
|
||||
@ -124,8 +132,12 @@ namespace steam
|
||||
|
||||
bool user::GetEncryptedAppTicket(void* pTicket, int cbMaxTicket, unsigned int* pcbTicket)
|
||||
{
|
||||
if (cbMaxTicket < 0) return false;
|
||||
return false;
|
||||
//Components::DemonWare::GetAuthTicket(pTicket, static_cast<unsigned int>(cbMaxTicket), pcbTicket);
|
||||
if (cbMaxTicket < 0 || auth_ticket.empty()) return false;
|
||||
|
||||
const auto size = std::min(size_t(cbMaxTicket), auth_ticket.size());
|
||||
std::memcpy(pTicket, auth_ticket.data(), size);
|
||||
*pcbTicket = size;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,8 @@ namespace utils
|
||||
*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_,
|
||||
if (unprotect && !keep_unprotected)
|
||||
VirtualProtect(this->place_, sizeof(this->buffer_), this->protection_,
|
||||
&this->protection_);
|
||||
|
||||
FlushInstructionCache(GetCurrentProcess(), this->place_, sizeof(this->buffer_));
|
||||
@ -112,6 +113,22 @@ namespace utils
|
||||
}
|
||||
}
|
||||
|
||||
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_);
|
||||
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "nt.hpp"
|
||||
|
||||
#define HOOK_JUMP true
|
||||
#define HOOK_CALL false
|
||||
@ -81,6 +82,8 @@ namespace utils
|
||||
void* get_address() 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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user