diff --git a/src/client/component/console.cpp b/src/client/component/console.cpp index 8b39323f..78ed8422 100644 --- a/src/client/component/console.cpp +++ b/src/client/component/console.cpp @@ -1,14 +1,10 @@ #include #include "console.hpp" #include "loader/component_loader.hpp" + #include "game/game.hpp" #include "command.hpp" -#include -#include -#include -#include - namespace game_console { void print(int type, const std::string& data); @@ -18,271 +14,50 @@ namespace console { namespace { - using message_queue = std::queue; - utils::concurrency::container messages; - - bool native_console() + DWORD WINAPI console(LPVOID) { - static const auto flag = utils::flags::has_flag("nativeconsole"); - return flag; - } + FreeConsole(); + AllocConsole(); + AttachConsole(GetCurrentProcessId()); - void hide_console() - { - auto* const con_window = GetConsoleWindow(); + (void)freopen("CONIN$", "r", stdin); + (void)freopen("CONOUT$", "w", stdout); - DWORD process; - GetWindowThreadProcessId(con_window, &process); - - if (!native_console() && (process == GetCurrentProcessId() || IsDebuggerPresent())) - { - ShowWindow(con_window, SW_HIDE); - } - } - - std::string format(va_list* ap, const char* message) - { - static thread_local char buffer[0x1000]; - - const auto count = _vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer), message, *ap); - - if (count < 0) return {}; - return {buffer, static_cast(count)}; - } - - void dispatch_message(const int type, const std::string& message) - { - if (native_console()) - { - printf("%s\n", message.data()); - return; - } - - game_console::print(type, message); - messages.access([&message](message_queue& msgs) - { - msgs.emplace(message); - }); - } - - void append_text(const char* text) - { - dispatch_message(con_type_info, text); - } - } - - class component final : public component_interface - { - public: - component() - { - hide_console(); - - if (native_console()) - { - setvbuf(stdout, nullptr, _IONBF, 0); - setvbuf(stderr, nullptr, _IONBF, 0); - } - else - { - (void)_pipe(this->handles_, 1024, _O_TEXT); - (void)_dup2(this->handles_[1], 1); - (void)_dup2(this->handles_[1], 2); - } - } - - void post_start() override - { - this->terminate_runner_ = false; - - this->console_runner_ = utils::thread::create_named_thread("Console IO", [this] - { - if (native_console()) - { - this->native_input(); - } - else - { - this->runner(); - } - }); - } - - void pre_destroy() override - { - this->terminate_runner_ = true; - - printf("\r\n"); - _flushall(); - - if (this->console_runner_.joinable()) - { - this->console_runner_.join(); - } - - if (this->console_thread_.joinable()) - { - this->console_thread_.join(); - } - -#ifndef NATIVE_CONSOLE - _close(this->handles_[0]); - _close(this->handles_[1]); -#endif - - messages.access([&](message_queue& msgs) - { - msgs = {}; - }); - } - - void post_unpack() override - { - // Redirect input (]command) - utils::hook::jump(SELECT_VALUE(0x1403E34C0, 0x1405141E0), append_text); // H1(1.4) - - this->initialize(); - } - - private: - volatile bool console_initialized_ = false; - volatile bool terminate_runner_ = false; - - std::thread console_runner_; - std::thread console_thread_; - - int handles_[2]{}; - - void initialize() - { - this->console_thread_ = utils::thread::create_named_thread("Console", [this]() - { - if (!native_console() && (game::environment::is_dedi() || !utils::flags::has_flag("noconsole"))) - { - game::Sys_ShowConsole(); - } - - if (!game::environment::is_dedi()) - { - // Hide that shit - ShowWindow(console::get_window(), SW_MINIMIZE); - } - - { - messages.access([&](message_queue&) - { - this->console_initialized_ = true; - }); - } - - MSG msg; - while (!this->terminate_runner_) - { - if (PeekMessageA(&msg, nullptr, NULL, NULL, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - { - command::execute("quit", false); - break; - } - - TranslateMessage(&msg); - DispatchMessage(&msg); - } - else - { - this->log_messages(); - std::this_thread::sleep_for(1ms); - } - } - }); - } - - void log_messages() - { - /*while*/ - if (this->console_initialized_ && !messages.get_raw().empty()) - { - std::queue message_queue_copy; - - { - messages.access([&](message_queue& msgs) - { - message_queue_copy = std::move(msgs); - msgs = {}; - }); - } - - while (!message_queue_copy.empty()) - { - log_message(message_queue_copy.front()); - message_queue_copy.pop(); - } - } - - fflush(stdout); - fflush(stderr); - } - - static void log_message(const std::string& message) - { - OutputDebugStringA(message.data()); - game::Conbuf_AppendText(message.data()); - } - - void runner() - { - char buffer[1024]; - - while (!this->terminate_runner_ && this->handles_[0]) - { - const auto len = _read(this->handles_[0], buffer, sizeof(buffer)); - if (len > 0) - { - dispatch_message(con_type_info, std::string(buffer, len)); - } - else - { - std::this_thread::sleep_for(1ms); - } - } - - std::this_thread::yield(); - } - - void native_input() - { std::string cmd; - while (!this->terminate_runner_) + while (true) { std::getline(std::cin, cmd); - command::execute(cmd); + } - std::this_thread::yield(); + return 0; } - }; - - HWND get_window() - { - return *reinterpret_cast((SELECT_VALUE(0x14CF56C00, 0x14DDFC2D0))); // H1(1.4) } - void set_title(std::string title) + std::string format(va_list* ap, const char* message) { - SetWindowText(get_window(), title.data()); + static thread_local char buffer[0x1000]; + + const auto count = _vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer), message, *ap); + + if (count < 0) return {}; + return { buffer, static_cast(count) }; } - void set_size(const int width, const int height) + void dispatch_message(const int type, const std::string& message) { - RECT rect; - GetWindowRect(get_window(), &rect); + //if (native_console()) + //{ + printf("%s\n", message.data()); + // return; + //} - SetWindowPos(get_window(), nullptr, rect.left, rect.top, width, height, 0); - - auto* const logo_window = *reinterpret_cast(SELECT_VALUE(0x14CF56C10, 0x14DDFC2E0)); // H1(1.4) - SetWindowPos(logo_window, nullptr, 5, 5, width - 25, 60, 0); + //game_console::print(type, message); + //messages.access([&message](message_queue& msgs) + // { + // msgs.emplace(message); + // }); } void print(const int type, const char* fmt, ...) @@ -294,6 +69,15 @@ namespace console dispatch_message(type, result); } + + class component final : public component_interface + { + public: + void post_start() override + { + CreateThread(0, 0, console, 0, 0, 0); + } + }; } -//REGISTER_COMPONENT(console::component) +REGISTER_COMPONENT(console::component) diff --git a/src/client/component/demonware.cpp b/src/client/component/demonware.cpp index 5363cbd7..7c2b1460 100644 --- a/src/client/component/demonware.cpp +++ b/src/client/component/demonware.cpp @@ -297,7 +297,7 @@ namespace demonware if (server) { - server->handle_input(buf, len, {s, to, tolen}); + server->handle_input(buf, len, { s, to, tolen }); return len; } @@ -425,9 +425,9 @@ namespace demonware } } - void bd_logger_stub(char* a1, void* a2, void* a3, void* a4, const char* function, ...) + void bd_logger_stub() { - + //printf("logged\n"); } #ifdef DEBUG @@ -481,6 +481,32 @@ namespace demonware printf("bdAuth: Unknown error\n"); } #endif + + utils::hook::detour kekw_hook; + bool kekw_stub(__int64 a1, __int64 a2, __int64* a3) + { + // Checks X-Signature header or something + utils::hook::set(0x7D4AB0_b, 0xC301B0); + // Checks extended_data and extra_data in json object + utils::hook::set(0x7D55C0_b, 0xC301B0); + return kekw_hook.invoke(a1, a2, a3); + } + + void* allocate_somewhere_near(uint8_t* base_address) + { + const size_t PAGE_SIZE = 0x1000; + size_t offset = 0; + while (true) + { + offset += PAGE_SIZE; + auto res = VirtualAlloc(base_address - offset, PAGE_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (res) + { + std::memset(res, 0, PAGE_SIZE); + return res; + } + } + } } class component final : public component_interface @@ -537,52 +563,69 @@ namespace demonware void post_unpack() override { - utils::hook::jump(SELECT_VALUE(0x140610320, 0x1407400B0), bd_logger_stub); + /* + mwr has upgraded some networking methods and the gethostbyname import from winsock library is no longer used + gethostbyname has been replaced with getaddrinfo + btw, still you can't get online.. + */ + //utils::hook::jump(SELECT_VALUE(0, 0x7EBC20_b), bd_logger_stub); if (game::environment::is_sp()) { - utils::hook::set(0x1405FCA00, 0xC3); // bdAuthSteam - utils::hook::set(0x140333A00, 0xC3); // dwNet + // utils::hook::set(0x1405FCA00, 0xC3); // bdAuthSteam H1(1.4) + // utils::hook::set(0x140333A00, 0xC3); // dwNet H1(1.4) return; } - utils::hook::set(0x140715039, 0x0); // CURLOPT_SSL_VERIFYPEER - utils::hook::set(0x140715025, 0xAF); // CURLOPT_SSL_VERIFYHOST - utils::hook::set(0x14095433C, 0x0); // HTTPS -> HTTP + utils::hook::set(0x7C0AD9_b, 0x0); // CURLOPT_SSL_VERIFYPEER H1MP64(1.15) + utils::hook::set(0x7C0AC5_b, 0xAF); // CURLOPT_SSL_VERIFYHOST H1MP64(1.15) + utils::hook::set(0xA1327C_b, 0x0); // HTTPS -> HTTP [MWR OK][S1X: 0x14088D0E8] //HTTPS -> HTTP - utils::hook::inject(0x14006DDA9, "http://prod.umbrella.demonware.net/v1.0/"); - utils::hook::inject(0x14006E11C, "http://prod.umbrella.demonware.net/v1.0/"); - utils::hook::inject(0x14006E2FB, "http://prod.umbrella.demonware.net/v1.0/"); - utils::hook::inject(0x14006E9A9, "http://prod.uno.demonware.net/v1.0/"); - utils::hook::inject(0x14006ED49, "http://prod.uno.demonware.net/v1.0/"); - utils::hook::inject(0x140728170, "http://%s:%d/auth/"); + char* umbrella = (char*)allocate_somewhere_near((uint8_t*)game::base_address); + std::memcpy(umbrella, "http://prod.umbrella.demonware.net/v1.0/", sizeof("http://prod.umbrella.demonware.net/v1.0/")); - utils::hook::set(0x14047F290, 0xC3); // SV_SendMatchData - utils::hook::set(0x140598990, 0xC3); // Live_CheckForFullDisconnect + utils::hook::inject(0x8615F_b, umbrella); + utils::hook::inject(0x8638C_b, umbrella); -#ifdef DEBUG - // yes - utils::hook::call(0x140727BEB, l); - utils::hook::call(0x140727AFC, i); - utils::hook::call(0x140727E49, h); - utils::hook::call(0x140727E30, g); - utils::hook::call(0x140727E37, f); - utils::hook::call(0x140727DF2, e); - utils::hook::call(0x140727DF9, d); - utils::hook::call(0x140727CFC, c); - utils::hook::call(0x140727C82, b); - utils::hook::call(0x140727E6A, a); -#endif + char* uno = (char*)allocate_somewhere_near((uint8_t*)game::base_address); + std::memcpy(uno, "http://prod.uno.demonware.net/v1.0/", sizeof("http://prod.uno.demonware.net/v1.0/")); + + utils::hook::inject(0x86C56_b, uno); + utils::hook::inject(0x86F96_b, uno); + + BYTE bytes[] = { 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x25, 0x73, 0x3A, 0x25, 0x64, 0x2F, 0x61, 0x75, 0x74, 0x68, 0x2F, 0x0 }; // KEKW + std::memcpy((void*)0x9EDB08_b, bytes, sizeof(bytes)); //utils::hook::inject(0x140728170, "http://%s:%d/auth/"); :DDD + + //utils::hook::set(0x14047F290, 0xC3); // SV_SendMatchData H1MP64(1.4) + //utils::hook::set(0x140598990, 0xC3); // Live_CheckForFullDisconnect H1MP64(1.4) + +//#ifdef DEBUG +// // yes +// utils::hook::call(0x140727BEB, l); +// utils::hook::call(0x140727AFC, i); +// utils::hook::call(0x140727E49, h); +// utils::hook::call(0x140727E30, g); +// utils::hook::call(0x140727E37, f); +// utils::hook::call(0x140727DF2, e); +// utils::hook::call(0x140727DF9, d); +// utils::hook::call(0x140727CFC, c); +// utils::hook::call(0x140727C82, b); +// utils::hook::call(0x140727E6A, a); +//#endif // Checks X-Signature header or something - utils::hook::set(0x140728380, 0xC301B0); + //utils::hook::set(0x7D4AB0_b, 0xC301B0); // Checks extended_data and extra_data in json object - utils::hook::set(0x140728E90, 0xC301B0); + //utils::hook::set(0x7D55C0_b, 0xC301B0); // Update check - utils::hook::set(0x1403A5390, 0xC301B0); - + //utils::hook::set(0x1403A5390, 0xC301B0); + // Remove some while loop in demonware that freezes the rendering for a few secs at launch - utils::hook::nop(0x14057DBC5, 5); + //utils::hook::nop(0x14057DBC5, 5); + + MessageBoxA(0, "TEST", "", 0); + kekw_hook.create(0x7AC600_b, kekw_stub); + MessageBoxA(0, "TEST2", "", 0); } void pre_destroy() override @@ -596,4 +639,4 @@ namespace demonware }; } -//REGISTER_COMPONENT(demonware::component) +REGISTER_COMPONENT(demonware::component) diff --git a/src/client/game/demonware/data_types.hpp b/src/client/game/demonware/data_types.hpp index fb108190..579e2248 100644 --- a/src/client/game/demonware/data_types.hpp +++ b/src/client/game/demonware/data_types.hpp @@ -170,4 +170,41 @@ namespace demonware buffer->read_blob(&this->data); } }; + + class bdFile2 final : public bdTaskResult + { + public: + uint32_t unk1; + uint32_t unk2; + uint32_t unk3; + bool priv; + uint64_t owner_id; + std::string platform; + std::string filename; + std::string data; + + void serialize(byte_buffer* buffer) override + { + buffer->write_uint32(this->unk1); + buffer->write_uint32(this->unk2); + buffer->write_uint32(this->unk3); + buffer->write_bool(this->priv); + buffer->write_uint64(this->owner_id); + buffer->write_string(this->platform); + buffer->write_string(this->filename); + buffer->write_blob(this->data); + } + + void deserialize(byte_buffer* buffer) override + { + buffer->read_uint32(&this->unk1); + buffer->read_uint32(&this->unk2); + buffer->read_uint32(&this->unk3); + buffer->read_bool(&this->priv); + buffer->read_uint64(&this->owner_id); + buffer->read_string(&this->platform); + buffer->read_string(&this->filename); + buffer->read_blob(&this->data); + } + }; } diff --git a/src/client/game/demonware/services/bdStorage.cpp b/src/client/game/demonware/services/bdStorage.cpp index 2e7f026c..9f398868 100644 --- a/src/client/game/demonware/services/bdStorage.cpp +++ b/src/client/game/demonware/services/bdStorage.cpp @@ -172,15 +172,45 @@ namespace demonware const auto path = get_user_file_path(filename); utils::io::write_file(path, data); - auto* info = new bdFileInfo; + auto* info = new bdFile2; - info->file_id = *reinterpret_cast(utils::cryptography::sha1::compute(filename).data()); + // int + // int + // int + // byte (priv) + // int64 (owner) + // string (platform) + // string (file) + // blob + // size + // data + // int + // int + // int + // byte + // int64 + // string (platform) + // string (file) + // blob + // size + // data + + info->unk1 = 0; + info->unk2 = 0; + info->unk3 = 0; + info->priv = false; + info->owner_id = owner; + info->platform = platform; + info->filename = filename; + info->data = data; + + /*info->file_id = *reinterpret_cast(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 = uint64_t(owner); - info->priv = priv; + info->priv = priv;*/ #ifdef DEBUG printf("[DW]: [bdStorage]: set user file: %s\n", filename.data()); @@ -213,6 +243,8 @@ namespace demonware auto reply = server->create_reply(this->task_id()); + printf("%i\n", numfiles); + for (uint32_t i = 0; i < numfiles; i++) { std::string filename, data; @@ -221,6 +253,9 @@ namespace demonware const auto path = get_user_file_path(filename); if (!utils::io::read_file(path, &data)) { +#ifdef DEBUG + printf("[DW]: [bdStorage]: get user file: missing file: %s, %s, %s\n", game.data(), filename.data(), platform.data()); +#endif continue; }