Fix steam proxy

This commit is contained in:
momo5502 2019-09-24 23:00:50 +02:00
parent c399eed444
commit 25a9919498
2 changed files with 433 additions and 436 deletions

View File

@ -1,426 +1,426 @@
#include <std_include.hpp>
#include "dw.hpp"
#include "utils/hook.hpp"
#include "game/game.hpp"
#include "utils/nt.hpp"
#include "utils/cryptography.hpp"
#include "game/demonware/services/bdLSGHello.hpp" // 7
#include "game/demonware/services/bdStorage.hpp" // 10
#include "game/demonware/services/bdDediAuth.hpp" // 12
#include "game/demonware/services/bdTitleUtilities.hpp" // 12
#include "game/demonware/services/bdDML.hpp" // 27
#include "game/demonware/services/bdDediRSAAuth.hpp" // 26
#include "game/demonware/services/bdSteamAuth.hpp" // 28
namespace demonware
{
namespace io
{
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);
}
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<bdDediAuth>();
auth_server->register_service<bdSteamAuth>();
auth_server->register_service<bdDediRSAAuth>();
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();
}
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];
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap);
printf("%s: %s\n", function, buffer);
va_end(ap);
}
REGISTER_MODULE(dw)
}
#include <std_include.hpp>
#include "dw.hpp"
#include "utils/hook.hpp"
#include "game/game.hpp"
#include "utils/nt.hpp"
#include "utils/cryptography.hpp"
#include "game/demonware/services/bdLSGHello.hpp" // 7
#include "game/demonware/services/bdStorage.hpp" // 10
#include "game/demonware/services/bdDediAuth.hpp" // 12
#include "game/demonware/services/bdTitleUtilities.hpp" // 12
#include "game/demonware/services/bdDML.hpp" // 27
#include "game/demonware/services/bdDediRSAAuth.hpp" // 26
#include "game/demonware/services/bdSteamAuth.hpp" // 28
namespace demonware
{
namespace io
{
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);
}
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<bdDediAuth>();
auth_server->register_service<bdSteamAuth>();
auth_server->register_service<bdDediRSAAuth>();
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();
}
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];
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap);
printf("%s: %s\n", function, buffer);
va_end(ap);
}
REGISTER_MODULE(dw)
}

View File

@ -12,18 +12,17 @@ class steam_proxy final : public module
public:
void post_start() override
{
if (game::is_dedi()) return;
this->run_mod();
this->load_client();
this->clean_up_on_error();
}
void post_load() override
{
if (game::is_dedi()) return;
this->load_client();
this->clean_up_on_error();
try
{
if (game::is_sp())
@ -116,10 +115,8 @@ private:
this->steam_pipe_ = this->steam_client_module_.invoke<void*>("Steam_CreateSteamPipe");
this->global_user_ = this->steam_client_module_.invoke<void*>("Steam_ConnectToGlobalUser", this->steam_pipe_);
this->client_user_ = this->client_engine_.invoke<void*>(8, this->steam_pipe_, this->global_user_,
"CLIENTUSER_INTERFACE_VERSION001"); // GetIClientUser
this->client_utils_ = this->client_engine_.invoke<void*>(13, this->steam_pipe_,
"CLIENTUTILS_INTERFACE_VERSION001"); // GetIClientUtils
this->client_user_ = this->client_engine_.invoke<void*>(8, this->steam_pipe_, this->global_user_); // GetIClientUser
this->client_utils_ = this->client_engine_.invoke<void*>(13, this->steam_pipe_); // GetIClientUtils
}
void start_mod(const std::string& title, size_t app_id)
@ -175,4 +172,4 @@ private:
}
};
//REGISTER_MODULE(steam_proxy)
REGISTER_MODULE(steam_proxy)