mirror of
https://github.com/SunsetMkt/Akebi-GC.git
synced 2025-09-19 12:06:04 +08:00
fix client side support for packet modification
This commit is contained in:
@ -66,17 +66,39 @@ namespace util
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
static T ReadMapped(void* data, int offset, bool littleEndian = false)
|
static T ReadMapped(void* data, int offset, bool is_little_endian = false)
|
||||||
{
|
{
|
||||||
char* cData = (char*)data;
|
T value; // No need to initialize, because we will fill it later
|
||||||
T result = {};
|
constexpr size_t value_size = sizeof(T);
|
||||||
if (IsLittleEndian() != littleEndian)
|
auto ptr_src = reinterpret_cast<char*>(data) + offset;
|
||||||
|
auto ptr_value = reinterpret_cast<char*>(&value);
|
||||||
|
|
||||||
|
if (IsLittleEndian() == is_little_endian)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < sizeof(T); i++)
|
memcpy_s(ptr_value, value_size, ptr_src, value_size);
|
||||||
((char*)&result)[i] = cData[offset + sizeof(T) - i - 1];
|
return value;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
memcpy_s(&result, sizeof(result), cData + offset, sizeof(result));
|
|
||||||
return result;
|
for (size_t i = 0; i < value_size; i++)
|
||||||
|
ptr_value[i] = ptr_src[value_size - i - 1];
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
static void WriteMapped(void* data, int offset, const T& value, bool is_little_endian = false)
|
||||||
|
{
|
||||||
|
constexpr size_t value_size = sizeof(T);
|
||||||
|
auto ptr_dest = reinterpret_cast<char*>(data) + offset;
|
||||||
|
auto ptr_value = reinterpret_cast<const char*>(&value);
|
||||||
|
|
||||||
|
if (IsLittleEndian() == is_little_endian)
|
||||||
|
{
|
||||||
|
memcpy_s(ptr_dest, value_size, ptr_value, value_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < value_size; i++)
|
||||||
|
ptr_dest[i] = ptr_value[value_size - i - 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,8 @@ DO_APP_FUNC(0x066218D0, Byte__Array*, Application_RecordUserData, (int32_t nType
|
|||||||
|
|
||||||
|
|
||||||
// Networking
|
// Networking
|
||||||
|
DO_APP_FUNC(0x01251620, void, Kcp_KcpNative_kcp_packet_destroy, (KcpPacket_1* packet, MethodInfo* method));
|
||||||
|
DO_APP_FUNC(0x01251820, KcpPacket_1*, Kcp_KcpNative_kcp_packet_create, (uint8_t* data, int32_t len, MethodInfo* method));
|
||||||
DO_APP_FUNC(0x012519C0, int32_t, Kcp_KcpNative_kcp_client_send_packet, (void* kcp_client, KcpPacket_1* packet, MethodInfo* method));
|
DO_APP_FUNC(0x012519C0, int32_t, Kcp_KcpNative_kcp_client_send_packet, (void* kcp_client, KcpPacket_1* packet, MethodInfo* method));
|
||||||
DO_APP_FUNC(0x00BD08A0, bool, MoleMole_KcpClient_TryDequeueEvent, (void* __this, ClientKcpEvent* evt, MethodInfo* method));
|
DO_APP_FUNC(0x00BD08A0, bool, MoleMole_KcpClient_TryDequeueEvent, (void* __this, ClientKcpEvent* evt, MethodInfo* method));
|
||||||
DO_APP_FUNC(0x029C3D60, void, MoleMole_Packet_XorEncrypt, (Byte__Array** bytes, int32_t length, MethodInfo* method));
|
DO_APP_FUNC(0x029C3D60, void, MoleMole_Packet_XorEncrypt, (Byte__Array** bytes, int32_t length, MethodInfo* method));
|
||||||
|
@ -42,22 +42,48 @@ namespace cheat::feature
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessModifiedData(app::KcpPacket_1* packet)
|
bool PacketSniffer::ProcessModifiedData(app::KcpPacket_1* packet)
|
||||||
{
|
{
|
||||||
auto modifyData = sniffer::MessageManager::WaitFor<ModifyData>();
|
auto modify_data = sniffer::MessageManager::WaitFor<ModifyData>();
|
||||||
if (!modifyData)
|
if (!modify_data)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
switch (modifyData->modifyType)
|
switch (modify_data->modify_type)
|
||||||
{
|
{
|
||||||
case PacketModifyType::Blocked:
|
case PacketModifyType::Blocked:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case PacketModifyType::Modified:
|
case PacketModifyType::Modified:
|
||||||
{
|
{
|
||||||
auto dataSize = modifyData->modifiedData.size();
|
auto data_size = modify_data->modified_head.size() + modify_data->modified_message.size() + 12;
|
||||||
packet->data = new byte[dataSize]();
|
char* data = new char[data_size];
|
||||||
memcpy_s(packet->data, dataSize, modifyData->modifiedData.data(), dataSize);
|
|
||||||
packet->dataLen = static_cast<uint32_t>(dataSize);
|
auto head_size = static_cast<uint16_t>(modify_data->modified_head.size());
|
||||||
|
auto message_size = static_cast<uint32_t>(modify_data->modified_message.size());
|
||||||
|
|
||||||
|
util::WriteMapped(data, 0, static_cast<uint16_t>(0x4567)); // Magic number
|
||||||
|
util::WriteMapped(data, 2, modify_data->message_id); // Message id
|
||||||
|
util::WriteMapped(data, 4, head_size); // Head size
|
||||||
|
util::WriteMapped(data, 6, message_size); // Message size
|
||||||
|
|
||||||
|
// Fill content
|
||||||
|
char* ptr_head_content = data + 10;
|
||||||
|
memcpy_s(ptr_head_content, head_size, modify_data->modified_head.data(), head_size);
|
||||||
|
|
||||||
|
char* ptr_message_content = ptr_head_content + modify_data->modified_head.size();
|
||||||
|
memcpy_s(ptr_message_content, message_size, modify_data->modified_message.data(), message_size);
|
||||||
|
|
||||||
|
util::WriteMapped(ptr_message_content, message_size, static_cast<uint16_t>(0x89AB));
|
||||||
|
|
||||||
|
EncryptXor(data, data_size);
|
||||||
|
|
||||||
|
// Can be memory leak.
|
||||||
|
auto new_packet = app::Kcp_KcpNative_kcp_packet_create(reinterpret_cast<uint8_t*>(data), static_cast<int32_t>(data_size), nullptr);
|
||||||
|
delete[] data;
|
||||||
|
|
||||||
|
// Will be deleted by KcpNative_kcp_client_network_thread
|
||||||
|
// app::Kcp_KcpNative_kcp_packet_destroy(packet, nullptr);
|
||||||
|
packet = new_packet;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PacketModifyType::Unchanged:
|
case PacketModifyType::Unchanged:
|
||||||
@ -88,26 +114,36 @@ namespace cheat::feature
|
|||||||
return !canceled;
|
return !canceled;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* PacketSniffer::EncryptXor(void* content, uint32_t length)
|
void PacketSniffer::EncryptXor(void* content, uint32_t length)
|
||||||
{
|
{
|
||||||
app::Byte__Array* byteArray = (app::Byte__Array*)new char[length + 0x20];
|
auto byteArray = reinterpret_cast<app::Byte__Array*>(new char[length + 0x20]);
|
||||||
byteArray->max_length = length;
|
byteArray->max_length = length;
|
||||||
memcpy_s(byteArray->vector, length, content, length);
|
memcpy_s(byteArray->vector, length, content, length);
|
||||||
|
|
||||||
app::MoleMole_Packet_XorEncrypt(&byteArray, length, nullptr);
|
app::MoleMole_Packet_XorEncrypt(&byteArray, length, nullptr);
|
||||||
|
|
||||||
auto result = new char[length];
|
memcpy_s(content, length, byteArray->vector, length);
|
||||||
memcpy_s(result, length, byteArray->vector, length);
|
|
||||||
delete[] byteArray;
|
delete[] byteArray;
|
||||||
|
|
||||||
return (char*)result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PacketData PacketSniffer::ParseRawPacketData(char* encryptedData, uint32_t length)
|
PacketData PacketSniffer::ParseRawPacketData(char* encryptedData, uint32_t length)
|
||||||
{
|
{
|
||||||
|
// Packet structure
|
||||||
|
// * Magic word (0x4567) [2 bytes]
|
||||||
|
// * message_id [2 bytes]
|
||||||
|
// * head_size [2 bytes]
|
||||||
|
// * message_size [4 bytes]
|
||||||
|
// * head_content [<head_size> bytes]
|
||||||
|
// * message_content [<message_size> bytes]
|
||||||
|
// * Magic word (0x89AB) [2 bytes]
|
||||||
|
|
||||||
|
// Header size - 12 bytes
|
||||||
|
|
||||||
PacketData packetData = sniffer::MessageManager::CreateMessage<PacketData>();
|
PacketData packetData = sniffer::MessageManager::CreateMessage<PacketData>();
|
||||||
// Decrypting packetData
|
// Decrypting packetData
|
||||||
auto data = EncryptXor(encryptedData, length);
|
auto data = new char[length];
|
||||||
|
memcpy_s(data, length, encryptedData, length);
|
||||||
|
EncryptXor(data, length);
|
||||||
|
|
||||||
uint16_t magicHead = util::ReadMapped<uint16_t>(data, 0);
|
uint16_t magicHead = util::ReadMapped<uint16_t>(data, 0);
|
||||||
|
|
||||||
|
@ -30,8 +30,9 @@ namespace cheat::feature
|
|||||||
private:
|
private:
|
||||||
PacketSniffer();
|
PacketSniffer();
|
||||||
|
|
||||||
|
bool ProcessModifiedData(app::KcpPacket_1* packet);
|
||||||
PacketData ParseRawPacketData(char* encryptedData, uint32_t length);
|
PacketData ParseRawPacketData(char* encryptedData, uint32_t length);
|
||||||
static char* EncryptXor(void* content, uint32_t length);
|
static void EncryptXor(void* content, uint32_t length);
|
||||||
static bool KcpClient_TryDequeueEvent_Hook(void* __this, app::ClientKcpEvent* evt, MethodInfo* method);
|
static bool KcpClient_TryDequeueEvent_Hook(void* __this, app::ClientKcpEvent* evt, MethodInfo* method);
|
||||||
static int32_t KcpNative_kcp_client_send_packet_Hook(void* kcp_client, app::KcpPacket_1* packet, MethodInfo* method);
|
static int32_t KcpNative_kcp_client_send_packet_Hook(void* kcp_client, app::KcpPacket_1* packet, MethodInfo* method);
|
||||||
|
|
||||||
|
@ -2,21 +2,27 @@
|
|||||||
#include "ModifyData.h"
|
#include "ModifyData.h"
|
||||||
|
|
||||||
ModifyData::ModifyData(const MessageHeader& header) : MessageBase(header),
|
ModifyData::ModifyData(const MessageHeader& header) : MessageBase(header),
|
||||||
modifyType(PacketModifyType::Unchanged), modifiedData({})
|
modify_type(PacketModifyType::Unchanged)
|
||||||
{
|
{ }
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModifyData::Write(PipeTransfer* transfer)
|
void ModifyData::Write(PipeTransfer* transfer)
|
||||||
{
|
{
|
||||||
transfer->Write<PacketModifyType>(modifyType);
|
transfer->Write<PacketModifyType>(modify_type);
|
||||||
if (modifyType == PacketModifyType::Modified)
|
if (modify_type == PacketModifyType::Modified)
|
||||||
transfer->Write(modifiedData);
|
{
|
||||||
|
transfer->Write(message_id);
|
||||||
|
transfer->Write(modified_head);
|
||||||
|
transfer->Write(modified_message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModifyData::Read(PipeTransfer* transfer)
|
void ModifyData::Read(PipeTransfer* transfer)
|
||||||
{
|
{
|
||||||
transfer->Read<PacketModifyType>(modifyType);
|
transfer->Read<PacketModifyType>(modify_type);
|
||||||
if (modifyType == PacketModifyType::Modified)
|
if (modify_type == PacketModifyType::Modified)
|
||||||
transfer->Read(modifiedData);
|
{
|
||||||
|
transfer->Read(message_id);
|
||||||
|
transfer->Read(modified_head);
|
||||||
|
transfer->Read(modified_message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,17 @@ enum class PacketModifyType
|
|||||||
class ModifyData : public MessageBase
|
class ModifyData : public MessageBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PacketModifyType modifyType;
|
PacketModifyType modify_type;
|
||||||
std::string modifiedData;
|
|
||||||
|
uint16_t message_id;
|
||||||
|
std::string modified_head;
|
||||||
|
std::string modified_message;
|
||||||
|
|
||||||
ModifyData(const MessageHeader& header);
|
ModifyData(const MessageHeader& header);
|
||||||
~ModifyData() {}
|
~ModifyData() {}
|
||||||
|
|
||||||
// Inherited via PipeSerializedObject
|
// Inherited via PipeSerializedObject
|
||||||
virtual void Write(PipeTransfer* transfer) override;
|
void Write(PipeTransfer* transfer) override;
|
||||||
virtual void Read(PipeTransfer* transfer) override;
|
void Read(PipeTransfer* transfer) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,15 +35,16 @@ void Run(HMODULE* phModule)
|
|||||||
|
|
||||||
DebuggerBypassPre();
|
DebuggerBypassPre();
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
LOG_DEBUG("Waiting 10sec for loading game library.");
|
|
||||||
Sleep(10000);
|
|
||||||
#else
|
|
||||||
while (GetModuleHandle("UserAssembly.dll") == nullptr)
|
while (GetModuleHandle("UserAssembly.dll") == nullptr)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("UserAssembly.dll isn't initialized, waiting for 2 sec.");
|
LOG_DEBUG("UserAssembly.dll isn't initialized, waiting for 2 sec.");
|
||||||
Sleep(2000);
|
Sleep(2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
LOG_DEBUG("Waiting 10sec for loading game library.");
|
||||||
|
Sleep(10000);
|
||||||
|
#else
|
||||||
LOG_DEBUG("Waiting 15sec for game initialize.");
|
LOG_DEBUG("Waiting 15sec for game initialize.");
|
||||||
Sleep(15000);
|
Sleep(15000);
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user