#include #include #include #include #include #include #include #include #include #include #include #include #include static int32_t(__fastcall* g_get_incoming_packet_info_original)(d2_tweaks::common::packet_header* data, unsigned int dataSize, size_t* packetSizeOut, size_t* someOffset, int* packetGroup, int32_t* a6, int a7, int a8); static int32_t(__fastcall* g_handle_packet_original)(diablo2::structures::game* game, diablo2::structures::unit* player, d2_tweaks::common::packet_header* data, size_t size); static int32_t(__fastcall* g_net_tick_original)(diablo2::structures::game*, diablo2::structures::unit*, int32_t, int32_t); //returns some kind of processing type (i.e. resultGroup == 0x04 means drop packet) static int32_t __fastcall get_incoming_packet_info(d2_tweaks::common::packet_header* data, unsigned int dataSize, size_t* packetSizeOut, size_t* someOffset, int* packetGroup, int32_t* a6, int a7, int a8) { static d2_tweaks::common::packet_header dummy; static auto& instance = singleton::instance(); const auto resultGroup = g_get_incoming_packet_info_original(data, dataSize, packetSizeOut, someOffset, packetGroup, a6, a7, a8); if (data->d2_packet_type == dummy.d2_packet_type && resultGroup == 0x04) { //0x04 - drop packet size_t size; if (!instance.get_packet_size_cs(data, size)) return resultGroup; *packetSizeOut = size; *packetGroup = 1; *a6 = 100; return 2; } return resultGroup; } static int32_t __fastcall handle_packet(diablo2::structures::game* game, diablo2::structures::unit* player, d2_tweaks::common::packet_header* data, size_t size) { static d2_tweaks::common::packet_header dummy; static auto& instance = singleton::instance(); if (data->d2_packet_type == dummy.d2_packet_type) { if (!instance.handle_packet(game, player, data)) return g_handle_packet_original(game, player, data, size); return 1; } return g_handle_packet_original(game, player, data, size); } d2_tweaks::server::server::server(token) { m_module_id_counter = 0; m_tick_handler_id_counter = 0; } static int32_t g_ebp_send_to_client; void __fastcall hook_sc_packet_before_sent(uint32_t* client_strc, d2_tweaks::common::packet_header* packet, size_t size) { #ifndef NDEBUG __asm { push [ebp + 0x30]; pop [g_ebp_send_to_client]; } if (size == -1) return; spdlog::error("[d2game SEND] Packet {} Message {} Size {} CallFrom {}", (void*)packet->d2_packet_type, (void*)packet->message_type, size, (void*)g_ebp_send_to_client); #endif return; } __declspec (naked) void hook_sc_packet_before_sent_wrapper() { __asm { pushad; pushfd; push [esp+0x28] call [hook_sc_packet_before_sent] popfd; popad; // оригинальные инструкции push ecx push ebp push esi mov esi, ecx } RET_TO_RVA(DLLBASE_D2GAME, 0xC715); } // d2game:$0xC710 static const DLLPatchStrc gpt_hook_sc_packet_before_sent[] = { {D2DLL_D2GAME, 0xC710 + 0, PATCH_JMP, FALSE, 0x1}, {D2DLL_D2GAME, 0xC710 + 1, (DWORD)hook_sc_packet_before_sent_wrapper, TRUE, 0x0}, {D2DLL_INVALID} }; void d2_tweaks::server::server::init() { hooking::hook(reinterpret_cast(diablo2::d2_game::get_base() + 0x59320), ::handle_packet, &g_handle_packet_original); hooking::hook(reinterpret_cast(diablo2::d2_game::get_base() + 0x50F80), net_tick, &g_net_tick_original); hooking::hook(reinterpret_cast(diablo2::d2_net::get_base() + 0x1FE0), get_incoming_packet_info, &g_get_incoming_packet_info_original); //D2TEMPLATE_ApplyPatch(gpt_hook_sc_packet_before_sent); //disable outgoing packet type checks DWORD oldProtect; if (VirtualProtect(diablo2::d2_net::get_base() + 0x18B2, 0x02, PAGE_EXECUTE_READWRITE, &oldProtect)) *reinterpret_cast(diablo2::d2_net::get_base() + 0x18B2) = 0xBC3C; if (VirtualProtect(diablo2::d2_net::get_base() + 0x18D0, 0x02, PAGE_EXECUTE_READWRITE, &oldProtect)) *reinterpret_cast(diablo2::d2_net::get_base() + 0x18D0) = 0xBC3C; for (size_t i = 0; i < sizeof m_modules / sizeof(void*); i++) { if (m_modules[i] == nullptr) break; m_modules[i]->init(); } } void d2_tweaks::server::server::send_packet(diablo2::structures::net_client* client, common::packet_header* packet, size_t size) { diablo2::d2_game::enqueue_packet(client, packet, size); } bool d2_tweaks::server::server::handle_packet(diablo2::structures::game* game, diablo2::structures::unit* player, common::packet_header* packet) { auto handler = m_packet_handlers[packet->message_type]; if (!handler) return false; return handler->handle_packet(game, player, packet); } void d2_tweaks::server::server::register_module(modules::server_module* module) { m_modules[m_module_id_counter++] = module; } void d2_tweaks::server::server::register_tick_handler(modules::server_module* module) { m_tick_handlers[m_tick_handler_id_counter++] = module; } void d2_tweaks::server::server::register_packet_handler(common::message_types_t type, modules::server_module* module) { if (m_packet_handlers[type] != nullptr) { spdlog::warn("Serverside packet handler for {0} is already registered!", type); } m_packet_handlers[type] = module; } diablo2::structures::unit* d2_tweaks::server::server::get_server_unit(diablo2::structures::game* game, uint32_t guid, diablo2::structures::unit_type_t type) { if (game == nullptr) return nullptr; auto typeIndex = static_cast(type); if (type == diablo2::structures::unit_type_t::UNIT_TYPE_MISSILE) typeIndex = 4; if (type == diablo2::structures::unit_type_t::UNIT_TYPE_ITEM) typeIndex = 3; const auto index = guid & 127; auto result = game->unit_list[typeIndex][index]; while (result != nullptr && result->guid != guid) { result = result->prev_unit; } return result; } void d2_tweaks::server::server::iterate_server_units(diablo2::structures::game* game, diablo2::structures::unit_type_t type, const std::function& cb) { if (!cb) return; if (!game) return; auto typeIndex = static_cast(type); if (type == diablo2::structures::unit_type_t::UNIT_TYPE_MISSILE) typeIndex = 4; if (type == diablo2::structures::unit_type_t::UNIT_TYPE_ITEM) typeIndex = 3; for (size_t index = 0; index < 128; index++) { auto unit = game->unit_list[typeIndex][index]; while (unit != nullptr) { if (!cb(unit)) return; unit = unit->prev_unit; } } } int32_t d2_tweaks::server::server::net_tick(diablo2::structures::game* game, diablo2::structures::unit* unit, int32_t a3, int32_t a4) { static auto& instance = singleton::instance(); for (size_t i = 0; i < sizeof instance.m_modules / sizeof(void*); i++) { if (instance.m_tick_handlers[i] == nullptr) break; instance.m_tick_handlers[i]->tick(game, unit); } return g_net_tick_original(game, unit, a3, a4); }