В принципе ничего сложного. Ниже пример, который перед приходом любого сообщения в общий чат (белый), отправляет клиенту новый пакет, в котором изменяется ник, и тип чата, так же перед текстом добавляется текущее время отправки). Код на скорую руку, многие вещи можно повыносить в классы\функции, и т п, с другой стороны, это просто пример, так что сойдет) Hf.
#pragma pack(push, 1)
struct UNetworkPacket
{
uint8_t id;
uint8_t res;
uint16_t id2;
uint32_t size;
void *data;
};
struct CreatureSayPartialPacket
{
uint32_t object_id;
uint32_t text_type;
};
#pragma pack(pop)
using GMallocType = void * (*) (wchar_t *type, uint32_t size);
using GFreeType = void (*) (void *addr);
using DispatchNetworkQueueType = int(__fastcall *)(void *This, int, UNetworkPacket **packet);
DispatchNetworkQueueType DispatchNetworkQueueOrig = nullptr;
//--
//--
//--
//--
void *gmalloc(uint32_t alloc_size)
{
static const auto gmalloc_export_name = "?GMalloc@@3PAVFMalloc@@A";
static const auto gmalloc_export = reinterpret_cast<void **>(
GetProcAddress(
GetModuleHandleA("core.dll"),
gmalloc_export_name));
static const auto fmalloc_object = *gmalloc_export;
static const auto gmalloc = ***reinterpret_cast<GMallocType ***>(gmalloc_export);
__asm
{
push 0
push alloc_size
mov ecx, fmalloc_object
call gmalloc
}
}
void gfree(void *addr)
{
static const auto gmalloc_export_name = "?GMalloc@@3PAVFMalloc@@A";
static const auto gmalloc_export = reinterpret_cast<void **>(
GetProcAddress(
GetModuleHandleA("core.dll"),
gmalloc_export_name));
static const auto fmalloc_object = *gmalloc_export;
static const auto gfree = *(**reinterpret_cast<GMallocType ***>(gmalloc_export) + 2);
__asm
{
push addr
mov ecx, fmalloc_object
call gfree
}
}
std::string current_time()
{
time_t now = time(0);
tm tstruct;
char buf[0x10];
localtime_s(&tstruct, &now);
strftime(buf, sizeof(buf), "%X", &tstruct);
// strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct);
return std::string(buf);
}
int __fastcall DispatchNetworkQueue(void *This, int, UNetworkPacket **packet)
{
static const uint8_t creature_say_id = 0x4a;
UNetworkPacket *current_packet = nullptr;
static std::queue< UNetworkPacket * > packets;
//--
//--
int result = 0;
if (!packets.empty())
{
*packet = packets.front();
packets.pop();
result = 1;
}
else
{
// Call original func
result = (*DispatchNetworkQueueOrig)(This, 0, ¤t_packet);
if (result)
{
*packet = current_packet;
if (creature_say_id == current_packet->id)
{
auto creature_say_packet = reinterpret_cast<CreatureSayPartialPacket *>(current_packet->data);
enum class ChatType : uint32_t
{
ALL = 0,
HERO_VOICE = 17,
};
if (ChatType::ALL == static_cast<ChatType>(creature_say_packet->text_type))
{
//--
// Parse packet
//--
auto ptr = reinterpret_cast<uint8_t *>(creature_say_packet);
auto object_id = reinterpret_cast<uint32_t *>(ptr);
ptr += sizeof(*object_id);
auto text_type = reinterpret_cast<uint32_t *>(ptr);
ptr += sizeof(*text_type);
auto char_name = reinterpret_cast<wchar_t *>(ptr);
ptr += (wcslen(char_name) + 1) * sizeof(wchar_t);
auto npc_string = reinterpret_cast<uint32_t *>(ptr);
ptr += sizeof(*npc_string);
auto text = reinterpret_cast<wchar_t *>(ptr);
ptr += (wcslen(text) + 1) * sizeof(wchar_t);
//--
//--
wchar_t new_char_name[] = L"GOD";
wchar_t new_text[0x200] = { 0 };
std::string cur_time = current_time();
swprintf_s(new_text, L"[%S] %s", cur_time.c_str(), text);
auto new_char_name_length = sizeof(new_char_name);
auto new_text_length = (wcslen(new_text) + 1) * sizeof(wchar_t);
auto new_packet_data_size = sizeof(*object_id)
+ sizeof(*text_type)
+ new_char_name_length
+ sizeof(*npc_string)
+ new_text_length;
//--
//--
//--
// Create new packet
//--
auto new_packet = reinterpret_cast<UNetworkPacket *>(gmalloc(sizeof(UNetworkPacket)));
new_packet->id = creature_say_id;
new_packet->id2 = 0xFFFF;
new_packet->size = new_packet_data_size;
new_packet->data = gmalloc(new_packet_data_size);
ptr = reinterpret_cast<uint8_t *>(new_packet->data);
*reinterpret_cast<uint32_t *>(ptr) = *object_id;
ptr += sizeof(*object_id);
*reinterpret_cast<uint32_t *>(ptr) = static_cast<uint32_t>(ChatType::HERO_VOICE);
ptr += sizeof(*text_type);
wcscpy_s(reinterpret_cast<wchar_t *>(ptr), new_char_name_length, new_char_name);
ptr += new_char_name_length;
*reinterpret_cast<uint32_t *>(ptr) = *npc_string;
ptr += sizeof(*npc_string);
wcscpy_s(reinterpret_cast<wchar_t *>(ptr), new_text_length, new_text);
ptr += new_text_length;
//--
//--
*packet = new_packet;
// Here we can delete old packet, or add it to queue for send to client
// gfree(p->data);
// gfree(p);
packets.push(current_packet);
}
}
}
}
return result;
}
void hook_dispatch_network_queue()
{
static const auto dispatch_network_queue_offset = 0x84;
static const auto uobject_export_name = "??_7UNetworkHandler@@6BUObject@@@";
auto UNetworkHandler_vftable = reinterpret_cast<void **>(
GetProcAddress(
GetModuleHandleA("Engine.dll"),
uobject_export_name));
auto DispatchNetworkQueueVMT = reinterpret_cast<DispatchNetworkQueueType *>(
UNetworkHandler_vftable + dispatch_network_queue_offset / sizeof(UNetworkHandler_vftable));
DispatchNetworkQueueOrig = *DispatchNetworkQueueVMT;
*DispatchNetworkQueueVMT = DispatchNetworkQueue;
}
DWORD WINAPI init_thread(LPVOID)
{
hook_dispatch_network_queue();
return 0;
}
Code: C++