101.网游逆向分析与插件开发-网络通信封包解析-解读聊天数据包并且利用Net发送

本文主要是介绍101.网游逆向分析与插件开发-网络通信封包解析-解读聊天数据包并且利用Net发送,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

内容参考于:易道云信息技术研究院VIP课

上一个内容:C++还原网络通信系统发送功能

下一个内容:解读喊话道具数据包并且利用Net发送

码云地址(游戏窗口化助手 分支):https://gitee.com/dye_your_fingers/sro_-ex.git

码云版本号:c78a135393b36cc4a6a6956b1309472951eb2acd

代码下载地址,在 SRO_EX 目录下,文件名为:SRO_Ex-解读聊天数据包并且利用Net发送.zip

链接:https://pan.baidu.com/s/1W-JpUcGOWbSJmMdmtMzYZg

提取码:q9n5

--来自百度网盘超级会员V4的分享

HOOK引擎,文件名为:黑兔sdk.zip

链接:https://pan.baidu.com/s/1IB-Zs6hi3yU8LC2f-8hIEw

提取码:78h8

--来自百度网盘超级会员V4的分享

以 C++还原网络通信系统发送功能 它的代码为基础进行修改

效果图:点击设置按钮消息发送成功

首先来到

然后断下来

下图红框位置,是把数据包拼入类的地方

然后分析数据包:现在的长度是E,数据是01 01 00 09 00 31 32 33 34 35 36 37 38 39 

然后再发送一个

这时它的长度是B,数据是 01 02 00 06 00 31 32 33 34 35 36

然后再发一个消息

这时的长度是F,数据是 01 03 00 0A 00 39 38 37 36 35 34 33 32 31 30

开始分析:

第一个字节的数据是01,它是固定的

第二个字节的数据每次都自增1,它不是一个固定的东西,不知道是什么

第四个字节09、06、0A也都在变,所以接下来就要破解第四个字节的数据跟数据有怎样的关系

第四个数据也很容易看出,第一个数据里的第四个字节的数据是09,然后我们的数据是9个字节,第二个数据里的第四个字节的数据是06,然后我们的数据是6个字节,第三个数据里的第四个字节的数据是0A,然后我们的数据是10个字节,所以第四个字节的数据是我们聊天发送的内容的长度

它的一个结构体

char 01 不变的

short un

short lenth

char* data 聊天数据

重新登陆游戏之后说话

下方是游戏重新登录之后的第二次说话,然后把这次说话的第二个字节原本是01改成了00(第一次说话时是00),这时发现,它说话成功了,但是没有任何内容

然后第四次说话

然后把原本的03改成了01

这时发现,我们说话的内容变了,原本是66666,现在变成了2222.。。。也就是我们的第二句话,这时很奇怪,我们并没有把第二句话发送给服务器,服务器也不可能保存我们说的话

它的作用,这就是韩国的这个游戏它设计的比较经典的地方,就是我们在下图红框位置说话,会对所有人广播

断线的时候说话,在下图红框位置是不显示内容的,只有在线的时候才会显示内容,也就是说在线的时候服务器是有响应的,所以当说完一句话之后服务器会给一个响应,会告诉你你说了一句什么样的话,周围的人也会看到你说了一句什么话,那么服务器再给予你说的什么话的内容的时候,这个游戏它的设计是,它给你发送消息前给每个消息编一个号,将来发送完消息之后,它告诉你第几号消息发送成功了,第几号消息发送成功,它就会把这个消息显示出来,这样的话它就不用把你说的这个话再广播给你了,这样就节约了网络,虽然节约了一点点,但也能看出它的一个设计

然后再登录一个账号,然后说话,这时说的是123

然后把数据改成456,这时网络发送的是456,不是123

然后查看两个账户的内容,另一个账号显示的是456,发送消息的账号显示的是123,这样证明了上方的想法,它会根据序号,读取本地之前发送的时候的存储的记录,然后显示说的话

然后现在就知道了,聊天数据包的结构,但是现在还有个问题,就是频道是哪个,然后在另一个频道说话

这时的数据包,数据包长度是8,数据是 05 05 00 3 00 31 31 31,与之前不同的是第一个字节的数据变成了05,所以第一个字节代表了频道

然后更新结构体:

它的一个结构体

char 01 频道 01 是公共频道 02 是单独聊天 04 是组队频道 05 是帮会频道

short un

short lenth

char* data 聊天数据

然后跟某个人单独聊天的数据结构,首先发送消息断点住

然后它的数据,长度是10,数据是 02 09 00 06 00 4D 61 73 74 65 72 03 00 31 32 33

 单独聊天的结构分析

第四个字节这时代表的是聊天目标角色名的长度

倒数第五个字节代表了聊天内容的长度

可以看出单独聊天与公共聊天是两种完全不同的数据结构,这个需要单独处理

然后测试C++代码,执行C++代码游戏闪退了,查看C++代码的方式,在代码中加一句MessageBox,然后通过x96dbg,在MessageBox函数头打断点,然后执行它的ret,就回到了我们写的C++代码里,这时就能分析我们的C++代码了

执行MessageBox函数的ret,就会来到下方我们的C++代码里,这样就可以对比我们的C++还原代码与游戏中的代码有什么不同了

然后修改C++代码(看后面的代码)之后,发现游戏不崩溃了,但是掉线了,这说明我们发送的数据有问题,严重不符合规定让服务器给我们断线了

extern_all.cpp文件的修改,修改了 InitClassProc函数

#include "pch.h"
#include "extern_all.h"void InitClassProc(LPVOID proc_addr, unsigned value)
{unsigned* uWrite = (unsigned*)proc_addr;uWrite[0] = value;
}void InitClassProc(LPVOID proc_addr, unsigned* vtable, unsigned index) {unsigned* addr = (unsigned*)vtable;InitClassProc(proc_addr, addr[index]);
}

CHelperUI.cpp文件的修改,修改了 OnBnClickedOk函数

// CHelperUI.cpp: 实现文件
//#include "pch.h"
#include "CHelperUI.h"
#include "afxdialogex.h"
#include "extern_all.h"LRESULT _stdcall CallWndProc(int nCode, WPARAM wParam, LPARAM lParam) {if (nCode == 0) {// 这里接收到的不只有游戏窗口的消息,还有我们的窗口消息// 所以要排除掉我们的窗口PCWPSTRUCT tmp = (PCWPSTRUCT)lParam;// 判断当前触发消息的窗口句柄是不是我们的游戏窗口句柄if (tmp->hwnd == _ui_helper->hwndGame) {// 拦截移动窗口消息if (tmp->message == WM_MOVE) {// 移动我们的窗口_ui_helper->MoveHelper();}if (tmp->message == WM_CLOSE) {// 游戏窗口右上角的X关闭按钮屏蔽掉了,这里我们给它处理一下// 让它点击之后可以隐藏游戏窗口并且显示我们的窗口/**_ui_helper->HideGame(); 里执行的代码如下面的两行this->ShowWindow(TRUE);::ShowWindow(hwndGame, GameShow = false);*/_ui_helper->HideGame();}}}return CallNextHookEx(_ui_helper->hookGameWnd, nCode, wParam, lParam);
}void _stdcall TimeProcHelper(HWND, UINT, UINT_PTR, DWORD) {if (_ui_helper)_ui_helper->ShowData();
}//获取程序当前所在显示器的分辨率大小,可以动态的获取程序所在显示器的分辨率
SIZE GetScreenResolution(HWND hWnd) {SIZE size{};if (!hWnd)return size;//MONITOR_DEFAULTTONEAREST 返回值是最接近该点的屏幕句柄//MONITOR_DEFAULTTOPRIMARY 返回值是主屏幕的句柄//如果其中一个屏幕包含该点,则返回值是该屏幕的HMONITOR句柄。如果没有一个屏幕包含该点,则返回值取决于dwFlags的值HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);MONITORINFOEX miex;miex.cbSize = sizeof(miex);if (!GetMonitorInfo(hMonitor, &miex))return size;DEVMODE dm;dm.dmSize = sizeof(dm);dm.dmDriverExtra = 0;//ENUM_CURRENT_SETTINGS 检索显示设备的当前设置//ENUM_REGISTRY_SETTINGS 检索当前存储在注册表中的显示设备的设置if (!EnumDisplaySettings(miex.szDevice, ENUM_CURRENT_SETTINGS, &dm))return size;size.cx = dm.dmPelsWidth;size.cy = dm.dmPelsHeight;return size;
}IMPLEMENT_DYNAMIC(CHelperUI, CDialogEx)CHelperUI::CHelperUI(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_HELPER, pParent)
{}CHelperUI::~CHelperUI()
{
}BOOL CHelperUI::OnInitDialog()
{CDialogEx::OnInitDialog();this->SetBackgroundColor(RGB(255, 255, 255));HPBar.SetBkColor(RGB(0 ,0, 0));MPBar.SetBkColor(RGB(0 ,0, 0));RageBar.SetBkColor(RGB(0 ,0, 0));ExBar.SetBkColor(RGB(0 ,0, 0));HPBar.SetBarColor(RGB(255 ,0, 0));MPBar.SetBarColor(RGB(0x0, 0x0, 0x99));RageBar.SetBarColor(RGB(0x66, 0x0, 0x66));ExBar.SetBarColor(RGB(0x00, 0xFF, 0xCC));HPBar.SetRange(0, 999);MPBar.SetRange(0, 1000);RageBar.SetRange(0, 5);ExBar.SetRange(0, 1000);//HPBar.SetPos(50);//MPBar.SetPos(50);//RageBar.SetPos(50);//ExBar.SetPos(50);::SetTimer(this->m_hWnd, 0x100002, 100, TimeProcHelper);return TRUE;
}void CHelperUI::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);DDX_Control(pDX, IDC_PRO_HP, HPBar);DDX_Control(pDX, IDC_PRO_MP, MPBar);DDX_Control(pDX, IDC_PRO_RAGE, RageBar);DDX_Control(pDX, IDC_PRO_RAGE2, ExBar);
}BEGIN_MESSAGE_MAP(CHelperUI, CDialogEx)ON_BN_CLICKED(IDOK, &CHelperUI::OnBnClickedOk)ON_BN_CLICKED(IDOK2, &CHelperUI::OnBnClickedOk2)ON_WM_CLOSE()
END_MESSAGE_MAP()// CHelperUI 消息处理程序struct ChatData {char un; // 内存对齐char id;// 频道short index; // 说话内容的序号short lenth; // 说话内容的长度char text[0x50]; // 说话的内容
};void CHelperUI::OnBnClickedOk()
{char talk[]{ "欢迎来到地球!" };char buff[0xFF]{};int len;auto netdata = _pgamebase->SRO_Net->CreateNetData(0x7025, 0x0);ChatData chat;chat.id = 1;chat.index = 0;chat.lenth = sizeof(talk) -1 ;memcpy(chat.text, talk, chat.lenth);len = chat.lenth + 5;netdata->MakeData(&chat.id, len);_pgamebase->SRO_Net->SendData(&netdata);// CDialogEx::OnOK();//CString tmp;//tmp.Format(L"%d", _pgamebase->SRO_Player->MapId);//AfxMessageBox(tmp);////CString city;//city.Format(L"%s", _pgamebase->SRO_Res->ReadTitle(tmp.GetBuffer())->wcstr());//AfxMessageBox(city);// _ui->UIShow();
}void CHelperUI::Init()
{if (hwndGame) return;wchar_t buff[0xFF]{};// 获取主窗口句柄HWND _hwnd = ::GetActiveWindow();// 获取窗口标题::GetWindowText(_hwnd, buff, 0xFF);CString _title = buff;if (_title == L"SRO_CLIENT") {hwndGame = _hwnd;CRect rect_me;// 获取当前窗口句柄GetWindowRect(&rect_me);helper_Width = rect_me.Width();SetWindowsHook(WH_CALLWNDPROC, CallWndProc);}
}void CHelperUI::MoveHelper()
{if (hwndGame) {CRect rect;// 获取游戏窗口(主窗口)样式::GetWindowRect(hwndGame, &rect);int helper_left = rect.left + rect.Width();SIZE windowSize = GetScreenResolution(this->m_hWnd);if ((helper_left + helper_Width) > windowSize.cx) {helper_left -= helper_Width;}// 设置窗口大小::MoveWindow(this->m_hWnd, helper_left, rect.top, helper_Width, rect.Height(), TRUE);}
}void CHelperUI::ShowData()
{CString tmp;CString city;auto _player = _pgamebase->SRO_Player;if (_player) {tmp.Format(L"%s Lv %d", _player->Name.wcstrByName(), _player->Lv);this->SetWindowText(tmp);float hpStep = _player->HP * 1000;hpStep = hpStep / _player->MaxHP;HPBar.SetPos(hpStep);float mpStep = _player->MP * 1000;mpStep = mpStep / _player->MaxMP;MPBar.SetPos(mpStep);RageBar.SetPos(_player->Rage);unsigned max_exp = _pgamebase->SRO_Core->GetLvMaxExp(_player->Lv)->Exp;float expSetp = _player->Exp * 1000;expSetp = expSetp / max_exp;ExBar.SetPos(expSetp);tmp.Format(L"%.1f %.1f %.1f", _player->x, _player->h, _player->y);GetDlgItem(IDC_STATIC_CORD)->SetWindowText(tmp);tmp.Format(L"%d", _pgamebase->SRO_Player->MapId);city.Format(L"%s", _pgamebase->SRO_Res->ReadTitle(tmp.GetBuffer())->wcstr());GetDlgItem(IDC_STATIC_MAP)->SetWindowText(city);}
}void CHelperUI::Show()
{MoveHelper();this->ShowWindow(TRUE);
}void CHelperUI::OnBnClickedOk2()
{if (hwndGame) {::ShowWindow(hwndGame, GameShow = !GameShow);}
}void CHelperUI::OnClose()
{if (hwndGame) {::ShowWindow(hwndGame, GameShow = true);this->ShowWindow(FALSE);}
}void CHelperUI::HideGame()
{this->ShowWindow(TRUE);::ShowWindow(hwndGame, GameShow = false);
}

这篇关于101.网游逆向分析与插件开发-网络通信封包解析-解读聊天数据包并且利用Net发送的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/846917

相关文章

Java的volatile和sychronized底层实现原理解析

《Java的volatile和sychronized底层实现原理解析》文章详细介绍了Java中的synchronized和volatile关键字的底层实现原理,包括字节码层面、JVM层面的实现细节,以... 目录1. 概览2. Synchronized2.1 字节码层面2.2 JVM层面2.2.1 ente

MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析

《MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析》本文将详细讲解MyBatis-Plus中的lambdaUpdate用法,并提供丰富的案例来帮助读者更好地理解和应... 目录深入探索MyBATis-Plus中Service接口的lambdaUpdate用法及示例案例背景

基于Python开发PDF转PNG的可视化工具

《基于Python开发PDF转PNG的可视化工具》在数字文档处理领域,PDF到图像格式的转换是常见需求,本文介绍如何利用Python的PyMuPDF库和Tkinter框架开发一个带图形界面的PDF转P... 目录一、引言二、功能特性三、技术架构1. 技术栈组成2. 系统架构javascript设计3.效果图

MyBatis-Plus中静态工具Db的多种用法及实例分析

《MyBatis-Plus中静态工具Db的多种用法及实例分析》本文将详细讲解MyBatis-Plus中静态工具Db的各种用法,并结合具体案例进行演示和说明,具有很好的参考价值,希望对大家有所帮助,如有... 目录MyBATis-Plus中静态工具Db的多种用法及实例案例背景使用静态工具Db进行数据库操作插入

Linux系统之authconfig命令的使用解读

《Linux系统之authconfig命令的使用解读》authconfig是一个用于配置Linux系统身份验证和账户管理设置的命令行工具,主要用于RedHat系列的Linux发行版,它提供了一系列选项... 目录linux authconfig命令的使用基本语法常用选项示例总结Linux authconfi

Windows server服务器使用blat命令行发送邮件

《Windowsserver服务器使用blat命令行发送邮件》在linux平台的命令行下可以使用mail命令来发送邮件,windows平台没有内置的命令,但可以使用开源的blat,其官方主页为ht... 目录下载blatBAT命令行示例备注总结在linux平台的命令行下可以使用mail命令来发送邮件,Win

Redis 内存淘汰策略深度解析(最新推荐)

《Redis内存淘汰策略深度解析(最新推荐)》本文详细探讨了Redis的内存淘汰策略、实现原理、适用场景及最佳实践,介绍了八种内存淘汰策略,包括noeviction、LRU、LFU、TTL、Rand... 目录一、 内存淘汰策略概述二、内存淘汰策略详解2.1 ​noeviction(不淘汰)​2.2 ​LR

基于Python开发PDF转Doc格式小程序

《基于Python开发PDF转Doc格式小程序》这篇文章主要为大家详细介绍了如何基于Python开发PDF转Doc格式小程序,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用python实现PDF转Doc格式小程序以下是一个使用Python实现PDF转DOC格式的GUI程序,采用T

使用Java发送邮件到QQ邮箱的完整指南

《使用Java发送邮件到QQ邮箱的完整指南》在现代软件开发中,邮件发送功能是一个常见的需求,无论是用户注册验证、密码重置,还是系统通知,邮件都是一种重要的通信方式,本文将详细介绍如何使用Java编写程... 目录引言1. 准备工作1.1 获取QQ邮箱的SMTP授权码1.2 添加JavaMail依赖2. 实现

IDEA与JDK、Maven安装配置完整步骤解析

《IDEA与JDK、Maven安装配置完整步骤解析》:本文主要介绍如何安装和配置IDE(IntelliJIDEA),包括IDE的安装步骤、JDK的下载与配置、Maven的安装与配置,以及如何在I... 目录1. IDE安装步骤2.配置操作步骤3. JDK配置下载JDK配置JDK环境变量4. Maven配置下