This commit is contained in:
Federico Cecchetto 2022-05-17 19:56:53 +02:00
parent 601c211cd7
commit befa637f87
4 changed files with 187 additions and 293 deletions

View File

@ -1,14 +1,10 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "console.hpp" #include "console.hpp"
#include "loader/component_loader.hpp" #include "loader/component_loader.hpp"
#include "game/game.hpp" #include "game/game.hpp"
#include "command.hpp" #include "command.hpp"
#include <utils/thread.hpp>
#include <utils/flags.hpp>
#include <utils/concurrency.hpp>
#include <utils/hook.hpp>
namespace game_console namespace game_console
{ {
void print(int type, const std::string& data); void print(int type, const std::string& data);
@ -18,271 +14,50 @@ namespace console
{ {
namespace namespace
{ {
using message_queue = std::queue<std::string>; DWORD WINAPI console(LPVOID)
utils::concurrency::container<message_queue> messages;
bool native_console()
{ {
static const auto flag = utils::flags::has_flag("nativeconsole"); FreeConsole();
return flag; AllocConsole();
} AttachConsole(GetCurrentProcessId());
void hide_console() (void)freopen("CONIN$", "r", stdin);
{ (void)freopen("CONOUT$", "w", stdout);
auto* const con_window = GetConsoleWindow();
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<size_t>(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<std::string> 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; std::string cmd;
while (!this->terminate_runner_) while (true)
{ {
std::getline(std::cin, cmd); std::getline(std::cin, cmd);
command::execute(cmd);
} }
std::this_thread::yield(); return 0;
} }
};
HWND get_window()
{
return *reinterpret_cast<HWND*>((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<size_t>(count) };
} }
void set_size(const int width, const int height) void dispatch_message(const int type, const std::string& message)
{ {
RECT rect; //if (native_console())
GetWindowRect(get_window(), &rect); //{
printf("%s\n", message.data());
// return;
//}
SetWindowPos(get_window(), nullptr, rect.left, rect.top, width, height, 0); //game_console::print(type, message);
//messages.access([&message](message_queue& msgs)
auto* const logo_window = *reinterpret_cast<HWND*>(SELECT_VALUE(0x14CF56C10, 0x14DDFC2E0)); // H1(1.4) // {
SetWindowPos(logo_window, nullptr, 5, 5, width - 25, 60, 0); // msgs.emplace(message);
// });
} }
void print(const int type, const char* fmt, ...) void print(const int type, const char* fmt, ...)
@ -294,6 +69,15 @@ namespace console
dispatch_message(type, result); 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)

View File

@ -297,7 +297,7 @@ namespace demonware
if (server) if (server)
{ {
server->handle_input(buf, len, {s, to, tolen}); server->handle_input(buf, len, { s, to, tolen });
return len; 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 #ifdef DEBUG
@ -481,6 +481,32 @@ namespace demonware
printf("bdAuth: Unknown error\n"); printf("bdAuth: Unknown error\n");
} }
#endif #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<bool>(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 class component final : public component_interface
@ -542,52 +568,64 @@ namespace demonware
gethostbyname has been replaced with getaddrinfo gethostbyname has been replaced with getaddrinfo
btw, still you can't get online.. btw, still you can't get online..
*/ */
utils::hook::jump(SELECT_VALUE(0x140610320, 0x1407400B0), bd_logger_stub); // H1MP64(1.4) //utils::hook::jump(SELECT_VALUE(0, 0x7EBC20_b), bd_logger_stub);
if (game::environment::is_sp()) if (game::environment::is_sp())
{ {
utils::hook::set<uint8_t>(0x1405FCA00, 0xC3); // bdAuthSteam H1(1.4) // utils::hook::set<uint8_t>(0x1405FCA00, 0xC3); // bdAuthSteam H1(1.4)
utils::hook::set<uint8_t>(0x140333A00, 0xC3); // dwNet H1(1.4) // utils::hook::set<uint8_t>(0x140333A00, 0xC3); // dwNet H1(1.4)
return; return;
} }
utils::hook::set<uint8_t>(0x140715039, 0x0); // CURLOPT_SSL_VERIFYPEER H1MP64(1.4) utils::hook::set<uint8_t>(0x7C0AD9_b, 0x0); // CURLOPT_SSL_VERIFYPEER H1MP64(1.15)
utils::hook::set<uint8_t>(0x140715025, 0xAF); // CURLOPT_SSL_VERIFYHOST H1MP64(1.4) utils::hook::set<uint8_t>(0x7C0AC5_b, 0xAF); // CURLOPT_SSL_VERIFYHOST H1MP64(1.15)
utils::hook::set<uint8_t>(0x14095433C, 0x0); // HTTPS -> HTTP [MWR OK][S1X: 0x14088D0E8] utils::hook::set<uint8_t>(0xA1327C_b, 0x0); // HTTPS -> HTTP [MWR OK][S1X: 0x14088D0E8]
//HTTPS -> HTTP //HTTPS -> HTTP
utils::hook::inject(0x14006DDA9, "http://prod.umbrella.demonware.net/v1.0/"); // ---> [H1MP1.4 - S1X: 0x14003852E] char* umbrella = (char*)allocate_somewhere_near((uint8_t*)game::base_address);
utils::hook::inject(0x14006E11C, "http://prod.umbrella.demonware.net/v1.0/"); // ---> [H1MP1.4 - S1X: 0x14003884F] std::memcpy(umbrella, "http://prod.umbrella.demonware.net/v1.0/", sizeof("http://prod.umbrella.demonware.net/v1.0/"));
utils::hook::inject(0x14006E2FB, "http://prod.umbrella.demonware.net/v1.0/"); // ---> [H1MP1.4 - S1X: 0x140038A07]
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/");
utils::hook::set<uint8_t>(0x14047F290, 0xC3); // SV_SendMatchData H1MP64(1.4) utils::hook::inject(0x8615F_b, umbrella);
utils::hook::set<uint8_t>(0x140598990, 0xC3); // Live_CheckForFullDisconnect H1MP64(1.4) utils::hook::inject(0x8638C_b, umbrella);
#ifdef DEBUG char* uno = (char*)allocate_somewhere_near((uint8_t*)game::base_address);
// yes std::memcpy(uno, "http://prod.uno.demonware.net/v1.0/", sizeof("http://prod.uno.demonware.net/v1.0/"));
utils::hook::call(0x140727BEB, l);
utils::hook::call(0x140727AFC, i); utils::hook::inject(0x86C56_b, uno);
utils::hook::call(0x140727E49, h); utils::hook::inject(0x86F96_b, uno);
utils::hook::call(0x140727E30, g);
utils::hook::call(0x140727E37, f); BYTE bytes[] = { 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x25, 0x73, 0x3A, 0x25, 0x64, 0x2F, 0x61, 0x75, 0x74, 0x68, 0x2F, 0x0 }; // KEKW
utils::hook::call(0x140727DF2, e); std::memcpy((void*)0x9EDB08_b, bytes, sizeof(bytes)); //utils::hook::inject(0x140728170, "http://%s:%d/auth/"); :DDD
utils::hook::call(0x140727DF9, d);
utils::hook::call(0x140727CFC, c); //utils::hook::set<uint8_t>(0x14047F290, 0xC3); // SV_SendMatchData H1MP64(1.4)
utils::hook::call(0x140727C82, b); //utils::hook::set<uint8_t>(0x140598990, 0xC3); // Live_CheckForFullDisconnect H1MP64(1.4)
utils::hook::call(0x140727E6A, a);
#endif //#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 // 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 // Checks extended_data and extra_data in json object
utils::hook::set(0x140728E90, 0xC301B0); //utils::hook::set(0x7D55C0_b, 0xC301B0);
// Update check // 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 // 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 void pre_destroy() override
@ -601,4 +639,4 @@ namespace demonware
}; };
} }
//REGISTER_COMPONENT(demonware::component) REGISTER_COMPONENT(demonware::component)

View File

@ -170,4 +170,41 @@ namespace demonware
buffer->read_blob(&this->data); 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);
}
};
} }

View File

@ -172,15 +172,45 @@ namespace demonware
const auto path = get_user_file_path(filename); const auto path = get_user_file_path(filename);
utils::io::write_file(path, data); utils::io::write_file(path, data);
auto* info = new bdFileInfo; auto* info = new bdFile2;
info->file_id = *reinterpret_cast<const uint64_t*>(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<const uint64_t*>(utils::cryptography::sha1::compute(filename).data());
info->filename = filename; info->filename = filename;
info->create_time = uint32_t(time(nullptr)); info->create_time = uint32_t(time(nullptr));
info->modified_time = info->create_time; info->modified_time = info->create_time;
info->file_size = uint32_t(data.size()); info->file_size = uint32_t(data.size());
info->owner_id = uint64_t(owner); info->owner_id = uint64_t(owner);
info->priv = priv; info->priv = priv;*/
#ifdef DEBUG #ifdef DEBUG
printf("[DW]: [bdStorage]: set user file: %s\n", filename.data()); printf("[DW]: [bdStorage]: set user file: %s\n", filename.data());
@ -213,6 +243,8 @@ namespace demonware
auto reply = server->create_reply(this->task_id()); auto reply = server->create_reply(this->task_id());
printf("%i\n", numfiles);
for (uint32_t i = 0; i < numfiles; i++) for (uint32_t i = 0; i < numfiles; i++)
{ {
std::string filename, data; std::string filename, data;
@ -221,6 +253,9 @@ namespace demonware
const auto path = get_user_file_path(filename); const auto path = get_user_file_path(filename);
if (!utils::io::read_file(path, &data)) 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; continue;
} }