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

相关文章

解析 XML 和 INI

XML 1.TinyXML库 TinyXML是一个C++的XML解析库  使用介绍: https://www.cnblogs.com/mythou/archive/2011/11/27/2265169.html    使用的时候,只要把 tinyxml.h、tinystr.h、tinystr.cpp、tinyxml.cpp、tinyxmlerror.cpp、tinyxmlparser.

[职场] 公务员的利弊分析 #知识分享#经验分享#其他

公务员的利弊分析     公务员作为一种稳定的职业选择,一直备受人们的关注。然而,就像任何其他职业一样,公务员职位也有其利与弊。本文将对公务员的利弊进行分析,帮助读者更好地了解这一职业的特点。 利: 1. 稳定的职业:公务员职位通常具有较高的稳定性,一旦进入公务员队伍,往往可以享受到稳定的工作环境和薪资待遇。这对于那些追求稳定的人来说,是一个很大的优势。 2. 薪资福利优厚:公务员的薪资和

Eclipse+ADT与Android Studio开发的区别

下文的EA指Eclipse+ADT,AS就是指Android Studio。 就编写界面布局来说AS可以边开发边预览(所见即所得,以及多个屏幕预览),这个优势比较大。AS运行时占的内存比EA的要小。AS创建项目时要创建gradle项目框架,so,创建项目时AS比较慢。android studio基于gradle构建项目,你无法同时集中管理和维护多个项目的源码,而eclipse ADT可以同时打开

Python应用开发——30天学习Streamlit Python包进行APP的构建(9)

st.area_chart 显示区域图。 这是围绕 st.altair_chart 的语法糖。主要区别在于该命令使用数据自身的列和指数来计算图表的 Altair 规格。因此,在许多 "只需绘制此图 "的情况下,该命令更易于使用,但可定制性较差。 如果 st.area_chart 无法正确猜测数据规格,请尝试使用 st.altair_chart 指定所需的图表。 Function signa

Windows中,.net framework 3.5安装

安装.net framework,目前已知2种方法,如下: 一、在MSDN下载对应的安装包,安装,这种可能无法安装成功,概率很大,不成功使用第二种方法,基本上没问题。 二、win8/8.1/10 下安装 .net framework 3.5.1: 1. 打开 win8/8.1/10 安装盘(这里指系统安装镜像文件),提取 sources\sxs 文件夹到 X:\sources\sxs (X代

高度内卷下,企业如何通过VOC(客户之声)做好竞争分析?

VOC,即客户之声,是一种通过收集和分析客户反馈、需求和期望,来洞察市场趋势和竞争对手动态的方法。在高度内卷的市场环境下,VOC不仅能够帮助企业了解客户的真实需求,还能为企业提供宝贵的竞争情报,助力企业在竞争中占据有利地位。 那么,企业该如何通过VOC(客户之声)做好竞争分析呢?深圳天行健企业管理咨询公司解析如下: 首先,要建立完善的VOC收集机制。这包括通过线上渠道(如社交媒体、官网留言

tf.split()函数解析

API原型(TensorFlow 1.8.0): tf.split(     value,     num_or_size_splits,     axis=0,     num=None,     name='split' ) 这个函数是用来切割张量的。输入切割的张量和参数,返回切割的结果。  value传入的就是需要切割的张量。  这个函数有两种切割的方式: 以三个维度的张量为例,比如说一

WordPress网创自动采集并发布插件

网创教程:WordPress插件网创自动采集并发布 阅读更新:随机添加文章的阅读数量,购买数量,喜欢数量。 使用插件注意事项 如果遇到404错误,请先检查并调整网站的伪静态设置,这是最常见的问题。需要定制化服务,请随时联系我。 本次更新内容 我们进行了多项更新和优化,主要包括: 界面设置:用户现在可以更便捷地设置文章分类和发布金额。代码优化:改进了采集和发布代码,提高了插件的稳定

WDF驱动开发-WDF总线枚举(一)

支持在总线驱动程序中进行 PnP 和电源管理 某些设备永久插入系统,而其他设备可以在系统运行时插入和拔出电源。 总线驱动 必须识别并报告连接到其总线的设备,并且他们必须发现并报告系统中设备的到达和离开情况。 总线驱动程序标识和报告的设备称为总线的 子设备。 标识和报告子设备的过程称为 总线枚举。 在总线枚举期间,总线驱动程序会为其子 设备创建设备对象 。  总线驱动程序本质上是同时处理总线枚

Python利用qq邮箱发送通知邮件(已封装成model)

因为经常喜欢写一些脚本、爬虫之类的东西,有需要通知的时候,总是苦于没有太好的通知方式,虽然邮件相对于微信、短信来说,接收性差了一些,但毕竟免费,而且支持html直接渲染,所以,折腾了一个可以直接使用的sendemail模块。这里主要应用的是QQ发邮件,微信关注QQ邮箱后,也可以实时的接收到消息,肾好! 好了,废话不多说,直接上代码。 # encoding: utf-8import lo