当前位置: 首页 > news >正文

85.网游逆向分析与插件开发-物品使用-物品使用的逆向分析与C++代码的封装

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

上一个内容:项目需求与需求拆解-CSDN博客

码云地址(ui显示角色数据 分支):https://gitee.com/dye_your_fingers/sro_-ex.git

码云版本号:453dd83d54140d2e1ee65c915ed2cede543f7400

代码下载地址,在 SRO_EX 目录下,文件名为:SRO_Ex-物品使用的逆向分析与C++代码的封装.zip

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

提取码:q9n5

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

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

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

提取码:78h8

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

以 82.网游逆向分析与插件开发-背包的获取-装备栏数据与算法的C++还原-CSDN博客 它的代码为基础进行修改

选择从网络的地方去下手,因为网络这个东西是它肯定避不开的环节,这是一个非常好的下手点,网络游戏整个逆向,或者说但凡有统一,就是所有东西都会访问一个函数,这种反而会分析起来难度比其它的难度要低非常多。

然后梳理一下思路,首先使用物品这时发出ui的消息,这个时候它一定会换算成网络消息,然后网络消息会经过一个组合,然后经过一个加密,然后经过一个发送,这就是它的一个大概的情况,这整个流程里面,只有一个最好切入,就是发送这个地方最好切入,使用ui的地方消息太多了,处理起来肯定会很麻烦,然后组合什么的都是算法,这东西没有一个明确的点没有一个明确的特征所以找不着,然后到了发送的地方,就简单了,因为网络的发送就是围绕着send函数和wsasend函数或sendto等函数,所以可以对这几个函数下断点来回溯它整个过程,然后分析过程中有一个要点,就是分析的时候会发现一个问题,发现它用了send函数或wsasend函数,这个时候一路往回找,但是要在哪停呢?比如第一次找去找到跟ui相关的,跟ui相关的会看到跟消息有关的函数,然后接下来再往后,这个时候要随时观察函数的参数,只要在参数里发现可以辨别的东西,那这个东西就基本找到了,所以有几个东西是需要密切关注的,比如物品的指针,或者说数组它的序号等这些信息比较重要,所以要随时观察,什么时候出现了这些数据就很关键,就知道什么时候停了。

然后打开x96dbg下断点,首先是send函数

然后是sendto函数,sendto一般在聊天软件里用的比较多

然后WSASend函数,它可以实现iocp(iocp例子),它是异步的,在新的游戏里用的比较多

然后可以发现WSASend会触发断点,那基本上就可以确认是它了,然后它会不停的断下来,会有干扰

然后游戏不动它也会停下来,原因是,游戏为了保证安全它有心跳包,这个时候最好找到它的长度通过条件断点筛选掉,或者眼疾手快点,然后使用物品,使用一个药物,然后它的id是应该是5912或者5913,然后因为现在以及知道它背包的物品是一个指针的数组,所以如果服务器响应这个东西,就要告诉服务器要用哪个物品,所以应该会给服务器发送一个可以证明是哪一个物品的数据,如果是数组的话使用序号的可能性要大,然后下图红框位置的物品数组下标是22,然后也可能是5912或者5913,所以看到这几个数据要敏感

然后接下来眼疾手快一点使用物品,然后就断下来了

 然后断点住后,把断点取消掉,再往上跟否则它会乱

然后一直ctrl+f9,再按f8,大致的过一遍,看看到什么位置就过不去了,然后就会看到在下图红框位置就结束了,这说明在循环里,然后下图红框位置附近有Sleep函数,这个Sleep函数一般跟消息靠的比较近,现在就大概知道它是一个什么情况了,函数很长,然后接着往下看

这么长的函数该怎样处理?首先要分清楚它的一个结构,就是游戏它有各种操作,比如a操作使用物品,b操作走路,c操作心跳包,d操作使用技能,它们都会走到网络的部分发送数据,刚刚经历的一系列函数,假设a是使用物品,那么它有一部分是属于a使用物品的,它的前面还有ui管理或者消息管理的一部分,如果要精确的找到a的过程,才能去分析它,刚刚的一系列操作该怎样排除ui或者send呢?倒着分析的逻辑的话是不需要排除ui的,只需要排除网络的部分,不可能在WSASend函数分析使用物品的逻辑,所以该怎样排除WSASend函数?然后ABCD这四个操作它基本上是共用或者部分共用这个send函数,就是共用网络发送的部分,网络发送的函数它一定是由N个函数构成,也就是说在ABCD所有的操作它到最后都会跑到send函数里,如果现在处在A的操作里面就会只有A操作能触发,就比如走路它就一定不触发A操作,使用使能也不会触发A操作,只有使用物品触发A操作,所以通过这一点就可以很容易的定位到A操作,所以接下来重新回到WSASend函数里,ctrl+f9再按f8每按一次都在上一行代码(调用函数的位置)打断点,然后走路或者执行一个非使用物品的操作,看看是否还会触发断点,如果触发就接着在断点位置使用一次物品,然后继续往上跟(ctrl+f9再按f8这个操作),然后一路这样打断点做非使用物品的操作,最终来到下图位置0x860A43,它并不会被其它操作影响,只会在使用物品的时候断下来

但是这个函数并不怎样理想,它的参数看不懂,ecx的数据也看不懂,这没关系,因为游戏它组织数据的时候一定也是循序渐进的,所以就继续往前找,一定能找到一个能看懂的地方,这个时候才好切入

然后ctrl+f9再按f8来到上一层,关键点 0x74688F

然后它的参数0x85F640函数的入参,它有三个入参,通过0x85F640函数的返回也就是ret位置看出的它是ret c,所以是三个参数,然后通过下图可以看出其中一个参数是索引,使用的物品正好是22

然后使用第一个物品,eax的值是0,所以它是索引,然后0x85F640函数就是使用物品的函数,它是0x1256E3C类里的成员函数,这个0x1256E3C之前已经用C++封装过了,也就是SRO_Control类的成员函数

效果图:可以正常使用物品了

总结:

在盲分析的情况下,可以发现是非常需要依赖参数的,能看懂参数会省很大的劲,可以尝试在0x74688F位置往上跟一层,看看它的入参,看看它的触发机制,还有下图所示的物品栏,是不是也能通过 0x74688F 位置分析到

新加按钮:

GameBase.cpp文件的修改,修改了 Init函数

#include "pch.h"
#include "GameBase.h"GameBase* _pgamebase;void GameBase::Init()
{unsigned* addrRead = (unsigned*)0x1256E3C;SRO_Res = (PRes)0x1036518;SRO_Control = (PControl)addrRead[0];addrRead = (unsigned*)0x1037D3C;SRO_Player = (PAIM)addrRead[0];InitClassProc(&Res::_ReadTitle, 0x9A46C0);InitClassProc(&Res::_ReadItemTitle, 0x9A4640);InitClassProc(&Control::_NormalNotice, 0x848580);InitClassProc(&Control::_NetNotice, 0x844E40);InitClassProc(&Control::_ChatNotice, 0x844E80);InitClassProc(&Control::_GetPPack, 0x866140);InitClassProc(&Control::_UseItem, 0x85F640);InitClassProc(&ITEM::_GetItemRes, 0x995800);InitClassProc(&Pack::_GetPackPack, 0x7722C0);InitClassProc(&Pack::_GetEquipPack, 0x772300);}void GameBase::InitClassProc(LPVOID proc_addr, unsigned value)
{unsigned* uWrite = (unsigned*)proc_addr;uWrite[0] = value;
}GameBase::GameBase()
{_pgamebase = this;// Init();// 初始化机制,完成游戏与我们dll的对接
}

Control.h文件的修改,新加 PROC_D_D_D函数指针类型、_UseItem函数指针变量、UseItem函数声明

#pragma once
#include "SRO_String.h"
#include "Pack.h"
typedef class Control
{typedef PPack (Control::* PROC)();typedef void (Control::* PROC_PSROSTR)(PSROSTRING);typedef void (Control::* PROC_D_PWSTR_D_D)(int, wchar_t*, int, int);typedef void (Control::* PROC_D_D_D)(int, int, int);
public:static PROC _GetPPack;static PROC_PSROSTR _NormalNotice;static PROC_PSROSTR _NetNotice;static PROC_D_PWSTR_D_D _ChatNotice;static PROC_D_D_D _UseItem;
public:void NormalNotice(PSROSTRING _txt);void NetNotice(PSROSTRING _txt);void ChatNotice(wchar_t* _txt, int color=0xFFFFAEC3, int type1=0x3, int type2=0x1);void UseItem(int index, int p1 = -1, int p2 = -1);PPack GetPPack();
}*PControl;

Control.cpp文件的修改,新加 UseItem函数、_UseItem变量初始化

#include "pch.h"
#include "Control.h"Control::PROC Control::_GetPPack{};
Control::PROC_PSROSTR Control::_NormalNotice{};
Control::PROC_PSROSTR Control::_NetNotice{};
Control::PROC_D_PWSTR_D_D Control::_ChatNotice{};
Control::PROC_D_D_D Control::_UseItem{};void Control::NormalNotice(PSROSTRING _txt)
{(this->*_NormalNotice)(_txt);
}void Control::NetNotice(PSROSTRING _txt)
{(this->*_NetNotice)(_txt);
}/**type1 默认0x3type2 默认0x1
*/
void Control::ChatNotice(wchar_t* _txt, int color, int type1, int type2)
{(this->*_ChatNotice)(type1, _txt, color, type2);
}void Control::UseItem(int index, int p1, int p2)
{(this->*_UseItem)(index, p1, p2);
}PPack Control::GetPPack()
{return (this->*_GetPPack)();
}

CUIWnd_1.cpp文件的修改,新加OnBnClickedButton3函数,OnBnClickedButton3函数是Button3按钮的点击事件处理函数

// CUIWnd_1.cpp: 实现文件
//#include "pch.h"
#include "htdMfcDll.h"
#include "CUIWnd_1.h"
#include "afxdialogex.h"
#include "extern_all.h"// CUIWnd_1 对话框IMPLEMENT_DYNAMIC(CUIWnd_1, CDialogEx)CUIWnd_1::CUIWnd_1(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_PAGE_1, pParent)
{}CUIWnd_1::~CUIWnd_1()
{
}void CUIWnd_1::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);DDX_Control(pDX, IDC_LIST1, lstPack);
}BEGIN_MESSAGE_MAP(CUIWnd_1, CDialogEx)ON_BN_CLICKED(IDC_BUTTON1, &CUIWnd_1::OnBnClickedButton1)ON_BN_CLICKED(IDC_BUTTON2, &CUIWnd_1::OnBnClickedButton2)ON_BN_CLICKED(IDC_BUTTON3, &CUIWnd_1::OnBnClickedButton3)
END_MESSAGE_MAP()// CUIWnd_1 消息处理程序void CUIWnd_1::OnBnClickedButton1()
{// int count = _pgamebase->SRO_Control->GetPPack()->GetPackBack()->PackCount();CString tmp;// tmp.Format(L"%d", count);// AfxMessageBox(tmp);PBackPack _PackBack = _pgamebase->SRO_Control->GetPPack()->GetPackBack();lstPack.ResetContent();for (int i = 0; i < _PackBack->PackCount(); i++){PITEM item = _PackBack->GetItem(i);if ((item != NULL) && (item->Type)) {tmp.Format(L"[%s][数量:%d][耐久:%d/%d]\n", item->GetNameByWide(), item->Count, item->Durabillty, item->MaxDurabillty);lstPack.AddString(tmp);}}}void CUIWnd_1::OnBnClickedButton2()
{// int count = _pgamebase->SRO_Control->GetPPack()->GetPackBack()->PackCount();CString tmp;// tmp.Format(L"%d", count);// AfxMessageBox(tmp);PEquipPack _PackBack = _pgamebase->SRO_Control->GetPPack()->GetEquipBack();lstPack.ResetContent();for (int i = 0; i < 13; i++){PITEM item = _PackBack->GetItem((EquipType)i);if ((item != NULL) && (item->Type > 0)) {tmp.Format(L"[%s][数量:%d][耐久:%d/%d]\n", item->GetNameByWide(), item->Count, item->Durabillty, item->MaxDurabillty);lstPack.AddString(tmp);}}
}void CUIWnd_1::OnBnClickedButton3()
{_pgamebase->SRO_Control->UseItem(12);
}
http://www.lryc.cn/news/290376.html

相关文章:

  • JVM系列——垃圾收集器
  • 那些年与指针的情仇(二)---二级指针指针与数组的那点事函数指针
  • APPCRASH 文件管理器不停重启问题记录 (最后reinstall解决)以及重装后到底会怎样
  • 导出excel功能,前端的解决方案
  • 【lesson24】MySQL索引的理解
  • Oracle篇—分区索引的重建和管理(第三篇,总共五篇)
  • 前端大厂面试题探索编辑部——第一期
  • 图扑 HT UI 5.0 全新升级,开箱即用!
  • 数据结构----链表介绍、模拟实现链表、链表的使用
  • 微信小程序如何控制元素的显示和隐藏
  • 解决ssh: connect to host github.com port 22: Connection timed out
  • idea 创建 spring boot
  • 【智能家居入门之微信小程序控制下位机】(STM32、ONENET云平台、微信小程序、HTTP协议)
  • 07.领域驱动设计:了解3种常见微服务架构模型的对比和分析
  • 设计模式——模板方法模式(Template Method Pattern)
  • 07. STP的基本配置
  • oracle分区范围修改与数据迁移处理
  • 回归预测 | Matlab实现CPO-LSSVM【24年新算法】冠豪猪优化最小二乘支持向量机多变量回归预测
  • SeaTunnel Web安装 一把成
  • 对话泛能网程路:能源产业互联网,行至中程
  • Doris简介及单机部署(超详细)
  • Pytest 识别case规则
  • gorm+mysql查询/修改json列相关操作汇总
  • CMake-Cookbook 第0章 配置环境
  • 优质硬盘检测工具SMART Utility,保障您的Mac数据安全
  • Spring: alibaba代码规范校验工具checkstyle
  • c++线程thread示例
  • Compose | UI组件(十一) | Spacer - 留白
  • PyTorch的nn.Module类的详细介绍
  • python使用activemq库ActiveMQClient类的连接activemq并订阅、发送和接收消息